Cortex M0のCMSISに割り込みハンドラーはどのように実装されますか?


9

LPC1114キットを持っています。過去数日間、Cortex M0のCMSIS実装を調査して、その中でどのように処理が行われているかを調べてきました。これまでのところ、各レジスタがどのようにマップされ、どのようにアクセスできるかを理解しました。しかし、それでも割り込みがどのように実装されているのかわかりません。CMSISの割り込みについて私が知っているのは、スタートアップファイルにいくつかの割り込みハンドラ名が記載されていることだけです。また、起動ファイルに記述されているのと同じ名前のC関数を記述するだけで、独自のハンドラーを作成できます。私を混乱させるのは、ユーザーガイドでは、すべてのGPIOを外部割り込みソースとして使用できると記載されていることです。ただし、スタートアップファイルに記載されているPIO割り込みは4つだけです。だから教えてください:

  1. 他のGPIOの外部割り込みハンドラーを実装するにはどうすればよいですか?
  2. 割り込みテーブルはCMSISのどこにマップされていますか?
  3. NVICとAVR / PICの割り込み実装の主な違いは何ですか?(NVICはフラッシュのどこにでもマッピングできます)

回答:


14

以下の情報は、イゴールの優れた回答に加えてです。

Cプログラミングの観点から見ると、割り込みハンドラーはcr_startup_xxx.cファイル(LPC1343の場合はcr_startup_lpc13.cファイルなど)で定義されています。そこではすべての可能な割り込みハンドラがWEAKエイリアスとして定義されています。割り込みソースに独自のXXX_Handler()を定義しない場合、このファイルで定義されているデフォルトの割り込みハンドラー関数が使用されます。リンカは、cr_startup_xxx.cからの割り込みベクタテーブルとともに、最終的なバイナリに含める関数を分類します。

ポートからのGPIO割り込みの例は、gpio.cのデモファイルに示されています。GPIOポートごとにNVICへの割り込み入力が1つあります。ポートの個々のビットを有効/無効にして、そのポートで割り込みを生成できます。たとえば、ポートPIO1_4およびPIO1_5での割り込みが必要な場合は、GPIO0IEで個々のPIO1_4およびPIO1_5割り込みビットを有効にします。PIOINT0_Handler()割り込みハンドラー関数が起動したとき、GPIO0RISレジスタを読み取って割り込みを適切に処理することにより、保留中のPIO1_4またはPIO1_5(または両方)の割り込みを判断する必要があります。


10

(ポイント1と2は実装の詳細であり、アーキテクチャ上の制限ではないことに注意してください。)

  1. より大きなNXPチップ(LPC17xxなど)には、独自の割り込みハンドラを持つ専用の割り込みピン(EINTn)がいくつかあります。残りのGPIOは、1つの共通割り込み(EINT3)を使用する必要があります。次に、割り込みステータスレジスタをポーリングして、割り込みをトリガーしたピンを確認できます。
  2. LPC11xxについてはあまり詳しくありませんが、GPIOポートごとに1つの割り込みがあるようです。特定のピンを特定するには、ステータスレジスタを再度確認する必要があります。ウェイクアップソースとして機能できる最大12本のピンもあります。それらを一般的な割り込みとしてハイジャックできるかどうかはわかりません(つまり、スリープ状態のときにのみトリガーされるでしょう)。
  3. デフォルトのハンドラーテーブルは、アドレス0(フラッシュ内)に配置されます。最初のエントリはSPレジスタのリセット値、2番目のエントリはリセットベクタ、残りはその他の例外と割り込みベクタです。最初の2つ(NMIやHardFaultなど)はARMによって修正され、残りはチップ固有です。実行時にベクトルを変更する必要がある場合は、RAMに再マップできます(最初にテーブルをコピーする必要があります)。LPC11xxでは、再マッピングはSRAMの先頭(0x10000000)に固定されており、他のチップはより柔軟にできます。
  4. NVICは、効率的な割り込み処理のために最適化されています。
    • 割り込みごとに0〜3のプログラム可能な優先度レベル。優先度の高い割り込みは、優先度の低い割り込みより優先されます(ネスト)。優先度の高い割り込みが終了すると、優先度の低い割り込みの実行が再開されます。
    • 割り込みエントリ時のプロセッサ状態の自動スタック。これにより、Cで直接割り込みハンドラーを記述でき、アセンブリラッパーが不要になります。
    • テールチェーン:状態をポップして再度プッシュするのではなく、次の保留中の割り込みがすぐに処理されます
    • 後着:プロセッサ状態のスタック中に優先度の高い割り込みが到着した場合、以前に保留されていた割り込みではなく、すぐに実行されます。

PICに慣れているので、このアプリケーションノートをご覧ください 。PICマイクロコントローラーからCortex-M3への移行

M3についてですが、ほとんどのポイントはM0にも適用されます。


8

オースティンとイゴールの回答は十分詳細です。しかし、私は別の方法で答えたいと思います。多分あなたはそれが役に立つと思うでしょう。

LPC11xx(Cortex-M0)のGPIOピンには4つのレベルがあり、GPIO0.0からGPIO0.nまでのすべてのピンは同じ割り込み番号を共有し、GPIO3.0からGPIO3.mまでのすべてのピンは同じ割り込み番号を共有します。

LPC11xxでGPIO割り込みを初期化するには6つのステップがあります

  1. ピン接続ブロックレジスタを変更して、ピン機能を設定します。
  2. GPIOデータ方向レジスタを変更してピン方向を設定します(デフォルト値は入力です)。
  3. 個別のピンごとに割り込みをセットアップします。GPIO割り込みマスクレジスタGPIOnIEに移動して、ビット(ピンに対応する)を論理1に設定する必要があります。
  4. GPIO割り込みセンスレジスタGPIOnIBEおよびGPIOnISを変更して、立ち上がりエッジまたは立ち下がりエッジ、あるいはその両方の割り込みをセットアップします。
  5. CMSIS関数を使用して、ネストされたベクトル割り込み制御でPIO_0 / PIO_1 / PIO_2 / PIO_3のいずれかの割り込みソースを有効にします。
  6. CMSIS関数を使用して割り込み優先順位を設定します。

コードの実装。2つの関数が必要です。1つは上記の6つのステップを初期化し、もう1つは割り込みハンドラーです。これは、スタートアップコードstartup_LPC11xx.sファイルで定義されているハンドラーと同じ名前にする必要があります。名前はPIOINT0_IRQHandlerPIOINT3_IRQHandlerです。別の名前を使用する場合は、起動ファイルの名前を変更する必要があります。

/*Init the GPIO pin for interrupt control */
void GPIO_Init(){
    LPC_IOCON-> =..              //Pin configuration register
    LPC_GPIO1->FIODIR = ...      //GPIO Data direction register
    LPC_GPIO1->FIOMASK = ..      //GPIO Data mask register - choose  the right pin
    LPC_GPIO1->GPIOnIE = ..      //Set up falling or rising edge 
    NVIC_EnableIRQ(PIO_1);       //Call API to enable interrupt in NVIC
    NVIC_SetPriority(PriorityN); //Set priority if needed
}


/*Must have the same name as listed in start-up file startup_LPC11xx.s */
void PIOINT1_IRQHandler(void){
   //Do something here
}
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.