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

[adc] Refactor ADS1115 driver #24428

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
166 changes: 36 additions & 130 deletions src/drivers/adc/ads1115/ADS1115.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -42,18 +42,7 @@ int ADS1115::init()
return ret;
}

uint8_t config[2] = {};
config[0] = CONFIG_HIGH_OS_NOACT | CONFIG_HIGH_MUX_P0NG | CONFIG_HIGH_PGA_6144 | CONFIG_HIGH_MODE_SS;
config[1] = CONFIG_LOW_DR_250SPS | CONFIG_LOW_COMP_MODE_TRADITIONAL | CONFIG_LOW_COMP_POL_RESET |
CONFIG_LOW_COMP_LAT_NONE | CONFIG_LOW_COMP_QU_DISABLE;
ret = writeReg(ADDRESSPOINTER_REG_CONFIG, config, 2);

if (ret != PX4_OK) {
PX4_ERR("writeReg failed (%i)", ret);
return ret;
}

setChannel(ADS1115::A0); // prepare for the first measure.
readChannel(Channel::A0); // prepare for the first measure.

ScheduleOnInterval(SAMPLE_INTERVAL / 4, SAMPLE_INTERVAL / 4);

Expand All @@ -62,152 +51,69 @@ int ADS1115::init()

int ADS1115::probe()
{
uint8_t buf[2] = {};
int ret = readReg(ADDRESSPOINTER_REG_CONFIG, buf, 2);
// The ADS1115 has no ID register, so we read out the threshold registers
// and check their default values. We cannot use the config register, as
// this is changed by this driver. Note the default value is in BE.
static constexpr uint32_t DEFAULT{0xFF7F0080};
union {
struct {
uint8_t low[2];
uint8_t high[2];
} parts;
uint32_t threshold{};
};
int ret = readReg(ADDRESSPOINTER_REG_LO_THRESH, parts.low, 2);

if (ret != PX4_OK) {
DEVICE_DEBUG("readReg failed (%i)", ret);
DEVICE_DEBUG("lo_thresh read failed (%i)", ret);
return ret;
}

if (buf[0] != CONFIG_RESET_VALUE_HIGH || buf[1] != CONFIG_RESET_VALUE_LOW) {
DEVICE_DEBUG("ADS1115 not found");
return PX4_ERROR;
ret = readReg(ADDRESSPOINTER_REG_HI_THRESH, parts.high, 2);

if (ret != PX4_OK) {
DEVICE_DEBUG("hi_thresh read failed (%i)", ret);
return ret;
}

return PX4_OK;
if (threshold == DEFAULT) {
return PX4_OK;
}

DEVICE_DEBUG("ADS1115 not found");
return PX4_ERROR;
}

int ADS1115::setChannel(ADS1115::ChannelSelection ch)
int ADS1115::readChannel(ADS1115::Channel ch)
{
uint8_t buf[2] = {};
uint8_t next_mux_reg = CONFIG_HIGH_MUX_P0NG;

switch (ch) {
case A0:
next_mux_reg = CONFIG_HIGH_MUX_P0NG;
break;

case A1:
next_mux_reg = CONFIG_HIGH_MUX_P1NG;
break;

case A2:
next_mux_reg = CONFIG_HIGH_MUX_P2NG;
break;

case A3:
next_mux_reg = CONFIG_HIGH_MUX_P3NG;
break;

default:
assert(false);
break;
}

buf[0] = CONFIG_HIGH_OS_START_SINGLE | next_mux_reg | CONFIG_HIGH_PGA_6144 | CONFIG_HIGH_MODE_SS;
uint8_t buf[2];
buf[0] = CONFIG_HIGH_OS_START_SINGLE | uint8_t(ch) | CONFIG_HIGH_PGA_6144 | CONFIG_HIGH_MODE_SS;
buf[1] = CONFIG_LOW_DR_250SPS | CONFIG_LOW_COMP_MODE_TRADITIONAL | CONFIG_LOW_COMP_POL_RESET |
CONFIG_LOW_COMP_LAT_NONE | CONFIG_LOW_COMP_QU_DISABLE;
return writeReg(ADDRESSPOINTER_REG_CONFIG, buf, 2); // must write whole register to take effect
}

bool ADS1115::isSampleReady()
int ADS1115::isSampleReady()
{
uint8_t buf[1] = {0x00};

if (readReg(ADDRESSPOINTER_REG_CONFIG, buf, 1) != 0) { return false; } // Pull config register
if (readReg(ADDRESSPOINTER_REG_CONFIG, buf, 1) != PX4_OK) { return -1; } // Pull config register

return (buf[0] & (uint8_t) 0x80);
return (buf[0] & (uint8_t) 0x80) ? 1 : 0;
}

ADS1115::ChannelSelection ADS1115::getMeasurement(int16_t *value)
ADS1115::Channel ADS1115::getMeasurement(int16_t *value)
{
uint8_t buf[2] = {0x00};
readReg(ADDRESSPOINTER_REG_CONFIG, buf, 1); // Pull config register
ChannelSelection channel;

switch ((buf[0] & (uint8_t) 0x70) >> 4) {
case 0x04:
channel = A0;
break;
if (readReg(ADDRESSPOINTER_REG_CONFIG, buf, 1) != PX4_OK) { return Channel::Invalid; }

case 0x05:
channel = A1;
break;
const auto channel{Channel(buf[0] & CONFIG_HIGH_MUX_P3NG)};

case 0x06:
channel = A2;
break;
if (readReg(ADDRESSPOINTER_REG_CONVERSATION, buf, 2) != PX4_OK) { return Channel::Invalid; }

case 0x07:
channel = A3;
break;
*value = int16_t((buf[0] << 8) | buf[1]);

default:
return Invalid;
}

readReg(ADDRESSPOINTER_REG_CONVERSATION, buf, 2);
uint16_t raw_adc_val = buf[0] * 256 + buf[1];

if (raw_adc_val & (uint16_t) 0x8000) { // Negetive value
raw_adc_val = ~raw_adc_val + 1; // 2's complement
*value = -raw_adc_val;

} else {
*value = raw_adc_val;
}

return channel;
}

ADS1115::ChannelSelection ADS1115::cycleMeasure(int16_t *value)
{
uint8_t buf[2] = {0x00};
readReg(ADDRESSPOINTER_REG_CONFIG, buf, 1); // Pull config register
ChannelSelection channel;
uint8_t next_mux_reg = CONFIG_HIGH_MUX_P0NG;

switch ((buf[0] & (uint8_t) 0x70) >> 4) {
case 0x04:
channel = A0;
next_mux_reg = CONFIG_HIGH_MUX_P1NG;
break;

case 0x05:
channel = A1;
next_mux_reg = CONFIG_HIGH_MUX_P2NG;
break;

case 0x06:
channel = A2;
next_mux_reg = CONFIG_HIGH_MUX_P3NG;
break;

case 0x07:
channel = A3;
next_mux_reg = CONFIG_HIGH_MUX_P0NG;
break;

default:
return Invalid;
}

readReg(ADDRESSPOINTER_REG_CONVERSATION, buf, 2);
uint16_t raw_adc_val = buf[0] * 256 + buf[1];

if (raw_adc_val & (uint16_t) 0x8000) { // Negetive value
raw_adc_val = ~raw_adc_val + 1; // 2's complement
*value = -raw_adc_val;

} else {
*value = raw_adc_val;
}

buf[0] = CONFIG_HIGH_OS_START_SINGLE | next_mux_reg | CONFIG_HIGH_PGA_6144 | CONFIG_HIGH_MODE_SS;
buf[1] = CONFIG_LOW_DR_250SPS | CONFIG_LOW_COMP_MODE_TRADITIONAL | CONFIG_LOW_COMP_POL_RESET |
CONFIG_LOW_COMP_LAT_NONE | CONFIG_LOW_COMP_QU_DISABLE;
writeReg(ADDRESSPOINTER_REG_CONFIG, buf, 2); // must write whole register to take effect
return channel;
}

Expand Down
39 changes: 20 additions & 19 deletions src/drivers/adc/ads1115/ADS1115.h
Original file line number Diff line number Diff line change
Expand Up @@ -93,9 +93,6 @@
#define CONFIG_LOW_COMP_QU_AFTER4 0x02
#define CONFIG_LOW_COMP_QU_DISABLE 0x03

#define CONFIG_RESET_VALUE_HIGH 0x85
#define CONFIG_RESET_VALUE_LOW 0x83

using namespace time_literals;

/*
Expand Down Expand Up @@ -127,35 +124,39 @@ class ADS1115 : public device::I2C, public I2CSPIDriver<ADS1115>

private:

uORB::PublicationMulti<adc_report_s> _to_adc_report{ORB_ID(adc_report)};
uORB::PublicationMulti<adc_report_s> _to_adc_report{ORB_ID(adc_report)};

static const hrt_abstime SAMPLE_INTERVAL{50_ms};
static const hrt_abstime SAMPLE_INTERVAL{50_ms};

adc_report_s _adc_report{};

perf_counter_t _cycle_perf;
perf_counter_t _cycle_perf;
perf_counter_t _comms_errors;

int _channel_cycle_count{0};
uint8_t _channel_cycle_mask{0};

bool _reported_ready_last_cycle{false};
static constexpr uint8_t MAX_READY_COUNTER{20};
uint8_t _ready_counter{MAX_READY_COUNTER};

// ADS1115 logic part
enum ChannelSelection {
Invalid = -1, A0 = 0, A1, A2, A3
enum class Channel : uint8_t {
A0 = CONFIG_HIGH_MUX_P0NG,
A1 = CONFIG_HIGH_MUX_P1NG,
A2 = CONFIG_HIGH_MUX_P2NG,
A3 = CONFIG_HIGH_MUX_P3NG,
Invalid = 0xff,
};
/* set multiplexer to specific channel */
int setChannel(ChannelSelection ch);
/* return true if sample result is valid */
bool isSampleReady();
constexpr unsigned ch2u(Channel ch) { return (unsigned(ch) >> 4) & 0b11u; }
constexpr Channel u2ch(unsigned ch) { return Channel((ch << 4) | CONFIG_HIGH_MUX_P0NG); }
// Set the channel and start a conversion
int readChannel(Channel ch);
// return 1 if sample result is valid else 0 or -1 if I2C transaction failed
int isSampleReady();
/*
* get adc sample. return the channel being measured.
* Invalid indicates sample failure.
*/
ChannelSelection getMeasurement(int16_t *value);
/*
* get adc sample and automatically switch to next channel and start another measurement
*/
ChannelSelection cycleMeasure(int16_t *value);
Channel getMeasurement(int16_t *value);

int readReg(uint8_t addr, uint8_t *buf, size_t len);

Expand Down
Loading
Loading