Compare commits

...

10 Commits

Author SHA1 Message Date
e1097048a6 RAM initialisation fixed in 086f915 2023-09-24 22:04:38 +02:00
b992e2b8fb First implementation of debug service
For now, only basic traces are implemented. The rest will follow once a printf
function is implemented
2023-09-24 22:02:20 +02:00
cc54ca7ca8 Improve mbuf fix
Byte index is now stored on 2 bytes. Macros have been made cleaner
2023-09-24 21:59:29 +02:00
0628c4c07c Use TC instead of TXE
Transfer Complete is preferable to TX Empty when using a DMA since we could be
polling the bit between transfers. TXE would be 1 but the DMA would be
transfering another at the same time. TC takes the DMA into account
2023-09-24 18:35:36 +02:00
dbfba20520 Temporary fix for mbuf's byte index
Each buffer should use its own byte index since the value would otherwise be
overwritten when writing to other buffers
2023-09-24 18:33:20 +02:00
a7099d5dfd Rename drivers folder to drv 2023-09-21 20:42:16 +02:00
086f9155f7 Fix RAM initialisation
The reset handler is responsible for loading the variables default values. This
includes variables initialized to 0, although they are handed through bss and
not data
2023-09-18 11:45:12 +02:00
4464156981 Move DMA config to buffers
Control over most parameters is not needed since they cannot change for the
buffer to work as expected. Only the priority should be adjustable
2023-09-17 17:52:14 +02:00
d84d9cef83 Move DMA's rx buffer to a separate module 2023-09-17 17:36:24 +02:00
e2adf48f82 Document dma multibuffer module 2023-09-17 00:04:06 +02:00
34 changed files with 427 additions and 199 deletions

View File

@ -1,49 +0,0 @@
/** @file dma_mbuf.h
* Module handling Direct Memory Access controller's TX functions
*
* The module provides convenient tools to send data to a peripheral in a
* buffered, non-blocking way
*/
#ifndef _DMA_MBUF_H_
#define _DMA_MBUF_H_
//--includes--------------------------------------------------------------------
#include "dma.h"
//--type definitions------------------------------------------------------------
struct DmaMultiBuffer {
void** buffers; //list of buffers to write to
volatile void* dest; //destination peripheral register
uint16_t buffer_size; //size of a single buffer
uint16_t byte_index; //index of the current byte in the current buffer
uint8_t buffer_nb; //total number of buffers
uint8_t free_buffer_nb; //number of buffers not currently used
uint8_t buffer_index; //index of the current buffer
uint8_t dma_buffer_index; //index of the DMA's current buffer
enum DmaPeriph dma; //DMA peripheral, must correspond to peripheral
enum DmaChannel channel; //DMA channel, must correspond to peripheral
enum DmaConfig config; //DMA config, must correspond to peripheral
};
//--functions-------------------------------------------------------------------
void dma_mbuf_configure(volatile struct DmaMultiBuffer* buffer, void** buffers,
volatile void* dest, uint16_t buffer_size, uint8_t buffer_nb,
enum DmaPeriph dma, enum DmaChannel channel, enum DmaConfig config);
uint32_t dma_mbuf_write_byte(volatile struct DmaMultiBuffer* buffer,
uint8_t byte);
void dma_mbuf_refresh(volatile struct DmaMultiBuffer* buffer);
#endif //_DMA_MBUF_H_

View File

@ -19,7 +19,7 @@
//--local definitions----------------------------------------------------------- //--local definitions-----------------------------------------------------------
static void configure_dma(volatile struct DMA* dma, enum DmaChannel channel, static void configure_dma(volatile struct DMA* dma, enum DmaChannel channel,
enum DmaConfig config_mask, volatile void* periph, void* mem, enum DmaConfig config_mask, volatile void* periph, volatile void* mem,
uint16_t size); uint16_t size);
@ -36,7 +36,7 @@ static volatile void* dma2_cb_params[5];
//--public functions------------------------------------------------------------ //--public functions------------------------------------------------------------
void dma_configure(enum DmaPeriph dma, enum DmaChannel channel, void dma_configure(enum DmaPeriph dma, enum DmaChannel channel,
enum DmaConfig config_mask, volatile void* periph, void* mem, enum DmaConfig config_mask, volatile void* periph, volatile void* mem,
uint16_t size, DmaCallback callback, volatile void* cb_param) uint16_t size, DmaCallback callback, volatile void* cb_param)
{ {
//reset peripheral first, to ensure proper configuration //reset peripheral first, to ensure proper configuration
@ -185,7 +185,7 @@ uint16_t dma_get_remaining(enum DmaPeriph dma, enum DmaChannel channel)
//--local functions------------------------------------------------------------- //--local functions-------------------------------------------------------------
static void configure_dma(volatile struct DMA* dma, enum DmaChannel channel, static void configure_dma(volatile struct DMA* dma, enum DmaChannel channel,
enum DmaConfig config_mask, volatile void* periph, void* mem, enum DmaConfig config_mask, volatile void* periph, volatile void* mem,
uint16_t size) uint16_t size)
{ {
volatile struct DMA_CHANNEL* regs = &dma->CHANNELS[channel]; volatile struct DMA_CHANNEL* regs = &dma->CHANNELS[channel];

View File

@ -81,7 +81,7 @@ typedef void (*DmaCallback)(enum DmaIRQSource, volatile void* param);
//--functions------------------------------------------------------------------- //--functions-------------------------------------------------------------------
void dma_configure(enum DmaPeriph dma, enum DmaChannel channel, void dma_configure(enum DmaPeriph dma, enum DmaChannel channel,
enum DmaConfig config_mask, volatile void* periph, void* mem, enum DmaConfig config_mask, volatile void* periph, volatile void* mem,
uint16_t size, DmaCallback callback, volatile void* cb_param); uint16_t size, DmaCallback callback, volatile void* cb_param);
void dma_configure_mem2mem(enum DmaPeriph dma, enum DmaChannel channel, void dma_configure_mem2mem(enum DmaPeriph dma, enum DmaChannel channel,

89
drv/dma_cbuf.c Normal file
View File

@ -0,0 +1,89 @@
/** @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,
volatile void* raw_buffer, volatile void* src, uint16_t buffer_size,
enum DmaPeriph dma, enum DmaChannel channel, enum DmaConfig priority)
{
#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 = DMA_CONFIG | priority;
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;
}

58
drv/dma_cbuf.h Normal file
View File

@ -0,0 +1,58 @@
/** @file dma_cbuf.h
* 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
*/
#ifndef _DMA_CBUF_H_
#define _DMA_CBUF_H_
//--includes--------------------------------------------------------------------
#include "dma.h"
//--type definitions------------------------------------------------------------
/**
* Struct used by the circular buffer system. This system allows bufferized
* reads to a peripheral with no latency, minimal cpu usage and customisable
* buffer sizes
*/
struct DmaCircBuffer {
volatile void* buffer; //the buffer to use as a circular buffer
volatile void* src; //source peripheral register
uint16_t size; //the size of the buffer
uint16_t begin; //pointer to the current begin of the buffer
enum DmaPeriph dma; //DMA peripheral, must correspond to peripheral
enum DmaChannel channel; //DMA channel, must correspond to peripheral
enum DmaConfig config; //DMA config, must correspond to peripheral
bool dma_looped; //whether the DMA looped or not (buffer overflow)
};
//--functions-------------------------------------------------------------------
/**
* Configure a DMA circular buffer for a single DMA channel. A standard buffer
* is used a base to construct a circular buffer, supplied in data by DMA
* tranfers from a peripheral. The DMA's priority is given as parameters.
* The peripheral's specific configuration must be handled separately.
*
* Once this function is called, the system will start running right away and
* will stay running until manually stopped
*/
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 priority);
uint32_t dma_cbuf_read_byte(volatile struct DmaCircBuffer* buffer,
uint8_t* byte);
#endif //_DMA_CBUF_H_

View File

@ -1,8 +1,8 @@
/** @file dma_mbuf.c /** @file dma_mbuf.h
* Module handling Direct Memory Access controller's TX functions * Module handling Direct Memory Access controller's multibuffer system
* *
* The module provides convenient tools to send data to a peripheral or memory * The module provides a convenient tool to send data to a peripheral in a
* area in a buffered, non-blocking way * buffered, low-altency, low-cpu usage, non-blocking way
*/ */
//--includes-------------------------------------------------------------------- //--includes--------------------------------------------------------------------
@ -12,8 +12,18 @@
//--local definitions----------------------------------------------------------- //--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); static void mbuf_callback(enum DmaIRQSource src, volatile void* param);
//take last 2 bytes of a buffer and assemble them store the current byte index
#define byte_index (((uint16_t**)buffer->buffers) \
[buffer->buffer_index][buffer->buffer_size/2])
#define dma_byte_index (((uint16_t**)buffer->buffers) \
[buffer->dma_buffer_index][buffer->buffer_size/2])
//--local variables------------------------------------------------------------- //--local variables-------------------------------------------------------------
@ -21,15 +31,14 @@ static void mbuf_callback(enum DmaIRQSource src, volatile void* param);
void dma_mbuf_configure(volatile struct DmaMultiBuffer* buffer, void** buffers, void dma_mbuf_configure(volatile struct DmaMultiBuffer* buffer, void** buffers,
volatile void* dest, uint16_t buffer_size, uint8_t buffer_nb, volatile void* dest, uint16_t buffer_size, uint8_t buffer_nb,
enum DmaPeriph dma, enum DmaChannel channel, enum DmaConfig config) enum DmaPeriph dma, enum DmaChannel channel, enum DmaConfig priority)
{ {
#warning "check for null ptr" #warning "check for null ptr"
buffer->buffers = buffers; buffer->buffers = buffers;
buffer->dest = dest; buffer->dest = dest;
buffer->buffer_size = buffer_size; buffer->buffer_size = buffer_size - 2;
buffer->byte_index = 0;
buffer->buffer_nb = buffer_nb; buffer->buffer_nb = buffer_nb;
buffer->free_buffer_nb = buffer_nb - 1; buffer->free_buffer_nb = buffer_nb - 1;
@ -38,7 +47,13 @@ void dma_mbuf_configure(volatile struct DmaMultiBuffer* buffer, void** buffers,
buffer->dma = dma; buffer->dma = dma;
buffer->channel = channel; buffer->channel = channel;
buffer->config = config; buffer->config = DMA_CONFIG | priority;
for (uint8_t i=0; i<buffer->buffer_nb; ++i) {
for (uint16_t j=0; j<buffer->buffer_size + 2; ++j) {
((uint8_t**)buffer->buffers)[i][j] = 0;
}
}
} }
uint32_t dma_mbuf_write_byte(volatile struct DmaMultiBuffer* buffer, uint32_t dma_mbuf_write_byte(volatile struct DmaMultiBuffer* buffer,
@ -47,7 +62,8 @@ uint32_t dma_mbuf_write_byte(volatile struct DmaMultiBuffer* buffer,
dma_enter_critical(buffer->dma, buffer->channel); dma_enter_critical(buffer->dma, buffer->channel);
//if the current buffer is full, we need to switch it with an empty one //if the current buffer is full, we need to switch it with an empty one
if (buffer->byte_index >= buffer->buffer_size) { volatile uint16_t index = byte_index;
if (byte_index >= buffer->buffer_size) {
//if all buffer full, give up //if all buffer full, give up
if (buffer->free_buffer_nb == 0) { if (buffer->free_buffer_nb == 0) {
@ -61,13 +77,14 @@ uint32_t dma_mbuf_write_byte(volatile struct DmaMultiBuffer* buffer,
} }
--buffer->free_buffer_nb; --buffer->free_buffer_nb;
buffer->byte_index = 0; byte_index = 0;
} }
//write the byte //write the byte
uint8_t** buffers = (uint8_t**)buffer->buffers; uint8_t** buffers = (uint8_t**)buffer->buffers;
buffers[buffer->buffer_index][buffer->byte_index] = byte; buffers[buffer->buffer_index][byte_index] = byte;
++buffer->byte_index; ++byte_index;
++index;
dma_exit_critical(buffer->dma, buffer->channel); dma_exit_critical(buffer->dma, buffer->channel);
return 0; return 0;
@ -77,14 +94,14 @@ void dma_mbuf_refresh(volatile struct DmaMultiBuffer* buffer)
{ {
//no more data to send, stop here //no more data to send, stop here
if (buffer->dma_buffer_index == buffer->buffer_index if (buffer->dma_buffer_index == buffer->buffer_index
&& buffer->byte_index == 0) { && byte_index == 0) {
return; return;
} }
//else start a new transfer //else start a new transfer
dma_configure(buffer->dma, buffer->channel, buffer->config, buffer->dest, dma_configure(buffer->dma, buffer->channel, buffer->config, buffer->dest,
buffer->buffers[buffer->dma_buffer_index], buffer->buffers[buffer->dma_buffer_index],
buffer->byte_index, mbuf_callback, buffer); dma_byte_index, mbuf_callback, buffer);
//if the newly transfering buffer was being written to, switch the current //if the newly transfering buffer was being written to, switch the current
//buffer. Since we just ended a transfer, the next buffer should be empty //buffer. Since we just ended a transfer, the next buffer should be empty
@ -94,7 +111,9 @@ void dma_mbuf_refresh(volatile struct DmaMultiBuffer* buffer)
if (buffer->buffer_index >= buffer->buffer_nb) { if (buffer->buffer_index >= buffer->buffer_nb) {
buffer->buffer_index = 0; buffer->buffer_index = 0;
} }
buffer->byte_index = 0; --buffer->free_buffer_nb;
byte_index = 0;
} }
return; return;

78
drv/dma_mbuf.h Normal file
View File

@ -0,0 +1,78 @@
/** @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
*/
#ifndef _DMA_MBUF_H_
#define _DMA_MBUF_H_
//--includes--------------------------------------------------------------------
#include "dma.h"
//--type definitions------------------------------------------------------------
/**
* Struct used by the multibuffer system. This system allows bufferized writes
* to a peripheral with no latency, minimal cpu usage and customisable buffer
* sizes
*/
struct DmaMultiBuffer {
void** buffers; //list of buffers to write to
volatile void* dest; //destination peripheral register
uint16_t buffer_size; //size of a single buffer
uint8_t buffer_nb; //total number of buffers
uint8_t free_buffer_nb; //number of buffers not currently used
uint8_t buffer_index; //index of the current buffer
uint8_t dma_buffer_index; //index of the DMA's current buffer
enum DmaPeriph dma; //DMA peripheral, must correspond to peripheral
enum DmaChannel channel; //DMA channel, must correspond to peripheral
enum DmaConfig config; //DMA config, must correspond to peripheral
};
//--functions-------------------------------------------------------------------
/**
* Configure a DMA multibuffer for a single DMA channel. A list of buffers is
* used to allow concurent write and DMA tranfers to the specified destination
* wich must be a peripheral. The DMA's priority is also given as parameters.
* The peripheral's specific configuration must be handled separately. 2 bytes
* are reserved in each buffer for index storage.
*
* This system needs to be started manually: dma_mbuf_refresh() should be called
* whenever a DMA transfer can be started. This can be done manually after
* filling up the buffer. Transfers will then automatically be started as long
* as there are bytes in the buffer. See the usart module for an usage exemple
*/
void dma_mbuf_configure(volatile struct DmaMultiBuffer* buffer, void** buffers,
volatile void* dest, uint16_t buffer_size, uint8_t buffer_nb,
enum DmaPeriph dma, enum DmaChannel channel, enum DmaConfig priority);
/**
* Write the given byte to the given buffer. Returns 0 if the write operation
* was successfull, 1 otherwise. The function is non-blocking.
*
* Note: calling this function will not trigger a DMA transfer, see
* dma_mbuf_refresh() to do that
*/
uint32_t dma_mbuf_write_byte(volatile struct DmaMultiBuffer* buffer,
uint8_t byte);
/**
* Refresh the buffer state, checking for bytes to send and triggering a DMA
* transfer if necessary. Should be called for the first transfer, any remaining
* transfer will be handled automatically until there are no bytes left in the
* buffer
*/
void dma_mbuf_refresh(volatile struct DmaMultiBuffer* buffer);
#endif //_DMA_MBUF_H_

View File

@ -15,34 +15,17 @@
#include "rcc.h" #include "rcc.h"
#include "dma.h" #include "dma.h"
#include "dma_mbuf.h" #include "dma_mbuf.h"
#include "dma_cbuf.h"
#include "stddef.h" #include "stddef.h"
//--local definitions----------------------------------------------------------- //--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 | DMA_CONFIG_PRIO_LOW)
struct CircularBuffer {
volatile uint8_t* buffer; //the buffer to use as a circular buffer
uint16_t size; //the size of the buffer
uint16_t begin; //pointer to the current begin of the buffer
bool dmaLooped; //whether the DMA looped or not (buffer overflow)
};
static void configure_usart(volatile struct USART* regs, static void configure_usart(volatile struct USART* regs,
enum UsartConfig config); enum UsartConfig config);
static void configure_baudrate(volatile struct USART* regs, uint32_t clock, static void configure_baudrate(volatile struct USART* regs, uint32_t clock,
uint32_t baudrate); uint32_t baudrate);
static uint32_t read_from_buffer(volatile struct CircularBuffer* buffer,
enum DmaChannel channel, uint8_t* byte);
static void usart1_rx_callback(enum DmaIRQSource src, volatile void* param);
static void usart2_rx_callback(enum DmaIRQSource src, volatile void* param);
static void usart3_rx_callback(enum DmaIRQSource src, volatile void* param);
//--local variables------------------------------------------------------------- //--local variables-------------------------------------------------------------
@ -51,11 +34,11 @@ static volatile struct USART* const usart1 = (struct USART*)USART1_BASE_ADDRESS;
static volatile struct USART* const usart2 = (struct USART*)USART2_BASE_ADDRESS; static volatile struct USART* const usart2 = (struct USART*)USART2_BASE_ADDRESS;
static volatile struct USART* const usart3 = (struct USART*)USART3_BASE_ADDRESS; static volatile struct USART* const usart3 = (struct USART*)USART3_BASE_ADDRESS;
static volatile struct CircularBuffer usart1_rx_buffer; static volatile struct DmaCircBuffer usart1_rx_buffer;
static volatile struct DmaMultiBuffer usart1_tx_buffer; static volatile struct DmaMultiBuffer usart1_tx_buffer;
static volatile struct CircularBuffer usart2_rx_buffer; static volatile struct DmaCircBuffer usart2_rx_buffer;
static volatile struct DmaMultiBuffer usart2_tx_buffer; static volatile struct DmaMultiBuffer usart2_tx_buffer;
static volatile struct CircularBuffer usart3_rx_buffer; static volatile struct DmaCircBuffer usart3_rx_buffer;
static volatile struct DmaMultiBuffer usart3_tx_buffer; static volatile struct DmaMultiBuffer usart3_tx_buffer;
@ -123,7 +106,7 @@ uint32_t usart_write_byte(enum UsartPeriph periph, uint8_t byte)
if (buffer->buffers) { if (buffer->buffers) {
//if the tx register is empty, there is no need to go through the dma //if the tx register is empty, there is no need to go through the dma
if (regs->SR.TXE) { if (regs->SR.TC) {
reg_write(regs->DR, USART_DR_DR, byte); reg_write(regs->DR, USART_DR_DR, byte);
//enable IRQ, disable DMA //enable IRQ, disable DMA
reg_reset(regs->CR3, USART_CR3_DMAT); reg_reset(regs->CR3, USART_CR3_DMAT);
@ -147,24 +130,20 @@ uint32_t usart_write_byte(enum UsartPeriph periph, uint8_t byte)
uint32_t usart_read_byte(enum UsartPeriph periph, uint8_t* byte) uint32_t usart_read_byte(enum UsartPeriph periph, uint8_t* byte)
{ {
volatile struct USART* regs; volatile struct USART* regs;
volatile struct CircularBuffer* buffer; volatile struct DmaCircBuffer* buffer;
enum DmaChannel dma_channel;
switch (periph) { switch (periph) {
case USART_PERIPH_1: case USART_PERIPH_1:
regs = usart1; regs = usart1;
buffer = &usart1_rx_buffer; buffer = &usart1_rx_buffer;
dma_channel = DMA_CHANNEL_5;
break; break;
case USART_PERIPH_2: case USART_PERIPH_2:
regs = usart2; regs = usart2;
buffer = &usart2_rx_buffer; buffer = &usart2_rx_buffer;
dma_channel = DMA_CHANNEL_6;
break; break;
case USART_PERIPH_3: case USART_PERIPH_3:
regs = usart3; regs = usart3;
buffer = &usart3_rx_buffer; buffer = &usart3_rx_buffer;
dma_channel = DMA_CHANNEL_3;
break; break;
default: default:
return 1; return 1;
@ -172,7 +151,7 @@ uint32_t usart_read_byte(enum UsartPeriph periph, uint8_t* byte)
} }
if (buffer->buffer) { if (buffer->buffer) {
return read_from_buffer(buffer, dma_channel, byte); return dma_cbuf_read_byte(buffer, byte);
} else { } else {
if (regs->SR.RXNE) { if (regs->SR.RXNE) {
*byte = regs->DR.DR; *byte = regs->DR.DR;
@ -184,69 +163,45 @@ uint32_t usart_read_byte(enum UsartPeriph periph, uint8_t* byte)
} }
void usart_set_tx_buffer(enum UsartPeriph periph, uint8_t** buffers, void usart_set_tx_buffer(enum UsartPeriph periph, uint8_t** buffers,
uint16_t buffer_size, uint8_t buffer_nb) uint16_t buffer_size, uint8_t buffer_nb, enum DmaConfig priority)
{ {
switch (periph) { switch (periph) {
case USART_PERIPH_1: case USART_PERIPH_1:
dma_mbuf_configure(&usart1_tx_buffer, (void**)buffers, &usart1->DR, dma_mbuf_configure(&usart1_tx_buffer, (void**)buffers, &usart1->DR,
buffer_size, buffer_nb, DMA_PERIPH_1, DMA_CHANNEL_4, buffer_size, buffer_nb, DMA_PERIPH_1, DMA_CHANNEL_4,
DMA_CONFIG); priority);
break; break;
case USART_PERIPH_2: case USART_PERIPH_2:
dma_mbuf_configure(&usart2_tx_buffer, (void**)buffers, &usart2->DR, dma_mbuf_configure(&usart2_tx_buffer, (void**)buffers, &usart2->DR,
buffer_size, buffer_nb, DMA_PERIPH_1, DMA_CHANNEL_7, buffer_size, buffer_nb, DMA_PERIPH_1, DMA_CHANNEL_7,
DMA_CONFIG); priority);
break; break;
case USART_PERIPH_3: case USART_PERIPH_3:
dma_mbuf_configure(&usart3_tx_buffer, (void**)buffers, &usart3->DR, dma_mbuf_configure(&usart3_tx_buffer, (void**)buffers, &usart3->DR,
buffer_size, buffer_nb, DMA_PERIPH_1, DMA_CHANNEL_2, buffer_size, buffer_nb, DMA_PERIPH_1, DMA_CHANNEL_2,
DMA_CONFIG); priority);
break; break;
} }
} }
void usart_set_rx_buffer(enum UsartPeriph periph, uint8_t* buffer, void usart_set_rx_buffer(enum UsartPeriph periph, uint8_t* buffer,
uint16_t size) uint16_t size, enum DmaConfig priority)
{ {
switch (periph) { switch (periph) {
case USART_PERIPH_1: case USART_PERIPH_1:
dma_configure(DMA_PERIPH_1, DMA_CHANNEL_5, dma_cbuf_configure(&usart1_rx_buffer, buffer, (void*)&usart1->DR,
DMA_CONFIG_IRQ_COMPLETE | DMA_CONFIG_FROM_PERIPH size, DMA_PERIPH_1, DMA_CHANNEL_5, priority);
| DMA_CONFIG_CIRCULAR | DMA_CONFIG_INC_MEM
| DMA_CONFIG_PSIZE_8BITS | DMA_CONFIG_MSIZE_8BITS
| DMA_CONFIG_PRIO_LOW, (void*)&usart1->DR, buffer,
size, usart1_rx_callback, NULL);
usart1_rx_buffer.buffer = buffer;
usart1_rx_buffer.size = size;
usart1_rx_buffer.begin = 0;
usart1_rx_buffer.dmaLooped = false;
reg_set(usart1->CR3, USART_CR3_DMAR); reg_set(usart1->CR3, USART_CR3_DMAR);
break; break;
case USART_PERIPH_2: case USART_PERIPH_2:
dma_configure(DMA_PERIPH_1, DMA_CHANNEL_6, dma_cbuf_configure(&usart2_rx_buffer, buffer, (void*)&usart2->DR,
DMA_CONFIG_IRQ_COMPLETE | DMA_CONFIG_FROM_PERIPH size, DMA_PERIPH_1, DMA_CHANNEL_6, priority);
| DMA_CONFIG_CIRCULAR | DMA_CONFIG_INC_MEM
| DMA_CONFIG_PSIZE_8BITS | DMA_CONFIG_MSIZE_8BITS
| DMA_CONFIG_PRIO_LOW, (void*)&usart2->DR, buffer,
size, usart2_rx_callback, NULL);
usart2_rx_buffer.buffer = buffer;
usart2_rx_buffer.size = size;
usart2_rx_buffer.begin = 0;
usart2_rx_buffer.dmaLooped = false;
reg_set(usart2->CR3, USART_CR3_DMAR); reg_set(usart2->CR3, USART_CR3_DMAR);
break; break;
case USART_PERIPH_3: case USART_PERIPH_3:
dma_configure(DMA_PERIPH_1, DMA_CHANNEL_3, dma_cbuf_configure(&usart3_rx_buffer, buffer, (void*)&usart3->DR,
DMA_CONFIG_IRQ_COMPLETE | DMA_CONFIG_FROM_PERIPH size, DMA_PERIPH_1, DMA_CHANNEL_3, priority);
| DMA_CONFIG_CIRCULAR | DMA_CONFIG_INC_MEM
| DMA_CONFIG_PSIZE_8BITS | DMA_CONFIG_MSIZE_8BITS
| DMA_CONFIG_PRIO_LOW, (void*)&usart3->DR, buffer,
size, usart3_rx_callback, NULL);
usart3_rx_buffer.buffer = buffer;
usart3_rx_buffer.size = size;
usart3_rx_buffer.begin = 0;
usart3_rx_buffer.dmaLooped = false;
reg_set(usart3->CR3, USART_CR3_DMAR); reg_set(usart3->CR3, USART_CR3_DMAR);
break; break;
@ -354,68 +309,6 @@ static void configure_baudrate(volatile struct USART* regs, uint32_t clock,
reg_write(regs->BRR, USART_BRR_DIV_Fraction, divider & 0xF); reg_write(regs->BRR, USART_BRR_DIV_Fraction, divider & 0xF);
} }
/**
* Reads the oldest byte from the given CircularBuffer if any. Returns 0 if the
* read was successfull, 1 otherwise
*/
static uint32_t read_from_buffer(volatile struct CircularBuffer* buffer,
enum DmaChannel channel, uint8_t* byte)
{
//retreive the current end of the buffer based on the DMA's progress
uint16_t end = buffer->size - dma_get_remaining(DMA_PERIPH_1, channel);
//check for bytes to read and overflow
if ((end > buffer->begin) && buffer->dmaLooped) {
//TODO overflow
buffer->begin = end;
} else if ((buffer->begin == end) && !buffer->dmaLooped) {
//TODO no data
return 1;
}
//read the oldest byte and advance the buffer
*byte = buffer->buffer[buffer->begin];
++buffer->begin;
if (buffer->begin >= buffer->size) {
buffer->begin = 0;
buffer->dmaLooped = false;
}
return 0;
}
//--allbacks-------------------------------------------------------------------
/**
* Callback called on DMA RX tranfert's completion. Sets a flag needed to
* properly handle the circular buffer
*/
static void usart1_rx_callback(enum DmaIRQSource src, volatile void* param)
{
(void)src; //only transfer complete expected
usart1_rx_buffer.dmaLooped = true;
}
/**
* Callback called on DMA RX tranfert's completion. Sets a flag needed to
* properly handle the circular buffer
*/
static void usart2_rx_callback(enum DmaIRQSource src, volatile void* param)
{
(void)src; //only transfer complete expected
usart2_rx_buffer.dmaLooped = true;
}
/**
* Callback called on DMA RX tranfert's completion. Sets a flag needed to
* properly handle the circular buffer
*/
static void usart3_rx_callback(enum DmaIRQSource src, volatile void* param)
{
(void)src; //only transfer complete expected
usart3_rx_buffer.dmaLooped = true;
}
//--ISRs------------------------------------------------------------------------ //--ISRs------------------------------------------------------------------------

View File

@ -10,6 +10,8 @@
//--includes-------------------------------------------------------------------- //--includes--------------------------------------------------------------------
#include "dma.h"
#include "stdint.h" #include "stdint.h"
@ -47,10 +49,10 @@ uint32_t usart_write_byte(enum UsartPeriph periph, uint8_t byte);
uint32_t usart_read_byte(enum UsartPeriph periph, uint8_t* byte); uint32_t usart_read_byte(enum UsartPeriph periph, uint8_t* byte);
void usart_set_tx_buffer(enum UsartPeriph periph, uint8_t** buffers, void usart_set_tx_buffer(enum UsartPeriph periph, uint8_t** buffers,
uint16_t buffer_size, uint8_t buffer_nb); uint16_t buffer_size, uint8_t buffer_nb, enum DmaConfig priority);
void usart_set_rx_buffer(enum UsartPeriph periph, uint8_t* buffer, void usart_set_rx_buffer(enum UsartPeriph periph, uint8_t* buffer,
uint16_t size); uint16_t size, enum DmaConfig priority);
#endif //_USART_H_ #endif //_USART_H_

View File

@ -64,7 +64,10 @@ SECTIONS
.bss : .bss :
{ {
. = ALIGN(4); . = ALIGN(4);
_sbss = .;
*(.bss) *(.bss)
. = ALIGN(4);
_ebss = .;
} > RAM } > RAM
/* memory space allocated to stack. The stack is situated at the very end of /* memory space allocated to stack. The stack is situated at the very end of

60
srv/debug.c Normal file
View File

@ -0,0 +1,60 @@
/** @file debug.c
* Module handling various debug functions
*
* The module provides a range of functions and tools to make debug more
* convenient
*/
//--includes--------------------------------------------------------------------
#include "debug.h"
//--local definitions-----------------------------------------------------------
#define BUFFER_SIZE 83 //80 char line + \n + 2 bytes for index
#define BUFFER_NB 3 //1 buffer in write, one in transfer and one waiting
//--local variables-------------------------------------------------------------
static enum UsartPeriph usart_periph;
static uint8_t tx_buffer1[BUFFER_SIZE];
static uint8_t tx_buffer2[BUFFER_SIZE];
static uint8_t tx_buffer3[BUFFER_SIZE];
static uint8_t* tx_buffers[BUFFER_NB] = {tx_buffer1, tx_buffer2, tx_buffer3};
//--public functions------------------------------------------------------------
#if DEBUG_TRACE || DEBUG_WARN || DEBUG_ERROR
void _debug_init(enum UsartPeriph usart, enum GpioPort tx_port,
enum GpioPin tx_pin)
{
usart_periph = usart;
gpio_configure(tx_port, tx_pin, GPIO_MODE_OUTPUT_FAST,
GPIO_CONFIG_OUT_ALT_PUSH_PULL);
usart_configure(usart_periph, USART_CONFIG_8N1, 1152000);
usart_set_tx_buffer(USART_PERIPH_3, tx_buffers, BUFFER_SIZE, BUFFER_NB,
DMA_CONFIG_PRIO_LOW);
debug_trace("\n");
debug_trace("--------------------------------------------------------------------------------\n");
debug_trace("starting debug software\n");
debug_trace("compiled on " __DATE__ " at " __TIME__ "\n");
debug_trace("--------------------------------------------------------------------------------\n");
}
void _debug_trace(char* format, ...)
{
while(*format != '\0') {
while(usart_write_byte(usart_periph, *format)) {}
++format;
}
}
#endif
//--local functions-------------------------------------------------------------

59
srv/debug.h Normal file
View File

@ -0,0 +1,59 @@
/** @file debug.h
* Module handling various debug functions
*
* The module provides a range of functions and tools to make debug more
* convenient
*/
#ifndef _DEBUG_H_
#define _DEBUG_H_
//--includes--------------------------------------------------------------------
#include "../drv/usart.h"
#include "../drv/gpio.h"
#include "stdint.h"
#define DEBUG_TRACE 1
#define DEBUG_WARN 0
#define DEBUG_ERROR 0
//--type definitions------------------------------------------------------------
#if DEBUG_TRACE || DEBUG_WARN || DEBUG_ERROR
#define debug_init(usart, tx_port, tx_pin) _debug_init(usart, tx_port, tx_pin)
#else
#define debug_init(usart) do {} while (0)
#endif
#if DEBUG_TRACE
#define debug_trace(format, ...) _debug_trace(format __VA_OPT__(,) __VA_ARGS__)
#else
#define debug_trace(format, ...) do {} while (0)
#endif
#if DEBUG_WARN
#define debug_warn(format, ...) _debug_warn(format __VA_OPT__(,) __VA_ARGS__)
#else
#define debug_warn(format, ...) do {} while (0)
#endif
#if DEBUG_ERROR
#define debug_error(format, ...) _debug_error(format __VA_OPT__(,) __VA_ARGS__)
#else
#define debug_error(format, ...) do {} while (0)
#endif
//--functions-------------------------------------------------------------------
void _debug_init(enum UsartPeriph usart, enum GpioPort tx_port,
enum GpioPin tx_pin);
void _debug_trace(char* format, ...);
void _debug_warn(char* format, ...);
void _debug_error(char* format, ...);
#endif //_DEBUG_H_

View File

@ -34,19 +34,35 @@ hdr_reset:
ldr r1, = _sdata ldr r1, = _sdata
ldr r2, = _edata ldr r2, = _edata
subs r2, r2, r1 subs r2, r2, r1
bcc startup_init_end bcc data_init_end
ldr r3, = _sromdata ldr r3, = _sromdata
movs r0, #0 movs r0, #0
startup_init_loop: data_init_loop:
ldr r4, [r3, r0] ldr r4, [r3, r0]
str r4, [r1, r0] str r4, [r1, r0]
adds r0, r0, #4 adds r0, r0, #4
cmp r0, r2 cmp r0, r2
bcc startup_init_loop bcc data_init_loop
startup_init_end: data_init_end:
//initialize RAM to zero
ldr r1, = _sbss
ldr r2, = _ebss
subs r2, r2, r1
bcc bss_init_end
movs r3, #0
movs r0, #0
bss_init_loop:
str r3, [r1, r0]
adds r0, r0, #4
cmp r0, r2
bcc bss_init_loop
bss_init_end:
b main b main
b hdr_reset b hdr_reset