diff --git a/Firmware/Inc/freertos_vars.h b/Firmware/Inc/freertos_vars.h index fd0bf85d..9a08d016 100644 --- a/Firmware/Inc/freertos_vars.h +++ b/Firmware/Inc/freertos_vars.h @@ -4,10 +4,14 @@ // List of semaphore osSemaphoreId sem_usb_irq; +osSemaphoreId sem_uart_dma; +osSemaphoreId sem_usb_rx; +osSemaphoreId sem_usb_tx; // List of threads osThreadId thread_motor_0; osThreadId thread_motor_1; osThreadId thread_cmd_parse; +osThreadId thread_usb_pump; #endif /* __FREERTOS_H */ \ No newline at end of file diff --git a/Firmware/Middlewares/ST/STM32_USB_Device_Library/Class/CDC/Src/usbd_cdc.c b/Firmware/Middlewares/ST/STM32_USB_Device_Library/Class/CDC/Src/usbd_cdc.c index b2ca5f16..345b0b0f 100644 --- a/Firmware/Middlewares/ST/STM32_USB_Device_Library/Class/CDC/Src/usbd_cdc.c +++ b/Firmware/Middlewares/ST/STM32_USB_Device_Library/Class/CDC/Src/usbd_cdc.c @@ -62,6 +62,8 @@ #include "usbd_cdc.h" #include "usbd_desc.h" #include "usbd_ctlreq.h" +#include +#include /** @addtogroup STM32_USB_DEVICE_LIBRARY @@ -669,7 +671,7 @@ static uint8_t USBD_CDC_DataIn (USBD_HandleTypeDef *pdev, uint8_t epnum) { hcdc->TxState = 0; - + osSemaphoreRelease(sem_usb_tx); return USBD_OK; } else diff --git a/Firmware/MotorControl/commands.c b/Firmware/MotorControl/commands.c index 0c01ccd9..76006a54 100644 --- a/Firmware/MotorControl/commands.c +++ b/Firmware/MotorControl/commands.c @@ -4,6 +4,7 @@ #include #include #include +#include extern PCD_HandleTypeDef hpcd_USB_OTG_FS; @@ -21,6 +22,10 @@ SerialPrintf_t serial_printf_select = SERIAL_PRINTF_IS_NONE; static const GpioMode_t gpio_mode = GPIO_MODE_UART; //GPIO 1,2 is UART Tx,Rx // static const GpioMode_t gpio_mode = GPIO_MODE_STEP_DIR; //GPIO 1,2 is M0 Step,Dir +static uint8_t* usb_buf; +static uint32_t usb_len; +extern USBD_HandleTypeDef hUsbDeviceFS; + // variables exposed to usb/serial interface via set/get/monitor // Note: this will be depricated soon static float* const exposed_floats[] = { @@ -163,6 +168,10 @@ void motor_parse_cmd(uint8_t* buffer, int len, SerialPrintf_t response_interface if (numscan == 2 && motor_number < num_motors) { set_current_setpoint(&motors[motor_number], current_feed_forward); } + } else if(buffer[0] == 'e'){ + int val = printf("Test 1\n"); + int val2 = printf("test 2\n"); + val = 0; } else if (buffer[0] == 'g') { // GET // g <0:float,1:int,2:bool,3:uint16> index int type = 0; @@ -338,18 +347,35 @@ void cmd_parse_thread(void const * argument) { // 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); + const uint32_t usb_check_timeout = 1; // ms + osStatus sem_stat = osSemaphoreWait(sem_usb_rx, usb_check_timeout); + if (sem_stat == osOK) { + motor_parse_cmd(usb_buf, usb_len, SERIAL_PRINTF_IS_USB); + USBD_CDC_ReceivePacket(&hUsbDeviceFS); // Allow next packet } } while (!reset_read_state); } - // If we get here, then this task is done vTaskDelete(osThreadGetId()); +} + +// Called from CDC_Receive_FS callback function, this allows motor_parse_cmd to access the +// incoming USB data +void set_cmd_buffer(uint8_t *buf, uint32_t len) { + usb_buf = buf; + usb_len = len; +} + +void usb_update_thread() { + for (;;) { + // Wait for signalling from USB interrupt (OTG_FS_IRQHandler) + osStatus semaphore_status = osSemaphoreWait(sem_usb_irq, osWaitForever); + 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); + } + } + vTaskDelete(osThreadGetId()); } \ No newline at end of file diff --git a/Firmware/MotorControl/commands.h b/Firmware/MotorControl/commands.h index 1483af9c..1cb5ad31 100644 --- a/Firmware/MotorControl/commands.h +++ b/Firmware/MotorControl/commands.h @@ -27,4 +27,7 @@ void init_communication(); void cmd_parse_thread(void const * argument); void motor_parse_cmd(uint8_t* buffer, int len, SerialPrintf_t response_interface); +void set_cmd_buffer(uint8_t *buf, uint32_t len); +void usb_update_thread(); + #endif /* COMMANDS_H */ diff --git a/Firmware/Src/freertos.c b/Firmware/Src/freertos.c index da369f40..e80163b2 100644 --- a/Firmware/Src/freertos.c +++ b/Firmware/Src/freertos.c @@ -88,10 +88,24 @@ void MX_FREERTOS_Init(void) { /* USER CODE END RTOS_MUTEX */ /* USER CODE BEGIN RTOS_SEMAPHORES */ - // Init usb irq binary semaphore, and start with no tolkens by removing the starting one. + // Init usb irq binary semaphore, and start with no tokens by removing the starting one. osSemaphoreDef(sem_usb_irq); sem_usb_irq = osSemaphoreCreate(osSemaphore(sem_usb_irq), 1); osSemaphoreWait(sem_usb_irq, 0); + + // Create a semaphore for UART DMA and remove a token + osSemaphoreDef(sem_uart_dma); + sem_uart_dma = osSemaphoreCreate(osSemaphore(sem_uart_dma), 1); + + // Create a semaphore for USB RX + osSemaphoreDef(sem_usb_rx); + sem_usb_rx = osSemaphoreCreate(osSemaphore(sem_usb_rx), 1); + osSemaphoreWait(sem_usb_irq, 0); // Remove a token. + + // Create a semaphore for USB RX + osSemaphoreDef(sem_usb_tx); + sem_usb_tx = osSemaphoreCreate(osSemaphore(sem_usb_tx), 1); + /* USER CODE END RTOS_SEMAPHORES */ /* USER CODE BEGIN RTOS_TIMERS */ @@ -132,10 +146,14 @@ void StartDefaultTask(void const * argument) thread_motor_0 = osThreadCreate(osThread(task_motor_0), &motors[0]); thread_motor_1 = osThreadCreate(osThread(task_motor_1), &motors[1]); - // Start USB command handling thread + // Start command handling thread osThreadDef(task_cmd_parse, cmd_parse_thread, osPriorityNormal, 0, 512); thread_cmd_parse = osThreadCreate(osThread(task_cmd_parse), NULL); + // Start USB interrupt handler thread + osThreadDef(task_usb_pump, usb_update_thread, osPriorityNormal, 0, 512); + thread_usb_pump = osThreadCreate(osThread(task_usb_pump), NULL); + //If we get to here, then the default task is done. vTaskDelete(defaultTaskHandle); diff --git a/Firmware/Src/syscalls.c b/Firmware/Src/syscalls.c index 3cd2a073..0f850cda 100644 --- a/Firmware/Src/syscalls.c +++ b/Firmware/Src/syscalls.c @@ -5,11 +5,12 @@ ****************************************************************************** */ -#include -#include -#include +#include #include - +#include +#include +#include +#include //int _read(int file, char *data, int len) {} //int _close(int file) {} @@ -20,34 +21,43 @@ #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) { +int _write(int file, char* data, int len) { + //number of bytes written + int written = 0; + switch (serial_printf_select) { + case SERIAL_PRINTF_IS_USB: { + // Wait on semaphore for the interface to be available + // Note that the USB driver will release the interface again when the TX completes + const uint32_t usb_tx_timeout = 100; // ms + osStatus sem_stat = osSemaphoreWait(sem_usb_tx, usb_tx_timeout); + if (sem_stat == osOK) { + uint8_t status = CDC_Transmit_FS((uint8_t*)data, len); // transmit over CDC + written = (status == USBD_OK) ? len : 0; + } // If the semaphore times out, we simply leave "written" as 0 + } break; - 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: { + //Check length + if (len > UART_TX_BUFFER_SIZE) + return 0; + // Wait on semaphore for the interface to be available + // Note that HAL_UART_TxCpltCallback will release the interface again when the TX completes + const uint32_t uart_tx_timeout = 100; // ms + osStatus sem_stat = osSemaphoreWait(sem_uart_dma, uart_tx_timeout); + if (sem_stat == osOK) { + memcpy(uart_tx_buf, data, len); // memcpy data into uart_tx_buf + HAL_UART_Transmit_DMA(&huart4, uart_tx_buf, len); // Start DMA background transfer + } // If the semaphore times out, we simply leave "written" as 0 + } break; - 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; + } - default: { - written = 0; - } break; - } - - return written; + return written; +} + +void HAL_UART_TxCpltCallback(UART_HandleTypeDef* huart) { + osSemaphoreRelease(sem_uart_dma); } diff --git a/Firmware/Src/usbd_cdc_if.c b/Firmware/Src/usbd_cdc_if.c index 8f6b7317..475c969e 100644 --- a/Firmware/Src/usbd_cdc_if.c +++ b/Firmware/Src/usbd_cdc_if.c @@ -51,6 +51,7 @@ /* USER CODE BEGIN INCLUDE */ #include "utils.h" #include "commands.h" +#include /* USER CODE END INCLUDE */ /** @addtogroup STM32_USB_OTG_DEVICE_LIBRARY @@ -272,10 +273,8 @@ static int8_t CDC_Receive_FS (uint8_t* Buf, uint32_t *Len) int modified_len = MACRO_MIN(*Len+1, APP_RX_DATA_SIZE); Buf[modified_len-1] = 0; - motor_parse_cmd(Buf, modified_len, SERIAL_PRINTF_IS_USB); - - // Allow next packet - USBD_CDC_ReceivePacket(&hUsbDeviceFS); + set_cmd_buffer(Buf, modified_len); + osSemaphoreRelease(sem_usb_rx); return (USBD_OK); /* USER CODE END 6 */