From 87c6979b97925309c4241c18c4f7ff4a5bb7f452 Mon Sep 17 00:00:00 2001 From: "C.S.M" Date: Tue, 29 Apr 2025 16:17:38 +0800 Subject: [PATCH] fix(i2c): Fix that fsm reset cause i2c scl frequency changed on esp32s2 --- components/esp_driver_i2c/i2c_master.c | 4 ++ components/esp_driver_i2c/i2c_private.h | 7 +-- components/hal/esp32/include/hal/i2c_ll.h | 60 +++++++++++------- components/hal/esp32c2/include/hal/i2c_ll.h | 56 +++++++++++++---- components/hal/esp32c3/include/hal/i2c_ll.h | 61 +++++++++++-------- components/hal/esp32c5/include/hal/i2c_ll.h | 60 +++++++++++------- components/hal/esp32c6/include/hal/i2c_ll.h | 46 +++++++------- components/hal/esp32h2/include/hal/i2c_ll.h | 60 +++++++++++------- components/hal/esp32p4/include/hal/i2c_ll.h | 46 +++++++------- components/hal/esp32s2/include/hal/i2c_ll.h | 59 +++++++++++------- components/hal/esp32s3/include/hal/i2c_ll.h | 61 +++++++++++-------- components/hal/i2c_hal.c | 11 +++- components/hal/include/hal/i2c_types.h | 15 ++++- .../hal_i2c/components/hal_i2c/hal_i2c.c | 8 ++- 14 files changed, 343 insertions(+), 211 deletions(-) diff --git a/components/esp_driver_i2c/i2c_master.c b/components/esp_driver_i2c/i2c_master.c index 7a1106eeea..500b62749c 100644 --- a/components/esp_driver_i2c/i2c_master.c +++ b/components/esp_driver_i2c/i2c_master.c @@ -131,6 +131,10 @@ static esp_err_t s_i2c_hw_fsm_reset(i2c_master_bus_handle_t i2c_master, bool cle } i2c_hal_master_init(hal); + // Restore the clock source here. + I2C_CLOCK_SRC_ATOMIC() { + i2c_ll_set_source_clk(hal->dev, i2c_master->base->clk_src); + } i2c_ll_disable_intr_mask(hal->dev, I2C_LL_INTR_MASK); i2c_ll_clear_intr_mask(hal->dev, I2C_LL_INTR_MASK); i2c_hal_set_timing_config(hal, &timing_config); diff --git a/components/esp_driver_i2c/i2c_private.h b/components/esp_driver_i2c/i2c_private.h index 0751d5dddd..2d4abe02e3 100644 --- a/components/esp_driver_i2c/i2c_private.h +++ b/components/esp_driver_i2c/i2c_private.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2023-2025 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -70,11 +70,6 @@ typedef struct i2c_bus_t *i2c_bus_handle_t; typedef struct i2c_master_dev_t i2c_master_dev_t; typedef struct i2c_slave_dev_t i2c_slave_dev_t; -typedef enum { - I2C_BUS_MODE_MASTER = 0, - I2C_BUS_MODE_SLAVE = 1, -} i2c_bus_mode_t; - typedef enum { I2C_SLAVE_FIFO = 0, I2C_SLAVE_NONFIFO = 1, diff --git a/components/hal/esp32/include/hal/i2c_ll.h b/components/hal/esp32/include/hal/i2c_ll.h index 99a7aa06f0..74c085ff62 100644 --- a/components/hal/esp32/include/hal/i2c_ll.h +++ b/components/hal/esp32/include/hal/i2c_ll.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2015-2025 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -652,6 +652,20 @@ static inline bool i2c_ll_master_is_bus_clear_done(i2c_dev_t *hw) return false; } +/** + * @brief Set the ACK level that the I2C master must send when the Rx FIFO count has reached the threshold value. + * ack_level: 1 (NACK) + * ack_level: 0 (ACK) + * + * @param hw Beginning address of the peripheral registers + * + * @return None + */ +static inline void i2c_ll_master_rx_full_ack_level(i2c_dev_t *hw, int ack_level) +{ + // Not supported on esp32 +} + /** * @brief Set I2C source clock * @@ -678,37 +692,37 @@ static inline void i2c_ll_enable_controller_clock(i2c_dev_t *hw, bool en) } /** - * @brief Init I2C master + * @brief Set the I2C bus mode (Master or Slave) * - * @param hw Beginning address of the peripheral registers - * - * @return None + * @param hw Pointer to the I2C hardware register structure. + * @param mode The desired I2C bus mode (Master or Slave). */ -static inline void i2c_ll_master_init(i2c_dev_t *hw) +static inline void i2c_ll_set_mode(i2c_dev_t *hw, i2c_bus_mode_t mode) { - typeof(hw->ctr) ctrl_reg; - ctrl_reg.val = 0; - ctrl_reg.ms_mode = 1; - ctrl_reg.sda_force_out = 1; - ctrl_reg.scl_force_out = 1; - hw->ctr.val = ctrl_reg.val; + hw->ctr.ms_mode = (mode == I2C_BUS_MODE_MASTER) ? 1 : 0; } /** - * @brief Init I2C slave + * @brief Enable or disable open-drain mode for I2C pins * - * @param hw Beginning address of the peripheral registers - * - * @return None + * @param hw Pointer to the I2C hardware register structure. + * @param enable_od Boolean flag to enable or disable open-drain mode: */ -static inline void i2c_ll_slave_init(i2c_dev_t *hw) +static inline void i2c_ll_enable_pins_open_drain(i2c_dev_t *hw, bool enable_od) { - typeof(hw->ctr) ctrl_reg; - ctrl_reg.val = 0; - ctrl_reg.sda_force_out = 1; - ctrl_reg.scl_force_out = 1; - hw->ctr.val = ctrl_reg.val; - hw->fifo_conf.fifo_addr_cfg_en = 0; + hw->ctr.sda_force_out = enable_od; + hw->ctr.scl_force_out = enable_od; +} + +/** + * @brief Enable or disable arbitration for I2C communication. + * + * @param hw Pointer to the I2C hardware instance. + * @param enable_arbi Boolean flag to enable (true) or disable (false) arbitration. + */ +static inline void i2c_ll_enable_arbitration(i2c_dev_t *hw, bool enable_arbi) +{ + ;// ESP32 do not support } /** diff --git a/components/hal/esp32c2/include/hal/i2c_ll.h b/components/hal/esp32c2/include/hal/i2c_ll.h index 104df947c6..a711993fca 100644 --- a/components/hal/esp32c2/include/hal/i2c_ll.h +++ b/components/hal/esp32c2/include/hal/i2c_ll.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2020-2024 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2020-2025 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -692,6 +692,20 @@ static inline bool i2c_ll_master_is_bus_clear_done(i2c_dev_t *hw) return hw->scl_sp_conf.scl_rst_slv_en; } +/** + * @brief Set the ACK level that the I2C master must send when the Rx FIFO count has reached the threshold value. + * ack_level: 1 (NACK) + * ack_level: 0 (ACK) + * + * @param hw Beginning address of the peripheral registers + * + * @return None + */ +static inline void i2c_ll_master_rx_full_ack_level(i2c_dev_t *hw, int ack_level) +{ + hw->ctr.rx_full_ack_level = ack_level; +} + /** * @brief Set I2C source clock * @@ -718,21 +732,37 @@ static inline void i2c_ll_enable_controller_clock(i2c_dev_t *hw, bool en) } /** - * @brief Init I2C master + * @brief Set the I2C bus mode (Master or Slave) * - * @param hw Beginning address of the peripheral registers - * - * @return None + * @param hw Pointer to the I2C hardware register structure. + * @param mode The desired I2C bus mode (Master or Slave). */ -static inline void i2c_ll_master_init(i2c_dev_t *hw) +static inline void i2c_ll_set_mode(i2c_dev_t *hw, i2c_bus_mode_t mode) { - typeof(hw->ctr) ctrl_reg; - ctrl_reg.val = 0; - ctrl_reg.ms_mode = 1; - ctrl_reg.clk_en = 1; - ctrl_reg.sda_force_out = 1; - ctrl_reg.scl_force_out = 1; - hw->ctr.val = ctrl_reg.val; + hw->ctr.ms_mode = (mode == I2C_BUS_MODE_MASTER) ? 1 : 0; +} + +/** + * @brief Enable or disable open-drain mode for I2C pins + * + * @param hw Pointer to the I2C hardware register structure. + * @param enable_od Boolean flag to enable or disable open-drain mode: + */ +static inline void i2c_ll_enable_pins_open_drain(i2c_dev_t *hw, bool enable_od) +{ + hw->ctr.sda_force_out = enable_od; + hw->ctr.scl_force_out = enable_od; +} + +/** + * @brief Enable or disable arbitration for I2C communication. + * + * @param hw Pointer to the I2C hardware instance. + * @param enable_arbi Boolean flag to enable (true) or disable (false) arbitration. + */ +static inline void i2c_ll_enable_arbitration(i2c_dev_t *hw, bool enable_arbi) +{ + hw->ctr.arbitration_en = enable_arbi; } /** diff --git a/components/hal/esp32c3/include/hal/i2c_ll.h b/components/hal/esp32c3/include/hal/i2c_ll.h index c74f591c01..0c86399077 100644 --- a/components/hal/esp32c3/include/hal/i2c_ll.h +++ b/components/hal/esp32c3/include/hal/i2c_ll.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2020-2024 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2020-2025 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -815,6 +815,20 @@ static inline bool i2c_ll_master_is_bus_clear_done(i2c_dev_t *hw) return hw->scl_sp_conf.scl_rst_slv_en; } +/** + * @brief Set the ACK level that the I2C master must send when the Rx FIFO count has reached the threshold value. + * ack_level: 1 (NACK) + * ack_level: 0 (ACK) + * + * @param hw Beginning address of the peripheral registers + * + * @return None + */ +static inline void i2c_ll_master_rx_full_ack_level(i2c_dev_t *hw, int ack_level) +{ + hw->ctr.rx_full_ack_level = ack_level; +} + /** * @brief Set I2C source clock * @@ -841,38 +855,37 @@ static inline void i2c_ll_enable_controller_clock(i2c_dev_t *hw, bool en) } /** - * @brief Init I2C master + * @brief Set the I2C bus mode (Master or Slave) * - * @param hw Beginning address of the peripheral registers - * - * @return None + * @param hw Pointer to the I2C hardware register structure. + * @param mode The desired I2C bus mode (Master or Slave). */ -static inline void i2c_ll_master_init(i2c_dev_t *hw) +static inline void i2c_ll_set_mode(i2c_dev_t *hw, i2c_bus_mode_t mode) { - typeof(hw->ctr) ctrl_reg; - ctrl_reg.val = 0; - ctrl_reg.ms_mode = 1; - ctrl_reg.clk_en = 1; - ctrl_reg.sda_force_out = 1; - ctrl_reg.scl_force_out = 1; - hw->ctr.val = ctrl_reg.val; + hw->ctr.ms_mode = (mode == I2C_BUS_MODE_MASTER) ? 1 : 0; } /** - * @brief Init I2C slave + * @brief Enable or disable open-drain mode for I2C pins * - * @param hw Beginning address of the peripheral registers - * - * @return None + * @param hw Pointer to the I2C hardware register structure. + * @param enable_od Boolean flag to enable or disable open-drain mode: */ -static inline void i2c_ll_slave_init(i2c_dev_t *hw) +static inline void i2c_ll_enable_pins_open_drain(i2c_dev_t *hw, bool enable_od) { - typeof(hw->ctr) ctrl_reg; - ctrl_reg.val = 0; - ctrl_reg.sda_force_out = 1; - ctrl_reg.scl_force_out = 1; - hw->ctr.val = ctrl_reg.val; - hw->fifo_conf.fifo_addr_cfg_en = 0; + hw->ctr.sda_force_out = enable_od; + hw->ctr.scl_force_out = enable_od; +} + +/** + * @brief Enable or disable arbitration for I2C communication. + * + * @param hw Pointer to the I2C hardware instance. + * @param enable_arbi Boolean flag to enable (true) or disable (false) arbitration. + */ +static inline void i2c_ll_enable_arbitration(i2c_dev_t *hw, bool enable_arbi) +{ + hw->ctr.arbitration_en = enable_arbi; } /** diff --git a/components/hal/esp32c5/include/hal/i2c_ll.h b/components/hal/esp32c5/include/hal/i2c_ll.h index 2bb6dd327e..d09e2de89e 100644 --- a/components/hal/esp32c5/include/hal/i2c_ll.h +++ b/components/hal/esp32c5/include/hal/i2c_ll.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2024-2025 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -763,6 +763,20 @@ static inline bool i2c_ll_master_is_bus_clear_done(i2c_dev_t *hw) return hw->scl_sp_conf.scl_rst_slv_en; } +/** + * @brief Set the ACK level that the I2C master must send when the Rx FIFO count has reached the threshold value. + * ack_level: 1 (NACK) + * ack_level: 0 (ACK) + * + * @param hw Beginning address of the peripheral registers + * + * @return None + */ +static inline void i2c_ll_master_rx_full_ack_level(i2c_dev_t *hw, int ack_level) +{ + hw->ctr.rx_full_ack_level = ack_level; +} + /** * @brief Set I2C source clock * @@ -790,37 +804,37 @@ static inline void i2c_ll_enable_controller_clock(i2c_dev_t *hw, bool en) } /** - * @brief Init I2C master + * @brief Set the I2C bus mode (Master or Slave) * - * @param hw Beginning address of the peripheral registers - * - * @return None + * @param hw Pointer to the I2C hardware register structure. + * @param mode The desired I2C bus mode (Master or Slave). */ -static inline void i2c_ll_master_init(i2c_dev_t *hw) +static inline void i2c_ll_set_mode(i2c_dev_t *hw, i2c_bus_mode_t mode) { - typeof(hw->ctr) ctrl_reg; - ctrl_reg.val = 0; - ctrl_reg.ms_mode = 1; - ctrl_reg.sda_force_out = 0; - ctrl_reg.scl_force_out = 0; - hw->ctr.val = ctrl_reg.val; + hw->ctr.ms_mode = (mode == I2C_BUS_MODE_MASTER) ? 1 : 0; } /** - * @brief Init I2C slave + * @brief Enable or disable open-drain mode for I2C pins * - * @param hw Beginning address of the peripheral registers - * - * @return None + * @param hw Pointer to the I2C hardware register structure. + * @param enable_od Boolean flag to enable or disable open-drain mode: */ -static inline void i2c_ll_slave_init(i2c_dev_t *hw) +static inline void i2c_ll_enable_pins_open_drain(i2c_dev_t *hw, bool enable_od) { - typeof(hw->ctr) ctrl_reg; - ctrl_reg.val = 0; - ctrl_reg.sda_force_out = 0; - ctrl_reg.scl_force_out = 0; - hw->ctr.val = ctrl_reg.val; - hw->fifo_conf.fifo_addr_cfg_en = 0; + hw->ctr.sda_force_out = !enable_od; + hw->ctr.scl_force_out = !enable_od; +} + +/** + * @brief Enable or disable arbitration for I2C communication. + * + * @param hw Pointer to the I2C hardware instance. + * @param enable_arbi Boolean flag to enable (true) or disable (false) arbitration. + */ +static inline void i2c_ll_enable_arbitration(i2c_dev_t *hw, bool enable_arbi) +{ + hw->ctr.arbitration_en = enable_arbi; } /** diff --git a/components/hal/esp32c6/include/hal/i2c_ll.h b/components/hal/esp32c6/include/hal/i2c_ll.h index e8aaa77828..d7e646061d 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-2024 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2022-2025 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -885,37 +885,37 @@ static inline void i2c_ll_enable_controller_clock(i2c_dev_t *hw, bool en) } /** - * @brief Init I2C master + * @brief Set the I2C bus mode (Master or Slave) * - * @param hw Beginning address of the peripheral registers - * - * @return None + * @param hw Pointer to the I2C hardware register structure. + * @param mode The desired I2C bus mode (Master or Slave). */ -static inline void i2c_ll_master_init(i2c_dev_t *hw) +static inline void i2c_ll_set_mode(i2c_dev_t *hw, i2c_bus_mode_t mode) { - typeof(hw->ctr) ctrl_reg; - ctrl_reg.val = 0; - ctrl_reg.ms_mode = 1; - ctrl_reg.sda_force_out = 0; - ctrl_reg.scl_force_out = 0; - hw->ctr.val = ctrl_reg.val; + hw->ctr.ms_mode = (mode == I2C_BUS_MODE_MASTER) ? 1 : 0; } /** - * @brief Init I2C slave + * @brief Enable or disable open-drain mode for I2C pins * - * @param hw Beginning address of the peripheral registers - * - * @return None + * @param hw Pointer to the I2C hardware register structure. + * @param enable_od Boolean flag to enable or disable open-drain mode: */ -static inline void i2c_ll_slave_init(i2c_dev_t *hw) +static inline void i2c_ll_enable_pins_open_drain(i2c_dev_t *hw, bool enable_od) { - typeof(hw->ctr) ctrl_reg; - ctrl_reg.val = 0; - ctrl_reg.sda_force_out = 0; - ctrl_reg.scl_force_out = 0; - hw->ctr.val = ctrl_reg.val; - hw->fifo_conf.fifo_addr_cfg_en = 0; + hw->ctr.sda_force_out = !enable_od; + hw->ctr.scl_force_out = !enable_od; +} + +/** + * @brief Enable or disable arbitration for I2C communication. + * + * @param hw Pointer to the I2C hardware instance. + * @param enable_arbi Boolean flag to enable (true) or disable (false) arbitration. + */ +static inline void i2c_ll_enable_arbitration(i2c_dev_t *hw, bool enable_arbi) +{ + hw->ctr.arbitration_en = enable_arbi; } /** diff --git a/components/hal/esp32h2/include/hal/i2c_ll.h b/components/hal/esp32h2/include/hal/i2c_ll.h index d636cc0c71..98d3f9ef92 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-2024 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2022-2025 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -765,6 +765,20 @@ static inline bool i2c_ll_master_is_bus_clear_done(i2c_dev_t *hw) return hw->scl_sp_conf.scl_rst_slv_en; } +/** + * @brief Set the ACK level that the I2C master must send when the Rx FIFO count has reached the threshold value. + * ack_level: 1 (NACK) + * ack_level: 0 (ACK) + * + * @param hw Beginning address of the peripheral registers + * + * @return None + */ +static inline void i2c_ll_master_rx_full_ack_level(i2c_dev_t *hw, int ack_level) +{ + hw->ctr.rx_full_ack_level = ack_level; +} + /** * @brief Set I2C source clock * @@ -792,37 +806,37 @@ static inline void i2c_ll_enable_controller_clock(i2c_dev_t *hw, bool en) } /** - * @brief Init I2C master + * @brief Set the I2C bus mode (Master or Slave) * - * @param hw Beginning address of the peripheral registers - * - * @return None + * @param hw Pointer to the I2C hardware register structure. + * @param mode The desired I2C bus mode (Master or Slave). */ -static inline void i2c_ll_master_init(i2c_dev_t *hw) +static inline void i2c_ll_set_mode(i2c_dev_t *hw, i2c_bus_mode_t mode) { - typeof(hw->ctr) ctrl_reg; - ctrl_reg.val = 0; - ctrl_reg.ms_mode = 1; - ctrl_reg.sda_force_out = 0; - ctrl_reg.scl_force_out = 0; - hw->ctr.val = ctrl_reg.val; + hw->ctr.ms_mode = (mode == I2C_BUS_MODE_MASTER) ? 1 : 0; } /** - * @brief Init I2C slave + * @brief Enable or disable open-drain mode for I2C pins * - * @param hw Beginning address of the peripheral registers - * - * @return None + * @param hw Pointer to the I2C hardware register structure. + * @param enable_od Boolean flag to enable or disable open-drain mode: */ -static inline void i2c_ll_slave_init(i2c_dev_t *hw) +static inline void i2c_ll_enable_pins_open_drain(i2c_dev_t *hw, bool enable_od) { - typeof(hw->ctr) ctrl_reg; - ctrl_reg.val = 0; - ctrl_reg.sda_force_out = 0; - ctrl_reg.scl_force_out = 0; - hw->ctr.val = ctrl_reg.val; - hw->fifo_conf.fifo_addr_cfg_en = 0; + hw->ctr.sda_force_out = !enable_od; + hw->ctr.scl_force_out = !enable_od; +} + +/** + * @brief Enable or disable arbitration for I2C communication. + * + * @param hw Pointer to the I2C hardware instance. + * @param enable_arbi Boolean flag to enable (true) or disable (false) arbitration. + */ +static inline void i2c_ll_enable_arbitration(i2c_dev_t *hw, bool enable_arbi) +{ + hw->ctr.arbitration_en = enable_arbi; } /** diff --git a/components/hal/esp32p4/include/hal/i2c_ll.h b/components/hal/esp32p4/include/hal/i2c_ll.h index 7471583274..4f0c315a72 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-2024 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2022-2025 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -889,37 +889,37 @@ static inline void i2c_ll_enable_controller_clock(i2c_dev_t *hw, bool en) } /** - * @brief Init I2C master + * @brief Set the I2C bus mode (Master or Slave) * - * @param hw Beginning address of the peripheral registers - * - * @return None + * @param hw Pointer to the I2C hardware register structure. + * @param mode The desired I2C bus mode (Master or Slave). */ -static inline void i2c_ll_master_init(i2c_dev_t *hw) +static inline void i2c_ll_set_mode(i2c_dev_t *hw, i2c_bus_mode_t mode) { - typeof(hw->ctr) ctrl_reg; - ctrl_reg.val = 0; - ctrl_reg.ms_mode = 1; - ctrl_reg.sda_force_out = 0; - ctrl_reg.scl_force_out = 0; - hw->ctr.val = ctrl_reg.val; + hw->ctr.ms_mode = (mode == I2C_BUS_MODE_MASTER) ? 1 : 0; } /** - * @brief Init I2C slave + * @brief Enable or disable open-drain mode for I2C pins * - * @param hw Beginning address of the peripheral registers - * - * @return None + * @param hw Pointer to the I2C hardware register structure. + * @param enable_od Boolean flag to enable or disable open-drain mode: */ -static inline void i2c_ll_slave_init(i2c_dev_t *hw) +static inline void i2c_ll_enable_pins_open_drain(i2c_dev_t *hw, bool enable_od) { - typeof(hw->ctr) ctrl_reg; - ctrl_reg.val = 0; - ctrl_reg.sda_force_out = 0; - ctrl_reg.scl_force_out = 0; - hw->ctr.val = ctrl_reg.val; - hw->fifo_conf.fifo_addr_cfg_en = 0; + hw->ctr.sda_force_out = !enable_od; + hw->ctr.scl_force_out = !enable_od; +} + +/** + * @brief Enable or disable arbitration for I2C communication. + * + * @param hw Pointer to the I2C hardware instance. + * @param enable_arbi Boolean flag to enable (true) or disable (false) arbitration. + */ +static inline void i2c_ll_enable_arbitration(i2c_dev_t *hw, bool enable_arbi) +{ + hw->ctr.arbitration_en = enable_arbi; } /** diff --git a/components/hal/esp32s2/include/hal/i2c_ll.h b/components/hal/esp32s2/include/hal/i2c_ll.h index 9391b32b27..d67920280f 100644 --- a/components/hal/esp32s2/include/hal/i2c_ll.h +++ b/components/hal/esp32s2/include/hal/i2c_ll.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2015-2025 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -681,6 +681,20 @@ static inline bool i2c_ll_master_is_bus_clear_done(i2c_dev_t *hw) return false; // not supported on esp32s2 } +/** + * @brief Set the ACK level that the I2C master must send when the Rx FIFO count has reached the threshold value. + * ack_level: 1 (NACK) + * ack_level: 0 (ACK) + * + * @param hw Beginning address of the peripheral registers + * + * @return None + */ +static inline void i2c_ll_master_rx_full_ack_level(i2c_dev_t *hw, int ack_level) +{ + hw->ctr.rx_full_ack_level = ack_level; +} + /** * @brief Set I2C source clock * @@ -708,36 +722,37 @@ static inline void i2c_ll_enable_controller_clock(i2c_dev_t *hw, bool en) } /** - * @brief Init I2C master + * @brief Set the I2C bus mode (Master or Slave) * - * @param hw Beginning address of the peripheral registers - * - * @return None + * @param hw Pointer to the I2C hardware register structure. + * @param mode The desired I2C bus mode (Master or Slave). */ -static inline void i2c_ll_master_init(i2c_dev_t *hw) +static inline void i2c_ll_set_mode(i2c_dev_t *hw, i2c_bus_mode_t mode) { - typeof(hw->ctr) ctrl_reg; - ctrl_reg.val = 0; - ctrl_reg.ms_mode = 1; - ctrl_reg.sda_force_out = 1; - ctrl_reg.scl_force_out = 1; - hw->ctr.val = ctrl_reg.val; + hw->ctr.ms_mode = (mode == I2C_BUS_MODE_MASTER) ? 1 : 0; } /** - * @brief Enable I2C internal open-drain mode - * If internal open-drain of the I2C module is disabled, scl and sda gpio should be configured in open-drain mode. - * Otherwise it is not needed. + * @brief Enable or disable open-drain mode for I2C pins * - * @param hw Beginning address of the peripheral registers - * @param internal_od_ena Set true to enable internal open-drain, otherwise, set it false. - * - * @return None + * @param hw Pointer to the I2C hardware register structure. + * @param enable_od Boolean flag to enable or disable open-drain mode: */ -static inline void i2c_ll_internal_od_enable(i2c_dev_t *hw, bool internal_od_ena) +static inline void i2c_ll_enable_pins_open_drain(i2c_dev_t *hw, bool enable_od) { - hw->ctr.sda_force_out = (internal_od_ena == false); - hw->ctr.scl_force_out = (internal_od_ena == false); + hw->ctr.sda_force_out = enable_od; + hw->ctr.scl_force_out = enable_od; +} + +/** + * @brief Enable or disable arbitration for I2C communication. + * + * @param hw Pointer to the I2C hardware instance. + * @param enable_arbi Boolean flag to enable (true) or disable (false) arbitration. + */ +static inline void i2c_ll_enable_arbitration(i2c_dev_t *hw, bool enable_arbi) +{ + hw->ctr.arbitration_en = enable_arbi; } /** diff --git a/components/hal/esp32s3/include/hal/i2c_ll.h b/components/hal/esp32s3/include/hal/i2c_ll.h index 50dfb6eaf7..bfdbe0f498 100644 --- a/components/hal/esp32s3/include/hal/i2c_ll.h +++ b/components/hal/esp32s3/include/hal/i2c_ll.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2020-2024 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2020-2025 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -820,6 +820,20 @@ static inline bool i2c_ll_master_is_bus_clear_done(i2c_dev_t *hw) return false; // not supported on esp32s3 } +/** + * @brief Set the ACK level that the I2C master must send when the Rx FIFO count has reached the threshold value. + * ack_level: 1 (NACK) + * ack_level: 0 (ACK) + * + * @param hw Beginning address of the peripheral registers + * + * @return None + */ +static inline void i2c_ll_master_rx_full_ack_level(i2c_dev_t *hw, int ack_level) +{ + hw->ctr.rx_full_ack_level = ack_level; +} + /** * @brief Set I2C source clock * @@ -845,38 +859,37 @@ static inline void i2c_ll_enable_controller_clock(i2c_dev_t *hw, bool en) } /** - * @brief Init I2C master + * @brief Set the I2C bus mode (Master or Slave) * - * @param hw Beginning address of the peripheral registers - * - * @return None + * @param hw Pointer to the I2C hardware register structure. + * @param mode The desired I2C bus mode (Master or Slave). */ -static inline void i2c_ll_master_init(i2c_dev_t *hw) +static inline void i2c_ll_set_mode(i2c_dev_t *hw, i2c_bus_mode_t mode) { - typeof(hw->ctr) ctrl_reg; - ctrl_reg.val = 0; - ctrl_reg.ms_mode = 1; - ctrl_reg.clk_en = 1; - ctrl_reg.sda_force_out = 1; - ctrl_reg.scl_force_out = 1; - hw->ctr.val = ctrl_reg.val; + hw->ctr.ms_mode = (mode == I2C_BUS_MODE_MASTER) ? 1 : 0; } /** - * @brief Init I2C slave + * @brief Enable or disable open-drain mode for I2C pins * - * @param hw Beginning address of the peripheral registers - * - * @return None + * @param hw Pointer to the I2C hardware register structure. + * @param enable_od Boolean flag to enable or disable open-drain mode: */ -static inline void i2c_ll_slave_init(i2c_dev_t *hw) +static inline void i2c_ll_enable_pins_open_drain(i2c_dev_t *hw, bool enable_od) { - typeof(hw->ctr) ctrl_reg; - ctrl_reg.val = 0; - ctrl_reg.sda_force_out = 1; - ctrl_reg.scl_force_out = 1; - hw->ctr.val = ctrl_reg.val; - hw->fifo_conf.fifo_addr_cfg_en = 0; + hw->ctr.sda_force_out = enable_od; + hw->ctr.scl_force_out = enable_od; +} + +/** + * @brief Enable or disable arbitration for I2C communication. + * + * @param hw Pointer to the I2C hardware instance. + * @param enable_arbi Boolean flag to enable (true) or disable (false) arbitration. + */ +static inline void i2c_ll_enable_arbitration(i2c_dev_t *hw, bool enable_arbi) +{ + hw->ctr.arbitration_en = enable_arbi; } /** diff --git a/components/hal/i2c_hal.c b/components/hal/i2c_hal.c index 8a96c56586..d6f0fcb9ef 100644 --- a/components/hal/i2c_hal.c +++ b/components/hal/i2c_hal.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2015-2025 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -13,7 +13,9 @@ void i2c_hal_slave_init(i2c_hal_context_t *hal) { - i2c_ll_slave_init(hal->dev); + i2c_ll_set_mode(hal->dev, I2C_BUS_MODE_SLAVE); + i2c_ll_enable_pins_open_drain(hal->dev, true); + i2c_ll_enable_arbitration(hal->dev, false); //MSB i2c_ll_set_data_mode(hal->dev, I2C_DATA_MODE_MSB_FIRST, I2C_DATA_MODE_MSB_FIRST); //Reset fifo @@ -36,7 +38,10 @@ void i2c_hal_master_fsm_rst(i2c_hal_context_t *hal) void i2c_hal_master_init(i2c_hal_context_t *hal) { - i2c_ll_master_init(hal->dev); + i2c_ll_set_mode(hal->dev, I2C_BUS_MODE_MASTER); + i2c_ll_enable_pins_open_drain(hal->dev, true); + i2c_ll_enable_arbitration(hal->dev, false); + i2c_ll_master_rx_full_ack_level(hal->dev, false); //MSB i2c_ll_set_data_mode(hal->dev, I2C_DATA_MODE_MSB_FIRST, I2C_DATA_MODE_MSB_FIRST); //Reset fifo diff --git a/components/hal/include/hal/i2c_types.h b/components/hal/include/hal/i2c_types.h index 6a0d685ac7..e2ed18b6fc 100644 --- a/components/hal/include/hal/i2c_types.h +++ b/components/hal/include/hal/i2c_types.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2015-2025 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -98,6 +98,19 @@ typedef enum { I2C_SLAVE_STRETCH_CAUSE_SENDING_ACK = 3, /*!< Stretching SCL low when slave sending ACK */ } i2c_slave_stretch_cause_t; +typedef enum { + I2C_SLAVE_WRITE_BY_MASTER = 0, + I2C_SLAVE_READ_BY_MASTER = 1, +} i2c_slave_read_write_status_t; + +/** + * @brief Enum for i2c working modes. + */ +typedef enum { + I2C_BUS_MODE_MASTER = 0, /*!< I2C works under master mode */ + I2C_BUS_MODE_SLAVE = 1, /*!< I2C works under slave mode */ +} i2c_bus_mode_t; + #if SOC_I2C_SUPPORTED /** * @brief I2C group clock source diff --git a/components/hal/test_apps/hal_i2c/components/hal_i2c/hal_i2c.c b/components/hal/test_apps/hal_i2c/components/hal_i2c/hal_i2c.c index 91adc7f3c6..cc738c77e9 100644 --- a/components/hal/test_apps/hal_i2c/components/hal_i2c/hal_i2c.c +++ b/components/hal/test_apps/hal_i2c/components/hal_i2c/hal_i2c.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2024-2025 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Unlicense OR CC0-1.0 */ @@ -92,7 +92,7 @@ esp_err_t hal_i2c_init(hal_i2c_config *cfg) // 2. Set both SCL and SDA open-drain // 3. Set both SCL and SDA pullup enable and pulldown disable. (If you use external pullup, this can be ignored) // 4. io mux function select - // 5. We connect out/in signal. As I2C master, out/in signal is necessary fpr both SCL and SDA according to esp hardware. + // 5. We connect out/in signal. As I2C master, out/in signal is necessary for both SCL and SDA according to esp hardware. // SDA pin configurations if (sda_io != -1) { @@ -117,7 +117,9 @@ esp_err_t hal_i2c_init(hal_i2c_config *cfg) esp_rom_gpio_connect_in_signal(scl_io, i2c_periph_signal[cfg->i2c_port].scl_out_sig, 0); } // Initialize I2C master bus. Including enable its clock, choose its mode, etc. - i2c_ll_master_init(dev); + i2c_ll_set_mode(dev, I2C_BUS_MODE_MASTER); + i2c_ll_enable_pins_open_drain(dev, true); + i2c_ll_enable_arbitration(dev, false); //MSB (I2C standard require the data to be sent with most MSB) i2c_ll_set_data_mode(dev, I2C_DATA_MODE_MSB_FIRST, I2C_DATA_MODE_MSB_FIRST); //Reset fifo