From 3f01812af618c7a9530490661c09e9a34884facc Mon Sep 17 00:00:00 2001 From: Frederic Pillon Date: Thu, 29 Aug 2019 08:54:03 +0200 Subject: [PATCH 1/2] [Time] Fix ticks per ms value used to compute micros The timer interrupt or COUNTFLAG bit (in the SysTick Control and Status register) is activated on the transition from 1 to 0, therefore it activates every n+1 clock ticks. So, ticks per ms is SysTick->LOAD +1. Signed-off-by: Frederic Pillon --- cores/arduino/stm32/clock.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/cores/arduino/stm32/clock.c b/cores/arduino/stm32/clock.c index 88633164cd..33c589e9a8 100644 --- a/cores/arduino/stm32/clock.c +++ b/cores/arduino/stm32/clock.c @@ -53,12 +53,13 @@ uint32_t getCurrentMicros(void) /* Ensure COUNTFLAG is reset by reading SysTick control and status register */ LL_SYSTICK_IsActiveCounterFlag(); uint32_t m = HAL_GetTick(); - uint32_t u = SysTick->LOAD - SysTick->VAL; + const uint32_t tms = SysTick->LOAD + 1; + __IO uint32_t u = tms - SysTick->VAL; if (LL_SYSTICK_IsActiveCounterFlag()) { m = HAL_GetTick(); - u = SysTick->LOAD - SysTick->VAL; + u = tms - SysTick->VAL; } - return (m * 1000 + (u * 1000) / SysTick->LOAD); + return (m * 1000 + (u * 1000) / tms); } /** From a53ddd02008a0ab77485fb29919e73bbf5491b93 Mon Sep 17 00:00:00 2001 From: Frederic Pillon Date: Thu, 29 Aug 2019 10:42:15 +0200 Subject: [PATCH 2/2] [Time] delayMicroseconds() accuracy delayMicroseconds() should not rely to getCurrentMicros() and should only compute required ticks for the delay requested. This allow to use it even if interrupts are disabled. Example for OneWire library. Fixes #412 Signed-off-by: Frederic Pillon --- cores/arduino/wiring_time.h | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/cores/arduino/wiring_time.h b/cores/arduino/wiring_time.h index 1fa68eb656..d82a737d78 100644 --- a/cores/arduino/wiring_time.h +++ b/cores/arduino/wiring_time.h @@ -69,8 +69,20 @@ static inline void delayMicroseconds(uint32_t us) while ((int32_t)dwt_getCycles() - start < cycles); #else - uint32_t start = getCurrentMicros(); - while (getCurrentMicros() - start < us); + __IO uint32_t currentTicks = SysTick->VAL; + /* Number of ticks per millisecond */ + const uint32_t tickPerMs = SysTick->LOAD + 1; + /* Number of ticks to count */ + const uint32_t nbTicks = ((us - ((us > 0) ? 1 : 0)) * tickPerMs) / 1000; + /* Number of elapsed ticks */ + uint32_t elapsedTicks = 0; + __IO uint32_t oldTicks = currentTicks; + do { + currentTicks = SysTick->VAL; + elapsedTicks += (oldTicks < currentTicks) ? tickPerMs + oldTicks - currentTicks : + oldTicks - currentTicks; + oldTicks = currentTicks; + } while (nbTicks > elapsedTicks); #endif }