Simplify dma buffers and adjust usart

The dma buffer should be services that are used on top of peripherals. As such,
the usart driver should'nt directly use them, this is up to the user. The
multi-buffer has also been simplified since I was not satisfied with the
previous implementation
This commit is contained in:
Steins7 2024-04-03 22:03:15 +02:00
parent e1097048a6
commit ccf36ac400
8 changed files with 218 additions and 302 deletions

View File

@ -77,6 +77,13 @@ enum DmaIRQSource {
typedef void (*DmaCallback)(enum DmaIRQSource, volatile void* param); typedef void (*DmaCallback)(enum DmaIRQSource, volatile void* param);
struct DmaParam {
void* periph;
enum DmaConfig config; //DMA config, must correspond to peripheral
enum DmaPeriph dma; //DMA peripheral, must correspond to peripheral
enum DmaChannel channel; //DMA channel, must correspond to peripheral
};
//--functions------------------------------------------------------------------- //--functions-------------------------------------------------------------------

View File

@ -1,143 +0,0 @@
/** @file dma_mbuf.h
* Module handling Direct Memory Access controller's multibuffer system
*
* The module provides a convenient tool to send data to a peripheral in a
* buffered, low-altency, low-cpu usage, non-blocking way
*/
//--includes--------------------------------------------------------------------
#include "dma_mbuf.h"
//--local definitions-----------------------------------------------------------
#define DMA_CONFIG (DMA_CONFIG_IRQ_COMPLETE | DMA_CONFIG_FROM_MEM \
| DMA_CONFIG_INC_MEM | DMA_CONFIG_PSIZE_8BITS \
| DMA_CONFIG_MSIZE_8BITS)
static void mbuf_callback(enum DmaIRQSource src, volatile void* param);
//take last 2 bytes of a buffer and assemble them store the current byte index
#define byte_index (((uint16_t**)buffer->buffers) \
[buffer->buffer_index][buffer->buffer_size/2])
#define dma_byte_index (((uint16_t**)buffer->buffers) \
[buffer->dma_buffer_index][buffer->buffer_size/2])
//--local variables-------------------------------------------------------------
//--public functions------------------------------------------------------------
void dma_mbuf_configure(volatile struct DmaMultiBuffer* buffer, void** buffers,
volatile void* dest, uint16_t buffer_size, uint8_t buffer_nb,
enum DmaPeriph dma, enum DmaChannel channel, enum DmaConfig priority)
{
#warning "check for null ptr"
buffer->buffers = buffers;
buffer->dest = dest;
buffer->buffer_size = buffer_size - 2;
buffer->buffer_nb = buffer_nb;
buffer->free_buffer_nb = buffer_nb - 1;
buffer->buffer_index = 0;
buffer->dma_buffer_index = 0;
buffer->dma = dma;
buffer->channel = channel;
buffer->config = DMA_CONFIG | priority;
for (uint8_t i=0; i<buffer->buffer_nb; ++i) {
for (uint16_t j=0; j<buffer->buffer_size + 2; ++j) {
((uint8_t**)buffer->buffers)[i][j] = 0;
}
}
}
uint32_t dma_mbuf_write_byte(volatile struct DmaMultiBuffer* buffer,
uint8_t byte)
{
dma_enter_critical(buffer->dma, buffer->channel);
//if the current buffer is full, we need to switch it with an empty one
volatile uint16_t index = byte_index;
if (byte_index >= buffer->buffer_size) {
//if all buffer full, give up
if (buffer->free_buffer_nb == 0) {
dma_exit_critical(buffer->dma, buffer->channel);
return 1;
}
++buffer->buffer_index;
if (buffer->buffer_index >= buffer->buffer_nb) {
buffer->buffer_index = 0;
}
--buffer->free_buffer_nb;
byte_index = 0;
}
//write the byte
uint8_t** buffers = (uint8_t**)buffer->buffers;
buffers[buffer->buffer_index][byte_index] = byte;
++byte_index;
++index;
dma_exit_critical(buffer->dma, buffer->channel);
return 0;
}
void dma_mbuf_refresh(volatile struct DmaMultiBuffer* buffer)
{
//no more data to send, stop here
if (buffer->dma_buffer_index == buffer->buffer_index
&& byte_index == 0) {
return;
}
//else start a new transfer
dma_configure(buffer->dma, buffer->channel, buffer->config, buffer->dest,
buffer->buffers[buffer->dma_buffer_index],
dma_byte_index, mbuf_callback, buffer);
//if the newly transfering buffer was being written to, switch the current
//buffer. Since we just ended a transfer, the next buffer should be empty
if (buffer->dma_buffer_index == buffer->buffer_index)
{
++buffer->buffer_index;
if (buffer->buffer_index >= buffer->buffer_nb) {
buffer->buffer_index = 0;
}
--buffer->free_buffer_nb;
byte_index = 0;
}
return;
}
//--local functions-------------------------------------------------------------
/**
* Callback called on DMA TX tranfert's completion. Checks for any remaining
* data to send. If any, starts a new transfer, else stop the DMA
*/
static void mbuf_callback(enum DmaIRQSource src, volatile void* param)
{
(void)src; //only transfer complete expected
volatile struct DmaMultiBuffer* buffer = param;
//increment DMA's buffer since the last once has already been sent
++buffer->dma_buffer_index;
if (buffer->dma_buffer_index >= buffer->buffer_nb) {
buffer->dma_buffer_index = 0;
}
++buffer->free_buffer_nb;
dma_mbuf_refresh(param);
}

View File

@ -14,8 +14,6 @@
#include "rcc.h" #include "rcc.h"
#include "dma.h" #include "dma.h"
#include "dma_mbuf.h"
#include "dma_cbuf.h"
#include "stddef.h" #include "stddef.h"
@ -27,6 +25,8 @@ static void configure_usart(volatile struct USART* regs,
static void configure_baudrate(volatile struct USART* regs, uint32_t clock, static void configure_baudrate(volatile struct USART* regs, uint32_t clock,
uint32_t baudrate); uint32_t baudrate);
#define DMA_CONFIG (DMA_CONFIG_PSIZE_8BITS)
//--local variables------------------------------------------------------------- //--local variables-------------------------------------------------------------
@ -34,12 +34,47 @@ static volatile struct USART* const usart1 = (struct USART*)USART1_BASE_ADDRESS;
static volatile struct USART* const usart2 = (struct USART*)USART2_BASE_ADDRESS; static volatile struct USART* const usart2 = (struct USART*)USART2_BASE_ADDRESS;
static volatile struct USART* const usart3 = (struct USART*)USART3_BASE_ADDRESS; static volatile struct USART* const usart3 = (struct USART*)USART3_BASE_ADDRESS;
static volatile struct DmaCircBuffer usart1_rx_buffer; static const struct DmaParam usart1_rx_param = {
static volatile struct DmaMultiBuffer usart1_tx_buffer; (void*)&usart1->DR,
static volatile struct DmaCircBuffer usart2_rx_buffer; DMA_CONFIG,
static volatile struct DmaMultiBuffer usart2_tx_buffer; DMA_PERIPH_1,
static volatile struct DmaCircBuffer usart3_rx_buffer; DMA_CHANNEL_5,
static volatile struct DmaMultiBuffer usart3_tx_buffer; };
static const struct DmaParam usart2_rx_param = {
(void*)&usart2->DR,
DMA_CONFIG,
DMA_PERIPH_1,
DMA_CHANNEL_6,
};
static const struct DmaParam usart3_rx_param = {
(void*)&usart3->DR,
DMA_CONFIG,
DMA_PERIPH_1,
DMA_CHANNEL_3,
};
static const struct DmaParam usart1_tx_param = {
(void*)&usart1->DR,
DMA_CONFIG,
DMA_PERIPH_1,
DMA_CHANNEL_4,
};
static const struct DmaParam usart2_tx_param = {
(void*)&usart2->DR,
DMA_CONFIG,
DMA_PERIPH_1,
DMA_CHANNEL_7,
};
static const struct DmaParam usart3_tx_param = {
(void*)&usart3->DR,
DMA_CONFIG,
DMA_PERIPH_1,
DMA_CHANNEL_2,
};
//--public functions------------------------------------------------------------ //--public functions------------------------------------------------------------
@ -55,22 +90,16 @@ void usart_configure(enum UsartPeriph periph, enum UsartConfig config,
rcc_enable(RCC_AHB_NONE, RCC_APB1_NONE, RCC_APB2_USART); rcc_enable(RCC_AHB_NONE, RCC_APB1_NONE, RCC_APB2_USART);
configure_baudrate(usart1, clocks.apb2_freq, baudrate); configure_baudrate(usart1, clocks.apb2_freq, baudrate);
configure_usart(usart1, config); configure_usart(usart1, config);
usart1_tx_buffer.buffers = NULL;
usart1_rx_buffer.buffer = NULL;
break; break;
case USART_PERIPH_2: case USART_PERIPH_2:
rcc_enable(RCC_AHB_NONE, RCC_APB1_USART2, RCC_APB2_NONE); rcc_enable(RCC_AHB_NONE, RCC_APB1_USART2, RCC_APB2_NONE);
configure_baudrate(usart2, clocks.apb1_freq, baudrate); configure_baudrate(usart2, clocks.apb1_freq, baudrate);
configure_usart(usart2, config); configure_usart(usart2, config);
usart2_tx_buffer.buffers = NULL;
usart2_rx_buffer.buffer = NULL;
break; break;
case USART_PERIPH_3: case USART_PERIPH_3:
rcc_enable(RCC_AHB_NONE, RCC_APB1_USART3, RCC_APB2_NONE); rcc_enable(RCC_AHB_NONE, RCC_APB1_USART3, RCC_APB2_NONE);
configure_baudrate(usart3, clocks.apb1_freq, baudrate); configure_baudrate(usart3, clocks.apb1_freq, baudrate);
configure_usart(usart3, config); configure_usart(usart3, config);
usart3_tx_buffer.buffers = NULL;
usart3_rx_buffer.buffer = NULL;
break; break;
default: default:
break; break;
@ -80,43 +109,22 @@ void usart_configure(enum UsartPeriph periph, enum UsartConfig config,
uint32_t usart_write_byte(enum UsartPeriph periph, uint8_t byte) uint32_t usart_write_byte(enum UsartPeriph periph, uint8_t byte)
{ {
volatile struct USART* regs; volatile struct USART* regs;
volatile struct DmaMultiBuffer* buffer;
enum NvicIrq irq;
switch (periph) { switch (periph) {
case USART_PERIPH_1: case USART_PERIPH_1:
regs = usart1; regs = usart1;
buffer = &usart1_tx_buffer;
irq = NVIC_IRQ_USART1;
break; break;
case USART_PERIPH_2: case USART_PERIPH_2:
regs = usart2; regs = usart2;
buffer = &usart2_tx_buffer;
irq = NVIC_IRQ_USART2;
break; break;
case USART_PERIPH_3: case USART_PERIPH_3:
regs = usart3; regs = usart3;
buffer = &usart3_tx_buffer;
irq = NVIC_IRQ_USART3;
break; break;
default: default:
return 1; return 1;
break; break;
} }
if (buffer->buffers) {
//if the tx register is empty, there is no need to go through the dma
if (regs->SR.TC) {
reg_write(regs->DR, USART_DR_DR, byte);
//enable IRQ, disable DMA
reg_reset(regs->CR3, USART_CR3_DMAT);
reg_set(regs->CR1, USART_CR1_TXEIE);
nvic_enable(irq);
return 0;
} else {
return dma_mbuf_write_byte(buffer, byte);
}
} else {
//only write data if the tx register it empty, give up otherwise //only write data if the tx register it empty, give up otherwise
if (regs->SR.TXE) { if (regs->SR.TXE) {
reg_write(regs->DR, USART_DR_DR, byte); reg_write(regs->DR, USART_DR_DR, byte);
@ -125,34 +133,26 @@ uint32_t usart_write_byte(enum UsartPeriph periph, uint8_t byte)
return 1; return 1;
} }
} }
}
uint32_t usart_read_byte(enum UsartPeriph periph, uint8_t* byte) uint32_t usart_read_byte(enum UsartPeriph periph, uint8_t* byte)
{ {
volatile struct USART* regs; volatile struct USART* regs;
volatile struct DmaCircBuffer* buffer;
switch (periph) { switch (periph) {
case USART_PERIPH_1: case USART_PERIPH_1:
regs = usart1; regs = usart1;
buffer = &usart1_rx_buffer;
break; break;
case USART_PERIPH_2: case USART_PERIPH_2:
regs = usart2; regs = usart2;
buffer = &usart2_rx_buffer;
break; break;
case USART_PERIPH_3: case USART_PERIPH_3:
regs = usart3; regs = usart3;
buffer = &usart3_rx_buffer;
break; break;
default: default:
return 1; return 1;
break; break;
} }
if (buffer->buffer) {
return dma_cbuf_read_byte(buffer, byte);
} else {
if (regs->SR.RXNE) { if (regs->SR.RXNE) {
*byte = regs->DR.DR; *byte = regs->DR.DR;
return 0; return 0;
@ -160,54 +160,53 @@ uint32_t usart_read_byte(enum UsartPeriph periph, uint8_t* byte)
return 1; return 1;
} }
} }
}
void usart_set_tx_buffer(enum UsartPeriph periph, uint8_t** buffers, const struct DmaParam* usart_configure_rx_dma(enum UsartPeriph periph)
uint16_t buffer_size, uint8_t buffer_nb, enum DmaConfig priority)
{ {
const struct DmaParam* param;
switch (periph) { switch (periph) {
case USART_PERIPH_1: case USART_PERIPH_1:
dma_mbuf_configure(&usart1_tx_buffer, (void**)buffers, &usart1->DR, param = &usart1_rx_param;
buffer_size, buffer_nb, DMA_PERIPH_1, DMA_CHANNEL_4,
priority);
break;
case USART_PERIPH_2:
dma_mbuf_configure(&usart2_tx_buffer, (void**)buffers, &usart2->DR,
buffer_size, buffer_nb, DMA_PERIPH_1, DMA_CHANNEL_7,
priority);
break;
case USART_PERIPH_3:
dma_mbuf_configure(&usart3_tx_buffer, (void**)buffers, &usart3->DR,
buffer_size, buffer_nb, DMA_PERIPH_1, DMA_CHANNEL_2,
priority);
break;
}
}
void usart_set_rx_buffer(enum UsartPeriph periph, uint8_t* buffer,
uint16_t size, enum DmaConfig priority)
{
switch (periph) {
case USART_PERIPH_1:
dma_cbuf_configure(&usart1_rx_buffer, buffer, (void*)&usart1->DR,
size, DMA_PERIPH_1, DMA_CHANNEL_5, priority);
reg_set(usart1->CR3, USART_CR3_DMAR); reg_set(usart1->CR3, USART_CR3_DMAR);
break; break;
case USART_PERIPH_2: case USART_PERIPH_2:
dma_cbuf_configure(&usart2_rx_buffer, buffer, (void*)&usart2->DR, param = &usart2_rx_param;
size, DMA_PERIPH_1, DMA_CHANNEL_6, priority);
reg_set(usart2->CR3, USART_CR3_DMAR); reg_set(usart2->CR3, USART_CR3_DMAR);
break; break;
case USART_PERIPH_3: case USART_PERIPH_3:
dma_cbuf_configure(&usart3_rx_buffer, buffer, (void*)&usart3->DR, param = &usart3_rx_param;
size, DMA_PERIPH_1, DMA_CHANNEL_3, priority);
reg_set(usart3->CR3, USART_CR3_DMAR); reg_set(usart3->CR3, USART_CR3_DMAR);
break; break;
default:
return nullptr;
} }
return param;
} }
const struct DmaParam* usart_configure_tx_dma(enum UsartPeriph periph)
{
const struct DmaParam* param;
switch (periph) {
case USART_PERIPH_1:
param = &usart1_tx_param;
break;
case USART_PERIPH_2:
param = &usart2_tx_param;
break;
case USART_PERIPH_3:
param = &usart3_tx_param;
break;
default:
return nullptr;
}
return param;
}
//--local functions------------------------------------------------------------- //--local functions-------------------------------------------------------------
/** /**
@ -309,39 +308,3 @@ static void configure_baudrate(volatile struct USART* regs, uint32_t clock,
reg_write(regs->BRR, USART_BRR_DIV_Fraction, divider & 0xF); reg_write(regs->BRR, USART_BRR_DIV_Fraction, divider & 0xF);
} }
//--ISRs------------------------------------------------------------------------
void hdr_usart1(void)
{
//disable the interrupt. It will be reenabled on a write if needed
nvic_clear_pending(NVIC_IRQ_USART1);
nvic_disable(NVIC_IRQ_USART1);
reg_reset(usart1->CR1, USART_CR1_TXEIE);
reg_set(usart1->CR3, USART_CR3_DMAT);
dma_mbuf_refresh(&usart1_tx_buffer);
}
void hdr_usart2(void)
{
//disable the interrupt. It will be reenabled on a write if needed
nvic_clear_pending(NVIC_IRQ_USART2);
nvic_disable(NVIC_IRQ_USART2);
reg_reset(usart2->CR1, USART_CR1_TXEIE);
reg_set(usart2->CR3, USART_CR3_DMAT);
dma_mbuf_refresh(&usart2_tx_buffer);
}
void hdr_usart3(void)
{
//disable the interrupt. It will be reenabled on a write if needed
nvic_clear_pending(NVIC_IRQ_USART3);
nvic_disable(NVIC_IRQ_USART3);
reg_reset(usart3->CR1, USART_CR1_TXEIE);
reg_set(usart3->CR3, USART_CR3_DMAT);
dma_mbuf_refresh(&usart3_tx_buffer);
}

View File

@ -41,18 +41,13 @@ enum UsartConfig {
void usart_configure(enum UsartPeriph periph, enum UsartConfig config, void usart_configure(enum UsartPeriph periph, enum UsartConfig config,
uint32_t baudrate); uint32_t baudrate);
void usart_reset(enum UsartPeriph periph); void usart_reset(enum UsartPeriph periph);
uint32_t usart_write_byte(enum UsartPeriph periph, uint8_t byte); uint32_t usart_write_byte(enum UsartPeriph periph, uint8_t byte);
uint32_t usart_read_byte(enum UsartPeriph periph, uint8_t* byte); uint32_t usart_read_byte(enum UsartPeriph periph, uint8_t* byte);
void usart_set_tx_buffer(enum UsartPeriph periph, uint8_t** buffers, const struct DmaParam* usart_configure_rx_dma(enum UsartPeriph periph);
uint16_t buffer_size, uint8_t buffer_nb, enum DmaConfig priority); const struct DmaParam* usart_configure_tx_dma(enum UsartPeriph periph);
void usart_set_rx_buffer(enum UsartPeriph periph, uint8_t* buffer,
uint16_t size, enum DmaConfig priority);
#endif //_USART_H_ #endif //_USART_H_

View File

@ -24,24 +24,23 @@ static void cbuf_callback(enum DmaIRQSource src, volatile void* param);
//--public functions------------------------------------------------------------ //--public functions------------------------------------------------------------
void dma_cbuf_configure(volatile struct DmaCircBuffer* buffer, void dma_cbuf_configure(volatile struct DmaCircBuffer* buffer,
volatile void* raw_buffer, volatile void* src, uint16_t buffer_size, const struct DmaParam* param, enum DmaConfig priority,
enum DmaPeriph dma, enum DmaChannel channel, enum DmaConfig priority) volatile void* raw_buffer, uint16_t buffer_size)
{ {
#warning "check for null ptr" #warning "check for null ptr"
buffer->buffer = raw_buffer; buffer->buffer = raw_buffer;
buffer->src = src;
buffer->param = param;
buffer->priority = priority;
buffer->size = buffer_size; buffer->size = buffer_size;
buffer->begin = 0; buffer->begin = 0;
buffer->dma = dma;
buffer->channel = channel;
buffer->config = DMA_CONFIG | priority;
buffer->dma_looped = false; buffer->dma_looped = false;
dma_configure(buffer->dma, buffer->channel, buffer->config, buffer->src, dma_configure(buffer->param->dma, buffer->param->channel,
buffer->param->config, buffer->param->periph,
buffer->buffer, buffer->size, cbuf_callback, buffer); buffer->buffer, buffer->size, cbuf_callback, buffer);
} }
@ -50,7 +49,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->dma, buffer->channel); - dma_get_remaining(buffer->param->dma, buffer->param->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) {

View File

@ -10,7 +10,7 @@
//--includes-------------------------------------------------------------------- //--includes--------------------------------------------------------------------
#include "dma.h" #include "../drv/dma.h"
//--type definitions------------------------------------------------------------ //--type definitions------------------------------------------------------------
@ -22,15 +22,13 @@
*/ */
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
volatile void* src; //source peripheral register
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; //DMA peripheral, must correspond to peripheral
enum DmaChannel channel; //DMA channel, must correspond to peripheral
enum DmaConfig config; //DMA config, must correspond to peripheral
bool dma_looped; //whether the DMA looped or not (buffer overflow) bool dma_looped; //whether the DMA looped or not (buffer overflow)
}; };
@ -47,8 +45,8 @@ struct DmaCircBuffer {
* will stay running until manually stopped * will stay running until manually stopped
*/ */
void dma_cbuf_configure(volatile struct DmaCircBuffer* buffer, void dma_cbuf_configure(volatile struct DmaCircBuffer* buffer,
volatile void* raw_buffer, volatile void* src, uint16_t buffer_size, const struct DmaParam* param, enum DmaConfig priority,
enum DmaPeriph dma, enum DmaChannel channel, enum DmaConfig priority); volatile void* raw_buffer, uint16_t buffer_size);
uint32_t dma_cbuf_read_byte(volatile struct DmaCircBuffer* buffer, uint32_t dma_cbuf_read_byte(volatile struct DmaCircBuffer* buffer,
uint8_t* byte); uint8_t* byte);

99
srv/dma_mbuf.c Normal file
View File

@ -0,0 +1,99 @@
/** @file dma_mbuf.h
* Module handling Direct Memory Access controller's multibuffer system
*
* The module provides a convenient tool to send data to a peripheral in a
* buffered, low-altency, low-cpu usage, non-blocking way
*/
//--includes--------------------------------------------------------------------
#include "dma_mbuf.h"
//--local definitions-----------------------------------------------------------
#define DMA_CONFIG (DMA_CONFIG_IRQ_COMPLETE | DMA_CONFIG_FROM_MEM \
| DMA_CONFIG_INC_MEM | DMA_CONFIG_PSIZE_8BITS \
| DMA_CONFIG_MSIZE_8BITS)
static void mbuf_callback(enum DmaIRQSource src, volatile void* param);
//--local variables-------------------------------------------------------------
//--public functions------------------------------------------------------------
void dma_mbuf_configure(volatile struct DmaMultiBuffer* buffer,
const struct DmaParam* param, enum DmaConfig priority,
void* raw_buffer, uint16_t buffer_size)
{
#warning "check for null ptr"
buffer->raw_buffer = raw_buffer;
buffer->param = param;
buffer->priority = priority;
buffer->buffer_size = buffer_size / 2;
buffer->byte_index = 0;
buffer->buffer_index = 0;
buffer->dma_running = false;
}
uint32_t dma_mbuf_write_byte(volatile struct DmaMultiBuffer* buffer,
uint8_t byte)
{
//if the current buffer is full, give up
if (buffer->byte_index >= buffer->buffer_size) {
return 1;
}
//write the byte
buffer->raw_buffer[buffer->buffer_index * buffer->buffer_size
+ buffer->byte_index] = byte;
++buffer->byte_index;
return 0;
}
void dma_mbuf_switch(volatile struct DmaMultiBuffer* buffer)
{
//if transfer already in progress or no data to send, don't start the
//transfer
if (buffer->dma_running || buffer->byte_index == 0) {
return;
}
//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->byte_index = 0;
++buffer->buffer_index;
if (buffer->buffer_index > 1) {
buffer->buffer_index = 0;
}
return;
}
//--local functions-------------------------------------------------------------
/**
* Callback called on DMA TX tranfert's completion. Checks for any remaining
* data to send. If any, starts a new transfer, else stop the DMA
*/
static void mbuf_callback(enum DmaIRQSource src, volatile void* param)
{
(void)src; //only transfer complete expected
volatile struct DmaMultiBuffer* buffer = param;
buffer->dma_running = false;
}

View File

@ -10,7 +10,7 @@
//--includes-------------------------------------------------------------------- //--includes--------------------------------------------------------------------
#include "dma.h" #include "../drv/dma.h"
//--type definitions------------------------------------------------------------ //--type definitions------------------------------------------------------------
@ -21,19 +21,17 @@
* sizes * sizes
*/ */
struct DmaMultiBuffer { struct DmaMultiBuffer {
void** buffers; //list of buffers to write to uint8_t* raw_buffer;
volatile void* dest; //destination peripheral register
uint16_t buffer_size; //size of a single buffer const struct DmaParam* param;
enum DmaConfig priority;
uint8_t buffer_nb; //total number of buffers uint16_t buffer_size;
uint8_t free_buffer_nb; //number of buffers not currently used
uint8_t buffer_index; //index of the current buffer
uint8_t dma_buffer_index; //index of the DMA's current buffer
enum DmaPeriph dma; //DMA peripheral, must correspond to peripheral uint8_t byte_index;
enum DmaChannel channel; //DMA channel, must correspond to peripheral uint8_t buffer_index;
enum DmaConfig config; //DMA config, must correspond to peripheral
bool dma_running;
}; };
@ -51,9 +49,9 @@ struct DmaMultiBuffer {
* filling up the buffer. Transfers will then automatically be started as long * filling up the buffer. Transfers will then automatically be started as long
* as there are bytes in the buffer. See the usart module for an usage exemple * as there are bytes in the buffer. See the usart module for an usage exemple
*/ */
void dma_mbuf_configure(volatile struct DmaMultiBuffer* buffer, void** buffers, void dma_mbuf_configure(volatile struct DmaMultiBuffer* buffer,
volatile void* dest, uint16_t buffer_size, uint8_t buffer_nb, const struct DmaParam* param, enum DmaConfig priority,
enum DmaPeriph dma, enum DmaChannel channel, enum DmaConfig priority); void* raw_buffer, uint16_t buffer_size);
/** /**
* Write the given byte to the given buffer. Returns 0 if the write operation * Write the given byte to the given buffer. Returns 0 if the write operation
@ -71,7 +69,7 @@ uint32_t dma_mbuf_write_byte(volatile struct DmaMultiBuffer* buffer,
* transfer will be handled automatically until there are no bytes left in the * transfer will be handled automatically until there are no bytes left in the
* buffer * buffer
*/ */
void dma_mbuf_refresh(volatile struct DmaMultiBuffer* buffer); void dma_mbuf_switch(volatile struct DmaMultiBuffer* buffer);
#endif //_DMA_MBUF_H_ #endif //_DMA_MBUF_H_