概要
GPIO(General Purpose Input/Output:汎用入出力)は、マイコン(MCU)やSoCに搭載された汎用のデジタル入出力ピンです。ソフトウェアから方向(入力・出力)や電気的状態(High/Low)を自由に制御できるため、「汎用」という名が付いています。
組み込みシステムにおけるGPIOの役割は非常に基本的でありながら重要です。LEDの点灯制御、スイッチやボタンの入力検出、センサーとのデジタル通信、リレー駆動など、あらゆる制御の出発点となります。UART・I2C・SPIといった専用バスとは異なり、プロトコルを持たない単純な電気信号のOn/Offを扱うのがGPIOの特徴です。
歴史・背景
GPIOという概念は、1970年代のマイクロコントローラ黎明期から存在していました。Intel 8255 PPI(Programmable Peripheral Interface)は1976年に登場した代表的なパラレルI/Oチップで、外部バスに接続してポート単位でデジタルI/Oを提供しました。
マイコンに内蔵されたGPIOポートは、1980年代以降の組み込み機器の普及とともに標準的な機能となりました。当初はポート単位での方向制御が主流でしたが、現代のマイコンではピン単位での制御が当たり前となっています。さらに、プルアップ/プルダウン抵抗の内蔵化、オープンドレイン出力、割り込み機能など、多彩な機能が追加されてきました。
Raspberry PiやArduinoの普及により、GPIOはエンジニアだけでなく教育・Makerムーブメントの文脈でも広く知られるようになりました。
技術仕様
電気的特性
GPIOの電圧レベルは使用するデバイスによって異なります:
| 電圧系 | 代表デバイス | Highレベル | Lowレベル |
|---|---|---|---|
| 5V系 | Arduino Uno (AVR) | 2.0V以上 | 0.8V以下 |
| 3.3V系 | STM32, nRF52, ESP32 | 2.0V以上 | 0.5V以下 |
| 1.8V系 | 一部のSoC(省電力設計) | 1.17V以上 | 0.5V以下 |
ソース電流(Highで外部に流せる電流)とシンク電流(Lowで吸い込める電流)はマイコンによって異なりますが、一般的なSTM32では1ピンあたり最大25mA、全ピン合計では電流制限があります。LEDを直接駆動する際は必ず電流制限抵抗を挿入します。
ピンのモード
GPIOピンは複数のモードを持ちます:
・入力モード(Input)
- フローティング入力:外部から電圧を供給
- プルアップ入力:内部抵抗でHighに引き上げ
- プルダウン入力:内部抵抗でLowに引き下げ
・出力モード(Output)
- プッシュプル出力:High/Lowを積極的に駆動(最も一般的)
- オープンドレイン出力:Lowのみ駆動、Highは外部プルアップに委ねる
・アナログモード:ADC/DACピンとして使用
・代替機能(Alternate Function):UART/SPI/I2C等のペリフェラルに割り当て
プルアップ・プルダウン抵抗
内蔵プルアップ/プルダウン抵抗の一般的な値は30kΩ〜50kΩ程度です。スイッチ入力では内部プルアップを使い、スイッチON時にGNDに短絡させる回路が定番です。I2CのSDA/SCL線では外部プルアップ(1kΩ〜10kΩ)が必要で、内蔵プルアップでは抵抗値が大きすぎてバスが正しく動作しません。
動作原理
GPIOはマイコン内部のレジスタ操作によって制御されます。代表的な制御レジスタ:
- Direction Register(DDR/GPIO_MODER): ピンごとに入力/出力を設定
- Output Register(PORT/GPIO_ODR): 出力値(High/Low)を設定
- Input Register(PIN/GPIO_IDR): 現在の入力値を読み取り
- Pull-up/down Register(GPIO_PUPDR): 内部プルアップ/ダウンを設定
- Alternate Function Register(GPIO_AFR): ペリフェラル機能へ割り当て
// STM32 HALを使ったGPIO制御の例
// GPIO初期化(出力設定)
GPIO_InitTypeDef GPIO_InitStruct = {0};
__HAL_RCC_GPIOB_CLK_ENABLE(); // GPIOBのクロックを有効化
GPIO_InitStruct.Pin = GPIO_PIN_0;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP; // プッシュプル出力
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
// LED点灯/消灯
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_0, GPIO_PIN_SET); // High → LED点灯
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_0, GPIO_PIN_RESET); // Low → LED消灯
HAL_GPIO_TogglePin(GPIOB, GPIO_PIN_0); // トグル
// GPIO初期化(入力・内部プルアップ)
GPIO_InitStruct.Pin = GPIO_PIN_13;
GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
GPIO_InitStruct.Pull = GPIO_PULLUP;
HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);
// スイッチ読み取り
if (HAL_GPIO_ReadPin(GPIOC, GPIO_PIN_13) == GPIO_PIN_RESET) {
// スイッチが押された(Low = スイッチON)
}
割り込み(EXTI)
GPIOの入力変化を割り込み(interrupt)で検出できます。ポーリング(polling)と比べてCPUを無駄に使わない利点があります:
// GPIO割り込み設定(STM32)
GPIO_InitStruct.Pin = GPIO_PIN_13;
GPIO_InitStruct.Mode = GPIO_MODE_IT_FALLING; // 立ち下がりエッジで割り込み
GPIO_InitStruct.Pull = GPIO_PULLUP;
HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);
HAL_NVIC_SetPriority(EXTI15_10_IRQn, 0, 0);
HAL_NVIC_EnableIRQ(EXTI15_10_IRQn);
// 割り込みハンドラ
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin) {
if (GPIO_Pin == GPIO_PIN_13) {
// ボタン押下処理
}
}
用途・ユースケース
GPIOは組み込みシステムのあらゆる場面で活躍します:
- LED制御: 電源LED・ステータスLED・デバッグ用Lチカ。電流制限抵抗(330Ω〜1kΩ程度)を忘れずに
- スイッチ・ボタン入力: タクトスイッチ・DIPスイッチの押下検出。チャタリング対策が必要
- リレー駆動: GPIOでトランジスタやMOSFETを制御し、大電流負荷をスイッチング
- デバッグ: オシロスコープやロジックアナライザで波形を観測するためのトリガーピン
- ビットバン(Bit-banging): 専用ペリフェラルが不足している場合にGPIOでシリアル通信を模倣
- センサーの割り込み出力: 加速度センサーや温湿度センサーの「データ準備完了」信号受信
実装・開発のポイント
チャタリング対策
機械式スイッチは接点が揺れる「チャタリング」が発生します。ソフトウェアでの対策:
// ソフトウェアデバウンス
#define DEBOUNCE_TIME_MS 20
uint32_t last_press_time = 0;
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin) {
uint32_t now = HAL_GetTick();
if (now - last_press_time > DEBOUNCE_TIME_MS) {
last_press_time = now;
// 有効な押下として処理
}
}
未使用ピンの処理
未使用のGPIOピンはフローティング状態になり、ノイズを拾って消費電流が増加します。入力モードに設定した上でプルアップまたはプルダウンを有効にするか、出力Lowに固定するのが定石です。
電圧レベル変換
3.3V系マイコンと5V系デバイスを接続する場合は、レベルシフタ(ロジックレベルコンバータ)が必要です。出力方向のみであれば分圧抵抗でも対応できますが、入力方向はマイコンの最大許容電圧に注意が必要です。
Open-drainとI2Cの関係
I2Cバスはオープンドレイン構成が必須です。GPIOのオープンドレインモードとプルアップ抵抗を組み合わせることで、複数デバイスがバスを共有しながらお互いに干渉しない「Wired-AND」が実現されます。
他技術との比較
GPIO vs 専用バス(UART/I2C/SPI)
| 項目 | GPIO | UART/I2C/SPI |
|---|---|---|
| 用途 | 単純なOn/Off制御 | プロトコルを持つデータ通信 |
| 実装難易度 | 低い | 中〜高 |
| 転送速度 | 低い(ビットバン時) | 高い(ハードウェア加速) |
| ピン数 | 1ピン/信号 | 複数信号で共有バス |
| CPU負荷 | 低い(割り込み使用時) | DMAで低減可能 |
GPIO vs PWM
PWM(パルス幅変調)はGPIOの出力を高速でOn/Offする仕組みですが、通常はタイマーハードウェアが自動的に波形を生成します。GPIOをソフトウェアで高速トグルする「ソフトウェアPWM」は、タイミング精度が低くCPU負荷が高いため、専用タイマーを使うハードウェアPWMが推奨されます。