Merge branch 'feat/i2c_port_handle_func_v5.3' into 'release/v5.3'

feat(i2c_master): Add an api for retrieveing handle via port (backport v5.3)

See merge request espressif/esp-idf!34438
This commit is contained in:
morris
2024-10-28 12:44:33 +08:00
7 changed files with 92 additions and 6 deletions

View File

@@ -127,7 +127,7 @@ static esp_err_t s_i2c_bus_handle_acquire(i2c_port_num_t port_num, i2c_bus_handl
return ret;
}
static bool i2c_bus_occupied(i2c_port_num_t port_num)
bool i2c_bus_occupied(i2c_port_num_t port_num)
{
return s_i2c_platform.buses[port_num] != NULL;
}
@@ -351,8 +351,8 @@ static esp_err_t s_lp_i2c_pins_config(i2c_bus_handle_t handle)
#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);
lp_gpio_connect_out_signal(handle->sda_num, i2c_periph_signal[port_id].sda_out_sig, 0, 0);
lp_gpio_connect_in_signal(handle->sda_num, i2c_periph_signal[port_id].sda_in_sig, 0);
#endif
rtc_gpio_init(handle->scl_num);
@@ -366,8 +366,8 @@ static esp_err_t s_lp_i2c_pins_config(i2c_bus_handle_t handle)
#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);
lp_gpio_connect_out_signal(handle->scl_num, i2c_periph_signal[port_id].scl_out_sig, 0, 0);
lp_gpio_connect_in_signal(handle->scl_num, i2c_periph_signal[port_id].scl_in_sig, 0);
#endif
return ESP_OK;

View File

@@ -47,6 +47,14 @@ static const char *TAG = "i2c.master";
#endif
#define I2C_CLR_BUS_TIMEOUT_MS (50) // 50ms is sufficient for clearing the bus
// Use the platform to same master bus handle
typedef struct i2c_master_bus_platform_t i2c_master_bus_platform_t;
struct i2c_master_bus_platform_t {
i2c_master_bus_handle_t handle[SOC_I2C_NUM];
};
static i2c_master_bus_platform_t s_platform;
static esp_err_t s_i2c_master_clear_bus(i2c_bus_handle_t handle)
{
@@ -813,7 +821,7 @@ static esp_err_t s_i2c_asynchronous_transaction(i2c_master_dev_handle_t i2c_dev,
// Clear unused memory
uint8_t unused_dim = I2C_STATIC_OPERATION_ARRAY_MAX - ops_dim;
if (unused_dim != 0) {
memset(&i2c_master->i2c_async_ops[i2c_master->ops_prepare_idx] + sizeof(i2c_operation_t) * ops_dim, 0, sizeof(i2c_operation_t) * unused_dim);
memset(&i2c_master->i2c_async_ops[i2c_master->ops_prepare_idx][ops_dim], 0, sizeof(i2c_operation_t) * unused_dim);
}
// Record current operation and feed to transaction queue.
ops_current = &i2c_master->i2c_async_ops[i2c_master->ops_prepare_idx][0];
@@ -994,6 +1002,7 @@ esp_err_t i2c_new_master_bus(const i2c_master_bus_config_t *bus_config, i2c_mast
xSemaphoreGive(i2c_master->cmd_semphr);
*ret_bus_handle = i2c_master;
s_platform.handle[i2c_port_num] = i2c_master;
return ESP_OK;
err:
@@ -1080,6 +1089,18 @@ esp_err_t i2c_master_bus_reset(i2c_master_bus_handle_t bus_handle)
return ESP_OK;
}
esp_err_t i2c_master_get_bus_handle(i2c_port_num_t port_num, i2c_master_bus_handle_t *ret_handle)
{
ESP_RETURN_ON_FALSE((port_num < SOC_I2C_NUM), ESP_ERR_INVALID_ARG, TAG, "invalid i2c port number");
if (i2c_bus_occupied(port_num) == false) {
ESP_LOGE(TAG, "this port has not been initialized, please initialize it first");
return ESP_ERR_INVALID_STATE;
} else {
*ret_handle = s_platform.handle[port_num];
}
return ESP_OK;
}
esp_err_t i2c_master_transmit(i2c_master_dev_handle_t i2c_dev, const uint8_t *write_buffer, size_t write_size, int xfer_timeout_ms)
{
ESP_RETURN_ON_FALSE(i2c_dev != NULL, ESP_ERR_INVALID_ARG, TAG, "i2c handle not initialized");

View File

@@ -252,6 +252,14 @@ esp_err_t i2c_select_periph_clock(i2c_bus_handle_t handle, soc_module_clk_t clk_
*/
esp_err_t i2c_common_set_pins(i2c_bus_handle_t handle);
/**
* @brief Check whether bus is acquired
*
* @param port_num number of port
* @return true if the bus is occupied, false if the bus is not occupied.
*/
bool i2c_bus_occupied(i2c_port_num_t port_num);
#ifdef __cplusplus
}
#endif

View File

@@ -231,6 +231,22 @@ esp_err_t i2c_master_bus_reset(i2c_master_bus_handle_t bus_handle);
*/
esp_err_t i2c_master_bus_wait_all_done(i2c_master_bus_handle_t bus_handle, int timeout_ms);
/**
* @brief Retrieves the I2C master bus handle for a specified I2C port number.
*
* This function retrieves the I2C master bus handle for the
* given I2C port number. Please make sure the handle has already been initialized, and this
* function would simply returns the existing handle. Note that the returned handle still can't be used concurrently
*
* @param port_num I2C port number for which the handle is to be retrieved.
* @param ret_handle Pointer to a variable where the retrieved handle will be stored.
* @return
* - ESP_OK: Success. The handle is retrieved successfully.
* - ESP_ERR_INVALID_ARG: Invalid argument, such as invalid port number
* - ESP_ERR_INVALID_STATE: Invalid state, such as the I2C port is not initialized.
*/
esp_err_t i2c_master_get_bus_handle(i2c_port_num_t port_num, i2c_master_bus_handle_t *ret_handle);
#ifdef __cplusplus
}
#endif

View File

@@ -26,9 +26,14 @@ extern "C" {
#endif
#if SOC_LP_I2C_SUPPORTED
#if CONFIG_IDF_TARGET_ESP32P4
#define LP_I2C_SCL_IO 4
#define LP_I2C_SDA_IO 5
#else
#define LP_I2C_SCL_IO 7
#define LP_I2C_SDA_IO 6
#endif
#endif
#define ESP_SLAVE_ADDR 0x28 /*!< ESP_I2C slave address, you can set any 7bit value */
#define TEST_I2C_PORT 0

View File

@@ -345,3 +345,19 @@ TEST_CASE("I2C master transaction receive check nack return value", "[i2c]")
TEST_ESP_ERR(ESP_ERR_INVALID_STATE, i2c_master_receive(dev_handle, data_rd, DATA_LENGTH, -1));
_test_i2c_del_bus_device(bus_handle, dev_handle);
}
TEST_CASE("Test get handle with known port", "[i2c]")
{
i2c_master_bus_handle_t handle;
TEST_ESP_ERR(ESP_ERR_INVALID_ARG, i2c_master_get_bus_handle(10, &handle));
TEST_ESP_ERR(ESP_ERR_INVALID_STATE, i2c_master_get_bus_handle(0, &handle));
i2c_master_bus_handle_t bus_handle;
i2c_master_dev_handle_t dev_handle;
_test_i2c_new_bus_device(&bus_handle, &dev_handle);
TEST_ESP_OK(i2c_master_get_bus_handle(0, &handle));
// Check the handle retrieved is as same as original handle
TEST_ASSERT((uint32_t)bus_handle == (uint32_t)handle);
_test_i2c_del_bus_device(bus_handle, dev_handle);
}

View File

@@ -140,6 +140,26 @@ 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));
Get I2C master handle via port
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Given that i2c master handle has been initialized in some module(e.g. an audio module), an another module(e.g. a video module) is not convenient to reused the handle. We have a helper function, :cpp:func:`i2c_master_get_bus_handle` for getting the initialized handle via port. However, please make sure the handle has already been initialized ahead of time. Otherwise an error would be reported.
.. code:: c
// Source File 1
#include "driver/i2c_master.h"
i2c_master_bus_handle_t bus_handle;
i2c_master_bus_config_t i2c_mst_config = {
... // same as others
};
ESP_ERROR_CHECK(i2c_new_master_bus(&i2c_mst_config, &bus_handle));
// Source File 2
#include "driver/i2c_master.h"
i2c_master_bus_handle_t handle;
ESP_ERROR_CHECK(i2c_master_get_bus_handle(0, &handle));
.. only:: SOC_LP_I2C_SUPPORTED
Install I2C master bus with LP I2C Peripheral