Skip to content

Commit 9285599

Browse files
authored
Merge pull request #189 from Pan-Chenliang/systime_fix
Fix systime_now_us() occasional fault
2 parents 9d777cf + f0b3947 commit 9285599

1 file changed

Lines changed: 20 additions & 6 deletions

File tree

src/module/system/systime.c

Lines changed: 20 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -28,12 +28,10 @@ static rt_device_t systick_dev;
2828

2929
/**
3030
* @brief Systick ISR callback
31-
*
3231
*/
3332
static void systick_isr_cb(void)
3433
{
3534
__systime.msPeriod += __systime.msPerPeriod;
36-
3735
rt_tick_increase();
3836
}
3937

@@ -96,20 +94,35 @@ uint64_t systime_now_us(void)
9694
{
9795
uint32_t systick_us = 0;
9896
uint64_t time_now_ms;
97+
uint64_t now_us;
98+
static uint64_t monotonic_us = 0;
9999
uint32_t level;
100100

101101
if (systick_dev == NULL) {
102102
return 0;
103103
}
104104

105-
rt_device_read(systick_dev, SYSTICK_RD_TIME_US, &systick_us, sizeof(uint32_t));
106-
107105
level = rt_hw_interrupt_disable();
106+
rt_device_read(systick_dev, SYSTICK_RD_TIME_US, &systick_us, sizeof(uint32_t));
108107
/* atomic read */
109108
time_now_ms = __systime.msPeriod;
109+
110+
now_us = time_now_ms * 1000ULL + systick_us;
111+
112+
/* Fix the race condition where the SysTick hardware timer has wrapped around */
113+
if (now_us < monotonic_us) {
114+
now_us += (uint64_t)__systime.msPerPeriod * 1000ULL;
115+
}
116+
117+
/* Ensure strict monotonicity */
118+
if (now_us > monotonic_us) {
119+
monotonic_us = now_us;
120+
} else {
121+
now_us = monotonic_us;
122+
}
110123
rt_hw_interrupt_enable(level);
111124

112-
return time_now_ms * (uint64_t)1000 + systick_us;
125+
return now_us;
113126
}
114127

115128
/**
@@ -189,7 +202,8 @@ fmt_err_t systime_init(void)
189202
systick_device = (systick_dev_t)systick_dev;
190203

191204
__systime.msPeriod = 0;
192-
__systime.msPerPeriod = systick_device->ticks_per_isr / systick_device->ticks_per_us / 1e3;
205+
/* Calculate integer ms without losing precision */
206+
__systime.msPerPeriod = systick_device->ticks_per_isr / (systick_device->ticks_per_us * 1000);
193207

194208
systick_device->systick_isr_cb = systick_isr_cb;
195209

0 commit comments

Comments
 (0)