Hallo,
ich versuche zur Zeit mit einem STM32-P103 Board (72Mhz) einen I2C Bus
zu sniffen, die Daten onboard zu analysieren und via CAN wieder
rauszuschicken. I2C Bus Speed bis max 200kbit soll unterstützt werden.
Zum Sniffen nutze ich GPIO's die als Interrupts konfiguriert sind und
auf SCL und SDA, falling und rising edge triggern um I2C nachzustellen.
Nun habe ich das Problem, dass ich nicht alle Nachrichten mitbekomme und
der Interrupt seltener aufgerufen wird als er sollte. Nach meinen
Berechnungen habe ich 180 Controller Ticks Zeit den Interrupt zu
bearbeiten, wenn ich nur die I2C Clock betrachte. Nun würde ich gerne
wissen, ob ich mein Board zu schwach dimensioniert habe oder mein
aktueller Ansatz vielleicht aus anderen gründen nicht möglich ist.
Externe Interrupts sind immer etwas schwierig. Versuche es mal mit einer
Endlosschleife in der main () die ständig die GPIO ausliest.
Alternative: Verwende zwei der I2C Schnittstellen als Master und Slave
und schalte sie zwischen die Kommunikation und leite alles durch. Das
erhöht zwar die Latenzen, müsste aber funktionieren.
David S. schrieb:> Nun würde ich gerne> wissen, ob ich mein Board zu schwach dimensioniert habe oder mein> aktueller Ansatz vielleicht aus anderen gründen nicht möglich ist.
Dein Board ist mit Sicherheit nicht zu schwach.
Ich habe das mal mit Tiny2313, 400KHz und Bitbanging gemacht, also
muss es ein STM32 erst recht schaffen.
Vor allem, da bei 100KHz tSU:STA und tHD:STA in us Bereich sind.
Dr. Sommer schrieb:> Externe Interrupts sind immer etwas schwierig. Versuche es mal mit einer> Endlosschleife in der main () die ständig die GPIO ausliest.
o.O Wie kommt man denn auf sowas?!
Draco schrieb:> Dr. Sommer schrieb:>> Externe Interrupts sind immer etwas schwierig. Versuche es mal mit einer>> Endlosschleife in der main () die ständig die GPIO ausliest.>> o.O Wie kommt man denn auf sowas?!
Wieso eigentlich nicht ?
Was hat ein I2C_Sniffer sonst zu tun ?
Marc V. schrieb:> Wieso eigentlich nicht ?> Was hat ein I2C_Sniffer sonst zu tun ?
Naja, aber Interrupt gesteuert auf der SCL Line zu lauschen ist doch
effektiver als Polling in einer Main.
Er will ja auch noch "analyzern". Sprich: ein wenig rechnen muss der STM
ja auch :-D Über die Performance des STM kann ich nichts sagen - da ich
da keine Erfahrung habe.
Aber ich rechne mal mit ca. 40 mips per ISR: 200.000 Impulse * 40 mips
sind dann 8 Mhz für die ISR alleine um alle abzufangen.
Draco schrieb:> Naja, aber Interrupt gesteuert auf der SCL Line zu lauschen ist doch> effektiver als Polling in einer Main.
Stimme ich zu, aber er darf nur nicht START verpassen, von da ab kann
es clockgesteuerte Interrupts geben, da ist selbst bei 400KHz genug
Zeit zwischen den Flanken um alles, auch evtl. Fehler zu "analyzern".
Das eigentliche Problem liegt gerade in SCL - START wird mit SCL
high und fallender Flanke von SDA eingeleitet. Da kann es keinen
Interrupt auf SCL geben, oder man müsste in der ISR auf fallende
SDA Flanke warten - und das kann ewig dauern - da kann man genauso
gut in main() warten...
Marc V. schrieb:> Das eigentliche Problem liegt gerade in SCL - START wird mit SCL> high und fallender Flanke von SDA eingeleitet. Da kann es keinen> Interrupt auf SCL geben, oder man müsste in der ISR auf fallende> SDA Flanke warten - und das kann ewig dauern - da kann man genauso> gut in main() warten...
Nö, da gibt es kein Problem. Interrupts kann man im Betrieb ein und
ausschalten. Es spricht also nichts dagegen, zunächst per Interrupt auf
eine fallende Flanke an SDA zu warten und erst dann auf SCL zu wechseln.
Ich denke, grundlegend hat es der TO auch vor, denn er spricht von
InterruptS - Mehrzahl. Den Interrupt auf SDA würde ich halt nach
Erkennung der Start-Condition abdrehen. Wegen möglicher Glitches auf der
Leitung (z.B. bei Wechsel vom Master zu Slave beim ACK) bekommt man
sonst recht viele Interrupts und da kann man sich dann schon mal
verschlucken. Also: wenn man dem Bus nicht zwischen die Bits gucken
will, alles schön synchron mit dem Takt einlesen.
Stefan schrieb:> Nö, da gibt es kein Problem. Interrupts kann man im Betrieb ein und> ausschalten. Es spricht also nichts dagegen, zunächst per Interrupt auf> eine fallende Flanke an SDA zu warten und erst dann auf SCL zu wechseln.
Es spricht einiges dagegen.
Erstens:
SCL Hi und fallende Flanke an SDA muss nicht unbedingt START bedeuten,
es können auch Glitches sein.
Das kann aber mit Polling in main() um einiges einfacher festgestellt
werden - welche Vorteile hat die Lösung mit Interrupt auf SDA ?
Anstatt in loop in main() den Zustand von SDA und SCL gleichzeitig
abzufragen und entsprechend zu reagieren, wird bei deiner "Lösung"
folgendes gemacht:
a) in einem leeren loop in main() auf Interrupt gewartet, um dann
in der ISR den Zustand von SCL abzufragen ?
b) in einem loop in main() wird nur der Zustand von SCL abgefragt
und in dem Moment, wo es auf Low geht, werden die Interrupts auf
SDA gesperrt ?
Und wie geht es dann weiter ?
Das kann doch nicht dein Ernst sein.
Zweitens:
Man soll es so einfach wie nur möglich machen - was soll ständiges
Umschalten zwischen SDA und SCL bringen wenn man sowieso den einen
oder anderen Zustand manuell dazu abfragen muss ?
Drittens:
Wie willst du mit Interrupt Repeated Start erkennen ?
Viertens:
Wie willst du STOP erkennen ?
Irgendetwas posten nur um zu zeigen, dass man weiss wovon die Rede ist,
ist nicht unbedingt produktiv.
Marc V. schrieb:> Stimme ich zu, aber er darf nur nicht START verpassen, von da ab kann> es clockgesteuerte Interrupts geben,
clockgesteuerte Interrupts halte ich für gar keine gute Idee. Denn der
I2C-Master kann mit seiner Clock quasi machen was er will solange er
keine schnellere Clock verwendet als das langsamste Gerät auf dem Bus.
Interrupts auf SCL und SDA halte ich daher für gar keine so schlechte
Idee.
Schön wäre es, wenn man beim DMA der STM32 auch EXTIs oder ähnliches als
DMA-Request-Trigger verwenden könnte. Dann könnte man hier einfach bei
jeder Änderung von SCL das DMA den gesamten Port (u.a. dann SCL und SDA)
auslesen und in einen Ringpuffer schreiben lassen. Nur leider habe ich
noch keine Möglichkeit gefunden das bei den STM32 so zu machen. Soweit
ich weiß können das nur einige von den Kinetis-µCs.
Gerd E. schrieb:> clockgesteuerte Interrupts halte ich für gar keine gute Idee. Denn der> I2C-Master kann mit seiner Clock quasi machen was er will solange er> keine schnellere Clock verwendet als das langsamste Gerät auf dem Bus.
Mit clockgesteurtem Interrupt meine ich Interrupt auf SCL.
Vielleicht schlecht formuliert.
> Interrupts auf SCL und SDA halte ich daher für gar keine so schlechte> Idee.
Interrupt auf SDA ist auf jeden Fall eine schlechte Idee.
Hey Leute,
ich bedanke mich für die anregenden Kommentare und kann euch ein kleines
Update geben. Bis 100 Kbit/s kann ich nun interruptgesteuert (SDA sowie
SDL auf falling und rising edge) Nachrichten analysieren. Nun werde ich
jedoch das Triggern von Start und Stop über D FLipFlops hardwareseitig
regeln, sodass ich nur noch auf rising edge der SCL Leitung Triggern
muss oder auch gegebenenfalls in der main danach polle. Das sollte einen
guten performanceboost geben, sodass ich vielleicht auch höhere
Geschwindigkeiten schaffe.
David S. schrieb:> Nun werde ich> jedoch das Triggern von Start und Stop über D FLipFlops hardwareseitig> regeln, sodass ich nur noch auf rising edge der SCL Leitung Triggern> muss oder auch gegebenenfalls in der main danach polle.
Das ist doch völlig unnötig. Wieso nimmst du nicht die Compare Funktion
je eines Timers (einer für SCL und einer für SDA) bzw. lass den anderen
im Slave Modus laufen oder synchonisiere ihn ein. Wenn du's dir voll
geben möchtest, dann nimm die DMA(s) dazu und dein Prozessorlast der
Aquisition ist gleich Null. Nun kannst du die Daten in aller Ruhe im
Speicher abholen.