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.

ADS1220: Configuring ADS1220 and MSP430F2013 for data Acquisition

Part Number: ADS1220
Other Parts Discussed in Thread: MSP430F2013

Hi Team,

I am posting this in behalf of our customer. Here it is below:

I am planning to do following:

1. Measure 3 bridge circuit with strain gauge and using 2 ADS1220 in differntial mode for sampling sequentially.

2. I need to record data from the ADS1220 hence I have to use MSP430f2013 to with SPI.

Now from research, I couldn't find examples of ADS1220 other than   https://www.ti.com/lit/zip/sbac227. Which were not so helpful.

After trying to configure MSP430f2013 partially I started to get the error of 

error #10234-D: unresolved symbols remain
error #10010: errors encountered during linking; "ads1220.out" not built
gmake[1]: *** [ads1220.out] Error 1
gmake: *** [all] Error 2
Please note that I have successfully configured MSP430F2013 before with CCS but now it doesn't build with ADS1220 code
#include <msp430.h>
#include <ADS1220.h>
/* Function declarations */
void Init_StartUp(void);
void SPIinit(void);
/* Global variable */
int dflag = 0;
static volatile unsigned int ChA2results = 0x00;
int main(void)
{
  volatile unsigned int i;

  WDTCTL = WDTPW + WDTHOLD;             // Stop watchdog timer


  USICTL0 |= USISWRST; //USI released for operation
  USICTL1 &= ~USII2C + USIIE; //switch USI to SPI-Mode
  USICTL0 |= USIMST; //set to SPI-Master-Mode
  USICTL0 |= USIPE6 + USIPE5 + USIPE7; //SDO-Port enabled; Pin8
  USICTL0 |= USIOE; //activate output
  USICTL0 &= ~USISWRST;
  USICKCTL = USISSEL_2;

  void Init_StartUp(void);                 // Initialize device
  void ADS1220Init(void);                    // Initializes the SPI port pins as well as control
   void ADS1220Config(void);                // Set base configuration for ADS1x20 device
   ADS1220SetChannel(ADS1220_MUX_0_1);
   ADS1220SetGain(ADS1220_GAIN_32);
   set_MODE(ADS1220_MODE_TURBO);
   set_CM(ADS1220_CC);
   set_VREF(ADS1220_VREF_INT);
   //ADS1220SetDataRate(ADS1220_DR_2000);
   set_DR(110);


    while(1)
     {
         /* Add specifc command for reading and writing ADS1220 here */
         /* dFlag is set in the interrupt service routine when DRDY triggers end
            of conversion */
         if (dflag)                      /* check if new data is available */
         {
             ChA2results = ADS1220ReadData();  /* get the data from the ADS1220 */
             dflag=0;
         }
         /* other routines could be added here, such as change the mux setting */
     }  /* end of while(1) */




 // __bis_SR_register(LPM0_bits + GIE);   // Enter LPM0 w/ interrupt
}




It would be great help if someone provided with suggestion to make this work.

0358.main.c
/* --COPYRIGHT--,BSD_EX
 * Copyright (c) 2012, Texas Instruments Incorporated
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * *  Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *
 * *  Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * *  Neither the name of Texas Instruments Incorporated nor the names of
 *    its contributors may be used to endorse or promote products derived
 *    from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 *******************************************************************************
 *
 *                       MSP430 CODE EXAMPLE DISCLAIMER
 *
 * MSP430 code examples are self-contained low-level programs that typically
 * demonstrate a single peripheral function or device feature in a highly
 * concise manner. For this the code may rely on the device's power-on default
 * register values and settings such as the clock configuration and care must
 * be taken when combining code from several examples to avoid potential side
 * effects. Also see www.ti.com/grace for a GUI- and www.ti.com/msp430ware
 * for an API functional library-approach to peripheral configuration.
 *
 * --/COPYRIGHT--*/
//******************************************************************************
//  MSP430F20x2/3 Demo - SPI full-Duplex 3-wire Master
//
//  Description: SPI Master communicates full-duplex with SPI Slave using
//  3-wire mode. The level on P1.4 is TX'ed and RX'ed to P1.0.
//  Master will pulse slave reset for synch start.
//  ACLK = n/a, MCLK = SMCLK = Default DCO
//
//                Slave                      Master
//               MSP430F20x2/3              MSP430F20x2/3
//             -----------------          -----------------
//            |              XIN|-    /|\|              XIN|-
//            |                 |      | |                 |
//            |             XOUT|-     --|RST          XOUT|-
//            |                 | /|\    |                 |
//            |          RST/NMI|--+<----|P1.2             |
//      LED <-|P1.0             |        |             P1.4|<-
//          ->|P1.4             |        |             P1.0|-> LED
//            |         SDI/P1.7|<-------|P1.6/SDO         |
//            |         SDO/P1.6|------->|P1.7/SDI         |
//            |        SCLK/P1.5|<-------|P1.5/SCLK        |
//
//  M. Buccini / L. Westlund
//  Texas Instruments Inc.
//  October 2005
//  Built with CCE Version: 3.2.0 and IAR Embedded Workbench Version: 3.40A
//******************************************************************************

#include <msp430.h>
#include <ADS1220.h>
/* Function declarations */
void Init_StartUp(void);
void SPIinit(void);
/* Global variable */
int dflag = 0;
static volatile unsigned int ChA2results = 0x00;
int main(void)
{
  volatile unsigned int i;

  WDTCTL = WDTPW + WDTHOLD;             // Stop watchdog timer


  USICTL0 |= USISWRST; //USI released for operation
  USICTL1 &= ~USII2C + USIIE; //switch USI to SPI-Mode
  USICTL0 |= USIMST; //set to SPI-Master-Mode
  USICTL0 |= USIPE6 + USIPE5 + USIPE7; //SDO-Port enabled; Pin8
  USICTL0 |= USIOE; //activate output
  USICTL0 &= ~USISWRST;
  USICKCTL = USISSEL_2;

  void Init_StartUp(void);                 // Initialize device
  void ADS1220Init(void);                    // Initializes the SPI port pins as well as control
   void ADS1220Config(void);                // Set base configuration for ADS1x20 device
   ADS1220SetChannel(ADS1220_MUX_0_1);
   ADS1220SetGain(ADS1220_GAIN_32);
   set_MODE(ADS1220_MODE_TURBO);
   set_CM(ADS1220_CC);
   set_VREF(ADS1220_VREF_INT);
   //ADS1220SetDataRate(ADS1220_DR_2000);
   set_DR(110);


    while(1)
     {
         /* Add specifc command for reading and writing ADS1220 here */
         /* dFlag is set in the interrupt service routine when DRDY triggers end
            of conversion */
         if (dflag)                      /* check if new data is available */
         {
             ChA2results = ADS1220ReadData();  /* get the data from the ADS1220 */
             dflag=0;
         }
         /* other routines could be added here, such as change the mux setting */
     }  /* end of while(1) */




 // __bis_SR_register(LPM0_bits + GIE);   // Enter LPM0 w/ interrupt
}




Best regards,

Jonathan

  • Hi Jonathan,

    First nothing will happen if the code doesn't build.  So we need to determine what symbol is showing as 'undefined' in the build process.  The symbol name should show up in the console build window, or as an error.  Sometimes issuing a Project->Clean will help clear out old data for the Project->Build to complete.

    Some potential issues I see is there are prototypes declared that do not exist such as:

    • void Init_StartUp(void); (this prototype is declared twice)

    • void SPIinit(void);

    There are other issues with prototype declarations that already exist in the ADS1220.h file, so they should not be redeclared a second time:

    • void ADS1220Init(void);                    // Initializes the SPI port pins as well as control
    • void ADS1220Config(void);                // Set base configuration for ADS1x20 device

    The ADS1220 Init and Config routines are based on a different MSP430 so care must be taken to define the pins properly in the ADS1220.h file.  It is most likely that there are symbol definitions missing for the ports that differ between MSP430 devices.  This would be at the top of the ADS1220.h file:

    /* Definition of GPIO Port Bits Used for Communication */
    /* P1.2 */
    #define ADS1220_CS 0x04
    /* P3.3 */
    #define ADS1220_DIN 0x08
    /* P3.4 */
    #define ADS1220_DOUT 0x10
    /* P2.6 */
    #define ADS1220_DRDY 0x40
    /* P2.7 */
    #define ADS1220_SCLK 0x80

    And the definitions in the ADS1220Init() function.  These definition/declarations need to match the MSP430 device being used.  In the end, this has nothing actually to do with the ADS1220 device itself but with setup and control of the MSP430.  Unfortunately example code cannot cover all possibilities of microcontrollers in use and requires further interaction and setup by the user.

    Best regards,

    Bob B

  • Hi Bob,

    We need further assistance. 

    Here is our customer issue. 

    "I tried to change pin config but didn#t succeded further so I have changed to the 5529 launch pad which is family with 5528 which is mentioned in the example but when I dumped the code in it I was not able to get anything out of it. Can you assist me with that?

    Best regards,

    Jonathan

  • Hi Jonathan,

    I fear that a lack of understanding of how the compiler and code projects come together is what is truly the issue here.  The example code was written many years ago before the 5529 LaunchPad was released.  Most likely the project files as well as the compiler used are much different.

    What is not clear is what is meant by "I was not able to get anything out of it".  There is no indication if the peripherals were set up correctly.  This requires some form of verification outside of the code by using an oscilloscope or logic analyzer to verify the communication.

    I could review the code if it were sent to me to see if there was something obvious.  However it would be much better for me to see communication with respect to the scope shots.  It would also be helpful to see the schematic and how the ADS1220 is connected to the LaunchPad.  Usually the communication issues relate to phase of the data transition relative to the SCLK edge, or CS not being held low throughout the entire communication transaction.  If a multi-byte communication takes place and CS toggles between bytes then the communication cancels and resets the SPI bus.  Normally CS would be controlled by a GPIO.  What we don't know is how all of this is actually connected and if the correct peripherals and pins of the LaunchPad are being used.

    I would suggest the customer review the material in TI Precision Labs on SPI communication.

    Best regards,

    Bob B

  • Hi Bob,

    Thank you so much for your support. Our customer had  a response and here it is. 

    Thank you for the update. I have read the answer by Bob, but is it possible to get another example from Texas experts about setting up ADS1220. The example SBAC227 is poor in regards of detailed application of commands(sorry to say that). What I meant was to was that there is no mention on how and where to set ADS channels, gain, Dr . All it said was " /* Add specifc command for reading and writing ADS1220 here */
    /* dFlag is set in the interrupt service routine when DRDY triggers end
    of conversion */
    if (dflag) /* check if new data is available */
    {
    tData = ADS1220ReadData(); /* get the data from the ADS1220 */
    dFlag=0;
    }
    /* other routines could be added here, such as change the mux setting */"

    It would be nice to give example with implementing one of ADS1220 channel in this code.

    In meantime I have tried to work with data sheet and came up with following code:( I have oscillopscope for monitoring SPI bus and I could initialize it

    6746.code.txt
    //
    //                   MSP430F5529
    //                 -----------------
    //            /|\ |             P2.0|-> Slave Chip Select (GPIO)
    //             |  |                 |
    //             ---|RST          P1.5|-> Slave Reset (GPIO)
    //                |                 |
    //                |             P3.3|-> Data Out (UCA0SIMO)
    //                |                 |
    //       Button ->|P1.1         P3.4|<- Data In (UCA0SOMI)
    //                |                 |
    //                |             P2.7|-> Serial Clock Out (UCA0CLK)
    
    
    
    #include <msp430f5529.h>
    #include "ADS1220.h"
    #include <stdint.h>
    #include <stdbool.h>
    
    #define SLAVE_CS_OUT    P2OUT
    #define SLAVE_CS_DIR    P2DIR
    #define SLAVE_CS_PIN    BIT0
    
    /**
     * main.c
     */
     unsigned char Result = 0;
    static volatile unsigned int ChA0results = 0x00;
    int main(void)
    {
    	WDTCTL = WDTPW | WDTHOLD;	// stop watchdog timer
    	P1DIR |= BIT2;
    
    	UCA0CTL1 |= UCSWRST;                      // **Put state machine in reset**
    	UCA0CTL0 |= UCMST+UCSYNC +UCMSB;    // 3-pin, 8-bit SPI master
    	                                            // Clock polarity high, MSB
    	UCA0CTL1 |= UCSSEL_2;                       // SMCLK  16 mhz = SCLK of SPI
    
    	UCA0BR0 = 0x02;                           // /2
    	UCA0BR1 = 0;                              //
    	UCA0MCTL = 0;                             // No modulation
    	UCA0CTL1 &= ~UCSWRST;                     // **Initialize USCI state machine**
    
    
    	ADS1220Init();
    	ADS1220Config();
    	//ADS1220SendStartCommand;
    	char input[] = {0x12};
    	char output[] = {0x00};
    	// write reg
    	ADS1220WriteRegister(0x00, 1, input);
    	 //read back
    	ADS1220ReadRegister(0, 1, output);
    
    	//set_VREF(ADS1220_VREF_INT);
    	//set_MUX(ADS1220_MUX_0_1);
       // set_GAIN(ADS1220_GAIN_128);
    	ADS1220SetChannel(ADS1220_MUX_0_1);
    	ADS1220SetChannel(ADS1220_MUX_2_3);
    	ADS1220SetVoltageReference(ADS1220_VREF_INT);
    
    	ADS1220WriteRegister(0x01, 0x01, 0xD4);
    	ADS1220AssertCS(1);
    	
    	while(1)
    	{
    	    UCA0RXBUF = ADS1220ReadData();
    	    Result = UCA0RXBUF;
    	    //ser_output(Result);
    	}
    
    }
    

    please note that the code is just for checking if ads has started sampling or not

    Best regards,

    Jonathan

  • Hi Jonathan,

    Example code is a series of hierarchy with very low-level code and higher level code.  What is difficult with any example code is the hardware abstraction in the low-level code layer.  The ADS1220 was actually one of the first example code releases and we have made some improvements with the example code since.  So I do agree with the customer that there is some information that is not clear in the current code release.  I will endeavor to update this code, but this will not happen anytime soon.  That said, the hardware abstraction layer (HAL) relates to the hardware low-level code and is extremely hardware dependent based on the microprocessor being used.  That is why there are comments relating to 'adding your code here' and you will see things similar to this in the updated examples as well.

    Also, it is difficult to know and anticipate what the end user wants to do.  So what the majority of customers ask for is a header file for the ADC and the high-level functions using the header file data to communicate to the device.

    What I would suggest first is to write a pseudo-code description of what the customer wants to accomplish.  This would be similar to what is shown in the datasheet in section 9.1.6.

    Next, determine how to transfer the pseudo-code to 'C' code.  This requires some understanding on the low-level functions of the micro as well as the higher functions of the ADS1220.

    The most basic method changing the ADS1220 configuration is through register writes which uses a pointer to a memory space.  The example code also breaks down the functionality to do specific tasks such as setting the input mux channel (ADS1220SetChannel) or setting the PGA gain (ADS1220SetGain), however these specific tasks may overwrite previous settings if you are not careful.  So it is generally recommended to use the write register setting with the desired functionality as opposed to the 'Set' configurations. 

    The process would be to set the base configuration first and then once in the 'while' loop make changes as needed.  These changes may include changing the mux channel.  As an additional example you would do the following commands:

    uint8_t data[4] = {0,0,0,0}; // up to four registers can be written via register write

    data[0] = ADS1220_DR_1000 | ADS1220_MODE_TURBO |  ADS1220_CC; // first data position to be written to the ADS1220

    ADS1220WriteRegister(ADS1220_1_REGISTER, 0x01, &data); // write Register 1, one register with the contents pointed to by data

    Instead of "ADS1220WriteRegister(0x01, 0x01, 0xD4);"

    Before the 'while' loop you need to send the START/SYNC command ("ADS1220SendStartCommand") to actually start taking conversions otherwise the ADS1220 will be idle in the low-power state.  In the current loop as presented there is a command to "ADS1220ReadData()" which returns the conversion data which is then written to the RX buffer which makes no sense.  For this function you need to declare the "Result" as a 32-bit integer and store the value returned from the conversion data read to the variable:

    int32_t Result;

    Result = ADS1220ReadData();

    However, you need to know when the conversion has completed (assuming the START/SYNC command was issued) and this can be done by monitoring DRDY, DOUT/DRDY or using a timer.  I don't see any of these methods being used, but instead just repeated function commands to read the data.

    Best regards, 

    Bob B