Hi,
ich habe folgendes Problem:
Ich versuche gerade eine I2C Kommunikation zwischen 2 Boards her zu
stellen. Auf einem Board läuft ein ATXMEGA16 auf dem anderen ein Cortex
STM32f103.
Nun ist es so, das der Cortex mit anderen Cortexen, und der ATXMAGA mit
anderen ATXMEGAS gut kommunizieren kann. Der Cortex kann auch per
Interrupt empfangen, was der ATXMEGA auf den I2C Bus sendet.
Nun das Problem:
Sobald der Cortex etwas auf den Bus sendet, steigt der ATXMEGA aus. Für
ein paar Byte sendet der ATXMEGA noch seine ACK, dann aber zieht er SCL
auf low, und reagiert nicht mehr. Der Cortex wartet dann endlos auf
Event 8.2
EV8 software sequence is managed before the current byte transfer
completes */
while ((I2Cx->SR1 & 0x00004) != 0x000004)
und nichts geht mehr.
Mesungen mit dem Oszi haben folgende Details gezeigt:
Beide senden mit ca 400 kHz, aber der Cortex hat eine geringere
Impulsbreite als der ATXMEGA.
Wenn der Cortex ein Byte verschickt, ist die Startcondition wesentlich
kürzer als die des ATXMEGA, auch geht SDL zwischen 2 Byte beim Cortex
nur ganz kurz auf High.
Ich sehe das so, dass der ATXMEGA mit den kürzeren clk Impulsen, der
kurzen Startbedingung und dem kurzen zwischen High der SDL Leitung nicht
zurechtkommt.
Wie kann ich den Cortex so konfigurieren, das er besser an den ATXMEGA
angepasst ist? (Auf die Programmierung des ATXMEGA habe ich keinen
Einfluss)
Hier mal meine Cortex gepollte Senderoutine. Ich habe es übrigens auch
mit DMA und Interrupgesteuertem senden versucht, aber auch Erfolglos
Sven Wagner schrieb:> Reduziere doch mal testweise die I2C-Geschwindigkeit auf 100 kHz.
hab ich schon versucht, hat nichts gebracht.
Laut I2C Spezifikation hält sich der Cortex an die Mindestbreiten von
Impulsdauer, Startbedingungsdauer und Dauer zwischen den Übertragungen.
Es ist zwar immer hart an der Grenze, aber die Mindestbedingungen werden
einghalten.
Daher befürchte ich, dass das Problem doch in meiner Cortex
Programmierung liegt.....
Die Diskussion geht schon länger, sie ist unter dem Thread
"stm32 Cortex I2C : Master zieht SCL auf Masse"
zu finden.......
> Es ist zwar immer hart an der Grenze, aber die Mindestbedingungen> werden einghalten.> Daher befürchte ich, dass das Problem doch in meiner Cortex> Programmierung liegt.....
Das verstehe ich nicht. Wenn sich der Cortex an die Spezifikation haelt
dann ist doch ganz offensichtlich die Gegenseite Murks. Also setze dort
einen Controller ein der sich auch an die Spezifikation haelt.
BTW: Ich habe den Eindruck als wenn ein gelegentliches Weghaengen von
Slaves bei I2C vollkommen normal ist. Aber natuerlich nicht andauernd!
Daher sollten die am I2C-Bus beteiligten Controller das erkennen und die
Uebertragung neu aufsetzen. Oder besser noch, man verzichtet auf dieses
Protokoll.
Olaf
Olaf schrieb:> Oder besser noch, man verzichtet auf dieses> Protokoll.
Das ist schon was Wahres dran :-)
Wäre es Dir möglich, die Cortex-Routinen so zu ändern, dass SCL und SDA
per Software geschaltet werden. Damit könntest Du das Timing nach
Belieben einstellen und sehen, WER der Böse im Spiel ist. Wenn es so
funktionieren sollte, wäre der Slave aus dem Schneider.
Olaf schrieb:> Das verstehe ich nicht. Wenn sich der Cortex an die Spezifikation haelt> dann ist doch ganz offensichtlich die Gegenseite Murks. Also setze dort> einen Controller ein der sich auch an die Spezifikation haelt.
ja das blöde ist halt, ich habe gestern mal versucht 2 Cortexe
miteinander sprechen zu lassen, und hatt dort das gleiche Phänomen:
Einer alleine sendet munter auf den I2C bus, wird ein zweiter
angeschlossen ist tot hose. Mal wird SCL gleich auf Low gezogen, mal
bleibt SCL auf high, aber immer ist funkstille auf dem Bus, weil im
entsprechenden Register des Cortex das Busy Flag gesetzt wird.
Willi schrieb:> Wäre es Dir möglich, die Cortex-Routinen so zu ändern, dass SCL und SDA> per Software geschaltet werden.
ich denke nicht, dass das geht. Normalerweise schreibt man in Register,
wartet auf Flags, und der Rest macht die Hardware....
Aber so langsam hab ich den Eindruck, das mit meinen Libs was nicht
stimmt.
Im Anhang mal die Libs die ich benutzt habe, vielleicht hat ja jemand
von euch schon Erfahrung mit diesen Libs gemacht, ob da was nicht so
richtig funktioniert.....
Beitrag "I2C-Master [ohne TWI (Softwarelösung) für die ATMEGAs"Sylvia H. schrieb:> ich denke nicht, dass das geht. Normalerweise schreibt man in Register,> wartet auf Flags, und der Rest macht die Hardware....
Genau das solltest Du nicht machen. Du brauchst eine stabile Referenz,
die sich nicht auf 'fremde' Hardware stützt.
Es gab Zeiten, da hatten nur wenige µCs IIC-Module, sodass man den
Bus-Master per Sofware impementieren mußte. Im einfachsten Fall war der
Slave ein EEPROM.
Eine reine Software-Lösung ist beispielsweise hier zu finden:
Beitrag "I2C-Master [ohne TWI (Softwarelösung) für die ATMEGAs"
Es ist natürlich ein bißchen Tipperei, aber besser, als sich graue Haare
zuzuziehen :-)
Willi schrieb:> Eine reine Software-Lösung ist beispielsweise hier zu finden:> Beitrag "I2C-Master [ohne TWI (Softwarelösung) für die ATMEGAs">> Es ist natürlich ein bißchen Tipperei, aber besser, als sich graue Haare> zuzuziehen :-)
Sieht interessant aus, wenn alle Stricke reissen werd ich mal das
Toggeln von Hand ausprobieren....
Hi!
lese das schon ne ganze Weile mit und werde das Gefühl nicht los das da
2 Master auf dem Buss rumplappern und keiner einen Rückzieher macht
(wer die meisten low's hat ist Sieger) Eins ist Fakt(meine ich
jedenfalls) Wärend einer Unterhaltung auf dem Bus ist nur ein Master
zugelassen. Treffen sich 2 Master muss einer aufgeben. Ist irgendwo ein
Collisionsflag vorhanden was man auswerten sollte?
Leider bastel ich (noch) nicht mit Cortex und es ist auch nur ein
Bauchgefühl, aber manchmal......
Viel Erfolg, Uwe
Uwe schrieb:> Treffen sich 2 Master muss einer aufgeben. Ist irgendwo ein> Collisionsflag vorhanden was man auswerten sollte?
Das war ein super Hinweis, ich habe mal in meiner (VON STM ZUR VERFÜGUNG
GESTELLT !!!) Lib nachgeschaut, und bei der Auswertung des Arbitration
Lost Flags einen Fehler entdeckt, dort wird das falsche Bit
zurückgesetzt! Man kann sich echt auf nichts mehr verlassen........
Ob das die Lösung ist weis ich nicht, bin im Moment gerade zuhause und
schreiben an meiner Bachelorarbeit. Aber am Montag schau ich sofort nach
was die Korrektur bringt !
Willi schrieb:> Eine reine Software-Lösung ist beispielsweise hier zu finden:> Beitrag "I2C-Master [ohne TWI (Softwarelösung) für die ATMEGAs"
Vorsicht, SW-I2C ist oft nur für dumme Slaves.
MC-Slaves benötigen noch das SCL-Stretching, da sie langsamer sind.
Läßt sich aber einfach in den SCL-Macros nachrüsten.
Willi schrieb:> Es ist natürlich ein bißchen Tipperei, aber besser, als sich graue Haare> zuzuziehen :-)
Am besten ausdrucken, einscannen und OCR laufen lassen.
Nur Warmduscher nehmen Ctrl+c, Ctrl+v.
Peter
Hi Leute,
nachdem ich tagelange Tests durchgeführt, ungefähr 1000000 mal alle
Register des Cortex kontrolliert, die I2C Spezifikation und das Cortex
Datasheet (sammt Errata) auswendig kann ;=) ....
Hier die Lösung des Problemes:
Die Von STM bereitgestellte Library für "Optimized I2C Exmples" (an2824)
weist folgende ausschlaggebende Fehler auf:
I2C2_ER_IRQHandler :
- Es fehlte die Behandlung folgender Error-Flags:
PECERR,TIMEOUT,SMBALERT
- ARLO: Das Flag wurde zum Zurücksetzen mit einer falschen Maske
verundet
- BERR: obwohl im Errata steht, es müsste nur in einer „noisy
environment“ folgendes programmiert werden, hat es sich herausgestellt,
dass man dies auch in einer ganz normalen Umgebung machen muss:
(übrigens, das Errata hat hier auch einen Fehler, man bräuchte wohl auch
noch ein Errata zum Errata…..)
Wenn ein BERR auftritt, und das START Bit ist gesetzt, muss I2C resettet
werden indem man in CR1 das SWRST Bit setzt. Aber Achtung, nicht
vergessen I2C2 danach wieder zu Initialisieren! Sonst läuft I2C2 weiter,
hat aber alle Register auf den Wert 0 gesetzt!!!!
Danach noch E2C Event Interrupts einschalten, und alles ist wieder ok:
1
/* If BERR = 1 */
2
if((SR1Register&0x0100)==0x0100){
3
4
I2C2->SR1&=0xFEFF;
5
6
if((I2C2->CR1&0x0100)==0x0100){//is START bit set?
7
/* Peripheral under reset */
8
I2C2->CR1|=CR1_SWRST_Set;//Errata S. 25
9
I2C_LowLevelInit(I2C2);
10
/* Enable the selected I2C interrupts */
11
I2C2->CR2|=I2C_IT_EVT;
12
}
13
14
SR1Register=0;
15
}
I2C_Master_BufferWrite:
Wenn der Master etwas auf den Bus schreiben möchte und die
Startbedingung gesetzt hat, dann wartet er auf Event 5.
Sollte in dieser Wartezeit ein BERR auftreten, wartet er endlos, deshalb
muss ein Timeout gesetzt werden. Kommt er in den Timeout, muss man hier
auch wieder I2C2 reseten, neu Initialisieren und den Event Interrupt
einschalten, genauso wie oben in der BERR = 1 Routine.
Dies sind die Fehler, die ich in der Firmaware gefunden habe. Was lerne
wir daraus? Mann kann echt auf nichts mehr verlassen, noch nicht mal auf
den Hersteller.....
Des Weiteren ist ein 10 kOhm pullup Widerstand wesentlich zu hoch.
Nun läufts auf dem I2C2 Bus !
Grüße von
Sylvia
Sylvia H. schrieb:> Was lerne> wir daraus? Mann kann echt auf nichts mehr verlassen, noch nicht mal auf> den Hersteller.....
Das war doch schon immer so :-)
Wenn scheinbar fertige Programme funktionieren und die LED lustig
blinkt, ist es schön. Wenn nicht, die Routinen besser selber schreiben
und Stück für Stück verstehen und testen.
Viele Demo-Programme sind so mit Kommentaren verstopft, dass man sie
garnicht mehr nachvollziehen kann. Auch ein Programmierstil, der
möglichst komplexe Strukturen verwendet, um zwei bis drei Bits zu
setzen, ist für Einsteiger nicht hilfreich.