公開日:2025/11/22
title.png

37th Season


#37-2 可変周波数クロック発振器(ふた)

 前回から引き続き、出力クロックの周波数を、ある程度任意に設定可能な可変周波数クロック発振器を作って行きます。目標仕様策定の続きからスタートです。

出力可能な周波数

 大元のクロックは内蔵RC発振器であり、手元のATtiny85では約5MHz〜17MHzで設定可能でした。この場合、以下の様な範囲のクロック出力が可能です。

OSCCAL
[MHz]
PLLCSR
LSMビット
PLL×8逓倍
周波数[MHz]
TCCR1
CS1フィールド
OCR1C 出力クロック
周波数
備考
5 ÷2 20 ÷16,384 0xff 2.38Hz 最低周波数
8 ÷2 32 ÷128 0x7c 1kHz  
8 ÷2 32 ÷8 0xc7 10kHz  
8 ÷2 32 ÷1 0x9f 100kHz  
8 ÷2 32 ÷1 0x0f 1MHz  
8 ÷2 32 ÷1 0x01 8MHz デフォルト
8 ÷2 32 ÷1 0x00 16MHz  
10 ÷2 40 ÷1 0x00 20MHz  
6.25 ÷1 50 ÷1 0x00 25MHz  
7.5 ÷1 60 ÷1 0x00 30MHz  
8 ÷1 64 ÷1 0x00 32MHz  
17 ÷1 ※85 ÷1 0x00 42.5MHz 最高周波数

※ATtiny85データシートより、PLLの最高発振周波数は85MHz(MIN)なので、それを示した。17MHz×8逓倍=136MHzだが、スペック面では、そこまで高速に発振できない。

 内蔵RC発振器やPLL、8ビットタイマTC1の設定によって、約2Hz〜42.5MHzまでの広い周波数範囲でクロック出力が可能な仕様です。

 例えば出力したクロックを使って、

 様々な用途に対して、任意のクロック周波数を作り出せるのが特徴です。

端子仕様

 ATtiny85の貴重な8本の端子は、以下表の様に機能を割り当てる事にしました。

DIP Arduino ATtiny85 可変周波数
クロック発振器
1 D5[A0] PB5(RESET) RESET
2 D3[A3] PB3 RESO
3 D4[A2] PB4(OC1B) CLKO
4 GND
5 D0 PB0(SDA) SDA
6 D1 PB1
7 D2[A1] PB2(SCL) SCL
8 VCC

 クロック出力CLKOでATmega328等、他のマイコンを駆動する場合を想定して、起動してからCLKOが安定するまでLOW出力するリセット出力端子RESOを備えています。

仕様制限

 ATtiny85の内蔵PLLは、参照クロック源として内蔵RC発振器の8MHzクロックを使っています。

 以上より、水晶発振器みたいな、高精度な周波数は出力できないことが制限です。

 その代わりRC発振器は水晶発振器と異なり、回路定数(抵抗値R等)を変化させることで、ある程度の範囲で発振周波数を制御することができます。

プログラム

 完成したプログラムを以下にリンクします。

  完成プログラム: ti85_vclkgen.ino

 ATtiny85へは、UNOを書き込み装置(Arduino ISP)として使い、シリアルプログラミングモードで書き込みます。具体的な書き込み方法は、こちらを参照してください。

クロックを作る実験

 完成した可変周波数クロック発振器(ATtiny85)の動作を、実験で確認して見ましょう。
 ATtiny85とI2C通信して可変周波数クロック発振器を制御するため、Arduino UNOを使います。プログラム(smbus_master.ino)を書き込んでおいてください。
 また、ATtiny85が出力したクロック波形を観測するため、STM32ボードLogiscopeを書き込んで、以下表の様に接続してください。

Arduino UNO 接続 ATtiny85 接続 STM32ボード
VCC VCC  
GND GND GND
A5(SCL) D2(SCL)  
A4(SDA) D0(SDA)
  D4(CLKO) D8(PA8)※

※STM32(3.3V定格)のD8(PA8)端子は5Vトレラントなので、CLKOを直結して良い。

 以下図に実験中の様子を示します。

a372_expr.jpg


 以下、実験サンプルに従って実験を進めましょう。

  実験サンプル:【 】内はUNOシリアルモニタからの送信データ
  【scan】
  OK+ +0 +1 +2 +3 +4 +5 +6 +7 +8 +9 +a +b +c +d +e +f
  00:             -- -- -- -- 0c -- -- --
  10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
  20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
  30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
  40: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
  50: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
  60: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
  70: -- -- -- -- -- -- -- --
  OK: scan i2c slave address


  【slv,0c】
  OK: i2c_slv_adr=0x0c

 コンパイル時に定数で指定しておいた、スレーブアドレス0x0cを検出しました。【slv】コマンドを使って、スレーブアドレス0x0cをアクセス対象として設定しました。

 可変周波数クロック発振器の各I/Oレジスタ初期値を確認して見ましょう。

  【srd1,0】……CMNDIDレジスタ
  OK: srd1.0c[0x00]=0x4f

  【srd1,1】……OSCCALレジスタ
  OK: srd1.0c[0x01]=0x57

  【srd1,2】……OSCFRQレジスタ
  OK: srd1.0c[0x02]=0x40

  【srd1,3】……PLLCSRレジスタ
  OK: srd1.0c[0x03]=0x81

  【srd1,4】……TCCR1レジスタ
  OK: srd1.0c[0x04]=0x01

  【srd1,5】……OCR1Cレジスタ
  OK: srd1.0c[0x05]=0x01

 ここで読み出した初期値では、出力クロック周波数が8MHzとなります。Logiscopeのサンプリングレートだと、あまり高速なクロックの計測はできません。MHzオーダのクロック出力を、どのように評価すべきか考えないといけませんね……。
 ひとまず、Logiscopeで観測可能な周波数まで落として評価を進めたいと思います。

 出力クロックを1,000Hzに設定してみます。

  【swr1,2,40】……OSCFRQ=8MHz(0x40=(8MHz−4MHz)×16)
  OK: swr1.0c[0x02]=0x40

  【swr1,3,80】……PLLCSR=÷2分周×8逓倍
  OK: swr1.0c[0x03]=0x80

  【swr1,4,08】……TCCR1=PCK/128
  OK: swr1.0c[0x04]=0x08

  【swr1,5,7c】……OCR1C=0x7c(PWM周期=(0x7c+1)×2)
  OK: swr1.0c[0x05]=0x7c

 fCLKO=8MHz÷2分周×8逓倍÷128分周÷(125×2)周期=1,000Hzです。

 Logiscopeで、出力クロック波形を確認して見ましょう。

  実験サンプル:【 】内はSTM32 Logiscopeからの送信データ
  【trg,8,r,21000】

a372_clko.png

 上図測定範囲内の平均で、周期約998[μs]、周波数にして約1,002Hzでした。
 ソフトウェアでサンプリングして波形を取得するLogiscopeなので、測定解像度は高くありません。ですので、測定した周波数の方に誤差があるのか、出力しているATtiny85の方に誤差があるのか、切り分けはできません。しかし、設定値1,000Hzに対して測定値1,002Hz、誤差約0.2%ですので、狙った周波数が観測できたと言って良いでしょう。


 ここまで、I2Cスレーブデバイスとして機能する事、少なくとも1kHzのクロック出力に関して設定通りの周波数で出力できた事、等を確認できました。MHzオーダの高速なクロック出力をどのように評価すれば良いか、考えてみます😤。ので、今回は、ここまでです。


btn_arduino.png

btn_prev.png btn_next.png

home