Arduino でAVR マイコンのプログラム

前回、手持ちのArduino MicroでAVRマイコンのライターを作成したので、それを使ってAVRマイコンをプログラムしてみる。

用意したのはAtmega168Aという28ピンのチップ。 買った状態では内部発振の1Mhzで動くようになっている。内部発振では1Mhzと8Mhzを選択できる。ちなみにArduino Unoは同系列の328P

まずは手始めにArduinoのIDEを使ってArduinoのスケッチを書き、コンパイルさせてAVRチップにアップロードしてみる。手順さえ間違わなければ これでちゃんと動作してしまうんである。

168AVRのチップのピン配列(PortB,PortC,PortD etc.,) と Arduino式の(D0~D13,A0~A5) ピン配列の関係についてはここにマッピング情報がある。 LEDのBlinkスケッチを使う場合、LEDを接続するD13に該当する出力ピンはPB5である、ということがわかる。

蛇足ながら、PB6とPB7はArduinoボードではクリスタルに接続されているために入出力ピンとしては使えないが168を内部発振で使う場合には使用可能、ただしDigitalPinの定義がないので、Cに落とした記述が必要。

IDEのメニューからTarget Board を選ばなければならいないが、当然のことながらAtmega168などという選択肢はない。ので、Arduino Pro Mini(with 8Mhz Atmega168)というのを代わりに選ぶ。

ただし、AtMega168は工場出荷時の内部クロックは1Mhzに既定値設定されている(内部発振8Mhzを8分割) 上記のBoard 選択では8Mhz 用にコンパイラがタイミングループを調整するので1秒の点滅を指定すると8秒の点滅になる。 これが嫌ならAVRDUDEを使ってAtmegaのFuseを書き換え内部クロックを8Mhzに設定するか、または Arduino/hardware/arduino/boards.txt にならって1Mhz のAtmega168をバリエーションとして追加してあげる必要がある。
8Mhzに設定するにはAVRDUDEを使ってフューズ設定を書き換えることになる。

C:\Program Files (x86)\Arduino\hardware\tools\avr\bin\avrdude.exe-c arduino -p atmega168 -P com5 -U lfuse:w:0xe2:m

Boards.txtへのアイテムの追加はこの記事が参考になる。

Arduino IDEではShiftキーを押しながらアップロードボタンをクリックするとUSBに接続されているライターを使ってターゲットBoard(Arduinoまたはマイコンチップ)にコードをアップロードしてくれる仕組みになっているが、このためにはToolメニューの中からプログラマを指定する必要がある。Arduino Unoをライターとして使う場合は”Arduino as ISP” という項目を選べばよいのだが、自分が使っているArduino Micro はこれでは動作してくれない。(Leonardでも同様) この設定はArduino/hardware/arduino/programmers.txtというファイルにあるが、Unoに指定の

Arduinoisp.protocol=stk500v1

ではうまくリセットがかからないようだ。以下のようにこのprogrammers.txt にMicro/leonard 専用の選択肢を追加してIDEを再起動し解決

arduinoisp.name=Arduino Micro or Leo as ISP
arduinoisp.communication=serial
arduinoisp.protocol=arduino
arduinoisp.speed=19200

これで、Atmega168のPB5にLEDを接続し、BlinkスケッチをダウンロードするとLEDが点滅を始める。

Arduinoを使うと豊富なライブラリーが使えるという利点があり、ATtinyをArduino IDEでプログラムしようというプロジェクトもあって資料も豊富だ。

欠点としては

1.ターゲット用にBoards.txt項目を追加する必要がある。 ただし、一度の作業。

2.Arduino IDEの使い心地。 これは個人的な嗜好の問題だがAVR用にC/C++をコーディングするのならArduino IDEよりも強力な無料のIDE (Eclipse with AVR  plugin [Linux, Windows],   AtmelStudio [Windows])が存在する。

Arduino でAVRプログラムライター

先回、ArduinoのIDEに同梱されているスケッチでAVRプログラマを作成できると知識だけで(無責任に)書いたのだが、本当にできるんだろうね、と検証してみたので結果を書いておく。

結果  できました。

前置き:
ATMELのサイトを眺めてみると、もっとも安価でかつポピュラーな純正プログラムライターはATMEL AVRISP MK2 なるものだが、価格は、とみると$34となっている。 本格的に開発に使おうとするならAVRDragonというのが良さげだが、これが$49.

MK2はArduino Unoの値段とほぼ同じ。 またAdaFruit.com でAVRプログラマシールドなるものを売っているが、シールドにZifソケットや328Pチップをつけてくれているとは言え、$17. これにArduinoを購入することになるので$50くらいの出費になる。これまたAVRDragonとほぼ同じ値段。

Arduino Proとか$10くらいの廉価品を買ってきてセットアップすれば本格的なライターより安くは組めるだろうが同じくらいの出費をするなら専用ライターを買ったほうが良いに決まっている。(Atmel Studioという統合型のIDEでデバッグなどにそのまま使える) Arduinoを使ってAVRプログラマを作成するというのはどこかに使っていないArduinoが転がっていて、かつAVRとC(++)をちょっと試してみようか、という状況ならともかく、普通はなるべく安いライターを探すことをまず考えるだろう。ま、arduinoを使えば、AVRに挫折したときに改めてArduinoとして再利用できる、という利点はある。実はAvrdudeを使えばプリンタ用のパラレルポートから直接ワイヤーを配線してAVRマイコンをプログラムすることが可能(つまりライターすらいらないの)だそうだが、最近のパソコンではパラレルポートなど実装していない。 (追記:amazon.comで$6のUSB ISPプログラマを売っているのを見つけた。現在のところこれが最安値)

本文
で、自分の場合、うっかり買ってしまったArduino Microという小さなArduino boardが手元に転がっていた。 そこで、このArduino Microに Arduino IDEのメニューのSampleの中から”Arduino ISP”というサンプルスケッチをアップロードし、このプログラムの中に書いてある通りにブレッドボードに配策し、試してみても動かない。

延べ4時間くらい、はまってしまったのだが、ネットを調べて最終的にはマイコンチップをプログラムできるようになった。 要点をかいつまんで書いておく。
1.Arduino MicroはArduino Leonardと同じく32u4というマイコンチップを使っている。 従前のArduinoが使っていたAtmega328Pというチップではない。このため、DigitalPinに対する入出力ポートの割り付けが従来とは異なっている。
2.このため、上記のスケッチで #define RESET SS となっている部分はUnoなどではPin10があてがわれるが、マイクロとLeonardではPin17に定義されている。 このPin17、RX_LEDへと接続されてしまっているので、上の表記は #define RESET 10 とPin 10に明示的に変更してやる必要がある。
3.同じようにSPI用のピン3本(MOSI,MISO,SCK) スケッチ上のコメントでは11,12,13の3つの出力に接続するような指示になっているが、Micro (Leonardも)の場合、SPIはこれらのピンにはマッピングされていない。幸いなことにMicroの場合、MOSI,MISO,SCKの3本がヘッダーピン配列に物理的に存在しているので、ここに接続してやることになる。(Leonardの場合はUnoと同じヘッダーピン配置というのが災い?してこれらのピンは存在しないので、ICP用の6本ピンヘッダーの当該PINにそれぞれ接続することになる。(ただし、ResetはPin10に接続)

回路図的にはこんな感じ。

Arduino Micro as AVRISP
Arduino Micro as AVRISP ダブルクリックで大きな図を見る

実際のブレッドボードへの配策はこんな感じ。

AVR ISP using Arduino Micro (at left)
AVR ISP using Arduino Micro (at left)左のArduinoMicroで右のATmega168をプログラムする図

手順だけ羅列すると
1.Arduino のSample sketchからArduino ISP をIDEに読み込み、#define reset SS を #define reset 10と書き換える。
2.”Arduino as ISP”スケッチをArduino Microにアップロード
3.上のようにワイヤを配策。LED3点については無くてもOK(だがあると恰好よい)
4.CファイルをAVR-GCCでコンパイルし、生成できたHEXファイルをAVRDUDEを使ってアップロード, あるいはArduino IDEでスケッチを作成、sift-Uploadでターゲットをプログラム。(この部分の説明は記事を改めていずれそのうち)

Arduino とは何か

今まで何度も取り上げていて、いまさら何かと切り出すのもなんだが、一度整理しておく。
はじめてArduinoのをみたのはおそらく2010年の年末だ、なんと近所のRadio Shackで入門本と一緒に売っていた。 (RadioShackが昔のように、電子工作の小物を置くようになったというのは非常にうれしいことである。最近はRaspberry PiとかBeaglebone Blackの入門キットも売っている。 閑話休題)
BasicStampに比べると値段が手ごろだったので購入したのだが、このときの解釈は Arduino = 開発ボード

しかし、入門本を読み、LEDの点灯を試み、サーボモーターやリレーの操作、さらには16×2ケタのLCDを表示するという一応のイニシエーションを行ったあと、改めて眺めてみれば、Arduino というのは開発ボード(だけ)ではなかった。

ボードを購入したあと、ユーザーはArduinoのサイトから開発環境をダウンロードしてプログラミングすることになる。 このときSketchという言語でプログラムを書くのだが、これはWiringという言語がもとになっている。 そしてWiringもSketchも基本的にはC言語を使ったFrameWorkだ。

IDEのGUIはJavaでできているものの、そのバックグランドで動いているものはAVRマイコン用に特化したGCC(AVR-GCC)であり、AVRDUDE(AVR Downloader/UploaDEr) という、マイコンプログラムの先人達によって鍛えられたAVRマイコン用のTool chainである。

ではArduino環境は従来のマイコン開発環境と比べると何が違うのか。
-ハードもソフトもできる限りのアブストラクト化がなされている。
という一点につきる。 AVR8はportB,C,D それぞれ8ビットが入出力になっており、本来のATMEL のC言語の操作ではこれらのポートレジスターにビット操作での書き込みをおこなっていた、つまりPortBの ビット0とか6とかを気にしてコーディングしていくのだが、 アブストラクション(抽象化)を行った結果、 ArduinoのユーザーはDigital pin 0~13, Analog input pin 0~5 という入出力ピンの操作だけを考えればよいようになっている。
スケッチもSetup()という初期化ルーチンとloop()という繰り返しルーチンを書けば、あとはTool chainがコンパイルし、プログラムをアップロードしてくれる。 このからくりはArduino のプログラムフォルダー(自分のWindows環境ではC:\Program Files (x86)\Arduino\hardware\arduino\cores\arduino)の中のmain.cppを眺めてみるとなんとなく見えてくる。

#include <Arduino.h>

int main(void)
{
	init();

#if defined(USBCON)
	USBDevice.attach();
#endif
	
	setup();
    
	for (;;) {
		loop();
		if (serialEventRun) serialEventRun();
	}
        
	return 0;
}

何故にwhileを使わず、for(;;) という構文を使っているのか、という疑問はさておき、Arduino のスケッチはこの上のmain.cppに組み込まれるsetup()とloop()関数を定義しているというわけで実際にコンパイルされるのはC++のソースだった。

Arduinoでは多くの周辺デバイスとのインターフェース、通信プロトコルなどはすでにライブラリーで提供されている。 またArduino自体にマイコンチップをプログラムできるような周辺回路およびブートローダーが組み込んてあるからチップにコードを焼くための専用プログラマが必要ない。

下のコードは、入門本で一番最初に出てくるLEDを点滅させるためのスケッチコード

int led = 13;
void setup() {                
  // initialize the digital pin as an output.
  pinMode(led, OUTPUT);     
}

void loop() {
  digitalWrite(led, HIGH);   // turn the LED on (HIGH is the voltage level)
  delay(1000);               // wait for a second
  digitalWrite(led, LOW);    // turn the LED off by making the voltage LOW
  delay(1000);               // wait for a second
}

ところがArduinoのIDEがインストールされたPC環境ではすでに上に述べたようにGCCとかtoolchainとかが導入済みになっているため、 以下のようなプログラムををCで書いて、コマンドラインを使ってコンパイルし、Arduinoへ書き込みをすることが可能になっている。 下のコードでやっているのは上 のスケッチと同じくPin 13を点滅させることだが、ArduinoスケッチのProgramがコンパイルしてアップロードするサイズが1000バイト以上あるのに対し、下のプログラムは200バイト以下になる。abstractionの代償はプログラムのサイズということらしい。


#include <avr/io.h>
#define F_CPU 16000000UL
#include <util/delay.h>

#define LED      PB5
#define LED_DDR  DDRB
#define LED_PORT PORTB
#define DELAYTIME 500 //delay 500ms. See _delay_ms definition

#define setBit(sfr, bit)     (_SFR_BYTE(sfr) |= (1 << bit))
#define clearBit(sfr, bit)   (_SFR_BYTE(sfr) &= ~(1 << bit))
#define toggleBit(sfr, bit)  (_SFR_BYTE(sfr) ^= (1 << bit))
long i;
int main(void)
{
    // setup()
    setBit(LED_DDR, LED);                      /* set LED pin for output */

    // loop()
    while (1) {

	    setBit(LED_PORT, LED);
	    _delay_ms(DELAYTIME);
	    clearBit(LED_PORT, LED);
		_delay_ms(DELAYTIME);
	    
    }
}

while分がArduinoスケッチのloop()に相当し、その上がsetup()に相当する。
上をblink.c というファイル名で保存し、Arduinoがつながった状態でコマンドラインから以下を実行するとLEDの点滅を始める。(もちろんserial portによってCom5部分は異なる)

>avr-gcc -Os -mmcu=atmega328p blink.c -o blink.o
>avr-objcopy -O ihex blink.o blink.hex
>avrdude -p atmega328p -c arduino -P com5 -U flash:w:blink.hex:i

コマンドライン3行をターミナルモードで打ち込むわけだが、Batch file にしてもよい。その実行はarduinoのアップロード機能を使うのに比べて恐ろしく早い、ということも実感できると思う。
Arduinoを使うのは野球のグローブをつけて裁縫をやるようなものだ、とかなんとか言った人がいる。 抽象化が過ぎてマイコンをプログラムしている気がしない、ということで、たしかに熟練者の目からみればもっともな話かもしれないが、Arduinoの一番の目的はマイコン学習を始めるための第一歩を容易にすることにある。(と思う) 豊富なサンプルコードやライブラリーを見るとその楽ちんさは尋常ではない。ハードとソフトの両方への入門が可能な環境になっている。 ずうっとArduinoとスケッチでいいじゃない、十分だよ、という気にもなってくる。 それにArduino IDEのサンプルメニューを眺めているとわかるが、Arduino自体をAVRマイコンのプログラマにしてしまうスケッチがご丁寧に同梱されている。 Arduinoにものたりなくなってきたら、(入出力が6本以下のマイコンでできることを、何が悲しゅうて28ピンのマイコンプラス不要な回路を載せたボードでやってまんねん、自分はミニマリスト的なアプローチがすきやねんとか思いはじめたら)ATtinyのチップだけ100円で購入してArduinoを使ってプログラムを焼くことも可能になっているわけだ。