@vicatcuの答えはかなり包括的です。注意すべきもう1つの点は、プログラムやデータメモリを含む I / Oにアクセスするときに、CPUが待機状態(CPUサイクルの停止)に陥ることがあることです。
たとえば、TI F28335 DSPを使用しています。RAMの一部の領域は、プログラムおよびデータメモリの0待機状態であるため、RAMでコードを実行すると、命令ごとに1サイクルで実行されます(1サイクル以上かかる命令を除く)。ただし、フラッシュメモリ(内蔵EEPROM、多かれ少なかれ)からコードを実行する場合、150MHzでフルに実行することはできず、数倍遅くなります。
高速割り込みコードに関しては、多くのことを学ぶ必要があります。
まず、コンパイラに慣れます。コンパイラーが適切に機能する場合、ほとんどの場合、手作業でコード化したアセンブリよりも遅くなることはありません。(「それよりもはるかに遅い」:2の要素は私には問題ありませんが、10の要素は受け入れられません)コンパイラ最適化フラグを使用する方法(およびいつ)を学習する必要があります。コンパイラーの出力で、その動作を確認します。
コードを高速化するためにコンパイラーにできるその他のこと:
小さな関数と、1回または2回だけ実行される関数の両方で、インライン関数を使用します(Cがこれをサポートしているかどうか、またはC ++-ismのみかどうかを思い出せません)。欠点は、特にコンパイラの最適化がオンになっている場合、インライン関数のデバッグが難しいことです。ただし、特に「関数」の抽象化がコードの実装ではなく概念設計の目的である場合は、不要な呼び出し/戻りシーケンスを節約できます。
コンパイラーのマニュアルを調べて、組み込み関数があるかどうかを確認してください。これらはコンパイラーに依存する組み込み関数であり、プロセッサーのアセンブリー命令に直接マップされます。一部のプロセッサには、最小/最大/ビット反転などの便利なことを行うアセンブリ命令があり、そうすることで時間を節約できます。
数値計算を行う場合は、数学ライブラリ関数を不必要に呼び出さないようにしてください。コードがy = (y+1) % 4
、期間が4のカウンターのようなもので、コンパイラーがモジュロ4をビットANDとして実装することを期待しているケースが1つありました。代わりに、数学ライブラリを呼び出しました。だから私たちy = (y+1) & 3
は、私たちがやりたいことをするために置き換えました。
ちょっとしたハックページに慣れてください。これらのうち少なくとも1つを頻繁に使用することを保証します。
また、CPUのタイマーペリフェラルを使用してコード実行時間を測定する必要があります。それらのほとんどには、CPUクロック周波数で実行するように設定できるタイマー/カウンターがあります。重要なコードの最初と最後でカウンターのコピーをキャプチャして、どれだけ時間がかかるかを確認できます。それができない場合は、別の方法として、コードの先頭で出力ピンを下げ、最後に上げて、オシロスコープでこの出力を見て実行時間を計ることができます。各アプローチにはトレードオフがあります。内部タイマー/カウンターはより柔軟です(いくつかの時間を計ることができます)が、情報を取得することは困難ですが、出力ピンの設定/クリアはスコープですぐに表示され、統計をキャプチャできますが、複数のイベントを区別するのは困難です。
最後に、経験が付属して非常に重要なスキルがあります-一般的および特定のプロセッサ/コンパイラの組み合わせで両方:ときといないときに最適化することを知ること。一般に、答えは最適化しないことです。Donald Knuthの引用はStackOverflowに頻繁に投稿されます(通常は最後の部分のみ)。
小さな効率については忘れてください。たとえば、約97%の時間です。時期尚早な最適化がすべての悪の根源です
しかし、ある種の最適化を行う必要があることがわかっている状況にいるので、弾丸を噛んで最適化(またはより高速なプロセッサ、またはその両方)を行う時が来ました。ISR全体をアセンブリで記述しないでください。これはほぼ保証された災害です。これを行うと、数か月または数週間以内に、行ったことの一部とその理由が忘れられ、コードは非常に壊れやすく、変更が困難になります。それは、しかし、あなたのコードの一部である可能性が高いがありますアセンブリのための良い候補。
コードの一部がアセンブリコーディングに適していることを示します。
- よく含まれ、明確に定義された小さなルーチンであり、変更される可能性が低い
- 特定のアセンブリ命令を利用できる関数(最小/最大/右シフトなど)
- 何度も呼び出される関数(乗数が得られます:各呼び出しで0.5usecを保存し、10回呼び出されると、5 usecを節約できます)
C呼び出し可能なアセンブリルーチンを記述できるように、コンパイラの関数呼び出し規約(たとえば、引数をレジスタに配置する場所、およびレジスタが保存/復元する場所)を学習します。
私の現在のプロジェクトでは、10kHzの割り込みで実行する必要がある重要なコード(100usec-なじみのある?)を備えたかなり大きなコードベースがあり、アセンブリで記述された関数はそれほど多くありません。つまり、CRC計算、ソフトウェアキュー、ADCゲイン/オフセット補償などです。
幸運を!