Soucis avec EEPROM I2C - 24C64 (Résolu)

Bonjour,

Une fois de plus, petit mail pour vous appeler au secours.....
j’essaie de mettre en œuvre une Eeprom (24C64 en I2C) pour faire de la sauvegarde de paramètres et peut-être un peu plus, mais gros problèmes !
je n'arrives pas à la faire fonctionner avec des entiers non signés :frowning:

après pas mal de recherches, j'ai fait une version Byte qui me permet d'écrire puis récupérer mes données sans problèmes
mais rien à faire pour la version orientée INT (celle qui m'intéresse), bien l'impression que ça n'écrit pas ou du moins très mal, je m'obstine à penser que je me plante dans les conversions de type (et oui, encore sérieusement débutant...), mais je vois plus !

si une âme charitable avait un petit moment à perdre (sans sourire de mes erreurs :wink: pour m'aider à y voir plus clair.......

merci d'avance,

(je vous met les fichiers en PJ)

Test24C64_BYTE_OK.ino (3.15 KB)

Test24C64_INT_PasOK.ino (4.69 KB)

Bonjour,

Un peu de documentation concernant la sauvegarde de paramètres en EEPROM :
http://arduino.cc/playground/Code/EEPROMLoadAndSaveSettings
http://arduino.cc/playground/Code/EEPROMWriteAnything

Et plus généralement sur les EEPROM I2C :
http://arduino.cc/playground/Code/I2CEEPROM

Dans ton code :

  • Quand on utilise pas de types "dure" tel que uint16_t (= unsigned int) il est plus lisible d'écrire :
sizeof(AI_C1) / sizeof(unsigned int)

au lieu de :

sizeof(AI_C1) / 2

Dans la partie sauvegarde :

unsigned int b = AI_C1[i] >> 8; //calcul MSB de l'entier
unsigned int c = AI_C1[i] & 0xFF; //calcul LSB de l'entier  
i2c_eeprom_write_byte(AdrBaseEeprom, byte(b) ); // écriture MSB
AdrBaseEeprom ++ ;  // adresse suivante
i2c_eeprom_write_byte(AdrBaseEeprom, byte(c) ); // écriture LSB
AdrBaseEeprom ++ ; // adresse suivante pour prochain tour
  • Tu travaille en "unsigned int", puis tu cast en byte, utilise plutôt directement un byte :wink:
byte b = AI_C1[i] >> 8; //calcul MSB de l'entier
byte c = AI_C1[i] & 0xFF; //calcul LSB de l'entier  
i2c_eeprom_write_byte(AdrBaseEeprom++, b); // écriture MSB
i2c_eeprom_write_byte(AdrBaseEeprom++, c); // écriture LSB

Même code mais condensé :

i2c_eeprom_write_byte(AdrBaseEeprom++, (AI_C1[i] >> 8)  & 0xFF); // écriture MSB
i2c_eeprom_write_byte(AdrBaseEeprom++, AI_C1[i] & 0xFF); // écriture LSB

Dans la partie lecture :

unsigned int b = i2c_eeprom_read_byte(AdrBaseEeprom); // chrgt MSB
AdrBaseEeprom ++ ; // octet suivant   
unsigned int c = i2c_eeprom_read_byte(AdrBaseEeprom); // chrgt LSB
AdrBaseEeprom ++ ; // octet suivant
unsigned int calcul = b << 8 + c; // reconstitution  INT
  • Même remarque que plus haut au sujet des types.
  • Pour le calcul du nombre final, n'utilise pas + (addition) mais | (ou logique) quand tu fait du "bitwish" (manipulation de byte).
    Le résultat est le même mais la façon de procéder n'est pas logique (assembler des bits = faire un ou logique, pas une addition).
  • De plus il est important de faire un cast en "type cible" de la partie MSB afin que le shift (<<) sache quelle est le nombre de décalages maximum possible.
byte b = i2c_eeprom_read_byte(AdrBaseEeprom++); // chrgt MSB
byte c = i2c_eeprom_read_byte(AdrBaseEeprom++); // chrgt LSB
unsigned int calcul = ((unsigned int)b << 8) | c; // reconstitution  INT

Et maintenant que je t'ai dit toute ces belles chose qui ne sont que des remarques, je peut t'annoncer d'ou vient ton bug :stuck_out_tongue:
-> tu ne stocke pas ta variable "calcul" dans ton tableau "AI_C1", c'est pas plus compliqué que ça :wink:

Il manque aprés la ligne "unsigned int calcul ..."

AI_C1[i] = calcul;

Une nouvelle fois, un énorme merci pour le temps que tu as passé sur mon problème.....

tes remarques sont super claires et efficaces, ce langage, votre dispo et votre facilité me bluffe toujours !

En fait, je découvre un peu ce langage et ose pas condenser à ce point, ça me fait toujours bizarre de mixer décalage d'un entier long, conversion en byte plus d'autres choses sur une même ligne de code..... :slight_smile:

Merci pour les liens, je me rends d'ailleurs compte que la base que j'avais trouvée est issue de celui vers les versions I2C, (la variante de gestion par page m'aurait d'ailleurs certainement évité mes soucis :wink:

J'ai donc essayé de suivre tes conseils et faire un peu mieux que ma première version :wink:
pour mon problème :
je n'avais volontairement pas traité " calcul ", le but était de le visualiser pour vérifier que les données source soient identiques aux données écrites.

Après pas mal de recherches, je me suis rendu compte que les appels consécutifs à ma routine d'écritures génèrent un fonctionnement aléatoire, à moins d'introduire un temps d'attente > 3ms entre chacun.
J'ai donc ajouté un delay(5) après chaque écriture et depuis plus de problèmes .......

Merci encore à toi et les animateurs de ce forum,

la version qui fonctionne là-dessous, pour ceux que ça pourrais intéresser,
(me reste à injecter tout ça dans mon code et vite finir mes mesures de température....)

#include <Wire.h> //I2C library
#include <LiquidCrystal_I2C.h>

#define ad_ROM_1_I2C 0x50
// définition des adresses I2C 
// Afficheur LCD a l'address 36Dec configure avec 20 car sur 4 lignes
LiquidCrystal_I2C lcd(0x24,20,4);

// variables a sauvegarder dans l'EEPROM
unsigned int AI_C1[] = {1234,5678,200,210,220,230,240,250,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,1,2,3,7,15,31,63,127,255,511,1023,2047,4095,8191,16383,32767,65535};

// routine d'ecriture de byte individuel dans l'EEPROM
// lui passer l'adresse, donnee, elle l'ecrit
  void i2c_eeprom_write_byte(unsigned int eeaddress, byte data ) 
  {
    Wire.beginTransmission(ad_ROM_1_I2C);
    Wire.write((int)(eeaddress >> 8)); // envoi du MSB de l'adresse
    Wire.write((int)(eeaddress & 0xFF)); // envoi du LSB de l'adresse
    Wire.write(data); //écriture de l'octet
    Wire.endTransmission();
    delay(5);// les écritures consécutives trop rapide mettent leur fiabilité en vrac (marche a partir de 3ms)    
  }

// routine de lecture de byte individuel dans l'EEPROM
// lui passer l'adresse, elle rend le byte correspondant
  byte i2c_eeprom_read_byte(unsigned int eeaddress ) 
  {
    byte rdata = 0xFF;
    Wire.beginTransmission(ad_ROM_1_I2C);
    Wire.write((int)(eeaddress >> 8)); // envoi du MSB de l'adresse
    Wire.write((int)(eeaddress & 0xFF)); // envoi du LSB de l'adresse
    Wire.endTransmission();
    Wire.requestFrom(ad_ROM_1_I2C,1);
    if (Wire.available()) rdata = Wire.read(); //lecture de l'octet adressé
    return rdata;
  }

void setup() 
{
    Wire.begin();  // Init port I2C
    lcd.init();    // initialisation du lcd 
    lcd.backlight();
    Serial.begin(9600);

    unsigned int AdrBaseEeprom =0; //adresse de l'EEPROM démarre à 0  
    for (int i=0; i<(sizeof(AI_C1) / sizeof(unsigned int)); i++) // boucle de balayage de la table
      {     
        unsigned int temp = AI_C1[i];
        i2c_eeprom_write_byte(AdrBaseEeprom++, (AI_C1[i] >> 8)  & 0xFF); // écriture MSB
        i2c_eeprom_write_byte(AdrBaseEeprom++, AI_C1[i] & 0xFF); // écriture LSB
        lcd.clear();
        lcd.setCursor(0,0);
        lcd.print("MAJ");
        lcd.setCursor(0,1);
        lcd.print("EEPROM"); 
      }
}

void loop() 
{
    //Lecture de l'EEPROM 
    unsigned int AdrBaseEeprom =0; //adresse de l'EEPROM démarre à 0
    for (int i=0; i<(sizeof(AI_C1) / sizeof(unsigned int)); i++) // boucle de balayage de la table
      {
        byte b = i2c_eeprom_read_byte(AdrBaseEeprom++); // chrgt MSB
        byte c = i2c_eeprom_read_byte(AdrBaseEeprom++); // chrgt LSB

// ligne a supprimer et remplacer par celle en commentaire dans version operationnelle
        unsigned int calcul = ((unsigned int)b << 8) | c; // reconstitution  INT
//        AI_C1[i] = ((unsigned int)b << 8) | c; // reconstitution  INT et MAJ

// sert a rien, a part verifier de visu que ce qui est écrit correspond aux valeurs qu'on a ecrit
        lcd.clear();
        lcd.setCursor(0,0);
        lcd.print("Valeur lue EEPROM ");
        lcd.setCursor(0,1);
        lcd.print(calcul);  // affiche Int calculé
        lcd.setCursor(0,2);
        lcd.print("Valeur Org ");
        lcd.setCursor(0,3);
        lcd.print(AI_C1[i]);// affiche variable de base    
         delay(1000);
      }   
}

legone:
tes remarques sont super claires et efficaces, ce langage, votre dispo et votre facilité me bluffe toujours !

Pas besoin de me vouvoyer, je suis pas ministre ou cadre supérieur :grin:

legone:
En fait, je découvre un peu ce langage et ose pas condenser à ce point, ça me fait toujours bizarre de mixer décalage d'un entier long, conversion en byte plus d'autres choses sur une même ligne de code..... :slight_smile:

Tu verras à force d'expérience on s'habitue à manipuler des types différents et à condenser les lignes de codes :wink:

legone:
J'ai donc essayé de suivre tes conseils et faire un peu mieux que ma première version :wink:
pour mon problème :
je n'avais volontairement pas traité " calcul ", le but était de le visualiser pour vérifier que les données source soient identiques aux données écrites.

Zut, je pensai avoir trouvé THE probléme :stuck_out_tongue:
(Du coup j'ai pas regardé la partie lcd mais juste tes calculs, le probléme était peut être dedans)

legone:
Après pas mal de recherches, je me suis rendu compte que les appels consécutifs à ma routine d'écritures génèrent un fonctionnement aléatoire, à moins d'introduire un temps d'attente > 3ms entre chacun.
J'ai donc ajouté un delay(5) après chaque écriture et depuis plus de problèmes .......

Il faut 3.3ms pour faire une écriture en EEPROM interne, mais avec une EEPROM I2C il ne devrait pas y avoir ce probléme ...

Si ça marche correctement en ajoutant un delay(5) tant mieux :grin:
(Juste pour l'info ton EEPROM est de quel fabricant (atmel, microchip, ...) ? -> AT24Cxx = ATMEL, 24LCxx = microchip)

eh eh !
t'inquiètes, te tutoie bel et bien, je faisait simplement également allusion à toi autant qu'a tous les piliers du forum.... vous me faites régulièrement tout simplement halluciner (y'as qu'a voir les inter Blyss ! :wink:

pour le langage, c'est maintenant que je vais souffrir, mes platines sont opérationnelles et gèrent leurs fonctions de base, mais reste à faire le cœur et là, je crains le pire ! :wink:

en ce qui concerne le chip, je suis pas sur de lire correctement le datasheet de microchip technoloy, mais il est fait allusion à un Write cycle time de 5 mS, ceci explique peut-être cela ?

Pour le fabricant, je n'arrive pas à identifier ce logo, mais voila ce qui est noté sur le chip :
CHN P
24C64WP
KVN720
ça te parleras surement plus qu'a moi,

legone:
t'inquiètes, te tutoie bel et bien, je faisait simplement également allusion à toi autant qu'a tous les piliers du forum.... vous me faites régulièrement tout simplement halluciner (y'as qu'a voir les inter Blyss ! :wink:

C'est vrai qu'on s'amuse bien sur certain projets :grin:

legone:
en ce qui concerne le chip, je suis pas sur de lire correctement le datasheet de microchip technoloy, mais il est fait allusion à un Write cycle time de 5 mS, ceci explique peut-être cela ?

Si c'est marqué "Write cycle : 5ms" c'est qu'il faut 5ms, faut pas chercher plus loin.
Je savais pas que les EEPROM I2C avait ce genre de "timing" ... c'est bon à savoir !

legone:
Pour le fabricant, je n'arrive pas à identifier ce logo, mais voila ce qui est noté sur le chip :
(..)
ça te parleras surement plus qu'a moi,

-> ST = STMicroelectronics
Je savais même pas qu'il faisait des EEPROM I2C ...