ESP32で500円3chプログラマブルオシレータ「Si5351A」を使ってみた


はじめに

作った回路の実験などで楽に使える信号源が欲しかったので
秋月電子で500円で買える3chのプログラマブルオシレータ「Si5351A」をESP32で使ってみた。
それの備忘録として。

※この記事は以下のサイトの内容を自分なりにかみ砕いた物となっております。詳細は以下のリンクをご参照ください。
3CHクロックジェネレータSi5351Aの実験

使用部材

3ch出力プログラマブル周波数ジェネレーターモジュール Si5351A使用
ESP32-DevKitC-32E ESP32-WROOM-32E開発ボード 4MB
・その他ブレッドボードやジャンパー線など

回路図

Si5351AはI2Cインターフェースで動くみたいなのでESP32のI2C制御pinに配線する。
ESP32のpinout(ピン割り当て)については以下のサイトのPin Layoutにある図がかなり分かりやすいので参考に

ESP32-DevKitC V4 Getting Started Guide
これを見るとGPIO22にWIRE_SCL、GPIO21にWIRE_SDAが割り当たっているのが分かる。

※上画像の回路図の「Si5351A」にはVDDが二つ記載されているが、正しくはSCLの上のピンがVDDO、CLKの上のピンがVDDとなる。
VDDにはコア電源を、VDDOには出力バッファ用の電源を繋がなければならないが、とりあえずESP32から3.3Vを繋げておけば問題ない。
今回買った「3ch出力プログラマブル周波数ジェネレーターモジュール」の回路図を見るとVDDとVDDOは基板上で繋がっていないので必ずVDD,VDDOの両方に3.3Vを給電すること。
また、バイパスコンデンサは基板上に既に0.1uFが実装されているので基板外で追加しなくても良い。

要するにとりあえず動かすには画像の通りにVDDとVDDOの両方にESP32の3.3Vピンを繋いておけば問題ないと思われる。

プログラム

とりあえず動作確認のために1チャンネル(CLK0)だけを使ってみる。
ここから先は先ほどの秋月電子のリンクからも閲覧できるSi5351Aのレジスタマップを見ながら進めていく。
Manually Generating an Si5351 Register Map


※レジスタマップとは
Si5351Aは0~255(8bit)まであるアドレス(Register)を持っており、各アドレスで違う機能を持っている。
操作したい機能を持ったアドレスに8bit幅で命令を出すことでその機能を使うことができる。
例えばレジスタマップのp.13に記載されているRegister 3. Output Enable Controlでは
各クロック出力ピンを使用するかしないかを決めることができる。
以下の画像を見るとResister 3.のD0~D7の8bit幅の命令内容が書いてある。

命令内容は「CLKx_OEB」「Output Disable for CLKx.」
要するにCLK0~7のクロック出力ピンを使うか使わないか命令を出すことが出来る。
機能の説明(Function)には
Where x = 0, 1, 2, 3, 4, 5, 6, 7
1:Disable CLKx output.
と記載されているので、各bitを0にするか1にするかで使う、使わないの命令を出せばいいことが分かる。
D0~D7の各bitに
今回使用するICはそもそもクロック出力ピンが3つしかないのでCLK0~CLK2までしか命令しても効果はないが、
同じSi5351シリーズにクロック出力ピンが8つある大容量タイプ(?)がある為、D3~D7はそれの制御用だと思われる。

今回は初期化の為にとりあえず全ての出力をOFF(Disable)にしたいので
D0~D7の全てを1にしたいので2bitでは「1111 1111」16進数に直すと「0xFF」となる。
これをResister 3.に命令すれば設定は完了。


プログラム本体はこちら
プログラムはほぼ参考元と同じで、周波数を変えたりコメントなどを追記した物です。

#include <Wire.h> //I2Cライブラリをインクルード

//Si5351のI2Cアドレスはどの環境でも2進数で0110 0000で固定されている。
//1b0110 0000は16進数で0x60
const byte Si5351_ADDR = 0x60;

void setup()
{
  Wire.begin(); // I2C通信開始.

  //CLK0の初期化とか
  Si5351_write(3, 0xFF);
  Si5351_write(16, 0x80);

  //秋月の取り扱い説明書にデフォルト10pFなのを8pfに変更すると記載されているので容量を変更
  Si5351_write(183, 0x92);

  //ここで具体的な周波数を決める
  PLLA_set();
  MS0_set();

  Si5351_write(177, 0xA0); //PLLAとPLLBのリセット
  Si5351_write(16, 0x4F); //CLC0の出力を8mAにパワーアップさせたりしてる。何故かは知らない
  Si5351_write(3, 0xFE); //Enable CLOCK0
}

void loop()
{
delay(10);
}

//I2C書き込み周りの関数化
void Si5351_write(byte Reg , byte Data)
{
  Wire.beginTransmission(Si5351_ADDR);
  Wire.write(Reg);
  Wire.write(Data);
  Wire.endTransmission();
}

void PLLA_set()
{
  //PLL分周設定
  //今回はPLL=400MHzに設定
  Si5351_write(26, 0); //MSNA_P3[15:8]
  Si5351_write(27, 1); //MSNA_P3[7:0]
  Si5351_write(28, 0x00); //MSNA_P1[17:16]
  Si5351_write(29, 0x06); //MSNA_P1[15:8]
  Si5351_write(30, 0x00); //MSNA_P1[7:0]
  Si5351_write(31, 0); //MSNA_P3[19:16]MSNA_P2[19:16]
  Si5351_write(32, 0); //MSNA_P2[15:8]
  Si5351_write(33, 0); //MSNA_P2[7:0]
}


void MS0_set() {
  //CLK出力設定
  //今回は250KHzに設定
  Si5351_write(42, 0); //MS0_P3[15:8]
  Si5351_write(43, 1); //MS0_P3[7:0]
  Si5351_write(44, 0x03); //MS0_P1[17:16]
  Si5351_write(45, 0x20); //MS0_P1[15:8]
  Si5351_write(46, 0x80); //MS0_P1[7:0]
  Si5351_write(47, 0); //MS0_P3[19:16]MS0_P2[19:16]
  Si5351_write(48, 0); //MS0_P2[15:8]
  Si5351_write(49, 0); //MS0_P2[7:0]
}

解説など

・Si5351_write(183, 0x92);
秋月の取り扱い説明書にデフォルト10pFなのを8pfに変更すると記載されているので容量を変更
参考サイトには0x80を書き込めと記載されているが、レジスタマップ183には
Bits 5:0 should be written to 010010b.って書いてあるし8pFの Bit 7:8の10を合わせて
0b10010010 → 0x92になる気がする(?)

・void Si5351_write(byte Reg , byte Data);
I2C書き込み周りの関数化
詳しくは
Arduino 日本語リファレンス
または
garretlab
などを参考に

・void PLLA_set()
・void MS0_set()
具体的な周波数の設定。
レジスタマップのP3,P6に書いてある。
設定の変数であるa,b,cは値の範囲が決まっているので注意しよう。
値の範囲は秋月電子のリンクに取り扱い説明書があるのでそれを参考にすると分かりやすい。

計算が複雑でかなり面倒なのでExcelシートを作って目標の周波数を計算させた方が良さそう。
自分は雑だけどこんな感じでとりあえず作った。
青が250kHZ設定の所

実際に使ってみる

手持ちのオシロのAnalogDiscovery2を使って実際に250kHzの出力を測ってみる。
赤線部、1/Δxに周波数248.5kHzが書いてある。
設定値は249.2kHzだったのでまぁこんなものだと思う。

1Mhzだとこんな感じ
周波数も出てるし出てる方形波も問題なさそうに見える。

5MHzにすると周波数自体は出ているが、かなり怪しい波形になる。
出力周波数2.5kHz~200MHzって書いてあったのに5MHzでもう限界?って思ったが
使ってるAnalogDiscovery2の帯域が30MHzまでしか無いので多分これはSi5351A側
ではなく、使っているオシロ側の限界なのだろう。
この辺は良いオシロもっていれば綺麗な方形波が出ていたのかも知れない。

今後やること

とりあえず使える事が分かったので、残りの2chも使えるようにする。
また、計算式をいい感じにプログラムに落とし込んで、エンコーダを手回しでリニアに可変できるオシレータに出来ると色々使いやすくて良いと思った。