Hardware PWM LED Dimming on Raspberry Pi Using pigpio
Learn how to wire an LED to GPIO18 and use hardware PWM via the pigpio daemon to achieve smooth brightness control with minimal CPU load.
01 Feb 2026, 22:45 UTC

Desired outcome
Achieve smooth brightness control of an LED connected to GPIO18 (BCM) by using the Raspberry Pi’s hardware PWM module. The goal is to vary the duty cycle from 0 % to 100 % without loading the CPU, so the LED appears to dim linearly.
Necessary prerequisites
- Raspberry Pi 4 (or any model with BCM2835/2836/2837/2840 SoC)
- Raspberry Pi OS Bullseye or later
- Basic electronics: one LED, a 220 Ω current‑limiting resistor, a breadboard, and jumper wires
- The
pigpiodaemon and its command‑line utilitypigsinstalled (e.g.,sudo apt install pigpio) - User with sudo privileges to start system services
Procedure
- Wire the circuit
- Connect the LED’s anode (longer lead) to one end of the 220 Ω resistor.
- Connect the other end of the resistor to GPIO18 (pin 12 on the 40‑pin header).
- Connect the LED’s cathode (shorter lead) to a ground pin (e.g., pin 6).
This arrangement limits the current to roughly
3.3 V / 220 Ω ≈ 15 mA, safely under the GPIO’s 16 mA per‑pin limit. - Start the pigpio daemon
sudo systemctl start pigpiodThe daemon provides access to the hardware PWM channels via DMA, offloading timing from the CPU.
- Set PWM frequency and duty cycle
Hardware PWM on the Pi uses a range of 0‑255 for the duty cycle, where 0 is off and 255 is fully on. Choose a frequency visible to the eye but high enough to avoid flicker; 800 Hz works well.
# Set frequency to 800 Hz on GPIO18 sudo pigs freq 18 800 # Sweep duty cycle from 0 to 255 and back (example shell loop) for i in {0..255}; do pigs p 18 $i sleep 0.01 done for i in {255..0}; do pigs p 18 $i sleep 0.01 doneAlternatively, a short Python script achieves the same:
import pigpio, time pi = pigpio.pi() if not pi.connected: exit() pi.set_PWM_frequency(18, 800) try: while True: for dc in range(0, 256): pi.set_PWM_dutycycle(18, dc) time.sleep(0.005) for dc in range(255, -1, -1): pi.set_PWM_dutycycle(18, dc) time.sleep(0.005) except KeyboardInterrupt: pi.set_PWM_dutycycle(18, 0) pi.stop()
Expected checks
- Visually, the LED should glow dimly at low duty cycles and reach full brightness near 255, with a smooth transition.
- Using a multimeter capable of measuring frequency/duty‑cycle, probe GPIO18 and ground; you should see a ~800 Hz square wave whose high‑time proportion matches the set duty cycle (e.g., 128 → ≈50 %).
- Run
toporhtopwhile the sweep is active; thepigpiodprocess should consume well under 5 % CPU, confirming hardware offload.
Recovery options
- If the LED remains off:
- Verify the resistor is present and correctly oriented.
- Check wiring: anode → resistor → GPIO18, cathode → ground.
- Confirm the daemon is running:
sudo systemctl status pigpiod. Start it if inactive.
- If the GPIO appears stuck at a constant level:
- Reset the pin to 0 % duty cycle:
pigs p 18 0. - As a last resort, reboot the Pi:
sudo reboot. - To avoid over‑current, measure the current through the resistor with a multimeter in series; ensure it stays below 16 mA per pin and the total GPIO current stays under 50 mA.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.