interrupts() の解説と実装リファレンス

記事内には広告が含まれています。

【概要】

interrupts() は、ArduinoフレームワークにおいてCPUのグローバル割り込み(Global Interrupts)を有効化する関数である。マイクロコントローラにおいて、割り込みは特定のイベント(タイマーの満了、外部ピンの変化、シリアル通信の受信など)が発生した際に、現在実行中のメインルーチンを一時中断し、特定の関数(ISR: Interrupt Service Routine)を実行するための仕組みである。interrupts() は、noInterrupts() 関数によって意図的に無効化された割り込み状態を解除し、システムのイベント駆動型処理を再開させる役割を担う。

【仕様】

  • 関数シグネチャ: void interrupts(void)
  • 引数: なし
  • 戻り値: なし(void)
  • データ型: 内部的にはCPUのステータスレジスタ(例:AVRのSREG)のビットフラグを操作する。
  • 初期状態: Arduinoの起動時、グローバル割り込みはデフォルトで有効(enabled)な状態から開始される。

【技術的特徴】

  • レジスタレベルの操作: この関数は抽象的なソフトウェア処理ではなく、ハードウェアの割り込みマスクレジスタを直接操作する。例えばAVRアーキテクチャにおいては、SREGレジスタのIビットをセットする動作に対応する。
  • noInterrupts() との対比: noInterrupts() と interrupts() は対になる関数である。クリティカルセクション(原子的な操作が必要な区間)を確保する際、このペアを使用して一時的に割り込みを停止・再開させる。
  • 優先度の無視: グローバル割り込みを制御するため、個別の割り込み優先度設定よりも上位の制御を司る。グローバル割り込みが無効な間は、すべての割り込みソースが無視される。

【注意点】

  • アトミック性の確保: interrupts() を呼び出す前後の区間が、データの整合性を保つために必要な「クリティカルセクション」であることを正確に把握する必要がある。不適切な範囲での無効化は、システムのリアルタイム性を損なう可能性がある。
  • 再入可能性(Reentrancy): 割り込みを有効にした直後のコードは、ISRによって中断される可能性がある。そのため、interrupts() 呼び出しの直後には、中断されても安全な(または共有リソースを保護した)コードを記述しなければならない。
  • 状態の保持: 標準的なArduinoの interrupts() は、以前の状態(有効だったか無効だったか)を保存しない。そのため、ネストされた割り込み制御を行う場合は、現在の状態を自分で管理するか、より高度なレジスタ操作を検討する必要がある。
  • ウォッチドッグタイマー: 割り込みを長時間無効にしたまま処理を行うと、ウォッチドッグタイマーが作動し、システムがリセットされる可能性がある。

【サンプルコード】

共有変数へのアクセスを保護するクリティカルセクションの実装例。

volatile int sharedCounter = 0;

// 外部割り込みによるカウンタ増加
void countISR() {
  sharedCounter++;
}

void setup() {
  pinMode(2, INPUT_PULLUP);
  attachInterrupt(digitalPinToInterrupt(2), countISR, FALLING);
  Serial.begin(9600);
}

void loop() {
  // 共有変数に対する安全な読み取り操作
  noInterrupts(); // 割り込みを無効化
  int currentCount = sharedCounter;
  noInterrupts(); // 割り込みを有効化(本来はinterrupts()を使用) 

  // 注意: Arduino環境では noInterrupts() の対として 
  // interrupts() を呼び出すのが標準的な作法です。

  Serial.print("Current Count: ");
  Serial.println(currentCount);
  delay(1000);
}

【活用例】

  1. 共有メモリの保護: メインループとISRの両方からアクセスする多バイトの変数(long型や構造体など)の更新時に、データの不整合を防ぐために使用する。
  2. 通信バッファの操作: UARTやSPIなどの通信プロトコルにおいて、受信バッファのポインタ操作やインデックス更新をアトミックに行う必要がある際に、その処理区間のみ割り込みを制御する。
  3. 精密なタイミング制御: 特定のセンサーデータ読み取り中に、他の割り込みによるジッタを完全に排除したい場合に、特定の処理ブロックをクリティカルセクションとして定義する。

コメント

タイトルとURLをコピーしました