Maker Faireからここしばらくイベントが続いて、積み基板ならぬ積みプロジェクトが多数放置状態でしたが、年末年始にかけて消化していきたいところです。DDS IQ AD9857をNucleoで変調する実験をしてみたところ、うまくいきました。以下詳細です。
DDS AD9857の実験ですが、前回シングルトーンを出せるところまで確認していました。Nucleo-F401REに載せるアドオンボードとして基板を作っていました。シングルトーン動作はクロックを与えて、SPIでレジスタを設定するだけでOKでした。水晶12MHzから内部のPLLをx16と設定し、DDSのクロックSYSCLKは仕様内の192MHzで動作させましたので、80MHz程度以下の任意の周波数の信号を生成できます。周波数設定は2^32の解像度がありますので、周波数ステップはおよそ0.0447Hzとなります。
もちろん次の目標は変調動作です。AD9857による変調は、IQ DDSであることからも判るように、デジタルデータとして直交信号を14bitのパラレルデータで与える必要があります。データシートではクァドラチュアモードと記載されています。このモードでは、AD9857からPDCLK(Parallel Data Clock)が出力されますので、このクロックに合わせて14bitデータを次々と送り込む必要があります。サンプル毎にIとQの二つのデータが必要ですが、これは交互に与えます。AD9857内部では4xNのインターポーレーションが設定できますが、SYSCLKは192MHzですので、ここでは4x32と設定して、データレートを 192/(4x32) = 1.5MHz としてみることにします。IQのためPDCLKは2倍の3MHzのパルスが出力されます。データはもちろんMCUで生成しますので、MCUに内蔵している機能を使って14bitデータを3MHzのレートで出力する必要があります。
果たしてこんなことが可能かどうか、Nucleoに搭載されているMCU STM32F401xEのデータシートというかリファレンスマニュアルを、じっくりと検討しました。所望の動作はタイマーの機能とDMAの組み合わせでなんとかなるような気はしましたが確証はありません。動作確認したいところですが、基板が無いと実験すらできないので、えいやっとピンアサインを決めて、基板を作ってしまいました。そうして、まずはとりあえずDDS単体でのシングルトーン動作が確認できた、というのが前回までのステータスでした。
その後調べてみたところ、タイマーとDMAを組み合わせて使う方法は、開発環境であるmbedの標準的なAPIではできないようです。mbedのコードはオープンソースですので、githubからソースを手元に引いてきて、中身を調べながら実装方法を検討しました。STM32F4向けの実装はHALというレイヤがあり、そのAPIを直接使うことでタイマーとDMAを自由に操作することができそうです。
まずはメモリにあるデータをPDCLKのパルスで次々と送り込むことができるかどうか実験しました。PDCLKをTIMの入力にし、TIMでDMAを駆動し、バッファ内のデータを次々とGPIOポートに出力するよう設定します。バッファのメモリを0x5555, 0xaaaaというパターンで埋め、オシロでピンを見ながら、バッファのデータが出力されるよう試行錯誤しました。なかなかDMAが動作せずに苦労しましたが、ようやくデータが出てくるようになりました。DDSからも入力に応じたノイズっぽい波形が出てきているようです。これはイケそうな感触です。
はやる期待をおさえつつ、続いてはsin関数で単一トーンの波形データをバッファに生成し、これをDDSに送り込んでみます。そうしたところ見事、変調波形がDDSから出力されてきました。Iのみサイン波とし、Qは0の信号を出力したので、両サイドにスペクトラムの立ったDSBな波形です。
AD9857とNucleoで変調実験成功。ここまで来たらあとはコードさえ書けば何でも出せる。 pic.twitter.com/CfkkNnZN6v
— TT@北海道 (@edy555) 2014, 12月 6
別の実験として、Qをcosにしてみると、ちゃんと片サイドのみのスペクトラムになりました。素晴らしい。数値的な処理なのでIQアンバランスや位相誤差の心配もありません。複数のトーンを重ねたりも自由自在に可能でした。
というわけで、無事にIQ DDSとしての動作を確認することができました。次のフェーズは動的な変調動作です。基板上にはオーディオコーデックチップを搭載予定でしたので、さっそくチップを載せて実装しました。もちろんマイクを接続して単体での変調動作できることを目指しています。チップは最近愛用しているTLV320AIC3204で、インターフェースはもちろんI2Sです。2つのミニジャックで音声信号の入出力を可能にしました。スピーカも直結できます。4極コネクタを使いましたので、マイク代わりにスマホ用のヘッドセットも使えます。このコーデックは携帯機器用のチップなのでこのようなインターフェースはスマートに実現できます。
LPC1768用では既存のI2Sモジュールがあり、使用経験はあったのですが残念ながらNucleoには対応していないようでした。NucleoでI2Sを使うことについては先人がおり、コードを参考にさせていただきました。やはりHALのレイヤから操作する必要があるようです。
まずはI2Sで固定トーンを出力する動作を実装しこれがうまく動くようになってから、ついでFull Duplexで入出力が同時に動くようにしました。マイクからの入力を即座にスピーカに出力するループバックで動作確認します。
I2S Audio Loopbackも確認おk。あとは48k->1.5MへのInterpolaterを実装。
— TT@北海道 (@edy555) 2014, 12月 22
クロックをどうするかちょっと悩みました。品種選択肢が多く入手しやすい12MHzの水晶を載せていたのですが、12MHzをベースにしたDDSのクロックとは単純な整数倍になりません。48kHzからインターポーレーションでクロックを持ち上げる必要があるのですが、ベースを24.576MHz等の周波数を選ぶと簡単になるので、置き換えようか考えたのですが、結局は12MHzのまま、ちょっと面倒な周波数スキームを実装してみることにしました。
48kHzからDDS入力の1.5MHzに持ち上げるためには、125/4倍する必要があります。FIRとCICを組み合わせてインターポーレーションします。FIRで25/4のリサンプリングを行い、その後CICで5倍することにします。
これらの信号処理の実装は慣れないとなかなか難しく、性能を出すために工夫が必要なところですが、Cortex-M4はSIMD命令が使えますのでうまくハマるようよく考えて実装します。CMSISにあるイントリンシック関数を使うと、CからSIMD命令を使うことが可能です。レジスタが少ないのでそのトレードオフも考える必要があります。コンパイル結果が想像付くようにアセンブラを使うようにCのコードを書き下し、実行に必要なサイクル数を勘定しておきます。Cortex-M4は多くの命令が1サイクルで実行可能ですし、コンパイラの能力にも依存しますが、それなりの精度でサイクル数を予想可能です。Nucleo F401REは84MHzで動作しますので、所要時間を見積もることができます。
I2SのDMA転送割り込みが完了したタイミングで、キャプチャしたデータをFIRとCICによりインターポーレートしメモリに広げます。この動作のタイミングをオシロで確認し、メモリに展開された結果を、シリアル経由で読んでデータをPython/Matplotlibでグラフ化してチェックしました。
インターポーレータ動作OK。20%程度の負荷で足りた。あとはDMAでAD9857に送り込むだけ。 pic.twitter.com/bnvSUUl7uz
— TT@北海道 (@edy555) 2014, 12月 25
うまく動作しているようですので、あとはこれをDMAでDDSに転送します。何か適当なアナログ信号を与えると変調された信号が出ています。そこでアナログ音声信号としてIQ信号を与えると、これをDDSで変調して意図したRF信号が得られることになります。MCUにはまだ変調機能を実装していませんので、GNURadioを使ってSSBやNBFMのIQ変調信号を生成します。それを音声信号としてライン出力し、それをI2Sコーデック経由でDDSで変調させてみたところ、見事に変調されたRF信号が得られました。スプリアスが出る不具合がありましたが、バグを発見、無事取り除くことができました。うまく動くようになるまでは、それなりに苦労しています。
Gnuradioで複素化した信号を9857で変調する実験中。ちゃんとSSBになってる pic.twitter.com/vEiEVyTpZ1
— TT@北海道 (@edy555) 2014, 12月 26
変調信号をハンディトランシーバで受信してみました。電波は出さずにDDSからケーブルで20dBのATT経由でトランシーバに入れています。DDSで51.5MHzを生成していますが、第2ナイキストの192MHz-51.5MHz = 140.5MHzで受信できています。
<動画を置く予定>
ポイントですがアナログ信号経由ではDCが出せないので、DC分が必要なFM変調IQ信号の場合は変調後の信号を周波数をオフセットして出力しています。100Hz程度のオフセットでとりあえず動作できることを確認しました。
上の実験では変調IQ信号生成にGNURadioを使用しました。これは即座に簡単に使えるからですが、本来ならMCU内に変調器を実装したいところです。これも近日中に実装してみる予定です。うまくいけばソフトウェアによる送信機の実現は概ね目処が立つことになります。
またアナログ経由でIQ信号を与えましたが、本当ならUSB経由のデジタル信号として与えたいところです。ところがまだNucleoでUSBをうまく動作させることができていません。これについても原因追及中です。うまくいけばデジタルコントロール可能な汎用変調器として便利に使えるようになると思います。
リファレンス
- アナデバAD9857製品ページ https://www.analog.com/jp/rfif-components/direct-digital-synthesis-dds/ad9857/products/product.html
- STMicroelectronics Nucleo https://www.st.com/web/catalog/tools/FM116/SC959/SS1532/LN1847
- TI TLV320AIC3204 https://www.tij.co.jp/product/jp/tlv320aic3204
- p igmonさんのNucleoでI2S https://developer.mbed.org/users/p_igmon/code/i2s_test_sample/
- 前回の記事 直交変調DDS AD9857をNucleo F401から使ってみる
- 昔の記事 GNURadioとベクトルSG MG3660による変調実験