koheiのおもちゃ修理記録

宇部おもちゃ病院 毎月第2土曜日 13:00~16:00
宇部新天町の西の端、市民活動センターで開院してます。

9/22 Attiny13aの内蔵オシレータキャリブレーション

2020-09-22 | PIC・電子工作
さてこの4連休、Attiny13aをつついて遊んでいます。
安くて便利なこのAttiny13aですが、内蔵RCオシレータの誤差が、カタログスペックで±10%となっています。
マイコンを赤外線リモコンの送信機等で使う場合、38kHzの変調波を作る必要があります。
一般的に使われてる赤外線受光素子は、外乱を受けない様に(代表的には)38kHzの信号のみを受信するように作られていますが、その周波数の必要精度はどのくらいでしょう?

データシートになかなか載ってないのですが、いつもお世話になってる大泉さんから型番(PL-IRM2121-A538)を教えて頂いて、周波数-感度のグラフをゲットしました。

これによると、38kHzから±10%外れると、感度半減です!これでは、操作可能距離に大きく影響すると思われます。
±5%ズレても70%。38kHz変調波の周波数誤差は、3%以内ぐらいに抑えたいです。
それなのに、使用するマイコンのオシレータ誤差が±10%もあったのでは話になりませんw。
(まああくまでも「保証値」なので、10%はないと思いますが。)

Attiny13aは、内蔵オシレータの精度を工場出荷時より上げたい場合には、自分で校正したOSCCALを指定してやる必要がありますが、Attiny13aにはクロック出力の機能が無いので、プログラムで何らか出力してやって、その周波数を測定する必要があります。
Attiny13aの内蔵オシレータキャリブレーションは、ネット上にいくつかありますが、参考にさせて貰いながら自分で作ってみます。

要件としては、
・インラインアセンブルできっちりサイクル数えて、ポートにパルスを出す。(結果、クロックの16分の1のパルスを出す事になった)
・PB3(PIN2)をLにするとOSCCAL値がインクリメントする。
・PB4(PIN3)をLにするとOSCCAL値がデクリメントする。
・目標の周波数になったら、PB1(PIN6)をLにするとOSCCAL値をeepromの0番地に書き込む。
とします。

プログラムはこうなりました。

/*
PB0(PIN5)に周波数カウンタ(又はオシロスコープ)を繋ぐ。
クロックの1/16がPB0出力に出力される→9.6MHzなら600kHzが目標。
PB3(PIN2)をLにするとOSCCAL値をインクリメントする。
PB4(PIN3)をLにするとOSCCAL値をデクリメントする。
目標の周波数になったら、PB1(PIN6)をLにするとOSCCAL値をeepromの0番地に書き込む。
*/ 

/*ヒューズ設定*/
// 7A FC

#define F_CPU 9600000 // 9.6MHz

#include <avr/io.h>
#include <avr/eeprom.h>
#include <util/delay.h>

int main(void)
{

    while (1) 
    {
	//ポート初期設定
		DDRB = 0x01;	//PB0を出力に
		PORTB = 0b00011110;	//PB1~4はプルアップ

	//信号出力
	      asm volatile(
			"ldi  r16, 0b00011110"    "\n\t"	// L出力用データ
			"ldi  r17, 0b00011111"    "\n\t"	// H出力用データ
			"ldi  r18, 0b00011110"    "\n\t"	// SW検出用マスク
			"LABEL1:"                 "\n\t"
			"out  0x18, r17"          "\n\t"	// H出力			CPU 1 cycle
			"in   r19,0x16"           "\n\t"	// ポート入力		CPU 1 cycle
			"com  r19"                "\n\t"	// 入力結果反転		CPU 1 cycle
			"and  r19, r18"           "\n\t"	// SWポートマスク	CPU 1 cycle
			"brne LABEL2"             "\n\t"	// 0でなければループ抜ける	CPU 1 cycle
			"nop"                     "\n\t"	//					CPU 1 cycle
			"nop"                     "\n\t"	//					CPU 1 cycle
			"nop"                     "\n\t"	//					CPU 1 cycle

			"out  0x18, r16"          "\n\t"	// L出力			CPU 1 cycle
			"in   r19,0x16"           "\n\t"	// ポート入力		CPU 1 cycle
			"com  r19"                "\n\t"	// 入力結果反転		CPU 1 cycle
			"and  r19, r18"           "\n\t"	// SWポートマスク	CPU 1 cycle
			"brne LABEL2"             "\n\t"	// 0でなければループ抜ける	CPU 1 cycle
			"nop"                     "\n\t"	//					CPU 1 cycle
			"rjmp LABEL1"             "\n\t"	// 先頭に戻る	CPU 2 cycle
			"LABEL2:"                 "\n\t"
			"nop"                     "\n\t"
	    :::"r16", "r17", "r18", "r19"
	    );

		if(!(PINB&0x08))		//PB3がLのときは
		{
			OSCCAL+=1;		// 校正値をインクリメントする
			_delay_ms(500);
			while(!(PINB&0x08));	//PB3がHになるまで待つ
			_delay_ms(500);
		}
		if(!(PINB&0x10))		//PB4がLのときは
		{
			OSCCAL-=1;		// 校正値をデクリメントする
			_delay_ms(500);
			while(!(PINB&0x10));	//PB4がHになるまで待つ
			_delay_ms(500);
		}
		if(!(PINB&0x02))		//PB1がLのときは
		{
			eeprom_busy_wait();	// キャリブレーション値をEEPRONの0番地に書込む
			eeprom_write_byte(0x0000,OSCCAL);
			_delay_ms(500);
			while(!(PINB&0x02));	//PB1がHになるまで待つ
			_delay_ms(500);
		}
		
    }
}

(あいかわらず<>を倍角で書き換えているので、コピペする場合はご注意願います。)

「メインルーチンをCで書いて、時間が重要な部分をインラインアセンブラで書く」のが普通なところ、逆にメインがアセンブラの様なプログラムになってしまいましたが、一応動きましたw。(C側の変数をインラインアセンブラ側で使う方法とか、まだまだ勉強が必要ですが、今回は「インラインアセンブラを初めて使ってみた!」という事でご勘弁をw。)

出力される周波数は、秋月のカウンターキットとオシロとで測定。(水晶発振の確認の為に買ったカウンターですが、アンプ通さないと測定できなくて、未だにちゃんと使えてない…。)

写真はほぼ600kHz(=9.6MHz)に校正後(OSCCALの1上げ下げで、5kHzぐらい変わるので、このくらいがほぼベスト)。SOP8のAttiny13aは、SOP8→DIP8の変換基板を使って作ったアダプターを使用して、ブレッドボードで仮組みです。

オシロでの測定状況。

使ったAttiny13aの「校正値バイト」は、"56 5A"でした。
それに対して、校正後のOSCCALは56→59で、校正前後で約3%の誤差でした。やはり、周囲とのやり取りで周波数やクロックが重要な場合には、校正が必要でしょう。

さて、以上は9.6MHz内蔵クロックの話ですが、4.8MHzを使う場合はどうなるのでしょう?
データシートによると、

17.3 校正バイト
Attiny13の識票エリアには、内蔵オシレータ用の2バイトの校正値が格納されている。校正データのアドレス0x00番地の上位バイトは、9.6MHz動作時のオシレータ設定に使用される。オシレータの正確な周波数を保証する為に、リセット時にこのバイトが自動的にOSCCALに書き込まれる。

4.8MHz動作時用に別個の校正バイトがあるが、そのデータは自動的には読み込まれない。ハードウェアはリセット中に、常に9.6MHz用の校正データを読み込む様になっている。4.8MHz動作時にこの別個の校正データを使うには、ファームウェアでOSCCALを更新する必要がある。4.8MHz動作時の校正データは、識票エリアのアドレス0x01番地の上位バイトに格納してある。

と書いてあるようです。
つまり、今回使用したAttiny13aの校正バイトは"56 5A"で、"56"の方が9.6MHz用の工場校正値で、これが自動的に読み込まれてOSCCALのデフォルトになる。"5A"の方は4.8MHz用の校正値だが、これは、せっかくあるのに使われない!
という事になりますね…。(なんでせっかく設定してるのに使わないんだ??)

先ほどの校正用プログラムを4.8MHzで動かしたときの状況です。

目標:300kHzに比べて、随分低くなってます。そりゃそうだよね、工場校正で「5Aがいいですよ」っていうのに、OSCCALは"56"になってるのですから。(実際、eepromに書き込んで確認しました。)
これを300kHzにするのに、OSCCALプラス8が必要でした。9.6MHz→4.8MHzで工場校正値の差が+4、9.6MHzの時の校正値が工場校正値より+3だったので、ちょうどそんなところでしょう。

つまり、Attiny13aを4.8MHzで使う際は、やっぱり校正した方がいいけど、せめて校正値バイトを読んでその2バイト目に書いてある数字でOSCCALを更新するべき!
という結論になりましたw。
コメント    この記事についてブログを書く
  • Twitterでシェアする
  • Facebookでシェアする
  • はてなブックマークに追加する
  • LINEでシェアする
« 9/21 LEDのI-V特... | トップ | 10/3 プレイルームおも... »

コメントを投稿