4 * Copyright 2003, 2004, 2005, 2006 Develer S.r.l. (http://www.develer.com/)
5 * Copyright 2000 Bernardo Innocenti <bernie@develer.com>
6 * This file is part of DevLib - See README.devlib for information.
9 * \brief Hardware independent timer driver (implementation)
12 * \author Bernardo Innocenti <bernie@develer.com>
17 *#* Revision 1.32 2007/10/08 12:14:32 batt
18 *#* Fix some review issues.
20 *#* Revision 1.31 2006/07/19 12:56:26 bernie
21 *#* Convert to new Doxygen style.
23 *#* Revision 1.30 2006/02/24 00:26:49 bernie
24 *#* Fixes for CONFIG_KERNEL.
26 *#* Revision 1.29 2006/02/17 22:24:07 bernie
27 *#* Add MOD_CHECK() checks.
29 *#* Revision 1.28 2006/02/10 12:32:52 bernie
30 *#* Update Copyright year.
32 *#* Revision 1.27 2005/11/27 03:04:08 bernie
33 *#* Move test code to timer_test.c; Add OS_HOSTED support.
35 *#* Revision 1.26 2005/11/04 16:20:02 bernie
36 *#* Fix reference to README.devlib in header.
38 *#* Revision 1.25 2005/07/19 07:26:37 bernie
39 *#* Refactor to decouple timer ticks from milliseconds.
41 *#* Revision 1.24 2005/04/11 19:10:28 bernie
42 *#* Include top-level headers from cfg/ subdir.
44 *#* Revision 1.23 2004/12/13 12:07:06 bernie
45 *#* DISABLE_IRQSAVE/ENABLE_IRQRESTORE: Convert to IRQ_SAVE_DISABLE/IRQ_RESTORE.
47 *#* Revision 1.22 2004/12/08 09:12:09 bernie
48 *#* Rename time_t to mtime_t.
50 *#* Revision 1.21 2004/11/28 23:20:25 bernie
51 *#* Remove obsolete INITLIST macro.
53 *#* Revision 1.20 2004/11/16 20:59:06 bernie
54 *#* Add watchdog timer support.
60 #include <cfg/debug.h>
61 #include <cfg/module.h>
62 #include <appconfig.h>
65 * Include platform-specific binding code if we're hosted.
66 * Try the CPU specific one for bare-metal environments.
69 #include OS_CSOURCE(timer)
71 #include CPU_CSOURCE(timer)
75 * Sanity check for config parameters required by this module.
77 #if !defined(CONFIG_KERNEL) || ((CONFIG_KERNEL != 0) && CONFIG_KERNEL != 1)
78 #error CONFIG_KERNEL must be set to either 0 or 1 in config.h
80 #if !defined(CONFIG_WATCHDOG) || ((CONFIG_WATCHDOG != 0) && CONFIG_WATCHDOG != 1)
81 #error CONFIG_WATCHDOG must be set to either 0 or 1 in config.h
89 #include <config_kern.h>
90 #if CONFIG_KERN_SIGNALS
91 #include <kern/signal.h> /* sig_wait(), sig_check() */
92 #include <kern/proc.h> /* proc_current() */
93 #include <cfg/macros.h> /* BV() */
99 * \def CONFIG_TIMER_STROBE
101 * This is a debug facility that can be used to
102 * monitor timer interrupt activity on an external pin.
104 * To use strobes, redefine the macros TIMER_STROBE_ON,
105 * TIMER_STROBE_OFF and TIMER_STROBE_INIT and set
106 * CONFIG_TIMER_STROBE to 1.
108 #if !defined(CONFIG_TIMER_STROBE) || !CONFIG_TIMER_STROBE
109 #define TIMER_STROBE_ON do {/*nop*/} while(0)
110 #define TIMER_STROBE_OFF do {/*nop*/} while(0)
111 #define TIMER_STROBE_INIT do {/*nop*/} while(0)
115 /// Master system clock (1 tick accuracy)
116 volatile ticks_t _clock;
119 #ifndef CONFIG_TIMER_DISABLE_EVENTS
122 * List of active asynchronous timers.
124 REGISTER static List timers_queue;
128 * Add the specified timer to the software timer service queue.
129 * When the delay indicated by the timer expires, the timer
130 * device will execute the event associated with it.
132 * \note Interrupt safe
134 void timer_add(Timer *timer)
140 /* Inserting timers twice causes mayhem. */
141 ASSERT(timer->magic != TIMER_MAGIC_ACTIVE);
142 DB(timer->magic = TIMER_MAGIC_ACTIVE;)
144 IRQ_SAVE_DISABLE(flags);
146 /* Calculate expiration time for this timer */
147 timer->tick = _clock + timer->_delay;
150 * Search for the first node whose expiration time is
151 * greater than the timer we want to add.
153 node = (Timer *)LIST_HEAD(&timers_queue);
154 while (node->link.succ)
157 * Stop just after the insertion point.
158 * (this fancy compare takes care of wrap-arounds).
160 if (node->tick - timer->tick > 0)
163 /* Go to next node */
164 node = (Timer *)node->link.succ;
167 /* Enqueue timer request into the list */
168 INSERT_BEFORE(&timer->link, &node->link);
175 * Remove a timer from the timer queue before it has expired.
177 Timer *timer_abort(Timer *timer)
179 ATOMIC(REMOVE(&timer->link));
180 DB(timer->magic = TIMER_MAGIC_INACTIVE;)
185 #endif /* CONFIG_TIMER_DISABLE_EVENTS */
189 * Wait for the specified amount of timer ticks.
191 void timer_delayTicks(ticks_t delay)
193 #if defined(IRQ_GETSTATE)
194 /* We shouldn't sleep with interrupts disabled */
195 ASSERT(IRQ_GETSTATE());
198 #if defined(CONFIG_KERN_SIGNALS) && CONFIG_KERN_SIGNALS
201 ASSERT(!sig_check(SIG_SINGLE));
202 timer_set_event_signal(&t, proc_current(), SIG_SINGLE);
203 timer_setDelay(&t, delay);
205 sig_wait(SIG_SINGLE);
207 #else /* !CONFIG_KERN_SIGNALS */
209 ticks_t start = timer_clock();
212 while (timer_clock() - start < delay)
219 #endif /* !CONFIG_KERN_SIGNALS */
223 #ifndef CONFIG_TIMER_DISABLE_UDELAY
226 * Busy wait until the specified amount of high-precision ticks have elapsed.
228 * \note This function is interrupt safe, the only
229 * requirement is a running hardware timer.
231 void timer_busyWait(hptime_t delay)
233 hptime_t now, prev = timer_hw_hpread();
238 now = timer_hw_hpread();
240 * We rely on hptime_t being unsigned here to
241 * reduce the modulo to an AND in the common
242 * case of TIMER_HW_CNT.
244 delta = (now - prev) % TIMER_HW_CNT;
253 * Wait for the specified amount of time (expressed in microseconds).
255 * \bug In AVR arch the maximum amount of time that can be used as
256 * delay could be very limited, depending on the hardware timer
257 * used. Check timer_avr.h, and what register is used as hptime_t.
259 void timer_delayHp(hptime_t delay)
261 if (UNLIKELY(delay > us_to_hptime(1000)))
263 timer_delayTicks(delay / (TIMER_HW_HPTICKS_PER_SEC / TIMER_TICKS_PER_SEC));
264 delay %= (TIMER_HW_HPTICKS_PER_SEC / TIMER_TICKS_PER_SEC);
267 timer_busyWait(delay);
269 #endif /* CONFIG_TIMER_DISABLE_UDELAY */
273 * Timer interrupt handler. Find soft timers expired and
274 * trigger corresponding events.
279 * With the Metrowerks compiler, the only way to force the compiler generate
280 * an interrupt service routine is to put a pragma directive within the function
284 #pragma interrupt saveall
287 #ifndef CONFIG_TIMER_DISABLE_EVENTS
291 * On systems sharing IRQ line and vector, this check is needed
292 * to ensure that IRQ is generated by timer source.
294 if (!timer_hw_triggered())
299 /* Perform hw IRQ handling */
302 /* Update the master ms counter */
305 #ifndef CONFIG_TIMER_DISABLE_EVENTS
307 * Check the first timer request in the list and process
308 * it when it has expired. Repeat this check until the
309 * first node has not yet expired. Since the list is sorted
310 * by expiry time, all the following requests are guaranteed
313 while ((timer = (Timer *)LIST_HEAD(&timers_queue))->link.succ)
315 /* This request in list has not yet expired? */
316 if (_clock - timer->tick < 0)
319 /* Retreat the expired timer */
320 REMOVE(&timer->link);
321 DB(timer->magic = TIMER_MAGIC_INACTIVE;)
323 /* Execute the associated event */
324 event_do(&timer->expire);
326 #endif /* CONFIG_TIMER_DISABLE_EVENTS */
336 void timer_init(void)
340 #ifndef CONFIG_TIMER_DISABLE_EVENTS
341 LIST_INIT(&timers_queue);