割り込み処理(ISR)はなぜ短くすべきなのか?組み込み設計の本質を解説

目次

はじめに

初心者さん

イベントが来たなら、そのままISRで全部処理した方が早くないですか?

エンジニアくん

初心者の頃はみんなそう考える。でもそれを始めると、後でシステム全体が崩れ始めるかもね

これまでの記事では、

  • 割り込みの基本
  • 割り込みでやってはいけないこと

について整理してきました。

今回はさらに一歩踏み込みます。

テーマは、

👉 「割り込みは処理を書く場所ではない」

という考え方です。

これは単なるテクニックではありません。

組み込み設計そのものに関わる、
かなり重要な設計思想です。

割り込みの基本についてはこちらの記事で解説しています。


割り込み処理解説シリーズ

本記事は「割り込み処理解説」シリーズの1つです。

割り込み処理解説シリーズの全体像はこちら

割り込み記事シリーズ一覧です。

  1. 割り込みとは何か?ポーリングとの違いから理解する【組み込み入門】
  2. 割り込み処理でやってはいけないこと5選|組み込み設計の落とし穴
  3. 割り込みは「処理を書く場所」ではない|組み込み設計の本質(この記事)
  4. 割り込み×状態遷移設計|イベント駆動型組み込みの基本パターン
  5. 割り込み優先度設計の考え方|リアルタイム性を壊さないために
  6. 割り込みとRTOSなし構成の違いとは?設計思想の本質を整理する

なぜ人はISRに処理を書いてしまうのか?

理由はシンプルです。

  • イベント発生場所に近い
  • すぐ動く
  • コードがまとまって見える
  • その場で完結できる

からです。

例えば:

C
void UART_IRQHandler(void) {
    receive_data();
    parse_packet();
    update_state();
}

一見、
かなり綺麗に見えます。

実際、
小規模サンプルでは普通に動いてしまいます。

しかしシステム規模が大きくなると、
この構造が問題を生み始めます。


何が問題なのか?

このコードは、

👉 「責務を混ぜている」

状態です。

本来、

  • イベント通知
  • データ解析
  • 状態更新
  • アプリケーション処理

は別レイヤーの責務です。

しかしISRへ全部詰め込むと、

  • 割り込み依存コード増加
  • 保守性低下
  • タイミング依存化
  • テスト困難

につながります。

ISRに重い処理を書く危険性については、こちらの記事でも詳しく解説しています。


ISRの本来の役割

ISR(割り込み処理)の役割は、
本来たった1つです。

👉 「イベントが発生したことを通知する」

ことです。

つまりISRは、

👉 「処理を完結させる場所」

ではありません。


理想的なISR

理想形はこうです。

C
volatile uint8_t uart_event = 0;

void UART_IRQHandler(void) {
    uart_event = 1;
}

ISRでは、
イベント通知だけ行います。

そして実際の処理は、
メインループ側で実行します。


実処理はメイン側へ逃がす

C
while(1) {
    if(uart_event) {
        uart_event = 0;

        receive_data();
        parse_packet();
        update_state();
    }
}

こうすることで、

  • ISR短縮
  • リアルタイム性向上
  • デバッグ容易化
  • 保守性向上

など、多くのメリットがあります。


なぜ「通知だけ」が重要なのか?

理由は主に4つあります。


① ISR実行時間を最小化できる

ISR実行中は、
CPUの通常処理が中断されています。

そのためISRが長いと、

  • 他割り込み遅延
  • タイマ精度悪化
  • UART取りこぼし
  • リアルタイム性崩壊

などが起きます。

ISRを短くすることは、
組み込み設計の基本です。


② 割り込みネストに強くなる

ISR中にさらにISRが発生すると、
割り込みネストが起きます。

Timer ISR 実行中

UART ISR 発生

さらに別ISR

ネストが深くなるほど、

  • スタック消費増加
  • RAM不足
  • HardFault

などの危険が増えます。

ISRを短くすることで、
こうしたリスクも減らせます。

スタック領域については、
こちらの記事で詳しく解説しています。


割り込みが連続する状況では、割り込み優先度設計も重要です。
割り込み優先度設計はこちらの記事で解説しています。

③ テストしやすくなる

これは実務ではかなり重要です。

ISRへロジックを書き始めると、

  • 単体テスト困難
  • 再現条件依存
  • ハード依存増加

などが発生します。

例えば:

C
void UART_IRQHandler(void) {
    parse_packet();
}

この場合、
「割り込み発生」が前提になります。

つまり、

👉 普通の関数テストがしづらい

ということです。

一方、
ロジックをメイン処理側へ逃がせば、

👉 通常関数としてテスト可能

になります。

これは保守性へかなり効きます。


④ 保守性が大きく変わる

ISRに処理を書き始めると、
仕様変更のたびにISRが肥大化します。

すると、

  • 他割り込みと干渉
  • デバッグ困難
  • 再現しない不具合

などが発生しやすくなります。

特に危険なのは、

👉 「タイミング依存バグ」

です。

実行順や割り込みタイミングでしか再現しないため、
解析が非常に難しくなります。


割り込みは「入口」にすぎない

設計視点で見ると、
理想構造は以下です。

[割り込み]

[イベント通知]

[状態管理]

[処理]

割り込みは、
一番外側の「入口」にすぎません。

ロジックの中心にしてはいけません。


イベント駆動設計との関係

組み込み設計では、

👉 「イベントを起点に状態を変化させる」

設計が非常によく使われます。

例えば:

割り込みと状態遷移

この考え方を、
「イベント駆動設計」と呼びます。

つまりISRは、

👉 イベント発生を知らせるだけ

なのです。

状態遷移設計については、
こちらの記事で詳しく解説しています。

この「イベント通知→処理実行」という考え方は、RTOS設計にもつながります。

RTOS設計についてはこちらの記事で解説しています。

並行処理としての割り込み

割り込みは本質的に、

👉 「並行処理」

です。

なぜなら、

  • いつ実行されるか分からない
  • メイン処理を中断する
  • 他ISRと競合する
  • スタックを共有する

からです。

ここを理解すると、

👉 ISRへロジックを書く危険性

が見えてきます。


実務で意識していること

私が実務でかなり意識しているのは、

👉 「ISRは3行以内」

という考え方です。

例えば:

  • フラグON
  • FIFO退避
  • タイムスタンプ取得

程度に留めます。

それ以上は、
メイン処理へ逃がします。

これだけでも、
トラブルはかなり減ります。


ISRで最低限の処理が必要なケース

もちろん実務では、

👉 ISR内で最低限の処理が必要

なケースもあります。

例えば:

  • UART FIFOが小さい
  • 数µsレベルで厳しい
  • レジスタ値を即保存する必要がある

などです。


例えばUART受信

C
void UART_IRQHandler(void) {
    uint8_t data = UART_DR;

    buffer[write_idx++] = data;
}

UARTでは、
受信レジスタを早く読み出さないと、

👉 次データで上書きされる

可能性があります。

そのため、

  • レジスタ読み出し
  • FIFO退避

程度はISRで行うことがあります。


ただし重要なのは「完結させない」こと

ここが重要です。

ISR内では、

  • 解析しない
  • 判定しない
  • 長いループを書かない
  • 状態変更を最小限にする

のが基本です。

つまり、

👉 「最低限だけやって、後は逃がす」

という考え方です。


設計思想の話

割り込みをどう扱うかには、

  • 並行処理理解
  • 責務分離
  • 保守性意識
  • リアルタイム設計

がそのまま表れます。

つまりここは、

👉 「動くコードを書く人」と
👉 「壊れない設計をする人」

の差が出る場所です。


まとめ

割り込みは、

  • 処理を書く場所ではない
  • イベント通知する場所
  • システムの入口

です。

ISRへロジックを書き始めると、

  • 保守性低下
  • タイミング依存化
  • デバッグ困難

などにつながります。

そのため実際の組み込みでは、

👉 ISRはイベント通知だけ行う

という設計が非常によく使われます。

次回予告

次回は、「割り込み×状態遷移設計」について、
イベント駆動型組み込み設計の基本パターンを整理します。

この記事が参考になった方へ

割り込み処理については、
こちらのまとめ記事で全体像を整理しています。

また当サイトでは、
割り込み理解に必要なC言語文法やメモリ構造についても実務目線で解説しています。

エンジニアとして技術を学ぶことは重要ですが、
キャリアや副業についても同時に考える必要があります。

副業の現実や市場価値、今後のキャリア戦略については、
こちらの記事でまとめています。

技術に関するご相談・開発・自動化ツール作成・記事執筆などのご依頼も承っています。

小さなご相談からでもお気軽にご連絡ください。

よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!

この記事を書いた人

組み込みソフトエンジニアとして働きながら、
C言語・メモリ・ポインタなどの基礎から実務まで解説しています。

副業・キャリアについても実体験ベースで発信中です。

X・Qiita・noteでも発信しています。
X:更新情報・日常
Qiita:技術発信
note:キャリア・副業

▼まずはここから読むのがおすすめ
C言語文法シリーズ
メモリ領域解説シリーズ
割り込み処理解説シリーズ
ソフトウェア設計解説シリーズ
キャリアと副業ロードマップ

コメント

コメントする


目次