組み込み開発では、制御したいハードウェアの仕様を理解し、そのハードウェアを制御するために、
知っておかなければならない基本知識がたくさんあります。
その1つとして「割り込み」があります。
ハードウェアを制御しているソフトウェアのほとんどは「割り込み」を使用しています。
ここでは、最低限知っておくと実践でも役に立つ割り込みの基本知識をイメージしやすいように、
Linuxのデバイスドライバなどを例にしながら、簡単に解説していきたいと思います。
1.割り込みとは?
割り込みとは、「CPUで何かイベントが発生した際にソフトウェアに通知する」仕組みのことを言います。
例えば、スマホで何かしらのデータを受信した場合、データ受信割り込みが発生し、
ソフトウェアがそのデータを取得します。
電源ボタンや音量UP/DOWNボタンを押したり話したりしても割り込みが発生します。
また、割り込みが発生したとしても、ソフトウェアでその割り込みを受け取る設定をしていなければ、
その割り込みは、何も処理されないまま無かったことになりますが、
開発対象のシステムで使用する割り込みは、設計段階であらかじめ決めてあり、
それに対応したデバイスドライバの開発を行うため、不要な割り込みが発生することはまずありません。
2.割り込みハンドラについて
割り込みハンドラとは、割り込みが発生した際に、ソフトウェアで一番最初に呼び出される関数で、
ISR(Interrupts Service Routine)とも呼ばれます。
割り込み込みが発生して、割り込みハンドラがコールされるためには、デバイスドライバの初期化処理で、設定しておく必要があります。
I2Cドライバを例に見てみると、設定しているプログラムは、こんな感じです。
I2Cドライバの初期化関数で、request_irq()関数を使用することで、割り込みと割り込みハンドラ関数を結びつけています。
上図のrequest_irg()関数の第一引数が割り込み、第二引数のbcm2835_i2c_isrが割り込みハンドラの関数名になっています。
また割り込み込みハンドラ関数名には、xxxx_isr()などisrが付いた関数名が多いです。
3.割り込みハンドラの処理時間について
割り込みハンドラの処理時間は、なるべく短くして次に処理を移します。
理由は、割り込みハンドラでの処理時間が長いと他の割り込み処理が実行できないため、
システムに遅延が発生して動作が重くなる原因となるからです。
システムによってガイドラインなどがあると思いますので、
割り込みハンドラの処理時間をなるべく短くするように意識しておくと良いです。
4.割り込みハンドラ処理内で絶対にやってはいけないこと
割り込みハンドラ内で、エラーログやトレースログなどをシリアル出力すると、
ほどんどの場合、システムがフリーズしたり落ちますのでログをシリアル出力してはいけません。
どうしてもログを取りたい場合は、メモリにログをためておき、後でツールなどを使用してメモリから吸い出すか、
ワークキューに処理が移った後などで出力すると良いです。
5.割り込みの種類
割り込みには、いろいろな種類があり、
・外部装置割り込み
・タイマー割り込み
・プロセッサ間割り込み
・マスク不可割り込み(NMI)
などがあります。
外部装置割り込み
外部装置割り込みは、CPUに接続している外部装置からの割り込みで、
例えば、タッチパネルを触った時は、タッチパネルデバイスから割り込みがCPUに入り、
タッチパネルのデバイスドライバの割り込みハンドラがコールされます。
タイマー割り込み
タイマーコントローラが一定周期で割り込みを発生させる割り込みです。
例えば、10ms毎にタイマー割り込みを発生させることができ、ウォッチドック機能などに使用されています。
補足で、ウォッチドック機能とは、タイマー割り込みを使用して、
システムがフリーズしていなかどうかをチェックする機能です。
プロセッサ(CPU)間割り込み
スマートフォンなど複数のプロセッサを搭載しているシステムは、プロセッサ間で通信を行いながら動作しています。
例えば、プロセッサ間でデータを渡したい時に、相手側に割り込みを発生させることで、
共有メモリにあるデータを渡したいことを伝えることができます。
マスク不可割り込み(NMI)
上記3種類の割り込みは、割り込み禁止(マスク)することができますが、
このマスク不可割り込みは、割り込み禁止をすることができません。
なので、通常は、システム障害発生時に使用したり、デバッガの強制起動など、
システムによって用途を決めて使用する割り込みです。
6.割り込みが発生するタイミング
割り込みが発生するタイミングは、1項ではデータを受信した際やボタンを押した際など、
割り込みをイメージできるように操作レベルで書きましたが、
組み込み開発では、電圧レベルでどのようなタイミングで発生するかをイメージできている必要があります。
電圧変化の状態によって発生する割り込みには呼び方があり、
・レベル割り込み
・エッジ割り込み
の2種類があります。
また、エッジ割り込みの中には、
・立ち上がりエッジ割り込み
・立ち下がりエッジ割り込み
・両エッジ割り込み
の3種類があります。
レベル割り込み
レベル割り込みとは、電位がLow状態からHigh状態もしくは、High状態からLow状態に変化してから、
一定時間経過すると割り込みが発生します。イメージとしては、下図のような感じになります。
上図では、電位がLowからHighに変化してから10ms経過した時点割り込みが発生します。
そして、割り込みハンドラ内で、割り込みクリアをされるまで、10ms毎に割り込みが発生し続けます。
システムによって、この10msという時間は変わりますが、
レベル割り込みは、このようなタイミングで割り込みが発生します。
レベル割り込みで注意しなければならないことは、1回目の割り込みが発生して、
その割り込みハンドラ内で割り込みクリアをする必要があります。
この割り込みクリアを行っていない場合、割り込みが発生し続けてシステムのバグになります。
エッジ割り込み
エッジ割り込みは、電位が変化した瞬間に割り込みが発生します。
レベル割り込みと異なるところは、割り込みハンドラ内で割り込みクリアをする必要がありません。
そして、先ほど書きましたが、エッジ割り込みには、割り込みが発生するタイミングが、
・立ち上がりエッジ割り込み
・立ち下がりエッジ割り込み
・両エッジ割り込み
の3種類があります。
それでは、それぞれについて解説していきます。
立ち上がりエッジ割り込み
立ち上がりエッジ割り込みは、電位がLow状態からHigh状態に変化したタイミングで発生します。
例えば、スマートフォンの音量アップボタンなどのボタンを押した時に、
割り込みを発生させたい場合は、ボタンに割り当てられている割り込みを立ち上がりエッジで設定しておきます。
立ち下がりエッジ割り込み
立ち下がりエッジ割り込みは、電位がHigh状態からLow状態に変化したタイミングで発生します。
例えば、スマートフォンの音量アップボタンなどのボタンを押して離した時に、
割り込みを発生させたい場合は、ボタンに割り当てられている割り込みを立ち下がりエッジで設定しておきます。
両エッジ割り込み
両エッジ割り込みは、上記の立ち上がりエッジ/立ち下がりエッジの両方のタイミングで割り込みが発生します。
例えば、スマートフォンの音量アップボタンなどのボタンを押した時と離した時の両方で、
割り込みを発生させたい場合は、ボタンに割り当てられている割り込みを両エッジで設定しておきます。
7.割り込みが発生したタイミングを確認する方法
システム不具合などのデバッグ時に、いつ割り込みが発生したのかを確認したい場合がよくあります。
そのような時には、システムで使用していないGPIOピンを使用して、
割り込みハンドラ関数の入口/出口で、そのGPIOピンをHigh/Lowさせて、
ロジックアナライザ(以下、ロジアナ)やオシロスコープ(以下、オシロ)で確認する方法と、
ログ用のメモリバッファを確保して置いて、そのバッファにログを残していく方法があります。
何故、この方法かというと、4項で書きましたように、ログを出力するとフリーズしたり、
パニックが発生するからです。
極力プログラムの処理時間がかからないコードを書く必要があり、GPIOピンをHighにする時間は、
約1~2nmぐらいで、バッファにログを残す場合も文字数を抑えれば問題ありません。
やはり、リアルタイムで波形の状況を見たい場合には、ロジアナやオシロを使用するのが一番です。
このようなことは、実際に業務をしている方は、仕事場に機材があるので、簡単にできると思いますが、
独学で勉強している方には、少しハードルが高いです。
独学の場合、簡単に準備できる機材としては、最低限必要なのは、
・RaspberryPi ボード
・ブレッドボードやT字デバッグピン、
です。
実際の確認手順としては、以下のような感じです。
- システムで使用していないGPIOピンを探す。
- そのGPIOピンをHigh/Lowさせるコードを入れるデバイスドライバの割り込みハンドラ関数を探して、関数入口でHigh、出口でLowにするコードを記述する。
- そのコードを含んだカーネルをビルドする。
- ビルド後にできたカーネルイメージをSDカードにコピーして、起動する。
- RaspberryPiを起動して、GPIOピンをHigh/LowしているGPIOピンとオシロやロジアナを接続する。
- そのGPIOピンに対して、立ち上がりエッジか立ち下がりエッジかのトリガーをかける。
- 割り込みハンドラに手を入れたデバイスを動作させて、トリガーにかかるか確認する。
ロジアナやオシロで、割り込みの発生のタイミングや処理時間を見ることができます。
ここまでの事を初心者の方が、独学で理解して確認までできれば、
組み込み開発の割り込みの基本知識としては、もう十分と言える範囲まで来ています。
後は、ソースコードを解析したり、CPUのデータシートを見たりして、知識を深めていくことで、
さらに理解が深まっていくと思います。
8.最後に
組み込み開発で必要となる「割り込み」について、組み込み初心者の方が、
頭の中で直感的にイメージできるように解説してみました。
組み込み開発は、デバイスドライバ開発だけではなく、ファームウェア開発やCPU関連の開発など様々ありますが、
割り込みの知識は、どのような組み込み開発でも必ず必要な知識になりますので、
ここで書かれている内容を理解しておくと開発現場でも役に立つと思います。
<関連・おすすめ記事>
Linux勉強用の中古パソコンおすすめショップランキング - 水瓶座列車
RaspberryPi (ラズパイ)の購入時に最低限必要なものとおすすめセット - 水瓶座列車
RaspberryPi 4Bと3B+のスペック比較解説 - 水瓶座列車
Raspberry Pi OSのカーネルソースビルド手順解説 - 水瓶座列車
プログラミングを独学で勉強するためのLinuxパソコン準備手順 - 水瓶座列車
C言語の始め方と基本構造、コンパイルから実行までを解説 - 水瓶座列車