Beaglebone Coding 101: Buttons and PWM

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
 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
 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

…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

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
 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

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
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

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

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

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
root:~# python

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
# cat period_ns

  • 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

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

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!

This entry was posted in Electronics, Programming and tagged , , . Bookmark the permalink.

68 Responses to Beaglebone Coding 101: Buttons and PWM

  1. Markus Klink says:

    Thank you very much for your blog series on the beaglebone. I always find it very informative, and hand out the link to anyone asking questions about how do I, where do find?…
    I am currently also writing a small C library for user space access to the pins of the beaglebone. It can be found here: As I also parse the original bone.js file to get my pin descriptions, it would be nice to exchange a bit about a kind of standard, so that we can use common information in various libraries, be it C, python or node.js.

    • dwatts says:


      Yes, I agree — a standard library syntax would be a good idea: method names, parameters, constants, etc. That certainly makes things easier for newcomers.

      I suppose the Arduino names are the “de facto” standard, and the bonescript package intends to implement many of the Arduino libraries and methods. Perhaps the rest of us should do the same?


  2. Huby says:


    I am a newbie on linux. So far I’ve been able to toggle an led and communicate on i2c but I got stuck onPWM.
    As far as I know my angstrom distribution contains the 3.2 kernel and when I tried to use the PWM the I got “segmentation errors and a lot of other moaning and groaning from the kernel” as you described :)
    so I’ve tried to run the python script to setup the PWM register but when I tried to install the python module mmap (root:~# opkg install python-mmap) I got the error:
    Unknown package ‘python-mmap’.
    Collected errors:
    * opkg_install_cmd: Cannot install package python-mmap.
    Any thought on what am I doing wrong?

    • dwatts says:


      That’s odd — python-mmap is the right name, so you entered the right opkg command.

      Are you using one of the Angstrom “demo” images (i.e. the one on the microSD card that came with the Beaglebone, or one downloaded from If you used Narcissus to build a custom image, or got a custom image from another source, then perhaps the package name is a little different? You can look at the list of available packages with ‘opkg list | grep “mmap”‘

      A few things to try:

      1. Run “opkg update”, and check the output to make sure there are no error messages. It is fairly common for opkg update to fail to download the package list from a repository (I have no idea why), and that might cause this problem. If you get an error, just rerun “opkg update” – when it fails the first time, it often succeeds the 2nd or 3rd time.

      2. If that’s not the problem try installing python-modules (i.e. “opkg install python-modules”). This will install all of the most commonly used add-on modules for Python, including mmap. That’s actually how I installed the package.

      3. If neither of these options work, and you are using an Angstrom demo image, then something might be corrupted in your opkg configuration. You are probably best to just download a new image and go from there. Otherwise, if you are using a custom image, you can try downloading the python-mmap .ipk file from the Angstrom web page. (For Beaglebone running Python 2.7 the right package is “python-mmap 2.7.2-r1.8 for armv7a”) Then install it with “opkg install python-mmap_2.7.2-r1.8_armv7a.ipk”



      • Huby says:

        Yeey it works :P
        Thank you for your quick response and thank you from behalf of all the linux embeded newbies :)
        I followd up the “third try”: downloaded the “python-mmap 2.7.2-r1.8 for armv7a” and than installed it manually.
        I think there is something wrong with my ethernet connection so I will try to investigate that now.

        ps there is a typo in the pwm example:
        The following settings will cause the LED to glow dimly.
        root:/sys/class/pwm/ehrpwm.1:0# echo 0 > run
        root:/sys/class/pwm/ehrpwm.1:0# echo 50 > duty_percent
        root:/sys/class/pwm/ehrpwm.1:0# echo 1 > period_freq
        root:/sys/class/pwm/ehrpwm.1:0# echo 1 > run

        I think the period_freq should be set to 100 for the LED to glow dimly.

  3. Al says:

    Thanks for the great series of articles … I’m really enjoying them.

    Last evening I was working through the PWM part of your most recent post. I was running an earlier version of the kernel, so the first I did “opkg update” and “opkg upgrade”. The upgrade may have had its own set of problems (near the end I was seeing a bunch of complaints about not having enough space), but I ended up with the 3.2.9+ version of the kernel in /boot which I copied to the first partition of the SD card, overwriting the uImage file that was there. After rebooting, “uname -r” gave “3.2.9+”.

    Next, I ran the python script to activate the PWM clock. The results were exactly what you showed in your post. This is where things got a bit strange. I did cd /sys/class/pwm/ehrpwm.1:0 and typed “echo 50 > duty_percent”. At this point, I typed “cat duty_percent” and was surprised to see that duty_percent = 7. I set period_freq and run to 1, and these read back OK. I did some testing with various duty_percent values. For input values from 0 -> 42 “cat duty_percent” returns the expected value. For 44% I read 0 back. Higher input values cause the value I read back to increase up to 43 until for 86 in I get 0 out again. This behavior repeats for inputs up to 99.

    I should also point out that I didn’t see any output on pin 14 of my beaglebone.

    So, any ideas about this? This may be one that I have to submit to the beagleboard forum.


    • dwatts says:


      I didn’t run into that problem when I was playing around with PWM, so I can only offer semi-educated guesses.

      First off, the problem you had when upgrading might have left something in a funny state. If you have a spare microSD card, I’d recommend downloading the 02.14.12 demo image from CircuitCo ( or the Beaglebone demo image page and trying it. I received an A5 revision Beaglebone the other day and tried PWM with that image (it has a 3.2.5+ kernel) to see if it worked, and it did. I’m currently running the 3.2.9+ kernel, so that should work too when you upgrade that demo image.

      Otherwise, a few things that you’ve probably already tried….

      If you have a cape plugged into Beaglebone, then try it without the cape.

      You should check your dmesg output to see if there are any errors logged when you set the duty cycle above 44.

      Did you set the PWM clock register by running the Python script or some other means? If you didn’t I would expect a bunch of kernel errors to be sent to the console, though.

      You should check your mux settings for that pin, though the default should be fine. On my ‘bone, it’s:

      # cat /sys/kernel/debug/omap_mux/gpmc_a2

      name: gpmc_a2.ehrpwm1A (0x44e10848/0×848 = 0×0006), b NA, t NA
      signals: gpmc_a2 | mii2_txd3 | rgmii2_td3 | mmc2_dat1 | NA | NA | ehrpwm1A | gpio1_18

      If none of that sheds any light on the problem, then you’re right, you should post this to the Beagleboard Google Group. There are plenty of people there who (unlike me) actually understand how TI’s PWM implementation works and will hopefully recognize this type of behaviour in the duty_percent setting.


  4. muhoo says:

    You CAN set the period_freq to greater than 250! You just have to first echo 0 > run to turn off the thing and echo 0 > duty_percent. Then it’ll let you change the freq to higher than you had it. Once it’s set, then echo 1> run to turn it back on.

    The reason is probably that it is a 16-bit counter, and it has to switch to a different divider to change freqs beyond certain ranges. But once you do that, you can set the clock quite high. I set mine to 10khz successfully.

    • dwatts says:

      Yes, you’re right! Thanks for pointing this out. I thought that 250 Hz was a suspiciously low limit.

      It seems that you can set the frequency as high as 10Mhz (100 ns) through the file system without any errors. I’ll have to check with an oscilloscope when I get home to see if that setting actually works.


  5. i have a problem with some of my pins, their mode 7 is not GPIO !!
    although according to the BeagleBone manual they should be GPIO on mode 7 but i get NA instead
    for example, i’ll use the same pin that you used
    cat gpmc_ad13
    name: gpmc_ad13.(null) (0x44e10834/0×834 = 0×0027), b NA, t NA
    signals: gpmc_ad13 | lcd_data21 | mmc1_dat5 | mmc2_dat1 | NA | NA | NA | NA

    what could be the problem?
    i have the same issue with old angstrom versions and new versions as well :(

    • dwatts says:


      The “NA” part is misleading – that pin really is in mode 7, and mode 7 really is for GPIO.

      The important part of the output is “OMAP_MUX_MODE7″. If you see that, you can be sure the pin is in Mode 7. The last digit of “= 0×0027″ is also an accurate indicator.

      I’m not sure where the “signals” line gets its data from, but it often incorrectly displays “NA” instead of the correct mux usage. This happens on both my Beaglebones too. The mux modes listed in the System Reference Manual in Tables 9, 10, 12, and 13 are accurate for all Beaglebones.


      • i expected that, so i manually checked each of the supposedly 66 pins that can operate as GPIO pins, only 16 of them could actually output a high or low current through the pins :(

        so i tried,
        root@mybeaglebone:/sys/kernel/debug# cat gpio
        the useful part of the output was
        GPIOs 64-95, gpio:
        gpio-89 (sysfs ) out hi

        this changes successfully according to my settings whether out or in, hi or lo

        but the pin actually always driving high output !!

        the same happens with all of the other GPIO pins that don’t give correct output, after inspecting, some of them had the “NA” problem, and some of them i couldn’t find the files where i should decide which mux mode this pin should use

        so now i ended up with only 16 pins working

        • dwatts says:


          Is Port 8 Pin 11 one of the pins that doesn’t work for you?

          The default settings for that pin don’t show any voltage or current. Like most of the GPIO pins, it starts off in input mode:

          root@betabone:/sys/class/gpio# cat /sys/kernel/debug/omap_mux/gpmc_ad13
          name: gpmc_ad13.gpio1_13 (0x44e10834/0×834 = 0×0027), 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
          root@betabone:/sys/class/gpio# cd /sys/class/gpio/
          root@betabone:/sys/class/gpio# cd gpio45
          root@betabone:/sys/class/gpio/gpio45# cat direction

          But the following sets the voltage to 3.3V:

          root@betabone:/sys/class/gpio/gpio45# echo out > direction
          root@betabone:/sys/class/gpio/gpio45# echo 1 > value

          Here’s what /sys/kernel/debug/gpio shows at this point. The entry for gpio45 didn’t show up until I exported that pin. I actually have never checked the value of /sys/kernel/debug/gpio before (my knowledge of embedded Linux is limited), so I don’t know if this is the expected result.

          root@betabone:/sys/class/gpio/gpio45# cat /sys/kernel/debug/gpio
          GPIOs 0-31, gpio:
          gpio-6 (mmc_cd ) in lo

          GPIOs 32-63, gpio:
          gpio-35 (w1 ) in hi
          gpio-45 (sysfs ) out hi
          gpio-53 (beaglebone::usr0 ) out lo
          gpio-54 (beaglebone::usr1 ) out lo
          gpio-55 (beaglebone::usr2 ) out lo
          gpio-56 (beaglebone::usr3 ) out lo

          GPIOs 64-95, gpio:

          GPIOs 96-127, gpio:

          This is with the latest Anstrom kernel, 3.2.11+, and running off a 5V AC adapter. If you are running off USB or a battery, perhaps that is affecting the behaviour of your Beaglebone?

          If you suspect your Beaglebone has a hardware problem, I’d suggest you post on the Beagleboard Google Group — that’s where the hardware guys hang out, and they can suggest a better way of testing for hardware problems.


          • i think i will try google groups, looks like a hardware problem that is gonna be costy to fix since i don’t live in the USA so shipping costs much, i’ll try to extend the 16 pins i have using decoders or may be a microcontroller

            and yes i am using the 5 V DC supply not the USB

  6. Pingback: » Cracking PDF-file passwords using a BeagleBone board Wunderkammer

  7. Bryan says:

    Hi! Thanks for all of the great articles. You mentioned looking for an interrupt solution for GPIO pins. Have you found any way of doing this, or any guidance on the subject? I need an interrupt to be thrown whenever a gpio pin changes status (edge or level triggered) without blocking while waiting for the pin to change.

    • dwatts says:


      No, I haven’t found a solution for Python yet. For C code, the approach described here should work on the Beaglebone:


      • Bryan says:


        Thanks for the timely response. I have taken a look at those sites, but it seems like they all use polling to wait until the pin changes. “Your process will block (i.e. let other processes run) while poll() waits for an interupt to occur.” What I am looking for is something which allows my code to continue running, and then calls an interrupt function when the pin changes. I have done a lot of reading about signals and interrupts in the linux kernel, but I am new to linux and haven’t been able to figure out if this is approach will work on the BeagleBone (it doesn’t help that I can’t seem to find the header file required to implement these functions).

      • Craig says:

        Hi, I got a python poll example working on my beaglebone. I kept is as simple as possible, so it only works for pin 11 (gpio47).

        It is pasted at:


        • dwatts says:

          Ah, great, you got that to work! I wasn’t able to get that approach working when I tried it.

          Now that I know how it works, I’ll try using it in my Python code.



  8. Jeshwanth Kumar N K says:

    Nice Article :) thank you .. And one suggestion if I am right, can you please move the section “polling for digital input” from “pwm section” to “digital input” section in the above… Because when we reading the pwm we may ignore polling for digital input.

  9. Willem Buitendyk says:

    Thanks so much. Very helpful and very much appreciated.

  10. Amir says:

    Thank you for the great articles.

    When connect to my beagleboard (Angstrom Kernel 3.2.14), using ssh from my Ubuntu laptop.

    when I run:
    /sys/class/pwm/ehrpwm.1:0# echo 0 > run

    it immediatly disconnects me from the terminal!!
    Connection to closed.

    Also I can run this:

    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

    and as soon as execute the last line I get disconnected.

    Any idea what is going on?

    I tried not connecting anything to PIN14 while running th command and it didnt make any difference.

    • Amir says:

      ops! I did not run the python code to activate PWM.

      After running the code, I dont get disconnected from ssh session anymore.

      But changing the values of duty_percent,… do not make any difference. I am not getting any thing out of P8 pin14 and pin16.

      Also, my /sys/class/pwm/ehrpwm.1:0 is linked to /sys/devices/platform/ehrpwm.1/pwm/ehrpwm.1:0

      Could it be that I am using USB power not an adaptor? dont have one to test it.

      • Amir says:

        I got it !

        My bone (A3) with the latest image ( Linux beaglebone 3.2.14 #1 Mon Apr 9 12:21:19 CEST 2012 armv7l GNU/Linux), aperantly did not have “gpmc_a2” set to MODE6. It was set to MODE7 by default.

        So I had to do this to get the pwm to work:
        echo 6 > /sys/kernel/debug/omap_mux/gpmc_a2

        • dwatts says:


          Oops – the mux mode setting is an important step that I should have mentioned in the article. I’ll update the article to include it.

          Thanks for pointing it out.


  11. Lachlan Fletcher says:

    Hi There,

    Thank you so much for your wonderful article. I have struggled to get started with GPIO on OMAP systems for a long time, and your article finally got me started.

    I have been applying your instructions to BeagleBoard and PandaBoard systems, and after struggling for several days it seems that although for the most part things are the same, part of your information does not work correctly on these systems.

    In case others have the same systems:

    On OMAP3 and OMAP4 processors, if a pin is set to “OMAP_PIN_OUTPUT” it means that the “Input Enable” bit is off, and the pin cannot be used as in INPUT. You can set the “direction” to “in”, and it will accept and reflect this, but the pin will always be low, no matter what you do.

    If you set the pin to “OMAP_PIN_INPUT”, then it actually becomes bidirectional, meaning you can use it as an input or output port, just by setting the “direction” file to “in” or “out”. There is a reference table describing which bits to set for which options, including enabling input and enabling pullups or pulldowns. For those who don’t understand this, here is a cheat sheet. The options are in hex format, so you need to echo those values to the file for the pin you want to setup.

    The last digit below is always 3, because on OMAP4 (PandaBoard) the Mux Mode for GPIO is 3. You can change this to 4 for OMAP3 (BeagleBoard). The first digits are the same for both boards.

    0×003 – This will set a pin as OUTPUT.
    0×103 – This will set a pin as INPUT, with no pullups/pulldowns.
    0x11b – This will set a pin as INPUT with Pullups enabled.
    0x10b – This will set a pin as INPUT with Pulldowns enabled.

    For example, on a PandaBoard, to set Pin 4 on Expansion Connector A (mcspi1_cs3) to INPUT with Pullups enabled you would do:

    “echo 0x11b > /sys/kernel/debug/omap_mux/mcspi_cs3″

    Finally, but importantly, the “/sys/kernel/debug/omap_mux” location is not automatically available on ubuntu or debian, and must be mounted before it can be used. Use the command:

    “mount -t debugfs none /sys/kernel/debug”

    Thanks again for your great article, and I hope my comments help some other users.

  12. Lachlan Fletcher says:

    Sorry, correction,

    For BeagleBoard which is Mux Mode 4 for GPIO, the last two examples for inputs pullup and pulldown are:

    0x11c – This will set a pin as INPUT with Pullups enabled (Mux Mode 4)
    0x10c – This will set a pin as INPUT with Pulldowns enabled (Mux Mode 4)

    • dwatts says:


      Thanks, that’s very helpful. I haven’t played around with GPIO on the Beagleboard yet, partly because I couldn’t find an explanation of how to set mux modes through the file system. Your explanation fills in the missing pieces.


  13. Zoltan says:

    hey Dan,

    I’m trying to get some PWM output from the beaglebone, but no luck whatsoever.

    root@beaglebone:~# python
    Register CM_PER_EPWMSS1_CLKCTRL was 0×2
    Register CM_PER_EPWMSS1_CLKCTRL changed to 0×2

    (I’ve run it before, that why it was in 0×2 initially).


    root@beaglebone:~# ls -las /sys/class/pwm/
    0 drwxr-xr-x 2 root root 0 Jan 1 00:00 .
    0 drwxr-xr-x 42 root root 0 Jan 1 00:00 ..
    but I’m on the right kernel:

    root@beaglebone:~# uname -a
    Linux beaglebone 3.2.14 #1 Thu Apr 19 12:35:12 CEST 2012 armv7l GNU/Linux

    any ideas what I could do?


  14. Zoltan says:


    I’m trying to get pwm to work, but the pwm directory is empty for me :(
    I’ve run your python script before, and I’m using a more recent kernel (.14 IIRC)

    Any ideas?


    • dwatts says:


      You’re right!

      I just upgraded to 3.2.14 to see if something changed, and the whole PWM file system has disappeared.

      Sorry, I don’t know what’s happened. I see one other person has asked about it on Google Groups, but no reply to his question.

      I restored the 3.2.13 uImage file, and /sys/class/pwm is back to normal there. Apparently something changed in the latest kernel.


      • Zoltan says:

        Hey Dan,

        Ok, then it’s a screwup with the kernel. I should have tried an older version before asking :-)

        Thanks for checking it out!

      • dg says:

        And PWM is still missing in 3.2.16
        The kernel seems in much flux the last several releases

  15. jezra says:

    First, I would like you thank you for such an excellent resource. Second, I have a question. Would it be possible to go into a bit more detail regarding pin selection for user input?

    In the article, you use pins 9-12 and 9-15 as input examples, *how* did you decide to use pins 9-12 and 9-15? Was it simply a matter of looking for specific text in a file? If so what was the process?

    • dwatts says:


      For GPIO input pins, you can pick almost any pin at random. Most of them will work as GPIO pins with the correct pin mux settings (i.e. mode 7).

      In general, when selecting pins, I go by the Beaglebone System Reference Manual: Tables 8 and 11 give the “common” usage of each pin. (Actually, the hardware designers have never explained why they chose those labels for each pin in those 2 tables, but I’m guessing they chose the feature they expected to be used most commonly). Any pin listed as GPIO in those tables is a safe choice as a GPIO input pin. On Port 9, 12 and 15 are the first 2 pins listed as GPIO pins.

      Note that the “common” usage isn’t necessarily the default pin mux setting. Not all of the GPIO pins are in GPIO mode (mode 7) by default, and not all of the GPIO pins are in input mode by default. So, setting the mux mode is still necessary.


      • jezra says:

        Thanks for the info Dan. Since I had such a difficult time trying to find an input pin with pullup resistor, either my board is having issues (it’s a Rev 3) or my muxing of my pins was wrong.

  16. Bart Libert says:

    Dear sir,

    Thank you for your very informing articles.

    While looking to enable at least 1 pwm output on my beaglebone, I found your very nice article which shows how to do it.

    The access through the filesystem is easy to port to other languages (I don’t use python but c)

    But…. the initialisation you made at is pure python.

    Of course I could run this code before running my program and the pwm would be inited, but is it maybe possible to say how to do this initting in C itself?

    Kind regards,
    Bart Libert

  17. Steve says:

    I’m in school and kind of new to Linux embedded development…
    What would the method be for changing the PWM parameters in code be?
    Is it custom to just
    open(“/sys/class/pwm/ehrpwm.2:0/request”, O_RDWR);
    then mmap it?

  18. Matt says:

    Great Article! I do have a question though. 0-100% doesn’t seem like very much resolution for the PWM. Are fractional values allowed? For example 85.3%?



  19. Emmanuel POULY says:


    Thanks a lot for your website, it helped me a lot at the beginning !!!

    About my own PWM experience on the beaglebone (Rev A3) bought one week ago:
    It was shipped with the v2011.11-core (Kernel 3.1.0+)
    I now run the v2012.04-core release (Kernel 3.2.14). I created a new SD card with Win32 Disk Imager using an image from the Angstrom Beaglebone Archive on the web.

    Everything work fine on the Port 9 with Pins P9.14 and P9.16
    I used your tutorial to update Python and then to enable the PWM on the beaglebone using

    Then I’m now able to use PWM. First I change mux_mode to mode 6 using this shell command for Pin P9.14

    echo 6 > /sys/kernel/debug/omap_mux/gpmc_a2

    and this one for Pin P9.16

    echo 6 > /sys/kernel/debug/omap_mux/gpmc_a3

    Here a simple script that works well with a Led (Positive Led Pin to P9.14 and Negative Led Pin to GND). Change ehrpwm.1:0 to ehrpwm.1:1 if you use Pin P9.16.


    cd /sys/class/pwm/ehrpwm.1:0

    # Request and Acquire the device
    echo 1 > request

    # Start the PWM Module
    echo 1 > run

    # Attributes that set Period then Duty Cycle
    echo 0 > duty_percent
    echo $1 > period_freq
    echo $2 > duty_percent

    # Wait a few seconds to see what happening with the Led :)
    sleep 10

    # Stop the PWM Module
    echo 0 > run

    # Free the device
    echo 0 > request

    # Print that the device is free ;)
    cat request

    If anyone request some help, feel free to ask ;)

  20. GP says:


    Cool article. I am going to order a BeagleBone for experimentation as soon as they are back in stock.

    Any idea of these PWM issues have been resolved in the A5 hardware and bundled Linux OS, does it now include the PWM filesystem again?

    And, have you figured out a way of using polling with Python for this method of controlling PWM via GPIO?

    Thanks in advance, and once again great article!

    • dwatts says:



      I have to admit that I’ve been neglecting the Beaglebone side of things for the last few months, but yes, PWM is working again in the 3.2.18 kernel. I’ve updated the article with that info – thanks for reminding me.

      I haven’t tried doing anything serious with PWM through GPIO pins (just blinky lights) but if I did I’d try using the PyBBIO library (, which can toggle the GPIOs as quickly as possible with Python.


  21. GP says:

    How did you get a 3.2.18 kernel? Using a brand new A5, I did an opkg update && opkg upgrade yet the kernel is only 3.2.14. And, there is nothing populated in /sys/class/pwm

    Any ideas?


  22. GP says:

    Any idea how many total hardware PWM outputs there on the BeagleBone? My initial research yielded only two, but after reading through the docs it looks like there are six independent hardware PWMs? Are they using some type of muxing setup to get to that hardware, for example if I were to wire six separate LEDs for hardware PWM what pins could be used for that purpose?

  23. GP says:


    “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.”

    With this statement, it would appear that 1:0 and 1:1 cannot be independently controlled for PWM? Is there a way of having separate frequency settings for all nine of the PWM outputs?

    • dwatts says:

      Well, that was a guess on my part based on trial and error, and I still haven’t seen any documentation that confirms it.

      My understanding is that the 2 PWM pins on each of the 3 EHRPWM “instances” must run at the same frequency. There are 3 instances (EHRPWM0 to EHRPWM2) that are definitely usable on the Beaglebone, so you can run PWM pins at up to 3 different frequencies.

      eCap is a different story – I would assume its frequency is independent of the EHRPWM pins, but I haven’t used eCap myself yet.


  24. Paul says:

    I was trying to do use PWM in Python the same way you showed in the shell.
    Something like this >


    print('echo 1 > /sys/class/pwm/ehrpwm.1:0/run

    it prints the output but doesnt seem to actually run the line. Is something more needed to simply print a command to the shell?

    thanks, and great series!

    • Paul says:

      I guess I cant edit my original post but I realize I left off the closing on that print statement above. in the code its right.

    • dwatts says:


      Sorry for the late response – I’ve been off the Net all week.

      It’s funny, but I thought of writing Python code that uses shell commands to update the file system — I’ve always used Python file I/O commands. However, the following seems to work:

      >>> import os
      >>> os.system(“echo 1 > /sys/class/pwm/ehrpwm.1:0/run”)

      I wouldn’t recommend taking this approach, since all of the other Python code I’ve seen uses file I/O. The file I/O equivalent can be found in the file that is referenced by the blog post:

      >>> open(“/sys/class/pwm/ehrpwm.1:0/run”, ‘w’).write(“1″)


  25. Peter W Fraser says:

    Thanks for a great series of articles. I’m new to the BeagleBone, and new to Linux, and have found your articles very helpful. I intend to use the BeagleBone with an interface cape to allow interaction with an FPGA. The FPGA would do video processing, with the BeagleBone doing some configuration, control, and analysis. I assume the interface should use the GPMC, and run the I/O in mux mode 0. I haven’t found much material on memory mapped I/O with the BeagleBone. Any pointers?



  26. madara_x64 says:

    Very nice set of articles! With the absolute latest release (the image shipped with the Bone Rev A6a), does one still have to enable the PWM clocks? The AM335x PWM Driver’s guide don’t seem to mention anything regarding enabling a clock..almost as though the clocks are already enabled and are ready to be used…so do we still have to use the python-mmap thingy and related?

    • dwatts says:


      I hadn’t run Angstrom for awhile, but I just gave the A6a image a spin and… you’re right! PWM now works without any the need for any python-mmap thingy.

      Thanks for pointing this out — I’ll update the article.


  27. Pingback: Beaglebone Coding 101: I2C | GigaMegaBlog

  28. Pingback: Switching it up – using a comparator as a level shifter | Hipstercircuits

Leave a Reply

Your email address will not be published.

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>