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.

MSP432 SPI busy wait UCBUSY stuck high



I'm trying to run an SPI communication protocol  with a third party ADC as fast as possible.

I initially configured the SPI modules using interrupt service routines. However with the ISR there were several microseconds of delay between bytes. I've now decided to use a busy-wait method, polling UCBUSY to try and save time.

I've configured my SPI module(s) in the following way (same for module A0):


const eUSCI_SPI_MasterConfig spiA1MasterConfig =
{
EUSCI_A_SPI_CLOCKSOURCE_SMCLK, //SMCLK
24000000, //Source clock rate=24MHz
8000000, //SPI clock rate=8MHz
EUSCI_A_SPI_MSB_FIRST, // MSB First
EUSCI_A_SPI_PHASE_DATA_CAPTURED_ONFIRST_CHANGED_ON_NEXT, // Phase
EUSCI_A_SPI_CLOCKPOLARITY_INACTIVITY_HIGH, // Polarity: Active LOW
EUSCI_A_SPI_3PIN // 3wire mode
};

I send garbage data using the driverLib SPI function MAP_SPI_transmitData, then wait until the eUSCI_A busy signal has finished "transmitting or receiving," then load use MAP_SPI_receiveData to load the freshly received data into a buffer.

Here's my source code to do this with two SPI module, 3 bytes per ADC:

// -----------A1-----------
// set A1 CONVST high to start its conversion
MAP_GPIO_setOutputHighOnPin(GPIO_PORT_P5, GPIO_PIN4);
for(int i =0; i<1; i++);

// Set CONVSTA1 low (chip select)
MAP_GPIO_setOutputLowOnPin(GPIO_PORT_P5, GPIO_PIN4);
// send garbage byte and listen for response
MAP_SPI_transmitData(EUSCI_A1_MODULE, 0);
// ...wait...
while(UCA1STATW & BIT0);
// -->receive
receiveDataA1[0] = MAP_SPI_receiveData(EUSCI_A1_MODULE);

// send garbage-->
MAP_SPI_transmitData(EUSCI_A1_MODULE, 0);
// ...wait...
while(UCA1STATW & BIT0);
// -->receive
receiveDataA1[1] = MAP_SPI_receiveData(EUSCI_A1_MODULE);

// send garbage-->
MAP_SPI_transmitData(EUSCI_A1_MODULE, 0);
// ...wait...
while(UCA1STATW & BIT0);
// -->receive
receiveDataA1[2] = MAP_SPI_receiveData(EUSCI_A1_MODULE);

// set CONVST back high
MAP_GPIO_setOutputHighOnPin(GPIO_PORT_P5, GPIO_PIN4);
CONVSTa1 = 1;

// ------A0-------
// start conversion NOW
MAP_GPIO_setOutputHighOnPin(GPIO_PORT_P5, GPIO_PIN3);
// wait for conversion to happen
for(int i =0; i<1; i++);

// Set CONVSTA0 low (chip select)
MAP_GPIO_setOutputLowOnPin(GPIO_PORT_P5, GPIO_PIN3);

// send garbage byte and listen for response
MAP_SPI_transmitData(EUSCI_A0_MODULE, 0);
// ...wait...
while(UCA0STATW & BIT0);
// -->receive
receiveDataA0[0] = MAP_SPI_receiveData(EUSCI_A0_MODULE);
//testBuf[0] = UCA0RXBUF;

// send garbage-->
MAP_SPI_transmitData(EUSCI_A0_MODULE, 0);
// ...wait...
test = UCA0STATW;
while(UCA0STATW & BIT0);
// -->receive
receiveDataA0[1] = MAP_SPI_receiveData(EUSCI_A0_MODULE);
//testBuf[1] = UCA0RXBUF;

// send garbage-->
MAP_SPI_transmitData(EUSCI_A0_MODULE, 0);
// ...wait...
while(UCA0STATW & BIT0);
// -->receive
receiveDataA0[2] = MAP_SPI_receiveData(EUSCI_A0_MODULE);
//testBuf[2] = UCA0RXBUF;

// set CONVST back high
MAP_GPIO_setOutputHighOnPin(GPIO_PORT_P5, GPIO_PIN3);
CONVSTa0 = 1;

This method works well for SPI clocks up to 8MHz when I'm running both SPI modules back to back. Oddly, when I comment out the second SPI method (A0), I can run A1 up to 12MHz.

At clock speeds higher than this the loop runs through healthy ONCE, then get gets hung up at the second 
while(UCA1STATW & BIT0);

(ie UCBUSY is stuck high, "transmitting or receiving").

What could be causing UCBUSY to stay high forever?

  • Maurizio,

    Could you also include your setup of the system clocks, as well as, what the max frequency the slave device should be able to handle? This might give me more insight on what the problem could be.

    Thanks,
    Michael Arriete

  • We've considered the issue being running the core voltage at VCORE = 1.2V. This could explain what we're seeing, based on the datasheet and the discussion found here (e2e.ti.com/.../1624394

    Clock Code:


    #define CPU_FREQ (48000000)

    void startCrystalOscillator(void);
    void setSystemClock(uint32_t CPU_Frequency);

    void setSystemClock(uint32_t CPU_Frequency)
    {
    /* Setting the external clock frequency. This API is optional, but will
    * come in handy if the user ever wants to use the getMCLK/getACLK/etc
    * functions
    */
    //
    // 15 October 2015: Removed the LFXT
    //
    MAP_CS_setExternalClockSourceFrequency(32768, CPU_Frequency);

    /* Before we start we have to change VCORE to 1 to support the 48MHz frequency */
    MAP_PCM_setCoreVoltageLevel(PCM_AM_LDO_VCORE1);
    MAP_FlashCtl_setWaitState(FLASH_BANK0, 2);
    MAP_FlashCtl_setWaitState(FLASH_BANK1, 2);

    /* Starting HFXT and LFXT in non-bypass mode without a timeout. */
    MAP_CS_startHFXT(false);
    //MAP_CS_startLFXT(false);

    /* Initializing the clock source as follows:
    * MCLK = HFXT = 48MHz
    * ACLK = LFXT = 48KHz
    * HSMCLK = HFXT/1 = 48MHz
    * SMCLK = HFXT/2 = 24MHz
    * BCLK = REFO = 32kHz
    */
    MAP_CS_initClockSignal(CS_MCLK, CS_HFXTCLK_SELECT, CS_CLOCK_DIVIDER_1);
    //MAP_CS_initClockSignal(CS_ACLK, CS_LFXTCLK_SELECT, CS_CLOCK_DIVIDER_1);
    MAP_CS_initClockSignal(CS_HSMCLK, CS_HFXTCLK_SELECT, CS_CLOCK_DIVIDER_1);
    MAP_CS_initClockSignal(CS_SMCLK, CS_HFXTCLK_SELECT, CS_CLOCK_DIVIDER_2);
    MAP_CS_initClockSignal(CS_BCLK, CS_REFOCLK_SELECT, CS_CLOCK_DIVIDER_1);
    }


    //***********************************************************
    //
    // The following function is responsible for starting XT1 in the
    // MSP432 that is used to source the internal FLL that drives the
    // MCLK and SMCLK.
    //
    //***********************************************************
    void startCrystalOscillator(void)
    {
    /* Configuring pins for peripheral/crystal HFXT*/
    MAP_GPIO_setAsPeripheralModuleFunctionOutputPin(GPIO_PORT_PJ,
    GPIO_PIN2 | GPIO_PIN3, GPIO_PRIMARY_MODULE_FUNCTION);

    /* Configuring pins for peripheral/crystal LFXT*/
    /*MAP_GPIO_setAsPeripheralModuleFunctionOutputPin(GPIO_PORT_PJ,
    GPIO_PIN0 | GPIO_PIN1, GPIO_PRIMARY_MODULE_FUNCTION);*/
    }

  • Maurizio,

    Have you been able to get the SPI module to work at your desired speeds?

    Regards,
    Michael Arriete
  • Not yet.

    Can you please confirm my VCORE is set to 1.4V using the command above:

    MAP_PCM_setCoreVoltageLevel(PCM_AM_LDO_VCORE1);

  • Yes, using VCORE1 will set your core voltage to 1.4V and allow usage of core frequencies up to 48 MHz.

    Regards,
    Michael Arriete
  • Maurizio,

    According to your original post, you stated that you could successfully run the SPI module at 12 MHz, running the core clock at 24MHz. This is, in fact, the max frequency that you can run SPI at that level, which is why your busy signal would stay high when trying to run it faster.

    Regards,
    Michael Arriete
  • I'm running my HFXT at 48MHz, and my SMCLK at HFXT/2 = 24MHz. I believe this is the fastest I can set my SMCLK.
    I use the SMCLK as my SPI source clock rate (24MHz).

    Does this mean I'm limited to 12MHz for my SPI? I've read on the data sheet the SPI should be able to run at 16MHz...
    Also, the busy signal stays high at clock rates higher than 8MHz when I try to use two different SPI modules (A0 and A1). It only functions correctly at 12MHz when I am polling a single module, either A0 or A1.
  • Maurizio,

    I have attached a zip folder containing SPI example project that enables and uses two SPI modules, running at 16MHz each, using the DCO as the clock source. Please look over the example code and make changes to how you are initializing the SPI module in your code. Let me know if this solves your problem!

    msp432_sample_spi_project_ccs.zip

    Thanks!

    Michael Arriete

**Attention** This is a public forum