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.

SPI: How do I force SPISTE high?

I'm trying to send distinct transmissions with the SPI peripheral on the F28M35H52C1. By distinct transmissions, I mean that SPISTE goes high between sets of data. How do I use the FIFO buffers in such a way that I can control when SPISTE goes high between sets of data?

I've read through the TRM, but it's not at all clear how to do this.

Thanks for any help.

  • Michael,

    The SPISTE will stay active (e.g., low) between back-to-back transfers.  This is documented in the device datasheet SPRS742G, for example the footnote below Figure 6-42.  You need to allow the TX FIFO to become empty and then the SPI will see there is nothing more to transmit and will drive SPISTE inactive.  In other words, do not put more words in the TX FIFO than you want to transmit with SPISTE staying active.  After the FIFO empties, SPISTE will go inactive and you can take the interrupt and re-load the FIFO with the next TX words.

    Regards,

    David

  • Hi David,


    Thanks for responding. Staying active with back-to-back transfers is fine, however, it is not clear how to wait until the FIFO empties for SPISTE to go inactive. I've tried checking on TXFFST == 0, however, if I add more words at that point then SPISTE will remain active.

    My current hack solution is to just wait 100 cycles on the processor, but this seems arbitrary and ad hoc, and surely there is a better way.


    Thanks

  • Michael,

    Since SPI transmit and receive always occur at the same time, how about using the receive side interrupt to tell you when transmission is complete.  Suppose you wanted to transmit 'x' words.  Make sure the RX FIFO is empty (by checking the RX level status bits), and set the receive FIFO interupt level to 'x'.  Then load up the TX FIFO with the 'x' words.  When the last words completes transmission, you will get the RX interrupt.  Also, you will know the TX shift register is completely empty and that SPISTE has gone inactive.

    Regards,

    David

    Michael Hu. said:

    Hi David,


    Thanks for responding. Staying active with back-to-back transfers is fine, however, it is not clear how to wait until the FIFO empties for SPISTE to go inactive. I've tried checking on TXFFST == 0, however, if I add more words at that point then SPISTE will remain active.

    My current hack solution is to just wait 100 cycles on the processor, but this seems arbitrary and ad hoc, and surely there is a better way.


    Thanks

  • Hi David,


    Waiting on the RX interrupt seems to work. Thanks for your help.

  • Hi David,

    Thanks again for your help with this issue. I've implemented what you wrote, and it seems to be working. I thought I'd write out my code here, and hope you could take a look and see if I am doing anything that might be problematic in the future, as well as to have the code in this thread as an example for other people to see.

    Here is my code for sending out data in the TX buffer, and waiting for the receive interrupt before sending out more:

    First, the data is put into the TX FIFO and the receive interrupt word length is set to the size of the transmission.

        SpiaRegs.SPIFFRX.bit.RXFFIL = 3; // Set length of transmission
                
        SpiaRegs.SPITXBUF = data1;
        SpiaRegs.SPITXBUF = data2;
        SpiaRegs.SPITXBUF = data3;

        WaitForReceive();

    It then waits for the receive interrupt in the last line. The receive FIFO interrupt sets a flag, called "received", and saves the buffer data:

    static interrupt void spiRx()
    {    
        received = true;
        Uint16 words = SpiaRegs.SPIFFRX.bit.RXFFST;
        
        ClearReceiveBuf();
        for (int i=0;i<words;i++)
        {
            receiveBuf[i] = SpiaRegs.SPIRXBUF;
        }
        SpiaRegs.SPIFFRX.bit.RXFFINTCLR=1; // Clear the RX interrupt flag in the SPI
        PieCtrlRegs.PIEACK.all|=M_INT6; // Write to the PIEACK to allow more interrupts
    }

    Which is what the waiting function was waiting for:

    static void WaitForReceive()
    {
    //    for(int i=0; i<100; i++)
        while(1)
        {
            if(received)
            {
                received = false;
                return;
            }
        }
    }

    Does this look like a reasonable structure for this?

    Thanks again for your help.

  • Michael,

    Just eyeballing the code it seems OK.  Obviously I have not tested anything.

    I do wonder though, you have a polling loop for 'received'.  Why then take the SPI receive interrupt?  Why not just directly poll the SPI RX interrupt flag in your polling loop, and process the data when the flag becomes set?  Then you don't need the ISR.  Polling is ugly of course.  Your application is going to be sitting and waiting for the SPI transmission to complete.  If you have nothing else to do, then fine.  Otherwise, you should not poll and take the SPI RX interrupt.

    Regards,

    David

  • I think there are two questions: why poll versus just use the interrupt, and if I'm polling, why not wait on the interrupt flag rather than add my own flag.

    Regarding polling: I need to send out a bunch of SPI transmissions one after another. For example, configure Register A, end transmission, configure Register B.... etc. Polling lets me write it all in one function sequentially, with polling happening between transmissions. If I didn't poll and relied only on the interrupt, then I have to write a bunch of continuations with callbacks, etc, leading to a mess of code legibility just to configure some registers. Please let me know if I am wrong and if there is a different way.

    Secondly, if I am polling, why not go all the way and get rid of the interrupt handler? That's a good question. If the receive buffer is not read in an interrupt, but instead in the main loop, and is interrupted mid-read between words, is there any hazard of the data being invalid or unavailable when the main loop is resumed? If not, I may switch to that.

    It seems then that the Rx interrupt handler is really ever only needed when operating in a Slave mode, am I correct? Is there any situation operating in Master mode where you would want to use the receive interrupt?

    Just to confirm, polling the interrupt flag would look like:

    while( ! SpiaRegs.SPIFFRX.bit.RXFFINT )
     {}

    ...

    Is that correct?

  • Michael,

    Michael Hu. said:

    I think there are two questions: why poll versus just use the interrupt, and if I'm polling, why not wait on the interrupt flag rather than add my own flag.

    Well put.

    Michael Hu. said:

    Regarding polling: I need to send out a bunch of SPI transmissions one after another. For example, configure Register A, end transmission, configure Register B.... etc. Polling lets me write it all in one function sequentially, with polling happening between transmissions. If I didn't poll and relied only on the interrupt, then I have to write a bunch of continuations with callbacks, etc, leading to a mess of code legibility just to configure some registers. Please let me know if I am wrong and if there is a different way.

    The software can be constructed in various ways.  Perhaps the simplest is to write the first frame of data in the main routine, and after that everything could be handled in the ISR using a state machine and one or more global control variables.  I completely understand this can be debated.  Use of global control variables for example is undesirable by many people.  Just saying there are some simple ways to handle the problem without using callbacks and complex software threads.

    The downside of polling is that you can't do anything else while you're sitting there spinning your wheels and polling.  If you can afford the time, by all means go ahead and poll!

    Michael Hu. said:

    Secondly, if I am polling, why not go all the way and get rid of the interrupt handler? That's a good question. If the receive buffer is not read in an interrupt, but instead in the main loop, and is interrupted mid-read between words, is there any hazard of the data being invalid or unavailable when the main loop is resumed? If not, I may switch to that.

    I'm not following.  If you poll in the main loop, then you read the data in the main loop.  You wouldn't take the interrupt at all.  The data is received and moved into the FIFO before the interrupt flag would get set.  The data will be valid.

    Michael Hu. said:

    It seems then that the Rx interrupt handler is really ever only needed when operating in a Slave mode, am I correct? Is there any situation operating in Master mode where you would want to use the receive interrupt?

     
    Technically, the TX interrupt happens before the RX interrupt.  The time between the two is how long it takes to transmit the specified number of words. If not using the FIFOs, people will use the TX ISR to keep the TX buffer full (no gaps between transmitted words).  Even with the FIFO, people sometimes want to eliminate gaps between transmitted frames, so they need to know when there is enough room in the TX FIFO to fit the next frame.  In your particular use case, you actually want a gap between frames, so the TX ISR doesn't seem to have much use.  You can do the job with the RX interrupt.
     
    Michael Hu. said:

    Just to confirm, polling the interrupt flag would look like:

    while( ! SpiaRegs.SPIFFRX.bit.RXFFINT )
     {}

    ...

    Is that correct?

     
    Correct.
     
    Regards,
    David
  • David, Michael,

    David M. Alter said:
    Perhaps the simplest is to write the first frame of data in the main routine, and after that everything could be handled in the ISR using a state machine and one or more global control variables.

    I like the idea David proposed here (and I acknowledge the drawbacks). If the inter-frame space is required, then using the RX interrupt to fill the TX FIFO based on a state machine seems to be exactly what you are looking for. How you go about starting various transmissions would be entirely up to your system, but you would know exactly when the last frame completed and allow SPISTE to return High.

    -Mark

  • David M. Alter said:

    The software can be constructed in various ways.  Perhaps the simplest is to write the first frame of data in the main routine, and after that everything could be handled in the ISR using a state machine and one or more global control variables.  I completely understand this can be debated.  Use of global control variables for example is undesirable by many people.  Just saying there are some simple ways to handle the problem without using callbacks and complex software threads.

    The downside of polling is that you can't do anything else while you're sitting then spinning your wheels and polling.  If you can afford the time, by all means go ahead and poll!

    Using control variables in the ISR is also a form of continuation, just not using callbacks, and might also lead to complex code in the interrupt, which in my experience is to be avoided. I definitely can understand the advantage versus polling for SPI heavy communications, but my particular use is very different. I configure the SPI slave once, upon device bootup, then leave it alone and never communicate again until I get an interrupt from the slave, which should rarely happen (it's a fault). In this case, I just want to configure the registers and be done with it, and polling upon boot-up is fine since nothing else is happening anyway. When I do get an interrupt from the slave, the microcontroller trips a fault and turns everything off anyway.

    David M. Alter said:
    I'm not following.  If you poll in the main loop, then you read the data in the main loop.  You wouldn't take the interrupt at all.  The data is received and moved into the FIFO before the interrupt flag would get set.  The data will be valid.

    What I mean is, if you read in the main loop, then something else can interrupt. If you don't resume where you left off for many cycles, is there any danger of the RX FIFO data being lost? I don't think this is a danger in my case, since I am not using the SPI for any other purpose, but I just wanted to check.

  • Michael Hu. said:

    What I mean is, if you read in the main loop, then something else can interrupt. If you don't resume where you left off for many cycles, is there any danger of the RX FIFO data being lost? I don't think this is a danger in my case, since I am not using the SPI for any other purpose, but I just wanted to check.

    Unless the RX FIFO overflows, there is no danger of losing data.  It doesn't seem the RX FIFO could overflow either, since you are the SPI master and you are not transmitting enough data before reading the FIFO completely for the FIFO to overflow.

    - David