STMicroelectronics社純正開発環境Cube IDEを使用し、STM32のHAL(hardware abstraction layer)を思いつくまま試用中です。前回はGPIO入力とprintf出力を使えるようになりました。今回はソフトウエアでのGPIOポーリングを割り込み入力に変更してみます。
※Windows 11 PC上にインストールしたSTM32CubeIDE Version: 1.13.2上で動作を確認しています。今回のターゲットボードは Nucleo-F072RBです。
GPIOピンの割り込み設定
前回作成したプロジェクトの設定を見直して気づきました。ユーザーボタンが設置されているPC13端子の設定、割り込み待ち受けできるような設定になっているんじゃないだろうか?
前回はチップイメージのPin Configurationを眺めてましたが、その左側に「テーブル」イメージのConfigurationも表示できたのです。それを見ていたら上のような設定になってました。上記はこちらで設定した記憶がないのでボードを選択時に「よきに計らってくれた」結果でしょう。上記から読み取れるのは
-
- PC13は割り込み受け可能な設定になっている
- トリガ条件は立下りエッジである
- チップ内のプルアップ、プルダウンはイネーブルになっていない
念のため、Nucleoの回路図を参照すると、B1 USERボタン(青色)、PC13ピンに接続はPUSHするとLOWが入力されるようなプッシュスイッチであり、4.7kΩのプルアップ抵抗が入ってます。ハード的には何もしないでも割り込みかけれそうね。
さてソフトウエアの割り込みハンドラはどうやって設定したら良いのでしょう?例によって、stm32f0xx_hal_gpio.c の中身を覗いてみるとありました。
__weak void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
上記がEXTI(外部割込み入力)のハンドラの仮のものみたいです。仮というのは他でありません、冒頭にある
__weak
がその心をしめしてます。この__weakが無ければ、他の場所で同名の関数を定義したりするとリンカが分けわからんとお怒りになってエラーになる筈。しかし、__weakと宣言されているここの関数は、そうでない同名の関数に負ける定めです。実際、この「仮関数」の中身をみると、ここのハンドラの中身を書き変えるんじゃなくて、ユーザファイルの中で同名の関数を定義しろ、というようなことが書いてあった気がします。
そこで前回プロジェクトをチョイ変して、HAL_GPIO_EXTI_Callback関数をデッチあげました。LEDを点灯するだけ。消灯はメインループにお任せです。勇躍ビルドしてボードに書き込みました。メインループは走っているのに割り込みが受け付けられません。printfでUART使っているからな、割り込み不許可の筈がないのだが。。。
そこで気づきました。STM32もArm Cortex-Mの一族です。Cortex-Mにおかれましては、NVICというArmの割り込みハンドラが漏れなく装備されており、各ペリフェラル割り込みはそこを設定しないと有効になりません。
CubeIDEのコンフィギュレーションをみればしっかりNVICのタブがありました。
ここのイネーブルにチェックを入れました。こんだけ。
プロジェクトの再ジェネレーション
Configurationを変更してしまったので、プロジェクトのソースを再生成しないとなりません。プロジェクトメニューから Generate Code を実施。ビルドすると前回なかったwarningが出てます。調べると、stdio.h が飛んでしまっていました。この理由は、前回 #includeを置いた位置が悪かったのでした。前回は、#include “main.h”の直下に並べておいたのですが、ココはIDEが勝手に生成消去する場所みたいです。USERが追加する#includeはその下の /* USER CODE BEGIN Includes */とENDの間に置かないと再生成のときに保護してもらえないみたいっす。
Cube IDE全般に、ソースコードの書き変えのお作法として
コメント内にUSER CODEと書かれているBEGIN~END内に書く
ということを徹底せにゃなりません。縛りはキツイけれども「型にはめとけ」ば何かと分かり易いかも。
今回実験したコード
割り込みからのCallback関数は以下のとおり、どこのピンから割り込みがかかっているのかもチェックしない手抜き。LED点灯のみ。
/* USER CODE BEGIN 0 */ void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin) { HAL_GPIO_WritePin(GPIOA, GPIO_PIN_5, GPIO_PIN_SET); } /* USER CODE END 0 */
main()関数内の無限ループ部分が以下に
/* Infinite loop */ /* USER CODE BEGIN WHILE */ while (1) { /* USER CODE END WHILE */ /* USER CODE BEGIN 3 */ printf("PUSH Blue key.\n"); HAL_Delay(2000); HAL_GPIO_WritePin(GPIOA, GPIO_PIN_5, GPIO_PIN_RESET); } /* USER CODE END 3 */
こちらは割り込みのタイミングなど無視して消灯専門。STDIOに青いキーを押せ!と出力。
前回で38400ボーでUSBシリアルに仮想端末を接続できるようにしてあったのでPUSH Blue key.と表示される度にユーザーキーをプッシュ。LEDが光りますぞ。あたりまえか。
STM32のHALの使い方について良いページがあった
上記のようなことを自力更生していて、ようやくSTM32のHALの使い方を説明してくださっているページに気づきました。stm32mcu/wiki内のページです。今回の外部端子からの割り込みについては以下に
STM32MCU Getting started with EXTI
なんだ、みんな書いてあるじゃん。早く言ってよ。