Forum: Mikrocontroller und Digitale Elektronik CAN: Timing Probleme


von can (Gast)


Lesenswert?

Hallo,

ich habe ein Steuergerät für ein Rennauto, was CAN spricht. Dieses 
sendet Can IDs 0x2000 bis 0x2005 mit wahlweise 10, 20 oder 50Hz

Diese Daten möchte ich mit einem Arduino Mega 2560 und dem Sparkfun 
CanShield loggen.

Daten werden empfangen, aber die ids 2003 und 2004 kommen deutlich 
langsamer als die restlichen. Laut der Auskunft des Herstellers werden 
alle Daten gleichzeitig versendet, so dass ich einen Fehler bei mir 
vermute.

Hier ist der Code-Schnippsel, wo die Daten gesammelt werden:
1
  Serial.println("searching 2003");
2
  time1 = millis();  
3
  while (!has2003) {
4
    if(CAN_MSGAVAIL == CAN0.checkReceive()) 
5
    {      
6
      CAN0.readMsgBuf(&len, rxBuf);              // Read data: len = data length, buf = data byte(s)
7
      rxId = CAN0.getCanId();                    // Get message ID
8
      
9
      if (rxId == 0x2003) {
10
        for (int i = 0; i < len; i++)
11
        {
12
          if (rxBuf[i] < 0x10)
13
          {
14
            data2003 = data2003 + "0";
15
          }
16
          data2003 = data2003 + rxBuf[i];
17
          data2003 = data2003 + " ";
18
        }
19
                
20
        has2003 = true;
21
        updateLCD();
22
        break;
23
      }
24
    }
25
    delay(10);
26
  }
27
  time2 = millis();
28
  timeTotal = time2-time1;
29
  Serial.print("search 2003 took ");
30
  Serial.print(timeTotal);
31
  Serial.println(" ms");
32
  
33
  Serial.println("searching 2004");
34
  time1 = millis();  
35
  while (!has2004) {
36
    if(CAN_MSGAVAIL == CAN0.checkReceive()) 
37
    {      
38
      CAN0.readMsgBuf(&len, rxBuf);              // Read data: len = data length, buf = data byte(s)
39
      rxId = CAN0.getCanId();                    // Get message ID      
40
      if (rxId == 0x2004) {                       
41
        has2004 = true;
42
        break;
43
      }
44
    }
45
    delay(10);
46
  }  
47
  time2 = millis();
48
  timeTotal = time2-time1;
49
  Serial.print("search 2004 took ");
50
  Serial.print(timeTotal);
51
  Serial.println(" ms");
52
  
53
  
54
  Serial.println("searching 2005");
55
  time1 = millis();  
56
  while (!has2005) {
57
    if(CAN_MSGAVAIL == CAN0.checkReceive()) 
58
    {      
59
      CAN0.readMsgBuf(&len, rxBuf);              // Read data: len = data length, buf = data byte(s)
60
      rxId = CAN0.getCanId();                    // Get message ID      
61
      if (rxId == 0x2005) {                       
62
        has2005 = true;
63
        break;
64
      }
65
    }
66
    delay(10);
67
  }  
68
  time2 = millis();
69
  timeTotal = time2-time1;
70
  Serial.print("search 2005 took ");
71
  Serial.print(timeTotal);
72
  Serial.println(" ms");  
73
  
74
  Serial.println("searching 2000");  
75
  time1 = millis();
76
  while (!has2000) {
77
    if(CAN_MSGAVAIL == CAN0.checkReceive()) 
78
    {          
79
      CAN0.readMsgBuf(&len, rxBuf);              // Read data: len = data length, buf = data byte(s)
80
      rxId = CAN0.getCanId();                    // Get message ID
81
      
82
      if (rxId == 0x2000) {
83
        for (int i = 0; i < len; i++)
84
        {
85
          if (rxBuf[i] < 0x10)
86
          {
87
            data2000 = data2000 + "0";
88
          }
89
          data2000 = data2000 + rxBuf[i];
90
          data2000 = data2000 + " ";
91
        }
92
        has2000 = true;
93
        updateLCD();
94
        break;
95
      }
96
    }
97
    delay(10);
98
  }  
99
  time2 = millis();
100
  timeTotal = time2-time1;
101
  Serial.print("search 2000 took ");
102
  Serial.print(timeTotal);
103
  Serial.println(" ms");
104
  
105
  Serial.println("searching 2001");    
106
  time1 = millis();  
107
  while (!has2001) {        
108
    if(CAN_MSGAVAIL == CAN0.checkReceive()) 
109
    {          
110
      CAN0.readMsgBuf(&len, rxBuf);              // Read data: len = data length, buf = data byte(s)
111
      rxId = CAN0.getCanId();                    // Get message ID
112
      
113
      if (rxId == 0x2001) {
114
        for (int i = 0; i < len; i++)
115
        {
116
          if (rxBuf[i] < 0x10)
117
          {
118
            data2001 = data2001 + "0";
119
          }
120
          data2001 = data2001 + rxBuf[i];
121
          data2001 = data2001 + " ";
122
        }
123
        has2001 = true;
124
        updateLCD();
125
        break;
126
      }
127
    }
128
    delay(10);
129
  }   
130
  
131
  time2 = millis();
132
  timeTotal = time2-time1;
133
  Serial.print("search 2000 took ");
134
  Serial.print(timeTotal);
135
  Serial.println(" ms");

Die Ausgabe dazu sieht wie folgt aus:
1
searching 2003
2
search 2003 took 59 ms
3
searching 2004
4
search 2004 took 906 ms
5
searching 2005
6
search 2005 took 2 ms
7
searching 2000
8
search 2000 took 15 ms
9
searching 2001
10
search 2000 took 14 ms
11
parsing CAN data took 6 ms
12
parse gps took 6 ms
13
save data took 0 ms
14
searching 2003
15
search 2003 took 272 ms
16
searching 2004
17
search 2004 took 2626 ms
18
searching 2005
19
search 2005 took 2 ms
20
searching 2000
21
search 2000 took 26 ms
22
searching 2001
23
search 2000 took 37 ms
24
parsing CAN data took 6 ms
25
parse gps took 6 ms
26
save data took 0 ms
27
searching 2003
28
search 2003 took 719 ms
29
searching 2004
30
search 2004 took 526 ms
31
searching 2005
32
search 2005 took 1 ms
33
searching 2000
34
search 2000 took 26 ms
35
searching 2001
36
search 2000 took 37 ms
37
parsing CAN data took 6 ms
38
parse gps took 6 ms
39
save data took 0 ms
40
searching 2003
41
search 2003 took 339 ms
42
searching 2004
43
search 2004 took 906 ms
44
searching 2005
45
search 2005 took 1 ms
46
searching 2000
47
search 2000 took 26 ms
48
searching 2001
49
search 2000 took 37 ms
50
parsing CAN data took 7 ms
51
parse gps took 7 ms
52
save data took 0 ms
53
searching 2003
54
search 2003 took 339 ms
55
searching 2004
56
search 2004 took 905 ms
57
searching 2005
58
search 2005 took 1 ms

Jemand eine Idee, was ich falsch mache, bzw wie man das Problem lösen 
kann?

Danke

von Rudolph R. (rudolph)


Lesenswert?

Keine Idee was der Code macht, Arduino Lib und so und keinen Bock drauf 
zu schauen. ;-)
Na okay, habs überflogen, sieht seltsam aus.

Aber, CAN-Botschaften kommen nicht "gleichzeitig" sondern nacheinander.
Wenn Botschaften verloren gehen kann das nur daher kommen, dass die 
direkt nacheinander gesendet werden und mit nur einer Message-Box 
empfangen werden sollen, diese Message-Box aber nicht schnell genug 
wieder geleert wird.
Wenn Du nur sechs Botschaften empfangen willst wären sechs Message-Boxen 
dafür optimal.

Der dusslige MCP52irgendwas SPI-CAN Chip auf dem Shield hat aber glaube 
ich nur fünf Message-Boxen, hab mich mit dem Ding aber nie ernsthaft 
beschäftigt.

Wenn man nicht jeder Botschaft eine eigene Message-Box spendieren kann 
könnte es helfen zwei Message-Boxen zu benutzen, eine für die 
Botschaften mit gerade ID, einer für die Botschaften mit ungerader ID.

Und der SPI muss dann auch schnell genug sein um die Message-Box wieder 
frei zu machen.

von can (Gast)


Lesenswert?

Sowas in der Art habe ich vermutet. Ich habe gesehen, dass die 
Arduino-Lib einen Filter bietet. Habe ich ausprobiert:


CAN0.init_Filt (2,1,0x2000);


Es werden trotzdem noch alle IDs empfangen. Ich hätte erwartet, dass nun 
nur 2000 ankommt - in dem Fall hätte ich den Filter nacheinander 
angepasst, bis alle gesuchten IDs empfangen wären. Das würde mein 
Problem vermutlich lösen?

von Lutz (Gast)


Lesenswert?

Ohne den vollständigen Code der ganzen Funktionen und defines wird dir 
da wohl keiner helfen können.

von Rudolph R. (rudolph)


Lesenswert?

Du machst den Fehler, dass Du auf die Botschaften wartest und zwar in 
einer festgelegten Reihenfolge.

Geschickter ist es, auf den Eingang einer Botschaft zu reagieren, 
festzustellen um welche es sich handelt und entsprechend den Inhalt zu 
speichern.
1
    if(CAN_MSGAVAIL == CAN0.checkReceive()) 
2
    {      
3
      CAN0.readMsgBuf(&len, rxBuf);              // Read data: len = data length, buf = data byte(s)
4
      rxId = CAN0.getCanId();                    // Get message ID
5
      
6
      if (rxId == 0x2000)
7
      {
8
      }
9
      else if (rxId == 0x2001)
10
      {
11
      }
12
      else if (rxId == 0x2002)
13
      {
14
      }

Die ganzen "Serial.println" Zeilen kosten übrigens Zeit ohne Ende weil 
die Funktion erst zurück kommt wenn der Text gesendet ist.
Für "updateLCD();" gilt wahrscheinlich das gleiche.
Der Controller ist wahrscheinlich die meiste Zeit damit beschäftigt gar 
nichts zu tun und verpasst alleine in dieser Zeit schon einen Teil der 
Botschaften.

Statt mit CAN0.checkReceive() zu pollen sollte das ganze besser in einen 
Interrupt, der CAN-Controller hat auch einen Ausgang dafür der auf dem 
Shield passend verdrahtet sein sollte.

von can (Gast)


Lesenswert?

Den Ansatz mit einer Prüfmethode habe ich auch schon ausprobiert. In dem 
Fall bekomme ich die 2003 noch seltener bis gar nicht mit.

Weisst du auf welchem Pin der Interrupt liegt?

von Rudolph R. (rudolph)


Lesenswert?

Dazu müsste man erstmal wissen, welches Shield genau.

Google hat mich gerade zu dem hier geführt:
https://www.sparkfun.com/datasheets/DevTools/Arduino/canbus_shield-v12.pdf

Und da wäre das dann D2.

Ich benutze aber weder den MCP2515 noch einen Arduino wenn ich nicht 
muss.
Und besonders der Arduino Mega ist eine elektrische Katastrophe, 
zumindest das Original.

Wie schnell lässt Du eigentlich den SPI laufen?

von Wolfgang (Gast)


Lesenswert?

Rudolph R. schrieb:
> Die ganzen "Serial.println" Zeilen kosten übrigens Zeit ohne Ende weil
> die Funktion erst zurück kommt wenn der Text gesendet ist.
> Für "updateLCD();" gilt wahrscheinlich das gleiche.

Rätsel über Rätsel. Wer weiß schon, wie schnell die serielle 
Schnittstelle läuft, ob die Ausgabe blockierend ist und wie lange das 
updateLCD() dn Prozessor blockiert?

Und ob ein delay(10) in einer Schleife, in der man eigentliche alles 
mitkriegen möchte, so förderlich ist, sei mal dahin gestellt ;-)

von can (Gast)


Lesenswert?

Ich benutze dieses Shield:

https://www.sparkfun.com/products/10039


Baudraten:
  // debug
  Serial.begin(115200);
  // gps
  Serial1.begin(9600);
  // lcd
  Serial2.begin(9600);

Der Mega ist von SainSmart - ich weiß nicht, ob der anders als der 
originale ist

von Rudolph R. (rudolph)


Lesenswert?

can schrieb:
> Der Mega ist von SainSmart - ich weiß nicht, ob der anders als der
> originale ist

Nein, der ist nach dem Referenz-Design und damit ebenfalls Müll.
Wenn man den Schaltplan hier posten würde mit dem Layout mit Bitte um 
Bewertung würde einem das Ding um die Ohren gehauen werden.

Aber das Ding läuft trotzdem irgendwie, das ist nicht Dein Problem.

von can (Gast)


Lesenswert?

Mit Interrupt dann wohl so?
1
  pinMode(2, OUTPUT);
2
  attachInterrupt(0, blink, CHANGE);
3
4
...
5
6
7
void blink() {
8
  intterruptFlag = true;
9
}
10
11
...
12
13
14
void loop() {
15
  if(intterruptFlag) {
16
    if(CAN_MSGAVAIL == CAN0.checkReceive()) 
17
    {
18
      CAN0.readMsgBuf(&len, rxBuf);              // Read data: len = data length, buf = data byte(s)
19
      rxId = CAN0.getCanId();                    // Get message ID
20
      
21
      Serial.print("id: ");
22
      Serial.println(rxId, HEX);
23
    } 
24
    intterruptFlag = false;   
25
  }
26
27
...
28
}

von Rudolph R. (rudolph)


Lesenswert?

Das könnte funktionieren, bei 115200 auf der Seriellen Schnittstelle 
müsste das eine Verzögerung von etwa 0,7ms sein.

Aber, noch geschickter wäre es, die Daten im Interrupt auch abzuholen 
damit
der CAN-Controller so schnell wie möglich wieder bereit ist, Daten 
anzunehmen.

Denn wenn in der loop() noch was dazu kommt, hast Du wieder das gleiche 
Problem.

Was auch passieren kann ist das während des Sendens auf der Seriellen 
Schnittstelle die nächste Botschaft ankommt.
Wenn das Flag dann erst danach gelöscht wird geht diese Botschaft 
verloren.
Also so wie das da steht sollte nach dem Erkennen des Flags dieses 
gleich gelöscht werden um das nächste Setzen nicht zu verpassen.

von can (Gast)


Lesenswert?

Danke schön!

Ich teste das und gebe Feedback

von can (Gast)


Lesenswert?

So ich habe es getestet, komischerweise wird die Interrupt-Methode nur 
einmal angesprungen, danach nicht mehr. Habe ich noch einen Denkfehler?

1
#include <mcp_can.h>
2
#include <SPI.h>
3
4
long unsigned int rxId;
5
unsigned char len = 0;
6
unsigned char rxBuf[8];
7
8
MCP_CAN CAN0(10);                               // Set CS to pin 10
9
10
boolean intterruptFlag;
11
12
13
void setup()
14
{
15
  delay(1000);
16
17
  Serial.begin(115200);
18
19
  int canStatus = CAN0.begin(CAN_1000KBPS);
20
  if (canStatus != 0) {
21
    Serial.println("Can init failed!");
22
  }
23
  else {
24
    Serial.println("Can init ok!");
25
  }
26
27
  attachInterrupt(0, blink, CHANGE);
28
}
29
30
void blink() {
31
  Serial.println("interrupt...");
32
  
33
  if(CAN_MSGAVAIL == CAN0.checkReceive()) 
34
  {
35
    CAN0.readMsgBuf(&len, rxBuf);              // Read data: len = data length, buf = data byte(s)
36
    rxId = CAN0.getCanId();                    // Get message ID
37
    
38
    Serial.print("id: ");
39
    Serial.println(rxId, HEX);
40
  } 
41
}
42
43
void loop()
44
{  
45
  Serial.print(".");  
46
}

von can (Gast)


Lesenswert?

Sorry, falsch. Interrupt wird genau 2 mal angesprungen, dann ist Ende.


Can init ok!
interrupt...
id: 2000
interrupt...
id: 2000

von can (Gast)


Lesenswert?

Gelöst: Pin bleibt auf LOW wenn nicht alle Nachrichten abgerufen wurden.

if(CAN_MSGAVAIL == CAN0.checkReceive())  --> while(CAN_MSGAVAIL == 
CAN0.checkReceive())

und es geht

von can (Gast)


Lesenswert?

Mit der oberen Version werden aber weiterhin Nachrichten verschluckt. 
Jemand eine Idee...?

von Rudolph R. (rudolph)


Lesenswert?

Also zumindest Serial.print() und Serial.println() haben im Interrupt 
nichts verloren.
Während das Serial.println() noch läuft sind schon drei Botschaften über 
den Bus gegangen von denen zwei verschluckt wurden.

von can (Gast)


Lesenswert?

Das habe ich mir auch schon gedacht und deswegen schon mal das hier 
getestet:
1
#include <mcp_can.h>
2
#include <SPI.h>
3
4
long unsigned int rxId;
5
unsigned char len = 0;
6
unsigned char rxBuf[8];
7
8
boolean interruptFlag = false;
9
10
MCP_CAN CAN0(10);                               // Set CS to pin 10
11
12
void setup()
13
{
14
  delay(1000);
15
16
  Serial.begin(115200);
17
18
  int canStatus = CAN0.begin(CAN_1000KBPS);
19
  if (canStatus != 0) {
20
    Serial.println("Can init failed!");
21
  }
22
  else {
23
    Serial.println("Can init ok!");
24
  }
25
26
  attachInterrupt(0, blink, CHANGE);
27
}
28
29
void blink() {  
30
  interruptFlag = true;
31
}
32
33
void loop()
34
{  
35
  if(interruptFlag) {
36
    while(CAN_MSGAVAIL == CAN0.checkReceive())
37
    {
38
      CAN0.readMsgBuf(&len, rxBuf);        
39
      rxId = CAN0.getCanId();                    // Get message ID      
40
      Serial.print("id: ");
41
      Serial.println(rxId, HEX);                  
42
    }
43
    interruptFlag = false;
44
  }
45
}

Ausgabe:
id: 2000
id: 2000
id: 2002
id: 2005
id: 2001
id: 2000
id: 2002
id: 2005
id: 2001
id: 2000
id: 2002
id: 2005
id: 2001
id: 2000
id: 2002
id: 2005
id: 2001
id: 2000
id: 2002
id: 2005
id: 2001
id: 2000
id: 2001
id: 2000
id: 2002
id: 2005
id: 2001
id: 2000
id: 2002
id: 2005
id: 2001
id: 2000
id: 2002
id: 2005
id: 2001
id: 2000
id: 2002

Man erkennt in der Ausgabe eine Regelmäßigkeit. Es fehlen immernoch die 
2003 und die 2004.
Ich habe gelesen, dass es Möglichkeiten gibt, mit Filtern auf bestimmte 
IDs zu hören. Ich vermute, dass es die Lösung für mich wäre, aber ich 
kriege den Filter ebenfalls nicht ans Laufen.

Hier steht was darüber, aber ich werde aus den Beiträgen nicht schlau. 
Wie muss ich den Filter und Masken setzen, um nur 2003 zu bekommen?
http://forum.arduino.cc/index.php?topic=156069.0

von Bestromer (Gast)


Lesenswert?

can schrieb:
> Ich vermute, dass es die Lösung für mich wäre, aber ich
> kriege den Filter ebenfalls nicht ans Laufen.

....wie es beim Arduino mit seiner merkwürdigen Programmierung umgesetzt 
wird kann ich Dir nicht sagen, allerdings müssen bei den Masken alle 
Bits gesetzt sein, es sei denn Du möchtest eine gewisse Range an IDs 
durchlassen.
Das kannst Du Dir so wie bei den Netzwerkadressen und den Subnetmasken 
im Ethernet vorstellen, wenn Dir das etwas sagt...
Ansonsten hast Du halt insgesamt 6 Filter die Du setzen kannst.
Ich weis nicht wie das bei Deinem Arduino ist, aber Du musst in der 
Konfiguration garantiert den Empfangsmodus noch einstellen!?
Dieser wird durch die RXM-Bits gesetzt:

11-alle IDs werden empfangen /Filter deaktiviert
10-nur standard-IDs laut Filterkriterien
01-nur extended-IDs laut Filterkriterien
00-standard und extended-IDs laut filterkriterien

....wobei der Modus 00 bei standard-IDs das erste und zweite Datenbyte 
zum Filtervergleich mit heranzieht.
Diesen Modus nutzt man also eigentlich nur in gewissen 
Protokollvarianten....

von can (Gast)


Lesenswert?

Ich habe hier ein Beispiel gefunden:

http://www.hobbytronics.co.uk/download/leonardo-canbus/test_receive_filter.ino
1
   // *********************************************************  
2
   // Basic Filtering on ID
3
   // *********************************************************    
4
   // Bytes 1 and 2 of mask/filter apply to ID
5
   // So the Mask and filter below will only allow ID 0x00 through
6
   //                                     ---- ID ----- 
7
   CAN0.init_Mask(0, 0, 0xFFFF); // 1111 1111 1111 1111   
8
   CAN0.init_Filt(0, 0, 0x0001); // 0000 0000 0000 0001 - FAIL
9
   CAN0.init_Filt(1, 0, 0x0001); // 0000 0000 0000 0001 - FAIL  
10
   CAN0.init_Mask(1, 0, 0xFFFF); // 1111 1111 1111 1111
11
   CAN0.init_Filt(2, 0, 0x0001); // 0000 0000 0000 0001 - FAIL
12
   CAN0.init_Filt(3, 0, 0x0001); // 0000 0000 0000 0001 - FAIL
13
   CAN0.init_Filt(4, 0, 0x0000); // 0000 0000 0000 0000 - ACCEPT
14
   CAN0.init_Filt(5, 0, 0x0001); // 0000 0000 0000 0001 - FAIL

Wie müsste man jetzt die Maske und Filter setzen, um nur 0x2003 (0010 
0000 0000 0011) zu bekommen?

von Rudolph R. (rudolph)


Lesenswert?

can schrieb:
> Das habe ich mir auch schon gedacht und deswegen schon mal das hier
> getestet:

Und das ist exakt genau so verkehrt.
Im Interrupt die Daten lesen, die Ausgabe in der Hauptschleife...

von can (Gast)


Lesenswert?

Rudolph R. schrieb:
> Und das ist exakt genau so verkehrt.
> Im Interrupt die Daten lesen, die Ausgabe in der Hauptschleife...

Hatte das hier getestet
1
#include <mcp_can.h>
2
#include <SPI.h>
3
4
long unsigned int rxId;
5
unsigned char len = 0;
6
unsigned char rxBuf[8];
7
8
boolean interruptFlag = false;
9
10
boolean has2000;
11
boolean has2001;
12
boolean has2003;
13
14
MCP_CAN CAN0(10);                               // Set CS to pin 10
15
16
void setup()
17
{
18
  delay(1000);
19
20
  Serial.begin(115200);
21
22
  int canStatus = CAN0.begin(CAN_1000KBPS);
23
  if (canStatus != 0) {
24
    Serial.println("Can init failed!");
25
  }
26
  else {
27
    Serial.println("Can init ok!");
28
  }
29
30
  attachInterrupt(0, blink, CHANGE);
31
}
32
33
void blink() {  
34
    while(CAN_MSGAVAIL == CAN0.checkReceive())
35
    {
36
      CAN0.readMsgBuf(&len, rxBuf);        
37
      rxId = CAN0.getCanId();                    // Get message ID      
38
      if(rxId == 0x2000) has2000 = true;
39
      if(rxId == 0x2001) has2001 = true;
40
      if(rxId == 0x2003) has2003 = true;      
41
    }
42
}
43
44
void loop()
45
{  
46
  if(has2000) {
47
    Serial.println("2000 ok");
48
  }
49
  if(has2001) {
50
    Serial.println("2001 ok");
51
  }
52
  if(has2003) {
53
    Serial.println("2003 ok");
54
  }  
55
}

Leider nur mit folgender Ausgabe:
1
Can init ok!
2
2000 ok
3
2000 ok
4
2000 ok
5
2000 ok
6
2000 ok
7
2000 ok
8
2000 ok
9
2000 ok
10
2000 ok
11
2000 ok
12
2000 ok
13
2000 ok
14
2000 ok
15
2001 ok
16
2000 ok
17
2001 ok
18
2000 ok
19
2001 ok
20
2000 ok
21
2001 ok
22
2000 ok
23
2001 ok
24
2000 ok
25
2001 ok
26
2000 ok
27
2001 ok
28
2000 ok
29
2001 ok
30
2000 ok
31
2001 ok
32
2000 ok
33
2001 ok
34
2000 ok
35
2001 ok
36
2000 ok
37
2001 ok
38
2000 ok
39
2001 ok
40
2000 ok
41
2001 ok

Also 2003 fehlt immernoch. Ich verstehe das Filterprinzip nicht ganz.
Laut Datenblatt Seite 32, müsste ich doch den Filter auf die ID setzen, 
die ich auch empfangen will. Also so?

   CAN0.init_Mask(0, 0, 0xFFFF);
   CAN0.init_Filt(0, 0, 0x2003);

Warum sind in meinem letzten Beitrag da Zeilen mit "fail" markiert?

von Bestromer (Gast)


Lesenswert?

can schrieb:
> Ich verstehe das Filterprinzip nicht ganz.
> Laut Datenblatt Seite 32, müsste ich doch den Filter auf die ID setzen,
> die ich auch empfangen will.

So ist es, dazu die Maskenbits alle setzen....

can schrieb:
> Also so?
>
>    CAN0.init_Mask(0, 0, 0xFFFF);
>    CAN0.init_Filt(0, 0, 0x2003);

Ob die Werte so stimmen weis nur Deine verwendete Library....ich 
programmiere in Assembler, da schreibe ich direkt in die jeweiligen 
Register des MCP2515.

Es gibt zwei Empfangspuffer RXB0 und RXB1,dabei hat RXB0 zwei 
Filter(0,1) und eine Maske(0)....entsprechend hat RXB1 die restlichen 
Filter(2-5) und die andere Maske(1).
Diese zwei Empfangspuffer haben jeweils ein Register zur Konfiguration 
(RXB0CTRL,RXB1CTRL).

Jetzt brauchst Du nur den Empfangsmodus einzustellen,eine zu filternde 
ID einzutragen und die Maske auf 0xFFFF zu stellen....funktioniert 
eigentlich ohne Probleme, wie das bei Deiner Library umgesetzt wird und 
welche Übergabewerte erwartet werden kann ich Dir nicht sagen....

von Peter P. (Gast)


Lesenswert?

Wenn ich die Doku unter

http://www.86duino.com/?p=8020

richtig verstehe, brauchst du etwas in der folgenden Art:
(um nur die CAN ID 0x2003 zu empfangen)

CAN0.init_Filt(0, CAN_EXTID, 0x00002003);
CAN0.init_Mask(0, CAN_EXTID, 0x00000000);

Beachte:
0x2003 (10 0000 0000 0011) braucht mehr wie 11 Bit,
daher werden Extended CAN IDs benutzt. Diese sind dann 29 Bit lang.

von can (Gast)


Lesenswert?

Hab´s so ausprobiert, kommen immernoch "alle" ids. Hier ist der Inhalt 
der Methode aus der Lib. Kannst du einschätzen, ob die das macht, was 
die machen soll?

1
INT8U MCP_CAN::init_Filt(INT8U num, INT8U ext, INT32U ulData)
2
{
3
    INT8U res = MCP2515_OK;
4
#if DEBUG_MODE
5
    Serial.print("Begin to set Filter!!\r\n");
6
#endif
7
    res = mcp2515_setCANCTRL_Mode(MODE_CONFIG);
8
    if(res > 0)
9
    {
10
#if DEBUG_MODE
11
      Serial.print("Enter setting mode fall\r\n"); 
12
#endif
13
      return res;
14
    }
15
    
16
    switch( num )
17
    {
18
        case 0:
19
        mcp2515_write_id(MCP_RXF0SIDH, ext, ulData);
20
        break;
21
22
        case 1:
23
        mcp2515_write_id(MCP_RXF1SIDH, ext, ulData);
24
        break;
25
26
        case 2:
27
        mcp2515_write_id(MCP_RXF2SIDH, ext, ulData);
28
        break;
29
30
        case 3:
31
        mcp2515_write_id(MCP_RXF3SIDH, ext, ulData);
32
        break;
33
34
        case 4:
35
        mcp2515_write_id(MCP_RXF4SIDH, ext, ulData);
36
        break;
37
38
        case 5:
39
        mcp2515_write_id(MCP_RXF5SIDH, ext, ulData);
40
        break;
41
42
        default:
43
        res = MCP2515_FAIL;
44
    }
45
    
46
    res = mcp2515_setCANCTRL_Mode(MODE_NORMAL);
47
    if(res > 0)
48
    {
49
#if DEBUG_MODE
50
      Serial.print("Enter normal mode fall\r\nSet filter fail!!\r\n"); 
51
#endif
52
      return res;
53
    }
54
#if DEBUG_MODE
55
    Serial.print("set Filter success!!\r\n");
56
#endif
57
    
58
    return res;
59
}

von Bestromer (Gast)


Lesenswert?

can schrieb:
> // *********************************************************
>    // Basic Filtering on ID
>    // *********************************************************
>    // Bytes 1 and 2 of mask/filter apply to ID
>    // So the Mask and filter below will only allow ID 0x00 through
>    //                                     ---- ID -----
>    CAN0.init_Mask(0, 0, 0xFFFF); // 1111 1111 1111 1111
>    CAN0.init_Filt(0, 0, 0x0001); // 0000 0000 0000 0001 - FAIL
>    CAN0.init_Filt(1, 0, 0x0001); // 0000 0000 0000 0001 - FAIL
>    CAN0.init_Mask(1, 0, 0xFFFF); // 1111 1111 1111 1111
>    CAN0.init_Filt(2, 0, 0x0001); // 0000 0000 0000 0001 - FAIL
>    CAN0.init_Filt(3, 0, 0x0001); // 0000 0000 0000 0001 - FAIL
>    CAN0.init_Filt(4, 0, 0x0000); // 0000 0000 0000 0000 - ACCEPT
>    CAN0.init_Filt(5, 0, 0x0001); // 0000 0000 0000 0001 - FAIL

...man kann hier schon erkennen, das die Hardware 1:1 abgebildet wird.
    Das wäre also RXB0:
    CAN0.init_Mask(0, 0, 0xFFFF); // 1111 1111 1111 1111
    CAN0.init_Filt(0, 0, 0x0001); // 0000 0000 0000 0001 - FAIL
    CAN0.init_Filt(1, 0, 0x0001); // 0000 0000 0000 0001 - FAIL

    Dies entsprechend RXB1
    CAN0.init_Mask(1, 0, 0xFFFF); // 1111 1111 1111 1111
    CAN0.init_Filt(2, 0, 0x0001); // 0000 0000 0000 0001 - FAIL
    CAN0.init_Filt(3, 0, 0x0001); // 0000 0000 0000 0001 - FAIL
    CAN0.init_Filt(4, 0, 0x0000); // 0000 0000 0000 0000 - ACCEPT
    CAN0.init_Filt(5, 0, 0x0001); // 0000 0000 0000 0001 - FAIL

....allerdings ist die Bitlänge etwas kurz, eine Extended-ID so wie Du 
sie nutzt belegt 29 Bit und eine Standard-ID 11Bit,so das es den 
Anschein macht als wäre hier nur die Übergabe von Standard-IDs 
möglich....

von Bestromer (Gast)


Lesenswert?

Peter P. schrieb:
> Wenn ich die Doku unter
>
> http://www.86duino.com/?p=8020
>
> richtig verstehe, brauchst du etwas in der folgenden Art:
> (um nur die CAN ID 0x2003 zu empfangen)
>
> CAN0.init_Filt(0, CAN_EXTID, 0x00002003);
> CAN0.init_Mask(0, CAN_EXTID, 0x00000000);
>
> Beachte:
> 0x2003 (10 0000 0000 0011) braucht mehr wie 11 Bit,
> daher werden Extended CAN IDs benutzt. Diese sind dann 29 Bit lang.

Peter war schneller und hat auch gleich eine Lösung im Gepäck :)

von can (Gast)


Lesenswert?

Danke euch, ich teste bzw lasse testen - das Auto ist nicht bei mir und 
der Kumpel flasht auf Anweisung und testet. Alles nicht so einfach ;)

von Programmierer (Gast)


Lesenswert?

Rennauto? Formula Student? Lasst euch von Vector CAN Debugger und Logger 
und Software gratis sponsorn, damit kann man so etwas hervorragend 
debuggen. Wenn's schnell gehen soll bei einem der 1000 anderen Teams, 
die vom Vector gesponsert werden, leihen ;-)

von can (Gast)


Lesenswert?

Nene, das ist "Privatspass". Caterham mit einem DTA S40 Steuergerät

von can (Gast)


Lesenswert?

Also ausprobiert, kommt immernoch "alles"
1
#include <mcp_can.h>
2
#include <SPI.h>
3
4
long unsigned int rxId;
5
unsigned char len = 0;
6
unsigned char rxBuf[8];
7
8
volatile boolean interruptFlag = false;
9
10
boolean has2000;
11
boolean has2001;
12
boolean has2003;
13
14
MCP_CAN CAN0(10);                               // Set CS to pin 10
15
16
void setup()
17
{
18
  delay(1000);
19
20
  Serial.begin(115200);
21
22
  int canStatus = CAN0.begin(CAN_1000KBPS);
23
  if (canStatus != 0) {
24
    Serial.println("Can init failed!");
25
  }
26
  else {
27
    Serial.println("Can init ok!");
28
  }
29
30
  attachInterrupt(0, blink, CHANGE);
31
  
32
  // 0010 0000 0000 0000
33
34
  CAN0.init_Filt(0, CAN_EXTID, 0x00002000);
35
  CAN0.init_Mask(0, CAN_EXTID, 0x00000000);  
36
     
37
}
38
39
void blink() {  
40
    while(CAN_MSGAVAIL == CAN0.checkReceive())
41
    {
42
      CAN0.readMsgBuf(&len, rxBuf);        
43
      rxId = CAN0.getCanId();                    // Get message ID      
44
      
45
      Serial.println(rxId, HEX);
46
          
47
    }
48
}
49
50
void loop()
51
{  
52
53
}

Auch probehalber Maske auf 0xFFFFFFFF gesetzt - laut 
http://www.hobbytronics.co.uk/datasheets/MCP2515.pdf wird Filter 
ausgewertet, wenn MaskBit auf 1 ist.

Und nu?

von Bestromer (Gast)


Lesenswert?

can schrieb:
> CAN0.init_Mask(0, CAN_EXTID, 0x00000000);

...wie war das mit der Maske ;-)

versuch es doch mal mit...

CAN0.init_Mask(0, CAN_EXTID, 0xffffffff)

von Bestromer (Gast)


Lesenswert?

can schrieb:
> Auch probehalber Maske auf 0xFFFFFFFF gesetzt - laut

...ok...war zu schnell..

von Bestromer (Gast)


Lesenswert?

...setze mal die zweite Maske auch auf 0xffffffff, sonst lässt der 
zweite Empfangspuffer alles durch....dann sollte es gehen!?

Also CAN0.init_Mask(0, CAN_EXTID, 0xffffffff)
     CAN0.init_Mask(1, CAN_EXTID, 0xffffffff)

von Thomas (kosmos)


Lesenswert?

Rudolph R. schrieb:
> can schrieb:
>> Der Mega ist von SainSmart - ich weiß nicht, ob der anders als der
>> originale ist
>
> Nein, der ist nach dem Referenz-Design und damit ebenfalls Müll.
> Wenn man den Schaltplan hier posten würde mit dem Layout mit Bitte um
> Bewertung würde einem das Ding um die Ohren gehauen werden.
>
> Aber das Ding läuft trotzdem irgendwie, das ist nicht Dein Problem.

Darf man fragen was am Schaltplan bzw. Layout nicht so gut ist? Habe 
auch einen SainSmart Megaboard für schnelle Versuche hier, hatte bisher 
aber noch keine Probleme damit.

von Bestromer (Gast)


Lesenswert?

Thomas O. schrieb:
> Darf man fragen was am Schaltplan bzw. Layout nicht so gut ist? Habe
> auch einen SainSmart Megaboard für schnelle Versuche hier, hatte bisher
> aber noch keine Probleme damit.



...solange alles funktioniert ist doch alles prima, ich kenne die 
Arduino-Geschichte nicht, wahrscheinlich wird es bezüglich 
Stromversorgung, Abschirmung und Portbeschaltung bessere Möglichkeiten 
geben, aber für den Preis z.B. von SainSmart kann man für den Einstieg 
wirklich nix falsch machen.....ausserdem ist ein grosser Markt an 
Zusatzplatinen entstanden (man kann schon fast von einem Hype 
sprechen),was doch für sich spricht ;-)

von Peter P. (Gast)


Lesenswert?

Ich habe mal nach mcp2515_write_id suchen lassen.
Kommt z.B. auf

https://github.com/dergraaf/avr-can-lib/blob/master/src/mcp2515_write_id.c

Dort gibt es eine Pre-Prozessor Define SUPPORT_EXTENDED_CANID.
Ist diese bei dir auch vorhanden und auch gesetzt?

Bzw. wie sieht bei dir die mcp2515_write_id aus bzw.
wo stammt sie her?

von can (Gast)


Lesenswert?

Peter:

Ich nutze diese Lib
https://github.com/reeedstudio/CAN_BUS_Shield

Die Version mit dem gesetzter zweiten Maske lasse ich testen

von Rudolph R. (rudolph)


Lesenswert?

Thomas O. schrieb:
> Darf man fragen was am Schaltplan bzw. Layout nicht so gut ist?

Darf man, das ist hier aber schon oft genug durchgekaut.
Einfach mal im Layout ansehen, wo die 5V hin gehen.

von Bestromer (Gast)


Lesenswert?

can schrieb:
> Die Version mit dem gesetzter zweiten Maske lasse ich testen

....es sind je nach Konfiguration zwei getrennt arbeitende 
Empfangspuffer,
wenn der zweite eine genullte Maske hat, dann lässt er natürlich jede ID 
durch....damit hast du einen Bypass gebastelt :)

von can (Gast)


Lesenswert?

Die Masken / Filter scheinen nun zu greifen, allerdings kommt nun gar 
keine Ausgabe mehr.
1
#include <mcp_can.h>
2
#include <SPI.h>
3
4
long unsigned int rxId;
5
unsigned char len = 0;
6
unsigned char rxBuf[8];
7
8
MCP_CAN CAN0(10);                               // Set CS to pin 10
9
10
void setup()
11
{
12
  delay(1000);
13
  Serial.begin(115200);
14
15
  int canStatus = CAN0.begin(CAN_1000KBPS);
16
  if (canStatus != 0) {
17
    Serial.println("Can init failed!");
18
  }
19
  else {
20
    Serial.println("Can init ok!");
21
  }
22
23
  CAN0.init_Mask(0, CAN_EXTID, 0xFFFFFFFF); // 1111 1111 1111 1111 
24
  CAN0.init_Filt(0, CAN_EXTID, 0x00002001); // 0000 0000 0000 0001 - FAIL
25
  CAN0.init_Mask(1, CAN_EXTID, 0xFFFFFFFF); // 1111 1111 1111 1111
26
  CAN0.init_Filt(2, CAN_EXTID, 0x00002001); // 0000 0000 0000 0001 - FAIL
27
28
  attachInterrupt(0, blink, CHANGE);
29
}
30
31
void blink() {  
32
    while(CAN_MSGAVAIL == CAN0.checkReceive())
33
    {
34
      CAN0.readMsgBuf(&len, rxBuf);        
35
      rxId = CAN0.getCanId();                    // Get message ID      
36
      
37
      Serial.println(rxId, HEX);          
38
    }
39
}
40
41
void loop()
42
{  
43
44
}

Weitere Ideen willkommen!

von Bestromer (Gast)


Lesenswert?

....dann stimmt etwas an der Aufbereitung Deiner IDs nicht, diese müssen 
entsprechend für die Filterregister vorbereitet werden, indem ein 
EXIDE-Bit in SIDL gesetzt wird....also mal Peters weg folgen...

von can (Gast)


Lesenswert?

Interessanter Effekt: ohne den Interrupt bekomme ich nun Ausgaben ?! Der 
Filter tut wie er soll!

1
#include <mcp_can.h>
2
#include <SPI.h>
3
4
long unsigned int rxId;
5
unsigned char len = 0;
6
unsigned char rxBuf[8];
7
8
MCP_CAN CAN0(10);                               // Set CS to pin 10
9
10
void setup()
11
{
12
  delay(1000);
13
  Serial.begin(115200);
14
15
  int canStatus = CAN0.begin(CAN_1000KBPS);
16
  if (canStatus != 0) {
17
    Serial.println("Can init failed!");
18
  }
19
  else {
20
    Serial.println("Can init ok!");
21
  }
22
23
  CAN0.init_Mask(0, CAN_EXTID, 0xFFFFFFFF); // 1111 1111 1111 1111 
24
  CAN0.init_Filt(0, CAN_EXTID, 0x00002001); // 0000 0000 0000 0001 - FAIL
25
26
  CAN0.init_Mask(1, CAN_EXTID, 0xFFFFFFFF); // 1111 1111 1111 1111
27
}
28
29
void blink() {    
30
}
31
32
void loop()
33
{  
34
  while(CAN_MSGAVAIL == CAN0.checkReceive()) {
35
      CAN0.readMsgBuf(&len, rxBuf);        
36
      rxId = CAN0.getCanId();                    // Get message ID      
37
      
38
      Serial.println(rxId, HEX);  
39
   }
40
}

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.