/** @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; }