IoT何をいまさら(85) Wio Terminal、SAMD51の周辺に直接アクセス

Joseph Halfmoon

久しぶりのWio Terminalです。フレームワークはArduinoのままですが、今回からマイコンであるSAMD51P19Aの周辺機能を「ことさら」ダイレクトに操作して行きたいとおもいます。Armコアのマイコンとして大人気?のSAMDシリーズのお勉強を兼ねて。最終的にはIoTネタに落ち着かせる予定ですが、当分、開発環境やマイコンネタが続いてしまいますがご勘弁を。

フレームワークはArduinoで変わらないと言いましたが、今回からこちらのシリーズでは、いつもの Arduino IDE 1.8.15 ではなく、VS Code + PlatformIO をArduino開発環境として使いたいと思います(PlatformIOのWio Terminalのページはこちら。)この組み合わせ、以前から他のマイコン向けで使用してきましたが、SAMD51プラットフォームのArduinoフレームワークに使うのは初回です。理由は、マイコンのハードウエア・レジスタに触るときはこちらの方が便利だから。後で実例はご覧いただきまする。

さて、本日の「課題」は以下の1行につきます。マイコンの内蔵ペリフェラルへのアクセスのためのオマジナイ。分かっていらっしゃる方は飛ばしてください。

 Pac* pac = (Pac*)PAC;

まず Pacだか、PACだか、P、A、Cという文字が繰り返されていますが、これはSAMD51内蔵のペリフェラルのお名前です。

Peripheral Access Controller

というもの。これが何をするものかというと、不用意にハードウエア制御レジスタに書き込むことが無いようにするための「門番」機能であります。ここで書き込み禁止にすると多くの制御レジスタの書き込みが禁止されます。書き込み許可もここでできることはできるのですが、書き込み禁止に加えて、さらに鍵(ロック)をかけるとRESETしない限り書き込み許可はおりなくなります。「安全、安心?」の機能だな。

今回から触っていくほとんどの周辺回路はこのPACに守られています。まあ、使わなければ「知らないで通りすぎることもできる」ようですが知らないでいると後が怖い。

さてオマジナイの1行ですが、これはPACに限らず、多くの内蔵ペリフェラルへのアクセスが同じようなスタイルになるんじゃないかと思います。お名前を変えるだけ。

早速、最初の Pac から読み解きたいと思います。最初のPacは「Typedefされた構造体のお名前」です。PACという周辺回路の中に多数の制御レジスタが存在するので、それらを包含する上位の構造体です。その構造体名Pacにアスタリスク(*)がついているので、Pac型の構造体を指すポインタの宣言としれます。そこで宣言されているポインタ変数のお名前が2番目の小文字で綴られた pac というわけです。

さてこのpac 変数にポインタを代入するのですが、代入するポインタの実体は、PACという名前の#define文で定義されたメモリアドレスを値としてもつマクロです。値のメモリアドレスはPAC回路の制御レジスタ群の先頭番地です。単なるマクロ定義の数値なのでその値はポインタとはコンパチブルではありません。そこで(Pac*) などとキャストして代入に使うことになります。

これでオマジナイの1行の意味は判明。実際にアクセスに使うときは、以下のような感じであります。

pac->STATUSA.reg

pacはポインタ変数なので、構造体メンバを指すのにはアロー演算子を使います。上記で指されているメンバSTATUSAは、Aという名のグループにまとめられている複数の周辺装置の書き込み許可、不許可のステータスビットを集めたレジスタを表す共用体です。regという共用体メンバへアクセスすれば32ビットのレジスタイメージでアクセスできますし、bitという共用体メンバ経由であれば、bitという名の構造体の中の各ステータスビットに対応するビットフィールドにアクセスすることができます。

これを使ってPAC内部に4個あるステータスレジスタをダンプする関数をVS Code上で書いているところがこちら。

VSCode_Wioなお、ステータスレジスタはリードオンリになっています。ステータスビットを書き込み可の状態に変更することはこのレジスタ経由ではできませぬ。別途、ちょいと面倒な値を別なレジスタに書き込む必要があります。実際のレジスタやビットの意味は、当然ながらMicroChip社のSAMD51のデータシートを参照する必要があります。

しかしSAMD51の周辺回路、数も機能も充実しています。ということは多数のペリフェラル回路、そしてその何十倍?もの制御レジスタがあるということです。私もデータシートを読んでいて道に迷ってしまいました。あれ、あのレジスタどこにあったっけ?名前は?

しかし朗報です。VS Code + PlatformIOの環境下では、エディタがメンバ名などを列挙してくれます。こんな感じ。ac_sample

これがあれば、記憶力の減退している私でもなんとかなります。さらにカーソルをマクロ名 PAC の上におけば、こんな感じ。define_sample

意味や値まで表示してくれます。データシートより痒い所に手が届く感じ。さらに詳しく調べたければ、右クリックメニューから、定義のソースファイルへ飛ぶこともできるっと。近代的なIDEでは普通にサポートしている機能だと思いますが、まだ改版されていない現行のArduino IDEでは不自由なところでしょう。

jump_sampleなお、PAC内部の各構造体の定義などは以下のような深い階層にあることが分かります。自分でタラタラ追いかけるのは大変。

SAMD51_headerそいういう分けで、PAC内のステータスレジスタ4本を、シリアルポートにダンプする関数がこちら。

void readPACStatus() {
  Pac* pac = (Pac*)PAC;
  Serial.print("PAC.STATUSA: ");
  Serial.println(pac->STATUSA.reg, HEX);
  Serial.print("PAC.STATUSB: ");
  Serial.println(pac->STATUSB.reg, HEX);
  Serial.print("PAC.STATUSC: ");
  Serial.println(pac->STATUSC.reg, HEX);
  Serial.print("PAC.STATUSD: ");
  Serial.println(pac->STATUSD.reg, HEX);
}

実行結果(値はすべてHEX)がこちら。

PAC.STATUSA: 10000
PAC.STATUSB: 2 
PAC.STATUSC: 0 
PAC.STATUSD: 0

STATUSAとSTATUSBに書き込み禁止を示すビットが立っていますが、これはデフォルト初期値のまま。書き込み禁止なのはDSU(Device Service Unit、デバッグのとき使う回路)のみでした。

ぶっちゃけ、全制御レジスタ書き放題!

自分でプログラムして自分で使うのだから、それが一番平和でしょう。次回からは周辺回路ツアーか。

IoT何をいまさら(84) Eddystoneパケット、Wiresharkで表示フィルタ へ戻る

IoT何をいまさら(86) Wio Terminal、SAMD51内蔵OSC信号を取り出す へ進む