RS-485 RTS drive RS-485 Tx-enable from Kernel

I have been struggling to get RS-485 Tx enable coms working on Beaglebone black.
As a newbie, Robert Nelson and Zmatt have been very helpful (and patient) with instructions to help me get this working.
I now have RTS and CTS enabled on my UART1 using BB-UART1-00A0.dts
I can drive RTS high and low from my CPP app, but the kernel does not automatically drive RTS for my RS-485 driver Tx-enable as I hoped.

I noted there was also a BB-UART4-RS485-00A0.dts file which pretty much models what I did to BB-UART1-00A0.dts except with UART4
The significant change was fragment 3 which has RS-485 related parameters which looked hopeful.

    fragment@3 {
        target = <&uart4>;
        __overlay__ {
            status = "okay";
            pinctrl-names = "default";
            pinctrl-0 = <&bb_uart4_rs485_pins>;
            rs485-rts-delay = <0 0>;

            rts-gpio = <&gpio3 19 1>; /*  GPIO_ACTIVE_HIGH>; */

So I tried this adding the following to my /boot/uEnv.txt file


sudo ./ gives me:

P9.11                             28 T17 fast rx      6 uart 4 rxd       serial@481a8000 (pinmux_bb_uart4_rs485_pins)
P9.13                             29 U17 fast         6 uart 4 txd       serial@481a8000 (pinmux_bb_uart4_rs485_pins)
P9.27                            105 C13 fast    down 7 gpio 3.19        serial@481a8000 (pinmux_bb_uart4_rs485_pins)

I am not driving P9 pin 27 in my CPP app, hoping the Kernel will control it automatically but my scope shows it stays low even when I transmit.

I feel I am very close now but just need help to get this over the line.


Hi Robert and Matt and anyone else following this.

I finally have it working on:

  • UART 1 using BB-UART1-00A0.dts
  • UART 4 using BB-UART4-00A0.dts

I had not configured the rs485conf struct using termios in my CPP test app properly.

If anyone follows this, please note:
RTS logic levels are backwards from what you might expect eg to set RTS high while transmitting you need:

  • rs485conf.flags &= ~(SER_RS485_RTS_ON_SEND);
  • rs485conf.flags |= (SER_RS485_RTS_AFTER_SEND);

You must also set the delays eg:
rs485conf.delay_rts_before_send = 1; /* Delay before send (milliseconds) /|
rs485conf.delay_rts_after_send = 0; /
Delay after send (milliseconds) */|

Thanks for your help - I really appreciate your time!
Best regards

I see in both cases, specifically the UART4 case, the regular overlay is used: BB-UART4-00A0.dts and not the RS485 Version (BB-UART4-RS485-00A0.dts) or the RTS/CTS version (BB-UART4-RTSCTS-00A0.dts). The regular overlay ignores RTS/CTS pins so they should not be able to be used.

In addition the UART4 RTS/CTS pins interfere with the HDMI/Video pins.

Given these facts I have a few questions

  1. How does the rs485 kernel software know which pin to pull to enable sending data?
  2. Are you using the default UART4 RTS pin (P8_33)?
  3. Did you also disable the video (disable_uboot_overlay_video=1) in /boot/uEnv.txt
  4. Do you have to recompile the Kernel with/wo the CONFIG_SERIAL_8250_OMAP=y remarked out?

I too need a RS485 port but I need an I2C and SPI buses as well so the UART4 seems to be the best route as I do not need HDMI out.

If anybody has a more in-depth and up-to-date understanding of how to make this work and how/why it does work, It would be appreciated. I am having a difficult time getting this to work with generic software like modpoll.

Hi Doug

I am far from an expert but I impart the following information from Robert which enabled me get it all working.

You must add the RTS and CTS line (CTS not required for RS-485) into the BB-UART4-RS485-00A0.dts file fragments 1 & 2 eg as follows:


  • Copyright (C) 2013 CircuitCo
  • Virtual cape for UART4 on connector pins P9.13 P9.11
  • This program is free software; you can redistribute it and/or modify
  • it under the terms of the GNU General Public License version 2 as
  • published by the Free Software Foundation.


#include <dt-bindings/board/am335x-bbw-bbb-base.h>
#include <dt-bindings/pinctrl/am33xx.h>

/ {
* Helper to show loaded overlays under: /proc/device-tree/chosen/overlays/
fragment@0 {
overlay {

        chosen {
            overlays {
                BB-UART4-00A0 = __TIMESTAMP__;

 * Free up the pins used by the cape from the pinmux helpers.
fragment@1 {
    target = <&ocp>;
    __overlay__ {
        P9_13_pinmux { status = "disabled"; };    /* uart4_txd */
        P9_11_pinmux { status = "disabled"; };    /* uart4_rxd */
        P8_33_pinmux { status = "disabled"; };
        P8_35_pinmux { status = "disabled"; };

fragment@2 {
    target = <&am33xx_pinmux>;
    __overlay__ {
        bb_uart4_pins: pinmux_bb_uart4_pins {
            pinctrl-single,pins = <
                BONE_P9_13 (PIN_OUTPUT | MUX_MODE6)    // gpmc_wpn.uart4_txd_mux2
                BONE_P9_11 (PIN_INPUT  | MUX_MODE6)    // gpmc_wait0.uart4_rxd_mux2
                BONE_P8_33 (PIN_OUTPUT | MUX_MODE6)    // uart4_rtsn.uart4_rtsn
                BONE_P8_35 (PIN_INPUT | MUX_MODE6)    // uart4_ctsn.uart4_ctsn

fragment@3 {
    target = <&uart4>;
    __overlay__ {
        status = "okay";
        pinctrl-names = "default";
        pinctrl-0 = <&bb_uart4_pins>;


Q1: See dts file source above.
Q2: Yes
Q3: Yes, and also disable_uboot_overlay_audio=1
You also need to map in the dtb0 files you are using eg in my case: i2c, Real time clock DS3231 (for DS1307) and the UARTx files as follows:



Q4 No I did not do this but you must also add the following text to /boot/uboot/uEnv.txt

optargs=quiet drm.debug=7 capemgr.enable_partno=BB-UART1,BB-UART2.BB-UART4,BB-UART5,BB-I2C1

You can test success (after reboot) using

cd /opt/scripts/device/bone
sudo ./

eg result include the following lines

> P9.20 / cape i²c sda  94 D18 fast rx   0 uart 1 cts  serial@48022000 (pinmux_bb_uart1_pins)
> P9.19 / cape i²c scl  95 D17 fast      0 uart 1 rts  serial@48022000 (pinmux_bb_uart1_pins)
> P9.26                  96 D16 fast rx   0 uart 1 rxd  serial@48022000 (pinmux_bb_uart1_pins)
> P9.24                  97 D15 fast      0 uart 1 txd  serial@48022000 (pinmux_bb_uart1_pins)

After this if you enable RS-485 mode (see my last post before this for CPP), you can just transmit data and the Kernel will assert RTS to drive Tx-Enable automatically. I have checked this with my scope and it works exceptionally well.

Good luck!

1 Like

Well, I did as suggested and got the UART4-RS485 ‘kind of’ working. I assume we had to add the RTS (P8_33) back in because the UART driver cannot really use GPIO pins as the UART4-RS485.dts suggests is possible.

After making all the changes I still have to open UART4 as an RS232 port, trying to open as RS485 port in libmodbus fails. In addition I have to tell libmodbus to use the RTS signaling otherwise I get no RTS output at all.

Just before I made these changes I had got a working setup with UART4 && UART4-RTSCTS and using the above mentioned settings for libmodbus.

So with all the changes I have the same setup as using UART4 && UART4-RTSCTS.

I am not sure what went wrong but I appreciate the help. This is farther than I have gotten with the UART4-RS485 so far. But if it is not going to get me any closer than a stock version of the other overlays, I will revert back to them.

One last question, is it reasonable to say the stock UART4-RS485 overlay does not work? If so, is the reason it is not changed because there is just not enough manpower or something else?
I am not entirely grasping what the development practice and mindset is for this community.

Thanks again for the help.

Hi Doug

I am just a humble user like you, relaying my own experience. I am new to the Beagle too since last December so I can’t speak to the mindset of the community. From my own experience, the BBB is a well equipped low cost low spec SBC. The problem I have is with the documentation on how you do all of this stuff. It seems to be a collection of community experiences, but the problem is many articles are out of date.

Robert Nelson and Matt helped me get it going with the process I described to you, although using using the standard BB-UARTX-00A0.dts → .dtbo files

My understanding is that the overlay enabled us to get RTS and CTS handshake lines assigned to UARTS 1, 4 & 5.

Once this is set up at OS level, in my case my CPP app using termios can configure under software control, the UART for:

  • no flow control
  • software flow control
  • rts / cts hardware flow control (eg for RS-232)
  • RS-485 Tx-enable (controlled by the Kernel) (for RS-485)

…without changing the overlays

This makes sense to me. I hope it helps.

These properties are specific to the omap-serial driver which hasn’t been used for quite a while, its replacement being the 8250-omap driver. Here are my personal notes on the rs485-related DT properties of both drivers: rs485 DT properties -

Yeah it’s broken, and there’s not really a proper replacement for it since 8250-omap doesn’t support using a random gpio for rts until kernel 5.3. And these overlays are kinda redundant anyway since rs485 mode is typically configured from userspace instead of using DT config.

Hi Matt
You said “…since 8250-omap doesn’t support using a random gpio for rts until kernel 5.3. …”
Do you mean we do not have to select expansion bus pins which also have an overlay map option for RTS?
The reason I ask is it would be nice to be able to also use UART2 with RTS for RS-485 by assigning RTS to a GPIO pin in the BB-UART2-00A0.dts file. Is this possible?

What I meant is that (in kernel 4.x, when using 8250-omap) you cannot use an artbirary pin as rts, the pin needs to actually have rts for that uart as one of its mux modes, e.g. for UART2 the only RTS pin is P8.38.