Raspberry Pi Picoで周波数カウンタ

更新日 2025.08.03 登録日 2025.07.20

Raspberry Pi Picoの周波数カウンタには A frequency counter library for the RP2040 が有るので期待していましたが、試しに使ってみると、やはりインタラプト処理によるソフトウェアでタイミングを取っているので、たまに変な値が出てしまいます。たまにしか起こらないので気にしなければ良いのですがやっぱり気になります。 下図では44.3MHzを測定してSerialに出力したものをArduino IDEのシリアルプロッタで表示したものですが、65KHz程上下に変動しています。これは16ビットカウンタのオーバーフロー処理をミスった結果です。

*

ネットでRaspberry Pi Picoの周波数カウンタについて調べていると Accurate frequency measurement on the Pi Pico RP2040 using C という記事でDMAを使ってキャプチャーもどきの機能を実現できることが分かりました。その記事の方法ではゲート時間を250msまでしか長く出来ないので、他の方法を使うことにします。

測定原理

先ず、16ビットカウンタで60MHz程度までカウントするためにはどうすれば良いかという問題があります。単純に考えればオーバーフローをソフトウェアインタラプトでカウントして合成すれば良いのですが、キャプチャーしたカウントとオーバーフローをカウントした値のタイミングのずれを完全に解消するのは困難で、前述の様な変動が出ます。そこで、16ビットカウンタが一巡する前にキャプチャーしてしまい、前回のキャプチャーとの差分を積算すればタイミングのずれを気にする必要が無くなります。 1msec間隔でキャプチャーする場合、16ビットカウンタが一巡するのは65.535MHzなので65MHz程度まではカウント出来ることになります。500usec間隔なら131MHz、250usec間隔なら262MHzまで原理的にはカウント可能です。

*

カウントのキャプチャーを実現するためには先の等間隔のタイミングを作るスライス (図中Slice0) のWRAPイベントでDMAを起動してカウント値 (図中Slice3) を特定の変数 cap1 に転送します。転送はソフトウェアの流れに較べて瞬時に終了するので、WRAPのインタラプト処理で次のWRAPイベントが起こる前までにカウント値の差分を積算すれば良いことになります。

測定周波数の上限ですが一般的にはクロック周波数133MHzの1/3の44.3MHzまでが安全ですが、65MHzまで何となく測れます。250MHzにオーバークロックすれば83.3MHzまでが安全で上限は125MHzです。300MHzにオーバークロックすれば100MHzまでが安全で上限は150MHzです。オーバークロックですがここまでダイレクトにカウントできるのはRasberry Pi Picoならではでしょう。

ゲート時間はFreqCount.begin(msec)のmsecで設定できます。msecは1msから65535msまで設定できます。 ゲート時間は動作中でもFreqCount.gatetime(msec)のmsecで変更できます。

開発環境

開発環境は Arduino IDE 1.8.19 + Raspberry Pi Pico/RP2040/RP2350 by Earle F. Philhower, III version 4.6.0です。
ボードは "Raspberry Pi Pico" または "Waveshare RP2040 Zero" を指定します。

ソースコード

ZIPファイルを展開したフォルダを library フォルダに置けばArduino IDEの「ファイル=>スケッチ例=>」からサンプルプログラムを選択することが出来ます。

FreqCountRPP.zip (2025.08.03 更新)

起動方法

  • FreqCount.begin(uint16_t msec);
  • 計測時間をmsecで指定できます。1秒の場合は1000を指定します。周波数入力ピンはGP7、ゲート時間を発生するスライスに対応するピン番号はGP0になります。

  • FreqCount.begin(uint16_t msec, uint8_t fpin, uint8_t gpin);
  • 計測時間をmsecで、周波数入力ピンをfpinで、ゲート時間を発生するスライスに対応するピン番号をgpinで指定できます。fpinは奇数、gpinは偶数を指定します。

  • FreqCount.begin(uint16_t msec, uint8_t fpin, uint8_t gpin, uint16_t khz);
  • CPUクロックではなく外部から基準周波数を入力する場合にその周波数をkhzで指定します。25MHzの場合は khz=25000 を指定します。基準周波数の入力ピンは (gpin+1) になります。khz=0 ならCPUクロックを使います。

    サンプルプログラム

    Serial

    Arduino IDEのシリアルモニターに結果を表示します。 PWMを使って14番ピンに44.3MHzを出してテストできるようにしました。 周波数入力ピンはGP7、ゲート時間を発生するスライスに対応するピン番号はGP0になります。

    *

    MAX7219

    MAX7219を使用した8桁7-segment LEDに結果を表示します。 PWMを使って14番ピンに44.3MHzを出してテストできるようにしました。 周波数入力ピンはGP7、ゲート時間を発生するスライスに対応するピン番号はGP0になります。

    *

    OLED1306

    SSD1306を使用した128x32のOLEDに結果を表示します。 PWMを使って14番ピンに44.3MHzを出してテストできるようにしました。 周波数入力ピンはGP7、ゲート時間を発生するスライスに対応するピン番号はGP0になります。

    *

    *

    OLED1306BigFont

    SSD1306を使用した128x32のOLEDに結果を表示します。大きい数字フォントで表示します。 PWMを使って14番ピンに44.3MHzを出してテストできるようにしました。 周波数入力ピンはGP7、ゲート時間を発生するスライスに対応するピン番号はGP0になります。
    TCXOから基準周波数を入力します。TCXOの周波数は簡易式の周波数カウンタで測定して自動的に設定します。周波数は10MHzから60MHzまでなら使えるはずですが、100kHz単位に四捨五入しているので10kHz以下の端数があるものは使えません。TCXOを接続しない場合は自動的にCPUクロックに切り替えます。入力アンプには74HCU04のアンバッファインバータを使用しています。100MHz近くまで使えると思います。下手にFETやトランジスタを使うより簡単です。

    *

    *

    写真は300MHzにオーバークロックして100MHzのテスト信号を発生して計測したものです。 100.003557MHzとなりCPUクロックがTCXOの基準から35.57ppm高いということが分かります。

    周波数誤差について

    Raspberry Pi Picoのシステムクロックは水晶発振器が使われていて50ppm以内の精度に収まるようです。

    計算で周波数を補正するには、例えば正確な16MHzを測定して16.000123MHzになったら、
    freq = (double)freq * 16.0 / 16.000123;
    と補正してしまえばとりあえず補正出来ます。それでも温度変動には無力で、水晶発振回路の性能次第になります。

    周波数偏差をソースコードで修正するのは面倒なので、例えば基準周波数の16MHz, 12MHz, 10MHz, 8MHz, 1MHzと100ppm以内の誤差ならばCalibrationボタンを押して自動的に補正して補正値を保存するようにすることも考えられます。これは STM32F103C8T6で192MHz周波数カウンタ を参照してください。

    WRAPイベントを発生しているスライスにシステムクロックではなくchannel BからTCXOやGPS受信モジュールからのPPS信号を与えればより精度を上げることが出来ます。

    GPIOとSliceとchannelの対応

    周波数入力ピンを変更するには以下の表を参照してGPIOとSliceとchannelを決定することになります。周波数入力ピンはchannel Bにする必要があります。

    GPIO 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
    PWM channel 0A 0B 1A 1B 2A 2B 3A 3B 4A 4B 5A 5B 6A 6B 7A 7B
    GPIO 16 17 18 19 20 21 22 23 24 25 26 27 28 29
    PWM channel 0A 0B 1A 1B 2A 2B 3A 3B 4A 4B 5A 5B 6A 6B

    References

  • Dan Ellis A frequency counter library for the RP2040
  • Jeremy P Bentham Accurate frequency measurement on the Pi Pico RP2040 using C
  • 居酒屋ガレージ店主 Arduino UNO R3で周波数を計る
  • siliconvalley4066 Arduino UNO R4で周波数カウンタ
  • siliconvalley4066 STM32F103C8T6で192MHz周波数カウンタ

  • <=Arduinoで電子工作に戻る
    <=Siliconvalley4066番地に戻る
    ゲストブックへ
    siliconvalley4066@yahoo.co.jp