Rework DMA buffer to work properly
DMA buffers now work reliably with USART. The DMA api has changed to make it more efficient code-size-wise. This may, however, complicate things when implementating powersaving features
This commit is contained in:
parent
7a19ae9223
commit
fd33003e26
43
drv/dma.c
43
drv/dma.c
@ -19,9 +19,9 @@
|
|||||||
//--local definitions-----------------------------------------------------------
|
//--local definitions-----------------------------------------------------------
|
||||||
|
|
||||||
static void configure_dma(volatile struct DMA* dma, enum DmaChannel channel,
|
static void configure_dma(volatile struct DMA* dma, enum DmaChannel channel,
|
||||||
enum DmaConfig config_mask, volatile void* periph, volatile void* mem,
|
enum DmaConfig config_mask, volatile void* periph);
|
||||||
uint16_t size);
|
static void start_dma(volatile struct DMA* dma, enum DmaChannel channel,
|
||||||
|
volatile void* mem, uint16_t size);
|
||||||
|
|
||||||
//--local variables-------------------------------------------------------------
|
//--local variables-------------------------------------------------------------
|
||||||
|
|
||||||
@ -36,8 +36,8 @@ static volatile void* dma2_cb_params[5];
|
|||||||
//--public functions------------------------------------------------------------
|
//--public functions------------------------------------------------------------
|
||||||
|
|
||||||
void dma_configure(enum DmaPeriph dma, enum DmaChannel channel,
|
void dma_configure(enum DmaPeriph dma, enum DmaChannel channel,
|
||||||
enum DmaConfig config_mask, volatile void* periph, volatile void* mem,
|
enum DmaConfig config_mask, volatile void* periph,
|
||||||
uint16_t size, DmaCallback callback, volatile void* cb_param)
|
DmaCallback callback, volatile void* cb_param)
|
||||||
{
|
{
|
||||||
//reset peripheral first, to ensure proper configuration
|
//reset peripheral first, to ensure proper configuration
|
||||||
dma_reset(dma, channel);
|
dma_reset(dma, channel);
|
||||||
@ -45,7 +45,7 @@ void dma_configure(enum DmaPeriph dma, enum DmaChannel channel,
|
|||||||
switch (dma) {
|
switch (dma) {
|
||||||
case DMA_PERIPH_1:
|
case DMA_PERIPH_1:
|
||||||
rcc_enable(RCC_AHB_DMA1, RCC_APB1_NONE, RCC_APB2_NONE);
|
rcc_enable(RCC_AHB_DMA1, RCC_APB1_NONE, RCC_APB2_NONE);
|
||||||
configure_dma(dma1, channel, config_mask, periph, mem, size);
|
configure_dma(dma1, channel, config_mask, periph);
|
||||||
if (callback) {
|
if (callback) {
|
||||||
dma1_callbacks[channel] = callback;
|
dma1_callbacks[channel] = callback;
|
||||||
dma1_cb_params[channel] = cb_param;
|
dma1_cb_params[channel] = cb_param;
|
||||||
@ -54,7 +54,7 @@ void dma_configure(enum DmaPeriph dma, enum DmaChannel channel,
|
|||||||
break;
|
break;
|
||||||
case DMA_PERIPH_2:
|
case DMA_PERIPH_2:
|
||||||
rcc_enable(RCC_AHB_DMA2, RCC_APB1_NONE, RCC_APB2_NONE);
|
rcc_enable(RCC_AHB_DMA2, RCC_APB1_NONE, RCC_APB2_NONE);
|
||||||
configure_dma(dma2, channel, config_mask, periph, mem, size);
|
configure_dma(dma2, channel, config_mask, periph);
|
||||||
if (callback) {
|
if (callback) {
|
||||||
dma2_callbacks[channel] = callback;
|
dma2_callbacks[channel] = callback;
|
||||||
dma2_cb_params[channel] = cb_param;
|
dma2_cb_params[channel] = cb_param;
|
||||||
@ -110,20 +110,21 @@ void dma_exit_critical(enum DmaPeriph dma, enum DmaChannel channel)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void dma_enable(enum DmaPeriph dma, enum DmaChannel channel)
|
void dma_start(enum DmaPeriph dma, enum DmaChannel channel,
|
||||||
|
volatile void* mem, uint16_t size)
|
||||||
{
|
{
|
||||||
switch (dma) {
|
switch (dma) {
|
||||||
case DMA_PERIPH_1:
|
case DMA_PERIPH_1:
|
||||||
reg_set(dma1->CHANNELS[channel].CCR, DMA_CCR_EN);
|
|
||||||
if (dma1_callbacks[channel]) {
|
if (dma1_callbacks[channel]) {
|
||||||
nvic_enable(NVIC_IRQ_DMA1_CHANNEL1 + channel);
|
nvic_enable(NVIC_IRQ_DMA1_CHANNEL1 + channel);
|
||||||
}
|
}
|
||||||
|
start_dma(dma1, channel, mem, size);
|
||||||
break;
|
break;
|
||||||
case DMA_PERIPH_2:
|
case DMA_PERIPH_2:
|
||||||
reg_set(dma2->CHANNELS[channel].CCR, DMA_CCR_EN);
|
|
||||||
if (dma2_callbacks[channel]) {
|
if (dma2_callbacks[channel]) {
|
||||||
nvic_enable(NVIC_IRQ_DMA2_CHANNEL1 + channel);
|
nvic_enable(NVIC_IRQ_DMA2_CHANNEL1 + channel);
|
||||||
}
|
}
|
||||||
|
start_dma(dma2, channel, mem, size);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
return;
|
return;
|
||||||
@ -146,7 +147,7 @@ void dma_enter_critical(enum DmaPeriph dma, enum DmaChannel channel)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void dma_disable(enum DmaPeriph dma, enum DmaChannel channel)
|
void dma_stop(enum DmaPeriph dma, enum DmaChannel channel)
|
||||||
{
|
{
|
||||||
switch (dma) {
|
switch (dma) {
|
||||||
case DMA_PERIPH_1:
|
case DMA_PERIPH_1:
|
||||||
@ -185,21 +186,27 @@ uint16_t dma_get_remaining(enum DmaPeriph dma, enum DmaChannel channel)
|
|||||||
//--local functions-------------------------------------------------------------
|
//--local functions-------------------------------------------------------------
|
||||||
|
|
||||||
static void configure_dma(volatile struct DMA* dma, enum DmaChannel channel,
|
static void configure_dma(volatile struct DMA* dma, enum DmaChannel channel,
|
||||||
enum DmaConfig config_mask, volatile void* periph, volatile void* mem,
|
enum DmaConfig config_mask, volatile void* periph)
|
||||||
uint16_t size)
|
|
||||||
{
|
{
|
||||||
volatile struct DMA_CHANNEL* regs = &dma->CHANNELS[channel];
|
volatile struct DMA_CHANNEL* regs = &dma->CHANNELS[channel];
|
||||||
|
|
||||||
//registers should already be at reset value, apply new config
|
//registers should already be at reset value, apply new config
|
||||||
regs->CCR.word = config_mask;
|
regs->CCR.word = config_mask;
|
||||||
reg_write(regs->CNDTR, DMA_CNDTR_NDT, size);
|
|
||||||
regs->CPAR = (uint32_t)periph;
|
regs->CPAR = (uint32_t)periph;
|
||||||
regs->CMAR = (uint32_t)mem;
|
|
||||||
|
|
||||||
//only enable channel when everything is configured
|
|
||||||
reg_set(regs->CCR, DMA_CCR_EN);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void start_dma(volatile struct DMA* dma, enum DmaChannel channel,
|
||||||
|
volatile void* mem, uint16_t size)
|
||||||
|
{
|
||||||
|
volatile struct DMA_CHANNEL* regs = &dma->CHANNELS[channel];
|
||||||
|
|
||||||
|
//registers should already be configured, apply transfer config
|
||||||
|
reg_write(regs->CNDTR, DMA_CNDTR_NDT, size);
|
||||||
|
regs->CMAR = (uint32_t)mem;
|
||||||
|
|
||||||
|
//only start transfer when everything is configured
|
||||||
|
reg_set(regs->CCR, DMA_CCR_EN);
|
||||||
|
}
|
||||||
|
|
||||||
//--ISRs------------------------------------------------------------------------
|
//--ISRs------------------------------------------------------------------------
|
||||||
|
|
||||||
|
|||||||
@ -88,8 +88,8 @@ struct DmaParam {
|
|||||||
//--functions-------------------------------------------------------------------
|
//--functions-------------------------------------------------------------------
|
||||||
|
|
||||||
void dma_configure(enum DmaPeriph dma, enum DmaChannel channel,
|
void dma_configure(enum DmaPeriph dma, enum DmaChannel channel,
|
||||||
enum DmaConfig config_mask, volatile void* periph, volatile void* mem,
|
enum DmaConfig config_mask, volatile void* periph,
|
||||||
uint16_t size, DmaCallback callback, volatile void* cb_param);
|
DmaCallback callback, volatile void* cb_param);
|
||||||
|
|
||||||
void dma_configure_mem2mem(enum DmaPeriph dma, enum DmaChannel channel,
|
void dma_configure_mem2mem(enum DmaPeriph dma, enum DmaChannel channel,
|
||||||
enum DmaConfigM2M config_mask, const void* src, void* dest,
|
enum DmaConfigM2M config_mask, const void* src, void* dest,
|
||||||
@ -99,11 +99,12 @@ void dma_reset(enum DmaPeriph dma, enum DmaChannel channel);
|
|||||||
|
|
||||||
void dma_exit_critical(enum DmaPeriph dma, enum DmaChannel channel);
|
void dma_exit_critical(enum DmaPeriph dma, enum DmaChannel channel);
|
||||||
|
|
||||||
void dma_enable(enum DmaPeriph dma, enum DmaChannel channel);
|
void dma_start(enum DmaPeriph dma, enum DmaChannel channel,
|
||||||
|
volatile void* mem, uint16_t size);
|
||||||
|
|
||||||
void dma_enter_critical(enum DmaPeriph dma, enum DmaChannel channel);
|
void dma_enter_critical(enum DmaPeriph dma, enum DmaChannel channel);
|
||||||
|
|
||||||
void dma_disable(enum DmaPeriph dma, enum DmaChannel channel);
|
void dma_stop(enum DmaPeriph dma, enum DmaChannel channel);
|
||||||
|
|
||||||
uint16_t dma_get_remaining(enum DmaPeriph dma, enum DmaChannel channe);
|
uint16_t dma_get_remaining(enum DmaPeriph dma, enum DmaChannel channe);
|
||||||
|
|
||||||
|
|||||||
@ -192,12 +192,15 @@ const struct DmaParam* usart_configure_tx_dma(enum UsartPeriph periph)
|
|||||||
switch (periph) {
|
switch (periph) {
|
||||||
case USART_PERIPH_1:
|
case USART_PERIPH_1:
|
||||||
param = &usart1_tx_param;
|
param = &usart1_tx_param;
|
||||||
|
reg_set(usart1->CR3, USART_CR3_DMAT);
|
||||||
break;
|
break;
|
||||||
case USART_PERIPH_2:
|
case USART_PERIPH_2:
|
||||||
param = &usart2_tx_param;
|
param = &usart2_tx_param;
|
||||||
|
reg_set(usart2->CR3, USART_CR3_DMAT);
|
||||||
break;
|
break;
|
||||||
case USART_PERIPH_3:
|
case USART_PERIPH_3:
|
||||||
param = &usart3_tx_param;
|
param = &usart3_tx_param;
|
||||||
|
reg_set(usart3->CR3, USART_CR3_DMAT);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|||||||
@ -31,17 +31,18 @@ void dma_cbuf_configure(volatile struct DmaCircBuffer* buffer,
|
|||||||
|
|
||||||
buffer->buffer = raw_buffer;
|
buffer->buffer = raw_buffer;
|
||||||
|
|
||||||
buffer->param = param;
|
|
||||||
buffer->priority = priority;
|
|
||||||
|
|
||||||
buffer->size = buffer_size;
|
buffer->size = buffer_size;
|
||||||
buffer->begin = 0;
|
buffer->begin = 0;
|
||||||
|
|
||||||
|
buffer->dma = param->dma;
|
||||||
|
buffer->channel = param->channel;
|
||||||
|
|
||||||
buffer->dma_looped = false;
|
buffer->dma_looped = false;
|
||||||
|
|
||||||
dma_configure(buffer->param->dma, buffer->param->channel,
|
dma_configure(buffer->dma, buffer->channel,
|
||||||
buffer->param->config, buffer->param->periph,
|
DMA_CONFIG | param->config | priority,
|
||||||
buffer->buffer, buffer->size, cbuf_callback, buffer);
|
param->periph, cbuf_callback, buffer);
|
||||||
|
dma_start(buffer->dma, buffer->channel, buffer->buffer, buffer->size);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t dma_cbuf_read_byte(volatile struct DmaCircBuffer* buffer,
|
uint32_t dma_cbuf_read_byte(volatile struct DmaCircBuffer* buffer,
|
||||||
@ -49,7 +50,7 @@ uint32_t dma_cbuf_read_byte(volatile struct DmaCircBuffer* buffer,
|
|||||||
{
|
{
|
||||||
//retreive the current end of the buffer based on the DMA's progress
|
//retreive the current end of the buffer based on the DMA's progress
|
||||||
uint16_t end = buffer->size
|
uint16_t end = buffer->size
|
||||||
- dma_get_remaining(buffer->param->dma, buffer->param->channel);
|
- dma_get_remaining(buffer->dma, buffer->channel);
|
||||||
|
|
||||||
//check for bytes to read and overflow
|
//check for bytes to read and overflow
|
||||||
if ((end > buffer->begin) && buffer->dma_looped) {
|
if ((end > buffer->begin) && buffer->dma_looped) {
|
||||||
@ -85,4 +86,3 @@ static void cbuf_callback(enum DmaIRQSource src, volatile void* param)
|
|||||||
buffer->dma_looped = true;
|
buffer->dma_looped = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -23,12 +23,12 @@
|
|||||||
struct DmaCircBuffer {
|
struct DmaCircBuffer {
|
||||||
volatile void* buffer; //the buffer to use as a circular buffer
|
volatile void* buffer; //the buffer to use as a circular buffer
|
||||||
|
|
||||||
const struct DmaParam* param;
|
|
||||||
enum DmaConfig priority; //DMA config, must correspond to peripheral
|
|
||||||
|
|
||||||
uint16_t size; //the size of the buffer
|
uint16_t size; //the size of the buffer
|
||||||
uint16_t begin; //pointer to the current begin of the buffer
|
uint16_t begin; //pointer to the current begin of the buffer
|
||||||
|
|
||||||
|
enum DmaPeriph dma;
|
||||||
|
enum DmaChannel channel;
|
||||||
|
|
||||||
bool dma_looped; //whether the DMA looped or not (buffer overflow)
|
bool dma_looped; //whether the DMA looped or not (buffer overflow)
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -31,15 +31,18 @@ void dma_mbuf_configure(volatile struct DmaMultiBuffer* buffer,
|
|||||||
|
|
||||||
buffer->raw_buffer = raw_buffer;
|
buffer->raw_buffer = raw_buffer;
|
||||||
|
|
||||||
buffer->param = param;
|
|
||||||
buffer->priority = priority;
|
|
||||||
|
|
||||||
buffer->buffer_size = buffer_size / 2;
|
buffer->buffer_size = buffer_size / 2;
|
||||||
|
|
||||||
buffer->byte_index = 0;
|
buffer->byte_index = 0;
|
||||||
buffer->buffer_index = 0;
|
buffer->buffer_index = 0;
|
||||||
|
buffer->dma = param->dma;
|
||||||
|
buffer->channel = param->channel;
|
||||||
|
|
||||||
buffer->dma_running = false;
|
buffer->dma_running = false;
|
||||||
|
|
||||||
|
dma_configure(buffer->dma, buffer->channel,
|
||||||
|
DMA_CONFIG | param->config | priority,
|
||||||
|
param->periph, mbuf_callback, buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t dma_mbuf_write_byte(volatile struct DmaMultiBuffer* buffer,
|
uint32_t dma_mbuf_write_byte(volatile struct DmaMultiBuffer* buffer,
|
||||||
@ -66,12 +69,10 @@ void dma_mbuf_switch(volatile struct DmaMultiBuffer* buffer)
|
|||||||
}
|
}
|
||||||
|
|
||||||
//start a new transfer
|
//start a new transfer
|
||||||
dma_configure(buffer->param->dma, buffer->param->channel,
|
|
||||||
DMA_CONFIG | buffer->param->config | buffer->priority,
|
|
||||||
buffer->param->periph,
|
|
||||||
&buffer->raw_buffer[buffer->buffer_index * buffer->buffer_size],
|
|
||||||
buffer->byte_index, mbuf_callback, buffer);
|
|
||||||
buffer->dma_running = true;
|
buffer->dma_running = true;
|
||||||
|
dma_start(buffer->dma, buffer->channel,
|
||||||
|
&buffer->raw_buffer[buffer->buffer_index * buffer->buffer_size],
|
||||||
|
buffer->byte_index);
|
||||||
|
|
||||||
buffer->byte_index = 0;
|
buffer->byte_index = 0;
|
||||||
++buffer->buffer_index;
|
++buffer->buffer_index;
|
||||||
@ -93,7 +94,7 @@ static void mbuf_callback(enum DmaIRQSource src, volatile void* param)
|
|||||||
{
|
{
|
||||||
(void)src; //only transfer complete expected
|
(void)src; //only transfer complete expected
|
||||||
volatile struct DmaMultiBuffer* buffer = param;
|
volatile struct DmaMultiBuffer* buffer = param;
|
||||||
|
dma_stop(buffer->dma, buffer->channel);
|
||||||
buffer->dma_running = false;
|
buffer->dma_running = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -23,13 +23,12 @@
|
|||||||
struct DmaMultiBuffer {
|
struct DmaMultiBuffer {
|
||||||
uint8_t* raw_buffer;
|
uint8_t* raw_buffer;
|
||||||
|
|
||||||
const struct DmaParam* param;
|
|
||||||
enum DmaConfig priority;
|
|
||||||
|
|
||||||
uint16_t buffer_size;
|
uint16_t buffer_size;
|
||||||
|
|
||||||
uint8_t byte_index;
|
uint8_t byte_index;
|
||||||
uint8_t buffer_index;
|
uint8_t buffer_index;
|
||||||
|
enum DmaPeriph dma;
|
||||||
|
enum DmaChannel channel;
|
||||||
|
|
||||||
bool dma_running;
|
bool dma_running;
|
||||||
};
|
};
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user