内蔵RC発振器でArduinoを動かす(旧)
Arduinoで何か作り、そしてそれをATMega168も含めてブレッドボードや万能基板で組む時、結構面倒に感じるのがクロックである16MHzの外部発振器。しかしATMega168には内蔵CR発振器があり、それを使えば最大8MHzで動作させることができます。ではArduinoとしてこれで動作させることはできないものか…ということでやってみました。
注:古いバージョンです。optibootの場合はoptiboot編を参照してください。
変更するところ
変更点としては以下のふたつです。
- ヒューズビットで、クロック元の選択をする。
- 8MHz対応のブートローダー に書き換える。
ヒューズビットの変更
Arduino Duemilanoveでは、標準状態ではヒューズビットは以下のように設定されています。
EXTENDED : F8
HIGH : DD
LOW : FF
AVR Studioで確認すると、この設定の場合、クロックは、
Ext. Crystal Osc. 8.0- MHz; Start-up time PWRDWN/RESET: 16K CK/14 CK + 65 ms
に設定されていることがわかります(「8.0- MHz」とは「8MHz以上」という意味で、8MHzというわけではありません)。
これを
Int. RC Osc. 8 MHz; Start-up time PWRDWN/RESET: 6 CK/14 CK + 65 ms
に変更しました。
これによってヒューズビットは、
EXTENDED : F8
HIGH : DD
LOW : E2
となります。
これをAVR Studioで書き込んで、とりあえずヒューズビットの設定は完了。
ブートローダーの書き換え
既に何か書き込まれているATMega168のヒューズビットを上記のとおりに変更すれば、そのまま8MHzで動作するはずです。しかしこのままではArduino IDEからの操作ができません。そこでブートローダーを8MHz対応に書き換えました。
幸いブートローダーはMakefle上でクロック周波数を指定しておけば、それに応じて各種設定レジスタの値が設定されるようです。ということでMakefileを書き換え、新たに「diecimila_8mhz」というターゲットを作成しました。
(前略) diecimila: TARGET = diecimila diecimila: CFLAGS += '-DMAX_TIME_COUNT=F_CPU>>4' '-DNUM_LED_FLASHES=1' diecimila: AVR_FREQ = 16000000L diecimila: $(PROGRAM)_diecimila.hex // 以下4行を追加 diecimila_8mhz: TARGET = diecimila_8mhz diecimila_8mhz: CFLAGS += '-DMAX_TIME_COUNT=F_CPU>>4' '-DNUM_LED_FLASHES=1' diecimila_8mhz: AVR_FREQ = 8000000L diecimila_8mhz: $(PROGRAM)_diecimila_8mhz.hex (以下略)
あとはこれをMakeするだけです。赤文字がコマンド入力部分。ちなみに以下の作業はMacにて実施しています。Windowsだとcigwinとか入れる必要があるのかな…。
avr-gcc -g -Wall -O2 -mmcu=atmega168 -DF_CPU=8000000L '-DMAX_TIME_COUNT=F_CPU>>4' '-DNUM_LED_FLASHES=1' -c -o ATmegaBOOT_168.o ATmegaBOOT_168.c
avr-gcc -g -Wall -O2 -mmcu=atmega168 -DF_CPU=8000000L '-DMAX_TIME_COUNT=F_CPU>>4' '-DNUM_LED_FLASHES=1' -Wl,--section-start=.text=0x3800 -o ATmegaBOOT_168_diecimila_8mhz.elf ATmegaBOOT_168.o
avr-objcopy -j .text -j .data -O ihex ATmegaBOOT_168_diecimila_8mhz.elf ATmegaBOOT_168_diecimila_8mhz.hex
rm ATmegaBOOT_168_diecimila_8mhz.elf ATmegaBOOT_168.o
$
これで、「ATmegaBOOT_168_diecimila_8mhz.hex」というファイルが作成されます。あとはこのファイルをAVR StudioでATMega168に書き込むだけ。
動作テスト
これだけで、あとは普通にIDEからの書き込みができてしまいました。とても簡単。
定番の「Blink」を書き込み、Arduino基板からATMega168を抜いてブレッドボードにマウント、電源とLED、そして電流制限抵抗を接続しただけで、きちんとBlinkが動きました。
さらには、汎用USB-Serialインターフェースを接続、この状態でIDEからプログラムの書き換え等も可能、最低限の部品でArduinoとして動作させることができました。
標準とちがうところ
このままの場合、各動作で標準の16MHzと違うところがいくつかあります。
単純に2倍遅くなります。例えばdelay(1000)だと2秒かかります。
Serial.begin()にて指定した値の半分のスピードになります。例えばSerial.begin(19200)だと、9600bpsで通信します。
PWM出力の周波数を測定すると約249Hzとなっていました。これも標準の半分の周波数になります。ちなみに標準では490Hzでした。
ボードの定義を書き換え
arduinoのIDEについても、ターゲットとなるArduinoの種類の中にクロック周波数も定義されているので、これを書きかれば良さそうです。ということで、board.txtに以下を追加しました。diecimilaの定義部分をコピー&ペーストし、定義文字列である「diecimila」を「diecimila_8mhz」に書き換え、されに赤字部分を書き換えてます。
diecimila_8mhz.name=Arduino Diecimila, Duemilanove, or Nano w/ ATmega168 8MHz diecimila_8mhz.upload.protocol=stk500 diecimila_8mhz.upload.maximum_size=14336 diecimila_8mhz.upload.speed=19200 diecimila_8mhz.bootloader.low_fuses=0xf8 diecimila_8mhz.bootloader.high_fuses=0xdd diecimila_8mhz.bootloader.extended_fuses=0xE2 diecimila_8mhz.bootloader.path=atmega diecimila_8mhz.bootloader.file=ATmegaBOOT_168_diecimila_8mhz.hex diecimila_8mhz.bootloader.unlock_bits=0x3F diecimila_8mhz.bootloader.lock_bits=0x0F diecimila_8mhz.build.mcu=atmega168 diecimila_8mhz.build.f_cpu=8000000L diecimila_8mhz.build.core=arduino
これを保存後にArduino IDEを立ち上げると、ToolsメニューのBoardに「Arduino Diecimila, Duemilanove, or Nano w/ ATmega168 8MHz」が追加されます。それを選択すれば、delay()関数、Serial入出力のスピードもプログラム通りのスピードになりました。
「賢い扇風機」に対してこのモードでプログラムしてみましたが、普通に8MHzでの動作も16MHzと全く同じように、問題なく動作しました。
安定性は大丈夫なのか?
データシートにもあるよう、内蔵RC発振器の周波数は電源電圧や温度にて変動します。タイマーを使って、厳密に時間を計ったり正確な周波数を出力したり…という事には向かいないでしょう。しかし、普通に38400bpsでデータを出力させ、ドライヤーで加熱した程度では通信上のエラーは発生しませんでした。まぁこれも正確なシリアル通信が求められるならば向かないとは思いますが、単純なモニタ用途であれば問題なく使えそうです。