stm32f1xx_HBL/srv/dma_cbuf.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;
}