Hallo, Ich arbeite nun schon ein halbes Jahr mit dem at90 und dem CAN-Bus, jetzt stellt sich aber ein größeres Problem: Ich möchte dem Mikrocontroller zwei unterschiedliche Nachrichten mit verschiedenen IDs senden, dieser soll per Interrupt reagieren und je nach ID die Daten in die richtigen Variablen übernehmen. Wie kann ich herausfinden welche ID den Interrupt ausgelöst hat? Das Beispiel von Atmel arbeitet mit dem Prioritätsregister, wenn ich das auch mache, kommt eine Nachricht (mit der niedrigeren Priorität) nicht mehr durch. Die Nachrichten werden extrem schnell hintereinander geschickt (max 10 ms Abstand, dann 50 ms, dann wieder 10...), kann das Probleme machen? Gruß David
Es soll damit ein Roboter angesteuert werden, der sich aus Servos zusammensetzt.
hallo,
>Wie kann ich herausfinden welche ID den Interrupt ausgelöst hat?
naja. zunächst einmal gar nicht. lösen zwei message-objekte (mobs)
gleichzeitig einen irq aus, ist das pech.
dann hast du die möglichkeit, das highest priority-register zu checken
und entsprechend das mob zu behandeln. wenn du damit fertig bist, das
entsprechende rx-flag löschen (und den ganzen restlichen kram, siehe
doku) und fertig. das nächste mob wird sich alsbald wieder melden, da es
ja noch nicht behandelt wurde.
eine andere möglichkeit ist das cansit-register abzuklappern. ich mache
das so, da ich mir merke, welches mob zuletzt behandelt wurde, um dann
in ring-buffer-manier vorzugehen. zweck: keine nachricht soll eine
andere überholen (stichwort: re-ordering durch den can-controller)
bye kosmo
Das mit dem cansit Register habe ich glaub ich schon ausprobiert, im Prinzip braucht man doch nur gucken wo überall eine 1 steht und dann entsprechend reagieren, hat aber nicht viel gebracht. Ich werd mich da morgen noch mal dransetzen... Danke für die schnelle Antwort David
ok, cansit ist recht dumm, weil da die id des mobs so schön verschoben und kodiert ist. irgendwie so:
1 | uint16_t cansit = (CANSIT1 << 8) | CANSIT2; |
2 | |
3 | for ( i = 0; i < CANARY_MOB_NUM; i++){ |
4 | if ( cansit & ( 1 << i) ){ |
5 | // found set bit in irq registers
|
6 | return i; |
7 | }
|
8 | }
|
canhpmob ist da wesentlich einfacher, weil es direkt die id des mobs ausgibt. viel erfolg, bye kosmo
Ich weiß jetzt nicht mehr weiter, es passiert immer noch das gleiche, egal wie ich die Abfrage mache, ich habe sogar schon eine Variante probiert, in der nur eine ID verwendet wird und die Zuordnung über höhere, unbenutzte Bits in der Nachricht selbst geschieht. Das ganze macht aber auch keinen Unterschied... Hier mal meine ISR, vielleicht fällt jemandem ja ein grober Schnitzer auf.
1 | SIGNAL (SIG_CAN_INTERRUPT1) |
2 | {
|
3 | |
4 | unsigned char temp = CANPAGE; //CANPAGE sichern |
5 | |
6 | unsigned char nummer = (CANHPMOB >> 4); //MOb finden |
7 | CANPAGE = (nummer << MOBNB0); |
8 | |
9 | unsigned char i; //Zähler |
10 | |
11 | CANPAGE = (nummer << MOBNB0); //Flags zurücksetzen |
12 | CANSTMOB &= ~(1 << RXOK); |
13 | CANSIT2 &= ~(1 << nummer); |
14 | CANCDMOB = 0; |
15 | CANGIT = 0xff; |
16 | |
17 | for (i=0; i<8; i++) //Daten auslesen |
18 | msg[0].data[i] = CANMSG; |
19 | |
20 | CANCDMOB = (1<<CONMOB1); //MOb wieder auf Empfang |
21 | |
22 | posidaten[nummer][0] = msg[0].data[0]; //Daten speichern |
23 | posidaten[nummer][1] = msg[0].data[1]; |
24 | posidaten[nummer][2] = msg[0].data[2]; |
25 | posidaten[nummer][3] = msg[0].data[3]; |
26 | posidaten[nummer][4] = msg[0].data[4]; |
27 | posidaten[nummer][5] = msg[0].data[5]; |
28 | posidaten[nummer][6] = msg[0].data[6]; |
29 | posidaten[nummer][7] = msg[0].data[7]; |
30 | |
31 | CANPAGE = temp; //CANPAGE zurück |
32 | }
|
Mehr Flags kann man doch gar nicht mehr zurücksetzen, oder?
hallo. erste frage: was funktioniert wie nicht? und nun die kritikpunkte :) >SIGNAL (SIG_CAN_INTERRUPT1) das heißt doch jetzt ISR(CANIT_vect) >{ > unsigned char temp = CANPAGE; //CANPAGE sichern > > unsigned char nummer = (CANHPMOB >> 4); //MOb finden > CANPAGE = (nummer << MOBNB0); > > unsigned char i; //Zähler soweit so gut. > CANPAGE = (nummer << MOBNB0); //Flags zurücksetzen warum wieder ein anderes mob? CANHPMOB gibt dir doch schon die id, und du hast doch richtig geshiftet, die 4 entspricht MOBNB0 > CANSTMOB &= ~(1 << RXOK); zu früh. > CANSIT2 &= ~(1 << nummer); brauchst nicht. ist ein nur-lese-register. > CANCDMOB = 0; ok, aber würde ich zusammen mit dem re-enablen hintereinander weg schreiben. > CANGIT = 0xff; brauchst nicht. > for (i=0; i<8; i++) //Daten auslesen > msg[0].data[i] = CANMSG; sehr fein. > CANCDMOB = (1<<CONMOB1); //MOb wieder auf Empfang zu früh, wenn du mich fragst. funktioniert aber. > posidaten[nummer][0] = msg[0].data[0]; //Daten speichern > posidaten[nummer][1] = msg[0].data[1]; > posidaten[nummer][2] = msg[0].data[2]; > posidaten[nummer][3] = msg[0].data[3]; > posidaten[nummer][4] = msg[0].data[4]; > posidaten[nummer][5] = msg[0].data[5]; > posidaten[nummer][6] = msg[0].data[6]; > posidaten[nummer][7] = msg[0].data[7]; > CANPAGE = temp; //CANPAGE zurück >} ok. ich würde das mob erst wieder freigeben, wenn die isr fertig ist, aber das ist geschmackssache. viele register musst du gar nicht setzen (read-only oder implizit). größter schnitzer ist aber das CANHPMOB, wenn ich das richtig erkannt habe. hth, bye kosmo
sorry, verlesen, CANHPMOB steht direkt über CANPAGE in der doku. du setzt CANPAGE zweimal, aber beide male richtig.
Hallo, Das mit dem zweiten CANPAGE ist da wohl beim reinkopieren reingeraten, der Code sieht in echt ein bißchen wüster aus, mit vielen auskommentierten Varianten... Was nicht geht ist, wenn ich eine Nachricht sende, auf die MOb 1 reagiert und dann eine, auf die MOb 2 reagieren soll (von den Message IDs her), dann passiert da nichts, andersherum geht, aber wenn ich dann wieder versuche MOb 2 anzusprechen geht das auch wieder nicht, das finde ich seltsam. Das mit der erneuten Freigabe des MObs ist doch eigentlich egal, die ISR wird doch nicht durch einen erneuten Interrupt unterbrochen, oder? Danke für´s auseinanderfleddern :-) David
hallo, >Das mit der erneuten Freigabe des MObs ist doch eigentlich egal, die ISR >wird doch nicht durch einen erneuten Interrupt unterbrochen, oder? nein, das nicht. daher ist es egal, ja. ich rate einfach mal: vielleicht siehst du da ein problem, wo gar keines ist. wenn du kein (!) masking benutzt, ist es doch egal, welches mob reagiert. die nummerierung der mobs hat in diesem falle rein gar nichst mit den CAN.identifyern (message-id's nennst du diese) zu tun. oder maskiertst du einzelne mobs für den empfang von speziellen identifiern? bye kosmo
Ja tue ich, Es müssen 8 Werte a 10 Bit übetragen werden (Positionen für 8 Servos), ich habe mir gedacht ich bastel die in 8 unsigned int um und splitte diese auf 16 unsigned char auf, somit brauche ich ja 2 Pakete um alles zu übertragen. Es ist nun ziemlich wichtig, dass die Nachrichten unterschieden werden, sonst werden nicht die richtigen Servos angesteuert. Wie gesagt hatte ich es auch schon damit probiert in den oberen 6 Bit die Zugehörigkeit zu kennzeichnen und alles mit der gleichen ID zu übertragen, aber das hat überhaupt keinen Unterschied gemacht, was ich ziemlich seltsam finde. Gruß David
das klingt alles für mich so, als wenn du das mob nicht wieder auf empfang stellst. dann sind die beiden voll, der controller findet kein freies mob und wirft es in die tonne. um das zu evaluieren: erst einmal masking aus. dann solltest du jede nachricht kriegen. wenn das funktioniert, lasse dir ausgeben, welches mob die isr behandelt. vielleicht hilft das weiter. ich selber mache das CANCDMOB niemals komplett platt. sondern schreibe nur die conf mit nem ODER neu rein (wie es die doku so schön verlangt). weiterhin benutze ich das dlc beim einlesen der daten, gut, wenn du immer 8 erhältst, ist das schnuppe. ansonsten sind mir keine großen unterschiede aufgefallen. zur not musst' halt noch n bischen code posten. bye kosmo
Ja, dann werd ich noch ein bißchen testen, vielen Dank für die Tipps, es ist allerdings so, dass MOb 1 (also nach meinem Verständnis der mit der höheren Priorität) immer die Nachrichten empfängt, nur die für Nummer 2 kommen nicht richtig an, aber das werd ich mir gleich noch mal ansehen. Gruß David
wenn mob 1 frei ist, wird es der controller immer vor mob 2 benutzen. vorausgesetzt natürlich, die maske passt. viel erfolg, bye kosmo
Also die Maskierung funktioniert, wenn ich nur eine ID benutze reagieren beide MObs so wie sie das sollen, ohne das ein anderer da mitredet... Ich bin jetzt soweit, dass ich einfach nen zweiten at90 einbaue, so dass jeder nur mit einer Nachricht arbeiten muss. Das funktioniert wenigstens und die Uni hat ja genug Geld :-) Inzwischen glaube ich auch immer mehr, dass die Interrupts einfach zu schnell hintereinander kommen. Naja, morgen gehts weiter, jetzt reicht das erst mal Gruß David
hallo, was du machst, ist fragmentierung von daten. du hast mehr daten, als in eine mtu passt. hab ich auch vor kurzem gemacht, um mehr als 8 byte über CAN zu übertragen. nettes thema bei mehreren puffern. problem ist doch, das ein höher priorisiertes mob für nachrichten benutzt wird, die zeitlich hinter anderen nachrichten angesiedelt sind. wobei letztere bereits in niedriger priorisierten mobs stecken. der controller nimmt somit ein re-ordering vor. da die abarbeitung eines mobs schlicht zeit in anspruch nimmt (register puschen, isr selber, register wieder poppen), sind manchmal mehrere mobs mit einem irq signalisiert. bei dir also mob 1 und 2 , obwohl du gerade auf eine nachricht im 2. mob wartest. was ist jetzt richtig? meiner meinung nach gibt es zwei möglichkeiten: 1. nimm nur ein mob, und unterscheide anhand des CAN-identifiers. also kein hardware-masking. ist zwar nicht sehr clever, aber einfach und sollte leicht gehen. 2. einfach merken, welches das letzte aktive mob war. wäre dies also mob 2, denn wäre also mob 1 das nächste erwartete (bei dir). oder entsprechend umgekehrt. kann man schön mit 15 mobs hochtreiben. funtkioniert, wie schon mal erwähnt. na viel spass (das macht es tatsächlich .. wenn es mal funktioniert) bye kosmo
Hallo, Nach langem, intensivem Testen bin ich jetzt auf den Kern des Problems gestoßen. Der liegt überhaupt nicht bei CAN (die Sache ging die ganze Zeit wunderbar), sondern an der Ansteuerung der Servos durch die PWM. Die Sache ist jetzt zwar auch nicht einfach, aber wenigstens bin ich nicht mehr Schuld :-) Gruß David
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.