FT4232H
http://strawberry-linux.com/catalog/items?code=50029
FT2232H か FT4232H を使って JTAG インターフェイスにするのが高コストパフォーマンスっぽいので、FT4232H を買ってみた。FTDI の一部のシリアルポート変換チップは、MPSSE という方法で JTAG や I2C, SPI を喋ることができる。
なので、UART 接続しつつ JTAG しつつ、みたいなのが1個あればできて便利そう!って感じです。ただ、他プロトコル喋らせるのは、やはりちょっとハマりどころがあった……
JTAG 専用の USB インターフェイスの中には普通にこれを使っているのも多いみたい。専用のものだとここに書いてあるようなハマり所はあまりなさそう。
OpenOCD
JTAG をハンドリングして使えるようにしてくれる OSS として Open OCD (オンチップデバッガー) というのがある。これは gdb のプロトコルを喋るサーバーになったりしてくれる。
FT4232H を生で使った場合、2つの方法がある。
libftd2xx を使う場合
FTDI が提供しているドライバを使う場合。ドライバ自体のソースは非公開のビルド済みのものを使う。
http://www.ftdichip.com/Drivers/D2XX.htm で libftd2xx をいれる
sudo cp /Volumes/release/D2XX/bin/10.5-10.7/libftd2xx.1.2.2.dylib /usr/local/lib/ sudo ln -sf /usr/local/lib/libftd2xx.1.2.2.dylib /usr/local/lib/libftd2xx.dylib sudo cp /Volumes/release/D2XX/Samples/ftd2xx.h /usr/local/include/ sudo cp /Volumes/release/D2XX/Samples/WinTypes.h /usr/local/include/ # Win とかついてるが必要
で、入れたら、homebrew で以下の通りインストールする
sudo brew install openocd ----enable-ft2232_ftd2xx
このようなファイルを generic-ft4232h.cfg でつくる。
# Adapter Configuration: # http://openocd.sourceforge.net/doc/html/Debug-Adapter-Configuration.html interface ft2232 ft2232_device_desc "Quad RS232-HS" ft2232_layout usbjtag ft2232_vid_pid 0x0403 0x6011 # vendor id, product id from usb
vid_pid は system_profiler SPUSBDataType を実行して出てくるやつを入れたらよい。
ft2232_layout は、この FT4232H を使う場合 usbjtag を指定すればよい。usbjtag を指定した場合
- ADBUS0 -> TCK
- ADBUS1 -> TDI
- ADBUS2 -> TDO
- ADBUS3 -> TMS
- ADBUS4 -> nTRST
- ADBUS5 -> WAIT or STOPCLK
- ADBUS6 -> nRST
- ADBUS7 -> RTCK
になる。
libftdi を使う場合
入れるのはより簡単
sudo brew install openocd --enable-ft2232_libftdi
とするだけで依存まで入る。ちなみに OpenOCD が最新の libftdi には対応していないので、自分でビルドしようとするとだいぶハマる。homebrew 使いましょう。
設定ファイルは以下のようになる。コメント頑張って書いた。AN_135_MPSSE_Basics.pdf で出てくるドキュメントと FT4232H のデータシートを読むとだいたい必要な情報は理解できる……
# Adapter Configuration: # http://openocd.sourceforge.net/doc/html/Debug-Adapter-Configuration.html # Use MPSSE adapter interface ftdi # USB driver name (must be matched with your device) ftdi_device_desc "Quad RS232-HS" # USB vendor ID, product ID pairs ftdi_vid_pid 0x0403 0x6011 # Channel for using JTAG ftdi_channel 0 # Initial state and direction setting (ref. AN_135_MPSSE_Basics.pdf) # ftdi_layout_init [data] [direction] # name signal state direction JTAG name # *DBUS0 TCK/SK (low =0) (out=1) TDI # *DBUS1 TDI/DO (low =0) (out=1) TDO # *DBUS2 TDO/DI (low =0) (in =0) TCK # *DBUS3 TMS/CS (high=1) (out=1) TMS # *DBUS4 GPIOL0 (low =0) (in =0) (nTRST) # *DBUS5 GPIOL1 (low =0) (in =0) WAIT | STOPCLK # *DBUS6 GPIOL2 (low =0) (in =0) (nRST) # *DBUS7 GPIOL3 (low =0) (in =0) RTCK ftdi_layout_init 0x08 0x0b # Use GPIOL0 as nTRST ftdi_layout_signal nTRST -data 0x10 # Use GPIOL2 as nRST ftdi_layout_signal nRST -oe 0x40
libftdi を使う場合エラーメッセージがろくに表示されないので罠い。例えば、ftdi_device_desc が間違っていると error code -100 みたいなエラーしかでないのでさっぱりわからない。
この設定ファイルの場合、ftd2xx の usbjtag と同じピン配置になる (はず…)。すなわち以下
- ADBUS0 -> TCK
- ADBUS1 -> TDI
- ADBUS2 -> TDO
- ADBUS3 -> TMS
- ADBUS4 -> nTRST
- ADBUS5 -> WAIT or STOPCLK
- ADBUS6 -> nRST
- ADBUS7 -> RTCK
Raspberry Pi との接続
Raspberry Pi 側の配置 (リビジョンによって違うが、最近のバージョン = rev2 で)
- 7pin TDI
- 13pin TMS
- 15pin TRST
- 18pin TDO
- 22pin TCK
- 25pin GND
Raspi <-> JTAG
- 7pin (TDI) 4pin (TDI)
- 13pin (TMS) 6pin (TMS)
- 15pin (TRST) 7pin (TRST, GPIOL0)
- 18pin (TDO) 5pin (TDO)
- 22pin (TCK) 3pin (TCK)
- 25pin GND
とする。あとは同じ名前のピン同士を接続する。
Bare metal Raspbery Pi 側で JTAG を有効にする
JTAG は GPIO ピンの ALT 機能なので (JTAG を使ってる場合これらのピンはGPIOとしては使えない)、JTAG を使うようにブートする必要がある。以下のイメージを kernel.img にして SD カードにコピー
https://github.com/dwelch67/raspberrypi/blob/master/armjtag/armjtag.bin
これは単に JTAG を利用するように設定したあと、LED をチカチカさせて接続を待つプログラムになっている。
接続する
raspi.cfg を以下の内容でつくる。
# Broadcom 2835 on Raspberry Pi telnet_port 4444 gdb_port 3333 #jtag_khz 1000 adapter_khz 1000 #jtag_nsrst_delay 400 #jtag_ntrst_delay 400 if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME raspi } reset_config none if { [info exists CPU_TAPID ] } { set _CPU_TAPID $CPU_TAPID } else { set _CPU_TAPID 0x07b7617F } jtag newtap $_CHIPNAME arm -irlen 5 -expected-id $_CPU_TAPID set _TARGETNAME $_CHIPNAME.arm target create $_TARGETNAME arm11 -chain-position $_TARGETNAME
でもって、
openocd -d -f generic-ft4232h.cfg -f raspi.cfg
とする。-d はデバッグオプションなので、ちゃんと動けばつけなくていい。
シリアルポートドライバのアンロード
ちゃんとデバイス名とか設定してるのに! 動かない! ってときは
kextstat | grep FTDI
してみると、シリアルポートドライバが (入れたなら) 入ってるので、それが動いている。そのポートに対して JTAG をしかけようとしても衝突するのでうまくいかない。
とりあえずアンロードして動くことを試す
sudo kextunload /System/Library/Extensions/FTDIUSBSerialDriver.kext # ドライバを無効にしている状態で抜き挿しするとロードされてしまう? アップルがデフォルトで入れてるドライバも無効にする kextstat | grep FTDI ででてくる sudo kextunload -b com.apple.driver.AppleUSBFTDI
ftd2xx の場合 FT_OpenEx あたりで、うまくいくはずなのに失敗している場合これが疑われる。libftdi の場合エラーがよくわからないので気付きにくい。
これで動くなら動くでいいんだけど、このままだと他のチャンネルをシリアルポートとして使えない。なので、一部のポートだけシリアルポート機能をやめたい。検索したところドライバの設定ファイルを変えればいいっぽい。以下の場所にある。
/System/Library/Extensions/FTDIUSBSerialDriver.kext/Contents/Info.plist
これに対して以下のように A ポートだけ無効にする。
--- Info.plist.orig 2014-03-02 14:58:05.000000000 +0900 +++ Info.plist 2014-03-02 14:58:35.000000000 +0900 @@ -2033,25 +2033,6 @@ <key>idVendor</key> <integer>1027</integer> </dict> - <key>FT4232H_A</key> - <dict> - <key>CFBundleIdentifier</key> - <string>com.FTDI.driver.FTDIUSBSerialDriver</string> - <key>IOClass</key> - <string>FTDIUSBSerialDriver</string> - <key>IOProviderClass</key> - <string>IOUSBInterface</string> - <key>bConfigurationValue</key> - <integer>1</integer> - <key>bInterfaceNumber</key> - <integer>0</integer> - <key>bcdDevice</key> - <integer>2048</integer> - <key>idProduct</key> - <integer>24593</integer> - <key>idVendor</key> - <integer>1027</integer> - </dict> <key>FT4232H_B</key> <dict> <key>CFBundleIdentifier</key>
一応バックアップをとってから編集して、
sudo kextunload /System/Library/Extensions/FTDIUSBSerialDriver.kext sudo kextload /System/Library/Extensions/FTDIUSBSerialDriver.kext
すると ls -l /dev/tty.usbserial-* の結果に A が出てこなくなり、JTAG もうまく動くようになる。
JTAG 経由で書きこんで実行してみる
$openocd -f generic-ft4232h.cfg -f raspi.cfg Open On-Chip Debugger 0.7.0 (2014-03-02-16:47) Licensed under GNU GPL v2 For bug reports, read http://openocd.sourceforge.net/doc/doxygen/bugs.html Info : only one transport option; autoselect 'jtag' adapter speed: 1000 kHz none separate raspi.arm Info : clock speed 1000 kHz Info : JTAG tap: raspi.arm tap/device found: 0x07b7617f (mfg: 0x0bf, part: 0x7b76, ver: 0x0) Info : found ARM1176 Info : raspi.arm: hardware has 6 breakpoints, 2 watchpoints
上記通りの設定をすると、コマンドでポート 4444 を listen するようになっている。この状態でイメージをアップロードしてみる。
$ telnet localhost 4444 Trying 127.0.0.1... Connected to localhost. Escape character is '^]'. Open On-Chip Debugger > halt target state: halted target halted in ARM state due to debug-request, current mode: Supervisor cpsr: 0x600001d3 pc: 0x000210d0 > load_image main.elf 330812 bytes written at address 0x00008000 downloaded 330812 bytes in 3.823093s (84.502 KiB/s) > resume 0 >
でうまくいけばとりあえず JTAG 経由で何かしらする準備ができた感じ。
gdb
上記通りの設定をしていると、gdb プロトコル用のポートとして 3333 も listen している。これを使って gdb でデバッグをする。
まず先に telnet するなりなんなりして halt してないとだめっぽい?
$ arm-none-eabi-gdb main.elf GNU gdb (32-bit ARM EABI Toolchain JBS-FLOAT_IO-SGXXLITE_ML-2013.05-23-v2013.05-20-g7e710b6) 7.4.50.20120716-cvs Copyright (C) 2012 Free Software Foundation, Inc. License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html> This is free software: you are free to change and redistribute it. There is NO WARRANTY, to the extent permitted by law. Type "show copying" and "show warranty" for details. This GDB was configured as "--host=x86_64-apple-darwin13.0.2 --target=arm-none-eabi". For bug reporting instructions, please see: <https://github.com/jsnyder/arm-eabi-toolchain>... Reading symbols from /Users/cho45/project/raspberrypi-mruby-bare-metal/main.elf...done. (gdb) target remote localhost:4445 Remote debugging using localhost:4445 0x00000000 in ?? () (gdb) load Loading section .text, size 0x52c00 lma 0x8000 Load failed
しかし load がうまくいかず……
Error: 33 words out of 4060 not transferred
みたいなエラーがでる。データラインにノイズが乗ってる?
ちょっとすぐ解決できなそうなので今日はここまで……