製作モジュール一覧

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

2017年7月8日土曜日

KIK01 SPI制御VCAと演算による振幅変調の比較

振幅変調をCPUの計算でやったものと、SPI VCAでやったものの出音を比較してみた。


動画の最後のOver Driveは、Over Driveエフェクタではなく、NJM13600への入力レベルを大きめにして歪ませてみた。

処理時間の比較


SPI VCA



ch1:D3 ch2:D2

ch1:D3がHの区間はサンプリング周期でエンベロープ出力のみに使った時間。およそ11us~14us。

ch2:D2がHの区間は同じく、全処理に使った時間(エンベロープ出力+波形出力)。およそ13~16us。

サンプリング周期が20us(50kHz)なのでほぼほぼ処理に時間消費してしまっている。


ch1:D3 ch2:CS

ch2:CSがLの区間は、MCP4922とのSPI通信に費やしている時間。おおよそ7us~9us。

エンベロープ出力に11us~14usかかっているので、4~5us程度がSPI通信以外のエンベロープ生成に使っている時間。


サンプリング・レートが50kHz程度だと、F446でも1chでSPI通信だけで9us程度使ってしまうので、MCP4922に2ch出力するのはキツそうだ。これ以上SPIクロックを上げてもあまり効果はなさそう。(参考「Nucleo F446RE(mbed)の内蔵DACとSPI DACのMCP4922の速度を比較する」)

内部演算

振幅変調をプログラムで行った場合。


ch1:D3 ch2:D2

エンベロープ計算に3us。波形出力完了まで4.8us。


SPI VCAのエンベロープ


SPI VCAの回路図

回路図のD-3エリアのトリマのR6とC3で構成されるLPFでエンベロープ波形を滑らかにしている。ここの波形を見るためにトリマを回しながらR7入口側のポイントの波形を見てみた。

R6最小

R6中間

R6最大

振幅変調のエンベロープはプログラムで滑らかにしているので、R6最小がパキっとした感じで良さそう。動画はR6を最小にして録音している。

2017年7月6日木曜日

キックマシン KIK01 SPI制御VCAを使ってみる。

周波数変調したサイン波をNucleo F446REの内蔵DACから出力し、ベースマシン用に作ったSPI VCAで振幅変調させてみた。

SPI VCAは、SPI制御DACのMCP4922の出力電圧を電圧→電流回路を通し、OTAのNJM13600(NJM13700でも可)を使って振幅変調し、SPI制御のVCAとして機能する。

必須要件ではないが、パラメータ入力用にPOTx16 Pizza Boxを使った。POTx16 Pizza Boxは可変抵抗の値をSPI制御のADCのMCP3008でA/D変換し、SPIスレーブの入力デバイスとして使える。

SPIバスを1つだけ使って共有


SPI VCAとPOTx16 PizzaBoxのSPIバスを同一のものとして使ってみた。切り替えはそれぞれに割り当てたSPIのCS線で行う。


mbed repository:
https://developer.mbed.org/users/ryood/code/KIK01_Proto03/ Revision:15

SPIバスを共有するとPOTx16 Pizza BoxとSPI VCAの処理のタイミングがバッティングしてしまい、うまく動かなかった。

サンプリングレートを変えてみると、

48kHzだとPOTx16 Pizza BoxのSPI通信に処理が回らない。
16kHzだとPOTx16 Pizza BoxにSPI通信の処理が周り、入力を受け付けるが変な音が出る。
8kHzだとまあまあちゃんとした音がでるが、さすがにサンプリングレートが低すぎて耳で聴こえるレベルのエイリアスが発生。

サンプリングレートが16kHzの場合のタイミングを見てみた。

D2 : SCK

ch1:D2 ch2:SCK

ch1のD2はプログラムでDout0と定義していて、内蔵DACからの出力と、SPI VCAへのSPI通信完了までHレベルにしている。オシロのようすを見ると、D2がLのときにSCKから出力されている信号はPOTx16用のSPI通信と思われ、D2がHのときに出力されている信号がSPI DCAへの出力と思われる。

D2がHのときにSCKが出力されていない場合がよくあるが、この場合はPOTx16との通信にじゃまされて、肝心のSPI VCAへの出力が行われていない(@@;

D4 : SCK

ch1:D4 ch2:SCK

同拡大

ch1のD4はプログラムでDout2と定義していて、POTx16とのSPI通信を行っている間Hにしている。メインループ内でThread::wait(1)として1msのwaitをかけているが、D4がLの間隔を見ると500us弱のwaitになっているようだ。

このPOTx16との通信中は、SPI VCAへの通信が不安定になっている可能性が高い。

SPIバスを2個使う


mbed repository:
https://developer.mbed.org/users/ryood/code/KIK01_Proto03/ Revision:16

配線図


SPIバスを共有せずに、POTx16とSPI VCAそれぞれにSPIバスを割り当ててみると、こちらはうまく動作してくれた(^q^/

SPI2(SPI DCAへの出力)


D2 : SPI2_SCK

ch1:D2 ch2:SPI2_SCK

D2がHのときにちゃんとSPI VCAとの通信が行われているように見える。多少エラーがあっても聴感上もんだい無ければかまわないが、もう少しテストする必要がある。

SPI2_SCKのクロック

プログラムの設定値が20MHzで、実測値11.22MHz。Nucleo F446REのMPUの駆動クロックは180MHzなのでだいたい1/16かな?

D4 : SPI2_SCK

ch1:D4 ch2:SPI2_SCK

D4がLの区間はPOTx16との通信が行われていないが、D4がHとLの区間でSPI VCAとのSPIクロックの出力とのようすが少し異なる。まだ干渉しているのか(@@?

←拡大して観察してみる?

D4がLの区間は表示では500us程度になっているが、300us~900usの間で変動する。

D2 : D4

ch1:D2 ch2:D4

メインループ内でThread::wait(1)をかけているのでch2:D4のLの区間は1ms程度になってほしいんだが、やはりかなり短い(300us~900us)

SPI1(POTx16からの入力)


D2 : SPI1_SCK

ch1:D2 ch2:SPI1_SCK

ch1:D2がHの区間はSPI2でSPI DCAへ出力中なので、SPI1は非同期で動作している。ch2のSPI1の通信中はch1のHの区間も間延びしているので、別のSPIハードウェアを使ってもSPI通信のオーバーヘッドのせい(?)で処理時間が間延びしている。

SPI1_SCKのクロック

プログラムの設定値が2MHzで、実測値1.406MHz。駆動クロックの1/128と思われる。

D4 : SPI1_SCK

ch1:D4 ch2:SPI1_SCK

wait中はSPI1からはSCKは出力されていない。

メモ:


SPIバスを2個使わないと、POTx16のADCと振幅変調用のSPI DCAは同時に使えなさそう。Nucleo F446はSPIが3個使えるが、Nucleo F303は1個しか使えない。さあ困った(@@;

Nucleo F303の仕様上の内蔵DAC2個が同時に使えればいいんだが、mbed 2で試してみたらうまく動かせなかった。(参考:「NucleoF303K8を買ってみた。http://dad8893.blogspot.jp/2017/06/nucleof303k8.html」)

以前、Nucleo F401REでmbedのSPI::transfer()を試してみてうまく動かせなかった。「Nucleo F401RE(mbed)同士でSPI通信してみる。(その2)http://dad8893.blogspot.jp//2016/10/nucleo-f401rembedspi.html

SPI::read()、SPI::write()ではなくてバイト列で送受信できればもう少し処理時間を節約できそうだが。


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を可変にしたほうがいい?