diff --git a/stm-firmware/include/uart/dma-ring-buffer.h b/stm-firmware/include/uart/dma-ring-buffer.h index b3e9c12..8ede524 100644 --- a/stm-firmware/include/uart/dma-ring-buffer.h +++ b/stm-firmware/include/uart/dma-ring-buffer.h @@ -14,9 +14,26 @@ struct dma_ring_buffer_to_mem { size_t element_size; }; +struct dma_ring_buffer_to_periph { + void *src_buffer; + size_t buffer_count; + DMA_Stream_TypeDef *dma; + volatile size_t dma_get_idx_current; + volatile size_t dma_get_idx_future; + volatile size_t sw_put_idx; + uint8_t dma_base_id; + size_t element_size; +}; + int dma_ring_buffer_periph_to_mem_initialize(struct dma_ring_buffer_to_mem *dma_buffer, uint8_t base_dma_id, DMA_Stream_TypeDef *dma_stream, size_t buffer_element_count, size_t element_size, void *data_buffer, void *src_reg, uint8_t dma_trigger_channel); int dma_ring_buffer_periph_to_mem_get_data(struct dma_ring_buffer_to_mem *buff, const void **data_buff, size_t *len); void dma_ring_buffer_periph_to_mem_stop(struct dma_ring_buffer_to_mem *buff); + +int dma_ring_buffer_mem_to_periph_initialize(struct dma_ring_buffer_to_periph *dma_buffer, uint8_t base_dma_id, DMA_Stream_TypeDef *dma_stream, size_t buffer_element_count, size_t element_size, void *data_buffer, uint8_t dma_trigger_channel, void *dest_reg); +int dma_ring_buffer_mem_to_periph_insert_data(struct dma_ring_buffer_to_periph *buff, const void *data_to_insert, size_t count); +void dma_ring_buffer_mem_to_periph_int_callback(struct dma_ring_buffer_to_periph *buff); +void dma_ring_buffer_mem_to_periph_stop(struct dma_ring_buffer_to_periph *buff); + #endif /* __DMA_RING_BUFFER_H__ */ diff --git a/stm-firmware/include/uart/uart.h b/stm-firmware/include/uart/uart.h index 437e5e9..a221bf5 100644 --- a/stm-firmware/include/uart/uart.h +++ b/stm-firmware/include/uart/uart.h @@ -6,7 +6,7 @@ #define UART_RECEIVE_DMA_STREAM DMA2_Stream5 -#define UART_SEND_DMA_STREAM +#define UART_SEND_DMA_STREAM DMA2_Stream7 #define UART_PERIPH USART1 #define UART_RCC_MASK RCC_APB2ENR_USART1EN @@ -42,11 +42,11 @@ void uart_send_char(char c); void uart_send_array(const char *data, uint32_t len); -void uart_send_string(char *string); +void uart_send_string(const char *string); -void uart_send_array_with_dma(char *data, uint32_t len); +void uart_send_array_with_dma(const char *data, uint32_t len); -void uart_send_string_with_dma(char *string); +void uart_send_string_with_dma(const char *string); int uart_receive_data_with_dma(const char **data, size_t *len); diff --git a/stm-firmware/main.c b/stm-firmware/main.c index 2460165..ff53de0 100644 --- a/stm-firmware/main.c +++ b/stm-firmware/main.c @@ -57,7 +57,6 @@ int main() shell_handle_input(shell_handle, uart_input, uart_input_len); } //systick_wait_ms(300); - } } diff --git a/stm-firmware/shell.c b/stm-firmware/shell.c index 672209e..a023ac6 100644 --- a/stm-firmware/shell.c +++ b/stm-firmware/shell.c @@ -16,8 +16,7 @@ static char history_buffer[1024]; static shellmatta_retCode_t write_shell_callback(const char *data, uint32_t len) { - uart_send_array(data, len); - + uart_send_array_with_dma(data, len); return SHELLMATTA_OK; } diff --git a/stm-firmware/uart/dma-ring-buffer.c b/stm-firmware/uart/dma-ring-buffer.c index c504640..aadc34f 100644 --- a/stm-firmware/uart/dma-ring-buffer.c +++ b/stm-firmware/uart/dma-ring-buffer.c @@ -1,6 +1,7 @@ #include #include #include +#include static int dma_ring_buffer_switch_clock_enable(uint8_t base_dma, bool clk_en) { @@ -105,3 +106,135 @@ void dma_ring_buffer_periph_to_mem_stop(struct dma_ring_buffer_to_mem *buff) dma_ring_buffer_switch_clock_enable(buff->base_dma_id, false); } + +int dma_ring_buffer_mem_to_periph_initialize(struct dma_ring_buffer_to_periph *dma_buffer, uint8_t base_dma_id, DMA_Stream_TypeDef *dma_stream, size_t buffer_element_count, size_t element_size, void *data_buffer, uint8_t dma_trigger_channel, void *dest_reg) +{ + if (!dma_buffer || !dma_stream || !data_buffer || !dest_reg) + return -1000; + + dma_buffer->dma = dma_stream; + dma_buffer->dma_base_id = base_dma_id; + dma_buffer->src_buffer = data_buffer; + dma_buffer->buffer_count = buffer_element_count; + dma_buffer->element_size = element_size; + dma_buffer->sw_put_idx = 0U; + dma_buffer->dma_get_idx_current = 0U; + dma_buffer->dma_get_idx_future = 0U; + + dma_ring_buffer_switch_clock_enable(base_dma_id, true); + + dma_stream->PAR = (uint32_t)dest_reg; + dma_stream->CR = DMA_SxCR_MINC | DMA_SxCR_TCIE | (dma_trigger_channel<<25) | DMA_SxCR_DIR_0; + + return 0; +} + +static size_t calculate_ring_buffer_fill_level(size_t buffer_size, size_t get_idx, size_t put_idx) +{ + size_t fill_level; + + if (put_idx >= get_idx) { + fill_level = (put_idx - get_idx); + } else { + fill_level = buffer_size - get_idx + put_idx; + } + + return fill_level; +} + +static void queue_or_start_dma_transfer(struct dma_ring_buffer_to_periph *buff) +{ + uint32_t dma_transfer_cnt; + + if (!buff) + return; + + /* Check if DMA is running. Do nothing in this case. Will be stated from interrupt */ + if (buff->dma_get_idx_current != buff->dma_get_idx_future) + return; + + /* No new data to transfer */ + if (buff->sw_put_idx == buff->dma_get_idx_current) + return; + + /* Calculate future get idx. Stop at end of buffer to prevent impossible wrap around */ + if (buff->sw_put_idx < buff->dma_get_idx_current && buff->sw_put_idx != 0) { + buff->dma_get_idx_future = 0U; + dma_transfer_cnt = buff->buffer_count - buff->dma_get_idx_current; + } else { + buff->dma_get_idx_future = buff->sw_put_idx; + if (buff->sw_put_idx == 0) + dma_transfer_cnt = buff->buffer_count - buff->dma_get_idx_current; + else + dma_transfer_cnt = buff->sw_put_idx - buff->dma_get_idx_current; + } + + buff->dma->NDTR = dma_transfer_cnt; + buff->dma->M0AR = (uint32_t)&((char *)buff->src_buffer)[buff->dma_get_idx_current * buff->element_size]; + buff->dma->CR |= DMA_SxCR_EN; +} + +int dma_ring_buffer_mem_to_periph_insert_data(struct dma_ring_buffer_to_periph *buff, const void *data_to_insert, size_t count) +{ + int ret = 0; + size_t free_item_count; + char *insert_ptr; + char *dest_ptr; + void *ptr; + size_t first_round_count; + + if (!buff || !data_to_insert || !count) + return -1000; + + /* Check if data fits into buffer minus one element. If not: try full-1 buffer and rest + * Buffer is not allowed to be completely full, because I cannot ddifferentiate a full buffer from a completely empty one + */ + if (count >= buff->buffer_count) { + ret = dma_ring_buffer_mem_to_periph_insert_data(buff, data_to_insert, buff->buffer_count - 1); + if (ret) + goto return_retval; + ptr = (void *)(((char *)data_to_insert) + ((buff->buffer_count-1) * buff->element_size)); + ret = dma_ring_buffer_mem_to_periph_insert_data(buff, ptr, count - buff->buffer_count + 1); + goto return_retval; + } + + /* Wait for buffer to be able to handle input */ + do { + free_item_count = buff->buffer_count - calculate_ring_buffer_fill_level(buff->buffer_count, buff->dma_get_idx_current, buff->sw_put_idx); + } while (free_item_count < count+1); + + /* Fillup buffer (max is buffer end, wrap around afterwards) */ + insert_ptr = (char *)data_to_insert; + dest_ptr = &((char *)buff->src_buffer)[buff->sw_put_idx * buff->element_size]; + if (buff->buffer_count - buff->sw_put_idx >= count) { + memcpy(dest_ptr, insert_ptr, buff->element_size * count); + buff->sw_put_idx += count; + if(buff->sw_put_idx >= buff->buffer_count) + buff->sw_put_idx = 0; + } else { + first_round_count = buff->element_size * (buff->buffer_count - buff->sw_put_idx); + memcpy(dest_ptr, insert_ptr, first_round_count); + insert_ptr += first_round_count; + memcpy(buff->src_buffer, insert_ptr, count - first_round_count); + buff->sw_put_idx = count - first_round_count; + } + queue_or_start_dma_transfer(buff); + +return_retval: + return ret; +} + +void dma_ring_buffer_mem_to_periph_int_callback(struct dma_ring_buffer_to_periph *buff) +{ + /* update current get index */ + buff->dma_get_idx_current = buff->dma_get_idx_future; + queue_or_start_dma_transfer(buff); +} + +void dma_ring_buffer_mem_to_periph_stop(struct dma_ring_buffer_to_periph *buff) +{ + buff->dma->CR = 0; + dma_ring_buffer_switch_clock_enable(buff->dma_base_id, false); + + memset(buff, 0, sizeof(struct dma_ring_buffer_to_periph)); +} diff --git a/stm-firmware/uart/uart.c b/stm-firmware/uart/uart.c index 7dc1bf8..1314543 100644 --- a/stm-firmware/uart/uart.c +++ b/stm-firmware/uart/uart.c @@ -13,10 +13,12 @@ #include #include #include +#include static struct dma_ring_buffer_to_mem ring_buff_rx; +static struct dma_ring_buffer_to_periph ring_buff_tx; static char uart_rx_buffer[64]; - +static char uart_tx_buffer[256]; #ifdef DEBUGBUILD static inline void uart_gpio_config() @@ -41,6 +43,10 @@ void uart_init_with_dma() dma_ring_buffer_periph_to_mem_initialize(&ring_buff_rx, 2, UART_RECEIVE_DMA_STREAM, sizeof(uart_rx_buffer), 1U, uart_rx_buffer, (char *)&UART_PERIPH->DR, 4); + dma_ring_buffer_mem_to_periph_initialize(&ring_buff_tx, 2, UART_SEND_DMA_STREAM, sizeof(uart_tx_buffer), 1U, + uart_tx_buffer, 4U, (void *)&UART_PERIPH->DR); + + NVIC_EnableIRQ(DMA2_Stream7_IRQn); } void uart_disable() @@ -49,7 +55,7 @@ void uart_disable() UART_PERIPH->CR2 = 0; UART_PERIPH->CR3 = 0; dma_ring_buffer_periph_to_mem_stop(&ring_buff_rx); - + dma_ring_buffer_mem_to_periph_stop(&ring_buff_tx); rcc_manager_disable_clock(&RCC->AHB1ENR, BITMASK_TO_BITNO(UART_PORT_RCC_MASK)); rcc_manager_disable_clock(&RCC->APB2ENR, BITMASK_TO_BITNO(UART_RCC_MASK)); } @@ -68,7 +74,7 @@ void uart_send_array(const char *data, uint32_t len) uart_send_char(data[i]); } -void uart_send_string(char *string) +void uart_send_string(const char *string) { int i; @@ -76,11 +82,30 @@ void uart_send_string(char *string) uart_send_char(string[i]); } -void uart_send_array_with_dma(char *data, uint32_t len); +void uart_send_array_with_dma(const char *data, uint32_t len) +{ + dma_ring_buffer_mem_to_periph_insert_data(&ring_buff_tx, data, len); +} -void uart_send_string_with_dma(char *string); +void uart_send_string_with_dma(const char *string) +{ + size_t len; + + len = strlen(string); + uart_send_array_with_dma(string, (uint32_t)len); +} int uart_receive_data_with_dma(const char **data, size_t *len) { return dma_ring_buffer_periph_to_mem_get_data(&ring_buff_rx, (const void **)data, len); } + +void DMA2_Stream7_IRQHandler() +{ + uint32_t hisr = DMA2->HISR; + DMA2->HIFCR = hisr; + + if (hisr & DMA_HISR_TCIF7) { + dma_ring_buffer_mem_to_periph_int_callback(&ring_buff_tx); + } +}