Hot!SPI collisions not detected?

Page: 12 > Showing page 1 of 2
Author
Cyber
New Member
  • Total Posts : 15
  • Reward points : 0
  • Joined: 2007/07/02 10:48:55
  • Location: 0
  • Status: offline
2018/03/01 15:54:50 (permalink)
0

SPI collisions not detected?

I am using a PIC16F18857 as SPI slave in mode 1, i.e. clock low when idle, data on high-to-low transition.  It is interrupt driven and I am using CLC to generate a "back off" signal for the master, which is set on SPI clock high and cleared when the interrupt has read and written the SPI data.  This mostly works fine, except for this one very weird case...
 
If the software buffer is empty and the slave wants to write something, I want to write it straight to the SSPBUF register instead of adding it to the buffer and waiting for the next clock, as to avoid clocking out rubbish.  This will always be the case if the slave wants to do the very first transmit to the master, for example.
 
Of course there's the possibility of a collision, i.e. the master starts clocking just as I'm writing to SSPBUF.  So in my write routine, I'll write to SSPBUF and if the collision flag is set, I'll clear it and just add the data to the buffer, since I know the interrupt will be called soon.  As a result I expect the "back off" line to clear in the interrupt, but it never does.  My digital analyser shows nothing unusual - the line just never clears after some random time.
 
After tonnes of analysis and debug, I'm getting this slight suspicion that it might be a silicone design problem.  In the last write where it fails, I find the following:
1) At the start of the function, clock measures high (in PIC).
2) Interrupt Enable flag cleared.
3) I write to SSPBUF.  No collision is detected.
4) Interrupt Enable flag set.
5) Clock pin measures low (in PIC).
6) "Back off" pin stays high -> interrupt not called?
 
This means that the clock transitioned from high to low (i.e. sampled the data pin) somewhere during the SSPBUF write without causing a collision and also not causing an interrupt.  If I remove the special case where I write directly to SSPBUF, it works flawlessly, except that I have one extra rubbish byte.
 
Has anyone come across this or have any suggestions?
 
#1

27 Replies Related Threads

    qɥb
    Monolothic Member
    • Total Posts : 3259
    • Reward points : 0
    • Joined: 2017/09/09 05:07:30
    • Location: Jupiter
    • Status: online
    Re: SPI collisions not detected? 2018/03/01 16:22:08 (permalink)
    +1 (1)
    I'm not following all of the logoic, but it sounds like some sort of race condition.
    What about if you manually set the "back off" signal before doing this initial write to SSPBUF?
     

    This forum is mis-configured so it only works correctly if you access it via https protocol.
    The Microchip website links to it using http protocol. Will they ever catch on?
    PicForum "it just works"
    #2
    Cyber
    New Member
    • Total Posts : 15
    • Reward points : 0
    • Joined: 2007/07/02 10:48:55
    • Location: 0
    • Status: offline
    Re: SPI collisions not detected? 2018/03/02 05:30:28 (permalink)
    0
    @qɥb: Setting the "back off" signal does not guarantee that the master will see and respond to it before I write to SSPBUF, so this would be a race condition.
     
    I have made progress since, along with some interesting discoveries...
     
    I raised a pin for the duration of the SSPBUF write and scoped it.  I can see that the write happens during the very last SPI clock down.  This makes me think that the SSPBUF write happens after the data becomes valid, but before the interrupt goes off.  Perhaps this makes the PIC discard the read data and not raise the interrupt?
     
    I then modified the write function only to write to SSPBUF after the interrupt is done, but before the master raises the next clock.  This worked 99%, but renders an even more bizarre exception...
     
    Sometimes the write happens JUST as the master raises the SPI clock for the next byte and the data is a mess.  The first bit is from the previous SSPBUF write and the rest are the first (MSB) to seventh bit of the data I just tried to write.  The next byte I see is the correct version of this new byte, which leads me to conclude that my function saw a collision and added it to the buffer, but the collision didn't prevent the data from being clocked into SSPBUF.  Obviously a big mess and not sure how to fix it.
     
    Glitch shown in the picture below.  The MSB is supposed to be low like in the following byte.  The previous byte was 0xFF.
     

    #3
    Aussie Susan
    Super Member
    • Total Posts : 3249
    • Reward points : 0
    • Joined: 2008/08/18 22:20:40
    • Location: Melbourne, Australia
    • Status: offline
    Re: SPI collisions not detected? 2018/03/04 18:37:59 (permalink)
    +1 (1)
    Are you sampling the SCK pin and using it to trigger an interrupt with the ISR writing to the SPI buffer?
    If you then you will probably need to change your logic as there will probably not be enough time for this to work correctly unless you have a very slow SPI clock and a very fast CPU clock on the slave.
    It would be better to have the master drop the \SS\ line to the slave and have the slave use that if it has to, but this also assumes that the master drops the \SS\ line far enough ahead of when it writes to its SPI buffer for the slave to fully react.
    A better scheme would probably be to use a separate line from the master to the slave to trigger the slave's writing to the SPI buffer so that the master has complete control over the timing between the "request" and the start of the exchange (which should really use the \SS\ - it seems to always be low in the image you have shown).
    Probably the most reliable is the 'double exchange' protocol or something similar - the master sends a command to the slave to say 'read' and then performs a second exchange after a suitable pause to receive the slaves data. Even a continuous sequence of exchanges such that the slave will put its current data into its SPI buffer after each exchange completes would be better.
    Susan
    #4
    Cyber
    New Member
    • Total Posts : 15
    • Reward points : 0
    • Joined: 2007/07/02 10:48:55
    • Location: 0
    • Status: offline
    Re: SPI collisions not detected? 2018/03/05 07:35:33 (permalink)
    0
    Hi Susan.
     
    No, I'm not using the SCK pin to generate an interrupt.  This is all done by the SPI peripheral itself using its standard interrupt mechanisms.  The problem happens when my write function, which normally only writes to the buffer, tries to write directly to SSPBUF.
     
    To get around these issues, I am currently blocking the slave from directly writing to SSPBUF when SS is active.  This should be okay normally.  If the slave wants to send the master something out-of-turn while SS is inactive, it is safe to write to SSPBUF and then drop the "back off" line.
     
    I don't want to rely on the slave understanding something like a "read" command, because if something glitches, the whole protocol is busted.  Also, speed is crucial in this application, so I can't do unnecessary communication.
     
    What does still worry me, is how the PIC fuses two bytes together under certain conditions.  This really should not happen, methinks.
    #5
    Aussie Susan
    Super Member
    • Total Posts : 3249
    • Reward points : 0
    • Joined: 2008/08/18 22:20:40
    • Location: Melbourne, Australia
    • Status: offline
    Re: SPI collisions not detected? 2018/03/05 18:26:05 (permalink)
    0
    I think it is (well past) time that you showed us all of your code, including the config settings.
    Also can you please explain exactly what you mean by "back off"? Does this mean that the slave is trying to tell the master that there is or is not data available, or what?
    I'm not sure what you mean by the PIC (the master or the slave?) fusing two bytes - perhaps you could explain this a bit more.
    Susan
    #6
    Cyber
    New Member
    • Total Posts : 15
    • Reward points : 0
    • Joined: 2007/07/02 10:48:55
    • Location: 0
    • Status: offline
    Re: SPI collisions not detected? 2018/03/06 08:59:15 (permalink)
    0
    Susan,
     
    I have attached my current SPI code and register settings.  My SPI code has been changed as described earlier, so that the write function only writes to SSPBUF if the slave select is inactive or in slave write-only mode (writing=1).
     
    The "back off" line tells the master not to clock the SPI and is used by the slave to give it enough time to process the last exchange, since the PIC does not have any SPI FIFO.  It could be used to throttle the master when either is transmitting - it's up to the slave to decide.
     
    I have described the fusion earlier in the thread, but to recap: "The first bit is from the previous SSPBUF write and the rest are the first (MSB) to seventh bit of the data I just tried to write."
     
    Thanks
    #7
    Aussie Susan
    Super Member
    • Total Posts : 3249
    • Reward points : 0
    • Joined: 2008/08/18 22:20:40
    • Location: Melbourne, Australia
    • Status: offline
    Re: SPI collisions not detected? 2018/03/06 20:29:04 (permalink)
    0
    A couple of things:
    - "...all of your code" does not mean 2 files - I've looked at those but they don't tell the whole story, especially with respect to the CLC configuration
    - I must admit that I really dislike MCC generated code and it just gets worse when you try to modify it yourself.
    - the 'writing' variable is always 1 (at least as far as I can see in the code files provided) and so it seems to just complicate some of your code
    - I *assume* that you don't call the 'SPI1_exchange8bit' and 'SPI1_Exchange8bitBuffer' functions (although I see you appear to have modified the first one with some CLC code)
    I *think* I can decipher what you are tying to do but I suspect that you are over complicating things. I've no idea what value the CLC is adding so I've ignored it in what follows, which is my suggestion to make things work.
    Firstly, in addition to the TX ring buffer, use a LAT bit that talks directly to the  master to tell it when we are ready to go - I'll assume a 0 means we have nothing and a 1 means we have loaded a value.
    Create a function to send a character with the following pseudocode:

    SPI_write(tx_value)
    {
        if(LAT bit is 0)
        {    // Load the value. ready for the next exchange
            SPIBUF = tx_value
            set the LAT bit to 1 that tells the master we have a value loaded and ready to exchange
        }
        else
        { add tx_value to the tx ring buffer }
    }

    You can then create an ISR along the lines of:

    SPI_ISR()
    {
        IF = 0    // Clear the IF flag
        Clear the LAT bit that tells the master we have a value to exchange as we don't as yet
        Save/discard the Rx'd character
        if(the Tx ring buffer has a character)
        {
            SPIBUF = next Tx ring buffer character
            set the LAT bit to 1 that tells the master we are ready for an exchange
        }
        // Else nothing more to do
    }

    This also assumes that the master is using the \SS\ line to re-sync the slave MSSP at the start of each exchange.
    I'll leave error handling to you but it should be minor as WCOL will not be set.
    If the master can be triggered off the rising edge of the pin signal then that would be great, but a level trigger will work as well.
    Susan
    #8
    Cyber
    New Member
    • Total Posts : 15
    • Reward points : 0
    • Joined: 2007/07/02 10:48:55
    • Location: 0
    • Status: offline
    Re: SPI collisions not detected? 2018/03/07 06:12:01 (permalink)
    0
    - I apologize for the limited code, but I don't want to share all my code, since the bulk of it is proprietary.  I have attached the CLC code, but I imagine it's hard to translate in one's head.  The earlier trace probably gives you the best ideas of how it works.
    - Yes, the auto-generated code is terrible and there's a bug in the default USART code as well.  The code I included is also still a bit messy, since it's in the middle of being debugged - apologies.
    - The "writing" variable is now used and is important.  The code is far from finished.  The problem I described is produced with "writing" is set to 0.
    - Correct, the 'SPI1_exchange8bit' and 'SPI1_Exchange8bitBuffer' functions are no longer used.
    - The LAT bit you describe sounds like my "back off" line.  It would be too slow, however, because my slave spends a lot of time in interrupts, which means there's no guarantee that the ISR could clear the LAT bit before the master clocks the next byte.  This is why I'm using CLC, which responds faster than any ISR could.
     
    It is working nicely now as long as I have "writing=1".  The only objection I have is that there seems to be a hardware bug that causes the fusing I described.
    #9
    Aussie Susan
    Super Member
    • Total Posts : 3249
    • Reward points : 0
    • Joined: 2008/08/18 22:20:40
    • Location: Melbourne, Australia
    • Status: offline
    Re: SPI collisions not detected? 2018/03/07 18:46:23 (permalink)
    +2 (2)
    Re the use of the LAT pin begin "too slow". If you use the edge trigger on the master then that would not be a factor.
    It is a pity you are using the PIC16 device as it only has a single interrupt level. The PIC18 devices have 2 levels so you could put the MSSP interrupt at the higher level.
    However that does lead to the question in my mind: have you written your other ISR code properly if you are spending so much time in the ISR that you cannot service other interrupts in time, then you probably have the wrong 'design pattern'. ISRs are intended to be fast "get in and out" code that either sets a flag for the mainline to do the processing, or performs some very simple operation (such as copy a value to/from a ring buffer).
    Susan
    #10
    Gort2015
    Klaatu Barada Nikto
    • Total Posts : 2645
    • Reward points : 0
    • Joined: 2015/04/30 10:49:57
    • Location: 0
    • Status: offline
    Re: SPI collisions not detected? 2018/03/08 08:25:07 (permalink)
    0
    Why do you need that:
    while(SSP1STATbits.BF == SPI_RX_IN_PROGRESS);
     
    Looks like a load of confusion to me, Just use 0 or false.
     
    Or
     
    while(!SSP1STATbits.BF);

    MPLab X playing up, bug in your code? Nevermind, Star Trek:Discovery will be with us soon.
    https://www.youtube.com/watch?v=Iu1qa8N2ID0
    + ST:Continues, "What Ships are Made for", Q's back.
    #11
    Gort2015
    Klaatu Barada Nikto
    • Total Posts : 2645
    • Reward points : 0
    • Joined: 2015/04/30 10:49:57
    • Location: 0
    • Status: offline
    Re: SPI collisions not detected? 2018/03/08 08:34:26 (permalink)
    0
    The slave spi buffer should already contain the data ready for the master.
    You should not get any collisions, there is only 1 master and 1 slave.
     
    Use a command structure, so that the master sends a command to the slave such as send me 10 bytes from memory location x.
     

    MPLab X playing up, bug in your code? Nevermind, Star Trek:Discovery will be with us soon.
    https://www.youtube.com/watch?v=Iu1qa8N2ID0
    + ST:Continues, "What Ships are Made for", Q's back.
    #12
    Cyber
    New Member
    • Total Posts : 15
    • Reward points : 0
    • Joined: 2007/07/02 10:48:55
    • Location: 0
    • Status: offline
    Re: SPI collisions not detected? 2018/03/08 08:37:45 (permalink)
    0
    The problem is not the master being too slow, but the slave being too slow to assert the pin once a byte is received.
     
    I think I can get around the single interrupt level problem by enabling interrupts the moment I enter into certain chosen interruptible interrupts.  However, that still doesn't allow enough time between bytes to call the interrupt and toggle the LAT pin.  The CLC idea is working very well, though.
     
    The culprit ISR is highly optimized, but the point of the application is for the PIC to sample-and-process as fast as possible, so I can't move the processing to the main loop.
    #13
    Cyber
    New Member
    • Total Posts : 15
    • Reward points : 0
    • Joined: 2007/07/02 10:48:55
    • Location: 0
    • Status: offline
    Re: SPI collisions not detected? 2018/03/08 08:42:24 (permalink)
    0
    @Gort: The buffer is only 1 byte long.  The master doesn't know when the slave has placed the second byte into the buffer, so it doesn't know when to continue clocking.  Unless you do something special such as implementing an additional control line.
     
    The collision refers to trying to write a byte into the SPI buffer after the master has started clocking a byte, not a physical collision.
    #14
    Gort2015
    Klaatu Barada Nikto
    • Total Posts : 2645
    • Reward points : 0
    • Joined: 2015/04/30 10:49:57
    • Location: 0
    • Status: offline
    Re: SPI collisions not detected? 2018/03/08 09:01:22 (permalink)
    0
    Where does the slave get it's data from?

    MPLab X playing up, bug in your code? Nevermind, Star Trek:Discovery will be with us soon.
    https://www.youtube.com/watch?v=Iu1qa8N2ID0
    + ST:Continues, "What Ships are Made for", Q's back.
    #15
    Aussie Susan
    Super Member
    • Total Posts : 3249
    • Reward points : 0
    • Joined: 2008/08/18 22:20:40
    • Location: Melbourne, Australia
    • Status: offline
    Re: SPI collisions not detected? 2018/03/08 18:24:56 (permalink)
    0
    Cyber
    The collision refers to trying to write a byte into the SPI buffer after the master has started clocking a byte, not a physical collision.

    That is the exact situation that is supposed to give rise to the WCOL error flag. If it is not or there is something else happening, then raise a ticket with Microchip as there could be a silicon bug.
    Susan
    #16
    Gort2015
    Klaatu Barada Nikto
    • Total Posts : 2645
    • Reward points : 0
    • Joined: 2015/04/30 10:49:57
    • Location: 0
    • Status: offline
    Re: SPI collisions not detected? 2018/03/09 06:56:00 (permalink)
    0
    You should not put anything into the slave buffer unless requested if using a protocol.
    (hand shaking)
     
    1. The slave has some data ready - interrupt to master.
    2. M can send a command to read a flag from S to see what data is available.
    3. M sends command to read data.
    4. S sends data.
    5. M sends command to clear S interrupt so that S can interrupt again.
        (slave can not interrupt again until interrupt flag is cleared)
     
    6. M can sleep, wakes up on interrupt.
     
    No timing or delay issues.
     

    MPLab X playing up, bug in your code? Nevermind, Star Trek:Discovery will be with us soon.
    https://www.youtube.com/watch?v=Iu1qa8N2ID0
    + ST:Continues, "What Ships are Made for", Q's back.
    #17
    Jerry Messina
    Super Member
    • Total Posts : 310
    • Reward points : 0
    • Joined: 2003/11/07 12:35:12
    • Status: offline
    Re: SPI collisions not detected? 2018/03/09 07:38:26 (permalink)
    0
    Seems to me we've been through this a number of times before.
     
    With the PIC16/PIC18, there's no way for the master to know when it's ok to send out a byte to the SPI slave which causes issues with both writing to and reading from the slave.

    You either have to generate a hardware handshake back to the master for each byte transfer (assisted by some code, but not totally software driven), or throttle the master using delays, crossing your fingers and hoping, or come up with a protocol that will guarantee that if you clock out transfers back to back to the slave it will somehow be able to recover from all the collisions and missed transfers and you'll be able to figure out the good transfers from the bad.
     
    I haven't seen that protocol yet.
    #18
    Gort2015
    Klaatu Barada Nikto
    • Total Posts : 2645
    • Reward points : 0
    • Joined: 2015/04/30 10:49:57
    • Location: 0
    • Status: offline
    Re: SPI collisions not detected? 2018/03/09 08:30:42 (permalink)
    0
    You have not looked far then and it's not rocket science.
     
    A protocol is essential in spi coms.
    Collisions occur in badly written code.
     
     

    MPLab X playing up, bug in your code? Nevermind, Star Trek:Discovery will be with us soon.
    https://www.youtube.com/watch?v=Iu1qa8N2ID0
    + ST:Continues, "What Ships are Made for", Q's back.
    #19
    Jerry Messina
    Super Member
    • Total Posts : 310
    • Reward points : 0
    • Joined: 2003/11/07 12:35:12
    • Status: offline
    Re: SPI collisions not detected? 2018/03/09 09:19:25 (permalink)
    0
    It may not be rocket science, but it's not as easy as you say it is.
     
    There are a number of race conditions in post #17 that ARE timing dependent. That code will fail given the proper circumstances.
     
    If you say you have code that works 100% for all conditions of master/slave timing, by all means please post it.
     
    #20
    Page: 12 > Showing page 1 of 2
    Jump to:
    © 2018 APG vNext Commercial Version 4.5