Arduino Nano e AT24C256

Buongiorno a chi mi legge

Con questo codice

scritto con Arduino IDE 2.3.6 e caricato su un Arduino Nano Clone old bootloader

mi succede che se salvo sulla Eeprom fino a 32 records di 8 bytes tutto funziona
correttamente, se provo a salvare 33 o più records i dati dei successivi ai 32 vanno a sovrascrivere quelli precedenti partendo dai primi (come se fosse un page overflow ma non mi pare che sia questo il caso)

allego il codice che uso per scrivere e quello che uso per leggere i dati sulla Eeprom

#include <Wire.h>
#include <AT24C256.h>

AT24C256 eeprom(0x50);

const long intervalSensor = 25;  // intervallo di lettura del sensore di pressione (millisecondi)
uint32_t currentMillis = 0;
uint32_t previousMillisSensor = 0;

uint16_t recordsCount = 0;

uint16_t maxRecordsCount = 32;

uint32_t myMillis = 0;   //|'
uint16_t pressione = 0;  //| valori di processo
float millimetri = 0;    //|,

bool finito = false;

//-----------------------------------------------------------------------------------
void setup() {
  Serial.begin(9600);
  delay(100);
  Serial.println();
  Serial.println("READY");
}
//----------------------------------------------------------------------------------
void loop() {
  if (recordsCount < maxRecordsCount) {
    currentMillis = millis();
    if (currentMillis - previousMillisSensor >= intervalSensor) {
      previousMillisSensor = currentMillis;

      myMillis = recordsCount * 100;
      pressione = recordsCount * 10;
      millimetri = millimetri + 0.25;

      recordRec(recordsCount, pressione, myMillis, millimetri);

      recordsCount++;
    }
  } else if (recordsCount >= maxRecordsCount) {
    if (!finito) {
      Serial.println("finito");
      finito = true;
    }
  }
}
void recordRec(uint16_t recordNumber, uint16_t pressione, uint32_t myMillis, float millimetri) {

  // questa parte è poco elegante ma con bitshift  non sono pratico

  uint8_t bytePressione[2];  // 2 byte per memorizzare il valore ADC del sensore di pressione 1 = MSB/0=LSB
  for (uint8_t i = 0; i < 8; i++) {
    bitWrite(bytePressione[0], i, bitRead(pressione, i));
  }
  for (uint8_t i = 0; i < 8; i++) {
    bitWrite(bytePressione[1], i, bitRead(pressione, i + 8));
  }

  uint8_t byteMillis[4];  // 4 byte per memorizzare i millisecondi 3=MSB /2/1/  0=LSB
  for (uint8_t x = 0; x < 4; x++) {
    for (uint8_t i = 0; i < 8; i++) {
      bitWrite(byteMillis[x], i, bitRead(myMillis, i + (x * 8)));
    }
  }

  uint8_t mmInt = (uint8_t)millimetri;  // tronca la parte decimale PARTE INTERA
  float mmDec = millimetri - mmInt;     // ricava la sola parte decimale PARTE DECIMALE
  mmDec = mmDec * 100.0;                // la moltiplica per 100 (rende interi due decimali)
  uint8_t mmDecX100 = round(mmDec);     // toglie eventuali decimali oltre i due

  uint8_t memArray[8];

  memArray[0] = byteMillis[0];
  memArray[1] = byteMillis[1];
  memArray[2] = byteMillis[2];
  memArray[3] = byteMillis[3];
  memArray[4] = bytePressione[0];
  memArray[5] = bytePressione[1];
  memArray[6] = mmDecX100;
  memArray[7] = mmInt;

  uint16_t moltiplicatore = 8;                          // cosi mi assicuro di passare un numero a 2 byte
  uint16_t memoryAddr = recordNumber * moltiplicatore;  // 1 record = 8 byte

  eeprom.write(memoryAddr, (uint8_t*)memArray, sizeof(memArray));

  delay(5);
}

e leggo con questo

#include <AT24C256.h>

AT24C256 eeprom(0x50);

uint8_t message[8];
uint16_t indirizzoEeprom = 0;
uint16_t howManyRecords = 33;  // 8 byte per record
uint16_t moltiplicatore = 8;

void setup() {

  Serial.begin(9600);
  delay(500);

  Serial.println("READY !!");

  Serial.println("reading eeprom");
  for (uint16_t i = 0; i < howManyRecords; i++) {
    indirizzoEeprom = i * moltiplicatore;
    eeprom.read(indirizzoEeprom, (uint8_t*)message, sizeof(message));
    Serial.print("Indirizzo di partenza : ");
    Serial.print(indirizzoEeprom);
    for (uint8_t i = 0; i < 8; i++) {
      Serial.print(" - ");
      Serial.print(message[i]);
    }
    Serial.println();
  }
}

void loop() {}

Sicuramente ho preso cipolla per ampolla da qualche parte, ma non riesco a venirne a capo ed avrei bisogno di registrare un migliaio di records in questa maniera.

p.s. : allegherei gli output del monitor seriale ma non so come si fa

E siccome penso che sia utile allego il codice della libreria che sto adoperando

Questa è la mia AT24C256.h

// 24C256 EEPROM driver header file
#ifndef AT24C256_h
#define AT24C256_h

#include "Arduino.h"
#include "Wire.h"

class AT24C256
{
public: 
		AT24C256(int address);
		void write(uint16_t writeAddress, uint8_t* data, uint8_t len);
//		void read(uint16_t readAddress, uint8_t* data, uint8_t len);
		void read(uint16_t readAddress, uint8_t* data, int len);

private:
		int _address;

};

#endif


e questo il relativo .cpp

//AT24C256 driver CPP file
#include "Arduino.h"
#include "Wire.h"
#include "AT24C256.h"

AT24C256::AT24C256(int address){
	Wire.begin();
	_address = address;
}

void AT24C256::write(uint16_t writeAddress, uint8_t* data, uint8_t len){

	Wire.beginTransmission(_address);
	Wire.write((byte)(writeAddress & 0xFF00) >> 8);
	Wire.write((byte)(writeAddress & 0x00FF));
	uint8_t i;
	for(i = 0; i < len; i++){
		Wire.write(data[i]);
	}
	Wire.endTransmission();

}

//void AT24C256::read(uint16_t readAddress, uint8_t* data, uint8_t len){
void AT24C256::read(uint16_t readAddress, uint8_t* data, int len){

	Wire.beginTransmission(_address);
	Wire.write((byte)(readAddress & 0xFF00) >> 8);
	Wire.write((byte)(readAddress & 0x00FF));
	Wire.endTransmission();

	Wire.requestFrom(_address, len);
	int i;
	for(i = 0; i < len; i++){
		if(Wire.available()) data[i] = Wire.read();
	}

}

le due modifiche da uint8_t a int le ho apportate perchè avevo un warning durante la compilazione ma non hanno sortito effetti risolutivi.

Il bug deriva dal fatto che l’AT24C256 possiede pagine da 64 byte, e la libreria che state usando non gestisce le scritture che superano la fine di una pagina. Quando scrivete un record di 8 byte a un indirizzo vicino alla fine di una pagina, i byte in eccesso “rimbalzano” all’inizio della stessa pagina, sovrascrivendo così i dati già presenti. Ecco perché tutto funziona fino al 32° record, ma quelli successivi sovrascrivono i primi.

Per esempio, se scrivete un record di 8 byte all’indirizzo 60 di una pagina da 64 byte, i primi 4 byte andranno correttamente agli indirizzi 60, 61, 62 e 63, ma i 4 byte restanti torneranno agli indirizzi 0, 1, 2 e 3 della stessa pagina, sovrascrivendo i dati già presenti a quegli indirizzi.

➜ Per correggere il problema, bisogna adattare la funzione di scrittura in modo che non superi mai il limite della pagina oppure suddividere automaticamente i blocchi.

Grazie dell'attenzione

mi pare che con sequenze di 8 bytes partendo dall'indirizzo zero quello che lei dice non dovrebbe succedere

infatti mi scrive 32 records da 8 bytes quindi l'ultimo indirizzo a cui la scrittura è corretta è (((32 x 8)-8) perchè parto da zero) l'indirizzo 248 che più 8 va fino a 255.

a partire dal 256 ho dei problemi, ma di pagine ne ho già scritte (256/64) 4.

Solo come idea, puoi cambiare il delay(5) in delay(10)?

Ancora grazie per l'interessamento

Credo di aver risolto
La libreria con quella conversione a byte non faceva passare bene l'indirizzo alla Wire, ne il scrittura ne in lettura

così funziona (senza libreria ciofeca)

write :

#include <Wire.h>

const long intervalSensor = 25;  // intervallo di lettura del sensore di pressione (millisecondi)
uint32_t currentMillis = 0;
uint32_t previousMillisSensor = 0;

uint16_t recordsCount = 0;

uint16_t maxRecordsCount = 300;

uint32_t myMillis = 0;   //|'
uint16_t pressione = 0;  //| valori di processo
float millimetri = 0;    //|,

bool finito = false;

//-----------------------------------------------------------------------------------
void setup() {
  Serial.begin(9600);
  delay(100);
  Wire.begin();
  Serial.println();
  Serial.println("READY");
}
//----------------------------------------------------------------------------------
void loop() {
  if (recordsCount < maxRecordsCount) {
    currentMillis = millis();
    if (currentMillis - previousMillisSensor >= intervalSensor) {
      previousMillisSensor = currentMillis;

      myMillis = recordsCount * 100;
      pressione = recordsCount * 10;
      millimetri = millimetri + 0.25;

      recordRec(recordsCount, pressione, myMillis, millimetri);

      recordsCount++;
    }
  } else if (recordsCount >= maxRecordsCount) {
    if (!finito) {
      Serial.println("finito");
      finito = true;
    }
  }
}
void recordRec(uint16_t recordNumber, uint16_t pressione, uint32_t myMillis, float millimetri) {

  // questa parte è poco elegante ma con bitshift  non sono pratico

  uint8_t bytePressione[2];  // 2 byte per memorizzare il valore ADC del sensore di pressione 1 = MSB/0=LSB
  for (uint8_t i = 0; i < 8; i++) {
    bitWrite(bytePressione[0], i, bitRead(pressione, i));
  }
  for (uint8_t i = 0; i < 8; i++) {
    bitWrite(bytePressione[1], i, bitRead(pressione, i + 8));
  }

  uint8_t byteMillis[4];  // 4 byte per memorizzare i millisecondi 3=MSB /2/1/  0=LSB
  for (uint8_t x = 0; x < 4; x++) {
    for (uint8_t i = 0; i < 8; i++) {
      bitWrite(byteMillis[x], i, bitRead(myMillis, i + (x * 8)));
    }
  }

  uint8_t mmInt = (uint8_t)millimetri;  // tronca la parte decimale PARTE INTERA
  float mmDec = millimetri - mmInt;     // ricava la sola parte decimale PARTE DECIMALE
  mmDec = mmDec * 100.0;                // la moltiplica per 100 (rende interi due decimali)
  uint8_t mmDecX100 = round(mmDec);     // toglie eventuali decimali oltre i due

  uint8_t memArray[8];

  memArray[0] = byteMillis[0];
  memArray[1] = byteMillis[1];
  memArray[2] = byteMillis[2];
  memArray[3] = byteMillis[3];
  memArray[4] = bytePressione[0];
  memArray[5] = bytePressione[1];
  memArray[6] = mmDecX100;
  memArray[7] = mmInt;

  uint16_t moltiplicatore = 8;                          // cosi mi assicuro di passare un numero a 2 byte
  uint16_t memoryAddr = recordNumber * moltiplicatore;  // 1 record = 8 byte
  uint8_t addrLow;
  uint8_t addrHigh;

  for (uint8_t i = 0; i < 8; i++) {
    bitWrite(addrLow, i, bitRead(memoryAddr, i));
  }

  for (uint8_t i = 8; i < 16; i++) {
    bitWrite(addrHigh, i - 8, bitRead(memoryAddr, i));
  }

  Wire.beginTransmission(0x50);
  Wire.write(addrHigh);
  Wire.write(addrLow);
  for (uint8_t i = 0; i < 8; i++) {
    Wire.write(memArray[i]);
  }
  Wire.endTransmission();
  delay(5);
}

read :

#include <Wire.h>

uint8_t message[8];
uint16_t indirizzoEeprom = 0;
uint16_t howManyRecords = 301;  // 8 byte per record
uint16_t moltiplicatore = 8;

void setup() {

  Serial.begin(9600);
  delay(500);
  Wire.begin();

  Serial.println("READY !!");

  Serial.println("reading eeprom");
  for (uint16_t i = 0; i < howManyRecords; i++) {
    indirizzoEeprom = i * moltiplicatore;

    uint8_t addrLow;
    uint8_t addrHigh;


    for (uint8_t i = 0; i < 8; i++) {
      bitWrite(addrLow, i, bitRead(indirizzoEeprom, i));
    }

    for (uint8_t i = 8; i < 16; i++) {
      bitWrite(addrHigh, i - 8, bitRead(indirizzoEeprom, i));
    }

    Wire.beginTransmission(0x50);
    Wire.write(addrHigh);
    Wire.write(addrLow);
    Wire.endTransmission();

    Wire.requestFrom(0x50, 8);

    for (uint8_t i = 0; i < 8; i++) {
      if (Wire.available()) {
        message[i] = Wire.read();
      }
    }


    Serial.print("Indirizzo di partenza : ");
    Serial.print(indirizzoEeprom);
    for (uint8_t i = 0; i < 8; i++) {
      Serial.print(" - ");
      Serial.print(message[i]);
    }
    Serial.println();
  }
}

void loop() {}

Ora posso mettere tutto in delle funzioni e rifinirlo un po', comunque funziona.

:+1: :+1: