L’ESP32 dispose de 16 Ko de SRAM appelée mémoire rapide RTC qui permet de stocker des données même lorsque le processeur est mis en veille. Les données enregistrées dans la mémoire RTC ne sont pas effacées pendant le sommeil profond (deep-sleep). Elles persistent jusqu’à ce que l’on appuie sur le bouton de réinitialisation (ou l’entrée EN de la carte ESP32).
Sommaire
C’est quoi la mémoire RTC ?
La mémoire RTC (Real Time Clock) est une zone de la SRAM du processeur qui reste alimentée et accessible aux fonctions RTC du micro-contrôleur ESP32 et du coprocesseur ULP même lorsque la veille est activée.
En effet, même en veille (sauf en hibernation), certaines fonctionnalités du processeur continuent à être exécutées à intervalle régulier et permettent de déclencher des événements ou des traitements.
La taille et la répartition de la mémoire RTC varie en fonction de la version du processeur ESP32.
A partir de la version 4 du kit de développement ESP32-DevKitC, on dispose de 16 Ko de mémoire RTC. Pour les versions antérieures, la mémoire RTC était partagée ainsi : 8 Ko pour le processeur (et donc par le code Arduino) et 8 Ko utilisable par le coprocesseur ULP.
Voici un tableau comparatif établi à partir des documentations officielles d’Espressif.
ESP32-DevKitC v4 | ESP32-DevKitC, toutes versions antérieures |
16 Ko SRAM réservée |
|
Architectures :
ESP32-D0WD-V3 • ESP32-D0WDQ6-V3 • ESP32-D0WD • ESP32-D0WDQ6 • ESP32-D2WD • ESP32-S0WD • ESP32-U4WDH |
Architecture :
ESP32-D0WDQ6 |
Documentation technique | Documentation technique |
La question que l’on peut se poser est “quelle est le nombre de mesures que l’on peut stocker avec si peu d’espace”.
Si on prend ce tableau, un entier long nécessite un espace mémoire de 8 octets que l’on va arrondir à 10 octets pour avoir un ordre de grandeur réaliste, ce qui donne :
- Avec 16 Ko (16384 octets), on pourra stocker plus de 1600 enregistrements.
- Avec 8 Ko (8192 octets), on pourra stocker plus de 800 enregistrements.
Finalement, c’est déjà énorme !
Les modes de veille compatibles
La mémoire RTC est utilisable dans tous les modes d’alimentation à l’exception du mode Hibernation.
Active | Modem-Sleep | Light-Sleep | Deep-Sleep | Hibernation |
✓ | ✓ | ✓ | ✓ | ✕ |
Que peut-on stocker dans la mémoire RTC ?
Tous les types de variables C++ peuvent être stockés dans la mémoire RTC, y compris les structures comme nous allons le voir dans l’exemple.
Comment utiliser la mémoire RTC ?
Il n’y a quasiment rien à faire au niveau du programme. La seule chose est d’ajouter RTC_DATA_ATTR
devant la déclaration la variable que l’on souhaite placer dans la mémoire RTC.
Par exemple ici, on enregistrera le nombre de démarrage (réveil) de l’ESP32.
RTC_DATA_ATTR int recordCounter = 0;
Comme la variable est directement stockée dans la mémoire RTC, la valeur est automatiquement actualisée sans qu’il y ait besoin d’appeler une méthode particulière. Ici par exemple, on incrémente la valeur du compteur.
recordCounter++;
Le fonctionnement est beaucoup plus simple que l’EEPROM
Limitations
Il y a malheureusement une limitation à connaître avant de se lancer, la mémoire RTC est volatile, c’est à dire que les données sont effacée en cas de coupure d’alimentation ou après un Reset de la carte.
Il faudra donc utiliser cette approche pour un stockage temporaire de données non essentielles.
Un exemple de code Arduino à téléverser
Créer un nouveau croquis et coller le code ci-dessous. Si vous utilisez l’IDE Arduino, retirer la première ligne #include nécessaire pour compiler avec PlatformIO.
#include
#include
#include
RTC_DATA_ATTR int recordCounter = 0;
typedef struct {
float Temp;
float Pressure;
} bmp180Records;
#define maxRecords 5 // Nombre max enregistrements
#define sleepTime 10 // Every 10-mins of sleep 10 x 60-secs
RTC_DATA_ATTR bmp180Records Records[maxRecords];
Adafruit_BMP085 bmp;
#define LED_PIN 32
#define LED_DELAY 500 // Allume la LED 500ms pour informer que ESP32 vient de faire un enregistrement
#define I2C_SDA 19 // Broche I2C SDA
#define I2C_SCL 22 // Broche I2C SCL
void setup() {
Serial.begin(115200);
pinMode(LED_PIN, OUTPUT);
Wire.begin(I2C_SDA, I2C_SCL);
bool status = bmp.begin();
if ( status ) {
Serial.println("Record new values");
digitalWrite (LED_PIN, HIGH);
Records[recordCounter].Temp = bmp.readTemperature(); // Units °C
Records[recordCounter].Pressure = bmp.readPressure() / 100.0F; // Units hPa
recordCounter++;
delay(LED_DELAY);
if ( recordCounter == 1 ) {
Serial.println(String(recordCounter) + " record is stored in RTC memory");
} else {
Serial.println(String(recordCounter) + " records are stored in RTC memory");
}
if (recordCounter >= maxRecords) {
for (int i = 0; i < maxRecords; i++){
// Display records in CSV format to the serial port
Serial.println(String(i)+","+String(Records[i].Temp)+","+String(Records[i].Pressure));
}
recordCounter = 0;
}
} else {
// Verifier la connexion I2C du BMP190 / BME280
Serial.println("Sorry but BMP180 did not respond !");
}
// Reveil regulierement le processeur de l ESP32 pour faire une nouvelle mesure
esp_sleep_enable_timer_wakeup(sleepTime * 1000000);
esp_deep_sleep_start();
}
void loop() {
}
Fichier de configuration platformio.ini pour une carte de développement LoLin D32.
[env:lolin_d32]
platform = espressif32
board = lolin_d32
framework = arduino
monitor_speed = 115200
lib_deps =
525
Circuit
Nous allons utiliser un BMP180 (ou un BME280 pour avoir le taux d’humidité relative) pour collecter des mesures (températures, pression atmosphérique…) via le bus I2C. Ici, la broche SDA du BMP180 est connecté sur la broche 22, la broche SCL sur l’entrée 19. Une LED connectée sur la broche 34 sera allumée durant 500ms chaque fois que l’ESP32 se réveille et enregistre une nouvelle mesure.
Comment fonctionne le code du projet ?
On va tout d’abord créer une structure destinée à recevoir les mesures du BMP180
typedef struct {
float Temp;
float Pressure;
} bmp180Records;
Puis on réserve un espace mémoire sous la forme d’un tableau dont la taille est définie par la variable maxRecords.
En faisant précédé la déclaration du tableau par RTC_DATA_ATTR, on indique au compilateur que celui-ci sera stocké dans la mémoire RTC.
RTC_DATA_ATTR bmp180Records Records[maxRecords];
Les broches I2C (SDA et SCL) peuvent ne pas être exposées (disponibles) sur le connecteur GPIO. Heureusement, l’adaptation de la librairie Wire.h pour ESP32 permet d’attribuer manuellement les broches du bus I2C.
Wire.begin(I2C_SDA, I2C_SCL);
A chaque fois que le processeur se réveille, on enregistre les nouvelles mesures dans le tableau à la position du pointeur (recordCounter).
Records[recordCounter].Temp = bmp.readTemperature(); // Units °C
Records[recordCounter].Pressure = bmp.readPressure() / 100.0F; // Units hPa
Que l’on incrémente pour le prochain réveil
recordCounter++;
Comme la taille du tableau de données est fixée par la variable maxRecords, il convient de réinitialiser le compteur pour se positionner au début du tableau. On vient en quelques lignes de code créer un buffer tournant.
if (recordCounter >= maxRecords) {
...
recordCounter = 0;
}
Et après 5 enregistrements, on exporte au format CSV les données vers le port série.
5 records are stored in RTC memory
0,24.10,982.82
1,24.10,982.79
2,24.10,982.87
3,24.10,982.81
4,24.10,982.84
Mises à jour
11/09/2020 Publication de l’article
- ESP32, broches GPIO et fonctions associées. I/O, PWM, RTC, I2C, SPI, ADC, DAC
- M5Stack Atomic GPS. Tracker ESP32 TinyGPS++, export GPX sur carte SD, visualisation sur Google Maps ou VSCode
- Stocker des données sur une carte micro SD. Code Arduino compatible ESP32, ESP8266
- Débuter Arduino. Recevoir des commandes depuis le port série (compatible ESP32 ESP8266)
- Fonctions C++ print•println•printf•sprintf pour Arduino ESP32 ESP8266. Combiner•formater → port série
Avez-vous aimé cet article ?