ペリフェラル
ペリフェラルとは何か?
ほとんどのマイクロコントローラはCPUやRAM、フラッシュメモリ以外のものを持っています。マイクロコントローラはシリコン上に専用のセクションを持っており、そのセクションは、マイクロコントローラの外のシステムとやり取りしたり、センサーやモーターコントローラ、またはディスプレイもしくはキーボードのようなヒューマンインタフェースによって世界中の周囲環境と直接的または間接的にやり取りするために使用されます。それらのコンポーネントはまとめてペリフェラルと呼ばれています。
これらのペリフェラルは有用です。なぜならば、開発者はペリフェラルに処理をオフロードすることが可能になるため、全ての処理をソフトウェアで行う必要がなくなります。デスクトップ開発者がグラフィック処理をビデオカードにオフロードするのと同じように、組込み開発者は一部のタスクをペリフェラルにオフロードして、CPUの時間を他の重要なことに使ったり、電力を節約するために何もしないようにすることができます。
1970年代か1980年代の旧式の家庭用コンピュータのメイン回路基板を見れば(実際に、旧式のデスクトップPCは今日の組込みシステムとさほど違いません)、次のものを目にするはずです。
- プロセッサ
- RAMチップ
- ROMチップ
- I/Oコントローラ
RAMチップ、ROMチップ、I/Oコントローラ(このシステムのペリフェラル)は「バス」として知られる一連の並列な配線を通してプロセッサに接続されているでしょう。アドレスバスは、プロセッサがバス上のどのデバイスと通信したいかを選択するアドレス情報を運び、データバスは、実際のデータを運びます。組込みマイクロコントローラにおいても、同じ原理が適用されます。それは全てが1つのシリコン片に詰め込まれているということです。
しかしながら、VulkanやMetal、OpenGLなどのソフトウェアのAPIを通常持つグラフィックカードとは異なり、ペリフェラルはメモリチャンクにマッピングされたハードウェアインターフェースとしてマイクロコントローラに公開されています。
線形な実メモリ空間
マイクロコントローラでは、0x4000_0000
や0x0000_0000
のような任意のアドレスにデータを書き込むことは、完全に正当な行為でしょう。
デスクトップシステムでは、メモリアクセスはMMU(メモリ管理ユニット)によって厳密に制御されています。このコンポーネントは2つの主な役割を持っています。メモリのセクションへのアクセス権限の強制(あるプロセスが別のプロセスのメモリを読み出したり変更したりできないようにする)、そして物理メモリのセグメントをソフトウェアで使用される仮想メモリ範囲に再マッピングすることです。マイクロコントローラは通常はMMUを持たず、代わりにソフトウェアで物理アドレスのみを使用します。
32ビットマイクロコントローラは0x0000_0000
から0xFFFF_FFFF
の線形な実アドレス空間を持ちますが、それらは大抵の場合、実際のメモリのためにはその範囲の数百キロバイトしか使用しません。これにより、かなりの量のアドレス空間が残ります。前の章では、RAMが0x2000_0000
のアドレスに配置されていることについて話しました。もしもRAMが64KiBの長さなら(すなわち、最大アドレスが0xFFFF)、0x2000_0000
から0x2000_FFFF
がRAMのアドレスに対応します。0x2000_1234
のアドレスにある変数に書き込むと、内部ではアドレスの上位部分(この例では0x2000)を検出し、アドレスの下位部分(この例では0x1234)に作用できるようにRAMをアクティブにします。Cortex-Mにおいては、フラッシュROMも0x0000_0000
から0x0007_FFFF
のアドレスにマッピングされています(512KiBのフラッシュROMが載っている場合)。これら2つの領域の間に残るスペースを全て無視するのではなく、代わりにマイクロコントローラの設計者は特定のメモリ配置にペリフェラルのインターフェースをマッピングしました。これは次のようなものになります。
Nordic nRF52832 Datasheet (pdf)
メモリマップド・ペリフェラル
一見すると、これらのペリフェラルとのやり取りは簡単です。正しいデータを正しいアドレスに書き込むだけです。例えば、32ビットワードをシリアルポート上で送信することは、32ビットワードを特定のメモリアドレスに書き込むことと同じくらい直接的になり得ます。シリアルポート・ペリフェラルは自動的にデータを引き受けて送信します。
これらのペリフェラルの設定についても同じように動作します。ペリフェラルの設定をするための関数を呼ぶ代わりに、ハードウェアAPIとして機能するメモリチャンクが公開されます。0x8000_0000
をSPI周波数の設定レジスタに書き込むと、SPIポートは8Mbpsでデータを送信するようになります。0x0200_0000
を同じアドレスに書き込むと、SPIは125Kbpsでデータを送信するようになります。これらの設定レジスタをちょっとだけ見てみます。
Nordic nRF52832 Datasheet (pdf)
アセンブリ言語やC言語、Rustなど、どの言語が使われようとも、このインターフェースがどのように作用するかはハードウェアによって定められています。