# MI_DmaCopy*

## 構文

  `#include <nitro/mi.h>`
  `void MI_DmaCopy32( u32 dmaNo,
  const void* src,
  void* dest,
  u32 size );`
  `void MI_DmaCopy32_SetUp( u32 dmaNo,
  const void* src,
  void* dest,
  u32 size );`
  `void MI_DmaCopy16( u32 dmaNo,
  const void* src,
  void* dest,
  u32 size );`
  `void MI_DmaCopy16_SetUp( u32 dmaNo,
  const void* src,
  void* dest,
  u32 size );`
  `void MI_DmaCopy32Async( u32 dmaNo,
  const void* src,
  void* dest,
  u32 size,
  MIDmaCallback callback,
  void* arg );`
  `void MI_DmaCopy32Async_SetUp( u32 dmaNo,
  const void* src,
  void* dest,
  u32 size,
  MIDmaCallback callback,
  void* arg );`
  `void MI_DmaCopy16Async( u32 dmaNo,
  const void* src,
  void* dest,
  u32 size,
  MIDmaCallback callback,
  void* arg );`
  `void MI_DmaCopy16Async_SetUp( u32 dmaNo,
  const void* src,
  void* dest,
  u32 size,
  MIDmaCallback callback,
  void* arg );`

## 引数

dmaNo | 使用DMAチャンネル
src | 転送元アドレス
dest | 転送先アドレス
size | 転送サイズ
callback | DMA終了時のコールバック
arg | DMA終了時のコールバック引数

## 返り値

なし。

## 説明

DMA を用いてコピーを行います。

`*_SetUp()` は実際にはDMAを行なわず、その設定のみを行います。実際のDMA開始は `MI_DmaRestart()` を呼んで下さい。

`MI_DmaCopy16*()` は 16ビット単位でコピーを行います。転送元アドレス、転送先アドレスは2バイトアラインメントする必要があります。

`MI_DmaCopy32*()` は 32ビット単位でコピーを行います。転送元アドレス、転送先アドレスは4バイトアラインメントする必要があります。

`MI_DmaCopy16()`, `MI_DmaCopy32()` は DMA の終了を関数内で待ちます。
`MI_DmaCopy16Async*()`, `MI_DmaCopy32Async*()` は、DMA終了時にコールバック callback を呼びます。コールバックは MIDmaCallback 型 ( void* 引数1つを取る void 型関数 ) です。callback は システムのDMA割り込みハンドラ内から呼び出されますので、割り込み禁止状態で呼び出されます。

Async 型の API の機能を引き出すにはその使用法を十分に理解する必要があります。

例として、次のような `Call_BackGroundJob_with_DMA()`というTCM内に配置された関数がある場合を考えます。

このときは以下のような処理が行なわれます。

- 関数内でDMAを使いデータ転送を始めます。
- DMA が終了すると `callback()` の中で、`isDmaFinished` に TRUE を入れます。
- `isDmaFinished` を終了フラグとしてポーリングし、DMAが終了するまでの間 `BackGroundJob()` を呼びつづけることが可能です。

但し、この処理が意図通りに処理されるには以下のようなことに注意しなくてはなりません。

- `isDmaFinished` が TCM 内に取られていないと `while(!isDmaFinished)` のチェックでストールします。
- `BackGroundJob()` がARMバスにアクセスするとストールします。
- 多くの場合、スタックも TCM 内に確保する必要があります。(SDK デフォルト設定ではスタックは DTCM 内に確保されています）
- もしこの関数がメインメモリ上に配置されていた場合、DMAを開始したときにストールするので `BackGroundJob()` を呼びつづけることは出来ません。

>     //--- sample code ( This code must be in ITCM )
>     void Call_BackGroundJob_with_DMA(void)
>     {
>     　　vu32 isDmaFinished = FALSE;
>     　　　　：
>     　　MI_DmaCopy32Async( dmaNo, srcArea, destArea, dataSize, callback, (void*)&isDmaFinished );
>     　　while( !isDmaFinished ){ BackGroundJob(); }
>     　　　　：
>     }

>     void callback( void* arg )
>     {
>     　 　*(vu32*)arg = TRUE;
>     }

###
DMAコントローラの不具合

旧DMAC にはハードウェア上の不具合があり、多重DMAで DMA0 のソースアドレスに 0xmmnnnnnn (mm=0x04, 0x08〜0xff で、nnnnnn は任意) を指定すると条件により不正リードアクセスが発生します。転送終了時のソースアドレスもこの制限を受けます。 そのためソースアドレスや転送終了時のソースアドレスがこのアドレス範囲に入っている場合は、ライブラリ内部で `OS_Panic()` で停止するようになっています。

ただし TWL では `SCFG_SetDmaFixed()` でこの旧DMA 回路の不具合修正を行うか行わないかの選択が可能になっており、修正を行っている場合はアドレスのチェックを行いません。

## 内部動作

IOレジスタのDMAnソースレジスタ(0x40000B0 + 12n)、DMAnデスティネーションレジスタ(0x40000B4 + 12n)、DMAnコントロールレジスタ(0x40000B8 + 12n)を使用します。( n は 使用するDMAチャンネルです。)

## 参照

`MI_DmaFill*, MI_DmaClear*, MI_DmaSend*, MI_CpuCopy*, MI_DmaRestart
`

## 履歴

2009/11/20 DMAコントローラの不具合について追記
2007/10/31 `_SetUp()` 追加
2005/03/08 用語統一 [割込み] → [割り込み]
2004/12/22 callback の呼び出しについての記述を追加
2003/12/01 初版