Go Down

Topic: Arduino: sauvegarde de données en EEPROM en cas de coupure d'alimentation (Read 897 times) previous topic - next topic

hbachetti


Un petit tuto pour les membre qui se posent le problème de sauvegarder des données en catastrophe lorsque l'alimentation disparaît :

https://riton-duino.blogspot.com/2019/03/arduino-sauvegarde-de-donnees-en-eeprom.html

Chiffres et tests à l'appui.

Bonnes sauvegardes.
Linux is like a wigwam: no Windows, no Gates, and an Apache inside ...

hbachetti

Un petit paragraphe supplémentaire :

7. Améliorons avec un CRC

Comment écrire des données dans l'EEPROM en ajoutant un CRC pour assurer l'intégrité des données.

Et bien entendu comment relire ces données en vérifiant le CRC.

Linux is like a wigwam: no Windows, no Gates, and an Apache inside ...

hbachetti

Linux is like a wigwam: no Windows, no Gates, and an Apache inside ...

nico78

Vraiment ingénieux ce système de sauvegarde, parait tellement simple à mettre en oeuvre et surtout merci pour  le détail, le choix porté sur les composants et les calculs.

La lecture de votre code m'a fait pensé a un problème concernant le fait de pouvoir faire un auto off d'une carte arduino (il y a quelques temps, j'ai fais des recherches là dessus ) car techniquement c'est un souci bien que l'on puisse croire que cela fonctionnera bien. Je me dis qu'avec cette technique du condensateur, cela pourrait bien faciliter les choses.

hbachetti

Quote
auto off d'une carte arduino
Pourquoi pas ?
Adapter simplement la capacité à la longueur du traitement à réaliser.
Linux is like a wigwam: no Windows, no Gates, and an Apache inside ...

J-M-L

Salut - merci pour ce partage. un vrai besoin!

Petites améliorations éventuelles:

- dans le texte il manque un bout de phrase
Quote
Dans la fonction powerLoss le nombre magique est mis à zéro au départ. Cela permet de s'assurer que la fonction aura bien le temps d'écrire l'intégralité des données plus le nombre magique.
Si celui-ci est relu et qu'il vaut zéro, cela voudra dire que ... suspense intenable :)...
- pour garantir la longueur des données et figer les types, ce serait pas mal de ne pas utiliser un #define pour MAGIC mais un const uint32_t et de mettre UL pour la lisibilité.

- ce serait pas mal de définir la structure eeprom_data avec __attribute__ ((packed)) partout (ça manque au tout début) et expliquer à quoi ça sert de mettre ce mot clé (très utile en gestion de version par exemple). Il serait bon d'ailleurs de prévoir aussi __aligned__ car sur des architectures 32 bits ça peut jouer des tours quand on étend la structure de début. c'est aussi non standard, une extension des compilo que GCC supporte

- tel que vous l'utilisez, il me semble que le mot clé struct n'est plus obligatoire, le typedef est implicite dans ce namespace donc
Code: [Select]
struct eeprom_data eepromData;peut s'écrire
Code: [Select]
eeprom_data eepromData;(idem dans les appels à offsetof()

- de même
Code: [Select]
struct tm t = {0};peut s'écrire
Code: [Select]
tm t = {0};et attention cette notation n'est pas conforme à la dernière norme et le compilateur peut se plaindre de

warning: missing initializer for member 'tm::tm_min' [-Wmissing-field-initializers]
warning: missing initializer for member 'tm::tm_hour' [-Wmissing-field-initializers]
warning: missing initializer for member 'tm::tm_mday' [-Wmissing-field-initializers]
warning: missing initializer for member 'tm::tm_wday' [-Wmissing-field-initializers]
warning: missing initializer for member 'tm::tm_mon' [-Wmissing-field-initializers]
warning: missing initializer for member 'tm::tm_year' [-Wmissing-field-initializers]
warning: missing initializer for member 'tm::tm_yday' [-Wmissing-field-initializers]
warning: missing initializer for member 'tm::tm_isdst' [-Wmissing-field-initializers]
   tm t = {0};


La notation
Code: [Select]
tm t = {};devrait forcer les éléments à 0 sans warning.

Hello - Please do not PM me for help,  others will benefit as well if you post your question publicly on the forums.
Bonjour Pas de messages privés SVP, postez dans le forum directement pour que ça profite à tous

hbachetti

Quote
- dans le texte il manque un bout de phrase
Corrigé.

Quote
- ce serait pas mal de définir la structure eeprom_data avec __attribute__ ((packed)) partout (ça manque au tout début) et expliquer à quoi ça sert de mettre ce mot clé
Idem.

Quote
- tel que vous l'utilisez, il me semble que le mot clé struct n'est plus obligatoire, le typedef est implicite dans ce namespace donc
Certes mais j'ai toujours évité les typedefs pour les structures, un vieil héritage d'OpenBSD !
J'ai gardé cette habitude, qui a l'avantage de passer partout.

A noter :
Imaginons qu'une structure eeprom_data soit déclarée dans un fichier eeprom_data.h.

Dans un autre fichier header machin.h, un prototype de fonction :

int write_data(struct eeprom_data *data);

Au lieu d'inclure eeprom_data.h il est possible d'écrire :

Code: [Select]

struct eeprom_data;

int write_data(struct eeprom_data *data);

A partir du moment où data est un pointeur, le compilateur n'a pas besoin de connaître la taille de la structure.
Cette manière de faire n'est pas possible avec un typedef, sauf s'il est implicite bien sûr.

Quote
struct tm t = {0};
Un copier / coller malencontreux sans doute.

J'ai préféré ajouter ceci, plus explicite :

Code: [Select]

  memset(&t, 0, sizeof(struct tm));


De toutes façons le éléments sont tous initialisés plus loin, à part tm_wday et tm_yday.
Linux is like a wigwam: no Windows, no Gates, and an Apache inside ...

J-M-L

OK - et oui étant donné que vous initialisez la variable tm plus loin, le memset() n'est pas nécessaire
comme dit plus haut, si vous voulez forcer la mise à 0 -->
Code: [Select]
struct tm t = {};devrait le faire.
Hello - Please do not PM me for help,  others will benefit as well if you post your question publicly on the forums.
Bonjour Pas de messages privés SVP, postez dans le forum directement pour que ça profite à tous

hbachetti

Tous les éléments ne sont pas initialisés explicitement (tm_wday et tm_yday ne le sont pas).

D'après ce fil, peu de choses sont définies en C standard au sujet les initialisations partielles.

C++ apporterait quelques petits + :

Code: [Select]

  struct tm t = {0};
  struct tm t = {};       // extension GNU semble t-il ?
  // seraient équivalents à :
  struct tm t = {0, 0, 0, 0, 0, 0, 0, 0, 0};


Mais je travaille rarement en C++, plutôt en C (pas forcément sur ARDUINO), et dans ce cas, je préfère initialiser explicitement avec un memset.
De plus je trouve que cela montre clairement que quelque chose doit être fait (et que c'est fait).

Je trouve le compilateur AVR-GCC peu loquace à propos des variables locales non initialisées (et pas que). Il y a certainement moyen d'ajouter des options.
Un compilateur ARM serait beaucoup plus bavard par défaut.

En résumé je préfère la prudence, plutôt que de me fier à des automatismes particuliers à C++ ou à des extensions d'un compilateur en particulier.

Linux is like a wigwam: no Windows, no Gates, and an Apache inside ...

J-M-L

c'est sûr que
Code: [Select]
  struct tm t = {0, 0, 0, 0, 0, 0, 0, 0, 0};est le plus clean
Hello - Please do not PM me for help,  others will benefit as well if you post your question publicly on the forums.
Bonjour Pas de messages privés SVP, postez dans le forum directement pour que ça profite à tous

hbachetti

Pas vraiment.
Avec un appel memset je n'ai pas besoin de connaître le nombre d'éléments ni leur type.
Et je suis à l'abri d'une évolution de la structure.
Linux is like a wigwam: no Windows, no Gates, and an Apache inside ...

J-M-L

Pour le memset() mon commentaire concernait plus le fait que vous n'avez pas besoin d'initialiser t puisque c'est fait par la fonction ensuite
Hello - Please do not PM me for help,  others will benefit as well if you post your question publicly on the forums.
Bonjour Pas de messages privés SVP, postez dans le forum directement pour que ça profite à tous

hbachetti

Bien sûr, si l'on ne sert pas des membres tm_wday et tm_yday c'est inutile.
Linux is like a wigwam: no Windows, no Gates, and an Apache inside ...

J-M-L

Et si vous vous en servez et qu'ils sont à 0 c'est pas plus juste statistiquement qu'une autre valeur.. le plus simple c'est qu'une fois la structure initialisée, vous appelez mktime() qui se chargera de mettre à jour les 2 variables manquantes voire de corriger les valeurs « out of range »)
Hello - Please do not PM me for help,  others will benefit as well if you post your question publicly on the forums.
Bonjour Pas de messages privés SVP, postez dans le forum directement pour que ça profite à tous

Littel-Finger

C'est bon les amis. Je trouve que beaucoup de personnes ont encore des difficultés. J'ai trouvé un article simple à comprendre sur ce sujet.  Ce lien donne des détails importants : https://wedilas.com/la-programmation-pour-tous-nous-avons-arduino/

Go Up