cancel
Showing results for 
Search instead for 
Did you mean: 

I2C communication takes too much time

KMarci
Associate II

Hello,

I've had some trouble using the i2c interface on my Nucleo F722ZE board.

I try to achive constant rate data sampling from my MPU6050 IMU. (accelerometer+gyroscope)

For this I use the following 1000 Hz timer interrupt routine:

void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim){
	if (htim->Instance==TIM3){
		GPIOB->ODR ^= GPIO_PIN_7; 
		SD_MPU6050_ReadAll(&hi2c1,&mpu1); 
		temper = mpu1.Temperature;
		g_x = mpu1.Gyroscope_X;
	  	g_y = mpu1.Gyroscope_Y;
	  	g_z = mpu1.Gyroscope_Z;
		a_x = mpu1.Accelerometer_X;
	  	a_y = mpu1.Accelerometer_Y;
		a_z = mpu1.Accelerometer_Z;
		GPIOB->ODR ^= GPIO_PIN_7;
	}
}

I toggle the B7 pin in order to measure the time the interrupt takes with an oscilloscope.

I set the IMU's data rate to 1 KHz or more.

The SD_MPU6050_ReadAll function uses the following lines to get the data from the IMU via i2c:

while(HAL_I2C_Master_Transmit(Handle, (uint16_t)address, &reg, 1, 1000) != HAL_OK);
while(HAL_I2C_Master_Receive(Handle, (uint16_t)address, data, 14, 1000) != HAL_OK);

So it transmits 1 and receives 14 bytes of data on i2c.

I currently use 1 MHz as i2c clock frequency. This is my i2c config generated by CubeMX:

  hi2c1.Instance = I2C1;
  hi2c1.Init.Timing = 0x00200922;
  hi2c1.Init.OwnAddress1 = 0;
  hi2c1.Init.AddressingMode = I2C_ADDRESSINGMODE_7BIT;
  hi2c1.Init.DualAddressMode = I2C_DUALADDRESS_DISABLE;
  hi2c1.Init.OwnAddress2 = 0;
  hi2c1.Init.OwnAddress2Masks = I2C_OA2_NOMASK;
  hi2c1.Init.GeneralCallMode = I2C_GENERALCALL_DISABLE;
  hi2c1.Init.NoStretchMode = I2C_NOSTRETCH_DISABLE;

And here is my problem:

The whole proccess is really slow. It takes 0.5ms to send and receive all the data (15 bytes) via i2c.

0690X000006CBdnQAG.jpg

The upper signal is generated by toggling the B7 pin at the start and the end of the interrupt routine.

The bottom one is the i2c SCL signal. This is what is looks like:

0690X000006CBdxQAG.jpg

0690X000006CBdsQAG.jpg

The signal is supposed to be 3x denser. It reminds me of this:

0690X000006CBe2QAG.jpgThis is visible on the measured frequency of the signal. It's 333 KHz instead of 1 MHz.

What could cause this? How did the data rate become so low and why does the SCL signal looks like this?

If I change i2c clock to 400KHz the interrupt frequency can't even maintain 1000 Hz.

UART communication is much slower than what I'd expect as well. It takes miliseconds to transmit a few bytes of data with high baud rate.

I've used the HAL libraries in both cases.

I don't know how optimized they are but I use 216 MHz clock frequency so I don't think performance should be a problem in communication.

Or at least I think I do. These are my clock settings:

0690X000006C8lBQAS.jpgNow based on this I belive that my Timer3 (the one I use for the 1000 Hz interrupt) runs on 108 MHz.

So according to my understanding by using a prescaler of 1079 and a Counter Period of 99, the timer overload frequency'll become 1000 Hz.

In reality I get 1000 Hz if I use a Counter Period of 31. Based on this I belive my timer is not running on 108 MHz.

Also, no matter what prescaler and Counter Period value I use, I can't get a faster interrupt frequency thank a few KHz.

This might be a separate problem though.

What do you think? How should I start fixing the i2c (and maybe the timer) problem?

6 REPLIES 6

Does the MPU6050 support I2C @ 1MHz? You really should be using SPI for these kinds of data rates.

AvaTar
Lead

> Does the MPU6050 support I2C @ 1MHz?

I suppose it would be obvious if it doesn't. This would be easy to check.

> I've used the HAL libraries in both cases.

But perhaps this is the problem.

while(HAL_I2C_Master_Transmit(Handle, (uint16_t)address, &reg, 1, 1000) != HAL_OK);

In don't use Cube, but that sound a bit like busy-looping.

BTW, the editor in this all-new forum is a PITA.

MPU6050 doesn't support 1MHz I2C communication. 400KHz is what you can get at most. Try to change the I2C speed in Cube and regenerate the code, see what happens. Even at 400KHz you can do 1KHz easily. Or even twice as much.

It doesn't really matter for your current problem, but..

Your approach of doing the work in an interrupt handler is.. not very correct. Just mark some volatile flag and on appearance of that flag in your main loop start the i2c sequence.

If this is not just a demo then you can also use interrupts for i2c instead of polling. It just boggles me a little bit that an 216MHz monster is wasting time in polling when it could do so much work in that time, or just sleep if there is nothing to do.

KMarci
Associate II

Thank you very much for your answers!

>Does the MPU6050 support I2C @ 1MHz?

On paper it supports I2C at 400 KHz. If I set the I2C clock to 400 KHz my interrupt routine will take more than 1ms to finish, so setting the SCL frequency to 1 MHz was the only thing I could do so far to ensure sampling in every ms.

I can't check the SCL signal with an oscilloscope at 400 KHz settings now (I will tomorrow), but my current SCL frequency is below 400 KHz and I still get faster transfer time with it. So I believe a similar problem is occurring at 400 KHz too.

>that sound a bit like busy-looping.

I've suspected the same thing before but removing the while loop (and simply calling the transmit function) didn't help.

[del]

KMarci
Associate II

Thank you very much for the tips After Forever!

>Your approach of doing the work in an interrupt handler is.. not very correct. Just mark some volatile flag and on appearance of that flag in your main loop start the i2c sequence.

It sounds reasonable, I'll defenetly try this. However I'm afraid this way the interrupt could easily lose it's priority over other taks and/or interrupts. The reason I didn't use a similar method is because the constant rate of the sampling is important so I want the mcu to stop whatever it's doing and jump to sampling code as soon as it can.

>If this is not just a demo then you can also use interrupts for i2c instead of polling.

For now I just try to get it work but I'll use I2C interrupts in the future.

Here are the results with the recommended 400 KHz SCL settings:

0690X000006CC2iQAG.jpg

As seen above, the execution of the interrupt takes longer than 1ms.0690X000006CC2nQAG.jpg

0690X000006CC2sQAG.jpg

One cycle takes about 2.5 μs, so if everything worked fine then the frequency would be 1/2.5μs=400KHz.

But on the picture one cycle takes about 3*2.5μs because of the 5μs gaps, so again we get an actual SCL frequency 3 times slower than the expected.

In short, the problem is exactly the same with lower frequencies. My I2C clock has big gaps and because of this it's 3 times slower than the set SCL frequency value.