Arduinoで、小っちゃいIC（ATTiny）を使う方法

![ArduinoUNO](http://img.dfm.lrv.jp/compress/UNO.png)

# Arduinoで、小っちゃいIC（ATTiny）を使う方法
## ちっちゃいICを使いたい！

Arduino、始めたばかりですが超楽しいです。（いや始めたばかりだから楽しいのかw）

お金が無いせいで、シールドとかにはまだ手を出してなくて、Arduino UNOとブレッドボード、それと安く手に入る部品だけを使って遊んでいます。
ブレッドボードで動作確認したら、ICをUNOから引き抜いて、ユニバーサル基盤に作った回路に組み込んでみたり。こうした使い方をしていることもあり、[ATmega328P](http://akizukidenshi.com/catalog/g/gI-03142/)を追加で買ったりしてるのですが、ATmega328Pは1コ250円もして、少々お高いのが気になってました。

それに28PIN-DIPって簡単な用途には大きくて配線もたいへん。
将来量産（なにを？！いや何か絶対！w）を見据え、もっと物理的にちっちゃいICを試してみたい。でも表面実装(SMD)版とかハンダ付け超ムリ！

### ATTinyはDIPでもちっちゃい！
というわけで目をつけたのがATTinyシリーズ。DIP版でも足の数が少ないので、ちっちゃいです。特に13A！
![Writer](http://img.dfm.lrv.jp/compress/ic.png)

**上からATTiny13A、ATTiny2313、一番下がATmega328P**

試しに20本足の[ATTiny2313-20PU](http://akizukidenshi.com/catalog/g/gI-01600/)と、8本足の[ATTiny13A](http://akizukidenshi.com/catalog/g/gI-02911/)を購入してみました。

**ざっくりSPEC表**

|SPEC|ATmega328P|ATTiny2313|ATTiny13A|
|:--:|:--:|:--:|:--:|
|価格<br>(2014.1.26現在)|[250円](http://akizukidenshi.com/catalog/g/gI-03142/)|[150円](http://akizukidenshi.com/catalog/g/gI-01600/)|[50円](http://akizukidenshi.com/catalog/g/gI-02911/)|
|DIP PIN数|28|20|8|
|ROM|32Kbyte|2Kbyte|1Kbyte|
|RAM|2Kbyte|128byte|64byte|

ATTinyは大きさだけでなく、性能も、ちっちゃい！w
どこまで使えるかわかりませんが、ちょっと触ってみようと思います。

## 1. Arduino UNOで、ちっちゃいIC(ATTiny)を開発する

Arduino UNOがあれば（それが互換機でも）ATTinyの開発ができます。UNO以外に必要なのは、ブレッドボードと抵抗、コンデンサ、ジャンパーピン、LEDなど。Arduino入門編をやってる方は持っているものばかりだと思います。

Arduino UNOでATTinyなどを開発するやり方は、[kosakalab](http://make.kosakalab.com/)さんの、下記記事で超詳しく紹介されています。
[Arduino IDEでATtiny他の開発（Arduino-ISP編）](http://make.kosakalab.com/make/electronic-work/arduino-ide-arduinoisp/)

私も記事の通りに進めることでATTiny13AとATTiny2313でのLチカに成功しました。
素晴らしい記事を書いてくれた[kosakalab](http://make.kosakalab.com/)さんには、本当に感謝です！

## 2. ROM/RAM使用量を確認できるようにする

### ROM使用量はIDEでビルドするだけで表示される

ATTinyはROM（正確にはFLASHROM）やRAM（正確にはSRAM）が小さいので、プログラムも小さくしなければ入らなくなります。
Arduinoのプログラムが、どのくらいROMやRAMを消費するか、Arduinoのいわゆる「Lチカ(blink)」を使って確かめてみましょう。

** Arduino IDEに付属のBLINKのコード (コメントは外してあります) **

(ATTiny対応にPIN番号だけ変更してあります。)

```cpp
	int led = 0;	// ATTiny2313用に変更
	void setup() {                
	  pinMode(led, OUTPUT);
	}
	
	void loop() {
	  digitalWrite(led, HIGH);
	  delay(1000);
	  digitalWrite(led, LOW);
	  delay(1000);
	}
```
これをビルドしてみます。すると、下記のような表示が。
![910byte](http://img.dfm.lrv.jp/compress/910.png)

910byte。え！Lチカだけで？こんなに大きいんだ。。。13A、Lチカ以外できないんじゃ？
と、一抹の不安を感じつつ。。
910byteというのはFLASH ROMの使用量です。まだRAMはどのくらい使ってるのかは解りません。

### RAM使用量の調べ方

というわけで、RAM使用量も確認してみます。

ArduinoのRAM使用量の調べかたは、下記で紹介されています。
[Arduinoでのメモリ使用率の調べ方](http://nishi-monodukuri.blog.eonet.jp/default/2013/06/arduino-b08d.html)

なんと、elfファイルからdumpしろ。ということらしいですね！
いきなり組み込み系な感じになって来ました。なんかArduinoの可愛さが薄れていくような。。。w

いえいえ、ちっちゃいATTinyのためです。やってみましょう。
	> avr-objdump -h プロジェクトファイル名.elf
と実行してみます。

![objdump](http://img.dfm.lrv.jp/compress/dump1.png)

Lチカのプログラムだけですと、.textと.bssしか出てきませんでした。よく見るとconstデータがありませんね。
これだとちょっと説明にならないので、少しプログラムを改造して、もう1度やってみます。
(Lチカのタイミングを少しおかしくしただけのものです)

```cpp
	int cnt;
	const int led = 0;
	const int a[] = {200,400,800,1000}; // Lチカのタイミング

	void setup() {                
	  pinMode(led, OUTPUT);     
	}
	
	void loop() {
	  int v;
	  v = a[cnt];
	  cnt++;
	  if(cnt == 4){
	    cnt = 0;
	  }
	  digitalWrite(led, HIGH);
	  delay(v);
	  digitalWrite(led, LOW);
	  delay(v);
	}
```
今回は、LEDのピン番号の変数と
このスケッチをビルドすると、Lチカタイミング用のテーブルをconstに追加してみました。
これをビルドしてみますと、

![982byte](http://img.dfm.lrv.jp/compress/982.png)
![objdump](http://img.dfm.lrv.jp/compress/dump2.png)

となりました。const変数を追加したので、今度は.dataというものが出てきました。
長くなりましたが、ROMとRAMの容量をまとめると、

	ROM使用量 = .textと.dataの合計 (今回の例では 982byte)
	RAM使用量 = .bssと.dataの合計  (今回の例では  19byte)

となります。
(RAMはもう少し複雑で、ヒープやスタックと共有で利用していますので、正確に言うと上記以外にも使われています)
RAMの使われ方については、下記サイトの説明がとても参考になります！
[Arduino Unoのメモリ](http://garretlab.web.fc2.com/arduino/introduction/memory/index.html)

## 3. プログラムをちっちゃくする！

さて、いよいよプログラムをちっちゃくするのに挑戦します！
そんなんかんたんにできるんか〜？と気になるところですが、さすがはArduino、さすがはインターネット！
いろいろな手法があるようです。

### ROMを減らす方法。単純に処理する関数をつくろう。

#### 簡単にやれることから  
Arduinoでは、いろいろな関数やライブラリが利用できます。
これらは、とても「書きやすく、とっつきやすい」ものですが、中を覗いてみると、様々なケースに対応できるようにするためか、結構なコード量だったりします。
先ほどのLチカにも出て来た`pinMode()`や`digitalWrite()`を置き換えるだけでも結構削減できるので、やってみたいと思います。  
※`pinMode()`や`digitalWrite()`がどのような処理を行っているかについては、下記サイトで詳細に解説されています。  
[Arduionoソフトウェアの内部構造: pinMode()](http://garretlab.web.fc2.com/arduino/inside/hardware/arduino/sam/cores/arduino/wiring_digital.c/pinMode.html)
[Arduionoソフトウェアの内部構造: digitalWrite()](http://garretlab.web.fc2.com/arduino/inside/hardware/arduino/sam/cores/arduino/wiring_digital.c/digitalWrite.html)  

上記サイトの情報をもとに、pinMode()とdigitalWrite()を書き換えてみます。
実はポート叩いてるだけなんで、マクロを作ります。

```cpp
	// ATTiny2313用。D0ピンIOマクロ
	#define PMD0_OUTPUT() (DDRD |= _BV(0))    // pinMode(0,OUTPUT)
	#define DWD0_HIGH()   (PORTD |= _BV(0))   // digitalWrite(0,HIGH)
	#define DWD0_LOW()    (PORTD &= ~_BV(0))  // digitalWrite(0,LOW)
```

あとは、pinMode()やdigitalWrite()と置き換えるだけ。

```cpp
	int cnt;
	// const int led = 0; // ←マクロにしたので要らなくなりました。
	const int a[] = {200,400,800,1000}; // Lチカのタイミング

	void setup() {                
	  PMD0_OUTPUT();     // pinMode(0,OUTPUT)
	}
	
	void loop() {
	  int v;
	  v = a[cnt];
	  cnt++;
	  if(cnt == 4){
	    cnt = 0;
	  }
	  DWD0_HIGH(); // digitalWrite(0,HIGH)
	  delay(v);
	  DWD0_LOW();  // digitalWrite(0,LOW)
	  delay(v);
	}
```

でビルドしてみると。
![624byte](http://img.dfm.lrv.jp/compress/624.png)
982→624byte！300byte以上も削減できました。

#### トレードオフできることはトレードオフしてみる。  

さきほどのpinMode()とdigitalWrite()の例は、もとある機能を変えずにコード圧縮を実現していました。
しかし、全ての機能を正確に実現することは、そんなに大事でないかもしれません。
たとえば、さきほどのLチカ。
Lチカであれば、LEDの間隔が多少ずれても、そんなにたいしたことではないはずです。
精密なタイマーの場合は大問題ですが、そもそも精密なタイマーにdelay()は使わないでしょうw
というわけで、`delay()`にもメスを入れてみます。かなり大胆にw

```cpp
	extern volatile unsigned long timer0_millis;
	void deeeelay(unsigned long ms) {
	  unsigned long exptim = timer0_millis+ms;
	  while (timer0_millis < exptim){}
	}
```

もう、あまり人におススメできる内容から脱線している気がしますw
冒頭で外部参照している`timer0_millis`は、hardware/arduino/cores/arduino/wiring.c
などで宣言されているグローバル変数で、起動時からの経過時間(但し限界まで行くと0に戻りまたカウント)をmsで記録しています。`millis()`を使っても良いのですが、関数呼ぶ分オーバーヘッドがあるので、直接参照しています。
で、中は見ての通りで、指定された時間が来るまで永久ループしてるだけです。
で、コレの何が「トレードオフ」なのかと言うと、delay()の1/1000の精度しかありません。気になる方はdelay()側のコードを見てください。


上記を使うコード部は、`delay(v)`を`deeeelay(v)`にするだけなので、割愛します。
ビルドしてみると、
![530byte](http://img.dfm.lrv.jp/compress/530.png)
530byte！
さらに100byte近く削減できました！

これ以上は、違うところ（本来触ってはいけないところ）を触らなければいけなさそうな気がします。。ので、そろそろ止めときます。（ここに書くのではなく、自分で勝手にコッソリ進めますw）

※実は今、ATTiny13AでTone()ぽいものを無理矢理動かしたくて、wiring.cを改造しまくってたり。。。

### RAMを減らす方法。.dataを減らしてROMへ。PROGMEMを使う。

さて、最後に.dataが使用するRAM容量を減らす方法を紹介して、この記事をしめたいと思います。
.dataはROMにも入ってるくせにRAMにも入っているという邪魔者です。
「データは入れときたいけど、使うときすぐに使いたいから起動するときROMからRAMに読み込んどく」ということをやってるかららしいです。
でも、大きなデータって主に配列だと思うのですが、これ、全部の要素を頻繁に上から下まで順番に読み込む、なんて使い方するんでしょうか。普通はあまりしないと思います。
通常は、何番目のデータを読むか？という指定をして、ダイレクトに使う部分のデータだけを読み込むことの方が多いと思います。こうした使い方だと、PROGMEMという方法が使えます。

使い方は、下記ページでとても詳しく教えてくれます。教わりました。
[Arduino Unoのメモリ](http://garretlab.web.fc2.com/arduino/introduction/memory/index.html)
※上記記事はArduino UNOを例に記載されていますので、ATTinyだとメモリ量やアドレスなどが異なります。

## まとめ

ATTinyに入れられるのは、ちっちゃいプログラムだけ！ちっちゃいは正義！ということでした。

最後まで読んでいただき、ありがとうございました！
間違いなど、ありましたら教えて頂けたらうれしいです。どうかよろしくお願いします〜。

**オマケ**
Arduinoで作ったBeep音楽器です。(これはATTinyではなくATmega168P使いました)
![beepSynth](http://img.dfm.lrv.jp/compress/beepSynth.jpg)
[InstagramにショートMovie Upしてます！]http://instagram.com/p/inYeIpnCkl/

## つづき

>2014.12.17更新
[つづき](http://qiita.com/tadfmac/items/3a42a641531f2c3679a1)を書きました！いろいろあるATTinyを何点かピックアップして紹介してみました〜！