Closed cpehonk closed 7 months ago
Yes, I already notice this. And it has been fixed internally. I think it will sync to github very quickly.
A quicker way if you want to try is to find s_i2c_read_command
function. Copy-paste following code.
static bool s_i2c_read_command(i2c_master_bus_handle_t i2c_master, i2c_operation_t *i2c_operation, uint8_t *fifo_fill, BaseType_t *do_yield)
{
i2c_master->async_break = false;
const size_t remaining_bytes = i2c_operation->total_bytes - i2c_operation->bytes_used;
const i2c_ll_hw_cmd_t hw_end_cmd = {
.op_code = I2C_LL_CMD_END
};
i2c_hal_context_t *hal = &i2c_master->base->hal;
i2c_bus_handle_t handle = i2c_master->base;
i2c_ll_hw_cmd_t hw_cmd = i2c_operation->hw_cmd;
*fifo_fill = MIN(remaining_bytes, SOC_I2C_FIFO_LEN - i2c_master->read_len_static);
i2c_master->rx_cnt = *fifo_fill;
hw_cmd.byte_num = *fifo_fill;
i2c_master->contains_read = true;
#if !SOC_I2C_STOP_INDEPENDENT
if (remaining_bytes < SOC_I2C_FIFO_LEN - 1) {
if (i2c_operation->hw_cmd.ack_val == 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;
i2c_master->cmd_idx++;
}
i2c_master->read_buf_pos = i2c_master->trans_idx;
} else {
i2c_ll_master_write_cmd_reg(hal->dev, hw_cmd, i2c_master->cmd_idx);
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);
}
}
} else {
atomic_store(&i2c_master->status, I2C_STATUS_READ);
portENTER_CRITICAL_SAFE(&handle->spinlock);
i2c_ll_master_write_cmd_reg(hal->dev, hw_cmd, i2c_master->cmd_idx);
i2c_ll_master_write_cmd_reg(hal->dev, hw_end_cmd, i2c_master->cmd_idx + 1);
if (i2c_master->async_trans == false) {
i2c_hal_master_trans_start(hal);
} else {
i2c_master->async_break = true;
}
portEXIT_CRITICAL_SAFE(&handle->spinlock);
}
#else
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 (i2c_operation->total_bytes == 0) {
i2c_master->trans_idx++;
hw_cmd = i2c_master->i2c_trans.ops[i2c_master->trans_idx].hw_cmd;
i2c_master->i2c_trans.cmd_count--;
}
}
i2c_ll_master_write_cmd_reg(hal->dev, hw_cmd, i2c_master->cmd_idx);
i2c_ll_master_write_cmd_reg(hal->dev, hw_end_cmd, i2c_master->cmd_idx + 1);
portEXIT_CRITICAL_SAFE(&handle->spinlock);
i2c_master->status = I2C_STATUS_READ;
portENTER_CRITICAL_SAFE(&handle->spinlock);
if (i2c_master->async_trans == false) {
i2c_hal_master_trans_start(hal);
} else {
i2c_master->async_break = true;
}
portEXIT_CRITICAL_SAFE(&handle->spinlock);
#endif
return i2c_master->async_break;
}
Thx, that does the job! :)
Answers checklist.
IDF version.
v5.2 master branch
Espressif SoC revision.
ESP32 Rev1.0
Operating System used.
Windows
How did you build your project?
Command line with Make
If you are using Windows, please specify command line type.
PowerShell
Development Kit.
WEMOS LOLIN32 (ESP32 WROVER)
Power Supply used.
USB
What is the expected behavior?
example: read chip revision of BME280 => i2c_master_transmit_receive should deliver chip revision byte
What is the actual behavior?
i2c_master_transmit_receive blocks forever, regardless if a timeout value != -1 is specified
Steps to reproduce.
esp_err_t i2c_master_bus_read_byte(i2c_master_dev_handle_t dev_handle, uint8_t mem_address, uint8_t data) { uint8_t buf[1] = {mem_address}; uint8_t buffer[1]; esp_err_t ret = i2c_master_transmit_receive(dev_handle, buf, 1, buffer, 1, CONFIG_I2C_TIMEOUT); data = buffer[0]; return ret; }
void app_main(void) { i2c_master_bus_config_t conf = { .i2c_port = -1, .sda_io_num = GPIO_NUM_23, .scl_io_num = GPIO_NUM_19, .clk_source = I2C_CLK_SRC_DEFAULT, .glitch_ignore_cnt = 7, };
Debug Logs.
More Information.
I traced it down to function s_i2c_send_commands (i2c_master.c #423). i2c_hal_master_trans_start(hal); never returns...