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.

ADS1212 Getting an accurate and precise digital readout

I am having problems getting a correct value from the Data Output Register (DOR). I am using an ADS1212 in slave mode with an Arduino as the master and I've mimicked the  circuit configuration in Figure 31 on page 32 of the data sheet  (2MHz clock).

I am able to communicate with the chip, which I verified by writing to and reading from the command register. However, I am a bit stumped on how to process the data read the DOR. I am receiving values that are inconsistant even when I bring the analog input to GND. For example, I may receive a value of 0 on one read but then -263,000 and then - 34,000. I have tried to tie AinP (Pin 1) to GND and AinN (Pin 2) to GND, AinP to 5V, 3.3V, 2.5V...but all with the same result. 

Here are the specific questions I have:

- Is my reading of the DOR and conversion to 2's complement correct? 

- How does the effective resolution effect the output? For example, if my effective resolution with be 20 bits, do I drop the first 4 bits of the number, or should I expect to receive 0 on those bits?

- Is each bit of resolution tied back to REFin or AVdd? So if I have 20 bits of resolution, 1,048,576 places, will each bit be 5V/1,048,576?

Maybe I am missing something really basic or fried the chip at some point, not sure, but I'd appreciate any help. My code is below. FYI, I am using the SPI library from Arduino.

///// Code /////

#include <SPI.h>

//SPI
const byte PIN_SCK = 13; //clock
const byte PIN_MISO = 12; //master in slave out
const byte PIN_MOSI = 11; //master out slave in
const byte PIN_SS = 10; //slave select
const byte DRDY = 9; //data ready

byte Insr;
byte DorOne;
byte DorTwo;
byte DorThree;
byte CmrOne;
byte CmrTwo;
byte CmrThree;
byte CmrFour;
byte OcrOne;
byte OcrTwo;
byte OcrThree;
byte FcrOne;
byte FcrTwo;
byte FcrThree;

long analogOutput;
long analogOutputTwos;

void setup(){
Serial.begin(9600);

SPI.begin();
SPI.setBitOrder(MSBFIRST);
SPI.setDataMode(SPI_MODE1);
SPI.setClockDivider(SPI_CLOCK_DIV128);

pinMode(SS,OUTPUT);
pinMode(DRDY,INPUT);

digitalWrite(PIN_SS,HIGH);

delay(1000);

while(digitalRead(DRDY)==HIGH){}; //wait until the chip is ready

digitalWrite(PIN_SS,LOW);

SPI.transfer(B01100100); //instruction to tell ADS to go to CMR byte 3
SPI.transfer(B01010010); //write to the CMR byte 3
SPI.transfer(B00100000); //write to the CMR byte 2 go through self calibration
SPI.transfer(B00000000); //write to the CMR byte 1
SPI.transfer(B00001100); //write to the CMR byte 0

delay(20);

digitalWrite(PIN_SS,HIGH);

delay(250);
}

void loop(){
if(digitalRead(DRDY)==LOW){

digitalWrite(PIN_SS,LOW); //get the chip ready to receive commands

SPI.transfer(B11000000); //instruction register to read 3 bytes from Dor

DorThree = SPI.transfer(0x00);
DorTwo = SPI.transfer(0x00);
DorOne = SPI.transfer(0x00);

digitalWrite(SS,HIGH);

analogOutput = DorThree;
analogOutput = analogOutput<<8; //bit shift to make room for byte 2
analogOutput |= DorTwo;
analogOutput = analogOutput<<8;  //bit shift to make room for byte 1
analogOutput |= DorOne;

analogOutputTwos = ~analogOutput; //convert to twos complement
analogOutputTwos = analogOutputTwos + 1;

Serial.print("Decimal");
Serial.print('\t');
Serial.println(analogOutputTwos);
Serial.print("Binary");
Serial.print('\t');
Serial.println(analogOutputTwos,BIN);

Serial.print("Dor3");
Serial.print('\t');
Serial.println(DorThree,BIN);

Serial.print("Dor2");
Serial.print('\t');
Serial.println(DorTwo,BIN);

Serial.print("Dor1");
Serial.print('\t');
Serial.println(DorOne,BIN);

Serial.println();
}


delay(250);


}

  • Hi Alec,

    According to the values your are writing to the command registers (CMR) you are in Unipolar mode which means that you will never have a result returned below 0.  This simplifies things as the resultant code will always be a positive value.

    Here is the fun thing about reading the values back.  With two's complement you don't convert the value as it is in the form of a signed value.  The MSB determines the sign.  For your configuration you don't need to worry about the sign.

    Normally what would happen with +/- return values (this is bipolar mode and the default) is analog_output is a signed 32 bit integer (bits 31-0).  If bit 23 is high (after you assemble all three bytes of the DOR), then you 'OR' 0xFF000000 to sign extend the value.  This is now in the proper format for a negative number.  If bit 23 is low, you do nothing.  In other words the ADS1212 will return the correct format, you just need to make sure that you sign extend the value properly as needed.

    Regarding effective resolution, this really refers to noise relative to a stable measurement of one sigma relative to the mean (RMS noise).  Noise free bits is the number of bits where the noise does not interfere at all with a stable output code.  Your return value is always 24 bits, and the lower bits will fluctuate a lot.  The amount of total noise is relative to the conversion process ( the 20 bit effective resolution) and the system noise which includes sensor noise, external noise sources (RF/EMI), reference stability and PCB layout.

    The resolution of the converter is 24-bit.  The value of one LSB (code) is LSB = 2*VREF/PGA*(2^24 -1).  For a PGA or 1 this simplifies to 5/16777215.

    You will need to determine the actual amount of noise for your system.  On a prototype board without a good ground plane you will not likely achieve 20 bits.  Let's say your noise free bits (noise has no effect on the result) is 18, you would right shift the result by 6 (or divide by 64) and adjust the transfer function appropriately for LSB = 5/262143.  So in essence you were correct with the value of one LSB (code) except the true range for 20 bits is from 0 to 1,048,575.

    Best regards,

    Bob B

  • Bob,

    Thanks for the response it was super helpful. I had one more question. You said that the LSB = 2*Vref/(PGA*2^24-1). Would it actually be LSB = 2*Vref/(PGA*2^23-1) because the first bit is a sign bit? 

    Also, when I have AinN tied to ground and AinP sampling REFout I am getting results that are not consistant. Sample read out below. Do you think I may have damaged the ADC at some point? My code is below as well.

    Sample Read Out

    Decimal 59728
    Binary 1110100101010000
    Dor3 0
    Dor2 11101001
    Dor1 1010000

    Decimal 854539
    Binary 11010000101000001011
    Dor3 1101
    Dor2 1010
    Dor1 1011

    Decimal 2571
    Binary 101000001011
    Dor3 0
    Dor2 1010
    Dor1 1011

    Decimal 856632
    Binary 11010001001000111000
    Dor3 1101
    Dor2 10010
    Dor1 111000

    Decimal 8855
    Binary 10001010010111
    Dor3 0
    Dor2 100010
    Dor1 10010111

    Decimal 856632
    Binary 11010001001000111000
    Dor3 1101
    Dor2 10010
    Dor1 111000

    Decimal 8855
    Binary 10001010010111
    Dor3 0
    Dor2 100010
    Dor1 10010111

    Decimal 850351
    Binary 11001111100110101111
    Dor3 1100
    Dor2 11111001
    Dor1 10101111

    Code

    #include <SPI.h>

    //SPI
    const byte PIN_SCK = 13; //clock
    const byte PIN_MISO = 12; //master in slave out
    const byte PIN_MOSI = 11; //master out slave in
    const byte PIN_SS = 10; //slave select
    const byte DRDY = 9; //data ready

    byte Insr;
    byte DorOne;
    byte DorTwo;
    byte DorThree;
    byte CmrOne;
    byte CmrTwo;
    byte CmrThree;
    byte CmrFour;
    byte OcrOne;
    byte OcrTwo;
    byte OcrThree;
    byte FcrOne;
    byte FcrTwo;
    byte FcrThree;

    int i;

    long analogOutput;
    long analogOutputTwos;

    unsigned long sum;

    void setup(){
    Serial.begin(9600);

    SPI.begin();
    SPI.setBitOrder(MSBFIRST);
    SPI.setDataMode(SPI_MODE1);
    SPI.setClockDivider(SPI_CLOCK_DIV128);

    pinMode(SS,OUTPUT);
    pinMode(DRDY,INPUT);

    digitalWrite(PIN_SS,HIGH);

    delay(1000);

    while(digitalRead(DRDY)==HIGH){}; //wait until the chip is ready

    digitalWrite(PIN_SS,LOW);

    SPI.transfer(B01100100); //instruction to tell ADS to go to CMR byte 3
    SPI.transfer(B01010010); //write to the CMR byte 3
    SPI.transfer(B00100000); //write to the CMR byte 2
    SPI.transfer(B00000000); //write to the CMR byte 1
    SPI.transfer(B00001100); //write to the CMR byte 0

    delay(20);

    digitalWrite(PIN_SS,HIGH);

    delay(250);
    }

    void loop(){

    while(i<=10){
    if(digitalRead(DRDY)==LOW){

    digitalWrite(PIN_SS,LOW); //get the chip ready to receive commands

    SPI.transfer(B11000000); //instruction register to read 3 bytes from Dor

    DorThree = SPI.transfer(0x00);
    DorTwo = SPI.transfer(0x00);
    DorOne = SPI.transfer(0x00);

    digitalWrite(SS,HIGH);

    analogOutput = DorThree;
    analogOutput = analogOutput<<8;
    analogOutput |= DorTwo;
    analogOutput = analogOutput<<8;
    analogOutput |= DorOne;

    sum += analogOutput;

    Serial.print("Decimal");
    Serial.print('\t');
    Serial.println(analogOutput);
    Serial.print("Binary");
    Serial.print('\t');
    Serial.println(analogOutput,BIN);

    Serial.print("Dor3");
    Serial.print('\t');
    Serial.println(DorThree,BIN);

    Serial.print("Dor2");
    Serial.print('\t');
    Serial.println(DorTwo,BIN);

    Serial.print("Dor1");
    Serial.print('\t');
    Serial.println(DorOne,BIN);

    Serial.println();

    i++;
    }
    }

    Serial.println(sum/10);
    Serial.println();

    sum = 0;
    i=0;

    delay(1000);


    }


  • Hi Alec,

    You are correct about the formula as I forgot that this part has full-scale range of 4*Vref/PGA gain which is rather unusual compared to most of our other parts.

    Your data is all over the place.  I would verify your connections and timing.  I would verify all communication with a scope or logic analyzer to make sure that the reads and writes are correct, and also monitor DRDY to make sure you are not reading data during the update period.  Are you using this device in a proto-board?

    Damaging a device is a possibility, but the device is pretty robust unless the Absolute Maximum Ratings have been exceeded.

    Best regards,

    Bob B

     

  • I'll check out the communication, but when I read from the command register for instance, I don't have issues reading the correct bits. I have the device connected on a breadboard. 

    -Alec

  • Hi Alec,

    Precision dataconverters and breadboards don't usually go well together.  Lots of possibilities for poor connections and miswiring.  Breadboards are also notorious for noise and oscillation.

    As far as communication, you can write something wrong and read it wrong, and you may have what you think is correct but the ADS1212 can have incorrect values in the register.  At the very least you should read out the registers to see if you have the default power up values.

    Best regards,

    Bob B