Beaglebone Black with RS232 Cape

I’ve recently bought a Beaglebone Black (BBB) and an RS232 cape (BB-BONE-SERL-03). Mine is revision A1 (important to know which, see later).

At the time of writing this and at the time I bought it, I did not realise that the cape was not yet supported in the Angstrom release. Because of the move to kernel 3.8, the majority of capes available need some software modifications to get them working. A list of compatible capes can be found here.

What follows is a summary of how I got the RS232 cape working, my trial and error can be found, if desired, here.

I started by following the instructions found here with modifications to suit my requirements. We want to create a device tree overlay which will be automatically loaded by the system when it detects the cape is attached.

We need to create a compiled device tree blob object file so first we have to create a device tree source file as follows:

Connect to your bone via ssh (ssh root@ and then create a file called BB-BONE-SERL.dts (I find nano easy to use on the bone).
Put in the following code:

 * Copyright (C) 2012 Texas Instruments Incorporated -
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 as
 * published by the Free Software Foundation.

/ {
    compatible = "ti,beaglebone", "ti,beaglebone-black";

    /* identification */
    part-number = "uart1";

    fragment@0 {
        target = <&am33xx_pinmux>;
        __overlay__ {
            pinctrl_uart1: pinctrl_uart1_pins {
                pinctrl-single,pins = <
	                 0x0180 0x20  /* P9_26 = UART1_RXD, MODE0 */
                         0x0184 0x00  /* P9_24 = UART1_TXD, MODE0 */

        target = <&uart2>; /* note we are really using uart1 but say uart2 here to force creation of /dev/ttyO1 */
        __overlay__ {
        status			= "okay";

    fragment@2 {
        target = <&ocp>;
        __overlay__ {
            test_helper: helper {
                compatible = "bone-pinmux-helper";
                pinctrl-names = "default";
                pinctrl-0 = <&pinctrl_uart1>;
                status = "okay";

Differences between my code here and the original instructions:

  • I am using uart1 instead of uart5 (I got pin conflicts when trying uart5 because I have an LCD3 cape attached)
  • I have therefore changed the addresses of the pins (0x0180 and 0x0184)
  • and changed the MODEs of the pins since accessing uart1 needs MODE0
  • by default, the OS will assign ttyO0 for uart1 but this is already used (not entirely sure why, tty0 is console but what it ttyO0 ?) so in order to force the OS to use ttyO1, I have lied in the fragment above to say we are using uart2

After saving that file, we compile it using the device tree compiler (comes pre-installed in the Angstrom image).
dtc -O dtb -o BB-BONE-SERL-03-00A1.dtbo -b 0 -@ BB-BONE-SERL.dts

Notice the file name of the compiled device tree blob object! – If this is to be automatically loaded by the OS when it detects the cape, the name is very important. It needs to start with BB-BONE-SERL-03 since that is what is in the EEPROM for the RS232 cape and then it also needs to include the version number of the cape (in my case A1) hence -00A1.dtbo (if you have a cape of a different version then change this).

Assuming that compiles ok then you will have a binary file called BB-BONE-SERL-03-00A1.dtbo which need to be copied to the /lib/firmware directory so it can be found on boot.

cp BB-BONE-SERL-03-00A1.dtbo /lib/firmware

Assuming all that has gone ok, reboot

If you then run dmesg and have a look through, you should find something like:

[ 3.310833] bone-capemgr bone_capemgr.9: slot #1: dtbo 'BB-BONE-SERL-03-00A1.dtbo' loaded; converting to live tree
[ 3.311040] bone-capemgr bone_capemgr.9: slot #1: #3 overlays
[ 3.311687] omap_uart 48022000.serial: did not get pins for uart1 error: -19
[ 3.314163] 48022000.serial: ttyO1 at MMIO 0x48022000 (irq = 89) is a OMAP UART1
[ 3.315216] bone-capemgr bone_capemgr.9: slot #1: Applied #3 overlays.
[ 3.315237] bone-capemgr bone_capemgr.9: loader: done slot-1 BB-BONE-SERL-03:00A1 (prio 0)

I have not yet figured out what the error: -19 message is but the subsequent line says that it has assigned ttyO1 to UART1

If you then run:
cat /sys/devices/bone_capemgr.*/slots
you should see that the cape is assigned to a slot (slot1 in my case). I also have an LCD3 cape so I get:

0: 54:P---L BeagleBone LCD3 CAPE,00A2,Beagleboardtoys,BB-BONE-LCD3-01
1: 55:P---L BeagleBone RS232 CAPE,00A1,Beagleboardtoys,BB-BONE-SERL-03
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-L Bone-Black-HDMI,00A0,Texas Instrument,BB-BONELT-HDMI

Notice that the EMMC and HDMI are in slots 4 and 5 – these are virtual capes on the BBB and can be disabled if the pins are required for othhr things.

If you also run:

cat /sys/kernel/debug/pinctrl/44e10800.pinmux/pingroups

you should get:

group: pinctrl_uart1_pins
pin 96 (44e10980)
pin 97 (44e10984)

and if you do:

ls -al /dev/ttyO*

you should get

crw-rw---- 1 root tty 249, 0 Jan 1 00:16 /dev/ttyO0
crw-rw---- 1 root dialout 249, 1 Jan 1 00:17 /dev/ttyO1

You can then try sending characters from the BBB to CuteCom (or another terminal) – by default use 9600 baud, 8 data bits, 1 stop bit and no parity. Remember to move the jumpers on the cape to position uart1 (by default they are uart2).

echo hello > /dev/ttyO1

And you can check that you can receive characters from CuteCom if you simply cat the serial port as follows:

cat /dev/ttyO1

I hope this helps someone else out – I also have an RS485 cape which should work with a few simple modifications to this procedure (see edit below).

EDIT: David Anders kindly pointed out that the two control lines (DriveEnable and ReceiveEnable) that the RS485 cape requires are used by one of the virtual capes (specifically the eMMC virtual cape) so that virtual cape will need to be disabled first – i.e. it will be necessary to boot from an external SD card.

Join the Conversation


  1. Very helpful writeup. However, using the dtc natively on a Beaglebone Black fails to compile the dts file given above. The dtc is unable to parse line 18, i.e. the blank target.

    1. Oops – sorry about that – the text seemed to get modified when posting so that the target was shown as blank. Now corrected so it should work for you. Let me know if you still have trouble 🙂

    1. While I do have an RS485 cape, I have not tried to get it working. It is similar to the RS232 in terms of data but you also have to route the data enable lines too. This can be done via the device tree overlay but IIRC there are only two ports which provide the necessary control lines which can be routed. I notice however on that they say the RS485 cape will need a hardware change before it can work – presumably this is because one or more of the control lines are currently shared with an onboard peripheral such as eMMC or HDMI. If you are happy modifying the cape hardware yourself, it should be possible to get it working 🙂

Leave a comment

Your email address will not be published. Required fields are marked *