AVRの割り込み中にコールスタックはどのように動作しましたか?


8

(Arduino Unoに固有...)

AVRマイクロコントローラーで割り込みが発生し、関数を呼び出すと、スタックはどうなりますか?コンパイラーはコードをインライン化しますか?スタックをどこかにキャッシュしてから、スタックポインターをリセットしますか?割り込み専用のセカンダリスタックはありますか?

私が理解しているように、割り込みのベクトルは、アセンブリでの直接GOTOコマンドです。また、マイクロコントローラーが自動的にスタックを台無しにすることはないと思いますので、おそらくそのままにしておきます。ただし、ISR中に関数がどのように機能するかはまだ説明されていません。


以下の答えはすばらしいです。コンパイラが割り込み呼び出しをインライン化できないことに注意してください。なぜなら、それらは割り込み呼び出しだからです:D
Vladimir Cravero

1
@VladimirCravero割り込み内で呼び出される関数をインライン化することを意味しました(ISRでfoo()を呼び出すとインライン化されるため、実際には関数呼び出しではありませんか?)
匿名ペンギン

だから、以下の答えはあなたの質問に答えませんか、それともそうですか?cavemanは、割り込みが発生したときに何が起こるかを説明しますが、関数が割り込みコンテキストで呼び出されたときに何が起こるかについては説明しません。後者に対する答えは、特別なものは何もありません。関数が呼び出され、それだけです。魔法は、割り込みがトリガーされたときに発生し、その後(iretの前に)は通常のコードで、通常は割り込み不可能です。
Vladimir Cravero 2015年

@VladimirCraveroはい、それは(間接的に)行います。スタックをISR用に変更する方法について話していました。そもそも関数を使用するにはスタックを変更する必要があると考えていました。ISRがセットアップされた後、関数はまったく同じように機能すると推測します。
匿名のペンギン

さて、あなたはそれを得ました。割り込みベクトルにジャンプした後は、すべて問題なく、どこにでも移動できます。
Vladimir Cravero 2015年

回答:


16

AVRはRISCアーキテクチャなので、割り込みのかなり基本的なハードウェア処理を備えています。ほとんどのプロセッサは割り込み中にスタックを混乱させますが、異なる方法を使用するいくつかの、特にARMとPowerPCがあります。

いずれにせよ、これはAVRが割り込みに対して行うことです。

割り込みが発生すると、プロセッサハードウェアは次の手順を実行します。これらの手順は単なるGOTOではありません。

  1. 現在の指示を終了します。
  2. グローバル割り込みフラグを無効にします。
  3. スタック上の次の命令のアドレスをプッシュします。
  4. (発生した割り込みに応じて)正しい割り込みベクトルのアドレスをプログラムカウンターにコピーします。

この時点で、ハードウェアは実行するすべてを実行しました。ソフトウェアは、物事を壊さないように正しく書かれている必要があります。通常、次のステップはこれらの線に沿っています。

  1. ステータスレジスタをスタックにプッシュします。(これは変更する前に最初に行う必要があります)。

  2. 変更される(または変更される可能性がある)CPUレジスタをスタックにプッシュします。この方法で保存する必要があるレジスタは、プログラミングモデルによって定義されます。プログラミングモデルはコンパイラによって定義されます。

これで、作業中の割り込みコードを実行できます。関数を呼び出す問題に対応するために、関数が常に実行することを実行し、スタックに戻り値をプッシュし、完了時に戻ります。これは、これまでスタックに保存したこれらの以前の値には影響しません。

  1. ISR作業コードを実行します。

これで完了です。割り込みから復帰したいと思います。まず、ソフトウェアのクリーンアップを行う必要があります。

  1. 手順6でプッシュしたCPUレジスタをポップします。
  2. 保存したステータス値をステータスレジスタにポップします。この後、ステータスレジスタを変更する可能性のある命令を実行しないように注意する必要があります。
  3. RTI命令を実行します。ハードウェアは、この命令に対して次の手順を実行します。

    a。グローバル割り込みフラグを有効にします。(次の割り込みが受け付けられる前に、少なくとも1つの命令を実行する必要があることに注意してください。これにより、重い割り込みがバックグラウンドの作業を完全にブロックするのを防ぎます。)

    b。保存された返信アドレスをPCにポップします。

これで通常のコードに戻りました。

特にステータスレジスタと変更される可能性のあるレジスタの保存に関しては、注意が必要な点がいくつかあることに注意してください。幸いにも、Cコンパイラを使用している場合、これらはすべて内部で処理されます。

また、スタックの深さに注意する必要があります。割り込みが有効になっているときはいつでも、ISRはローカルコードを見ると明らかなよりも多くのスタックを使用できます。もちろん、これは、メモリを限界まで押し出さない限り、実際にはあまり起こりません。

ここではあなたが参照したい場合は、このプロセスを記述したリンクです。


ステップ5/6の目的は何ですか?レジスタを直接変更しないのはばかげているように思えますが、割り込み中にいくつかのレジスタをいじると、厄介な結果になる可能性があります。
匿名ペンギン

1
ステップ5と6はシステムの現在の(割り込み前の)状態を保存するので、割り込みが完了した後で復元でき(ステップ8と9)、メインプログラムが割り込みを受けなかったかのように続行できます。
Peter Bennett

1
これはすばらしい要約です。
コナーウルフ2015年

3
注目すべき点は、本当に何をしているのか本当にわかっている場合は、GCCフラグ(ISR_NAKED)を使用して、ステータスと他のレジスタの自動保存を無効にできることです。これにより、これらのサイクルが本当に必要な状況で、ステップ5、6、8、9をスキップできます。欠点は、あなたがする必要がある絶対にあなたがいずれかの任意の関連するレジスタを保持します特定の、または害なしでそれらを上書きすることができます。
コナーウルフ

2
それは興味深いことですが、そのフラグを使用する前にアセンブリプログラミングを実行します。とても危険...
穴居人2015年
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.