CBB-Serial Cape: Problems with RS-485

Hello,

I have a BeagleBone Black with a “Serial Cape” (http://www.logicsupply.com/eu-en/cbb-serial/). This cape supports RS-485 which i’m interested in. Before i had this cape, i used a RS-485-to-USB-converter.

My problem:
I try to read some data from an external device. It’s very simple: The request is just “/?!\r\n” and then i get the data.

With the RS485-to-USB-Stick i used this serial port configuration (with ser2net):
/dev/ttyUSB0 9600 7DATABITS EVEN 1STOPBIT

With the cape i tried this configuration:
/dev/ttyO4 9600 7DATABITS EVEN 1STOPBIT

Unfortunately this first try didn’t work. I didn’t get any response. I also tried this configuration:
/dev/ttyO4 9600 7DATABITS EVEN 1STOPBIT RTSCTS

I set the jumpers on the cape like this:
J8: RS485
J7: UART4 RTS

The RS485+ wire is connected to the RS485B port, and the RS485- wire is connected to the RS485A port.
(https://docs.google.com/document/d/1sgurQ-7gLyn7g-Kg983NRM0aDkYEqHqy9dmrieX_RUM/edit page7)

To get a better overview i made a photo:

At the bottom of the picture there is the RS485-to-USB converter. It just has two ports which i used to connect the RS485 wires.

I think the board itself should work, because if i execute “cat /sys/devices/bone_capemgr.*/slots” i can see it.

My question:
Do i do something wrong? Maybe someone else has used this cape with RS485? I thought it should be almost as easy as with the USB converter?

Thank you for any help

Best regards
Benj

YOU FORGOT A GROUND WIRE

The BeagleBone’s omap-serial driver doesn’t support RS-485 DE/RE control with the RTS flow control signal. Instead it has an RS-485 mode using a GPIO pin for DE/RE control, and has a modified serial_rs485 struct from the standard serial driver. You have to use ioctl on the corresponding /dev/ttyOx file to put the serial driver in RS-485 mode and tell it which pin to use, and you also have to take care of muxing the pin to GPIO mode.

So with the jumper in the RTS position that would be the GPIO signal that shares the pin with the UART4 RTS signal, so that’s GPIO0_9 on P8.33. Or you can put it to the GPIO1_16 position and use GPIO1_16 instead. (I believe GPIO1_16

There’s a tutorial here: http://inspire.logicsupply.com/2014/09/beaglebone-rs-485-communication.html

Also, I believe RS485B is the inverting output, so you have your +/- swapped.

Thank you very much for the input. Now it works:)

I switched the wires and i played around with the tutorial.

I use now this script:

import serial, fcntl, struct, time

ser = serial.Serial(
port=’/dev/ttyO4’,
baudrate=9600,
timeout=10,
parity=serial.PARITY_EVEN,
stopbits=serial.STOPBITS_ONE,
bytesize=serial.SEVENBITS
)

Standard Linux RS485 ioctl:

TIOCSRS485 = 0x542F

define serial_rs485 struct per Michael Musset’s patch that adds gpio RE/DE

control:

(https://github.com/RobertCNelson/bb-kernel/blob/am33x-v3.8/patches/fixes/0007-omap-RS485-support-by-Michael-Musset.patch#L30)

SER_RS485_ENABLED = (1 << 0)
SER_RS485_RTS_ON_SEND = (1 << 1)
SER_RS485_RTS_AFTER_SEND = (1 << 2)
SER_RS485_RTS_BEFORE_SEND = (1 << 3)
SER_RS485_USE_GPIO = (1 << 5)

Enable RS485 mode using a GPIO pin to control RE/DE:

RS485_FLAGS = SER_RS485_ENABLED | SER_RS485_USE_GPIO

With this configuration the GPIO pin will be high when transmitting and low

when not

If SER_RS485_RTS_ON_SEND and SER_RS485_RTS_AFTER_SEND flags are included the

RE/DE signal will be inverted, i.e. low while transmitting

The GPIO pin to use, using the Kernel numbering:

RS485_RTS_GPIO_PIN = 48 # GPIO1_16 → GPIO(1)_(16) = (1)*32+(16) = 48

Pack the config into 8 consecutive unsigned 32-bit values:

(per struct serial_rs485 in patched serial.h)

serial_rs485 = struct.pack(‘IIIIIIII’,
RS485_FLAGS, # config flags
0, # delay in us before send
0, # delay in us after send
RS485_RTS_GPIO_PIN, # the pin number used for DE/RE
0, 0, 0, 0 # padding - space for more values
)

Apply the ioctl to the open ttyO4 file descriptor:

fd=ser.fileno()
fcntl.ioctl(fd, TIOCSRS485, serial_rs485)

Send some bytes:

GPIO1_16 should be low here

time.sleep(0.2)

GPIO1_16 should be high while this is being transmitted:

ser.write("/?!\r\n");

count=1
while True:
line = ser.readline();
print("Received: " + line)
count = count + 1

for line in ser.readline():

print(str(count) + str(’: ') + chr(line) )

count = count+1

GPIO1_16 should be low again after transmitting

time.sleep(0.2)
ser.close();

Best regards
Benj

Hello:)

I have a new problem. I use now a script to read the data from the external device (see my post before: http://beagleboard.org/Community/Forums?place=msg%2Fbeagleboard%2FpfRLpoOEv9M%2Fj4LJHPGOJgAJ ). This script is just a copy of the script in the linked tutorial. I just changed the baudrate, data bits and the input/output strings.

This script works, but only sometimes. Unfortunately it doesn’t work always. I think it works with a success rate of 20%. In the other 80% there is just no output from the external device, which means it didn’t receive the request string “/?!\r\n”.

Has anyone an idea why? I also did a dirty-patch for ser2net to use this GPIO-thing, but also with ser2net i only have a success rate of +/- 20%.

The externel device works without any problems, because if i use the RS485<->USB-converter every data readout is successful.

Is there another trick with this GPIO-thing? In the tutorial i did not find any other problem sources.

Thank you &
Best regards
Benj