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!

One thought on “Using PWM on the Beaglebone Black

  1. Hi Saad ...

    Nice... I got your product to work from Eclipse remote debug. There is one caveat in the remote cross compiling setup: CLOCKS_PER_SEC is not defined. I hard-coded it to be the value I have the CPU running at and bingo, nice job on the code -- it works perfectly. So I found on the PC, that arm gnueabi in Eclipse does not have the include/bits/ directory (where the hardware time.h is and defines CLOCKS_PER_SEC), whereas on the BBB it does. Hence if your original code is compiled on the BBB, there is no problem. But I need cross-compile. I tried mkdir bits/ on the PC include/, copied over the time.h from the BBB, but it was not recognized by the IDE. Can you help ?

Leave a Reply

Your email address will not be published. Required fields are marked *