※本記事は広告を含みます。
目次
割り込み処理解説シリーズ
本記事は「割り込み処理解説」シリーズの1つです。
- 割り込みとは何か?ポーリングとの違いから理解する【組み込み入門】
- 割り込み処理でやってはいけないこと5選|組み込み設計の落とし穴(この記事)
- 割り込みは「処理を書く場所」ではない|組み込み設計の本質
- 割り込み×状態遷移設計|イベント駆動型組み込みの基本パターン
- 割り込み優先度設計の考え方|リアルタイム性を壊さないために
- 割り込みとRTOSなし構成の違いとは?設計思想の本質を整理する
前回の記事では、割り込みの基本とポーリングとの違いを整理しました。
今回は一歩踏み込みます。
割り込みは便利だが、扱いを間違えると一番危険な場所になる。
実務でよく見る「やってはいけない設計」を整理します。
① 割り込み内で重い処理を書く
これは最も多いミスです。
例:
void UART_IRQHandler(void)
{
printf("received\n");
heavy_calculation();
}なぜダメか?
- 他の割り込みが遅延する
- リアルタイム性が崩れる
- ネスト発生時に破綻する
原則
割り込みは「処理を書く場所」ではなく「通知する場所」
最低限の処理だけにする。
② printfを入れる
デバッグでやりがちです。
しかし、
- ブロッキングする
- 内部でさらに割り込みを使う可能性がある
- 実行時間が読めない
実機でだけ不具合が出る原因になります。
③ 共有変数をそのまま触る
int flag;
void ISR(void)
{
flag = 1;
}
int main(void)
{
while(1)
{
if(flag == 1)
{
flag = 0;
process();
}
}
}一見問題なさそうに見えます。
しかし:
- 最適化で読み飛ばされる
- アトミックでない場合がある
- データ競合が発生する
必須事項
- volatile指定
- クリティカルセクション管理
- アトミック性の理解
④ 割り込み内でメモリ確保をする
void ISR(void)
{
char* buf = malloc(128);
}これはかなり危険です。
理由:
- 実行時間が不定
- フラグメンテーション
- メモリ不足で落ちる
リアルタイム設計では基本的に禁止です。
組み込み開発でmallocが嫌われる理由については、こちらの記事でも解説しています。
⑤ 割り込みネストを考慮しない
優先度設定を適当にすると:
- 上位割り込みが下位を中断
- スタック使用量増大
- 予想外の再入
RAM不足やスタック破壊の原因になります。
正しい設計パターン
理想はこれ:
volatile uint8_t event_flag = 0;void ISR(void)
{
event_flag = 1; // 通知のみ
}int main(void)
{
while(1)
{
if(event_flag)
{
event_flag = 0;
process();
}
}
}割り込みは「トリガー」だけにする。
処理はメインループへ。
なぜ割り込みは設計力が問われるのか?
割り込みは、
- 実行タイミングが予測しづらい
- 同時実行性がある
- スタックを消費する
- 優先度概念がある
つまり、
並行処理設計そのもの
ここを軽く扱うと、
バグが再現しない地獄に入ります。
まとめ
割り込みでやってはいけないこと:
- 重い処理を書く
- printfする
- 共有変数を雑に扱う
- mallocする
- ネストを無視する
割り込みは便利な機能ではなく、
最も慎重に扱うべき設計ポイント
です。
次回は、
割り込みは“処理を書く場所ではない”という設計思想
をさらに深掘ります。
この記事が参考になった方へ
割り込みについてはこちらの記事でもまとめています。
- 割り込みとは何か?ポーリングとの違いから理解する【組み込み入門】
- 割り込み処理でやってはいけないこと5選|組み込み設計の落とし穴(この記事)
- 割り込みは「処理を書く場所」ではない|組み込み設計の本質
- 割り込み×状態遷移設計|イベント駆動型組み込みの基本パターン
- 割り込み優先度設計の考え方|リアルタイム性を壊さないために
- 割り込みとRTOSなし構成の違いとは?設計思想の本質を整理する
技術に関するご相談・開発・自動化ツール作成・記事執筆などのご依頼も承っています。
小さなご相談からでもお気軽にご連絡ください。

コメント