BBB UART4 RTS for RS-485

Hello,
I’m writing an app for BeagleBoneBlack running debian (3.8.13-bone50). I would like to use UART4 to communicate with RS485 transmitter over P9.24(UART4 Tx), P9.26(UART4 Rx) and P8.33 (UART4 RTS).
I’ve disabled HDMI and enabled overlays BB-UART4 and BB-UART4-RTSCTS

`
cat /sys/devices/bone_capemgr.9/slots
0: 54:PF—
1: 55:PF—
2: 56:PF—
3: 57:PF—
4: ff:P-O-L Bone-LT-eMMC-2G,00A0,Texas Instrument,BB-BONE-EMMC-2G
5: ff:P-O-- Bone-Black-HDMI,00A0,Texas Instrument,BB-BONELT-HDMI
6: ff:P-O-- Bone-Black-HDMIN,00A0,Texas Instrument,BB-BONELT-HDMIN
7: ff:P-O-L Override Board Name,00A0,Override Manuf,BB-UART4
10: ff:P-O-L Override Board Name,00A0,Override Manuf,BB-UART4-RTSCTS

cat /proc/tty/driver/OMAP-SERIAL
serinfo:1.0 driver revision:
0: uart:OMAP UART0 mmio:0x44E09000 irq:72 tx:345 rx:0 RTS|CTS|DTR|DSR
4: uart:OMAP UART4 mmio:0x481A8000 irq:45 tx:61355 rx:1 brk:1 RTS|DTR|DSR

`

RS485 transmitter is connected through RS485-USB converter to PC. When I run screen /dev/ttyO4 9600 +crtscts and periodicaly write some data to it, PC receives it properly, but RTS line stays constantly low (I’m using scope on Tx and RTS lines).
I’ve also tried to write simple C program, using struct serial_rs485. When I write some data over this program, I got response: Resource temporarily unavailable and dmesg says omap_uart 481a8000.serial: Must use GPIO for RS485 Support.
When I tried to use:

struct serial_rs485 rs485conf; rs485conf.flags |= SER_RS485_USE_GPIO; rs485conf.gpio_pin = GPIO0_9;

I got error from gcc that it does not know those macros:

`
‘SER_RS485_USE_GPIO’ was not declared in this scope
rs485conf.flags |= SER_RS485_USE_GPIO;
‘struct serial_rs485’ has no member named ‘gpio_pin’
rs485conf.gpio_pin = GPIO0_9;
‘GPIO0_9’ was not declared in this scope
rs485conf.gpio_pin = GPIO0_9;

`

Could somebody help me? I have no more ideas.

Hi,

BB-UART4-RTSCTS-00A0.dts uses set those pins to UART RTS and CTS (mode 6).

But to use with “struct serial_rs485 rs485conf” you don’t need to set the pin as RTS, you just need to set the pin to GPIO (mode 7, at the .dts file).

I don’t know if I was clear, but I used RS485 and RTS as a GPIO, works nice.​

I actually just put up a tutorial for doing this in Python: http://inspire.logicsupply.com/2014/09/beaglebone-rs-485-communication.html

It uses GPIO1_16, but of course you can use any GPIO pin, including the one that’s shared with UART4 RTS.

When I tried to use:

struct serial_rs485 rs485conf; rs485conf.flags |= SER_RS485_USE_GPIO; rs485conf.gpio_pin = GPIO0_9;

I got error from gcc that it does not know those macros:

`
‘SER_RS485_USE_GPIO’ was not declared in this scope
rs485conf.flags |= SER_RS485_USE_GPIO;
‘struct serial_rs485’ has no member named ‘gpio_pin’
rs485conf.gpio_pin = GPIO0_9;
‘GPIO0_9’ was not declared in this scope
rs485conf.gpio_pin = GPIO0_9;

`

That’s because you’re compiling with the standard libc headers, which don’t include the modified serial_rs485 struct that uses the GPIO pin. The tutorial I linked above uses Python and just defines the same values locally, which you could do in C as well. You could also grab the Kernel source and include ‘include/uapi/linux/serial.h’, which has the patched serial_rs485 struct (https://github.com/RobertCNelson/bb-kernel/blob/am33x-v3.8/patches/fixes/0007-omap-RS485-support-by-Michael-Musset.patch#L201).

Thank you for your answers. The python code is working perfectly.
I need to use it in greater C project though. So I am compiling new kernel including RS485 patch. I have tried /opt/scripts/tools/update_kernel.sh hoping that it includes the RS485 patch …unsuccessfully.
I am now following steps from http://jkridner.wordpress.com/2014/06/04/yet-another-set-of-notes-on-building-beaglebone-kernel/

Dne středa, 3. září 2014 17:57:53 UTC+2 lucaso...@gmail.com napsal(a):

In the Debian image from Robert C Nelson, the patch rs485 is already included.

I’ve downloaded Robert C Nelson’s code and run build_kernel.sh and install_kernel.sh. I’ve controlled that sources are patched by rs485 patch.
BBB booted up normally and uname -r says that I am running new kernel. But I don’t have patched kernel headers. I have created serial.h header as following:

`
1 #include <linux/types.h>
2
3
4 struct serial_rs485 {
5 __u32 flags; /* RS485 feature flags /
6 #define SER_RS485_ENABLED (1 << 0) /
If enabled /
7 #define SER_RS485_RTS_ON_SEND (1 << 1) /
Logical level for
8 RTS pin when
9 sending /
10 #define SER_RS485_RTS_AFTER_SEND (1 << 2) /
Logical level for
11 RTS pin after sent*/
12 #define SER_RS485_RTS_BEFORE_SEND (1 << 3)
13 #define SER_RS485_USE_GPIO (1 << 5)
14 //#define SER_RS485_RX_DURING_TX (1 << 4)
15 __u32 delay_rts_before_send; /* Delay before send (milliseconds) /
16 __u32 delay_rts_after_send; /
Delay after send (milliseconds) /
17 // __u32 padding[5]; /
Memory is cheap, new structs
18 __u32 gpio_pin; /* GPIO Pin Index /
19 __u32 padding[4]; /
Memory is cheap, new structs
20 are a royal PITA … */
21 };

`

and used it in small example program:

`
#include <fcntl.h>
#include <termios.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include “serial.h”
//#include <include/uapi/linux/serial.h>
#include <stdio.h>
#include <unistd.h>

int main()
{
int fd = open("/dev/ttyO4", O_RDWR | O_NOCTTY | O_NDELAY);
if (fd < 0)
{
perror(“Error opening tty!”);
return 1;
}

struct serial_rs485 rs485conf;

rs485conf.flags |= SER_RS485_ENABLED;

rs485conf.flags |= SER_RS485_USE_GPIO;
rs485conf.gpio_pin = 9;
rs485conf.flags |= SER_RS485_RTS_ON_SEND;
rs485conf.flags &= ~(SER_RS485_RTS_AFTER_SEND);
rs485conf.delay_rts_before_send = 0;
rs485conf.delay_rts_after_send = 0;

if (ioctl (fd, TIOCSRS485, &rs485conf) < 0)
{
perror(“Bad ioctl”);
}

struct termios ttyc;
tcgetattr(fd, &ttyc);

cfsetospeed(&ttyc, B9600);
cfsetispeed(&ttyc, B9600);
ttyc.c_cflag &= ~CRTSCTS;
ttyc.c_cflag |= CS8 | CLOCAL | CREAD;
ttyc.c_cflag |= CRTSCTS;
ttyc.c_cc[VMIN] = 1;
ttyc.c_cc[VTIME] = 5;
tcsetattr(fd, TCSANOW, &ttyc);

char data = 0xAA;

int i = 0;
while(i < 10000)
{
if(write(fd, &data, 1) < 1)
{
perror(“Error sending char”);
break;
}

i++;
}

if (close (fd) < 0)
{
perror(“Error closing tty!”);
return 1;
}

return 0;
}
`
but RTS pin stays still LOW.

Dne čtvrtek, 4. září 2014 21:51:58 UTC+2 Mickae1 napsal(a):

Normally If you look at the log (dmsg) you should see a line rs485 something. It’s a printk that I show when the ioctl work.

And of course you have to configure the pin correctly = pin mode for TX, rx, gpio.

Normally If you look at the log (dmsg) you should see a line rs485 something. It’s a printk that I show when the ioctl work.

Right, it’s ‘rs485 v1.1’. If you see that in dmesg then the ioctl worked and it’s almost certainly a pinmux issue.

Yes, I can see ‘rs485 v1.1’. The python code still works fine out of the box. C code Rx and Tx lines work OK but RTS still does nothing.
When I exported the GPIO9 by hand, dmesg got:

`
[ 222.055685] gpio_request: gpio-9 (RS485 TXE) status -16
[ 222.055730] omap_uart 481a8000.serial: Could not request GPIO 9 : -16

`
That means that 485 kernel support works. Without manually exporting it says just “[ 537.089146] rs485 v1.1” and does nothing.

BUT now I’ve discovered something strange with logical level flags in struct serial_rs485, maybe I’m using different header or maybe I don’t understand it correctly.
When I changed the SER_RS485_RTS_AFTER_SEND to 0 and SER_RS485_RTS_ON_SEND to 0, it started working fine.
That means, when sending data, RTS goes HIGH, after sending, it goes immediately LOW , that means,
I expected setting ON_SEND to 1 and AFTER_SEND to 0, but with this setting it just changed from LOW to LOW.

Thank you both again for Your valuable help.
I’m satisfied now :slight_smile:

Dne pondělí, 8. září 2014 19:12:55 UTC+2 Alexander Hiam napsal(a):

Yes, I can see ‘rs485 v1.1’. The python code still works fine out of the box. C code Rx and Tx lines work OK but RTS still does nothing.
When I exported the GPIO9 by hand, dmesg got:

`
[ 222.055685] gpio_request: gpio-9 (RS485 TXE) status -16
[ 222.055730] omap_uart 481a8000.serial: Could not request GPIO 9 : -16

`
That means that 485 kernel support works. Without manually exporting it says just “[ 537.089146] rs485 v1.1” and does nothing.

BUT now I’ve discovered something strange with logical level flags in struct serial_rs485, maybe I’m using different header or maybe I don’t understand it correctly.
When I changed the SER_RS485_RTS_AFTER_SEND to 0 and SER_RS485_RTS_ON_SEND to 0, it started working fine.
That means, when sending data, RTS goes HIGH, after sending, it goes immediately LOW , that means,
I expected setting ON_SEND to 1 and AFTER_SEND to 0, but with this setting it just changed from LOW to LOW.

Oh yeah, forgot about that. There’s a couple ternary operators in the driver that I think might be backwards, which makes it the logic levels a bit counter intuitive. It’s:
SER_RS485_ENABLED | SER_RS485_USE_GPIO
for an active high RE/DE signal and:
SER_RS485_ENABLED | SER_RS485_USE_GPIO | SER_RS485_RTS_ON_SEND | SER_RS485_RTS_AFTER_SEND
for an inverted, active low RE/DE signal.

Hello, everyone, I just notify something with the RS485 :

I’ve made a test programm, and in this programm, I’m sending all the time one byte.

With the oscilloscope, I can see that there is a delay between each frame : 100ms .

Do you have the same thing ?

Micka,

my problem was two program working on the same uart …^^

Hi Alexander,

The link you provided does not work:

http://inspire.logicsupply.com/2014/09/beaglebone-rs-485-communication.html

Do you mind sending me the tutorial? I am currently designing my own cape which will support two RS485 half duplex channels and your tutorial would be very helpful to get me started. My questions are:

  1. Am I limited to UART4 or can I use any of the available UARTs on the Beaglebone Black?

  2. Just to be 100% sure, I can use any of the GPIO pins for controlling DE & /RE pins on the RS485 transceiver (I’m using TI’s ISO15MDW)?

Thank you,

Bolek

Hi,

We are having allot of problems getting RS485 with RTS working on Debian: Linux 4.4
CAn someone help?

There is no problem with the kernel 4.4 and rs485. Just use the omap driver and not the 8250 driver. It works well for me since 4 years.