Arduino PRO MINIのフラッシュメモリの消去と書き換え

概要

Arduino PRO MINIを使った研究(?)をしていて失敗してしまい、Arduino IDEからスケッチの書き換えができなくなってしまった。その上、ArduinoISPスケッチを使ったブートローダーやスケッチの書き込みもエラーが起きてできなくなった。

回復するため、もう1枚のPRO MINIをプログラマとして使いArduinoISPスケッチで復旧した話。

Arduino PRO MINI
Arduino PRO MINI ここに配線を追加してISPとターゲットにした。

問題のスケッチ

PRO MINIのクロックと電圧はそのままで省電力化を試みるため、内蔵のウォッチドッグタイマー(wdt)の動作との関係を調べようとしていた。#include <avr/wdt.h> して、wdt_disable()  とか書いてみようとしていたのだけど、不用意にも wdt_enable(0) と書いてしまってニッチもサッチも行かなくなってしまったのだった。

もともと何をやろうとしていたかと言うと、

  • タクトスイッチを押したらスリープが解除されるよう、attachInterrupt() する。
  • スリープに入る。
  • スリープから抜けたらPRO MINI上のLED (D13) を1秒間点灯する。

という具合。ブレッドボード上ではPRO MINIのD2とGND間にスリープ復帰用のタクトスイッチを配置した回路を使っている。タクトスイッチ操作によるスリープ復帰の確認や、消費電流の比較なんかをしていた。10行目に wdt_enable(0); を書くまでは意図通りに動いていた。

だが wdt_enable(0) ; と書いてしまったことで、

  • wdt_enable(0) により15msecでタイムアウトするカウンタが動作を開始する。
  • sleep_mode() の呼出しでスリープに入る。
  • スリープ中もwdtは有効だから、15msec後にタイムアウトしマイコンにリセットがかかる。
  • setup() から実行を再開する…永遠に。
  • 見た目の症状としては、D13に接続したLEDが超高速に点滅を繰り返していた。
    追記 : ブートローダーのソースを見て分かったのだけど、LEDを点灯させていたのはスケッチではなくてブートローダーのようである。そうでなければ点灯する理由がない。

この状況では、シリアル入力を受信している最中にもwdtによるリセットがかかってしまうから、PRO MINIのブートローダは入力を検出できないようである。Arduino IDEにて「マイコンボードに書き込む」をクリックしてみると以下のように表示された。

リセットスイッチを押しながら転送開始するなどしてみたが効果はなく、しょうがないのでPRO MINI内をきれいさっぱり消してしまうことにした。”The Simple” が336円(送料込)で売っているから、何も考えずに捨ててしまうことも考えましたが。

ArduinoISPによるスケッチの書換え

AVRマイコン内のEEPROMやフラッシュメモリを書き込むための ArduinoISP というスケッチを使って、スケッチの内容を書替えることにした。
このスケッチは、Arduino IDE (1.6.7版を使用中) にスケッチ例として付属している。使い方については、このスケッチのコメントや、https://www.arduino.cc/en/Tutorial/ArduinoISP を参考にした。

ISPとは、In-System Programming の略で、Arduino によく使われているAtmel社のATmegaマイコンシリーズでは、SPIシリアルインタフェースを介して、内蔵フラッシュメモリのプログラムの更新等ができるようになっている。ArduinoISPというスケッチは、シリアル接続を介してPC (Arduino IDE) からのコマンドを解釈したり、転送すべきデータを受け取ったりし、その内容をSPIを介してターゲットのAVRマイコンに送り込む機能を持っている。

PRO MINIを使ったISP

参考にしたページにはArduino UNOを使った配線図がでていたのだけど、手元に無事なPRO MINIがあったので、ISP側にもPRO MINIを使うことにした。ブレッドボードの実体配線図ではよく分からないので回路図っぽい配線図に描き直した。SPI接続用の3本とターゲット側のRESETをコントロールするためのピンが1本。そしてISPスケッチの動作状況を表すLEDが3つ。

 

Arduino as ISP. 右がISP,左がターゲット

こういった構成にしてArduinoISPスケッチをISPとする側(回路図では右側のPRO MINI) に送り込み、念のためリセットして開始させると、D9につないだ緑色のLEDが点灯した。準備オーケーのはずなので、ターゲット側 (回路図左側)にも+5Vを与え、Arduino IDEのツールメニューにて下図のように書込み装置を選択した。この段階でも、ターゲット側D13のLEDは高速点滅のままだった。

書込み装置の選択

Arduino IDEでは、ツールメニュー内の「マイコンボード」として書込み先のArduinoの種類(PRO MINI)を選択し、「書込装置」として”Arduino as ISP” を選択する。
今回はISPもターゲットもPRO MINIなので「マイコンボード」の選択を変更する必要はないが、例えばArduino ADKをISPとして使うような場合には、もともとはArduino ADKになっているはずなので変更することになる。

スケッチの書込み (書込み装置を使って書き込む)

問題のスケッチを上書きすればオーケーだろうと思ったので、IDEで無難なスケッチを開き、スケッチメニューにある「書込み装置を使って書き込む」を選択した。
ISP側のPRO MINIにはArduinoISPスケッチが動作しているとはいえ、「マイコンボードに書き込む」を選んでしまうと、ISP側のPRO MINIのスケッチが書き換わってしまうことに注意。「書込装置」として”Arduino as ISP“を選択していても、この動作は変わらないようだった。

PRO MINI as ISP
左側がターゲット、右側がISP

普通のブレッドボードに2つのPRO MINIを載せ、ISP側はAE-FT231Xに接続している。

書込みを開始するとISP側に接続したLEDが点滅したが、以下のようなメッセージが表示されて失敗した。

ターゲット側で高速に点滅するLEDはD13に接続されているわけで、この信号線はSPI接続時にも使われるから、ISP-ターゲット間の通信に問題があるように思えた。

何度か試したが同じだったので、AVRマイコンのデータシート ( ATmega48A/PA/88A/PA/168A/PA/328/P [DATASHEET], Atmel-8271J-AVR- ATmega-Datasheet_11/2015 ) を読んで、28.8項のシリアルプログラミングについて調べてみたところ、ターゲット側のRESETとSCKをLOWにしてから電源を与える必要があるよし(代替手順も書いてあるが)。ArduinoISPのsetup() を少し手直しし、RESET=LOW状態で開始し、その後ターゲットに電源を与えるようにしてみたところ、ようやく書込みが成功。D13 LEDの点滅も止まってくれた。

きょうのまとめ

  • ターゲット側にFT-231Xをつないで、Arduino IDEからもスケッチを更新することができるようになった。復旧したと見てよいだろう。
  • データシートにある Chip Erase というバイトシーケンスも試してみたが、ブートローダーもスケッチもきれいさっぱり消えてしまうようだった。その後、ブートローダーのみを書込みと、D13のLEDが1Hz以上の周期で点滅を繰り返すようになったが、それが正しい動作なのかどうか確認する手段も情報もない。
  • Arduino PRO MINIは、いわばフラット型のAVRマイコンのDIP化キット(ブレークアウトボード)みたいなもので、ほぼ素の状態のマイコンに触れる。今後もちょくちょく使うことになりそう。

追記

  • Arduinoのブートローダーのソースファイルは、は、”…\hardware\arduino\avr\bootloaders\atmega\ATmegaBOOT_168.c” としてArduino IDEと共に配布されていた。”__AVR_ATmega328P__“を与えてmakeするのだろう。ヒマな時にでも読んでみます。
  • AVRマイコン (ATmega328p) のデータシートは改訂されており、きょう現在ダウンロードできるのは、Atmel-42735A-ATmega328/P_Datasheet_Complete-06/2016 になっている。これを見ると、SPIを使ったシリアルプログラミングについては31.8項に書かれている。