mirror of
https://github.com/espressif/esp-idf.git
synced 2025-08-03 12:44:33 +02:00
Merge branch 'feat/customize_i2c_operation_transaction_v5.3' into 'release/v5.3'
feat(i2c): Add api for customize i2c transaction interface for un-standard i2c device (backport v5.3) See merge request espressif/esp-idf!37416
This commit is contained in:
@@ -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
|
||||
*/
|
||||
@@ -68,6 +68,7 @@ static const char *I2C_TAG = "i2c";
|
||||
#define I2C_CMD_USER_ALLOC_ERR_STR "i2c command link allocation error: the buffer provided is too small."
|
||||
#define I2C_TRANS_MODE_ERR_STR "i2c trans mode error"
|
||||
#define I2C_MODE_ERR_STR "i2c mode error"
|
||||
#define I2C_CLEAR_BUS_ERR_STR "clear bus error"
|
||||
#define I2C_SDA_IO_ERR_STR "sda gpio number error"
|
||||
#define I2C_SCL_IO_ERR_STR "scl gpio number error"
|
||||
#define I2C_SCL_SDA_EQUAL_ERR_STR "scl and sda gpio numbers are the same"
|
||||
@@ -126,6 +127,8 @@ static const char *I2C_TAG = "i2c";
|
||||
#define I2C_RCC_ATOMIC()
|
||||
#endif
|
||||
|
||||
#define I2C_CLR_BUS_TIMEOUT_MS (50) // 50ms is sufficient for clearing the bus
|
||||
|
||||
/**
|
||||
* I2C bus are defined in the header files, let's check that the values are correct
|
||||
*/
|
||||
@@ -657,6 +660,7 @@ esp_err_t i2c_get_data_mode(i2c_port_t i2c_num, i2c_trans_mode_t *tx_trans_mode,
|
||||
**/
|
||||
static esp_err_t i2c_master_clear_bus(i2c_port_t i2c_num)
|
||||
{
|
||||
esp_err_t ret = ESP_OK;
|
||||
#if !SOC_I2C_SUPPORT_HW_CLR_BUS
|
||||
const int scl_half_period = I2C_CLR_BUS_HALF_PERIOD_US; // use standard 100kHz data rate
|
||||
int i = 0;
|
||||
@@ -685,11 +689,22 @@ static esp_err_t i2c_master_clear_bus(i2c_port_t i2c_num)
|
||||
i2c_set_pin(i2c_num, sda_io, scl_io, 1, 1, I2C_MODE_MASTER);
|
||||
#else
|
||||
i2c_ll_master_clr_bus(i2c_context[i2c_num].hal.dev, I2C_CLR_BUS_SCL_NUM, true);
|
||||
// If the i2c master clear bus state machine got disturbed when working, it would go into error state.
|
||||
// The solution here is to use freertos tick counter to set a timeout threshold. If it doesn't return on time,
|
||||
// return invalid state and turn off the state machine as its always wrong.
|
||||
TickType_t start_tick = xTaskGetTickCount();
|
||||
const TickType_t timeout_ticks = pdMS_TO_TICKS(I2C_CLR_BUS_TIMEOUT_MS);
|
||||
while (i2c_ll_master_is_bus_clear_done(i2c_context[i2c_num].hal.dev)) {
|
||||
if ((xTaskGetTickCount() - start_tick) > timeout_ticks) {
|
||||
ESP_LOGE(I2C_TAG, I2C_CLEAR_BUS_ERR_STR);
|
||||
i2c_ll_master_clr_bus(i2c_context[i2c_num].hal.dev, 0, false);
|
||||
ret = ESP_ERR_INVALID_STATE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
i2c_ll_update(i2c_context[i2c_num].hal.dev);
|
||||
#endif
|
||||
return ESP_OK;
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**if the power and SDA/SCL wires are in proper condition, everything works find with reading the slave.
|
||||
|
@@ -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
|
||||
*/
|
||||
@@ -111,7 +111,7 @@ static esp_err_t s_i2c_master_clear_bus(i2c_bus_handle_t handle)
|
||||
*
|
||||
* @param[in] i2c_master I2C master handle
|
||||
*/
|
||||
static esp_err_t s_i2c_hw_fsm_reset(i2c_master_bus_handle_t i2c_master)
|
||||
static esp_err_t s_i2c_hw_fsm_reset(i2c_master_bus_handle_t i2c_master, bool clear_bus)
|
||||
{
|
||||
esp_err_t ret = ESP_OK;
|
||||
i2c_hal_context_t *hal = &i2c_master->base->hal;
|
||||
@@ -123,19 +123,27 @@ static esp_err_t s_i2c_hw_fsm_reset(i2c_master_bus_handle_t i2c_master)
|
||||
i2c_ll_master_get_filter(hal->dev, &filter_cfg);
|
||||
|
||||
//to reset the I2C hw module, we need re-enable the hw
|
||||
ret = s_i2c_master_clear_bus(i2c_master->base);
|
||||
if (clear_bus) {
|
||||
ret = s_i2c_master_clear_bus(i2c_master->base);
|
||||
}
|
||||
I2C_RCC_ATOMIC() {
|
||||
i2c_ll_reset_register(i2c_master->base->port_num);
|
||||
}
|
||||
|
||||
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);
|
||||
i2c_ll_master_set_filter(hal->dev, filter_cfg);
|
||||
#else
|
||||
i2c_ll_master_fsm_rst(hal->dev);
|
||||
ret = s_i2c_master_clear_bus(i2c_master->base);
|
||||
if (clear_bus) {
|
||||
ret = s_i2c_master_clear_bus(i2c_master->base);
|
||||
}
|
||||
#endif
|
||||
return ret;
|
||||
}
|
||||
@@ -219,14 +227,30 @@ static bool s_i2c_write_command(i2c_master_bus_handle_t i2c_master, i2c_operatio
|
||||
i2c_master->async_break = true;
|
||||
}
|
||||
} else {
|
||||
i2c_master->cmd_idx++;
|
||||
i2c_master->trans_idx++;
|
||||
i2c_master->i2c_trans.cmd_count--;
|
||||
if (i2c_master->async_trans == false) {
|
||||
if (xPortInIsrContext()) {
|
||||
xSemaphoreGiveFromISR(i2c_master->cmd_semphr, do_yield);
|
||||
// Handle consecutive i2c write operations
|
||||
i2c_operation_t next_transaction = i2c_master->i2c_trans.ops[i2c_master->trans_idx + 1];
|
||||
if (next_transaction.hw_cmd.op_code == I2C_LL_CMD_WRITE) {
|
||||
portENTER_CRITICAL_SAFE(&handle->spinlock);
|
||||
i2c_ll_master_write_cmd_reg(hal->dev, hw_end_cmd, i2c_master->cmd_idx + 1);
|
||||
portEXIT_CRITICAL_SAFE(&handle->spinlock);
|
||||
i2c_master->cmd_idx = 0;
|
||||
i2c_master->trans_idx++;
|
||||
i2c_master->i2c_trans.cmd_count--;
|
||||
if (i2c_master->async_trans == false) {
|
||||
i2c_hal_master_trans_start(hal);
|
||||
} else {
|
||||
xSemaphoreGive(i2c_master->cmd_semphr);
|
||||
i2c_master->async_break = true;
|
||||
}
|
||||
} else {
|
||||
i2c_master->cmd_idx++;
|
||||
i2c_master->trans_idx++;
|
||||
i2c_master->i2c_trans.cmd_count--;
|
||||
if (i2c_master->async_trans == false) {
|
||||
if (xPortInIsrContext()) {
|
||||
xSemaphoreGiveFromISR(i2c_master->cmd_semphr, do_yield);
|
||||
} else {
|
||||
xSemaphoreGive(i2c_master->cmd_semphr);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -267,7 +291,7 @@ static bool s_i2c_read_command(i2c_master_bus_handle_t i2c_master, i2c_operation
|
||||
i2c_master->contains_read = true;
|
||||
#if !SOC_I2C_STOP_INDEPENDENT
|
||||
if (remaining_bytes < I2C_FIFO_LEN(i2c_master->base->port_num) - 1) {
|
||||
if (i2c_operation->hw_cmd.ack_val == ACK_VAL) {
|
||||
if (i2c_operation->hw_cmd.ack_val == I2C_ACK_VAL) {
|
||||
if (remaining_bytes != 0) {
|
||||
i2c_ll_master_write_cmd_reg(hal->dev, hw_cmd, i2c_master->cmd_idx);
|
||||
i2c_master->read_len_static = i2c_master->rx_cnt;
|
||||
@@ -276,6 +300,13 @@ static bool s_i2c_read_command(i2c_master_bus_handle_t i2c_master, i2c_operation
|
||||
i2c_master->read_buf_pos = i2c_master->trans_idx;
|
||||
} else {
|
||||
i2c_ll_master_write_cmd_reg(hal->dev, hw_cmd, i2c_master->cmd_idx);
|
||||
// If the read position has not been marked, that means the transaction doesn't contain read-ack
|
||||
// operation, then mark the read position in read-nack operation.
|
||||
// i2c_master->read_buf_pos will never be 0.
|
||||
if (i2c_master->read_buf_pos == 0) {
|
||||
i2c_master->read_buf_pos = i2c_master->trans_idx;
|
||||
i2c_master->read_len_static = i2c_master->rx_cnt;
|
||||
}
|
||||
i2c_master->cmd_idx++;
|
||||
}
|
||||
i2c_master->trans_idx++;
|
||||
@@ -303,7 +334,7 @@ static bool s_i2c_read_command(i2c_master_bus_handle_t i2c_master, i2c_operation
|
||||
portENTER_CRITICAL_SAFE(&handle->spinlock);
|
||||
// If the read command work with ack_val, but no bytes to read, we skip
|
||||
// this command, and run next command directly.
|
||||
if (hw_cmd.ack_val == ACK_VAL) {
|
||||
if (hw_cmd.ack_val == I2C_ACK_VAL) {
|
||||
if (i2c_operation->total_bytes == 0) {
|
||||
i2c_master->trans_idx++;
|
||||
hw_cmd = i2c_master->i2c_trans.ops[i2c_master->trans_idx].hw_cmd;
|
||||
@@ -347,17 +378,25 @@ static void s_i2c_start_end_command(i2c_master_bus_handle_t i2c_master, i2c_oper
|
||||
uint8_t cmd_address = i2c_master->i2c_trans.device_address;
|
||||
uint8_t addr_byte = 1;
|
||||
#endif
|
||||
if (i2c_master->i2c_trans.device_address == I2C_DEVICE_ADDRESS_NOT_USED) {
|
||||
// Bypass the address.
|
||||
addr_byte = 0;
|
||||
}
|
||||
uint8_t addr_write[addr_byte];
|
||||
uint8_t addr_read[addr_byte];
|
||||
memset(addr_write, 0, sizeof(addr_write));
|
||||
memset(addr_read, 0, sizeof(addr_read));
|
||||
|
||||
addr_write[0] = I2C_ADDRESS_TRANS_WRITE(cmd_address);
|
||||
addr_read[0] = I2C_ADDRESS_TRANS_READ(cmd_address);
|
||||
if (addr_byte != 0) {
|
||||
addr_write[0] = I2C_ADDRESS_TRANS_WRITE(cmd_address);
|
||||
addr_read[0] = I2C_ADDRESS_TRANS_READ(cmd_address);
|
||||
#if SOC_I2C_SUPPORT_10BIT_ADDR
|
||||
if (i2c_master->addr_10bits_bus == I2C_ADDR_BIT_LEN_10) {
|
||||
addr_write[1] = i2c_master->i2c_trans.device_address & 0xff;
|
||||
addr_read[1] = i2c_master->i2c_trans.device_address & 0xff;
|
||||
}
|
||||
if (i2c_master->addr_10bits_bus == I2C_ADDR_BIT_LEN_10) {
|
||||
addr_write[1] = i2c_master->i2c_trans.device_address & 0xff;
|
||||
addr_read[1] = i2c_master->i2c_trans.device_address & 0xff;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
portENTER_CRITICAL_SAFE(&i2c_master->base->spinlock);
|
||||
i2c_ll_master_write_cmd_reg(hal->dev, hw_cmd, i2c_master->cmd_idx);
|
||||
@@ -457,7 +496,7 @@ static void s_i2c_send_commands(i2c_master_bus_handle_t i2c_master, TickType_t t
|
||||
}
|
||||
|
||||
if (atomic_load(&i2c_master->status) == I2C_STATUS_TIMEOUT) {
|
||||
s_i2c_hw_fsm_reset(i2c_master);
|
||||
s_i2c_hw_fsm_reset(i2c_master, true);
|
||||
i2c_master->cmd_idx = 0;
|
||||
i2c_master->trans_idx = 0;
|
||||
ESP_LOGE(TAG, "I2C hardware timeout detected");
|
||||
@@ -566,7 +605,7 @@ static esp_err_t s_i2c_transaction_start(i2c_master_dev_handle_t i2c_dev, int xf
|
||||
// Sometimes when the FSM get stuck, the ACK_ERR interrupt will occur endlessly until we reset the FSM and clear bus.
|
||||
esp_err_t ret = ESP_OK;
|
||||
if (atomic_load(&i2c_master->status) == I2C_STATUS_TIMEOUT || i2c_ll_is_bus_busy(hal->dev)) {
|
||||
ESP_RETURN_ON_ERROR(s_i2c_hw_fsm_reset(i2c_master), TAG, "reset hardware failed");
|
||||
ESP_RETURN_ON_ERROR(s_i2c_hw_fsm_reset(i2c_master, true), TAG, "reset hardware failed");
|
||||
}
|
||||
|
||||
if (i2c_master->base->pm_lock) {
|
||||
@@ -579,6 +618,7 @@ static esp_err_t s_i2c_transaction_start(i2c_master_dev_handle_t i2c_dev, int xf
|
||||
i2c_master->cmd_idx = 0;
|
||||
i2c_master->rx_cnt = 0;
|
||||
i2c_master->read_len_static = 0;
|
||||
i2c_master->read_buf_pos = 0;
|
||||
|
||||
I2C_CLOCK_SRC_ATOMIC() {
|
||||
i2c_hal_set_bus_timing(hal, i2c_dev->scl_speed_hz, i2c_master->base->clk_src, i2c_master->base->clk_src_freq_hz);
|
||||
@@ -642,7 +682,10 @@ IRAM_ATTR static void i2c_isr_receive_handler(i2c_master_bus_t *i2c_master)
|
||||
i2c_operation_t *i2c_operation = &i2c_master->i2c_trans.ops[i2c_master->read_buf_pos];
|
||||
portENTER_CRITICAL_ISR(&i2c_master->base->spinlock);
|
||||
i2c_ll_read_rxfifo(hal->dev, i2c_operation->data + i2c_operation->bytes_used, i2c_master->read_len_static);
|
||||
i2c_ll_read_rxfifo(hal->dev, i2c_master->i2c_trans.ops[i2c_master->read_buf_pos + 1].data, 1);
|
||||
// If the read command only contain nack marker, no read it for the second time.
|
||||
if (i2c_master->i2c_trans.ops[i2c_master->read_buf_pos + 1].data) {
|
||||
i2c_ll_read_rxfifo(hal->dev, i2c_master->i2c_trans.ops[i2c_master->read_buf_pos + 1].data, 1);
|
||||
}
|
||||
i2c_master->w_r_size = i2c_master->read_len_static + 1;
|
||||
i2c_master->contains_read = false;
|
||||
portEXIT_CRITICAL_ISR(&i2c_master->base->spinlock);
|
||||
@@ -895,7 +938,7 @@ static esp_err_t s_i2c_synchronous_transaction(i2c_master_dev_handle_t i2c_dev,
|
||||
|
||||
err:
|
||||
// When error occurs, reset hardware fsm in case not influence following transactions.
|
||||
s_i2c_hw_fsm_reset(i2c_dev->master_bus);
|
||||
s_i2c_hw_fsm_reset(i2c_dev->master_bus, false);
|
||||
xSemaphoreGive(i2c_dev->master_bus->bus_lock_mux);
|
||||
return ret;
|
||||
}
|
||||
@@ -1100,7 +1143,7 @@ esp_err_t i2c_master_bus_reset(i2c_master_bus_handle_t bus_handle)
|
||||
{
|
||||
ESP_RETURN_ON_FALSE((bus_handle != NULL), ESP_ERR_INVALID_ARG, TAG, "This bus is not initialized");
|
||||
// Reset I2C master bus
|
||||
ESP_RETURN_ON_ERROR(s_i2c_hw_fsm_reset(bus_handle), TAG, "I2C master bus reset failed");
|
||||
ESP_RETURN_ON_ERROR(s_i2c_hw_fsm_reset(bus_handle, true), TAG, "I2C master bus reset failed");
|
||||
// Reset I2C status state
|
||||
atomic_store(&bus_handle->status, I2C_STATUS_IDLE);
|
||||
return ESP_OK;
|
||||
@@ -1147,8 +1190,8 @@ esp_err_t i2c_master_transmit_receive(i2c_master_dev_handle_t i2c_dev, const uin
|
||||
{.hw_cmd = I2C_TRANS_START_COMMAND},
|
||||
{.hw_cmd = I2C_TRANS_WRITE_COMMAND(i2c_dev->ack_check_disable ? false : true), .data = (uint8_t *)write_buffer, .total_bytes = write_size},
|
||||
{.hw_cmd = I2C_TRANS_START_COMMAND},
|
||||
{.hw_cmd = I2C_TRANS_READ_COMMAND(ACK_VAL), .data = read_buffer, .total_bytes = read_size - 1},
|
||||
{.hw_cmd = I2C_TRANS_READ_COMMAND(NACK_VAL), .data = (read_buffer + read_size - 1), .total_bytes = 1},
|
||||
{.hw_cmd = I2C_TRANS_READ_COMMAND(I2C_ACK_VAL), .data = read_buffer, .total_bytes = read_size - 1},
|
||||
{.hw_cmd = I2C_TRANS_READ_COMMAND(I2C_NACK_VAL), .data = (read_buffer + read_size - 1), .total_bytes = 1},
|
||||
{.hw_cmd = I2C_TRANS_STOP_COMMAND},
|
||||
};
|
||||
|
||||
@@ -1167,8 +1210,8 @@ esp_err_t i2c_master_receive(i2c_master_dev_handle_t i2c_dev, uint8_t *read_buff
|
||||
|
||||
i2c_operation_t i2c_ops[] = {
|
||||
{.hw_cmd = I2C_TRANS_START_COMMAND},
|
||||
{.hw_cmd = I2C_TRANS_READ_COMMAND(ACK_VAL), .data = read_buffer, .total_bytes = read_size - 1},
|
||||
{.hw_cmd = I2C_TRANS_READ_COMMAND(NACK_VAL), .data = (read_buffer + read_size - 1), .total_bytes = 1},
|
||||
{.hw_cmd = I2C_TRANS_READ_COMMAND(I2C_ACK_VAL), .data = read_buffer, .total_bytes = read_size - 1},
|
||||
{.hw_cmd = I2C_TRANS_READ_COMMAND(I2C_NACK_VAL), .data = (read_buffer + read_size - 1), .total_bytes = 1},
|
||||
{.hw_cmd = I2C_TRANS_STOP_COMMAND},
|
||||
};
|
||||
|
||||
@@ -1212,6 +1255,8 @@ esp_err_t i2c_master_probe(i2c_master_bus_handle_t bus_handle, uint16_t address,
|
||||
i2c_ll_set_source_clk(hal->dev, bus_handle->base->clk_src);
|
||||
i2c_hal_set_bus_timing(hal, 100000, bus_handle->base->clk_src, bus_handle->base->clk_src_freq_hz);
|
||||
}
|
||||
i2c_ll_txfifo_rst(hal->dev);
|
||||
i2c_ll_rxfifo_rst(hal->dev);
|
||||
i2c_ll_master_set_fractional_divider(hal->dev, 0, 0);
|
||||
i2c_ll_enable_intr_mask(hal->dev, I2C_LL_MASTER_EVENT_INTR);
|
||||
// 20ms is sufficient for stretch, since there is no device config on probe operation.
|
||||
@@ -1234,6 +1279,55 @@ esp_err_t i2c_master_probe(i2c_master_bus_handle_t bus_handle, uint16_t address,
|
||||
return ret;
|
||||
}
|
||||
|
||||
esp_err_t i2c_master_execute_defined_operations(i2c_master_dev_handle_t i2c_dev, i2c_operation_job_t *i2c_operation, size_t operation_list_num, int xfer_timeout_ms)
|
||||
{
|
||||
ESP_RETURN_ON_FALSE(i2c_dev != NULL, ESP_ERR_INVALID_ARG, TAG, "i2c handle not initialized");
|
||||
ESP_RETURN_ON_FALSE(i2c_operation != NULL, ESP_ERR_INVALID_ARG, TAG, "i2c operation pointer is invalid");
|
||||
ESP_RETURN_ON_FALSE(operation_list_num <= (SOC_I2C_CMD_REG_NUM), ESP_ERR_INVALID_ARG, TAG, "i2c command list cannot contain so many commands");
|
||||
|
||||
i2c_operation_t i2c_ops[operation_list_num];
|
||||
memset(i2c_ops, 0, sizeof(i2c_ops));
|
||||
for (int i = 0; i < operation_list_num; i++) {
|
||||
switch (i2c_operation[i].command) {
|
||||
case I2C_MASTER_CMD_START:
|
||||
i2c_ops[i].hw_cmd.op_code = I2C_LL_CMD_RESTART;
|
||||
break;
|
||||
case I2C_MASTER_CMD_WRITE:
|
||||
i2c_ops[i].hw_cmd.op_code = I2C_LL_CMD_WRITE;
|
||||
i2c_ops[i].hw_cmd.ack_en = i2c_operation[i].write.ack_check;
|
||||
i2c_ops[i].data = i2c_operation[i].write.data;
|
||||
i2c_ops[i].total_bytes = i2c_operation[i].write.total_bytes;
|
||||
break;
|
||||
case I2C_MASTER_CMD_READ:
|
||||
i2c_ops[i].hw_cmd.op_code = I2C_LL_CMD_READ;
|
||||
i2c_ops[i].hw_cmd.ack_val = i2c_operation[i].read.ack_value;
|
||||
i2c_ops[i].data = i2c_operation[i].read.data;
|
||||
i2c_ops[i].total_bytes = i2c_operation[i].read.total_bytes;
|
||||
// Add check: If current command is READ and the next command is STOP, ack_value must be NACK
|
||||
if (i + 1 < operation_list_num && i2c_operation[i + 1].command == I2C_MASTER_CMD_STOP) {
|
||||
if (i2c_operation[i].read.ack_value != I2C_NACK_VAL) {
|
||||
ESP_LOGE(TAG, "ack_value must be NACK (1) when the next command of READ is STOP.");
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case I2C_MASTER_CMD_STOP:
|
||||
i2c_ops[i].hw_cmd.op_code = I2C_LL_CMD_STOP;
|
||||
break;
|
||||
default:
|
||||
ESP_LOGE(TAG, "Invalid command.");
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
}
|
||||
|
||||
if (i2c_dev->master_bus->async_trans == false) {
|
||||
ESP_RETURN_ON_ERROR(s_i2c_synchronous_transaction(i2c_dev, i2c_ops, operation_list_num, xfer_timeout_ms), TAG, "I2C transaction failed");
|
||||
} else {
|
||||
ESP_RETURN_ON_ERROR(s_i2c_asynchronous_transaction(i2c_dev, i2c_ops, operation_list_num, xfer_timeout_ms), TAG, "I2C transaction failed");
|
||||
}
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t i2c_master_register_event_callbacks(i2c_master_dev_handle_t i2c_dev, const i2c_master_event_callbacks_t *cbs, void *user_data)
|
||||
{
|
||||
ESP_RETURN_ON_FALSE(i2c_dev != NULL, ESP_ERR_INVALID_ARG, TAG, "i2c handle not initialized");
|
||||
|
@@ -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
|
||||
*/
|
||||
@@ -59,9 +59,6 @@ extern "C" {
|
||||
#define I2C_PM_LOCK_NAME_LEN_MAX 16
|
||||
#define I2C_STATIC_OPERATION_ARRAY_MAX SOC_I2C_CMD_REG_NUM
|
||||
|
||||
#define ACK_VAL 0
|
||||
#define NACK_VAL 1
|
||||
|
||||
#define I2C_TRANS_READ_COMMAND(ack_value) {.ack_val = (ack_value), .op_code = I2C_LL_CMD_READ}
|
||||
#define I2C_TRANS_WRITE_COMMAND(ack_check) {.ack_en = (ack_check), .op_code = I2C_LL_CMD_WRITE}
|
||||
#define I2C_TRANS_STOP_COMMAND {.op_code = I2C_LL_CMD_STOP}
|
||||
@@ -73,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,
|
||||
|
@@ -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
|
||||
*/
|
||||
@@ -36,12 +36,14 @@ typedef struct {
|
||||
} flags; /*!< I2C master config flags */
|
||||
} i2c_master_bus_config_t;
|
||||
|
||||
#define I2C_DEVICE_ADDRESS_NOT_USED (0xffff) /*!< Skip carry address bit in driver transmit and receive */
|
||||
|
||||
/**
|
||||
* @brief I2C device configuration
|
||||
*/
|
||||
typedef struct {
|
||||
i2c_addr_bit_len_t dev_addr_length; /*!< Select the address length of the slave device. */
|
||||
uint16_t device_address; /*!< I2C device raw address. (The 7/10 bit address without read/write bit) */
|
||||
uint16_t device_address; /*!< I2C device raw address. (The 7/10 bit address without read/write bit). Macro I2C_DEVICE_ADDRESS_NOT_USED (0xFFFF) stands for skip the address config inside driver. */
|
||||
uint32_t scl_speed_hz; /*!< I2C SCL line frequency. */
|
||||
uint32_t scl_wait_us; /*!< Timeout value. (unit: us). Please note this value should not be so small that it can handle stretch/disturbance properly. If 0 is set, that means use the default reg value*/
|
||||
struct {
|
||||
@@ -49,6 +51,38 @@ typedef struct {
|
||||
} flags; /*!< I2C device config flags */
|
||||
} i2c_device_config_t;
|
||||
|
||||
/**
|
||||
* @brief Structure representing an I2C operation job
|
||||
*
|
||||
* This structure is used to define individual I2C operations (write or read)
|
||||
* within a sequence of I2C master transactions.
|
||||
*/
|
||||
typedef struct {
|
||||
i2c_master_command_t command; /**< I2C command indicating the type of operation (START, WRITE, READ, or STOP) */
|
||||
union {
|
||||
/**
|
||||
* @brief Structure for WRITE command
|
||||
*
|
||||
* Used when the `command` is set to `I2C_MASTER_CMD_WRITE`.
|
||||
*/
|
||||
struct {
|
||||
bool ack_check; /**< Whether to enable ACK check during WRITE operation */
|
||||
uint8_t *data; /**< Pointer to the data to be written */
|
||||
size_t total_bytes; /**< Total number of bytes to write */
|
||||
} write;
|
||||
/**
|
||||
* @brief Structure for READ command
|
||||
*
|
||||
* Used when the `command` is set to `I2C_MASTER_CMD_READ`.
|
||||
*/
|
||||
struct {
|
||||
i2c_ack_value_t ack_value; /**< ACK value to send after the read (ACK or NACK) */
|
||||
uint8_t *data; /**< Pointer to the buffer for storing the data read from the bus */
|
||||
size_t total_bytes; /**< Total number of bytes to read */
|
||||
} read;
|
||||
};
|
||||
} i2c_operation_job_t;
|
||||
|
||||
/**
|
||||
* @brief Group of I2C master callbacks, can be used to get status during transaction or doing other small things. But take care potential concurrency issues.
|
||||
* @note The callbacks are all running under ISR context
|
||||
@@ -189,6 +223,30 @@ esp_err_t i2c_master_receive(i2c_master_dev_handle_t i2c_dev, uint8_t *read_buff
|
||||
*/
|
||||
esp_err_t i2c_master_probe(i2c_master_bus_handle_t bus_handle, uint16_t address, int xfer_timeout_ms);
|
||||
|
||||
/**
|
||||
* @brief Execute a series of pre-defined I2C operations.
|
||||
*
|
||||
* This function processes a list of I2C operations, such as start, write, read, and stop,
|
||||
* according to the user-defined `i2c_operation_job_t` array. It performs these operations
|
||||
* sequentially on the specified I2C master device.
|
||||
*
|
||||
* @param[in] i2c_dev Handle to the I2C master device.
|
||||
* @param[in] i2c_operation Pointer to an array of user-defined I2C operation jobs.
|
||||
* Each job specifies a command and associated parameters.
|
||||
* @param[in] operation_list_num The number of operations in the `i2c_operation` array.
|
||||
* @param[in] xfer_timeout_ms Timeout for the transaction, in milliseconds.
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK: Transaction completed successfully.
|
||||
* - ESP_ERR_INVALID_ARG: One or more arguments are invalid.
|
||||
* - ESP_ERR_TIMEOUT: Transaction timed out.
|
||||
* - ESP_FAIL: Other error during transaction.
|
||||
*
|
||||
* @note The `ack_value` field in the READ operation must be set to `I2C_NACK_VAL` if the next
|
||||
* operation is a STOP command.
|
||||
*/
|
||||
esp_err_t i2c_master_execute_defined_operations(i2c_master_dev_handle_t i2c_dev, i2c_operation_job_t *i2c_operation, size_t operation_list_num, int xfer_timeout_ms);
|
||||
|
||||
/**
|
||||
* @brief Register I2C transaction callbacks for a master device
|
||||
*
|
||||
|
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
|
||||
* SPDX-FileCopyrightText: 2023-2025 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
@@ -44,6 +44,29 @@ typedef enum {
|
||||
I2C_EVENT_TIMEOUT, /*!< i2c bus timeout */
|
||||
} i2c_master_event_t;
|
||||
|
||||
/**
|
||||
* @brief Enum for I2C master commands
|
||||
*
|
||||
* These commands are used to define the I2C master operations.
|
||||
* They correspond to hardware-level commands supported by the I2C peripheral.
|
||||
*/
|
||||
typedef enum {
|
||||
I2C_MASTER_CMD_START, /**< Start or Restart condition */
|
||||
I2C_MASTER_CMD_WRITE, /**< Write operation */
|
||||
I2C_MASTER_CMD_READ, /**< Read operation */
|
||||
I2C_MASTER_CMD_STOP, /**< Stop condition */
|
||||
} i2c_master_command_t;
|
||||
|
||||
/**
|
||||
* @brief Enum for I2C master ACK values
|
||||
*
|
||||
* These values define the acknowledgment (ACK) behavior during read operations.
|
||||
*/
|
||||
typedef enum {
|
||||
I2C_ACK_VAL = 0, /**< Acknowledge (ACK) signal */
|
||||
I2C_NACK_VAL = 1, /**< Not Acknowledge (NACK) signal */
|
||||
} __attribute__((packed)) i2c_ack_value_t;
|
||||
|
||||
/**
|
||||
* @brief Type of I2C master bus handle
|
||||
*/
|
||||
|
@@ -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: Unlicense OR CC0-1.0
|
||||
*/
|
||||
@@ -785,3 +785,94 @@ static void uart_test_i2c_master_freq(void)
|
||||
TEST_CASE_MULTIPLE_DEVICES("I2C master clock frequency test", "[i2c][test_env=generic_multi_device][timeout=150]", uart_test_i2c_master_freq, i2c_master_write_fsm_reset);
|
||||
|
||||
#endif // CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32S3
|
||||
|
||||
static void i2c_master_write_test_with_customize_api(void)
|
||||
{
|
||||
uint8_t data_wr[DATA_LENGTH] = { 0 };
|
||||
int i;
|
||||
|
||||
i2c_master_bus_config_t i2c_mst_config = {
|
||||
.clk_source = I2C_CLK_SRC_DEFAULT,
|
||||
.i2c_port = TEST_I2C_PORT,
|
||||
.scl_io_num = I2C_MASTER_SCL_IO,
|
||||
.sda_io_num = I2C_MASTER_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 = 0xFFFF,
|
||||
.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);
|
||||
|
||||
uint8_t address = (0x58 << 1 | 0);
|
||||
|
||||
i2c_operation_job_t i2c_ops[] = {
|
||||
{ .command = I2C_MASTER_CMD_START },
|
||||
{ .command = I2C_MASTER_CMD_WRITE, .write = { .ack_check = true, .data = (uint8_t *) &address, .total_bytes = 1 } },
|
||||
{ .command = I2C_MASTER_CMD_WRITE, .write = { .ack_check = true, .data = (uint8_t *) data_wr, .total_bytes = DATA_LENGTH } },
|
||||
{ .command = I2C_MASTER_CMD_STOP },
|
||||
};
|
||||
|
||||
TEST_ESP_OK(i2c_master_execute_defined_operations(dev_handle, i2c_ops, sizeof(i2c_ops) / sizeof(i2c_operation_job_t), -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 i2c_slave_read_test_v1(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 = I2C_SLAVE_SCL_IO,
|
||||
.sda_io_num = I2C_SLAVE_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("I2C master write slave with customize api", "[i2c][test_env=generic_multi_device][timeout=150]", i2c_master_write_test_with_customize_api, i2c_slave_read_test_v1);
|
||||
|
@@ -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
|
||||
}
|
||||
|
||||
/**
|
||||
|
@@ -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;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@@ -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;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@@ -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;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@@ -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;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@@ -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;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@@ -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;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@@ -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;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@@ -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;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@@ -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
|
||||
|
@@ -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
|
||||
|
@@ -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
|
||||
|
@@ -386,6 +386,76 @@ Simple example for probing an I2C device:
|
||||
ESP_ERROR_CHECK(i2c_del_master_bus(bus_handle));
|
||||
|
||||
|
||||
I2C Master Execute Customized Transactions
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Not all I2C devices strictly adhere to the standard I2C protocol, as different manufacturers may implement custom variations. For example, some devices require the address to be shifted, while others do not. Similarly, certain devices mandate acknowledgment (ACK) checks for specific operations, whereas others might not. To accommodate these variations, :cpp:func:`i2c_master_execute_defined_operations` function allow developers to define and execute fully customized I2C transactions. This flexibility ensures seamless communication with non-standard devices by tailoring the transaction sequence, addressing, and acknowledgment behavior to the device's specific requirements.
|
||||
|
||||
.. note::
|
||||
|
||||
If you want to define your address in :cpp:type:`i2c_operation_job_t`, please set :cpp:member:`i2c_device_config_t::device_address` as I2C_DEVICE_ADDRESS_NOT_USED to skip internal address configuration in driver.
|
||||
|
||||
For address configuration of using defined transactions, given that a device address is 0x20, there are two situations, see following example:
|
||||
|
||||
.. code:: c
|
||||
|
||||
i2c_device_config_t i2c_device = {
|
||||
.device_address = I2C_DEVICE_ADDRESS_NOT_USED,
|
||||
.scl_speed_hz = 100 * 1000,
|
||||
.scl_wait_us = 20000,
|
||||
};
|
||||
|
||||
i2c_master_dev_handle_t dev_handle;
|
||||
|
||||
i2c_master_bus_add_device(bus_handle, &i2c_device, &dev_handle);
|
||||
|
||||
// Situation one: The device does not allow device address shift
|
||||
uint8_t address1 = 0x20;
|
||||
i2c_operation_job_t i2c_ops1[] = {
|
||||
{ .command = I2C_MASTER_CMD_START },
|
||||
{ .command = I2C_MASTER_CMD_WRITE, .write = { .ack_check = false, .data = (uint8_t *) &address1, .total_bytes = 1 } },
|
||||
{ .command = I2C_MASTER_CMD_STOP },
|
||||
};
|
||||
|
||||
// Situation one: The device should left shift one byte with carrying a write or read bit (official protocol)
|
||||
uint8_t address2 = (0x20 << 1 | 0); // (0x20 << 1 | 1)
|
||||
i2c_operation_job_t i2c_ops2[] = {
|
||||
{ .command = I2C_MASTER_CMD_START },
|
||||
{ .command = I2C_MASTER_CMD_WRITE, .write = { .ack_check = false, .data = (uint8_t *) &address2, .total_bytes = 1 } },
|
||||
{ .command = I2C_MASTER_CMD_STOP },
|
||||
};
|
||||
|
||||
There are also some devices does not need an address, you can directly do transaction with data:
|
||||
|
||||
.. code:: c
|
||||
|
||||
uint8_t data[8] = {0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88};
|
||||
|
||||
i2c_operation_job_t i2c_ops[] = {
|
||||
{ .command = I2C_MASTER_CMD_START },
|
||||
{ .command = I2C_MASTER_CMD_WRITE, .write = { .ack_check = false, .data = (uint8_t *)data, .total_bytes = 8 } },
|
||||
{ .command = I2C_MASTER_CMD_STOP },
|
||||
};
|
||||
|
||||
i2c_master_execute_defined_operations(dev_handle, i2c_ops, sizeof(i2c_ops) / sizeof(i2c_operation_job_t), -1);
|
||||
|
||||
As for read direction, the theory is same but please always be aware the last byte of read before stop should always be nack. Example is as follows:
|
||||
|
||||
.. code:: c
|
||||
|
||||
uint8_t address = (0x20 << 1 | 1);
|
||||
uint8_t rcv_data[10] = {};
|
||||
|
||||
i2c_operation_job_t i2c_ops[] = {
|
||||
{ .command = I2C_MASTER_CMD_START },
|
||||
{ .command = I2C_MASTER_CMD_WRITE, .write = { .ack_check = false, .data = (uint8_t *) &address, .total_bytes = 1 } },
|
||||
{ .command = I2C_MASTER_CMD_READ, .read = { .ack_value = I2C_ACK_VAL, .data = (uint8_t *)rcv_data, .total_bytes = 9 } },
|
||||
{ .command = I2C_MASTER_CMD_READ, .read = { .ack_value = I2C_NACK_VAL, .data = (uint8_t *)(rcv_data + 9), .total_bytes = 1 } }, // This must be nack.
|
||||
{ .command = I2C_MASTER_CMD_STOP },
|
||||
};
|
||||
|
||||
i2c_master_execute_defined_operations(dev_handle, i2c_ops, sizeof(i2c_ops) / sizeof(i2c_operation_job_t), -1);
|
||||
|
||||
I2C Slave Controller
|
||||
^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
|
Reference in New Issue
Block a user