pic24h SPI Problem

Started by demolitron June 20, 2009
Hello again,

I think I've exhausted myself over this one. SPI is supposed to be REALLY simple, right? But, I can not get my SPI slave (PIC24) to do even recognize that SPI is happening at all.

Here is the rest of the story:

My project has two MCU's in it. A dsPIC30F3012 that reads the sensors and performs all the fun DSP stuff. It is the SPI Master and spits out data for the PIC24HJ64GP504 who will use that sensor data to control a watercraft.

Because I needed the analog inputs on the dsPIC I am forced to do software SPI on it. No problem, I setup an interrupt driven SPI master using Timer1. I've attached the code I've been using for testing it below.

Now I've verified and re-verified that the PCB traces are good and that the Clock and Data signals are making it from the dsPIC into the PIC24. Both parts are 3.3V driven and there is nothing but copper from pin to pin. I will be using the Slave Select feature later, but for testing purposes I am not.

I believe my PIC24 is good as I've gotten the UARTs to work. That also makes me believe that I am doing the PPS stuff and Oscillator switching right.

Please someone, shine a light on this for me. =) I am using the MPLAB C30 compiler and a PicKit2 debugger.
Here is the PIC24H code:
CODE

#include

unsigned int flag, token;

int main(void)
{
//Setup Ports & PPS
{
TRISA= 0b0000000000000000;
TRISB= 0b0111000010000000;
TRISC= 0b0000001000100000;

__builtin_write_OSCCONL(OSCCON & ~(1<<6));

//SPI2 - Slave
RPINR22bits.SDI2R; //RP12 - Data Input
RPINR22bits.SCK2R; //RP13 - Clock Input
RPINR23bits.SS2R; //RP14 - Slave Select Input

__builtin_write_OSCCONL(OSCCON | (1<<6));
}

//Set clock to External PLL @ 40MIPS w/ 10MHz EC Clock
{
PLLFBD0;
CLKDIVbits.PLLPOST=0;
CLKDIVbits.PLLPRE=0;
__builtin_write_OSCCONH(0x03);
__builtin_write_OSCCONL(0x01);
while (OSCCONbits.COSC != 0b011);
while(OSCCONbits.LOCK!=1);
}

//Setup SPI2
{
SPI2BUF=0;
SPI2CON1bits.MODE16=1;
SPI2STATbits.SPIROV=0;
SPI2STATbits.SPIEN=1;
}

while(1)
{
while(!SPI2STATbits.SPIRBF);
token=SPI2BUF; //Break Point is SET HERE
if (SPI2STATbits.SPIROV) SPI2STATbits.SPIROV=0;
}

return(0);
}

I set a breakpoint at the commented code above and it never breaks. SFR Watching reveals that the SPIRBF flag never get set, nothing gets set...
And here is the dsPIC Code:
CODE

#include

#define SCK LATCbits.LATC13
#define SDO LATCbits.LATC14
#define SS LATDbits.LATD0

volatile unsigned int SPITX;
volatile char SPIState;

unsigned int delay;

void __attribute__((interrupt,no_auto_psv)) _T1Interrupt(void);
void send_word(unsigned int dat);

void __attribute__((interrupt,no_auto_psv)) _T1Interrupt(void)
{
TMR1=0;
switch (SPIState)
{
case 32 : SCK=1; if(SPITX & 0b1000000000000000) SDO=1; else SDO=0; SPIState--; break;
case 31 : SCK=0; SPIState--; break;
case 30 : SCK=1; if(SPITX & 0b0100000000000000) SDO=1; else SDO=0; SPIState--; break;
case 29 : SCK=0; SPIState--; break;
case 28 : SCK=1; if(SPITX & 0b0010000000000000) SDO=1; else SDO=0; SPIState--; break;
case 27 : SCK=0; SPIState--; break;
case 26 : SCK=1; if(SPITX & 0b0001000000000000) SDO=1; else SDO=0; SPIState--; break;
case 25 : SCK=0; SPIState--; break;
case 24 : SCK=1; if(SPITX & 0b0000100000000000) SDO=1; else SDO=0; SPIState--; break;
case 23 : SCK=0; SPIState--; break;
case 22 : SCK=1; if(SPITX & 0b0000010000000000) SDO=1; else SDO=0; SPIState--; break;
case 21 : SCK=0; SPIState--; break;
case 20 : SCK=1; if(SPITX & 0b0000001000000000) SDO=1; else SDO=0; SPIState--; break;
case 19 : SCK=0; SPIState--; break;
case 18 : SCK=1; if(SPITX & 0b0000000100000000) SDO=1; else SDO=0; SPIState--; break;
case 17 : SCK=0; SPIState--; break;
case 16 : SCK=1; if(SPITX & 0b0000000010000000) SDO=1; else SDO=0; SPIState--; break;
case 15 : SCK=0; SPIState--; break;
case 14 : SCK=1; if(SPITX & 0b0000000001000000) SDO=1; else SDO=0; SPIState--; break;
case 13 : SCK=0; SPIState--; break;
case 12 : SCK=1; if(SPITX & 0b0000000000100000) SDO=1; else SDO=0; SPIState--; break;
case 11 : SCK=0; SPIState--; break;
case 10 : SCK=1; if(SPITX & 0b0000000000010000) SDO=1; else SDO=0; SPIState--; break;
case 9 : SCK=0; SPIState--; break;
case 8 : SCK=1; if(SPITX & 0b0000000000001000) SDO=1; else SDO=0; SPIState--; break;
case 7 : SCK=0; SPIState--; break;
case 6 : SCK=1; if(SPITX & 0b0000000000000100) SDO=1; else SDO=0; SPIState--; break;
case 5 : SCK=0; SPIState--; break;
case 4 : SCK=1; if(SPITX & 0b0000000000000010) SDO=1; else SDO=0; SPIState--; break;
case 3 : SCK=0; SPIState--; break;
case 2 : SCK=1; if(SPITX & 0b0000000000000001) SDO=1; else SDO=0; SPIState--; break;
case 1 : SCK=0; SPIState--; break;
case 0 : SCK=0; SDO=0; break;
default : SCK=0; SDO=0; SPIState=0; break;
}
IFS0bits.T1IF=0;
}

int main(void)
{
ADPCFG = 0b0000000000110000; //AN4 & AN5 Digital Inputs Other are Analog
TRISB0000000011001111;
TRISC0000000000000000;
TRISD0000000000000000;

SCK=0;
SDO=0;
SS=1;

SPITX=0;
SPIState=0;
PR1000;
TMR1=0;

IFS0bits.T1IF=0;
IEC0bits.T1IE=1;
T1CONbits.TON=1;

while(1)
{
send_word(0xFF00);
while(delay--);
send_word(0xAAAA);
while(delay--);
send_word(0x00);
while(delay--);
}
return(0);
}

void send_word(unsigned int dat)
{
SPITX;
SPIState2;
while(SPIState);
}

I'll bet that SPI code is a little heavy handed and could be done more elegantly...

Here is the trace of the Data and Clock lines. Top trace is clock, bottom trace is data. Here I am sending out data word 0xAAAA. Looks good to me. Clock speed is around 10KHz as I've seriously slowed it down. I've tried it at 100KHz as well.

http://img13.imageshack.us/img13/227/img00004x.jpg

Thanks for your Help!

----- Original Message -----
From: demolitron
To: p...
Sent: Saturday, June 20, 2009 9:12 AM
Subject: [SPAM] [piclist] pic24h SPI Problem

Hello again,

I think I've exhausted myself over this one. SPI is supposed to be REALLY
simple, right? But, I can not get my SPI slave (PIC24) to do even recognize
that SPI is happening at all.
I always do a simple loop-back test if I have problems, and also use a
little PCB I've made with a 74HC595 and eight LEDs driven from the outputs.
The 'HC595 is SPI-compatible. Once I've established that the device is
transmitting and receiving properly, I can then find out why the other end
isn't working.

Leon

--- In p..., "demolitron" wrote:

> Now I've verified and re-verified that the PCB traces are good and that the Clock and Data signals are making it from the dsPIC into the PIC24. Both parts are 3.3V driven and there is nothing but copper from pin to pin. I will be using the Slave Select feature later, but for testing purposes I am not.
>

But you do make slave select active, right? Then there is the matter of slave select polarity and, in some cases, slave select is used to 'frame' the data. That is, slave select is REQUIRED to be inactive between bytes (words), go active during receipt and go inactive at the end of the frame.

Now, I don't know ANYTHING about the PIC24 or dspPIC so take all of this with a huge helping of salt. But look at the PIC24 end, read through the documentation and, in particular, look at the timing diagram for the mode you have picked (based on clock polarity, in general). The timing diagram may very well indicate that the data is to be 'framed' by slave select.

Richard