5#include <driver/gpio.h>
15static const char *
const TAG =
"i2c.idf";
18static constexpr size_t I2C_MAX_LOG_BYTES = 32;
21 static i2c_port_t next_hp_port = I2C_NUM_0;
22#if SOC_LP_I2C_SUPPORTED
23 static i2c_port_t next_lp_port = LP_I2C_NUM_0;
27 ESP_LOGW(TAG,
"Using max allowed timeout: 13 ms");
33 i2c_master_bus_config_t bus_conf{};
34 memset(&bus_conf, 0,
sizeof(bus_conf));
35 bus_conf.sda_io_num = gpio_num_t(
sda_pin_);
36 bus_conf.scl_io_num = gpio_num_t(
scl_pin_);
37 bus_conf.glitch_ignore_cnt = 7;
38#if SOC_LP_I2C_SUPPORTED
40 if ((next_lp_port - LP_I2C_NUM_0) == SOC_LP_I2C_NUM) {
41 ESP_LOGE(TAG,
"No more than %u LP buses supported", SOC_LP_I2C_NUM);
45 this->
port_ = next_lp_port;
46 next_lp_port = (i2c_port_t) (next_lp_port + 1);
47 bus_conf.lp_source_clk = LP_I2C_SCLK_DEFAULT;
50 if (next_hp_port == SOC_HP_I2C_NUM) {
51 ESP_LOGE(TAG,
"No more than %u HP buses supported", SOC_HP_I2C_NUM);
55 this->
port_ = next_hp_port;
56 next_hp_port = (i2c_port_t) (next_hp_port + 1);
57 bus_conf.clk_source = I2C_CLK_SRC_DEFAULT;
58#if SOC_LP_I2C_SUPPORTED
61 bus_conf.i2c_port = this->
port_;
63 esp_err_t err = i2c_new_master_bus(&bus_conf, &this->
bus_);
65 ESP_LOGW(TAG,
"i2c_new_master_bus failed: %s", esp_err_to_name(err));
70 i2c_device_config_t dev_conf{};
71 memset(&dev_conf, 0,
sizeof(dev_conf));
72 dev_conf.dev_addr_length = I2C_ADDR_BIT_LEN_7;
73 dev_conf.device_address = I2C_DEVICE_ADDRESS_NOT_USED;
75 dev_conf.scl_wait_us = this->
timeout_;
76 err = i2c_master_bus_add_device(this->
bus_, &dev_conf, &this->
dev_);
78 ESP_LOGW(TAG,
"i2c_master_bus_add_device failed: %s", esp_err_to_name(err));
86 ESP_LOGV(TAG,
"Scanning for devices");
92 ESP_LOGCONFIG(TAG,
"I2C Bus:");
96 " Frequency: %" PRIu32
" Hz",
99 ESP_LOGCONFIG(TAG,
" Timeout: %" PRIu32
"us", this->
timeout_);
101 switch (this->recovery_result_) {
103 ESP_LOGCONFIG(TAG,
" Recovery: bus successfully recovered");
106 ESP_LOGCONFIG(TAG,
" Recovery: failed, SCL is held low on the bus");
109 ESP_LOGCONFIG(TAG,
" Recovery: failed, SDA is held low on the bus");
113 ESP_LOGCONFIG(TAG,
"Results from bus scan:");
115 ESP_LOGCONFIG(TAG,
"Found no devices");
119 ESP_LOGCONFIG(TAG,
"Found device at address 0x%02X", s.first);
121 ESP_LOGE(TAG,
"Unknown error at address 0x%02X", s.first);
133 ESP_LOGW(TAG,
"i2c bus not initialized!");
137 i2c_operation_job_t jobs[8]{};
139 uint8_t write_addr = (
address << 1) | I2C_MASTER_WRITE;
140 uint8_t read_addr = (
address << 1) | I2C_MASTER_READ;
141 ESP_LOGV(TAG,
"Writing %zu bytes, reading %zu bytes", write_count, read_count);
142 if (read_count == 0 && write_count == 0) {
144 ESP_LOGV(TAG,
"0x%02X BUS PROBE",
address);
145 jobs[num_jobs++].command = I2C_MASTER_CMD_START;
146 jobs[num_jobs].command = I2C_MASTER_CMD_WRITE;
147 jobs[num_jobs].write.ack_check =
true;
148 jobs[num_jobs].write.data = &write_addr;
149 jobs[num_jobs++].write.total_bytes = 1;
151 if (write_count != 0) {
152#if ESPHOME_LOG_LEVEL >= ESPHOME_LOG_LEVEL_VERBOSE
156 jobs[num_jobs++].command = I2C_MASTER_CMD_START;
157 jobs[num_jobs].command = I2C_MASTER_CMD_WRITE;
158 jobs[num_jobs].write.ack_check =
true;
159 jobs[num_jobs].write.data = &write_addr;
160 jobs[num_jobs++].write.total_bytes = 1;
161 jobs[num_jobs].command = I2C_MASTER_CMD_WRITE;
162 jobs[num_jobs].write.ack_check =
true;
163 jobs[num_jobs].write.data = (uint8_t *) write_buffer;
164 jobs[num_jobs++].write.total_bytes = write_count;
166 if (read_count != 0) {
167 ESP_LOGV(TAG,
"0x%02X RX bytes %zu",
address, read_count);
168 jobs[num_jobs++].command = I2C_MASTER_CMD_START;
169 jobs[num_jobs].command = I2C_MASTER_CMD_WRITE;
170 jobs[num_jobs].write.ack_check =
true;
171 jobs[num_jobs].write.data = &read_addr;
172 jobs[num_jobs++].write.total_bytes = 1;
173 if (read_count > 1) {
174 jobs[num_jobs].command = I2C_MASTER_CMD_READ;
175 jobs[num_jobs].read.ack_value = I2C_ACK_VAL;
176 jobs[num_jobs].read.data = read_buffer;
177 jobs[num_jobs++].read.total_bytes = read_count - 1;
179 jobs[num_jobs].command = I2C_MASTER_CMD_READ;
180 jobs[num_jobs].read.ack_value = I2C_NACK_VAL;
181 jobs[num_jobs].read.data = read_buffer + read_count - 1;
182 jobs[num_jobs++].read.total_bytes = 1;
185 jobs[num_jobs++].command = I2C_MASTER_CMD_STOP;
186 ESP_LOGV(TAG,
"Sending %zu jobs", num_jobs);
187 esp_err_t err = i2c_master_execute_defined_operations(this->
dev_, jobs, num_jobs, 100);
188 if (err == ESP_ERR_INVALID_STATE) {
189 ESP_LOGV(TAG,
"TX to %02X failed: not acked",
address);
191 }
else if (err == ESP_ERR_TIMEOUT) {
192 ESP_LOGV(TAG,
"TX to %02X failed: timeout",
address);
194 }
else if (err != ESP_OK) {
195 ESP_LOGV(TAG,
"TX to %02X failed: %s",
address, esp_err_to_name(err));
204void IDFI2CBus::recover_() {
205 ESP_LOGI(TAG,
"Performing bus recovery");
207 const auto scl_pin =
static_cast<gpio_num_t
>(
scl_pin_);
208 const auto sda_pin =
static_cast<gpio_num_t
>(
sda_pin_);
216 const auto half_period_usec = 7;
219 gpio_set_level(scl_pin, 1);
220 gpio_config_t scl_config{};
221 scl_config.pin_bit_mask = 1ULL <<
scl_pin_;
222 scl_config.mode = GPIO_MODE_INPUT_OUTPUT_OD;
223 scl_config.pull_up_en = GPIO_PULLUP_ENABLE;
224 scl_config.pull_down_en = GPIO_PULLDOWN_DISABLE;
225 scl_config.intr_type = GPIO_INTR_DISABLE;
226 gpio_config(&scl_config);
229 gpio_set_level(sda_pin, 1);
230 gpio_config_t sda_conf{};
231 sda_conf.pin_bit_mask = 1ULL <<
sda_pin_;
232 sda_conf.mode = GPIO_MODE_INPUT_OUTPUT_OD;
233 sda_conf.pull_up_en = GPIO_PULLUP_ENABLE;
234 sda_conf.pull_down_en = GPIO_PULLDOWN_DISABLE;
235 sda_conf.intr_type = GPIO_INTR_DISABLE;
236 gpio_config(&sda_conf);
241 if (gpio_get_level(scl_pin) == 0) {
242 ESP_LOGE(TAG,
"Recovery failed: SCL is held LOW on the bus");
254 for (
auto i = 0; i < 9; i++) {
255 gpio_set_level(scl_pin, 0);
257 gpio_set_level(scl_pin, 1);
268 while (wait-- && gpio_get_level(scl_pin) == 0) {
272 if (gpio_get_level(scl_pin) == 0) {
273 ESP_LOGE(TAG,
"Recovery failed: SCL is held LOW during clock pulse cycle");
282 if (gpio_get_level(sda_pin) == 0) {
283 ESP_LOGE(TAG,
"Recovery failed: SDA is held LOW after clock pulse cycle");
300 gpio_set_level(sda_pin, 0);
309 gpio_set_level(sda_pin, 1);
void feed_wdt(uint32_t time=0)
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
void i2c_scan_()
Scans the I2C bus for devices.
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_OK
No error found during execution of method.
@ 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
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.