Arduino UNO R4ユーザーに朗報、ソースコードデバッグが可能に!
この度、次の2つの記事で紹介してきた R7FA4M1AB.svd
の修正版 が、Arduino 公式 GitHub に 取り込まれることになりました。
おそらく UNO R4 用ボードマネージャーの更新(本記事執筆時点のバージョンは 1.1.0)という形で配信されると思います。
2024年6月3日にバージョン 1.2.0 がリリースされ、貢献者にハンドル名が載りました。嬉しい限りです!
この修正により、UNO R4 Minima は CMSIS-DAP をサポートした JTAG/SWD デバッグプローブ)で、UNO R4 WiFi は ESP32 を介したオンボードデバッガで、それぞれソースコードデバッグが可能になります。
「SVDファイルとは何者?」から、CMSIS-DAP や CMSIS-SVD、JTAG/SWD デバッグプローブについての図を再掲します。
本来は Renesas RA4M1グループ ユーザーズマニュアル ハードウェア編 の仕様と対比して修正内容を提示したいところですが、Renesas の文書による許諾が必要なため、CC BY-SA の元に公開されている Arduino UNO R4 Minima のピン配図 と MIT ライセンスの元に公開されている R7FA4M1AB.svd
を用いて説明を試みます。
とても退屈な話になりますが…、苦労話を書きたくなる気持ちを察してやって下さい
R7FA4M1AB.svd とは
SVD は System View Description の略で、Arm Cortex-M の持つ機能を XML で記述したものになります。また R7FA4M1AB
は UNO R4 に搭載された Renesas MCU の型番の一部です。
例えば、僕らがプロセッサやその周辺回路の使い方をマニュアルで調べるのと同様、Arduino IDE のデバッガは、どのレジスタが何処のアドレスにマッピングされているかを知るために SVD ファイルを参照します。
つまり Arduino IDE にとって R7FA4M1AB.svd
は、人間にとっての ユーザーズマニュアル に相当し、そのフォーマットは CMSIS-SVD スキーマ として定められています。
人用のマニュアルが 1700 ページほどあるのに対し、R7FA4M1AB.svd
は6万数千行もあります。その中身は共通部分も多く、親とその派生で定義が可能な感じですが、仮に手作業でこれを作成するとしたら、間違えも起きるよネというのが正直な感想です。
ちなみに R7FA4M1AB.svd
の原版は、Arm のサイトに公開されています。
問題点の分析と修正方針
UNO R4 用オンボードマネージャのバージョン 1.1.0 では、 でデバッガを起動すると、以下のエラーが起きます。
Unable to parse SVD file /Users/xxxx/Library/Arduino15/packages/arduino/hardware/renesas_uno/1.1.0/svd/R7FA4M1AB.svd: Error: SVD error: Invalid 'derivedFrom' "P100PFS" for register "P30%sPFS"
この問題は、Arduino 公式 GitHub にも「“Unable to parse SVD file” error when starting debugger #276」として挙がっていますが、「無効な P100PFS
から P30xPFS
を派生させている」ことを訴えています。
P100PFS
の PFS
は Port Function Select の略で、汎用 I/O 端子 P000
〜 P915
の入出力方向の切り替え、プルアップ抵抗や割り込み有無の設定など、汎用 I/O 端子の機能を選択するレジスタ群になります。
ちなみにこのエラーによりプログラムが暴走したりすることはなく、単に IDE の UI を通してレジスタの内容を表示したり書き換えたりする機能に影響があるだけです。
さて、エラーを手掛かりに R7FA4M1AB.svd
を精査すると、次の2つの問題があることが判明しました。
-
CMSIS-SVD スキーマ 上
P100PFS
の定義は正しいが、派生元の親として定義されてない - ユーザーズマニュアル 上、幾つかの I/O 端子は派生元の親を間違えて定義されている
従って修正方針はこれらの裏返しです。
- 派生元の親となり得るよう
P100PFS
を再定義する - 派生元の親を間違えている I/O 端子を抽出し、正しい親を定義し直す
何せ行数が多いため、汎用 I/O 端子ごとにチェックリストを作成しながら進めました。
SVD ファイルの修正内容
ここからは以下の章立てにより、修正内容の説明を試みます。
-
PFS レジスタの概要
Arduino IDE のデバッガを通して、PFS
レジスタの全体像を把握します。 -
P100PFS の再定義
ユーザーズマニュアル の定義に基づき、P100PFS
を再定義した内容を提示します。 -
派生に関する修正
派生元となる親を間違えているレジスタの修正内容を提示します。
PFS レジスタの概要
Arduino IDE でデバッガを起動すると、MCU に内蔵された周辺装置のレジスタを「CORTEX PERIPHERALS」から、参照または編集ができるようになります。
詳細は ユーザーズマニュアル を参照してもらうとして、IDE で表示された P100PFS
の内容と SVD ファイルの定義を一覧にすると、次のようになります。
ビットフィールド | ビットレンジ | 名称 |
---|---|---|
PODR |
[0:0] | Port Output Data |
PIDR |
[1:1] | Port Input Data |
PDR |
[2:2] | Port Direction |
Reserved | [3:3] | 予約ビット |
PCR |
[4:4] | Pull-up Control |
Reserved | [5:5] | 予約ビット |
NCODR |
[6:6] | N-Channel Open Drain Control |
Reserved | [9:7] | 予約ビット |
DSCR |
[10:10] | Port Drive Capability |
Reserved | [11:11] | 予約ビット |
EOR |
[12:12] | Event on Rising |
EOF |
[13:13] | Event on Falling |
ISEL |
[14:14] | IRQ input enable |
ASEL |
[15:15] | Analog Input enable |
PMR |
[16:16] | Port Mode Control |
Reserved | [23:17] | 予約ビット |
PSEL |
[28:24] | Port Function Select |
Reserved | [31:29] | 予約ビット |
ここでのポイントは、汎用 I/O 端子は P000
から P915
まで多数あり、USB や シリアル通信など、特定用途で使われる端子の仕様が、他の I/O 端子と微妙に異なるという点です。
言い換えれば、これらの仕様違いを正しく XML で記述する必要があるという事です。
ユーザーズマニュアル の P.430 には、但し書きで仕様違いをを規定していますが、この規定と SVD ファイルとの相違が Arduino IDE でのエラー につながっていました。
中でも「P408 は DSCR1 ビットだけを持ちます」という記述は誤訳なので要注意です。原文は「P408 only has DSCR1 bit」であり、「P408 だけが DSCR1 ビットを持ちます」と訳すのが正解です(Renesas に確認済み)。
P100PFS の再定義
修正前は、P000PFS
を派生の親とする子の位置付けで定義されていましたが、他の親となり得るよう、次のように再定義しました(→ 差分を確認)
ユーザーズマニュアル のメモリマップによると、汎用 I/O 関連のレジスタは 0x40000000
〜 0x40100000
番地にマッピングされています。
このうち PFS (Pin Function Select) は、下記 XML の通り 0x40040800
から始まると定義されていて、P100PFS
はこのセクションに属しています。
即ち P100PFS
は、baseAddress
の 0x4004 0800
に addressOffset
の 0x040
を加えた 0x4004 0840
番地にマッピングされています。
また resetValue
は各レジスタで異なる値を取り、特にリセット後の値が不定なビットがあるため resetMask
でマスクする定義となっています。
以下、予約ビットを除き、P100PFS
の修正済み定義を示します。
PODR
ビットフィールド | ビットレンジ | 名称 | 機能 | R/W |
---|---|---|---|---|
PODR |
[0:0] | Port Output Data | 0: Low output 1: High output |
R/W |
PIDR
ビットフィールド | ビットレンジ | 名称 | 機能 | R/W |
---|---|---|---|---|
PIDR |
[1:1] | Port Input Data | 0: Low input 1: High input |
R |
PDR
ビットフィールド | ビットレンジ | 名称 | 機能 | R/W |
---|---|---|---|---|
PDR |
[2:2] | Port Direction | 0: Input (Functions as an input pin) 1: Output (Functions as an output pin) |
R/W |
PCR
ビットフィールド | ビットレンジ | 名称 | 機能 | R/W |
---|---|---|---|---|
PCR |
[4:4] | Pull-up Control | 0: Disables an input pull-up 1: Enables an input pull-up |
R/W |
NCODR
ビットフィールド | ビットレンジ | 名称 | 機能 | R/W |
---|---|---|---|---|
NCODR |
[6:6] | N-Channel Open Drain Control | 0: CMOS output 1: NMOS open-drain output |
R/W |
DSCR
ビットフィールド | ビットレンジ | 名称 | 機能 | R/W |
---|---|---|---|---|
DSCR |
[10:10] | Port Drive Capability | 0: Low drive 1: Middle drive |
R/W |
先に示した通り、「P408 だけが DSCR1 ビットを持ちます」。それ以外の端子で DSCR1
(ビットレンジ [11:11])は、予約ビットとなります。
EOR
ビットフィールド | ビットレンジ | 名称 | 機能 | R/W |
---|---|---|---|---|
EOR |
[12:12] | Event on Rising | 0: Do not care 1: Detect rising edge |
R/W |
EOF
ビットフィールド | ビットレンジ | 名称 | 機能 | R/W |
---|---|---|---|---|
EOF |
[13:13] | Event on Falling | 0: Do not care 1: Detect falling edge |
R/W |
EOR
、EOF
は、P100PFS
〜 P415PFS
にだけ定義されています。修正前の P100PFS
は、P000PFS
を継承し予約ビットとなっていたため、あらためて P100PFS
を派生元の親として再定義し、P200PFS
〜 P415PFS
がこれを継承するように修正しました。
ISEL
ビットフィールド | ビットレンジ | 名称 | 機能 | R/W |
---|---|---|---|---|
ISEL |
[14:14] | IRQ input enable | 0: Not used as IRQn input pin 1: Used as IRQn input pin |
R/W |
ASEL
ビットフィールド | ビットレンジ | 名称 | 機能 | R/W |
---|---|---|---|---|
ASEL |
[15:15] | Analog Input enable | 0: Used other than as analog pin 1: Used as analog pin |
R/W |
PMR
ビットフィールド | ビットレンジ | 名称 | 機能 | R/W |
---|---|---|---|---|
PMR |
[16:16] | Port Mode Control | 0: Uses the pin as a general I/O pin 1: Uses the pin as an I/O port for peripheral functions |
R/W |
PSEL
ビットフィールド | ビットレンジ | 名称 | 機能 | R/W |
---|---|---|---|---|
PSEL |
[28:24] | Port Function Select | These bits select the peripheral function | R/W |
以上が修正した P100PFS
の全てです。
派生に関する修正
例えば修正前の P101PFS
〜 P107PFS
は、次のように P100PFS
もろとも P000PFS
の派生として定義されていました。
P101PFS
〜 P107PFS
を P100PFS
の派生とするため、次の様に修正しました。(→ 差分)
また P200PFS
、P400PFS
も同様に修正しています。以下は P200PFS
の例です。(→ 差分)
ここまで P100PFS
を例に 32ビット幅のフィールド定義だけを示してきましたが、全ての汎用 I/O 端子に PxxxPFS_HA
(16ビット)、PxxxPFS_BY
(8ビット)が割り当てられており、これら全てについても仕様に基づく検査と修正を行っています。
以上が修正の全容です。
いつの日か、こういう地味な作業を AI に任せられる日が来ると良いですネ。
SVDConv utility による検査
CMSIS-Toolbox には、CMSIS-SVD スキーマ に従い SVD ファイルを検査するコマンド svdconv が含まれています。そこで修正前の R7FA4M1AB.svd
をこのコマンドにかけてみましたが、Arduino IDE で見られたようなエラーは検出できませんでした。つまり、文法上は合っていても MCU の機能が正しく定義されているとは限らないと言うことです。
代わりに次のようなエラーが3つ検出されました。
Expression marker found but no <dim> specified: 'P00 Pin Function Control Register'
ここで言う <dim>
とは配列などの要素数を示すと思われますが、何をどう修正すれば良いのか分かりません。まぁ、Arduino IDE には影響が無さそうなので今のところは放置です
あとがき
最初は UNO R4 と同じ Cortex-M4 アーキテクチャの R7FA6M1AD.svd
から P100PSF
の定義をまるっとコピーし、「とりあえずエラーが出なくなったので OK!」とはしゃぎ、あとは「エキスパートによる修正を待つ」気でいました。
ところがどっこい、GitHub に上げてしまったところからプルリクのハナシが飛び出し、急遽再チェックしたところ初版の間違いに気づき、また日本語 ユーザーズマニュアル の誤訳に惑わされ、Renesas に真偽を問い合わせたり…と。
結局最後は自分で自分のケツを拭かざるを得なくなり、5000 行弱の該当部分をマニュアル片手に 1 行ずつチェックすると言う、実に地味な作業を強いられる羽目となりました。
でもまぁ、それもこれも UNO R4 ユーザーの皆さんの役に立てると思えばハッピーです!