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.

ADS1120 measured results is 4x smaller then expected

Other Parts Discussed in Thread: ADS1120, DAC8552

I'm testing ADS1120 and came into the following situation: measured results is 4x smaller then expected. Here is my test setup:


Channel 1 (Vout A) of DAC8552 is used as voltage source which is directly connected to ADS1120 channel 1 (Ain 0). They share the same external reference +2.5V. ADS1120 register setup is the following:

  SPI.transfer(B01000011); // Write four bytes starting at configuration register 00h
  SPI.transfer(B10000001); // Register 00h: AINp=AIN0, AINn=AVss, Gain=1, PGA disabled and bypassed
  SPI.transfer(B00000000); // Register 01h: 20SPS, 256KHz modulator clock, Single shot, disable temp sensor, Current sources off
  SPI.transfer(B01100001); // Register 02h: External Vref, 50Hz rejection, PSW off, IDAC not used
  SPI.transfer(B11111100); // Register 03h: IDAC1 not used, IDAC2 not used, dedicated DRDY

For example if I send 0x8000 to DAC8552 I got 0x2012 on ADS1120 (small error of LSB=12 is reasonable since everything is testing on breadboard but MSB value is 4x smaller).

  • Hi Denis,

    I can at least explain where a difference of a factor of 2 would be coming from. DAC8552 and ADS1120 use different coding schemes and have different full scale ranges.

    DAC8552 uses a straight binary coding scheme as shown in the datasheet on p.13, equation 1.
    VOUT = VREF x Code/2^16
    The full scale range ranges from 0V to VREF. Which means the LSB size is LSB=VREF/2^16

    ADS1120 instead uses a twos-complement coding scheme and the differential full scale range ranges from -VREF to +VREF (assuming Gain=1).
    The LSB size is then calculated as LSB = 2 x VREF /2^16.

    The DAC8552 will output a voltage of VOUT = VREF x 32768/2^16=1.25V
    The ADS1120 should then in theory generate a code of 1.25V/ (2 x VREF/2^16) = 16384 (=4000h).

    I need to think about where we could lose another factor of 2...

    Regards,
  • Yes, I'm aware that I'm actually losing one bit of resolution and that on ADC side I'll get 15-bit. That's acceptable for my application. With 0x8000 sent to DAC8552 I'm getting 1.25V on output, but ADS1120 "see" this as ~ 0x2000.
  • Hi Denis,

    what I wanted to explain is that the hex output code will differ by a factor of 2 between DAC8552 and ADS1120 if everything is correct.
    An input voltage of 1.25V on the ADS1120 input should yield an output code of 0x4000.
    That means we still need to find out where you are losing a factor of 2.

    What output code are you getting when you use the internal 2.048V REF of ADS1120?
    This should yield a code of 4E20.

    I just noticed another thing which you may want to change, but it will not solve your issue.
    If you want to disable the IDACs you should set IDAC[2:0]=000 and I1MUX[2:0]=I2MUX[2:0]=000.
    What I wanted to say with 'not used' in the register settings of the datasheet is, that those bit settings should not be used. Maybe I should change that to 'reserved' or something similar. I apologize for confusing you with it.

    You may want to run an offset calibration after power up of the ADS1120. This should remove part of the error (12 codes) that you see. You can measure the offset of the ADS1120 by setting MUX[3:0]=1110. You can then read the result (average multiple readings) with your MCU and store the value as the offset correction value in your MCU.

    Regards,
  • Joachim Wurker said:
    Hi Denis,

    what I wanted to explain is that the hex output code will differ by a factor of 2 between DAC8552 and ADS1120 if everything is correct.
    An input voltage of 1.25V on the ADS1120 input should yield an output code of 0x4000.
    That means we still need to find out where you are losing a factor of 2.

    What output code are you getting when you use the internal 2.048V REF of ADS1120?
    This should yield a code of 4E20.

    Thanks Joachim once again for your assistance. Yes, using the internal reference for 1.25V we have 1.25 / 2.048 = 0,610351563 * 2^15 = 20000 = 4E20h. I tried that and guest what, again I got again too small result: MSB is 27h instead of 4Eh. I also tried with to do the same applying input voltage to the channel 1, 2, 3 but  result is the same (as should be). Also I applied external voltage to AIN0/AIN3 (register 02h code: 1010 0001) and got MSB=20h instead of 40h.

    Joachim Wurker said:
    I just noticed another thing which you may want to change, but it will not solve your issue.
    If you want to disable the IDACs you should set IDAC[2:0]=000 and I1MUX[2:0]=I2MUX[2:0]=000.
    What I wanted to say with 'not used' in the register settings of the datasheet is, that those bit settings should not be used. Maybe I should change that to 'reserved' or something similar. I apologize for confusing you with it.

    That was my first choice but that didn't make any difference. I'll continue testing with register 03h code 0000 0000.

    Joachim Wurker said:
    You may want to run an offset calibration after power up of the ADS1120. This should remove part of the error (12 codes) that you see. You can measure the offset of the ADS1120 by setting MUX[3:0]=1110. You can then read the result (average multiple readings) with your MCU and store the value as the offset correction value in your MCU.

    Thanks for reminder. That is something that I was planned as a next step when first issue is resolved.

  • Hi Denis,

    to me it seems like your data is simply right shifted by one 1bit.
    Did you check if your communication is correct? Could you send a scope picture showing /CS, SCLK, DIN, DOUT?
    Or might there be something wrong in your code how you read the data from the device?

    Regards,

  • Hi Joachim,

    the error was (of course :) on my side. I'd like to document that here if someone else oversight the thing. For sake of simplicity in this moment I'm using Arduino for testing and made a mistake with selecting SPI mode. While DAC8552 require MODE0 it's not possible to do something wrong by selecting SPI_MODE0 (defined constant) or 0x00 value. With other SPI mode the situation is quite different since SPI_MODE1 is not  1 but 0x04 :)

    Here is the code if someone in the future need a quick check of both DAC8552 and ADS1120:

    #include "SPI.h" // necessary library
    int s_dac=10; // using digital pin 10 for DAC slave select
    int s_adc=4; // using digital pin 4 for ADC slave select
    int eoc=2; // using digital pin 2 for EOC (End of Conversion)
    byte reg00=0x00;
    byte reg01=0x00;
    byte reg02=0x00;
    byte reg03=0x00;
    byte dmsb;
    byte dlsb;
    
    void setup()
    {
    
      // DAC8552 setup
    
      pinMode(s_dac, OUTPUT); // we use this for DAC select pin 
      digitalWrite(s_dac, HIGH); // force DAC to disabled 
    
      SPI.begin(); // wake up the SPI bus.
      SPI.setBitOrder(MSBFIRST);
      SPI.setDataMode(0x00);  //CPOL=0, CPHA=0
      digitalWrite(s_dac, LOW);
      SPI.transfer(B00000000); // Write to Data Buffer A
      SPI.transfer(0x80); // send first byte
      SPI.transfer(0x00);  // send second byte  
      digitalWrite(s_dac, HIGH); // Deselect DAC
      digitalWrite(s_dac, LOW);
      SPI.transfer(B00110100); // Write to Data Buffer B and activate both channel simultaneously
      SPI.transfer(0x80); // send first byte
      SPI.transfer(0x00);  // send second byte  
      digitalWrite(s_dac, HIGH); // Deselect DAC 
    
      // ADS1120 setup
    
      pinMode(s_adc, OUTPUT); // we use this for ADC select pin
      pinMode(eoc, INPUT); // we use this for EOC pin
      SPI.begin(); // wake up the SPI bus.
    
      SPI.setBitOrder(MSBFIRST);
      SPI.setDataMode(SPI_MODE1);  //CPOL=0, CPHA=1 DO NOT USE HERE VALUE 1 (SPI_MODE1=0x04)!
    
      // Initialize serial communication  
      Serial.begin(9600);
      // wait until the serial stream is not open (Leonardo only)
      while (!Serial);
      Serial.println("Serial com ready");
    
      // Send RESET command
      digitalWrite(s_adc, LOW);
      SPI.transfer(B00000110);
      digitalWrite(s_adc, HIGH);
      delayMicroseconds(100); // Guard time
    
      // Set up configuration registers
      digitalWrite(s_adc, LOW);
      SPI.transfer(B01000011); // Write four bytes starting at configuration register 00h
    
      SPI.transfer(B10010001); // Register 00h: AINp=AIN1, AINn=AVss, Gain=1, PGA disabled and bypassed
      SPI.transfer(B00000000); // Register 01h: 20SPS, 256KHz modulator clock, Single shot, disable temp sensor, Current sources off
      SPI.transfer(B10100001); // Register 02h: External Vef on AIN0/AIN3, 50Hz rejection, PSW off, IDAC not used 
      SPI.transfer(B00000000); // Register 03h: IDAC1 disabled, IDAC2 disabled, dedicated DRDY 
      digitalWrite(s_adc, HIGH);
    
      // Read back configuration registers as a sanity check
      digitalWrite(s_adc, LOW);
      SPI.transfer(B00100011); // Read four bytes starting at configuration register 00h
      reg00=SPI.transfer(0); 
      reg01=SPI.transfer(0);
      reg02=SPI.transfer(0);
      reg03=SPI.transfer(0);
      digitalWrite(s_adc, HIGH);
      Serial.print("Reg00: ");
      Serial.println(reg00, HEX); // Display Reg00
      Serial.print("Reg01: ");  
      Serial.println(reg01, HEX); // Display Reg01
      Serial.print("Reg02: "); 
      Serial.println(reg02, HEX); // Display Reg02
      Serial.print("Reg03: "); 
      Serial.println(reg03, HEX); // Display Reg03
    
      // Enable interrupt and start first conversion
      attachInterrupt(0, adc_read, FALLING); 
      digitalWrite(s_adc, LOW);
      SPI.transfer(B00001000); // Start first conversion (single shot)
      digitalWrite(s_adc, HIGH);
    }
    
    void loop()
    {
      // Nothing to do
    }
    
    void adc_read()
    {
      // Read conversion data
      digitalWrite(s_adc, LOW);
      SPI.transfer(B00010000); // Send RDATA command
      delayMicroseconds(50); // Guard time
      dmsb=SPI.transfer(0);
      dlsb=SPI.transfer(0);
      digitalWrite(s_adc, HIGH);
    
      // Display conversion data on console
      Serial.print("MSB=");
      Serial.println(dmsb, HEX);
      Serial.print("LSB=");
      Serial.println(dlsb, HEX); 
      delay(10000); // Delay between two conversation
    
      digitalWrite(s_adc, LOW);
      SPI.transfer(B00001000); // Start next conversion (single shot)
      digitalWrite(s_adc, HIGH); 
    }
    
    
    
    
    
    

    Thanks again and I'm terribly sorry for bothering you with this issue.

  • Hi Denis,

    I am glad we could find the problem. Thanks a lot for sharing your finding with the community!

    Regards,