Resumen:
rbdimmerESP32está diseñado para ESP32 de doble núcleo (original y S3). ESP32-S2, C3, C6 y H2 son de un solo núcleo. La biblioteca intenta aislar la tarea del dimmer en un núcleo dedicado — lo cual es imposible en chips de un solo núcleo. La ISR compite con la pila WiFi, el timing se altera y el resultado es parpadeo, fallos aleatorios y brillo inestable. La solución es DimmerLink (ZC por hardware + I2C) o cambiar a un chip de doble núcleo.
Descripción del problema
Compraste un ESP32-C3 o ESP32-S2 — compacto, con WiFi/BLE, económico.
Conectas un dimmer AC directamente, usas rbdimmerESP32 — y observas:
- La carga parpadea a cualquier nivel de brillo
- El timing es inestable —
setPower(50)da 30 % un momento, 70 % al siguiente - Fallos con WiFi activo — funciona mejor sin WiFi, caos con WiFi
- El código compila sin errores, inestabilidad solo en tiempo de ejecución
O el compilador advierte sobre xTaskCreatePinnedToCore con un núcleo inexistente.
Mensajes típicos en foros:
- «ESP32-C3 + dimmer — parpadeo a cualquier nivel de potencia»
- «rbdimmerESP32 funciona en ESP32 pero no en ESP32-S2»
- «setPower(50) da brillo aleatorio en C3»
- «Funciona bien sin WiFi, falla en cuanto se conecta el WiFi»
Causa raíz
Qué chips ESP32 son de doble núcleo y cuáles no
| Chip | Núcleos | Arquitectura | Dimming ISR directo |
|---|---|---|---|
| ESP32 (original) | 2 | Xtensa LX6 | ✅ rbdimmerESP32 |
| ESP32-S3 | 2 | Xtensa LX7 | ✅ rbdimmerESP32 |
| ESP32-S2 | 1 | Xtensa LX7 | ⚠️ Solo DimmerLink |
| ESP32-C3 | 1 | RISC-V | ⚠️ Solo DimmerLink |
| ESP32-C6 | 1 | RISC-V | ⚠️ Solo DimmerLink |
| ESP32-H2 | 1 | RISC-V | ⚠️ Solo DimmerLink |
⚠️ Nota sobre ESP32-C6: el C6 tiene un núcleo LP adicional (Low Power), pero no es adecuado para dimming ISR — funciona a frecuencia reducida sin soporte completo de FreeRTOS. El núcleo principal es único.
⚠️ Confusión frecuente: ESP32-S3 es de doble núcleo (funciona). ESP32-S2 es de un solo núcleo (no funciona con ISR directa). Son chips diferentes.
Por qué la atenuación por corte de fase requiere aislamiento de núcleos
Timing de la compuerta TRIAC: desde el cruce por cero hasta el pulso de la compuerta — un retardo de 100–9000 µs, precisión ±10–20 µs. Cualquier retraso significa brillo incorrecto.
rbdimmerESP32 logra esta precisión en doble núcleo así:
- Núcleo 0 — tarea del dimmer (bucle de timing, manejo de ZC, disparo del TRIAC)
- Núcleo 1 — pila WiFi, TCP/IP, código de usuario
Se ejecutan en paralelo y no se bloquean mutuamente.
En un solo núcleo (C3, S2, H2) — ambos hilos comparten un único núcleo. La pila WiFi bloquea regularmente la CPU durante 1–5 ms para procesar paquetes. Durante ese tiempo, la ISR del dimmer pierde su ventana de timing → la lámpara parpadea.
Las interrupciones DMA WiFi tienen una prioridad de hardware alta fija en ESP-IDF —
no son interrumpidas por ISR IRAM_ATTR de nivel de usuario en un solo núcleo.
portDISABLE_INTERRUPTS() tampoco ayuda: el DMA WiFi se ejecuta a nivel NMI.
Esto no se puede resolver por software.
Soluciones
🟢 Para todos: DimmerLink — solución por hardware
La única solución fiable para ESP32 de un solo núcleo con WiFi. DimmerLink detecta el cruce por cero y controla el TRIAC por sí mismo — tu MCU solo envía el nivel de brillo por I2C.
Cualquier ESP32 has its own controller. Your ESP32-C3 only sets the brightness — no ISR, no timing-critical code on the MCU side.
Cableado para ESP32-C3:
- VCC → 3.3V
- GND → GND
- SDA → GPIO 8 (SDA por defecto en ESP32-C3)
- SCL → GPIO 9 (SCL por defecto en ESP32-C3)
⚠️ En algunos módulos ESP32-C3 los GPIO 8/9 son usados por la flash externa. Si
Wire.begin()no funciona — especifica los pines explícitamente:Wire.begin(SDA_PIN, SCL_PIN)con GPIOs libres (ej. 1, 10).
Cableado para ESP32-S2:
- SDA → GPIO 3 (verifica el diagrama de pines de tu placa)
- SCL → GPIO 4
Código (igual para todas las plataformas):
// DimmerLink en ESP32-C3 / S2 / H2 — sin ISR en el MCU
// Operación estable con WiFi activo
#include <Wire.h>
#define DIMMER_ADDR 0x50
#define REG_LEVEL 0x10
void setLevel(uint8_t level) { // level: 0–100%
Wire.beginTransmission(DIMMER_ADDR);
Wire.write(REG_LEVEL);
Wire.write(level);
Wire.endTransmission();
}
void setup() {
Wire.begin(); // SDA/SCL por defecto para tu placa
setLevel(50); // brillo 50%
}
void loop() {
// WiFi se puede usar libremente — el dimmer no se ve afectado
}Resultado: Operación estable con WiFi/BLE en cualquier ESP32 de un solo núcleo.
🔵 ¿Quieres ISR directa? — cambia a un ESP32 de doble núcleo
¿Necesitas la arquitectura ISR directa? Usa el ESP32 original o el S3.
El ESP32 original y el ESP32-S3 son de doble núcleo, rbdimmerESP32 funciona normalmente:
// ESP32 original / ESP32-S3 — doble núcleo
// rbdimmerESP32 funciona según lo previsto
#include "rbdimmerESP32.h"
#define ZC_PIN 18
#define DIM_PIN 19
rbdimmer dimmer;
void setup() {
Serial.begin(115200);
dimmer.begin(ZC_PIN, DIM_PIN, 50); // ZC_PIN, DIM_PIN, 50 Hz
dimmer.setPower(50);
}
void loop() {}Cuándo elegir cambiar el chip:
the project
⚠️ Errores comunes
-
«Funciona sin WiFi en C3, parpadea con WiFi»: Síntoma clásico de conflicto ISR en un solo núcleo. Comportamiento bien documentado. Solución: DimmerLink.
-
«
rbdimmerESP32compiló en C3 — debería funcionar»: Compila porque el núcleo 0 existe incluso en chips de un solo núcleo.xTaskCreatePinnedToCore(..., 0)creará la tarea, pero sin aislamiento del WiFi. El timing es inestable — eso no es «funcionar». -
«Uso ESPHome / Tasmota en ESP32-C3 — el dimmer no funciona»: ESPHome y Tasmota en ESP32 de un solo núcleo tienen las mismas limitaciones que el código personalizado. La pila WiFi compite con la ISR del dimmer. Usa DimmerLink con ESPHome vía I2C (
i2c:+sensor:o uncustom_component). -
«ESP32-S3 también tiene S — ¿es de un solo núcleo también?»: No. ESP32-S3 es de doble núcleo (como el ESP32 original, solo que LX7). Se confunde con ESP32-S2. Verifica el marcado del chip en tu placa.
-
«Uso FreeRTOS manualmente y puedo fijar tareas yo mismo»: En un solo núcleo,
xTaskCreatePinnedToCore(..., 0)crea la tarea, pero la pila WiFi también está en el núcleo 0. CualquiervTaskDelay(1)en la tarea del dimmer cede la CPU al WiFi — el timing se rompe. Y las interrupciones DMA WiFi tienen prioridad de hardware superior a las ISR de usuario. Esto no se puede resolver por software. DimmerLink es la única solución fiable. -
"I'm using FreeRTOS manually and can pin tasks myself": On single-core
xTaskCreatePinnedToCore(..., 0)creates the task, but the WiFi stack is also on Core 0. AnyvTaskDelay(1)in the dimmer task yields the CPU to WiFi — timing breaks. And WiFi DMA interrupts have a hardware priority above user ISR. This can't be solved in software. DimmerLink is the only reliable solution.
Verificación rápida
Problemas relacionados
- ESP32 + TRIAC: Guru Meditation Error →
troubleshooting/esp32-iram-attr.md - Cruce por cero no detectado →
troubleshooting/zero-cross-detection-errors.md - Zero-cross not detected →
troubleshooting/zero-cross-detection-errors.md
¿Todavía tienes preguntas?
Ask on forum.rbdimmer.com or open a GitHub Issue.