Forum: Compiler & IDEs At90can128 mehrere Nachrichten unterscheiden


von David (Gast)


Lesenswert?

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

von David (Gast)


Lesenswert?

Es soll damit ein Roboter angesteuert werden, der sich aus Servos 
zusammensetzt.

von kosmonaut pirx (Gast)


Lesenswert?

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

von David H. (dafhit)


Lesenswert?

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

von kosmonaut pirx (Gast)


Lesenswert?

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

von David H. (dafhit)


Lesenswert?

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?

von kosmonaut pirx (Gast)


Lesenswert?

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


von kosmonaut pirx (Gast)


Lesenswert?

sorry, verlesen, CANHPMOB steht direkt über CANPAGE in der doku. du 
setzt CANPAGE zweimal, aber beide male richtig.

von David H. (dafhit)


Lesenswert?

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

von kosmonaut pirx (Gast)


Lesenswert?

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

von David H. (dafhit)


Lesenswert?

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

von kosmonaut pirx (Gast)


Lesenswert?

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

von David H. (dafhit)


Lesenswert?

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

von kosmonaut pirx (Gast)


Lesenswert?

wenn mob 1 frei ist, wird es der controller immer vor mob 2 benutzen. 
vorausgesetzt natürlich, die maske passt.

viel erfolg,
bye kosmo

von David H. (dafhit)


Lesenswert?

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

von kosmonaut pirx (Gast)


Lesenswert?

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

von David H. (dafhit)


Lesenswert?

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