After receiving by master the last byte a new transmit is started (CR2.START set) from within the last ISR.RXNE ISR handler call with CR2.AUTOEND set.
As a result, ISR.STOPF flag gets set and it does not get cleared setting ICF.STOPCF. Peripheral jams and only reset helps (CR1.PE off/on). Surprisingly, ICF.STOPCF flag gets set even when this event is disabled (CR1.STOPIE not set). I am not certain it is a bug or undocumented limitation.
Tested with STM32L432
Disabling an interrupt (xxxIE = 0) only disables the interrupt for that particular event. It doesn’t stop the event from happening. If it’s a situation that has to be handled then you still have to handle it - but you’ll only be aware that it has arisen when you next poll the device.
There’s a lot you haven’t said about your system, and without more information we’re just guessing as to what might be wrong.
Am I right in thinking your stm32 is the I2C master? And that the I2C slave is not another microcontroller (misbehaviour at that end can also lock up the master)?
I2C is a powerful and complex protocol. ST have, over time, made improvements to the I2C peripheral in the stm32. But as a consequence there are several different versions of the peripheral in their current product range. I2C code written for one stm32 might not work on another. The only way to be sure is to look at the Reference Manual for each one.
@Danish I did not really expect anyone to provide an answer. I wrote this just for the record and for those who might experience the same issue. Probably I should have stated it clearly. I already know RM0394 section 37 by heart. During over the last two months I built my own I2C driver to handle SMBus with DMA and entire test environment based on Free RTOS with over 100 test cases. I test it using two I2C ports on the same chip. It works great, but it seems that in this process I discovered two hardware bugs. The other one I described here.
I understand your frustration.
But please go the extra mile and provide sufficient information to allow someone to reproduce the symptoms. Ideally ST would then spot the cause of the bug and fix it and identify a workaround.
Having coded interrupt-driven I2C on stm32 myself, I’m aware of difficulties I have found, particularly with reprated-start. I’ve never actually needed to use repeated-start as my systems only have the one master. But I still wanted to do repeated-start for e.g. eeprom reading.
I don’t have the code to hand, but I do remember concluding that the way to get my code to work was, in one particular instance, to delay writing to an I2C control register by “other means�?. By this I mean there wasn’t an I2C interrupt I could wait for. And there’s no way I’d put a delay into an ISR. So I set up a timer to fire an interrupt after a delay, and used that ISR to write the particular I2C control bit.
It’s possible that a different order of writes to the I2C peripheral would not hit that problem. But I didn’t have time/inclination to exhaustively explore that.
@Danish Exactly, it seems the way to do it is to always start a new transfer from a non-i2c event like timer (or thread), button press, etc; not from i2c RXNE event. The exception is restart condition - no STOP. Documentation does not mention that. That works well besides one specific and rare case - the other bug I mentioned. For those who designed this hardware I think the provided info would be sufficient.
I am sorry, I cannot share the repro because that would require sharing my i2c driver code and that is very proprietary piece of software.
In my view, ST is a company which is yet to realize that these days software (I mean their HAL drivers) matters as much as hardware.
Currently, serious programming with ST MPUs above all requires strong ability to manage frustration, relaxation techniques, positive attitude, determination and firm faith that one day you will figure out what the person writing the docs tried to describe - apparently without fully understanding it.
An update: It seems that even when CR1.STOPIE bit is not set, ISR.STOPF flag gets set when host/controller issues STOP condition, either because CR2.AUTOEND is set or CR2.STOP is set at the end of transmission. In another words, host/controller detects STOP condition it issues and when it happens, setting ICF.STOPCF does not clear ISR.STOPF. I found no trace of this behavior description in RM or errata docs. The good news is that it seems that this ISR.STOPF flag can be ignored on the host/controller.
I am also showing that it is perfectly OK to set CR2.START bit and begin new operation from. e.g. RXNE ot TC event while CR2.BUSY is still set.
Earlier described I2C peripheral jamming was caused by my driver and I was able to fix it.