I2C ADC
DJLevel3 opened this issue · 8 comments
Is there any plan to support I2C ADCs such as an ADS1115?
I want to use this library to measure current from a step-down CT (I'm measuring some seriously large currents) and with an Arduino's built-in ADC I won't get the resolution I need. I want to use an ADS1115 board (such as https://a.co/d/4EJSIGC) but I don't see any functionality of the sort in this library. I'll see if I can find a way to get it to work, and if I do I'll update here, but if not is it a possibility for a dev to add this feature?
Thanks!
Hi,
Plans exist but no time at the moment as other tasks have my priority.
This is what I have in mind
Lib for the ADS1115 is available and stable.
https://github.com/RobTillaart/ADS1X15
Other libs like the mcp-adc are also stable and much faster. https://github.com/RobTillaart/MCP_ADC
What need to be done is create a function pointer that takes analogRead() as default argument and which can be overridden by another function that wraps the ADS1115 call. The pin parameter can be interpreted as one of the 4 channels.
There need to be a *setADC((int read)(int pin)) function to do the work. (Something like that,) and a variable that holds the function pointer. That latter should be used where now analogRead() is called.
Did extend this ACS lib once with an ADCsimulator to do some math testing in a similar way and that worked well. So there is some evidence this will work
Will give it some thoughts coming days, as it is an intriguing question
If you can create a PR according to the flow I propose it might be merged into it.
(Problem is that the Arduino build-CI is broken so automatic testing is almost zero)
proof of concept for function pointer (will be added as example to ADS1x15 lib in future)
Give it a try
// FILE: ADS_pointerToFunction.ino
// AUTHOR: Rob Tillaart
// DATE: 2023-01-14
// PURPOSE: replace internal ADC with external ADC by using pointer to function
// URL: https://github.com/RobTillaart/ADS1X15
#include "Arduino.h"
#include "ADS1X15.h"
// adjust address if needed
ADS1115 ADS(0x48);
// pointer to ADC function
int (*readADC)(uint8_t);
void setup()
{
Serial.begin(115200);
while(!Serial);
Serial.println(__FILE__);
ADS.begin(); // use defaults
readADC = analogRead; // start with internal
}
void loop()
{
delay(500);
int x = readADC(1);
Serial.println(x);
if (millis() > 5000) readADC = wrapper;
}
// wrapper takes care of optional casting
int wrapper(uint8_t x)
{
return ADS.readADC(x);
}
// -- END OF FILE --
@DJLevel3
Created a develop branch with setADC() function to replace the internal ADC with an external one.
Be sure to adjust the parameters of the constructor to the ADC used
These might become parameters of setADC() too.
See the example ACS712_20_DC_external_ADC.ino how to wrap the external ADC in a function that can be passed to setADC(). Similar as the sketch above.
Alternative is to make a cast in the call of setADC() directly.
- tested compilation and the new example => worked on UNO,
- not tested with a real external ADC
Please give it a try and let me know if it works.
Done additional tests,
- made changes to get it compiling on different boards (UNO, ESP32, NANO33ble)
- added parameters to overrule constructor settings
What is missing is a function to reset to the internal ADC.
Alternative is to make a cast in the call of setADC() directly.
This gives problems and it appears not possible
See - https://stackoverflow.com/questions/559581/casting-a-function-pointer-to-another-type
Might be a good idea to just use #define and #ifdef to swap out a function at compile time, no?
Might be a good idea to just use #define and #ifdef to swap out a function at compile time, no?
That will work too,
one need to add a guard to prevent double defines and to be able to overrule it command line.
The setADC will still be useful to easily set the parameters.
The way i'm after makes it possible to change ADC runtime.
That would allow different ADC's to be used. Think of a 16 bit slow for very precise measurements incl low currents and a 8 bit fast for larger currents.
Merged the setADC() so you can runtime change the ADC used on any platform. Besides setting an external ADC of choice runtime one can (in theory)
- set a simulator e.g any waveform any frequency
- adjust the internal ADC in a non linear way
- average multi ADC's or muliple readings
- replay a recorded signal,
- create a recording ADC to do previous
- ...