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.

ADS1256: ADS1256 for photovoltaic design using arduino platform

Part Number: ADS1256
Other Parts Discussed in Thread: ADS1261, ADS1261EVM, ADS1262

Hi Ti!

I am having an ADS1256 module and I need to configure it as a precision ADC for a photodiode in photovoltaic mode for an environment monitoring system, can you share a base level setup guideline for me to use it in the arduino platform please?

many thanks in advance!

Alvin.

  • Hi Alvin,

    The good news is that the ADS1256 is already configured as precision ADC for you, so you're well on your way there ;)

    Unfortunately, we do not work with Arduino Microcontrollers or provide Arduino examples with our devices. However, I have seen many online Arduino projects that either provide generic SPI examples or even specific examples of how to interface to the ADS1256. One recent E2E Thread had some Arduino Uno code, found here: https://e2e.ti.com/support/data-converters/f/73/p/782256/2894069#2894069

    There is also a third-party Github project here: https://github.com/baettigp/ADS12xx-Library, though I have not tested this code myself.

    Please refer to those examples for specifics on how to interface with an Arduino; however, if you have any general questions about the ADS1256 or how to configure the registers settings for your application, I'll be glad to help provide some guidance there!

     

  • Hi Chris,

    Thank you for sharing!

    I will try the code and revert for specific guidance on how to optimize registers to suit my application.

    Many thanks in advance!

    Alvin.

  • Hi Chris,

    The code runs on well on the Arduino Uno, however have you come across similar code that can be run on esp32?

    Appreciate your help!

    Alvin.

  • Hi Chris,

    I am implementing below on ESP32 there seems to be some spiking happening especially close to the lower level of signals, any suggestion to improve? I am also noticing that I cannot get the registers to configure properly, and cannot control PGA etc.

    ADS1256 code.txt
    #include <Arduino.h>
    #include <Wire.h>
    #include <SPI.h>
    
    #define mosi 23
    #define miso 19
    #define sclk 18
    #define cs   5
    #define rst  17
    #define rdy  16
    
    #define SPISPEED 1000000 //  1.92MHz std.@ 7.68/4 MHz
    
    const float Vref = 2.485;
    
    void sendAds ()
    {
      unsigned long adc_val[8] = {0,0,0,0,0,0,0,0};
      byte mux[8] = {0x08,0x18,0x28,0x38,0x48,0x58,0x68,0x78};
      
      int i = 0;
    
      SPI.beginTransaction(SPISettings(SPISPEED, MSBFIRST, SPI_MODE1));
      digitalWrite(cs, LOW);
      delayMicroseconds(1);
    
      for (i=0; i <= 7; i++)
      {
        byte channel = mux[i];
        
        while (digitalRead(rdy)) {} ;                          
    
        SPI.transfer(0x50 | 0x01);
        SPI.transfer(0x00);
        SPI.transfer(channel);
        delayMicroseconds(2);
    
        SPI.transfer(0xFC);
        delayMicroseconds(2);
    
        SPI.transfer(0x00);
        delayMicroseconds(250);
        
        SPI.transfer(0x01);
        delayMicroseconds(7);
        
        adc_val[i] = SPI.transfer(0);
        adc_val[i] <<= 8;
        adc_val[i] |= SPI.transfer(0);
        adc_val[i] <<= 8;
        adc_val[i] |= SPI.transfer(0);
    
        delayMicroseconds(1);
    
      }
      
      digitalWrite(cs, HIGH);
      SPI.endTransaction();
    
      for (i=0; i <= 7; i++)
      {
    
        if(adc_val[i] > 0x7fffff)
        {
          adc_val[i] = 16777216ul-adc_val[i];
        }
    
      }
    
      double FV0 = adc_val[0] * 2 * Vref / 8388607 ;
      double FV1 = adc_val[1] * 2 * Vref / 8388607 ;
      double FV2 = adc_val[2] * 2 * Vref / 8388607 ;
      double FV3 = adc_val[3] * 2 * Vref / 8388607 ;
      double FV4 = adc_val[4] * 2 * Vref / 8388607 ;
      double FV5 = adc_val[5] * 2 * Vref / 8388607 ;
      double FV6 = adc_val[6] * 2 * Vref / 8388607 ;
      double FV7 = adc_val[7] * 2 * Vref / 8388607 ;
    
      delay(1);
    
    }
    
    void setup()
    {
      Serial.begin(115200);
      delay(100);
    
      pinMode(cs, OUTPUT);
      digitalWrite(cs, LOW);
      pinMode(rdy, INPUT);
      pinMode(rst, OUTPUT);
      digitalWrite(rst, LOW);
      delay(1);
      digitalWrite(rst, HIGH);
      
      delay(500);
      SPI.begin();
      delay(500);
    
      digitalWrite(cs, LOW);
    
      while (digitalRead(rdy)) {}
      SPI.beginTransaction(SPISettings(SPISPEED, MSBFIRST, SPI_MODE1));
      digitalWrite(cs, LOW);
      delayMicroseconds(10);
    
      SPI.transfer(0xFE);
      delay(10);
    
      byte status_reg = 0x00 ;
      byte status_data = 0x07;
      SPI.transfer(0x50 | status_reg);
      SPI.transfer(0x00);
      SPI.transfer(status_data);
      delayMicroseconds(10);
    
      byte adcon_reg = 0x02;
      byte adcon_data = 0x00;
      SPI.transfer(0x50 | adcon_reg);
      SPI.transfer(0x00);
      SPI.transfer(adcon_data);
      delayMicroseconds(10);
    
      byte drate_reg = 0x03;
      byte drate_data = 0xF0;
      SPI.transfer(0x50 | drate_reg);
      SPI.transfer(0x00);
      SPI.transfer(drate_data);
      delayMicroseconds(10);
    
      SPI.transfer(0xF0);
      delay(400);
      digitalWrite(cs, HIGH);
      SPI.endTransaction();
    
      while (!Serial && (millis ()  <=  5000));
      Serial.println("configured, starting");
      Serial.println("");
      Serial.println("A0,A1,A2,A3,A4,A5,A6,A7");
        
      terminal.flush();
      terminal.clear();         
    
      timer.setInterval(1000L, sendAds);
        
    }
    
    void loop()
    {
      timer.run();
    }

  • Hi Alvin,

    Sorry for my delayed response.

    Looking at your code, I don't see a delay to allow the ADC's conversion to complete. After the SYNC and WAKEUP commands the ADC will be performing a conversion, but the conversion results will not be ready until after the /DRDY goes low. Therefore, before sending the "0x01" byte (RDATA command ), poll the /DRDY pin and check if it is low.
  • Hi Chris,

    I tried including the additional code lines and there was an improvement on the single ended mode- thanks!

    However I am still seeing some spikes in the differential mode. Attached is the code, can you suggest an improvement please?

    Thanks in advance!

    Also, in either case, with open ended imputs, I seldom see the voltage settling to close to zero. any thoughts to why this is the case?

    Alvin.

    ADS1256 Diff..txt
    #include <Arduino.h>
    #include <Wire.h>
    #include <SPI.h>
    
    #define mosi 23
    #define miso 19
    #define sclk 18
    #define cs   5
    #define rst  17
    #define rdy  16
    
    #define SPISPEED 1920000 //  1.92MHz std.@ 7.68/4 MHz
    
    const float Vref = 2.485;
    
    void sendAds ()
    {
      unsigned long adc_val[4] = {0,0,0,0};
      byte mux[4] = {0x01,0x23,0x45,0x67};
      
      int i = 0;
    
      digitalWrite(cs, LOW);
      delayMicroseconds(10);
    
      //while (digitalRead(rdy)) {}
      //SPI.transfer(0xFE);
    
      for (i=0; i <= 3; i++)
      {
        byte channel = mux[i];
        
        while (digitalRead(rdy)) {};      
    
        SPI.transfer(0x50 | 0x01);
        SPI.transfer(0x00);
        SPI.transfer(channel);
        delayMicroseconds(2);
    
        SPI.transfer(0xFC);
        delayMicroseconds(2);
     
        SPI.transfer(0x00);
        delayMicroseconds(2);
        
        while (digitalRead(rdy)) {} ; 
        SPI.transfer(0x01);
        delayMicroseconds(7);
        
        adc_val[i] = SPI.transfer(0);
        adc_val[i] <<= 8;
        adc_val[i] |= SPI.transfer(0);
        adc_val[i] <<= 8;
        adc_val[i] |= SPI.transfer(0);
    
      }
      
      digitalWrite(cs, HIGH);
      SPI.endTransaction();
    
      for (i=0; i <= 3; i++)
      {
        
        if(adc_val[i] > 0x7fffff)
        {
          adc_val[i] = 16777216-adc_val[i]; 
        }
    
      }
      
      double FV0 = adc_val[0] * 2 * Vref / 8388607 ;
      double FV1 = adc_val[1] * 2 * Vref / 8388607 ;
      double FV2 = adc_val[2] * 2 * Vref / 8388607 ;
      double FV3 = adc_val[3] * 2 * Vref / 8388607 ;
    
      Blynk.virtualWrite(V60, FV0);
      Blynk.virtualWrite(V61, FV1);
      Blynk.virtualWrite(V62, FV2);
      Blynk.virtualWrite(V63, FV3);
    
    }
    
    void setup()
    {
      Serial.begin(115200);
    
      pinMode(cs, OUTPUT);
      pinMode(rdy, INPUT);
      pinMode(rst, OUTPUT);
    
      digitalWrite(cs, LOW);
      digitalWrite(rst, LOW);
    
      delay(1);
      digitalWrite(rst, HIGH);
      
      delay(500);
      SPI.begin();
      delay(500);
    
      digitalWrite(cs, LOW);
    
      while (digitalRead(rdy)) {}
    
      SPI.beginTransaction(SPISettings(SPISPEED, MSBFIRST, SPI_MODE1));
      digitalWrite(cs, LOW);
      delayMicroseconds(10);
    
      while (digitalRead(rdy)) {}
      SPI.transfer(0xFE);
      delay(1);
    
      while (digitalRead(rdy)) {}
      byte status_reg = 0x00 ;
      byte status_data = 0x05;
      SPI.transfer(0x50 | status_reg);
      SPI.transfer(0x00);
      SPI.transfer(status_data);
      delayMicroseconds(100);
    
      while (digitalRead(rdy)) {}
      byte adcon_reg = 0x02;
      byte adcon_data = 0x02;
      SPI.transfer(0x50 | adcon_reg);
      SPI.transfer(0x00);
      SPI.transfer(adcon_data);
      delayMicroseconds(100);
    
      while (digitalRead(rdy)) {}
      byte drate_reg = 0x03;
      byte drate_data = 0xF0;
      SPI.transfer(0x50 | drate_reg);
      SPI.transfer(0x00);
      SPI.transfer(drate_data);
      delayMicroseconds(100);
    
      while (digitalRead(rdy)) {}
      SPI.transfer(0xF0);
      delay(400);
    
      digitalWrite(cs, HIGH);
      SPI.endTransaction();
    
      while (!Serial && (millis ()  <=  5000));
      Serial.println("configured, starting");
      Serial.println("");
      Serial.println("A0,A1,A2,A3");
        
      terminal.flush();
      terminal.clear();         
    
      timer.setInterval(1000L, sendAds);
      timer.setInterval(1000L, sendWifi);
        
    }
    
    void loop()
    {
      timer.run();
    }
    

  • Hi Alvin,

    Have you tried shorting the inputs to some common voltage and seeing if the spikes are still present in the data?

    NOTE: In the case of the ADS1256, you can short both inputs to ground, but on many other ADCs with built-in PGAs this would violate the PGA input common-mode range.

    I'd also recommend looking at the raw data bytes contained within the "adc_val" array to see if perhaps the spikes are being introduced into the data during post-processing.

    ...With the inputs shorted together, you will see some noise, but it should be fairly Gaussian and not contain too many outliers. 

  • ADS diff. code.rtfHi Chris,

    I believe I have optimized the code (attached). and let me know if further optimization is possible. I have used a drate of 50 to minimize supply noise.

    I am understanding from your site there are newer chips with nano volt level noise, can you recommend some chips that may be superior to the ADS1256? and that are optimized to work with photodiodes in photovoltaic mode? - or does the ADS1256 does it well?

    My goal is to design a precision lowest noise possible ADC which can directly draw signals from a Li-Cor 190R PAR sensor. equipped with a millivolt adapter that has a 745 Ohm shunt. (Without the need of pre-amplifying the signal)

    Many thanks again I have learnt a lot from you!

    Alvin.

  • Hi Alvin,

    Please pardon the delayed response over the holiday weekend.

    I would recommend looking at the ADS1261. This device is one of our newest and has better noise performance and much higher input impedance than the ADS1256. However, you'd likely need to take care to ensure that your sensor voltage is within the ADS1261's PGA common-mode input range (Refer to www.ti.com/.../ads1261-excel-calc-tool for help in checking the input voltage range). The negative input of the ADS1261 cannot connect to ground (as it can with the ADS1256). Therefore, I'd recommend using the internal level shifter on the AINCOM pin to bias the input sensor to a mid-supply voltage (2.5V) instead of ground.
  • Hi Chris,

    No worries, Sri Lanka was in turmoil last Easter Sunday unfortunately :(

    Thank you for your advice on the ADS1261 which seems very promising indeed!, unfortunately I am finding it difficult to find modules around the ADS1261, unlike the ones I have on ebay for the ADS1256.

    Does Ti have such modules for the ADS1261 in ebay or any global marketplace? if so let me know.
    I have checked DigiKey but they only have the chip alone.

    In the mean time since I already have the ADS1256, do you feel that I have maximized the code? and do you have any further recommendations for further improvement?

    Many thanks in advance!
    Alvin.
  • Hi Alvin,

    If you need a breakout board, then perhaps look for an ADS1262. This is a very similar device to the ADS1261, but I know there are breakout boards available for this device. Otherwise, the ADS1261EVM has an unpopulated header that you could use to jumper wire to your Arduino.

    I looked at your code and the only thing that stood out to me was line 66 where you perform the subtraction:

    adc_val[i] = adc_val[i] - 16777216ul;

    Since "adc_val" is unsigned and this subtraction could result in a negative number, you'll end up with a wrap around positive result  (see https://stackoverflow.com/questions/7221409/is-unsigned-integer-subtraction-defined-behavior)

  • Hi Chris,

    Saw the eval board board for the 1262, unfortunately its far beyond my budget :(

    noted your comment on line 66 I'll rectify this.

    Many thanks again.

    Alvin.