From e5d7e593ec8a1587983e2ca9504af6b4e9d17578 Mon Sep 17 00:00:00 2001 From: Kevin O'Connor Date: Fri, 10 Mar 2017 23:00:17 -0500 Subject: [PATCH] generic: Move generic parts of sam3x8e timer.c to generic directory Most of sam3x8e/timer.c is going to be platform agnostic for any board with standard irq handling. Move the generic code into a new file generic/timer.c. Signed-off-by: Kevin O'Connor --- src/avr/main.c | 4 ++ src/avr/timer.c | 1 - src/generic/timer.c | 87 ++++++++++++++++++++++++++++++++++++++ src/sam3x8e/Makefile | 2 +- src/sam3x8e/main.c | 3 ++ src/sam3x8e/timer.c | 99 +++++--------------------------------------- 6 files changed, 106 insertions(+), 90 deletions(-) create mode 100644 src/generic/timer.c diff --git a/src/avr/main.c b/src/avr/main.c index 7651ab4a..4a3f871a 100644 --- a/src/avr/main.c +++ b/src/avr/main.c @@ -4,9 +4,13 @@ // // This file may be distributed under the terms of the GNU GPLv3 license. +#include "autoconf.h" // CONFIG_MCU +#include "command.h" // DECL_CONSTANT #include "irq.h" // irq_enable #include "sched.h" // sched_main +DECL_CONSTANT(MCU, CONFIG_MCU); + // Main entry point for avr code. int main(void) diff --git a/src/avr/timer.c b/src/avr/timer.c index 06d8845e..3818e772 100644 --- a/src/avr/timer.c +++ b/src/avr/timer.c @@ -17,7 +17,6 @@ ****************************************************************/ DECL_CONSTANT(CLOCK_FREQ, F_CPU); -DECL_CONSTANT(MCU, CONFIG_MCU); // Return the number of clock ticks for a given number of microseconds uint32_t diff --git a/src/generic/timer.c b/src/generic/timer.c new file mode 100644 index 00000000..13a8bfe5 --- /dev/null +++ b/src/generic/timer.c @@ -0,0 +1,87 @@ +// Generic interrupt based timer helper functions +// +// Copyright (C) 2017 Kevin O'Connor +// +// This file may be distributed under the terms of the GNU GPLv3 license. + +#include "autoconf.h" // CONFIG_CLOCK_FREQ +#include "board/irq.h" // irq_disable +#include "board/misc.h" // timer_from_us +#include "command.h" // shutdown +#include "sched.h" // sched_timer_kick + +// In order to use this code the board must still define +// timer_read_time(). In addition, it must also provide a timer_set() +// function. +void timer_set(uint32_t next); + +DECL_CONSTANT(CLOCK_FREQ, CONFIG_CLOCK_FREQ); + +// Return the number of clock ticks for a given number of microseconds +uint32_t +timer_from_us(uint32_t us) +{ + return us * (CONFIG_CLOCK_FREQ / 1000000); +} + +// 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) + +#define TIMER_MIN_TRY_TICKS timer_from_us(1) +#define TIMER_DEFER_REPEAT_TICKS timer_from_us(5) + +// Set the next timer wake time (in absolute clock ticks) or return 1 +// if the next timer is too close to schedule. Caller must disable +// irqs. +uint8_t +timer_try_set_next(uint32_t next) +{ + uint32_t now = timer_read_time(); + int32_t diff = next - now; + if (diff > (int32_t)TIMER_MIN_TRY_TICKS) + // Schedule next timer normally. + goto done; + + // Next timer is in the past or near future - can't reschedule to it + if (likely(sched_is_before(now, timer_repeat_until))) { + // Can run more timers from this irq; briefly allow irqs + irq_enable(); + while (diff >= 0) { + // Next timer is in the near future - wait for time to occur + now = timer_read_time(); + diff = next - now; + } + irq_disable(); + return 0; + } + if (diff < (int32_t)(-timer_from_us(1000))) + goto fail; + + // Too many repeat timers from a single interrupt - force a pause + timer_repeat_until = now + TIMER_REPEAT_TICKS; + next = now + TIMER_DEFER_REPEAT_TICKS; + +done: + timer_set(next); + return 1; +fail: + shutdown("Rescheduled timer in the past"); +} + +// Periodic background task that temporarily boosts priority of +// timers. This helps prioritize timers when tasks are idling. +static void +timer_task(void) +{ + irq_disable(); + timer_repeat_until = timer_read_time() + TIMER_IDLE_REPEAT_TICKS; + irq_enable(); +} +DECL_TASK(timer_task); diff --git a/src/sam3x8e/Makefile b/src/sam3x8e/Makefile index bf38846f..d8e63c0c 100644 --- a/src/sam3x8e/Makefile +++ b/src/sam3x8e/Makefile @@ -16,7 +16,7 @@ LDFLAGS-y += --specs=nano.specs --specs=nosys.specs # Add source files src-y += sam3x8e/main.c sam3x8e/timer.c sam3x8e/gpio.c -src-y += generic/crc16_ccitt.c generic/armcm_irq.c +src-y += generic/crc16_ccitt.c generic/armcm_irq.c generic/timer.c src-y += ../lib/cmsis-sam3x8e/source/system_sam3xa.c src-y += ../lib/cmsis-sam3x8e/source/gcc/startup_sam3xa.c src-$(CONFIG_SERIAL) += sam3x8e/serial.c diff --git a/src/sam3x8e/main.c b/src/sam3x8e/main.c index 9fa27297..2ad907c9 100644 --- a/src/sam3x8e/main.c +++ b/src/sam3x8e/main.c @@ -5,9 +5,12 @@ // This file may be distributed under the terms of the GNU GPLv3 license. #include "board/misc.h" // alloc_maxsize +#include "command.h" // DECL_CONSTANT #include "sam3x8e.h" // WDT #include "sched.h" // sched_main +DECL_CONSTANT(MCU, "sam3x8e"); + /**************************************************************** * watchdog handler diff --git a/src/sam3x8e/timer.c b/src/sam3x8e/timer.c index dbc7700e..e450d21e 100644 --- a/src/sam3x8e/timer.c +++ b/src/sam3x8e/timer.c @@ -4,28 +4,12 @@ // // This file may be distributed under the terms of the GNU GPLv3 license. -#include "autoconf.h" // CONFIG_CLOCK_FREQ #include "board/irq.h" // irq_disable -#include "board/misc.h" // timer_from_us -#include "command.h" // shutdown +#include "board/misc.h" // timer_read_time +#include "command.h" // DECL_SHUTDOWN #include "sam3x8e.h" // TC0 #include "sched.h" // sched_timer_kick - -/**************************************************************** - * Low level timer code - ****************************************************************/ - -DECL_CONSTANT(CLOCK_FREQ, CONFIG_CLOCK_FREQ); -DECL_CONSTANT(MCU, "sam3x8e"); - -// Return the number of clock ticks for a given number of microseconds -uint32_t -timer_from_us(uint32_t us) -{ - return us * (CONFIG_CLOCK_FREQ / 1000000); -} - // IRQ handler void __visible TC0_Handler(void) @@ -37,12 +21,20 @@ TC0_Handler(void) irq_enable(); } -static void +// Set the next irq time +void timer_set(uint32_t value) { TC0->TC_CHANNEL[0].TC_RA = value; } +// Return the current time (in absolute clock ticks). +uint32_t +timer_read_time(void) +{ + return TC0->TC_CHANNEL[0].TC_CV; +} + static void timer_init(void) { @@ -70,72 +62,3 @@ timer_shutdown(void) TC0->TC_CHANNEL[0].TC_SR; // read to clear irq pending } DECL_SHUTDOWN(timer_shutdown); - -// Called by main code once every millisecond. (IRQs disabled.) -void -timer_periodic(void) -{ -} - -// Return the current time (in absolute clock ticks). -uint32_t -timer_read_time(void) -{ - return TC0->TC_CHANNEL[0].TC_CV; -} - -static uint32_t timer_repeat_until; -#define TIMER_IDLE_REPEAT_TICKS timer_from_us(500) -#define TIMER_REPEAT_TICKS timer_from_us(100) - -#define TIMER_MIN_TRY_TICKS timer_from_us(1) -#define TIMER_DEFER_REPEAT_TICKS timer_from_us(5) - -// Set the next timer wake time (in absolute clock ticks) or return 1 -// if the next timer is too close to schedule. Caller must disable -// irqs. -uint8_t -timer_try_set_next(uint32_t next) -{ - uint32_t now = timer_read_time(); - int32_t diff = next - now; - if (diff > (int32_t)TIMER_MIN_TRY_TICKS) - // Schedule next timer normally. - goto done; - - // Next timer is in the past or near future - can't reschedule to it - if (likely(sched_is_before(now, timer_repeat_until))) { - // Can run more timers from this irq; briefly allow irqs - irq_enable(); - while (diff >= 0) { - // Next timer is in the near future - wait for time to occur - now = timer_read_time(); - diff = next - now; - } - irq_disable(); - return 0; - } - if (diff < (int32_t)(-timer_from_us(1000))) - goto fail; - - // Too many repeat timers from a single interrupt - force a pause - timer_repeat_until = now + TIMER_REPEAT_TICKS; - next = now + TIMER_DEFER_REPEAT_TICKS; - -done: - timer_set(next); - return 1; -fail: - shutdown("Rescheduled timer in the past"); -} - -// Periodic background task that temporarily boosts priority of -// timers. This helps prioritize timers when tasks are idling. -static void -timer_task(void) -{ - irq_disable(); - timer_repeat_until = timer_read_time() + TIMER_IDLE_REPEAT_TICKS; - irq_enable(); -} -DECL_TASK(timer_task);