I2C reading data from MPU 9265

dforeman
Posts: 3
Joined: Sun Sep 13, 2020 8:57 pm

I2C reading data from MPU 9265

Postby dforeman » Sun Sep 13, 2020 9:46 pm

I've been trying to read a register from a MPU 9265 9DOF IMU, but I have been continuously met by an error code (-1) each read.
I have run code on an Arduino to verify that the IMU works, and it works fine. That code is here (https://www.luisllamas.es/usar-arduino- ... -mpu-9250/)I have written data (1 byte each time) to the IMU, and it has gone through fine. However, it stubbornly refuses to read anything off the sensor.

I have omitted the config code for brevity. However, it must be correct, as it has successfully written to a device register.
Here is the working write code:

Code: Select all

esp_err_t I2C::i2c_master_write_slave(uint8_t *data_wr, size_t size, uint8_t register2set)
{ //see above for comments
    if (size == 0)
    {
        return ESP_OK;
    }
    if (register2set > 0xEF)
    {
        return ESP_FAIL;
    }
    i2c_cmd_handle_t cmd = i2c_cmd_link_create();
    i2c_master_start(cmd);
    std::cout<<"slavewrite status: "<<i2c_master_write_byte(cmd, (slaveaddress << 1) | I2C_MASTER_WRITE, ACK_CHECK_EN)<<std::endl;
    std::cout<<"registerwrite status: "<<i2c_master_write_byte(cmd, register2set, ACK_CHECK_EN)<<std::endl;
    std::cout<<"data status: "<<i2c_master_write(cmd, data_wr, size, ACK_CHECK_EN)<<std::endl;
    std::cout<<"stop status: "<<i2c_master_stop(cmd)<<std::endl;
    esp_err_t ret = i2c_master_cmd_begin(I2C_NUM_0, cmd, 1000 / portTICK_RATE_MS);
    i2c_cmd_link_delete(cmd);
    return ret;
}



And here is the code that is not working for reading data

Code: Select all

esp_err_t I2C::i2c_master_read_slave(uint8_t *data_rd, size_t size, uint8_t register2get)
{
    if (size == 0)
    {
        return ESP_OK;
    }
    if (register2get > 0xEF)
    {
        return ESP_FAIL;
    }
    i2c_cmd_handle_t cmd = i2c_cmd_link_create();
    i2c_master_start(cmd);
    i2c_master_write_byte(cmd, (slaveaddress << 1) | I2C_MASTER_WRITE, ACK_CHECK_EN);
    i2c_master_write_byte(cmd, register2get, ACK_CHECK_EN);
    i2c_master_start(cmd);
    i2c_master_write_byte(cmd, (slaveaddress << 1) | I2C_MASTER_READ, ACK_CHECK_EN);
    if (size > 1)
    {   
        i2c_master_read(cmd, data_rd, size - 1, ACK_VAL);
    }
    i2c_master_read_byte(cmd, data_rd + size - 1, NACK_VAL);
    i2c_master_stop(cmd);
    auto ret=i2c_master_cmd_begin(I2C_NUM_0, cmd, 1000 / portTICK_RATE_MS);    
    i2c_cmd_link_delete(cmd);
    return ret;
Here is another hopeful version of this code that is somehow actually failing at the write to registry part of the read:

Code: Select all

i2c_cmd_handle_t cmd = i2c_cmd_link_create();
    i2c_master_start(cmd);
    i2c_master_write_byte(cmd, (slaveaddress << 1) | I2C_MASTER_WRITE, ACK_CHECK_EN);
    i2c_master_write_byte(cmd, register2get, ACK_CHECK_EN);
    i2c_master_stop(cmd);
    auto ret=i2c_master_cmd_begin(I2C_NUM_0, cmd, 1000 / portTICK_RATE_MS);    
    i2c_cmd_link_delete(cmd);

    cmd = i2c_cmd_link_create();
    i2c_master_start(cmd);
    i2c_master_write_byte(cmd, (slaveaddress << 1) | I2C_MASTER_READ, ACK_CHECK_EN);
    if (size > 1)
    {   
        i2c_master_read(cmd, data_rd, size - 1, ACK_VAL);
    }
    i2c_master_read_byte(cmd, data_rd + size - 1, NACK_VAL);
    i2c_master_stop(cmd);
    i2c_master_cmd_begin(I2C_NUM_0, cmd, 1000 / portTICK_RATE_MS);    
    i2c_cmd_link_delete(cmd);
    return ret;

My code to call the write is here in abridged form. It is an adaptation of the code used successfully by the arduino:

Code: Select all

I2C MPU9250(MPU9250_ADDRESS);
//Buf is the pointer to the length 14 buffer
uint8_t Buf[14];
std::cout<<"IMU Read Status: "<<MPU9250.i2c_master_read_slave(Buf, 1, 0x3B)<<std::endl;
//this always prints -1, which means that it failed.
As far as I can tell, both the read and write are correct according to I2C protocol and this forum post, but only the writing to registry actually seems to work:
https://www.esp32.com/viewtopic.php?t=3678


I'm at my wit's end as to why this keeps failing. I've tried all sorts of spurious combinations of commands in hopes that one would work, and so far, the only one that doesn't give the generic failure code (-1) is the one where it simply starts and ends an I2C transmission, which errors in a timeout error instead of a generic -1 error. None of the demo code online for I2C has worked for the writing part either. Does anyone have an idea what is wrong with the code to read from the IMU's register?



***Edit 9/14/2020***
After probing the SCL and SDA lines, it seems as though the ESP32 cannot actually transmit at the advertised speeds of 100KHz. The fastest it goes is actually only 100Hz, or 200Hz with certain combinations of external resistors. After dropping the speed 3 orders of magnitude, it actually outputs a clock signal and can start trying to communicate with other devices.

I'm now getting error 263, which is an error timeout. It's progress, but just barely. Also, it doesn't seem like I'm the only one to have this issue with reading from IMU sensors on the ESP32 platform:
https://www.reddit.com/r/esp32/comments ... c_timeout/

ESP_Sprite
Posts: 8921
Joined: Thu Nov 26, 2015 4:08 am

Re: I2C reading data from MPU 9265

Postby ESP_Sprite » Tue Sep 15, 2020 11:07 am

That sounds vague... you're saying your setup code is correct as it does write a device register, then you notice electrical-level strangeness on the lines? Are you sure the write you did actually was correct? Can you post your initialization code anyway?

dforeman
Posts: 3
Joined: Sun Sep 13, 2020 8:57 pm

Re: I2C reading data from MPU 9265

Postby dforeman » Wed Sep 16, 2020 3:39 am

As far as I can tell, clocking above 100Hz somehow downclocks to somewhere between 2-5Hz, which causes transmission failures. I thought this was very strange, but I tried it on two ESP32s, one brand new, and they both had this strange issue. Perhaps it is the Espressif board that is causing it somehow, because that's the only other thing they had in common besides code.

Here is the initialization code I use to configure the ESP32 as a master.

Code: Select all

void I2C::configureMaster()
{
    i2c_config_t config;

    config.mode = I2C_MODE_MASTER;
    config.sda_io_num = static_cast<gpio_num_t>(18);
    config.scl_io_num = static_cast<gpio_num_t>(19); 
    //For the actual device, using external pull-up resistors are recommended
    config.sda_pullup_en = GPIO_PULLUP_DISABLE;
    config.scl_pullup_en = GPIO_PULLUP_DISABLE;
    config.master.clk_speed = 1 * 100;

    //for some reason, it doesn't error when you put numbers too high.  
    //clock speed of 100 works.
    //it seems anything above 100 fails for some reason.  Probably an unmentioned software limit.
    //arduino has 77Hz frequency.

    std::cout << "Config status: " << (int)i2c_param_config(I2C_NUM_0, &config) << std::endl;
    std::cout << "Driver status: " << (int)i2c_driver_install(I2C_NUM_0, config.mode, 0, 0, 0) << std::endl;
    //values return 0, meaning both configs are working properly.
};
I have external pullup resistors, and I've tried it with the internal pullups enabled but still encounter the same issue.

I was also very confused with how the device was writing multiple times to registers so quickly, as the clock speed seemed abnormally slow. However, I think the ESP32 is writing something because when I pull out the data cables and re-run the code, the parts that write to register indicate that they failed like one would expect, which implies there is some sort of affirmative communication (ACK) being sent by the sensor after being written to.

ESP_Sprite
Posts: 8921
Joined: Thu Nov 26, 2015 4:08 am

Re: I2C reading data from MPU 9265

Postby ESP_Sprite » Wed Sep 16, 2020 8:56 am

Don't use initialization structs like this: `i2c_config_t config;` allocates the struct on stack, which pre-fills it with whatever random shit is on the stack, meaning that unless you fill every single entry in the struct, some are going to contain garbage. Suggest changing to ` i2c_config_t config={};`instead to zero-initialize it. (In esp-idf, zero by default is a good value for uninitialized members.)

dforeman
Posts: 3
Joined: Sun Sep 13, 2020 8:57 pm

Re: I2C reading data from MPU 9265

Postby dforeman » Wed Sep 16, 2020 3:46 pm

I've retried the code using the initialization brackets to zero the struct, but the error still remains (263 timeout error). Do you think that there could be something wrong with the timeout limit? I've tried making it larger or smaller, but the problem still remains that it is thinking it has not received any ACK signal from the sensor.

Who is online

Users browsing this forum: Bing [Bot] and 137 guests