kopia lustrzana https://github.com/espressif/esp-idf
Merge branch 'feature/support_lp_i2c_in_drv' into 'master'
feat(i2c_master): Add feature for support using lp_i2c in i2c_master driver See merge request espressif/esp-idf!29907pull/13660/head
commit
6224fca8a0
|
@ -129,13 +129,13 @@ static const char *I2C_TAG = "i2c";
|
|||
/**
|
||||
* I2C bus are defined in the header files, let's check that the values are correct
|
||||
*/
|
||||
#if SOC_I2C_NUM >= 2
|
||||
#if SOC_HP_I2C_NUM >= 2
|
||||
_Static_assert(I2C_NUM_1 == 1, "I2C_NUM_1 must be equal to 1");
|
||||
#endif // SOC_I2C_NUM >= 2
|
||||
#endif // SOC_HP_I2C_NUM >= 2
|
||||
#if SOC_LP_I2C_SUPPORTED
|
||||
_Static_assert(I2C_NUM_MAX == (SOC_I2C_NUM + SOC_LP_I2C_NUM), "I2C_NUM_MAX must be equal to SOC_I2C_NUM + SOC_LP_I2C_NUM");
|
||||
_Static_assert(I2C_NUM_MAX == (SOC_HP_I2C_NUM + SOC_LP_I2C_NUM), "I2C_NUM_MAX must be equal to SOC_HP_I2C_NUM + SOC_LP_I2C_NUM");
|
||||
#else
|
||||
_Static_assert(I2C_NUM_MAX == SOC_I2C_NUM, "I2C_NUM_MAX must be equal to SOC_I2C_NUM");
|
||||
_Static_assert(I2C_NUM_MAX == SOC_HP_I2C_NUM, "I2C_NUM_MAX must be equal to SOC_HP_I2C_NUM");
|
||||
#endif /* SOC_LP_I2C_SUPPORTED */
|
||||
|
||||
typedef struct {
|
||||
|
@ -225,7 +225,7 @@ static i2c_context_t i2c_context[I2C_NUM_MAX] = {
|
|||
I2C_CONTEX_INIT_DEF(I2C_NUM_0),
|
||||
/* Now that I2C_NUM_MAX is part of an enum (i2c_port_t), we cannot use
|
||||
* it anomore in the preprocessor! */
|
||||
#if SOC_I2C_NUM > 1
|
||||
#if SOC_HP_I2C_NUM > 1
|
||||
I2C_CONTEX_INIT_DEF(I2C_NUM_1),
|
||||
#endif
|
||||
};
|
||||
|
|
|
@ -47,11 +47,11 @@
|
|||
#define READ_BIT I2C_MASTER_READ /*!< I2C master read */
|
||||
#define ACK_CHECK_EN 0x1 /*!< I2C master will check ack from slave*/
|
||||
|
||||
static DRAM_ATTR i2c_dev_t *const I2C[SOC_I2C_NUM] = { &I2C0,
|
||||
#if SOC_I2C_NUM > 1
|
||||
&I2C1,
|
||||
static DRAM_ATTR i2c_dev_t *const I2C[SOC_HP_I2C_NUM] = { &I2C0,
|
||||
#if SOC_HP_I2C_NUM > 1
|
||||
&I2C1,
|
||||
#endif
|
||||
};
|
||||
};
|
||||
|
||||
#define ACK_VAL 0
|
||||
#define NACK_VAL 1
|
||||
|
@ -503,7 +503,7 @@ static void i2c_slave_repeat_read(void)
|
|||
|
||||
TEST_CASE_MULTIPLE_DEVICES("I2C repeat write test", "[i2c][test_env=generic_multi_device][timeout=150]", i2c_master_repeat_write, i2c_slave_repeat_read);
|
||||
|
||||
#if SOC_I2C_NUM > 1
|
||||
#if SOC_HP_I2C_NUM > 1
|
||||
|
||||
static void i2c_master_write_test_more_ports(void)
|
||||
{
|
||||
|
|
|
@ -27,6 +27,12 @@
|
|||
#include "esp_clk_tree.h"
|
||||
#include "clk_ctrl_os.h"
|
||||
#include "esp_private/gpio.h"
|
||||
#if SOC_LP_I2C_SUPPORTED
|
||||
#include "hal/rtc_io_ll.h"
|
||||
#include "driver/rtc_io.h"
|
||||
#include "soc/rtc_io_channel.h"
|
||||
#include "driver/lp_io.h"
|
||||
#endif
|
||||
#if CONFIG_PM_POWER_DOWN_PERIPHERAL_IN_LIGHT_SLEEP
|
||||
#include "esp_private/sleep_retention.h"
|
||||
#endif
|
||||
|
@ -69,22 +75,38 @@ static esp_err_t s_i2c_bus_handle_acquire(i2c_port_num_t port_num, i2c_bus_handl
|
|||
bus->port_num = port_num;
|
||||
bus->spinlock = (portMUX_TYPE)portMUX_INITIALIZER_UNLOCKED;
|
||||
bus->bus_mode = mode;
|
||||
bus->is_lp_i2c = (bus->port_num < SOC_HP_I2C_NUM) ? false : true;
|
||||
|
||||
#if CONFIG_PM_POWER_DOWN_PERIPHERAL_IN_LIGHT_SLEEP && !CONFIG_IDF_TARGET_ESP32P4 // TODO: IDF-9353
|
||||
sleep_retention_module_init_param_t init_param = {
|
||||
.cbs = { .create = { .handle = s_i2c_sleep_retention_init, .arg = (void *)bus } }
|
||||
};
|
||||
ret = sleep_retention_module_init(I2C_SLEEP_RETENTION_MODULE(port_num), &init_param);
|
||||
if (ret == ESP_OK) {
|
||||
sleep_retention_module_allocate(I2C_SLEEP_RETENTION_MODULE(port_num));
|
||||
if (bus->is_lp_i2c == false) {
|
||||
sleep_retention_module_init_param_t init_param = {
|
||||
.cbs = { .create = { .handle = s_i2c_sleep_retention_init, .arg = (void *)bus } }
|
||||
};
|
||||
ret = sleep_retention_module_init(I2C_SLEEP_RETENTION_MODULE(port_num), &init_param);
|
||||
if (ret == ESP_OK) {
|
||||
sleep_retention_module_allocate(I2C_SLEEP_RETENTION_MODULE(port_num));
|
||||
}
|
||||
} else {
|
||||
ESP_LOGW(TAG, "Detected PM_POWER_DOWN_PERIPHERAL_IN_LIGHT_SLEEP is enabled while LP_I2C is used. Sleep retention is not supported on LP I2C. Please use it properly");
|
||||
}
|
||||
#endif
|
||||
|
||||
// Enable the I2C module
|
||||
I2C_RCC_ATOMIC() {
|
||||
i2c_ll_enable_bus_clock(bus->port_num, true);
|
||||
i2c_ll_reset_register(bus->port_num);
|
||||
if (!bus->is_lp_i2c) {
|
||||
I2C_RCC_ATOMIC() {
|
||||
i2c_ll_enable_bus_clock(bus->port_num, true);
|
||||
i2c_ll_reset_register(bus->port_num);
|
||||
}
|
||||
}
|
||||
#if SOC_LP_I2C_SUPPORTED
|
||||
else {
|
||||
LP_I2C_BUS_CLK_ATOMIC() {
|
||||
lp_i2c_ll_enable_bus_clock(bus->port_num - SOC_HP_I2C_NUM, true);
|
||||
lp_i2c_ll_reset_register(bus->port_num - SOC_HP_I2C_NUM);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
I2C_CLOCK_SRC_ATOMIC() {
|
||||
i2c_hal_init(&bus->hal, port_num);
|
||||
}
|
||||
|
@ -117,7 +139,7 @@ esp_err_t i2c_acquire_bus_handle(i2c_port_num_t port_num, i2c_bus_handle_t *i2c_
|
|||
esp_err_t ret = ESP_OK;
|
||||
_lock_acquire(&s_i2c_platform.mutex);
|
||||
if (port_num == -1) {
|
||||
for (int i = 0; i < SOC_I2C_NUM; i++) {
|
||||
for (int i = 0; i < SOC_HP_I2C_NUM; i++) {
|
||||
bus_occupied = i2c_bus_occupied(i);
|
||||
if (bus_occupied == false) {
|
||||
ret = s_i2c_bus_handle_acquire(i, i2c_new_bus, mode);
|
||||
|
@ -154,9 +176,11 @@ esp_err_t i2c_release_bus_handle(i2c_bus_handle_t i2c_bus)
|
|||
do_deinitialize = true;
|
||||
s_i2c_platform.buses[port_num] = NULL;
|
||||
#if CONFIG_PM_POWER_DOWN_PERIPHERAL_IN_LIGHT_SLEEP && !CONFIG_IDF_TARGET_ESP32P4 // TODO: IDF-9353
|
||||
esp_err_t err = sleep_retention_module_free(I2C_SLEEP_RETENTION_MODULE(port_num));
|
||||
if (err == ESP_OK) {
|
||||
err = sleep_retention_module_deinit(I2C_SLEEP_RETENTION_MODULE(port_num));
|
||||
if (i2c_bus->is_lp_i2c == false) {
|
||||
esp_err_t err = sleep_retention_module_free(I2C_SLEEP_RETENTION_MODULE(port_num));
|
||||
if (err == ESP_OK) {
|
||||
err = sleep_retention_module_deinit(I2C_SLEEP_RETENTION_MODULE(port_num));
|
||||
}
|
||||
}
|
||||
#endif
|
||||
if (i2c_bus->intr_handle) {
|
||||
|
@ -166,9 +190,18 @@ esp_err_t i2c_release_bus_handle(i2c_bus_handle_t i2c_bus)
|
|||
ESP_RETURN_ON_ERROR(esp_pm_lock_delete(i2c_bus->pm_lock), TAG, "delete pm_lock failed");
|
||||
}
|
||||
// Disable I2C module
|
||||
I2C_RCC_ATOMIC() {
|
||||
i2c_ll_enable_bus_clock(port_num, false);
|
||||
if (!i2c_bus->is_lp_i2c) {
|
||||
I2C_RCC_ATOMIC() {
|
||||
i2c_ll_enable_bus_clock(port_num, false);
|
||||
}
|
||||
}
|
||||
#if SOC_LP_I2C_SUPPORTED
|
||||
else {
|
||||
LP_I2C_BUS_CLK_ATOMIC() {
|
||||
lp_i2c_ll_enable_bus_clock(port_num - SOC_HP_I2C_NUM, false);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
free(i2c_bus);
|
||||
}
|
||||
}
|
||||
|
@ -192,7 +225,7 @@ esp_err_t i2c_release_bus_handle(i2c_bus_handle_t i2c_bus)
|
|||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t i2c_select_periph_clock(i2c_bus_handle_t handle, i2c_clock_source_t clk_src)
|
||||
esp_err_t i2c_select_periph_clock(i2c_bus_handle_t handle, soc_module_clk_t clk_src)
|
||||
{
|
||||
esp_err_t ret = ESP_OK;
|
||||
ESP_RETURN_ON_FALSE(handle, ESP_ERR_INVALID_ARG, TAG, "I2C empty controller handle");
|
||||
|
@ -211,7 +244,7 @@ esp_err_t i2c_select_periph_clock(i2c_bus_handle_t handle, i2c_clock_source_t cl
|
|||
|
||||
// TODO: [clk_tree] to use a generic clock enable/disable or acquire/release function for all clock source
|
||||
#if SOC_I2C_SUPPORT_RTC
|
||||
if (clk_src == I2C_CLK_SRC_RC_FAST) {
|
||||
if (clk_src == (soc_module_clk_t)I2C_CLK_SRC_RC_FAST) {
|
||||
// RC_FAST clock is not enabled automatically on start up, we enable it here manually.
|
||||
// Note there's a ref count in the enable/disable function, we must call them in pair in the driver.
|
||||
periph_rtc_dig_clk8m_enable();
|
||||
|
@ -229,19 +262,24 @@ esp_err_t i2c_select_periph_clock(i2c_bus_handle_t handle, i2c_clock_source_t cl
|
|||
esp_pm_lock_type_t pm_lock_type = ESP_PM_NO_LIGHT_SLEEP;
|
||||
|
||||
#if SOC_I2C_SUPPORT_RTC
|
||||
if (clk_src == I2C_CLK_SRC_RC_FAST) {
|
||||
if (clk_src == (soc_module_clk_t)I2C_CLK_SRC_RC_FAST) {
|
||||
// I2C use fifo, which connected to APB, so we cannot use I2C either when in light sleep.
|
||||
need_pm_lock = ESP_PM_NO_LIGHT_SLEEP;
|
||||
pm_lock_type = ESP_PM_NO_LIGHT_SLEEP;
|
||||
}
|
||||
#endif // SOC_I2C_SUPPORT_RTC
|
||||
|
||||
#if SOC_I2C_SUPPORT_APB
|
||||
if (clk_src == I2C_CLK_SRC_APB) {
|
||||
if (clk_src == (soc_module_clk_t)I2C_CLK_SRC_APB) {
|
||||
// APB clock frequency can be changed during DFS
|
||||
pm_lock_type = ESP_PM_APB_FREQ_MAX;
|
||||
}
|
||||
#endif // SOC_I2C_SUPPORT_APB
|
||||
|
||||
if (handle->is_lp_i2c) {
|
||||
// Even for LP I2C, the clock will also be powered down when going into light sleep.
|
||||
pm_lock_type = ESP_PM_NO_LIGHT_SLEEP;
|
||||
}
|
||||
|
||||
if (need_pm_lock) {
|
||||
sprintf(handle->pm_lock_name, "I2C_%d", handle->port_num); // e.g. PORT_0
|
||||
ret = esp_pm_lock_create(pm_lock_type, 0, handle->pm_lock_name, &handle->pm_lock);
|
||||
|
@ -253,10 +291,8 @@ esp_err_t i2c_select_periph_clock(i2c_bus_handle_t handle, i2c_clock_source_t cl
|
|||
return ret;
|
||||
}
|
||||
|
||||
esp_err_t i2c_common_set_pins(i2c_bus_handle_t handle)
|
||||
static esp_err_t s_hp_i2c_pins_config(i2c_bus_handle_t handle)
|
||||
{
|
||||
esp_err_t ret = ESP_OK;
|
||||
ESP_RETURN_ON_FALSE(handle, ESP_ERR_INVALID_ARG, TAG, "I2C empty controller handle");
|
||||
int port_id = handle->port_num;
|
||||
|
||||
// SDA pin configurations
|
||||
|
@ -286,5 +322,71 @@ esp_err_t i2c_common_set_pins(i2c_bus_handle_t handle)
|
|||
gpio_func_sel(handle->scl_num, PIN_FUNC_GPIO);
|
||||
esp_rom_gpio_connect_out_signal(handle->scl_num, i2c_periph_signal[port_id].scl_out_sig, 0, 0);
|
||||
esp_rom_gpio_connect_in_signal(handle->scl_num, i2c_periph_signal[port_id].scl_in_sig, 0);
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
#if SOC_LP_I2C_SUPPORTED
|
||||
|
||||
static esp_err_t s_lp_i2c_pins_config(i2c_bus_handle_t handle)
|
||||
{
|
||||
ESP_RETURN_ON_ERROR(!rtc_gpio_is_valid_gpio(handle->sda_num), TAG, "LP I2C SDA GPIO invalid");
|
||||
ESP_RETURN_ON_ERROR(!rtc_gpio_is_valid_gpio(handle->scl_num), TAG, "LP I2C SCL GPIO invalid");
|
||||
|
||||
#if !SOC_LP_GPIO_MATRIX_SUPPORTED
|
||||
/* Verify that the SDA and SCL line belong to the LP IO Mux I2C function group */
|
||||
ESP_RETURN_ON_FALSE((handle->sda_num == LP_I2C_SDA_IOMUX_PAD), ESP_ERR_INVALID_ARG, TAG, LP_I2C_SDA_PIN_ERR_LOG);
|
||||
ESP_RETURN_ON_FALSE((handle->scl_num == LP_I2C_SCL_IOMUX_PAD), ESP_ERR_INVALID_ARG, TAG, LP_I2C_SCL_PIN_ERR_LOG);
|
||||
#endif /* !SOC_LP_GPIO_MATRIX_SUPPORTED */
|
||||
int port_id = handle->port_num;
|
||||
|
||||
rtc_gpio_init(handle->sda_num);
|
||||
rtc_gpio_set_direction(handle->sda_num, RTC_GPIO_MODE_INPUT_OUTPUT_OD);
|
||||
rtc_gpio_pulldown_dis(handle->sda_num);
|
||||
if (handle->pull_up_enable) {
|
||||
rtc_gpio_pullup_en(handle->sda_num);
|
||||
} else {
|
||||
rtc_gpio_pullup_dis(handle->sda_num);
|
||||
}
|
||||
#if !SOC_LP_GPIO_MATRIX_SUPPORTED
|
||||
rtc_gpio_iomux_func_sel(handle->sda_num, i2c_periph_signal[port_id].iomux_func);
|
||||
#else
|
||||
lp_gpio_connect_out_signal(handle->sda_num, i2c_periph_signal[port_id].scl_out_sig, 0, 0);
|
||||
lp_gpio_connect_in_signal(handle->sda_num, i2c_periph_signal[port_id].scl_in_sig, 0);
|
||||
#endif
|
||||
|
||||
rtc_gpio_init(handle->scl_num);
|
||||
rtc_gpio_set_direction(handle->scl_num, RTC_GPIO_MODE_INPUT_OUTPUT_OD);
|
||||
rtc_gpio_pulldown_dis(handle->scl_num);
|
||||
if (handle->pull_up_enable) {
|
||||
rtc_gpio_pullup_en(handle->scl_num);
|
||||
} else {
|
||||
rtc_gpio_pullup_dis(handle->scl_num);
|
||||
}
|
||||
#if !SOC_LP_GPIO_MATRIX_SUPPORTED
|
||||
rtc_gpio_iomux_func_sel(handle->scl_num, i2c_periph_signal[port_id].iomux_func);
|
||||
#else
|
||||
lp_gpio_connect_out_signal(handle->scl_num, i2c_periph_signal[port_id].sda_out_sig, 0, 0);
|
||||
lp_gpio_connect_in_signal(handle->scl_num, i2c_periph_signal[port_id].sda_in_sig, 0);
|
||||
#endif
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
#endif // SOC_LP_I2C_SUPPORTED
|
||||
|
||||
esp_err_t i2c_common_set_pins(i2c_bus_handle_t handle)
|
||||
{
|
||||
esp_err_t ret = ESP_OK;
|
||||
|
||||
if (handle->is_lp_i2c == false) {
|
||||
ESP_RETURN_ON_ERROR(s_hp_i2c_pins_config(handle), TAG, "config i2c pins failed");
|
||||
}
|
||||
#if SOC_LP_I2C_SUPPORTED
|
||||
else {
|
||||
ESP_RETURN_ON_ERROR(s_lp_i2c_pins_config(handle), TAG, "config i2c lp pins failed");
|
||||
}
|
||||
#endif
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
|
|
@ -40,6 +40,12 @@ static const char *TAG = "i2c.master";
|
|||
#define I2C_ADDRESS_TRANS_WRITE(device_address) (((device_address) << 1) | 0)
|
||||
#define I2C_ADDRESS_TRANS_READ(device_address) (((device_address) << 1) | 1)
|
||||
|
||||
#if SOC_LP_I2C_SUPPORTED
|
||||
#define I2C_FIFO_LEN(port_num) (((port_num) < SOC_HP_I2C_NUM) ? SOC_I2C_FIFO_LEN : SOC_LP_I2C_FIFO_LEN)
|
||||
#else
|
||||
#define I2C_FIFO_LEN(port_num) (SOC_I2C_FIFO_LEN)
|
||||
#endif
|
||||
|
||||
static esp_err_t s_i2c_master_clear_bus(i2c_bus_handle_t handle)
|
||||
{
|
||||
#if !SOC_I2C_SUPPORT_HW_CLR_BUS
|
||||
|
@ -136,7 +142,7 @@ static bool s_i2c_write_command(i2c_master_bus_handle_t i2c_master, i2c_operatio
|
|||
uint8_t data_fill = 0;
|
||||
|
||||
// data_fill refers to the length to fill the data
|
||||
data_fill = MIN(remaining_bytes, SOC_I2C_FIFO_LEN - *address_fill);
|
||||
data_fill = MIN(remaining_bytes, I2C_FIFO_LEN(i2c_master->base->port_num) - *address_fill);
|
||||
write_pr = i2c_operation->data + i2c_operation->bytes_used;
|
||||
i2c_operation->bytes_used += data_fill;
|
||||
hw_cmd.byte_num = data_fill + *address_fill;
|
||||
|
@ -216,13 +222,13 @@ static bool s_i2c_read_command(i2c_master_bus_handle_t i2c_master, i2c_operation
|
|||
i2c_bus_handle_t handle = i2c_master->base;
|
||||
i2c_ll_hw_cmd_t hw_cmd = i2c_operation->hw_cmd;
|
||||
|
||||
*fifo_fill = MIN(remaining_bytes, SOC_I2C_FIFO_LEN - i2c_master->read_len_static);
|
||||
*fifo_fill = MIN(remaining_bytes, I2C_FIFO_LEN(i2c_master->base->port_num) - i2c_master->read_len_static);
|
||||
i2c_master->rx_cnt = *fifo_fill;
|
||||
hw_cmd.byte_num = *fifo_fill;
|
||||
|
||||
i2c_master->contains_read = true;
|
||||
#if !SOC_I2C_STOP_INDEPENDENT
|
||||
if (remaining_bytes < SOC_I2C_FIFO_LEN - 1) {
|
||||
if (remaining_bytes < I2C_FIFO_LEN(i2c_master->base->port_num) - 1) {
|
||||
if (i2c_operation->hw_cmd.ack_val == ACK_VAL) {
|
||||
if (remaining_bytes != 0) {
|
||||
i2c_ll_master_write_cmd_reg(hal->dev, hw_cmd, i2c_master->cmd_idx);
|
||||
|
@ -531,8 +537,20 @@ static esp_err_t s_i2c_transaction_start(i2c_master_dev_handle_t i2c_dev, int xf
|
|||
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);
|
||||
|
||||
if (!i2c_master->base->is_lp_i2c) {
|
||||
I2C_CLOCK_SRC_ATOMIC() {
|
||||
i2c_ll_set_source_clk(hal->dev, i2c_master->base->clk_src);
|
||||
}
|
||||
}
|
||||
#if SOC_LP_I2C_SUPPORTED
|
||||
else {
|
||||
LP_I2C_SRC_CLK_ATOMIC() {
|
||||
lp_i2c_ll_set_source_clk(hal->dev, i2c_master->base->clk_src);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
I2C_CLOCK_SRC_ATOMIC() {
|
||||
i2c_ll_set_source_clk(hal->dev, i2c_master->base->clk_src);
|
||||
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);
|
||||
|
@ -692,7 +710,8 @@ static esp_err_t i2c_param_master_config(i2c_bus_handle_t handle, const i2c_mast
|
|||
i2c_hal_context_t *hal = &handle->hal;
|
||||
|
||||
ESP_RETURN_ON_ERROR(i2c_common_set_pins(handle), TAG, "i2c master set pin failed");
|
||||
ESP_RETURN_ON_ERROR(i2c_select_periph_clock(handle, i2c_conf->clk_source), TAG, "i2c select clock failed");
|
||||
soc_module_clk_t clk_source = i2c_conf->clk_source;
|
||||
ESP_RETURN_ON_ERROR(i2c_select_periph_clock(handle, clk_source), TAG, "i2c select clock failed");
|
||||
handle->clk_src = i2c_conf->clk_source;
|
||||
portENTER_CRITICAL(&handle->spinlock);
|
||||
i2c_hal_master_init(hal);
|
||||
|
|
|
@ -36,6 +36,11 @@ extern "C" {
|
|||
#define I2C_RCC_ATOMIC()
|
||||
#endif
|
||||
|
||||
#if SOC_LP_I2C_SUPPORTED
|
||||
#define LP_I2C_SRC_CLK_ATOMIC() PERIPH_RCC_ATOMIC()
|
||||
#define LP_I2C_BUS_CLK_ATOMIC() PERIPH_RCC_ATOMIC()
|
||||
#endif
|
||||
|
||||
#if CONFIG_I2C_ISR_IRAM_SAFE
|
||||
#define I2C_MEM_ALLOC_CAPS (MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT)
|
||||
#else
|
||||
|
@ -100,9 +105,10 @@ typedef struct {
|
|||
|
||||
struct i2c_bus_t {
|
||||
i2c_port_num_t port_num; // Port(Bus) ID, index from 0
|
||||
bool is_lp_i2c; // true if current port is lp_i2c. false is hp_i2c
|
||||
portMUX_TYPE spinlock; // To protect pre-group register level concurrency access
|
||||
i2c_hal_context_t hal; // Hal layer for each port(bus)
|
||||
i2c_clock_source_t clk_src; // Record the port clock source
|
||||
soc_module_clk_t clk_src; // Record the port clock source
|
||||
uint32_t clk_src_freq_hz; // Record the clock source frequency
|
||||
int sda_num; // SDA pin number
|
||||
int scl_num; // SCL pin number
|
||||
|
@ -232,7 +238,7 @@ esp_err_t i2c_release_bus_handle(i2c_bus_handle_t i2c_bus);
|
|||
* - ESP_ERR_INVALID_STATE: Set clock source failed because the clk_src is different from other I2C controller
|
||||
* - ESP_FAIL: Set clock source failed because of other error
|
||||
*/
|
||||
esp_err_t i2c_select_periph_clock(i2c_bus_handle_t handle, i2c_clock_source_t clk_src);
|
||||
esp_err_t i2c_select_periph_clock(i2c_bus_handle_t handle, soc_module_clk_t clk_src);
|
||||
|
||||
/**
|
||||
* @brief Set I2C SCL/SDA pins
|
||||
|
|
|
@ -188,7 +188,10 @@ esp_err_t i2c_new_slave_device(const i2c_slave_config_t *slave_config, i2c_slave
|
|||
i2c_slave_dev_t *i2c_slave = NULL;
|
||||
ESP_RETURN_ON_FALSE(slave_config && ret_handle, ESP_ERR_INVALID_ARG, TAG, "invalid argument");
|
||||
ESP_RETURN_ON_FALSE(GPIO_IS_VALID_GPIO(slave_config->sda_io_num) && GPIO_IS_VALID_GPIO(slave_config->scl_io_num), ESP_ERR_INVALID_ARG, TAG, "invalid SDA/SCL pin number");
|
||||
ESP_RETURN_ON_FALSE(slave_config->i2c_port < SOC_I2C_NUM || slave_config->i2c_port == -1, ESP_ERR_INVALID_ARG, TAG, "invalid i2c port number");
|
||||
#if SOC_LP_I2C_SUPPORTED
|
||||
ESP_RETURN_ON_FALSE(slave_config->i2c_port != (SOC_I2C_NUM - 1), ESP_ERR_NOT_SUPPORTED, TAG, "LP i2c is not supported in I2C slave");
|
||||
#endif
|
||||
ESP_RETURN_ON_FALSE(slave_config->i2c_port < SOC_HP_I2C_NUM || slave_config->i2c_port == -1, ESP_ERR_INVALID_ARG, TAG, "invalid i2c port number");
|
||||
ESP_RETURN_ON_FALSE((slave_config->send_buf_depth > 0), ESP_ERR_INVALID_ARG, TAG, "invalid SCL speed");
|
||||
#if SOC_I2C_SLAVE_SUPPORT_BROADCAST
|
||||
ESP_RETURN_ON_FALSE(((slave_config->addr_bit_len != I2C_ADDR_BIT_LEN_10) || (!slave_config->flags.broadcast_en)), ESP_ERR_INVALID_STATE, TAG, "10bits address cannot used together with broadcast");
|
||||
|
|
|
@ -19,10 +19,15 @@ extern "C" {
|
|||
* @brief I2C master bus specific configurations
|
||||
*/
|
||||
typedef struct {
|
||||
i2c_port_num_t i2c_port; /*!< I2C port number, `-1` for auto selecting */
|
||||
i2c_port_num_t i2c_port; /*!< I2C port number, `-1` for auto selecting, (not include LP I2C instance) */
|
||||
gpio_num_t sda_io_num; /*!< GPIO number of I2C SDA signal, pulled-up internally */
|
||||
gpio_num_t scl_io_num; /*!< GPIO number of I2C SCL signal, pulled-up internally */
|
||||
i2c_clock_source_t clk_source; /*!< Clock source of I2C master bus, channels in the same group must use the same clock source */
|
||||
union {
|
||||
i2c_clock_source_t clk_source; /*!< Clock source of I2C master bus */
|
||||
#if SOC_LP_I2C_SUPPORTED
|
||||
lp_i2c_clock_source_t lp_source_clk; /*!< LP_UART source clock selection */
|
||||
#endif
|
||||
};
|
||||
uint8_t glitch_ignore_cnt; /*!< If the glitch period on the line is less than this value, it can be filtered out, typically value is 7 (unit: I2C module clock cycle)*/
|
||||
int intr_priority; /*!< I2C interrupt priority, if set to 0, driver will select the default priority (1,2,3). */
|
||||
size_t trans_queue_depth; /*!< Depth of internal transfer queue, increase this value can support more transfers pending in the background, only valid in asynchronous transaction. (Typically max_device_num * per_transaction)*/
|
||||
|
|
|
@ -21,6 +21,10 @@ if(CONFIG_SOC_I2C_SUPPORT_10BIT_ADDR AND CONFIG_SOC_I2C_SUPPORT_SLAVE)
|
|||
list(APPEND srcs "test_i2c_10bit.c")
|
||||
endif()
|
||||
|
||||
if(CONFIG_SOC_LP_I2C_SUPPORTED)
|
||||
list(APPEND srcs "test_lp_i2c.c")
|
||||
endif()
|
||||
|
||||
# Only build this file with `CONFIG_PM_POWER_DOWN_CPU_IN_LIGHT_SLEEP` and `CONFIG_IEEE802154_ENABLED` enabled
|
||||
# Enable `CONFIG_IEEE802154_ENABLED` is for modem domain really power down.
|
||||
# This reliable can be removed if the sleep retention got finished.
|
||||
|
|
|
@ -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
|
||||
*/
|
||||
|
@ -25,6 +25,11 @@ extern "C" {
|
|||
#define I2C_MASTER_SDA_IO 2 /*!< gpio number for I2C master data */
|
||||
#endif
|
||||
|
||||
#if SOC_LP_I2C_SUPPORTED
|
||||
#define LP_I2C_SCL_IO 7
|
||||
#define LP_I2C_SDA_IO 6
|
||||
#endif
|
||||
|
||||
#define ESP_SLAVE_ADDR 0x28 /*!< ESP_I2C slave address, you can set any 7bit value */
|
||||
#define TEST_I2C_PORT 0
|
||||
#define DATA_LENGTH 100
|
||||
|
|
|
@ -55,7 +55,7 @@ TEST_CASE("I2C bus install-uninstall test", "[i2c]")
|
|||
};
|
||||
i2c_master_bus_handle_t i2c_mst_handle1;
|
||||
|
||||
#if SOC_I2C_NUM > 1
|
||||
#if SOC_HP_I2C_NUM > 1
|
||||
i2c_master_bus_config_t i2c_mst_config_2 = {
|
||||
.clk_source = I2C_CLK_SRC_DEFAULT,
|
||||
.i2c_port = 1,
|
||||
|
@ -68,7 +68,7 @@ TEST_CASE("I2C bus install-uninstall test", "[i2c]")
|
|||
// Install master bus 0
|
||||
ESP_LOGI(TAG, "Initialize bus0");
|
||||
TEST_ESP_OK(i2c_new_master_bus(&i2c_mst_config_1, &i2c_mst_handle1));
|
||||
#if SOC_I2C_NUM > 1
|
||||
#if SOC_HP_I2C_NUM > 1
|
||||
// Install master bus 1
|
||||
ESP_LOGI(TAG, "Initialize bus1");
|
||||
TEST_ESP_OK(i2c_new_master_bus(&i2c_mst_config_2, &i2c_mst_handle2));
|
||||
|
@ -78,7 +78,7 @@ TEST_CASE("I2C bus install-uninstall test", "[i2c]")
|
|||
TEST_ESP_ERR(ESP_ERR_INVALID_STATE, i2c_new_master_bus(&i2c_mst_config_1, &i2c_mst_handle1));
|
||||
ESP_LOGI(TAG, "Delete bus0");
|
||||
TEST_ESP_OK(i2c_del_master_bus(i2c_mst_handle1));
|
||||
#if SOC_I2C_NUM > 1
|
||||
#if SOC_HP_I2C_NUM > 1
|
||||
ESP_LOGI(TAG, "Delete bus1");
|
||||
TEST_ESP_OK(i2c_del_master_bus(i2c_mst_handle2));
|
||||
#endif
|
||||
|
|
|
@ -613,7 +613,7 @@ static void slave_init_for_probe(void)
|
|||
|
||||
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
|
||||
#if SOC_HP_I2C_NUM > 1
|
||||
// Now chips with multiple I2C controllers are up to 2, can test more ports when we have more I2C controllers.
|
||||
static void i2c_master_write_test_more_port(void)
|
||||
{
|
||||
|
|
|
@ -0,0 +1,154 @@
|
|||
/*
|
||||
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Unlicense OR CC0-1.0
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include "sdkconfig.h"
|
||||
#include "unity.h"
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "freertos/queue.h"
|
||||
#include "esp_err.h"
|
||||
#include "soc/gpio_periph.h"
|
||||
#include "soc/clk_tree_defs.h"
|
||||
#include "soc/soc_caps.h"
|
||||
#include "hal/gpio_hal.h"
|
||||
#include "hal/uart_ll.h"
|
||||
#include "esp_private/periph_ctrl.h"
|
||||
#include "driver/gpio.h"
|
||||
#include "driver/i2c_master.h"
|
||||
#include "driver/i2c_slave.h"
|
||||
#include "esp_rom_gpio.h"
|
||||
#include "esp_log.h"
|
||||
#include "test_utils.h"
|
||||
#include "test_board.h"
|
||||
|
||||
#define DATA_LENGTH 100
|
||||
|
||||
static QueueHandle_t s_receive_queue;
|
||||
|
||||
TEST_CASE("LP I2C initialize on i2c slave", "[i2c]")
|
||||
{
|
||||
i2c_slave_config_t i2c_slv_config = {
|
||||
.addr_bit_len = I2C_ADDR_BIT_LEN_7,
|
||||
.clk_source = LP_I2C_SCLK_DEFAULT,
|
||||
.i2c_port = LP_I2C_NUM_0,
|
||||
.send_buf_depth = 256,
|
||||
.scl_io_num = LP_I2C_SCL_IO,
|
||||
.sda_io_num = LP_I2C_SDA_IO,
|
||||
.slave_addr = 0x58,
|
||||
};
|
||||
|
||||
i2c_slave_dev_handle_t slave_handle;
|
||||
TEST_ESP_ERR(ESP_ERR_NOT_SUPPORTED, i2c_new_slave_device(&i2c_slv_config, &slave_handle));
|
||||
}
|
||||
|
||||
#if CONFIG_IDF_TARGET_ESP32C6
|
||||
|
||||
TEST_CASE("LP I2C initialize with wrong IO", "[i2c]")
|
||||
{
|
||||
i2c_master_bus_config_t i2c_mst_config = {
|
||||
.lp_source_clk = LP_I2C_SCLK_DEFAULT,
|
||||
.i2c_port = LP_I2C_NUM_0,
|
||||
.scl_io_num = 5,
|
||||
.sda_io_num = 6,
|
||||
.flags.enable_internal_pullup = true,
|
||||
};
|
||||
i2c_master_bus_handle_t bus_handle;
|
||||
|
||||
TEST_ESP_ERR(ESP_ERR_INVALID_ARG, i2c_new_master_bus(&i2c_mst_config, &bus_handle));
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
static IRAM_ATTR bool test_i2c_rx_done_callback(i2c_slave_dev_handle_t channel, const i2c_slave_rx_done_event_data_t *edata, void *user_data)
|
||||
{
|
||||
BaseType_t high_task_wakeup = pdFALSE;
|
||||
QueueHandle_t receive_queue = (QueueHandle_t)user_data;
|
||||
xQueueSendFromISR(receive_queue, edata, &high_task_wakeup);
|
||||
return high_task_wakeup == pdTRUE;
|
||||
}
|
||||
|
||||
static void lp_i2c_master_write_test(void)
|
||||
{
|
||||
uint8_t data_wr[DATA_LENGTH] = { 0 };
|
||||
int i;
|
||||
|
||||
i2c_master_bus_config_t i2c_mst_config = {
|
||||
.lp_source_clk = LP_I2C_SCLK_DEFAULT,
|
||||
.i2c_port = LP_I2C_NUM_0,
|
||||
.scl_io_num = LP_I2C_SCL_IO,
|
||||
.sda_io_num = LP_I2C_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));
|
||||
|
||||
i2c_device_config_t dev_cfg = {
|
||||
.dev_addr_length = I2C_ADDR_BIT_LEN_7,
|
||||
.device_address = 0x58,
|
||||
.scl_speed_hz = 100000,
|
||||
};
|
||||
|
||||
i2c_master_dev_handle_t dev_handle;
|
||||
TEST_ESP_OK(i2c_master_bus_add_device(bus_handle, &dev_cfg, &dev_handle));
|
||||
|
||||
unity_wait_for_signal("i2c slave init finish");
|
||||
|
||||
unity_send_signal("master write");
|
||||
for (i = 0; i < DATA_LENGTH; i++) {
|
||||
data_wr[i] = i;
|
||||
}
|
||||
|
||||
disp_buf(data_wr, i);
|
||||
TEST_ESP_OK(i2c_master_transmit(dev_handle, data_wr, DATA_LENGTH, -1));
|
||||
unity_wait_for_signal("ready to delete");
|
||||
TEST_ESP_OK(i2c_master_bus_rm_device(dev_handle));
|
||||
|
||||
TEST_ESP_OK(i2c_del_master_bus(bus_handle));
|
||||
}
|
||||
|
||||
static void hp_i2c_slave_read_test(void)
|
||||
{
|
||||
uint8_t data_rd[DATA_LENGTH] = {0};
|
||||
|
||||
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 = LP_I2C_SCL_IO,
|
||||
.sda_io_num = LP_I2C_SDA_IO,
|
||||
.slave_addr = 0x58,
|
||||
};
|
||||
|
||||
i2c_slave_dev_handle_t slave_handle;
|
||||
TEST_ESP_OK(i2c_new_slave_device(&i2c_slv_config, &slave_handle));
|
||||
|
||||
s_receive_queue = xQueueCreate(1, sizeof(i2c_slave_rx_done_event_data_t));
|
||||
i2c_slave_event_callbacks_t cbs = {
|
||||
.on_recv_done = test_i2c_rx_done_callback,
|
||||
};
|
||||
ESP_ERROR_CHECK(i2c_slave_register_event_callbacks(slave_handle, &cbs, s_receive_queue));
|
||||
|
||||
i2c_slave_rx_done_event_data_t rx_data;
|
||||
TEST_ESP_OK(i2c_slave_receive(slave_handle, data_rd, DATA_LENGTH));
|
||||
|
||||
unity_send_signal("i2c slave init finish");
|
||||
|
||||
unity_wait_for_signal("master write");
|
||||
xQueueReceive(s_receive_queue, &rx_data, pdMS_TO_TICKS(10000));
|
||||
disp_buf(data_rd, DATA_LENGTH);
|
||||
for (int i = 0; i < DATA_LENGTH; i++) {
|
||||
TEST_ASSERT(data_rd[i] == i);
|
||||
}
|
||||
vQueueDelete(s_receive_queue);
|
||||
unity_send_signal("ready to delete");
|
||||
TEST_ESP_OK(i2c_del_slave_device(slave_handle));
|
||||
}
|
||||
|
||||
TEST_CASE_MULTIPLE_DEVICES("LP_I2C master write slave test", "[i2c][test_env=generic_multi_device][timeout=150]", lp_i2c_master_write_test, hp_i2c_slave_read_test);
|
|
@ -77,6 +77,14 @@ typedef enum {
|
|||
#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).
|
||||
|
||||
// Record for Pins usage logs
|
||||
|
||||
#define LP_I2C_SCL_PIN_ERR_LOG "SCL pin can only be configured as GPIO#7"
|
||||
#define LP_I2C_SDA_PIN_ERR_LOG "SDA pin can only be configured as GPIO#6"
|
||||
|
||||
#define LP_I2C_SDA_IOMUX_PAD 6
|
||||
#define LP_I2C_SCL_IOMUX_PAD 7
|
||||
|
||||
// I2C sleep retention module
|
||||
#define I2C_SLEEP_RETENTION_MODULE(i2c_num) (SLEEP_RETENTION_MODULE_I2C0)
|
||||
|
||||
|
@ -619,7 +627,7 @@ static inline void i2c_ll_get_stop_timing(i2c_dev_t *hw, int *setup_time, int *h
|
|||
*
|
||||
* @param hw Beginning address of the peripheral registers
|
||||
* @param ptr Pointer to data buffer
|
||||
* @param len Amount of data needs to be writen
|
||||
* @param len Amount of data needs to be written
|
||||
*
|
||||
* @return None.
|
||||
*/
|
||||
|
@ -654,7 +662,7 @@ static inline void i2c_ll_read_rxfifo(i2c_dev_t *hw, uint8_t *ptr, uint8_t len)
|
|||
* @param hw Beginning address of the peripheral registers
|
||||
* @param ram_offset Offset value of I2C RAM.
|
||||
* @param ptr Pointer to data buffer
|
||||
* @param len Amount of data needs to be writen
|
||||
* @param len Amount of data needs to be written
|
||||
*/
|
||||
static inline void i2c_ll_write_by_nonfifo(i2c_dev_t *hw, uint8_t ram_offset, const uint8_t *ptr, uint8_t len)
|
||||
{
|
||||
|
@ -754,7 +762,7 @@ static inline void i2c_ll_master_clr_bus(i2c_dev_t *hw, uint32_t slave_pulses)
|
|||
hw->scl_sp_conf.scl_rst_slv_num = slave_pulses;
|
||||
hw->scl_sp_conf.scl_rst_slv_en = 1;
|
||||
hw->ctr.conf_upgate = 1;
|
||||
// hardward will clear scl_rst_slv_en after sending SCL pulses,
|
||||
// hardware will clear scl_rst_slv_en after sending SCL pulses,
|
||||
// and we should set conf_upgate bit to synchronize register value.
|
||||
while (hw->scl_sp_conf.scl_rst_slv_en);
|
||||
hw->ctr.conf_upgate = 1;
|
||||
|
@ -1003,7 +1011,7 @@ typedef enum {
|
|||
* @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 high_period The I2C SCL height 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.
|
||||
*
|
||||
|
@ -1191,7 +1199,7 @@ static inline void i2c_ll_slave_disable_rx_it(i2c_dev_t *hw)
|
|||
* @brief Configure I2C SCL timing
|
||||
*
|
||||
* @param hw Beginning address of the peripheral registers
|
||||
* @param hight_period The I2C SCL hight period (in core clock cycle, hight_period > 2)
|
||||
* @param hight_period The I2C SCL height period (in core clock cycle, hight_period > 2)
|
||||
* @param low_period The I2C SCL low period (in core clock cycle, low_period > 1)
|
||||
*
|
||||
* @return None.
|
||||
|
|
|
@ -21,9 +21,9 @@ extern "C" {
|
|||
*/
|
||||
typedef enum {
|
||||
I2C_NUM_0 = 0, /*!< I2C port 0 */
|
||||
#if SOC_I2C_NUM >= 2
|
||||
#if SOC_HP_I2C_NUM >= 2
|
||||
I2C_NUM_1, /*!< I2C port 1 */
|
||||
#endif /* SOC_I2C_NUM >= 2 */
|
||||
#endif /* SOC_HP_I2C_NUM >= 2 */
|
||||
#if SOC_LP_I2C_NUM >= 1
|
||||
LP_I2C_NUM_0, /*< LP_I2C port 0 */
|
||||
#endif /* SOC_LP_I2C_NUM >= 1 */
|
||||
|
@ -44,9 +44,9 @@ typedef enum {
|
|||
* @brief Data structure for calculating I2C bus timing.
|
||||
*/
|
||||
typedef struct {
|
||||
uint16_t clkm_div; /*!< I2C core clock devider */
|
||||
uint16_t clkm_div; /*!< I2C core clock divider */
|
||||
uint16_t scl_low; /*!< I2C scl low period */
|
||||
uint16_t scl_high; /*!< I2C scl hight period */
|
||||
uint16_t scl_high; /*!< I2C scl high period */
|
||||
uint16_t scl_wait_high; /*!< I2C scl wait_high period */
|
||||
uint16_t sda_hold; /*!< I2C scl low period */
|
||||
uint16_t sda_sample; /*!< I2C sda sample time */
|
||||
|
@ -103,6 +103,14 @@ typedef enum {
|
|||
* @brief I2C group clock source
|
||||
*/
|
||||
typedef soc_periph_i2c_clk_src_t i2c_clock_source_t;
|
||||
|
||||
#if SOC_LP_I2C_SUPPORTED
|
||||
/**
|
||||
* @brief LP_UART source clock
|
||||
*/
|
||||
typedef soc_periph_lp_i2c_clk_src_t lp_i2c_clock_source_t;
|
||||
#endif
|
||||
|
||||
#else
|
||||
/**
|
||||
* @brief Default type
|
||||
|
|
|
@ -355,6 +355,10 @@ config SOC_I2C_NUM
|
|||
int
|
||||
default 2
|
||||
|
||||
config SOC_HP_I2C_NUM
|
||||
int
|
||||
default 2
|
||||
|
||||
config SOC_I2C_FIFO_LEN
|
||||
int
|
||||
default 32
|
||||
|
|
|
@ -193,7 +193,8 @@
|
|||
|
||||
/*-------------------------- I2C CAPS ----------------------------------------*/
|
||||
// ESP32 has 2 I2C
|
||||
#define SOC_I2C_NUM (2)
|
||||
#define SOC_I2C_NUM (2U)
|
||||
#define SOC_HP_I2C_NUM (2)
|
||||
|
||||
#define SOC_I2C_FIFO_LEN (32) /*!< I2C hardware FIFO depth */
|
||||
#define SOC_I2C_CMD_REG_NUM (16) /*!< Number of I2C command registers */
|
||||
|
|
|
@ -327,6 +327,10 @@ config SOC_I2C_NUM
|
|||
int
|
||||
default 1
|
||||
|
||||
config SOC_HP_I2C_NUM
|
||||
int
|
||||
default 1
|
||||
|
||||
config SOC_I2C_FIFO_LEN
|
||||
int
|
||||
default 16
|
||||
|
|
|
@ -148,6 +148,7 @@
|
|||
/*-------------------------- I2C CAPS ----------------------------------------*/
|
||||
// ESP32-C2 has 1 I2C
|
||||
#define SOC_I2C_NUM (1U)
|
||||
#define SOC_HP_I2C_NUM (1U)
|
||||
|
||||
#define SOC_I2C_FIFO_LEN (16) /*!< I2C hardware FIFO depth */
|
||||
#define SOC_I2C_CMD_REG_NUM (8) /*!< Number of I2C command registers */
|
||||
|
|
|
@ -419,6 +419,10 @@ config SOC_I2C_NUM
|
|||
int
|
||||
default 1
|
||||
|
||||
config SOC_HP_I2C_NUM
|
||||
int
|
||||
default 1
|
||||
|
||||
config SOC_I2C_FIFO_LEN
|
||||
int
|
||||
default 32
|
||||
|
|
|
@ -186,6 +186,7 @@
|
|||
/*-------------------------- I2C CAPS ----------------------------------------*/
|
||||
// ESP32-C3 has 1 I2C
|
||||
#define SOC_I2C_NUM (1U)
|
||||
#define SOC_HP_I2C_NUM (1U)
|
||||
|
||||
#define SOC_I2C_FIFO_LEN (32) /*!< I2C hardware FIFO depth */
|
||||
#define SOC_I2C_CMD_REG_NUM (8) /*!< Number of I2C command registers */
|
||||
|
|
|
@ -263,6 +263,10 @@ config SOC_I2C_NUM
|
|||
int
|
||||
default 1
|
||||
|
||||
config SOC_HP_I2C_NUM
|
||||
int
|
||||
default 1
|
||||
|
||||
config SOC_I2C_FIFO_LEN
|
||||
int
|
||||
default 32
|
||||
|
|
|
@ -234,7 +234,8 @@
|
|||
|
||||
/*-------------------------- I2C CAPS ----------------------------------------*/
|
||||
// ESP32-C5 has 1 I2C
|
||||
#define SOC_I2C_NUM (1UL)
|
||||
#define SOC_I2C_NUM (1U)
|
||||
#define SOC_HP_I2C_NUM (1U)
|
||||
|
||||
#define SOC_I2C_FIFO_LEN (32) /*!< I2C hardware FIFO depth */
|
||||
#define SOC_I2C_CMD_REG_NUM (8) /*!< Number of I2C command registers */
|
||||
|
|
|
@ -131,6 +131,10 @@ config SOC_I2C_NUM
|
|||
int
|
||||
default 1
|
||||
|
||||
config SOC_HP_I2C_NUM
|
||||
int
|
||||
default 1
|
||||
|
||||
config SOC_LEDC_SUPPORT_PLL_DIV_CLOCK
|
||||
bool
|
||||
default y
|
||||
|
|
|
@ -208,7 +208,7 @@
|
|||
// Support to hold a single digital I/O when the digital domain is powered off
|
||||
#define SOC_GPIO_SUPPORT_HOLD_SINGLE_IO_IN_DSLP (1)
|
||||
|
||||
// The Clock Out singnal is route to the pin by GPIO matrix
|
||||
// The Clock Out signal is route to the pin by GPIO matrix
|
||||
// #define SOC_GPIO_CLOCKOUT_BY_GPIO_MATRIX (1)
|
||||
|
||||
/*-------------------------- RTCIO CAPS --------------------------------------*/
|
||||
|
@ -227,7 +227,8 @@
|
|||
|
||||
/*-------------------------- I2C CAPS ----------------------------------------*/
|
||||
// ESP32-C5 has 1 I2C
|
||||
#define SOC_I2C_NUM (1UL)
|
||||
#define SOC_I2C_NUM (1U)
|
||||
#define SOC_HP_I2C_NUM (1U)
|
||||
|
||||
// #define SOC_I2C_FIFO_LEN (32) /*!< I2C hardware FIFO depth */
|
||||
// #define SOC_I2C_CMD_REG_NUM (8) /*!< Number of I2C command registers */
|
||||
|
@ -501,7 +502,7 @@
|
|||
// #define SOC_PM_SUPPORT_BEACON_WAKEUP (1)
|
||||
// #define SOC_PM_SUPPORT_BT_WAKEUP (1)
|
||||
// #define SOC_PM_SUPPORT_EXT1_WAKEUP (1)
|
||||
// #define SOC_PM_SUPPORT_EXT1_WAKEUP_MODE_PER_PIN (1) /*!<Supports one bit per pin to configue the EXT1 trigger level */
|
||||
// #define SOC_PM_SUPPORT_EXT1_WAKEUP_MODE_PER_PIN (1) /*!<Supports one bit per pin to configure the EXT1 trigger level */
|
||||
#define SOC_PM_SUPPORT_CPU_PD (1)
|
||||
#define SOC_PM_SUPPORT_MODEM_PD (1)
|
||||
#define SOC_PM_SUPPORT_XTAL32K_PD (1)
|
||||
|
|
|
@ -9,6 +9,8 @@
|
|||
#include "soc/regdma.h"
|
||||
#include "soc/i2c_reg.h"
|
||||
|
||||
#define LP_I2C_MUX_FUNC (1)
|
||||
|
||||
/*
|
||||
Bunch of constants for every I2C peripheral: GPIO signals, irqs, hw addr of registers etc
|
||||
*/
|
||||
|
@ -21,6 +23,15 @@ const i2c_signal_conn_t i2c_periph_signal[SOC_I2C_NUM] = {
|
|||
.irq = ETS_I2C_EXT0_INTR_SOURCE,
|
||||
.module = PERIPH_I2C0_MODULE,
|
||||
},
|
||||
{
|
||||
.sda_out_sig = 0,
|
||||
.sda_in_sig = 0,
|
||||
.scl_out_sig = 0,
|
||||
.scl_in_sig = 0,
|
||||
.iomux_func = LP_I2C_MUX_FUNC,
|
||||
.irq = ETS_LP_I2C_INTR_SOURCE,
|
||||
.module = PERIPH_LP_I2C0_MODULE,
|
||||
},
|
||||
};
|
||||
|
||||
// I2C sleep retention entries
|
||||
|
@ -48,6 +59,6 @@ static const regdma_entries_config_t i2c0_regs_retention[] = {
|
|||
.owner = ENTRY(0) | ENTRY(2) }, \
|
||||
};
|
||||
|
||||
const i2c_reg_ctx_link_t i2c_regs_retention[SOC_I2C_NUM] = {
|
||||
const i2c_reg_ctx_link_t i2c_regs_retention[SOC_HP_I2C_NUM] = {
|
||||
{i2c0_regs_retention, ARRAY_SIZE(i2c0_regs_retention)},
|
||||
};
|
||||
|
|
|
@ -552,6 +552,10 @@ config SOC_DEDIC_PERIPH_ALWAYS_ENABLE
|
|||
default y
|
||||
|
||||
config SOC_I2C_NUM
|
||||
int
|
||||
default 2
|
||||
|
||||
config SOC_HP_I2C_NUM
|
||||
int
|
||||
default 1
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
|
||||
* SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
|
|
@ -233,7 +233,8 @@
|
|||
|
||||
/*-------------------------- I2C CAPS ----------------------------------------*/
|
||||
// ESP32-C6 has 1 I2C
|
||||
#define SOC_I2C_NUM (1U)
|
||||
#define SOC_I2C_NUM (2U) // I2C_NUM = HP_I2C + LP_I2C
|
||||
#define SOC_HP_I2C_NUM (1U)
|
||||
|
||||
#define SOC_I2C_FIFO_LEN (32) /*!< I2C hardware FIFO depth */
|
||||
#define SOC_I2C_CMD_REG_NUM (8) /*!< Number of I2C command registers */
|
||||
|
|
|
@ -219,6 +219,10 @@ config SOC_I2C_NUM
|
|||
int
|
||||
default 1
|
||||
|
||||
config SOC_HP_I2C_NUM
|
||||
int
|
||||
default 1
|
||||
|
||||
config SOC_I2C_FIFO_LEN
|
||||
int
|
||||
default 32
|
||||
|
|
|
@ -233,6 +233,7 @@
|
|||
/*-------------------------- I2C CAPS ----------------------------------------*/
|
||||
// ESP32-C61 has 1 I2C
|
||||
#define SOC_I2C_NUM (1U)
|
||||
#define SOC_HP_I2C_NUM (1U)
|
||||
|
||||
#define SOC_I2C_FIFO_LEN (32) /*!< I2C hardware FIFO depth */
|
||||
#define SOC_I2C_CMD_REG_NUM (8) /*!< Number of I2C command registers */
|
||||
|
|
|
@ -72,7 +72,7 @@ static const regdma_entries_config_t i2c1_regs_retention[] = {
|
|||
.owner = ENTRY(0) | ENTRY(2) }, \
|
||||
};
|
||||
|
||||
const i2c_reg_ctx_link_t i2c_regs_retention[SOC_I2C_NUM] = {
|
||||
const i2c_reg_ctx_link_t i2c_regs_retention[SOC_HP_I2C_NUM] = {
|
||||
{i2c0_regs_retention, ARRAY_SIZE(i2c0_regs_retention)},
|
||||
{i2c1_regs_retention, ARRAY_SIZE(i2c1_regs_retention)},
|
||||
};
|
||||
|
|
|
@ -555,6 +555,10 @@ config SOC_I2C_NUM
|
|||
int
|
||||
default 2
|
||||
|
||||
config SOC_HP_I2C_NUM
|
||||
int
|
||||
default 2
|
||||
|
||||
config SOC_I2C_FIFO_LEN
|
||||
int
|
||||
default 32
|
||||
|
|
|
@ -236,6 +236,7 @@
|
|||
/*-------------------------- I2C CAPS ----------------------------------------*/
|
||||
// ESP32-H2 has 2 I2C
|
||||
#define SOC_I2C_NUM (2U)
|
||||
#define SOC_HP_I2C_NUM (2U)
|
||||
|
||||
#define SOC_I2C_FIFO_LEN (32) /*!< I2C hardware FIFO depth */
|
||||
#define SOC_I2C_CMD_REG_NUM (8) /*!< Number of I2C command registers */
|
||||
|
|
|
@ -1,11 +1,12 @@
|
|||
/*
|
||||
* SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD
|
||||
* SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include "soc/i2c_periph.h"
|
||||
#include "soc/gpio_sig_map.h"
|
||||
#include "soc/lp_gpio_sig_map.h"
|
||||
|
||||
/*
|
||||
Bunch of constants for every I2C peripheral: GPIO signals, irqs, hw addr of registers etc
|
||||
|
@ -27,4 +28,12 @@ const i2c_signal_conn_t i2c_periph_signal[SOC_I2C_NUM] = {
|
|||
.irq = ETS_I2C1_INTR_SOURCE,
|
||||
.module = PERIPH_I2C1_MODULE,
|
||||
},
|
||||
{
|
||||
.sda_out_sig = LP_I2C_SDA_PAD_OUT_IDX,
|
||||
.sda_in_sig = LP_I2C_SDA_PAD_IN_IDX,
|
||||
.scl_out_sig = LP_I2C_SCL_PAD_OUT_IDX,
|
||||
.scl_in_sig = LP_I2C_SCL_PAD_IN_IDX,
|
||||
.irq = ETS_LP_I2C_INTR_SOURCE,
|
||||
.module = PERIPH_LP_I2C0_MODULE,
|
||||
},
|
||||
};
|
||||
|
|
|
@ -600,6 +600,10 @@ config SOC_ANA_CMPR_SUPPORT_ETM
|
|||
default y
|
||||
|
||||
config SOC_I2C_NUM
|
||||
int
|
||||
default 3
|
||||
|
||||
config SOC_HP_I2C_NUM
|
||||
int
|
||||
default 2
|
||||
|
||||
|
|
|
@ -256,7 +256,8 @@
|
|||
|
||||
/*-------------------------- I2C CAPS ----------------------------------------*/
|
||||
// ESP32-P4 has 2 I2Cs
|
||||
#define SOC_I2C_NUM (2U)
|
||||
#define SOC_I2C_NUM (3U) // I2C_NUM = HP_I2C + LP_I2C
|
||||
#define SOC_HP_I2C_NUM (2U)
|
||||
|
||||
#define SOC_I2C_FIFO_LEN (32) /*!< I2C hardware FIFO depth */
|
||||
#define SOC_I2C_CMD_REG_NUM (8) /*!< Number of I2C command registers */
|
||||
|
|
|
@ -423,6 +423,10 @@ config SOC_I2C_NUM
|
|||
int
|
||||
default 2
|
||||
|
||||
config SOC_HP_I2C_NUM
|
||||
int
|
||||
default 2
|
||||
|
||||
config SOC_I2C_FIFO_LEN
|
||||
int
|
||||
default 32
|
||||
|
|
|
@ -189,7 +189,8 @@
|
|||
|
||||
/*-------------------------- I2C CAPS ----------------------------------------*/
|
||||
// ESP32-S2 has 2 I2C
|
||||
#define SOC_I2C_NUM (2)
|
||||
#define SOC_I2C_NUM (2U)
|
||||
#define SOC_HP_I2C_NUM (2U)
|
||||
|
||||
#define SOC_I2C_FIFO_LEN (32) /*!< I2C hardware FIFO depth */
|
||||
#define SOC_I2C_CMD_REG_NUM (16) /*!< Number of I2C command registers */
|
||||
|
|
|
@ -491,6 +491,10 @@ config SOC_I2C_NUM
|
|||
int
|
||||
default 2
|
||||
|
||||
config SOC_HP_I2C_NUM
|
||||
int
|
||||
default 2
|
||||
|
||||
config SOC_I2C_FIFO_LEN
|
||||
int
|
||||
default 32
|
||||
|
|
|
@ -195,7 +195,8 @@
|
|||
|
||||
/*-------------------------- I2C CAPS ----------------------------------------*/
|
||||
// ESP32-S3 has 2 I2C
|
||||
#define SOC_I2C_NUM (2)
|
||||
#define SOC_I2C_NUM (2U)
|
||||
#define SOC_HP_I2C_NUM (2U)
|
||||
|
||||
#define SOC_I2C_FIFO_LEN (32) /*!< I2C hardware FIFO depth */
|
||||
#define SOC_I2C_CMD_REG_NUM (8) /*!< Number of I2C command registers */
|
||||
|
|
|
@ -25,6 +25,7 @@ typedef struct {
|
|||
const uint8_t sda_in_sig;
|
||||
const uint8_t scl_out_sig;
|
||||
const uint8_t scl_in_sig;
|
||||
const uint8_t iomux_func;
|
||||
const uint8_t irq;
|
||||
const periph_module_t module;
|
||||
} i2c_signal_conn_t;
|
||||
|
@ -37,7 +38,7 @@ typedef struct {
|
|||
uint32_t link_num;
|
||||
} i2c_reg_ctx_link_t;
|
||||
|
||||
extern const i2c_reg_ctx_link_t i2c_regs_retention[SOC_I2C_NUM];
|
||||
extern const i2c_reg_ctx_link_t i2c_regs_retention[SOC_HP_I2C_NUM];
|
||||
#endif
|
||||
#endif // SOC_I2C_SUPPORTED
|
||||
|
||||
|
|
|
@ -6,7 +6,13 @@ Introduction
|
|||
|
||||
I2C is a serial, synchronous, multi-device, half-duplex communication protocol that allows co-existence of multiple masters and slaves on the same bus. I2C uses two bidirectional open-drain lines: serial data line (SDA) and serial clock line (SCL), pulled up by resistors.
|
||||
|
||||
{IDF_TARGET_NAME} has {IDF_TARGET_SOC_I2C_NUM} I2C controller (also called port), responsible for handling communication on the I2C bus. A single I2C controller can be a master or a slave.
|
||||
{IDF_TARGET_NAME} has {IDF_TARGET_SOC_HP_I2C_NUM} I2C controller (also called port), responsible for handling communication on the I2C bus. A single I2C controller can be a master or a slave.
|
||||
|
||||
.. only:: SOC_LP_I2C_SUPPORTED
|
||||
|
||||
Additionally, the {IDF_TARGET_NAME} chip has 1 low-power (LP) I2C controller. It is the cut-down version of regular I2C. Usually, the LP I2C controller only support basic I2C functionality with a much smaller RAM size, and does not support slave mode. For a full list of difference between HP I2C and LP I2C, please refer to the *{IDF_TARGET_NAME} Technical Reference Manual* > *I2C Controller (I2C)* > *Features* [`PDF <{IDF_TARGET_TRM_EN_URL}#i2c>`__].
|
||||
|
||||
You can use LP I2C peripheral when HP I2C is not sufficient for users' usage. But please note again the LP I2C does not support all HP I2C functions. Please read docs before you use it.
|
||||
|
||||
Typically, an I2C slave device has a 7-bit address or 10-bit address. {IDF_TARGET_NAME} supports both I2C Standard-mode (Sm) and Fast-mode (Fm) which can go up to 100KHz and 400KHz respectively.
|
||||
|
||||
|
@ -134,6 +140,38 @@ Once the :cpp:type:`i2c_device_config_t` structure is populated with mandatory p
|
|||
i2c_master_dev_handle_t dev_handle;
|
||||
ESP_ERROR_CHECK(i2c_master_bus_add_device(bus_handle, &dev_cfg, &dev_handle));
|
||||
|
||||
.. only:: SOC_LP_I2C_SUPPORTED
|
||||
|
||||
Install I2C master bus with LP I2C Peripheral
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Install I2C master bus with LP I2C peripheral is almost as same as how HP I2C peripheral is installed. However, there are still some difference user should take focus on including IOs, clock sources, i2c port number, etc. Following code will show you how to install I2C master bus with LP_I2C.
|
||||
|
||||
.. code:: c
|
||||
|
||||
#include "driver/i2c_master.h"
|
||||
|
||||
i2c_master_bus_config_t i2c_mst_config = {
|
||||
.clk_source = LP_I2C_SCLK_DEFAULT, // clock source for LP i2c, might different from HP I2C
|
||||
.i2c_port = LP_I2C_NUM_0, // Assign to LP I2C port
|
||||
.scl_io_num = 7, // SCL IO number. Please refer to technical reference manual
|
||||
.sda_io_num = 6, // SDA IO number. Please refer to technical reference manual
|
||||
.glitch_ignore_cnt = 7,
|
||||
.flags.enable_internal_pullup = true,
|
||||
};
|
||||
|
||||
i2c_master_bus_handle_t bus_handle;
|
||||
ESP_ERROR_CHECK(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,
|
||||
};
|
||||
|
||||
i2c_master_dev_handle_t dev_handle;
|
||||
ESP_ERROR_CHECK(i2c_master_bus_add_device(bus_handle, &dev_cfg, &dev_handle));
|
||||
|
||||
Uninstall I2C master bus and device
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
|
@ -292,7 +330,7 @@ Simple example for writing and reading from slave:
|
|||
ESP_ERROR_CHECK(i2c_master_bus_add_device(I2C_PORT_NUM_0, &dev_cfg, &dev_handle));
|
||||
uint8_t buf[20] = {0x20};
|
||||
uint8_t buffer[2];
|
||||
ESP_ERROR_CHECK(i2c_master_transmit_receive(i2c_bus_handle, buf, sizeof(buf), buffer, 2, -1));
|
||||
ESP_ERROR_CHECK(i2c_master_transmit_receive(dev_handle, buf, sizeof(buf), buffer, 2, -1));
|
||||
|
||||
I2C Master Probe
|
||||
~~~~~~~~~~~~~~~~
|
||||
|
|
Ładowanie…
Reference in New Issue