stm32f1xx_HBL/srv/dma_mbuf.c

108 lines
2.7 KiB
C

/** @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-----------------------------------------------------------
/**
* 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_MEM \
| DMA_CONFIG_INC_MEM | 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->buffer_size = buffer_size / 2;
buffer->byte_index = 0;
buffer->buffer_index = 0;
buffer->dma = param->dma;
buffer->channel = param->channel;
buffer->dma_running = false;
dma_configure(buffer->dma, buffer->channel,
DMA_CONFIG | param->config | priority,
param->periph, mbuf_callback, buffer);
}
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;
}
uint32_t dma_mbuf_switch(volatile struct DmaMultiBuffer* buffer)
{
//no data to send, stop here
if (buffer->byte_index == 0) {
return 0;
}
//dma already running, give up
if (buffer->dma_running) {
return 1;
}
//start a new transfer
buffer->dma_running = true;
dma_start(buffer->dma, buffer->channel,
&buffer->raw_buffer[buffer->buffer_index * buffer->buffer_size],
buffer->byte_index);
buffer->byte_index = 0;
++buffer->buffer_index;
if (buffer->buffer_index > 1) {
buffer->buffer_index = 0;
}
return 0;
}
//--local functions-------------------------------------------------------------
/**
* Callback called on DMA TX tranfert's completion. Stops the DMA and notifies
* the buffer that the transfer is done.
*/
static void mbuf_callback(enum DmaIRQSource src, volatile void* param)
{
(void)src; //only transfer complete expected
volatile struct DmaMultiBuffer* buffer = param;
dma_stop(buffer->dma, buffer->channel);
buffer->dma_running = false;
}