Ir al contenido

ESP32-S2/C3/H2: el dimmer AC no funciona en ESP32 de un solo núcleo

ESP32-C3/S2/H2 son de un solo núcleo — rbdimmerESP32 no puede aislar la tarea del dimmer del WiFi. Las interrupciones DMA WiFi se ejecutan a nivel NMI y alteran el timing del TRIAC a nivel de hardware. DimmerLink por I2C es la única solución fiable.

Resumen: rbdimmerESP32 está 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 inestablesetPower(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):

cpp
// 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:

cpp
// 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:

  • ☐ Ya tienes código con conexión ZC/DIM directa
  • ☐ Necesitas controlar múltiples canales simultáneamente
  • ☐ La diferencia de precio entre ESP32 y ESP32-C3 no es significativa para el proyecto
  • 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.

    • «rbdimmerESP32 compiló 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 un custom_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. Cualquier vTaskDelay(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. Any vTaskDelay(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

  • ☐ ESP32-C3/S2/H2/C6 — un solo núcleo → DimmerLink
  • ☐ ESP32 (sin sufijo) / S3 — doble núcleo → `rbdimmerESP32` funciona
  • ☐ ¿Funciona sin WiFi, falla con WiFi? → Conflicto ISR de un solo núcleo
  • ☐ DimmerLink: ¿pines SDA/SCL correctos para tu chip?
  • ☐ DimmerLink: correct SDA/SCL pins for your chip?


  • Problemas relacionados

    • ESP32 + TRIAC: Guru Meditation Errortroubleshooting/esp32-iram-attr.md
    • Cruce por cero no detectadotroubleshooting/zero-cross-detection-errors.md
    • Zero-cross not detectedtroubleshooting/zero-cross-detection-errors.md



    ¿Todavía tienes preguntas?

    Ask on forum.rbdimmer.com or open a GitHub Issue.

    Compartir esta publicación
    Iniciar sesión para dejar un comentario