Working with PWM on a BeagleBone Black

I recently figured out how to enable and set PWM pins on a BlackBone Black rev. C running debian with a test image dated 2014/12/19. I got the image from here. The debain version is 3.8.13-bone68. All instruction are from the command line of a ssh session. I work on a MacBook Pro, so beaglebone.local works with Bonjour, so I don’t need to know the IP address for the board.

I started by updating and installing the universal io device tree overlays, whose source is in the folder /opt/source/beaglebone-universal-io. This folder contains the github source, so I made sure it was up to date by typing,

git pull origin master

, then to install I typed

make install

In my detective work on this subject, there a two parts to setting up a pin,

  1. Set the pin multiplexing for the mode/function (gpio, pwm, I2C …), which the universal IO device tree overlays allow you to do.
  2. Setup the peripheral for the pin function.

To start, I needed to load the universal IO device tree overlay with following command,

root@beaglebone:~# echo cape-universaln > /sys/devices/bone_capemgr.*/slots

This created files in the /sys/devices/ocp.* folder for the expansion header pins (the files have a “pinmux” extension), which can be used to for pin multiplexing. I have four motors that I control with motor drivers, which I have PWM outputs connected to P9.14, P9.16, P9.21, and P9.22. So, I can look at the multiplexing modes for each pin like this,

root@beaglebone:~# config-pin -l P9.14
default gpio gpio_pu gpio_pd pwm

“pwm” is what I want, so I multiplex the pin by typing

root@beaglebone:~# config-pin P9.14 pwm

I can check pinmux state using the pinmux file in the ocp folder like this,

root@beaglebone:~# cat /sys/devices/ocp.*/P9_14_pinmux.*/state

Note that the state can be set like this,

root@beaglebone:~# echo pwm > /sys/devices/ocp.*/P9_14_pinmux.*/state

This is useful to know when coding in C/C++.

Now, I’m ready to enable and setup the PWM peripherals. With some detective work by searching, reading blogs, and going through some forum discussions, I pieced together the following. So, the pwm system files are in the folder /sys/class/pwm. This is the listing I got.

root@beaglebone:~# ls -l /sys/class/pwm/
total 0
--w------- 1 root root 4096 Dec 31 1999 export
lrwxrwxrwx 1 root root 0 Jan 6 17:56 pwmchip0 -> ../../devices/ocp.3/48300000.epwmss/48300200.ehrpwm/pwm/pwmchip0
lrwxrwxrwx 1 root root 0 Jan 6 17:56 pwmchip2 -> ../../devices/ocp.3/48300000.epwmss/48300100.ecap/pwm/pwmchip2
lrwxrwxrwx 1 root root 0 Jan 6 17:56 pwmchip3 -> ../../devices/ocp.3/48302000.epwmss/48302200.ehrpwm/pwm/pwmchip3
lrwxrwxrwx 1 root root 0 Jan 6 17:56 pwmchip5 -> ../../devices/ocp.3/48304000.epwmss/48304200.ehrpwm/pwm/pwmchip5
lrwxrwxrwx 1 root root 0 Jan 6 17:56 pwmchip7 -> ../../devices/ocp.3/48304000.epwmss/48304100.ecap/pwm/pwmchip7
--w------- 1 root root 4096 Dec 31 1999 unexport

So, there is a lot to be learned from this listing. I read in a forum post that you export 0 thru 7 to enable the 8 available PWM channels, but that didn’t tell me which pin they corresponded to. So, I noticed that the files “pwmchip#” are links to another folder, and they range from 0 to 7. Looking at the paths there are two numbers that look like memory addresses. So, the next clues can be found in the “AM335x Sitara Processors, Technical Reference Manual” which can be found here.
Looking for address 48300000 in the memory map, I found this was in the L4_PER block, and this was listed as the “PWM subsystem 0”, and 48300200 was the EHR0 PWM channel and 48300100 the eCAP0 PWM. Also, address 4830200 is the “PWM subsystem 1”, and address 4830400 is the “PWM subsystem 2”.  Awesome, I’m on the right track to figuring this out. Now, using the pin names found from the “BeagleBoard.org – bone101” page served from the board, and deductive reasoning. I came up with the following maping of pin to export number.

export number pin name pins
0 EHRPWM0A P9.22,P9.31
1 EHRPWM0B P9.21,P9.29
2 ECAPPWM0 P9.42
3 EHRPWM1A P9.14,P8.36
4 EHRPWM1B P9.16,P8.34
5 EHRPWM2A P8.19,P8.45
6 EHRPWM2B P8.13,P8.46
7 ECAPPWM2 P9.28

Awesome!! So, I’m now ready to setup the PWM to control the speed of my motors. P9.14 was one of the PWM pins I connected, so it is EHRPWM1A with export number 3. So, to enable the peripheral I can type the following,

root@beaglebone:~# echo 3 > /sys/class/pwm/export

Listing the contents of the pwm folder I see this,

root@beaglebone:~# ls /sys/class/pwm/
export pwm3 pwmchip0 pwmchip2 pwmchip3 pwmchip5 pwmchip7 unexport

So, a folder named “pwm3” showed which means that the export worked. Next, I want to look inside this folder,

root@beaglebone:~# ls /sys/class/pwm/pwm3/
device duty_ns period_ns polarity power run subsystem uevent

Perfect, I can configure the PWM, but what do I set these to? I found a link to “Linux Core PWM User’s Guide, however, some of it is wrong, but it gave me enough to understand how to configure the PWM. The duty cycle and period are in nanoseconds, and “run” will enable the output. So, I can check and set things as follows,

root@beaglebone:~# cat /sys/class/pwm/pwm3/duty_ns
root@beaglebone:~# echo 500000 > /sys/class/pwm/pwm3/duty_ns
root@beaglebone:~# cat /sys/class/pwm/pwm3/duty_ns

I was able run my motors and change the speed using the command line. The next step would be to code this in C/C++ using the open(), write(), and close() functions. So, that was my adventure in getting the PWM output working in my project.