timer.c

Go to the documentation of this file.
00001 
00040 #include "timer.h"
00041 
00042 #include <cpu/attr.h>
00043 #include <cpu/types.h>
00044 #include <cpu/irq.h>
00045 
00046 #include <cfg/os.h>
00047 #include <cfg/debug.h>
00048 #include <cfg/module.h>
00049 #include <appconfig.h>
00050 
00051 /*
00052  * Include platform-specific binding code if we're hosted.
00053  * Try the CPU specific one for bare-metal environments.
00054  */
00055 #if OS_HOSTED
00056     #include OS_CSOURCE(timer)
00057 #else
00058     #include CPU_CSOURCE(timer)
00059 #endif
00060 
00061 /*
00062  * Sanity check for config parameters required by this module.
00063  */
00064 #if !defined(CONFIG_KERNEL) || ((CONFIG_KERNEL != 0) && CONFIG_KERNEL != 1)
00065     #error CONFIG_KERNEL must be set to either 0 or 1 in config.h
00066 #endif
00067 #if !defined(CONFIG_WATCHDOG) || ((CONFIG_WATCHDOG != 0) && CONFIG_WATCHDOG != 1)
00068     #error CONFIG_WATCHDOG must be set to either 0 or 1 in config.h
00069 #endif
00070 
00071 #if CONFIG_WATCHDOG
00072     #include <drv/wdt.h>
00073 #endif
00074 
00075 #if CONFIG_KERNEL
00076     #include <config_kern.h>
00077     #if CONFIG_KERN_PREEMPTIVE
00078         #include <hw/switch.h>
00079     #endif
00080     #if CONFIG_KERN_SIGNALS
00081         #include <kern/signal.h> /* sig_wait(), sig_check() */
00082         #include <kern/proc.h>   /* proc_current() */
00083         #include <cfg/macros.h>  /* BV() */
00084     #endif
00085 #endif
00086 
00087 
00098 #if !defined(CONFIG_TIMER_STROBE) || !CONFIG_TIMER_STROBE
00099     #define TIMER_STROBE_ON    do {/*nop*/} while(0)
00100     #define TIMER_STROBE_OFF   do {/*nop*/} while(0)
00101     #define TIMER_STROBE_INIT  do {/*nop*/} while(0)
00102 #endif
00103 
00104 
00106 volatile ticks_t _clock;
00107 
00108 
00109 #ifndef CONFIG_TIMER_DISABLE_EVENTS
00110 
00114 REGISTER static List timers_queue;
00115 
00116 
00124 void timer_add(Timer *timer)
00125 {
00126     Timer *node;
00127     cpuflags_t flags;
00128 
00129 
00130     /* Inserting timers twice causes mayhem. */
00131     ASSERT(timer->magic != TIMER_MAGIC_ACTIVE);
00132     DB(timer->magic = TIMER_MAGIC_ACTIVE;)
00133 
00134     IRQ_SAVE_DISABLE(flags);
00135 
00136     /* Calculate expiration time for this timer */
00137     timer->tick = _clock + timer->_delay;
00138 
00139     /*
00140      * Search for the first node whose expiration time is
00141      * greater than the timer we want to add.
00142      */
00143     node = (Timer *)LIST_HEAD(&timers_queue);
00144     while (node->link.succ)
00145     {
00146         /*
00147          * Stop just after the insertion point.
00148          * (this fancy compare takes care of wrap-arounds).
00149          */
00150         if (node->tick - timer->tick > 0)
00151             break;
00152 
00153         /* Go to next node */
00154         node = (Timer *)node->link.succ;
00155     }
00156 
00157     /* Enqueue timer request into the list */
00158     INSERT_BEFORE(&timer->link, &node->link);
00159 
00160     IRQ_RESTORE(flags);
00161 }
00162 
00163 
00167 Timer *timer_abort(Timer *timer)
00168 {
00169     ATOMIC(REMOVE(&timer->link));
00170     DB(timer->magic = TIMER_MAGIC_INACTIVE;)
00171 
00172     return timer;
00173 }
00174 
00175 #endif /* CONFIG_TIMER_DISABLE_EVENTS */
00176 
00177 
00181 void timer_delayTicks(ticks_t delay)
00182 {
00183 #if defined(IRQ_ENABLED)
00184     /* We shouldn't sleep with interrupts disabled */
00185     ASSERT(IRQ_ENABLED());
00186 #endif
00187 
00188 #if defined(CONFIG_KERN_SIGNALS) && CONFIG_KERN_SIGNALS
00189     Timer t;
00190 
00191     ASSERT(!sig_check(SIG_SINGLE));
00192     timer_set_event_signal(&t, proc_current(), SIG_SINGLE);
00193     timer_setDelay(&t, delay);
00194     timer_add(&t);
00195     sig_wait(SIG_SINGLE);
00196 
00197 #else /* !CONFIG_KERN_SIGNALS */
00198 
00199     ticks_t start = timer_clock();
00200 
00201     /* Busy wait */
00202     while (timer_clock() - start < delay)
00203     {
00204 #if CONFIG_WATCHDOG
00205         wdt_reset();
00206 #endif
00207     }
00208 
00209 #endif /* !CONFIG_KERN_SIGNALS */
00210 }
00211 
00212 
00213 #ifndef CONFIG_TIMER_DISABLE_UDELAY
00214 
00221 void timer_busyWait(hptime_t delay)
00222 {
00223     hptime_t now, prev = timer_hw_hpread();
00224     hptime_t delta;
00225 
00226     for(;;)
00227     {
00228         now = timer_hw_hpread();
00229         /*
00230          * We rely on hptime_t being unsigned here to
00231          * reduce the modulo to an AND in the common
00232          * case of TIMER_HW_CNT.
00233          */
00234         delta = (now - prev) % TIMER_HW_CNT;
00235         if (delta >= delay)
00236             break;
00237         delay -= delta;
00238         prev = now;
00239     }
00240 }
00241 
00249 void timer_delayHp(hptime_t delay)
00250 {
00251     if (UNLIKELY(delay > us_to_hptime(1000)))
00252     {
00253         timer_delayTicks(delay / (TIMER_HW_HPTICKS_PER_SEC / TIMER_TICKS_PER_SEC));
00254         delay %= (TIMER_HW_HPTICKS_PER_SEC / TIMER_TICKS_PER_SEC);
00255     }
00256 
00257     timer_busyWait(delay);
00258 }
00259 #endif /* CONFIG_TIMER_DISABLE_UDELAY */
00260 
00261 
00266 DEFINE_TIMER_ISR
00267 {
00268     /*
00269      * With the Metrowerks compiler, the only way to force the compiler generate
00270      * an interrupt service routine is to put a pragma directive within the function
00271      * body.
00272      */
00273     #ifdef __MWERKS__
00274     #pragma interrupt saveall
00275     #endif
00276 
00277 #ifndef CONFIG_TIMER_DISABLE_EVENTS
00278     Timer *timer;
00279 #endif
00280     /*
00281      * On systems sharing IRQ line and vector, this check is needed
00282      * to ensure that IRQ is generated by timer source.
00283      */
00284     if (!timer_hw_triggered())
00285         return;
00286 
00287     TIMER_STROBE_ON;
00288 
00289     /* Perform hw IRQ handling */
00290     timer_hw_irq();
00291 
00292     /* Update the master ms counter */
00293     ++_clock;
00294 
00295 #ifndef CONFIG_TIMER_DISABLE_EVENTS
00296     /*
00297      * Check the first timer request in the list and process
00298      * it when it has expired. Repeat this check until the
00299      * first node has not yet expired. Since the list is sorted
00300      * by expiry time, all the following requests are guaranteed
00301      * to expire later.
00302      */
00303     while ((timer = (Timer *)LIST_HEAD(&timers_queue))->link.succ)
00304     {
00305         /* This request in list has not yet expired? */
00306         if (_clock - timer->tick < 0)
00307             break;
00308 
00309         /* Retreat the expired timer */
00310         REMOVE(&timer->link);
00311         DB(timer->magic = TIMER_MAGIC_INACTIVE;)
00312 
00313         /* Execute the associated event */
00314         event_do(&timer->expire);
00315     }
00316 #endif /* CONFIG_TIMER_DISABLE_EVENTS */
00317 
00318     TIMER_STROBE_OFF;
00319 }
00320 
00321 MOD_DEFINE(timer)
00322 
00323 
00326 void timer_init(void)
00327 {
00328     TIMER_STROBE_INIT;
00329 
00330 #ifndef CONFIG_TIMER_DISABLE_EVENTS
00331     LIST_INIT(&timers_queue);
00332 #endif
00333 
00334     _clock = 0;
00335 
00336     timer_hw_init();
00337 
00338     MOD_INIT(timer);
00339 }