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.

LP-MSP430FR2476: SPI receive

Part Number: LP-MSP430FR2476

I am trying to setup SPI master transactions based of off eusci_a_spi_ex1master.c file. This file shows enabling the SPI RX interrupt, however it also checks for the TX interrupt though not explicitly enabled. How does the Tx interrupt work?  I don't understand how to setup the SPI RX ISR. The RX ISR is triggering after the fifth transaction, I can get a breakpoint to halt. However,

RXData = EUSCI_A_SPI_receiveData(EUSCI_A1_BASE); is showing a value of 0 for RXData. I don't have a scope on hand, I don't understand why the data is not showing up?

Thanks,

Priya

/*
* Initialize the SPI peripheral on EUSCI A1
*/
void init_spi_peripheral()
{
//Initialize Master
EUSCI_A_SPI_initMasterParam param = {0};
param.selectClockSource = EUSCI_A_SPI_CLOCKSOURCE_SMCLK;
param.clockSourceFrequency = CS_getSMCLK();
param.desiredSpiClock = 1000000;
param.msbFirst = UCMSB;
param.clockPhase = UCCKPH;
param.clockPolarity = 0;
param.spiMode = EUSCI_A_SPI_3PIN;
EUSCI_A_SPI_initMaster(EUSCI_A1_BASE, &param);

EUSCI_A_SPI_enable(EUSCI_A1_BASE);
}

void CheckUSCI_A1_TxReady(void){
//USCI_A1 TX buffer ready?
while (!EUSCI_A_SPI_getInterruptStatus(EUSCI_A1_BASE,
EUSCI_A_SPI_TRANSMIT_INTERRUPT));
}

void MaximUARTDaisyChainInitStart(void){

daisyChainInit = 1;

//USCI_A1 TX buffer ready?
CheckUSCI_A1_TxReady();
//Transmit Data to slave
for (i = 0; i < 2; i++)
EUSCI_A_SPI_transmitData(EUSCI_A1_BASE, DCInit_transaction1[i]);
TXData++;

CheckUSCI_A1_TxReady();
//Enable Rx Interrupt flags
for (i = 0; i < 2; i++)
EUSCI_A_SPI_transmitData(EUSCI_A1_BASE, DCInit_transaction2[i]);
TXData++;

CheckUSCI_A1_TxReady();
//Clear receive buffer
EUSCI_A_SPI_transmitData(EUSCI_A1_BASE, DCInit_transaction3);
TXData++;

CheckUSCI_A1_TxReady();
//Wakeup UART slave devices
for (i = 0; i < 2; i++)
EUSCI_A_SPI_transmitData(EUSCI_A1_BASE, DCInit_transaction4[i]);
TXData++;

CheckUSCI_A1_TxReady();
//Wait for all UART slave devices to wake up
EUSCI_A_SPI_transmitData(EUSCI_A1_BASE, DCInit_transaction5);

   

}

int main(void)
{
WDTCTL = WDTPW | WDTHOLD; // stop watchdog timer

init_gpio(); // Set up IO pins
init_clock(); // Set up the system clocks for 16 MHz (on the MSP430)

// Setup peripheral(s) now that gpio and clocks are setup
init_spi_peripheral(); // Init Maxim spi peripheral

//Clear receive interrupt flag
EUSCI_A_SPI_clearInterrupt(EUSCI_A1_BASE,
EUSCI_A_SPI_RECEIVE_INTERRUPT
);

// Enable USCI_A1 RX interrupt
EUSCI_A_SPI_enableInterrupt(EUSCI_A1_BASE,
EUSCI_A_SPI_RECEIVE_INTERRUPT);

//Wait for slave to initialize
__delay_cycles(100);

TXData = 0x1; // Holds TX data

MaximUARTDaisyChainInitStart();

__bis_SR_register(LPM0_bits + GIE); // CPU off, enable interrupts
__no_operation(); // Remain in LPM0


return 0;
}

#if defined(__TI_COMPILER_VERSION__) || defined(__IAR_SYSTEMS_ICC__)
#pragma vector=USCI_A1_VECTOR
__interrupt
#elif defined(__GNUC__)
__attribute__((interrupt(USCI_A1_VECTOR)))
#endif
void USCI_A1_ISR(void)
{
if (USCI_SPI_UCRXIFG){

RXData = EUSCI_A_SPI_receiveData(EUSCI_A1_BASE);

if (daisyChainInit == 1 && (TXData == 0x5)){
if (RXData == 0x21){
TXData++;
}
}

//Delay between transmissions for slave to process information
__delay_cycles(40);
}
}

PS: I know the receive works with a evaluation GUI for these evaluation board transactions. It is something about the MSP430 SPI I don't have down correctly.

  • Hi Priya,

    For your question on how the TX interrupt works, I'd refer you to section 23.3.3 "Master Mode" of the User Guide, this discusses the eUSCI_A SPI module and explains how the data transfer occurs and the roles that the TX and RX interrupts play [link].

    I would also change the ISR to follow the format of eusci_a_spi_ex1master.c (using switch statement). Looking at the example code and several examples in the User Guide ("UCAxIV Software Example" for UART and "UCBxIV Software Example" for I2C), it seems that the ISRs for serial communication should be written in this way.

    Thanks,

    Urica Wang

  • if (USCI_SPI_UCRXIFG){

    Is a simple constant so is always true. It is intended to be used as a bit mask with the status register. Do that or use the IV register.

  • Thank you for your replies. I have located the correct MSP430 user guide slau445I and I am working on setting the SPI correctly. In the next 2-3 days, I should have this understood. I will keep this thread open until then.

  • I need more help setting up the SPI to transmit on interrupt. Here is what I tried today:

    1. Need to setup EUSCI_A1_BASE as SPI master
    2. Slave works on SPI mode 0 (CPOL=0, CPHA=0). Are the SPI master settings correct for this?
    3. The slave needs a 4 pin SPI master. Will this statement make the CS active low? This is done when initializing the SPI peripheral.
    P3SEL1 |= BIT1; //Turn on SPI CS
    4. I am trying to transmit messages to the slave on the SPI tx interrupt. As I understand, the tx interrupt will trigger whenever the TX buffer is ready to transmit another byte. How do I initiate this first SPI transmit and keep it going? The slave will send back a GPIO interrupt at the end of transaction 9. With this code, I am not getting any SPI transmit interrupts, even the first one.

    I will get a scope next week. But I am not sure I am using the SPI correctly.

    static uint8_t TXData = 0;

    typedef struct {
    uint8_t Len;
    uint8_t *Data;
    } spi_MaximTrans_t;

    spi_MaximTrans_t DCInit_transactions[15];


    uint8_t i = 0;

    /**
    * Initialize all of the IO pins per their configuration
    */
    static void init_gpio(void) {
    // Set all GPIO pins to output low to prevent floating input and reduce power consumption
    GPIO_setOutputLowOnPin(GPIO_PORT_P1, GPIO_PIN_ALL8);
    GPIO_setOutputLowOnPin(GPIO_PORT_P2, GPIO_PIN_ALL8);
    GPIO_setOutputLowOnPin(GPIO_PORT_P3, GPIO_PIN_ALL8);
    GPIO_setOutputLowOnPin(GPIO_PORT_P4, GPIO_PIN_ALL8);
    GPIO_setOutputLowOnPin(GPIO_PORT_P5, GPIO_PIN_ALL8);
    GPIO_setOutputLowOnPin(GPIO_PORT_P6, GPIO_PIN0 | GPIO_PIN1 | GPIO_PIN2);

    GPIO_setAsOutputPin( GPIO_PORT_P1, GPIO_PIN_ALL8);
    GPIO_setAsOutputPin( GPIO_PORT_P2, GPIO_PIN_ALL8);
    GPIO_setAsOutputPin( GPIO_PORT_P3, GPIO_PIN_ALL8);
    GPIO_setAsOutputPin( GPIO_PORT_P4, GPIO_PIN_ALL8);
    GPIO_setAsOutputPin( GPIO_PORT_P5, GPIO_PIN_ALL8);
    GPIO_setAsOutputPin( GPIO_PORT_P6, GPIO_PIN0 | GPIO_PIN1 | GPIO_PIN2);
    }

    /*
    * Initialize the SPI peripheral on EUSCI A1
    */
    void init_spi_peripheral()
    {
    //Initialize Master
    EUSCI_A_SPI_initMasterParam param = {0};
    param.selectClockSource = EUSCI_A_SPI_CLOCKSOURCE_SMCLK;
    param.clockSourceFrequency = CS_getSMCLK();
    param.desiredSpiClock = 1000000;
    param.msbFirst = UCMSB;
    param.clockPhase = 0;
    param.clockPolarity = EUSCI_A_SPI_CLOCKPOLARITY_INACTIVITY_LOW;
    param.spiMode = EUSCI_A_SPI_4PIN_UCxSTE_ACTIVE_LOW;
    EUSCI_A_SPI_initMaster(EUSCI_A1_BASE, &param);

    EUSCI_A_SPI_enable(EUSCI_A1_BASE);

    // Enable the TX and RX interrupts for the SPI bus.
    UCA1IE |= (UCRXIE | UCTXIE);
    P3SEL1 |= BIT1; //Turn on SPI CS
    }


    void SetUpTransactions(void){
    //Enable keep alive mode
    DCInit_transactions[0].Len = 2;
    DCInit_transactions[0].Data[0] = 0x10;
    DCInit_transactions[0].Data[1] = 0x5;

    //Enable Rx Interrupt flags
    DCInit_transactions[1].Len = 2;
    DCInit_transactions[1].Data[0] = 0x4;
    DCInit_transactions[1].Data[1] = 0x88;

    //Clear receive buffer
    DCInit_transactions[2].Len = 1;
    DCInit_transactions[2].Data[0] = 0xe0;

    //Wakeup UART slave devices
    DCInit_transactions[3].Len = 2;
    DCInit_transactions[3].Data[0] = 0xe0;
    DCInit_transactions[3].Data[1] = 0x30;

    //Wait for all UART slave devices to wake up
    DCInit_transactions[4].Len = 1;
    DCInit_transactions[4].Data[0] = 0x01;

    //End of UART slave device wake-up period
    DCInit_transactions[5].Len = 2;
    DCInit_transactions[5].Data[0] = 0x0e;
    DCInit_transactions[5].Data[1] = 0x10;

    //Wait for null message to be received
    DCInit_transactions[6].Len = 1;
    DCInit_transactions[6].Data[0] = 0x01;

    //Clear transmit buffer
    DCInit_transactions[7].Len = 1;
    DCInit_transactions[7].Data[0] = 0x20;

    //Clear receive buffer
    DCInit_transactions[8].Len = 1;
    DCInit_transactions[8].Data[0] = 0xe0;

    }


    /**
    * main.c
    */
    int main(void)
    {
    WDTCTL = WDTPW | WDTHOLD; // stop watchdog timer

    //Set external frequency for XT1
    CS_setExternalClockSource(32768);

    //Select XT1 as the clock source for SMCLK with no frequency divider
    CS_initClockSignal(CS_SMCLK, CS_XT1CLK_SELECT, CS_CLOCK_DIVIDER_1);

    //Start XT1 with no time out
    CS_turnOnXT1(CS_XT1_DRIVE_0);

    init_gpio(); // Set up IO pins


    // Set P1.0 to output direction
    GPIO_setAsOutputPin (GPIO_PORT_P1, GPIO_PIN0);
    GPIO_setAsInputPinWithPullUpResistor (GPIO_PORT_P4, GPIO_PIN2);
    GPIO_enableInterrupt (GPIO_PORT_P4, GPIO_PIN2);
    GPIO_selectInterruptEdge (GPIO_PORT_P4, GPIO_PIN2, GPIO_HIGH_TO_LOW_TRANSITION);
    GPIO_clearInterrupt (GPIO_PORT_P4, GPIO_PIN2);

    SetUpTransactions();
    TXData = 0x0; // Holds transaction number

    // Setup peripheral(s) now that gpio and clocks are setup
    init_spi_peripheral(); // Init Maxim spi peripheral

    //USCI_A0 TX buffer ready?
    while (!EUSCI_A_SPI_getInterruptStatus(EUSCI_A0_BASE,
    EUSCI_A_SPI_TRANSMIT_INTERRUPT)) ;

    //Transmit Data to slave
    EUSCI_A_SPI_transmitData(EUSCI_A0_BASE, DCInit_transactions[TXData].Data[0]);

    i++;

    //Wait for slave to initialize
    __delay_cycles(100);


    //USCI_A0 TX buffer ready?
    while (!EUSCI_A_SPI_getInterruptStatus(EUSCI_A1_BASE,
    EUSCI_A_SPI_TRANSMIT_INTERRUPT)) ;

    __bis_SR_register(LPM0_bits + GIE); // CPU off, enable interrupts
    __no_operation(); // Remain in LPM0


    return 0;
    }

    //******************************************************************************
    //
    //This is the PORT2_VECTOR interrupt vector service routine
    //
    //******************************************************************************
    #if defined(__TI_COMPILER_VERSION__) || defined(__IAR_SYSTEMS_ICC__)
    #pragma vector=PORT4_VECTOR
    __interrupt
    #elif defined(__GNUC__)
    __attribute__((interrupt(PORT2_VECTOR)))
    #endif
    void P4_ISR (void)
    {
    GPIO_clearInterrupt (GPIO_PORT_P4, GPIO_PIN2);
    // Toggle P1.0 output
    GPIO_toggleOutputOnPin (GPIO_PORT_P1, GPIO_PIN0);
    }


    /****************************************************************************
    * EUSCI_A1_isr()
    *
    * This interrupt is used for SPI interrupts (UCA1).
    ****************************************************************************/
    #pragma vector = EUSCI_A1_VECTOR
    __interrupt void EUSCI_A1_isr(void)
    {
    // SPI TX interrupt?
    if (UCA1IFG & UCTXIFG)
    {
    while (i < DCInit_transactions[TXData].Len){
    EUSCI_A_SPI_transmitData(EUSCI_A1_BASE, DCInit_transactions[TXData].Data[i]);
    i++;
    }
    if (i == DCInit_transactions[TXData].Len){
    UCA1IE &= ~UCTXIE;
    i = 0;
    TXData++;
    }

    /* Put a new byte to send into the TX buffer.
    * This prevents us from stuffing an extra byte.
    *****/

    /* Disable the TX interrupt. Since the last byte of the message
    * has been sent, disable the TX interrupt. If this is not done,
    * the ISR will be repeatedly invoked between the time that the
    * time that the UCA1TXBUF is empty and the time that the receive
    * byte is available in UCA1RXBUF.
    *****/


    if (TXData == 8)
    {
    // Reset EUSCIA1 (this disables RX & TX interrupts.
    UCA1CTLW0 |= UCSWRST;

    /* Turn the SPI Chip Select input into a regular input pin so the
    * main program can check that the SPI CS is not asserted before
    * re-enabling the SPI bus. P1SEL1 remains 0 for both the GPIO and
    * SPI functionality.
    *****/
    P3SEL1 &= ~BIT1;
    }

    }


    /* If both the RX & TX have completed, turn off the SPI interface.
    * The main program will turn it back on after it is finished
    * processing the message.
    *****/


    __delay_cycles(40);
    }

  • The P3SEL configures that pin for use as an SPI slave. It is an input, not an output. For the CS signal, just use a regular GPIO of your choice.

    TXIFG is set during reset so I have to assume that the driver library clears that or the interrupt would happen as soon as you set TXIE. You can set it yourself to kick off the transmit process. (UCA1IFG |= UCTXIFG; )

    Starting up an interrupt driven serial transmit is always tricky. As is shutting it down. Sometimes you can just shut it down by disabling the transmit interrupt and start it up be enabling it. That is what I usually do with the MSP430.

    Oh, please use the insert code feature so that your code appears in a scrollable sub window instead of just running on and on.

  • The SPI TX interrupt is now triggering. However, some of my transaction values are 16 bits long-- x88, xe0. How do I send this using EUSCI_SPI_transmitData function?

  • while (i < DCInit_transactions[TXData].Len){
      EUSCI_A_SPI_transmitData(EUSCI_A1_BASE, DCInit_transactions[TXData].Data[i]);
      i++;
    }

    Each TXIFG (in general) only allows you to send one byte to TXBUF. I think you can just remove the while():

       EUSCI_A_SPI_transmitData(EUSCI_A1_BASE, DCInit_transactions[TXData].Data[i]);
       i++;

    ---------------------

    if (TXData == 8)
    {
       UCA1CTLW0 |= UCSWRST;
       P3SEL1 &= ~BIT1;
    }

    This probably de-asserts  /CS before the last Tx byte has been sent. Wait for the SPI to no longer be busy (it won't take too long):

    if (TXData == 8)
    {
       while (UCA1STATW & UCBUSY)/*EMPTY*/;  // Wait for last byte to complete
       UCA1CTLW0 |= UCSWRST;
       P3SEL1 &= ~BIT1;
    }

  • #include <stdio.h>
    #include <stdlib.h>
    #include <stdint.h>
    #include <string.h>
    
    #include <driverlib.h>
    #include <msp430.h> 
    #include "clock~.h"                 // Clock configurations
    
    
    static uint8_t TXData = 0;
    
    typedef struct {
        uint8_t     Len;
        uint16_t    Data[5];
    } spi_MaximTrans_t;
    
    static spi_MaximTrans_t DCInit_transactions[15];
    
    
    uint8_t i = 0;
    
    /**
     *  Initialize system clocks
     */
    static void init_clock(void) {
        // Configure one FRAM waitstate as required by the device datasheet for MCLK
        // operation beyond 8MHz _before_ configuring the clock system.
        FRAMCtl_configureWaitStateControl(FRAMCTL_ACCESS_TIME_CYCLES_1);
    
        //Set DCO FLL reference = REFO
        CS_initClockSignal(CS_FLLREF, CS_REFOCLK_SELECT,   CS_CLOCK_DIVIDER_1);
        //Set ACLK = REFO
        CS_initClockSignal(CS_ACLK,   CS_REFOCLK_SELECT,   CS_CLOCK_DIVIDER_1);
    
        CS_initFLLParam param = {0};
        //Set Ratio/Desired MCLK Frequency, initialize DCO, save trim values
        CS_initFLLCalculateTrim(CS_MCLK_DESIRED_FREQUENCY_IN_KHZ, CS_MCLK_FLLREF_RATIO, &param);
    
        //Set MCLK = REFO
        CS_initClockSignal(CS_MCLK,   CS_REFOCLK_SELECT,   CS_CLOCK_DIVIDER_1);
        //Set SMCLK = DCO
        CS_initClockSignal(CS_SMCLK,  CS_DCOCLKDIV_SELECT, CS_CLOCK_DIVIDER_1);
    
        //Clear all OSC fault flag
        CS_clearAllOscFlagsWithTimeout(1000);
    }
    
    /**
     *  Initialize all of the IO pins per their configuration
     */
    static void init_gpio(void) {
        // Set all GPIO pins to output low to prevent floating input and reduce power consumption
        GPIO_setOutputLowOnPin(GPIO_PORT_P1, GPIO_PIN_ALL8);
        GPIO_setOutputLowOnPin(GPIO_PORT_P2, GPIO_PIN_ALL8);
        GPIO_setOutputLowOnPin(GPIO_PORT_P3, GPIO_PIN0|GPIO_PIN2|GPIO_PIN3|GPIO_PIN4|GPIO_PIN5|GPIO_PIN6|GPIO_PIN7);
        GPIO_setOutputLowOnPin(GPIO_PORT_P4, GPIO_PIN_ALL8);
        GPIO_setOutputLowOnPin(GPIO_PORT_P5, GPIO_PIN_ALL8);
        GPIO_setOutputLowOnPin(GPIO_PORT_P6, GPIO_PIN0 | GPIO_PIN1 | GPIO_PIN2);
    
        GPIO_setOutputHighOnPin(GPIO_PORT_P3, GPIO_PIN1);
    
        GPIO_setAsOutputPin(   GPIO_PORT_P1, GPIO_PIN_ALL8);
        GPIO_setAsOutputPin(   GPIO_PORT_P2, GPIO_PIN_ALL8);
        GPIO_setAsOutputPin(   GPIO_PORT_P3, GPIO_PIN_ALL8);
        GPIO_setAsOutputPin(   GPIO_PORT_P4, GPIO_PIN_ALL8);
        GPIO_setAsOutputPin(   GPIO_PORT_P5, GPIO_PIN_ALL8);
        GPIO_setAsOutputPin(   GPIO_PORT_P6, GPIO_PIN0 | GPIO_PIN1 | GPIO_PIN2);
    }
    
    /*
     * Initialize the SPI peripheral on EUSCI A1
     */
    void init_spi_peripheral()
    {
        //Initialize Master
            EUSCI_A_SPI_initMasterParam param = {0};
            param.selectClockSource = EUSCI_A_SPI_CLOCKSOURCE_SMCLK;
            param.clockSourceFrequency = CS_getSMCLK();
            param.desiredSpiClock = 1000000;
            param.msbFirst = UCMSB;
            param.clockPhase = 0;
            param.clockPolarity = EUSCI_A_SPI_CLOCKPOLARITY_INACTIVITY_LOW;
            param.spiMode = EUSCI_A_SPI_4PIN_UCxSTE_ACTIVE_LOW;
            EUSCI_A_SPI_initMaster(EUSCI_A1_BASE, &param);
    
            EUSCI_A_SPI_enable(EUSCI_A1_BASE);
    
            // Enable the TX and RX interrupts for the SPI bus.
            UCA1IE |= (UCRXIE | UCTXIE);
    
    }
    
    
    void SetUpTransactions(void){
        //Enable keep alive mode
        DCInit_transactions[0].Len = 2;
        DCInit_transactions[0].Data[0] = 0x10;
        DCInit_transactions[0].Data[1] = 0x5;
    
        //Enable Rx Interrupt flags
        DCInit_transactions[1].Len = 2;
        DCInit_transactions[1].Data[0] = 0x4;
        DCInit_transactions[1].Data[1] = 0x88;
    
        //Clear receive buffer
        DCInit_transactions[2].Len = 1;
        DCInit_transactions[2].Data[0] = 0xe0;
    
        //Wakeup UART slave devices
        DCInit_transactions[3].Len = 2;
        DCInit_transactions[3].Data[0] = 0xe0;
        DCInit_transactions[3].Data[1] = 0x30;
    
        //Wait for all UART slave devices to wake up
        DCInit_transactions[4].Len = 1;
        DCInit_transactions[4].Data[0] = 0x01;
    
        //End of UART slave device wake-up period
        DCInit_transactions[5].Len = 2;
        DCInit_transactions[5].Data[0] = 0x0e;
        DCInit_transactions[5].Data[1] = 0x10;
    
        //Wait for null message to be received
        DCInit_transactions[6].Len = 1;
        DCInit_transactions[6].Data[0] = 0x01;
    
        //Clear transmit buffer
        DCInit_transactions[7].Len = 1;
        DCInit_transactions[7].Data[0] = 0x20;
    
        //Clear receive buffer
        DCInit_transactions[8].Len = 1;
        DCInit_transactions[8].Data[0] = 0xe0;
    
    }
    
    
    /**
     * main.c
     */
    int main(void)
    {
    	WDTCTL = WDTPW | WDTHOLD;	// stop watchdog timer
    	
    
        init_clock();
        init_gpio();                                    // Set up IO pins
    
    
        // Set P1.0 to output direction
    
        GPIO_setAsOutputPin (GPIO_PORT_P1, GPIO_PIN0);
        GPIO_setAsInputPinWithPullUpResistor (GPIO_PORT_P4, GPIO_PIN2);
        GPIO_enableInterrupt (GPIO_PORT_P4, GPIO_PIN2);
        GPIO_selectInterruptEdge (GPIO_PORT_P4, GPIO_PIN2, GPIO_HIGH_TO_LOW_TRANSITION);
        GPIO_clearInterrupt (GPIO_PORT_P4, GPIO_PIN2);
    
        SetUpTransactions();
        TXData = 0x0;                             // Holds transaction number
    
    
    
        // Setup peripheral(s) now that gpio and clocks are setup
        init_spi_peripheral();                      // Init Maxim spi peripheral
        //Wait for slave to initialize
            __delay_cycles(100);
    
        GPIO_setOutputLowOnPin(GPIO_PORT_P3, GPIO_PIN1);        //Maxim chip select low
        UCA1IFG |= UCTXIFG;
    
    
    
        __bis_SR_register(LPM0_bits + GIE);      // CPU off, enable interrupts
        __no_operation();                       // Remain in LPM0
    
    
    	return 0;
    }
    
    //******************************************************************************
    //
    //This is the PORT2_VECTOR interrupt vector service routine
    //
    //******************************************************************************
    #if defined(__TI_COMPILER_VERSION__) || defined(__IAR_SYSTEMS_ICC__)
    #pragma vector=PORT4_VECTOR
    __interrupt
    #elif defined(__GNUC__)
    __attribute__((interrupt(PORT2_VECTOR)))
    #endif
    void P4_ISR (void)
    {
        GPIO_clearInterrupt (GPIO_PORT_P4, GPIO_PIN2);
        // Toggle P1.0 output
        GPIO_toggleOutputOnPin (GPIO_PORT_P1, GPIO_PIN0);
    }
    
    
    /****************************************************************************
     * EUSCI_A1_isr()
     *
     * This interrupt is used for SPI interrupts (UCA1).
     ****************************************************************************/
    #pragma vector = EUSCI_A1_VECTOR
    __interrupt void EUSCI_A1_isr(void)
    {
        // SPI TX interrupt?
        if (UCA1IFG & UCTXIFG)
        {
    
            EUSCI_A_SPI_transmitData(EUSCI_A1_BASE, DCInit_transactions[TXData].Data[i]);
            i++;
    
            if (i == DCInit_transactions[TXData].Len){
                UCA1IE &= ~UCTXIE;
                i = 0;
                TXData = TXData+1;
                if (TXData == 9) {
                    while (UCA1STATW & UCBUSY);     //wait for the last byte to transmit
                              // Reset EUSCIA1 (this disables RX & TX interrupts.
                    UCA1CTLW0 |= UCSWRST;
    
                          /* Turn the SPI Chip Select input into a regular input pin so the
                           * main program can check that the SPI CS is not asserted before
                           * re-enabling the SPI bus.  P1SEL1 remains 0 for both the GPIO and
                           * SPI functionality. *****/
    
                    GPIO_setOutputHighOnPin(GPIO_PORT_P3, GPIO_PIN1);
                 }
            }
            if (TXData < 9)
                UCA1IFG |= UCTXIFG;
    
            /* Put a new byte to send into the TX buffer.
             * This prevents us from stuffing an extra byte.
             *****/
    
                /* Disable the TX interrupt.  Since the last byte of the message
                 * has been sent, disable the TX interrupt.  If this is not done,
                 * the ISR will be repeatedly invoked between the time that the
                 * time that the UCA1TXBUF is empty and the time that the receive
                 * byte is available in UCA1RXBUF.
                 *****/
    
    
    
         }
    
    
        /* If both the RX & TX have completed, turn off the SPI interface.
         * The main program will turn it back on after it is finished
         * processing the message.
         *****/
    
    
        __delay_cycles(40);
    }
    
    
    

    Thank you for your replies. My current code is pasted to this post. I am concerned about transactions such as this:

    DCInit_transactions[1].Data[1] = 0x88;

    EUSCI_A_SPI_transmitData(EUSCI_A1_BASE, DCInit_transactions[TXData].Data[i]);

    EUSCI_A_SPI_transmitData expects 8 bit data, whereas 0x88 is 16 bits. 

  • The constant 0x88 is only 8 bits long. Skimming your program, I don't see any such constants which are more than 8 bits.

    If your device expects these 8-bit constants to be sent as 16-bit values over the bus, the simplest way is probably to double the Len field and explicitly insert the high-order 0x00 bytes. (Check the device data sheet for byte-ordering.)

  • Yes, there is nothing past 8 bits, I was confused. For some reason, the SPI transaction is not yet working.

    I will get a scope by this weekend. I will troubleshoot further with the scope and come back. I will keep this thread open until then.

  • How do you tell that the transaction isn't working? Is  your program hanging? Or is the device not behaving as expected? (Yes, a scope is very handy for a case like this.)

  • I expect an LED to light up on the SPI peripheral board at the end of wakeup. This happens when I use their evaluation GUI. I need to look at the scope signals to find out what is happening.

  • I got the scope. At this time, I am only viewing the LP SPI output signals. I don't have any slaves connected. I needed to add    PMM_unlockLPM5(); at the end of configuring GPIOs. Only after this, I can see the CS transition to the correct values. However, I don't see the SPI clock on the scope. Why is this? I am attaching my current code for your reference, it has not changed much since my last post.

    #include <stdio.h>
    #include <stdlib.h>
    #include <stdint.h>
    #include <string.h>
    
    #include <driverlib.h>
    #include <msp430.h> 
    #include "clock~.h"                 // Clock configurations
    
    
    static uint8_t TXData = 0;
    
    typedef struct {
        uint8_t     Len;
        uint8_t    Data[5];
    } spi_MaximTrans_t;
    
    static spi_MaximTrans_t DCInit_transactions[15];
    
    
    uint8_t SPI_TX_index = 0;
    
    /**
     *  Initialize system clocks
     */
    static void init_clock(void) {
        // Configure one FRAM waitstate as required by the device datasheet for MCLK
        // operation beyond 8MHz _before_ configuring the clock system.
        FRAMCtl_configureWaitStateControl(FRAMCTL_ACCESS_TIME_CYCLES_1);
    
        //Set DCO FLL reference = REFO
        CS_initClockSignal(CS_FLLREF, CS_REFOCLK_SELECT,   CS_CLOCK_DIVIDER_1);
        //Set ACLK = REFO
        CS_initClockSignal(CS_ACLK,   CS_REFOCLK_SELECT,   CS_CLOCK_DIVIDER_1);
    
        CS_initFLLParam param = {0};
        //Set Ratio/Desired MCLK Frequency, initialize DCO, save trim values
        CS_initFLLCalculateTrim(CS_MCLK_DESIRED_FREQUENCY_IN_KHZ, CS_MCLK_FLLREF_RATIO, &param);
    
        //Set MCLK = REFO
        CS_initClockSignal(CS_MCLK,   CS_REFOCLK_SELECT,   CS_CLOCK_DIVIDER_1);
        //Set SMCLK = DCO
        CS_initClockSignal(CS_SMCLK,  CS_DCOCLKDIV_SELECT, CS_CLOCK_DIVIDER_1);
    
        //Clear all OSC fault flag
        CS_clearAllOscFlagsWithTimeout(1000);
    }
    
    /**
     *  Initialize all of the IO pins per their configuration
     */
    static void init_gpio(void) {
        // Set all GPIO pins to output low to prevent floating input and reduce power consumption
        GPIO_setOutputLowOnPin(GPIO_PORT_P1, GPIO_PIN_ALL8);
        GPIO_setOutputLowOnPin(GPIO_PORT_P2, GPIO_PIN_ALL8);
        GPIO_setOutputLowOnPin(GPIO_PORT_P3, GPIO_PIN_ALL8);
        GPIO_setOutputLowOnPin(GPIO_PORT_P4, GPIO_PIN_ALL8);
        GPIO_setOutputLowOnPin(GPIO_PORT_P5, GPIO_PIN_ALL8);
        GPIO_setOutputLowOnPin(GPIO_PORT_P6, GPIO_PIN0 | GPIO_PIN1 | GPIO_PIN2);
    
    
    
    
    
        GPIO_setAsOutputPin(   GPIO_PORT_P1, GPIO_PIN_ALL8);
        GPIO_setAsOutputPin(   GPIO_PORT_P2, GPIO_PIN_ALL8);
        GPIO_setAsOutputPin(   GPIO_PORT_P3, GPIO_PIN_ALL8);
        GPIO_setAsOutputPin(   GPIO_PORT_P4, GPIO_PIN_ALL8);
        GPIO_setAsOutputPin(   GPIO_PORT_P5, GPIO_PIN_ALL8);
        GPIO_setAsOutputPin(   GPIO_PORT_P6, GPIO_PIN0 | GPIO_PIN1 | GPIO_PIN2);
    
    
    
    }
    
    /*
     * Initialize the SPI peripheral on EUSCI A1
     */
    void init_spi_peripheral()
    {
        //Initialize Master
            EUSCI_A_SPI_initMasterParam param = {0};
            param.selectClockSource = EUSCI_A_SPI_CLOCKSOURCE_SMCLK;
            param.clockSourceFrequency = CS_getSMCLK();
            param.desiredSpiClock = 1000000;
            param.msbFirst = UCMSB;
            param.clockPhase = 0;
            param.clockPolarity = EUSCI_A_SPI_CLOCKPOLARITY_INACTIVITY_LOW;
            param.spiMode = EUSCI_A_SPI_4PIN_UCxSTE_ACTIVE_LOW;
            EUSCI_A_SPI_initMaster(EUSCI_A1_BASE, &param);
    
            EUSCI_A_SPI_enable(EUSCI_A1_BASE);
    
            // Enable the TX and RX interrupts for the SPI bus.
            EUSCI_A_SPI_enableInterrupt(EUSCI_A1_BASE, EUSCI_A_SPI_TRANSMIT_INTERRUPT);
            EUSCI_A_SPI_enableInterrupt(EUSCI_A1_BASE, EUSCI_A_SPI_RECEIVE_INTERRUPT);
    
    }
    
    
    void SetUpTransactions(void){
        //Enable keep alive mode
        DCInit_transactions[0].Len = 2;
        DCInit_transactions[0].Data[0] = 0x10;
        DCInit_transactions[0].Data[1] = 0x5;
    
        //Enable Rx Interrupt flags
        DCInit_transactions[1].Len = 2;
        DCInit_transactions[1].Data[0] = 0x4;
        DCInit_transactions[1].Data[1] = 0x88;
    
        //Clear receive buffer
        DCInit_transactions[2].Len = 1;
        DCInit_transactions[2].Data[0] = 0xe0;
    
        //Wakeup UART slave devices
        DCInit_transactions[3].Len = 2;
        DCInit_transactions[3].Data[0] = 0xe0;
        DCInit_transactions[3].Data[1] = 0x30;
    
        //Wait for all UART slave devices to wake up
        DCInit_transactions[4].Len = 1;
        DCInit_transactions[4].Data[0] = 0x01;
    
        //End of UART slave device wake-up period
        DCInit_transactions[5].Len = 2;
        DCInit_transactions[5].Data[0] = 0x0e;
        DCInit_transactions[5].Data[1] = 0x10;
    
        //Wait for null message to be received
        DCInit_transactions[6].Len = 1;
        DCInit_transactions[6].Data[0] = 0x01;
    
        //Clear transmit buffer
        DCInit_transactions[7].Len = 1;
        DCInit_transactions[7].Data[0] = 0x20;
    
        //Clear receive buffer
        DCInit_transactions[8].Len = 1;
        DCInit_transactions[8].Data[0] = 0xe0;
    
    }
    
    
    /**
     * main.c
     */
    int main(void)
    {
    	WDTCTL = WDTPW | WDTHOLD;	// stop watchdog timer
    	
    
        init_clock();
        init_gpio();                                    // Set up IO pins
    
        GPIO_setOutputHighOnPin(GPIO_PORT_P3, GPIO_PIN1);
    
        // Configure SPI Pins for UCA1CLK, UCA1TXD/UCA1SIMO and UCA1RXD/UCA1SOMI
        /*
        * Select Port 2
        * Set Pin 4, Pin 5 and Pin 6 to input Secondary Module Function
        */
        GPIO_setAsPeripheralModuleFunctionInputPin(
            GPIO_PORT_P2,
            GPIO_PIN4 + GPIO_PIN5 + GPIO_PIN6,
            GPIO_PRIMARY_MODULE_FUNCTION
        );
    
        // Set P1.0 to output direction
    
        GPIO_setAsOutputPin (GPIO_PORT_P1, GPIO_PIN0);
        GPIO_setAsInputPinWithPullUpResistor (GPIO_PORT_P4, GPIO_PIN2);
        GPIO_enableInterrupt (GPIO_PORT_P4, GPIO_PIN2);
        GPIO_selectInterruptEdge (GPIO_PORT_P4, GPIO_PIN2, GPIO_HIGH_TO_LOW_TRANSITION);
        GPIO_clearInterrupt (GPIO_PORT_P4, GPIO_PIN2);
    
        PMM_unlockLPM5();
    
        SetUpTransactions();
        TXData = 0x0;                             // Holds transaction number
    
    
        // Setup peripheral(s) now that gpio and clocks are setup
        init_spi_peripheral();                      // Init Maxim spi peripheral
        //Wait for slave to initialize
            __delay_cycles(100);
    
        GPIO_setOutputLowOnPin(GPIO_PORT_P3, GPIO_PIN1);        //Maxim chip select low
        UCA1IFG |= UCTXIFG;
    
    
    
        __bis_SR_register(LPM0_bits + GIE);      // CPU off, enable interrupts
        __no_operation();                       // Remain in LPM0
    
    
    	return 0;
    }
    
    //******************************************************************************
    //
    //This is the PORT2_VECTOR interrupt vector service routine
    //
    //******************************************************************************
    #if defined(__TI_COMPILER_VERSION__) || defined(__IAR_SYSTEMS_ICC__)
    #pragma vector=PORT4_VECTOR
    __interrupt
    #elif defined(__GNUC__)
    __attribute__((interrupt(PORT2_VECTOR)))
    #endif
    void P4_ISR (void)
    {
        GPIO_setOutputHighOnPin(GPIO_PORT_P3, GPIO_PIN1);
        GPIO_clearInterrupt (GPIO_PORT_P4, GPIO_PIN2);
        // Toggle P1.0 output
        GPIO_toggleOutputOnPin (GPIO_PORT_P1, GPIO_PIN0);
    
        GPIO_disableInterrupt (GPIO_PORT_P4, GPIO_PIN2);
    }
    
    
    /****************************************************************************
     * EUSCI_A1_isr()
     *
     * This interrupt is used for SPI interrupts (UCA1).
     ****************************************************************************/
    #pragma vector = EUSCI_A1_VECTOR
    __interrupt void EUSCI_A1_isr(void)
    {
        // SPI TX interrupt?
        if (UCA1IFG & UCTXIFG)
        {
    
            EUSCI_A_SPI_transmitData(EUSCI_A1_BASE, DCInit_transactions[TXData].Data[SPI_TX_index]);
            SPI_TX_index++;
    
            if (SPI_TX_index == DCInit_transactions[TXData].Len){
                EUSCI_A_SPI_disableInterrupt(EUSCI_A1_BASE, EUSCI_A_SPI_TRANSMIT_INTERRUPT);
                SPI_TX_index = 0;
                TXData = TXData+1;
                if (TXData == 9) {
                    while (UCA1STATW & UCBUSY);     //wait for the last byte to transmit
                              // Reset EUSCIA1 (this disables RX & TX interrupts.
                    EUSCI_A_SPI_disableInterrupt(EUSCI_A1_BASE, EUSCI_A_SPI_TRANSMIT_INTERRUPT);
                    EUSCI_A_SPI_disableInterrupt(EUSCI_A1_BASE, EUSCI_A_SPI_RECEIVE_INTERRUPT);
    
                          /* Turn the SPI Chip Select input into a regular input pin so the
                           * main program can check that the SPI CS is not asserted before
                           * re-enabling the SPI bus.  P1SEL1 remains 0 for both the GPIO and
                           * SPI functionality. *****/
    
    
                 }
            }
            if (TXData < 9)
                UCA1IFG |= UCTXIFG;
    
            /* Put a new byte to send into the TX buffer.
             * This prevents us from stuffing an extra byte.
             *****/
    
                /* Disable the TX interrupt.  Since the last byte of the message
                 * has been sent, disable the TX interrupt.  If this is not done,
                 * the ISR will be repeatedly invoked between the time that the
                 * time that the UCA1TXBUF is empty and the time that the receive
                 * byte is available in UCA1RXBUF.
                 *****/
    
    
    
         }
    
    
        /* If both the RX & TX have completed, turn off the SPI interface.
         * The main program will turn it back on after it is finished
         * processing the message.
         *****/
    
    }
    
    
    

  • >param.spiMode = EUSCI_A_SPI_4PIN_UCxSTE_ACTIVE_LOW;

    Since you're not using the STE pin, this generates a UCFE on every byte [Ref User Guide (SLAU445I) Sec 23.3.3.1]. This is why you're not seeing any clocks. Use instead:

    >param.spiMode = EUSCI_A_SPI_3PIN;  // 3-pin mode -- We handle the /CS

    ----------------------

    >if (TXData < 9)
    >  UCA1IFG |= UCTXIFG;

    You shouldn't be triggering the TXIFG artificially here since the byte is (most likely) not sent yet. Just remove these lines.

    ----------------------

    > if (SPI_TX_index == DCInit_transactions[TXData].Len){
    >    EUSCI_A_SPI_disableInterrupt(EUSCI_A1_BASE, EUSCI_A_SPI_TRANSMIT_INTERRUPT);

    This disables TXIE after the first block, which is much too earlly. Just remove the second line. (It will be done a few lines below, at the right time.)

    ----------------------

    > EUSCI_A_SPI_enableInterrupt(EUSCI_A1_BASE, EUSCI_A_SPI_RECEIVE_INTERRUPT);

    You're not using the RXIFG, so you shouldn't enable it. Just remove this line.

  • This has much improved the SPI signals. I may still need to wait after one of the transactions during slave initialization. I will look closer at the peripheral registers. Thank you for the help.

**Attention** This is a public forum