diff --git a/cores/arduino/main.cpp b/cores/arduino/main.cpp index 741f041d0a..e6b1470f1f 100644 --- a/cores/arduino/main.cpp +++ b/cores/arduino/main.cpp @@ -34,14 +34,10 @@ void initVariant() { } #ifdef NVIC_PRIORITYGROUP_4 HAL_NVIC_SetPriorityGrouping(NVIC_PRIORITYGROUP_4); #endif -#if (__CORTEX_M == 0x07U) +#if (__CORTEX_M == 0x07U) && !defined(UNUSED_ID_CACHE) // Defined in CMSIS core_cm7.h -#ifndef I_CACHE_DISABLED SCB_EnableICache(); -#endif -#ifndef D_CACHE_DISABLED SCB_EnableDCache(); -#endif #endif init(); diff --git a/cores/arduino/stm32/timer.c b/cores/arduino/stm32/timer.c index dff17f6a33..4b8a4e7459 100644 --- a/cores/arduino/stm32/timer.c +++ b/cores/arduino/stm32/timer.c @@ -846,7 +846,7 @@ void HAL_TIM_OC_DelayElapsedCallback(TIM_HandleTypeDef *htim) return; break; } - obj->irqHandleOC(obj, channel); + obj->irqHandleOC(obj, channel); } } diff --git a/libraries/Watchdog/README.md b/libraries/Watchdog/README.md new file mode 100644 index 0000000000..e999f570d1 --- /dev/null +++ b/libraries/Watchdog/README.md @@ -0,0 +1,81 @@ +## **Watchdog Library V1.0** for Arduino + +**Written by:** _Venelin Efremov_. + +### **What is the Watchdog library.** + +Th Watchdog library provides an interface to the independent watchdog module (IWDG) inside STM32 chips. +The IWDG module is used in production systems to generate a reset signal to the CPU in case some +catastrophic event in causes the software to become "stuck" or unresponsive. + +The IWDG module contains a count-down timer. The module would generate a reset condition when the timer reaches zero. In normal operation mode the software running on the CPU would reload the timer periodically to +prevent the reset condition from happening. However if a software bug or other error causes the CPU to execute a different code path for too long, the reload would not happen and the IWDG module would reset the CPU. + +### **How to use it** +The Watchdog library is included with the STM32 core download. To add its functionality to your sketch you'll need to reference the library header file. You do this by adding an include directive to the top of your sketch. + +```Arduino +#include + +void setup() { + ... + // Initialize the IWDG with 4 seconds timeout. + // This would cause a CPU reset if the IWDG timer + // is not reloaded in approximately 4 seconds. + watchdog_init(4000); +} + +void loop() { + ...your code here... + // make sure the code in this loop is executed in + // less than 2 seconds to leave 50% headroom for + // the timer reload. + watchdog_reset(); +} + +``` + +### **Library functions** + +#### **`watchdog_init(uint16_t timeout_ms)`** + +The `watchdog_init()` function would initialize the IWDG hardware block. + +The timeout_ms parameter would set the timer reset timeout. When the +timer reaches zero the hardware block would generate a reset signal +for the CPU. + +When specifying timeout value plan to refresh the timer at least twice +as often. The `watchdog_reset()` operation is not expensive. + +The downside of slecting a very large timeout value is that your system +may be left in a "stuck" state for too long, before the reset is +generated. + +Valid timeout values are between 1ms and 32,768ms (~32.8 seconds). For +values above 4095 the timeout paramater starts to loose precision: + + | timeout value range | timeout value precision | + | ------------------- |:-----------------------:| + | 1 - 4096 | 1ms + | 4097 - 8192 | 2ms + | 8193 - 16384 | 4ms + | 16385 - 32768 | 8ms + +Calling the `watchdog_init()` method with value outside of the valid range +would return without initializing the watchdog timer. + +**WARNING:** +*Once started the watchdog timer can not be stopped. If you are +planning to debug the live system, the watchdog timer may cause the +system to be reset while you are stopped in the debugger. Also consider +the watchdog timer implications if you are designing a system which puts +the CPU in sleep mode.* + +#### **`watchdog_reset()`** + +The `watchdog_reset()` function would reset the watchdog timer. + +Once you have initialized the watchdog you **HAVE** to call `watchdog_reset()` +periodically to prevent the CPU being reset. + diff --git a/libraries/Watchdog/Watchdog.cpp b/libraries/Watchdog/Watchdog.cpp new file mode 100644 index 0000000000..31f01635f7 --- /dev/null +++ b/libraries/Watchdog/Watchdog.cpp @@ -0,0 +1,34 @@ +#include "Watchdog.h" + +static IWDG_HandleTypeDef hiwdg; + +void watchdog_init(uint16_t timeout_ms) { + if (timeout_ms == 0 || timeout_ms > 32768) { + return; + } + hiwdg.Instance = IWDG; + // Compute the prescaler value. Start with 32 which gives 1ms precision. + hiwdg.Init.Prescaler = IWDG_PRESCALER_32; + timeout_ms--; + if (timeout_ms > 4095) { + // 2ms precision + hiwdg.Init.Prescaler = IWDG_PRESCALER_64; + timeout_ms >>= 1; + } + if (timeout_ms > 4095) { + // 4ms precision + hiwdg.Init.Prescaler = IWDG_PRESCALER_128; + timeout_ms >>= 1; + } + if (timeout_ms > 4095) { + // 8ms precision + hiwdg.Init.Prescaler = IWDG_PRESCALER_256; + timeout_ms >>= 1; + } + hiwdg.Init.Reload = timeout_ms; + HAL_IWDG_Init(&hiwdg); +} + +void watchdog_reset() { + HAL_IWDG_Refresh(&hiwdg); +} diff --git a/libraries/Watchdog/Watchdog.h b/libraries/Watchdog/Watchdog.h new file mode 100644 index 0000000000..7a616b2f2e --- /dev/null +++ b/libraries/Watchdog/Watchdog.h @@ -0,0 +1,66 @@ +#ifndef __WATCHDOG_STM32_H__ +#define __WATCHDOG_STM32_H__ + +#include "Arduino.h" +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * To enable the IWDG HAL component used by this library you must add a + * file named build_opt.h to your sketch with the following content: + * + * -DHAL_IWDG_MODULE_ENABLED + * + * Include the dash (-) in front of DHAL_IWDG_MODULE_ENABLED + */ + +/* + * The watchdog_init function would initialize the IWDG hardware block. + * + * The timeout_ms parameter would set the timer reset timeout. When the + * timer reaches zero the hardware block would generate a reset signal + * for the CPU. + * + * When specifying timeout value plan to refresh the timer at least twice + * as often. The reset operation is not very expensive. + * + * The downside of slecting a very large timeout value is that your system + * may be left in a "stuck" state for too long, before the reset is + * generated. + * + * Valid timeout values are between 1ms and 32,768ms (~32.8 seconds). For + * values above 4095 the timeout paramater starts to loose precision: + * + * timeout value range | timeout value precision + * 00001-04096 | 1ms + * 04097-08192 | 2ms + * 08193-16384 | 4ms + * 16385-32768 | 8ms + * + * Calling the watchdog_init method with value outside of the valid range + * would return without initializing the watchdog timer. + * + * WARNING: Once started the watchdog timer can not be stopped. If you are + * planning to debug the live system, the watchdog timer may cause the + * system to be reset while you are stopped in the debugger. Also consider + * the watchdog timer implications if you are designing a system which puts + * the CPU in sleep mode. + * + */ +void watchdog_init(uint16_t timeout_ms); + +/* + * The watchdog_reset() function would reset the watchdog timer. Once you + * have initialized the watchdog you HAVE to call watchdog_reset() + * periodically to prevent the CPU being reset. + */ +void watchdog_reset(); + +#ifdef __cplusplus +} +#endif + +#endif // __WATCHDOG_STM32_H__ diff --git a/libraries/Watchdog/examples/Button/Button.ino b/libraries/Watchdog/examples/Button/Button.ino new file mode 100644 index 0000000000..f13a1d20be --- /dev/null +++ b/libraries/Watchdog/examples/Button/Button.ino @@ -0,0 +1,55 @@ +/* + Watchdog + Button + + This example code is in the public domain. + + The code demonstrates the use of a watchdog timer. The watchdog timer is + initialized with timeout of 10 seconds. Every time the button is pressed, + the watchdog timer is reset. If left unattended the system would reset + itself about every 10 seconds. + + You would have to keep pressing the button frequently (< 10 seoncds apart) + to prevent the system from reseting itself. + + You would recongnize the reset condition when the LED blinks rapidly a + few times. + + This is not a practical example, in real code you would reset the watchdog + timer in the main loop without requiring user input. + + The code is modified version of the code from: + http://www.arduino.cc/en/Tutorial/Button +*/ + +#include + +const int buttonPin = USER_BTN; +const int ledPin = LED_BUILTIN; + +void setup() { + pinMode(ledPin, OUTPUT); + pinMode(buttonPin, INPUT); + + // Blink the LED to indicate reset. + for(uint8_t idx = 0; idx < 5; idx++) { + digitalWrite(ledPin, HIGH); + delay(100); + digitalWrite(ledPin, LOW); + delay(100); + } + // Init the watchdog timer with 10 seconds timeout + watchdog_init(10000); +} + +void loop() { + // read the state of the pushbutton value: + int buttonState = digitalRead(buttonPin); + + if (buttonState == HIGH) { + digitalWrite(ledPin, HIGH); + } else { + digitalWrite(ledPin, LOW); + // Reset the watchdog only when the button is pressed. + watchdog_reset(); + } +} diff --git a/libraries/Watchdog/examples/Button/build_opt.h b/libraries/Watchdog/examples/Button/build_opt.h new file mode 100644 index 0000000000..911022e87a --- /dev/null +++ b/libraries/Watchdog/examples/Button/build_opt.h @@ -0,0 +1 @@ +-DHAL_IWDG_MODULE_ENABLED diff --git a/libraries/Watchdog/keywords.txt b/libraries/Watchdog/keywords.txt new file mode 100644 index 0000000000..0d24219152 --- /dev/null +++ b/libraries/Watchdog/keywords.txt @@ -0,0 +1,20 @@ +####################################### +# Syntax Coloring Map For Watchdog +####################################### + +####################################### +# Datatypes (KEYWORD1) +####################################### + + +####################################### +# Methods and Functions (KEYWORD2) +####################################### + +watchdog_init KEYWORD2 +watchdog_reset KEYWORD2 + +####################################### +# Constants (LITERAL1) +####################################### + diff --git a/libraries/Watchdog/library.properties b/libraries/Watchdog/library.properties new file mode 100644 index 0000000000..ada12a745a --- /dev/null +++ b/libraries/Watchdog/library.properties @@ -0,0 +1,9 @@ +name=Watchdog +version=1.0 +author=Arduino, Venelin Efremov +maintainer=stm32duino +sentence=Enables support for independent watchdog hardware on STM32 processors. +paragraph=Independent watchdog (IWDG) is a hardware timer on the chip which would generate a reset condition if the times is not reloaded withing the specified time. It is genrally used in production systems to reset the system if the CPU becomes "stuck". +category=Timing +url= +architectures=stm32 diff --git a/variants/DISCO_F746NG/variant.cpp b/variants/DISCO_F746NG/variant.cpp index 5f98190d2a..d5f582cf16 100644 --- a/variants/DISCO_F746NG/variant.cpp +++ b/variants/DISCO_F746NG/variant.cpp @@ -129,14 +129,14 @@ WEAK void SystemClock_Config(void) PeriphClkInitStruct.PeriphClockSelection = RCC_PERIPHCLK_LTDC|RCC_PERIPHCLK_USART1 |RCC_PERIPHCLK_CLK48; - PeriphClkInitStruct.PLLSAI.PLLSAIN = 192; - PeriphClkInitStruct.PLLSAI.PLLSAIR = 5; + PeriphClkInitStruct.PLLSAI.PLLSAIN = 100; + PeriphClkInitStruct.PLLSAI.PLLSAIR = 2; PeriphClkInitStruct.PLLSAI.PLLSAIQ = 2; - PeriphClkInitStruct.PLLSAI.PLLSAIP = RCC_PLLSAIP_DIV4; + PeriphClkInitStruct.PLLSAI.PLLSAIP = RCC_PLLSAIP_DIV2; PeriphClkInitStruct.PLLSAIDivQ = 1; PeriphClkInitStruct.PLLSAIDivR = RCC_PLLSAIDIVR_4; PeriphClkInitStruct.Usart1ClockSelection = RCC_USART1CLKSOURCE_PCLK2; - PeriphClkInitStruct.Clk48ClockSelection = RCC_CLK48SOURCE_PLLSAIP; + PeriphClkInitStruct.Clk48ClockSelection = RCC_CLK48SOURCE_PLL; if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInitStruct) != HAL_OK) { _Error_Handler(__FILE__, __LINE__);