前回は USB DFU じゃなくて、JTAG で弄り倒すよ!と宣言し、実機を手にする前にアセンブリしてました。
が、やっぱり JTAG は無理(Mac や Linux 上では)という結論に落ち着きましたので、どうして無理なのかという点をこの記事に示したいと思います。
つまりこの記事はなにかものを作るのではなく、ただただダメなところを指摘する生産性のない記事です。Google 先生とかで調べてきた方向けと言ってもいいでしょう。
JTAGのための構成
JTAG は IC 向けのデバッグ規格(と勝手に思い込んでいます)ですが、これを利用するには対応するインターフェイスを用意する必要があります。
お高いお高い ICE や、有名なデバッグプローブを購入してもいいのですが、僕は最近鉄道趣味が高じて金欠なので、安い FT232H を利用します。秋月リンクはこちら。
そして、使う PC 側のソフトウェアは、毎度おなじみ OpenOCD (Open On-Chip-Debugger) です。こちらは JTAG、SWD だったら基本対応しています。これ使えると思ったんだけどなあ...
接続はデータシートと OpenOCD の cfg ファイル(tcl スクリプト)を見て以下のように配線すれば OK です。
FT232H 側ピン | マイコン側ピン |
---|---|
AD0 | TCK |
AD1 | TDI |
AD2 | TDO |
AD3 | TMS |
AC1 | RESET_N |
自作スクリプト作成
いざ接続!と思ったのですが、どうやら OpenOCD が標準で用意している AVR32 用のスクリプトだとデバイスIDが合わない事が判明。ぶっちゃけこのへんは理解できていないので、とりあえず /usr/local/share/openocd/scripts/target/avr32.cfg を参考に改造してみました。
set _CHIPNAME avr32
set _ENDIAN big
set _CPUTAPID 0x4203003f # CHANGED from its original
adapter_nsrst_delay 100
jtag_ntrst_delay 100
reset_config trst_and_srst separate
# jtag scan chain
# format L IRC IRCM IDCODE (Length, IR Capture, IR Capture Mask, IDCODE)
jtag newtap $_CHIPNAME cpu -irlen 5 -ircapture 0x1 -irmask 0xf -expected-id $_CPUTAPID
set _TARGETNAME [format "%s.cpu" $_CHIPNAME]
target create $_TARGETNAME avr32_ap7k -endian $_ENDIAN -chain-position $_TARGETNAME
ということで、これを avr32.cfg
としてプロジェクト直下に保存しておきました。
接続...はできるが
さて、早速接続してみましょう。それ以前にこのマイコンには多数のキャパシタやインダクタが必要で接続が非常に面倒くさいんですがね。。。
それらの素子はちゃんと接続したとして、コマンドを叩いて接続してみます。
$ openocd -f interface/ftdi/um232h.cfg -c 'adapter_khz 2000; transport select jtag' -f ./avr32.cfg
はい、接続できますね。それではプログラム(output.elf
) を書き込んでみましょうか。
$ openocd -f interface/ftdi/um232h.cfg -c 'adapter_khz 2000; transport select jtag' -f ./avr32.cfg -c 'program output.elf'
(ずらずら)
Warn: avr32_ap7k_assert_reset: implement me
Warn: avr32_ap7k_assert_reset: implement me
(ずらずら)
target not halted
はああ? 謎のワーニングとともに、接続が切れてしまいました。どういうことなんだ?
しかも implement me とは... 悪い予感がします。
OpenOCD を紐解く
流石にこれは意味がわからないエラーなので、OpenOCD のソースコードを見てみます。
ソースコードの中身
git clone
して、src/target/avr32_ap7k.c
を開いてみると、衝撃の実装が。。。
static int avr32_ap7k_assert_reset(struct target *target)
{
LOG_ERROR("%s: implement me", __func__);
return ERROR_OK;
}
static int avr32_ap7k_deassert_reset(struct target *target)
{
LOG_ERROR("%s: implement me", __func__);
return ERROR_OK;
}
えっ?えっ??
なんと、リセットのアサート・デアサート実装されていないじゃないですか!!これは困りました。
リセットのアサートとは
僕もあんまり詳しく分かっていないんですが、これらの関数はターゲットをリセットして、その後の状態を司る役割があります。
例えば単に reset
と打ったら、そのターゲット(マイコン)はリセットして、通常動作に戻ります。また、reset halt
と打ったら、ターゲットは再起動して、halt 状態に遷移します。要は再起動後のモード遷移に必要ってわけですね。
それで、実際にプログラムを書き込むとなると、リセット後 halt モードに遷移する必要があるのが普通です。このマイコンもそうで、つまりリセットのアサート実装が無いということは、プログラムを書くことができるモードに入ることができないということを意味します。これは完全に詰みました。。。
「だったら自分でそれを実装して、OpenOCD をビルドしたらいいんじゃないの」との声が上がってきそうですが、僕の経験上 Mac で OpenOCD のビルドに成功した試しがありません。無理です。
終
ということで、ゲームオーバーです。せっかく費用を抑えるために USB を積んでいない安い型番を選んだのですが、唯一の綱である JTAG on OpenOCD が使用不可だと分かりました。
なので、このマイコンのこの型番は使えないということになってしまいました。なので次は USB DFU を頼りに書き込み、弄りを楽しむことができればなあと思います。
JTAG で通信できない〜って腐っているだけではなく、「これこれこういう理由で絶対に無理」と分かっただけ進捗だと思います。それでは次回ご期待を。