2017-01-11 11:18 PM
I am using an STM32F407 on a customer board and have trouble with the I2C handling.
I am using the latest HAL HAL_I2C_MasterTransmitIT and HAL_I2C_MasterReceiveIT to poll data from a sensor.
The problem is that after a while the I2C lines lock up (both SDA and SCL low) and the
HAL_I2C_MasterTransmitIT returns errors.
I do detect the error and try to handle the problem by deinit the I2C. I then reconfigure the I/O to software handle some clocking that release SDA if it is stuck by a slave on the bus. At that point I can see that the lines go high again so it is the I2C peripheral in the STM that is pulling it low ( I can also see that on the scope with the low level slightly above ground while when the lines are pulled by a slave device, the go lower).
I then
reinit the I2C peripheral but as soon as the I2C is activated and connected to the I/O lines, the SDA and SCL are pulled low again.
So I can't seem to reset the I2C without restarting the whole chip.
Is there a other way to properly reset the I2C?
Also, what can be causing this lockup in the first place?
#stm32-i2c-master2017-01-13 04:19 AM
I guess you are aware that the pull-up resistors must 'stay in place' while pulling the slave, else you measure something else ...
OH yes, have we talked about the pullup resistors already? What value are they? Have you had a look at the buses using an oscilloscope rather than just a LA? Are the levels and edges nice?
I recently had an encounter with I2C on a physically longer line being unreliable (on the slave side, though, and that slave did not implement glitch rejection which distinguishes good I2C incarnations from the poor ones). Setting the lowest slew rate (a.k.a. GPIO speed) helped more than anything else.
JW
2017-01-13 04:21 AM
Have not used the SPL before, but it might be worth a try before going fully bare metal.
No, its not.
My
1c
0.5c.JW
2017-01-13 04:38 AM
Pullups originally were 4K7 with a 220R series to the STM. Later I lowered the pull ups to around 2K and a 50R series resistor but it did not make a difference as far as I could tell.
On an oscilloscope, the signals look good. Upgoing edge has a little rounding near the top but most of it is straight.
Low level on the slave side is less than 100mV and a bit lower than that when the slave ack's or sends data. So I can see a difference between master lows and slave lows.
I also played around with the bit rates and varies it anywhere between 10kHz to 200kHz (from the nominal 100kHz I intended to use) so when edges are a problem that should reduce when the clocks goes slower. No difference. Lockup occurs at around the same time.
I do have the GPIO on high speed. Should they be slow?
2017-01-13 04:39 AM
Noted.
2017-01-13 04:43 AM
I do have the GPIO on high speed. Should they be slow?
I don't say they *should* but that I had a good experience with that and it should make no harm as long as you are at 100kHz.
Shouldn't be related to your problem, though.
JW
2017-04-30 03:57 PM
I would love to know if anybody managed to workaround this issue. I have exactly the same problem with i2c getting stuck after trying to reset it. (stm is pulling both lines down)
2017-05-01 11:01 AM
Bitbang 9 stop bits work for me even if the i2c lines are on a video cable with hot plug unplug. Without it, the bus hangs is few seconds of manipulation. Check bus idle before attempting to generate a start bit and then, when needed, run 9 stop bits prior to a start.
2017-05-01 12:28 PM
Hi, thanks for response! I spent all day trying different solutions and it looks like those are the steps to reliably restart stuck i2c (at least on my board
STM32F446)
:> disable I2C
> change sda & scl pin mode to output
> generate 9 stop bits
> change sda & scl pin mode back to alternate function
> set SWRST flag in i2c control register
> then enable i2c and initialize it
There's a helpful snippet of code in an answer to a very similar problem on stackexchange, which can be easily modified to generate more that one stop bit:
2018-03-16 01:14 PM
After a few days of frustration, I've pretty much proved to myself there are bugs in the HAL I2C (using interrupt) routines. I've an application that reads a MPU-6050 gyro via I2C. There are also other simple edge-detecting GPIO interrupts - nothing to do with the I2C. I find that the I2C works flawlessly for hours on end providing the other interrupts never occur. When activity begins on the GPIO lines causing other interrupts then the I2C comms stops at random - sometimes after a few minutes or sometimes within seconds. I've also found that using UART transmits with interrupt callback (to send log messages to a debug monitor) will also cause the I2C to stall.
If anyone has found a fix to this problem I'd be happy to know - I've spent hours searching but found nothing really helpful. I think it's time to ditch the HAL routines and research how to hit the I2C hardware more directly.
2018-03-17 08:20 AM
When activity begins on the GPIO lines causing other interrupts then the I2C comms stops at random - sometimes after a few minutes or sometimes within seconds.
I'm not going to defend Cube, but this may be not entirely software-related. Depending on particular setup, GPIO lines may introduce unexpected noise into the I2C lines (especially SDA), and the I2C machine may go in an unexpected way then. Check with exercising the GPIO and UART without having the interrupts enabled.
If this proves to be the problem, check and recheck the I2C timing settings, decrease pullup values, improve layout (grounds are often a neglected issue) or introduce timeouts/recovery mechanisms if these methods won't help.
If hardware proves to be innocent, it's time to ditch Cube (frankly, it's always a good time to ditch Cube, except perhaps when beginners try to make applications straighforwardly fitting the provided examples; but it's also a bad idea to take substantial measures without being sure of the primary cause of problem).
Also, note, that there are several rather different incarnations of the I2C in various STM32 subfamilies, so it always helps to state which model are you using.
JW