RS485 on Embedded Linux Boards

Introduction

An often asked issue in embedded systems is the use of any kind of RS485 busses. This example illustrates how to interface RS485 from our embedded linux boards. It covers the software part as well as the hardware.

Hardware

Using RS485 requires a RS485 tranceiver chip to be connected to an USART that is not level converted to RS232. On NanosG20 an ISL83485 is already integrated on USART1 (see NanosG20 technical reference for schematics). Normally, USART1 is /dev/ttyS2 on our Debian SD cards. It is recommended to use the USART's RTS line to control transmitter enable since RTS is used by the serial kernel driver in RS485 mode.

Note: Related to NanosG20 it is important to know RS485+ and RS485- occupy DTR and DSR pins on D-Sub X13. Special care has to be taken when using this multiplexed connector with RS232.

Note: On NanosG20 PB29 needs to be low to enable ISL83485's receiver.

NanosG20:~# echo 93 > /sys/class/gpio/export
NanosG20:~# echo out > /sys/class/gpio/gpio93/direction
NanosG20:~# echo 0 > /sys/class/gpio/gpio93/value

The exported PIN number 93 comes from 29 for PB29 added to PIOB's base address (which was 64 on our Debian Lenny systems). The Wheezy update uses 32 as base for PIOB. So, PB29 would become 29 + 32 = 61 there. See www.armbedded.eu/node/258 for details.

If a RS232 interface should be used for RS485 communication a converter is required. Taskit offers such a converter (rs232-to-rs485). It supports I/O handling via RTS line.

Software

Software handling does not differ that much from "normal" serial devices. The main difference is that the RS485 tranceiver needs to be considered correctly. Fortunately, this is covered by the serial device since kernel 2.6.35.
Note: Depending on hardware wiring it is not unusual that sent data is read back. The Software should either be aware of that or should disable the receiver during transmit.

Enable or disable RS485 mode.
RS485 mode can be enabled or disabled using a specific structure from <linux/serial.h>. Note that RTS is not used for any handshake in RS485 mode. Despite of this RTS is used to enable or disable the transmitter and is handled by serial driver automatically. A delay specifiying the amount of time the transmitter is to be enabled before any data is sent can be configured as well.

#include <fcntl.h>
#include <termios.h>
#include <linux/ioctl.h>
#include <linux/types.h>
#include <linux/serial.h>

void rs485_mode(int on)
{
	struct serial_rs485 rs485conf;

	if(on)
	{
		rs485conf.flags |= SER_RS485_ENABLED;
		rs485conf.delay_rts_before_send = 0x00000004;
		ioctl(fd, TIOCSRS485, &rs485conf);
	}
	else
	{
		rs485conf.flags &= ~SER_RS485_ENABLED;
		ioctl(fd, TIOCSRS485, &rs485conf);
	}
}

Control the receiver
Since transmit and receive lines are shared in a RS485 two wire bus, it might be useful to disable the receiver during a transmit to avoid reading back currently send data. For that case use c_cflag in struct termios.

#include <fcntl.h>
#include <termios.h>
#include <linux/ioctl.h>
#include <linux/types.h>
#include <linux/serial.h>

void rs485_receiver(int on)
{
	struct termios options;

	tcgetattr(fd, &options);
	if(on)
		options.c_cflag |= CREAD;
	else
		options.c_cflag &= ~CREAD;
	tcsetattr(fd, TCSANOW, &options);
	fcntl(fd, F_SETFL, FNDELAY);
}