ESP32forth et DEEPSLEEP

publication: 9 janvier 2025 / mis à jour 9 janvier 2025

Read this page in english

 

Vaclav POSSELT

Première remarque : testé sur ESP32forth 7.0.7.20, Arduino IDE2.3.2, ESP32 lib 2.0.14, ESP32 Dev Module.

ESP32forth est écrit en Arduino C et une certaine connaissance de C est très utile. En tant que programmeur amateur, avec des connaissances de base de Forth seulement, j'ai décidé d'apprendre également les bases d'Arduino C pour pouvoir mieux comprendre et utiliser ESP32forth. J'ai créé quelques notes sur mes exemples pour aider les autres dans la même situation. Dans ce texte, il y a quelques notes sur le mode d'alimentation Deep Sleep.

La puce ESP32 a plus de modes d'alimentation pour réduire la consommation d'énergie, ce qui peut aider dans les constructions avec une alimentation par batterie. Mes expériences sont basées sur du texte libre sur un excellent site Web
ESP32 Deep Sleep with Arduino IDE and Wake Up Sources
donc je ne mets pas de code C ici, possible d'en trouver là.

Dans ESP32forth, le mode Deep Sleep est pris en charge dans le vocabulaire ESP. Avec le mot deepsleep (temps en microsec--- ), il est possible de réduire la consommation à une fraction de la consommation d'exécution normale pendant le temps souhaité en microsecondes. Il s'agit de la méthode de réveil par minuterie. En mode Deep Sleep, seules la mémoire RTC SRAM et le coprocesseur ULP restent actifs, le reste de la puce est éteint, donc pas de CPU, pas de WiFi/BT, pas de mémoire programme SRAM . Le programme utilisateur ESP32forth est stocké dans la SRAM, donc pendant le Deep Sleep, il est perdu. Une fois le processeur de réveil réinitialisé, ESP32forth redémarre. La meilleure solution pour un programme utilisant Deep Sleep est d'utiliser le fichier autoexec.fs dans la mémoire SPIFFS (mémoire Flash non affectée par Deep Sleep). L'utilisation de Deep Sleep convient donc aux programmes effectuant des tâches répétitives avec un délai plus important comme les stations météorologiques. Le cycle complet peut être Démarrer - effectuer des mesures - stocker les données dans une mémoire non volatile ou les envoyer via WiFi/LoRa/BT sans fil - passer en veille profonde et redémarrer le cycle complet. Il n'est pas possible de geler uniquement le statut et de continuer le programme après le réveil.

Pour la démonstration, j'ai créé un programme simple DPdemo.fs activé à partir d'autoexec.fs après redémarrage avec la commande include /SPIFFS/DPdemo.fs à la fin de autoexec.fs. Pour la création/modification de fichiers dans /SPIFFS/, j'utilise le programme de Bob Edwards RECORDFILE ( "filename" "filecontents" "" -- ), j'ai la commande RECORDFILE dans mon autoexec.fs avec une meilleure commande de vidage pour afficher le contenu de la mémoire.

\ DPdemo.fs with subs words of some real program 
cr ." OK, here I am after restart of ESP32forth." 1000 ms cr 
: first ." measuring no 1" cr 1000 ms ; 
: second ." measuring no 2" cr 1000 ms ; 
: third ." meauring no 3" cr 1000 ms ; 
: save-send ." now sending/saving measurements" cr 1000 ms ; 
esp 
: mainprg \ ( --- ) program to run 
    first second third 
    save-send 
    ." going to Deep Sleep for 5 secs"  
    5000000  deepsleep 
    ; 
mainprg 

La sortie dans la fenêtre du terminal ressemble à ceci, notez également la source de la réinitialisation - DEEPSLEEP RESET, ce qui est important pour la section suivante sur la mémoire RST :

Pour mettre fin à ce cycle répétitif activé par autoexec.fs, appuyez sur un bouton du clavier du terminal pendant la réinitialisation pour ignorer autoexec.fs et revenir à la ligne de commande.

Bien sûr, j'ai mesuré la consommation. En mode normal, ma carte de développement ESP32 utilisait 75 mA, en veille profonde 6 mA, avec la radio WiFi activée, elle était de 155 mA. La consommation en veille profonde est supérieure à celle selon la spécification ESP32, mais je mesure toute la carte avec USB en utilisant un compteur USB.

Pour terminer ce cycle répétitif activé par autoexec.fs, appuyez sur un bouton du clavier du terminal pendant la réinitialisation pour ignorer autoexec.fs et revenir à la ligne de commande.

Bien sûr, j'ai mesuré la consommation. En mode normal, ma carte de développement ESP32 utilisait 75 mA, en veille profonde 6 mA, avec la radio WiFi activée, elle était de 155 mA. La consommation en veille profonde est supérieure à selon la spécification ESP32, mais je mesure toute la carte avec USB en utilisant un compteur USB.

J'étais également intéressé par la mémoire SRAM RTC, qui reste active pendant la veille profonde. D'après la fiche technique il y a une région d'adresse de 0x3FF8:0000 à 0x5000:1FFF deux fois 8 Ko appelée mémoire RTC lente et rapide. Dans Arduino C, il est possible de déclarer l'utilisation par
  RTC_DATA_ATTR int RTCvar1 =0 ; // variable in RTC memory

Dans ESP32forth, il est possible de vider le contenu ou d'accéder à cette mémoire avec L! et UL@, mais j'avais peur de ne pas endommager quelque chose utilisé par ESP32 lui-même. J'ai donc créé un simple fichier userwords.h pour faire quelques expériences avec la mémoire RTC. Après la compilation, il y a de nouveaux mots dans ESP32forth :
  RTC1! ( n--- ) \ save integer into RTC1 variable
  RTC1@ ( ---n ) \ read integer from RTC1 var
  RTC1addr ( ---addr ) read address of RTC1 variable in RTC memory
  RTCstr! ( str-z--- ) \ store c-type string max 31 chars

et ainsi de suite.

Je m'intéressais aux adresses de ces variables. Mon idée était que si je les déclarais, l'espace qu'elles occuperaient serait réservé afin que le prochain accès direct depuis ESP32forth soit correct et sûr.

Userwords.h:

#include <cstring>
 
RTC_DATA_ATTR int RTCvar1 =0 ;    // variable in RTC memory
RTC_DATA_ATTR int RTCvar2 =0 ;    // variable in RTC memory
RTC_DATA_ATTR char RTCstr[32];    // char variable in RTC memory
void savetoRTC1(int value1)          // save value to  RTC 
    { RTCvar1= value1; }
void savetoRTC2(int value1)          // save value to  RTC 
    { RTCvar2= value1; }
void savetoRTCstr(char value3[32])
    { strcpy(RTCstr,value3);}    
 
#define USER_WORDS \
X("RTC1!", savetoRTC1, savetoRTC1(n0); DROP; ) \
X("RTC1@", fromRTC1, PUSH RTCvar1; ) \
X("RTC1addr", RTC1addr, PUSH (uintptr_t)&RTCvar1; ) \
X("RTC2!", savetoRTC2, savetoRTC2(n0); DROP; ) \
X("RTC2@", fromRTC2, PUSH RTCvar2; ) \
X("RTC2addr", RTC2addr, PUSH (uintptr_t)&RTCvar2; ) \
X("RTCstr!", savetoRTCstr, savetoRTCstr(c0); DROP; ) \
X("RTCstr@", fromRTCstr, PUSH RTCstr; ) \
X("RTCstraddr", RTCstraddr, PUSH (uintptr_t)&RTCstr; )

Et un test simple, tout en hexadécimal :

Qu'est-ce qu'il y a - les adresses des variables RTC déclarées commencent à 0x5000:0200, selon la fiche technique, il s'agit de la zone de mémoire lente RTC. La première est une zone pour 32 octets de RTCstr, puis deux fois 4 octets pour les entiers 32 bits. Il est maintenant possible d'utiliser en toute sécurité ces emplacements de données dans la mémoire RTC directement si nous en avons besoin, et non pas uniquement d'utiliser les mots RTC créés.

Maintenant, nous essayons le sommeil profond.

Les données restent en mémoire et peuvent être utilisées de manière cohérente entre les commandes de sommeil profond. Et maintenant, réinitialisez avec le bouton RESET.

Les données dans la mémoire SRAM RTC sont perdues. Exactement selon les spécifications, voici une utilisation limitée visible de la mémoire SRAM RTC. Chaque réinitialisation par bouton, réinitialisation par mise hors tension effacera les données stockées. Donc, pour un stockage sûr dans la construction, l'utilisation de Deep Sleep est nécessaire pour utiliser une mémoire plus robuste comme SPIFFS ou flash NVM avec preferences.h comme je l'ai expliqué dans l'article précédent. Le flash a une limite théorique dans les cycles d'écriture, il peut s'user, mais en pratique? Je pense que cette mémoire RTC est là pour être utilisée avec un coprocesseur ULP capable de faire quelque chose même en mode Deep Sleep.

Si cela aide quelqu'un, j'en serai ravi, s'il y a des erreurs dans mon explication, je serai également ravi d'être corrigé.


Legal: site web personnel sans commerce / personal site without seling