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
100 lines
2.6 KiB
C
100 lines
2.6 KiB
C
/** @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;
|
|
}
|
|
|