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: USCIB0 SPI driver issue

Part Number: MSP430FR5969
Other Parts Discussed in Thread: LDC1101

Hiiyyaa Forum experts,
I was writing a basic SPI driver for LDC1101. So just for test I'm trying to write into one register and read from that. But the issue I faced that it was unable to make CS pin high and the cursor is stucked there. If you resolve my issue I would be thankful for that. By the way I'm using MSP430FR5969 Development board and LDC1101. so Here is my code:
I'm using USCIB0 for SPI
////////////////////////////
#define SLAVE_CS_OUT    P1OUT
#define SLAVE_CS_DIR    P1DIR
#define SLAVE_CS_PIN    BIT3

#define ENABLE_SPI_TX_INT()      { UCB0IE |= UCTXIE;}
/* Enable receive interrupt */
#define ENABLE_SPI_RX_INT()      { UCB0IE |= UCRXIE;}

/* Disable receive interrupt */
#define DISABLE_SPI_RX_INT()     { UCB0IE &= ~UCRXIE;}


void 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 = DCORSEL | DCOFSEL_4;             // Set DCO to 16MHz
    CSCTL2 = SELA__VLOCLK | SELS__DCOCLK | SELM__DCOCLK;
    CSCTL3 = DIVA__2 | DIVS__2 | DIVM__2;     // Set all dividers

    CSCTL0_H = 0;                             // Lock CS registerss
}
void initGPIO()
{
    //LEDs
    P1OUT = 0x00;                             // P1 setup for LED & reset output
    P1DIR |= BIT0 + BIT4;

    P4DIR |= BIT6;
    P4OUT &= ~(BIT6);
    
    P3DIR |= BIT4;
    P3SEL1 |= BIT4;                           // Output SMCLK

    // Configure SPI pins
    P2SEL1 |= BIT2;                           //clk    
    P1SEL1 |= BIT6 | BIT7;                  // Configure MISO/MOSI pins    

    SLAVE_CS_DIR |= SLAVE_CS_PIN;             // STE Pin
    SLAVE_CS_OUT |= SLAVE_CS_PIN;             // STE pin enable

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

void WriteUCB0Data(uint8_t val)
{
    while (!(UCB0IFG & UCTXIFG));              // USCI_B0 RX buffer ready?
    UCB0TXBUF = val;
}
SPI_Mode SPI_Master_WriteReg(uint8_t reg_addr, uint8_t reg_data, uint8_t count)
{
    TransmitRegAddr = reg_addr;
    TransmitBuffer = reg_data;
    UCB0_TxComplete = true;
    //Copy register data to TransmitBuffer
    //memcpy((void *)TransmitBuffer, (const void *) reg_data, sizeof(reg_data));

    TXByteCtr = count;

    ENABLE_CHIPSELECT();
    ENABLE_SPI_TX_INT();
    WriteUCB0Data(TransmitRegAddr);

    __bis_SR_register(LPM0_bits + GIE);              // Enter LPM0 w/ interrupts
    
    while( UCB0_TxComplete != true )                   //My program stucks here please help me to resolve the issue
      DISABLE_CHIPSELECT();
    return MasterMode;
}

SPI_Mode SPI_Master_ReadReg(uint8_t reg_addr, uint8_t count)
{
    TransmitRegAddr = reg_addr;
    RXByteCtr = count;
    TXByteCtr = 0;
    ReceiveIndex = 0;
    TransmitIndex = 0;

    SLAVE_CS_OUT &= ~(SLAVE_CS_PIN);
    WriteUCB0Data(TransmitRegAddr);

    __bis_SR_register(CPUOFF + GIE);              // Enter LPM0 w/ interrupts

    SLAVE_CS_OUT |= SLAVE_CS_PIN;
    return MasterMode;
}


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

    initClockTo8MHz();
    initGPIO();
    initSPI();
    
    SPI_Master_WriteReg(RP_SET, 0x45, WRITE_COUNT);
    SPI_Master_ReadReg(RP_SET, READ_COUNT);
    __bis_SR_register(LPM0_bits + GIE);       // CPU off, enable interrupts
    /*
    
    
    Logic must be added here for Inductive sensing
    
    
    
    */
    //while(1)
      __no_operation();

    return 0;
}    


//////SPI Interrupt /////////
#if defined(__TI_COMPILER_VERSION__) || defined(__IAR_SYSTEMS_ICC__)
#pragma vector=USCI_B0_VECTOR
__interrupt void USCI_B0_ISR(void)
#elif defined(__GNUC__)
void __attribute__ ((interrupt(USCI_B0_VECTOR))) USCI_B0_ISR (void)
#else
#error Compiler not supported!
#endif
{
    uint8_t ucb0_rx_val = 0;
  if ((UCB0IE & UCTXIE) && (UCB0IFG & UCTXIFG))
  {
    if (TXByteCtr)
    {
      //WriteUCB0Data(TransmitBuffer[TransmitIndex++]);
      WriteUCB0Data(TransmitBuffer);
      TXByteCtr--;
    }
    else
    {
      //Done with transmission
      MasterMode = IDLE_MODE;
      __bic_SR_register_on_exit(CPUOFF);      // Exit LPM0
    }
    UCB0IFG &= ~UCTXIFG;        /* Clear transmit interrupt flag */
    UCB0_TxComplete = false;
  }

  if ((UCB0IE & UCRXIE) && (UCB0IFG & UCRXIFG))         //it comes here checks and it stucks
  {
    if (RXByteCtr)
    {
      ReceiveBuffer[ReceiveIndex++] = ucb0_rx_val;
      //Transmit a dummy
      RXByteCtr--;
    }
    if (RXByteCtr == 0)
    {
      MasterMode = IDLE_MODE;
      __bic_SR_register_on_exit(CPUOFF);      // Exit LPM0
    }
    else
    {
      WriteUCB0Data(DUMMY);
                    }
    /* Clear receive interrupt flag */
    UCB0IFG &= ~UCRXIFG;
  }
 }
 

  • Hi Manish,

    I do not find your initSPI() function, I have a look your code and found you should use 3-wire SPI. 

    I think you can block other code to just test this P1.3 pin.

    Best Regards

    Johnson

  • Hi johnson

    pardon me for that

    void initSPI()
    {
        //Clock Polarity: The inactive state is high
        //MSB First, 8-bit, Master, 3-pin mode, Synchronous
        UCB0CTLW0 = UCSWRST;                       // **Put state machine in reset**
        UCB0CTLW0 |= UCCKPL + UCMSB + UCSYNC + UCMODE_0
                    + UCMST + UCSSEL__SMCLK;      // 3-pin, 8-bit SPI Slave
        UCB0BRW = 0x20;
        //UCB0MCTLW = 0;                            // No modulation
        UCB0CTLW0 &= ~UCSWRST;                     // **Initialize USCI state machine (Disable software reset**
        ENABLE_SPI_TX_INT();                          // Enable USCI0 TX interrupt
    }

    please take a look and identify my error

  •  >  while( UCB0_TxComplete != true )                   //My program stucks here please help me to resolve the issue
     >     DISABLE_CHIPSELECT();

    1) The ISR sets this variable =false on completion, so I'm not quite sure what this is waiting for.

    2) Due to the LPM, once you reach this point the value of this variable will never change, so either the loop won't do anything or it will spin forever.

    3) This loop repeatedly de-asserts /CS, though you actually want it to only do this after the operation is complete. (Are you missing a ";"?)

    4) The ISR wakes up WriteReg() before all the bits have been sent. You should spin on UCBUSY before de-asserting /CS.

    5) This variable should be declared "volatile".

    Try something like:

    > while (UCB0_TxComplete) /*EMPTY*/;   // Wait for ISR to clear TxComplete (it has probably already happened)

    > while (UCB0STAT & UCBUSY) /*EMPTY*/; // Wait for last bits to be sent

    > DISABLE_CHIPSELECT(); 

    Unsolicited: The LDC1101 is capable of 8MHz on its SPI. I suggest you speed up the SPI clock (BRW) and do the transactions using spin-loops (no interrupts). This will be faster and will be much easier to get right.

  • Hry Bruce, Thanks let me try this method

  • Hey Bruce and Jhinson,

    Can you say whether my configuration are proper are not I need to confirm Once. Please reply fast you can find my updated code there I have solved my previous issue but now I'm able to write to some data into LDC registers but unable to read from that. PLease look into my attached code3000.new 2.h

  • Based on LDC1101 data sheet (SNOSD01D) Figs 1-2, your SPI configuration looks fine.

    With SPI, you receive exactly the number of bytes that you send. So: 

    >RXByteCtr = count;
    >TXByteCtr = 0;

    With this combination, your ISR will never transmit anything and thus will not receive anything. I see your ISR sends dummy bytes, but only if receives a byte. You may need to adjust your code structure to make this work.

    > UCB0IFG &= ~UCTXIFG; /* Clear transmit interrupt flag */

    Writing TXBUF clears TXIFG, so you shouldn't be clearing it yourself. If you don't have anything to send, clear TXIE instead. Similarly for RXBUF/RXIFG.

    [Edit: Also you're still not waiting (UCBUSY -- see above) for all the bits to be sent before de-asserting /CS. Since your SPI is so slow, this is very likely to cause trouble.]

  • Hey Bruce,

    You have suggested me to increse the clock speed for SPI but I looked into the userguide I'm unable to know which value shall I put to make SPI more faster. Can you suggest me something regarding this

  • BRW is a simple integer divider from (in your case) SMCLK. You've configured SMCLK to run from an external crystal (HFXT), so I don't know how fast that is. Supposing the HFXT runs at 8MHz, BRW=2 would set the SPI clock to (8MHz/2)=4MHz.

    Unsolicited: You're running MCLK from the DCO and SMCLK from the HFXT. Unless you have some specific purpose, I suggest you use the same source for both (either DCO or HFXT). In theory, what you have will work, but there are corners of the system where it makes a difference, and (I suspect) that's not the experiment you want to do right now.

  • Hey Bruce and all forum experts,

    If anyone has a demo code for LDC1101 then can you please give a link to me it will be helpful for me as I'm facing a lots of issue regarding this matter. Source code should me made available for Public or else who will use LDC with their custom PCB if anyone wants to develop something.

  • Thanks for this reply and aslo for suggestion

  • If you're willing to give up using interrupts (you'll also want to speed up the SPI, though that isn't strictly required), I suggest the "spix()" (SPI-eXchange) function discussed over here:

    https://e2e.ti.com/support/microcontrollers/msp430/f/166/p/758000/2800722

**Attention** This is a public forum