diff --git a/libraries/WDT/examples/WatchdogRefresh/WatchdogRefresh.ino b/libraries/WDT/examples/WatchdogRefresh/WatchdogRefresh.ino new file mode 100644 index 000000000..f7cda2fa9 --- /dev/null +++ b/libraries/WDT/examples/WatchdogRefresh/WatchdogRefresh.ino @@ -0,0 +1,66 @@ +/* + Watchdog Refresh + + 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); + + pinMode(LED_BUILTIN, OUTPUT); + + if(wdtInterval < 1) { + Serial.println("Invalid watchdog interval"); + while(1){} + } + + 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() { + 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(); + } + +} 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..b3d5bcf26 --- /dev/null +++ b/libraries/WDT/src/WDT.cpp @@ -0,0 +1,160 @@ +/* + 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() +: _is_initialized {false} +, _p_ctrl {0} +, _timeout {0} +{ + +} + +WDTimer::~WDTimer() { } + +int WDTimer::begin(wdt_cfg_t config) +{ + if (_is_initialized) { + return 1; + } + + fsp_err_t err = R_WDT_Open(&_p_ctrl, &config); + if (err != FSP_SUCCESS) { + return 0; + } + R_WDT_Refresh(&_p_ctrl); + _is_initialized = true; + + return 1; +} + +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 new file mode 100644 index 000000000..cb834b2ee --- /dev/null +++ b/libraries/WDT/src/WDT.h @@ -0,0 +1,116 @@ +/* + 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" + +#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; + +#endif