From 7c233ebc807dd7181b345c02dcaf854718974933 Mon Sep 17 00:00:00 2001 From: Cao Sen Miao Date: Tue, 19 Mar 2024 12:15:24 +0800 Subject: [PATCH] feat(i2c_master): Add parameter to config I2C scl await time --- components/driver/i2c/i2c_master.c | 2 ++ components/driver/i2c/i2c_private.h | 1 + .../driver/i2c/include/driver/i2c_master.h | 1 + components/hal/esp32/include/hal/i2c_ll.h | 14 ++++++++++++++ components/hal/esp32c2/include/hal/i2c_ll.h | 14 ++++++++++++++ components/hal/esp32c3/include/hal/i2c_ll.h | 14 ++++++++++++++ components/hal/esp32c6/include/hal/i2c_ll.h | 16 +++++++++++++++- components/hal/esp32h2/include/hal/i2c_ll.h | 16 +++++++++++++++- components/hal/esp32p4/include/hal/i2c_ll.h | 16 +++++++++++++++- components/hal/esp32s2/include/hal/i2c_ll.h | 14 ++++++++++++++ components/hal/esp32s3/include/hal/i2c_ll.h | 14 ++++++++++++++ components/hal/i2c_hal.c | 6 ++++++ components/hal/include/hal/i2c_hal.h | 9 +++++++++ docs/en/api-reference/peripherals/i2c.rst | 2 ++ 14 files changed, 136 insertions(+), 3 deletions(-) diff --git a/components/driver/i2c/i2c_master.c b/components/driver/i2c/i2c_master.c index 1bbfc80a6f..13954c805d 100644 --- a/components/driver/i2c/i2c_master.c +++ b/components/driver/i2c/i2c_master.c @@ -529,6 +529,7 @@ static esp_err_t s_i2c_transaction_start(i2c_master_dev_handle_t i2c_dev, int xf i2c_master->rx_cnt = 0; i2c_master->read_len_static = 0; + i2c_hal_master_set_scl_timeout_val(hal, i2c_dev->scl_wait_us, i2c_master->base->clk_src_freq_hz); i2c_hal_set_bus_timing(hal, i2c_dev->scl_speed_hz, i2c_master->base->clk_src, i2c_master->base->clk_src_freq_hz); i2c_ll_master_set_fractional_divider(hal->dev, 0, 0); i2c_ll_update(hal->dev); @@ -957,6 +958,7 @@ esp_err_t i2c_master_bus_add_device(i2c_master_bus_handle_t bus_handle, const i2 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_dev->scl_wait_us = (dev_config->scl_wait_us == 0) ? I2C_LL_SCL_WAIT_US_VAL_DEFAULT : dev_config->scl_wait_us; 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`"); diff --git a/components/driver/i2c/i2c_private.h b/components/driver/i2c/i2c_private.h index 4e4bf1076d..fde194dacb 100644 --- a/components/driver/i2c/i2c_private.h +++ b/components/driver/i2c/i2c_private.h @@ -152,6 +152,7 @@ struct i2c_master_dev_t { i2c_master_bus_t *master_bus; // I2C master bus base class uint16_t device_address; // I2C device address uint32_t scl_speed_hz; // SCL clock frequency + uint32_t scl_wait_us; // SCL await time (unit:us) 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. diff --git a/components/driver/i2c/include/driver/i2c_master.h b/components/driver/i2c/include/driver/i2c_master.h index c0ca2e5ea5..cdbc564436 100644 --- a/components/driver/i2c/include/driver/i2c_master.h +++ b/components/driver/i2c/include/driver/i2c_master.h @@ -38,6 +38,7 @@ 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. */ + uint32_t scl_wait_us; /*!< Timeout value. (unit: us). Please note this value should not be so small that it can handle stretch/disturbance properly. If 0 is set, that means use the default reg value*/ 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 */ diff --git a/components/hal/esp32/include/hal/i2c_ll.h b/components/hal/esp32/include/hal/i2c_ll.h index 73d85a802e..e78a7ff32d 100644 --- a/components/hal/esp32/include/hal/i2c_ll.h +++ b/components/hal/esp32/include/hal/i2c_ll.h @@ -69,6 +69,7 @@ typedef enum { #define I2C_LL_SLAVE_EVENT_INTR (I2C_TRANS_COMPLETE_INT_ENA_M|I2C_TXFIFO_EMPTY_INT_ENA_M|I2C_RX_REC_FULL_INT_ST_M) #define I2C_LL_SLAVE_RX_EVENT_INTR (I2C_TRANS_COMPLETE_INT_ENA_M|I2C_RX_REC_FULL_INT_ST_M) #define I2C_LL_SLAVE_TX_EVENT_INTR (I2C_TXFIFO_EMPTY_INT_ENA_M) +#define I2C_LL_SCL_WAIT_US_VAL_DEFAULT (2000) // 2000 is not default value on esp32, but 0 is not good to be default /** * @brief Calculate I2C bus frequency @@ -749,6 +750,19 @@ static inline void i2c_ll_slave_clear_stretch(i2c_dev_t *dev) // Not supported on esp32 } +/** + * @brief Calculate SCL timeout us to reg value + * + * @param timeout_us timeout value in us + * @param src_clk_hz source clock frequency + * @return uint32_t reg value + */ +static inline uint32_t i2c_ll_calculate_timeout_us_to_reg_val(uint32_t src_clk_hz, uint32_t timeout_us) +{ + uint32_t clk_cycle_num_per_us = src_clk_hz / (1 * 1000 * 1000); + return clk_cycle_num_per_us * timeout_us; +} + //////////////////////////////////////////Deprecated Functions////////////////////////////////////////////////////////// /////////////////////////////The following functions are only used by the legacy driver///////////////////////////////// /////////////////////////////They might be removed in the next major release (ESP-IDF 6.0)////////////////////////////// diff --git a/components/hal/esp32c2/include/hal/i2c_ll.h b/components/hal/esp32c2/include/hal/i2c_ll.h index 58d6da0f43..a7550cab69 100644 --- a/components/hal/esp32c2/include/hal/i2c_ll.h +++ b/components/hal/esp32c2/include/hal/i2c_ll.h @@ -59,6 +59,7 @@ typedef enum { #define I2C_LL_GET_HW(i2c_num) (&I2C0) #define I2C_LL_MASTER_EVENT_INTR (I2C_NACK_INT_ENA_M|I2C_TIME_OUT_INT_ENA_M|I2C_TRANS_COMPLETE_INT_ENA_M|I2C_ARBITRATION_LOST_INT_ENA_M|I2C_END_DETECT_INT_ENA_M) #define I2C_LL_RESET_SLV_SCL_PULSE_NUM_DEFAULT (9) +#define I2C_LL_SCL_WAIT_US_VAL_DEFAULT (2000) // Approximate value for SCL timeout regs (in us). /** * @brief Calculate I2C bus frequency @@ -698,6 +699,19 @@ static inline volatile void *i2c_ll_get_interrupt_status_reg(i2c_dev_t *dev) return &dev->int_status; } +/** + * @brief Calculate SCL timeout us to reg value + * + * @param timeout_us timeout value in us + * @param src_clk_hz source clock frequency + * @return uint32_t reg value + */ +static inline uint32_t i2c_ll_calculate_timeout_us_to_reg_val(uint32_t src_clk_hz, uint32_t timeout_us) +{ + uint32_t clk_cycle_num_per_us = src_clk_hz / (1 * 1000 * 1000); + return 31 - __builtin_clz(clk_cycle_num_per_us * timeout_us); +} + //////////////////////////////////////////Deprecated Functions////////////////////////////////////////////////////////// /////////////////////////////The following functions are only used by the legacy driver///////////////////////////////// /////////////////////////////They might be removed in the next major release (ESP-IDF 6.0)////////////////////////////// diff --git a/components/hal/esp32c3/include/hal/i2c_ll.h b/components/hal/esp32c3/include/hal/i2c_ll.h index 3dcedf8f5a..11091748ee 100644 --- a/components/hal/esp32c3/include/hal/i2c_ll.h +++ b/components/hal/esp32c3/include/hal/i2c_ll.h @@ -73,6 +73,7 @@ typedef enum { #define I2C_LL_SLAVE_RX_EVENT_INTR (I2C_TRANS_COMPLETE_INT_ENA_M | I2C_RXFIFO_WM_INT_ENA_M | I2C_SLAVE_STRETCH_INT_ENA_M) #define I2C_LL_SLAVE_TX_EVENT_INTR (I2C_TXFIFO_WM_INT_ENA_M) #define I2C_LL_RESET_SLV_SCL_PULSE_NUM_DEFAULT (9) +#define I2C_LL_SCL_WAIT_US_VAL_DEFAULT (2000) // Approximate value for SCL timeout regs (in us). /** * @brief Calculate I2C bus frequency @@ -871,6 +872,19 @@ static inline void i2c_ll_slave_clear_stretch(i2c_dev_t *dev) dev->scl_stretch_conf.slave_scl_stretch_clr = 1; } +/** + * @brief Calculate SCL timeout us to reg value + * + * @param timeout_us timeout value in us + * @param src_clk_hz source clock frequency + * @return uint32_t reg value + */ +static inline uint32_t i2c_ll_calculate_timeout_us_to_reg_val(uint32_t src_clk_hz, uint32_t timeout_us) +{ + uint32_t clk_cycle_num_per_us = src_clk_hz / (1 * 1000 * 1000); + return 31 - __builtin_clz(clk_cycle_num_per_us * timeout_us); +} + //////////////////////////////////////////Deprecated Functions////////////////////////////////////////////////////////// /////////////////////////////The following functions are only used by the legacy driver///////////////////////////////// /////////////////////////////They might be removed in the next major release (ESP-IDF 6.0)////////////////////////////// diff --git a/components/hal/esp32c6/include/hal/i2c_ll.h b/components/hal/esp32c6/include/hal/i2c_ll.h index b6dadfa477..6b6aa120f1 100644 --- a/components/hal/esp32c6/include/hal/i2c_ll.h +++ b/components/hal/esp32c6/include/hal/i2c_ll.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -75,6 +75,7 @@ typedef enum { #define I2C_LL_SLAVE_RX_EVENT_INTR (I2C_TRANS_COMPLETE_INT_ENA_M | I2C_RXFIFO_WM_INT_ENA_M | I2C_SLAVE_STRETCH_INT_ENA_M) #define I2C_LL_SLAVE_TX_EVENT_INTR (I2C_TXFIFO_WM_INT_ENA_M) #define I2C_LL_RESET_SLV_SCL_PULSE_NUM_DEFAULT (9) +#define I2C_LL_SCL_WAIT_US_VAL_DEFAULT (2000) // Approximate value for SCL timeout regs (in us). /** * @brief Calculate I2C bus frequency @@ -912,6 +913,19 @@ static inline void i2c_ll_slave_clear_stretch(i2c_dev_t *dev) dev->scl_stretch_conf.slave_scl_stretch_clr = 1; } +/** + * @brief Calculate SCL timeout us to reg value + * + * @param timeout_us timeout value in us + * @param src_clk_hz source clock frequency + * @return uint32_t reg value + */ +static inline uint32_t i2c_ll_calculate_timeout_us_to_reg_val(uint32_t src_clk_hz, uint32_t timeout_us) +{ + uint32_t clk_cycle_num_per_us = src_clk_hz / (1 * 1000 * 1000); + return 31 - __builtin_clz(clk_cycle_num_per_us * timeout_us); +} + //////////////////////////////////////////Deprecated Functions////////////////////////////////////////////////////////// /////////////////////////////The following functions are only used by the legacy driver///////////////////////////////// /////////////////////////////They might be removed in the next major release (ESP-IDF 6.0)////////////////////////////// diff --git a/components/hal/esp32h2/include/hal/i2c_ll.h b/components/hal/esp32h2/include/hal/i2c_ll.h index d6833dca44..26ff59a11a 100644 --- a/components/hal/esp32h2/include/hal/i2c_ll.h +++ b/components/hal/esp32h2/include/hal/i2c_ll.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -74,6 +74,7 @@ typedef enum { #define I2C_LL_SLAVE_RX_EVENT_INTR (I2C_TRANS_COMPLETE_INT_ENA_M | I2C_RXFIFO_WM_INT_ENA_M | I2C_SLAVE_STRETCH_INT_ENA_M) #define I2C_LL_SLAVE_TX_EVENT_INTR (I2C_TXFIFO_WM_INT_ENA_M) #define I2C_LL_RESET_SLV_SCL_PULSE_NUM_DEFAULT (9) +#define I2C_LL_SCL_WAIT_US_VAL_DEFAULT (2500) // Approximate value for SCL timeout regs (in us). /** * @brief Calculate I2C bus frequency @@ -829,6 +830,19 @@ static inline void i2c_ll_slave_clear_stretch(i2c_dev_t *dev) dev->scl_stretch_conf.slave_scl_stretch_clr = 1; } +/** + * @brief Calculate SCL timeout us to reg value + * + * @param timeout_us timeout value in us + * @param src_clk_hz source clock frequency + * @return uint32_t reg value + */ +static inline uint32_t i2c_ll_calculate_timeout_us_to_reg_val(uint32_t src_clk_hz, uint32_t timeout_us) +{ + uint32_t clk_cycle_num_per_us = src_clk_hz / (1 * 1000 * 1000); + return 31 - __builtin_clz(clk_cycle_num_per_us * timeout_us); +} + //////////////////////////////////////////Deprecated Functions////////////////////////////////////////////////////////// /////////////////////////////The following functions are only used by the legacy driver///////////////////////////////// /////////////////////////////They might be removed in the next major release (ESP-IDF 6.0)////////////////////////////// diff --git a/components/hal/esp32p4/include/hal/i2c_ll.h b/components/hal/esp32p4/include/hal/i2c_ll.h index 5983c5a930..88940be813 100644 --- a/components/hal/esp32p4/include/hal/i2c_ll.h +++ b/components/hal/esp32p4/include/hal/i2c_ll.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -79,6 +79,7 @@ typedef enum { #define I2C_LL_SLAVE_RX_EVENT_INTR (I2C_TRANS_COMPLETE_INT_ENA_M | I2C_RXFIFO_WM_INT_ENA_M | I2C_SLAVE_STRETCH_INT_ENA_M) #define I2C_LL_SLAVE_TX_EVENT_INTR (I2C_TXFIFO_WM_INT_ENA_M) #define I2C_LL_RESET_SLV_SCL_PULSE_NUM_DEFAULT (9) +#define I2C_LL_SCL_WAIT_US_VAL_DEFAULT (2000) // Approximate value for SCL timeout regs (in us). /** * @brief Calculate I2C bus frequency @@ -850,6 +851,19 @@ static inline void i2c_ll_slave_clear_stretch(i2c_dev_t *dev) dev->scl_stretch_conf.slave_scl_stretch_clr = 1; } +/** + * @brief Calculate SCL timeout us to reg value + * + * @param timeout_us timeout value in us + * @param src_clk_hz source clock frequency + * @return uint32_t reg value + */ +static inline uint32_t i2c_ll_calculate_timeout_us_to_reg_val(uint32_t src_clk_hz, uint32_t timeout_us) +{ + uint32_t clk_cycle_num_per_us = src_clk_hz / (1 * 1000 * 1000); + return 31 - __builtin_clz(clk_cycle_num_per_us * timeout_us); +} + //////////////////////////////////////////Deprecated Functions////////////////////////////////////////////////////////// /////////////////////////////The following functions are only used by the legacy driver///////////////////////////////// /////////////////////////////They might be removed in the next major release (ESP-IDF 6.0)////////////////////////////// diff --git a/components/hal/esp32s2/include/hal/i2c_ll.h b/components/hal/esp32s2/include/hal/i2c_ll.h index 9a648beeb6..f068512996 100644 --- a/components/hal/esp32s2/include/hal/i2c_ll.h +++ b/components/hal/esp32s2/include/hal/i2c_ll.h @@ -69,6 +69,7 @@ typedef enum { #define I2C_LL_SLAVE_RX_EVENT_INTR (I2C_TRANS_COMPLETE_INT_ENA_M | I2C_RXFIFO_WM_INT_ENA_M | I2C_SLAVE_STRETCH_INT_ENA_M) #define I2C_LL_SLAVE_TX_EVENT_INTR (I2C_TXFIFO_WM_INT_ENA_M) #define I2C_LL_RESET_SLV_SCL_PULSE_NUM_DEFAULT (9) +#define I2C_LL_SCL_WAIT_US_VAL_DEFAULT (2000) // 2000 is not default value on esp32s2, but 0 is not good to be default /** * @brief Calculate I2C bus frequency @@ -798,6 +799,19 @@ static inline void i2c_ll_slave_clear_stretch(i2c_dev_t *dev) dev->scl_stretch_conf.slave_scl_stretch_clr = 1; } +/** + * @brief Calculate SCL timeout us to reg value + * + * @param timeout_us timeout value in us + * @param src_clk_hz source clock frequency + * @return uint32_t reg value + */ +static inline uint32_t i2c_ll_calculate_timeout_us_to_reg_val(uint32_t src_clk_hz, uint32_t timeout_us) +{ + uint32_t clk_cycle_num_per_us = src_clk_hz / (1 * 1000 * 1000); + return clk_cycle_num_per_us * timeout_us; +} + //////////////////////////////////////////Deprecated Functions////////////////////////////////////////////////////////// /////////////////////////////The following functions are only used by the legacy driver///////////////////////////////// /////////////////////////////They might be removed in the next major release (ESP-IDF 6.0)////////////////////////////// diff --git a/components/hal/esp32s3/include/hal/i2c_ll.h b/components/hal/esp32s3/include/hal/i2c_ll.h index e4b758c3a9..f833cf9aa5 100644 --- a/components/hal/esp32s3/include/hal/i2c_ll.h +++ b/components/hal/esp32s3/include/hal/i2c_ll.h @@ -73,6 +73,7 @@ typedef enum { #define I2C_LL_SLAVE_RX_EVENT_INTR (I2C_TRANS_COMPLETE_INT_ENA_M | I2C_RXFIFO_WM_INT_ENA_M | I2C_SLAVE_STRETCH_INT_ENA_M) #define I2C_LL_SLAVE_TX_EVENT_INTR (I2C_TXFIFO_WM_INT_ENA_M) #define I2C_LL_RESET_SLV_SCL_PULSE_NUM_DEFAULT (9) +#define I2C_LL_SCL_WAIT_US_VAL_DEFAULT (2000) // Approximate value for SCL timeout regs (in us). /** * @brief Calculate I2C bus frequency @@ -865,6 +866,19 @@ static inline void i2c_ll_slave_clear_stretch(i2c_dev_t *dev) dev->scl_stretch_conf.slave_scl_stretch_clr = 1; } +/** + * @brief Calculate SCL timeout us to reg value + * + * @param timeout_us timeout value in us + * @param src_clk_hz source clock frequency + * @return uint32_t reg value + */ +static inline uint32_t i2c_ll_calculate_timeout_us_to_reg_val(uint32_t src_clk_hz, uint32_t timeout_us) +{ + uint32_t clk_cycle_num_per_us = src_clk_hz / (1 * 1000 * 1000); + return 31 - __builtin_clz(clk_cycle_num_per_us * timeout_us); +} + //////////////////////////////////////////Deprecated Functions////////////////////////////////////////////////////////// /////////////////////////////The following functions are only used by the legacy driver///////////////////////////////// /////////////////////////////They might be removed in the next major release (ESP-IDF 6.0)////////////////////////////// diff --git a/components/hal/i2c_hal.c b/components/hal/i2c_hal.c index abf4b03db4..3e43f56027 100644 --- a/components/hal/i2c_hal.c +++ b/components/hal/i2c_hal.c @@ -59,6 +59,12 @@ void i2c_hal_deinit(i2c_hal_context_t *hal) hal->dev = NULL; } +void i2c_hal_master_set_scl_timeout_val(i2c_hal_context_t *hal, uint32_t timeout_us, uint32_t sclk_clock_hz) +{ + uint32_t reg_val = i2c_ll_calculate_timeout_us_to_reg_val(sclk_clock_hz, timeout_us); + i2c_ll_set_tout(hal->dev, reg_val); +} + #if !SOC_I2C_SUPPORT_HW_FSM_RST void i2c_hal_get_timing_config(i2c_hal_context_t *hal, i2c_hal_timing_config_t *timing_config) diff --git a/components/hal/include/hal/i2c_hal.h b/components/hal/include/hal/i2c_hal.h index 7b0629ee85..831c7b6f52 100644 --- a/components/hal/include/hal/i2c_hal.h +++ b/components/hal/include/hal/i2c_hal.h @@ -124,6 +124,15 @@ void i2c_hal_master_handle_tx_event(i2c_hal_context_t *hal, i2c_intr_event_t *ev */ void i2c_hal_master_handle_rx_event(i2c_hal_context_t *hal, i2c_intr_event_t *event); +/** + * @brief Set scl timeout reg value according to given timeout us and source clock frequency + * + * @param hal Context of the HAL layer + * @param timeout_us timeout us + * @param sclk_clock_hz source clock hz + */ +void i2c_hal_master_set_scl_timeout_val(i2c_hal_context_t *hal, uint32_t timeout_us, uint32_t sclk_clock_hz); + /** * @brief Init I2C hal layer * diff --git a/docs/en/api-reference/peripherals/i2c.rst b/docs/en/api-reference/peripherals/i2c.rst index 7adc7dae42..519135740e 100644 --- a/docs/en/api-reference/peripherals/i2c.rst +++ b/docs/en/api-reference/peripherals/i2c.rst @@ -104,6 +104,8 @@ I2C master device requires the configuration that specified by :cpp:type:`i2c_de - :cpp:member:`i2c_device_config_t::dev_addr_length` configure the address bit length of the slave device. User can choose from enumerator :cpp:enumerator:`I2C_ADDR_BIT_LEN_7` or :cpp:enumerator:`I2C_ADDR_BIT_LEN_10` (if supported). - :cpp:member:`i2c_device_config_t::device_address` I2C device raw address. Please parse the device address to this member directly. For example, the device address is 0x28, then parse 0x28 to :cpp:member:`i2c_device_config_t::device_address`, don't carry a write/read bit. - :cpp:member:`i2c_device_config_t::scl_speed_hz` set the scl line frequency of this device. +- :cpp:member:`i2c_device_config_t::scl_wait_us`. SCL await time (in us). Usually this value should not be very small because slave stretch will happen in pretty long time. (It's possible even stretch for 12ms). Set 0 means use default reg value. + Once the :cpp:type:`i2c_device_config_t` structure is populated with mandatory parameters, users can call :cpp:func:`i2c_master_bus_add_device` to allocate an I2C device instance and mounted to the master bus then. This function will return an I2C device handle if it runs correctly. Specifically, when the I2C bus is not initialized properly, calling this function will result in a :c:macro:`ESP_ERR_INVALID_ARG` error.