Unable to access PWM from userspace on BBB

Unfortunately they seemed to have changed the PWM driver in the newer linux kernels. I’ve been trying to find some good documentation on it myself, but nothing so far. I was able to play around with it a bit by digging through the current Bonescript source for analogWrite to see what it does and was able to PWM an LED via an NPN transistor.

I also came across this article: http://hipstercircuits.com/enable-pwm-on-beaglebone-with-device-tree-overlays

But it was a little hard to follow for an amateur like me.

I found the same link and I also find it all a bit overwhelming. I've switched to Debian Squeeze with a 3.2 kernel following the instructions here: http://eewiki.net/display/linuxonarm/BeagleBone. So far I see nothing on HDMI and I'm not seeing any serial connection detecting on my host linux system. Does anyone know if these instructions are valid for the BBB? Will a 3.2 kernel work

No, it won't

Unfortunately I’m in the process of replacing my BBB so I don’t have one for probably another week, but I’m very interested in using the PWM as well (disclaimer: I want to try and make a quadcopter out of it). As soon as I get my bone back I’ll be putting a lot of effort into understanding how the device tree works and such. I’d be happy with work with you on putting together a rock solid beginner tutorial on a wiki or block somewhere. I know that doesn’t help you much now, but hang in there :).

I dug around in some of the other posts and it looks like in general, the entire device tree stuff is in a state of flux. Sounds like there either hasn’t been a solid proposal going forward, or at least there hasn’t been enough agreement quite yet. So it might very well be that there’s not a whole lot of concrete docs yet because it hasn’t been finalized. That said, this IS an open source project so we can easily just start dissecting the device drivers and figuring this stuff out ourselves.

I also want to figure out how these cool PRUs are supposed to work. Flying a quadcopter can be dangerous in a non-realtime OS but the Bone has lots of extras that should make it possible. We just have to unlock all their secrets :).

~ Jason

That is a great idea - count me in. I’ve done lots of arduino / AVR stuff, but this is my first linux / ARM system. I would be delighted to help with the tutorials. My interest is in developing laboratory instrumentation with these things - like pH meters, spectroscopes, impedance analyzers, data loggers etc. So would like to help with your tutorials.

I also teach a college-level instrumentation class, so I might be a user for your tutorials as well.

If the goal is a tutorial, the SYSFS interface does provide the simplest way to ease someone into using PWM. I think that being able to simply access it from the command-line does make it very approachable from a beginner point of view. I agree that there is definitely more efficient means for working with the PWM, but realistically if you need that low level of interaction, you’ll likely being using the /dev/mem device to direct access to the registers (or using a polished C library that does it for you).

Also, as I understand it, the SYSFS interface is the only way to mux the pins you’d need from userspace.

I got PWM working on my BBB from the command line the other day. Here’s what I did on Angstrom (4/13 image).

Add the am33xx_pwm module to the bone_capemgr. You’ll have to look at your BBB for the # of the cape manager. Mine is bone_capemgr.8, but since I’ve only tested on a single board, I’m not sure if the numbers are the same across every board.
$ echo am33xx_pwm > /sys/devices/bone_capemgr.#/slots

Add the individual PWM module to the bone_capemgr. For example, EHRPWM2B is pin 13 on the P8 connector. To enable this pin for PWM, use the following command
$ echo bone_pwm_P8_13 > /sys/devices/bone_capemgr.#/slots

This creates a link in /sys/devices/ocp.#/pwm_test_P8_13.#. For my BBB, I have /sys/devices/ocp.2/pwm_test_P8_13.12. The number in the pwm_test has changed for me for a couple times that I’ve used it, so you’ll have to see what number it assigns for you.

All the settings for the PWM configuration are found in that folder similar to the old interface. To generate a 50 Hz signal with 50% duty cycle, (the period and duty times are giving in nanoseconds)
$ echo 20000000 > /sys/devices/ocp.#/pwm_test_P8_13.#/period
$ echo 10000000 > /sys/devices/ocp.#/pwm_test_P8_13.#/duty

I found all this from digging through the BoneScript source code found here https://github.com/jadonk/bonescript. bonescript/node_modules/bonescript/index.js has the core implementation of the module.

Hope this helps.

So, can you expand a little on "only partially" worked, at what point
did the directions fail for you?


The instructions were great in general and was able to get them to work
almost letter for letter. The only hiccup I had was that I had to append
"--no-check-certificate" on all the wget commands, it was complaining about
the certificates being self signed.

Weird, better fire up a new vm and try it without first git cloning
one of the github tree's, as that probably okay'ed the certificate on
my system... Thanks!

The problem I had was just with enabling the PWMs. Following Michael's
instructions I got a "/sys/devices/ocp.2/pwm_test_P8_13.12" folder but there
was were no "duty" or "period" files in the folder. It's possible I made a
typo since I didn't do too much troubleshooting before I rebooted into
Angstrom when I didn't see the links I needed to control the PWM.


Did you ever find a fix to this? It appears that ubuntu also suffers the same problem. (I trying to write a proper c++ library for the servos)

Derek, could you elaborate on what you mean by the Ubuntu image not having EHRPWM_TEST set? I’m experiencing the same problem of the missing duty and period files in the Ubuntu image and am trying to figure out where to make these changes (and then how to recompile and and reinstall the kernel).

I have some detailed notes[1] I’ve made up for my students that might be helpful. I think pwm a moving target at this time.


[1] http://elinux.org/EBC_Exercise_13_Pulse_Width_Modulation

Hi John

Did you figure out how to set the EHRPWM_TEST?


Thanks for sweet tutorial. Only one thing, I get invalid argument after entering : Beagle$ echo 1000000 > period_ns … any ideas?

Try setting the duty cycle to 0 before changing the period.


I’ve succeeded in setting this EHRPWM_TEST flag. Do the following: download demo image for beaglebone black by following instructions from: http://elinux.org/BeagleBoardUbuntu#Demo_Image
After that, run script ./build_kernel.sh. After the building is done, in folder KERNEL, edit the file defconfig - find the flag CONFIG_EHRPWM_TEST, uncomment it and set to:

Now just rebuild the kernel with ./tools/rebuild_kernel.sh.
Finally insert your mmc car with previously installed ubuntu, set mmc variable in file system.sh (uncomment and set for example MMC=/dev/mmcblko) and run the script ./tools/rebuild_kernel.sh. The kernel will be updated and now you can follow instructions from: http://elinux.org/EBC_Exercise_13_Pulse_Width_Modulation or you can write:

echo am33xx_pwm > /sys/devices/bone_capemgr./slots
echo bone_pwm_P8_13 > /sys/devices/bone_capemgr.

echo /sys/device/ocp/pwm_test_P8_13*/period
echo /sys/device/ocp/pwm_test_P8_13*/duty

Just a small correction - to install kernel on mmc card run ./tools/install_kernel.sh and not ./tools/build_kernel.sh.

$ echo bone_pwm_P8_13 > /sys/devices/bone_capemgr.*/slots

$ echo 20000000 > /sys/devices/ocp./pwm_test_P8_13./period
$ echo 10000000 > /sys/devices/ocp./pwm_test_P8_13./duty
Wildcards are the best way to do this.

John, did you ever figure out what Derek was referring to here? If so, could you post more info?


I completely agree with your comments on there needing to be a C/C++ equivalent to the bonescript. With beaglebone 3.8.13, I am able to successfully control a PWM actuator following Mark Yoder’s example: (http://elinux.org/EBC_Exercise_13_Pulse_Width_Modulation), almost exactly the procedure Michael Vernier posted above. However, it will only work after I run a bonescript analogWrite() on the PWM pin. It took some digging to reverse engineer the \bonescript-master\node_modules\bonescript\index.js::analogWrite() to determine what it is doing that afterwards allows me to successfully use the PWM device.

The analogWrite sets the PWM polarity to zero during the configuration of the PWM: “fs.writeFileSync(pwm_test+’/polarity’, 0);”

A similar operation from my C++ side resolved my issue and allowed me to use the PWM device successfully: system(“cd /sys/devices/ocp.2/pwm_test_P9_21.14; echo 0 > polarity”);


Well if you all need / want a C/C++ PWM library. Sounds like you all best get started :slight_smile: