SWD (Serial Wire Debug) やっててさらにトレース(printfみたいなこと)も行いたいことは多い。別途 USART を繋げて printf() デバッグしても良いが、正直めんどうくさい。
ITM とは?
Instrument Trace Macrocell の略で Cortex-M の Arm CoreSight (MCU 側のデバッグ機能) に含まれるトレース機能。トレース機能は雑にいうと printf() みたいなもので、実際 printf() を中継するのに使うこともできる。
SWO (Serial Wire Output) というトレース用のピンを使う。
semihosting との違い
セミホスティングとはが詳しいが、セミホスティングはホスト側でシステムコールの一部をホストするという仕組みで、bkpt (ブレークポイント) などで発生する例外を ARM プロセッサのデバッガインターフェイスが拾ってホスト側に中継する。
仕組み的にビルド・トレース環境とかを作るのがめんどい。
ITM の Pros. Cons.
- ↑ 特殊なビルドが不要
- ↓ 余計な配線が1つ必要 (SWO)
semihosting の Pros. Cons.
- ↑ できることが多い
- ↓ ビルドが複雑
中華 ST-Link V2 の改造
よく売ってる安い ST-Link V2 には SWO 用のピンが出ていない。機能自体はあるので配線してやる。5V と 3.3V はピンが2本ずつ重複しているので、片方を潰せば特にデメリットなく拡張できる。
↑ こういう感じでケース(カバー?)は外せる。USB コネクタ側にスライドする
↑ 31ピンが SWO 用のピン。一応親切?なのか若干配線が伸びてるので、カッターでレジストを剥してはんだづけするのが楽
↑ 今回は 5V のピンを1つ配線をカットして使うことにした。22Ωを介して外に出す。UEW 線でやってる。ちゃんとテスターで導通チェックしましょう
配線
MCU 側は SYS_JTDO_SWO の機能があるピンを設定する。STM32F401 の場合は PB3。Alternate function を設定しなければデフォルトで SWO のはず?モノによるかも
コード側
ここでは printf() を中継する前提で _write() を適当な位置に定義する
int _write(int file, char *ptr, int len) {
for(int i = 0; i < len; i++) {
ITM_SendChar(*ptr++);
}
return len;
}
あとは printf() を使うところで以下のように stdio.h を include すれば良い
#include <stdio.h>
VSCode + Cortex-Debug の設定
Cortex-Debug は ITM のデコードをサポートしていて以下のような設定をできる。
launch.json
{ "version": "0.2.0", "configurations": [ { "name": "OpenOCD-Debug", "type": "cortex-debug", "request": "launch", "servertype": "openocd", "executable": "build/stm32f401-usbserial-host.elf", "configFiles": [ "interface/stlink.cfg", "target/stm32f4x.cfg" ], "postLaunchCommands": [ "monitor reset init", "monitor itm port 0 on" ], "cwd": "${workspaceRoot}", "svdFile": "STM32F4x1.svd", "device": "stm32f4x", "preLaunchTask": "build", "swoConfig": { "cpuFrequency": 64000000, "source": "probe", "swoFrequency": 1000000, "enabled": true, "decoders": [ { "port": 0, "label": "ITM", "type": "console" } ] } } ] }
これで、VSCode の「出力」タブのドロップダウン「SWO: ITM [port: 0, type: console]」に ITM 経由のログが出るようになる。type: console の場合 "\n" 区切りであることを前提にタイムスタンプを追加してくれる。
postLaunchCommands
の monitor reset init
はないほうがいいかも。cpuFrequency
は HCLK にあわせるのが良い。