ADCとDMAモジュールの使い方

AD変換モジュールの使い方

概要

以前の記事でDMAを用い任意にアナログ波形が出力可能となったので、今回はその出力した電圧を別のDMAを用いCPU負荷ゼロでAD変換を行います。

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

周辺モジュールと全体構成は以下の通り

  • SCCP2とDMA0、DAC1Hを使用しDACOUTピン(41pin)から波形出力
  • SCCP3、DMA2を用い、DACOUTピンからAD変換
(fig.1)全体ブロック図

DMA関連のレジスタは以下の8種類

ソースコード

今回は特筆する事は有りません。

コンフィグレーション設定について

コンフィグレーション設定についてはコンフィグレーション設定に記載しております。

コピーして下記のソースコードの「 //ここにコンフィグレーション設定を挿入する// 」の位置に挿入してください。

クロック設定について

クロック設定用関数 vds_Main_Init_Clock_Register(); のソースコードはクロック設定のページに記載しております。

コピーして下記のソースコードの「 //ここにクロック設定ソースをコピペする// 」の位置に挿入してください。

/*------------------------------------------------------------------------------*/
/* @file      DAC_DMA_AD.c */
/* @brief     DACOUTから任意信号を出力しDMAでAD変換をする */
/*------------------------------------------------------------------------------*/
/*------------------------------------------------------------------------------*/
/* コンフィグレーション設定*/
/*------------------------------------------------------------------------------*/
//ここにコンフィグレーション設定を挿入する//
/*------------------------------------------------------------------------------*/
/* インクルードファイル*/
/*------------------------------------------------------------------------------*/
#include <stdio.h>
#include <stdlib.h>
#include <xc.h>
/*------------------------------------------------------------------------------*/
/* 定数定義*/
/*------------------------------------------------------------------------------*/
/*------------------------------------------------------------------------------*/
/*変数定義*/
/*------------------------------------------------------------------------------*/
/*波形ROM ([嵌り事]constを付けると上手く行かない)*/
unsigned int cu2l_Data[] = 
{
2047 ,2212 ,2376 ,2538	,2696	,
2849	,2997	,3136	,3268	,3390	,
3502	,3603	,3692	,3768	,3832	,
3882	,3918	,3939	,3947	,3939	,
3918	,3882	,3832	,3768	,3692	,
3603	,3502	,3390	,3268	,3136	,
2997	,2849	,2696	,2538	,2376	,
2212	,2047	,1881	,1717	,1555	,
1397	,1244	,1097	,957	,825	,
703	,591	,490	,401	,325	,
261	,211	,175	,154	,147	,
154	,175	,211	,261	,325	,
401	,490	,591	,703	,825	,
957	,1097	,1244	,1397	,1555	,
1717	,1881
};
unsigned int u2g_ADCData[24];
/*------------------------------------------------------------------------------*/
/* クロック設定 */
/*------------------------------------------------------------------------------*/
//ここにクロック設定ソースを挿入する//
/*------------------------------------------------------------------------------*/
/* Main関数 */
/*------------------------------------------------------------------------------*/
int main(int argc, char** argv) 
{
    /*-------------------------------------------------------------------------*/
    /* クロック初期化*/
    /*-------------------------------------------------------------------------*/
        vds_Main_Init_Clock_Register();     /* クロック初期化 */
    /*-------------------------------------------------------------------------*/
    /* GPIO初期化*/
    /*-------------------------------------------------------------------------*/
        TRISEbits.TRISE0 = 0u;          /* LED1 */
        ANSELAbits.ANSELA0 = 1u;        /* RA0ピンはアナログピン*/
        ANSELBbits.ANSELB2 = 1u;        /* RB2ピンはアナログピン(DACOUT1) */
        RPOR19bits.RP71R = 0x17u;       /* RGB LED GREEN[OCM4] */
    /*-------------------------------------------------------------------------*/
    /* CMP初期化*/
    /*-------------------------------------------------------------------------*/
        DACCTRL1L = 0x0000u;
            DACCTRL1Lbits.CLKSEL = 0u;  /* DACクロック源( 0 = AFVCO/2 = 500MHz) */
            DACCTRL1Lbits.CLKDIV = 0u;  /* DACクロックディバイダ (0 = 1/1) */
            DACCTRL1Lbits.FCLKDIV = 7u; /* コンパレータフィルタクロックディバイダ*/
            DACCTRL1Lbits.DACON = 1u;   /* モジュール有効化(0 = 無効,1 = 有効) */
        DACCTRL2H = 0x001Au;            /* 移行開始からの時間 */
        DACCTRL2L = 0x0055u;            /* 遷移モードの継続時間 */
        DAC1CONH = 0x0000u;
        DAC1CONL = 0x0000u;
            DAC1CONLbits.INSEL = 0u;    /* コンパレータ入力ソース */
            DAC1CONLbits.HYSSEL = 1u;   /* コンパレータヒステリシス (1 = 15mV) */
            DAC1CONLbits.DACOEN = 1u;   /* DAC外部出力 (0 = 無効,1 = 有効) */
        DAC1DATH = 0x0000u;             /* コンパレータ比較値上限 */
        DAC1DATL = 0x0000u;             /* コンパレータ比較値下限 */
    /*-------------------------------------------------------------------------*/
    /* DAC1の有効化*/
    /*-------------------------------------------------------------------------*/
        DAC1CONLbits.DACEN = 1u;            /* DAC1の有効化 */
    /*-------------------------------------------------------------------------*/
    /* SCCP2初期化(DAC出力)*/
    /* [嵌り事]TimerモードではDAC出力タイミングの周期はPRHで設定*/
    /* [嵌り事]OCモードではDAC出力タイミングの周期はPRL,RAL!=RABで設定*/
    /*-------------------------------------------------------------------------*/
        CCP2CON1L = 0x0000u;
        CCP2CON1H = 0x0000u;
        CCP2CON2H = 0x0000u;
            CCP2CON2Hbits.AUXOUT = 1u;   /* イベント時補助出力信号選択ビット*/
        CCP2PRL = 240u;                  /* 周期(PWMモード) */
        CCP2PRH = 240u;                  /* 周期(タイマーモード) */
        CCP2RAL = 130u;                  /* 立ち上がりタイミング(PWMモード) */
        CCP2RBL = 0u;                    /* 立ち下がりタイミング(PWMモード) */
        CCP2CON1Lbits.CCPON = 1u;
    /*-------------------------------------------------------------------------*/
    /* SCCP3初期化(ADトリガ間隔)*/
    /*-------------------------------------------------------------------------*/ 
        CCP3CON1L = 0x0000u;
            CCP3CON1Lbits.CLKSEL = 0;   /* クロック源選択(0 = FP) */
            CCP3CON1Lbits.TMRPS = 0u;   /* クロックプリスケーラ選択(0 = 1:1) */
            CCP3CON1Lbits.CCSEL = 0u;   /* Capモード選択(0 = OC,Timerモード) */
            CCP3CON1Lbits.MOD = 5u;     /* 動作モード(5 = PWMモード(必須)) */
            CCP3CON1Lbits.T32 = 0u;     /* 32ビットモード(0 = 16bit / 1 = 32Bit) */
        CCP3CON1H = 0x0000u;
        // CCP2PRL > CCP2RAL > CCP2RBL ...トリガ可能
        // CCP2PRL > CCP2RBL > CCP2RAL ...トリガ可能
        // CCP2PRL > CCP2RAL = CCP2RBL ...トリガ不可
        CCP3PRL = 1000;                /* 周期 */
        CCP3RAL = 0;                    /* 立ち上がりタイミング */
        CCP3RBL = 100;                 /* 立ち下がりタイミング */
    /*-------------------------------------------------------------------------*/ 
    /* DMA1初期化 */		
    /*-------------------------------------------------------------------------*/
        DMAH = 0xC000u;                     /* DMA転送最大アドレス */
        DMAL = 0x080u;                      /* DMA転送最小アドレス */
        DMACON = 0x0000u;
            DMACONbits.DMAEN = 1u;          /* DMAモジュール有効化 */
            DMACONbits.PRSSEL = 1u;         /* ラウンドロビン方式 */
        DMACH0 = 0x0000u;
            DMACH0bits.SAMODE = 1u;         /* 送信元アドレスをインクリメントする */
            DMACH0bits.DAMODE = 0u;         /* 受信元アドレスは固定 */
            DMACH0bits.TRMODE = 1u;         /* 繰り返し、ワンショットモード */
            DMACH0bits.RELOAD = 1u;         /* 自動でリロードする */
            DMACH0bits.SIZE = 0u;           /* 16bit転送モード */
        DMAINT0 = 0x0000u;
            DMAINT0bits.CHSEL = 0x0C;       /* トリガイベント = SCCP2 */
        DMASRC0	= (unsigned int)&cu2l_Data; /* 送信元データは cu2l_Data[] */
        DMADST0	= (unsigned int)&DAC1DATH;  /* 送信先はDAC1DATHレジスタ */
        DMACNT0	= 71u;                      /* 送信カウントは72(71 + 1)回 */
    /*-------------------------------------------------------------------------*/ 
    /* DMA2初期化 */		
    /*-------------------------------------------------------------------------*/
        DMACH2 = 0x0000u;
            DMACH2bits.SAMODE = 0u;         /* 送信元アドレスは固定 */
            DMACH2bits.DAMODE = 1u;         /* 受信元アドレスをインクリメントする */
            DMACH2bits.TRMODE = 1u;         /* 繰り返し、ワンショットモード */
            DMACH2bits.RELOAD = 1u;         /* 自動でリロードする */
            DMACH2bits.SIZE = 0u;           /* 16bit転送モード */
        DMAINT2 = 0x0000u;
            DMAINT2bits.CHSEL = 0x2F;       /* トリガイベント = ADCdone AN7 */
        DMASRC2	= (unsigned int)&ADCBUF7; /* 送信元データは cu2l_Data[] */
        DMADST2	= (unsigned short int)&u2g_ADCData;  /* 送信先はDAC1DATHレジスタ */
        DMACNT2	= 18u;                      /* 送信カウントは18(17 + 1)回 */
        
        DMACH0bits.CHEN = 1u;               /* DMA0チャンネルを有効にする */
        IFS0bits.DMA0IF = 0u;
        DMACH2bits.CHEN = 1u;               /* DMA1チャンネルを有効にする */
        IFS1bits.DMA2IF = 0u;

    /*-------------------------------------------------------------------------*/
    /* ADモジュール初期化*/
    /*-----------------------------------------------------------------------------*/
        ADCON1L = 0x0000u;
        ADCON1H = 0x0000u;
        ADCON2L = 0x0000u;
        ADCON2H = 0x0000u;
        ADCON3L = 0x0000u;
        ADCON3H = 0x0000u;
        ADCON5H = 0x0000u;
        ADTRIG0L = 0x0000u;
        ADTRIG0H = 0x0000u;
        ADTRIG1L = 0x0000u;
        ADTRIG1H = 0x0000u;
        ADTRIG2L = 0x0000u;
        ADTRIG2H = 0x0000u;
        ADTRIG3L = 0x0000u;
        ADTRIG3H = 0x0000u;
        ADTRIG4L = 0x0000u;
        ADTRIG4H = 0x0000u;
        ADTRIG5L = 0x0000u;
        ADLVLTRGL = 0x0000u;
        ADLVLTRGH = 0x0000u;
        ADCMP0CON = 0x0000u;
        ADCMP0ENL = 0x0000u;
        ADCMP0ENH = 0x0000u;
        
        /***** AD制御レジスタの設定 ******/
        ADCON1Hbits.SHRRES = 3u;            /* シェアADC分解能 (3 = 12bit) */
        ADCON2Lbits.SHRADCS = 2u;           /* シェアADCClockディバイダ(2 = 4Clock) */
        ADCON2Hbits.SHRSAMC = 4u;           /* シェアADCサンプル時間 (3 = 4TAD) */
        ADCON3Lbits.CNVCHSEL = 0u;          /* ソフトウェアAD入力(0 =AN0入力)*/
        ADCON3Hbits.CLKSEL = 2u;            /* ADCクロックソース (2 = AFVCODIV) */
        ADCON3Hbits.CLKDIV = 2u;            /* ADCクロックディバイダ(2 = 3Clock)*/
        ADCON5Hbits.WARMTIME = 15u;         /* ウォームアップ時間(15 = 32768Clock) */

        /***** ADトリガ―の設定 ******/
        ADTRIG1Hbits.TRGSRC7 = 0x16;        /* AN7入力のトリガ設定(SCCP3) */
        
        /***** AD割り込みの設定(重要) ******/
        ADIELbits.IE7 = 1u;
        IEC6bits.ADCAN7IE = 0u;
        
        /***** ADFilter ******/
        ADFL0CONbits.FLCHSEL = 7u;          /* 入力チャンネル設定(AN7)*/
        ADFL0CONbits.MODE = 3u;             /* フィルタモード */
        ADFL0CONbits.OVRSAM = 0u;           /* オーバーサンプリング比 */
        ADFL0CONbits.FLEN = 1u;             /* フィルタの有効化 */
        
        /***** ADの有効化 ******/
        ADCON1Lbits.ADON = 1u;              /* ADC全体のパワーON */
        ADCON5Lbits.SHRPWR = 1u;            /* シェアADCのパワーON */
        while(ADCON5Lbits.SHRRDY == 0u){;}
        ADCON3Hbits.SHREN = 1u;             /* シェアADCの有効化 */

    /*-----------------------------------------------------------------------------*/
    /* CCPモジュール有効化*/
    /*-----------------------------------------------------------------------------*/
        CCP3CON1Lbits.CCPON = 1u;
    /*-----------------------------------------------------------------------------*/
    /* メインルーチン*/
    /*-----------------------------------------------------------------------------*/
        while(1)
        {

        }
}

結果

取得したu2g_ADCData[]の中身をCSVにて書き出し、グラフ化してみるとサイン波が格納されている事が確認できます。サンプルの6番目と7番目が不連続なのは入出力のサンプリング周波数が異なる為です。

(fig.2)AD変換結果

参考文献

コメント

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