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.

MSP430F5529: How to configure the 4 wire SPI Connection in salve MCU?

Part Number: MSP430F5529
Other Parts Discussed in Thread: MSP430WARE

Tool/software:

I have write the following code for SPI configuration but can't able to receive the data from the master

void spi_init(void)
{

P3SEL |= BIT0; // SOMI
P3SEL |= BIT1; // SIM0
P3SEL |= BIT2; // CLK
P2SEL |= BIT7; //CS

//P2DIR &= ~(BIT7) ; // Slave Select

UCB0CTL1 |= UCSWRST; // **Put state machine in reset**
UCB0CTL0 |= UCMODE_2+UCSYNC+UCCKPL+UCMSB; // 4-pin, 8-bit SPI Slave 0 enabled
// Clock polarity high, MSB
UCB0CTL1 &= ~UCSWRST; // **Initialize USCI state machine**
UCB0IE |= UCRXIE; // Enable USCI_B0 RX interrupt

}

  • Hi, 

    Please refer to MSP430's SDK:

    C:\ti\msp\MSP430Ware_3_80_14_01\examples\devices\MSP430F5xx_6xx\MSP430F55xx_Code_Examples\C

    Here is the 4 wires SPI slave example code:

    6558.MSP430F55xx_usci_spi_standard_slave.c
    //******************************************************************************
    //   MSP430F552x Demo - USCI_A0, SPI 3-Wire Slave multiple byte RX/TX
    //
    //   Description: SPI master communicates to SPI slave sending and receiving
    //   3 different messages of different length. SPI slave will enter LPM0
    //   while waiting for the messages to be sent/receiving using SPI interrupt.
    //   ACLK = NA, MCLK = SMCLK = DCO 16MHz.
    //
    //
    //                   MSP430F5529
    //                 -----------------
    //            /|\ |             P2.0|<- Master's GPIO (Chip Select)
    //             |  |                 |
    //             ---|RST          RST |<- Master's GPIO (To reset slave)
    //                |                 |
    //                |             P3.3|<- Data In (UCA0SIMO)
    //                |                 |
    //                |             P3.4|-> Data Out (UCA0SOMI)
    //                |                 |
    //                |             P2.7|<- Serial Clock In (UCA0CLK)
    //
    //   Nima Eskandari
    //   Texas Instruments Inc.
    //   April 2017
    //   Built with CCS V7.0
    //******************************************************************************
    
    #include <msp430.h> 
    #include <stdint.h>
    #include <stdbool.h>
    
    //******************************************************************************
    // Example Commands ************************************************************
    //******************************************************************************
    
    #define DUMMY   0xFF
    
    #define SLAVE_CS_IN     P2IN
    #define SLAVE_CS_DIR    P2DIR
    #define SLAVE_CS_PIN    BIT0
    
    /* CMD_TYPE_X_SLAVE are example commands the master sends to the slave.
     * The slave will send example SlaveTypeX buffers in response.
     *
     * CMD_TYPE_X_MASTER are example commands the master sends to the slave.
     * The slave will initialize itself to receive MasterTypeX example buffers.
     * */
    
    #define CMD_TYPE_0_SLAVE              0
    #define CMD_TYPE_1_SLAVE              1
    #define CMD_TYPE_2_SLAVE              2
    
    #define CMD_TYPE_0_MASTER              3
    #define CMD_TYPE_1_MASTER              4
    #define CMD_TYPE_2_MASTER              5
    
    #define TYPE_0_LENGTH              1
    #define TYPE_1_LENGTH              2
    #define TYPE_2_LENGTH              6
    
    #define MAX_BUFFER_SIZE     20
    
    /* MasterTypeX are example buffers initialized in the master, they will be
     * sent by the master to the slave.
     * SlaveTypeX are example buffers initialized in the slave, they will be
     * sent by the slave to the master.
     * */
    
    uint8_t MasterType2 [TYPE_2_LENGTH] = {0};
    uint8_t MasterType1 [TYPE_1_LENGTH] = { 0, 0};
    uint8_t MasterType0 [TYPE_0_LENGTH] = { 0};
    
    uint8_t SlaveType2 [TYPE_2_LENGTH] = {'A', 'B', 'C', 'D', '1', '2'};
    uint8_t SlaveType1 [TYPE_1_LENGTH] = {0x15, 0x16};
    uint8_t SlaveType0 [TYPE_0_LENGTH] = {12};
    
    //******************************************************************************
    // General SPI State Machine ***************************************************
    //******************************************************************************
    
    typedef enum SPI_ModeEnum{
        IDLE_MODE,
        TX_REG_ADDRESS_MODE,
        RX_REG_ADDRESS_MODE,
        TX_DATA_MODE,
        RX_DATA_MODE,
        TIMEOUT_MODE
    } SPI_Mode;
    
    /* Used to track the state of the software state machine*/
    SPI_Mode SlaveMode = RX_REG_ADDRESS_MODE;
    
    /* The Register Address/Command to use*/
    uint8_t ReceiveRegAddr = 0;
    
    /* ReceiveBuffer: Buffer used to receive data in the ISR
     * RXByteCtr: Number of bytes left to receive
     * ReceiveIndex: The index of the next byte to be received in ReceiveBuffer
     * TransmitBuffer: Buffer used to transmit data in the ISR
     * TXByteCtr: Number of bytes left to transfer
     * TransmitIndex: The index of the next byte to be transmitted in TransmitBuffer
     * */
    uint8_t ReceiveBuffer[MAX_BUFFER_SIZE] = {0};
    uint8_t RXByteCtr = 0;
    uint8_t ReceiveIndex = 0;
    uint8_t TransmitBuffer[MAX_BUFFER_SIZE] = {0};
    uint8_t TXByteCtr = 0;
    uint8_t TransmitIndex = 0;
    
    /* Initialized the software state machine according to the received cmd
     *
     * cmd: The command/register address received
     * */
    void SPI_Slave_ProcessCMD(uint8_t cmd);
    
    /* The transaction between the slave and master is completed. Uses cmd
     * to do post transaction operations. (Place data from ReceiveBuffer
     * to the corresponding buffer based in the last received cmd)
     *
     * cmd: The command/register address corresponding to the completed
     * transaction
     */
    void SPI_Slave_TransactionDone(uint8_t cmd);
    void CopyArray(uint8_t *source, uint8_t *dest, uint8_t count);
    void SendUCA0Data(uint8_t val);
    
    void SendUCA0Data(uint8_t val)
    {
        while (!(UCA0IFG & UCTXIFG));              // USCI_A0 TX buffer ready?
        UCA0TXBUF = val;
    }
    
    void SPI_Slave_ProcessCMD(uint8_t cmd)
    {
        ReceiveIndex = 0;
        TransmitIndex = 0;
        RXByteCtr = 0;
        TXByteCtr = 0;
    
        switch (cmd)
        {
            case (CMD_TYPE_0_SLAVE):                        //Send slave device id (This device's id)
                SlaveMode = TX_DATA_MODE;
                TXByteCtr = TYPE_0_LENGTH;
                //Fill out the TransmitBuffer
                CopyArray(SlaveType0, TransmitBuffer, TYPE_0_LENGTH);
                //Send First Byte
                SendUCA0Data(TransmitBuffer[TransmitIndex++]);
                TXByteCtr--;
                break;
            case (CMD_TYPE_1_SLAVE):                      //Send slave device time (This device's time)
                SlaveMode = TX_DATA_MODE;
                TXByteCtr = TYPE_1_LENGTH;
                //Fill out the TransmitBuffer
                CopyArray(SlaveType1, TransmitBuffer, TYPE_1_LENGTH);
                //Send First Byte
                SendUCA0Data(TransmitBuffer[TransmitIndex++]);
                TXByteCtr--;
                break;
            case (CMD_TYPE_2_SLAVE):                  //Send slave device location (This device's location)
                SlaveMode = TX_DATA_MODE;
                TXByteCtr = TYPE_2_LENGTH;
                //Fill out the TransmitBuffer
                CopyArray(SlaveType2, TransmitBuffer, TYPE_2_LENGTH);
                //Send First Byte
                SendUCA0Data(TransmitBuffer[TransmitIndex++]);
                TXByteCtr--;
                break;
            case (CMD_TYPE_0_MASTER):
                SlaveMode = RX_DATA_MODE;
                RXByteCtr = TYPE_0_LENGTH;
                break;
            case (CMD_TYPE_1_MASTER):
                SlaveMode = RX_DATA_MODE;
                RXByteCtr = TYPE_1_LENGTH;
                break;
            case (CMD_TYPE_2_MASTER):
                SlaveMode = RX_DATA_MODE;
                RXByteCtr = TYPE_2_LENGTH;
                break;
            default:
                //while(1);
                __no_operation();
                break;
        }
    }
    
    
    void SPI_Slave_TransactionDone(uint8_t cmd)
    {
        switch (cmd)
        {
            case (CMD_TYPE_0_SLAVE):                        //Slave device id was sent(This device's id)
                break;
            case (CMD_TYPE_1_SLAVE):                      //Slave device time was sent(This device's time)
                break;
            case (CMD_TYPE_2_SLAVE):                  //Send slave device location (This device's location)
                break;
            case (CMD_TYPE_0_MASTER):
                CopyArray(ReceiveBuffer, MasterType0, TYPE_0_LENGTH);
                break;
            case (CMD_TYPE_1_MASTER):
                CopyArray(ReceiveBuffer, MasterType1, TYPE_1_LENGTH);
                break;
            case (CMD_TYPE_2_MASTER):
                CopyArray(ReceiveBuffer, MasterType2, TYPE_2_LENGTH);
                break;
            default:
                __no_operation();
                break;
        }
    }
    
    void CopyArray(uint8_t *source, uint8_t *dest, uint8_t count)
    {
        uint8_t copyIndex = 0;
        for (copyIndex = 0; copyIndex < count; copyIndex++)
        {
            dest[copyIndex] = source[copyIndex];
        }
    }
    
    
    //******************************************************************************
    // Device Initialization *******************************************************
    //******************************************************************************
    
    void initGPIO()
    {
      //LEDs
      P1OUT = 0x00;                             // P1 setup for LED & reset output
      P1DIR |= BIT0 + BIT5;
    
      P4DIR |= BIT7;
      P4OUT &= ~(BIT7);
    
      //SPI Pins
      P3SEL |= BIT3 + BIT4;                     // P3.3,4 option select
      P2SEL |= BIT7;                            // P2.7 option select
    
    }
    
    void initSPI()
    {
      //Clock Polarity: The inactive state is high
      //MSB First, 8-bit, Master, 3-pin mode, Synchronous
      UCA0CTL1 = UCSWRST;                       // **Put state machine in reset**
      UCA0CTL0 |= UCCKPL + UCMSB + UCSYNC;      // 3-pin, 8-bit SPI Slave
      UCA0CTL1 &= ~UCSWRST;                     // **Initialize USCI state machine**
      UCA0IE |= UCRXIE;                          // Enable USCI0 RX interrupt
    
      SLAVE_CS_DIR &= ~(SLAVE_CS_PIN);
    
    }
    
    void initClockTo16MHz()
    {
        UCSCTL3 |= SELREF_2;                      // Set DCO FLL reference = REFO
        UCSCTL4 |= SELA_2;                        // Set ACLK = REFO
        __bis_SR_register(SCG0);                  // Disable the FLL control loop
        UCSCTL0 = 0x0000;                         // Set lowest possible DCOx, MODx
        UCSCTL1 = DCORSEL_5;                      // Select DCO range 16MHz operation
        UCSCTL2 = FLLD_0 + 487;                   // Set DCO Multiplier for 16MHz
                                                  // (N + 1) * FLLRef = Fdco
                                                  // (487 + 1) * 32768 = 16MHz
                                                  // Set FLL Div = fDCOCLK
        __bic_SR_register(SCG0);                  // Enable the FLL control loop
    
        // Worst-case settling time for the DCO when the DCO range bits have been
        // changed is n x 32 x 32 x f_MCLK / f_FLL_reference. See UCS chapter in 5xx
        // UG for optimization.
        // 32 x 32 x 16 MHz / 32,768 Hz = 500000 = MCLK cycles for DCO to settle
        __delay_cycles(500000);//
        // Loop until XT1,XT2 & DCO fault flag is cleared
        do
        {
            UCSCTL7 &= ~(XT2OFFG + XT1LFOFFG + DCOFFG); // Clear XT2,XT1,DCO fault flags
            SFRIFG1 &= ~OFIFG;                          // Clear fault flags
        }while (SFRIFG1&OFIFG);                         // Test oscillator fault flag
    }
    
    uint16_t setVCoreUp(uint8_t level){
        uint32_t PMMRIE_backup, SVSMHCTL_backup, SVSMLCTL_backup;
    
        //The code flow for increasing the Vcore has been altered to work around
        //the erratum FLASH37.
        //Please refer to the Errata sheet to know if a specific device is affected
        //DO NOT ALTER THIS FUNCTION
    
        //Open PMM registers for write access
        PMMCTL0_H = 0xA5;
    
        //Disable dedicated Interrupts
        //Backup all registers
        PMMRIE_backup = PMMRIE;
        PMMRIE &= ~(SVMHVLRPE | SVSHPE | SVMLVLRPE |
                    SVSLPE | SVMHVLRIE | SVMHIE |
                    SVSMHDLYIE | SVMLVLRIE | SVMLIE |
                    SVSMLDLYIE
                    );
        SVSMHCTL_backup = SVSMHCTL;
        SVSMLCTL_backup = SVSMLCTL;
    
        //Clear flags
        PMMIFG = 0;
    
        //Set SVM highside to new level and check if a VCore increase is possible
        SVSMHCTL = SVMHE | SVSHE | (SVSMHRRL0 * level);
    
        //Wait until SVM highside is settled
        while((PMMIFG & SVSMHDLYIFG) == 0)
        {
            ;
        }
    
        //Clear flag
        PMMIFG &= ~SVSMHDLYIFG;
    
        //Check if a VCore increase is possible
        if((PMMIFG & SVMHIFG) == SVMHIFG)
        {
            //-> Vcc is too low for a Vcore increase
            //recover the previous settings
            PMMIFG &= ~SVSMHDLYIFG;
            SVSMHCTL = SVSMHCTL_backup;
    
            //Wait until SVM highside is settled
            while((PMMIFG & SVSMHDLYIFG) == 0)
            {
                ;
            }
    
            //Clear all Flags
            PMMIFG &= ~(SVMHVLRIFG | SVMHIFG | SVSMHDLYIFG |
                         SVMLVLRIFG | SVMLIFG |
                         SVSMLDLYIFG
                         );
    
            //Restore PMM interrupt enable register
            PMMRIE = PMMRIE_backup;
            //Lock PMM registers for write access
            PMMCTL0_H = 0x00;
            //return: voltage not set
            return false;
        }
    
        //Set also SVS highside to new level
        //Vcc is high enough for a Vcore increase
        SVSMHCTL |= (SVSHRVL0 * level);
    
        //Wait until SVM highside is settled
        while((PMMIFG & SVSMHDLYIFG) == 0)
        {
            ;
        }
    
        //Clear flag
        PMMIFG &= ~SVSMHDLYIFG;
    
        //Set VCore to new level
        PMMCTL0_L = PMMCOREV0 * level;
    
        //Set SVM, SVS low side to new level
        SVSMLCTL = SVMLE | (SVSMLRRL0 * level) |
                   SVSLE | (SVSLRVL0 * level);
    
        //Wait until SVM, SVS low side is settled
        while((PMMIFG & SVSMLDLYIFG) == 0)
        {
            ;
        }
    
        //Clear flag
        PMMIFG &= ~SVSMLDLYIFG;
        //SVS, SVM core and high side are now set to protect for the new core level
    
        //Restore Low side settings
        //Clear all other bits _except_ level settings
        SVSMLCTL &= (SVSLRVL0 + SVSLRVL1 + SVSMLRRL0 +
                     SVSMLRRL1 + SVSMLRRL2
                     );
    
        //Clear level settings in the backup register,keep all other bits
        SVSMLCTL_backup &=
            ~(SVSLRVL0 + SVSLRVL1 + SVSMLRRL0 + SVSMLRRL1 + SVSMLRRL2);
    
        //Restore low-side SVS monitor settings
        SVSMLCTL |= SVSMLCTL_backup;
    
        //Restore High side settings
        //Clear all other bits except level settings
        SVSMHCTL &= (SVSHRVL0 + SVSHRVL1 +
                     SVSMHRRL0 + SVSMHRRL1 +
                     SVSMHRRL2
                     );
    
        //Clear level settings in the backup register,keep all other bits
        SVSMHCTL_backup &=
            ~(SVSHRVL0 + SVSHRVL1 + SVSMHRRL0 + SVSMHRRL1 + SVSMHRRL2);
    
        //Restore backup
        SVSMHCTL |= SVSMHCTL_backup;
    
        //Wait until high side, low side settled
        while(((PMMIFG & SVSMLDLYIFG) == 0) &&
              ((PMMIFG & SVSMHDLYIFG) == 0))
        {
            ;
        }
    
        //Clear all Flags
        PMMIFG &= ~(SVMHVLRIFG | SVMHIFG | SVSMHDLYIFG |
                    SVMLVLRIFG | SVMLIFG | SVSMLDLYIFG
                    );
    
        //Restore PMM interrupt enable register
        PMMRIE = PMMRIE_backup;
    
        //Lock PMM registers for write access
        PMMCTL0_H = 0x00;
    
        return true;
    }
    
    bool increaseVCoreToLevel2()
    {
        uint8_t level = 2;
        uint8_t actlevel;
        bool status = true;
    
        //Set Mask for Max. level
        level &= PMMCOREV_3;
    
        //Get actual VCore
        actlevel = PMMCTL0 & PMMCOREV_3;
    
        //step by step increase or decrease
        while((level != actlevel) && (status == true))
        {
            if(level > actlevel)
            {
                status = setVCoreUp(++actlevel);
            }
        }
    
        return (status);
    }
    
    //******************************************************************************
    // Main ************************************************************************
    // Enters LPM0 and waits for SPI interrupts. The data sent from the master is  *
    // then interpreted and the device will respond accordingly                    *
    //******************************************************************************
    
    int main(void) {
        WDTCTL = WDTPW + WDTHOLD;               // Stop watchdog timer
    
        while (!(P1IN & BIT4));                 // If clock sig from mstr stays low,
                                                // it is not yet in SPI mode
        increaseVCoreToLevel2();
        initClockTo16MHz();
        initGPIO();
        initSPI();
    
    
        __bis_SR_register(LPM0_bits + GIE);                 // Enter LPM0, enable interrupts
        __no_operation();
    	return 0;
    }
    
    
    //******************************************************************************
    // SPI Interrupt ***************************************************************
    //******************************************************************************
    
    #if defined(__TI_COMPILER_VERSION__) || defined(__IAR_SYSTEMS_ICC__)
    #pragma vector=USCI_A0_VECTOR
    __interrupt void USCI_A0_ISR(void)
    #elif defined(__GNUC__)
    void __attribute__ ((interrupt(USCI_A0_VECTOR))) USCI_A0_ISR (void)
    #else
    #error Compiler not supported!
    #endif
    {
      uint8_t uca0_rx_val = 0;
      switch(__even_in_range(UCA0IV,4))
      {
        case 0:break;                             // Vector 0 - no interrupt
        case 2:
            uca0_rx_val = UCA0RXBUF;
            if (!(SLAVE_CS_IN & SLAVE_CS_PIN))
            {
                switch (SlaveMode)
                {
                      case (RX_REG_ADDRESS_MODE):
                          ReceiveRegAddr = uca0_rx_val;
                          SPI_Slave_ProcessCMD(ReceiveRegAddr);
                          break;
                      case (RX_DATA_MODE):
                          ReceiveBuffer[ReceiveIndex++] = uca0_rx_val;
                          RXByteCtr--;
                          if (RXByteCtr == 0)
                          {
                              //Done Receiving MSG
                              SlaveMode = RX_REG_ADDRESS_MODE;
                              SPI_Slave_TransactionDone(ReceiveRegAddr);
                          }
                          break;
                      case (TX_DATA_MODE):
                          if (TXByteCtr > 0)
                          {
                              SendUCA0Data(TransmitBuffer[TransmitIndex++]);
                              TXByteCtr--;
                          }
                          if (TXByteCtr == 0)
                          {
                              //Done Transmitting MSG
                              SlaveMode = RX_REG_ADDRESS_MODE;
                              SPI_Slave_TransactionDone(ReceiveRegAddr);
                          }
                          break;
                      default:
                          __no_operation();
                          break;
                }
            }
            break;
        case 4:break;                             // Vector 4 - TXIFG
        default: break;
      }
    }
    

    Regarads,

    Helic

  • thank you for the reply. the example is for 3 pin mode. I want to know the setup for 4 pin mode

  • Hi, 

    You can get the example usage guide from line 10 to line 21, P2.0 is for chip select.

    Do you mean that you need a SPI hardware CS pin?

    Not a software controlled P2.0 in demo code?

    Regards,

    Helic

  • Yes. I need the setup for SPI hardware CS pin P2.7 (UCB0STE)

  • Hi, 

    Please refer to User's Guide: https://www.ti.com/lit/ug/slau208q/slau208q.pdf

    40.3.4.1 4-Pin SPI Slave Mode

    And table [Table 40-1. UCxSTE Operation] in 40.3 eUSCI Operation – SPI Mode.

    Regards,

    Helic

  • I don't see anything obviously wrong with your code. Is your master also using (CPHA=1, CPOL=1)?

    How do you tell that you're not receiving data? (Breakpoint in ISR? Incorrect data bytes?)

    Data sheet (SLAS590N) Table 6-47 Note (3) mentions a possible conflict over P2.7 if you're also using UCA0 for SPI. I suspect you aren't, but I thought I should ask.

  • void spi_init(void)
    {
        P3SEL |= BIT0;      // MOSI
        P3SEL |= BIT1;      // MISO
        P3SEL |= BIT2;      // CLK
    
        P1DIR |= 0xff;      // set all to output direction  CS10, CS9, CS8, CS7, CS6, CS5, CS4, CS3
        P2DIR |= BIT1 + BIT0; //Set to Output Direction CS1, CS2;
    
        UCB0CTL1 |= UCSWRST;                      // **Put state machine in reset**
        UCB0CTL0 |= UCMST+UCSYNC+UCCKPL+UCMSB;    // 3-pin, 8-bit SPI master
                                                      // Clock polarity high, MSB
        UCB0CTL1 |= UCSSEL_2;                     // SMCLK 8MHz
        UCB0BR0 = 0x08;                           // /8 = 1Mhz
        UCB0BR1 = 0;                              //
        //UCB0MCTL = 0x00;                             // No modulation
        UCB0CTL1 &= ~UCSWRST;                     // **Initialize USCI state machine**
    
    }
    
    void spi_init(void)
    {
        P3SEL |= BIT0;      // MOSI
        P3SEL |= BIT1;      // MISO
        P3SEL |= BIT2;      // CLK
    
        P1DIR |= 0xff;      // set all to output direction  CS10, CS9, CS8, CS7, CS6, CS5, CS4, CS3
        P2DIR |= BIT1 + BIT0; //Set to Output Direction CS1, CS2;
    
        UCB0CTL1 |= UCSWRST;                      // **Put state machine in reset**
        UCB0CTL0 |= UCMST+UCSYNC+UCCKPL+UCMSB;    // 3-pin, 8-bit SPI master
                                                      // Clock polarity high, MSB
        UCB0CTL1 |= UCSSEL_2;                     // SMCLK 8MHz
        UCB0BR0 = 0x08;                           // /8 = 1Mhz
        UCB0BR1 = 0;                              //
        //UCB0MCTL = 0x00;                             // No modulation
        UCB0CTL1 &= ~UCSWRST;                     // **Initialize USCI state machine**
    
    }
    

    this is the configuration in master. In my program, I receive the data from master and then assign the values to the GPIO pins. So I check the GPIO pins, It's not giving the output. I  am using  UCB0 for the SPI configurations.

**Attention** This is a public forum