aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKevin O'Connor <kevin@koconnor.net>2017-08-06 19:21:16 -0400
committerKevin O'Connor <kevin@koconnor.net>2017-08-08 00:27:28 -0400
commit78982ebb51b0895b3178a85edcb1543939dc13b4 (patch)
treea1961fb294104a81e37ff3af93e643fdd35e5f30
parent6a63c27542fc7b432ed438ce1d62243b5aebc3da (diff)
downloadkutter-78982ebb51b0895b3178a85edcb1543939dc13b4.tar.gz
kutter-78982ebb51b0895b3178a85edcb1543939dc13b4.tar.xz
kutter-78982ebb51b0895b3178a85edcb1543939dc13b4.zip
avr: Implement internal avr specific timer to handle 16bit overflows
Don't rely on the generic scheduler code to always have a timer no more than 1ms in the future. Instead, create an avr specific timer that will be called every 0x8000 ticks. This simplifies the generic code and it reduces the amount of code that needs to be run every millisecond. Signed-off-by: Kevin O'Connor <kevin@koconnor.net>
-rw-r--r--src/avr/timer.c32
-rw-r--r--src/generic/misc.h1
-rw-r--r--src/generic/timer_irq.c6
-rw-r--r--src/sched.c13
-rw-r--r--src/simulator/main.c5
5 files changed, 31 insertions, 26 deletions
diff --git a/src/avr/timer.c b/src/avr/timer.c
index a87ae206..1b281ec9 100644
--- a/src/avr/timer.c
+++ b/src/avr/timer.c
@@ -85,6 +85,15 @@ timer_kick(void)
TIFR1 = 1<<OCF1A;
}
+static struct timer wrap_timer;
+
+void
+timer_reset(void)
+{
+ sched_add_timer(&wrap_timer);
+}
+DECL_SHUTDOWN(timer_reset);
+
void
timer_init(void)
{
@@ -96,6 +105,7 @@ timer_init(void)
irqstatus_t flag = irq_save();
timer_kick();
timer_repeat_set(timer_get() + 50);
+ timer_reset();
TIFR1 = 1<<TOV1;
// enable interrupt
TIMSK1 = 1<<OCIE1A;
@@ -115,25 +125,33 @@ uint32_t
timer_read_time(void)
{
irqstatus_t flag = irq_save();
- union u32_u calc;
- calc.val = timer_get();
+ union u32_u calc = { .val = timer_get() };
calc.hi = timer_high;
- if (TIFR1 & (1<<TOV1) && calc.lo < 0x8000)
- calc.hi++;
+ if (unlikely(TIFR1 & (1<<TOV1))) {
+ irq_restore(flag);
+ if (calc.b1 < 0xff)
+ calc.hi++;
+ return calc.val;
+ }
irq_restore(flag);
return calc.val;
}
-// Called by main code once every millisecond. (IRQs disabled.)
-void
-timer_periodic(void)
+// Timer that runs every ~2ms - allows 16bit comparison optimizations
+static uint_fast8_t
+timer_event(struct timer *t)
{
if (TIFR1 & (1<<TOV1)) {
// Hardware timer has overflowed - update overflow counter
TIFR1 = 1<<TOV1;
timer_high++;
}
+ wrap_timer.waketime += 0x8000;
+ return SF_RESCHEDULE;
}
+static struct timer wrap_timer = {
+ .func = timer_event,
+};
#define TIMER_IDLE_REPEAT_TICKS 8000
#define TIMER_REPEAT_TICKS 3000
diff --git a/src/generic/misc.h b/src/generic/misc.h
index f0f8e5a5..65861207 100644
--- a/src/generic/misc.h
+++ b/src/generic/misc.h
@@ -12,7 +12,6 @@ uint32_t timer_from_us(uint32_t us);
uint8_t timer_is_before(uint32_t time1, uint32_t time2);
uint32_t timer_read_time(void);
void timer_kick(void);
-void timer_periodic(void);
void *dynmem_start(void);
void *dynmem_end(void);
diff --git a/src/generic/timer_irq.c b/src/generic/timer_irq.c
index 127601e2..605fc129 100644
--- a/src/generic/timer_irq.c
+++ b/src/generic/timer_irq.c
@@ -30,12 +30,6 @@ timer_is_before(uint32_t time1, uint32_t time2)
return (int32_t)(time1 - time2) < 0;
}
-// Called by main code once every millisecond. (IRQs disabled.)
-void
-timer_periodic(void)
-{
-}
-
static uint32_t timer_repeat_until;
#define TIMER_IDLE_REPEAT_TICKS timer_from_us(500)
#define TIMER_REPEAT_TICKS timer_from_us(100)
diff --git a/src/sched.c b/src/sched.c
index 92fc5504..0aadcc75 100644
--- a/src/sched.c
+++ b/src/sched.c
@@ -24,12 +24,11 @@ static struct timer sentinel_timer, deleted_timer;
// The periodic_timer simplifies the timer code by ensuring there is
// always a timer on the timer list and that there is always a timer
-// not more than 1ms in the future.
+// not far in the future.
static uint_fast8_t
periodic_event(struct timer *t)
{
- timer_periodic();
- periodic_timer.waketime += timer_from_us(1000);
+ periodic_timer.waketime += timer_from_us(100000);
sentinel_timer.waketime = periodic_timer.waketime + 0x80000000;
return SF_RESCHEDULE;
}
@@ -162,9 +161,9 @@ sched_timer_dispatch(void)
return next_waketime;
}
-// Shutdown all user timers on an emergency stop.
-void
-sched_timer_shutdown(void)
+// Remove all user timers on a shutdown
+static void
+sched_timer_reset(void)
{
timer_list = &deleted_timer;
deleted_timer.waketime = periodic_timer.waketime;
@@ -172,7 +171,6 @@ sched_timer_shutdown(void)
periodic_timer.next = &sentinel_timer;
timer_kick();
}
-DECL_SHUTDOWN(sched_timer_shutdown);
/****************************************************************
@@ -230,6 +228,7 @@ run_shutdown(int reason)
if (!shutdown_status)
shutdown_reason = reason;
shutdown_status = 2;
+ sched_timer_reset();
extern void ctr_run_shutdownfuncs(void);
ctr_run_shutdownfuncs();
shutdown_status = 1;
diff --git a/src/simulator/main.c b/src/simulator/main.c
index 7519a35b..e0384611 100644
--- a/src/simulator/main.c
+++ b/src/simulator/main.c
@@ -85,11 +85,6 @@ timer_kick(void)
{
}
-void
-timer_periodic(void)
-{
-}
-
/****************************************************************
* Turn stdin/stdout into serial console