From f354dc067f8a78ff824a909d73f28a487b6f5a6c Mon Sep 17 00:00:00 2001 From: Devan Lai Date: Sat, 20 May 2017 21:50:20 -0700 Subject: [PATCH 1/2] Import DMA-driven UART RX Port DMA-driven circular buffer for UART RX from the termlink project Bump RX buffer sizes to 1KiB/4KiB for F042/F103 targets, respectively Fix USART mapping for STLINKV2-1-STBOOT target --- src/console.c | 100 +++++++++++++++++-------- src/stm32f042/brain3.3/config.h | 5 +- src/stm32f042/dap42/config.h | 5 +- src/stm32f042/dap42k6u/config.h | 5 +- src/stm32f042/kitchen42/config.h | 5 +- src/stm32f103/stlinkv2-1/config.h | 16 ++-- src/stm32f103/stlinkv2-dongle/config.h | 8 +- 7 files changed, 102 insertions(+), 42 deletions(-) diff --git a/src/console.c b/src/console.c index 226ab74..c143e1b 100644 --- a/src/console.c +++ b/src/console.c @@ -17,6 +17,8 @@ */ #include +#include +#include #include "console.h" #include "target.h" @@ -36,16 +38,32 @@ void console_setup(uint32_t baudrate) { usart_enable(CONSOLE_USART); nvic_enable_irq(CONSOLE_USART_NVIC_LINE); + rcc_periph_clock_enable(CONSOLE_RX_DMA_CLOCK); } void console_tx_buffer_clear(void); void console_rx_buffer_clear(void); +#define IS_POW_OF_TWO(X) (((X) & ((X)-1)) == 0) +_Static_assert(IS_POW_OF_TWO(CONSOLE_TX_BUFFER_SIZE), + "Unmasked circular buffer size must be a power of two"); +_Static_assert(CONSOLE_TX_BUFFER_SIZE <= UINT16_MAX/2, + "Buffer size too big for unmasked circular buffer"); + +static volatile uint8_t console_tx_buffer[CONSOLE_TX_BUFFER_SIZE]; +static volatile uint8_t console_rx_buffer[CONSOLE_RX_BUFFER_SIZE]; + +static volatile uint16_t console_tx_head = 0; +static volatile uint16_t console_tx_tail = 0; + +static uint16_t console_rx_head = 0; + void console_reconfigure(uint32_t baudrate, uint32_t databits, uint32_t stopbits, uint32_t parity) { // Disable the UART and clear buffers usart_disable(CONSOLE_USART); - usart_disable_rx_interrupt(CONSOLE_USART); + + usart_disable_rx_dma(CONSOLE_USART); usart_disable_tx_interrupt(CONSOLE_USART); nvic_disable_irq(CONSOLE_USART_NVIC_LINE); @@ -63,20 +81,27 @@ void console_reconfigure(uint32_t baudrate, uint32_t databits, uint32_t stopbits usart_set_parity(CONSOLE_USART, parity); usart_set_mode(CONSOLE_USART, CONSOLE_USART_MODE); - // Re-enable the UART with the new settings - usart_enable(CONSOLE_USART); - usart_enable_rx_interrupt(CONSOLE_USART); - nvic_enable_irq(CONSOLE_USART_NVIC_LINE); -} + dma_channel_reset(CONSOLE_RX_DMA_CONTROLLER, CONSOLE_RX_DMA_CHANNEL); -static volatile uint8_t console_tx_buffer[CONSOLE_TX_BUFFER_SIZE]; -static volatile uint8_t console_rx_buffer[CONSOLE_RX_BUFFER_SIZE]; + // Configure RX DMA... + dma_set_peripheral_address(CONSOLE_RX_DMA_CONTROLLER, CONSOLE_RX_DMA_CHANNEL, (uint32_t)&USART_RDR(CONSOLE_USART)); + dma_set_memory_address(CONSOLE_RX_DMA_CONTROLLER, CONSOLE_RX_DMA_CHANNEL, (uint32_t)console_rx_buffer); + dma_set_number_of_data(CONSOLE_RX_DMA_CONTROLLER, CONSOLE_RX_DMA_CHANNEL, CONSOLE_RX_BUFFER_SIZE); + dma_set_read_from_peripheral(CONSOLE_RX_DMA_CONTROLLER, CONSOLE_RX_DMA_CHANNEL); + dma_enable_memory_increment_mode(CONSOLE_RX_DMA_CONTROLLER, CONSOLE_RX_DMA_CHANNEL); + dma_set_peripheral_size(CONSOLE_RX_DMA_CONTROLLER, CONSOLE_RX_DMA_CHANNEL, DMA_CCR_PSIZE_8BIT); + dma_set_memory_size(CONSOLE_RX_DMA_CONTROLLER, CONSOLE_RX_DMA_CHANNEL, DMA_CCR_MSIZE_8BIT); + dma_set_priority(CONSOLE_RX_DMA_CONTROLLER, CONSOLE_RX_DMA_CHANNEL, DMA_CCR_PL_HIGH); + dma_enable_circular_mode(CONSOLE_RX_DMA_CONTROLLER, CONSOLE_RX_DMA_CHANNEL); -static volatile uint16_t console_tx_head = 0; -static volatile uint16_t console_tx_tail = 0; + dma_enable_channel(CONSOLE_RX_DMA_CONTROLLER, CONSOLE_RX_DMA_CHANNEL); -static volatile uint16_t console_rx_head = 0; -static volatile uint16_t console_rx_tail = 0; + usart_enable_rx_dma(CONSOLE_USART); + nvic_enable_irq(CONSOLE_USART_NVIC_LINE); + + // Re-enable the UART with the new settings + usart_enable(CONSOLE_USART); +} static bool console_tx_buffer_empty(void) { return console_tx_head == console_tx_tail; @@ -107,16 +132,12 @@ size_t console_send_buffer_space(void) { } static bool console_rx_buffer_empty(void) { - return console_rx_head == console_rx_tail; -} - -static bool console_rx_buffer_full(void) { - return console_rx_head == ((console_rx_tail + 1) % CONSOLE_RX_BUFFER_SIZE); -} - -static void console_rx_buffer_put(uint8_t data) { - console_rx_buffer[console_rx_tail] = data; - console_rx_tail = (console_rx_tail + 1) % CONSOLE_RX_BUFFER_SIZE; + if (DMA_CCR(CONSOLE_RX_DMA_CONTROLLER, CONSOLE_RX_DMA_CHANNEL) & DMA_CCR_EN) { + uint16_t console_rx_tail = (CONSOLE_RX_BUFFER_SIZE - DMA_CNDTR(CONSOLE_RX_DMA_CONTROLLER, CONSOLE_RX_DMA_CHANNEL)) % CONSOLE_RX_BUFFER_SIZE; + return console_rx_tail == console_rx_head; + } else { + return true; + } } static uint8_t console_rx_buffer_get(void) { @@ -127,7 +148,7 @@ static uint8_t console_rx_buffer_get(void) { void console_rx_buffer_clear(void) { console_rx_head = 0; - console_rx_tail = 0; + dma_disable_channel(CONSOLE_RX_DMA_CONTROLLER, CONSOLE_RX_DMA_CHANNEL); } size_t console_send_buffered(const uint8_t* data, size_t num_bytes) { @@ -146,8 +167,30 @@ size_t console_send_buffered(const uint8_t* data, size_t num_bytes) { size_t console_recv_buffered(uint8_t* data, size_t max_bytes) { size_t bytes_read = 0; - while (!console_rx_buffer_empty() && (bytes_read < max_bytes)) { - data[bytes_read++] = console_rx_buffer_get(); + if (max_bytes == 1) { + if (!console_rx_buffer_empty()) { + *data = console_rx_buffer_get(); + bytes_read = 1; + } + } else if (!console_rx_buffer_empty()) { + uint16_t console_rx_tail = (CONSOLE_RX_BUFFER_SIZE - DMA_CNDTR(CONSOLE_RX_DMA_CONTROLLER, CONSOLE_RX_DMA_CHANNEL)) % CONSOLE_RX_BUFFER_SIZE; + if (console_rx_head > console_rx_tail) { + while (console_rx_head < CONSOLE_RX_BUFFER_SIZE && bytes_read < max_bytes) { + data[bytes_read++] = console_rx_buffer[console_rx_head++]; + } + if (console_rx_head == CONSOLE_RX_BUFFER_SIZE) { + console_rx_head = 0; + } + } + + if ((bytes_read < max_bytes) && (console_rx_head < console_rx_tail)) { + while (console_rx_head < console_rx_tail && bytes_read < max_bytes) { + data[bytes_read++] = console_rx_buffer[console_rx_head++]; + } + if (console_rx_head == CONSOLE_RX_BUFFER_SIZE) { + console_rx_head = 0; + } + } } return bytes_read; @@ -162,13 +205,6 @@ uint8_t console_recv_blocking(void) { } void CONSOLE_USART_IRQ_NAME(void) { - if (usart_get_interrupt_source(CONSOLE_USART, USART_SR_RXNE)) { - uint8_t received_byte = (uint8_t)usart_recv(CONSOLE_USART); - if (!console_rx_buffer_full()) { - console_rx_buffer_put(received_byte); - } - } - if (usart_get_interrupt_source(CONSOLE_USART, USART_SR_TXE)) { if (!console_tx_buffer_empty()) { usart_word_t buffered_byte = console_tx_buffer_get(); diff --git a/src/stm32f042/brain3.3/config.h b/src/stm32f042/brain3.3/config.h index 44041e7..4a3d8a1 100644 --- a/src/stm32f042/brain3.3/config.h +++ b/src/stm32f042/brain3.3/config.h @@ -34,7 +34,7 @@ #define CONSOLE_USART USART2 #define CONSOLE_TX_BUFFER_SIZE 128 -#define CONSOLE_RX_BUFFER_SIZE 128 +#define CONSOLE_RX_BUFFER_SIZE 1024 #define CONSOLE_USART_GPIO_PORT GPIOA #define CONSOLE_USART_GPIO_PINS (GPIO2|GPIO3) @@ -44,6 +44,9 @@ #define CONSOLE_USART_IRQ_NAME usart2_isr #define CONSOLE_USART_NVIC_LINE NVIC_USART2_IRQ +#define CONSOLE_RX_DMA_CONTROLLER DMA1 +#define CONSOLE_RX_DMA_CLOCK RCC_DMA +#define CONSOLE_RX_DMA_CHANNEL DMA_CHANNEL5 #define DFU_AVAILABLE 1 #define nBOOT0_GPIO_CLOCK RCC_GPIOB diff --git a/src/stm32f042/dap42/config.h b/src/stm32f042/dap42/config.h index a448a26..227e461 100644 --- a/src/stm32f042/dap42/config.h +++ b/src/stm32f042/dap42/config.h @@ -34,7 +34,7 @@ #define CONSOLE_USART USART2 #define CONSOLE_TX_BUFFER_SIZE 128 -#define CONSOLE_RX_BUFFER_SIZE 128 +#define CONSOLE_RX_BUFFER_SIZE 1024 #define CONSOLE_USART_GPIO_PORT GPIOA #define CONSOLE_USART_GPIO_PINS (GPIO2|GPIO3) @@ -44,6 +44,9 @@ #define CONSOLE_USART_IRQ_NAME usart2_isr #define CONSOLE_USART_NVIC_LINE NVIC_USART2_IRQ +#define CONSOLE_RX_DMA_CONTROLLER DMA1 +#define CONSOLE_RX_DMA_CLOCK RCC_DMA +#define CONSOLE_RX_DMA_CHANNEL DMA_CHANNEL5 #define DFU_AVAILABLE 1 #define nBOOT0_GPIO_CLOCK RCC_GPIOB diff --git a/src/stm32f042/dap42k6u/config.h b/src/stm32f042/dap42k6u/config.h index fe510ee..816382a 100644 --- a/src/stm32f042/dap42k6u/config.h +++ b/src/stm32f042/dap42k6u/config.h @@ -34,7 +34,7 @@ #define CONSOLE_USART USART1 #define CONSOLE_TX_BUFFER_SIZE 128 -#define CONSOLE_RX_BUFFER_SIZE 128 +#define CONSOLE_RX_BUFFER_SIZE 1024 #define CONSOLE_USART_GPIO_PORT GPIOB #define CONSOLE_USART_GPIO_PINS (GPIO6|GPIO7) @@ -44,6 +44,9 @@ #define CONSOLE_USART_IRQ_NAME usart1_isr #define CONSOLE_USART_NVIC_LINE NVIC_USART1_IRQ +#define CONSOLE_RX_DMA_CONTROLLER DMA1 +#define CONSOLE_RX_DMA_CLOCK RCC_DMA +#define CONSOLE_RX_DMA_CHANNEL DMA_CHANNEL3 #define DFU_AVAILABLE 1 #define nBOOT0_GPIO_CLOCK RCC_GPIOF diff --git a/src/stm32f042/kitchen42/config.h b/src/stm32f042/kitchen42/config.h index 67beff0..26da08a 100644 --- a/src/stm32f042/kitchen42/config.h +++ b/src/stm32f042/kitchen42/config.h @@ -34,7 +34,7 @@ #define CONSOLE_USART USART2 #define CONSOLE_TX_BUFFER_SIZE 128 -#define CONSOLE_RX_BUFFER_SIZE 128 +#define CONSOLE_RX_BUFFER_SIZE 1024 #define CONSOLE_USART_GPIO_PORT GPIOA #define CONSOLE_USART_GPIO_PINS (GPIO2|GPIO3) @@ -44,6 +44,9 @@ #define CONSOLE_USART_IRQ_NAME usart2_isr #define CONSOLE_USART_NVIC_LINE NVIC_USART2_IRQ +#define CONSOLE_RX_DMA_CONTROLLER DMA1 +#define CONSOLE_RX_DMA_CLOCK RCC_DMA +#define CONSOLE_RX_DMA_CHANNEL DMA_CHANNEL5 #define DFU_AVAILABLE 1 #define nBOOT0_GPIO_CLOCK RCC_GPIOF diff --git a/src/stm32f103/stlinkv2-1/config.h b/src/stm32f103/stlinkv2-1/config.h index 7f307e9..a5114b9 100644 --- a/src/stm32f103/stlinkv2-1/config.h +++ b/src/stm32f103/stlinkv2-1/config.h @@ -33,7 +33,7 @@ #define CONSOLE_USART USART1 #define CONSOLE_TX_BUFFER_SIZE 128 -#define CONSOLE_RX_BUFFER_SIZE 128 +#define CONSOLE_RX_BUFFER_SIZE 4096 #define CONSOLE_USART_GPIO_PORT GPIOA #define CONSOLE_USART_GPIO_TX GPIO2 @@ -41,14 +41,20 @@ #define CONSOLE_USART_MODE USART_MODE_TX_RX -#define CONSOLE_USART_CLOCK RCC_USART1 - -#define CONSOLE_USART_IRQ_NAME usart1_isr -#define CONSOLE_USART_NVIC_LINE NVIC_USART1_IRQ +#define CONSOLE_USART_CLOCK RCC_USART2 +#define CONSOLE_USART_IRQ_NAME usart2_isr +#define CONSOLE_USART_NVIC_LINE NVIC_USART2_IRQ +#define CONSOLE_RX_DMA_CONTROLLER DMA1 +#define CONSOLE_RX_DMA_CLOCK RCC_DMA1 +#define CONSOLE_RX_DMA_CHANNEL DMA_CHANNEL6 + /* Word size for usart_recv and usart_send */ typedef uint16_t usart_word_t; +/* Workaround for non-commonalized STM32F0 USART code */ +#define USART_RDR(usart_base) USART_DR(usart_base) + #define LED_OPEN_DRAIN 0 #endif diff --git a/src/stm32f103/stlinkv2-dongle/config.h b/src/stm32f103/stlinkv2-dongle/config.h index 3ab0c21..6d6e482 100644 --- a/src/stm32f103/stlinkv2-dongle/config.h +++ b/src/stm32f103/stlinkv2-dongle/config.h @@ -33,7 +33,7 @@ #define CONSOLE_USART USART3 #define CONSOLE_TX_BUFFER_SIZE 128 -#define CONSOLE_RX_BUFFER_SIZE 128 +#define CONSOLE_RX_BUFFER_SIZE 4096 #define CONSOLE_USART_GPIO_PORT GPIOB #define CONSOLE_USART_GPIO_TX 0 @@ -45,12 +45,18 @@ #define CONSOLE_USART_IRQ_NAME usart3_isr #define CONSOLE_USART_NVIC_LINE NVIC_USART3_IRQ +#define CONSOLE_RX_DMA_CONTROLLER DMA1 +#define CONSOLE_RX_DMA_CLOCK RCC_DMA1 +#define CONSOLE_RX_DMA_CHANNEL DMA_CHANNEL3 #define TARGET_DFU_AVAILABLE 0 /* Word size for usart_recv and usart_send */ typedef uint16_t usart_word_t; +/* Workaround for non-commonalized STM32F0 USART code */ +#define USART_RDR(usart_base) USART_DR(usart_base) + #define LED_OPEN_DRAIN 0 #endif From e1691cb49de95337346eb6515c28e48b15b2c71f Mon Sep 17 00:00:00 2001 From: Devan Lai Date: Sat, 20 May 2017 23:15:19 -0700 Subject: [PATCH 2/2] Import SOF/callback driven CDC-ACM code Port the SOF/data-in-complete callback driven CDC-ACM code from the termlink project --- src/USB/cdc.c | 63 +++++++++++++++++++++++------------- src/USB/composite_usb_conf.c | 20 ++++++++++++ src/USB/composite_usb_conf.h | 2 ++ 3 files changed, 62 insertions(+), 23 deletions(-) diff --git a/src/USB/cdc.c b/src/USB/cdc.c index 70e2fdd..3bfa9b3 100644 --- a/src/USB/cdc.c +++ b/src/USB/cdc.c @@ -204,21 +204,23 @@ static void cdc_bulk_data_out(usbd_device *usbd_dev, uint8_t ep) { // Handle flow control if (accept_more_packets) { cdc_clear_nak(); - } else { - cdc_set_nak(); } } +static void cdc_bulk_data_in(usbd_device *usbd_dev, uint8_t ep); +static void cdc_start_in_transfer(void); + static void cdc_set_config(usbd_device *usbd_dev, uint16_t wValue) { (void)wValue; usbd_ep_setup(usbd_dev, ENDP_CDC_DATA_OUT, USB_ENDPOINT_ATTR_BULK, 64, cdc_bulk_data_out); - usbd_ep_setup(usbd_dev, ENDP_CDC_DATA_IN, USB_ENDPOINT_ATTR_BULK, 64, NULL); + usbd_ep_setup(usbd_dev, ENDP_CDC_DATA_IN, USB_ENDPOINT_ATTR_BULK, 64, cdc_bulk_data_in); usbd_ep_setup(usbd_dev, ENDP_CDC_COMM_IN, USB_ENDPOINT_ATTR_INTERRUPT, 16, NULL); cmp_usb_register_control_class_callback(INTF_CDC_DATA, cdc_control_class_request); cmp_usb_register_control_class_callback(INTF_CDC_COMM, cdc_control_class_request); + cmp_usb_register_sof_callback(cdc_start_in_transfer); } /* CDC-ACM USB UART bridge functionality */ @@ -330,36 +332,51 @@ void cdc_uart_app_set_timeout(uint32_t timeout_ms) { packet_timeout = timeout_ms; } -bool cdc_uart_app_update() { - bool active = false; - - // Handle sending received data to the host +static bool transfer_complete = false; +static void cdc_start_in_transfer(void) { + transfer_complete = false; if (packet_len < USB_CDC_MAX_PACKET_SIZE) { uint16_t max_bytes = (USB_CDC_MAX_PACKET_SIZE- packet_len); packet_len += console_recv_buffered(&packet_buffer[packet_len], max_bytes); } - uint32_t now = get_ticks(); - bool flush = false; - bool timeout = (now - packet_timestamp) >= packet_timeout; - if (packet_len == USB_CDC_MAX_PACKET_SIZE) { - flush = true; - } else if (timeout && (packet_len > 0 || need_zlp)) { - flush = true; - } - - if (flush && cmp_usb_configured()) { - if (cdc_send_data(packet_buffer, packet_len) || (packet_len == 0)) { - active = (packet_len > 0); - need_zlp = (packet_len == USB_CDC_MAX_PACKET_SIZE); - packet_len = 0; - packet_timestamp = now; - + if (packet_len > 0) { + if (cdc_send_data(packet_buffer, packet_len)) { + transfer_complete = (packet_len < USB_CDC_MAX_PACKET_SIZE); + packet_len = console_recv_buffered(packet_buffer, USB_CDC_MAX_PACKET_SIZE); if (cdc_uart_tx_callback) { cdc_uart_tx_callback(); } } + } else { + transfer_complete = true; } +} + +static void cdc_bulk_data_in(usbd_device *usbd_dev, uint8_t ep) { + (void)usbd_dev; + (void)ep; + + if (packet_len < USB_CDC_MAX_PACKET_SIZE) { + uint16_t max_bytes = (USB_CDC_MAX_PACKET_SIZE- packet_len); + packet_len += console_recv_buffered(&packet_buffer[packet_len], max_bytes); + } + + if (!transfer_complete) { + cdc_send_data(packet_buffer, packet_len); + if (packet_len < USB_CDC_MAX_PACKET_SIZE) { + transfer_complete = true; + } + packet_len = 0; + + if (cdc_uart_tx_callback) { + cdc_uart_tx_callback(); + } + } +} + +bool cdc_uart_app_update() { + bool active = false; // Handle flow control for data received from the host if (console_send_buffer_space() >= USB_CDC_MAX_PACKET_SIZE) { diff --git a/src/USB/composite_usb_conf.c b/src/USB/composite_usb_conf.c index d6542d8..36738de 100644 --- a/src/USB/composite_usb_conf.c +++ b/src/USB/composite_usb_conf.c @@ -412,6 +412,22 @@ void cmp_usb_register_reset_callback(GenericCallback callback) { } } +static GenericCallback sof_callbacks[USB_MAX_SOF_CALLBACKS]; +static uint8_t num_sof_callbacks; + +void cmp_usb_register_sof_callback(GenericCallback callback) { + if (num_sof_callbacks < USB_MAX_SOF_CALLBACKS) { + sof_callbacks[num_sof_callbacks++] = callback; + } +} + +static void cmp_usb_handle_sof(void) { + uint8_t i; + for (i=0; i < num_sof_callbacks; i++) { + (*sof_callbacks[i])(); + } +} + /* Configuration status */ static bool configured = false; @@ -429,6 +445,9 @@ static void cmp_usb_handle_reset(void) { for (i=0; i < num_callbacks; i++) { (*reset_callbacks[i])(); } + + // Unregister all SOF callbacks + num_sof_callbacks = 0; } /* Class-specific control request handlers */ @@ -519,5 +538,6 @@ usbd_device* cmp_usb_setup(void) { usbd_control_buffer, sizeof(usbd_control_buffer)); usbd_register_set_config_callback(usbd_dev, cmp_usb_set_config); usbd_register_reset_callback(usbd_dev, cmp_usb_handle_reset); + usbd_register_sof_callback(usbd_dev, cmp_usb_handle_sof); return usbd_dev; } diff --git a/src/USB/composite_usb_conf.h b/src/USB/composite_usb_conf.h index 6f141eb..e6d3442 100644 --- a/src/USB/composite_usb_conf.h +++ b/src/USB/composite_usb_conf.h @@ -94,6 +94,7 @@ enum { #define USB_MAX_CONTROL_CLASS_CALLBACKS 8 #define USB_MAX_SET_CONFIG_CALLBACKS 8 #define USB_MAX_RESET_CALLBACKS 8 +#define USB_MAX_SOF_CALLBACKS 8 extern void cmp_set_usb_serial_number(const char* serial); extern usbd_device* cmp_usb_setup(void); @@ -102,5 +103,6 @@ extern void cmp_usb_register_control_class_callback(uint16_t interface, usbd_control_callback callback); extern void cmp_usb_register_set_config_callback(usbd_set_config_callback callback); extern void cmp_usb_register_reset_callback(GenericCallback callback); +extern void cmp_usb_register_sof_callback(GenericCallback callback); #endif