Forum: Mikrocontroller und Digitale Elektronik Kuriose effekte beim beschreiben von EEprom 24C512


von Pascal G. (Firma: http://www.pgollor.de) (mc-kalle)


Lesenswert?

Hallo an alle Cracks, :)

ich habe ein Problem an dem ich mittlerweile seit ca. 30 Arbeitsstunden
sitze und so langsam mit meinem Latein am Ende bin.

Mein System:
- atmega32 wahlweise auch atmega16
- EEprom 24HC512
- Hardware TWI (100kHz) des µCs per Bibliothek von Peter Flury
- Debugausgabe per Uart
- avr-gcc 4.3.4
- 5V Versorgungsspannung
- 16 MHz Quarz am µc

Ein Problem mit der Bibliothek und der Hardware kann ich fast
ausschließen, da ich an dem I2C Bus noch weitere Bausteine angeschlossen
habe und diese einwandfrei funktionieren. Zum testen habe ich allerdings
meinen Code und meine Schaltung auf das nötigste beschränkt.

Ich möchte gerne viele Werte hintereinander in den Speicher schreiben.
Am Anfang schreibe ich ein paar Byte als Startwerte die ich später
benötige und anschließend kommt eine lange reihe von Messwerten. Bei
kleinen Messungen funktioniert dies auch sehr gut aber sobald ich über
4096 Byte komme treten sehr komische Effekte auf. Dazu aber gleich mehr.

Das schreiben in den EEprom erfolgt für jedes Byte nach einander. Ich
greife sowohl auf das acknowlege polling zurück und warte zusätzlich
zwischen dem schreiben der einzelnen Werte auf jeden Fall die 10ms die
der EEprom benötigt. Somit habe ich zu sowohl sichergestellt, dass werte
nicht verschluckt werden sowohl auch, dass die Aufteilung von 512 Seiten
im EEprom a 128 Byte mir egal sein sollte.

Das Phänomen ist jetzt folgendes: Sobald ich ein Byte mehr als 4096
schreibe wird automatisch das aller erste beschriebene Byte (bei dem ich
angefangen habe) nicht direkt überschrieben sondern mit dem neuen wert
per logischem UND verknüpft.

Um es verständlicher zu machen hier ein kleines Beispiel:

Adresse Wert
0       193
4095    97
4096    97   ---> hier wird aber NICHT der korrekte in 4096 geschrieben, 
sondern der
Werte in 0 und 4096 ist plötzlich 65. Das entspricht 193 & 97.
Als ob die beiden Speicherbereiche irgendwie mit einander verknüpft
wären.

Das Phänomen taucht nicht nur auf, wenn ich bei 0 anfange, sondern auch
wenn ich bei 60 oder 1000 anfange. Aber auch erst wieder nach 4096
Bytes.
Wenn ich dann noch weiter schreibe wird der geschriebene Wert mit dem 
Speicherbereich Start+1 Verknüpft und in beide Speicherbereiche 
geschrieben.

So langsam weiß ich einfach nicht mehr woran es liegen könnte. Die
Adresse zum beschreiben wird immer um 1 iteriert und als Word (16Bit) an
das EEprom gesendet.

Hier noch ein paar Ausschnitte aus meinem Code:

1
void eeprom_write(uint16_t addr, uint8_t val)
2
{  i2c_start_wait(Dev24C512+I2C_WRITE);
3
  //i2c_write( (addr/256) );
4
  //i2c_write( (addr%256) );
5
  i2c_write((addr>>8)&0xFF);
6
  i2c_write(addr&0xFF);
7
  i2c_write(val);
8
  i2c_stop();
9
10
  _delay_ms(20);
11
}
1
uint8_t eeprom_read(uint16_t addr)
2
{
3
  i2c_start_wait(Dev24C512+I2C_WRITE);
4
  //i2c_write( (addr/256) );
5
  //i2c_write( (addr%256) );
6
  i2c_write((addr>>8)&0xFF);
7
  i2c_write(addr&0xFF);
8
  i2c_rep_start(Dev24C512+I2C_READ);
9
  uint8_t ret = i2c_readNak();
10
  i2c_stop();
11
12
  return ret;
13
}

Simulation der Messwerte
1
for (uint16_t i = 0; i < 4096; i++)
2
{
3
  eeprom_write_inc(&cur_addr, 97);
4
5
  uint8_t val = eeprom_read(start);
6
  if (val != 0b11000001)
7
  {
8
    printf("val %x:%b" CR, start, val);
9
    printf("break %i %x i%i" CR, (cur_addr-1), (cur_addr-1), i);
10
    _delay_ms(10);
11
    break;
12
  }
13
}

eeprom_write_inc verweist auf eeprom_write nur dass sie zusätzlich den 
übergebenen Adresswert um eins erhöht.


Ich hoffe einfach, dass mir jemand von euch weiter helfen kann.


Gruß
Kalle

von thb4hw45 (Gast)


Lesenswert?

Oszilloskop an den Bus hängen und mitloggen, was da wirklich passiert.

von c-hater (Gast)


Lesenswert?

Pascal G. schrieb:

> Ich
> greife sowohl auf das acknowlege polling zurück

Wo? In dem geposteten Code ist davon jedenfalls nichts zu sehen.

von Pascal G. (Firma: http://www.pgollor.de) (mc-kalle)


Angehängte Dateien:

Lesenswert?

Moin erst einmal,

ich freue mich, dass sich so schnell schon jemand gemeldet hat um mir zu 
helfen.

thb4hw45 schrieb:
> Oszilloskop an den Bus hängen und mitloggen, was da wirklich passiert.

Ja daran habe ich natürlich auch schon gedacht, aber es ist leider nicht 
so einfach eins zu besorgen. Daher fällt das leider erst einmal flach.
Ich denke aber auch nicht, dass es so dringend notwendig ist, da ich mit 
der gleichen Bibliothek mehrere I2C Geräte (die zB auch einen kleinen 
EEprom dabei haben ähnlich dem 24C512) einwandfrei ansprechen kann. 
Darüber hinaus funktioniert es mit kleineren Datenmengen ja auch.
Außerdem tritt das Problem auch auf, wenn ich bei dem Beschreiben der 
Werte in der Mitte eine längere Pause mache.


c-hater schrieb:
> Pascal G. schrieb:
>
>> Ich
>> greife sowohl auf das acknowlege polling zurück
>
> Wo? In dem geposteten Code ist davon jedenfalls nichts zu sehen.

Tut mir leid, ich hatte angenommen, dass hier im Forum die Bibliothek 
von Peter Flury sehr bekannt ist und daher den Code nicht auch noch 
gepostet. Aber hier ein kleiner Ausschnitt dazu. Der Rest ist im Code 
als Anhang dabei.
1
/*************************************************************************
2
 Issues a start condition and sends address and transfer direction.
3
 If device is busy, use ack polling to wait until device is ready
4
 
5
 Input:   address and transfer direction of I2C device
6
*************************************************************************/
7
void i2c_start_wait(unsigned char address)
8
{
9
    uint8_t   twst;
10
11
12
    while ( 1 )
13
    {
14
      // send START condition
15
      TWCR = (1<<TWINT) | (1<<TWSTA) | (1<<TWEN);
16
    
17
      // wait until transmission completed
18
      while(!(TWCR & (1<<TWINT)));
19
    
20
      // check value of TWI Status Register. Mask prescaler bits.
21
      twst = TW_STATUS & 0xF8;
22
      if ( (twst != TW_START) && (twst != TW_REP_START)) continue;
23
    
24
      // send device address
25
      TWDR = address;
26
      TWCR = (1<<TWINT) | (1<<TWEN);
27
    
28
      // wail until transmission completed
29
      while(!(TWCR & (1<<TWINT)));
30
    
31
      // check value of TWI Status Register. Mask prescaler bits.
32
      twst = TW_STATUS & 0xF8;
33
      if ( (twst == TW_MT_SLA_NACK )||(twst ==TW_MR_DATA_NACK) ) 
34
      {          
35
          /* device busy, send stop condition to terminate write operation */
36
          TWCR = (1<<TWINT) | (1<<TWEN) | (1<<TWSTO);
37
          
38
          // wait until stop condition is executed and bus released
39
          while(TWCR & (1<<TWSTO));
40
          
41
          continue;
42
      }
43
      //if( twst != TW_MT_SLA_ACK) return 1;
44
      break;
45
     }
46
47
}/* i2c_start_wait */

Darüber hinaus ist es vermutlich für mein Problem nicht so relevant ob 
das Acknowlege Polling funktioniert oder nicht da ich im Moment zu 
Testzwecken ja sowieso die Doppelte Zeit warte die der EEprom zum 
Speichern benötigt.

Trotzdem habe ich das noch mal getestet. Wenn ich den Delay weglasse 
nach dem schreiben, dann werden einige Werte verschluckt, da das 
Acknowlege Polling anscheinend nicht 100% funktioniert. Auch nicht wenn 
ich es auf folgende Art nach baue:
1
aiagin:;
2
uint8_t r = i2c_start(Dev24C512+I2C_WRITE);
3
if (r != 0)
4
{
5
  i2c_stop();
6
  goto agian;
7
}

Falls ich mich aber irre, freue ich mich sehr über 
Verbesserungsvorschläge. Anscheinend muss ich an irgend einer Stelle ja 
einen Denkfehler haben.


Gruß
Kalle

von Sebastian W. (sebastian_w29)


Lesenswert?

24HC512? Original-IC oder Plagiat?

Ansonsten mal deinen kompletten Test-Quellcode.

LG, Sebastian

von Pascal G. (Firma: http://www.pgollor.de) (mc-kalle)


Lesenswert?

Sebastian W. schrieb:
> 24HC512? Original-IC oder Plagiat?

Ich habe mittlerweile zwei verschiedene denke ich getestet.
Das eine ist ein
ATMLU040
2FB 2
Im DIP8 Gehäuse. Das Ding von Atmel.

Und das andere IC ist im SOIC8 Gehäuase also als SMD Bauform. Drauf 
steht:
24512WA
Ich glaube dort ein Atmel Logo erkennen zu können, aber das kann auch 
nur ein Fake sein.

Sebastian W. schrieb:
> Ansonsten mal deinen kompletten Test-Quellcode.
Der komplette Code ist anbei. Ich hoffe, dass man halbwegs 
nachvollziehen kann was ich hier mache. Es ist sicherlich etwas 
umständlich, aber zum testen reicht es.

Eine Kurze Erklärung dazu:
Am Anfang schreibe ich überall Nullen rein damit ich immer die gleiche 
Ausgangslage habe.
Anschließend erfolgt eine kleine Ausgabe.
Dann werden die Startwerte geschrieben. Hierbei habe ich nur zum testen 
auf die Pagewrite Funktion zurück gegriffen.
Danach folgt wieder eine Ausgabe des gleichen Adressintervalls.
Darauf Folgend werden dann die Testmesswerte geschrieben. Hier habe ich 
gerade zum testen einmal nicht mehr jeden Werte, sondern jeden zweiten 
Wert geschrieben. Leider selbes Ergebnis. Das heißt beim Startwert + 
4096 Treten die gleichen Probleme wieder auf. Obwohl ich nur jeden 
zweiten Adresse beschreibe.
Am Ende erfolgt dann wieder eine Ausgabe der selben Bereiche.

Ich programmiere das ganze unter Ubuntu mit dem AVR Eclipse Plugin. Die 
Frequenz und der Controllertyp sind in den Einstellungen richtig 
eingestellt. Aber es macht auch kein Unterschied wenn ich das ganze mit 
einem eigenen Makefile kompiliere. Das heißt Probleme bei Eclipse sind 
auch eher aus zu schließen.
Ach so und die Fusebits sind wie fogl gesetzt:
low:CF
high:D9

Vielen Danke noch mal für die schnellen Antworten.


Gruß
Kalle

von Pascal G. (Firma: http://www.pgollor.de) (mc-kalle)


Angehängte Dateien:

Lesenswert?

Pascal G. schrieb:
> Der komplette Code ist anbei.

Man sollte auch nicht vergessen die Datei an zu hängen. ;-)


Gruß
Kalle

von Sebastian W. (sebastian_w29)


Lesenswert?

Ich kenn die I2C-Bibliothek nicht, aber i2c_start_wait gibt ja keinen 
Fehlercode zurück. Vielleicht solltest du in eeprom_read und 
eeprom_write mal alternativ i2c_start mit Auswertung des Rückgabewerts 
benutzen, vor allem, wenn du weder Logikanalyser (z.b Saleae & Co) noch 
Oszi hast.

von c-hater (Gast)


Lesenswert?

Pascal G. schrieb:

> Tut mir leid, ich hatte angenommen, dass hier im Forum die Bibliothek
> von Peter Flury sehr bekannt ist

Bei den C-lern vermutlich schon. Ich bin aber keiner, jedenfalls 
höchstens unfreiwillig. Wie auch immer...

Dein Code macht jedenfalls nicht das, was nötig wäre. Was das ist, steht 
im Datenblatt des 24C512 auf Seite 9.

> Darüber hinaus ist es vermutlich für mein Problem nicht so relevant

Im Gegenteil, das ist sogar höchst relevant, denn...

> Wenn ich den Delay weglasse
> nach dem schreiben, dann werden einige Werte verschluckt, da das
> Acknowlege Polling anscheinend nicht 100% funktioniert.

Eben. Genau das ist der springende Punkt. Du solltest du dich doch wohl 
ernsthaft fragen, warum das wohl so sein mag...

Ich würde mal folgende Fassung vorschlagen:

void eeprom_write(uint16_t addr, uint8_t val)
{
  i2c_start_wait(Dev24C512+I2C_WRITE);
  i2c_write((addr>>8)&0xFF);
  i2c_write(addr&0xFF);
  i2c_write(val);
}

Funktioniert das besser?

von Wilhelm F. (Gast)


Lesenswert?

Pascal G. schrieb:

> Am Anfang schreibe ich überall Nullen rein damit ich immer die gleiche
> Ausgangslage habe.

Sicher, daß da im Leerzustand Nullen drin sein sollen, und nicht Einsen?

Mit sowas hatte ich auch schon mal Probleme, allerdings bei einem 
anderen EEPROM-Typ.

von Pascal G. (Firma: http://www.pgollor.de) (mc-kalle)


Lesenswert?

Sebastian W. schrieb:
> Ich kenn die I2C-Bibliothek nicht, aber i2c_start_wait gibt ja keinen
> Fehlercode zurück. Vielleicht solltest du in eeprom_read und
> eeprom_write mal alternativ i2c_start mit Auswertung des Rückgabewerts
> benutzen, vor allem, wenn du weder Logikanalyser (z.b Saleae & Co) noch
> Oszi hast.

"i2c_start_wait" gibt keinen Code zurück, da in dieser Funktion so lange 
eine Schleife durchläuft bis kein Fehler mehr entsteht. Also braucht es 
auch keinen zurück geben. Aber dennoch habe ich wie oben vorher 
beschrieben auch schon die Variante mit "i2c_start" versucht.

------------------------------------------------------------

c-hater schrieb:
> Dein Code macht jedenfalls nicht das, was nötig wäre. Was das ist, steht
> im Datenblatt des 24C512 auf Seite 9.

Das verstehe ich jetzt nicht so ganz. Wieso macht mein Code nicht das 
was es machen sollte? Da wäre ein Hinweis ganz nett.
Und ja ich habe das Datenblatt schon mehr als einmal gelesen. Falls du 
darauf abzielen solltest.

>> Wenn ich den Delay weglasse
>> nach dem schreiben, dann werden einige Werte verschluckt, da das
>> Acknowlege Polling anscheinend nicht 100% funktioniert.
>
> Eben. Genau das ist der springende Punkt. Du solltest du dich doch wohl
> ernsthaft fragen, warum das wohl so sein mag...

Ja das habe ich mich auch schon gefragt. Aber das ist ja im Moment nicht 
mein Problem, da ich dem EEprom ja genug Zeit gebe um die Daten aus 
seinem flüchtigen Speicher in den nicht flüchtigen Speicher zu 
schreiben.
Ich sehe im Moment nicht den direkten Zusammenhang zwischen diesem 
Problem und meinem Hauptproblem. Für Eine Erklärung bin ich aber immer 
offen.

> Ich würde mal folgende Fassung vorschlagen:
>
> void eeprom_write(uint16_t addr, uint8_t val)
> {
>   i2c_start_wait(Dev24C512+I2C_WRITE);
>   i2c_write((addr>>8)&0xFF);
>   i2c_write(addr&0xFF);
>   i2c_write(val);
> }
>
> Funktioniert das besser?

Damit ich dich nicht falsch verstehe. Dein Vorschlag entspricht meinem 
Code mit der Ausnahme dass der Delay und das Stopp Signal weg gelassen 
werden sollen? Das "i2c_start_wait" ist in meinem code auch drinne, nur 
es ist hier im Forum in eine Zeile drüber gerutscht.
Ich kann das gerne versuchen, aber sehe da den Sinn noch nicht so ganz. 
Ohne Delay habe ich es bereits versucht. Darüber hinaus ist im 
Datenblatt genau beschrieben, dass nach dem Schreibvorgang ein Stopp 
Signal gesendet werden muss.

Mal komplett abgesehen davon. Wieso treten die Fehler nur auf, wenn ich 
viel in den Speicher schreibe und bei anderen ICs über die I2C 
Schnittstelle gar nicht? Das Verstehe ich halt nicht so recht.

------------------------------------------------------------

Wilhelm Ferkes schrieb:
> Sicher, daß da im Leerzustand Nullen drin sein sollen, und nicht Einsen?
>
> Mit sowas hatte ich auch schon mal Probleme, allerdings bei einem
> anderen EEPROM-Typ.

Nein da bin ich mir gar nicht sicher. Aber ich würde ungern 1 Nehmen, da 
1 auch ein Messwert sein könnte. Aber auch das werde ich kurz testen.


Vielen Dank für eure Vorschläge. Ich werde mich wieder melden, wenn ich 
weitere Informationen habe oder es sogar funktionieren sollte. :-)


Gruß
Kalle

von Ben _. (burning_silicon)


Lesenswert?

Weiß nicht obs Dir hilft, aber diese Verknüpfung zweier Werte klingt für 
mich so, als ob diese Adresse doppelt beschrieben wird ohne den EEPROM 
zu löschen.

von c-hater (Gast)


Lesenswert?

Pascal G. schrieb:

> Damit ich dich nicht falsch verstehe. Dein Vorschlag entspricht meinem
> Code mit der Ausnahme dass der Delay und das Stopp Signal weg gelassen
> werden sollen?

Genau so ist das.

von Pascal G. (Firma: http://www.pgollor.de) (mc-kalle)


Lesenswert?

c-hater schrieb:
> Pascal G. schrieb:
>
>> Damit ich dich nicht falsch verstehe. Dein Vorschlag entspricht meinem
>> Code mit der Ausnahme dass der Delay und das Stopp Signal weg gelassen
>> werden sollen?
>
> Genau so ist das.

Okay. Ich werde es versuchen und mich dann wieder melden. Könntest du 
mir vielleicht noch erklären, aus welchem Grund ich das Stoppsignal weg 
lassen soll?
Und wenn es dadurch funktionieren sollte würde ich mit meinem µC doch 
den I2C Bus dauerhaft blockieren oder?


Gruß
Kalle

von Wilhelm F. (Gast)


Lesenswert?

Pascal G. schrieb:

> Nein da bin ich mir gar nicht sicher. Aber ich würde ungern 1 Nehmen, da
> 1 auch ein Messwert sein könnte. Aber auch das werde ich kurz testen.

Dann stimmt grundsätzlich mit deinem Konzept was nicht.

Ich fand das in meiner Anfangszeit auch mal merkwürdig, daß in einem 
leeren Baustein Einsen drin stehen. Bei Flash ist das auch so, und ein 
EPROM hat nach dem UV-Löscher auch nur Einsen. Die Speicherzellen werden 
mit Null aktiv beschrieben. Man gewöhnt sich dran.

von Pascal G. (Firma: http://www.pgollor.de) (mc-kalle)


Lesenswert?

Wilhelm Ferkes schrieb:
> Dann stimmt grundsätzlich mit deinem Konzept was nicht.
>
> Ich fand das in meiner Anfangszeit auch mal merkwürdig, daß in einem
> leeren Baustein Einsen drin stehen. Bei Flash ist das auch so, und ein
> EPROM hat nach dem UV-Löscher auch nur Einsen. Man gewöhnt sich dran.

Das Konzept zu ändern ist im Moment noch kein großes Problem das würde 
ich hin bekommen.
Meinst du wirklich für jedes Byte = 1 oder für jedes Bit?
Also beim beschrieben 0x01 oder 0xFF?


Gruß
Kalle

von Peter D. (peda)


Lesenswert?

Pascal G. schrieb:
> Meinst du wirklich für jedes Byte = 1 oder für jedes Bit?
> Also beim beschrieben 0x01 oder 0xFF?

Es ist wurscht, was man reinschreibt, der EEPROM macht grundsätzlich ein 
Erase vor jedem Schreiben, das kannst Du nicht verhindern.
Deshalb heißt er ja EEPROM, wäre ein Erase nötig, hieße er Flash.

Ob man nun ungültig als 0x00 oder 0xFF oder sonstwas markiert, ist rein 
persönlicher Geschmack.

von c-hater (Gast)


Lesenswert?

Pascal G. schrieb:

> Könntest du
> mir vielleicht noch erklären, aus welchem Grund ich das Stoppsignal weg
> lassen soll?

Weil der nächste Aufruf sowohl von eeprom_write als auch für eeprom_read 
für das Device das implizit in i2c_start_wait erledigt und zwar (im 
Gegensatz zu deinem Code) auch noch im richtigen "Moment".

> Und wenn es dadurch funktionieren sollte würde ich mit meinem µC doch
> den I2C Bus dauerhaft blockieren oder?

Richtig, gut mitgedacht. Deswegen sollte dein letzter Zugriff auf das 
Device auch immer ein eeprom_read sein. Das dortige i2c_stop kannst du 
übrigens auch gleich noch entsorgen. Es richtet hier zwar wenigstens 
keinen Schaden an, nützt aber auch nix. Warum? Auf Seite 10 des 
Datenblattes steht die Antwort.

von Wilhelm F. (Gast)


Lesenswert?

Pascal G. schrieb:

> Meinst du wirklich für jedes Byte = 1 oder für jedes Bit?

Jedes Bit natürlich.



Peter Dannegger schrieb:

> Es ist wurscht, was man reinschreibt, der EEPROM macht grundsätzlich ein
> Erase vor jedem Schreiben, das kannst Du nicht verhindern.
> Deshalb heißt er ja EEPROM, wäre ein Erase nötig, hieße er Flash.

Nicht generell. Ich habe hier noch einige parallele 28C16A, die auch der 
EPROMMER nicht generell löscht. Will ich den Baustein neu beschreiben, 
dann muß ich den EPROMMER vorher mit einem Hex-File laden, welches nur 
Einsen hat, dann brennen. Erst nach diesem Vorgang kann ich den Baustein 
neu beschreiben. Diese parallelen 28C16A hatten aber auch keinen 
Löschbefehl intern, keine Steuerung, waren simpelst. Das einzige, was 
die machten, war eine interne Programmierspannungserzeugung, wenn man 
den Nicht-A-Typ hatte.

von Peter D. (peda)


Lesenswert?

Pascal G. schrieb:
> Könntest du
> mir vielleicht noch erklären, aus welchem Grund ich das Stoppsignal weg
> lassen soll?

Das STOP ist unbedingt nötig!
Senden man ein (Repeat-)Start, d.h. ohne vorheriges Stop nach den zu 
schreibenden Daten, wird das Schreiben abgebrochen. Der EEPROM behält 
die alten Daten. Das steht auch eindeutig im Datenblatt.

Der EEPROM kann ja nicht hellsehen, wieviel Bytes Du reinschreiben 
willst. Daher wartet er mit dem Schreibzyklus bis zum Empfang des Stop.

von c-hater (Gast)


Lesenswert?

Peter Dannegger schrieb:

> Das STOP ist unbedingt nötig!

Ja, natürlich. Nur nicht an dieser Stelle im Code. Dort ist es noch "zu 
früh" dafür.

von Peter D. (peda)


Lesenswert?

c-hater schrieb:
> Ja, natürlich. Nur nicht an dieser Stelle im Code. Dort ist es noch "zu
> früh" dafür.

Vermutlich meinst Du nach dem Senden der Adresse und vor dem Umschalten 
auf Lesen. Da braucht man es nicht, aber es stört auch nicht.
Es würde nur in einer Multimasterumgebung stören, dann könnte sich ein 
anderer Master den EEPROM krallen und das Lesen schlägt fehl.

von c-hater (Gast)


Lesenswert?

Peter Dannegger schrieb:

> Vermutlich meinst Du nach dem Senden der Adresse und vor dem Umschalten
> auf Lesen

Nein.

von c-hater (Gast)


Lesenswert?

c-hater schrieb:
> Peter Dannegger schrieb:
>
>> Vermutlich meinst Du nach dem Senden der Adresse und vor dem Umschalten
>> auf Lesen
>
> Nein.

Ergänzung: Jetzt erkenne ich erst, daß sich deine Anmerkung auf meinen 
Vorschlag bezieht, auch in eeprom_read das i2c_stop wegzulassen.

Diesbezüglich hast du völlig recht, das war Blödsinn. Datenblatt zu 
flüchtig gelesen.

von Pascal G. (Firma: http://www.pgollor.de) (mc-kalle)


Lesenswert?

Moin,

also ich denke auch nicht, dass man es beim schreiben weg lassen sollte. 
Im Datenblatt ist eindeutig zu erkennen, dass nach dem Wert den man 
schreiben möchte ein Stoppsignal zu senden ist.
Ich habe es auch mal ohne versucht, daher

Dieser Code ist ja auch nur ein kleiner Test. Später sollen alle 10 
Sekunden ein Byte in den EEprom geschrieben werden. Innerhalb der 10 
Sekunden greift der Controller auf andere I2C ICs zu.
In dem gepostetem Code soll das zum Testen nur etwas beschleunigt 
werden. Das heißt es ist für mich wirklich nötig nach dem Schreiben den 
Bus wieder frei zu geben um mit anderen Geräten kommunizieren zu können.

Wenn ich die Stoppbedingung nicht senden würde, dann würde ich doch ein 
einfaches Pagewrite machen oder? Und das ist ja eigentlich nicht das was 
ich möchte.

Ich hoffe mal, dass wir nicht aneinander vorbeireden.

Also zum schrieben:
1
i2c_start_wait(Dev24C512+I2C_WRITE);
2
i2c_write((addr>>8)&0xFF);
3
i2c_write(addr&0xFF);
4
i2c_write(val);
5
i2c_stop();

Wenn ich hier die Rückgabewerte abfrage nach jedem write, bekomme ich 
auch keinen Fehler zurück.

Und zum lesen
1
i2c_start_wait(Dev24C512+I2C_WRITE);
2
i2c_write((addr>>8)&0xFF);
3
i2c_write(addr&0xFF);
4
i2c_rep_start(Dev24C512+I2C_READ);
5
uint8_t ret = i2c_readNak();
6
i2c_stop();


Peter Dannegger schrieb:
> Es ist wurscht, was man reinschreibt, der EEPROM macht grundsätzlich ein
> Erase vor jedem Schreiben, das kannst Du nicht verhindern.
> Deshalb heißt er ja EEPROM, wäre ein Erase nötig, hieße er Flash.
>
> Ob man nun ungültig als 0x00 oder 0xFF oder sonstwas markiert, ist rein
> persönlicher Geschmack.

Danke für den Post und ich dachte schon ich hätte alles falsch 
verstanden. ;-)


Gruß
Kalle

von c-hater (Gast)


Lesenswert?

Pascal G. schrieb:

Ja und? Was ist dabei rausgekommen? Das wäre interessant gewesen.

> Dieser Code ist ja auch nur ein kleiner Test. Später sollen alle 10
> Sekunden ein Byte in den EEprom geschrieben werden. Innerhalb der 10
> Sekunden greift der Controller auf andere I2C ICs zu.

So what? Du machst einfach, was ich dir vorgeschlagen habe (abzüglich 
des von Peter bereits korrigierten Blödsinns über das Weglassen von 
i2c_stop in eeprom_read natürlich).

Du läßt also das i2c_stop in eeprom_write weg und baust zusätzlich eine 
neue Funktion

int eeprom_write_and_verify(uint16_t addr, uint8_t val)
{
  eeprom_write(addr, val);
  return eeprom_read(addr) == val;
}

und rufst die (und nicht direkt eeprom_write) alle 10 Sekunden auf. Da 
hast du dann obendrein immer auch gleich noch die Rückinformation, ob 
das Schreiben wirklich geklappt hat.

Und der Bus ist dann in der Zwischenzeit auch frei.

Und wenn ich die Ursache des Problems wirklich richtig erkannt habe, 
verschwinden dann auch die "kuriosen Effekte".

von Christian H. (netzwanze) Benutzerseite


Lesenswert?

Und wenn das die Lösung ist, wäre es nett, wenn Du den Grund ausführlich 
darlegst. Dann haben auch noch andere Leute einen Lernerfolg.

von Pascal G. (Firma: http://www.pgollor.de) (mc-kalle)


Lesenswert?

c-hater schrieb:
> Ja und? Was ist dabei rausgekommen? Das wäre interessant gewesen.

Es hatte nicht funktioniert.

> Du läßt also das i2c_stop in eeprom_write weg und baust zusätzlich eine
> neue Funktion
>
> int eeprom_write_and_verify(uint16_t addr, uint8_t val)
> {
>   eeprom_write(addr, val);
>   return eeprom_read(addr) == val;
> }
>
> und rufst die (und nicht direkt eeprom_write) alle 10 Sekunden auf. Da
> hast du dann obendrein immer auch gleich noch die Rückinformation, ob
> das Schreiben wirklich geklappt hat.

Wie ich vermutet habe, funktioniert das leider nicht.

Der Controller macht nach meinem Verständnis jetzt auch nicht das was er 
tun sollte.
Nach deinem Vorschlag macht er glaube ich Folgendes:
- Start Signal
- write Device Adresse + Write Bit (0)
- write Wert
- sendet ein erneutes Start signal
- write Device Adresse + Read bit (1)
- stop Signal
- erneutes Start Signal
usw......

So das ist aber laut Datenblatt ja nicht richtig, da das EEprom ein 
Stoppsignal benötigt damit er weis, dass ich nicht weiter schreiben 
möchte.
Daher wirft er die Schreibwerte einfach weg.
Dies wurde aber weiter oben in einem Post auch schon erwähnt.

Und falls das gerade nicht so herüber kommt. Ich bin wirklich dankbar, 
dass du dich so mit meinem Problem Auseinander setzt. Aber wir scheinen 
einfach wirklich aneinander vorbei zu reden oder zwei verschiedene 
Sachen machen zu wollen.
Ich werde gegen Ende der Woche mal versuchen mit einem I2C Sniffer 
wirklich zu schauen, was auf dem Bus vor sich geht und mich dann hier 
wieder melden.

Daher wirklich vielen Dank für deine Mühen!


Gruß
Kalle

von Sebastian W. (sebastian_w29)


Lesenswert?

Mal noch ne andere Idee: Hast du A0, A1 und WP mit GND verbunden?

Seltsam dass wir hier alle so im Nebel stochern ...

LG, Sebastian

von c-hater (Gast)


Lesenswert?

Pascal G. schrieb:

> Es hatte nicht funktioniert.

OK. Dann eine andere Variante. Dein ursprünglicher Code, aber die 
Reihenfolge von i2c_stop und delay getauscht. Wenn das funktioniert, 
delay ggf. verkürzen.

von Pascal G. (Firma: http://www.pgollor.de) (mc-kalle)


Lesenswert?

Sebastian W. schrieb:
> Mal noch ne andere Idee: Hast du A0, A1 und WP mit GND verbunden?

Ja das habe ich gemacht. Aber das ist ja nur für die Device Adresse. Das 
Device kann ich ja einwandfrei ansprechen.
Eher könnte es sein, dass der WP (Write Protection) Pin intern nicht 
richtig auf Masse gelegt ist, aber das habe ich mittlerweile auch schon 
vorgenommen.

c-hater schrieb:
> OK. Dann eine andere Variante. Dein ursprünglicher Code, aber die
> Reihenfolge von i2c_stop und delay getauscht. Wenn das funktioniert,
> delay ggf. verkürzen.

Okay danke. Aber führt leider auch nicht zu dem gewünschten Effekt.
Habe es mit verschiedenen Werten zwischen 1ms und 15ms versucht.

Wie gesagt, am Wochenende werde ich mir mal mit einem anderen Atmega 
anschauen, was wirklich auf der Schnittstelle los ist.
Darüber hinaus werde ich als nächstes einmal versuchen ein Page Write 
vor zu nehmen, dass ich auf einmal 128 Werte schreibe und dann wieder 
solange bis ich dann zu einem Fehler komme.


Gruß
Kalle

von Pascal G. (Firma: http://www.pgollor.de) (mc-kalle)


Lesenswert?

Moin noch mal,

jetzt habe ich den Code mal auf ein Minimu reduziert und es scheint mir 
einfach, dass ich anscheinend entgegen meiner Meinung die Adressierung 
des EEproms doch nicht richtig verstanden habe.

Der Minimalcode mit Debugausgabe:
1
int main()
2
{
3
  // initialisieren des I2C bus
4
  i2c_init();
5
6
  // initialisiere uart
7
  usart_init(BAUDRATE);
8
9
  sei();
10
11
  eeprom_init();
12
13
14
  _delay_ms(100);
15
  usart_write(CR CR "-- start --" CR);
16
  _delay_ms(100);
17
18
  printf("test mit 0x%x - h:0x%x l:0x%x" CR, 0x1000, (0x1000>>8)&0xFF, 0x1000&0xFF);
19
20
  eeprom_write(0x00, 0x0);
21
  _delay_ms(100);
22
  eeprom_write(0x1000, 0x0);
23
24
  _delay_ms(100);
25
  uint8_t v1 = eeprom_read(0x00);
26
  uint8_t v2 = eeprom_read(0x1000);
27
  printf("0:%x - 1000:%x" CR, v1, v2);
28
  _delay_ms(100);
29
30
  eeprom_write(0x00, 0xf0);
31
32
  _delay_ms(100);
33
  v1 = eeprom_read(0x00);
34
  v2 = eeprom_read(0x1000);
35
  printf("0:%x - 1000:%x" CR, v1, v2);
36
  _delay_ms(100);
37
38
  eeprom_write(0x1000, 0xee);
39
40
  _delay_ms(100);
41
  v1 = eeprom_read(0x00);
42
  v2 = eeprom_read(0x1000);
43
  printf("0:%x - 1000:%x" CR, v1, v2);
44
  _delay_ms(100);
45
46
  for(;;);
47
48
  return 0;
49
}

Die Ausgaeb dazu:
1
-- start --
2
test mit 0x1000 - h:0x10 l:0x0
3
0:0 - 1000:0
4
0:f0 - 1000:0
5
0:e0 - 1000:ee

Das Sieht doch wirklich stark danach aus, dass die Adressierung nicht 
stimmt oder?
Jetzt muss ich wohl doch mal schauen, dass ich ein Oszi bekommen um mir 
das mal genauer an zu sehen.


Gruß
Kalle

von Pascal G. (Firma: http://www.pgollor.de) (mc-kalle)


Lesenswert?

Hallo, ich mal wieder. ;)

Das Problem schient bei den höchstwertigen 4 Bit zu liegen und auch 
immer nur bei Adresse die n * 0x1000 auseinander liegen.

Das heißt wenn ich 0x00 beschriebe und anschließend 0x1000 tritt das 
Problem auf wie im Post vorher zu sehen, aber auch wenn ich 0x1000 und 
0x3000 beschreibe.
Mit anderen Worten die höchstwertigen 4 Bit werden anscheinend nicht 
richtig übertragen.

Aber um dies genau zu testen, muss ich erst mal warten bis ich ein Oszi 
zur verfügung habe.


Gruß
Kalle

von holger (Gast)


Lesenswert?

>Das Problem schient bei den höchstwertigen 4 Bit zu liegen und auch
>immer nur bei Adresse die n * 0x1000 auseinander liegen.

Hast du da vieleicht ein 24C32 EEPROM und kein 24C512?

Ich glaub hier haben schon alle aufgegeben;)

von Weingut P. (weinbauer)


Lesenswert?

öhm ... welche Pullups hast Du denn drannen?
kannst ja mal etwas mit dem Takt arbeiten, mal nen höheren oder tieferen 
Bustakt ausprobiert?

von Pascal G. (Firma: http://www.pgollor.de) (mc-kalle)


Lesenswert?

Ein langer Leidensweg ist zu Ende. Der Fehler ist gefunden. ;-)
Erst einmal vielen Dank an alle die sich die Köpfe für mich angestrengt 
haben.

Hatte vor lägerem alles andere abgezogen, was noch an meinem µC mit dran 
hängt, aber zwischenzeitlich um etwas anderes zu testen eine RTC wieder 
mit angeschlossen. Und diese war der Übeltäter.

Fhutdhb Ufzjjuz schrieb:
> öhm ... welche Pullups hast Du denn drannen?
> kannst ja mal etwas mit dem Takt arbeiten, mal nen höheren oder tieferen
> Bustakt ausprobiert?

Hatte mehrmals zwischen 100kHz und 400kHz variiert. An Pullups verwende 
ich 10kOhm.

Gruß
Kalle

von Pascal G. (Firma: http://www.pgollor.de) (mc-kalle)


Lesenswert?

Falls es noch wen interessiert.

Ein kleiner Nachtrag noch. Mittlerweile habe ich auch das Problem 
komplett analysieren können.
Der EEprom auf dem RTC Modul ist ein 32K EEprom mit der gleichen Adresse 
wie mein 512K EEprom. Das heißt, immer wenn das RTC Modul angeschlossen 
war, habe ich ohne es zu merken das EEprom beschrieben und nicht das 
Große, dass ich angeschlossen habe.

Die Adresse habe ich jetzt über die Hardeware Adressierung verändert und 
es funktioniert einwandfrei.
Auch der I2C Code funktioniert jetzt ohne delay.


Gruß
Kalle

von Georg G. (df2au)


Lesenswert?

Verrätst du uns bitte noch, wie das RTC Modul heißt, damit wir das 
Fettnäpfchen vermeiden können?

von Pascal G. (Firma: http://www.pgollor.de) (mc-kalle)


Lesenswert?

Georg G. schrieb:
> Verrätst du uns bitte noch, wie das RTC Modul heißt, damit wir das
> Fettnäpfchen vermeiden können?

Na klar sorry.
Wie das Board jetzt genau heißt kann ich dir allerdings nicht genau 
sagen. Das scheint aber in der AVR Welt bekannt zu sein.

Auf dem Board ist ein DS1307 mit nem 24C32 von Atmel. In den gänigen 
Suchmaschinen findet man ziemlich schnell etwas dazu.


Gruß
Kalle

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.