Tutorial.12 DMA

DMA(Direct Memory Access)はCPUを介さず、
高速にメモリ間のデータ転送を行うハードウェア機能です。

GBAのDMAでは0〜3の4つのチャンネルがあり、それぞれ特徴が異なります。
違いはほとんどありませんけれど、詳しくはGBATEKを参照してください。

  • DMA0
    最も優先度が高く、転送する時間が厳密である必要があるときに使います。
    内部メモリから内部メモリへの転送のみ可能です。
  • DMA1
    DMA0の次に優先度が高く、サウンド再生時のFIFOにデータを
    転送する時に使われることが多い。
    内部メモリ・外部メモリから内部メモリへの転送が可能です。
  • DMA2
    DMA1とほぼ同じ。
  • DMA3
    最も優先度が低いDMA。
    転送先・転送元ともに内部メモリ・外部メモリのいずれでも指定できます。
    最も汎用的に使えるのが特徴です。

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

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

  • 16bit転送の場合、0,2,4,6,8,a,c,e
  • 32bit転送の場合、0,4,8,c

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

#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();
	}
}

動作画面

clip_1.png

履歴

  • 2014/12/27
  • 2007/09/05

添付ファイル: fileclip_1.png 221件 [詳細]

Last-modified: 2014-12-29 (月) 23:55:27 (2838d)