From 1a77595c9e8cc16a36b23bcf01746b98601e852e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Beat=20K=C3=BCng?= Date: Wed, 3 Jul 2019 09:23:18 -0600 Subject: [PATCH 1/2] [BACKPORT] arch/arm/src/stm32f7/stm32_serial.c: This adds the ability to invert and swap RX/TX on STM32F7 UARTs. I added the TIOCGINVERT as well to reserve the IOCTL number, but did not implement it. This is the same as for TIOCGSINGLEWIRE. --- arch/arm/src/stm32f7/Kconfig | 16 ++++ arch/arm/src/stm32f7/stm32_serial.c | 113 ++++++++++++++++++++++++++-- include/nuttx/serial/tioctl.h | 15 ++++ 3 files changed, 138 insertions(+), 6 deletions(-) diff --git a/arch/arm/src/stm32f7/Kconfig b/arch/arm/src/stm32f7/Kconfig index 2031bf5fb48..1b038ef0821 100644 --- a/arch/arm/src/stm32f7/Kconfig +++ b/arch/arm/src/stm32f7/Kconfig @@ -1940,6 +1940,22 @@ config STM32F7_USART_SINGLEWIRE Enable single wire UART support. The option enables support for the TIOCSSINGLEWIRE ioctl in the STM32F7 serial driver. +config STM32F7_USART_INVERT + bool "Signal Invert Support" + default n + depends on STM32F7_USART + ---help--- + Enable signal inversion UART support. The option enables support for the + TIOCSINVERT ioctl in the STM32F7 serial driver. + +config STM32F7_USART_SWAP + bool "Swap RX/TX pins support" + default n + depends on STM32F7_USART + ---help--- + Enable RX/TX pin swapping support. The option enables support for the + TIOCSSWAP ioctl in the STM32F7 serial driver. + if PM config STM32F7_PM_SERIAL_ACTIVITY diff --git a/arch/arm/src/stm32f7/stm32_serial.c b/arch/arm/src/stm32f7/stm32_serial.c index d9e037a08e8..da8b3da2fe1 100644 --- a/arch/arm/src/stm32f7/stm32_serial.c +++ b/arch/arm/src/stm32f7/stm32_serial.c @@ -76,7 +76,9 @@ /**************************************************************************** * Pre-processor Definitions ****************************************************************************/ + /* Some sanity checks *******************************************************/ + /* Total number of possible serial devices */ #define STM32_NSERIAL (STM32F7_NUSART + STM32F7_NUART) @@ -1260,12 +1262,13 @@ static void up_set_format(struct uart_dev_s *dev) /* Get the original state of UE */ - cr1 = up_serialin(priv, STM32_USART_CR1_OFFSET); + cr1 = up_serialin(priv, STM32_USART_CR1_OFFSET); cr1_ue = cr1 & USART_CR1_UE; - cr1 &= ~USART_CR1_UE; + cr1 &= ~USART_CR1_UE; /* Disable UE as the format bits and baud rate registers can not be - * updated while UE = 1 */ + * updated while UE = 1 + */ up_serialout(priv, STM32_USART_CR1_OFFSET, cr1); @@ -1356,7 +1359,7 @@ static void up_set_format(struct uart_dev_s *dev) /* Configure STOP bits */ - regval = up_serialin(priv, STM32_USART_CR2_OFFSET); + regval = up_serialin(priv, STM32_USART_CR2_OFFSET); regval &= ~(USART_CR2_STOP_MASK); if (priv->stopbits2) @@ -1685,6 +1688,7 @@ static int up_setup(struct uart_dev_s *dev) #endif /* Configure CR2 */ + /* Clear STOP, CLKEN, CPOL, CPHA, LBCL, and interrupt enable bits */ regval = up_serialin(priv, STM32_USART_CR2_OFFSET); @@ -1701,6 +1705,7 @@ static int up_setup(struct uart_dev_s *dev) up_serialout(priv, STM32_USART_CR2_OFFSET, regval); /* Configure CR1 */ + /* Clear TE, REm and all interrupt enable bits */ regval = up_serialin(priv, STM32_USART_CR1_OFFSET); @@ -1709,6 +1714,7 @@ static int up_setup(struct uart_dev_s *dev) up_serialout(priv, STM32_USART_CR1_OFFSET, regval); /* Configure CR3 */ + /* Clear CTSE, RTSE, and all interrupt enable bits */ regval = up_serialin(priv, STM32_USART_CR3_OFFSET); @@ -2150,6 +2156,99 @@ static int up_ioctl(struct file *filep, int cmd, unsigned long arg) break; #endif +#ifdef CONFIG_STM32F7_USART_INVERT + case TIOCSINVERT: + { + uint32_t cr1; + uint32_t cr1_ue; + irqstate_t flags; + + flags = enter_critical_section(); + + /* Get the original state of UE */ + + cr1 = up_serialin(priv, STM32_USART_CR1_OFFSET); + cr1_ue = cr1 & USART_CR1_UE; + cr1 &= ~USART_CR1_UE; + + /* Disable UE, {R,T}XINV can only be written when UE=0 */ + + up_serialout(priv, STM32_USART_CR1_OFFSET, cr1); + + /* Enable/disable signal inversion. */ + + uint32_t cr = up_serialin(priv, STM32_USART_CR2_OFFSET); + + if (arg & SER_INVERT_ENABLED_RX) + { + cr |= USART_CR2_RXINV; + } + else + { + cr &= ~USART_CR2_RXINV; + } + + if (arg & SER_INVERT_ENABLED_TX) + { + cr |= USART_CR2_TXINV; + } + else + { + cr &= ~USART_CR2_TXINV; + } + + up_serialout(priv, STM32_USART_CR2_OFFSET, cr); + + /* Re-enable UE if appropriate */ + + up_serialout(priv, STM32_USART_CR1_OFFSET, cr1 | cr1_ue); + leave_critical_section(flags); + } + break; +#endif + +#ifdef CONFIG_STM32F7_USART_SWAP + case TIOCSSWAP: + { + uint32_t cr1; + uint32_t cr1_ue; + irqstate_t flags; + + flags = enter_critical_section(); + + /* Get the original state of UE */ + + cr1 = up_serialin(priv, STM32_USART_CR1_OFFSET); + cr1_ue = cr1 & USART_CR1_UE; + cr1 &= ~USART_CR1_UE; + + /* Disable UE, SWAP can only be written when UE=0 */ + + up_serialout(priv, STM32_USART_CR1_OFFSET, cr1); + + /* Enable/disable Swap mode. */ + + uint32_t cr = up_serialin(priv, STM32_USART_CR2_OFFSET); + + if (arg == SER_SWAP_ENABLED) + { + cr |= USART_CR2_SWAP; + } + else + { + cr &= ~USART_CR2_SWAP; + } + + up_serialout(priv, STM32_USART_CR2_OFFSET, cr); + + /* Re-enable UE if appropriate */ + + up_serialout(priv, STM32_USART_CR1_OFFSET, cr1 | cr1_ue); + leave_critical_section(flags); + } + break; +#endif + #ifdef CONFIG_SERIAL_TERMIOS case TCGETS: { @@ -2260,9 +2359,10 @@ static int up_ioctl(struct file *filep, int cmd, unsigned long arg) up_txint(dev, false); - /* Configure TX as a GPIO output pin and Send a break signal*/ + /* 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); + tx_break = GPIO_OUTPUT | + (~(GPIO_MODE_MASK | GPIO_OUTPUT_SET) & priv->tx_gpio); stm32_configgpio(tx_break); leave_critical_section(flags); @@ -3000,6 +3100,7 @@ static int up_pm_prepare(struct pm_callback_s *cb, int domain, default: /* Should not get here */ + break; } diff --git a/include/nuttx/serial/tioctl.h b/include/nuttx/serial/tioctl.h index 5cde6507652..614b126984b 100644 --- a/include/nuttx/serial/tioctl.h +++ b/include/nuttx/serial/tioctl.h @@ -190,6 +190,21 @@ #define TIOCSERGSTRUCT _TIOC(0x0032) /* Get device TTY structure */ +/* Inversion Support */ + +#define TIOCSINVERT _TIOC(0x0033) /* Set Singal Inversion */ +#define TIOCGINVERT _TIOC(0x0034) /* Get Singal Inversion */ + +#define SER_INVERT_ENABLED_RX (1 << 0) /* Enable/disable signal inversion for RX */ +#define SER_INVERT_ENABLED_TX (1 << 1) /* Enable/disable signal inversion for TX */ + +/* RX/TX Swap Support */ + +#define TIOCSSWAP _TIOC(0x0035) /* Set RX/TX Swap */ +#define TIOCGSWAP _TIOC(0x0036) /* Get RX/TX Swap */ + +#define SER_SWAP_ENABLED (1 << 0) /* Enable/disable RX/TX swap */ + /******************************************************************************************** * Public Type Definitions ********************************************************************************************/ From 9e8019b0fe983d05dfa516f09d249b9029bb9f42 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Beat=20K=C3=BCng?= Date: Wed, 3 Jul 2019 20:22:09 +0000 Subject: [PATCH 2/2] [BACKPORT] Merged in bkueng/nuttx/uart_invert_ioctl_continued (pull request #930) serial: add TIOCSINVERT and TIOCSSWAP ioctl's for stm32{l4,h7} and imxrt * stm32l4 serial: add TIOCSINVERT and TIOCSSWAP ioctl's * stm32l4 serial: ensure TIOCSSINGLEWIRE is atomic and UE disabled * stm32h7 serial: add TIOCSINVERT and TIOCSSWAP ioctl's * imxrt serial: add TIOCSINVERT ioctl Approved-by: Gregory Nutt --- arch/arm/src/imxrt/Kconfig | 13 +++ arch/arm/src/imxrt/imxrt_serial.c | 47 +++++++++++ arch/arm/src/stm32h7/Kconfig | 16 ++++ arch/arm/src/stm32h7/stm32_serial.c | 93 +++++++++++++++++++++ arch/arm/src/stm32l4/Kconfig | 16 ++++ arch/arm/src/stm32l4/stm32l4_serial.c | 115 ++++++++++++++++++++++++++ 6 files changed, 300 insertions(+) diff --git a/arch/arm/src/imxrt/Kconfig b/arch/arm/src/imxrt/Kconfig index 87223e999b9..dfcd94b7e5e 100644 --- a/arch/arm/src/imxrt/Kconfig +++ b/arch/arm/src/imxrt/Kconfig @@ -193,6 +193,19 @@ config IMXRT_LPUART8 endmenu # LPUART Peripherals +menu "LPUART Configuration" + depends on IMXRT_HAVE_LPUART + +config IMXRT_LPUART_INVERT + bool "Signal Invert Support" + default n + depends on IMXRT_HAVE_LPUART + ---help--- + Enable signal inversion UART support. The option enables support for the + TIOCSINVERT ioctl in the IMXRT serial driver. + +endmenu # LPUART Configuration + menu "LPI2C Peripherals" menuconfig IMXRT_LPI2C1 diff --git a/arch/arm/src/imxrt/imxrt_serial.c b/arch/arm/src/imxrt/imxrt_serial.c index 4f3cc1fea77..5d9a938f903 100644 --- a/arch/arm/src/imxrt/imxrt_serial.c +++ b/arch/arm/src/imxrt/imxrt_serial.c @@ -1212,6 +1212,53 @@ static int imxrt_ioctl(struct file *filep, int cmd, unsigned long arg) break; #endif /* CONFIG_SERIAL_TERMIOS */ +#ifdef CONFIG_IMXRT_LPUART_INVERT + case TIOCSINVERT: + { + uint32_t ctrl; + uint32_t stat; + uint32_t regval; + irqstate_t flags; + + flags = spin_lock_irqsave(); + ctrl = imxrt_serialin(priv, IMXRT_LPUART_CTRL_OFFSET); + stat = imxrt_serialin(priv, IMXRT_LPUART_STAT_OFFSET); + regval = ctrl; + + /* {R|T}XINV bit field can only be written when the receiver is disabled (RE=0). */ + + regval &= ~LPUART_CTRL_RE; + + imxrt_serialout(priv, IMXRT_LPUART_CTRL_OFFSET, regval); + + /* Enable/disable signal inversion. */ + + if (arg & SER_INVERT_ENABLED_RX) + { + stat |= LPUART_STAT_RXINV; + } + else + { + stat &= ~LPUART_STAT_RXINV; + } + + if (arg & SER_INVERT_ENABLED_TX) + { + ctrl |= LPUART_CTRL_TXINV; + } + else + { + ctrl &= ~LPUART_CTRL_TXINV; + } + + imxrt_serialout(priv, IMXRT_LPUART_STAT_OFFSET, stat); + imxrt_serialout(priv, IMXRT_LPUART_CTRL_OFFSET, ctrl); + + spin_unlock_irqrestore(flags); + } + break; +#endif + case TIOCSBRK: /* BSD compatibility: Turn break on, unconditionally */ case TIOCCBRK: /* BSD compatibility: Turn break off, unconditionally */ default: diff --git a/arch/arm/src/stm32h7/Kconfig b/arch/arm/src/stm32h7/Kconfig index 7fd28f7435e..cb938e0312e 100644 --- a/arch/arm/src/stm32h7/Kconfig +++ b/arch/arm/src/stm32h7/Kconfig @@ -689,6 +689,22 @@ config STM32H7_USART_SINGLEWIRE Enable single wire UART support. The option enables support for the TIOCSSINGLEWIRE ioctl in the STM32H7 serial driver. +config STM32H7_USART_INVERT + bool "Signal Invert Support" + default n + depends on STM32H7_USART + ---help--- + Enable signal inversion UART support. The option enables support for the + TIOCSINVERT ioctl in the STM32H7 serial driver. + +config STM32H7_USART_SWAP + bool "Swap RX/TX pins support" + default n + depends on STM32H7_USART + ---help--- + Enable RX/TX pin swapping support. The option enables support for the + TIOCSSWAP ioctl in the STM32H7 serial driver. + if PM config STM32H7_PM_SERIAL_ACTIVITY diff --git a/arch/arm/src/stm32h7/stm32_serial.c b/arch/arm/src/stm32h7/stm32_serial.c index 8254b555054..8a9a621299c 100644 --- a/arch/arm/src/stm32h7/stm32_serial.c +++ b/arch/arm/src/stm32h7/stm32_serial.c @@ -1557,6 +1557,99 @@ static int up_ioctl(struct file *filep, int cmd, unsigned long arg) break; #endif +#ifdef CONFIG_STM32H7_USART_INVERT + case TIOCSINVERT: + { + uint32_t cr1; + uint32_t cr1_ue; + irqstate_t flags; + + flags = enter_critical_section(); + + /* Get the original state of UE */ + + cr1 = up_serialin(priv, STM32_USART_CR1_OFFSET); + cr1_ue = cr1 & USART_CR1_UE; + cr1 &= ~USART_CR1_UE; + + /* Disable UE, {R,T}XINV can only be written when UE=0 */ + + up_serialout(priv, STM32_USART_CR1_OFFSET, cr1); + + /* Enable/disable signal inversion. */ + + uint32_t cr = up_serialin(priv, STM32_USART_CR2_OFFSET); + + if (arg & SER_INVERT_ENABLED_RX) + { + cr |= USART_CR2_RXINV; + } + else + { + cr &= ~USART_CR2_RXINV; + } + + if (arg & SER_INVERT_ENABLED_TX) + { + cr |= USART_CR2_TXINV; + } + else + { + cr &= ~USART_CR2_TXINV; + } + + up_serialout(priv, STM32_USART_CR2_OFFSET, cr); + + /* Re-enable UE if appropriate */ + + up_serialout(priv, STM32_USART_CR1_OFFSET, cr1 | cr1_ue); + leave_critical_section(flags); + } + break; +#endif + +#ifdef CONFIG_STM32H7_USART_SWAP + case TIOCSSWAP: + { + uint32_t cr1; + uint32_t cr1_ue; + irqstate_t flags; + + flags = enter_critical_section(); + + /* Get the original state of UE */ + + cr1 = up_serialin(priv, STM32_USART_CR1_OFFSET); + cr1_ue = cr1 & USART_CR1_UE; + cr1 &= ~USART_CR1_UE; + + /* Disable UE, SWAP can only be written when UE=0 */ + + up_serialout(priv, STM32_USART_CR1_OFFSET, cr1); + + /* Enable/disable Swap mode. */ + + uint32_t cr = up_serialin(priv, STM32_USART_CR2_OFFSET); + + if (arg == SER_SWAP_ENABLED) + { + cr |= USART_CR2_SWAP; + } + else + { + cr &= ~USART_CR2_SWAP; + } + + up_serialout(priv, STM32_USART_CR2_OFFSET, cr); + + /* Re-enable UE if appropriate */ + + up_serialout(priv, STM32_USART_CR1_OFFSET, cr1 | cr1_ue); + leave_critical_section(flags); + } + break; +#endif + #ifdef CONFIG_SERIAL_TERMIOS case TCGETS: { diff --git a/arch/arm/src/stm32l4/Kconfig b/arch/arm/src/stm32l4/Kconfig index ee3451bb3c1..3287011238a 100644 --- a/arch/arm/src/stm32l4/Kconfig +++ b/arch/arm/src/stm32l4/Kconfig @@ -4005,6 +4005,22 @@ config STM32L4_USART_SINGLEWIRE Enable single wire UART support. The option enables support for the TIOCSSINGLEWIRE ioctl in the STM32L4 serial driver. +config STM32L4_USART_INVERT + bool "Signal Invert Support" + default n + depends on STM32L4_USART + ---help--- + Enable signal inversion UART support. The option enables support for the + TIOCSINVERT ioctl in the STM32L4 serial driver. + +config STM32L4_USART_SWAP + bool "Swap RX/TX pins support" + default n + depends on STM32L4_USART + ---help--- + Enable RX/TX pin swapping support. The option enables support for the + TIOCSSWAP ioctl in the STM32L4 serial driver. + if PM config STM32L4_PM_SERIAL_ACTIVITY diff --git a/arch/arm/src/stm32l4/stm32l4_serial.c b/arch/arm/src/stm32l4/stm32l4_serial.c index e9b5548e22b..c564cae5a0c 100644 --- a/arch/arm/src/stm32l4/stm32l4_serial.c +++ b/arch/arm/src/stm32l4/stm32l4_serial.c @@ -1789,6 +1789,23 @@ static int stm32l4serial_ioctl(FAR struct file *filep, int cmd, #ifdef CONFIG_STM32L4_USART_SINGLEWIRE case TIOCSSINGLEWIRE: { + + uint32_t cr1; + uint32_t cr1_ue; + irqstate_t flags; + + flags = enter_critical_section(); + + /* Get the original state of UE */ + + cr1 = stm32l4serial_getreg(priv, STM32L4_USART_CR1_OFFSET); + cr1_ue = cr1 & USART_CR1_UE; + cr1 &= ~USART_CR1_UE; + + /* Disable UE, HDSEL can only be written when UE=0 */ + + stm32l4serial_putreg(priv, STM32L4_USART_CR1_OFFSET, cr1); + /* Change the TX port to be open-drain/push-pull and enable/disable * half-duplex mode. */ @@ -1807,6 +1824,104 @@ static int stm32l4serial_ioctl(FAR struct file *filep, int cmd, } stm32l4serial_putreg(priv, STM32L4_USART_CR3_OFFSET, cr); + + /* Re-enable UE if appropriate */ + + stm32l4serial_putreg(priv, STM32L4_USART_CR1_OFFSET, cr1 | cr1_ue); + leave_critical_section(flags); + } + break; +#endif + +#ifdef CONFIG_STM32L4_USART_INVERT + case TIOCSINVERT: + { + uint32_t cr1; + uint32_t cr1_ue; + irqstate_t flags; + + flags = enter_critical_section(); + + /* Get the original state of UE */ + + cr1 = stm32l4serial_getreg(priv, STM32L4_USART_CR1_OFFSET); + cr1_ue = cr1 & USART_CR1_UE; + cr1 &= ~USART_CR1_UE; + + /* Disable UE, {R,T}XINV can only be written when UE=0 */ + + stm32l4serial_putreg(priv, STM32L4_USART_CR1_OFFSET, cr1); + + /* Enable/disable signal inversion. */ + + uint32_t cr = stm32l4serial_getreg(priv, STM32L4_USART_CR2_OFFSET); + + if (arg & SER_INVERT_ENABLED_RX) + { + cr |= USART_CR2_RXINV; + } + else + { + cr &= ~USART_CR2_RXINV; + } + + if (arg & SER_INVERT_ENABLED_TX) + { + cr |= USART_CR2_TXINV; + } + else + { + cr &= ~USART_CR2_TXINV; + } + + stm32l4serial_putreg(priv, STM32L4_USART_CR2_OFFSET, cr); + + /* Re-enable UE if appropriate */ + + stm32l4serial_putreg(priv, STM32L4_USART_CR1_OFFSET, cr1 | cr1_ue); + leave_critical_section(flags); + } + break; +#endif + +#ifdef CONFIG_STM32L4_USART_SWAP + case TIOCSSWAP: + { + uint32_t cr1; + uint32_t cr1_ue; + irqstate_t flags; + + flags = enter_critical_section(); + + /* Get the original state of UE */ + + cr1 = stm32l4serial_getreg(priv, STM32L4_USART_CR1_OFFSET); + cr1_ue = cr1 & USART_CR1_UE; + cr1 &= ~USART_CR1_UE; + + /* Disable UE, SWAP can only be written when UE=0 */ + + stm32l4serial_putreg(priv, STM32L4_USART_CR1_OFFSET, cr1); + + /* Enable/disable Swap mode. */ + + uint32_t cr = stm32l4serial_getreg(priv, STM32L4_USART_CR2_OFFSET); + + if (arg == SER_SWAP_ENABLED) + { + cr |= USART_CR2_SWAP; + } + else + { + cr &= ~USART_CR2_SWAP; + } + + stm32l4serial_putreg(priv, STM32L4_USART_CR2_OFFSET, cr); + + /* Re-enable UE if appropriate */ + + stm32l4serial_putreg(priv, STM32L4_USART_CR1_OFFSET, cr1 | cr1_ue); + leave_critical_section(flags); } break; #endif