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()ではなくてバイト列で送受信できればもう少し処理時間を節約できそうだが。