組み込みシステムにおける GPIO ポートの構成と割込み処理

マイクロコントローラを用いたファームウェア開発において、汎用入出力(GPIO)ポートは外部ハードウェアとの通信を実現するための基本的なインターフェースとなります。プロセッサ上のピン状態をソフトウェアから制御することで、デジタル信号の読み取りや出力が可能になります。本解説では、レジスタレベルでの GPIO 制御機制と、具体的な実装例を通じて入出力および割込み処理の手法について説明します。

1. レジスタ構成の概要

GPIO ピンの動作モードは、専用の制御レジスタによって管理されます。主なレジスタとしては、ピンの電気的な状態を保持するデータレジスタ、入出力方向を定義する方向レジスタ、そして外部イベントを検知するための割込み設定レジスタがあります。

  • データレジスタ(Data Register): 出力ピンの論理レベルを設定し、または入力ピンの現在の状態を読み取るために使用されます。
  • 方向レジスタ(Direction Register): 各ピンの動作方向を決定します。通常、ビットを 1 に設定すると出力モード、0 に設定すると入力モードとして機能します。
  • 割込みレジスタ(Interrupt Register): 信号の変化を検知し、プロセッサに割込みを要求するかどうかを構成します。

2. 基本的な出力制御の実装

ここでは ARM Cortex-M 系のアーキテクチャを想定し、C 言語を用いて 2 つの LED を制御する例を示します。LED_A はピン 5 に、LED_B はピン 6 に接続されており、それぞれのピンに高電圧を印加することで点灯します。

#include <stdint.h>
#include "hardware_map.h" // ハードウェア抽象化レイヤのヘッダ

int main(void)
{
    // ピン 5 と 6 を出力モードに設定
    GPIO_PORT->cfg_reg |= (1U << 5); 
    GPIO_PORT->cfg_reg |= (1U << 6);

    while (1)
    {
        // LED_A 点灯
        GPIO_PORT->out_reg |= (1U << 5);
        busy_wait(500); // 500ms 待機

        // LED_A 消灯
        GPIO_PORT->out_reg &= ~(1U << 5);
        busy_wait(500);

        // LED_B 点灯
        GPIO_PORT->out_reg |= (1U << 6);
        busy_wait(500);

        // LED_B 消灯
        GPIO_PORT->out_reg &= ~(1U << 6);
        busy_wait(500);
    }
}

3. 待機処理の構成

LED の点滅周期を視認可能にするため、簡易的な待機関数を用意します。プロセッサのクロック频率に応じてループ回数を調整する必要があります。

#include <stdint.h>

void busy_wait(uint32_t count)
{
    // システムクロック 100MHz を想定した調整係数
    volatile uint32_t loop = count * 8000;
    while (loop--)
    {
        __NOP(); // 空命令で最適化を防止
    }
}

4. 割込みによるイベント処理

ポーリング処理だけでなく、GPIO 割込みを利用することで、外部信号の変化に即座に対応できます。例えば、スイッチの押下を検知して LED を点灯させる場合、入力ピンのエッジ検出設定と割込み許可が必要です。

ここではピン 7 に接続されたスイッチが押下された際に、ピン 5 の LED を点灯させる処理を実装します。

#include <stdint.h>
#include "hardware_map.h"

void setup_gpio_interrupt(void)
{
    // ピン 7 を入力モードに設定
    GPIO_PORT->cfg_reg &= ~(1U << 7);

    // 立下りエッジで割込みを発生させる
    GPIO_PORT->edge_cfg |= (1U << 7);

    // 割込みを有効化
    GPIO_PORT->int_en |= (1U << 7);

    // 全局割込みの許可
    __enable_irq();
}

void GPIO_Handler(void)
{
    // ピン 7 の割込みフラグを確認
    if (GPIO_PORT->int_status & (1U << 7))
    {
        // LED を点灯
        GPIO_PORT->out_reg |= (1U << 5);

        // 割込みフラグをクリア
        GPIO_PORT->int_status |= (1U << 7);
    }
}

int main(void)
{
    // LED 用ピン 5 を出力設定
    GPIO_PORT->cfg_reg |= (1U << 5);

    // 割込み初期化
    setup_gpio_interrupt();

    while (1)
    {
        // バックグラウンドタスクを実行
    }
}

※上記のレジスタ名は概念図であり、実際のチップマニュアルに基づいて定義する必要があります。

5. 応用技術

基本的な入出力および割込み処理に加え、GPIO はより高度な制御にも利用されます。

5.1. PWM 信号の生成

パルス幅変調(PWM)は、デジタル出力のデューティ比を制御する技術です。タイマモジュールと連携させることで、モータの回転速度や LED の輝度調整を実現できます。特定の周期内で GPIO の出力状態を高速に切り替えることによってアナログ的な制御を模倣します。

5.2. 外部トリガ割込み

特定の GPIO ピンを外部割込み源として設定することで、センサーからのパルス信号計測や、緊急停止信号の検知などが可能になります。これにより、メインループの処理状況に関わらず、重要なイベントに対して優先的に処理を割り当てることができます。

タグ: Embedded-Systems gpio-control interrupt-handling arm-cortex-m firmware-development

6月9日 22:11 投稿