DMA

DMA(Direct Memory Access)はCPUを介さず、高速にメモリ間のデータ転送を行うハードウェア機能です。GBAのDMAでは0~3の4つのチャンネルがあり、それぞれ特徴が異なります。違いはほとんどありませんけれど、詳しくはGBATEKを参照してください。

I/Oアドレス

アドレス、設定についてを見ていきましょう。

#define REG_DMA0SAD	*(vu32*)(REG_BASE + 0x0b0)
#define REG_DMA0DAD	*(vu32*)(REG_BASE + 0x0b4)
#define REG_DMA0CNT	*(vu32*)(REG_BASE + 0x0b8)

#define REG_DMA1SAD	*(vu32*)(REG_BASE + 0x0bc)
#define REG_DMA1DAD	*(vu32*)(REG_BASE + 0x0c0)
#define REG_DMA1CNT	*(vu32*)(REG_BASE + 0x0c4)

#define REG_DMA2SAD	*(vu32*)(REG_BASE + 0x0c8)
#define REG_DMA2DAD	*(vu32*)(REG_BASE + 0x0cc)
#define REG_DMA2CNT	*(vu32*)(REG_BASE + 0x0d0)

#define REG_DMA3SAD	*(vu32*)(REG_BASE + 0x0d4)
#define REG_DMA3DAD	*(vu32*)(REG_BASE + 0x0d8)
#define REG_DMA3CNT	*(vu32*)(REG_BASE + 0x0dc)
REG_DMxSADSource Addressの略で、転送元のアドレスを指定します。
REG_DMxDADDestination Addressの略で、転送先のアドレスを指定します。
REG_DMxCNT(下位)転送するサイズ(16 or 32bit)を指定します。
REG_DMxCNT(上位)DMA転送の設定をします。

REG_DMxSAD、REG_DMxDAD

アライメントの関係で転送元、転送先のアドレスの最後の桁に注意してください。

でないと失敗します。エミュレータで成功する場合もありますが実機でハマります。

#define ALIGN(m)	__attribute__((aligned (m)))

u16 dataBuf[64] ALIGN(4);
u16 buf[SCREEN_CX][SCREEN_CY] ALIGN(4);

DMA転送に関わるすべての変数については、ALIGNマクロをつけておく事をおすすめします。

REG_DMxCNT_L

転送したいバイト数を登録します。ただし転送サイズが32ビットの場合は4で、16ビットの場合は2であらかじめ割っておく必要があります。

REG_DMxCNT_H

#define DMA_DST_INC		(0<<21)
#define DMA_DST_DEC		(1<<21)
#define DMA_DST_FIXED		(2<<21) // 固定
#define DMA_DST_RELOAD		(3<<21)

#define DMA_SRC_INC		(0<<23)
#define DMA_SRC_DEC		(1<<23)
#define DMA_SRC_FIXED		(2<<23) // 固定

転送アドレスをどう変化させるかの設定です。FIXEDはアドレスを固定し、同じアドレスのデータを転送するようになります。DMA_DST_RELOADは転送ごとに増加し、すべての転送が終わった時に最初のアドレスに戻します。

#define DMA_REPEAT		(1<<25)

一度のDMA転送が終了したあとに次回のDMA転送を繰り返し行うか行わないかの設定です。サウンド再生用のFIFOへの転送やフレームごとの転送を行う場合はONにするようです。

#define DMA_IRQ			(1<<30)

DMAの転送終了時に割り込みを発生させるかの設定です。

#define DMA_ENABLE		(1<<31)

DMAが有効になります。

#define DMA_IMMEDIATE		(0<<28)
#define DMA_VBLANK		(1<<28)
#define DMA_HBLANK		(2<<28)
#define DMA_SPECIAL		(3<<28)

DMA_ENABLE設定後の、転送開始のタイミングです。

Mode3で画像をDMA転送例

#include "lib/gba.h"
#include "res.h"
 
//---------------------------------------------------------------------------
void WaitForVsync(void)
{
	while(*(vu16*)0x4000006 >= 160) {};
	while(*(vu16*)0x4000006 <  160) {};
}
//---------------------------------------------------------------------------
int main(void)
{
	// モード設定
	SetMode(MODE_3 | BG2_ENABLE);

	// 画像の読み込み
	REG_DMA3SAD = (u32)&imageBitmap;
	REG_DMA3DAD = (u32)VRAM;
	REG_DMA3CNT = (u32)(240*160) | (DMA_SRC_INC | DMA_DST_INC | DMA16 | DMA_ENABLE);

	for(;;)
	{
	    WaitForVsync();
	}
}

動作画面

1.png

履歴


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