ledc API set to 20,000 Hz. Pair it with a Mean Well PWM-120-24 constant-voltage driver and a Lutron DVELV-300P trailing-edge dimmer on the AC side. Never use standard 490 Hz Arduino analogWrite for architectural lighting, and never put a leading-edge dimmer on a switching LED power supply.
The Core Circuit: Arduino Code for RGB LED PWM Control
Standard AVR-based Arduino boards (like the Uno) output PWM at roughly 490 Hz by default. When you point a smartphone camera at a 490 Hz light source, the rolling shutter creates a beat frequency, resulting in severe visual banding. To fix this, we use the ESP32 DevKit v1 programmed via the Arduino IDE. The ESP32's LED Control (LEDC) peripheral allows us to push the PWM frequency to 20 kHz, which is entirely imperceptible to both the human eye and high-speed camera sensors Espressif LEDC API Documentation.
Because the ESP32 GPIO pins output 3.3V logic and can only source about 40mA, you cannot drive the LED strip directly. You must use N-channel logic-level MOSFETs (like the IRLZ44N) to switch the 24V load. The gate threshold voltage (Vgs) of the IRLZ44N is fully saturated at 3.3V, making it ideal for direct ESP32 drive without a gate driver IC.
| ESP32 GPIO | LEDC Channel | MOSFET Gate | Color Channel |
|---|---|---|---|
| GPIO 16 | 0 | Gate 1 | Red |
| GPIO 17 | 1 | Gate 2 | Green |
| GPIO 18 | 2 | Gate 3 | Blue |
| GND | N/A | Sources (Tied) | Common Ground |
// ESP32 Arduino IDE Code for 20kHz Flicker-Free RGB PWM
const int freq = 20000; // 20 kHz to eliminate camera flicker
const int resolution = 12; // 12-bit resolution (0-4095)
const int redPin = 16;
const int greenPin = 17;
const int bluePin = 18;
void setup() {
// Configure LEDC channels
ledcSetup(0, freq, resolution);
ledcSetup(1, freq, resolution);
ledcSetup(2, freq, resolution);
// Attach channels to GPIO pins
ledcAttachPin(redPin, 0);
ledcAttachPin(greenPin, 1);
ledcAttachPin(bluePin, 2);
}
void loop() {
// Example: Smooth crossfade to warm white (RGB: 255, 180, 50 equivalent in 12-bit)
ledcWrite(0, 4095); // Red 100%
ledcWrite(1, 2890); // Green ~70%
ledcWrite(2, 800); // Blue ~20%
delay(5000);
// Fade out
for(int duty = 4095; duty >= 0; duty -= 10) {
ledcWrite(0, duty);
ledcWrite(1, duty * 0.7);
ledcWrite(2, duty * 0.2);
delay(5);
}
delay(2000);
}
Sizing the Power Supply (Lumens, Watts, and Inrush Math)
When sizing a constant-voltage (CV) power supply for an RGB strip, you must calculate the maximum simultaneous draw (all channels at 100% duty cycle, yielding white light) and add a 20% derating margin for thermal longevity. Below is a lumens and watts equivalence table for standard 24V architectural strips, including efficacy context to help you judge light output per watt DOE Solid-State Lighting Basics.
| Strip Density | Watts per Meter | Lumens per Meter | Efficacy (lm/W) | 5-Meter Total Draw |
|---|---|---|---|---|
| 60 LEDs/m (Standard) | 14.4 W/m | 1,050 lm/m | 72.9 lm/W | 72W (3.0A @ 24V) |
| 120 LEDs/m (High Density) | 28.8 W/m | 2,200 lm/m | 76.3 lm/W | 144W (6.0A @ 24V) |
| 240 LEDs/m (COB/Dot-Free) | 24.0 W/m | 2,050 lm/m | 85.4 lm/W | 120W (5.0A @ 24V) |
Circuit Impact Math: Let's size for the 120 LEDs/m strip (144W total). Adding the 20% safety margin brings our required continuous capacity to 172W. A standard 200W 24V supply is required. However, the hidden killer in LED circuit design is inrush current. When a switching power supply like the Mean Well LRS-200-24 is first energized, the bulk input capacitors act as a dead short. The datasheet specifies a cold-start inrush of 60A for 0.5ms at 230VAC. If you put this on a standard 10A Type B residential breaker, the magnetic trip will instantly fire. You must use a Type C or Type D MCB (Miniature Circuit Breaker) which tolerates 5x to 10x instantaneous inrush spikes without tripping.
Additionally, consider the Power Factor (PF). A 200W driver with active PFC will show a PF of 0.95 at full load. But if your Arduino code spends most of its time dimming the strip to 20% brightness, the PF can drop to 0.75, increasing the apparent power (VA) and causing slight inefficiencies on the AC mains side.
Dimmer Compatibility and Wall-Switch Integration
If your project requires integration with a physical wall switch, you cannot place a standard AC dimmer on the DC output of the power supply, nor can you use a leading-edge (TRIAC) dimmer on the AC input of a switching power supply. Leading-edge dimmers chop the front of the AC sine wave, which causes the power supply's EMI filter capacitors to draw massive current spikes, resulting in audible buzzing, destroyed TRIACs, and premature driver failure Lutron LED Dimming Guide.
1. Topology: You must use a Trailing-Edge (ELV) dimmer. These use MOSFETs to chop the back of the sine wave, which is gentle on capacitive loads like LED drivers.
2. Minimum Load: Most ELV dimmers require a minimum load (typically 5W to 15W) to keep their internal logic powered. If your Arduino dims the RGB strip below this threshold, the wall switch will start 'popping' or strobing.
3. Driver Type: The power supply must be explicitly rated as 'dimmable' (e.g., Mean Well PWM-series) and feature a 0-10V or PWM dimming input, or be designed to interpret phase-cut AC waveforms.
Which dimmer/driver for this fixture count? For a single 5-meter run of 120 LED/m RGB strip (144W), pair the Mean Well PWM-120-24 (a dedicated CV dimmable driver) with the Lutron Diva DVELV-300P trailing-edge dimmer. The PWM-120-24 translates the AC phase-cut signal into a clean 24V PWM signal for your strip, bypassing the need for the ESP32 MOSFET circuit entirely if you only want wall-dimming. If you want ESP32 smart control *and* wall dimming, wire the Lutron to a smart relay, and let the ESP32 handle the DC-side MOSFET dimming.
Solving PWM Flicker and Thermal Enclosure Constraints
Why flicker happens and the fix: As mentioned, 490 Hz PWM causes rolling-shutter banding. But there is a second type of flicker: low-frequency strobing caused by the power supply's internal protection circuits. If your ESP32 code demands more current than the power supply's rated limit (e.g., asking for 150W from a 120W driver), the driver enters 'hiccup mode'—shutting down and restarting every 2 seconds. The fix is strict adherence to the 80% continuous load rule outlined in the sizing table above.
Heat and enclosure constraints: High-density RGB strips generate significant heat at the PCB trace level. While the IRLZ44N MOSFETs on your breadboard will only dissipate about 0.088W each (Calculated via $P = I^2R$, where $I = 2A$ and $R_{ds(on)} = 0.022\Omega$), the LED strip itself will degrade rapidly if trapped in a sealed enclosure. A 28.8 W/m strip running at 100% white in a sealed polycarbonate diffuser will push the LED junction temperature past 85°C, causing a 30% drop in lumen output within 6 months. You must mount high-density strips inside an aluminum extrusion channel with a thermal pad to act as a heatsink, and ensure the MOSFET driver board has at least 15mm of clearance for convective airflow inside your project enclosure.
Decision Tree: Finalizing Your Component Pick
Use this decision path to lock in your exact Bill of Materials (BOM) based on your strip length and control requirements. Do not mix and match incompatible topologies.
| Condition / Requirement | Component Selection | Why This Pick? |
|---|---|---|
| Strip draw is < 60W (e.g., 2m of 120 LED/m) | Mean Well PWM-60-24 | Matches load, built-in phase-cut decoding, high PF. |
| Strip draw is 60W - 120W (e.g., 4m of 120 LED/m) | Mean Well PWM-120-24 | Provides 20% headroom over 96W load, prevents hiccup mode. |
| Strip draw is > 120W (e.g., 5m+ of 120 LED/m) | Mean Well HLG-240H-24B | Industrial grade, handles massive inrush, active PFC. |
| Wall control required (AC side) | Lutron DVELV-300P | Trailing-edge ELV, handles capacitive driver loads smoothly. |
| Smart/Code control required (DC side) | ESP32 + 3x IRLZ44N MOSFETs | Native 20kHz LEDC API eliminates camera banding. |
Final Default Recommendation: For the most common architectural use case—a 5-meter run of 24V COB RGB strip (120W total) requiring both smooth color mixing and zero camera flicker—purchase the Mean Well PWM-120-24 power supply, an ESP32 DevKit v1, and three IRLZ44N MOSFETs. Wire the ESP32 to the DC side using the 20kHz code provided above, and leave the AC side on a dedicated 10A Type C breaker. This exact configuration eliminates flicker, survives inrush spikes, and provides 1:1 color resolution without thermal throttling.






