From 089578319a4257570524690ff836d75dfd968dfb Mon Sep 17 00:00:00 2001 From: Gregory Nutt Date: Sat, 27 Dec 2014 18:58:18 -0600 Subject: [PATCH] STM32 Serial: PX4 HW workarround for flaky STM32 RTS. From David Sidrane --- arch/arm/src/stm32/Kconfig | 10 ++++++++ arch/arm/src/stm32/stm32_serial.c | 39 ++++++++++++++++++++++++++++--- drivers/serial/Kconfig | 3 ++- include/nuttx/serial/serial.h | 30 ++++++++++++++++++++++-- 4 files changed, 76 insertions(+), 6 deletions(-) diff --git a/arch/arm/src/stm32/Kconfig b/arch/arm/src/stm32/Kconfig index 0a3f971fc1..354e1fad03 100644 --- a/arch/arm/src/stm32/Kconfig +++ b/arch/arm/src/stm32/Kconfig @@ -3109,6 +3109,16 @@ config SERIAL_DISABLE_REORDERING want the side effect of having all serial port names change when just the console is moved from serial to USB. +config STM32_FLOWCONTROL_BROKEN + bool "Use Software UART RTS flow control" + depends on STM32_USART + default n + ---help--- + Enable UART RTS flow control using Software. Because STM + Current STM32 have broken HW based RTS behavior (they assert + nRTS after every byte received) Enable this setting workaround + this issue by useing software based management of RTS + endmenu config STM32_USART_SINGLEWIRE diff --git a/arch/arm/src/stm32/stm32_serial.c b/arch/arm/src/stm32/stm32_serial.c index 4dd764c192..d0f80f7cec 100644 --- a/arch/arm/src/stm32/stm32_serial.c +++ b/arch/arm/src/stm32/stm32_serial.c @@ -410,6 +410,9 @@ static const struct uart_ops_s g_uart_dma_ops = .receive = up_dma_receive, .rxint = up_dma_rxint, .rxavailable = up_dma_rxavailable, +#ifdef CONFIG_SERIAL_IFLOWCONTROL + .rxflowcontrol = up_rxflowcontrol, +#endif .send = up_send, .txint = up_txint, .txready = up_txready, @@ -1294,7 +1297,7 @@ static void up_set_format(struct uart_dev_s *dev) regval = up_serialin(priv, STM32_USART_CR3_OFFSET); regval &= ~(USART_CR3_CTSE|USART_CR3_RTSE); -#ifdef CONFIG_SERIAL_IFLOWCONTROL +#if defined(CONFIG_SERIAL_IFLOWCONTROL) && !defined(CONFIG_STM32_FLOWCONTROL_BROKEN) if (priv->iflow && (priv->rts_gpio != 0)) { regval |= USART_CR3_RTSE; @@ -1437,8 +1440,15 @@ static int up_setup(struct uart_dev_s *dev) #ifdef CONFIG_SERIAL_IFLOWCONTROL if (priv->rts_gpio != 0) { - stm32_configgpio(priv->rts_gpio); - } + uint32_t config = priv->rts_gpio; + +#ifdef CONFIG_STM32_FLOWCONTROL_BROKEN + /* Instead of letting hw manage this pin, we will bitbang */ + + config = (config & ~GPIO_MODE_MASK) | GPIO_OUTPUT; +#endif + stm32_configgpio(config); + } #endif #if HAVE_RS485 @@ -2140,6 +2150,18 @@ static bool up_rxavailable(struct uart_dev_s *dev) * Return true if UART activated RX flow control to block more incoming * data * + * Input parameters: + * dev - UART device instance + * nbuffered - the number of characters currently buffered + * (if CONFIG_SERIAL_IFLOWCONTROL_WATERMARKS is + * not defined the value will be 0 for an empty buffer or the + * defined buffer size for a full buffer) + * upper - true indicates the upper watermark was crossed where + * false indicates the lower watermark has been crossed + * + * Returned Value: + * true if RX flow control activated. + * ****************************************************************************/ #ifdef CONFIG_SERIAL_IFLOWCONTROL @@ -2149,6 +2171,16 @@ static bool up_rxflowcontrol(struct uart_dev_s *dev, struct up_dev_s *priv = (struct up_dev_s*)dev->priv; uint16_t ie; +#if defined(CONFIG_SERIAL_IFLOWCONTROL_WATERMARKS) && defined(CONFIG_STM32_FLOWCONTROL_BROKEN) + if (priv->iflow && (priv->rts_gpio != 0)) + { + /* Assert/de-assert nRTS set it high resume/stop sending */ + + stm32_gpiowrite(priv->rts_gpio, upper); + return upper; + } + +#else if (priv->iflow) { /* Is the RX buffer full? */ @@ -2185,6 +2217,7 @@ static bool up_rxflowcontrol(struct uart_dev_s *dev, up_rxint(dev, true); } } +#endif return false; } diff --git a/drivers/serial/Kconfig b/drivers/serial/Kconfig index e3c7856b5f..65131f2b08 100644 --- a/drivers/serial/Kconfig +++ b/drivers/serial/Kconfig @@ -539,7 +539,8 @@ config SERIAL_IFLOWCONTROL_WATERMARKS Call the "lower half" rxflowcontrol method whenever the number of characters in the serial RX buffer falls above an upper water mark level or below a lower watermark level. The default behavior is to - call the rxflowcontrol method only when the RX buffer is full. + call the rxflowcontrol method only when the RX buffer is empty or + full. if SERIAL_IFLOWCONTROL_WATERMARKS diff --git a/include/nuttx/serial/serial.h b/include/nuttx/serial/serial.h index 34eb1cc6d7..710345511f 100644 --- a/include/nuttx/serial/serial.h +++ b/include/nuttx/serial/serial.h @@ -1,7 +1,7 @@ /************************************************************************************ * include/nuttx/serial/serial.h * - * Copyright (C) 2007-2008, 2012-2013 Gregory Nutt. All rights reserved. + * Copyright (C) 2007-2008, 2012-2014 Gregory Nutt. All rights reserved. * Author: Gregory Nutt * * Redistribution and use in source and binary forms, with or without @@ -53,7 +53,7 @@ #include /************************************************************************************ - * Definitions + * Pre-processor Definitions ************************************************************************************/ /* Maximum number of threads than can be waiting for POLL events */ @@ -62,6 +62,32 @@ # define CONFIG_SERIAL_NPOLLWAITERS 2 #endif +/* RX flow control */ + +#ifndef CONFIG_SERIAL_IFLOWCONTROL +# undef CONFIG_SERIAL_IFLOWCONTROL_WATERMARKS +#endif + +#ifndef CONFIG_SERIAL_IFLOWCONTROL_WATERMARKS +# undef CONFIG_SERIAL_IFLOWCONTROL_LOWER_WATERMARK +# undef CONFIG_SERIAL_IFLOWCONTROL_UPPER_WATERMARK +#endif + +#ifdef CONFIG_SERIAL_IFLOWCONTROL_WATERMARKS +# ifndef CONFIG_SERIAL_IFLOWCONTROL_LOWER_WATERMARK +# define CONFIG_SERIAL_IFLOWCONTROL_LOWER_WATERMARK 10 +# endif + +# ifndef CONFIG_SERIAL_IFLOWCONTROL_UPPER_WATERMARK +# define CONFIG_SERIAL_IFLOWCONTROL_UPPER_WATERMARK 90 +# endif + +# if CONFIG_SERIAL_IFLOWCONTROL_LOWER_WATERMARK > \ + CONFIG_SERIAL_IFLOWCONTROL_UPPER_WATERMARK +# warning Lower watermark pct exceeds upper watermark pct +# endif +#endif + /* vtable access helpers */ #define uart_setup(dev) dev->ops->setup(dev)