This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

Erroneous write on SPI

Hi,

I am sharing one SPI device between three different tasks of different priorities and on occasion the device writes out wrong data to one of the slaves. The SPI driver is operating in DMAINTERRUPT mode and I am using the 1.30.1 psp driver.  My first guess is that the EDMA is transferring wrong data to the driver. How can I verify that this is what is happening?

I have 3 separate channels for the different tasks. I use the oscilloscope to decode whatever the SPI device is writing out and that is how I detect this error. The three different slave devices I am writing to are ADCs and DACs and the DSP is the master. Usually when I see this error it seems another task interrupts the task with the lower priority which causes it to write out wrong data. The CS, DATA_OUT, DATA_IN and CLK signals all look ok on the scope but the data written out is wrong. How is it possible that the task of lower priority writes out wrong data even before it is interrupted by the higher priority task? On the scope the word from the lower priority task occurs before the higher priority task's words.

Even when I write the same data to the low priority channel everytime, the data eventually gets corrupted with the same value (i.e  the output from the SPI device is always the same when this error happens). It is only when I change the values I am writing to the spi channel in the higher priority task that causes a change in the value of the corrupt data written in the lower priority spi channel and this leads me to my initial guess that the EDMA is mixing the data.

Thanks

  • I also know that if I make all three tasks the same priority so they don't preempt one another everything works fine so there has to be something wrong with the preemption that causes this error.

  • Hi Cecil Schandorf,

    If you look at the SPI driver implemention, whenever a request is submitted to the driver, the "currentActiveChannel" will become the current active channel. Till it gets completed, the "currentActiveChannel" will be holding the handle of the active channel. Once EDMA completes its transaction, an interrupt will be generated which will call the spi edma callback functions. This is the point at which we make the "currentActiveChannel" as NULL if there is no pended request in the pending list.

    If a channel 'B' request comes while servicing the the channel 'A', then the channel 'B' request will be put in the "queuePendingList" and after the completion of the channel 'A', the channel 'B' will be made active.

    So you need to do two things, one is to see whether the channel request is getting queued properly in the "queuePendingList" when the request comes from multiple tasks. This can be achived by putting the breakpoint in the file "pspdrivers_01_30_01\packages\ti\pspiom\spi\src\Spi.c" (line num 1194) as shown below, (Please verify the second request is from other than the currently active channel)

     if ((NULL == instHandle->currentActiveChannel) &&
          (Spi_DriverState_PWRM_SUSPEND != instHandle->devState))
     {

          ...............
     }

    else

    {

           ...........

           if (Spi_OpMode_POLLED != chanHandle->channelState)
          {
    Breakpoint Here----->QUE_put(
                            &(chanHandle->queuePendingList),
                            (Ptr)ioPacket);
                            instHandle->stats.pendingPacket++;
       
                         status = IOM_PENDING;
                    }
    }

    Secondly, once after completing the current channel request, the channel request queued in the pending list is taken out and made as the active. This can be verified by confirming the code sequence in the EDMA interrupt context (EDMA callback),

    spi_localCompleteIOedmaCallback() [spi_edma.c] ->Spi_loadPendedIops() [spi.c] ->Spi_localGetNextChannel() [spi.c]

    The channel handle which you get from the Spi_localGetNextChannel() has to be equal to the one which you used to queue the earlier request.

    Can you please conduct the experiment and let me know the result?

    Is it fine with you to share the application which you are using?

    Thanks and Regards,

    Sandeep K

  • Hi Sandeep,

    I have done the tests you recommended and everything seems to be happening in the right sequence. The second request which gets queued up is always different from the current active channel and is the spi handle of the higher priority task. Secondly, after the edmaCallback the next channel popped off the queuePendingList is the same channel that was queued up earlier.

    I am digging through the spi driver code to see whether I can find something suspicious.

    There is one possible bug (not the solution to this problem) on line 763/764 of Spi_edma.c where the function EDMA3_DRV_clearErrorBits is called. I think this should be called with instHandle->deviceInfo.rxDmaEventNumber instead of txDmaEventNumber since the RX channel was what was requested just before this line of code.

    Also about sharing my application: As it is now the application is too big to share. I will have to create a simpler version and see if I can reproduce this same problem before I send it to you.

  • Okay I found what the problem was.

    Apparently after I split up the SPI channels so that different channel handles were used in different tasks which write to different slave devices I forgot to modify my spi driver class which contained a single read and a single write buffer. This meant the same buffers were being shared by all the tasks to read/write so when the higher priority task preempted the lower priority task it overwrote the buffer with its data so the spi edmatransfer which copied the contents of this buffer ended up copying the data of the higher priority task but sending that on the lower priority task's spi channel.

    Thanks for the suggestions.