mirror of
https://github.com/odriverobotics/ODrive.git
synced 2026-08-29 15:15:55 +08:00
working bidirectional arbitrated UART and USB comms
This commit is contained in:
+1
-1
@@ -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 */
|
||||
+21
-22
@@ -1,4 +1,5 @@
|
||||
/* Includes ------------------------------------------------------------------*/
|
||||
#include <cmsis_os.h>
|
||||
#include <commands.h>
|
||||
#include <usart.h>
|
||||
#include <freertos_vars.h>
|
||||
@@ -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());
|
||||
}
|
||||
+2
-3
@@ -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);
|
||||
|
||||
+18
-5
@@ -6,31 +6,44 @@
|
||||
*/
|
||||
|
||||
#include <sys/unistd.h>
|
||||
#include "usbd_cdc_if.h"
|
||||
#include <usbd_cdc_if.h>
|
||||
#include <usart.h>
|
||||
#include <commands.h>
|
||||
|
||||
|
||||
//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;
|
||||
|
||||
+1
-1
@@ -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
|
||||
|
||||
+1
-1
@@ -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"
|
||||
|
||||
Reference in New Issue
Block a user