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.

ADS1258 how to convert unipolar value?

Other Parts Discussed in Thread: ADS1258, ADS1158

Hi all.


As says in datasheet on p.26, the adc values are coded in two-s complement. But my scheme is using unipolar signal (0 to 4.096V) for adc inputs.

I cant understand how to can convert the signed values to unipolar values? The values are always signed?

AINCOM is connected to VREFN and analog GND net.

So, for example, i read this values from ADC:

VCC = 10.66667v
GAIN = 0.99503v
REF = 10.66667v
TEMP = 24.57360C
OFFSET = 0.00334v

000000  AIN 0:  0.00000v
56c1d7  AIN 1:  3.17450v
56c118  AIN 2:  3.17439v
56c31a  AIN 3:  3.17468v
56beee  AIN 4:  3.17408v
56bee0  AIN 5:  3.17407v
004ef6  AIN 6:  0.01129v
5bd0b9  AIN 7:  3.35958v
5bca58  AIN 8:  3.35866v
5be632  AIN 9:  3.36264v
5bb8e8  AIN10:  3.35617v
5bad18  AIN11:  3.35448v
5b7166  AIN12:  3.34595v
ff547b  AIN13:  9.34267v
5b4752  AIN14:  3.33994v
5bc839  AIN15:  3.35836v

As you can see, for status bytes and AIN13 i have a invalid values. How treat this ADC codes correctly?

Please help. Thanks a lot.

Code that reads ADC:

#define SCALE                   (4.096 / 0x780000) * 1.06666660308837

#define V                       1
#define mV                      0.001
#define uV                      0.000001

// read values in auto-scan mode
void adc_request_values(uint8_t n_channels)
{
    uint8_t buf[16+5][4] = {0,0};
    uint8_t ch, byte = 0;
    float vcc, adcgain, ref, temp, offset = 0;
    int32_t tmp = 0;
    
    ADS_SET_HIGH(ADS_PIN_START); // start conversion
    for(ch = 0; ch < n_channels+5; ch++)
    {
        while(GPIO_ReadInputDataBit(GPIOA, ADS_PIN_DRDY) != 0); // wait for data ready
        // read data direct
        ADS_SET_LOW(ADS_PIN_CS);
        for(byte = 0; byte < 4; byte++)
        {
            buf[ch][byte] = ads_spi_xmit(0);
        }
        ADS_SET_HIGH(ADS_PIN_CS);
    }
    ADS_SET_LOW(ADS_PIN_START); // stop conversion
    
    offset  =    ((uint32_t) ((buf[16][1] << 16) | (buf[16][2] << 8) | buf[16][3])) / 786432.0;
    vcc     =    ((uint32_t) ((buf[17][1] << 16) | (buf[17][2] << 8) | buf[17][3])) / 786432.0;
    temp    = (((((uint32_t) ((buf[18][1] << 16) | (buf[18][2] << 8) | buf[18][3])) * SCALE * uV) - 168) / 394) + 25 ;
    adcgain =    ((uint32_t) ((buf[19][1] << 16) | (buf[19][2] << 8) | buf[19][3])) / 7864320.0;
    ref     =    ((uint32_t) ((buf[20][1] << 16) | (buf[20][2] << 8) | buf[20][3])) / 786432.0;

    printf("VCC = %2.5fv\n", vcc);
    printf("GAIN = %2.5fv\n", adcgain);
    printf("REF = %2.5fv\n", ref);
    printf("TEMP = %2.5fC\n", temp);
    printf("OFFSET = %2.5fv\n", offset);
    printf("\n");
    
    for(ch = 0; ch < n_channels; ch++)
    {
        printf("%06x", (uint32_t) ((buf[ch][1] << 16) | (buf[ch][2] << 8) | buf[ch][3]));
        printf("  AIN%2d:", (buf[ch][0] & 0x1F) - 8);
        printf("  %2.5fv", ((buf[ch][1] << 16) | (buf[ch][2] << 8) | buf[ch][3]) * SCALE / adcgain);
        if(((buf[ch][0] & 0x40) >> 6) == 1) printf("   Voltage overflow! (Vin > 1.06*Vref)");
        if(((buf[ch][0] & 0x20) >> 5) == 1) printf("   Lost supply! (AVDD-AVSS below a preset limit)");
        printf("\n");
    }
}

  • Hi,

    Welcome to the TI E2E Forums!

    The ADS1258 inputs are differential  and the output codes are always signed two's compliment (though you can take unipolar measurements by tying the negative input to ground). If you only apply positive voltages, you will only see positive output codes (except near zero, it is still possible for a small offset to result in a negative output code).

    It looks like you code is mostly correct, with just a couple of issues:

    1. Don't multiply the SCALE constant (i.e. the LSB size) by "1.066...". Just divide VREF by 780000h and the "1.066.." factor will be taken into account.
    2. Currently the code is not handling signed data; therefore, the AIN13 result is incorrect. "FF547B" should be a small negative number, but by assigning it to an unsigned data type it is treated as a large unsigned value.
    3. The VCC, OFFSET, TEMP, GAIN, and REF calculations may not be cast correctly. The data is cast into a UINT32_T data type, which is okay for combining the data bytes. However, when you perform the division (without any additional casting), this results in a UINT32_T remainder, which is then converted into the FLOAT variable. Instead you ought to also cast the division into a FLOAT datatype, so the the remainder is calculated as a FLOAT and then saved into the FLOAT variable.

    I recommend that you cast the ADC data bytes into a SIGNED data type and perform sign extension to make sure the signed 24-bit data is properly represented in a signed 32-bit data type. There is an example of this in the following blog post:

    ...I didn't see anything wrong with your STATUS bytes. It appears you only use the STATUS byte to get the channel number, which appears to be working.

     

    Best Regards,
    Chris

  • Dear Christopher, thanks for great reply.

    So i still have a few questions:
    1. I understood correctly that ADC core is ALWAYS treat their inputs as differential?
    2. It is correct that for unipolar measurements i need to use only positive inputs (ADCINP and VREFP)?
    3. It is correct that in this case i lost negative half of ADC values range (0 downto FFFFFF, so roughly speaking i just ignore values with MSB=1)?
    4. About VCC, VREF, TEMP and GAIN values: i cant understand that you say me. I use casting to uint_32 only for combining bytes into a single word, then i use a float representation of scaling coeff (eg 786432.0) that will result a float division. What wrong i do?
    5. About VCC, VREF, TEMP and GAIN values: for my case (my circuit, see start post) which coeffs i need to use? As datasheet or other?

    Big thanks.
  • Hi, I'll try to address your questions...

    pavel1 pavel2 said:
    1. I understood correctly that ADC core is ALWAYS treat their inputs as differential?

    Yes, if you think about it all voltage measurements are technically differential. We just refer to "single-ended" measurements as being the voltage difference between some potential and a ground reference; while "differential" measurements are the voltage difference between two voltage potentials (other than ground).

    With the ADS1258, you can use the AINCOM pin as a type of ground reference for single-ended measurements; however, this is really just the negative input pin. You don't necessarily have to bias the AINCOM pin to ground. If you do, make sure any external circuitry between  the MUXOUT and ADCIN pins can drive to ground potential.

     

    pavel1 pavel2 said:
    It is correct that for unipolar measurements i need to use only positive inputs (ADCINP and VREFP)?

    It is possible to have negative inputs as well... Simply bias AINCOM to 2.5V and when the input on AINx is 0V, the ADC will see AINx-AINCOM = -2.5V.

     

    pavel1 pavel2 said:
    3. It is correct that in this case i lost negative half of ADC values range (0 downto FFFFFF, so roughly speaking i just ignore values with MSB=1)?

    If the input signals are always positive, then yes, you lose half of the ADC's input range (or dynamic range, so ENOB drops by 1 bit). However, I would not ignore these values because you can still get negative results when differential signal is near zero and there is a small negative offset; OR if you bias AINCOM to 2.5V, then you would expect both positive and negative results.

     

    pavel1 pavel2 said:
    4. About VCC, VREF, TEMP and GAIN values: i cant understand that you say me. I use casting to uint_32 only for combining bytes into a single word, then i use a float representation of scaling coeff (eg 786432.0) that will result a float division. What wrong i do?

    You may need to perform an additional cast into a float so that division is done in float format, like such:

    offset  =    (float) (((uint32_t) ((buf[16][1] << 16) | (buf[16][2] << 8) | buf[16][3])) / 786432.0);

     

    pavel1 pavel2 said:
    5. About VCC, VREF, TEMP and GAIN values: for my case (my circuit, see start post) which coeffs i need to use? As datasheet or other?

    Use the datasheet values. It looks like you did, except for the VCC and REF measurements. For these, divide by 3072, as shown of page 24 of the ADS1258 datasheet.

     

    Best Regards,
    Chris

  • Christopher Hall said:
    Use the datasheet values. It looks like you did, except for the VCC and REF measurements. For these, divide by 3072, as shown of page 24 of the ADS1258 datasheet.

    Thats not correct (( This coeff 3072 is used for ADS1158. As says me datasheet, for ADS1258 it must be a 786432, but with this coeff i still have invalid voltage VCC and REF calculations (like VCC = 10.66667v, REF = 10.66667v).

  • Hi Pavel,

    You're correct it is divide by 786432, I'm sorry for my confusion.


    What is the raw data that you read for the VCC and REF measurements?

    ...You showed it for the channel data, but not for the internal system readings. It would be good to double check that the math operation is producing the correct result.


    Best Regards,
    Chris

  • Hi Christopher,


    Below is lot of my status values (values latched at one hardware run cycle):

    000a1c  OFFSET = 0.00329v
    7fffff  VCC = 10.66667v
    05bc0b  TEMP = 24.57360C
    7768b4  GAIN = 0.99507v
    7fffff  REF = 10.66667v
    
    7fffff  OFFSET = 10.66667v
    05c318  VCC = 0.48017v
    77689d  TEMP = 24.57360C
    7fffff  GAIN = 1.06667v
    45b79d  REF = 5.80977v
    
    05b351  OFFSET = 0.47504v
    776901  VCC = 9.95085v
    7fffff  TEMP = 24.57360C
    45b20f  GAIN = 0.58080v
    459bb3  REF = 5.80068v
    
    776809  OFFSET = 9.95053v
    7fffff  VCC = 10.66667v
    45af43  TEMP = 24.57360C
    459578  GAIN = 0.57987v
    4598c3  REF = 5.79973v
    
    7fffff  OFFSET = 10.66667v
    45ae63  VCC = 5.80677v
    45972b  TEMP = 24.57360C
    459707  GAIN = 0.57992v
    458c6f  REF = 5.79571v
    
    45abd4  OFFSET = 5.80593v
    459276  VCC = 5.79768v
    4594b2  TEMP = 24.57360C
    458a4c  GAIN = 0.57950v
    4562c3  REF = 5.78215v
    
    459055  OFFSET = 5.79698v
    4593e8  VCC = 5.79815v
    45874a  TEMP = 24.57360C
    456529  GAIN = 0.57829v
    4583bb  REF = 5.79288v
    
    4590f0  OFFSET = 5.79718v
    458824  VCC = 5.79432v
    4561fc  TEMP = 24.57360C
    458101  GAIN = 0.57920v
    45910c  REF = 5.79722v

    So, below is a code that show this result:

        #define SCALE                   (4.096 / 0x780000)
        uint32_t vcc, adcgain, ref, temp, offset = 0;
        offset  = (uint32_t) ((buf[16][1] << 16) | (buf[16][2] << 8) | buf[16][3]);
        vcc     = (uint32_t) ((buf[17][1] << 16) | (buf[17][2] << 8) | buf[17][3]);
        temp    = (uint32_t) ((buf[18][1] << 16) | (buf[18][2] << 8) | buf[18][3]);
        adcgain = (uint32_t) ((buf[19][1] << 16) | (buf[19][2] << 8) | buf[19][3]);
        ref     = (uint32_t) ((buf[20][1] << 16) | (buf[20][2] << 8) | buf[20][3]);
    
        printf("%06x  OFFSET = %2.5fv\n", offset,  (float) (offset / 786432.0) );
        printf("%06x  VCC = %2.5fv\n",    vcc,     (float) (vcc / 786432.0) );
        printf("%06x  TEMP = %2.5fC\n",   temp,    (float) ((((temp * SCALE * uV) - 168) / 394) + 25) );
        printf("%06x  GAIN = %2.5fv\n",   adcgain, (float) (adcgain / 7864320.0) );
        printf("%06x  REF = %2.5fv\n",    ref,     (float) (ref / 786432.0) );
        printf("\n");
    

    As you can see, the VCC and REF values are not showed correctly... Also i am confused about TEMP value: it is so much stable...

  • Hi Pavel,

    Some of your results are very questionable, it is odd to see sporadic full-scale results ("7FFFFF") for the system internal results. Also, a gain of 0.57 V/V is a huge gain error!

    I see a couple of possible issues:

    • If vcc is greater than 5.5V, then the device could get damaged. Check your supply supply voltage and keep it within 4.75 to 5.25V. Perhaps this device was damaged?
    • Your reference voltage appears to be approximately equal to your supply voltage, are these connected together? Often supply voltages are very noisy and don't provide stable ADC conversion results. Check to make sure your reference voltage is stable.

    • To calculate "offset", multiply it by your "SCALE" factor (instead of dividing by "786432"). Otherwise the other calculations appear correct.

     

    Best Regards,
    Chris