2016年6月13日月曜日

MCP4922とNJM13700でSPI制御のDCAを作ってみる。

配線図


OPAMPはTL072を使用。両電源が必要なTL072とNJM13700はプラス5VをArduinoから給電、マイナス5Vを自作の5V-3.3V安定化電源Ver.2から給電。

振幅制御用にPOT3個(ぴゅんぴゅんコントローラー1号)を使った。

ブレッドボード図では18kΩになっているV-I変換用のRの値を47kΩにしてV→Iの変換比率を下げ、たまに発振するようなので2.2kΩのRと並列に0.1uFのCを入れた。(気休め)

Arduinoのスケッチ


ArduinoとSPIのDAC(MCP4922)でエンベロープ・ジェネレーターを作る。」のスケッチとほとんど同じだが、5V MAXで出力するとV-I変換でNJM13700に入力する電流が大きくなりすぎるので、2bit右シフトして出力電圧を1/4にして出力するようにした。

MCP4922_NJM13700_DCA_Test

#include <SPI.h>
#include <MsTimer2.h>

#define MOD_RATE  1   // ms

#define PIN_LDAC   9      // MCP4922のラッチ動作出力ピン
#define PIN_DURATION  A0
#define PIN_DECAY     A1
#define PIN_SUSTAIN   A2   

int16_t beatLen = 500;

int16_t level = 4095;
int16_t duration = 400;
int16_t decay = 100;
int16_t sustain = 2000;

int16_t decay_delta;
int16_t mod_value;

int16_t tick;

// DACに出力
// parameter: v: 出力値(0 .. 4095)
void outDAC(int16_t v)
{
  v >>= 2;
  digitalWrite(PIN_LDAC, HIGH) ;
  digitalWrite(SS, LOW) ;
  SPI.transfer((v >> 8)| 0x30) ;
  SPI.transfer(v & 0xff) ;
  digitalWrite(SS, HIGH) ;
  digitalWrite(PIN_LDAC, LOW) ;
}

void outADSR()
{
  tick++;
  
  if (tick > beatLen) {
    tick = 0;    
    // モジュレーション波形を初期化する
    mod_value = level;
    decay_delta = (level - sustain) / decay;
  }
  
  // 出力値補正
  if (mod_value < 0) {
      mod_value = 0;
  }
  outDAC(mod_value);
  
  if (tick < decay) {
    mod_value -= decay_delta;
  }
  if (tick == duration) {
    mod_value = 0;
  }
}

void setup() {
  Serial.begin(9600);
  
  // DAC出力の初期化
  pinMode(PIN_LDAC, OUTPUT);
  SPI.begin();
  SPI.setBitOrder(MSBFIRST);            // ビットオーダー
  SPI.setClockDivider(SPI_CLOCK_DIV8);  // クロック(CLK)をシステムクロックの1/8で使用(16MHz/8)
  SPI.setDataMode(SPI_MODE0) ;          // クロック極性0(LOW) クロック位相0
  
  // Timerの初期化
  MsTimer2::set(MOD_RATE, outADSR);
  MsTimer2::start();
}

void loop() {
  
  duration = map(analogRead(PIN_DURATION), 0, 1023, 0, beatLen);
  decay    = map(analogRead(PIN_DECAY), 0, 1023, 0, beatLen);
  sustain  = analogRead(PIN_SUSTAIN) << 2;
  
  Serial.print(duration);
  Serial.print("\t");
  Serial.print(decay);
  Serial.print("\t");
  Serial.print(sustain);
  Serial.print("\n");
}

入出力のようす


自作のファンクションジェネレータで100Hzのノコギリ波を出力して振幅を変化させてみた。


ch1:Audio Out ch2:MCP4922の出力


ch1:Audio Out ch2:Audio In

入力信号はノイズに埋もれてしまっているが、出力信号はまあまあきれに変調できているようだ。

メモ:


OPAMPとPNP Trの組み合わせでV-I変換の比率をシミュレーションで調べた方がいいかも知れない。TrのhFEが絡んでくるのかどうかよくわからない。

DACへの入力を1/4にすると精度が悪くなるので(12bit精度が10bit精度になる)アナログ回路的にもう少し考える。