STM32 NucleoでGPIO割り込みの実装

GPIO interrupts on STM32
 
GPIOピンへの信号の変化など、外部の要因で割り込み処理を発生させる機能はSTM32では「外部割り込みコントローラー(EXTI)」と呼んでいます。STM32ではGPIO向けに7つの受け入れ口(ハンドラ)があり、PA0とPB0のように同じラインに属するピンは同じハンドラに渡されるため、実際にどのピンが切り替わったかは、割り込みルーチン内で調べる必要があります。

では、Nucleoに標準で付いている青いユーザーボタン(B1)を使った割り込み処理のプログラムを作ってみましょう。

STM32CubeMXを開いたら、ピンアウト設定でPC13のGPIOモードを「外部割り込みによるエッジの立ち上がり・立ち下がりを検出(External Interrupt Mode with Rising/Falling edge trigger detection)」を選択し、ボタンを押したときと離したときにイベントが発生するようにします。
通常、マイコンのスイッチ操作では誤動作防止用の抵抗やコンデンサーが必要ですが、Nucleoの回路図を見てわかるように、青いスイッチにはこれらの部品がすでに備わっているので、ソフトウェア側でプルアップ抵抗などを指定する必要は特にありません。
続いてEXTIを有効化します。ピンアウト設定の「GPIO」もしくは「NVIC」カテゴリーにある「EXTI line[15:10] interrupts」にチェックを入れます。この「15:10」というのは10~15ラインを示していて、すべてのポートの10~15番ピンが、同じ割り込み処理で呼び出されることになります。


STM32CubeMXで生成される割り込み処理関連のコードは「Src/stm32f4xx_it.c(STM32F466REボードの場合)」にまとめられています。このファイルから「EXTI15_10_IRQHandler()」関数を探しだし、「HAL_GPIO_EXTI_IRQHandler()」の前にコードを追記します(HAL_GPIO_EXTI_IRQHandlerで割り込みフラグがリセットされるため)。
stm32f4xx_it.c
/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include "app.h"
/* USER CODE END Includes */

void EXTI15_10_IRQHandler(void)
{
  /* USER CODE BEGIN EXTI15_10_IRQn 0 */
  OnInterruptEXTI15_10();
  /* USER CODE END EXTI15_10_IRQn 0 */
  HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_13);
  /* USER CODE BEGIN EXTI15_10_IRQn 1 */
  /* USER CODE END EXTI15_10_IRQn 1 */
}
app.h
#ifndef APP_H_
#define APP_H_

void OnInterruptEXTI15_10();

#endif /* APP_H_ */
オンボードのスイッチを押すと回路はGNDに直結される、つまり、スイッチを押している状態だとGPIO_PIN_RESET(0)になるので、スイッチを押してLEDを点灯させたいのであれば、B1の返す値を反転させる必要があります。
app.c
#include "main.h"

void OnInterruptEXTI15_10()
{
	auto ps = HAL_GPIO_ReadPin(B1_GPIO_Port, B1_Pin);
	HAL_GPIO_WritePin(LD2_GPIO_Port, LD2_Pin, !ps);
}
2019/03/05