Control over most parameters is not needed since they cannot change for the buffer to work as expected. Only the priority should be adjustable
90 lines
2.5 KiB
C
90 lines
2.5 KiB
C
/** @file dma_cbuf.c
|
|
* Module handling Direct Memory Access controller's circular system
|
|
*
|
|
* The module provides a convenient tool to receive data from a peripheral in a
|
|
* buffered, low-latency, low-cpu usage, non-blocking way
|
|
*/
|
|
|
|
//--includes--------------------------------------------------------------------
|
|
|
|
#include "dma_cbuf.h"
|
|
|
|
|
|
//--local definitions-----------------------------------------------------------
|
|
|
|
#define DMA_CONFIG (DMA_CONFIG_IRQ_COMPLETE | DMA_CONFIG_FROM_PERIPH \
|
|
| DMA_CONFIG_CIRCULAR | DMA_CONFIG_INC_MEM \
|
|
| DMA_CONFIG_PSIZE_8BITS | DMA_CONFIG_MSIZE_8BITS)
|
|
|
|
static void cbuf_callback(enum DmaIRQSource src, volatile void* param);
|
|
|
|
|
|
//--local variables-------------------------------------------------------------
|
|
|
|
//--public functions------------------------------------------------------------
|
|
|
|
void dma_cbuf_configure(volatile struct DmaCircBuffer* buffer,
|
|
volatile void* raw_buffer, volatile void* src, uint16_t buffer_size,
|
|
enum DmaPeriph dma, enum DmaChannel channel, enum DmaConfig priority)
|
|
{
|
|
#warning "check for null ptr"
|
|
|
|
buffer->buffer = raw_buffer;
|
|
buffer->src = src;
|
|
|
|
buffer->size = buffer_size;
|
|
buffer->begin = 0;
|
|
|
|
buffer->dma = dma;
|
|
buffer->channel = channel;
|
|
buffer->config = DMA_CONFIG | priority;
|
|
|
|
buffer->dma_looped = false;
|
|
|
|
dma_configure(buffer->dma, buffer->channel, buffer->config, buffer->src,
|
|
buffer->buffer, buffer->size, cbuf_callback, buffer);
|
|
}
|
|
|
|
uint32_t dma_cbuf_read_byte(volatile struct DmaCircBuffer* buffer,
|
|
uint8_t* byte)
|
|
{
|
|
//retreive the current end of the buffer based on the DMA's progress
|
|
uint16_t end = buffer->size
|
|
- dma_get_remaining(buffer->dma, buffer->channel);
|
|
|
|
//check for bytes to read and overflow
|
|
if ((end > buffer->begin) && buffer->dma_looped) {
|
|
//TODO overflow
|
|
buffer->begin = end;
|
|
} else if ((buffer->begin == end) && !buffer->dma_looped) {
|
|
//TODO no data
|
|
return 1;
|
|
}
|
|
|
|
//read the oldest byte and advance the buffer
|
|
uint8_t* raw_buffer = (uint8_t*)buffer->buffer;
|
|
*byte = raw_buffer[buffer->begin];
|
|
++buffer->begin;
|
|
if (buffer->begin >= buffer->size) {
|
|
buffer->begin = 0;
|
|
buffer->dma_looped = false;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
//--local functions-------------------------------------------------------------
|
|
|
|
/**
|
|
* Callback called on DMA RX tranfert's completion. Sets a flag needed to
|
|
* properly handle the circular buffer
|
|
*/
|
|
static void cbuf_callback(enum DmaIRQSource src, volatile void* param)
|
|
{
|
|
(void)src; //only transfer complete expected
|
|
volatile struct DmaCircBuffer* buffer = param;
|
|
buffer->dma_looped = true;
|
|
}
|
|
|
|
|