From e218723e0e23bf43f1181af93673ab7222bc1f90 Mon Sep 17 00:00:00 2001 From: Cao Sen Miao Date: Mon, 27 Jun 2022 12:00:04 +0800 Subject: [PATCH] I2C: Make I2C clock frequency accurate --- components/driver/i2c.c | 6 +-- components/hal/esp32/include/hal/i2c_ll.h | 33 ++++++++++++ components/hal/esp32c2/include/hal/i2c_ll.h | 54 ++++++++++++++++--- components/hal/esp32c3/include/hal/i2c_ll.h | 54 ++++++++++++++++--- components/hal/esp32h2/include/hal/i2c_ll.h | 54 ++++++++++++++++--- components/hal/esp32s2/include/hal/i2c_ll.h | 51 +++++++++++++----- components/hal/esp32s3/include/hal/i2c_ll.h | 55 ++++++++++++++++---- components/hal/include/hal/i2c_hal.h | 23 ++++++++ docs/en/api-reference/peripherals/i2c.rst | 6 +++ docs/zh_CN/api-reference/peripherals/i2c.rst | 6 +++ tools/ci/check_copyright_ignore.txt | 1 - 11 files changed, 293 insertions(+), 50 deletions(-) diff --git a/components/driver/i2c.c b/components/driver/i2c.c index 10619c37f0..0fb9513d88 100644 --- a/components/driver/i2c.c +++ b/components/driver/i2c.c @@ -635,14 +635,14 @@ static esp_err_t i2c_hw_fsm_reset(i2c_port_t i2c_num) // A workaround for avoiding cause timeout issue when using // hardware reset. #if !SOC_I2C_SUPPORT_HW_FSM_RST - int scl_low_period, scl_high_period; + int scl_low_period, scl_high_period, scl_wait_high_period; int scl_start_hold, scl_rstart_setup; int scl_stop_hold, scl_stop_setup; int sda_hold, sda_sample; int timeout; uint8_t filter_cfg; - i2c_hal_get_scl_timing(&(i2c_context[i2c_num].hal), &scl_high_period, &scl_low_period); + i2c_hal_get_scl_clk_timing(&(i2c_context[i2c_num].hal), &scl_high_period, &scl_low_period, &scl_wait_high_period); i2c_hal_get_start_timing(&(i2c_context[i2c_num].hal), &scl_rstart_setup, &scl_start_hold); i2c_hal_get_stop_timing(&(i2c_context[i2c_num].hal), &scl_stop_setup, &scl_stop_hold); i2c_hal_get_sda_timing(&(i2c_context[i2c_num].hal), &sda_sample, &sda_hold); @@ -657,7 +657,7 @@ static esp_err_t i2c_hw_fsm_reset(i2c_port_t i2c_num) i2c_hal_master_init(&(i2c_context[i2c_num].hal), i2c_num); i2c_hal_disable_intr_mask(&(i2c_context[i2c_num].hal), I2C_LL_INTR_MASK); i2c_hal_clr_intsts_mask(&(i2c_context[i2c_num].hal), I2C_LL_INTR_MASK); - i2c_hal_set_scl_timing(&(i2c_context[i2c_num].hal), scl_high_period, scl_low_period); + i2c_hal_set_scl_clk_timing(&(i2c_context[i2c_num].hal), scl_high_period, scl_low_period, scl_wait_high_period); i2c_hal_set_start_timing(&(i2c_context[i2c_num].hal), scl_rstart_setup, scl_start_hold); i2c_hal_set_stop_timing(&(i2c_context[i2c_num].hal), scl_stop_setup, scl_stop_hold); i2c_hal_set_sda_timing(&(i2c_context[i2c_num].hal), sda_sample, sda_hold); diff --git a/components/hal/esp32/include/hal/i2c_ll.h b/components/hal/esp32/include/hal/i2c_ll.h index 9a99341c59..df4a7d5eb7 100644 --- a/components/hal/esp32/include/hal/i2c_ll.h +++ b/components/hal/esp32/include/hal/i2c_ll.h @@ -890,6 +890,39 @@ static inline void i2c_ll_update(i2c_dev_t *hw) ;// ESP32 do not support } +/** + * @brief Configure I2C SCL timing + * + * @param hw Beginning address of the peripheral registers + * @param high_period The I2C SCL hight period (in core clock cycle, hight_period > 2) + * @param low_period The I2C SCL low period (in core clock cycle, low_period > 1) + * @param wait_high_period The I2C SCL wait rising edge period. + * + * @return None. + */ +static inline void i2c_ll_set_scl_clk_timing(i2c_dev_t *hw, int high_period, int low_period, int wait_high_period) +{ + (void)wait_high_period; + hw->scl_low_period.period = low_period; + hw->scl_high_period.period = high_period; +} + +/** + * @brief Get I2C SCL timing configuration + * + * @param hw Beginning address of the peripheral registers + * @param high_period Pointer to accept the SCL high period + * @param low_period Pointer to accept the SCL low period + * + * @return None + */ +static inline void i2c_ll_get_scl_clk_timing(i2c_dev_t *hw, int *high_period, int *low_period, int *wait_high_period) +{ + *wait_high_period = 0; // Useless + *high_period = hw->scl_high_period.period; + *low_period = hw->scl_low_period.period; +} + #ifdef __cplusplus } #endif diff --git a/components/hal/esp32c2/include/hal/i2c_ll.h b/components/hal/esp32c2/include/hal/i2c_ll.h index f24baec52f..61f54a25ef 100644 --- a/components/hal/esp32c2/include/hal/i2c_ll.h +++ b/components/hal/esp32c2/include/hal/i2c_ll.h @@ -110,12 +110,12 @@ static inline void i2c_ll_cal_bus_clk(uint32_t source_clk, uint32_t bus_freq, i2 clk_cal->clkm_div = clkm_div; clk_cal->scl_low = half_cycle; // default, scl_wait_high < scl_high - int scl_wait_high = (bus_freq <= 50000) ? 0 : (half_cycle / 8); // compensate the time when freq > 50K - clk_cal->scl_wait_high = scl_wait_high; - clk_cal->scl_high = half_cycle - scl_wait_high; + // Make 80KHz as a boundary here, because when working at lower frequency, too much scl_wait_high will faster the frequency + // according to some hardware behaviors. + clk_cal->scl_wait_high = (bus_freq >= 80*1000) ? (half_cycle / 2 - 2) : (half_cycle / 4); + clk_cal->scl_high = half_cycle - clk_cal->scl_wait_high; clk_cal->sda_hold = half_cycle / 4; - // scl_wait_high < sda_sample <= scl_high - clk_cal->sda_sample = half_cycle / 2; + clk_cal->sda_sample = half_cycle / 2 + clk_cal->scl_wait_high; clk_cal->setup = half_cycle; clk_cal->hold = half_cycle; //default we set the timeout value to about 10 bus cycles @@ -146,9 +146,14 @@ static inline void i2c_ll_update(i2c_dev_t *hw) static inline void i2c_ll_set_bus_timing(i2c_dev_t *hw, i2c_clk_cal_t *bus_cfg) { HAL_FORCE_MODIFY_U32_REG_FIELD(hw->clk_conf, sclk_div_num, bus_cfg->clkm_div - 1); - //scl period - hw->scl_low_period.scl_low_period = bus_cfg->scl_low - 2; - hw->scl_high_period.scl_high_period = bus_cfg->scl_high - 3; + /* According to the Technical Reference Manual, the following timings must be subtracted by 1. + * However, according to the practical measurement and some hardware behaviour, if wait_high_period and scl_high minus one. + * The SCL frequency would be a little higher than expected. Therefore, the solution + * here is not to minus scl_high as well as scl_wait high, and the frequency will be absolutely accurate to all frequency + * to some extent. */ + hw->scl_low_period.scl_low_period = bus_cfg->scl_low - 1; + hw->scl_high_period.scl_high_period = bus_cfg->scl_high; + hw->scl_high_period.scl_wait_high_period = bus_cfg->scl_wait_high; //sda sample hw->sda_hold.sda_hold_time = bus_cfg->sda_hold - 1; hw->sda_sample.sda_sample_time = bus_cfg->sda_sample - 1; @@ -776,6 +781,39 @@ static inline void i2c_ll_master_init(i2c_dev_t *hw) hw->ctr.val = ctrl_reg.val; } +/** + * @brief Configure I2C SCL timing + * + * @param hw Beginning address of the peripheral registers + * @param high_period The I2C SCL hight period (in core clock cycle, hight_period > 2) + * @param low_period The I2C SCL low period (in core clock cycle, low_period > 1) + * @param wait_high_period The I2C SCL wait rising edge period. + * + * @return None. + */ +static inline void i2c_ll_set_scl_clk_timing(i2c_dev_t *hw, int high_period, int low_period, int wait_high_period) +{ + hw->scl_low_period.scl_low_period = low_period; + hw->scl_high_period.scl_high_period = high_period; + hw->scl_high_period.scl_wait_high_period = wait_high_period; +} + +/** + * @brief Get I2C SCL timing configuration + * + * @param hw Beginning address of the peripheral registers + * @param high_period Pointer to accept the SCL high period + * @param low_period Pointer to accept the SCL low period + * + * @return None + */ +static inline void i2c_ll_get_scl_clk_timing(i2c_dev_t *hw, int *high_period, int *low_period, int *wait_high_period) +{ + *high_period = hw->scl_high_period.scl_high_period; + *wait_high_period = hw->scl_high_period.scl_wait_high_period; + *low_period = hw->scl_low_period.scl_low_period; +} + #ifdef __cplusplus } #endif diff --git a/components/hal/esp32c3/include/hal/i2c_ll.h b/components/hal/esp32c3/include/hal/i2c_ll.h index a4b3662fb5..c2aee7b27f 100644 --- a/components/hal/esp32c3/include/hal/i2c_ll.h +++ b/components/hal/esp32c3/include/hal/i2c_ll.h @@ -114,12 +114,12 @@ static inline void i2c_ll_cal_bus_clk(uint32_t source_clk, uint32_t bus_freq, i2 clk_cal->clkm_div = clkm_div; clk_cal->scl_low = half_cycle; // default, scl_wait_high < scl_high - int scl_wait_high = (bus_freq <= 50000) ? 0 : (half_cycle / 8); // compensate the time when freq > 50K - clk_cal->scl_wait_high = scl_wait_high; - clk_cal->scl_high = half_cycle - scl_wait_high; + // Make 80KHz as a boundary here, because when working at lower frequency, too much scl_wait_high will faster the frequency + // according to some hardware behaviors. + clk_cal->scl_wait_high = (bus_freq >= 80*1000) ? (half_cycle / 2 - 2) : (half_cycle / 4); + clk_cal->scl_high = half_cycle - clk_cal->scl_wait_high; clk_cal->sda_hold = half_cycle / 4; - // scl_wait_high < sda_sample <= scl_high - clk_cal->sda_sample = half_cycle / 2; + clk_cal->sda_sample = half_cycle / 2 + clk_cal->scl_wait_high; clk_cal->setup = half_cycle; clk_cal->hold = half_cycle; //default we set the timeout value to about 10 bus cycles @@ -150,9 +150,14 @@ static inline void i2c_ll_update(i2c_dev_t *hw) static inline void i2c_ll_set_bus_timing(i2c_dev_t *hw, i2c_clk_cal_t *bus_cfg) { HAL_FORCE_MODIFY_U32_REG_FIELD(hw->clk_conf, sclk_div_num, bus_cfg->clkm_div - 1); - //scl period - hw->scl_low_period.period = bus_cfg->scl_low - 2; - hw->scl_high_period.period = bus_cfg->scl_high - 3; + /* According to the Technical Reference Manual, the following timings must be subtracted by 1. + * However, according to the practical measurement and some hardware behaviour, if wait_high_period and scl_high minus one. + * The SCL frequency would be a little higher than expected. Therefore, the solution + * here is not to minus scl_high as well as scl_wait high, and the frequency will be absolutely accurate to all frequency + * to some extent. */ + hw->scl_low_period.period = bus_cfg->scl_low - 1; + hw->scl_high_period.period = bus_cfg->scl_high; + hw->scl_high_period.scl_wait_high_period = bus_cfg->scl_wait_high; //sda sample hw->sda_hold.time = bus_cfg->sda_hold - 1; hw->sda_sample.time = bus_cfg->sda_sample - 1; @@ -907,6 +912,39 @@ static inline void i2c_ll_slave_init(i2c_dev_t *hw) hw->fifo_conf.fifo_addr_cfg_en = 0; } +/** + * @brief Configure I2C SCL timing + * + * @param hw Beginning address of the peripheral registers + * @param high_period The I2C SCL hight period (in core clock cycle, hight_period > 2) + * @param low_period The I2C SCL low period (in core clock cycle, low_period > 1) + * @param wait_high_period The I2C SCL wait rising edge period. + * + * @return None. + */ +static inline void i2c_ll_set_scl_clk_timing(i2c_dev_t *hw, int high_period, int low_period, int wait_high_period) +{ + hw->scl_low_period.period = low_period; + hw->scl_high_period.period = high_period; + hw->scl_high_period.scl_wait_high_period = wait_high_period; +} + +/** + * @brief Get I2C SCL timing configuration + * + * @param hw Beginning address of the peripheral registers + * @param high_period Pointer to accept the SCL high period + * @param low_period Pointer to accept the SCL low period + * + * @return None + */ +static inline void i2c_ll_get_scl_clk_timing(i2c_dev_t *hw, int *high_period, int *low_period, int *wait_high_period) +{ + *high_period = hw->scl_high_period.period; + *wait_high_period = hw->scl_high_period.scl_wait_high_period; + *low_period = hw->scl_low_period.period; +} + #ifdef __cplusplus } #endif diff --git a/components/hal/esp32h2/include/hal/i2c_ll.h b/components/hal/esp32h2/include/hal/i2c_ll.h index d4a0e760d6..c88bc68068 100644 --- a/components/hal/esp32h2/include/hal/i2c_ll.h +++ b/components/hal/esp32h2/include/hal/i2c_ll.h @@ -114,12 +114,12 @@ static inline void i2c_ll_cal_bus_clk(uint32_t source_clk, uint32_t bus_freq, i2 clk_cal->clkm_div = clkm_div; clk_cal->scl_low = half_cycle; // default, scl_wait_high < scl_high - int scl_wait_high = (bus_freq <= 50000) ? 0 : (half_cycle / 8); // compensate the time when freq > 50K - clk_cal->scl_wait_high = scl_wait_high; - clk_cal->scl_high = half_cycle - scl_wait_high; + // Make 80KHz as a boundary here, because when working at lower frequency, too much scl_wait_high will faster the frequency + // according to some hardware behaviors. + clk_cal->scl_wait_high = (bus_freq >= 80*1000) ? (half_cycle / 2 - 2) : (half_cycle / 4); + clk_cal->scl_high = half_cycle - clk_cal->scl_wait_high; clk_cal->sda_hold = half_cycle / 4; - // scl_wait_high < sda_sample <= scl_high - clk_cal->sda_sample = half_cycle / 2; + clk_cal->sda_sample = half_cycle / 2 + clk_cal->scl_wait_high; clk_cal->setup = half_cycle; clk_cal->hold = half_cycle; //default we set the timeout value to about 10 bus cycles @@ -150,9 +150,14 @@ static inline void i2c_ll_update(i2c_dev_t *hw) static inline void i2c_ll_set_bus_timing(i2c_dev_t *hw, i2c_clk_cal_t *bus_cfg) { HAL_FORCE_MODIFY_U32_REG_FIELD(hw->clk_conf, sclk_div_num, bus_cfg->clkm_div - 1); - //scl period - hw->scl_low_period.period = bus_cfg->scl_low - 2; - hw->scl_high_period.period = bus_cfg->scl_high - 3; + /* According to the Technical Reference Manual, the following timings must be subtracted by 1. + * However, according to the practical measurement and some hardware behaviour, if wait_high_period and scl_high minus one. + * The SCL frequency would be a little higher than expected. Therefore, the solution + * here is not to minus scl_high as well as scl_wait high, and the frequency will be absolutely accurate to all frequency + * to some extent. */ + hw->scl_low_period.period = bus_cfg->scl_low - 1; + hw->scl_high_period.period = bus_cfg->scl_high; + hw->scl_high_period.scl_wait_high_period = bus_cfg->scl_wait_high; //sda sample hw->sda_hold.time = bus_cfg->sda_hold - 1; hw->sda_sample.time = bus_cfg->sda_sample - 1; @@ -904,6 +909,39 @@ static inline void i2c_ll_slave_init(i2c_dev_t *hw) hw->fifo_conf.fifo_addr_cfg_en = 0; } +/** + * @brief Configure I2C SCL timing + * + * @param hw Beginning address of the peripheral registers + * @param high_period The I2C SCL hight period (in core clock cycle, hight_period > 2) + * @param low_period The I2C SCL low period (in core clock cycle, low_period > 1) + * @param wait_high_period The I2C SCL wait rising edge period. + * + * @return None. + */ +static inline void i2c_ll_set_scl_clk_timing(i2c_dev_t *hw, int high_period, int low_period, int wait_high_period) +{ + hw->scl_low_period.period = low_period; + hw->scl_high_period.period = high_period; + hw->scl_high_period.scl_wait_high_period = wait_high_period; +} + +/** + * @brief Get I2C SCL timing configuration + * + * @param hw Beginning address of the peripheral registers + * @param high_period Pointer to accept the SCL high period + * @param low_period Pointer to accept the SCL low period + * + * @return None + */ +static inline void i2c_ll_get_scl_clk_timing(i2c_dev_t *hw, int *high_period, int *low_period, int *wait_high_period) +{ + *high_period = hw->scl_high_period.period; + *wait_high_period = hw->scl_high_period.scl_wait_high_period; + *low_period = hw->scl_low_period.period; +} + #ifdef __cplusplus } #endif diff --git a/components/hal/esp32s2/include/hal/i2c_ll.h b/components/hal/esp32s2/include/hal/i2c_ll.h index 1d2b8a0c13..f332613e56 100644 --- a/components/hal/esp32s2/include/hal/i2c_ll.h +++ b/components/hal/esp32s2/include/hal/i2c_ll.h @@ -1,16 +1,8 @@ -// Copyright 2015-2019 Espressif Systems (Shanghai) PTE LTD -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. +/* + * SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ // The LL layer for I2C register operations @@ -907,6 +899,39 @@ static inline void i2c_ll_update(i2c_dev_t *hw) ;// ESP32S2 do not support } +/** + * @brief Configure I2C SCL timing + * + * @param hw Beginning address of the peripheral registers + * @param high_period The I2C SCL hight period (in core clock cycle, hight_period > 2) + * @param low_period The I2C SCL low period (in core clock cycle, low_period > 1) + * @param wait_high_period The I2C SCL wait rising edge period. + * + * @return None. + */ +static inline void i2c_ll_set_scl_clk_timing(i2c_dev_t *hw, int high_period, int low_period, int wait_high_period) +{ + hw->scl_low_period.period = low_period; + hw->scl_high_period.period = high_period; + hw->scl_high_period.scl_wait_high_period = wait_high_period; +} + +/** + * @brief Get I2C SCL timing configuration + * + * @param hw Beginning address of the peripheral registers + * @param high_period Pointer to accept the SCL high period + * @param low_period Pointer to accept the SCL low period + * + * @return None + */ +static inline void i2c_ll_get_scl_clk_timing(i2c_dev_t *hw, int *high_period, int *low_period, int *wait_high_period) +{ + *high_period = hw->scl_high_period.period; + *wait_high_period = hw->scl_high_period.scl_wait_high_period; + *low_period = hw->scl_low_period.period; +} + #ifdef __cplusplus } #endif diff --git a/components/hal/esp32s3/include/hal/i2c_ll.h b/components/hal/esp32s3/include/hal/i2c_ll.h index ec209daf2e..20b5c7d9ed 100644 --- a/components/hal/esp32s3/include/hal/i2c_ll.h +++ b/components/hal/esp32s3/include/hal/i2c_ll.h @@ -109,11 +109,12 @@ static inline void i2c_ll_cal_bus_clk(uint32_t source_clk, uint32_t bus_freq, i2 clk_cal->clkm_div = clkm_div; clk_cal->scl_low = half_cycle; // default, scl_wait_high < scl_high - clk_cal->scl_high = (bus_freq <= 50000) ? half_cycle : (half_cycle / 5 * 4 + 4); - clk_cal->scl_wait_high = half_cycle - clk_cal->scl_high; - clk_cal->sda_hold = half_cycle / 2; - // scl_wait_high < sda_sample <= scl_high - clk_cal->sda_sample = half_cycle / 2; + // Make 80KHz as a boundary here, because when working at lower frequency, too much scl_wait_high will faster the frequency + // according to some hardware behaviors. + clk_cal->scl_wait_high = (bus_freq >= 80*1000) ? (half_cycle / 2 - 2) : (half_cycle / 4); + clk_cal->scl_high = half_cycle - clk_cal->scl_wait_high; + clk_cal->sda_hold = half_cycle / 4; + clk_cal->sda_sample = half_cycle / 2 + clk_cal->scl_wait_high; clk_cal->setup = half_cycle; clk_cal->hold = half_cycle; //default we set the timeout value to about 10 bus cycles @@ -145,10 +146,13 @@ static inline void i2c_ll_set_bus_timing(i2c_dev_t *hw, i2c_clk_cal_t *bus_cfg) { HAL_FORCE_MODIFY_U32_REG_FIELD(hw->clk_conf, sclk_div_num, bus_cfg->clkm_div - 1); /* According to the Technical Reference Manual, the following timings must be subtracted by 1. - * Moreover, the frequency calculation also shows that we must subtract 3 to the total SCL */ - //scl period - hw->scl_low_period.scl_low_period = bus_cfg->scl_low - 1 - 2; - hw->scl_high_period.scl_high_period = bus_cfg->scl_high - 1 - 1; + * However, according to the practical measurement and some hardware behaviour, if wait_high_period and scl_high minus one. + * The SCL frequency would be a little higher than expected. Therefore, the solution + * here is not to minus scl_high as well as scl_wait high, and the frequency will be absolutely accurate to all frequency + * to some extent. */ + hw->scl_low_period.scl_low_period = bus_cfg->scl_low - 1; + hw->scl_high_period.scl_high_period = bus_cfg->scl_high; + hw->scl_high_period.scl_wait_high_period = bus_cfg->scl_wait_high; //sda sample hw->sda_hold.sda_hold_time = bus_cfg->sda_hold - 1; hw->sda_sample.sda_sample_time = bus_cfg->sda_sample - 1; @@ -205,6 +209,23 @@ static inline void i2c_ll_set_scl_timing(i2c_dev_t *hw, int high_period, int low hw->scl_high_period.scl_wait_high_period = high_period - high_period_output; } +/** + * @brief Configure I2C SCL timing + * + * @param hw Beginning address of the peripheral registers + * @param high_period The I2C SCL hight period (in core clock cycle, hight_period > 2) + * @param low_period The I2C SCL low period (in core clock cycle, low_period > 1) + * @param wait_high_period The I2C SCL wait rising edge period. + * + * @return None. + */ +static inline void i2c_ll_set_scl_clk_timing(i2c_dev_t *hw, int high_period, int low_period, int wait_high_period) +{ + hw->scl_low_period.scl_low_period = low_period; + hw->scl_high_period.scl_high_period = high_period; + hw->scl_high_period.scl_wait_high_period = wait_high_period; +} + /** * @brief Clear I2C interrupt status * @@ -559,6 +580,22 @@ static inline void i2c_ll_get_scl_timing(i2c_dev_t *hw, int *high_period, int *l *low_period = hw->scl_low_period.scl_low_period + 1; } +/** + * @brief Get I2C SCL timing configuration + * + * @param hw Beginning address of the peripheral registers + * @param high_period Pointer to accept the SCL high period + * @param low_period Pointer to accept the SCL low period + * + * @return None + */ +static inline void i2c_ll_get_scl_clk_timing(i2c_dev_t *hw, int *high_period, int *low_period, int *wait_high_period) +{ + *high_period = hw->scl_high_period.scl_high_period; + *wait_high_period = hw->scl_high_period.scl_wait_high_period; + *low_period = hw->scl_low_period.scl_low_period; +} + /** * @brief Write the I2C hardware txFIFO * diff --git a/components/hal/include/hal/i2c_hal.h b/components/hal/include/hal/i2c_hal.h index dc0a5c0eba..42d85969c3 100644 --- a/components/hal/include/hal/i2c_hal.h +++ b/components/hal/include/hal/i2c_hal.h @@ -182,6 +182,29 @@ void i2c_hal_slave_handle_event(i2c_hal_context_t *hal, i2c_intr_event_t *event) */ #define i2c_hal_set_source_clk(hal, src_clk) i2c_ll_set_source_clk((hal)->dev, src_clk) +/** + * @brief Configure I2C SCL timing + * + * @param hw Beginning address of the peripheral registers + * @param high_period The I2C SCL hight period (in core clock cycle, hight_period > 2) + * @param low_period The I2C SCL low period (in core clock cycle, low_period > 1) + * @param wait_high_period The I2C SCL wait rising edge period. + * + * @return None. + */ +#define i2c_hal_set_scl_clk_timing(hal, high_period, low_period, wait_high_period) i2c_ll_set_scl_clk_timing((hal)->dev, high_period, low_period, wait_high_period) + +/** + * @brief Get I2C SCL timing configuration + * + * @param hw Beginning address of the peripheral registers + * @param high_period Pointer to accept the SCL high period + * @param low_period Pointer to accept the SCL low period + * + * @return None + */ +#define i2c_hal_get_scl_clk_timing(hal, high_period, low_period, wait_high_period) i2c_ll_get_scl_clk_timing((hal)->dev, high_period, low_period, wait_high_period) + /** * @brief Init the I2C master. * diff --git a/docs/en/api-reference/peripherals/i2c.rst b/docs/en/api-reference/peripherals/i2c.rst index 61e51aa727..4b5e5060d5 100644 --- a/docs/en/api-reference/peripherals/i2c.rst +++ b/docs/en/api-reference/peripherals/i2c.rst @@ -206,6 +206,12 @@ Explanations for :cpp:member:`i2c_config_t::clk_flags` are as follows: The clock frequency of SCL in master mode should not be lager than max frequency for SCL mentioned in the table above. +.. note:: + + The clock frequency of SCL will be influenced by the pull-up resistors and wire capacitance (or might slave capacitance) together. Therefore, users need to choose correct pull-up resistors by themselves to make the frequency accurate. It is recommended by I2C protocol that the pull-up resistors commonly range from 1KOhms to 10KOhms, but different frequencies need different resistors. + + Generally speaking, the higher frequency is selected, the smaller resistor should be used (but not less than 1KOhms). This is because high resistor will decline the current, which will lengthen the rising time and reduce the frequency. Usually, range 2KOhms to 5KOhms is what we recommend, but users also might need to make some adjustment depends on their reality. + .. _i2c-api-install-driver: Install Driver diff --git a/docs/zh_CN/api-reference/peripherals/i2c.rst b/docs/zh_CN/api-reference/peripherals/i2c.rst index 86faffa8b8..b1bb004acf 100644 --- a/docs/zh_CN/api-reference/peripherals/i2c.rst +++ b/docs/zh_CN/api-reference/peripherals/i2c.rst @@ -206,6 +206,12 @@ I2C 驱动程序管理在 I2C 总线上设备的通信,该驱动程序具备 在主机模式下,SCL 的时钟频率不应大于上表中提到的 SCL 的最大频率。 +.. note:: + + SCL 的时钟频率会被上拉电阻和线上电容(或是从机电容)一起影响。因此,用户需要自己选择合适的上拉电阻去保证 SCL 时钟频率是准确的。尽管 I2C 协议推荐上拉电阻值为 1K 欧姆到 10K 欧姆,但是需要根据不同的频率需要选择不同的上拉电阻。 + + 通常来说,所选择的频率越高,需要的上拉电阻越小 (但是不要小于 1K 欧姆)。这是因为高电阻会减小电流,这会延长上升时间从而是频率变慢。通常我们推荐的上拉阻值范围为 2K 欧姆到 5K 欧姆,但是用户可能也需要根据他们的实际情况做出一些调整。 + .. _i2c-api-install-driver: 安装驱动程序 diff --git a/tools/ci/check_copyright_ignore.txt b/tools/ci/check_copyright_ignore.txt index a31f185011..8e06e60a19 100644 --- a/tools/ci/check_copyright_ignore.txt +++ b/tools/ci/check_copyright_ignore.txt @@ -780,7 +780,6 @@ components/hal/esp32s2/include/hal/aes_ll.h components/hal/esp32s2/include/hal/crypto_dma_ll.h components/hal/esp32s2/include/hal/dac_hal.h components/hal/esp32s2/include/hal/dedic_gpio_ll.h -components/hal/esp32s2/include/hal/i2c_ll.h components/hal/esp32s2/include/hal/memprot_peri_ll.h components/hal/esp32s2/include/hal/mpu_ll.h components/hal/esp32s2/include/hal/rtc_io_ll.h