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