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 SPI can't receive data

Other Parts Discussed in Thread: MSP430FG4618, ADC128S102

Normal 0 false false false EN-US X-NONE X-NONE

Hi,

I’m using MSP430FG4618 (USCI port B) to drive ADC121S102. (MSP430FG4618/2013 Experimenter's board)

http://cache.national.com/ds/DC/ADC128S102.pdf

I was able to drive the ADC correctly (measured the output with an oscilloscope), but the received data always shows 00. 

The following is a portion of my code.  Can someone tell me where the problem is?
Thanks.

 

sync = 0;                                           // ADC Sync (enable)
UCB0TXBUF = TXdata1;                // Load shift register for first byte
while(!(IFG2 & UCB0TXIFG));                // wait for TX1 to complete
RXdata1 = UCB0RXBUF;             // Read-in the 1st received byte     
UCB0TXBUF=TXdata2;                         // Load shift register for 2nd byte
while(!(IFG2 & UCB0TXIFG));                // wait for TX2 to complete
RXdata2 = UCB0RXBUF;            // Read-in the 2nd received byte
sync = 1;                                         // Raise ADC sync (disable)

  • Here's my code.  Can anyone point out where the problem is? Thanks.

    // Driving ADC128S102 - to acquire CH6 MSP430FG4618
    // The readout of the ADC (pin15) should be around 110010101110 ----- 3.963Volt
    // while the measured voltage is 3.957V
    //Header1 P2: Data
    //Header1 P6: /Sync (nSS)
    //Header1 P8: SCLK
    //----------------------------------------------------------------------
    #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 RXdata1=0, TXdata1 = 0x30;        // Received and transmitted data,
    uint8_t RXdata2=0, TXdata2 = 0x00;        // Received and transmitted data,

    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
              P2DIR |= 0x06;                         //Set P5.1 to output direction -- LED is connected to this pin
              P2OUT = 0;//~BIT2|~BIT1;  //turn off LEDs

        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_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

        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 = BT_fCLK2_ACLK | BT_fCLK2_DIV8;
        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
    {
                    nSS = 0;                            // Lower nSS (make active)
                    UCB0TXBUF = TXdata1;            // Load shift register for first byte
                    while(!(IFG2 & UCB0TXIFG));             //wait for register to empty   
                 RXdata1 = UCB0RXBUF;            // Store received data (first byte)
                    UCB0TXBUF=TXdata2;                      //2nd byte
                    while((UCB0STAT&BIT0));                  //wait for the transmission to be completed
                 RXdata2 = UCB0RXBUF;            // Store received data (second byte)
                    nSS = 1;                            //Raise sync (nSS)
                   
                    if (RXdata1==0x0A)        // If upper byte received (0x0A is a known value from scope)
                      P2OUT=P2OUT|BIT2;       // Turn on LED1
                    if (RXdata2 >= 0x01)       // If lower byte received (as long as it receives non-zero value)
                      P2OUT=P2OUT|BIT1;       // Turn on LED2
    }

  • Although not perfect, here the solution

               uint32_t ADC_data;            // Converted value of temperature
               nSS = 0;                            // Lower nSS (make active)
               UCB0TXBUF = TXdata1;            // Tx first byte
               while (!(IFG2 & UCB0RXIFG));//wait for the data to be loaded on receiving buffer
               RXdata1 = UCB0RXBUF;            // Store received data (first byte)
               UCB0TXBUF=TXdata2;                      //Tx 2nd byte
               while((UCB0STAT&BIT0));                  //wait for the transmission to be completed
               RXdata2 = UCB0RXBUF;            // Store received data (second byte)
               nSS = 1;                            //Raise sync (nSS)
               ADC_data=(RXdata1<<8)+RXdata2;          //Combine High and Low

     

    The only problem is that there's a clock delay between the first byte and 2nd byte.  Although it does not affect the function of ADC.

  • Shang Wu said:
    UCB0TXBUF = TXdata1;                // Load shift register for first byte
    while(!(IFG2 & UCB0TXIFG));                // wait for TX1 to complete
    RXdata1 = UCB0RXBUF;             // Read-in the 1st received byte    

    Here's the problem: The SPI registers are double-buffered.

    Once you wrote the first byte to TXBUF, it is immediately moved to the output shift and TXIFG is set once more. that does NOT mean that the previous content of TXBUF has been sent yet. In this case, just the first bit is in the process of sending. But TXBUF is ready to receive the next byte.

    As a result, nothing (maybe not even the first bit) has been received yet. But you read RXBUF right now. Which contains nothing at this point.
    Even after teh second byte has been moved from TXBUF to the output and TXBUF is empty the second time, the first byte does not necessarily have to be received and arrived in RXBUF yet. Since the output is sent at one while the input is received at the other edge of the clock signal. So you're reading the same still empty RXBUF once more.

    To be sure that something has arrived, use the RXIFG bit (clear it before starting) and to ensure that the last transfer is complete, eitehr too rely on the RXIFG bit (which will be set after the last bit has been sent) or check the busy status bit.

  • Yes, that makes sense.

    Thank you.

**Attention** This is a public forum