PIC32MZシリーズ1①DMAモジュールの使い方

DMAモジュールの使い方

概要

以下の記事に記載しましたが、従来Microchipの32bitマイコンはMIPSコアを採用したPIC32Mシリーズ(MK,MM,MX,MZ)が主流でした。最近ではCortex-Mシリーズを搭載したPIC32Cシリーズが続々と新登場しています。これは他のマイコンメーカの採用実績が裏付けるように、世界的な流れとして当然であると思われ、今後PIC32Mシリーズの新しいMCUは発売されないかも知れません。

PIC32Cシリーズに関して – ぴくおの電子工作的な何かWP (electricpico.com)

そんな中はありますが、今回はPIC32MZのDMA転送について紹介します。

環境

今回はMikroElektronikaから発売されている「MINI-32 for PIC32ボード」(PIC32MZ1024EFH064-I/MR搭載) MINI-32 for PIC32MZ – compact PIC32MZ development board | MikroElektronika を使用します。

(図1)MINI-32 for PIC32ボード外観

MPLAB X IDEは v6.15、コンパイラはXC32 V4.35を使用します。

ハードウェア構成と制御ブロック

DMAモジュールは以下の通りとなっており、複数のDMAチャンネルの転送要求をアービターが調整しROM、RAM、ペリフェラルレジスタ間のデータをCPUの介在内なしに実行します。

(図2)DMAモジュールブロック図 (DS60001320D-page 173 より)

レジスタとコンフィグレーション

DMAモジュールのレジスタは以下のとおりです。

レジスタ名(x=1~8)機能
DMACONDMA制御レジスタ
DMASTATDMAステータスレジスタ
DMAADDRDMAアドレスレジスタ
DCRCCONDMA CRC制御レジスタ
DCRCDATADMA CRCデータレジスタ
DCRCXORDMA CRCXORレジスタ
DCHxCONDMAチャンネルx制御レジスタ
DCHxECONDMAチャンネルxイベント制御レジスタ
DCHxINTDMAチャンネルx割り込み制御レジスタ
DCHxSSADMAチャンネルx転送元スタートアドレスレジスタ
DCHxDSADMAチャンネルx転送先スタートアドレスレジスタ
DCHxSSIZDMAチャンネルx転送元サイズレジスタ
DCHxDSIZDMAチャンネルx転送先サイズレジスタ
DCHxSPTRDMAチャンネルx転送元ポインタレジスタ
DCHxDPTRDMAチャンネルx転送先ポインタレジスタ
DCHxCSIZDMAチャンネルxセルサイズレジスタ
DCHxDATDMAチャンネルxパターンデータレジスタ

ソースコード(変数間コピー)

(図3)のように、1回の転送トリガで複数バイトの変数のコピーを行うためには、DCHxSSIZ、DCHxDSIZ、DCHxCSIZを同一の値に設定します。

(図3)基本転送モード / 複数バイトコピー
項目
転送モード基本転送モード
転送元アドレス(DCHxSSA)virt_to_phys(&srcData1[0])
転送元サイズ(DCHxSSIZ)32
転送先アドレス(DCHxDSA)virt_to_phys(&dstData[0])
転送先サイズ(DCHxDSIZ)32
セル転送サイズ(DCHxCSIZ)32
char __attribute__((coherent)) srcData1[512];
char __attribute__((coherent)) dstData[512];

#define ConvertToPhysicalAddress(a) ((uint32_t)KVA_TO_PA(a))
#define ConvertToVirtualAddress(a)  PA_TO_KVA1(a)

int main ( void )
{
   int i,cycle ;

    /* Initialize all modules */
    __builtin_disable_interrupts();

    /* Configure Prefetch, Wait States and ECC */
    PRECONbits.PREFEN = 3;
    PRECONbits.PFMWS = 3;
    CFGCONbits.ECCCON = 3;

    __builtin_enable_interrupts();
    
    for ( i=0;i<32 ;i++)
    {
	srcData1[i] = i & 0xff;
	dstData[i] = 0x0a;	
    }
    
    IEC1CLR=0x00010000;
    IFS1CLR=0x00010000;

    DMACONbits.ON = 1u; //DMA有効化
    
    DCH0CONbits.CHPIGN = 0u; //チャンネル レジスタ データビット
    DCH0CONbits.CHBUSY = 0u; //チャンネル ビジービット
    DCH0CONbits.CHPIGNEN = 0u;//パターンマッチ バイト無視イネーブルビット
    DCH0CONbits.CHAED = 0u;//パターン長ビット
    DCH0CONbits.CHCHNS = 0u;//チェーン チャンネル選択ビット
    DCH0CONbits.CHEN = 0u;//チャンネル イネーブルビット 
    DCH0CONbits.CHAED = 0u;//無効中チャンネル イベント検出ビット
    DCH0CONbits.CHCHN = 0u;//チャンネル チェーン イネーブルビット
    DCH0CONbits.CHAEN = 0u;//チャンネル自動有効化ビット
    DCH0CONbits.CHEDET = 0u;//チャンネル イベント検出ビット
    DCH0CONbits.CHPRI = 3u; //チャンネル優先度ビット

    DCH0ECONbits.CHAIRQ = 0x00u;//チャンネル転送中止 IRQ ビット
    DCH0ECONbits.CHSIRQ = 0x00u;//チャンネル転送開始 IRQ ビット
    DCH0ECONbits.CFORCE = 0u;//DMA 転送開始ビット
    DCH0ECONbits.CABORT = 0u;//DMA 転送中止ビット
    DCH0ECONbits.PATEN = 0u;//チャンネル パターンマッチ転送中止イネーブルビット
    DCH0ECONbits.SIRQEN = 0u;//チャンネル転送開始 IRQ イネーブルビット
    DCH0ECONbits.AIRQEN = 0u;//チャンネル中止 IRQ イネーブルビット
		
    DCH0SSA = virt_to_phys(&srcData1[0]);
    DCH0DSA = virt_to_phys(&dstData[0]);
	
    DCH0SSIZ = 32; // source size 200 bytes
    DCH0DSIZ = 32; // destination size 200 bytes
    DCH0CSIZ = 32; // 200 bytes transferred per event

    DCH0INTbits.CHSDIE = 0u;//チャンネルソース完了割り込みイネーブルビット
    DCH0INTbits.CHSHIE = 0u;//チャンネルソース 1/2 エンプティ割り込みイネーブルビット
    DCH0INTbits.CHDDIE = 0u;//チャンネル デスティネーション完了割り込みイネーブルビット
    DCH0INTbits.CHDHIE = 0u;//チャンネル デスティネーション 1/2 フル割り込みイネーブルビット
    DCH0INTbits.CHBCIE = 0u;//チャンネル ブロック転送完了割り込みイネーブルビット
    DCH0INTbits.CHCCIE = 0u;//チャンネルセル転送完了割り込みイネーブルビット	
    DCH0INTbits.CHTAIE = 0u;//チャンネル転送中止割り込みイネーブルビット
    DCH0INTbits.CHERIE = 0u;//チャンネル アドレスエラー割り込みイネーブルビット
    DCH0INTbits.CHSDIF = 0u;//チャンネルソース完了割り込みフラグビット
    DCH0INTbits.CHSHIF = 0u;//チャンネルソース 1/2 エンプティ割り込みフラグビッ
    DCH0INTbits.CHDDIF = 0u;//チャンネル デスティネーション完了割り込みフラグビット
    DCH0INTbits.CHDHIF = 0u;//チャンネル デスティネーション 1/2 フル割り込みフラグビット
    DCH0INTbits.CHBCIF = 0u;//チャンネル ブロック転送完了割り込みフラグビット
    DCH0INTbits.CHCCIF = 0u;//チャンネル セル転送完了割り込みフラグビット
    DCH0INTbits.CHTAIF = 0u;//チャンネル転送中止割り込みフラグビット
    DCH0INTbits.CHERIF = 0u;// チャンネル アドレスエラー割り込みフラグビット

    DCH0CONbits.CHEN = 1u;//チャンネル イネーブルビット
    DCH0ECONbits.CFORCE = 1u;//DMA 転送開始ビット
    
    cycle = 0;
    while(DCH0INTbits.CHCCIF == 0)
    {
        cycle ++;
    }
    
    while(1)
    {
        ;
    }
}

ソースコード(変数→ペリフェラル)

DMA転送の別の例として、OCモジュールのPWMを用いた疑似D/A変換を行います。今回は図4のように、TIMER2とOC1を組み合わせ、OCの出力をローパスフィルタにかける事でPWM波形をアナログ電圧にします。
TIMER2のコンペアマッチで自身の周期をリセットし、DMAに転送トリガを与えます。この転送トリガにより、4バイトのソースデータの値がOC1RS(Duty)レジスタにコピーされます。次の転送トリガでは、次の4バイトのソースデータが転送されます。256バイトの転送が完了すると、先頭のデータから再度転送が行われます。

uint32_t __attribute__((coherent)) srcData1[64] =
{
100	,
109	,
119	,
128	,
137	,
146	,
155	,
162	,
170	,
176	,
182	,
187	,
191	,
194	,
197	,
198	,
199	,
198	,
197	,
194	,
191	,
187	,
182	,
176	,
170	,
162	,
155	,
146	,
137	,
128	,
119	,
109	,
100	,
90	,
80	,
71	,
62	,
53	,
44	,
37	,
29	,
23	,
17	,
12	,
8	,
5	,
2	,
1	,
1	,
1	,
2	,
5	,
8	,
12	,
17	,
23	,
29	,
37	,
44	,
53	,
62	,
71	,
80	,
90	

};

int main ( void )
{
    /*-------------------------------------------------------*/
    /* 割り込み禁止 */
    /*-------------------------------------------------------*/
        __builtin_disable_interrupts();

    /*-------------------------------------------------------*/
    /* ロック */
    /*-------------------------------------------------------*/
        SYSKEY = 0x00000000;
        SYSKEY = 0xAA996655;
        SYSKEY = 0x556699AA;
    /*-------------------------------------------------------*/    
    /* PMD / PPS 設定 */
    /*-------------------------------------------------------*/
        CFGCONbits.PMDLOCK = 0;

        PMD1 = 0x1001;
        PMD2 = 0x3;
        PMD3 = 0x1ff01ff;
        PMD4 = 0x1ff;
        PMD5 = 0xfeffffff;
        PMD6 = 0xfffff0ff;
        PMD7 = 0xffffffef;

        PMD3bits.OC1MD = 0;
        PMD4bits.T2MD = 0;

        CFGCONbits.PMDLOCK = 1;

        CFGCONbits.IOLOCK = 0;

        CNPUG = 0xFFFF;
        /* PPS Output Remapping */
        RPD0R =12; //OC1
        /* Lock back the system after PPS configuration */
        CFGCONbits.IOLOCK = 1;
    /*-------------------------------------------------------*/
    /* アンロック */
    /*-------------------------------------------------------*/
        SYSKEY = 0x33333333;
    
    /*-------------------------------------------------------*/
    /* Configure Prefetch, Wait States and ECC */
    /*-------------------------------------------------------*/
        PRECONbits.PREFEN = 3;
        PRECONbits.PFMWS = 3;
        CFGCONbits.ECCCON = 3;

    /*-------------------------------------------------------*/
    /* ポート設定 */
    /*-------------------------------------------------------*/
        ANSELBCLR = 0xFFFF; /* Digital Mode Enable */
        TRISEbits.TRISE0 = 0;
        TRISEbits.TRISE1 = 0;
        TRISFbits.TRISF3 = 0;
        LATFbits.LATF3 = 1;
        TRISDbits.TRISD0 = 0;
        LATDbits.LATD0 = 0;

    /*-------------------------------------------------------*/
  /* 全割り込み有効化 */
    /*-------------------------------------------------------*/
        __builtin_enable_interrupts();
    

        IEC1CLR=0x00010000;
        IFS1CLR=0x00010000;

    /*-------------------------------------------------------*/
  /* TIMER2設定 */
    /*-------------------------------------------------------*/
        PR2 = 200;
        T2CON = 0x00000000;     //T2ON

    /*-------------------------------------------------------*/
  /* OC設定 */
    /*-------------------------------------------------------*/
        OC1RS = 100;
        OC1R = 100;
        OC1CON = 0x0006;    //OC1 ON,PWMMode

        T2CONSET = 0x8000;
        OC1CONSET = 0x8000;
    /*-------------------------------------------------------*/
  /* DMA設定 */
    /*-------------------------------------------------------*/
        DMACONbits.ON = 1u; //DMA有効化

        DCH0CONbits.CHPIGN = 0u; //チャンネル レジスタ データビット
        DCH0CONbits.CHBUSY = 0u; //チャンネル ビジービット
        DCH0CONbits.CHPIGNEN = 0u;//パターンマッチ バイト無視イネーブルビット
        DCH0CONbits.CHAED = 0u;//パターン長ビット
        DCH0CONbits.CHCHNS = 0u;//チェーン チャンネル選択ビット
        DCH0CONbits.CHEN = 0u;//チャンネル イネーブルビット 
        DCH0CONbits.CHAED = 0u;//無効中チャンネル イベント検出ビット
        DCH0CONbits.CHCHN = 0u;//チャンネル チェーン イネーブルビット
        DCH0CONbits.CHAEN = 1u;//チャンネル自動有効化ビット
        DCH0CONbits.CHEDET = 0u;//チャンネル イベント検出ビット
        DCH0CONbits.CHPRI = 3u; //チャンネル優先度ビット

        DCH0ECONbits.CHAIRQ = 0x00u;//チャンネル転送中止 IRQ ビット
        DCH0ECONbits.CHSIRQ = 0x09u;//チャンネル転送開始 IRQ ビット
        DCH0ECONbits.CFORCE = 0u;//DMA 転送開始ビット
        DCH0ECONbits.CABORT = 0u;//DMA 転送中止ビット
        DCH0ECONbits.PATEN = 0u;//チャンネル パターンマッチ転送中止イネーブルビット
        DCH0ECONbits.SIRQEN = 1u;//チャンネル転送開始 IRQ イネーブルビット
        DCH0ECONbits.AIRQEN = 0u;//チャンネル中止 IRQ イネーブルビット

        DCH0SSA = virt_to_phys(&srcData1[0]);
        DCH0DSA = virt_to_phys((const void*)&OC1RS); //ok 0x1F840010
        DCH0SSIZ = 256; 
        DCH0DSIZ = 4; 
        DCH0CSIZ = 4; 

        DCH0INTbits.CHSDIE = 0u;//チャンネルソース完了割り込みイネーブルビット
        DCH0INTbits.CHSHIE = 0u;//チャンネルソース 1/2 エンプティ割り込みイネーブルビット
        DCH0INTbits.CHDDIE = 0u;//チャンネル デスティネーション完了割り込みイネーブルビット
        DCH0INTbits.CHDHIE = 0u;//チャンネル デスティネーション 1/2 フル割り込みイネーブルビット
        DCH0INTbits.CHBCIE = 0u;//チャンネル ブロック転送完了割り込みイネーブルビット
        DCH0INTbits.CHCCIE = 0u;//チャンネルセル転送完了割り込みイネーブルビット	
        DCH0INTbits.CHTAIE = 0u;//チャンネル転送中止割り込みイネーブルビット
        DCH0INTbits.CHERIE = 0u;//チャンネル アドレスエラー割り込みイネーブルビット 
        DCH0INTbits.CHSDIF = 0u;//チャンネルソース完了割り込みフラグビット
        DCH0INTbits.CHSHIF = 0u;//チャンネルソース 1/2 エンプティ割り込みフラグビッ
        DCH0INTbits.CHDDIF = 0u;//チャンネル デスティネーション完了割り込みフラグビット
        DCH0INTbits.CHDHIF = 0u;//チャンネル デスティネーション 1/2 フル割り込みフラグビット
        DCH0INTbits.CHBCIF = 0u;//チャンネル ブロック転送完了割り込みフラグビット
        DCH0INTbits.CHCCIF = 0u;//チャンネル セル転送完了割り込みフラグビット
        DCH0INTbits.CHTAIF = 0u;//チャンネル転送中止割り込みフラグビット
        DCH0INTbits.CHERIF = 0u;// チャンネル アドレスエラー割り込みフラグビット

        DCH0CONbits.CHEN = 1u;//チャンネル イネーブルビット 
        DCH0ECONbits.CFORCE = 1u;//DMA 転送開始ビット
    
    while(1)
    {
    }
    

    return ( EXIT_FAILURE );
}

参考文献

コメント

タイトルとURLをコピーしました