Modified version of the Watchdog library with improved support for STM32
Dependents: LightSaber iot_water_monitor_v2
Fork of Watchdog by
Watchdog.cpp@9:84f7c088c261, 2015-11-11 (annotated)
- Committer:
- salarian
- Date:
- Wed Nov 11 16:05:42 2015 +0000
- Revision:
- 9:84f7c088c261
- Parent:
- 8:3c7d083f26b5
Refactored the STM32 bit variant of the functions and set the default clock to 32.768 kHz (crystal oscillator)
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
WiredHome | 2:2873f068f325 | 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 | /// |
WiredHome | 0:7a316f14da9c | 15 | #include "mbed.h" |
WiredHome | 0:7a316f14da9c | 16 | #include "Watchdog.h" |
WiredHome | 0:7a316f14da9c | 17 | |
WiredHome | 5:2dad2a78ffbd | 18 | #if defined( TARGET_LPC1768 ) |
WiredHome | 0:7a316f14da9c | 19 | /// Watchdog gets instantiated at the module level |
WiredHome | 0:7a316f14da9c | 20 | Watchdog::Watchdog() { |
WiredHome | 2:2873f068f325 | 21 | wdreset = (LPC_WDT->WDMOD >> 2) & 1; // capture the cause of the previous reset |
WiredHome | 0:7a316f14da9c | 22 | } |
WiredHome | 0:7a316f14da9c | 23 | |
WiredHome | 0:7a316f14da9c | 24 | /// Load timeout value in watchdog timer and enable |
WiredHome | 0:7a316f14da9c | 25 | void Watchdog::Configure(float s) { |
WiredHome | 0:7a316f14da9c | 26 | LPC_WDT->WDCLKSEL = 0x1; // Set CLK src to PCLK |
WiredHome | 0:7a316f14da9c | 27 | uint32_t clk = SystemCoreClock / 16; // WD has a fixed /4 prescaler, PCLK default is /4 |
WiredHome | 2:2873f068f325 | 28 | LPC_WDT->WDTC = (uint32_t)(s * (float)clk); |
WiredHome | 0:7a316f14da9c | 29 | LPC_WDT->WDMOD = 0x3; // Enabled and Reset |
WiredHome | 0:7a316f14da9c | 30 | Service(); |
WiredHome | 0:7a316f14da9c | 31 | } |
WiredHome | 0:7a316f14da9c | 32 | |
WiredHome | 0:7a316f14da9c | 33 | /// "Service", "kick" or "feed" the dog - reset the watchdog timer |
WiredHome | 0:7a316f14da9c | 34 | /// by writing this required bit pattern |
WiredHome | 0:7a316f14da9c | 35 | void Watchdog::Service() { |
WiredHome | 0:7a316f14da9c | 36 | LPC_WDT->WDFEED = 0xAA; |
WiredHome | 0:7a316f14da9c | 37 | LPC_WDT->WDFEED = 0x55; |
WiredHome | 0:7a316f14da9c | 38 | } |
WiredHome | 0:7a316f14da9c | 39 | |
WiredHome | 0:7a316f14da9c | 40 | /// get the flag to indicate if the watchdog causes the reset |
WiredHome | 0:7a316f14da9c | 41 | bool Watchdog::WatchdogCausedReset() { |
WiredHome | 0:7a316f14da9c | 42 | return wdreset; |
WiredHome | 0:7a316f14da9c | 43 | } |
WiredHome | 5:2dad2a78ffbd | 44 | #elif defined( TARGET_LPC4088 ) |
WiredHome | 5:2dad2a78ffbd | 45 | // from Gesotec Gesotec |
WiredHome | 5:2dad2a78ffbd | 46 | /// Watchdog gets instantiated at the module level |
WiredHome | 5:2dad2a78ffbd | 47 | Watchdog::Watchdog() { |
WiredHome | 5:2dad2a78ffbd | 48 | wdreset = (LPC_WDT->MOD >> 2) & 1; // capture the cause of the previous reset |
WiredHome | 5:2dad2a78ffbd | 49 | } |
WiredHome | 5:2dad2a78ffbd | 50 | |
WiredHome | 5:2dad2a78ffbd | 51 | /// Load timeout value in watchdog timer and enable |
WiredHome | 5:2dad2a78ffbd | 52 | void Watchdog::Configure(float s) { |
WiredHome | 5:2dad2a78ffbd | 53 | //LPC_WDT->CLKSEL = 0x1; // Set CLK src to PCLK |
WiredHome | 5:2dad2a78ffbd | 54 | uint32_t clk = 500000 / 4; // WD has a fixed /4 prescaler, and a 500khz oscillator |
WiredHome | 5:2dad2a78ffbd | 55 | LPC_WDT->TC = (uint32_t)(s * (float)clk); |
WiredHome | 5:2dad2a78ffbd | 56 | LPC_WDT->MOD = 0x3; // Enabled and Reset |
WiredHome | 5:2dad2a78ffbd | 57 | Service(); |
WiredHome | 5:2dad2a78ffbd | 58 | } |
WiredHome | 5:2dad2a78ffbd | 59 | |
WiredHome | 5:2dad2a78ffbd | 60 | /// "Service", "kick" or "feed" the dog - reset the watchdog timer |
WiredHome | 5:2dad2a78ffbd | 61 | /// by writing this required bit pattern |
WiredHome | 5:2dad2a78ffbd | 62 | void Watchdog::Service() { |
WiredHome | 5:2dad2a78ffbd | 63 | LPC_WDT->FEED = 0xAA; |
WiredHome | 5:2dad2a78ffbd | 64 | LPC_WDT->FEED = 0x55; |
WiredHome | 5:2dad2a78ffbd | 65 | } |
WiredHome | 5:2dad2a78ffbd | 66 | |
WiredHome | 5:2dad2a78ffbd | 67 | /// get the flag to indicate if the watchdog causes the reset |
WiredHome | 5:2dad2a78ffbd | 68 | bool Watchdog::WatchdogCausedReset() { |
WiredHome | 5:2dad2a78ffbd | 69 | return wdreset; |
WiredHome | 5:2dad2a78ffbd | 70 | } |
WiredHome | 5:2dad2a78ffbd | 71 | #elif defined( TARGET_STM ) |
WiredHome | 5:2dad2a78ffbd | 72 | // Derived from Chau Vo |
WiredHome | 5:2dad2a78ffbd | 73 | /// Watchdog gets instantiated at the module level |
WiredHome | 5:2dad2a78ffbd | 74 | Watchdog::Watchdog() { |
WiredHome | 5:2dad2a78ffbd | 75 | wdreset = (RCC->CSR & (1<<29)) ? true : false; // read the IWDGRSTF (Independent WD, not the windows WD) |
WiredHome | 5:2dad2a78ffbd | 76 | } |
WiredHome | 0:7a316f14da9c | 77 | |
salarian | 7:8912bb017956 | 78 | // Compute the log2 of an integer. This is the simplest algorithm but probably is a bit slow. |
salarian | 9:84f7c088c261 | 79 | int Watchdog::log2(unsigned v) |
salarian | 7:8912bb017956 | 80 | { |
salarian | 7:8912bb017956 | 81 | unsigned r = 0; |
salarian | 7:8912bb017956 | 82 | |
salarian | 7:8912bb017956 | 83 | while (v >>= 1) |
salarian | 7:8912bb017956 | 84 | r++; |
salarian | 7:8912bb017956 | 85 | |
salarian | 7:8912bb017956 | 86 | return r; |
salarian | 7:8912bb017956 | 87 | } |
salarian | 7:8912bb017956 | 88 | |
salarian | 7:8912bb017956 | 89 | |
WiredHome | 5:2dad2a78ffbd | 90 | /// Load timeout value in watchdog timer and enable |
salarian | 7:8912bb017956 | 91 | void Watchdog::Configure(float s) { |
WiredHome | 5:2dad2a78ffbd | 92 | // http://www.st.com/web/en/resource/technical/document/reference_manual/CD00171190.pdf |
salarian | 7:8912bb017956 | 93 | |
salarian | 9:84f7c088c261 | 94 | s = s * 32768; // Newer Nucleo boards have 32.768 kHz crystal. Without it, the internal |
salarian | 9:84f7c088c261 | 95 | // RC clock would have an average frequency of 40 kHz (variable between 30 and 60 kHz) |
salarian | 9:84f7c088c261 | 96 | |
salarian | 7:8912bb017956 | 97 | int scale = 1 + log2(s / 4096); // The RLR register is 12 bits and beyond that a prescaler should be used |
salarian | 7:8912bb017956 | 98 | int residual = s / (1 << scale); // The value for the RLR register |
salarian | 7:8912bb017956 | 99 | |
salarian | 8:3c7d083f26b5 | 100 | if (scale > 8) { //STM32 allows a maximum time of around 26.2 seconds for the Watchdog timer |
salarian | 8:3c7d083f26b5 | 101 | scale = 8; |
salarian | 8:3c7d083f26b5 | 102 | residual = 0xFFF; |
salarian | 8:3c7d083f26b5 | 103 | } |
salarian | 9:84f7c088c261 | 104 | |
WiredHome | 5:2dad2a78ffbd | 105 | IWDG->KR = 0x5555; // enable write to PR, RLR |
salarian | 7:8912bb017956 | 106 | IWDG->PR = scale - 2; // Prescaler has values of multiples of 4 (i.e. 2 ^2), page 486 Reference Manual |
salarian | 7:8912bb017956 | 107 | IWDG->RLR = residual; // Init RLR |
WiredHome | 5:2dad2a78ffbd | 108 | IWDG->KR = 0xAAAA; // Reload the watchdog |
WiredHome | 5:2dad2a78ffbd | 109 | IWDG->KR = 0xCCCC; // Starts the WD |
WiredHome | 5:2dad2a78ffbd | 110 | } |
WiredHome | 0:7a316f14da9c | 111 | |
WiredHome | 5:2dad2a78ffbd | 112 | /// "Service", "kick" or "feed" the dog - reset the watchdog timer |
WiredHome | 5:2dad2a78ffbd | 113 | void Watchdog::Service() { |
WiredHome | 5:2dad2a78ffbd | 114 | IWDG->KR = 0xAAAA; |
WiredHome | 5:2dad2a78ffbd | 115 | } |
WiredHome | 5:2dad2a78ffbd | 116 | |
WiredHome | 5:2dad2a78ffbd | 117 | /// get the flag to indicate if the watchdog causes the reset |
WiredHome | 5:2dad2a78ffbd | 118 | bool Watchdog::WatchdogCausedReset() { |
WiredHome | 5:2dad2a78ffbd | 119 | if (wdreset) { |
WiredHome | 5:2dad2a78ffbd | 120 | RCC->CSR |= (1<<24); // clear reset flag |
WiredHome | 5:2dad2a78ffbd | 121 | } |
WiredHome | 5:2dad2a78ffbd | 122 | return wdreset; |
WiredHome | 5:2dad2a78ffbd | 123 | } |
WiredHome | 5:2dad2a78ffbd | 124 | #endif |