今回はウォッチドッグタイマーについてお話します。
投稿時の開発環境を記しておきます。
PC:Windows10 OS
IDE: STM32CubeIDE Version1.3.0
Configurator: STM32CubeMX Version5.5.0
Board: STM32Nucleo-F401RE
ウォッチドッグタイマーとは?
番犬タイマーと呼べば良いでしょうか、WDTと省略して呼ばれています。
カウンタを監視していて、オーバーフローするとマイコンにリセットがかかるというものです。
WDTは例えばプログラムが暴走して動かなくなった場合にリセットをかけて正常に動作させる役割を持ちます。
通常はリセットがかからないようにカウンタをリフレッシュしてあげます。
ひと昔前までは、電源電圧の低下を監視する機能なども含んだ専用のICが主流でしたが今ではマイコンに内蔵しているものが多くなっています。
コスト的にも、こちらを使わない手はありません。
STM32では2種類のウォッチドッグタイマーが存在します。
IWDG:
独立型ウォッチドッグタイマー
先頭の I は independence の略ですね。
どちらかと言えば、こちらが一般的なのではないかと思います。
IWDGはカウンタを動かしてオーバーフローした時にリセットをかけるものです。
独立型と言われるのは、タイマーを動かすクロックがマイコンのメインクロックとは別にあるからです。
何かの障害でマイコンのクロックが停止してしまった場合でも、IWDGが動いていればリセットをかけることができます。
WWDG:
ウィンドウ・ウォッチドッグタイマー
言うまでもなく先頭の W は window の略ですね。
ウィンドウの意味は窓というよりは窓枠です。
WWDGはカウンタがオーバーフローすることに加えて、そのタイミングが想定よりも早くなることも検出します。
より堅牢なシステムでは、これら2つのWDTを組み合わせて使うことが推奨されているようです。
独立型ウォッチドッグタイマー
今回は独立型ウォッチドッグタイマーの挙動について確認してみます。
いつものように IDE (STM32CubeIDE) でプロジェクトを作成します。
File – New – STM32 Project を選択します。
Board Selector で NUCLEO-F401RE を選択し Next を押します。
Project Name に F401IWDT と入力して Finish を押します。
Initialize all peripherals with their default Mode ? と聞いてくるので Yes を押します。
(周辺機能をデフォルト値で初期化しますか?)
This kind of project is associated with the STM32CubeMx perspective.
Do you want to open this perspective now? と聞いてくるので Yes を押します。
(この種のプロジェクトはSTM32CubeMXパースペクティブに関連づけられています。今開きますか?)
この意味がわかりにくいのですが「コンフィグレーターであるSTM32CubeMXをIDEのレイアウトに取り込みますか?」と解釈しました。
これで、このボード用のある仕様で周辺機能の初期化まで行ったプロジェクトがつくられました。
Pinout & Configuration – Categories – System Core の IWDG をクリックします。
Mode – Activated にチェックを入れます。
Parameter Settings のところはそのままにしておきます。
Project Explorer でプロジェクト名 F401IWDT をクリックしておき、 Project – Build Project を選択しビルドします。
main()の中に MX_IWDG_Init()が作成されました。
MX_IWDG_Init()をダブルクリックして選択し、右クリックメニューから Open Declaration を選択することで関数の中を見ることができます。
IWDT 初期化のコード
static void MX_IWDG_Init(void)
{
hiwdg.Instance = IWDG;
hiwdg.Init.Prescaler = IWDG_PRESCALER_4;
hiwdg.Init.Reload = 4095;
if (HAL_IWDG_Init(&hiwdg) != HAL_OK)
{
Error_Handler();
}
}
コメントを省くと上のコードが書かれています。
hiwdg は IWDG_HandleTypeDef型の構造体です。
これをダブルクリックして選択し右クリックメニューから Open Declaration すると宣言部分に飛んでいき確認することができます。
IWDGはプリスケーラとリロードするカウント値のパラメータがあります。
クロックとこれらのパラメータによりウォッチドッグタイマーのタイムアウト(オーバーフロー)値が決まります。
IWDGのクロックは32kHzなので、タイムアウト値は 4 * 4095 * 1/32k = 0.511875 [sec] となっています。
プリスケーラーはいくつかの選択肢があるようです。
IWDG_PRESCALER_4 をダブルクリックして選択し、右クリックメニューから Open Declaration を選択します。
4, 8, 16, 32, 64, 128, 256 のいずれかを選択できます。
そうするとタイムアウト値は
4 * 1 * 1/32k = 125 usec から
256 * 4095 * 1/32k = 32.76 sec
の範囲に設定することができるようです。
リセット動作を確認する
ウォッチドッグタイマーを働かせないためには、カウンタをリフレッシュする必要がありますが、今の段階ではそのコードがありません。
また、ウォッチドッグタイマーの初期化処理でタイマーがスタートするコードが書かれています。
従ってプログラムを動かすと約0.5秒後にリセットがかかることになります。
まずその挙動を確認してみましょう。
ボードとPCをUSBケーブルで接続しておきます。
main()のすぐ下の HAL_Init()の行番号の部分(こちらの環境では79行目)をダブルクリックしてブレークポイントを貼ります。
Run – Debug を選択すると HAL_Init()の行でブレークします。
そこで Run – Resume (または F8キー)すると、再び HAL_Init()の行でブレークします。
下には while(1)ループがあるので、プログラムにリセットがかかっていることになります。
MX_IWDG_Init()の部分をコメントにして無効にし、同じことをすると HAL_Init()には最初の1度だけしかブレークしないので IWDT のタイムアウトによってリセットがかかっていることがわかります。
カウンターをリフレッシュするコードを追加する
このままでは使い物にならないので、リセットがかからないようにするコードを追加してみます。
Project Explorer の Drivers – STM32F4xx_HAL_Driver – Src – stm32f4xx_hal_iwdg.c をダブルクリックして開きます。
HAL_IWDG_Refresh()という関数があるので確認してください。
これを main()のwhile(1)ループに置きます。
関数の引数には IWDGの構造体アドレスの &hiwdg を指定します。
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
HAL_IWDG_Refresh(&hiwdg);
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
}
/* USER CODE END 3 */
これでプログラムを実行すると HAL_Init()には最初の一度だけしか来ないことが確認でき、カウンターのリフレッシュ動作が効いていることがわかります。
もっとも、リフレッシュの処理はwhile(1)ループで頻繁に行う必要はなく、定期的に処理するなどシステムによって検討する必要があります。
IWDG はいかがでしたか?
使われたことがない方は、ぜひ試してみてください。
コメントを書く