オーディオ発振器の製作 2022.8.18
2022.9.10(改修)

    2022.9.10:周波数設定を1Hz単位で行えるように改修しました。

    1.はじめに
    MDレコーダのケースに組み込んだ発振器とカウンター

     約10年前にジャンクのMDレコーダのケースを使ったオーディオ発振器とカウンターを製作しました。

     この装置ですが、大きくて手軽さに欠けることから製作はしたもののほとんど使わずじまいで置き場所にも困り廃棄してしまいました。中に組み込んだマイコン基板は取り外して保管していました。

     今回このマイコンを再利用し、オーディオアンプなどの修理・調整用の音源として使えるコンパクトなオーディオ発振器を製作しました。

    PICを古い基板から取り外して
    ピッチ変換基板に付け直しました
    今回製作した発振器
     ユニバーサル基板で製作
     PIC基板の下にR-2Rラダー回路が隠れています

    2.仕 様

     発振器の装置仕様は次の通りとしました。

      発振波形正弦波、三角波、鋸歯状波(上昇・下降)、パルス波
      周波数10Hz 〜 20KHz, 1Hzステップ
      電 源 +5V ACアダプタ
      出 力3.5φステレオオーディオジャック
      操作部ロータリーエンコーダーによる波形選択ならびに発振周波数選択
      表示部小型キャラクタ型LCD(8文字x2行)
      外 形ポリカーボネートケースに収納

     発振周波数は目的がオーディオ装置の調整用ですので 10Hz 〜 20KHz までとしました。回路的には、60KHz以上まで発振出来ますが発振波形が荒くなり出力レベルも下がってしまいます。

     発振方式は、前回製作と同様、波形データテーブルを参照するDDS方式・抵抗によるR-2RラダーによるDA変換としました。DA変換機の出力にはオペアンプによるバッファ回路を設けることにしました・。

     ロータリーエンコーダーは、サーボテスター(改良版)の製作で使用したものと同じ物を使いました。波形選択や周波数選択の操作を行います。

     再利用するマイコンdsPIC30F2012のROM容量は12KBと小さいです。文字フォントを格納する余裕がありませんのでLCDにはフォントデータが不要なキャラクタ型を採用しました。

     電源は、dsPIC30F2012 が5Vマイコンですので、+5V出力のACアダプタから直接供給することにしました。

     今回採用したLCDですが、商品説明では電源電圧3.3Vとあります。+5Vの電源で使うには3.3Vのレギュレータ回路が必要です。また、+5VのPICとの接続では、電圧のレベルシフト回路が必要となります。

     ところで、このLCDに使われているチップST7032の仕様を確認してみると+5Vでも動作可能なようです。そこで、試しに +5Vで動かしてみると壊れることもなく正常に動作しました。商品の仕様の範囲外ですが+5Vで動かすことで、3.3Vのレギュレータ回路もレベルシフト回路も不要となりました。


    3.使い方

     DCジャックに+5VのACアダプタを接続すると、パワーランプのLEDが点灯します。

     LCDの一行目に=Select=の文字が表示され波形選択メニューとなります。エンコーダを回転すると以下の写真のようにLCDの2行目に出力波形名が順次表示されます。

    正弦波
    三角波
    鋸歯状波(上昇)
    鋸歯状波(下降)
    パルス波

     出力したい波形が表示されている時に、エンコーダのつまみを押し込むと周波数選択に切り替わります。このタイミングでオーディオ出力ジャックには、約1000Hzの選択した波形が出力されます。

    正弦波 1000Hzを選択
    オシロスコープによる出力観測波形

     エンコーダを右に回転すると周波数が高くなり、左に回転すると周波数が低くなります。
     早く回転すると大きく変化します。ゆっくり回転すると1Hz単位で増減します。出力周波数もそれに応じて変化します。

     ここでエンコーダのつまみを押し込むと、出力波形の選択メニューへと戻ります。


    4.回 路
    回路図(クリックで拡大)

     電源は、+5VマイコンdsPIC30F2012を採用しましたので+5V出力のACアダプタから直接供給するようにしています。

     ロータリーエンコーダーの出力ピンには、2.7KΩと20KΩのプルアップ抵抗と1μFのセラミックコンデンサを接続しています。

     コンデンサはエンコーダ内部のスィッチのチャタリングを除去するためのものです。

     DA変換には、10KΩと20KΩの抵抗によるR-2Rラダー回路を採用しました。

     変換器出力には、出力インピーダンスを下げるためにオペアンプNJU7032Dによるバッファ回路を設けています。

     更にその先には、DDS発振のクロック成分除去のために、1.5KΩと1,000pFによるRCローパスフィルタを接続しています。

     LCDモジュールはマイコンとはI2Cでの接続になります。SDAやSCLラインの外付けプルアップ抵抗は、LCDモジュール内でプルアップされているので不要です。

     マイコンのクロック発振には、20MHzのセラミック発振子を使いました。cpu config にて、HS 1/2, 8xPLLを設定しましたので、命令クロックならびにペリフェラルクロックは20MHzとなっています。

     マイコンのファームウェアは、MPLAB IDE にて c30 コンパイラにて作成しました。主なソースコードは generate.c, main.c です。
     その他のソースコードについてはプロジェクトファイルを参照ください。 Projectファイルはこちらです。


    5.ファームウエア補足説明

    5−1 DDS発振について

     正弦波、三角波などの1周期分の波形データを次のように予め配列変数に設定しておきます。

     正弦波は 127*sin(x)+128 で 最小値が 1 最大値が 255 になっています。三角波も同様に 128+/-127 で 最小値が 1 最大値が 255 になっています。鋸歯状波は 1 から 253 までの上昇となっています。

     const unsigned char sine_wave[128] = {
        128, 134, 140, 147, 153, 159, 165, 171,
        177, 182, 188, 193, 199, 204, 209, 213,
        218, 222, 226, 230, 234, 237, 240, 243,
        245, 248, 250, 251, 253, 254, 254, 255,
        255, 255, 254, 254, 253, 251, 250, 248,
        245, 243, 240, 237, 234, 230, 226, 222,
        218, 213, 209, 204, 199, 193, 188, 182,
        177, 171, 165, 159, 153, 147, 140, 134,
        128, 122, 116, 109, 103,  97,  91,  85,
         79,  74,  68,  63,  57,  52,  47,  43,
         38,  34,  30,  26,  22,  19,  16,  13,
         11,   8,   6,   5,   3,   2,   2,   1,
          1,   1,   2,   2,   3,   5,   6,   8,
         11,  13,  16,  19,  22,  26,  30,  34,
         38,  43,  47,  52,  57,  63,  68,  74,
         79,  85,  91,  97, 103, 109, 116, 122,
        };
    
    
     const unsigned char triangle_wave[128] = {
          1,   4,   8,  12,  16,  20,  24,  28, 
         32,  36,  40,  44,  48,  52,  56,  60, 
         64,  68,  72,  76,  80,  84,  88,  92, 
         96, 100, 104, 108, 112, 116, 120, 124, 
        128, 131, 135, 139, 143, 147, 151, 155, 
        159, 163, 167, 171, 175, 179, 183, 187, 
        191, 195, 199, 203, 207, 211, 215, 219, 
        223, 227, 231, 235, 239, 243, 247, 251, 
        255, 251, 247, 243, 239, 235, 231, 227, 
        223, 219, 215, 211, 207, 203, 199, 195, 
        191, 187, 183, 179, 175, 171, 167, 163, 
        159, 155, 151, 147, 143, 139, 135, 131, 
        128, 124, 120, 116, 112, 108, 104, 100, 
         96,  92,  88,  84,  80,  76,  72,  68, 
         64,  60,  56,  52,  48,  44,  40,  36, 
         32,  28,  24,  20,  16,  12,   8,   4, 
        };
    
    
     const unsigned char saw_tooth_wave[128] = {
          1,   2,   4,   6,   8,  10,  12,  14, 
         16,  18,  20,  22,  24,  26,  28,  30, 
         32,  34,  36,  38,  40,  42,  44,  46, 
         48,  50,  52,  54,  56,  58,  60,  62, 
         64,  66,  68,  70,  72,  74,  76,  78, 
         80,  82,  84,  86,  88,  90,  92,  94, 
         96,  98, 100, 102, 104, 106, 108, 110, 
        112, 114, 116, 118, 120, 122, 124, 126, 
        128, 129, 131, 133, 135, 137, 139, 141, 
        143, 145, 147, 149, 151, 153, 155, 157, 
        159, 161, 163, 165, 167, 169, 171, 173, 
        175, 177, 179, 181, 183, 185, 187, 189, 
        191, 193, 195, 197, 199, 201, 203, 205, 
        207, 209, 211, 213, 215, 217, 219, 221, 
        223, 225, 227, 229, 231, 233, 235, 237, 
        239, 241, 243, 245, 247, 249, 251, 253, 
       };
    

     この配列データを0番目から順番に127番目まで(127番目の次は0番目に戻ります)一定の速度で読みだしながら、DA変換器に出力すると波形が生成されます。

     読み出し速度を一定にしておいてデータを 1つ飛びに読み出すと出力波形の周波数は2倍となり、2つ飛びに行うと3倍の周波数となります。あるいは、読み出し間隔(1つ飛びや2つ飛びなど)を一定にしておいて読み出し速度を2倍にすると出力周波数は2倍になり、3倍にすると3倍の周波数になります。

     つまり、読み出し速度や読み出し間隔を適当に設定することで任意の周波数の波形を出力できることになります。

     本作では、タイマー2の周期割込みを使って配列データの読み出しを行っています。タイマー2のクロックは 20MHz です。仮に10クロック毎に割込みが発生すると仮定すると読み出し速度は2MHzになり、読み出し間隔が 2(1つ飛び) であるとすると、出力周波数は、 2MHz * 2 / 128 = 31,250Hz となります。

     見方を変えて、1,000Hzの周波数を発生させるには、読み出し速度が 2MHz とするなら、その読み出し間隔(n)は、次の計算式で求められます。

      n = 128 * 1000 / 2MHz 1000Hz

      n = 128 * 1001 / 2MHz 1001Hzの場合
      n = 128 * 2345 / 2MHz 2345Hzの場合

     この式で求められる n は整数ではなく少数を含む実数となります。つまり、読み出し間隔を整数ではなく実数に設定できれば1Hz単位で任意の周波数を作ることが出来ることになります。

     dsPICには浮動小数演算モジュールはありません。そこで、整数部16bit+少数部16bitの 32bit固定少数演算で行います。


     最終的に、固定少数演算に要する時間やその他の処理時間も考慮して、タイマー2の割込みは、45クロック(2.25μsec)で行うようにし、正弦波の波形データは1024サンプルの配列データを用意しました。この条件で、任意の周波数(f)を出力するための、32bit固定少数点で表した読み出し間隔(n)は、次のような計算式で求められます。

     n = ( (1024 * f * 45) << 16 ) / 20MHz

     他の波形データも1024サンプル準備出来れば良かったのですが dsPIC30F2012のROM容量の制限から断念し128サンプルとしています。


    5−2 マイコンのクロックについて

     採用したマイコンdsPIC30F2012のクロックについてです。このPICの cpu config では、 HS 1/2, 16xPLL の設定が可能です。

     この意味ですが、PICのシステムクロックは、外部接続した発振子の周波数の1/2の周波数を、PLLを使って16倍した周波数に設定できるというものです。そしてこのPICの命令クロックはシステムクロックの1/4です。

     今回外付けの発振子に20MHzのセラロックを使っています。この設定にすると、(20MHz/2)*16 / 4 = 40MHzとなり、命令速度も速くなりDDS発振の処理にも余裕が出来ます。

     実際の所、電圧 5.15V出力のACアダプタでは、PLL 160MHz, 命令クロック 40MHz で問題なく動作したのですが、4.90V出力のACアダプタに交換するとPLLが安定せずマイコンがリセットを繰り返す現象となりました。

     そこで、安定動作する HS 1/2 8xPLL の設定で動かしています。


    5−3 R−2Rラダーの出力電圧
    DAC出力 (クリックで拡大)

     R-2RラダーによるDAC変換器の出力電圧は、RB0-RB7に出力する値によって変化しますが、その出力電圧は次の計算式で求められます。電源電圧は+5Vとします。

     DAC出力 = 1.66V * { RB7 * 1 + RB6 * (1/2) + RB5 * (1/4) + RB4 * (1/8) + RB3 * (1/16) + RB2 * (1/32) + RB1 * (1/64) + RB0 * (1/128) }
      *)RBx は1または0です。

     この式から最小0Vから最大3.32Vの出力となります。127*sin(x)+128 の正弦波データでは、最小 0.013V から 最大 3.32V の出力となります。実際の出力はピタリではありませんがほぼ計算通りです。


    5−4 オペアンプの選定

     DACの出力は約0Vから3.3Vですから、+5Vで動く、単電源動作・レールtoレールのオペアンプを選定すれば問題ないと思われます。そこで、JRCのNJM2732DをDACの出力バッファとして接続してみました。

     約20KHzの正弦波とパルス波のDAC出力(オペアンプ入力)波形とオペアンプ出力波形は次のように観測されました。

    オペアンプにNJM2732を使用
    DAC出力 sin 20KHz
    (クリックで拡大)
    OPアンプ出力 sin 20KHz
    (クリックで拡大)
    DAC出力 pulse 20KHz
    (クリックで拡大)
    OPアンプ出力 pulse 20KHz
    (クリックで拡大)

     正弦波については、入力と出力に違いは見当たりませんが、パルス波については、オペアンプ出力の立ち上がり・立下りに約8μsecの時間を要しています。

     NJM2732のスルーレートを仕様書で確認すると 0.4V/μsecとあります。パルス波は、約0Vから3.2Vぐらいの振れですので、立ち上がり時間は、3.2V/0.4V = 8μsec と仕様どおりの動作です。

     立ち上がり・立下りを早くするには、スルーレートの大きいオペアンプが必要ということです。オペアンプを単電源・高スルーレートのNJU7032Dに変更して波形を観測したのが次です。

    オペアンプにNJU7032を使用
    OPアンプ出力 sin 20KHz
    (クリックで拡大)
    pulse 20KHz 青:入力 赤:出力
    (クリックで拡大)
    SAW down 20KHz 青:入力 赤:出力
    (クリックで拡大)
    SAW up 20KHz 青:入力 赤:出力
    (クリックで拡大)

     NJU7032のスルーレートは、3.5V/μsec です。正弦波については、入力と同様の出力となっています。パルス波の立ち上がりは、NJM2732の時に比べて 1から2μsecの遅れに改善しています。一方、立下りは入力波形自体が数μsecの立下りなので出力に遅れは見られません。鋸歯状波の立ち上がり、立下りについてもパルス波と同様です。 

     以上の検証からオペアンプは、NJU7032Dを使うことにしました。

     なお、発振器の出力電圧はこのままでは、ピークtoピーク +/-1.6V でオーディオ機器の入力信号としては大きすぎます。出力レベル調整用のボリュームを追加するのではなく、波形データの値を修正し、DACの出力電圧を約半分程度に下げました。


    5−5 ローパスフィルタ通過後の最終出力波形

    sin 10Hz
    (クリックで拡大)
    sin 20KHz
    (クリックで拡大)
    triangle 10Hz
    (クリックで拡大)
    triangle 20KHz
    (クリックで拡大)
    saw 10Hz
    (クリックで拡大)
    saw 20KHz
    (クリックで拡大)
    pulse 20Hz
    (クリックで拡大)
    pulse 20KHz
    (クリックで拡大)

     出力電圧は、ピークtoピーク +/-0.8Vになっています。20KHzでもレベル低下せずに出力出来ています。