Building a reliable, flicker-free lamp for Raspberry Pi requires more than just wiring an LED to a GPIO pin. To handle the current of a functional desk or room lamp without burning out your Pi's logic board, you need a logic-level MOSFET driver circuit and a hardware PWM pin. By targeting GPIO 18 (the only hardware PWM0 pin available on the standard 40-pin header) and using an IRLZ44N MOSFET, you can smoothly dim a 12V LED strip from 0% to 100% without the visible flicker or audio interference that plagues software PWM implementations.
Time to Build: 45 minutes.
Target Board Variants: Raspberry Pi 4 Model B (4GB) and Raspberry Pi 5 (4GB/8GB) running Raspberry Pi OS (Bookworm or newer).
Hardware BOM and Electrical Specifications
Before stripping any wires, verify your components against this bill of materials. Using a standard 5V logic MOSFET like the IRF520 will result in incomplete switching and excessive heat at 3.3V gate drive; the IRLZ44N is mandatory for direct Pi GPIO driving.
| Component | Exact Model / Variant | Key Specification | Est. Cost (2026) |
|---|---|---|---|
| Microcontroller | Raspberry Pi 4B (4GB) or Pi 5 | 3.3V Logic, Hardware PWM on GPIO 18 | $55 - $80 |
| MOSFET | IRLZ44N (Infineon/International Rectifier) | Logic-Level, Vgs(th) ≤ 2.0V, Rds(on) 22mΩ | $1.50 |
| LED Load | 12V 5050 SMD Analog LED Strip | 14.4W/meter, Resistive/Capacitive load | $15.00 / 5m |
| Power Supply | Mean Well LRS-60-12 | 12V DC, 5A (60W), Enclosed | $18.00 |
| Gate Resistor | 100Ω 1/4W Carbon Film | Prevents high-frequency gate ringing | $0.10 |
| Pull-down Resistor | 10kΩ 1/4W Carbon Film | Keeps MOSFET off during Pi boot | $0.10 |
Pin Mapping and Wiring Table
This table maps the physical Raspberry Pi header pins to the MOSFET driver circuit. Always double-check pinouts with a multimeter before applying power.
| Pi Pin (BCM / Physical) | Function | Connects To | Notes |
|---|---|---|---|
| GPIO 18 / Pin 12 | Hardware PWM0 Output | 100Ω Resistor → MOSFET Gate | Only hardware PWM pin on standard header |
| GND / Pin 6 | Logic Ground | MOSFET Source & 10kΩ Pull-down | Must share common ground with 12V PSU |
| N/A (External) | 12V DC Positive | LED Strip +12V | From Mean Well LRS-60-12 V+ terminal |
| N/A (External) | 12V DC Negative | MOSFET Drain (via LED Strip) | From Mean Well LRS-60-12 V- terminal |
Wiring the 12V MOSFET Driver Circuit
The Raspberry Pi GPIO pins can only source about 16mA safely. A 1-meter strip of 12V LEDs draws roughly 1.2A. We use the Pi to switch the gate of the MOSFET, which in turn switches the high-current 12V load.
- Prepare the Gate Drive: Solder the 100Ω resistor to the end of a jumper wire. Connect the other end of the resistor to the Gate (middle pin) of the IRLZ44N. This resistor dampens parasitic oscillation that can fry your Pi's GPIO pin.
- Install the Pull-down: Solder the 10kΩ resistor between the Gate and Source (right pin, tab is also Source) of the MOSFET. When the Pi boots, GPIO pins float; this resistor ensures the lamp stays off until your Python script explicitly initializes the pin.
- Wire the Logic Ground: Connect a jumper wire from the MOSFET Source to the Raspberry Pi's GND (Pin 6). Critical: The Pi and the 12V power supply must share a common ground reference for the 3.3V logic signal to be recognized by the MOSFET.
- Connect the 12V Load: Connect the 12V Positive output from the Mean Well PSU directly to the positive lead of the LED strip. Connect the negative lead of the LED strip to the Drain (left pin) of the MOSFET.
- Complete the Power Circuit: Connect the 12V Negative output from the PSU to the MOSFET Source (tying it in with the Pi GND connection made in Step 3).
- Connect the Signal: Finally, connect the free end of the 100Ω gate resistor wire to GPIO 18 (Physical Pin 12) on the Pi.
Python Control Code with Error Handling
We use the gpiozero library, which is pre-installed on modern Raspberry Pi OS and abstracts the hardware PWM cleanly. This code targets both the Pi 4 and Pi 5, utilizing the PWMLED class to handle the duty cycle calculations.
from gpiozero import PWMLED
from signal import pause
import sys
import logging
# Configure basic logging for debugging
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
# Hardware PWM pin on Raspberry Pi 4/5 (BCM numbering)
LAMP_PIN = 18
def initialize_lamp():
"""Initializes the PWM LED with hardware PWM on GPIO 18."""
try:
# frequency=1000 ensures smooth dimming without audible whine from the MOSFET
lamp = PWMLED(LAMP_PIN, frequency=1000, initial_value=0)
logging.info(f'Successfully initialized PWM lamp on GPIO {LAMP_PIN}')
return lamp
except Exception as e:
logging.critical(f'Failed to initialize GPIO {LAMP_PIN}: {e}')
sys.exit(1)
def main():
lamp = initialize_lamp()
try:
logging.info('Starting smooth fade-in sequence...')
# Fade in over 2 seconds, stay on, then pulse 3 times
lamp.fade_in(fade_time=2)
lamp.brightness = 0.85 # Set to 85% duty cycle for nominal desk lighting
logging.info('Lamp set to 85% brightness. Press Ctrl+C to exit.')
# Keep the script running to maintain the PWM signal
pause()
except KeyboardInterrupt:
logging.info('Shutdown signal received (Ctrl+C).')
except Exception as e:
logging.error(f'Unexpected runtime error: {e}')
finally:
# Always ensure the hardware is cleaned up and turned off
logging.info('Turning off lamp and releasing GPIO resources.')
lamp.off()
lamp.close()
if __name__ == '__main__':
main()
Debugging: Fixing "RuntimeError: This module can only be run on a Raspberry Pi!"
If you copy legacy code from older tutorials using the RPi.GPIO library on a Raspberry Pi 5, your script will immediately crash with this exact error string:
RuntimeError: This module can only be run on a Raspberry Pi!
This happens because the Raspberry Pi 5 uses the new RP1 southbridge chip, and the legacy RPi.GPIO library hardcodes a check for the older BCM2711 SoC found on the Pi 4. It fails the hardware check and aborts.
The First Three Things to Check When It Fails
- Verify Your Library: Check your
importstatements. If you seeimport RPi.GPIO as GPIO, you are using the legacy library. Refactor your code to usegpiozero(as shown above) or install the modern forkrpi-lgpioviasudo apt install python3-rpi-lgpio. - Check User Permissions (gpio group): If you are running a minimal container or a custom OS build, your user might lack hardware access. Run
groupsin the terminal. Ifgpiois missing, add your user withsudo usermod -aG gpio $USERand reboot. - Inspect for Pin Conflicts: While GPIO 18 is dedicated to PWM0, ensure you haven't accidentally enabled an overlay in
/boot/firmware/config.txt(likedtoverlay=pwm-2chan) that remaps the pin to an audio output, which will causegpiozeroto throw aPinFactoryFallbackwarning or fail to assert the signal.
Extending and Simplifying the Build
Once you have the baseline lamp working, you can adapt the architecture to fit your specific project constraints.
How to Simplify (No Pi Required)
If you realize you don't need network connectivity or complex scheduling, driving a Pi just to dim an LED is massive overkill. You can simplify this exact MOSFET driver circuit by replacing the Pi with a 555 Timer IC (NE555) wired in astable mode with a diode across the timing resistor. This gives you a physical potentiometer knob for PWM dimming, costs under $2 in parts, and draws microamps of standby current compared to the Pi's 3W-5W idle draw.
How to Extend (Home Assistant / MQTT)
To integrate this lamp into a smart home ecosystem without relying on proprietary cloud APIs, extend the Python script using the paho-mqtt library.
Add an MQTT client that subscribes to a topic like home/office/desk_lamp/set. When a payload of {"brightness": 150} arrives (using an 8-bit 0-255 scale), map that value to the 0.0-1.0 float required by gpiozero (150 / 255.0) and update lamp.brightness. This allows seamless integration with Home Assistant via the MQTT integration, giving you local-only, sub-50ms latency control over your lighting without exposing your network to external cloud servers.
For deeper reading on hardware PWM capabilities and pin multiplexing on the RP1 chip, refer to the official Raspberry Pi Compute Documentation and the gpiozero PWMLED API reference.






