problème l'écriture ou lecture dans l'EEPROM

Bonjour
J’utilise une Uno avec 1024 octets d’EEPROM, dans laquelle je souhaite enregistrer l’instant de la mesure en secondes sur 2 octets et la valeur de la température sur un octect. Je définis une structure TetM en conséquence Préalablement au stockage des données j’efface le contenu précédent avec une série de 0, ou de 1 (j’alterne à chaque compilation). Si je ne déconnecte pas l’alim de la carte, ça marche bien. Mais si je la déconnecte de l’alimentation, j’ai une partie de la mémoire qui contient des données erronées, ou qui contient les 0 ou 1 mis pour l’effacement. Si, une fois qu’une lecture correcte à été faite sans déconnexion, je me déconnecte ensuite, une nouvelle lecture donne les valeurs attendues.

Le code pour l’écriture

#include <LiquidCrystal.h>            // Inclusion de la librairie LiquidCrystal pour l'afficheur LCD
#include <EEPROM.h>                   // Inclusion de la librairie EEPROM pour stocker les données de mesure du capteur de température en mémoire EEPROM (non volatile) d'Arduino

// Déclaration des constantes de broches
const int broche1 = 0;                // cablage de la broche 1 du moteur pas à pas sur l'entrée/sortie numérique 0 d'arduino
const int broche2 = 1;                // cablage de la broche 2 du moteur pas à pas sur l'entrée/sortie numérique 1 d'arduino. L'utilisation des ces 2 broches (Rx, TX) interdit l'usage de la liaison série
const int broche3 = 2;                // cablage de la broche 3 du moteur pas à pas sur l'entrée/sortie numérique 2 d'arduino
const int broche4 = 3;                // cablage de la broche 4 du moteur pas à pas sur l'entrée/sortie numérique 3 d'arduino
const byte DB4 = 4;                   // cablage de l'entrée DB4 de l'afficheur LCD sur l'entrée/sortie numérique 4 d'Arduino
const byte DB5 = 5;                   // cablage de l'entrée DB5 de l'afficheur LCD sur l'entrée/sortie numérique 5 d'Arduino
const byte DB6 = 6;                   // cablage de l'entrée DB6 de l'afficheur LCD sur l'entrée/sortie numérique 6 d'Arduino
const byte DB7 = 7;                   // cablage de l'entrée DB7 de l'afficheur LCD sur l'entrée/sortie numérique 7 d'Arduino
const byte RS = 8;                    // cablage de l'entrée RS de l'afficheur LCD sur l'entrée/sortie numérique 8 d'Arduino
const byte E = 9;                     // cablage de l'entrée E de l'afficheur LCD sur l'entrée/sortie numérique 9 d'Arduino

const byte brocheThermoF = 2;         // cablage de la sortie analogique du capteur de température du four sur l'entrée analogique A2 d'Arduino

// --- Déclaration des objets ---
LiquidCrystal lcd(RS, E, DB4, DB5, DB6, DB7);   // Création de l'objet lcd avec initialisation de l'afficheur en mode 4 bits conformément au cablage du shield

void setup() 
{ 
  int x = 0;
  
  Serial.begin(9600);                 // initialise connexion série à 9600 bauds. Connexion nécessaire pour la mise à l'heure du RTC et l'interface graphique Processing
    while ( x < EEPROM.length())  {
      EEPROM.put(x, 0);                                             // écriture de la structure en mémoire EEPROM à l'adresse eeAddress
      x++;
    }
}

void loop()
{  
float tempFour;                         // température du four en °C
long tpsMesure;                         // instant en millisecondes où l'on fait la mesure de temperature
struct TetM {                           // structure d'une ensemble de données non homogènes appelée TetM comprenant
  unsigned int temps;                   // l'instant en secondes de la mesure de température. On doit pouvoir faire 12 h de mesures soit 43200 secondes
  byte mesure;                          // la mesure de température du four
} varTetM;                              // définit une variable de type TetM appelée varTetM
static int eeAddress = 0;               // adresse ou l'on va écrire dans la mémoire EEPROM, initialisée à 0 qu'=au 1er appel de la fonction  
   
   
  tempFour = (float)analogRead(brocheThermoF)*500/1023;                 // lecture de valeur retournée par le thermomètre du four et conversion d'échelle: [0; 1023] en [0; 500°C]
  tpsMesure = millis();                                                 // on relève le nombre de secondes écoulées depuis le début du programme, et c'est l'instant de la mesure
    Serial.print(tpsMesure);Serial.print("\t");Serial.print(eeAddress/3);Serial.print("\t");Serial.println((int)tempFour);
    while (eeAddress > EEPROM.length()-2) {                                      // si capacité de l'EEPROM -2 dépassée (le -2 est là pour tenir compte de la taille de la structure à écrite dans la mémoire)
      lcd.clear();
      lcd.print("EEPROM pleine");
      delay(1000);
      lcd.noDisplay();                                                              // clignotement du message (1 s allumé, 0.5 s éteint)
      delay(500);
      lcd.display();
    }
    varTetM = {tpsMesure/1000, (int)tempFour};                                  // remplissage de la structure varTetM par l'instant de la mesure en secondes et la température du four en °C entiers
    EEPROM.put(eeAddress, varTetM);                                             // écriture de la structure en mémoire EEPROM à l'adresse eeAddress
    eeAddress+= 3;
}

Le code pour la lecture

#include <EEPROM.h>                   // Inclusion de la librairie EEPROM où sont stocké les données de mesure du capteur de température


void setup() {
  Serial.begin(9600);                 // initialisation de la liaison série
}

void loop() 
{
// Déclarations des variables locales
struct TetM {                           // structure d'une ensemble de données non homogènes appelée TetM comprenant
  unsigned int temps;                   // l'instant en secondes de la mesure de température
  byte mesure;                          // la mesure de température du four
} varTetM;                              // définit une variable de type TetM appelée varTetM
int eeAddress = 0;                      // adresse ou l'on va lire dans la mémoire EEPROM

  while(eeAddress <= EEPROM.length()-2)  {     // Tant que l'on n'est pas sur la dernière adresse de l'EEPROM -2 (le -2 est necessaire car il faut pouvoir mémoriser toutes la structure qui occupe 3 octects)
  EEPROM.get(eeAddress, varTetM);             // Lecture de l'EEPROM à l'adresse eeAdress s'une structure de type TetM nomée varTetM
  Serial.print(eeAddress/3);Serial.print("\t");Serial.print(varTetM.temps);Serial.print("\t");Serial.println(varTetM.mesure);   // Ecriture dans le terminal série pour être copié ensuite sous Excel avec un control C
  eeAddress +=3;                              // on passe à l'adresse de la structure suivante, soit un pas de 3 (1 int = 2 octects et 1 byte = 1 octect)
  }
  while(1);                                   // on arrête le bouclage de loop()
}

Merci d’avance de votre aide

Petite précision suite à de nouveaux essais. J'ai fais suivre l'écrite dans l'EEPROM par une lecture avec affichage sur le LCD. 1) Exécution du programme avec écriture suivie immédiatement après de la lecture: tout est OK 2) Je débranche l'alim, puis je rebranche. Que je fasse une lecture sur terminal série ou sur LCD, une partie des données de temps et de températures sont perdues, mais tantôt c'est 1/3 des premières cellules mémoires qui sont affectées, tantôt c'est le dernier 1/3. Mais les données perdues ne sont pas remplacées par n'importe quoi: elles contiennent la valeur d'initialisation posées par le setup.

Je n'y comprends rien. Comment, en débranchant l'alimentation je peux perdre une partie des données, jamais les mêmes. Et celles perdues, alors que j'ai vérifié juste après écriture qu'elles avaient bien été écrites, sont remplacées par la valeur d'initialisation des cellules mémoires de l'EEPROM. ?????

J'ai aussi testé avec une autre carte UNO, même problème Parfois ce n'est que 1/3 de données qui sont perdues, parfois c'est 99%, mais quelque soit l'étendue de la perte, c'est toujours soit en début soit en fin de mémoire que cela se produit

c'est quoi ces déclarations ?

// Déclaration des constantes de broches
const int broche1 = 0;                // cablage de la broche 1 du moteur pas à pas sur l'entrée/sortie numérique 0 d'arduino
const int broche2 = 1;                // cablage de la broche 2 du moteur pas à pas sur l'entrée/sortie numérique 1 d'arduino. L'utilisation des ces 2 broches (Rx, TX) interdit l'usage de la liaison série

vous les utilisez?

c'est quoi ce délire avec un while? vous mettez votre programme dans une boucle infinie une fois la mémoire pleine? (en fait vous avez déjà débordé)

   while (eeAddress > EEPROM.length()-2) {                                      // si capacité de l'EEPROM -2 dépassée (le -2 est là pour tenir compte de la taille de la structure à écrite dans la mémoire)

de plus avec

struct TetM {                           // structure d'une ensemble de données non homogènes appelée TetM comprenant
  unsigned int temps;                   // l'instant en secondes de la mesure de température. On doit pouvoir faire 12 h de mesures soit 43200 secondes
  byte mesure;                          // la mesure de température du four
} varTetM;

votre structure ne fait pas 2 octets... (utilisez sizeof(varTetM) au lieu de 2)

généralement on déclare les types en global, pas au sein d'une fonction

si vous ne voulez faire quelque chose qu'une seule fois, faites le dans le setup au lieu de faire une boucle infinie qui bloque la loop()

Je ferai deux remarques :

R1
Encore un fois tant qu’Arduino n’expliquera pas sur son site la vraie structure du fichier transmis au compilateur on trouvera se genre d’incompréhension.

Exemple de programme transmis au compilateur une fois les fonctions setup et loop écrites.

#include Arduino.h

void setup();
void loop() ;

int main(){
  init();    //fonction arduino qui configure le micro
  setup()
  while (1){   // on ne peut sortir de la boucle while(1) c'est ce qui provoque une boucle infinie.
    loop();
  }
}

void setup(){
  // code de setup()
}

void loop(){
 // code de loop()
}

R2 :
Cette fonction pour écrire dans l’eeprom du micro est horriblement compliquée.
Elle a été réécrite (complexifiée) pour être compatible avec les ARM (Due et Zero)

Dans un premier temps Wiring (arduino) avait juste encapsulé une macro Atmel dans une classe pour cacher l’usage d’un pointeur.
C’était déjà bien plus simple et en étant un peu curieux on pouvait trouver d’autres macros Atmel bien pratiques pour utiliser des “words” ,des floats, etc → voir l’ “avr-libc”
http://www.nongnu.org/avr-libc/user-manual/group__avr__eeprom.html

S’il n’y a que des entiers sur 8 bits à mettre en mémoire c’est encore plus simple d’utiliser la datasheet du micro.
Exemple tiré de la datasheet (il n’y a même pas besoin de connaître le rôle des registres) :

void EEPROM_write(unsigned int uiAddress, unsigned char ucData)
{
/* Wait for completion of previous write */
while(EECR & (1<<EEPE))
;
/* Set up address and Data Registers */
EEAR = uiAddress;
EEDR = ucData;
/* Write logical one to EEMPE */
EECR |= (1<<EEMPE);
/* Start eeprom write by setting EEPE */
EECR |= (1<<EEPE);
}

Réponse à J-M-L

Point1) oui, ces déclarations n'ont rien à voir. En fait c'est un programme plus complexe (850 lignes), et j'ai extrait ce qui pose problème. Et méa culpa, j'ai oublié d'enlever la déclaration de constantes des broches du moteur pas à pas

Point 2) Je n'ai pas débordé de ma mémoire puisque je teste si l'adresse est strictement inférieure à la taille de la mémoire -2

Point 3) Ma structure ne fait pas 2 octets, effectivement. Et c'est pour cela que le pas de progression de mon adressage mémoire est de 3 en 3, ce qui correspond à la taille de ma structure

Point 4) On ne déclare pas les variables de manière globales si on n'en a besoin que de manière locale...économie de mémoire

Point 5) Vous avez raison, ceci dit, ma manière de faire n'est pas un problème en soit

Réponse à 68tjs

Je n'ai pas compris ce que vous voulez dire par la R1. Vous parlez de structure de fichier qui poserait problème. De quelle structure s'agit-il? Quel rapport avec mon programme?

Vous pointez du doigt la fonction utilisée pour écrire dans la mémoire. J'imagine que vous parlez la fonction EEPROM.put()? Pourtant dans le lien des macros que vos m'indiquez cette fonction existe bien!

Enfin, la durée de la mesure s'étant sur environ un peu moins de 11,33h (une mesure toutes le 2 minutes soit 340 mesures prenant 3 octets chacune, soit 1020 octets), cela représente 40800 secondes, qui sont stockées sur 2 octets.

Erwan19: Point1) oui, ces déclarations n'ont rien à voir. En fait c'est un programme plus complexe (850 lignes), et j'ai extrait ce qui pose problème. Et méa culpa, j'ai oublié d'enlever la déclaration de constantes des broches du moteur pas à pas

OK - attention à ne pas faire de Serial.print si vous avez des trucs sur 0 et 1

Erwan19: Point 2) Je n'ai pas débordé de ma mémoire puisque je teste si l'adresse est strictement inférieure à la taille de la mémoire -2

Ce que je voulais dire c'est que le code est "chanceux"... :)

En pratique vous testez while (eeAddress [color=red]>[/color] EEPROM.length()-2) { si c'est strictement supérieur donc ça veut dire que si c'est inférieur ou égal vous continuez. Donc si vous arriviez avec eeAddress égal à 1022 vous passeriez votre while et iriez écrire 3 octets en 1022, 1023 et 1024... hors il n'y a pas de case mémoire N° 1024.

Dans votre cas ça n'arrive pas parce que vous commencez à remplir la mémoire à 0 et en augmentant de 3 en 3 eeAddress ne vaudra jamais 1022 mais si par hasard vous aviez décidé de commencer à écrire en 2 (pour avoir les 2 premiers octets pour un N° de version par exemple) alors vous auriez vos enregistrements de 3 octets en [2,3,4] puis [5,6,7] puis [8,9,10] puis ... [1019,1020,1021] et là votre pointeur est en 1022, le test foire et vous débordez...

Erwan19: Point 3) Ma structure ne fait pas 2 octets, effectivement. Et c'est pour cela que le pas de progression de mon adressage mémoire est de 3 en 3, ce qui correspond à la taille de ma structure

Mais sur une autre architecture où les int ne sont pas sur 2 octets mais 4 (genre ESP) alors ça ne fonctionne pas, d'où l'idée de bien utiliser sizeof() pour avoir un code portable indépendant des choix du compilateur

Erwan19: Point 4) On ne déclare pas les variables de manière globales si on n'en a besoin que de manière locale...économie de mémoire

je parlais de déclarer [u]le type[/u] en global pour le fichier - ça ne prend pas de mémoire. la variable peut être locale effectivement.

Erwan19: Point 5) Vous avez raison, ceci dit, ma manière de faire n'est pas un problème en soit

Disons que sur certaines architectures ou suivant la configuration quand vous rentrez dans une boucle infinie sans repasser par le main ça peut déclencher le watchdog et donc le reboot intempestif de votre Arduino et donc vous relancez le setup et vous recommencez à écrire dans votre EEPROM (qui a un nombre max d'écriture - même s'il est assez grand - 100,000 - si on peut éviter, c'est quand même mieux. ---> d'où ma recommandation (et puis ça vous oblige ensuite à rebooter, l'utilisateur ne peut plus rien faire)

J-M-L: En pratique vous testez while (eeAddress [color=red]>[/color] EEPROM.length()-2) { si c'est strictement supérieur donc ça veut dire que si c'est inférieur ou égal vous continuez. Donc si vous arriviez avec eeAddress égal à 1022 vous passeriez votre while et iriez écrire 3 octets en 1022, 1023 et 1024... hors il n'y a pas de case mémoire N° 1024.

Dans votre cas ça n'arrive pas parce que vous commencez à remplir la mémoire à 0 et en augmentant de 3 en 3 eeAddress ne vaudra jamais 1022 mais si par hasard vous aviez décidé de commencer à écrire en 2 (pour avoir les 2 premiers octets pour un N° de version par exemple) alors vous auriez vos enregistrements de 3 octets en [2,3,4] puis [5,6,7] puis [8,9,10] puis ... [1019,1020,1021] et là votre pointeur est en 1022, le test foire et vous débordez...

Ce que vous dites est juste, mais justement mon while() n'est pas là pour remplir la mémoire, mais pour arrêter de la remplir, donc si eeAddress = 1022, je ne remplis pas et j'affiche "EEPROM pleine" OK pour le reste

Erwan19:
Ce que vous dites est juste, mais justement mon while() n’est pas là pour remplir la mémoire, mais pour arrêter de la remplir, donc si eeAddress = 1022, je ne remplis pas et j’affiche “EEPROM pleine”
OK pour le reste

Non parce que vous faites strictement supérieur dans le code, pas supérieur ou égal.
cf Votre boucle:while (eeAddress > EEPROM.length()-2) { // <<======= ICI
tant que 1022 > 1022 → test faux donc on passe le while et vous faites EEPROM.put(eeAddress, varTetM); qui déborderait

 void loop()
{  
float tempFour;                         // température du four en °C
long tpsMesure;                         // instant en millisecondes où l'on fait la mesure de temperature
struct TetM {                           // structure d'une ensemble de données non homogènes appelée TetM comprenant
  unsigned int temps;                   // l'instant en secondes de la mesure de température. On doit pouvoir faire 12 h de mesures soit 43200 secondes
  byte mesure;                          // la mesure de température du four
} varTetM;                              // définit une variable de type TetM appelée varTetM
static int eeAddress = 0;               // adresse ou l'on va écrire dans la mémoire EEPROM, initialisée à 0 qu'=au 1er appel de la fonction  
   
   
  tempFour = (float)analogRead(brocheThermoF)*500/1023;                 // lecture de valeur retournée par le thermomètre du four et conversion d'échelle: [0; 1023] en [0; 500°C]
  tpsMesure = millis();                                                 // on relève le nombre de secondes écoulées depuis le début du programme, et c'est l'instant de la mesure
    Serial.print(tpsMesure);Serial.print("\t");Serial.print(eeAddress/3);Serial.print("\t");Serial.println((int)tempFour);
    while (eeAddress > EEPROM.length()-2) {               // <<======= ICI
      lcd.clear();
      lcd.print("EEPROM pleine");
      delay(1000);
      lcd.noDisplay();                                                              // clignotement du message (1 s allumé, 0.5 s éteint)
      delay(500);
      lcd.display();
    }
    varTetM = {tpsMesure/1000, (int)tempFour};                                  // remplissage de la structure varTetM par l'instant de la mesure en secondes et la température du four en °C entiers
    EEPROM.put(eeAddress, varTetM);                                             // écriture de la structure en mémoire EEPROM à l'adresse eeAddress
    eeAddress+= 3;
}

OK J-M-L, ce que vous dites est tout à fait exact. J'avais mal interprété la signification de EEPROM.length() que je croyais égal à 1023, alors que c'est la longueur et non l'adresse du dernier octet, donc ça vaut 1024.

Cependant, après correction du défaut, ça ne change rien au problème, puisque, comme vous l'avez déjà dit, ma progression se fait de 3 en 3

Je ne sais pas si j’ai bien compris ce que voulais dire 68tjs, mais j’ai réécris l’écriture et la lecture sans faire appel aux fonctions EEPROM.put() et EEPROM.get(), donc également sans structure de 3 octets. J’écris donc dorénavant octet après octet. J’ai pris notes également des remarques de J-M-L. Mais malheureusement le problème demeure

Code de l’écriture

#include <LiquidCrystal.h>            // Inclusion de la librairie LiquidCrystal pour l'afficheur LCD
#include <EEPROM.h>                   // Inclusion de la librairie EEPROM pour stocker les données de mesure du capteur de température en mémoire EEPROM (non volatile) d'Arduino

// Déclaration des constantes de broches
const byte DB4 = 4;                   // cablage de l'entrée DB4 de l'afficheur LCD sur l'entrée/sortie numérique 4 d'Arduino
const byte DB5 = 5;                   // cablage de l'entrée DB5 de l'afficheur LCD sur l'entrée/sortie numérique 5 d'Arduino
const byte DB6 = 6;                   // cablage de l'entrée DB6 de l'afficheur LCD sur l'entrée/sortie numérique 6 d'Arduino
const byte DB7 = 7;                   // cablage de l'entrée DB7 de l'afficheur LCD sur l'entrée/sortie numérique 7 d'Arduino
const byte RS = 8;                    // cablage de l'entrée RS de l'afficheur LCD sur l'entrée/sortie numérique 8 d'Arduino
const byte E = 9;                     // cablage de l'entrée E de l'afficheur LCD sur l'entrée/sortie numérique 9 d'Arduino


const byte brocheThermoF = 1;         // cablage de la sortie analogique du capteur de température du four sur l'entrée analogique A2 d'Arduino

// --- Déclaration des objets ---
LiquidCrystal lcd(RS, E, DB4, DB5, DB6, DB7);   // Création de l'objet lcd avec initialisation de l'afficheur en mode 4 bits conformément au cablage du shield

void setup() 
{ 
  int x = 0;
  lcd.begin(16,2);  
  Serial.begin(9600);                 // initialise connexion série à 9600 bauds. Connexion nécessaire pour la mise à l'heure du RTC et l'interface graphique Processin
  while ( x < EEPROM.length())  {
    EEPROM.write(x, 0);                                             // écriture de la structure en mémoire EEPROM à l'adresse eeAddress
    x++;
    }
  mesureSauvegardeTemperature(); 
}


void loop()
{
}


void mesureSauvegardeTemperature()
{  
byte tempFour;                         // température du four en °C
unsigned int temps;                   // l'instant en secondes de la mesure de température. On doit pouvoir faire 12 h de mesures soit 43200 secondes
static int eeAddress = 0;               // adresse ou l'on va écrire dans la mémoire EEPROM, initialisée à 0 qu'=au 1er appel de la fonction  
   
   
 tempFour = analogRead(brocheThermoF);                 // épuration de la 1ère valeur du CAN
 while (eeAddress < EEPROM.length()-2) {               //tant que la capacité de l'EEPROM n'est pas dépassé
    tempFour = (byte)analogRead(brocheThermoF)*500/1023;      // lecture de valeur retournée par le thermomètre du four et conversion d'échelle: [0; 1023] en [0; 500°C]
    temps = millis();                                         // on relève le nombre de secondes écoulées depuis le début du programme, et c'est l'instant de la mesure
    delay(20);
    Serial.print(temps);Serial.print("\t");Serial.print(eeAddress/3);Serial.print("\t");Serial.println((int)tempFour);
    EEPROM.write(eeAddress, temps >> 8);                      // écriture en mémoire EEPROM à l'adresse eeAddress des 8 bits de poids fort de temps
    EEPROM.write(eeAddress+1, temps & 0x00FF);                // écriture en mémoire EEPROM à l'adresse eeAddress+1 des 8 bits de poids faible de temps
    EEPROM.write(eeAddress+2, tempFour);                      // écriture en mémoire EEPROM à l'adresse eeAddress+2 des 8 bits de mesure
    eeAddress += 3;
  }
      lcd.clear();
      lcd.print("EEPROM pleine");
}

Code de la lecture

#include <EEPROM.h>                   // Inclusion de la librairie EEPROM où sont stocké les données de mesure du capteur de température


void setup() {
// Déclarations des variables locales
unsigned int temps;                   // l'instant en secondes de la mesure de température
byte mesure;                          // la mesure de température du four
int eeAddress = 0;                      // adresse ou l'on va lire dans la mémoire EEPROM

    Serial.begin(9600);                 // initialisation de la liaison série
  while(eeAddress < EEPROM.length()-2)  {     // Tant que l'on n'est pas sur la dernière adresse de l'EEPROM -2 (le -2 est necessaire car il faut pouvoir mémoriser toutes la structure qui occupe 3 octects)
    temps = EEPROM.read(eeAddress) << 8;            // Lecture de l'EEPROM à l'adresse eeAdress des 8 bits de poids fort de temps
    temps += EEPROM.read(eeAddress+1);              // Lecture de l'EEPROM à l'adresse eeAdress+1 des 8 bits de poids faible de temps et qu'on rajoute au précédent
    mesure = EEPROM.read(eeAddress+2);              // Lecture de l'EEPROM à l'adresse eeAdress+2 des 8 bits de mesure
    Serial.print(eeAddress/3);Serial.print("\t");Serial.print(temps);Serial.print("\t");Serial.println(mesure);   // Ecriture dans le terminal série pour être copié ensuite sous Excel avec un control C
    eeAddress +=3;                              // on passe à l'adresse de la structure suivante, soit un pas de 3 (1 int = 2 octects et 1 byte = 1 octect)
    delay(10);
  } 
}

void loop() 
{

}

Bonsoir
je n’ai pas été voir comment sont écrites les fonctions d’écriture en EEPROM dans la librairie et ne connais donc pas leur timing… à tout hasard je tenterai un petit delay(x) entre chaque écriture en EEPROM…ça ne coute pas grand chose d’essayer…

tempFour = (byte)analogRead(brocheThermoF)*500/1023;

A mon Avis une valeur de 0 à 500 ca ne rentre pas dans un byte. Et faire du calcul entier hum....

Temps devrait être un unsigned long (millis() comme son nom l’indique étant des ms pas des s)

(Pas de soucis de timing - la librairie fait ça bien - vider la mémoire au début prend du temps cependant)

A Al1fch: J'ai déjà un délai de 20 ms entre chq écriture, ça n'a rien changé

A J-M-L: La température du four ne dépasse pas 150°C, donc pas de souci de l'avoir défini comme un byte. Temps est bien dans le programme réel un unsigned long puisque la mesure dure 40 800 000 ms. Mais dans l'extrait de programme que j'ai publié, pour remplir mon EEPROM rapidement, les mesures et écritures s'enchainent les une après les autres après un délai de 20 ms. L'EEPROM est ainsi remplie en 9300 ms, dont Temps peut être un unsigned int.

Je rappelle que l'écriture et la lecture se font correctement si il n'y a pas de coupure d'alimentation de la carte. Donc s'il devait y avoir un souci de définition de variables, le problème existerait de manière permanente. Chose plus intrigante encore: si je fais une 1ère lecture sans avoir coupée l'alim, elle est correcte comme je viens de le dire, et si après une 1ère lecture, je coupe l'alimentation, toutes les lectures suivantes sont également bonnes. Mais si l'alim est coupée avant la 1ère lecture, des données sont perdues

Bonjour

je viens de tester les 2 programmes lecture et écriture sur une carte analogue à la Leonardo

Deux petites modifs :

-l'une nécessaire à la Leonardo pour attendre la disponibilité du port série après téléchargement

    Serial.begin(9600);                 // initialisation de la liaison série
     while (!Serial) {
    ; // wait for serial port to connect. Needed for native USB port only
  }

-l'autre pour ménager une petite pause de 10ms entre les écritures en EEPROM (l'écriture en EEPROM implique la mise en route d'une pompe de charge interne pour créer la tension nécessaire , si la tension n'est pas correcte l'écriture n'est pas robuste)

    EEPROM.write(eeAddress, temps >> 8);                      // écriture en mémoire EEPROM à l'adresse eeAddress des 8 bits de poids fort de temps
    delay(10);
    EEPROM.write(eeAddress + 1, temps & 0x00FF);              // écriture en mémoire EEPROM à l'adresse eeAddress+1 des 8 bits de poids faible de temps
    delay(10);
    EEPROM.write(eeAddress + 2, tempFour);                    // écriture en mémoire EEPROM à l'adresse eeAddress+2 des 8 bits de mesure
    eeAddress += 3;

4 essais successifs d'écriture, coupure d'alimentation puis lecture donnent après remise en marche de la carte des données lues identiques à celles affichées à l'issue de l'écriture, et ce pour la totalité des 340 lignes.

je suis resté sur l'idée d'un timing critique parce quelque les symptômes me font penser à une charge incomplète des grilles flottantes des MOS composant l'EEPROM

Erwan19:
les mesures et écritures s’enchainent les une après les autres après un délai de 20 ms. L’EEPROM est ainsi remplie en 9300 ms, dont Temps peut être un unsigned int

L’effacement des données dans la première partie peut prendre jusqu’à 3.3 ms x 1024 = 3,4 secondes et dans la seconde partie vous avez un delay(20) et 3 écritures d’octets donc environ 10ms de plus soit 30ms par enregistrement vous en faites 341donc 10.5 secondes

→ au total pour un cycle complet d’éxécution il vous faut sans doute donc environ 14 secondes

Erwan19:
Mais si l’alim est coupée avant la 1ère lecture, des données sont perdues

et vous coupez quand l’alimentation? si vous n’attendez pas les 14 secondes c’est sûr que la mémoire ne sera pas remplie.

Erwan19:
A J-M-L: La température du four ne dépasse pas 150°C, donc pas de souci de l’avoir défini comme un byte.

C’est un problème quand même parce que le calcul se fait en entier tel que vous l’avez écrit ce qui conduit à une mesure erronée. Essayez ce petit programme:

void setup() {
  byte tempFourEntier;
  byte tempFourFlottant;
  int analogValue;

  Serial.begin(115200);
  for (analogValue = 0; analogValue < 1024; analogValue++) {
    tempFourEntier = (byte) analogValue * 500 / 1023;

    tempFourFlottant = (byte) (analogValue * 500.0 / 1023);  // force le calcul en nombre flottant puis on tronque dans un byte
    if (tempFourEntier != tempFourFlottant) {
      Serial.print(F("Valeur analogique: ")); Serial.print(analogValue);
      Serial.print(F("\tentier: ")); Serial.print(tempFourEntier);
      Serial.print(F("\tFlottant: ")); Serial.println(tempFourFlottant);
    }
  }
}

void loop() {}

→ vous verrez que pour une valeur de lecture analogique entre 66 et 1023 vous n’obtenez pas le bon résultat avec votre formule. la console série affichera

[sub][color=purple]
Valeur analogique: 66	entier: 225	Flottant: 32
Valeur analogique: 67	entier: 225	Flottant: 32
Valeur analogique: 68	entier: 226	Flottant: 33
Valeur analogique: 69	entier: 226	Flottant: 33
Valeur analogique: 70	entier: 227	Flottant: 34
Valeur analogique: 71	entier: 227	Flottant: 34
....
Valeur analogique: 1020	entier: 252	Flottant: 242
Valeur analogique: 1021	entier: 252	Flottant: 243
Valeur analogique: 1022	entier: 253	Flottant: 243
Valeur analogique: 1023	entier: 253	Flottant: 244
[/color][/sub]

al1fch: je suis resté sur l'idée d'un timing critique parce quelque les symptômes me font penser à une charge incomplète des grilles flottantes des MOS composant l'EEPROM

Merci Al1fch d'avoir pris le temps de faire cet essai. J'ai, comme tu le proposes, ajouté 10 ms, et même 20 ms, entre chq écriture d'octets (moi je n'avais fait de pose qu'après l'écriture d'un trio, ce qui était une erreur), mais j'ai toujours le même problème!

Ma carte aurait-elle un souci???

Erwan19:
Merci Al1fch d’avoir pris le temps de faire cet essai. J’ai, comme tu le proposes, ajouté 10 ms, et même 20 ms, entre chq écriture d’octets (moi je n’avais fait de pose qu’après l’écriture d’un trio, ce qui était une erreur), mais j’ai toujours le même problème!

Ma carte aurait-elle un souci???

il n’y a aucun besoin de faire une attente, c’est géré au niveau bas par la fonction eeprom_write_byte()

si vous regardez la fonction put, vous verrez qu’elle balance tous les octets sans faire de pause et ça fonctionne très bien

 template< typename T > const T &put( int idx, const T &t ){
        EEPtr e = idx;
        const uint8_t *ptr = (const uint8_t*) &t;
        for( int count = sizeof(T) ; count ; --count, ++e )  (*e).update( *ptr++ );
        return t;
    }

Erwan19:
Ma carte aurait-elle un souci???

essayez avec rien de branché sur votre carte. Un test tout bête d’écriture dans la mémoire… par exemple avec ce code

#include <EEPROM.h>

uint16_t EEPROM_SIZE;

void viderEEPROM()
{
  digitalWrite(LED_BUILTIN, HIGH);
  for (uint16_t adresse = 0; adresse < EEPROM_SIZE; adresse++) {
    Serial.write('.');
    if (((adresse + 1) % 32) == 0) Serial.write('\n');
    EEPROM.write(adresse, 0);
  }
  digitalWrite(LED_BUILTIN, LOW);
}

void ecrireEEPROM()
{
  digitalWrite(LED_BUILTIN, HIGH);
  for (uint16_t adresse = 0; adresse < EEPROM_SIZE; adresse++) {
    Serial.write('.');
    if (((adresse + 1) % 32) == 0) Serial.write('\n');
    EEPROM.write(adresse, (byte) adresse );
  }
  digitalWrite(LED_BUILTIN, LOW);
}

void verifierEEPROM()
{
  uint16_t nbErreurs = 0;

  digitalWrite(LED_BUILTIN, HIGH);
  for (uint16_t adresse = 0; adresse < EEPROM_SIZE; adresse++) {
    byte attendu = adresse % 256;
    byte lu = EEPROM.read(adresse);
    if ( attendu != lu) {
      Serial.print(F("ERREUR @"));
      Serial.print(adresse);
      Serial.write('\t');
      Serial.print(F("LU="));
      Serial.print(lu);
      Serial.print(F("\tATTENDU="));
      Serial.println(attendu);
      nbErreurs++;
    }
  }
  digitalWrite(LED_BUILTIN, LOW);

  if (nbErreurs == 0) Serial.println(F("EEPROM COHERENTE"));
}

void setup() {
  Serial.begin(115200);
  pinMode(LED_BUILTIN, OUTPUT);
  digitalWrite(LED_BUILTIN, LOW);

  EEPROM_SIZE = EEPROM.length();

  Serial.println(F("\n------ TEST EEPROM -------\n"));
  Serial.println(F("\n------ RESET EEPROM -------\n"));
  viderEEPROM();

  Serial.println(F("\n------ ECRITURE EEPROM -------\n"));
  ecrireEEPROM();

  Serial.println(F("\n------ TEST EEPROM -------\n"));
  verifierEEPROM();
}

void loop() {}

quand le fais tourner sur mon Arduino UNO j’obtiens

[sub][color=purple]

------ TEST EEPROM -------


------ RESET EEPROM -------

................................
................................
................................
................................
................................
................................
................................
................................
................................
................................
................................
................................
................................
................................
................................
................................
................................
................................
................................
................................
................................
................................
................................
................................
................................
................................
................................
................................
................................
................................
................................
................................

------ ECRITURE EEPROM -------

................................
................................
................................
................................
................................
................................
................................
................................
................................
................................
................................
................................
................................
................................
................................
................................
................................
................................
................................
................................
................................
................................
................................
................................
................................
................................
................................
................................
................................
................................
................................
................................

------ TEST EEPROM -------

EEPROM COHERENTE
[/color][/sub]