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
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
Hmmm... Also "while(!(TWCR & (1<<TWINT)));" ist fünf mal in Deinem i2c.c drin, bei welchem bricht Dein Programm denn ab?
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
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
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.
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.
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
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
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 berprfen 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 berprfen 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
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
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.
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
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
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
> 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?
>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
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.
Ich schicke doch auch jedes mal ein STOP (s. erste Anweisung in der do..while Schleife). Jochen
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.
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.