Arduino UNO R4 Minimaのオシロスコープにも周波数カウンタを組み込みたいと思っていたら、タイミング良く居酒屋ガレージ店主さんのブログ
Arduino UNO R4互換:RA4M1コアボードで周波数カウンタ
が見つかりました。先人の功績は有難いものです。
早速組み込み用にライブラリ風にアレンジしてArduinoのFreqCountライブラリと同じ使い方ができるようにしました。
32ビットカウンタGPT1のキャプチャータイミングを作るカウンタはGPT2からGPT6に変更しました。
キャプチャーによるインタラプトを登録する方法が分からなかったので、その元になるGPT6のオーバーフローでインタラプト処理をしてGPT1のカウント値を読み取っています。FspTimerでGPT6による1秒周期のインタラプトを設定しています。1秒は仮の設定で、後からレジスタ直接アクセスで設定値を変更しています。
D2ピンが周波数入力で、入力にアンプを付けることを想定してプルアップは外してあります。
他のピンはD3ピンも使わないようにしたつもりですが自信がありません。
GTETRGを入力にする方法では12MHz以上でカウントミスが多くなります。3回サンプリングのフィルタのせいかとも思いましたが、通常はoffでonにすると上限がもっと下がりました。余分な回路がいっぱい入るのでこの方法では駄目なのでしょう。
GTCRレジスタのTPCSビットフィールドの定義にミスがあるようなので、修正があっても影響がないようにレジスタ全体を設定するように書き換えています。
測定周波数の上限ですが一般的にはクロック周波数48MHzの1/3の16MHzまでが安全ですが、20MHzまで何となく測れます。R4自身で発生したCPUクロックに同期した信号なら限界の24MHzでもきっちり測れています。
ゲート時間はFreqCount.begin(msec)のmsecで設定できます。msecは1msから65535msまで設定できます。GPT6だけで発生できる 1...88,100,200,400,600,800,1000 等は一回毎のインタラプトで計測します。その他のmsecの値については1ms毎のインタラプトの回数を数えて計測します。これは居酒屋ガレージ店主さんの御助言を受けて対処しました。クロックのプリスケーラで1msを作れれば良いんですが、1/1, 1/4, 1/16, 1/64, 1/256, 1/1024しか使えないのでこんなことになっています。24MHzの周波数に対しても178秒までは32ビットカウンタが折り返さないので、計測値の積算はしていません。178秒以上のゲート時間が必要な場合は64ビット整数の(long long)に積算すれば可能ですが、そこまでの拡張は今のところ考えていません。 (2025.05.16 update)
ゲート時間は動作中でもFreqCount.gatetime(msec)のmsecで変更できます。
Arduino UNO R4 Minimaのオシロスコープに組み込みました。 (2025.05.13 update)
開発環境は
Arduino IDE 1.8.19 + Arduino UNO R4 Boards by Arduino version 1.3.2です。
ボードはArduino UNO R4 Minimaを指定します。
Arduino UNO R4 Minimaのレシプロカル周波数カウンタ Arduino UNO R4でレシプロカル周波数カウンタ も作ったので参考にしてください。 (2025.06.07 追記)
Arduino IDEのシリアルモニターに結果を表示します。 PwmOutクラスを使ってD10ピンに16MHzを出してテストできるようにしました。ちなみに、この状態ではGPT3が使われています。
freq_count.zip (2025.05.13 update)
Arduino UNO R4のシステムクロックは内蔵CR発振器が使われていて、一般的な水晶発振器に比較して精度も悪く、不安定です。ただしPCとUSB接続している場合は水晶並みの精度が出ているという話があります。しかしジッターは多いようです。精度にはあまり期待しない方が良いと思います。
純正のUNO R4 Minima基板には水晶実装用のパッドがあるのでそこに水晶発振子を載せることもできますが、そのままでは使われないので別途ソフトで設定を変更する必要があります。また、中華互換機の中には16MHzの水晶が実装されているものがあります。こちらも別途ソフトで設定を変更する必要がありますが、16MHzの水晶では仕様範囲外になってしまいます。この辺の話はReferencesを参照してください。いずれにしても一般的な水晶の精度は20ppmから50ppm程度ですので、付加するコンデンサを調整しなければ精度を上げることができません。TCXOに置き換えることが出来れば1ppm以下に出来ますが、UNO R4でそこまでする必要はないと思います。
ということで、計算で補正してしまった方が楽です。例えば正確な16MHzを測定して16.000123MHzになったら、
freq = (double)freq * 16.0 / 16.000123;
と補正してしまえばとりあえず補正出来ます。それでも温度変動には無力で、UNO R4の水晶発振回路の性能次第になります。
周波数偏差をソースコードで修正するのは面倒なので、例えば基準周波数の16MHz, 12MHz, 10MHz, 8MHz, 1MHzと100ppm以内の誤差ならばCalibrationボタンを押して自動的に補正して補正値を保存するようにすることも考えられます。これは STM32F103C8T6で192MHz周波数カウンタ を参照してください。
analogWriteやPwmOutクラスでPWMパルスを出力する場合、ピン番号によって使われるGPTが以下のように変わります。したがって、GPT1に対応するD2, D3, D11, D12へPWMを出力するかGPT6を別の目的に使うプログラムと競合します。 (2025.05.13 update)
Pwmピン | D0 | D1 | D2 | D3 | D4 | D5 | D6 | D7 | D8 | D9 | D10 | D11 | D12 | D13 | A4 | A5 |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
使用GPT | GPT4 | GPT4 | GPT1 | GPT1 | GPT2 | GPT2 | GPT0 | GPT0 | GPT7 | GPT7 | GPT3 | GPT1 | GPT1 | GPT3 | GPT5 | GPT5 |