Forum: Mikrocontroller und Digitale Elektronik MCP2515 Sendepuffer


von Stefan (Gast)


Lesenswert?

Hallo zusammen,

ich habe eine Schaltung zusammen gebaut mit einem ATMEGA32 und einem CAN 
Controller MCP2515. Schaltung und Code basieren auf den Daten von 
Kreatives-Chaos.com. Da das dortige Tutorial sehr verbreitet ist, hoffe 
ich das mir hier jemand helfen kann...

Ich hab versucht eine Nachricht zu senden. Dies schlägt allerdings fehl, 
da die Abfrage, ob die Sendepuffer frei sind, immer ein false zurück 
liefert.
In dem o.g. Tutorial ist auch ein Democode von dem Can Controller zu 
finden. Auch bei diesem Code tritt der gleiche Fehler auf. Zusätzlich 
wird in der Initialisierung des Controllers versucht, ein Register 
auszulesen, welches zuvor beschrieben wurde. Dies schlägt bei mir auch 
fehl (also das auslesen).

Ich habe die Schaltung bereits mehrfach gecheckt und konnte keinen 
Fehler finden. Auch die SPI Kommunikation scheint zu funktionieren.
Aktuell weis ich absolut nicht mehr, wo ich noch suchen soll. Falls 
jemand eine Idee hat wäre ich wirklich sehr dankbar...

Viele Grüße
Stefan

von (prx) A. K. (prx)


Lesenswert?

Ist der Controller allein im Netz? Wenn ja: Das geht bei CAN nicht, 
führt zu Dauerfehler mangels Quittierung. In dem Fall solltest du deine 
ersten Tests im Loopback-Testmodus machen.

Wär ohnehin kein Fehler, wenn du dir die Status/Error-Register 
anschaust.

PS: Das setzt natürlich voraus, dass du den MCP überhaupt ansprechen 
kannst. Dein Text erweckt aber etwas undeutlich den Eindruck, dass der 
Treiber mit einem Stück Holz redet. Um das also zu klären: Funktioniert 
der Zugriff auf die Register des MCP? Wenn nicht: Falsch angeschlossen, 
falsche Pindefinitionen, kein Takt und hundert andere Möglichkeiten.

von Stefan (Gast)


Lesenswert?

Hi A.K.

danke für deine Nachricht. Ehrlich gesagt bin ich auch etwas verwirrt, 
weshalb ich in der mcp init ein Register nicht auslesen konnte (als 
Test). Ich habe mittels Oszilloskop allerdings schonmal geschaut, ob die 
Pins vom µC während der Datenübertragung mittels SPI richtig geschaltet 
werden. Das sieht eigentlich ganz gut aus. Werd wohl nochmal versuchen 
ein anderes Register auszulesen, um zu schauen ob das funktioniert.

Ja der Controller ist alleime am Netz. Müsste er nicht im ersten Moment 
die Nachricht absenden und erst in den Fehlerzustand gehen, wenn er kein 
Ack bekommen hat ? In dem Democode zum MCP2515 ist am Anfang der 
Loopback gesetzt und ich hab das gleiche Problem, dass die Sendepuffer 
nicht freigegeben sind.

Viele Grüße
Stefan

von TestX .. (xaos)


Lesenswert?

Stefan schrieb:
> Ja der Controller ist alleime am Netz. Müsste er nicht im ersten Moment
> die Nachricht absenden und erst in den Fehlerzustand gehen, wenn er kein
> Ack bekommen hat ?

ja raussenden wird der controller den frame, also mit dem oszilloskop 
zwischen CANH und CANL wirst du was sehen. der controller wird nur 
irgendwann in den error modus gehen ohne ack

von cskulkw (Gast)


Lesenswert?

Welches Register konntest Du nicht verändern?

CNF1, CNT2, CNF3, TXRTSCTRL, Filter und Mask-Register lassen sich nur im 
Konfigurationmodus verändern. Dazu CANTCTRL.REQOP auf 0b100 setzen. Bzw. 
Bit7 im CANCTRL-Register setzen.

Mit Bit 3 (von 0 angefangen zu zählen) kann man den MCP2515 in den 
One-Shot-Modus bringen. Dann sendet er nur einmal die Botschaft und 
wartet nicht auf Acknowledge. Dadurch kann man verhindern, dass er zu 
schnell in den Fehlermodus springt.

Wenn das alles nichts hilft. Dann einen Software-reset mit dem 
SPI-Kommando 0xC0 senden.

von Stefan (Gast)


Lesenswert?

Guten Abend zusammen,

vielen Dank für die rege Beteiligung.
Auf der Seite von kreatives-chaos gibt es ein Demo Package zum MCP2515. 
Hier wird in der Init nach setzen des Configurationsmodus die Baudrate 
eingestellt und anschließend versucht, diese zu lesen. Hier bekomme ich 
aber lediglich ein false zurück
1
// reset MCP2515 by software reset.
2
  // After this he is in configuration mode.
3
  RESET(MCP2515_CS);
4
  spi_putc(SPI_RESET);
5
  SET(MCP2515_CS);
6
  
7
  // wait a little bit until the MCP2515 has restarted
8
  _delay_us(10);
9
  
10
  // load CNF1..3 Register
11
  RESET(MCP2515_CS);
12
  spi_putc(SPI_WRITE);
13
  spi_putc(CNF3);
14
  
15
  spi_putc((1<<PHSEG21));    // Bitrate 125 kbps at 16 MHz
16
  spi_putc((1<<BTLMODE)|(1<<PHSEG11));
17
  spi_putc((1<<BRP2)|(1<<BRP1)|(1<<BRP0));  //CNF1
18
  
19
  // activate interrupts
20
  spi_putc((1<<RX1IE)|(1<<RX0IE));
21
  SET(MCP2515_CS);
22
  
23
  // test if we could read back the value => is the chip accessible?
24
  if (mcp2515_read_register(CNF1) != ((1<<BRP2)|(1<<BRP1)|(1<<BRP0))) {
25
    return false;
26
  }

Warum das nicht funktioniert, ist mir ein Rätsel. Habe auch gerade 
versucht manuell ein Bit zu setzen und anschließend auszulesen. Ich kann 
leider nicht debuggen, sondern habe nur eine LED zum An-/Ausschalten
1
//... Konfigurationsmodus aktiv...
2
mcp2515_write_register( CNF3, (1<<PHSEG21) ); //Bit 1
3
uint8_t test;
4
test = mcp2515_read_register(CNF3);
5
    
6
if (test = 2) 
7
{
8
PORTA |= (1<<PA0);
9
}
Das komische ist, vergleiche ich "test" auf 2, leuchtet die LED. 2 ist 
auch der erwarte Wert. Vergleiche ich auf 0, bleibt die LED aus. Passt 
also auch. Vergleiche ich aber z.B. auf test=1, ist die LED wieder an, 
was aber garnicht sein darf, da Bit0 = 0 ist. Versteh ich nicht... ?!

Der Vollständigkeit halber noch die Sende- und Empfangsroutinen:
1
void mcp2515_write_register( uint8_t adress, uint8_t data )
2
{
3
    // /CS des MCP2515 auf Low ziehen
4
    PORT_CS &= ~(1<<P_CS);
5
   
6
    spi_putc(SPI_WRITE);
7
    spi_putc(adress);
8
    spi_putc(data);
9
   
10
    // /CS Leitung wieder freigeben
11
    PORT_CS |= (1<<P_CS);
12
}
13
uint8_t mcp2515_read_register(uint8_t adress)
14
{
15
    uint8_t data;
16
   
17
    // /CS des MCP2515 auf Low ziehen
18
    PORT_CS &= ~(1<<P_CS);
19
   
20
    spi_putc(SPI_READ);
21
    spi_putc(adress);
22
   
23
    data = spi_putc(0xff); 
24
   
25
    // /CS Leitung wieder freigeben
26
    PORT_CS |= (1<<P_CS);
27
   
28
    return data;
29
}

von STK500-Besitzer (Gast)


Lesenswert?

Den CAN-Controller kann man auch im Loopback-Modus (oder so ähnlich) 
betreiben.
Da kann man ihn dann für sich alleine testen, ohne einen weiteren Knoten 
zu haben.

von cskulkw (Gast)


Lesenswert?

Wenn Du das selbst Programmiert hast, dann funktioniert das nicht, weil 
Du das Tripel Komando, Register, Daten nicht einhälst.

Stefan schrieb:
> // load CNF1..3 Register
>
>   RESET(MCP2515_CS);
>
>   spi_putc(SPI_WRITE);
>
>   spi_putc(CNF3);
>
>
>
>   spi_putc((1<<PHSEG21));    // Bitrate 125 kbps at 16 MHz
>
>   spi_putc((1<<BTLMODE)|(1<<PHSEG11));
>
>   spi_putc((1<<BRP2)|(1<<BRP1)|(1<<BRP0));  //CNF1
>
>
>
>   // activate interrupts
>
>   spi_putc((1<<RX1IE)|(1<<RX0IE));
>
>   SET(MCP2515_CS);


Vielleicht funktioniert das hier:

   RESET(MCP2515_CS);
   /* Kommando 0x02*/
   spi_putc(SPI_WRITE);
   /* Registeradresse */
   spi_putc(CNF3);
   /* Daten für CNF3 */
   spi_putc((1<<PHSEG21));    // Bitrate 125 kbps at 16 MHz
   /* Chip-Select wieder auf 1 -> siehe dazu Fig 11-04*/
   /* auf Seite 63 des Datenblattes MCP2515 */
   SET(MCP2515_CS);

  /*Warten ist hier nicht verkehrt*/
  _delay_us(10);


   RESET(MCP2515_CS);
   /* Kommando 0x02*/
   spi_putc(SPI_WRITE);
   /* Registeradresse */
   spi_putc(CNF2);
   /* Daten für CNF2 */
   spi_putc((1<<BTLMODE)|(1<<PHSEG11));
   SET(MCP2515_CS);

  /*Warten ist hier nicht verkehrt*/
  _delay_us(10);

   RESET(MCP2515_CS);
   /* Kommando 0x02*/
   spi_putc(SPI_WRITE);
   /* Registeradresse */
   spi_putc(CNF1);
   /* Daten für CNF1 */
   spi_putc((1<<BRP2)|(1<<BRP1)|(1<<BRP0));  //CNF1
   SET(MCP2515_CS);

  /*Warten ist hier nicht verkehrt*/
  _delay_us(10);

   RESET(MCP2515_CS);
   /* Kommando 0x02*/
   spi_putc(SPI_WRITE);
   /* Registeradresse */
   spi_putc(CANINTE);
   /* Daten für CANINTE */
   spi_putc((1<<RX1IE)|(1<<RX0IE));  //CANINTE1
   SET(MCP2515_CS);

  /*Warten ist hier nicht verkehrt*/
  _delay_us(10);

HIER MUSST DU GENAUSO DEINE FILTER SETZEN FUER DIE MBX 0 und 1

  /*ZUM SCHLUSS KONFIGURATIONMODUS AUF NORMALMODUS UMSCHALTEN !!!*/

   RESET(MCP2515_CS);
   /* Kommando 0x02*/
   spi_putc(SPI_WRITE);
   /* Registeradresse */
   spi_putc(CANCTRL);
   /* Daten für CANCTRL BIt 8 löschen -> Normalmodus
   /* Bit4 -> OneShotModus */
   spi_putc(0x04);  //CANCTRL
   SET(MCP2515_CS);

Ab hier dann fröhliches Senden und empfangenn

Stefan schrieb:
> void mcp2515_write_register( uint8_t adress, uint8_t data )
>
> {
>
>     // /CS des MCP2515 auf Low ziehen
>
>     PORT_CS &= ~(1<<P_CS);
>
>
>
>     spi_putc(SPI_WRITE);
>
>     spi_putc(adress);
>
>     spi_putc(data);
>
>
>
>     // /CS Leitung wieder freigeben
>
>     PORT_CS |= (1<<P_CS);
>
> }

Hier ist die Reihenfolge richtig. Aber in der Initialisierung wird der 
Konfigurationmodus nie verlassen. Abgesehen davon, weiss der MCP beim 
besten Willen nicht, was er mit den Informationen anfangen sollen, wenn 
man die Reihenfolge Kommando, Register, Daten nicht einhält.

Viel Erfolg

von Stefan (Gast)


Angehängte Dateien:

Lesenswert?

Guten Abend,

Der erste Teil des Quellcodes stammt aus dem DemoCode.

Ich hab ein File angefügt, indem die Funktionen enthalten sind, wie ich 
sie nutze (Redundants bereits entfernt).
Ich habe in der can_send_message Funktion auch einen Vermerkt gemacht, 
wo bei mir das Problem liegt. Bis auf die Main Funktion stammt der Code 
ebenfalls von kreatives Chaos. Bisher hab ich aber nur Beiträge im Netz 
gefunden, dass das so funktioniert.
Ich weis nicht mehr weiter -.-

Viele Grüße
Stefan

von cskulkw (Gast)


Lesenswert?

Also, das sieht soweit o.k. aus.

In meiner Initialisierung habe ich das zuvor beschriebene Register 
gelesen und mit der Vorgabe verglichen. Erst dann setzt die 
Initialisierung fort.

Ich weiß nicht, ob Du weißt, wo Dein Programm stehen bleibt? Hast Du das 
mal gescheckt? Wie wird der MCP getaktet? externer Quarz oder von 
Mikrocontroler?

Eine Sache noch: Nach dem Reset (Software) 0xC0 mußt Du mal das CANSTAT 
lesen und prüfen, ob 0x100x xxxx vorliegt. Erst dann ist der Controler 
im Konfigurationsmodus. Wenn nicht, dann ist klar, warum er nicht 
sendet. Er ist dann nicht konfiguriert.

Wenn Du keinen Debugger hast, würde ich zunächst auf einen freien Port 
8LEDs anschließen und mit jedem Byte ein Zähler inkrementieren, dann 
weißt Du, wo er hängen bleibt.

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.