How to use RS485

From IGEP - ISEE Wiki

Revision as of 11:06, 6 October 2011 by Pau (talk | contribs)

Jump to: navigation, search

Overview of How-To

This How-To is meant to be a starting point for people to learn to use the RS-485 port on IGEP0020 board.

Below this How-To is a short .c file which describe how to setup and write data on the RS-485 port.

Feedback and Contributing

At any point, if you see a mistake you can contribute to this How-To.

Add RS-485 support to Linux

Using kernel 2.6.35.13

In this kernel is not necessary add RS-485 support

Using kernel 2.6.33 series

Follow http://www.igep.es/index.php?option=com_kunena&Itemid=97&func=view&catid=13&id=1195&limit=6

Using kernel 2.6.28 series

Tested on a 2.6.28.10-3 version kernel.

To use correctly the RS-485 interface chip we need to configure the serial port driver in the kernel to manage the RTS signal (Request To Send) to enable the TX section (DE pin) only when data are transmitted on TXD line (Transmit Data). This is a software only solution, requiring no special hardware, but timing control for delays is only accurate to the next nearest jiffy.

First of all, download the latest stable kernel version

$ wget http://downloads.igep.es/sources/kernel/linux-omap-2.6.28.10-3.tar.gz
$ tar xzf linux-omap-2.6.28.10-3.tar.gz
$ cd linux-omap-2.6.28.10-3
$ make ARCH=arm CROSS_COMPILE=arm-none-linux-gnueabi- igep0020_defconfig

Next, enable the RS-485 support.

$ make ARCH=arm CROSS_COMPILE=arm-none-linux-gnueabi- menuconfig

Configure the kernel to enable RS-485 support.

Device drivers --->
Character devices --->
Serial drivers  --->
*** serial port extensions ***
[*] Allow hand shake line half duplex direction signaling

Finally build kernel image with RS-485 support

$ make ARCH=arm CROSS_COMPILE=arm-none-linux-gnueabi- uImage

Test RS-485 communication with two IGEP0020 boards

Connect two IGEP0020 boards using J940 connector like this:

 J940                         J940
 ---                           ---
| 1 |---------- GND ----------| 1 |
| 2 |-X                     X-| 2 |
| 3 |-X                     X-| 3 |
| 4 |----------  A  ----------| 4 |
| 5 |----------  B  ----------| 5 |
 ---                           ---

Setup a NFS-TFTP environment (poky-image-sato) for each board using kernel image with RS-485 support, and power up

Build the example for your target boards,

$ cd linux-omap-2.6.28.10-3
$ arm-none-linux-gnueabi-gcc 485-example.c -o 485-example -Iinclude -Iarch/arm/include

and copy to target rootfs.

Now, open a ssh console to the first board and execute the microcom command:

root@igep0020:~# microcom /dev/ttyS0 
connected to '/dev/ttyS0' (9600 bps), exit with ctrl-X...

On second board, open a ssh and execute the 485 example:

root@igep0020:~# ./485-example

If all is ok, should appear "ABC" in microcom console.

root@igep0020:~# microcom /dev/ttyS0 
connected to '/dev/ttyS0' (9600 bps), exit with ctrl-X...
ABC

Appendix A: 485-example.c : Basic example of RS-485 half duplex transmission

/* 485-example.c : Basic example of RS485 half duplex transmission */
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <termios.h>

#include <sys/ioctl.h>
#include <asm/ioctls.h>

#include <linux/rs485.h>

int main(void)
{
	char dev[] = "/dev/ttyS0";
	char tosend[] = {'A', 'B', 'C'};
	struct serial_rs485_settings ctrl485;
	int status;
	int fd;

	struct termios ti;
	speed_t speed;

	/* Open the port */
	fd = open(dev, O_RDWR);
	if (fd < 0) {
		printf("%s: Unable to open.\n", dev);
		return -1;
	}

	/* Set the port in 485 mode */
	ctrl485.flags = SER_RS485_MODE | SER_RS485_MODE_RTS | SER_RS485_RTS_TX_LOW;
	ctrl485.delay_before_send = 0;
	ctrl485.delay_after_send = 0;

	status = ioctl(fd, TIOCSRS485, &ctrl485);
	if (status) {
		printf("%s: Unable to configure port in 485 mode, status (%i)\n", dev, status);
		return -1;
	}

	/* Set the port speed */
	speed = B9600;
	tcgetattr(fd, &ti);
	cfsetospeed(&ti, speed);
	cfsetispeed(&ti, speed);
	tcsetattr(fd, TCSANOW, &ti);

	/* Send content to RS485 */
	if (write(fd, tosend, sizeof(tosend)) != sizeof(tosend)) {
		printf("%s: write() failed\n", dev);
	}

	return 0;
}

References

ISEE References

Read the Official IGEP0020 Hardware Reference Manual (chapter "5.3 CONNECTOR J940: POWER + RS-485" )