mirror of
https://github.com/espressif/esp-idf
synced 2025-03-09 17:19:09 -04:00
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
This commit is contained in:
commit
5054e0caf3
@ -825,6 +825,9 @@ esp_err_t i2c_param_config(i2c_port_t i2c_num, const i2c_config_t *i2c_conf)
|
||||
#endif // SOC_I2C_SUPPORT_SLAVE
|
||||
{
|
||||
i2c_hal_master_init(&(i2c_context[i2c_num].hal));
|
||||
I2C_CLOCK_SRC_ATOMIC() {
|
||||
i2c_ll_set_source_clk(i2c_context[i2c_num].hal.dev, src_clk);
|
||||
}
|
||||
//Default, we enable hardware filter
|
||||
i2c_ll_master_set_filter(i2c_context[i2c_num].hal.dev, I2C_FILTER_CYC_NUM_DEF);
|
||||
I2C_CLOCK_SRC_ATOMIC() {
|
||||
|
@ -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
|
||||
*/
|
||||
@ -285,7 +285,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;
|
||||
@ -321,7 +321,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;
|
||||
@ -365,17 +365,23 @@ 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];
|
||||
|
||||
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);
|
||||
@ -1205,8 +1211,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},
|
||||
};
|
||||
|
||||
@ -1225,8 +1231,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},
|
||||
};
|
||||
|
||||
@ -1290,6 +1296,54 @@ 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] = {};
|
||||
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");
|
||||
|
@ -63,9 +63,6 @@ extern "C" {
|
||||
#define I2C_PM_LOCK_NAME_LEN_MAX 16
|
||||
#define I2C_STATIC_OPERATION_ARRAY_MAX 6
|
||||
|
||||
#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}
|
||||
|
@ -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
|
||||
*/
|
||||
@ -39,12 +39,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 {
|
||||
@ -52,6 +54,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 I2C master transmit buffer information structure
|
||||
*/
|
||||
@ -218,6 +252,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-2024 Espressif Systems (Shanghai) CO LTD
|
||||
* SPDX-FileCopyrightText: 2023-2025 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
@ -45,6 +45,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
|
||||
*/
|
||||
|
@ -237,4 +237,56 @@ static void slave_write_buffer_test_v2(void)
|
||||
|
||||
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);
|
||||
|
||||
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 = I2C_DEVICE_ADDRESS_NOT_USED,
|
||||
.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 = (ESP_SLAVE_ADDR << 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));
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
#endif // SOC_I2C_SLAVE_CAN_GET_STRETCH_CAUSE
|
||||
|
@ -439,6 +439,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
|
||||
^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user