Update Dec 16 2012 – As pointed out in the comments, the PWM clock is activated by default in the current Angstrom version, Revision A6A. If you are running this image, there is no need to use mmap to activate thte clock.
My earlier articles [1, 2] on Beaglebone coding ignored one of the basics: digital input. The main reason I skipped it is that the I only knew how to handle input by polling, and polling is lame. I decided to wait until I had some Python code to handle input using interrupts, and write about that instead.
Well, here we are, a couple of months later, and … um … it turns out that polling is cool. Interrupts are lame. You know who uses interrupts? Microsoft! Need I say more?
I’ll also cover a relatively new addition to the Beaglebone’s kernel, PWM.
Digital Input
The Beaglebone has a number of pins that default to GPIO mode, and all of them are initially configured for input, not output: the receive feature is enabled, and the GPIO direction flag is set to “in”.
If you take a look at the pin mux settings for these pins, you’ll notice they are similar, but not the same.
For example, here is Port 8 Pin 3:
root:/sys/kernel/debug/omap_mux# cat gpmc_ad6
name: gpmc_ad6.gpio1_6 (0x44e10818/0x818 = 0x0037), b NA, t NA
mode: OMAP_PIN_OUTPUT | OMAP_MUX_MODE7
signals: gpmc_ad6 | mmc1_dat6 | NA | NA | NA | NA | NA | gpio1_6
And here is Port 8 Pin 11:
root:/sys/kernel/debug/omap_mux# cat gpmc_ad13
name: gpmc_ad13.gpio1_13 (0x44e10834/0x834 = 0x0027), b NA, t NA
mode: OMAP_PIN_OUTPUT | OMAP_MUX_MODE7
signals: gpmc_ad13 | lcd_data21 | mmc1_dat5 | mmc2_dat1 |
NA | NA | NA | gpio1_13
Both pins are configured for Mode 7 (GPIO mode), but Pin 3′s mux setting is x37, and Pin 11′s is x27.
From the mux register description in the AM335x Technical Reference, we know that this means both pins are configured for input (Received enabled), but Pin 3 is set to use pullup resistors, and Pin 11 is set to use pulldown resistors.

By default, then, Pin 3 reads HIGH when nothing is connected to it, and Pin 11 reads LOW.
Sure enough, if we export the pin, then look at its value, we see that it is a 1 for Pin 3:
root:/sys/class/gpio# echo 38 > export
root:/sys/class/gpio# cd gpio38/
root:/sys/class/gpio/gpio38# cat value
1
…and a zero for Pin 11:
root:/sys/class/gpio# echo 45 > export
root:/sys/class/gpio# cd gpio45
root:/sys/class/gpio/gpio45# cat value
0
I have no idea why these default settings were chosen: possibly to give creators of capes more plug-and-play flexibility, possibly to give me yet another opportunity to write about mux settings, or maybe they just couldn’t decide. However, when you hook up a circuit you really do have to make a choice.
With Pin 3′s setting, a button (or any other digital input device), needs to connect to Ground when the button is pressed. If you connect it to a voltage pin, nothing good will come of it, but quite possibly a lot of bad.
The GPIO pins on the Beaglebone are quite fragile, compared to the Arduino‘s or Netduino‘s. The Arduino is happy with 5V of input, but can also work with 3.3V. The Netduino prefers 3.3V, but is 5V “tolerant”, meaning you can get away with it. The Beaglebone, on the other hand, is decidedly intolerant of 5V. Hook it up to 5V, even for a split second, and it will die. I wish I could say that I learned this by reading about it, but you can trust me on this one.
The GPIO pins are also more delicate than the Arduino when it comes to current.
According to this post by Beaglebone hardware designer Gerald Coley, the recommended max output current through a pin is 4-6 mA, and the max input current is 8 mA. On the Arduino, it is 40 mA. (Based on my own experience, the Beaglebone seems to be tolerant of higher currents: I’ve measured 60 mA coming out of a GPIO pin. That was a different Beaglebone than the one that died, by the way. What can I say: I’m the Michael Vick of electronics!)
For this reason, I think it’s safest to configure a digital input pin with a pull-up resistor, and connect the button to ground. If you go the other way and use a pull-down resistor, be very certain you don’t accidentally hook it up to the 5V pins, and be sure to use an external resistor too – the internal pull-down resistor won’t knock down the current for you.
The photo below shows 2 pushbuttons connected to 2 GPIO pins: Port 9 Pins 12 (purple wire) and 15 (green wire).

Pin 12 is configured with a pull-up resistor by default. (Note that there is a typo in the System Reference Manual: the pin name is gpmc_ben1, not gpmc_be1n. )
root:/sys/kernel/debug/omap_mux# cat gpmc_ben1
name: gpmc_ben1.gpio1_28 (0x44e10878/0x878 = 0x0037), b NA, t NA
mode: OMAP_PIN_OUTPUT | OMAP_MUX_MODE7
signals: gpmc_ben1 | mii2_col | NA | mmc2_dat3 | NA | NA | mcasp0_aclkr | gpio1_28
So, the circuit for connecting a button is quite simple:
- Pin 12 to Button (purple wire)
- Button to Ground
When the button is pressed, the value will change from 1 to 0, making the button behave like a normally closed button (unless you actually have a normally closed button – hey, so that’s what those crazy NC buttons are for!). Be sure to account for this in your code.
root:/sys/class/gpio# echo 60 > export
root:/sys/class/gpio# cd gpio60
root:/sys/class/gpio/gpio60# cat value
0
Pin 15 is, by default, configured to use pull-down resistors.
root:/sys/kernel/debug/omap_mux# cat gpmc_a0
name: gpmc_a0.gpio1_16 (0x44e10840/0x840 = 0x0027), b NA, t NA
mode: OMAP_PIN_OUTPUT | OMAP_MUX_MODE7
signals: gpmc_a0 | mii2_txen | rgmii2_tctl | rmii2_txen | NA | NA | NA | gpio1_16
You can, of course, change that mux setting if you want to use the same simple button circuit as with Pin 12, but for the sake of variety I’ve hooked it up as-is:
- Pin 15 to button
- Button to 1K resistor
- Resistor to 3.3V
The resistor value is actually quite unimportant, as long as it’s 550R or higher. While the Beaglebone’s GPIO pins don’t like high current, they have no problem with very low current, so 1K, 10K or 100K resistors should all work.
With the button connected to Pin 15 held down, we get a value of 1:
root:/sys/class/gpio# echo 48 > export
root:/sys/class/gpio# cd gpio48
root:/sys/class/gpio/gpio48# cat value
1
As promised, I’ll be showing some code that reads the buttons using some cutting edge polling technology, but first let’s take a look at PWM.
Enabling PWM Support in the Kernel
PWM support was added to version 3.2 of the Angstrom kernel. (I believe it was initially in 3.2.0, but I didn’t start working with it until 3.2.6.) These kernel updates were delivered via opkg updates in February.
Unfortunately, while opkg delivers the new kernels, it doesn’t activate them. That requires some manual intervention. Let me walk you through it…
First, check what kernel version you are currently running
root:~# uname -r
3.2.6+
If you have 3.2.6+ (or later), then great, you’re ready to go. Skip ahead to the Activating the PWM Clock section below.
Otherwise, you’ll need to update the kernel.
[Update Sept 11: I just switched to the latest Angstrom image (stamped 2012.08.14) from the demo files page, and found -- to my shock and awe -- that the process of upgrading the kernel is a lot simpler. Just, update the packages and reboot:
okg update
opkg upgrade
shutdown -r now
This brought me from kernel version 3.2.25 to 3.2.28. Groovy!
This is news to me, so I don't know whether you're likely to have the same experience in other Angstrom images. If you don't get the kernel automagically installed through this method, then read on...]
Check to see what kernels have been installed by opkg:
root:~/tmp# ls -l /boot
total 12180
-rwxr-xr-x 1 root root 33 Feb 14 18:31 uEnv.txt
lrwxrwxrwx 1 root root 13 Mar 7 20:26 uImage -> uImage-3.2.9+
-rw-r--r-- 1 root root 3042328 Jan 26 12:49 uImage-3.1.0+
-rw-r--r-- 1 root root 3135840 Feb 10 03:57 uImage-3.2.0+
-rw-r--r-- 1 root root 3137472 Feb 22 05:37 uImage-3.2.6+
-rw-r--r-- 1 root root 3140088 Mar 6 13:47 uImage-3.2.9+
Right now (mid March), the latest and greatest is 3.2.9+.
If you don’t have the 3.2.x kernels listed in /lib/modules, then be sure to update your packages:
opkg update
opkg upgrade
If the opkg fairy still didn’t leave a new kernel under your pillow, then you might need to upgrade to a new image on the SD card.
Currently, the latest image is the February 14th “2012.02” version, which shipped with Revision 5 of the Beaglebone. You can download it from the Beaglebone Demo page or from CircuitCo . Circuitco’s page has instructions for installing the image to an SD card using Windows. This image comes with the 3.2.5+ kernel, which supports PWM, but after giving it a spin you’ll probably want to go ahead and upgrade to the latest kernel anyway.
When opkg delivers the kernels, it doesn’t install them. To start using a new kernel, you need to manually install it onto the boot partition of the SD card – you can easily do this right from the Beaglebone command prompt.
Begin by mounting the boot partition. You need to use a directory as a mount point: I’m using one called tmp:
root:~# mkdir tmp
root:~# mount /dev/mmcblk0p1 tmp
If you look at the mount point, you should see the following files:
root:~# ls tmp
Docs LICENSE.txt README.htm u-boot.img uImage
Drivers MLO autorun.inf info.txt uEnv.txt
Overwrite the uImage with the latest kernel file from /boot:
root:~# cp /boot/uImage-3.2.9+ tmp/uImage
Unmount to make sure everything is nicely tucked away on the SD card, then reboot:
root:~# umount tmp
root:~# shutdown -r now
After rebooting, your system should report the new kernel:
root:~# uname -r
3.2.9+
Activating the PWM Clock
Update Dec 16 2012 – As pointed out in the comments, the PWM clock is activated by default in the current Angstrom version, Revision A6A. If you are running an up-to-date Angstrom image, you can skip this section.
By default, the 3.2 kernel supports PWM, but doesn’t enable it. If you try to use it through the file system, you’ll get “segmentation errors” and a lot of other moaning and groaning from the kernel.
As explained in this post on the Beagleboard group, the PWM clock needs to be enabled before you start using PWM.
The clock control register is documented in the AM335x Technical Reference Manual as follows:

The clock register isn’t exposed through the file system, so the only way to change this setting is by directly updating the register in memory. Fortunately another post in the Beagleboard group provided the necessary code:
I’ve put a copy of the code here. To run it on the Beaglebone:
root:~# opkg install python-mmap
root:~# wget http://www.gigamegablog.com/docs/setPWMReg.py
root:~# python setPWMReg.py
You should see:
Register CM_PER_EPWMSS1_CLKCTRL was 0x30000
Register CM_PER_EPWMSS1_CLKCTRL changed to 0x2
So, the IDLEST field is initially set to Disable – the code clears that field, and set the MODULEMODE field to ENABLE.
Having got the clock up and running, we’re ready to control the PWM settings through the file system.
Controlling PWM Using the File System
There are 2 pins on Port 9 that, by default, are configured for PWM, Pins 14 and 16. The Beaglebone System Reference manual identifies these as EHRPWM1A and EHRPWM1B; to the file system, they are ehrpwm.1:0 and ehrpwm.1:1, respectively.
The “EHR” part means Enhanced High Resolution. There is also a second type of PWM pin on the Beaglebone, called ECAP, or Enhanced Capture. The 2 types of PWM pins have similar settings exposed through the file system, as explained in the AM335x PWM Driver’s Guide on the TI web site.
To me, the most important difference between the 2 type of PWM is that I can’t get ECAP to work. So, let’s give the EHR PWM a whirl.
A good way to experiment with the PWM settings is to connect the positive pin of an LED to one of these pins, and negative pin of LED to ground. You can safely do so without using a resistor, assuming the LED can be powered by the 3.3V that comes out of these pins.
A garden variety red or white LED should be fine – in the photo below, I have a red LED connected to pin 14.

[Updated Apr 25: Added the mux mode settings]
For starters, set the mux mode settings for the 2 pins to Mode 6 for EHRPWM:
root:~# echo 6 > /sys/kernel/debug/omap_mux/gpmc_a2
root:~# echo 6 > /sys/kernel/debug/omap_mux/gpmc_a3
There are a variety of PWM settings exposed through the file system, as described in the PWM Driver’s Guide, but the two key ones are period_freq, which is the frequency in Hz, and duty_percent, the duty cycle setting.
The following will blink the LED slowly, once per second: [Updated Mar 25: Before changing the period_freq setting, duty_percent should be set to 0. Otherwise, the value of duty_percent might be (silently and mysteriously) reset to another value]
root:~# cd /sys/class/pwm/ehrpwm.1:0
root:/sys/class/pwm/ehrpwm.1:0# echo 0 > duty_percent
root:/sys/class/pwm/ehrpwm.1:0# echo 1 > period_freq
root:/sys/class/pwm/ehrpwm.1:0# echo 50 > duty_percent
root:/sys/class/pwm/ehrpwm.1:0# echo 1 > run
The following settings will cause the LED to glow dimly [Corrected Mar 20]
root:/sys/class/pwm/ehrpwm.1:0# echo 0 > run
root:/sys/class/pwm/ehrpwm.1:0# echo 0 > duty_percent
root:/sys/class/pwm/ehrpwm.1:0# echo 200 > period_freq
root:/sys/class/pwm/ehrpwm.1:0# echo 20 > duty_percent
root:/sys/class/pwm/ehrpwm.1:0# echo 1 > run
To make the LED glow more brightly:
root:/sys/class/pwm/ehrpwm.1:0# echo 80 > duty_percent
It’s safe to change the duty_percent setting on the fly, without changing the other settings first.
The TI guide advises checking the availability of the PWM pin first:
root~:/sys/class/pwm/ehrpwm.1:0# cat request
ehrpwm.1:0 is free
I haven’t seen it return anything except “free” yet, so I’m not sure under which circumstances it returns “busy”. But, feel “free” to check.
With the second PWM port, right next door, I decided to try a high-power LED with this one, the CREE XLAMP. This is actually a good use of PWM, since without it the CREE’s brightness makes it a pain to work with. (I blinded me with science!)
Here, the GPIO pin’s current restriction is a problem: the CREE won’t even flicker with the max recommended output current of 6mA. The 300 mA that flows out of the 3.3V port will do the trick, though.
To control the flow using PWM, you can use a transistor. I used a common NPN “switching” transistor, the 2N2222.
The base of the transistor can be connected to the PWM pin, through a resistor. The resistor keeps the current within the recommended 4-6 mA for a GPIO pin. I used a 1K resistor, but as with the digital input sensors the exact value doesn’t matter as long as you’re above 550R: you don’t need much current to control the transistor base.
- Pin 16 to 1K resistor.
- Resistor to Base
- 3.3V to positive pad of XLAMP
- Negative pad of XLAMP to Collector of 2N2222
- Emitter of 2N2222 to ground

With this circuit, and a duty cycle of just 1%, the XLAMP is no longer blinding (though still surprisingly bright).
A couple of things to note about the frequency setting:
- Corrected Mar 21: As pointed out by muhoo in the Comments section, you can take the PWM frequency well past 250 Hz. The key is to set the duty_cycle to zero before changing the frequency. I’m not sure what the actual maximum frequency is, but the file system allows it to be set to 10 Mhz:
# echo 0 > run
# echo 0 > duty_percent
# echo 10000000 > period_freq
# echo 50 > duty_percent
# echo 1 > run
# cat period_freq
10000000
# cat period_ns
100
The maximum is 250 Hz. I actually couldn’t find this documented anywhere, but currently setting it to anything above that value returns an error message. (There is an alternative setting of period_ns, but the minimum for that is 4 million – same difference.)
root:/sys/class/pwm/ehrpwm.1:0# echo 251 > period_freq sh: echo: write error: Invalid argument
- The frequency setting is shared between ehrpwm.1:0 and ehrpwm.1:1 — if you change it for one, the other will be automatically set to the same frequency. So, unlike the duty_percent, you’ll probably want to set the “run” flag to 0 for both PWM devices before changing it.
Programmer’s Show And Tell
There aren’t many interesting ways to combine digital input and PWM output, and I’ve set out to prove this with some sample Python code I’ve used one of the buttons and the 2 PWM-driver LEDs from earlier in the article. Press the button and the lights come on. Press and hold the button, and light state toggles between on and off. Whee!
You can download the program from my Google Code site.
There are, however, a few things worth pointing out in the code.
Firstly, I’ve (ahem) borrowed the pin mode table from bonescript in order to implement Python versions of pinMode, digitalRead and digitalWrite .
Python’s Dictionary is an easy-going data type: you can store anything in it, including another dictionary. This is similar to node.js, so the syntax of the bone_pins definition is almost identical to its bonescript counterpart:
bone_pins = { "P8_1": { "name": "DGND" },
"P8_2": { "name": "DGND" },
"P8_3": { "name": "GPIO1_6", "gpio": gpio1+6, "mux": "gpmc_ad6", "eeprom": 26 },
"8_4" : . . .
Adding more information to a pin definition is just a matter of adding another entry to the dictionary. So, to extend the table to include PWM pins, I just added a “pwm” key …
"P9_14": { "name": "EHRPWM1A", "gpio": gpio1+18, "mux": "gpmc_a2", "eeprom": 34, "pwm" : "ehrpwm.1:0" },
"P9_16": { "name": "EHRPWM1B", "gpio": gpio1+19, "mux": "gpmc_a3", "eeprom": 35, "pwm" : "ehrpwm.1:1" },
To check if a pin supports pwm:
if not "pwm" in bone_pins[pin]:
print "ERROR: pin %s does not support PWM" % pin
Like node.js, Python provides a command line for experimenting with code without running the full application. So, you can take advantage of these functions by loading the module, then calling the functions manually.
This is somewhat quicker and a lot easier than controlling the settings from the Linux command prompt. For example, to set Port 8 Pin 5 for input, then check the current input value (you’ll need to run python from the directory that contains ButtonsAndLights.py):
root:~# python
>>> import ButtonsAndLights as bb
>>> bb.pinMode("P8_5", "in")
setting /sys/kernel/debug/omap_mux/gpmc_ad2 to 0x37
getting direction /sys/class/gpio/gpio34/direction
exporting GPIO 34
Exported /sys/class/gpio/gpio34/direction is in
>>> bb.digitalRead("P8_5")
/sys/class/gpio/gpio34/value is 1
1
The extra “verbiage” are some print statements in the Python code for debugging purposes – I haven’t fully cleaned up the code yet to make it more usable as a plug-in module. For a more polished and better performing Python implementation of digital I/O functions, take a look at PyBBIO. This code interacts with the GPIO pins using direct register access, rather than the file system, so PyBBIO should prove much faster, perhaps fast enough to handle the microsecond-level timing needed to implement device drivers.
I’ve also implemented pwmMode, pwmStart and pwmStop functions. (This time I didn’t go with the Arduino naming convention – I can’t bring myself to refer to PWM as “analogWrite” like those bohemian Arduinoists.).
def pwmWrite(pin, frequency, duty_cycle, start = True):
""" Changes settings of specified PWM pin (e.g. "P9_14") and optionally enables it.
Note that frequency and duty_cycle can be omitted to leave them unchanged """
def pwmStart(pin):
""" Turn on PWM on the specified pin. PWM settings must previously have been passed to pwmWrite() """
def pwmStop(pin):
""" Turn off PWM on the specified pin """
These, too, can be used from the Python command line. To set Port 9 Pin 14 to run at 200 Hz 80%:
>>> bb.pinMode("P9_14", "pwm")
setting /sys/kernel/debug/omap_mux/gpmc_a2 to 0x6
>>> bb.pwmWrite("P9_14", 200, 80)
>>> bb.pwmStart("P9_14")
Last, and least, there is the polling for digital input:
lastButtonState = digitalRead(BUTTON_NC_PIN)
while 1 == 1:
buttonState = digitalRead(BUTTON_NC_PIN)
# NOTE: will return another value if unable to read
if buttonState == HIGH or buttonState == LOW:
if buttonState != lastButtonState:
# do stuff
time.sleep(BUTTON_POLL_INTERVAL / 1000.0)
While polling is, um, rather quaint, the AM335x is fast enough that it doesn’t significantly slow things down – the polling done in the sample code, once every 250 ms, spends about 99% of its time sleeping.
However, polling becomes somewhat less quaint when you’ve got a lot of digital inputs or sensors to keep track of, so I’m still looking for an interrupt driven solution for GPIO pins. If anyone has that working from Python on a Beaglebone, please let me know.
Wrapping Up
These are still early days for the Beaglebone, and some of the basic building blocks for hobbyists are yet to fall in place. No big surprise, of course: when the Arduino first appeared (back in the day, naught-5 I believe it was) it lacked libraries for things like LCDs and I2C sensors, but over the next few years those were written and became standardized.
But I’ve noticed quite a few interesting projects over the last month pushing out the boundaries of what can be done with userspace applications, like the aforementioned PyBBIO project, and this bonescript project that writes to a Nokia 5110 display.
The kernel continues to leap ahead with new releases every few weeks: kernel maven Koen Kooi recently posted a proposed roadmap for what lies ahead.
The Beaglebone has also popping up on some popular hobbyist sites, like Make Magazine and Hack-A-Day.
It’s quite fun to watch a platform grow from the ground up!