Working on directly publishing from ISR for ads1115_int. WIP (controller hangs)
This commit is contained in:
parent
a105cf0748
commit
20d2e5b4ef
@ -20,7 +20,7 @@ CONFIG_SCHEMA = (
|
||||
{
|
||||
cv.GenerateID(): cv.declare_id(ADS1115Component),
|
||||
cv.Required(CONF_ALERT_RDY_PIN): pins.internal_gpio_input_pin_schema,
|
||||
cv.Optional(CONF_CONTINUOUS_MODE, default=False): cv.boolean,
|
||||
# cv.Optional(CONF_CONTINUOUS_MODE, default=False): cv.boolean,
|
||||
}
|
||||
)
|
||||
.extend(cv.COMPONENT_SCHEMA)
|
||||
@ -37,4 +37,4 @@ async def to_code(config):
|
||||
)
|
||||
if alert_rdy is not None:
|
||||
cg.add(var.set_alert_pin(alert_rdy))
|
||||
cg.add(var.set_continuous_mode(config[CONF_CONTINUOUS_MODE]))
|
||||
# cg.add(var.set_continuous_mode(config[CONF_CONTINUOUS_MODE]))
|
||||
|
||||
@ -19,6 +19,7 @@ void ADS1115Component::setup() {
|
||||
this->mark_failed();
|
||||
return;
|
||||
}
|
||||
// setup with default values
|
||||
uint16_t config = 0;
|
||||
// Clear single-shot bit
|
||||
// 0b0xxxxxxxxxxxxxxx
|
||||
@ -71,6 +72,28 @@ void ADS1115Component::setup() {
|
||||
return;
|
||||
}
|
||||
}
|
||||
// Method to set mux data for later use, i.e. when data is to be read
|
||||
void ADS1115Component::set_mux_data(ADS1115Multiplexer multiplexer, ADS1115Gain gain, ADS1115Resolution resolution, ADS1115Samplerate samplerate, sensor::Sensor *sensor_ptr)
|
||||
{
|
||||
int index = -1;
|
||||
for(int i=0; i<4; i++) {
|
||||
if(this->muxdata_[i].multiplexer == multiplexer) {
|
||||
index = i;
|
||||
break;
|
||||
}
|
||||
if(this->muxdata_[i].multiplexer == ADS1115_MULTIPLEXER_INVALID && index == -1) {
|
||||
index = i;
|
||||
}
|
||||
}
|
||||
if(index != -1) {
|
||||
this->muxdata_[index].multiplexer = multiplexer;
|
||||
this->muxdata_[index].gain = gain;
|
||||
this->muxdata_[index].resolution = resolution;
|
||||
this->muxdata_[index].samplerate = samplerate;
|
||||
this->muxdata_[index].sensor_ptr = sensor_ptr;
|
||||
}
|
||||
}
|
||||
|
||||
bool ADS1115Component::set_data_ready_mode()
|
||||
{
|
||||
uint16_t config = this->prev_config_;
|
||||
@ -88,36 +111,44 @@ bool ADS1115Component::set_data_ready_mode()
|
||||
if(!this->write_byte_16(ADS1115_REGISTER_LO_TRESH, 0x0000)) {
|
||||
return false;
|
||||
}
|
||||
// also clear all data_ready_ flags
|
||||
for (int i = 0; i < 8; i++)
|
||||
this->data_ready_[i] = false;
|
||||
return true;
|
||||
}
|
||||
// ISR function to handle interrupt from alert pin
|
||||
// only function that sets data_ready_ flags
|
||||
void IRAM_ATTR ADS1115Component::isr(ADS1115Component *arg)
|
||||
{
|
||||
for (int i = 0; i < 8; i++)
|
||||
arg->data_ready_[i] = true;
|
||||
}
|
||||
bool ADS1115Component::is_data_ready(ADS1115Multiplexer multiplexer)
|
||||
{
|
||||
int index = static_cast<int>(multiplexer);
|
||||
if(index < 0 || index >= 8)
|
||||
return false;
|
||||
return this->data_ready_[index];
|
||||
}
|
||||
void ADS1115Component::clear_data_ready(ADS1115Multiplexer multiplexer)
|
||||
{
|
||||
int index = static_cast<int>(multiplexer);
|
||||
if(index < 0 || index >= 8)
|
||||
return;
|
||||
this->data_ready_[index] = false;
|
||||
arg->update_sensor();
|
||||
}
|
||||
|
||||
// call only when data_ready_ is true
|
||||
double ADS1115Component::read_data(int16_t& raw_value, ADS1115Multiplexer multiplexer, ADS1115Gain gain, ADS1115Resolution resolution, ADS1115Samplerate samplerate)
|
||||
void ADS1115Component::update_sensor() {
|
||||
int mux_index = this->mux_data_index_;
|
||||
ADS1115Multiplexer multiplexer = this->muxdata_[mux_index].multiplexer;
|
||||
if (multiplexer != ADS1115_MULTIPLEXER_INVALID) {
|
||||
int16_t raw_value = 0;
|
||||
double v = this->read_data(raw_value, mux_index);
|
||||
auto sensor_ptr = this->muxdata_[mux_index].sensor_ptr;
|
||||
if (!std::isnan(v)) {
|
||||
if(this->count_ % 10 == 0) {
|
||||
ESP_LOGI(TAG, "'% -18s': Raw=% 6d %fV", sensor_ptr->get_name().c_str(), raw_value, v);
|
||||
}
|
||||
this->count_++;
|
||||
ESP_LOGD(TAG, "'%s': Got Voltage=%fV", sensor_ptr->get_name().c_str(), v);
|
||||
sensor_ptr->publish_state(v);
|
||||
}
|
||||
}
|
||||
if(next_mux_data_index() != -1) {
|
||||
this->start_single_shot_conversion();
|
||||
}
|
||||
}
|
||||
|
||||
bool ADS1115Component::start_single_shot_conversion()
|
||||
{
|
||||
int mux_index = this->mux_data_index_;
|
||||
ADS1115Multiplexer multiplexer = this->muxdata_[mux_index].multiplexer;
|
||||
if (multiplexer != ADS1115_MULTIPLEXER_INVALID) {
|
||||
ADS1115Gain gain = this->muxdata_[mux_index].gain;
|
||||
ADS1115Resolution resolution = this->muxdata_[mux_index].resolution;
|
||||
ADS1115Samplerate samplerate = this->muxdata_[mux_index].samplerate;
|
||||
uint16_t config = this->prev_config_;
|
||||
// Multiplexer
|
||||
// 0bxBBBxxxxxxxxxxxx
|
||||
@ -134,36 +165,41 @@ double ADS1115Component::read_data(int16_t& raw_value, ADS1115Multiplexer multip
|
||||
config &= 0b1111111100011111;
|
||||
config |= (samplerate & 0b111) << 5;
|
||||
|
||||
if (!this->continuous_mode_) {
|
||||
// Start conversion
|
||||
config |= 0b1000000000000000;
|
||||
}
|
||||
|
||||
this->clear_data_ready(multiplexer);
|
||||
//ESP_LOGI(TAG, "'mux:%d': Gain=%d, Res=%d, CONF=<0x%04X>", static_cast<int>(multiplexer), static_cast<int>(gain), static_cast<int>(resolution), config);
|
||||
// write config if in single-shot mode or config has changed
|
||||
if (!this->continuous_mode_ || this->prev_config_ != config) {
|
||||
if (!this->write_byte_16(ADS1115_REGISTER_CONFIG, config)) {
|
||||
this->status_set_warning();
|
||||
return false;
|
||||
}
|
||||
this->prev_config_ = config;
|
||||
//
|
||||
// removed delay
|
||||
//
|
||||
if (!this->continuous_mode_) {
|
||||
uint32_t start = millis();
|
||||
// wait for conversion to complete
|
||||
while (this->read_byte_16(ADS1115_REGISTER_CONFIG, &config) && (config >> 15) == 0) {
|
||||
if (millis() - start > 100) {
|
||||
ESP_LOGW(TAG, "Reading ADS1115 timed out");
|
||||
this->status_set_warning();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
int ADS1115Component::next_mux_data_index()
|
||||
{
|
||||
int start_index = this->mux_data_index_;
|
||||
do {
|
||||
this->mux_data_index_ = (this->mux_data_index_ + 1) % 4;
|
||||
if(this->muxdata_[this->mux_data_index_].multiplexer != ADS1115_MULTIPLEXER_INVALID) {
|
||||
return this->mux_data_index_;
|
||||
}
|
||||
} while(this->mux_data_index_ != start_index);
|
||||
return -1; // no valid mux data found
|
||||
}
|
||||
// call only when data_ready_ is true
|
||||
double ADS1115Component::read_data(int16_t& raw_value, int mux_index)
|
||||
{
|
||||
ADS1115Multiplexer multiplexer = this->muxdata_[mux_index].multiplexer;
|
||||
raw_value = 0;
|
||||
if(multiplexer == ADS1115_MULTIPLEXER_INVALID) {
|
||||
ESP_LOGE(TAG, "MUX data not set for index %d", mux_index);
|
||||
return NAN;
|
||||
}
|
||||
yield();
|
||||
}
|
||||
}
|
||||
}
|
||||
ADS1115Gain gain = this->muxdata_[mux_index].gain;
|
||||
ADS1115Resolution resolution = this->muxdata_[mux_index].resolution;
|
||||
|
||||
uint16_t raw_conversion;
|
||||
if (!this->read_byte_16(ADS1115_REGISTER_CONVERSION, &raw_conversion)) {
|
||||
this->status_set_warning();
|
||||
|
||||
@ -2,6 +2,7 @@
|
||||
|
||||
#include "esphome/components/i2c/i2c.h" // Ensure this header defines i2c::I2CDevice
|
||||
#include "esphome/core/component.h" // Ensure this header defines Component
|
||||
#include "esphome/components/sensor/sensor.h"
|
||||
|
||||
#include <vector>
|
||||
#include <esphome/core/gpio.h>
|
||||
@ -18,6 +19,7 @@ enum ADS1115Multiplexer {
|
||||
ADS1115_MULTIPLEXER_P1_NG = 0b101,
|
||||
ADS1115_MULTIPLEXER_P2_NG = 0b110,
|
||||
ADS1115_MULTIPLEXER_P3_NG = 0b111,
|
||||
ADS1115_MULTIPLEXER_INVALID = 0xFF
|
||||
};
|
||||
|
||||
enum ADS1115Gain {
|
||||
@ -46,25 +48,41 @@ enum ADS1115Samplerate {
|
||||
};
|
||||
|
||||
class ADS1115Component : public Component, public i2c::I2CDevice {
|
||||
private:
|
||||
struct mux_data_item {
|
||||
ADS1115Multiplexer multiplexer;
|
||||
ADS1115Gain gain;
|
||||
ADS1115Resolution resolution;
|
||||
ADS1115Samplerate samplerate;
|
||||
sensor::Sensor *sensor_ptr; // ADS1115Sensor *sensor_ptr
|
||||
mux_data_item() { multiplexer = ADS1115_MULTIPLEXER_INVALID; }
|
||||
};
|
||||
void request_data();
|
||||
int next_mux_data_index();
|
||||
void update_sensor();
|
||||
int mux_data_index_{0};
|
||||
mux_data_item muxdata_[4];
|
||||
uint64_t count_{0};
|
||||
|
||||
public:
|
||||
void setup() override;
|
||||
void dump_config() override;
|
||||
/// HARDWARE_LATE setup priority
|
||||
void set_continuous_mode(bool continuous_mode) { continuous_mode_ = continuous_mode; }
|
||||
// we will force single-shot mode for interrupt operation; kept continuous_mode_ for ease of reversal if needed
|
||||
//void set_continuous_mode(bool continuous_mode) { continuous_mode_ = continuous_mode; }
|
||||
|
||||
// Method to read converted data
|
||||
double read_data(int16_t& raw_value, ADS1115Multiplexer multiplexer, ADS1115Gain gain, ADS1115Resolution resolution, ADS1115Samplerate samplerate);
|
||||
double read_data(int16_t& raw_value, int mux_index);
|
||||
bool start_single_shot_conversion();
|
||||
void set_alert_pin(InternalGPIOPin *pin) { alert_pin_ = pin; }
|
||||
bool set_data_ready_mode();
|
||||
bool is_data_ready(ADS1115Multiplexer multiplexer);
|
||||
void clear_data_ready(ADS1115Multiplexer multiplexer);
|
||||
void set_mux_data(ADS1115Multiplexer multiplexer, ADS1115Gain gain, ADS1115Resolution resolution, ADS1115Samplerate samplerate, sensor::Sensor *sensor_ptr);
|
||||
|
||||
protected:
|
||||
uint16_t prev_config_{0};
|
||||
bool continuous_mode_;
|
||||
bool continuous_mode_{false};
|
||||
InternalGPIOPin *alert_pin_;
|
||||
static void isr(ADS1115Component *arg);
|
||||
volatile bool data_ready_[8]{false};
|
||||
|
||||
};
|
||||
|
||||
|
||||
@ -8,19 +8,13 @@ namespace ads1115_int {
|
||||
static const char *const TAG = "ads1115_int.sensor";
|
||||
|
||||
void ADS1115Sensor::loop() {
|
||||
if (parent_->is_data_ready(this->multiplexer_)) {
|
||||
this->parent_->clear_data_ready(this->multiplexer_);
|
||||
int16_t raw_value = -1000;
|
||||
double v = this->parent_->read_data(raw_value, this->multiplexer_, this->gain_, this->resolution_, this->samplerate_);
|
||||
if (!std::isnan(v)) {
|
||||
if(this->count_ % 10 == 0) {
|
||||
ESP_LOGI(TAG, "'% -18s': Raw=% 6d %fV", this->get_name().c_str(), raw_value, v);
|
||||
}
|
||||
this->count_++;
|
||||
ESP_LOGD(TAG, "'%s': Got Voltage=%fV", this->get_name().c_str(), v);
|
||||
this->publish_state(v);
|
||||
}
|
||||
if(this->first_reading_) {
|
||||
this->parent_->set_mux_data(this->multiplexer_, this->gain_, this->resolution_, this->samplerate_, this);
|
||||
//delay(100);
|
||||
this->first_reading_ = false;
|
||||
this->parent_->start_single_shot_conversion(); // this will set off the first conversion; subsequent conversions will be triggered by the ISR
|
||||
}
|
||||
// Data reading and publishing is handled in the parent component's update_sensor() method
|
||||
}
|
||||
|
||||
void ADS1115Sensor::dump_config() {
|
||||
|
||||
@ -30,7 +30,7 @@ class ADS1115Sensor : public sensor::Sensor,
|
||||
ADS1115Gain gain_;
|
||||
ADS1115Resolution resolution_;
|
||||
ADS1115Samplerate samplerate_;
|
||||
uint64_t count_{0};
|
||||
bool first_reading_{true};
|
||||
};
|
||||
|
||||
} // namespace ads1115
|
||||
|
||||
@ -274,7 +274,6 @@ ads1115_pol:
|
||||
ads1115_int:
|
||||
- address: 0x48
|
||||
id: ads1115_48
|
||||
continuous_mode: true
|
||||
alert_rdy_pin:
|
||||
number: GPIO3
|
||||
mode:
|
||||
|
||||
Loading…
Reference in New Issue
Block a user