Electronics > Microcontrollers

pic24 spi slave MISO function

(1/2) > >>

Using a pic24f04ka200 as a slave to another micro.

Reception from master is good.  But when I write data to SPI1BUF for sending back to master nothing
comes out of SDO1 pin on the next reception.    Pin9 ( SDO1 )  is setup as output.
Can SPI1BUF be written anytime after completion of a transaction.  ( txbuf should always be empty right ? )
Does it matter the state of SS1 line.


--- Code: ---      if(SPI1STATbits.SPIRBF)   // spi recieved a word
          SpiWordHold = SPI1BUF;
          SpiWordRecFlag = 1;
          IFS0bits.SPI1IF = 0;
          if(SpiWordHold == 0x1111)
              DebugBitTimer = 5000;
              asm BSET LATB, #4
          SpiReturnWord = 0x2525;
          SPI1BUF = SpiReturnWord;        // setup return val for next xmission

--- End code ---

setup is

--- Code: ---void SpiSetup(void)
    // slave setup  copied from DS70005185A-page 17
    //**** denotes changes from app note
    SPI1BUF = 0;
    IFS0bits.SPI1IF = 0; // Clear the Interrupt flag
    IEC0bits.SPI1IE = 0; // Disable the interrupt
// SPI1CON1 Register Settings
    SPI1CON1bits.DISSCK = 0; // Internal Serial Clock is enabled
    SPI1CON1bits.DISSDO = 0; // SDOx pin is controlled by the module
    SPI1CON1bits.MODE16 = 1; // Communication is word-wide (16 bits)
    SPI1CON1bits.SMP = 0; // Input data is sampled at the middle of data

    SPI1CON1bits.SSEN = 1;  // needed to enable slave select   ****

// output time.
    SPI1CON1bits.CKE = 1; // Serial output data changes on transition   ****
// from active clock state to idle clock state
    SPI1CON1bits.CKP = 0; // Idle state for clock is a low level; active
// state is a high level
    SPI1CON1bits.MSTEN = 0; // Master mode disabled
    SPI1STATbits.SPIROV=0; // No Receive Overflow has occurred
    SPI1STATbits.SPIEN = 1; // Enable SPI module
// Interrupt Controller Settings
///    IFS0bits.SPI1IF = 0; // Clear the Interrupt flag. don't need interrupt
//    IEC0bits.SPI1IE = 1; // Enable the interrupt


--- End code ---

Well a hail mary pass did the trick.  Not sure why.

I just have to poll this code very frequently.

--- Code: ---     if(!SPI1STATbits.SPITBF)  //  buffer empty ??
        SPI1BUF = SpiReturnWord;

--- End code ---

Datasheet could use some work explaining this.  If anyone sees where this is clearly explained please reply.


Since the data is exchanged during the SPI transaction, you must write data before the transaction (otherwise there will be nothing to transmit during the transaction), then read data after the transaction (because the data do not exist yet until the transaction is complete). I don't see how this could be any other way.

Consider that when the RX isr it's being triggered your micro will switch to the isr in about 20-30 cycles, by that time the spi exchange has already happened, and if you did not fill in the data beforehand you will send a wrong answer to the master.  You can do some stuff to improve for example:
a) You can enable enhanced buffer if it's available for your PIC family and you will have a FIFO of 8 words to fill in the response. 
b) Fill in the queue beforehand
c) On your main poll the buffer queue empty bit to fill it again until all data has been transmitted
d) Make SPI transfer on the master as slow as possible
e) Run SPI slave at a higher frequency if your application allows it
f) Use circular buffers to handle the queues

Its kinda hard to get proper synchrony by pure SPI, on some implementations that I have done I had to use other pins to signal to the master when the response is ready, so for example in the first stage the master sends a cmd over spi, upon ISR reception on the PIC slave it turns on a "busy" pin, the slave has all the time that it requires to fill in the response buffer and then turn off the "busy" pin so the master can start exchanging more bytes to read the response.

You can view an SPI transfer as beginning with the /CS line going low. So you could allocate a GPIO pin on the PIC slave as a /CS line and the full protocol would be:

1. master brings the /CS line low
2. master waits X number of microseconds
3. master initiates SPI transfer

The wait in step 2 gives the PIC slave time to load the SPI transfer registers with the data that it wants to return.


[0] Message Index

[#] Next page

There was an error while thanking
Go to full version