From 5631ff6db1eaa9eac8e945b0a68c22a70c0ed42a Mon Sep 17 00:00:00 2001 From: Jiri Vlasak Date: Fri, 20 Feb 2026 10:55:07 +0100 Subject: [PATCH 1/4] kinetis/serial: Enable RTS as GPIO for RS485CONTROL When using CONFIG_UART?_RS485CONTROL, RTS pin is set high when sending data and low otherwise. PIN_UART?_RTS is defined in the board.h file as the appropriate ALT functionality of the chip's port. However, it may happen that PIN_UART?_RTS is wired to another pin of the chip that does not support the RTS as ALT functionality of the UART? in question. This commit addresses such a situation. When UART?_RS485CONTROL_RTSISGPIO is set in menuconfig for the given UART?, it is expected that the PIN_UART?_RTS is defined as GPIO_OUTPUT, and the PIN_UART?_RTS is set high when sending data and low otherwise. Signed-off-by: Jiri Vlasak --- arch/arm/src/kinetis/Kconfig | 66 +++++++++++++++++ arch/arm/src/kinetis/kinetis_serial.c | 103 ++++++++++++++++++++++++++ 2 files changed, 169 insertions(+) diff --git a/arch/arm/src/kinetis/Kconfig b/arch/arm/src/kinetis/Kconfig index 4349d5ee7e895..3403ae098c3b6 100644 --- a/arch/arm/src/kinetis/Kconfig +++ b/arch/arm/src/kinetis/Kconfig @@ -1409,6 +1409,17 @@ config UART0_RS485CONTROL ---help--- Enable RS-485 transmit enable on UART0. +config UART0_RS485CONTROL_RTSISGPIO + bool "RTS pin of the UART0 is GPIO" + default n + depends on UART0_RS485CONTROL + ---help--- + RTS pin of the UART0 is wired to something else than the chip's + ALT pin with UART0 RTS functionality. + + The GPIO, to which the UART0's RTS pin is wired to, is set to + high when sending data and low otherwise. + config UART1_RS485CONTROL bool "Use UART1 RTS as RS-485 transmit enable" default n @@ -1417,6 +1428,17 @@ config UART1_RS485CONTROL ---help--- Enable RS-485 transmit enable on UART1. +config UART1_RS485CONTROL_RTSISGPIO + bool "RTS pin of the UART1 is GPIO" + default n + depends on UART1_RS485CONTROL + ---help--- + RTS pin of the UART1 is wired to something else than the chip's + ALT pin with UART1 RTS functionality. + + The GPIO, to which the UART1's RTS pin is wired to, is set to + high when sending data and low otherwise. + config UART2_RS485CONTROL bool "Use UART2 RTS as RS-485 transmit enable" default n @@ -1425,6 +1447,17 @@ config UART2_RS485CONTROL ---help--- Enable RS-485 transmit enable on UART2. +config UART2_RS485CONTROL_RTSISGPIO + bool "RTS pin of the UART2 is GPIO" + default n + depends on UART2_RS485CONTROL + ---help--- + RTS pin of the UART2 is wired to something else than the chip's + ALT pin with UART2 RTS functionality. + + The GPIO, to which the UART2's RTS pin is wired to, is set to + high when sending data and low otherwise. + config UART3_RS485CONTROL bool "Use UART3 RTS as RS-485 transmit enable" default n @@ -1433,6 +1466,17 @@ config UART3_RS485CONTROL ---help--- Enable RS-485 transmit enable on UART3. +config UART3_RS485CONTROL_RTSISGPIO + bool "RTS pin of the UART3 is GPIO" + default n + depends on UART3_RS485CONTROL + ---help--- + RTS pin of the UART3 is wired to something else than the chip's + ALT pin with UART3 RTS functionality. + + The GPIO, to which the UART3's RTS pin is wired to, is set to + high when sending data and low otherwise. + config UART4_RS485CONTROL bool "Use UART4 RTS as RS-485 transmit enable" default n @@ -1441,6 +1485,17 @@ config UART4_RS485CONTROL ---help--- Enable RS-485 transmit enable on UART4. +config UART4_RS485CONTROL_RTSISGPIO + bool "RTS pin of the UART4 is GPIO" + default n + depends on UART4_RS485CONTROL + ---help--- + RTS pin of the UART4 is wired to something else than the chip's + ALT pin with UART4 RTS functionality. + + The GPIO, to which the UART4's RTS pin is wired to, is set to + high when sending data and low otherwise. + config UART5_RS485CONTROL bool "Use UART5 RTS as RS-485 transmit enable" default n @@ -1449,6 +1504,17 @@ config UART5_RS485CONTROL ---help--- Enable RS-485 transmit enable on UART5. +config UART5_RS485CONTROL_RTSISGPIO + bool "RTS pin of the UART5 is GPIO" + default n + depends on UART5_RS485CONTROL + ---help--- + RTS pin of the UART5 is wired to something else than the chip's + ALT pin with UART5 RTS functionality. + + The GPIO, to which the UART5's RTS pin is wired to, is set to + high when sending data and low otherwise. + endmenu # Kinetis RS485 transmit driver support endmenu # Kinetis UART Configuration diff --git a/arch/arm/src/kinetis/kinetis_serial.c b/arch/arm/src/kinetis/kinetis_serial.c index 5ce2fd4cb9f4f..232f0999aa9b7 100644 --- a/arch/arm/src/kinetis/kinetis_serial.c +++ b/arch/arm/src/kinetis/kinetis_serial.c @@ -1296,6 +1296,107 @@ static int up_interrupts(int irq, void *context, void *arg) uart_xmitchars(dev); handled = true; } + + if ((s1 & UART_S1_TC) == 0) + { + /* TC cleared, transmission started. */ + +#if defined(CONFIG_UART0_RS485CONTROL_RTSISGPIO) + if (&g_uart0priv == priv) + { + kinetis_gpiowrite(g_uart0priv.rts_gpio, 1); + handled = true; + } + +#endif +#if defined(CONFIG_UART1_RS485CONTROL_RTSISGPIO) + if (&g_uart1priv == priv) + { + kinetis_gpiowrite(g_uart1priv.rts_gpio, 1); + handled = true; + } + +#endif +#if defined(CONFIG_UART2_RS485CONTROL_RTSISGPIO) + if (&g_uart2priv == priv) + { + kinetis_gpiowrite(g_uart2priv.rts_gpio, 1); + handled = true; + } + +#endif +#if defined(CONFIG_UART3_RS485CONTROL_RTSISGPIO) + if (&g_uart3priv == priv) + { + kinetis_gpiowrite(g_uart3priv.rts_gpio, 1); + handled = true; + } + +#endif +#if defined(CONFIG_UART4_RS485CONTROL_RTSISGPIO) + if (&g_uart4priv == priv) + { + kinetis_gpiowrite(g_uart4priv.rts_gpio, 1); + handled = true; + } + +#endif +#if defined(CONFIG_UART5_RS485CONTROL_RTSISGPIO) + if (&g_uart5priv == priv) + { + kinetis_gpiowrite(g_uart5priv.rts_gpio, 1); + handled = true; + } + +#endif + } + else + { + /* Transmission complete. Do not set handle, exit immediately. */ + +#if defined(CONFIG_UART0_RS485CONTROL_RTSISGPIO) + if (&g_uart0priv == priv) + { + kinetis_gpiowrite(g_uart0priv.rts_gpio, 0); + } + +#endif +#if defined(CONFIG_UART1_RS485CONTROL_RTSISGPIO) + if (&g_uart1priv == priv) + { + kinetis_gpiowrite(g_uart1priv.rts_gpio, 0); + } + +#endif +#if defined(CONFIG_UART2_RS485CONTROL_RTSISGPIO) + if (&g_uart2priv == priv) + { + kinetis_gpiowrite(g_uart2priv.rts_gpio, 0); + } + +#endif +#if defined(CONFIG_UART3_RS485CONTROL_RTSISGPIO) + if (&g_uart3priv == priv) + { + kinetis_gpiowrite(g_uart3priv.rts_gpio, 0); + } + +#endif +#if defined(CONFIG_UART4_RS485CONTROL_RTSISGPIO) + if (&g_uart4priv == priv) + { + kinetis_gpiowrite(g_uart4priv.rts_gpio, 0); + } + +#endif +#if defined(CONFIG_UART5_RS485CONTROL_RTSISGPIO) + if (&g_uart5priv == priv) + { + kinetis_gpiowrite(g_uart5priv.rts_gpio, 0); + } + +#endif + } } return OK; @@ -1919,6 +2020,7 @@ static void up_txint(struct uart_dev_s *dev, bool enable) #ifndef CONFIG_SUPPRESS_SERIAL_INTS priv->ie |= UART_C2_TIE; + priv->ie |= UART_C2_TCIE; up_setuartint(priv); /* Fake a TX interrupt here by just calling uart_xmitchars() with @@ -1933,6 +2035,7 @@ static void up_txint(struct uart_dev_s *dev, bool enable) /* Disable the TX interrupt */ priv->ie &= ~UART_C2_TIE; + priv->ie &= ~UART_C2_TCIE; up_setuartint(priv); } From d5db9f7a7ed54c7a0f34581e949705a2c5b534c3 Mon Sep 17 00:00:00 2001 From: Jiri Vlasak Date: Wed, 25 Mar 2026 12:04:40 +0100 Subject: [PATCH 2/4] kinetis/serial: Do not xmit when no chars to xmit When there are no data in the TX buffer, we can avoid call to the uart_xmitchars. Signed-off-by: Jiri Vlasak --- arch/arm/src/kinetis/kinetis_serial.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm/src/kinetis/kinetis_serial.c b/arch/arm/src/kinetis/kinetis_serial.c index 232f0999aa9b7..ddffc8130c098 100644 --- a/arch/arm/src/kinetis/kinetis_serial.c +++ b/arch/arm/src/kinetis/kinetis_serial.c @@ -1288,7 +1288,7 @@ static int up_interrupts(int irq, void *context, void *arg) * the TX data register. */ - if ((s1 & UART_S1_TDRE) != 0) + if ((s1 & UART_S1_TDRE) != 0 && dev->xmit.head != dev->xmit.tail) #endif { /* Process outgoing bytes */ From 17b925d05c49efa94f0b77cefac67e9429d094f4 Mon Sep 17 00:00:00 2001 From: Jiri Vlasak Date: Wed, 25 Mar 2026 12:09:18 +0100 Subject: [PATCH 3/4] kinetis/serial: Do not fake TX interrupt Because it is not needed anymore. The original code here is from the initial implementation in the commit 66b873ef77e. Signed-off-by: Jiri Vlasak --- arch/arm/src/kinetis/kinetis_serial.c | 6 ------ 1 file changed, 6 deletions(-) diff --git a/arch/arm/src/kinetis/kinetis_serial.c b/arch/arm/src/kinetis/kinetis_serial.c index ddffc8130c098..ccfa84ef29e90 100644 --- a/arch/arm/src/kinetis/kinetis_serial.c +++ b/arch/arm/src/kinetis/kinetis_serial.c @@ -2022,12 +2022,6 @@ static void up_txint(struct uart_dev_s *dev, bool enable) priv->ie |= UART_C2_TIE; priv->ie |= UART_C2_TCIE; up_setuartint(priv); - - /* Fake a TX interrupt here by just calling uart_xmitchars() with - * interrupts disabled (note this may recurse). - */ - - uart_xmitchars(dev); #endif } else From 94e564acd13f3216b907d635880ed85e22808e54 Mon Sep 17 00:00:00 2001 From: Jiri Vlasak Date: Thu, 26 Mar 2026 12:26:31 +0100 Subject: [PATCH 4/4] kinetis/pinmux: Do not redefine PIN_UART2_RTS When a developer working on BSP wants UART1 with RTS, the following needs to be added in the BSP's include/board.h file: #define PIN_UART1_RTS PIN_UART1_RTS_1 which says that PIN_UART1_RTS_1 -- the first alternative pin with UART1 RTS function -- should be used for the UART1's RTS. There are no alternative pins for PIN_UART2_RTS, therefore a similar definition is not used for PIN_UART2_RTS. However, that is a complication when we want PIN_UART2_RTS to be defined as GPIO, for example: #define PIN_UART2_RTS (GPIO_OUTPUT | PIN_PORTB | PIN2) In such a case, PIN_UART2_RTS is later redefined to the only alternative function from hardware/kinetis_???pinmux.h file. This patch avoids the redefinition of already defined names. We considered renaming PIN_UART2_RTS to PIN_UART2_RTS_1 in the hardware/kinetis_???pinmux.h file, but that is breaking change. We try to avoid breaking change. Signed-off-by: Jiri Vlasak --- arch/arm/src/kinetis/hardware/kinetis_k40pinmux.h | 4 +++- arch/arm/src/kinetis/hardware/kinetis_k60pinmux.h | 4 +++- arch/arm/src/kinetis/hardware/kinetis_k64pinmux.h | 4 +++- arch/arm/src/kinetis/hardware/kinetis_k66pinmux.h | 4 +++- 4 files changed, 12 insertions(+), 4 deletions(-) diff --git a/arch/arm/src/kinetis/hardware/kinetis_k40pinmux.h b/arch/arm/src/kinetis/hardware/kinetis_k40pinmux.h index ad647509d39a8..8d274df1df2fa 100644 --- a/arch/arm/src/kinetis/hardware/kinetis_k40pinmux.h +++ b/arch/arm/src/kinetis/hardware/kinetis_k40pinmux.h @@ -351,7 +351,9 @@ #define PIN_LCD_P40 (PIN_ANALOG | PIN_PORTD | PIN0) #define PIN_SPI0_PCS0_3 (PIN_ALT2 | PIN_PORTD | PIN0) -#define PIN_UART2_RTS (PIN_ALT3 | PIN_PORTD | PIN0) +#if !defined(PIN_UART2_RTS) +# define PIN_UART2_RTS (PIN_ALT3 | PIN_PORTD | PIN0) +#endif #define PIN_LCD_P40F (PIN_ALT7 | PIN_PORTD | PIN0) #define PIN_LCD_P41 (PIN_ANALOG | PIN_PORTD | PIN1) #define PIN_ADC0_SE5B (PIN_ANALOG | PIN_PORTD | PIN1) diff --git a/arch/arm/src/kinetis/hardware/kinetis_k60pinmux.h b/arch/arm/src/kinetis/hardware/kinetis_k60pinmux.h index f2afdbe118a26..8b2f73815961d 100644 --- a/arch/arm/src/kinetis/hardware/kinetis_k60pinmux.h +++ b/arch/arm/src/kinetis/hardware/kinetis_k60pinmux.h @@ -346,7 +346,9 @@ #define PIN_FB_TA (PIN_ALT6 | PIN_PORTC | PIN19) #define PIN_SPI0_PCS0_3 (PIN_ALT2 | PIN_PORTD | PIN0) -#define PIN_UART2_RTS (PIN_ALT3 | PIN_PORTD | PIN0) +#if !defined(PIN_UART2_RTS) +# define PIN_UART2_RTS (PIN_ALT3 | PIN_PORTD | PIN0) +#endif #define PIN_FTM3_CH0_2 (PIN_ALT4 | PIN_PORTD | PIN0) #define PIN_FB_ALE (PIN_ALT5 | PIN_PORTD | PIN0) #define PIN_FB_CS1 (PIN_ALT5 | PIN_PORTD | PIN0) diff --git a/arch/arm/src/kinetis/hardware/kinetis_k64pinmux.h b/arch/arm/src/kinetis/hardware/kinetis_k64pinmux.h index dd71e6a5cef10..76a93c5b87533 100644 --- a/arch/arm/src/kinetis/hardware/kinetis_k64pinmux.h +++ b/arch/arm/src/kinetis/hardware/kinetis_k64pinmux.h @@ -563,7 +563,9 @@ #define PIN_UART1_TX_2 (PIN_ALT3 | PIN_PORTE | PIN0) #define PIN_UART2_CTS (PIN_ALT3 | PIN_PORTD | PIN1) -#define PIN_UART2_RTS (PIN_ALT3 | PIN_PORTD | PIN0) +#if !defined(PIN_UART2_RTS) +# define PIN_UART2_RTS (PIN_ALT3 | PIN_PORTD | PIN0) +#endif #define PIN_UART2_RX (PIN_ALT3 | PIN_PORTD | PIN2) #define PIN_UART2_TX (PIN_ALT3 | PIN_PORTD | PIN3) diff --git a/arch/arm/src/kinetis/hardware/kinetis_k66pinmux.h b/arch/arm/src/kinetis/hardware/kinetis_k66pinmux.h index ab9960f4e94b6..089e8563081ba 100644 --- a/arch/arm/src/kinetis/hardware/kinetis_k66pinmux.h +++ b/arch/arm/src/kinetis/hardware/kinetis_k66pinmux.h @@ -678,7 +678,9 @@ #define PIN_UART1_TX_2 (PIN_ALT3 | PIN_PORTE | PIN0) #define PIN_UART2_CTS (PIN_ALT3 | PIN_PORTD | PIN1) -#define PIN_UART2_RTS (PIN_ALT3 | PIN_PORTD | PIN0) +#if !defined(PIN_UART2_RTS) +# define PIN_UART2_RTS (PIN_ALT3 | PIN_PORTD | PIN0) +#endif #define PIN_UART2_RX (PIN_ALT3 | PIN_PORTD | PIN2) #define PIN_UART2_TX (PIN_ALT3 | PIN_PORTD | PIN3)