OpenOCDが動くまで
出典: Wikimura
目次 |
はじめに
OpenOCDはJTAGデバッグを可能にするプログラムです。 GDBはTCP経由でデバッグを行える(GDBのコマンドをTCPで送るということ)のですが、OpenOCDはこのパケットを受け取るTCPサーバとして機能します。ホストPC内のOpenOCDが監視するポートに対してGDBがコマンドを送り、OpenOCDがそれをJTAG操作に置き換え、ドライバを操作することでJTAG信号を作るということです。
ただ、JTAGは操作対象のID、JTAGチェインの構成などを知っていないと正しい操作が行えません。 私は操作の仕方がわからない頃、電源を入れてつなげば認識するだろうと思っていたのですが...下記のようなエラーに見舞われました。
確かに、チップ識別ができなくてはJTAG操作を受け付けない上、基板上のチップのつながり方(JTAGチェイン)によって、送る信号を変えなくてはならない...知識としては知っていたのですが。ちなみにTAP(Test Access Port)はバウンダリテストの操作を行うためのステートマシンだそうです。
>openocd -f ../interface/arm-jtag-tiny-a.cfg Open On-Chip Debugger 0.1.0 (2009-01-21-21:15) Release BUGS? Read http://svn.berlios.de/svnroot/repos/openocd/trunk/BUGS $URL: https://kc8apf@svn.berlios.de/svnroot/repos/openocd/tags/openocd-0.1.0/src/openocd.c$ jtag_speed: 1 Error: There are no enabled taps? Error: There are no enabled taps? Warn : no gdb ports allocated as no target has been specified Warn : no tcl port specified, using default port 6666
ここでは、インストールからOpenOCDがターゲットで動くまでの流れを示します。 といっても、現在進行形で勉強中です。
インストール
Solitonwaveが取り扱っているOlimex社のARM-JTAG-TINYの場合、付属CDにドライバが入っています。 しかし、ドライバだけでなく、古い開発環境がCドライブ直下に強制的に作られ、勝手にPATH(環境変数)が通されてしまいます。OpenOCD自体は開発環境とは独立してインストールできるものなのですが...何とも嫌なインストーラが付いているものです。安心といえば安心ですが。
付属の開発環境は一般的に使われているEclipseベースです。ただ、付属バージョンはEuropa(木星の第2衛星)、現時点で最新バージョンはGanymede(木星の第3衛星)です。これらはバージョンが違うだけなのですが、若干インストールするものが変わってきます。これについてはARM用クロス開発環境を作るを参照してください。
最新の開発環境を使いたい場合、以下のようにして古い開発環境をアンインストールします。といっても、単純にファイルを消すだけでOKです。
- 付属CDのインストーラでインストール
- [C:\gccfd\Olimex OpenOCD Drivers]をどこかへ退避し、[gccfd]を捨てる
- PATHに追加された[C:\gccfd\bin;C:\gccfd\util]を削除
- ARM-JTAG-TINYケーブルを接続
- ドライバインストールで[特定の場所からインストール]を選択
- ドライバの参照先として、先ほど退避した[Olimex OpenOCD Drivers]を設定
- 2~3回ドライバのインストールが求められるが、同様に処理
以上でOpenOCDが動作する下地ができます。
設定ファイルを作るには
OpenOCDは、起動すればあとは自動...ではありません。ターゲットの情報を教えてあげなくてはなりません。手を抜けば[There are no enabled taps?]と言われてしまいます。(メッセージは疑問形なのでしょうか?)
設定ファイルの作り方については、[2][3]に記述されています。
実は、設定ファイルは全部自分で書かなくてはならないわけではなく、一部の市販品については用意されています。JTAGコネクタに必要な設定は[OpenOCD_install_dir/interface]以下にあり、ターゲットチップ毎の設定は[OpenOCD_install_dir/target]以下にあります。これらの設定ファイルを以下のように与えることで、記述の追加は最小限に抑えられるよう工夫されています。
>openocd -f config1.cfg -f config2.cfg ...
[2]によれば、設定ファイルの作り方は4通りに分けられるそうです。
- 他の設定ファイルを"source"(includeに相当)するもの
- 単一のopenocd.cfg設定ファイル → デフォルトで読まれる名前で単一のを作る
- コマンドライン上で[-f オプション]を並べる → すべて読み込まれる
- これらの組み合わせ
設定ファイルはTcl(JIM-Tclという縮小版)らしく、文字列の操作を行うことができるそうです。これを使うことで、1つの設定ファイルでいくつかのターゲットに柔軟に対応することが可能になるようです。この言語については[4]に記述されています。一部を日本語化(翻訳ではなく)したものをOpenOCDのTclに書きます。
幸いなことに、STM32シリーズについては、既に設定ファイルが用意されています。ターゲットデバイスにあった数値を変数に入れておくことで対応するようです。
ARM-JTAG-TINY + STM32-H103ボード用設定ファイルを作る
「Stm32.cfgを読む」で書いたように、いくつかの変数を予め用意しておくことで、stm32.cfgがJTAGの準備をしてくれるようです。 そこで、前述した設定ファイルの分類の1つ目、sourceを使うもので設定ファイルを構築してみます。
stm32.cfgを見てみると、パラメータとして必ず設定しなくてはならない部分は2つありました。 これらについては、リファレンスマニュアルに載っています。
- BSTAPID: バウンダリスキャン用TAPID
- CPUTAPID: CPU用TAPID
この2つがなぜ必要かといえば、STM32の中に、2つのTAPが入っているからです。 リファレンスマニュアル[6]の[Figure 259. JTAG TAP connections]を参照してください。
ターゲットマイコン
STM32-H103ボードに搭載されているのは、STM32F103RBT6という、パフォーマンスラインのMedium-densityのものです。 リビジョンはYと印字されていました。
CPUTAPID
リファレンスマニュアル[6]の「26.6.3 Cortex-M3 TAP」に載っていました。 Medium-densityでリビジョンYのチップの場合、[0x3ba00477]とすれば良いようです。
The TAP of the ARM Cortex-M3 integrates a JTAG ID code. This ID code is the ARM default one and has not been modified. This code is only accessible by the JTAG Debug Port. This code is 0x3BA00477 (corresponds to Cortex-M3 r1p1-01rel0, see Related documents on page 1). Only the DEV_ID(11:0) should be used for identification by the debugger/programmer tools.
BSTAPID
リファレンスマニュアル[6]の「26.6.2 Boundary scan TAP」に載っていました。 Medium-densityでリビジョンYのチップの場合、[0x16410041]とすれば良いようです。
JTAG ID code The TAP of the STM32F10xxx BSC (boundary scan) integrates a JTAG ID code equal to: ・In low-density devices: – 0x06412041 = Revision A ・In medium-density devices: – 0x06410041 = Revision A – 0x16410041 = Revision B and Revision Z ・In high-density devices: – 0x06414041 = Revision A
ひとまず完成した設定ファイル
なんとか認識に成功した模様です。 なお設定ファイルの最初の三行は、この後に読み込んでいるolimex-jtag-tiny-a.cfgの最初に書いてあります。ただし、インストール後のデフォルト状態においてコメントアウトされています。 とりあえず下記の設定ファイルをコピペして使いたい人が、olimex-jtag-tiny-a.cfgをいじらなくて済むようにするために、あえてつけました。 olimex-jtag-tiny-a.cfgをいじる場合は、最初の3行は不要となります。
ただし、このままではFlash書き込みはできません。とりあえず通信だけできる状態です。
#STM32F103RB, Revision Y interface ft2232 ft2232_device_desc "Olimex OpenOCD JTAG TINY A" ft2232_layout olimex-jtag set CPUTAPID 0x3ba00477 set BSTAPID 0x16410041 source [find ../interface/olimex-jtag-tiny-a.cfg] source [find ../target/stm32.cfg] --実行結果------------------------------------------------------ >openocd Open On-Chip Debugger 0.1.0 (2009-01-21-21:15) Release BUGS? Read http://svn.berlios.de/svnroot/repos/openocd/trunk/BUGS $URL: https://kc8apf@svn.berlios.de/svnroot/repos/openocd/tags/openocd-0.1.0/src/openocd.c $ jtag_speed: 1 500 kHz Info : JTAG tap: stm32.cpu tap/device found: 0x3ba00477 (Manufacturer: 0x23b, Part: 0xba00, Version: 0x3) Info : JTAG Tap/device matched Info : JTAG tap: stm32.bs tap/device found: 0x16410041 (Manufacturer: 0x020, Part: 0x6410, Version: 0x1) Info : JTAG Tap/device matched Warn : no tcl port specified, using default port 6666
OpenOCDと通信する
上記のようにOpenOCDが起動できたら、別のコマンドプロンプトを開いてOpenOCDにtelnet接続します。 すると、OpenOCDからJTAGを操作することができるようになります。試しにhelpコマンドとscan_chainコマンドを実行した結果を示します。scan_chainの結果、2つのTAPが存在することがわかります。設定ファイルで指定したTAP名でパラメータが表示されます。
>telnet localhost 4444
Open On-Chip Debugger
> help
bp set breakpoint <address> <length> [hw]
cpu <name> - prints out target options and a comment
on CPU which matches name
debug_level adjust debug level <0-3>
drscan execute DR scan <device> <num_bits> <value>
<num_bits1> <value2> ...
dump_image dump_image <file> <address> <size>
endstate finish JTAG operations in <tap_state>
exit exit telnet session
fast fast <enable/disable> - place at beginning of
config files. Sets defaults to fast and dangerous.
fast_load loads active fast load image to current target -
mainly for profiling purposes
fast_load_image same args as load_image, image stored in memory -
mainly for profiling purposes
find <file> - print full path to file according to
OpenOCD search rules
ft2232_device_desc the USB device description of the FTDI FT2232
device
ft2232_latency set the FT2232 latency timer to a new value
ft2232_layout the layout of the FT2232 GPIO signals used to
control output-enables and reset signals
ft2232_serial the serial number of the FTDI FT2232 device
ft2232_vid_pid the vendor ID and product ID of the FTDI FT2232
device
gdb_breakpoint_override hard/soft/disabled - force breakpoint type for gdb
'break' commands.The raison d'etre for this option
is to support GDB GUI's without a hard/soft
breakpoint concept where the default OpenOCD
behaviour is not sufficient
gdb_detach
gdb_flash_program enable or disable flash program
gdb_memory_map enable or disable memory map
gdb_port daemon configuration command gdb_port
gdb_report_data_abort enable or disable report data
halt halt target
help Tcl implementation of help command
init initializes target and servers - nop on subsequent
invocations
interface try to configure interface
irscan execute IR scan <device> <instr> [dev2] [instr2]
...
jtag perform jtag tap actions
jtag_device jtag_device <ir_length> <ir_expected> <ir_mask>
jtag_khz same as jtag_speed, except it takes maximum khz as
arguments. 0 KHz = RTCK.
jtag_nsrst_delay jtag_nsrst_delay <ms> - delay after deasserting
srst in ms
jtag_ntrst_delay jtag_ntrst_delay <ms> - delay after deasserting
trst in ms
jtag_rclk fallback_speed_khz - set JTAG speed to RCLK or use
fallback speed
jtag_reset toggle reset lines <trst> <srst>
jtag_speed set jtag speed (if supported)
load_image load_image <file> <address>
['bin'|'ihex'|'elf'|'s19'] [min_address]
[max_length]
log_output redirect logging to <file> (default: stderr)
mdb display memory bytes <addr> [count]
mdh display memory half-words <addr> [count]
mdw display memory words <addr> [count]
mwb write memory byte <addr> <value> [count]
mwh write memory half-word <addr> <value> [count]
mww write memory word <addr> <value> [count]
ocd_array2mem convert a TCL array to memory locations and write
the values
ocd_flash_banks return information about the flash banks
ocd_mem2array read memory and return as a TCL array for script
processing
poll poll target state
power_restore Overridable procedure run when power restore is
detected. Runs 'reset init' by default.
production <serialnumber> - Runs production procedure. Throws
exception if procedure failed. Prints progress
messages. Implement this procedure in the target
script.
production Runs test procedure. Throws exception if procedure
failed. Prints progress messages. Implement in
target script.
production_info Displays information on production procedure for
target script. Implement this procedure in target
script.
profile profiling samples the CPU PC
rbp remove breakpoint <adress>
reg display or set a register
reset reset target [run|halt|init] - default is run
reset_config [none/trst_only/srst_only/trst_and_srst]
[srst_pulls_trst/trst_pulls_srst]
[combined/separate]
[trst_push_pull/trst_open_drain]
[srst_push_pull/srst_open_drain]
resume resume target [addr]
runtest move to Run-Test/Idle, and execute <num_cycles>
rwp remove watchpoint <adress>
scan_chain print current scan chain configuration
script <filename> - filename of OpenOCD script (tcl) to
run
shutdown shut the server down
sleep <n> [busy] - sleep for n milliseconds. "busy"
means busy wait
soft_reset_halt halt the target and do a soft reset
srst_deasserted Overridable procedure run when srst deassert is
detected. Runs 'reset init' by default.
step step one instruction from current PC or [addr]
target configure target
targets change the current command line target (one
parameter) or lists targets (with no parameter)
tcl_port port on which to listen for incoming TCL syntax
telnet_port port on which to listen for incoming telnet
connections
verify_image verify_image <file> [offset] [type]
verify_ircapture verify value captured during Capture-IR
<enable|disable>
version show OpenOCD version
virt2phys translate a virtual address into a physical
address
wait_halt wait for target halt [time (s)]
wp set watchpoint <address> <length> <r/w/a> [value]
[mask]
xsvf run xsvf <file> [virt2]
cortex_m3 maskisr mask cortex_m3 interrupts ['on'|'off']
flash bank flash bank <driver> <base> <size> <chip_width>
<bus_width> <target> [driver_options ...]
flash erase_address erase address range <address> <length>
flash erase_check check erase state of sectors in flash bank <num>
flash erase_sector erase sectors at <bank> <first> <last>
flash fillb fill with pattern <address> <byte_pattern> <count>
flash fillh fill with pattern <address> <halfword_pattern>
<count>
flash fillw fill with pattern (no autoerase) <address>
<word_pattern> <count>
flash info print info about flash bank <num>
flash probe identify flash bank <num>
flash protect_check check protection state of sectors in flash bank
<num>
flash protect set protection of sectors at <bank> <first> <last>
<on|off>
flash write_bank write binary data to <bank> <file> <offset>
flash write_image write_image [erase] <file> [offset] [type]
mflash bank mflash bank <soc> <base> <chip_width> <bus_width>
<RST pin> <WP pin> <DPD pin> <target #>
nand device
pld device
stm32x lock lock device
stm32x mass_erase mass erase device
stm32x options_read read device option bytes
stm32x options_write write device option bytes
stm32x unlock unlock protected device
target_request debugmsgs enable/disable reception of debug messages from
target
trace history display trace history, ['clear'] history or set
[size]
trace point display trace points, ['clear'] list of trace
points, or add new tracepoint at [address]
> scan_chain
TapName | Enabled | IdCode Expected IrLen IrCap IrMask Instr
---|--------------------|---------|------------|------------|------|------|------|---------
0 | stm32.cpu | Y | 0x3ba00477 | 0x3ba00477 | 0x04 | 0x01 | 0x0f | 0x0a
1 | stm32.bs | Y | 0x16410041 | 0x16410041 | 0x05 | 0x01 | 0x01 | 0x1f
Flash書き込み
[7]によれば、Flashはマイコンを停止させてから書きこむようです。stm32.cfgにはFlashの番地が設定されていませんでした。
それなのに番地がわかるのは、flash probeコマンドが調べてくれるからなのかもしれません。
とりあえずオフセットを与えて書き込みを行いました。そうしないとだめなようで...リンカスクリプトを正しく書けばオフセットは不要になりました。これについてはARM開発環境構築手順を参照してください。
Open On-Chip Debugger
> halt
マイコンを停止
> poll
target state: halted
target halted due to undefined, current mode: Thread
xPSR: 0x00000000 pc: 0x00000000
状態を確認
> flash probe 0
device id = 0x20036410
flash size = 128kbytes
flash 'stm32x' found at 0x08000000
Flashの中身を見る? 1つ目のバンクを見る(stm32.cfgに書かれている?)
> flash write_image erase main.out 0x08000000 elf
auto erase enabled
wrote 4632 byte from file main.out in 1.218750s (3.711538 kb/s)
Flashを削除してから、elf形式のバイナリmain.outを0x08000000から書きこむ。
> reset
JTAG tap: stm32.cpu tap/device found: 0x3ba00477 (Manufacturer: 0x23b, Part: 0xb
a00, Version: 0x3)
JTAG Tap/device matched
JTAG tap: stm32.bs tap/device found: 0x16410041 (Manufacturer: 0x020, Part: 0x64
10, Version: 0x1)
JTAG Tap/device matched
target state: halted
target halted due to debug-request, current mode: Thread
xPSR: 0x21000000 pc: 0x00000110
JTAGからリセットする
> resume
停止状態を解除→プログラムが動き始める
まとめ
OpenOCDはターゲットに合わせて設定ファイルを作らなくては、正しく動作しないことがわかりました。 設定ファイルは何もない状態から作る必要はなく、市販のコネクタ、チップの設定ファイルは既に用意されています。
あとは、自分で作った設定ファイルにおいて、足りない個別のパラメータ...ターゲットCPUのモデルごとのIDなどを補ってから、コネクタ用とCPU用の設定ファイルをsourceで読み込めばOKです。
××間違った内容××
CPUTAPID
リファレンスマニュアル[6]の「26.6.1 MCU device ID code」に載っていました。 Medium-densityでリビジョンYのチップが搭載されていることから、[0x20030410]とすれば良いようです。
Bits 31:16 REV_ID(15:0) Revision identifier
This field indicates the revision of the device:
In low-density devices:
– 0x1000 = Revision A
In medium-density devices:
– 0x0000 = Revision A
– 0x2000 = Revision B
– 0x2001 = Revision Z
– 0x2003 = Revision Y
In high-density devices:
– 0x1000 = Revision A
– 0x1001 = Revision Z
In connectivity line devices:
– 0x1000 = Revision A
Bits 27:12 Reserved <---------------------図では15:12と書かれているので、たぶん間違い
Bits 11:0 DEV_ID(11:0): Device identifier
This field indicates the device ID.
For low-density devices, the device ID is 0x412
For medium-density devices, the device ID is 0x410
For high-density devices, the device ID is 0x414
For connectivity devices, the device ID is 0x418
→なんか別のものだった...
#STM32F103RB, Revision Y interface ft2232 ft2232_device_desc "Olimex OpenOCD JTAG TINY A" ft2232_layout olimex-jtag set CPUTAPID 0x20030410 set BSTAPID 0x16410041 source [find ../interface/olimex-jtag-tiny-a.cfg] source [find ../target/stm32.cfg] --実行結果------------------------------------------------------ >openocd Open On-Chip Debugger 0.1.0 (2009-01-21-21:15) Release BUGS? Read http://svn.berlios.de/svnroot/repos/openocd/trunk/BUGS $URL: https://kc8apf@svn.berlios.de/svnroot/repos/openocd/tags/openocd-0.1.0/src/openocd.c $ jtag_speed: 1 500 kHz Info : JTAG tap: stm32.cpu tap/device found: 0x3ba00477 (Manufacturer: 0x23b, Part: 0xba00, Version: 0x3) Error: JTAG tap: stm32.cpu got: 0x3ba00477 (mfg: 0x23b, part: 0xba00, ver: 0x3) Error: JTAG tap: stm32.cpu expected 1 of 1: 0x20030410 (mfg: 0x208, part: 0x0030, ver: 0x2) Error: trying to validate configured JTAG chain anyway... Warn : no tcl port specified, using default port 6666
デバイスが見つかって、0x3ba00477だと名乗ってきたが、設定したCPUTAPの値0x20030410と違うと怒られてしまう。
コメント
質問、要望などどうぞ(著者自身も書きます)
- ICのリビジョンには注意すべきです。JTAGの設定が違うと動かないので、気付かずに嵌ってしまいます。
- チップが同じなのでOlimex社のSTM32-H103ボードにも対応できそうです。
関連

