Pi IoT In Python Using Linux Drivers - PWM
Written by Harry Fairhead & Mike James   
Monday, 11 October 2021
Article Index
Pi IoT In Python Using Linux Drivers - PWM
PWM Driver
PWM Class
Number of Duty Cycles

The PWM Driver

All Pi models have two PWM channels implemented in hardware, but on models earlier than the Pi 4 these are also used to generate audio. What this means is that if you want to use hardware PWM on a Pi Zero or earlier you have to disable or at least not use audio at the same time. You can use both on a Pi 4, but notice that the PWM channels and the audio share the same clock signal and this can still cause problems.

The two PWM hardware modules can be configured to drive different GPIO lines. For the Pi the standard configuration is to have PWM0 drive either GPIO18 or GPIO12 and PWM1 drive either GPIO13 or GPIO19.

There are two PWM drivers available. One that activates a single PWM channel and one that activates both the available channels. The documentation for both is:

Name:  pwm
Info:  Configures a single PWM channel
       Legal pin,function combinations for each channel:
       PWM0:12,4(Alt0) 18,2(Alt5) 40,4(Alt0) 52,5(Alt1)
       PWM1:13,4(Alt0) 19,2(Alt5) 41,4(Alt0) 45,4(Alt0)
53,5(Alt1) N.B.: 1) Pin 18 is the only one available on all
platforms, and it is the one used by the
I2S audio interface. Pins 12 and 13 might be better choices on
an A+/B+/Pi2. 2) The onboard analogue audio output uses
both PWM channels. 3) So be careful mixing audio and PWM. 4) Currently the clock must have been enabled
and configured by other means. Load: dtoverlay=pwm,<param>=<val> Params:pin Output pin (default 18) - see table func Pin function (default 2 = Alt5)
- see above clock PWM clock frequency (informational) Name: pwm-2chan Info: Configures both PWM channels Legal pin,function combinations for each channel: PWM0: 12,4(Alt0) 18,2(Alt5) 40,4(Alt0) 52,5(Alt1) PWM1: 13,4(Alt0) 19,2(Alt5) 41,4(Alt0) 45,4(Alt0)
53,5(Alt1) N.B.: 1) Pin 18 is the only one available on all
platforms, and it is the one used by the
I2S audio interface. Pins 12 and 13 might be better choices on
an A+/B+/Pi2. 2) The onboard analogue audio output uses both
PWM channels. 3) So be careful mixing audio and PWM. 4) Currently the clock must have been enabled
and configured by other means. Load: dtoverlay=pwm-2chan,<param>=<val> Params: pin Output pin (default 18) - see table pin2 Output pin for other channel
(default 19) func Pin function (default 2 = Alt5)
- see above func2 Function for pin2 (default 2 = Alt5) clock PWM clock frequency (informational)

Note: There is a relatively recent (late 2019) patch to the driver that fixes a problem at high PWM frequencies. Use:

sudo apt update

followed by:

sudo apt full-upgrade

to make sure you have the up-to-date driver.

In simple terms you can use one or two channels of PWM and you would be well advised to use GPIO18 for PWM0 and GPIO19 for PWM1 on all modern Pis. Notice that you cannot currently use the driver to set the frequency of the PWM clock, but this is automatically enabled at a default frequency. You can find what the frequency is using:

vcgencmd measure_clock pwm

at the command prompt. It only reports an accurate value if the PWM driver is loaded and enabled. On a Pi Zero and a Pi 4 it reports 99995000, i.e. approximately 100Mhz, and empirical measurements give the effective clock rate, after division by 5, as 20MHz for both the Pi 4 and Pi Zero. The clock rate is important because it determines the resolution of the duty cycle – see later.

If you load either driver by adding:

dtoverlay=pwm

or

dtoverlay=pwm-2chan

to boot/config.txt, you will discover that on reboot you have a new pwmchip0 folder in the /sys/pwm folder.

The pi driver is configured to see the PWM hardware as a single PWM “chip”. To work with either PWM channel you have to export it. In this context exporting means that you claim sole use of the channel. To do this you have to write a “0” or a “1” to the export file in the pwmchip0 folder. To unexport you do do the same to the unexport file in the pwmchip0 folder.

After you have exported the channel you will see new folders, pwm0 and pwm1 in the pwmchip0 folder. Of course you only see the folders you have exported and you can only export pwm0 if you have use the PWM driver.

Within the pwmx folder you will find the following important files:

period  	period in nanoseconds
duty_cycle 	duty cycle in nanoseconds
enable 	        write 1 to enable, 0 to disable

So all you have to do is:

  1. export the channel

  2. write to period

  3. write to duty_cycle

  4. write “1” to enable

Notice that as this is hardware PWM, once you have set and enabled the channel, the PWM generation continues after the program ends.

A simple program to use PWM0 is:

import subprocess 
import io
def checkPWM():
    indicator = "pwm-2chan"
    command =["sudo", "dtoverlay", "pwm-2chan"]
    temp = subprocess.Popen(["sudo", "dtparam", "-l"],
                              stdout = subprocess.PIPE) 
    output = str(temp.communicate())
    print(output)
    if output.find(indicator)==-1:
        temp = subprocess.Popen(command, 
stdout = subprocess.PIPE) output = str(temp.communicate()) print(output) return checkPWM() fdw = io.open("/sys/class/pwm/pwmchip0/export", "wb",
buffering=0) fdw.write(b"0") fdw.close() fdw = io.open("/sys/class/pwm/pwmchip0/pwm0/period", b", buffering=0) fdw.write(b"10000000") fdw.close() fdw = io.open("/sys/class/pwm/pwmchip0/pwm0/duty_cycle", "wb", buffering=0) fdw.write(b"8000000") fdw.close() fdw = io.open("/sys/class/pwm/pwmchip0/pwm0/enable", "wb", buffering=0) fdw.write(b"1") fdw.close()

The checkPWM function dynamically loads the pwm-2chan driver – you can change it to pwm if you only need one channel. It exports the channel and then sets the period to 100Hz with an 80% duty cycle. This program doesn’t need root permissions to run, only to dynamically install the driver. You can use the other channel in the same way.



Last Updated ( Monday, 11 October 2021 )