Transistor Gijutsu, October 2014, Special Features Chapter 9, Software of the Function Generator トランジスタ技術2014年10月号 特集第9章のソフトウェア わがまま波形発生器のソフトウェア

Dependencies:   USBDevice mbed

Information

tg_201410s8_AD7714 トランジスタ技術 2014年 10月号 第9章のソフトウェア

Program for Section 9 in October. 2014 issue of the Transistor Gijutsu
(Japanese electronics magazine)

概要

このプログラムは、ソフトウエアDDSにより、任意の波形を出力(2ch)します。 特徴は次のとおりです。

  • PWM出力をDAコンバータとして利用します。
  • 周波数や波形、バースト条件などを個別に設定できる独立した出力を2チャネル持っています。
  • 周波数分解能0.023mHz
  • 周波数範囲0.023mHz~10kHz
  • 各チャネルにそれぞれ、波形の先頭で出力されるトリガ出力があります。
  • 出力波形を関数で定義できます。
  • 休止波数、出力波数、を設定することでバースト波形が出力できます。

ファイル

このソフトウエアは、次のファイルから構成されています。

  • DDS.cpp - DDSによる波形発生
  • main.cpp - main()関数

詳細については、10月号の記事および上記ファイル中のコメントを参照してください。

Revision:
0:f1ecca559ec3
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/DDS/DDS.cpp	Fri Aug 29 08:33:17 2014 +0000
@@ -0,0 +1,259 @@
+#include "mbed.h"
+#include "USBSerial.h"
+#include "DDS.h"
+#include "DigitalOut.h"
+#include "math.h"
+
+DigitalOut out1(P0_2);  // osc1のトリガ出力ピン
+DigitalOut out2(P0_23); // osc2のトリガ出力ピン
+
+// 最適化指定。DDS基準周波数100kHzに必要。
+#pragma O3
+
+// スタティック変数の領域確保
+int16_t DDS::waveForm1[DDS::TBLSIZE];
+unsigned int DDS::phaseAcc1 = 0;
+unsigned int DDS::phaseInc1 = 0;
+unsigned int DDS::phaseShift1 = 0;
+int DDS::bstBgn1;
+int DDS::bstEnd1;
+int DDS::bstLen1;
+int DDS::bstDcL1;
+int DDS::trigger1;
+int DDS::wc1;
+int DDS::lp1;
+
+int16_t DDS::waveForm2[DDS::TBLSIZE];
+unsigned int DDS::phaseAcc2 = 0;
+unsigned int DDS::phaseInc2 = 0;
+unsigned int DDS::phaseShift2 = 0;
+int DDS::bstBgn2;
+int DDS::bstEnd2;
+int DDS::bstLen2;
+int DDS::bstDcL2;
+int DDS::trigger2;
+int DDS::wc2;
+int DDS::lp2;
+
+
+// 割り込みハンドラ
+void PWM1_IRQHandler (void)
+{
+    static int pw1 = 1;
+    static int pw2 = 1;
+    LPC_CT32B1->IR |= 0x01; // 割り込み要因のリセット
+    LPC_CT32B1->MR1 = pw1;  // PWM1パルス幅変更
+    LPC_CT32B1->MR2 = pw2;  // PWM2パルス幅変更
+    out1 = DDS::trigger1;   // トリガパルス出力
+    out2 = DDS::trigger2;
+    DDS::trigger1 = 0;      // トリガ要因リセット
+    DDS::trigger2 = 0;
+    
+    // 次のPWM幅とトリガ要因を計算
+    pw1 = DDS::getNextPw1();
+    pw2 = DDS::getNextPw2();
+    // トリガパルス終了。パルス幅はPWM計算時間。
+    out1 = 0;
+    out2 = 0;
+}
+
+// osc1次のパルス幅を得る
+inline int DDS::getNextPw1(void)
+{
+    static int ret = 0;
+
+    // 位相の更新
+    phaseAcc1 += phaseInc1;
+    // バースト信号処理
+    if(bstBgn1 <= wc1 && wc1 <= bstEnd1){
+        ret = waveForm1[(phaseAcc1 + phaseShift1)>> WFRES];
+    }else{
+        ret = bstDcL1;
+    }
+    if(lp1 > phaseAcc1){
+        // バースト出力の先頭でトリガパルスを発生する
+        wc1++;
+        if(wc1 > bstLen1){
+            wc1 = 1;
+            trigger1 = 1;
+        }
+    }
+    lp1 = phaseAcc1;
+
+    return ret;
+};
+
+// osc2次のパルス幅を得る
+inline int DDS::getNextPw2(void)
+{
+    static int ret = 0;
+
+    phaseAcc2 += phaseInc2;
+    if(bstBgn2 <= wc2 && wc2 <= bstEnd2){
+        ret = waveForm2[(phaseAcc2 + phaseShift2) >> WFRES];
+    }else{
+        ret = bstDcL2;
+    }
+    if(lp2 > phaseAcc2){
+        wc2++;
+        if(wc2 > bstLen2){
+            wc2 = 1;
+            trigger2 = 1;
+        }
+    }
+    lp2 = phaseAcc2;
+    return ret;
+};
+
+void DDS::reset(void)
+{
+    // 割り込みを停止してから変数を初期化
+    NVIC_DisableIRQ(TIMER_32_1_IRQn);
+    phaseAcc1 = phaseAcc2 = 0;
+    wc1 = wc2 = 1;
+    lp1 = lp2 = 0xffffffff;
+    NVIC_EnableIRQ(TIMER_32_1_IRQn);
+}
+
+// osc1バースト波形の設定
+void DDS::burst1(int begin, int end, int length, float dcLevel)
+{
+    bstBgn1 = begin;
+    bstEnd1 = end;
+    bstLen1 = length;
+    bstDcL1 = WFVSPN - WFMAG * dcLevel * WFVSPN;
+}
+
+// osc1バースト波形の設定
+void DDS::burst2(int begin, int end, int length, float dcLevel)
+{
+    bstBgn2 = begin;
+    bstEnd2 = end;
+    bstLen2 = length;
+    bstDcL2 = WFVSPN - WFMAG * dcLevel * WFVSPN;
+}
+
+void DDS::fillTable(int16_t wftbl[], float level, float ofst, float (*wf)(float x))
+{
+    level = (level < -2.0) ? -2.0 : level;
+    level = (level >  2.0) ?  2.0 : level;
+
+    for(int a = 0; a < TBLSIZE; a++){
+        // ラジアンを引数として関数値を計算
+        float val = wf(2.0 * PI * a / TBLSIZE);
+        val = (val < -1.0) ? -1.0 : val;
+        val = (val >  1.0) ?  1.0 : val;
+        // PWMの極性に合わせるためvalの符号を反転し、PWM値に変換
+        //val = (level * val + ofst) * WFMAG * WFVSPN;
+        val = (level * val + ofst) * WFMAG * WFVSPN;
+        wftbl[a] = WFVSPN - val;
+    }
+}
+
+/// OSC1の波形定義
+void DDS::osc1(float f, float p, float level, float ofst, float (*wf)(float x))
+{
+    phaseInc1 = (PACCLEN / DDSCLK) * f;
+    if(p < 0){
+        p = 360 - p;
+    }
+    phaseShift1 = PACCLEN * p / 360.0;
+    fillTable(waveForm1, level, ofst, wf);
+}
+
+/// OSC2の波形定義
+void DDS::osc2(float f, float p, float level, float ofst, float (*wf)(float x))
+{
+    // 位相増分
+    phaseInc2 = (PACCLEN / DDSCLK) * f;
+    if(p < 0){
+        p = 360 - p;
+    }
+    phaseShift2 = PACCLEN * p / 360.0;
+    fillTable(waveForm2, level, ofst, wf);
+}
+
+void DDS::osc1(float freq, float phase)
+{
+    phaseInc1 = (PACCLEN / DDSCLK) * freq;
+    phaseShift1 = PACCLEN * phase / 360.0;
+}
+
+void DDS::osc2(float freq, float phase)
+{
+    phaseInc2 = (PACCLEN / DDSCLK) * freq;
+    phaseShift2 = PACCLEN * phase / 360.0;
+}
+
+// 三角波
+float triangle(float x)
+{
+    if(x < PI){
+        return 2.0 * x / PI - 1.0;
+    }else{
+        return 2.0 * (2 * PI - x) / PI - 1.0;
+    }
+}
+
+// 三角関数の合成による三角波
+float triangleSin(float x)
+{
+    x -= PI / 2.0;
+    return 8.0 / PI / PI * (sin(x) - sin(3.0 * x) / 9.0 + sin(5.0 * x) / 25.0);
+    //return 8.0 / PI / PI * (sin(x) - sin(3.0 * x) / 9.0 + sin(5.0 * x) / 25.0 - sin(7.0 * x) / 49.0 + sin(9.0 * x)/81.0);
+}
+
+// 方形波
+float square(float x)
+{
+    if(x < PI){
+        return 1.0;
+    }else{
+        return -1.0;
+    }
+}
+
+// コンソトラクタ、ハードウエアの初期化
+DDS::DDS(void)
+{
+    LPC_IOCON->TRST_PIO0_14 = 0x83;           // P0_14 -> CT32B1_MAT1
+    LPC_IOCON->SWDIO_PIO0_15 = 0x83;          // P0_15 -> CT32B1_MAT2
+    LPC_SYSCON->SYSAHBCLKCTRL |= 0x1 << 10;   // Enable clock CT32B1
+    LPC_CT32B1->PWMC = 0xf;                   // Enable MAT0..3
+    LPC_CT32B1->MCR = 0x03;                   // MR0 reset & interrupt
+
+    LPC_CT32B1->PR = 0;
+    LPC_CT32B1->MR0 = WFVSPN - 1;   // PWM周期
+    LPC_CT32B1->MR1 = WFVSPN / 2;   // duty 50%
+    LPC_CT32B1->MR2 = WFVSPN / 2;
+    LPC_CT32B1->TCR = 0x02;         // counter reset
+
+    // デフォルトのDDS波形は1kHz連続正弦波
+    trigger1 = 0;
+    burst1(1, 1, 1, 1.0);
+    osc1(1000.0, 0.0, 0.5, 1.0, sin);
+    trigger2 = 0;
+    burst2(1, 1, 1, 1.0);
+    osc2(2000.0, 0.0, 0.5, 1.0, sin);
+    reset();
+
+    // USB割り込みの優先順位を下げる。
+    NVIC_SetPriority(USB_IRQn, 3);
+    NVIC_SetPriority(USB_FIQn, 3);
+    NVIC_SetPriority(TIMER_32_1_IRQn, 0);
+
+    // 割り込み処理の登録と許可
+    NVIC_SetVector(TIMER_32_1_IRQn, (unsigned int)&PWM1_IRQHandler);
+    NVIC_EnableIRQ(TIMER_32_1_IRQn);
+}
+
+
+void DDS::start(void)
+{
+  LPC_CT32B1->TCR = 0x01;                   // counter enable
+}
+
+void DDS::stop(void)
+{
+  LPC_CT32B1->TCR = 0x02;                   // counter reset
+}