timer.c
Go to the documentation of this file.00001
00039 #include "timer.h"
00040 #include "hw/hw_timer.h"
00041
00042 #include "cfg/cfg_timer.h"
00043 #include "cfg/cfg_wdt.h"
00044 #include "cfg/cfg_proc.h"
00045 #include "cfg/cfg_signal.h"
00046 #include <cfg/os.h>
00047 #include <cfg/debug.h>
00048 #include <cfg/module.h>
00049
00050 #include <cpu/attr.h>
00051 #include <cpu/types.h>
00052 #include <cpu/irq.h>
00053 #include <cpu/power.h>
00054
00055 #include <kern/proc_p.h>
00056
00057
00058
00059
00060
00061 #if OS_HOSTED
00062
00063 #include <emul/timer_posix.c>
00064 #else
00065 #ifndef WIZ_AUTOGEN
00066 #warning Deprecated: now you should include timer_<cpu> directly in the makefile. Remove this line and the following once done.
00067 #include CPU_CSOURCE(timer)
00068 #endif
00069 #endif
00070
00071
00072
00073
00074 #if !defined(CONFIG_KERN) || ((CONFIG_KERN != 0) && CONFIG_KERN != 1)
00075 #error CONFIG_KERN must be set to either 0 or 1 in config.h
00076 #endif
00077 #if !defined(CONFIG_WATCHDOG) || ((CONFIG_WATCHDOG != 0) && CONFIG_WATCHDOG != 1)
00078 #error CONFIG_WATCHDOG must be set to either 0 or 1 in config.h
00079 #endif
00080
00081 #if CONFIG_WATCHDOG
00082 #include <drv/wdt.h>
00083 #endif
00084
00085 #if defined (CONFIG_KERN_SIGNALS) && CONFIG_KERN_SIGNALS
00086 #include <kern/signal.h>
00087 #include <kern/proc.h>
00088 #include <cfg/macros.h>
00089 #endif
00090
00091
00102 #if !defined(CONFIG_TIMER_STROBE) || !CONFIG_TIMER_STROBE
00103 #define TIMER_STROBE_ON do {} while(0)
00104 #define TIMER_STROBE_OFF do {} while(0)
00105 #define TIMER_STROBE_INIT do {} while(0)
00106 #endif
00107
00108
00110 volatile ticks_t _clock;
00111
00112
00113 #if CONFIG_TIMER_EVENTS
00114
00118 REGISTER static List timers_queue;
00119
00124 INLINE void timer_addToList(Timer *timer, List *queue)
00125 {
00126
00127 ASSERT(timer->magic != TIMER_MAGIC_ACTIVE);
00128 DB(timer->magic = TIMER_MAGIC_ACTIVE;)
00129
00130
00131
00132 timer->tick = _clock + timer->_delay;
00133
00134
00135
00136
00137
00138 Timer *node = (Timer *)LIST_HEAD(queue);
00139 while (node->link.succ)
00140 {
00141
00142
00143
00144
00145 if (node->tick - timer->tick > 0)
00146 break;
00147
00148
00149 node = (Timer *)node->link.succ;
00150 }
00151
00152
00153 INSERT_BEFORE(&timer->link, &node->link);
00154 }
00155
00163 void timer_add(Timer *timer)
00164 {
00165 ATOMIC(timer_addToList(timer, &timers_queue));
00166 }
00167
00174 Timer *timer_abort(Timer *timer)
00175 {
00176 ATOMIC(REMOVE(&timer->link));
00177 DB(timer->magic = TIMER_MAGIC_INACTIVE;)
00178
00179 return timer;
00180 }
00181
00182
00183 INLINE void timer_poll(List *queue)
00184 {
00185 Timer *timer;
00186
00187
00188
00189
00190
00191
00192
00193
00194 while ((timer = (Timer *)LIST_HEAD(queue))->link.succ)
00195 {
00196
00197 if (timer_clock() - timer->tick < 0)
00198 break;
00199
00200
00201 REMOVE(&timer->link);
00202 DB(timer->magic = TIMER_MAGIC_INACTIVE;)
00203
00204
00205 event_do(&timer->expire);
00206 }
00207 }
00208
00213 void synctimer_add(Timer *timer, List *queue)
00214 {
00215 timer_addToList(timer, queue);
00216 }
00217
00235 void synctimer_poll(List *queue)
00236 {
00237 timer_poll(queue);
00238 }
00239
00240 #endif
00241
00242
00248 void timer_delayTicks(ticks_t delay)
00249 {
00250
00251 IRQ_ASSERT_ENABLED();
00252
00253 #if CONFIG_KERN_SIGNALS
00254 Timer t;
00255
00256 if (proc_preemptAllowed())
00257 {
00258 ASSERT(!sig_check(SIG_SINGLE));
00259 timer_setSignal(&t, proc_current(), SIG_SINGLE);
00260 timer_setDelay(&t, delay);
00261 timer_add(&t);
00262 sig_wait(SIG_SINGLE);
00263 }
00264 else
00265 #endif
00266 {
00267 ticks_t start = timer_clock();
00268
00269
00270 while (timer_clock() - start < delay)
00271 cpu_relax();
00272 }
00273 }
00274
00275
00276 #if CONFIG_TIMER_UDELAY
00277
00284 void timer_busyWait(hptime_t delay)
00285 {
00286 hptime_t now, prev = timer_hw_hpread();
00287 hptime_t delta;
00288
00289 for(;;)
00290 {
00291 now = timer_hw_hpread();
00292
00293
00294
00295
00296
00297 delta = (now - prev) % TIMER_HW_CNT;
00298 if (delta >= delay)
00299 break;
00300 delay -= delta;
00301 prev = now;
00302 }
00303 }
00304
00312 void timer_delayHp(hptime_t delay)
00313 {
00314 if (UNLIKELY(delay > us_to_hptime(1000)))
00315 {
00316 timer_delayTicks(delay / (TIMER_HW_HPTICKS_PER_SEC / TIMER_TICKS_PER_SEC));
00317 delay %= (TIMER_HW_HPTICKS_PER_SEC / TIMER_TICKS_PER_SEC);
00318 }
00319
00320 timer_busyWait(delay);
00321 }
00322 #endif
00323
00328 DEFINE_TIMER_ISR
00329 {
00330
00331
00332
00333
00334
00335 #ifdef __MWERKS__
00336 #pragma interrupt saveall
00337 #endif
00338
00339
00340
00341
00342
00343 if (!timer_hw_triggered())
00344 return;
00345
00346 TIMER_STROBE_ON;
00347
00348
00349 ++_clock;
00350
00351
00352 proc_decQuantum();
00353
00354 #if CONFIG_TIMER_EVENTS
00355 timer_poll(&timers_queue);
00356 #endif
00357
00358
00359 timer_hw_irq();
00360
00361 TIMER_STROBE_OFF;
00362 }
00363
00364 MOD_DEFINE(timer)
00365
00366
00369 void timer_init(void)
00370 {
00371 #if CONFIG_KERN_IRQ
00372 MOD_CHECK(irq);
00373 #endif
00374
00375 #if CONFIG_TIMER_EVENTS
00376 LIST_INIT(&timers_queue);
00377 #endif
00378
00379 TIMER_STROBE_INIT;
00380
00381 _clock = 0;
00382
00383 timer_hw_init();
00384
00385 MOD_INIT(timer);
00386 }
00387
00388
00389 #if (ARCH & ARCH_EMUL)
00390
00393 void timer_cleanup(void)
00394 {
00395 MOD_CLEANUP(timer);
00396
00397 timer_hw_cleanup();
00398
00399
00400
00401 }
00402 #endif