Hallo, ich möchte Messdaten einiger Slaves über i2c zu einem Master übertragen. Die Messwerte der Slaves sind 12 bit lang, ich kann allerdings nur jeweils 8bit übertragen. Die Messung erfolgt zyklisch in jedem Durchlauf der Endlosschleife. Wird der entsprechende Slave angesprochen, soll der Master via interrupt den buffer auslesen. Nun kann es ja passieren, dass der interrupt kommt, wenn der Slave gerade nur die ersten vier bit in den buffer geschrieben hat, und die anderen acht noch nicht. Demnach würde der Master einen falschen Wert auslesen. Wie kann ich dieses grundsätzliche Problem umgehen? Wäre schön, wenn mit jemand einen Tipp geben kann:) Bei den Slaves handelt es sich übrigens um Attiny24.
Matthias R. schrieb: > Nun kann es ja passieren, dass der interrupt kommt, wenn der Slave > gerade nur die ersten vier bit in den buffer geschrieben hat, und die > anderen acht noch nicht. Demnach würde der Master einen falschen Wert > auslesen. Dann solltest du das abstellen und den "Interrupt" nur dann aktivieren/Nutzen wenn ein vollständiges Paket empfangen wurde.
Matthias R. schrieb: > Nun kann es ja passieren, dass der interrupt kommt, wenn der Slave > gerade nur die ersten vier bit in den buffer geschrieben hat Den Master mußt Du mir erstmal zeigen, der sowas verrücktes kann. Interrupts gibt es jeweils nur nach 9 Bits, d.h. nach jedem ACK oder NACK. 12 Bit sind auch kein Problem, muß der Master eben 2 Byte lesen.
Matthias R. schrieb: > Wie kann ich dieses grundsätzliche Problem umgehen? Es gibt zwei Möglichkeiten: 1) Der Slave "signalisiert" dem Master in irgendeiner Form, daß er aktuell nicht bereit ist, konsistente Werte zu liefern. Der Master muß dafür natürlich darauf vorbereitet sein, eine entsprechende Signalsierung sinnvoll zu behandeln. 2) Der Slave sorgt dafür, daß er immer konsistente Werte liefern kann. Double buffering und "interruptsichere" Umschaltung der beiden Buffer.
Matthias R. schrieb: > Die Messung erfolgt zyklisch in jedem Durchlauf > der Endlosschleife. In der Endlosschleife des Slaves? Matthias R. schrieb: > Wird der entsprechende Slave angesprochen, soll der > Master via interrupt den buffer auslesen. Wer macht hier wem nen Interrupt? Der Master dem Slave?
Ich denke, Matthias hat sich unglücklich ausgedrückt. Er hat einen Tiny, der die Messungen macht. Der Master kann die Werte vom Tiny per TWI auslesen. Jede TWI Kommunikation wird auf dem Tiny per Interrupt abgewickelt. Dazu hält der Tiny das letzte Messergebnis in globalen Variablen vor, die er dann auf Anfrage rausrückt. D.h. es kann passieren, dass der Master seine TWI Abfrage just in dem Moment stellt, in dem die Messchleife die globalen Variablen zum Teil schon upgedated hat und einen Teil noch nicht. Was in weiterer Folge dazu führen kann, dass der Master inkonsistente Ergebnisse kriegt. Die Lösung: Der eigentliche Update der globalen Variablen erfolgt unter Interruptsperre. Selbstverständlich versucht man diese so kurz wie möglich zu halten, d.h. man bereitet sich das nächste veröffentlichungswürdige Ergebnis erst mal im Speicher vor und aktieviert es dann möglichst auf einen Schlag unter Interruptsperre. Die paar Takte, die so etwas üblicherweise dauert, sind kein Problem. Wenn eine Kommunikation eine derartige fallweise Verzögerung nicht verkraftet, dann kann man sie kaum als robust bezeichnen.
Karl Heinz Buchegger schrieb: > D.h. es kann passieren, dass der Master seine TWI Abfrage just in dem > Moment stellt, in dem die Messchleife die globalen Variablen zum Teil > schon upgedated hat und einen Teil noch nicht. Was in weiterer Folge > dazu führen kann, dass der Master inkonsistente Ergebnisse kriegt. Das geht beim AVR nicht oder man muß sich schon extra dumm anstellen: "When ADCL is read, the ADC Data Register is not updated until ADCH is read." "ADCL must be read first, then ADCH."
Peter Dannegger schrieb: > Karl Heinz Buchegger schrieb: >> D.h. es kann passieren, dass der Master seine TWI Abfrage just in dem >> Moment stellt, in dem die Messchleife die globalen Variablen zum Teil >> schon upgedated hat und einen Teil noch nicht. Was in weiterer Folge >> dazu führen kann, dass der Master inkonsistente Ergebnisse kriegt. > > Das geht beim AVR nicht oder man muß sich schon extra dumm anstellen: > > "When ADCL is read, the ADC Data Register is not updated until ADCH is > read." > "ADCL must be read first, then ADCH." Ich meinte das eher so
1 | volatile uint8_t Spannung_Low; |
2 | volatile uint8_t Spannung_High; |
3 | |
4 | ....
|
5 | |
6 | Spannung_Low = ADCL; |
7 | Spannung_High = ADCH; |
8 | ...
|
kommt die TWI-Interrupt Anfrage vom Master da dazwischen, dann kriegt der Master inkonsistente Ergebnisse. Ein ....
1 | ...
|
2 | cli(); |
3 | Spannung_Low = ADCL; |
4 | Spannung_High = ADCH; |
5 | sei(); |
6 | ...
|
... behebt das und die paar Takte unter Interruptsperre sollten doch das TWI nicht weiter stören. Aber vielleicht hat Matthias ja auch ganz was anderes gemeint.
Karl Heinz Buchegger schrieb: > Ein .... >
1 | > ... |
2 | > cli(); |
3 | > Spannung_Low = ADCL; |
4 | > Spannung_High = ADCH; |
5 | > sei(); |
6 | > ... |
7 | >
|
> > ... behebt das Oder man macht das Update einfach in der ADC-ISR, in der konkurriende Interrupts sowieso schon gesperrt sind. > und die paar Takte unter Interruptsperre sollten doch das > TWI nicht weiter stören. Nunja, wenn das TWI "auf Kante" genäht ist, können auch schon wenige Takte stören. Dann muß man halt mit der Bitrate runtergehen. Ist nicht gut für die Busstabilität, wenn Busteilnehmer so nah am Limit laufen.
c-hater schrieb: > Nunja, wenn das TWI "auf Kante" genäht ist Slave und Master können nicht auf Kante sein, wenn sie ein HW-I2C haben. Der Slave hält sein SCL auf low, bis sein Interrupt beendet ist und der Master wartet geduldig, bis SCL high ist, ehe er einen Interrupt erhält (nennt sich SCL-Stretching). Die können sich also Jahre Zeit lassen und der Transfer ist trotzdem ohne Datenverlust.
Peter Dannegger schrieb: > Der Slave hält sein SCL auf low, bis sein Interrupt beendet ist und der > Master wartet geduldig Das wäre das klassische Beispiel, wie man Busdesign NICHT machen sollte. Ein abgekackter Client legt den ganzen Bus lahm...
c-hater schrieb: > Das wäre das klassische Beispiel, wie man Busdesign NICHT machen sollte. Das mußt Du Philips/NXP sagen, die haben den I2C so spezifiziert. Und die werden sich schon was dabei gedacht haben.
Matthias R. schrieb: > Wie kann ich dieses grundsätzliche Problem umgehen? Ist dir die Bedeutung von ACK bzw. NAK nicht bekannt? Natürlich MUSS der Slave dem Master in irgendeiner Form signalisieren, ob er denn zur Herausgabe eines neuen Datensatzes bereit ist oder nicht. Man kann sowas per auszulesendem Statusbyte oder Statusbits machen oder eben ruppiger, indem der Slave beim Versuch, ihn zu adressieren, kein ACK gibt. Fertig. Nochwas: Bei solchen Anwendungen sollte man sich sowieso irgendein sinnvolles Protokoll ausdenken und nicht mit "Ich will jetzt 12 Bit rüberschaufeln!" draudlostrampeln. W.S.
Peter Dannegger schrieb: > Das mußt Du Philips/NXP sagen, die haben den I2C so spezifiziert. Nein, das haben sie so nicht spezifiziert. Vielmehr sieht der Standard zwei Varianten vor. Entweder eben dieses unselige "clock hold" oder alternativ die masterseitige Reduktion des Bustaktes. Nachzulesen z.B. in AN10216 von NXP, Seite 16. Das eine ist die billige Lösung, das andere die Sinnvolle... Im gleichen Dokument wird übrigens noch eine dritte Alternative vorgeschlagen, Bussegmentierung für Geräte mit stark unterschiedlicher Geschwindigkeit. Naja, nicht ganz der Sinn eines Busses. Es zeigt aber überdeutlich, daß dieser Bus nicht ganz so gut durchdacht war, wie er hätte sein sollen...
c-hater schrieb: > Vielmehr sieht der Standard zwei Varianten vor. Entweder eben dieses > unselige "clock hold" oder alternativ die masterseitige Reduktion des > Bustaktes. Ein langsamer Takt macht nur die Übertragung insgesamt langsamer, er gibt aber dem Slave kaum mehr Zeit, in den Interrupt zu springen und die Behandlung zu machen. Das Stretching wird ja nur alle 9 Takte benötigt. Es sei denn der Slave hat ein Multibyte-I2C mit DMA, nur dann käme er ohne Stretching aus. Oder eben die Slaves ohne MC (EEPROM, ADC, PIO), da ist SCL nur ein Eingang.
c-hater schrieb: > Es zeigt aber überdeutlich, daß > dieser Bus nicht ganz so gut durchdacht war, wie er hätte sein sollen... Ich finde im Gegenteil dieses Stretching äußerst intelligent und sehr sinnvoll. Es ist quasi ein Handshake, was die Übertragung absichert. Ein I2C-Transfer kann also nie Daten verlieren, der langsamste Teilnehmer bestimmt das Tempo. Im Vergleich dazu das Krüppel-SPI der AVRs ohne Sendepuffer taugt kaum als Slave. Der Master muß nach jedem Byte zusätzlich lange Gedenkpausen einlegen und hat trotzdem nicht die Gewähr, daß der Slave rechtzeitig das nächste Byte in das Senderegister schreiben konnte, weil er gerade einen anderen Interrupt noch beenden mußte. Ich hab mir daher erst gar nicht die Mühe gemacht, SPI zwischen 2 AVRs zu versuchen. Dafür sind I2C oder CAN einfach besser geeignet. Daß ein Bus tot ist, wenn ein Teilnehmer abstürzt, ist keine Besonderheit des I2C, sondern trifft auf jeden Bus zu. Z.B. RS-485 ist auch tot, wenn ein Slave seinen Sendetreiber nicht wieder abschaltet.
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.