Forum: Compiler & IDEs Probleme mit 24c16


von jochen (Gast)


Lesenswert?

Hallo Zusammen,

ich ärgere mich gerade mit einem EEPROM 24c16 rum. Wenn ich das EEPROM,
das leer ist, auslese bekomme ich immer FF (was ja auch soweit okay
sein sollte. Nun versuch ich Daten in das EEPROM zu schreiben was
soweit auch keine Fehlermeldungen verursacht. Wenn ich nun aber den
eben beschriebenen Bereich wieder auslesen will kan ich zwar noch das
erste Byte lesen (Was auch den richtigen wert hat, dann hängt sich das
Programm aber auf)

Mittels Ausgaben auf er seriellen hab ich herausgefunden das sich das
Programm bei folgender Codezeile verabschiedet:
while(!(TWCR & (1<<TWINT)));

Mittels meinen bescheidenen Englischkenntnissen sagt mir das Datenblatt
das TWINT gesetzt wird sobald das TWI mit der davor gestarteten Aufgabe
fertig ist.

In meinem Fall wäre das
TWCR = (1<<TWINT) | (1<<TWSTA) | (1<<TWEN);
was im Endeffekt das senden der Startbedinung(lt. Datenblatt)
wiederspiegelt.

Wenn ich das alles soweit richtig interprtetiere reagiert wohl das
EEPROM beim abfragen des zweiten Bytes nicht auf die Startbedingung -
warum?

Ist es möglich das ich mir irgend wie die Speicherzellen im EEPROM
zerschossen habe?

Hatte vielleicht schon mal jemad ein ähnliches Verhalten oder kann sich
hierauf einen Reim machen.

Bin für jede Hilfe dankbar.

Schönen Tag noch, der Jochen

von OldBug (Gast)


Lesenswert?

Hallo Jochen!

Poste doch mal bitte Deinen Schreib-/Lesecode.

Gruß,
Patrick

von jochen (Gast)


Angehängte Dateien:

Lesenswert?

So,

hab den Code mal hochgeladen.
Hab auch noch das i2c.c File beigepackt weil da ja auch potentielle
Fehler drin sein könnten.

Schon mal vielen Dank für die Mühe, Jochen

von OldBug (Gast)


Lesenswert?

Hmmm...

Also "while(!(TWCR & (1<<TWINT)));" ist fünf mal in Deinem i2c.c
drin, bei welchem bricht Dein Programm denn ab?

von jochen (Gast)


Lesenswert?

Sorry,

bei dem hier:

int start_i2c(unsigned char address)
{

  //Senden der START Bedingung
  TWCR = (1<<TWINT) | (1<<TWSTA) | (1<<TWEN);

  //Warten bis TWI Bedingung gesendet wurde
  while(!(TWCR & (1<<TWINT)));
...
}

Jochen

von Peter D. (peda)


Lesenswert?

Ja, das ist eben das gefährliche an der Hardware-I2C, sie kann sich in
jedem beliebigen Zustand befinden.
Z.B. auch in einem Zustand, wo der Bus belegt ist und somit kein Start
gesendet werden kann.

Am sicherchsten ist es dann einen Timeout aufzusetzen, der immer dann
zuschlägt, sobald etwas klemmt und dann neu initialisiert und wenn
nötig den Bus freigibt.


In Deinem Fall vermute ich mal, Du hast einfach vergessen, daß man im
Master-Read-Mode nach dem Empfang des letzten Bytes immer ein NACK
senden muß, damit der Slave weiß, daß er den Bus nun freigeben muß.


Peter

von jochen (Gast)


Lesenswert?

Schande über mein Haupt grrrrrrrrr.

Vielen lieben Dank lieber Peter das Du mir die Augen geöffnet hast,
oder gessergesagt wer lesen kann ist klar im Vorteil!

Ich hab aus welchem Grund auch immer im Datenbaltt immer unter
schreiben anstat von lesen nachgeschaut und da wird nach dem senden des
letzten Bytes noch ein ACK geschickt.

Hab das jetzt in ein NACK geändert und schon tut es.

Trotzdem hätte ich noch ine andere Frage. Kann mir jemand sagen was ich
mit folgendem Text aus dem Datenblatt anfangen soll, ich bekomme infach
nicht gebachen was man da mchen muss?

This involves issuing the start condition followed by the slave address
for a write operation the 26c16 ist still busy with the write
opperation no ACK will be returned. If the 26c16 has completed the
write operation an ACK will be returned and the host can then proceed
with the next read or write operation.

Meinem bescheiden Englisch zufolge heißt das so viel wie das ich
solange I2C Startbedinungen schicken muss bis ich ein ACK
zurückbekomme. Leider funktioniert das nicht. Kann mir da jemand auf
die Sprünge helfen.


Vielen Dank noch mal, der Jochen.

von Jörg Wunsch (Gast)


Lesenswert?

Mein Datenblatt (von ISSI) dokumentiert das ein wenig anders:

``...and and the Master generates the STOP condition, at which time
the device begins its internal programming cycle. While this internal
cycle is in progress, the device will not respond to any request from
the Master device.''

...

``Acknowledge Polling

The disabling of the inputs can be used to take advantage of the
typical write cycle time. Once the stop condition is issued to
indicate the end of the host's write operation, the IS24CXX initiates
the internal write cycle. ACK polling can be initiated immediately.
This involves issuing the start condition followed by the slave
address for a write operation. If the IS24CXX is still busy with the
write operation, no ACK will be returned. If the IS24CXX has completed
the write operation, an ACK will be returned and the host can then
proceed with the next read or write operation.''

Aber im Prinzip sollte sich das so verhalten, wie Du es interpretiert
hast, ja.

von jochen (Gast)


Lesenswert?

Prinzipiell hab ich damit kein Problem einfach ein paar ms zu warten bis
die Daten im EEPROM sind, es wäre mir jedoch lieber wenn ich eine
saubere Lösung hinbekommen würde.

Was ich derzeit im Code mache ist folgendes:

    ret = start_i2c(ADDRESS+WRITE);
    if ( !ret )
    {
      write_i2c(wo);
      write_i2c(was);
    }

Die Funktion liefert eine 0 zurück wenn ein ACK empfabngen wurde also
TW_MT_SLA_ACK wahr ist.

Daraus hab ich dann diesen Code generiert:

    while((ret = start_i2c(ADDRESS+WRITE));
    write_i2c(wo);
    write_i2c(was);

Nun sollte er doch so lange in der while-Schleife rumeiern bis er ein
ACK bekommt und dann die Daten schreiben.

Oder seh ich da was falsch??

Jochen

von Peter D. (peda)


Lesenswert?

Also das Busy-Polling geht so:

1. sende start
2. sende adreßbyte, ACK merken
3. sende stop
4. wenn nach 2. kein ACK kam, gehe zu 1.


Peter

von jochen (Gast)


Lesenswert?

Okay,

noch mal ich ;-)

hab das jetzt versucht wiw folgt unzusetzten.

void bussy_polling(unsigned char address)
{
  start:
  //Senden der START Bedingung
  TWCR = (1<<TWINT) | (1<<TWSTA) | (1<<TWEN);
  //Warten bis TWI Bedingung gesendet wurde
  while(!(TWCR & (1<<TWINT)));
  //TWI Status berprfen
  if((TWSR & 0xF8) != TW_START)
  {
    stop_i2c();
    goto start;
  }
  //Adresse des anzusprechenden Devices senden
  TWDR = address;
  TWCR = (1<<TWINT) | (1<<TWEN);
  //Warten bis TWI Bedingung gesendet wurde
  while(!(TWCR & (1<<TWINT)));
  //TWI Status berprfen
  if((TWSR & 0xF8) != TW_MT_SLA_ACK)
  {
    stop_i2c();
    goto start;
  }
  stop_i2c();
}


Nicht hauen wegen dem goto, das war jetzt hal mal die schnellste
Lösung. Unabhängig davon ist da wohl immer noch ein Fehler drin Denn er
schreibt mir so nix ins EEPROM.

Vielleicht kann mir ja jemand helfen.

Schönen Abend noch und Danke, Jochen

von Jochen (Gast)


Lesenswert?

Hallo,

ich hab noch mal versucht mit folgendem Code ein Acknowledge Polling
hinzubekommen.

void poll(unsigned char address)
{
    do
    {
        TWCR = (1<<TWINT) | (1<<TWSTA) | (1<<TWEN);

        //Warten bis TWI Bedingung gesendet wurde
        while(!(TWCR & (1<<TWINT)));

        //if((TWSR & 0xF8) != TW_START) return 1;

        //Adresse des anzusprechenden Devices senden
        TWDR = address;
        TWCR = (1<<TWINT) | (1<<TWEN);
        //Warten bis TWI Bedingung gesendet wurde
        while(!(TWCR & (1<<TWINT)));
        //TWSR an die Serielle schicken (in hex)
        int2hex(TWSR & 0xF8);
        USART_new_line();
    }while((TWSR & 0xF8) == TW_MT_SLA_NACK);

    stop_i2c();
}

das Problem ist nun das ich hier permanent 0x20 zurück bekomme was lt.
avr/twi.h soviel wie TW_MTSLA_NACK heißt. Ergo kommt kein ACK vom
EEPROM zurück. Warum? mit den delays tuts doch ???

Wer kann mir auf die Sprüge helfen?

Der Jochen

von Jörg Wunsch (Gast)


Lesenswert?

Wenn ich das mal gegen das twitest.c aus den avr-libc Beispielen
vergleiche, fällt mir auf:

. Du überprüfst nach dem Senden der Startbedingung nicht das
  TW_STATUS, damit kannst Du (bspw. im Falle TW_MT_ARB_LOST)
  unzulässige Bustransaktionen auslösen.

. Du verwechselst möglicherweise die Geräteadresse mit der
  EEPROM-Adresse; insbesondere muß zum Schreiben der Geräte-
  adresse `address | TW_WRITE' nach TWDR geschrieben werden;
  vermutlich wird dadurch das Gerät gar nicht selektiert.

. Du sendest keine Stopbedingung.

von Jochen (Gast)


Lesenswert?

Nachtrag,

ich hab die falsche Deviceaddresse übergeben daher kamen die NACKS.

Nun ist es so das ich jeden "poll-request" sofort mit 0x18 also
TW_MT_SLA_ACK bestätigt bekomme. Die Daten sind aber nicht im ROM.
Irgend wie versteh ich das nicht mer ???

Wo liegt mein Denkfehler ??

Jochen

von Peter D. (peda)


Lesenswert?

Ich hab noch nichts mit dem Hardware-I2C des AVR gemacht.

Hier mein Code für EEPROMS auf dem 8051:


http://www.specs.de/users/danni/appl/soft/c51/eeprom/index.htm


Es unterstützt auch das Auslesen / Schreiben von Pages.



Peter

von Jochen (Gast)


Lesenswert?

So,

noch mal ich. Mit folgender Funktion läuft das ganze jetzt:

void poll(unsigned char address)
{
    do
    {
      TWCR = (1<<TWINT) | (1<<TWSTO) | (1<<TWEN);
        TWCR = (1<<TWINT) | (1<<TWSTA) | (1<<TWEN);

        //Warten bis TWI Bedingung gesendet wurde
        while(!(TWCR & (1<<TWINT)));

        if(((TWSR & 0xF8) != TW_START) & ((TWSR & 0xF8) !=
TW_REP_START)) USART_Transmit((TWSR & 0xF8));
        <--  Das hier versteh ich nicht ??? -->
        Wenn ich diese Zeile weg lasse geht es nicht. Aber in der
        Zeile werden doch keine Daten manipuliert, oder?

        //Adresse des anzusprechenden Devices senden
        TWDR = address;
        TWCR = (1<<TWINT) | (1<<TWEN);
        //Warten bis TWI Bedingung gesendet wurde
        while(!(TWCR & (1<<TWINT)));
        //int2hex(TWSR & 0xF8);

    }while((TWSR & 0xF8) == TW_MT_SLA_NACK);

    stop_i2c();
}

@Jörg
Das TW_WRITE wird schon beim übergeben der Addresse an die Pollfunktion
hinzugefügt.

Die Stop-Bedingung hatte ich davor schon gesendet hatte aber auch nicht
funktioniert deshalb hatte ich sie raus. Nun ist sie wieder drin.

Wenn mir jetzt noch iner sagen kann warum ich die oben markierte Zeile
haben muss obwohl sie eigentlich nichts tut dann bin ich glücklich.

Danke trotzdem noch mal an alle die mir geholfen haben.

Der Jochen

von Jörg Wunsch (Gast)


Lesenswert?

> Wenn mir jetzt noch iner sagen kann warum ich die oben markierte
> Zeile haben muss obwohl sie eigentlich nichts tut dann bin ich
> glücklich.

Da Du den Wert von TWSR ja über UART ausgibst, was steht denn drin?

Vom Statusdiagramm her müßte noch TW_MT_ARB_LOST zulässig sein, dann
wäre allerdings die Startbedingung zu wiederholen.

Vielleicht ist es auch das Timing, d. h. Deine Übertragung per UART
dauert lange genug, als daß danach der Rest funktioniert?

von jochen (Gast)


Lesenswert?

>Da Du den Wert von TWSR ja über UART ausgibst, was steht denn drin?

Mach ich ja nur im Fehlerfall, also wenn TWSR&F8 nicht TW_START oder
TW_REP_START ist. Wenn ich mir das immer ausgeben lasse bekomme ich
beim ersten mal TW_START dann 2x TW_REP_START und dann bekomme ich das
ACK vom 24C16 zurück. Lass ich diese if-Abfrage aber weg tuts nicht

Jochen

von Jörg Wunsch (Gast)


Lesenswert?

Das TW_REP_START ist meiner Meinung nach aber schon falsch.  Du
solltest jedesmal ein Stop schicken, auch bei fehlgeschlagenen
Versuchen.  Zumindest interpretiere ich Peters Algorithmus so.

von jochen (Gast)


Lesenswert?

Ich schicke doch auch jedes mal ein STOP (s. erste Anweisung in der
do..while Schleife).

Jochen

von Jörg Wunsch (Gast)


Lesenswert?

Hmm, dort hatte ich es nicht erwartet, etwas ungewöhnlich.

Was passiert, wenn man ein stop sendet, obwohl einem der Bus gar nicht
gehört?

Aber ganz verstehe ich das auch alles nicht mehr, in der Tat.  Könnte
mal irgendwann selbst einen 24Cxx aus der Kiste kramen und das
nachvollziehen.  Hast Du das eigentlich mal mit dem twidemo.c
probiert?  Im Prinzip tut das genau das, was Du willst, einschließlich
busy polling.  Hmm, nein, nur teilweise: beim Lesen wird kein busy
polling gemacht, sondern im NACK-Falle abgebrochen.  Beim Schreiben
ist das busy polling aber drin, das müßtest Du nur noch in die
Leseroutine cut&pasten.  Falls Du das im twidemo.c noch nachrüsten
willst, please send code.  Dann würde ich das in der avr-libc gern
auch übernehmen.

von jochen (Gast)


Lesenswert?

Hab das twidemo.c mal probiert lief aber nicht. Hab da jetzt auch nicht
all zu viel Zeit hinein investiert. Im Moment ist es mir wichtiger das
es überhaupt tut.

Wenn ich die nächsten Tage/Wochen mal Zeit habe schau ich mir das mal
etwas genauer an.

Wenn da was bei rum kommt meld ich mich auf jeden fall noch mal.

Grüßle, der Jochen

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.