/** @file dma_mbuf.h * Module handling Direct Memory Access controller's multibuffer system * * The module provides a convenient tool to send data to a peripheral in a * buffered, low-altency, low-cpu usage, non-blocking way */ //--includes-------------------------------------------------------------------- #include "dma_mbuf.h" //--local definitions----------------------------------------------------------- #define DMA_CONFIG (DMA_CONFIG_IRQ_COMPLETE | DMA_CONFIG_FROM_MEM \ | DMA_CONFIG_INC_MEM | DMA_CONFIG_PSIZE_8BITS \ | DMA_CONFIG_MSIZE_8BITS) static void mbuf_callback(enum DmaIRQSource src, volatile void* param); //--local variables------------------------------------------------------------- //--public functions------------------------------------------------------------ void dma_mbuf_configure(volatile struct DmaMultiBuffer* buffer, const struct DmaParam* param, enum DmaConfig priority, void* raw_buffer, uint16_t buffer_size) { #warning "check for null ptr" buffer->raw_buffer = raw_buffer; buffer->param = param; buffer->priority = priority; buffer->buffer_size = buffer_size / 2; buffer->byte_index = 0; buffer->buffer_index = 0; buffer->dma_running = false; } uint32_t dma_mbuf_write_byte(volatile struct DmaMultiBuffer* buffer, uint8_t byte) { //if the current buffer is full, give up if (buffer->byte_index >= buffer->buffer_size) { return 1; } //write the byte buffer->raw_buffer[buffer->buffer_index * buffer->buffer_size + buffer->byte_index] = byte; ++buffer->byte_index; return 0; } void dma_mbuf_switch(volatile struct DmaMultiBuffer* buffer) { //if transfer already in progress or no data to send, don't start the //transfer if (buffer->dma_running || buffer->byte_index == 0) { return; } //start a new transfer dma_configure(buffer->param->dma, buffer->param->channel, DMA_CONFIG | buffer->param->config | buffer->priority, buffer->param->periph, &buffer->raw_buffer[buffer->buffer_index * buffer->buffer_size], buffer->byte_index, mbuf_callback, buffer); buffer->dma_running = true; buffer->byte_index = 0; ++buffer->buffer_index; if (buffer->buffer_index > 1) { buffer->buffer_index = 0; } return; } //--local functions------------------------------------------------------------- /** * Callback called on DMA TX tranfert's completion. Checks for any remaining * data to send. If any, starts a new transfer, else stop the DMA */ static void mbuf_callback(enum DmaIRQSource src, volatile void* param) { (void)src; //only transfer complete expected volatile struct DmaMultiBuffer* buffer = param; buffer->dma_running = false; }