Hallo zusammen,
ich habe ein Problem mit dem I2C eines STM32F103 in Verbindung mit einem
EEPROM 24C02. Die I2C-Routinen habe ich nach der Application Note AN2824
implementiert. Das merkwürdige Verhalten zeigt sich während der Laufzeit
der Funktion "I2C_Receivebuffer".
Will ich den EEPROM komplett auslesen mit: 1 | uint8_t status;
| 2 | uint8_t buffer[EEPROM_SIZE_BYTES];
| 3 |
| 4 | status = eeprom_read_block(buffer,0,EEPROM_SIZE_BYTES);
|
was die folgende Funktion aufruft: 1 | /* Viele Bytes aus EEPROM auslesen */
| 2 | /* Nur getesten fuer EEPROMS vom Typ 24C02, bei groesseren muss die */
| 3 | /* Speicheradresse in die I2C-Adresse eingerechnet werden */
| 4 | /* size = 0 ist immer erfolgreich und fuehrt keine Busoperation aus */
| 5 | uint_fast8_t eeprom_read_block(uint8_t *buffer,uint8_t addr,uint8_t size) {
| 6 | uint8_t status;
| 7 |
| 8 | if(size==0) return ee_ok;
| 9 |
| 10 | // Auf gueltige Adresse pruefen
| 11 | if((addr+size)>EEPROM_SIZE_BYTES) {
| 12 | return ee_invalidAddress<<4;
| 13 | }
| 14 | if((addr)>EEPROM_SIZE_BYTES) {
| 15 | return ee_invalidAddress<<4;
| 16 | }
| 17 |
| 18 |
| 19 | // Kommando ohne Stopbit senden
| 20 | status = I2C_Sendbuffer(EEPROM_I2C_DEVICE,EEPROM_I2C_ADDRESS,&addr,1,noStop);
| 21 | if (status!=0)
| 22 | goto error;
| 23 |
| 24 | status = I2C_Receivebuffer(EEPROM_I2C_DEVICE,EEPROM_I2C_ADDRESS,buffer,size);
| 25 | if (status!=0)
| 26 | goto error;
| 27 |
| 28 |
| 29 | error:
| 30 | I2C_reset(EEPROM_I2C_DEVICE); // STOP wuerde meist auch reichen
| 31 | return status;
| 32 | }
|
Leider schlägt die Leseoperation fehl, vermutlich weil der STM32 den
Empfang des zweiten Bytes mit NACK beantwortet. So sieht der Verkehr auf
dem I2C aus: 1 | sA0a00a
| 2 | sA1a0AnFFnFFnFFnFFnFFnFFnFFnFFnFFnFFnFFnFFnFFnFFnFFnFFnFFnFFnFFnFFnFFnFFnFFnFFnFFnFFnFFnFFnFFnFFnFFnFFnFFnFFnFFnFFnFFnFFnFFnFFnFFnFFnFFnFFnFFnFFnFFnFFnFFnFFnFFnFFnFFnFFnFFnFFnFFnFFnFFnFFnFFnFFnFFnFFnFFnFFnFFnFFnFFnFFnFFnFFnFFnFFnFFnFFnFFnFFnFFnFFnFFnFFnFFnFFnFFnFFnFFnFFnFFnFFnFFnFFnFFnFFnFFnFFnFFnFFnFFnFFnFFnFFnFFnFFnFFnFFnFFnFFnFFnFFnFFnFFnFFnFFnFFnFFnFFnFFnFFnFFnFFnFFnFFnFFnFFnFFnFFnppFFnp
|
und so sollte er aussehen (gleiches EEPROM vom AVR angesprochen): 1 | sA0a00a
| 2 | sA1a0Aa03a04a32aFFa3Ca05a00a00a00aD0a07a01a0FaC0a01aB9a1Aa12a13a14a15a16a17a18a19a1Aa1Ba1Ca1Da1Ea1Fa20a21a22a23a24a25a26a27a28a29a2Aa2Ba2Ca2Da2Ea2Fa30a31a32a33a34a35a36a37a38a39a3Aa3Ba3Ca3Da3Ea3Fa40a41a42a43a44a45a46a47a48a49a4Aa4Ba4Ca4Da4Ea4Fa50a51a52a53a54a55a56a57a58a59a5Aa5Ba5Ca5Da5Ea5Fa60a61a62a63a64a65a66a67a68a69a6Aa6Ba6Ca6Da6Ea6Fa70a71a72a73a74a75a76a77a78a79a7Aa7Ba7Ca7Da7Ea7Fn
|
(Wie man sieht, befinden sich im hinteren Teil des EEPROMs nur
Test-Muster, die einen guten Wiedererkennungswert auf dem Bus haben.)
Andere Daten werden von der Funktion "I2C_Receivebuffer" korrekt
empfangen (und mit einem Ack belegt), z.B. hier die Kommunikation mit
einem TMC222: 1 | 24640: sC0aFCa
| 2 | 24640: sC1aE0aD7a96aD7a96a00aF8aFFnp
| 3 | 24641: sC0aFCa
| 4 | 24641: sC1aE0aD7a96aD7a96a00aF8aFFnp
|
der das gleiche Muster aufweist (Gesendet I2C-Adresse + 1 Byte, Anwort
"lange" Bytefolge.
Den Bustakt habe ich testweise schon auf 100 kHz gesenkt; mit dem AVR
läuft aber auch alles bei 250 kHz noch korrekt.
Und jetzt stehe ich da, wie der Ochse vom Berg.
Hat jemand einen Ansatzpunkt?
Viele Grüße
W.T.
Edit: Beitrag gelöscht. Der vorher hier beschriebene Teil war ein
Artefakt. Die obige Frage bleibt leider. Wenn EEPROM_SIZE_BYTES==3,
ergibt sich: 1 | IST:
| 2 | 54979: sA0a00a
| 3 | 54979: sA1a00nFFnFFnp
| 4 |
| 5 | SOLL:
| 6 | 56382: sA0a00a
| 7 | 56382: sA1a00a01a02np
|
Es ist zum verzweifeln. Das geht: 1 | /* Kommando an TMC222 senden und Antwort lesen */
| 2 | /* Der Aufrufer muss einen passenden Puffer zur Verfuegung stellen
| 3 | * buffer[0] : Kommando mit Sendeaufforderung
| 4 | * buffer[1 - ende] : Empfangspuffer
| 5 | * */
| 6 | uint_fast8_t
| 7 | tmc222_SendCommandAndRead(uint8_t i2c_addr,uint8_t *buffer,uint8_t bufsize)
| 8 | {
| 9 | uint_fast8_t status;
| 10 |
| 11 | // Kommando ohne Stopbit senden
| 12 | status = I2C_Sendbuffer(TMC222_I2C_DEVICE,i2c_addr,buffer,1,noStop);
| 13 | if (status!=0)
| 14 | goto error;
| 15 | buffer++;
| 16 |
| 17 | status = I2C_Receivebuffer(TMC222_I2C_DEVICE,i2c_addr,buffer,bufsize-1);
| 18 | if (status!=0)
| 19 | goto error;
| 20 |
| 21 | return status;
| 22 |
| 23 | error:
| 24 | I2C_reset(TMC222_I2C_DEVICE);
| 25 | return status;
| 26 | }
|
und liefert: 1 | 19876: sC0aFCa
| 2 | 19876: sC1aE0a00a00a00a00a00aF8aFFnp
|
Und das funktioniert nicht: 1 | /* Viele Bytes aus EEPROM auslesen */
| 2 | /* Nur getesten fuer EEPROMS vom Typ 24C02, bei groesseren muss die */
| 3 | /* Speicheradresse in die I2C-Adresse eingerechnet werden */
| 4 | /* size = 0 ist immer erfolgreich und fuehrt keine Busoperation aus */
| 5 | uint_fast8_t eeprom_read_block(uint8_t *buffer,uint8_t addr,uint8_t size) {
| 6 | uint_fast8_t status;
| 7 |
| 8 | if(size==0) return ee_ok;
| 9 |
| 10 | // Auf gueltige Adresse pruefen
| 11 | if((addr+size)>EEPROM_SIZE_BYTES) {
| 12 | return ee_invalidAddress<<4;
| 13 | }
| 14 | if((addr)>EEPROM_SIZE_BYTES) {
| 15 | return ee_invalidAddress<<4;
| 16 | }
| 17 |
| 18 |
| 19 | // Kommando ohne Stopbit senden
| 20 | status = I2C_Sendbuffer(EEPROM_I2C_DEVICE,EEPROM_I2C_ADDRESS,&addr,1,noStop);
| 21 | if (status!=0)
| 22 | goto error;
| 23 |
| 24 | status = I2C_Receivebuffer(EEPROM_I2C_DEVICE,EEPROM_I2C_ADDRESS,buffer,size);
| 25 | if (status!=0)
| 26 | goto error;
| 27 |
| 28 |
| 29 | error:
| 30 | I2C_reset(EEPROM_I2C_DEVICE); // STOP wuerde meist auch reichen
| 31 | return status;
| 32 | }
|
denn es liefert: 1 | 28407: sA0a01a
| 2 | 28408: sA1aAAnFFnFFnFFnFFnFFnFFnFFnFFnFFnFFnFFnFFnFFnFFnFFnFFnFFnFFnFFnFFnFFnFFnFFnFFnFFnFFnFFnFFnFFnFFnFFnFFnFFnFFnFFnFFnFFnFFnFFnFFnFFnFFnFFnFFnFFnFFnFFnFFnFFnFFnFFnFFnFFnFFnFFnFFnFFnFFnFFnFFnFFnFFnFFnFFnFFnFFnFFnFFnFFnFFnFFnFFnFFnFFnFFnFFnFFnFFnFFnFFnFFnFFnFFnFFnFFnFFnFFnFFnFFnFFnFFnFFnFFnFFnFFnFFnFFnFFnFFnFFnFFnFFnFFnFFnFFnFFnFFnFFnFFnFFnFFnFFnFFnFFnFFnFFnFFnFFnFFnFFnFFnFFnFFnFFnFFnFFnpFFnp
|
Und es ist definiert: 1 | #define TMC222_I2C_DEVICE I2C1
| 2 | #define EEPROM_I2C_DEVICE I2C1
|
Beide Funktionen sind:
Start ->Addr->Byte0 -> Start -> Addr+1 -> Byte1 ....
nur die eine Funktion quittiert Byte1 mit ACK und die andere mit NACK.
Absolut reproduzierbar.
Hier nochmal meine obigen Aussagen in bunt.
Hallo Walter,
Glückwunsch :) Kannst du bitte noch dein Gesammtprojekt hochladen,
sodass auch andere Nutzer von deinem Erfolg profitieren können? ;-)
Wäre sehr nett. :)
Gruß Julian
Julian S. schrieb:
> Glückwunsch :
Äh nein: Es funktioniert ja nicht.
Hallo, kannst du mir bitte erklären, warum du die EEPROM_I2C_ADDRESSE
nicht um eins nach links shiften musst?
1 | I2C_Sendbuffer(EEPROM_I2C_DEVICE,EEPROM_I2C_ADDRESS,&addr,1,noStop);
|
Die 7 MSB Bits stellen die Addresse dar und das LSB READ/WRITE,
wenn ich das richtig verstanden habe?!
Auch in der Funktionn Sendbuffer wird nicht mehr geshiftet, bin ich auf
dem falschen Dampfer? :D
1 | /* Send slave address */
| 2 | /* Reset the address bit0 for write*/
| 3 | slaveaddr &= ~1U;
| 4 | I2Cx->DR = slaveaddr;
|
Gruß Julian
Julian S. schrieb:
> Hallo, kannst du mir bitte erklären, warum du die EEPROM_I2C_ADDRESSE
> nicht um eins nach links shiften musst?
Ganz einfach: Sie ist schon im Define linksbündig. Da man
nicht-linksbündige Version nirgendwo gebrauchen kann, bietet sich das
an. Aber laß uns solche Sachen in Deinem Thread diskutieren - da paßt
das besser hinein. Hier in diesem geht es um die geschlossene
Problemstellung "Kein ACK beim EEPROM lesen".
Wahrscheinlich habe ich es gefunden: Nach der Initialisierung schlägt
das erste Lesem immer fehl, wenn mehr als ein Byte gelesen wird. Der
Grund ist mir noch schleierhaft.
Schlägt das Lesen fehl, wird ein Bus-Reset gemacht (freitakten) und der
I2C neu initialisiert.
Damit ist jedes Lesen vom EEPROM das erste Mal nach der Initialisierung.
Mache ich ein Dummy-Lesen eines einzelnen Bytes vor dem Lesen eines
Blocks funktioniert alles.
Danke für's Lesen!
@Julian: Ich mache das jetzt wieder schön, dann kannst Du gern meine
I2C-Routinen nutzen.
Viele Grüße
W.T.
Ist schon 'ne Zeit her, dass ich das für einem STM32F103 geschrieben
habe. Aber soweit ich mich erinnere, war es mehr ein Abschreiben von den
StdPeriph_Examples. Als EEPROM hatte ich ein 24AA01 eingesetzt. Kannst
ja mal nachschauen, ob diese beiden EEPROM kompatibel sind. In diesem
Fall würde ich mal in den Backups nachschauen.
@Julian: Soo...im Anhang finden sich jetzt die funktionsfähigen EEPROM-
und I2C-Routinen. Ob als hilfreiche Schnipsel oder als warnendes
Beispiel darf sich jeder selbst aussuchen.
@Mehmet: Mich würde es schon interessieren, ob das Fehl-Lesen, das
auftritt, wenn das erste Lesen nach der Initialisierung mehr als ein
Byte ist, "normal" ist. Aber dafür jemanden in altem Quelltext
herumwühlen lassen kann man wohl niemandem zumuten.
Viele Grüße
W.T.
@Walter: Super Dankeschön. Werde ich gleich mal ausprobieren, ob ich
damit einen Schritt weiter komme. :)
Gruß Julian
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
|