Verständnisfrage EEPROM schreiben

Guten Morgen,

habe eine Verständnisfrage zum schreiben auf EEPROM 24C08....

Das EEPORM hat 8K, Organisiert als 1024 x 8 Bit.

ich kann also mit
Wire.beginTransmission(i2c_eeprom_adr);
Wire.write(Byte-Adr.)

direkt in die Speicherbytes 0-127 (1024/8) maximal die Zahlenwerte 0-255 schreiben.
Diese sollte dann auf Page 0 gespeichert sein.

Jetzt möchte ich z.B. den Wert 500 in Adr. 0 schreiben.

mit

Wire.beginTransmission(0x50)
Wire.write(0)
Wire.write(255)

kann ich dann auf Page0 den Wert 255 schreiben

und mit

Wire.beginTransmission(0x50)
Wire.write(0 | 1) <<<<<<<<<<<< hier die Umschaltung auf Page 1 (oder 2-7.)
Wire.write(245)

den Rest schreiben.

meine Frage ist jetzt, funktioniert das mit der Page - Steuerung so wie oben beschrieben?
Ich würde gerne jede Speicherzelle Byteweise beschreiben.., die Codesegmente sind nur
lückenhaft, es fehlen natürlich noch einige Zeilen und delays...

Vielen Dank und alles Gute für 2016!

Beim Schreiben einzelner Bytes brauchst Du Dich nicht um die Pages zu kümmern. es genügt die Adresse anzugeben.

Um die Pages mußt Du Dich beim Brust-schreiben (sequenzielles Schreiben /lesen von mehreren Bytes nacheinander ohne immer wieder die Adresse einzugeben zu müssen) kümmern, da dies nicht über Pagesgrenzen hinaus funktioniert bzw die Daten an den Anfang der gleichen Page geschrieben werden und nicht in die nächste Page.
Grüße Uwe

Naja...
Wenn man den Wert 500 schreiben möchte, kann schon passieren, dass u.U. eine Pagegrenze überschritten wird.

Meine Frage ist eher "funktionell" gedacht, funktioniert denn das so mit dem schreiben auf einzelne Pages, wie im Beispiel oben?

Hintergrund ist folgender, ich habe 4 Sensoren deren Werte ich voraussichtlich halbstündlich abspeichern möchte.
und ich hätte das gerne so abgespeichert:

Messung 1 Sensor 1 = Adr. 0, Page0
Sensor 2 = Adr. 0, Page1
Sensor 3 = Adr, 0, Page2
Sensor 4 = Adr. 0, Page3

Messung 2 Sensor 1 = Adr. 1, Page 0
usw... bis Messung 128, danach wieder von 0 beginnend... überschreiben

Wobei die Werte je Sensor nur zwischen 0 und 200 liegen werden, die gespeichert werden sollen.

Ähm...
Warum hast du dich so auf Pages fixiert?

Du denkst zu kompliziert.

http://www.st.com/st-web-ui/static/active/en/resource/technical/document/datasheet/DM00070057.pdf
Zuerst hat das 24C08 die Eigenart nur eine 8Bit Adresse für die Ansteuerung der Speicherzelle in I2C Protokoll zu übermitteln. Die restlichen 2 notwendigen Bits ergeben sich aus der I2C Device-Adresse (siehe Tabelle auf Seite 13 Datenblatt).

Das EEprom hat Pages zu 16 Byte. Du kannst darum 16 Byte in einem Rutsch übermitteln (page write bzw Page read) wobei das erste Byte aber am Pagesanfang stehen muß (alle 16 Byte in der gleichen Page).
Die Page gehen von den Ardessen 0 bis 15, 16 bis 31 ecc) (siehe Seite 16 Datenblatt).

Natürlich kannst Du Daten auf den Adressen 0, 16, 32, und 48 abspeichern, aber ich sehe weder die Notwendigkeit noch einen Sinn.
Du hast aber viel heufigere Writezyklen da Du auch in der gleichen Page alle Daten der 4 Sensoren in einem Rutsch abspeichern kannst.

Grüße Uwe

24C08 .... www.st.com

Ich tippe da eher auf ein AT24C08 ...
Aber ich weiß es nicht. No!

Und auch egal, habe keins von beidem zum Testen hier....

Der AT24c08 scheint mir kompatibel zu dem von ST zu sein.

Grüße Uwe

Die Kombination aus Page und Adresse in der Page kann man mit Division und Modulo-Division berechnen:

z.B. 0-1023 mit 256 Byte Pages:

2: 2 / 256 = 0, 2 % 256 = 2
300: 300 / 256 = 1, 300 % 256 = 44
1023: 1023 / 256 = 3, 1023 % 256 = 255

Damit muss man nicht in Pages denken sondern hat einen sequentiellen Adressraum

Es sind 16 Byte Pages.

War ja nur ein theoretisches Beispiel um das Prinzip zu zeigen. Geht genauso mit anderen Größen

@Serenifly

Die Kombination aus Page und Adresse in der Page kann man mit Division und Modulo-Division berechnen

Das fehlt mir noch in meinen (nichtvorhandenen) Multibyte Funktionen

uwefed:
Es sind 16 Byte Pages.

Hmm...
Vielleicht so besser: (?)
256 Byte Pages, welche wiederum in 16 Byte Rows unterteilt sind.

uwefed:
Der AT24c08 scheint mir kompatibel zu dem von ST zu sein.

Softwareseitig, wohl ja, scheint mir....

Der folgende Code ist völlig ungetestet, da ich keinen einzigen vergleichbaren Baustein im Zugriff habe. Wäre schön wenn das jemand tun könnte.....

Also: Keine Garantie auf garnichts.

#include <Wire.h>

/*
 * Verwendbar für 24C01 , 24C02 , 24C04 , 24C08 24C16
 * Wenn die EEProm Adressen (A0 bis A2) fortlaufend vergeben sind,
 * reicht eine I2cEeprom Instanz um mehrere Bausteine anzusprechen.
 * 
 * Ausnahmen: 
 * Der 24C16, der nutzt schon alle Adressen
 * Bei mehreren 24C01 entstehen Doppeleinblendungen im Adressraum, 
 * denn er nutzt nur 7 Bit adressen, eine Page ist also nur 
 * 128 Byte groß.
 * 
 * Die anderen Bausteine fügen sich Nahtlos aneinander.
 * 
 * 
 * Kompatibilität:
 * Die Zugriffsmethoden dieser Klasse sind aufrufkompatibel mit 
 * der original Arduino EEPROM Library. Also sollten die dort   
 * mitgelieferten Beispiele grundsätzlich funktionieren.
 * 
 * Ausnahme: 
 * Das Array Access Interface ist nicht implementiert. Die darauf 
 * basierenden Beispiele funktionieren nicht.
 * 
 * Desweiteren muss eine Instanz der Klasse erzeugt werden.
 * Die orginallib macht das automatisch.
 * 
 * ToDo:
 * Adressüberschreitungen abfangen
 * Array Access implementieren
 * Multibyte Read&Write, also schreiben in 16 Byte Row Durchgängen
 * 
 */


class I2cEeprom
{
  private:
  uint8_t busAddress;

  public:
  I2cEeprom(uint8_t busAddress):busAddress(busAddress){}
  
  uint8_t read(uint16_t address)
  {
     uint8_t result = 0; 
     int Adresse =  busAddress + (address >> 8);
     Wire.beginTransmission(Adresse); 
     Wire.write(address & 0x00ff);       
     Wire.endTransmission();    
     Wire.requestFrom(Adresse,1);
     if (Wire.available()) result = Wire.read();
     return   result; 
  }
  
  void write(uint16_t address,uint8_t value)
  {
     int Adresse =  busAddress + (address >> 8);
     Wire.beginTransmission(Adresse); 
     Wire.write(address & 0x00ff);       
     Wire.write(value);             
     Wire.endTransmission();    
  }
  
  void update(uint16_t address,uint8_t value)
  {
    uint16_t old = read(address);
    if (old != value) write(address,value);
  }
  
  template< typename T >
  T &get(uint16_t address, T &customvar)
  {
    uint8_t *ptr = (uint8_t*) &customvar;
    for(int i = 0; i < sizeof(T); i++)
      *ptr++ = read(address + i);
    return &customvar;
  }

  template< typename T >
  T put(uint16_t address,T &customvar)
  {
    uint8_t *ptr = (uint8_t*) &customvar;
    for(int i = 0; i < sizeof(T); i++)
       update(address + i,*ptr++);
    return &customvar;
  }
  // EEPROM[]
};

I2cEeprom eep(0x50); // Instanz anlegen mit der I2C Basisadresse 0x50

void setup() 
{
  Wire.begin();
  eep.update(0,112); // 112 an die Adresse 0 schreiben. (wenn nicht schon geschehen)
}

void loop() {
  // put your main code here, to run repeatedly:

}

Hmm...
Vielleicht so besser: (?)
256 Byte Pages, welche wiederum in 16 Byte Rows unterteilt sind.

Es sind 64 Pages zu je 16 Byte beim 24C08.
Grüse Uwe

Ja, warum ich da zu kompliziert denke weis ich nicht...

ich habe bislang, wenn ich ein ext. EEPROM benötigt habe, immer nur einzelne Bytes an in div. Adr. geschrieben.

Da A0-A2 alle auf GND sind, sollte die Dev-Adr. ja 0x50 sein?

ich habe dann also an Adr. 0x50, Platz 0- (ich glaub) 127 gesendet, und das klappte auch,
eine Speicherzelle mit Adr. 0x50, Platz 200 z.B. konnte ich nicht beschreiben/lesen,..,

ich glaub da muss ich jetzt nachmals drüber schlafen und das Datenblatt des EEPROM nochmals lesen,
es ist übrigens von ST!

Danke vorerst

Da A0-A2 alle auf GND sind, sollte die Dev-Adr. ja 0x50 sein?

Nein.
Die ersten 256 Byte findest Du auf der Adresse 0x50 die nächsten auf der Adresse 0x51, 0x52 bzw 0x53

Mit A2 kannst Du 2 EEprom am gleichen I2C Bus betreiben mit Adressen von 0x50-0x53 bzw 0x54 bis 0x58

A1 und A0 sind beim 24C08 nicht benutzt.

Grüße Uwe

Wobei es da einfacher ist nur mit der Basis-Adresse 0x50 zu denken. Die Page/Seite kann man mit einem bitweisen ODER zur I2C-Adresse hinzufügen bevor man die Adresse auf den Bus schreibt.

Aha, jetzt komm ich etwas weiter..

ich dachte immer, ich kann alle Zellen unter 0x50 erreichen,...

aber, unter 0x50 sollte es dann ja die Zellen 0-255 (Byteweise) ansprechen können,
das hat bei mir bislang nicht geklappt, es ging nur bis Zelle 127, danach kamen nur falsche
Werte beim auslesen zurück.. Warum?
Kann ich nicht direkt in die höheren Zellen schreiben?

Tja.....

Ich könnte mal sagen: Zeig mal deinen Code!
Oder: Probiere doch mal meine Klasse aus... (egoistisch, oder?)

Hast du vielleicht ein EEPROM mit 128 Byte Pages? Das müsste man dann wirklich mal abklären.

Das ist aber auch sehr verwirrend. Es gibt nämlich das 24C08B. Das hat 4 * 256 Bytes für 8kBit

Du kannst es so machen (mal für 256 Bytes Pages angenommen, aber das kann man anpassen wenn es doch anders ist)

const byte DEVICE_ADR = 0x50;
const unsigned int PAGE_SIZE = 256;

void writeByte(unsigned int adr, byte data)
{
   byte page = adr / PAGE_SIZE;
   adr = adr % PAGE_SIZE;

   Wire.beginTransmission(DEVICE_ADR | page);
   Wire.write((byte)adr);
   Wire.write(data);
   Wire.endTransmission();
}

byte readByte(unsigned int adr)
{
   byte page = adr / PAGE_SIZE;
   adr = adr % PAGE_SIZE;

   Wire.beginTransmission(DEVICE_ADR | page);
   Wire.write((byte)adr);
   Wire.endTransmission();

   return Wire.read();
}

Nicht getestet!

adr ist dabei eine Adresse durchgehend über alle Pages von 0 bis zur höchsten Speicherzelle!

Und wenn du Multi-Byte Datentypen hast rufst du mehrmals readByte() oder writeByte() auf. Dadurch entsteht zwar etwas Overhead wenn man in einer Seite ist, aber der Zugriff über Seiten-Grenzen hinaus ist sehr einfach.

Hab jetzt noch schnell nachgeschaut, das EEPROM ist von ST und trägt die Aufschrift 24C08WP 78277 325.

Den Code den ich nutze, muss ich von einem anderen PC kopieren, ist aber eigentlich nur so wie oben

Wire.beginTransmission(0x50);
Wire.write((250); <<- hier stehen dann die Adr. 0-255 - was aber nur von 0-127 funktioniert
Wire.write(100); <<- hier sehen dann die zu speichernden Werte von 0-255.
Wire.endTransmission();

melde mich morgen wieder! Danke!