Forum: Mikrocontroller und Digitale Elektronik Zusammenhang bei mehreren auszulesenden Bytes sicherstellen


von Matthias R. (losth1ker)


Lesenswert?

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.

von Läubi .. (laeubi) Benutzerseite


Lesenswert?

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.

von Peter D. (peda)


Lesenswert?

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.

von c-hater (Gast)


Lesenswert?

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.

von Schlumpf (Gast)


Lesenswert?

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?

von Karl H. (kbuchegg)


Lesenswert?

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.

von Peter D. (peda)


Lesenswert?

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."

von Karl H. (kbuchegg)


Lesenswert?

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.

von c-hater (Gast)


Lesenswert?

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.

von Peter D. (peda)


Lesenswert?

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.

von c-hater (Gast)


Lesenswert?

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...

von Peter D. (peda)


Lesenswert?

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.

von W.S. (Gast)


Lesenswert?

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.

von c-hater (Gast)


Lesenswert?

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...

von Peter D. (peda)


Lesenswert?

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.

von Peter D. (peda)


Lesenswert?

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
Noch kein Account? Hier anmelden.