From cc5ca9eef6da6ef4038902032a2e4a28b97d4d29 Mon Sep 17 00:00:00 2001 From: pennam Date: Mon, 12 Jun 2023 11:42:55 +0200 Subject: [PATCH 1/3] Watchdog Timer: basic support --- .../WatchdogRefresh/WatchdogRefresh.ino | 34 ++++++++++++++ libraries/WDT/library.properties | 9 ++++ libraries/WDT/src/WDT.cpp | 45 +++++++++++++++++++ libraries/WDT/src/WDT.h | 41 +++++++++++++++++ 4 files changed, 129 insertions(+) create mode 100644 libraries/WDT/examples/WatchdogRefresh/WatchdogRefresh.ino create mode 100644 libraries/WDT/library.properties create mode 100644 libraries/WDT/src/WDT.cpp create mode 100644 libraries/WDT/src/WDT.h diff --git a/libraries/WDT/examples/WatchdogRefresh/WatchdogRefresh.ino b/libraries/WDT/examples/WatchdogRefresh/WatchdogRefresh.ino new file mode 100644 index 000000000..592944ac7 --- /dev/null +++ b/libraries/WDT/examples/WatchdogRefresh/WatchdogRefresh.ino @@ -0,0 +1,34 @@ +/* + Watchdog Refresh + + This sketch shows how to enable the watchdog and + refresh the timer to avoid resets + + Circuit: + - Portenta C33 +*/ + +#include + +void setup() { + Serial.begin(9600); + while (!Serial); + + wdt_cfg_t p_cfg; + + p_cfg.timeout = WDT_TIMEOUT_16384; + p_cfg.clock_division = WDT_CLOCK_DIVISION_8192; + p_cfg.window_start = WDT_WINDOW_START_100; + p_cfg.window_end = WDT_WINDOW_END_0; + p_cfg.reset_control = WDT_RESET_CONTROL_RESET; + p_cfg.stop_control = WDT_STOP_CONTROL_ENABLE; + + WDT.begin(p_cfg); +} + +void loop() { + Serial.println("Still Alive..."); + // Comment the line above to stop refreshing the watchdog + WDT.refresh(); + delay(1000); +} diff --git a/libraries/WDT/library.properties b/libraries/WDT/library.properties new file mode 100644 index 000000000..b0055c4e3 --- /dev/null +++ b/libraries/WDT/library.properties @@ -0,0 +1,9 @@ +name=WDT +version=0.0.1 +author=Arduino +maintainer=Arduino +sentence=Watchdog timer library for Renesas RA boards +paragraph= +category=Timing +url= +architectures=renesas diff --git a/libraries/WDT/src/WDT.cpp b/libraries/WDT/src/WDT.cpp new file mode 100644 index 000000000..c5ea1b72f --- /dev/null +++ b/libraries/WDT/src/WDT.cpp @@ -0,0 +1,45 @@ +/* + WDT.cpp + Copyright (c) 2023 Arduino SA. 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 "WDT.h" + +WDTimer::WDTimer() { } +WDTimer::~WDTimer() { } + +int WDTimer::begin(wdt_cfg_t config) +{ + if(_is_initialized) { + return FSP_SUCCESS; + } + + fsp_err_t err = R_WDT_Open(&_p_ctrl, &config); + if(FSP_SUCCESS == err ) { + R_WDT_Refresh(&_p_ctrl); + _is_initialized = true; + } + + return (int)err; +} + +void WDTimer::refresh() +{ + R_WDT_Refresh(&_p_ctrl); +} + +WDTimer WDT; diff --git a/libraries/WDT/src/WDT.h b/libraries/WDT/src/WDT.h new file mode 100644 index 000000000..7431f0b66 --- /dev/null +++ b/libraries/WDT/src/WDT.h @@ -0,0 +1,41 @@ +/* + WDT.h + Copyright (c) 2023 Arduino SA. 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 _WDTIMER_H_ +#define _WDTIMER_H_ + +#include "r_wdt.h" + +class WDTimer { + private: + bool _is_initialized; + wdt_instance_ctrl_t _p_ctrl; + + public: + WDTimer(); + ~WDTimer(); + + int begin(wdt_cfg_t config); + + void refresh(); +}; + +extern WDTimer WDT; + +#endif From 1220c31e2ee04e083661d8007b49d850b654ce39 Mon Sep 17 00:00:00 2001 From: pennam Date: Fri, 16 Jun 2023 11:02:52 +0200 Subject: [PATCH 2/3] Watchdog timer: add functions to configure timeout in ms * Fix return values * Check is initialized flag --- libraries/WDT/src/WDT.cpp | 131 +++++++++++++++++++++++++++++++++++--- libraries/WDT/src/WDT.h | 85 +++++++++++++++++++++++-- 2 files changed, 203 insertions(+), 13 deletions(-) diff --git a/libraries/WDT/src/WDT.cpp b/libraries/WDT/src/WDT.cpp index c5ea1b72f..b3d5bcf26 100644 --- a/libraries/WDT/src/WDT.cpp +++ b/libraries/WDT/src/WDT.cpp @@ -19,27 +19,142 @@ #include "WDT.h" -WDTimer::WDTimer() { } +WDTimer::WDTimer() +: _is_initialized {false} +, _p_ctrl {0} +, _timeout {0} +{ + +} + WDTimer::~WDTimer() { } int WDTimer::begin(wdt_cfg_t config) { - if(_is_initialized) { - return FSP_SUCCESS; + if (_is_initialized) { + return 1; } fsp_err_t err = R_WDT_Open(&_p_ctrl, &config); - if(FSP_SUCCESS == err ) { - R_WDT_Refresh(&_p_ctrl); - _is_initialized = true; + if (err != FSP_SUCCESS) { + return 0; } + R_WDT_Refresh(&_p_ctrl); + _is_initialized = true; - return (int)err; + return 1; } -void WDTimer::refresh() +int WDTimer::begin(uint32_t timeout_ms) { + if (_is_initialized) { + return 1; + } + + const uint8_t pr = getPrescaler(timeout_ms); + if (pr == WDT_INVALID_TIMEOUT) { + return 0; + } + + const uint8_t rl = getReload(pr, timeout_ms); + + wdt_cfg_t p_cfg; + p_cfg.timeout = (wdt_timeout_t)rl; + p_cfg.clock_division = (wdt_clock_division_t)pr; + p_cfg.window_start = WDT_WINDOW_START_100; + p_cfg.window_end = WDT_WINDOW_END_0; + p_cfg.reset_control = WDT_RESET_CONTROL_RESET; + p_cfg.stop_control = WDT_STOP_CONTROL_ENABLE; + + fsp_err_t err = R_WDT_Open(&_p_ctrl, &p_cfg); + if (err != FSP_SUCCESS) { + return 0; + } + R_WDT_Refresh(&_p_ctrl); + _is_initialized = true; + + return 1; +} + +void WDTimer::refresh() +{ + if (_is_initialized) { + R_WDT_Refresh(&_p_ctrl); + } +} + +uint32_t WDTimer::getTimeout() +{ + if (_is_initialized) { + return _timeout; + } + return 0; +} + +uint32_t WDTimer::getCounter() +{ + uint32_t count = 0; + + if (_is_initialized) { + R_WDT_CounterGet (&_p_ctrl, &count); + } + return count; +} + +uint32_t WDTimer::getTicksMs() +{ + return (R_FSP_SystemClockHzGet(FSP_PRIV_CLOCK_PCLKB) / 1000); +} + +uint32_t WDTimer::getMaxTimeout() +{ + return ((WDT_RL_VALUES::RL_16384 * WDT_PR_VALUES::PR_8192) / getTicksMs()); +} + +uint32_t WDTimer::getPrescalerMaxTimeout(WDT_PR_VALUES pr) +{ + return ((WDT_RL_VALUES::RL_16384 * pr) / getTicksMs()); +} + +uint8_t WDTimer::getPrescaler(uint32_t timeout_ms) +{ + const uint32_t max_timeout_ms = getMaxTimeout(); + + if (timeout_ms > max_timeout_ms) { + return WDT_INVALID_TIMEOUT; + } + + uint32_t pr; + for (pr = 0; pr < WDT_PR_ARRAY_SIZE; pr++) { + if (!prescaler_values[pr]) { + break; + } + + const uint32_t pr_max_timeout_ms = getPrescalerMaxTimeout(prescaler_values[pr]); + if (timeout_ms <= pr_max_timeout_ms) { + break; + } + } + + const uint32_t pr_max_timeout_ms = getPrescalerMaxTimeout(WDT_PR_VALUES::PR_128); + if (pr > WDT_CLOCK_DIVISION_64 && timeout_ms <= pr_max_timeout_ms) { + return WDT_CLOCK_DIVISION_128; + } + return pr; +} + +uint8_t WDTimer::getReload(uint8_t pr, uint32_t timeout_ms) +{ + uint32_t rl; + for (rl = 0; rl < WDT_RL_ARRAY_SIZE; rl++) { + const uint32_t pr_max_timeout_ms = (reload_values[rl] * prescaler_values[pr]) / (getTicksMs()); + if (timeout_ms <= pr_max_timeout_ms) { + _timeout = pr_max_timeout_ms; + return rl; + } + } + return rl; } WDTimer WDT; diff --git a/libraries/WDT/src/WDT.h b/libraries/WDT/src/WDT.h index 7431f0b66..cb834b2ee 100644 --- a/libraries/WDT/src/WDT.h +++ b/libraries/WDT/src/WDT.h @@ -22,18 +22,93 @@ #include "r_wdt.h" -class WDTimer { - private: - bool _is_initialized; - wdt_instance_ctrl_t _p_ctrl; +#define WDT_INVALID_TIMEOUT 255 +#define WDT_PR_ARRAY_SIZE 16 +#define WDT_RL_ARRAY_SIZE 7 +class WDTimer { public: WDTimer(); ~WDTimer(); int begin(wdt_cfg_t config); - + int begin(uint32_t timeout_ms); void refresh(); + uint32_t getTimeout(); + uint32_t getCounter(); + + private: + bool _is_initialized; + wdt_instance_ctrl_t _p_ctrl; + uint32_t _timeout; + + /* WDT prescaler values */ + enum WDT_PR_VALUES + { + PR_INVALID = 0, + PR_1 = 1, + PR_4 = 4, + PR_16 = 16, + PR_32 = 32, + PR_64 = 64, + PR_128 = 128, + PR_256 = 256, + PR_512 = 512, + PR_2048 = 2048, + PR_8192 = 8192, + }; + + /* WDT reload values */ + enum WDT_RL_VALUES + { + RL_128 = 128, + RL_512 = 512, + RL_1024 = 1024, + RL_2048 = 2048, + RL_4096 = 4096, + RL_8192 = 8192, + RL_16384 = 16384, + }; + + /* Maps to WDT clock division ratio. e_wdt_clock_division */ + const WDT_PR_VALUES prescaler_values[WDT_PR_ARRAY_SIZE] = + { + WDT_PR_VALUES::PR_1, + WDT_PR_VALUES::PR_4, + WDT_PR_VALUES::PR_16, + WDT_PR_VALUES::PR_32, + WDT_PR_VALUES::PR_64, + WDT_PR_VALUES::PR_256, + WDT_PR_VALUES::PR_512, + WDT_PR_VALUES::PR_2048, + WDT_PR_VALUES::PR_8192, + WDT_PR_VALUES::PR_INVALID, + WDT_PR_VALUES::PR_INVALID, + WDT_PR_VALUES::PR_INVALID, + WDT_PR_VALUES::PR_INVALID, + WDT_PR_VALUES::PR_INVALID, + WDT_PR_VALUES::PR_INVALID, + WDT_PR_VALUES::PR_128 + }; + + /* Maps to WDT time-out periods. e_wdt_timeout */ + const WDT_RL_VALUES reload_values[WDT_RL_ARRAY_SIZE] = + { + WDT_RL_VALUES::RL_128, + WDT_RL_VALUES::RL_512, + WDT_RL_VALUES::RL_1024, + WDT_RL_VALUES::RL_2048, + WDT_RL_VALUES::RL_4096, + WDT_RL_VALUES::RL_8192, + WDT_RL_VALUES::RL_16384 + }; + + uint32_t getTicksMs(); + uint32_t getMaxTimeout(); + uint32_t getPrescalerMaxTimeout(WDT_PR_VALUES pr); + uint8_t getPrescaler(uint32_t timeout_ms); + uint8_t getReload(uint8_t pr, uint32_t timeout_ms); + }; extern WDTimer WDT; From e18075b579e226abcde21f42316d7bf23900f41e Mon Sep 17 00:00:00 2001 From: pennam Date: Fri, 16 Jun 2023 11:12:55 +0200 Subject: [PATCH 3/3] Watchdog timer: update example --- .../WatchdogRefresh/WatchdogRefresh.ino | 56 +++++++++++++++---- 1 file changed, 44 insertions(+), 12 deletions(-) diff --git a/libraries/WDT/examples/WatchdogRefresh/WatchdogRefresh.ino b/libraries/WDT/examples/WatchdogRefresh/WatchdogRefresh.ino index 592944ac7..f7cda2fa9 100644 --- a/libraries/WDT/examples/WatchdogRefresh/WatchdogRefresh.ino +++ b/libraries/WDT/examples/WatchdogRefresh/WatchdogRefresh.ino @@ -4,31 +4,63 @@ This sketch shows how to enable the watchdog and refresh the timer to avoid resets + Watchdog intervals are limited to 7 timeout periods + the library will select the best clock divisor and timeout + according to the selected wdtInterval. + + UNO R4 min wdtInterval 1ms / max wdtInterval 5592ms + Comment out Serial.print() in the setup to make it work with + small intervals + + Portenta C33 min wdtInterval 1ms / max wdtInterval 2684ms + Circuit: - Portenta C33 + - UNO R4 */ #include +const long ledInterval = 1000; +unsigned long ledMillis = 0; +bool ledState = true; +const long wdtInterval = 2684; +unsigned long wdtMillis = 0; + void setup() { Serial.begin(9600); while (!Serial); - wdt_cfg_t p_cfg; + pinMode(LED_BUILTIN, OUTPUT); - p_cfg.timeout = WDT_TIMEOUT_16384; - p_cfg.clock_division = WDT_CLOCK_DIVISION_8192; - p_cfg.window_start = WDT_WINDOW_START_100; - p_cfg.window_end = WDT_WINDOW_END_0; - p_cfg.reset_control = WDT_RESET_CONTROL_RESET; - p_cfg.stop_control = WDT_STOP_CONTROL_ENABLE; + if(wdtInterval < 1) { + Serial.println("Invalid watchdog interval"); + while(1){} + } - WDT.begin(p_cfg); + if(WDT.begin(wdtInterval)) { + Serial.print("WDT interval: "); + WDT.refresh(); + Serial.print(WDT.getTimeout()); + WDT.refresh(); + Serial.println(" ms"); + WDT.refresh(); + } else { + Serial.println("Error initializing watchdog"); + while(1){} + } } void loop() { - Serial.println("Still Alive..."); - // Comment the line above to stop refreshing the watchdog - WDT.refresh(); - delay(1000); + if(millis() - ledMillis >= ledInterval) { + digitalWrite(LED_BUILTIN, ledState); + ledState = !ledState; + ledMillis = millis(); + } + + if(millis() - wdtMillis >= wdtInterval - 1) { + WDT.refresh(); // Comment this line to stop refreshing the watchdog + wdtMillis = millis(); + } + }