RS485 while booting

      RS485 while booting

      Dear support-team,

      we're using armstoneA9 ttymxc3 for RS485 (Modbus RTU). We have connected RX/TX to R/D as well as RTS to enable RE/DE on a SN65HVD10 transceiver. It's working perfect but while booting sequence. The problem seems that while booting the RTS is enabling driving the bus lines on the transceiver. This will disturb communication of all other devices for some seconds. How can I invert this RTS line while booting on U-boot and inside the kernel so that the driver will be disabled?

      Thanks for answers.
      Kind regards.
      RTS seems to be high while booting because on UART with RTS/CTS this will indicate the receiver is not ready.
      What if I would change the following device tree configuration

      Source Code

      1. #ifdef CONFIG_ARMSTONEA9_UART_D
      2. /* UART4 on pins 19,20,23,24 Port D */
      3. pinctrl_uart4_1: uart4grp-1{
      4. fsl,pins = <
      5. MX6QDL_PAD_CSI0_DAT12__UART4_TX_DATA 0x1b0b1
      6. MX6QDL_PAD_CSI0_DAT13__UART4_RX_DATA 0x1b0b1
      7. #ifdef CONFIG_ARMSTONEA9_UART_D_RTSCTS
      8. MX6QDL_PAD_CSI0_DAT16__UART4_CTS_B 0x1b0b1
      9. MX6QDL_PAD_CSI0_DAT17__UART4_RTS_B 0x1b0b1
      10. #endif /* CONFIG_ARMSTONEA9_UART_D_RTSCTS */
      11. >;
      12. };
      13. #endif

      to

      Source Code

      1. #ifdef CONFIG_ARMSTONEA9_UART_D
      2. /* UART4 on pins 19,20,23,24 Port D */
      3. pinctrl_uart4_1: uart4grp-1{
      4. fsl,pins = <
      5. MX6QDL_PAD_CSI0_DAT12__UART4_TX_DATA 0x1b0b1
      6. MX6QDL_PAD_CSI0_DAT13__UART4_RX_DATA 0x1b0b1
      7. #ifdef CONFIG_ARMSTONEA9_UART_D_RTSCTS
      8. MX6QDL_PAD_CSI0_DAT16__UART4_CTS_B 0x1b0b1
      9. MX6QDL_PAD_CSI0_DAT17__UART4_RTS_B 0x130b1
      10. #endif /* CONFIG_ARMSTONEA9_UART_D_RTSCTS */
      11. >;
      12. };
      13. #endif

      If I understood the documentation correctly this would enable a 100kOhm pull down instead of a 100kOhm pull up. Could this help without messing up the whole configuration/functionality? Or is there a better way to ensure MX6QDL_PAD_CSI0_DAT17__UART4_RTS_B to be low while booting?

      Thanks for any help.
      1. Settings in the device tree have only influence in Linux itself, not during the boot process in the bootloaders. To have a different setting before Linux, you have to modify U-Boot.

      2. If a signal is an output, then the pull-up or pull-down does not have an effect because the state of the pin is set by the output value. Pull resistors can only influence high impedance signals, e.g. signals that are set as input. So as long as you have this pin still set as RTS, you have to change the RTS state, not the pull resistor.

      3. The serial ports on all i.MX6 CPUs suffer from a misnaming on behalf of NXP. The naming of all UART pins is given with DCE meaning, only the TXD and RXD lines are given with DTE meaning. But on a DCE device, RTS is an input and CTS is an output. So the driver actually needs to change the CTS pin for RS485. However in our hardware description, we are using the more common naming scheme with DTE meaning. not DCE. Here RTS is an output and CTS an input. We handle this consistently across all documents and across all our boards. Only here in the device tree you get in contact with the original NXP naming scheme. Which means you actually have to modify MX6QDL_PAD_CSI0_DAT16__UART4_CTS_B in the device tree to have an effect on the line that is named RTS in our hardware description. (And before you ask, no, using the port in DTE mode would not be better, because then the TXD line would be an input and the RXD line an output.) Sorry for this confusion, but believe me, we have cursed this NXP naming scheme more than once. Everybody uses DTE names. How can they use DCE names? And if they really think they must use DCE meaning, then they should use it consistently, i.e. also for the TXD and RXD lines.

      You F&S Support Team
      F&S Elektronik Systeme GmbH
      As this is an international forum, please try to post in English.
      Da dies ein internationales Forum ist, bitten wir darum, Beiträge möglichst in Englisch zu verfassen.
      Thanks for that explanation. But what does it mean for me?
      So I guess what to do now is adding something like this to board_init in u-boot:

      Source Code

      1. static iomux_v3_cfg_t const pwmpad[] = {
      2. IOMUX_PADS(PAD_CSI0_DAT16__UART4_CTS_B | MUX_PAD_CTRL(NO_PAD_CTRL)),
      3. };
      4. int board_init(void) {
      5. ...
      6. SETUP_IOMUX_PADS(pwmpad);
      7. gpio_direction_output(IMX_GPIO_NR(x, xx), 1);
      8. ...
      9. }

      And do I have to control this pin manually in kernel startup again or does the kernel leave the state as it was set by u-boot?
      Nearly. You still initialize the pin as CTS which means it is still an output and it is still controlled by the UART function. You need to configure it as a GPIO. And the NO_PAD_CTRL simply means that the settings for speed, pull resistor, drive strength etc. are not changed. Which means the previous settings (for example the reset value) is kept. This means the pull resistor may still be a pull-up. This is not what you want.

      So the right way would be:

      Source Code

      1. static iomux_v3_cfg_t const pwmpad[] = {
      2. IOMUX_PADS(PAD_CSI0_DAT16__GPIO6_IO02 | MUX_PAD_CTRL(PAD_CTL_PUS_100K_DOWN)),
      3. };


      The pad remains as GPIO until Linux starts the UART driver for this UART. Then the pin gets reconfigured as CTS (in NXP names) which makes it again an output, which may set the pin again to high level. However then you can quickly open the port and configure it for RS485, which should put the pin to read state.

      A completely different approach would be to change the hardware. For example have a second GPIO that is known to be kept as input across the whole boot process, add a pull-down to it and AND this signal with the RTS (alias CTS) signal. This means the result is definitely low as long as the GPIO is low.

      When the boot procedure is over, your application has started and you have switched the UART port to RS485 mode, you manually set the GPIO to output high. From now on the UART will control the level of the combined signal.

      Your F&S Support Team
      F&S Elektronik Systeme GmbH
      As this is an international forum, please try to post in English.
      Da dies ein internationales Forum ist, bitten wir darum, Beiträge möglichst in Englisch zu verfassen.
      Thanks for answering. I got it working while booting in u-boot.

      The time between the kernel muxing the pin to UART and my firmware is starting still is too long.
      So I muxed the pin to GPIO in device tree too. Now the pin is low while complete booting and kernel starting.

      The problem now is how do I remux the pin to UART in my firmware before opening the UART.
      If I leave the pin as GPIO the UART is working without the RTS signal only.
      Are there functions for remuxing the pins at runtime?
      Is there a way to remux pins with help of the sysfs?

      Thanks in advance...
      Sorry for the late answer, but last week was Embedded World Exhibition and most of our developers were there at the fair in Nürnberg.

      I'm not aware of any sysfs option to switch to a different pinmux at runtime. This is why I suggested the solution with an additional GPIO that is ANDed with the real RTS signal. This GPIO can be switched manually at any time and would work in the way as you want. But of course this is a hardware modification.

      Some drivers use more than one group of pinmux settings. For example the usdhc driver (MMC) has one set for 50 MHz, one set for 100 MHz and one set for 200 MHz. You can see this for example in the efusA7UL device tree (efusa7ul.dts). But then the driver switches the pinmux sets when necessary. So theoretically the UART driver could also have two sets, one for regular operation and one for RS485 operation and when RS485 mode is switched on and off by the user with ioctl(), the driver could switch between these sets. Or the driver could also have an additional device tree property RS485, that starts the port in RS485 mode with RTS in the correct state (read), even before the port is opened. But unfortunately at the moment the driver uses neither this nor that variant. To have such a feature, the driver implementation must be enhanced.

      Your F&S Support Team
      F&S Elektronik Systeme GmbH
      As this is an international forum, please try to post in English.
      Da dies ein internationales Forum ist, bitten wir darum, Beiträge möglichst in Englisch zu verfassen.
      I decided doing it the last way and checking for a "linux,rs485-enabled-at-boot-time" inside the device tree uart definition (e.g. like the atmel or omap drivers are doing this).

      If anybody is interested I can send the modified drivers/tty/serial/imx.c file without warranty (it's working for me).
      I was not able to attach the file directly to this post. How to do this??
      When adding an answer, you can also click on "Erweiterte Antwort". There you can usually also attach files.

      Your F&S Support Team
      F&S Elektronik Systeme GmbH
      As this is an international forum, please try to post in English.
      Da dies ein internationales Forum ist, bitten wir darum, Beiträge möglichst in Englisch zu verfassen.