#include "ads1115_int.h" #include "esphome/core/hal.h" #include "esphome/core/log.h" namespace esphome { namespace ads1115_int { static const char *const TAG = "ads1115_int"; static const uint8_t ADS1115_REGISTER_CONVERSION = 0x00; static const uint8_t ADS1115_REGISTER_CONFIG = 0x01; static const uint8_t ADS1115_REGISTER_LO_TRESH = 0x02; static const uint8_t ADS1115_REGISTER_HI_TRESH = 0x03; void ADS1115Component::setup() { uint16_t value; this->alert_pin_->setup(); this->alert_pin_->attach_interrupt(&ADS1115Component::isr, this, gpio::INTERRUPT_FALLING_EDGE); if (!this->read_byte_16(ADS1115_REGISTER_CONVERSION, &value)) { this->mark_failed(); return; } uint16_t config = 0; // Clear single-shot bit // 0b0xxxxxxxxxxxxxxx config |= 0b0000000000000000; // Setup multiplexer // 0bx000xxxxxxxxxxxx config |= ADS1115_MULTIPLEXER_P0_N1 << 12; // Setup Gain // 0bxxxx000xxxxxxxxx config |= ADS1115_GAIN_6P144 << 9; if (this->continuous_mode_) { // Set continuous mode // 0bxxxxxxx0xxxxxxxx config |= 0b0000000000000000; } else { // Set singleshot mode // 0bxxxxxxx1xxxxxxxx config |= 0b0000000100000000; } // Set data rate - 860 samples per second // 0bxxxxxxxx100xxxxx config |= ADS1115_860SPS << 5; // Set comparator mode - hysteresis // 0bxxxxxxxxxxx0xxxx config |= 0b0000000000000000; // Set comparator polarity - active low // 0bxxxxxxxxxxxx0xxx config |= 0b0000000000000000; // Set comparator latch enabled - false // 0bxxxxxxxxxxxxx0xx config |= 0b0000000000000000; // Set comparator que mode - disabled // 0bxxxxxxxxxxxxxx11 config |= 0b0000000000000011; if (!this->write_byte_16(ADS1115_REGISTER_CONFIG, config)) { this->mark_failed(); return; } this->prev_config_ = config; if(!this->set_data_ready_mode()) { this->mark_failed(); return; } } bool ADS1115Component::set_data_ready_mode() { uint16_t config = this->prev_config_; // Set comparator que mode - assert after one conversion // 0bxxxxxxxxxxxxxx00 config &= 0b1111111111111100; if (!this->write_byte_16(ADS1115_REGISTER_CONFIG, config)) { return false; } this->prev_config_ = config; if(!this->write_byte_16(ADS1115_REGISTER_HI_TRESH, 0x8000)) { return false; } 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(multiplexer); if(index < 0 || index >= 8) return false; return this->data_ready_[index]; } void ADS1115Component::clear_data_ready(ADS1115Multiplexer multiplexer) { int index = static_cast(multiplexer); if(index < 0 || index >= 8) return; this->data_ready_[index] = false; } // call only when data_ready_ is true double ADS1115Component::read_data(int16_t& raw_value, ADS1115Multiplexer multiplexer, ADS1115Gain gain, ADS1115Resolution resolution, ADS1115Samplerate samplerate) { uint16_t config = this->prev_config_; // Multiplexer // 0bxBBBxxxxxxxxxxxx config &= 0b1000111111111111; config |= (multiplexer & 0b111) << 12; // Gain // 0bxxxxBBBxxxxxxxxx config &= 0b1111000111111111; config |= (gain & 0b111) << 9; // Sample rate // 0bxxxxxxxxBBBxxxxx 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(multiplexer), static_cast(gain), static_cast(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 NAN; } yield(); } } } uint16_t raw_conversion; if (!this->read_byte_16(ADS1115_REGISTER_CONVERSION, &raw_conversion)) { this->status_set_warning(); return NAN; } //ESP_LOGI(TAG, "'mux:%d': raw=<0x%04X>", static_cast(multiplexer), raw_conversion); if (resolution == ADS1015_12_BITS) { bool negative = (raw_conversion >> 15) == 1; // shift raw_conversion as it's only 12-bits, left justified raw_conversion = raw_conversion >> (16 - ADS1015_12_BITS); // check if number was negative in order to keep the sign if (negative) { // the number was negative // 1) set the negative bit back raw_conversion |= 0x8000; // 2) reset the former (shifted) negative bit raw_conversion &= 0xF7FF; } } auto signed_conversion = static_cast(raw_conversion); raw_value = signed_conversion; double millivolts; double divider = (resolution == ADS1115_16_BITS) ? 32768.0f : 2048.0f; switch (gain) { case ADS1115_GAIN_6P144: millivolts = (signed_conversion * 6144) / divider; break; case ADS1115_GAIN_4P096: millivolts = (signed_conversion * 4096) / divider; break; case ADS1115_GAIN_2P048: millivolts = (signed_conversion * 2048) / divider; break; case ADS1115_GAIN_1P024: millivolts = (signed_conversion * 1024) / divider; break; case ADS1115_GAIN_0P512: millivolts = (signed_conversion * 512) / divider; break; case ADS1115_GAIN_0P256: millivolts = (signed_conversion * 256) / divider; break; default: millivolts = NAN; } this->status_clear_warning(); return millivolts / 1e3f; } void ADS1115Component::dump_config() { ESP_LOGCONFIG(TAG, "ADS1115_INT:"); LOG_I2C_DEVICE(this); LOG_PIN(" ALERT Pin:", this->alert_pin_); if (this->is_failed()) { ESP_LOGE(TAG, ESP_LOG_MSG_COMM_FAIL); } } } // namespace ads1115_int } // namespace esphome