aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/stm32f1/timer.c86
1 files changed, 39 insertions, 47 deletions
diff --git a/src/stm32f1/timer.c b/src/stm32f1/timer.c
index c3b13989..a247983d 100644
--- a/src/stm32f1/timer.c
+++ b/src/stm32f1/timer.c
@@ -1,6 +1,7 @@
// STM32F1 timer interrupt scheduling code.
//
// Copyright (C) 2018 Grigori Goronzy <greg@kinoho.net>
+// Copyright (C) 2018 Kevin O'Connor <kevin@koconnor.net>
//
// This file may be distributed under the terms of the GNU GPLv3 license.
@@ -11,6 +12,7 @@
#include "stm32f1xx_ll_bus.h"
#include "stm32f1xx_ll_tim.h"
#include "command.h" // shutdown
+#include "board/io.h" // readl
#include "board/irq.h" // irq_save
#include "sched.h" // sched_timer_dispatch
@@ -21,12 +23,6 @@
DECL_CONSTANT(CLOCK_FREQ, CONFIG_CLOCK_FREQ);
-union u32_u {
- struct { uint8_t b0, b1, b2, b3; };
- struct { uint16_t lo, hi; };
- uint32_t val;
-};
-
static inline uint32_t
timer_get(void)
{
@@ -54,7 +50,37 @@ timer_kick(void)
LL_TIM_ClearFlag_CC1(TIM2);
}
-static struct timer wrap_timer;
+
+/****************************************************************
+ * 16bit hardware timer to 32bit conversion
+ ****************************************************************/
+
+// High bits of timer (top 17 bits)
+static uint32_t timer_high;
+
+// Return the current time (in absolute clock ticks).
+uint32_t
+timer_read_time(void)
+{
+ uint32_t th = readl(&timer_high);
+ uint32_t cur = timer_get();
+ // Combine timer_high (high 17 bits) and current time (low 16
+ // bits) using method that handles rollovers correctly.
+ return (th ^ cur) + (th & 0x8000);
+}
+
+// Update timer_high every 0x8000 clock ticks
+static uint_fast8_t
+timer_event(struct timer *t)
+{
+ timer_high += 0x8000;
+ t->waketime = timer_high + 0x8000;
+ return SF_RESCHEDULE;
+}
+static struct timer wrap_timer = {
+ .func = timer_event,
+ .waketime = 0x8000,
+};
void
timer_reset(void)
@@ -63,6 +89,11 @@ timer_reset(void)
}
DECL_SHUTDOWN(timer_reset);
+
+/****************************************************************
+ * Timer init
+ ****************************************************************/
+
void
timer_init(void)
{
@@ -86,48 +117,9 @@ DECL_INIT(timer_init);
/****************************************************************
- * 32bit timer wrappers
+ * Main timer dispatch irq handler
****************************************************************/
-static uint32_t timer_high;
-
-// Return the current time (in absolute clock ticks).
-uint32_t
-timer_read_time(void)
-{
- irqstatus_t flag = irq_save();
- union u32_u calc = { .val = timer_get() };
- calc.hi = timer_high;
- if (unlikely(LL_TIM_IsActiveFlag_UPDATE(TIM2))) {
- irq_restore(flag);
- if (calc.b1 < 0xff)
- calc.hi++;
- return calc.val;
- }
- irq_restore(flag);
- return calc.val;
-}
-
-// Timer that runs every cycle - allows 16bit comparison optimizations
-static uint_fast8_t
-timer_event(struct timer *t)
-{
- union u32_u *nextwake = (void*)&wrap_timer.waketime;
- if (LL_TIM_IsActiveFlag_UPDATE(TIM2)) {
- // Hardware timer has overflowed - update overflow counter
- LL_TIM_ClearFlag_UPDATE(TIM2);
- timer_high++;
- *nextwake = (union u32_u){ .hi = timer_high, .lo = 0x8000 };
- } else {
- *nextwake = (union u32_u){ .hi = timer_high + 1, .lo = 0x0000 };
- }
- return SF_RESCHEDULE;
-}
-static struct timer wrap_timer = {
- .func = timer_event,
- .waketime = 0x8000,
-};
-
#define TIMER_IDLE_REPEAT_TICKS timer_from_us(500)
#define TIMER_REPEAT_TICKS timer_from_us(100)