Utilisation de la mémoire RTC, problème..

Bonjour à tous,
Je vous souhaite une bonne année 2021.

Je rencontre un problème à l'utilisation de la mémoire RTC sur un ESP8266 NodeMCU.

Pour une raison que j'ignore, je n'arrive pas à stocker/lire des variables de types différents dans cette mémoire.

Les variables de type FLOAT sont bien retrouvées, mais celle du type INT non. Au lieu de 1, je retrouve un nombre du genre 2015215414...

Dans l'extrait ci-dessous, j'ai fait un essai en remplaçant la variable INT par FLOAT et là, pas de soucis...

J'utilise un ESP8266 NodeMCU V3 avec l'IDE Arduino IDE et ESP8266 core version 2.7.4.

Pour info, la longueur stockée de rtcMem est de 12 octets.

Quelqu'un a t-il une idée ?
Merci,

#define RTCMEMORYSTART 65 // where the storage in rtc memory begins

  typedef struct {
    float last_weight;
    float last_temperatureC;
    int counter;
    } rtcStore;
  rtcStore rtcMem;

system_rtc_mem_write (RTCMEMORYSTART,&rtcMem,sizeof(rtcMem));

system_rtc_mem_read(RTCMEMORYSTART, &rtcMem, sizeof(rtcMem));

Es-tu sûr de la longueur des int ? 4 ou 2 octets ?

Bonjour et merci,

C'est bien ce que me donne sizeof(rtcMem)...

J'avoue que c'est curieux. Bref, je tourne en rond... :-((

Bonjour

Oui , 12 octets : int sur 4 octets pour ESP8266 (=int32)

la variable counter a-t-elle été déclarée avec l'attribut adéquat ?

+Avec le petit extrait de code on ne voit pas comment est exploitée la structure + on n'est pas certain qu'elle soit logée en RTCRAM

al1fch:
Bonjour

Oui , 12 octets : int sur 4 octets pour ESP8266 (=int32)

la variable counter a-t-elle été déclarée avec l'attribut adéquat ?

+Avec le petit extrait de code on ne voit pas comment est exploitée la structure + on n'est pas certain qu'elle soit logée en RTCRAM

Bonjour et merci,

OK pour les 12 octets

Non, il n'y a pas d'autre déclaration de la variable counter. Celle dans struct rtcStore ne suffit-elle pas ?

L'instruction system_rtc_mem_write, ne sert-elle pas justement à mettre en RAM RTC ?

ma mémoire me joue des tours et probable confusion avec l'attribut RTC_DATA_ATTR des ESP32 !!

l'exemple RTCUserMemory est la référence pour ESP8266 avec ESP.rtcUserMemoryWrite()

al1fch:
ma mémoire me joue des tours et probable confusion avec l'attribut RTC_DATA_ATTR des ESP32 !!

l'exemple RTCUserMemory est la référence pour ESP8266 avec ESP.rtcUserMemoryWrite()

OK..

J'ai essayé avec les instructions ESP.rtcUser , avec le même résultat .
J'ai même changé le type de la variable counter en la passant à uint32_t...

L'exemple donné sur ton lien fonctionne, mais la donnée est un tableau et non pas des types différents

Je commence mal l'année... >:(

#define RTCMEMORYSTART 65 // where the storage in rtc memory begins

peut être un problème d'alignement de la structure : adresse de début à positionner sur un multiple de 32 bits
Essayer 64

al1fch:

#define RTCMEMORYSTART 65 // where the storage in rtc memory begins

peut être un problème d'alignement de la structure : adresse de début à positionner sur un multiple de 32 bits
Essayer 64

La valeur 64 est réservée par le système.. Mais j'ai essayé aussi.
Mais avec les instructions ESP.rtcUser sur lesquels je suis resté, j'ai l'impression que l'offset peut commencer à zéro.

J'ai lu que "Les données doivent être alignées sur 4 octets".

Comment m'y prendre ? Je pensais qu'en passant de INT à uint32_t, je n'aurais pas de souci..
J'ai fouillé tout le net sans trouver de solution...

C'est enrageant cette affaire !

Bonjour

Il vaut mieux utiliser ESP.rtcUserMemoryRead(...) et ESP.rtcUserMemoryWrite(...) dont voici le code source

bool EspClass::rtcUserMemoryRead(uint32_t offset, uint32_t *data, size_t size)
{
    if (offset * 4 + size > 512 || size == 0) {
        return false;
    } else {
        return system_rtc_mem_read(64 + offset, data, size);
    }
}

bool EspClass::rtcUserMemoryWrite(uint32_t offset, uint32_t *data, size_t size)
{
    if (offset * 4 + size > 512 || size == 0) {
        return false;
    } else {
        return system_rtc_mem_write(64 + offset, data, size);
    }
}

Et la documentation.)
ESP.rtcUserMemoryWrite(offset, &data, sizeof(data)) and
ESP.rtcUserMemoryRead(offset, &data, sizeof(data)) allow data to be stored in and retrieved from the RTC user memory of the chip respectively. offset is measured in blocks of 4 bytes and can range from 0 to 127 blocks (total size of RTC memory is 512 bytes). data should be 4-byte aligned. The stored data can be retained between deep sleep cycles, but might be lost after power cycling the chip. Data stored in the first 32 blocks will be lost after performing an OTA update, because they are used by the Core internals.

Conclusion :

Normalement un ESP.rtcUserMemoryWrite(0, (uint32_t *)&rtcMem, sizeof(rtcMem));
et un ESP.rtcUserMemoryRead(0, (uint32_t *)&rtcMem, sizeof(rtcMem));

devraient fonctionner, en ayant au préalable vérifié que sizeof(rtcMem) est bien un multiple de 4.

Nb :

Ton code "sent" la sonde en deepsleep qui se réveille à intervalles réguliers :slight_smile:

A mon sens, il manque au moins une donnée conservée en rtcMemory, afin de savoir si l'ESP est réveillé après un deepsleep ou s'il a démarré à froid.

D'autant que si le montage est sur batterie, lorsque celle-ci devient faiblarde, j'ai constaté des sorties de deepsleep sans conservation de la rtcMemory.

Perso j'ai pris comme option d'ajouter dans les données conservées :

  • une constante sur 32 bits, peu importe la valeur mais différente d'un programme à l'autre.
  • un CRC32

Ainsi au démarrage, la vérification de la constante et du CRC32 permet de s'assurer de la consistance des données lues.

Merci,

J'ai écrit le petit bout de code ci-dessous en respectant la même syntaxe que mon sketch, et là tout fonctionne normalement !
Reste maintenant à comprendre pourquoi ça ne fonctionne pas ... :confused:

 typedef struct {
    float last_weight;
    float last_temperatureC;
    int32_t last_counter;
    } rtcStore;
  rtcStore rtcMem;

 int32_t counter = 0;
 float weight = 100.00;
 float temperature = 20.00;
  
void setup() {
  Serial.begin(115200);
  Serial.println();

  if (ESP.rtcUserMemoryRead(0, (uint32_t*) &rtcMem, sizeof(rtcMem))) {
    Serial.println("Reading... ");
    Serial.print ("Weight = ");
    Serial.println (rtcMem.last_weight);

    Serial.print ("Temp = ");
    Serial.println (rtcMem.last_temperatureC);

    Serial.print ("Counter = ");
    Serial.println (rtcMem.last_counter);

    counter = rtcMem.last_counter;
    weight = rtcMem.last_weight;
    temperature = rtcMem.last_temperatureC;
  }

  counter += 1;
  rtcMem.last_counter = counter;
  weight +=1;
  rtcMem.last_weight = weight;
  temperature += 0.1;
  rtcMem.last_temperatureC = temperature;

   if (ESP.rtcUserMemoryWrite(0, (uint32_t*) &rtcMem, sizeof(rtcMem))) {
    Serial.println("Writing... ");
    Serial.println();
  }
        

  
  Serial.println ("Deep sleep");
  ESP.deepSleep(15 *1000000);
  }

void loop() {
}

Merci,

Mais la lecture des données FLOAT est bonne.... seule la vaeur INT est erronnée !

bricoleau:
Nb :

Ton code "sent" la sonde en deepsleep qui se réveille à intervalles réguliers :slight_smile:

A mon sens, il manque au moins une donnée conservée en rtcMemory, afin de savoir si l'ESP est réveillé après un deepsleep ou s'il a démarré à froid.

D'autant que si le montage est sur batterie, lorsque celle-ci devient faiblarde, j'ai constaté des sorties de deepsleep sans conservation de la rtcMemory.

Perso j'ai pris comme option d'ajouter dans les données conservées :

  • une constante sur 32 bits, peu importe la valeur mais différente d'un programme à l'autre.
  • un CRC32

Ainsi au démarrage, la vérification de la constante et du CRC32 permet de s'assurer de la consistance des données lues.