Arduino UNO R4で2つの1Hz信号の位相変化を見る
まさにラジオペンチさんに試してもらいたい内容です。
Arduino UNO R4に搭載のマイコンRA4M1のタイマカウンタに
は贅沢な機能が搭載されています。
周波数や周期の測定で活用できるのがインプットキャプチャ。
各タイマ、2つのキャプチャ入力を持っています。
2つあれば、2つの信号の位相差変化を観察することができます。
48MHzのメインクロックでタイマを走らせ、A入力とB入力で
タイマカウント値をキャプチャさせます。
2つのカウント値の差の変化が位相差変化。
48MHzが分解能。
さらに面白いことに、キャプチャ信号でカウンタの
クリアもできるのです。
キャプチャAを「正の1Hz」につなぎ、キャプチャさせる
とともにクリアの機能も有効に。
するとキャプチャAのデータには1Hzのカウント値が
ラッチされ、同時にゼロクリアしてカウントが
再スタートします。
ラッチされたデータは1Hz間のクロック数ですので、
そのまま48000000が出てきます。
32bitカウンタだからできる技。
キャプチャBは比較したいクロック源につなぎます。
1.1Hzを入れるとこんな感じでデータが得られます。
cap A cap B D=A-B Dn-D(n-1)
48000407 3824229 44176178 3261976
48000277 45300801 2699476 3261599
48000397 42039033 5961364 3261888
48000381 38776951 9223430 3262066
48000361 35515063 12485298 3261868
48000385 32253111 15747274 3261976
48000393 28991307 19009086 3261812
48000349 25729291 22271058 3261972
48000313 22467319 25532994 3261936
48000473 19205553 28794920 3261926
48000277 15943485 32056792 3261872
48000485 12681605 35318880 3262088
48000329 9419641 38580688 3261808
48000335 6157735 41842600 3261912
48000457 47634349 366108 3262053
cap Aは48MHz付近をうろうろ。
※ジッタによるクロック誤差が憎い!
cap Bは1.1Hz(およそ)でキャプチャ値がゼロのほうに
進みます。
右端の数字が差の差でおよそ一定。
差のオーバーフロ発生時、偏差として突拍子も
ない数字が出ないよう、押さえつけています。
前回値を保存するややこしい処理はこれのため。
cap A検出のタイミングでデータを出力していますが、
その直前に新たなcap Bのデータが確定してないとい
けません。
B波形の変動によってこれが抜けることがあります。
BのエッジがAのエッジを左から右に
通り過ぎた時。
Aの2つのエッジ間にBのエッジが一つも
入らないタイミング。
現スケッチは、このタイミングの計数を無視し
ちゃってます。
/**********************************************/
/* Arduino UNO R4 minima, 1Hz位相差検出 */
/**********************************************/
// 入力ピン
// D2 P105 GPT1A キャプチャ入力A 外部から1Hzを入力 ↓を検出
// キャプチャと同時にGTCNTクリア
// D3 P104 GPT1B キャプチャ入力B 比較入力 ↓を検出
// タイマー1インプットキャプチャフラグ
#define CK_TCFA (R_GPT1->GTST_b.TCFA) // GPT1インプットキャプチャAチェック
#define CLR_TCFA (R_GPT1->GTST_b.TCFA = 0) // インプットキャプチャAクリア
#define CK_TCFB (R_GPT1->GTST_b.TCFB) // GPT1インプットキャプチャBチェック
#define CLR_TCFB (R_GPT1->GTST_b.TCFB = 0) // インプットキャプチャBクリア
// 文字出力バッファ
char str_bff[80]; // sprintfで使用
/***** SETUP *****/
void setup() {
// モジュールストップ解除
R_MSTP->MSTPCRD_b.MSTPD5 = 0; // 32bit PWMモジュールストップ解除
R_MSTP->MSTPCRD_b.MSTPD6 = 0; // 16bit PWMモジュールストップ解除
R_MSTP->MSTPCRD_b.MSTPD14 = 0; // POEGモジュールストップ解除
// D2:P105 GPT1A キャプチャ入力A
R_PFS->PORT[1].PIN[5].PmnPFS_b.PCR = 1; // P105入力pullup
R_PFS->PORT[1].PIN[5].PmnPFS_b.PSEL = 0b00010; // GTETRGA入力に
R_PFS->PORT[1].PIN[5].PmnPFS_b.PMR = 1; // 周辺機能有効
R_GPT1->GTICASR_b.ASGTRGAF = 1; // A↓でキャプチャ
R_GPT1->GTCSR_b.CSGTRGAF = 1; // A↓でクリア
// D3:P104 GPT1B キャプチャ入力B
R_PFS->PORT[1].PIN[4].PmnPFS_b.PCR = 1; // P105入力pullup
R_PFS->PORT[1].PIN[4].PmnPFS_b.PSEL = 0b00010; // GTETRGB入力に
R_PFS->PORT[1].PIN[4].PmnPFS_b.PMR = 1; // 周辺機能有効
R_GPT1->GTICBSR_b.BSGTRGBF = 1; // B↓でキャプチャ
R_GPT1->GTCR_b.CST = 1; // GPT1カウント開始
// Serialでデータ出力
Serial.begin(9600); // 9600BPSで
while (!Serial); // USB接続チェック
}
/***** キャプチャデータ *****/
int32_t d_cap[2]; // キャプチャA,B値
// Aにジャスト1Hzを入れるとcap[0]は48000000となる
int32_t d_ab; // 差分(A-B)データ プラスの値
int32_t m_ab; // 前回の差分保存データ
int32_t d_dev; // 差分からの偏差
int32_t m_dev; // 偏差保存データ
int32_t m_cap0; // cap A保存データ
byte f_mab; // A-B差分保存済みフラグ
/***** LOOP *****/
void loop() {
Serial.println("1Hz_PH01b.ino"); // タイトル
while(1){
if(CK_TCFA){ // キャプチャA発生
CLR_TCFA; // Aフラグクリア
if(CK_TCFB){ // キャプチャBあり?
CLR_TCFB; // Bフラグクリア
d_cap[0] = R_GPT1->GTCCR[0]; // CAP Aデータ保存
d_cap[1] = R_GPT1->GTCCR[1]; // CAP Bデータ保存
d_ab = d_cap[0] - d_cap[1]; // A-B 差分
if(f_mab == 0){ // 初めての差分
f_mab = 1;
m_ab = d_ab; // 差分を保存
m_cap0 = d_cap[0]; // Aキャプチャ値を保存
}
else{ // 差分2回目以降
d_dev = d_ab - m_ab; // 偏差:差分の差
if(abs(d_dev) >= (d_cap[0] / 2)){ // 前回との差が48Mの半分越え
if(d_dev >= 0){ // 差がプラス
d_dev = d_dev - d_cap[0]; // 偏差を修正
}
else{ // 差がマイナス
d_dev = d_dev - m_dev + m_cap0; // 偏差を修正
}
}
sprintf(str_bff, "%11u %11u %11d %11d",
d_cap[0], d_cap[1], // A,Bキャプチャ値
d_ab, // A-B差分
d_dev); // 偏差
Serial.println(str_bff);
m_ab = d_ab; // 差分を保存
m_dev = d_dev; // 偏差を保存
m_cap0 = d_cap[0]; // Aキャプチャ値を保存
}
}
else{ // ★ capAが来た時にcapBが無かったら
// Serial.println(); // 改行で知らせる
}
}
}
}
※関連
・GPSとArduinoでRTCの誤差(確度)を精密測定
実用するには、UNO R4に水晶発振子をくっつけて
クロックを安定化しないといけません。
クロック精度が悪くてもかまわないのですが、
(UNO R3のように)、UNO R4のジッタがイケません。
計測データ、右端cap A値、ほんとなら48000000近辺で
止まっていてくれなくちゃいけません。
※実験中の様子
左から
・DDS IC AD9833を使って1.0Hzとかを発生。
0.1Hzを調整できる。
・UNO R4基板
・32.768kHz時計用水晶を使った1Hz発生回路
・12.8MHz発振子を使った1Hz発生回路
※追記:RA4M1コアボードで試す
RA4M1コアボードの水晶(16MHz)+PLLを使って、
1Hzの位相差検出を試してみました。
・スケッチ:
ダウンロード - 1hz_phx01.txt
すると・・・
cap Aが12.8MHz発振器を使った1Hz発生回路
cap Bが32.768kHz時計用水晶を使った1Hz発生回路
cap A cap B D=A-B Dn-D(n-1)
48001139 34840845 13160294 194
48001141 34840651 13160490 196
48001139 34840455 13160684 194
48001141 34840261 13160880 196
48001139 34840065 13161074 194
48001139 34839871 13161268 194
48001141 34839677 13161464 196
:
・AとBを入れ換えると
48000945 13164763 34836182 -196
48000947 13164957 34835990 -192
48000945 13165149 34835796 -194
48000947 13165343 34835604 -192
48000947 13165537 34835410 -194
48000947 13165729 34835218 -192
48000947 13165921 34835026 -192
48000947 13166115 34834832 -194
:
・PLLを使うことによりcap Aの値が安定。
飛びが2~3に
・偏差も安定。
・cap AとcapBを入れ換えると偏差の+/-が逆に。
・RA4M1コアボードの水晶発振+PLL周波数がちょい高め。
このくらいだと位相変化が安心して読め、
1Hz発生回路の違いが見えます。
| 固定リンク
「Arduino UNO R4」カテゴリの記事
- Arduino UNO R4 minimaに12MHz水晶を(2025.06.09)
- Arduino UNO R4で2つの1Hz信号の位相変化を見る(2025.06.06)
- UNO R4はanalogWrite(n,128)でデュティー50%の方形波が出るぞ(2025.06.03)
- Arduino UNO R4 minima 電源供給方法でクロックが変わる#6(2025.06.02)
- Arduino UNO R4 minima 電源供給方法でクロックが変わる#5(2025.06.01)
コメント
32ビットカウンタなので48MHzクロックを直接計測しても約90秒くらいの時間は測れるということですね。
こりゃ水晶クロックが実装されているRA4M1のコアボードが欲しくなります。ただあのボードはブレッドボードに挿さらないのが残念なんですよね。
投稿: ラジオペンチ | 2025年6月 9日 (月) 07時21分
32ビットカウンタは偉大です。
投稿: 居酒屋ガレージ店主(JH3DBO) | 2025年6月 9日 (月) 14時11分
UNO R4 minimaに12MHz水晶を。
http://igarage.cocolog-nifty.com/blog/2025/06/post-500e2e.html
大きいけれど、HC-49USのをハンダ付け。
投稿: 居酒屋ガレージ店主(JH3DBO) | 2025年6月10日 (火) 08時46分