Difference between revisions of "RS-485"

From ArmadeusWiki
Jump to: navigation, search
(Add supported platforms)
(Links)
 
(12 intermediate revisions by 2 users not shown)
Line 1: Line 1:
 
Informations and HOWTOs for ArmadeuS RS-485 support.
 
Informations and HOWTOs for ArmadeuS RS-485 support.
  
Author: JanosA
+
RS-485 mostly used in half duplex operation mode, and uses a differential balanced line over twisted pair. RS-485 drivers need to be put in transmit mode explicitly by asserting a signal to the driver. This allows RS-485 to implement linear topologies using only two wires, and it can span relatively large distances (up to 1,200m @ 100kbit/s).
  
 +
Before the RS-485 related parts, please have a look on: [[Serial ports usage on Linux]]
  
== Supported Board and Software versions ==
+
Author: [[Users:JanosA]]
* Currently only the APF28 (iMX28) board with Linux kernel v2.6.35.3 supported. (mxs-auart patch)
+
* Linux stty patch included only in busybox v1.19.4 (Patch already submitted to the busybox mailing list)
+
  
 +
== Supported Board and Software versions ==
 +
* Use the latest Armadeus GIT/SF repository or the latest stable release.
 +
* Currently tested only on the [[APF28]] (i.MX28) board with Linux kernel 2.6.35 (patch 462) and 4.9 (patch 703). If device tree is used, you need to activate rts/cts on UART used for RS-485.
 +
* Busybox ''stty'' command requires a patch included in Armadeus BSP, to handle specifics RS-485 parameters handling.
  
== Linux stty ==
+
== Changing port parameters ==
 
* Setup APF28 serial port for RS-485 communication:
 
* Setup APF28 serial port for RS-485 communication:
 
<pre class=apf>
 
<pre class=apf>
# stty -F /dev/ttySP0 raw
+
# export SERIAL_DEV=/dev/ttySP0
# stty -F /dev/ttySP0 -echo -echoe -echok
+
# stty -F $SERIAL_DEV 9600
# stty -F /dev/ttySP0 rs485
+
# stty -F $SERIAL_DEV raw
 +
# stty -F $SERIAL_DEV -echo -echoe -echok
 +
# stty -F $SERIAL_DEV rs485
 
</pre>
 
</pre>
  
 
* Set extra delays (if needed) for TXEN/RTS signaling before and after the transmitted packet (in microseconds):
 
* Set extra delays (if needed) for TXEN/RTS signaling before and after the transmitted packet (in microseconds):
 
<pre class=apf>
 
<pre class=apf>
# stty -F /dev/ttySP0 rs485delaybefore 100
+
# stty -F $SERIAL_DEV rs485delaybefore 100
# stty -F /dev/ttySP0 rs485delayafter 100
+
# stty -F $SERIAL_DEV rs485delayafter 100
 
</pre>
 
</pre>
  
* To get current RS-485 parameters. (If the port device supports the RS-485 options you will see the last two lines)
+
* To get current RS-485 parameters: (if the serial port supports the RS-485 options, you will see previous rs485 parameters values)
 
<pre class=apf>
 
<pre class=apf>
 
# stty -F /dev/ttySP0
 
# stty -F /dev/ttySP0
Line 36: Line 41:
 
Please note:
 
Please note:
 
* You can't set the "rs485delaylastchartx" parameter, it's calculated automatically from the baudrate.
 
* You can't set the "rs485delaylastchartx" parameter, it's calculated automatically from the baudrate.
Special notes for the APF28/iMX28 mxs-auart driver:
+
Special notes for the APF28/i.MX28 ''mxs-auart'' driver:
 
* All delays are in microseconds.
 
* All delays are in microseconds.
 
* The "rs485delaylastchartx" parameter is not used in DMA mode.
 
* The "rs485delaylastchartx" parameter is not used in DMA mode.
 
* The parameters: "rs485rtsonsend" "rs485rtsaftersend" "rs485rxduringtx" are not used. (Only used by atmel_serial.c and crisv10.c drivers)
 
* The parameters: "rs485rtsonsend" "rs485rtsaftersend" "rs485rxduringtx" are not used. (Only used by atmel_serial.c and crisv10.c drivers)
* If the RS-485 mode is turned on, it will override (turn off) the RTS/CTS hardware flow settings of the uart, don't care what is configured.
+
* If the RS-485 mode is turned on, it will override (turn off) the RTS/CTS hardware flow settings of the UART, whatever is configured.
  
 
+
== How to use it from C code ==
== C code ==
+
* The RS-485 mode can also be turned on with ioctl calls from C code, here is the example:
* The RS-485 mode can be turned on with ioctl calls from C code, here is the example:
+
 
<source lang="C">
 
<source lang="C">
 
#include <stdio.h>
 
#include <stdio.h>
Line 93: Line 97:
 
}
 
}
 
</source>
 
</source>
 
  
 
== Hardware Notes ==
 
== Hardware Notes ==
* The RS-485 Transmit Enable (TXEN) output will be the RTS pin of the uart.  
+
* The RS-485 Transmit Enable (TXEN) output will be the RTS pin of the UART.  
* The TXEN/RTS output is _active low_, it must be inverted to use it with the popular RS-485 transceiver ICs.
+
* The TXEN/RTS output is _active low_, it must be inverted to use it with the popular RS-485 transceiver ICs. On kernel with device tree, this can be done with ''rs485-rts-active-high'' option when declaring UART config.
* When the u-boot runs and the board start to boot, the RTS pin works as input, please add a pullup resistor to this pin before the inverter, to prevent RS-485 bus lockups.
+
* When U-Boot runs and the board start to boot, the RTS pin works as an input, so please add a pull-up resistor to this pin, before the inverter, to prevent RS-485 bus lockups.
 +
 
 +
==Links==
 +
* Some C example code to use Modbus RTU through RS485: https://github.com/artemysfr/embedded-tools
 +
* De-asserting RTS fastest as possible is a well known problem on every platforms:
 +
** https://blog.savoirfairelinux.com/en-ca/2013/adding-rs-485-support-to-the-beaglebone-with-short-turnaround-delay/
 +
 
 +
[[Category:Serial ports]]
 +
[[Category:RS485]]
 +
[[Category:Modbus]]

Latest revision as of 17:41, 1 April 2022

Informations and HOWTOs for ArmadeuS RS-485 support.

RS-485 mostly used in half duplex operation mode, and uses a differential balanced line over twisted pair. RS-485 drivers need to be put in transmit mode explicitly by asserting a signal to the driver. This allows RS-485 to implement linear topologies using only two wires, and it can span relatively large distances (up to 1,200m @ 100kbit/s).

Before the RS-485 related parts, please have a look on: Serial ports usage on Linux

Author: Users:JanosA

Supported Board and Software versions

  • Use the latest Armadeus GIT/SF repository or the latest stable release.
  • Currently tested only on the APF28 (i.MX28) board with Linux kernel 2.6.35 (patch 462) and 4.9 (patch 703). If device tree is used, you need to activate rts/cts on UART used for RS-485.
  • Busybox stty command requires a patch included in Armadeus BSP, to handle specifics RS-485 parameters handling.

Changing port parameters

  • Setup APF28 serial port for RS-485 communication:
# export SERIAL_DEV=/dev/ttySP0
# stty -F $SERIAL_DEV 9600
# stty -F $SERIAL_DEV raw
# stty -F $SERIAL_DEV -echo -echoe -echok
# stty -F $SERIAL_DEV rs485
  • Set extra delays (if needed) for TXEN/RTS signaling before and after the transmitted packet (in microseconds):
# stty -F $SERIAL_DEV rs485delaybefore 100
# stty -F $SERIAL_DEV rs485delayafter 100
  • To get current RS-485 parameters: (if the serial port supports the RS-485 options, you will see previous rs485 parameters values)
# stty -F /dev/ttySP0
speed 9600 baud; line = 0;
intr = ^C; quit = ^\; erase = ^?; kill = ^U; eof = ^D; eol = <undef>;
eol2 = <undef>; swtch = <undef>; start = ^Q; stop = ^S; susp = ^Z; rprnt = ^R;
werase = ^W; lnext = ^V; flush = ^O; min = 1; time = 0;
-brkint -imaxbel
rs485 -rs485rtsonsend -rs485rtsaftersend -rs485rxduringtx
rs485delaybefore = 100; rs485delayafter = 100; rs485delaylastchartx = 1250;

Please note:

  • You can't set the "rs485delaylastchartx" parameter, it's calculated automatically from the baudrate.

Special notes for the APF28/i.MX28 mxs-auart driver:

  • All delays are in microseconds.
  • The "rs485delaylastchartx" parameter is not used in DMA mode.
  • The parameters: "rs485rtsonsend" "rs485rtsaftersend" "rs485rxduringtx" are not used. (Only used by atmel_serial.c and crisv10.c drivers)
  • If the RS-485 mode is turned on, it will override (turn off) the RTS/CTS hardware flow settings of the UART, whatever is configured.

How to use it from C code

  • The RS-485 mode can also be turned on with ioctl calls from C code, here is the example:
#include <stdio.h>
#include <fcntl.h>
#include <linux/ioctl.h>
#include <linux/serial.h>
#include <asm-generic/ioctls.h> /* TIOCGRS485 + TIOCSRS485 ioctl definitions */

int main(void) {
         struct serial_rs485 rs485conf;

         int fd = open ("/dev/ttySP0", O_RDWR);
         if (fd < 0) {
                 printf("Error: Can't open: /dev/ttySP0\n");
         }


         /* Don't forget to read first the current state of the RS-485 options with ioctl.
            If You don't do this, You will destroy the rs485conf.delay_rts_last_char_tx
            parameter which is automatically calculated by the driver when You opens the
            port device. */
         if (ioctl (fd, TIOCGRS485, &rs485conf) < 0) {
                 printf("Error: TIOCGRS485 ioctl not supported.\n");
         }

         /* Enable RS-485 mode: */
         rs485conf.flags |= SER_RS485_ENABLED;

         /* Set rts/txen delay before send, if needed: (in microseconds) */
         rs485conf.delay_rts_before_send = 0;

         /* Set rts/txen delay after send, if needed: (in microseconds) */
         rs485conf.delay_rts_after_send = 0;

         if (ioctl (fd, TIOCSRS485, &rs485conf) < 0) {
                 printf("Error: TIOCSRS485 ioctl not supported.\n");
         }

         fcntl(fd, F_SETFL, 0);
         int n = write(fd, "ABC\r\n", 5);
         if (n < 0) {
                 /* Error handling */
         }

         if (close (fd) < 0) {
                 printf("Error: Can't close: /dev/ttySP0\n");
         }
}

Hardware Notes

  • The RS-485 Transmit Enable (TXEN) output will be the RTS pin of the UART.
  • The TXEN/RTS output is _active low_, it must be inverted to use it with the popular RS-485 transceiver ICs. On kernel with device tree, this can be done with rs485-rts-active-high option when declaring UART config.
  • When U-Boot runs and the board start to boot, the RTS pin works as an input, so please add a pull-up resistor to this pin, before the inverter, to prevent RS-485 bus lockups.

Links