mirror of
https://github.com/betaflight/betaflight.git
synced 2025-07-15 12:25:20 +03:00
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().
This commit is contained in:
parent
a21694b065
commit
59e78fcd8e
2 changed files with 44 additions and 1 deletions
|
@ -24,6 +24,7 @@
|
||||||
#include "light_led.h"
|
#include "light_led.h"
|
||||||
#include "sound_beeper.h"
|
#include "sound_beeper.h"
|
||||||
#include "nvic.h"
|
#include "nvic.h"
|
||||||
|
#include "common/atomic.h"
|
||||||
|
|
||||||
#include "system.h"
|
#include "system.h"
|
||||||
|
|
||||||
|
@ -61,15 +62,56 @@ void cycleCounterInit(void)
|
||||||
}
|
}
|
||||||
|
|
||||||
// SysTick
|
// SysTick
|
||||||
|
|
||||||
|
static volatile int sysTickPending = 0;
|
||||||
|
|
||||||
void SysTick_Handler(void)
|
void SysTick_Handler(void)
|
||||||
{
|
{
|
||||||
|
ATOMIC_BLOCK(NVIC_PRIO_MAX) {
|
||||||
sysTickUptime++;
|
sysTickUptime++;
|
||||||
|
sysTickPending = 0;
|
||||||
|
(void)(SysTick->CTRL);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Return system uptime in microseconds (rollover in 70minutes)
|
// 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)
|
uint32_t micros(void)
|
||||||
{
|
{
|
||||||
register uint32_t ms, cycle_cnt;
|
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 {
|
do {
|
||||||
ms = sysTickUptime;
|
ms = sysTickUptime;
|
||||||
cycle_cnt = SysTick->VAL;
|
cycle_cnt = SysTick->VAL;
|
||||||
|
|
|
@ -22,6 +22,7 @@ void delayMicroseconds(uint32_t us);
|
||||||
void delay(uint32_t ms);
|
void delay(uint32_t ms);
|
||||||
|
|
||||||
uint32_t micros(void);
|
uint32_t micros(void);
|
||||||
|
uint32_t microsISR(void);
|
||||||
uint32_t millis(void);
|
uint32_t millis(void);
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue