From acaebb361b9fb3235affbdcfa74ac0ac0577906c Mon Sep 17 00:00:00 2001 From: David Sidrane Date: Fri, 10 Mar 2017 05:07:39 -1000 Subject: [PATCH] STM32, STM32 F7, and STM32 L4: Clone Freddie Chopin's I2C change to similar STM32 I2C drivers. Save elapsed time before handling I2C in stm32_i2c_sem_waitstop() This patch follows the same logic as in previous fix to stm32_i2c_sem_waitdone(). It is possible that a context switch occurs after I2C registers are read but before elapsed time is saved in stm32_i2c_sem_waitstop(). It is then possible that the registers were read only once with "elapsed time" equal 0. When scheduler resumes this thread it is quite possible that now "elapsed time" will be well above timeout threshold. In that case the function returns and reports a timeout, even though the registers were not read "recently". Fix this by inverting the order of operations in the loop - save elapsed time before reading registers. This way a context switch anywhere in the loop will not cause an erroneous "timeout" error. --- arch/arm/src/stm32/stm32_i2c.c | 8 ++++---- arch/arm/src/stm32/stm32f30xxx_i2c.c | 7 ++++--- arch/arm/src/stm32/stm32f40xxx_i2c.c | 7 ++++--- arch/arm/src/stm32f7/stm32_i2c.c | 11 ++++++----- arch/arm/src/stm32l4/stm32l4_i2c.c | 7 ++++--- 5 files changed, 22 insertions(+), 18 deletions(-) diff --git a/arch/arm/src/stm32/stm32_i2c.c b/arch/arm/src/stm32/stm32_i2c.c index 2110a4847f2..666ad304ad3 100644 --- a/arch/arm/src/stm32/stm32_i2c.c +++ b/arch/arm/src/stm32/stm32_i2c.c @@ -729,6 +729,10 @@ static inline void stm32_i2c_sem_waitstop(FAR struct stm32_i2c_priv_s *priv) start = clock_systimer(); do { + /* Calculate the elapsed time */ + + elapsed = clock_systimer() - start; + /* Check for STOP condition */ cr1 = stm32_i2c_getreg(priv, STM32_I2C_CR1_OFFSET); @@ -744,10 +748,6 @@ static inline void stm32_i2c_sem_waitstop(FAR struct stm32_i2c_priv_s *priv) { return; } - - /* Calculate the elapsed time */ - - elapsed = clock_systimer() - start; } /* Loop until the stop is complete or a timeout occurs. */ diff --git a/arch/arm/src/stm32/stm32f30xxx_i2c.c b/arch/arm/src/stm32/stm32f30xxx_i2c.c index 487a8c07118..ba7c02ea651 100644 --- a/arch/arm/src/stm32/stm32f30xxx_i2c.c +++ b/arch/arm/src/stm32/stm32f30xxx_i2c.c @@ -844,6 +844,10 @@ static inline void stm32_i2c_sem_waitstop(FAR struct stm32_i2c_priv_s *priv) start = clock_systimer(); do { + /* Calculate the elapsed time */ + + elapsed = clock_systimer() - start; + /* Check for STOP condition */ cr = stm32_i2c_getreg32(priv, STM32_I2C_CR2_OFFSET); @@ -860,9 +864,6 @@ static inline void stm32_i2c_sem_waitstop(FAR struct stm32_i2c_priv_s *priv) return; } - /* Calculate the elapsed time */ - - elapsed = clock_systimer() - start; } /* Loop until the stop is complete or a timeout occurs. */ diff --git a/arch/arm/src/stm32/stm32f40xxx_i2c.c b/arch/arm/src/stm32/stm32f40xxx_i2c.c index 29a8b449c80..c0d1a2d6fd0 100644 --- a/arch/arm/src/stm32/stm32f40xxx_i2c.c +++ b/arch/arm/src/stm32/stm32f40xxx_i2c.c @@ -731,6 +731,10 @@ static inline void stm32_i2c_sem_waitstop(FAR struct stm32_i2c_priv_s *priv) start = clock_systimer(); do { + /* Calculate the elapsed time */ + + elapsed = clock_systimer() - start; + /* Check for STOP condition */ cr1 = stm32_i2c_getreg(priv, STM32_I2C_CR1_OFFSET); @@ -747,9 +751,6 @@ static inline void stm32_i2c_sem_waitstop(FAR struct stm32_i2c_priv_s *priv) return; } - /* Calculate the elapsed time */ - - elapsed = clock_systimer() - start; } /* Loop until the stop is complete or a timeout occurs. */ diff --git a/arch/arm/src/stm32f7/stm32_i2c.c b/arch/arm/src/stm32f7/stm32_i2c.c index 50ae643876e..17c11d7b15a 100644 --- a/arch/arm/src/stm32f7/stm32_i2c.c +++ b/arch/arm/src/stm32f7/stm32_i2c.c @@ -7,7 +7,7 @@ * * With extensions and modifications for the F1, F2, and F4 by: * - * Copyright (C) 2016 Gregory Nutt. All rights reserved. + * Copyright (C) 2016-2017 Gregory Nutt. All rights reserved. * Authors: Gregroy Nutt * John Wharington * David Sidrane @@ -1034,7 +1034,11 @@ static inline void stm32_i2c_sem_waitstop(FAR struct stm32_i2c_priv_s *priv) start = clock_systimer(); do { - /* Check for STOP condition */ + /* Calculate the elapsed time */ + + elapsed = clock_systimer() - start; + + /* Check for STOP condition */ cr = stm32_i2c_getreg32(priv, STM32_I2C_CR2_OFFSET); if ((cr & I2C_CR2_STOP) == 0) @@ -1050,9 +1054,6 @@ static inline void stm32_i2c_sem_waitstop(FAR struct stm32_i2c_priv_s *priv) return; } - /* Calculate the elapsed time */ - - elapsed = clock_systimer() - start; } /* Loop until the stop is complete or a timeout occurs. */ diff --git a/arch/arm/src/stm32l4/stm32l4_i2c.c b/arch/arm/src/stm32l4/stm32l4_i2c.c index b6ee80df8b0..3468af22be2 100644 --- a/arch/arm/src/stm32l4/stm32l4_i2c.c +++ b/arch/arm/src/stm32l4/stm32l4_i2c.c @@ -788,6 +788,10 @@ static inline void stm32l4_i2c_sem_waitstop(FAR struct stm32l4_i2c_priv_s *priv) start = clock_systimer(); do { + /* Calculate the elapsed time */ + + elapsed = clock_systimer() - start; + /* Check for STOP condition */ cr = stm32l4_i2c_getreg32(priv, STM32L4_I2C_CR2_OFFSET); @@ -804,9 +808,6 @@ static inline void stm32l4_i2c_sem_waitstop(FAR struct stm32l4_i2c_priv_s *priv) return; } - /* Calculate the elapsed time */ - - elapsed = clock_systimer() - start; } /* Loop until the stop is complete or a timeout occurs. */