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.

MSP430FG4618 - How to use the SPI mode with 16-bit data

Other Parts Discussed in Thread: MSP430FG4618, MSP430F2013

I'm trying to setup the SPI communication (with USCI) on MSP430FG4618.  I couldn't find it anywhere talking about 16-bit transmit buffer.  Basically I'm trying to use FG4618 to communicate with an ADC that requires a 16-bit data.

I have used the 16-bit SPI with USI on MSP430F2013 and it worked fine (setting the USI16B bit).  Does USCI support 16-bit SPI?  If not, can I transmit 2 8-bit cycles?  How?

Thanks.

Here's the sample code that only does 8-bit.  (By. Davies)

 

 

// uscispiloop1.c - test SPI using USCI_B with loopback (int and ext)
// 8-bit transfer, SPI mode 3 (CPOL = CPHA = 1), every (1/4)ms after BT
// FG4619 on TI Experimenter's Board, 32KHz crystal, DCO at 6MHz
//   SPI clock = SMCLK / 60 = 100kHz, so about 80us for transfer
//   SCLK on P3.3, MOSI on P3.1, MISO on P3.2
//   P3.0 used as _SS (nSS) but TIMING IS NOT PRECISE (done in software)
// J H Davies, 2007-11-05; IAR Kickstart version 4.09A
//----------------------------------------------------------------------
#include <io430xG46x.h>                // Specific device
#include <intrinsics.h>                // Intrinsic functions
#include <stdint.h>                    // Integers of defined sizes
//#include "LCDutils2.h"                // TI exp board utility functions

#define nSS        P3OUT_bit.P3OUT_0    // Output pin for _SS (active low)

//uint8_t RXdata, TXdata = 0x5A;        // Received and transmitted data,
uint16_t RXdata, TXdata = 0x385A; //16 bit data
                                    //   subsequent values incremented
void main (void)
{
    volatile uint16_t i;            // Loop counter to stabilize FLL+

    WDTCTL = WDTPW | WDTHOLD;        // Stop watchdog timer
    FLL_CTL0 = DCOPLUS | XCAP14PF;    // FLL+ divider, 14pF load caps
    SCFQCTL = 91;                    // f_DCO = 2(91 + 1)f_ACLK = 6.03MHz  (Default D=2)
    SCFI0 = FLLD_2 | FN_3;            // Multiply by 2, 2.2 - 17MHz range
    do {                            // Wait until FLL has locked
        for (i = 0xFFFF; i > 0; --i) {
        }                             // Delay for FLL+ to lock
        IFG1_bit.OFIFG = 0;            // Attempt to clear osc fault flag
    } while (IFG1_bit.OFIFG != 0);    // Repeat if not yet clear
       // P3OUT = BIT1 | BIT2 | BIT5;            // F2013 might tie 1,2 high;
//    P3DIR = 0xFF;                        //   P3.5 high for buzzer off
    P3OUT_bit.P3OUT_0 = 1;            // High for nSS inactive
    P3DIR_bit.P3DIR_0 = 1;            // Enable for nSS output
    P3SEL = BIT1 | BIT2 | BIT3;        // Route pins to USCI_B for SPI
// SPI mode 3 needs CPOL=CKPL=1, CPHA=1 -> CKPH=0; msb first, master,
//   8 bit (default), 3-wire (default, mode 0), synchronous
    UCB0CTL0 = UCCKPL | UCMSB | UCMST | UCMODE_0 | UCSYNC;
    UCB0CTL1 = UCSSEL1 | UCSWRST;    // Clock from SMCLK; hold in reset
    UCB0BR1 = 0;                    // Upper byte of divider word
    UCB0BR0 = 60;                    // Clock = SMCLK / 60 = 100kHz
    UCB0STAT = UCLISTEN;            // Internal loopback
    UCB0CTL1 &= ~UCSWRST;            // Release from reset
    IE2_bit.UCB0RXIE = 1;            // Enable interrupts on receive
// Basic Timer: hold, counter 2 from ACLK, period = 8 (cntr 1 not used)
//    BTCTL = BTHOLD | BT_fCLK2_ACLK | BT_fCLK2_DIV8;
        BTCTL = BT_fCLK2_ACLK | BT_fCLK2_DIV16;
    BTCNT2 = 0;                    // Clear counter
    BTCTL &= ~BTHOLD;                // Start basic timer
    IE2_bit.BTIE = 1;                // Enable basic timer interrupts
    for (;;) {                    // Transmissions triggered by BT
        __low_power_mode_3();        // LPM3 between interrupts
    }
}
//----------------------------------------------------------------------
// ISR for basic timer: check TXIFG, activate nSS, start new SPI transfr
//----------------------------------------------------------------------
#pragma vector = BASICTIMER_VECTOR
__interrupt void BASICTIMER_ISR (void)    // Acknowledged automatically
{
    if (IFG2_bit.UCB0TXIFG == 1) {    // Ready for new data?
        nSS = 0;                    // Lower nSS (make active)
        UCB0TXBUF = TXdata;            // Load shift register for transfer
    }                    // SMCLK remains active for USCI automatically
}
//----------------------------------------------------------------------
// ISR for USCI_A,B0 RX: deactivate nSS, store rec'd data (acknowledges)
//----------------------------------------------------------------------
#pragma vector = USCIAB0RX_VECTOR
__interrupt void USCIAB0RX_ISR (void)    // Not acknowledged automaticaly
{
    nSS = 1;                        // Raise nSS (make inactive)
    RXdata = UCB0RXBUF;                // Store received data, clears flag
    TXdata = RXdata;// + 1;            // Slightly different next time!
}

  • Hello,

    There is no 'special' 16 bit mode for the USCI SPI.

    However the module is capable of back-to-back 8-bit transfers with no latency.

    This is because the SPI TX/RX register is double-buffered. 2 MCLKs after a byte is loaded onto the TXBUF, it gets shifted to a TX shift register - so the next byte can be immediately loaded onto the TXBUF; ready to go out ;at the end of the first 8-bit transaction.

    It does not require any special handling but I would recommend using DMA to load the TXBUF to prevent any latency of servicing the interrupt between 2; 8-bit transfers.

    If the SPI Bitclk << CPU speed; you may also be able to use interrupts to load TXBUF.

    Regards,

    Priya

  • Do you mean that I can do something like this (back to back)?

    while(!(IFG2 & UCB0TXIFG));                 //wait for register empty

    UCB0TXBUF = First_byte;                     // Send the first 8-bit

    while(!(IFG2 & UCB0TXIFG));              //wait for register empty

    UCB0TXBUF = Second_byte;              // Send the second 8-bit

     

    I'm new to MSP430.  Can you provide example code on this?

    Thanks.

  • I think I have it worked.

                    nSS = 0;                            // Lower nSS (make active)
                    UCB0TXBUF = TXdata;            // Load shift register for first byte
                    while(!(IFG2 & UCB0TXIFG));             //wait for register to empty       
                    UCB0TXBUF=TXdata2;                      //2nd byte
                    while(!(IFG2 & UCB0TXIFG));             //wait for register to empty
                    for (i=100; i>0; i--)                   //Even if the register is empty, the transmission may not be completed
                    {                                       //wait longer
                     }
                    nSS = 1;                            //Raise sync (nSS)

     

    There's a small problem though.  The second while statement seems not doing what I want.  The register is cleared right after the second byte is loaded.  However, it the transmission process is not completed.  I had to make another delay before I raise the sync signal.

    Is there any flag that I can use to monitor the end of transmission, so I can raise the sync signal "Right After" the transmission is completed?

    Thanks.

  •  

    Sorry, unfortunately the TXIFG only works to indicate that another byte can be loaded to the TXBUF not that the previous byte has been sent out on the bus.

    So yes, the second while loop will exit after one iteration (2MCLKs) and before the second byte gets placed on the bus.

    You could try polling the UCBUSY bit in the UCxxSTAT register that allows you to check if the SPI is busy before asserting the Sync signal.

    Regards,

    Priya

  • Yes, that helped.

    Thank you.

     

    Here's my code in case people have the same problem.

     

                    nSS = 0;                            // Lower nSS (make active)
                    UCB0TXBUF = TXdata;            // Load shift register for first byte
                    while(!(IFG2 & UCB0TXIFG));             //wait for register to empty       
                    UCB0TXBUF=TXdata2;                      //2nd byte

                    while((UCB0STAT&BIT0));                  //wait for the the busy signal to clear
                    nSS = 1;

**Attention** This is a public forum