MSP430FR6043: Use the UCA2's SPI port on PJ.0/PJ2/PJ3

Part Number: MSP430FR6043

Tool/software:

Hello;

I am trying to use the UCA2's SPI port on PJ.0/PJ2/PJ3. I could not get it working. 

Using the same code and mapped the UCA2's SPI to P5.2/P5.1/P5.0, it worked fine.

Below is the code I am using to configure the SPI port.

which is based on the example project "eusci_a_spi_ex1_master" that I downloaded.

Thanks!

================================

#include "driverlib.h"

uint8_t RXData = 0;
uint8_t TXData = 0;

void main(void)
{
volatile uint16_t i;

//Stop watchdog timer
WDT_A_hold(WDT_A_BASE);

/*
* Select Port 1
* Set Pin 0 as output
*/
GPIO_setAsOutputPin(
GPIO_PORT_P1,
GPIO_PIN0
);
/*
* Select Port 1
* Set Pin 0 to output Low.
*/
GPIO_setOutputLowOnPin(
GPIO_PORT_P1,
GPIO_PIN0
);

//Set DCO frequency to max DCO setting
CS_setDCOFreq(CS_DCORSEL_0, CS_DCOFSEL_3);
//Select DCO as the clock source for SMCLK with no frequency divider
CS_initClockSignal(CS_SMCLK, CS_DCOCLK_SELECT, CS_CLOCK_DIVIDER_1);

/*
* Select Port J
* Set Pin 0 to input Secondary Module Function, (UCA2CLK).
*/
GPIO_setAsPeripheralModuleFunctionInputPin(
GPIO_PORT_PJ,
GPIO_PIN0,
GPIO_SECONDARY_MODULE_FUNCTION
);

/*
* Select Port J
* Set Pin 2, 3 to input Secondary Module Function, (UCA2TXD/UCA2SIMO, UCA2RXD/UCA2SOMI).
*/
GPIO_setAsPeripheralModuleFunctionInputPin(
GPIO_PORT_PJ,
GPIO_PIN2 + GPIO_PIN3,
GPIO_SECONDARY_MODULE_FUNCTION
);

/*
* Disable the GPIO power-on default high-impedance mode to activate
* previously configured port settings
*/
PMM_unlockLPM5();

//Initialize Master
EUSCI_A_SPI_initMasterParam param = {0};
param.selectClockSource = EUSCI_A_SPI_CLOCKSOURCE_SMCLK;
param.clockSourceFrequency = CS_getSMCLK();
param.desiredSpiClock = 500000;
param.msbFirst = EUSCI_A_SPI_MSB_FIRST;
param.clockPhase = EUSCI_A_SPI_PHASE_DATA_CHANGED_ONFIRST_CAPTURED_ON_NEXT;
param.clockPolarity = EUSCI_A_SPI_CLOCKPOLARITY_INACTIVITY_HIGH;
param.spiMode = EUSCI_A_SPI_3PIN;
EUSCI_A_SPI_initMaster(EUSCI_A2_BASE, &param);

//Enable SPI module
EUSCI_A_SPI_enable(EUSCI_A2_BASE);

EUSCI_A_SPI_clearInterrupt(EUSCI_A2_BASE,
EUSCI_A_SPI_RECEIVE_INTERRUPT);
// Enable USCI_A2 RX interrupt
EUSCI_A_SPI_enableInterrupt(EUSCI_A2_BASE,
EUSCI_A_SPI_RECEIVE_INTERRUPT);

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

TXData = 0x1; // Holds TX data

//USCI_A2 TX buffer ready?
while (!EUSCI_A_SPI_getInterruptStatus(EUSCI_A2_BASE,
EUSCI_A_SPI_TRANSMIT_INTERRUPT)) ;

//Transmit Data to slave
EUSCI_A_SPI_transmitData(EUSCI_A2_BASE, TXData);

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

#if defined(__TI_COMPILER_VERSION__) || defined(__IAR_SYSTEMS_ICC__)
#pragma vector=USCI_A2_VECTOR
__interrupt
#elif defined(__GNUC__)
__attribute__((interrupt(USCI_A2_VECTOR)))
#endif
void USCI_A2_ISR(void)
{
switch(__even_in_range(UCA2IV, USCI_SPI_UCTXIFG))
{
case USCI_SPI_UCRXIFG: // UCRXIFG
//USCI_A2 TX buffer ready?
while (!EUSCI_A_SPI_getInterruptStatus(EUSCI_A2_BASE,
EUSCI_A_SPI_TRANSMIT_INTERRUPT));

RXData = EUSCI_A_SPI_receiveData(EUSCI_A2_BASE);

//Increment data
TXData++;

//Send next value
EUSCI_A_SPI_transmitData(EUSCI_A2_BASE,
TXData
);

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

  • GPIO_setAsPeripheralModuleFunctionInputPin(GPIO_PORT_PJ,GPIO_PIN2 + GPIO_PIN3,GPIO_SECONDARY_MODULE_FUNCTION);

    Per data sheet (SLASEF5B) Table 9-47, for UCA2 the PSEL=01, so this should be:

    GPIO_setAsPeripheralModuleFunctionInputPin(GPIO_PORT_PJ,GPIO_PIN2 + GPIO_PIN3,GPIO_PRIMARY_MODULE_FUNCTION);

    Similarly for PJ.0.

  • Thank you so much for the quick reply.

    I have changed GPIO setting according to your suggestion: using GPIO_PRIMARY_MODULE_FUNCTION.

    I still could not get the PJ.0/UCA2CLK working, there is no SPI clock output.

    However, I did see the PJ2/UCA2SIMO output data signal.

    Any suggestion?

    Here is the updated code:

    //========================

    #include "driverlib.h"

    uint8_t RXData = 0;
    uint8_t TXData = 0;

    void main(void)
    {
    volatile uint16_t i;

    //Stop watchdog timer
    WDT_A_hold(WDT_A_BASE);

    /*
    * Select Port 1
    * Set Pin 0 as output
    */
    GPIO_setAsOutputPin(
    GPIO_PORT_P1,
    GPIO_PIN0
    );
    /*
    * Select Port 1
    * Set Pin 0 to output Low.
    */
    GPIO_setOutputLowOnPin(
    GPIO_PORT_P1,
    GPIO_PIN0
    );

    //Set DCO frequency to max DCO setting
    CS_setDCOFreq(CS_DCORSEL_0, CS_DCOFSEL_3);
    //Select DCO as the clock source for SMCLK with no frequency divider
    CS_initClockSignal(CS_SMCLK, CS_DCOCLK_SELECT, CS_CLOCK_DIVIDER_1);

    /*
    * Select Port J
    * Set Pin 0 to input Secondary Module Function, (UCA2CLK).
    */
    GPIO_setAsPeripheralModuleFunctionInputPin(
    GPIO_PORT_PJ,
    GPIO_PIN0,
    GPIO_PRIMARY_MODULE_FUNCTION
    );

    /*
    * Select Port J
    * Set Pin 2, 3 to input Secondary Module Function, (UCA2TXD/UCA2SIMO, UCA2RXD/UCA2SOMI).
    */
    GPIO_setAsPeripheralModuleFunctionInputPin(
    GPIO_PORT_PJ,
    GPIO_PIN2 + GPIO_PIN3,
    GPIO_PRIMARY_MODULE_FUNCTION
    );

    /*
    * Disable the GPIO power-on default high-impedance mode to activate
    * previously configured port settings
    */
    PMM_unlockLPM5();

    //Initialize Master
    EUSCI_A_SPI_initMasterParam param = {0};
    param.selectClockSource = EUSCI_A_SPI_CLOCKSOURCE_SMCLK;
    param.clockSourceFrequency = CS_getSMCLK();
    param.desiredSpiClock = 500000;
    param.msbFirst = EUSCI_A_SPI_MSB_FIRST;
    param.clockPhase = EUSCI_A_SPI_PHASE_DATA_CHANGED_ONFIRST_CAPTURED_ON_NEXT;
    param.clockPolarity = EUSCI_A_SPI_CLOCKPOLARITY_INACTIVITY_HIGH;
    param.spiMode = EUSCI_A_SPI_3PIN;
    EUSCI_A_SPI_initMaster(EUSCI_A2_BASE, &param);

    //Enable SPI module
    EUSCI_A_SPI_enable(EUSCI_A2_BASE);

    EUSCI_A_SPI_clearInterrupt(EUSCI_A2_BASE,
    EUSCI_A_SPI_RECEIVE_INTERRUPT);
    // Enable USCI_A2 RX interrupt
    EUSCI_A_SPI_enableInterrupt(EUSCI_A2_BASE,
    EUSCI_A_SPI_RECEIVE_INTERRUPT);

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

    TXData = 0x1; // Holds TX data

    //USCI_A2 TX buffer ready?
    while (!EUSCI_A_SPI_getInterruptStatus(EUSCI_A2_BASE,
    EUSCI_A_SPI_TRANSMIT_INTERRUPT)) ;

    //Transmit Data to slave
    EUSCI_A_SPI_transmitData(EUSCI_A2_BASE, TXData);

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

    #if defined(__TI_COMPILER_VERSION__) || defined(__IAR_SYSTEMS_ICC__)
    #pragma vector=USCI_A2_VECTOR
    __interrupt
    #elif defined(__GNUC__)
    __attribute__((interrupt(USCI_A2_VECTOR)))
    #endif
    void USCI_A2_ISR(void)
    {
    switch(__even_in_range(UCA2IV, USCI_SPI_UCTXIFG))
    {
    case USCI_SPI_UCRXIFG: // UCRXIFG
    //USCI_A2 TX buffer ready?
    while (!EUSCI_A_SPI_getInterruptStatus(EUSCI_A2_BASE,
    EUSCI_A_SPI_TRANSMIT_INTERRUPT));

    RXData = EUSCI_A_SPI_receiveData(EUSCI_A2_BASE);

    //Increment data
    TXData++;

    //Send next value
    EUSCI_A_SPI_transmitData(EUSCI_A2_BASE,
    TXData
    );

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

  • Apparently there is indeed something odd about PJ.0 -- for UCA2CLK you have to explicitly make it an output to make it work:

    https://e2e.ti.com/support/microcontrollers/msp-low-power-microcontrollers-group/msp430/f/msp-low-power-microcontroller-forum/820120/msp430fr6043-issue-with-spi-clk-uca2-when-mapped-to-port-pj

    That thread suggests setting PJDIR directly. There's also a function GPIO_setAsPeripheralModuleFunctionOutputPin() if you prefer.

**Attention** This is a public forum