Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

I2C ADC #31

Closed
DJLevel3 opened this issue Jan 13, 2023 · 8 comments · Fixed by #32
Closed

I2C ADC #31

DJLevel3 opened this issue Jan 13, 2023 · 8 comments · Fixed by #32
Assignees
Labels
enhancement New feature or request question Further information is requested

Comments

@DJLevel3
Copy link

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!

@RobTillaart
Copy link
Owner

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

@RobTillaart
Copy link
Owner

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)

@RobTillaart RobTillaart self-assigned this Jan 13, 2023
@RobTillaart RobTillaart added enhancement New feature or request question Further information is requested labels Jan 13, 2023
@RobTillaart
Copy link
Owner

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 --

@RobTillaart
Copy link
Owner

@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.

@RobTillaart
Copy link
Owner

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

@DJLevel3
Copy link
Author

Might be a good idea to just use #define and #ifdef to swap out a function at compile time, no?

@RobTillaart
Copy link
Owner

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.

@RobTillaart RobTillaart linked a pull request Jan 15, 2023 that will close this issue
@RobTillaart
Copy link
Owner

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
  • ...

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request question Further information is requested
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants