QMKをICEでデバッグ

# ICE？

この記事でいうICEとは、ブレークポイントやウォッチやステップ実行のこと。

## ST-LINK？

STMicroelectronicsのICEプローブ。PC→（USB接続）→ST-LINK→（SWD接続）→STM32とつながる。

# 環境

- STM32F072の評価ボード [STM32F072B-DISCO](https://www.st.com/en/evaluation-tools/32f072bdiscovery.html)
    - ボード上にST-LINKが載っている。
    - STM32F072側のFlashに書き込まれているファームウェアは出荷時のデモを想定。もし違っていても、SWDがつながる状態ならOK。SWD接続に必要なA13 / A14ピンを使ってしまうファームもたまによくある。
    - ST-LINK側のファームウェアはアップデートしておく。[アップデータ](https://www.st.com/en/development-tools/stsw-link007.html)
- Windows 11のUbuntu on WSL2
- Ubuntu on WSL2から`code .`で開いたリモートモードのVSCode
    - [QMKのインクルードパスやマクロを調べてVSCodeに設定](https://qiita.com/hajimen/items/8eb57d6f2b1ae1ff6495) で設定済み
- `.wslconfig`に`networkingMode=mirrored`を設定（このためにWindows 11が必要）

# 接続

評価ボードのST-LINK側のUSB mini-BをPCにつなぐ。ドライバはSTMicroelectronicsから。

評価ボードのジャンパはldd（左側中段）とST-LINK / DISCOVERY（右上）両方とも装着。

# インストール（Windows側）

- OpenOCD （ICE用のgdbserver。いろんなICEプローブとマイコンに対応）
    1. [バイナリ](https://gnutoolchains.com/arm-eabi/openocd/)を取ってくる
    2. `openocd -f interface/stlink.cfg -f target/stm32f0x.cfg -c "bindto 0.0.0.0"`を実行
    3. openocdがTCPポートをLISTENしはじめたら、ファイアウォールを開ける。gdbを待機しはじめたらOK。
    4. openocdがgdbを待機せず、すぐ終了してしまう？　その場合、STM32F072側のファームウェアをDFUで（つまりSTM32F072側のUSB mini-B経由で）書き込んで出荷時に戻す。

# インストール（Ubuntu on WSL2側）

- gdb-multiarch （ARMをターゲットにできるgdb）
    - `sudo apt install gdb-multiarch`

- VSCodeのエクステンション [Native Debug](https://marketplace.visualstudio.com/items?itemName=webfreak.debug)

# ビルド

`~/qmk_firmware`ディレクトリ上で、

```
make *keyboard*:*layout* OPT=g
```

これで`.build`ディレクトリにデバッグ用の`*keyboard*_*layout*.elf`ファイルができる。`tasks.json`に設定しておくといい。

## A13 / A14ピンの罠

今回`*keyboard*`としてretro_75を使ったところ、SWD接続に必要なA14ピンを使ってしまっている。retro_75の`config.h`の45行目を以下のように書き換えて、A14の代わりにC0ピンを使った。

```C:keyboards/retro_75/config.h
#define MATRIX_COL_PINS { A5, A4, A3, F0, C15, C14, C13, A6, B11, B10, B2, B1, B0, A7, C0, A15 }
```

# `launch.json`の設定

VSCodeの`launch.json`は以下のとおり。

```json:.vscode/launch.json
{
    // Use IntelliSense to learn about possible attributes.
    // Hover to view descriptions of existing attributes.
    // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
    "version": "0.2.0",
    "configurations": [
        {
            "name": "(gdb) Attach to OpenOCD",
            "type": "gdb",
            "request": "attach",
            "executable": "${workspaceFolder}/.build/*keyboard*_*layout*.elf",
            "target": "localhost:3333",
            "remote": true,
            "cwd": "${workspaceFolder}",
            "gdbpath": "gdb-multiarch",
            "autorun": [
                "load"
            ]
        }
    ]
}
```

WSL2に`networkingMode=mirrored`がついたので、普通にlocalhostでGDB serverにつながる。これがない時代は、Windows側のIPアドレスが毎回変わって死ぬほどだるかった。

# ブレークポイントを設定

マトリックスをスキャンするたびに実行される場所にブレークポイントを設定する。`quantum/matrix.c`の`read_cols_on_row()`あたりが手頃。
![breakpoint.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/325885/55029f73-c91a-337f-dec2-4890472998fb.png)

# 実行

`(gdb) Attach to OpenOCD`をデバッグ開始。

![bp2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/325885/8500fe57-d1f5-fdfd-e20e-f53b71cecda8.png)

ブレークポイントで止まったよ！

![bp3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/325885/d2baea72-9140-c5fd-5d3c-3d1cfb197883.png)

コールスタックも見えるよ！