93 lines
2.6 KiB
C
93 lines
2.6 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-----------------------------------------------------------
|
|
|
|
/**
|
|
* DMA configuration to be used for the buffer. Additionnal configuration may be
|
|
* added by the peripherals used
|
|
*/
|
|
#define DMA_CONFIG (DMA_CONFIG_IRQ_COMPLETE | DMA_CONFIG_FROM_PERIPH \
|
|
| DMA_CONFIG_CIRCULAR | DMA_CONFIG_INC_MEM \
|
|
| 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,
|
|
const struct DmaParam* param, enum DmaConfig priority,
|
|
volatile void* raw_buffer, uint16_t buffer_size)
|
|
{
|
|
#warning "check for null ptr"
|
|
|
|
buffer->buffer = raw_buffer;
|
|
|
|
buffer->size = buffer_size;
|
|
buffer->begin = 0;
|
|
|
|
buffer->dma = param->dma;
|
|
buffer->channel = param->channel;
|
|
|
|
buffer->dma_looped = false;
|
|
|
|
dma_configure(buffer->dma, buffer->channel,
|
|
DMA_CONFIG | param->config | priority,
|
|
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,
|
|
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;
|
|
}
|
|
|