DMAモジュール
メモリ間転送
(→プロジェクトファイル(Harmony Ver.2.04版 ) ダウンロード)
DMAモジュールを使うことにより、CPUの介在なしてメモリ間のデータ転送が可能です。
以下に DMA転送によりメモリ間の転送を行い、結果をキャラクタ液晶に表示する例を紹介します。
本サンプルプログラムは マイクロチップのHarmonyのdma_mem2memを参考にして作成しています。 dma_mem2memは、下記のパスにあります。
"C:\microchip\harmony\v2_04\apps\examples\system\dma\dma_mem2mem"
<仕様>
・ メモリからメモリにDMA転送によりデータを転送する。
・ キャラクタ液晶に以下の要領で結果を表示する。
① 液晶上段 …… DMA転送前のデータ(メモリの内容)
尚、データの前に src= を表示すること
② 液晶下段 …… DMA転送後のデータ(メモリの内容)
尚、データの前に dst= を表示すること
DMA転送用データ: Hellow
・ 転送が完了したら LED(RG15)を点灯のこと
また、転送が失敗したらLED(RD4)を点灯のこと
・キャラクタ液晶には、PIC起動時に以下を表示のこと
PIC32MZ
Start Test1
<外観> PIC32MZ評価ボード(→購入方法)を使った実験品の外観です。
<動作結果> (→ 動画:1080pのHD動画を見ることができます。)
DMA転送後の表示 |
![]() |
<解説> 記載してある内容は要点だけです。 詳細はプロジェクトファイルを精読願います。
(以下は、Harmony v2.04 をもとに作成しています。最新のバージョンとは異なることがあるかもしれませんので注意してください。)
■ MHC設定
■ Options
項目 | ①Config設定 Device & Project Configuration > PIC32MZ2048 Device Configuration |
②DMA設定 Harmony Framework Configuration > System Services > DMA |
MHC | ![]() |
![]() |
備考 |
■ Pin Settings
項目 | ③ポート設定1 | ④ポート設定2 |
MHC | ![]() |
![]() |
備考 | デフォルトからの変更要領 RG15/Function: GPIO_OUT (LED出力ポート設定) |
デフォルトからの変更要領 RD4/Function: GPIO_OUT (LED出力ポート設定) |
■ キャラクタ液晶表示のライブラリ 1lcd_lib_XC32.h と 1lcd_lib_XC32.cを main.cと同じフォルダにコピーして、プロジェクトに追加します。
(詳細→ キャラクタ液晶表示方法 参照)
■ app.cに、青字部分を追加します。
①インクルードファイルを追加します。stdio.hがないと、sprintf( )がコンパイラのバージョンによってコンパイルで警告となることが
あります。
#include "stdio.h"
②DMAチャンネル0のハンドルを宣言します。
DMA転送元のメモリデータを定義してメモリを確保します。DMA転送先のメモリデータのメモリも宣言して確保します。 __attribute__は
アトリビュート修飾子と呼ばれるコンパイラ命令で、変数の配置場所を指定します。__attribute__((coherent)) は バッファにキャッシュ
を使ってはいけません(directs the linker to allocate this buffer in un-cached memory).と云う命令です。
マイクロチップの
dma_mem2memにはPIC32MXが対象デバイスである為__attribute__((coherent)) は使用されていません。 本サンプルプログラムは
PIC32MZ用なので__attribute__((coherent))は必須となります。 PIC32MXの場合はなくても動くようです。(参考
→ URL)
SYS_DMA_CHANNEL_HANDLE channelHandle0;
static char __attribute__ ((aligned (32)))__attribute__((coherent)) source[16]
= {"Hellow World"};
static char __attribute__ ((aligned (32)))__attribute__((coherent)) destination[16]
= {};
③遅延関数やキャラクタ液晶表示関連のバッファなどを定義します。
int delay_Clock = 200000000; //システムクロック:200MHz
char Buf[32];
void delay_us(volatile unsigned int usec) //1μsec遅延
{
volatile int count;
……
……
④DmaInit( )で DMA制御関連のレジスタを設定します。
SYS_DMA_ChannelAllocate(DMA_CHANNEL_0)でチャンネル0のハンドルを取得します。
SYS_DMA_ChannelSetup()でチャンネルのモードを設定します。ここではベーシックモード かつトリガなしのモードを設定します。
SYS_DMA_ChannelTransferAdd()でDMA転送の 転送元(ポインタ)、転送データのサイズ(バイト)、転送先(ポインタ)、
転送先のサイズ(バイト)、セルサイズ(1回の転送で送るサイズ) などを設定します。
SYS_DMA_ChannelForceStart() DMA転送開始命令です。
void DmaInit(void)
{
//Harmonyライブラリ関数による制御
channelHandle0 = SYS_DMA_ChannelAllocate(DMA_CHANNEL_0);
SYS_DMA_ChannelSetup(channelHandle0, SYS_DMA_CHANNEL_OP_MODE_BASIC
, DMA_TRIGGER_SOURCE_NONE);
SYS_DMA_ChannelTransferAdd(channelHandle0, source, sizeof(source) ,
destination, sizeof(destination), sizeof(source));
SYS_DMA_ChannelForceStart(channelHandle0);
⑤ PIC立ち上がり後、キャラクタ液晶を初期化して "PIC32MZ DMA Start Test 1"を液晶に表示したら DmaInit()でDMAモジュールを
初期化してメモリ間のDMA転送を実行します。
void APP_Initialize ( void )
{
/* Place the App state machine in its initial state. */
appData.state = APP_STATE_INIT;
/* TODO: Initialize your application's state machine and other
* parameters.
*/
lcd_init(); // LCD初期化
lcd_cmd(0b00001100); // カーソル:OFF ブリンク:OFF
lcd_clear();
lcd_cmd(0x80); //1目の先頭へ
sprintf(Buf,"PIC32MZ DMA ");//
lcd_str(Buf); //液晶表示
lcd_cmd(0xC0); //2行目の先頭へ
sprintf(Buf," Start Test 1 "); //
lcd_str(Buf); // 開始メッセージ1行目表示
delay_ms(2000);
DmaInit();
}
⑥ 転送元と転送先のデータを読み出し比較します。 転送元データと転送先のデータが一致した場合はDMA転送が
成功したと判断してRG15のLEDを点灯します。 不一致の場合は失敗と判断してRD4のLEDを点灯します。
その後 読み出したデータをキャラクタ液晶に表示します。
case APP_STATE_SERVICE_TASKS:
{
if(0 == strncmp(source, destination, sizeof(source))) //転送元/転送先データ比較
{
LATGbits.LATG15 = 1; //一致の場合
}
else LATAbits.LATA14 = 1; //不一致の場合
lcd_cmd(0x80); //1行目
sprintf(Buf,"src=%s ", source);
lcd_str(Buf);
lcd_cmd(0xC0); //2行目
sprintf(Buf,"dst=%s ", destination);
lcd_str(Buf);
break;
}
以下、app.c