Adafruit ADC1115 really slow

Hi,

Very new to Arduino programming but getting somewhere.

I'm using a Duemilanove with an Adafruit ADC1115 16 bit ADC to read from a potentiometer and move a microstepper motor driver with 25600 steps to focus a camera in real time. I found the built in ADC not high enough resolution to provide smooth movement.

The following code works but its incredibly slow taking 10-15 seconds to do a full turn.

Is there a better way of doing this or is the ADC inherently slow to read?

    #include <Wire.h>
    #include <Adafruit_ADS1015.h>
    #define PotIn  0
    
       Adafruit_ADS1115 ads1115;
 


void setup(){
  // initialize the digital pins as an output.
  pinMode(13, OUTPUT);
  pinMode(12, OUTPUT);
  ads1115.begin();
}
int pos=0;                 //Position in steps

void loop(){
  int val = ads1115.readADC_SingleEnded(0);   //get the potentiometer value (range 47-26294)
  

  if(abs(val - pos)> 1 ){         //if diference is greater than 1 steps.
      if((val - pos)> 1){
          digitalWrite(12, HIGH);   // set the direction forward
          digitalWrite(13, HIGH);   // send pulse to driver

          digitalWrite(13, LOW);    // turn off pulse by making the voltage LOW
         pos++;
          }
      if((val - pos)< 1){
          digitalWrite(12, LOW);   // set the direction reversd
          digitalWrite(13, HIGH);   // send puls to driver

          digitalWrite(13, LOW);    // turn off pulse by making the voltage LOW  
          pos--;
          }
      }

}

Thanks for any advice you can give.

Are you pulsing once per loop, and have to do 25600 pulses? That would take time, yes. Nothing to do with the ADC converter.

A couple of tips

  1. auto format your code, this makes it much easier for YOU and us to understand your code and will make a lot of bugs obvious.

  2. place all your global vars before your functions it makes them easy to find and the code easier to understand.

Mark

I am also getting some slow results with the Adafruit ADC1115. Not in the second range by any means. But It is taking ~30ms per loop. With the 860 hz sampling rate of the ADC1115 I figured i should be getting around 5ms per loop. Maybe a little slower with the serial output. Any suggestions would be appreciated.

The breakout board I am using (ADS1115 16-Bit ADC - 4 Channel with Programmable Gain Amplifier [STEMMA QT / Qwiic] : ID 1085 : $14.95 : Adafruit Industries, Unique & fun DIY electronics and kits).

My code
#include <Wire.h>
#include <Adafruit_ADS1015.h>

Adafruit_ADS1115 ads1115;

void setup(void)
{
Serial.begin(115200);
Serial.println("Hello!");

Serial.println("Getting single-ended readings from AIN0..3");
Serial.println("ADC Range: +/- 6.144V (1 bit = 3mV)");

// The ADC input range (or gain) can be changed via the following
// functions, but be careful never to exceed VDD +0.3V max, or to
// exceed the upper and lower limits if you adjust the input range!
// Setting these values incorrectly may destroy your ADC!

ads1115.setGain(GAIN_TWO); // 2x gain +/- 2.048V 1 bit = 1mV

ads1115.begin();
}

void loop(void)
{
int16_t adc0, adc1, adc2, adc3;
String data = "";
adc0 = ads1115.readADC_SingleEnded(0);
adc1 = ads1115.readADC_SingleEnded(1);
adc2 = ads1115.readADC_SingleEnded(2);
adc3 = ads1115.readADC_SingleEnded(3);
data +=String(millis()); data+=",";
data +=String(adc0); data+=",";
data +=String(adc1); data+=",";
data +=String(adc2); data+=",";
data +=String(adc3); data+=",";
Serial.println(data);

}

[ Don't use the String class or Serial in a timing loop, both take an unknown and potential
long time! ]

You basic problem is that you want to implement a servo feedback loop which has to monitor a
slow ADC and simultaneously output tonnes of pulses to a stepper motor. You need
to offload one of these tasks to an interrupt routine I think, so that the pulses can stream
smoothly. You also need something like a PID loop (perhaps just PI terms) to control the
rate of pulse production from the sensed error - then you'll get realistic acceleration. The
I term should get the final stopping position spot-on. This is going to be fairly complex/tricky
to tune I suspect.

digitalWrite is a great place to start when learning, from a uno @ 16mhz it takes 56 cycles whereas directly setting a bit in the register takes 2 cycles.

void loop(void)

{
  int16_t adc0, adc1, adc2, adc3;
  String data = "";
  adc0 = ads1115.readADC_SingleEnded(0); 
  adc1 = ads1115.readADC_SingleEnded(1); 
  adc2 = ads1115.readADC_SingleEnded(2); 
  adc3 = ads1115.readADC_SingleEnded(3);
  data +=String(millis()); data+=",";
  data +=String(adc0); data+=",";
  data +=String(adc1); data+=",";
  data +=String(adc2); data+=",";
  data +=String(adc3); data+=",";
  Serial.println(data);
 
}

Code tags, please.

Read this before posting a programming question

String is really slow, in particular concatenation. Read this:

Sorry guys I am pretty new to this. I will figure out the character array's and I'm sure that will help. Still I could be wrong but I don't think that using the String class accounts for an extra 25 ms per cycle. "Time taken to concatenate 100 bytes: 2,480 µS." - Nick Gammon. I have used a code similar to this many times where I was just reading in 4 voltage channels(10-bit integers) on the analog inputs and writing to an SD card. The times I would get were around 2ms per cycle. I have also used the i2c pins to read and write 4 measures off of the mpu-6050 and it was much faster than this ~5ms.

I have also tried using Jeff Rowberg's library which actually lets you choose the cycles per second.

* Basic testing and check out sketch for a TI ADS1115 4 channel,16 bit, I2C, analog to digital converter chip
   Leftyretro 08/06/11
   With thanks to Jeff Rowberg for the development of the ADS1115 and I2Cdev I2C libraries
*/
#include <Wire.h>
#include "ADS1115.h"
#include "I2Cdev.h"

ADS1115 adc;

void setup() 
  {
    Wire.begin();  // join I2C bus
    Serial.begin(115200); // initialize serial communication 
    Serial.println("Initializing I2C devices..."); 
    adc.initialize(); // initialize ADS1115 16 bit A/D chip
    Serial.println("Testing device connections...");
    Serial.println(adc.testConnection() ? "ADS1115 connection successful" : "ADS1115 connection failed");
    Serial.println("   ");
    
//  select desired conversion method
    adc.setMode(ADS1115_MODE_CONTINUOUS); // free running conversion
    // adc.setMode(ADS1115_MODE_SINGLESHOT); // single conversion

// select desired measurement range
     adc.setGain(ADS1115_PGA_0P512);  // +/-  .512 range, .000015625 volts/step
    
    
//  Select desired sample speed
 
    adc.setRate(ADS1115_RATE_860);  // 860 samples per second
    
    //adc.setMultiplexer(ADS1115_MUX_P0_N1);  // AN0+ Vs AN1-
     adc.setMultiplexer(ADS1115_MUX_P0_NG);  // AN0+ Vs ground 

   }
void loop() {
    String data = "";
    
data+= adc.getConversionP0GND();data+= ",";
data+= adc.getConversionP1GND();data+= ",";
data+= adc.getConversionP2GND();data+= ",";
data+= adc.getConversionP3GND();data+= ",";
data+= millis();
    
    Serial.println(data);
   
}

Try timing this line:

 adc0 = ads1115.readADC_SingleEnded(0);

Read micros() before, and after, subtract one from the other and print the result.

I will figure out the character array's and I'm sure that will help.

Why? Is there some reason to send the data using a single call to Serial.println()? Whatever you are sending the data to can't tell whether the data was put in the outgoing buffer using one call, 4 calls, or 25 calls. Don't waste space collecting data. Just write the data to the port as you have it.

Are you pulsing once per loop, and have to do 25600 pulses? That would take time, yes. Nothing to do with the ADC converter.

If I don't include the read ADC line it'll do a full rotation (25600 steps) in about a quarter of a second (yes I was impressed too) :slight_smile:

What is your I2C speed? The ADS1115 supports up to 3.4Mbit/sec.