rework #4

Merged
Steins7 merged 88 commits from rework into dev 2024-04-20 18:20:23 +00:00
Showing only changes of commit b9285f2ab9 - Show all commits

View File

@ -21,20 +21,20 @@
//--local definitions----------------------------------------------------------- //--local definitions-----------------------------------------------------------
struct CircularBuffer { struct CircularBuffer {
volatile uint8_t* buffer; volatile uint8_t* buffer; //the buffer to use as a circular buffer
uint16_t size; uint16_t size; //the size of the buffer
uint16_t begin; uint16_t begin; //pointer to the current begin of the buffer
bool dmaLooped; bool dmaLooped; //whether the DMA looped or not (buffer overflow)
}; };
struct FragmentedBuffer { struct FragmentedBuffer {
uint8_t** buffers; uint8_t** buffers; //list of buffers to write to
uint16_t buffer_size; uint16_t buffer_size; //size of a single buffer
uint16_t byte_index; uint16_t byte_index; //index of the current byte in the current buffer
uint8_t buffer_nb; uint8_t buffer_nb; //total number of buffers
uint8_t free_buffer_nb; uint8_t free_buffer_nb; //number of buffers not currently used
uint8_t buffer_index; uint8_t buffer_index; //index of the current buffer
uint8_t dma_buffer_index; uint8_t dma_buffer_index; //index of the DMA's current buffer
}; };
static void configure_usart(volatile struct USART* regs, static void configure_usart(volatile struct USART* regs,
@ -202,6 +202,10 @@ void usart_set_rx_buffer(enum UsartPeriph periph, uint8_t* buffer,
//--local functions------------------------------------------------------------- //--local functions-------------------------------------------------------------
/**
* Apply the given configuration to the given registers. Generic version of
* usart_configure()
*/
static void configure_usart(volatile struct USART* regs, static void configure_usart(volatile struct USART* regs,
enum UsartConfig config) enum UsartConfig config)
{ {
@ -279,6 +283,11 @@ static void configure_usart(volatile struct USART* regs,
reg_set(regs->CR1, USART_CR1_UE); reg_set(regs->CR1, USART_CR1_UE);
} }
/**
* Configure the given registers with the given baudrate. Baudrate is dependant
* on the peripheric's clock and may not be exact due to precision errors (see
* table 192 in documentation)
*/
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)
{ {
@ -292,10 +301,17 @@ 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);
} }
/**
* Non-blocking write to the given USART. Will return 0 if the write was
* successfull, 1 otherwise. If the write is successfull, the tranfer complete
* IRQ is enabled and the DMA disabled
*/
static uint32_t write_byte(volatile struct USART* regs, uint8_t byte) static uint32_t write_byte(volatile struct USART* regs, uint8_t byte)
{ {
//write if TX register empty
if (regs->SR.TXE) { if (regs->SR.TXE) {
reg_write(regs->DR, USART_DR_DR, byte); reg_write(regs->DR, USART_DR_DR, byte);
//enable IRQ, disable DMA
reg_reset(regs->CR3, USART_CR3_DMAT); reg_reset(regs->CR3, USART_CR3_DMAT);
reg_set(regs->CR1, USART_CR1_TXEIE); reg_set(regs->CR1, USART_CR1_TXEIE);
nvic_enable(NVIC_IRQ_USART1); nvic_enable(NVIC_IRQ_USART1);
@ -305,6 +321,10 @@ static uint32_t write_byte(volatile struct USART* regs, uint8_t byte)
} }
} }
/**
* Writes the given byte to the given UART, using a FragmentedBuffer and a DMA
* to bufferize the write if the peripheral is already busy.
*/
static uint32_t write_to_buffer(volatile struct USART *regs, static uint32_t write_to_buffer(volatile struct USART *regs,
volatile struct FragmentedBuffer *buffer, enum DmaChannel channel, volatile struct FragmentedBuffer *buffer, enum DmaChannel channel,
uint8_t byte) uint8_t byte)
@ -335,6 +355,7 @@ static uint32_t write_to_buffer(volatile struct USART *regs,
dma_enter_critical(DMA_PERIPH_1, channel); dma_enter_critical(DMA_PERIPH_1, channel);
} }
//write the byte
buffer->buffers[buffer->buffer_index][buffer->byte_index] = byte; buffer->buffers[buffer->buffer_index][buffer->byte_index] = byte;
++buffer->byte_index; ++buffer->byte_index;
@ -342,11 +363,17 @@ static uint32_t write_to_buffer(volatile struct USART *regs,
return 0; return 0;
} }
/**
* 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, static uint32_t read_from_buffer(volatile struct CircularBuffer* buffer,
enum DmaChannel channel, uint8_t* byte) 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); 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) { if ((end > buffer->begin) && buffer->dmaLooped) {
//TODO overflow //TODO overflow
buffer->begin = end; buffer->begin = end;
@ -355,6 +382,7 @@ static uint32_t read_from_buffer(volatile struct CircularBuffer* buffer,
return 1; return 1;
} }
//read the oldest byte and advance the buffer
*byte = buffer->buffer[buffer->begin]; *byte = buffer->buffer[buffer->begin];
++buffer->begin; ++buffer->begin;
if (buffer->begin >= buffer->size) { if (buffer->begin >= buffer->size) {
@ -367,11 +395,16 @@ static uint32_t read_from_buffer(volatile struct CircularBuffer* buffer,
//--callbacks------------------------------------------------------------------- //--callbacks-------------------------------------------------------------------
/**
* 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 usart1_tx_callback(enum DmaIRQSource src) static void usart1_tx_callback(enum DmaIRQSource src)
{ {
(void)src; //only transfer complete expected (void)src; //only transfer complete expected
volatile struct FragmentedBuffer* buffer = &usart1_tx_buffer; volatile struct FragmentedBuffer* buffer = &usart1_tx_buffer;
//increment DMA's buffer since the last once has already been sent
++buffer->dma_buffer_index; ++buffer->dma_buffer_index;
if (buffer->dma_buffer_index >= buffer->buffer_nb) { if (buffer->dma_buffer_index >= buffer->buffer_nb) {
buffer->dma_buffer_index = 0; buffer->dma_buffer_index = 0;
@ -384,6 +417,7 @@ static void usart1_tx_callback(enum DmaIRQSource src)
return; return;
} }
//else start a new transfer
dma_configure(DMA_PERIPH_1, DMA_CHANNEL_4, dma_configure(DMA_PERIPH_1, DMA_CHANNEL_4,
DMA_CONFIG_IRQ_COMPLETE | DMA_CONFIG_FROM_MEM DMA_CONFIG_IRQ_COMPLETE | DMA_CONFIG_FROM_MEM
| DMA_CONFIG_INC_MEM | DMA_CONFIG_PSIZE_8BITS | DMA_CONFIG_INC_MEM | DMA_CONFIG_PSIZE_8BITS
@ -393,6 +427,8 @@ static void usart1_tx_callback(enum DmaIRQSource src)
buffer->byte_index, buffer->byte_index,
usart1_tx_callback); usart1_tx_callback);
//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
if (buffer->dma_buffer_index == buffer->buffer_index) if (buffer->dma_buffer_index == buffer->buffer_index)
{ {
++buffer->buffer_index; ++buffer->buffer_index;
@ -403,6 +439,10 @@ static void usart1_tx_callback(enum DmaIRQSource src)
} }
} }
/**
* 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) static void usart1_rx_callback(enum DmaIRQSource src)
{ {
(void)src; //only transfer complete expected (void)src; //only transfer complete expected