From 016877b7ce184e8e8e0cdb037c230a887bc8a5dc Mon Sep 17 00:00:00 2001 From: Cao Sen Miao Date: Fri, 15 Mar 2024 14:06:52 +0800 Subject: [PATCH] fix(i2c_master): Fix issue that initialize esp32 and using i2c_master_probe issue, and probe might failed. Fixed I2C cannot return err code when nack detected Closes https://github.com/espressif/esp-idf/issues/13213, Closes https://github.com/espressif/esp-idf/issues/12929, Closes https://github.com/espressif/esp-idf/issues/13398, --- components/esp_driver_i2c/i2c_master.c | 51 ++++++++--- components/esp_driver_i2c/i2c_private.h | 2 + .../include/driver/i2c_master.h | 18 +++- .../i2c_test_apps/main/test_i2c_common.c | 89 ++++++++++++++++++- .../i2c_test_apps/main/test_i2c_multi.c | 54 +++++++++++ docs/en/api-reference/peripherals/i2c.rst | 4 + 6 files changed, 203 insertions(+), 15 deletions(-) diff --git a/components/esp_driver_i2c/i2c_master.c b/components/esp_driver_i2c/i2c_master.c index e1d2237316..9a11338384 100644 --- a/components/esp_driver_i2c/i2c_master.c +++ b/components/esp_driver_i2c/i2c_master.c @@ -345,7 +345,7 @@ static void s_i2c_start_end_command(i2c_master_bus_handle_t i2c_master, i2c_oper } #endif i2c_ll_hw_cmd_t hw_write_cmd = { - .ack_en = false, + .ack_en = i2c_master->ack_check_disable ? false : true, .op_code = I2C_LL_CMD_WRITE, .byte_num = 1, }; @@ -412,11 +412,13 @@ static void s_i2c_send_commands(i2c_master_bus_handle_t i2c_master, TickType_t t s_i2c_hw_fsm_reset(i2c_master); i2c_master->cmd_idx = 0; i2c_master->trans_idx = 0; + ESP_LOGE(TAG, "I2C hardware timeout detected"); xSemaphoreGive(i2c_master->cmd_semphr); return; } if (i2c_master->status == I2C_STATUS_ACK_ERROR) { + ESP_LOGE(TAG, "I2C hardware NACK detected"); const i2c_ll_hw_cmd_t hw_stop_cmd = { .op_code = I2C_LL_CMD_STOP, }; @@ -471,6 +473,20 @@ static void s_i2c_send_command_async(i2c_master_bus_handle_t i2c_master, BaseTyp i2c_master->sent_all = true; return; } + + // Stop the transaction when invalid event is detected + if (i2c_master->event == I2C_EVENT_NACK || i2c_master->event == I2C_EVENT_TIMEOUT) { + i2c_master->sent_all = true; + i2c_master->trans_finish = true; + i2c_master->in_progress = false; + if (i2c_master->queue_trans) { + i2c_master->ops_cur_size--; + xQueueSendFromISR(i2c_master->trans_queues[I2C_TRANS_QUEUE_COMPLETE], &i2c_master->i2c_trans, do_yield); + } + i2c_master->i2c_trans.cmd_count = 0; + i2c_master->event = I2C_EVENT_ALIVE; + return; + } while (i2c_ll_is_bus_busy(hal->dev)) {} while (i2c_master->i2c_trans.cmd_count && !needs_start) { @@ -532,6 +548,8 @@ static esp_err_t s_i2c_transaction_start(i2c_master_dev_handle_t i2c_dev, int xf if (i2c_master->status != I2C_STATUS_DONE) { ret = ESP_ERR_INVALID_STATE; } + // Interrupt can be disabled when on transaction finishes. + i2c_ll_disable_intr_mask(hal->dev, I2C_LL_MASTER_EVENT_INTR); } if (i2c_master->base->pm_lock) { @@ -650,7 +668,6 @@ static void IRAM_ATTR i2c_master_isr_handler_default(void *arg) i2c_master->read_len_static = 0; i2c_ll_txfifo_rst(hal->dev); i2c_ll_rxfifo_rst(hal->dev); - i2c_ll_enable_intr_mask(hal->dev, I2C_LL_MASTER_EVENT_INTR); i2c_master->i2c_trans = t; memcpy(i2c_master->i2c_ops, t.ops, t.cmd_count * sizeof(i2c_operation_t)); @@ -810,9 +827,12 @@ static esp_err_t s_i2c_synchronous_transaction(i2c_master_dev_handle_t i2c_dev, i2c_dev->master_bus->sent_all = false; i2c_dev->master_bus->trans_finish = false; i2c_dev->master_bus->queue_trans = false; + i2c_dev->master_bus->ack_check_disable = i2c_dev->ack_check_disable; ESP_GOTO_ON_ERROR(s_i2c_transaction_start(i2c_dev, timeout_ms), err, TAG, "I2C transaction failed"); err: + // When error occurs, reset hardware fsm in case not influence following transactions. + s_i2c_hw_fsm_reset(i2c_dev->master_bus); xSemaphoreGive(i2c_dev->master_bus->bus_lock_mux); return ret; } @@ -840,6 +860,10 @@ esp_err_t i2c_new_master_bus(const i2c_master_bus_config_t *bus_config, i2c_mast i2c_master->base->scl_num = bus_config->scl_io_num; i2c_master->base->sda_num = bus_config->sda_io_num; i2c_master->base->pull_up_enable = bus_config->flags.enable_internal_pullup; + + if (i2c_master->base->pull_up_enable == false) { + ESP_LOGW(TAG, "Please check pull-up resistances whether be connected properly. Otherwise unexpected behavior would happen. For more detailed information, please read docs"); + } ESP_GOTO_ON_ERROR(i2c_param_master_config(i2c_master->base, bus_config), err, TAG, "i2c configure parameter failed"); i2c_master->bus_lock_mux = xSemaphoreCreateBinaryWithCaps(I2C_MEM_ALLOC_CAPS); @@ -865,6 +889,7 @@ esp_err_t i2c_new_master_bus(const i2c_master_bus_config_t *bus_config, i2c_mast xSemaphoreGive(i2c_master->bus_lock_mux); // Initialize the queue if (bus_config->trans_queue_depth) { + ESP_LOGW(TAG, "Please note i2c asynchronous is only used for specific scenario currently. It's experimental for other users because user cannot get bus error from API. And It's not compatible with ``i2c_master_probe``. If user makes sure there won't be any error on bus and tested with no problem, this message can be ignored."); i2c_master->async_trans = true; i2c_master->sent_all = true; i2c_master->trans_finish = true; @@ -900,7 +925,6 @@ esp_err_t i2c_new_master_bus(const i2c_master_bus_config_t *bus_config, i2c_mast ESP_GOTO_ON_ERROR(ret, err, TAG, "install i2c master interrupt failed"); atomic_init(&i2c_master->status, I2C_STATUS_IDLE); - i2c_ll_enable_intr_mask(hal->dev, I2C_LL_MASTER_EVENT_INTR); i2c_ll_master_set_filter(hal->dev, bus_config->glitch_ignore_cnt); xSemaphoreGive(i2c_master->cmd_semphr); @@ -932,6 +956,7 @@ esp_err_t i2c_master_bus_add_device(i2c_master_bus_handle_t bus_handle, const i2 i2c_dev->scl_speed_hz = dev_config->scl_speed_hz; i2c_dev->addr_10bits = dev_config->dev_addr_length; i2c_dev->master_bus = i2c_master; + i2c_dev->ack_check_disable = dev_config->flags.disable_ack_check; i2c_master_device_list_t *device_item = (i2c_master_device_list_t *)calloc(1, sizeof(i2c_master_device_list_t)); ESP_GOTO_ON_FALSE((device_item != NULL), ESP_ERR_NO_MEM, err, TAG, "no memory for i2c device item`"); @@ -997,7 +1022,7 @@ esp_err_t i2c_master_transmit(i2c_master_dev_handle_t i2c_dev, const uint8_t *wr i2c_operation_t i2c_ops[] = { {.hw_cmd = I2C_TRANS_START_COMMAND}, - {.hw_cmd = I2C_TRANS_WRITE_COMMAND(false), .data = (uint8_t *)write_buffer, .total_bytes = write_size}, + {.hw_cmd = I2C_TRANS_WRITE_COMMAND(i2c_dev->ack_check_disable ? false : true), .data = (uint8_t *)write_buffer, .total_bytes = write_size}, {.hw_cmd = I2C_TRANS_STOP_COMMAND}, }; @@ -1017,7 +1042,7 @@ esp_err_t i2c_master_transmit_receive(i2c_master_dev_handle_t i2c_dev, const uin i2c_operation_t i2c_ops[] = { {.hw_cmd = I2C_TRANS_START_COMMAND}, - {.hw_cmd = I2C_TRANS_WRITE_COMMAND(false), .data = (uint8_t *)write_buffer, .total_bytes = write_size}, + {.hw_cmd = I2C_TRANS_WRITE_COMMAND(i2c_dev->ack_check_disable ? false : true), .data = (uint8_t *)write_buffer, .total_bytes = write_size}, {.hw_cmd = I2C_TRANS_START_COMMAND}, {.hw_cmd = I2C_TRANS_READ_COMMAND(ACK_VAL), .data = read_buffer, .total_bytes = read_size - 1}, {.hw_cmd = I2C_TRANS_READ_COMMAND(NACK_VAL), .data = (read_buffer + read_size - 1), .total_bytes = 1}, @@ -1059,6 +1084,7 @@ esp_err_t i2c_master_probe(i2c_master_bus_handle_t bus_handle, uint16_t address, if (xSemaphoreTake(bus_handle->bus_lock_mux, ticks_to_wait) != pdTRUE) { return ESP_ERR_TIMEOUT; } + esp_err_t ret = ESP_OK; bus_handle->cmd_idx = 0; bus_handle->trans_idx = 0; @@ -1082,17 +1108,22 @@ esp_err_t i2c_master_probe(i2c_master_bus_handle_t bus_handle, uint16_t address, i2c_hal_set_bus_timing(hal, 100000, bus_handle->base->clk_src, bus_handle->base->clk_src_freq_hz); } i2c_ll_master_set_fractional_divider(hal->dev, 0, 0); + i2c_ll_enable_intr_mask(hal->dev, I2C_LL_MASTER_EVENT_INTR); i2c_ll_update(hal->dev); s_i2c_send_commands(bus_handle, ticks_to_wait); if (bus_handle->status == I2C_STATUS_ACK_ERROR) { - // Reset the status to done, in order not influence next time transaction. - bus_handle->status = I2C_STATUS_DONE; - xSemaphoreGive(bus_handle->bus_lock_mux); - return ESP_ERR_NOT_FOUND; + ret = ESP_ERR_NOT_FOUND; + } else if (bus_handle->status == I2C_STATUS_TIMEOUT) { + ESP_LOGE(TAG, "probe device timeout. Please check if xfer_timeout_ms and pull-ups are correctly set up"); + ret = ESP_ERR_TIMEOUT; } + + // Reset the status to done, in order not influence next time transaction. + bus_handle->status = I2C_STATUS_DONE; + i2c_ll_disable_intr_mask(hal->dev, I2C_LL_MASTER_EVENT_INTR); xSemaphoreGive(bus_handle->bus_lock_mux); - return ESP_OK; + return ret; } esp_err_t i2c_master_register_event_callbacks(i2c_master_dev_handle_t i2c_dev, const i2c_master_event_callbacks_t *cbs, void *user_data) diff --git a/components/esp_driver_i2c/i2c_private.h b/components/esp_driver_i2c/i2c_private.h index 57ef2b71b7..911b881d3a 100644 --- a/components/esp_driver_i2c/i2c_private.h +++ b/components/esp_driver_i2c/i2c_private.h @@ -138,6 +138,7 @@ struct i2c_master_bus_t { uint32_t w_r_size; // The size send/receive last time. bool trans_over_buffer; // Data length is more than hardware fifo length, needs interrupt. bool async_trans; // asynchronous transaction, true after callback is installed. + bool ack_check_disable; // Disable ACK check volatile bool trans_done; // transaction command finish SLIST_HEAD(i2c_master_device_list_head, i2c_master_device_list) device_list; // I2C device (instance) list // asnyc trans members @@ -165,6 +166,7 @@ struct i2c_master_dev_t { uint16_t device_address; // I2C device address uint32_t scl_speed_hz; // SCL clock frequency i2c_addr_bit_len_t addr_10bits; // Whether I2C device is a 10-bits address device. + bool ack_check_disable; // Disable ACK check i2c_master_callback_t on_trans_done; // I2C master transaction done callback. void *user_ctx; // Callback user context }; diff --git a/components/esp_driver_i2c/include/driver/i2c_master.h b/components/esp_driver_i2c/include/driver/i2c_master.h index 228f64fcc9..f4fc6acdb8 100644 --- a/components/esp_driver_i2c/include/driver/i2c_master.h +++ b/components/esp_driver_i2c/include/driver/i2c_master.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -38,6 +38,9 @@ typedef struct { i2c_addr_bit_len_t dev_addr_length; /*!< Select the address length of the slave device. */ uint16_t device_address; /*!< I2C device raw address. (The 7/10 bit address without read/write bit) */ uint32_t scl_speed_hz; /*!< I2C SCL line frequency. */ + struct { + uint32_t disable_ack_check: 1; /*!< Disable ACK check. If this is set false, that means ack check is enabled, the transaction will be stoped and API returns error when nack is detected. */ + } flags; /*!< I2C device config flags */ } i2c_device_config_t; /** @@ -160,6 +163,19 @@ esp_err_t i2c_master_receive(i2c_master_dev_handle_t i2c_dev, uint8_t *read_buff * @param[in] bus_handle I2C master device handle that created by `i2c_master_bus_add_device`. * @param[in] address I2C device address that you want to probe. * @param[in] xfer_timeout_ms Wait timeout, in ms. Note: -1 means wait forever (Not recommended in this function). + * + * @attention Pull-ups must be connected to the SCL and SDA pins when this function is called. If you get `ESP_ERR_TIMEOUT + * while `xfer_timeout_ms` was parsed correctly, you should check the pull-up resistors. If you do not have proper resistors nearby. + * `flags.enable_internal_pullup` is also acceptable. + * + * @note The principle of this function is to sent device address with a write command. If the device on your I2C bus, there would be an ACK signal and function + * returns `ESP_OK`. If the device is not on your I2C bus, there would be a NACK signal and function returns `ESP_ERR_NOT_FOUND`. `ESP_ERR_TIMEOUT` is not an expected + * failure, which indicated that the i2c probe not works properly, usually caused by pull-up resistors not be connected properly. Suggestion check data on SDA/SCL line + * to see whether there is ACK/NACK signal is on line when i2c probe function fails. + * + * @note There are lots of I2C devices all over the world, we assume that not all I2C device support the behavior like `device_address+nack/ack`. + * So, if the on line data is strange and no ack/nack got respond. Please check the device datasheet. + * * @return * - ESP_OK: I2C device probe successfully * - ESP_ERR_NOT_FOUND: I2C probe failed, doesn't find the device with specific address you gave. diff --git a/components/esp_driver_i2c/test_apps/i2c_test_apps/main/test_i2c_common.c b/components/esp_driver_i2c/test_apps/i2c_test_apps/main/test_i2c_common.c index 964892fb49..1aa749c82c 100644 --- a/components/esp_driver_i2c/test_apps/i2c_test_apps/main/test_i2c_common.c +++ b/components/esp_driver_i2c/test_apps/i2c_test_apps/main/test_i2c_common.c @@ -26,6 +26,24 @@ static const char TAG[] = "test-i2c"; +// Make it as a local test, because don't know where there happened to be any pull-up on CI. +TEST_CASE("I2C master initialize without pins pull-up ", "[i2c][ignore]") +{ + i2c_master_bus_config_t i2c_mst_config_1 = { + .clk_source = I2C_CLK_SRC_DEFAULT, + .i2c_port = TEST_I2C_PORT, + .scl_io_num = I2C_MASTER_SCL_IO, + .sda_io_num = I2C_MASTER_SDA_IO, + .flags.enable_internal_pullup = false, // no pull-up + }; + i2c_master_bus_handle_t bus_handle; + + TEST_ESP_OK(i2c_new_master_bus(&i2c_mst_config_1, &bus_handle)); + TEST_ESP_ERR(ESP_ERR_TIMEOUT, i2c_master_probe(bus_handle, 0x22, 20)); + vTaskDelay(1000); + TEST_ESP_OK(i2c_del_master_bus(bus_handle)); +} + TEST_CASE("I2C bus install-uninstall test", "[i2c]") { i2c_master_bus_config_t i2c_mst_config_1 = { @@ -142,10 +160,10 @@ TEST_CASE("I2C master probe device test", "[i2c]") i2c_master_bus_handle_t bus_handle; TEST_ESP_OK(i2c_new_master_bus(&i2c_mst_config_1, &bus_handle)); - TEST_ESP_ERR(i2c_master_probe(bus_handle, 0x22, -1), ESP_ERR_NOT_FOUND); - TEST_ESP_ERR(i2c_master_probe(bus_handle, 0x33, -1), ESP_ERR_NOT_FOUND); - TEST_ESP_ERR(i2c_master_probe(bus_handle, 0x44, -1), ESP_ERR_NOT_FOUND); - TEST_ESP_ERR(i2c_master_probe(bus_handle, 0x55, -1), ESP_ERR_NOT_FOUND); + TEST_ESP_ERR(ESP_ERR_NOT_FOUND, i2c_master_probe(bus_handle, 0x22, -1)); + TEST_ESP_ERR(ESP_ERR_NOT_FOUND, i2c_master_probe(bus_handle, 0x33, -1)); + TEST_ESP_ERR(ESP_ERR_NOT_FOUND, i2c_master_probe(bus_handle, 0x44, -1)); + TEST_ESP_ERR(ESP_ERR_NOT_FOUND, i2c_master_probe(bus_handle, 0x55, -1)); TEST_ESP_OK(i2c_del_master_bus(bus_handle)); } @@ -187,6 +205,7 @@ TEST_CASE("I2C master transaction non-blocking mode with large amount of transac .dev_addr_length = I2C_ADDR_BIT_LEN_7, .device_address = 0x58, .scl_speed_hz = 400000, + .flags.disable_ack_check = true, }; i2c_master_dev_handle_t dev_handle; @@ -229,3 +248,65 @@ TEST_CASE("I2C master transaction non-blocking mode with large amount of transac TEST_ESP_OK(i2c_master_bus_rm_device(dev_handle)); TEST_ESP_OK(i2c_del_master_bus(bus_handle)); } + +static void _test_i2c_new_bus_device(i2c_master_bus_handle_t *bus_handle, i2c_master_dev_handle_t *dev_handle) +{ + i2c_master_bus_config_t i2c_mst_config = { + .clk_source = I2C_CLK_SRC_DEFAULT, + .i2c_port = TEST_I2C_PORT, + .scl_io_num = I2C_MASTER_SCL_IO, + .sda_io_num = I2C_MASTER_SDA_IO, + .flags.enable_internal_pullup = true, + }; + + TEST_ESP_OK(i2c_new_master_bus(&i2c_mst_config, bus_handle)); + + i2c_device_config_t dev_cfg = { + .dev_addr_length = I2C_ADDR_BIT_LEN_7, + .device_address = 0x58, + .scl_speed_hz = 100000, + }; + + TEST_ESP_OK(i2c_master_bus_add_device(*bus_handle, &dev_cfg, dev_handle)); +} + +static void _test_i2c_del_bus_device(i2c_master_bus_handle_t bus_handle, i2c_master_dev_handle_t dev_handle) +{ + TEST_ESP_OK(i2c_master_bus_rm_device(dev_handle)); + TEST_ESP_OK(i2c_del_master_bus(bus_handle)); +} + +TEST_CASE("I2C master transaction transmit check nack return value", "[i2c]") +{ + uint8_t data_wr[DATA_LENGTH] = { 0 }; + + i2c_master_bus_handle_t bus_handle; + i2c_master_dev_handle_t dev_handle; + _test_i2c_new_bus_device(&bus_handle, &dev_handle); + TEST_ESP_ERR(ESP_ERR_INVALID_STATE, i2c_master_transmit(dev_handle, data_wr, DATA_LENGTH, -1)); + _test_i2c_del_bus_device(bus_handle, dev_handle); +} + +TEST_CASE("I2C master transaction transmit receive check nack return value", "[i2c]") +{ + uint8_t data_wr[DATA_LENGTH] = { 0 }; + uint8_t data_rd[DATA_LENGTH] = { 0 }; + + i2c_master_bus_handle_t bus_handle; + i2c_master_dev_handle_t dev_handle; + _test_i2c_new_bus_device(&bus_handle, &dev_handle); + TEST_ESP_ERR(ESP_ERR_INVALID_STATE, i2c_master_transmit_receive(dev_handle, data_wr, DATA_LENGTH, data_rd, DATA_LENGTH, -1)); + _test_i2c_del_bus_device(bus_handle, dev_handle); +} + +TEST_CASE("I2C master transaction receive check nack return value", "[i2c]") +{ + uint8_t data_rd[DATA_LENGTH] = { 0 }; + + i2c_master_bus_handle_t bus_handle; + i2c_master_dev_handle_t dev_handle; + + _test_i2c_new_bus_device(&bus_handle, &dev_handle); + TEST_ESP_ERR(ESP_ERR_INVALID_STATE, i2c_master_receive(dev_handle, data_rd, DATA_LENGTH, -1)); + _test_i2c_del_bus_device(bus_handle, dev_handle); +} diff --git a/components/esp_driver_i2c/test_apps/i2c_test_apps/main/test_i2c_multi.c b/components/esp_driver_i2c/test_apps/i2c_test_apps/main/test_i2c_multi.c index 2f7e5d45d1..292b6612ce 100644 --- a/components/esp_driver_i2c/test_apps/i2c_test_apps/main/test_i2c_multi.c +++ b/components/esp_driver_i2c/test_apps/i2c_test_apps/main/test_i2c_multi.c @@ -552,6 +552,60 @@ static void slave_write_buffer_1b_test(void) TEST_CASE_MULTIPLE_DEVICES("I2C master read slave 1 byte test", "[i2c][test_env=generic_multi_device][timeout=150]", master_read_slave_1b_test, slave_write_buffer_1b_test); +static void master_probe_slave(void) +{ + i2c_master_bus_config_t i2c_mst_config = { + .clk_source = I2C_CLK_SRC_DEFAULT, + .i2c_port = TEST_I2C_PORT, + .scl_io_num = I2C_MASTER_SCL_IO, + .sda_io_num = I2C_MASTER_SDA_IO, + .flags.enable_internal_pullup = true, + }; + i2c_master_bus_handle_t bus_handle; + TEST_ESP_OK(i2c_new_master_bus(&i2c_mst_config, &bus_handle)); + + unity_wait_for_signal("i2c slave init finish"); + + esp_err_t ret = ESP_OK; + for (uint8_t i = 0x01; i < 0x7F; i++) { + ret = i2c_master_probe(bus_handle, i, -1); + if (ret == ESP_OK) { + printf("The slave has been found, the address is %x\n", i); + TEST_ASSERT(i == 0x58); + break; + } + TEST_ASSERT(ret == ESP_ERR_NOT_FOUND); + } + + unity_send_signal("probe finish"); + + TEST_ESP_OK(i2c_del_master_bus(bus_handle)); +} + +static void slave_init_for_probe(void) +{ + i2c_slave_config_t i2c_slv_config = { + .addr_bit_len = I2C_ADDR_BIT_LEN_7, + .clk_source = I2C_CLK_SRC_DEFAULT, + .i2c_port = TEST_I2C_PORT, + .send_buf_depth = 256, + .scl_io_num = I2C_SLAVE_SCL_IO, + .sda_io_num = I2C_SLAVE_SDA_IO, + .slave_addr = 0x58, + }; + + i2c_slave_dev_handle_t slave_handle; + TEST_ESP_OK(i2c_new_slave_device(&i2c_slv_config, &slave_handle)); + + unity_send_signal("i2c slave init finish"); + + unity_wait_for_signal("probe finish"); + + TEST_ESP_OK(i2c_del_slave_device(slave_handle)); +} + +TEST_CASE_MULTIPLE_DEVICES("I2C master probe slave test", "[i2c][test_env=generic_multi_device][timeout=150]", master_probe_slave, slave_init_for_probe); + #if SOC_I2C_NUM > 1 // Now chips with mutiple I2C controllers are up to 2, can change this to interation when we have more I2C controllers. static void i2c_master_write_test_more_port(void) diff --git a/docs/en/api-reference/peripherals/i2c.rst b/docs/en/api-reference/peripherals/i2c.rst index 74f6da3322..ff861008f5 100644 --- a/docs/en/api-reference/peripherals/i2c.rst +++ b/docs/en/api-reference/peripherals/i2c.rst @@ -297,6 +297,10 @@ I2C Master Probe I2C driver can use :cpp:func:`i2c_master_probe` to detect whether the specific device has been connected on I2C bus. If this function return ``ESP_OK``, that means the device has been detected. +.. important:: + + Pull-ups must be connected to the SCL and SDA pins when this function is called. If you get `ESP_ERR_TIMEOUT` while `xfer_timeout_ms` was parsed correctly, you should check the pull-up resistors. If you do not have proper resistors nearby, setting `flags.enable_internal_pullup` as true is also acceptable. + .. figure:: ../../../_static/diagrams/i2c/i2c_master_probe.png :align: center :alt: I2C master probe