From 3dcdc5b26f769ce9131b8a476d8dbe8992f1284e Mon Sep 17 00:00:00 2001 From: Gareth McMullin Date: Sat, 26 May 2012 20:57:47 +1200 Subject: Improve USB UART handling. Fix interrupt priorities. --- src/stm32/cdcacm.c | 6 +++--- src/stm32/platform.c | 26 ++++++++++++++++++++++++-- src/stm32/platform.h | 12 ++++++++++++ src/stm32/traceswo.c | 2 +- 4 files changed, 40 insertions(+), 6 deletions(-) diff --git a/src/stm32/cdcacm.c b/src/stm32/cdcacm.c index 6a70acc..99efaf8 100644 --- a/src/stm32/cdcacm.c +++ b/src/stm32/cdcacm.c @@ -521,7 +521,7 @@ static void cdcacm_set_config(u16 wValue) /* Serial interface */ usbd_ep_setup(0x03, USB_ENDPOINT_ATTR_BULK, CDCACM_PACKET_SIZE, cdcacm_data_rx_cb); - usbd_ep_setup(0x83, USB_ENDPOINT_ATTR_BULK, CDCACM_PACKET_SIZE, NULL); + usbd_ep_setup(0x83, USB_ENDPOINT_ATTR_BULK, CDCACM_PACKET_SIZE, uart_usb_buf_drain); usbd_ep_setup(0x84, USB_ENDPOINT_ATTR_INTERRUPT, 16, NULL); /* Trace interface */ @@ -563,9 +563,9 @@ void cdcacm_init(void) usbd_set_control_buffer_size(sizeof(usbd_control_buffer)); usbd_register_set_config_callback(cdcacm_set_config); - nvic_set_priority(NVIC_USB_LP_CAN_RX0_IRQ, 1); + nvic_set_priority(NVIC_USB_LP_CAN_RX0_IRQ, IRQ_PRI_USB); nvic_enable_irq(NVIC_USB_LP_CAN_RX0_IRQ); - nvic_set_priority(USB_VBUS_IRQ, 14); + nvic_set_priority(USB_VBUS_IRQ, IRQ_PRI_USB_VBUS); nvic_enable_irq(USB_VBUS_IRQ); gpio_set(USB_VBUS_PORT, USB_VBUS_PIN); diff --git a/src/stm32/platform.c b/src/stm32/platform.c index 522e920..8218894 100644 --- a/src/stm32/platform.c +++ b/src/stm32/platform.c @@ -238,15 +238,37 @@ static void uart_init(void) /* Enable interrupts */ USART1_CR1 |= USART_CR1_RXNEIE; - nvic_set_priority(NVIC_USART1_IRQ, 14); + nvic_set_priority(NVIC_USART1_IRQ, IRQ_PRI_USART1); nvic_enable_irq(NVIC_USART1_IRQ); } +static uint8_t uart_usb_buf[CDCACM_PACKET_SIZE]; +static uint8_t uart_usb_buf_size; + +void uart_usb_buf_drain(uint8_t ep) +{ + if (!uart_usb_buf_size) + return; + + usbd_ep_write_packet(ep, uart_usb_buf, uart_usb_buf_size); + uart_usb_buf_size = 0; +} + void usart1_isr(void) { char c = usart_recv(USART1); - usbd_ep_write_packet(0x83, &c, 1); + /* Try to send now */ + if (usbd_ep_write_packet(0x83, &c, 1) == 1) + return; + + /* We failed, so queue for later */ + if (uart_usb_buf_size == CDCACM_PACKET_SIZE) { + /* Drop if the buffer's full: we have no flow control */ + return; + } + + uart_usb_buf[uart_usb_buf_size++] = c; } #endif diff --git a/src/stm32/platform.h b/src/stm32/platform.h index ab292d9..5b546ca 100644 --- a/src/stm32/platform.h +++ b/src/stm32/platform.h @@ -80,6 +80,15 @@ #define LED_IDLE GPIO10 #define LED_ERROR GPIO11 +/* Interrupt priorities. Low numbers are high priority. + * For now USART1 preempts USB which may spin while buffer is drained. + * TIM3 is used for traceswo capture and must be highest priority. + */ +#define IRQ_PRI_USB (2 << 4) +#define IRQ_PRI_USART1 (1 << 4) +#define IRQ_PRI_USB_VBUS (14 << 4) +#define IRQ_PRI_TIM3 (0 << 4) + #define DEBUG(...) extern uint8_t running_status; @@ -121,6 +130,9 @@ void cdcacm_init(void); int cdcacm_get_config(void); int cdcacm_get_dtr(void); +/* */ +void uart_usb_buf_drain(uint8_t ep); + /* Use newlib provided integer only stdio functions */ #define sscanf siscanf #define sprintf siprintf diff --git a/src/stm32/traceswo.c b/src/stm32/traceswo.c index 0451210..926a057 100644 --- a/src/stm32/traceswo.c +++ b/src/stm32/traceswo.c @@ -68,7 +68,7 @@ void traceswo_init(void) timer_slave_set_mode(TIM3, TIM_SMCR_SMS_RM); /* Enable capture interrupt */ - nvic_set_priority(NVIC_TIM3_IRQ, 0); + nvic_set_priority(NVIC_TIM3_IRQ, IRQ_PRI_TIM3); nvic_enable_irq(NVIC_TIM3_IRQ); timer_enable_irq(TIM3, TIM_DIER_CC1IE); -- cgit v1.2.3