PWM is something that we all use every day, even if we don’t know it. It’s a technique that’s straightforward and incredibly useful in a range of applications. Best yet, it’s something that your Raspberry Pi can do without breaking a sweat. How? Let’s take a look.
What Is PWM?
As terminology goes, “Pulse-Width Modulation” sounds pretty fancy. But all we’re really talking about here is turning an electrical signal off and on again—extremely quickly. Why might we want to do this? Simply because it’s a very easy way of simulating a variable analog signal, without resorting toRaspberry Pi HATs, add-ons, or extra circuitry. For certain applications, like heating a stove, driving a motor, or dimming an LED, a PWM signal is literally indistinguishable from a “real” analog voltage.
Duty Cycles
So, we have a series of pulses being fed into a load (the thing that we’re driving). This alone isn’t all that useful—until we start changing (or modulating) the width of those pulses. The “on” phase of a given on-off period can take up anywhere from 0–100% of the total cycle. We call this percentage theduty cycle.
For example, suppose we have a 3V PWM signal with a duty cycle of 50%. The average amount of power going through the LED would be equivalent to an always-on signal of 1.5V. Crank the duty cycle up, and the LED gets brighter; dial it down, and the LED dims. We can generate audio using the same method—which is why the audio out on your Raspberry Pi might stop functioning if you’re using PWM for other things.

PWM on the Raspberry Pi
You can use software PWM on every GPIO pin of the Raspberry Pi. But hardware PWM is available only onGPIO12, GPIO13, GPIO18,andGPIO19.
What’s the difference? Well, if you’re going to use software to generate the signal, then you’ll be consuming CPU cycles. Your CPU might have better things to do than tell an LED to turn off and on several hundred times per second, however. In fact, it might become distracted and bogged down by other tasks, which can seriously mess with your PWM timings.

Consequently, it’s often a better idea to delegate the task to specialized circuitry. In the case of the Raspberry Pi, this circuitry lives insidethe System on Chipthat houses the CPU. Hardware PWM is often far more precise and convenient, and thus it’s the preferred option in most cases. If you want an idea of what’s going on under the hood in the Raspberry Pi 4’s Broadcom BCM2711 chip, then you can look atthe BCM2711 documentation. Chapter 8 covers the PWM stuff!
Dimming an LED
To get our LED working with our Raspberry Pi, we’ll need to do some breadboarding. That means two components: the LED itself, and a current-limiting resistor, which we’ll connect in series with it. Without the resistor, your LED is at risk of dying in a foul-smelling puff of smoke if too much current passes through it.
Working Out the Resistor Value
It doesn’t matter which end of the LED you connect the resistor to. What matters is the resistor’s value. The Raspberry Pi 4 can provide around 16 milliamps per pin. So, we canuse Ohm’s lawto work out the value of the resistor needed.
Said law states that the resistance should equal the voltage over the current. We know the voltage coming out of the Pi’s GPIO pin (3.3V), and we know what the current should be (16 milliamps, or 0.016 amps). If we divide the former by the latter, we get 206.25. Now, since you’ll struggle to find resistors of this value, let’s go for 220 ohms instead.

Connect the LED’s anode (long leg) toGPIO 18(which is physical pin 12 on the Raspberry Pi). Connect the cathode (short leg) to any of the Pi’s ground pins. Don’t forget the resistor, somewhere along the path. You’re now ready to go!
Implementing PWM on Raspberry Pi
To get the hardware PWM working on Raspberry Pi, we’ll use therpi-hardware-pwm library from Cameron Davidson-Pilon, adapted fromcode by Jeremy Impson. This has been used in thePioreactor(a Pi-based bioreactor)—but it’s simple enough for our purposes.
First, let’sedit the config.txtfile, found in the/bootdirectory. We just need to add one line:dtoverlay=pwm-2chan. If we wanted to use GPIO pins other than 18 and 19, we could add some additional arguments here. For now, let’s keep things simple.
Reboot your Pi and run:
This command lists all the modules loaded onto the central part of the OS, called the kernel. Here, we’re filtering them to find only the PWM stuff, using thegrep(that’s “global regular expression print”) command.
Ifpwm_bcm2835shows up among the listed modules, then we’re on the right track. We’re almost done preparing! All that remains is to install the actual library. From the terminal, run:
We’re now ready to get started.
Coding the PWM LED Circuit
Time to get our hands dirty with a little bit ofcoding in Python. Fire up Thonny and copy in the following code. Then hitRun.
All being well, you’ll see the LED get gradually brighter until theicounter variable reaches 100.Then it’ll turn off.What’s going on here? Let’s walk through it.
We’re importing the relevant chunk of the hardware PWM library (along with thetimemodule) and declaring a new variable. We can set thepwm_channelto 0 or 1, which correspond respectively to GPIO pins 18 and 19 on the Pi.
Thehzvalue we can set to whatever frequency we like (though we’re ultimately limited by the Pi’s clock speed). At 60Hz, we shouldn’t see any PWM flicker. But it might be a good idea to start with a very low value (like 10) and gradually shift things up. Do this, and you’ll actually be able to see the pulses happening. Don’t just take our word for it!
We work our duty cycle (i) up from 0 to 100using a Python for loop. It’s worth noting that we can set thetime.sleepargument to as long as we like—since the PWM is being handled in hardware, it’ll run behind the scenes, however long we tell the program to wait.
There’s More to Learn With PWM
Congratulations! You’ve written your first PWM program. But, as is so often the case with the Raspberry Pi, there’s a lot you can do with this stuff, especially if you augment your Raspberry Pi with the right PWM HAT. So, don’t be content with one little LED. You can use this new power to control motors, encode messages, and generate synthesizer tones. A world of modulation awaits!