1
votes

I have two PIC32MX microcontrollers that are connected over a 1.53MHz SPI bus with Chip Select. I am having trouble getting my slave side interrupt service routine to transmit data correctly. As a test case, I'm having the master send out two bytes (0x01, 0x00) every 10 ms. The slave is supposed to receive the 0x01 command id and respond with a 0x02 when the master sends the 2nd byte (the dummy 0x00).

Ideally each transfer should look like this.
Master Slave
0x01 0x00
0x00 0x02

I'm really not sure where to start with the slave interrupt though. I'm using a fifo buffer called airsysTx to hold data that needs to be shifted out the next time the master makes a request. The slave receives the 0x01 from the master just fine and writes 0x02 to the fifo buffer when it does. I'm not sure how to code the interrupt so that it will be sure to transmit correctly. The code I have below is a good start, but it's wrong. Suggestions?

/*******************************************************************************
 * Interrupt service routine for SPI3 interrupts from Air MCU.
 * The user's code at this vector should perform any application specific
 * operations and MUST clear the SPI3 interrupt flags before exiting.
 ******************************************************************************/
void    __ISR(_SPI_3_VECTOR, ipl7) _SPI3Interrupt()
{
    BYTE MasterCMD;

    SET_D1();//Set debug LED


    // RX INTERRUPT
    if(IFS0bits.SPI3RXIF) // receive data available in SPI3BUF Rx buffer
    {
        MasterCMD = SPI3BUF;
        if(AirCMD == 0x01)
        {
            airsysTxFlush();
            airsysTxWrite(0x02);
        }
    }

    //Transmit data if needed.
    if(SPI3STATbits.SPITBE)
    {
        if(!airsysTxIsEmpty())
        {
            SPI3BUF = airsysTxRead();
        }
        else
        {
            //Else write 0 to the tx buffer to clear the spi shift reg
            SPI3BUF = 0x00;
        }
    }


    IFS0bits.SPI3RXIF = 0;
    IFS0bits.SPI3TXIF = 0;
    IFS0bits.SPI3EIF = 0;
    SPI3STATbits.SPIROV = 0;// clear the Overflow
    CLEAR_D1();//CLEAR Debug LED

} // end ISR

What this code is actually transmitting is something like this:

Ideally each transfer should look like this.
Master Slave
0x01 0x02
0x00 0x01

1

1 Answers

1
votes

Generally you can't write a slave SPI driver to interact in the way you describe because you can't control the timing precisely as a slave. What generates your ISR, is it Rx of first byte from master or assertion of chip select?

As the slave, you need to have set up the data bytes you want to transmit before the master starts the transaction. You usually don't have time to react to the first byte. There are a couple of ways to do this:

1) You could use a protocol where master does a 1 or 2 byte write-only transaction that tells the slave what it wants to read. Then master waits a few milliseconds to allow the slave to prepare the response. Then master does a read-only transaction to get the slave response.

2) If using DMA or FIFO, slave preloads the first padding byte(s) into the fifo before master starts the transaction. Then as you get the ISR you put the remaining response data into the fifo (without a flush). You need to have enough pad bytes to accommodate the slave ISR latency in forming the response. So for example, you may define your protocol where master knows that the first N bytes of response are pad bytes, followed by response data. Padding requirement would depend on your master clock speed and slave CPU speed/interrupt latency.