From 43089519ddfad745cb27fe702d035253bf6e7bb4 Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Tue, 28 Oct 2014 18:36:34 +1100 Subject: stm32_i2c: handle more error conditions on I2C bus this fixes a I2C ISR storm condition where status=0x70084, which can happen with some specific types of noise on the I2C bus. This was reproduced by playing 80s rock through a Jabra wireless headset close to the I2C cables. --- nuttx/arch/arm/src/stm32/stm32_i2c.c | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/nuttx/arch/arm/src/stm32/stm32_i2c.c b/nuttx/arch/arm/src/stm32/stm32_i2c.c index 44978862d..fb8718316 100644 --- a/nuttx/arch/arm/src/stm32/stm32_i2c.c +++ b/nuttx/arch/arm/src/stm32/stm32_i2c.c @@ -93,6 +93,9 @@ #include "stm32_i2c.h" #include "stm32_waste.h" +// useful when debugging +// #pragma GCC optimize("O0") + /* At least one I2C peripheral must be enabled */ #if defined(CONFIG_STM32_I2C1) || defined(CONFIG_STM32_I2C2) || defined(CONFIG_STM32_I2C3) @@ -316,6 +319,8 @@ static inline uint32_t stm32_i2c_disablefsmc(FAR struct stm32_i2c_priv_s *priv); static inline void stm32_i2c_enablefsmc(uint32_t ahbenr); #endif /* I2C1_FSMC_CONFLICT */ static int stm32_i2c_isr(struct stm32_i2c_priv_s * priv); +// useful when debugging +// static int stm32_i2c_isr(struct stm32_i2c_priv_s *priv) __attribute__((optimize("O0"))); #ifndef CONFIG_I2C_POLLED #ifdef CONFIG_STM32_I2C1 static int stm32_i2c1_isr(int irq, void *context); @@ -1262,6 +1267,29 @@ static int stm32_i2c_isr(struct stm32_i2c_priv_s *priv) // throw away the unexpected byte stm32_i2c_getreg(priv, STM32_I2C_DR_OFFSET); } + } else if (status & I2C_SR1_TXE) { + /* this should never happen, but it does happen + occasionally with lots of noise on the bus. It means the + peripheral is expecting more data bytes, but we don't have + any to give. + This has been seen with status=0x70084, reproduced with + noise generated by a Jabra wireless headset in close + proximity to the I2C lines + */ + stm32_i2c_putreg(priv, STM32_I2C_DR_OFFSET, 0); + } else if (status & I2C_SR1_BTF) { + /* + we should have handled all cases where this could happen + above, but just to ensure it gets acked, lets clear it here + */ + stm32_i2c_getreg(priv, STM32_I2C_DR_OFFSET); + } else if (status & I2C_SR1_STOPF) { + /* + we should never get this, as we are a master not a + slave. Write CR1 with its current value to clear the + error + */ + stm32_i2c_modifyreg(priv, STM32_I2C_CR1_OFFSET, 0, 0); } /* Do we have more bytes to send, enable/disable buffer interrupts -- cgit v1.2.3