2018-08-20 01:48 AM
Hello
I have trouble with handling an I2C error on my STM32F407. My I2C bus usually works fine but it sometimes hangs, with both clock and data lines are high, but the I2C communication does not start. The SR2.BUSY bit remains high and sometimes when this bit is indeed low, the SR1.SB bit remains low after the code sets the CR1.START to initiate a transfer.
I've noticed that resetting the entire MCU fixes the problem, I2C communication restarts and everything is fine.
However, resetting the entire MCU is not an option. Instead I'd rather like to reset just the I2C peripheral.
I've tried doing this in a number of ways:
The above is followed by calling the same setup routines as used initially to set up I2C communication.
Once the error happens, none of this seems to fix the error.
I have spent a lot of time with this issue and would greatly appreciate any help I could get.
Best regards
Nils
2018-08-20 02:25 AM
Have you tried to disable power and clock to the I2C peripheral ?
2018-08-20 04:25 AM
Hi
I've tried to disable the clock by clearing the APB1ENR.I2C2EN bit, but how do you mean I should disable the power to the I2C peripheral?
/Nils
2018-08-20 05:09 AM
Mainly RCC (RCC_APB1) to disable/enable the clock.
It were long holidays ...
You could go the long way and note the differences in I2C config register settings during hardware reset, and your reset methods. I avoid ST's I2C peripheral when possible, since it is overly complicated and confusing.
Or you can check how the SPL did it.
2018-08-20 05:40 AM
The SPL?
2018-08-20 07:24 AM
I2C is notoriously hard to get right, both in hardware and software, and ST's incarnations are no shining positive exemptions. To make things worse, there are at least 3 quite different I2C modules present in different STM32 families.
The I2C module in the 'F2 and 'F4 has at least one internal state not reported through publicly readable flags. I am not sure as I don't have access to the module's internals and I had no time to experiment extensively to prove it, but my suspicion is that this happens if the I2C in master state loses arbitration - or it thinks it has lost it, due to e.g. noise when reading back SDA state, it goes internally into slave mode and ceases to emit clocks, but if there is no genuine other master to provide clocks, it does not not indicate it through ARLO until the whole frame has been finished, which in this case never happens.
There may be others, as I have this remark at the module reset in my sources:
// !!!!!!!! this reset is necessary, otherwise the I2C module remains hanging at the first START attempt until SDA is pulled low externally !!!! (some internal/user-invisible state machine flag hangs probably)
However, so far, I was always successful by resetting it through APB1RSTR.I2CxRST; and AFAIK using CR1.SWRST should be as good as using the RCC reset. My I2C startup code also contains the slave-recovery sequence as per the I2C specification (NXP UM10204 rev.6, 3.1.16 Bus clear).
JW
2018-08-20 08:11 AM
Thank you JW for your answer.
I'd don't quite follow you, at which point do you reset the I2C peripheral (through APB1RSTR.I2CxRST or CR1.SWRST)? Is it after you've detected that I2C communication has stopped working or do you do this reset in a preventive manner?
/Nils
2018-08-20 08:40 AM
> Is it after you've detected that I2C communication has stopped working
Yes.
Ever since I started with I2C, in any mcu, the code ended up being a complex state machine with timeouts throughout (see my first sentence above... :) or :( I'm not quite sure)
JW
2018-08-21 11:34 PM
Thanks everyone for your help.
I've fixed the issue. The init function in the driver code that I'm using had an if statement that returned from the init function right away without doing anything (the purpose of this was of course to make sure the peripheral is only initiated once). Now when I circumvented this I got it all to work.
So, in all, what I did was set the software reset bit (CR1.SWRST) and then call the init function once more, thus resetting the peripheral to the same state it is after startup.
My advice to anyone with similar issues is to use the debugger to read all registries of the peripheral after startup (when it works) and then once the error has occurred, any differences would probably be a clue to what's wrong.
2018-08-22 02:19 AM
> My advice to anyone with similar issues is to use the debugger to read all registries of the peripheral after
> startup (when it works) and then once the error has occurred, any differences would probably be a clue to what's wrong.
Can you please elaborate? I mean, what were your findings?
Thanks,
JW