ArduinoISPを高速化する

# 動機

Arduino IDEにはArduino UNOなどのボードをAVRライターにする「[ArduinoISP.ino]()」が含まれています。

![ArduinoISP](http://img.dfm.lrv.jp/ArduinoISP/01.png)

> ArduinoISPの使い方は下記を参照ください

> - [Using an Arduino as an AVR ISP (In-System Programmer)](http://www.arduino.cc/en/Tutorial/ArduinoISP)
> - [Arduino IDEでATtiny他の開発（Arduino-ISP編）by kosakalabさん](http://make.kosakalab.com/make/electronic-work/arduino-ide-arduinoisp/)


私はArduinoISPを使って[ATtiny841](http://www.atmel.com/ja/jp/devices/ATTINY841.aspx)の開発を実施しているのですが、なんとこのマイコン、他のAVRと比べて明かに**ISPの書き込みが遅い（2分30秒かかる！）**のが悩みの種でした。

ATtiny841のFlashはページサイズが1ページ16バイトのものが採用されています。1ページ64バイトのATtiny85やATtiny84と比べて読み・書き回数が4倍に増えます。その分ISP実行時のコマンドが多く発行されるので遅くなっていると思われます。

当初ATtiny841の設定変更で改善を試みたのですがうまくいかなかったので、ArduinoISP.inoを高速化することにしました。

# 注意

今回は超遅いATtiny841のためにArduinoISPの高速化パッチを用意しましたが、他のマイコンでは書き込みがうまくいかなくなるかもしれません。

危険なので、あまり困ってないなら、標準版をそのまま使った方が良いです。
また、下記修正は Arduino 1.6.3で確認しました。

# 実施したこと

実施したことは下記の２つです。

1. ArduinoISPはPCと19200bpsで通信している。これを**115200bps**に変更。
2. ArduinoISP.ino内の（応答の調整も兼ねてると思われる）**ディレイを少なく**

変更方法を紹介しますが、くれぐれも標準のArduinoISP.inoを上書きせず、コピーを用意してくださいね。

## 1. シリアル通信速度を変更

ArduinoISP.inoのシリアル通信速度を変更するには、下記2つのファイルを修正します。

1. ArduinoISP.ino（ArduinoISPのスケッチ）
2. Arduino.app/Contents/Java/hardware/arduino/avr/programmers.txt

### 1-1. ArduinoISP.inoの修正箇所

ArduinoISP.inoの69行目くらいに、`Serial.begin(19200);`という箇所があります。

```cpp:ArduinoISP.ino
void setup() {
  Serial.begin(19200);  // <--ここを変更する
  :
}
```

これを、`Serial.begin(115200);`に変更します。

もう１カ所、シリアル通信速度の高速化に伴い修正が必要な箇所があります。
[ArduinoISP @57600 baud instead of 19200](http://forum.dev.arduino.cc/index.php?topic=48784.0)で紹介されている内容ですが、要は`heartbeat()`というLEDをチカチカさせる関数があって、この中のdelayが大きすぎるようです。

めんどくさいので、`heartbeat()`の呼び出し箇所でコメントアウトします。

```cpp:ArduinoISP.ino

void loop(void) {
  // is pmode active?
  if (pmode) digitalWrite(LED_PMODE, HIGH);
  else digitalWrite(LED_PMODE, LOW);
  // is there an error?
  if (error) digitalWrite(LED_ERR, HIGH);
  else digitalWrite(LED_ERR, LOW);

  // light the heartbeat LED
  heartbeat();  // <--これをコメントアウトする。
  if (Serial.available()) {
    avrisp();
  }
}

```

### 1-2. programmers.txtの修正箇所

programmers.txtは、Arduino IDEで選択できるAVRライターを定義するファイルです。
この中に、ArduinoISP.inoを書き込んだArduinoの定義もあります。

**Arduino as ISP**

```programmers.txt
arduinoasisp.name=Arduino as ISP
arduinoasisp.communication=serial
arduinoasisp.protocol=stk500v1
arduinoasisp.speed=19200
arduinoasisp.program.protocol=stk500v1
arduinoasisp.program.speed=19200
arduinoasisp.program.tool=avrdude
arduinoasisp.program.extra_params=-P{serial.port} -b{program.speed}
```

上記の`arduinoasisp.speed=19200`と`arduinoasisp.program.speed=19200`のパラメータを書き換えることで高速化できますが、この定義を書き換えてしまうと、オリジナルのArduinoISP.inoを焼き込んだArduinoが使えなくなってしまいます。

そこで、上記定義をマルっとコピーして、下記のようにすると良いと思います。

```programmers.txt

# オリジナル
arduinoasisp.name=Arduino as ISP
arduinoasisp.communication=serial
arduinoasisp.protocol=stk500v1
arduinoasisp.speed=19200
arduinoasisp.program.protocol=stk500v1
arduinoasisp.program.speed=19200
arduinoasisp.program.tool=avrdude
arduinoasisp.program.extra_params=-P{serial.port} -b{program.speed}

# 高速化版
arduinoasisp_115200.name=Arduino as ISP(115200)
arduinoasisp_115200.communication=serial
arduinoasisp_115200.protocol=stk500v1
arduinoasisp_115200.speed=115200
arduinoasisp_115200.program.protocol=stk500v1
arduinoasisp_115200.program.speed=115200
arduinoasisp_115200.program.tool=avrdude
arduinoasisp_115200.program.extra_params=-P{serial.port} -b{program.speed}
```

上記追加が終わったらArduino IDEを再起動してください。
すると、`Tools>Programmer`メニューから`Arduino as ISP(115200)`が選択できるようになります。

![ArduinoISP](http://img.dfm.lrv.jp/ArduinoISP/02.png)

これでPCと高速化したArduinoISP.inoを書き込んだArduinoとの間で115200bpsでシリアル通信できるようになりました。

## 2. ArduinoISP.ino内の（応答の調整も兼ねてると思われる）ディレイを少なく

これまでのシリアル通信速度の変更だけでも、ATtiny841の書き込み速度で30秒近く改善します。（2:30→2:00くらいに改善）
しかし、2:00でもまだ遅いですよね。

そこで、さらなる調整をします。
ATtiny841が遅いのは、Flashのページ書き込みなので、そこを速くしたい。
そこで、ArduinoISP.inoの`write_flash_pages()`内のdelay()待ち時間を少なくする方針で調整を行いました。

修正箇所は、ArduinoISP.inoの141行目にある

```cpp:ArduinoISP.ino
#define PTIME 30
```

の部分です。`PTIME`で定義した時間、`write_flash_pages()`から呼び出される`commit()`の中の`delay()`で待ってしまいます。

最終的には、

```cpp:ArduinoISP.ino
#define PTIME 8
```

まで減らしました。`7`だとうまく書き込めなかったので、限界のようですw

# まとめ

ArduinoISP経由でATtiny841を45秒程度で書き込めるようになりました。
これでも遅いのですが、なんとか許せるレベルになったかと。

もちろん、ATtiny841以外も速くなったので、今後これを使っていこうと思います。

> もっと良い方法等あれば教えていただけると嬉しいです！