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!
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
@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. !
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
... 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...
...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);
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
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
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
@ 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! :)
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).
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... :-/
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.