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です。

  1. 付属CDのインストーラでインストール
  2. [C:\gccfd\Olimex OpenOCD Drivers]をどこかへ退避し、[gccfd]を捨てる
  3. PATHに追加された[C:\gccfd\bin;C:\gccfd\util]を削除
  4. ARM-JTAG-TINYケーブルを接続
  5. ドライバインストールで[特定の場所からインストール]を選択
  6. ドライバの参照先として、先ほど退避した[Olimex OpenOCD Drivers]を設定
  7. 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通りに分けられるそうです。

  1. 他の設定ファイルを"source"(includeに相当)するもの
  2. 単一のopenocd.cfg設定ファイル → デフォルトで読まれる名前で単一のを作る
  3. コマンドライン上で[-f オプション]を並べる → すべて読み込まれる
  4. これらの組み合わせ

設定ファイルは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ボードにも対応できそうです。

関連

  1. OpenOCDのTcl
  2. Stm32.cfgを読む
  3. ARM用クロス開発環境を作る
  4. STM32-H103用LED点滅プログラム


参考文献

  1. OpenOCDオンラインマニュアル
  2. Simple Configuration Files
  3. Config File Guidelines
  4. Tcl Crash Course
  5. STM32F103RBxx
  6. STM32リファレンス
  7. ARM Cortex-M3 開発環境構築方法
個人用ツール