How to properly configure the PWM on debian gnu/linux 10 (buster)


I’m trying to make use of two PWM output lines from the BBB however, I am confused on how to properly enable them. I’ve looked at several resources and some are using capes/overlays and the subdirectories also look different from my BBB.

Here’s how I am currently approaching the PWM:

Export the pwm:

int fd, len;
char buf[MAX_BUF];
fd = open("/sys/class/pwm/pwmchip0/export", O_WRONLY);
len = snprintf(buf, sizeof(buf), "%d", 1);
write(fd, buf, len);

Set the Period, duty cycle:

fd = open("/sys/class/pwm/pwm-0:0/period", O_WRONLY);

Start PWM:

int fd, len;
char buf[MAX_BUF]; 
fd = open("/sys/class/pwm/pwm-0:0/enable", O_WRONLY);
len = snprintf(buf, sizeof(buf), "%d", 1);
write(fd, buf, len);

However, I get no output on Pin P9.21/22

What is further confusing is the maping of the pinouts and the directory of the PWM folders. Looking in /sys/class/pwm I see folders: pwm-0:0, pwm-1:1 … pwm-7:1, pwmchip0, pwmchip 1, … pwmchip7. However when I go into /sys/class/pwm/pwmchip0 I also see another folder pwm-0:0. So which folder do I have to write to in order to correctly initialize and start the PWM modulation. Also which Pin does pwm-0:0 correspond to versus pwm-1:0 and pwm-1:1. I’ve googled around and have come to the conclusion that:

P8.13 corresponds to folder: /sys/class/pwm/pwm-6:1
P8.19 corresponds to folder: /sys/class/pwm/pwm-6:0
P9.14 corresponds to folder: /sys/class/pwm/pwm-3:0
P9.16 corresponds to folder: /sys/class/pwm/pwm-3:1
P9.21 corresponds to folder: /sys/class/pwm/pwm-1:1
P9.22 corresponds to folder: /sys/class/pwm/pwm-1:0

I am unsure if that is indeed accurate

Here’s a summary of what I did to see pwm coming out…

These shell commands configured the port and
made the interface available at “/sys/class/pwm/pwm-4:0/”:

This command sets the processor’s pinmux setting for the pad going to P9 pin 14 to the PWM function

config-pin p9.14 pwm

Then this command writes a “0” to the file /sys/class/pwm/pwmchip0/export

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

Writing to the “export” file turns on the PWM interface for that chip, and brings the set of files for enabling pwm output, and setting the period, on-time, and polarity of the pwm.
The Value of “0” references the first of the two outputs of that port. Writing a “1” to that same file would turn on the interface for “/sys/class/pwm/pwm-4:1/”

At this point, the operating system will, at its own pace, set things up and eventually give permission to set the value(s). This has been initially measured at 150ms, and would not be surprising if it got longer due to processor loading. Plan accordingly. The nanosleep() function can provide the necessary delay.

I was testing things out using P9.14 and the period, duty_cycle, and enable files in /sys/class/pwm/pwm-4:0/ to do the controlling of that pin.

And the units for the duty_cycle, and period files were in nanoseconds, with about a 10ns offset. I got this by measuring the actual widths and repeat rates and comparing them to the values I wrote. For example, a value of 100 for translates to 110ns and 50 translates to 60ns)

This works, thank you. My only question is how did you correspond Pin P9_14 with …/pwm-4:0 and so forth?

My research landed me at:

I’m sure there’s a better resource in the kernel source tree just waiting to pop up.
Trial and error also worked. Seeing what files appeared when pinmux did its thing also helps. Keep in mind that sys/class/pwm/pwm-4:0/ isn’t hooked up to a filesystem. When it gets disabled. the file(s) go away. It’s not a real storage location, but a hook to a driver.

1 Like

Hello @jnelson ,

Seth here. I found this online: Pulse Width Modulation (PWM) interface — The Linux Kernel documentation .

It seems that one would need to initialize the driver once it is typed out. I am sure that has some ideas on this instance and initialization. For me, a singular person here, I am stuck on these ideas:

  1. Does this get declared in a .dts file and then I can use it in a .dtbo file from uEnv.txt in the /boot dir?


  1. Does one have to write up an entire driver w/:
    a. pwm_request() // taken from the kernel…
    b. Then initialized via: int pwm_apply_state(struct pwm_device *pwm, struct pwm_state *state);
    // taken from the kernel source

It seems w/ Bullseye things have changed or they are heading into a change b/c of the new kernel rules/ideas.


P.S. If anyone would like to jump in here for promoting a driver or just using some basic .c files, please do. It seems one must have access outside of sudo permissions to handle pwm instantiations. Argh!

1 Like