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

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

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);

// Send RESET command
SPI.transfer(B00000110);
delayMicroseconds(100); // Guard time

// Set up configuration registers
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

// Read back configuration registers as a sanity check
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);
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
SPI.transfer(B00001000); // Start first conversion (single shot)
}

void loop()
{
// Nothing to do
}

{
SPI.transfer(B00010000); // Send RDATA command
delayMicroseconds(50); // Guard time
dmsb=SPI.transfer(0);
dlsb=SPI.transfer(0);

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

SPI.transfer(B00001000); // Start next conversion (single shot)
}

```

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,