Skip to content

Commit 5054e0c

Browse files
committed
Merge branch 'fix/i2c_scl_freq_s2_v5.4' into 'release/v5.4'
fix(i2c): Fix scl frequency is wrong on esp32s2 in legacy i2c driver & Add api for customize i2c transaction interface for un-standard i2c device (backport v5.4) See merge request espressif/esp-idf!37113
2 parents ab0e43d + 3299b65 commit 5054e0c

File tree

7 files changed

+276
-19
lines changed

7 files changed

+276
-19
lines changed

components/driver/i2c/i2c.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -825,6 +825,9 @@ esp_err_t i2c_param_config(i2c_port_t i2c_num, const i2c_config_t *i2c_conf)
825825
#endif // SOC_I2C_SUPPORT_SLAVE
826826
{
827827
i2c_hal_master_init(&(i2c_context[i2c_num].hal));
828+
I2C_CLOCK_SRC_ATOMIC() {
829+
i2c_ll_set_source_clk(i2c_context[i2c_num].hal.dev, src_clk);
830+
}
828831
//Default, we enable hardware filter
829832
i2c_ll_master_set_filter(i2c_context[i2c_num].hal.dev, I2C_FILTER_CYC_NUM_DEF);
830833
I2C_CLOCK_SRC_ATOMIC() {

components/esp_driver_i2c/i2c_master.c

Lines changed: 67 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD
2+
* SPDX-FileCopyrightText: 2023-2025 Espressif Systems (Shanghai) CO LTD
33
*
44
* SPDX-License-Identifier: Apache-2.0
55
*/
@@ -285,7 +285,7 @@ static bool s_i2c_read_command(i2c_master_bus_handle_t i2c_master, i2c_operation
285285
i2c_master->contains_read = true;
286286
#if !SOC_I2C_STOP_INDEPENDENT
287287
if (remaining_bytes < I2C_FIFO_LEN(i2c_master->base->port_num) - 1) {
288-
if (i2c_operation->hw_cmd.ack_val == ACK_VAL) {
288+
if (i2c_operation->hw_cmd.ack_val == I2C_ACK_VAL) {
289289
if (remaining_bytes != 0) {
290290
i2c_ll_master_write_cmd_reg(hal->dev, hw_cmd, i2c_master->cmd_idx);
291291
i2c_master->read_len_static = i2c_master->rx_cnt;
@@ -321,7 +321,7 @@ static bool s_i2c_read_command(i2c_master_bus_handle_t i2c_master, i2c_operation
321321
portENTER_CRITICAL_SAFE(&handle->spinlock);
322322
// If the read command work with ack_val, but no bytes to read, we skip
323323
// this command, and run next command directly.
324-
if (hw_cmd.ack_val == ACK_VAL) {
324+
if (hw_cmd.ack_val == I2C_ACK_VAL) {
325325
if (i2c_operation->total_bytes == 0) {
326326
i2c_master->trans_idx++;
327327
hw_cmd = i2c_master->i2c_trans.ops[i2c_master->trans_idx].hw_cmd;
@@ -365,17 +365,23 @@ static void s_i2c_start_end_command(i2c_master_bus_handle_t i2c_master, i2c_oper
365365
uint8_t cmd_address = i2c_master->i2c_trans.device_address;
366366
uint8_t addr_byte = 1;
367367
#endif
368+
if (i2c_master->i2c_trans.device_address == I2C_DEVICE_ADDRESS_NOT_USED) {
369+
// Bypass the address.
370+
addr_byte = 0;
371+
}
368372
uint8_t addr_write[addr_byte];
369373
uint8_t addr_read[addr_byte];
370374

371-
addr_write[0] = I2C_ADDRESS_TRANS_WRITE(cmd_address);
372-
addr_read[0] = I2C_ADDRESS_TRANS_READ(cmd_address);
375+
if (addr_byte != 0) {
376+
addr_write[0] = I2C_ADDRESS_TRANS_WRITE(cmd_address);
377+
addr_read[0] = I2C_ADDRESS_TRANS_READ(cmd_address);
373378
#if SOC_I2C_SUPPORT_10BIT_ADDR
374-
if (i2c_master->addr_10bits_bus == I2C_ADDR_BIT_LEN_10) {
375-
addr_write[1] = i2c_master->i2c_trans.device_address & 0xff;
376-
addr_read[1] = i2c_master->i2c_trans.device_address & 0xff;
377-
}
379+
if (i2c_master->addr_10bits_bus == I2C_ADDR_BIT_LEN_10) {
380+
addr_write[1] = i2c_master->i2c_trans.device_address & 0xff;
381+
addr_read[1] = i2c_master->i2c_trans.device_address & 0xff;
382+
}
378383
#endif
384+
}
379385

380386
portENTER_CRITICAL_SAFE(&i2c_master->base->spinlock);
381387
i2c_ll_master_write_cmd_reg(hal->dev, hw_cmd, i2c_master->cmd_idx);
@@ -1205,8 +1211,8 @@ esp_err_t i2c_master_transmit_receive(i2c_master_dev_handle_t i2c_dev, const uin
12051211
{.hw_cmd = I2C_TRANS_START_COMMAND},
12061212
{.hw_cmd = I2C_TRANS_WRITE_COMMAND(i2c_dev->ack_check_disable ? false : true), .data = (uint8_t *)write_buffer, .total_bytes = write_size},
12071213
{.hw_cmd = I2C_TRANS_START_COMMAND},
1208-
{.hw_cmd = I2C_TRANS_READ_COMMAND(ACK_VAL), .data = read_buffer, .total_bytes = read_size - 1},
1209-
{.hw_cmd = I2C_TRANS_READ_COMMAND(NACK_VAL), .data = (read_buffer + read_size - 1), .total_bytes = 1},
1214+
{.hw_cmd = I2C_TRANS_READ_COMMAND(I2C_ACK_VAL), .data = read_buffer, .total_bytes = read_size - 1},
1215+
{.hw_cmd = I2C_TRANS_READ_COMMAND(I2C_NACK_VAL), .data = (read_buffer + read_size - 1), .total_bytes = 1},
12101216
{.hw_cmd = I2C_TRANS_STOP_COMMAND},
12111217
};
12121218

@@ -1225,8 +1231,8 @@ esp_err_t i2c_master_receive(i2c_master_dev_handle_t i2c_dev, uint8_t *read_buff
12251231

12261232
i2c_operation_t i2c_ops[] = {
12271233
{.hw_cmd = I2C_TRANS_START_COMMAND},
1228-
{.hw_cmd = I2C_TRANS_READ_COMMAND(ACK_VAL), .data = read_buffer, .total_bytes = read_size - 1},
1229-
{.hw_cmd = I2C_TRANS_READ_COMMAND(NACK_VAL), .data = (read_buffer + read_size - 1), .total_bytes = 1},
1234+
{.hw_cmd = I2C_TRANS_READ_COMMAND(I2C_ACK_VAL), .data = read_buffer, .total_bytes = read_size - 1},
1235+
{.hw_cmd = I2C_TRANS_READ_COMMAND(I2C_NACK_VAL), .data = (read_buffer + read_size - 1), .total_bytes = 1},
12301236
{.hw_cmd = I2C_TRANS_STOP_COMMAND},
12311237
};
12321238

@@ -1290,6 +1296,54 @@ esp_err_t i2c_master_probe(i2c_master_bus_handle_t bus_handle, uint16_t address,
12901296
return ret;
12911297
}
12921298

1299+
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)
1300+
{
1301+
ESP_RETURN_ON_FALSE(i2c_dev != NULL, ESP_ERR_INVALID_ARG, TAG, "i2c handle not initialized");
1302+
ESP_RETURN_ON_FALSE(i2c_operation != NULL, ESP_ERR_INVALID_ARG, TAG, "i2c operation pointer is invalid");
1303+
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");
1304+
1305+
i2c_operation_t i2c_ops[operation_list_num] = {};
1306+
for (int i = 0; i < operation_list_num; i++) {
1307+
switch (i2c_operation[i].command) {
1308+
case I2C_MASTER_CMD_START:
1309+
i2c_ops[i].hw_cmd.op_code = I2C_LL_CMD_RESTART;
1310+
break;
1311+
case I2C_MASTER_CMD_WRITE:
1312+
i2c_ops[i].hw_cmd.op_code = I2C_LL_CMD_WRITE;
1313+
i2c_ops[i].hw_cmd.ack_en = i2c_operation[i].write.ack_check;
1314+
i2c_ops[i].data = i2c_operation[i].write.data;
1315+
i2c_ops[i].total_bytes = i2c_operation[i].write.total_bytes;
1316+
break;
1317+
case I2C_MASTER_CMD_READ:
1318+
i2c_ops[i].hw_cmd.op_code = I2C_LL_CMD_READ;
1319+
i2c_ops[i].hw_cmd.ack_val = i2c_operation[i].read.ack_value;
1320+
i2c_ops[i].data = i2c_operation[i].read.data;
1321+
i2c_ops[i].total_bytes = i2c_operation[i].read.total_bytes;
1322+
// Add check: If current command is READ and the next command is STOP, ack_value must be NACK
1323+
if (i + 1 < operation_list_num && i2c_operation[i + 1].command == I2C_MASTER_CMD_STOP) {
1324+
if (i2c_operation[i].read.ack_value != I2C_NACK_VAL) {
1325+
ESP_LOGE(TAG, "ack_value must be NACK (1) when the next command of READ is STOP.");
1326+
return ESP_ERR_INVALID_ARG;
1327+
}
1328+
}
1329+
break;
1330+
case I2C_MASTER_CMD_STOP:
1331+
i2c_ops[i].hw_cmd.op_code = I2C_LL_CMD_STOP;
1332+
break;
1333+
default:
1334+
ESP_LOGE(TAG, "Invalid command.");
1335+
return ESP_ERR_INVALID_ARG;
1336+
}
1337+
}
1338+
1339+
if (i2c_dev->master_bus->async_trans == false) {
1340+
ESP_RETURN_ON_ERROR(s_i2c_synchronous_transaction(i2c_dev, i2c_ops, operation_list_num, xfer_timeout_ms), TAG, "I2C transaction failed");
1341+
} else {
1342+
ESP_RETURN_ON_ERROR(s_i2c_asynchronous_transaction(i2c_dev, i2c_ops, operation_list_num, xfer_timeout_ms), TAG, "I2C transaction failed");
1343+
}
1344+
return ESP_OK;
1345+
}
1346+
12931347
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)
12941348
{
12951349
ESP_RETURN_ON_FALSE(i2c_dev != NULL, ESP_ERR_INVALID_ARG, TAG, "i2c handle not initialized");

components/esp_driver_i2c/i2c_private.h

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -63,9 +63,6 @@ extern "C" {
6363
#define I2C_PM_LOCK_NAME_LEN_MAX 16
6464
#define I2C_STATIC_OPERATION_ARRAY_MAX 6
6565

66-
#define ACK_VAL 0
67-
#define NACK_VAL 1
68-
6966
#define I2C_TRANS_READ_COMMAND(ack_value) {.ack_val = (ack_value), .op_code = I2C_LL_CMD_READ}
7067
#define I2C_TRANS_WRITE_COMMAND(ack_check) {.ack_en = (ack_check), .op_code = I2C_LL_CMD_WRITE}
7168
#define I2C_TRANS_STOP_COMMAND {.op_code = I2C_LL_CMD_STOP}

components/esp_driver_i2c/include/driver/i2c_master.h

Lines changed: 60 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD
2+
* SPDX-FileCopyrightText: 2023-2025 Espressif Systems (Shanghai) CO LTD
33
*
44
* SPDX-License-Identifier: Apache-2.0
55
*/
@@ -39,19 +39,53 @@ typedef struct {
3939
} flags; /*!< I2C master config flags */
4040
} i2c_master_bus_config_t;
4141

42+
#define I2C_DEVICE_ADDRESS_NOT_USED (0xffff) /*!< Skip carry address bit in driver transmit and receive */
43+
4244
/**
4345
* @brief I2C device configuration
4446
*/
4547
typedef struct {
4648
i2c_addr_bit_len_t dev_addr_length; /*!< Select the address length of the slave device. */
47-
uint16_t device_address; /*!< I2C device raw address. (The 7/10 bit address without read/write bit) */
49+
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. */
4850
uint32_t scl_speed_hz; /*!< I2C SCL line frequency. */
4951
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*/
5052
struct {
5153
uint32_t disable_ack_check: 1; /*!< Disable ACK check. If this is set false, that means ack check is enabled, the transaction will be stopped and API returns error when nack is detected. */
5254
} flags; /*!< I2C device config flags */
5355
} i2c_device_config_t;
5456

57+
/**
58+
* @brief Structure representing an I2C operation job
59+
*
60+
* This structure is used to define individual I2C operations (write or read)
61+
* within a sequence of I2C master transactions.
62+
*/
63+
typedef struct {
64+
i2c_master_command_t command; /**< I2C command indicating the type of operation (START, WRITE, READ, or STOP) */
65+
union {
66+
/**
67+
* @brief Structure for WRITE command
68+
*
69+
* Used when the `command` is set to `I2C_MASTER_CMD_WRITE`.
70+
*/
71+
struct {
72+
bool ack_check; /**< Whether to enable ACK check during WRITE operation */
73+
uint8_t *data; /**< Pointer to the data to be written */
74+
size_t total_bytes; /**< Total number of bytes to write */
75+
} write;
76+
/**
77+
* @brief Structure for READ command
78+
*
79+
* Used when the `command` is set to `I2C_MASTER_CMD_READ`.
80+
*/
81+
struct {
82+
i2c_ack_value_t ack_value; /**< ACK value to send after the read (ACK or NACK) */
83+
uint8_t *data; /**< Pointer to the buffer for storing the data read from the bus */
84+
size_t total_bytes; /**< Total number of bytes to read */
85+
} read;
86+
};
87+
} i2c_operation_job_t;
88+
5589
/**
5690
* @brief I2C master transmit buffer information structure
5791
*/
@@ -218,6 +252,30 @@ esp_err_t i2c_master_receive(i2c_master_dev_handle_t i2c_dev, uint8_t *read_buff
218252
*/
219253
esp_err_t i2c_master_probe(i2c_master_bus_handle_t bus_handle, uint16_t address, int xfer_timeout_ms);
220254

255+
/**
256+
* @brief Execute a series of pre-defined I2C operations.
257+
*
258+
* This function processes a list of I2C operations, such as start, write, read, and stop,
259+
* according to the user-defined `i2c_operation_job_t` array. It performs these operations
260+
* sequentially on the specified I2C master device.
261+
*
262+
* @param[in] i2c_dev Handle to the I2C master device.
263+
* @param[in] i2c_operation Pointer to an array of user-defined I2C operation jobs.
264+
* Each job specifies a command and associated parameters.
265+
* @param[in] operation_list_num The number of operations in the `i2c_operation` array.
266+
* @param[in] xfer_timeout_ms Timeout for the transaction, in milliseconds.
267+
*
268+
* @return
269+
* - ESP_OK: Transaction completed successfully.
270+
* - ESP_ERR_INVALID_ARG: One or more arguments are invalid.
271+
* - ESP_ERR_TIMEOUT: Transaction timed out.
272+
* - ESP_FAIL: Other error during transaction.
273+
*
274+
* @note The `ack_value` field in the READ operation must be set to `I2C_NACK_VAL` if the next
275+
* operation is a STOP command.
276+
*/
277+
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);
278+
221279
/**
222280
* @brief Register I2C transaction callbacks for a master device
223281
*

components/esp_driver_i2c/include/driver/i2c_types.h

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD
2+
* SPDX-FileCopyrightText: 2023-2025 Espressif Systems (Shanghai) CO LTD
33
*
44
* SPDX-License-Identifier: Apache-2.0
55
*/
@@ -45,6 +45,29 @@ typedef enum {
4545
I2C_EVENT_TIMEOUT, /*!< i2c bus timeout */
4646
} i2c_master_event_t;
4747

48+
/**
49+
* @brief Enum for I2C master commands
50+
*
51+
* These commands are used to define the I2C master operations.
52+
* They correspond to hardware-level commands supported by the I2C peripheral.
53+
*/
54+
typedef enum {
55+
I2C_MASTER_CMD_START, /**< Start or Restart condition */
56+
I2C_MASTER_CMD_WRITE, /**< Write operation */
57+
I2C_MASTER_CMD_READ, /**< Read operation */
58+
I2C_MASTER_CMD_STOP, /**< Stop condition */
59+
} i2c_master_command_t;
60+
61+
/**
62+
* @brief Enum for I2C master ACK values
63+
*
64+
* These values define the acknowledgment (ACK) behavior during read operations.
65+
*/
66+
typedef enum {
67+
I2C_ACK_VAL = 0, /**< Acknowledge (ACK) signal */
68+
I2C_NACK_VAL = 1, /**< Not Acknowledge (NACK) signal */
69+
} __attribute__((packed)) i2c_ack_value_t;
70+
4871
/**
4972
* @brief Type of I2C master bus handle
5073
*/

components/esp_driver_i2c/test_apps/i2c_test_apps/main/test_i2c_slave_v2.c

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -237,4 +237,56 @@ static void slave_write_buffer_test_v2(void)
237237

238238
TEST_CASE_MULTIPLE_DEVICES("I2C master read slave test", "[i2c][test_env=generic_multi_device][timeout=150]", master_read_slave_test_v2, slave_write_buffer_test_v2);
239239

240+
static void i2c_master_write_test_with_customize_api(void)
241+
{
242+
uint8_t data_wr[DATA_LENGTH] = { 0 };
243+
int i;
244+
245+
i2c_master_bus_config_t i2c_mst_config = {
246+
.clk_source = I2C_CLK_SRC_DEFAULT,
247+
.i2c_port = TEST_I2C_PORT,
248+
.scl_io_num = I2C_MASTER_SCL_IO,
249+
.sda_io_num = I2C_MASTER_SDA_IO,
250+
.flags.enable_internal_pullup = true,
251+
};
252+
i2c_master_bus_handle_t bus_handle;
253+
254+
TEST_ESP_OK(i2c_new_master_bus(&i2c_mst_config, &bus_handle));
255+
256+
i2c_device_config_t dev_cfg = {
257+
.dev_addr_length = I2C_ADDR_BIT_LEN_7,
258+
.device_address = I2C_DEVICE_ADDRESS_NOT_USED,
259+
.scl_speed_hz = 100000,
260+
};
261+
262+
i2c_master_dev_handle_t dev_handle;
263+
TEST_ESP_OK(i2c_master_bus_add_device(bus_handle, &dev_cfg, &dev_handle));
264+
265+
unity_wait_for_signal("i2c slave init finish");
266+
267+
unity_send_signal("master write");
268+
for (i = 0; i < DATA_LENGTH; i++) {
269+
data_wr[i] = i;
270+
}
271+
272+
disp_buf(data_wr, i);
273+
274+
uint8_t address = (ESP_SLAVE_ADDR << 1 | 0);
275+
276+
i2c_operation_job_t i2c_ops[] = {
277+
{ .command = I2C_MASTER_CMD_START },
278+
{ .command = I2C_MASTER_CMD_WRITE, .write = { .ack_check = true, .data = (uint8_t *) &address, .total_bytes = 1 } },
279+
{ .command = I2C_MASTER_CMD_WRITE, .write = { .ack_check = true, .data = (uint8_t *) data_wr, .total_bytes = DATA_LENGTH } },
280+
{ .command = I2C_MASTER_CMD_STOP },
281+
};
282+
283+
TEST_ESP_OK(i2c_master_execute_defined_operations(dev_handle, i2c_ops, sizeof(i2c_ops) / sizeof(i2c_operation_job_t), -1));
284+
unity_wait_for_signal("ready to delete");
285+
TEST_ESP_OK(i2c_master_bus_rm_device(dev_handle));
286+
287+
TEST_ESP_OK(i2c_del_master_bus(bus_handle));
288+
}
289+
290+
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_v2);
291+
240292
#endif // SOC_I2C_SLAVE_CAN_GET_STRETCH_CAUSE

0 commit comments

Comments
 (0)