ウォッチドッグ・ライブラリを作ってみた。
タイムアウト時間は8ms(1.024ms x 8)から16S(1.024ms x 16384)まで。begin()で指定したタイムアウト時間以内にreset()が呼び出されないとシステムリセットされる。逆に指定時間以内にreset()が呼び出されるとシステムリセットするウインドウ・モードもある。
GCLOCK_SRC_OSCULP32Kからのクロックなのでスリープ・モードでも動作し続ける。そのため早期警告割り込みを使うと定期的にウェイクアップする間欠処理型アプリケーションに応用できるとドキュメントには書かれている。この場合の設定は、windowとewoffsetに同じ時間を指定すると良い。逆に言うと待ち時間の不明なスリープモードに入る前には停止する必要があるということになる。
・ノーマル・モード
正常範囲<タイムアウト値(8ms-16S)
・ウインドウ・モード
ウインドウ値(8ms-16S)<正常範囲<ウインドウ値+タイムアウト値(16ms-32S)
PS.
本日、OSアップデートしたところ本ブログがバッサリと丸ごと消されてしまい焦ってしまった。普段何気にアップデートしていたがこういうこともあるんだと思うとやはりバックアップはこまめにとっておくべきだと痛感した今日この頃。もう、こんなことはないと祈るしか手段がないのが辛いが...って、鯖メーカーさん、アップデートで既存ディレクトリ丸ごと消すってはいくらなんでも酷すぎはしませんか?
ということで、このブログも昨年から事故続きでいつまで持つかわからないのでした...
【概要】
1 |
void begin(WATCHDOG_TIMEOUT timeout, WATCHDOG_WINDOW window = WATCHDOG_WINDOW_NONE, WATCHDOG_EWOFFSET ewoffset = WATCHDOG_EWOFFSET_NONE, WATCHDOG_CALLBACK cb = 0) |
指定したタイムアウト時間(timeout)でウォッチドッグを開始する。ウインドウ・モード(window)や早期警告割り込み(ewoffset and cb)も設定可能。
1 |
void end(void) |
ウォッチドッグを停止する。
1 |
void reset(void) |
ウォッチドッグを再スタートする。
【サンプルスケッチ】
1 2 3 4 5 6 7 8 9 10 11 |
#include “watchdog.h” void setup() { WatchDog::begin(WATCHDOG_TIMEOUT_2S); } void loop() { WatchDog::reset(); } |
【ライブラリ】
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 |
/* watchdog.h - WatchDog Library for Microchip ATSAMD21 (Cortex®-M0+) Copyright (c) 2020 Sasapea's Lab. All right reserved. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef __WATCHDOG_H #define __WATCHDOG_H #include <stdint.h> #include <stdbool.h> #include <sam.h> #include "gclock.h" typedef enumは { WATCHDOG_TIMEOUT_8MS = WDT_CONFIG_PER_8_Val, WATCHDOG_TIMEOUT_16MS = WDT_CONFIG_PER_16_Val, WATCHDOG_TIMEOUT_32MS = WDT_CONFIG_PER_32_Val, WATCHDOG_TIMEOUT_64MS = WDT_CONFIG_PER_64_Val, WATCHDOG_TIMEOUT_128MS = WDT_CONFIG_PER_128_Val, WATCHDOG_TIMEOUT_256MS = WDT_CONFIG_PER_256_Val, WATCHDOG_TIMEOUT_512MS = WDT_CONFIG_PER_512_Val, WATCHDOG_TIMEOUT_1S = WDT_CONFIG_PER_1K_Val, WATCHDOG_TIMEOUT_2S = WDT_CONFIG_PER_2K_Val, WATCHDOG_TIMEOUT_4S = WDT_CONFIG_PER_4K_Val, WATCHDOG_TIMEOUT_8S = WDT_CONFIG_PER_8K_Val, WATCHDOG_TIMEOUT_16S = WDT_CONFIG_PER_16K_Val, } WATCHDOG_TIMEOUT; typedef enum { WATCHDOG_WINDOW_8MS = WDT_CONFIG_WINDOW_8_Val, WATCHDOG_WINDOW_16MS = WDT_CONFIG_WINDOW_16_Val, WATCHDOG_WINDOW_32MS = WDT_CONFIG_WINDOW_32_Val, WATCHDOG_WINDOW_64MS = WDT_CONFIG_WINDOW_64_Val, WATCHDOG_WINDOW_128MS = WDT_CONFIG_WINDOW_128_Val, WATCHDOG_WINDOW_256MS = WDT_CONFIG_WINDOW_256_Val, WATCHDOG_WINDOW_512MS = WDT_CONFIG_WINDOW_512_Val, WATCHDOG_WINDOW_1S = WDT_CONFIG_WINDOW_1K_Val, WATCHDOG_WINDOW_2S = WDT_CONFIG_WINDOW_2K_Val, WATCHDOG_WINDOW_4S = WDT_CONFIG_WINDOW_4K_Val, WATCHDOG_WINDOW_8S = WDT_CONFIG_WINDOW_8K_Val, WATCHDOG_WINDOW_16S = WDT_CONFIG_WINDOW_16K_Val, WATCHDOG_WINDOW_NONE = WATCHDOG_WINDOW_16S + 1, } WATCHDOG_WINDOW; typedef enum { WATCHDOG_EWOFFSET_8MS = WDT_EWCTRL_EWOFFSET_8_Val, WATCHDOG_EWOFFSET_16MS = WDT_EWCTRL_EWOFFSET_16_Val, WATCHDOG_EWOFFSET_32MS = WDT_EWCTRL_EWOFFSET_32_Val, WATCHDOG_EWOFFSET_64MS = WDT_EWCTRL_EWOFFSET_64_Val, WATCHDOG_EWOFFSET_128MS = WDT_EWCTRL_EWOFFSET_128_Val, WATCHDOG_EWOFFSET_256MS = WDT_EWCTRL_EWOFFSET_256_Val, WATCHDOG_EWOFFSET_512MS = WDT_EWCTRL_EWOFFSET_512_Val, WATCHDOG_EWOFFSET_1S = WDT_EWCTRL_EWOFFSET_1K_Val, WATCHDOG_EWOFFSET_2S = WDT_EWCTRL_EWOFFSET_2K_Val, WATCHDOG_EWOFFSET_4S = WDT_EWCTRL_EWOFFSET_4K_Val, WATCHDOG_EWOFFSET_8S = WDT_EWCTRL_EWOFFSET_8K_Val, WATCHDOG_EWOFFSET_16S = WDT_EWCTRL_EWOFFSET_16K_Val, WATCHDOG_EWOFFSET_NONE = WATCHDOG_EWOFFSET_16S + 1, } WATCHDOG_EWOFFSET; typedef void (*WATCHDOG_CALLBACK)(void); #define WATCHDOG_CLEAR_KEY 0xA5 class WatchDog { private: static void setCallback(WATCHDOG_CALLBACK cb); static void sync(void) { while (WDT->STATUS.bit.SYNCBUSY) continue; } public: static void begin(WATCHDOG_TIMEOUT timeout, WATCHDOG_WINDOW window = WATCHDOG_WINDOW_NONE, WATCHDOG_EWOFFSET ewoffset = WATCHDOG_EWOFFSET_NONE, WATCHDOG_CALLBACK cb = 0) { if (WDT->CTRL.reg & (WDT_CTRL_ALWAYSON | WDT_CTRL_ENABLE)) return; // GCLK = 32.768KHz / (1 << (4 + 1)) = 1.024KHz GCLOCK_GEN gen = GClock::config(GCLOCK_SRC_OSCULP32K, 4, true); if (gen == GCLOCK_GEN_NONE) return; GClock::select(GCLOCK_ID_WDT, gen); GClock::control(GCLOCK_ID_WDT, true); setCallback(cb); if (cb && (ewoffset < WATCHDOG_EWOFFSET_NONE)) { NVIC_EnableIRQ(WDT_IRQn); NVIC_SetPriority(WDT_IRQn, 0); WDT->EWCTRL.reg = WDT_EWCTRL_EWOFFSET(ewoffset); WDT->INTENSET.reg = WDT_INTENSET_EW; } else { NVIC_DisableIRQ(WDT_IRQn); WDT->INTENCLR.reg = WDT_INTENCLR_EW; } WDT->CONFIG.reg = WDT_CONFIG_PER(timeout) | WDT_CONFIG_WINDOW(window < WATCHDOG_WINDOW_NONE ? window : 0); sync(); WDT->CTRL.reg = WDT_CTRL_ENABLE | (window < WATCHDOG_WINDOW_NONE ? WDT_CTRL_WEN : 0); sync(); } static void end(void) { if (WDT->CTRL.bit.ALWAYSON || !WDT->CTRL.bit.ENABLE) return; while (WDT->STATUS.bit.SYNCBUSY) continue; NVIC_DisableIRQ(WDT_IRQn); WDT->INTENCLR.reg = WDT_INTENCLR_EW; WDT->CTRL.reg = 0; sync(); GClock::control(GCLOCK_ID_WDT, false); } static void reset(void) { if (WDT->CTRL.bit.ENABLE && !WDT->STATUS.bit.SYNCBUSY) WDT->CLEAR.reg = WATCHDOG_CLEAR_KEY; } }; #endif |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 |
/* watchdog.cpp - WatchDog Library for Microchip ATSAMD21 (Cortex®-M0+) Copyright (c) 2020 Sasapea's Lab. All right reserved. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #include "watchdog.h" static WATCHDOG_CALLBACK _callback; void WDT_Handler(void) { if (WDT->INTFLAG.reg & WDT_INTFLAG_EW) { WDT->INTFLAG.reg = WDT_INTFLAG_EW; if (_callback) _callback(); } } void WatchDog::setCallback(WATCHDOG_CALLBACK cb) { _callback = cb; } |
【参照ライブラリ】
Seeeduino XIAO (ATSAMD21G18) のGCLKライブラリ (gclock.h/gclock.cpp)