IoT何をいまさら(88) Wio Terminal、SAMD51周波数メータを使う

Joseph Halfmoon

昨日ラズパイPico(RP2040)の周波数カウンタというものを使ってみました。同様な機能はSAMD51にも備わっています。こちらSAMD51での呼び方は Frequency Meter(FREQM)です。これを使い、外部端子から入力した信号の周波数を計測してみました。設定と適用の限界を見極めておれば、便利な機能であります。

実験のターゲットデバイスは SeeedStudio社のWio Terminal でVS Code + PlatformIOを開発環境とし、Arduinoプラットフォーム利用です。しかし、今回も実験対象の周辺回路を操作する部分ではArduinoの「高水準」な関数のお世話にはならず、直接SAMD51のハードウエア・レジスタを直接操作して動作を確認していきたいと思います。

頼りとするのは Microchip ATSAM51P19A からダウンロード可能なSAMD51のデータシートであります。

前回、SAMD51のタイマを外部クロックで動作させました。今回は、その時に設定した外部クロック入力を流用させていただきます。端子的には、Wio Terminal背面のRaspberry Pi互換端子のGPIO5番です。

SAMD51のFREQM

ラズパイPicoのFrequency Counter同様、SAMD51のFrequency Meterも、「いまどんな周波数で動作しているのかしら?」と確かめたくなったときに、内部のシステムクロックでも、外部信号でもその周波数を測定できる専用カウンタです。原理は簡単で、周波数が既知の参照クロック(REFクロック)の設定したサイクル数期間中、被測定信号のクロック数を数えるハードウエアです。被測定信号のクロック数を、設定の参照クロック数で割って、参照クロックの周波数を乗ずればお答えが出る、という塩梅。

今回は参照クロックとして外部32kHzのオシレータ(XOSC32)の32.768kHzクロックを使います(前々回は常に動作している内蔵32kHzクロックを測定してみましたが、外部のクリスタルが動作しているなら、その方が精度がよいです。)

実験としては以下のような設定です。

  1. XOSC32の32.768kHzクロックをGCLKのクロックジェネレータ7番に供給し、背面GPIO6から出力させておく(REFクロックの実測確認用)
  2. クロックジェネレータ7番の出力をFREQMのREFクロックに指定
  3. 測定期間はREFクロック128発分(256分の1秒期間)
  4. 背面GPIO5へ波形発生器を接続し、各種周波数の方形波(デューティ50%)を入力する。
  5. GPIO5番はクロックジェネレータ6番に接続、分周なし、6番の出力をFREQMの被測定クロックに指定

確認用にGPIO5番と6番をオシロでみているところがこちら。黄色が被測定クロック、青がREFクロック。

FREQMwaveform

FREQMの初期化

以下の初期化コードで行っているのは以下のような操作です。

  1. REFクロックと非測定クロックのソースを設定
  2. FREQMブロックへのAPBバスクロックを許可(デフォルトでは不許可なので)
  3. 参照クロックの測定期間として128クロック設定
  4. 割り込みは使用しないので念のため禁止
  5. FREQMの動作を許可
  6. 許可後「クロック同期」の期間を確保
void enableFREQM() {
  int timeoutCount = 0;
  Gclk* gclk = (Gclk*)GCLK;
  gclk->PCHCTRL[5].reg = 0x46; //GCLK_FREQM_MSR <= Generator 6(PB12 input)
  gclk->PCHCTRL[6].reg = 0x47; //GCLK_FREQM_REF <= Generator 7(XOSC32K)
  Mclk* mclk = (Mclk*)MCLK;
  mclk->APBAMASK.bit.FREQM_ = 1;  // enable APB CLOCK
  Freqm* freqm = (Freqm*)FREQM;
  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

測定対象によってクロックソースを変更したり、測定期間を変えたりすれば所望の測定ができそうです。今回は中途半端にREFクロック128発としましたが、最大255まで設定可能です。長くする方が測定時間はかかるけれども精度は良くなるはず。

計測スタートと値の読み取り

計測スタートは開始ビットを立てるだけです。これによりREFクロックの所定期間の測定が始まります。

カウントの終了後、カウンタ値を読みます。今回、終了確認には割り込みをつかっていないので、ポーリングする必要があります。FREQMのカウント中でBUSYとなるフラグがあるのでそれが下がるまで待ちます。以下のコードでは念のためタイムアウトも監視していますが、キメウチの値なので測定期間を変えたならば要変更です。被測定クロックのカウントは24ビットのカウンタなのでそうそうあふれるとも思われませんが、一応カウンタのオーバーフローも確認しています。

void startFREQM() {
  Freqm* freqm = (Freqm*)FREQM;
  freqm->CTRLB.bit.START = 1; // start FREQM
}

int readFREQM() {
  int timeoutCount = 0;
  Freqm* freqm = (Freqm*)FREQM;
  while (freqm->STATUS.bit.BUSY == 1) {
    if (timeoutCount++ > 1000000) return -1;
  }
  if (freqm->STATUS.bit.OVF == 1) {
    freqm->STATUS.bit.OVF = 1;
    return -1;
  }
  return (int)freqm->VALUE.bit.VALUE;
}
計測実験の結果

実験結果を標準出力に取り出し、結果を確認します。測定結果のカウント値に、設定を反映した定数を乗ずれば周波数に変換できます。ここでは、分かり易いように以下の2つの定数から求めています。

#define FREQMREFNUM (128)
#define FREQMREFFREQ (32768)

SAMD51P19Aは、Arm Cortex M4F搭載なので、浮動小数をサポートしています。最初周波数変換は素直にfloatで計算したのですが、printf関数でfloat型の書式指定を使用したらうまく変換してくれませんでした。Wio TerminalのArduino環境の制約かもしれないです。深く調べず、整数型で計算してお茶を濁しています。

startFREQM();
measuredV = readFREQM();
int freq = measuredV*FREQMREFFREQ/FREQMREFNUM;
Serial.printf("FREQM=%d (%d.%-3d[kHz])\r\n", measuredV, freq/1000, freq%1000);

50kHz外部クロック時の実測結果は以下です。まずまずな感じ。非同期のクロック同士なので、カウントの最後の1くらいは測定の度に変動する可能性があります。

FREQM=194 (49.664[kHz])

100kHzに周波数アップ。カウンタがあふれなければ、周波数が高い方が精度[%]はよくなる筈。

FREQM=389 (99.584[kHz])

1MHz。いいんでないかい。

FREQM=3905 (999.680[kHz])

10MHz。まだまだイケそうですが、とりあえずここまで。

FREQM=39061 (9999.616[kHz])

逆にクロック速度が遅いと、測定精度はボロボロになります。ここでは測定期間が32.768kHz128発で256分の1秒固定です。1kHzといったクロックであると、その期間中に3発カウントするのがやっとです。1kHzのときの結果はこちら。

FREQM=3 (0.768[kHz])

同じような原理、そして参照クロックはどちらも32kHzクロックなのですが、昨日のラズパイPicoの周波数カウンタ読み取り関数は、外部クロック1kHzいれると0[kHz]を返してき、2kHzだと2[kHz]と判定しました。こちらとは挙動が違いますが、いずれもREFクロックに対して遅すぎるクロックはうまく測定できません。まあ、測定時の制限事項として忘れなければよいかと(そういって忘れるのですが、自分は。)

IoT何をいまさら(88) Wio Terminal、SAMD51タイマの外部クロック駆動 へ戻る

IoT何をいまさら(89) Wio Terminal、外部割込みとSMAD51 EIC へ進む