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.

CCS/MSP430FR5969: SPI Reading problem

Part Number: MSP430FR5969

Tool/software: Code Composer Studio

Hello everyone,

I'm using USCI_A1 SPI module to communicate with a slave. The problem fell in reading routine. I know that to receive a byte, the master must send a dummy byte for the module to actually activate the clock. The transmitting routine was successful, and the signals monitored by oscilloscope showed that the slave gave a byte back. But the data read from UCA1RXBUF was always 0x00. I don't know what is wrong with my program. So, please help me have a look at the following codes and I hope you can tell me where I got wrong.

//Variable declaration
static struct {
    bool bPortInUse;
    bool bNewDataReceived;
    unsigned int indexRx;
    unsigned int indexTx;
    unsigned int uiBytesToSend;
    uint8_t *pcRxBuffer;
    uint8_t *pcTxBuffer;
} spiSM;

//This function is to transmit/receive data from the slave
//rxBuf, txBuf: pointers of receiving/transmitting data, respectively
//size: number of bytes to be received/transmitted

bool spi_transaction(uint8_t* rxBuf, uint8_t* txBuf, uint16_t size) {

    spiSM.bNewDataReceived = false;
    spiSM.indexRx = 0;
    spiSM.indexTx = 0;
    spiSM.uiBytesToSend = size;

    spiSM.pcRxBuffer = rxBuf;                               // pcRxBuffer points to the receiving buffer
    spiSM.pcTxBuffer = txBuf;                               // pcTxBuffer points to the transmitting buffer

    SPI_En;                                                 //SPI disabled (UCA1CTLW0 &= ~UCSWRST)
    UCA1IE |= UCTXIE | UCRXIE;                              // interrupts enabled but interrupt flags still = 0 because GIE is not set

    do {
        // Reset receive flag
        spiSM.bNewDataReceived = false;

        // Start transmission
        TXBUF_Temp = spiSM.pcTxBuffer[spiSM.indexTx];

        // Sleep until transmit/receive interrupt flags occur
        __bis_SR_register(LPM3_bits|GIE);

        // Move to next TX and RX index
        spiSM.indexTx++;
        spiSM.indexRx++;
        spiSM.uiBytesToSend--;

    } while(spiSM.uiBytesToSend);                           // repeat until receive all desired bytes

    SPI_Dis;                                                //SPI disabled (UCA1CTLW0 |= UCSWRST)

    return true;
}

#pragma vector=USCI_A1_VECTOR
__interrupt void SPI_ISR(void) {

    if(UCRXIFG){
        spiSM.pcRxBuffer[spiSM.indexRx] = UCA1RXBUF;
        spiSM.bNewDataReceived = true;
        UCA1IFG &= ~UCRXIFG;    // Not sure it is vital to write this command or not but just as being punctilious
        __bic_SR_register_on_exit(LPM4_bits);
    }

    if(UCTXIFG){
        UCA1TXBUF = TXBUF_Temp;
        UCA1IFG &= ~UCTXIFG;
        __bic_SR_register_on_exit(LPM3_bits|GIE);       // just added recently
    }
}

Here are the signals monitored on an oscilloscope. In this case I want to read the slave's FIFO status register. The reading routine is as the following picture.The green one is MOSI, the red one is CLK, and the blue one is MISO. It showed that the slave returned a data #0 (at the second 8-bit clock) after the master transmitted the command code, but UCA1RXBUF returned 0.  

Thank you so much and look forward to your support.

  • One more thing I'd like to ask. In MSP430FR5x Family User Guide, page 784, it is said that "UCRXIFG is set, indicating the RX/TX operation is complete". But in page 787 it is said "The UCRXIFG interrupt flag is set each time a character is received and loaded into UCxRXBUF". So, what should I understand? Is it right that any complete transmission, either transmitting or receiving, will activate that UCRXIFG? If so, how can I know when the Rx, not Tx, is complete and the data is available at the buffer?
  • > if(UCRXIFG){
    This condition is always true. Try:
    > if(UCA1IFG &UCRXIFG){

    > UCA1IFG &= ~UCRXIFG; // Not sure it is vital to write this command or not but just as being punctilious
    Don't do this. Reading UCA1RXBUF clears RXIFG. Clearing it explicitly is a recipe for losing interrupt events.

    [Both points apply to UCTXIFG as well.]

    The TXIFGs and RXIFGs are paired, but off-by-one, since the TXIFG indicates loading the shift register and the RXIFG indicates the shift-out completion. Keeping track of both is a bit of a headache. For short transactions, I suggest feeding the bytes one at a time: Write TXBUF, wait for the RXIFG, then read the RXBUF (then repeat the process). (For long transactions I recommend DMA.)

    More generally: For a fast SPI clock, interrupts just add complexity and slow things down. Consider doing this with a simple byte-by-byte PIO loop.
  • Dear Bruce,

    Thank you so much for your recommendation. I need interrupt because my application needs to save as much power as possible. So sleeping during waiting will be the preferable option. But I'll try what you suggested and give you the result.

    However, as you suggested, write TXBUF and wait for RXIFG. RXIFG = 1 when transmitting completes. But if there is no data on RXBUF, so, what will happen? Why could not my code capture the received data? Could you please explain this to me, I still get stuck on this. Thank you so much.
  • RXIFG and TXIFG mean different things, though due to the duplex nature of SPI every RXIFG is (normally) accompanied by a TXIFG condition.

    RXIFG is set when RXBUF is loaded. If the SPI unit shifted in 0x00 (as with the first clock burst in your scope trace), then that is what will appear. What's less obvious is when you actually read the RXBUF to see its contents.

    The multiple wakeups are probably confusing your loop, particularly if (as you suggest) your SPI clock is very slow. As I read it, there's probably no reason to wake main up on a TXIFG, so I suggest you remove that.

  • Dear Bruce,

    Thank you very much for your kind support. I've changed my code as you suggested and the SPI module worked (the below codes). So I don't use the interrupt now. Later I'll try again the ISR routine. Thank you again.




    UCA1TXBUF = spiSM.pcTxBuffer[spiSM.indexTx]; // UCTXIFG = 1 when UCAxTXBUF is ready to load new data // writing to UCAxTXBUF activates clock generator // Wait until receive occurs (after command code has been transmitted) while(!(UCA1IFG & UCRXIFG)); spiSM.pcRxBuffer[spiSM.indexRx] = UCA1RXBUF; // save data into *pcRxBuffer

**Attention** This is a public forum