timer.c
Go to the documentation of this file.00001
00039 #include "timer.h"
00040
00041 #include "cfg/cfg_timer.h"
00042 #include "cfg/cfg_wdt.h"
00043 #include "cfg/cfg_proc.h"
00044 #include "cfg/cfg_signal.h"
00045 #include <cfg/os.h>
00046 #include <cfg/debug.h>
00047 #include <cfg/module.h>
00048
00049 #include <cpu/attr.h>
00050 #include <cpu/types.h>
00051 #include <cpu/irq.h>
00052 #include <cpu/power.h>
00053
00054
00055
00056
00057
00058 #if OS_HOSTED
00059
00060 #include <emul/timer_posix.c>
00061 #else
00062 #ifndef WIZ_AUTOGEN
00063 #warning Deprecated: now you should include timer_<cpu> directly in the makefile. Remove this line and the following once done.
00064 #include CPU_CSOURCE(timer)
00065 #endif
00066 #endif
00067
00068
00069
00070
00071 #if !defined(CONFIG_KERN) || ((CONFIG_KERN != 0) && CONFIG_KERN != 1)
00072 #error CONFIG_KERN must be set to either 0 or 1 in config.h
00073 #endif
00074 #if !defined(CONFIG_WATCHDOG) || ((CONFIG_WATCHDOG != 0) && CONFIG_WATCHDOG != 1)
00075 #error CONFIG_WATCHDOG must be set to either 0 or 1 in config.h
00076 #endif
00077
00078 #if CONFIG_WATCHDOG
00079 #include <drv/wdt.h>
00080 #endif
00081
00082 #if defined (CONFIG_KERN_SIGNALS) && CONFIG_KERN_SIGNALS
00083 #include <kern/signal.h>
00084 #include <kern/proc.h>
00085 #include <cfg/macros.h>
00086 #endif
00087
00088
00099 #if !defined(CONFIG_TIMER_STROBE) || !CONFIG_TIMER_STROBE
00100 #define TIMER_STROBE_ON do {} while(0)
00101 #define TIMER_STROBE_OFF do {} while(0)
00102 #define TIMER_STROBE_INIT do {} while(0)
00103 #endif
00104
00105
00107 volatile ticks_t _clock;
00108
00109
00110 #if CONFIG_TIMER_EVENTS
00111
00115 REGISTER static List timers_queue;
00116
00117
00125 void timer_add(Timer *timer)
00126 {
00127 Timer *node;
00128 cpu_flags_t flags;
00129
00130
00131
00132 ASSERT(timer->magic != TIMER_MAGIC_ACTIVE);
00133 DB(timer->magic = TIMER_MAGIC_ACTIVE;)
00134
00135 IRQ_SAVE_DISABLE(flags);
00136
00137
00138 timer->tick = _clock + timer->_delay;
00139
00140
00141
00142
00143
00144 node = (Timer *)LIST_HEAD(&timers_queue);
00145 while (node->link.succ)
00146 {
00147
00148
00149
00150
00151 if (node->tick - timer->tick > 0)
00152 break;
00153
00154
00155 node = (Timer *)node->link.succ;
00156 }
00157
00158
00159 INSERT_BEFORE(&timer->link, &node->link);
00160
00161 IRQ_RESTORE(flags);
00162 }
00163
00164
00171 Timer *timer_abort(Timer *timer)
00172 {
00173 ATOMIC(REMOVE(&timer->link));
00174 DB(timer->magic = TIMER_MAGIC_INACTIVE;)
00175
00176 return timer;
00177 }
00178
00179 #endif
00180
00181
00185 void timer_delayTicks(ticks_t delay)
00186 {
00187
00188 IRQ_ASSERT_ENABLED();
00189
00190 #if defined(CONFIG_KERN_SIGNALS) && CONFIG_KERN_SIGNALS
00191 Timer t;
00192
00193 ASSERT(!sig_check(SIG_SINGLE));
00194 timer_setSignal(&t, proc_current(), SIG_SINGLE);
00195 timer_setDelay(&t, delay);
00196 timer_add(&t);
00197 sig_wait(SIG_SINGLE);
00198
00199 #else
00200
00201 ticks_t start = timer_clock();
00202
00203
00204 while (timer_clock() - start < delay)
00205 cpu_relax();
00206
00207 #endif
00208 }
00209
00210
00211 #if CONFIG_TIMER_UDELAY
00212
00219 void timer_busyWait(hptime_t delay)
00220 {
00221 hptime_t now, prev = timer_hw_hpread();
00222 hptime_t delta;
00223
00224 for(;;)
00225 {
00226 now = timer_hw_hpread();
00227
00228
00229
00230
00231
00232 delta = (now - prev) % TIMER_HW_CNT;
00233 if (delta >= delay)
00234 break;
00235 delay -= delta;
00236 prev = now;
00237 }
00238 }
00239
00247 void timer_delayHp(hptime_t delay)
00248 {
00249 if (UNLIKELY(delay > us_to_hptime(1000)))
00250 {
00251 timer_delayTicks(delay / (TIMER_HW_HPTICKS_PER_SEC / TIMER_TICKS_PER_SEC));
00252 delay %= (TIMER_HW_HPTICKS_PER_SEC / TIMER_TICKS_PER_SEC);
00253 }
00254
00255 timer_busyWait(delay);
00256 }
00257 #endif
00258
00259
00264 DEFINE_TIMER_ISR
00265 {
00266
00267
00268
00269
00270
00271 #ifdef __MWERKS__
00272 #pragma interrupt saveall
00273 #endif
00274
00275 #if CONFIG_TIMER_EVENTS
00276 Timer *timer;
00277 #endif
00278
00279
00280
00281
00282
00283 if (!timer_hw_triggered())
00284 return;
00285
00286 TIMER_STROBE_ON;
00287
00288
00289 timer_hw_irq();
00290
00291
00292 ++_clock;
00293
00294 #if CONFIG_TIMER_EVENTS
00295
00296
00297
00298
00299
00300
00301
00302 while ((timer = (Timer *)LIST_HEAD(&timers_queue))->link.succ)
00303 {
00304
00305 if (_clock - timer->tick < 0)
00306 break;
00307
00308
00309 REMOVE(&timer->link);
00310 DB(timer->magic = TIMER_MAGIC_INACTIVE;)
00311
00312
00313 event_do(&timer->expire);
00314 }
00315 #endif
00316
00317 TIMER_STROBE_OFF;
00318 }
00319
00320 MOD_DEFINE(timer)
00321
00322
00325 void timer_init(void)
00326 {
00327 #if CONFIG_KERN_IRQ
00328 MOD_CHECK(irq);
00329 #endif
00330
00331 #if CONFIG_TIMER_EVENTS
00332 LIST_INIT(&timers_queue);
00333 #endif
00334
00335 TIMER_STROBE_INIT;
00336
00337 _clock = 0;
00338
00339 timer_hw_init();
00340
00341 MOD_INIT(timer);
00342 }
00343
00344
00345 #if (ARCH & ARCH_EMUL)
00346
00349 void timer_cleanup(void)
00350 {
00351 MOD_CLEANUP(timer);
00352
00353 timer_hw_cleanup();
00354
00355
00356
00357 }
00358 #endif