5#include <driver/gpio.h>
16static const char *
const TAG =
"i2c.idf";
19static constexpr size_t I2C_MAX_LOG_BYTES = 32;
22 static i2c_port_t next_hp_port = I2C_NUM_0;
23#if SOC_LP_I2C_SUPPORTED
24 static i2c_port_t next_lp_port = LP_I2C_NUM_0;
28 ESP_LOGW(TAG,
"Using max allowed timeout: 13 ms");
34 i2c_master_bus_config_t bus_conf{};
35 memset(&bus_conf, 0,
sizeof(bus_conf));
36 bus_conf.sda_io_num = gpio_num_t(
sda_pin_);
37 bus_conf.scl_io_num = gpio_num_t(
scl_pin_);
38 bus_conf.glitch_ignore_cnt = 7;
39#if SOC_LP_I2C_SUPPORTED
41 if ((next_lp_port - LP_I2C_NUM_0) == SOC_LP_I2C_NUM) {
42 ESP_LOGE(TAG,
"No more than %u LP buses supported", SOC_LP_I2C_NUM);
46 this->
port_ = next_lp_port;
47 next_lp_port = (i2c_port_t) (next_lp_port + 1);
48 bus_conf.lp_source_clk = LP_I2C_SCLK_DEFAULT;
51 if (next_hp_port == SOC_HP_I2C_NUM) {
52 ESP_LOGE(TAG,
"No more than %u HP buses supported", SOC_HP_I2C_NUM);
56 this->
port_ = next_hp_port;
57 next_hp_port = (i2c_port_t) (next_hp_port + 1);
58 bus_conf.clk_source = I2C_CLK_SRC_DEFAULT;
59#if SOC_LP_I2C_SUPPORTED
62 bus_conf.i2c_port = this->
port_;
64 esp_err_t
err = i2c_new_master_bus(&bus_conf, &this->
bus_);
66 ESP_LOGW(TAG,
"i2c_new_master_bus failed: %s", esp_err_to_name(
err));
71 i2c_device_config_t dev_conf{};
72 memset(&dev_conf, 0,
sizeof(dev_conf));
73 dev_conf.dev_addr_length = I2C_ADDR_BIT_LEN_7;
74 dev_conf.device_address = I2C_DEVICE_ADDRESS_NOT_USED;
76 dev_conf.scl_wait_us = this->
timeout_;
77 err = i2c_master_bus_add_device(this->
bus_, &dev_conf, &this->
dev_);
79 ESP_LOGW(TAG,
"i2c_master_bus_add_device failed: %s", esp_err_to_name(
err));
87 ESP_LOGV(TAG,
"Scanning for devices");
93 ESP_LOGCONFIG(TAG,
"I2C Bus:");
97 " Frequency: %" PRIu32
" Hz",
100 ESP_LOGCONFIG(TAG,
" Timeout: %" PRIu32
"us", this->
timeout_);
102 switch (this->recovery_result_) {
104 ESP_LOGCONFIG(TAG,
" Recovery: bus successfully recovered");
107 ESP_LOGCONFIG(TAG,
" Recovery: failed, SCL is held low on the bus");
110 ESP_LOGCONFIG(TAG,
" Recovery: failed, SDA is held low on the bus");
114 ESP_LOGCONFIG(TAG,
"Results from bus scan:");
116 ESP_LOGCONFIG(TAG,
"Found no devices");
120 ESP_LOGCONFIG(TAG,
"Found device at address 0x%02X", s.first);
122 ESP_LOGE(TAG,
"Unknown error at address 0x%02X", s.first);
134 ESP_LOGW(TAG,
"i2c bus not initialized!");
138 i2c_operation_job_t jobs[8]{};
140 uint8_t write_addr = (
address << 1) | I2C_MASTER_WRITE;
141 uint8_t read_addr = (
address << 1) | I2C_MASTER_READ;
142 ESP_LOGV(TAG,
"Writing %zu bytes, reading %zu bytes", write_count, read_count);
143 if (read_count == 0 && write_count == 0) {
145 ESP_LOGV(TAG,
"0x%02X BUS PROBE",
address);
146 jobs[num_jobs++].command = I2C_MASTER_CMD_START;
147 jobs[num_jobs].command = I2C_MASTER_CMD_WRITE;
148 jobs[num_jobs].write.ack_check =
true;
149 jobs[num_jobs].write.data = &write_addr;
150 jobs[num_jobs++].write.total_bytes = 1;
152 if (write_count != 0) {
153#if ESPHOME_LOG_LEVEL >= ESPHOME_LOG_LEVEL_VERBOSE
157 jobs[num_jobs++].command = I2C_MASTER_CMD_START;
158 jobs[num_jobs].command = I2C_MASTER_CMD_WRITE;
159 jobs[num_jobs].write.ack_check =
true;
160 jobs[num_jobs].write.data = &write_addr;
161 jobs[num_jobs++].write.total_bytes = 1;
162 jobs[num_jobs].command = I2C_MASTER_CMD_WRITE;
163 jobs[num_jobs].write.ack_check =
true;
164 jobs[num_jobs].write.data = (uint8_t *) write_buffer;
165 jobs[num_jobs++].write.total_bytes = write_count;
167 if (read_count != 0) {
168 ESP_LOGV(TAG,
"0x%02X RX bytes %zu",
address, read_count);
169 jobs[num_jobs++].command = I2C_MASTER_CMD_START;
170 jobs[num_jobs].command = I2C_MASTER_CMD_WRITE;
171 jobs[num_jobs].write.ack_check =
true;
172 jobs[num_jobs].write.data = &read_addr;
173 jobs[num_jobs++].write.total_bytes = 1;
174 if (read_count > 1) {
175 jobs[num_jobs].command = I2C_MASTER_CMD_READ;
176 jobs[num_jobs].read.ack_value = I2C_ACK_VAL;
177 jobs[num_jobs].read.data = read_buffer;
178 jobs[num_jobs++].read.total_bytes = read_count - 1;
180 jobs[num_jobs].command = I2C_MASTER_CMD_READ;
181 jobs[num_jobs].read.ack_value = I2C_NACK_VAL;
182 jobs[num_jobs].read.data = read_buffer + read_count - 1;
183 jobs[num_jobs++].read.total_bytes = 1;
186 jobs[num_jobs++].command = I2C_MASTER_CMD_STOP;
187 ESP_LOGV(TAG,
"Sending %zu jobs", num_jobs);
188 esp_err_t
err = i2c_master_execute_defined_operations(this->
dev_, jobs, num_jobs, 20);
189 if (
err == ESP_ERR_INVALID_STATE) {
190 ESP_LOGV(TAG,
"TX to %02X failed: not acked",
address);
192 }
else if (
err == ESP_ERR_TIMEOUT) {
193 ESP_LOGV(TAG,
"TX to %02X failed: timeout",
address);
195 }
else if (
err != ESP_OK) {
196 ESP_LOGV(TAG,
"TX to %02X failed: %s",
address, esp_err_to_name(
err));
205void IDFI2CBus::recover_() {
206 ESP_LOGI(TAG,
"Performing bus recovery");
208 const auto scl_pin =
static_cast<gpio_num_t
>(
scl_pin_);
209 const auto sda_pin =
static_cast<gpio_num_t
>(
sda_pin_);
217 const auto half_period_usec = 7;
220 gpio_set_level(scl_pin, 1);
221 gpio_config_t scl_config{};
222 scl_config.pin_bit_mask = 1ULL <<
scl_pin_;
223 scl_config.mode = GPIO_MODE_INPUT_OUTPUT_OD;
224 scl_config.pull_up_en = GPIO_PULLUP_ENABLE;
225 scl_config.pull_down_en = GPIO_PULLDOWN_DISABLE;
226 scl_config.intr_type = GPIO_INTR_DISABLE;
227 gpio_config(&scl_config);
230 gpio_set_level(sda_pin, 1);
231 gpio_config_t sda_conf{};
232 sda_conf.pin_bit_mask = 1ULL <<
sda_pin_;
233 sda_conf.mode = GPIO_MODE_INPUT_OUTPUT_OD;
234 sda_conf.pull_up_en = GPIO_PULLUP_ENABLE;
235 sda_conf.pull_down_en = GPIO_PULLDOWN_DISABLE;
236 sda_conf.intr_type = GPIO_INTR_DISABLE;
237 gpio_config(&sda_conf);
242 if (gpio_get_level(scl_pin) == 0) {
243 ESP_LOGE(TAG,
"Recovery failed: SCL is held LOW on the bus");
255 for (
auto i = 0; i < 9; i++) {
256 gpio_set_level(scl_pin, 0);
258 gpio_set_level(scl_pin, 1);
269 while (wait-- && gpio_get_level(scl_pin) == 0) {
273 if (gpio_get_level(scl_pin) == 0) {
274 ESP_LOGE(TAG,
"Recovery failed: SCL is held LOW during clock pulse cycle");
283 if (gpio_get_level(sda_pin) == 0) {
284 ESP_LOGE(TAG,
"Recovery failed: SDA is held LOW after clock pulse cycle");
301 gpio_set_level(sda_pin, 0);
310 gpio_set_level(sda_pin, 1);
void feed_wdt(uint32_t time=0)
virtual void mark_failed()
Mark this component as failed.
bool scan_
Should we scan ? Can be set in the yaml.
std::vector< std::pair< uint8_t, bool > > scan_results_
array containing scan results
i2c_master_bus_handle_t bus_
void dump_config() override
i2c_master_dev_handle_t dev_
ErrorCode write_readv(uint8_t address, const uint8_t *write_buffer, size_t write_count, uint8_t *read_buffer, size_t read_count) override
ErrorCode
Error codes returned by I2CBus and I2CDevice methods.
@ ERROR_TIMEOUT
timeout while waiting to receive bytes
@ ERROR_NOT_ACKNOWLEDGED
I2C bus acknowledgment not received.
@ ERROR_NOT_INITIALIZED
call method to a not initialized bus
@ ERROR_UNKNOWN
miscellaneous I2C error during execution
@ RECOVERY_FAILED_SDA_LOW
@ RECOVERY_FAILED_SCL_LOW
Providing packet encoding functions for exchanging data with a remote host.
void IRAM_ATTR HOT delayMicroseconds(uint32_t us)
char * format_hex_pretty_to(char *buffer, size_t buffer_size, const uint8_t *data, size_t length, char separator)
Format byte array as uppercase hex to buffer (base implementation).
constexpr size_t format_hex_pretty_size(size_t byte_count)
Calculate buffer size needed for format_hex_pretty_to with separator: "XX:XX:...:XX\0".
Application App
Global storage of Application pointer - only one Application can exist.