AVRには外部クロックがなくても動作するように、ICの内部にRC発振回路によるクロックを内蔵しています。
工場出荷時に規定の周波数(基本的に8MHz)になるように校正されていますが、データシートによると10%までの誤差がある可能性があり、シリアル通信では致命傷になります。
そこで、個別に調整できるようにOSCCAL(発振校正レジスタ)が存在します。このレジスタをプログラム実行時に書き換えることで発振周波数を変更できます。OSCCALが大きいほど高い周波数で、小さいほど低い周波数で動作します。
AVRはヒューズビットのCKOUTをプログラム(0)することにより、CLK0端子からシステムクロックが出力されます。これを測定機器で観測しながらOSCCALレジスタを操作することによりクロックを調整します。
校正
手元にあったATmega88を8Mhzに校正してみました。今回は周波数の測定には周波数カウンタを利用しました。もちろんオシロスコープで周波数を算出しても構いません。
工場出荷時の校正値はAVR ISP mkⅡを利用して読み出せます。この個体は0xbbになっていました。この状態での発振周波数はこのようになりました。
8.09MHzと少し高い周波数になっていました。誤差は+1.3%とデータシートの許容範囲10%に比べるとかなりよい精度です。が、少し高いので0xbaにしてみました。
0xbaにしたところ8.03MHz。これでもまだ高いので、0xb9にしてみます。
0xb9にすると7.99MHzと誤差は-0.13%とかなり高精度にできました。しかし、残念ながらCR発振は気温等に影響されるので常にこの精度を維持することはできません。あくまでも「今の環境」での周波数です。
実験
試しにどこまでいけるのか、CLK0端子を周波数カウンタに接続しながらいろいろとOSCCALを操作して動作周波数を見てみます。
OSCCALを0×00にしてみると、3.92MHz。
半分の0x7fでは、8.08MHz。あれ?0xb9の時より高い?
そこで、0x8fにしてみると、6.53MHz。データシートを読んでみると、最上位ビットは高周波範囲(1)か低周波範囲(0)かの選択になっているようで、この2つの範囲は重なっており、0x7fの時の方が0×80のときより高い周波数になっているようです。
最後にもっとも大きい0xffにしてみると、12.97MHzとなりました。
これほど範囲が広いのであれば無理矢理でよければ内蔵CRである程度の速度まで動かすことができそうです。
おまけ
周波数カウンタに接続したブローブをどこにもつながないと、商用電源のノイズを広うようで、60Hz近辺の周波数が表示されました。








AVRのマニュアルでは、キャリブレーションすれば±1%の精度が可能と記載されていますが、温度偏差含めて本当に可能なのか、そんな実験結果がありますでしょうか。
どうでしょうか、温度まで含めてとなると結構大変な実験ですね。
データシートの表記では分かりにくいのですが、これは各温度で1%の誤差で調整できるという意味だと思うのですがどうでしょう?
それなら十分可能な気がします。
PICではosccalを自動で合わせるプログラムがあります。
(書き込んだとき見失って工場設定に復元できない場合)
AVRにはあるかご存じでしょうか?
(有れば応用したいです)
規定値以外ですと誤動作する場合があり、
かつEEPROMやフラッシュに書き込めないときがあります。
外部から1MHzを与えるとこれで書き込めます。
AVRはリセット時には常に工場出荷時に戻っているため工場出荷時に戻すことは簡単です。
そのため調整する=プログラム起動時に毎回OSCCALを書き換える、ということなので、
OSCCALを変更しないようにプログラムを変更すれば工場出荷時のまま動作させることができます。
自動調整は外部のシリアル通信の波形を基準に調整するサンプルは見たことがありますが、AVR単体では調整できないと思います。
よろしいでしょうか?参考になれば幸いです。