M5Stackでプログラマブル周波数ジェネレーターモジュールを作った

# はじめに

今回は前に作成した
[ESP32で500円3chプログラマブルオシレータ「Si5351A」を使ってみた](https://qiita.com/Konbanwa11/items/fe10430e0b5192d691e4)
これをM5stackに組み込んで使いやすくしました。

基板は毎度のことながらJLCPCBにお願いしました。
今回は4層基板にしたのにも関わらず2ドルで作ってもらえました。
相変わらず安くて驚きます。

JLCPCBのサイトはこちら！

https://jlcpcb.com/HAR

JLCPCBは新規ユーザー向けに54ドルのクーポンを配っているのでみなさんも是非作ってみてください！

https://jlcpcb.com/JPV

今回使用したフリーのEDAソフト「kiCad」もJLCPCBはサポートしているみたいです。

https://jlcpcb.com/RGE/kicadjp

特に最近はkiCadのJLCPCBプラグインも出たみたいで、BOMも一発で出せてしまうみたいで、どんどん便利になっています。

# ハードウェア

まず、回路図を作成する。
Si5351Aに必要な3.3VはM5stackの3.3V出力ピンから出せるが、せっかくなら5VからLDOで3.3Vに降圧し、なるべくノイズが乗っていない高品質な波形を目指す。
今回は手持ちの秋月で売っているLDOを使用した。
[低損失ＣＭＯＳ可変レギュレーター　６００ｍＡ　ＴＰＳ７４００１ＳＦ５　（５個入）](https://akizukidenshi.com/catalog/g/gI-17396/)
同価格帯で同フットプリントだとこっちの方がローノイズっぽい。
出力電圧は100mAと低めだが、今回の用途では十分だと思われる。
[ローノイズ低飽和型レギュレーター　３．３Ｖ１００ｍＡ　ＮＪＭ２８６３Ｆ３３　（１０個入）](https://akizukidenshi.com/catalog/g/gI-05579/)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/867623/da84601b-199b-2968-a5a7-44e72860effe.png)

今回はSi5351Aのデータシートを見るとどうやら50Ωで送った方が良さそうなので4層基板にすることにした。
(データシート P.25参照)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/867623/936119d8-7994-8cc3-010b-cbc8ac22ec99.png)

JLCPCBはインピーダンスコントロールが必要な基板は↓のサイトで計算して板材に適した線幅を出してくれる。
https://cart.jlcpcb.com/impedanceCalculation
詳細なJLCPCBでのインピーダンスコントロールのやり方は前に投稿したこの記事を参照してください。
[JLCPCBでのインピーダンスコントロールのやり方](https://qiita.com/Konbanwa11/items/f61fad957eb694204b3a)

信号を送るケーブルも50Ωの同軸を使用しないと意味がないのでコネクタはヒロセのU.FLコネクタにした。
後述するが普通のSMAコネクタは使用できなかったので秋月で入手しやすく安いこれにした。
[Ｕ．ＦＬコネクタ　Ｕ．ＦＬ－Ｒ－ＳＭＴ－１　（４個入）](https://akizukidenshi.com/catalog/g/gC-12225/)

ちなみにU.FLからSMAへの変換は同じく秋月に売っているこれが安くて使いやすかった。
[ＳＭＡ－Ｊ⇔ＩＰＥＸ（ＩＰＸ／Ｕ．ＦＬ）変換ケーブル（１２０ｍｍ）　テフロン同軸ケーブル](https://akizukidenshi.com/catalog/g/gC-12225/)

今回作成する基板はM5stackの基板作成テンプレートがgithubにあったので使用させて頂きました。
以下を参照。
[KiCad6-Environment](https://github.com/botanicfields/KiCad6-Environment)

完成品は以下の通り。
ピンアサインを間違えてパターンカット、ジャンパだらけの基板になってしまったが、次に生かせばヨシ！とする。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/867623/6c77bbac-5b1d-2ea1-daf5-1ed7a2739c15.png)
![IMG_2533.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/867623/276d0606-a148-ed16-5198-3d79f7aa64a7.jpeg)
![IMG_2534.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/867623/9382b6e5-daf3-5d17-c358-d22efa6d4b80.jpeg)
![IMG_2535.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/867623/4fbb57be-a231-46fe-df9e-a4b5b65c69b5.jpeg)
基板の外側の枠？は同寸法のM5プロトモジュールを使用する。
[M5Stack用プロトモジュール [M001]](https://www.switch-science.com/products/3650)
このプロトモジュールのアミアミの部分をニッパーで切って同軸ケーブルを横から出す。
![IMG_2536.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/867623/2e9ab2a1-d40a-3019-b6a0-ddec18a05ef4.jpeg)


実際に250kHzで動かしてみる。
3ch同時に出力出来るが、部屋にあるオシロが2chまでしか見れないのでとりあえず2chで。
![IMG_2531.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/867623/9620bcf7-044c-ec0e-b73e-8e013a59810b.jpeg)
ch間の位相差が800kHzくらいあるが1chでの運用しか考えていないのでいいでしょう。
Si5351Aは波形のスイープとか出来るっぽい？ので上手くレジスタ設定したら合わせられるかも。

# プログラム

プログラムは以下の通り。
基本は前に書いた記事↓

https://qiita.com/Konbanwa11/items/fe10430e0b5192d691e4

前に書いた記事で参照させて頂いた記事↓

http://jh7ubc.web.fc2.com/arduino/Si5351A.html

これをM5stack用に書き加えた物。
周波数は250kHzのみで他の周波数にする設定を入れていないので各自で適当にカスタマイズしてください。
ほぼUIはgithubにあったものに微調整を加えた物だがどうしても参照したURLが見つからない…

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

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

TFT_eSprite sprite = TFT_eSprite(&M5.Lcd);

//I2C書き込み周りの関数化
void Si5351_write(byte Reg , byte Data)
{
  Wire.beginTransmission(Si5351_ADDR);
  Wire.write(Reg);
  Wire.write(Data);
  Wire.endTransmission();
  byte error = 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() {
  //CLK0出力設定
  //今回は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]
}

void MS1_set() {
  //CLK1出力設定
  //今回は250KHzに設定
  Si5351_write(50, 0); //MS1_P3[15:8]
  Si5351_write(51, 1); //MS2_P3[7:0]
  Si5351_write(52, 0x03); //MS01_P1[17:16]
  Si5351_write(53, 0x20); //MS1_P1[15:8]
  Si5351_write(54, 0x80); //MS1_P1[7:0]
  Si5351_write(55, 0); //MS1_P3[19:16]MS0_P2[19:16]
  Si5351_write(56, 0); //MS1_P2[15:8]
  Si5351_write(57, 0); //MS1_P2[7:0]
}

void MS2_set() {
  //CLK2出力設定
  //今回は250KHzに設定
  Si5351_write(58, 0); //MS1_P3[15:8]
  Si5351_write(59, 1); //MS2_P3[7:0]
  Si5351_write(60, 0x03); //MS01_P1[17:16]
  Si5351_write(61, 0x20); //MS1_P1[15:8]
  Si5351_write(62, 0x80); //MS1_P1[7:0]
  Si5351_write(63, 0); //MS1_P3[19:16]MS0_P2[19:16]
  Si5351_write(64, 0); //MS1_P2[15:8]
  Si5351_write(65, 0); //MS1_P2[7:0]
}

void freqDisp(String Unit)
{
  M5.Lcd.fillRect(0, 0, 320, 170, WHITE);
  M5.Lcd.setTextSize(4);
  M5.Lcd.setCursor(230, 25);
  M5.Lcd.setTextColor(BLACK);
  M5.Lcd.print(Unit);
  M5.Lcd.setCursor(230, 75);
  M5.Lcd.setTextColor(BLACK);
  M5.Lcd.print(Unit);
  M5.Lcd.setCursor(230, 125);
  M5.Lcd.setTextColor(BLACK);
  M5.Lcd.print(Unit);
}

//左ボタン割り込み
void IRAM_ATTR onLeftButton()
{
}

//真ん中ボタン割り込み
void IRAM_ATTR onMiddleButton()
{
}

//右ボタン割り込み
void IRAM_ATTR onRightButton()
{
}

void setup()
{
  M5.begin(1, 0, 0, 1);
  Serial.begin(115200);
  delay(10);
  Wire.begin(); // I2C通信開始.
  delay(10);

  Wire.beginTransmission(Si5351_ADDR);

  //I2C接続が成功したかどうか
  byte error = Wire.endTransmission();
  if (error == 0) {
    Serial.println("I2C connection success");
  } else {
    Serial.println("I2C connection failed");
  }

    // 左ボタンの割込み
  pinMode(GPIO_NUM_39, INPUT);
  attachInterrupt(GPIO_NUM_39, onLeftButton, FALLING);

  // 真ん中ボタンの割込み
  pinMode(GPIO_NUM_38, INPUT);
  attachInterrupt(GPIO_NUM_38, onMiddleButton, FALLING);

  // 右ボタンの割込み
  pinMode(GPIO_NUM_37, INPUT);
  attachInterrupt(GPIO_NUM_37, onRightButton, FALLING);

  //LCD初期化
  M5.Lcd.fillScreen(WHITE);
  M5.Lcd.setTextColor(BLACK);
  M5.Lcd.drawFastHLine(0,170,320,BLACK);

  // M5スピーカーミュート(pin25を使用する)
  M5.Speaker.begin();
  M5.Speaker.mute();

  //左ボタン表記
  M5.Lcd.drawRoundRect(15,180,90,50,20,BLACK);
  M5.Lcd.setCursor(34,192,1);
  M5.Lcd.setTextSize(3);
  M5.Lcd.setTextColor(BLACK);
  M5.Lcd.print("xxx");

  //真ん中ボタン表記
  M5.Lcd.drawRoundRect(115,180,90,50,20,BLACK);
  M5.Lcd.setCursor(135,192,1);
  M5.Lcd.setTextSize(3);
  M5.Lcd.setTextColor(BLACK);
  M5.Lcd.print("xxx");

  //右ボタン表記
  M5.Lcd.drawRoundRect(215,180,90,50,20,BLACK);
  M5.Lcd.setTextSize(3);
  M5.Lcd.setCursor(234,192,1);
  M5.Lcd.setTextColor(BLACK);
  M5.Lcd.print("xxx");

  freqDisp("kHz");

  //CLK0,1,2の初期化
  Si5351_write(3, 0xFF);
  Si5351_write(16, 0x80);
  Si5351_write(17, 0x80);
  Si5351_write(18, 0x80);

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

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

  Si5351_write(177, 0xA0); //PLLAとPLLBのリセット
  Si5351_write(16, 0x4F); //CLC0の出力を8mA
  Si5351_write(17, 0x4F); //CLC1の出力を8mA
  Si5351_write(18, 0x4F); //CLC2の出力を8mA
  //Si5351_write(3, 0xFD); //Enable CLOCK0
  //Si5351_write(3, 0xFD); //Enable CLOCK1
  //Si5351_write(3, 0xFD); //Enable CLOCK2
  Si5351_write(3, 0xF8); //Enable CLOCK0,1,2
}

void loop()
{
  // スプライト準備
  sprite.createSprite(230, 170);
  sprite.fillScreen(WHITE);

  // ch1
  sprite.setTextSize(5);
  sprite.setTextColor(BLACK);
  sprite.drawRightString("250", 220, 19, 1);

  // ch2
  sprite.setTextSize(5);
  sprite.setTextColor(BLACK);
  sprite.drawRightString("250", 220, 69, 1);

  // ch3
  sprite.setTextSize(5);
  sprite.setTextColor(BLACK);
  sprite.drawRightString("250", 220, 119, 1);

  // スプライトを出力
  sprite.pushSprite(0, 0);
}
```

# 最後に
JLCPCBへの注文の仕方や、KiCad6での製造データ作成方法は他の記事に書いているので参考にしてみて下さい。
[JLCPCBで基板を作ろう[KiCad6編]](https://qiita.com/Konbanwa11/items/4e1d14b7cdc2282063fb)
[JLCPCBで４層基板を作った](https://qiita.com/Konbanwa11/items/f44084b8963d0147c9f6)