タイマー

GBAのタイマーは4つ用意されており、カウントアップにはCPUのクロック数が基準になっています。人間の体感では秒より下数桁はなかなか知覚できない世界です。少し背中がむず痒くなるかもしれません。GBAのCPUクロック数は16.78Mhzです。Hzにすると16,780,000になります。クロック数を1秒で割り算すると1サイクル時間がわかるという寸法です。結果は0.00000005959475566となりました。これらを人間に理解できる単位に直してみましょう。

s0.00000005959475566
ミリ秒ms0.00005959475566
マイクロ秒us0.05959475566
ナノ秒ns59.59475566

秒を1000倍したのがミリ秒、ミリ秒を1000倍したのがマイクロ秒、マイクロ秒を1000倍したのがナノ秒という単位です。約59nsがCPUの1クロック数ということがわかりました。さて、タイマーは1, 64, 256, 1024クロックごとにインクリメント(カウントアップ)する設定が可能です。この関係を表にすると以下のようになります。

1クロック1サイクル時間(ns)
159.59475566
643814.064362
25615256.25745
102461025.0298

そろそろ頭痛くなってきました。書いている中の人もこの数値に意味を持たせることはできるのだろうかと思ってしまいます。もう少しお付き合いください。このタイマーカウンターは16bitである為、0x0から0xffffという範囲が決まっています。この入れ物を溢れさせる数0x10000(10進数は65536)を計算したものが次の表です。

nsusmss
1 * 0x100003905601.9073905.6019073.9056019070.003905601907
64 * 0x10000249958522.1249958.5221249.95852210.2499585221
256 * 0x10000999834088.2999834.0882999.83408820.9998340882
1024 * 0x1000039993363533999336.3533999.3363533.999336353

ナノ秒の世界からようやく秒の世界に戻ってきました。上記の表でいうと256クロックでカウンタを0から開始すると、約1秒後(0.99834...)にカウンタが溢れるということがわかります。このことから0.5秒後にしたいなら初期値を0x10000/2にすれば良いということもわかります。

アドレス

タイマーの値はu16(16bit)なので65536(0x10000)まで増加すると次は0になります。このことをオーバーフローといいます。オーバーフロー時、割り込みを発生させることやカスケード機能(後述)を利用することができます。なお0以外の初期値を入れておくとオーバーフロー時、その初期値に戻ります。

下位0-1bitにて1, 64, 256, 1024クロックのどのタイミングでインクリメントするかを決めます。下位2bit目は、カスケード機能と呼ばれていて下位のタイマー(タイマー1なら0、タイマー2なら1)がオーバーフローしたときに、上位のタイマーの値がインクリメントされるという機能です。カスケード機能を使うと上位のタイマー自身は周期によってインクリメントされないようになります。ちなみにタイマー0は下位のタイマーがないのでカスケード機能は使えません。6bit目はタイマーがオーバーフローしたときに割り込みを発生させるかの設定です。7bit目はセットした瞬間にタイマーが開始されます。順番としてはTMxCNT_Lで値を入れてからTMxCNT_Hを実行してください。

1.png

動作例

int main(void)
{
	// モード設定
	SetMode(MODE_0 | OBJ_ENABLE | OBJ_1D_MAP);

	SpriteInit();
	SpriteSetDatChr((u16*)&sprTiles, sprTilesLen);
	SpriteSetDatPal((u16*)&sprPal);

	u32 i;

	// タイマー0  5個のスプライトを使用
	for(i=0; i<5; i++)
	{
		SpriteSetSize (i, OBJ_SIZE(Sprite_8x8), OBJ_SQUARE, OBJ_16_COLOR);
		SpriteSetChr  (i, 0);
		SpriteMove    (i, 20+i*8, 20);
		SpriteSetPalNo(i, 0);
	}

	// タイマー1  5個のスプライトを使用
	for(i=5; i<10; i++)
	{
		SpriteSetSize (i, OBJ_SIZE(Sprite_8x8), OBJ_SQUARE, OBJ_16_COLOR);
		SpriteSetChr  (i, 0);
		SpriteMove    (i, 40+i*8, 20);
		SpriteSetPalNo(i, 0);
	}

	// タイマー設定
	REG_TM0CNT_L = 0;
	REG_TM1CNT_L = 0;
	REG_TM0CNT_H = TIMER_FREQ_PER_256 | TIMER_START;
	REG_TM1CNT_H = TIMER_CASCADE      | TIMER_START;

	for(;;)
	{
		WaitForVsync();

		SpriteShowNumber(0, REG_TM0CNT_L);
		SpriteShowNumber(5, REG_TM1CNT_L);
	}
}

スプライトを使って数字を表示しています。左側がタイマー0、右側がタイマー1です。

動作画面

2.png

履歴


トップ   一覧 検索 最終更新   ヘルプ   最終更新のRSS