組み込み開発者必見!OpenOCDで効率的なデバッグ環境を構築しよう


組み込み開発者必見!OpenOCDで効率的なデバッグ環境を構築しよう

組み込みシステムの開発において、デバッグは避けて通れない重要なプロセスです。しかし、従来のデバッグ手法には様々な課題があり、特にコストや柔軟性の面で頭を悩ませている開発者も多いのではないでしょうか。

この記事では、オープンソースの強力なツール「OpenOCD (Open On-Chip Debugger)」に焦点を当て、その基本から応用、そして効率的なデバッグ環境の構築方法までを詳細に解説します。OpenOCDを使いこなすことで、デバッグの効率を大幅に向上させ、開発コストを削減することが可能になります。組み込み開発に携わるすべての方に、ぜひ知っていただきたいツールです。

1. なぜOpenOCDなのか?組み込みデバッグの現状と課題

組み込みシステムの開発は、PCソフトウェア開発とは異なり、ターゲットとなるハードウェア上でプログラムを動作させ、デバッグする必要があります。この過程で、プログラムの誤動作の原因特定、メモリ内容の確認、レジスタ値の監視といった作業が必須となります。

従来のデバッグ手法と課題

  • ROMモニタ/シリアルデバッグ:
    • ターゲット上で動作するデバッグモニタプログラムと、PC上のターミナルソフトをシリアル通信で接続して行う手法です。
    • メリット: 追加のハードウェアが比較的安価または不要な場合が多い。
    • デメリット: 機能が限定的(ブレークポイントが少ない、メモリ参照・変更が煩雑)、ターゲットプログラムにデバッグモニタを組み込む必要がある(メモリや実行時間への影響)、リアルタイム性が低い。
  • インサーキットエミュレータ (ICE):
    • CPUソケットに挿入したり、専用のデバッグポートに接続したりする高価な専用ハードウェアです。CPUの動作を外部から完全に制御できます。
    • メリット: 非常に強力で、リアルタイムトレースなど高度な機能を持つ。
    • デメリット: 非常に高価(数十万円〜数百万円)、特定のCPUファミリーや開発環境に特化していることが多い、ハードウェア設計の変更に弱い場合がある。
  • 専用デバッグプローブ + ベンダー提供ツール:
    • CPUベンダーやツールベンダーが提供する専用デバッグプローブ(例: J-Link, U-Link, ST-Linkなど)と、それに付属する専用IDEやデバッガを使用する手法です。
    • メリット: 特定のCPUに対して最適化されており、設定が比較的容易。高性能な場合が多い。
    • デメリット: プローブが高価な場合がある、ベンダー独自のインターフェースや機能にロックインされやすい、異なるベンダーのCPUを使う場合に別のツールが必要になる。

これらの手法に対し、OpenOCDはオープンソースでありながら、多様なデバッグアダプターとターゲットCPUに対応し、標準的なデバッグインターフェース(GDBサーバー)を提供するという強力な特徴を持っています。これにより、以下のようなメリットが得られます。

  • コスト削減: オープンハードウェアベースの安価なデバッグアダプター(数百円〜数千円で購入可能)や、開発ボードに内蔵されたデバッグ機能(ST-Linkなど)を最大限に活用できます。高価な専用ツールを購入する必要がなくなります。
  • 柔軟性と汎用性: 様々なCPUアーキテクチャ(ARM, RISC-V, MIPSなど多数)と多数のデバッグアダプターに対応しています。異なるプロジェクトやターゲットハードウェアでも、同じOpenOCDの知識とツールチェーンを活用できます。
  • 標準インターフェース: GDB (GNU Debugger) と連携するための標準的なGDBサーバー機能を提供します。これにより、Visual Studio Code, Eclipse, CLion, Emacsなど、多くのIDEやエディタがGDBインターフェース経由でOpenOCDと連携し、使い慣れた環境でデバッグできます。
  • 自動化と拡張性: Tclスクリプトによる強力な制御機能を持っています。複雑な初期化処理、テストの自動化、カスタムデバッグコマンドなどをスクリプトで記述できます。
  • 透明性とコミュニティ: オープンソースであるため、内部の動作を理解しやすく、問題が発生した場合もコミュニティのサポートやソースコードの確認が可能です。

これらの理由から、OpenOCDは特にコストを抑えつつ、柔軟性の高いデバッグ環境を構築したい組み込み開発者にとって、非常に魅力的な選択肢となっています。

2. OpenOCDの基本概念とアーキテクチャ

OpenOCD(Open On-Chip Debugger)は、名前の通りオンチップデバッグを行うためのツールです。その主な役割は、PC上で動作するデバッガ(主にGDB)と、ターゲットボード上のCPUの間に入って、デバッグ通信の仲介を行うことです。

OpenOCDの役割

OpenOCDは、PCのUSBポートなどに接続されたデバッグアダプター(JTAG/SWDプローブ)を介して、ターゲットCPUのデバッグインターフェース(JTAGやSWD)と通信します。PC側のデバッガは、TCP/IPなどのネットワーク経由でOpenOCDに接続し、ブレークポイント設定、メモリ読み書き、レジスタ操作、プログラム実行制御といったデバッグコマンドを送信します。OpenOCDはこれらのコマンドを受け取り、JTAG/SWDプロトコルに変換してデバッグアダプター経由でターゲットに送信し、結果をデバッガに返します。

OpenOCDのアーキテクチャ

OpenOCDの内部は、主に以下の層に分かれています。

  1. Adapter Layer (アダプター層):

    • 様々な種類のデバッグアダプターと通信するためのドライバーが含まれます。FTDIベースのアダプター、ST-Link、J-Linkクローン、CMSIS-DAPなど、ハードウェア固有の通信プロトコルを抽象化します。
    • アダプターの初期化、JTAG/SWD信号の生成、ターゲットとの物理的なやり取りを担当します。
    • 設定ファイルでは interface コマンドで指定されます。
  2. Target Layer (ターゲット層):

    • ターゲットとなるCPUアーキテクチャ(ARM Cortex-M, ARM Cortex-A, RISC-V, MIPSなど)や、特定のシリコンベンダーのチップ固有のデバッグ機能を扱います。
    • コアの停止/実行、レジスタアクセス、メモリマップ、フラッシュメモリのプログラミング方法、リセットメカニズムなどを定義します。
    • 設定ファイルでは target コマンドで指定されます。
  3. RTOS Awareness Layer (RTOS認識層):

    • FreeRTOS, ChibiOS, NuttXなどのリアルタイムOSがターゲット上で動作している場合に、タスクリスト、キュー、セマフォといったOS内部の情報をデバッガから参照可能にする機能です。
    • OSの種類と必要な情報を設定ファイルで指定します。
  4. Flash Programming Layer (フラッシュプログラミング層):

    • ターゲット上のフラッシュメモリにプログラムやデータを書き込むための機能を提供します。
    • 様々なフラッシュメモリの種類(NOR Flash, NAND Flash, 内蔵フラッシュなど)や、書き込みアルゴリズムをサポートします。
    • ターゲット設定ファイルや専用のスクリプトで定義されます。
  5. Command Layer / Scripting Layer (コマンド/スクリプト層):

    • OpenOCD独自のコマンドセットを提供し、Tclスクリプトエンジンを内蔵しています。
    • これにより、デバッグセッションの初期化、自動化された操作、カスタムコマンドの定義などが可能です。
    • GDBサーバーやTelnetサーバー経由で外部からアクセスできます。
  6. GDB Server Layer (GDBサーバー層):

    • 標準的なGDBリモートデバッグプロトコルを実装し、GDBからの接続を受け付けます。
    • GDBからのデバッグコマンド(ブレークポイント設定、レジスタ/メモリ読み書きなど)を内部のコマンドに変換し、ターゲット層を通じてハードウェアにアクセスします。

このモジュール化されたアーキテクチャにより、OpenOCDは様々なハードウェア構成に柔軟に対応できると同時に、GDBという標準的なインターフェースを提供できるのです。

3. デバッグに必要なハードウェア

OpenOCDを使ったデバッグ環境を構築するには、以下のハードウェアが必要です。

  1. デバッグ対象のターゲットボード:

    • 開発中の組み込みシステム本体です。
    • デバッグプローブを接続するためのデバッグコネクタ(JTAGヘッダ、SWDヘッダなど)が必要です。ピン配置とデバッグインターフェース(JTAGまたはSWD)の種類を確認してください。一般的には2×10ピン (JTAG) または2×5ピン (SWD) のヘッダが使われます。
    • ターゲットボードには電源が必要です。デバッグプローブから給電可能な場合もありますが、基本的にはターゲット自身に電源を供給します。
    • デバッグインターフェースの電圧レベル(3.3V, 1.8Vなど)と、デバッグプローブの電圧サポート範囲を確認してください。
  2. デバッグアダプター(JTAG/SWDプローブ):

    • PCとターゲットボードのデバッグインターフェースを接続するハードウェアです。OpenOCDは多数のアダプターをサポートしています。代表的なものをいくつか挙げます。
      • FTDIベース: FT2232HやFT232Hチップを使用したアダプター。Olimex ARM-USB-OCD(-TINY/-H), Bus Blasterなどが有名です。汎用性が高く、多くのアーキテクチャで利用できます。Windowsでは専用のUSBドライバー設定(Zadigなど)が必要になることがあります。
      • ST-Link/V2/V3: STM32系の開発ボード(Nucleo, Discoveryシリーズ)に内蔵されているデバッガー。または単体のプローブとしても入手可能です。非常に一般的で、STM32開発には必須とも言えます。OpenOCDはこれらのST-Linkをサポートしています。
      • J-Link (Segger): 高性能なプローブとして知られます。OpenOCDは通常、J-Linkのクローンや、J-Linkプロトコル互換モードを持つアダプターをサポートします。公式のSegger J-Linkは通常、Segger Native Driverの使用が推奨されますが、OpenOCDでも使用可能です(ただしライセンスに注意が必要な場合あり)。
      • CMSIS-DAP: ARMが提唱するデバッグインターフェース標準。mbed開発ボードなどに多く搭載されています。OpenOCDもこれをサポートします。
      • Raspberry Pi Pico Debug Probe: Raspberry Pi Pico(RP2040)を専用ファームウェアでデバッグプローブとして機能させたもの。非常に安価で入手しやすく、RP2040だけでなく他のターゲット(CMSIS-DAP互換として)のデバッグにも利用できます。
      • RasPi GPIO: Raspberry PiのGPIOピンを直接JTAG/SWDアダプターとして使用することも可能ですが、電気的な問題(電圧レベル変換、信号品質)に注意が必要です。ブレークアウトボードと適切に使用することをお勧めします。
    • アダプターを選択する際は、サポートするターゲットCPUアーキテクチャ、デバッグインターフェース(JTAG/SWD)、電圧レベル、そしてOpenOCDが公式にサポートしているかどうかを確認してください。
  3. PC (開発ホスト):

    • OpenOCD、クロスコンパイラ、GDB、そして必要に応じてIDEやエディタをインストールして使用する開発用PCです。
    • Windows, Linux, macOSなど、OpenOCDが動作するOSが必要です。

JTAGとSWDについて

OpenOCDが主に利用するデバッグインターフェースには、JTAG (Joint Test Action Group) と SWD (Serial Wire Debug) があります。

  • JTAG: IEEE 1149.1として標準化された境界スキャンテストおよびデバッグのためのインターフェースです。通常、TMS (Test Mode Select), TCK (Test Clock), TDI (Test Data In), TDO (Test Data Out) の4つの信号線と、オプションでTRST (Test Reset), SRST (System Reset) を使用します。信号線が多く、デイジーチェーン接続で複数のチップをデバッグできる利点があります。
  • SWD: ARMによって開発されたデバッグインターフェースで、JTAGよりも少ない信号線(SWDIO, SWCLKの2線+オプションでSWO)で高速なデバッグを実現します。特にピン数の限られたマイコンでよく利用されます。SWDは通常、JTAGポートと信号線を共有しており、アダプター側でJTAGとSWDを切り替えて使用します。

デバッグプローブとターゲットボードを接続する際は、JTAGまたはSWDの正しいピン配置を確認し、確実に接続することが最も重要です。誤った接続はハードウェアの損傷につながる可能性もあります。多くのプローブやボードにはピン配置が記載されていますが、不明な場合はデータシートや回路図を参照してください。

4. OpenOCDのインストール

OpenOCDはクロスプラットフォームで動作するため、Windows, Linux, macOSなど、様々な環境にインストールできます。インストール方法は、OSや入手したいバージョンによって異なります。

Windowsでのインストール

WindowsでOpenOCDを使う場合、最も簡単な方法は既にビルドされたバイナリパッケージを利用することです。

  1. バイナリパッケージの入手:

    • OpenOCDの公式サイト (openocd.org) や、サードパーティが提供するバイナリ配布サイトからダウンロードできます。組み込み開発ツールチェーン(例: GNU ARM Embedded Toolchain, Keil MDK, IAR Embedded Workbenchなど)に含まれている場合もあります。
    • 例えば、GNU ARM Embedded Toolchain (GCC ARM) の配布サイトでOpenOCDバイナリが提供されていることがあります。また、一部のチップベンダー(STMicroelectronicsなど)が提供する開発環境にOpenOCDがバンドルされていることもあります。
    • ダウンロードしたZIPファイルなどを任意のディレクトリ(例: C:\openocd)に展開します。
  2. 環境変数PATHの設定:

    • OpenOCD実行ファイル(openocd.exe)が含まれるディレクトリ(例: C:\openocd\bin)をシステムの環境変数PATHに追加します。これにより、コマンドプロンプトやPowerShellのどこからでもopenocdコマンドを実行できるようになります。
  3. USBドライバーの設定 (重要):

    • 多くのUSBデバッグアダプター(特にFTDIベースのアダプターや、一部のGeneric CMSIS-DAPアダプターなど)は、Windows標準のドライバーではなく、OpenOCDが使用するlibusb互換のドライバーで動作させる必要があります。
    • この設定には、Zadig というツールを使用するのが一般的です。
      • Zadigをダウンロードして実行します。
      • Optionsメニューから “List All Devices” にチェックを入れます。
      • ドロップダウンリストから、接続したデバッグアダプターのUSBデバイスを選択します(デバイス名を確認してください。例: “Dual RS232” や “USB Serial Converter B” など)。
      • Driverの右側にある矢印をクリックし、Replace DriverまたはInstall Driverを選択します。インストールするドライバーの種類は “libusbK (v3.0.x.x)” を選択するのが一般的です。もしlibusbKで問題があれば、WinUSBやlibusb-win32を試す場合もありますが、libusbKが最も推奨されます。
      • “Replace Driver” または “Install Driver” ボタンをクリックします。警告が表示されることがありますが、続行してください。
      • ドライバーのインストールが成功したら、Zadigを閉じます。
    • ST-Linkなど、ベンダー提供のドライバーでOpenOCDが動作するものもあります(OpenOCDのST-LinkドライバーはWinUSBまたはSTMicro純正ドライバーで動作)。この場合はZadigは不要かもしれません。アダプターのマニュアルやOpenOCDのドキュメントで確認してください。

Linuxでのインストール

Linuxでは、パッケージマネージャーを使う方法と、ソースコードからビルドする方法があります。

  1. パッケージマネージャーを使う方法 (推奨):

    • 多くの主要なLinuxディストリビューションのリポジトリにはOpenOCDが含まれています。
    • Debian/Ubuntu: sudo apt update && sudo apt install openocd
    • Fedora: sudo dnf install openocd
    • Arch Linux: sudo pacman -S openocd
    • この方法が最も手軽で、依存関係も自動的に解決されます。ただし、リポジトリにあるバージョンが最新版ではない場合があります。
  2. ソースコードからビルドする方法:

    • 最新版の機能を使いたい場合や、特定のハードウェアサポートを有効にしたい場合に選択します。
    • 必要な依存ライブラリをインストールします。OpenOCDのビルドには通常、libtool, autoconf, automake, texinfo, libusb-1.0-0-dev, libhidapi-dev などが必要です。アダプターによっては追加のライブラリ(例: FTDIにはlibftdi-dev)が必要です。
    • OpenOCDのソースコードをダウンロードします。
    • ターミナルを開き、ソースコードディレクトリに移動します。
    • ビルドスクリプトを実行します: ./bootstrap
    • configureスクリプトを実行します。この際、サポートしたいアダプターや機能を指定します。例: ./configure --enable-stlink --enable-jlink --enable-ftdi --enable-cmsis-dap--helpオプションで利用可能なオプションを確認できます。
    • コンパイルとインストールを実行します: make -j$(nproc) (並列ビルド) followed by sudo make install.
  3. udevルールの設定 (重要):

    • 非rootユーザーがデバッグアダプターにアクセスできるようにするために、udevルールを設定する必要があります。
    • OpenOCDのソースコードには、contrib/60-openocd.rules のようなudevルールのサンプルファイルが含まれています。
    • このファイルを/etc/udev/rules.d/ ディレクトリにコピーします。sudo cp contrib/60-openocd.rules /etc/udev/rules.d/
    • udevルールをリロードします。sudo udevadm control --reload-rules および sudo udevadm trigger
    • PCからデバッグアダプターを一度抜いて、再度接続します。これで非rootユーザーでもアダプターにアクセスできるようになるはずです。

macOSでのインストール

macOSでも、パッケージマネージャーを使う方法とソースコードからビルドする方法があります。

  1. Homebrewを使う方法 (推奨):

    • Homebrewがインストールされている場合、以下のコマンドで簡単にインストールできます。
    • brew update
    • brew install openocd
    • Homebrewは依存関係も自動的に解決してくれます。
  2. ソースコードからビルドする方法:

    • Linuxとほぼ同様の手順です。Xcode Command Line ToolsとHomebrewなどで依存ライブラリ(libusb, hidapiなど)をインストールしておく必要があります。

インストール後、ターミナルやコマンドプロンプトで openocd --version を実行して、OpenOCDが正しくインストールされ、パスが通っているか確認しましょう。

5. OpenOCDの設定ファイル (.cfg)

OpenOCDの動作は、1つまたは複数の設定ファイル(通常 .cfg 拡張子)によって制御されます。これらのファイルは、使用するデバッグアダプターの種類、ターゲットCPU、ターゲットボードの構成、フラッシュメモリ情報、起動時の処理などをOpenOCDに指示します。

OpenOCDは、起動時に指定された設定ファイルを順番に読み込み、記述されているコマンドを実行します。設定ファイルはTclスクリプト形式で記述されており、OpenOCD独自のコマンドとTclの構文を組み合わせることができます。

設定ファイルの種類と構造

OpenOCDのインストールディレクトリには、多くのサンプル設定ファイルが用意されています。これらは通常、以下のディレクトリに分類されています。

  • interface/: 様々なデバッグアダプターに関する設定ファイル。stlink.cfg, ftdi/olimex-arm-usb-ocd-h.cfg, cmsis-dap.cfg などがあります。
  • target/: 様々なCPUアーキテクチャや具体的なチップに関する設定ファイル。arm7t(dmi).cfg, cortex_m.cfg, stm32f4x.cfg, esp32.cfg などがあります。
  • board/: 特定の開発ボード向けに、アダプター設定とターゲット設定を組み合わせ、さらにボード固有の初期化コマンドなどを追加したファイル。stm32f4discovery.cfg, nucleo_f401re.cfg などがあります。

デバッグセッションを開始する際は、これらのファイルの中から、使用するアダプターとターゲットボードに合ったものを組み合わせて指定します。最も一般的なのは、interface/*.cfgtarget/*.cfg を組み合わせて指定するか、または board/*.cfg ファイルを使用する方法です。board/*.cfg ファイルは、内部で対応する interface/*.cfgtarget/*.cfgsource コマンドでインクルードしている場合が多いです。

主要なOpenOCDコマンド例 (設定ファイル内で使用)

設定ファイルでは、以下のようなOpenOCDコマンドを記述します。

  • source [ファイル名]: 別の設定ファイルを読み込み、その内容を実行します。board ファイルが interfacetarget ファイルをインクルードする際によく使われます。
  • interface [ドライバー名]: 使用するデバッグアダプターのドライバーを指定します。例: interface ftdi, interface stlink, interface cmsis_dap.
  • adapter speed [khz]: JTAG/SWD通信のクロック速度をkHz単位で設定します。ターゲットが高速な通信をサポートしない場合や、配線が長い場合は遅く設定する必要があります。adapter speed auto とすると、ターゲットのTDO信号から適切な速度を自動検出(一部アダプターのみ)または最大速度で試行します。
  • transport [タイプ]: JTAGまたはSWDのどちらのトランスポートを使用するかを指定します。例: transport select swd.
  • target [アーキテクチャ名] [オプション]: ターゲットCPUの種類を指定し、関連設定を行います。例: target cortex_m main.cpu. cortex_m はARM Cortex-Mコアを指定し、main.cpu はターゲットオブジェクトに付ける名前です。
  • flash bank [バンク名] [ドライバー] [ベースアドレス] [サイズ] [0] [ターゲット名]: ターゲット上のフラッシュメモリバンクを設定します。[ドライバー] はフラッシュ書き込みに使用するアルゴリズム、[ベースアドレス] はメモリマップ上の開始アドレス、[サイズ] はバンクのサイズ、[ターゲット名] はそのフラッシュを含むターゲットオブジェクトの名前です。例: flash bank stm32f4x 0x08000000 0x100000 main.cpu.
  • reset_config [オプション]: リセット信号(SRST, TRST)の制御方法や、リセット後のターゲット状態を設定します。例: reset_config srst_only srst_pullup separate.
  • init: アダプターとターゲットを初期化し、ターゲットに接続を試みます。通常、起動時に自動で実行されますが、スクリプト内で明示的に呼び出すこともあります。
  • halt: ターゲットCPUの実行を停止させます。
  • program [ファイル名] [アドレス] [ファイルタイプ]: 指定されたファイルをターゲットメモリに書き込みます。これはOpenOCD起動 に、Telnet/TclインターフェースやGDB経由で実行されるコマンドですが、設定ファイル中のスクリプトブロック(例: init 後に実行されるコールバック)で使うこともあります。
  • flash write_image [ファイル名] [アドレス] [ファイルタイプ]: プログラムをフラッシュメモリに書き込み、必要なら消去やベリファイも自動で行います。これも通常起動 に実行されるコマンドです。
  • $_TARGETNAME configure -rtos auto: RTOS認識機能を有効にします。$_TARGETNAMEtarget コマンドで指定したターゲットオブジェクト名(例: main.cpu)です。auto はOSを自動検出します。

設定ファイルの作成とカスタマイズ

多くの場合、既存の board/*.cfg ファイルが利用できるか、あるいはそれに近い interface/*.cfgtarget/*.cfg ファイルが存在します。まずはこれらのサンプルファイルを参考にし、必要に応じてカスタマイズするのが効率的です。

  • 既存のボードファイルを使う: 開発ボードがOpenOCDで広く使われているものなら、board/ ディレクトリに対応するファイルがある可能性が高いです。例: openocd -f board/stm32f4discovery.cfg
  • インターフェースとターゲットファイルを組み合わせる: 汎用アダプターや、ボードファイルがない場合は、アダプター設定とターゲット設定ファイルを指定します。例: openocd -f interface/ftdi/olimex-arm-usb-ocd-h.cfg -f target/stm32f4x.cfg
  • カスタム設定ファイルを作成する: 既存のファイルをコピーして、ボード固有のピン設定、フラッシュマップ、リセット設定などを追加・変更して独自の .cfg ファイルを作成します。例: my_board.cfg を作成し、source interface/stlink.cfgsource target/stm32g0x.cfg を記述した後、ボード固有の設定コマンドを追加します。

設定ファイルの検索パス

OpenOCDは、-f オプションで指定されたファイルの他、所定のパス(通常はOpenOCDインストールディレクトリの scripts サブディレクトリや、環境変数 OPENOCD_SCRIPTS で指定されたパス)を検索して設定ファイルを探します。

6. OpenOCDの起動と基本的な使い方

OpenOCDは、コマンドラインから起動するのが基本です。

コマンドラインからの起動

OpenOCDを起動するには、ターミナル(コマンドプロンプト、PowerShell, Bashなど)を開き、openocd コマンドに -f オプションで1つ以上の設定ファイルを指定します。

“`bash
openocd -f [アダプター設定ファイル] -f [ターゲット設定ファイル] …

または

openocd -f [ボード設定ファイル]
“`

例:

  • ST-Link/V2を使ってSTM32F4Discoveryボードをデバッグする場合:
    bash
    openocd -f board/stm32f4discovery.cfg
  • Olimex ARM-USB-OCD-H (FTDIベース) を使ってSTM32F103をデバッグする場合:
    bash
    openocd -f interface/ftdi/olimex-arm-usb-ocd-h.cfg -f target/stm32f1x.cfg

OpenOCDが正常に起動すると、デバッグアダプターを認識し、ターゲットに接続を試みます。成功すると、以下のようなログメッセージが表示されます。

Open On-Chip Debugger 0.11.0+dev (...)
Licensed under GNU GPL v2
For bug reports, help and support, please visit http://openocd.org
[ボードファイル名]を読み込みます
adapter speed: 1000 kHz
Info : auto-selecting first available adapter list: "stlink"
Info : STLINK V2J39S7 (API v2) VID:PID 0483:3748
Info : Target voltage: 3.247761
Info : clock speed 1000 kHz
Info : STLINK V2J39S7 (API v2) Target: stm32f4x.cpu
Info : stm32f4x.cpu: hardware has 6 breakpoints, 4 watchpoints
Info : stm32f4x.cpu: external reset detected
Info : Listening on port 3333 for gdb connections
Info : Listening on port 6666 for tcl connections
Info : Listening on port 4444 for telnet connections

このログから、使用しているOpenOCDのバージョン、アダプターの認識状況(タイプ、シリアル番号など)、ターゲットへの接続状況、クロック速度、ブレークポイント/ウォッチポイント数、そしてGDBサーバー、Tclサーバー、Telnetサーバーがそれぞれどのポートでリスニングしているかなどが分かります。デフォルトでは、GDBはポート3333、Tclはポート6666、Telnetはポート4444で待ち受けます。

OpenOCD起動中の状態

OpenOCDが起動すると、通常はターゲットCPUはリセット直後の状態または停止した状態になります(設定によります)。この状態で、OpenOCDは外部からの接続(GDB, Tcl, Telnet)を待っています。

OpenOCDが起動したターミナル自体は、デバッグサーバーとして動作しており、OpenOCD独自のコマンドを入力することはできません(Ctrl+Cで終了)。デバッグ操作は、GDBやTelnetクライアントなどの別のプロセスから行います。

基本的な操作インターフェース

OpenOCDは主に以下の3つのインターフェースを提供します。

  1. GDBサーバー (ポート 3333):
    • 標準的なGDBリモートデバッグプロトコルを提供します。GDBやGUIデバッガ(IDE内蔵デバッガなど)は、このポートに接続してデバッグセッションを行います。ブレークポイント設定、ステップ実行、レジスタ/メモリ読み書き、プログラムロードなど、デバッグの主要な操作はここから行われます。
  2. Tclインターフェース (ポート 6666):
    • OpenOCD独自のTclコマンドを実行するためのインターフェースです。OpenOCDの内部状態の確認、特定のハードウェアレジスタ操作、フラッシュプログラミング、スクリプト実行など、GDBでは直接できない低レベルな操作やOpenOCD固有の機能へのアクセスに利用できます。Telnetクライアントなどで接続して手動でコマンドを入力するか、外部スクリプトから自動で実行できます。
  3. Telnetインターフェース (ポート 4444):
    • Tclインターフェースとほぼ同じ機能を提供しますが、Telnetプロトコルを使用します。古い設定ではTclインターフェースとは別のポートでしたが、最近のバージョンではポート6666と共有されることが多いです。Telnetクライアントで接続して、Tclコマンドを入力できます。

初めてOpenOCDが正常に起動したことを確認するには、別のターミナルを開き、Telnetクライアントで接続してみるのが簡単です。

“`bash
telnet localhost 4444

または

telnet localhost 6666
“`

接続が成功すると、OpenOCDのプロンプト(> または OpenOCD>)が表示されます。ここでOpenOCDコマンドを入力できます。例えば:

  • halt: ターゲットを停止
  • resume: ターゲットを実行再開
  • reg: レジスタ値を表示
  • mdw 0x08000000: アドレス0x08000000からのメモリ内容をワード(32-bit)単位で表示
  • flash probe 0: フラッシュメモリを検出 (バンク0)

デバッグの主操作はGDBから行うため、Tcl/Telnetインターフェースは主にOpenOCDの動作確認、セットアップ、高度なスクリプト実行のために利用します。

7. GDBとの連携

組み込み開発におけるOpenOCDの最も一般的な使い方は、GNU Debugger (GDB) のバックエンドとして利用することです。GDBは、ソースコードレベルでのデバッグ、ブレークポイント、ウォッチポイント、変数参照など、開発者が最もよく使うデバッグ機能を提供します。

GDBのインストール

ターゲットCPUに合わせたクロス開発用のGDBが必要です。例えばARM Cortex-M開発なら、arm-none-eabi-gdb のようなツールチェーンに含まれるGDBを使用します。これは通常、クロスコンパイラ(GCCなど)と一緒にインストールされます。

GDBからOpenOCDへの接続

OpenOCDがGDBサーバーとして起動したら、別のターミナルを開きGDBを起動します。そして、GDBの target remote コマンドを使ってOpenOCDのGDBサーバーポートに接続します。

“`bash

ターゲットの実行ファイルを指定してGDBを起動 (任意)

gdb [実行ファイル名].elf

GDBプロンプト (gdb) でOpenOCDに接続

(gdb) target remote localhost:3333
“`

localhost はOpenOCDが実行されているPCのホスト名またはIPアドレスです。通常は同じPC上で実行するため localhost を指定します。3333 はOpenOCDのGDBサーバーポート番号です(設定で変更可能)。

接続が成功すると、GDBはターゲットCPUの現在の状態(プログラムカウンタ、レジスタなど)を取得し、以下のようなメッセージが表示される場合があります。

Remote debugging using localhost:3333
[New Remote target]
0x0800xxxx in [関数名] ()

これでGDBはOpenOCD経由でターゲットCPUと通信できる状態になりました。

GDBを使った基本的なデバッグ操作 (OpenOCD経由)

GDBの標準的なコマンドを使って、ターゲット上でデバッグを行います。

  • プログラムのロード:
    • コンパイル済みの実行ファイル(通常はELF形式)をターゲットのフラッシュメモリまたはRAMに書き込みます。OpenOCDの flash write_image コマンドが使われます。
    • gdb
      (gdb) load [実行ファイル名].elf
      # または
      (gdb) flash write_image erase [実行ファイル名].elf 0 elf

      load はGDBのコマンドですが、OpenOCDに接続している場合、OpenOCDのフラッシュ書き込み機能が呼び出されます。erase オプションは書き込み前にフラッシュを消去します。
  • 実行の開始/継続:
    • gdb
      (gdb) run # プログラムの先頭から実行 (通常リセット後)
      (gdb) continue # 停止しているプログラムの実行を再開
      (gdb) c # continue の短縮形
    • run コマンドは、通常、ターゲットをリセットしてプログラムエントリポイントから実行を開始します。
  • ステップ実行:
    • gdb
      (gdb) step # 1ステップ実行 (関数コールの中に入る)
      (gdb) next # 1ステップ実行 (関数コールは飛ばす)
      (gdb) si # 1命令実行 (アセンブリレベル)
      (gdb) ni # 1命令実行 (関数コールは飛ばす、アセンブリレベル)
  • ブレークポイントの設定:
    • プログラムの特定の箇所で実行を停止させます。
    • gdb
      (gdb) break [ファイル名]:[行番号]
      (gdb) break [関数名]
      (gdb) break *[アドレス] # 特定アドレスに設定
    • OpenOCDはハードウェアブレークポイント(CPUが提供するデバッグレジスタを使用)とソフトウェアブレークポイント(対象コードを一時的にブレークポイント命令に置き換える)の両方をサポートします。ハードウェアブレークポイントには数に限りがあります。
    • gdb
      (gdb) info breakpoints # 設定済みブレークポイント一覧表示
      (gdb) delete [ブレークポイント番号] # ブレークポイント削除
  • ウォッチポイントの設定:
    • 特定の変数やメモリ領域の値が変化したときに実行を停止させます。ハードウェアウォッチポイントを使用します。
    • gdb
      (gdb) watch [変数名]
      (gdb) awatch [変数名] # Read/Writeアクセスで停止
      (gdb) rwatch [変数名] # Readアクセスで停止
      (gdb) watch *[アドレス] # 特定アドレスを監視
    • ハードウェアウォッチポイントも数に限りがあります。
  • 変数やメモリの参照/変更:
    • gdb
      (gdb) print [変数名] # 変数の値を表示
      (gdb) display [変数名] # ステップ実行ごとに値を自動表示
      (gdb) set variable [変数名] = [値] # 変数の値を変更
      (gdb) x/[N][サイズ][フォーマット] [アドレス/変数名] # メモリ内容をダンプ
      # 例: x/10xw my_array (my_arrayの先頭から10個のワードを16進数で表示)
      # N: 個数, サイズ: b(byte), h(halfword), w(word), g(giantword=8 bytes), フォーマット: x(hex), d(decimal), u(unsigned decimal), f(float), c(char), s(string), i(instruction)
  • レジスタの参照:
    • gdb
      (gdb) info registers # すべてのレジスタ値を表示
      (gdb) print $[レジスタ名] # 特定レジスタの値を表示 (例: print $pc)
  • スタックトレース:
    • 現在のコールスタックを表示します。
    • gdb
      (gdb) backtrace # コールスタックを表示
      (gdb) bt # backtrace の短縮形
  • ターゲットのリセット:
    • gdb
      (gdb) monitor reset # OpenOCDのresetコマンドを実行
    • monitor コマンドは、GDBから接続しているOpenOCDに対して、OpenOCD独自のコマンド(この場合は reset)を実行させるためのコマンドです。

.gdbinit ファイル

GDBの起動時に自動的に実行されるコマンドを記述しておくファイルです。プロジェクトのルートディレクトリなどに .gdbinit または .gdbinit-[アーキテクチャ] という名前で配置しておくと便利です。

例えば、以下のような内容を .gdbinit に記述しておくと、GDB起動時にOpenOCDに自動接続し、プログラムをロードし、main関数で停止させることができます。

“`gdb
target remote localhost:3333

ファイルが存在し、ビルドが成功していることを確認してからロード

if file(“build/my_program.elf”)
load
# break main # main関数で停止したい場合
endif

continue # ロード後にそのまま実行したい場合

“`

これにより、デバッグ開始時の定型作業を自動化できます。

8. フラッシュプログラミング

OpenOCDは強力なフラッシュプログラミング機能を持っています。これはGDBの load コマンドから透過的に呼び出されるだけでなく、OpenOCD独自のコマンドで直接実行することも可能です。

OpenOCDコマンドによるフラッシュプログラミング

Telnet/TclインターフェースやGDBの monitor コマンド経由で、以下のOpenOCDフラッシュ関連コマンドを実行できます。

  • flash info [バンク番号]: 指定したフラッシュバンクの情報を表示します。
  • flash probe [バンク番号]: フラッシュメモリを検出します。
  • flash erase_sector [バンク番号] [開始セクター] [終了セクター]: 指定した範囲のセクターを消去します。
  • flash erase_area [バンク番号] [ベースアドレス] [サイズ]: 指定したアドレス範囲を消去します。
  • flash erase_chip [バンク番号]: チップ全体を消去します。
  • flash write_image [ファイル名] [アドレス] [ファイルタイプ]: 指定されたファイルをターゲットの指定アドレスに書き込みます。ファイルタイプは elf, ihex (Intel Hex), binary, srec (Motorola SREC) などが指定できます。
  • flash verify_image [ファイル名] [アドレス] [ファイルタイプ]: 指定されたファイルの内容と、ターゲットメモリの指定アドレスからの内容を比較し、書き込みが正しいか検証します。
  • program [ファイル名] [verify] [reset] [アドレス] [ファイルタイプ]: GDBの load コマンドに対応するOpenOCDコマンドです。write_image に似ていますが、通常はデバッグセッションの開始時に使用され、より高レベルな処理(リセット、ベリファイオプションなど)を含みます。

フラッシュプログラミングの手順例 (Telnet/Tclから)

  1. OpenOCDを起動します (openocd -f ...)。
  2. 別のターミナルでTelnetまたはTclクライアントを起動し、OpenOCDに接続します (telnet localhost 4444)。
  3. ターゲットが停止していることを確認します (halt)。リセット直後であれば停止しているはずです。
  4. フラッシュを消去します(必要であれば)。
    tcl
    flash erase_chip 0

    または特定領域
    tcl
    flash erase_area 0 0x08000000 0x10000 # Bank 0, Address 0x08000000, Size 0x10000
  5. プログラム(ELFファイルなど)を書き込みます。
    tcl
    flash write_image my_program.elf 0 elf

    アドレスを省略した場合や、ファイルタイプがbinaryの場合は明示的なアドレスが必要です。
    tcl
    flash write_image my_program.bin 0x08000000 binary
  6. 書き込みが正しいか検証します(オプション)。
    tcl
    flash verify_image my_program.elf 0 elf
  7. ターゲットをリセットして実行を開始します。
    tcl
    reset run

    reset run はリセット後にすぐに実行を開始します。reset halt はリセット後に停止した状態で待機します。reset のみだと設定ファイル中の reset_config に従います。

これらのコマンドは、ビルドスクリプトからOpenOCDのTclポートに接続して自動実行させることも可能です。例えば、ビルド完了後に自動でフラッシュ書き込みを行うことができます。

フラッシュ書き込みの設定(アルゴリズム、セクターサイズなど)は、ターゲット設定ファイル(target/*.cfg)内の flash banks コマンドや、別途フラッシュドライバーファイルで定義されています。使用するチップに合わせて正しい設定ファイルを選ぶことが重要です。

9. 高度なデバッグ機能とTclスクリプト

OpenOCDはその豊富なコマンドセットとTclスクリプトエンジンにより、基本的なデバッグ操作だけでなく、より高度な機能や自動化を実現できます。

OpenOCDコマンドの活用 (Tcl/Telnet or GDB monitor)

Telnet/TclインターフェースやGDBの monitor コマンドから実行できる便利なコマンドをいくつか紹介します。

  • メモリ/レジスタの直接操作:

    • mdw [アドレス] [数]: 指定アドレスから[数]ワード(32bit)を読み出し、16進数で表示 (Memory Display Word)
    • mdd [アドレス] [数]: 指定アドレスから[数]ダブルワード(64bit)を読み出し
    • mdh [アドレス] [数]: 指定アドレスから[数]ハーフワード(16bit)を読み出し
    • mdb [アドレス] [数]: 指定アドレスから[数]バイト(8bit)を読み出し
    • mww [アドレス] [値]: 指定アドレスにワード(32bit)を書き込み (Memory Write Word)
    • mwh [アドレス] [値]: 指定アドレスにハーフワード(16bit)を書き込み
    • mwb [アドレス] [値]: 指定アドレスにバイト(8bit)を書き込み
    • reg [レジスタ名]: 指定レジスタの値を表示
    • reg [レジスタ名] [値]: 指定レジスタに値を書き込み
      これらのコマンドは、特定のハードウェアレジスタ(GPIO設定、クロック設定など)の状態をデバッグ中に確認したり、一時的に変更したりするのに役立ちます。
  • リセット制御:

    • reset: 設定ファイルで定義された方法でターゲットをリセットします。
    • reset init: リセット後、設定ファイルの init セクションを再実行します。
    • reset run: リセット後、ターゲットの実行を開始します。
    • reset halt: リセット後、ターゲットを停止した状態で待機します。
    • soft_reset_halt: CPUのリセット命令などによるソフトウェアリセットを実行し、停止します。
    • system_reset_halt: システムリセット信号(SRST)によるリセットを実行し、停止します。
  • ランコントロール:

    • halt: ターゲットの実行を停止します。
    • resume [アドレス]: 停止しているターゲットの実行を指定アドレスから再開します。アドレスを省略すると現在のPCから再開します。
  • ターゲット状態の確認:

    • target status: ターゲットの現在の状態(Running, Haltedなど)を表示します。
    • targets: 検出されたターゲットの一覧を表示します(マルチコアCPUの場合など)。

Tclスクリプトによる自動化

OpenOCDの設定ファイルはTclスクリプトそのものです。これにより、起動時の複雑な初期化処理を記述したり、デバッグセッション中にカスタムコマンドを定義したり、一連のデバッグ操作を自動化したりすることが可能です。

Tclスクリプトの例:

  1. 起動時のカスタム初期化:
    ボード固有の設定ファイル (my_board.cfg) に、ターゲット接続後、フラッシュ書き込み前に特定のレジスタを設定する処理を追加する例。

    “`tcl

    … interface および target 設定 …

    ターゲット接続後のコールバック関数を定義

    proc my_board_post_init {} {
    echo “— My board post-init started —“

    # 例: 特定のIOピンを有効化する (架空のレジスタアドレスと値)
    echo "Setting up GPIO..."
    mww 0x40020000 0x00000001 # GPIOポートAのクロックを有効化 (仮)
    mww 0x48000000 0x00000008 # GPIOAピン3を出力モードに設定 (仮)
    
    echo "--- My board post-init finished ---"
    

    }

    ‘init’ コマンド実行後に my_board_post_init を呼び出すようにフックを設定

    target name が main.cpu と仮定

    main.cpu configure -event post-init { my_board_post_init }

    … flash bank 設定 …

    “`

    この例では、proc コマンドで my_board_post_init という名前のTclプロシージャ(関数)を定義しています。このプロシージャは、ターゲットのメモリマップに直接値を書き込む mww コマンドを実行しています。そして、configure -event post-init コマンドを使って、OpenOCDがターゲットへの接続と初期化を完了した直後(init コマンドの実行後)にこのプロシージャが自動的に実行されるように設定しています。

  2. カスタムデバッグコマンドの定義:
    Telnet/TclインターフェースやGDBの monitor コマンドから呼び出せる独自のコマンドを定義する例。

    “`tcl

    LEDを点灯させるカスタムコマンドを定義

    proc led_on {} {
    echo “Turning LED on…”
    # 仮定: アドレス 0x48000014 のバイト値を 1 にするとLED点灯
    mwb 0x48000014 1
    }

    LEDを消灯させるカスタムコマンドを定義

    proc led_off {} {
    echo “Turning LED off…”
    # 仮定: アドレス 0x48000014 のバイト値を 0 にするとLED消灯
    mwb 0x48000014 0
    }
    ``
    これらの定義を
    .cfgファイルに含めるか、OpenOCD起動後にTcl/Telnetで入力しておくと、Telnetでled_onled_offと入力したり、GDBでmonitor led_on` と入力したりして、定義した処理を実行できるようになります。これは特定のハードウェア機能のテストや状態確認に非常に便利です。

  3. 自動テストスクリプト:
    ビルドスクリプトなどからOpenOCDを起動し、Tclポート経由で一連のコマンド(フラッシュ書き込み、プログラム実行、特定のメモリ値の確認など)を自動実行させることで、簡単なハードウェアテストを自動化できます。

    “`tcl

    auto_test.tcl

    proc run_test {} {
    echo “— Running Automated Test —“

    # ターゲットをリセットし、プログラムをロード
    reset halt
    flash write_image my_test_program.elf 0 elf
    verify_image my_test_program.elf 0 elf
    
    # プログラムを実行
    resume
    
    # テスト完了またはエラー発生まで待機 (タイムアウト付き)
    set timeout_sec 10
    set start_time [clock seconds]
    set test_finished 0
    while { [clock seconds] - $start_time < $timeout_sec && $test_finished == 0 } {
        sleep 100 # 100ミリ秒待機
        # 仮定: テスト結果を示す変数 result_status (アドレス 0x20000000) を監視
        set status [mdb 0x20000000 1]
        if { [string match "01" $status] } { # 仮定: result_status が 1 なら成功
            echo "Test passed!"
            set test_finished 1
        } elseif { [string match "FF" $status] } { # 仮定: result_status が 255 ならエラー
            echo "Test failed with error code: [mdb 0x20000001 1]"
            halt # エラー発生時など、必要に応じてターゲットを停止
            set test_finished 1
        }
    }
    
    if { $test_finished == 0 } {
        echo "Test timed out."
        halt
    }
    
    echo "--- Test Finished ---"
    

    }

    OpenOCD起動後に自動で run_test プロシージャを実行する場合:

    init コマンド実行後に呼び出す例 (設定ファイルに記述)

    main.cpu configure -event post-init { run_test }

    外部から Tcl で実行する場合:

    openocd -f … -c “tcl_port 6666; init” # OpenOCD起動

    tclsh # 別のターミナルでTclクライアント起動

    package require TclSock # ソケット通信ライブラリ読み込み

    set sock [socket localhost 6666] # OpenOCD Tclポートに接続

    puts $sock “source auto_test.tcl” # スクリプトファイルを読み込み

    gets $sock line # OpenOCDからの応答を読み飛ばし

    puts $sock “run_test” # run_test プロシージャ実行

    gets $sock line # OpenOCDからの応答を読み飛ばし

    … 応答をパースしてテスト結果を判定 …

    close $sock

    exit # Tclクライアント終了

    “`
    このスクリプトは複雑ですが、OpenOCDのTclスクリプト機能がテスト自動化にいかに強力かを示しています。外部プロセスからTclポートに接続してスクリプトを実行することで、CI/CDパイプラインなどに組み込むことも可能です。

OpenOCDのTclスクリプト機能は非常に柔軟で強力です。OpenOCDユーザーマニュアルのTclコマンドリファレンスを参照すると、さらに多くの機能(条件分岐、ループ、ファイル操作など)を利用できることが分かります。

10. 一般的なトラブルシューティング

OpenOCDを使ったデバッグ環境の構築や使用中に遭遇しやすいトラブルと、その対処法をいくつか挙げます。

1. OpenOCDがデバッグアダプターを認識しない/接続できない

  • WindowsでのUSBドライバー問題:
    • 最も一般的な原因の一つです。Zadigを使ってアダプターに適切なlibusbK (またはWinUSB/libusb-win32) ドライバーがインストールされているか確認してください。デバイスマネージャーでデバイスが正しく認識されているか、不明なデバイスになっていないか確認します。
  • Linuxでの権限問題:
    • 非rootユーザーでOpenOCDを実行している場合、USBデバイスへのアクセス権限がない可能性があります。udevルールが正しく設定・適用されているか確認してください (/etc/udev/rules.d/60-openocd.rules のようなファイルが存在し、udevadm control --reload-rulesudevadm trigger を実行したか)。USBデバイスを一度抜き差しすることも有効です。
  • 物理的な接続問題:
    • USBケーブル、デバッグケーブル(JTAG/SWDフラットケーブル)、ターゲットボードとのコネクタ接続が緩んでいないか、正しい向きで挿されているか確認してください。
  • アダプターがサポートされていない/認識設定が間違っている:
    • 使用しているアダプターがOpenOCDでサポートされているか、そして -f interface/...cfg ファイルで正しいアダプタードライバーが指定されているか確認してください。
  • アダプターの故障:
    • まれですが、アダプター自体が故障している可能性もあります。可能であれば別のアダプターで試してください。

2. OpenOCDがターゲットCPUに接続できない (‘Error: JTAG scan chain interrogation failed’, ‘Error: Cortex-M reset request failed’ など)

  • 配線ミス:
    • JTAG/SWDのピン配置(TCK, TMS/SWDIO, TDI, TDO, SWCLK, SWDIO, SRST, TRST, GND, VCC)がターゲットボードとデバッグアダプター間で正しく接続されているか、電圧レベルが合っているか(アダプターがターゲット電圧をサポートしているか)を何度も確認してください。VCC(VTref)信号も正しく接続されている必要があります。
  • ターゲットボードの電源:
    • ターゲットボードに正しく電源が供給されているか確認してください。デバッグプローブから給電できる場合もありますが、基本はターゲット自身に電源が必要です。
  • アダプター速度が速すぎる:
    • 特に配線が長い場合や、ターゲットのクロック周波数が低い場合、アダプター速度が速すぎると通信が不安定になります。OpenOCDログで速度が表示されているか確認し、設定ファイルで adapter speed 1000adapter speed 100 のように遅く設定して試してください。
  • リセット設定が間違っている:
    • reset_config コマンドの設定がターゲットのリセット回路と合っていない可能性があります。特にSRST (System Reset) の制御方法(プルアップ、プルダウン、オープンコレクタなど)を確認し、reset_config のオプションを調整してください。srst_only, srst_pullup, srst_open_drain, connect_assert_srst, connect_deassert_srst などのオプションがあります。
  • ターゲットCPUがデバッグ不能な状態にある:
    • プログラムが暴走している、クロックが停止している、非常に深い低電力モードに入っている、フラッシュプロテクトがかかっている、ブートモード設定が間違っているなど、CPU自体がデバッグインターフェースに応答できない状態になっている可能性があります。場合によっては、ターゲットをリセットしながら接続を試みる、ブートモードピンを設定する、外部要因(発振子など)を確認する、プロテクト解除ツールを使うなどの対処が必要です。
  • ターゲット設定ファイルの間違い:
    • 指定した target/*.cfg ファイルがターゲットCPUのアーキテクチャ、コア数、デバッグレジスタアドレスなどに合っているか確認してください。カスタムボードの場合は、既知の近いチップの設定ファイルを参考に、必要に応じて修正が必要です。
  • マルチコアCPUでコアの選択が間違っている:
    • マルチコアCPUの場合、OpenOCDがどのコアに接続しようとしているか、設定ファイルで正しく指定されているか確認してください(target コマンドのオプションなど)。

3. フラッシュ書き込みが失敗する

  • フラッシュ設定 (flash banks) の間違い:
    • ターゲット設定ファイル (target/*.cfg またはカスタム設定ファイル) で定義されている flash banks のベースアドレス、サイズ、ドライバー名、セクターサイズなどがターゲットのフラッシュメモリの仕様と合っているか確認してください。
  • 書き込み権限/保護:
    • フラッシュメモリの書き込み保護(読み出し保護、書き込み禁止領域など)が有効になっていないか確認してください。プロテクト解除方法はチップによって異なります。
  • 書き込みアドレス範囲の間違い:
    • flash write_image コマンドなどで指定したアドレスやファイルタイプが正しいか確認してください。ELFファイルの場合は通常アドレスは不要ですが、BinaryやHexの場合は正確なアドレスが必要です。
  • ファイル形式の間違い:
    • 指定したファイルタイプ (elf, binary, ihexなど) が実際のファイル形式と合っているか確認してください。
  • ターゲットが停止していない:
    • フラッシュ書き込みを行う際は、通常ターゲットCPUは停止している必要があります。OpenOCDのログでターゲットの状態を確認し、必要であれば halt コマンドで停止させてから書き込みを実行してください。

4. GDBからOpenOCDに接続できない

  • OpenOCDが起動していない:
    • OpenOCDがエラーなく起動し、GDBサーバーポート(デフォルト3333)でリスニングしているか確認してください。OpenOCDが起動しているターミナルを見て、”Listening on port 3333 for gdb connections” のようなメッセージが出ているか確認します。
  • ファイアウォール:
    • PCのファイアウォールがポート3333(TCP)での接続をブロックしていないか確認してください。
  • ポート番号の間違い:
    • GDBの target remote コマンドで指定しているポート番号が、OpenOCDの設定(デフォルト3333)と合っているか確認してください。
  • OpenOCDがハングアップしている:
    • OpenOCDが何らかの原因で応答しなくなっている可能性があります。OpenOCDを一度終了させ(Ctrl+C)、再度起動してみてください。

5. OpenOCDのデバッグログレベルを上げて詳細を確認する

問題の原因特定に役立つのが、OpenOCDの詳細なログ出力です。OpenOCD起動時に -d オプションを付けることで、デバッグログレベルを上げることができます。

bash
openocd -d -f ... # Debugレベル
openocd -d 3 -f ... # より詳細なレベル (0: error, 1: warning, 2: info, 3: debug)

ログレベル3で起動すると、JTAG/SWD通信の詳細、内部処理のステップなどが表示され、問題が発生している箇所を特定しやすくなります。

トラブルシューティングの際は、まずOpenOCDのログメッセージを注意深く読むことが最も重要です。エラーメッセージや警告メッセージに、問題解決の手ヒントが含まれている場合がほとんどです。また、OpenOCDのユーザーマニュアルやFAQ、コミュニティフォーラムも役立ちます。

11. 開発環境との統合 (IDE連携)

OpenOCDはGDBサーバーとして機能するため、多くの主要な統合開発環境(IDE)からデバッグプローブとして利用できます。IDEと連携することで、ソースコードにブレークポイントを設定したり、変数の値をGUIで確認したりと、視覚的で効率的なデバッグが可能になります。

主なIDEでのOpenOCD連携設定について、一般的な項目を説明します。具体的な設定方法はIDEのバージョンや種類によって異なるため、各IDEのマニュアルを参照してください。

一般的なIDEでの設定項目

IDEでOpenOCDをデバッグプローブとして設定する際、通常以下のような項目を設定します。

  • Debugger / Debug Probe Type: 使用するデバッガーの種類を選択します。ここで「GDB Server」や「OpenOCD」を選択します。
  • GDB Executable: 使用するクロス開発用GDB(例: arm-none-eabi-gdb)の実行ファイルパスを指定します。
  • GDB Server Settings:
    • GDB Server Executable: OpenOCDの実行ファイルパス(例: openocd.exeopenocd)を指定します。
    • GDB Server Arguments / Configuration Options: OpenOCDを起動する際のコマンドライン引数を指定します。ここに -f [設定ファイル1] -f [設定ファイル2] ... のように、使用するOpenOCD設定ファイルへのパスを指定します。
    • GDB Server Port: OpenOCDのGDBサーバーが使用するポート番号(デフォルト3333)を指定します。IDEのデバッガはこのポートに接続しに行きます。
    • Telnet/Tcl Port: OpenOCDのTcl/Telnetポート番号(デフォルト6666または4444)を指定します。IDEによっては、このポートを使ってOpenOCDにコマンドを送る機能を提供している場合があります。
  • Target Connection / Board Settings:
    • 多くの場合、OpenOCDの設定ファイルでアダプターとターゲットは指定されるため、IDE側で別途詳細な接続設定は不要なことが多いです。しかし、IDEによってはアダプターの種類やシリアル番号などをIDEの設定画面で直接指定し、IDEがOpenOCDの起動引数を自動生成する場合もあります。
  • Startup Commands / Initialization Script:
    • デバッグセッション開始時にGDBやOpenOCDに対して実行させたいコマンドを指定します。これには、target remote, load, break main, monitor reset halt といったコマンドが含まれます。IDEによってはGUIでこれらのステップを設定できます。.gdbinit ファイルを使用する設定項目がある場合もあります。
  • Program / Project File:
    • デバッグ対象の実行ファイル(ELFファイルなど)を指定します。IDEがこのファイルを使用してGDBを起動したり、OpenOCD経由でターゲットにロードしたりします。

主要なIDEでの連携例

  • Visual Studio Code (VS Code):
    • C/C++拡張機能やPlatformIO拡張機能などを使用します。デバッグ設定は .vscode/launch.json ファイルにJSON形式で記述します。typecppdbgplatformio-debug とし、requestlaunch に設定します。miDebuggerPath でGDB、miDebuggerArgs でGDB引数、customLaunchSetupCommands でGDB起動後の初期コマンド(target remote ... など)を指定します。debugServerPath でOpenOCD、debugServerArgs でOpenOCD引数 (-f ... など) を指定します。
  • Eclipse (CDT):
    • C/C++ Development Toolkit (CDT) をインストールし、Debug Configurationsを開きます。GDB Hardware Debugging構成を作成し、Debuggerタブで「Using GDB (DSF) Manual Remote Debugging Launcher」や「GDB OpenOCD Debugging」などを選択します。MainタブでC/C++ Applicationを指定し、DebuggerタブでGDBコマンドとGDB Server Settings(OpenOCDパス、ポート、設定ファイル引数)を設定します。Startupタブで初期化コマンドを設定します。
  • STM32CubeIDE:
    • STMicroelectronicsが提供するEclipseベースのIDEです。プロジェクト作成時にデバッガーとしてST-LinkやOpenOCDを選択するオプションがあります。OpenOCDを選択した場合、使用するOpenOCD設定ファイルをIDEのGUIで指定できます。内部的にOpenOCDを起動し、GDB連携を行います。
  • SEGGER Embedded Studio:
    • SEGGER Embedded StudioもOpenOCDをデバッガーとして設定可能です。Project Options -> Debugger -> ConnectionTypeで「Remote GDB server」を選択し、GDB Server Settingsで「Server Executable」にOpenOCDパス、「Arguments」にOpenOCD引数を指定します。

IDE連携を設定することで、ソースコードエディタ上でブレークポイントをクリックして設定したり、デバッグビューで変数の値やレジスタの状態をリアルタイムに確認したり、コールスタックを視覚的に追跡したりと、OpenOCD単体やコマンドラインGDBよりも遥かに快適なデバッグ作業が可能になります。

12. まとめと今後の展望

OpenOCDは、組み込み開発におけるデバッグ環境を構築するための非常に強力で柔軟、そしてコスト効率の高いツールです。オープンソースでありながら、多様なハードウェアアダプターとCPUアーキテクチャをサポートし、標準的なGDBインターフェースを提供することで、特定のベンダーやツールに依存しない開発ワークフローを実現できます。

この記事では、OpenOCDの基本的な概念、必要なハードウェア、インストール方法、設定ファイルの記述、GDB連携、フラッシュプログラミング、そして高度な機能とトラブルシューティングについて詳細に解説しました。これらの知識を活用することで、開発者はOpenOCDを効果的にデバッグ作業に組み込むことができるようになります。

OpenOCD活用のメリット再確認:

  • コスト: 安価なアダプターや既存の開発ボード内蔵デバッガーを活用可能。
  • 柔軟性: 多数のCPUとアダプターに対応、ハードウェア変更への適応が容易。
  • 標準性: GDBインターフェースにより、様々なIDEやツールと連携可能。
  • 自動化: Tclスクリプトによる複雑な処理やテスト自動化の実現。
  • 透明性: オープンソースによる内部理解の容易さとコミュニティサポート。

今後の展望と応用:

OpenOCDの可能性は、ここで紹介した基本的な使い方に留まりません。

  • マルチコアデバッグ: 複数のCPUコアを持つシステムにおいて、各コアのデバッグをOpenOCD経由で行う設定。
  • 外部メモリデバッグ: SDRAMなどの外部メモリにロードされたプログラムのデバッグや、そのメモリ内容の確認。
  • RTOS認識: より高度なRTOS認識機能(カスタムRTOSへの対応など)の設定と活用。
  • カスタムハードウェアサポート: 特殊なデバッグインターフェースを持つハードウェアや、新しいCPUアーキテクチャに対するOpenOCDドライバーの開発や貢献。
  • 自動テストシステムへの組み込み: CI/CDパイプラインにおいて、ビルド後のフラッシュ書き込みや起動テスト、自己診断プログラムの実行などをOpenOCDとスクリプトで自動化。

OpenOCDを使いこなすことは、単にデバッグツールを習得するだけでなく、組み込みシステムのデバッグインターフェースやハードウェアの動作に関する深い理解を促進します。発生した問題に対して、表層的なエラーメッセージだけでなく、ハードウェアレベルでの原因究明が可能になります。

OpenOCDは活発なオープンソースプロジェクトであり、常に進化しています。最新の情報や機能については、OpenOCD公式サイトのドキュメントやメーリングリスト、Wikiなどを参照することをお勧めします。

効率的なデバッグ環境は、組み込み開発の生産性と品質に直結します。ぜひOpenOCDを使いこなし、快適な開発ワークフローを構築してください。

13. 参考資料

  • OpenOCD 公式サイト: http://openocd.org/
    • ユーザーマニュアル、インストール手順、サポートハードウェアリストなどが掲載されています。
  • OpenOCD Wiki: http://openocd.org/doc/html/
    • ドキュメントのHTML版。検索可能で便利です。特にTclコマンドリファレンスは役立ちます。
  • Zadig (Windows USBドライバーツール): https://zadig.akeo.ie/
  • GNU Debugger (GDB) 公式サイト: https://www.gnu.org/software/gdb/
  • 各種デバッグアダプターやターゲットボードのドキュメント: 使用するハードウェアのマニュアルで、デバッグコネクタのピン配置や仕様を確認してください。

コメントする

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

上部へスクロール