mirror of
https://github.com/espressif/esp-idf.git
synced 2024-10-05 20:47:46 -04:00
i2c: fix I2C slave clock source selection
In I2C slave mode, clock source can now be changed, according to the flags specified in `i2c_config_t` structure. Thus, ESP32-S2 can now act as an I2C slave, even with a 400KHz master clock.
This commit is contained in:
parent
f29d873c54
commit
2575c0d49f
@ -631,7 +631,7 @@ static esp_err_t i2c_hw_fsm_reset(i2c_port_t i2c_num)
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
static i2c_sclk_t i2c_get_clk_src(const i2c_config_t *i2c_conf)
|
||||
static i2c_sclk_t i2c_get_clk_src(const uint32_t clk_flags, const uint32_t clk_speed)
|
||||
{
|
||||
for (i2c_sclk_t clk = I2C_SCLK_DEFAULT + 1; clk < I2C_SCLK_MAX; clk++) {
|
||||
#if CONFIG_IDF_TARGET_ESP32S3
|
||||
@ -639,7 +639,8 @@ static i2c_sclk_t i2c_get_clk_src(const i2c_config_t *i2c_conf)
|
||||
continue;
|
||||
}
|
||||
#endif
|
||||
if (((i2c_conf->clk_flags & i2c_clk_alloc[clk].character) == i2c_conf->clk_flags) && (i2c_conf->master.clk_speed <= i2c_clk_alloc[clk].clk_freq)) {
|
||||
if ( ((clk_flags & i2c_clk_alloc[clk].character) == clk_flags) &&
|
||||
(clk_speed <= i2c_clk_alloc[clk].clk_freq) ) {
|
||||
return clk;
|
||||
}
|
||||
}
|
||||
@ -648,14 +649,29 @@ static i2c_sclk_t i2c_get_clk_src(const i2c_config_t *i2c_conf)
|
||||
|
||||
esp_err_t i2c_param_config(i2c_port_t i2c_num, const i2c_config_t *i2c_conf)
|
||||
{
|
||||
i2c_sclk_t src_clk = I2C_SCLK_DEFAULT;
|
||||
esp_err_t ret = ESP_OK;
|
||||
|
||||
ESP_RETURN_ON_FALSE(i2c_num < I2C_NUM_MAX, ESP_ERR_INVALID_ARG, I2C_TAG, I2C_NUM_ERROR_STR);
|
||||
ESP_RETURN_ON_FALSE(i2c_conf != NULL, ESP_ERR_INVALID_ARG, I2C_TAG, I2C_ADDR_ERROR_STR);
|
||||
ESP_RETURN_ON_FALSE(i2c_conf->mode < I2C_MODE_MAX, ESP_ERR_INVALID_ARG, I2C_TAG, I2C_MODE_ERR_STR);
|
||||
|
||||
if (i2c_conf->mode == I2C_MODE_MASTER) {
|
||||
ESP_RETURN_ON_FALSE(i2c_get_clk_src(i2c_conf) != I2C_SCLK_MAX, ESP_ERR_INVALID_ARG, I2C_TAG, I2C_CLK_FLAG_ERR_STR);
|
||||
src_clk = i2c_get_clk_src(i2c_conf->clk_flags, i2c_conf->master.clk_speed);
|
||||
ESP_RETURN_ON_FALSE(src_clk != I2C_SCLK_MAX, ESP_ERR_INVALID_ARG, I2C_TAG, I2C_CLK_FLAG_ERR_STR);
|
||||
} else {
|
||||
#if CONFIG_IDF_TARGET_ESP32S2
|
||||
/* On ESP32-S2, APB clock shall always be used in slave mode as the
|
||||
* other one, I2C_SCLK_REF_TICK, is too slow, even for sampling a
|
||||
* 100KHz SCL. */
|
||||
src_clk = I2C_SCLK_APB;
|
||||
#else
|
||||
src_clk = i2c_get_clk_src(i2c_conf->clk_flags, i2c_conf->slave.maximum_speed);
|
||||
ESP_RETURN_ON_FALSE(src_clk != I2C_SCLK_MAX, ESP_ERR_INVALID_ARG, I2C_TAG, I2C_CLK_FLAG_ERR_STR);
|
||||
#endif
|
||||
}
|
||||
|
||||
esp_err_t ret = i2c_set_pin(i2c_num, i2c_conf->sda_io_num, i2c_conf->scl_io_num,
|
||||
ret = i2c_set_pin(i2c_num, i2c_conf->sda_io_num, i2c_conf->scl_io_num,
|
||||
i2c_conf->sda_pullup_en, i2c_conf->scl_pullup_en, i2c_conf->mode);
|
||||
if (ret != ESP_OK) {
|
||||
return ret;
|
||||
@ -666,6 +682,7 @@ esp_err_t i2c_param_config(i2c_port_t i2c_num, const i2c_config_t *i2c_conf)
|
||||
i2c_hal_clr_intsts_mask(&(i2c_context[i2c_num].hal), I2C_LL_INTR_MASK);
|
||||
if (i2c_conf->mode == I2C_MODE_SLAVE) { //slave mode
|
||||
i2c_hal_slave_init(&(i2c_context[i2c_num].hal), i2c_num);
|
||||
i2c_hal_set_source_clk(&(i2c_context[i2c_num].hal), src_clk);
|
||||
i2c_hal_set_slave_addr(&(i2c_context[i2c_num].hal), i2c_conf->slave.slave_addr, i2c_conf->slave.addr_10bit_en);
|
||||
i2c_hal_set_rxfifo_full_thr(&(i2c_context[i2c_num].hal), I2C_FIFO_FULL_THRESH_VAL);
|
||||
i2c_hal_set_txfifo_empty_thr(&(i2c_context[i2c_num].hal), I2C_FIFO_EMPTY_THRESH_VAL);
|
||||
@ -678,7 +695,7 @@ esp_err_t i2c_param_config(i2c_port_t i2c_num, const i2c_config_t *i2c_conf)
|
||||
i2c_hal_master_init(&(i2c_context[i2c_num].hal), i2c_num);
|
||||
//Default, we enable hardware filter
|
||||
i2c_hal_set_filter(&(i2c_context[i2c_num].hal), I2C_FILTER_CYC_NUM_DEF);
|
||||
i2c_hal_set_bus_timing(&(i2c_context[i2c_num].hal), i2c_conf->master.clk_speed, i2c_get_clk_src(i2c_conf));
|
||||
i2c_hal_set_bus_timing(&(i2c_context[i2c_num].hal), i2c_conf->master.clk_speed, src_clk);
|
||||
}
|
||||
I2C_EXIT_CRITICAL(&(i2c_context[i2c_num].spinlock));
|
||||
return ESP_OK;
|
||||
|
@ -79,6 +79,7 @@ typedef struct{
|
||||
struct {
|
||||
uint8_t addr_10bit_en; /*!< I2C 10bit address mode enable for slave mode */
|
||||
uint16_t slave_addr; /*!< I2C address for slave mode */
|
||||
uint32_t maximum_speed; /*!< I2C expected clock speed from SCL. */
|
||||
} slave; /*!< I2C slave config */
|
||||
};
|
||||
uint32_t clk_flags; /*!< Bitwise of ``I2C_SCLK_SRC_FLAG_**FOR_DFS**`` for clk source choice*/
|
||||
|
@ -680,7 +680,7 @@ static inline void i2c_ll_master_clr_rx_it(i2c_dev_t *hw)
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief
|
||||
* @brief Enable I2C slave TX interrupt
|
||||
*
|
||||
* @param hw Beginning address of the peripheral registers
|
||||
*
|
||||
@ -752,7 +752,7 @@ static inline void i2c_ll_slave_clr_rx_it(i2c_dev_t *hw)
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Reste I2C master FSM. When the master FSM is stuck, call this function to reset the FSM
|
||||
* @brief Reset I2C master FSM. When the master FSM is stuck, call this function to reset the FSM
|
||||
*
|
||||
* @param hw Beginning address of the peripheral registers
|
||||
*
|
||||
|
@ -110,6 +110,16 @@ typedef struct {
|
||||
*/
|
||||
#define i2c_hal_slave_clr_rx_it(hal) i2c_ll_slave_clr_rx_it((hal)->dev)
|
||||
|
||||
/**
|
||||
* @brief Set the source clock. This function is meant to be used in
|
||||
* slave mode, in order to select a source clock abe to handle
|
||||
* the expected SCL frequency.
|
||||
*
|
||||
* @param hal Context of the HAL layer
|
||||
* @param src_clk Source clock to use choosen from `i2c_sclk_t` type
|
||||
*/
|
||||
#define i2c_hal_set_source_clk(hal, src_clk) i2c_ll_set_source_clk((hal)->dev, src_clk)
|
||||
|
||||
/**
|
||||
* @brief Init the I2C master.
|
||||
*
|
||||
|
Loading…
x
Reference in New Issue
Block a user