製作モジュール一覧

ラベル SPI-VCA の投稿を表示しています。 すべての投稿を表示
ラベル SPI-VCA の投稿を表示しています。 すべての投稿を表示

2016年7月28日木曜日

NJM13700 DCAの基板でけた。

回路図

基板図

途中でMCP4922(IC2)を間違えて5ホール分(基板のガイド線1個分)ずれてはんだ付けしてしまったので、急遽部品の配置を変更。R6とC3だがなんとか大事に至らず変更できた。助かった(^q^;;;

部品面

はんだ面

電解コンデンサの正負を間違えてはんだ付けしたり、なんだかんだあったがなんとか完成(^q^/

出力波形


PCM5102AのファンクションジェネレータとNucleoシーケンサーをつないで動作確認。


ch1:入力波形 ch2:出力波形

2016年7月25日月曜日

NJM13700 DCAの基板設計

回路図

基板図

配線の都合で、NJM13700はチャンネルA、TL072はチャンネルBを使うように変更した。

33kΩの抵抗の手持ちがなくなったので27kΩに変更。出力レベルが若干上がる。100mV(p-p)の入力で2V(p-p)強。

部品並べ



頑張れば1日ではんだ付けできるかな?

配線の再チェック


NJM13700のチャンネルを変更して再度チェックしてみた。(パイロットランプ用のLEDもつけた)



これ完成させたらラズパイ買う!!

2016年7月23日土曜日

NJM13700 DCAの設計

回路図

図ではOTAはLM13600ANになっているが、NJM13700を使った。NJM13600でも動作する。

R1とR2の分圧で入力を100mV(p-p)になるように調整する(NJM13700の信号入力範囲)。

C1とR3はACカップリング(fc≒1.38Hz)。C2とR9も出力用のACカップリング。

R6とC3はバイアス波形(エンベロープ)をなまらせるLPFでR6で調節する。IC3BとTr1付近はOTAに入力するための電圧→電流変換回路。

NJM13700ボードはSPIハブ(?)機能をもたせる(JP5, JP6)。

このボードに±5Vを入力し、IC4(3.3V LDO)で3.3V電源とし、あわせて±5V/3Vの電源供給元(JP7, JP8, JP9)とする予定。

配線チェック


配線図


シーケンサーとして使うNucleo F401の5V電源も、NJM13700 DCAから供給した。Nucleoのボード上のJP5のE5V側をショートし、morpho headerのE5V/GNDから電源を供給した。

電源電流
+5V 62mA~73mA
-5V 4.80mA

出力波形


矩形波

ch1:NJM13700の+INPUT B(14Pin)への入力波形 ch2:出力波形

サイン波

ノコギリ波


2016年7月19日火曜日

NucleoシーケンサーとDCO、DCF、DCAの結合テスト(UIなし)

やっと音が出た(^q^/


配線図

Nucleoシーケンサー
https://developer.mbed.org/users/ryood/code/SpiSequenceSender_Test/rev/c248781608af

PSoC4 DCO
https://github.com/ryood/PSoC4_DCO/tree/c9a644f7217aabb522c75d070f4e08a5680e7dde

VCVS DCFとDCAを組み合わせると結構不安定になり、フィルターのcutoff/resonaceのツマミの位置でブツブツ言ったり、発振してしまったりする。

製品のように安定して使えるわけではないが、ギリギリのパラメーターを狙っていくのも面白いかもしれない。(←言い訳半分)

ブレッドボードでの実験もそろそろ限界っぽいので、シーケンス打ち込み用のUIをつなぐ前に、ユニバーサル基板で組んでしまう予定。

出力波形

ch1:VCVS DCFの出力をACカップリングした後の波形 ch2:DCAの出力

メモ:


DCOの出力はGND~VDDの波形なのでACカップリングした。→GNDを中心に振れる波形になった。

DCOの出力にデジタル歪が乗っているのでLPFを入れる。(単体である程度テスト)

VCVS DCFはいきなりシールドで組んだが基本アナログ回路なので無謀だったかもしれない(^q^;

VCVS DCFがうまく動かなかった原因はOPAMPのICソケットの接触不良のようだ。丸ピンのICソケットを一段かませたら安定しているようだ。

VCVS DCFの後段でACカップリングしたが、DCOとDCFの間に入れた方がいいか。

DCAのコントロール用に6連POT BOXを作成。


あ~早くリズムマシンとミックスしたい(^q^/

2016年6月26日日曜日

NucleoシーケンサーとPSoC4 DCOとDCAの結合テスト(UIなし)

NucleoシーケンサーのUIを省いてDCO->DCAのテスト

配線図


MCP4922+NJM13700のDCAのエンベロープ波形をコントロールするPOTはつないでいる。

 Level | Duration | Decay | Sustain

Nucleoシーケンサー:
https://developer.mbed.org/users/ryood/code/SpiSequenceSender_Test/

PSoC4 DCO:
https://github.com/ryood/PSoC4_DCO/tree/master/PSoC/PSoC4_DCO_for_NucleoF401RE_Interrupt_Test.cydsn

SpiSequenceSender_Test
main.cpp

#include "mbed.h"
#include "rtos.h"

#define UART_TRACE  (0)
#include "SpiSequenceSender.h"
#include "EnvelopeGenerator.h"
#include "SpiAmpController.h"

#define SEQUENCE_N  (16)
#define SPI_RATE    (8000000)

const int samplingPeriod = 1;   // ms
const int bpm = 120;
const int envelopeLength = (60 * 1000 / (bpm * 4)) / samplingPeriod;

AnalogIn levelIn(A0);
AnalogIn durationIn(A1);
AnalogIn decayIn(A2);
AnalogIn sustainIn(A3);

SPI spiMaster(SPI_MOSI, SPI_MISO, SPI_SCK);

Sequence sequence[SEQUENCE_N];
SpiSequenceSender sequenceSender(&spiMaster, D9, sequence, SEQUENCE_N, samplingPeriod, bpm);

Envelope envelope(4095, envelopeLength, envelopeLength*3/4, envelopeLength/2, 2047);
EnvelopeGenerator envelopeGenerator;
SpiAmpController ampController(&spiMaster, D8, D7);


class TestClass {
public:
    void callbackFunction(int ticks)
    {
        if (ticks == 0) {
            envelopeGenerator.init(envelope);
        }
        uint16_t level = envelopeGenerator.getModLevel();
        //printf("m,%d\r\n", level);
        ampController.outDca(level);
        envelopeGenerator.update();
    }
} testClass;

void callbackFunction(int ticks)
{
    if (ticks == 0) {
        envelopeGenerator.init(envelope);
    }
    uint16_t level = envelopeGenerator.getModLevel();
    //printf("g,%d\r\n", level);
    ampController.outDca(level);
    envelopeGenerator.update();
}

int main()
{
    spiMaster.format(8, 0);
    spiMaster.frequency(SPI_RATE);
    
    // Test SequencerSender Run
    //
    sequenceSender.setBpm(bpm);
    for (int i = 0; i < SEQUENCE_N; i++) {
        Sequence& seq = sequenceSender.getSequences()[i];
        seq.setPitch(i);
        seq.setOctave(-1);
        seq.tie = true;
    }

    sequence[3].setOctave(0);
    sequence[7].setOctave(0);
    sequence[11].setOctave(0);
    sequence[15].setOctave(0);
    
    envelopeGenerator.init(envelope);
    
    sequenceSender.attachUpdate(&testClass, &TestClass::callbackFunction);
    //sequenceSender.attachUpdate(&callbackFunction);
    sequenceSender.setWaveShape(SpiSequenceSender::WAVESHAPE_SAW);
    sequenceSender.run(0);
    
    for (;;) {
        /*
        sequenceSender.setPulseWidth(sequenceSender.getPulseWidth() + 4);
        Thread::wait(500);
        sequenceSender.setWaveShape(SpiSequenceSender::WAVESHAPE_SAW);
        Thread::wait(500);
        sequenceSender.setWaveShape(SpiSequenceSender::WAVESHAPE_SQUARE);
        */
        envelope.setLevel(levelIn * 4095);
        envelope.setDuration(durationIn * envelopeLength);
        envelope.setDecay(decayIn * envelopeLength);
        envelope.setSustain(sustainIn * 4095);
    }
}

プログラムはCallbackのテストも兼ねているのでTestClass::callbackFunction(int ticks)とcallbackFunction(int ticks)を定義しているが、呼び出しているのはcallbackFunction(int ticks) TestClass::callbackFunction(int ticks)。

入出力波形



ch1:DCA出力波形 ch2:PSoC4 DCO出力波形

PSoC4 DCOの出力を100mV(p-p)以下にしているので、ノイズ(おそらくSPI信号)がかなり重畳している。


ch1:DCA出力波形 ch2:MCP4922の出力波形(エンベロープ)

エンベロープを変化させたようすをYoutubeにあげた。


メモ:


DCOの出力波形が0V~+100mV程度になっているのを-50mV~0V~+50mVにしたほうがいいか?
→AC結合すればなんとかなる(@@?

シーケンスのnoteOn/Offは未実装。DCOではなくDCAで処理する。

エンベロープのパラメータをいじるPOTx4はNucleoのArduino HeadersではなくMorpho Headersに繋げるようにする?

MCP4922とNJM13700のDCAの整理

この間作ったAmpControllerクラスでMCP4922とNJM13700のDCAを制御する実験をしてみた。

配線図


mbed repository:
https://developer.mbed.org/users/ryood/code/AmpController_Test/

入出力のようす



ch1:波形出力 ch2:MCP4922からの出力


ch1:波形出力 ch2:波形入力

拡大

入力波形を100mV(p-p)以内にしておけば、MCP4922からの出力は0V~3.3V(MCP4922のGND-VDDのフルスケール)でも出力波形は歪まないようだ。

NJM13700の使ってないチャンネルの処理


NJM13700のチャンネルBを開放のまま使うとすぐ発振したりするのでOPAMPの使っていない回路と同じように、OUTPUTとINPUT-を直結してボルテージフォロアにし、INPUT+をGNDに落とした。

また、OUTPUTはBUFFER INPUTにも接続。BIAS INPUTは電流を流し込まなければ良いと思うので開放のままとした。

これでいいのかどうかわからないが安定度はだいぶ増した感じだ。

DIODE BIASはいまだよくわかっていないので両チャンネルとも開放のままとした。

※LM13700のDATASHEETを見るとRを介して正電源に接続して電流を流してやればリニアリティが改善するようなことが書いてある。

NJM13700のチャンネルBを処理しても、まだ発振する場合がある。条件は不明。

波形入力には自作のPCM5102を使ったファンクションジェネレータを使っていて、この出力が発振する。


(右端にちょこっと見えてるのがファンクションジェネレータ)

出力に4次バターワースLPF を入れていて、これが発振してしまっているのかもしれない?ファンクションジェネレータのスイッチをOFF→ONすれば直るが。

NJM13700のチャンネルBを処理する前は全体の電源を入れなおさないと発振が止まらなかった。

また、波形のGNDレベルが片側に張り付いてしまうこともあった。


ch1:波形入力 ch2:波形出力

これも直ったような感じだがもうちょっとテストした方が良さそう。

メモ:


電源をちゃんと考える。
 Nucleo: 5V
 PSoC4: 5V (PSoC4 Prototyping Kitを使う場合は3.3V)
 DCF: 5V
 DCA: 3.3Vと±5V

基板に実装する前にOPAMP+PNPトランジスタの電圧→電流変換回路をもう一度シミュレーションしてみる。

NJM13700のDIODEバイアスの実験。リニアリティはそんなに要求されないので気が向いたら(^q^;

MCP4922からの出力波形をなまらすために1次CR LPFを入れているが、調節出来るようにRを可変にしたほうがいい?

2016年6月15日水曜日

MCP4922とNJM13700でSPI制御のDCA(Nucleo編)

Nucleo F401REで動作させてみた。

回路図


ブレッドボード図


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は兼用できないか?


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精度になる)アナログ回路的にもう少し考える。