Closed hanmey97 closed 2 years ago
hi @hanmey97
The max speed is only possible in continuous mode (in my experience) for a single channel. As the differential read need two ADC calls I expect it can only go roughly at half speed. (iirc there is only one ADC internally)
What performance do you get with a single channel read()?
If for instance channel 0 changes much less (e.g. 10x less) than channel 1 you could do the differential yourself in a faster way.
start = micros();
for (int i = 0; i < 60; i++)
{
uint32_t val0 = ADS.readADC(0);
for (int j = 0; j < 10; j++)
{
result[i] = val0 - ADS.readADC(1);
}
}
end = micros();
If this is usable depends on the signals of both channels.
Another way to get finer granularity of the results is the alternating method. If this is usable also depends on the signals.
start = micros();
uint32_t val1 = 0;
uint32_t val0 = ADS.readADC(0);
for (int i = 0; i < 600; )
{
val1 = ADS.readADC(1);
result[i++} = val0 - val1;
val0 = ADS.readADC(0);
result[i++} = val0 - val1;
}
end = micros();
Thank you for your prompt reply!
I tried the Single Channel ans also the alternating Mode. In each Version, it tooks around 720µs for each measurement. I read about the HighSpeed-Mode in the Datasheet, which allows higher I2C Speeds. Up to 3,5MHz. Do you think this could help?
720 us is also ~1400x sec.
The time you measure is (1) initiate the sampling (2) making the sample (3) communicating the value to your processor (4) store it in the result array.
Setting high speed I2C would reduce the communication time.
If you do continuous sampling and use an interrupt flag (1) would go automatically (2) would take same time but when reading (3) the ADS could already make the next sample.
CAn you check the - ADS_async_differential.ino example ? What performance do you get there?
Okay. I tried the continous measurement.
void setup()
{
Serial.begin(115200);
//Serial.begin();
Serial.println(__FILE__);
Serial.print("ADS1X15_LIB_VERSION: ");
Serial.println(ADS1X15_LIB_VERSION);
ADS.begin();
ADS.setGain(0); // 6.144 volt
ADS.setDataRate(7);
ADS.setWireClock(400000);
ADS.setMode(1);
ADS.requestADC_Differential_0_1();
}
void loop()
{
start = micros();
for (int i = 0; i < (int)samples; i)
{
//result[i] = ADS.readADC_Differential_0_1();
if (ADS.isReady()){
ADS.requestADC_Differential_0_1();
result[i] = ADS.getValue();
i++;
}
//result_time[i] = micros();
}
end = micros();
with this code i get 574µs per measurement. That would be enough for my purpose.
Still, it's strange that it doesn't even come close to reaching full speed.
@hanmey97 574 us = ~1740 differential readings per second.
Be aware that you need two readings for one differential so the ADC makes ~3480 conversions per second. This is pretty much what is possible.
If you need more samples you need to drive 2 IC's in parallel, each their own ADC and do the diff on the processor. Might be a nice example sketch to write :)
Had a quick "merge of two examples" to get a high speed differential with 2 IC's and taking differential between both channel 0, 1 2 and 3. Will add soon to the example sketches so this is an unverified "sneak preview" ;)
//
// FILE: ADS_high_speed_differential.ino.ino
// AUTHOR: Rob.Tillaart
// VERSION: 0.1.0
// PURPOSE: read from 2 IC's for high speed differential
// interrupt driven to catch all conversions.
//
// test setup (not tested yet)
// - connect 2 ADS1x15 to I2C bus
// - connect potmeters to all channels
// - code reads both at the same frequency
// and calculates differential per pair.
// as 2 ADC's go in parallel, two ADS1015 should get
// 3000+ differential samples / second.
//
#include "ADS1X15.h"
// adjust addresses if needed
ADS1115 ADS_1(0x49);
ADS1115 ADS_2(0x48);
volatile bool RDY_1 = false;
volatile bool RDY_2 = false;
uint8_t channel = 0;
int32_t differential[4] = { 0, 0, 0, 0 };
void setup()
{
Serial.begin(115200);
Serial.println(__FILE__);
Serial.print("ADS1X15_LIB_VERSION: ");
Serial.println(ADS1X15_LIB_VERSION);
// SETUP FIRST ADS1115
ADS_1.begin();
ADS_1.setGain(0); // 6.144 volt
ADS_1.setDataRate(7); // fastest conversion rate.
// SET ALERT RDY PIN
ADS_1.setComparatorThresholdHigh(0x8000);
ADS_1.setComparatorThresholdLow(0x0000);
ADS_1.setComparatorQueConvert(0);
// SET INTERRUPT HANDLER TO CATCH CONVERSION READY
pinMode(2, INPUT_PULLUP);
attachInterrupt(digitalPinToInterrupt(2), adsReady_1, RISING);
ADS_1.setMode(0); // continuous mode
ADS_1.readADC(channel); // trigger first read
// SETUP SECOND ADS1115
ADS_2.begin();
ADS_2.setGain(0); // 6.144 volt
ADS_2.setDataRate(7);
// SET ALERT RDY PIN
ADS_2.setComparatorThresholdHigh(0x8000);
ADS_2.setComparatorThresholdLow(0x0000);
ADS_2.setComparatorQueConvert(0);
// SET INTERRUPT HANDLER TO CATCH CONVERSION READY
pinMode(3, INPUT_PULLUP);
attachInterrupt(digitalPinToInterrupt(3), adsReady_2, RISING);
ADS_2.setMode(0); // continuous mode
ADS_2.readADC(channel); // trigger first read
}
void loop()
{
if (handleConversion() == true)
{
for (int i = 0; i < 4; i++)
{
Serial.print(differential[i]);
Serial.print("\t");
}
Serial.println();
}
}
// catch interrupt and set flag
void adsReady_1()
{
RDY_1 = true;
}
void adsReady_2()
{
RDY_2 = true;
}
// handle conversions if both are ready
bool handleConversion()
{
if (RDY_1 == false) return false;
if (RDY_2 == false) return false;
// read the value of both
int16_t a = ADS_1.getValue();
int16_t b = ADS_2.getValue();
differential[channel] = a - b;
// request next channel
channel++;
if (channel >= 4) channel = 0;
ADS_1.readADC(channel);
ADS_2.readADC(channel);
RDY_1 = false;
RDY_2 = false;
return true;
}
// -- END OF FILE --
update: added to master branch, will be part of next release (whenever).
Thats a good version for differential measurement.
I made one for a single measurement. For this example the ADC-Pins are connected in parallel.
I just edited the handleConvrsaion()
int16_t handleConversion()
{
int16_t analog_val;
if (first_adc == true && RDY_1 == true){
analog_val = ADS_1.getValue();
first_adc = !first_adc;
RDY_1 = false;
ADS_1.readADC(channel);
}
else if (first_adc == false && RDY_2 == true){
analog_val = ADS_2.getValue();
first_adc = !first_adc;
RDY_2 = false;
ADS_2.readADC(channel);
}
else return false;
// read the value of both
channel++;
if (channel >= 4) channel = 0;
return analog_val;
}
It's untested too, but my second ADS1015 ist on the way. When it arrives, I'll test it.
Think your function will not return what you expect as the variable analog-val is declared multiple times with different scope.
Oh thats right. It was a copy-paste mistake. On declaration should be enough.
And you should initialize it to some value in case both paths of the if else if fail
Think the issue can be closed?
Yes, thank you very much!
Hey, i'm using your Library with PlatormIO on my Black STM32F407VE. It works good, but the Datarate is a bit too low. I only archive 1375 SPS with the ADS1015.
Do you know, where my Problem is?
Thank you very much!