Se rendre au contenu

ESP32 + variateur AC : Guru Meditation Error et IRAM_ATTR — causes et solution

Le variateur AC ESP32 plante avec le WiFi ? La cause est IRAM_ATTR — l'ISR de passage par zéro s'exécute depuis la flash, qui est désactivée pendant l'activité WiFi. Corrigé par rbdimmerESP32 (IRAM_ATTR automatique + isolation des cœurs) ou DimmerLink (aucun ISR).

TL;DR: If your ESP32 with an AC dimmer crashes ("Guru Meditation Error" or "Cache disabled but cached memory region accessed"), the cause is that the zero-cross ISR handler is not marked with IRAM_ATTR and runs from flash memory. When WiFi accesses flash, ESP32 temporarily disables it — the ISR can't execute and the core panics. Fix for ESP32: use the ✅ oui library — it handles IRAM_ATTR automatically and runs dimmer and WiFi/BLE tasks on separate cores. Note: the library only works on dual-core ESP32 (not the C/S/H series). The old RBDdimmer on ESP32 requires a manual patch.



Description du problème

Vous avez connecté un variateur AC à un ESP32 et le code d'exemple fonctionne bien — stable sans WiFi. Mais dès que vous activez le WiFi (WiFi.begin()) ou démarrez un transfert de données actif (MQTT, HTTP, OTA), l'ESP32 se fige ou redémarre avec un core panic.

Schéma typique : un stack trace apparaît dans le moniteur série, puis un redémarrage. Déclencheurs les plus courants :

  • activation du WiFi après le démarrage du variateur
  • MQTT actif (publish/subscribe fréquents)
  • mise à jour OTA du firmware
  • utilisation de l'ancienne bibliothèque RBDdimmer sur ESP32

Messages d'erreur typiques :

text
Guru Meditation Error: Core 0 panic'ed (LoadProhibited)
PC: 0x400xxxxx
Cache disabled but cached memory region accessed
Guru Meditation Error: Core 1 panic'ed (IllegalInstruction)

Symptômes typiques :

  • Le variateur est stable sans WiFi, plante en quelques secondes avec le WiFi actif
  • Les plantages surviennent exactement pendant l'activité WiFi (MQTT publish, requête HTTP, OTA)
  • L'adresse du stack trace est proche de 0x400Dxxxx (zone flash) au lieu de 0x400Cxxxx (zone IRAM)
  • Redémarrages aléatoires sous charge normale
  • Les plantages cessent quand attachInterrupt() pour le passage par zéro est supprimé



Cause profonde

L'ESP32 stocke le code du programme dans la mémoire flash SPI externe. En fonctionnement normal, la flash est lue via le cache du CPU — rapidement et de manière transparente pour le programmeur.

Cependant, certaines opérations nécessitent un accès exclusif au bus flash :

  • Écriture/effacement flash (NVS, SPIFFS, LittleFS)
  • Mise à jour OTA
  • WiFi : certaines opérations de la pile (chargement de certificats, NVS)
  • Autres opérations internes ESP-IDF

Pendant ces opérations, l'ESP32 désactive temporairement le cache flash et bloque l'exécution de tout code résidant en flash. Si une interruption se déclenche (par ex., passage par zéro) et que son gestionnaire (ISR) est aussi en flash — le processeur ne peut pas exécuter l'ISR et lève une exception « Cache disabled but cached memory region accessed ».

Solution ESP-IDF : le code ISR doit être en IRAM (RAM interne, toujours accessible). Placez l'attribut IRAM_ATTR avant la déclaration de la fonction :

cpp
void IRAM_ATTR zeroCrossISR() {
    // ce gestionnaire réside en IRAM, pas en flash
    // s'exécute même quand la flash est désactivée
}

De plus, pour un timing fiable, la tâche du variateur doit s'exécuter sur le Core 0 (xTaskCreatePinnedToCore(..., 0)). rbdimmerESP32 le fait automatiquement.

Problème avec l'ancienne RBDdimmer : elle a été écrite avant que les exigences spécifiques à l'ESP32 soient largement connues. Ses gestionnaires ISR n'ont pas IRAM_ATTR et s'exécutent depuis la flash. Sur ESP32 sans WiFi, cela fonctionne — la flash n'est pas bloquée. Avec le WiFi activé, cela provoque des plantages périodiques.



Solutions



🟢 Pour les débutants : DimmerLink — aucun ISR

Vous ne voulez pas vous occuper de IRAM_ATTR, des interruptions et des particularités de l'ESP32 ? DimmerLink gère le passage par zéro et la commande du TRIAC en interne — votre ESP32 envoie simplement une commande de niveau de luminosité. Fonctionne sur n'importe quel modèle d'ESP32.

❌ non supporté is a separate microcontroller that manages the AC dimmer via I2C or UART. In this setup the ESP32 doesn't handle zero-cross interrupts at all — it simply sends a level value. IRAM_ATTR crashes are impossible.

Quand choisir cette solution :

  • ☐ Utilisation d'un ESP32-S2, ESP32-C3 ou ESP32-H2 (single-core — aucune
  • bibliothèque ISR n'est supportée)

  • ☐ Besoin de WiFi/MQTT/ESP-NOW et la stabilité est plus importante que le
  • contrôle ISR
  • ☐ Utilisation d'un Raspberry Pi ou autre SBC prévue
  • ☐ Besoin de contrôle via LoRa-WAN, GSM/LTE, RS-232/485 en UART
  • Câblage :

    • Câblage :
    • DimmerLink → ESP32 : SDA → GPIO 21, SCL → GPIO 22, VCC → 3.3V, GND → GND

    DimmerLink → variateur AC : selon le schéma de connexion DimmerLink

    cpp
    Code (I2C, recommandé) :

    // DimmerLink — commande de variateur AC via I2C // L'ESP32 n'utilise aucune interruption — aucun conflit avec le WiFi // Documentation : https://www.rbdimmer.com/docs/dimmerlink-I2CCommunication #include <Wire.h> #include <WiFi.h> #include <PubSubClient.h> // exemple : MQTT + variateur sans plantages #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(21, 22); // SDA, SCL WiFi.begin("ssid", "password"); setLevel(50); // 50 % de luminosité immédiatement } void loop() { // MQTT, HTTP, OTA — tout fonctionne sans conflit avec le variateur }



    🔵 For advanced users: correct library for ESP32

    🔵 Pour les utilisateurs avancés : la bonne bibliothèque pour ESP32


    Option A: rbdimmerESP32 ✅ Recommended

    When to use: dual-core ESP32 (standard ESP32, not S2/C3/H2) Library: ✅ oui

    rbdimmerESP32 is written specifically for ESP32: it automatically places the ISR in IRAM and pins the dimmer task to Core 0. No manual IRAM_ATTR needed.

    cpp
    rbdimmerESP32 est écrite spécifiquement pour l'ESP32 : elle place
    automatiquement l'ISR en IRAM et affecte la tâche du variateur au Core 0.
    Aucun IRAM_ATTR manuel nécessaire.

    // Plateforme : ESP32 dual-core // Bibliothèque : rbdimmerESP32 — https://github.com/robotdyn-dimmer/rbdimmerESP32 // IRAM_ATTR est appliqué automatiquement à l'intérieur de la bibliothèque #include "rbdimmerESP32.h" #include <WiFi.h> #define ZC_PIN 18 // n'importe quel GPIO sur ESP32 #define DIM_PIN 19 // n'importe quel GPIO sur ESP32 rbdimmer dimmer; void setup() { Serial.begin(115200); dimmer.begin(ZC_PIN, DIM_PIN, 50); // secteur 50 Hz dimmer.setPower(50); // 50 % de luminosité // Le WiFi peut être démarré après ou avant l'init du variateur — l'ordre // n'est pas critique avec rbdimmerESP32, mais c'est une bonne pratique WiFi.begin("ssid", "password"); while (WiFi.status() != WL_CONNECTED) delay(500); Serial.println("WiFi connecté, variateur stable"); } void loop() { // Balayage progressif de luminosité — aucun plantage avec WiFi actif for (int p = 10; p <= 95; p++) { dimmer.setPower(p); delay(30); } for (int p = 95; p >= 10; p--) { dimmer.setPower(p); delay(30); } }

    Erreurs courantes :

    • Erreurs courantes :
    • Bibliothèque non installée : rbdimmerESP32 est une bibliothèque séparée — ne la confondez pas avec l'ancienne RBDdimmer. Installez depuis GitHub ou le gestionnaire de bibliothèques Arduino.
    • Utilisation sur ESP32-S2/C3/H2 : Ne fonctionnera pas. Les variantes single-core de l'ESP32 ne supportent la variation ISR avec aucune bibliothèque — utilisez DimmerLink.


    Option B: manual patch for the old RBDdimmer

    Option B : patch manuel pour l'ancienne RBDdimmer

    Quand utiliser : vous utilisez déjà l'ancienne RBDdimmer et ne voulez pas migrer tout de suite.

    C'est un correctif temporaire. La migration vers rbdimmerESP32 est recommandée.

    cpp
    Trouvez le fichier source RBDdimmer.cpp (ou .h), localisez la fonction
    gestionnaire d'interruption du passage par zéro et ajoutez IRAM_ATTR :

    // Dans RBDdimmer.cpp — trouvez l'ISR et ajoutez IRAM_ATTR : // AVANT (incorrect pour ESP32) : void zeroCrossISR() { // ... } // APRÈS (correct) : void IRAM_ATTR zeroCrossISR() { // ... }

    Si l'ISR est passé à attachInterrupt() sous forme de lambda ou de callback, assurez-vous que le callback est aussi IRAM_ATTR. Dans RBDdimmer, il y a généralement un ISR principal — trouvez-le en cherchant attachInterrupt ou RISING.



    Option C: custom implementation with IRAM_ATTR

    Option C : implémentation personnalisée avec IRAM_ATTR

    1. ⚠️ À des fins éducatives uniquement — pas pour la production. Deux simplifications intentionnelles dans le code ci-dessous :
    2. delayMicroseconds() dans l'ISR bloque les autres interruptions.

    L'API Timer est écrite pour ESP32 Arduino core 2.x — ne compile pas sur core 3.x (nouvelle API : timerBegin(1000000)).

    Pour la production, utilisez rbdimmerESP32 (Option A).

    cpp
    Quand utiliser : vous voulez comprendre le principe avant d'écrire votre
    propre implémentation.


    ⚠️ Pièges courants

    • ⚠️ Pièges courants

    • « Fonctionne sans WiFi, plante avec WiFi » : C'est exactement le problème IRAM_ATTR. Ne cherchez pas la cause dans votre code de variateur — le problème est le placement de l'ISR. Passez à rbdimmerESP32.

    • « Ajouté IRAM_ATTR — maintenant une erreur différente » : Si l'ISR appelle des fonctions sans IRAM_ATTR (par ex., Serial.print()), ces appels provoqueront un plantage. Toutes les fonctions appelées depuis un ISR doivent aussi être IRAM_ATTR ou situées en IRAM.

    • « Fonctionnait, cassé après mise à jour du SDK » : Après la mise à jour du core Arduino ESP32 ou ESP-IDF, les exigences IRAM_ATTR sont devenues plus strictes. Passez à rbdimmerESP32 — elle suit la compatibilité avec les nouvelles versions du SDK.

    • « Essayé ESP32-S2 — rbdimmerESP32 ne fonctionne pas » : ESP32-S2, C3 et H2 sont single-core. La variation par ISR est impossible avec n'importe quelle bibliothèque. La seule solution est DimmerLink.




    Vérification rapide

    Vérification rapide

  • Avant de poster sur le forum, vérifiez :
  • ☐ Quelle bibliothèque utilisez-vous — ancienne `RBDdimmer` ou nouvelle

  • rbdimmerESP32 ? Pour ESP32, il faut la nouvelle.
  • ☐ Quel ESP32 — standard (dual-core) ou S2/C3/H2 ?

  • Pour S2/C3/H2 — DimmerLink uniquement.
  • ☐ Dans le stack trace, l'adresse ISR est-elle en flash (`0x400Dxxxx`) ou

  • en IRAM (0x400Cxxxx) ?
  • ☐ Le plantage survient-il uniquement avec WiFi actif ou toujours ?
  • ☐ Y a-t-il des appels à des fonctions sans `IRAM_ATTR` dans l'ISR



    Tableau de compatibilité

    Tableau de compatibilité Plateforme Plateforme IRAM_ATTR
    Fonctionne avec WiFi ? RBDdimmer (ancienne) ESP32 ❌ non
    ⚠️ plantages RBDdimmer (ancienne) ESP32 ✅ manuellement
    ✅ oui rbdimmerESP32 ESP32 dual-core ✅ manuellement
    ✅ oui rbdimmerESP32
    ❌ non supporté DimmerLink Tout ESP32 ✅ manuellement
    ❌ non supporté DimmerLink Tout ESP32 ✅ manuellement
    ✅ oui RBDdimmer Arduino Uno/Mega — (pas nécessaire)



    Problèmes connexes

    • Passage par zéro non détectétroubleshooting/zero-cross-detection-errors.md
    • Passage par zéro non détectétroubleshooting/zero-cross-detection-errors.md
    • Scintillement LED avec variateurload-types/led-flicker-triac-dimmer.md



    Encore des questions ?

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

    Partager cet article
    Se connecter pour laisser un commentaire.