Serie inDetail - komplexe Themen verständlich dargestellt

Einstellungen des MCP2515 CAN Controllers

Damit das Senden und Empfangen mit dem MCP2515 ordentlich funktioniert müssen noch ein paar Einstellungen vorgenommen werden.

Reset des Controllers - resetController()

Mit dieser Funktion werden alle Register mit den Werten '0' überschrieben. Durch die anschließende 'Reset' Funktionn werden alle Control-Register anschließend wieder mit den "Werkseinstellungen" gefüllt. Die RX Buffer lassen sich übrigens nicht mit registerWrite() überschreiben bzw. löschen.

Baudrate Einstellen - setBaudrate()

Das MCP2515 CAN Modul kann bis zu 1 Mbit/s übertragen. Aber auch 500, 250 oder 125 kbit/s sind üblich. Jeder CAN Knoten muss daher auf die geplante CAN Bus Geschwindigkeit eingestellt werden. Der Takt des externen Oszillator welcher den MCP2515 taktet ist mit 8 MHz oder auch 20 MHz wesentlich schneller. Jedes auf dem CAN Bus übertragene Bit dauert daher mehrere Oszillator-Takte.

Zwei Oszillator-Takte nennt man ein Time-Quantum (TQ) der Grundzeiteinheit für die Berechnung der Bitlänge. An unserem MCP2515 ist ein 8MHz Oszillator angeschlossen. Daher ergibt sich ...

CAN Bus Bit Timing

Zeitdauer von einem Oszi-Takt =
1 ÷ 8MHz = 125ns

Time Quantum (TQ) =
2 × 125ns= 250ns

Die Zeitdauer eines Bit ist beim CAN in 4 Segmente eingeteilt. SYNC dient zum Synchronisieren, danach kommt eine Zeitdauer bis sich das Signal ausgebreitet hat (Propagation Delay) und dann folgen 2 Segmente an deren Übergang das Bit von allen Empfängern ausgelesen wird (=sampling). Die Bereiche werden nun so eingestellt, dass der Sampling Point nach rund 60-70% der Zeit erfolgt (siehe Tabelle).

TQ ist die Zeiteinheit und in unserem Fall 250ns. SYNC ist immer 1TQ, und die anderen Bereiche werden bezogen auf den Sampling Point aufgeteilt und in die entsprechenden Register geschrieben. Bei einer Baudrate von 125kbit/sreichen die 3Bit Speicherbereiche für die drei Segment nicht mehr aus. Daher wird der Prescaler im Register 0x2A erhöht, so dass ein TQ nun 500ns ist.

Empfangsfilter Filter setzen - setRxFilter() und setRxFilterMask()

Mit Empfangsfilter lassen sich CAN Botschaften ausfiltern die für den jeweiligen CAN Knoten nicht relevant sind. Das funktioniert rein auf Hardwareebene innerhalb des MCP2515 ohne den angeschlossenen Mikrocontroller mit der Filterung über eine if-Abfrage zu belasten.

Der vorgeschaltete Filter funktioniert zweistufig. Zuerst wird mit einer Maske festgelegt welche Stellen für die Filterung relevant sind. Die zweite Stufe - der eigentliche Filter- beinhaltet dann die Werte, die auch bei der eingehenden Nachricht gleich sein müssen, um in einen RX-Buffer kopiert zu werden.

Für den ersten Eingangs-Buffer RXB0 ist die Maske RXM0 und die beiden Filter RXF0 und RXF1 vorgesehen. Die andere Maske und die weiteren Filter sind für den Eingangs-Buffer RXB1.

Hinweis: Sollen CAN Nachrichten mit Extended Identifiers (EID) empfangen werden muss mindestens ein RX-Filter entsprechend eingestellt werden.

Klasse "MCP25215" mit den Methoden zum Einstellen des MCP2515 #include "SPI.h" /* Erstellen eines eigenen Datentyps 'Buffer' mit den gleichen Namen und der gleichen Reihenfolge wie die * entsprechenden Buffer im MCP2515 (Kopie der 5 Buffer 3x Tx und 2xRx) */ struct Buffer{ byte SIDH; byte SIDL; byte EID8; byte EID0; byte DLC; byte D0, D1, D2, D3, D4, D5, D6, D7; }; /* Erstellen eines eigenen Datentyps 'Payload' um die empfangenen Nutzdaten mit der Funktion 'get Payload' * zurückzugeben.*/ struct Payload { byte anzahlBytes; byte D0, D1, D2, D3, D4, D5, D6, D7; }; class MCP2515 { private: byte CS; // Speichern des von Konstruktor übertragenen 'Chip Select' Pins Buffer RXB0, RXB1, TXB0, TXB1, TXB2; // Byte-Container vom oben definierten Typ 'Buffer' void reset(); // Reset des MCP2515 (= wie VCC Unterbrechung) byte registerRead(byte); // Liest ein Registerinhalt (regAdr) void registerWrite(byte, byte); // Beschreibt ein Register (regAdr, daten) void modifyBits(byte, byte, byte); // Verändert einzelne Bits des Registers (regAdr, maske, daten) void sendRTS(byte); // 'Request to Send' eines TX Buffers (bufferNr) void setMode(byte); // 0=Normal Mode, 1=Sleep , 2=Loopback , 3= Listen , 4= Config void readRXbuffer(byte); // Auslesen und quittieren eines RX/Empfangs Buffer (bufferNr) void loadTXbuffer(byte); // Übertragen eines kompletten Buffers auf den MCP2515 (bufferNr) public: // Konstruktor (Initialisierungsfunktion) MCP2515(byte cs = 10) { SPI.begin(); SPI.setDataMode(SPI_MODE0); // oder SPI_MODE3 SPI.setClockDivider(SPI_CLOCK_DIV4); // max. 10 Mhz SPI.setBitOrder(MSBFIRST); CS = cs; // Ein andere CS Pin kann optional übergeben werden pinMode(CS, OUTPUT); // Chip Select Pin für die SPI Schnittstelle konfigurieren // Befehle zum Senden von Nachrichten void setSID(byte, unsigned int); // Schreibt die SID in den gewählten Buffer (bufferNr, SID) void setEID(byte, unsigned long); // schreibt die EID in den gewählten Buffer (bufferNr, EID) void setPayload(byte, byte, byte, byte, byte, byte, byte, byte, byte); // schreibt die Nutzdaten void setDLC(byte, byte, bool); // (bufferNr, anzahlPayload, RemoteFrame) void sendTXbuffer(byte); // sendet den gewählten Buffer auf den CAN Bus (bufferNr) // Befehle zum Empfangen von Nachrichten bool loadRXbuffer(byte); // Überträgt einen RX Buffer. Gibt true zurück bei neuer Nachricht byte getStatus(byte); // Analysiert die die geladene Nachricht und gibt den Status aus unsigned long getID(byte); // Gibt die ID (SID oder EID) der heruntergeladenen Nachricht zurück Payload getPayload(byte); // Gibt die kompl. Nutzdaten der heruntergeladenen Nachricht zurück // Einstellungen ändern auf dem MCP2515 void resetController(); // Löscht alle Register und stellt die Standartwerte wieder her void setBaudrate(unsigned int); // CAn Bus Baudrate einstellen (1000, 500, 250, 125) [kbit/s] void setRxFilter(byte, bool, unsigned long); // (filterNr, SID=0|EID=1, SID bzw EID) void setRxFilterMask(byte, bool, unsigned long); // (filterNr, SID=0|EID=1, SID bzw EID) }; //// PRIVATE METHODS ////////////////////////////////////////////////////////////////////////////////// /* Zur besseren Übersichtlichkeit werden die PRIVATE Methoden hier nicht mehr angezeigt */ // PUBLIC METHODEN /////////////////////////////////////////////////////////////////////////////////// /* Zur besseren Übersichtlichkeit werden die Methoden zum Senden und Empfangen nicht mehr angezeigt */ void MCP2515::resetController() { /* Mit dieser Funktion werden zunächst (eigentlich nur zur besseren Übersichtlichkeit) alle Registerinhalte gelöscht. * Control-Register werden nicht gelöscht. Diese werden mit dem anschließenden 'reset()' Befehl auf die Grundeinstellung * zurückgesetzt. Um die Filter und Maskenbereiche zu löschen muss sich der CAN Controller im CONFIG MODE befinden. Daher * wird zu Begin der Funktion der CONFIG MODE ein- und am Ende der Funktion wieder ausgeschalten. * Die Eingangsbuffer (RXB) lassen sich nicht löschen. */ reset(); // Private Funktion mit dem RESET Befehl setMode(4); // Modul auf CONFIG MODE stellen for (int i = 0; i < 13; i++) registerWrite(i, 0); for (int i = 16; i < 29; i++) registerWrite(i, 0); for (int i = 32; i < 40; i++) registerWrite(i, 0); for (int i = 49; i < 62; i++) registerWrite(i, 0); for (int i = 65; i < 78; i++) registerWrite(i, 0); for (int i = 81; i < 94; i++) registerWrite(i, 0); setMode(0); // Modul auf NORMAL MODE stellen } //---------------------------------------------------------------------------------------------------- oid MCP2515::setBaudrate(unsigned int br) { /* Methode dient zum Einstellen der CAN Bus Übertragungsrate. Dazu werden 3 Register verändert CANF1, CANF2, CANF3. * Der Methode kann die Baudrate in kbit/s übergeben werden (1000, 500,250 oder 125) * Ein Bit besteht aus 4 Segmenten welche zusammen 1µs(1Mbit/s), 2µs, 4µs oder 8µs(125kbit/s) lang sind. * Die Länge der Bereiche werden in den Registern eingestellt. */ setMode(4); // 4= Config Mode if (br == 1000) { // Bitrate auf 1 Mbit/s einstellen registerWrite(0x29, B10000000); // |1|0|3xSeg1|3xPropagation| registerWrite(0x28, B00000000); // |0|0|0|0|0|3xSeg2| } else if (br == 500) { //Bitrate auf 500 kbit/s einstellen registerWrite(0x29, B10001001); registerWrite(0x28, B00000010); } else if (br == 250){ //Bitrate auf 250 kbit/s einstellen registerWrite(0x29, B10100011); registerWrite(0x28, B00000101); } else if (br == 125){ //Bitrate auf 125 kbit/s einstellen registerWrite(0x2A, B00000001); // Prescaler verdoppeln (TQ=500ns) registerWrite(0x29, B10100100); registerWrite(0x28, B00000100); } setMode(0); } //---------------------------------------------------------------------------------------------------- void MCP2515::setRxFilter(byte filterNr, bool eidOrSid, unsigned long id) { /* Mit Filtern können empfangen CAN Nachrichten überprüft werden ob diese relevant sind. Erst wenn eine Nachricht * die Filterkriterien erfüllt wird die Nachricht in einen der beiden RX Buffer weitergeleitet. * Es gibt 5 Filter. die erste if Abfrage begrenzt diesen Bereich. (Filter 0 und 1 sind für den Rx Buffer 0, * die Filter 2-5 für den Rx Buffer 1).*/ if (filterNr > 5) filterNr = 5; byte regAdr; if (filterNr < 3) regAdr = filterNr * 4; // Erste Adresse (SIDH) des entsprechenden Filters (0=0, 1=4, 2=8) else regAdr = filterNr * 4 + 4 ; // 3=16, 4=20, 5=24 setMode(4); // auf ConfigMode stellen if (eidOrSid == 0) { // SID ausgewählt if (id > 2047) id = 2047; // SID max 11 Stellen (=2047) registerWrite(regAdr + 0, id >> 3); // SIDH Register registerWrite(regAdr + 1, id << 5); // SIDL Register registerWrite(regAdr + 2, 0); // EID8 Register registerWrite(regAdr + 3, 0); // EID0 Register } else { // EID if (id > 536870911) id = 536870911; // EID max 29 Stellen (=536870911) registerWrite(regAdr + 0, id >> 21); // SIDH Register registerWrite(regAdr + 1,(id >> 13 & B11100000) | B00001000 | (id >> 16 & B00000111)) ; // SIDL Register registerWrite(regAdr + 2, id >> 8); // EID8 Register registerWrite(regAdr + 3, id); // EID0 Register } setMode(0); // wieder auf NormalMode stellen } void MCP2515::setRxFilterMask(byte maskenNr, bool eidOrSid, unsigned long id) { /* Die Filtermaske legt fest welche Bit durch die Filter überprüft werden. * Nur Bits die in der Maske mit '1' maskiert sind werden durch den nachfolgenden Filter überprüft.*/ if (maskenNr > 1) maskenNr = 1; byte regAdr; if (maskenNr == 0) regAdr = 32; // Erste Adresse (SIDH) der Maske RXM0 else regAdr = 36 ; // Erste Adresse (SIDH) der Maske RXM1 setMode(4); // auf ConfigMode stellen if (eidOrSid == 0) { // SID ausgewählt if (id > 2047) id = 2047; // SID max 11 Stellen (=2047) registerWrite(regAdr + 0, id >> 3); // SIDH Register registerWrite(regAdr + 1, id << 5); // SIDL Register registerWrite(regAdr + 2, 0); // EID8 Register registerWrite(regAdr + 3, 0); // EID0 Register } else { // EID if (id > 536870911) id = 536870911; // EID max 29 Stellen (=536870911) registerWrite(regAdr + 0, id >> 21); // SIDH Register registerWrite(regAdr + 1,(id >> 13 & B11100000) | (id >> 16 & B00000111)) ; // SIDL Register registerWrite(regAdr + 2, id >> 8); // EID8 Register registerWrite(regAdr + 3, id); // EID0 Register } setMode(0); // wieder auf NormalMode stellen }