From b11f49e7f15255791746e32aecb6e06838be41e4 Mon Sep 17 00:00:00 2001 From: David Sidrane Date: Tue, 17 May 2016 12:22:25 -1000 Subject: [PATCH] Support BSD compatible breaks on stm32 U[S]ART --- arch/arm/src/stm32/Kconfig | 19 ++++++++ arch/arm/src/stm32/stm32_serial.c | 72 ++++++++++++++++++++++++++++++- 2 files changed, 89 insertions(+), 2 deletions(-) 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 f58501715eb..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,8 +2074,52 @@ 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 */ + { + 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; @@ -2070,7 +2131,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; @@ -2081,6 +2142,7 @@ static int up_ioctl(struct file *filep, int cmd, unsigned long arg) 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);