Tomonori Kuroki / MuWatchdog

Fork of Watchdog by David Smart

Committer:
mutech
Date:
Mon Oct 15 12:10:15 2018 +0000
Revision:
25:4eecd15f0c38
Parent:
24:bb99754d8098
Child:
26:f7ccf62c4dd0
This provides a basic Watchdog service, and includes a startup detection to determine if the reset was caused by the WD.

Who changed what in which revision?

UserRevisionLine numberNew contents of line
mutech 11:a1611543c454 1 /// @file Watchdog.cpp provides the interface to the Watchdog module
WiredHome 2:2873f068f325 2 ///
WiredHome 2:2873f068f325 3 /// This provides basic Watchdog service for the mbed. You can configure
WiredHome 2:2873f068f325 4 /// various timeout intervals that meet your system needs. Additionally,
WiredHome 2:2873f068f325 5 /// it is possible to identify if the Watchdog was the cause of any
WiredHome 2:2873f068f325 6 /// system restart.
WiredHome 2:2873f068f325 7 ///
WiredHome 2:2873f068f325 8 /// Adapted from Simon's Watchdog code from http://mbed.org/forum/mbed/topic/508/
WiredHome 2:2873f068f325 9 ///
WiredHome 2:2873f068f325 10 /// @note Copyright © 2011 by Smartware Computing, all rights reserved.
WiredHome 2:2873f068f325 11 /// This software may be used to derive new software, as long as
WiredHome 2:2873f068f325 12 /// this copyright statement remains in the source file.
WiredHome 2:2873f068f325 13 /// @author David Smart
WiredHome 2:2873f068f325 14 ///
mutech 7:3814d72b8166 15 /// \li v2.10 - 20160914: Changed TARGET_STM by mutech, t.kuroki
mutech 7:3814d72b8166 16
WiredHome 0:7a316f14da9c 17 #include "Watchdog.h"
WiredHome 0:7a316f14da9c 18
WiredHome 5:2dad2a78ffbd 19 #if defined( TARGET_LPC1768 )
WiredHome 0:7a316f14da9c 20 /// Watchdog gets instantiated at the module level
WiredHome 0:7a316f14da9c 21 Watchdog::Watchdog() {
mutech 15:e0e4c2268558 22 _wdreset = (LPC_WDT->WDMOD >> 2) & 1; // capture the cause of the previous reset
WiredHome 0:7a316f14da9c 23 }
WiredHome 0:7a316f14da9c 24
WiredHome 0:7a316f14da9c 25 /// Load timeout value in watchdog timer and enable
WiredHome 0:7a316f14da9c 26 void Watchdog::Configure(float s) {
WiredHome 0:7a316f14da9c 27 LPC_WDT->WDCLKSEL = 0x1; // Set CLK src to PCLK
WiredHome 0:7a316f14da9c 28 uint32_t clk = SystemCoreClock / 16; // WD has a fixed /4 prescaler, PCLK default is /4
WiredHome 2:2873f068f325 29 LPC_WDT->WDTC = (uint32_t)(s * (float)clk);
WiredHome 0:7a316f14da9c 30 LPC_WDT->WDMOD = 0x3; // Enabled and Reset
WiredHome 0:7a316f14da9c 31 Service();
WiredHome 0:7a316f14da9c 32 }
WiredHome 0:7a316f14da9c 33
mutech 7:3814d72b8166 34 void Watchdog::Configure(int ms) {
mutech 7:3814d72b8166 35 LPC_WDT->WDCLKSEL = 0x1; // Set CLK src to PCLK
mutech 7:3814d72b8166 36 uint32_t clk = SystemCoreClock / 1000; //
mutech 7:3814d72b8166 37 LPC_WDT->WDTC = (ms * clk) / 16; // WD has a fixed /4 prescaler, PCLK default is /4
mutech 7:3814d72b8166 38 LPC_WDT->WDMOD = 0x3; // Enabled and Reset
mutech 7:3814d72b8166 39 Service();
mutech 7:3814d72b8166 40 }
mutech 7:3814d72b8166 41
WiredHome 0:7a316f14da9c 42 /// "Service", "kick" or "feed" the dog - reset the watchdog timer
WiredHome 0:7a316f14da9c 43 /// by writing this required bit pattern
WiredHome 0:7a316f14da9c 44 void Watchdog::Service() {
WiredHome 0:7a316f14da9c 45 LPC_WDT->WDFEED = 0xAA;
WiredHome 0:7a316f14da9c 46 LPC_WDT->WDFEED = 0x55;
WiredHome 0:7a316f14da9c 47 }
WiredHome 0:7a316f14da9c 48
WiredHome 0:7a316f14da9c 49 /// get the flag to indicate if the watchdog causes the reset
WiredHome 0:7a316f14da9c 50 bool Watchdog::WatchdogCausedReset() {
mutech 15:e0e4c2268558 51 return _wdreset;
WiredHome 0:7a316f14da9c 52 }
WiredHome 5:2dad2a78ffbd 53 #elif defined( TARGET_LPC4088 )
WiredHome 5:2dad2a78ffbd 54 // from Gesotec Gesotec
WiredHome 5:2dad2a78ffbd 55 /// Watchdog gets instantiated at the module level
WiredHome 5:2dad2a78ffbd 56 Watchdog::Watchdog() {
mutech 15:e0e4c2268558 57 _wdreset = (LPC_WDT->MOD >> 2) & 1; // capture the cause of the previous reset
WiredHome 5:2dad2a78ffbd 58 }
WiredHome 5:2dad2a78ffbd 59
WiredHome 5:2dad2a78ffbd 60 /// Load timeout value in watchdog timer and enable
WiredHome 5:2dad2a78ffbd 61 void Watchdog::Configure(float s) {
WiredHome 5:2dad2a78ffbd 62 //LPC_WDT->CLKSEL = 0x1; // Set CLK src to PCLK
WiredHome 5:2dad2a78ffbd 63 uint32_t clk = 500000 / 4; // WD has a fixed /4 prescaler, and a 500khz oscillator
WiredHome 5:2dad2a78ffbd 64 LPC_WDT->TC = (uint32_t)(s * (float)clk);
WiredHome 5:2dad2a78ffbd 65 LPC_WDT->MOD = 0x3; // Enabled and Reset
WiredHome 5:2dad2a78ffbd 66 Service();
WiredHome 5:2dad2a78ffbd 67 }
mutech 7:3814d72b8166 68
mutech 7:3814d72b8166 69 void Watchdog::Configure(int ms) {
mutech 7:3814d72b8166 70 //LPC_WDT->CLKSEL = 0x1; // Set CLK src to PCLK
mutech 7:3814d72b8166 71 uint32_t clk = 500000 / 4; // WD has a fixed /4 prescaler, and a 500khz oscillator
mutech 7:3814d72b8166 72 LPC_WDT->TC = (ms * clk) / 1000;
mutech 7:3814d72b8166 73 LPC_WDT->MOD = 0x3; // Enabled and Reset
mutech 7:3814d72b8166 74 Service();
mutech 7:3814d72b8166 75 }
mutech 7:3814d72b8166 76
WiredHome 5:2dad2a78ffbd 77 /// "Service", "kick" or "feed" the dog - reset the watchdog timer
WiredHome 5:2dad2a78ffbd 78 /// by writing this required bit pattern
WiredHome 5:2dad2a78ffbd 79 void Watchdog::Service() {
WiredHome 5:2dad2a78ffbd 80 LPC_WDT->FEED = 0xAA;
WiredHome 5:2dad2a78ffbd 81 LPC_WDT->FEED = 0x55;
WiredHome 5:2dad2a78ffbd 82 }
WiredHome 5:2dad2a78ffbd 83
WiredHome 5:2dad2a78ffbd 84 /// get the flag to indicate if the watchdog causes the reset
WiredHome 5:2dad2a78ffbd 85 bool Watchdog::WatchdogCausedReset() {
mutech 15:e0e4c2268558 86 return _wdreset;
WiredHome 5:2dad2a78ffbd 87 }
mutech 17:ccd155378a9b 88
mutech 17:ccd155378a9b 89 #elif defined(TARGET_LPC81X) || defined(TARGET_LPC82X)
mutech 18:edfbf294c9e2 90
mutech 17:ccd155378a9b 91 // from Gesotec Gesotec
mutech 17:ccd155378a9b 92 /// Watchdog gets instantiated at the module level
mutech 17:ccd155378a9b 93 Watchdog::Watchdog()
mutech 17:ccd155378a9b 94 {
mutech 17:ccd155378a9b 95 _wdreset = (LPC_WWDT->MOD >> 2) & 1; // capture the cause of the previous reset
mutech 17:ccd155378a9b 96 }
mutech 17:ccd155378a9b 97
mutech 17:ccd155378a9b 98 /// Load timeout value in watchdog timer and enable
mutech 17:ccd155378a9b 99 void Watchdog::Configure(float s)
mutech 17:ccd155378a9b 100 {
mutech 17:ccd155378a9b 101 Configure((int)(s * 1000));
mutech 17:ccd155378a9b 102 }
mutech 17:ccd155378a9b 103
mutech 19:3b172e42d8ee 104 #define WDTOSCCTRL_Val(clk, div) ((((uint32_t)(clk)) << 5) | (((div) >> 1) - 1))
mutech 19:3b172e42d8ee 105
mutech 17:ccd155378a9b 106 void Watchdog::Configure(int ms)
mutech 17:ccd155378a9b 107 {
mutech 18:edfbf294c9e2 108 #if 0
mutech 18:edfbf294c9e2 109 uint32_t clk = get_wdtclock() / 4; // WD has a fixed /4 prescaler, and a 500khz oscillator
mutech 18:edfbf294c9e2 110 LPC_WWDT->TC = (ms * clk) / 1000;
mutech 18:edfbf294c9e2 111 #else
mutech 19:3b172e42d8ee 112 LPC_SYSCON->WDTOSCCTRL = WDTOSCCTRL_Val(10, 2); // wdt_osc_clk = Fclkana/2, Fclkana = 3.5MHz
mutech 18:edfbf294c9e2 113 LPC_SYSCON->SYSAHBCLKCTRL |= (1 << 17); // Enable Clock WWDT
mutech 18:edfbf294c9e2 114 LPC_SYSCON->PDRUNCFG &= ~(1 << 6); // Enable Power WDTOSC_PD
mutech 18:edfbf294c9e2 115 uint32_t clk = ((3500000/2)/4); // COUNT = wdt_osc_clk/4
mutech 18:edfbf294c9e2 116 LPC_WWDT->TC = (ms * clk) / 1000;
mutech 18:edfbf294c9e2 117 #endif
mutech 18:edfbf294c9e2 118 LPC_WWDT->MOD = 0x3; // Enabled and Reset
mutech 18:edfbf294c9e2 119 Service();
mutech 18:edfbf294c9e2 120 }
mutech 18:edfbf294c9e2 121
mutech 18:edfbf294c9e2 122 uint32_t Watchdog::get_wdtclock()
mutech 18:edfbf294c9e2 123 {
mutech 22:3c7ea2ad3a85 124 #if 0
mutech 17:ccd155378a9b 125 uint32_t wdt_osc = 0;
mutech 18:edfbf294c9e2 126
mutech 17:ccd155378a9b 127 /* Determine clock frequency according to clock register values */
mutech 17:ccd155378a9b 128 switch ((LPC_SYSCON->WDTOSCCTRL >> 5) & 0x0F)
mutech 17:ccd155378a9b 129 {
mutech 17:ccd155378a9b 130 case 0: wdt_osc = 0; break;
mutech 18:edfbf294c9e2 131 case 1: wdt_osc = 600000; break;
mutech 18:edfbf294c9e2 132 case 2: wdt_osc = 1050000; break;
mutech 18:edfbf294c9e2 133 case 3: wdt_osc = 1400000; break;
mutech 18:edfbf294c9e2 134 case 4: wdt_osc = 1750000; break;
mutech 18:edfbf294c9e2 135 case 5: wdt_osc = 2100000; break;
mutech 18:edfbf294c9e2 136 case 6: wdt_osc = 2400000; break;
mutech 18:edfbf294c9e2 137 case 7: wdt_osc = 2700000; break;
mutech 18:edfbf294c9e2 138 case 8: wdt_osc = 3000000; break;
mutech 18:edfbf294c9e2 139 case 9: wdt_osc = 3250000; break;
mutech 18:edfbf294c9e2 140 case 10: wdt_osc = 3500000; break;
mutech 18:edfbf294c9e2 141 case 11: wdt_osc = 3750000; break;
mutech 18:edfbf294c9e2 142 case 12: wdt_osc = 4000000; break;
mutech 18:edfbf294c9e2 143 case 13: wdt_osc = 4200000; break;
mutech 18:edfbf294c9e2 144 case 14: wdt_osc = 4400000; break;
mutech 18:edfbf294c9e2 145 case 15: wdt_osc = 4600000; break;
mutech 17:ccd155378a9b 146 }
mutech 22:3c7ea2ad3a85 147 #else
mutech 22:3c7ea2ad3a85 148 const uint32_t osctab[16] =
mutech 22:3c7ea2ad3a85 149 {
mutech 22:3c7ea2ad3a85 150 0, // 0
mutech 22:3c7ea2ad3a85 151 600000, // 1
mutech 22:3c7ea2ad3a85 152 1050000, // 2
mutech 22:3c7ea2ad3a85 153 1400000, // 3
mutech 22:3c7ea2ad3a85 154 1750000, // 4
mutech 22:3c7ea2ad3a85 155 2100000, // 5
mutech 22:3c7ea2ad3a85 156 2400000, // 6
mutech 22:3c7ea2ad3a85 157 2700000, // 7
mutech 22:3c7ea2ad3a85 158 3000000, // 8
mutech 22:3c7ea2ad3a85 159 3250000, // 9
mutech 22:3c7ea2ad3a85 160 3500000, // 10
mutech 22:3c7ea2ad3a85 161 3750000, // 11
mutech 22:3c7ea2ad3a85 162 4000000, // 12
mutech 22:3c7ea2ad3a85 163 4200000, // 13
mutech 22:3c7ea2ad3a85 164 4400000, // 14
mutech 22:3c7ea2ad3a85 165 4600000 // 15
mutech 22:3c7ea2ad3a85 166 };
mutech 22:3c7ea2ad3a85 167 #endif
mutech 22:3c7ea2ad3a85 168 uint32_t wdt_osc = osctab[(LPC_SYSCON->WDTOSCCTRL >> 5) & 0x0F];
mutech 22:3c7ea2ad3a85 169
mutech 18:edfbf294c9e2 170 // wdt_osc /= ((LPC_SYSCON->WDTOSCCTRL & 0x1F) << 1) + 2;
mutech 18:edfbf294c9e2 171 return wdt_osc;
mutech 17:ccd155378a9b 172 }
mutech 17:ccd155378a9b 173
mutech 17:ccd155378a9b 174 /// "Service", "kick" or "feed" the dog - reset the watchdog timer
mutech 17:ccd155378a9b 175 /// by writing this required bit pattern
mutech 17:ccd155378a9b 176 void Watchdog::Service()
mutech 17:ccd155378a9b 177 {
mutech 17:ccd155378a9b 178 LPC_WWDT->FEED = 0xAA;
mutech 17:ccd155378a9b 179 LPC_WWDT->FEED = 0x55;
mutech 17:ccd155378a9b 180 }
mutech 17:ccd155378a9b 181
mutech 17:ccd155378a9b 182 /// get the flag to indicate if the watchdog causes the reset
mutech 17:ccd155378a9b 183 bool Watchdog::WatchdogCausedReset()
mutech 17:ccd155378a9b 184 {
mutech 17:ccd155378a9b 185 return _wdreset;
mutech 17:ccd155378a9b 186 }
mutech 17:ccd155378a9b 187
mutech 7:3814d72b8166 188 #elif defined(TARGET_STM)
mutech 7:3814d72b8166 189 Watchdog::Watchdog()
mutech 7:3814d72b8166 190 {
mutech 15:e0e4c2268558 191 _rcc_csr = RCC->CSR;
mutech 15:e0e4c2268558 192 RCC->CSR |= RCC_CSR_RMVF; // clear reset flag
WiredHome 5:2dad2a78ffbd 193 }
WiredHome 0:7a316f14da9c 194
mutech 11:a1611543c454 195 // 整数Xを含む最小のべき乗指数
mutech 11:a1611543c454 196 int Watchdog::calcExponent16bit(uint16_t v)
mutech 11:a1611543c454 197 {
mutech 11:a1611543c454 198 // return (v == 0) ? 0 : MSB16bit(v - 1) + 1;
mutech 11:a1611543c454 199 if (!v)
mutech 11:a1611543c454 200 return 0;
mutech 11:a1611543c454 201 --v;
mutech 7:3814d72b8166 202 // 最大有効ビット数(MSB:Most Significant Bit)
mutech 7:3814d72b8166 203 v |= (v >> 1);
mutech 7:3814d72b8166 204 v |= (v >> 2);
mutech 7:3814d72b8166 205 v |= (v >> 4);
mutech 7:3814d72b8166 206 v |= (v >> 8);
mutech 7:3814d72b8166 207 // return count16bit(v) - 1;
mutech 7:3814d72b8166 208 // 立っているビットの数を数える
mutech 7:3814d72b8166 209 v = (v & 0x5555) + ((v >> 1) & 0x5555);
mutech 7:3814d72b8166 210 v = (v & 0x3333) + ((v >> 2) & 0x3333);
mutech 7:3814d72b8166 211 v = (v & 0x0f0f) + ((v >> 4) & 0x0f0f);
mutech 11:a1611543c454 212 return (v & 0x00ff) + ((v >> 8) & 0x00ff);
mutech 7:3814d72b8166 213 }
mutech 7:3814d72b8166 214
mutech 24:bb99754d8098 215 #if defined(TARGET_STM32F0) || defined(TARGET_STM32F1) || defined(TARGET_STM32F3)
mutech 14:30665d9afe68 216 #define WDT_CLOCK 40000U // 40 kHz
mutech 14:30665d9afe68 217 #else
mutech 24:bb99754d8098 218 // TARGET_STM32L0/STM32L1/STM32L4/STM32F4/STM32F7
mutech 14:30665d9afe68 219 #define WDT_CLOCK 32768U // 32.768 kHz
mutech 14:30665d9afe68 220 #endif
mutech 7:3814d72b8166 221
WiredHome 5:2dad2a78ffbd 222 /// Load timeout value in watchdog timer and enable
mutech 7:3814d72b8166 223 void Watchdog::Configure(float s)
mutech 7:3814d72b8166 224 {
WiredHome 5:2dad2a78ffbd 225 // http://www.st.com/web/en/resource/technical/document/reference_manual/CD00171190.pdf
mutech 7:3814d72b8166 226
mutech 11:a1611543c454 227 // Newer Nucleo boards have 32.768 kHz crystal. Without it, the internal
mutech 7:3814d72b8166 228 // RC clock would have an average frequency of 40 kHz (variable between 30 and 60 kHz)
mutech 11:a1611543c454 229 uint32_t tick = (uint32_t)(s * WDT_CLOCK + 0.5f);
mutech 11:a1611543c454 230 // The RLR register is 12 bits and beyond that a prescaler should be used
mutech 11:a1611543c454 231 int scale = calcExponent16bit((tick + 4095) >> 12);
mutech 7:3814d72b8166 232 if (scale < 2)
mutech 7:3814d72b8166 233 scale = 2;
mutech 10:673dff2b0ee6 234 else if (scale > 8) // STM32 allows a maximum time of around 26.2 seconds for the Watchdog timer
mutech 7:3814d72b8166 235 scale = 8;
mutech 11:a1611543c454 236
mutech 11:a1611543c454 237 int residual = tick / (1 << scale); // The value for the RLR register
mutech 11:a1611543c454 238 if (residual < 1)
mutech 11:a1611543c454 239 residual = 1;
mutech 11:a1611543c454 240 else if (residual > 4096)
mutech 7:3814d72b8166 241 residual = 4096;
mutech 7:3814d72b8166 242
WiredHome 5:2dad2a78ffbd 243 IWDG->KR = 0x5555; // enable write to PR, RLR
mutech 7:3814d72b8166 244 IWDG->PR = scale - 2; // Prescaler has values of multiples of 4 (i.e. 2 ^2), page 486 Reference Manual
mutech 7:3814d72b8166 245 IWDG->RLR = residual - 1; // Init RLR
mutech 7:3814d72b8166 246 IWDG->KR = 0xAAAA; // Reload the watchdog
mutech 7:3814d72b8166 247 IWDG->KR = 0xCCCC; // Starts the WD
mutech 7:3814d72b8166 248 }
mutech 7:3814d72b8166 249
mutech 7:3814d72b8166 250 void Watchdog::Configure(int ms)
mutech 7:3814d72b8166 251 {
mutech 7:3814d72b8166 252 // http://www.st.com/web/en/resource/technical/document/reference_manual/CD00171190.pdf
mutech 7:3814d72b8166 253
mutech 11:a1611543c454 254 // Newer Nucleo boards have 32.768 kHz crystal. Without it, the internal
mutech 11:a1611543c454 255 // RC clock would have an average frequency of 40 kHz (variable between 30 and 60 kHz)
mutech 11:a1611543c454 256 // tick = (ms / (1/WDT_CLOCK))/1000;
mutech 11:a1611543c454 257 uint32_t tick = ((uint32_t)ms * WDT_CLOCK + 500U) / 1000U;
mutech 11:a1611543c454 258 // The RLR register is 12 bits and beyond that a prescaler should be used
mutech 11:a1611543c454 259 int scale = calcExponent16bit((tick + 4095) >> 12);
mutech 11:a1611543c454 260 if (scale < 2)
mutech 11:a1611543c454 261 scale = 2;
mutech 11:a1611543c454 262 else if (scale > 8) // STM32 allows a maximum time of around 26.2 seconds for the Watchdog timer
mutech 11:a1611543c454 263 scale = 8;
mutech 10:673dff2b0ee6 264
mutech 11:a1611543c454 265 int residual = tick / (1 << scale); // The value for the RLR register
mutech 11:a1611543c454 266 if (residual < 1)
mutech 7:3814d72b8166 267 residual = 1;
mutech 11:a1611543c454 268 else if (residual > 4096)
mutech 7:3814d72b8166 269 residual = 4096;
mutech 7:3814d72b8166 270
mutech 7:3814d72b8166 271 IWDG->KR = 0x5555; // enable write to PR, RLR
mutech 7:3814d72b8166 272 IWDG->PR = scale - 2; // Prescaler has values of multiples of 4 (i.e. 2 ^2), page 486 Reference Manual
mutech 7:3814d72b8166 273 IWDG->RLR = residual - 1; // Init RLR
WiredHome 5:2dad2a78ffbd 274 IWDG->KR = 0xAAAA; // Reload the watchdog
WiredHome 5:2dad2a78ffbd 275 IWDG->KR = 0xCCCC; // Starts the WD
WiredHome 5:2dad2a78ffbd 276 }
WiredHome 0:7a316f14da9c 277
WiredHome 5:2dad2a78ffbd 278 /// "Service", "kick" or "feed" the dog - reset the watchdog timer
mutech 7:3814d72b8166 279 void Watchdog::Service()
mutech 7:3814d72b8166 280 {
WiredHome 5:2dad2a78ffbd 281 IWDG->KR = 0xAAAA;
WiredHome 5:2dad2a78ffbd 282 }
WiredHome 5:2dad2a78ffbd 283
WiredHome 5:2dad2a78ffbd 284 /// get the flag to indicate if the watchdog causes the reset
mutech 7:3814d72b8166 285 bool Watchdog::WatchdogCausedReset()
mutech 7:3814d72b8166 286 {
mutech 25:4eecd15f0c38 287 #if defined(RCC_CSR_IWDGRSTF)
mutech 15:e0e4c2268558 288 return (_rcc_csr & (RCC_CSR_IWDGRSTF | RCC_CSR_WWDGRSTF)) != 0; // read the IWDGRSTF (Independent WD, not the windows WD)
mutech 25:4eecd15f0c38 289 #else
mutech 25:4eecd15f0c38 290 // for old library
mutech 25:4eecd15f0c38 291 return (_rcc_csr & (RCC_CSR_WDGRSTF | RCC_CSR_WWDGRSTF)) != 0; // read the IWDGRSTF (Independent WD, not the windows WD)
mutech 25:4eecd15f0c38 292 #endif
WiredHome 5:2dad2a78ffbd 293 }
WiredHome 5:2dad2a78ffbd 294 #endif