回路図
ブレッドボード図
Nucleoは3.3V駆動なので、MCP4922も3.3V駆動させた。I-V変換回路とNJM13700は別に±5Vの電源を使用。
mbed Repository:
https://developer.mbed.org/users/ryood/code/Nucleo_MCP4922_DCA_Test/
main.cpp
#include "mbed.h" #include "rtos.h" #include "AverageAnalogIn.h" #define SPIM_TIMER_PERIOD (5) // 5ms #define SPIM_RATE (8000000) // 8MHz #define SPIM_WAIT /*(wait_us(1))*/ // ピン・アサイン #define PIN_CHECK PA_10 #define PIN_DAC_CS PA_9 #define PIN_DAC_LDAC PA_8 SPI SpiM(SPI_MOSI, SPI_MISO, SPI_SCK); DigitalOut DacCs(PIN_DAC_CS); DigitalOut DacLdac(PIN_DAC_LDAC); DigitalOut CheckPin(PIN_CHECK); AverageAnalogIn DurationIn(A0); AverageAnalogIn DecayIn(A1); AverageAnalogIn SustainIn(A2); int16_t beatLen = 25; int16_t level = 4095; int16_t duration = 400; int16_t decay = 100; int16_t sustain = 2000; int16_t decay_delta; int16_t release_delta = 1000; int16_t mod_value; int16_t tick; // DAC A Channelに出力 // parameter: v: 出力値(0 .. 4095) void writeToDacA(int16_t v) { // Channel A DacLdac = 1; DacCs = 0; SpiM.write((v >> 8) | 0x30); // 0x30: DAC_A(0) | Vref Unbuffered(0) | Vout 1x(1) | !SHDN(1) SpiM.write(v & 0xff); SPIM_WAIT; DacCs = 1; DacLdac = 0; } // DAC B ChannelにA ChannelのVrefを出力 void outVref() { // Channel B DacLdac = 1; DacCs = 0; SpiM.write(0x08 | 0xB0); // 0xB0: DAC_B(1) | Vref Unbuffered(0) | Vout 1x(1) | !SHDN(1) SpiM.write(0x00); SPIM_WAIT; DacCs = 1; DacLdac = 0; } // ADSR波形を出力 void outADSR(void const* arg) { tick++; if (tick > beatLen) { tick = 0; // モジュレーション波形を初期化する mod_value = level; decay_delta = (level - sustain) / decay; } // 出力値補正 if (mod_value < 0) { mod_value = 0; } writeToDacA(mod_value); if (tick < decay) { mod_value -= decay_delta; } /* if (tick >= duration) { mod_value -= release_delta; } */ if (tick == duration) { mod_value = 0; } } int main() { RtosTimer SpiM_timer(outADSR, osTimerPeriodic); SpiM.format(8, 0); SpiM.frequency(SPIM_RATE); outVref(); SpiM_timer.start(SPIM_TIMER_PERIOD); while(true) { duration = DurationIn.read() * beatLen; decay = DecayIn.read() * beatLen; sustain = SustainIn.read() * 4095; printf("%d\t%d\t%d\r\n", duration, decay, sustain); Thread::wait(10); } }
MCP4922の余っているchannel Bをchannel AのVrefとして使うようにしてみた。0x0800(2048)を出力しているので、channel AのVrefはVDD/2になり、channelAの出力は0V~VDD/2、3.3V駆動させているので0V~1.65Vの振幅になる。
プログラムで後から振幅を調整できるのがメリット。
入出力のようす
ch1:MCP4922の出力 ch2:WaveOut
ch1:WaveIn ch2:WaveOut
拡大
WaveInの振幅
差動入力電圧100mV(p-p)以下
ch1:WaveIn ch2:WaveOut
差動入力電圧100mV(p-p)以上
波形の振幅は±100mV(p-p)以内におさえないと激しく歪む。歪ました方が面白い場合もあるのでトリマーで調節できるようにしようか。
ADSR波形にLPFを入れてみる
MCP4922で出力した波形がカックカクなので、出音がブツブツ言う。なのでLPFを入れてアナログチックな波形にしてみた。
LTSpiceでシミュレーション
過渡解析
125m秒と言うのは、120BPMの四分音符の長さ。これぐらいのなまり方ちょうど良さそう。
ch1:MCP4922の出力 ch2:WaveOut
メモ:
いまだに割と簡単に発振してしまう。意図しない発振なのでつぶす必要がある。デカップリングコンデンサは入れているので、NJM13700の使ってないB側をGND入力のボルテージフォロワーにして安定させてみるとか。オーディオ信号が発振するのでNJM13700の周辺だと思う。
ADSR波形のLPFもなまり方を可変できるようにRを10kΩ程度のトリマーにしてみる?
回路図のR1とR2は兼用できないか?
0 件のコメント:
コメントを投稿