PWM0 & 1
Getting the PWM’s working reliably in user land is a bit of a journey. There are some decisions to make along the way so configuration is quite as straight forward as the other hardware.
PWM is available on the following pins:
- PWM0 GPIO12 & 18
- PWM1 GPIO13 & 19
Those of you will older 26pin header rPi’s will only have PWM0 on GPIO18.
Note that the PWM clocks are used by the analogue audio output. So if you are going to use the PWMs you need to be aware you cannot use the analogue audio. Digital (hdmi) audio is fine though.
Prerequisite Configuration
- Arch requires Prerequisite Configuration. See this page for more information.
- Raspbian requires some Prerequisite Configuration. See this page for more information.
/boot/config.txt
Before you can do anything you have to work out what configuration is best for yourself
- Those with a 26pin header can only use PWM0 on GPIO18.
- Those with a 40pin header
- Decide if you would like to have 1 or 2 PWMs
- If you plan to use SPI1 in the future you should use PWM0 on GPIO12 and|or PWM1 on GPIO13.
- If you do not plan to use SPI1 in the future I still suggest PWM0 on GPIO12 and|or PWM1 on GPIO13. This is because there is a lot of alternate functions on GPIO18/19 – PCM audio, Slave BCS/SPI, SPI1 (Aux) – some of which we will see in the future.
Make note of the GPIO/Func values below for your selected configuration:
PWM | GPIO Pin | Func |
---|---|---|
0 | 12 | 4 |
0 | 18 | 2 |
1 | 13 | 4 |
1 | 19 | 2 |
(The ‘Func’ value is just the ‘alternate function code’ from the p102 & p98 of the Broadcom BCM2835 ARM Peripherals document.)
Now its just a matter of putting the appropriate dtoverlay line into /boot/config.txt:
A single PWM uses a command like ‘dtoverlay=pwm,pin=#,func=#’
eg PWM0 on GPIO18 for a rPi A
dtoverlay=pwm,pin=18,func=2
To setup 2 PWMs use a command like ‘dtoverlay=pwm-2chan,pin=#,func=#,pin2=#,func2=#’
eg PWM0 on GPIO12 & PWM1 on GPIO13 for a rPi2 B
dtoverlay=pwm-2chan,pin=12,func=4,pin2=13,func2=4
FYI: This is all documented in /boot/overlays/README.
Kernel Module
Once enabled in the config.txt the kernel module should load automatically after a reboot. Check with lsmod.
$ lsmod | grep pwm pwm_bcm2835 2631 2
If it doesn’t appear make sure this isn’t blacklisted in/etc/modprobe.d/raspi-blacklist.conf. When the module is running you will find the following item now exists in sys fs.
/sys/class/pwm/pwmchip0
System Config
There are a few steps to do here.
Firstly configure the rPi not to use analogue audio since as previously mentioned the clocks for this are taken from the PWM’s. To do this run raspi-config and select 8) Advanced Options → A9) Audio → 2) Force HDMI
Now for the ‘less than ideal’ bit…
At every bootup several things must happen for the PWM(s) to be usable.
- They must be enabled in sysfs
- They need have their permissions changed so that members of the group (we have just created) can use them.
- The PWM clock needs to be started – yep I know, kind of odd that the driver doesn’t start the PWM clock but lets not go there.
This is all handled by a script that got installed in /usr/local/bin/librpip-util called ‘librpip-pwm-init’ that got installed when librpip got installed. Check the documentation page for more details on exactly what it is doing.
Arch
To configure the system enable the pwm-init.service that was installed as part of the prerequisites.
$ systemctl enable pwm-init.service
Raspbian
To configure the system just call this script from /etc/rc.local by adding it before the ‘exit 0’ like so:
/usr/local/bin/librpip-util/librpip-pwm-init exit 0
Now you rPi will enable the PWMs at each boot up. You should reboot and make sure everything happened automatically. If all is good a PWM0 and or PWM1 directory (whatever you decided on) should be in /sys/class/pwm/pwmchip0 with rw access to the pwm group to the files inside.
$ ls -l /sys/class/pwm/pwmchip0/pwm* /sys/class/pwm/pwmchip0/pwm0: total 0 -rw-rw---- 1 root pwm 4096 Jan 25 17:41 duty_cycle -rw-rw---- 1 root pwm 4096 Jan 25 17:41 enable -rw-rw---- 1 root pwm 4096 Jan 25 17:41 period -rw-rw---- 1 root pwm 4096 Jan 25 17:41 polarity -rw-rw---- 1 root pwm 4096 Jan 25 17:41 uevent
/sys/class/pwm/pwmchip0/pwm1: total 0 -rw-rw---- 1 root pwm 4096 Jan 25 17:41 duty_cycle -rw-rw---- 1 root pwm 4096 Jan 25 17:41 enable -rw-rw---- 1 root pwm 4096 Jan 25 17:41 period -rw-rw---- 1 root pwm 4096 Jan 25 17:41 polarity -rw-rw---- 1 root pwm 4096 Jan 25 17:41 uevent
A brief rundown of those files.
- duty_cycle and period both expect a positive integer in nano seconds. duty_cycle must be less than period so set period first.
- enable expects a o or 1 (off & on)
- polarity expects a ‘normal’ or ‘inverted’ and cannot be changed while the PWM is enabled.
To test connect lets create a 20us period with 25% (=5us) duty cycle. You’ll need to physically connect up a LED and small (330 ohm) resistor from whatever pin you decided on to ground and then run the following commands:
echo 20000 > /sys/class/pwm/pwmchip0/pwm0/period echo 5000 > /sys/class/pwm/pwmchip0/pwm0/duty_cycle echo 1 > /sys/class/pwm/pwmchip0/pwm0/enable
Issues
While sysfs is a fantastic place for linux to reveal internal details about itself it’s not really the right place for users to access hardware. That has always been /dev. Although the sysfs interface works it is much slower than the equivalent /dev interface as the sysfs files must be opened and closed with each access unlike /dev where the interface stays open between calls. You’ll notice a fade out of a lcd display for example takes longer than expected. But hey it’s better than nothing and I’m not complaining!
For any serious PWM work you are much better of with something like this.
If you are going to drive servo’s it is probably good idea to level shift the output up to 5v.