diff --git a/arch/arm/src/stm32/Kconfig b/arch/arm/src/stm32/Kconfig index 4c4dd327c0c..f45579d1dd8 100644 --- a/arch/arm/src/stm32/Kconfig +++ b/arch/arm/src/stm32/Kconfig @@ -5634,6 +5634,25 @@ config STM32_FLOWCONTROL_BROKEN nRTS after every byte received) Enable this setting workaround this issue by useing software based management of RTS +config STM32_USART_BREAKS + bool "Add TIOxSBRK to support sending Breaks" + depends on STM32_USART + default n + ---help--- + Add TIOCxBRK routines to send a line break per the STM32 manual, the + break will be a pulse based on the value M. This is not a BSD compatible + break. + +config STM32_SERIALBRK_BSDCOMPAT + bool "Use GPIO To send Break" + depends on STM32_USART && STM32_USART_BREAKS + default n + ---help--- + Enable using GPIO on the TX pin to send a BSD compatible break: + TIOCSBRK will start the break and TIOCCBRK will end the break. + The current STM32 U[S]ARTS have no way to leave the break (TX=LOW) + on because the SW starts the break and then the HW automatically clears + the break. This makes it is difficult to sent a long break. endmenu config STM32_USART_SINGLEWIRE diff --git a/arch/arm/src/stm32/stm32_serial.c b/arch/arm/src/stm32/stm32_serial.c index 73039dcf6db..510523f4be5 100644 --- a/arch/arm/src/stm32/stm32_serial.c +++ b/arch/arm/src/stm32/stm32_serial.c @@ -255,6 +255,23 @@ # define PM_IDLE_DOMAIN 0 /* Revisit */ #endif +/* + * Keep track if a Break was set + * + * Note: + * + * 1) This value is set in the priv->ie but never written to the control + * register. It must not collide with USART_CR1_USED_INTS or USART_CR3_EIE + * 2) USART_CR3_EIE is also carried in the up_dev_s ie member. + * + * see up_restoreusartint where the masking is done. + */ + +#ifdef CONFIG_STM32_SERIALBRK_BSDCOMPAT +# define USART_CR1_IE_BREAK_INPROGRESS_SHFTS 15 +# define USART_CR1_IE_BREAK_INPROGRESS (1 << USART_CR1_IE_BREAK_INPROGRESS_SHFTS) +#endif + #ifdef USE_SERIALDRIVER #ifdef HAVE_UART @@ -2057,30 +2074,75 @@ static int up_ioctl(struct file *filep, int cmd, unsigned long arg) break; #endif /* CONFIG_SERIAL_TERMIOS */ -#ifdef CONFIG_USART_BREAKS +#ifdef CONFIG_STM32_USART_BREAKS +# ifdef CONFIG_STM32_SERIALBRK_BSDCOMPAT case TIOCSBRK: /* BSD compatibility: Turn break on, unconditionally */ { - uint32_t cr2; irqstate_t flags; + uint32_t tx_break; flags = enter_critical_section(); - cr2 = up_serialin(priv, STM32_USART_CR2_OFFSET); - up_serialout(priv, STM32_USART_CR2_OFFSET, cr2 | USART_CR2_LINEN); + + /* Disable any further tx activity */ + + priv->ie |= USART_CR1_IE_BREAK_INPROGRESS; + + up_txint(dev, false); + + /* Configure TX as a GPIO output pin and Send a break signal*/ + + tx_break = GPIO_OUTPUT | (~(GPIO_MODE_MASK|GPIO_OUTPUT_SET) & priv->tx_gpio); + stm32_configgpio(tx_break); + leave_critical_section(flags); } break; case TIOCCBRK: /* BSD compatibility: Turn break off, unconditionally */ { - uint32_t cr2; + uint32_t cr1; irqstate_t flags; flags = enter_critical_section(); - cr2 = up_serialin(priv, STM32_USART_CR2_OFFSET); - up_serialout(priv, STM32_USART_CR2_OFFSET, cr2 & ~USART_CR2_LINEN); + + /* Configure TX back to U(S)ART */ + + stm32_configgpio(priv->tx_gpio); + + priv->ie &= ~USART_CR1_IE_BREAK_INPROGRESS; + + /* Enable further tx activity */ + + up_txint(dev, true); + leave_critical_section(flags); } break; +# else + case TIOCSBRK: /* No BSD compatibility: Turn break on for M bit times */ + { + uint32_t cr1; + irqstate_t flags; + + flags = enter_critical_section(); + cr1 = up_serialin(priv, STM32_USART_CR1_OFFSET); + up_serialout(priv, STM32_USART_CR1_OFFSET, cr1 | USART_CR1_SBK); + leave_critical_section(flags); + } + break; + + case TIOCCBRK: /* No BSD compatibility: May turn off break too soon */ + { + uint32_t cr1; + irqstate_t flags; + + flags = enter_critical_section(); + cr1 = up_serialin(priv, STM32_USART_CR1_OFFSET); + up_serialout(priv, STM32_USART_CR1_OFFSET, cr1 & ~USART_CR1_SBK); + leave_critical_section(flags); + } + break; +# endif #endif default: @@ -2469,6 +2531,12 @@ static void up_txint(struct uart_dev_s *dev, bool enable) ie |= USART_CR1_TCIE; } # endif +# ifdef CONFIG_STM32_SERIALBRK_BSDCOMPAT + if (priv->ie & USART_CR1_IE_BREAK_INPROGRESS) + { + return; + } +# endif up_restoreusartint(priv, ie); diff --git a/arch/arm/src/stm32f7/Kconfig b/arch/arm/src/stm32f7/Kconfig index d31b3a6ea54..24e3da9946f 100644 --- a/arch/arm/src/stm32f7/Kconfig +++ b/arch/arm/src/stm32f7/Kconfig @@ -435,6 +435,254 @@ config STM32F7_WWDG endmenu +menu "U[S]ART Configuration" + depends on STM32F7_USART + +config USART1_RS485 + bool "RS-485 on USART1" + default n + depends on STM32F7_USART1 + ---help--- + Enable RS-485 interface on USART1. Your board config will have to + provide GPIO_USART1_RS485_DIR pin definition. Currently it cannot be + used with USART1_RXDMA. + +config USART1_RS485_DIR_POLARITY + int "USART1 RS-485 DIR pin polarity" + default 1 + range 0 1 + depends on USART1_RS485 + ---help--- + Polarity of DIR pin for RS-485 on USART1. Set to state on DIR pin which + enables TX (0 - low / nTXEN, 1 - high / TXEN). + +config USART1_RXDMA + bool "USART1 Rx DMA" + default n + depends on STM32F7_USART1 && STM32F7_DMA1 + ---help--- + In high data rate usage, Rx DMA may eliminate Rx overrun errors + +config USART2_RS485 + bool "RS-485 on USART2" + default n + depends on STM32F7_USART2 + ---help--- + Enable RS-485 interface on USART2. Your board config will have to + provide GPIO_USART2_RS485_DIR pin definition. Currently it cannot be + used with USART2_RXDMA. + +config USART2_RS485_DIR_POLARITY + int "USART2 RS-485 DIR pin polarity" + default 1 + range 0 1 + depends on USART2_RS485 + ---help--- + Polarity of DIR pin for RS-485 on USART2. Set to state on DIR pin which + enables TX (0 - low / nTXEN, 1 - high / TXEN). + +config USART2_RXDMA + bool "USART2 Rx DMA" + default n + depends on STM32F7_USART2 && STM32F7_DMA1 + ---help--- + In high data rate usage, Rx DMA may eliminate Rx overrun errors + +config USART3_RS485 + bool "RS-485 on USART3" + default n + depends on STM32F7_USART3 + ---help--- + Enable RS-485 interface on USART3. Your board config will have to + provide GPIO_USART3_RS485_DIR pin definition. Currently it cannot be + used with USART3_RXDMA. + +config USART3_RS485_DIR_POLARITY + int "USART3 RS-485 DIR pin polarity" + default 1 + range 0 1 + depends on USART3_RS485 + ---help--- + Polarity of DIR pin for RS-485 on USART3. Set to state on DIR pin which + enables TX (0 - low / nTXEN, 1 - high / TXEN). + +config USART3_RXDMA + bool "USART3 Rx DMA" + default n + depends on STM32F7_USART3 && STM32F7_DMA1 + ---help--- + In high data rate usage, Rx DMA may eliminate Rx overrun errors + +config UART4_RS485 + bool "RS-485 on UART4" + default n + depends on STM32F7_UART4 + ---help--- + Enable RS-485 interface on UART4. Your board config will have to + provide GPIO_UART4_RS485_DIR pin definition. Currently it cannot be + used with UART4_RXDMA. + +config UART4_RS485_DIR_POLARITY + int "UART4 RS-485 DIR pin polarity" + default 1 + range 0 1 + depends on UART4_RS485 + ---help--- + Polarity of DIR pin for RS-485 on UART4. Set to state on DIR pin which + enables TX (0 - low / nTXEN, 1 - high / TXEN). + +config UART4_RXDMA + bool "UART4 Rx DMA" + default n + depends on STM32F7_UART4 && STM32F7_DMA1 + ---help--- + In high data rate usage, Rx DMA may eliminate Rx overrun errors + +config UART5_RS485 + bool "RS-485 on UART5" + default n + depends on STM32F7_UART5 + ---help--- + Enable RS-485 interface on UART5. Your board config will have to + provide GPIO_UART5_RS485_DIR pin definition. Currently it cannot be + used with UART5_RXDMA. + +config UART5_RS485_DIR_POLARITY + int "UART5 RS-485 DIR pin polarity" + default 1 + range 0 1 + depends on UART5_RS485 + ---help--- + Polarity of DIR pin for RS-485 on UART5. Set to state on DIR pin which + enables TX (0 - low / nTXEN, 1 - high / TXEN). + +config UART5_RXDMA + bool "UART5 Rx DMA" + default n + depends on STM32F7_UART5 && STM32F7_DMA1 + ---help--- + In high data rate usage, Rx DMA may eliminate Rx overrun errors + +config USART6_RS485 + bool "RS-485 on USART6" + default n + depends on STM32F7_USART6 + ---help--- + Enable RS-485 interface on USART6. Your board config will have to + provide GPIO_USART6_RS485_DIR pin definition. Currently it cannot be + used with USART6_RXDMA. + +config USART6_RS485_DIR_POLARITY + int "USART6 RS-485 DIR pin polarity" + default 1 + range 0 1 + depends on USART6_RS485 + ---help--- + Polarity of DIR pin for RS-485 on USART6. Set to state on DIR pin which + enables TX (0 - low / nTXEN, 1 - high / TXEN). + +config USART6_RXDMA + bool "USART6 Rx DMA" + default n + depends on STM32F7_USART6 && STM32F7_DMA2 + ---help--- + In high data rate usage, Rx DMA may eliminate Rx overrun errors + +config UART7_RS485 + bool "RS-485 on UART7" + default n + depends on STM32F7_UART7 + ---help--- + Enable RS-485 interface on UART7. Your board config will have to + provide GPIO_UART7_RS485_DIR pin definition. Currently it cannot be + used with UART7_RXDMA. + +config UART7_RS485_DIR_POLARITY + int "UART7 RS-485 DIR pin polarity" + default 1 + range 0 1 + depends on UART7_RS485 + ---help--- + Polarity of DIR pin for RS-485 on UART7. Set to state on DIR pin which + enables TX (0 - low / nTXEN, 1 - high / TXEN). + +config UART7_RXDMA + bool "UART7 Rx DMA" + default n + depends on STM32F7_UART7 && STM32F7_DMA2 + ---help--- + In high data rate usage, Rx DMA may eliminate Rx overrun errors + +config UART8_RS485 + bool "RS-485 on UART8" + default n + depends on STM32F7_UART8 + ---help--- + Enable RS-485 interface on UART8. Your board config will have to + provide GPIO_UART8_RS485_DIR pin definition. Currently it cannot be + used with UART8_RXDMA. + +config UART8_RS485_DIR_POLARITY + int "UART8 RS-485 DIR pin polarity" + default 1 + range 0 1 + depends on UART8_RS485 + ---help--- + Polarity of DIR pin for RS-485 on UART8. Set to state on DIR pin which + enables TX (0 - low / nTXEN, 1 - high / TXEN). + +config UART8_RXDMA + bool "UART8 Rx DMA" + default n + depends on STM32F7_UART8 && STM32F7_DMA2 + ---help--- + In high data rate usage, Rx DMA may eliminate Rx overrun errors + +config SERIAL_DISABLE_REORDERING + bool "Disable reordering of ttySx devices." + depends on STM32F7_USART1 || STM32F7_USART2 || STM32F7_USART3 || STM32F7_UART4 || STM32F7_UART5 || STM32F7_USART6 || STM32F7_UART7 || STM32F7_UART8 + default n + ---help--- + NuttX per default reorders the serial ports (/dev/ttySx) so that the + console is always on /dev/ttyS0. If more than one UART is in use this + can, however, have the side-effect that all port mappings + (hardware USART1 -> /dev/ttyS0) change if the console is moved to another + UART. This is in particular relevant if a project uses the USB console + in some configs and a serial console in other configs, but does not + want the side effect of having all serial port names change when just + the console is moved from serial to USB. + +config STM32F7_FLOWCONTROL_BROKEN + bool "Use Software UART RTS flow control" + depends on STM32F7_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 + +config STM32F7_USART_BREAKS + bool "Add TIOxSBRK to support sending Breaks" + depends on STM32F7_USART + default n + ---help--- + Add TIOCxBRK routines to send a line break per the STM32 manual, the + break will be a pulse based on the value M. This is not a BSD compatible + break. + +config STM32F7_SERIALBRK_BSDCOMPAT + bool "Use GPIO To send Break" + depends on STM32F7_USART && STM32F7_USART_BREAKS + default n + ---help--- + Enable using GPIO on the TX pin to send a BSD compatible break: + TIOCSBRK will start the break and TIOCCBRK will end the break. + The current STM32 U[S]ARTS have no way to leave the break (TX=LOW) + on because the SW starts the break and then the HW automatically clears + the break. This makes it is difficult to sent a long break. +endmenu + config STM32F7_CUSTOM_CLOCKCONFIG bool "Custom clock configuration" default n diff --git a/arch/arm/src/stm32f7/stm32_serial.c b/arch/arm/src/stm32f7/stm32_serial.c index 78810f52f36..ad7d80dce04 100644 --- a/arch/arm/src/stm32f7/stm32_serial.c +++ b/arch/arm/src/stm32f7/stm32_serial.c @@ -208,6 +208,23 @@ # define PM_IDLE_DOMAIN 0 /* Revisit */ #endif +/* + * Keep track if a Break was set + * + * Note: + * + * 1) This value is set in the priv->ie but never written to the control + * register. It must not collide with USART_CR1_USED_INTS or USART_CR3_EIE + * 2) USART_CR3_EIE is also carried in the up_dev_s ie member. + * + * see up_restoreusartint where the masking is done. + */ + +#ifdef CONFIG_STM32F7_SERIALBRK_BSDCOMPAT +# define USART_CR1_IE_BREAK_INPROGRESS_SHFTS 15 +# define USART_CR1_IE_BREAK_INPROGRESS (1 << USART_CR1_IE_BREAK_INPROGRESS_SHFTS) +#endif + #ifdef USE_SERIALDRIVER #ifdef HAVE_UART @@ -1964,30 +1981,75 @@ static int up_ioctl(struct file *filep, int cmd, unsigned long arg) break; #endif /* CONFIG_SERIAL_TERMIOS */ -#ifdef CONFIG_USART_BREAKS +#ifdef CONFIG_STM32F7_USART_BREAKS +# ifdef CONFIG_STM32F7_SERIALBRK_BSDCOMPAT case TIOCSBRK: /* BSD compatibility: Turn break on, unconditionally */ { - uint32_t cr2; irqstate_t flags; + uint32_t tx_break; flags = enter_critical_section(); - cr2 = up_serialin(priv, STM32_USART_CR2_OFFSET); - up_serialout(priv, STM32_USART_CR2_OFFSET, cr2 | USART_CR2_LINEN); + + /* Disable any further tx activity */ + + priv->ie |= USART_CR1_IE_BREAK_INPROGRESS; + + up_txint(dev, false); + + /* Configure TX as a GPIO output pin and Send a break signal*/ + + tx_break = GPIO_OUTPUT | (~(GPIO_MODE_MASK|GPIO_OUTPUT_SET) & priv->tx_gpio); + stm32_configgpio(tx_break); + leave_critical_section(flags); } break; case TIOCCBRK: /* BSD compatibility: Turn break off, unconditionally */ { - uint32_t cr2; + uint32_t cr1; irqstate_t flags; flags = enter_critical_section(); - cr2 = up_serialin(priv, STM32_USART_CR2_OFFSET); - up_serialout(priv, STM32_USART_CR2_OFFSET, cr2 & ~USART_CR2_LINEN); + + /* Configure TX back to U(S)ART */ + + stm32_configgpio(priv->tx_gpio); + + priv->ie &= ~USART_CR1_IE_BREAK_INPROGRESS; + + /* Enable further tx activity */ + + up_txint(dev, true); + leave_critical_section(flags); } break; +# else + case TIOCSBRK: /* No BSD compatibility: Turn break on for M bit times */ + { + uint32_t cr1; + irqstate_t flags; + + flags = enter_critical_section(); + cr1 = up_serialin(priv, STM32_USART_CR1_OFFSET); + up_serialout(priv, STM32_USART_CR1_OFFSET, cr1 | USART_CR1_SBK); + leave_critical_section(flags); + } + break; + + case TIOCCBRK: /* No BSD compatibility: May turn off break too soon */ + { + uint32_t cr1; + irqstate_t flags; + + flags = enter_critical_section(); + cr1 = up_serialin(priv, STM32_USART_CR1_OFFSET); + up_serialout(priv, STM32_USART_CR1_OFFSET, cr1 & ~USART_CR1_SBK); + leave_critical_section(flags); + } + break; +# endif #endif default: @@ -2399,6 +2461,12 @@ static void up_txint(struct uart_dev_s *dev, bool enable) ie |= USART_CR1_TCIE; } # endif +# ifdef CONFIG_STM32_SERIALBRK_BSDCOMPAT + if (priv->ie & USART_CR1_IE_BREAK_INPROGRESS) + { + return; + } +# endif up_restoreusartint(priv, ie); diff --git a/arch/arm/src/stm32l4/Kconfig b/arch/arm/src/stm32l4/Kconfig index f334ca32bc6..11b622785cc 100644 --- a/arch/arm/src/stm32l4/Kconfig +++ b/arch/arm/src/stm32l4/Kconfig @@ -782,6 +782,26 @@ config STM32L4_FLOWCONTROL_BROKEN nRTS after every byte received) Enable this setting workaround this issue by useing software based management of RTS +config STM32L4_USART_BREAKS + bool "Add TIOxSBRK to support sending Breaks" + depends on STM32_USART + default n + ---help--- + Add TIOCxBRK routines to send a line break per the STM32 manual, the + break will be a pulse based on the value M. This is not a BSD compatible + break. + +config STM32L4_SERIALBRK_BSDCOMPAT + bool "Use GPIO To send Break" + depends on STM32_USART && STM32_USART_BREAKS + default n + ---help--- + Enable using GPIO on the TX pin to send a BSD compatible break: + TIOCSBRK will start the break and TIOCCBRK will end the break. + The current STM32 U[S]ARTS have no way to leave the break (TX=LOW) + on because the SW starts the break and then the HW automatically clears + the break. This makes it is difficult to sent a long break. + endmenu menu "SPI Configuration" diff --git a/arch/arm/src/stm32l4/stm32l4_serial.c b/arch/arm/src/stm32l4/stm32l4_serial.c index 8f68409dba5..629ed59e153 100644 --- a/arch/arm/src/stm32l4/stm32l4_serial.c +++ b/arch/arm/src/stm32l4/stm32l4_serial.c @@ -208,6 +208,23 @@ # define PM_IDLE_DOMAIN 0 /* Revisit */ #endif +/* + * Keep track if a Break was set + * + * Note: + * + * 1) This value is set in the priv->ie but never written to the control + * register. It must not collide with USART_CR1_USED_INTS or USART_CR3_EIE + * 2) USART_CR3_EIE is also carried in the up_dev_s ie member. + * + * see up_restoreusartint where the masking is done. + */ + +#ifdef CONFIG_STM32L4_SERIALBRK_BSDCOMPAT +# define USART_CR1_IE_BREAK_INPROGRESS_SHFTS 15 +# define USART_CR1_IE_BREAK_INPROGRESS (1 << USART_CR1_IE_BREAK_INPROGRESS_SHFTS) +#endif + #ifdef USE_SERIALDRIVER #ifdef HAVE_UART @@ -1720,30 +1737,75 @@ static int up_ioctl(struct file *filep, int cmd, unsigned long arg) break; #endif /* CONFIG_SERIAL_TERMIOS */ -#ifdef CONFIG_USART_BREAKS +#ifdef CONFIG_STM32L4_USART_BREAKS +# ifdef CONFIG_STM32L4_SERIALBRK_BSDCOMPAT case TIOCSBRK: /* BSD compatibility: Turn break on, unconditionally */ { - uint32_t cr2; irqstate_t flags; + uint32_t tx_break; flags = enter_critical_section(); - cr2 = up_serialin(priv, STM32L4_USART_CR2_OFFSET); - up_serialout(priv, STM32L4_USART_CR2_OFFSET, cr2 | USART_CR2_LINEN); + + /* Disable any further tx activity */ + + priv->ie |= USART_CR1_IE_BREAK_INPROGRESS; + + up_txint(dev, false); + + /* Configure TX as a GPIO output pin and Send a break signal*/ + + tx_break = GPIO_OUTPUT | (~(GPIO_MODE_MASK|GPIO_OUTPUT_SET) & priv->tx_gpio); + stm32_configgpio(tx_break); + leave_critical_section(flags); } break; case TIOCCBRK: /* BSD compatibility: Turn break off, unconditionally */ { - uint32_t cr2; + uint32_t cr1; irqstate_t flags; flags = enter_critical_section(); - cr2 = up_serialin(priv, STM32L4_USART_CR2_OFFSET); - up_serialout(priv, STM32L4_USART_CR2_OFFSET, cr2 & ~USART_CR2_LINEN); + + /* Configure TX back to U(S)ART */ + + stm32_configgpio(priv->tx_gpio); + + priv->ie &= ~USART_CR1_IE_BREAK_INPROGRESS; + + /* Enable further tx activity */ + + up_txint(dev, true); + leave_critical_section(flags); } break; +# else + case TIOCSBRK: /* No BSD compatibility: Turn break on for M bit times */ + { + uint32_t cr1; + irqstate_t flags; + + flags = enter_critical_section(); + cr1 = up_serialin(priv, STM32_USART_CR1_OFFSET); + up_serialout(priv, STM32_USART_CR1_OFFSET, cr1 | USART_CR1_SBK); + leave_critical_section(flags); + } + break; + + case TIOCCBRK: /* No BSD compatibility: May turn off break too soon */ + { + uint32_t cr1; + irqstate_t flags; + + flags = enter_critical_section(); + cr1 = up_serialin(priv, STM32_USART_CR1_OFFSET); + up_serialout(priv, STM32_USART_CR1_OFFSET, cr1 & ~USART_CR1_SBK); + leave_critical_section(flags); + } + break; +# endif #endif default: @@ -2132,6 +2194,12 @@ static void up_txint(struct uart_dev_s *dev, bool enable) ie |= USART_CR1_TCIE; } # endif +# ifdef CONFIG_STM32L4_SERIALBRK_BSDCOMPAT + if (priv->ie & USART_CR1_IE_BREAK_INPROGRESS) + { + return; + } +# endif up_restoreusartint(priv, ie);