Forum: Mikrocontroller und Digitale Elektronik STM32F10x : Fehler bei I2C


von Walter T. (nicolas)


Angehängte Dateien:

Lesenswert?

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.

: Bearbeitet durch User
von Walter T. (nicolas)


Lesenswert?

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

: Bearbeitet durch User
von Walter T. (nicolas)


Lesenswert?

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.

von Walter T. (nicolas)


Angehängte Dateien:

Lesenswert?

Hier nochmal meine obigen Aussagen in bunt.

von Julian S. (yusa)


Lesenswert?

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

: Bearbeitet durch User
von Walter T. (nicolas)


Lesenswert?

Julian S. schrieb:
> Glückwunsch :

Äh nein: Es funktioniert ja nicht.

von Julian S. (yusa)


Lesenswert?

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

von Walter T. (nicolas)


Lesenswert?

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".

von Julian S. (yusa)


Lesenswert?

Achso, alles klar ;)

von Walter T. (nicolas)


Lesenswert?

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.

von Mehmet K. (mkmk)


Lesenswert?

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.

von Walter T. (nicolas)


Angehängte Dateien:

Lesenswert?

@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.

von Julian S. (yusa)


Lesenswert?

@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.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.