From 43f7e7a3cf384e880bfefa6257f15c8915b02e3b Mon Sep 17 00:00:00 2001 From: Allen Ibara Date: Wed, 27 Mar 2013 12:09:49 -0700 Subject: Changes to the USBUART to make it less likely to drop characters at higher baud rates. USB UART seems to work fine at 115.2Kbps or 230.4Kbps, but starts to drop characters as the data rate goes higher. This commit changes the usbuart ISR to fill a software FIFO, and adds a low priority timer interrupt to run deferred processing to drain a FIFO and send USB CDCACM packets, rather than calling the usb send within the UART ISR. Tested on native platform, up to 1.5MBps. --- src/platforms/f4discovery/platform.h | 5 ++ src/platforms/native/platform.c | 3 +- src/platforms/native/platform.h | 5 ++ src/platforms/stlink/platform.h | 5 ++ src/platforms/stm32/usbuart.c | 126 ++++++++++++++++++++++++++++------- src/platforms/swlink/platform.h | 5 ++ 6 files changed, 123 insertions(+), 26 deletions(-) (limited to 'src/platforms') diff --git a/src/platforms/f4discovery/platform.h b/src/platforms/f4discovery/platform.h index 0010ec4..c1423b6 100644 --- a/src/platforms/f4discovery/platform.h +++ b/src/platforms/f4discovery/platform.h @@ -112,6 +112,7 @@ extern usbd_device *usbdev; */ #define IRQ_PRI_USB (2 << 4) #define IRQ_PRI_USBUSART (1 << 4) +#define IRQ_PRI_USBUSART_TIM (3 << 4) #define IRQ_PRI_TRACE (0 << 4) #define USBUSART USART3 @@ -124,6 +125,10 @@ extern usbd_device *usbdev; #define USBUSART_RX_PORT GPIOD #define USBUSART_RX_PIN GPIO9 #define USBUSART_ISR usart3_isr +#define USBUSART_TIM TIM4 +#define USBUSART_TIM_CLK_EN() rcc_peripheral_enable_clock(&RCC_APB1ENR, RCC_APB1ENR_TIM4EN) +#define USBUSART_TIM_IRQ NVIC_TIM4_IRQ +#define USBUSART_TIM_ISR tim4_isr #define UART_PIN_SETUP() do { \ gpio_mode_setup(USBUSART_TX_PORT, GPIO_MODE_AF, GPIO_PUPD_NONE, \ diff --git a/src/platforms/native/platform.c b/src/platforms/native/platform.c index 24eb79b..3bd0816 100644 --- a/src/platforms/native/platform.c +++ b/src/platforms/native/platform.c @@ -108,8 +108,6 @@ int platform_init(void) systick_interrupt_enable(); systick_counter_enable(); - usbuart_init(); - if (platform_hwversion() > 0) { adc_init(); } else { @@ -121,6 +119,7 @@ int platform_init(void) SCB_VTOR = 0x2000; // Relocate interrupt vector table here cdcacm_init(); + usbuart_init(); jtag_scan(NULL); diff --git a/src/platforms/native/platform.h b/src/platforms/native/platform.h index a1471dc..eb91f8b 100644 --- a/src/platforms/native/platform.h +++ b/src/platforms/native/platform.h @@ -122,6 +122,7 @@ extern usbd_device *usbdev; */ #define IRQ_PRI_USB (2 << 4) #define IRQ_PRI_USBUSART (1 << 4) +#define IRQ_PRI_USBUSART_TIM (3 << 4) #define IRQ_PRI_USB_VBUS (14 << 4) #define IRQ_PRI_TRACE (0 << 4) @@ -133,6 +134,10 @@ extern usbd_device *usbdev; #define USBUSART_PORT GPIOA #define USBUSART_TX_PIN GPIO9 #define USBUSART_ISR usart1_isr +#define USBUSART_TIM TIM4 +#define USBUSART_TIM_CLK_EN() rcc_peripheral_enable_clock(&RCC_APB1ENR, RCC_APB1ENR_TIM4EN) +#define USBUSART_TIM_IRQ NVIC_TIM4_IRQ +#define USBUSART_TIM_ISR tim4_isr #define TRACE_TIM TIM3 #define TRACE_TIM_CLK_EN() rcc_peripheral_enable_clock(&RCC_APB1ENR, RCC_APB1ENR_TIM3EN) diff --git a/src/platforms/stlink/platform.h b/src/platforms/stlink/platform.h index cbfc0ba..09fab96 100644 --- a/src/platforms/stlink/platform.h +++ b/src/platforms/stlink/platform.h @@ -107,6 +107,7 @@ extern usbd_device *usbdev; */ #define IRQ_PRI_USB (2 << 4) #define IRQ_PRI_USBUSART (1 << 4) +#define IRQ_PRI_USBUSART_TIM (3 << 4) #define IRQ_PRI_USB_VBUS (14 << 4) #define IRQ_PRI_TIM3 (0 << 4) @@ -118,6 +119,10 @@ extern usbd_device *usbdev; #define USBUSART_PORT GPIOA #define USBUSART_TX_PIN GPIO2 #define USBUSART_ISR usart2_isr +#define USBUSART_TIM TIM4 +#define USBUSART_TIM_CLK_EN() rcc_peripheral_enable_clock(&RCC_APB1ENR, RCC_APB1ENR_TIM4EN) +#define USBUSART_TIM_IRQ NVIC_TIM4_IRQ +#define USBUSART_TIM_ISR tim4_isr #define DEBUG(...) diff --git a/src/platforms/stm32/usbuart.c b/src/platforms/stm32/usbuart.c index 1c71105..6694d90 100644 --- a/src/platforms/stm32/usbuart.c +++ b/src/platforms/stm32/usbuart.c @@ -21,6 +21,7 @@ #include #include #include +#include #include #include #include @@ -28,6 +29,20 @@ #include +#define USBUART_TIMER_FREQ_HZ 1000000U /* 1us per tick */ +#define USBUART_RUN_FREQ_HZ 5000U /* 200us (or 100 characters at 2Mbps) */ + +#define FIFO_SIZE 128 + +/* RX Fifo buffer */ +static uint8_t buf_rx[FIFO_SIZE]; +/* Fifo in pointer, writes assumed to be atomic, should be only incremented within RX ISR */ +static uint8_t buf_rx_in; +/* Fifo out pointer, writes assumed to be atomic, should be only incremented outside RX ISR */ +static uint8_t buf_rx_out; + +static void usbuart_run(void); + void usbuart_init(void) { #if defined(BLACKMAGIC) @@ -56,6 +71,62 @@ void usbuart_init(void) USBUSART_CR1 |= USART_CR1_RXNEIE; nvic_set_priority(USBUSART_IRQ, IRQ_PRI_USBUSART); nvic_enable_irq(USBUSART_IRQ); + + /* Setup timer for running deferred FIFO processing */ + USBUSART_TIM_CLK_EN(); + timer_reset(USBUSART_TIM); + timer_set_mode(USBUSART_TIM, TIM_CR1_CKD_CK_INT, TIM_CR1_CMS_EDGE, TIM_CR1_DIR_UP); + timer_set_prescaler(USBUSART_TIM, rcc_ppre2_frequency/TIMER_FREQ_HZ*2 - 1); + timer_set_period(USBUSART_TIM, TIMER_FREQ_HZ/USBUART_RUN_FREQ_HZ - 1); + + /* Setup update interrupt in NVIC */ + nvic_set_priority(USBUSART_TIM_IRQ, IRQ_PRI_USBUSART_TIM); + nvic_enable_irq(USBUSART_TIM_IRQ); + + /* turn the timer on */ + timer_enable_counter(USBUSART_TIM); +} + +/* + * Runs deferred processing for usb uart rx, draining RX FIFO by sending characters to host PC via CDCACM. + * Allowed to read from FIFO in pointer, but not write to it. Allowed to write to FIFO out pointer. + */ +static void usbuart_run(void) +{ + /* forcibly empty fifo if no USB endpoint */ + if (cdcacm_get_config() != 1) + { + buf_rx_out = buf_rx_in; + } + + /* if fifo empty, nothing further to do */ + if (buf_rx_in == buf_rx_out) { + /* turn off LED, disable IRQ */ + timer_disable_irq(USBUSART_TIM, TIM_DIER_UIE); + gpio_clear(LED_PORT_UART, LED_UART); + } + else + { + uint8_t packet_buf[CDCACM_PACKET_SIZE]; + uint8_t packet_size = 0; + uint8_t buf_out = buf_rx_out; + + /* copy from uart FIFO into local usb packet buffer */ + while (buf_rx_in != buf_out && packet_size < CDCACM_PACKET_SIZE) + { + packet_buf[packet_size++] = buf_rx[buf_out++]; + + /* wrap out pointer */ + if (buf_out >= FIFO_SIZE) + { + buf_out = 0; + } + + } + + /* advance fifo out pointer by amount written */ + buf_rx_out = (buf_rx_out + usbd_ep_write_packet(usbdev, CDCACM_UART_ENDPOINT, packet_buf, packet_size)) % FIFO_SIZE; + } } void usbuart_set_line_coding(struct usb_cdc_line_coding *coding) @@ -108,41 +179,48 @@ void usbuart_usb_out_cb(usbd_device *dev, uint8_t ep) gpio_clear(LED_PORT_UART, LED_UART); } -static uint8_t uart_usb_buf[CDCACM_PACKET_SIZE]; -static uint8_t uart_usb_buf_size; void usbuart_usb_in_cb(usbd_device *dev, uint8_t ep) { - if (!uart_usb_buf_size) { - gpio_clear(LED_PORT_UART, LED_UART); - return; - } - - usbd_ep_write_packet(dev, ep, uart_usb_buf, uart_usb_buf_size); - uart_usb_buf_size = 0; + (void) dev; + (void) ep; } +/* + * Read a character from the UART RX and stuff it in a software FIFO. + * Allowed to read from FIFO out pointer, but not write to it. Allowed to write to FIFO in pointer. + */ void USBUSART_ISR(void) { char c = usart_recv(USBUSART); - /* Don't try to write until we are configured. - * Otherwise enumeration hanged in some cases. - */ - if (cdcacm_get_config() != 1) - return; - + /* Turn on LED */ gpio_set(LED_PORT_UART, LED_UART); - /* Try to send now */ - if (usbd_ep_write_packet(usbdev, CDCACM_UART_ENDPOINT, &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; + /* If the next increment of rx_in would put it at the same point + * as rx_out, the FIFO is considered full. + */ + if (((buf_rx_in + 1) % FIFO_SIZE) != buf_rx_out) + { + /* insert into FIFO */ + buf_rx[buf_rx_in++] = c; + + /* wrap out pointer */ + if (buf_rx_in >= FIFO_SIZE) + { + buf_rx_in = 0; + } + + /* enable deferred processing if we put data in the FIFO */ + timer_enable_irq(USBUSART_TIM, TIM_DIER_UIE); } +} + +void USBUSART_TIM_ISR(void) +{ + /* need to clear timer update event */ + timer_clear_flag(USBUSART_TIM, TIM_SR_UIF); - uart_usb_buf[uart_usb_buf_size++] = c; + /* process FIFO */ + usbuart_run(); } diff --git a/src/platforms/swlink/platform.h b/src/platforms/swlink/platform.h index 469499f..c7eaca5 100644 --- a/src/platforms/swlink/platform.h +++ b/src/platforms/swlink/platform.h @@ -106,6 +106,7 @@ extern usbd_device *usbdev; */ #define IRQ_PRI_USB (2 << 4) #define IRQ_PRI_USBUSART (1 << 4) +#define IRQ_PRI_USBUSART_TIM (3 << 4) #define IRQ_PRI_USB_VBUS (14 << 4) #define IRQ_PRI_TRACE (0 << 4) @@ -117,6 +118,10 @@ extern usbd_device *usbdev; #define USBUSART_PORT GPIOB #define USBUSART_TX_PIN GPIO6 #define USBUSART_ISR usart1_isr +#define USBUSART_TIM TIM4 +#define USBUSART_TIM_CLK_EN() rcc_peripheral_enable_clock(&RCC_APB1ENR, RCC_APB1ENR_TIM4EN) +#define USBUSART_TIM_IRQ NVIC_TIM4_IRQ +#define USBUSART_TIM_ISR tim4_isr #define TRACE_TIM TIM2 #define TRACE_TIM_CLK_EN() rcc_peripheral_enable_clock(&RCC_APB1ENR, RCC_APB1ENR_TIM2EN) -- cgit v1.2.3 From e3f3171a33f12064b876b98b537f2c6347761f42 Mon Sep 17 00:00:00 2001 From: Gareth McMullin Date: Sat, 27 Apr 2013 13:14:22 -0700 Subject: usbuart: Fix build error and clean up whitespace. --- src/platforms/stm32/usbuart.c | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) (limited to 'src/platforms') diff --git a/src/platforms/stm32/usbuart.c b/src/platforms/stm32/usbuart.c index 6694d90..7f5ebde 100644 --- a/src/platforms/stm32/usbuart.c +++ b/src/platforms/stm32/usbuart.c @@ -75,9 +75,12 @@ void usbuart_init(void) /* Setup timer for running deferred FIFO processing */ USBUSART_TIM_CLK_EN(); timer_reset(USBUSART_TIM); - timer_set_mode(USBUSART_TIM, TIM_CR1_CKD_CK_INT, TIM_CR1_CMS_EDGE, TIM_CR1_DIR_UP); - timer_set_prescaler(USBUSART_TIM, rcc_ppre2_frequency/TIMER_FREQ_HZ*2 - 1); - timer_set_period(USBUSART_TIM, TIMER_FREQ_HZ/USBUART_RUN_FREQ_HZ - 1); + timer_set_mode(USBUSART_TIM, TIM_CR1_CKD_CK_INT, + TIM_CR1_CMS_EDGE, TIM_CR1_DIR_UP); + timer_set_prescaler(USBUSART_TIM, + rcc_ppre2_frequency / USBUART_TIMER_FREQ_HZ * 2 - 1); + timer_set_period(USBUSART_TIM, + USBUART_TIMER_FREQ_HZ / USBUART_RUN_FREQ_HZ - 1); /* Setup update interrupt in NVIC */ nvic_set_priority(USBUSART_TIM_IRQ, IRQ_PRI_USBUSART_TIM); @@ -88,8 +91,9 @@ void usbuart_init(void) } /* - * Runs deferred processing for usb uart rx, draining RX FIFO by sending characters to host PC via CDCACM. - * Allowed to read from FIFO in pointer, but not write to it. Allowed to write to FIFO out pointer. + * Runs deferred processing for usb uart rx, draining RX FIFO by sending + * characters to host PC via CDCACM. Allowed to read from FIFO in pointer, + * but not write to it. Allowed to write to FIFO out pointer. */ static void usbuart_run(void) { @@ -125,7 +129,9 @@ static void usbuart_run(void) } /* advance fifo out pointer by amount written */ - buf_rx_out = (buf_rx_out + usbd_ep_write_packet(usbdev, CDCACM_UART_ENDPOINT, packet_buf, packet_size)) % FIFO_SIZE; + buf_rx_out += usbd_ep_write_packet(usbdev, + CDCACM_UART_ENDPOINT, packet_buf, packet_size); + buf_rx_out %= FIFO_SIZE; } } @@ -188,7 +194,8 @@ void usbuart_usb_in_cb(usbd_device *dev, uint8_t ep) /* * Read a character from the UART RX and stuff it in a software FIFO. - * Allowed to read from FIFO out pointer, but not write to it. Allowed to write to FIFO in pointer. + * Allowed to read from FIFO out pointer, but not write to it. + * Allowed to write to FIFO in pointer. */ void USBUSART_ISR(void) { @@ -224,3 +231,4 @@ void USBUSART_TIM_ISR(void) /* process FIFO */ usbuart_run(); } + -- cgit v1.2.3