mirror of
https://github.com/meshtastic/firmware.git
synced 2025-07-30 02:15:41 +00:00
Initial integration of ADS1X15 ADC
This commit is contained in:
parent
547767ca68
commit
49b32debe4
@ -202,3 +202,5 @@ lib_deps =
|
||||
sensirion/Sensirion Core@0.7.1
|
||||
# renovate: datasource=custom.pio depName=Sensirion I2C SCD4x packageName=sensirion/library/Sensirion I2C SCD4x
|
||||
sensirion/Sensirion I2C SCD4x@1.1.0
|
||||
# renovate: datasource=custom.pio depName=Adafruit ADS1X15 packageName=adafruit/library/Adafruit ADS1X15 Library
|
||||
adafruit/Adafruit ADS1X15@2.5.0
|
||||
|
@ -195,6 +195,10 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#define LTR390UV_ADDR 0x53
|
||||
#define XPOWERS_AXP192_AXP2101_ADDRESS 0x34 // same adress as TCA8418
|
||||
#define PCT2075_ADDR 0x37
|
||||
#define ADS1X15_ADDR 0x48 // same address as FT6336U
|
||||
#define ADS1X15_ADDR_ALT1 0x49
|
||||
#define ADS1X15_ADDR_ALT2 0x4A
|
||||
#define ADS1X15_ADDR_ALT3 0x4B
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// ACCELEROMETER
|
||||
|
@ -75,6 +75,7 @@ class ScanI2C
|
||||
TCA8418KB,
|
||||
PCT2075,
|
||||
BMM150,
|
||||
ADS1X15,
|
||||
} DeviceType;
|
||||
|
||||
// typedef uint8_t DeviceAddress;
|
||||
|
@ -564,7 +564,16 @@ void ScanI2CTwoWire::scanPort(I2CPort port, uint8_t *address, uint8_t asize)
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x48: {
|
||||
case 0x48: { // same as ADS1X15 main address
|
||||
|
||||
// ADS1X15 default config register is 8583h
|
||||
registerValue = getRegisterValue(ScanI2CTwoWire::RegisterLocation(addr, 0x01), 2);
|
||||
if (registerValue == 0x8583) {
|
||||
type = ADS1X15;
|
||||
logFoundDevice("ADS1X15", (uint8_t)addr.address);
|
||||
break;
|
||||
}
|
||||
|
||||
i2cBus->beginTransmission(addr.address);
|
||||
uint8_t getInfo[] = {0x5A, 0xC0, 0x00, 0xFF, 0xFC};
|
||||
uint8_t expectedInfo[] = {0xa5, 0xE0, 0x00, 0x3F, 0x19};
|
||||
@ -584,6 +593,17 @@ void ScanI2CTwoWire::scanPort(I2CPort port, uint8_t *address, uint8_t asize)
|
||||
break;
|
||||
}
|
||||
|
||||
case ADS1X15_ADDR_ALT1:
|
||||
case ADS1X15_ADDR_ALT2:
|
||||
case ADS1X15_ADDR_ALT3:
|
||||
// ADS1X15 default config register is 8583h
|
||||
registerValue = getRegisterValue(ScanI2CTwoWire::RegisterLocation(addr, 0x01), 2);
|
||||
if (registerValue == 0x8583) {
|
||||
type = ADS1X15;
|
||||
logFoundDevice("ADS1X15", (uint8_t)addr.address);
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
LOG_INFO("Device found at address 0x%x was not able to be enumerated", (uint8_t)addr.address);
|
||||
}
|
||||
|
@ -703,6 +703,7 @@ void setup()
|
||||
scannerToSensorsMap(i2cScanner, ScanI2C::DeviceType::RAK12035, meshtastic_TelemetrySensorType_RAK12035);
|
||||
scannerToSensorsMap(i2cScanner, ScanI2C::DeviceType::PCT2075, meshtastic_TelemetrySensorType_PCT2075);
|
||||
scannerToSensorsMap(i2cScanner, ScanI2C::DeviceType::SCD4X, meshtastic_TelemetrySensorType_SCD4X);
|
||||
scannerToSensorsMap(i2cScanner, ScanI2C::DeviceType::ADS1X15, meshtastic_TelemetrySensorType_ADS1X15);
|
||||
|
||||
i2cScanner.reset();
|
||||
#endif
|
||||
|
@ -22,6 +22,13 @@
|
||||
#include "graphics/ScreenFonts.h"
|
||||
#include <Throttle.h>
|
||||
|
||||
#if __has_include(<Adafruit_ADS1015.h>)
|
||||
#include "Sensor/ADS1X15Sensor.h"
|
||||
ADS1X15Sensor ads1x15Sensor;
|
||||
#else
|
||||
NullSensor ads1x15Sensor;
|
||||
#endif
|
||||
|
||||
namespace graphics
|
||||
{
|
||||
extern void drawCommonHeader(OLEDDisplay *display, int16_t x, int16_t y, const char *titleStr, bool battery_only);
|
||||
@ -74,6 +81,8 @@ int32_t PowerTelemetryModule::runOnce()
|
||||
result = ina3221Sensor.isInitialized() ? 0 : ina3221Sensor.runOnce();
|
||||
if (max17048Sensor.hasSensor())
|
||||
result = max17048Sensor.isInitialized() ? 0 : max17048Sensor.runOnce();
|
||||
if (ads1x15Sensor.hasSensor())
|
||||
result = ads1x15Sensor.isInitialized() ? 0 : ads1x15Sensor.runOnce();
|
||||
}
|
||||
|
||||
// it's possible to have this module enabled, only for displaying values on the screen.
|
||||
@ -205,6 +214,8 @@ bool PowerTelemetryModule::getPowerTelemetry(meshtastic_Telemetry *m)
|
||||
valid = ina3221Sensor.getMetrics(m);
|
||||
if (max17048Sensor.hasSensor())
|
||||
valid = max17048Sensor.getMetrics(m);
|
||||
if (ads1x15Sensor.hasSensor())
|
||||
valid = ads1x15Sensor.getMetrics(m);
|
||||
#endif
|
||||
|
||||
return valid;
|
||||
@ -246,9 +257,10 @@ bool PowerTelemetryModule::sendTelemetry(NodeNum dest, bool phoneOnly)
|
||||
m.time = getTime();
|
||||
if (getPowerTelemetry(&m)) {
|
||||
LOG_INFO("Send: ch1_voltage=%f, ch1_current=%f, ch2_voltage=%f, ch2_current=%f, "
|
||||
"ch3_voltage=%f, ch3_current=%f",
|
||||
"ch3_voltage=%f, ch3_current=%f, ch4_voltage=%f",
|
||||
m.variant.power_metrics.ch1_voltage, m.variant.power_metrics.ch1_current, m.variant.power_metrics.ch2_voltage,
|
||||
m.variant.power_metrics.ch2_current, m.variant.power_metrics.ch3_voltage, m.variant.power_metrics.ch3_current);
|
||||
m.variant.power_metrics.ch2_current, m.variant.power_metrics.ch3_voltage, m.variant.power_metrics.ch3_current,
|
||||
m.variant.power_metrics.ch4_voltage);
|
||||
|
||||
sensor_read_error_count = 0;
|
||||
|
||||
|
111
src/modules/Telemetry/Sensor/ADS1X15Sensor.cpp
Normal file
111
src/modules/Telemetry/Sensor/ADS1X15Sensor.cpp
Normal file
@ -0,0 +1,111 @@
|
||||
#include "configuration.h"
|
||||
|
||||
#if HAS_TELEMETRY && !MESHTASTIC_EXCLUDE_ENVIRONMENTAL_SENSOR && __has_include(<Adafruit_ADS1015.h>)
|
||||
|
||||
#include "../mesh/generated/meshtastic/telemetry.pb.h"
|
||||
#include "ADS1X15Sensor.h"
|
||||
#include "TelemetrySensor.h"
|
||||
#include <Adafruit_ADS1015.h>
|
||||
|
||||
ADS1X15Sensor::ADS1X15Sensor() : TelemetrySensor(meshtastic_TelemetrySensorType_ADS1X15, "ADS1X15") {}
|
||||
|
||||
int32_t ADS1X15Sensor::runOnce()
|
||||
{
|
||||
LOG_INFO("Init sensor: %s", sensorName);
|
||||
if (!hasSensor()) {
|
||||
return DEFAULT_SENSOR_MINIMUM_WAIT_TIME_BETWEEN_READS;
|
||||
}
|
||||
|
||||
status = ads1x15.begin(nodeTelemetrySensorsMap[sensorType].first);
|
||||
|
||||
return initI2CSensor();
|
||||
}
|
||||
|
||||
void ADS1X15Sensor::setup() {}
|
||||
|
||||
struct _ADS1X15Measurement ADS1X15Sensor::getMeasurement(ads1x15_ch_t ch)
|
||||
{
|
||||
struct _ADS1X15Measurement measurement;
|
||||
|
||||
// Reset gain
|
||||
ads1x15.setGain(GAIN_TWOTHIRDS);
|
||||
double voltage_range = 6.144;
|
||||
|
||||
// Get value with full range
|
||||
uint16_t value = ads.readADC_SingleEnded(ch);
|
||||
|
||||
// Dynamic gain, to increase resolution of low voltage values
|
||||
// If value is under 4.096v increase the gain depending on voltage
|
||||
if (value < 21845) {
|
||||
if (value > 10922) {
|
||||
|
||||
// 1x gain, 4.096V
|
||||
ads1x15.setGain(GAIN_ONE);
|
||||
voltage_range = 4.096;
|
||||
|
||||
} else if (value > 5461) {
|
||||
|
||||
// 2x gain, 2.048V
|
||||
ads1x15.setGain(GAIN_TWO);
|
||||
voltage_range = 2.048;
|
||||
|
||||
} else if (value > 2730) {
|
||||
|
||||
// 4x gain, 1.024V
|
||||
ads1x15.setGain(GAIN_FOUR);
|
||||
voltage_range = 1.024;
|
||||
|
||||
} else if (value > 1365) {
|
||||
|
||||
// 8x gain, 0.25V
|
||||
ads1x15.setGain(GAIN_EIGHT);
|
||||
voltage_range = 0.512;
|
||||
|
||||
} else {
|
||||
|
||||
// 16x gain, 0.125V
|
||||
ads1x15.setGain(GAIN_SIXTEEN);
|
||||
voltage_range = 0.256;
|
||||
}
|
||||
|
||||
// Get the value again
|
||||
value = ads1x15.readADC_SingleEnded(ch);
|
||||
}
|
||||
|
||||
reading = (float)value / 32768 * voltage_range;
|
||||
measurement.voltage = reading;
|
||||
|
||||
return measurement;
|
||||
}
|
||||
|
||||
struct _ADS1X15Measurements ADS1X15Sensor::getMeasurements()
|
||||
{
|
||||
struct _ADS1X15Measurements measurements;
|
||||
|
||||
// ADS1X15 has 4 channels starting from 0
|
||||
for (int i = 0; i < 4; i++) {
|
||||
measurements.measurements[i] = getMeasurement((ads1x15_ch_t)i);
|
||||
}
|
||||
|
||||
return measurements;
|
||||
}
|
||||
|
||||
bool ADS1X15Sensor::getMetrics(meshtastic_Telemetry *measurement)
|
||||
{
|
||||
|
||||
struct _ADS1X15Measurements m = getMeasurements();
|
||||
|
||||
measurement->variant.power_metrics.has_ch1_voltage = true;
|
||||
measurement->variant.power_metrics.has_ch2_voltage = true;
|
||||
measurement->variant.power_metrics.has_ch3_voltage = true;
|
||||
measurement->variant.power_metrics.has_ch4_voltage = true;
|
||||
|
||||
measurement->variant.power_metrics.ch1_voltage = m.measurements[0].voltage;
|
||||
measurement->variant.power_metrics.ch2_voltage = m.measurements[1].voltage;
|
||||
measurement->variant.power_metrics.ch3_voltage = m.measurements[2].voltage;
|
||||
measurement->variant.power_metrics.ch4_voltage = m.measurements[3].voltage;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
#endif
|
24
src/modules/Telemetry/Sensor/ADS1X15Sensor.h
Normal file
24
src/modules/Telemetry/Sensor/ADS1X15Sensor.h
Normal file
@ -0,0 +1,24 @@
|
||||
#include "configuration.h"
|
||||
|
||||
#if HAS_TELEMETRY && !MESHTASTIC_EXCLUDE_ENVIRONMENTAL_SENSOR && __has_include(<Adafruit_ADS1015.h>)
|
||||
|
||||
#include "../mesh/generated/meshtastic/telemetry.pb.h"
|
||||
#include "TelemetrySensor.h"
|
||||
#include "VoltageSensor.h"
|
||||
#include <Adafruit_ADS1015.h>
|
||||
|
||||
class ADS1X15Sensor : public TelemetrySensor, VoltageSensor
|
||||
{
|
||||
private:
|
||||
Adafruit_ADS1015 ads1x15;
|
||||
|
||||
protected:
|
||||
virtual void setup() override;
|
||||
|
||||
public:
|
||||
ADS1X15Sensor();
|
||||
virtual int32_t runOnce() override;
|
||||
virtual bool getMetrics(meshtastic_Telemetry *measurement) override;
|
||||
};
|
||||
|
||||
#endif
|
Loading…
Reference in New Issue
Block a user