Implement RS-485 Transeiver support in Kernel/DT

Hello,

I would like to know if it would be possible to implement RS-485 functionality in the kernel/devicetree.

We use a custom carrierboard, that uses up to 3 external, independant RS-485 busses (connected to the SOMs uarts). The busses all operate with 38400baud. We have some timer flops that automatically change the transeiver state between send/receive.

The following functions are available, per bus, which help us to optimize the transmission:

  • 1 Pin to detect if the transeiver is currently receiving data (RX_BUSY). This helps us to detect if there’s activity on the bus, so we won’t send anything to prevent collisions
  • 1 Pin to immediately set the transeiver to receive (TX_DISABLE) (this is currently not used by the software)
    Here’s an excerpt of the schematics for 1 bus (others are identical):
    mb-rs485 hosted at ImgBB — ImgBB

We use the following Pins:
Bus1:

  • TX: SODIMM 35 (UART_A TX)
  • RX: SODIMM 33 (UART_A RX)
  • RX_BUSY: SODIMM 97 (GPIO input)
  • TX_DISABLE: SODIMM 98 (GPIO output)

Bus2:

  • TX: SODIMM 38 (UART_B TX)
  • RX: SODIMM 36 (UART_B RX)
  • RX_BUSY: SODIMM 92 (GPIO input)
  • TX_DISABLE: SODIMM 95 (GPIO output)

Bus3:

  • TX: SODIMM 21 (UART_C TX)
  • RX: SODIMM 19 (UART_C RX)
  • RX_BUSY: SODIMM 88 (GPIO input)
  • TX_DISABLE: SODIMM 90 (GPIO output)

For now, we handle the GPIOs in userspace due to legacy reasons (currently, WinCE is used in the field).

Because we’re currently redesiging the carrierboard, it might be an option to change this part, so we could possibly use the integrated RS-485 driver from the kernel, including flow control to the transeiver.
Would it be possible to configure this in the device-tree? It is important to still support the legacy carrierboards aswell (using a different device-tree).

We use Toradex’ Yocto BSP 7 as a base for our system.
The following modules should be supported:
Colibri IMX8X
Colibri IMX6ULL

Nice to have, if possible:
Colibri T30

Info to our hardware:
RS-485 Transeiver: https://www.ti.com/product/THVD1410
Timer: https://www.ti.com/product/SN74LV123A

Thanks and Regards,

Simon

Hi, I’m the Toradex AI Assistant. The Toradex Support team will follow up with you shortly!

Did you like my answer?

:+1: :-1:


Hello Simon,

Thank you for reaching out with your question about implementing RS-485 functionality in the kernel/device tree for your custom carrier board using Toradex modules. Here’s how you can proceed:

  1. Device Tree Configuration: To enable RS-485 support, you can configure the device tree with properties such as linux,rs485-enabled-at-boot-time, rs485-rts-active-low, and rs485-rx-during-tx. These settings will help manage the RS-485 transceiver automatically through the UART interface.

  2. Handling GPIOs: For the RX_BUSY and TX_DISABLE pins, you can define these GPIOs in the device tree. While the kernel can manage some aspects, you might need a custom driver or a userspace application to handle specific logic, such as detecting bus activity and controlling the transceiver state.

  3. Legacy Support: To accommodate both new and legacy carrier boards, consider maintaining separate device tree configurations. This approach allows you to ensure each board version is correctly configured without impacting the other.

  4. Module Compatibility: Ensure your device tree modifications are compatible with the Colibri iMX8X and iMX6ULL modules. The Colibri T30 may have limitations due to its hardware constraints, as Tegra modules generally lack RS-485 transceiver control support.

By following these steps, you can effectively integrate RS-485 functionality into your system while maintaining compatibility with existing hardware setups. If you have further questions or need additional guidance, feel free to ask.

Best regards,
Toradex AI Assistant

Please, also check if these links can help you solve your problem:

How to Define RS485 in Device Tree.

Hello @SimonG,

To the best of my knowledge, this can be achieved by modifying the nodes for lpuart0, lpuart2 and lpuart3 to support rs485. These are defined in the file imx8x-colibri.dtsi. Following this article, the modified nodes would look like:

/* Colibri UART_B */
&lpuart0 {
        pinctrl-names = "default";
        pinctrl-0 = <&pinctrl_lpuart0>;
        linux,rs485-enabled-at-boot-time;
        rs485-rts-active-low;
        rs485-rx-during-tx;
        status= "okay";
};

/* Colibri UART_C */
&lpuart2 {
        pinctrl-names = "default";
        pinctrl-0 = <&pinctrl_lpuart2>;
        linux,rs485-enabled-at-boot-time;
        rs485-rts-active-low;
        rs485-rx-during-tx;
        status= "okay";
};

/* Colibri UART_A */
&lpuart3 {
        pinctrl-names = "default";
        pinctrl-0 = <&pinctrl_lpuart3>, <&pinctrl_lpuart3_ctrl>;
        linux,rs485-enabled-at-boot-time;
        rs485-rts-active-low;
        rs485-rx-during-tx;
        status= "okay";
};

I have not tested this. However, this is my assumption following other related threads that @ToradexAI suggested. Let me know if this works.

Hello @rudhi.tx

Thanks for your response. I checked the article, and in general, it shouldn’t be hard to enable RS-485 functionality like this.

However, I’m not sure how it would be possible to configure the RTS/CTS pins to control the transceiver. Are these just the same as for the regular uarts? Because UART_C does not have these for IMX8X and IMX6ULL.

Would it be possible to implement this in the driver directly, for half-duplex operation?
Basically, we could just use 1 pin to toggle the transceiver: for sending, set to high, for receiving (or while idle) set to low.

Regards,
Simon

Hi @SimonG

You might need to give a look to using the rts-gpios in the device tree to enable that functionality in the driver. There is a ton of info out there to parse and you’ll do yourself a favor looking around a while (if you haven’t already). Search thru here for things like:

rs485-gpios
rs485-rx-active-high
rs485-rx-during-tx

Regards,
Dave

@DaveM

Thanks for your hints, I’ll check this when I have some spare time available, probably in April.

Regards Simon