Esp32 : deep sleep et SPIFFS

lesept:
Je suppose que c'est ce qui permet de le réveiller via une interruption envoyée par un capteur, dans mon cas l'accéléromètre ?

Oui j'alimente tout le système par le switch - donc quand j'éteins le switch (on peut le faire par programme) - ça coupe tout et quand il se rallume, ben ça rallume tout comme si vous aviez appuyé sur le bouton.

Salut,

Heu, je suis un peu surpris par le contenu de ce sujet ... Je n'ai pas encore utilisé l'ESP32 mais je connais bien l'ESP8266, j'imagine que c'est plus ou moins la même chose :slight_smile:

En résumé, oui, quand tu te reveille d'un DeepSleep, c'est pareil qu'un boot, donc TOUTES TA MEMOIRE a disparu hormis le contenu de la RTC.
Je pense qu'il y a une grosse confusion à ce niveau : il faut considérer cette mémoire comme un stockage externe à l'instar d'un fichier stocké sur la SPIFF.

Voici comment je procède :

J'ai créé une librairie qui me facilite la gestion de la RTC : KeepInRTC.
Les informations que je souhaites conserver sont stockées dans des variables "normale". Une instance de KeepInRtc::KeepMe gère le fait qu'on souhaite le sauvegarder.
J'ai les fonctions suivantes :

  • le constructeur de ma classe KeepMe par laquelle, je reserve chacune des variables : je passe un pointeur sur celle-ci et sa taille . Si ma RTC contient des données valables (que j'identifie par une "valeur magique" comme l'expliquait J-M-L), je restore la valeur de ma variables ... ce qui me permet de la conserver d'un redemarrage a un autre

  • save() que j'appele à chaque fois que je souhaites sauvegarder le nouveau contenu de ma variable

Il y a des exemples dans le répertoire du même nom.

Pour un exemple plus complet avec tout pleins de variables sauvegardés de manière parfaitement anarchiques (== n'importe quand), y'a mon projet pour mon poulailler. Il fonctionne très bien mais je n'irai pas au bout, car j'ai eu des problèmes avec le poulailler lui-même donc je suis parti sur autre chose. Mais j'utilise ma librairie pour d'autres projets :slight_smile:

Bref, ce code est pour ESP8266, je n'ai pas (encore :slight_smile: ) utilisé l'ESP32, mais y'a peut-être de quoi s'en inspirer.

A+

Bonsoir detroyedlolo

Je pense qu'il y a une grosse confusion à ce niveau

peux tu préciser en quoi consisterait cette 'grosse confusion' ?

Oui les ESP8266 et ESP32 sont voisins quand au deep sleep, mias pas identiques, plus simple.

Nous sommes d'accord pour dire que tout le contenu de la SRAM interne à l'ESP32 (520k) a disparu ...puisqu'elle a cessé d'être alimentée.. à l'exception des 2 RAM RTC (8k chacunes) qui, elles, ont continué à être alimentées.
Bien entendu la ROM interne à l'ESP32 (448k) est conservée de même que le contenu de la mémoire SPI FLASH externe (souvent 4 MB) ...( plus toujours externe d'ailleurs puis qu'Expressif vient de sortir deux variantes d'ESP32 avec une FLASH interne de 2 ou 4 MB... plus besoin dans ce cas du petit boitier Winbond 4MB ou 8MB , toujours associé jusqu'à présent aux l'ESP32*)*

(J'utilise les termes 'interne et externe' au sens physique : ce qui est ou n'est pas dans le boitier de la puce)

Oui la RAM RTC(8k) disponible sur un ESP32 s'utilise d'une manière très simple : Il suffit déclarer spécifiquement les variables que l'on veut y placer (autres plages d'adresses) Bien déclarées on peut à tout moment y accéder en lecture ou écriture, sans mécanisme particulier contrairement à une EEPROM, une , une FLASH, sans appel d'une fonction particulière contrairment à l'ESP8266.

RTC_DATA_ATTR int bootCount = 0;
.....
++bootCount;
Serial.println("Boot number: " + String(bootCount));

ben par rapport au

45 ko de variables globales

Est-il vraiment obligatoire d'y stocker TOUTES les variables globales ?
Normalement, seul les variables de contextes ont ce besoin :slight_smile:

destroyedlolo:
ben par rapport auEst-il vraiment obligatoire d'y stocker TOUTES les variables globales ?
Normalement, seul les variables de contextes ont ce besoin :slight_smile:

c’est quoi une “variable de contexte” selon vous?...

Bonsoir
Merci de toutes vos réponses. J'ai en effet sauvegardé mes 'variables de contexte', c'est à dire celles que je dois pouvoir utiliser après un réveil, dans la RAM RTC comme l'indique Al1 dans la réponse 22.

Ça, ça marche.
J'ai ensuite testé la mise en sommeil et le réveil par timer et par les touches tactiles de l'ESP32.

Ça, ça marche aussi.
Maintenant, je me bats avec le réveil par une interruption externe : un bouton d'abord. Ça marche. C'est dommage que ce soit incompatible du réveil par les touches tactiles, j'aurais bien aimé avoir les deux...

Reste à implémenter le réveil par la détection d'un mouvement avec un accéléromètre MPU6050... Et là, ça marche pas, je rame... Rien de probant sur le net. Si vous avez des pistes, je suis preneur.

Bonsoir lesept

Pas encore résolu la question du seuil de mouvement et de la durée de mouvement pour obtenir une interruption en sortie du MPU6050 :wink: ?

Je ne connais pas bien la puce, sa datasheet et la ou les librairies mais une idée vient :
l'interruption par 'détection du mouvement' est elle possible DMP désactivée ?

En effet, question pertinente. Je me suis posé la même, mais pas eu le temps de tester...

EDIT : ton lien est faux... Peux-tu vérifier ?

lien corrigé, c'était encore la malédiction du http://http://http//.....""""""

Au fait, dois-je ou puis-je mettre la pin qui reçoit l'interruption en pullup ou pulldown ?

la doc du mpu dit que la sortie INT peut être configurée en 'totem pole' ou 'open drain'
Un pull up ne peut pas faire de mal !
On voit sur le web des schémas avec un pull up externe.

Bonsoir
J'ai pas mal cherché, et j'ai finalement un code qui marche...

// Bus 2 : l'accéléro
#define SDA2 5
#define SCL2 4

#include <Wire.h>
#include "I2Cdev.h"
#include <MPU6050.h>

RTC_DATA_ATTR int bootCount = 0;
MPU6050 accelgyro;
/*
  Method to print the reason by which ESP32 has been awaken from sleep
*/
void print_wakeup_reason() {
  esp_sleep_wakeup_cause_t wakeup_reason;
  wakeup_reason = esp_sleep_get_wakeup_cause();
  switch (wakeup_reason)
  {
    case 1  : Serial.println("Wakeup caused by external signal using RTC_IO"); break;
    case 2  : Serial.println("Wakeup caused by external signal using RTC_CNTL"); break;
    case 3  : Serial.println("Wakeup caused by timer"); break;
    case 4  : Serial.println("Wakeup caused by touchpad"); break;
    case 5  : Serial.println("Wakeup caused by ULP program"); break;
    default : Serial.println("Wakeup was not caused by deep sleep"); break;
  }
}

bool InitAccelero () {
  Wire.begin(SDA2, SCL2);
  accelgyro.initialize();
  bool Success  = accelgyro.testConnection(); // verify connection
  if (Success) {
    Serial.println("MPU6050 connection successful");
  }
  else Serial.println("MPU6050 connection failed");
  return Success;
}

void setup() {
  Serial.begin(115200);
  bool AcceleroSuccess = InitAccelero ();

  // instructions from : https://lukelectro.wordpress.com/2016/08/11/how-to-enable-motion-detection-interrupt-on-mpu6050/
  accelgyro.resetGyroscopePath();
  accelgyro.resetAccelerometerPath();
  accelgyro.setInterruptDrive(0);
  accelgyro.setInterruptMode(1); // 0=active-high, 1=active-low
  accelgyro.setDHPFMode(MPU6050_DHPF_5);
  accelgyro.setMotionDetectionThreshold(2); // Threshold in 2mg (ajouté by me)
  accelgyro.setMotionDetectionDuration(100); //Duration in ms
  accelgyro.setAccelerometerPowerOnDelay(1); // Set accelerometer power-on delay
  accelgyro.setFreefallDetectionCounterDecrement(1); // Set Free Fall detection counter decrement
  accelgyro.setMotionDetectionCounterDecrement(1); // Set Motion detection counter decrement
  accelgyro.setIntMotionEnabled(true);

  delay(200); //Take some time to open up the Serial Monitor
  //Increment boot number and print it every reboot
  ++bootCount;
  Serial.println("Boot number: " + String(bootCount));
  delay(20);

  print_wakeup_reason(); //Print the wakeup reason for ESP32
  // Configure RTCIO as wakeup source
  esp_sleep_enable_ext0_wakeup(GPIO_NUM_13, 0); //1 = High, 0 = Low

  //Go to sleep now
  Serial.println("Going to sleep now");
  delay(200);
  esp_deep_sleep_start();
}

void loop() { }

Les connexions :
VCC, GND, SDA sur pin 5, SCL sur pin 4 et INT sur 13.

Bravo !
Merci pour le retour

Merci mais ce n'est pas encore terminé.
J'ai donc les moyens de mettre mon système en sommeil profond et de le réveiller soit par le timer (toutes les minutes pour affichage de l'heure) soit avec un mouvement par l'accéléromètre.
Mais dans ce dernier cas j'ai alors besoin de savoir combien de temps s'est écoulé depuis la mise en sommeil pour régler le timer avant de remettre en sommeil.
Comment puis je connaître ce temps écoulé ?

tu veux savoir combien de temps à dormi un 'ESP32 , réveillé par une interruption.c'est ça ?.
..... pas de pb en ajoutant un circuit RTC !!

Sinon il faudrait, au reveil, pouvoir lire la valeur du compteur interne 'RTC' , celui qui est capable de réveiller l'ESP
Je ne sais pas si ce compteur est accessible en lecture depui le code exécuté au réveil. Il faut chercher.

(millis () étant remis à zéro au reveil on ne peut s'en servir pour ce que tu veux faire)

Je préférerais éviter la RTC, mon idée était bien de le le contenu de ce registre

En demandant l'heure qu'il est à la RTC avant de s'endormir et en le notant dans la mémoire de la RTC puis en comparant avec l'heure qu'il est au réveil ? (ça semble fixé maintenant)

Bonne nouvelle JML !! Merci pour le lien.
ça commence à mériter le terme de RTC ... si en plus on fait tourner ça avec un quartz de 32 kHZ
Reste à tester ça sous IDE Arduino

J'ai trouvé un exemple :

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

#include "sys/time.h"

#include "sdkconfig.h"

#include "esp_deep_sleep.h"

#define GPIO_DEEP_SLEEP_DURATION     10  // sleep 10 seconds and then wake up
RTC_DATA_ATTR static time_t last;        // remember last boot in RTC Memory

void app_main() {
	struct timeval now;

	printf("start ESP32\n");

	gettimeofday(&now, NULL);

	printf("deep sleep (%lds since last reset, %lds since last boot)\n",now.tv_sec,now.tv_sec-last);

	last = now.tv_sec;
	esp_deep_sleep(1000000LL * GPIO_DEEP_SLEEP_DURATION);

}

Le code se réveille toutes les 10 secondes et affiche le temps de sommeil, mais en secondes. Il reste juste à trouver le moyen d'obtenir des microsecondes...
Probable qu'on puisse utiliser

	last = now.tv_usec;

ou convertir les temps en microsecondes comme

now.tv_sec * 1000000 + now.tv_usec

Je teste ça dès que j'ai un moment...

Voila le résultat :

#define uS_TO_S_FACTOR 1000000  /* Conversion factor for micro seconds to seconds */
#define TIME_TO_SLEEP  5       /* Time ESP32 will go to sleep (in seconds) */

#include "sys/time.h"

RTC_DATA_ATTR int bootCount = 0;
RTC_DATA_ATTR static time_t last;        // remember last boot in RTC Memory
RTC_DATA_ATTR static time_t lastus;        // remember last boot in RTC Memory


void setup() {
  Serial.begin(115200);

  struct timeval now;
  gettimeofday(&now, NULL);
  long temps = now.tv_sec * 1000000 + now.tv_usec - (last * 1000000 + lastus);
  Serial.println(temps);

  //Configure Timer as wakeup source
  esp_sleep_enable_timer_wakeup(TIME_TO_SLEEP * uS_TO_S_FACTOR);

  delay(1); //delayMicroseconds(400);
  last = now.tv_sec;
  lastus = now.tv_usec;
  esp_deep_sleep_start();
}

void loop() { }

Pour un temps de sommeil demandé de 5 secondes, j'obtiens des réveils avec un temps mesuré autour de 5 secondes et 129 ms

rst:0x1 (POWERON_RESET),boot:0x17 (SPI_FAST_FLASH_BOOT)
configsip: 0, SPIWP:0xee
clk_drv:0x00,q_drv:0x00,d_drv:0x00,cs0_drv:0x00,hd_drv:0x00,wp_drv:0x00
mode:DIO, clock div:1
load:0x3fff0018,len:4
load:0x3fff001c,len:808
load:0x40078000,len:6084
load:0x40080000,len:6696
entry 0x400802e4
20144
ets Jun 8 2016 00:22:57

rst:0x5 (DEEPSLEEP_RESET),boot:0x17 (SPI_FAST_FLASH_BOOT)
configsip: 0, SPIWP:0xee
clk_drv:0x00,q_drv:0x00,d_drv:0x00,cs0_drv:0x00,hd_drv:0x00,wp_drv:0x00
mode:DIO, clock div:1
load:0x3fff0018,len:4
load:0x3fff001c,len:808
load:0x40078000,len:6084
load:0x40080000,len:6696
entry 0x400802e4
5129085
ets Jun 8 2016 00:22:57

rst:0x5 (DEEPSLEEP_RESET),boot:0x17 (SPI_FAST_FLASH_BOOT)
configsip: 0, SPIWP:0xee
clk_drv:0x00,q_drv:0x00,d_drv:0x00,cs0_drv:0x00,hd_drv:0x00,wp_drv:0x00
mode:DIO, clock div:1
load:0x3fff0018,len:4
load:0x3fff001c,len:808
load:0x40078000,len:6084
load:0x40080000,len:6696
entry 0x400802e4
5129022

Ces 129 ms supplémentaires semblent dépendre des instructions qui se trouvent entre les instructions liées au temps : gettimeofday et affectation des variables last et lastus

Par exemple si je mets
  esp_sleep_enable_timer_wakeup(5000000);il y a une multiplication en moins et je passe à 128,9 ms. Par contre si j'ajoute les instructions de configuration de mon accéléromètre, je passe à 528 ms...

Et déplacer le Serial.begin après le gettimeofday ne change rien !

Enfin, le delay(1) sert à attendre que le port série envoie la donnée (temps), si on optimise avec delayMicroseconds(400) on passe à 128,5 ms.

Ce temps additionnel est indépendant de la durée du temps de sommeil : si je mets 10 ou 30 secondes, les résultats sont similaires.