5#include <driver/gpio.h>
16static const char *
const TAG =
"i2c.idf";
19 static i2c_port_t next_hp_port = I2C_NUM_0;
20#if SOC_LP_I2C_SUPPORTED
21 static i2c_port_t next_lp_port = LP_I2C_NUM_0;
25 ESP_LOGW(TAG,
"Using max allowed timeout: 13 ms");
31 i2c_master_bus_config_t bus_conf{};
32 memset(&bus_conf, 0,
sizeof(bus_conf));
33 bus_conf.sda_io_num = gpio_num_t(
sda_pin_);
34 bus_conf.scl_io_num = gpio_num_t(
scl_pin_);
35 bus_conf.glitch_ignore_cnt = 7;
36#if SOC_LP_I2C_SUPPORTED
38 if ((next_lp_port - LP_I2C_NUM_0) == SOC_LP_I2C_NUM) {
39 ESP_LOGE(TAG,
"No more than %u LP buses supported", SOC_LP_I2C_NUM);
43 this->
port_ = next_lp_port;
44 next_lp_port = (i2c_port_t) (next_lp_port + 1);
45 bus_conf.lp_source_clk = LP_I2C_SCLK_DEFAULT;
48 if (next_hp_port == SOC_HP_I2C_NUM) {
49 ESP_LOGE(TAG,
"No more than %u HP buses supported", SOC_HP_I2C_NUM);
53 this->
port_ = next_hp_port;
54 next_hp_port = (i2c_port_t) (next_hp_port + 1);
55 bus_conf.clk_source = I2C_CLK_SRC_DEFAULT;
56#if SOC_LP_I2C_SUPPORTED
59 bus_conf.i2c_port = this->
port_;
61 esp_err_t
err = i2c_new_master_bus(&bus_conf, &this->
bus_);
63 ESP_LOGW(TAG,
"i2c_new_master_bus failed: %s", esp_err_to_name(
err));
68 i2c_device_config_t dev_conf{};
69 memset(&dev_conf, 0,
sizeof(dev_conf));
70 dev_conf.dev_addr_length = I2C_ADDR_BIT_LEN_7;
71 dev_conf.device_address = I2C_DEVICE_ADDRESS_NOT_USED;
73 dev_conf.scl_wait_us = this->
timeout_;
74 err = i2c_master_bus_add_device(this->
bus_, &dev_conf, &this->
dev_);
76 ESP_LOGW(TAG,
"i2c_master_bus_add_device failed: %s", esp_err_to_name(
err));
84 ESP_LOGV(TAG,
"Scanning for devices");
90 ESP_LOGCONFIG(TAG,
"I2C Bus:");
94 " Frequency: %" PRIu32
" Hz",
97 ESP_LOGCONFIG(TAG,
" Timeout: %" PRIu32
"us", this->
timeout_);
99 switch (this->recovery_result_) {
101 ESP_LOGCONFIG(TAG,
" Recovery: bus successfully recovered");
104 ESP_LOGCONFIG(TAG,
" Recovery: failed, SCL is held low on the bus");
107 ESP_LOGCONFIG(TAG,
" Recovery: failed, SDA is held low on the bus");
111 ESP_LOGCONFIG(TAG,
"Results from bus scan:");
113 ESP_LOGCONFIG(TAG,
"Found no devices");
117 ESP_LOGCONFIG(TAG,
"Found device at address 0x%02X", s.first);
119 ESP_LOGE(TAG,
"Unknown error at address 0x%02X", s.first);
131 ESP_LOGW(TAG,
"i2c bus not initialized!");
135 i2c_operation_job_t jobs[8]{};
137 uint8_t write_addr = (
address << 1) | I2C_MASTER_WRITE;
138 uint8_t read_addr = (
address << 1) | I2C_MASTER_READ;
139 ESP_LOGV(TAG,
"Writing %zu bytes, reading %zu bytes", write_count, read_count);
140 if (read_count == 0 && write_count == 0) {
142 ESP_LOGV(TAG,
"0x%02X BUS PROBE",
address);
143 jobs[num_jobs++].command = I2C_MASTER_CMD_START;
144 jobs[num_jobs].command = I2C_MASTER_CMD_WRITE;
145 jobs[num_jobs].write.ack_check =
true;
146 jobs[num_jobs].write.data = &write_addr;
147 jobs[num_jobs++].write.total_bytes = 1;
149 if (write_count != 0) {
151 jobs[num_jobs++].command = I2C_MASTER_CMD_START;
152 jobs[num_jobs].command = I2C_MASTER_CMD_WRITE;
153 jobs[num_jobs].write.ack_check =
true;
154 jobs[num_jobs].write.data = &write_addr;
155 jobs[num_jobs++].write.total_bytes = 1;
156 jobs[num_jobs].command = I2C_MASTER_CMD_WRITE;
157 jobs[num_jobs].write.ack_check =
true;
158 jobs[num_jobs].write.data = (uint8_t *) write_buffer;
159 jobs[num_jobs++].write.total_bytes = write_count;
161 if (read_count != 0) {
162 ESP_LOGV(TAG,
"0x%02X RX bytes %zu",
address, read_count);
163 jobs[num_jobs++].command = I2C_MASTER_CMD_START;
164 jobs[num_jobs].command = I2C_MASTER_CMD_WRITE;
165 jobs[num_jobs].write.ack_check =
true;
166 jobs[num_jobs].write.data = &read_addr;
167 jobs[num_jobs++].write.total_bytes = 1;
168 if (read_count > 1) {
169 jobs[num_jobs].command = I2C_MASTER_CMD_READ;
170 jobs[num_jobs].read.ack_value = I2C_ACK_VAL;
171 jobs[num_jobs].read.data = read_buffer;
172 jobs[num_jobs++].read.total_bytes = read_count - 1;
174 jobs[num_jobs].command = I2C_MASTER_CMD_READ;
175 jobs[num_jobs].read.ack_value = I2C_NACK_VAL;
176 jobs[num_jobs].read.data = read_buffer + read_count - 1;
177 jobs[num_jobs++].read.total_bytes = 1;
180 jobs[num_jobs++].command = I2C_MASTER_CMD_STOP;
181 ESP_LOGV(TAG,
"Sending %zu jobs", num_jobs);
182 esp_err_t
err = i2c_master_execute_defined_operations(this->
dev_, jobs, num_jobs, 20);
183 if (
err == ESP_ERR_INVALID_STATE) {
184 ESP_LOGV(TAG,
"TX to %02X failed: not acked",
address);
186 }
else if (
err == ESP_ERR_TIMEOUT) {
187 ESP_LOGV(TAG,
"TX to %02X failed: timeout",
address);
189 }
else if (
err != ESP_OK) {
190 ESP_LOGV(TAG,
"TX to %02X failed: %s",
address, esp_err_to_name(
err));
199void IDFI2CBus::recover_() {
200 ESP_LOGI(TAG,
"Performing bus recovery");
202 const auto scl_pin =
static_cast<gpio_num_t
>(
scl_pin_);
203 const auto sda_pin =
static_cast<gpio_num_t
>(
sda_pin_);
211 const auto half_period_usec = 7;
214 gpio_set_level(scl_pin, 1);
215 gpio_config_t scl_config{};
216 scl_config.pin_bit_mask = 1ULL <<
scl_pin_;
217 scl_config.mode = GPIO_MODE_INPUT_OUTPUT_OD;
218 scl_config.pull_up_en = GPIO_PULLUP_ENABLE;
219 scl_config.pull_down_en = GPIO_PULLDOWN_DISABLE;
220 scl_config.intr_type = GPIO_INTR_DISABLE;
221 gpio_config(&scl_config);
224 gpio_set_level(sda_pin, 1);
225 gpio_config_t sda_conf{};
226 sda_conf.pin_bit_mask = 1ULL <<
sda_pin_;
227 sda_conf.mode = GPIO_MODE_INPUT_OUTPUT_OD;
228 sda_conf.pull_up_en = GPIO_PULLUP_ENABLE;
229 sda_conf.pull_down_en = GPIO_PULLDOWN_DISABLE;
230 sda_conf.intr_type = GPIO_INTR_DISABLE;
231 gpio_config(&sda_conf);
236 if (gpio_get_level(scl_pin) == 0) {
237 ESP_LOGE(TAG,
"Recovery failed: SCL is held LOW on the bus");
249 for (
auto i = 0; i < 9; i++) {
250 gpio_set_level(scl_pin, 0);
252 gpio_set_level(scl_pin, 1);
263 while (wait-- && gpio_get_level(scl_pin) == 0) {
267 if (gpio_get_level(scl_pin) == 0) {
268 ESP_LOGE(TAG,
"Recovery failed: SCL is held LOW during clock pulse cycle");
277 if (gpio_get_level(sda_pin) == 0) {
278 ESP_LOGE(TAG,
"Recovery failed: SDA is held LOW after clock pulse cycle");
295 gpio_set_level(sda_pin, 0);
304 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)
std::string format_hex_pretty(const uint8_t *data, size_t length, char separator, bool show_length)
Format a byte array in pretty-printed, human-readable hex format.
Application App
Global storage of Application pointer - only one Application can exist.