Arduino PRO MINIのBODLEVELヒューズの書き換え

概要

ちょっと前に小さな赤外線リモコンを作るにあたってArduino PRO MINIを使い、いろいろと省電力化のための工夫をしてみた。ただ、Arduino PRO MINIは電源電圧が約2.7Vを下回ったことを検出するとリセットがかかってしまうことが分かった。

このことに気が付かないでPRO MINIを基板にハンダ付けしてしまったので、アルカリ乾電池の寿命が尽きる前どころか、十分に余裕がある状態で使用不能になってしまうことが明らかになった。

今回は、この原因と回避のための方法についての話。

動作確認のための仕組み

出力電圧を調整可能な降圧型電源モジュールが手に入ったので、これを使って電源電圧を下げて確認した。中国からの送料込みで280円だった。発注してから到着するまでの期間が、ふだんは3週間でも4週間でも気にならないのだが、今回だけはもうちょっと早く来てればなとは思った。

LM2596 3A 降圧電源モジュール

プラスチックのスペーサーを脚にして、9V 2.5A出力のACアダプタをつないで使った。入力電圧や出力電圧をプッシュスイッチで切り替えてデジタル表示できるのがよいところ。

出力調整可能降圧電源モジュール

最初、調整用のボリュームを回してもなかなか出力電圧が下がらないので焦ったが、時計の反対回りに10回ほど回すといきなり下がり始めた。その後は電源投入で最後の設定電圧が出てくれるし、その周辺の微調整もできるのでとても便利。

電圧表示の調整方法

出力をテスターにつないで見たところ、モジュール上の表示電圧とテスターの表示とが0.5V以上ずれていた。調整方法を探したところ以下の記述を発見したので載せておきます。出力だけでなく入力電圧表示も調整可能で、おのおの調整結果が記憶される。

  1. When the voltmeter shows output voltage, long press the right button for 2 seconds, then release, voltmeter and “OUT” LED flash in synchronization. Now the voltmeter enters into output voltage calibration mode. Similarly, when the voltmeter shows input voltage, long press the right button for 2 seconds, then release, voltmeter and “IN” LED flash in synchronization, now the voltmeter enters into input voltage calibration mode.
  2. Touch the right button, the voltage rises a unit; Touch the left button, the voltage drops a unit. Due to a unit is less than 0.1 V, so you need to continuously press 5 times to see that the voltmeter changes 0.1 V.
  3. After calibration, long press the right button for 2 seconds, then release. Now the voltmeter exits the voltage calibration mode. All the parameters will be saved automatically.

(http://a.co/7aEBB4m より抜粋。日本語に似せた言葉が書いてあるサイトより分かりやすい)。

出力調整可能電源モジュール。 出力側電圧を表示中

PRO MINIの動作の確認をするときには、3.3V動作のArduino PRO MINIのVCCとGNDに出力を接続して使った。

PRO MINIと電源モジュール

テスト回路

テスト用のPRO MINI (3.3V, 8MHz版)周りは以下のような回路とし、短いスケッチを入れた。上の写真が実装したところ。

スケッチ

回路およびスケッチの意図は以下のとおり。

  • setup()が終わるとすぐにスリープ状態(SLEEP_MODE_PWR_DOWN)に入る。
  • SWを押すとスリープから復帰しLEDを点滅させる。
  • そして、再度スリープに入る。
  • スリープ中に電源電圧を下げてやり、SWを押したときにLEDが点滅するかどうかで動作しているかどうかを判断する。

スリープ時にBODを禁止した方がより電流を節約できるということなのでMCUCRレジスタを操作している。また、MCUCRレジスタのBODSビット操作時のタイミングを意識して、スリープに入る部分も “avr/sleep.h” に定義されているマクロを呼ぶことにした。データシートの 14.12.2. MCU Control Register を参照。果たして効果があるのかどうか、うちの安いテスターでは判断できなかった。

この仕組みにより、BODLEVELを変更する前のデフォルトのArduino PRO MINIは、2.7Vを下回ったあたりで動作しなくなることが確認できた。

BODLEVELの変更

ATmegaのBOD (Brown Out Detection) は、動作中またはスリープ中に電源電圧が規定電圧(VBOT: Brown-Out Reset Threahold)を下回ったとき、マイコンがおかしな挙動をしないよう内部リセットをかける。そのために常に電圧の比較を行っていることになる。
また、リセット回路も電源電圧が規定(VPOT : Power-on Reset Threahold)を下回ったときにマイコンをリセットしてくれる。

2つの規定電圧は VBOT > VPOT の関係にあり、VPOT の代表値は1.5V(電圧上昇時)または1.0V(下降時)と決まっているが、VBOTはBODLEVEL Fuseの設定によって変更可能で、4.3V、 2.7V、 1.8V、BOD動作禁止の4種類から選択できる(電圧は代表値)。

今回赤外線リモコンを作るにあたっては、Arduino PRO MINIに載っているマイコンではBOD動作禁止になっていると思いこんでいた。そのためスリープ時にBOD回路が消費する電流についても考慮していなかった。
現実には2.7Vに設定されているので、システムクロックプリスケーラを使おうがクロックを1MHzに落とそうが、2.7V以下の電源電圧では動作しないようになっていた。

なお、Brown-outという言葉はBlack-outに類似の言葉のようで、完全な電力断のちょっと前、真っ暗ではなく薄暗い状態、といった意味のようである。

Arduino PRO MINIのBODLEVEL

Arduino IDEをPCに導入すると、導入先フォルダ( {Arduino} と記載。うちの場合は C:\Program Files (x86)\Arduino )の中の、{Arduino}\hardware\arduino\avr の中に、boards.txt というテキストファイルが書かれる。これを開けてPRO MINI 3.3V, 8MHzに対応する項目を探すと、

と書いてある。この中にある、

pro.menu.cpu.8MHzatmega328.bootloader.extended_fuses=0xFD

の、extended_fuses の値 0xFD (実際はその下位3ビット) がBODLEVEL Fuseの値を表しているようである。データシートの、Table 32-8. BODLEVEL Fuse Coding を引き写すと以下のようになっいる。

BODLEVEL [2:0] Fuses Min. VBOT Typ. VBOT Max VBOT Units
111 BOD Disabled
110 1.7 1.8 2.0 V
101 2.5 2.7 2.9
100 4.1 4.3 4.5
011 Reserved
010 Reserved
001 Reserved
000 Reserved

(Atmel-42735B-ATmega328/P_Datasheet_Complete-11/2016 より抜粋)

0xFDの下位3ビットは101 なので、2.7V typ. に設定されていることが分かる。これで、可変電圧レギュレータを使って電圧を下げたとき、2.7V近辺でリセットがかかる理由がはっきりした。赤外線リモコンに組み込んだ PRO MINIのBODLEVELを変更しないことには電池がまだ元気なうちに止まってしまうから、BODLEVEL Fuseを変更することにした。

Arduino ISPとavrdudeの利用

先に挙げたboards.txt の中で、名前(キー名)に .bootloader. が含まれている行は、ISP (In-System Programmer) を使ってブートローダーを書き込むとき同時にマイコンに反映されるようである。つまり、ブートローダーが書ける仕組み(ISP)ならばfuseも変更できるということ。今回は、Arduino IDEのサンプルとして付属しているArduinoISPスケッチを利用することにした。以前にも使ったが、3.3V動作のPRO MINIをターゲットにするので、やはり3.3V動作のPRO MINIにArduinoISPスケッチを仕込むことにした。

Arduino as ISP

Arduino as ISP

写真では、左側がISPとしてふるまうPRO MINIで、USBシリアル変換デバイスのAE-FT231Xに接続しておりAMS1117-3.3から3.3V電源をもらっている。右側がターゲットのPRO MINI。ISP側とターゲットの接続については、Using an Arduino as an AVR ISP (In-System Programmer) にしたがった。

以下は、5VのPRO MINIのスケッチを消したりブートローダを書いたりしたとき、ブレッドボードの実体配線図がなんとも馴染めなくて書いた参考回路図。

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

Arduino as ISP を使うときの注意点は、PCとISP間の通信速度を19200bpsに設定することに尽きると思う。その他は特に工夫しなくも、上にリンクを載せたArduino.cc のチュートリアルに従えば動いてくれる。

avrdudeを使う

Arduino IDEにはブートローダーを書き込む仕組みがあるものの、fuseだけを明示的に書き換える仕組みはない。fuseの読出しや書込みのためには、Arduino IDEをインストールすると同時にPCに導入されるavrdude.exe というプログラムを用いる。

avrdude.exeは、{Arduino}\hardware\tools\avr\bin に格納されていた。Arduino IDE 1.8.3 のWindowsインストーラ版を導入したが、avrdude.exeのバージョンは 6.3 だった。avrdude.exeの使い方は、http://download.savannah.gnu.org/releases/avrdude/avrdude-doc-6.3.pdf を参照した。

コマンドプロンプトを開き、ここがカレントディレクトリになるように cd したあとで、以下のように実行する。

avrdude -C ..\etc\avrdude.conf -p m328p -P COM4 -b 19200 -c avrisp

各パラメータの意味については、avrdude.exeをパラメータ無しで実行したときに表示される usage の内容を参照のこと。
なお、“-C” で指定する設定ファイルもArduino IDEと共に導入されているので、内容を変更することなくそのまま使っている。
“-P”で指定するCOMポートについては、USB-シリアル変換デバイス用のドライバに割り当てられたCOMポートを指定する必要がある。
“-b”で指定する通信速度は、ArduinoISPスケッチ内にも 19200bpsと書かれているので、同じ値を指定する。

実行すると、以下のように表示された。

Fuses OKのあとにavrdudeが読み取ったfuseの内容が表示されている。E: に引き続く値が、BODLEVELを含むExtended Fuseの現在の内容にあたる。Arduino PRO MINIなので、予定通り FD という値が得られている。

今回はBODLEVEL として 1.8V typ. に対応する Bxxxxx110 を書き込むことにした。これは4MHz動作が保証されている最小電圧にあたる。BODLEVEL Fuseの上位5ビットについては特に規定がないが、余計なビットに影響を与えないよう0xFEという値に書き換える。その際には以下のようにする。

最後のパラメータ “-U” から始まる部分がextended fuseの書き換えを指示する部分にあたり、”:”で区切られた各部は以下のような意味がある。

  • -U は内部メモリ操作指示
  • efuse が対象がextented fuseであること
  • w が直後のデータをマイコンに書込むことの指定
  • 0xFE が書き込む値
  • は、w の直後のフィールドがファイル名ではなく16進数の値そのものであること

コマンドを実行すると、以下のように表示された。

Fuses を見ると、たしかに Extended fuseの内容は書き換わったようである。Arduino as ISP を構成しているPRO MINIの電源をオフにし、もう一度オンにしてから avrdude を実行しても、書き換わったあとの内容が表示された。

そして、Extended fuseを書き換えた Arduino PRO MINIを最初に載せたテスト回路にセットして使ったところ、スリープ中に1.8Vまで電源を下げてもちゃんと動作した。1.8Vの状態で手動でリセットしても不思議なことに、あるいは、運良くちゃんと動いていた。ただ、電源電圧がPRO MINI上のLEDのVF値に近いせいか、とても頼りなく点滅する。

fuseを書き換えるには何かちゃんとしたハードウェアを買う必要があるのかと思っていたが、Arduino PRO MINIが2枚とブレッドボード他でうまくいった。ただ、書き換える対象によっては今回のようなシリアル方式では不可能なものもあるようだ。

赤外線リモコンのPRO MINIの改修

すでに基板にハンダ付けしてしまっているので、ブレッドボードに乗せてfuseを書き換えるわけにもいかない。さいわい、接続が必要な端子(D11,D12,D13およびRESET)は使用していないので、リード線をハンダ付けして引き出すことにした。4本必要なので、ブレッドボード用の長めのジャンパワイヤ(オス-オス)を2本、真ん中で切断して使った。もったいない気もするが、また使う機会もあるだろう。

赤外線リモコンを手術中

リモコン内部の乾電池を電池ボックスから外し、リモコン側から引き出したリード線は先に使ったArduino as ISPブレッドボードに差し込んで接続した。リモコン側の電源もブレッドボードからもらっている。

BODLEVEL fuseの書き換え後、スケッチも若干修正して書き込んだ。スケッチの書込みはAE-FT231Xをリモコン内のPRO MINIに接続して行った。
スケッチの内容については、今回のテストでも使ったスリープ時のBOD禁止を追加し、スリープ開始を定義済マクロに変更している。変更箇所は void loop() 内の以下に示す部分だけにした。

スリープ時のBOD禁止による効果は分からないが、まあ全体として同じように動くので問題はないだろう。

きょうのまとめ

  • Arduino を使った電子工作をするにあたって、ATmegaのデータシートは読むようにしていたが、Arduinoそのものに関してはあまり調べていなかった。次に何か作るときは、もうちょっと事例をあたったりしてからにしようと思っている。
  • 出力電圧を調整可能な電圧レギュレータユニットにより、赤外線リモコンの問題の検出や修正後の確認もすんなり行えた。こういう道具は事前に用意しておいてしかるべきものなのだが、持っていなかったのだからしょうがない。それにしても、珍しくいい買い物した気分になった。
  • 今回リモコンから電池を外すときに電圧を測ると約3.1Vだった。稼働し始めが3.15V程度だったので、10日間ちょっとで0.05V下がっていた。このままリニアに下がり続けるとすると、あと220日間で2.0Vに達することになる。果たしていつまで動いてくれるのか。