mirror of
https://github.com/odriverobotics/ODrive.git
synced 2026-09-22 08:04:07 +08:00
Merge pull request #57 from Wetmelon/usb_thread
Async USB Handling and printf blocking
This commit is contained in:
@@ -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 */
|
||||
@@ -62,6 +62,8 @@
|
||||
#include "usbd_cdc.h"
|
||||
#include "usbd_desc.h"
|
||||
#include "usbd_ctlreq.h"
|
||||
#include <cmsis_os.h>
|
||||
#include <freertos_vars.h>
|
||||
|
||||
|
||||
/** @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
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
#include <usart.h>
|
||||
#include <gpio.h>
|
||||
#include <freertos_vars.h>
|
||||
#include <usbd_cdc.h>
|
||||
|
||||
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());
|
||||
}
|
||||
@@ -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 */
|
||||
|
||||
+20
-2
@@ -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);
|
||||
|
||||
|
||||
+41
-31
@@ -5,11 +5,12 @@
|
||||
******************************************************************************
|
||||
*/
|
||||
|
||||
#include <sys/unistd.h>
|
||||
#include <usbd_cdc_if.h>
|
||||
#include <usart.h>
|
||||
#include <cmsis_os.h>
|
||||
#include <commands.h>
|
||||
|
||||
#include <freertos_vars.h>
|
||||
#include <sys/unistd.h>
|
||||
#include <usart.h>
|
||||
#include <usbd_cdc_if.h>
|
||||
|
||||
//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);
|
||||
}
|
||||
|
||||
@@ -51,6 +51,7 @@
|
||||
/* USER CODE BEGIN INCLUDE */
|
||||
#include "utils.h"
|
||||
#include "commands.h"
|
||||
#include <freertos_vars.h>
|
||||
/* 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 */
|
||||
|
||||
Reference in New Issue
Block a user