/** @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----------------------------------------------------------- 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 config) { #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 = config; 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; }