Bienvenue dans ce tutoriel dédié à l’ESP32 et à la gestion de sa mémoire avec l’IDE Arduino ! Les partitions permettent d’organiser efficacement la mémoire flash de l’ESP32. Une configuration adaptée permet d’organiser la mémoire flash afin de tirer pleinement parti des capacités de l’ESP32.
Pourquoi est-ce important ? Que vous souhaitiez stocker des fichiers (comme des pages web pour un serveur embarqué), mettre à jour votre firmware à distance (OTA), ou simplement sauvegarder des paramètres (comme les identifiants Wi-Fi), comprendre les schémas de partition est essentiel. Sans une configuration adaptée, vous risquez de manquer d’espace, de ne pas pouvoir utiliser certaines fonctionnalités, ou même de corrompre votre mémoire.
Avant de plonger dans les schémas de partition, commençons par un rappel sur les différentes mémoires utilisées par un microcontrôleur. Cela vous permettra de mieux comprendre où et comment vos données sont stockées, et surtout, comment optimiser l’utilisation de l’espace disponible.
Les bases : Comprendre les mémoires d’un microcontrôleur avec l’exemple de l’Arduino Uno
L’arduino UNO R3 est basé sur le microcontrôleur ATMEGA 328P, équipé des mémoires suivantes selon la documentation de ce microcontrôleur :
- 32 ko de mémoire FLASH
- 1 ko de mémoire EEPROM
- 2 ko de mémoire SRAM

Il n’y a pas de schéma de partition configurable dans l’IDE Arduino pour l’Arduino UNO R3. En effet, son microcontrôleur utilise une mémoire flash fixe de 32 Ko, sans système de fichiers ni support OTA natif. Mais commençons par comprendre les différents types de mémoire utilisées par les microcontrôleurs :
- EEPROM : mémoire non volatile qui conserve les données même sans alimentation. Ce type de mémoire de petite capacité est optimisée pour des écritures fréquentes (100.000 cycles).
- FLASH : comme la mémoire EEPROM, la mémoire FLASH est non volatile et conserve les données même sans alimentation. Ce type de mémoire a généralement une plus grande capacité, mais permet moins de cycles d’écriture (10.000 cycles).
- SRAM : mémoire volatile ultra-rapide qui s’efface dès coupure alimentation.

Prenons par exemple le programme suivant, et expliquons l’utilisation de la mémoire :
// Exemple illustrant l'utilisation des differentes memoires
// d'un Arduino UNO R3
//
// https://tutoduino.fr/
char* pointeur = NULL; // le compilateur reserve 2 octets en SRAM pour stocker ce pointeur
void setup() {
Serial.begin(115200);
pointeur = (char*)malloc(200 * sizeof(char)); // allocation dynamique de 200 octets en SRAM
if (pointeur == NULL) {
Serial.println("Erreur d'allocation mémoire!");
} else {
free(pointeur);
pointeur = NULL;
}
}
void loop() {
delay(1000);
}Une fois compilé, le programme occupe 2264 octets de Flash. Les variables globales utilisent 228 octets de SRAM, laissant 1820 octets de disponibles sur les 2 ko de mémoire SRAM totale.
Sketch uses 2264 bytes (7%) of program storage space. Maximum is 32256 bytes.
Global variables use 228 bytes (11%) of dynamic memory, leaving 1820 bytes for local variables. Maximum is 2048 bytes.Note : Sur les 32 768 octets (32 ko) de Flash, 512 octets sont réservés au bootloader Arduino, laissant 32256 octets maximum pour le programme utilisateur.
Si le programme essaie d’allouer plus de mémoire que disponible en SRAM, l’allocation va échouer. Exemple ici avec une tentative d’allocation de 1900 octets :

La mémoire du XIAO ESP32-C5
Le module XIAO ESP32-C5 est basé sur le micro-contrôleur ESP32-C5 équipé d’une SRAM externe de 8 Mo ainsi que d’une FLASH externe de 8 Mo.
Le micro-contrôleur ESP32-C5 possède la mémoire interne suivante :
- 384 ko de SRAM haute performance (HP), utilisée par le cœur haute performance (HP core), qui fonctionne à une fréquence élevée (240 MHz).
- 16 ko de SRAM basse consommation (LP), associée au cœur basse consommation (LP core), qui fonctionne à une fréquence beaucoup plus basse (40 MHz).
- 320 ko de ROM, mémoire immuable en lecture seule, dédiée aux fonctions de base et au démarrage du système.
Le schéma de partition de l’IDE Arduino
Le menu Partition Scheme de l’IDE Arduino permet de définir comment doit être utilisée la mémoire FLASH externe des microcontrôleurs ESP32.

Pour bien choisir un schéma de partition sur un ESP32, il est essentiel de comprendre les acronymes et les rôles de chaque section de la mémoire flash :
- SPIFFS (Serial Peripheral Interface Flash File System) est un système de fichiers qui permet de créer, lire, modifier et supprimer des fichiers directement dans la mémoire flash. Ce système de fichiers gère l’usure, la fragmentation et la persistance des données, spécifique à la technologie flash. Ce système ne permet pas d’organiser les fichiers en dossiers (tous les fichiers sont à la racine).
- FATFS est un système de fichiers est une implémentation légère du système de fichiers FAT (File Allocation Table) conçue pour les systèmes embarqués. Permet d’organiser les fichiers en dossiers et sous-dossiers et permet de gérer des fichiers et des partitions bien plus grandes que SPIFFS.
- APP (Application) est la partition dédiée au stockage du firmware (programme compilé) de l’ESP32. La partition APP peut être divisée en plusieurs partitions (ex : app0, app1) pour permettre des mises à jour du firmware à distance (OTA). La partition app0 contient le firmware principal (version actuelle ou précédente) alors que la partition app1 contient une seconde copie du firmware. Pendant qu’une nouvelle version est téléchargée dans app1, app0 continue de fonctionner. Après la mise à jour, l’ESP32 redémarre sur app1.
- OTA (Over-The-Air) est la partition qui stocke les métadonnées pour les mises à jour OTA, comme l’état de la dernière mise à jour ou la partition active (app0 ou app1).
Les schémas de partition sont stockés dans le répertoire d’installation du core ESP32 pour Arduino. Par exemple sous Linux :
~/.arduino15/packages/esp32/hardware/esp32/3.3.6/tools/partitionsVoici un exemple des schémas de partitions disponibles pour la version 3.3.6 du core ESP32.

Ces fichiers au format CSV contiennent la définition des partitions :
- Name : Identifiant de la partition (ex : app0, spiffs).
- Type : Type de partition (app, data).
- SybType : Sous-type (ota_0, ota_1, spiffs, fatfs, etc.).
- Offset : Offset en hexadécimal dans la mémoire flash.
- Size : Taille de la partition en hexadécimal.
- Flags : Options supplémentaires (ex : encrypted).
Voici par exemple le contenu du fichier default_8MB.csv

L’IDE Arduino utilise le fichier de partition (.csv) sélectionné pour générer une table de partition binaire, intégrée au firmware. Cette table est écrite dans la mémoire flash de l’ESP32, à l’adresse 0x8000, lors du téléversement. Le bootloader de l’ESP32 lit cette table lors de son exécution pour savoir où se trouvent les partitions (APP, SPIFFS, OTA, etc.).
Je vous recommande la lecture de la documentation dédiée au tables de partition sur le site Espressif : https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-guides/partition-tables.html
Exemple de problème lié aux schémas de partition
Vous souhaitez développer un projet de lampe connectée basée sur un ESP32-C5, vous allez exploiter les capacités de ce microcontrôleur pour créer un appareil compatible avec Home Assistant, en utilisant le protocole Matter sur Thread. Ce choix vous permet de concevoir un objet connecté sécurisé, interopérable et facilement intégrable dans un écosystème domotique existant. Je vous invite à lire mon tutoriel Intégrer un appareil Matter (Wi-Fi et Thread) dans Home Assistant.
Pour ce projet, vous partez de l’exemple MatterOnOffLight, fourni par Espressif. Cet exemple est spécialement conçu pour les applications de type “lampe connectée” et intègre la prise en charge du protocole Matter sur Thread, ce qui simplifie grandement l’intégration avec Home Assistant.
Essayons d’utiliser le schéma de partition Minimal pour ce programme :

Ce schéma de partition minimal.csv réserve une partition app0 de type app et de taille 0x140000 (1310720 octets) :
# Name, Type, SubType, Offset, Size, Flags
nvs, data, nvs, 0x9000, 0x5000,
otadata, data, ota, 0xe000, 0x2000,
app0, app, ota_0, 0x10000, 0x140000,
spiffs, data, spiffs, 0x150000, 0xA0000,
coredump, data, coredump,0x1F0000, 0x10000,Une erreur apparaît lors de la compilation du programme. En effet, le programme compilé occupe 2193968 octets, ce qui est supérieur à la taille de la partition app configurée par le schéma de partition Minimal sélectionné (1310720 octets) :
Le croquis utilise 2193968 octets (167%) de l'espace de stockage de programmes. Le maximum est de 1310720 octets.Le fichier README de cet exemple indique bien qu’il faut sélectionner le schéma de partition Huge APP (3MB No OTA/1MB SPIFFS).


La partition app0 de type app est en effet bien configurée avec une taille 0x300000 (3145728 octets) dans le schéma de partition huge_app.csv :
# Name, Type, SubType, Offset, Size, Flags
nvs, data, nvs, 0x9000, 0x5000,
otadata, data, ota, 0xe000, 0x2000,
app0, app, ota_0, 0x10000, 0x300000,
spiffs, data, spiffs, 0x310000,0xE0000,
coredump, data, coredump,0x3F0000,0x10000,Une fois compilé, le firmware occupe 2193976 octets de la mémoire flash. Ce qui est bien inférieur au maximum de 3145728 octets (3 Mo) réservé pour notre partition APP.
Le croquis utilise 2193976 octets (69%) de l'espace de stockage de programmes. Le maximum est de 3145728 octets.
Les variables globales utilisent 100740 octets (30%) de mémoire dynamique, ce qui laisse 226940 octets pour les variables locales. Le maximum est de 327680 octets.SRAM et PSRAM
Si la compilation du programme se déroule correctement avec le schéma de partition Huge APP (3MB No OTA/1MB SPIFFS), une erreur se produit lors de l’exécution de ce programme sur le module XIAO ESP32-C5 !
Le moniteur série de l’IDE Arduino affiche en effet un message indique un échec de la création du pool de mémoire tampon de messages :
E (1166) OPENTHREAD: Failed to create message buffer pool
assert failed: otPlatMessagePoolInit esp_openthread_messagepool.c:25 (false)En revenant sur le début de ce tutoriel, vous devriez vous souvenir qu’une allocation de mémoire dynamique se fait dans la SRAM. Et il se trouve que la SRAM interne du microcontrôleur ESP32-C5 est limitée à 384 ko. Et il semble bien que ce programme nécessite plus de mémoire SRAM.
C’est là qu’intervient la PSRAM de 8 Mo du module XIAO ESP32-C5. La PSRAM est une mémoire externe (connectée via SPI), conçue pour imiter la SRAM mais avec une technologie DRAM (Dynamic RAM). Mais cette PSRAM de 8 Mo n’est pas activée par défaut dans la configuration des ESP32 de l’IDE Arduino.

Dans l’IDE Arduino, la PSRAM n’est pas toujours automatiquement activée pour tous les modules ESP32, même si le matériel la supporte. Pour le XIAO ESP32-C5, il faut explicitement activer la PSRAM dans les paramètres de l’IDE.

