stm32f1xx_HBL/srv/dma_cbuf.c
Steins7 ccf36ac400 Simplify dma buffers and adjust usart
The dma buffer should be services that are used on top of peripherals. As such,
the usart driver should'nt directly use them, this is up to the user. The
multi-buffer has also been simplified since I was not satisfied with the
previous implementation
2024-04-03 22:03:15 +02:00

89 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,
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->param = param;
buffer->priority = priority;
buffer->size = buffer_size;
buffer->begin = 0;
buffer->dma_looped = false;
dma_configure(buffer->param->dma, buffer->param->channel,
buffer->param->config, buffer->param->periph,
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->param->dma, buffer->param->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;
}