ご飯が遅れるとマイコンをリセットする!Watchdogの仕組みと使い方

Rust
Sponsored

Watchdogタイマ(WDT)は、マイコン(MCU)が停止または暴走していないかを見張るタイマーであり、Watchdogの意味通り「番犬」としての役割を果たす。

この記事では、Raspberry Pi Picoボードに内蔵されたWatchdogタイマをRust言語で動かしながら解説し、Watchdogの動作や活用方法、さらにRaspberry Pi Pico内の時間計測におけるWatchdogタイマの役割について具体的に理解することを目指す。

Watchdogタイマ

Watchdogタイマの基本動作

RustによるRaspberry Pi Picoの開発環境では、rp2040_halクレートにWatchdogタイマが実装されている。

後述する方法でWatchdogタイマを取得し、以下のコードを書くことで、WatchdogタイマによるMCUの監視をはじめることができる。

// Activate Watchdog with time limit of 1.05 seconds
watchdog.start(1_050.millis());

ここでは制限時間を1,050ミリ秒(=1.05秒)に指定して監視を開始した。

これは、次のような契約を意味する。

タイムアウトモード

MCU
MCU

1.05秒に1回はご飯をあげるよ。

Watchdog
Watchdog

よろしくね。

MCU
MCU

僕が寝落ちしない限りは大丈夫。

制限時間内にご飯をあげたとき

監視がはじまると、Watchdogタイマは制限時間のカウントダウンをはじめる。

この間にfeedメソッドを呼ぶことで、Watchdogへの「餌付け」を行うことができる。

watchdog.feed();
MCU
MCU

watchdog.feed()

Watchdog
Watchdog

今後ともご贔屓に。

これにより、Watchdogタイマのカウントダウンが再び最初から実行される。

制限時間を超過したとき

MCU
MCU

...

Watchdog
Watchdog

ご主人が寝てる!リセットしてやる!

制限時間内にfeedメソッドが呼ばれなかった場合、WatchdogはMCUをリセット(再起動)し、プログラムを最初から実行する。

つまり、一定時間MCUからの信号がないことで、MCUの停止を検知している。

このようなWatchdogの機能をタイムアウトモードという。

ウインドウモード

Raspberry Pi PicoのWatchdogタイマには実装されていないが、以下のように、より高度な監視を行う機能も存在する。

MCU
MCU

0.05~1.05秒に1回ご飯をあげるよ。

Watchdog
Watchdog

よろしくね。

MCU
MCU

ゴハンデスヨ!

Watchdog
Watchdog

ありがとう?

MCU
MCU

ゴハンデスヨ!

Watchdog
Watchdog

ご主人が暴走してる!リセットしなきゃ!

こちらでは、異常に短い間隔で信号が与えられたときにMCUが暴走したと判断する機能が追加されている。

このような機能をウインドウモードという。

Watchdogタイマの利用方法

Watchdogタイマの取得

rp2040_halクレートを用いて、Watchdogタイマは以下のコードで取得できる。

let mut pac = pac::Peripherals::take().unwrap();

let mut watchdog = hal::Watchdog::new(pac.WATCHDOG);

Watchdogタイマによる時間計測の開始

Watchdogタイマによる監視を行う前に、Watchdogタイマが正確な時間を刻めるように設定し、時間の計測を開始する必要がある。

enable_tick_generationメソッドを呼ぶことで、Watchdogがtickの生成を開始する(時計の針を動かしはじめる)。

// Start Watchdog tick generation at 120 MHz
watchdog.enable_tick_generation((XTAL_FREQ_HZ / 1_000_000) as u8);

メソッドの引数にはWatchdogが参照するクロック(外部クリスタル)の周波数clk_refをMHz単位で表したものを与える。

Raspberry Pi Picoでは、clk_ref

const XTAL_FREQ_HZ: u32 = 12_000_000u32;

に設定されているため、引数の値は12MHzとなる。

enable_tick_generationメソッドを呼ぶのではなく、Clockを取得(初期化)することによってもWatchdogによる時間計測を開始できる。

let clocks = hal::clocks::init_clocks_and_plls(
    XTAL_FREQ_HZ,
    pac.XOSC,
    pac.CLOCKS,
    pac.PLL_SYS,
    pac.PLL_USB,
    &mut pac.RESETS,
    &mut watchdog,
)
.ok()
.unwrap();

なぜならば、Clockを初期化する際に用いたinit_clocks_and_plls関数の内部で、enable_tick_generationメソッドが実行されているためである。

WatchdogとTimerの関係

Raspberry Pi PicoのTimerは、Watchdogにおけるtick生成を参照して時間の計測を行っている。

そのためWatchdogタイマを使用しない場合であっても、Timerを使用する際にはenable_tick_generationメソッドかinit_clocks_and_plls関数でWatchdogタイマにおける時間計測を開始しておく必要がある。

サンプルコード

このコードでは、Watchdogタイマによるリセットを利用して、Raspberry Pi Picoの内部LEDの点滅タイミングを変えている。

  1. 2秒間LEDを点灯
  2. 1HzでLEDを点滅(Watchdogタイマは正常に「餌付け」される)
  3. 5HzでLEDを点滅(Watchdogタイマへの「餌付け」を行わない)
  4. 1.05秒後にWatchdogタイマがリセット信号を発し、プログラムを最初から実行する(1.に戻る)

Comments