2019年11月14日木曜日

単品売りのATMEGA168Pをbootloader焼きから使うための地雷回避術

Arduino NanoやUNOを中華通販で買って使うのもいいんですけど、Arduino UNOのCPUであるATMEGA328Pを単品買いして自作PCBに載せれば、UNOを買うよりも安い価格でArduino cloneを自作できます.

さらに、ATMEGA168PというFLASH容量が少ない製品ならばもっと安価です.中華通販で@¥70ぐらいで買えたりもします.うは~こんなに安いのなら使いたい放題、遊びたい放題ですね.

さらに、外付けのXTAL 16MHzがArduino PCB上にありますが、これすら不要にすることもできます.XTALの替わりにATMEGAxxxの内蔵発振器(8MHz)を使うんです.発振周波数精度は高くはなく、VCC依存で7.3~8.1MHzとデータシートに書かれています.
正確なタイマ割り込みをしたい用途でなければ無問題で使えるでしょう.

そこでわたしは、中華通販で調達したATMEGA168P(正確には168PA)を使います.

ところが地雷がたくさん埋まっていて回避するのに難儀します.

しか~し後続の勇者諸君、わたしは諸君を安易に見捨てたりはしないぞ.諸君のために地雷原の地図を残しておこうじゃないか.

でも間違ってたら素直に地雷で吹き飛んでくれよな.諸君の骨を拾ってくれる者は居ないだろうが、迷わず成仏してくれ.

-------
生168Pを使う作業の地雷概要

以下ではArduinoとはAduino基板のコトを指します.168PやATMEGAxxxはCPUチップ単品を指します.

それと、ATMEGAのclockには、外部水晶(16MHzや8MHz)、内蔵8MHz、他にもあるんですが、ここでは内蔵8MHzで動かすのが目標です.

普段我々がArduinoを調達したときのATMEGAxxxには、工場でbootloaderが焼かれています.bootloaderが焼かれているので、PCのUSBコネクタにUSB-SERIAL変換回路を接続し、SERIAL線のTX/RXを使ってATMEGAxxxにユーザープログラムを焼けるようになっています.
ゆえに、Arduino基板上のATMEGAxxxには2つのプログラムが格納されています.
1)bootloader
2)user program

実はこれだけでなく第3の格納データがATMEGAxxxには存在します.clockのようなCPUハードウエアに密接なパラメータを格納する3BYTEsの領域です.これをfuse memoryと呼びます.
3)fuse memory

買ったばかりの生ATMEGAを使うにはこの3つをATMEGAxxxに焼かなくてはなりません.

ところがかったるい.この3者の焼き方がまるっきしてんでばらばらなんです.
このバラバラさを理解するのが最初の一歩.
手をつけるべき順にいきます.

なお、全てwindowsで作業します.わたしはwin7です.

fuse memory
ライタ:選択肢はいろいろあるが、ここではArduino Nanoを母体とした自作AVRISP
ピン:MOSI,MISO,SCK
ソフト:avrdude     ←今回知った、DOS窓で操作する

avrdudeを使うにはWinAVR-20100110-install.exeを検索してインストするべし.そうするとavrdudeにPATHが通って使えるようになっている.地雷あり.

fuse memoryを真っ先にやるべき理由は、次の手順で述べるbootloaderを焼くにあたって、ATMEGAxxxのclock周波数を確定させてやらなければならないからです.ATMEGAが内蔵8MHzで動いてるのに外部16MHzのbootloaderを焼いてしまったら動かなくなってしまいますから.

内蔵8MHzに設定するためのfuse memory設定は、ATMEGA168P datasheetを読みます. →こちら日本語

bootloader
ライタ:選択肢はいろいろあるが、ここではArduino Nanoを母体とした自作AVRISP
ピン:MOSI,MISO,SCK
ソフト:Arduino IDE    いまわたしは1.8.10を使っています    地雷あり

user program
ライタ:USB-SERIAL変換器.FT232がポピュラーだが最近はCH340なんつうのも見かけますね.win driverのインストはよしなにどうぞ.
ピン:TX,RX
ソフト:Arduino IDE    いまわたしは1.8.10を使っています

以上が地雷除去作業の概要です.

以下では各作業の具体的な地雷撤去作業を説明します.

--------
fuse memory操作(内蔵8MHzで動かす設定)

さぁて、何から解説するかねぇ?

まずはhardwareから.
Arduino NanoをMISO/MOSI経由のプログラマ(AVRISP)として使います.
右上のArduino pro miniがtargetです.
結線はこうなってます.電源は供給しないようにしました.
Nano     Target
D13   →  D13    SCK
D12   →  D12    MISO
D11   →  D11    MOSI
D10   →  RESET
GND   →  GND

Arduino NanoをAVRISPに化かすためのプログラムを焼かなくちゃいけません.
その操作は簡単です.
Arduino IDEの ファイル→スケッチ例→11.ArduinoISP→ArduinoISP これをNanoに焼けばAVRISPの完成です.

hardwareは完成したとして、次はfuse memory読み書きソフトのavrdudeを動かす段階になりますが、これが動きません.地雷です.動かない理由は、ATMEGA168には対応しているけれどATMEGA168Pには対応してないんですよ.

これを解決します.  →参考サイト
わたしの環境でWinAVR-20100110がインストされているのは、C:\WinAVR-20100110\bin です.
この中にあるavrdude.confを改造します.こちらで置き換えます.
あるいは、既存のavrdude.confの末尾にこれを追加するのでもOKです.

DOS窓を開いて、avrdudeを動かします.
fuse memoryを読みます.コマンドはこれです.
avrdude -c avrisp -P COM7 -p m168p -b 19200  -U efuse:r:con:h -U hfuse:r:con:h -U lfuse:r:con:h
読者の環境次第で変えなくちゃいけないのは、Arduino NanoのCOM番号です.わたしの環境ではCOM7でした.

正常に動いたならこんな表示が出ます.
avrdude: AVR device initialized and ready to accept instructions

Reading | ################################################## | 100% 0.08s
avrdude: Device signature = 0x1e940b

avrdude: reading efuse memory:
Reading | ################################################## | 100% 0.02s
avrdude: writing output file "con"
0x0

avrdude: reading hfuse memory:
Reading | ################################################## | 100% 0.02s
avrdude: writing output file "con"
0xdd

avrdude: reading lfuse memory:
Reading | ################################################## | 100% 0.03s
avrdude: writing output file "con"
0xff

avrdude: safemode: Fuses OK
avrdude done.  Thank you.

この結果は市販品のArduino pro mini 5V 16MHzのfuse memoryです.意味を分析してみましょう.

0x1e940bが見えます.
ATMEGA168Pの場合はこの数字が出てきます.コマンドラインでm168pを指定したにも関わらず0x1e940bでない場合はavrdudeがエラーで停まってしまいます.avrdude.confを改造したのはこのエラーを回避するためだったのです.

efuse 0x0が見えます.
こちらの資料の202ページに解説があります.あまり重要でないのでスルーします.

hfuse 0xddが見えます.
clockには関係ないのでスルーします.

lfuse 0xffが見えます.
これがclockにモロ関係します.CKSELが重要です.
 [7]    1:sys clk分周しない
 [6]    1:sys clkをB0へ出力
 [5:4]  内蔵RC発振器起動時間
 [3:0]  CKSEL
CKSELの意味はこうなってます.
内蔵8MHzにするにはCKSEL=0010にすればいいつまり0xf2
 CKSEL   0000        外部0-20MHz
 CKSEL   0001        reserved
 CKSEL   0010        内蔵8MHz
 CKSEL   0011        内蔵128kHz
 CKSEL   0100~1111  外部XTAL

つぎに、生ATMEGA168Pのfuse memoryを読んでみました.(PCB半田付済写真)
ここにも地雷が在ったのだけど、まずは結果だけ記すとこうなりました.
 Device signature = 0x1e940b
 reading efuse memory:  0x1
 reading hfuse memory:  0xdd
 reading lfuse memory:  0xf7
clockを決める0xf7の意味は何でしょうか? それは、外部XTALの意味 でした.

あれれ? これって結構な殺傷力の地雷なんですけど..... それはなぜか?
Arduino生産工場が生ATMEGAをPCBに半田付します.生産ラインで最初に火入れしたとき、ATMEGAが動かないと困ります.そのためにはATMEGA clockは内蔵8MHzであれば安心です.IC生産工場では内蔵8MHzに設定して出荷しているそうです.すなわち、バージンATMEGA168Pならば0xf2になっているはず.

ところが0xf7だったということは、このATMEGA168Pはバージンじゃないってことよ.
非処女だったか、、、がっかりした.

ハナシは逸れますけど、ハムスターのメスを買って単独飼育している人が、バージンのはずのメスハムが子供を産んだのでびっくりという奇抜な出来事があるんだそうです、処女懐胎.ペットブリーダーの品質管理ミスですね.(笑)

このATMEGA168Pは処女懐胎というよりもArduino生産ラインの横流し品かもね.

この結構な殺傷力の地雷のせいで悩みましたよ.
↓生ATMEGA168Pのfuse memoryを読み出している作業場面.
↓生ATMEGA168P拡大.外付けXTALを使わないで168Pを動かしたいわけですから、外付け部品はごく僅かです.ところがこれだとfuse memoryを読み出せません.悩みました.
↓最後の手段で16MHzを外付けしてみたら動きました.非処女確定です.上述のとおり0xf7の外部XTAL設定になっていました.
もしかしたらbootloaderも焼かれているのかもしれんなどと、疑心暗鬼が広がります.

裏切りのショックから立ち直る間もなく、168Pを内蔵8MHzに設定しましょう.
市販品のArduino pro miniに倣い、しかしながらclockは内蔵8MHzにするためこの設定を採用します.(動作保障は知らん)
 reading efuse memory:  0x00
 reading hfuse memory:  0xdd
 reading lfuse memory:  0xf2
DOS窓のコマンドはこれです.
avrdude -c avrisp -P COM7 -p m168p -b 19200 -U efuse:w:0x00:m -U hfuse:w:0xdd:m -U lfuse:w:0xF2:m

DOS窓表示を念のため転記しときます.
C:\Users\hira>avrdude -c avrisp -P COM7 -p m168p -b 19200 -U efuse:w:0x00:m -U
fuse:w:0xdd:m -U lfuse:w:0xF2:m
avrdude: AVR device initialized and ready to accept instructions
Reading | #################################### | 100% 0.08s
avrdude: Device signature = 0x1e940b
avrdude: reading input file "0x00"
avrdude: writing efuse (1 bytes):
Writing | ################################################## | 100% 0.02s
avrdude: 1 bytes of efuse written
avrdude: verifying efuse memory against 0x00:
avrdude: load data efuse data from input file 0x00:
avrdude: input file 0x00 contains 1 bytes
avrdude: reading on-chip efuse data:
Reading | #################################### | 100% 0.08s
avrdude: verifying ...
avrdude: 1 bytes of efuse verified
avrdude: reading input file "0xdd"
avrdude: writing hfuse (1 bytes):
Reading | #################################### | 100% 0.08s
avrdude: 1 bytes of hfuse written
avrdude: verifying hfuse memory against 0xdd:
avrdude: load data hfuse data from input file 0xdd:
avrdude: input file 0xdd contains 1 bytes
avrdude: reading on-chip hfuse data:
Reading | #################################### | 100% 0.08s
avrdude: verifying ...
avrdude: 1 bytes of hfuse verified
avrdude: reading input file "0xF2"
avrdude: writing lfuse (1 bytes):
Reading | #################################### | 100% 0.08s
avrdude: 1 bytes of lfuse written
avrdude: verifying lfuse memory against 0xF2:
avrdude: load data lfuse data from input file 0xF2:
avrdude: input file 0xF2 contains 1 bytes
avrdude: reading on-chip lfuse data:
Reading | #################################### | 100% 0.08s
avrdude: verifying ...
avrdude: 1 bytes of lfuse verified
avrdude: safemode: Fuses OK
avrdude done.  Thank you.

これでもうXTALを外してもOKなはずです.XTALを外します.fuse memoryを正常に読めます.

--------
bootloaderを焼く
作業hardwareはこのままです.

Arduino IDEを起動します.

ここに地雷あり.Arduino IDEはデフォルトでは168Pに対応していません.168になら対応しています.

地雷を除去します.ツール → ボード → ボードマネージャ
ボードマネージャで、DIY ATmega48,ATmega88,ATmega168,ATmega328 というのを探してインストします.これで168Pが使えます.




ルーツ→ボードにこれが現れるはず.ATmega168/A/P/PA/PBを選択.
最終的に下図のようになるように設定します.必須と思ったところは赤丸です.COM portは読者の環境によりけりです.
これでようやくbootloaderを生ATMEGA168Pに焼けるようになりました.
ツール→ブートローダを書き込む     と操作します.

Arduino IDEが気になるメッセージを出します.
avrdude: WARNING: invalid value for unused bits in fuse "efuse", should be set to 1 according to datasheet
efuseを1にしとけと言ってるんだけど、datasheetを読むとなんか災いがありそうなんで、1にするのは見送ります.

もうひとつ気になる現象があります.bootloaderを焼いた後で、fuse memoryがf2→e2に書き換わっています.
 reading efuse memory:  0x00
 reading hfuse memory:  0xdd
 reading lfuse memory:  0xe2
このbit4=0は内蔵発振器の起動時間設定だそうです.
ここでもういちど、fuse memoryを00/dd/f2になるように上書きしておきました.必要度は不明です.

ホント、地雷多いです.

----------------
user programを焼く

ここまで辿り着いて、通常やってるワークフローになります.

ATMEGA168PからAVRISPを取り外します.
替わりに、USB-SERIALを接続します.
USB-SERIALの接続は、信号線は3本です.この他にはGND/VCC.
     168P                FT232
 29pin RESET →  0.1uF  →  DTR
 30pin RXD       →        TXD
 31pin TXD       →        RXD

Arduino IDEの設定はbootloderを焼いた時と基本的に同じです.COM portは例外であって、AVRISPではCOM7だったのが、USB-SERIALだとCOM4になったのでそこは修正すべきです.

Arduino IDEのスケッチ例のBLINKを焼いてみますと、LEDが点滅します.動作確認終了です.

勇者の諸君もがんばってくれたまえ.

かしこ

0 件のコメント:

コメントを投稿