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.

Connecting an MSP430 to ADS1248 via SPI

Other Parts Discussed in Thread: ADS1248, MSP430F2132, ADS1241, ADS1220, ADS1247

Hello,

i am trying to program my MSP430 with ADS1248 via SPI.

Can someone post me some example codes for the IAR compiler?

 Best regards,

Diego V.

  • Diego,

    Unfortunately we do not have a direct example for you to run on IAR at this time.  However I should be able to help you get things going.  What MSP430 are you using?  Are you mostly concerned about setting up the SPI or reading and writing the device?

    Best regards,

    Bob B

  • Bob,

    Thanks for your answer.I am using a MSP430F2132. 

    In a previous project achieved successfully communicate with an AD7793 (Analog Device) via SPI. Now I want to change the ADC by the type of application, and chose the ADS1248. I can use the application note: sbaa121 "Interfacing the ADS1241 to MSP430 Processors"?

    Best regards,

    Diego V.

  • Diego,

    The code example you mentioned should get you started.  Obviously the header definition will be different as the register set is different.  Also, some of the commands/functions might not be compatible with IAR as the project was written for GCC, but it should be mostly ok.  Let me know if you have specific questions about getting things to work and I'll be glad to help you through them.

    Best regards,

    Bob B

  • Bob,

    I'm trying to read the temperature of a three-wire RTD, using the circuit of Figure 2 (sbaa180.pdf).
    They do not work the excitation current sources. The control registers write the following values:

    MUX0 = 0x01
    VBIAS = 0x00
    MUX1 = 0x20
    SYS0 = 0x60 (PGA = 64)

    IDAC0 = 0x06 (Idac = 1mA)
    IDAC1 = 0x01 (AIN0->IDAC1 , AIN1->IDAC2)

    Using Rbias = 1K would have to measure a Vref = 2V but I measure 0V.

    The result of the conversion is = 8388607 (use RDATA command) -> Rtd = 31.25 ohms????

  • Diego,

    It looks like your settings are correct assuming you are connected to REF0 for your reference.  Can you send me scope shots of your communication just to verify your communication is correct?  Have you read back your register values after setting them to make sure they are what you expect?  The other thing is to verify that you are actually getting good connections to the ADS1248.  Can you send me a picture of your setup?

    Something else seems to be wrong.  You should read different values (like full-scale) if you don't have a reference voltage.  I would verify my communication to the device with an oscilloscope.  Your data should be stable on the falling edge of SCLK.

    Best regards,

    Bob B

  • Bob,

    The reference is connected to REF0.
    These are the registers values ​​after the configuration (command RREG):

    MUX0 = 0x01
    VBIAS = 0x00
    MUX1 = 0x20
    SYS0 = 0x60
    OFC0 = 0x00
    OFC1 = 0x00
    OFC2 = 0x00
    FSC0 = 0x00
    FSC1 = 0x1A
    FSC2 = 0x40
    IDAC0 = 0x86
    IDAC1 = 0x01
    GPIOCFG = 0x00
    GPIODIR = 0x00
    GPIODAT = 0x00

    Best regards,

    Diego V.

  • Bob

    Attached circuit schematic.

    At all times Vref = 0V, I measure it with a tester.

    Best regards,

    Diego V.

  • Diego,

    For the analog portions to be active, START must be logic high.  Is START high?  Also, do you have any scope shots of the communications?

    Best regards,

    Bob B

  • Bob

    Yes, START is active. Unfortunately I haven't high-frequency oscilloscope.

    I find it strange that Vref = 0V. The current sources not seem to work.

    Best regards,

    Diego V.

  • Diego,

    I suspect you have communication issues.  Are you able to read the registers and verify the contents have been written as you would expect?  Can you send me a code snippet of how you are setting up the USCI peripheral?

    Best regards,

    Bob B

  • Bob,

    These are the registers values ​​after the configuration (command RREG):

    MUX0 = 0x01
    VBIAS = 0x00
    MUX1 = 0x20
    SYS0 = 0x60
    OFC0 = 0x00
    OFC1 = 0x00
    OFC2 = 0x00
    FSC0 = 0x80
    FSC1 = 0x1C
    FSC2 = 0x40
    IDAC0 = 0x86
    IDAC1 = 0x01
    GPIOCFG = 0x00
    GPIODIR = 0x00
    GPIODAT = 0x00

    Attached code used:

    4377.mainredADS1248.c
    /*============================================================================*
    * *
    * FICHERO....: main.c *
    * PROYECTO...: *
    * AUTORES....:  *
    * FECHA......:  *
    * VERSI�N:....  *
    * ESTADO.....: *
    * *
    * DESCRIPCION:  *
    * *
    *============================================================================*/
    
    
    /*----------------------------------------------------------------------------*
    * DEFINICI�N DE LAS CABECERAS A INCLUIR *
    *----------------------------------------------------------------------------*/
    
    #include "math.h"
    #include "stdbool.h"
    #include "SPIADS1248.h"
    #include "Medidas.h"
    #include "msp430x21x2.h"
    
    /*----------------------------------------------------------------------------*
    * C�DIGO DE LAS FUNCIONES GLOBALES DEL M�DULO *
    *----------------------------------------------------------------------------*/
    
    void Inicia (void);
    
    /*============================================================================*
    * Comienzo de la funci�n main() *
    * *
    * Programa principal, se encarga de inicializar todos los perif�ricos y del *
     * tratamiento de los datos capturados. es un bucle que se est� siempre *
     * ejecut�ndose y se corresponde con el proceso de menor prioridad. *
    *============================================================================*/
    
    
    int main(void)
    {
      //Variables locales de la funci�n
      float Rtd = 0; //Almacenna el resultado calculado de las medidas
      unsigned int i=0,j=0;
      unsigned long Code=0; //Valor de Lectura Instantaneo
      
      //C�digo de la funci�n
      Inicia(); //iniciar perifricos del uP
       
      ADS1248CargaInicial();
    
      
      
      //Bucle infinito del programa principal
      while(1) //Ejecutar siempre
      {
        
    
        Code = ADS1248ReadData();
        
        //Usando una PT100
        //Rtd = 2*Rref*Code/((2^23-1)*Gain)   Rref=1K  Gain=64
        Rtd = 3.725290742E-6*(float)(Code);  
        
            
        }
      
    }
    //Fin de la funci�n main()
    
    /*============================================================================*
    * Comienzo de la funci�n Inicia() *
    * *
    * Se encarga de inicializar los perif�ricos, los puertos de E/S y de *
    * arrancar las comunicaciones modbus. *
    *============================================================================*/
    
    void Inicia (void)
    {
      //Variables locales de la funci�n
      int i=0; //Variable auxiliar para recorrer las tablas
    
      //C�digo de la funci�n
      P1DIR|=1; //Se configuran los puertos de salida
                //P1.0 Led de Indicacion
                //P1.1 Boton de Reset para Ajustes por Defecto
      P1OUT&=(~BIT0); //Se apaga el Led
    
      
      WDTCTL = WDTPW + WDTHOLD;                 // Stop watchdog timer
    
      //Inicializaci�n de los relojes de forma segura, tal y como recomienda TI
      //Cuando Inicia el MCLK esta aliemntado con el DCO a aprox. 1.1Mhz
      __delay_cycles(250000); //Realim b    zamos una pausa aprox 150uS es el TURN ON del Regulador
    
      if (CALBC1_8MHZ ==0xFF || CALDCO_8MHZ == 0xFF)                                     
      {  
        while(1);                               // If calibration constants erased
        // do not load, trap CPU!!
      }   
      BCSCTL1 = CALBC1_8MHZ;                    // Set DCO to 8MHz
      DCOCTL = CALDCO_8MHZ;
        
    
     
    }
    //Fin de la funci�n Inicia()
    
    

    7127.SPIADS1248.c
    /*============================================================================*
    * *
    * FICHERO....: SPIAD1248.c *
    * PROYECTO...: Modulo Remoto de Entradas Analogicas*
    * AUTORES....: Diego Villarraza *
    * FECHA......: 14 de Julio de 2012 *
    * VERSI�N:.... 1.0 *
    * ESTADO.....: Inicio *
    * *
    * DESCRIPCION:Funciones para comunicarse via SPI con el AD ADS1248  *
    * *
    *============================================================================*/
    
    #include "msp430x21x2.h"
    #include "SPIADS1248.h"
    
    
    /*----------------------------------------------------------------------------*
    * DEFINICI�N DE VARIABLES GLOBALES DEL M�DULO *
    *----------------------------------------------------------------------------*/
    
    unsigned char regreadads[15]; //Tabla con los registros de control del AD
    unsigned char regwriteads[15]; //Tabla con los registros de control del AD
    
    
    /*----------------------------------------------------------------------------*
    * C�DIGO DE LAS FUNCIONES GLOBALES DEL M�DULO *
    *----------------------------------------------------------------------------*/
    
    
    
    void ADS1248AssertCS( int fAssert)
    {
       if (fAssert)
          P3OUT &= ~ADS1248_CS;
       else
          P3OUT |=  ADS1248_CS;
    }
    
    int ADS1248SPIInit(void)
    {
      //Configuramos el puerto 3 para utilizar las siguientes salidas
      //P3.3 SCLK -> Serial Clock Out (Salida)
      //P3.1 UCBOTXD -> Master Out (Salida)
      //P3.2 UCBORXD -> Master In (Entrada)
      P3SEL |= ADS1248_SCLK + ADS1248_DOUT_DRDY + ADS1248_DIN; // P3.1,2,3 USCI_B0 option select
      
      P3DIR |= ADS1248_CS; //P3.7 Como salida para manejar la habilitacion del AD 
      P1DIR |= ADS1248_RESET + ADS1248_START; //P1.5 (Salida) Reset del AD
                                              //P1.6 (Salida) Start el AD
                                              //P1.7 (Entrada) DRDY el AD
      
      
      //Definimos el registro de control: 8 bit, Modo Master, MSB se recibe primero, Modo Sincronico  
      UCB0CTL0 |= UCMST + UCMSB + UCSYNC;  
      //Definimos el segundo registro de control: Fuente de Reloj SMCLK 
      UCB0CTL1 |= UCSSEL_2;  // SMCLK
      //Pre-escalamos el Clk a SMCLK/2 = 8Mhz/2 
      UCB0BR0 = 0x02; // /2
      UCB0BR1 = 0;    //
      //UCB0MCTL = 0;  // No modulation  
      //Habilitamos para que funcione el Modulo de Comunicacion
      UCB0CTL1 &= ~UCSWRST; // **Initialize USCI state machine**  
     
        
      //Secuencia de Encendido
      
      ADS1248AssertCS(0);  
      P3OUT |= ADS1248_START; //Start High
      P3OUT |= ADS1248_RESET; //Reset High
      
      __delay_cycles(128000); //Pausa de 16ms -> Fosc*16ms=8Mhz*16ms = 128000 segun datasheet
                              
      ADS1248AssertCS(1);
      
      
      
      return 0;
            
    }
    
    
    int ADS1248CargaInicial(void)
    {
      
      int i;
      int resultado;
      
      
      //Iniciamos puertos del uC para comunicarse con el AD y configuramos el UART para utilizar SPI
      ADS1248SPIInit();
      
      //Realizamos un reset del AD
      ADS1248SendResetCommand();
        
      //Enviamos el comando SDATAC ya que por default el AD empieza con RDATAC
      ADS1248Stop();
      
      //Leemos todos los registros del AD para guardar los registros que nos se modifican y despues 
      //poder comparar todos los registros
      ADS1248ReadRegister();
      
      //Copiamos registro tabla de registros leidos a tabla de registros a escribir 
      for(i=0;i<15;i++)
        regwriteads[i] = regreadads[i];
      
      //Configuramos los primeros cuatro registros
      /* MUX0 = 00 Corriente de Burnout off
                000 AIN0 es positivo
                001 AIN1 es negativo
                = 0x01 */
      regwriteads[ADS1248_MUX0_REGISTER] = 0x01;
    
      /* VBIAS = 0x00 No se aplica Vbias */
      regwriteads[ADS1248_VBIAS_REGISTER] = 0x00;
    
      /* MUX1 = 0 Oscilador Interno
                01 Referencia interna siempre ON (necesario para usar IDAC)
                00 REF0 se utiliza una Rbias externa
                000 Operacion Normal
              = 0x20 */
     regwriteads[ADS1248_MUX1_REGISTER] = 0x20;
      
      
      /*SYS0 = 0 Siempre es 0
               110 Ganancia es 64
               0000 5SPS 
             = 0x60
      */
      regwriteads[ADS1248_SYS0_REGISTER] = 0x60;
      
      //Escribimos los primeros cuatro registros
      ADS1248WriteRegister(ADS1248_MUX0_REGISTER , 4);
      
      //Configuramos registro IDAC0 y IDAC1
      /*IDAC0 = 0000 siempre es 0
                0 DOUT//DRDY funcionamiento pin solo como datos de salida
                110 IDAC = 1ma 
              = 0x06*/
      regwriteads[ADS1248_IDAC0_REGISTER] = 0x06;  
      /*IDAC1 = 0000 La primer fuente de corriente en AIN0
                0001 La segunda fuente de corriente en AIN1
              = 0x01*/
      regwriteads[ADS1248_IDAC1_REGISTER] = 0x01;  
      //Escribimos registro
      ADS1248WriteRegister(ADS1248_IDAC0_REGISTER , 2);
      
      
      //Leemos registros para comprobar que la escritura fue exitosa
      ADS1248ReadRegister();
      
      //Comparamos registros
      resultado = 0;
      for(i=0;i<15;i++)
      {
        if (regwriteads[i] != regreadads[i])
          resultado = 1;
      }
      
      
        __delay_cycles(10000); //Pausa
      
      
      return resultado;
      
      
    }
    
    
    
    /*
    ******************************************************************************
    */
    
    /*Escribe los parametros en los registros de control*/
    int ADS1248WriteRegister(int StartAddress, int NumRegs)
    {
      int i;
      unsigned char dummy;
      unsigned char reg[15]; //Tabla que datos a escribir
      
      
      //Copia datos de tabla general a tabla a transmitir
      for (i=0;i<NumRegs;++i)
      {
        reg[i] = regwriteads[StartAddress + i];
      }
      
      
      ADS1248Stop(); //Detiene la recopilacion de datos
      
      // assert CS to start transfer
      ADS1248AssertCS(1); // CS goes low
       
      //Primer Comando: La direccion del primer registro a escribir
      while(!(IFG2 & UCB0TXIFG));
      UCB0TXBUF= ADS1248_CMD_WREG + StartAddress;
      
      //Segundo Comando: El numero de Registros a escribir
      while(!(IFG2 & UCB0RXIFG));
      dummy=UCB0RXBUF;
      while(!(IFG2 & UCB0TXIFG));
      UCB0TXBUF=NumRegs - 1;
      
      //Bytes de Datos: Datos de los registros a escribir
      while(!(IFG2 & UCB0RXIFG));
      dummy=UCB0RXBUF;
      for (i=0;i<NumRegs;++i)
      {
        while(!(IFG2 & UCB0TXIFG));
        UCB0TXBUF=reg[i];
        while(!(IFG2 & UCB0RXIFG));
        dummy=UCB0RXBUF;
      }
    
      __delay_cycles(1000); //Pausa
                              
      ADS1248AssertCS(0); // CS goes high
      
      return 0;
      
    
    }
    
    /*Lee los datos de los registros de control*/
    void ADS1248ReadRegister()
    {
      unsigned char dummy;
      unsigned char reg[15];
      int i;
      
      ADS1248Stop(); //Detiene la recopilacion de datos
      __delay_cycles(40); //Pausa
    
      // Reset SPI
      ADS1248AssertCS(0); // CS goes high
      __delay_cycles(10); //Pausa 
      ADS1248AssertCS(1); // CS goes low
    
      while(!(IFG2 & UCB0TXIFG));
      UCB0TXBUF=ADS1248_CMD_RREG;	// Command for register read
      while(!(IFG2 & UCB0RXIFG));
      dummy=UCB0RXBUF;
      
    
      while(!(IFG2 & UCB0TXIFG));
      UCB0TXBUF=0x0E;		// Command for number of registers to read
      while(!(IFG2 & UCB0RXIFG));
      dummy=UCB0RXBUF;
    
      for (i=0; i<15; ++i) 
      {
        UCB0TXBUF=0xff;
        while(!(IFG2 & UCB0RXIFG));
        reg[i]=UCB0RXBUF;           // Lee los datos de los registros
      }
    
      //Copia tabla leida a la tabla general
      for(i=0;i<15;i++)
        regreadads[i] = reg[i];
      
      ADS1248AssertCS(0); // CS goes high
      
    }
    
    //Lee u
    long ADS1248ReadData()
    {
      char dummy;
      unsigned int data1, data2, data3;   
      long dato;
      
      // assert CS to start transfer
      ADS1248AssertCS(1); // CS goes low
    
      //Espero por RDY sea bajo
      while(P1IN & ADS1248_DRDY);
      
      //Se envia comando RDATA
      while(!(IFG2 & UCB0TXIFG));
      UCB0TXBUF=ADS1248_CMD_RDATA;
      while(!(IFG2 & UCB0RXIFG));
      dummy=UCB0RXBUF;
      __delay_cycles(20); //Pausa 
        
      //Lee datos como palabra de 24 bits.
      UCB0TXBUF=0xff;
      while(!(IFG2 & UCB0RXIFG));
      data1=UCB0RXBUF; //MSB
    
      //Lee datos como palabra de 24 bits.
      UCB0TXBUF=0xff;
      while(!(IFG2 & UCB0RXIFG));
      data2=UCB0RXBUF; //Mid-Byte
    
      //Lee datos como palabra de 24 bits.
      UCB0TXBUF=0xff;
      while(!(IFG2 & UCB0RXIFG));
      data3=UCB0RXBUF; //LSB
      
      dato = ((long)data1<<16)+((long)data2<<8)+((long)data3);
      
      ADS1248AssertCS(0); // CS goes high  
      
      return dato;
      
    }
    
    int ADS1248SendResetCommand(void)
    {
    
      char dummy;
      
      // assert CS to start transfer
       ADS1248AssertCS(1); // CS goes low
    
       // send the command byte
        while(!(IFG2 & UCB0TXIFG));
        UCB0TXBUF= ADS1248_CMD_RESET;
        while(!(IFG2 & UCB0RXIFG));
        dummy=UCB0RXBUF;
    
       // de-assert CS
       ADS1248AssertCS(0); // CS goes high
       
       __delay_cycles(48000); //Pausa de 0.6ms -> Fosc*0.6ms=8Mhz*0.6ms = 128000 segun datasheet
       
       return 0;
    }
    
    /* stop collecting data */
    void ADS1248Stop(void)
    {
          unsigned char dummy;
          
          // Reset SPI
          ADS1248AssertCS(0); // CS goes high
          __delay_cycles(30); //Pausa 
          ADS1248AssertCS(1); // CS goes low
          
          // Command to stop taking continous readings
          
          //Analizar espera que DRDY sea bajo
          //Espero por RDY sea bajo
          while(P1IN & ADS1248_DRDY);
          
          while(!(IFG2 & UCB0TXIFG));
                  UCB0TXBUF=ADS1248_CMD_SDATAC;
          while(!(IFG2 & UCB0RXIFG));
                  dummy=UCB0RXBUF;
          __delay_cycles(20); //Pausa 
     
          ADS1248AssertCS(0); // CS goes high
          
    }
    
    

    0830.SPIADS1248.h

    To test, We replaced the AD by an equal. In this case the readings are different values. Before reading only = 8388607.

    Best regards,

    Diego V.

  • Diego,

    I can't find anything obviously wrong with your code.  I did notice that you do not sign extend your data when reading the result.  You need to sign extend from 24 bit value to 32 bit as the data result is a signed value.

    I would still try to verify the communication with an oscilloscope if possible.  I would also verify all my analog connections, especially ground.  Can you send me a picture of your setup?

    Best regards,

    Bob B

     

     

  • Bob,

    Ok, I will try to send them.
    When should the reference voltage appear?. After writing the control registers, or when executo RDATA command.

    Best regards,

    Diego V.

  • Diego,

    You should see the reference voltage as soon as the internal reference and IDACs are turned on.  This happens as soon as you complete the register write.

    Best regards,

    Bob B

  • Bob,

    Finally, I found the problem and now works fine. VREFCOM pin should be grounded.

    What is the maximum value of the PGA gain that I can use? When Idac = 1mA and Rbias = 1K. Using a RTD in the range of -50 ° C to 50 ° C. Rcomp unused.

    Best regards,

    Diego V.

  • Diego,

    Oh, yes, VREFCOM should be grounded and there should be a cap between VREFOUT and VREFCOM.  Sorry I missed that before.  As far as setting the bias point and determining maximum gain, my colleague has put together information regarding the calculations.  It can be found here:

    http://e2e.ti.com/support/data_converters/precision_data_converters/w/design_notes/1370.input-voltage-range-requirements-for-the-ads1248-and-ads1148-families.aspx

    Best regards,

    Bob B

  • Bob,

    Finally everything works great.
    Given that the circuit will be used in an industrial environment. I have to try to make it suitable for this.
    What type of power supply isolated is recommended to have an has a Vin = 24Vdc and Vout = 5v and 3.3 V?
    How can isolate the sensor inputs?
    Does the SPI communication between UC and the AD should be isolated?

    Best regards,

    Diego

  • Diego,

    Glad to hear you are making progress.  For the supply, it is best to have a linear, well regulated, low noise supply.  You will need to determine your current needs to find a regulator that fits your requirement.  The place to start is:

    http://www.ti.com/lsds/ti/analog/powermanagement/power_portal.page

    Sensor connecttions to the analog inputs can be as simple as a filtering circuit using R-L-Cs or something much more elaborate. This will depend on what sensors are being connected, and whether true isolation is necessary or just noise filtering.  Sometimes Schottky or TVS diodes are used as overvoltage protection.

    Digital isolation is usually not necessary.  However, if the digital section is extremely noisy isolation can be used.  You can do a search for isolators similar to the power products search.  One part that may work is the ISO7240.

    Best regards,

    Bob B

  • Bob

    Now I need to change the type of temperature sensor. I will use a thermistor 10K@25ºC.
    What kind of topology is recommended to use? I'm testing with radiometric topology. Two-Wire RTD Application (figure 1 sbaa180.pdf).
    Because I want to measure in the range of -50 ° C to 50 ° C then resistance range 670k to 3.6 K. If we use IDAC = 100uA -> Vin = 100uA * 670k =67V. To avoid this I put in parallel 10K resistor.
    I use a Rbias = 20K. (Vref = 100ua*20K = 2V) 

    Best regards,

    Diego V.

  • Diego,

    The circuit you are describing should work.  I don't know of any specific recommendation as there are a number of variables, including self-heating of the thermistor.  There are generally two main considerations.  One is the amount of current to reduce self-heating effects (and you might want to consider 50uA instead of 100uA.)  The other consideration is linearization for the desired temperature range.  The parallel resistor should help with this, but there are a variety of methods that can be used for this purpose.

    Best regards,

    Bob B

  • Bob,

    We designed and constructed the circuit to measure temperature with thermistors, using Idac a Rbias and a resistor in parallel with each sensor.
    In the lab, everything works perfectly, when we place the sensors in an industrial environment unfortunately did not work well.
    What lowpass filter circuit recommended for entries AIN0 ... AIN7?.
    What data rate is better?
      We note that there is too much interference between channels.
    Please any suggestion is accepted we can not find a solution and we need it urgently.

    Best regards,

    Diego

  • Diego,

    Can you send me your schematic and board layout?  If you don't want to post it publicly you can start a conversation with me by clicking on my name, and then click on start a conversation on the upper right corner of the page.

    Best regards,

    Bob B

  • Hi Diego,

    Could you send me schematic and code you successfully communicate MSP430 with an AD7793 (Analog Device) via SPI?

    I'm try to measure analog signal 4 - 20mA via AD7794 and MSP430.

    Thanks and best regards,

  • Hi Thuy,

    our forum is used to help customers with questions regarding devices from Texas Instruments. If you have questions regarding devices from Analog Devices please contact them through a different channel. I am hoping for your understanding.

    However you might want to have a look at our new ADS1220 which would be an ideal solution to implement a 4-20mA measurement.

    Other alternatives to the devices you mentioned would be ADS1247 and ADS1248.

    Regards,