ESPHome  2024.3.1
ads1115.cpp
Go to the documentation of this file.
1 #include "ads1115.h"
2 #include "esphome/core/log.h"
3 #include "esphome/core/hal.h"
4 
5 namespace esphome {
6 namespace ads1115 {
7 
8 static const char *const TAG = "ads1115";
9 static const uint8_t ADS1115_REGISTER_CONVERSION = 0x00;
10 static const uint8_t ADS1115_REGISTER_CONFIG = 0x01;
11 
12 static const uint8_t ADS1115_DATA_RATE_860_SPS = 0b111; // 3300_SPS for ADS1015
13 
15  ESP_LOGCONFIG(TAG, "Setting up ADS1115...");
16  uint16_t value;
17  if (!this->read_byte_16(ADS1115_REGISTER_CONVERSION, &value)) {
18  this->mark_failed();
19  return;
20  }
21 
22  ESP_LOGCONFIG(TAG, "Configuring ADS1115...");
23 
24  uint16_t config = 0;
25  // Clear single-shot bit
26  // 0b0xxxxxxxxxxxxxxx
27  config |= 0b0000000000000000;
28  // Setup multiplexer
29  // 0bx000xxxxxxxxxxxx
30  config |= ADS1115_MULTIPLEXER_P0_N1 << 12;
31 
32  // Setup Gain
33  // 0bxxxx000xxxxxxxxx
34  config |= ADS1115_GAIN_6P144 << 9;
35 
36  if (this->continuous_mode_) {
37  // Set continuous mode
38  // 0bxxxxxxx0xxxxxxxx
39  config |= 0b0000000000000000;
40  } else {
41  // Set singleshot mode
42  // 0bxxxxxxx1xxxxxxxx
43  config |= 0b0000000100000000;
44  }
45 
46  // Set data rate - 860 samples per second (we're in singleshot mode)
47  // 0bxxxxxxxx100xxxxx
48  config |= ADS1115_DATA_RATE_860_SPS << 5;
49 
50  // Set comparator mode - hysteresis
51  // 0bxxxxxxxxxxx0xxxx
52  config |= 0b0000000000000000;
53 
54  // Set comparator polarity - active low
55  // 0bxxxxxxxxxxxx0xxx
56  config |= 0b0000000000000000;
57 
58  // Set comparator latch enabled - false
59  // 0bxxxxxxxxxxxxx0xx
60  config |= 0b0000000000000000;
61 
62  // Set comparator que mode - disabled
63  // 0bxxxxxxxxxxxxxx11
64  config |= 0b0000000000000011;
65 
66  if (!this->write_byte_16(ADS1115_REGISTER_CONFIG, config)) {
67  this->mark_failed();
68  return;
69  }
70  this->prev_config_ = config;
71 }
73  ESP_LOGCONFIG(TAG, "Setting up ADS1115...");
74  LOG_I2C_DEVICE(this);
75  if (this->is_failed()) {
76  ESP_LOGE(TAG, "Communication with ADS1115 failed!");
77  }
78 
79  for (auto *sensor : this->sensors_) {
80  LOG_SENSOR(" ", "Sensor", sensor);
81  ESP_LOGCONFIG(TAG, " Multiplexer: %u", sensor->get_multiplexer());
82  ESP_LOGCONFIG(TAG, " Gain: %u", sensor->get_gain());
83  ESP_LOGCONFIG(TAG, " Resolution: %u", sensor->get_resolution());
84  }
85 }
87  uint16_t config = this->prev_config_;
88  // Multiplexer
89  // 0bxBBBxxxxxxxxxxxx
90  config &= 0b1000111111111111;
91  config |= (sensor->get_multiplexer() & 0b111) << 12;
92 
93  // Gain
94  // 0bxxxxBBBxxxxxxxxx
95  config &= 0b1111000111111111;
96  config |= (sensor->get_gain() & 0b111) << 9;
97 
98  if (!this->continuous_mode_) {
99  // Start conversion
100  config |= 0b1000000000000000;
101  }
102 
103  if (!this->continuous_mode_ || this->prev_config_ != config) {
104  if (!this->write_byte_16(ADS1115_REGISTER_CONFIG, config)) {
105  this->status_set_warning();
106  return NAN;
107  }
108  this->prev_config_ = config;
109 
110  // about 1.2 ms with 860 samples per second
111  delay(2);
112 
113  // in continuous mode, conversion will always be running, rely on the delay
114  // to ensure conversion is taking place with the correct settings
115  // can we use the rdy pin to trigger when a conversion is done?
116  if (!this->continuous_mode_) {
117  uint32_t start = millis();
118  while (this->read_byte_16(ADS1115_REGISTER_CONFIG, &config) && (config >> 15) == 0) {
119  if (millis() - start > 100) {
120  ESP_LOGW(TAG, "Reading ADS1115 timed out");
121  this->status_set_warning();
122  return NAN;
123  }
124  yield();
125  }
126  }
127  }
128 
129  uint16_t raw_conversion;
130  if (!this->read_byte_16(ADS1115_REGISTER_CONVERSION, &raw_conversion)) {
131  this->status_set_warning();
132  return NAN;
133  }
134 
135  if (sensor->get_resolution() == ADS1015_12_BITS) {
136  bool negative = (raw_conversion >> 15) == 1;
137 
138  // shift raw_conversion as it's only 12-bits, left justified
139  raw_conversion = raw_conversion >> (16 - ADS1015_12_BITS);
140 
141  // check if number was negative in order to keep the sign
142  if (negative) {
143  // the number was negative
144  // 1) set the negative bit back
145  raw_conversion |= 0x8000;
146  // 2) reset the former (shifted) negative bit
147  raw_conversion &= 0xF7FF;
148  }
149  }
150 
151  auto signed_conversion = static_cast<int16_t>(raw_conversion);
152 
153  float millivolts;
154  float divider = (sensor->get_resolution() == ADS1115_16_BITS) ? 32768.0f : 2048.0f;
155  switch (sensor->get_gain()) {
156  case ADS1115_GAIN_6P144:
157  millivolts = (signed_conversion * 6144) / divider;
158  break;
159  case ADS1115_GAIN_4P096:
160  millivolts = (signed_conversion * 4096) / divider;
161  break;
162  case ADS1115_GAIN_2P048:
163  millivolts = (signed_conversion * 2048) / divider;
164  break;
165  case ADS1115_GAIN_1P024:
166  millivolts = (signed_conversion * 1024) / divider;
167  break;
168  case ADS1115_GAIN_0P512:
169  millivolts = (signed_conversion * 512) / divider;
170  break;
171  case ADS1115_GAIN_0P256:
172  millivolts = (signed_conversion * 256) / divider;
173  break;
174  default:
175  millivolts = NAN;
176  }
177 
178  this->status_clear_warning();
179  return millivolts / 1e3f;
180 }
181 
182 float ADS1115Sensor::sample() { return this->parent_->request_measurement(this); }
184  float v = this->parent_->request_measurement(this);
185  if (!std::isnan(v)) {
186  ESP_LOGD(TAG, "'%s': Got Voltage=%fV", this->get_name().c_str(), v);
187  this->publish_state(v);
188  }
189 }
190 
191 } // namespace ads1115
192 } // namespace esphome
bool read_byte_16(uint8_t a_register, uint16_t *data)
Definition: i2c.h:246
void status_set_warning(const char *message="unspecified")
Definition: component.cpp:146
uint8_t get_multiplexer() const
Definition: ads1115.h:68
float request_measurement(ADS1115Sensor *sensor)
Helper method to request a measurement from a sensor.
Definition: ads1115.cpp:86
uint8_t get_resolution() const
Definition: ads1115.h:70
uint32_t IRAM_ATTR HOT millis()
Definition: core.cpp:25
Internal holder class that is in instance of Sensor so that the hub can create individual sensors...
Definition: ads1115.h:60
void status_clear_warning()
Definition: component.cpp:161
uint8_t get_gain() const
Definition: ads1115.h:69
void IRAM_ATTR HOT yield()
Definition: core.cpp:24
std::vector< ADS1115Sensor * > sensors_
Definition: ads1115.h:54
virtual void mark_failed()
Mark this component as failed.
Definition: component.cpp:113
void setup() override
Set up the internal sensor array.
Definition: ads1115.cpp:14
This is a workaround until we can figure out a way to get the tflite-micro idf component code availab...
Definition: a01nyub.cpp:7
bool write_byte_16(uint8_t a_register, uint16_t data)
Definition: i2c.h:266
void IRAM_ATTR HOT delay(uint32_t ms)
Definition: core.cpp:26