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.

MSP430FR2311: SPI multi Byte Interrupt

Part Number: MSP430FR2311

Hi,

I have a SPI master that is sending data to a slave MSP430FR2311 over SPI.  I have been able to get data in a single byte without issue but I can not get multiple bytes.  I have verified with a seperate device that the master is sending the correct data.  Currently I use the CS pin to interrupt, turn on the RX interrupt and then take data in in the RX interrupt.  There is example code for taking in multiple bytes but all of that example code goes to sleep between bytes, I have to stay up while receiving data.  I have tried a couple ways in the RX interrupt to receive data but I always get either garbage data or repeating data.  

For reference here are a couple code examples of what I have tried:

Example 1:

#pragma vector=USCI_A0_VECTOR
__interrupt void USCI_A0_ISR(void)
{
    RXBuf[cmd_index] = UCA0RXBUF;
    cmd_index++;
    if(cmd_index >= RXBuf[0])    // check for all byte RX
    {
        cmd_index = 0;
        P1IE  |= BIT3;          //  Enable CS Line
        UCA0IE = 0;             // Disable USCI_A0 RX interrupt
        //__bis_SR_register_on_exit(LPM3_bits | GIE);
    }
}  //End USCI_A0_VECTOR

Example 2:

#pragma vector=USCI_A0_VECTOR
__interrupt void USCI_A0_ISR(void)
{
    RX_count =0;

    switch(RX_count)
    {
            case 0:                     // RX Byte 1: Packet Length
                lengthSPI = UCA0RXBUF;
                RX_count += 1;
                break;

            case 1:                     // RX Byte 2: CheckSum
                CheckSum = UCA0RXBUF;
                RX_count += 1;
                break;

            case 2:                     // RX Byte 3: RTCMOD Low Byte
                Command = UCA0RXBUF;
                RX_count +=1;
                break;

            case 3:
                IncrementsHigh = UCA0RXBUF;
                RX_count +=1;
                break;

            case 4:
                IncrementsLow = UCA0RXBUF;
                RX_count +=1;
                break;

            case 5:
                RTCMODHigh = UCA0RXBUF;
                RX_count +=1;
                break;

            case 6:
                RTCMODLow = UCA0RXBUF;
                RX_count +=1;
                break;
            }
    if(RX_count >= lengthSPI)    // check for all byte RX
    {
        RX_count = 0;
        P1IE  |= BIT3;          //  Enable CS Line
        UCA0IE = 0;             // Disable USCI_A0 RX interrupt
        //__bis_SR_register_on_exit(LPM3_bits | GIE);
    }

}  //End USCI_A0_VECTOR

Thanks for your help!

  • It's fairly easy to overrun a (software) SPI Slave, since it has no control over how fast the bytes arrive.

    SPI has no mechanism for feedback/flow control, so you have to design for the (Slave) worst-case, but it's not always easy to estimate how long it takes to process each byte.

    The most obvious remedies are:
    1) Slow down the Master; the simplest way is usually to slow down its SPI clock. The Examples use a very slow Master clock (ACLK/2).
    and/or
    2) Speed up the Slave clock (MCLK).
  • Unsolicited: If you can free up the STE pin, I suggest you use 4-wire mode for the Slave, rather than managing /CS yourself. This will allow you to give those extra CPU clocks (from the pin ISR) over to processing the data. It will also give you some "insulation" if you ever go multi-drop.
  • After a bunch of playing around and staring at registers to ensure there are no errors or odd behavior, I have narrowed the issue a bit.  I lowered the clock rate to half the local clock and still get odd results.  Whats really odd though is the switch statement never gets by the first case but it is always filled with the last byte that I send.  Since all the example code for this version is going to sleep and I am not, because I can not, do I need to do something else to get the interrupt to iterate through the data coming in?  It seems like it is just putting each byte into the first case through out the whole packet.

    Thanks!

  • Half of whose "local clock"? If the SPI is running at half of your Slave's MCLK, that only gives it 16 (CPU) clocks to process a byte, which is barely enough to get into the ISR, much less do anything there.

    Only seeing the final byte suggests that the Master is sending all of its bytes in the time it takes your Slave to get into the ISR. What processor is your Master running on?

    I suggest you start by slowing your SPI cllock Way Way Down. As I mentioned, the Examples run their SPI clocks at ~16kHz, so maybe that's a good starting point. Then you can step the clock upwards and see where you start to see trouble.
  • Hi,

    I am running the master, a beaglebone Black at 16kHz which is half od the MSP430FR2311's clock speed. 

    Thanks!

  • The "half of" observation above still holds, even if the Slave is running very slowly, since it's based on MCLK ticks.

    If you really need to run your Slave at 32kHz, then "Way Way Down" is probably more like 1kHz.
  • Hi,

    Thanks I will give this a try. I had previously been trying to use 1 kHz but kept locking up the BBB. Upon further research i see that its min is 5kHz so I will give that a shot. Should this prove to still not work I guess I will have to look at dyncamically setting the clock speed per application in the code. Maybe using a flag that survives resets to change the initialization or something.

    Thanks for all your help on this!
  • evan griffith said:
    Hi,
    Whats really odd though is the switch statement never gets by the first case but it is always filled with the last byte that I send.

    Your second example sets the RX count to zero at the beginning of the ISR, right before it checks the value.  So the value is always zero.  As such, you should always be hitting the first case of the switch statement the way the code is written.

    Walter

  • This is the correct answer.  It was driving me nuts.  I did not realize that the interrupt was reinterrupting per byte, which resets the counter.  I was so sure I knew what it was doing I did not carefully read the state machine.  Thank you for finding this!

**Attention** This is a public forum