Forum: Mikrocontroller und Digitale Elektronik AT90CAN Probleme beim senden in kurzer Folge


von Michael S. (michi-s2)


Angehängte Dateien:

Lesenswert?

Hallo,

ich hab ein Problem wenn ich mehrere CAN Nachrichten gleich nacheinander 
senden will, werden manche verschluckt.
Es kommen nur Nachricht 1 und 4 an. Es ist egal, ob die in dem selben 
mob sind oder nicht.
Anscheinend mache ich beim warten bis alles gesendet ist was falsch.
1
int can_init_mob_tx2(uint8_t mob, uint8_t ide, uint16_t id, uint8_t dlc, unsigned char *data, int rtr){
2
  uint8_t i = 0;
3
  
4
  
5
  if(mob < 8) while(CANEN2 & mob);
6
  else while(CANEN1 & (mob >> 8));
7
  
8
  while(CANGSTA & (1<<TXBSY));  //Transmitter Busy
9
  
10
  
11
  CANPAGE = ((mob) << 4);
12
  
13
  //Can_clear_mob   Teile aus der lib vom Forum hier
14
  uint8_t  volatile *__i_; 
15
  for (__i_=&CANSTMOB; __i_<&CANSTML; __i_++) { *__i_=0x00 ;} //WTF Datasheet 405
16
  
17
18
  CANIDT1  = CAN_SET_STD_ID_10_4(id); 
19
  CANIDT2  = CAN_SET_STD_ID_3_0( id); 
20
  CANIDT3  = 0;
21
  CANIDT4  = 0;
22
23
  for (i=0; i<dlc; i++) CANMSG = data[i];
24
  
25
  CANSTMOB = 0;    
26
27
  CANCDMOB = (1  << CONMOB0) | dlc;//tx
28
  
29
  
30
  while(! (CANSTMOB & (1<<TXOK)));  //wait till tx ok 
31
  
32
  CANCDMOB = 0;
33
}
1
int main(){ 
2
...
3
    while (1) 
4
    {
5
    can_init_mob_tx2(1,CAN_2A,0x0280,8,nachricht_1,CAN_NO_RTR);
6
    //_delay_ms(1);
7
    can_init_mob_tx2(2,CAN_2A,0x0550,8,nachricht_2,CAN_NO_RTR);
8
    //_delay_ms(1);
9
    can_init_mob_tx2(3,CAN_2A,0x02A0,8,nachricht_3,CAN_NO_RTR);
10
    //_delay_ms(1);
11
    can_init_mob_tx2(4,CAN_2A,0x04A8,8,nachricht_4,CAN_NO_RTR);
12
    //_delay_ms(1);
13
14
15
    //Nachrichten sollen alle 20 ms gesendet werden.
16
    _delay_ms(20);
17
    }

Ohne den delays geht es nicht, mit den delays kein Problem.


Bemerkung:
Die main.c ist so geschrieben, dass sie bei jedem sofort mit Atmel 
Studio kompilieren sollte.
Momentan nur 2 AT90CAN128 am CAN.
Bus ist terminiert.
Der Andere liest nur. (Nicht im spy/silent mode)
Baudrate 500kB/s.
Normalerweise werden die Nachrichten in nem Timer gesendet und da ist 
das delay ein Problem.
Mir ist klar, dass endlos whiles doof sind.

Danke,
Michi

von Thomas (kosmos)


Lesenswert?

liefert der integrierte CAN Controller nichts das man weiß ob die 
Übertragung ok oder fehlerhaft war, der ATM16M1 spuckt z.B einige 
Interrupts aus, diese muss man eben auch auswerten.

Interrupt on receive completed OK
Interrupt on transmit completed OK
Interrupt on error (bit error, stuff error, CRC error, form error, 
acknowledge error)
Interrupt on frame buffer full
Interrupt on “Bus Off” setting
Interrupt on overrun of CAN timer

von Michael S. (michi-s2)


Lesenswert?

Mit dem
1
while(! (CANSTMOB & (1<<TXOK)));  //wait till tx ok

warte ich eigentlich auf das Interrupt auslösende Bit.

So wie ich das gesehen hab, muss der Interrupt dafür aber nicht extra 
Aktiviert werden.

TXOK: Transmit OK
This flag can generate an interrupt. It must be cleared using a 
read-modify-write software routine on the whole CANSTMOB register.
The communication enabled by transmission is completed.
TxOK rises at the end of EOF field and then, the MOb is disabled (the 
corresponding ENMOB-bit of CANEN registers is cleared). When the 
controller is ready to send a frame, if two or more message objects are 
enabled as producers, the lower MOb index is supplied >first.

von Thomas (kosmos)


Lesenswert?

stimmt die Interruptroutine muss man nicht anspringen lassen, aber du 
musst das Bit nach jeder Übertragung löschen damit du es wieder neu 
auswerten kannst.

von Michael S. (michi-s2)


Lesenswert?

Das passiert zwei Zeilen drüber.

von Marc V. (Firma: Vescomp) (logarithmus)


Lesenswert?

Michael S. schrieb:
> Anscheinend mache ich beim warten bis alles gesendet ist was falsch.
1
  while(! (CANSTMOB & (1<<TXOK)));  //wait till tx ok 
2
  
3
  CANCDMOB = 0;

 Und CANSTMOB auf 0 setzen ?

von Michael S. (michi-s2)


Lesenswert?

1
  CANSTMOB = 0;    
2
3
  CANCDMOB = (1  << CONMOB0) | dlc;//tx
4
  
5
  
6
  while(! (CANSTMOB & (1<<TXOK)));  //wait till tx ok 
7
  
8
  CANCDMOB = 0;

Mach ich davor, um sicher zu gehen, dass zwischen den Aufrufen nichts 
darin passiert. (z.B. Nachrichten empfangen)

Aber auch wenn ich es davor und danach mache bleibt das Problem 
bestehen.

von Rudolph R. (rudolph)


Lesenswert?

https://www.mikrocontroller.net/attachment/216654/16M1_Test.c

In der can_init() muss für den 90CAN128 nur eine 15 in der Schleife 
eingetragen werden, der hat ja mehr MOBs.

Nur die beiden Zeilen hier sind Quatsch und können gelöscht werden:
1
CANEN1 = 0x00;
2
CANEN2 = (1<<ENMOB0);// | (1<<ENMOB1); // enable MOB0, MOB1

von Michael S. (michi-s2)


Lesenswert?

Danke für deinen Code, aber auch damit funktioniert es bei mir nicht. 
Hast du damit schon erfolgreich mehrere Nachrichten gleich nacheinander 
gesendet?

von Rudolph (Gast)


Lesenswert?

Ich habe gerade mal kurz ausprobiert den Bus voll zu machen und das 
funktioniert so nicht, es gehen nicht alle Botschaften durch.
Von vier Botschaften hintereinander weg kommen nur die ersten zwei auf 
dem Bus an.

Macht aber auch Sinn, durch die Priorisierung der Botschaften sollte 
eigentlich nur die Botschaft mit der niedrigsten ID durch gehen,
wenn man versucht in einer engen Schleife zu senden.
Die zweite Botschaft geht mit durch, weil genug Zeit ist zwischen dem 
Abschluss des Sendens der niedrigsten ID und dem neu befüllen des MOB.

Okay, also mal anders:
1
  while(1)
2
  {
3
    counter++;
4
5
    CANPAGE = (3<<4); // select MOB3
6
    if(CANSTMOB & (1<<TXOK)) // fertig mit Senden?
7
    {
8
9
      CANPAGE = (0<<4); // select MOB0
10
      if(CANSTMOB & (1<<TXOK)) // fertig mit Senden?
11
      {
12
        CANSTMOB &= ~(1<<TXOK); // reset flag
13
        CANCDMOB = (1<<DLC1); // 2 Byte
14
        CANMSG = counter;
15
        CANMSG = 0xaa;
16
        CANCDMOB |= (1<<CONMOB0); // Transfer einleiten
17
      }
18
19
      CANPAGE = (1<<4); // select MOB1
20
      if(CANSTMOB & (1<<TXOK)) // fertig mit Senden?
21
      {
22
        CANSTMOB &= ~(1<<TXOK); // reset flag
23
        CANCDMOB = (1<<DLC1); // 2 Byte
24
        CANMSG = counter;
25
        CANMSG = 0xaa;
26
        CANCDMOB |= (1<<CONMOB0); // Transfer einleiten
27
      }
28
29
      CANPAGE = (2<<4); // select MOB2
30
      if(CANSTMOB & (1<<TXOK)) // fertig mit Senden?
31
      {
32
        CANSTMOB &= ~(1<<TXOK); // reset flag
33
        CANCDMOB = (1<<DLC1); // 2 Byte
34
        CANMSG = counter;
35
        CANMSG = 0xaa;
36
        CANCDMOB |= (1<<CONMOB0); // Transfer einleiten
37
      }
38
    
39
      CANPAGE = (3<<4); // select MOB3
40
      if(CANSTMOB & (1<<TXOK)) // fertig mit Senden?
41
      {
42
        CANSTMOB &= ~(1<<TXOK); // reset flag
43
        CANCDMOB = (1<<DLC1); // 2 Byte
44
        CANMSG = counter;
45
        CANMSG = 0xaa;
46
        CANCDMOB |= (1<<CONMOB0); // Transfer einleiten
47
      }
48
    }
49
  }

Erst wieder neu die MOBs füllen wenn die letze Botschaft auch durch ist.

Damit sehe ich dann auch alle vier Botschaften auf dem Bus 
hintereinander weg mit dem jeweils aktuellen Zählerstand, da fehlt 
nichts mehr.
Das sind dann auch alle 130µs eine Botschaft, das passt zur Länge einer 
2-Byte Botschaft mit 500kBit.

     Time       Chn     ID    Name   Dir    DLC   Data
     0.000132   CAN 1   200          Rx     2     C4 AA
     0.000130   CAN 1   201          Rx     2     C4 AA
     0.000130   CAN 1   202          Rx     2     C4 AA
     0.000130   CAN 1   203          Rx     2     C4 AA
     0.000130   CAN 1   200          Rx     2     CD AA
     0.000130   CAN 1   201          Rx     2     CD AA
     0.000130   CAN 1   202          Rx     2     CD AA
     0.000130   CAN 1   203          Rx     2     CD AA
     0.000130   CAN 1   200          Rx     2     D3 AA

von Peter (Gast)


Lesenswert?

Ich probiere auch gerade ein Programm mit dem AT90CAN zu schreiben, im 
speziellen geht es darum, dass ich 2 Nachrichten zeitgleich übertrage, 
oder zumindest den Payload zeitgleich übertrage. Das hat denn Sinn, dass 
man dadurch einen Schlüsselausstausch erreichen kann (Plug-and-Secure 
Verfahren von Bosch).
Jedoch frage ich mich jetzt langsam, ob es überhaupt mit dem AT90CAN 
funktionieren kann? Bisher habe ich es mit einem Trigger durch einen 
zusätzlichen Interrupt probiert, sodass beide Seiten zeitgleich eine 
CAN-Nachricht verschicken, anscheinend passiert das aber nicht 
zeitgleich. Die ID ist auch die selbe.
Hat da jemand von euch Erfahrung mit?

von Rudolph (Gast)


Lesenswert?

Zwei MOBs direkt hintereinander zu füllen damit zwei Botschaften direkt 
hintereinander raus gehen ist doch gar kein Problem, wenn man das zum 
Beispiel nur alle 10ms versucht.
Das Problem hier war nur den Bus maximal voll zu bekommen ohne 
Botschaften an die Priorisierung zu verlieren.

von Peter (Gast)


Lesenswert?

Danke schon mal für deine Antwort. Ich meinte aber vielmehr, dass ich 
zwei AT90CANs auf dem CAN Bus habe. Diesen sollen nun zeitgleich jeweils 
eine Nachricht senden und lesen. Es geht vorallem darum, dass der 
Payload zeitgleich auf den Bus geschrieben und gelesen wird. Dadurch 
bekommt man in diesem Schlüsselaustausch das Geheimnis.

von Marc V. (Firma: Vescomp) (logarithmus)


Lesenswert?

Peter schrieb:
> zwei AT90CANs auf dem CAN Bus habe. Diesen sollen nun zeitgleich jeweils
> eine Nachricht senden und lesen. Es geht vorallem darum, dass der

 Das geht natürlich nicht, wenn es gleichzeitig gehen soll.
 Falls beide dasselbe Format haben:
   Die niedrigere ID geht durch.
 Falls nicht:
   CAN Standard geht durch, CAN Extended nicht.

 Wenn du mit zeitgleich die zeitlichen Abstände meinst, dann wird es
 mit der Genauigkeit nicht sehr wit her sein...

: Bearbeitet durch User
von Peter (Gast)


Lesenswert?

Was würde denn theorethisch passieren, wenn beide die selbe ID haben? 
Dann könnte es doch passieren, dass beide anfangen zu senden, weil sie 
denken, sie haben die niedrigste ID?
Ich meinte schon, dass zeitgleiche Versenden und nicht das Senden von 
Nachrichten mit gleichem Abstand hintereinander.

Nur mit einem Transceiver habe ich es bisher schon implementiert. Das 
kann man aber ja leider nicht so direkt auf den Controller übertragen. 
Dort habe ich jeweils die beiden Parteien, die Bits senden lassen und 
dann wenig später den Bus von Beiden lesen lassen.

von Rudolph (Gast)


Lesenswert?

Peter schrieb:
> Was würde denn theorethisch passieren, wenn beide die selbe ID haben?

Dann sendet ganz praktisch erst der eine Controller auf der ID, dann der 
andere.
Du wirst es niemals hinbekommen, dass beide gleichzeitig anfangen zu 
senden, auch nicht mit einer gemeinsamen Trigger-Leitung und ansonsten 
Bus-Ruhe.
Zwei Controller laufen niemals exakt synchron, selbst bei zwei direkt 
nebeneinander die mit einem gemeinsamen Oszillator laufen wird das eher 
nichts.

Und selbst wenn das zufällig doch mal klappen sollte, dann wird es 
CRC-Fehler geben.

von Peter (Gast)


Lesenswert?

Ich habe das ja schon mal auf einem Transceiver gemacht. Da ist mir ja 
schon aufgefallen, dass es niemals komplett synchron war. Es gab immer 
einen Zeitunterschied. Durch den Interrupt und eine Anpassung, wo der 
Sender eine Zeit lang nichts tut (da er schneller ist/war), konnte die 
Übertragung der Bits dann aber doch stattfinden.
Beim Controller kann ich aber aber ja nicht so direkt auf alles 
zugreifen, da er mir ja auch Arbeit abnehmen soll.

von M. Н. (Gast)


Lesenswert?

Peter schrieb:
> Was würde denn theorethisch passieren, wenn beide die selbe ID haben?
> Dann könnte es doch passieren, dass beide anfangen zu senden, weil sie
> denken, sie haben die niedrigste ID?

Die Arbitrierung ist nur während der ID erlaubt. Sollte der Unterschied 
beider Frames während der Datenphase auffallen, ist dies ein Fehler.

Um eine korrekte Operation sicherzustellen, muss sichergestellt sein, 
dass eine ID nur von einem Knoten gesendet wird.

Bei CAN-FD ist das ganze durch den möglichen Bitratenwechsel sowieso so. 
Eine Arbitrierung im schnellen Datenfeld ist durch Laufzeiten auf dem 
Bus sowieso ausgeschlossen.

von Thomas (kosmos)


Lesenswert?

M. H. schrieb:
> Was würde denn theorethisch passieren, wenn beide die selbe ID haben?
>> Dann könnte es doch passieren, dass beide anfangen zu senden, weil sie
>> denken, sie haben die niedrigste ID?

die dominanten Bits würden die rezesiven Bits eben unterdrücken und die 
Checksumme wird dann nicht mehr passen.

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.