Using PWM on the Beaglebone Black

Problem

After searching the internet I found that most PWM and pin muxing code had been rendered obsolete due to the new 3.8 kernel used in the BBB. I found two sources of information that were helpful in order to get PWM working (here and here). From this I played around until I got the EHRPWM pins working. I have written up a C++ library so that you guys can use it from within your applications.

The main problem I found with the steps was a similar problem that other people were having.

  1. I couldnt change the period of the pin
  2. If I changed the period for one channel of the PWM module, I didnt get period/duty/polarity files that I could modify for the other channel

The reason for not being able to set the period is that both channels need to share the same period. As a result if both channels are enabled (such as P8 Pin 13 and 19) then setting either period will conflict with the other. If the period was initially changed for one of the channels then the other period (which is initialized from the device tree module) has a conflicting period and thus does not actually allow the pin driver to be setup.

Solution

To fix these issues I modified the pwm_test kernel driver so that it would not initialize the channel if it has a period of 0. (Line 273 in kernel/drivers/pwm/pwm_test.c


/* Only set the config if the period is > 0. Otherwise the period will be set later dynamically */
if ( pwm_test->period > 0 )
{
/* polarity is already set */
rc = pwm_config(pwm_test->pwm, pwm_test->duty, pwm_test->period);
if (rc) {
dev_err(dev, "pwm_config() failed\n");
return rc;
}
} else {
pwm_test->period = 0;
}

The next thing that needed be changed was the device overlays for the bone_pwm_P* pins were changed so that they had a period of 0 and were disabled at the start.

pwms = <&ehrpwm2 1 500000 1>;
enabled = ;

became (for each bone_pwm_P module)

pwms = <&ehrpwm2 1 0 1>;
enabled = ;

Once I made those changes, I recompiled the kernel (following the instructions here or here). Copied over pwm_test.ko to /lib/drivers/, copy the compiled dtbo files into /lib/firmware and then manipulated the period as described in the previous links. The only thing to make sure now is that you set the periods for both channels at the start to whatever you desire and then enable it by echo'ing 1 to the run fille.

Code/Files

I've uploaded the compiled files and the library on a git-hub repo (https://github.com/SaadAhmad/beaglebone-black-cpp-PWM)  and installation instructions can be found there

 

Hope you guys find this useful!