I2C bus stuck after enable/disable I2C master mode

I am using the following hardware:

  1. stm32f401ccu6+ mpu9250 (or rather 6500 - without a magnetometer)
  2. esp32 + mpu9250 (or rather 6500 - without a magnetometer)
    Software:
  3. arduino IDE 1.8.19
  4. example code from here.
    I know for sure that my MPU9250 is fake and does not have a magnetometer.
    But ... now I am conducting an experiment, I take ESP32 + MPU9250 and STM32F4 + MPU9250.
    I flash these two microcontrollers with the same code, of course, for STM32 I choose the core, and for ESP32 I choose the core.
    These cores have different wire.cpp files.
    But the point is not that, on each microcontroller, I compare with the help of a logic analyzer what happens on the I2C bus when the microcontroller communicates with the MPU9250 board.
    So, when I run the code on STM32 + MPU9250, packet transmission starts on the I2C bus.
    The first packet has 3 bytes, then after 99.6ms another packet of 31 bytes, and then after 2.9ms the last packet of 30 bytes and with that all activity on the bus stops.
    In this case, of course, the MPU9250 does not transmit any data to the bus, and nothing is output to the serial.

    It is impossible to make screenshots in detail, because it is very small and you get a lot of information.
    When I load the code into ESP32 + MPU9250, miracles happen.
    Firstly, the data from the MPU9250 board goes to the serial port.
    Of course, the magnetometer does not give anything - because it does not exist!
    Скриншот 20-07-2023 21 21 56
    But, what is going on on the I2C bus?
    And what happens on the bus is approximately the same as on the STM32F4 bus, only there are differences.

    Packet transmission also starts with 3 bytes, and is similar to the packet in STM32F4.
    Then, after 99.3 ms, there is also a packet of 31 bytes and it is similar to the packet in STM32F4.
    But the next packet is different ... it consists of 26 bytes, i.e. 4 bytes shorter than STM32F4.
    Data from the signal analyzer of the third package from STM32F4 + MPU9250 below

    Data on the I2C bus on the STM32F4
1.
write to 0x68 ack data: 0x6B 0x80 
2.
write to 0x68 ack data: 0x6B 0x00 
write to 0x68 ack data: 0x1D 0x48 
write to 0x68 ack data: 0x1B 0x18 
write to 0x68 ack data: 0x1C 0x00 
write to 0x68 ack data: 0x1A 0x03 
write to 0x68 ack data: 0x19 0x13 
write to 0x68 ack data: 0x1A 0x04 
write to 0x68 ack data: 0x38 0x00 
write to 0x68 ack data: 0x6A 
read to 0x68 ack data: 0x00
write to 0x68 ack data: 0x6A 0x00 
3.
write to 0x68 ack data: 0x37 0x82 
write to 0x0C nak
read to 0x0C nak
write to 0x0D nak
read to 0x0D nak
write to 0x0E nak
read to 0x0E nak
write to 0x0F nak
read to 0x0F nak
write to 0x68 ack data: 0x34 0x04 
write to 0x68 ack data: 0x6B 0x40 
write to 0x68 ack data: 0x6C 0x3F 
write to 0x68 ack data: 0x6A 
read to 0x68 ack data: 0x00
write to 0x68 ack data: 0x64 0x10 
write to 0x68 ack data: 0x6A 0x00 
Stop

Data from the signal analyzer of the third package from ESP32 + MPU9250 below


Data on the I2C bus on the ESP32 in table

1.
write to 0x68 ack data: 0x6B 0x80 
2.
write to 0x68 ack data: 0x6B 0x00 
write to 0x68 ack data: 0x1D 0x48 
write to 0x68 ack data: 0x1B 0x18 
write to 0x68 ack data: 0x1C 0x00 
write to 0x68 ack data: 0x1A 0x03 
write to 0x68 ack data: 0x19 0x13 
write to 0x68 ack data: 0x1A 0x04 
write to 0x68 ack data: 0x38 0x00 
write to 0x68 ack data: 0x6A 
read to 0x68 ack data: 0x00
write to 0x68 ack data: 0x6A 0x00 
3.
write to 0x68 ack data: 0x37 0x82 
write to 0x0C nak
write to 0x0D nak
write to 0x0E nak
write to 0x0F nak
write to 0x68 ack data: 0x34 0x04 
write to 0x68 ack data: 0x6B 0x40 
write to 0x68 ack data: 0x6C 0x3F 
write to 0x68 ack data: 0x6A 
read to 0x68 ack data: 0x00
write to 0x68 ack data: 0x64 0x10 
write to 0x68 ack data: 0x6A 0x00 
4.
write to 0x68 ack data: 0x6B 0x01 
write to 0x68 ack data: 0x6C 0x00 
write to 0x68 ack data: 0x6A 
read to 0x68 ack data: 0x00
write to 0x68 ack data: 0x64 0x11 
write to 0x68 ack data: 0x6A 0x20 
5.
write to 0x68 ack data: 0x6B 0x01 
write to 0x68 ack data: 0x6C 0x00 
write to 0x68 ack data: 0x6A 
read to 0x68 ack data: 0x20
write to 0x68 ack data: 0x64 0x11 
write to 0x68 ack data: 0x6A 0x20 
6. Data...
write to 0x68 ack data: 0x1A 0x06 
write to 0x68 ack data: 0x19 0x63 
write to 0x68 ack data: 0x34 0x00 
write to 0x68 ack data: 0x34 0x00 
write to 0x68 ack data: 0x3A 
read to 0x68 ack data: 0x05
write to 0x68 ack data: 0x3B 
read to 0x68 ack data: 0xDE 0xF8 0xCE 0x50 0xEF 0x08
write to 0x68 ack data: 0x43 
read to 0x68 ack data: 0xFF 0xB3 0x00 0x2B 0x00 0x1D
write to 0x68 ack data: 0x49 
read to 0x68 ack data: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
write to 0x68 ack data: 0x3A 
read to 0x68 ack data: 0x00
write to 0x68 ack data: 0x3A 
read to 0x68 ack data: 0x00
write to 0x68 ack data: 0x3A 
read to 0x68 ack data: 0x00
write to 0x68 ack data: 0x3A 
read to 0x68 ack data: 0x00
write to 0x68 ack data: 0x3A 
read to 0x68 ack data: 0x00
write to 0x68 ack data: 0x3A 
read to 0x68 ack data: 0x00
write to 0x68 ack data: 0x3A 
read to 0x68 ack data: 0x00
write to 0x68 ack data: 0x3A 

ESP32 on the left, STM32F4 on the right.


For STM32F4, communication on the I2C bus ends with 3 packets.
For ESP32 after three packet of data, activity on the I2C bus continues .
After the third packet of data, after 49.9 ms there is a packet of data consisting of 16 bytes, and then, also after 49.9 ms, another packet of data consisting of 16 bytes.

Well, then, after 50.1 ms, the actual data transfer from the MPU9250 begins and this data is output to the ESP32 serial port.

I don't understand what's wrong with my STM32F4 or MPU9250?
The I2C bus on STM32F4 works, but stops working.
@fpistm everything works for you ...
I noticed that in the wire.cpp file of the ESP32 there is no bit shift to the left for the device address, in the wire.cpp file of the STM core this happens.

  ownAddress = address << 1;

  _i2c.isMaster = (address == MASTER_ADDRESS) ? 1 : 0;

  _i2c.generalCall = (generalCall == true) ? 1 : 0;

  _i2c.NoStretchMode = (NoStretchMode == true) ? 1 : 0;

  recoverBus(); // in case I2C bus (device) is stuck after a reset for example

  i2c_custom_init(&_i2c, 100000, I2C_ADDRESSINGMODE_7BIT, ownAddress);

I tried to remove the bit shift of the address, but there are no changes in the work.
Only a different address is written to the I2C bus, apparently in the ESP32 core, the device address is shifted elsewhere(or file) in order to have a 7-bit address.
...
Termination of activity on the I2C bus occurs after the execution of the code

Pack 1
write to 0x68 ack data: 0x6B 0x80  //inv_mpu.c string 652 pwr_mgmt_1
Pack 2
write to 0x68 ack data: 0x6B 0x00  //inv_mpu.c 658 pwr_mgmt_1
write to 0x68 ack data: 0x1D 0x48  //inv_mpu.c 668 accel_cfg2
write to 0x68 ack data: 0x1B 0x18  //inv_mpu.c 1171 gyro_cfg
write to 0x68 ack data: 0x1C 0x00  //inv_mpu.c 1236 accel_cfg
write to 0x68 ack data: 0x1A 0x03  //inv_mpu.c 1305/1368 lpf
write to 0x68 ack data: 0x19 0x13  //inv_mpu.c 1358 rate_div
write to 0x68 ack data: 0x1A 0x04  //inv_mpu.c 1361 lpf
write to 0x68 ack data: 0x38 0x00  //inv_mpu.c 579 int_enable
write to 0x68 ack data: 0x6A       //user_ctrl, mpu_set_bypass
read to 0x68 ack data: 0x00
write to 0x68 ack data: 0x6A 0x00  //user_ctrl
Pack 3
write to 0x68 ack data: 0x37 0x82 //inv_mpu.c 2868 mpu_set_bypass(1)
/* Find compass. Possible addresses range from 0x0C to 0x0F. */
write to 0x0C nak                 //inv_mpu.c 2871 find compass - no
read to 0x0C nak
write to 0x0D nak
read to 0x0D nak
write to 0x0E nak
read to 0x0E nak
write to 0x0F nak
read to 0x0F nak//Compass not found
write to 0x68 ack data: 0x34 0x04 //inv_mpu.c 1408 s4_ctrl
write to 0x68 ack data: 0x6B 0x40 
write to 0x68 ack data: 0x6C 0x3F 
write to 0x68 ack data: 0x6A 
read to 0x68 ack data: 0x00
write to 0x68 ack data: 0x64 0x10 //inv_mpu.c 1614 s1_do
write to 0x68 ack data: 0x6A 0x00 //inv_mpu.c 1617
Stop

Simple code works great on stm32f401ccu6+ mpu9250

#include "Wire.h"
const int MPU_addr = 0x68; // sensor address
// data array
// [accX, accY, accZ, temp, gyrX, gyrY, gyrZ]
// acc - acceleration, gyr - angular velocity, temp - temperature (raw)
int16_t data[7];  
void setup() {
  // initialization
  Wire.begin();
  Wire.beginTransmission(MPU_addr);
  Wire.write(0x6B);  // PWR_MGMT_1 register
  Wire.write(0);     // set to zero (wakes up)
  Wire.endTransmission(true);
  
  Serial.begin(115200);
}
void loop() {
  getData();  // get data
  // print
  for (byte i = 0; i < 7; i++) {
    Serial.print(data[i]);
    Serial.print('\t');
  }
  Serial.println();
  delay(200);
}
void getData() {
  Wire.beginTransmission(MPU_addr);
  Wire.write(0x3B);  // starting with register 0x3B (ACCEL_XOUT_H)
  Wire.endTransmission(false);
  Wire.requestFrom(MPU_addr, 14, true); // request a total of 14 registers
  for (byte i = 0; i < 7; i++) {
    data[i] = Wire.read() << 8 | Wire.read();
  }
}

and I get raw data ACCEL_XOUT_H on I2C

write to 0x68 ack data: 0x6B 0x00 
write to 0x68 ack data: 0x3B 
read to 0x68 ack data: 0xF2 0x4C 0x00 0xC8 0x41 0x88 0x0E 0x20 0xFD 0xAB 0x01 0x93 0x00 0x9A
write to 0x68 ack data: 0x3B 
read to 0x68 ack data: 0xF2 0x68 0x00 0xA0 0x41 0x7C 0x0E 0x70 0xFD 0xBA 0x01 0x86 0x00 0xB8
write to 0x68 ack data: 0x3B 
read to 0x68 ack data: 0xF2 0x50 0x00 0xAC 0x41 0x8C 0x0E 0x70 0xFD 0xA0 0x01 0x8E 0x00 0xAC
write to 0x68 ack data: 0x3B 
read to 0x68 ack data: 0xF2 0x34 0x00 0xD0 0x41 0x20 0x0E 0x50 0xFD 0xA5 0x01 0x74 0x00 0xA1
write to 0x68 ack data: 0x3B 
read to 0x68 ack data: 0xF2 0x90 0x00 0x90 0x41 0x94 0x0E 0x40 0xFD 0xA2 0x01 0x6B 0x00 0xBB
write to 0x68 ack data: 0x3B 
read to 0x68 ack data: 0xF2 0x98 0x01 0x10 0x41 0x7C 0x0E 0x50 0xFD 0x97 0x01 0x6D 0x00 0xE1

and Serial.
Скриншот 21-07-2023 15 53 25
I also found that the core uses a not very fresh Wire library, but everything works for others, it doesn’t work only with my hardware (I have 3 BlackPills).
What could be the problem?

You took a deep dive, but even without touching the water with my big toe, I can feel that something is wrong.

First of all, this is not how to solve a problem. You need a I2C device that is known to be good and working and you need a library that is known to work with that I2C device.
Then it is important to make small steps.
Let a I2C Scanner run for hour and keep track of all the misses.
Then try to read the WHO_AM_I register.

Your STM32 core is not by Arduino.
Arduino has the Nicla Vision with a STM32. For that board, the Arduino software layer is on top of Mbed. It has its own variant here: https://github.com/arduino/ArduinoCore-mbed/tree/main/variants/NICLA_VISION

Your ESP32 core is also not by Arduino but by Espressif. That is no problem, it reliable and good.

Can you show a photo, so we can see the wiring: if you use 3.3V or 5V, if there is a voltage regulator on the sensor module that drops the voltage for the sensor too much, if there are pullup resistors or maybe too much pullup, how your grounding is, and so on.

Could you to upgrade to Arduino 2.1.1 ?

Do you see that I'm still miles away from the details that you gathered ? Your sensor chip could be running at 2.3V with the wrong amount of pullup. You could even have a flat ribbon cable with SDA next to SCL :scream:

1 Like

Thank you for your response.
I've been using the core for a long time, and it suits me.
With mbed there were thoughts to figure it out, but I still can’t find the time.
Arduino IDE 1.8.19 suits quite well, especially since I don’t use it, I do everything through Arduino-Cli.
The I2C bus works fine, pull-up with 4.7 kΩ resistors to 3.3 volts.
With stm32f4ccu6 on the I2C bus, the BMP180 sensor and the gyro / axel BMI160 work fine.
While the mpu9250 has been put aside, anyway, without a magnetometer, it will not be useful to me, because. I can't calculate the quaternions, and without a magnetometer, I can't eliminate the drift of the gyroscope.


I wrote about the problem, because only with the example from SparkFan on the I2C bus something strange happens, namely, the termination of work after three packets.

The are too many uncertainties.

That your I2C bus works, that does not mean that it is good.
That the Sparkfun example causes a problem, that does not mean that it is bad.

Since it is a fake sensor, can you let it rest ? Move on. Use a real sensor.

1 Like

In fact, I think everything is simple there, well, for those who understand.
If the I2C bus didn't work at all, it wouldn't work for other devices either.
If it did not work for MPU9250, it would not start sending packets.


If the I2C bus was not working and the MPU9250 sensor was faulty, it would not provide data with a simple code with raw data.
f4fe677e-b6f1-4972-b8d1-172f5dcf859e
It seems to me that the problem is that the example from SparkFan is not suitable for STM32F401CCU6, I just do not have enough programming skills to figure out how to rewrite the library.

I agree that the most logical explanation is the combination of the Sparkfun code with the stm32duino implementation of the Wire library, but I don't think it is simple. The hardware might be part of it as well.

I'm not familiar with the STM32 implementation of the Wire library.
The Arduino layer (on top of Mbed) for the STM32 is specifically for the Nicla Vision. It will probably not work on your board, you don't have to try it.

The Sparkfun code uses the Wire library in a normal way: https://github.com/sparkfun/SparkFun_MPU-9250-DMP_Arduino_Library/blob/master/src/util/arduino_mpu9250_i2c.cpp
But this file is complex and has while-loops: https://github.com/sparkfun/SparkFun_MPU-9250-DMP_Arduino_Library/blob/master/src/util/inv_mpu.c

:arrow_right: Have you seen this Issue: Mystical oddities with the MPU9250 and the library · Issue #53 · sparkfun/SparkFun_MPU-9250-DMP_Arduino_Library · GitHub

At least we know that there is indeed a problem with the Sparkfun library and the STM32.
You could add your investigation to that Github Issue.

Please :pleading_face: leave this nasty swamp full of bugs behind you. It does not work. Stay away from that Sparkfun code, stay away from fake sensors, stay away from MPUxxxx sensors.

1 Like

Incorrect it all depends on any single device on the I2C bus and how it is configured.
If the MPU9250 had stopped working with the I2C lines switched to input, as they should be, then anything else on the I2C bus will carry on working.

I notice at the offending line of code I can only assume that something is hanging on to the I2C bus and you really should have a timeout built into your code for this eventuality.

If you understand I2C and its differences with normal serial transmission, then you would program for this eventuality.

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.