Forum: Mikrocontroller und Digitale Elektronik Erkennung eines fehlenden EEPROMS über I²C-Bus


von Knut S. (Firma: Schmersal) (knuts)


Lesenswert?

Hallo.

Ich versuche zu über I²C zu prüfen, ob ein EEPROM vorhanden ist oder 
nicht.

dabei haben ich folgende Konfiguration:
 STM_enableRCCAPB1PeriphClock( RCC_APB1Periph_I2C1, ENABLE );
 STM_resetRCCAPB1PeriphCmd( RCC_APB1Periph_I2C1, DISABLE );
 I2C_Cmd( m_pEE_I2C_TYPE, ENABLE );
 I2C_ITConfig( m_pEE_I2C_TYPE, I2C_IT_ERR, ENABLE );
 I2C_InitStructure.I2C_Mode = EE_I2C_MODE;
 I2C_InitStructure.I2C_DutyCycle = EE_I2C_DUTY_CYCLE;
 I2C_InitStructure.I2C_OwnAddress1 = EE_I2C_OWN_ADDRESS;
 I2C_InitStructure.I2C_Ack = EE_I2C_ACK;
 I2C_InitStructure.I2C_AcknowledgedAddress = EE_I2C_ACK_ADDR;
 I2C_InitStructure.I2C_ClockSpeed = EE_I2C_CLOCK_SPEED;
 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6 BITOR GPIO_Pin_7;
 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_OD;

Mein Ansatz beruht auf der Idee, daß generateSTART() falls erfolgreich 
das SB-Bit im SR1-Register setzt und send7bitAddress() diese wieder 
löscht und im Erfolgsfall TxE (Transmit-Buffer leer) oder im Fehlerfall 
(AF (Acknowledge Fail) setzt; zudem hätte ich erwartet daß im 
Erfolgsfall auch ADDR gesetzt wird, aber das passiert wohl nicht oder es 
wird sofort zurückgesetzt.

  ...
  I2C_GenerateSTART( m_pI2C1, ENABLE );
  volatile uint16_t SR1Register = m_pI2C1->SR1;
  tRetval = u32_checkEvent( I2C_EVENT_MASTER_MODE_SELECT );
  if ( tRetval  EQ  EE_OK )
  {
    I2C_Send7bitAddress( m_pI2C1, u8DevAddr, I2C_Direction_Transmitter 
);
    // SR1->AF = 1, falls kein EERPOM,
    // TxE = 1 falls EEPROM, warum nicht ADDR?
    while ( ( SBBit  NEQ  0u )  OR  ( TeXBit  EQ  0u ) )
    {
       SR1Register = m_pI2C1->SR1;
       SBBit   = SR1Register & 0x001u;
       ADDRBit = SR1Register & 0x002u;
       TeXBit  = SR1Register & 0x080u;
    }
    SR1Register = m_pI2C1->SR1;
    uint16_t AFBit = SR1Register & 0x0400u;
    if ( AFBit  EQ  0u )
    { ...

Das scheitert aber, weil sich die Abarbeitung beim I2C_Send7bitAddress() 
aufhängt; genauer gesagt bei F11 beim Rücksprung nach erfolgreichem 
I2Cx->DR = Address und bei F10 beim folgenden while ((SBBit NEQ 0u) OR 
(TeXBit EQ 0u) (Ich verwende den IAR).

Kann mir irgendjemand sagen ob die Grundannahmen falsch sind, und falls 
nicht, was die Ursache für das Aufhängen sein könnte?

von Einer K. (Gast)


Lesenswert?

Knut S. schrieb:
> Mein Ansatz beruht auf der Idee,

Das nötige Verfahren wird auch "I2C Acknowledge Polling" genannt.

Damit sollten sich auch für deinen geheimnisvollen Rechner irgendwelche 
Erklärungen finden lassen.

von Knut Schünemann (Gast)


Lesenswert?

Mea Culpa,
Es geht um einen STM32F103 der einen 24AA044 von Microchip ansprechen 
soll.

von OMG (Gast)


Lesenswert?

Knut S. schrieb:
> genauer gesagt bei F11 beim Rücksprung nach erfolgreichem
> I2Cx->DR = Address und bei F10 beim folgenden while ((SBBit NEQ 0u) OR
> (TeXBit EQ 0u) (Ich verwende den IAR).

Du sprichst in Rätseln.

Meine Milchmädchenrechnung lautet: wenn man ein Byte von eimem
EEPROM lesen möchte und einen Fehlerzustand zurückgemeldet
bekommt dass ist kein EEPROM da. So einfach ist das. Dazu
braucht es keine sophisticated selbstgeschriebene Detektions-
routine.

von Cyblord -. (cyblord)


Lesenswert?

OMG schrieb:
> Knut S. schrieb:
>> genauer gesagt bei F11 beim Rücksprung nach erfolgreichem
>> I2Cx->DR = Address und bei F10 beim folgenden while ((SBBit NEQ 0u) OR
>> (TeXBit EQ 0u) (Ich verwende den IAR).
>
> Du sprichst in Rätseln.
>
> Meine Milchmädchenrechnung lautet: wenn man ein Byte von eimem
> EEPROM lesen möchte und einen Fehlerzustand zurückgemeldet
> bekommt dass ist kein EEPROM da. So einfach ist das. Dazu
> braucht es keine sophisticated selbstgeschriebene Detektions-
> routine.

Korrekt.
Es reicht eigentlich völlig aus nach dem rauschreiben der Adresse das 
ACK zu prüfen. Genau dafür ist das an dieser Stelle ja da.

von OMG (Gast)


Lesenswert?

OMG schrieb:
> dass ist kein EEPROM da

Nachbesserung: dann ist kein EEPROM da

von OMG (Gast)


Lesenswert?

Knut Schünemann schrieb:
> Es geht um einen STM32F103 der einen 24AA044 von Microchip ansprechen
> soll.

Das geht natürlich nicht, STM-Controller arbeiten nur mit
EEPROMs von STM zusammen, doch klar oder?

von Knut S. (Firma: Schmersal) (knuts)


Lesenswert?

Ja.

Ich hatte es zu Beginn mit einem klassischen Ack Polling versucht, aber 
da ähnliche Probleme wie Beitrag "I2C Problem mit Acknowledge Polling" 
bemerkt.
ACK und AF gleichzeitig gesetzt und der Prozeß hängt beim lesenden 
Zugriff auf SR1 nach dem Senden der Adresse; daher die Idee nur einzelne 
Bits der Register zu  zu betrachten in der Hoffnung daß man so Probleme 
mit der Library umgehen könnte.

von Knut S. (Firma: Schmersal) (knuts)


Lesenswert?

Das Problem ist daß das Lesen des Registers nicht zurückkehrt; der 
Prozeß steht bis ein IRQ-Timeout zuschlägt (nicht nur im Debugger, ich 
sehe in der freilaufenden Baugruppe dasselbe Verhalten); gleichgültig ob 
ich nach dem Ereignis mit einer Bibliotheksfunktion wie I2C_CheckEvent() 
sehe, mit  I2C_GetFlagStatus() die einzelnen Flags teste, oder direkt 
die Bits des Statusregisters prüfe, z.B. (((*(__IO uint32_t*)m_pI2C1 + 
0x14u)) & 0x400u).

Darum der Versuch, den Vorgängen durch Betrachtung der einzelnen Bits 
auf die Schliche zu kommen, und dann die Fragen:
- warum sind AF und ACK gleichzeitig oben? (ACK ist im CR1, steuert also 
und gibt keinen Status wieder.)
- wie kann ACK überhaupt gesetzt sein, wenn niemand da ist der die 
Adresse akzeptieren könnte? (dito)
- wann wird ADDR je gesetzt?
- gibt es für irgendwelche anderen Register außer CR1 noch weitere 
Zugriffverbot in bestimmten Stati der Kommunikation?

Beitrag #6674957 wurde vom Autor gelöscht.
von Knut S. (Firma: Schmersal) (knuts)


Lesenswert?

Ja, dachte ich auch so.
Es klappt auch wenn das EEPROM vorhanden ist: Nach dem Schreiben der 
Adresse AF gelöscht -> paßt.
(Wobei es noch das kleine Problem des "wann" gibt. Kann es passieren, 
daß der Controller schon das Flag prüft, während das EEPROM noch nicht 
alle Bits empfangen und sein ACK geschickt hat? Das ist ja kein 
synchroner Vorgang sondern läuft mit einer eigenen Clock auf dem 
geringeren Tempo des EEPROMs.)

Es klappt nicht unbedingt bei fehlendem EEPROM. Registriert der 
Controller überhaupt die fehlende Antwort als NACK? (Die Leitung bleibt 
Low, sollte also implizit funktionieren.)
Aber wie gesagt beobachte ich in dem Falle ein Halten des Prozesses; und 
da wäre wieder mein Problem.

von Knut S. (Firma: Schmersal) (knuts)


Lesenswert?

Das bezweifle ich.
I²C kam vom Philips und wird von einer Vielzahl Herstellern in ihre 
Produkte integriert; mit variierenden Protokollen für höhere 
Geschwindigkeiten, etc.
Er ist üblich als Kommunikationsprotokoll zwischen Bauteilen 
unterschiedlicher Hersteller, und auch zwischen Baugruppen mit ganz 
unterschiedlichen Komponenten.
Insbesondere weil nicht jeder Hersteller vom µC auch das ganze Spektrum 
an Peripherie anbietet.
Zudem funktioniert hier das Schreiben und Lesen ja durchaus - wenn das 
EEPROM existiert; mein Problem ist ein optional vorhandenes EEPROM, also 
aus Sicht des I²Cs eine Adresse im Kabelbaum, die auch im Nichts enden 
könnte.

von Oliver S. (oliverso)


Lesenswert?

Es wurde jetzt ja schon mehrfach gesagt:

Ein nicht vorhandenes i2c-Device verhält sich wie ein falsch 
addresiertes, und gibt dir ein NACK bei der Addressierung zurück. Rein 
technisch bleibt SDA im ACK-cycle einfach high, weil nichts da ist, 
das das low zieht.

Das ist eine so grundlegende i2c-Funktion, daß muß jeder I2C-Master im 
Schlaf ohne jegliches Programmier-Voodoo abhandeln können.

Knut S. schrieb:
> Es klappt nicht unbedingt bei fehlendem EEPROM. Registriert der
> Controller überhaupt die fehlende Antwort als NACK? (Die Leitung bleibt
> Low, sollte also implizit funktionieren.)

Finde den Fehler.

Oliver

: Bearbeitet durch User
von Cyblord -. (cyblord)


Lesenswert?

Knut S. schrieb:
> Es klappt nicht unbedingt bei fehlendem EEPROM. Registriert der
> Controller überhaupt die fehlende Antwort als NACK? (Die Leitung bleibt
> Low, sollte also implizit funktionieren.)

Welche "fehlende Antwort"? Es geht um EIN Bit. Das ACK/NAK.

Wenn die Leitung low bleibt stimmt etwas gewaltig nicht. Woher sollte 
das low kommen?
Vielleicht führst du dir erstmal in aller Ruhe die I2C Specs zu Gemüte 
und schaust dir dann das Problem nochmal an. Irgendwo scheint es da im 
Verständnis zu klemmen.
Einfach nur HAL/StdPeriph API reicht halt nicht. Man sollte schon wissen 
was man eigentlich tun will.

: Bearbeitet durch User
von jo mei (Gast)


Lesenswert?

Knut S. schrieb:
> Es klappt nicht unbedingt bei fehlendem EEPROM. Registriert der
> Controller überhaupt die fehlende Antwort als NACK? (Die Leitung bleibt
> Low, sollte also implizit funktionieren.)

Rieche ich da fehlende Pullup-Widerstände? Die müssen immer da
sein, auch wenn kein EEPROM angeschlossen ist.

Fehlende Pullups an den I2C Pins können ein nicht vorhandenes
ACK vortäuschen (lassen).

von jo mei (Gast)


Lesenswert?

Cyblord -. schrieb:
> Wenn die Leitung low bleibt stimmt etwas gewaltig nicht. Woher sollte
> das low kommen?

Wie ich gerade vorher schrub.

von Christian J. (Gast)


Angehängte Dateien:

Lesenswert?

Knut S. schrieb:
> Ich versuche zu über I²C zu prüfen, ob ein EEPROM vorhanden ist oder
> nicht.

Grüße nach Wuppertal erstmal von einem Wettbewerber! hehe :-)

Gleiche mal Deinen I2C Code mit meinem ab, der klappt nämlich 
einwandfrei inzwischen. Und wenn da nix drin steckt gibt es kein Event, 
while wartet ewig und dann müsste der WDG zuschlagen. Die einzelnen 
Events ab zu sichern ist nervig, bei mir haut der WDG rein, wenn da ein 
Bit hängt.

Und denke dran, dass EEPROMs nicht rücksetzbar sind! Ja, da gibt es die 
Geschichte mit den 9 Takten, im Jahre 2000 mal von Microchip in einer 
AppNote beschrieben worden, die bei mir nie funktioniert hat. Alle 2-3 
Wochen stand die Sache still. Inzwischen designe ich die EE mit einem 
PNP Transistor als abschaltbares VCC und wenn da was hängt schalte ich 
die kurz ab.

Was ist denn das ??? BITOR ???
PIO_InitStructure.GPIO_Pin = GPIO_Pin_6 BITOR GPIO_Pin_7;

Man nimmt einfach | :-)

Ist übrigens keine gute Idee SPL, HAL und Register zu mischen! Entweder 
man hält sich an eine API, weil die geprüft ist oder man haut sich 
zusätzliche Fehler mit dieser Bit-Pfuscherei rein, die kein Mensch 
später mehr nachvollziehen kann ohne das Reference Manual daneben liegen 
zu haben.

Ohne Dir zu nahe treten zu wollen, der Code sieht grauenhaft aus!

von Bit Fuscher (Gast)


Lesenswert?

Christian J. schrieb:
> Entweder
> man hält sich an eine API, weil die geprüft ist oder man haut sich
> zusätzliche Fehler mit dieser Bit-Pfuscherei rein,

Aha, eine API ist also immer fehlerfrei da geprüft!
Wenn man die Register direkt anspricht und das hinreichend kommentiert 
muß man nicht im RM nachschlagen. Und wenn man ein timeout so einfügt, 
dass es von der Taktfrequenz des verwendeten Controllers unabhängig ist, 
vermeidet man spontane Fehler, die nur schwer zu finden sind, Herr 
Wettbewerber.

> Ohne Dir zu nahe treten zu wollen, der Code sieht grauenhaft aus!

Deine "i2c_basic.h" auch.

von Knut S. (Firma: Schmersal) (knuts)


Lesenswert?

@Oliver S.:

Ja, danke, das ist mir jetzt auch klar, die Frage nach der 
Interpretation der leeren Leitung.

Aber die Frage ist, wann liegt dieses Belegung im Register vor?
Ich sende die Adresse raus, dann sollte BUSY gesetzt sein, wenn alle 
Bits draußen sind geht TxE hoch (oder nicht? Ich sehen nicht daß das 
passiert), irgendwann merkt der Master daß das NACK statt ACK auf der 
Leitung anliegt und setzt AF im SR1, korrekt?
Wann kann ich die Belegung des Registers als endgültigen Zustand ansehen 
und auswerten, insbesondere wenn mein Slave dann Clock Stretching 
betreiben könnte?
Und wann wird in dem Fall BUSY zurückgesetzt?

BTW:
Teste ich auf I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED, so prüfe ich 
ja auf  ADDR & BERR (nicht TxE?) & MSL & BUSY & TRA gesetzt.
Warum BERR?

von Knut S. (Firma: Schmersal) (knuts)


Lesenswert?

@Cyblord & jo mei:

Ja, danke, habe ich geprüft; das ist nicht das Problem.
Der NACK kommt und wird vom µC erkannt und ist als AF-Bit prüfbar.
Es war mein Mißverständis, das ACK-Bit nicht als Steuerbit erkannt zu 
haben  und darum dort eine Reaktion zu erwarten.
(Und normales Lesen und Schreiben klappt ja auch.)

Aber das bringt mich um Punkt den ich in der Spec nicht verstehe: Wenn 
der Slave viel langsamer als der µC ist, und außerdem Clock Stretching 
zugelassen ist, zu welchem Zeitpunkt oder welcher Situation kann ich 
davon ausgehen, daß ein gelöschtes AF-Bit einen funktionierenden Slave 
anzeigt?
ADDR sehe ich nie gesetzt, auch nicht wenn das angesprochene EERPOM 
existiert, TxE scheint mir in der Situation ein komplementäres Bit zu AF 
zu sein, aber warum maskiert I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED 
dann dieses Bit aus?

Sorry wegen der Low Level Fragen, aber bis jetzt habe ich nirgendwo eine 
Erklärung gefunden - vielleicht war da ja jemand erfolgreicher und hat 
eine Referenz zu Hand?

von Peter D. (peda)


Lesenswert?

Knut S. schrieb:
> Aber das bringt mich um Punkt den ich in der Spec nicht verstehe: Wenn
> der Slave viel langsamer als der µC ist, und außerdem Clock Stretching
> zugelassen ist, zu welchem Zeitpunkt oder welcher Situation kann ich
> davon ausgehen, daß ein gelöschtes AF-Bit einen funktionierenden Slave
> anzeigt?

Der Master sendet immer 9 Takte, d.h. Adresse/Daten + ACK/NACK werden in 
einem Rutsch gelesen. Clock Stretching ist also egal, der Interrupt 
kommt immer erst nach den 9 Takten.

von Knut S. (Gast)


Lesenswert?

@Christian J.:

Grüße zurück, wohin auch immer.

Danke für den Code.
Allerdings ist er praktisch identisch in den Abfolge der Schritte und 
führt zum selben Fehler: Aufhängen beim 1. I2C_CheckEvent(... 
,I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED) (falls kein EEPRoM 
existiert, sonst läuft es eh).

Aber ich wollte mal sehen ob der Hänger an einer anderen Stelle im 
Disassembly erfolgt als beim sehr ähnlichen früheren Code, ...und siehe 
da, als Einzelschritt über Mnenomics funktioniert es, und der das 
Aufhängen passiert an einem späteren checkEvent(), nachdem man den 
Einzelschritt Modus verlassen hat.
Also eher kein Problem mit dem Quellcode.


Reset ist klar, aber ich habe keinen Einfluß auf die Elektronik.
Sorry wegen dem Code, ist teilweise Copy & Paste aus der Sandbox, aber 
mit MISRA-Voreinstellungen aktiv.
Auch das mit dem Mischen von APIs ist einsichtig, aber wie gesagt: 
Sandbox und ich experimentiere mit Vorschlägen aus unterschiedlichen 
Quellen, und habe auch hier teilweise die Originalquellen zitiert.

von Peter D. (peda)


Lesenswert?

Christian J. schrieb:
> Und denke dran, dass EEPROMs nicht rücksetzbar sind! Ja, da gibt es die
> Geschichte mit den 9 Takten, im Jahre 2000 mal von Microchip in einer
> AppNote beschrieben worden, die bei mir nie funktioniert hat. Alle 2-3
> Wochen stand die Sache still.

Ja, diese AppNote ist falsch.
Man darf nicht stur 9 Takte senden, sondern muß nach jedem Takt prüfen, 
ob der Bus frei ist. Ein Slave sendet beim Schreiben jeden 9. Takt ein 
ACK bis zum St. Nimmerleins Tag.

Einem EEPROM den Saft abdrehen, das macht man einfach nicht.

: Bearbeitet durch User
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.