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