Go Down

Topic: CAN-BUS MCP_CAN Mask und Filter setzen (Read 177 times) previous topic - next topic

Wampo

Hy zusammen,

ich möchte mich auf den Thread mit dem CAN TEENSY etwas anknüpfen  -->Alter Thread

Kurze erläuterung was ich mache:

Mit dem Arduino und einem Pythonprogramm Sniffe ich mein Fahrzeug auf der CAN BUS Leitung. Ich empfange also alle möglichen Daten und das in Echtzeit. Soweit kein Problem, unten noch ein Bild vom Sniffen.
Ich sehe also die ID´s der CAN Pakete und deren Inhalt mit dem ich auch soweit was anfangen kann.



Nun habe ich mir für das gleiche Shield mit dem MCP2515, einen kleinen Code geschrieben der mit bestimmte ID´s filtern soll und es mir auf nem 20x4 I2C Display ausgeben soll. Soweit passt auch alles in dem unten stehendem Code Filtere ich zb. Motordrehzahl und Wassertemp, diese werden mir ebenfalls in echtzeit angezeit ohne jegliche große verzögerung.

Code: [Select]
#include <LiquidCrystal_I2C.h>
#include <mcp_can.h>
#include <SPI.h>

LiquidCrystal_I2C lcd(0x3F, 20, 4);

MCP_CAN CAN(10); 

unsigned char len = 0;
byte buf[8];
unsigned long canID;

unsigned char lenk;
unsigned char water;
unsigned char tmp;
float intemp;
unsigned int rpm;
float klimf;
float klimbf;
unsigned char midklim;

byte gc[8] = {
  B11000,
  B11000,
  B00111,
  B01000,
  B01000,
  B01000,
  B00111,
};

void setup(){
  lcd.begin();                     // Setting pin 2 for /INT input
  lcd.createChar(0, gc);
 
START_INIT:
if (CAN.begin(MCP_STDEXT, CAN_100KBPS, MCP_16MHZ) == CAN_OK)       //CAN STANDART with 100KB/S and Chip-Crystal at 16MHZ
  {   
    lcd.setCursor(0, 0);
    lcd.print("INIT CAN  BUS Shield");
    lcd.setCursor(0, 1);
    lcd.print("     Test  OK!      ");
  }
else
{
    lcd.setCursor(0, 0);
    lcd.print("! INIT CAN FAILED !");
    lcd.setCursor(0, 2);
    lcd.print("! INIT CAN AGAIN  !");
    delay(800);
    goto START_INIT;
}

    CAN.init_Mask(0,0,0x07FF0000);                // Init first mask...
    CAN.init_Filt(0,0,0x00AA0000);                // Init first filter...
    CAN.init_Filt(1,0,0x01D00000);                // Init second filter...
   
    lcd.setCursor(0, 2);
    lcd.print("MASK & Filter 1 Set!");
   
    CAN.init_Mask(1,0,0x03FF0000);                // Init second mask...
    CAN.init_Filt(2,0,0x02E60000);                // Init third filter...
    CAN.init_Filt(3,0,0x032E0000);                // Init fouth filter...
    CAN.init_Filt(4,0,0x02EA0000);                // Init fifth filter...
    CAN.init_Filt(5,0,0x0C800000);                // Init sixth filter...
   
    lcd.setCursor(0, 3);
    lcd.print("MASK & Filter 2 Set!");
   
    CAN.setMode(MCP_LISTENONLY);                // Set operation mode to normal so the MCP2515 sends acks to received data
    delay(1000);
    lcd.clear();
}

void loop(){
 
  if (CAN.checkReceive() == CAN_MSGAVAIL) {
      CAN.readMsgBuf(&canID, &len, buf); // Read data: len = data length, buf = data byte(s)

 
if (canID == 0x1D0){  //Wassertemperatur
        water = buf[0];
    }

if (canID == 0x0AA){  //Motordrehzahl
        rpm = buf[5];
        rpm = rpm << 8;
        tmp = buf[4] & 0x3F;
        rpm = rpm + tmp;
    }



if (canID == 0x2E6){  //Fahrertemperatur
        klimf = buf[2];

    }

if (canID == 0x2EA){  //Beifahrertemperatur
        klimbf = buf[2];


        midklim = buf[3]; //Mittelrad Lüftung
    }

if (canID == 0x32E){  //Innenraumtemperatur
        intemp = buf[3];
        intemp = intemp * 256;
        intemp = intemp * 0.03125;
        intemp = intemp / 100;
    }

if (canID == 0xC8){  //Lenkwinkel
        lenk = buf[2];
 
    }
  }
       
        lcd.setCursor(0, 0);
        lcd.print("RPM: ");
        lcd.print(rpm/4);
        lcd.print(" ");
         
        lcd.setCursor(0, 1);
        lcd.print("W: ");
        lcd.print(water - 48);
        lcd.write(byte(0));
        lcd.print(" ");


        lcd.setCursor(11, 1);
        lcd.print("T: ");
        lcd.print(intemp, 1);
        lcd.write(byte(0));
        lcd.print(" ");     
       
        lcd.setCursor(0, 2);
        lcd.print("Lenk: ");
        lcd.print(lenk);
        lcd.print(" ");

        lcd.setCursor(0, 3);
        lcd.print(klimf, 1);
        lcd.write(byte(0));
        lcd.print(" ");
   
        lcd.setCursor(9, 3);
        lcd.print(midklim);
        lcd.print("% ");
       
        lcd.setCursor(14, 3);
        lcd.print(klimbf, 1);
        lcd.write(byte(0));
        lcd.print(" ");
   
}


Jedoch alles was in der zweiten Mask steht wird nur Sporadisch aktualisiert oder gar nicht angezeigt.

Jetzt meine Hauptfrage:
Setze ich den Filter richtig ein? Könnte man das nochmal für Dummys erklären ich werde aus dem Teil überhaupt nicht schlau:

Code: [Select]

    CAN.init_Mask(0,0,0x01FF0000);                // Init first mask...
    CAN.init_Filt(0,0,0x00AA0000);                // Motordrehzahl soll angezeigt werden
    CAN.init_Filt(1,0,0x01D00000);                // wasser soll angezeigt werden
   
    lcd.setCursor(0, 2);
    lcd.print("MASK & Filter 1 Set!");
   
    CAN.init_Mask(1,0,0x0CFF0000);                // Init second mask...
    CAN.init_Filt(2,0,0x02E60000);                // Init third filter...
    CAN.init_Filt(3,0,0x032E0000);                // Init fouth filter...
    CAN.init_Filt(4,0,0x02EA0000);                // Init fifth filter...
    CAN.init_Filt(5,0,0x0C800000);                // Init sixth filter...
   


Mein aktuelles Verständniss bezüglich des Filters:

Im Mask sage ich 0x01FF0000 somit lässt der Filter mir die Adressen bis 0x01FF0000 zu,alles was drüber geht wird ignoriert?

Welche funktion hat Mask 0 und 1 ?


Gruß Daniel

agmue

#1
Oct 21, 2019, 03:39 pm Last Edit: Oct 21, 2019, 04:55 pm by agmue
Im Mask sage ich 0x01FF0000 somit lässt der Filter mir die Adressen bis 0x01FF0000 zu,alles was drüber geht wird ignoriert?

Welche funktion hat Mask 0 und 1 ?
Ich verstehe Maske und Filter nicht als Zahl, sondern als eine Ansammlung von Bits. Siehe dazu TABLE 4-2: FILTER/MASK TRUTH TABLE im Datenblatt.

Mit einer 1 (true) in der Maske ist dieses Bit relevant, bei einer 0 egal.

Die hereinkommende ID muß bei den relevanten Bits mit einem der Filter übereinstimmen, damit sie durchgelassen wird.

Zur Maske 0 gehören die Filter 0 und 1, zur Maske 1 die restlichen Filter. Es gibt zwischen den Masken eine Priorisierung. Siehe dazu FIGURE 4-2: RECEIVE BUFFER BLOCK DIAGRAM im Datenblatt.

Das gilt nur für MCP2515, der Teensy tickt etwas anders.

Alle Angaben nach bestem Wissen, aber ohne Gewähr!
Wahnsinn und Verstand trennt nur eine dünne Wand. (Daniel Düsentrieb)

noiasca

#2
Oct 21, 2019, 08:33 pm Last Edit: Oct 21, 2019, 08:50 pm by noiasca
Quote
Mein aktuelles Verständniss bezüglich des Filters:
so wie agmue schon schrieb in anderen Worten:

in der Mask gibst du an welche Bits geprüft werden sollen.
im Filter gibst du an, wie die in der Mask gesetzten Bits gesetzt sein sollen, damit die Message durchgeht.
Zum anfangen rate ich dir dringend, Mask und Filter binär hinzuschreiben, damit wir es einfacher lesbar was eigentlich durchgehen soll.

Wenn alles funktioniert, kannst du es immer noch auf hex umstellen.

edit.
wenn ich das mal probiere was du aktuell hast
Code: [Select]

‭0b0001111111110000000000000000‬ // 1st mask
0b0000‭101010100000000000000000‬ // motordrehzahl
‭0b0001110100000000000000000000‬ // Wasser

‭0b0011111111110000000000000000‬ // 2nd Mask
‭0b0010111001100000000000000000‬ // 2nd F1
‭0b0011001011100000000000000000‬ // 2nd F2
‭0b0010111010100000000000000000‬ // 2nd F3
‭0b1100100000000000000000000000‬ // 2nd F4


du gibst z.b. einen Filter4 für 2nd Mask, wo du zwei Bits setzt die diese Maske ohnehin nicht berücksichtigt.

Evlt. hilft es, wenn du beide MASK auf
0b1111111111110000000000000000‬ // 0xFFF0000‬

setzt. zumindest wäre dann interessant,
welche Messages durchgehen.
Welche Messages du dann vermisst
welche Messages du irrtümlich bekommst
alles binär ;-)
how to react on postings:
- post helped: provide your final sketch, say thank you & give karma.
- post not understood: Ask as long as you understand the post
- post is off topic (or you think it is): Stay to your topic. Ask again.
- else: Ask again.

Wampo

Danke schon mal euch beiden,

gute erklärung von euch beiden. Hat mir schon mal n gutes stück weitergeholfen.

Habe also gar nicht mal soooo viel Falsch verstanden bzw gemacht.

Hab nur mal Spaßeshalber MASK 0 und Filter 0,1 Kommentiert und habe die Motordrehzahl in MASK1 gepackt.

Anscheinend ist MASK 1 ne absolut Lahme Ente.... bekomme nicht mal ansatzweise eine Echtzeitanzeige hin, dies würde erklären warum meine anderen Werte nicht sauber reinkommen.
Oder die Drehzahldaten kommen so schnell rein das er sich "verschluckt"???

Habt Ihr noch ne andere Idee um den CAN effektiv ausfiltern kann, außer mit dem HARDWARE-FILTER?
Habe auch schon mal probiert alle CAN Daten rein zu lassen und mit ner if Anweisung das ganze zu machen aber da funktioniert bei mir irgendwie erst recht nix. Was mein Horizont schon wieder sprengt da der Sniffer der über den selben Arduinoshield läuft nur mit etwas anderem Code?

Code: [Select]

#include <SPI.h>
#include "mcp_can.h"

MCP_CAN CAN(10);
unsigned char len = 0;
byte buf[8];
unsigned long canID;

void setup() {
    Serial.begin(115200);

    while (CAN.begin(MCP_ANY, CAN_100KBPS, MCP_16MHZ) != CAN_OK) {
      delay(500);
      Serial.println("FAILURE ---> RE-INIT");
    }
    CAN.setMode(MCP_LISTENONLY);
}

void loop() {
 
    if (CAN.checkReceive() == CAN_MSGAVAIL) {
        CAN.readMsgBuf(&canID, &len, buf);

        Serial.print("FRAME:ID=");
        Serial.print(canID);
        Serial.print(":LEN=");
        Serial.print(len);
       
        char tmp[3];
        for(int i = 0; i<len; i++) {
            Serial.print(":");
           
            snprintf(tmp, 3, "%02X", buf[i]);
           
            Serial.print(tmp);
        }

        Serial.println();
    }
}


Ist der MCP überhaupt für solche mengen an CAN Daten ungeeignet?
Was mein Verständnis nur übersteigt ist warum der Sniffer so schnell und sauber läuft

Betreibe ihn mit einem 16MHz und auf 100kbps am richtigen CAN. 

Gruß Daniel

noiasca

Quote
Habt Ihr noch ne andere Idee um den CAN effektiv ausfiltern kann, außer mit dem HARDWARE-FILTER?
siehe #2
Quote
Evlt. hilft es, wenn du beide MASK auf
0b1111111111110000000000000000‬ // 0xFFF0000‬

setzt. zumindest wäre dann interessant,
welche Messages durchgehen.
Welche Messages du dann vermisst
welche Messages du irrtümlich bekommst
die 3 Fragen beantworten und/oder gegebenenfalls beschreiben, was daran nicht funktioniert.
how to react on postings:
- post helped: provide your final sketch, say thank you & give karma.
- post not understood: Ask as long as you understand the post
- post is off topic (or you think it is): Stay to your topic. Ask again.
- else: Ask again.

ArduFE

#5
Oct 22, 2019, 07:53 am Last Edit: Oct 22, 2019, 08:29 am by ArduFE
Wenn eine Message ab und zu fehlt, kann da noch ein anderer Effekt zuschlagen:

Soweit ich das verstehe hat der MCP2515 nur zwei Puffer um CAN Messages zwischenzuspeichern. Wenn man mit den Filtern arbeitet, hat jedes Filtersystem nur einen Puffer.

Auf dem CAN Bus kommen Messages gerne mal schnell in Gruppen hintereinander. Wenn da zwei Messages, auf die ein Filter anspricht, direkt hintereinander kommen, kann da schon mal was verloren gehen, wenn das Abholen über SPI zu langsam ist.

Nicht umsonst haben neuere Chips aus der Familie (MCP2517, MCP2518) nicht zwei sondern 31 Puffer. Auch die Controller mit eingebauten CAN haben mehr Mailboxen (=Puffer), der Due 8, die Teensy 3.x 16 und der Teensy 4.0 gar 64.

agmue

#6
Oct 22, 2019, 09:23 am Last Edit: Oct 22, 2019, 09:44 am by agmue
Was mein Verständnis nur übersteigt ist warum der Sniffer so schnell und sauber läuft
Der Unterschied könnte in der Ausgabe liegen, mal Serial, mal LCD über I2C. Mit einem I2C-Scanner kannst Du die maximale Geschwindigkeit ermitteln, die Deine Hardware verträgt. Dann erhöhst Du die I2C-Busgeschwindugkeit. I2C - Two-Wire Peripheral Interface - for Arduino Timing

Außerdem könntest Du feststehenden Text wie "RPM: " nur einmal schreiben.
Wahnsinn und Verstand trennt nur eine dünne Wand. (Daniel Düsentrieb)

Wampo

nAbend,

vorerst danke schon mal für die gute Hilfestellung.
Habe jetzt alles soweit zum laufen gebracht was so nicht funktionierte.
Geschwindigkeit, Echtzeit, Daten Sieben usw.

Der Grund ist eigentlich relativ simpel. Das Maskieren und Filtern ist meistens etwas umständlich beschrieben
Im Prinzip ist das Maskieren nichts weiter wie das Blocken von Daten, setze ich den MASK auf 0x07FF0000 unterbinde ich eigentlich das eindringen sämtlicher ID´s nur was im Filter steht wird auch reingelassen. (so meine erkenntnis)
Vielleicht habe ich auch zu kompliziert gedacht und es deshalb nicht verstanden.

Ich habe auch noch den MCP Mode geändert, vorm setzen der MASK&FILTER schalte ich auf den LOOPBACK Modus --->setze dann die MASK&FILTER---->schalte dann in den NormalModus um.  
ICh weiß nicht genau wo aber ich habe gelesen das im Modus LISTEN ONLY auch Fehlerhafte Pakete entgegengenommen werden und der Filter nicht wirklich funktioniert.

Ganz ausgereift ist der Code jedoch noch nicht, feststehende Werte, wie agmue schon sagt, könnte man im Setup setzen.
Werde auch noch die Geschwindigkeit vom I2C_LCD auf 400khz setzen, somit sollte dann kein Timingproblem mehr vorhanden sein.

Code: [Select]
#include <LiquidCrystal_I2C.h>
#include <mcp_can.h>
#include <SPI.h>

LiquidCrystal_I2C lcd(0x3F, 20, 4);

MCP_CAN CAN(10);  

 
unsigned char len = 0;
byte buf[8];
unsigned long canID;

unsigned char lenktmp;
int lenk;
unsigned char water;
unsigned char tmp;
float intemp;
unsigned int rpm;
unsigned char klapp;
unsigned char midklim;
unsigned char dimm;



byte gc[8] = {
  B11000,
  B11000,
  B00111,
  B01000,
  B01000,
  B01000,
  B00111,
};

void setup(){
  lcd.begin();                     // Setting pin 2 for /INT input
  lcd.createChar(0, gc);
  
START_INIT:
    lcd.setCursor(0, 0);
    lcd.print(" INIT  MCP2515  CAN ");
    
if (CAN.begin(MCP_STDEXT, CAN_100KBPS, MCP_16MHZ) == CAN_OK)       //CAN STANDART with 100KB/S and Chip-Crystal at 16MHZ
  {    
    lcd.setCursor(0, 1);
    lcd.print("      Init  OK!     ");
  }
else
{
    lcd.setCursor(0, 0);
    lcd.print("! INIT CAN FAILED !");
    lcd.setCursor(0, 2);
    lcd.print("! INIT CAN AGAIN  !");
    delay(500);
    goto START_INIT;
}
    CAN.setMode(MCP_LOOPBACK);
    delay(500);

    CAN.init_Mask(0,0,0x07FF0000);                // 0x0CAA0000
    CAN.init_Filt(0,0,0x00AA0000);                // 0x00AA0000 Drehzahl
    CAN.init_Filt(1,0,0x00C80000);                // 0x0C800000 Lenkradstellung
      
    lcd.setCursor(0, 2);
    lcd.print("MASK & Filter 1 Set!");
    delay(500);
    
    CAN.init_Mask(1,0,0x07FF0000);                // 0x03FF0000
    CAN.init_Filt(2,0,0x01D00000);                // 0x01D00000 Motortemp
    CAN.init_Filt(3,0,0x02E60000);                // 0x02E60000 Fahrerlüftungsklappen
    CAN.init_Filt(4,0,0x032E0000);                // 0x032E0000 Innenraumtemp
    CAN.init_Filt(5,0,0x02020000);  
  
    lcd.setCursor(0, 3);
    lcd.print("MASK & Filter 2 Set!");
    delay(500);
    
    CAN.setMode(MCP_NORMAL);                // Set operation mode to normal so the MCP2515 sends acks to received data
    delay(500);
    lcd.clear();
    
        lcd.setCursor(0, 0);
        lcd.print("RPM: ");
        lcd.setCursor(0, 1);
        lcd.print("W: ");
        lcd.setCursor(11, 1);
        lcd.print("T: ");
        lcd.setCursor(11, 0);
        lcd.print("L: ");
        
}

void loop(){
  
  if (CAN.checkReceive() == CAN_MSGAVAIL) {
      CAN.readMsgBuf(&canID, &len, buf); // Read data: len = data length, buf = data byte(s)
 
if (canID == 0x1D0){  //Motortemp
        water = buf[0];
        water = water - 48;
    }

if (canID == 0x0AA){  //Drehzahl
        rpm = buf[5];
        rpm = rpm << 8;
        tmp = buf[4] & 0x3F;
        rpm = rpm + tmp;
        rpm = rpm / 4;
    }

if (canID == 0x2E6){  //Fahrerlüftungsklappen
        klapp = buf[1];
        midklim = buf[3]; //Mittelrad Lüftung
    }


if (canID == 0x32E){  //Innenraumtemp
        intemp = buf[3];
    }

if (canID == 0xC8){  //Lenkradstellung
        lenktmp = buf[1] & buf[0];
        if(lenktmp <= 20000){
          lenk = lenktmp / 23;
        }
        else
        lenktmp = 65535 - (buf[1] & buf[0]);
        lenk = lenktmp / 23;
        
    }
    if (canID == 0x202){  //Innenlicht Dimmer
        dimm = buf[0];
 
    }
  }
      
        lcd.setCursor(5,0);
        lcd.print(rpm);
        lcd.print(" ");
                
        lcd.setCursor(3,1);
        lcd.print(water);
        lcd.write(byte(0));
        lcd.print(" ");

        lcd.setCursor(14, 1);
        lcd.print((intemp / 10) + 6, 1);
        lcd.write(byte(0));
        lcd.print(" ");
        
        lcd.setCursor(0, 2);
        lcd.print(lenk);
        lcd.print("  ");
    
        lcd.setCursor(0, 3);
        lcd.print(midklim);
        lcd.print("% ");

        lcd.setCursor(15, 3);
        lcd.print(klapp);
        lcd.print("% ");

        lcd.setCursor(14, 0);
        lcd.print(dimm);
        lcd.print("% ");
        
}


Noch eine Frage zu guter letzt:

Was mache ich jetzt wenn ich mehr ID´s benötige als mein Filter hergibt? Da werde ich wohl nicht um den MCP2517/18 drumrum kommen oder? Ist der Arduinotauglich (passende Library´s) oder muss der mit Teensy betrieben werden?


Gruß Daniel

postmaster-ino

Hi

Denke, dann wirst Du den 'kleinsten möglichen Gemeinsamen' bestimmen müssen und selber ebenfalls etwas Prüfen.
Vll. kannst Du vorher ja austesten, welche ID wie häufig vorkommt, wo Es also Sinn macht, Das in Hardware (also vom CAN-Chip selber) ausfiltern zu lassen und nur die spärlich auftretenden unerwünschten IDs in Deine Maske/Filter einbeziehst.

Verständlich genug ausgedrückt?

MfG
anscheinend ist Es nicht erwünscht, einen Foren-internen Link als 'Homepage' einzubinden, damit JEDER nur einen Klick von combie's Liste zum Thema State-Maschine entfernt ist.
... dann eben nicht ...

Go Up