前回から引き続き、出力クロックの周波数を、ある程度任意に設定可能な可変周波数クロック発振器を作って行きます。目標仕様策定の続きからスタートです。
大元のクロックは内蔵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を直結して良い。
以下図に実験中の様子を示します。

以下、実験サンプルに従って実験を進めましょう。
実験サンプル:【 】内は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】

上図測定範囲内の平均で、周期約998[μs]、周波数にして約1,002Hzでした。
ソフトウェアでサンプリングして波形を取得するLogiscopeなので、測定解像度は高くありません。ですので、測定した周波数の方に誤差があるのか、出力しているATtiny85の方に誤差があるのか、切り分けはできません。しかし、設定値1,000Hzに対して測定値1,002Hz、誤差約0.2%ですので、狙った周波数が観測できたと言って良いでしょう。
ここまで、I2Cスレーブデバイスとして機能する事、少なくとも1kHzのクロック出力に関して設定通りの周波数で出力できた事、等を確認できました。MHzオーダの高速なクロック出力をどのように評価すれば良いか、考えてみます😤。ので、今回は、ここまでです。


