Passa al contenuto

ESP32-S2/C3/H2: il dimmer AC non funziona su ESP32 single-core

ESP32-C3/S2/H2 sono single-core — rbdimmerESP32 non può isolare il task del dimmer dal WiFi. Gli interrupt DMA WiFi operano a livello NMI e compromettono il timing del TRIAC a livello hardware. DimmerLink via I2C è l'unica soluzione affidabile.

In breve: rbdimmerESP32 è progettato per ESP32 dual-core (originale e S3). ESP32-S2, C3, C6 e H2 sono single-core. La libreria tenta di isolare il task del dimmer su un core dedicato — il che è impossibile sui chip single-core. La ISR compete con lo stack WiFi, il timing viene compromesso e il risultato è sfarfallio, anomalie casuali e luminosità instabile. La soluzione è DimmerLink (ZC hardware + I2C) o il passaggio a un chip dual-core.



Descrizione del problema

Hai acquistato un ESP32-C3 o ESP32-S2 — compatto, con WiFi/BLE, economico. Colleghi un dimmer AC direttamente, usi rbdimmerESP32 — e osservi:

  • Il carico sfarfalla a qualsiasi livello di luminosità
  • Il timing è instabilesetPower(50) dà il 30 % un istante, il 70 % l'istante dopo
  • Anomalie con WiFi attivo — funziona meglio senza WiFi, caos con il WiFi
  • Il codice compila senza errori, instabilità solo a runtime

Oppure il compilatore avvisa riguardo a xTaskCreatePinnedToCore con un core inesistente.

Messaggi tipici nei forum:

  • «ESP32-C3 + dimmer — sfarfallio a qualsiasi livello di potenza»
  • «rbdimmerESP32 funziona su ESP32 ma non su ESP32-S2»
  • «setPower(50) dà luminosità casuale su C3»
  • «Funziona senza WiFi, si blocca appena il WiFi si connette»



Causa profonda


Quali chip ESP32 sono dual-core e quali no

Chip Core Architettura Dimming ISR diretto
ESP32 (originale) 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 sull'ESP32-C6: il C6 ha un core LP aggiuntivo (Low Power), ma non è adatto al dimming ISR — opera a frequenza ridotta senza supporto completo di FreeRTOS. Il core principale è singolo.

⚠️ Confusione frequente: l'ESP32-S3 è dual-core (funziona). L'ESP32-S2 è single-core (non funziona con ISR diretta). Sono chip diversi.


Perché la dimmerizzazione con taglio di fase richiede l'isolamento dei core

Timing del gate TRIAC: dal passaggio per lo zero all'impulso del gate — un ritardo di 100–9000 µs, precisione ±10–20 µs. Qualsiasi ritardo significa luminosità errata.

rbdimmerESP32 raggiunge questa precisione su dual-core in questo modo:

  • Core 0 — task del dimmer (loop di timing, gestione ZC, attivazione TRIAC)
  • Core 1 — stack WiFi, TCP/IP, codice utente

Funzionano in parallelo e non si bloccano a vicenda.

Su single-core (C3, S2, H2) — entrambi i thread condividono un unico core. Lo stack WiFi blocca regolarmente la CPU per 1–5 ms per elaborare i pacchetti. Durante quel tempo la ISR del dimmer perde la sua finestra di timing → la lampada sfarfalla.

Gli interrupt DMA WiFi hanno una priorità hardware alta fissa in ESP-IDF — non vengono interrotti dalle ISR IRAM_ATTR a livello utente su single-core. portDISABLE_INTERRUPTS() non aiuta: il DMA WiFi opera a livello NMI. Questo non può essere risolto via software.



Soluzioni



🟢 Per tutti: DimmerLink — soluzione hardware

L'unica soluzione affidabile per ESP32 single-core con WiFi. DimmerLink rileva il passaggio per lo zero e controlla il TRIAC autonomamente — il tuo MCU invia solo il livello di luminosità via I2C.

DimmerLink has its own controller. Your ESP32-C3 only sets the brightness — no ISR, no timing-critical code on the MCU side.

Cablaggio per ESP32-C3:

  • VCC → 3.3V
  • GND → GND
  • SDA → GPIO 8 (SDA predefinito su ESP32-C3)
  • SCL → GPIO 9 (SCL predefinito su ESP32-C3)

⚠️ Su alcuni moduli ESP32-C3 i GPIO 8/9 sono utilizzati dalla flash esterna. Se Wire.begin() non funziona — specifica i pin esplicitamente: Wire.begin(SDA_PIN, SCL_PIN) con GPIO liberi (es. 1, 10).

Cablaggio per ESP32-S2:

  • SDA → GPIO 3 (verifica la piedinatura della tua scheda)
  • SCL → GPIO 4

Codice (identico per tutte le piattaforme):

cpp
// DimmerLink su ESP32-C3 / S2 / H2 — nessuna ISR sul MCU
// Funzionamento stabile con WiFi attivo
#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 predefiniti per la tua scheda
    setLevel(50);  // luminosità 50%
}
void loop() {
    // Il WiFi può essere usato liberamente — il dimmer non è influenzato
}

Risultato: Funzionamento stabile con WiFi/BLE su qualsiasi ESP32 single-core.



🔵 Vuoi la ISR diretta — passa a un ESP32 dual-core

Serve l'architettura ISR diretta? Usa l'ESP32 originale o l'S3.

L'ESP32 originale e l'ESP32-S3 sono dual-core, rbdimmerESP32 funziona normalmente:

cpp
// ESP32 originale / ESP32-S3 — dual-core
// rbdimmerESP32 funziona come 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() {}

Quando conviene cambiare chip:

  • ☐ Hai già codice con connessione ZC/DIM diretta
  • ☐ Devi controllare più canali contemporaneamente
  • ☐ La differenza di prezzo tra ESP32 ed ESP32-C3 non è significativa per il progetto
  • the project



    ⚠️ Errori comuni

    • «Funziona senza WiFi su C3, sfarfalla con WiFi»: Sintomo classico del conflitto ISR su single-core. Comportamento ben documentato. Soluzione: DimmerLink.

    • «rbdimmerESP32 compila su C3 — dovrebbe funzionare»: Compila perché il core 0 esiste anche sui chip single-core. xTaskCreatePinnedToCore(..., 0) creerà il task, ma senza isolamento dal WiFi. Il timing è instabile — questo non è «funzionare».

    • «Uso ESPHome / Tasmota su ESP32-C3 — il dimmer non funziona»: ESPHome e Tasmota su ESP32 single-core hanno le stesse limitazioni del codice personalizzato. Lo stack WiFi compete con la ISR del dimmer. Usa DimmerLink con ESPHome via I2C (i2c: + sensor: o un custom_component).

    • «Anche l'ESP32-S3 ha la S — è single-core anche quello?»: No. L'ESP32-S3 è dual-core (come l'ESP32 originale, solo LX7). Viene confuso con l'ESP32-S2. Controlla la marcatura del chip sulla tua scheda.

    • «Uso FreeRTOS manualmente e posso assegnare i task da solo»: Su single-core xTaskCreatePinnedToCore(..., 0) crea il task, ma lo stack WiFi è anch'esso sul core 0. Qualsiasi vTaskDelay(1) nel task del dimmer cede la CPU al WiFi — il timing si rompe. E gli interrupt DMA WiFi hanno una priorità hardware superiore alle ISR utente. Questo non si risolve via software. DimmerLink è l'unica soluzione affidabile.

    • "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.




    Controllo rapido

  • ☐ ESP32-C3/S2/H2/C6 — single-core → DimmerLink
  • ☐ ESP32 (senza suffisso) / S3 — dual-core → `rbdimmerESP32` funziona
  • ☐ Funziona senza WiFi, si blocca con WiFi? → Conflitto ISR single-core
  • ☐ DimmerLink: pin SDA/SCL corretti per il tuo chip?
  • ☐ DimmerLink: correct SDA/SCL pins for your chip?


  • Problemi correlati

    • ESP32 + TRIAC: Guru Meditation Errortroubleshooting/esp32-iram-attr.md
    • Passaggio per lo zero non rilevatotroubleshooting/zero-cross-detection-errors.md
    • Zero-cross not detectedtroubleshooting/zero-cross-detection-errors.md



    Hai ancora domande?

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

    Condividi articolo
    Accedi per lasciare un commento