From 23d7bbdeaa2fb5973fb9897c1ce2d8a354b67f7b Mon Sep 17 00:00:00 2001 From: Oskar Weigl Date: Tue, 10 Oct 2017 22:37:23 -0700 Subject: [PATCH] working bidirectional arbitrated UART and USB comms --- Inc/freertos_vars.h | 2 +- MotorControl/commands.c | 43 ++++++++++++++++++++--------------------- Src/freertos.c | 5 ++--- Src/syscalls.c | 23 +++++++++++++++++----- Src/usbd_cdc_if.c | 2 +- Src/usbd_desc.c | 2 +- 6 files changed, 44 insertions(+), 33 deletions(-) diff --git a/Inc/freertos_vars.h b/Inc/freertos_vars.h index a0bc6d2b..fd0bf85d 100644 --- a/Inc/freertos_vars.h +++ b/Inc/freertos_vars.h @@ -8,6 +8,6 @@ osSemaphoreId sem_usb_irq; // List of threads osThreadId thread_motor_0; osThreadId thread_motor_1; -osThreadId thread_usb_cmd; +osThreadId thread_cmd_parse; #endif /* __FREERTOS_H */ \ No newline at end of file diff --git a/MotorControl/commands.c b/MotorControl/commands.c index 83b0f3ee..1eeef4ac 100644 --- a/MotorControl/commands.c +++ b/MotorControl/commands.c @@ -1,4 +1,5 @@ /* Includes ------------------------------------------------------------------*/ +#include #include #include #include @@ -241,7 +242,7 @@ static void print_monitoring(int limit) { // Thread to handle deffered processing of USB interrupt, and // read commands out of the UART DMA circular buffer -void usb_cmd_thread(void const * argument) { +void cmd_parse_thread(void const * argument) { //DMA open loop continous circular buffer //1ms delay periodic, chase DMA ptr around, on new data: @@ -250,16 +251,16 @@ 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]; + #define UART_RX_BUFFER_SIZE 64 + static uint8_t dma_circ_buffer[UART_RX_BUFFER_SIZE]; + static uint8_t parse_buffer[UART_RX_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; + uint32_t last_rcv_idx = UART_RX_BUFFER_SIZE - huart4.hdmarx->Instance->NDTR; // Re-run state-machine forever for (;;) { //Inialize recieve state machine @@ -269,13 +270,13 @@ void usb_cmd_thread(void const * argument) { //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; + uint32_t rcv_idx = UART_RX_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) + if (++last_rcv_idx == UART_RX_BUFFER_SIZE) last_rcv_idx = 0; // Look for start character if (c == '$') { @@ -292,7 +293,7 @@ void usb_cmd_thread(void const * argument) { // Reset receieve state machine reset_read_state = true; break; - } else if (parse_buffer_idx == UART_BUFFER_SIZE - 1) { + } else if (parse_buffer_idx == UART_RX_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. @@ -301,23 +302,21 @@ void usb_cmd_thread(void const * argument) { } } } - // When we reach here, we are out of immediate characters to fetch out of buffer - // So we sleep for a bit. - osDelay(1); + // When we reach here, we are out of immediate characters to fetch out of UART buffer + // Now we check if there is any USB processing to do: we wait for up to 1 ms, + // before going back to checking UART again. + int USB_check_timeout = 1; + // Wait for signalling from USB interrupt (OTG_FS_IRQHandler) + osStatus semaphore_status = osSemaphoreWait(sem_usb_irq, USB_check_timeout); + if (semaphore_status == osOK) { + // We have a new incoming USB transmission: handle it + HAL_PCD_IRQHandler(&hpcd_USB_OTG_FS); + // Let the irq (OTG_FS_IRQHandler) fire again. + HAL_NVIC_EnableIRQ(OTG_FS_IRQn); + } } while (!reset_read_state); } - for (;;) { - // Wait for signalling from USB interrupt (OTG_FS_IRQHandler) - osSemaphoreWait(sem_usb_irq, osWaitForever); - // Irq processing loop - //while(HAL_NVIC_GetActive(OTG_FS_IRQn)) { - HAL_PCD_IRQHandler(&hpcd_USB_OTG_FS); - //} - // Let the irq (OTG_FS_IRQHandler) fire again. - HAL_NVIC_EnableIRQ(OTG_FS_IRQn); - } - // If we get here, then this task is done vTaskDelete(osThreadGetId()); } \ No newline at end of file diff --git a/Src/freertos.c b/Src/freertos.c index b8cee15a..62d3a451 100644 --- a/Src/freertos.c +++ b/Src/freertos.c @@ -71,7 +71,6 @@ extern void MX_USB_DEVICE_Init(void); void MX_FREERTOS_Init(void); /* (MISRA C 2004 rule 8.1) */ /* USER CODE BEGIN FunctionPrototypes */ -void usb_cmd_thread(void const * argument); /* USER CODE END FunctionPrototypes */ @@ -131,8 +130,8 @@ void StartDefaultTask(void const * argument) thread_motor_1 = osThreadCreate(osThread(task_motor_1), &motors[1]); // Start USB command handling thread - osThreadDef(task_usb_cmd, usb_cmd_thread, osPriorityNormal, 0, 512); - thread_usb_cmd = osThreadCreate(osThread(task_usb_cmd), NULL); + osThreadDef(task_cmd_parse, cmd_parse_thread, osPriorityNormal, 0, 512); + thread_cmd_parse = osThreadCreate(osThread(task_cmd_parse), NULL); //If we get to here, then the default task is done. vTaskDelete(defaultTaskHandle); diff --git a/Src/syscalls.c b/Src/syscalls.c index cce3b77e..3cd2a073 100644 --- a/Src/syscalls.c +++ b/Src/syscalls.c @@ -6,31 +6,44 @@ */ #include -#include "usbd_cdc_if.h" +#include +#include #include + //int _read(int file, char *data, int len) {} //int _close(int file) {} //int _lseek(int file, int ptr, int dir) {} //int _fstat(int file, struct stat *st) {} //int _isatty(int file) {} -//static char uart_tx_buf +#define UART_TX_BUFFER_SIZE 64 +static uint8_t uart_tx_buf[UART_TX_BUFFER_SIZE]; int _write(int file, char *data, int len) { - //number of bytes written int written = 0; - switch (serial_printf_select) { + case SERIAL_PRINTF_IS_USB: { // transmit over CDC uint8_t status = CDC_Transmit_FS((uint8_t*)data, len); written = (status == USBD_OK) ? len : 0; } break; - case SERIAL_PRINTF_IS_UART: { + case SERIAL_PRINTF_IS_UART: { + //Check length + if (len > UART_TX_BUFFER_SIZE) + return 0; + // Check if transfer is already ongoing + if(huart4.gState != HAL_UART_STATE_READY) + return 0; + // memcpy data into uart_tx_buf + memcpy(uart_tx_buf, data, len); + // Start DMA background trasnfer + HAL_UART_Transmit_DMA(&huart4, uart_tx_buf, len); } break; + default: { written = 0; } break; diff --git a/Src/usbd_cdc_if.c b/Src/usbd_cdc_if.c index 50696d9b..632c5f41 100644 --- a/Src/usbd_cdc_if.c +++ b/Src/usbd_cdc_if.c @@ -297,7 +297,7 @@ uint8_t CDC_Transmit_FS(uint8_t* Buf, uint16_t Len) uint8_t result = USBD_OK; /* USER CODE BEGIN 7 */ - //Check Len + //Check length if (Len > APP_TX_DATA_SIZE) return USBD_FAIL; // memcpy Buf into UserTxBufferFS diff --git a/Src/usbd_desc.c b/Src/usbd_desc.c index 1e8f425f..54a656ac 100644 --- a/Src/usbd_desc.c +++ b/Src/usbd_desc.c @@ -75,7 +75,7 @@ #define USBD_LANGID_STRING 1033 #define USBD_MANUFACTURER_STRING "ODrive" #define USBD_PID_FS 0x0D31 -#define USBD_PRODUCT_STRING_FS "ODrive rev 3.1" +#define USBD_PRODUCT_STRING_FS "ODrive v3.1" #define USBD_SERIALNUMBER_STRING_FS "000000000001" #define USBD_CONFIGURATION_STRING_FS "CDC Config" #define USBD_INTERFACE_STRING_FS "CDC Interface"