mirror of
https://github.com/espressif/esp-idf.git
synced 2024-10-05 20:47:46 -04:00
feat(i2c_master): Add feature for transmit multi buffer in one transaction,
Closes https://github.com/espressif/esp-idf/pull/13635
This commit is contained in:
parent
7c281c0380
commit
af1524e7bb
@ -193,14 +193,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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1057,23 +1073,45 @@ esp_err_t i2c_master_bus_reset(i2c_master_bus_handle_t bus_handle)
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t i2c_master_multi_buffer_transmit(i2c_master_dev_handle_t i2c_dev, i2c_master_transmit_multi_buffer_info_t *buffer_info_array, size_t array_size, int xfer_timeout_ms)
|
||||
{
|
||||
ESP_RETURN_ON_FALSE(i2c_dev != NULL, ESP_ERR_INVALID_ARG, TAG, "i2c handle not initialized");
|
||||
ESP_RETURN_ON_FALSE(array_size <= (SOC_I2C_CMD_REG_NUM - 2), ESP_ERR_INVALID_ARG, TAG, "i2c command list cannot contain so many commands");
|
||||
ESP_RETURN_ON_FALSE(buffer_info_array != NULL, ESP_ERR_INVALID_ARG, TAG, "buffer info array is empty");
|
||||
|
||||
size_t op_index = 0;
|
||||
i2c_operation_t i2c_ops[SOC_I2C_CMD_REG_NUM] = {};
|
||||
i2c_ops[op_index++].hw_cmd.op_code = I2C_LL_CMD_RESTART;
|
||||
for (int i = 0; i < array_size; i++) {
|
||||
if (buffer_info_array[i].buffer_size == 0) {
|
||||
continue;
|
||||
}
|
||||
i2c_ops[op_index].hw_cmd.ack_en = i2c_dev->ack_check_disable ? false : true;
|
||||
i2c_ops[op_index].hw_cmd.op_code = I2C_LL_CMD_WRITE;
|
||||
i2c_ops[op_index].data = (uint8_t*)buffer_info_array[i].write_buffer;
|
||||
i2c_ops[op_index].total_bytes = buffer_info_array[i].buffer_size;
|
||||
i2c_ops[op_index].bytes_used = 0;
|
||||
op_index++;
|
||||
}
|
||||
|
||||
i2c_ops[op_index++].hw_cmd.op_code = I2C_LL_CMD_STOP;
|
||||
if (i2c_dev->master_bus->async_trans == false) {
|
||||
ESP_RETURN_ON_ERROR(s_i2c_synchronous_transaction(i2c_dev, i2c_ops, op_index, xfer_timeout_ms), TAG, "I2C transaction failed");
|
||||
} else {
|
||||
ESP_RETURN_ON_ERROR(s_i2c_asynchronous_transaction(i2c_dev, i2c_ops, op_index, xfer_timeout_ms), TAG, "I2C transaction failed");
|
||||
}
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t i2c_master_transmit(i2c_master_dev_handle_t i2c_dev, const uint8_t *write_buffer, size_t write_size, int xfer_timeout_ms)
|
||||
{
|
||||
ESP_RETURN_ON_FALSE(i2c_dev != NULL, ESP_ERR_INVALID_ARG, TAG, "i2c handle not initialized");
|
||||
ESP_RETURN_ON_FALSE((write_buffer != NULL) && (write_size > 0), ESP_ERR_INVALID_ARG, TAG, "i2c transmit buffer or size invalid");
|
||||
|
||||
i2c_operation_t i2c_ops[] = {
|
||||
{.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_STOP_COMMAND},
|
||||
i2c_master_transmit_multi_buffer_info_t buffer_info[1] = {
|
||||
{.write_buffer = (uint8_t*)write_buffer, .buffer_size = write_size},
|
||||
};
|
||||
|
||||
if (i2c_dev->master_bus->async_trans == false) {
|
||||
ESP_RETURN_ON_ERROR(s_i2c_synchronous_transaction(i2c_dev, i2c_ops, DIM(i2c_ops), xfer_timeout_ms), TAG, "I2C transaction failed");
|
||||
} else {
|
||||
ESP_RETURN_ON_ERROR(s_i2c_asynchronous_transaction(i2c_dev, i2c_ops, DIM(i2c_ops), xfer_timeout_ms), TAG, "I2C transaction failed");
|
||||
}
|
||||
return ESP_OK;
|
||||
return i2c_master_multi_buffer_transmit(i2c_dev, buffer_info, 1, xfer_timeout_ms);
|
||||
}
|
||||
|
||||
esp_err_t i2c_master_transmit_receive(i2c_master_dev_handle_t i2c_dev, const uint8_t *write_buffer, size_t write_size, uint8_t *read_buffer, size_t read_size, int xfer_timeout_ms)
|
||||
|
@ -49,6 +49,14 @@ typedef struct {
|
||||
} flags; /*!< I2C device config flags */
|
||||
} i2c_device_config_t;
|
||||
|
||||
/**
|
||||
* @brief I2C master transmit buffer information structure
|
||||
*/
|
||||
typedef struct {
|
||||
uint8_t *write_buffer; /*!< Pointer to buffer to be written. */
|
||||
size_t buffer_size; /*!< Size of data to be written. */
|
||||
} i2c_master_transmit_multi_buffer_info_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
|
||||
@ -123,6 +131,24 @@ esp_err_t i2c_master_bus_rm_device(i2c_master_dev_handle_t handle);
|
||||
*/
|
||||
esp_err_t i2c_master_transmit(i2c_master_dev_handle_t i2c_dev, const uint8_t *write_buffer, size_t write_size, int xfer_timeout_ms);
|
||||
|
||||
/**
|
||||
* @brief Transmit multiple buffers of data over an I2C bus.
|
||||
*
|
||||
* This function transmits multiple buffers of data over an I2C bus using the specified I2C master device handle.
|
||||
* It takes in an array of buffer information structures along with the size of the array and a transfer timeout value in milliseconds.
|
||||
*
|
||||
* @param i2c_dev I2C master device handle that created by `i2c_master_bus_add_device`.
|
||||
* @param buffer_info_array Pointer to buffer information array.
|
||||
* @param array_size size of buffer information array.
|
||||
* @param xfer_timeout_ms Wait timeout, in ms. Note: -1 means wait forever.
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK: I2C master transmit success
|
||||
* - ESP_ERR_INVALID_ARG: I2C master transmit parameter invalid.
|
||||
* - ESP_ERR_TIMEOUT: Operation timeout(larger than xfer_timeout_ms) because the bus is busy or hardware crash.
|
||||
*/
|
||||
esp_err_t i2c_master_multi_buffer_transmit(i2c_master_dev_handle_t i2c_dev, i2c_master_transmit_multi_buffer_info_t *buffer_info_array, size_t array_size, int xfer_timeout_ms);
|
||||
|
||||
/**
|
||||
* @brief Perform a write-read transaction on the I2C bus.
|
||||
* The transaction will be undergoing until it finishes or it reaches
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
|
||||
* SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
@ -149,32 +149,40 @@ static esp_err_t panel_io_i2c_tx_buffer(esp_lcd_panel_io_t *io, int lcd_cmd, con
|
||||
esp_err_t ret = ESP_OK;
|
||||
lcd_panel_io_i2c_t *i2c_panel_io = __containerof(io, lcd_panel_io_i2c_t, base);
|
||||
bool send_param = (lcd_cmd >= 0);
|
||||
int write_size = 0;
|
||||
uint8_t *write_buffer = (uint8_t*)heap_caps_malloc(CONTROL_PHASE_LENGTH + CMD_LENGTH + buffer_size, MALLOC_CAP_8BIT);
|
||||
ESP_GOTO_ON_FALSE(write_buffer, ESP_ERR_NO_MEM, err, TAG, "no mem for write buffer");
|
||||
|
||||
uint8_t control_phase_byte = 0;
|
||||
size_t control_phase_size = 0;
|
||||
if (i2c_panel_io->control_phase_enabled) {
|
||||
write_buffer[0] = is_param ? i2c_panel_io->control_phase_cmd : i2c_panel_io->control_phase_data;
|
||||
write_size += 1;
|
||||
control_phase_byte = is_param ? i2c_panel_io->control_phase_cmd : i2c_panel_io->control_phase_data;
|
||||
control_phase_size = 1;
|
||||
}
|
||||
|
||||
uint8_t *cmd_buffer = NULL;
|
||||
size_t cmd_buffer_size = 0;
|
||||
// some displays don't want any additional commands on data transfers
|
||||
if (send_param) {
|
||||
uint8_t cmds[4] = {BYTESHIFT(lcd_cmd, 3), BYTESHIFT(lcd_cmd, 2), BYTESHIFT(lcd_cmd, 1), BYTESHIFT(lcd_cmd, 0)};
|
||||
size_t cmds_size = i2c_panel_io->lcd_cmd_bits / 8;
|
||||
if (cmds_size > 0 && cmds_size <= sizeof(cmds)) {
|
||||
memcpy(write_buffer + write_size, cmds + (sizeof(cmds) - cmds_size), cmds_size);
|
||||
write_size += cmds_size;
|
||||
cmd_buffer = cmds + (sizeof(cmds) - cmds_size);
|
||||
cmd_buffer_size = cmds_size;
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t *lcd_buffer = NULL;
|
||||
size_t lcd_buffer_size = 0;
|
||||
if (buffer) {
|
||||
memcpy(write_buffer + write_size, buffer, buffer_size);
|
||||
write_size += buffer_size;
|
||||
lcd_buffer = (uint8_t*)buffer;
|
||||
lcd_buffer_size = buffer_size;
|
||||
}
|
||||
|
||||
ESP_GOTO_ON_ERROR(i2c_master_transmit(i2c_panel_io->i2c_handle, write_buffer, write_size, -1), err, TAG, "i2c transaction failed");
|
||||
free(write_buffer);
|
||||
i2c_master_transmit_multi_buffer_info_t lcd_i2c_buffer[3] = {
|
||||
{.write_buffer = &control_phase_byte, .buffer_size = control_phase_size},
|
||||
{.write_buffer = cmd_buffer, .buffer_size = cmd_buffer_size},
|
||||
{.write_buffer = lcd_buffer, .buffer_size = lcd_buffer_size},
|
||||
};
|
||||
|
||||
ESP_GOTO_ON_ERROR(i2c_master_multi_buffer_transmit(i2c_panel_io->i2c_handle, lcd_i2c_buffer, sizeof(lcd_i2c_buffer) / sizeof(i2c_master_transmit_multi_buffer_info_t), -1), err, TAG, "i2c transaction failed");
|
||||
if (!is_param) {
|
||||
// trans done callback
|
||||
if (i2c_panel_io->on_color_trans_done) {
|
||||
@ -184,9 +192,6 @@ static esp_err_t panel_io_i2c_tx_buffer(esp_lcd_panel_io_t *io, int lcd_cmd, con
|
||||
|
||||
return ESP_OK;
|
||||
err:
|
||||
if (write_buffer) {
|
||||
free(write_buffer);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user