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.

RTOS/MSP430F5438A: SPI code problem ... UCB1RXBUF always zero

Part Number: MSP430F5438A


Tool/software: TI-RTOS

I am having a problem writing SPI code for my MSP430 to talk to a FLASH chip.

I've tried writing both a polling routine, and an Interrupt ISR, and result is the same.  No matter what I try, UCB1RXBUF is always zero.

Here is my init routine:

void hal_spi_init(void)
{
    ////////////////////////////////////////////////////////////////////////////
    // Here are all the relevant IO Pins:
    //          FLASH_SS                P3.6        UCB1STE/CS#     (active low)
    //          FLASH_MOSI              P3.7        UCB1SIMO/SI
    //          FLASH_MISO              P5.4        UCB1SOMI/SO
    //          FLASH_SCLK              P5.5        UCB1CLK/SCK

    P3DIR |= FLASH_SS;                      // P3.6 FLASH_SS is an output pin
    P3OUT |= FLASH_SS;                      // active low, (disable)

    // set special mode for MOSI (P3.7), MISO (P5.4), SCLK (P5.5)
    GPIO_setAsPeripheralModuleFunctionOutputPin(GPIO_PORT_P3, FLASH_MOSI);
    GPIO_setAsPeripheralModuleFunctionInputPin(GPIO_PORT_P5, FLASH_MISO);
    GPIO_setAsPeripheralModuleFunctionOutputPin(GPIO_PORT_P5, FLASH_SCLK);

    // Initialize SPI in Master mode
    USCI_B_SPI_initMasterParam param = {0};
    param.selectClockSource = USCI_B_SPI_CLOCKSOURCE_SMCLK;
    param.clockSourceFrequency = UCS_getSMCLK();
    param.desiredSpiClock = 1000000;
    param.msbFirst = USCI_B_SPI_MSB_FIRST;
    param.clockPhase = USCI_B_SPI_PHASE_DATA_CAPTURED_ONFIRST_CHANGED_ON_NEXT;
    param.clockPolarity = USCI_B_SPI_CLOCKPOLARITY_INACTIVITY_LOW;      //or USCI_B_SPI_CLOCKPOLARITY_INACTIVITY_HIGH;
    bool rc = USCI_B_SPI_initMaster(USCI_B1_BASE, &param);
    assert(rc == STATUS_SUCCESS);

    // Enable SPI module
    USCI_B_SPI_enable(USCI_B1_BASE);

    // Disable interrupts
    USCI_B_SPI_clearInterrupt(USCI_B1_BASE,
                              USCI_B_SPI_RECEIVE_INTERRUPT|USCI_B_SPI_TRANSMIT_INTERRUPT);
    USCI_B_SPI_disableInterrupt(USCI_B1_BASE,
                              USCI_B_SPI_RECEIVE_INTERRUPT|USCI_B_SPI_TRANSMIT_INTERRUPT);
}

Next, here is the spi_transfer routine:

void hal_spi_transfer(
        uint8_t *txbuf, uint8_t *rxbuf, size_t txrxlen, uint8_t flags)
{
    if (flags & SPI_CS_ENABLE)
        flash_ss_active();

    // initiate the first byte transmit
    for ( ; txrxlen; --txrxlen) {

        uint8_t tbyte = txbuf ? *txbuf++ : 0;

        // USCI_B_SPI_transmitData(USCI_B1_BASE, tbyte);
        UCB1TXBUF = tbyte;
        UCB1IFG &= ~UCRXIFG;     // Clear RXIFG as transmit always sets the RX flag

        // wait until the RX byte is completely received
        while (!(UCB1IFG & UCRXIFG))
            ;

        uint8_t rbyte = UCB1RXBUF;        // USCI_B_SPI_receiveData(USCI_B1_BASE);

        if (rxbuf != NULL)
            *rxbuf++ = rbyte;
    }

    if (flags & SPI_CS_DISABLE)
        flash_ss_inactive();
}

When this routine is called, only zeros are read.

On the logic analyzer, I can see that data is properly on the SPI bus.   In the following example, we send the FLASH_READID command (hex 9F), and then read the 0x56 bytes of the chip configuration info:

    hal_spi_send_byte(FLASH_READID, SPI_CS_ENABLE);
    hal_spi_transfer(NULL, flash_CFI, sizeof flash_CFI, SPI_CS_DISABLE);

On the Logic Analyzer, we see all the SPI data:

And we can see on the blue line (probe 6) that the Flash chip received the command, and is returning the CFI data.   I can zoom in and examine the data, and it is absolutely correct.

I've also put an oscilloscope probe on the CPU pin (pin 51), and I get the same result.  The voltage levels look ok  (3v or so).

However, the 'flash_CFI[]' array is always zero.

Is it possibly my hardware is damaged and the SPI receiver doesn't work?

-allan schwartz

  • To further clarify the problem, I've just instrumented the code to flash test signals at 3 key points inside spi_transfer inner loop:

    void hal_spi_transfer(
            uint8_t *txbuf, uint8_t *rxbuf, size_t txrxlen, uint8_t flags)
    {
        assert(txrxlen > 0);
    
        if (flags & SPI_CS_ENABLE)
            flash_ss_active();
    
        // initiate the first byte transmit
        for ( ; txrxlen; --txrxlen) {
    
            uint8_t tbyte = 0;
            if (txbuf != NULL)
                tbyte = *txbuf++;
    
            // USCI_B_SPI_transmitData(USCI_B1_BASE, tbyte);
            green_leds_on(); green_leds_off();
            UCB1TXBUF = tbyte;
            UCB1IFG &= ~UCRXIFG;                // Clear RXIFG as transmit always sets the RX flag
            while ((UCB1IFG & UCTXIFG) == 0)
                ;
            blue_led_on(); blue_led_off();
    
            // wait until the RX byte is completely received
            while (!(UCB1IFG & UCRXIFG))
                ;
    
            red_led_on(); red_led_off();
            uint8_t rbyte = UCB1RXBUF;          // USCI_B_SPI_receiveData(USCI_B1_BASE);
    
            if (rxbuf != NULL)
                *rxbuf++ = rbyte;
        }
    
        if (flags & SPI_CS_DISABLE)
            flash_ss_inactive();
    }
    

    So, the green LED is flashed just before the TXBUF is stuffed.  Then the blue LED is flashed when the TXBUF is free, because it has been transferred to the internal shift register.  Then the red LED is flashed when RXIFG is asserted, meaning RXBUF is ready.   Here is what that looks like on the logic analyzer (notice all the signals are labeled on the left-hand side):

    (Zooming into just the first three bytes of transfers)

    And timing mark A1 marks where TXBUF is written to.   And timing mark A2 marks where RXBUF is read.   It looks like the correct timing.   However, RXBUF is always zero.

    Anyone have any ideas?

  • Hi Allan,

    Thank you for providing such detail on the issue you're observing. Your code appears to be reading and writing to the USCI_B1 registers correctly. Is it possible for you to use a debugger to place a breakpoint when you read from UCB1RXBUF and see the value of rbyte?

    I also see that the DriverLib API guide mentions that the MSP430F5xx/6xx does not support the function modes for the GPIO_setAsPeripheralModuleFunctionInputPin and GPIO_setAsPeripheralModuleFunctionOutputPin functions:

    http://software-dl.ti.com/msp430/msp430_public_sw/mcu/msp430/MSP430_Driver_Library/latest/exports/driverlib/msp430_driverlib_2_91_03_00/doc/MSP430F5xx_6xx/html/group__gpio__api.html#gaedffb91ddac0949fcbb73fbc3636b62a

    Can you try programming the GPIO registers directly to ensure the SOMI pin is being setup properly. The following code should do the trick:

        P3SEL |= BIT7;         // Set P3.7 to UCB1SIMO functionality
        P5SEL |= BIT4 + BIT5;  // Set P5.4 and P5.4 to UCB1SOMI and UCB1CLK functionality respectively

    Best regards, 
    Caleb Overbay

  • Thank you Caleb.  I had placed a breakpoint. I had also summed all the bytes read from RXBUF.   (Was zero).  I had also tried using the P3SEL and P5SEL directly.  But all excellent ideas.

    However, my most recent experiment is most interesting.

    I rewrote my code as a ‘bit-banger’, in case the SPI hardware on the microcontroller was faulty (maybe the RXBUF shift register wasn’t getting clock, or something). And the bit-banger version also did not work!

    So now I suspect that the drivers on pin 51 (Port 5 BIT4) are blown, if it can’t receive any I/O input. To test that theory, I just now jumpered from the FLASH SO signal to another MSP430 input pin — P1.0, which has a TP on my board. And I recompiled with this change of SPI_MISO port, and of course using ‘big-banger’ version, and it worked first time.  Here is my logic analyzer grab of that moment:

    and a bit of my Console window:
    00:13:06 | in flash_read_id
    00:13:06 | init_flash: model 3031, v1.3, size = 0x04000000
    spi_sigma 5e flash_CFI: 01 02 20 4d  00 80 30 31  82 ff ff ff
    00:13:16> 
    So this is now reading the Flash perfectly. This bit-banger version of SPI is many times slower than using the SPI hardware, but it seems to work!
    So somehow I’ve broken this MSP430, port 5.4.
  • For completeness, I'm going to include the working version of my spi_transfer function, and then mark this resolved.

    void hal_spi_transfer(
            uint8_t *txptr, uint8_t *rxptr, size_t txrxlen, uint8_t flags)
    {
        assert(txrxlen > 0);
    
    #if BIT_BANG
        P3SEL &= ~FLASH_MOSI;
        P3DIR |= FLASH_MOSI;
        P5SEL &= ~(FLASH_MISO + FLASH_SCLK);
        P5DIR |= FLASH_SCLK;
        // MISO is the problem...
    //    P5DIR &= ~FLASH_MISO;
        P1DIR &= BIT0;
    #else
        P3SEL |= FLASH_MOSI;
        P5SEL |= FLASH_MISO + FLASH_SCLK;
    #endif
        if (flags & SPI_CS_ENABLE)
            flash_ss_active();
    
        // initiate the first byte transmit
        for ( ; txrxlen; --txrxlen) {
    
            uint8_t tbyte = 0;
            if (txptr != NULL)
                tbyte = *txptr++;
    
            // USCI_B_SPI_transmitData(USCI_B1_BASE, tbyte);
            green_leds_on(); green_leds_off();
    #if BIT_BANG
            uint8_t Txbuf = tbyte;
            uint8_t Rxbuf = 0;
            uint8_t i = 9;
            while (--i) {
                if ( Txbuf & 0x80 )
                    P3OUT |= FLASH_MOSI;
                else
                    P3OUT &= ~FLASH_MOSI;
                P5OUT |= FLASH_SCLK;
                Txbuf <<= 1;
                _nop();            _nop();            _nop();            _nop();
                _nop();            _nop();            _nop();            _nop();
                Rxbuf <<= 1;
    //            Rxbuf |= ((P5IN & FLASH_MISO)>>4);
                Rxbuf |= P1IN & BIT0;
                P5OUT &= ~FLASH_SCLK;
            }
            red_led_on(); red_led_off();
            uint8_t rbyte = Rxbuf;
    #else
            UCB1TXBUF = tbyte;
            UCB1IFG &= ~UCRXIFG;                // Clear RXIFG as transmit always sets the RX flag
            while ((UCB1IFG & UCTXIFG) == 0)
                ;
            blue_led_on(); blue_led_off();
    
            // wait until the RX byte is completely received
            while (!(UCB1IFG & UCRXIFG))
                ;
    
            red_led_on(); red_led_off();
            uint8_t rbyte = UCB1RXBUF;          // USCI_B_SPI_receiveData(USCI_B1_BASE);
    #endif
            spi_sigma += rbyte;
    
            if (rxptr != NULL)
                *rxptr++ = rbyte;
        }
    
        if (flags & SPI_CS_DISABLE)
            flash_ss_inactive();
    }
    

  • Hi Allan,

    Thank you for providing the solution. It does sound like the MSP430 you're working on may have been damaged in some way. Let me know if you have any other issues related to this. In the meantime, I'll close-out this thread on my end as well.

    Best regards,
    Caleb Overbay

**Attention** This is a public forum