- 追加された行はこの色です。
- 削除された行はこの色です。
#author("2023-04-24T19:15:59+09:00","","")
* Tutorial.9 タイマー [#y7e25f12]
GBAのタイマーは4つ用意されており、カウントアップには~
CPUのクロック数が基準になっています。~
1秒1カウントしたい、といった方法には少し頭を捻ることが必要でしょう。~
** タイマーとCPUの関係 [#o37ad083]
GBAのCPUクロック数は16.78Mhzで、Hzの単位にすると16,780,000になります。~
この数を1秒で割ると1サイクル時間がわかるという寸法です。~
タイマーは1, 64, 256, 1024クロックごとに~
インクリメント(カウントアップ)する設定が可能です。~
この関係を表にすると以下のようになります。~
| CPU(クロック) | 1サイクル時間 | 16bit カウント時間 |
| 1 | 60ns | 3.9ms |
| 64 | 3.8us | 250ms |
| 256 | 15.3us | 1s |
| 1024 | 61us | 4s |
** タイマーのアドレス [#c804519b]
#define REG_TM0CNT_L *(vu16*)(REG_BASE + 0x100)
#define REG_TM0CNT_H *(vu16*)(REG_BASE + 0x102)
#define REG_TM1CNT_L *(vu16*)(REG_BASE + 0x104)
#define REG_TM1CNT_H *(vu16*)(REG_BASE + 0x106)
#define REG_TM2CNT_L *(vu16*)(REG_BASE + 0x108)
#define REG_TM2CNT_H *(vu16*)(REG_BASE + 0x10a)
#define REG_TM3CNT_L *(vu16*)(REG_BASE + 0x10c)
#define REG_TM3CNT_H *(vu16*)(REG_BASE + 0x10e)
''CNT_Lがタイマーの値、CNT_Hが設定値''と分かれています。大きさは16bit単位です。~
*** TMxCNT_L [#of668bfe]
タイマーの値はu16(16bit)なので65535まで増加すると次は0になります。~
このことを''オーバーフロー''といいます。~
オーバーフロー時に割り込みを発生させることや''カスケード機能''(後述)を利用することができます。~
また、0以外の初期値を入れておくとオーバーフロー時、その初期値からスタートします。~
*** TMxCNT_H [#i44a23a3]
//タイマーが進む周期 何クロックにインクリメントするか
#define TIMER_FREQ_PER_1 0
#define TIMER_FREQ_PER_64 1
#define TIMER_FREQ_PER_256 2
#define TIMER_FREQ_PER_1024 3
//カスケード
#define TIMER_CASCADE (1<<2)
カスケード機能は下位のタイマー(タイマー1なら0、タイマー2なら1)が~
オーバーフローしたときに、上位のタイマーの値がインクリメントされるという機能です。~
カスケード機能を使うと上位のタイマー自身は周期によって~
インクリメントされないようになっています。~
ちなみにタイマー0は下位のタイマーがないのでカスケード機能は使えません。~
#define TIMER_IRQ BIT(6)
タイマーがオーバーフローしたときに割り込みを発生させるかの設定です。~
#define TIMER_START BIT(7)
TM_ENABLEをセットした瞬間にタイマーが開始されます。~
#ref(clip_2.png,nolink)
** タイマーの動作例 [#qaa9c659]
#include "lib/gba.h"
#include "res.h"
//---------------------------------------------------------------------------
void WaitForVsync(void)
{
while(*(vu16*)0x4000006 >= 160) {};
while(*(vu16*)0x4000006 < 160) {};
}
//---------------------------------------------------------------------------
void SpriteSetPalNo(u32 num, u32 palNo)
{
OBJATTR* sp = (OBJATTR*)OAM + num;
sp->attr2 &= 0x0fff;
sp->attr2 |= (palNo << 12);
}
//---------------------------------------------------------------------------
void SpriteMove(u32 num, s32 x, s32 y)
{
OBJATTR* sp = (OBJATTR*)OAM + num;
sp->attr1 &= 0xfe00;
sp->attr0 &= 0xff00;
sp->attr1 |= (x & 0x01ff);
sp->attr0 |= (y & 0x00ff);
}
//---------------------------------------------------------------------------
void SpriteSetSize(u32 num, u32 size, u32 form, u32 col)
{
OBJATTR* sp = (OBJATTR*)OAM + num;
sp->attr0 &= 0x1fff;
sp->attr1 &= 0x3fff;
sp->attr0 |= col | form | (160);
sp->attr1 |= size | (240);
}
//---------------------------------------------------------------------------
void SpriteSetChr(u32 num, u32 ch)
{
OBJATTR* sp = (OBJATTR*)OAM + num;
sp->attr2 &= 0xfc00;
sp->attr2 |= ch;
}
//---------------------------------------------------------------------------
void SpriteInit(void)
{
u32 i;
for(i=0; i<128; i++)
{
SpriteMove(i, 240, 160);
}
}
//---------------------------------------------------------------------------
void SpriteShowNumber(u32 base, s32 num)
{
s32 i;
for(i=5-1; i>=0; i--)
{
SpriteSetChr(base + i, num % 10);
num /= 10;
}
}
//---------------------------------------------------------------------------
void SpriteSetDatChr(u16* dat, u32 size)
{
u16* p = OBJ_BASE_ADR;
u32 i;
for(i=0; i<size/2; i++)
{
p[i] = dat[i];
}
}
//---------------------------------------------------------------------------
void SpriteSetDatPal(u16* pal)
{
u16* p = OBJ_COLORS;
u32 i;
for(i=0; i<16; i++)
{
p[i] = pal[i];
}
}
//---------------------------------------------------------------------------
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);
}
}
*** 動作画面 [#gc843ec0]
#ref(clip_1.png,nolink)
** 履歴 [#za126cf7]
- 2014/12/25