Sida 1 av 1

Problem med SPI mellan PIC18F4550 och MCP2515

Postat: 30 januari 2011, 16:14:44
av kriba150
Hej!

Jag har lite problem med att skriva till registren i CAN-controllern MCP2515. Jag använder HI-TECH C kompilatorn tillsammans med MPLAB och SPI funktionerna är mina egna. Problemet är att när jag försöker skriva till ett register och sedan läsa registret igen får jag tillbaka 0x00, 0xFF eller något annat random. Jag provade därför att skriva ett litet program i mikroC och använde det inbyggda biblioteket för SPI men mina egna funktioner för att skriva till CAN-controllern och fick då tillbaka rätt data. Sedan provade jag att använda min egen init-kod för SPI modulen och min egen Read funktion vilket också fungerar. Men använder jag min egen Write funktion funkar det inte varefter det borde vara något fel i denna men jag vet inte vad.

Koden jag använder mig av är:

Kod: Markera allt

// =========================
//  CAN
// =========================

LATB.RB3 = 0;        // Chip Select
SPI1_Write(0x05);    // Bit Modify Command
SPI1_Write(0x0F);    // Address
SPI1_Write(0xE0);    // Mask
SPI1_Write(0x40);    // Data (Loopback Mode)
LATB.RB3 = 1;        // Chip Select
    
LATB.RB3 = 0;        // Chip Select
SPI1_Write(0x03);    // Read Command
SPI1_Write(0x0E);    // Address
OperationMode = SPI_Read(0x00);          // Read data
LATB.RB3 = 1;        // Chip Select


// =========================
//  SPI
// =========================

void SPI_Init(void)
  {
  SSPCON1.SSPEN = 0;  // Disable serial port
  SSPCON1 = 0x01;     // Master mode, Fosc/16
  
  SSPCON1.CKP = 0;    // Mode 0,0
  SSPSTAT.CKE = 1;
  
  SSPSTAT.SMP = 0;    // Data sampled at middle
  SSPCON1.SSPEN = 1;  // Enable serial port
  }

unsigned char SPI_Read(unsigned char DummyData)
  {
  SSPBUF = DummyData;
  while (!SSPSTAT.BF);
  return (SSPBUF);
  }

void SPI_Write(unsigned char Data)
  {
  unsigned char Temp;

  SSPBUF = Data;
  while (!SSPSTAT.BF);
  Temp = SSPBUF;
  }
Använder en 20 MHz kristall med 22 pF kondingar till CAN-controllern och kör PICen i 48 MHz (använder USB också).

Tacksam för all hjälp jag kan få!

Re: Problem med SPI mellan PIC18F4550 och MCP2515

Postat: 30 januari 2011, 16:30:27
av sodjan
Några småsaker bara...

Normalt är det effektivare (man väntar inte i onödan, så att säga)
att testa BF flaggen först innan man skriver till SSPBUF. Det är även
så som exemplen i databladet gör. Någon speciell anledning till att du
inte gör som exemplet i databladet ?

Jag har för mig att det ska finnas källkod till MicroC's libbar.
I alla fall så borde det göra det...

Om inte annan så borde du kunna kolla maskinkoden efter länkning
för att kolla vad MikroC gör. Du kör alltså "SPI Library", inte
"Software SPI Library" !?

Re: Problem med SPI mellan PIC18F4550 och MCP2515

Postat: 30 januari 2011, 21:39:59
av kriba150
Någon speciell anledning till att du inte gör som exemplet i databladet ?
Nej, det kan jag inte påstå. Kan bero på att jag är totalt oduglig när det gäller assembler och har lite problem att tyda exemplet utan flertalet sökningar på internet.

Du kör alltså "SPI Library", inte "Software SPI Library" !?
Precis, jag använder hårdvarubiblioteket.

Jag har för mig att det ska finnas källkod till MicroC's libbar.
Jag har letat men inte hittat något tyvärr.

Jag har dock gjort lite framsteg genom att jämföra assemblerkoden som genereras. Min funktion ser ut enligt följande:

Kod: Markera allt

_SPI_Write:

MOVF        FARG_SPI_Write_Data+0, 0 
MOVWF    SSPBUF+0 
L_SPI_Write15:
BTFSC       SSPSTAT+0, 0 
GOTO        L_SPI_Write16
GOTO        L_SPI_Write15
L_SPI_Write16:
RETURN      0

; end of _SPI_Write
och koden från det inbyggda biblioteket ser ut på följande sätt:

Kod: Markera allt

_SPI1_Write:	

MOVFF       FARG_SPI1_Write_data_, SSPBUF	
L_SPI1_Write6:
BTFSC       SSPSTAT, 0 
BRA         L_SPI1_Write7	
NOP
BRA         L_SPI1_Write6
L_SPI1_Write7:		
MOVFF       SSPBUF, R0	
RETURN      0

; end of _SPI1_Write
Inte helt olika i alla fall. Lägger jag till "NOP" och "MOVFF SSPBUF,R0" mha inline asm så fungerar det som det ska. Jag är med på vad NOP gör men inte helt hundra på vad den andra raden gör (jag kan VÄLDIGT lite om asm). Rätta mig om jag har fel men läser den inte bara SSPBUF registret och sparar det i R0? Eller betyder R0 något annat för jag har aldrig definierat en sådan variabel?

Den nya Write funktionen ser ut enligt följande:

Kod: Markera allt

void SPI_Write(unsigned char Data)
  {
  SSPBUF = Data;
  while (SSPSTAT.BF == 0)
    {
    asm NOP;
    }
  asm MOVFF  SSPBUF,R0;
  }
Hur skulle en ekvivalent kod i HI-TECH C kunna se ut? Jag får det nämligen inte att fungera med inline asm i HI-TECH C (MPLAB) då jag får felmeddelande på R0.

Re: Problem med SPI mellan PIC18F4550 och MCP2515

Postat: 30 januari 2011, 23:01:49
av sodjan
> Kan bero på att jag är totalt oduglig när det gäller assembler och har lite problem
> att tyda exemplet utan flertalet sökningar på internet.

Nja, nu så tänkte jag mer på att de testade BF först och sen skrev till SSPBUF.
Inte att du nödvändigtsvis måste skriva även din kod i assembler.
Dock, du bör ju i alla fall kunna *läsa* ett exempel med 4-5 rader kod, även
om det är skrivet i assembler. Hur ska du annars kunna läsa databladet ?

"R0" är sannolikt något intern definition av temorära variabler som MikroC (var
det inte MikroC som du använde) använder. Det är inte säkert att den är
"synlig" för assembler kod, och det är absolut inte säkert (om ens troligt)
att en annan kompilator (t.ex Hi-tech C) skulle råka använda exakt samma
interna namn på slask/temp variabler.

Det är lite märkligt med den där extra NOP i koden. Logiskt så blir det ju
samma funktion på det hela. Kan bara se att det är något timing-rellaterat.

Vad var det mer konkret som var oklart med MOVFF ? Om du t.ex citerar det
i beskrivningen av MOVFF i databladet som inte var helt tydligt så är det
mycket enkare att ge ett bra svar.

Se också punkt 18, 26 och 38 i detta dokument :
http://ww1.microchip.com/downloads/en/D ... 80478a.pdf
Eller, tja, allt som har med MSSP modulen att göra... :-)

Re: Problem med SPI mellan PIC18F4550 och MCP2515

Postat: 31 januari 2011, 00:27:33
av kriba150
Dock, du bör ju i alla fall kunna *läsa* ett exempel med 4-5 rader kod, även om det är skrivet i assembler.
Absolut, det är verkligen dags att titta igenom grunderna till assembler!

"R0" är sannolikt något intern definition av temorära variabler...
Okej, så tanken med raden "MOVFF SSPBUF,R0" är egentligen bara att läsa SSPBUF för att sätta BF = 0 i enlighet med punkt 38 i dokumentet du länkade till?

Se också punkt 18, 26 och 38 i detta dokument...
Har bara kollat igenom dessa punkter lite snabbt och måste säga att där stod en hel del av intresse. Borde ha kollat där tidigare förstås men nu vet jag till nästa gång. Ska prova dessa "Work Arounds" när jag får tid att sätta mig med detta igen.


Tack så mycket för hjälpen så länge, känns som jag är på rätt väg nu i alla fall!

Re: Problem med SPI mellan PIC18F4550 och MCP2515

Postat: 31 januari 2011, 00:43:37
av sodjan
> Okej, så tanken med raden "MOVFF SSPBUF,R0"........

Japp, så tolkar jag det också. De gör en dummy-läsning för
att uppfylla vilkoren/rekomendationerna. Jag tror nog i och för sig
att just *det* även står i det vanliga databladet, om man läser allt om
MSSP modulen ordentligt, men jag har inte tagit mig tid att analyser det.

Just MSSP modulen är något där det har varit en del (lite för mycket
säger en del) skrivet i "Errata" dokumenten... :-)

Man borde ju dock kunna anta att t.ex de som fixat libarna till
MikroC och HiTech-C har lusläst dessa dokument. Och deras rutiner
fungerar ju uppenbarligen.

En sak som inte direkt stog var *varför* det var problem med att läsa
BF flaggan direkt. Tydligen är det OK om man först läser hela registret
och kollar BF-flaggan i kopian av registret.

En annan sak, det är inte säkert att alla punkter i Errata är rellevanta för
de senare versionerna av processorn. Det står under varje punkt. Sen är
deet ofta en annan fråga hur man vet vilken kisel-version man har.... :-)

Re: Problem med SPI mellan PIC18F4550 och MCP2515

Postat: 31 januari 2011, 23:14:31
av kriba150
Jag tror nog i och för sig att just *det* även står i det vanliga databladet
Yes, det gör det! Läser även från SSPBUF efter skrivning i koden som jag postade i första posten men tydligen räckte det inte.

Sen är deet ofta en annan fråga hur man vet vilken kisel-version man har....
Jo, precis den tanken slog mig när jag läste igenom de punkter i Errata du tipsade om. :) För säkerhets skull så uteslöt jag ingen av kisel-versionerna.

Hur som så är problemet löst nu i alla fall. :D För den intresserade så postar jag lösningen som egentligen är samma kod som i exemplet i Errata dokumentet.

Kod: Markera allt

void SPI_WriteByte(unsigned char Data)
   	{
   	unsigned char TempVar;

	// Clear SPI interrupt flag
	PIR1bits.SSPIF = 0;		

	// Reads from SSPBUF, ensures BF bit is clear 
	// before sending the next byte.
	TempVar = SSPBUF;		

	// Load data to send into SSPBUF to initialize
	// transmission
	SSPBUF = Data;	
		
	// Wait until the transmission is complete
	while(!PIR1bits.SSPIF);		
   	}
Stort tack för hjälpen sodjan!

Re: Problem med SPI mellan PIC18F4550 och MCP2515

Postat: 31 januari 2011, 23:24:37
av sodjan
OK, kul att det fungerar ! :-)

Den ända lilla saken jag kan ha imot din lösning, är att du eventuellt
kommer att vänta på att "the transmission is complete" i onödan.
Det kan ju hända att din kod i alla fall har annat att göra medan
senaste byten sänds, och då hade det varit effektivare att vänta
på SSPIF i början av SPI_WriteByte. Eventuellt blir det ingen väntan
alls (om du har haft tillräckligt mycket annat att göra)...

Det borde räcka med att bara flytta upp "while(!PIR1bits.SSPIF);"
några rader och lägga det direkt före "PIR1bits.SSPIF = 0;".

Re: Problem med SPI mellan PIC18F4550 och MCP2515

Postat: 31 januari 2011, 23:36:15
av kriba150
Den ända lilla saken jag kan ha imot din lösning...
Förstår vad du menar. Ändrat det nu, så nu funkar det såklart ännu bättre. :wink: