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