Hallo zusammen, ich habe ein CAN- Bus Netzwerk mit 3 Teilnehmener (2x Arduino, 1x Raspberry), welche miteinander Daten austauschen. Als Controller für den Bus wird ein MCP2515 verwndet. Wenn auf Teilnehmer A ein bestimmtes Event eintritt, so soll Teilnehmer B davon in Kenntnis gesetzt werden (wobei garantiert werden muss, dass Teilnehmer B auch das Event empfängt). Es kommt auch vor, dass innerhalb 400ms 20 Events generiert werden. Der MCP2515 kann aber nur 2 Receive Events gleichzeitig speichern. Nun kommt es vor, dass Daten zu schnell geschickt werden und dabei Events verschluckt werden. Um das zu lösen, habe ich ein kleines Protokoll gebaut, wo Teilnehmer B bestätigen muss, dass das Event von Teilnehmer A empfangen wurde. Erhält Teilnehmer A keine Bestätigung, so schickt er das gleiche Event nochmals. Funktioniert seit einem Jahr problemlos, nur mir gefällt der ganze Software Overhead nicht (Teilnehmer A muss sich alle Events solange merken, bis die Empfangsbestätigung eingetroffen ist, Teilnehmer B muss sich alle bereits empfangen Events merken, damit dieser keine doppelt empfängt). Es gibt bestimmt bessere und einfachere Lösungen. Wie garantiert ihr, dass bestimmte Pakete auch tatsächlich beim Empfänger ankommen. Bin auf eure Tipps gespannt! lG
Thomas schrieb: > Es gibt bestimmt bessere und einfachere Lösungen. Glaube ich nicht. Wenn du deine Quelltexte zeigen würdest, finden wir sicher Kleinigkeiten, die man dabei verbessern kann. Aber das Konzept an sich ist so in Ordnung. CAN enthält halt kein Handshake mit ACK in Hardware.
Thomas schrieb: > Teilnehmer B muss > sich alle bereits empfangen Events merken, damit dieser keine doppelt > empfängt wenn Du nicht doppelt sendest, dann muss B sich auch nichts merken
Thomas schrieb: > Wenn auf Teilnehmer A ein bestimmtes Event eintritt, so soll Teilnehmer > B davon in Kenntnis gesetzt werden (wobei garantiert werden muss, dass > Teilnehmer B auch das Event empfängt). > Es kommt auch vor, dass innerhalb 400ms 20 Events generiert werden. Muss B wirklich über jedes einzelne Event separat informiert werden? Würde es ausreichen, wenn im Falle der vielen Events in kurzer Zeit nur ein Zähler übermittelt wird der sagt wie viele Events in den letzten z.B. 100ms aufgetreten sind?
Mit anderen Protokollen auf anderen Bussystemen. CAN ist ausdrücklich nicht dazu da, sicherzustellen das "der eine" Empfänger die Nachricht auch bekommt, sondern eher "fire and forget". Ich würde eine Queue realisieren, immer eine Nachricht abschicken, Quittung abwarten -> Antwort ok = nächste, Timeout = Repeat. 3x Repeat = #Bus Error. Dann müssen eben so viele Nachrichten gespeichert werden, wie in 3x Timeout passen. Oder Timeout so kurz machen das das RAM passt.
Thomas schrieb: > Es kommt auch vor, dass innerhalb 400ms 20 Events generiert werden. Das ist doch eher wenig. Da langweilt sich doch der Bus. > Der MCP2515 kann aber nur 2 Receive Events gleichzeitig speichern. Nun > kommt es vor, dass Daten zu schnell geschickt werden und dabei Events > verschluckt werden. Daten werden nicht zu schnell verschickt. Das regelt der MCP2515 schon von selbst und sendet nur wenn der Bus frei ist. Deine Software ist einfach zu langsam die empfangenen Botschaften aus den Receive-Puffern auszulesen bevor eine neuen Botschaft eintrifft. Also: Software optimieren.
Verschiedenes: Dass B "garantiert" das Event von A empfängt bekommst du nur mit einer expliziten Bestätigungsmeldung hin. CAN an sich funktioniert zwar sehr zuverlässig. Das hilft aber nicht, wenn B ausgeschaltet ist :-) Jetzt zu den 20 Events in 400ms: Wenn so viele Events auf einmal kommen liegt der Verdacht nahe, dass die was miteinander zu tun haben. Lässt sich das vielleicht konsolidieren und in weniger Nachrichten packen? Dann die Empfangsseite: Ja, der MCP2515 hat nur 2 Puffer. Aber er kann einen Hardwareinterrupt auslösen. Und wenn ich mich recht erinnere, ist es sogar möglich, über die IO-Pins des MCP auszugeben, welcher der 2 Puffer belegt ist. Wenn man nicht rumtrödelt kann man die Nachricht locker abholen während im 2. Puffer noch der Empfang läuft. Den SPI-Bus kann man schnell takten. Wenn du die Nachrichten natürlich superaufwändig auswerten willst musst du dir einen Empfangspuffer bauen. Wenn dir das zu stressig ist kannst du sicher auch langsamer senden. Wie schnell muss denn dein Bus sein? Du kannst sicher mit der Bitrate extrem runtergehen. Dann soll A halt schauen, wie er seine Events loswird bzw. muss eine Sende-Queue haben. (Die hast du dort ja offensichtlich eh schon, wenn du es dir leisten kannst, auf das ACK-Event zu warten)
Gerd E. schrieb: > Thomas schrieb: >> Wenn auf Teilnehmer A ein bestimmtes Event eintritt, so soll Teilnehmer >> B davon in Kenntnis gesetzt werden (wobei garantiert werden muss, dass >> Teilnehmer B auch das Event empfängt). >> Es kommt auch vor, dass innerhalb 400ms 20 Events generiert werden. > > Muss B wirklich über jedes einzelne Event separat informiert werden? > > Würde es ausreichen, wenn im Falle der vielen Events in kurzer Zeit nur > ein Zähler übermittelt wird der sagt wie viele Events in den letzten > z.B. 100ms aufgetreten sind? die Zähler dann am Besten noch zu einem großen "Sägezahn" aufsummieren, dann tut auch eine Botschaft die nicht ankommt nicht weh wenn man die Überlaufbehandlung vom Sägezahn sauber macht.
Hallo, danke für eure Antworten: Stefan E. schrieb: > Thomas schrieb: >> Teilnehmer B muss >> sich alle bereits empfangen Events merken, damit dieser keine doppelt >> empfängt > > wenn Du nicht doppelt sendest, dann muss B sich auch nichts merken Empfänger muss sich merken, welches Paket schon empfangen wurde. Beispiel: A sendet B ein Paket, B sendet ACK zu A, A empfängt es aber nicht. Nun glaubt A, B hat Paket nicht empfangen und sendet nochmal. B merkt nun, dass Paket bereits empfangen wurde und sendet erneut das ACK. Tilo R. schrieb: > Dass B "garantiert" das Event von A empfängt bekommst du nur mit einer > expliziten Bestätigungsmeldung hin. > CAN an sich funktioniert zwar sehr zuverlässig. Das hilft aber nicht, > wenn B ausgeschaltet ist :-) Wenn der Node ausgeschalten ist, hab ich sowies ein Problem. Daher würde ich das Problem, wenn ein Node nicht mehr verfügbar ist, ignorieren. Jeder Node sendet jede Sekunde ein "HELLO", damit jeder Node weiß, ob eh alle verfügbar sind. Tilo R. schrieb: > Jetzt zu den 20 Events in 400ms: > Wenn so viele Events auf einmal kommen liegt der Verdacht nahe, dass die > was miteinander zu tun haben. Lässt sich das vielleicht konsolidieren > und in weniger Nachrichten packen? Ja, kann man bestimmt zusammenfassen., gute Idee Tilo R. schrieb: > Dann die Empfangsseite: Ja, der MCP2515 hat nur 2 Puffer. Aber er kann > einen Hardwareinterrupt auslösen. Und wenn ich mich recht erinnere, ist > es sogar möglich, über die IO-Pins des MCP auszugeben, welcher der 2 > Puffer belegt ist. Wenn man nicht rumtrödelt kann man die Nachricht > locker abholen während im 2. Puffer noch der Empfang läuft. Den SPI-Bus > kann man schnell takten. Wenn du die Nachrichten natürlich > superaufwändig auswerten willst musst du dir einen Empfangspuffer bauen. Ja, den Hardware- Interrupt könnte ich auch noch implementieren. Aber funktioniert das auch korrekt? Wenn ich gerade eine Nachricht sende und der Hardware- Interrupt löst aus, kann ich dann auch die Nachricht lesen, wobei ich gerade am Senden bin, ohne das ich das SPI Protokoll zerstöre? Tilo R. schrieb: > Wenn dir das zu stressig ist kannst du sicher auch langsamer senden. Wie > schnell muss denn dein Bus sein? Du kannst sicher mit der Bitrate extrem > runtergehen. Dann soll A halt schauen, wie er seine Events loswird bzw. > muss eine Sende-Queue haben. (Die hast du dort ja offensichtlich eh > schon, wenn du es dir leisten kannst, auf das ACK-Event zu warten) Meine Aktuelle CAN Geschwindigkeit ist CAN_125KBPS, wobei ich diese auch noch um ein vielfaches reduzieren kann. Dnake für eure Tipps!
Thomas schrieb: > Empfänger muss sich merken, welches Paket schon empfangen wurde. > Beispiel: A sendet B ein Paket, B sendet ACK zu A, A empfängt es aber > nicht. Nun glaubt A, B hat Paket nicht empfangen und sendet nochmal. B > merkt nun, dass Paket bereits empfangen wurde und sendet erneut das ACK. Das wäre mir viel zu umständlich. Wie oben schon beschrieben: Der Sender sendet nur, die Empfänger müssen schon selber klar kommen und alles richtig empfangen. Zur Nachverfolgung kann man in die einzelnen Botschaften einen Botschaftszähler einbauen welcher von 0-255 hochläuft und dann wieder bei 0 beginnt. Thomas schrieb: > Ja, den Hardware- Interrupt könnte ich auch noch implementieren. Aber > funktioniert das auch korrekt? Natürlich funktioniert der korrekt! > Wenn ich gerade eine Nachricht sende und der Hardware- Interrupt löst > aus, kann ich dann auch die Nachricht lesen, wobei ich gerade am Senden > bin, ohne das ich das SPI Protokoll zerstöre? Bei einem Interrupt wird das Übertragen (nicht Senden) der Botschaft zum MCP2515 nicht unterbrochen. Die kurze und schlanke CAN-Interrupt-Routine setzt beim Auslösen nur einen Merker (Flag), mehr nicht. Das Hauptprogramm überprüft dann nach dem Übertragen anhand des Merkers ob eine neuen Botschaft vorhanden ist und holt diese dann ab.
Thomas F. schrieb: >> Wenn ich gerade eine Nachricht sende und der Hardware- Interrupt löst >> aus, kann ich dann auch die Nachricht lesen, wobei ich gerade am Senden >> bin, ohne das ich das SPI Protokoll zerstöre? > > Bei einem Interrupt wird das Übertragen (nicht Senden) der Botschaft zum > MCP2515 nicht unterbrochen. Die kurze und schlanke CAN-Interrupt-Routine > setzt beim Auslösen nur einen Merker (Flag), mehr nicht. Das > Hauptprogramm überprüft dann nach dem Übertragen anhand des Merkers ob > eine neuen Botschaft vorhanden ist und holt diese dann ab. Wenn man das so macht, lohnt sich der Interrupt eigentlich nicht. Richtig ist: eine laufende SPI-Übertragung darf man natürlich nicht unterbrechen. Der Interrupt-Ausgang des MCP sagt ja eigentlich nur "da ist was, schau mal". Der uC hat jetzt 2 Möglichkeiten, damit umzugehen: 1. Als IO-Pin. Als erster Befehl in der Mainloop schauen, ob man Nachrichten holen muss. Das ist so eine einzelne IO-Abfrage und kostet praktisch nichts. Ohne den angeschlossenen Interrupt-Ausgang müsste man den MCP per SPI fragen, das dauert länger. Dann Nachrichten holen, bis der MCP leer ist. Nachteil: die restliche Main-Loop darf nicht zu lange dauern. Mit der CAN-Bitrate und der Messagegröße, bzw. der maximalen Message-Rate kannst du diese Maximaldzeit ausrechnen und den Rest des Programms darauf abstimmen. Ggf. ist es notwendig, aufwendige Tasks in kleinere zu zerteilen. Die Mainloop muss halt oft genug laufen, sonst können Nachrichten verloren gehen. 2. Ein echter Hardware-Interrupt. In der angesprungenen Interrupt-Routine muss dann die Nachricht abgeholt und gespeichert oder verarbeitet werden. Dein restliches Programm kann dann beliebig langsam sein und praktisch alles machen, außer den SPI benutzen. Zum Senden muss man den Interrupt abschalten. Es gibt auch die Möglichkeit beides zu kombinieren: d.h. es wird ein echter Interrupt ausgelöst. In der ISR macht man aber nichts (oder setzt nur ein Flag, wie von Thomas F vorgeschlagen). Das Abholen macht man dann wie bei 1. in der Mainloop. Vorteil hier ist, dass der Interrupt den uC auch aufweckt, wenn man in einem Stromsparmodus war.
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.