Changing PWM frequency at run time

Hello all,

As (probably) most of you are aware, the most straightforward method of changing the pwm period (frequency) is at boot by setting it in a .dts overlay. This may be the solution for 90% of pwm users, but we have run into the situation where we would like to change the pwm period at run time to avoid re-compiling the .dts overlay when we wish to swap between different applications. After poking around I present our breadcrumb trail:

Start with http://git.kernel.org/cgit/linux/kernel/git/stable/linux-stable.git/tree/drivers/pwm/pwm-tiehrpwm.c
This is apparently near the current source tree. There is a func() ehrpwm_pwm_config that talks about setting the period and duty.

Once compiled, it seems to end up in the beaglebone’s file system here. Is this .ko strictly necessary if we only fix the pwm period at boot? Is this the real kernel module? The name implies this is not the official pwm driver, but perhaps it is?

/lib/modules/3.8.13/kernel/drivers/pwm/pwm_test.ko

There is a note that seems to point out the limitations of common clock sources
/*

  • Period values should be same for multiple PWM channels as IP uses
  • same period register for multiple channels.
    /
    There is a note to allow this if and only if:
    /
  • Allow channel to reconfigure period if no other
  • channels being configured.
    */

And if that if and only if fails it gripes
dev_err(chip->dev, “Period value conflicts with channel %d\n”, i);
return -EINVAL;

The routine continues to set the channel pwm->hwpwm. Apparently, the pwm chip pointed to by *pc has NUM_PWM_CHANNELs, which is 2? A trial hack might be to just ignore that gripe and configure all/both channels. For example, this seems to do the actual write:
ehrpwm_write(pc->mmio_base, TBPRD, period_cycles);

But apparently, each channel has its own compare register, just a common clock:
if (pwm->hwpwm == 1)
/* Channel 1 configured with compare B register /
cmp_reg = CMPB;
else
/
Channel 0 configured with compare A register */
cmp_reg = CMPA;

ehrpwm_write(pc->mmio_base, cmp_reg, duty_cycles);

So, if a hack at the source is to be tried, I’d comment out the check about the other channel already having a differing value. We can trust ourselves to work within the constraint and remember that changing Channel 1’s clock also changes Channel 0’s clock. Of course, even trying this requires recompiling the kernel OR trying to make a tiehrpwm_test .ko of our own. Unfortunately neither of these options are within our skill-set.

The author obviously recognized the clock dependency between the two channels and trapped it. But how did they expect users to deal with it? And who was the author? It would be nice to ask them. The header on this file shows credit to Texas Instruments circa 2012 but no human names given.

There is a public workaround to allow setting of the pwm_period ONCE at run-time. We have successfully tested this within the 9.04 Angstrom release on the Beaglebone black. It requires a (included and precompiled) .ko kernel module which will unfortunately not load in the recent Debian builds.

https://github.com/SaadAhmad/beaglebone-black-cpp-PWM/blob/master/driver/pwm_test.c

The driver source file at https://github.com/SaadAhmad/beaglebone-black-cpp-PWM/blob/master/driver/pwm_test.c
Includes the same Texas Instruments header as if Saad is from TI, or perhaps he just copied it over without changing.

He has a personal URL http://saadahmad.ca/ Well, this “explains” quite a bit of how he does it. He doesn’t conclude with a proposed set of changes to the kernel, but has built a work around. It requires changing the the pwm_test.ko and setting the pwm period in the device tree to 0 at boot, then setting it only once at run-time.

We would like to see a (hopefully) small fix in the official TI ehrpwm driver that allows us to change the pwm period as frequently as we wish at run-time make its way into the beaglebone black build chain.

Best,
C Briggs, J Strawson

Hi,

Hello all,

As (probably) most of you are aware, the most straightforward method of changing the pwm period (frequency) is at boot by setting it in a .dts overlay. This may be the solution for 90% of pwm users, but we have run into the situation where we would like to change the pwm period at run time to avoid re-compiling the .dts overlay when we wish to swap between different applications.

How about something like this in runtime?

echo 0 > /sys/class/pwm/pwmchip1/export

cd /sys/class/pwm/pwmchip1/pwm0

1 kHz:
echo 0 > enable
echo 1000000 > period
echo 500000 > duty_cycle
echo 1 > enable

100 Hz:
echo 0 > enable
echo 10000000 > period
echo 5000000 > duty_cycle
echo 1 > enable

Regards,

Robert