外部イベント割り込み

 

※ 外部イベント割り込み

ProjectName:"20201230ExternalInterruptTest"

 タイマなどは内部カウントしてある時間になるとイベントを発生させるため,内部イベントと呼ばれる。

 一方,ユーザのボタン操作やセンサの読み取り完了、データ受信などは外部イベント割り込みを利用する。

 イベントを発生させるトリガは入力信号の立ち上がりや立ち下がり、或いは両方の設定が可能。

 

On CubeMX

              GPIO >> PA0

              Pinoutタブ >> GPIO_EXTI*

              Configurationタブ >> GPIO ボタン

                            外部信号の立ち上がりでイベントを発生させる場合は

                            External Interrupt Mode with Rising edge trigger detection

                            立下りでイベント発生

                            Falling edge

                            両方のイベントを発生させる場合は

                            Rising/Falling

 

                            --------------------------------------------------------------------

 

                            GPIO Pull-up/Pull-down >> Pull up を選択

 

 内部プルアップ抵抗が有効になり,外部にプルアップ抵抗が不要になる。そのため,PA0にスイッチを取り付け,片方をGNDへ落とすだけの配線でスイッチを落とすとイベントを発生させることができる。

 

              Configurationタブ >> NVICボタン >> EXTI line*にチェック

                            割り込みを有効化する

 

 

 EXTI割り込みを起こすための設定はスケルトンが全部やっている。

 CubeMXが生成するスケルトンのEXTI処理手順は以下のとおり。

 

@ CPUが割り込みを受理し、CubeMXが生成したEXTI0_IRQHandler()が呼ばれる。

A EXTI0_IRQHandler()が、割り込み番号を引数としてHAL_GPIO_EXTI_IRQHandler()を呼ぶ。

B HAL_GPIO_EXTI_IRQHandler()が指定された割り込みが発生しているか確認し、発生していれば割り込みをクリアしてHAL_GPIO_EXTI_Callback()を呼ぶ。

 

HAL_GPIO_EXTI_IRQHandler()HAL_GPIO_EXTI_Callback()は名前のとおりHALの関数であり、あらかじめ用意されている。

 

※「コールバックがHALに存在するのはおかしくない?」

 

 HAL_GPIO_EXTI_Callback()weakと宣言されており、同名の関数があるとそちらがリンクされ、あらかじめHAL内部に用意されている実体は無視される。うまい仕掛けではあるが、名前を間違えてコールバック関数を作ると、リンクエラーが起きないのに永遠に呼ばれない。

 

< stm32f3xx_it.c >の関数を見る

 

/******************************************************************************/

196 /* STM32F3xx Peripheral Interrupt Handlers                                    */

197 /* Add here the Interrupt Handlers for the used peripherals.                  */

198 /* For the available peripheral interrupt handler names,                      */

199 /* please refer to the startup file (startup_stm32f3xx.s).                    */

200 /******************************************************************************/

201

202 /**

203   * @brief This function handles EXTI line0 interrupt.

204   */

205 void EXTI0_IRQHandler(void)

206 {

207   /* USER CODE BEGIN EXTI0_IRQn 0 */

208

209   /* USER CODE END EXTI0_IRQn 0 */

210   HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_0);

211   /* USER CODE BEGIN EXTI0_IRQn 1 */

212

213   /* USER CODE END EXTI0_IRQn 1 */

214 }

 

 この関数の中に割り込み処理を書く場合、「どの割り込みが発生したか」は自分で調べないといけない。

 void EXTI0_IRQHandler(void)内にコードを書くときは,もう少し低層をコントロールするときに検討すればよいかも。。。

 

< /Drivers/STM32F3xx_HAL_Driver/Src/stm32f3xx_hal_gpio.c > の関数を見る

 

*** void HAL_GPIO_EXTI_IRQHandler(uint16_t GPIO_Pin)

*** {

***   /* EXTI line interrupt detected */

***   if(__HAL_GPIO_EXTI_GET_IT(GPIO_Pin) != 0x00u)

***   {

***     __HAL_GPIO_EXTI_CLEAR_IT(GPIO_Pin);

***     HAL_GPIO_EXTI_Callback(GPIO_Pin);

***   }

*** }

-------------------------------------------------------------------------------------------

*** __weak void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)

*** {

***  /* Prevent unused argument(s) compilation warning */

***  UNUSED(GPIO_Pin);

***

***  /* NOTE: This function should not be modified, when the callback is needed,

***  the HAL_GPIO_EXTI_Callback could be implemented in the user file

*** */

*** }

 

 HAL_GPIO_EXTI_IRQHandler() は割り込みをクリアする。割り込みクリア前にしたいこと、割り込みクリア後にしたいことを書く。今回はこのまま,実際はmain.cファイル内に

 

        void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin){ }

 

を追加して,その中に具体的な処理を書けばいいらしい。

 

 ここでは発生した割り込みを受け取るハンドラの記述を行う。外部イベント割り込み関数 HAL_GPIO_EXTI_Callbackをグローバル関数として追加。外部イベント割り込みが発生するとこの関数が呼び出される。

 今回はPA0で外部イベント割り込みを設定したため,GPIO_PIN_0で割り込みが発生した際の処理を行う。

 

<コーディング> main.c

 

*** /* USER CODE BEGIN 4 */

*** void HAL_GPIO_EXTI_Callback( uint16_t GPIO_Pin ) {

***    if ( GPIO_Pin == GPIO_PIN_0 ){

***        HAL_GPIO_TogglePin(LD2_GPIO_Port, LD2_Pin);

***    }

*** }

*** /* USER CODE END 4 */

 チャタリングが発生しているため,LED_Greenの反応にバタつきがある。

 また余談だが,HAL_Delay(100);等を使うが想定通り動かなかった。割り込み内でディレイはあまりしないほうがよい?