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月号の記事および上記ファイル中のコメントを参照してください。

DDS/DDS.cpp

Committer:
Dance
Date:
2014-08-29
Revision:
0:f1ecca559ec3

File content as of revision 0:f1ecca559ec3:

#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
}