AGT レジスタ

Arduino UNO R4の周辺回路レジスタをモニターするプログラムを作りました。

上の画像は、低消費電力非同期汎用タイマ(AGT)のレジスタのモニター出力です。AGT は 1ms を刻む millis() で使われていて、「1」が立ってるビットを ユーザーズマニュアル で調べると、次のことが分かります。

  1. AGT コントロールレジスタ (AGTCR)
    • TSTART[1] および TCSTF[1]
      カウント動作が開始され、カウントが実行中であることを示しています。
  2. AGT モードレジスタ 1 (AGTMR1)
    • TMOD[3]
      「パルス幅測定モード」で動作しています。
    • TCK[3]
      周辺回路用クロック PCLKB(24MHz)の 分周比 18\frac{1}{8} をカウントソースとしています。
  3. AGT カウンタレジスタ (AGT)
    • AGT[16]
      824000000=13000000\frac{8}{24000000} = \frac{1}{3000000} 秒を 3000 回カウントして1ms としています。

AGT だけじゃなく、汎用 I/O 端子のレジスタをモニターする機能も入れたので、誰かの役に立つことを願い、紹介したいと思います!

FSP ユーザーマニュアル には、レジスタ、及びその下のビットフィールへのアクセスは、MCU タイプ別に定義された構造体により、次のルールに従うと定義されています。

R_ + 周辺回路の略語 + チャネル番号 + -> レジスタ名
R_ + 周辺回路の略語 + チャネル番号 + -> レジスタ名 + _b. + ビットフィールド名

上の例で言えば、AGT0 の コントロールレジスタ AGTCR の下にあるビットフィールド TSTART へのアクセスは、次のようになります。

R_AGT0->AGTCR_b.TSTART

PeripheralMonitor の紹介

仕組みはとても簡単です。UNO R4 ボードで読み取ったレジスタ情報をシリアル通信でホスト PC に送り、Tera Term 等の VT100 端末エミュレータ ソフトで表示します。プログラムは UNO R4 用ライブラリとして GitHub のリポジトリ PeripheralMonitor に上げました。

ホスト PC との接続

Arduino 公式リファレンス に従い、UNO R4 Minima/WiFi の D0 (Rx)D1 (Tx) を、秋月で入手できる FT234XCH340E などの USB シリアル変換モジュールに繋ぎます。接続は、Arduino 側の Rx を 相手側の Tx に、TxRx につなぐ、クロス接続です。もちろん USB 側は PC に繋ぎます。

Fritzig ブレッドボード図 シリアル接続

動作環境

僕の環境はとても古く、参考にならない部分もあるとは思いますが、一応記しておきます。

  • Windows:
    Intel Mac 上の Parallels で動作する Windows 7
  • MacOS:
    MacBook Pro (Late 2013), Big Sur (macOS バージョン 11.7.10)
  • Arduino IDE
    バージョン: 2.3.2、UNO R4 ボードマネージャ: 1.1.0
  • シリアル通信のプロトコル
    送信側の SERIAL_8N1 と合わせるため、データ長やパリティ、フロー制御はデフォルトのままにします。

Windows の場合

Tera Term のシリアルポート 設定と接続
Tera Term: シリアル 設定と接続

FT234X は自動でデバイスドライバがインストールされ、Tera Term の最大ボーレート 921600 まで OK でした。

一方の CH340E製造元のページ からデバイスドライバ(Windows 7 まで対応との記述あり)をダウンロード&インストールしましたが、ボーレートを下げたり delay() を咬ませたりしても文字化けが起きてしまいました。

Mac ではちゃんと動作しているので、デバイスドライバか OS に問題がありそうです。Windows 10 以上で確認ができればよかったのですが…。勘弁してください :bowing_man:

Mac の場合

FT234XCH340E とも問題なく正常に動作しました。デバイスドライバは、ターミナル.app を立ち上げ、ls -l /dev/tty.* の実行結果から、それらしい名前のファイルを見つけます。

以下は僕の環境の場合ですが、/dev/tty.usbserial-DK0G1BIL が該当します。

$ ls -l /dev/tty.*
crw-rw-rw-  1 root  wheel   22,   0  5 30 06:58 /dev/tty.Bluetooth-Incoming-Port
crw-rw-rw-  1 root  wheel   22,   2  6  2 00:49 /dev/tty.usbmodem1
crw-rw-rw-  1 root  wheel   22,   4  5 30 13:32 /dev/tty.usbmodem14201
crw-rw-rw-  1 root  wheel   22,   4  6  2 00:49 /dev/tty.usbserial-DK0G1BIL
システム情報 → ハードウェア → USB
システム情報→ハードウェア→USB

Arduino IDE がアップロード用に使うデバイスと区別するには、「アプリケーションユーティリティシステム情報.app」、または Apple マーク から「この Mac についてシステムレポートハードウェアUSB」で得られる情報と付き合わせるのが確実です。

続いて、見つけたデバイスファイル名とボーレートを screen コマンドに渡し、エミュレータを起動します。僕の Mac では、230400 がボーレートの最大でした。

screen /dev/tty.usbserial-DK0G1BIL 230400

エミュレータから抜けるには CTRL-a + k を入力します。またターミナルの表示がバグったら reset コマンドで正常に戻せます(理由は後述しますが、ほぼ確実にバグります)。

スケッチのインストールと実行

リアルタイムクロック (RTC) の Periodic Interrupt を流用し、一定時間ごとに画面を更新するサンプルスケッチを用意しました。ここでは手っ取り早く、ライブラリをインストールして実行する方法を示します。

  1. GitHub のリポジトリ から最新版の .zip ファイルを ダウンロードします。
  2. Arduino IDE のメニュー「スケッチライブラリのインクルード.ZIP形式のライブラリをインストール…」からダウンロードした .zip ファイルを読み込ませます。
  3. 続いて「ファイルスケッチ例PeripheralMonitormonitor_by_rtc」から、スケッチの サンプル を開きます。
  4. 書き込みボタン でコンパイル&アップロードすると、エミュレータに初期画面が表示されます。

画面の説明

全部で5つの画面があります。スケッチの サンプル では、D13 ピンの「ポート mn 端子機能選択レジスタ(PmnPFS)」の画面を表示します。

Arduino IDE のシリアルモニタに ?help を入力すると、使えるコマンドを表示します。超簡単な CLI ですネ。また画面が乱れた時はリターンキーのみの入力で再描画します。

Possible commands: ports, port, pins, p, agt, a, d, ?, help

1. PORTS 画面

ポート 1〜4 の Port Control レジスタ
ポート1〜4の Port Control レジスタ

ports と入力すると、ポート 1 からポート 4 まで、ポートコントロールレジスタ(PCNTR1 〜 PCNTR4)の中身を 4 桁の 16 進数で表示します。[] 内の数字はビット幅です。

各ポートには、それぞれ 0 〜 15 のビットに対応づけられた、最大で 16 本の I/O 端子(ピン)が割り当てられています。

プログラムではなり振り構わず表示してしまいますが、ユーザーズマニュアル によると、全てのピンが存在するわけではなく、下表のように構成されています。

ポートごとのピンの構成表
ポート ピン(パッケージ: 64ピン) 本数
ポート 0 P000 ~ P004, P010 ~ P015 11
ポート 1 P100 ~ P113 14
ポート 2 P200, P201, P204 ~ P206, P212 ~ P215 9
ポート 3 P300 ~ P304 5
ポート 4 P400 ~ P402, P407 ~ P411 8
ポート 5 P500 ~ P502 3
ポート 6 なし 0
ポート 7 なし 0
ポート 8 なし 0
ポート 9 P914, P915 2

サンプル画像 では、ポート 1 の PODR(端子出力データ、0: Low 出力、1: High 出力)と PIDR(端子状態、0: Low レベル、1: High レベル)がチラチラと変化する様子が見えます。これを次のコマンドで、詳細に確認することが出来ます。

2. PORT 画面

ポート 1 の Port Control レジスタ
ポート1 の Port Control レジスタ

例えば port1 のように、port に続けて 0 〜 9 を入力すると、各ポートのコントロールレジスタの中身を確認できます。

サンプル画像では、PODRPIDR の3ビット目、即ちピン P102 で、何かが起きていることが確認できます。

3. PmnPFS 画面

ポート 102 の Port Function Select レジスタ
P102 の PmnPFS レジスタ

例えば p102 のように、p に続けて 0 〜 9 のポート番号 m と 00 〜 15 のピン番号 n を入力すると、ポート mn 端子機能選択レジスタ(PmnPFS)を表示します。

このレジスタは、ポートコントロールレジスタと重複する一部のビット列を含み、入出力の機能を制御するビットフィールドで構成されています。

重複するビットフィールドへのアクセス方法について

例えば P102PmnPFS レジスタの下にあるビットフィールド PODR に「1」を書き込むコードは、次の2つのパターンが可能です。

R_PFS->PORT[1].PIN[2].PmnPFS |= (1 << R_PFS_PORT_PIN_PmnPFS_PODR_Pos);
R_PFS->PORT[1].PIN[2].PmnPFS_b.PODR = 1;

一方 PODR は、ポートコントロールレジスタ PCNTR1 のビットフィールド PODR とも重複するので、次の方法でも可能です。

R_PORT1->PCNTR1        |= (1 << (R_PORT0_PCNTR1_PODR_Pos + 2));
R_PORT1->PCNTR1_b.PODR |= (1 << 2);
R_PORT1->PODR          |= (1 << 2);
R_PORT1->PODR_b.PODR2 = 1;

上の例の様に、書き込むビットフィールドが1つの場合、敢えて可読性の低い方法を選択するのはナンセンスですが、複数のビットフィールドをまとめて設定する場合、レジスタへのアクセス回数が極力少なくなるよう、複数の方法が提供されています。

詳しくは FSP ユーザーマニュアル の実例を参照してください。

4. PINS 画面

D0〜D19 の Port Function Select レジスタ
D0〜D19 の PmnPFS レジスタ

単に pins と入力すると、ボード上のデジタルピンとアナログピンの PmnPFS レジスタを一覧表示します。表示上、D10D13DaDd としています。

また逆引きも可能で、例えば d13 を入力すると、Minima では P111 を、WiFi では P102 を表示します。

5. AGT 画面

AGT0 レジスタ
AGT0 レジスタ

冒頭に示した AGT レジスタの画面を表示するには、agt0 または agt1 と入力します。

この画面は、「BGM再生用に作成したArduino UNO R4用タイマライブラリの解説」で FspTimer クラス をテストするときに欲しかった機能で、ようやく実現しました :+1:

画面表示と実行速度について

表示がバグったコンソール.app
表示がバグったコンソール.app

画面のカーソル制御に ANSI エスケープコード を使っている関係上、特に Mac では通信が途切れるとシーケンスが乱れ、バグったような状態になります。このような状態になったら、コマンド reset を入力してください。正常に戻ります。

また、本来は PC 側で curses ライブラリ や GUI ソフトで画面制御すべきを、Arduino ボード側で行っているため、それなりの時間を要します。下の表は、シリアル通信のボーレートと各画面の実行時間を micros() で計測した結果です。

Baud Rate PORTS [ms] PORTx [ms] PINS [ms] Pxxx [ms] AGTx [ms] Windows MacOS
115200 44.903 26.336 198.231 11.660 24.006
230400 23.815 13.620 105.974 6.014 12.327
460800 13.248 7.255 59.804 3.187 6.486 ×
921600 7.957 4.069 36.668 1.773 3.560 ×

数値には文字列の生成と通信の時間を含んでいて、ほぼボーレートと反比例の関係にあることから、通信にかかる時間が支配的であることが分かります。

Blutooth を使えばもう少し速くなるとは思いますが、他のプログラムと組み合わせてデバッグに使える程のリアルタイム性はなく、あくまで学習用というワケです。

周辺回路のレジスタ定義について

以前の記事 で解説したR7FA4M1AB.svd には、周辺回路のレジスタやアドレスが定義されてますが、プログラミングには R7FA4M1AB.h が便利です。

このファイルは Arduino 階層の深いところにあります。以下は Mac での例です(1.2.0 はボードマネージャのバージョン)。

/Users/xxxx/Library/Arduino15/packages/arduino/hardware/renesas_uno/1.2.0/variants/MINIMA/includes/ra/fsp/src/bsp/cmsis/Device/RENESAS/Include/R7FA4M1AB.h

これを手作業で見つけ出すのは激ムズです。そんな時、Mac や Linux の人なら次の find コマンドが便利です。

find . -name "*.h" -exec grep -w R_PORT1 {} \; -print

このコマンドは、以下の様に働きます。

  • . が示す現在のディレクトリから、-name で示される .h ファイルを探し、
  • -exec\; で囲まれたコマンドを実行し、
  • {} でファイルへのパスを grep に渡し、
  • -w でワード単位に R_PORT1 を検索し、
  • -print で検索に引っ掛かったファイルへのパスを出力する。

find には沢山のオプションがあるので、幾つかを覚えておくと便利ですョ :point_up:

おまけ

Minima の P204 の状態がチラついている
Minima の P204 がチラついている

Minima の汎用 I/O 端子レジスタを観察していたら、何やら P204 の状態がフラついているのが観測されました。

ご存知の方も多いと思いますが、Minima の回路図 を見ると、これは基盤裏側の LOVE ピンですネ。

この LOVE ピンは Arduino Forum でも取り上げられていて、このピンを GND に落とすだけの、なんちゃってタッチセンサを実験している人がいました。

さらに、とても研究熱心な Delta_G さんユーザーズマニュアル を元に作り込んだライブラリもありました。33 分にもなる 解説の YouTube 動画 は勉強になります!

今後の予定は…

何を作るにせよ、割り込みコントローラユニット (ICU) やイベントリンクコントローラ (ELC) がキモになりそうな気がしています。

Arduino IDE のデバッグ機能にある CORTEX PERIPHERALS は、とても使い勝手が悪いので、作ってみるカモです :clown_face:

Arduino IDE の CORTEX PERIPHERALS は使い勝手が最悪!
Arduino IDE の CORTEX PERIPHERALS は使い勝手が最悪!

ご参考

PeripheralMonitor を作るに当たり、参考にさせて頂いたサイトです。