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.

MSP430FR5969: UCA1 SPI PROBLEM - CLOCK JITTER

Part Number: MSP430FR5969

Hi,

I'm trying to use UCA1 SPI to communicate the MSP430FR5969 with HopeRF RFM69 transceiver. So the MSP430 (master) sends commands to configure the RFM69 and makes it transmit some data. However the transceiver doesn't work and when I check the SPI signals by logic analyser, there are some clock jitters (as in pictures) which makes the MSP430 randomly sends some wrong data to the RFM69. I have tested it on both the board EXP430FR5969 and seperately with the MSP430FR5969 chip (I made a PCB) and both had this problem. Some commands are correct and some are not due to these strange jitters.

But when I used the UCB0 SPI on the EXP430FR5969 it worked just fine, the transceiver could transmit data (tested for many times). I have included my "SPI.h" and "SPI.c" below, these were written based on the example "msp430fr59xx_eusci_spi_standard_master.c". Can you please help?

  4617.SPI.h

//******************************************************************************
//   MSP430FR59xx Demo - eUSCI_A0, SPI 3-Wire Master multiple byte RX/TX
//
//   Description: SPI master communicates to SPI slave sending and receiving
//   3 different messages of different length. SPI master will enter LPM0 mode
//   while waiting for the messages to be sent/receiving using SPI interrupt.
//   SPI Master will initially wait for a port interrupt in LPM0 mode before
//   starting the SPI communication.
//   ACLK = NA, MCLK = SMCLK = DCO 16MHz.
//
//
//                   MSP430FR5969
//                 -----------------
//            /|\ |             P1.3|-> Slave Chip Select (GPIO)
//             |  |                 |
//             ---|RST          P1.4|-> Slave Reset (GPIO)
//                |                 |
//                |             P2.5|-> Data Out (UCA1MOSI)
//                |                 |
//       Button ->|P1.1         P2.6|<- Data In (UCA1MISO)
//                |                 |
//                |             P2.4|-> Serial Clock Out (UCA1CLK)
//
//   Nima Eskandari
//   Texas Instruments Inc.
//   April 2017
//   Built with CCS V7.0
//******************************************************************************

#include <SPI.h>


void SendUCA1Data(uint8_t val)
{
    while (!(UCA1IFG & UCTXIFG));              // USCI_A0 TX buffer ready?
    UCA1TXBUF = val;
}

void SPI_CopyArray(uint8_t *source, uint8_t *dest, uint8_t count)
{
    uint8_t copyIndex = 0;
    for (copyIndex = 0; copyIndex < count; copyIndex++)
    {
        dest[copyIndex] = source[copyIndex];
    }
}


SPI_Mode SPI_Master_WriteReg(uint8_t reg_addr, uint8_t *reg_data, uint8_t count)
{
    MasterMode = TX_REG_ADDRESS_MODE;
    SPI_TransmitRegAddr = reg_addr | 0x80;

    //Copy register data to SPI_TransmitBuffer
    SPI_CopyArray(reg_data, SPI_TransmitBuffer, count);

    SPI_TXByteCtr = count;
    SPI_RXByteCtr = 0;
    SPI_ReceiveIndex = 0;
    SPI_TransmitIndex = 0;

    SLAVE_CS_OUT &= ~(SLAVE_CS_PIN);

    SendUCA1Data(SPI_TransmitRegAddr);

    __bis_SR_register(LPM3_bits + GIE);              // Enter LPM3 w/ interrupts

    SLAVE_CS_OUT |= SLAVE_CS_PIN;

    return MasterMode;
}

SPI_Mode SPI_Master_ReadReg(uint8_t reg_addr, uint8_t count)
{
    MasterMode = TX_REG_ADDRESS_MODE;
    SPI_TransmitRegAddr = reg_addr & 0x7F;
    SPI_RXByteCtr = count;
    SPI_TXByteCtr = 0;
    SPI_ReceiveIndex = 0;
    SPI_TransmitIndex = 0;

    SLAVE_CS_OUT &= ~(SLAVE_CS_PIN);
    SendUCA1Data(SPI_TransmitRegAddr);

    __bis_SR_register(LPM3_bits + GIE);              // Enter LPM3 w/ interrupts

    SLAVE_CS_OUT |= SLAVE_CS_PIN;
    return MasterMode;
}

//******************************************************************************
// Device Initialization *******************************************************
//******************************************************************************

void SPI_init()
{
    //Clock Polarity: The inactive state is high
    //MSB First, 8-bit, Master, 3-pin mode, Synchronous
    UCA1CTLW0 = UCSWRST;                       // **Put state machine in reset**
    UCA1CTLW0 |= UCMSB + UCSYNC
                + UCMST + UCSSEL__SMCLK;      // 3-pin, 8-bit SPI Slave
    UCA1BRW = 0x08;                         // Prescaler = 8, f(spi) = f(clk)/8
    //UCA1BRW = 0x20;                         // Prescaler = 8, f(spi) = f(clk)/8

    //UCA1MCTLW = 0;
    UCA1CTLW0 &= ~UCSWRST;                     // **Initialize USCI state machine**
    UCA1IE |= UCRXIE;                          // Enable USCI0 RX interrupt

    /* Used to track the state of the software state machine*/
    MasterMode = IDLE_MODE;

    /* The Register Address/Command to use*/
    SPI_TransmitRegAddr = 0;

    /* SPI_ReceiveBuffer: Buffer used to receive data in the ISR
     * SPI_RXByteCtr: Number of bytes left to receive
     * SPI_ReceiveIndex: The index of the next byte to be received in SPI_ReceiveBuffer
     * SPI_TransmitBuffer: Buffer used to transmit data in the ISR
     * SPI_TXByteCtr: Number of bytes left to transfer
     * SPI_TransmitIndex: The index of the next byte to be transmitted in SPI_TransmitBuffer
     * */
    SPI_ReceiveBuffer[SPI_MAX_BUFFER_SIZE] = {0};
    SPI_RXByteCtr = 0;
    SPI_ReceiveIndex = 0;
    SPI_TransmitBuffer[SPI_MAX_BUFFER_SIZE] = {0};
    SPI_TXByteCtr = 0;
    SPI_TransmitIndex = 0;
}


void SPI_initGPIO()
{

    //P4DIR |= BIT3;                          // Set pin 4.3 as output for chip enable (CE)
    //P4OUT |= BIT3;

    // Configure GPIO

    /* Connect up SIMO, MISO. */

    //P1SEL1 |= BIT6|BIT7;
    //P1SEL0 &= ~(BIT6|BIT7);
    P2SEL1 |= BIT4 | BIT5 | BIT6;           // Enable pin 2.4 (SCL), 2.5 (MOSI), 2.6 (MISO)
    P2SEL0 &= ~(BIT4|BIT5|BIT6);
    /* Connect up SCLK. */

    //P2SEL1 |= BIT2;
    //P2SEL0 &= ~BIT2;

    SLAVE_CS_DIR |= SLAVE_CS_PIN;
    SLAVE_CS_OUT |= SLAVE_CS_PIN;

    // Disable the GPIO power-on default high-impedance mode to activate
    // previously configured port settings
    PM5CTL0 &= ~LOCKLPM5;
}

void SPI_initClockTo8MHz()
{
    // Configure one FRAM waitstate as required by the device datasheet for MCLK
    // operation beyond 8MHz _before_ configuring the clock system.
    FRCTL0 = FRCTLPW | NWAITS_1;

    // Clock System Setup
    CSCTL0_H = CSKEY >> 8;                    // Unlock CS registers
    CSCTL1 = DCOFSEL_3 | DCORSEL;             // Set DCO to 8MHz
    //CSCTL1 = DCOFSEL_4 | DCORSEL;             // Set DCO to 16MHz
    CSCTL2 = SELA__VLOCLK | SELS__DCOCLK | SELM__DCOCLK;
    CSCTL3 = DIVA__1 | DIVS__1 | DIVM__1;     // Set all dividers

    CSCTL0_H = 0;                             // Lock CS registerss
}



//******************************************************************************
// SPI Interrupt ***************************************************************
//******************************************************************************

#if defined(__TI_COMPILER_VERSION__) || defined(__IAR_SYSTEMS_ICC__)
#pragma vector=USCI_A1_VECTOR
__interrupt void USCI_A1_ISR(void)
#elif defined(__GNUC__)
void __attribute__ ((interrupt(USCI_A0_VECTOR))) USCI_A1_ISR (void)
#else
#error Compiler not supported!
#endif
{
    uint8_t UCA1_rx_val = 0;
    switch(__even_in_range(UCA1IV, USCI_SPI_UCTXIFG))
    {
        case USCI_NONE: break;
        case USCI_SPI_UCRXIFG:         // Receive interrupt flag. UCRXIFG is set when UCAxRXBUF has received a complete character.
            UCA1_rx_val = UCA1RXBUF;
            UCA1IFG &= ~UCRXIFG;
            switch (MasterMode)
            {
                case TX_REG_ADDRESS_MODE:
                    if (SPI_RXByteCtr)
                    {
                        MasterMode = RX_DATA_MODE;   // Need to start receiving now
                        //Send Dummy To Start receiving
                        //__delay_cycles(20000);
                        SendUCA1Data(DUMMY);
                    }
                    else
                    {

                        MasterMode = TX_DATA_MODE;        // Continue to transmision with the data in Transmit Buffer
                        //Send First
                        SendUCA1Data(SPI_TransmitBuffer[SPI_TransmitIndex++]);
                        SPI_TXByteCtr--;
                    }
                    break;

                case TX_DATA_MODE:
                    //uartTxString("Enter TX_DATA_MODE  \n");

                    if (SPI_TXByteCtr)
                    {
                      SendUCA1Data(SPI_TransmitBuffer[SPI_TransmitIndex++]);
                      SPI_TXByteCtr--;
                    }
                    else
                    {
                      //Done with transmission
                      MasterMode = IDLE_MODE;
                      __bic_SR_register_on_exit(LPM3_bits);      // Exit LPM3
                    }
                    break;

                case RX_DATA_MODE:
                    //uartTxString("Enter RX_DATA_MODE  \n");

                    if (SPI_RXByteCtr)
                    {
                        SPI_ReceiveBuffer[SPI_ReceiveIndex++] = UCA1_rx_val;
                        //Transmit a dummy
                        SPI_RXByteCtr--;
                    }
                    if (SPI_RXByteCtr == 0)
                    {
                        MasterMode = IDLE_MODE;
                        __bic_SR_register_on_exit(LPM3_bits);      // Exit LPM3
                    }
                    else
                    {
                        SendUCA1Data(DUMMY);
                    }
                    break;

                default:
                    __no_operation();
                    break;
            }
            //__delay_cycles(1000);
            break;
        case USCI_SPI_UCTXIFG:
            break;
        default: break;
    }
}

  • Thai,

    If you run the example loopback code without adding anything extra, do you still see the issue? The device errata sheet can be found below. USCI45 sounds similar, but it does not look like you have asynchronous clock. When you run using the UCB0 SPI, is the code exactly the same except for the change to UCB0?

    www.ti.com/.../slaz473ab.pdf
  • Hi Eddie,

    Thanks for your reply. I fixed the problem. It is the SPI signals timing diagram from the example code didn't match the required timing diagram of the RFM69. The RFM69 requires "MOSI is generated by the master on the falling edge of SCK and is sampled by the slave (i.e. this SPI interface) on the rising edge of SCK", while the example code put it the other way around. For some unknown reason the example code still worked on UCB0. Now when I configure the correct timing diagram for the SPI of the MSP430 it works fine on both interfaces.

**Attention** This is a public forum