ArduinoUnoR4MinimaをDAPLinkでデバッグする

# はじめに
Arduino Uno R4 Minimaが発売開始になって(記事執筆の2025年6月時点で)早2年です。
従来のUno R3でもICSP端子でデバッグはできましたが、Uno R4 MinimaからはSWD端子でデバッグを行うことになります。(Uno R4 WiFiはWI-Fi接続用のesp32s3をオンボードデバッガとして利用できるので、SWD端子はありません)

UnoR4を使って開発を楽しむ中で、@74th さんの[CH32V203 で Arduino UNO R4 の SWD 仕様の DAPLink を作る](https://74th.hateblo.jp/entry/2023/07/09/092748)という記事とXのポストを見つけたので、このDAPLinkデバッガを使ってUnoR4 Minimaをデバッグする方法を調べました。

https://x.com/74th/status/1677656741897715713

# デバッグ環境

- Windows11 Home
- [VSCode](https://code.visualstudio.com/) 1.100.2
- [PlatformIO](https://platformio.org/) v3.3.4 
- [platformio/renesas-ra](https://registry.platformio.org/platforms/platformio/renesas-ra) 1.7.0
- [Arduino Uno R4 Minima](https://www.renesas.com/ja/products/microcontrollers-microprocessors/ra-cortex-m-mcus/ra-partners/arduino-uno-r4)
- [platformio/tool-openocd](https://registry.platformio.org/tools/platformio/tool-openocd) 3.1200.0 (12.0)

# ファイル構成
以下のようにファイルを構成します。（今回の記事に関係のないファイルは省略しています）


```
Project
│  dap_link.cfg
│  platformio.ini
│  renesas_ra4m1.cfg
│
├─.pio
│
├─.vscode
│
├─include
│
├─lib
│
└─src
       main.cpp

```

ここで重要なのは`platformio.ini` と `renesas_ra4m1.cfg` と `dap_link.cfg` の3つです。

# ファイルの詳細

## platformio.ini
まずは`platformio.ini`の中身を確認しましょう。

```platformio.ini
; 通常アップロード環境（DFU使用）
[env:uno_r4_upload]
platform = renesas-ra
board = uno_r4_minima
framework = arduino
upload_protocol = dfu
build_type = debug
build_flags = 
    -DDEBUG=1
    -g3
    -O0
monitor_speed = 115200

; デバッグ用環境
[env:uno_r4_debug_config_cfg]
platform = renesas-ra
board = uno_r4_minima
framework = arduino
; デバッグ設定
debug_tool = cmsis-dap
; カスタム設定ファイルを使用
debug_server = 
    $PLATFORMIO_CORE_DIR/packages/tool-openocd/bin/openocd
    -f dap_link.cfg
    -f renesas_ra4m1.cfg
    -c init
; アップロード設定
upload_protocol = dfu  ; custom の場合はアップロードしない
; ビルド設定
build_type = debug
build_flags = 
    -DDEBUG=1
    -g3
    -O0
; モニター設定
monitor_speed = 115200
; デバッグ追加オプション
debug_init_break = tbreak loop
debug_load_mode = modified
```

`[env:uno_r4_upload]`はデバッグをせずUno R4に書き込むだけの設定です。
主役はデバッグを行う`[env:uno_r4_debug_config_cfg]`です。
デバッグに関係する部分のみ解説します。
詳細は https://docs.platformio.org/en/latest/plus/debugging.html も参照ください

**デバッグ関連**
- `debug_tool = cmsis-dap`: デバッグプローブの種類
  cmsis-dapは汎用CMSIS-DAP互換デバッガ用  
  他の選択肢例:    
  - ST-Link互換の場合: `stlink`
  - Segger J-Linkの場合: `jlink`

- `debug_server =`: OpenOCD（On-Chip Debugger）を起動する際のコマンド・引数リスト。
  - `$PLATFORMIO_CORE_DIR/packages/tool-openocd/bin/openocd`: openocdのインストール先
  - `-f dap_link.cfg`インターフェース用設定ファイル
  ここはプローブの種類やベンダによって内容が変わる。
  `dap_link.cfg` の内容については後ほど説明する。  
    他の選択肢例:
    - ST-Linkの場合: `-f interface/stlink.cfg`
    - J-Linkの場合: `-f interface/jlink.cfg`
  - `-f renesas_ra4m1.cfg`: 対象マイコン（RA4M1）の設定ファイル。
    他のマイコンの場合は適切なcfgファイルに置き換え。
  - `-c init`: OpenOCDの初期化コマンド。

**書き込み関連**
- `upload_protocol = dfu`: プログラム書き込み方法を指定
  dfuはUno R4をUSB経由で書き込む
  他の選択肢例:
  - `custom`: 書き込まない
  - `cmsis-dap`: プローブ経由で書き込む場合
  ※ UnoR4の場合、デバッグプローブ経由では書き込めないので注意
  - `mbed`: mbed互換ボードの場合

**ビルドオプション**

- `build_type = debug`: デバッグビルドを指定（最適化なし、デバッグシンボル付き）。
- `build_flags =`: ビルド時のフラグを設定する
  - `-DDEBUG=1`: DEBUGマクロを有効化
  - `-g3`: 最大限のデバッグ情報を付加
  - `-O0`: 最適化を無効化（デバッグしやすくなる）
  - `;-fno-omit-frame-pointer`: （コメントアウト）フレームポインタを省略しない。
  スタックトレースやバックトレースの精度が向上するが、有効化しているとデバッグに失敗したのでコメントアウトして無効化している。
    他の選択肢例:
    - `-O2`: リリースビルド（最適化有効）
    - `-g1` シンボル最小化

**デバッグ追加オプション**

- `debug_init_break = tbreak loop`: デバッグ開始時に loop 関数先頭で一時停止する設定。
tbreak main や break 任意の関数名 にも変更可能。
- `debug_load_mode = modified`: プログラム書き込みタイミングを制御。
`modified` はバイナリ更新時のみ書き込み
  他の選択肢例:
  - `always`: 毎回書き込み。
  - `manual`: 手動で書き込み指示時のみ


**補足**
debug_server で指定するcfgファイルは、この場合はplatformio.iniと同じディレクトリに配置する想定です。
openocd/scriptsパス以降に配置する場合は
`-f /interface/dap_link.cfg`
`-f /target/renesas_ra4m1.cfg`
のようになります。

## dap_link.cfg

dap_link.cfg は、OpenOCDでCMSIS-DAP対応のデバッグプローブ（例：DAPLink, XV-Linkなど）を使う際のインターフェース設定ファイルです。
OpenOCDには標準で含まれていないので、今回新規に作成しています。

```dap_link.cfg
adapter driver cmsis-dap
cmsis_dap_vid_pid 0x0416 0x5051
transport select swd
adapter speed 1000
```

- `interface cmsis-dap`: CMSIS-DAP（ARM標準のデバッグプローブ）を使うことを指定。
  他の選択肢
  - `interface stlink`: ST-Link用
  - `interface jlink`: J-Link用
  - `interface ft2232`: FTDI FT2232ベースのUSB JTAGなど  

- `cmsis_dap_vid_pid 0x0D28 0x0204`: デバッグプローブのUSBベンダID/プロダクトIDを指定。
ここでは、DAPLinkでのIDを指定している。
プローブによってIDが異なるので、ファイルを個別に作成すること

- `transport select swd`: SWD（Serial Wire Debug：2本線のデバッグ通信）を指定。
  Renesas RA4M1や最近のARM Cortex-Mマイコンは通常SWDを使用。
  省略するとデフォルト値になるが、明示的に記載するのが推奨。  
  他の選択肢
  - `transport select jtag`: JTAG通信の場合。古いマイコンや特定用途

- `adapter speed 1000`: デバッグ通信速度（kHz単位）。
  ここでは1MHz（1000kHz）を設定。
  ボードや回路状況により2000, 4000（2MHz, 4MHz）などに上げられる。
  通信が不安定な場合は数値を下げる（例: 500）とよい。

**dap_link.cfg でよく使われる他のオプション**
- `cmsis_dap_serial <シリアル番号>`: プローブが複数接続されている場合の選択肢。
  特定のデバイスだけをシリアル番号で指定可能。
- `reset_config srst_only srst_nogate`: リセット方法の変更。ハードリセット回路付きの場合に指定。
- `log_output openocd.log`: OpenOCDのログをファイル出力する

## renesas_ra4m1.cfg

OpenOCDでRenesas RA4M1シリーズ（例: Arduino Uno R4 Minima等）をデバッグするためのターゲット設定ファイル
これもOpenOCDには標準で含まれていないので、今回新規に作成しています。

```renesas_ra4m1.cfg
# Renesas RA4M1 (Arduino Uno R4 Minima) target configuration
# Based on working debug_server configuration

# Transport selection
transport select swd

# Adapter speed
adapter speed 1000

# CMSIS-DAP VID/PID for Arduino Uno R4 Minima debugger
# This should be set in the interface file, but we include it here for completeness
# cmsis_dap_vid_pid 0x0416 0x5051

# Target configuration
if { [info exists CHIPNAME] } {
    set _CHIPNAME $CHIPNAME
} else {
    set _CHIPNAME ra4m1
}

if { [info exists ENDIAN] } {
    set _ENDIAN $ENDIAN
} else {
    set _ENDIAN little
}

# Work-area is a space in RAM used for flash programming
if { [info exists WORKAREASIZE] } {
    set _WORKAREASIZE $WORKAREASIZE
} else {
    # 32KB of internal SRAM
    set _WORKAREASIZE 0x8000
}

# Expected DAP ID for RA4M1
if { [info exists DAP_TAPID] } {
    set _DAP_TAPID $DAP_TAPID
} else {
    set _DAP_TAPID 0x5ba02477
}

# SWD/JTAG interface setup
source [find target/swj-dp.tcl]
swj_newdap $_CHIPNAME cpu -expected-id $_DAP_TAPID

# Create DAP
dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu

# Create target
set _TARGETNAME $_CHIPNAME.cpu
target create $_TARGETNAME cortex_m -endian $_ENDIAN -dap $_CHIPNAME.dap

# Configure work area
$_TARGETNAME configure -work-area-phys 0x20000000 -work-area-size $_WORKAREASIZE -work-area-backup 0

# Flash configuration (optional - add if needed for programming)
# set _FLASHNAME $_CHIPNAME.flash
# flash bank $_FLASHNAME renesas_rpb 0x00000000 0 0 0 $_TARGETNAME

# Reset configuration
$_TARGETNAME configure -event reset-init {
    # Configure system clock if needed
    # This may need adjustment based on your specific requirements
}

# Debugging helpers
$_TARGETNAME configure -event gdb-attach {
    echo "Debugger attached to RA4M1"
    halt
}

$_TARGETNAME configure -event gdb-detach {
    echo "Debugger detached from RA4M1"
}
```

- `CHIPNAME, DAP_TAPID`: マイコン名と、DAP（デバッグアクセスポート）のJTAG/SWD識別子を設定。
※ 他のRAファミリやCortex-Mデバイスの場合は、名前とID値が異るので、MCUに合わせて設定する
RA4M1のDAP_TAPIDは`0x5ba02477`だが、他チップではそれぞれの固有値にすること

- `source [find target/swj-dp.tcl]`: ARM SWJ-DP（Serial Wire/JTAG Debug Port）のOpenOCDスクリプトを読み込み。
基本はこのままだが、非ARMコアの場合は不要。

- `swj_newdap, dap create, target create`: SWJ（デバッグアクセスポート）とDAP、Cortex-MターゲットコアのOpenOCD内オブジェクトを作成。
他MCU（RA2, RA6など）では名前や構成が異なることがある。
デバッグ対象が複数コアの場合はtarget createが複数行になる。

- `configure -work-area-phys ...`: OpenOCDがフラッシュ書き込みやメモリ操作に使う作業用RAM領域を指定。
0x20000000はRA4M1のRAM先頭アドレス、0x8000は32KBの作業領域。
RAM容量が異なる場合や競合回避が必要な場合はアドレスやサイズを調整。
-work-area-backup 0 でバックアップをしないなども可。


# デバッグ結果

Uno R4とDAPLinkの接続は写真のように行います。
Uno R4の方にUSB-Cケーブルが接続されていますが、これはプログラムを書き込むためなのでデバッグには不要です。
![PXL_20250603_143916383.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/360166/cb1469f3-f0f3-4ce8-9db7-27924c598331.jpeg)

VSCodeのデバッグ画面はこのようになります。
ブレークポイントを設定し一時停止すると、変数やレジスタなどが参照できます。
（通常通り連続で動作しているときは変数などは参照できないので、停止しては困る環境でのデバッグには注意してください。）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/360166/0ee648b3-844d-485e-8eb1-b35b109d54e6.png)