espressif / esp-idf

Espressif IoT Development Framework. Official development framework for Espressif SoCs.
Apache License 2.0
13.53k stars 7.26k forks source link

i2c_master_read_from_device causes crash (IDFGH-10031) #11308

Open tobiaseul opened 1 year ago

tobiaseul commented 1 year ago

Answers checklist.

IDF version.

ESP-IDF v5.2-dev-350-g56123c52aa-dirty

Operating System used.

Linux

How did you build your project?

Command line with idf.py

If you are using Windows, please specify command line type.

None

Development Kit.

ESP32-WROOM-32 dev kit

Power Supply used.

USB

What is the expected behavior?

Function should return ESP_OK

What is the actual behavior?

But crashes

Steps to reproduce.

I have following code:

constexpr int I2C_IFACE1 = 0; constexpr int I2C_SDA_PIN = 21; constexpr int I2C_SCL_PIN = 22; constexpr int I2C_FREQ_HZ = 400000; constexpr int I2C_TIMEOUT_MS = 20;

i2c_config_t i2cConfig = {};

i2cConfig.mode = I2C_MODE_MASTER; i2cConfig.sda_io_num = I2C_SDA_PIN; i2cConfig.scl_io_num = I2C_SCL_PIN; i2cConfig.sda_pullup_en = GPIO_PULLUP_ENABLE; i2cConfig.scl_pullup_en = GPIO_PULLUP_ENABLE; i2cConfig.master.clk_speed = I2C_FREQ_HZ;

I2C::SPtr i2c = std::make_shared(I2C_IFACE1, I2C_TIMEOUT_MS, i2cConfig);

I2C::I2C(int p_interface, int p_timeout, i2c_config_t p_config): m_interface(p_interface), m_timeout(p_timeout), m_config(p_config) { i2c_param_config(static_cast(m_interface), &m_config); i2c_driver_install(static_cast(m_interface), m_config.mode, 0, 0, 0); }

esp_err_t I2C::readRegister(uint8_t p_i2cAddr, uint8_t p_regAddr, std::vector& p_data, size_t p_len){

uint8_t data[p_len];
int ret = i2c_master_read_from_device(static_cast<i2c_port_t>(m_interface), p_i2cAddr, data, p_len, m_timeout / configTICK_RATE_HZ);

p_data = std::vector<int8_t>(data, data + sizeof(data) / sizeof(data[0]));  
return ret;

}

By running this code:

constexpr uint8_t I2C_ADDR = 0x68; constexpr uint8_t REG_GYRO_X = 0x43;

std::vector data = {}; m_i2c->readRegister(I2C_ADDR, REG_GYRO_X, data, 6);

Then it crashes at /esp/esp-idf/components/driver/i2c/i2c.c:1368

Debug Logs.

Guru Meditation Error: Core  0 panic'ed (StoreProhibited). Exception was unhandled.

Core  0 register dump:
PC      : 0x40084bdd  PS      : 0x00060031  A0      : 0x800847d5  A1      : 0x3ffb0e30  
0x40084bdd: i2c_master_cmd_begin_static at /home/tobias/esp/esp-idf/components/driver/i2c/i2c.c:1368

A2      : 0x0006f845  A3      : 0x00000000  A4      : 0x3ffb78e5  A5      : 0x00000000  
A6      : 0x00060923  A7      : 0x3ffb0e30  A8      : 0x00000000  A9      : 0x3ffb83d0  
A10     : 0x00000003  A11     : 0x3ffb7630  A12     : 0x00060023  A13     : 0x00000000  
A14     : 0x00060023  A15     : 0x3ffb8370  SAR     : 0x0000001d  EXCCAUSE: 0x0000001d  
EXCVADDR: 0x0006f84d  LBEG    : 0x4000c2e0  LEND    : 0x4000c2f6  LCOUNT  : 0xffffffff  

Backtrace: 0x40084bda:0x3ffb0e30 0x400847d2:0x3ffb0f10 0x4008426d:0x3ffb0fd0 0x4000bfed:0x3ffb76f0 0x4008edaf:0x3ffb7700 0x4008b7b2:0x3ffb7720 0x400e1571:0x3ffb7770 0x400e0c07:0x3ffb77e0 0x400db9a9:0x3ffb78e0 0x400daac1:0x3ffb7950 0x400dabcc:0x3ffb7990 0x400dca35:0x3ffb79e0 0x40120909:0x3ffb7a10 0x400d9545:0x3ffb7a40 0x400d9597:0x3ffb7c70 0x401249a4:0x3ffb7cb0
0x40084bda: i2c_master_cmd_begin_static at /home/tobias/esp/esp-idf/components/driver/i2c/i2c.c:1368

0x400847d2: i2c_isr_handler_default at /home/tobias/esp/esp-idf/components/driver/i2c/i2c.c:549

0x4008426d: _xt_lowint1 at /home/tobias/esp/esp-idf/components/xtensa/xtensa_vectors.S:1226

0x4008edaf: vPortClearInterruptMaskFromISR at /home/tobias/esp/esp-idf/components/freertos/FreeRTOS-Kernel/portable/xtensa/include/freertos/portmacro.h:568
 (inlined by) vPortExitCritical at /home/tobias/esp/esp-idf/components/freertos/FreeRTOS-Kernel/portable/xtensa/port.c:532

0x4008b7b2: xQueueReceive at /home/tobias/esp/esp-idf/components/freertos/FreeRTOS-Kernel/queue.c:1576

0x400e1571: i2c_master_cmd_begin at /home/tobias/esp/esp-idf/components/driver/i2c/i2c.c:1549

0x400e0c07: i2c_master_read_from_device at /home/tobias/esp/esp-idf/components/driver/i2c/i2c.c:1037

0x400db9a9: I2C::readRegister(unsigned char, unsigned char, std::vector<signed char, std::allocator<signed char> >&, unsigned int) at /home/tobias/Documents/Drone/build/../main/i2c.cpp:24

0x400daac1: Mpu6050::readGyroValues() at /home/tobias/Documents/Drone/build/../main/mpu6050.cpp:32

More Information.

I have tryed multiple dev boards to ensure it isn't a hardware defact.

I had this code running ~2 years back, with an older version of idf. But i have no more information about the version i used back then.

This error is like errors from v4.4 (https://github.com/espressif/esp-idf/issues/8348) but this is allready fixed.

o-marshmallow commented 1 year ago

Hello @tobiaseul ,

This part of the I2C has not been changed for the past few months, have you tried to use git-bisect to see which commit broke your program? I suspect it could be a side-effect.

In fact, in your code you are using an array on the stack with a variable length uint8_t data[p_len];. In the current situation, I don't think that's the problem because 6 is a reasonable amount of bytes to allocate, but overall, this can be dangerous and not recommended in embedded systems, mainly when the memory is limited.

Can you try something like:

esp_err_t I2C::readRegister(uint8_t p_i2cAddr, uint8_t p_regAddr, std::vector<int8_t>& p_data, size_t p_len)
{
    p_data.resize(p_len);
    int ret = i2c_master_read_from_device(static_cast<i2c_port_t>(m_interface), p_i2cAddr, p_data.data(), p_len, m_timeout / configTICK_RATE_HZ);
    return ret;
}

Moreover, I notice that you are not using register address, so you are reading from the device without giving a register address, you should use i2c_master_write_read_device instead:

esp_err_t I2C::readRegister(uint8_t p_i2cAddr, uint8_t p_regAddr, std::vector<int8_t>& p_data, size_t p_len)
{
    p_data.resize(p_len);
    int ret = i2c_master_write_read_device(static_cast<i2c_port_t>(m_interface), p_i2cAddr, 
                                                                   &p_regAddr, sizeof(uint8_t),
                                                                   p_data.data(), p_len, m_timeout / configTICK_RATE_HZ);
    return ret;
}

Out of curiosity, why not using the CXX I2C API? You can find it here: https://github.com/espressif/esp-idf-cxx/blob/main/include/i2c_cxx.hpp