cancel
Showing results for 
Search instead for 
Did you mean: 

F411: how to handle I2C Errors

HDaji.1
Senior

I am using the I2C code in STM32Cube_FW_F4_V1.26.0\Projects\STM32F411E-Discovery\Examples\I2C\I2C_TwoBoards_ComPolling as base to write my own I2C firmware.

I would say the HAL library in stm32f4xx_hal_i2c.c is quite useful and covers all I2C communication cases. However, there is not much about how to recover from an I2C error.

In the I2C_TwoBoards_ComPolling sample, if there is I2C error, error handler does nothing and MCU just hangs.

So far in my application, I run into two I2C errors: AF and TIMEOUT.

  1. I wonder in those two cases how I can recover I2C communication without software reset I2C.
  2. For the worst case, if I want to reset, what are the proper steps? Disable I2C and do Init again?

BTW, I am using F411.

12 REPLIES 12
TDK
Guru

To recover:

  • Reset the peripheral.
  • Toggle SCL 9 times at an appropriate clock speed while holding SDA high to clear slaves.
  • Re-initialize the peripheral an associated software state machine.

The HAL library doesn't support this ability natively.

Generally if you're regularly encountering I2C errors you should figure out why those are happening rather than just ignoring and resetting.

The STM32F4 I2C peripheral is a mess. The newer families have a much better interface.

If you feel a post has answered your question, please click "Accept as Solution".
AScha.3
Chief III

sorry, to disturb.

but i have also problem on I2C : with H743, on I2C talking to device (ES9038q2m , audio dac) communication ok, until after some time, no more response . Dont know why, just can assume: some spike, creating error. but how to reset "soft" , in hardware set/reset reset pin works, but this also stopping communication, dac working still ok, so whow to find out to get I2C working again, without hardware reset?

If you feel a post has answered your question, please click "Accept as Solution".

As TDK indicates the usual method is to try an clock the peripheral device off the bus.

Most devices are pretty dumb, and also don't have an asynchronous reset.

Generally one needs to consider capacitance of the bus, and how rapidly the SCL and SDA rise. There's a trade-off in the pull-up vs speed vs current.

Have a very short bus, have 2K7 or smaller pull-ups at the end

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..

Need to do those 3 things sequentially or one is enough?

Yes, I agree with you that I need to find the root cause for the error. We guess it is due to some part of PCB not properly done, which we will definitely improve in our next version.

However, for the firmware robustness point of view, I think I need to add software reset instead of just letting it hang.

S.Ma
Principal

Obvious statement, how can a start bit be issued if both sda and scl are not both high?

If it is so, send 18 stop bits by bit bang to resync the bus. Usually bus hang from pure hw slaves which were transmitting a 0x00 data value and something happened...

Debug reset and restart the mcu sw is one,

Noise or plug unplug a i2c bus on cable is another.

Crazy robust I2C test was to wrap the I2C bus around a noisy driller and check....

All 3.
PCB errors rarely show up intermittent I2C errors. More likely to be software based. Consider using a logic analyzer to see what happens on the bus and isolate when the issue occurs.
If you feel a post has answered your question, please click "Accept as Solution".

my sensor I2C address is configurable by a few pins, one of which is connected to a voltage source. The source somehow sometimes fluctuates, which we guess is the cause.

AScha.3
Chief III

just today it happened: I2C stopped working, PC was connected on debug : so i could check I2C registers and see: all ok, but "busy" on. -> so maybe a spike on SDA made it busy waiting....forever.

my simple idea now, to see, is problem only in STM I2C master : reset/restart I2C.

i found in HAL lib macros and put together:

if (__HAL_I2C_GET_FLAG(hi2c, I2C_FLAG_BUSY))
{
	/* Generate Stop */
	hi2c->Instance->CR2 |= I2C_CR2_STOP;
	__HAL_I2C_DISABLE(hi2c);      // stop i2c
}
printf("I2C: restart \n");           // info msg
 
__HAL_I2C_ENABLE(hi2c);               // start i2c

If you feel a post has answered your question, please click "Accept as Solution".
S.Ma
Principal

Trying to generate a 9 STOP bit by the HW cell probably isn't a good lead.

Use bit bang STOP generation, and maybe if the cell is in slave mode, its BUSY state will clear up like the external slave....