google-site-verification: google3bd66dd162ef54c7.html
fc2ブログ

Arduino UNO R4 の内蔵クロック周波数をトリムレジスタで調整

◆まえがき
Arduino UNO R4 MINIMA の記事がまだ続きます。前回の記事では UNO R4 のクロックを IOピンに出して周波数を正確に測定 出来るようになりました。そうやって測定してみると、UNO R4 のクロック周波数の誤差はかなり大きいことが判りました。

UNO R4 のクロック発生回路に水晶やセラミック振動子は使われておらず、チップに内蔵されたCRオシレーターなので仕方ないのですが、もう少し何とかしたくなります。

このクロックの周波数は、トリムレジスタを調整することでユーザーのプログラムから調整出来るようになっているので、実際にやってみました。

◆クロック周波数調整レジスタ
CPUチップ内蔵クロックは下図のように、ユーザートリミングレジスタの値を設定することで調整可能になっています。
HOCOUTCRの説明
上記はHOCOクロックのトリミングレジスタですが、LOCOとMOCOにも同様な調整レジスタがあります。

ユーザートリミングと言う名前で呼ばれているということは、ファクトリートリミングレジスタなんてのが見えない所にあって、チップ製造時にメーカーがトリミングの初期値を書き込んでいるのではないかと思います。

◆トリミング機能付きのクロック周波数測定プログラム
調査用に、トリムレジスタに値を設定し、D11ピンに選択したクロック(を分周した)信号を出力するプログラムを作りました。
// Arduino R4 MINIMA のクロック周波数調整と確認 20240217_UnoR4ClockFreqTrimTest
// クロック トリムレジスタを設定し、D11ピン(P109)に指定したCLKOUT信号を出す

char cbuff[10];  // 文字列操作バッファ

void setup() {
  Serial.begin(115200);
  delay(1000);
  Serial.println();
  Serial.println("Clock out test Start !");

  trimHOCO(3);      // HOCO(48MHz)    トリム量設定 (0.056%/step)
  trimMOCO(-3);     // MOCO(8MHz)     トリム量設定 (1.5%/step)
  trimLOCO(0);      // LOCO(32.768kHz)トリム量設定 (3.77%/step)
  d11AsClockOut();  // 指定クロックをD11ポートから出力
}

void loop() {
}

void d11AsClockOut() {  // D11ピンをクロックアウトで使用
  // CKCORを設定(クロックソースと分周比を設定)
  R_SYSTEM->PRCR = 0xA501;           // レジスタプロテクト解除
  R_SYSTEM->CKOCR = 0;               // CKOCRの全ビットクリア
  R_SYSTEM->CKOCR_b.CKOSEL = 0b000;  // ソース選択 HOCO:000, MOCO:001, LOCO:010, MOSC:011, SOSC:100
  R_SYSTEM->CKOCR_b.CKODIV = 0b011;  // 分周比選択 1分周:000, 001, 010, 011, 100, 101, 110, 128分周:111
  R_SYSTEM->CKOCR_b.CKOEN = 1;       // クロックアウト許可
  R_SYSTEM->PRCR = 0xA500;           // レジスタを再プロテクト
  viewCKOCR();                       // 念のために確認

  // D11(P109)をCLKOUTにアサイン
  R_PMISC->PWPR_b.B0WI = 0;                       // 書き込みプロテクトを、
  R_PMISC->PWPR_b.PFSWE = 1;                      // 外す
  R_PFS->PORT[1].PIN[9].PmnPFS = 0;               // 念のために設定をリセット
  R_PFS->PORT[1].PIN[9].PmnPFS_b.PDR = 1;         // D11(P109)を出力に設定
  R_PFS->PORT[1].PIN[9].PmnPFS_b.PSEL = 0b01001;  // CLKOUTを選択
  R_PFS->PORT[1].PIN[9].PmnPFS_b.PMR = 1;         // 周辺機能をON
  R_PMISC->PWPR_b.PFSWE = 0;                      // 書き込みプロテクトを、
  R_PMISC->PWPR_b.B0WI = 1;                       // セット
  viewD11();                                      // 念のために確認
}

void trimHOCO(int tm) {     // HOCO(48MHz)の周波数をトリム(値は±10程度まで)
  R_SYSTEM->PRCR = 0xA501;  // レジスタプロテクト解除
  R_SYSTEM->HOCOUTCR = tm;  // HOCOの周波数を調整(0.056%/LSB)
  R_SYSTEM->PRCR = 0xA500;  // レジスタを再プロテクト
  sprintf(cbuff, "HOCOUTCR  = 0x%02x", R_SYSTEM->HOCOUTCR);
  Serial.println(cbuff);
}

void trimMOCO(int tm) {     // MOCO(8MHz)の周波数をトリム(値は±10程度まで)
  R_SYSTEM->PRCR = 0xA501;  // レジスタプロテクト解除
  R_SYSTEM->MOCOUTCR = tm;  // HOCOの周波数を調整(0.057%/LSB)
  R_SYSTEM->PRCR = 0xA500;  // レジスタを再プロテクト
  sprintf(cbuff, "MOCOUTCR  = 0x%02x", R_SYSTEM->MOCOUTCR);
  Serial.println(cbuff);
}

void trimLOCO(int tm) {     // LOCO(32.768kHz)の周波数をトリム(値は±10程度まで)
  R_SYSTEM->PRCR = 0xA501;  // レジスタプロテクト解除
  R_SYSTEM->LOCOUTCR = tm;  // HOCOの周波数を調整(3.7%/LSB)
  R_SYSTEM->PRCR = 0xA500;  // レジスタを再プロテクト
  sprintf(cbuff, "LOCOUTCR  = 0x%02x", R_SYSTEM->LOCOUTCR);
  Serial.println(cbuff);
}

void viewCKOCR() {          // CKOCRの内容を出力
  sprintf(cbuff, "CKOCR     = 0x%02x", R_SYSTEM->CKOCR);
  Serial.println(cbuff);
}

void viewD11() {            // D11のポート設定を出力
  sprintf(cbuff, "D11(P109) = 0x%08lx", R_PFS->PORT[1].PIN[9].PmnPFS);
  Serial.println(cbuff);
}
選択できるクロック(と分周率)は一つだけなので、複数のクロックを調整したい場合は設定を変えてその都度確認を行うことになります。トリム量設定のプログラムは単独の関数にしてあるので、その部分を流用すれば別のプログラムからでも簡単に使えるようになっています。

◆測定結果
1)HOCO
HOCOはCPUのメインクロックでR4では標準値は48MHzです。
HOCOtable
トリム量を変えた時の周波数測定結果です。トリム量ゼロの時の測定結果は5.988Mhzなので、8分周する前のクロックの発振周波数は47.904MHzです。標準値は48MHzなので 0.2% 周波数が低いことになります。

HOCOgraph
トリム量を変えた時の周波数変化グラフから近似直線の傾きを調べると、0.0559%でした。これが調整感度になります。

初期の誤差は -0.2% だったので必要なトリム量は +3.58 となります。整数値しか設定出来ないので +4を設定することにしました。この調整を行うことで、-0.2% だったクロック周波数の誤差が +0.024% に改善されるはずです。

2)MOCO
これは8MHzのクロックです。IO周りで使われていると思うのですが詳しい用途は調べていませんが、もしもタイマーに使われているなら、時間精度に直結するので気になります。

MOCOtable
公称値に対して3.25%周波数が高いです。

MocoGraph
調整感度は1.499%なので、3.25/1.499=2.16.つまり、トリム量を-2にしておけば良さそうです。この調整を行えば、+3.25%あったクロック周波数の誤差が +0.25%に減るはずです。

3) LOCO
時計などに使われる32.768kHzのクロックです。
発振周波数の測定結果は33kHzちょうどだったので、0.708%周波数が高いことが判りました。

20240217LocoTable.jpg


LocoGraph
トリム感度は 3.77%とびっくりするくらい大きな値でした。こんなに大きな値だと現状より正確な周波数に合わせ込むことは出来ません。そんなことで、LOCOのトリム量はゼロのままにするしかありませんでした。

◆電源電圧の影響
電源電の変化でクロック周波数が大きく変わってしまうようでは、クロックのトリムを細かく調整してもあまり意味が無くなります。そこで、電源電圧変化に対する、クロック周波数の変化を測定してみました。方法としては、USBコネクタから電源供給し、その電圧を安定化電源を使って3Vから5.5Vまで変化させました。

結果は、大きく電源電圧変化させても、HOCO, MOCO, LOCO の全てで周波数の変化はほとんどありませんでした(ばらつきの範囲内でした)。つまり通常の使用範囲での電源電圧の変化に対して、クロック周波数の変化量は無視できる程度でした。

想像ですが、内部オシレーターは、チップ内のローカルレギュレーターから安定化された電源電圧を供給されて動いているような気がします。

◆まとめ
クロック周波数のユーザートリミングレジスタを設定して、その効果を定量的に測定してみました。

HOCOについては0.056%ステップで調整が可能であることが判りました。もう少し細かく調整が出来ると良いのですが、内蔵クロックは周波数の下の4桁目あたりが常にふらふらと変動しているので、これ以上細かいことを言っても仕方が無い感じです。

LOCOはリアルタイムクロック(RTC)の信号源なので、正確な周期を供給出来るようにしておいて欲しいところです。しかし、元々その誤差が大きく、さらにトリミング量のステップが3.77%と大きいので、正確に調整することは不可能でした。とても残念な結果です。

正確な時計が必要な場合は水晶オシレーターを使うべきなんでしょう。ただ、UNO R4 MINIMA には水晶振動子は付いていないので改造が必要です。(私の買ったR4の互換品の基板には部品の取り付けパッドも省略されていました)。そういう面倒臭いことになるなら、外付けのRTCを使った方が手っ取り早い気がします。

カレンダー
01 | 2024/02 | 03
- - - - 1 2 3
4 5 6 7 8 9 10
11 12 13 14 15 16 17
18 19 20 21 22 23 24
25 26 27 28 29 - -
プロフィール

ラジオペンチ

Author:ラジオペンチ
電子工作を中心としたブログです。たまに近所(東京都稲城市)の話題など。60過ぎて視力や器用さの衰えを感じつつ日々挑戦!
コメントを入れる時にメールアドレスの記入は不要です。なお、非公開コメントは受け付けていません。
記事の内容のご利用は読者の自己責任でお願いします。

記事が気に入ったらクリックを!
最新記事
カテゴリ
最新コメント
リンク
FC2カウンター
検索フォーム
月別アーカイブ
RSSリンクの表示
QRコード
QRコード