読者です 読者をやめる 読者になる 読者になる

μ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 の割込み番号で、データシートには書いてないが Linuxlinux/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;
}