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: Reading from ADS1118

Part Number: MSP430F5529
Other Parts Discussed in Thread: ADS1118

Hello,

I'm using the MSP430F5529 to communicate to three ADS1118 via SPI.  I'm having trouble reading the output of the ADS1118 since its SPI protocol is somewhat different than a standard SPI protocol.  My MSP430 code (attached) only reads the MSB, and it fails to read the LSB ADS1118 output code.  Any help would be appreciated.

I'm attaching the SPI protocol of the ADS1118.  The MSP430 (master) is writing 0x8F (MSB) and 0xEB (LSB) to the ADS1118 (slave).  I can scope my SPI protocol and confirm this is correct.  

I'm also attaching my MSP430 SPI code.

Thanks.

ADS1118_SPI_MSP430FF529_Code.txt
//******************************************************************************
//
//   Description: SPI master (MSP430F5529) communicates to 3 ADS1118 slaves
//
//                   MSP430F5529
//                 -----------------
//                |      (See below)|-> Slave Chip Select (GPIO)
//                |                 |
//                |                 |
//                |                 |
//                |             P3.3|-> Data Out (UCA0SIMO/DIN)
//                |                 |
//                |             P3.4|<- Data In (UCA0SOMI/DOUT)
//                |                 |
//                |             P2.7|-> Serial Clock Out (UCA0CLK)
//                |                 |
//                |                 |
//
//CSB_ADC1 = P1.2; CSB_ADC2 = P1.3 ; CSB_ADC3 = P1.4
//
//
//******************************************************************************

#include <msp430.h> 
#include <stdint.h>
#include <stdbool.h>

#define DUMMY   0x00

#define CSB_M1_OUT    P1OUT
#define CSB_M1_DIR    P1DIR
#define CSB_M1_PIN    BIT2

#define CSB_M2_OUT    P1OUT
#define CSB_M2_DIR    P1DIR
#define CSB_M2_PIN    BIT3

#define CSB_M3_OUT    P1OUT
#define CSB_M3_DIR    P1DIR
#define CSB_M3_PIN    BIT4

#define LENGTH_ONE              1
#define LENGTH_TWO              2
#define LENGTH_SIX              6

#define MAX_BUFFER_SIZE     20
  
#define ADS1118_REG_ADDR_CONFIG_REG_MSB_def 0x8F //1000_1110
  //8: MODE = 0 for continuous conversion mode; 1 = power down mode
  //11:9: VREF = 111 for FSR = +/-0.256V
  //14:12: MUX = 000 for AIN0 = (+ve) and AIN1 = (-ve)
  //15: Single shot conversion start = 0 for no effect; 1 = start single conversion

typedef enum SPI_ModeEnum{
    IDLE_MODE,
    TX_REG_ADDRESS_MODE,
    RX_REG_ADDRESS_MODE,
    TX_DATA_MODE,
    RX_DATA_MODE,
    WRITE_READ_MODE,
    TIMEOUT_MODE
} SPI_Mode;


uint8_t ADS1118_REG_ADDR_CONFIG_REG_LSB[LENGTH_ONE] = {0xEB}; //1110_1010
  //0: Reserved
  //2:1: NOOP = 01 (Valid data)
  //3: PULL-UP EN = When /CSB is high, this pulls up the DOUT pin
  //4: TS_MODE = 0 (ADC) or 1 (Temp Sensor)
  //7:5: DR = 111 (860 SPS)

uint8_t CopyDestBuffer[LENGTH_SIX] = {0};
SPI_Mode MasterMode = IDLE_MODE;

uint8_t TransmitRegAddr = 0;
uint8_t TransmitDataMSB = 0;
uint8_t TransmitDataLSB = 0;
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;
uint8_t sensor_number = 0;
uint8_t num_accels = 5;
int sensorno;
int mymode = 0;
uint8_t mydata = 0;

void SendUCA0Data(uint8_t val);

//******************************************************************************
// CopyArray********************************************************************
//******************************************************************************
void CopyArray(uint8_t *source, uint8_t *dest, uint8_t count);
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];
    }
}

//******************************************************************************
// Master write to slave*******************************************************
//******************************************************************************
SPI_Mode SPI_Master_WriteReg(uint8_t reg_addr, uint8_t *reg_data, uint8_t count, int senNum, int mode);
SPI_Mode SPI_Master_WriteReg(uint8_t reg_addr, uint8_t *reg_data, uint8_t count, int senNum, int mode)
{
  
    sensor_number = senNum;
    MasterMode = TX_REG_ADDRESS_MODE; 
    TransmitRegAddr = reg_addr;

    //Copy register data to TransmitBuffer
    CopyArray(reg_data, TransmitBuffer, count);

    TXByteCtr = count;
    RXByteCtr = 0;  
    ReceiveIndex = 0;
    TransmitIndex = 0;
    mymode = mode;
       
    if (sensor_number == 6){
      CSB_M1_OUT &= ~(CSB_M1_PIN);
    }

    else if (sensor_number == 7){
      CSB_M2_OUT &= ~(CSB_M2_PIN);
    }

    else if (sensor_number == 8){
      CSB_M3_OUT &= ~(CSB_M3_PIN);
    }
    
    SendUCA0Data(TransmitRegAddr);

      __bis_SR_register(CPUOFF + GIE);              // Enter LPM0 w/ interrupts
  
    if (sensor_number == 6){
      CSB_M1_OUT |= CSB_M1_PIN;
    }  
    
    else if (sensor_number == 7){
      CSB_M2_OUT |= CSB_M2_PIN;
    }  
    
    else if (sensor_number == 8){
      CSB_M3_OUT |= CSB_M3_PIN;
    }  
    
    return MasterMode;
}

//******************************************************************************
// Master reads from Slave******************************************************
//******************************************************************************
SPI_Mode SPI_Master_ReadReg(uint8_t reg_addr, uint8_t count, int senNum);
SPI_Mode SPI_Master_ReadReg(uint8_t reg_addr, uint8_t count, int senNum)
{
    sensor_number = senNum;
    MasterMode = TX_REG_ADDRESS_MODE;
    TransmitRegAddr = reg_addr;
    RXByteCtr = count;
    TXByteCtr = 0;
    ReceiveIndex = 0;
    TransmitIndex = 0;

   if (sensor_number == 6){
      CSB_M1_OUT &= ~(CSB_M1_PIN);
    }

    else if (sensor_number == 7){
      CSB_M2_OUT &= ~(CSB_M2_PIN);
    }

    else if (sensor_number == 8){
      CSB_M3_OUT &= ~(CSB_M3_PIN);
    }

    __bis_SR_register(CPUOFF + GIE);              // Enter LPM0 w/ interrupts
    
    if (sensor_number == 6){
      CSB_M1_OUT |= CSB_M1_PIN;
    }  
    
    else if (sensor_number == 7){
      CSB_M2_OUT |= CSB_M2_PIN;
    }  
    
    else if (sensor_number == 8){
      CSB_M3_OUT |= CSB_M3_PIN;
    }   
    
    return MasterMode;
}

//******************************************************************************
//Send Data*********************************************************************
//******************************************************************************

void SendUCA0Data(uint8_t val)
{
 
    while (!(UCA0IFG & UCTXIFG));              // USCI_A0 TX buffer ready?
    UCA0TXBUF = val;
    
}

//******************************************************************************
// Set CLOCK to 16MHz*
//******************************************************************************

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
}

//******************************************************************************
// INIT GPIO
//******************************************************************************
void initGPIO()
{
  //The following for GPIOs for CSB:
  //CSB_A1 = P2.0; CSB_A2 = P2.2; CSB_A3 = P2.4; CSB_A4 = P2.5; CSB_A5 = P1.5
  //CSB_M1 = P1.2; CSB_M2 = P1.3 ; CSB_M3 = P1.4
 
  P4DIR |= BIT7;
  P4OUT &= ~(BIT7);

  //SPI Pins
  P3SEL |= BIT3 + BIT4;                     // P3.3 = SIMO; P3.4 = SOMI
  P2SEL |= BIT7;                            // P2.7 = SCLK
  
  //UART
  P4SEL |= BIT4 + BIT5;                   // P4.4 = UART TXD; P4.5 = UART RXD
  /*
  //Button to initiate transfer
  P2DIR &= ~BIT6;                           // Set P2.1 to inpput direction
  P2REN |= BIT6;                            // Enable P2.1 internal resistance
  P2OUT |= BIT6;                            // Set P2.1 as pull-Up resistance
  P2IES |= BIT6;                            // P2.1 Hi/Lo edge
  P2IFG &= ~BIT6;                           // P2.1 IFG cleared
  P2IE |= BIT6;                             // P2.1 interrupt enabled
*/
}

//******************************************************************************
// INIT SPI
//******************************************************************************
void initSPI(int sensorno)
{
  UCA0CTL0 &= 0;                        //clear this register
  UCA0CTL1 |= UCSWRST;                  // **Put state machine in reset**
  
    UCA0CTL0 |= UCMSB + UCMST + UCSYNC;
    /*UCCKPH = clock phase select = 0 according to ADS1118 SPI timing diagram
      UCCKPL = clock polarity select = 0 according to ADS1118 SPI timing diagram
      UCMSB = MSB first
      UCMST = MSP430F5528 is the master, MC3672 and ADS1118 = slaves
      UCSYNC = synchronous*/
 

  UCA0CTL1 |= UCSSEL_2;                     // clock = SMCLK
  UCA0BR0 |= 0x20;                          // Bit rate 
  UCA0BR1 = 0;                              //
  UCA0MCTL = 0;                             // No modulation must be cleared for SPI
  UCA0CTL1 &= ~UCSWRST;                     // **Initialize USCI state machine**
  UCA0IE |= UCRXIE;                          // Enable USCI0 RX interrupt
  
 
  CSB_M1_DIR |= CSB_M1_PIN;
  CSB_M1_OUT |= CSB_M1_PIN;
  
  CSB_M2_DIR |= CSB_M2_PIN;
  CSB_M2_OUT |= CSB_M2_PIN;
  
  CSB_M3_DIR |= CSB_M3_PIN;
  CSB_M3_OUT |= CSB_M3_PIN;
  
}


//******************************************************************************
// Main ************************************************************************
// Send and receive three messages containing the example commands *************
//******************************************************************************
int main(void) {
     
    WDTCTL = WDTPW | WDTHOLD;	// Stop watchdog timer
    initClockTo16MHz();
    initGPIO();
    
    while(1)
     {

        initSPI(1); //Initialize SPI for ADS1118
      	SPI_Master_WriteReg(ADS1118_REG_ADDR_CONFIG_REG_MSB_def, ADS1118_REG_ADDR_CONFIG_REG_LSB, LENGTH_ONE, 6, 1); //Write to and read from ADS1118
      
     }//end while
     
}//end main


//******************************************************************************
// 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:                                   // Vector 2 - RXIFG
      
        uca0_rx_val = UCA0RXBUF;
        
        switch (MasterMode)
        {
          //---Always starts with this---
            case TX_REG_ADDRESS_MODE:
                if (RXByteCtr)          //If Master reading from slave
                {
                    MasterMode = RX_DATA_MODE;   // Need to start receiving now
                    //Send Dummy To Start
                    __delay_cycles(75);
                    SendUCA0Data(DUMMY);
                }
                else if (TXByteCtr)                    //If Master writing to slave
                {
                    MasterMode = TX_DATA_MODE;        // Send the register address first
                    SendUCA0Data(TransmitBuffer[TransmitIndex++]);
                    TXByteCtr--;
                }
                break;

            case TX_DATA_MODE:          //If Master writing to slave
                if (TXByteCtr)          //Send the data
                {
                  SendUCA0Data(TransmitBuffer[TransmitIndex++]);
                  TXByteCtr--;
                }
                else
                {
                 if (mymode==1){
                    uca0_rx_val = UCA0RXBUF;
                    ReceiveBuffer[0] = uca0_rx_val;
                    uca0_rx_val = UCA0RXBUF;
                    ReceiveBuffer[1] = uca0_rx_val;
                    uca0_rx_val = UCA0RXBUF;
                    ReceiveBuffer[2] = uca0_rx_val;
                  }
                  //Done with transmission
                  MasterMode = IDLE_MODE;
                  __bic_SR_register_on_exit(CPUOFF);      // Exit LPM0
                }
                break;

            case RX_DATA_MODE:          //If Master reading from slave     
                if (RXByteCtr)
                {
                    ReceiveBuffer[ReceiveIndex++] = uca0_rx_val; //Read the data from slave
                    //Transmit a dummy
                    RXByteCtr--;
                }
                if (RXByteCtr == 0)
                {
                    MasterMode = IDLE_MODE;
                    __bic_SR_register_on_exit(CPUOFF);      // Exit LPM0
                }
                else
                {
                    SendUCA0Data(DUMMY);
                }
                break;
              
            default:
                __no_operation();
                break;
        }
        __delay_cycles(1); //100 is ~20us break between Master Writes
        break;
    case 4:break;                             // Vector 4 - TXIFG
    default: break;
  }
}

//******************************************************************************
//
//   Description: SPI master (MSP430F5529) communicates to 3 ADS1118 slaves
//
//                   MSP430F5529
//                 -----------------
//                |      (See below)|-> Slave Chip Select (GPIO)
//                |                 |
//                |                 |
//                |                 |
//                |             P3.3|-> Data Out (UCA0SIMO/DIN)
//                |                 |
//                |             P3.4|<- Data In (UCA0SOMI/DOUT)
//                |                 |
//                |             P2.7|-> Serial Clock Out (UCA0CLK)
//                |                 |
//                |                 |
//
//CSB_ADC1 = P1.2; CSB_ADC2 = P1.3 ; CSB_ADC3 = P1.4
//
//
//******************************************************************************

#include <msp430.h> 
#include <stdint.h>
#include <stdbool.h>

#define DUMMY   0x00

#define CSB_M1_OUT    P1OUT
#define CSB_M1_DIR    P1DIR
#define CSB_M1_PIN    BIT2

#define CSB_M2_OUT    P1OUT
#define CSB_M2_DIR    P1DIR
#define CSB_M2_PIN    BIT3

#define CSB_M3_OUT    P1OUT
#define CSB_M3_DIR    P1DIR
#define CSB_M3_PIN    BIT4

#define LENGTH_ONE              1
#define LENGTH_TWO              2
#define LENGTH_SIX              6

#define MAX_BUFFER_SIZE     20
  
#define ADS1118_REG_ADDR_CONFIG_REG_MSB_def 0x8F //1000_1110
  //8: MODE = 0 for continuous conversion mode; 1 = power down mode
  //11:9: VREF = 111 for FSR = +/-0.256V
  //14:12: MUX = 000 for AIN0 = (+ve) and AIN1 = (-ve)
  //15: Single shot conversion start = 0 for no effect; 1 = start single conversion

typedef enum SPI_ModeEnum{
    IDLE_MODE,
    TX_REG_ADDRESS_MODE,
    RX_REG_ADDRESS_MODE,
    TX_DATA_MODE,
    RX_DATA_MODE,
    WRITE_READ_MODE,
    TIMEOUT_MODE
} SPI_Mode;


uint8_t ADS1118_REG_ADDR_CONFIG_REG_LSB[LENGTH_ONE] = {0xEB}; //1110_1010
  //0: Reserved
  //2:1: NOOP = 01 (Valid data)
  //3: PULL-UP EN = When /CSB is high, this pulls up the DOUT pin
  //4: TS_MODE = 0 (ADC) or 1 (Temp Sensor)
  //7:5: DR = 111 (860 SPS)

uint8_t CopyDestBuffer[LENGTH_SIX] = {0};
SPI_Mode MasterMode = IDLE_MODE;

uint8_t TransmitRegAddr = 0;
uint8_t TransmitDataMSB = 0;
uint8_t TransmitDataLSB = 0;
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;
uint8_t sensor_number = 0;
uint8_t num_accels = 5;
int sensorno;
int mymode = 0;
uint8_t mydata = 0;

void SendUCA0Data(uint8_t val);

//******************************************************************************
// CopyArray********************************************************************
//******************************************************************************
void CopyArray(uint8_t *source, uint8_t *dest, uint8_t count);
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];
    }
}

//******************************************************************************
// Master write to slave*******************************************************
//******************************************************************************
SPI_Mode SPI_Master_WriteReg(uint8_t reg_addr, uint8_t *reg_data, uint8_t count, int senNum, int mode);
SPI_Mode SPI_Master_WriteReg(uint8_t reg_addr, uint8_t *reg_data, uint8_t count, int senNum, int mode)
{
  
    sensor_number = senNum;
    MasterMode = TX_REG_ADDRESS_MODE; 
    TransmitRegAddr = reg_addr;

    //Copy register data to TransmitBuffer
    CopyArray(reg_data, TransmitBuffer, count);

    TXByteCtr = count;
    RXByteCtr = 0;  
    ReceiveIndex = 0;
    TransmitIndex = 0;
    mymode = mode;
       
    if (sensor_number == 6){
      CSB_M1_OUT &= ~(CSB_M1_PIN);
    }

    else if (sensor_number == 7){
      CSB_M2_OUT &= ~(CSB_M2_PIN);
    }

    else if (sensor_number == 8){
      CSB_M3_OUT &= ~(CSB_M3_PIN);
    }
    
    SendUCA0Data(TransmitRegAddr);

      __bis_SR_register(CPUOFF + GIE);              // Enter LPM0 w/ interrupts
  
    if (sensor_number == 6){
      CSB_M1_OUT |= CSB_M1_PIN;
    }  
    
    else if (sensor_number == 7){
      CSB_M2_OUT |= CSB_M2_PIN;
    }  
    
    else if (sensor_number == 8){
      CSB_M3_OUT |= CSB_M3_PIN;
    }  
    
    return MasterMode;
}

//******************************************************************************
// Master reads from Slave******************************************************
//******************************************************************************
SPI_Mode SPI_Master_ReadReg(uint8_t reg_addr, uint8_t count, int senNum);
SPI_Mode SPI_Master_ReadReg(uint8_t reg_addr, uint8_t count, int senNum)
{
    sensor_number = senNum;
    MasterMode = TX_REG_ADDRESS_MODE;
    TransmitRegAddr = reg_addr;
    RXByteCtr = count;
    TXByteCtr = 0;
    ReceiveIndex = 0;
    TransmitIndex = 0;

   if (sensor_number == 6){
      CSB_M1_OUT &= ~(CSB_M1_PIN);
    }

    else if (sensor_number == 7){
      CSB_M2_OUT &= ~(CSB_M2_PIN);
    }

    else if (sensor_number == 8){
      CSB_M3_OUT &= ~(CSB_M3_PIN);
    }

    __bis_SR_register(CPUOFF + GIE);              // Enter LPM0 w/ interrupts
    
    if (sensor_number == 6){
      CSB_M1_OUT |= CSB_M1_PIN;
    }  
    
    else if (sensor_number == 7){
      CSB_M2_OUT |= CSB_M2_PIN;
    }  
    
    else if (sensor_number == 8){
      CSB_M3_OUT |= CSB_M3_PIN;
    }   
    
    return MasterMode;
}

//******************************************************************************
//Send Data*********************************************************************
//******************************************************************************

void SendUCA0Data(uint8_t val)
{
 
    while (!(UCA0IFG & UCTXIFG));              // USCI_A0 TX buffer ready?
    UCA0TXBUF = val;
    
}

//******************************************************************************
// Set CLOCK to 16MHz*
//******************************************************************************

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
}

//******************************************************************************
// INIT GPIO
//******************************************************************************
void initGPIO()
{
  //The following for GPIOs for CSB:
  //CSB_A1 = P2.0; CSB_A2 = P2.2; CSB_A3 = P2.4; CSB_A4 = P2.5; CSB_A5 = P1.5
  //CSB_M1 = P1.2; CSB_M2 = P1.3 ; CSB_M3 = P1.4
 
  P4DIR |= BIT7;
  P4OUT &= ~(BIT7);

  //SPI Pins
  P3SEL |= BIT3 + BIT4;                     // P3.3 = SIMO; P3.4 = SOMI
  P2SEL |= BIT7;                            // P2.7 = SCLK
  
  //UART
  P4SEL |= BIT4 + BIT5;                   // P4.4 = UART TXD; P4.5 = UART RXD
  /*
  //Button to initiate transfer
  P2DIR &= ~BIT6;                           // Set P2.1 to inpput direction
  P2REN |= BIT6;                            // Enable P2.1 internal resistance
  P2OUT |= BIT6;                            // Set P2.1 as pull-Up resistance
  P2IES |= BIT6;                            // P2.1 Hi/Lo edge
  P2IFG &= ~BIT6;                           // P2.1 IFG cleared
  P2IE |= BIT6;                             // P2.1 interrupt enabled
*/
}

//******************************************************************************
// INIT SPI
//******************************************************************************
void initSPI(int sensorno)
{
  UCA0CTL0 &= 0;                        //clear this register
  UCA0CTL1 |= UCSWRST;                  // **Put state machine in reset**
  
    UCA0CTL0 |= UCMSB + UCMST + UCSYNC;
    /*UCCKPH = clock phase select = 0 according to ADS1118 SPI timing diagram
      UCCKPL = clock polarity select = 0 according to ADS1118 SPI timing diagram
      UCMSB = MSB first
      UCMST = MSP430F5528 is the master, MC3672 and ADS1118 = slaves
      UCSYNC = synchronous*/
 

  UCA0CTL1 |= UCSSEL_2;                     // clock = SMCLK
  UCA0BR0 |= 0x20;                          // Bit rate 
  UCA0BR1 = 0;                              //
  UCA0MCTL = 0;                             // No modulation must be cleared for SPI
  UCA0CTL1 &= ~UCSWRST;                     // **Initialize USCI state machine**
  UCA0IE |= UCRXIE;                          // Enable USCI0 RX interrupt
  
 
  CSB_M1_DIR |= CSB_M1_PIN;
  CSB_M1_OUT |= CSB_M1_PIN;
  
  CSB_M2_DIR |= CSB_M2_PIN;
  CSB_M2_OUT |= CSB_M2_PIN;
  
  CSB_M3_DIR |= CSB_M3_PIN;
  CSB_M3_OUT |= CSB_M3_PIN;
  
}


//******************************************************************************
// Main ************************************************************************
// Send and receive three messages containing the example commands *************
//******************************************************************************
int main(void) {
     
    WDTCTL = WDTPW | WDTHOLD;	// Stop watchdog timer
    initClockTo16MHz();
    initGPIO();
    
    while(1)
     {

        initSPI(1); //Initialize SPI for ADS1118
      	SPI_Master_WriteReg(ADS1118_REG_ADDR_CONFIG_REG_MSB_def, ADS1118_REG_ADDR_CONFIG_REG_LSB, LENGTH_ONE, 6, 1); //Write to and read from ADS1118
      
     }//end while
     
}//end main


//******************************************************************************
// 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:                                   // Vector 2 - RXIFG
      
        uca0_rx_val = UCA0RXBUF;
        
        switch (MasterMode)
        {
          //---Always starts with this---
            case TX_REG_ADDRESS_MODE:
                if (RXByteCtr)          //If Master reading from slave
                {
                    MasterMode = RX_DATA_MODE;   // Need to start receiving now
                    //Send Dummy To Start
                    __delay_cycles(75);
                    SendUCA0Data(DUMMY);
                }
                else if (TXByteCtr)                    //If Master writing to slave
                {
                    MasterMode = TX_DATA_MODE;        // Send the register address first
                    SendUCA0Data(TransmitBuffer[TransmitIndex++]);
                    TXByteCtr--;
                }
                break;

            case TX_DATA_MODE:          //If Master writing to slave
                if (TXByteCtr)          //Send the data
                {
                  SendUCA0Data(TransmitBuffer[TransmitIndex++]);
                  TXByteCtr--;
                }
                else
                {
                 if (mymode==1){
                    uca0_rx_val = UCA0RXBUF;
                    ReceiveBuffer[0] = uca0_rx_val;
                    uca0_rx_val = UCA0RXBUF;
                    ReceiveBuffer[1] = uca0_rx_val;
                    uca0_rx_val = UCA0RXBUF;
                    ReceiveBuffer[2] = uca0_rx_val;
                  }
                  //Done with transmission
                  MasterMode = IDLE_MODE;
                  __bic_SR_register_on_exit(CPUOFF);      // Exit LPM0
                }
                break;

            case RX_DATA_MODE:          //If Master reading from slave     
                if (RXByteCtr)
                {
                    ReceiveBuffer[ReceiveIndex++] = uca0_rx_val; //Read the data from slave
                    //Transmit a dummy
                    RXByteCtr--;
                }
                if (RXByteCtr == 0)
                {
                    MasterMode = IDLE_MODE;
                    __bic_SR_register_on_exit(CPUOFF);      // Exit LPM0
                }
                else
                {
                    SendUCA0Data(DUMMY);
                }
                break;
              
            default:
                __no_operation();
                break;
        }
        __delay_cycles(1); //100 is ~20us break between Master Writes
        break;
    case 4:break;                             // Vector 4 - TXIFG
    default: break;
  }
}
  • Hello Amy,

    Two things that jump out at me so far.

    First, you don't seem to be using the recommended DriverLib code that properly increases VCORE for 16MHz operation in your initClockTo16MHz() function.

    Second, I wouldn't recommend putting your SPI configuration code inside the endless while(1) function. It probably only needs done once. What happens if you execute the following two functions only once? Does the communication happen correctly?

    initSPI(1); //Initialize SPI for ADS1118
    SPI_Master_WriteReg(ADS1118_REG_ADDR_CONFIG_REG_MSB_def, ADS1118_REG_ADDR_CONFIG_REG_LSB, LENGTH_ONE, 6, 1); //Write to and read from ADS1118

    Regards,

    James

  • You're right, for this code, I can put the intSPI(1) outside of the while(1) loop. However, in my overall code, I am actually talking to other sensors (I am not showing it in the code), and the clock polarity for the other sensors is different than the clock polarity for the ADS1118, so I needed to change that every time I talk to ADS1118.

    Anyhow, if I only execute the two functions only once, then no, I am still unable to read the LSB of the ADS1118 output code.
  • You'll want to make sure you're SMCLK is exactly what you're expecting, so please look into setting up VCORE properly.

    Also, have you been following the pseudo code flow provided in Figure 49 in the Ultra-Small, Low-Power, SPI-Compatible, 16-Bit ADC and Temp Sensor w/ Int Ref datasheet? If your CPU is operating at a different frequency than expected and your delays don't match whats recommended, this could be why your communication doesn't work properly.

  • Hi James,

    Yes, I checked against the pseudo code flow, and all looks good. I can see the SPI communication using a scope, so I'm able to check the timing, but my code is not able to capture the LSB data from the ADS1118.

    Also added the code to set up VCORE properly. Thanks.
  • An SPI transaction is an Exchange -- in order to get a byte back, you need to send a byte. Thus,

    > if (mymode==1){
    > uca0_rx_val = UCA0RXBUF;
    > ReceiveBuffer[0] = uca0_rx_val;
    > uca0_rx_val = UCA0RXBUF;
    > ReceiveBuffer[1] = uca0_rx_val;
    > uca0_rx_val = UCA0RXBUF;
    > ReceiveBuffer[2] = uca0_rx_val;
    > }
    This will read duplicate bytes, since you're not sending anything in between.

    Is there a reason you can't just use ReadReg? It seems like all the infrastructure is there.
  • Hi Bruce,

    I see.  So it seems like the MSP430 needs to write CONFIG MSB and read DATA MSB, then write CONFIG LSB and read DATA LSB.

    So far, I've been doing - MSP430 writes CONFIG MSB and CONFIG LSB, then reads DATA MSB and DATA LSB but fails.  

    I'll give your suggestion a try. Thanks. 

     Hmm, 

  • Hello all,

    Ok, the MSP430 sent CONFIG MSB (0x8F), and it is able to read the correct DATA MSB from the ADS1118.  Then the MSP430 sent CONFIG LSB (0xEB), but once again, it is still unable to read DATA LSB from the ADS1118.  Codes attached. 

    If I'm sending the second byte, how come I am not getting the second byte back? Scoping the SPI shows the MSP430 is writing the correct values, the ADS1118 is reporting the correct values, and the timing looks good. 

    Thanks. 

    ADS1118_SPI_MSP430FF529_Code_v2.txt
    //******************************************************************************
    //   MSP430F552x Demo - USCI_A0, SPI 4-Wire Master multiple byte RX/TX
    //
    //   Description: SPI master (MSP430F5529) communicates to four MC3672 accelerometers
    //   and 3 ADS1118 (connected to TMR2901 3 channel device).  MC3672 will be operating
    //   in CWAKE mode using the INT pin as an output to indicate data ready. 
    //
    //                   MSP430F5529
    //                 -----------------
    //                |             P2.0|-> Slave Chip Select (GPIO)
    //                |                 |
    //                |                 |
    //                |                 |
    //                |             P3.3|-> Data Out (UCA0SIMO/DIN)
    //                |                 |
    //                |             P3.4|<- Data In (UCA0SOMI/DOUT)
    //                |                 |
    //                |             P2.7|-> Serial Clock Out (UCA0CLK)
    //                |                 |
    //                |             P4.5| -->UART (UCA1RXD)
    //                |                 |
    //                |             P4.4| -->UART (UCA1TXD)
    //                |                 |
    //
    //CSB_A1 = P2.0; CSB_A2 = P2.2; CSB_A3 = P2.4; CSB_A4 = P2.5; CSB_A5 = P1.5
    //CSB_M1 = P1.2; CSB_M2 = P1.3 ; CSB_M3 = P1.4
    //
    //INT_A1 = P2.6
    //
    //July 11, 2018: I can write from master to slave, but I can't seem to read from slave (SOMI looks odd on scope, maybe bad DUT?)
    //Aug 17, 2018: Can now talk to one MC3672 via SPI
    //Aug 21, 2018: I can now talk to 5 MC3672 but need to talk to the ADC as well.  
    //Aug 23, 2018: Trying to get MC3672 to interrupt, but its INT pin keeps going high all the time\
    //******************************************************************************
    
    #include <msp430.h> 
    #include <stdint.h>
    #include <stdbool.h>
    
    #define DUMMY   0x00
    
    #define CSB_A1_OUT    P2OUT
    #define CSB_A1_DIR    P2DIR
    #define CSB_A1_PIN    BIT0
    
    #define CSB_A2_OUT    P2OUT
    #define CSB_A2_DIR    P2DIR
    #define CSB_A2_PIN    BIT2
    
    #define CSB_A3_OUT    P2OUT
    #define CSB_A3_DIR    P2DIR
    #define CSB_A3_PIN    BIT4
    
    #define CSB_A4_OUT    P2OUT
    #define CSB_A4_DIR    P2DIR
    #define CSB_A4_PIN    BIT5
    
    #define CSB_A5_OUT    P1OUT
    #define CSB_A5_DIR    P1DIR
    #define CSB_A5_PIN    BIT5
    
    #define CSB_M1_OUT    P1OUT
    #define CSB_M1_DIR    P1DIR
    #define CSB_M1_PIN    BIT2
    
    #define CSB_M2_OUT    P1OUT
    #define CSB_M2_DIR    P1DIR
    #define CSB_M2_PIN    BIT3
    
    #define CSB_M3_OUT    P1OUT
    #define CSB_M3_DIR    P1DIR
    #define CSB_M3_PIN    BIT4
    
    //MC3672 SPI PROTOCOL = [\W,R][1][Reg Addr][Data]
    #define MC3672_REG_ADDR_EN_SPI_WR_0D       0x4D
    #define MC3672_REG_ADDR_SCRATCH_PAD_WR_1B  0x5B //1B = 01_1011 --> 0101_1011 = 0x5B
    #define MC3672_REG_ADDR_SCRATCH_PAD_RD_1B  0xDB //1B=0001_1011 -->1101_1011 = 0xDB
    
    #define MC3672_REG_ADDR_MODE_WR_10  0x50 //10 = 0001_0000 --> 0101_0000 = 0x50
    #define MC3672_REG_ADDR_MODE_RD_10  0xD0 //10 = 0001_0000 --1101_0000 = 0xD0
    #define MC3672_REG_ADDR_RESET_WR_24  0x64 //24 = 0010_0100 --> 0110_0100 = 0x64
    #define MC3672_REG_ADDR_INIT1_WR_0F  0x4F //0F = 0000_1111 --> 0100_1111 = 0x4F
    #define MC3672_REG_ADDR_INIT2_WR_20  0x60 //20 = 0010_0000 -->0110_0000 = 0x60
    #define MC3672_REG_ADDR_INIT3_WR_21  0x61 //21 = 0010_0001 -->0110_0001 = 0x61
    #define MC3672_REG_ADDR_INIT4_WR_28  0x68 //28 = 0010_1000 -->0110_1000 = 0x68
    #define MC3672_REG_ADDR_INIT5_WR_1A  0x5A //1A = 0001_1010 --> 0101_1010 = 0x5A  
    
    #define MC3672_REG_ADDR_RANGE_WR_15  0x55 //15 = 0001_0101 --> 0101_0101 = 0x55
    #define MC3672_REG_ADDR_FIFO_WR_16  0x56 //16 = 0001_0110 --> 0101_0110 = 56
    #define MC3672_REG_ADDR_UL_PWR_WR_1C  0x5C //1C = 0001_1100 --> 0101_1100 = 5C
    #define MC3672_REG_ADDR_SPS_WR_11  0x51 //11=0001_0001 --> 0101_0001 = 51
    #define MC3672_REG_ADDR_XYZ_RD_02  0xC2 //02=0000_0010 --1100_0010 = C2
    #define MC3672_REG_ADDR_TRIG_CNT_WR_29 0x69 //29 = 0010_1001 --> 0110_1001 = 69
    #define MC3672_REG_ADDR_INT_WR_17 0x57 //17 = 0001_0111 --> 0101_0111 = 57
    #define MC3672_REG_ADDR_STAT1_RD_08  0xC8 //08 = 0000_1000 -->1100_1000
    
    #define LENGTH_ONE              1
    #define LENGTH_TWO              2
    #define LENGTH_SIX              6
    
    #define MAX_BUFFER_SIZE     20
      
    #define ADS1118_REG_ADDR_CONFIG_REG_MSB_def 0x8F //1000_1110
      //8: MODE = 0 for continuous conversion mode; 1 = power down mode
      //11:9: VREF = 111 for FSR = +/-0.256V
      //14:12: MUX = 000 for AIN0 = (+ve) and AIN1 = (-ve)
      //15: Single shot conversion start = 0 for no effect; 1 = start single conversion
    #define LSB 0xEB
    
    typedef enum SPI_ModeEnum{
        IDLE_MODE,
        TX_REG_ADDRESS_MODE,
        RX_REG_ADDRESS_MODE,
        TX_DATA_MODE,
        RX_DATA_MODE,
        WRITE_READ_MODE,
        TIMEOUT_MODE
    } SPI_Mode;
    
    uint8_t MC3672_DATA_EN_SPI_80[LENGTH_ONE] = {0x80};
    uint8_t MC3672_DATA_SCRATCH_PAD_AA[LENGTH_ONE] = {0xAA};
    uint8_t MC3672_DATA_STANDBY_01[LENGTH_ONE] = {0x01};
    uint8_t MC3672_DATA_RESET_40[LENGTH_ONE] = {0x40};
    uint8_t MC3672_DATA_INIT1_42[LENGTH_ONE] = {0x42};
    uint8_t MC3672_DATA_INIT2_01[LENGTH_ONE] = {0x01};
    uint8_t MC3672_DATA_INIT3_80[LENGTH_ONE] = {0x80};
    uint8_t MC3672_DATA_00[LENGTH_ONE] = {0x00};
    uint8_t MC3672_DATA_RANGE_2G_12BIT_04[LENGTH_ONE] = {0x04};
    uint8_t MC3672_DATA_UL_PWR_03[LENGTH_ONE] = {0x03};
    uint8_t MC3672_DATA_SPS_0B[LENGTH_ONE] = {0x0B};
    uint8_t MC3672_DATA_SPS_08[LENGTH_ONE] = {0x08};
    uint8_t MC3672_DATA_CWAKE_05[LENGTH_ONE] = {0x05};
    uint8_t MC3672_DATA_INT[LENGTH_ONE] = {0x09}; //0000_1001
    uint8_t MC3672_DATA_TRIG_MODE[LENGTH_ONE] = {0x87}; //1000_0111
    uint8_t MC3672_DATA_TRIG_COUNT[LENGTH_ONE] = {0x01}; 
    uint8_t MC3672_DATA_CLEAR_INT[LENGTH_ONE] = {0x00}; 
    
    uint8_t ADS1118_REG_ADDR_CONFIG_REG_LSB[LENGTH_ONE] = {0xEB}; //1110_1010
      //0: Reserved
      //2:1: NOOP = 01 (Valid data)
      //3: PULL-UP EN = When /CSB is high, this pulls up the DOUT pin
      //4: TS_MODE = 0 (ADC) or 1 (Temp Sensor)
      //7:5: DR = 111 (860 SPS)
    
    uint8_t CopyDestBuffer[LENGTH_SIX] = {0};
    SPI_Mode MasterMode = IDLE_MODE;
    
    /* The Register Address/Command to use*/
    uint8_t TransmitRegAddr = 0;
    uint8_t TransmitDataMSB = 0;
    uint8_t TransmitDataLSB = 0;
    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;
    uint8_t sensor_number = 0;
    uint8_t num_accels = 5;
    int mymode = 0;
    uint8_t mydata = 0;
    
    void SendUCA0Data(uint8_t val);
    
    //******************************************************************************
    // CopyArray********************************************************************
    //******************************************************************************
    void CopyArray(uint8_t *source, uint8_t *dest, uint8_t count);
    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];
        }
    }
    
    //******************************************************************************
    // Master write to slave*******************************************************
    //******************************************************************************
    SPI_Mode SPI_Master_WriteReg(uint8_t reg_addr, uint8_t *reg_data, uint8_t count, int senNum, int mode);
    SPI_Mode SPI_Master_WriteReg(uint8_t reg_addr, uint8_t *reg_data, uint8_t count, int senNum, int mode)
    {
      
        sensor_number = senNum;
        MasterMode = TX_REG_ADDRESS_MODE; 
        TransmitRegAddr = reg_addr;
    
        //Copy register data to TransmitBuffer
        CopyArray(reg_data, TransmitBuffer, count);
    
        TXByteCtr = count;
        RXByteCtr = 0;  
        ReceiveIndex = 0;
        TransmitIndex = 0;
        mymode = mode;
           
        if (sensor_number == 1){
          CSB_A1_OUT &= ~(CSB_A1_PIN);
        }
        
        else if (sensor_number == 2){
          CSB_A2_OUT &= ~(CSB_A2_PIN);
        }
    
        else if (sensor_number == 3){
          CSB_A3_OUT &= ~(CSB_A3_PIN);
        }
         
        else if (sensor_number == 4){
          CSB_A4_OUT &= ~(CSB_A4_PIN);
        }
         
        else if (sensor_number == 5){
          CSB_A5_OUT &= ~(CSB_A5_PIN);
        }
        
        else if (sensor_number == 6){
          CSB_M1_OUT &= ~(CSB_M1_PIN);
        }
    
        else if (sensor_number == 7){
          CSB_M2_OUT &= ~(CSB_M2_PIN);
        }
    
        else if (sensor_number == 8){
          CSB_M3_OUT &= ~(CSB_M3_PIN);
        }
        
        SendUCA0Data(TransmitRegAddr);
    
          __bis_SR_register(CPUOFF + GIE);              // Enter LPM0 w/ interrupts
      
    
        if (sensor_number == 1){
          CSB_A1_OUT |= CSB_A1_PIN;
        }
        
        else if (sensor_number == 2){
          CSB_A2_OUT |= CSB_A2_PIN;
        }
    
        else if (sensor_number == 3){
          CSB_A3_OUT |= CSB_A3_PIN;
        }
    
        else if (sensor_number == 4){
          CSB_A4_OUT |= CSB_A4_PIN;
        }
    
        else if (sensor_number == 5){
          CSB_A5_OUT |= CSB_A5_PIN;
        } 
        
        else if (sensor_number == 6){
          CSB_M1_OUT |= CSB_M1_PIN;
        }  
        
        else if (sensor_number == 7){
          CSB_M2_OUT |= CSB_M2_PIN;
        }  
        
        else if (sensor_number == 8){
          CSB_M3_OUT |= CSB_M3_PIN;
        }  
        
        return MasterMode;
    }
    
    //******************************************************************************
    // Master reads from Slave******************************************************
    //******************************************************************************
    SPI_Mode SPI_Master_ReadReg(uint8_t reg_addr, uint8_t count, int senNum, int mode);
    SPI_Mode SPI_Master_ReadReg(uint8_t reg_addr, uint8_t count, int senNum, int mode)
    {
        sensor_number = senNum;
        MasterMode = TX_REG_ADDRESS_MODE;
        TransmitRegAddr = reg_addr;
        RXByteCtr = count;
        TXByteCtr = 0;
        ReceiveIndex = 0;
        TransmitIndex = 0;
        mymode = mode;
    
        if (sensor_number == 1){
          CSB_A1_OUT &= ~(CSB_A1_PIN);
        }
        
        else if (sensor_number == 2){
          CSB_A2_OUT &= ~(CSB_A2_PIN);
        }
    
        else if (sensor_number == 3){
          CSB_A3_OUT &= ~(CSB_A3_PIN);
        }
         
        else if (sensor_number == 4){
          CSB_A4_OUT &= ~(CSB_A4_PIN);
        }
         
        else if (sensor_number == 5){
          CSB_A5_OUT &= ~(CSB_A5_PIN);
        }
    
        else if (sensor_number == 6){
          CSB_M1_OUT &= ~(CSB_M1_PIN);
        }
    
        else if (sensor_number == 7){
          CSB_M2_OUT &= ~(CSB_M2_PIN);
        }
    
        else if (sensor_number == 8){
          CSB_M3_OUT &= ~(CSB_M3_PIN);
        }
        
        SendUCA0Data(TransmitRegAddr);  
    
        __bis_SR_register(CPUOFF + GIE);              // Enter LPM0 w/ interrupts
        
        if (sensor_number == 1){
          CSB_A1_OUT |= CSB_A1_PIN;
        }
        
        else if (sensor_number == 2){
          CSB_A2_OUT |= CSB_A2_PIN;
        }
    
        else if (sensor_number == 3){
          CSB_A3_OUT |= CSB_A3_PIN;
        }
    
        else if (sensor_number == 4){
          CSB_A4_OUT |= CSB_A4_PIN;
        }
    
        else if (sensor_number == 5){
          CSB_A5_OUT |= CSB_A5_PIN;
        }  
        
        else if (sensor_number == 6){
          CSB_M1_OUT |= CSB_M1_PIN;
        }  
        
        else if (sensor_number == 7){
          CSB_M2_OUT |= CSB_M2_PIN;
        }  
        
        else if (sensor_number == 8){
          CSB_M3_OUT |= CSB_M3_PIN;
        }   
        
        return MasterMode;
    }
    
    //******************************************************************************
    //Send Data*********************************************************************
    //******************************************************************************
    
    void SendUCA0Data(uint8_t val)
    {
     
        while (!(UCA0IFG & UCTXIFG));              // USCI_A0 TX buffer ready?
        UCA0TXBUF = val;
    
    }
    
    //******************************************************************************
    // Set CLOCK to 16MHz*
    //******************************************************************************
    
    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
    }
    
    //******************************************************************************
    // INIT GPIO
    //******************************************************************************
    void initGPIO()
    {
      //The following for GPIOs for CSB:
      //CSB_A1 = P2.0; CSB_A2 = P2.2; CSB_A3 = P2.4; CSB_A4 = P2.5; CSB_A5 = P1.5
      //CSB_M1 = P1.2; CSB_M2 = P1.3 ; CSB_M3 = P1.4
     
      P4DIR |= BIT7;
      P4OUT &= ~(BIT7);
    
      //SPI Pins
      P3SEL |= BIT3 + BIT4;                     // P3.3 = SIMO; P3.4 = SOMI
      P2SEL |= BIT7;                            // P2.7 = SCLK
      
      //UART
      P4SEL |= BIT4 + BIT5;                   // P4.4 = UART TXD; P4.5 = UART RXD
      /*
      //Button to initiate transfer
      P2DIR &= ~BIT6;                           // Set P2.1 to inpput direction
      P2REN |= BIT6;                            // Enable P2.1 internal resistance
      P2OUT |= BIT6;                            // Set P2.1 as pull-Up resistance
      P2IES |= BIT6;                            // P2.1 Hi/Lo edge
      P2IFG &= ~BIT6;                           // P2.1 IFG cleared
      P2IE |= BIT6;                             // P2.1 interrupt enabled
    */
    }
    
    //******************************************************************************
    // INIT SPI
    //******************************************************************************
    void initSPI()
    {
      UCA0CTL0 &= 0;                        //clear this register
      UCA0CTL1 |= UCSWRST;                  // **Put state machine in reset**
      
      UCA0CTL0 |= UCCKPL + UCMSB + UCMST + UCSYNC; 
      /*UCCKPH = clock phase select = 0 according to MC3672 SPI timing diagram
      UCCKPL = clock polarity select = 1 according to MC3672 SPI timing diagram
      UCMSB = MSB first
      UCMST = MSP430F5528 is the master, MC3672 and ADS1118 = slaves
      UCSYNC = synchronous*/
    
      UCA0CTL1 |= UCSSEL_2;                     // clock = SMCLK
      UCA0BR0 |= 0x20;                          // Bit rate 
      UCA0BR1 = 0;                              //
      UCA0MCTL = 0;                             // No modulation must be cleared for SPI
      UCA0CTL1 &= ~UCSWRST;                     // **Initialize USCI state machine**
      UCA0IE |= UCRXIE;                          // Enable USCI0 RX interrupt
      
      CSB_A1_DIR |= CSB_A1_PIN;
      CSB_A1_OUT |= CSB_A1_PIN;
      
      CSB_A2_DIR |= CSB_A2_PIN;
      CSB_A2_OUT |= CSB_A2_PIN;
      
      CSB_A3_DIR |= CSB_A3_PIN;
      CSB_A3_OUT |= CSB_A3_PIN;
      
      CSB_A4_DIR |= CSB_A4_PIN;
      CSB_A4_OUT |= CSB_A4_PIN;
      
      CSB_A5_DIR |= CSB_A5_PIN;
      CSB_A5_OUT|= CSB_A5_PIN;
      
      CSB_M1_DIR |= CSB_M1_PIN;
      CSB_M1_OUT |= CSB_M1_PIN;
      
      CSB_M2_DIR |= CSB_M2_PIN;
      CSB_M2_OUT |= CSB_M2_PIN;
      
      CSB_M3_DIR |= CSB_M3_PIN;
      CSB_M3_OUT |= CSB_M3_PIN;
      
    }
    
    //******************************************************************************
    //Initialize UART***************************************************************
    //******************************************************************************
    void initUART();
    void initUART()
    {
      int br = 1;
      UCA1CTL1 |= UCSWRST;          //Reset state machine
      
      if (br == 1){     //baud rate of 115200
        UCA1CTL1 |= UCSSEL_2;         //CLK = SMCLK = 16MHz
        UCA1BR0 = 0x8A;                //Baud rate = 115200
        UCA1BR1 = 0x0;  
        UCA0MCTL = 0x07;
      }
    
      UCA1CTL0 = 0x00;              //Not used
      UCA1CTL1 &= ~UCSWRST;         //Initialize state machine
    
    }
    
    //******************************************************************************
    //Sending data through UART*****************************************************
    //******************************************************************************
    void Send_UART(uint8_t BytetoSend, int sensor_number, int mode);
    void Send_UART(uint8_t BytetoSend, int sensor_number, int mode)
    {
      int i;
      int max;
      
      if (mode==0){
        max = 6;
      }
      else{
        max = 2;
      }
      
      int sensor = sensor_number;
      
      if (sensor ==1)
      {
        UCA1TXBUF = 0x53;
        while(UCA1STAT&UCBUSY);
      }
      else if (sensor ==2)
      {
        UCA1TXBUF = 0x54;
        while(UCA1STAT&UCBUSY);
      }
      else if (sensor ==3)
      {
        UCA1TXBUF = 0x55;
        while(UCA1STAT&UCBUSY);
      }
      else if (sensor ==4)
      {
        UCA1TXBUF = 0x56;
        while(UCA1STAT&UCBUSY);
      }
       
        else if (sensor ==5)
      {
        UCA1TXBUF = 0x57;
        while(UCA1STAT&UCBUSY);
      }
      
      else if (sensor ==6)
      {
        UCA1TXBUF = 0x58;
        while(UCA1STAT&UCBUSY);
      }
      
      else if (sensor ==7)
      {
        UCA1TXBUF = 0x59;
        while(UCA1STAT&UCBUSY);
      }
      
      else if (sensor ==8)
      {
        UCA1TXBUF = 0x5A;
        while(UCA1STAT&UCBUSY);
      }
          
      for (i=0; i<max; i++)
      { //send for one byte
          UCA1TXBUF = ReceiveBuffer[i];
          while(UCA1STAT&UCBUSY);
      }
    
        UCA1TXBUF = 0x0d; //return
        while (UCA1STAT&UCBUSY);
        UCA1TXBUF = 0x0a;  //new line  
        while (UCA1STAT&UCBUSY);
    
      
       for (i=0; i<7; i++)//clear out the Receive Buffer
        {
           ReceiveBuffer[i] = 0x00;
        }  
        
    } //end function
    
    //******************************************************************************
    //Initialize the accelerometers*************************************************
    //******************************************************************************
    void initAccels();
    void initAccels()
    {  
      int sensor_no;
      initSPI(); //Initalize SPI for MC3672
      for (sensor_no = 1; sensor_no < 2; sensor_no++)
      { 
        SPI_Master_WriteReg(MC3672_REG_ADDR_MODE_WR_10, MC3672_DATA_STANDBY_01, LENGTH_ONE, sensor_no, 0);//sleep
      //  SPI_Master_WriteReg(MC3672_REG_ADDR_RESET_WR_24, MC3672_DATA_RESET_40, LENGTH_ONE, sensor_no, 0);//reset
        __delay_cycles(20000);    //wait for 1ms
        
        //Initialize
        SPI_Master_WriteReg(MC3672_REG_ADDR_EN_SPI_WR_0D, MC3672_DATA_EN_SPI_80, LENGTH_ONE, sensor_no, 0); //Enable SPI
        SPI_Master_WriteReg(MC3672_REG_ADDR_SCRATCH_PAD_WR_1B, MC3672_DATA_SCRATCH_PAD_AA, LENGTH_ONE, sensor_no, 0);
        SPI_Master_WriteReg(MC3672_REG_ADDR_INIT1_WR_0F, MC3672_DATA_INIT1_42, LENGTH_ONE, sensor_no, 0);
        SPI_Master_WriteReg(MC3672_REG_ADDR_INIT2_WR_20, MC3672_DATA_INIT2_01, LENGTH_ONE, sensor_no, 0);   
        SPI_Master_WriteReg(MC3672_REG_ADDR_INIT3_WR_21, MC3672_DATA_INIT3_80, LENGTH_ONE, sensor_no, 0);
        SPI_Master_WriteReg(MC3672_REG_ADDR_INIT4_WR_28, MC3672_DATA_00, LENGTH_ONE, sensor_no, 0);
        SPI_Master_WriteReg(MC3672_REG_ADDR_INIT5_WR_1A, MC3672_DATA_00, LENGTH_ONE, sensor_no, 0);
        
        SPI_Master_WriteReg(MC3672_REG_ADDR_RANGE_WR_15, MC3672_DATA_RANGE_2G_12BIT_04, LENGTH_ONE, sensor_no, 0); //set range and resolution
        SPI_Master_WriteReg(MC3672_REG_ADDR_INT_WR_17, MC3672_DATA_INT, LENGTH_ONE, sensor_no, 0);  //Interrupt
        SPI_Master_WriteReg(MC3672_REG_ADDR_UL_PWR_WR_1C, MC3672_DATA_UL_PWR_03, LENGTH_ONE, sensor_no, 0); //Ultra low power mode
        SPI_Master_WriteReg(MC3672_REG_ADDR_SPS_WR_11, MC3672_DATA_SPS_08, LENGTH_ONE, sensor_no, 0); //100 SPS
      //  SPI_Master_WriteReg(MC3672_REG_ADDR_TRIG_CNT_WR_29, MC3672_DATA_TRIG_COUNT, LENGTH_ONE, sensor_no, 0); //TRIG count register
        SPI_Master_WriteReg(MC3672_REG_ADDR_MODE_WR_10, MC3672_DATA_CWAKE_05, LENGTH_ONE, sensor_no, 0); //CWAKE mode
        
      }
      
    }//end function
    
    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 ************************************************************************
    // Send and receive three messages containing the example commands *************
    //******************************************************************************
    int main(void) {
         
        increaseVCoreToLevel2();
        WDTCTL = WDTPW | WDTHOLD;	// Stop watchdog timer
        initClockTo16MHz();
        initGPIO();
        initUART();
        
        initAccels();
        initSPI(); //Initalize SPI for MC3672
        
        while(1)
         {
    
            UCA0CTL0 = 0x29; //0010_1001 = UCMSB + UCMST + UCSYNC; change ADS1118 clock polarity
            SPI_Master_ReadReg(ADS1118_REG_ADDR_CONFIG_REG_MSB_def, LENGTH_ONE, 6, 1);
            Send_UART(LENGTH_TWO, 6, 1);   //number of bytes to send, sensor*/
          
         }//end while
         
    }//end main
    
    
    //******************************************************************************
    // 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:                                   // Vector 2 - RXIFG
          
            uca0_rx_val = UCA0RXBUF;
             
            switch (MasterMode)
            {
              //---Always starts with this---
                case TX_REG_ADDRESS_MODE:
                    if (RXByteCtr)          //If Master reading from slave
                    {
                        MasterMode = RX_DATA_MODE;   // Need to start receiving now
                        //Send Dummy To Start
                        __delay_cycles(75);
                        if (mymode ==0){
                          SendUCA0Data(DUMMY);
                        }
                        else if (mymode==1){
                          ReceiveBuffer[0] = uca0_rx_val;
                          SendUCA0Data(LSB);
                        }
                    }
                    else if (TXByteCtr)                    //If Master writing to slave
                    {
                        MasterMode = TX_DATA_MODE;        // Send the register address first
                        SendUCA0Data(TransmitBuffer[TransmitIndex++]);
                        TXByteCtr--;
                    }
                    break;
    
                case TX_DATA_MODE:          //If Master writing to slave
                    if (TXByteCtr)          //Send the data
                    {
                      SendUCA0Data(TransmitBuffer[TransmitIndex++]);
                      TXByteCtr--;
                    }
                    else
                    {
                      //Done with transmission
                      MasterMode = IDLE_MODE;
                      __bic_SR_register_on_exit(CPUOFF);      // Exit LPM0
                    }
                    break;
    
                case RX_DATA_MODE:          //If Master reading from slave     
                    if (RXByteCtr)
                    {
                      if (mymode ==0){
                        ReceiveBuffer[ReceiveIndex++] = uca0_rx_val; //Read the data from slave
                      }
                      else if (mymode ==1){
                        ReceiveBuffer[1] = uca0_rx_val;
                      }
                        //Transmit a dummy
                        RXByteCtr--;
                    }
                    if (RXByteCtr == 0)
                    {
                        MasterMode = IDLE_MODE;
                        __bic_SR_register_on_exit(CPUOFF);      // Exit LPM0
                    }
                    else
                    {
                        SendUCA0Data(DUMMY);
                    }
                    break;
                  
                default:
                    __no_operation();
                    break;
            }
            __delay_cycles(75); //100 is ~20us break between Master Writes
            break;
        case 4:break;                             // Vector 4 - TXIFG
        default: break;
      }
    }
    

  • I don't see any obvious flaws in the logic here.

    What does "unable to read" mean exactly? Is the program not requesting (Tx) the second byte, or is the resulting (Rx) second byte incorrect? What does the UART report?

    > UCA0CTL0 = 0x29; //0010_1001 = UCMSB + UCMST + UCSYNC; change ADS1118 clock polarity
    UCCKPL is marked as a field which requires a reset (UCSWRST sequence) to change, so I suspect this change isn't happening. What does the clock polarity look like on the scope?

    Also, "mymode" should be declared "volatile". Even if this isn't causing trouble now, it will eventually.

    The next thing I would do is put a breakpoint on this line:
    > ReceiveBuffer[1] = uca0_rx_val;
    and see (1) if it gets there (2) what uca0_rx_val is.
  • Hi Bruce,

    >>"Unable to read" means UCA0RXBUF__SPI is unable to read the LSB of the ADS1118. 

    I'm attaching the ADS1118 SPI diagram, and as you can, the ADS1118 DATA MSB = 0x02 and DATA LSB = 0xC8.  If I run through the code, UCA0RXBUF__SPI keeps reporting 0x02 (the MSB); it never reads 0xC8 (the LSB).

    My ReceiveBuffer[0] = 0x02, and ReceiveBuffer[1] = 0x02.

    >> I'm also attaching a picture the ADS1118 clock polarity, which I think is fine.  If this were wrong, the ADS1118 would not have reported the correct output code. 

    Thanks

    .

  • Curious. Combined with the clock polarity, this behavior is more consistent with your first code than your second.

    What do you see when you hit that breakpoint I suggested? (At that point ReceiveBuffer[1] should be 0.)

    What does the UART output say?
  • Hi Bruce,

    Ok, this is very strange.  When I put a break point at just ReceiveBuffer[1], then I can see the correct ADS1118 MSB+LSB, and my ReceiveBuffer reports 0x02 and 0xC8.

    However, when I put a break point at both ReceiveBuffer[0] and ReceiveBuffer[1] and keeps pressing F5, then my ReceiveBuffer contains 0x02 and 0x02.  

    If I just let the code free run and use Putty to probe UART, then it was very hard to decipher the ASCII code.  I wasn't able to see what code was coming out, but it seems like only one byte is coming out (picture of Putty UART communication attached. Note: "X" is just 0x58 that I used to indicate which sensor I'm communicating to)

  • I put your "v2" code on an F5529 Launchpad, and jumpered P3.3 to P3.4 (SIMO to SOMI), creating a loopback.

    When I run it and pause every so often, I always see [0x8F,0xEB,0x00] in ReceiveBuffer, which is what I expect. (Occasionally I see all-0s, meaning I caught it just after Send_UART cleared it.)

    I'm not sure what you and I are doing differently.
  • Hi Bruce,

    I repeated your experiment, and I'm getting the same result as you.  

    However, if I connect SIMO and SOMI to the ADS1118, then I just can't seem to read out the ADS1118 LSB data.  Is this something I should ask the ADS1118 team? 

  • I tried hooking up an "echo server" SPI slave (derived from one of the TI examples) and I get the same (correct) results.

    It's not at all obvious to me how the ADS1118 could cause the symptom you describe, particularly with that scope trace. But it's also the case that I've run out of things to try, since I don't have your equipment.

    Maybe (as you say) the ADS1118 people will recognize something.
  • Amy,


    Just so that I understand, does the ADS1118 respond with the proper output? From your scope plot, it looks like the ADS1118 gives the proper DOUT (MISO) response. The readback looks like 0x02 0xC8. On the scope, does the readback ever look like 0x02 0x02 as you're getting from the MSP430?

    The only thing that might reset the DOUT is if the conversions are not synchronized with the communications. For example, if you are in the middle of reading the data, a new conversion completes. Then the DOUT will be updated with the new conversion result. This would cause the reading to restart. Most of the time, we recommend running the device in single-shot conversion mode and then have the master wait the full data period plus 10% for clock variation. For example, if the device is set for 128SPS, you would wait about 8.6ms to read the device.

    If you are running in continuous conversion mode, you want to make sure you start the data read with the DOUT/DRDY transition low. If you do it only by polling, then new conversion data could come up during a read, which could cause a problem in reading SPI data.

    However, if the ADS1118 DOUT always looks ok on the scope, but you're still getting read errors from the MSP430, I would suspect the problem is with the MSP430 or the code.


    Joseph Wu
  • Hi Amy,

    Based on the description of what is happening, I would consider the possibility that something is incorrect relative to timing. It is very possible that the execution of your program flow is actually faster than the time it takes to transmit the TX buffer contents. This may be especially true if the interrupt service routine has a delay sequence that is much much smaller than the time to transmit.

    As your read routine is independent of the interrupt state machine, it is quite possible that you have already entered into the UART transmit sequence before the state machine has become idle. The incorrect timing is most likely why you are able to see the correct data when using a breakpoint.

    Best regards,
    Bob B

**Attention** This is a public forum