RS-485 Tx-Enable UART1 Continuing from issue 31223

Hi Robert
Thanks for your assistance. I am sorry to be a burden but I just need a little more help if possible please.
I have done the following:

  1. cloned the beagleboard/bb.org-overlays project
  2. edited the file home\debian/bb.org-overlays/src/arm/BB-UART1-00A0.dts and added (uncommented and changed to mode 7)
    BONE_P9_19 (PIN_OUTPUT | MUX_MODE7)|// uart1_rtsn.uart1_rtsn
    BONE_P9_20 (PIN_INPUT | MUX_MODE7)|// uart1_ctsn.uart1_ctsn
  3. checked lines 59-64 but found they already contained the text you described.
  4. make
  5. sudo make install
  6. rebooted.
    Everything built successfully and no errors were reported.

But when I check my UART1 RTS pin using:

config-pin -q p9.19
Current mode for P9_19 is: default

…there is no change.

I tried changing it to mode0 as for UART1 the the P9 port pin 19 is uart1_rtsn in MODE0 and MODE7 is GPIO.

My test app still cannot manually control RTS and the driver does not automatically drive it for Tx-Enable when I am sending data which is what I am hoping for. (checked on my oscillation).

I think the missing pieces in my understanding might be:

  • confirming expectations: Are we able to get RTS to automatically drive Tx-Enablke when I send data or must I drive it high manually before I send and low after all data is sent?
  • confirming which mode I need to set uart1_rtsn and uart1_ctsn to: mode 0 or 7 for RTS to drive my Tx-Enable
  • confirming if I need to add other parameters to the section in lines 59 - 64? If so, what do I need to add.
  • confirming if I need to add other parameters from your earlier response to the 8250_omap.yaml file. I also don’t understand how this fits in. Do I need to clone this project or do anything with this file.

Thanks and best regards
Michael

config-pin should not be used on pins configured in a specific mode in an overlay…

Use show-pins:

debian@bbb-pwr01-ser09:/opt/scripts/device/bone$ ./show-pins.pl 

Regards,

1 Like

Hi Robert
Thanks for the quick response.
This shows P9.20 and P9.19 seem to be assigned as i2c 2

P9.20 / cape i²c sda 94 D18 fast rx up 3 i²c 2 sda ocp/P9_ 20_pinmux (pinmux_P9_20_default_pin)
P9.19 / cape i²c scl 95 D17 fast rx up 3 i²c 2 scl ocp/P9_ 19_pinmux (pinmux_P9_19_default_pin)

I don’t understand why as this is MODE3 according to the Expansion Header table.
I guess I need to remove i2c2 support but I couldn’t see any way to do this in /boot/uEnv.txt. Can you please advise.

Can you please help clarify my understanding by answering the following:

  • confirming expectations: Are we able to get RTS to automatically drive Tx-Enablke when I send data or must I drive it high manually before I send and low after all data is sent?
  • confirming which mode I need to set uart1_rtsn and uart1_ctsn to: mode 0 or 7 for RTS to drive my Tx-Enable
  • confirming if I need to add other parameters to the section in lines 59 - 64? If so, what do I need to add.
  • confirming if I need to add other parameters from your earlier response to the 8250_omap.yaml file. I also don’t understand how this fits in. Do I need to clone this project or do anything with this file.

Really appreciate your help.

In

change:

P9_24_pinmux { status = disabled; };/* uart1_txd */
P9_26_pinmux { status = disabled; };/* uart1_rxd */

to:

P9_24_pinmux { status = disabled; };/* uart1_txd */
P9_26_pinmux { status = disabled; };/* uart1_rxd */
P9_19_pinmux { status = disabled; };
P9_20_pinmux { status = disabled; };

Then it should lock P9_19/P9_20 to your overlay…

Regards,

Hi Robert
Thanks for your reply.
I did what you said but it gave an error when I ran make as follows:

debian@beaglebone:~/bb.org-overlays$ make
DTC src/arm/BB-UART1-00A0.dtbo
Error: src/arm/BB-UART1-00A0.dts:41.28-29 syntax error
FATAL ERROR: Unable to parse input tree
make[1]: *** [Makefile:173: src/arm/BB-UART1-00A0.dtbo] Error 1
make: *** [Makefile:119: all_arm] Error 2

Wondering if it was a typo I added quotes around “disabled” and then make and sudo make install were successfull.

But after a reboot, udo ./show-pins.pl still reports P9.20 and P9.19 mapped to i2c2 as follows:

P9.20 / cape i²c sda 94 D18 fast rx up 3 i²c 2 sda ocp/P9_20_pinmux (pinmux_P9_20_default_pin)
P9.19 / cape i²c scl 95 D17 fast rx up 3 i²c 2 scl ocp/P9_19_pinmux (pinmux_P9_19_default_pin)
P9.26 96 D16 fast rx up 0 uart 1 rxd ocp/P9_26_pinmux (pinmux_P9_26_uart_pin)
P9.24 97 D15 fast rx up 0 uart 1 txd ocp/P9_24_pinmux (pinmux_P9_24_uart_pin)

So the BB-UART1-00AA.dts file from line 34 looks like this:

	 * Free up the pins used by the cape from the pinmux helpers.
	 */
	fragment@1 {
		target = <&ocp>;
		__overlay__ {
			P9_24_pinmux { status = "disabled"; };/* uart1_txd */
			P9_26_pinmux { status = "disabled"; };/* uart1_rxd */
			P9_19_pinmux { status = "disabled"; };
			P9_20_pinmux { status = "disabled"; };
		};
	};

	fragment@2 {
		target = <&am33xx_pinmux>;
		__overlay__ {
			bb_uart1_pins: pinmux_bb_uart1_pins {
				pinctrl-single,pins = <
					BONE_P9_24 (PIN_OUTPUT | MUX_MODE0)	// uart1_txd.uart1_txd
					BONE_P9_26 (PIN_INPUT | MUX_MODE0)	// uart1_rxd.uart1_rxd
					BONE_P9_19 (PIN_OUTPUT | MUX_MODE0)	// uart1_rtsn.uart1_rtsn
					BONE_P9_20 (PIN_INPUT | MUX_MODE0)	// uart1_ctsn.uart1_ctsn
				>;
			};
		};
	};

	fragment@3 {
		target = <&uart1>;
		__overlay__ {
			status = "okay";
			pinctrl-names = "default";
			pinctrl-0 = <&bb_uart1_pins>;
		};
	};
};

It looks like your overlay isn’t being used at all, did you enable it by configuring its path into one of the uboot_overlay_addr4…7 variables in /boot/uEnv.txt ? Note that configuring a pin using an overlay is mutually exclusive with being able to use config-pin on that pin. If you’re able to query or set a pin’s mode using config-pin, then that pin has not been (successfully) setup by an overlay.

Why are you using an overlay anyway? If you want to use P9.19 in gpio mode then you can just reconfigure it with e.g. config-pin P9.19 gpio_pd (to configure gpio mode with weak internal pull-down enabled). Note that P9.19 by default is configured to have weak internal pull-up, so if you want to use it as an active-high drive-enable signal you’ll probably want to add an external 1 kΩ pulldown to ensure the driver doesn’t get unintionally enabled during boot. (Hopefully doing so doesn’t confuse u-boot too much). Or beter, just use some other pin that’s already gpio with internal pulldown by default.

If you want to use kernel-controlled RS485 driver-enable then it needs to be configured into uart rts mode, not gpio mode. It appears that the uart rts/cts modes are inexplicably missing from cape-universal so for that you will need to use an overlay, but setting mux mode 0 (in case of P9_19) rather than mode 7. I’m not sure what you’re doing with P9.20, rs485 does not use the cts pin.

Hi Matt

Thanks for your help.

I had not enabled my overlay in the /boot/uEnv.txt (I have not used overlay before and wasn’t aware of this step).

I have now done this with some success.

debian@beaglebone:/opt/scripts/device/bone$ sudo ./show-pins.pl
now shows

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)

Also from my CPP app I can now toggle RTS under software control to control RS-485 Tx-enable eg:

int rts = TIOCM_RTS;
if (ioctl(port, TIOCMBIC, &rts) < 0) {
   throw std::runtime_error("Failed to clear RTS");
}
int rts = TIOCM_RTS;
if (ioctl(port, TIOCMBIS, &rts) < 0) {
   throw std::runtime_error("Failed to set RTS");
}

and I can see the line switching on my scope.

You are correct I am not using CTS for RS-485 but I thought I would set configure both RTS and CTS so I can use them for flow control on RS-232 on other ports.

But I am still wondering (hopeful) if that it is possible for this to be switched automatically whenever I transmit data - eg you mentioned “kernel-controlled RS485 driver-enable”. Can you please advise if this is possible and if so, what changes I need to make. I have already configured cts and rts for UART1 to mux mode 0.
But I only want to do this if the Kernel uses something a little more sophisticated than sitting in a tight loop polling the UART registers for transmit buffer empty. I have a working solution now which I think works better than this by keeping the receiver enabled so I receive what I send. By monitoring the reception of what I send I can effectively turn off RTS when the last byte of my transmission is received back within 1 - 3 milliseconds which isn’t too bad for 9600 and 19.2 kbps.

Cheers

For enabling kernel rs485 support I found this bit of code in one of my pastebins:

#include <sys/ioctl.h>
#include <linux/serial.h>
 
int uart_get_rs485_config( int fd, struct serial_rs485 *config )
{
    return ioctl( fd, TIOCGRS485, config );
}
 
int uart_set_rs485_config( int fd, struct serial_rs485 const *config )
{
    return ioctl( fd, TIOCSRS485, config );
}
 
int uart_enable_rs485( int fd, bool active_low )
{
    struct serial_rs485 config;
    int res = uart_get_rs485_config( fd, &config );
    if( res < 0 )
        return res;
    if( active_low ) {
        config.flags &= ~SER_RS485_RTS_ON_SEND;
        config.flags |= SER_RS485_RTS_AFTER_SEND;
    } else {
        config.flags |= SER_RS485_RTS_ON_SEND;
        config.flags &= ~SER_RS485_RTS_AFTER_SEND;
    }
    config.flags |= SER_RS485_ENABLED;
    return uart_set_rs485_config( fd, &config );
}

(I don’t remember if it was tested at all)

And kernel rs485 mode will deassert RTS using an interrupt from the uart upon transmit completion (fifo and serializer empty), or, if you configure non-zero delay_rts_after_send, the kernel will schedule a high-resolution timer in the uart interrupt handler and deassert RTS in the timer interrupt. Any solution you might hack together in userspace will be less reliable and less efficient than kernel rs485 mode.

Hi Matt
Thanks for this.
I left a note on ticket 31327 to say I managed to get this going and thanking you and Robert Nelson for your invaluable help.
Best regards