ESPHome  2023.11.6
i2c_bus_esp_idf.cpp
Go to the documentation of this file.
1 #ifdef USE_ESP_IDF
2 
3 #include "i2c_bus_esp_idf.h"
4 #include "esphome/core/hal.h"
5 #include "esphome/core/log.h"
6 #include "esphome/core/helpers.h"
8 #include <cstring>
9 #include <cinttypes>
10 
11 namespace esphome {
12 namespace i2c {
13 
14 static const char *const TAG = "i2c.idf";
15 
17  ESP_LOGCONFIG(TAG, "Setting up I2C bus...");
18  static i2c_port_t next_port = I2C_NUM_0;
19  port_ = next_port;
20 #if I2C_NUM_MAX > 1
21  next_port = (next_port == I2C_NUM_0) ? I2C_NUM_1 : I2C_NUM_MAX;
22 #else
23  next_port = I2C_NUM_MAX;
24 #endif
25 
26  if (port_ == I2C_NUM_MAX) {
27  ESP_LOGE(TAG, "Too many I2C buses configured");
28  this->mark_failed();
29  return;
30  }
31 
32  recover_();
33 
34  i2c_config_t conf{};
35  memset(&conf, 0, sizeof(conf));
36  conf.mode = I2C_MODE_MASTER;
37  conf.sda_io_num = sda_pin_;
38  conf.sda_pullup_en = sda_pullup_enabled_;
39  conf.scl_io_num = scl_pin_;
40  conf.scl_pullup_en = scl_pullup_enabled_;
41  conf.master.clk_speed = frequency_;
42  esp_err_t err = i2c_param_config(port_, &conf);
43  if (err != ESP_OK) {
44  ESP_LOGW(TAG, "i2c_param_config failed: %s", esp_err_to_name(err));
45  this->mark_failed();
46  return;
47  }
48  err = i2c_driver_install(port_, I2C_MODE_MASTER, 0, 0, ESP_INTR_FLAG_IRAM);
49  if (err != ESP_OK) {
50  ESP_LOGW(TAG, "i2c_driver_install failed: %s", esp_err_to_name(err));
51  this->mark_failed();
52  return;
53  }
54  initialized_ = true;
55  if (this->scan_) {
56  ESP_LOGV(TAG, "Scanning i2c bus for active devices...");
57  this->i2c_scan_();
58  }
59 }
61  ESP_LOGCONFIG(TAG, "I2C Bus:");
62  ESP_LOGCONFIG(TAG, " SDA Pin: GPIO%u", this->sda_pin_);
63  ESP_LOGCONFIG(TAG, " SCL Pin: GPIO%u", this->scl_pin_);
64  ESP_LOGCONFIG(TAG, " Frequency: %" PRIu32 " Hz", this->frequency_);
65  switch (this->recovery_result_) {
66  case RECOVERY_COMPLETED:
67  ESP_LOGCONFIG(TAG, " Recovery: bus successfully recovered");
68  break;
70  ESP_LOGCONFIG(TAG, " Recovery: failed, SCL is held low on the bus");
71  break;
73  ESP_LOGCONFIG(TAG, " Recovery: failed, SDA is held low on the bus");
74  break;
75  }
76  if (this->scan_) {
77  ESP_LOGI(TAG, "Results from i2c bus scan:");
78  if (scan_results_.empty()) {
79  ESP_LOGI(TAG, "Found no i2c devices!");
80  } else {
81  for (const auto &s : scan_results_) {
82  if (s.second) {
83  ESP_LOGI(TAG, "Found i2c device at address 0x%02X", s.first);
84  } else {
85  ESP_LOGE(TAG, "Unknown error at address 0x%02X", s.first);
86  }
87  }
88  }
89  }
90 }
91 
92 ErrorCode IDFI2CBus::readv(uint8_t address, ReadBuffer *buffers, size_t cnt) {
93  // logging is only enabled with vv level, if warnings are shown the caller
94  // should log them
95  if (!initialized_) {
96  ESP_LOGVV(TAG, "i2c bus not initialized!");
97  return ERROR_NOT_INITIALIZED;
98  }
99  i2c_cmd_handle_t cmd = i2c_cmd_link_create();
100  esp_err_t err = i2c_master_start(cmd);
101  if (err != ESP_OK) {
102  ESP_LOGVV(TAG, "RX from %02X master start failed: %s", address, esp_err_to_name(err));
103  i2c_cmd_link_delete(cmd);
104  return ERROR_UNKNOWN;
105  }
106  err = i2c_master_write_byte(cmd, (address << 1) | I2C_MASTER_READ, true);
107  if (err != ESP_OK) {
108  ESP_LOGVV(TAG, "RX from %02X address write failed: %s", address, esp_err_to_name(err));
109  i2c_cmd_link_delete(cmd);
110  return ERROR_UNKNOWN;
111  }
112  for (size_t i = 0; i < cnt; i++) {
113  const auto &buf = buffers[i];
114  if (buf.len == 0)
115  continue;
116  err = i2c_master_read(cmd, buf.data, buf.len, i == cnt - 1 ? I2C_MASTER_LAST_NACK : I2C_MASTER_ACK);
117  if (err != ESP_OK) {
118  ESP_LOGVV(TAG, "RX from %02X data read failed: %s", address, esp_err_to_name(err));
119  i2c_cmd_link_delete(cmd);
120  return ERROR_UNKNOWN;
121  }
122  }
123  err = i2c_master_stop(cmd);
124  if (err != ESP_OK) {
125  ESP_LOGVV(TAG, "RX from %02X stop failed: %s", address, esp_err_to_name(err));
126  i2c_cmd_link_delete(cmd);
127  return ERROR_UNKNOWN;
128  }
129  err = i2c_master_cmd_begin(port_, cmd, 20 / portTICK_PERIOD_MS);
130  i2c_cmd_link_delete(cmd);
131  if (err == ESP_FAIL) {
132  // transfer not acked
133  ESP_LOGVV(TAG, "RX from %02X failed: not acked", address);
134  return ERROR_NOT_ACKNOWLEDGED;
135  } else if (err == ESP_ERR_TIMEOUT) {
136  ESP_LOGVV(TAG, "RX from %02X failed: timeout", address);
137  return ERROR_TIMEOUT;
138  } else if (err != ESP_OK) {
139  ESP_LOGVV(TAG, "RX from %02X failed: %s", address, esp_err_to_name(err));
140  return ERROR_UNKNOWN;
141  }
142 
143 #ifdef ESPHOME_LOG_HAS_VERY_VERBOSE
144  char debug_buf[4];
145  std::string debug_hex;
146 
147  for (size_t i = 0; i < cnt; i++) {
148  const auto &buf = buffers[i];
149  for (size_t j = 0; j < buf.len; j++) {
150  snprintf(debug_buf, sizeof(debug_buf), "%02X", buf.data[j]);
151  debug_hex += debug_buf;
152  }
153  }
154  ESP_LOGVV(TAG, "0x%02X RX %s", address, debug_hex.c_str());
155 #endif
156 
157  return ERROR_OK;
158 }
159 ErrorCode IDFI2CBus::writev(uint8_t address, WriteBuffer *buffers, size_t cnt, bool stop) {
160  // logging is only enabled with vv level, if warnings are shown the caller
161  // should log them
162  if (!initialized_) {
163  ESP_LOGVV(TAG, "i2c bus not initialized!");
164  return ERROR_NOT_INITIALIZED;
165  }
166 
167 #ifdef ESPHOME_LOG_HAS_VERY_VERBOSE
168  char debug_buf[4];
169  std::string debug_hex;
170 
171  for (size_t i = 0; i < cnt; i++) {
172  const auto &buf = buffers[i];
173  for (size_t j = 0; j < buf.len; j++) {
174  snprintf(debug_buf, sizeof(debug_buf), "%02X", buf.data[j]);
175  debug_hex += debug_buf;
176  }
177  }
178  ESP_LOGVV(TAG, "0x%02X TX %s", address, debug_hex.c_str());
179 #endif
180 
181  i2c_cmd_handle_t cmd = i2c_cmd_link_create();
182  esp_err_t err = i2c_master_start(cmd);
183  if (err != ESP_OK) {
184  ESP_LOGVV(TAG, "TX to %02X master start failed: %s", address, esp_err_to_name(err));
185  i2c_cmd_link_delete(cmd);
186  return ERROR_UNKNOWN;
187  }
188  err = i2c_master_write_byte(cmd, (address << 1) | I2C_MASTER_WRITE, true);
189  if (err != ESP_OK) {
190  ESP_LOGVV(TAG, "TX to %02X address write failed: %s", address, esp_err_to_name(err));
191  i2c_cmd_link_delete(cmd);
192  return ERROR_UNKNOWN;
193  }
194  for (size_t i = 0; i < cnt; i++) {
195  const auto &buf = buffers[i];
196  if (buf.len == 0)
197  continue;
198  err = i2c_master_write(cmd, buf.data, buf.len, true);
199  if (err != ESP_OK) {
200  ESP_LOGVV(TAG, "TX to %02X data write failed: %s", address, esp_err_to_name(err));
201  i2c_cmd_link_delete(cmd);
202  return ERROR_UNKNOWN;
203  }
204  }
205  if (stop) {
206  err = i2c_master_stop(cmd);
207  if (err != ESP_OK) {
208  ESP_LOGVV(TAG, "TX to %02X master stop failed: %s", address, esp_err_to_name(err));
209  i2c_cmd_link_delete(cmd);
210  return ERROR_UNKNOWN;
211  }
212  }
213  err = i2c_master_cmd_begin(port_, cmd, 20 / portTICK_PERIOD_MS);
214  i2c_cmd_link_delete(cmd);
215  if (err == ESP_FAIL) {
216  // transfer not acked
217  ESP_LOGVV(TAG, "TX to %02X failed: not acked", address);
218  return ERROR_NOT_ACKNOWLEDGED;
219  } else if (err == ESP_ERR_TIMEOUT) {
220  ESP_LOGVV(TAG, "TX to %02X failed: timeout", address);
221  return ERROR_TIMEOUT;
222  } else if (err != ESP_OK) {
223  ESP_LOGVV(TAG, "TX to %02X failed: %s", address, esp_err_to_name(err));
224  return ERROR_UNKNOWN;
225  }
226  return ERROR_OK;
227 }
228 
232 void IDFI2CBus::recover_() {
233  ESP_LOGI(TAG, "Performing I2C bus recovery");
234 
235  const gpio_num_t scl_pin = static_cast<gpio_num_t>(scl_pin_);
236  const gpio_num_t sda_pin = static_cast<gpio_num_t>(sda_pin_);
237 
238  // For the upcoming operations, target for a 60kHz toggle frequency.
239  // 1000kHz is the maximum frequency for I2C running in standard-mode,
240  // but lower frequencies are not a problem.
241  // Note: the timing that is used here is chosen manually, to get
242  // results that are close to the timing that can be archieved by the
243  // implementation for the Arduino framework.
244  const auto half_period_usec = 7;
245 
246  // Configure SCL pin for open drain input/output, with a pull up resistor.
247  gpio_set_level(scl_pin, 1);
248  gpio_config_t scl_config{};
249  scl_config.pin_bit_mask = 1ULL << scl_pin_;
250  scl_config.mode = GPIO_MODE_INPUT_OUTPUT_OD;
251  scl_config.pull_up_en = GPIO_PULLUP_ENABLE;
252  scl_config.pull_down_en = GPIO_PULLDOWN_DISABLE;
253  scl_config.intr_type = GPIO_INTR_DISABLE;
254  gpio_config(&scl_config);
255 
256  // Configure SDA pin for open drain input/output, with a pull up resistor.
257  gpio_set_level(sda_pin, 1);
258  gpio_config_t sda_conf{};
259  sda_conf.pin_bit_mask = 1ULL << sda_pin_;
260  sda_conf.mode = GPIO_MODE_INPUT_OUTPUT_OD;
261  sda_conf.pull_up_en = GPIO_PULLUP_ENABLE;
262  sda_conf.pull_down_en = GPIO_PULLDOWN_DISABLE;
263  sda_conf.intr_type = GPIO_INTR_DISABLE;
264  gpio_config(&sda_conf);
265 
266  // If SCL is pulled low on the I2C bus, then some device is interfering
267  // with the SCL line. In that case, the I2C bus cannot be recovered.
268  delayMicroseconds(half_period_usec);
269  if (gpio_get_level(scl_pin) == 0) {
270  ESP_LOGE(TAG, "Recovery failed: SCL is held LOW on the I2C bus");
271  recovery_result_ = RECOVERY_FAILED_SCL_LOW;
272  return;
273  }
274 
275  // From the specification:
276  // "If the data line (SDA) is stuck LOW, send nine clock pulses. The
277  // device that held the bus LOW should release it sometime within
278  // those nine clocks."
279  // We don't really have to detect if SDA is stuck low. We'll simply send
280  // nine clock pulses here, just in case SDA is stuck. Actual checks on
281  // the SDA line status will be done after the clock pulses.
282  for (auto i = 0; i < 9; i++) {
283  gpio_set_level(scl_pin, 0);
284  delayMicroseconds(half_period_usec);
285  gpio_set_level(scl_pin, 1);
286  delayMicroseconds(half_period_usec);
287 
288  // When SCL is kept LOW at this point, we might be looking at a device
289  // that applies clock stretching. Wait for the release of the SCL line,
290  // but not forever. There is no specification for the maximum allowed
291  // time. We yield and reset the WDT, so as to avoid triggering reset.
292  // No point in trying to recover the bus by forcing a uC reset. Bus
293  // should recover in a few ms or less else not likely to recovery at
294  // all.
295  auto wait = 250;
296  while (wait-- && gpio_get_level(scl_pin) == 0) {
297  App.feed_wdt();
298  delayMicroseconds(half_period_usec * 2);
299  }
300  if (gpio_get_level(scl_pin) == 0) {
301  ESP_LOGE(TAG, "Recovery failed: SCL is held LOW during clock pulse cycle");
302  recovery_result_ = RECOVERY_FAILED_SCL_LOW;
303  return;
304  }
305  }
306 
307  // By now, any stuck device ought to have sent all remaining bits of its
308  // transaction, meaning that it should have freed up the SDA line, resulting
309  // in SDA being pulled up.
310  if (gpio_get_level(sda_pin) == 0) {
311  ESP_LOGE(TAG, "Recovery failed: SDA is held LOW after clock pulse cycle");
312  recovery_result_ = RECOVERY_FAILED_SDA_LOW;
313  return;
314  }
315 
316  // From the specification:
317  // "I2C-bus compatible devices must reset their bus logic on receipt of
318  // a START or repeated START condition such that they all anticipate
319  // the sending of a target address, even if these START conditions are
320  // not positioned according to the proper format."
321  // While the 9 clock pulses from above might have drained all bits of a
322  // single byte within a transaction, a device might have more bytes to
323  // transmit. So here we'll generate a START condition to snap the device
324  // out of this state.
325  // SCL and SDA are already high at this point, so we can generate a START
326  // condition by making the SDA signal LOW.
327  delayMicroseconds(half_period_usec);
328  gpio_set_level(sda_pin, 0);
329 
330  // From the specification:
331  // "A START condition immediately followed by a STOP condition (void
332  // message) is an illegal format. Many devices however are designed to
333  // operate properly under this condition."
334  // Finally, we'll bring the I2C bus into a starting state by generating
335  // a STOP condition.
336  delayMicroseconds(half_period_usec);
337  gpio_set_level(sda_pin, 1);
338 
339  recovery_result_ = RECOVERY_COMPLETED;
340 }
341 
342 } // namespace i2c
343 } // namespace esphome
344 
345 #endif // USE_ESP_IDF
void dump_config() override
std::vector< std::pair< uint8_t, bool > > scan_results_
Definition: i2c_bus.h:64
ErrorCode writev(uint8_t address, WriteBuffer *buffers, size_t cnt, bool stop) override
ErrorCode readv(uint8_t address, ReadBuffer *buffers, size_t cnt) override
Application App
Global storage of Application pointer - only one Application can exist.
virtual void mark_failed()
Mark this component as failed.
Definition: component.cpp:112
Implementation of SPI Controller mode.
Definition: a01nyub.cpp:7
void IRAM_ATTR HOT delayMicroseconds(uint32_t us)
Definition: core.cpp:28
stm32_cmd_t * cmd
Definition: stm32flash.h:96