Forum: Mikrocontroller und Digitale Elektronik SPI Problem mit MCP2515


von Philipp C. (ba4_philipp)


Lesenswert?

Hallo,

ich habe einige Module mit einem Mega8 und MCP2515 gebaut. Allerdings 
funktioniert die Kommunikation nur mit 125kbit/s (auf dem SPI).
Ich habe den Mega8 mit dem internen RC Oszillator auf 8MHz laufen, der 
MCP2515 hat einen 16 MHz Quarz.
Wenn ich nun den SPI Teiler auf 64 stelle funktioniert alles, aber 
sobald ich auf /32 gehe kann ich keine Register im MCP2515 mehr lesen.
Aufgebaut ist es auf verschiedenen Platinen (geätzt und Lochstreifen). 
Das SCK Signal sieht bei 250 kHz genauso sauber aus wie bei 125kHz (MOSI 
auch). Laut Datenblatt kann der SPI vom MCP2515 bis 10 MHz (125kHz wären 
ja auch nicht wirklich sinnvoll, wenn er CAN mit 1MBit/s machen soll :) 
)

Hat jmd ne Idee woran das liegen kann? Muss man evtl. den SPI am Mega 
noch anders konfigurieren?

Vielen Dank schonmal
Gruß Philipp

von crazy horse (Gast)


Lesenswert?

ich habe den MCP2515 in einigen Applikationen drin.
Im zeitkritischsten Fall (2x500kBit-CAN) läuft der Mega32 mit 16MHz, die 
SPI mit 8MHz. Übrigens völlig problemlos.

// SPI initialization
// SPI Type: Master
// SPI Clock Rate: 2*4000,000 kHz
// SPI Clock Phase: Cycle Half
// SPI Clock Polarity: Low
// SPI Data Order: MSB First
SPCR=0x50;
SPSR=0x01;

von Philipp C. (ba4_philipp)


Lesenswert?

Hmm, so hab ich meinen SPI auch konfiguriert (bis auf die Teiler, da hab 
ich schon alles Mögliche probiert).
Wenigstens weiß ich nun, dass es so passen sollte.

Vielen Dank
Gruß Philipp

von crazy horse (Gast)


Lesenswert?

und was machst du mit dem CS?

von Philipp C. (ba4_philipp)


Lesenswert?

CS hab ich auf 1 und bevor ich schreibe/lese ziehe ich CS auf 0 und am 
Ende wieder hoch. Wie gesagt bis 125kHz SPI Takt funzt es auch nur 
darüber nicht mehr

von crazy horse (Gast)


Lesenswert?

naja, so soll es ja auch sein. Aber ohne Schaltung und Software wird dir 
keiner weiterhelfen können...

von Andreas K. (a-k)


Lesenswert?

Wenn es bei allen funktioniert (9,x MHz), nur bei dir nicht, was sagt 
dir das?

von Philipp C. (ba4_philipp)


Lesenswert?

Was sollte mir das sagen Andreas? Das es bis 10MHz gehen sollte hab ich 
bereits oben erwähnt, aber trotzdem vielen Dank für Deinen überaus 
hilfreichen Beitrag...

@crazy horse: Also die Schaltung besteht nur aus Mega8 und MCP2515 am 
CAN. CS vom MCP2515 ist an PB2 (das ist /SS am Mega8 sollte aber denke 
ich kein Problem sein, weil es als Ausgang konfiguriert ist), der Rest 
ist halt am HW SPI.

Die Software ist nach dem Beispiel von kijon:

void spi_init(void)
{
  DDR_SPI   |= (1<<P_SCK)|(1<<P_MOSI);
  PORT_SPI &= ~((1<<P_SCK)|(1<<P_MOSI)|(1<<P_MISO));
  DDR_CS   |= (1<<P_CS);
  PORT_CS  |= (1<<P_CS);
  SPCR = (1<<SPE)|(1<<MSTR)|(1<<SPR1); //SPR1 gesetzt für clk/32
  SPSR = (1<<SPI2X);
}

uint8_t spi_putc( uint8_t data )
{
  SPDR = data;
  while( !( SPSR & (1<<SPIF) ) );
  return SPDR;
}

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);
}

uint8_t mcp2515_read_register(uint8_t adress)
{
  uint8_t data;
  PORT_CS &= ~(1<<P_CS);

  spi_putc(SPI_READ);
  spi_putc(adress);

  data = spi_putc(0xff);

  PORT_CS |= (1<<P_CS);
  return data;
}

Nach dem Einschalten mache ich einen Software Reset. Was daran etwas 
komisch ist, dass es bis zu einem bestimmten Takt funktioniert oder ist 
da evtl. ein Fehler der aus irgendwelchen Gründen bei kleinen Frequenzen 
nicht zum Tragen kommt?

von crazy horse (Gast)


Lesenswert?

tja, das deckt sich im wesentlichen mit dem, was ich verwende.
Die Funktion read_register habe ich allerdings nie verwendet (und auch 
noch keine Verwendung dafür gehabt), da kann ich dir also nicht sagen, 
ob die so auch so funktioniert.
Ich benutze nur get_message (welche wiederum nur 
mcp2515_read_rx_status() benutzt), send_message, bit_modify und init.

von Philipp C. (ba4_philipp)


Lesenswert?

Ich habe eben mal die init routine auskommentiert und nur einfach den 
Soft Reset gesendet dann funktioniert es. Das Problem scheint also da zu 
liegen.

void mcp2515_init(void)
{
  // SPI Interface initialisieren
  spi_init();

  // MCP2515 per Software Reset zurücksetzten,
  // danach ist der MCP2515 im Configuration Mode
  PORTB &= ~(1<<SPI_CS);
  spi_putc( SPI_RESET );
  PORTB |= (1<<SPI_CS);

  // BRP = 7 für 125 kbit/s
  mcp2515_write_register( CNF1, (1<<BRP0)|(1<<BRP1)|(1<<BRP2) );

  // Prop Seg und Phase Seg1 einstellen
  mcp2515_write_register( CNF2, (1<<BTLMODE)|(1<<PHSEG11) );

  // Wake-up Filter deaktivieren, Phase Seg2 einstelen
  mcp2515_write_register( CNF3, (1<<PHSEG21) );

  // Aktivieren der Rx Buffer Interrupts
  mcp2515_write_register( CANINTE, (1<<RX1IE)|(1<<RX0IE) );

  // Buffer 0 : Empfangen aller Nachrichten
  mcp2515_write_register( RXB0CTRL, (1<<RXM1)|(1<<RXM0) );

  // Buffer 1 : Empfangen aller Nachrichten
  mcp2515_write_register( RXB1CTRL, (1<<RXM1)|(1<<RXM0) );

  // Alle Bits der Empfangsmaske löschen,
  // damit werden alle Nachrichten empfangen
  mcp2515_write_register( RXM0SIDH, 0 );
  mcp2515_write_register( RXM0SIDL, 0 );
  mcp2515_write_register( RXM0EID8, 0 );
  mcp2515_write_register( RXM0EID0, 0 );

  mcp2515_write_register( RXM1SIDH, 0 );
  mcp2515_write_register( RXM1SIDL, 0 );
  mcp2515_write_register( RXM1EID8, 0 );
  mcp2515_write_register( RXM1EID0, 0 );

  // Device zurück in den normalen Modus versetzten
  mcp2515_bit_modify( CANCTRL, 0xE0, 0);
}

von Andreas K. (a-k)


Lesenswert?

Tip für Initialisierung von Ports, muss aber nicht für das Problem 
relevant sein: immer erst die Daten setzen, dann die Richtung. Obiger 
Code sorgt beispielsweise dafür, dass CS kurz aktiv ist, weil der Pin 
erst als Ausgang aktiviert, dann auf 1 gesetzt wird.

Apropos CS: externer Pullup empfohlen, damit inaktiv wenn der µC noch 
nicht initialisiert ist.

von crazy horse (Gast)


Lesenswert?

habe ich jetzt keine Lust, das einzeln durchzuklamüsern.
Hier "meine" init, die funktioniert.
Nicht von CAN_sw verunsichern lassen, dass kommt nur davon, dass 2 
MCP2515 an der SPI hängen.

//|========================== MCP2515 Initialisation 
==========================|
void mcp2515_init(unsigned char CNF1_val, unsigned char CNF2_val, 
unsigned char CNF3_val)
{
  if (!CAN_sw)  PORTB &= ~(1<<SPI_CS1);    // CS low
      else PORTB &= ~(1<<SPI_CS2);     //|------------- MCP2515 per 
Software Reset zurücksetzten -----------|
  spi_putc( SPI_RESET );
  PORTB |= (1<<SPI_CS1 | 1<<SPI_CS2);      // CS high


//|---------- Device in den Konfigurations Modus versetzten ---------|
//|-------------------- CLKOUT Pin deaktivieren ---------------------|
   mcp2515_bit_modify( CANCTRL, 0xE0, (1<<REQOP2) );


//|------------------- Einstellen des Bit Timings -------------------|


// 10kbit @16MHz
   //prescaler
   mcp2515_write_register( CNF1, CNF1_val); //0x1f);

   // Prop Seg und Phase Seg1 einstellen
   mcp2515_write_register( CNF2, CNF2_val); //0xbf );

   // Phase Seg2 einstelen
   mcp2515_write_register( CNF3, CNF3_val); //0x07 );


//|-------------- Einstellen der Rx Buffer Interrupts ---------------|
   mcp2515_write_register( CANINTE, (1<<RX1IE)|(1<<RX0IE) );


//|--------------------- Buffer Operating Mode ----------------------|
   // Buffer 0 : Empfangen aller Nachrichten, Infos Datasheet S.27
   mcp2515_write_register( RXB0CTRL, (1<<RXM1)|(1<<RXM0) );

   // Buffer 1 : Empfangen aller Nachrichten, Infos Datasheet S.28
   mcp2515_write_register( RXB1CTRL, (1<<RXM1)|(1<<RXM0) );


// Alle Bits der Empfangsmaske löschen,
  // damit werden alle Nachrichten empfangen
  mcp2515_write_register( RXM0SIDH, 0 );
  mcp2515_write_register( RXM0SIDL, 0 );
  mcp2515_write_register( RXM0EID8, 0 );
  mcp2515_write_register( RXM0EID0, 0 );

  mcp2515_write_register( RXM1SIDH, 0 );
  mcp2515_write_register( RXM1SIDL, 0 );
  mcp2515_write_register( RXM1EID8, 0 );
  mcp2515_write_register( RXM1EID0, 0 );

// Deaktivieren der Pins RXnBF Pins ( High Impedance State )
  mcp2515_write_register( BFPCTRL, 0 );

  // TXnRTS Bits als Inputs schalten
  mcp2515_write_register( TXRTSCTRL, 0 );


//|--------- Device zurück in den normalen Modus versetzten ---------|
//mcp2515_bit_modify( CANCTRL, 0xE0, 0);
//|--------- Device zurück in den listen-Modus versetzten ---------|
//CLK_OUT on, prescaler 1
// mcp2515_bit_modify( CANCTRL, 0xE7, (1<<REQOP1 | 1<<REQOP0|1<<CLKEN));
//|--------- Device zurück in den normalen Modus versetzten ---------|
//CLK_OUT on, prescaler 1
mcp2515_bit_modify( CANCTRL, 0xE7, (1<<CLKEN));
}

von Philipp C. (ba4_philipp)


Lesenswert?

Vielen Dank, ich werde das mal vergleichen.
Auch das mit dem Pullup werde ich mal probieren. Das es im Master 
Betrieb Probleme mit dem /SS Pin geben kann hab ich im Datenblatt leider 
erst gelesen, als es schon verdrahtet war.

Vielen Dank für Eure Hilfe
und gute Nacht

von Andreas K. (a-k)


Lesenswert?

Was hängt denn an SS dran?

von Philipp C. (ba4_philipp)


Lesenswert?

Am SS hängt CS vom MCP2515 ist aber als Ausgang konfiguriert und auf 
high, wenn der Mega8 nicht mit dem MCP redet.

Ich habe eben mal in meine Init nach dem SoftReset eine kleine Wartezeit 
eingebaut (hab einfach mit 4k8 was auf dem uart ausgeben) und nun 
scheint es zu gehen? Bei crazy horse ist ja allerdings keine Wartezeit 
nach dem Reset.

Edit: Es ist reproduzierbar:

PORTB &= ~(1<<SPI_CS);
spi_putc( SPI_RESET );
PORTB |= (1<<SPI_CS);

SendStr("bischen warten....");

mcp2515_write_register( CNF1, (1<<BRP0)|(1<<BRP1)|(1<<BRP2) );
...

Nehme ich das "bischen warten" wieder raus funktioniert es nicht mehr

von Markus B. (wolframator)


Lesenswert?

Hallo,

seit ich den CKDIV8 von meinem 644 "ausgeschaltet" habe und statt mit 
1MHz mit 8MHz alles laufen lasse hab ich einige Probleme mit dem SPI... 
Das Interessante ist das es mal geht und mal geht es nicht. Was ja in 
der digitalen Welt schon seltsam ist :/

Ab der Zeile "spi_putc(SPI_WRITE);" bleibt alles stehen. :( Ich hab kein 
Plan warum...
1
//SPI Master Interface aktivieren (Register SPCR, SPSR and SPDR)
2
//Atmega 644 20PU.pdf Seite 161
3
//SPR1, SPR0 = SPI Clock Rate Select
4
//F_CPU =  8MHz -> SPR1=1 SPR0=0 -> F_CPU /  64
5
SPCR = (1<<SPE)|(1<<MSTR) | (1<<SPR1)|(0<<SPR0);
6
SPSR = 0;
7
8
//PIN MCP2515_CS als Ausgang definieren
9
SET_OUTPUT(MCP2515_CS);
10
//SPI-CS auf Hi setzen (Hi=SPI auf Zielkomponente inaktiv)
11
SET(MCP2515_CS);
12
13
//PIN P_SCK und P_MOSI als Ausgang definieren
14
SET_OUTPUT(P_SCK);
15
SET_OUTPUT(P_MOSI);
16
//Rücksetzen der Pins P_SCK und P_MOSI
17
RESET(P_SCK);
18
RESET(P_MOSI);
19
20
//PIN P_MISO als Eingang definieren
21
SET_INPUT(P_MISO);
22
RESET(P_MISO);
23
24
//PIN MCP2515_INT als Eingang definieren
25
SET_INPUT(MCP2515_INT);
26
SET(MCP2515_INT);
27
28
//SPI-CS auf Lo setzen (Lo=SPI auf Zielkomponente aktiv)
29
RESET(MCP2515_CS);
30
//MCP 2515 per SPI resetten um ihn in den Konfigurationsmodus zu bringen
31
spi_putc(SPI_RESET);
32
//SPI-CS auf Hi setzen (Hi=SPI auf Zielkomponente inaktiv)
33
SET(MCP2515_CS);
34
35
//10µs warten bis der Reset vom MCP 2515 durchgeführt wurde >>> 2µs sind minimum
36
//(MCP 2515-I-P.pdf Seite 55)
37
_delay_us(10);
38
39
//SPI-CS auf Lo setzen (Lo=SPI auf Zielkomponente aktiv)
40
RESET(MCP2515_CS);
41
42
//Die Konfigurationsregister laden (CNF1, CNF2 und CNF3)
43
//(MCP 2515-I-P.pds Seite 57)
44
spi_putc(SPI_WRITE);

von Andreas K. (a-k)


Lesenswert?

Dein PC scheint an dieser Zeile auch zu verzweifeln. Oder wie ist es zu 
verstehen, dass der Quelltext genau da endet und auch sonst reichlich 
unvollständig ist (lies: zur Analyse unbrauchbar).

Und weil das bis auf den Chip nichts mit diesem Thread zu tun hat: Mach 
einen neuen Thread auf.

von Markus B. (wolframator)


Lesenswert?

Egal was nach der letzten Zeile von mir kommt wird nicht mehr 
ausgeführt... Und wie man hier im Thread sehen kann hängt es an der 
gleichen Stelle auch bei anderen. Warum sollte mein Problem denn ein 
anderes sein?

von Andreas K. (a-k)


Lesenswert?

Lies dir mal im Datasheet das Kapitel über den SS-Pin im Master-Betrieb 
durch. Und dann überleg, was passieren kann, wenn zuerst MSTR=1 und 
danach erst SS=Output programmiert wird.

von Markus B. (wolframator)


Lesenswert?

Arg, sch****... Man sollte sein Quellcode natürlich nicht kaputt 
optimieren. Hatte das in unterschiedlichen Funktionen stehen und hatte 
das heute zusammengeführt und die Reihenfolge wohl vertauscht... Thx! 
Geht jetzt wieder wie bisher :) Dachte schon das würde an der Umstellung 
der Geschwindigkeit liegen. selbst-paddel

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.