Author Topic: PIC SPI sending stale data instead of what I want to send  (Read 1126 times)

0 Members and 1 Guest are viewing this topic.

Offline perdrixTopic starter

  • Frequent Contributor
  • **
  • Posts: 634
  • Country: gb
PIC SPI sending stale data instead of what I want to send
« on: January 15, 2022, 10:21:15 am »
This is a dsPIC33FJ12MC201 (should that be relevant).   I'm running a test that returns amongst other things the position of a servo motor which is controlled by the PIC running as an SPI slave.

The SPI data (MISO) sent in response to the first of a sequence of 0xEBEB (Request_PID_Tune) messages should(for this test) always have the value 0x0046 - like this LA trace fragment:

Code: [Select]
Time [s],Packet ID,MOSI,MISO
4.836107562500000,0,0xEBEB,0x3004     <== response to previous message from master
4.836192937500000,0,0xEBEB,0x0046     <== response to 1st 0xEBEB
4.836286250000000,0,0xEBEB,0x9DEE
4.836379625000000,0,0xEBEB,0x02C9
4.836475687500000,0,0xEBEB,0x01C7
4.836569000000000,0,0xFFFF,0x00A5

Sometimes however I get this:

Code: [Select]
Time [s],Packet ID,MOSI,MISO
4.839946000000000,0,0xEBEB,0x11EE
4.840031312500000,0,0xEBEB,0x11EE     <== WHAT ON EARTH?
4.840127375000000,0,0xEBEB,0x9EAD
4.840220750000000,0,0xEBEB,0x02B0
4.840314062500000,0,0xEBEB,0x01D3
4.840407437500000,0,0xFFFF,0x00A3

My code is simple enough:

Code: [Select]
//==============================================================================
//  SPI1 Interrupt data has been received.
//==============================================================================
void _ISR _SPI1Interrupt(void)
{
    uint16_t reply = 0;                 // Reply
    :
    static uint8_t pidState = 0;
    :
    SPI_Received = SPI1BUF;     // Read SPI input into buffer
    :

    if (Request_PID_Tune == SPI_Received)
    {
        switch(pidState)
        {
            case (0):   // First PID tune msg received
                pollPosCount = posCount;    // Save position counter
                reply = (pollPosCount & 0xFFFF0000) >> 16;
                ++pidState;
                break;
            case (1):
                reply = pollPosCount & 0x0000FFFF;
                ++pidState;
                break;
            case (2):
                reply = PWM_Output;
                ++pidState;
                break;
            case (3):
                reply = currentSpeed;
                ++pidState;
                break;
            case (4):
                reply = speedPID;
                blockLoop = false;
                pidState = 0;
                break;
        }
        :
        :
    }
    //
    // Wait for the transmit buffer to be available
    //
    while(_SPITBF);
    SPI1BUF = reply;
    IFS0bits.SPI1IF = 0;    // Clear the interrupt flag
}

What's wrong ?

Thanks
« Last Edit: January 15, 2022, 10:28:42 am by perdrix »
 

Online NorthGuy

  • Super Contributor
  • ***
  • Posts: 3136
  • Country: ca
Re: PIC SPI sending stale data instead of what I want to send
« Reply #1 on: January 15, 2022, 09:44:30 pm »
There's a race condition between two events

- You send your reply back
- The master initates the next SPI transfer

In the first case, the master gets your reply. In the second case, the master gets whatever was transmitted the last time - this is sometimes called "buffer underrun".

You need to re-think your communication protocol.
 

Offline perdrixTopic starter

  • Frequent Contributor
  • **
  • Posts: 634
  • Country: gb
Re: PIC SPI sending stale data instead of what I want to send
« Reply #2 on: January 16, 2022, 03:56:16 am »
A bit more detail would help a lot.   I don't have the code for the master, but AFAIK  it only sends the second 0XEBEB when it has read the data from the slave.

Questions:
  • Is there anything the slave can do resolve this issue or does this need to be fixed at the master?
  • Would this show up at the slave as a "receive overflow" (SPI1STATbits.SPIROV = 1)?
  • What should a well mannered slave implementation do it if detects receive overflow?
  • Are you suggesting a short pause between each 0xEBEB poll? Or,
  • Should the master stop the SPI clock between frames?
David
« Last Edit: January 16, 2022, 09:58:46 am by perdrix »
 

Online NorthGuy

  • Super Contributor
  • ***
  • Posts: 3136
  • Country: ca
Re: PIC SPI sending stale data instead of what I want to send
« Reply #3 on: January 16, 2022, 07:39:18 pm »
A bit more detail would help a lot.   I don't have the code for the master, but AFAIK  it only sends the second 0XEBEB when it has read the data from the slave.

There are two wires - MISO (master input / slave output) and MOSI (master output / slave input) which produce signals simultaneously and synchronous to the clock produced by the master. The master produces the clock at will. By the time the master starts to produce clocks you should have your data written to the BUF register, then the master will receive it.

Is there anything the slave can do resolve this issue or does this need to be fixed at the master?

The master usually makes pauses for the slave to respond. Read the master's datasheet. It should explain the protocol. Typically, master sends some sort of command in one transaction then initiates the next transaction to send data to the slave or to receive the response from the slave. When the master expects data, it may produce delay and/or extra bytes to give the slave more time.

Would this show up at the slave as a "receive overflow" (SPI1STATbits.SPIROV = 1)?

You'll get if you don't read. There might be a small FIFO buffer in the module, so you may not get it right away.

If you don't want to read, on some modules you can disable reading, others will allow you not to read and will continue to work even after the buffer overflow. However, some of the modules will hang if you don't read. Read the datasheet for your particular SPI module to find out.

What should a well mannered slave implementation do it if detects receive overflow?

Well written slave writes/reads everything in time. Usually it is easy to do as SPI rates are typically slow.

Are you suggesting a short pause between each 0xEBEB poll? Or,

There's no poll. Master decides when to transmit (unless there's some sort of external arrangement where the slave can request the transmission). The slave must adapt to whatever master is doing. This should be described in the datasheet. Transactions are not always bi-directional, might be read only or write only. In such one-sided transactions,  one of the parties simply discards whatever was read. Thus, if the transaction is transmit-only for the slave, you must read and discard the BUF to remain in sync with the process.

Should the master stop the SPI clock between frames?

Most of the slow ones will. With faster transmissions clock is often continuous. Usually there's a SS (Slave Select) line also called SE (Slave Enable). The slave must monitor the line and discard all the signalling on MOSI and tri-state MISO while the SS line is high. This lets the master talk to multiple slaves.
 

Offline perdrixTopic starter

  • Frequent Contributor
  • **
  • Posts: 634
  • Country: gb
Re: PIC SPI sending stale data instead of what I want to send
« Reply #4 on: January 17, 2022, 05:51:10 pm »
0XEBEB poll - my terminology for the sequence of five 0xEBEB messages followed by 0xFFFF - no intention on my part to suggest that SPI is a polling protocol.

a 10uS pause between sending each of the 0xEBEB messages was added at the master, problem now fixed.  :)

Thanks for identifying what caused the issue

David

 


Share me

Digg  Facebook  SlashDot  Delicious  Technorati  Twitter  Google  Yahoo
Smf