Go言語でMCU向けのオブジェクトを生成できるTinyGoは便利です。テキトーに書けば「動いてしまう」のでとってもお楽。しかし古色蒼然たる「ベアメタル派」としてはMCUがどんな設定で動いているのだか知らないと気持ちが悪いです。それに後で周辺回路を直接制御もしたいです。今回はMCUの根っこ、発振回りの設定を確認。
※「AT SAMの部屋」 投稿順indexはこちら
今回ターゲットは、Arm Cortex-M0+コアのSeeeduino XIAOボードです。搭載MCUは、Microchip社のATSAMD21G18です。製品ページは以下に。データシートは以下からダウンロードできると思います。
ATSAMD21G18 | Microchip Technology
さて今回TinyGoでオブジェクトを作ったときの「多分デフォルト」の設定値を調べてみるのは発振器の設定です。発振なしにはマイコンは動きません。マイコンの根っこのハードウエアであります。
調べ方としてはブートから丹念にソースを読んでいくというのも手ですが、不埒なベアメタル派としては「動いているデバイスに聞く」方がお楽。
ATSAMシリーズのマイコンは近代的なマイコンの通例にもれず、内蔵、外付けの各種オシレータに対応しています。まずは内蔵オシレータを列挙します。
-
- OSCULP32K
- OSC32K
- OSC8M
3つも搭載しておりますな。最初のOSCULP32KのULPはUltra Low Powerだと思います。超低消費電力の内蔵32K(32.768kHz)オシレータです。常に発振しつづけ、パワーオン後の初期化やスタンバイとかスリープなどといった局面で働く「最後の砦(いや最初の砦か)」的な発振器みたいです。知らんけど。
これに対して後の2つOSC32KとOSC8Mの2個は内蔵オシレータですが、デフォルトはディセーブルです。許可しないと動きません。また、必要に応じて止めることもできるので、通常の周辺回路の制御には便利です。
上記の内蔵発振器に対して外付けXTAL(水晶振動子)または外部クロックソースをつかうものが2つあります。上記の内蔵オシレータにはキャリブレーション機能もついているのですが、基本がRC発振回路だと思うので精度的にはちと低い(具体的には、32Kの内蔵発振を時計に使うと残念な結果になる?)はずです。高精度が必要な場合外付けXOSCにデバイス接続してくれ、って感じじゃないかと思います。
-
- XOSC32K
- XOSC
低速32.768kHz向けと高速(最大32MHz)の2系統があります。しかしXiaoボードの回路図を見るとXOSCには何もつながってないみたいです。XOSC32Kの方には外付け水晶振動子が接続されてました。よって設定すれば使用可能の筈。
このマイコンの場合USBが使えるのでUSB用の48MHzクロックは必須です。そのため、上記の発信源から最低でも48MHzを生成するものが必要です。そのような「速い」クロックを生成するためにDFFLとFDPLLと2つのハードウエアが存在します。
-
- DFFL48M
- FDPLL96M
第1のDFFL48Mは Digital Frequency Locked Loopです。普通のPLLではロックできないような参照信号からも「周波数で」ロックできるもの。懐が深い(許容範囲が広い)んでないかい。以下のページが絵入りで分かり易い気がしました(個人の感想です。)
How a Frequency Locked Loop (FLL) Works
名前に48Mと入っていますが、周辺回路のUSBを使わなければ48MHz設定以外でも動作するのではないかと想像します(確かめてません。)
第2のFDPLL96MはPLLですが、小数点数で分周比を設定してロックする周波数を調整できる Fractional Digital Phase-Locked Loop らしいです。
SYSCTRL
今回使用のATSAMD21G18に限らず、ATSAMマイコンは多数品種があるといっても制御レジスタなどは統一感のある構成になっています。一つ分かれば以下同文とな。ホントか?
さて発振器関係の制御はSYSCTRLというペリフェラル・モジュールが制御しています。上記の発振器が動いているか否かというステータスは以下のレジスタに「大体」まとまっています。
PCLKSR、Power and Clocks Status
これにアクセスするために、TinyGoの srcフォルダ配下にある以下のファイルをまず参照してみました。
atsamd21g18a.go
このファイルの冒頭から1行引用させていただくと
// Automatically generated file. DO NOT EDIT.
だそうです。自動生成されているファイルなので、多分ほとんどの(もしかすると全ての)ハードウエアレジスタが列挙されているだけでなく、PCLKSRなどは各ビットを個別にSet/Getするための関数まで用意されていました。しかしね、逆に個別ビットの操作はチト怪しいです。手元のデータシートを読むとPCLKSRレジスタはReadOnlyに見えるのですが、Setするための関数も定義してあり。私の勘違いか自動生成ツールの勇み足か。まあ、怪しいところは使わないでおきます。レジスタ名でアクセスすることはできそうなので、レジスタレベルで Set() Get()するのが確実そうです。
実験に使用したGo言語ソース
今回実験に使用したソースはごく短い以下のものです。PCLKSRレジスタを読み出して、各オシレータの「稼働状況」をUSBシリアル経由で仮想端末に報告するものです。こんな感じ。
package main import ( "device/sam" "fmt" "time" ) func main() { for { pclksr := sam.SYSCTRL.PCLKSR.Get() fmt.Printf ("PCLKSR: %08x\n", pclksr) fmt.Println("XOSCRDY: ", pclksr & 0x00000001) fmt.Println("XOSC32KRDY: ", (pclksr & 0x00000002)>>1) fmt.Println("OSC32KRDY: ", (pclksr & 0x00000004)>>2) fmt.Println("OSC8MRDY: ", (pclksr & 0x00000008)>>3) fmt.Printf ("DFLL: %02x\n", (pclksr & 0x000001F0)>>4) fmt.Printf ("DPLL: %02x\n", (pclksr & 0x00038000)>>15) time.Sleep(5 * time.Second) } }
ビルドして実行
ビルドと書き込みはWindowsPC上の TinyGo で行いました。USBでXiaoボードを接続したら、後は以下でビルド後オブジェクトが書き込まれてスタートします。
$ tinygo flash -target=xiao xiao_PCLKSR.go
Teratermで接続して結果を見ているところを冒頭のアイキャッチ画像に掲げましたが、結果は以下の通りです。
PCLKSR: 00005adc XOSCRDY: 0 XOSC32KRDY: 0 OSC32KRDY: 1 OSC8MRDY: 1 DFLL: 0d DPLL: 00
XOSCは動いてません。先ほど述べたとおりXOSCには何もつながっていないので当然か。XOSC32Kも動いてません。こちらには外付けの水晶振動子が付いているので、ちゃんと設定すれば動くのではないかと思いますケド(後でやってみろよ、自分。)
一方内蔵OSC32Kと内蔵OSC8Mは生きてます。今はこちらで動いておると。DFLL(48M)は参照クロック(このソースはまた後で確かめます)生きていて、DFLL自体も動作中です。ロックも外れてないようです。OKだね。ホントか。
一方DPLLの方は動作してないということで良いですか?
今回、発振器について分かった(つもり)なので、次回はクロックジェネレータですな。ATSAMマイコンの豊富な周辺回路を動かすためには、それが設定できないと。野望が広がるです。