From 9abec8af005d5eaf9115e7070b6164a86980a0c8 Mon Sep 17 00:00:00 2001 From: Oskar Weigl Date: Sat, 23 Sep 2017 20:31:43 -0700 Subject: [PATCH] implement UART read state machine --- Makefile | 1 + Src/freertos.c | 59 +++++++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 59 insertions(+), 1 deletion(-) diff --git a/Makefile b/Makefile index e2033d82..a852af35 100644 --- a/Makefile +++ b/Makefile @@ -51,6 +51,7 @@ C_SOURCES = \ Src/stm32f4xx_hal_msp.c \ Src/can.c \ Src/usart.c \ + Src/dma.c \ Src/usbd_conf.c \ Src/usbd_desc.c \ Src/usb_device.c \ diff --git a/Src/freertos.c b/Src/freertos.c index e62c1813..41094c23 100644 --- a/Src/freertos.c +++ b/Src/freertos.c @@ -54,6 +54,7 @@ /* USER CODE BEGIN Includes */ #include "freertos_vars.h" #include "low_level.h" +#include "usart.h" #include "version.h" /* USER CODE END Includes */ @@ -142,6 +143,7 @@ void StartDefaultTask(void const * argument) /* USER CODE BEGIN Application */ +//TODO move this to a different file // Thread to handle deffered processing of USB interrupt void usb_cmd_thread(void const * argument) { @@ -152,7 +154,62 @@ void usb_cmd_thread(void const * argument) { // check for end-char // checksum, etc. - + #define UART_BUFFER_SIZE 64 + static uint8_t dma_circ_buffer[UART_BUFFER_SIZE]; + static uint8_t parse_buffer[UART_BUFFER_SIZE]; + + // DMA is set up to recieve in a circular buffer forever. + // We dont use interrupts to fetch the data, instead we periodically read + // data out of the circular buffer into a parse buffer, controlled by a state machine + HAL_UART_Receive_DMA(&huart4, dma_circ_buffer, sizeof(dma_circ_buffer)); + + uint32_t last_rcv_idx = UART_BUFFER_SIZE - huart4.hdmarx->Instance->NDTR; + // Re-run state-machine forever + for (;;) { + //Inialize recieve state machine + bool reset_read_state = false; + bool read_active = false; + uint32_t parse_buffer_idx = 0; + //Run state machine until reset + do { + // Fetch the circular buffer "write pointer", where it would write next + uint32_t rcv_idx = UART_BUFFER_SIZE - huart4.hdmarx->Instance->NDTR; + // During sleeping, we may have fallen several characters behind, so we keep + // going until we are caught up, before we sleep again + while (rcv_idx != last_rcv_idx) { + // Fetch the next char, rotate read ptr + uint8_t c = dma_circ_buffer[last_rcv_idx]; + if (++last_rcv_idx == UART_BUFFER_SIZE) + last_rcv_idx = 0; + // Look for start character + if (c == '$') { + read_active = true; + continue; // do not record start char + } + // Record into parse buffer when actively reading + if (read_active) { + parse_buffer[parse_buffer_idx++] = c; + if (c == '\r' || c == '\n') { + // End of command string: exchange end char with terminating null + parse_buffer[parse_buffer_idx-1] = '\0'; + osDelay(1); + // Reset receieve state machine + reset_read_state = true; + break; + } else if (parse_buffer_idx == UART_BUFFER_SIZE - 1) { + // We are not at end of command, and receiving another character after this + // would go into the last slot, which is reserved for terminating null. + // We have effectively overflowed parse buffer: abort. + reset_read_state = true; + break; + } + } + } + // When we reach here, we are out of immediate characters to fetch out of buffer + // So we sleep for a bit. + osDelay(1); + } while (!reset_read_state); + } for (;;) { // Wait for signalling from USB interrupt (OTG_FS_IRQHandler)