マイコンのプログラムを勉強していると、レジスタ(Register)という言葉が登場します。
ArduinoではpinMode()やdigitalWrite()などの関数を使うだけでGPIOを制御できますが、その裏側ではマイコン内部のレジスタを使って周辺回路が設定されています。
レジスタを理解すると、GPIOだけでなく、タイマー、UART、SPI、I2C、ADCなど、これまで学んできた周辺回路がどのようにソフトウェアから制御されているのかが見えてきます。
この記事では、マイコンのレジスタとは何かという基本から、ビットフィールド、レジスタの読み書き、ビット演算との関係、データシートでレジスタを調べる方法まで解説します。
レジスタとは?
レジスタとは、マイコン内部でCPUや周辺回路の状態を保持したり、動作を設定したりするために使われる領域です。
組み込み開発で「レジスタを設定する」という場合、特にGPIO、タイマー、UARTなどの周辺回路を制御するためのレジスタを指していることがよくあります。
たとえばGPIOには、次のような設定や状態を管理するレジスタがあります。
- GPIOを入力にするか出力にするか
- 出力をHIGHにするかLOWにするか
- 入力がHIGHかLOWか
- プルアップ・プルダウンを使用するか
- 割り込みを使用するか
プログラムからこれらのレジスタを操作することで、マイコン内部のハードウェアを制御できます。
上図のように、レジスタはソフトウェアとGPIOやタイマーなどのハードウェアをつなぐ重要な役割を持っています。
CPUのレジスタと周辺回路のレジスタ
「レジスタ」という言葉には複数の意味があるため、最初に整理しておきましょう。
CPU内部には、演算やアドレス管理などに使用されるCPUレジスタがあります。
一方、GPIOやUART、タイマーなどの周辺回路にも、動作を設定したり状態を確認したりするための周辺回路レジスタがあります。
| 種類 | 主な役割 |
|---|---|
| CPUレジスタ | 演算、アドレス、プログラム実行などに使用 |
| 周辺回路レジスタ | GPIO、UART、タイマーなどの設定や状態確認に使用 |
この記事では、主に後者の周辺回路を制御するレジスタについて扱います。
レジスタとRAMは何が違う?
レジスタも値を保存できるため、RAMとの違いが分かりにくいかもしれません。
通常のRAMは、変数や配列などプログラムが使用するデータを保存するために使われます。
一方、周辺回路のレジスタは単なるデータ保存場所ではなく、各ビットがハードウェアの設定や状態と結び付いている点が重要です。
たとえば、あるレジスタのビット3を1にするとGPIO出力が有効になる、といった使われ方をします。
レジスタは複数のビットで構成されている
レジスタは8ビット、16ビット、32ビットなどのビット列で構成されています。
たとえば説明用として、次の8ビットレジスタを考えてみます。
bit 7 6 5 4 3 2 1 0 ┌───┬───┬───┬───┬───┬───┬───┬───┐ │ │ │ │ │EN │ │PU │IE │ └───┴───┴───┴───┴───┴───┴───┴───┘
仮にそれぞれを次のような機能だとします。
| ビット | 名称 | 意味 |
|---|---|---|
| 3 | EN | 機能を有効にする |
| 1 | PU | プルアップを有効にする |
| 0 | IE | 入力を有効にする |
このように、1つのレジスタの中を複数の設定項目に分けて使用することがあります。
ビットフィールドとは?
レジスタ内で特定の機能に割り当てられている1ビットまたは複数ビットの領域を、ビットフィールドと呼ぶことがあります。
1ビットだけでON/OFFを表す場合もあれば、複数ビットを使って複数の設定値から選択する場合もあります。
bit 5 bit 4 0 0 MODE 0 0 1 MODE 1 1 0 MODE 2 1 1 MODE 3
2ビットあれば、4種類の状態を表現できます。
ここでビット演算が必要になる
前回の記事で学んだビット演算が、レジスタ操作で活躍します。
たとえばレジスタのビット3だけを1にしたい場合、次のような操作ができます。
REG |= (1U << 3);
1U << 3でビット3だけが1のマスクを作り、OR演算によって元の値のほかのビットを維持したままビット3を1にします。
反対にビット3だけを0にするなら、次のようにできます。
REG &= ~(1U << 3);
ビット演算については「ビット演算とは?AND・OR・XOR・NOT・シフト演算を初心者向けに解説」で詳しく解説しています。
レジスタの値を読み出す
レジスタは設定を書き込むだけでなく、ハードウェアの状態を読み出すためにも使われます。
たとえば説明用の入力状態レジスタがあるとします。
uint32_t value = INPUT_REG;
この値のビット5がGPIO5の状態を表しているなら、AND演算を使って確認できます。
if (value & (1U << 5)) {
// bit5 が 1
}
このように、レジスタを読む → 必要なビットを取り出すという処理も組み込み開発では頻繁に登場します。
Read-Modify-Writeとは?
レジスタ操作でよく使われる考え方がRead-Modify-Writeです。
- 現在のレジスタ値を読み出す(Read)
- 必要なビットだけ変更する(Modify)
- 変更した値を書き戻す(Write)
uint32_t value;
value = REG; // Read
value |= (1U << 3); // Modify
REG = value; // Write
REG |= (1U << 3);のような記述も、概念的には現在値を基に一部を変更して書き戻す操作です。
レジスタは好き勝手に読み書きできるわけではない
ここは非常に重要です。
すべてのレジスタやビットが、同じように読み書きできるわけではありません。
データシートやテクニカルリファレンスマニュアルでは、レジスタごとに次のような属性が指定されています。
| 例 | 意味 |
|---|---|
| R | 読み出し可能 |
| W | 書き込み可能 |
| R/W | 読み書き可能 |
| RO | 読み出し専用 |
| WO | 書き込み専用 |
また、マイコンによっては「1を書き込むとフラグがクリアされる」など、特殊な動作をするビットもあります。
そのため、レジスタを操作するときは必ず対象マイコンの資料を確認します。
予約ビットにも注意する
レジスタの説明にはReserved(予約)と書かれたビットが登場することがあります。
予約ビットは将来の機能拡張や内部用途などのために確保されている領域で、どのように扱うべきかはマイコンの仕様に従う必要があります。
「使っていないビットだから自由に書き換えてよい」と考えず、データシートやリファレンスマニュアルに記載された方法で操作しましょう。
GPIOをレジスタで制御するイメージ
GPIOを出力として使用するときには、概念的には次のような設定が必要です。
- GPIOを出力として設定する
- 出力値をHIGHまたはLOWに設定する
説明用の架空のレジスタを使うと、次のようなイメージになります。
GPIO_ENABLE_REG |= (1U << 8);
GPIO_OUTPUT_REG |= (1U << 8);
1行目でGPIO8の出力を有効にし、2行目でGPIO8の出力をHIGHにするイメージです。
ここで使用しているレジスタ名は仕組みを説明するための例です。実際のESP32-C3のレジスタ名や操作方法は、Espressifの資料を確認してください。
digitalWrite()の裏側では何が起きている?
Arduinoでは、次のように簡単にGPIOを制御できます。
pinMode(8, OUTPUT);
digitalWrite(8, HIGH);
このコードを書くと、Arduino Coreなどのソフトウェアがマイコンに応じた処理を行い、最終的にはGPIO周辺回路の設定や出力状態を変更します。
つまりArduinoの関数は、複雑なハードウェア操作を分かりやすい関数として利用できるようにしているわけです。
Arduinoを使う場合でも、レジスタの仕組みを理解しておくと、ライブラリ内部のコードやマイコンのリファレンスマニュアルを読みやすくなります。
GPIO以外にもレジスタがある
レジスタはGPIOだけで使用するものではありません。
これまで学習してきた多くの周辺回路にも設定用・状態確認用のレジスタがあります。
| 周辺回路 | レジスタで設定する内容の例 |
|---|---|
| GPIO | 入出力、出力状態、プルアップなど |
| UART | 通信設定、送受信状態など |
| SPI | クロック、通信モード、転送設定など |
| I2C | 通信設定、状態、割り込みなど |
| ADC | 変換設定や状態など |
| タイマー | カウンタやアラームなど |
マイコンの周辺回路を深く理解しようとすると、最終的にレジスタの説明へたどり着くことが多いのはこのためです。
レジスタはどこを見れば分かる?
実際のレジスタ名、アドレス、ビットの意味は、マイコンメーカーが公開している資料で確認します。
資料の名称はメーカーによって異なりますが、主に次のような資料があります。
- データシート
- リファレンスマニュアル
- テクニカルリファレンスマニュアル
- プログラミングマニュアル
- SDKやHALのヘッダーファイル
ESP32-C3の場合も、チップのデータシートだけでなく、周辺回路の詳細を説明したTechnical Reference Manualなどを確認します。
レジスタ表はどう読む?
レジスタの資料には、一般的に次のような情報が掲載されています。
- レジスタ名
- アドレスまたはオフセット
- ビット位置
- ビットフィールド名
- 読み書き属性
- リセット時の初期値
- 各ビットの機能説明
最初からすべて理解する必要はありません。
まずは「変更したい機能を探す → 対応するレジスタを探す → 必要なビットを確認する」という順番で読んでいくと理解しやすくなります。
KUMITATE-C3でレジスタを学ぶ意味
KUMITATE-C3では、まずArduinoのpinMode()やdigitalWrite()を使ってGPIOを簡単に制御できます。
そのあとで、「この関数の内部では何をしているのだろう?」とライブラリやESP32-C3の資料を調べていくと、より深い組み込み開発の学習につながります。
最初からすべてをレジスタで書く必要はありません。
Arduinoで動かす → ライブラリの中を見る → レジスタを調べるという順番で学ぶと、ソフトウェアとハードウェアのつながりを理解しやすくなります。
レジスタを直接操作するときの注意点
レジスタを直接操作するとハードウェアを細かく制御できますが、その分注意点も増えます。
- マイコンごとにレジスタ構成が異なる
- 同じシリーズでも仕様差がある場合がある
- 読み書き属性を確認する
- 予約ビットを勝手に変更しない
- 書き込みによって特殊動作をするビットに注意する
- SDKやドライバが同じレジスタを操作する場合がある
- 複数の処理から同時に操作する場合は競合にも注意する
「レジスタを直接操作した方が高度」というわけではなく、用途に応じてArduino API、SDK、ドライバ、レジスタ操作を使い分けることが重要です。
まとめ
レジスタは、マイコン内部のCPUや周辺回路の設定・状態管理に使われる重要な仕組みです。
- CPUレジスタと周辺回路のレジスタは役割が異なる
- 周辺回路レジスタの各ビットにはハードウェア上の意味がある
- 複数ビットで1つの設定を表す場合もある
- ビット演算を使って必要なビットだけ変更できる
- レジスタは読み出しにも書き込みにも使われる
- Read-Modify-Writeは基本的なレジスタ操作の考え方
- すべてのレジスタが自由に読み書きできるわけではない
- 実際のレジスタ仕様はデータシートやリファレンスマニュアルで確認する
レジスタを理解すると、これまで学んできたGPIO、UART、SPI、I2C、ADC、タイマーなどが、ソフトウェアからどのようにハードウェアへつながっているのかが見えてきます。
次はさらに一歩進んで、「なぜプログラムから特定のアドレスを読み書きするとレジスタを操作できるのか」というメモリマップドI/Oの仕組みを見ていきましょう。

