Beaglebone Black


This weekend I received my shiny new BeagleBone Black (BBB) which is destined to be installed in my car for data logging and all sorts. We've been using the original model at work for a while now but the £65 price tag always put me off getting one for myself (as I'm fairly sure I'll break it eventually!). The sheer number of IO pins make them ideal for all kinds of projects, of particular interest to me are the UARTs and CANbus interface. Here are my experiences so far...

Initial Impressions...

My experience with the preinstalled Angstrom OS was somewhat hit and miss. I spent hours pulling my hair out over why rfkill was permanently soft blocking my bluetooth dongle. Turns out this is enforced by the connman service, setting Enabled=true in the bluetooth section of /var/lib/connman/settings solved that one.

Next up I attempted to set up a systemd service to tether to my phone on boot (after compiling Bluez myself as the Angstrom package didn't include pand). After trying and failing to get boot time dependencies to work (such that my service started after the bluetooth was active) I gave up with bluetooth for the moment.

Then I stumbled across the wonderful world of the device tree pinmuxing, which has replaced the familiar and convenient /sys/kernel/debug/omap_mux directory in the v3.8 kernel. This got me sufficiently confused that I gave up altogether and decided to install Ubuntu.

Ubuntu Install

Thinking I'd have to do lots of kernel recompiles to get pinmuxing and CANbus working, I followed the excellent instructions here to build everything from scratch. However, I couldn't get the uEnv.txt file given there to work, it seems that a number of the default uboot parameters (such as loaduimage) are incorrect and not overwritten by the file. To solve this I followed the pre-compiled image installation here (I used Method 1 and installed 13.04) and then overwrote the kernel and modules I'd built myself, this worked perfectly.

At present I am running everything from the SD card as this seems to be the default boot device (which is at odds with what the SRM says, but prevents the system booting if you insert a blank card) and I have no idea how to flash the eMMC with a custom image. Eventually I would like to boot from the eMMC and just use the SD card for storage, but I'll tackle that one at a later date.

The Ubuntu image doesn't seem to start the USB networking and as I've no need for that in the long run I just did everything over the serial console. The Sparkfun FTDI breakout fits perfectly on the serial console header (pin 1 is ground, identified by the small white dot on BBB). This has the added advantage that a serial terminal survives reboots (unlike SSH), which came in handy when I started messing around with the device tree (see below...).


Bluetooth PAN

Once up and running I set about getting the bluetooth up and running as I'd done on Angstrom before. I'll be using bluetooth PAN to control the BBB from my phone via a web browser, which has the added benefit of giving the BBB access to the phones internet connection. I prefer to use bluetooth over wifi tethering for as it allows me to have my phone connected to my home wifi and bridge this network to the BBB (saving on mobile data when using apt-get). My bluetooth dongle is nothing special, it identifies itself as


ubuntu@arm:~$ lsusb
Bus 001 Device 002: ID 0a12:0001 Cambridge Silicon Radio, Ltd Bluetooth Dongle (HCI mode)

Connect your BBB to the internet and update apt then install bluez

ubuntu@arm:~$ sudo dhclient eth0
ubuntu@arm:~$ sudo ifconfig eth0
eth0      Link encap:Ethernet  HWaddr c8:a0:30:aa:e4:48
          inet addr:192.168.20.22  Bcast:192.168.20.255  Mask:255.255.255.0
          inet6 addr: fe80::caa0:30ff:feaa:e448/64 Scope:Link
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:1078 errors:0 dropped:0 overruns:0 frame:0
          TX packets:20 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000
          RX bytes:163754 (163.7 KB)  TX bytes:3006 (3.0 KB)
          Interrupt:56

ubuntu@arm:~$ sudo apt-get update && sudo apt-get install bluez-utils bluez-compat

Once apt is finished I pulled the ethernet out of the BBB so I could easily test the PAN connectivity. 

First things first, we need to know the address of the phone. Make sure your phones bluetooth is visible and run

ubuntu@arm:~$ hcitool scan
Scanning ...
        B8:D9:CE:B7:F2:21       GT-I9300

Now we need to create a connection and authenticate it

ubuntu@arm:~$ sudo hcitool cc B8:D9:CE:B7:F2:21
ubuntu@arm:~$ sudo hcitool auth B8:D9:CE:B7:F2:21

Set up the PAN connection and issue a DHCP request

ubuntu@arm:~$ sudo pand -c B8:D9:CE:B7:F2:21 -n
pand[1045]: Bluetooth PAN daemon version 4.101
pand[1045]: Connecting to B8:D9:CE:B7:F2:21
pand[1045]: bnep0 connected
ubuntu@arm:~$ sudo dhclient bnep0
ubuntu@arm:~$ ifconfig bnep0
bnep0     Link encap:Ethernet  HWaddr 00:10:60:d2:a5:0d
          inet addr:192.168.44.177  Bcast:192.168.44.255  Mask:255.255.255.0
          inet6 addr: fe80::210:60ff:fed2:a50d/64 Scope:Link
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:13 errors:0 dropped:0 overruns:0 frame:0
          TX packets:9 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000
          RX bytes:1340 (1.3 KB)  TX bytes:993 (993.0 B)

Verify connectivity with a quick ping

ubuntu@arm:~$ ping -c1 google.com
PING google.com (173.194.34.69) 56(84) bytes of data.
64 bytes from lhr14s19-in-f5.1e100.net (173.194.34.69): icmp_req=1 ttl=43 time=93.1 ms

--- google.com ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms
rtt min/avg/max/mdev = 93.160/93.160/93.160/0.000 ms

The Ubuntu image comes with Apache preinstalled, so navigating my phones browser to the BBB IP gives me the default "It works!" page.

To autostart the PAN network on boot I put the following in to rc.local (which is much easier than the systemd approach in Angstrom!)

ubuntu@arm:~$ cat /etc/rc.local
#!/bin/sh -e

export BT_ADDR=B8:D9:CE:B7:F2:21

pand -c ${BT_ADDR} -n
dhclient bnep0

exit 0

So that was all fairly straightforward, now for the trickier task of enabling the CANbus

CANbus

********************************************
Update 14 Aug 2013: This section is now out of date as I've got device tree overlays working on Ubuntu. I'm also migrating away from this site to my new blog, so details of the "right way" to enable the CANBus can be found here
********************************************

Enabling the CANbus would probably have been fairly simple back in the v3.2 kernel days, but since the device tree has now taken over it is pretty complex and poorly documented process. I don't claim to understand much of what I've done here, but all I can say is that it worked, so here goes...

Enable CANbus device

For the most part I followed the instructions by Nick Garner here for enabling UART2, as the process is the same. Firstly, we need to enable the CANbus device itself so that it shows up in /proc/net/dev. Then we have to sort out the pinmuxing to turn pins 24 and 26 on the P9 header to dcan1 mode. This can all be done by modifying the am335x-boneblack.dtb binary in the dtbs folder of the boot partition. To do so you first need the source files, which you can get from Nick's site

ubuntu@arm:~$ wget http://pignology.net/blackdts.tgz
ubuntu@arm:~$ tar xvzf blackdts.tgz
ubuntu@arm:~$ cd blackdts

The file we're after is am335x-bone-common.dtsi, which contains the device set up code (which I don't even slightly understand). In the file you will find a section labelled "ocp", after which is the code which enables UART1 and UART2. This should look something like
                
                uart1: serial@44e09000 {
                        status = "okay";
                };

                uart2: serial@48022000 {
                        status = "okay";
                };

Since UART2 (/dev/ttyO1) is on the same pins as dcan1 you'll want to disable it. And we need to add some code to enable dcan1, this will be of the same form as that above, to find the register value we can have a look at am33xx.dsti

ubuntu@arm:~/blackdts$ cat am33xx.dtsi | grep dcan1
                dcan1: d_can@481d0000 {
 
So the modified section of am335x-bone-common.dtsi looks like this

                uart1: serial@44e09000 {
                        status = "okay";
                };

                uart2: serial@48022000 {
                        status = "disabled";    //Switch off UART2
                };

                dcan1: d_can@481d0000 {
                        status = "okay";         // Switch on DCAN1
                };

At this point we can compile this (see below) and reboot and we'll see the device showing up in /proc/net/dev

ubuntu@arm:~$ cat /proc/net/dev
Inter-|   Receive                                                |  Transmit
 face |bytes    packets errs drop fifo frame compressed multicast|bytes    packets errs drop fifo colls carrier compressed
 bnep0:    3630      33    0    0    0     0          0         0     2945      38    0    0    0     0       0          0
    lo:     112       1    0    0    0     0          0         0      112       1    0    0    0     0       0          0
  eth0:       0       0    0    0    0     0          0         0        0       0    0    0    0     0       0          0
  can0:       0       0    0    0    0     0          0         0        0       0    0    0    0     0       0          0
But we can't use it until we figure out the pinmuxing, this is also done in am335x-bone-common.dtsi.

Pinmuxing

Note that from now on I do things slightly differently to Nick's guide. I've no real idea what I'm doing so this may be completely wrong, but all I can say is it works for me. Near the top of am335x-bone-common.dtsi is a section detailing the default pinmuxes for LEDs and I2C.

        am33xx_pinmux: pinmux@44e10800 {
                pinctrl-names = "default";
                pinctrl-0 = <&userled_pins>;

                userled_pins: pinmux_userled_pins {
                        pinctrl-single,pins = <
                                0x54 0x7        /* gpmc_a5.gpio1_21, OUTPUT | MODE7 */
                                0x58 0x17       /* gpmc_a6.gpio1_22, OUTPUT_PULLUP | MODE7 */
                                0x5c 0x7        /* gpmc_a7.gpio1_23, OUTPUT | MODE7 */
                                0x60 0x17       /* gpmc_a8.gpio1_24, OUTPUT_PULLUP | MODE7 */
                        >;
                };
                i2c0_pins: pinmux_i2c0_pins {
                        pinctrl-single,pins = <
                                0x188 0x70      /* i2c0_sda, SLEWCTRL_SLOW | INPUT_PULLUP | MODE0 */
                                0x18c 0x70      /* i2c0_scl, SLEWCTRL_SLOW | INPUT_PULLUP | MODE0 */
                        >;
                };
                i2c2_pins: pinmux_i2c2_pins {
                        pinctrl-single,pins = <
                                0x178 0x73      /* uart1_ctsn.i2c2_sda, SLEWCTRL_SLOW | INPUT_PULLUP | MODE3 */
                                0x17c 0x73      /* uart1_rtsn.i2c2_scl, SLEWCTRL_SLOW | INPUT_PULLUP | MODE3 */
                        >;
                };
        };

I added a section to this for the dcan1 pins. The pins happen to be the same as those for UART2 which is convenient because Nick's guide has already identified the correct offsets (0x180 and 0x184) from the TRM. Details on setting the correct mode can be found here, but briefly put we want to set the bits as follows

 Pin Slew Rate  Input  Pull Up  Pull Up   Mode Mode Mode  In Hex 
d_can1_tx (0x180)  0 1 0x12 
d_can1_rx (0x184) 0 1 1 0 0 1 0 0x32 

So the modified pinmux section looks like

am33xx_pinmux: pinmux@44e10800 {
pinctrl-names = "default";
pinctrl-0 = <&userled_pins>;

userled_pins: pinmux_userled_pins {
pinctrl-single,pins = <
0x54 0x7 /* gpmc_a5.gpio1_21, OUTPUT | MODE7 */
0x58 0x17 /* gpmc_a6.gpio1_22, OUTPUT_PULLUP | MODE7 */
0x5c 0x7 /* gpmc_a7.gpio1_23, OUTPUT | MODE7 */
0x60 0x17 /* gpmc_a8.gpio1_24, OUTPUT_PULLUP | MODE7 */
>;
};
i2c0_pins: pinmux_i2c0_pins {
pinctrl-single,pins = <
0x188 0x70 /* i2c0_sda, SLEWCTRL_SLOW | INPUT_PULLUP | MODE0 */
0x18c 0x70 /* i2c0_scl, SLEWCTRL_SLOW | INPUT_PULLUP | MODE0 */
>;
};
i2c2_pins: pinmux_i2c2_pins {
pinctrl-single,pins = <
0x178 0x73 /* uart1_ctsn.i2c2_sda, SLEWCTRL_SLOW | INPUT_PULLUP | MODE3 */
0x17c 0x73 /* uart1_rtsn.i2c2_scl, SLEWCTRL_SLOW | INPUT_PULLUP | MODE3 */
>;
};
dcan1_pins: pinmux_dcan1_pins {
pinctrl-single,pins = <
0x180 0x12 /* uart1_rxd.d_can1_tx, SLEWCTRL_FAST | INPUT_PULLUP | MODE2 */
0x184 0x32  /* uart1_rxd.d_can1_tx, SLEWCTRL_FAST | RECV_ENABLE | INPUT_PULLUP | MODE2 */
>;
};
};

Now unfortunately this did nothing, but I figured out that these muxes weren't actually being executed. To do this we need to go back to the first modification we made and add the following

dcan1: d_can@481d0000 {
status = "okay"; // Switch on DCAN1
pinctrl-names = "default"; // Apply default pinmuxing
pinctrl-0 = <&dcan1_pins>;
};

Compiling device tree binary

So now we have a complete working source (attached at the bottom of this page). To compile this (under Ubuntu, on the BBB) we need the device-tree-compiler

ubuntu@arm:~$ sudo apt-get install device-tree-compiler

Then we run the command

ubuntu@arm:~$ dtc -O dtb -o am335x-boneblack.dtb -b 0 am335x-boneblack.dts

This will create the binary we need which we must replace the default with

sudo mv /boot/uboot/dtbs/am335x-boneblack.dtb /boot/uboot/dtbs/am335x-boneblack.orig.dtb
sudo mv am335x-boneblack.dtb /boot/uboot/dtbs/

After a reboot, we can confirm the pins have been correctly muxed with 

ubuntu@arm:~$ sudo cat /sys/kernel/debug/pinctrl/44e10800.pinmux/pins | egrep "980|984"
pin 96 (44e10980) 00000012 pinctrl-single
pin 97 (44e10984) 00000032 pinctrl-single

Everything is now up and running!

Testing with SocketCAN

Despite the drivers being included in the kernel by default I couldn't find a SocketCAN utilities package for Ubuntu (not that I looked too hard), so I went ahead and compiled from source as follows

ubuntu@arm:~$ svn co svn://svn.berlios.de/socketcan/trunk
ubuntu@arm:~$ cd trunk/can-utils/
ubuntu@arm:~/trunk/can-utils$ make

Now we simply set up the interface and start listening

ubuntu@arm:~/trunk/can-utils$ sudo ip link set can0 up type can bitrate 500000
ubuntu@arm:~/trunk/can-utils$ sudo ifconfig can0 up
ubuntu@arm:~/trunk/can-utils$ ./candump can0

And then there was a CANbus!


This is as far as I've got, next step is to start making sense of the CAN data coming from the car

ċ
am335x-bone-common.dtsi
(10k)
Owen McAree,
May 6, 2013, 6:12 PM
Comments