Hi, ich möchte mich mit I2C beschäftigen und frage mich, wie man's richtig macht? MCU ist Cortex-MO/LPC11xx und Cortex-M3/LPC13xx bzw. LPC17xx von Nxp. Die Frage kam beim Studium des UserManuals auf. Die I2C-Hardware basiert wohl darauf, dass der jeweilige Zustand (z.B. StartCondition gesendet, Arbitrierung verloren, etc.) über ein Statuswort rückgemeldet wird. Somit kann (soll) die ganze Sache eigentlich als StateMachine betrachtet werden. Meine Frage ist nun, wie man beispielsweise den I2C-Interrupt so schreibt, dass er universell verwendbar ist. Damit meine ich nicht, dass er gleich Multimasterbetrieb abdecken können muss, sondern dass man einen allgemeinen I2C-Treiber hat, über den alle angeschlossenen Devices (z.B. EEPROM, ADC, etc.) abgedeckt werden können. Wie geht man da am geschicktesten vor? Mir kam eine Lösung in den Sinn, die einen Buffer (plus Hilfsvariablen) verwendet. Hilfsvariablen wären ein Schreib- und ein Lesezähler. Will man Daten zum Device senden, füllt man den Buffer, setzt den Schreibzähler auf die entsprechende Anzahl Daten und schickt das raus. Dasselbe analog für's Lesen, wobei jeweils einer der beiden Zähler immer 0 ist. Will man Daten senden und direkt danach schreiben (Beispiel EEPROM: Adresspointer schreiben und dann Daten lesen) ohne den Bus aufzugeben (also mit RepeatedStart) setzt man den Lesezähler entsprechend. Die Interrupt-Routine erkennt dies und setzt anstatt einer StopCondition nach dem Schreiben eine (erneute) StartCondition ab. Was meint ihr? Zu blauäugig/einfach oder brauchbar? Oder hat noch jemand ne Idee wie man's machen kann (sollte)? Ralf
Ja, ich baute auf einem LPC2000 auch mal eine Interruptmaschine zum I2C. Damit das Ding dann auch voll im Hintergrund abspielt. Anfangs erschien mir das gar nicht so einfach, aber auf den Internetseiten von Philips, heute NXP, fand ich auch ausgezeichnete Papiere mit den States, und Flußdiagramme. Das half mir auf jeden Fall. Wenn man in der Interruptmaschine alle States berücksichtigt, ist das Ding dann natürlich auch universell einsetzbar. Man muß es aber einmal machen. Also: Such beim Hersteller Philips oder NXP mal nach den Papieren zu I2C. Philips hatte es wohl auch erfunden. Etwas nachdenken, mußt du dann schon noch. Das kann dir niemand abnehmen.
> Was meint ihr? Zu blauäugig/einfach oder brauchbar? > Oder hat noch jemand ne Idee wie man's machen kann (sollte)? Das kann man machen und habe ich auch schonmal so gemacht. Genauer gesagt habe ich eine Fifo mit structs implementiert wo ausserhalb des IRQs die Funktionen ihre Schreib/Lese-Daten, Adressen, usw. bereitstellen. Im IRQ laeuft dann eine Statemachine welche die Fifo abarbeitet. Grundsaetzlich funktioniert das gut. Vor allem ist es eine Freude sobald man auf Fehler stoesst weil man sich von der Statemachine genaue Fehlerflags zurueckgeben kann und man so weiss was wann wo und warum nicht funktioniert hat. Allerdings ist es nicht ganz so effizient und cool wie man sich das urspruenglich vorstellt. Das liegt daran das man bei vielen Zugriffen auf I2C-Bausteinen dann im Hauptprogramm wartet bis der Zugriff gelaufen ist weil weil man erst dann etwas anderes machen kann. Mit anderen Worten man hat bei I2C-Haeufig den Bedarf blocking zu arbeiten und dann lohnt der Aufwand nicht mehr so. Olaf
Man nehme einfach die fertigen Routinen aus der passenden NXP CMSIS: http://ics.nxp.com/support/documents/?type=software Zumistest in der Version für LPC17[56]x sind passende Interrupt Handler dabei.
@Wilhelm: Danke, dann werd ich die NxP-Seite mal genauer durchstöbern. Ich hatte dort nur nach der I2C-Spec gesucht. Mal sehen ob ich die von dir erwähnten Dokumente finde :) @Olaf: Für gewöhnlich schreibe ich meine Software so, dass niemals irgendwo auf etwas gewartet wird. Vielleicht bekomme ich das auch hier hin ^^ Das mit den Fehlerflags gefällt mir, ich will schauen ob ich das auch so hinbekomme. @Turbo J: CMSIS ist so ne Sache, weiss noch nicht was ich davon halten soll, weil ich mich etwas schwer tue, CMSIS richtig zu verwenden. Schätze das kommt mit der Erfahrung :) Aber reingucken werd ich, danke. Ralf
Ralf schrieb: > @Wilhelm: > Danke, dann werd ich die NxP-Seite mal genauer durchstöbern. Ich hatte > dort nur nach der I2C-Spec gesucht. Mal sehen ob ich die von dir > erwähnten Dokumente finde :) Die Dokumente waren damals auf der Homepage etwas versteckt, bekam sie teilweise von Kollegen. I2C-Specs. Wenn nicht NXP, vielleicht findet sich ja auf der Philips-HP noch was. Ach ja, ich erinnere mich jetzt: Das Hinterhältige an der Sache war, daß I2C-Beispiele (z.B. vollständige Flußdiagramme) teilweise in Datenblättern von Bausteinen mit I2C-Schnittstelle versteckt waren. Wenn alle Stricke reißen, frag mich hier noch mal. Ich könnte auf alten Datenträgern mal suchen, ob ich noch Information finde. Die Flußdiagramme mit allen States zum I2C-Bus fand ich für mich sehr wichtig, um einen klaren Überblick über die gesamte Funktionsweise zu bekommen. Keil hatte zu den LPC2000 ein I2C-Beispiel, in dem die Arbeit mit der Interrupt-Statemachine anhand von 3 oder 4 States im Minimalausbau gezeigt wurde. Das half mir. Den Interrupt erweitert man dann einfach um die benötigten States, ich glaube es sind 27 insgesamt. Multimaster brauchte ich nicht, das blieb bei mir erst mal draußen. Mit den LPC2000 habe ich lange nichts gemacht, auch nicht mehr auf die Keil-Homepage geschaut. Zu den LPC2000 hatte ich damals das Buch mit Beispielen von Trevor Martin, das war auch ganz nett.
Sorry für die späte Antwort. @Wilhelm: Ich hab auch noch was interessantes gefunden, für die Leute, die sich auch damit beschäftigen möchten: http://www.i2c-bus.org Momentan bin ich dran, den Ablauf wie er im LPC11xx UserManual dargestellt ist in Software umzusetzen. Vielleicht kann ich heut abend schon einen ersten Probelauf machen. Als Versuchskaninchen hab ich je ein 24LC02 und ein 24LC64 EEPROM an den Bus gepappt. Erster Stolperstein dürfte die Frage sein, wie man bei der Implementierung gemäß UserManual das Polling durchführt um zu erkennen, ob das EEPROM bereit für neue Kommandos ist, aber ich schätze dafür muss man dann den Treiber nach Bedarf erweitern. Ralf
Ralf schrieb: > Erster Stolperstein dürfte die Frage sein, wie man bei der > Implementierung gemäß UserManual das Polling durchführt um zu erkennen, > ob das EEPROM bereit für neue Kommandos ist, aber ich schätze dafür muss > man dann den Treiber nach Bedarf erweitern. So ein I2C-EEPROM eignet sich auch sehr gut für Tests. Verzeihung, es ist lange her, daß ich bei LPC2000 den I2C-Bus programmierte. Ich kann da nur aus lang zurück liegender Erinnerung sprechen. Aber das Acknowledge-Polling war wohl ein ganz normaler Lesezugriff vom Master auf den Slave, wie wenn man Daten liest. Was ich auf meinem Rechner noch fand: i2c_specs.pdf I2C_BUS_SPECIFICATION_2.pdf Hier sind Graphen der Abhängigkeiten der Buskapazität zu den Pullup-Widerständen drin. 8xC5x2_OV.pdf Hier sind die I2C-States vollständig beschrieben, und ein paar Diagramme zu den Betriebsmodes (Master Transmitter, Master Receiver, Slave Transmitter, Slave Receiver). Die sollten so auch bei Philips oder NXP auffindbar sein. Die Datei mit dem vollständigen Flußdiagramm zu allen I2C-States fand ich noch nicht. Das ist aber die, die eigentlich sehr wichtig ist. Es ist etwas mühsam, 10 alte CDs mit 5GB Daten noch mal zu durchstöbern.
Hi Wilhelm, mach dir keine großen Umstände, ich werd dank deiner Beschreibung die Dateien schon finden. Du hast recht, deswegen hab ich für den Anfang die EEPROMs gewählt. Der Stolperstein ist übrigens nicht wie erwartet das Polling, sondern meine Fehlinterpretation des LPC UserManuals. Ich hab brav das Softwarebeispiel umgesetzt ohne im ersten Moment zu kapieren, dass dieses nicht von einem Zustand zu allen möglichen anderen springt, sondern nur ein paar Fälle abdeckt. Das heisst für mich erstmal, der Stolperstein ist das Treiberdesign, damit ich soweit flexibel bin, dass diverse I2C-Peripherie angebunden werden, ohne nochmal im eigentlichen I2C-Treiber rumwerkeln zu müssen :) Aber das guck ich mir morgen an, gute Nacht. Ralf
So, hab mich nun noch etwas tiefer durchgewühlt durch die Materie, vor allem auch durch die Tabellen aus dem LPC11xx UserManual, in denen die einzelnen Zustände und die jeweils möglichen Folgezustände beschrieben sind. Irgendwie will mir da was noch nicht ganz in den Kopf... Wenn ich wie oben eigentlich angedacht einen Buffer verwende, kann ich ja beispielsweise anhand eines Zählers bestimmen, wann der Master beim Empfangen ein NACK generieren soll (üblicherweise beim letzten Datenbyte). Beim Senden generiert der Slave das Ack-Flag. So, nehmen wir jetzt an, ich habe am Bus ein Device, bei dem der Transfer abgebrochen und neu gestartet werden soll, wenn das Device unerwartet ein NACK generiert. Zusätzlich hab ich ein Device, bei dem ich den Transfer abbrechen, aber nicht neu starten will. Soooo, wie macht denn das nun? Das einzige was mir so spontan eingefallen ist, wäre dass nicht die Interrupt-Routine (alleine) entscheidet was passiert, sondern auch der Buffer: Jedes Datenbyte (und das Adressbyte) bekommen zusätzlich noch zwei Statusbytes die entscheiden bei welchem I2C-Status es im ACK/NACK-Fall weitergeht. Zu (kompliziert) um die Ecke gedacht oder sinnvoll? Ralf
>Beim Senden generiert der Slave das Ack-Flag. So, nehmen wir jetzt an, >ich habe am Bus ein Device, bei dem der Transfer abgebrochen und neu >gestartet werden soll, wenn das Device unerwartet ein NACK generiert. >Zusätzlich hab ich ein Device, bei dem ich den Transfer abbrechen, aber >nicht neu starten will. Den Fall gibt es nicht bei I2C. Da geht alles der Reihe nach.
@Holger:
> Den Fall gibt es nicht bei I2C. Da geht alles der Reihe nach.
Du meinst es gibt das unerwartete NACK nicht?
Ralf
>> Den Fall gibt es nicht bei I2C. Da geht alles der Reihe nach. >Du meinst es gibt das unerwartete NACK nicht? Doch, aber es gibt kein zweites Device das auf einen Transfer wartet. Das geht bei I2C nicht.
> Doch, aber es gibt kein zweites Device das auf einen > Transfer wartet. Das geht bei I2C nicht. So meinte ich das auch nicht. Ich meinte, dass bei den beiden Devices unterschiedlich reagiert werden soll, wenn ein NACK auftritt. Beim einen Device möchte man den Transfer wiederholen, beim anderen nicht. Ralf
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.