Thursday, February 16, 2012

BeagleBone GPIO Testing

Being completely new to embedded Linux and having only read how to use GPIO on other platforms I was quite pleased to finally get something working.

The script found here (1) was my starting place. The script seems extremely strait forward however I found myself struggling to figure out which GPIO # corresponded with which pin on the Beaglebone. Looking through the system reference manual for the BeagleBone and comparing it to the TI reference manual ended up confusing the issue. Basically the GPIO # corresponds to (32*First # + Second #) of a pin designation. To make this less confusing lets look at a couple of examples. First what is the pin number of GPIO0_15? Pluggin into the formula we get (32*0+15) therefore the pin number must be 15. How about one that is in the second GPIO bank, say GPIO2_23? Again, using the formula we get (32*2+23) which equals 87.

Another issue was TI reference manual states that the default mux setting for a pin corresponds to the pin name. So then I look at the BeagleBone manual and, for example, it says pin 25 on header J8 is GPIO1_0 you would think, Okay cool! I can export GPIO 32 (using the aforementioned formula) and blink an LED. Now if you try this without doing anything first you will end up with a LED that is dimly lit (at least that is what happened in my case, I am guessing a weak pull-up caused this behavior).

What could be wrong? Well it turns out whoever wrote the BeagleBone SRM (system reference manual)  decided that it would be awesome to rename all of the pins randomly to one of their many muxable outputs. Great.

How do we make it so we can we change these mux settings? First, we must first figure out what the acutal name of the pin is. This can be done by looking at what the primary mode of the pin is. In the case of pin 25 on header J8 we see that MODE0 is gpmc_ad0. Now that we have this information we can properly change the mux mode and other pin setting.

"The /sys/kernel/debug/omap_mux filenames are taken from the Mode 0 
usages of the pins, regardless of which mode the pin mux is currently 
in." - Found here (2)

Ok so if we want pin 25 on header J8 to actually be muxed to GPIO1_0 that means we need to set the mode to 7 (as per the BeagleBone SRM).

This command ought to do nicely:
echo 7 > /sys/kernel/debug/omap_mux/gpmc_ad0
To check an make sure the change was made properly you can run this:
cat /sys/kernel/debug/omap_mux/gpmc_ad0
which, if the pin was set correctly, should have this:
as part of the output.

Sweet, we can now write something to toggle GPIO1_0 on pin 25 of header J8.

To recap here is what needs to be done in shell commands:
#Make sure the pin is in the right mode.
cat /sys/kernel/debug/omap_mux/gpmc_ad0
#If the mode returned by this command is not mux_mode7 set it.
echo 7 > /sys/kernel/debug/omap_mux/gpmc_ad0
#Okay now the pin is ready to be used
#Export the pin
echo 32 > /sys/class/gpio/export
#Turn the pin on
echo "high" > /sys/class/gpio/gpio32/direction
#Turn pin off
echo "low" > /sys/class/gpio/gpio32/direction
#Unexport the pin
echo 32 > /sys/class/gpio/unexport

Finally I want to leave links to the resources I used to figure this out.
For  (4) I used both the Technical Reference Manual and the AM335x ARM Cortex-A8 Microprocessors data sheets.


  1. On my beaglebone, the path is different:

    localhost proc # echo "high" > /sys/class/gpio/gpio32/direction

    1. You may have a newer version of the angstrom build than I did

  2. Great work. Just want to check something though. My understanding is that the direction is either "in" or "out" and that to turn the pin on or off you have to send a 1 or 0 to "value". e.g:

    cd /sys/class/gpio
    echo 32 > export
    cd gpio32
    echo out > direction
    echo 1 > value
    echo 0 > value

    It may be working for you because you are switching the pin between being an input and an output, rather than setting the pin high/low. If you echo a high to direction it will echo as "out" and low to direction will echo as "in".

    1. You may indeed be correct, I got it from the link labeled (1) and it worked so I did not pursue it any further. My intent was to make a kernel module that could do this.

  3. hi,after 3.8 kernel,the debugfs is obsoleted,so we should use Device Tree instead.