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