Forum: Mikrocontroller und Digitale Elektronik Can Bus Kommunikation


von Thomas (Gast)


Lesenswert?

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

von Stefan F. (Gast)


Lesenswert?

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.

von Stefan E. (stefanosch)


Lesenswert?

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

von Gerd E. (robberknight)


Lesenswert?

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?

von Jens M. (schuchkleisser)


Lesenswert?

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.

von Thomas F. (igel)


Lesenswert?

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.

von Tilo R. (joey5337) Benutzerseite


Lesenswert?

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)

von rcc (Gast)


Lesenswert?

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.

von Thomas (Gast)


Lesenswert?

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!

von Thomas F. (igel)


Lesenswert?

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.

von Tilo R. (joey5337) Benutzerseite


Lesenswert?

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