お手軽指向などといいつつ、基本面倒なことは後回し。以前に調べておけばよかったですが、今になってちょっと「速い」クロックが欲しい、ということで初期設定後のWio Terminal上で、どのようなクロック周波数が即使えるのか調べておくことにいたしました。前々回の周波数メータの応用であります。
※「IoT何をいまさら」投稿順Indexはこちら
Arm Cortex M4F をコアにいただく、Microchip社のATSAMD51P19A搭載のWio Terminalを使って、SAMD51マイコンの周辺機能を「出来合いのAPIをなるべく使わず、直接」プログラムしてその機能を勉強してきております。するとほとんどのペリフェラルで最初に行なわないとならないのが、供給するクロックの設定であります。
過去数回、外部クロックを内部に供給して周辺回路を動かすというパターンをやってきました。内部クロック源は参照用に「遅い」32kHzクロック以外は使ってきませんでした。ここにきてちょっと速いMHz級の内部クロックを使いたくなりました。そこで稼働中の、
クロックジェネレータのx番がyMHz
という基本的なリストが知りたくなりました、ようやくね。当然、関係するソースコードを読んで行けば分かる「事実」ではあります。しかし、目の前に現物があります。現物に聞くのがお手軽かつ間違いもない(丹念にソース読むのがメンドイだけじゃん。)ということで前々回の周波数カウンタをクロックジェネレータ群に「端から適用」して確認してみました。
クロックジェネレータ、GCLKの復習
周辺回路各部で使われるクロックはGCLK(Generic Clock Controller)内のクロックジェネレータで生成されたものが分配されます。以前調べたのは以下でした。(なお、実機確認用オブジェクトコードは、VS Code + PlatformIOを使用し、PlatformIOからターゲットボードをSeeduino Wio Terminal、フレームワークをArduinoとして作成したプロジェクトにより生成しています。)
-
- ハードウエア上クロックジェネレータは12本存在する
- main()起動前の初期化により6本のクロックジェネレータが割り当て済で稼働している
- 残り6本のクロックジェネレータは未使用。勝手に使えそうだが、クロックを外部に入出力しようとすると使えるのは2本だけである
過去投稿では勝手に使えて外部入出力ができる2本を活用していた、というわけです。それでもクロックジェネレータは4本も「余って」いるので別途勝手に設定して使っても良いのですが有限なリソースをモッタイない。システム側で6本も設定済なので、適当なものがあれば「便乗」させてもらってもいいじゃないか、という発想であります。
クロック周波数の確認関数
以下に示す関数は、クロックジェネレータの番号(0から11)を引数にとり、それぞれに設定されている発振器と、クロックジェネレータがイネーブルか否かを示したうえで、前々回のFREQMを使って周波数を実測するものです。計測用の参照クロックとしてXOSC32の32.768kHzクロックを使っています。
void checkGCLKF(int gnum) { int measuredV = 0; gnum &= 0xF; uint16_t src = (uint16_t)GCLK->GENCTRL[gnum].bit.SRC; uint16_t ge = (uint16_t)GCLK->GENCTRL[gnum].bit.GENEN; Serial.printf("GENCTRL[%d].src = %d ge = %d\r\n", gnum, src, ge); int timeoutCount = 0; GCLK->PCHCTRL[5].reg = (0x40 | gnum); //GCLK_FREQM_MSR <= Generator gnum GCLK->PCHCTRL[6].reg = 0x47; //GCLK_FREQM_REF <= Generator 7(XOSC32K) MCLK->APBAMASK.bit.FREQM_ = 1; // enable APB CLOCK FREQM->CFGA.bit.REFNUM = 128; // measurement time = 1/256 second FREQM->INTENCLR.bit.DONE = 1; // disable FREQM interrupt FREQM->CTRLA.bit.ENABLE = 1; // enable FREQM while (FREQM->SYNCBUSY.bit.ENABLE == 1) { if (timeoutCount++ > 100) break; } //Sync Busy startFREQM(); measuredV = readFREQM(); int freq = measuredV*FREQMREFFREQ/FREQMREFNUM; Serial.printf("FREQ SRC=GEN%d FREQM=%d (%d.%-3d[kHz])\r\n", gnum, measuredV, freq/1000, freq%1000); }
上記の関数にシステムが使っているジェネレータである、0から5までを引数として与えた結果が以下です。
GENCTRL[0].src = 7 ge = 1 FREQ SRC=GEN0 FREQM=469587 (120214.272[kHz]) GENCTRL[1].src = 6 ge = 1 FREQ SRC=GEN1 FREQM=187832 (48084.992[kHz]) GENCTRL[2].src = 8 ge = 1 FREQ SRC=GEN2 FREQM=391340 (100183.40 [kHz]) GENCTRL[3].src = 5 ge = 1 FREQ SRC=GEN3 FREQM=127 (32.512[kHz]) GENCTRL[4].src = 6 ge = 1 FREQ SRC=GEN4 FREQM=46962 (12022.272[kHz]) GENCTRL[5].src = 6 ge = 1 FREQ SRC=GEN5 FREQM=3913 (1001.728[kHz])
結果のまとめ
上記の生の出力では見ずらいので、その結果を手動にて表にしたものが以下です。
GEN# | OSC | FREQ[MHz] |
---|---|---|
0 | DPLL0 | 120 |
1 | DFLL | 48 |
2 | DPLL1 | 100 |
3 | XOSC32 | — |
4 | DFLL | 12 |
5 | DFLL | 1 |
GEN#はGCLK内のクロックジェネレータ番号です。OSCはクロックジェネレータの入力に接続されている発振器です。そしてFREQ[MHz]は、当方独断にて測定値を「丸めた」クロック周波数[MHz]です。FREQMによる周波数測定は実測なので毎回微妙に異なる結果が得られるうえに32.765kHz基準です。独断で「だいたいそうであろう」数字にしてしまいました。覚えやすいから。まあ、細かいところが必要だったらまた考えるということで(いい加減な。)
なお、同じOSC源に接続していても、クロックジェネレータ側の分周の設定などにより、クロックジェネレータからの出力クロックの周波数は異なります。
こうしてみると、使えそうな周波数が一通りある感じ。当然か。寄生虫路線でもOKでしょう。それでよいのか。