0

I am writing code to receive SPI data in an interrupt service routine on a PIC18F2680 microcontroller that is running at 40MHz that needs to receive 2 bytes (16 bits) of data from another microcontroller. The PIC only receives data (passively listening), and does not send anything back to the sender. The two data lines that are used MISO, and SCLK on the device. There was no slave select used in the SPI communication, and MOSI is not necessary for listening to the commands, only the slaves responses.

I did not realize at the time of design that the SPI data packets were sent 16 bits at a time, otherwise I would have used a different microcontroller.

I wanted to see if there was a way to read in two consecutive bytes in a SPI ISR without losing any data. My current implementation:

OpenSPI(SLV_SSOFF,MODE_00,SMPMID);

    //***********************************SPI ISR*********************************
#pragma code InterruptVectorHigh = 0x08 
void InterruptVectorHigh (void) 
{ 
  _asm 
    goto InterruptHandlerHigh //jump to interrupt routine 
  _endasm 
} 

//---------------------------------------------------------------------------- 
// High priority interrupt routine 

#pragma code 
#pragma interrupt InterruptHandlerHigh 
void InterruptHandlerHigh () {
    unsigned int next;
    //the interrupt flag is set for SPI
    if(PIR1bits.SSPIF ==1){
        spiByte1 = SSPBUF;
        while(SSPSTATbits.BF != 0);
        spiByte2 = SSPBUF;
    }
    PIR1bits.SSPIF = 0;
}

However, this seems to be getting some correct data, but losing a lot of other bytes. Is there a better way to accomplish this, or am I SOL using an 8-bit MCU?

Thank you,

John

user2339652
  • 19
  • 1
  • 4
  • Isn't the condition in the while loop wrong? Shouldn't you be waiting until the buffer is full (BF is 1)? As it is now it waits until BF==0, which should be true immediately (i.e. no wait). – avl_sweden May 09 '15 at 17:04

1 Answers1

0

The nature of SPI bus is symetrical meaning that each data transfer on the SPI port is simultaneously a transmission and a reception.The master sends a bit on the MOSI line and the slave reads it, while the slave sends a bit on the MISO line and the master reads it. This sequence is maintained even when only one-directional data transfer is intended.

I have implemented an 8, a 12 and a 16bit data transfers but not as interrupt code, I think putting it in a pure interrupt can be a bit tricky but this may me

Read the following which is from Microchip PIC and was great help for me when I had trouble understanding the SPI bus.
Overview and Use of the PICmicro Serial Peripheral Interface

If it helps, I'm sharing with you some code of mine for reading a temprature value in 12bit from a MAX6675 SPI device connected to a PIC. This is not done in an interrupt and is just one of the millions of applications you can have, I just had it handy and I'm presenting it here as it may be of some help if you study it.

unsigned int spi_temp(void)         // Read the temp from MAX6675 connected to SPI output is (12bit)
{
unsigned int spi_12bit;             // specify an int so can hold the 12bit number
CHIP_EN = 0 ;                       // Enable SPI on MAX6675. (When Low enables the Max6675 and stops any conversion process)
__delay_ms(1);                      // Small delay required by MAXX6675 after enabling CS (Chip Select)
SSPIF = 0;                      // Clear Master Synchronous Serial Port Flag
spi_12bit = SSPBUF;                 // Read Buffer to clear it and to reset the BF Flag
SSPBUF = 0b10101010;                // Loading the Buffer with some data junk to start transmision (We're not sending them anywhere)

while (!SSPIF) continue;            // wait until data is clocked out
spi_12bit = (0b01111111 & SSPBUF)<<8;   // Read the Buffer with the fresh first 8bit DATA from MAX6675 
                                        // disregard MSB bit of unimportant data and shift it left
SSPIF = OFF;                        // Clear Flag to get ready for the next 8bit DATA

SSPBUF = 0b10101010;                // Load the Buffer with more junk data
while (!SSPIF) continue;            // wait until data is clocked out
SSPIF = OFF;                        // Clear the Flag

spi_12bit = spi_12bit | SSPBUF;     // Read the Buffer with the other 8bit data and keep it as a 16bit variable
spi_12bit = spi_12bit >>3;          // We disregard the leftmost 3 bits on unimportant Data according to Datasheet
CHIP_EN = 1 ;                       // disabling CS (Chip Select). Let MAX6675 continue conversion processreading
delay_200ms(1);                     // Small delay required by MAXX6675 to do conversion typ 0.2sec
spi_12bit = (int)(spi_12bit * 0.25);//(reading in 12bit * 1024 total steps / 4096;
return spi_12bit;

}   // spi_temp

This is just an example, hope it can be of help understanding how SPI works.