電音の歩み

電子楽器を中心とし、ものづくり関係も含めて紹介していきます。

デジタル版Frequency Shifterの検討 その5 RP2040 + I2S ( D/A )+SPI( A/D ) ソフト編2

どんどん検討方向がずれて来ていますが、Arduino IDE でRP2040の開発をする前提で検討しています。まだ、ArduinoIDEでのRP2040サポートが

 

 

■RP2040 arduino(ボード Raspberry Pi PICO)で利用できる低レベル関数

・GPIOのR/Wでは、digitalWriteと比べてgpio_putなどの低レベル関数の方が圧倒的に速い。// 8ns  STM32のように5Vトレラントで無い点は要注意。

・内蔵12bitADCは4個しか無いがなかなか速い。adc_read() // 2usec  もちろんanalogRead()は遅い。

・タイマー割り込みの機能は一つしか無いが、8つもあるPWMカウンタで割り込みを書けれるので困ることはない。

・PWMの使い方には癖がある。PWMは独立したものが8個(1個に付き比較器は2個)あり、これを8スライスと呼ぶ。どのスライスを使うかは、GPIO番号により固定されている。、スラスイ0からスラスイ7まで割り振られており変更できない。スライス番号を使用してPWMカウンタでタイマー割り込みを掛けることもできる。

・2コアは、setup1(),loop1()を用意するだけで簡単に起動できる。

 

■まず I2S D/A は?

RP2040 arduino I2S は、ハードではなく、PIO プロセッサを用いてサポートされている。ライブラリの初期化時にPIO プロセッサにコードが送り込まれ起動するようです。PIOプロセッサのコードは、arduinoでは書けない。(Pythonではできるのに)

D/A チップには、定番らしいTi社のPCM5102 を使用。DIPボード化品をAliで安価に入手できた。

PCM5102は、16/24/32bit が2チャンネルありS/Nは100dB以上。3.3V単一でありながらチャージポンプを内蔵して、AC 2.1V(RMS)が出力できます。もちろんデルタシグマのオーバーサンプリング処理なのでアンチエリアシングフィルタもディジタルで内蔵されています。(SPI D/Aと比べると夢のような仕様で明らかに高音質が期待できます)

I2S マスター/スレーブが使用でき、fsck分周比も多数サポート、特に嬉しいのが、PICO I2Sでは、MCKクロックが出力されないが、PCM5102のMCK端子をGNDに接続すると内蔵PLLでMCKを発生してくれること。 

テストしたのは、16bitと24bit。fsck = 44.1KHz、DMA bufferは、L/R合わせて32bit*8本です。24bitの場合、LRCLKに44.1KHzでは、BCLKは、44.1KHz*24*2 =2.1168MHz をスレーブのPCM5102に与えると、内部でオーバーサンプリング用クロックMCKが生成され、デルタシグマ処理とデジタルフィルタを動作させてくれます。

注意すべき点は、I2S は完全な同期処理なので、マイコンがマスターとはいえ、ソフトはこのタイミングに従う作りにする必要があります。実際にはDMAバッファの空き具合に合わせることになります。

テストの結果は良好で、今まで苦労したS/Nが嘘のように改善され、惚れてしまいました。また、24bitにすると、アナログでのゲイン調整を省略しても支障なさそうなので、アナログがとてもシンプルにできます。

このD/Aが使えるだけでもRP2040にする価値があると思います。

 

■次に I2S A/Dは?

リーズナブルな I2S A/Dとして、同じくTiの定番ぽいPCM1808を検討しました。Ali でも多数ある。

結果から言うと、数々の課題に当たり、今回は使用するのを断念しました

本当は、安価で24bit でアンチエリアシング内蔵のA/D というだけでも、すごい魅力があるわけですが・・・ 残念。

一応、検討メモとして残しておきます。( 私自身I2S初心者のため、あちこち寄り道していますが・・)

PCM1808は、MSCKを与える必要がありかつ24bit固定
D/AにはPCM5102を使うことは決定しているので、D/AだけでなくA/Dも完全同期処理になる。D/A とA/Dで物理的に誤差なくFsck レートを合わせる必要がある。もしD/AとA/Dで異なるビット精度を選択すると各々のBCLKが異なることになり、Fsckを完全に合わすのは難しくなる。
またPCM1808はPLL でMCKを内部で生成してくれないので、普通は外部オシレータで生成する必要がある。
・参考にした、PCM1808 -> PCM5102 直結動作例
 PCM1808をマスターモードに設定し、外部オシレータからMCKを与え分周比を設定すると、PCM1808は、BCLK、LRCLK、Doutを出力する。このMCK、BCLK、LRCLKをPCM5102(スレーブ固定) に与えると、分周比は自動で設定され、A/D D/Aの完全同期が達成されるというエレガントな方法です。もちろん24bit固定のPCM1809に合わせてPCM5102も24bitに統一します。 
ところが、実際問題として、RP2040 arduinoI2S のライブラリがマスタ固定なので、この構成では、D/A には出力できるが、A/Dからの入力ができないことが判明しこのやり方は断念。(今後のライブラリ進化に期待)
 
・そこでひねり出してのが、PCM1808 ,PCM5102を共にスレーブにしかつ同期させる方法
2チャンネルのI2Sポートにそれぞれスレーブ設定のPCM1808とPCM5102を接続し、両Iチャンネルから全く同じ周波数のBCLK、LRCLKを出すように設定する作戦です。
マイコン側がマスターなのでBCLK,LRCLKは、マイコンのクロック基準で作られます。この際、MCKとして外部オシレータから非同期のものを与えると、PCM1808とPCM5102が完全に同期されない危険があり得るので(うまくいくかもしれないが)、MCKもマイコンに同期したものを出すことにします。BCLKは、RP2040のクロック133MHzを11分周して発生します。この12.09MHzから、256分周に設定したLRCLKは、47.23KHzになります。(この手法では、48KHzとか44.1KHzのサンプリングレートにはできないが、直接デジタルで外部に出すことは無いので、自己都合のサンプリングレートで良しとします)
ここまでは目論見通りに行ったのですが、実際にテストプログラムを組もうとすると、24bit固定のPCM1809をつないだI2Sの入力ライブラリが、24bitをサポートしていない様子。A/D 値がNGで行き詰まる。それに加えて、入力用に用意されている関数がブロッキングのread関数のみ。出力用I2Sでは用意されていた、availableのような関数も無い。ということで、この手法も断念。PIOプロセッサのコードとライブラリの改定に期待したい。
結局今回は、I2SのA/Dが使えないことになり、残念ながらSPI でいく方針に変更
arduinoで使いたいと考えている人以外は、解決策があると思いますが・・