PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : I2C zwischen Controllern



Sauerbruch
01.07.2015, 15:01
Dear all,

ich arbeite mich gerade in die Materie ein, mehrere Controller per I2C kommunizieren zu lassen. Die Rollenverteilung ist einfach: Ein Master der nur sendet und 2-3 Slaves, die nur empfangen.

Der Befehl I2cwbyte funktioniert schon mal super, im Oszillogramm sehe ich, dass der Master perfekte Clock- und Data-Signale einschließlich Taktzyklus für das ACK-Bit generiert.

Auf der Slave-Seite muss dann ja der Befehl I2crbyte dazugehören, allerdings frage ich mich gerade woher der Slave weiß, wann er diesen Befehl ausführen soll. Schließlich kann der Code im Slave ja nicht wissen, wann der Master seine Daten schickt... Und was ich ebenfalls nicht verstehe: Was ist, wenn das ACK-Bit des Slaves ausbleibt, weil er z.B. gerade anderweitig beschäftigt ist? Ich habe verstanden dass dieses ACK-Bit dem Master signalisiert, dass der Slave korrekt durch seine Adresse angesprochen wurde - aber was wenn nicht? Dann würde es ja keinen Sinn machen, gleich mit I2cwbyte weitere Daten auf den Bus zu schicken...

Viellecht kann mir ja jemand mal vom Schlauch runterhelfen, auf dem ich gerade zu stehen scheine...

RoboHolIC
01.07.2015, 17:22
... allerdings frage ich mich gerade woher der Slave weiß, wann er diesen Befehl ausführen soll.
Immer dann, wenn er adressiert wurde. Das entscheidet entweder die Hardware-Mimik des Slave-Controllers, sofern man ihn als (ideal: interruptgetriebenen) Slave konfiguriert hat - oder die Firmware.

... Schließlich kann der Code im Slave ja nicht wissen, wann der Master seine Daten schickt...
Naja, Interrupt oder eben Polling. Mehr Auswahl gibt es meines Wissens nicht.

... Und was ich ebenfalls nicht verstehe: Was ist, wenn das ACK-Bit des Slaves ausbleibt, weil er z.B. gerade anderweitig beschäftigt ist? ...
Dann bleibt die Kommunikation stecken - ohne wenn und aber - so ist I2C spezifiziert. Abhilfe kann ein Timeout-Zähler und Warteschleifenabbruch schaffen.

Klebwax
01.07.2015, 18:05
Was ist, wenn das ACK-Bit des Slaves ausbleibt, weil er z.B. gerade anderweitig beschäftigt ist?

Ein Slave muß ständig auf dem Bus mitlauschen. Wenn da eine Startcondition zu sehen ist, weiß er daß die nächsten 7 Bit die Slaveadresse sind. Er hat dann 1 Bit Zeit um festzustellen, ob er angesprochen wird. Daß RW braucht er sich nur für später zu merken. Beim nächsten Takt vom Master zieht er SDA auf low und der Master liest das als ACK. Tut der Slave. das nicht, aus welchem Grund auch immer, ist es ein NAK und der Master muß die Übertragung abbrechen. Wenn der Slave einen kleinen Aufschub braucht, kann er die SCL-Leitung auf low halten, bis er sich entschieden hat, was er antworten will.

aber was wenn nicht? Dann würde es ja keinen Sinn machen, gleich mit I2cwbyte weitere Daten auf den Bus zu schicken...
Das ist richtig, es interessiert aber eigentlich Niemand. Bei fast jedem Codestück, das ich hier im Forum gesehen habe, wird ACK/NAK niemals ausgewertet sondern munter an einen nicht antwortenden Slave weitergesendet.

MfG Klebwax

Sauerbruch
01.07.2015, 20:33
Ja, soweit hatte ich das auch verstanden, aber trotzdem verwirrt mich noch etwas: Das "lauschen" an sich (und das anschließende Vergleichen, ob die gerade gehörte 7-Bit-Adresse die eigene war) benötigt ja keinen eigenen, konkreten Befehl, oder? Ich stell´ mir das so vor wie das Reintrudeln von Bytes über die USART-Schnittstelle, was ja auch jederzeit unabhängig vom gerade laufenden Programm geschehen kann. Aber I2crbyte ist ja nun mal ein konkreter Befehl, der ja sofort ablaufen müsste, wenn der Controller seine eigene Slave-Adresse und das "W"-Bit vom master erkannt hat, oder?

RoboHolIc deutete Interrupts an - aber ich werde diesbezüglich aus dem Daenblatt (ATMega8 ) irgendwie nicht richtig schlau: Dort steht als Interrupt-Vektor Nr. 18 zwar ein TWI-Interrupt, aber was heißt denn bitteschön die Interrupt-Definition "Two-wire serial interface"? Was muss denn genau in diesem Interface passieren, damit der Interrupt ausgelöst wird?

RoboHolIC
01.07.2015, 23:50
Die Analogie zum USART ist treffend bzgl. des asynchronen Eintrudelns von Eingangsdaten.

Das "lauschen" erledigt das I2C / TWI-Modul und aktiviert ggf. Statusflags, auf die man einen Interrupt ansetzen oder eben aktiv pollen muss. I2crbyte ist dann der konkrete Befehl, der das Auslesen des Empfangsbuffers und evtl das ACK-Handling plattformunabhängig implementiert. (ich schreib das mal ganz mutig in Analogie zu den PIC-Controllern).

Bei keinem der (wenigen) I2C-Bausteine, die ich bisher verwendet habe, gibt es Clockstretching. Alle liefern auf Anfrage Daten und kennen keine unvorhersehbaren Verzögerungen bei der Buskommunikation, weil sie die I2C-Engine in Hardware haben.

Allerdings sollte man das Auftreten von Busblockierungen einkalkulieren, die durch EMI, unerwartete Resets und Kontaktprobleme entstehen können.

Klebwax
02.07.2015, 00:32
Bei keinem der (wenigen) I2C-Bausteine, die ich bisher verwendet habe, gibt es Clockstretching. Alle liefern auf Anfrage Daten und kennen keine unvorhersehbaren Verzögerungen bei der Buskommunikation, weil sie die I2C-Engine in Hardware haben.

Das sagst du so locker.

Clockstretching tritt sogar ohne Slave auf. Nimm mal einen "sauber" implementierten I2C Master und betreibe ihn mit 400kHz, bei höheren Geschwindigkeiten ist der Effekt leichter zu erkennen. Ein Slave ist nicht angeschlossen, die Pullups sind so 10kOhm. Die 400kHz sind leicht nachzumessen. Nun schalte mal 400pF zwischen SCL und GND, das ist die maximale kapazitive Buslast nach der Spec. Der Bus wird jetzt merkbar langsamer (solange der Master sauber implementiert ist). Der Grund ist einfach: der Master setzt SCL für die halbe Bitzeit passend zu 400kHz auf low. Dann läßt er das Signal los und wartet, daß es high wird. Durch die hohe Kapazität des Busses dauert es aber eine Zeit, bis der High-Pegel erreicht wird. Erst dann startet er den Timer, wieder eine halbe Bitzeit, für die High-Phase von SCL. Die messbare SCL-Frequenz wird damit langsamer, die Clock "gestreckt". Es ist egal, wer oder warum SCL länger low ist, als der Master vorgibt. Der häufigste Fall ist natürlich, daß sich der Slave beim ACK erwas Zeit nimmt indem er SCL low hält.

Bei einer Prozessor-Prozessor Verbindung ist Clockstretching eigentlich unvermeidlich und sehr hilfreich. Man kann im Slave wesentlich lockerer mit Interrupten und Interrupt-Sperren umgehen ohne die Integrität der Übertragung zu gefährden.

MfG Klebwax

RoboHolIC
02.07.2015, 11:55
Nun ja. Wenn man das elektrische Tiefpassverhalten der Busverdrahtung (aus Sicht des Masters verständlich) auch dem Thema Clockstretching zuordnet, dann hast du natürlich recht.

Andererseits: 400kHz und 400pF sind zwar innerhalb der Spec, nicht aber in Verbindung mit den 10k Pullups, weil man damit eine RC-Zeitkonstante von 4µs, mithin 250kHz vorgibt, aber den Bus mit 400kHz betreibt. Die Busverlangsamung demonstriert dann, dass der Master das Clockstretching toleriert.

Sauerbruch
02.07.2015, 14:36
Also im Moment wäre ich ja schon froh, wenn der Slave einfach nur auf den Master reagieren würde... habe hierzu folgenden Code für den Master geschrieben:



$regfile = m8def.dat
$Crystal = 1000000

Config sda = PORTD.7
Config scl = PORTB.0

Do

I2cstart
I2cwbyte &b00000010
I2cstop

waitms 200

Loop


scl und sda sind mit 4k7 mit +5V verbunden, die Signale sehen gut aus.

Beim Slave wollte ich mit einer toggelnden LED einfach nur mal sehen, ob er wenigstens schon mal in die TWI-ISR springt, wenn der Master die Slave-Adresse sendet:



$regfile = m8def.dat
$crystal = 1000000

Config sda = PORTD.7
Config scl = PORTB.0

DDRD.0=1

TWCR = &b00000101
TWAR = &b00000010

On TWI Empfang
Enable TWI
Enable Interrupts

Do
Loop

Empfang:
Toggle PORTD.0
Return


Aber leider passiert nichts. Ich habe mir vorsichtshalber gerade die I2C-lib gekauft und werde sie heute Abend mal einbinden...

RoboHolIC
02.07.2015, 20:38
OK, mein Beitrag über dedizierte I2C-Slave-ICs war schon am Thema vorbei.
Aber jetzt klinke ich mich besser aus, weil ich aus dem Code nichtmal rauslesen kann, ob es sich um TWI-Hardware oder eine Emulation in den Slaves handelt.

Sauerbruch
02.07.2015, 20:46
Aber jetzt klinke ich mich besser aus, weil ich aus dem Code nichtmal rauslesen kann, ob es sich um TWI-Hardware oder eine Emulation in den Slaves handelt.

Ich würd´s Dir gerne verraten - wenn ich es selber wüsste :-)

Mal sehen ob mich die I2c-Lib weiterbringt, ich werde jetzt noch ein wenig weiterpuzzeln!

021aet04
04.07.2015, 22:18
Ich kenne mich mit Bascom nicht aus, aber du verwendest TWAR und TWCR. Somit verwendest du Hardware I2C (TWI). TWAR ist das Adressregister (Two Wire Adress Register) und TWCR ist das Control Register (Two Wire Control Register). Wie du den Atmega als I2C Slave verwendest steht ab S177 im Datenblatt. Dort steht z.B. das das TWEA und TWEN Bit in TWCR "1" sein müssen. Bei dir ist das TWEA Bit aber nicht gesetzt (ist das 6te Bit). TWSTA und TWSTO dürfen nicht gesetzt werden.

MfG Hannes

Sauerbruch
09.07.2015, 22:05
So, jetzt habe ich mir das LIB-Paket von MCS Electronics gekauft und mich entschieden, für erste Versuche zwei Mega8 und Hardware-I2C zu verwenden, um es so unkompliziert wie möglich zu machen.
Trotzdem wirft das Ganze bei mir immer wieder neue Fragen auf, auf die vielleicht hier jemand die Antwort weiß:

1. Wenn I2C und TWI tatsächlich das gleiche sind, wie in der Bascom-Hilfe ja imer wieder mantrahaft wiederholt wird, weshalb gibt es dann für beides Befehle zur Konfiguration eines Slaves (CONFIG I2CSLAVE und CONFIG TWISLAVE)?

2. ist mir bei ersten Versuchen aufgefallen, dass der Befehl CONFIG I2CSLAVE lediglich zwei Labels benötigt (I2c_master_needs_data und I2c_master_has_data), während die Verwendung von CONFIG TWISLAVE gleich ein halbes Dutzend Labels verlangt (twi_addressed_goread, twi_gotdata, twi_stop_rstart_received, twi_addressed_gowrite, twi_master_needs_byte und twi_master_need_nomore_byte).

Wenn der Slave eine variable Anzahl an bytes empfangen soll wäre es doch sinnvoll, nach der korrekten Read-Addressierung eine Zählvariable auf 1 zu setzen, sie nach jedem empfangenen Byte um 1 zu inkrementieren, und damit ein Array zu füllen. Wie kann man so etwas denn lösen, wenn man den CONFIG I2CSLAVE-Befehl nutzt, und dementsprechend nur die Labels I2c_master_has_data und I2c_master_needs_data hat?

3. Mit dem Befehl CONFIG TWISLAVE kann ich bisher leider gar nicht rumexperimentieren, weil beim Kompilieren stets die Fehlermeldung "Illegal character [expected(, got "[TWI_CBTR]]" erscheint. Weiß jemand damit etwas anzufangen? (Habe die Bascom-Version 2.0.7.3)

RoboHolIC
11.07.2015, 00:04
Ja, so kenne ich es auch: TWI ist I2C; und das hat angeblich mit der Vermeidung von Lizenzgebühren zu tun.

Hast du mit der LIB nicht auch den Quellcode verfügbar? Besser noch: Dokumentation und Beispielprogramme ???

CONFIG TWISLAVE scheint die I2C-Spezifikation abzubilden (START, REPEATED START, ACK, NACK etc.).
CONFIG I2CSLAVE könnte eine höhere Abstraktionsebene sein, wo Daten per programmtechnischem Handshake ausgetauscht werden. (Es gibt da mit Sicherheit auch noch ein/zwei Datenregister, vllt. sogar die regulären physischen Register / deren Namen aus dem Controller-Manual !?)

Feuerring
04.07.2016, 03:02
Hallo,

auch ich möchte gerne mehrere Arduino_Nano (ATmega328P) über I2C verbinden ... 1 x Master 2-3 x Slave

möchte mit Bascom arbeiten ... als Master ja kein Problem aber als Slave ?

@Sauerbruch
bist Du zu einer Lösung gekommen ?

Sauerbruch
04.07.2016, 09:56
Hallo Feuerring,

ja, nach längerem herumpuzzeln mit dem LIB-Paket, das ich für ein paar Euros gekauft hatte, funktioniert es einwandfrei!

Feuerring
04.07.2016, 14:09
Hallo Sauerbruch,

kannst Du mir auch Details nennen, wo es gehangen hat und wie Du die LIB eingebunden und verwendest hast ...

Programm-Teile die die LIB verwenden wären glaube ganz hilfreich ...