Arduino IDEで素のATmega328Pに書き込む ~ あれ?Lチカが遅いぞの巻

Arduinoで開発したプログラムを実際の装置に組み込む場合、Arduinoである必要はなくAVRマイコンそのものとして使えればよいはず。

しかし、ちょっと考えてみるとArduino Nanoの互換品ならATmega328Pと値段はさほど変らないし、実装面積もArduino Nanoの下の空間が使えることを考えれば「土地問題」も大したことはない気もする。「上空」が確保できるのならArduino Nano(互換品)をそのまま載せるのが楽か?

ま、それはそれとして、やっぱり、チップだけを載せた方がスッキリするのでArduino IDEから素のATmega328Pに書き込む方法を調べてやってみる。

なお、この記事はATmega328Pの内蔵クロックを使う方法の説明。外部クロックを使う場合はこちらの記事で(タイトルで混乱しそうだけど、この記事の中にATmega328Pを外部クロックで使う話がある)。

Arduinoのブートローダとは?

「Arduino IDEでATmega328Pに書込み」とか調べてると「まず、ブートローダを書き込んで」という話によく当たる。ワンチップマイコンを動かすのになんでブートローダが必要なんだろう?さらに調べてみると、どうやら「ATmega328PをArduinoとして動かすために」ブートローダが必要らしい。

Arduinoのブートローダには、二つの機能があるとのこと。

  1. シリアルポートを監視し、(外部からの)プログラム書込み要求があればそれをチップ内部のEEPROMに書き込む。
  2. (一定時間内に)プログラム書込み要求がなければ、チップ内部のEEPROMの本来のプログラム(アプリケーション)に処理を移す。

Arduinoはブートローダ内にこの書込機構を設けることで、プログラムライタなしでプログラムを書き込めるようにしたことがミソ(多分)。この辺り、こちらの記事でようやく理解した。

実際のところ本来のプログラムを「ロード」しているわけではないので、「ブートローダ」って呼ぶのはどうよ、って気がしないでもないけど。まぁ、外部からの書込み要求されたものをチップ内部にロードしていると言えなくもないか。いずれにしても、普通に考える「ブートローダ」とはちょっと違う。

ということで、ATmega328Pを(単なる)ワンチップマイコンとして動かすのならArduinoブートローダを書き込む必要はない。本来の動かしたいプログラムを(ライタを使って)書いておけば良い。Atmel Studioで作ったプログラムをライタで書き込んだ場合にはそうなっているはず。

Atmel Studio 7.0でビルドしたバイナリをAVRに書き込む方法をまとめておく。 書込みツール AVRにプログラムを...

Arduinoブートローダを書き込まいなら、その分、EEPROMの空間の一部を取られなくて済むというメリットもある。

Arduino IDEからATmega328Pに書き込む

ATmega328Pを内蔵クロックで動かす

Arduinoは16MHzのクリスタルを搭載してるが、ATmega328Pには内蔵クロックもある。内蔵クロックは8MHzだけど、それで間に合うなら(高速処理が必要なければ)部品点数が減らせて都合が良い。

ATmega328Pを内蔵クロックで動かす方法は、Arduinoの公式サイトに説明がある。

この記事の後半の「Minimal Circuit (Eliminating the External Clock)」のところ。この記事ではATmega328PにArduinoブートローダを書き込んでから(つまり、Arduino化してから)目的のスケッチ(プログラム)を書き込むという二段階の方法が説明されている。しかし、Aruduino化する必要はないので、最初の手順で(ブートローダではなく)目的のプログラムを書き込めばOK。

Arduino IDEの設定

まずは、上記のページに沿ってArduino IDEを設定する。

  1. breadboard-1-6-x.zipをダウンロードする(ダウンロードリンクは上記ページ内にあり)。使っているArduino IDEは1.8.xだけどこれでいいみたい(これより新しいのはないし)。
  2. ダウンロードしたbreadboard-1-6-x.zipを展開。
  3. 一旦、Arduino IDEを立ち上げて環境設定を開き、「スケッチブックの保存場所」を確認。確認(コピー)したら、Arduino IDEは閉じる。
  4. 「スケッチブックの保存場所」をエクスプローラで開き、そこに「hardware」フォルダを作る(以前作ったことがあれば、そのままでOK)。
  5. 作成した「hardware」フォルダ内に、先程展開したbreadboard-1-6-x.zipの「breadboard」フォルダを丸ごとコピー(移動)する。
  6. Arduino IDEを立ち上げる。「ツール」→「ボード」→「breadboard-avr (in sketchbook)」→「ATmega328 on a breadboard (8 MHz internal clock)」があるはず(なければ先程のフォルダのコピー場所が間違っている)。これを選択。

これでATmage328Pを内蔵クロックで使うための設定は完了。

Lチカ

試しに「Lチカ」してみる。

まず、回路。

ATmega328PにISPコネクタを直結しただけ。それと、D13にLED(つまり、ビルトインLEDと同じ)。おまけでVCCにパスコン。

スケッチは、サンプルのBlink

これをコンパイル。

コンパイルは通る(当り前)が、ワーニングが出る。

Warning: Board breadboard:avr:atmega328bb doesn’t define a ‘build.board’ preference. Auto-set to: AVR_ATMEGA328BB

無視(放置)しても良さそうな内容だけど気持ち悪いので調べてみると、どうやら先ほどダウンロードして設置したファイルに定義漏れがあるらしい。

先程、設置したフォルダ「breadboard」の下の「avr」の中の「boards.txt」を開き、一番下に「atmega328bb.build.board=AVR_ATMEGA328BB」と書き加える。

ワーニングの内容も「build.boardの定義がないからAVR_ATMEGA328BBを自動設定するよ」って言ってただけで、この追加もそれを明示的に指定するというだけのもの(たぶん)。

再コンパイル。

今度はワーニングなし。

では、書込み。

書込装置はUSBaspで

Arduino IDEからライタ(書込装置)を使ってマイコンに書き込むには、まず、「ツール」→「書込装置」でライタを指定する。

いろいろなライタがサポートされている。Arduinoをライタとして使うこともできるようだけど、なんだか面倒そうなので手持ちのUSBaspを使う。

USBaspの設定はこちらの記事で。

Atmel Studio 7.0でビルドしたバイナリをAVRに書き込む方法をまとめておく。 書込みツール AVRにプログラムを...

念のため、「ボード」が「ATmega328 on a breadboard (8 MHz internal clock)」、「書込装置」が「USBasp」になっていることを今一度確認(なっていなければ、このように設定)。

書込装置を使って書き込む」を選択。

これで、(再)コンパイルと書き込みが行われる。

無事、書込完了。書込み中はボード上のLED(SCK/D13につないだLED)がチラチラする。

ワーニングが出ているが、これはUSBaspのファームウェアが古いため。ATmega328Pに書込みを行うには問題ないはず。USBaspのファームウェアをバージョンアップすれば消える。こちらの記事が詳しい。

実際の様子。

無事、LEDが点滅。

動作が遅い

Lチカは動いているけど、なんだかおかしい。なんだかどころではなく、明らかにおかしい。点滅速度が遅すぎる。点灯/消灯を1秒ごとに繰り返すはずが、点灯も消灯も7~8秒くらい掛かっている(続いている)状態。点滅はしているけど、ちっとも「無事」ではなかった。

いろいろ調べてわかったのは、ATmega328Pの初期設定がクロックを8分周するようになっているということ。そのため、動作速度が想定の1/8になり、LED点滅間隔は8秒ごと。

問題はフューズビットの既定値

その設定がフューズビット。下の表は、ATmega328の日本語データシートから引用したもの。

これのビット7(CKDIV8)。既定値が「0」でシステムクロックを8分周することになっている(負論理なのかな?)。ちなみに、CKSEL3~0がクロック源。「0010」でチップ内蔵クロックを指定している。

このページには、この「下位バイト」の他に、「拡張バイト」と「上位バイト」も掲載されている。既定値は拡張・上位・下位バイトの順に0xFF、0xD9、0x62と記載されている(ビットごとに記載されているけどここではHEXで表した)。

なんで8分周するようになっているんだろうかと思ったら、Vccによって上限周波数が決まっているからのようだ。例えば、下限電圧の1.8Vだと最高周波数は4MHz。下の表はデータシートの207ページから引用。

Vccが低い場合でも大丈夫なように、出荷時は1MHz動作にしているのだろう。

ということがわかったところで、実際のフューズビットを読み出してみる。USBaspをつないでいるので、そのままavrdudeで。

下から二行目、「E:FF, H:D9, L:62」とあり、データシート通り。ということで、この下位バイトのビット7を「1」にして書き込めばいいはず。

ここでは、別途インストールしたavrdudeを使ったけれど、Arduino IDEの中にもavrdudeは含まれている。

こっちを使っても大丈夫なはず(要するに、Arduino IDEもデバイスへの書込みにはavrdudeを使っているってこと)。

フューズビットを書き込む

では、フューズビットを書き込む。これもavrdudeで。オプションの説明はこちらのページが詳しい。

設定を変更したいのは下位バイト(のうちの1ビット)だけなので、下位バイトだけ書き込めば大丈夫だろう(上位バイトや拡張バイトは変えない)。「だろう」などと曖昧な書き方をしているけど、フューズビットをおかしなことにしてしまうと次回から書き込めなくなってしまうことがあるようなので慎重に(例えば、外部クロック指定にしてしまったら、外部クロックを接続しないと書き込みもできなくなるとか)。

そうすると、0x62のビット7を「1」にするので、書き込む値は0xE2。

せっかくなので、Arduino IDEに付属のavrdudeでやってみる。まずは、念のため情報の読み出し。

先程と同じく「E:FF, H:D9, L:62」と読めた。問題なし。なお、コンフィグファイルが必要なようで、探してみたところ一つ上の「etc」フォルダ内に「avrdude.conf」があったので、それを指定している。念のため、コマンドラインを書き出しておくとこう。

avrdude -c usbasp -C ..\etc\avrdude.conf -p m328p

では、いよいよ書込み。下位バイトのビット7を「1」にして、0xE2とすれば良いので、次のように指定する。

avrdude -c usbasp -C ..\etc\avrdude.conf -p m328p -U lfuse:w:0xe2:m

書き込めた。ベリファイも通っているので大丈夫だろう。念のため、もう一度読み出してみる。

「L:E2」と読めている。Lチカもちゃんと1秒間隔になった。

余談ながら、Arduinoとして使う場合には外部クロックの16MHzで動かすのでフューズビットをそのように設定する必要があるが、それはブートローダ書き込み時に一緒にやっているのだろう。

まとめ

ATmega328Pを内蔵クロック(8MHz)で動作させる場合、Arduino IDEで書き込むには次のように行う。

  • フューズビットでクロック分周をやめるように設定。
  • Arduino IDEの「ボード」で8MHz内部クロックのものを選択し、「書込装置を使って書き込む」を行う。

なお、これはATmega328PをArduino化せず、素のAVRマイコンとして動かす方法。装置に組み込んだATmega328Pは、ほとんどの場合はArduinoである必要はない(Arduinoブートローダを持っている必要はない)と思う。

だったら、Atmel Studioで開発してもいいのだけど、Arduino IDEを使うと開発が楽というメリットがある。一方、その分、余計な(と言ってはナンだけど)ライブラリがメモリを食ったり、オーバヘッドで処理に時間がかかったりするみたい。シビアな開発ならAtmel Studioで、そうじゃなければArduino IDEで楽に、といったところ(だと理解している)。


Arduino IDEで素のATmega328Pに書き込めるようになったので、今度はATtiny85に書き込めるようにしてみる。この手の情...