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 047db9f87ef..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,8 +1737,52 @@ 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 */ + { + irqstate_t flags; + uint32_t tx_break; + + flags = enter_critical_section(); + + /* 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 cr1; + irqstate_t flags; + + flags = enter_critical_section(); + + /* 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; @@ -1733,7 +1794,7 @@ static int up_ioctl(struct file *filep, int cmd, unsigned long arg) } break; - case TIOCCBRK: /* BSD compatibility: Turn break off, unconditionally */ + case TIOCCBRK: /* No BSD compatibility: May turn off break too soon */ { uint32_t cr1; irqstate_t flags; @@ -1744,6 +1805,7 @@ static int up_ioctl(struct file *filep, int cmd, unsigned long arg) 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);