YS電子工作ラボ

PWM + LPF(ローパスフィルタ) による
DA出力制御

(→プロジェクトファイル(Harmony Ver.2.04版 ) ダウンロード

 OC(Output Compare)モジュールのPWM制御とLPF(ローパスフィルタ)を使ったDA出力制御の例を紹介します。 目的によっては、
それほど高精度(低リップル、高応答性、直線性等)でない直流出力で足る場合があります。こういった場合は PWM+LFPは1つの
安価で有効な方法です。


<仕様>
 ・PIC32MZのOCモジュールのPWM制御とLPFを組み合わせて三角波(のこぎり波)の電圧出力を生成する。
 ・三角波の周期は1秒、振幅は0~3.3Vとする。
 ・PWMの周波数は、1KHzとする。
 ・フィルタは2次のCRフィルタとし、レール ツー レールのオペアンプをバッファアンプとする。
 ・PWM出力値は 割り込みタイマを用い10msec毎にデューティを変えて出力電圧を制御する。
 ・OC制御
   Harmonyは、OCモジュールのスタティックライブラりを用いる。
   割り込みタイマ(タイマ1) 及び PWM用タイマ(タイマ2)はダイナミックライブラリを用いる。


<回路図> (→ PDFファイル




<外観>PIC32MZ評価ボード(→購入方法)を使った実験品の外観です。




<動作結果> (→ 動画:1080pのHD動画を見ることができます。)

オペアンプ AD8532の出力電圧
(1v/div、500msec/div) 


PWM出力電圧(RD9 68ピン 出力電圧)  
(1V/div、200μsec/div) 
Duty = 4 % Duty = 20 % Duty = 60 % Duty = 99 %

<解説>  記載してある内容は要点だけです。 詳細はプロジェクトファイルを精読願います
       (以下は、Harmony v2.04 をもとに作成しています。最新のバージョンとは異なる点があるかもしれませんので注意してください。)


 ■ MHC設定
  ■ Ootions

項目 ①Config設定
Device & Project Configuration
  > PIC32MZ2048 Device Configuration 
②OC設定
Harmony Framework Configuration > Drivers
 > OC
③タイマ設定(参考)
Harmony Framework Configuration > Drivers
 > Timer
MHC  
備考 デフォルトからの変更要領:
 FPLLIDIV: DIV3
 FPLLICLK: PLL_POSC
 POSCMOD: EC

システムクロック周波数: 200MHz
外部OSC: 24MHz


#pragma config FNOSC = SPLL
#pragma config POSCMOD = EC
#pragma config FPLLIDIV = DIV_3
#pragma config FPLLICLK = PLL_POSC
#pragma config FPLLMULT = MUL_50
#pragma config FPLLODIV = DIV_2 
デフォルトからの変更要領:
 □Use OC Driver? チェックを追加
 OC Module ID: OC_ID_5
 OC Modules:
      OC_COMPARE_PWM_EDGE_ALIGNED_MODE
デフォルトからの変更要領:
 なし

 タイマDeiverに係る設定は OCを設定するとMHCにより自動的に設定されます。




   Pin Settings

項目 ④ポート設定
MHC  
備考 デフォルトからの変更要領:
RD9/Functions: OC5


■ app.cに、青字部分を追加します。  system_interrupt.cへの追記はありません。

 ① ここでOC_ID_5をコンパイルするには、peripheral/oc/plib_oc.hをインクルードする必要があるようです。
   変数の宣言、定義を行います。
    #include "peripheral/oc/plib_oc.h" //要追加 OC_ID_5のコンパイル

    DRV_HANDLE myHandle;
    bool Timer_Trigger;

    ……
    ……

 ② インターバルタイマのコールバック関数が呼ばれたらフラグをたてます。
    void tmrISR(uintptr_t context, uint32_t alarmCount ) //タイマ1コールバック関数
    {
      Timer_Trigger = 1;
    };

 ③ APP_Initialize ( )の中で、OC(PWM)の周期、デューティなどの設定を行った後、OCをイネーブルにします。
    //PWM周期 Fpwm = 1000Hz = 1 KHz //分解脳 1/100000000/16 / 1/1000 = 16/100000 = 0.00016 = 0.016%
    //PR(PRレジスタ値) = Fpbclk3(ペリフェラルバスクロック周波数)/Fpwm(PWM周波数)/タイマプリスケール値 - 1;
    myPR = (int)(100000000/Fpwm/PS_T2 -1); //=100000000/1000/16 -1 // Fpbclk3 = 100 MHz
    PLIB_TMR_Period16BitSet(TMR_ID_2, myPR); //PWMの周期を設定 //Set period
    ……
    ……

  ④ ダイナミックインターバルタイマの定数、コールバック関数名などを設定します。
    myHandle = DRV_TMR_Open ( DRV_TMR_INDEX_0, DRV_IO_INTENT_EXCLUSIVE );
    //タイマ1ハンドル取得

    uint32_t divider = 3907; //周期レジスタ初期値 //最初の割り込みまでの時間をセット
    //5 nsec x2 x 3907 x 256 = 10.00192msec = 10 msec at Fblclk3( = 10MHz)
    DRV_TMR_AlarmRegister ( myHandle, divider, true, 0, tmrISR );


  ⑤ APP_Tasks ( )のcase APP_STATE_SERVICE_TASKS:の中で コールバック関数にフラグが立った場合
    インクリメントして、PWMのデューティの計算、設定を行います。
    if(Timer_Trigger == 1)
    {
      Timer_Trigger = 0;
      ix++;

    ……
    ……


以下、app.c