μT-Kernel for Raspberry Pi おぼえがき(5)
タイマー周り
μT-Kernel のシステム資源としてタイマーがある。kernel/tkernel/src/timer.c の knl_timer_initialize という関数が初期化ルーチンである。
knl_timer_initialize が呼ばれるまでを順番に追うと、
- icrt0.S の kernel_start: の次の行の main() の呼び出し
- kernel/sysinit/src/sysinit_main.c の main
- kernel/tkernel/src/tkstart.c の knl_t_kernel_main
- InitModule(timer) というマクロが knl_timer_initialize() に展開されて knl_timer_initialize の呼び出し
となる。
knl_timer_initialize は knl_start_hw_timer を呼び出している。knl_start_hw_timer は kernel/sysdepend/device/app_raspib/tkdev_timer.h で Inline として定義されていて knl_init_hw_timer で必要なハードウェアの初期化をおこなったあと、knl_define_inthdr(1, knl_timer_handler_startup) のように、割込みハンドラを設定する。1 は BCM2708 のタイマー 1 の割込み番号で、データシートには書いてないが Linux の linux/arch/arm/mach-bcm2708/include/mach/platform.h を参考にした。
BCM2708 のタイマーは、常にカウントアップし続けているカウンタがあって、割込みを起こすカウントをセットする、という使い方しかできない。周波数は 1MHz (1000000Hz) である。knl_init_hw_timer では、最初の割込みのためのカウントを設定している。
Inline void knl_init_hw_timer( void ) { knl_timer_interval = CFN_TIMER_PERIOD * TMCLK / 1000; /* set first wakeup */ knl_timer_next = in_w(0x20003004) + knl_timer_interval; out_w(0x20003010, knl_timer_next); }
一旦動き出してからは、割込みハンドラ knl_timer_handler_startup ( kernel/sysdepend/cpu/raspib/cpu_support.S ) から呼ばれている knl_timer_handler(機種共通部) から呼んでいる knl_clear_hw_timer_interrupt ( kernel/sysdepend/device/app_raspib/tkdev_timer.h ) で、次のカウントを設定している。
Inline void knl_clear_hw_timer_interrupt( void ) { /* set next wakeup */ knl_timer_next += knl_timer_interval; out_w(0x20003010, knl_timer_next); /* Timer interrupt disable */ DisableInt(1); /* Clear timer interrupt */ out_w(0x20003000, 0x00000002); /* Multiplexed interrupt enable */ ENAINT; }