PSoC 4200 Prototyping Kit (10)

タイミング・チャートの形で表現したレシプロカル周波数カウンタ (周期カウンタ) の処理の概要を下に示します。

一番上の波形はソフトウェア的な「ゲート信号」で、対応するハードウェア信号はありません。
測定していない時にはタイマ・カウンタは 2 つとも停止しており、キャプチャ・イベントの発生は無効になっています。
pcnt_Start() 関数で測定を開始する際にリロード・コマンドを発行して、ソフトウェア的に 2 つのタイマ・カウンタを同時に始動させます。
単なる「スタート」コマンドとは違って、「リロード」コマンドではアップ・カウント・モードではカウンタの値を 0 にリセットしてからクロックのカウントを始めます。
ケート・タイムの管理は、タイマ 1 (モジュロ 216 = 65536) の TC (Terminal Count) を数えることによって行っています。
48 MHz クロックに対しては、
65536 / 48 [MHz] = 1.365 [ms]
ごとに TC 割り込みが発生します。
pcnt_Start() 関数の引数「ms」から TC 割り込み何回分かを計算し、pcnt.tc_max 変数にその値をセットしておきます。 1 秒 = 1000 ms に対しては pcnt.tc_max = 732 です。
TC のカウントおよび終了処理はタイマ 1 割り込みハンドラの中で行います。
この「ゲート・タイム」は「直接カウント方式」の周波数カウンタの場合とは違って、厳密さは要求されません。
直接カウント方式では、ゲート・タイムの誤差は直接に測定される周波数の誤差に結びつきます。
周期カウンタでは、測定対象は入力信号の (複数サイクルの) エッジ間の時間間隔であり、ゲート・タイムは単にエッジ検出をイネーブルにする時間の範囲を示しているに過ぎません。
ハードウェアによる周期カウンタの実現では、複数周期の測定についてはプリスケーラを設けて、入力信号を都合の良い一定の分周比で分周してから一対のエッジ間の時間間隔を測定するのが普通です。
ここでは、入力信号のプリスケーラを設けず、入力信号のすべての有効エッジでキャプチャを行い、ゲート・タイム内に入ったエッジの数を数えておいて、周波数/周期は後で計算によって求めています。
CC (Compare/Capture) 割り込みもタイマ 1 の割り込みハンドラで処理します。
ここで問題になるのが、周期測定には「最初」と「最後」のエッジでのキャプチャ値が必要になりますが、その「最後」のキャプチャ割り込みであるかどうかを事前には判断できないことです。
入力信号に何の仮定も置かないとすると、ゲート・タイムが完了してから、始めて「最後」のキャプチャ割り込みが確定することになります。
「最初」のエッジは判断できますし、そのキャプチャ値を pcnt.cap0 変数に保存しておく必要がありますが、それ以降のキャプチャ値は「最後」以外の値は全く必要がありません。
しかし、事前に最後かどうかは判断できないので、ここでは、中国剰余定理を利用した処理も大した負担ではないので、キャプチャ割り込みごとに 32 ビット・カウント値まで求めて pcnt.cap 変数に保存しておくことにしました。
タイマ 1 割り込みハンドラの中で TC 割り込み回数 (pcnt.tc_cnt) が pcnt.tc_max に達すると終了処理に入りますが、ここでも問題がひとつあります。
タイマに「ストップ・コマンド」を発行すると、カウンタは停止し、当然 TC も発生しなくなり、キャプチャ・イベントも禁止されます。
しかし、TC が発生してからストップ・コマンド発行までは即時には行えず、「割り込み応答」+「割り込みハンドラ内の処理」の時間がかかるので、その間に CC 割り込みが発生すると、その割り込みはサービスされないままに無効化される可能性があります。
キャプチャ・イベントでハードウェア的には、すでにキャプチャ・レジスタにカウント値が取り込まれており、CC 割り込みがサービスされないとソフトウェア的にカウントしているエッジの数 (pcnt.ncyc) との間に食い違いが生じる恐れがあります。
この点に関しては、キャプチャ割り込みで毎回 pcnt.cap を (pcnt.ncyc とともに) 更新しているので、キャプチャ・レジスタ直接ではなく、pcnt.cap の方を参照すればエッジの数と食い違うことはありません。
ただし、本当に最後のエッジが無視され、そのひとつ前のエッジを「最後」として扱う可能性がありますが、測定結果に悪影響を及ぼすことはありません。