I2C hangs in event interrupt if I2C bus is disturbed
Posted: Sun Feb 22, 2015 9:57 am
This is a minor issue from RTOS point of view, but still I need to find a solution for it ...
I have a system where the MCU (STM32F4) communicates with a slave chip - ecompass. Currently the MCU polls the ecompass chip every 20ms to feed data to ecompass processing algorithm that makes the calculation and automatic magnetic calibration.
This same I2C bus (same SDA and SCL lines) are routed out to a connector for optional modules. So the behavior of those modules might break the operation of the on-board I2C bus.
What I observe is that the I2C driver enters endless loop if the bus gets disturbed - I see that an optional module attempts to play as master on this bus.
This should not be a SW issue, the modules should not play master on this bus. But still those modules are out of my control and I would like to have a robust implementation that could detect this behavior, or at least I want to avoid the complete OS hanging in this situation.
While I see that the driver sometimes detects the BERR and ARLO conditions (errors), I also see that sometimes (in the same problematic case where bus is disturbed by external master) the I2C driver hands in its "event interrupt". Because now the I2C interrupt is at highest priority my complete OS hands - threads are not running any more, also other interrupts are not running.
I saw that there is a safety timer for the I2C transactions - but it is surved as VT timer and it is blocked by the I2C interrupt too.
I know that this might be related to the tricky STM32F4 peripheral block. I already saw and discribed similar situation in UART driver, where I had to make a dirty patch to avoid a case that is not handled in the driver.
I seems to me that there is a similar solution for this problem too. Most of the cases where I see the problem (the SW stops to react on UI commands) and then I pause the debugger, I see that the code runs in the I2C serve event interrupt, getting into "I2C_EV8_2_MASTER_BYTE_TRANSMITTED" case, with dmaStreamGetTransactionSize(i2cp->dmarx) bigger that 0. I see that the value of SR1 is 132, and the value of SR2 is 7.
This seems to be handled already, there is a code after this check, and this code runs fine in most of the time, it is part of the active communication. That's why I think that the problem has happened eariler and I cannot see it.
Once I saw the interrupt with SR1=128 and SR2=7. This situation goes to the "default:" case of the interrupt handler - maybe this is the root of the problem? In this situation I see no action taken from the driver, maybe there needs to be an active interrupt confirmation?
I will keep on investigating, the best way is to find the precise reason and fix the driver. But it would be nice to protect the OS from such "endless" interrupts - maybe some kind of "debugging" option that can detect similar cases?
I have a system where the MCU (STM32F4) communicates with a slave chip - ecompass. Currently the MCU polls the ecompass chip every 20ms to feed data to ecompass processing algorithm that makes the calculation and automatic magnetic calibration.
This same I2C bus (same SDA and SCL lines) are routed out to a connector for optional modules. So the behavior of those modules might break the operation of the on-board I2C bus.
What I observe is that the I2C driver enters endless loop if the bus gets disturbed - I see that an optional module attempts to play as master on this bus.
This should not be a SW issue, the modules should not play master on this bus. But still those modules are out of my control and I would like to have a robust implementation that could detect this behavior, or at least I want to avoid the complete OS hanging in this situation.
While I see that the driver sometimes detects the BERR and ARLO conditions (errors), I also see that sometimes (in the same problematic case where bus is disturbed by external master) the I2C driver hands in its "event interrupt". Because now the I2C interrupt is at highest priority my complete OS hands - threads are not running any more, also other interrupts are not running.
I saw that there is a safety timer for the I2C transactions - but it is surved as VT timer and it is blocked by the I2C interrupt too.
I know that this might be related to the tricky STM32F4 peripheral block. I already saw and discribed similar situation in UART driver, where I had to make a dirty patch to avoid a case that is not handled in the driver.
I seems to me that there is a similar solution for this problem too. Most of the cases where I see the problem (the SW stops to react on UI commands) and then I pause the debugger, I see that the code runs in the I2C serve event interrupt, getting into "I2C_EV8_2_MASTER_BYTE_TRANSMITTED" case, with dmaStreamGetTransactionSize(i2cp->dmarx) bigger that 0. I see that the value of SR1 is 132, and the value of SR2 is 7.
This seems to be handled already, there is a code after this check, and this code runs fine in most of the time, it is part of the active communication. That's why I think that the problem has happened eariler and I cannot see it.
Once I saw the interrupt with SR1=128 and SR2=7. This situation goes to the "default:" case of the interrupt handler - maybe this is the root of the problem? In this situation I see no action taken from the driver, maybe there needs to be an active interrupt confirmation?
I will keep on investigating, the best way is to find the precise reason and fix the driver. But it would be nice to protect the OS from such "endless" interrupts - maybe some kind of "debugging" option that can detect similar cases?