Forum: Mikrocontroller und Digitale Elektronik [AVR] Datenkommunikation - quasi Daisy-Chain mit Token


von Florian (Gast)


Lesenswert?

Hallo allerseits,

ich arbeite gerade an einem Projekt, bei dem mehrere kleine, identische 
Platinen mit jeweils einem AVR ATmega8 miteinander kommunizieren, also 
Daten durchreichen können sollen.
Die maximal 15 Platinen befinden sich dabei in beliebiger, änderbarer 
Reihenfolge in jeweils maximal 30 cm Abstand zueinander, verbunden durch 
ein Kabel (+12V, GND, CLK und DATA).
Die zu übertragenden Daten haben immer eine Größe bzw. Länge von 2 Byte 
(1 Byte Befehle + 1 Byte Daten) und es ist keine variable, erweiterbare 
Länge notwendig.
Es ist wichtig, dass die Platinen ihren örtlich nächsten Partner, also 
die beiden direkt per Kabel verbundenen Nachbarn, ansprechen können, 
ohne eine ID zu kennen.
Deshalb entschied ich mich gegen einen normalen (Feld-)Bus wie I2C.
Außerdem sollte nur immer eine Platine das Recht haben, Daten zu 
verteilen - Token-Weitergabe.

Ich überlegte mir nun eine Art Daisy-Chain, allerdings ohne separaten 
Rückkanal.
Pro Platine benötige ich somit zwei serielle, bidirektionale 
Schnittstellen, eine für den linken und eine für den rechten Nachbarn.
Leider benötige ich den USART des ATmega8 bereits für andere Zwecke, 
sodass ich wohl oder übel selber zwei serielle Interfaces programmieren 
muss.

In der Hardware habe ich für die serielle Kommunikation nun zwei externe 
Interrupts reserviert, sowie zwei weitere Pins:
INT0 - Clock-Leitung A
PD6 - Daten-Leitung A
INT1 - Clock-Leitung B
PD7 - Daten-Leitung B

Alle vier Pins sind über 1 kOhm mit der Außenwelt verbunden, sodass es 
bei einer P2P-Verbindung zweier Platinen A und B so aussieht:
PinA - 1 kOhm - Kabelleitung - 1 kOhm - PinB

Da der ATmega8 ja interne 10 kOhm Pullups besitzt, dachte ich mir, dass 
ich im Ruhezustand die Pins den Pegel via Pullup auf 5V hochziehen lasse 
(logisch 0), wie das auch bei manchen Bussen der Fall ist.
Möchte nun eine Platine etwas senden, so zieht sie den Pegel auf der 
Clock-Leitung auf nahezu GND.
Das erkennt die benachbarte Platine via Interrupt.
Daraufhin sendet die Platine einen ACK auf der Daten-Leitung (GND - 
logisch 1).
Nun sendet die erste Platine ein Clock-Signal und gleichzeitig die 2 
Byte Daten.
Das bestätigt dann die zweite Platine wieder mit einem ACK, womit das 
Senden dann abgeschlossen ist.

Meine ersten Versuche waren insoweit bereits erfolgreich, dass die 
Platinen aufeinander reagiert haben.
Leider wurden die Daten noch nicht fehlerfrei übertragen.
Vielleicht sollte ich noch ein Prüfbit einsetzen o.ä..
Außerdem habe ich bisher die Eingänge gepollt - wenn es nun Fehler im 
Ablauf gab, hing sich das Ganze auf ... :D

Bevor ich mir nun aber noch mehr Arbeit mache, habe ich nun beschlossen 
zu fragen, ob es für solche Einsatzzwecke nicht bereits eine Lösung 
gibt!?
Die ganze Logik drumherum kann ich selbst schreiben, ich benötige nur 
eine Kommunikation via zwei Pins, wobei einer interruptfähig sein kann.

Vielen Dank für eure Hilfe und Tipps!
Florian

PS: Ich weiß, der Text ist ziemlich komplex, falls ihr offene Fragen 
habt, liefere ich gerne noch ausführlichere Erklärungen!

von Florian (Gast)


Lesenswert?

Hmm schade, hat niemand eine Idee oder einen Tipp für eine einfache 
softwareimplementierte serielle Schnittstelle über einen normalen und 
einen Interrupt-Pin?

Liebe Grüße
Florian

von erhardd (Gast)


Lesenswert?

@Florian (Gast)
...also für mich sieht das Beschriebene sehr nach einem ( nein, 2 pro
Platine ) Software-SPI ohne CS-Steuerung aus.
Wobei alle "Platinen" als -SLAVE- abwarten, bis einer den -MASTER_ 
macht,
um Daten in eine (oder auch 2 ) Richtungen zu senden;
Dein dem TWI-Protokol nachempfundene ACK-Auswertung wird Dich kaum vor 
Konflikten schützen, sobald mehr als 1 Master aktiv wird;
(die zwei 1k Widerstände schützen vor Kurzschluss, -oder weshalb);
Und, -legst Du die ser.-ausgeschifteten Daten( per Clock vom Master )
als 16 Bit Variable ab ?
Oder wie erkennt die "Platine", daß das Daten für sie sind?
Wenn nicht für sie, -dann weiterleiten?
Oder auf jeden Fall weiterleiten?
Aber wenn die "benachbarte Platine" grade selbst Master ist, wohin dann 
mit den Daten?
Verwerfen oder Zwischenspeichern?
Ist eine Kette aus Schiftregistern nicht sinnvoller? Dann bestimmt die 
Anzahl der Takte den Zielpunkt...
Übrigens nimm PC-Interupts, keine der ext.Int.  !

von Florian (Gast)


Lesenswert?

Hallo erhardd,
Danke für Deine Antwort! :)

> ...also für mich sieht das Beschriebene sehr nach einem ( nein, 2 pro
> Platine ) Software-SPI ohne CS-Steuerung aus.
Stimmt, die Ähnlichkeit ist mir noch nicht aufgefallen :D
ChipSelect ist ja unnötig, da ja nur ein Slave adressiert wird.

> Wobei alle "Platinen" als -SLAVE- abwarten, bis einer den -MASTER_
> macht, um Daten in eine (oder auch 2 ) Richtungen zu senden;
Das hätte ich vielleicht besser betonen sollen, es ist nur Halbduplex 
notwendig!

> Dein dem TWI-Protokol nachempfundene ACK-Auswertung wird Dich kaum vor
> Konflikten schützen, sobald mehr als 1 Master aktiv wird;
Es ist immer nur genau ein Master aktiv, alle anderen lauschen bzw. 
erfüllen ihre normalen Tätigkeiten.
Die ACKs sind in meiner Idee nur dafür da, zu bestätigen, dass die Daten 
korrekt angekommen sind.
Ich dachte mir, dass zu Anfang über ein externes Signal ein Master 
definiert wird, dieser dann den Token hat und die nächste Platine 
ansprechen darf. Diese bekommt dann den Token und darf wieder den 
nächsten ansprechen. Am Ende der Kette antwortet der Platine niemand und 
sie schickt wieder zurück. Somit wandert der Token immer hin und her in 
der Kette von Platinen, wie ein Lauflicht (Knightrider mäßig ;) ).

> (die zwei 1k Widerstände schützen vor Kurzschluss, -oder weshalb);
Ja genau, gegen Kurzschlüsse habe ich die eingesetzt.
Ich hatte irgendwann mal berechnet was für ein Strom dabei auftreten 
würde und den fand ich erträglich, deshalb 1kOhm ;)

> Und, -legst Du die ser.-ausgeschifteten Daten( per Clock vom Master )
> als 16 Bit Variable ab ?
> Oder wie erkennt die "Platine", daß das Daten für sie sind?
> Wenn nicht für sie, -dann weiterleiten?
> Oder auf jeden Fall weiterleiten?
Es gibt bei dem Aufbau drei Arten von Kommunikation:
1. Broadcast -> die Nachricht soll an alle weitergeleitet werden bis es 
keinen Nachbarn mehr gibt.
2. Die Daten werden an den direkten Nachbarn weitergeleitet.
3. Die Daten werden an eine Platine des selben Typs weitergeleitet (es 
gibt drei Typen von Platine).
Der Slave bekommt also ein Wort Daten, er schaut für wen es ist und 
leitet es dann ggf. weiter.

> Ist eine Kette aus Schiftregistern nicht sinnvoller? Dann bestimmt die
> Anzahl der Takte den Zielpunkt...
Das hatte ich auch erst überlegt, aber dann entschied ich mich dagegen, 
da der Platz auf den Platinen sehr, sehr knapp bemessen ist - eigentlich 
sind sie selbst so noch zu groß, passen ganz knapp.

> Übrigens nimm PC-Interupts, keine der ext.Int.  !
Welche Vorteile haben PC-Interrupts gegenüber "normalen" externen 
Interrupts?
Egal welche es sind, so muss ich leider darauf verzichten, der ATmega8 
hat ja leider keine...

Ich schaue mir nun gerade die Application Notes 304 und 305 von ATMEL 
und verschiedene Lösungen für Software SPI an.
Vielleicht finde ich dort etwas passendes :)

Viele Grüße
Florian

von erhardd (Gast)


Lesenswert?

... mir verschliesst sich immernoch der "tiefere" Sinn des Ganzen !
Wenn Du vermeiden willst, das ein einmaliger Anstoss durch ein 
Datenpaket
zum fröhlichen "Nightrider" Hin-und Herschicken von Daten führt, 
brauchst Du zumindest eine def. Abbruchbedingung!
Schliesse doch den Ring.
Dann bekommt der "Sender" irgentwann sein "Packet" zurück und weiß, -aha
 , -einmal durch (oder so);
Dir ist schon klar, das die Interupts in der Kette erhebliche Laufzeiten 
verursachen?
Aber, da Du über den Sinn des Ganzen noch nicht's verraten hast, kann
 ich das nicht beurteilen...

von erhardd (Gast)


Lesenswert?

...wenn ich mir das recht überlege wäre folgendes machbar;
-Broadcast (an alle ) paralelle Leitungsführung;
-1. Byte: Adresse --> hier Bausteinspezifische Markierung

Florian schrieb:
> 3. Die Daten werden an eine Platine des selben Typs weitergeleitet (es
> gibt drei Typen von Platine).

-2. Byte: Command (was ist zu tun?);
-3. Byte: Daten  (mit diesem);

die Anzahl der Platinen wäre somit egal(nach Bedarf änderbar);

von Florian (Gast)


Lesenswert?

Hallo erhardd,


erhardd schrieb:
> Aber, da Du über den Sinn des Ganzen noch nicht's verraten hast, kann
>  ich das nicht beurteilen...
Ich wollte die Erklärungen so einfach wie möglich halten, deswegen 
wollte ich solche "Nebensächlichkeiten" rauslassen.
Aber Du hast Recht, eine Anwendung macht das ganze anschaulicher...
Es handelt sich um ein Sensornetzwerk.
Dabei gibt es drei Typen von Platinen, drei Sorten von Sensoren bzw. 
Aktoren.
Die Platinen benötigen zum Berechnen von bestimmten Werten die Werte der 
Nachbarn, sowie für manche Berechnungen die Werte der gesamten Gruppe 
des selben Typs.
Zur Gesamtauswertung wird durch äußere Einwirkung ein Broadcast 
ausgelöst, der dann die gesamten Werte einholt.

> ... mir verschliesst sich immernoch der "tiefere" Sinn des Ganzen !
> Wenn Du vermeiden willst, das ein einmaliger Anstoss durch ein
> Datenpaket
> zum fröhlichen "Nightrider" Hin-und Herschicken von Daten führt,
> brauchst Du zumindest eine def. Abbruchbedingung!
> Schliesse doch den Ring.
> Dann bekommt der "Sender" irgentwann sein "Packet" zurück und weiß, -aha
>  , -einmal durch (oder so);
Die definierte Abbruchbedingung ist das Ende der Kette, ist kein Nachbar 
mehr vorhanden, der die Daten nicht geschickt hat, dann werden die Daten 
verworfen.

erhardd schrieb:
> Dir ist schon klar, das die Interupts in der Kette erhebliche Laufzeiten
> verursachen?
Sind Interrupts so langsam?
Ich hatte mit 2 bis 3 Takten gerechnet, habe ich mich da so verschätzt?
Ich muss zugeben, ich habe noch nicht im Datenblatt nachgeschaut, 
vielleicht sollte ich das mal tun. ;)

Bevor wir jetzt über das explizite Protokoll diskutieren sollte ich 
vielleicht ersteinmal die Kommunikation zwischen zwei Platinen 
hinbekommen.
Kann mir jemand einen Software-SPI-Code empfehlen?
Ich schaue gerade in die Richtung und werde versuchen heute abend mich 
einmal etwas mit der Materie zu beschäftigen.

Mir würde es zunächst erst einmal ausreichen, wenn ich fehlerfrei zwei 
Byte über zwei Leitungen übertragen könnte.
Bei meinen letzten Versuchen hatte ich scheinbar einen so großen Jitter, 
dass die Daten nicht heile übermittelt werden konnten.
Vielleicht lag das sogar an der interruptbasierten Übertragung?

Das schaue ich nun mal nach und prüfe es...

Viele Grüße
Florian

von Peter D. (peda)


Lesenswert?

Florian schrieb:
> Sind Interrupts so langsam?
> Ich hatte mit 2 bis 3 Takten gerechnet

Rechne je nach Programmiersprache und Erfahrung des Programmierers mit 
50 .. 500 Zyklen je Interrupthandler.


Peter

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

Florian schrieb:
> Sind Interrupts so langsam?
> Ich hatte mit 2 bis 3 Takten gerechnet, habe ich mich da so verschätzt?
Was, wenn gerade ein ANDERER Interrupt bearbeitet wird?
Und ich könnte mir vorstellen, den Interrupt mal zu sperren...  :-o

von Peter D. (peda)


Lesenswert?


von Florian (Gast)


Lesenswert?

@ Peter:
> Rechne je nach Programmiersprache und Erfahrung des Programmierers mit
> 50 .. 500 Zyklen je Interrupthandler.
Damit habe ich nun gar nicht gerechnet...
Ist ja wirklich keine zu unterschätzende Zeitspanne! :-O
Ich programmiere mit dem Gcc im AVR Studio, von daher nehme ich nun eher 
die 500 Zyklen an ;)
Was passiert während dieser Zyklen, läuft das Programm so lange einfach 
weiter oder arbeitet der Controller so lange am Interrupthandling?
Sollte ich manche Dinge vielleicht doch lieber pollen.
Danke für den Link, das schaue ich mir nachher mal genauer an :)

@ Lothar:
> Was, wenn gerade ein ANDERER Interrupt bearbeitet wird?
> Und ich könnte mir vorstellen, den Interrupt mal zu sperren...  :-o
Für solche Fälle hatte ich vorgesehen, dass der Empfänger nach Interrupt 
ein ACK schickt, damit der Sender weiß, dass er nun senden darf.
Der Empfänger ist dann in Erwartungshaltung und wartet nur auf die 
Signale.
Da aber der Interrupt sogar 500 Zyklen dauern kann, ist es klar, dass 
sich meine Programme z.T. sogar aufhängen, da nicht genügend Daten 
ankommen ;)

Vielen Dank für eure Tipps und Anregungen! :)

von Volkmar D. (volkmar)


Lesenswert?

Das Programm läuft solange weiter bis der entsprechende Interrupt die 
Berechtigung zum Ausführen der ISR bekommt. Der Einsprung in die ISR 
dauert nur wenige Takte, aber bis in der ISR dann der entscheidende Code 
ausgeführt wird, das hängt dann wieder vom Programmierer und der 
Programmiersprache ab.

Die "500 Zyklen" war nur eine Hausnummer, das hängt ganz davon ab wie 
lang Interrupts gesperrt sind (sei es durch cli oder einfach durch 
andere Interrupts).

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

Florian schrieb:
> Da aber der Interrupt sogar 500 Zyklen dauern kann, ist es klar, dass
> sich meine Programme z.T. sogar aufhängen, da nicht genügend Daten
> ankommen ;)
Ein richtiger Hacker kommt da schon mal auf 10ms, wenn er meint, im 
Interrupt ein LCD bedienen bedienen zu müssen...  :-/

von Florian (Gast)


Lesenswert?

Lothar Miller schrieb:
> Ein richtiger Hacker kommt da schon mal auf 10ms, wenn er meint, im
> Interrupt ein LCD bedienen bedienen zu müssen...  :-/
:D Nene, Interruptroutinen möglichst kurz halten, das kenne ich noch aus 
meinen ASM-Zeiten ;)
Aber das mit der ewigen Ausführverzögerung von Interrupts von ca. 50 bis 
500 Zyklen hat mich eben etwas verwundert...

Volkmar Dierkes schrieb:
> Die "500 Zyklen" war nur eine Hausnummer, das hängt ganz davon ab wie
> lang Interrupts gesperrt sind (sei es durch cli oder einfach durch
> andere Interrupts).
Ah ok, dann weiß ich Bescheid!
Es hat mich auch etwas verwundert, denn Interrupts werden ja auch zum 
Zählen etc. eingesetzt und da wäre ein Interrupt nach 500 Zyklen etwas 
langsam und Zweckfremd.

Aber ich werde mir diesbezüglich mein Programm nochmal anschauen und 
etwas rumexperimentieren! :)

Viele Grüße
Florian

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.