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_ATTRand 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 handlesIRAM_ATTRautomatically 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 oldRBDdimmeron 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
RBDdimmersur ESP32
Messages d'erreur typiques :
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 de0x400Cxxxx(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 :
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 :
bibliothèque ISR n'est supportée)
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
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.
rbdimmerESP32est écrite spécifiquement pour l'ESP32 : elle place automatiquement l'ISR en IRAM et affecte la tâche du variateur au Core 0. AucunIRAM_ATTRmanuel 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 :
rbdimmerESP32est une bibliothèque séparée — ne la confondez pas avec l'ancienneRBDdimmer. 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.
Trouvez le fichier sourceRBDdimmer.cpp(ou.h), localisez la fonction gestionnaire d'interruption du passage par zéro et ajoutezIRAM_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
- ⚠️ À des fins éducatives uniquement — pas pour la production. Deux simplifications intentionnelles dans le code ci-dessous :
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).
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 êtreIRAM_ATTRou 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
☐ 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 ?
☐ Dans le stack trace, l'adresse ISR est-elle en flash (`0x400Dxxxx`) ou
0x400Cxxxx) ?☐ 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 variateur →
load-types/led-flicker-triac-dimmer.md
Encore des questions ?
Ask on forum.rbdimmer.com or open a GitHub Issue.