From 59e78fcd8e68fae7191593eea1ccb7052215ac3d Mon Sep 17 00:00:00 2001 From: jflyper Date: Mon, 26 Sep 2016 23:42:35 +0900 Subject: [PATCH 1/5] Fix micros using COUNTFLAG Current micros() may return past time when called from ISR or elevated BASEPRI context. This is because a call to the SysTick interrupt handler sysTick_Hanlder(), which is responsible for 1ms rollover is blocked in these contexts. This PR introduces microsISR() that is guranteed to return correct time in these contexts. Legacy micros() was also modified to call microISR() in these contexts. The microISR() uses SysTick's COUNTFLAG to detect a pending rollover and use it to compensate the return value on its own. Actual rollover to sysTickUptime variable is still handled in the sysTick_Hanlder(). --- src/main/drivers/system.c | 44 ++++++++++++++++++++++++++++++++++++++- src/main/drivers/system.h | 1 + 2 files changed, 44 insertions(+), 1 deletion(-) diff --git a/src/main/drivers/system.c b/src/main/drivers/system.c index 962b637349..a05a73bd14 100644 --- a/src/main/drivers/system.c +++ b/src/main/drivers/system.c @@ -24,6 +24,7 @@ #include "light_led.h" #include "sound_beeper.h" #include "nvic.h" +#include "common/atomic.h" #include "system.h" @@ -61,15 +62,56 @@ void cycleCounterInit(void) } // SysTick + +static volatile int sysTickPending = 0; + void SysTick_Handler(void) { - sysTickUptime++; + ATOMIC_BLOCK(NVIC_PRIO_MAX) { + sysTickUptime++; + sysTickPending = 0; + (void)(SysTick->CTRL); + } } // Return system uptime in microseconds (rollover in 70minutes) + +uint32_t microsISR(void) +{ + register uint32_t ms, cycle_cnt; + + ATOMIC_BLOCK(NVIC_PRIO_MAX) { + cycle_cnt = SysTick->VAL; + + if (SysTick->CTRL & SysTick_CTRL_COUNTFLAG_Msk) { + // Update pending. + // Remember it for multiple calls within the same rollover period + // (Will be cleared when serviced). + // Note that multiple rollovers are not considered. + + sysTickPending = 1; + + // Read VAL again to ensure the value is read after the rollover. + + cycle_cnt = SysTick->VAL; + } + + ms = sysTickUptime; + } + + return ((ms + sysTickPending) * 1000) + (usTicks * 1000 - cycle_cnt) / usTicks; +} + uint32_t micros(void) { register uint32_t ms, cycle_cnt; + + // Call microsISR() in interrupt and elevated (non-zero) BASEPRI context + + if ((SCB->ICSR & SCB_ICSR_VECTACTIVE_Msk) || (__get_BASEPRI())) { + return microsISR(); + } + do { ms = sysTickUptime; cycle_cnt = SysTick->VAL; diff --git a/src/main/drivers/system.h b/src/main/drivers/system.h index 105a584c44..b2e4e45a83 100644 --- a/src/main/drivers/system.h +++ b/src/main/drivers/system.h @@ -22,6 +22,7 @@ void delayMicroseconds(uint32_t us); void delay(uint32_t ms); uint32_t micros(void); +uint32_t microsISR(void); uint32_t millis(void); typedef enum { From a89c36b5e1c44ce308b30cf621d32278352a289e Mon Sep 17 00:00:00 2001 From: jflyper Date: Tue, 4 Oct 2016 03:53:59 +0900 Subject: [PATCH 2/5] Cache sysTickPending inside ATOMIC_BLOCK --- src/main/drivers/system.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/main/drivers/system.c b/src/main/drivers/system.c index a05a73bd14..13c7a04152 100644 --- a/src/main/drivers/system.c +++ b/src/main/drivers/system.c @@ -78,7 +78,7 @@ void SysTick_Handler(void) uint32_t microsISR(void) { - register uint32_t ms, cycle_cnt; + register uint32_t ms, pending, cycle_cnt; ATOMIC_BLOCK(NVIC_PRIO_MAX) { cycle_cnt = SysTick->VAL; @@ -97,9 +97,10 @@ uint32_t microsISR(void) } ms = sysTickUptime; + pending = sysTickPending; } - return ((ms + sysTickPending) * 1000) + (usTicks * 1000 - cycle_cnt) / usTicks; + return ((ms + pending) * 1000) + (usTicks * 1000 - cycle_cnt) / usTicks; } uint32_t micros(void) From 2a0e22f8b40182a25adaefab9e2ab95e4e1a0d67 Mon Sep 17 00:00:00 2001 From: jflyper Date: Wed, 5 Oct 2016 02:00:02 +0900 Subject: [PATCH 3/5] Travis, what did you do with common/atomic.h? --- src/main/drivers/system.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/drivers/system.c b/src/main/drivers/system.c index 13c7a04152..6fa44a1c96 100644 --- a/src/main/drivers/system.c +++ b/src/main/drivers/system.c @@ -122,6 +122,7 @@ uint32_t micros(void) */ asm volatile("\tnop\n"); } while (ms != sysTickUptime); + return (ms * 1000) + (usTicks * 1000 - cycle_cnt) / usTicks; } From e9484986954687a209570875636cb44dc9bc6243 Mon Sep 17 00:00:00 2001 From: jflyper Date: Fri, 7 Oct 2016 20:22:12 +0900 Subject: [PATCH 4/5] atomic.h inclusion path fixed for development branch --- src/main/drivers/system.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/drivers/system.c b/src/main/drivers/system.c index 6fa44a1c96..123b6b6883 100644 --- a/src/main/drivers/system.c +++ b/src/main/drivers/system.c @@ -24,7 +24,7 @@ #include "light_led.h" #include "sound_beeper.h" #include "nvic.h" -#include "common/atomic.h" +#include "build/atomic.h" #include "system.h" From 76392c2da757283275c36bdbe704154a4f4ab16c Mon Sep 17 00:00:00 2001 From: jflyper Date: Sat, 8 Oct 2016 07:20:40 +0900 Subject: [PATCH 5/5] Travis kick --- src/main/drivers/system.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/drivers/system.c b/src/main/drivers/system.c index 123b6b6883..068fbe3858 100644 --- a/src/main/drivers/system.c +++ b/src/main/drivers/system.c @@ -85,7 +85,7 @@ uint32_t microsISR(void) if (SysTick->CTRL & SysTick_CTRL_COUNTFLAG_Msk) { // Update pending. - // Remember it for multiple calls within the same rollover period + // Record it for multiple calls within the same rollover period // (Will be cleared when serviced). // Note that multiple rollovers are not considered.