基板は、FPGA開発・学習ボードDE0-NanoのGPIO端子に取り付けて使用するスタイルです。(ねじ穴は合わないもののDE10-Nanoにも対応)AD9957のデジタルアップコンバータ機能を使いDE0-NanoからのIQ信号を任意の周波数に変換して出力できます。とりあえずの応用例として例のごとくFMトランスミッタを念頭に置いていますが、別の実験でも使えるよう出力ローパスフィルタを省略しました。
またAD9957の設定用としてAVRマイコンも付いていますので、シングルトーンモードであればDE0-Nanoなしにスタンドアロンで任意の周波数を生成することができます。
試作基板
試作した基板の回路構成
この基板は、DE0-NanoのGPIO端子からIQ波形を18ビットのパラレル信号を受け取り、AD9957内でアップサンプリング。デジタル処理でNCO波形にQAM変調を掛けることで、任意の周波数に周波数変換して14ビットD/Aコンバータで出力します。基板は1.6mm厚の4層、基板CADはDesignSpark PCB、製造依頼先はJLCPCBです。
AD9957のブロック図(データシートより)
試作基板回路図(QDUC部)
試作基板回路図(制御部)
試作基板回路図(電源部)
システムクロックの検討
音声信号のサンプルレート、IQ波形のサンプルレート、AD9957のシステムクロック周波数、PLL逓倍器の使用有無など検討事項は盛りだくさんです。FMステレオコンポジット信号処理を行う前提として、音声信号のサンプルレートはデジタルオーディオで馴染みのある192kHzを選びました。これをFPGA内で16倍にサンプルレート変換して3,072kHzでAD9957に渡します。
ところでFM放送周波数は76~90(95)MHzです。この周波数を直接生成するため、AD9957内部D/Aコンバータの動作クロック(システムクロック)は、少なくともその4倍以上にしたいところです。そのような周波数で位相雑音の低いクロックを用意するのは大変なので、AD9957内蔵のPLL逓倍器を使用することにします。その場合、基準クロックは60MHz以下という条件があり、49.152MHz(192kHz×16)としました。
PLL逓倍器にも動作条件があります。動作周波数は420MHzから1GHz、逓倍数は12から127倍です。さらにAD9957をQAM変調器モードで動作させる場合、IQ波形のサンプルレートからのサンプルレート変換比の上限は252です。これらの条件から、今回はシステムクロック737.28MHz(逓倍数15かつサンプルレート変換比240)としました。
PLL逓倍器の設計
AD9957 Evaluation Board向けのPLL Loop Filter Toolを使ってみました。周波数等の緒元を入れてループフィルタ部品の抵抗やコンデンサの値を選ぶとループフィルタのカットオフ周波数や位相余裕などが表示される便利ツールです。このツールによると位相余裕は45~60度が一般的だとメモがありましたが、カットオフ周波数については記述がありません。Webで調べたところわかりやすく解説したページを見つけました。これを参考にVCO周波数737.28MHzに換算した位相雑音をグラフにプロットしてみました。AD9957内蔵VCOの単体特性についてはデータシートに記載がありませんが、PLL使用時のものはグラフが載っています。2MHz付近の盛り上がりより高い周波数はVCOの単体の特性で低い周波数はPLLによって基準クロックの特性が見えているのかなと考えました。
AD9957の位相雑音(VCOの裸の特性はこれより悪いはず)
基準クロック TAITIEN OY-Uの位相雑音
これらの結果から、今回選定したTAITIEN OY-U発振器はほぼ全周波数にわたりAD9957内蔵PLLよりも位相雑音が低くみえます。これならカットオフ周波数を低くする必要もありません。まずは1MHz以上を目安にして設計することにしました。PLL Loop Filter Toolの画面を示します。
PLL Loop Filter Tool その1
PLL Loop Filter Tool その2
PLL Loop Filter Tool その3
電源の設計
AD9957の電源は、3.3Vデジタル、3.3Vアナログ、1.8Vデジタル、1.8Vアナログの4種類が必要です。類似のデバイスですがAD9910に関するWebページ(How to use DDS evaluation Board AD9910/PCBZ)によると、内蔵PLLを使用する場合、信号品質は1.8Vアナログ電源の品質に大きく影響を受けるとされる一方で、内蔵PLLを使用しない場合は、もっぱら基準クロックの品質で決まるそうです。今回は1.8Vデジタル電源をのぞき、各々にLDOレギュレータLP5907を使いました。さて、問題は1.8Vデジタル電源です。システムクロック1GHzのとき610mAも流れます。この1.8Vをリニアレギュレータで5Vから落とす場合、電力損失2Wと放熱器が必要になりそうです。大きな放熱器はコンパクトな基板には不釣り合いかと思い、電力変換効率のよいスイッチング式DC-DCコンバータを考えました。とはいえ、スイッチング式にノイズはつきものです。仮にノイズが影響したとして、FMの音声帯域に入り込むのは面白くないので、スイッチング周波数600kHzで1.8V出力の電力変換効率85%以上が見込めるムラタパワーソリューションズOKL-T/3-W5N-Cを選定しました。ところがDC-DCコンバータの漏れ磁束がPLLに影響を与えたためリニアレギュレータLM350Tを外付けすることで解決しました。(後述)
シングルトーンモードでの消費電流は、システムクロック786.432MHz、DDS出力73.92MHzのとき5Vで約0.29A。AD9957の表面温度は室温から13度上昇しました。
電源コネクタとして、マイクロUSBコネクタを使いました。USBバスパワー電流は標準で0.5Aですが、スマホ充電用などで1Aを超えるUSB電源アダプタを想定しています。そこで気になるのがマイクロUSBコネクタの電流容量です。今回は定格電流1.8Aで秋月でも扱いのあるヒロセZX62を使いました。さらに大電流のものとしてはWurth Electronicsに3A対応品があります。
AD9957をシングルトーンモードで動作させる
まずは動作確認のためにシングルトーンモードとしてCW波を出力させ信号品質を確認しました。ブロック図(シングルトーンモード)
AD9957のSPI通信
AD9957の初期設定は、ボード上のAVRマイコンATmega328からSPI通信で行います。コマンドは、4本の信号でシリアルポートバッファにいったん書き込み、さらにI/O_UPDATEピンをHにするとデータが内部レジスタに転送されます。レジスタのデータ長は16/32/48/64ビットなんですが、データシートではデータ長8ビットの例が書かれていて困惑します。結局、そのまま続けて送れば動作すると実験的に確認しました。不親切だなーと思いました。なお、この基板ではCS(とI/O_RESET)は常時L固定で動作させています。
ところで日本語版のデータシートはRev.Aで、肝心な説明がなかったり文章がわかりづらいことがあって、英語版Rev.Eを見たら情報が増えていた、ということに気がつきました。確かに、Revision History見ると、情報の追加、改訂がたくさん書かれています。どうも説明不足だなーと感じたら最新のデータシートをみるのが大切と感じました。
AD9957のシリアル制御インターフェース
AD9957レジスタ設定
周波数等の設定は複数のPROFILEレジスタに格納できますが、この基板ではPROFILE=0だけを使います。CFR1レジスタ 動作モード設定
CFR2レジスタ インターフェース関係の設定
CFR3レジスタ リファレンスクロック設定
Auxiliary DACレジスタ DACゲイン設定
Profile 0レジスタ シングルトーンモード設定
それから、REFCLK Input Divider Bypass時にREFCLK Input Divider ResetBを0にするとこれまた動作しなくなります。Bypass回路は、単なるセレクタではないのでしょう。
レジスタのデフォルト値にご注目
ノイズ・スプリアス対策
(1)LDOの発振
またやってしまいました。LDOレギュレータLP5907の発振です。データシートによると、出力に1uF以上のバイパスコンデンサを付けることになっています。今回、LDO出力に0.1uFを付け、貫通コンデンサを挟んで負荷付近に10uFをぶら下げる設計としましたが、この貫通コンデンサを入れたことで負荷の10uFが見えなくなり、バイパスコンデンサの所要容量を満たせなくなったため発振したようです。そこでC89を1uFに交換したら発振は止まりました。LDO発振によるスプリアス
発振した回路
LP5907標準使用例(入出力に1uFのバイパスコンデンサが必要)
ところで、発振箇所の特定のためにセミリジッドケーブルと貫通コンデンサを組み合わせた直流カット測定ツールをつくりました。スペアナに接続して、あちこち当てまくってノイズ源を特定します。つまらないものですが便利です。
スペアナ用 直流カット測定ツール
測定ツールの材料
(2)スイッチング式DC-DCコンバータのノイズ
PLL回路にスイッチング式DC-DCコンバータを使うのは初めてです。高周波出力にスイッチング周波数617kHzがばっちり乗っています。DC-DCコンバータモジュールのトランス付近にフェライトや金属(文鎮)を載せるとノイズ量がぴょこっと変化するので、原因はコイツに間違い有りません。DC-DCコンバータによるスプリアス(その1)
DC-DCコンバータによるスプリアス(その2)
ノイズの混入ルートとしては、DC-DCコンバータ出力または入力から流れ出るものと、トランスからの漏れ磁束が考えられます。まずは、望み薄かと思いつつ、モジュールの入出力に挿入されたフェライトビーズをインダクタに交換してみましたが、変化なしです。とすると漏れ磁束が内蔵PLLに影響を与えているに違いありません。磁束の遮蔽は難しいので物理的に離すしかなく部品追加等では対策が困難です。仕方なく、リニアレギュレータLM350Tを外付けして1.8Vを供給することで解決しました。
DC-DCコンバータ入出力にインダクタを入れてもダメ
外付け基板からデジタル1.8Vを供給して解決
DC-DCコンバータの使用NGと決めつけるのは簡単ですが、電源効率を考えると選択肢から外すのは勿体ないと思います。ノイズ量をあと20dB下げられれば使えるのではないでしょうか。後学のため、磁界プローブを製作してノイズ量を調べてみることにしました。セミリジッドケーブルをループ状に巻き、ループを構成するよう端末で芯線と外皮を接続しています。黄色い熱収縮チューブをかぶせるとそれらしい仕上がりになりました。直径27mmの小さなループですが、携帯電話の電波がたくさん入ってきます。
磁界プローブでノイズ調査
製作した磁界プローブ
DC-DCコンバータのノイズ
AD9957のノイズ
さて肝心なDC-DCコンバータのノイズですが、離隔45mmで-61dBmでした。これを20dB下げるには、単純に考えると100mmほど離隔を取れば良いことになります。でも基板サイズが100mm以下なのでそれはムリです。あるいは、磁束による起電力が小さくなるよう基板パターンを工夫することでしょうか。試作を重ねないと難しいアプローチだと思います。
(3)基準クロックの飛び込みと混変調
スペアナで広帯域のスプリアスを見たところ、基準クロックに関係する3次混変調が多数並びSFDR -59dBcとなっていました。そこでかねてから気になっていた、ループフィルタ付近を走る基準クロックのパターンを同軸ケーブルで分離するとSFDR -65dBcまで改善できました。
広帯域SFDR(対策前)
広帯域SFDR(対策後)
基準クロックのパターンを同軸ケーブルで分離
どうやらPLLに基準クロックが乗っていることがスプリアスの主因と思えます。そういえば基準クロックとPLL付近のアースはくっついていて、今さら分離することもできないので、外付け基板から基準クロックを供給してみましたが、変化はありませんでした。これ以上は打つ手なしです。
(4)DE0-nanoのノイズ
なかなか原因を掴めなかったものがこれです。DE0-Nanoのクロックモジュール50MHzと基準クロック49.152MHzの差848kHzが出力に混変調として現れていました。この基板では50MHzを使用していないのでアースや信号ラインに乗り移ってきたものが影響しているようです。こんなものまで影響するのか!?という思いです。外付けMCUで変調処理する場合など、AD9957と別のクロックを使う場合には注意が要ります。
#define DAC_CS 6
#define DAC_SCK 7
#define DAC_MISO 8
#define DAC_MOSI 9
#define DAC_UPDATE 10
#define DAC_REFLOCK 2
//#define VR1 A2
#define LED1 4
void setup() {
pinMode(DAC_RESET, OUTPUT);
pinMode(DAC_CS, OUTPUT);
pinMode(DAC_SCK, OUTPUT);
pinMode(DAC_MISO, INPUT);
pinMode(DAC_MOSI, OUTPUT);
pinMode(DAC_UPDATE, OUTPUT);
pinMode(DAC_REFLOCK, INPUT);
pinMode(LED1, OUTPUT);
AD9957_INIT();
}
void AD9957_INIT() {
digitalWrite(DAC_RESET, HIGH); // Master Reset
digitalWrite(DAC_UPDATE, LOW);
digitalWrite(DAC_CS, LOW);
digitalWrite(DAC_SCK, LOW);
digitalWrite(DAC_RESET, LOW);
// Control Function Register 1 (CFR1)
SPI_begin();
SPI_write(0x00);
SPI_send_data(0x01); // Single tone mode
// SPI_send_data(0x00); // QDUC mode
SPI_send_data(0x40);
SPI_send_data(0x00);
SPI_send_data(0x02);
SPI_end();
// Control Function Register 2 (CFR2)
SPI_begin();
SPI_write(0x01);
SPI_send_data(0x00);
SPI_send_data(0x00);
SPI_send_data(0x28);
SPI_send_data(0x20);
SPI_end();
// Control Function Register 3 (CFR3)
SPI_begin();
SPI_write(0x02);
SPI_send_data(0x0B); // VCO3
SPI_send_data(0x3F);
SPI_send_data(0xC1);
SPI_send_data(0x1E); // N=15
SPI_end();
// Auxiliary DAC
SPI_begin();
SPI_write(0x03);
SPI_send_data(0x00);
SPI_send_data(0x00);
SPI_send_data(0x00);
SPI_send_data(0x7F);
SPI_end();
// Profile<0> Register—Single Tone
// -- Amplitude Scale Factor 0000h
// -- Phase Offset Word 0000h
// -- Frequency Tuning Word 0x1D838E38 (85MHz/clk 737.28MHz)
// -- Frequency Tuning Word 0x22B8E38E (100MHz/clk 737.28MHz)
// -- Frequency Tuning Word 0x4571C71C (200MHz/clk 737.28MHz)
SPI_begin();
SPI_write(0x0E);
SPI_send_data(0x00);
SPI_send_data(0x00);
SPI_send_data(0x00);
SPI_send_data(0x00);
SPI_send_data(0x1D);
SPI_send_data(0x83);
SPI_send_data(0x8E);
SPI_send_data(0x38);
SPI_end();
}
void SPI_begin(void) {
digitalWrite(DAC_SCK, LOW);
}
void SPI_write(int reg_addr) {
int command_byte = (0x1F & reg_addr);
for (int n = 7; n >= 0; n--) {
if (bitRead(command_byte, n)) {
digitalWrite(DAC_MOSI, HIGH);
} else {
digitalWrite(DAC_MOSI, LOW);
}
digitalWrite(DAC_SCK, HIGH);
digitalWrite(DAC_SCK, LOW);
}
}
void SPI_read(int reg_addr) {
int command_byte = (0x1F & reg_addr) ^ 0x80;
for (int n = 7; n >= 0; n--) {
if (bitRead(command_byte, n)) {
digitalWrite(DAC_MOSI, HIGH);
} else {
digitalWrite(DAC_MOSI, LOW);
}
digitalWrite(DAC_SCK, HIGH);
digitalWrite(DAC_SCK, LOW);
}
}
void SPI_send_data(int val) {
for (int n = 7; n >= 0; n--) {
if (bitRead(val, n)) {
digitalWrite(DAC_MOSI, HIGH);
} else {
digitalWrite(DAC_MOSI, LOW);
}
digitalWrite(DAC_SCK, HIGH);
digitalWrite(DAC_SCK, LOW);
}
}
void SPI_end(void) {
digitalWrite(DAC_MOSI, LOW);
digitalWrite(DAC_UPDATE, HIGH);
digitalWrite(DAC_UPDATE, LOW);
}
void loop() {
if (digitalRead(DAC_REFLOCK)==1) {
digitalWrite(LED1, HIGH);
}
else {
digitalWrite(LED1, LOW);
}
}
スプリアス測定
データシートの参考値と比較して出力を85MHzにセットしたときのSFDRは4dBほど、100MHzでは10dBほど良くない結果となりました。出力85MHz(SPAN 20MHz)
出力85MHz(CENTER 200MHz, SPAN 400MHz)
出力100MHz(SPAN 20MHz)
出力100MHz(CENTER 200MHz, SPAN 400MHz)
Wideband SFDR参考値(データシートより)
まとめ
- 内蔵PLLは位相雑音がどうなのかと心配していましたが、スペアナで観測して見劣りするようなことはありませんでした。ただ、基準クロックの起因のスプリアスがSFDRの数値を押し下げています。さらに、DE0-Nanoのノイズの影響まで受ける始末で、部品レイアウトやパターンの配置をよく検討する必要があります。50MHz以下の基準クロックを使えるPLLは魅力的ですが、スプリアス面では手慣れた玄人向けかもしれません。
- DC-DCコンバータのスイッチングノイズは凄まじく、ノイズに敏感なPLLと基板上で同居させるのは課題があります。ただ、電源を別基板にするなど離隔をとったり、たとえばSi5338のようなフットプリントの小さなクロックジェネレータチップであれば影響の受け方は異なるのではと考えます。
- QDUC(直交変調)モードについては別記事で纏めたいと思います。
制御用Arduinoスケッチ
#define DAC_RESET 5#define DAC_CS 6
#define DAC_SCK 7
#define DAC_MISO 8
#define DAC_MOSI 9
#define DAC_UPDATE 10
#define DAC_REFLOCK 2
//#define VR1 A2
#define LED1 4
void setup() {
pinMode(DAC_RESET, OUTPUT);
pinMode(DAC_CS, OUTPUT);
pinMode(DAC_SCK, OUTPUT);
pinMode(DAC_MISO, INPUT);
pinMode(DAC_MOSI, OUTPUT);
pinMode(DAC_UPDATE, OUTPUT);
pinMode(DAC_REFLOCK, INPUT);
pinMode(LED1, OUTPUT);
AD9957_INIT();
}
void AD9957_INIT() {
digitalWrite(DAC_RESET, HIGH); // Master Reset
digitalWrite(DAC_UPDATE, LOW);
digitalWrite(DAC_CS, LOW);
digitalWrite(DAC_SCK, LOW);
digitalWrite(DAC_RESET, LOW);
// Control Function Register 1 (CFR1)
SPI_begin();
SPI_write(0x00);
SPI_send_data(0x01); // Single tone mode
// SPI_send_data(0x00); // QDUC mode
SPI_send_data(0x40);
SPI_send_data(0x00);
SPI_send_data(0x02);
SPI_end();
// Control Function Register 2 (CFR2)
SPI_begin();
SPI_write(0x01);
SPI_send_data(0x00);
SPI_send_data(0x00);
SPI_send_data(0x28);
SPI_send_data(0x20);
SPI_end();
// Control Function Register 3 (CFR3)
SPI_begin();
SPI_write(0x02);
SPI_send_data(0x0B); // VCO3
SPI_send_data(0x3F);
SPI_send_data(0xC1);
SPI_send_data(0x1E); // N=15
SPI_end();
// Auxiliary DAC
SPI_begin();
SPI_write(0x03);
SPI_send_data(0x00);
SPI_send_data(0x00);
SPI_send_data(0x00);
SPI_send_data(0x7F);
SPI_end();
// Profile<0> Register—Single Tone
// -- Amplitude Scale Factor 0000h
// -- Phase Offset Word 0000h
// -- Frequency Tuning Word 0x1D838E38 (85MHz/clk 737.28MHz)
// -- Frequency Tuning Word 0x22B8E38E (100MHz/clk 737.28MHz)
// -- Frequency Tuning Word 0x4571C71C (200MHz/clk 737.28MHz)
SPI_begin();
SPI_write(0x0E);
SPI_send_data(0x00);
SPI_send_data(0x00);
SPI_send_data(0x00);
SPI_send_data(0x00);
SPI_send_data(0x1D);
SPI_send_data(0x83);
SPI_send_data(0x8E);
SPI_send_data(0x38);
SPI_end();
}
void SPI_begin(void) {
digitalWrite(DAC_SCK, LOW);
}
void SPI_write(int reg_addr) {
int command_byte = (0x1F & reg_addr);
for (int n = 7; n >= 0; n--) {
if (bitRead(command_byte, n)) {
digitalWrite(DAC_MOSI, HIGH);
} else {
digitalWrite(DAC_MOSI, LOW);
}
digitalWrite(DAC_SCK, HIGH);
digitalWrite(DAC_SCK, LOW);
}
}
void SPI_read(int reg_addr) {
int command_byte = (0x1F & reg_addr) ^ 0x80;
for (int n = 7; n >= 0; n--) {
if (bitRead(command_byte, n)) {
digitalWrite(DAC_MOSI, HIGH);
} else {
digitalWrite(DAC_MOSI, LOW);
}
digitalWrite(DAC_SCK, HIGH);
digitalWrite(DAC_SCK, LOW);
}
}
void SPI_send_data(int val) {
for (int n = 7; n >= 0; n--) {
if (bitRead(val, n)) {
digitalWrite(DAC_MOSI, HIGH);
} else {
digitalWrite(DAC_MOSI, LOW);
}
digitalWrite(DAC_SCK, HIGH);
digitalWrite(DAC_SCK, LOW);
}
}
void SPI_end(void) {
digitalWrite(DAC_MOSI, LOW);
digitalWrite(DAC_UPDATE, HIGH);
digitalWrite(DAC_UPDATE, LOW);
}
void loop() {
if (digitalRead(DAC_REFLOCK)==1) {
digitalWrite(LED1, HIGH);
}
else {
digitalWrite(LED1, LOW);
}
}
0 件のコメント:
コメントを投稿