Forum: Mikrocontroller und Digitale Elektronik I2C Problem mit Acknowledge Polling


von Joey4711 (Gast)


Lesenswert?

Hallo zusammen,

ich möchte mit einem STM32F205 ein EEPROM vom Typ "24LC32" über I2C 
ansteuern und bekomme das auch gut hin... Außer einer Kleinigkeit.

Man kann das 24LC32 Pageweise schreiben, wenn man nach Übermittlung von 
32 Byte (= 1 Page) die STOP - Condition sendet, so entkoppelt sich das 
EEPROM vom I2C Bus und startet seinen internen Schreibzyklus. Während 
dieser Zeit reagiert das EEPROM nicht auf I2C - Signale... und das kann 
man sich zunutze machen für sogenanntes "ACK Polling".

Man sendet dabei eine START - Condition, gefolgt von einem AdressByte 
und wartet dananch auf das ACK vom EEPROM. Das tut man solang, bis das 
ACK tatsächlich kommt - dann ist nämlicher der interne Schreibzyklus des 
EEPROMs abgeschlossen.

Soweit zur Erklärung. Ich habe jetzt folgendes Problem: Das ACK sehe ich 
am Oszilloskop, die FW erkennt es aber nicht, zur Illustration hier noch 
das "ACK Polling" Codesegment:
1
uint8_t state = ERROR;
2
do
3
{
4
  I2C_GenerateSTART(I2C1, ENABLE);
5
  while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_MODE_SELECT));
6
  I2C_Send7bitAddress(I2C1, 0xA0, I2C_Direction_Transmitter);
7
  state = I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED);
8
}  
9
while(state==ERROR);

Zusammengefaßt: das ACK sehe ich am Oszilloskop, allerdings detektiert 
es die FW nicht.

Für das gleiche EEPROM habe ich schon mehrere Funktionen für I2C - 
Zugriff programmiert (auch mit ACK - Abfrage natürlich...), die jeweils 
einwandfrei funktionieren.

Mein aktueller Workaround sieht so aus, dass ich nach jedem Page - Write 
einfach 10ms warte.

Ich bitte Euch um Antworten.

Gruß, Johann

von (prx) A. K. (prx)


Lesenswert?

Funktioniert möglicherweise besser, wenn nach einen Fehlversuch erst 
einmal ein STOP kommt, bevor das nächste START ausgelöst wird.

: Bearbeitet durch User
von Walter T. (nicolas)


Lesenswert?

Joey4711 schrieb:
> Mein aktueller Workaround sieht so aus, dass ich nach jedem Page - Write
> einfach 10ms warte.

Meiner auch (5ms). Auch wenn ich fürchte, daß Dir das nicht hilft.

von Joey4711 (Gast)


Angehängte Dateien:

Lesenswert?

... hab ich gemacht, sieht so aus:
1
do
2
{
3
  I2C_GenerateSTART(I2C1, ENABLE);
4
  while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_MODE_SELECT));
5
  I2C_Send7bitAddress(I2C1, 0xA0, I2C_Direction_Transmitter);
6
  state = I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED);    
7
  if (state == ERROR)
8
  {
9
    I2C_GenerateSTOP(I2C1, ENABLE);  
10
  }
11
}  
12
while(state==ERROR);

.. und bringt leider nichts.

Die anhängenden Bilder zeigen das Ganze einmal mit und einmal ohne den 
vorgeschlagenen STOP - Puls, beides funktioniert nicht.

von Walter T. (nicolas)


Lesenswert?

Im Datenblatt des 24LC04 (hatte ich gerade zur Hand) steht auf Seite 8 
auch explizit ein Flußdiagramm, wo ersichtlich ist, daß da ein STOP 
nicht hineingehört.

Beim AVR geht das Ganze auf einwandfrei, nur beim STM32 (hier: 
STM32F103) will das nicht so recht. Das könnte mit dem Errata-Sheet der 
I2C-Hardware erklärt werden.

: Bearbeitet durch User
von Walter T. (nicolas)


Lesenswert?

A. K. schrieb im Beitrag #4224198:
> Ich bezog mich eher auf
> die I2C-Statemachine des µC.

Stimmt, das EEPROM ist ja eh erst einmal tot, solange es schreibt - da 
sollte das nichts ausmachen.

Joey4711 schrieb:
> beides funktioniert nicht

Was funktioniert nicht? Wird der state==ERROR nie verlassen?

von Joey4711 (Gast)


Lesenswert?

Walter T. schrieb:
> Was funktioniert nicht? Wird der state==ERROR nie verlassen?

Richtig. "state==ERROR" wird nie verlassen. Es scheint also nicht am 
STOP Pulse zu liegen

von (prx) A. K. (prx)


Lesenswert?

Walter T. schrieb:
> Stimmt, das EEPROM ist ja eh erst einmal tot, solange es schreibt - da
> sollte das nichts ausmachen.

Yep, aber hab grad nachgesehen. ST erlaubt als Reaktion auf NACK bei der 
Adressierung auch ein REPEATED START, also ist STOP unnötig. Schaden tut 
es aber auch nicht.

: Bearbeitet durch User
von Walter T. (nicolas)


Lesenswert?

[unsinnige Bemerkung von mir gelöscht]

: Bearbeitet durch User
von Klaus (Gast)


Lesenswert?

Walter T. schrieb:
> Im Datenblatt des 24LC04 (hatte ich gerade zur Hand) steht auf Seite 8
> auch explizit ein Flußdiagramm, wo ersichtlich ist, daß da ein STOP
> nicht hineingehört.

Das Datenblatt des 24LC04 kann nur sagen, was den 24LC angeht und nicht 
was den I2C Bus allgemein. Der 24LC braucht offensichtlich kein STOP. 
Aber wie willst du in der Pause zwischen deinen Polls irgendein anderes 
I2C Device ansprechen, wenn du den Bus nicht mit STOP freigegeben hast? 
Das Polling mit Auswertung des ACKs hat doch gerade den Zweck, den Bus 
nicht zu blockieren. Es reicht ja auch, beim nächsten Schreiben 
ausnahmsweise das ACK nach dem Adressbyte mal auszuwerten und das 
Schreiben solange zu verzögern, bis es kommt (oder eine Timeout "EEPROM 
kaputt" signalisiert). Dann braucht man nicht sinnlos zu pollen.

Walter T. schrieb:
> Mir fehlt auch irgendwie die Stelle, wo Du auf den Ack-Timeout wartest.

Der Master taktet das ACK selbst, da kann es kein Timeout geben.

MfG Klaus

von Walter T. (nicolas)


Lesenswert?

Wieso schickst Du eigentlich immer wieder eine 7-Bit Addresse und nicht 
I2C_SendData? Im Datenblatt-Flußdiagramm will das EEPROM ein "Control 
Byte".

: Bearbeitet durch User
von Walter T. (nicolas)


Lesenswert?

Klaus schrieb:
> Der Master taktet das ACK selbst, da kann es kein Timeout geben.

Deswegen auch:

Walter T. schrieb:
> [unsinnige Bemerkung von mir gelöscht]

Manchmal braucht es ein wenig Zeit, bis man wieder im I2C drin steckt.

von (prx) A. K. (prx)


Lesenswert?

Walter T. schrieb:
> Wieso schickst Du eigentlich immer wieder eine 7-Bit Addresse und nicht
> I2C_SendData?

Das was du als Control Byte bezeichnest, das nennt der Rest der Welt 
eine I2C Adresse.

von Joey4711 (Gast)


Lesenswert?

Walter T. schrieb:
> Wieso schickst Du eigentlich immer wieder eine 7-Bit Addresse und nicht
> I2C_SendData? Im Datenblatt-Flußdiagramm will das EEPROM ein "Control
> Byte".

Weil im "Control Byte" die Adresse, gefolgt von einem R/W - Bit, 
enthalten ist... Und weil ichs mir gerade mit I2C_SendData am 
Oszilloskop angesehen habe und das am Oszilloskop gleich aussieht und 
auch der Fehler erhalten bleibt.

von Peter D. (peda)


Lesenswert?

Klaus schrieb:
> Es reicht ja auch, beim nächsten Schreiben
> ausnahmsweise das ACK nach dem Adressbyte mal auszuwerten und das
> Schreiben solange zu verzögern, bis es kommt

Nein!
Die SDA-Leitung muß bei SCL = 1 stabil sein, sonst verletzt man die 
I2C-Spezifikation.

von Walter T. (nicolas)


Lesenswert?

Joey4711 schrieb:
> Weil im "Control Byte" die Adresse, gefolgt von einem R/W - Bit

+ die Pagenummer (Block Address)

Aber ja: Es entspricht tatsächlich der Adresse.

: Bearbeitet durch User
von Klaus (Gast)


Lesenswert?

Peter D. schrieb:
> Nein!
> Die SDA-Leitung muß bei SCL = 1 stabil sein, sonst verletzt man die
> I2C-Spezifikation.

Was hat den das damit zu tun. Der Master darf nach jedem Byte eine 
Transaktion mit STOP abbrechen. Ein I2C EEPROM, das gerade schreibt, 
beantwortet seine Adresse nicht, stellt sich tot. Das liefert halt ein 
NAK. Mehr steckt in den tollen Begriff "ACK Polling" nicht drin.

Und so wie man jedem anderen Peripheral normalerweise nicht wartet, bis 
es endlich fertig ist, sondern beim nächsten Ansprechen schaut, ob es 
schon fertig, geht das natürlich beim EEPROM auch.

MfG Klaus

von Peter D. (peda)


Lesenswert?

Klaus schrieb:
> Was hat den das damit zu tun.

Er wollte ja auf das ACK warten und das geht nicht.
Kommt ein NACK, muß man neu abfragen, d.h. Start + Adresse neu senden.

von Joey4711 (Gast)


Lesenswert?

Hallo Herr Dannegger,

also die geforderte Bedingung (SDA Leitung stabil während SCL auf HIGH 
ist) ist erfüllt (siehe auch die Screenshots weiter oben).

Was mich irritiert ist, dass alle andere I2C Aktionen einwandfrei 
funktionieren; mein Verdacht ist, dass es eine "Besonderheit" auf Seite 
des STM32 ist, denn es gibt mehrere Foren, die das "ACK Polling" Problem 
betreffen, und da geht es immer um STM32 Controller, nie um andere (ist 
natürlich ein Indiz, kein Beweis).

Wie gesagt: meine aktueller Workaround ist, einfach 10ms zu warten und 
dann die nächste Page zu schreiben. Funktioniert einwandfrei, 
reproduzierbar und beliebig oft. Sollte aber dennoch mal ein EEPROM 
länger als 10ms schreiben (warum auch immer!), dann haben wir ein Gerät 
im Feld, das blockiert- nur als Hintergrund: wir gehen in einigen 
Monaten in Serie mit einigen 10.000 Geräten. Jedes Gerät hat eine 
Lebensdauer von 6 Jahren. Damit will ich sagen: jeder Fehler, der 
irgendwann auftreten könnte- der TRITT auch auf irgendwann. Daher liegt 
mir dieses Thema am Herzen.

Dennoch mal einen schönen Dank an alle Mit - Teilnehmer zu diesem Thema.

von Frank B. (f-baer)


Lesenswert?

Die I2C-Peripherie des STM32 ist gelinde gesagt eine Katastrophe.
Benutze am besten die CPAL-Library, darin sind die meisten Fehler schon 
abgefangen. Dann gibts nur noch ab und zu Probleme damit, 1-Byte-Befehle 
zu senden (also Start-Adresse-Byte-Stop), das sollte man tunlichst 
vermeiden.
Ich habe damit leider jeden Tag zu tun und seit ich alles auf CPAL 
umgerüstet habe, ist die Sache deutlich stabiler, wenn auch nicht immer 
alles perfekt läuft.

von Klaus (Gast)


Lesenswert?

Peter D. schrieb:
> Er wollte ja auf das ACK warten und das geht nicht.

Das geht prizipiell nicht. Ich zitier mich selber:

Klaus schrieb:
> Der Master taktet das ACK selbst, da kann es kein Timeout geben.

Joey4711 schrieb:
> as mich irritiert ist, dass alle andere I2C Aktionen einwandfrei
> funktionieren; mein Verdacht ist, dass es eine "Besonderheit" auf Seite
> des STM32 ist, denn es gibt mehrere Foren, die das "ACK Polling" Problem
> betreffen, und da geht es immer um STM32 Controller, nie um andere (ist
> natürlich ein Indiz, kein Beweis).

Wenn eine gelieferte Library im Spiel ist, könnte es daran liegen. Da 
die meisten Programme, die ich hier gesehen habe, das ACK bzw NAK 
grundsätzlich nicht auswerten (andere Fehlerzustände natürlich auch 
nicht), würde ein SW-Fehler da lange unentdeckt bleiben.

MfG Klaus

von MWS (Gast)


Lesenswert?


von Peter D. (peda)


Angehängte Dateien:

Lesenswert?

Frank B. schrieb:
> Die I2C-Peripherie des STM32 ist gelinde gesagt eine Katastrophe.

Da ich keinen I2C-Interrupt verwende, mache ich einfach das I2C in 
Software. Das funktioniert immer und auf Anhieb. Und mehr Code ist es 
auch nicht.

Anbei mal meine EEPROM-Lib.

von Walter T. (nicolas)


Lesenswert?

Peter D. schrieb:
> mache ich einfach das I2C in
> Software.

Das ist geschummelt! Du drückst Dich um das Tal der Tränen, das jeder, 
der die STM32-Peripherie nutzen will, durchschreiten muß. Und das 
Schlimme ist: Ich habe Deine I2C-Bitbang-Schummel-Routinen auch schon 
genutzt. Nämlich dann, wenn ich nicht sicher war, ob ein merkwürdiges 
Verhalten von der I2C-Peripherie auf der MCU oder vom angesprochenen 
Device kommt.

von Peter D. (peda)


Lesenswert?

Walter T. schrieb:
> Das ist geschummelt! Du drückst Dich um das Tal der Tränen

Warum soll man durch das steinige Tal gehen, wenn der bequeme Weg genau 
gleich lang dauert?
Das HW-I2C hat erst dann Vorteile, wenn man es als Interrupt im 
Hintergrund laufen läßt bzw. einen I2C-Slave benötigt.

von Frank B. (f-baer)


Lesenswert?

Peter D. schrieb:
> Frank B. schrieb:
>> Die I2C-Peripherie des STM32 ist gelinde gesagt eine Katastrophe.
>
> Da ich keinen I2C-Interrupt verwende, mache ich einfach das I2C in
> Software. Das funktioniert immer und auf Anhieb. Und mehr Code ist es
> auch nicht.
>
> Anbei mal meine EEPROM-Lib.

Interessant und traurig zugleich, dass man heute auf einem 
hochgezüchteten Controller mit so viel Peripherie lieber Bitbanging 
benutzt.
Ich bin in meinen Programmen leider auf Interrupts angewiesen, sonst 
dreht der CAN-Bus durch, wenns mal wieder länger dauert.

von Walter T. (nicolas)


Lesenswert?

Peter D. schrieb:
> Warum soll man durch das steinige Tal gehen, wenn der bequeme Weg genau
> gleich lang dauert?

DMA

von Peter D. (peda)


Lesenswert?

Frank B. schrieb:
> Ich bin in meinen Programmen leider auf Interrupts angewiesen, sonst
> dreht der CAN-Bus durch, wenns mal wieder länger dauert.

Ich mache CAN generell immer als Interrupt, da kann sich das Main soviel 
Zeit lassen, wie es lustig ist.
Auch kann man das I2C leicht in Scheibchen schneiden, da es keine 
Maximalzeiten kennt (ein Byte oder nur ein Bit je Maindurchlauf).

von Peter D. (peda)


Lesenswert?

Walter T. schrieb:
> DMA

Sag ich doch, nur im Hintergrund hat das HW-I2C Vorteile.
Allerdings lohnt sich der Aufwand nur, wenn man austesten will, nach 
wieviel Mio Schreibzyklen der EEPROM die Grätsche macht.
Nur um 0..3 mal am Tag ne neue Konfiguration abzuspeichern, aber eher 
nicht.
I2C belegt nur selten ein merkbare CPU-Last, daher wird es auch kaum als 
Interrupt implementiert.

: Bearbeitet durch User
von Joachim B. (jar)


Lesenswert?

was der TO am Anfang beschreibt ist mir auch beim Arduino passiert, kann 
also nix mit dem STM oder der Lib zu tun haben.

Ich hatte vorher ja nur im AVR Studio gearbeitet und wusste wann ich 
eine ACK oder NACK Sequenz brauchte und konnte das manuell einpflegen.

Am Arduno Fehlanzeige, solange ich "nur" einen PCF85574(A) befrage oder 
nur ein DS3231 Register abhole kein Problem.

Am Arduino wurde das I2C EEPROM in allen Listings immer mit delay(5) 
gelöst, für mich unhaltbar auf jede Zelle 5ms zu warten was bei Block 
write auch schiefgehen kann wenn das EEPROM 6ms braucht.

Ich überlegte doch glatt für 10µs mit einem anderen Port den Zustand 
abzufragen nach einer write Sequenz und fand dann aber das 
"Prüfkommando", einfach neues Read nach write in einer Schleife zu 
starten und wenn das fehlerfrei klappte ohne ERROR war das I2C EEPROM 
wieder bereit. Beim purren EEPROM hatte ich früher ja das busy Bit 
befragen können, nun eben wenn das EEPROM sich wieder meldet.

Klaus schrieb:
> Wenn eine gelieferte Library im Spiel ist, könnte es daran liegen. Da
> die meisten Programme, die ich hier gesehen habe, das ACK bzw NAK
> grundsätzlich nicht auswerten

das hat doch nix mit auswerten zu tun, oder verstehe ich was falsch?

Ich will 2 Bytes empfangen und das erste wird mit ACK quittiert, das 2te 
und letzte mit NACK

genauso bei einer Kette von 10 Byte, 9x ACK das letzte mit NACK

Wie soll man das machen wenn man einen Block per LIB schickt, dort 
müsste das letzte Byte ja in der LIB per NACK verarbeitet werden, aber 
wenn I2C stretching auftritt weiss ich nie wann, ergo delay oder Port 
beobachten oder prüfen wann das IC wieder mit mir redet.
1
// P. Fleury war so nett eine LIB zu bauen 
2
// Auschnitt:
3
i2c_start_wait(DS3231+I2C_WRITE);  // set device address and write mode
4
i2c_write(DS3231_ControlReg);
5
i2c_rep_start(DS3231+I2C_READ);     // set device address and read mode
6
control=i2c_readAck();
7
status=i2c_readNak();
8
i2c_stop();


also so nach write und nach write block
1
do {
2
Wire.beginTransmission(_address); Wire.requestFrom(_address, 1);
3
_data = readIIC();
4
_error = Wire.endTransmission();
5
}while(_error);

kann ja mit einem timeout erweitert werden

: Bearbeitet durch User
von Klaus (Gast)


Lesenswert?

Joachim B. schrieb:
> Klaus schrieb:
>> Wenn eine gelieferte Library im Spiel ist, könnte es daran liegen. Da
>> die meisten Programme, die ich hier gesehen habe, das ACK bzw NAK
>> grundsätzlich nicht auswerten
>
> das hat doch nix mit auswerten zu tun, oder verstehe ich was falsch?

Wenn die Lib buggy ist und sich nie jemand um ACK bzw NAK kümmert, merkt 
das kein Mensch. Das war gemeint.

Auch die Funktionen der  P. Fleury Lib haben Returnwerte und auch in 
deinem Code sehe ich nichts, was sie auswertet. Obwohl ich es da für 
unwahrscheinlich halte, das die Lib buggy ist.

Joachim B. schrieb:
> Wie soll man das machen wenn man einen Block per LIB schickt, dort
> müsste das letzte Byte ja in der LIB per NACK verarbeitet werden,

Eine Blockfunktion sollte einen brauchbaren Returnwert haben so z.B.

- cannot set START, Bus not idle
- no ACK at address Byte, operation with STOP aborted
- no ACK at data Byte ...
.
.

Joachim B. schrieb:
> fand dann aber das
> "Prüfkommando", einfach neues Read nach write in einer Schleife zu
> starten und wenn das fehlerfrei klappte

Damit hast du gerade das "ACK polling" erfunden. Wobei es geschickter 
ist, mit R/W = 0 zu pollen und danach mit STOP abzubrechen. Ganz ganz 
dumme Slaves erwarten nach einem Read mindestens 9 Clockpulse, bevor sie 
den Bus wieder frei geben.

MfG Klaus

von Joachim B. (jar)


Lesenswert?

Klaus schrieb:
> Damit hast du gerade das "ACK polling" erfunden.

ich war es nicht, aber danke für diesen Hinweis:

Klaus schrieb:
> mit R/W = 0 zu pollen

Mich wunderte nur das dies so schwer zu finden war und warum fast alle 
ein delay nach I2C EEPROM write setzen, klar es geht aber elegant ist 
anders.

Klaus schrieb:
> Wobei es geschickter
> ist danach mit STOP abzubrechen.

macht das nicht?

Wire.endTransmission();

: Bearbeitet durch User
von Joachim B. (jar)


Lesenswert?

Klaus schrieb:
> Auch die Funktionen der  P. Fleury Lib haben Returnwerte und auch in
> deinem Code sehe ich nichts, was sie auswertet. Obwohl ich es da für
> unwahrscheinlich halte, das die Lib buggy ist.

ich weiss, da kürze ich Schlamper gerne ab, mal aus Bequemlichkeit, mal 
aus Platznot, rate mal warum ich den Arduino mighty atmega1284p so mag?

buggy ist P.Fleurys LIB definitiv nicht, sie sogar sauber und leicht 
verständlich.

: Bearbeitet durch User
von Frank B. (f-baer)


Lesenswert?

Peter D. schrieb:
> Frank B. schrieb:
>> Ich bin in meinen Programmen leider auf Interrupts angewiesen, sonst
>> dreht der CAN-Bus durch, wenns mal wieder länger dauert.
>
> Ich mache CAN generell immer als Interrupt, da kann sich das Main soviel
> Zeit lassen, wie es lustig ist.

Schon klar, ich habe noch ein CANopen-Protokoll zeitnah auszuwerten, 
denn der HBC ärgert sich, wenn die Antwortzeiten zu lang werden...

von Walter T. (nicolas)


Lesenswert?

Funktioniert das "acknoledge polling" jetzt eigentlich mit den 
bitbanging-Routinen?

von Peter D. (peda)


Lesenswert?

Frank B. schrieb:
> Die I2C-Peripherie des STM32 ist gelinde gesagt eine Katastrophe.

Ich bin auch nicht mit dem I2C der AVRs zufrieden, das hängt sich als 
Multimaster ständig auf, man braucht einen Timeouthandler, der es 
rücksetzt. Das gleiche auch bei den Atmel 8051.

Richtig zuverlässig hat bei mir nur das I2C der original Philips P80C652 
funktioniert, das braucht keine Überwachung mit Timeout. Einmal enablen 
und es läuft und läuft und ...

von Klaus (Gast)


Lesenswert?

Walter T. schrieb:
> Funktioniert das "acknoledge polling" jetzt eigentlich mit den
> bitbanging-Routinen?

Irgendwie scheinst du noch nicht verstanden zu haben, worum es beim "ACK 
polling" wirklich geht.

Ein I2C Slave muß auf seine Adresse nach START mit ACK reagieren. Ein 
EEPROM stellt sich aber tot, wenn es mit Schreiben beschäftigt ist. Es 
antwortet nicht, das heißt der Master liest ein NAK vom Bus. Ein sauber 
programmierter Master beendet dann die Übertragung mit einem STOP. Erst 
wenn es mit Schreiben fertig ist, liefert das EEPROM wieder ein ACK auf 
seine Adresse. Die Funktionen START anlegen, Adresse senden und dabei 
ACK/NAK einlesen, STOP erzeugen etc sind die Grundfuktionen von I2C. Ob 
diese von einer HW oder einer SW erzeugt werden, ist unerheblich.

MfG Klaus

von Gerhard O. (gerhard_)


Lesenswert?

Zur Information,

Ich Verwende schon seit einigen Jahren mit guten Erfolg die "Optimized 
I2C library". Die funktioniert einwandfrei und hatte noch nie Probleme 
damit. Kann ich nur wärmstens empfehlen. Die lässt sich auch mit 
interrupt, gepollt, und mit DMA konfigurieren.

Diese Library verwendet die I2C hardware ohne irgendwelche Probleme. 
auch ACK polling funktioniert richtig.

Die Beschreibung der I2C Hardware im User Manual ist meiner Meinung nach 
aber eher suboptimal. Da tut man sich schwer die Idiosynkrasien der I2C 
Hardware genügend zu verstehen. Auch sind die Errata darüber recht 
voluminös.

Hatte mit keinem der getesteten EEPROMS irgendwelche Probleme.

Lese mal die AN2824 zum Überblick durch.

https://my.st.com/public/STe2ecommunities/mcu/Lists/cortex_mx_stm32/Flat.aspx?RootFolder=https%3a%2f%2fmy%2est%2ecom%2fpublic%2fSTe2ecommunities%2fmcu%2fLists%2fcortex%5fmx%5fstm32%2fUsing%20STM32%20Optimized%20I2C%20examples%20when%20two%20I2C%20devices%20connected%20to%20one%20I2C%20port&FolderCTID=0x01200200770978C69A1141439FE559EB459D7580009C4E14902C3CDE46A77F0FFD06506F5B&currentviews=8277

Für mich ist sie jedenfalls jetzt meine Standard I2C Library auf die man 
sich verlassen kann.

Vorher verwendete ich eine eigene soft Lib ähnlich wie die von PD. Hat 
auch gut funktioniert.

Gruß,
Gerhard

von Christian J. (Gast)


Lesenswert?

Klaus schrieb:
> Irgendwie scheinst du noch nicht verstanden zu haben, worum es beim "ACK
> polling" wirklich geht.

Ich hol das mal wieder hoch, weil ich JETZT GERADE vor dem genau 
gleichen Problem stehe bei einem 64k E2PROM das ACK zu pollen, während 
das E2PROM gerade  ein Byte wegschreibt. Das muss doch irgendwie gehen, 
meine Routinen funktionieren auch.

Bloss das hier nicht, was ich mir aus den Finger gesogen habe, wie es 
gehen könnte. Tut es aber nicht :-(
1
// Polling, bis E2PROM das Byte weggeschrieben hat
2
        uint cnt = 0;
3
        do {
4
            I2C_GenerateSTART(I2C3, ENABLE);
5
            I2C_Send7bitAddress(I2C3, MEM_DEVICE_WRITE_ADDR, I2C_Direction_Transmitter);
6
            /* Test on I2C3 EV6 and clear it */
7
            timeout = I2C_TIMEOUT_MAX; /* Initialize timeout value */
8
            while(!I2C_CheckEvent(I2C3, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED))
9
            {
10
                /* If the timeout delay is exeeded, exit with error code */
11
                if ((timeout--) == 0) return 0xFF;
12
            }
13
            cnt++;
14
        } while (I2C_CheckEvent(I2C3, I2C_EVENT_SLAVE_ACK_FAILURE));

Ist das überhaupt das richtige Event? I2C_EVENT_SLAVE_ACK_FAILURE

Mama..... ich will meinen Arduino wiederhaben.....das klappte da alles 
:-(

von Peter D. (peda)


Lesenswert?

Christian J. schrieb:
> Bloss das hier nicht, was ich mir aus den Finger gesogen habe, wie es
> gehen könnte. Tut es aber nicht :-(

Kein Wunder, Du ignorierst ja standhaft die Beispiele, bzw. die 
I2C-Beschreibung im Datenblatt des EEPROM.

ACK-Polling heißt, Du sendest Start+Adresse+Stop in einer Schleife und 
prüfst das ACK auf die Adresse.
Diese Schleife hast Du nicht, also kanns nicht gehen.

von Joachim B. (jar)


Lesenswert?

Peter D. schrieb:
> Kein Wunder, Du ignorierst ja standhaft die Beispiele, bzw. die
> I2C-Beschreibung im Datenblatt des EEPROM.
>
> ACK-Polling heißt, Du sendest Start+Adresse+Stop in einer Schleife und
> prüfst das ACK auf die Adresse.
> Diese Schleife hast Du nicht, also kanns nicht gehen.

Christian J. schrieb:
> das ACK zu pollen, während
> das E2PROM gerade  ein Byte wegschreibt. Das muss doch irgendwie gehen,
> meine Routinen funktionieren auch.

ich hatte ja hier beschrieben wie es geht:
Beitrag "Re: I2C Problem mit Acknowledge Polling"

das sollte auch anderswo klappen:

Joachim B. schrieb:
> also so nach write und nach write block
> do {
> Wire.beginTransmission(_address); Wire.requestFrom(_address, 1);
> _data = readIIC();
> _error = Wire.endTransmission();
> }while(_error);

von Christian J. (Gast)


Lesenswert?

Joachim B. schrieb:
> ich hatte ja hier beschrieben wie es geht:
> Beitrag "Re: I2C Problem mit Acknowledge Polling"

Arduino hat aber auch nichts mit dem STM32 zu tun. es geht mir nicht um 
die Vorgehensweise sondern um die Coderierung. Das I2C Modul des STM32 
ist um Längen komplexer als das eines AVR.

von Peter D. (peda)


Lesenswert?

Christian J. schrieb:
> Das I2C Modul des STM32
> ist um Längen komplexer als das eines AVR.

Trotzdem muß man aber den gleichen Ablauf verwenden, wie beim AVR, 8051 
oder SW-IWC und kann sich nicht was anderes aus den Fingern saugen.

: Bearbeitet durch User
von Joachim B. (jar)


Lesenswert?

Peter D. schrieb:
> Trotzdem muß man aber den gleichen Ablauf verwenden, wie beim AVR

danke, sehe ich als Einäugiger genauso, es ist doch egal unter welcher 
Plattform, ich speche den Chip solange an bis er sich wieder meldet, 
solange ist er eben "busy" und wer Hosenträger und Gürtel mag der nimmt 
zusätzlich einen timeout.

von Christian J. (Gast)


Lesenswert?

Ok,

trotzdem wäre es nett, wenn jemand eine fertige Routine hätte, welches 
Bit da wo geprüft wird, welches Eventflag zuständig ist usw.

>> bis er sich wieder meldet,

Dazu müsste ich erstmal wissen, welche Funktion der StdPeriphLib mir 
mitteilt, dass er sich gemeldet hat.... das I2C Modul hat mehr als
hundert Config und Flag Bits. Das Prinzip ist mir klar, es geht nur um
die Codierung für diespen speziellen Prozessor mit einer speziellen
HAL.

Der Code oben ist komplett, er sendet Start und Schreibadresse, wartet 
bis diese raus sind. Ok, vielleicht fehlt noch ein Stop.

I2C_CheckEvent(I2C3, I2C_EVENT_SLAVE_ACK_FAILURE)); ???

von Mehmet K. (mkmk)


Lesenswert?

@peda
Wenn ich mir ein IC aussuche, dann achte ich darauf, dass es keines mit 
I2C-Interface ist. Mit anderen Worten: I2C ist nicht so mein Gebiet.

Bei Deinem Kod ist mir aber aufgefallen, dass Du nirgends 
Clock-Stretching in Betracht gezogen hast. Habe ich in Deinem Kod etwas 
übersehen? Oder ist das nicht so wichtig?

von Peter D. (peda)


Lesenswert?

Mehmet K. schrieb:
> Bei Deinem Kod ist mir aber aufgefallen, dass Du nirgends
> Clock-Stretching in Betracht gezogen hast.

Bei EEPROM, IO-Expander usw. ist SCL nur ein Eingang.
Ist der Slave aber ein weiterer MC, muß man das Clock-Stretching 
natürlich noch implementieren.

von Peter D. (peda)


Lesenswert?

Christian J. schrieb:
> I2C_CheckEvent(I2C3, I2C_EVENT_SLAVE_ACK_FAILURE)); ???

Das alles sollte aber doch im Manual zu Deiner Lib umfassend beschrieben 
sein.
Wenn nicht, dann hilft nur die Lib wegschmeißen und die Register/Bits 
selber setzen/auswerten.

von Christian J. (Gast)


Lesenswert?

Peter D. schrieb:
> Das alles sollte aber doch im Manual zu Deiner Lib umfassend beschrieben
> sein.

Peter, diese Lib schreibe ich gerade. Alle bisher gefundenen Libs haben 
E2Proms nicht auf dem Radar oder da steht einfach Delay(5ms) hinter 
jedem Byte was ja nicht Sinn der Sache sein kann. Und ACK Polling ist in 
keinem Beispiel zu finden bzw. sehe ich es wohl nicht. Das braucht man 
auch beim Page Write, es sei denn man will 10ms warten, obwohl es 
vielleicht auch nur 5ms sind.

von Peter D. (peda)


Lesenswert?

Christian J. schrieb:
> Alle bisher gefundenen Libs haben
> E2Proms nicht auf dem Radar

Darum geht es nicht, sondern um die Lib für die I2C Basisfunktionen.
Und die I2C-Write Funktion muß zurückliefern, ob sie vom Slave ACK oder 
NACK empfangen hat.
Erst dann kann man sich aus den Basisfunktionen eine EEPROM-Lib bauen.
Schau Dir mal mein Beispiel an:
Beitrag "Re: I2C Problem mit Acknowledge Polling"

von Christian J. (Gast)


Lesenswert?

Tja, siehst Du da was, was so ausschaut? Das ist nur Einzelbyte 
Schreiben.....
1
uint8_t Write_24Cxx(uint16_t Addr, uint8_t Data, uint8_t Mem_Type)
2
    {
3
     
4
      uint32_t timeout = I2C_TIMEOUT_MAX;
5
      uint8_t upper_addr,lower_addr;
6
     
7
      lower_addr = (uint8_t)((0x00FF)&Addr);
8
     
9
      if(Mem_Type==M24512)
10
      {
11
      Addr = Addr>>8;
12
      upper_addr = (uint8_t)((0x00FF)&Addr);
13
            }
14
           /* Generate the Start Condition */
15
           I2C_GenerateSTART(I2C1, ENABLE);
16
     
17
           /* Test on I2C1 EV5, Start trnsmitted successfully and clear it */
18
           timeout = I2C_TIMEOUT_MAX; /* Initialize timeout value */
19
           while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_MODE_SELECT))
20
           {
21
                /* If the timeout delay is exeeded, exit with error code */
22
        if ((timeout--) == 0) return 0xFF;
23
           }
24
     
25
           /* Send Memory device slave Address for write */
26
           I2C_Send7bitAddress(I2C1, MEM_DEVICE_WRITE_ADDR, I2C_Direction_Transmitter);
27
     
28
           /* Test on I2C1 EV6 and clear it */
29
           timeout = I2C_TIMEOUT_MAX; /* Initialize timeout value */
30
           while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED))
31
           {
32
               /* If the timeout delay is exeeded, exit with error code */
33
        if ((timeout--) == 0) return 0xFF;
34
           }
35
     
36
      if(Mem_Type==M24512)
37
      {
38
        /* Send I2C1 location address LSB */
39
        I2C_SendData(I2C1, upper_addr);
40
     
41
        /* Test on I2C1 EV8 and clear it */
42
        timeout = I2C_TIMEOUT_MAX; /* Initialize timeout value */
43
        while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTED))
44
        {
45
          /* If the timeout delay is exeeded, exit with error code */
46
          if ((timeout--) == 0) return 0xFF;
47
        }
48
      }
49
      /* Send I2C1 location address LSB */
50
            I2C_SendData(I2C1, lower_addr);
51
     
52
          /* Test on I2C1 EV8 and clear it */
53
          timeout = I2C_TIMEOUT_MAX; /* Initialize timeout value */
54
          while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTED))
55
          {
56
                /* If the timeout delay is exeeded, exit with error code */
57
        if ((timeout--) == 0) return 0xFF;
58
          }
59
     
60
           /* Send Data */
61
           I2C_SendData(I2C1, Data);
62
     
63
            /* Test on I2C1 EV8 and clear it */
64
            timeout = I2C_TIMEOUT_MAX; /* Initialize timeout value */
65
            while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTED))
66
            {
67
                 /* If the timeout delay is exeeded, exit with error code */
68
        if ((timeout--) == 0) return 0xFF;
69
            }  
70
     
71
            /* Send I2C1 STOP Condition */
72
            I2C_GenerateSTOP(I2C1, ENABLE);
73
     
74
            /* If operation is OK, return 0 */
75
            return 0;
76
    }

von Joachim B. (jar)


Lesenswert?

Christian J. schrieb:
> Und ACK Polling ist in
> keinem Beispiel zu finden bzw. sehe ich es wohl nicht. Das braucht man
> auch beim Page Write, es sei denn man will 10ms warten, obwohl es
> vielleicht auch nur 5ms sind.

deswegen habe ich ja die Arduino Routine erweitert, alle I2C EEPROM LIB 
die ich fand wartete immer 5-10ms, das kann nicht sinnvoll sein, mit dem 
polling ist es viel schneller.

: Bearbeitet durch User
von Peter D. (peda)


Lesenswert?

Christian J. schrieb:
> Tja, siehst Du da was, was so ausschaut?

Weil Du das ACK-Polling nicht verstanden hast. Nirgends wird auf ACK 
geprüft und das ist zwingend notwendig!

Wie das ACK/NACK vom I2C_CheckEvent() geliefert werden kann weißt nur Du 
nach dem Lesen der Doku zu Deiner I2C-Lib. Ich kenne Deine Lib ja nicht.

Hier nochmal das ACK-Polling Pseudocode:
1
  while( 1 ){
2
    I2C_start();
3
    I2C_write(adresse);
4
    if( I2C_status == ACK )
5
      break;
6
    I2C_stop();
7
  };

von Joachim B. (jar)


Lesenswert?

Peter D. schrieb:
> if( I2C_status == ACK )
>       break;

muss man nich auch auf NACK abfragen wenn nur ein Byte gelesen werden 
soll?

von Peter D. (peda)


Lesenswert?

Joachim B. schrieb:
> muss man nich auch auf NACK abfragen wenn nur ein Byte gelesen werden
> soll?

Beim Lesen dreht sich die Datenrichtung um, d.h. der Master liest das 
Byte und sendet das ACK.
Das ACK zeigt dem Slave an, daß der Master noch weitere Bytes lesen 
will.
Nach dem letzten Byte muß daher der Master ein NACK senden, ansonsten 
kann das STOP fehlschlagen.
In meiner EEPROM-Lib ist das entsprechend implementiert:
1
    *sram++ = si2c_r( !--len );                         // NACK on last byte

von Christian J. (Gast)


Lesenswert?

Peter D. schrieb:
> Wie das ACK/NACK vom I2C_CheckEvent() geliefert werden kann weißt nur Du
> nach dem Lesen der Doku zu Deiner I2C-Lib. Ich kenne Deine Lib ja nicht.

Peter..... nochmal: Es gibt keine Lib! Ich schreibe die Funktionen 
gerade. Weil ich mich in vieles eingelesen habe und feststelle, dass die 
allermeisten Libs aus dem Netz, die halbwegs lesbar sind und nicht nur 
aus einem Wust Registerzugriffen bestehen sehr "dürftig" sind. Nämlich 
meist überhaupt keine Fehlerbehandlung haben, auch kein ACK des Slaves 
prüfen bei Schreiben usw. Ok, was soll man auch machen, wenn was 
schiefgeht? Reparieren kann es die CPU ja nicht.

Ich habe jedenfalls aufgegeben sowas simples wie das ACK zu ckecken für 
die StdPeriphLibs des STM32. Ohne deren genaue Funktion zu kennen hat 
das keinen Sinn und die .chm Datei die es nur noch als Hilfe gibt funzt 
bei mir nicht.

von Peter D. (peda)


Lesenswert?

Christian J. schrieb:
> Peter..... nochmal: Es gibt keine Lib!
...
> Ich habe jedenfalls aufgegeben sowas simples wie das ACK zu ckecken

Warum?
Da Du den konkreten Typ nicht nennst, habe ich mal ins STM32F303 
Reference Manual geschaut:
1
28.7.7 Interrupt and status register (I2C_ISR)
2
3
Bit 4 NACKF: Not Acknowledge received flag
4
This flag is set by hardware when a NACK is received after a byte transmission. It is cleared by
5
software by setting the NACKCF bit.
6
Note: This bit is cleared by hardware when PE=0.

Was ist so schwer daran, dieses Bit zu lesen?

von Klaus (Gast)


Lesenswert?

Christian J. schrieb:
> Peter..... nochmal: Es gibt keine Lib!

Wo kommen denn dann diese Funktionen her?

> I2C_GenerateSTART(I2C1, ENABLE)

oder

> I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_MODE_SELECT)

MfG Klaus

von Christian J. (Gast)


Lesenswert?

Peter D. schrieb:
> This flag is set by hardware when a NACK is received after a byte
> transmission.

Ja, das gilt aber nur für den Slave Betrieb. Die zugehörige Lib Funktion 
heisst I2C_Event(I2Cx, I2C_EVENT_SLAVE_ACK_FAILS), die aber nicht 
funktioniert da ich damit schon alle Variationen ausprobiert habe.

Der Master sendet ja NAK und danach STOP, wenn er keine weiteren Bytes 
lesen will, damit der Slave weiss, dass Ende ist.

Leider ist das Ganze schwer zu debuggen, da zeitkritisch.

Ich lass das erstmal ruhen, bis ich mich besser in die StdPeriphLib 
eingearbeitet habe.

von Peter D. (peda)


Lesenswert?

Christian J. schrieb:
> Ja, das gilt aber nur für den Slave Betrieb.

Nö:
1
Master transmitter
2
In the case of a write transfer, the TXIS flag is set after each byte transmission, after the 9th
3
SCL pulse when an ACK is received.
4
...
5
If a NACK is received: the TXIS flag is not set, and a STOP condition is automatically
6
sent after the NACK reception. the NACKF flag is set in the I2C_ISR register, and an
7
interrupt is generated if the NACKIE bit is set.

von Christian J. (Gast)


Lesenswert?

Evtl ist das beim 407 anders, der hat dieses Bit nicht aber

Acknowledge failure (AF)
This error occurs when the interface detects a nonacknowledge bit. In 
this case:
• the AF bit is set and an interrupt is generated if the ITERREN bit is 
set
• a transmitter which receives a NACK must reset the communication:
– If Slave: lines are released by hardware
– If Master: a Stop or repeated Start condition must be generated by 
software

von Christian J. (Gast)


Lesenswert?

Kurz die Auflösung für nachfolgende Generationen:

Ob ein EEPROM seinen Schreibzyklus beendet hat findet man mit folgender 
Sequenz bei einem STM32F4xx heraus (Timeout noch nicht drin). Nach ca 
3-4 Durchläufen kommt das ACK, alles drüber ist Timeout.
1
 // Warte bis Byte weggeschrieben wurde (Slave sendet solange kein ACK)
2
        do{
3
            I2C_GenerateSTART(I2C3, ENABLE);
4
            while(!I2C_CheckEvent(I2C3, I2C_EVENT_MASTER_MODE_SELECT));
5
            I2C_Send7bitAddress(I2C3, MEM_DEVICE_WRITE_ADDR, I2C_Direction_Transmitter);
6
7
        } while(I2C_WaitForByteTransmitted(I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED)!=0);

weil ich endlich im Header diesen Abschnitt fand.
Address Acknowledge
  *
  * After checking on EV5 (start condition correctly released on the 
bus), the
  * master sends the address of the slave(s) with which it will 
communicate
  * (I2C_Send7bitAddress() function, it also determines the direction of 
the communication:
  * Master transmitter or Receiver). Then the master has to wait that a 
slave acknowledges
  * his address. If an acknowledge is sent on the bus, one of the 
following events will
  * be set:
  *
  *  1) In case of Master Receiver (7-bit addressing): the 
I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED
  *     event is set.
  *
  *  2) In case of Master Transmitter (7-bit addressing): the 
I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED
  *     is set

von Peter D. (peda)


Lesenswert?

Christian J. schrieb:
> Nach ca
> 3-4 Durchläufen kommt das ACK, alles drüber ist Timeout.

So wenige? Dann hast Du aber den Timeout sehr hoch gesetzt.
Da der EEPROM kein Clock-Stretching macht, sollte ein Timeout = 0 
reichen.

Christian J. schrieb:
> weil ich endlich im Header diesen Abschnitt fand.

Also benutzt Du doch eine fertige Lib. Und zu dieser gibt es wirklich 
keine Doku?

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.