Friday, September 23, 2016

BeagleBone to Android via USB Serial

As I mentioned in my last post, BeagleBone uses the Linux g_multi kernel module so that when you plug it into a PC, it appears to be a USB hub with USB-serial, USB-ethernet and USB storage devices attached.

In the other post I talk about how to plug a BeagleBone into an Android phone via USB and communicate between them using Ethernet.  Unfortunately it requires shutting off Wifi and cellular data.

So instead, I investigated communicating via USB serial instead of USB ethernet.  It should work out of the box, but none of the dozens of Android apps I tried could find the USB Serial device the BeagleBone provided.

Thus I used the same trick as before, replacing g_multi with a single-purpose device.  As in the last post, you'll have to comment out a big block of shell script in /opt/scripts/boot/

Then, instead of adding "modprobe g_cdc ${g_network}" and "usb0=enable" to explicitly load the USB Ethernet CDC driver, add:

modprobe g_serial

When you reboot, you won't be able to "ssh" from your PC anymore.  Instead, you'll only get /dev/ttyACM0, and you'll need to login using a terminal emulator like minicom or screen.

(As before, you may want to make these changes while booting from a microSD card so that you can just pop the card out if it doesn't work).

After verifying that I could get in from my workstation, I connected my phone to the BeagleBone with an OTG adapter (careful!  Not all of them work right), then used the "Android USB Serial Monitor Lite" to connect to the BeagleBone.  (Open the "three dots" menu and select "Open Device", then send a newline and you should get a login prompt).

Connecting BeagleBone to newer Android Nexus phones (like Nexus 5X and Nexus 6P) via USB Ethernet

Update: Huh, I just discovered that this exists: Settings > developer options > networking > select USB configuration > RNDIS (USB ethernet).  But it doesn't seem to work.  So I suspect the RNDIS option there doesn't actually do anything.

The BeagleBone comes with a neat feature: when you plug it into your computer's USB port, the BeagleBone pretends it is a USB hub connected to several things: a serial port, USB storage and an ethernet adapter.  Thus you can point your PC's browser to and pull up the BeagleBone's built-in webserver, login via /dev/ttyACM0, or look through the files on its boot partition.

This all happens thanks to the g_multi Linux kernel module, which is one of several modules that allow devices with USB OTG ports to pretend to have things like storage, serial ports, ethernet and even MIDI ports.  g_multi aggregates a bunch of those together and presents them all to the host under a virtual USB hub.

This works great when connecting the BeagleBone to my Linux workstation over USB, and it also partly works when I connect the BeagleBone to my (stock) Nexus 5X: I can attach the BeagleBone to the phone using this VicTsing OTG adapter, and the BeagleBone will power itself from the phone and let me browse its USB storage.

I haven't had any success with the serial port, unfortunately.  I tried a bunch of different Android serial apps, and the phone seems to realize that the BeagleBone is offering a serial port, but I can't get any data between the devices.

Ethernet: if you want to talk from your Android phone to your beaglebone via TCP/IP over the USB cable, the first thing you'll have to do is, sadly, turn on airplane mode so that cellular and wifi data are disabled.  If one of those interfaces is active, pings and HTTP requests no longer make it to the BeagleBone.

Here's the other issue: recent phones like the Nexus 6P have a smaller set of USB Ethernet drivers enabled in the stock distro.  So with the BeagleBone in its default configuration, the Nexus 5X sees the ethernet interface just fine, but the Nexus 6P doesn't.

Fortunately, the g_multi can pretend to be one of two different *types* of USB Ethernet device.  The default is RNDIS, which apparently is a common thing on Windows, and is one of the drivers that got removed on the Nexus 6P.  The other is CDC, which is apparently a cleaner standard that manufacturers of USB Ethernet adapters can follow (so that each manufacturer doesn't have to invent their own driver interface).

Annoyingly, I can't find docs on g_multi's module parameters anywhere.  But I did manage to switch my BeagleBone from RNDIS to CDC ethernet with this change to /opt/scripts/boot/

As you can see, I just commented out the block of code that decides how to load g_multi, and instead I load the standalone g_cdc CDC Ethernet driver.  (This means you'll no longer get the USB storage and serial interfaces):

 # Added these two lines:  
 modprobe g_cdc ${g_network}  
 # And commented out this big block:  
 ##g_multi: Do we have image file?  
 #if [ -f ${usb_image_file} ] ; then  
 #    modprobe g_multi file=${usb_image_file} cdrom=0 ro=0 stall=0 removable=1 nofua=1 ${g_network} || true  
 #    usb0="enable"  
 #    ttyGS0="enable"  
 #    #g_multi: Do we have a non-rootfs "fat" partition?  
 #    unset root_drive  
 #    root_drive="$(cat /proc/cmdline | sed 's/ /\n/g' | grep root=UUID= | awk -F 'root=' '{print $2}' || true)"  
 #    if [ ! "x${root_drive}" = "x" ] ; then  
 #        root_drive="$(/sbin/findfs ${root_drive} || true)"  
 #    else  
 #        root_drive="$(cat /proc/cmdline | sed 's/ /\n/g' | grep root= | awk -F 'root=' '{print $2}' || true)"  
 #    fi  
 #    if [ "x${root_drive}" = "x/dev/mmcblk0p1" ] || [ "x${root_drive}" = "x/dev/mmcblk1p1" ] ; then  
 #        #g_ether: Do we have udhcpd/dnsmasq?  
 #        if [ -f /usr/sbin/udhcpd ] || [ -f /usr/sbin/dnsmasq ] ; then  
 #            modprobe g_ether ${g_network} || true  
 #            usb0="enable"  
 #        else  
 #            #g_serial: As a last resort...  
 #            modprobe g_serial || true  
 #            ttyGS0="enable"  
 #        fi  
 #    else  
 #        boot_drive="${root_drive%?}1"  
 #        modprobe g_multi file=${boot_drive} cdrom=0 ro=0 stall=0 removable=1 nofua=1 ${g_network} || true  
 #        usb0="enable"  
 #        ttyGS0="enable"  
 #    fi  

Be careful not to comment too much: you still want the "if [ "x${usb0}" = "xenable" ] " block below to be active so that the network interface gets set up correctly.

You might want to do all this while booted from a microSD card so that if you screw it up and can't access the BeagleBone over USB anymore, you can just pop out the card and fix from your PC.

Tuesday, July 26, 2016

SeeedStudio Xadow with Ubuntu

Seems like every time I try to use the Xadow board, I have to spend hours getting it to program via the Arduino IDE.  This time, the solution seems to have been putting this in a file called /etc/udev/rules.d/78-xadow.rules and then rebooting:

ATTR{idVendor}=="2886",  ENV{ID_MM_DEVICE_IGNORE}="1"

Thursday, June 09, 2016

Which GPIO pins work with Adafruit_BBIO

Working with the Beaglebone can be really frustrating.  There are a lot of buggy libraries and incomplete docs, and the Sitara chip is really complicated, overloading its pins to do lots of different things.

Today I needed 8 GPIO pins for a test harness.  I looked at the diagrams for the P8 and P9 headers and picked some likely-looking pins.  I used the Adafruit_BBIO python library and set them up as outputs, then toggled them and watched with the meter.  Three of them didn't work.

So I changed my script to try to toggle *all* the pins on P9, even the ground and VCC pins.  Of course this doesn't bother Adafruit_BBIO because it has no error checking (ugh).  Here are the pins that worked as GPIO outputs.

Note that this is from my Beaglebone *Green*.  On the Beaglebone *Black* you'd probably need to disable HDMI for some of these pins to work.

Beware: I repeated this test several times across reboot and power down, and some of the pins worked the second or third time that didn't work the first.  It's possible that's sloppiness on my part, but my intuition says no, and that Adafruit_BBIO isn't initializing the pins correctly, so there's some random chance at play.  The best reference I've found so far in how stuff actually works is "Exploring Beaglebone", which is unfortunately a non-free book, but very well written.



Adafruit_BBIO bugs

First bug was mine.  I was doing "import Adafruit_BBIO as GPIO" instead of "import Adafruit_BBIO.GPIO as GPIO".  That gave this error once I started trying to use it:

$ ./
Traceback (most recent call last):
  File "./", line 5, in <module>
    GPIO.setup("P9_11", GPIO.OUT)
AttributeError: 'module' object has no attribute 'setup'

The other bug was theirs: the code appeared to be working, but the GPIO pins weren't changing state.  Turns out there's no error checking in the library (ugh).  So it wasn't giving any errors when I failed to run the script as root.

Wednesday, February 24, 2016

Beaglebone black PWM minimum frequency

By trial and error, I just figured out that 1 billion is the longest period you can set for (at least this particular) PWM channel.

root@beaglebone:/sys/devices/ocp.3/pwm_test_P9_31.13# echo 1000000000 > period
root@beaglebone:/sys/devices/ocp.3/pwm_test_P9_31.13# echo 1000000001 > period 
bash: echo: write error: Numerical result out of range

The value is in nanoseconds, so that gives a minimum frequency of 1Hz for PWM on beaglebone black.

Also note that it won't let you set the period lower than the duty cycle setting (which we should really call the pulse width instead):

root@beaglebone:/sys/devices/ocp.3/pwm_test_P9_31.13# echo 2000 > duty
root@beaglebone:/sys/devices/ocp.3/pwm_test_P9_31.13# echo 1000 > period 
bash: echo: write error: Invalid argument
root@beaglebone:/sys/devices/ocp.3/pwm_test_P9_31.13# echo 500 > duty
root@beaglebone:/sys/devices/ocp.3/pwm_test_P9_31.13# echo 1000 > period 

Friday, February 19, 2016

Connect beaglebone black to android via USB OTG

With the right USB OTG cables, I was able to connect my Nexus 5X to a beaglebone black and a beaglebone green.  I had to try several cables before the beaglebone would power up; I suspect it's the USB-C adapter that's the most problematic.  This is the USB-C OTG cable that worked.

Once the board booted, I got a notification on my phone about the beaglebone USB storage device becoming available.  But I wanted to send data back and forth between an android app and a beaglebone process, so the network interface was the important thing to me.

When I connect the beaglebone to my PC, it shows up as a USB ethernet adapter, and I can talk to it at  I downloaded an android app called "Terminal Emulator", and when I ran "ifconfig" I could see that I had an eth0 device with IP  But I couldn't connect to it.

But if I turn on airplane mode, oddly, I can connect just fine by putting "" in the address bar of the browser.  I haven't figured out yet whether it's possible to have LTE or Wifi on and still reach the beaglebone; perhaps it's just something to do with the IP addresses used by the Wifi or beaglebone.