From 1583929f9a8756aeb5537a19e396ad6e0009ea58 Mon Sep 17 00:00:00 2001 From: Steven Cartmell Date: Tue, 14 Nov 2017 13:02:02 +0000 Subject: [PATCH 01/62] Add Watchdog HAL API specification headers HAL watchdog functionality will be implemented as two separate APIs. The reset reason API allows a user to detect the last system reset reason to identify if a Watchdog was triggered. The Watchdog API allows configuring and updating Watchdog timers on all boards. This commit defines the headers. --- hal/reset_reason_api.h | 71 ++++++++++++++++++ hal/watchdog_api.h | 167 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 238 insertions(+) create mode 100644 hal/reset_reason_api.h create mode 100644 hal/watchdog_api.h diff --git a/hal/reset_reason_api.h b/hal/reset_reason_api.h new file mode 100644 index 00000000000..8c5c3b7c75f --- /dev/null +++ b/hal/reset_reason_api.h @@ -0,0 +1,71 @@ +/** \addtogroup hal */ +/** @{*/ +/* mbed Microcontroller Library + * Copyright (c) 2017 ARM Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef MBED_RESET_REASON_API_H +#define MBED_RESET_REASON_API_H + +#if DEVICE_RESET_REASON + +#ifdef __cplusplus +extern "C" { +#endif + +typedef enum { + RESET_REASON_POWER_ON = (1 << 0), /**< Set when power is initially applied to the board. The power-on-reset circuit causes a POWER_ON reset when this occurs */ + RESET_REASON_PIN_RESET = (1 << 1), /**< Set when a reset is triggered by the hardware pin on the board */ + RESET_REASON_BROWN_OUT = (1 << 2), /**< Triggered when the voltage drops below the low voltage detect (LVD) threshold the system will be held in a reset until the voltage rises above the threshold */ + RESET_REASON_SOFTWARE = (1 << 3), /**< Set during software reset, typically triggered by writing the SYSRESETREQ bit in the Application Interrupt and Reset Control register */ + RESET_REASON_WATCHDOG = (1 << 4), /**< Set when a running watchdog timer fails to be refreshed */ + RESET_REASON_LOCKUP = (1 << 5), /**< Set when the core is locked because of an unrecoverable exception */ + RESET_REASON_MULTIPLE = (1 << 6), /**< Set if multiple reset reasons are set within the board. Occurs when the reset reason registers aren't cleared between resets */ + RESET_REASON_PLATFORM = (1 << 7), /**< Platform specific reset reason not captured in this enum */ + RESET_REASON_UNKNOWN = (1 << 8) /**< Unknown or unreadable reset reason **/ +} reset_reason_t; + +/** + * Fetch the reset reason for the last system reset + * + * Note: Some platforms contain reset reason registers that persist through + * system resets. If the registers haven't been cleared before calling this + * function multiple reasons may be set within the registers. If multiple reset + * reasons are detected this function will return RESET_REASON_MULTIPLE. + * + * @return enum containing the last reset reason for the board. + */ + reset_reason_t hal_reset_reason_get(void); + + /** + * Clear the reset reason from registers + * + * Reset the value of the reset status registers, the reset reason will persist + * between system resets on certain platforms so the registers should be cleared + * before the system resets. Failing to do so may make it difficult to determine + * the cause of any subsequent system resets. + */ + void hal_reset_reason_clear(void); + +/**@}*/ + +#ifdef __cplusplus +} +#endif + +#endif // DEVICE_RESET_REASON + +#endif // MBED_RESET_REASON_API_H + +/** @}*/ diff --git a/hal/watchdog_api.h b/hal/watchdog_api.h new file mode 100644 index 00000000000..d78af01afca --- /dev/null +++ b/hal/watchdog_api.h @@ -0,0 +1,167 @@ +/** \addtogroup hal */ +/** @{*/ +/* mbed Microcontroller Library + * Copyright (c) 2017 ARM Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef MBED_WATCHDOG_API_H +#define MBED_WATCHDOG_API_H + +#if DEVICE_WATCHDOG + +#include +#include + +/** \file watchdog_api.h + * + * This module provides platform independent access to the system watchdog timer + * which is an embedded peripheral that will reset the system in the case of + * system failures or malfunctions. + * + * The watchdog timer initialises a system timer with a time period specified in + * the configuration. This timer counts down and triggers a system reset when it + * wraps. To prevent the system reset the timer must be continually + * kicked/refreshed by calling hal_watchdog_kick which will reset the countdown + * to the user specified reset value. + * + * The watchdog timer supports a second mode of operation called windowed mode. + * When configured in this mode by setting enable_window to true, the timer + * watchdog will enable a restriction on the kick. If the watchdog timer too + * soon after it has last been refreshed a system reset occurs. The earliest + * time in milliseconds the timer can be kicked without triggering a reset is + * specified by window_ms. + * + */ + +typedef struct +{ + /** + * Refresh value for the watchdog in milliseconds. The maximum value of this + * setting is platform dependent, to find the maximum value for the current + * platform call hal_watchdog_get_max_timeout(void) + */ + uint32_t timeout_ms; + /** + * Configures the watchdog for windowed mode of operation instead of running + * the independent watchdog. In this mode a restriction is placed on the + * time period in which the watchdog can be refreshed/kicked. If the + * watchdog is kicked too soon after it has last been refreshed the system + * will be reset. The period of time in which the reset will be triggered is + * defined by window_ms. This value is false by default. + */ + bool enable_window; + /** + * Specifies the time window for the watchdog window in milliseconds. If the + * watchdog is configured to run in windowed mode kicking the watchdog less + * than this many milliseconds after it has last been kicked will trigger a + * system reset. This value must be less than timeout_ms. + */ + uint32_t window_ms; + /** + * Configures the watchdog timer to run while the core is in sleep mode. By + * default when the system is put into the sleep the watchdog timer is paused. + * Enabling this setting causes the timer to countdown during this time. This + * flag is disabled by default. + */ + bool enable_sleep; +} watchdog_config_t; + + +typedef enum { + WATCHDOG_STATUS_OK, + WATCHDOG_STATUS_NOT_SUPPORTED, + WATCHDOG_STATUS_INVALID_ARGUMENT +} watchdog_status_t; + +#ifdef __cplusplus + extern "C" { +#endif + +/** Initialise and start a watchdog timer with the given configuration. + * + * If the watchdog timer is configured and started successfully this + * function will return WATCHDOG_STATUS_OK. + * + * If the enable_window is set but windowed mode is not supported by the + * platform the function will return WATCHDOG_STATUS_NOT_SUPPORTED. + * + * If the timeout specified is outside the range supported by the platform, + * or if the window period is greater than the timeout period it will return + * WATCHDOG_STATUS_INVALID_ARGUMENT. + * + * @param[in] config Configuration settings for the watchdog timer + * + * @return WATCHDOG_STATUS_OK if the watchdog is configured correctly and + * has started. Otherwise a status indicating the fault. + */ +watchdog_status_t hal_watchdog_init(const watchdog_config_t *config); + +/** Refreshes the watchdog timer. + * + * This function should be called periodically before the watchdog times out. + * Otherwise, the system is reset. + * + * If using the windowed operation mode this function must be called within the + * configured timeout window. If the function is called before the window is + * reached the system is reset. + * + * If a watchdog is not currently running this function does nothing + */ +void hal_watchdog_kick(void); + +/** Stops the watchdog timer + * + * Calling this function will attempt to disable any currently running watchdog + * timers if supported by the current platform + * + * @return Returns WATCHDOG_STATUS_OK if the watchdog timer was succesfully + * stopped, or if the timer was never started. Returns + * WATCHDOG_STATUS_NOT_SUPPORTED if the watchdog cannot be disabled on + * the current platform. + */ +watchdog_status_t hal_watchdog_stop(void); + +/** Get the watchdog timer refresh value + * + * This function returns the configured refresh timeout of the watchdog timer. + * + * @return Reload value for the watchdog timer in milliseconds. + */ +uint32_t hal_watchdog_get_reload_value(void); + +/** Checks if the last system reset was caused by a watchdog timer. + * + * @return True if last reset was triggered by a watchdog, False if not. + */ +bool hal_watchdog_caused_last_reset(void); + +/** Get the maximum refresh value for the current platform in milliseconds + * + * @return Maximum refresh value supported by the watchdog for the current + * platform in milliseconds + */ +uint32_t hal_watchdog_get_max_timeout(void); + +/**@}*/ + +#ifdef __cplusplus +} +#endif + +#endif // DEVICE_WATCHDOG + +#endif // MBED_WATCHDOG_API_H + +/** @}*/ From 568824c07ae29542b00049bcd5ddb1c0ed146925 Mon Sep 17 00:00:00 2001 From: Steven Cartmell Date: Fri, 17 Nov 2017 15:49:57 +0000 Subject: [PATCH 02/62] Add K64F reset reason reference implementation --- .../TARGET_MCU_K64F/reset_reason.c | 79 +++++++++++++++++++ 1 file changed, 79 insertions(+) create mode 100644 targets/TARGET_Freescale/TARGET_MCUXpresso_MCUS/TARGET_MCU_K64F/reset_reason.c diff --git a/targets/TARGET_Freescale/TARGET_MCUXpresso_MCUS/TARGET_MCU_K64F/reset_reason.c b/targets/TARGET_Freescale/TARGET_MCUXpresso_MCUS/TARGET_MCU_K64F/reset_reason.c new file mode 100644 index 00000000000..6c8716c1744 --- /dev/null +++ b/targets/TARGET_Freescale/TARGET_MCUXpresso_MCUS/TARGET_MCU_K64F/reset_reason.c @@ -0,0 +1,79 @@ +#include "reset_reason_api.h" + +#include "fsl_rcm.h" + +reset_reason_t hal_reset_reason_get(void) +{ + const uint32_t reset_sources = + RCM_GetPreviousResetSources(RCM) & kRCM_SourceAll; + + // Check POR flag first. During a POR reset there will be two reset sources + // set: POR and LVD. As during the power on phase the low voltage detector + // circuit will detect a low voltage while the voltage is initially ramping + // up and set the BROWN_OUT flag. Therefore, if LVD is set we must check the + // POR to determine what the actual cause was. + if ((reset_sources & kRCM_SourcePor) != 0) { + return RESET_REASON_POWER_ON; + } + + if ((reset_sources & kRCM_SourceLvd) != 0) { + return RESET_REASON_BROWN_OUT; + } + + if ((reset_sources & kRCM_SourceWdog) != 0) { + return RESET_REASON_WATCHDOG; + } + + if ((reset_sources & kRCM_SourcePin) != 0) { + return RESET_REASON_PIN_RESET; + } + + if ((reset_sources & kRCM_SourceSw) != 0) { + return RESET_REASON_SOFTWARE; + } + +#if (defined(FSL_FEATURE_RCM_HAS_LOC) && FSL_FEATURE_RCM_HAS_LOC) + if ((reset_sources & kRCM_SourceLoc) != 0) { + return RESET_REASON_PLATFORM; + } +#endif + +#if (defined(FSL_FEATURE_RCM_HAS_LOL) && FSL_FEATURE_RCM_HAS_LOL) + if ((reset_sources & kRCM_SourceLol) != 0) { + return RESET_REASON_PLATFORM; + } +#endif + +#if (defined(FSL_FEATURE_RCM_HAS_WAKEUP) && FSL_FEATURE_RCM_HAS_WAKEUP) + if ((reset_sources & kRCM_SourceWakeup) != 0) { + return RESET_REASON_PLATFORM; + } +#endif + +#if (defined(FSL_FEATURE_RCM_HAS_JTAG) && FSL_FEATURE_RCM_HAS_JTAG) + if ((reset_sources & kRCM_SourceJtag) != 0) { + return RESET_REASON_PLATFORM; + } +#endif + +#if (defined(FSL_FEATURE_RCM_HAS_MDM_AP) && FSL_FEATURE_RCM_HAS_MDM_AP) + if ((reset_sources & kRCM_SourceMdmap) != 0) { + return RESET_REASON_PLATFORM; + } +#endif + +#if (defined(FSL_FEATURE_RCM_HAS_EZPORT) && FSL_FEATURE_RCM_HAS_EZPORT) + if ((reset_sources & kRCM_SourceEzpt) != 0) { + return RESET_REASON_PLATFORM; + } +#endif + + return RESET_REASON_UNKNOWN; +} + +void hal_reset_reason_clear(void) +{ +#if (defined(FSL_FEATURE_RCM_HAS_SSRS) && FSL_FEATURE_RCM_HAS_SSRS) + RCM_ClearStickyResetSources(RCM, kRCM_SourceAll); +#endif +} From bd493df7bf74a2e76c3a8849c6a4b9b266aa6660 Mon Sep 17 00:00:00 2001 From: Steven Cartmell Date: Mon, 20 Nov 2017 15:52:17 +0000 Subject: [PATCH 03/62] Add simple watchdog reference implementation for K64F - Add preprocessor guard to watchdog api that errors if the reset reason api is not also implemented - Add RESET_REASON and WATCHDOG to K64F targets.json - Add watchdog reference implementation --- hal/watchdog_api.h | 4 + .../TARGET_MCU_K64F/watchdog.c | 123 ++++++++++++++++++ targets/targets.json | 3 +- 3 files changed, 129 insertions(+), 1 deletion(-) create mode 100644 targets/TARGET_Freescale/TARGET_MCUXpresso_MCUS/TARGET_MCU_K64F/watchdog.c diff --git a/hal/watchdog_api.h b/hal/watchdog_api.h index d78af01afca..14f8610cc87 100644 --- a/hal/watchdog_api.h +++ b/hal/watchdog_api.h @@ -21,6 +21,10 @@ #if DEVICE_WATCHDOG +#if !(DEVICE_RESET_REASON) + #error "Watchdog feature depends on reset reason API also being implemented" +#endif + #include #include diff --git a/targets/TARGET_Freescale/TARGET_MCUXpresso_MCUS/TARGET_MCU_K64F/watchdog.c b/targets/TARGET_Freescale/TARGET_MCUXpresso_MCUS/TARGET_MCU_K64F/watchdog.c new file mode 100644 index 00000000000..5b7a7ca4fc1 --- /dev/null +++ b/targets/TARGET_Freescale/TARGET_MCUXpresso_MCUS/TARGET_MCU_K64F/watchdog.c @@ -0,0 +1,123 @@ +#include "watchdog_api.h" + +#include "reset_reason_api.h" + +#include "fsl_wdog.h" + +// Platform specific watchdog definitions +#define LPO_CLOCK_FREQUENCY 1000 +#define MAX_PRESCALER 8 +#define MAX_TIMEOUT 0xFFFFFFFF + +// Number of decrements in the timeout register per millisecond +#define TICKS_PER_MS (LPO_CLOCK_FREQUENCY / 1000) +// Maximum timeout that can be specified in milliseconds +#define MAX_TIMEOUT_MS ((MAX_TIMEOUT / TICKS_PER_MS) * MAX_PRESCALER) + +// Maximum supported watchdog timeout for given prescaler value +#define CALCULATE_MAX_TIMEOUT_MS(scale) \ + ((MAX_TIMEOUT / TICKS_PER_MS) * scale) + + +#if defined(FSL_FEATURE_WDOG_HAS_WAITEN) && FSL_FEATURE_WDOG_HAS_WAITEN + #define PLATFORM_SUPPORTS_SLEEP true +#else + #define PLATFORM_SUPPORTS_SLEEP false +#endif + + +static uint32_t calculate_prescaler_value(const uint32_t timeout_ms) +{ + if (timeout_ms > MAX_TIMEOUT_MS) { + return 0; + } + + for (uint32_t scale = 1; scale < MAX_PRESCALER; ++scale) { + if (timeout_ms < CALCULATE_MAX_TIMEOUT_MS(scale)) { + return scale; + } + } + + return 0; +} + + +watchdog_status_t hal_watchdog_init(const watchdog_config_t *config) +{ + // Validate the input parameters + if (config == NULL) { + return WATCHDOG_STATUS_INVALID_ARGUMENT; + } + + if (config->timeout_ms > MAX_TIMEOUT_MS) { + return WATCHDOG_STATUS_INVALID_ARGUMENT; + } + + if (config->window_ms > MAX_TIMEOUT_MS) { + return WATCHDOG_STATUS_INVALID_ARGUMENT; + } + + if (config->window_ms > config->timeout_ms) { + return WATCHDOG_STATUS_INVALID_ARGUMENT; + } + + if (config->enable_sleep && !PLATFORM_SUPPORTS_SLEEP) { + return WATCHDOG_STATUS_NOT_SUPPORTED; + } + + wdog_config_t cfg; + cfg.enableWdog = true; + cfg.clockSource = kWDOG_LpoClockSource; + cfg.enableUpdate = true; + cfg.enableInterrupt = false; + cfg.enableWindowMode = config->enable_window; + cfg.workMode.enableWait = config->enable_sleep; + cfg.workMode.enableStop = true; + cfg.workMode.enableDebug = false; + + const uint32_t prescaler = calculate_prescaler_value(config->timeout_ms); + + if (prescaler == 0) { + return WATCHDOG_STATUS_INVALID_ARGUMENT; + } + + cfg.prescaler = (wdog_clock_prescaler_t)(prescaler - 1); + cfg.timeoutValue = (TICKS_PER_MS * config->timeout_ms) / prescaler; + cfg.windowValue = (TICKS_PER_MS * config->window_ms) / prescaler; + + WDOG_Init(WDOG, &cfg); + + return WATCHDOG_STATUS_OK; +} + +void hal_watchdog_kick(void) +{ + WDOG_Refresh(WDOG); +} + +watchdog_status_t hal_watchdog_stop(void) +{ + WDOG_Disable(WDOG); + + return WATCHDOG_STATUS_OK; +} + +uint32_t hal_watchdog_get_reload_value(void) +{ + const uint32_t timeout = + (((WDOG->TOVALH & 0xFFFFU) << 16U) | (WDOG->TOVALL & 0xFFFFU)); + + const uint32_t prescaler = WDOG_PRESC_PRESCVAL(WDOG->PRESC); + + return ((timeout / TICKS_PER_MS) * (prescaler + 1)); +} + +bool hal_watchdog_caused_last_reset(void) +{ + return (hal_reset_reason_get() == RESET_REASON_WATCHDOG); +} + +uint32_t hal_watchdog_get_max_timeout(void) +{ + return MAX_TIMEOUT_MS; +} diff --git a/targets/targets.json b/targets/targets.json index a4792e6950b..04840083726 100644 --- a/targets/targets.json +++ b/targets/targets.json @@ -1479,7 +1479,8 @@ "STDIO_MESSAGES", "STORAGE", "TRNG", - "FLASH" + "FLASH", + "WATCHDOG" ], "features": ["STORAGE"], "release_versions": ["2", "5"], From 8e9eb45a98b5d4a6b52484f56cf8343b8f225cb8 Mon Sep 17 00:00:00 2001 From: Steven Cartmell Date: Wed, 22 Nov 2017 12:56:30 +0000 Subject: [PATCH 04/62] Fix watchdog API issues - Fix typo in module comment - Redefine the default system behaviour in sleep mode - Guard K64F enableWait flag - Remove bit shifts from reset reason enum --- hal/reset_reason_api.h | 21 ++++++++++--------- hal/watchdog_api.h | 12 +++++------ .../TARGET_MCU_K64F/reset_reason.c | 15 +++++++------ .../TARGET_MCU_K64F/watchdog.c | 4 +++- 4 files changed, 28 insertions(+), 24 deletions(-) diff --git a/hal/reset_reason_api.h b/hal/reset_reason_api.h index 8c5c3b7c75f..536c1903175 100644 --- a/hal/reset_reason_api.h +++ b/hal/reset_reason_api.h @@ -25,15 +25,16 @@ extern "C" { #endif typedef enum { - RESET_REASON_POWER_ON = (1 << 0), /**< Set when power is initially applied to the board. The power-on-reset circuit causes a POWER_ON reset when this occurs */ - RESET_REASON_PIN_RESET = (1 << 1), /**< Set when a reset is triggered by the hardware pin on the board */ - RESET_REASON_BROWN_OUT = (1 << 2), /**< Triggered when the voltage drops below the low voltage detect (LVD) threshold the system will be held in a reset until the voltage rises above the threshold */ - RESET_REASON_SOFTWARE = (1 << 3), /**< Set during software reset, typically triggered by writing the SYSRESETREQ bit in the Application Interrupt and Reset Control register */ - RESET_REASON_WATCHDOG = (1 << 4), /**< Set when a running watchdog timer fails to be refreshed */ - RESET_REASON_LOCKUP = (1 << 5), /**< Set when the core is locked because of an unrecoverable exception */ - RESET_REASON_MULTIPLE = (1 << 6), /**< Set if multiple reset reasons are set within the board. Occurs when the reset reason registers aren't cleared between resets */ - RESET_REASON_PLATFORM = (1 << 7), /**< Platform specific reset reason not captured in this enum */ - RESET_REASON_UNKNOWN = (1 << 8) /**< Unknown or unreadable reset reason **/ + RESET_REASON_POWER_ON, /**< Set when power is initially applied to the board. The power-on-reset circuit causes a POWER_ON reset when this occurs */ + RESET_REASON_PIN_RESET, /**< Set when a reset is triggered by the hardware pin on the board */ + RESET_REASON_BROWN_OUT, /**< Triggered when the voltage drops below the low voltage detect (LVD) threshold the system will be held in a reset until the voltage rises above the threshold */ + RESET_REASON_SOFTWARE, /**< Set during software reset, typically triggered by writing the SYSRESETREQ bit in the Application Interrupt and Reset Control register */ + RESET_REASON_WATCHDOG, /**< Set when a running watchdog timer fails to be refreshed */ + RESET_REASON_LOCKUP, /**< Set when the core is locked because of an unrecoverable exception */ + RESET_REASON_WAKE_LOW_POWER, /**< Set when waking from deep sleep mode */ + RESET_REASON_MULTIPLE, /**< Set if multiple reset reasons are set within the board. Occurs when the reset reason registers aren't cleared between resets */ + RESET_REASON_PLATFORM, /**< Platform specific reset reason not captured in this enum */ + RESET_REASON_UNKNOWN /**< Unknown or unreadable reset reason **/ } reset_reason_t; /** @@ -48,7 +49,7 @@ typedef enum { */ reset_reason_t hal_reset_reason_get(void); - /** +/** * Clear the reset reason from registers * * Reset the value of the reset status registers, the reset reason will persist diff --git a/hal/watchdog_api.h b/hal/watchdog_api.h index 14f8610cc87..8950efab2a2 100644 --- a/hal/watchdog_api.h +++ b/hal/watchdog_api.h @@ -41,12 +41,11 @@ * to the user specified reset value. * * The watchdog timer supports a second mode of operation called windowed mode. - * When configured in this mode by setting enable_window to true, the timer - * watchdog will enable a restriction on the kick. If the watchdog timer too + * When configured in this mode by setting enable_window to true, the watchdog + * will enable a restriction on the kick. If the watchdog timer is kicked too * soon after it has last been refreshed a system reset occurs. The earliest * time in milliseconds the timer can be kicked without triggering a reset is * specified by window_ms. - * */ typedef struct @@ -74,10 +73,9 @@ typedef struct */ uint32_t window_ms; /** - * Configures the watchdog timer to run while the core is in sleep mode. By - * default when the system is put into the sleep the watchdog timer is paused. - * Enabling this setting causes the timer to countdown during this time. This - * flag is disabled by default. + * Configures the watchdog behaviour while the system is in sleep mode. When + * this flag is enabled the watchdog timer runs normally while the system is + * in sleep mode, when disabled the watchdog is paused during this time. */ bool enable_sleep; } watchdog_config_t; diff --git a/targets/TARGET_Freescale/TARGET_MCUXpresso_MCUS/TARGET_MCU_K64F/reset_reason.c b/targets/TARGET_Freescale/TARGET_MCUXpresso_MCUS/TARGET_MCU_K64F/reset_reason.c index 6c8716c1744..d8c8bedc888 100644 --- a/targets/TARGET_Freescale/TARGET_MCUXpresso_MCUS/TARGET_MCU_K64F/reset_reason.c +++ b/targets/TARGET_Freescale/TARGET_MCUXpresso_MCUS/TARGET_MCU_K64F/reset_reason.c @@ -7,6 +7,15 @@ reset_reason_t hal_reset_reason_get(void) const uint32_t reset_sources = RCM_GetPreviousResetSources(RCM) & kRCM_SourceAll; + // Low power mode is exited via the RESET pin. Therefore, when this reset is + // triggered both the PIN and WAKEUP will have bits set, so check this flag + // first. +#if (defined(FSL_FEATURE_RCM_HAS_WAKEUP) && FSL_FEATURE_RCM_HAS_WAKEUP) + if ((reset_sources & kRCM_SourceWakeup) != 0) { + return RESET_REASON_PLATFORM; + } +#endif + // Check POR flag first. During a POR reset there will be two reset sources // set: POR and LVD. As during the power on phase the low voltage detector // circuit will detect a low voltage while the voltage is initially ramping @@ -44,12 +53,6 @@ reset_reason_t hal_reset_reason_get(void) } #endif -#if (defined(FSL_FEATURE_RCM_HAS_WAKEUP) && FSL_FEATURE_RCM_HAS_WAKEUP) - if ((reset_sources & kRCM_SourceWakeup) != 0) { - return RESET_REASON_PLATFORM; - } -#endif - #if (defined(FSL_FEATURE_RCM_HAS_JTAG) && FSL_FEATURE_RCM_HAS_JTAG) if ((reset_sources & kRCM_SourceJtag) != 0) { return RESET_REASON_PLATFORM; diff --git a/targets/TARGET_Freescale/TARGET_MCUXpresso_MCUS/TARGET_MCU_K64F/watchdog.c b/targets/TARGET_Freescale/TARGET_MCUXpresso_MCUS/TARGET_MCU_K64F/watchdog.c index 5b7a7ca4fc1..e2fd1a7936f 100644 --- a/targets/TARGET_Freescale/TARGET_MCUXpresso_MCUS/TARGET_MCU_K64F/watchdog.c +++ b/targets/TARGET_Freescale/TARGET_MCUXpresso_MCUS/TARGET_MCU_K64F/watchdog.c @@ -71,8 +71,10 @@ watchdog_status_t hal_watchdog_init(const watchdog_config_t *config) cfg.enableUpdate = true; cfg.enableInterrupt = false; cfg.enableWindowMode = config->enable_window; +#if PLATFORM_SUPPORTS_SLEEP cfg.workMode.enableWait = config->enable_sleep; - cfg.workMode.enableStop = true; +#endif + cfg.workMode.enableStop = false; cfg.workMode.enableDebug = false; const uint32_t prescaler = calculate_prescaler_value(config->timeout_ms); From e8adab72d74c650d584100c785a19a867ce025f6 Mon Sep 17 00:00:00 2001 From: Steven Cartmell Date: Mon, 27 Nov 2017 10:26:22 +0000 Subject: [PATCH 05/62] Add Reset Reason platform API --- hal/reset_reason_api.h | 6 ++-- platform/mbed_reset_reason.cpp | 35 +++++++++++++++++++++ platform/mbed_reset_reason.h | 56 ++++++++++++++++++++++++++++++++++ 3 files changed, 95 insertions(+), 2 deletions(-) create mode 100644 platform/mbed_reset_reason.cpp create mode 100644 platform/mbed_reset_reason.h diff --git a/hal/reset_reason_api.h b/hal/reset_reason_api.h index 536c1903175..be1a19d85d7 100644 --- a/hal/reset_reason_api.h +++ b/hal/reset_reason_api.h @@ -32,6 +32,8 @@ typedef enum { RESET_REASON_WATCHDOG, /**< Set when a running watchdog timer fails to be refreshed */ RESET_REASON_LOCKUP, /**< Set when the core is locked because of an unrecoverable exception */ RESET_REASON_WAKE_LOW_POWER, /**< Set when waking from deep sleep mode */ + RESET_REASON_ACCESS_ERROR, /**< Umbrella value that encompasses any access related reset */ + RESET_REASON_BOOT_ERROR, /**< Umbrella value that encompasses any boot related reset */ RESET_REASON_MULTIPLE, /**< Set if multiple reset reasons are set within the board. Occurs when the reset reason registers aren't cleared between resets */ RESET_REASON_PLATFORM, /**< Platform specific reset reason not captured in this enum */ RESET_REASON_UNKNOWN /**< Unknown or unreadable reset reason **/ @@ -47,7 +49,7 @@ typedef enum { * * @return enum containing the last reset reason for the board. */ - reset_reason_t hal_reset_reason_get(void); +reset_reason_t hal_reset_reason_get(void); /** * Clear the reset reason from registers @@ -57,7 +59,7 @@ typedef enum { * before the system resets. Failing to do so may make it difficult to determine * the cause of any subsequent system resets. */ - void hal_reset_reason_clear(void); +void hal_reset_reason_clear(void); /**@}*/ diff --git a/platform/mbed_reset_reason.cpp b/platform/mbed_reset_reason.cpp new file mode 100644 index 00000000000..5ff5d5aad44 --- /dev/null +++ b/platform/mbed_reset_reason.cpp @@ -0,0 +1,35 @@ +/* mbed Microcontroller Library + * Copyright (c) 2017 ARM Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "mbed_reset_reason.h" + +#if DEVICE_RESET_REASON + +namespace mbed { + +reset_reason_t mbed_reset_reason_get(void) +{ + // Store the reason statically so it can be accessed after the first call to + // this function resets it. + const static reset_reason_t reason = hal_reset_reason_get(); + + hal_reset_reason_clear(); + + return reason; +} +} // namespace mbed + +#endif // DEVICE_RESET_REASON diff --git a/platform/mbed_reset_reason.h b/platform/mbed_reset_reason.h new file mode 100644 index 00000000000..507461a32cb --- /dev/null +++ b/platform/mbed_reset_reason.h @@ -0,0 +1,56 @@ +/** \addtogroup hal */ +/** @{*/ +/* mbed Microcontroller Library + * Copyright (c) 2017 ARM Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef MBED_RESET_REASON_H +#define MBED_RESET_REASON_H + +#if DEVICE_RESET_REASON + +#include "reset_reason_api.h" + +namespace mbed { +/** \addtogroup platform */ +/** @{*/ +/** + * \defgroup reset_reason reset reason functions + * @{ + */ + +/** Get the platform-independent reason code for the last system reset. + * + * Example: + * @code + * const reset_reason_t reason = mbed_reset_reason_get(); + * + * if (reason == RESET_REASON_WATCHDOG) { + * std::cout << "Watchdog reset" << std::endl; + * rollback(); + * } + * @endcode + */ +reset_reason_t mbed_reset_reason_get(void); + +/**@}*/ +/**@}*/ + +} // namespace mbed + +#endif // DEVICE_RESET_REASON + +/**@}*/ + +#endif // MBED_RESET_REASON_H From a1e38fe26db7ffabda66c1efcc908d661308d57c Mon Sep 17 00:00:00 2001 From: Steven Cartmell Date: Mon, 27 Nov 2017 12:22:27 +0000 Subject: [PATCH 06/62] Add reset reason reference implementation STM32 --- targets/TARGET_STM/reset_reason.c | 59 +++++++++++++++++++++++++++++++ targets/targets.json | 1 + 2 files changed, 60 insertions(+) create mode 100644 targets/TARGET_STM/reset_reason.c diff --git a/targets/TARGET_STM/reset_reason.c b/targets/TARGET_STM/reset_reason.c new file mode 100644 index 00000000000..0d3ee42de3c --- /dev/null +++ b/targets/TARGET_STM/reset_reason.c @@ -0,0 +1,59 @@ +#include "reset_reason_api.h" + +#ifdef DEVICE_RESET_REASON + +#include "device.h" + +reset_reason_t hal_reset_reason_get(void) +{ +#ifdef RCC_FLAG_SFTRST + if (__HAL_RCC_GET_FLAG(RCC_FLAG_SFTRST)) { + return RESET_REASON_SOFTWARE; + } +#endif + +#ifdef RCC_FLAG_BORRST + if (__HAL_RCC_GET_FLAG(RCC_FLAG_BORRST)) { + return RESET_REASON_BROWN_OUT; + } +#endif + +#ifdef RCC_FLAG_PORRST + if (__HAL_RCC_GET_FLAG(RCC_FLAG_PORRST)) { + return RESET_REASON_POWER_ON; + } +#endif + +#ifdef RCC_FLAG_PINRST + if (__HAL_RCC_GET_FLAG(RCC_FLAG_PINRST)) { + return RESET_REASON_PIN_RESET; + } +#endif + +#ifdef RCC_FLAG_IWDGRST + if (__HAL_RCC_GET_FLAG(RCC_FLAG_IWDGRST)) { + return RESET_REASON_WATCHDOG; + } +#endif + +#ifdef RCC_FLAG_WWDGRST + if (__HAL_RCC_GET_FLAG(RCC_FLAG_WWDGRST)) { + return RESET_REASON_WATCHDOG; + } +#endif + +#ifdef RCC_FLAG_LPWRRST + if (__HAL_RCC_GET_FLAG(RCC_FLAG_LPWRRST)) { + return RESET_REASON_WAKE_LOW_POWER; + } +#endif + + return RESET_REASON_UNKNOWN; +} + +void hal_reset_reason_clear(void) +{ + __HAL_RCC_CLEAR_RESET_FLAGS(); +} + +#endif // DEVICE_RESET_REASON diff --git a/targets/targets.json b/targets/targets.json index 04840083726..9edcc67a609 100644 --- a/targets/targets.json +++ b/targets/targets.json @@ -1757,6 +1757,7 @@ "PORTIN", "PORTINOUT", "PORTOUT", + "RESET_REASON", "PWMOUT", "SERIAL", "SLEEP", From 7006017f2ad8a6a06cf6cb6944c11e57fa400c82 Mon Sep 17 00:00:00 2001 From: Steven Cartmell Date: Mon, 27 Nov 2017 15:55:00 +0000 Subject: [PATCH 07/62] Add function to fetch platform specific reset reason register values --- hal/reset_reason_api.h | 17 +++++++++++++---- platform/mbed_reset_reason.cpp | 10 ++++++++++ platform/mbed_reset_reason.h | 19 +++++++++++++++++++ .../TARGET_MCU_K64F/reset_reason.c | 7 +++++++ targets/TARGET_STM/reset_reason.c | 7 +++++++ 5 files changed, 56 insertions(+), 4 deletions(-) diff --git a/hal/reset_reason_api.h b/hal/reset_reason_api.h index be1a19d85d7..037d2665e2b 100644 --- a/hal/reset_reason_api.h +++ b/hal/reset_reason_api.h @@ -20,6 +20,8 @@ #if DEVICE_RESET_REASON +#include + #ifdef __cplusplus extern "C" { #endif @@ -39,8 +41,7 @@ typedef enum { RESET_REASON_UNKNOWN /**< Unknown or unreadable reset reason **/ } reset_reason_t; -/** - * Fetch the reset reason for the last system reset +/** Fetch the reset reason for the last system reset * * Note: Some platforms contain reset reason registers that persist through * system resets. If the registers haven't been cleared before calling this @@ -51,8 +52,16 @@ typedef enum { */ reset_reason_t hal_reset_reason_get(void); -/** - * Clear the reset reason from registers + +/** Fetch the raw platform specific reset reason register value + * + * @return value containing the reset reason register for the given platform. + * If the platform contains reset reasons across multiple registers they + * will be concatenated here. + */ +uint32_t hal_reset_reason_get_raw(void); + +/** Clear the reset reason from registers * * Reset the value of the reset status registers, the reset reason will persist * between system resets on certain platforms so the registers should be cleared diff --git a/platform/mbed_reset_reason.cpp b/platform/mbed_reset_reason.cpp index 5ff5d5aad44..06f30ca24e7 100644 --- a/platform/mbed_reset_reason.cpp +++ b/platform/mbed_reset_reason.cpp @@ -26,10 +26,20 @@ reset_reason_t mbed_reset_reason_get(void) // this function resets it. const static reset_reason_t reason = hal_reset_reason_get(); + // Call get raw to cache the reset reason before clearing the registers. + hal_reset_reason_get_raw(); hal_reset_reason_clear(); return reason; } + +uint32_t mbed_reset_reason_get_raw(void) +{ + const static uint32_t reason = hal_reset_reason_get_raw(); + + return reason; +} + } // namespace mbed #endif // DEVICE_RESET_REASON diff --git a/platform/mbed_reset_reason.h b/platform/mbed_reset_reason.h index 507461a32cb..1c8b31b6072 100644 --- a/platform/mbed_reset_reason.h +++ b/platform/mbed_reset_reason.h @@ -22,6 +22,8 @@ #include "reset_reason_api.h" +#include + namespace mbed { /** \addtogroup platform */ /** @{*/ @@ -44,6 +46,23 @@ namespace mbed { */ reset_reason_t mbed_reset_reason_get(void); + +/** Get the platform specific reason code for the last system reset. + * + * Platform specific reasons that are not covered by the reset_reason_t enum + * will cause the mbed_reset_reason_get function to return RESET_REASON_PLATFORM + * In order to get the actual reason the register value must be fetched directly + * using this function and interpreted in a platform specific manner. + * + * Example: + * @code + * if (mbed_reset_reason_get() == RESET_REASON_PLATFORM) { + * const uint32_t platform_reason = mbed_reset_reason_get_raw(); + * } + * @endcode + */ +uint32_t mbed_reset_reason_get_raw(void); + /**@}*/ /**@}*/ diff --git a/targets/TARGET_Freescale/TARGET_MCUXpresso_MCUS/TARGET_MCU_K64F/reset_reason.c b/targets/TARGET_Freescale/TARGET_MCUXpresso_MCUS/TARGET_MCU_K64F/reset_reason.c index d8c8bedc888..924f0f1921a 100644 --- a/targets/TARGET_Freescale/TARGET_MCUXpresso_MCUS/TARGET_MCU_K64F/reset_reason.c +++ b/targets/TARGET_Freescale/TARGET_MCUXpresso_MCUS/TARGET_MCU_K64F/reset_reason.c @@ -74,6 +74,13 @@ reset_reason_t hal_reset_reason_get(void) return RESET_REASON_UNKNOWN; } + +uint32_t hal_reset_reason_get_raw(void) +{ + return (RCM_GetPreviousResetSources(RCM) & kRCM_SourceAll); +} + + void hal_reset_reason_clear(void) { #if (defined(FSL_FEATURE_RCM_HAS_SSRS) && FSL_FEATURE_RCM_HAS_SSRS) diff --git a/targets/TARGET_STM/reset_reason.c b/targets/TARGET_STM/reset_reason.c index 0d3ee42de3c..3b7a82863c5 100644 --- a/targets/TARGET_STM/reset_reason.c +++ b/targets/TARGET_STM/reset_reason.c @@ -51,6 +51,13 @@ reset_reason_t hal_reset_reason_get(void) return RESET_REASON_UNKNOWN; } + +uint32_t hal_reset_reason_get_raw(void) +{ + return RCC->CSR; +} + + void hal_reset_reason_clear(void) { __HAL_RCC_CLEAR_RESET_FLAGS(); From 2359f5fca4096f42eeff2110be7888700e694415 Mon Sep 17 00:00:00 2001 From: Steven Cartmell Date: Mon, 27 Nov 2017 17:20:58 +0000 Subject: [PATCH 08/62] Add independent watchdog reference implementation for STM32 --- {platform => drivers}/mbed_reset_reason.cpp | 0 {platform => drivers}/mbed_reset_reason.h | 0 targets/TARGET_STM/TARGET_STM32F4/watchdog.c | 116 +++++++++++++++++++ targets/targets.json | 3 +- 4 files changed, 118 insertions(+), 1 deletion(-) rename {platform => drivers}/mbed_reset_reason.cpp (100%) rename {platform => drivers}/mbed_reset_reason.h (100%) create mode 100644 targets/TARGET_STM/TARGET_STM32F4/watchdog.c diff --git a/platform/mbed_reset_reason.cpp b/drivers/mbed_reset_reason.cpp similarity index 100% rename from platform/mbed_reset_reason.cpp rename to drivers/mbed_reset_reason.cpp diff --git a/platform/mbed_reset_reason.h b/drivers/mbed_reset_reason.h similarity index 100% rename from platform/mbed_reset_reason.h rename to drivers/mbed_reset_reason.h diff --git a/targets/TARGET_STM/TARGET_STM32F4/watchdog.c b/targets/TARGET_STM/TARGET_STM32F4/watchdog.c new file mode 100644 index 00000000000..a9ef3375fce --- /dev/null +++ b/targets/TARGET_STM/TARGET_STM32F4/watchdog.c @@ -0,0 +1,116 @@ +#include "watchdog_api.h" + +#include "reset_reason_api.h" + +#include "device.h" + + +// Platform specific watchdog definitions +#define LPO_CLOCK_FREQUENCY 40000 +#define MAX_PRESCALER 256 +#define MAX_TIMEOUT 0xFFF + +// Number of decrements in the timeout register per millisecond +#define TICKS_PER_MS (LPO_CLOCK_FREQUENCY / 1000) +// Maximum timeout that can be specified in milliseconds +#define MAX_TIMEOUT_MS ((MAX_TIMEOUT / TICKS_PER_MS) * MAX_PRESCALER) +// Maximum supported watchdog timeout for given prescaler value +#define CALCULATE_MAX_TIMEOUT_MS(scale) \ + ((MAX_TIMEOUT / TICKS_PER_MS) * scale) + + +static uint32_t calculate_prescaler_value(const uint32_t timeout_ms) +{ + if (timeout_ms > MAX_TIMEOUT_MS) { + return 0; + } + + for (uint32_t scale = 0; scale < 7; ++scale) { + const uint32_t prescaler = (4U << scale); + + if (timeout_ms < CALCULATE_MAX_TIMEOUT_MS(prescaler)) { + return scale; + } + } + + return 0; +} + + +watchdog_status_t hal_watchdog_init(const watchdog_config_t *config) +{ + // Validate the input parameters + if (config == NULL) { + return WATCHDOG_STATUS_INVALID_ARGUMENT; + } + + if (config->timeout_ms > MAX_TIMEOUT_MS) { + return WATCHDOG_STATUS_INVALID_ARGUMENT; + } + + if (config->window_ms > MAX_TIMEOUT_MS) { + return WATCHDOG_STATUS_INVALID_ARGUMENT; + } + + if (config->window_ms > config->timeout_ms) { + return WATCHDOG_STATUS_INVALID_ARGUMENT; + } + + if (config->enable_sleep == false) { + return WATCHDOG_STATUS_NOT_SUPPORTED; + } + + + const uint32_t prescaler = calculate_prescaler_value(config->timeout_ms); + + if (prescaler == 0) { + return WATCHDOG_STATUS_INVALID_ARGUMENT; + } + + // Enable write access to Prescaler(IWDG_PR) and Reload(IWDG_RLR) registers + IWDG->KR = 0x5555; + + // Set the prescaler and timeout values + IWDG->RLR = (TICKS_PER_MS * config->timeout_ms) / (4U << prescaler); + IWDG->PR = prescaler; + + // Reload the Watchdog Counter. + IWDG->KR = 0xAAAA; + // Enable the Independent Watchdog. + IWDG->KR = 0xCCCC; + + return WATCHDOG_STATUS_OK; +} + + +void hal_watchdog_kick(void) +{ + IWDG->KR = 0xAAAA; +} + + +watchdog_status_t hal_watchdog_stop(void) +{ + return WATCHDOG_STATUS_NOT_SUPPORTED; +} + + +uint32_t hal_watchdog_get_reload_value(void) +{ + const uint32_t timeout = (IWDG->RLR & 0xFFF); + const uint32_t prescaler = (4U << (IWDG->PR & 0x7)); + + return ((timeout / TICKS_PER_MS) * prescaler); +} + + +bool hal_watchdog_caused_last_reset(void) +{ + return (hal_reset_reason_get() == RESET_REASON_WATCHDOG); +} + + +uint32_t hal_watchdog_get_max_timeout(void) +{ + return MAX_TIMEOUT_MS; +} diff --git a/targets/targets.json b/targets/targets.json index 9edcc67a609..55de7f8021e 100644 --- a/targets/targets.json +++ b/targets/targets.json @@ -1830,7 +1830,8 @@ "SPI", "SPISLAVE", "SPI_ASYNCH", - "STDIO_MESSAGES" + "STDIO_MESSAGES", + "WATCHDOG" ] }, "MIMXRT1050_EVK": { From 8fb7220ddff9ea80db9285289d5e3c7c08fefa1c Mon Sep 17 00:00:00 2001 From: Steven Cartmell Date: Tue, 28 Nov 2017 12:01:48 +0000 Subject: [PATCH 09/62] Amend reset reason driver API - Change API to match C++ API throughout drivers - Amend HAL API documentation to be more specific --- ...{mbed_reset_reason.cpp => ResetReason.cpp} | 27 +++---- drivers/ResetReason.h | 77 +++++++++++++++++++ drivers/mbed_reset_reason.h | 75 ------------------ hal/reset_reason_api.h | 20 +++++ 4 files changed, 111 insertions(+), 88 deletions(-) rename drivers/{mbed_reset_reason.cpp => ResetReason.cpp} (56%) create mode 100644 drivers/ResetReason.h delete mode 100644 drivers/mbed_reset_reason.h diff --git a/drivers/mbed_reset_reason.cpp b/drivers/ResetReason.cpp similarity index 56% rename from drivers/mbed_reset_reason.cpp rename to drivers/ResetReason.cpp index 06f30ca24e7..7070cef4901 100644 --- a/drivers/mbed_reset_reason.cpp +++ b/drivers/ResetReason.cpp @@ -14,30 +14,31 @@ * limitations under the License. */ -#include "mbed_reset_reason.h" +#include "ResetReason.h" -#if DEVICE_RESET_REASON +#ifdef DEVICE_RESET_REASON namespace mbed { -reset_reason_t mbed_reset_reason_get(void) +reset_reason_t ResetReason::get() { - // Store the reason statically so it can be accessed after the first call to - // this function resets it. - const static reset_reason_t reason = hal_reset_reason_get(); + // Store the reason statically so it can be accessed after the first call to + // this function resets it. + const static reset_reason_t reason = hal_reset_reason_get(); - // Call get raw to cache the reset reason before clearing the registers. - hal_reset_reason_get_raw(); - hal_reset_reason_clear(); + // Call get raw to cache the reset reason before clearing the registers. + ResetReason::get_raw(); - return reason; + hal_reset_reason_clear(); + + return reason; } -uint32_t mbed_reset_reason_get_raw(void) +uint32_t ResetReason::get_raw() { - const static uint32_t reason = hal_reset_reason_get_raw(); + const static uint32_t reason = hal_reset_reason_get_raw(); - return reason; + return reason; } } // namespace mbed diff --git a/drivers/ResetReason.h b/drivers/ResetReason.h new file mode 100644 index 00000000000..cd30c6c798e --- /dev/null +++ b/drivers/ResetReason.h @@ -0,0 +1,77 @@ +/** \addtogroup hal */ +/** @{*/ +/* mbed Microcontroller Library + * Copyright (c) 2017 ARM Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef MBED_RESET_REASON_H +#define MBED_RESET_REASON_H + +#ifdef DEVICE_RESET_REASON + +#include "reset_reason_api.h" + +namespace mbed +{ +/** \addtogroup drivers */ +/** @{*/ +/** + * \defgroup reset_reason reset reason functions + * @{ + */ +class ResetReason +{ +public: + /** Get the platform-independent reason code for the last system reset. + * + * Example: + * @code + * const reset_reason_t reason = ResetReason::get(); + * + * if (reason == RESET_REASON_WATCHDOG) { + * std::cout << "Watchdog reset" << std::endl; + * rollback(); + * } + * @endcode + */ + static reset_reason_t get(); + + /** Get the platform specific reason code for the last system reset. + * + * Platform specific reasons that are not covered by the reset_reason_t enum + * will cause the ResetReason::get() function to return + * RESET_REASON_PLATFORM. In order to get the actual reason the register + * value must be fetched directly using this function and interpreted in a + * platform specific manner. + * + * Example: + * @code + * if (ResetReason::get() == RESET_REASON_PLATFORM) { + * const uint32_t platform_reason = ResetReason::get_raw(); + * } + * @endcode + */ + static uint32_t get_raw(); +}; + + +/**@}*/ +/**@}*/ + +} // namespace mbed + +/**@}*/ + +#endif // DEVICE_RESET_REASON +#endif // MBED_RESET_REASON_H diff --git a/drivers/mbed_reset_reason.h b/drivers/mbed_reset_reason.h deleted file mode 100644 index 1c8b31b6072..00000000000 --- a/drivers/mbed_reset_reason.h +++ /dev/null @@ -1,75 +0,0 @@ -/** \addtogroup hal */ -/** @{*/ -/* mbed Microcontroller Library - * Copyright (c) 2017 ARM Limited - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -#ifndef MBED_RESET_REASON_H -#define MBED_RESET_REASON_H - -#if DEVICE_RESET_REASON - -#include "reset_reason_api.h" - -#include - -namespace mbed { -/** \addtogroup platform */ -/** @{*/ -/** - * \defgroup reset_reason reset reason functions - * @{ - */ - -/** Get the platform-independent reason code for the last system reset. - * - * Example: - * @code - * const reset_reason_t reason = mbed_reset_reason_get(); - * - * if (reason == RESET_REASON_WATCHDOG) { - * std::cout << "Watchdog reset" << std::endl; - * rollback(); - * } - * @endcode - */ -reset_reason_t mbed_reset_reason_get(void); - - -/** Get the platform specific reason code for the last system reset. - * - * Platform specific reasons that are not covered by the reset_reason_t enum - * will cause the mbed_reset_reason_get function to return RESET_REASON_PLATFORM - * In order to get the actual reason the register value must be fetched directly - * using this function and interpreted in a platform specific manner. - * - * Example: - * @code - * if (mbed_reset_reason_get() == RESET_REASON_PLATFORM) { - * const uint32_t platform_reason = mbed_reset_reason_get_raw(); - * } - * @endcode - */ -uint32_t mbed_reset_reason_get_raw(void); - -/**@}*/ -/**@}*/ - -} // namespace mbed - -#endif // DEVICE_RESET_REASON - -/**@}*/ - -#endif // MBED_RESET_REASON_H diff --git a/hal/reset_reason_api.h b/hal/reset_reason_api.h index 037d2665e2b..d2df64a8e2d 100644 --- a/hal/reset_reason_api.h +++ b/hal/reset_reason_api.h @@ -42,6 +42,17 @@ typedef enum { } reset_reason_t; /** Fetch the reset reason for the last system reset + * + * This function must return the contents of the system reset reason registers + * cast to an appropriate platform independent reset reason. If multiple reset + * reasons are set this function should return RESET_REASON_MULTIPLE. If the + * reset reason does not match any existing platform independent value this + * function should return RESET_REASON_PLATFORM. If no reset reason can be + * determined this function should return RESET_REASON_UNKNOWN. + * + * This function is not idempotent, there is no guarantee that the system + * reset reason will not be cleared between calls to this function altering the + * return value between calls. * * Note: Some platforms contain reset reason registers that persist through * system resets. If the registers haven't been cleared before calling this @@ -54,6 +65,15 @@ reset_reason_t hal_reset_reason_get(void); /** Fetch the raw platform specific reset reason register value + * + * This function must return the raw contents of the system reset reason + * registers cast to a uint32_t value. If the platform contains reset reasons + * that span multiple registers/addresses the value should be concatenated into + * the return type. + * + * This function is not idempotent, there is no guarantee that the system + * reset reason will not be cleared between calls to this function altering the + * return value between calls. * * @return value containing the reset reason register for the given platform. * If the platform contains reset reasons across multiple registers they From fa339a260927bf52afa3a3abb48c0c0f328fd944 Mon Sep 17 00:00:00 2001 From: Steven Cartmell Date: Tue, 28 Nov 2017 14:00:56 +0000 Subject: [PATCH 10/62] Add Watchdog driver API --- drivers/ResetReason.h | 2 +- drivers/Watchdog.cpp | 68 +++++++++ drivers/Watchdog.h | 137 ++++++++++++++++++ hal/watchdog_api.h | 53 +++++-- .../TARGET_MCU_K64F/watchdog.c | 31 ++-- targets/TARGET_STM/TARGET_STM32F4/watchdog.c | 27 ++-- 6 files changed, 279 insertions(+), 39 deletions(-) create mode 100644 drivers/Watchdog.cpp create mode 100644 drivers/Watchdog.h diff --git a/drivers/ResetReason.h b/drivers/ResetReason.h index cd30c6c798e..7c9f85422ac 100644 --- a/drivers/ResetReason.h +++ b/drivers/ResetReason.h @@ -40,7 +40,7 @@ class ResetReason * const reset_reason_t reason = ResetReason::get(); * * if (reason == RESET_REASON_WATCHDOG) { - * std::cout << "Watchdog reset" << std::endl; + * printf("Watchdog reset\n"); * rollback(); * } * @endcode diff --git a/drivers/Watchdog.cpp b/drivers/Watchdog.cpp new file mode 100644 index 00000000000..358b41003a0 --- /dev/null +++ b/drivers/Watchdog.cpp @@ -0,0 +1,68 @@ +/* mbed Microcontroller Library + * Copyright (c) 2017 ARM Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifdef DEVICE_WATCHDOG + +#include "Watchdog.h" + +namespace mbed +{ + +watchdog_status_t Watchdog::start(const uint32_t timeout, const bool enable_sleep) +{ + return start(timeout, 0, enable_sleep); +} + + +watchdog_status_t Watchdog::start(const uint32_t timeout, const uint32_t window, const bool enable_sleep) +{ + watchdog_config_t config; + config.timeout_ms = timeout; + config.window_ms = window; + config.enable_window = (window != 0); + config.enable_sleep = enable_sleep; + + return hal_watchdog_init(&config); +} + + +void Watchdog::kick() +{ + hal_watchdog_kick(); +} + + +watchdog_status_t Watchdog::stop() +{ + return hal_watchdog_stop(); +} + + +uint32_t Watchdog::reload_value() const +{ + return hal_watchdog_get_reload_value(); +} + + +uint32_t Watchdog::max_timeout() +{ + const watchdog_features_t features = hal_watchdog_get_platform_features(); + + return features.max_timeout; +} + +} // namespace mbed + +#endif // DEVICE_WATCHDOG diff --git a/drivers/Watchdog.h b/drivers/Watchdog.h new file mode 100644 index 00000000000..dca16740bca --- /dev/null +++ b/drivers/Watchdog.h @@ -0,0 +1,137 @@ +/** \addtogroup hal */ +/** @{*/ +/* mbed Microcontroller Library + * Copyright (c) 2017 ARM Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef MBED_WATCHDOG_H +#define MBED_WATCHDOG_H + +#ifdef DEVICE_WATCHDOG + +#include "watchdog_api.h" + +#include + + +namespace mbed { +/** \addtogroup drivers */ +/** @{*/ +/** A system timer that will reset the system in the case of system failures or + * malfunctions. + * + * Example: + * @code + * + * Watchdog watchdog = Watchdog(); + * watchdog.set_timeout(2000); + * watchdog.start(); + * + * while (true) { + * watchdog.kick(); + * + * // Application code + * } + * @endcode + * + */ +class Watchdog +{ +public: + Watchdog() {} + +public: + /** Start an independent watchdog timer with specified parameters + * + * @param timeout Timeout of the watchdog in milliseconds + * @param enable_sleep Sets sleep mode behaviour. When enabled the watchdog + * will continue to run in sleep mode. When disable the + * watchdog will be paused. This feature is not + * supported on all platforms. + * + * @return status WATCHDOG_STATUS_OK if the watchdog timer was started + * successfully. WATCHDOG_INVALID_ARGUMENT if one of the input + * parameters is out of range for the current platform. + * WATCHDOG_NOT_SUPPORTED if one of the enabled input + * parameters is not supported by the current platform. + */ + watchdog_status_t start(const uint32_t timeout, const bool enable_sleep = true); + + + /** Start a windowed watchdog timer with specified parameters + * + * @param timeout Timeout of the watchdog in milliseconds + * @param window Time period of the window of the watchdog + * @param enable_sleep Sets sleep mode behaviour. When enabled the watchdog + * will continue to run in sleep mode. When disable the + * watchdog will be paused. This feature is not + * supported on all platforms. + * + * @return status WATCHDOG_STATUS_OK if the watchdog timer was started + * successfully. WATCHDOG_INVALID_ARGUMENT if one of the input + * parameters is out of range for the current platform. + * WATCHDOG_NOT_SUPPORTED if one of the enabled input + * parameters is not supported by the current platform. + */ + watchdog_status_t start(const uint32_t timeout, const uint32_t window, const bool enable_sleep = true); + + + /** Refreshes the watchdog timer. + * + * This function should be called periodically before the watchdog times out. + * Otherwise, the system is reset. + * + * If the watchdog timer is not currently running this function does nothing + */ + void kick(); + + + /** Stops the watchdog timer + * + * Calling this function will attempt to disable any currently running + * watchdog timers if supported by the current platform. + * + * @return Returns WATCHDOG_STATUS_OK if the watchdog timer was succesfully + * stopped, or if the timer was never started. Returns + * WATCHDOG_STATUS_NOT_SUPPORTED if the watchdog cannot be disabled + * on the current platform. + */ + watchdog_status_t stop(); + + + /** Get the watchdog timer refresh value + * + * This function returns the refresh timeout of the watchdog timer. + * + * @return Reload value for the watchdog timer in milliseconds. + */ + uint32_t reload_value() const; + + + /** Get the maximum refresh value for the current platform in milliseconds + * + * @return Maximum refresh value supported by the watchdog for the current + * platform in milliseconds + */ + static uint32_t max_timeout(); +}; + +} // namespace mbed + +/**@}*/ +/**@}*/ + +#endif // DEVICE_WATCHDOG +#endif // MBED_WATCHDOG_H diff --git a/hal/watchdog_api.h b/hal/watchdog_api.h index 8950efab2a2..e403fcaedf3 100644 --- a/hal/watchdog_api.h +++ b/hal/watchdog_api.h @@ -21,10 +21,6 @@ #if DEVICE_WATCHDOG -#if !(DEVICE_RESET_REASON) - #error "Watchdog feature depends on reset reason API also being implemented" -#endif - #include #include @@ -53,7 +49,10 @@ typedef struct /** * Refresh value for the watchdog in milliseconds. The maximum value of this * setting is platform dependent, to find the maximum value for the current - * platform call hal_watchdog_get_max_timeout(void) + * platform call hal_watchdog_get_features() and check the timeout value + * member. The minimum valid value for this setting is 1, attempting to + * initialise the watchdog with a timeout of 0ms will return + * WATCHDOG_STATUS_INVALID_ARGUMENT. */ uint32_t timeout_ms; /** @@ -81,6 +80,36 @@ typedef struct } watchdog_config_t; +typedef struct +{ + /** + * Maximum timeout value for the watchdog in milliseconds. + */ + uint32_t max_timeout; + /** + * Maximum timeout value for the watchdog in milliseconds during window + * operation mode + */ + uint32_t max_timeout_window_mode; + /** + * Watchdog timer supports window mode operation + */ + bool window_mode; + /** + * Watchdog configuration can be updated after the watchdog has been started + */ + bool update_config; + /** + * Watchdog can be stopped after it is started without a reset + */ + bool disable_watchdog; + /** + * Watchdog can be paused while the core is in sleep mode + */ + bool pause_during_sleep; +} watchdog_features_t; + + typedef enum { WATCHDOG_STATUS_OK, WATCHDOG_STATUS_NOT_SUPPORTED, @@ -143,18 +172,12 @@ watchdog_status_t hal_watchdog_stop(void); */ uint32_t hal_watchdog_get_reload_value(void); -/** Checks if the last system reset was caused by a watchdog timer. - * - * @return True if last reset was triggered by a watchdog, False if not. - */ -bool hal_watchdog_caused_last_reset(void); - -/** Get the maximum refresh value for the current platform in milliseconds +/** Get information on the current platforms supported watchdog functionality * - * @return Maximum refresh value supported by the watchdog for the current - * platform in milliseconds + * @return watchdog_feature_t indicating supported watchdog features on the + * current platform */ -uint32_t hal_watchdog_get_max_timeout(void); +watchdog_features_t hal_watchdog_get_platform_features(void); /**@}*/ diff --git a/targets/TARGET_Freescale/TARGET_MCUXpresso_MCUS/TARGET_MCU_K64F/watchdog.c b/targets/TARGET_Freescale/TARGET_MCUXpresso_MCUS/TARGET_MCU_K64F/watchdog.c index e2fd1a7936f..d0e540789ed 100644 --- a/targets/TARGET_Freescale/TARGET_MCUXpresso_MCUS/TARGET_MCU_K64F/watchdog.c +++ b/targets/TARGET_Freescale/TARGET_MCUXpresso_MCUS/TARGET_MCU_K64F/watchdog.c @@ -7,12 +7,12 @@ // Platform specific watchdog definitions #define LPO_CLOCK_FREQUENCY 1000 #define MAX_PRESCALER 8 -#define MAX_TIMEOUT 0xFFFFFFFF +#define MAX_TIMEOUT 0xFFFFFFFFULL // Number of decrements in the timeout register per millisecond #define TICKS_PER_MS (LPO_CLOCK_FREQUENCY / 1000) // Maximum timeout that can be specified in milliseconds -#define MAX_TIMEOUT_MS ((MAX_TIMEOUT / TICKS_PER_MS) * MAX_PRESCALER) +const uint64_t max_timeout_ms = ((MAX_TIMEOUT / TICKS_PER_MS) * MAX_PRESCALER); // Maximum supported watchdog timeout for given prescaler value #define CALCULATE_MAX_TIMEOUT_MS(scale) \ @@ -28,11 +28,11 @@ static uint32_t calculate_prescaler_value(const uint32_t timeout_ms) { - if (timeout_ms > MAX_TIMEOUT_MS) { + if (timeout_ms > max_timeout_ms) { return 0; } - for (uint32_t scale = 1; scale < MAX_PRESCALER; ++scale) { + for (uint32_t scale = 1; scale <= MAX_PRESCALER; ++scale) { if (timeout_ms < CALCULATE_MAX_TIMEOUT_MS(scale)) { return scale; } @@ -49,11 +49,15 @@ watchdog_status_t hal_watchdog_init(const watchdog_config_t *config) return WATCHDOG_STATUS_INVALID_ARGUMENT; } - if (config->timeout_ms > MAX_TIMEOUT_MS) { + if (config->timeout_ms == 0) { return WATCHDOG_STATUS_INVALID_ARGUMENT; } - if (config->window_ms > MAX_TIMEOUT_MS) { + if (config->timeout_ms > max_timeout_ms) { + return WATCHDOG_STATUS_INVALID_ARGUMENT; + } + + if (config->window_ms > max_timeout_ms) { return WATCHDOG_STATUS_INVALID_ARGUMENT; } @@ -114,12 +118,15 @@ uint32_t hal_watchdog_get_reload_value(void) return ((timeout / TICKS_PER_MS) * (prescaler + 1)); } -bool hal_watchdog_caused_last_reset(void) -{ - return (hal_reset_reason_get() == RESET_REASON_WATCHDOG); -} -uint32_t hal_watchdog_get_max_timeout(void) +watchdog_features_t hal_watchdog_get_max_timeout(void) { - return MAX_TIMEOUT_MS; + watchdog_features_t features; + features.max_timeout = max_timeout_ms; + features.max_timeout_window_mode = max_timeout_ms; + features.update_config = true; + features.disable_watchdog = true; + features.pause_during_sleep = true; + + return features; } diff --git a/targets/TARGET_STM/TARGET_STM32F4/watchdog.c b/targets/TARGET_STM/TARGET_STM32F4/watchdog.c index a9ef3375fce..95c394a8174 100644 --- a/targets/TARGET_STM/TARGET_STM32F4/watchdog.c +++ b/targets/TARGET_STM/TARGET_STM32F4/watchdog.c @@ -8,12 +8,13 @@ // Platform specific watchdog definitions #define LPO_CLOCK_FREQUENCY 40000 #define MAX_PRESCALER 256 -#define MAX_TIMEOUT 0xFFF +#define MAX_TIMEOUT 0xFFFULL // Number of decrements in the timeout register per millisecond #define TICKS_PER_MS (LPO_CLOCK_FREQUENCY / 1000) // Maximum timeout that can be specified in milliseconds -#define MAX_TIMEOUT_MS ((MAX_TIMEOUT / TICKS_PER_MS) * MAX_PRESCALER) +const uint64_t max_timeout_ms = ((MAX_TIMEOUT / TICKS_PER_MS) * MAX_PRESCALER); + // Maximum supported watchdog timeout for given prescaler value #define CALCULATE_MAX_TIMEOUT_MS(scale) \ ((MAX_TIMEOUT / TICKS_PER_MS) * scale) @@ -44,6 +45,10 @@ watchdog_status_t hal_watchdog_init(const watchdog_config_t *config) return WATCHDOG_STATUS_INVALID_ARGUMENT; } + if (config->timeout_ms == 0) { + return WATCHDOG_STATUS_INVALID_ARGUMENT; + } + if (config->timeout_ms > MAX_TIMEOUT_MS) { return WATCHDOG_STATUS_INVALID_ARGUMENT; } @@ -103,14 +108,14 @@ uint32_t hal_watchdog_get_reload_value(void) return ((timeout / TICKS_PER_MS) * prescaler); } - -bool hal_watchdog_caused_last_reset(void) -{ - return (hal_reset_reason_get() == RESET_REASON_WATCHDOG); -} - - -uint32_t hal_watchdog_get_max_timeout(void) +watchdog_features_t hal_watchdog_get_max_timeout(void) { - return MAX_TIMEOUT_MS; + watchdog_features_t features; + features.max_timeout = max_timeout_ms; + features.max_timeout_window_mode = max_timeout_ms; + features.update_config = true; + features.disable_watchdog = false; + features.pause_during_sleep = true; + + return features; } From fd005cdebfc6bc7e3e92275aa3317bf3ba6da89d Mon Sep 17 00:00:00 2001 From: Steven Cartmell Date: Mon, 4 Dec 2017 11:38:24 +0000 Subject: [PATCH 11/62] Remove window and sleep mode options for watchdog API --- drivers/ResetReason.h | 19 +++---- drivers/Watchdog.cpp | 13 +---- drivers/Watchdog.h | 35 ++---------- hal/watchdog_api.h | 54 +------------------ .../TARGET_MCU_K64F/watchdog.c | 30 ++--------- targets/TARGET_STM/TARGET_STM32F4/watchdog.c | 27 ++++------ targets/targets.json | 34 +++++++----- 7 files changed, 48 insertions(+), 164 deletions(-) diff --git a/drivers/ResetReason.h b/drivers/ResetReason.h index 7c9f85422ac..54f4ff102d7 100644 --- a/drivers/ResetReason.h +++ b/drivers/ResetReason.h @@ -1,5 +1,3 @@ -/** \addtogroup hal */ -/** @{*/ /* mbed Microcontroller Library * Copyright (c) 2017 ARM Limited * @@ -25,10 +23,11 @@ namespace mbed { /** \addtogroup drivers */ -/** @{*/ -/** - * \defgroup reset_reason reset reason functions - * @{ +/** ResetReason API. When the system is restarted, the reason for the restart is + * contained in the system registers at boot time in a platform specific manner, + * this API provides a generic method of fetching the reason for the restart. + * + * @ingroup drivers */ class ResetReason { @@ -58,20 +57,14 @@ class ResetReason * Example: * @code * if (ResetReason::get() == RESET_REASON_PLATFORM) { - * const uint32_t platform_reason = ResetReason::get_raw(); + * const uint32_t platform_reason = ResetReason::get_raw(); * } * @endcode */ static uint32_t get_raw(); }; - -/**@}*/ -/**@}*/ - } // namespace mbed -/**@}*/ - #endif // DEVICE_RESET_REASON #endif // MBED_RESET_REASON_H diff --git a/drivers/Watchdog.cpp b/drivers/Watchdog.cpp index 358b41003a0..6c8a6edf6dd 100644 --- a/drivers/Watchdog.cpp +++ b/drivers/Watchdog.cpp @@ -20,19 +20,10 @@ namespace mbed { -watchdog_status_t Watchdog::start(const uint32_t timeout, const bool enable_sleep) -{ - return start(timeout, 0, enable_sleep); -} - - -watchdog_status_t Watchdog::start(const uint32_t timeout, const uint32_t window, const bool enable_sleep) +watchdog_status_t Watchdog::start(const uint32_t timeout) { watchdog_config_t config; - config.timeout_ms = timeout; - config.window_ms = window; - config.enable_window = (window != 0); - config.enable_sleep = enable_sleep; + config.timeout_ms = timeout; return hal_watchdog_init(&config); } diff --git a/drivers/Watchdog.h b/drivers/Watchdog.h index dca16740bca..66cefcaed78 100644 --- a/drivers/Watchdog.h +++ b/drivers/Watchdog.h @@ -1,5 +1,3 @@ -/** \addtogroup hal */ -/** @{*/ /* mbed Microcontroller Library * Copyright (c) 2017 ARM Limited * @@ -28,7 +26,6 @@ namespace mbed { /** \addtogroup drivers */ -/** @{*/ /** A system timer that will reset the system in the case of system failures or * malfunctions. * @@ -36,8 +33,7 @@ namespace mbed { * @code * * Watchdog watchdog = Watchdog(); - * watchdog.set_timeout(2000); - * watchdog.start(); + * watchdog.start(2000); * * while (true) { * watchdog.kick(); @@ -45,7 +41,7 @@ namespace mbed { * // Application code * } * @endcode - * + * @ingroup drivers */ class Watchdog { @@ -56,10 +52,6 @@ class Watchdog /** Start an independent watchdog timer with specified parameters * * @param timeout Timeout of the watchdog in milliseconds - * @param enable_sleep Sets sleep mode behaviour. When enabled the watchdog - * will continue to run in sleep mode. When disable the - * watchdog will be paused. This feature is not - * supported on all platforms. * * @return status WATCHDOG_STATUS_OK if the watchdog timer was started * successfully. WATCHDOG_INVALID_ARGUMENT if one of the input @@ -67,25 +59,7 @@ class Watchdog * WATCHDOG_NOT_SUPPORTED if one of the enabled input * parameters is not supported by the current platform. */ - watchdog_status_t start(const uint32_t timeout, const bool enable_sleep = true); - - - /** Start a windowed watchdog timer with specified parameters - * - * @param timeout Timeout of the watchdog in milliseconds - * @param window Time period of the window of the watchdog - * @param enable_sleep Sets sleep mode behaviour. When enabled the watchdog - * will continue to run in sleep mode. When disable the - * watchdog will be paused. This feature is not - * supported on all platforms. - * - * @return status WATCHDOG_STATUS_OK if the watchdog timer was started - * successfully. WATCHDOG_INVALID_ARGUMENT if one of the input - * parameters is out of range for the current platform. - * WATCHDOG_NOT_SUPPORTED if one of the enabled input - * parameters is not supported by the current platform. - */ - watchdog_status_t start(const uint32_t timeout, const uint32_t window, const bool enable_sleep = true); + watchdog_status_t start(const uint32_t timeout); /** Refreshes the watchdog timer. @@ -130,8 +104,5 @@ class Watchdog } // namespace mbed -/**@}*/ -/**@}*/ - #endif // DEVICE_WATCHDOG #endif // MBED_WATCHDOG_H diff --git a/hal/watchdog_api.h b/hal/watchdog_api.h index e403fcaedf3..24396da7b3f 100644 --- a/hal/watchdog_api.h +++ b/hal/watchdog_api.h @@ -35,13 +35,6 @@ * wraps. To prevent the system reset the timer must be continually * kicked/refreshed by calling hal_watchdog_kick which will reset the countdown * to the user specified reset value. - * - * The watchdog timer supports a second mode of operation called windowed mode. - * When configured in this mode by setting enable_window to true, the watchdog - * will enable a restriction on the kick. If the watchdog timer is kicked too - * soon after it has last been refreshed a system reset occurs. The earliest - * time in milliseconds the timer can be kicked without triggering a reset is - * specified by window_ms. */ typedef struct @@ -55,28 +48,6 @@ typedef struct * WATCHDOG_STATUS_INVALID_ARGUMENT. */ uint32_t timeout_ms; - /** - * Configures the watchdog for windowed mode of operation instead of running - * the independent watchdog. In this mode a restriction is placed on the - * time period in which the watchdog can be refreshed/kicked. If the - * watchdog is kicked too soon after it has last been refreshed the system - * will be reset. The period of time in which the reset will be triggered is - * defined by window_ms. This value is false by default. - */ - bool enable_window; - /** - * Specifies the time window for the watchdog window in milliseconds. If the - * watchdog is configured to run in windowed mode kicking the watchdog less - * than this many milliseconds after it has last been kicked will trigger a - * system reset. This value must be less than timeout_ms. - */ - uint32_t window_ms; - /** - * Configures the watchdog behaviour while the system is in sleep mode. When - * this flag is enabled the watchdog timer runs normally while the system is - * in sleep mode, when disabled the watchdog is paused during this time. - */ - bool enable_sleep; } watchdog_config_t; @@ -86,15 +57,6 @@ typedef struct * Maximum timeout value for the watchdog in milliseconds. */ uint32_t max_timeout; - /** - * Maximum timeout value for the watchdog in milliseconds during window - * operation mode - */ - uint32_t max_timeout_window_mode; - /** - * Watchdog timer supports window mode operation - */ - bool window_mode; /** * Watchdog configuration can be updated after the watchdog has been started */ @@ -103,10 +65,6 @@ typedef struct * Watchdog can be stopped after it is started without a reset */ bool disable_watchdog; - /** - * Watchdog can be paused while the core is in sleep mode - */ - bool pause_during_sleep; } watchdog_features_t; @@ -125,12 +83,8 @@ typedef enum { * If the watchdog timer is configured and started successfully this * function will return WATCHDOG_STATUS_OK. * - * If the enable_window is set but windowed mode is not supported by the - * platform the function will return WATCHDOG_STATUS_NOT_SUPPORTED. - * - * If the timeout specified is outside the range supported by the platform, - * or if the window period is greater than the timeout period it will return - * WATCHDOG_STATUS_INVALID_ARGUMENT. + * If the timeout specified is outside the range supported by the platform + * it will return WATCHDOG_STATUS_INVALID_ARGUMENT. * * @param[in] config Configuration settings for the watchdog timer * @@ -144,10 +98,6 @@ watchdog_status_t hal_watchdog_init(const watchdog_config_t *config); * This function should be called periodically before the watchdog times out. * Otherwise, the system is reset. * - * If using the windowed operation mode this function must be called within the - * configured timeout window. If the function is called before the window is - * reached the system is reset. - * * If a watchdog is not currently running this function does nothing */ void hal_watchdog_kick(void); diff --git a/targets/TARGET_Freescale/TARGET_MCUXpresso_MCUS/TARGET_MCU_K64F/watchdog.c b/targets/TARGET_Freescale/TARGET_MCUXpresso_MCUS/TARGET_MCU_K64F/watchdog.c index d0e540789ed..84cabf44ec3 100644 --- a/targets/TARGET_Freescale/TARGET_MCUXpresso_MCUS/TARGET_MCU_K64F/watchdog.c +++ b/targets/TARGET_Freescale/TARGET_MCUXpresso_MCUS/TARGET_MCU_K64F/watchdog.c @@ -19,13 +19,6 @@ const uint64_t max_timeout_ms = ((MAX_TIMEOUT / TICKS_PER_MS) * MAX_PRESCALER); ((MAX_TIMEOUT / TICKS_PER_MS) * scale) -#if defined(FSL_FEATURE_WDOG_HAS_WAITEN) && FSL_FEATURE_WDOG_HAS_WAITEN - #define PLATFORM_SUPPORTS_SLEEP true -#else - #define PLATFORM_SUPPORTS_SLEEP false -#endif - - static uint32_t calculate_prescaler_value(const uint32_t timeout_ms) { if (timeout_ms > max_timeout_ms) { @@ -57,27 +50,15 @@ watchdog_status_t hal_watchdog_init(const watchdog_config_t *config) return WATCHDOG_STATUS_INVALID_ARGUMENT; } - if (config->window_ms > max_timeout_ms) { - return WATCHDOG_STATUS_INVALID_ARGUMENT; - } - - if (config->window_ms > config->timeout_ms) { - return WATCHDOG_STATUS_INVALID_ARGUMENT; - } - - if (config->enable_sleep && !PLATFORM_SUPPORTS_SLEEP) { - return WATCHDOG_STATUS_NOT_SUPPORTED; - } wdog_config_t cfg; cfg.enableWdog = true; cfg.clockSource = kWDOG_LpoClockSource; + cfg.windowValue = 0; cfg.enableUpdate = true; cfg.enableInterrupt = false; - cfg.enableWindowMode = config->enable_window; -#if PLATFORM_SUPPORTS_SLEEP - cfg.workMode.enableWait = config->enable_sleep; -#endif + cfg.enableWindowMode = false; + cfg.workMode.enableWait = true; cfg.workMode.enableStop = false; cfg.workMode.enableDebug = false; @@ -89,7 +70,6 @@ watchdog_status_t hal_watchdog_init(const watchdog_config_t *config) cfg.prescaler = (wdog_clock_prescaler_t)(prescaler - 1); cfg.timeoutValue = (TICKS_PER_MS * config->timeout_ms) / prescaler; - cfg.windowValue = (TICKS_PER_MS * config->window_ms) / prescaler; WDOG_Init(WDOG, &cfg); @@ -119,14 +99,12 @@ uint32_t hal_watchdog_get_reload_value(void) } -watchdog_features_t hal_watchdog_get_max_timeout(void) +watchdog_features_t hal_watchdog_get_platform_features(void) { watchdog_features_t features; features.max_timeout = max_timeout_ms; - features.max_timeout_window_mode = max_timeout_ms; features.update_config = true; features.disable_watchdog = true; - features.pause_during_sleep = true; return features; } diff --git a/targets/TARGET_STM/TARGET_STM32F4/watchdog.c b/targets/TARGET_STM/TARGET_STM32F4/watchdog.c index 95c394a8174..6ee416b1913 100644 --- a/targets/TARGET_STM/TARGET_STM32F4/watchdog.c +++ b/targets/TARGET_STM/TARGET_STM32F4/watchdog.c @@ -2,8 +2,11 @@ #include "reset_reason_api.h" +#ifdef DEVICE_WATCHDOG + #include "device.h" +#include // Platform specific watchdog definitions #define LPO_CLOCK_FREQUENCY 40000 @@ -22,7 +25,7 @@ const uint64_t max_timeout_ms = ((MAX_TIMEOUT / TICKS_PER_MS) * MAX_PRESCALER); static uint32_t calculate_prescaler_value(const uint32_t timeout_ms) { - if (timeout_ms > MAX_TIMEOUT_MS) { + if (timeout_ms > max_timeout_ms) { return 0; } @@ -49,23 +52,10 @@ watchdog_status_t hal_watchdog_init(const watchdog_config_t *config) return WATCHDOG_STATUS_INVALID_ARGUMENT; } - if (config->timeout_ms > MAX_TIMEOUT_MS) { - return WATCHDOG_STATUS_INVALID_ARGUMENT; - } - - if (config->window_ms > MAX_TIMEOUT_MS) { - return WATCHDOG_STATUS_INVALID_ARGUMENT; - } - - if (config->window_ms > config->timeout_ms) { + if (config->timeout_ms > max_timeout_ms) { return WATCHDOG_STATUS_INVALID_ARGUMENT; } - if (config->enable_sleep == false) { - return WATCHDOG_STATUS_NOT_SUPPORTED; - } - - const uint32_t prescaler = calculate_prescaler_value(config->timeout_ms); if (prescaler == 0) { @@ -108,14 +98,15 @@ uint32_t hal_watchdog_get_reload_value(void) return ((timeout / TICKS_PER_MS) * prescaler); } -watchdog_features_t hal_watchdog_get_max_timeout(void) + +watchdog_features_t hal_watchdog_get_platform_features(void) { watchdog_features_t features; features.max_timeout = max_timeout_ms; - features.max_timeout_window_mode = max_timeout_ms; features.update_config = true; features.disable_watchdog = false; - features.pause_during_sleep = true; return features; } + +#endif // DEVICE_WATCHDOG diff --git a/targets/targets.json b/targets/targets.json index 55de7f8021e..a5527c4c795 100644 --- a/targets/targets.json +++ b/targets/targets.json @@ -2302,7 +2302,7 @@ }, "detect_code": ["0720"], "macros_add": ["USB_STM_HAL", "USBHOST_OTHER"], - "device_has_add": ["SERIAL_ASYNCH", "SERIAL_FC", "FLASH", "MPU"], + "device_has_add": ["SERIAL_ASYNCH", "SERIAL_FC", "FLASH", "MPU", "LOWPOWERTIMER", "WATCHDOG"], "release_versions": ["2", "5"], "device_name": "STM32F401RE" }, @@ -2352,7 +2352,8 @@ "SERIAL_FC", "TRNG", "FLASH", - "MPU" + "MPU", + "WATCHDOG" ], "release_versions": ["2", "5"], "device_name": "STM32F410RB" @@ -2376,7 +2377,7 @@ } }, "macros_add": ["USB_STM_HAL", "USBHOST_OTHER"], - "device_has_add": ["SERIAL_ASYNCH", "SERIAL_FC", "FLASH", "MPU"], + "device_has_add": ["SERIAL_ASYNCH", "SERIAL_FC", "FLASH", "MPU", "WATCHDOG"], "release_versions": ["2", "5"], "device_name": "STM32F411RE", "bootloader_supported": true @@ -2401,7 +2402,8 @@ "SERIAL_FC", "TRNG", "FLASH", - "MPU" + "MPU", + "WATCHDOG" ], "release_versions": ["2", "5"], "device_name": "STM32F412ZG", @@ -2527,7 +2529,8 @@ "TRNG", "FLASH", "QSPI", - "MPU" + "MPU", + "WATCHDOG" ], "bootloader_supported": true, "release_versions": ["2", "5"], @@ -2621,7 +2624,8 @@ "SERIAL_FC", "TRNG", "FLASH", - "MPU" + "MPU", + "WATCHDOG" ], "detect_code": ["0796"], "release_versions": ["2", "5"], @@ -2672,7 +2676,8 @@ "SERIAL_FC", "TRNG", "FLASH", - "MPU" + "MPU", + "WATCHDOG", ], "detect_code": ["0797"], "release_versions": ["2", "5"], @@ -2702,7 +2707,8 @@ "SERIAL_ASYNCH", "SERIAL_FC", "FLASH", - "MPU" + "MPU", + "WATCHDOG" ], "release_versions": ["2", "5"], "device_name": "STM32F446RE", @@ -2728,7 +2734,8 @@ "SERIAL_ASYNCH", "SERIAL_FC", "FLASH", - "MPU" + "MPU", + "WATCHDOG" ], "release_versions": ["2", "5"], "device_name": "STM32F446ZE" @@ -2745,7 +2752,8 @@ "SERIAL_ASYNCH", "SERIAL_FC", "FLASH", - "MPU" + "MPU", + "WATCHDOG" ], "release_versions": ["2", "5"], "device_name": "STM32F446VE" @@ -3826,7 +3834,7 @@ "function": "MTSCode.combine_bins_mts_dragonfly", "toolchains": ["GCC_ARM", "ARM_STD", "ARM_MICRO", "IAR"] }, - "device_has_add": ["MPU"], + "device_has_add": ["MPU", "WATCHDOG"], "release_versions": ["2", "5"], "device_name": "STM32F411RE" }, @@ -4016,6 +4024,7 @@ "EMAC", "TRNG", "FLASH", + "WATCHDOG", "WIFI", "SERIAL_FC", "SERIAL" @@ -4111,7 +4120,8 @@ "SERIAL_FC", "TRNG", "FLASH", - "MPU" + "MPU", + "WATCHDOG" ], "public": false, "device_name": "STM32F437VG", From a49b74ef466b215a2f870f09ef745230c7aaba94 Mon Sep 17 00:00:00 2001 From: Steven Cartmell Date: Mon, 8 Jan 2018 12:19:01 +0000 Subject: [PATCH 12/62] Add missing license headers --- .../TARGET_MCU_K64F/reset_reason.c | 15 +++++++++++++++ .../TARGET_MCU_K64F/watchdog.c | 15 +++++++++++++++ targets/TARGET_STM/TARGET_STM32F4/watchdog.c | 16 ++++++++++++++++ targets/TARGET_STM/reset_reason.c | 15 +++++++++++++++ 4 files changed, 61 insertions(+) diff --git a/targets/TARGET_Freescale/TARGET_MCUXpresso_MCUS/TARGET_MCU_K64F/reset_reason.c b/targets/TARGET_Freescale/TARGET_MCUXpresso_MCUS/TARGET_MCU_K64F/reset_reason.c index 924f0f1921a..1a5eb42909c 100644 --- a/targets/TARGET_Freescale/TARGET_MCUXpresso_MCUS/TARGET_MCU_K64F/reset_reason.c +++ b/targets/TARGET_Freescale/TARGET_MCUXpresso_MCUS/TARGET_MCU_K64F/reset_reason.c @@ -1,3 +1,18 @@ +/* mbed Microcontroller Library + * Copyright (c) 2006-2017 ARM Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ #include "reset_reason_api.h" #include "fsl_rcm.h" diff --git a/targets/TARGET_Freescale/TARGET_MCUXpresso_MCUS/TARGET_MCU_K64F/watchdog.c b/targets/TARGET_Freescale/TARGET_MCUXpresso_MCUS/TARGET_MCU_K64F/watchdog.c index 84cabf44ec3..34d6bab1ae5 100644 --- a/targets/TARGET_Freescale/TARGET_MCUXpresso_MCUS/TARGET_MCU_K64F/watchdog.c +++ b/targets/TARGET_Freescale/TARGET_MCUXpresso_MCUS/TARGET_MCU_K64F/watchdog.c @@ -1,3 +1,18 @@ +/* mbed Microcontroller Library + * Copyright (c) 2017 ARM Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ #include "watchdog_api.h" #include "reset_reason_api.h" diff --git a/targets/TARGET_STM/TARGET_STM32F4/watchdog.c b/targets/TARGET_STM/TARGET_STM32F4/watchdog.c index 6ee416b1913..a4550c27671 100644 --- a/targets/TARGET_STM/TARGET_STM32F4/watchdog.c +++ b/targets/TARGET_STM/TARGET_STM32F4/watchdog.c @@ -1,3 +1,19 @@ +/* mbed Microcontroller Library + * Copyright (c) 2006-2017 ARM Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + #include "watchdog_api.h" #include "reset_reason_api.h" diff --git a/targets/TARGET_STM/reset_reason.c b/targets/TARGET_STM/reset_reason.c index 3b7a82863c5..24b1b1fc6c6 100644 --- a/targets/TARGET_STM/reset_reason.c +++ b/targets/TARGET_STM/reset_reason.c @@ -1,3 +1,18 @@ +/* mbed Microcontroller Library + * Copyright (c) 2006-2017 ARM Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ #include "reset_reason_api.h" #ifdef DEVICE_RESET_REASON From c44311fd2f7c96c74e2e7316b5274c092dd154c8 Mon Sep 17 00:00:00 2001 From: Steven Cartmell Date: Mon, 8 Jan 2018 12:49:50 +0000 Subject: [PATCH 13/62] Move watchdog parameter validation into the driver layer --- drivers/Watchdog.cpp | 8 ++++++++ .../TARGET_MCU_K64F/watchdog.c | 14 -------------- targets/TARGET_STM/TARGET_STM32F4/watchdog.c | 13 ------------- 3 files changed, 8 insertions(+), 27 deletions(-) diff --git a/drivers/Watchdog.cpp b/drivers/Watchdog.cpp index 6c8a6edf6dd..36a6dd2e18e 100644 --- a/drivers/Watchdog.cpp +++ b/drivers/Watchdog.cpp @@ -22,6 +22,14 @@ namespace mbed watchdog_status_t Watchdog::start(const uint32_t timeout) { + if (timeout == 0) { + return WATCHDOG_STATUS_INVALID_ARGUMENT; + } + + if (timeout > max_timeout()) { + return WATCHDOG_STATUS_INVALID_ARGUMENT; + } + watchdog_config_t config; config.timeout_ms = timeout; diff --git a/targets/TARGET_Freescale/TARGET_MCUXpresso_MCUS/TARGET_MCU_K64F/watchdog.c b/targets/TARGET_Freescale/TARGET_MCUXpresso_MCUS/TARGET_MCU_K64F/watchdog.c index 34d6bab1ae5..e72f04db30b 100644 --- a/targets/TARGET_Freescale/TARGET_MCUXpresso_MCUS/TARGET_MCU_K64F/watchdog.c +++ b/targets/TARGET_Freescale/TARGET_MCUXpresso_MCUS/TARGET_MCU_K64F/watchdog.c @@ -52,20 +52,6 @@ static uint32_t calculate_prescaler_value(const uint32_t timeout_ms) watchdog_status_t hal_watchdog_init(const watchdog_config_t *config) { - // Validate the input parameters - if (config == NULL) { - return WATCHDOG_STATUS_INVALID_ARGUMENT; - } - - if (config->timeout_ms == 0) { - return WATCHDOG_STATUS_INVALID_ARGUMENT; - } - - if (config->timeout_ms > max_timeout_ms) { - return WATCHDOG_STATUS_INVALID_ARGUMENT; - } - - wdog_config_t cfg; cfg.enableWdog = true; cfg.clockSource = kWDOG_LpoClockSource; diff --git a/targets/TARGET_STM/TARGET_STM32F4/watchdog.c b/targets/TARGET_STM/TARGET_STM32F4/watchdog.c index a4550c27671..ac66d23fcf5 100644 --- a/targets/TARGET_STM/TARGET_STM32F4/watchdog.c +++ b/targets/TARGET_STM/TARGET_STM32F4/watchdog.c @@ -59,19 +59,6 @@ static uint32_t calculate_prescaler_value(const uint32_t timeout_ms) watchdog_status_t hal_watchdog_init(const watchdog_config_t *config) { - // Validate the input parameters - if (config == NULL) { - return WATCHDOG_STATUS_INVALID_ARGUMENT; - } - - if (config->timeout_ms == 0) { - return WATCHDOG_STATUS_INVALID_ARGUMENT; - } - - if (config->timeout_ms > max_timeout_ms) { - return WATCHDOG_STATUS_INVALID_ARGUMENT; - } - const uint32_t prescaler = calculate_prescaler_value(config->timeout_ms); if (prescaler == 0) { From e07b70f8a99c23188d843402f9055ed226ef7962 Mon Sep 17 00:00:00 2001 From: Steven Cartmell Date: Mon, 8 Jan 2018 15:17:45 +0000 Subject: [PATCH 14/62] Fix Watchdog::stop on K64F target WDOG_Disable will suspend the watchdog until a reset is triggered instead of stopping it altogether. Deinit will disable it until it is reinitialized. --- .../TARGET_MCUXpresso_MCUS/TARGET_MCU_K64F/watchdog.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/targets/TARGET_Freescale/TARGET_MCUXpresso_MCUS/TARGET_MCU_K64F/watchdog.c b/targets/TARGET_Freescale/TARGET_MCUXpresso_MCUS/TARGET_MCU_K64F/watchdog.c index e72f04db30b..48ffc50ad1a 100644 --- a/targets/TARGET_Freescale/TARGET_MCUXpresso_MCUS/TARGET_MCU_K64F/watchdog.c +++ b/targets/TARGET_Freescale/TARGET_MCUXpresso_MCUS/TARGET_MCU_K64F/watchdog.c @@ -84,7 +84,7 @@ void hal_watchdog_kick(void) watchdog_status_t hal_watchdog_stop(void) { - WDOG_Disable(WDOG); + WDOG_Deinit(WDOG); return WATCHDOG_STATUS_OK; } From 9f454cc3632b795ff8d9b80faa46bd0ab09cec72 Mon Sep 17 00:00:00 2001 From: Filip Jagodzinski Date: Tue, 9 Jan 2018 17:51:28 +0100 Subject: [PATCH 15/62] K64F: watchdog HAL: Fix max_timeout. Limit MAX_TIMEOUT_MS to UINT32_MAX. Improve MAX_TIMEOUT_MS handling. Fix hal_watchdog_get_platform_features() returning .max_timeout = 0xfffffff8 instead of 0xffffffff. --- .../TARGET_MCU_K64F/watchdog.c | 22 ++++++++++++------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/targets/TARGET_Freescale/TARGET_MCUXpresso_MCUS/TARGET_MCU_K64F/watchdog.c b/targets/TARGET_Freescale/TARGET_MCUXpresso_MCUS/TARGET_MCU_K64F/watchdog.c index 48ffc50ad1a..4f5e2e7c1bd 100644 --- a/targets/TARGET_Freescale/TARGET_MCUXpresso_MCUS/TARGET_MCU_K64F/watchdog.c +++ b/targets/TARGET_Freescale/TARGET_MCUXpresso_MCUS/TARGET_MCU_K64F/watchdog.c @@ -22,26 +22,32 @@ // Platform specific watchdog definitions #define LPO_CLOCK_FREQUENCY 1000 #define MAX_PRESCALER 8 -#define MAX_TIMEOUT 0xFFFFFFFFULL +#define MAX_TIMEOUT 0xFFFFFFFFUL // Number of decrements in the timeout register per millisecond -#define TICKS_PER_MS (LPO_CLOCK_FREQUENCY / 1000) +#define TICKS_PER_MS ((LPO_CLOCK_FREQUENCY) / 1000) + // Maximum timeout that can be specified in milliseconds -const uint64_t max_timeout_ms = ((MAX_TIMEOUT / TICKS_PER_MS) * MAX_PRESCALER); +#define MAX_TIMEOUT_MS_UINT64 (1ULL * ((MAX_TIMEOUT) / (TICKS_PER_MS)) * (MAX_PRESCALER)) +#if (MAX_TIMEOUT_MS_UINT64 > UINT32_MAX) +#define MAX_TIMEOUT_MS UINT32_MAX +#else +#define MAX_TIMEOUT_MS (MAX_TIMEOUT_MS_UINT64 & 0xFFFFFFFFUL) +#endif // Maximum supported watchdog timeout for given prescaler value -#define CALCULATE_MAX_TIMEOUT_MS(scale) \ - ((MAX_TIMEOUT / TICKS_PER_MS) * scale) +#define CALCULATE_MAX_TIMEOUT_MS_UINT64(scale) \ + (1ULL * ((MAX_TIMEOUT) / (TICKS_PER_MS)) * (scale)) static uint32_t calculate_prescaler_value(const uint32_t timeout_ms) { - if (timeout_ms > max_timeout_ms) { + if (timeout_ms > MAX_TIMEOUT_MS) { return 0; } for (uint32_t scale = 1; scale <= MAX_PRESCALER; ++scale) { - if (timeout_ms < CALCULATE_MAX_TIMEOUT_MS(scale)) { + if (timeout_ms <= CALCULATE_MAX_TIMEOUT_MS_UINT64(scale)) { return scale; } } @@ -103,7 +109,7 @@ uint32_t hal_watchdog_get_reload_value(void) watchdog_features_t hal_watchdog_get_platform_features(void) { watchdog_features_t features; - features.max_timeout = max_timeout_ms; + features.max_timeout = MAX_TIMEOUT_MS; features.update_config = true; features.disable_watchdog = true; From 77b3adae63d73a7f918a8821b98fec4b67c617ca Mon Sep 17 00:00:00 2001 From: Steven Cartmell Date: Tue, 16 Jan 2018 14:33:16 +0000 Subject: [PATCH 16/62] Add RESET_REASON and WATCHDOG definitions to hexiwear build target --- targets/targets.json | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/targets/targets.json b/targets/targets.json index a5527c4c795..fc39264689f 100644 --- a/targets/targets.json +++ b/targets/targets.json @@ -1622,6 +1622,7 @@ "PORTINOUT", "PORTOUT", "PWMOUT", + "RESET_REASON", "SERIAL", "SERIAL_ASYNCH", "SERIAL_FC", @@ -1631,7 +1632,8 @@ "SPISLAVE", "STDIO_MESSAGES", "TRNG", - "FLASH" + "FLASH", + "WATCHDOG" ], "default_lib": "std", "release_versions": ["2", "5"], From e94f8b1e6ec0deb4941af1311185316acbb953a5 Mon Sep 17 00:00:00 2001 From: Steven Cartmell Date: Wed, 24 Jan 2018 14:13:28 +0000 Subject: [PATCH 17/62] Rename watchdog.c -> watchdog_api.c to prevent name collision with Platform API --- .../TARGET_MCU_K64F/{watchdog.c => watchdog_api.c} | 0 targets/TARGET_STM/TARGET_STM32F4/{watchdog.c => watchdog_api.c} | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename targets/TARGET_Freescale/TARGET_MCUXpresso_MCUS/TARGET_MCU_K64F/{watchdog.c => watchdog_api.c} (100%) rename targets/TARGET_STM/TARGET_STM32F4/{watchdog.c => watchdog_api.c} (100%) diff --git a/targets/TARGET_Freescale/TARGET_MCUXpresso_MCUS/TARGET_MCU_K64F/watchdog.c b/targets/TARGET_Freescale/TARGET_MCUXpresso_MCUS/TARGET_MCU_K64F/watchdog_api.c similarity index 100% rename from targets/TARGET_Freescale/TARGET_MCUXpresso_MCUS/TARGET_MCU_K64F/watchdog.c rename to targets/TARGET_Freescale/TARGET_MCUXpresso_MCUS/TARGET_MCU_K64F/watchdog_api.c diff --git a/targets/TARGET_STM/TARGET_STM32F4/watchdog.c b/targets/TARGET_STM/TARGET_STM32F4/watchdog_api.c similarity index 100% rename from targets/TARGET_STM/TARGET_STM32F4/watchdog.c rename to targets/TARGET_STM/TARGET_STM32F4/watchdog_api.c From 779796448ddcde652f0fbc253c83b0f891499d3c Mon Sep 17 00:00:00 2001 From: Bartek Szatkowski Date: Tue, 30 Jan 2018 16:36:56 -0600 Subject: [PATCH 18/62] Add definition of reset reason and watchdog doxy groups --- hal/reset_reason_api.h | 5 +++++ hal/watchdog_api.h | 5 +++++ 2 files changed, 10 insertions(+) diff --git a/hal/reset_reason_api.h b/hal/reset_reason_api.h index d2df64a8e2d..aa0333cb190 100644 --- a/hal/reset_reason_api.h +++ b/hal/reset_reason_api.h @@ -26,6 +26,11 @@ extern "C" { #endif +/** + * \defgroup hal_reset_reason Reset Reason HAL API + * @{ + */ + typedef enum { RESET_REASON_POWER_ON, /**< Set when power is initially applied to the board. The power-on-reset circuit causes a POWER_ON reset when this occurs */ RESET_REASON_PIN_RESET, /**< Set when a reset is triggered by the hardware pin on the board */ diff --git a/hal/watchdog_api.h b/hal/watchdog_api.h index 24396da7b3f..51c689eccf0 100644 --- a/hal/watchdog_api.h +++ b/hal/watchdog_api.h @@ -24,6 +24,11 @@ #include #include +/** + * \defgroup hal_watchdog Watchdog HAL API + * @{ + */ + /** \file watchdog_api.h * * This module provides platform independent access to the system watchdog timer From 9392a3db1c915f2c59a4e15d80cc7050635de9dd Mon Sep 17 00:00:00 2001 From: Filip Jagodzinski Date: Thu, 23 Nov 2017 16:18:46 +0100 Subject: [PATCH 19/62] Tests: HAL API: Watchdog: Add tests --- TESTS/host_tests/sync_on_reset.py | 72 ++++++ TESTS/mbed_hal/watchdog/main.cpp | 219 +++++++++++++++++++ TESTS/mbed_hal/watchdog/watchdog_api_tests.h | 101 +++++++++ 3 files changed, 392 insertions(+) create mode 100644 TESTS/host_tests/sync_on_reset.py create mode 100644 TESTS/mbed_hal/watchdog/main.cpp create mode 100644 TESTS/mbed_hal/watchdog/watchdog_api_tests.h diff --git a/TESTS/host_tests/sync_on_reset.py b/TESTS/host_tests/sync_on_reset.py new file mode 100644 index 00000000000..134f3c53351 --- /dev/null +++ b/TESTS/host_tests/sync_on_reset.py @@ -0,0 +1,72 @@ +""" +mbed SDK +Copyright (c) 2017 ARM Limited + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +""" +import time +from mbed_host_tests import BaseHostTest + +DEFAULT_CYCLE_PERIOD = 4.0 + +MSG_VALUE_DUMMY = '0' +MSG_KEY_DEVICE_READY = 'ready' +MSG_KEY_START_CASE = 'start_case' +MSG_KEY_DEVICE_RESET = 'reset_on_case_teardown' +MSG_KEY_SYNC = '__sync' + + +class SyncOnReset(BaseHostTest): + """Host side test that handles device reset during case teardown. + + Given a device that performs a reset during a test case teardown. + When the device notifies the host about the reset. + Then the host: + * keeps track of the test case index of the current test suite, + * performs a dev-host handshake, + * advances the test suite to next test case. + + Note: + Developed for a watchdog test, so that it can be run on devices that + do not support watchdog timeout updates after the initial setup. + As a solution, after testing watchdog with one set of settings, the + device performs a reset and notifies the host with the test case number, + so that the test suite may be advanced once the device boots again. + """ + + def __init__(self): + super(SyncOnReset, self).__init__() + self.test_case_num = 0 + cycle_s = self.get_config_item('program_cycle_s') + self.program_cycle_s = cycle_s if cycle_s is not None else DEFAULT_CYCLE_PERIOD + + def setup(self): + self.register_callback(MSG_KEY_DEVICE_READY, self.cb_device_ready) + self.register_callback(MSG_KEY_DEVICE_RESET, self.cb_device_reset) + + def cb_device_ready(self, key, value, timestamp): + """Advance the device test suite to the next test case.""" + self.send_kv(MSG_KEY_START_CASE, self.test_case_num) + + def cb_device_reset(self, key, value, timestamp): + """Wait for the device to boot and perform a handshake. + + Additionally, keep track of the last test case number. + """ + try: + self.test_case_num = int(value) + except ValueError: + pass + self.test_case_num += 1 + time.sleep(self.program_cycle_s) + self.send_kv(MSG_KEY_SYNC, MSG_VALUE_DUMMY) diff --git a/TESTS/mbed_hal/watchdog/main.cpp b/TESTS/mbed_hal/watchdog/main.cpp new file mode 100644 index 00000000000..bbb2dd7fbbc --- /dev/null +++ b/TESTS/mbed_hal/watchdog/main.cpp @@ -0,0 +1,219 @@ +/* mbed Microcontroller Library + * Copyright (c) 2017 ARM Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#if !DEVICE_WATCHDOG +#error [NOT_SUPPORTED] Watchdog not supported for this target +#endif + +#include "greentea-client/test_env.h" +#include "utest/utest.h" +#include "unity/unity.h" +#include "hal/watchdog_api.h" +#include "watchdog_api_tests.h" + +/* This is platform specific and depends on the watchdog timer implementation, + * e.g. STM32F4 uses 32kHz internal RC oscillator to clock the IWDG, so + * when the prescaler divider is set to max value of 256 the resolution + * drops to 8 ms. + */ +#define WORST_TIMEOUT_RESOLUTION_MS 8UL + +#define TIMEOUT_DELTA_MS (WORST_TIMEOUT_RESOLUTION_MS) +#define WDG_TIMEOUT_MS 500UL + +#define MSG_VALUE_DUMMY "0" +#define MSG_VALUE_LEN 24 +#define MSG_KEY_LEN 24 + +#define MSG_KEY_DEVICE_READY "ready" +#define MSG_KEY_START_CASE "start_case" +#define MSG_KEY_DEVICE_RESET "reset_on_case_teardown" + +int CASE_INDEX_START; +int CASE_INDEX_CURRENT; + +using utest::v1::Case; +using utest::v1::Specification; +using utest::v1::Harness; + +const watchdog_config_t WDG_CONFIG_DEFAULT = { .timeout_ms = WDG_TIMEOUT_MS }; + +void test_max_timeout_is_valid() +{ + TEST_ASSERT(hal_watchdog_get_platform_features().max_timeout > 1UL); +} + +void test_restart_is_possible() +{ + watchdog_features_t features = hal_watchdog_get_platform_features(); + if (!features.disable_watchdog) { + TEST_IGNORE_MESSAGE("Disabling watchdog not supported for this platform"); + return; + } + TEST_ASSERT(features.update_config); +} + +void test_stop() +{ + watchdog_features_t features = hal_watchdog_get_platform_features(); + if (!features.disable_watchdog) { + TEST_ASSERT_EQUAL(WATCHDOG_STATUS_NOT_SUPPORTED, hal_watchdog_stop()); + TEST_IGNORE_MESSAGE("Disabling watchdog not supported for this platform"); + return; + } + + TEST_ASSERT_EQUAL(WATCHDOG_STATUS_OK, hal_watchdog_stop()); + + TEST_ASSERT_EQUAL(WATCHDOG_STATUS_OK, hal_watchdog_init(&WDG_CONFIG_DEFAULT)); + TEST_ASSERT_EQUAL(WATCHDOG_STATUS_OK, hal_watchdog_stop()); + // Make sure that a disabled watchdog does not reset the core. + wait_ms(WDG_TIMEOUT_MS + TIMEOUT_DELTA_MS); + + TEST_ASSERT_EQUAL(WATCHDOG_STATUS_OK, hal_watchdog_stop()); +} + +void test_update_config() +{ + watchdog_features_t features = hal_watchdog_get_platform_features(); + if (!features.update_config) { + TEST_IGNORE_MESSAGE("Updating watchdog config not supported for this platform"); + return; + } + + watchdog_config_t config = WDG_CONFIG_DEFAULT; + TEST_ASSERT_EQUAL(WATCHDOG_STATUS_OK, hal_watchdog_init(&config)); + TEST_ASSERT_UINT32_WITHIN(WORST_TIMEOUT_RESOLUTION_MS, config.timeout_ms, hal_watchdog_get_reload_value()); + + config.timeout_ms = features.max_timeout - 2 * WORST_TIMEOUT_RESOLUTION_MS; + TEST_ASSERT_EQUAL(WATCHDOG_STATUS_OK, hal_watchdog_init(&config)); + TEST_ASSERT_UINT32_WITHIN(WORST_TIMEOUT_RESOLUTION_MS, config.timeout_ms, hal_watchdog_get_reload_value()); + + config.timeout_ms = features.max_timeout; + TEST_ASSERT_EQUAL(WATCHDOG_STATUS_OK, hal_watchdog_init(&config)); + TEST_ASSERT_UINT32_WITHIN(WORST_TIMEOUT_RESOLUTION_MS, config.timeout_ms, hal_watchdog_get_reload_value()); +} + +utest::v1::status_t case_setup_sync_on_reset(const Case * const source, const size_t index_of_case) +{ + CASE_INDEX_CURRENT = index_of_case; + return utest::v1::greentea_case_setup_handler(source, index_of_case); +} + +utest::v1::status_t case_teardown_sync_on_reset(const Case * const source, const size_t passed, const size_t failed, + const utest::v1::failure_t failure) +{ + utest::v1::status_t status = utest::v1::greentea_case_teardown_handler(source, passed, failed, failure); + if (failed) { + /* Return immediately and skip the device reset, if the test case failed. + * Provided that the device won't be restarted by other means (i.e. watchdog timer), + * this should allow the test suite to finish in a defined manner + * and report failure to host. + * In case of watchdog reset during test suite teardown, the loss of serial + * connection is possible, so the host-test-runner may return 'TIMEOUT' + * instead of 'FAIL'. + */ + return status; + } + greentea_send_kv(MSG_KEY_DEVICE_RESET, CASE_INDEX_START + CASE_INDEX_CURRENT); + utest_printf("The device will now restart.\n"); + wait_ms(10); // Wait for the serial buffers to flush. + NVIC_SystemReset(); + return status; // Reset is instant so this line won't be reached. +} + +utest::v1::status_t case_teardown_wdg_stop_or_reset(const Case * const source, const size_t passed, const size_t failed, + const utest::v1::failure_t failure) +{ + watchdog_features_t features = hal_watchdog_get_platform_features(); + if (features.disable_watchdog) { + hal_watchdog_stop(); + return utest::v1::greentea_case_teardown_handler(source, passed, failed, failure); + } + + return case_teardown_sync_on_reset(source, passed, failed, failure); +} + +template +void test_init() +{ + watchdog_config_t config = { timeout_ms }; + TEST_ASSERT_EQUAL(WATCHDOG_STATUS_OK, hal_watchdog_init(&config)); + TEST_ASSERT_UINT32_WITHIN(WORST_TIMEOUT_RESOLUTION_MS, timeout_ms, hal_watchdog_get_reload_value()); +} + +void test_init_max_timeout() +{ + watchdog_features_t features = hal_watchdog_get_platform_features(); + watchdog_config_t config = { .timeout_ms = features.max_timeout }; + TEST_ASSERT_EQUAL(WATCHDOG_STATUS_OK, hal_watchdog_init(&config)); + TEST_ASSERT_UINT32_WITHIN(WORST_TIMEOUT_RESOLUTION_MS, features.max_timeout, hal_watchdog_get_reload_value()); +} + +int testsuite_setup_sync_on_reset(const size_t number_of_cases) +{ + GREENTEA_SETUP(45, "sync_on_reset"); + utest::v1::status_t status = utest::v1::greentea_test_setup_handler(number_of_cases); + if (status != utest::v1::STATUS_CONTINUE) { + return status; + } + + char key[MSG_KEY_LEN + 1] = { }; + char value[MSG_VALUE_LEN + 1] = { }; + + greentea_send_kv(MSG_KEY_DEVICE_READY, MSG_VALUE_DUMMY); + greentea_parse_kv(key, value, MSG_KEY_LEN, MSG_VALUE_LEN); + + if (strcmp(key, MSG_KEY_START_CASE) != 0) { + utest_printf("Invalid message key.\n"); + return utest::v1::STATUS_ABORT; + } + + char *tailptr = NULL; + CASE_INDEX_START = (int) strtol(value, &tailptr, 10); + if (*tailptr != '\0' || CASE_INDEX_START < 0) { + utest_printf("Invalid start case index received from host\n"); + return utest::v1::STATUS_ABORT; + } + + utest_printf("Starting with test case index %i of all %i defined test cases.\n", CASE_INDEX_START, number_of_cases); + return CASE_INDEX_START; +} + +Case cases[] = { + Case("Platform feature max_timeout is valid", test_max_timeout_is_valid), + Case("Stopped watchdog can be started again", test_restart_is_possible), + Case("Watchdog can be stopped", test_stop), + + Case("Update config with multiple init calls", + (utest::v1::case_setup_handler_t) case_setup_sync_on_reset, + test_update_config, + (utest::v1::case_teardown_handler_t) case_teardown_wdg_stop_or_reset), + + // Do not set watchdog timeout shorter than 500 ms as it may cause the + // host-test-runner return 'TIMEOUT' instead of 'FAIL' / 'PASS' if watchdog + // performs reset during test suite teardown. + Case("Init, 500 ms", (utest::v1::case_setup_handler_t) case_setup_sync_on_reset, + test_init<500UL>, (utest::v1::case_teardown_handler_t) case_teardown_sync_on_reset), + Case("Init, max_timeout", (utest::v1::case_setup_handler_t) case_setup_sync_on_reset, + test_init_max_timeout, (utest::v1::case_teardown_handler_t) case_teardown_sync_on_reset), +}; + +Specification specification((utest::v1::test_setup_handler_t) testsuite_setup_sync_on_reset, cases); + +int main() +{ + // Harness will start with a test case index provided by host script. + return !Harness::run(specification); +} diff --git a/TESTS/mbed_hal/watchdog/watchdog_api_tests.h b/TESTS/mbed_hal/watchdog/watchdog_api_tests.h new file mode 100644 index 00000000000..82dfd5795d1 --- /dev/null +++ b/TESTS/mbed_hal/watchdog/watchdog_api_tests.h @@ -0,0 +1,101 @@ +/* mbed Microcontroller Library + * Copyright (c) 2017 ARM Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @addtogroup hal_watchdog_tests + * @{ + */ + +#ifndef MBED_HAL_WATCHDOG_API_TESTS_H +#define MBED_HAL_WATCHDOG_API_TESTS_H + +#if DEVICE_WATCHDOG + +/** Test max_timeout is valid + * + * Given a device supporting watchdog HAL API + * When @a hal_watchdog_get_platform_features() is called + * Then max_timeout member of returned watchdog_features_t struct is greater than 1 + */ +void test_max_timeout_is_valid(); + +/** Test stopped watchdog can be started again + * + * Given a device supporting watchdog HAL API + * When the device supports the @a disable_watchdog feature + * Then the device also supports @a update_config feature + */ +void test_restart_is_possible(); + +/** Test watchdog can be stopped + * + * Given a device without a support for the @a disable_watchdog feature + * When @a hal_watchdog_stop() is called + * Then WATCHDOG_STATUS_NOT_SUPPORTED is returned + * + * Given a device supporting @a disable_watchdog feature + * When watchdog is not running and @a hal_watchdog_stop() is called + * Then WATCHDOG_STATUS_OK is returned + * When watchdog is running + * and @a hal_watchdog_stop() is called before timeout + * Then WATCHDOG_STATUS_OK is returned + * and watchdog does not reset the device + * When watchdog has already been stopped and @a hal_watchdog_stop() is called + * Then WATCHDOG_STATUS_OK is returned + */ +void test_stop(); + +/** Test update config with multiple init calls + * + * Given @a max_timeout value returned by @a hal_watchdog_get_platform_features() + * and @a hal_watchdog_init() called multiple times with same @a config + * When @a config.timeout_ms is set to WDG_CONFIG_DEFAULT + * Then return value of hal_watchdog_init() is @a WATCHDOG_STATUS_OK + * and @a hal_watchdog_get_reload_value() returns WDG_CONFIG_DEFAULT + * When @a config.timeout_ms is set to max_timeout-delta + * Then return value of hal_watchdog_init() is @a WATCHDOG_STATUS_OK + * and @a hal_watchdog_get_reload_value() returns max_timeout-delta + * When @a config.timeout_ms is set to max_timeout + * Then return value of hal_watchdog_init() is @a WATCHDOG_STATUS_OK + * and @a hal_watchdog_get_reload_value() returns max_timeout + */ +void test_update_config(); + +/** Test init with a valid config + * + * Given a device supporting watchdog HAL API + * When @a config.timeout_ms is set to value X within platform's timeout range + * Then return value of hal_watchdog_init() is @a WATCHDOG_STATUS_OK + * and @a hal_watchdog_get_reload_value() returns X + */ +template +void test_init(); + +/** Test init with a max_timeout + * + * Given @a max_timeout value returned by @a hal_watchdog_get_platform_features() + * When @a config.timeout_ms is set to max_timeout + * Then return value of hal_watchdog_init() is @a WATCHDOG_STATUS_OK + * and @a hal_watchdog_get_reload_value() returns max_timeout + */ +void test_init_max_timeout(); + +#endif + +#endif + +/** @}*/ + From 47e47a5ca810300a8f2117cc02caa8db42036650 Mon Sep 17 00:00:00 2001 From: Filip Jagodzinski Date: Mon, 11 Dec 2017 13:46:13 +0100 Subject: [PATCH 20/62] Tests: HAL API: Watchdog: Add dev reset tests --- TESTS/host_tests/watchdog_reset.py | 96 ++++++ TESTS/mbed_hal/watchdog_reset/main.cpp | 286 ++++++++++++++++++ .../watchdog_reset/watchdog_reset_tests.h | 77 +++++ 3 files changed, 459 insertions(+) create mode 100644 TESTS/host_tests/watchdog_reset.py create mode 100644 TESTS/mbed_hal/watchdog_reset/main.cpp create mode 100644 TESTS/mbed_hal/watchdog_reset/watchdog_reset_tests.h diff --git a/TESTS/host_tests/watchdog_reset.py b/TESTS/host_tests/watchdog_reset.py new file mode 100644 index 00000000000..637055f68fc --- /dev/null +++ b/TESTS/host_tests/watchdog_reset.py @@ -0,0 +1,96 @@ +""" +mbed SDK +Copyright (c) 2017 ARM Limited + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +""" +import collections +import threading +from mbed_host_tests import BaseHostTest + +TestCaseData = collections.namedtuple('TestCaseData', ['index', 'data_to_send']) + +DEFAULT_CYCLE_PERIOD = 4.0 + +MSG_VALUE_DUMMY = '0' +CASE_DATA_INVALID = 0xffffffff +CASE_DATA_PHASE2_OK = 0xfffffffe + +MSG_KEY_SYNC = '__sync' +MSG_KEY_DEVICE_READY = 'ready' +MSG_KEY_START_CASE = 'start_case' +MSG_KEY_DEVICE_RESET = 'dev_reset' + + +class WatchdogReset(BaseHostTest): + """Host side test that handles device reset. + + Given a device with a watchdog timer started. + When the device notifies the host about an incoming reset. + Then the host: + * keeps track of the test case index of the current test suite, + * performs a dev-host handshake. + """ + + def __init__(self): + super(WatchdogReset, self).__init__() + self.current_case = TestCaseData(0, CASE_DATA_INVALID) + self.__handshake_timer = None + cycle_s = self.get_config_item('program_cycle_s') + self.program_cycle_s = cycle_s if cycle_s is not None else DEFAULT_CYCLE_PERIOD + + def handshake_timer_start(self, seconds=1.0): + """Start a new handshake timer. + + Perform a dev-host handshake by sending a sync message. + """ + self.__handshake_timer = threading.Timer(seconds, self.send_kv, + [MSG_KEY_SYNC, MSG_VALUE_DUMMY]) + self.__handshake_timer.start() + + def handshake_timer_cancel(self): + """Cancel the current handshake timer.""" + try: + self.__handshake_timer.cancel() + except AttributeError: + pass + finally: + self.__handshake_timer = None + + def setup(self): + self.register_callback(MSG_KEY_DEVICE_READY, self.cb_device_ready) + self.register_callback(MSG_KEY_DEVICE_RESET, self.cb_device_reset) + + def teardown(self): + self.handshake_timer_cancel() + + def cb_device_ready(self, key, value, timestamp): + """Advance the device test suite to a proper test case. + + Additionally, send test case data to the device. + """ + self.handshake_timer_cancel() + msg_value = '{0.index:02x},{0.data_to_send:08x}'.format(self.current_case) + self.send_kv(MSG_KEY_START_CASE, msg_value) + + def cb_device_reset(self, key, value, timestamp): + """Keep track of the test case number. + + Also set a new handshake timeout, so when the device gets + restarted by the watchdog, the communication will be restored + by the __handshake_timer. + """ + self.handshake_timer_cancel() + case_num, dev_reset_delay_ms = (int(i, base=16) for i in value.split(',')) + self.current_case = TestCaseData(case_num, CASE_DATA_PHASE2_OK) + self.handshake_timer_start(self.program_cycle_s + dev_reset_delay_ms / 1000.0) diff --git a/TESTS/mbed_hal/watchdog_reset/main.cpp b/TESTS/mbed_hal/watchdog_reset/main.cpp new file mode 100644 index 00000000000..edaf66dea2e --- /dev/null +++ b/TESTS/mbed_hal/watchdog_reset/main.cpp @@ -0,0 +1,286 @@ +/* mbed Microcontroller Library + * Copyright (c) 2017 ARM Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#if !DEVICE_WATCHDOG +#error [NOT_SUPPORTED] Watchdog not supported for this target +#endif + +#include "greentea-client/test_env.h" +#include "utest/utest.h" +#include "unity/unity.h" +#include "hal/watchdog_api.h" +#include "watchdog_reset_tests.h" +#include "mbed.h" + +#define TIMEOUT_MS 500UL +#define TIMEOUT_DELTA_MS 50UL + +#define MSG_VALUE_DUMMY "0" +#define CASE_DATA_INVALID 0xffffffffUL +#define CASE_DATA_PHASE2_OK 0xfffffffeUL + +#define MSG_VALUE_LEN 24 +#define MSG_KEY_LEN 24 + +#define MSG_KEY_DEVICE_READY "ready" +#define MSG_KEY_START_CASE "start_case" +#define MSG_KEY_DEVICE_RESET "dev_reset" + +using utest::v1::Case; +using utest::v1::Specification; +using utest::v1::Harness; + +struct testcase_data { + int index; + int start_index; + uint32_t received_data; +}; + +void release_sem(Semaphore *sem) +{ + sem->release(); +} + +testcase_data current_case; + +bool send_reset_notification(testcase_data * tcdata, uint32_t delay_ms) +{ + char msg_value[12]; + int str_len = snprintf(msg_value, sizeof msg_value, "%02x,%08lx", tcdata->start_index + tcdata->index, delay_ms); + if (str_len != (sizeof msg_value) - 1) { + utest_printf("Failed to compose a value string to be sent to host."); + return false; + } + greentea_send_kv(MSG_KEY_DEVICE_RESET, msg_value); + return true; +} + +void test_simple_reset() +{ + // Phase 2. -- verify the test results. + // Verify if this test case passed based on data received from host. + if (current_case.received_data != CASE_DATA_INVALID) { + TEST_ASSERT_EQUAL(CASE_DATA_PHASE2_OK, current_case.received_data); + current_case.received_data = CASE_DATA_INVALID; + return; + } + + // Phase 1. -- run the test code. + // Init the watchdog and wait for a device reset. + watchdog_config_t config = { TIMEOUT_MS }; + if (send_reset_notification(¤t_case, TIMEOUT_MS + TIMEOUT_DELTA_MS) == false) { + TEST_ASSERT_MESSAGE(0, "Dev-host communication error."); + return; + } + TEST_ASSERT_EQUAL(WATCHDOG_STATUS_OK, hal_watchdog_init(&config)); + wait_ms(TIMEOUT_MS + TIMEOUT_DELTA_MS); // Device reset expected. + + // Watchdog reset should have occurred during wait_ms() above; + + hal_watchdog_kick(); // Just to buy some time for testsuite failure handling. + TEST_ASSERT_MESSAGE(0, "Watchdog did not reset the device as expected."); +} + +#if DEVICE_SLEEP +void test_sleep_reset() +{ + // Phase 2. -- verify the test results. + if (current_case.received_data != CASE_DATA_INVALID) { + TEST_ASSERT_EQUAL(CASE_DATA_PHASE2_OK, current_case.received_data); + current_case.received_data = CASE_DATA_INVALID; + return; + } + + // Phase 1. -- run the test code. + watchdog_config_t config = { TIMEOUT_MS }; + Semaphore sem(0, 1); + Timeout timeout; + if (send_reset_notification(¤t_case, TIMEOUT_MS + TIMEOUT_DELTA_MS) == false) { + TEST_ASSERT_MESSAGE(0, "Dev-host communication error."); + return; + } + TEST_ASSERT_EQUAL(WATCHDOG_STATUS_OK, hal_watchdog_init(&config)); + sleep_manager_lock_deep_sleep(); + timeout.attach_us(mbed::callback(release_sem, &sem), 1000ULL * (TIMEOUT_MS + TIMEOUT_DELTA_MS)); + if (sleep_manager_can_deep_sleep()) { + TEST_ASSERT_MESSAGE(0, "Deepsleep should be disallowed."); + return; + } + while (sem.wait(0) != 1) { + sleep(); // Device reset expected. + } + sleep_manager_unlock_deep_sleep(); + + // Watchdog reset should have occurred during sleep() above; + + hal_watchdog_kick(); // Just to buy some time for testsuite failure handling. + TEST_ASSERT_MESSAGE(0, "Watchdog did not reset the device as expected."); +} + +#if DEVICE_LOWPOWERTIMER +void test_deepsleep_reset() +{ + // Phase 2. -- verify the test results. + if (current_case.received_data != CASE_DATA_INVALID) { + TEST_ASSERT_EQUAL(CASE_DATA_PHASE2_OK, current_case.received_data); + current_case.received_data = CASE_DATA_INVALID; + return; + } + + // Phase 1. -- run the test code. + watchdog_config_t config = { TIMEOUT_MS }; + Semaphore sem(0, 1); + LowPowerTimeout lp_timeout; + if (send_reset_notification(¤t_case, TIMEOUT_MS + TIMEOUT_DELTA_MS) == false) { + TEST_ASSERT_MESSAGE(0, "Dev-host communication error."); + return; + } + TEST_ASSERT_EQUAL(WATCHDOG_STATUS_OK, hal_watchdog_init(&config)); + lp_timeout.attach_us(mbed::callback(release_sem, &sem), 1000ULL * (TIMEOUT_MS + TIMEOUT_DELTA_MS)); + wait_ms(10); // Wait for the serial buffers to flush. + if (!sleep_manager_can_deep_sleep()) { + TEST_ASSERT_MESSAGE(0, "Deepsleep should be allowed."); + } + while (sem.wait(0) != 1) { + sleep(); // Device reset expected. + } + + // Watchdog reset should have occurred during that sleep() above; + + hal_watchdog_kick(); // Just to buy some time for testsuite failure handling. + TEST_ASSERT_MESSAGE(0, "Watchdog did not reset the device as expected."); +} +#endif +#endif + +void test_restart_reset() +{ + watchdog_features_t features = hal_watchdog_get_platform_features(); + if (!features.disable_watchdog) { + TEST_IGNORE_MESSAGE("Disabling watchdog not supported for this platform"); + return; + } + + // Phase 2. -- verify the test results. + if (current_case.received_data != CASE_DATA_INVALID) { + TEST_ASSERT_EQUAL(CASE_DATA_PHASE2_OK, current_case.received_data); + current_case.received_data = CASE_DATA_INVALID; + return; + } + + // Phase 1. -- run the test code. + watchdog_config_t config = { TIMEOUT_MS }; + TEST_ASSERT_EQUAL(WATCHDOG_STATUS_OK, hal_watchdog_init(&config)); + wait_ms(TIMEOUT_MS / 2UL); + TEST_ASSERT_EQUAL(WATCHDOG_STATUS_OK, hal_watchdog_stop()); + // Check that stopping the watchdog prevents a device reset. + wait_ms(TIMEOUT_MS / 2UL + TIMEOUT_DELTA_MS); + + if (send_reset_notification(¤t_case, TIMEOUT_MS + TIMEOUT_DELTA_MS) == false) { + TEST_ASSERT_MESSAGE(0, "Dev-host communication error."); + return; + } + TEST_ASSERT_EQUAL(WATCHDOG_STATUS_OK, hal_watchdog_init(&config)); + wait_ms(TIMEOUT_MS + TIMEOUT_DELTA_MS); // Device reset expected. + + // Watchdog reset should have occurred during that wait() above; + + hal_watchdog_kick(); // Just to buy some time for testsuite failure handling. + TEST_ASSERT_MESSAGE(0, "Watchdog did not reset the device as expected."); +} + +void test_kick_reset() +{ + // Phase 2. -- verify the test results. + if (current_case.received_data != CASE_DATA_INVALID) { + TEST_ASSERT_EQUAL(CASE_DATA_PHASE2_OK, current_case.received_data); + current_case.received_data = CASE_DATA_INVALID; + return; + } + + // Phase 1. -- run the test code. + watchdog_config_t config = { TIMEOUT_MS }; + TEST_ASSERT_EQUAL(WATCHDOG_STATUS_OK, hal_watchdog_init(&config)); + for (int i = 3; i; i--) { + wait_ms(TIMEOUT_MS / 2UL); + hal_watchdog_kick(); + } + if (send_reset_notification(¤t_case, TIMEOUT_MS + TIMEOUT_DELTA_MS) == false) { + TEST_ASSERT_MESSAGE(0, "Dev-host communication error."); + return; + } + wait_ms(TIMEOUT_MS + TIMEOUT_DELTA_MS); // Device reset expected. + + // Watchdog reset should have occurred during that wait() above; + + hal_watchdog_kick(); // Just to buy some time for testsuite failure handling. + TEST_ASSERT_MESSAGE(0, "Watchdog did not reset the device as expected."); +} + +utest::v1::status_t case_setup(const Case * const source, const size_t index_of_case) +{ + current_case.index = index_of_case; + return utest::v1::greentea_case_setup_handler(source, index_of_case); +} + +int testsuite_setup(const size_t number_of_cases) +{ + GREENTEA_SETUP(90, "watchdog_reset"); + utest::v1::status_t status = utest::v1::greentea_test_setup_handler(number_of_cases); + if (status != utest::v1::STATUS_CONTINUE) { + return status; + } + + char key[MSG_KEY_LEN + 1] = { }; + char value[MSG_VALUE_LEN + 1] = { }; + + greentea_send_kv(MSG_KEY_DEVICE_READY, MSG_VALUE_DUMMY); + greentea_parse_kv(key, value, MSG_KEY_LEN, MSG_VALUE_LEN); + + if (strcmp(key, MSG_KEY_START_CASE) != 0) { + utest_printf("Invalid message key.\n"); + return utest::v1::STATUS_ABORT; + } + + int num_args = sscanf(value, "%02x,%08lx", &(current_case.start_index), &(current_case.received_data)); + if (num_args == 0 || num_args == EOF) { + utest_printf("Invalid data received from host\n"); + return utest::v1::STATUS_ABORT; + } + + utest_printf("This test suite is composed of %i test cases. Starting at index %i.\n", number_of_cases, + current_case.start_index); + return current_case.start_index; +} + +Case cases[] = { + Case("Watchdog reset", case_setup, test_simple_reset), +#if DEVICE_SLEEP + Case("Watchdog reset in sleep mode", case_setup, test_sleep_reset), +#if DEVICE_LOWPOWERTIMER + Case("Watchdog reset in deepsleep mode", case_setup, test_deepsleep_reset), +#endif +#endif + Case("Watchdog started again", case_setup, test_restart_reset), + Case("Kicking the watchdog prevents reset", case_setup, test_kick_reset), +}; + +Specification specification((utest::v1::test_setup_handler_t) testsuite_setup, cases); + +int main() +{ + // Harness will start with a test case index provided by host script. + return !Harness::run(specification); +} diff --git a/TESTS/mbed_hal/watchdog_reset/watchdog_reset_tests.h b/TESTS/mbed_hal/watchdog_reset/watchdog_reset_tests.h new file mode 100644 index 00000000000..a90e0b95a2e --- /dev/null +++ b/TESTS/mbed_hal/watchdog_reset/watchdog_reset_tests.h @@ -0,0 +1,77 @@ +/* mbed Microcontroller Library + * Copyright (c) 2017 ARM Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @addtogroup hal_watchdog_tests + * @{ + */ + +#ifndef MBED_HAL_WATCHDOG_RESET_TESTS_H +#define MBED_HAL_WATCHDOG_RESET_TESTS_H + +#if DEVICE_WATCHDOG + +/** Test watchdog reset + * + * Given a device with a watchdog started + * When a watchdog timeout expires + * Then the device is restarted + */ +void test_simple_reset(); + +/** Test watchdog reset in sleep mode + * + * Given a device supporting sleep mode, with a watchdog started + * When the device is in sleep mode and watchdog timeout expires + * Then the device is restarted + */ +void test_sleep_reset(); + +/** Test watchdog reset in deepsleep mode + * + * Given a device supporting deepsleep mode, with watchdog started + * When the device is in deepsleep mode and watchdog timeout expires + * Then the device is restarted + */ +void test_deepsleep_reset(); + +/** Test stopped watchdog can be started again and reset the device + * + * Given a device supporting 'disable_watchdog' feature, with watchdog started + * When the watchdog is stopped before timeout expires + * Then the device is not restarted + * When the watchdog is started again and it's timeout expires + * Then the device is restarted + */ +void test_restart_reset(); + +/** Test kicking the watchdog prevents reset + * + * Given a device with watchdog started + * When the watchdog is kicked before timeout expires + * Then the device restart is prevented + * When the watchdog is *NOT* kicked again before next timeout expires + * Then the device is restarted + * + */ +void test_kick_reset(); + +#endif + +#endif + +/** @}*/ + From bbb3a7af3f705b1b0537aa6be78e60f731e9b29e Mon Sep 17 00:00:00 2001 From: Filip Jagodzinski Date: Mon, 15 Jan 2018 10:35:45 +0100 Subject: [PATCH 21/62] Tests: HAL API: Watchdog: Add time accuracy tests --- TESTS/host_tests/watchdog_reset.py | 60 ++++++- TESTS/mbed_hal/watchdog_timing/main.cpp | 148 ++++++++++++++++++ .../watchdog_timing/watchdog_timing_tests.h | 47 ++++++ 3 files changed, 249 insertions(+), 6 deletions(-) create mode 100644 TESTS/mbed_hal/watchdog_timing/main.cpp create mode 100644 TESTS/mbed_hal/watchdog_timing/watchdog_timing_tests.h diff --git a/TESTS/host_tests/watchdog_reset.py b/TESTS/host_tests/watchdog_reset.py index 637055f68fc..c8f32168213 100644 --- a/TESTS/host_tests/watchdog_reset.py +++ b/TESTS/host_tests/watchdog_reset.py @@ -21,15 +21,18 @@ TestCaseData = collections.namedtuple('TestCaseData', ['index', 'data_to_send']) DEFAULT_CYCLE_PERIOD = 4.0 +MAX_HB_PERIOD = 2.5 # [s] Max expected heartbeat period. MSG_VALUE_DUMMY = '0' CASE_DATA_INVALID = 0xffffffff CASE_DATA_PHASE2_OK = 0xfffffffe +CASE_DATA_INSUFF_HB = 0x0 MSG_KEY_SYNC = '__sync' MSG_KEY_DEVICE_READY = 'ready' MSG_KEY_START_CASE = 'start_case' MSG_KEY_DEVICE_RESET = 'dev_reset' +MSG_KEY_HEARTBEAT = 'hb' class WatchdogReset(BaseHostTest): @@ -48,14 +51,19 @@ def __init__(self): self.__handshake_timer = None cycle_s = self.get_config_item('program_cycle_s') self.program_cycle_s = cycle_s if cycle_s is not None else DEFAULT_CYCLE_PERIOD + self.drop_heartbeat_messages = True + self.hb_timestamps_us = [] - def handshake_timer_start(self, seconds=1.0): - """Start a new handshake timer. + def handshake_timer_start(self, seconds=1.0, pre_sync_fun=None): + """Start a new handshake timer.""" - Perform a dev-host handshake by sending a sync message. - """ - self.__handshake_timer = threading.Timer(seconds, self.send_kv, - [MSG_KEY_SYNC, MSG_VALUE_DUMMY]) + def timer_handler(): + """Perform a dev-host handshake by sending a sync message.""" + if pre_sync_fun is not None: + pre_sync_fun() + self.send_kv(MSG_KEY_SYNC, MSG_VALUE_DUMMY) + + self.__handshake_timer = threading.Timer(seconds, timer_handler) self.__handshake_timer.start() def handshake_timer_cancel(self): @@ -67,9 +75,28 @@ def handshake_timer_cancel(self): finally: self.__handshake_timer = None + def heartbeat_timeout_handler(self): + """Handler for the heartbeat timeout. + + Compute the time span of the last heartbeat sequence. + Set self.current_case.data_to_send to CASE_DATA_INVALID if no heartbeat was received. + Set self.current_case.data_to_send to CASE_DATA_INSUFF_HB if only one heartbeat was + received. + """ + self.drop_heartbeat_messages = True + dev_data = CASE_DATA_INVALID + if len(self.hb_timestamps_us) == 1: + dev_data = CASE_DATA_INSUFF_HB + self.log('Not enough heartbeats received.') + elif len(self.hb_timestamps_us) >= 2: + dev_data = int(round(0.001 * (self.hb_timestamps_us[-1] - self.hb_timestamps_us[0]))) + self.log('Heartbeat time span was {} ms.'.format(dev_data)) + self.current_case = TestCaseData(self.current_case.index, dev_data) + def setup(self): self.register_callback(MSG_KEY_DEVICE_READY, self.cb_device_ready) self.register_callback(MSG_KEY_DEVICE_RESET, self.cb_device_reset) + self.register_callback(MSG_KEY_HEARTBEAT, self.cb_heartbeat) def teardown(self): self.handshake_timer_cancel() @@ -82,6 +109,8 @@ def cb_device_ready(self, key, value, timestamp): self.handshake_timer_cancel() msg_value = '{0.index:02x},{0.data_to_send:08x}'.format(self.current_case) self.send_kv(MSG_KEY_START_CASE, msg_value) + self.drop_heartbeat_messages = False + self.hb_timestamps_us = [] def cb_device_reset(self, key, value, timestamp): """Keep track of the test case number. @@ -94,3 +123,22 @@ def cb_device_reset(self, key, value, timestamp): case_num, dev_reset_delay_ms = (int(i, base=16) for i in value.split(',')) self.current_case = TestCaseData(case_num, CASE_DATA_PHASE2_OK) self.handshake_timer_start(self.program_cycle_s + dev_reset_delay_ms / 1000.0) + + def cb_heartbeat(self, key, value, timestamp): + """Save the timestamp of a heartbeat message. + + Additionally, keep track of the test case number. + + Also each heartbeat sets a new timeout, so when the device gets + restarted by the watchdog, the communication will be restored + by the __handshake_timer. + """ + if self.drop_heartbeat_messages: + return + self.handshake_timer_cancel() + case_num, timestamp_us = (int(i, base=16) for i in value.split(',')) + self.current_case = TestCaseData(case_num, CASE_DATA_INVALID) + self.hb_timestamps_us.append(timestamp_us) + self.handshake_timer_start( + seconds=(MAX_HB_PERIOD + self.program_cycle_s), + pre_sync_fun=self.heartbeat_timeout_handler) diff --git a/TESTS/mbed_hal/watchdog_timing/main.cpp b/TESTS/mbed_hal/watchdog_timing/main.cpp new file mode 100644 index 00000000000..ffc657c0fd6 --- /dev/null +++ b/TESTS/mbed_hal/watchdog_timing/main.cpp @@ -0,0 +1,148 @@ +/* mbed Microcontroller Library + * Copyright (c) 2018 ARM Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#if !DEVICE_WATCHDOG +#error [NOT_SUPPORTED] Watchdog not supported for this target +#endif + +#include "greentea-client/test_env.h" +#include "utest/utest.h" +#include "unity/unity.h" +#include "hal/watchdog_api.h" +#include "watchdog_timing_tests.h" + +#define MSG_VALUE_DUMMY "0" +#define CASE_DATA_INVALID 0xffffffffUL + +#define MSG_VALUE_LEN 24 +#define MSG_KEY_LEN 24 + +#define MSG_KEY_DEVICE_READY "ready" +#define MSG_KEY_START_CASE "start_case" +#define MSG_KEY_HEARTBEAT "hb" + +using utest::v1::Case; +using utest::v1::Specification; +using utest::v1::Harness; + +struct testcase_data { + int index; + int start_index; + uint32_t received_data; +}; + +testcase_data current_case; + +template +void test_timing() +{ + // Phase 2. -- verify the test results. + // Verify the heartbeat time span sent by host is within given delta. + if (current_case.received_data != CASE_DATA_INVALID) { + TEST_ASSERT_UINT32_WITHIN(delta_ms, timeout_ms, current_case.received_data); + current_case.received_data = CASE_DATA_INVALID; + return; + } + + // Phase 1. -- run the test code. + // Send heartbeat messages to host until the watchdeg resets the device. + const ticker_data_t * const us_ticker = get_us_ticker_data(); + us_timestamp_t current_ts, next_ts, expected_reset_ts, divider, ts_increment; + char msg_value[12]; + + watchdog_config_t config = { timeout_ms }; + TEST_ASSERT_EQUAL(WATCHDOG_STATUS_OK, hal_watchdog_init(&config)); + next_ts = ticker_read_us(us_ticker); + expected_reset_ts = next_ts + 1000ULL * timeout_ms; + + divider = 0x2ULL; + while (1) { + current_ts = ticker_read_us(us_ticker); + if (current_ts < next_ts) { + continue; + } + + int str_len = snprintf(msg_value, sizeof msg_value, "%02x,%08lx", current_case.start_index + current_case.index, + (uint32_t) current_ts); + if (str_len != (sizeof msg_value) - 1) { + utest_printf("Failed to compose a value string to be sent to host."); + return; + } + greentea_send_kv(MSG_KEY_HEARTBEAT, msg_value); + + // The closer to expected reset, the smaller heartbeat time difference. + // This should reduce measurement error present for heartbeat with + // equal periods. + ts_increment = (1000ULL * timeout_ms / divider); + next_ts += ts_increment; + + if (current_ts <= expected_reset_ts) { + divider <<= 1; + } else if (divider > 0x2ULL) { + divider >>= 1; + } + } +} + +utest::v1::status_t case_setup(const Case * const source, const size_t index_of_case) +{ + current_case.index = index_of_case; + return utest::v1::greentea_case_setup_handler(source, index_of_case); +} + +int testsuite_setup(const size_t number_of_cases) +{ + GREENTEA_SETUP(90, "watchdog_reset"); + utest::v1::status_t status = utest::v1::greentea_test_setup_handler(number_of_cases); + if (status != utest::v1::STATUS_CONTINUE) { + return status; + } + + char key[MSG_KEY_LEN + 1] = { }; + char value[MSG_VALUE_LEN + 1] = { }; + + greentea_send_kv(MSG_KEY_DEVICE_READY, MSG_VALUE_DUMMY); + greentea_parse_kv(key, value, MSG_KEY_LEN, MSG_VALUE_LEN); + + if (strcmp(key, MSG_KEY_START_CASE) != 0) { + utest_printf("Invalid message key.\n"); + return utest::v1::STATUS_ABORT; + } + + int num_args = sscanf(value, "%02x,%08lx", &(current_case.start_index), &(current_case.received_data)); + if (num_args == 0 || num_args == EOF) { + utest_printf("Invalid data received from host\n"); + return utest::v1::STATUS_ABORT; + } + + utest_printf("This test suite is composed of %i test cases. Starting at index %i.\n", number_of_cases, + current_case.start_index); + return current_case.start_index; +} + +Case cases[] = { + Case("Timing, 200 ms", case_setup, test_timing<200UL, 55UL>), + Case("Timing, 500 ms", case_setup, test_timing<500UL, 65UL>), + Case("Timing, 1000 ms", case_setup, test_timing<1000UL, 130UL>), + Case("Timing, 3000 ms", case_setup, test_timing<3000UL, 190UL>), +}; + +Specification specification((utest::v1::test_setup_handler_t) testsuite_setup, cases); + +int main() +{ + // Harness will start with a test case index provided by host script. + return !Harness::run(specification); +} diff --git a/TESTS/mbed_hal/watchdog_timing/watchdog_timing_tests.h b/TESTS/mbed_hal/watchdog_timing/watchdog_timing_tests.h new file mode 100644 index 00000000000..7ea8bdf4753 --- /dev/null +++ b/TESTS/mbed_hal/watchdog_timing/watchdog_timing_tests.h @@ -0,0 +1,47 @@ +/* mbed Microcontroller Library + * Copyright (c) 2018 ARM Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @addtogroup hal_watchdog_tests + * @{ + */ + +#ifndef MBED_HAL_WATCHDOG_TIMING_TESTS_H +#define MBED_HAL_WATCHDOG_TIMING_TESTS_H + +#if DEVICE_WATCHDOG + +/** Test watchdog timing accuracy + * + * Phase 1. + * Given a watchdog timer started with a timeout value of X ms + * When given time of X ms elapses + * Then the device is restarted by the watchdog + * + * Phase 2. + * Given a device restarted by the watchdog timer + * When the device receives time measurement from the host + * Then time measured by host equals X ms + */ +template +void test_timing(); + +#endif + +#endif + +/** @}*/ + From 00fa5e298aa01c37767892e027cb8bd63c17451c Mon Sep 17 00:00:00 2001 From: Filip Jagodzinski Date: Tue, 30 Jan 2018 17:08:02 +0100 Subject: [PATCH 22/62] Tests: Drivers: Watchdog: Add tests --- TESTS/mbed_drivers/watchdog/Watchdog_tests.h | 108 +++++++ TESTS/mbed_drivers/watchdog/main.cpp | 221 ++++++++++++++ .../watchdog_reset/Watchdog_reset_tests.h | 77 +++++ TESTS/mbed_drivers/watchdog_reset/main.cpp | 285 ++++++++++++++++++ 4 files changed, 691 insertions(+) create mode 100644 TESTS/mbed_drivers/watchdog/Watchdog_tests.h create mode 100644 TESTS/mbed_drivers/watchdog/main.cpp create mode 100644 TESTS/mbed_drivers/watchdog_reset/Watchdog_reset_tests.h create mode 100644 TESTS/mbed_drivers/watchdog_reset/main.cpp diff --git a/TESTS/mbed_drivers/watchdog/Watchdog_tests.h b/TESTS/mbed_drivers/watchdog/Watchdog_tests.h new file mode 100644 index 00000000000..cf2d6da30a5 --- /dev/null +++ b/TESTS/mbed_drivers/watchdog/Watchdog_tests.h @@ -0,0 +1,108 @@ +/* mbed Microcontroller Library + * Copyright (c) 2018 ARM Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @addtogroup drivers_watchdog_tests + * @{ + */ + +#ifndef MBED_DRIVERS_WATCHDOG_TESTS_H +#define MBED_DRIVERS_WATCHDOG_TESTS_H + +#if DEVICE_WATCHDOG + +/** Test max_timeout is valid + * + * Given a device supporting Watchdog driver API + * When @a Watchdog::max_timeout() is called + * Then the returned value is greater than 1 + */ +void test_max_timeout_is_valid(); + +/** Test watchdog can be stopped + * + * Given a platform with a support for disabling a running watchdog + * When watchdog is not running and @a Watchdog::stop() is called + * Then WATCHDOG_STATUS_OK is returned + * When watchdog is running + * and @a Watchdog::stop() is called before timeout + * Then WATCHDOG_STATUS_OK is returned + * and watchdog does not reset the device + * When watchdog has already been stopped and @a Watchdog::stop() is called + * Then WATCHDOG_STATUS_OK is returned + */ +void test_stop(); + +/** Test restart watchdog multiple times + * + * Given @a max_timeout value returned by @a Watchdog::max_timeout() + * and @a Watchdog::start() called multiple times + * When @a timeout is set to max_timeout - delta + * Then return value of @a Watchdog::start() is @a WATCHDOG_STATUS_OK + * and @a Watchdog::reload_value() returns max_timeout - delta + * When @a timeout is set to max_timeout + * Then return value of @a Watchdog::start() is @a WATCHDOG_STATUS_OK + * and @a Watchdog::reload_value() returns max_timeout + * When @a timeout is set to max_timeout + delta + * Then return value of @a Watchdog::start() is @a WATCHDOG_STATUS_INVALID_ARGUMENT + * and @a Watchdog::reload_value() returns previously set value (max_timeout) + * When @a timeout is set to 0 + * Then return value of @a Watchdog::start() is @a WATCHDOG_STATUS_INVALID_ARGUMENT + * and @a Watchdog::reload_value() returns previously set value (max_timeout) + */ +void test_restart(); + +/** Test start with 0 ms + * + * Given a device supporting Watchdog driver API + * When @a timeout is set to 0 ms + * Then return value of Watchdog::start() is @a WATCHDOG_STATUS_INVALID_ARGUMENT + */ +void test_start_zero(); + +/** Test start with a valid config + * + * Given a device supporting Watchdog driver API + * When @a timeout is set to value X within platform's timeout range + * Then return value of Watchdog::start() is @a WATCHDOG_STATUS_OK + * and @a Watchdog::reload_value() returns X + */ +template +void test_start(); + +/** Test start with a max_timeout + * + * Given @a max_timeout value returned by @a Watchdog::max_timeout() + * When @a timeout is set to max_timeout + * Then return value of Watchdog::start() is @a WATCHDOG_STATUS_OK + * and @a Watchdog::reload_value() returns max_timeout + */ +void test_start_max_timeout(); + +/** Test start with a timeout value exceeding max_timeout + * + * Given a device supporting Watchdog driver API + * When @a timeout is set to max_timeout + 1 + * Then return value of Watchdog::start() is @a WATCHDOG_STATUS_INVALID_ARGUMENT + */ +void test_start_max_timeout_exceeded(); + +#endif + +#endif + +/** @}*/ + diff --git a/TESTS/mbed_drivers/watchdog/main.cpp b/TESTS/mbed_drivers/watchdog/main.cpp new file mode 100644 index 00000000000..386593e172d --- /dev/null +++ b/TESTS/mbed_drivers/watchdog/main.cpp @@ -0,0 +1,221 @@ +/* mbed Microcontroller Library + * Copyright (c) 2018 ARM Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#if !DEVICE_WATCHDOG +#error [NOT_SUPPORTED] Watchdog not supported for this target +#endif + +#define __STDC_LIMIT_MACROS +#include +#include "greentea-client/test_env.h" +#include "utest/utest.h" +#include "unity/unity.h" +#include "drivers/Watchdog.h" +#include "Watchdog_tests.h" + +/* This is platform specific and depends on the watchdog timer implementation, + * e.g. STM32F4 uses 32kHz internal RC oscillator to clock the IWDG, so + * when the prescaler divider is set to max value of 256 the resolution + * drops to 8 ms. + */ +#define WORST_TIMEOUT_RESOLUTION_MS 8UL + +#define TIMEOUT_DELTA_MS (WORST_TIMEOUT_RESOLUTION_MS) +#define WDG_TIMEOUT_MS 500UL + +#define MSG_VALUE_DUMMY "0" +#define MSG_VALUE_LEN 24 +#define MSG_KEY_LEN 24 + +#define MSG_KEY_DEVICE_READY "ready" +#define MSG_KEY_START_CASE "start_case" +#define MSG_KEY_DEVICE_RESET "reset_on_case_teardown" + +int CASE_INDEX_START; +int CASE_INDEX_CURRENT; + +using utest::v1::Case; +using utest::v1::Specification; +using utest::v1::Harness; + +void test_max_timeout_is_valid() +{ + Watchdog watchdog; + TEST_ASSERT(watchdog.max_timeout() > 1UL); +} + +void test_stop() +{ + Watchdog watchdog; + if (watchdog.stop() == WATCHDOG_STATUS_NOT_SUPPORTED) { + TEST_IGNORE_MESSAGE("Disabling watchdog not supported for this platform"); + return; + } + + TEST_ASSERT_EQUAL(WATCHDOG_STATUS_OK, watchdog.stop()); + + TEST_ASSERT_EQUAL(WATCHDOG_STATUS_OK, watchdog.start(WDG_TIMEOUT_MS)); + TEST_ASSERT_EQUAL(WATCHDOG_STATUS_OK, watchdog.stop()); + // Make sure that a disabled watchdog does not reset the core. + wait_ms(WDG_TIMEOUT_MS + TIMEOUT_DELTA_MS); + + TEST_ASSERT_EQUAL(WATCHDOG_STATUS_OK, watchdog.stop()); +} + +void test_restart() +{ + Watchdog watchdog; + watchdog.start(watchdog.max_timeout()); + uint64_t timeout = watchdog.max_timeout() - 2ULL * WORST_TIMEOUT_RESOLUTION_MS; + watchdog_status_t status = watchdog.start(timeout); + + if (status == WATCHDOG_STATUS_NOT_SUPPORTED) { + TEST_IGNORE_MESSAGE("Updating watchdog config not supported for this platform"); + return; + } + + TEST_ASSERT_EQUAL(WATCHDOG_STATUS_OK, status); + TEST_ASSERT_UINT32_WITHIN(WORST_TIMEOUT_RESOLUTION_MS, timeout, watchdog.reload_value()); + + TEST_ASSERT_EQUAL(WATCHDOG_STATUS_OK, watchdog.start(watchdog.max_timeout())); + TEST_ASSERT_UINT32_WITHIN(WORST_TIMEOUT_RESOLUTION_MS, watchdog.max_timeout(), watchdog.reload_value()); + + timeout = watchdog.max_timeout() + 2ULL * WORST_TIMEOUT_RESOLUTION_MS; + // Make sure requested timeout does not overflow uint32_t. + if (timeout <= UINT32_MAX) { + TEST_ASSERT_EQUAL(WATCHDOG_STATUS_INVALID_ARGUMENT, watchdog.start(timeout)); + TEST_ASSERT_UINT32_WITHIN(WORST_TIMEOUT_RESOLUTION_MS, watchdog.max_timeout(), watchdog.reload_value()); + } + + TEST_ASSERT_EQUAL(WATCHDOG_STATUS_INVALID_ARGUMENT, watchdog.start(0UL)); + TEST_ASSERT_UINT32_WITHIN(WORST_TIMEOUT_RESOLUTION_MS, watchdog.max_timeout(), watchdog.reload_value()); +} + +utest::v1::status_t case_setup_sync_on_reset(const Case * const source, const size_t index_of_case) +{ + CASE_INDEX_CURRENT = index_of_case; + return utest::v1::greentea_case_setup_handler(source, index_of_case); +} + +utest::v1::status_t case_teardown_sync_on_reset(const Case * const source, const size_t passed, const size_t failed, + const utest::v1::failure_t failure) +{ + utest::v1::status_t status = utest::v1::greentea_case_teardown_handler(source, passed, failed, failure); + if (failed) { + /* Return immediately and skip the device reset, if the test case failed. + * Provided that the device won't be restarted by other means (i.e. watchdog timer), + * this should allow the test suite to finish in a defined manner + * and report failure to host. + * In case of watchdog reset during test suite teardown, the loss of serial + * connection is possible, so the host-test-runner may return 'TIMEOUT' + * instead of 'FAIL'. + */ + return status; + } + greentea_send_kv(MSG_KEY_DEVICE_RESET, CASE_INDEX_START + CASE_INDEX_CURRENT); + utest_printf("The device will now restart.\n"); + wait_ms(10); // Wait for the serial buffers to flush. + NVIC_SystemReset(); + return status; // Reset is instant so this line won't be reached. +} + +void test_start_zero() +{ + Watchdog watchdog; + TEST_ASSERT_EQUAL(WATCHDOG_STATUS_INVALID_ARGUMENT, watchdog.start(0UL)); +} + +template +void test_start() +{ + Watchdog watchdog; + TEST_ASSERT_EQUAL(WATCHDOG_STATUS_OK, watchdog.start(timeout_ms)); + TEST_ASSERT_UINT32_WITHIN(WORST_TIMEOUT_RESOLUTION_MS, timeout_ms, watchdog.reload_value()); +} + +void test_start_max_timeout() +{ + Watchdog watchdog; + TEST_ASSERT_EQUAL(WATCHDOG_STATUS_OK, watchdog.start(watchdog.max_timeout())); + TEST_ASSERT_UINT32_WITHIN(WORST_TIMEOUT_RESOLUTION_MS, watchdog.max_timeout(), watchdog.reload_value()); +} + +void test_start_max_timeout_exceeded() +{ + Watchdog watchdog; + uint64_t timeout = watchdog.max_timeout() + 2ULL * WORST_TIMEOUT_RESOLUTION_MS; + // Make sure requested timeout does not overflow uint32_t. + if (timeout > UINT32_MAX) { + TEST_IGNORE_MESSAGE("Requested timeout overflows uint32_t -- ignoring test case."); + return; + } + TEST_ASSERT_EQUAL(WATCHDOG_STATUS_INVALID_ARGUMENT, watchdog.start(timeout)); +} + +int testsuite_setup_sync_on_reset(const size_t number_of_cases) +{ + GREENTEA_SETUP(45, "sync_on_reset"); + utest::v1::status_t status = utest::v1::greentea_test_setup_handler(number_of_cases); + if (status != utest::v1::STATUS_CONTINUE) { + return status; + } + + char key[MSG_KEY_LEN + 1] = { }; + char value[MSG_VALUE_LEN + 1] = { }; + + greentea_send_kv(MSG_KEY_DEVICE_READY, MSG_VALUE_DUMMY); + greentea_parse_kv(key, value, MSG_KEY_LEN, MSG_VALUE_LEN); + + if (strcmp(key, MSG_KEY_START_CASE) != 0) { + utest_printf("Invalid message key.\n"); + return utest::v1::STATUS_ABORT; + } + + char *tailptr = NULL; + CASE_INDEX_START = (int) strtol(value, &tailptr, 10); + if (*tailptr != '\0' || CASE_INDEX_START < 0) { + utest_printf("Invalid start case index received from host\n"); + return utest::v1::STATUS_ABORT; + } + + utest_printf("Starting with test case index %i of all %i defined test cases.\n", CASE_INDEX_START, number_of_cases); + return CASE_INDEX_START; +} + +Case cases[] = { + Case("max_timeout is valid", test_max_timeout_is_valid), + Case("Stop", test_stop), + Case("Restart multiple times", (utest::v1::case_setup_handler_t) case_setup_sync_on_reset, + test_restart, (utest::v1::case_teardown_handler_t) case_teardown_sync_on_reset), + + // Do not set watchdog timeout shorter than 500 ms as it may cause the + // host-test-runner return 'TIMEOUT' instead of 'FAIL' / 'PASS' if watchdog + // performs reset during test suite teardown. + Case("Start, 500 ms", (utest::v1::case_setup_handler_t) case_setup_sync_on_reset, + test_start<500UL>, (utest::v1::case_teardown_handler_t) case_teardown_sync_on_reset), + Case("Start, max_timeout", (utest::v1::case_setup_handler_t) case_setup_sync_on_reset, + test_start_max_timeout, (utest::v1::case_teardown_handler_t) case_teardown_sync_on_reset), + + Case("Start, 0 ms", test_start_zero), + Case("Start, max_timeout exceeded", test_start_max_timeout_exceeded), +}; + +Specification specification((utest::v1::test_setup_handler_t) testsuite_setup_sync_on_reset, cases); + +int main() +{ + // Harness will start with a test case index provided by host script. + return !Harness::run(specification); +} diff --git a/TESTS/mbed_drivers/watchdog_reset/Watchdog_reset_tests.h b/TESTS/mbed_drivers/watchdog_reset/Watchdog_reset_tests.h new file mode 100644 index 00000000000..e4add3a50a8 --- /dev/null +++ b/TESTS/mbed_drivers/watchdog_reset/Watchdog_reset_tests.h @@ -0,0 +1,77 @@ +/* mbed Microcontroller Library + * Copyright (c) 2018 ARM Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @addtogroup drivers_watchdog_tests + * @{ + */ + +#ifndef MBED_DRIVERS_WATCHDOG_RESET_TESTS_H +#define MBED_DRIVERS_WATCHDOG_RESET_TESTS_H + +#if DEVICE_WATCHDOG + +/** Test watchdog reset + * + * Given a device with a watchdog started + * When a watchdog timeout expires + * Then the device is restarted + */ +void test_simple_reset(); + +/** Test watchdog reset in sleep mode + * + * Given a device supporting sleep mode, with a watchdog started + * When the device is in sleep mode and watchdog timeout expires + * Then the device is restarted + */ +void test_sleep_reset(); + +/** Test watchdog reset in deepsleep mode + * + * Given a device supporting deepsleep mode, with watchdog started + * When the device is in deepsleep mode and watchdog timeout expires + * Then the device is restarted + */ +void test_deepsleep_reset(); + +/** Test stopped watchdog can be started again and reset the device + * + * Given a device supporting 'disable_watchdog' feature, with watchdog started + * When the watchdog is stopped before timeout expires + * Then the device is not restarted + * When the watchdog is started again and it's timeout expires + * Then the device is restarted + */ +void test_restart_reset(); + +/** Test kicking the watchdog prevents reset + * + * Given a device with watchdog started + * When the watchdog is kicked before timeout expires + * Then the device restart is prevented + * When the watchdog is *NOT* kicked again before next timeout expires + * Then the device is restarted + * + */ +void test_kick_reset(); + +#endif + +#endif + +/** @}*/ + diff --git a/TESTS/mbed_drivers/watchdog_reset/main.cpp b/TESTS/mbed_drivers/watchdog_reset/main.cpp new file mode 100644 index 00000000000..45d8e941c85 --- /dev/null +++ b/TESTS/mbed_drivers/watchdog_reset/main.cpp @@ -0,0 +1,285 @@ +/* mbed Microcontroller Library + * Copyright (c) 2018 ARM Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#if !DEVICE_WATCHDOG +#error [NOT_SUPPORTED] Watchdog not supported for this target +#endif + +#include "greentea-client/test_env.h" +#include "utest/utest.h" +#include "unity/unity.h" +#include "drivers/Watchdog.h" +#include "Watchdog_reset_tests.h" +#include "mbed.h" + +#define TIMEOUT_MS 500UL +#define TIMEOUT_DELTA_MS 50UL + +#define MSG_VALUE_DUMMY "0" +#define CASE_DATA_INVALID 0xffffffffUL +#define CASE_DATA_PHASE2_OK 0xfffffffeUL + +#define MSG_VALUE_LEN 24 +#define MSG_KEY_LEN 24 + +#define MSG_KEY_DEVICE_READY "ready" +#define MSG_KEY_START_CASE "start_case" +#define MSG_KEY_DEVICE_RESET "dev_reset" + +using utest::v1::Case; +using utest::v1::Specification; +using utest::v1::Harness; + +struct testcase_data { + int index; + int start_index; + uint32_t received_data; +}; + +void release_sem(Semaphore *sem) +{ + sem->release(); +} + +testcase_data current_case; + +bool send_reset_notification(testcase_data * tcdata, uint32_t delay_ms) +{ + char msg_value[12]; + int str_len = snprintf(msg_value, sizeof msg_value, "%02x,%08lx", tcdata->start_index + tcdata->index, delay_ms); + if (str_len != (sizeof msg_value) - 1) { + utest_printf("Failed to compose a value string to be sent to host."); + return false; + } + greentea_send_kv(MSG_KEY_DEVICE_RESET, msg_value); + return true; +} + +void test_simple_reset() +{ + // Phase 2. -- verify the test results. + // Verify if this test case passed based on data received from host. + if (current_case.received_data != CASE_DATA_INVALID) { + TEST_ASSERT_EQUAL(CASE_DATA_PHASE2_OK, current_case.received_data); + current_case.received_data = CASE_DATA_INVALID; + return; + } + + // Phase 1. -- run the test code. + // Init the watchdog and wait for a device reset. + Watchdog watchdog; + if (send_reset_notification(¤t_case, TIMEOUT_MS + TIMEOUT_DELTA_MS) == false) { + TEST_ASSERT_MESSAGE(0, "Dev-host communication error."); + return; + } + TEST_ASSERT_EQUAL(WATCHDOG_STATUS_OK, watchdog.start(TIMEOUT_MS)); + wait_ms(TIMEOUT_MS + TIMEOUT_DELTA_MS); // Device reset expected. + + // Watchdog reset should have occurred during wait_ms() above; + + watchdog.kick(); // Just to buy some time for testsuite failure handling. + TEST_ASSERT_MESSAGE(0, "Watchdog did not reset the device as expected."); +} + +#if DEVICE_SLEEP +void test_sleep_reset() +{ + // Phase 2. -- verify the test results. + if (current_case.received_data != CASE_DATA_INVALID) { + TEST_ASSERT_EQUAL(CASE_DATA_PHASE2_OK, current_case.received_data); + current_case.received_data = CASE_DATA_INVALID; + return; + } + + // Phase 1. -- run the test code. + Watchdog watchdog; + Semaphore sem(0, 1); + Timeout timeout; + if (send_reset_notification(¤t_case, TIMEOUT_MS + TIMEOUT_DELTA_MS) == false) { + TEST_ASSERT_MESSAGE(0, "Dev-host communication error."); + return; + } + TEST_ASSERT_EQUAL(WATCHDOG_STATUS_OK, watchdog.start(TIMEOUT_MS)); + sleep_manager_lock_deep_sleep(); + timeout.attach_us(mbed::callback(release_sem, &sem), 1000ULL * (TIMEOUT_MS + TIMEOUT_DELTA_MS)); + if (sleep_manager_can_deep_sleep()) { + TEST_ASSERT_MESSAGE(0, "Deepsleep should be disallowed."); + return; + } + while (sem.wait(0) != 1) { + sleep(); // Device reset expected. + } + sleep_manager_unlock_deep_sleep(); + + // Watchdog reset should have occurred during sleep() above; + + watchdog.kick(); // Just to buy some time for testsuite failure handling. + TEST_ASSERT_MESSAGE(0, "Watchdog did not reset the device as expected."); +} + +#if DEVICE_LOWPOWERTIMER +void test_deepsleep_reset() +{ + // Phase 2. -- verify the test results. + if (current_case.received_data != CASE_DATA_INVALID) { + TEST_ASSERT_EQUAL(CASE_DATA_PHASE2_OK, current_case.received_data); + current_case.received_data = CASE_DATA_INVALID; + return; + } + + // Phase 1. -- run the test code. + Watchdog watchdog; + Semaphore sem(0, 1); + LowPowerTimeout lp_timeout; + if (send_reset_notification(¤t_case, TIMEOUT_MS + TIMEOUT_DELTA_MS) == false) { + TEST_ASSERT_MESSAGE(0, "Dev-host communication error."); + return; + } + TEST_ASSERT_EQUAL(WATCHDOG_STATUS_OK, watchdog.start(TIMEOUT_MS)); + lp_timeout.attach_us(mbed::callback(release_sem, &sem), 1000ULL * (TIMEOUT_MS + TIMEOUT_DELTA_MS)); + wait_ms(10); // Wait for the serial buffers to flush. + if (!sleep_manager_can_deep_sleep()) { + TEST_ASSERT_MESSAGE(0, "Deepsleep should be allowed."); + } + while (sem.wait(0) != 1) { + sleep(); // Device reset expected. + } + + // Watchdog reset should have occurred during that sleep() above; + + watchdog.kick(); // Just to buy some time for testsuite failure handling. + TEST_ASSERT_MESSAGE(0, "Watchdog did not reset the device as expected."); +} +#endif +#endif + +void test_restart_reset() +{ + Watchdog watchdog; + if (watchdog.stop() == WATCHDOG_STATUS_NOT_SUPPORTED) { + TEST_IGNORE_MESSAGE("Disabling watchdog not supported for this platform"); + return; + } + + // Phase 2. -- verify the test results. + if (current_case.received_data != CASE_DATA_INVALID) { + TEST_ASSERT_EQUAL(CASE_DATA_PHASE2_OK, current_case.received_data); + current_case.received_data = CASE_DATA_INVALID; + return; + } + + // Phase 1. -- run the test code. + TEST_ASSERT_EQUAL(WATCHDOG_STATUS_OK, watchdog.start(TIMEOUT_MS)); + wait_ms(TIMEOUT_MS / 2UL); + TEST_ASSERT_EQUAL(WATCHDOG_STATUS_OK, watchdog.stop()); + // Check that stopping the watchdog prevents a device reset. + wait_ms(TIMEOUT_MS / 2UL + TIMEOUT_DELTA_MS); + + if (send_reset_notification(¤t_case, TIMEOUT_MS + TIMEOUT_DELTA_MS) == false) { + TEST_ASSERT_MESSAGE(0, "Dev-host communication error."); + return; + } + TEST_ASSERT_EQUAL(WATCHDOG_STATUS_OK, watchdog.start(TIMEOUT_MS)); + wait_ms(TIMEOUT_MS + TIMEOUT_DELTA_MS); // Device reset expected. + + // Watchdog reset should have occurred during that wait() above; + + watchdog.kick(); // Just to buy some time for testsuite failure handling. + TEST_ASSERT_MESSAGE(0, "Watchdog did not reset the device as expected."); +} + +void test_kick_reset() +{ + // Phase 2. -- verify the test results. + if (current_case.received_data != CASE_DATA_INVALID) { + TEST_ASSERT_EQUAL(CASE_DATA_PHASE2_OK, current_case.received_data); + current_case.received_data = CASE_DATA_INVALID; + return; + } + + // Phase 1. -- run the test code. + Watchdog watchdog; + TEST_ASSERT_EQUAL(WATCHDOG_STATUS_OK, watchdog.start(TIMEOUT_MS)); + for (int i = 3; i; i--) { + wait_ms(TIMEOUT_MS / 2UL); + watchdog.kick(); + } + if (send_reset_notification(¤t_case, TIMEOUT_MS + TIMEOUT_DELTA_MS) == false) { + TEST_ASSERT_MESSAGE(0, "Dev-host communication error."); + return; + } + wait_ms(TIMEOUT_MS + TIMEOUT_DELTA_MS); // Device reset expected. + + // Watchdog reset should have occurred during that wait() above; + + watchdog.kick(); // Just to buy some time for testsuite failure handling. + TEST_ASSERT_MESSAGE(0, "Watchdog did not reset the device as expected."); +} + +utest::v1::status_t case_setup(const Case * const source, const size_t index_of_case) +{ + current_case.index = index_of_case; + return utest::v1::greentea_case_setup_handler(source, index_of_case); +} + +int testsuite_setup(const size_t number_of_cases) +{ + GREENTEA_SETUP(90, "watchdog_reset"); + utest::v1::status_t status = utest::v1::greentea_test_setup_handler(number_of_cases); + if (status != utest::v1::STATUS_CONTINUE) { + return status; + } + + char key[MSG_KEY_LEN + 1] = { }; + char value[MSG_VALUE_LEN + 1] = { }; + + greentea_send_kv(MSG_KEY_DEVICE_READY, MSG_VALUE_DUMMY); + greentea_parse_kv(key, value, MSG_KEY_LEN, MSG_VALUE_LEN); + + if (strcmp(key, MSG_KEY_START_CASE) != 0) { + utest_printf("Invalid message key.\n"); + return utest::v1::STATUS_ABORT; + } + + int num_args = sscanf(value, "%02x,%08lx", &(current_case.start_index), &(current_case.received_data)); + if (num_args == 0 || num_args == EOF) { + utest_printf("Invalid data received from host\n"); + return utest::v1::STATUS_ABORT; + } + + utest_printf("This test suite is composed of %i test cases. Starting at index %i.\n", number_of_cases, + current_case.start_index); + return current_case.start_index; +} + +Case cases[] = { + Case("Watchdog reset", case_setup, test_simple_reset), +#if DEVICE_SLEEP + Case("Watchdog reset in sleep mode", case_setup, test_sleep_reset), +#if DEVICE_LOWPOWERTIMER + Case("Watchdog reset in deepsleep mode", case_setup, test_deepsleep_reset), +#endif +#endif + Case("Watchdog started again", case_setup, test_restart_reset), + Case("Kicking the watchdog prevents reset", case_setup, test_kick_reset), +}; + +Specification specification((utest::v1::test_setup_handler_t) testsuite_setup, cases); + +int main() +{ + // Harness will start with a test case index provided by host script. + return !Harness::run(specification); +} From 4af4158a4c37cf83266edc4471b16e67c3a6931c Mon Sep 17 00:00:00 2001 From: Filip Jagodzinski Date: Wed, 7 Feb 2018 18:22:43 +0100 Subject: [PATCH 23/62] STM32F4: watchdog HAL: Fix issues found with tests Fix WATCHDOG_STATUS_INVALID_ARGUMENT for timeout values from 1 ms to 407 ms (fix inability to set prescaler bits to zero). Fix timeout <-> IWDG registers conversions. Fix read & write access to IWDG_PR and IWDG_RLR registers. Fix LSI RC frequency setting. Limit MAX_TIMEOUT_MS to UINT32_MAX. --- .../TARGET_STM/TARGET_STM32F4/watchdog_api.c | 130 +++++++++++------- 1 file changed, 80 insertions(+), 50 deletions(-) diff --git a/targets/TARGET_STM/TARGET_STM32F4/watchdog_api.c b/targets/TARGET_STM/TARGET_STM32F4/watchdog_api.c index ac66d23fcf5..3a0060996b7 100644 --- a/targets/TARGET_STM/TARGET_STM32F4/watchdog_api.c +++ b/targets/TARGET_STM/TARGET_STM32F4/watchdog_api.c @@ -24,88 +24,118 @@ #include -// Platform specific watchdog definitions -#define LPO_CLOCK_FREQUENCY 40000 -#define MAX_PRESCALER 256 -#define MAX_TIMEOUT 0xFFFULL - -// Number of decrements in the timeout register per millisecond -#define TICKS_PER_MS (LPO_CLOCK_FREQUENCY / 1000) -// Maximum timeout that can be specified in milliseconds -const uint64_t max_timeout_ms = ((MAX_TIMEOUT / TICKS_PER_MS) * MAX_PRESCALER); - -// Maximum supported watchdog timeout for given prescaler value -#define CALCULATE_MAX_TIMEOUT_MS(scale) \ - ((MAX_TIMEOUT / TICKS_PER_MS) * scale) - - -static uint32_t calculate_prescaler_value(const uint32_t timeout_ms) -{ - if (timeout_ms > max_timeout_ms) { - return 0; - } - - for (uint32_t scale = 0; scale < 7; ++scale) { - const uint32_t prescaler = (4U << scale); - - if (timeout_ms < CALCULATE_MAX_TIMEOUT_MS(prescaler)) { - return scale; +#define LSI_RC_HZ 32000 // Frequency of the low-speed internal RC oscillator that drives IWDG +#define MAX_IWDG_PR 0x6 // Max value of Prescaler_divider bits (PR) of Prescaler_register (IWDG_PR) +#define MAX_IWDG_RL 0xFFFUL // Max value of Watchdog_counter_reload_value bits (RL) of Reload_register (IWDG_RLR). + +// Convert Prescaler_divider bits (PR) of Prescaler_register (IWDG_PR) to a prescaler_divider value. +#define PR2PRESCALER_DIV(PR_BITS) \ + (4UL << (PR_BITS)) + +// Convert Prescaler_divider bits (PR) of Prescaler_register (IWDG_PR) +// and Watchdog_counter_reload_value bits (RL) of Reload_register (IWDG_RLR) +// to a timeout value [ms]. +#define PR_RL2UINT64_TIMEOUT_MS(PR_BITS, RL_BITS) \ + ((PR2PRESCALER_DIV(PR_BITS)) * (RL_BITS) * 1000ULL / (LSI_RC_HZ)) + +// Convert Prescaler_divider bits (PR) of Prescaler_register (IWDG_PR) and a timeout value [ms] +// to Watchdog_counter_reload_value bits (RL) of Reload_register (IWDG_RLR) +#define PR_TIMEOUT_MS2RL(PR_BITS, TIMEOUT_MS) \ + ((TIMEOUT_MS) * (LSI_RC_HZ) / (PR2PRESCALER_DIV(PR_BITS)) / 1000UL) + +#define MAX_TIMEOUT_MS_UINT64 PR_RL2UINT64_TIMEOUT_MS(MAX_IWDG_PR, MAX_IWDG_RL) +#if (MAX_TIMEOUT_MS_UINT64 > UINT32_MAX) +#define MAX_TIMEOUT_MS UINT32_MAX +#else +#define MAX_TIMEOUT_MS (MAX_TIMEOUT_MS_UINT64 & 0xFFFFFFFFUL) +#endif + +#define INVALID_IWDG_PR ((MAX_IWDG_PR) + 1) // Arbitrary value used to mark an invalid PR bits value. + +// Pick a minimal Prescaler_divider bits (PR) value suitable for given timeout. +static uint8_t pick_min_iwdg_pr(const uint32_t timeout_ms) { + for (uint8_t pr = 0; pr <= MAX_IWDG_PR; pr++) { + // Check that max timeout for given pr is greater than + // or equal to timeout_ms. + if (PR_RL2UINT64_TIMEOUT_MS(pr, MAX_IWDG_RL) >= timeout_ms) { + return pr; } } - - return 0; + return INVALID_IWDG_PR; } - watchdog_status_t hal_watchdog_init(const watchdog_config_t *config) { - const uint32_t prescaler = calculate_prescaler_value(config->timeout_ms); - - if (prescaler == 0) { + const uint8_t pr = pick_min_iwdg_pr(config->timeout_ms); + if (pr == INVALID_IWDG_PR) { return WATCHDOG_STATUS_INVALID_ARGUMENT; } + const uint32_t rl = PR_TIMEOUT_MS2RL(pr, config->timeout_ms); - // Enable write access to Prescaler(IWDG_PR) and Reload(IWDG_RLR) registers - IWDG->KR = 0x5555; + // Set the Key_value bits (KEY) of Key_register (IWDG_KR) to 0x5555 + // in order to enable write access to IWDG_PR and IWDG_RLR registers. + MODIFY_REG(IWDG->KR, IWDG_KR_KEY_Msk, (IWDG_KR_KEY_Msk & (0x5555U << IWDG_KR_KEY_Pos))); - // Set the prescaler and timeout values - IWDG->RLR = (TICKS_PER_MS * config->timeout_ms) / (4U << prescaler); - IWDG->PR = prescaler; + // Wait for the Watchdog_prescaler_value_update bit (PVU) of + // Status_register (IWDG_SR) to be reset. + while (READ_BIT(IWDG->SR, IWDG_SR_PVU)) { + } + // Set the Prescaler_divider bits (PR) of Prescaler_register (IWDG_PR). + MODIFY_REG(IWDG->PR, IWDG_PR_PR_Msk, (IWDG_PR_PR_Msk & (pr << IWDG_PR_PR_Pos))); + + // Wait for the Watchdog_counter_reload_value_update bit (RVU) of + // Status_register (IWDG_SR) to be reset. + while (READ_BIT(IWDG->SR, IWDG_SR_RVU)) { + } + // Set the Watchdog_counter_reload_value bits (RL) of Reload_register (IWDG_RLR). + MODIFY_REG(IWDG->RLR, IWDG_RLR_RL_Msk, (IWDG_RLR_RL_Msk & (rl << IWDG_RLR_RL_Pos))); - // Reload the Watchdog Counter. - IWDG->KR = 0xAAAA; - // Enable the Independent Watchdog. - IWDG->KR = 0xCCCC; + // Set the Key_value bits (KEY) of Key_register (IWDG_KR) to 0xAAAA + // in order to reload IWDG_RLR register value. + MODIFY_REG(IWDG->KR, IWDG_KR_KEY_Msk, (IWDG_KR_KEY_Msk & (0xAAAAU << IWDG_KR_KEY_Pos))); + + // Set the Key_value bits (KEY) of Key_register (IWDG_KR) to 0xCCCC + // in order to start the watchdog. + MODIFY_REG(IWDG->KR, IWDG_KR_KEY_Msk, (IWDG_KR_KEY_Msk & (0xCCCCU << IWDG_KR_KEY_Pos))); return WATCHDOG_STATUS_OK; } - void hal_watchdog_kick(void) { - IWDG->KR = 0xAAAA; + // Set the Key_value bits (KEY) of Key_register (IWDG_KR) to 0xAAAA + // in order to reload IWDG_RLR register value. + MODIFY_REG(IWDG->KR, IWDG_KR_KEY_Msk, (IWDG_KR_KEY_Msk & (0xAAAAU << IWDG_KR_KEY_Pos))); } - watchdog_status_t hal_watchdog_stop(void) { return WATCHDOG_STATUS_NOT_SUPPORTED; } - uint32_t hal_watchdog_get_reload_value(void) { - const uint32_t timeout = (IWDG->RLR & 0xFFF); - const uint32_t prescaler = (4U << (IWDG->PR & 0x7)); + // Wait for the Watchdog_prescaler_value_update bit (PVU) of + // Status_register (IWDG_SR) to be reset. + while (READ_BIT(IWDG->SR, IWDG_SR_PVU)) { + } + // Read Prescaler_divider bits (PR) of Prescaler_register (IWDG_PR). + const uint8_t pr = (IWDG->PR & IWDG_PR_PR_Msk) >> IWDG_PR_PR_Pos; - return ((timeout / TICKS_PER_MS) * prescaler); -} + // Wait for the Watchdog_counter_reload_value_update bit (RVU) of + // Status_register (IWDG_SR) to be reset. + while (READ_BIT(IWDG->SR, IWDG_SR_RVU)) { + } + // Read Watchdog_counter_reload_value bits (RL) of Reload_register (IWDG_RLR). + const uint32_t rl = (IWDG->RLR & IWDG_RLR_RL_Msk) >> IWDG_RLR_RL_Pos; + return PR_RL2UINT64_TIMEOUT_MS(pr, rl); +} watchdog_features_t hal_watchdog_get_platform_features(void) { watchdog_features_t features; - features.max_timeout = max_timeout_ms; + features.max_timeout = MAX_TIMEOUT_MS; features.update_config = true; features.disable_watchdog = false; From 3c0765eaaa147973cc11486e1d816be58cfa463e Mon Sep 17 00:00:00 2001 From: Filip Jagodzinski Date: Mon, 19 Feb 2018 16:09:05 +0100 Subject: [PATCH 24/62] K64F: watchdog HAL: Fix init() and stop() Added a missing wait for the WCT window end. Without it, consecutive init() or stop() calls were ignored. --- .../TARGET_MCU_K64F/watchdog_api.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/targets/TARGET_Freescale/TARGET_MCUXpresso_MCUS/TARGET_MCU_K64F/watchdog_api.c b/targets/TARGET_Freescale/TARGET_MCUXpresso_MCUS/TARGET_MCU_K64F/watchdog_api.c index 4f5e2e7c1bd..22006d91773 100644 --- a/targets/TARGET_Freescale/TARGET_MCUXpresso_MCUS/TARGET_MCU_K64F/watchdog_api.c +++ b/targets/TARGET_Freescale/TARGET_MCUXpresso_MCUS/TARGET_MCU_K64F/watchdog_api.c @@ -14,15 +14,16 @@ * limitations under the License. */ #include "watchdog_api.h" - #include "reset_reason_api.h" - #include "fsl_wdog.h" +#include "fsl_clock.h" +#include "platform/mbed_wait_api.h" // Platform specific watchdog definitions #define LPO_CLOCK_FREQUENCY 1000 #define MAX_PRESCALER 8 #define MAX_TIMEOUT 0xFFFFFFFFUL +#define WCT_IN_BUS_CYCLES 256U // Watchdog configuration time (WCT) in bus clock cycles. // Number of decrements in the timeout register per millisecond #define TICKS_PER_MS ((LPO_CLOCK_FREQUENCY) / 1000) @@ -55,6 +56,11 @@ static uint32_t calculate_prescaler_value(const uint32_t timeout_ms) return 0; } +// Wait until watchdog configuration time window closes. +static inline void wait_WCT(void) { + uint32_t WCT_us = (WCT_IN_BUS_CYCLES) * 1000000UL / CLOCK_GetBusClkFreq(); + wait_us(WCT_us); +} watchdog_status_t hal_watchdog_init(const watchdog_config_t *config) { @@ -79,6 +85,7 @@ watchdog_status_t hal_watchdog_init(const watchdog_config_t *config) cfg.timeoutValue = (TICKS_PER_MS * config->timeout_ms) / prescaler; WDOG_Init(WDOG, &cfg); + wait_WCT(); // Updates in the write-once registers take effect only after the WCT window closes. return WATCHDOG_STATUS_OK; } @@ -91,6 +98,7 @@ void hal_watchdog_kick(void) watchdog_status_t hal_watchdog_stop(void) { WDOG_Deinit(WDOG); + wait_WCT(); // Updates in the write-once registers take effect only after the WCT window closes. return WATCHDOG_STATUS_OK; } From 9f012f058304af5fe44a6eafb11be4a07b95ceea Mon Sep 17 00:00:00 2001 From: Bartek Szatkowski Date: Thu, 15 Mar 2018 10:34:36 +0000 Subject: [PATCH 25/62] Add RESET_REASON and WATCHDOG to doxygen options --- doxyfile_options | 2 ++ doxygen_options.json | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/doxyfile_options b/doxyfile_options index b477f1909be..b18cb2748ed 100644 --- a/doxyfile_options +++ b/doxyfile_options @@ -2088,6 +2088,7 @@ PREDEFINED = DOXYGEN_ONLY \ DEVICE_PORTINOUT \ DEVICE_PORTOUT \ DEVICE_PWMOUT \ + DEVICE_RESET_REASON \ DEVICE_RTC \ DEVICE_TRNG \ DEVICE_SERIAL \ @@ -2099,6 +2100,7 @@ PREDEFINED = DOXYGEN_ONLY \ DEVICE_SPISLAVE \ DEVICE_QSPI \ DEVICE_STORAGE \ + DEVICE_WATCHDOG \ COMPONENT_SPE \ COMPONENT_SPM_MAILBOX \ "MBED_DEPRECATED_SINCE(d, m)=" \ diff --git a/doxygen_options.json b/doxygen_options.json index 0e884b9a43f..6c51f2821ac 100644 --- a/doxygen_options.json +++ b/doxygen_options.json @@ -6,7 +6,7 @@ "SEARCH_INCLUDES": "YES", "INCLUDE_PATH": "", "INCLUDE_FILE_PATTERNS": "", - "PREDEFINED": "DOXYGEN_ONLY DEVICE_ANALOGIN DEVICE_ANALOGOUT DEVICE_CAN DEVICE_CRC DEVICE_ETHERNET DEVICE_EMAC DEVICE_FLASH DEVICE_I2C DEVICE_I2CSLAVE DEVICE_I2C_ASYNCH DEVICE_INTERRUPTIN DEVICE_ITM DEVICE_LPTICKER DEVICE_MPU DEVICE_PORTIN DEVICE_PORTINOUT DEVICE_PORTOUT DEVICE_PWMOUT DEVICE_RTC DEVICE_TRNG DEVICE_SERIAL DEVICE_SERIAL_ASYNCH DEVICE_SERIAL_FC DEVICE_SLEEP DEVICE_SPI DEVICE_SPI_ASYNCH DEVICE_SPISLAVE DEVICE_QSPI DEVICE_STORAGE COMPONENT_SPE COMPONENT_SPM_MAILBOX \"MBED_DEPRECATED_SINCE(f, g)=\" \"MBED_ENABLE_IF_CALLBACK_COMPATIBLE(F, M)=\" \"MBED_DEPRECATED(s)=\"", + "PREDEFINED": "DOXYGEN_ONLY DEVICE_ANALOGIN DEVICE_ANALOGOUT DEVICE_CAN DEVICE_CRC DEVICE_ETHERNET DEVICE_EMAC DEVICE_FLASH DEVICE_I2C DEVICE_I2CSLAVE DEVICE_I2C_ASYNCH DEVICE_INTERRUPTIN DEVICE_ITM DEVICE_LPTICKER DEVICE_MPU DEVICE_PORTIN DEVICE_PORTINOUT DEVICE_PORTOUT DEVICE_PWMOUT DEVICE_RTC DEVICE_TRNG DEVICE_SERIAL DEVICE_SERIAL_ASYNCH DEVICE_SERIAL_FC DEVICE_SLEEP DEVICE_SPI DEVICE_SPI_ASYNCH DEVICE_SPISLAVE DEVICE_QSPI DEVICE_STORAGE DEVICE_WATCHDOG COMPONENT_SPE COMPONENT_SPM_MAILBOX \"MBED_DEPRECATED_SINCE(f, g)=\" \"MBED_ENABLE_IF_CALLBACK_COMPATIBLE(F, M)=\" \"MBED_DEPRECATED(s)=\"", "EXPAND_AS_DEFINED": "", "SKIP_FUNCTION_MACROS": "NO", "STRIP_CODE_COMMENTS": "NO", From 78766e8ba3c5bb9cd41303c086a1217bb90ac3ce Mon Sep 17 00:00:00 2001 From: Bartek Szatkowski Date: Thu, 15 Mar 2018 10:56:47 +0000 Subject: [PATCH 26/62] Document reset reason enum --- hal/reset_reason_api.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/hal/reset_reason_api.h b/hal/reset_reason_api.h index aa0333cb190..e9d0d793984 100644 --- a/hal/reset_reason_api.h +++ b/hal/reset_reason_api.h @@ -31,6 +31,8 @@ extern "C" { * @{ */ +/** Definitions of different reset reasons + */ typedef enum { RESET_REASON_POWER_ON, /**< Set when power is initially applied to the board. The power-on-reset circuit causes a POWER_ON reset when this occurs */ RESET_REASON_PIN_RESET, /**< Set when a reset is triggered by the hardware pin on the board */ From 4160c37a84ddf32de990d7473e05bb85586ea1a7 Mon Sep 17 00:00:00 2001 From: Bartek Szatkowski Date: Mon, 19 Mar 2018 10:38:07 +0000 Subject: [PATCH 27/62] Disable Watchdog on Odin as it fails intermittently --- targets/targets.json | 1 - 1 file changed, 1 deletion(-) diff --git a/targets/targets.json b/targets/targets.json index fc39264689f..9a3b9774f2f 100644 --- a/targets/targets.json +++ b/targets/targets.json @@ -4026,7 +4026,6 @@ "EMAC", "TRNG", "FLASH", - "WATCHDOG", "WIFI", "SERIAL_FC", "SERIAL" From 7d97592094b66c362153bddd30c78ffb6176c7d4 Mon Sep 17 00:00:00 2001 From: Filip Jagodzinski Date: Thu, 15 Mar 2018 13:32:22 +0100 Subject: [PATCH 28/62] Tests: HAL: Watchdog: Fix timing accuracy test Relax time measurement margins for UBLOX_EVK_ODIN_W2. --- TESTS/mbed_hal/watchdog_timing/main.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/TESTS/mbed_hal/watchdog_timing/main.cpp b/TESTS/mbed_hal/watchdog_timing/main.cpp index ffc657c0fd6..38711e76090 100644 --- a/TESTS/mbed_hal/watchdog_timing/main.cpp +++ b/TESTS/mbed_hal/watchdog_timing/main.cpp @@ -134,9 +134,9 @@ int testsuite_setup(const size_t number_of_cases) Case cases[] = { Case("Timing, 200 ms", case_setup, test_timing<200UL, 55UL>), - Case("Timing, 500 ms", case_setup, test_timing<500UL, 65UL>), - Case("Timing, 1000 ms", case_setup, test_timing<1000UL, 130UL>), - Case("Timing, 3000 ms", case_setup, test_timing<3000UL, 190UL>), + Case("Timing, 500 ms", case_setup, test_timing<500UL, 130UL>), + Case("Timing, 1000 ms", case_setup, test_timing<1000UL, 255UL>), + Case("Timing, 3000 ms", case_setup, test_timing<3000UL, 380UL>), }; Specification specification((utest::v1::test_setup_handler_t) testsuite_setup, cases); From f5e49557bfac94deb35fedcca28a4653ea9a2e06 Mon Sep 17 00:00:00 2001 From: Filip Jagodzinski Date: Wed, 29 Nov 2017 13:18:27 +0100 Subject: [PATCH 29/62] Tests: HAL API: Reset_reason: Add tests --- TESTS/host_tests/reset_reason.py | 162 ++++++++++++++++++ TESTS/mbed_hal/reset_reason/main.cpp | 136 +++++++++++++++ .../reset_reason/reset_reason_api_tests.h | 48 ++++++ 3 files changed, 346 insertions(+) create mode 100644 TESTS/host_tests/reset_reason.py create mode 100644 TESTS/mbed_hal/reset_reason/main.cpp create mode 100644 TESTS/mbed_hal/reset_reason/reset_reason_api_tests.h diff --git a/TESTS/host_tests/reset_reason.py b/TESTS/host_tests/reset_reason.py new file mode 100644 index 00000000000..f099e041a18 --- /dev/null +++ b/TESTS/host_tests/reset_reason.py @@ -0,0 +1,162 @@ +""" +mbed SDK +Copyright (c) 2017-2017 ARM Limited + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +""" +import time +from mbed_host_tests import BaseHostTest +from mbed_host_tests.host_tests_runner.host_test_default import DefaultTestSelector + +DEFAULT_CYCLE_PERIOD = 4.0 + +MSG_VALUE_WATCHDOG_PRESENT = 'wdg_present' +MSG_VALUE_DUMMY = '0' +MSG_VALUE_RESET_REASON_GET = 'get' +MSG_VALUE_RESET_REASON_CLEAR = 'clear' +MSG_VALUE_DEVICE_RESET_NVIC = 'nvic' +MSG_VALUE_DEVICE_RESET_WATCHDOG = 'watchdog' + +MSG_KEY_DEVICE_READY = 'ready' +MSG_KEY_RESET_REASON_RAW = 'reason_raw' +MSG_KEY_RESET_REASON = 'reason' +MSG_KEY_DEVICE_RESET = 'reset' +MSG_KEY_SYNC = '__sync' + +RESET_REASONS = { + 'POWER_ON': '0', + 'PIN_RESET': '1', + 'BROWN_OUT': '2', + 'SOFTWARE': '3', + 'WATCHDOG': '4', + 'LOCKUP': '5', + 'WAKE_LOW_POWER': '6', + 'ACCESS_ERROR': '7', + 'BOOT_ERROR': '8', + 'MULTIPLE': '9', + 'PLATFORM': '10', + 'UNKNOWN': '11' +} + + +def raise_if_different(expected, actual, text=''): + """Raise a RuntimeError if actual is different than expected.""" + if expected != actual: + raise RuntimeError('{}Got {!r}, expected {!r}' + .format(text, actual, expected)) + + +class ResetReasonTest(BaseHostTest): + """Test for the Reset Reason HAL API. + + Given a device supporting a Reset Reason API. + When the device is restarted using various methods. + Then the device returns a correct reset reason for every restart. + """ + + def __init__(self): + super(ResetReasonTest, self).__init__() + self.device_has_watchdog = None + self.raw_reset_reasons = set() + cycle_s = self.get_config_item('program_cycle_s') + self.program_cycle_s = cycle_s if cycle_s is not None else DEFAULT_CYCLE_PERIOD + self.test_steps_sequence = self.test_steps() + # Advance the coroutine to it's first yield statement. + self.test_steps_sequence.send(None) + + def setup(self): + self.register_callback(MSG_KEY_DEVICE_READY, self.cb_device_ready) + self.register_callback(MSG_KEY_RESET_REASON_RAW, self.cb_reset_reason_raw) + self.register_callback(MSG_KEY_RESET_REASON, self.cb_reset_reason) + self.register_callback(MSG_KEY_DEVICE_RESET, self.cb_reset_reason) + + def cb_device_ready(self, key, value, timestamp): + """Request a raw value of the reset_reason register. + + Additionally, save the device's watchdog status on the first call. + """ + if self.device_has_watchdog is None: + self.device_has_watchdog = (value == MSG_VALUE_WATCHDOG_PRESENT) + self.send_kv(MSG_KEY_RESET_REASON_RAW, MSG_VALUE_RESET_REASON_GET) + + def cb_reset_reason_raw(self, key, value, timestamp): + """Verify that the raw reset_reason register value is unique. + + Fail the test suite if the raw reset_reason value is not unique. + Request a platform independent reset_reason otherwise. + """ + if value in self.raw_reset_reasons: + self.log('TEST FAILED: The raw reset reason is not unique. ' + '{!r} is already present in {!r}.' + .format(value, self.raw_reset_reasons)) + self.notify_complete(False) + else: + self.raw_reset_reasons.add(value) + self.send_kv(MSG_KEY_RESET_REASON, MSG_VALUE_RESET_REASON_GET) + + def cb_reset_reason(self, key, value, timestamp): + """Feed the test_steps coroutine with reset_reason value. + + Pass the test suite if the coroutine yields True. + Fail the test suite if the iterator stops or raises a RuntimeError. + """ + try: + if self.test_steps_sequence.send(value): + self.notify_complete(True) + except (StopIteration, RuntimeError) as exc: + self.log('TEST FAILED: {}'.format(exc)) + self.notify_complete(False) + + def test_steps(self): + """Generate a sequence of test steps. + + This coroutine calls yield to wait for the input from the device + (the reset_reason). If the device gives the wrong response, the + generator raises a RuntimeError exception and fails the test. + """ + # Ignore the first reason. + __ignored_reset_reason = yield + self.raw_reset_reasons.clear() + self.send_kv(MSG_KEY_RESET_REASON, MSG_VALUE_RESET_REASON_CLEAR) + __ignored_clear_ack = yield + + # Request a NVIC_SystemReset() call. + self.send_kv(MSG_KEY_DEVICE_RESET, MSG_VALUE_DEVICE_RESET_NVIC) + __ignored_reset_ack = yield + time.sleep(self.program_cycle_s) + self.send_kv(MSG_KEY_SYNC, MSG_VALUE_DUMMY) + reset_reason = yield + raise_if_different(RESET_REASONS['SOFTWARE'], reset_reason, 'Wrong reset reason. ') + self.send_kv(MSG_KEY_RESET_REASON, MSG_VALUE_RESET_REASON_CLEAR) + __ignored_clear_ack = yield + + # Reset the device using DAP. + self.reset_dut(DefaultTestSelector.RESET_TYPE_SW_RST) + reset_reason = yield + raise_if_different(RESET_REASONS['PIN_RESET'], reset_reason, 'Wrong reset reason. ') + self.send_kv(MSG_KEY_RESET_REASON, MSG_VALUE_RESET_REASON_CLEAR) + __ignored_clear_ack = yield + + # Start a watchdog timer and wait for it to reset the device. + if not self.device_has_watchdog: + self.log('DUT does not have a watchdog. Skipping this reset reason.') + else: + self.send_kv(MSG_KEY_DEVICE_RESET, MSG_VALUE_DEVICE_RESET_WATCHDOG) + __ignored_reset_ack = yield + time.sleep(self.program_cycle_s) + self.send_kv(MSG_KEY_SYNC, MSG_VALUE_DUMMY) + reset_reason = yield + raise_if_different(RESET_REASONS['WATCHDOG'], reset_reason, 'Wrong reset reason. ') + + # The sequence is correct -- test passed. + yield True diff --git a/TESTS/mbed_hal/reset_reason/main.cpp b/TESTS/mbed_hal/reset_reason/main.cpp new file mode 100644 index 00000000000..20f21a94091 --- /dev/null +++ b/TESTS/mbed_hal/reset_reason/main.cpp @@ -0,0 +1,136 @@ +/* mbed Microcontroller Library + * Copyright (c) 2017 ARM Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#if !DEVICE_RESET_REASON +#error [NOT_SUPPORTED] Reset reason API not supported for this target +#endif + +#include "greentea-client/test_env.h" +#include "unity/unity.h" +#include "hal/reset_reason_api.h" +#include "reset_reason_api_tests.h" +#include "mbed.h" + +#if DEVICE_WATCHDOG +#include "hal/watchdog_api.h" + +#define MSG_VALUE_WATCHDOG_STATUS "wdg_present" +#define WDG_TIMEOUT_MS 50UL +#define WDG_TIMEOUT_DELTA_MS 50UL + +#else +#define MSG_VALUE_WATCHDOG_STATUS "no_wdg" +#endif + +#define MSG_VALUE_DUMMY "0" +#define MSG_VALUE_RESET_REASON_GET "get" +#define MSG_VALUE_RESET_REASON_CLEAR "clear" +#define MSG_VALUE_RESET_REASON_CLEAR_ACK "cleared" +#define MSG_VALUE_DEVICE_RESET_ACK "ack" +#define MSG_VALUE_DEVICE_RESET_NVIC "nvic" +#define MSG_VALUE_DEVICE_RESET_WATCHDOG "watchdog" +#define MSG_VALUE_LEN 16 +#define MSG_KEY_LEN 16 + +#define MSG_KEY_DEVICE_READY "ready" +#define MSG_KEY_RESET_REASON_RAW "reason_raw" +#define MSG_KEY_RESET_REASON "reason" +#define MSG_KEY_DEVICE_RESET "reset" + +typedef enum { + CMD_STATUS_CONTINUE, + CMD_STATUS_ERROR +} cmd_status_t; + +static cmd_status_t handle_command(const char *key, const char *value) +{ + if (strcmp(key, MSG_KEY_RESET_REASON_RAW) == 0) { + uint32_t raw_reason = hal_reset_reason_get_raw(); + char raw_reason_hex_str[9] = { }; + int raw_reason_hex_str_len = snprintf(raw_reason_hex_str, + sizeof raw_reason_hex_str, "%08lx", raw_reason); + + if (raw_reason_hex_str_len != (sizeof raw_reason_hex_str) - 1) { + TEST_ASSERT_MESSAGE(0, "Failed to compose raw reset reason hex string."); + return CMD_STATUS_ERROR; + } + + greentea_send_kv(MSG_KEY_RESET_REASON_RAW, raw_reason_hex_str); + return CMD_STATUS_CONTINUE; + } + + if (strcmp(key, MSG_KEY_RESET_REASON) == 0 && strcmp(value, MSG_VALUE_RESET_REASON_GET) == 0) { + int reason = (int) hal_reset_reason_get(); + greentea_send_kv(MSG_KEY_RESET_REASON, reason); + return CMD_STATUS_CONTINUE; + } + + if (strcmp(key, MSG_KEY_RESET_REASON) == 0 && strcmp(value, MSG_VALUE_RESET_REASON_CLEAR) == 0) { + hal_reset_reason_clear(); + greentea_send_kv(MSG_KEY_RESET_REASON, MSG_VALUE_RESET_REASON_CLEAR_ACK); + return CMD_STATUS_CONTINUE; + } + + if (strcmp(key, MSG_KEY_DEVICE_RESET) == 0 && strcmp(value, MSG_VALUE_DEVICE_RESET_NVIC) == 0) { + greentea_send_kv(MSG_KEY_DEVICE_RESET, MSG_VALUE_DEVICE_RESET_ACK); + wait_ms(10); // Wait for the serial buffers to flush. + NVIC_SystemReset(); + TEST_ASSERT_MESSAGE(0, "NVIC_SystemReset did not reset the device as expected."); + return CMD_STATUS_ERROR; + } + +#if DEVICE_WATCHDOG + if (strcmp(key, MSG_KEY_DEVICE_RESET) == 0 && strcmp(value, MSG_VALUE_DEVICE_RESET_WATCHDOG) == 0) { + greentea_send_kv(MSG_KEY_DEVICE_RESET, MSG_VALUE_DEVICE_RESET_ACK); + wait_ms(10); // Wait for the serial buffers to flush. + watchdog_config_t config = { .timeout_ms = WDG_TIMEOUT_MS }; + if (hal_watchdog_init(&config) != WATCHDOG_STATUS_OK) { + TEST_ASSERT_MESSAGE(0, "hal_watchdog_init() error."); + return CMD_STATUS_ERROR; + } + wait_ms(WDG_TIMEOUT_MS + WDG_TIMEOUT_DELTA_MS); + TEST_ASSERT_MESSAGE(0, "Watchdog did not reset the device as expected."); + return CMD_STATUS_ERROR; + } +#endif + + TEST_ASSERT_MESSAGE(0, "Invalid message key."); + return CMD_STATUS_ERROR; +} + +void test_reset_reason() +{ + // Report readiness and watchdog status. + greentea_send_kv(MSG_KEY_DEVICE_READY, MSG_VALUE_WATCHDOG_STATUS); + + cmd_status_t cmd_status = CMD_STATUS_CONTINUE; + static char _key[MSG_KEY_LEN + 1] = { }; + static char _value[MSG_VALUE_LEN + 1] = { }; + + // Let the host side decide what to do and just handle the commands. + while (CMD_STATUS_CONTINUE == cmd_status) { + memset(_key, 0, sizeof _key); + memset(_value, 0, sizeof _value); + greentea_parse_kv(_key, _value, MSG_KEY_LEN, MSG_VALUE_LEN); + cmd_status = handle_command(_key, _value); + } +} + +int main() +{ + GREENTEA_SETUP(60, "reset_reason"); + test_reset_reason(); // The result of this test suite is reported by the host side. + GREENTEA_TESTSUITE_RESULT(0); // Fail on any error. +} diff --git a/TESTS/mbed_hal/reset_reason/reset_reason_api_tests.h b/TESTS/mbed_hal/reset_reason/reset_reason_api_tests.h new file mode 100644 index 00000000000..c9f9efc0644 --- /dev/null +++ b/TESTS/mbed_hal/reset_reason/reset_reason_api_tests.h @@ -0,0 +1,48 @@ +/* mbed Microcontroller Library + * Copyright (c) 2017 ARM Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @addtogroup hal_reset_reason_tests + * @{ + */ + +#ifndef MBED_HAL_RESET_REASON_API_TESTS_H +#define MBED_HAL_RESET_REASON_API_TESTS_H + +#if DEVICE_RESET_REASON + +#ifdef __cplusplus +extern "C" { +#endif + +/** Test the Reset Reason HAL API + * + * Given a device supporting a Reset Reason API + * When the device is restarted using various methods + * Then the device returns a correct reset reason for every restart + */ +void test_reset_reason(); + +#ifdef __cplusplus +} +#endif + +#endif + +#endif + +/** @}*/ + From ea7e8bbd54ea81f5436ae34938fdb13507c164b9 Mon Sep 17 00:00:00 2001 From: Filip Jagodzinski Date: Tue, 30 Jan 2018 17:06:57 +0100 Subject: [PATCH 30/62] Tests: Drivers: Reset_reason: Add tests --- TESTS/host_tests/reset_reason.py | 2 +- .../reset_reason/ResetReason_tests.h | 40 +++++ TESTS/mbed_drivers/reset_reason/main.cpp | 141 ++++++++++++++++++ 3 files changed, 182 insertions(+), 1 deletion(-) create mode 100644 TESTS/mbed_drivers/reset_reason/ResetReason_tests.h create mode 100644 TESTS/mbed_drivers/reset_reason/main.cpp diff --git a/TESTS/host_tests/reset_reason.py b/TESTS/host_tests/reset_reason.py index f099e041a18..2cfe131cb70 100644 --- a/TESTS/host_tests/reset_reason.py +++ b/TESTS/host_tests/reset_reason.py @@ -1,6 +1,6 @@ """ mbed SDK -Copyright (c) 2017-2017 ARM Limited +Copyright (c) 2017 ARM Limited Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/TESTS/mbed_drivers/reset_reason/ResetReason_tests.h b/TESTS/mbed_drivers/reset_reason/ResetReason_tests.h new file mode 100644 index 00000000000..80671d8526f --- /dev/null +++ b/TESTS/mbed_drivers/reset_reason/ResetReason_tests.h @@ -0,0 +1,40 @@ +/* mbed Microcontroller Library + * Copyright (c) 2018 ARM Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @addtogroup drivers_reset_reason_tests + * @{ + */ + +#ifndef MBED_DRIVERS_RESET_REASON_TESTS_H +#define MBED_DRIVERS_RESET_REASON_TESTS_H + +#if DEVICE_RESET_REASON + +/** Test the ResetReason driver API + * + * Given a device supporting a ResetReason API + * When the device is restarted using various methods + * Then the device returns a correct reset reason for every restart + */ +void test_reset_reason(); + +#endif + +#endif + +/** @}*/ + diff --git a/TESTS/mbed_drivers/reset_reason/main.cpp b/TESTS/mbed_drivers/reset_reason/main.cpp new file mode 100644 index 00000000000..5ca38feec1c --- /dev/null +++ b/TESTS/mbed_drivers/reset_reason/main.cpp @@ -0,0 +1,141 @@ +/* mbed Microcontroller Library + * Copyright (c) 2018 ARM Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#if !DEVICE_RESET_REASON +#error [NOT_SUPPORTED] Reset reason API not supported for this target +#endif + +#include "greentea-client/test_env.h" +#include "unity/unity.h" +#include "drivers/ResetReason.h" +#include "ResetReason_tests.h" +#include "mbed.h" + +#if DEVICE_WATCHDOG +#include "drivers/Watchdog.h" + +#define MSG_VALUE_WATCHDOG_STATUS "wdg_present" +#define WDG_TIMEOUT_MS 50UL +#define WDG_TIMEOUT_DELTA_MS 50UL + +#else +#define MSG_VALUE_WATCHDOG_STATUS "no_wdg" +#endif + +#define MSG_VALUE_DUMMY "0" +#define MSG_VALUE_RESET_REASON_GET "get" +#define MSG_VALUE_RESET_REASON_CLEAR "clear" +#define MSG_VALUE_RESET_REASON_CLEAR_ACK "cleared" +#define MSG_VALUE_DEVICE_RESET_ACK "ack" +#define MSG_VALUE_DEVICE_RESET_NVIC "nvic" +#define MSG_VALUE_DEVICE_RESET_WATCHDOG "watchdog" +#define MSG_VALUE_LEN 16 +#define MSG_KEY_LEN 16 + +#define MSG_KEY_DEVICE_READY "ready" +#define MSG_KEY_RESET_REASON_RAW "reason_raw" +#define MSG_KEY_RESET_REASON "reason" +#define MSG_KEY_DEVICE_RESET "reset" + +typedef enum { + CMD_STATUS_CONTINUE, + CMD_STATUS_ERROR +} cmd_status_t; + +static cmd_status_t handle_command(const char *key, const char *value) +{ + if (strcmp(key, MSG_KEY_RESET_REASON_RAW) == 0) { + uint32_t raw_reason = ResetReason::get_raw(); + char raw_reason_hex_str[9] = { }; + int raw_reason_hex_str_len = snprintf(raw_reason_hex_str, + sizeof raw_reason_hex_str, "%08lx", raw_reason); + + if (raw_reason_hex_str_len != (sizeof raw_reason_hex_str) - 1) { + TEST_ASSERT_MESSAGE(0, "Failed to compose raw reset reason hex string."); + return CMD_STATUS_ERROR; + } + + greentea_send_kv(MSG_KEY_RESET_REASON_RAW, raw_reason_hex_str); + return CMD_STATUS_CONTINUE; + } + + if (strcmp(key, MSG_KEY_RESET_REASON) == 0 && strcmp(value, MSG_VALUE_RESET_REASON_GET) == 0) { + int reason = (int) ResetReason::get(); + greentea_send_kv(MSG_KEY_RESET_REASON, reason); + return CMD_STATUS_CONTINUE; + } + + if (strcmp(key, MSG_KEY_RESET_REASON) == 0 && strcmp(value, MSG_VALUE_RESET_REASON_CLEAR) == 0) { + /* In order to keep this code compatible with a host script common for + * both HAL API tests and driver API tests, ignore the 'clear' command + * received from host. + * + * The driver API does not provide clear() function directly. + */ + greentea_send_kv(MSG_KEY_RESET_REASON, MSG_VALUE_RESET_REASON_CLEAR_ACK); + return CMD_STATUS_CONTINUE; + } + + if (strcmp(key, MSG_KEY_DEVICE_RESET) == 0 && strcmp(value, MSG_VALUE_DEVICE_RESET_NVIC) == 0) { + greentea_send_kv(MSG_KEY_DEVICE_RESET, MSG_VALUE_DEVICE_RESET_ACK); + wait_ms(10); // Wait for the serial buffers to flush. + NVIC_SystemReset(); + TEST_ASSERT_MESSAGE(0, "NVIC_SystemReset did not reset the device as expected."); + return CMD_STATUS_ERROR; + } + +#if DEVICE_WATCHDOG + if (strcmp(key, MSG_KEY_DEVICE_RESET) == 0 && strcmp(value, MSG_VALUE_DEVICE_RESET_WATCHDOG) == 0) { + greentea_send_kv(MSG_KEY_DEVICE_RESET, MSG_VALUE_DEVICE_RESET_ACK); + wait_ms(10); // Wait for the serial buffers to flush. + Watchdog watchdog; + if (watchdog.start(WDG_TIMEOUT_MS) != WATCHDOG_STATUS_OK) { + TEST_ASSERT_MESSAGE(0, "watchdog.start() error."); + return CMD_STATUS_ERROR; + } + wait_ms(WDG_TIMEOUT_MS + WDG_TIMEOUT_DELTA_MS); + TEST_ASSERT_MESSAGE(0, "Watchdog did not reset the device as expected."); + return CMD_STATUS_ERROR; + } +#endif + + TEST_ASSERT_MESSAGE(0, "Invalid message key."); + return CMD_STATUS_ERROR; +} + +void test_reset_reason() +{ + // Report readiness and watchdog status. + greentea_send_kv(MSG_KEY_DEVICE_READY, MSG_VALUE_WATCHDOG_STATUS); + + cmd_status_t cmd_status = CMD_STATUS_CONTINUE; + static char _key[MSG_KEY_LEN + 1] = { }; + static char _value[MSG_VALUE_LEN + 1] = { }; + + // Let the host side decide what to do and just handle the commands. + while (CMD_STATUS_CONTINUE == cmd_status) { + memset(_key, 0, sizeof _key); + memset(_value, 0, sizeof _value); + greentea_parse_kv(_key, _value, MSG_KEY_LEN, MSG_VALUE_LEN); + cmd_status = handle_command(_key, _value); + } +} + +int main() +{ + GREENTEA_SETUP(60, "reset_reason"); + test_reset_reason(); // The result of this test suite is reported by the host side. + GREENTEA_TESTSUITE_RESULT(0); // Fail on any error. +} From 50473fe3f43d82107d1fefa988f1f36ce8780568 Mon Sep 17 00:00:00 2001 From: Filip Jagodzinski Date: Wed, 21 Feb 2018 14:22:46 +0100 Subject: [PATCH 31/62] STM: HAL: Reset_reason: Correct return values --- targets/TARGET_STM/reset_reason.c | 42 +++++++++++++++---------------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/targets/TARGET_STM/reset_reason.c b/targets/TARGET_STM/reset_reason.c index 24b1b1fc6c6..6772c34ebc4 100644 --- a/targets/TARGET_STM/reset_reason.c +++ b/targets/TARGET_STM/reset_reason.c @@ -21,45 +21,45 @@ reset_reason_t hal_reset_reason_get(void) { -#ifdef RCC_FLAG_SFTRST - if (__HAL_RCC_GET_FLAG(RCC_FLAG_SFTRST)) { - return RESET_REASON_SOFTWARE; +#ifdef RCC_FLAG_LPWRRST + if (__HAL_RCC_GET_FLAG(RCC_FLAG_LPWRRST)) { + return RESET_REASON_WAKE_LOW_POWER; } #endif -#ifdef RCC_FLAG_BORRST - if (__HAL_RCC_GET_FLAG(RCC_FLAG_BORRST)) { - return RESET_REASON_BROWN_OUT; +#ifdef RCC_FLAG_WWDGRST + if (__HAL_RCC_GET_FLAG(RCC_FLAG_WWDGRST)) { + return RESET_REASON_WATCHDOG; } #endif -#ifdef RCC_FLAG_PORRST - if (__HAL_RCC_GET_FLAG(RCC_FLAG_PORRST)) { - return RESET_REASON_POWER_ON; +#ifdef RCC_FLAG_IWDGRST + if (__HAL_RCC_GET_FLAG(RCC_FLAG_IWDGRST)) { + return RESET_REASON_WATCHDOG; } #endif -#ifdef RCC_FLAG_PINRST - if (__HAL_RCC_GET_FLAG(RCC_FLAG_PINRST)) { - return RESET_REASON_PIN_RESET; +#ifdef RCC_FLAG_SFTRST + if (__HAL_RCC_GET_FLAG(RCC_FLAG_SFTRST)) { + return RESET_REASON_SOFTWARE; } #endif -#ifdef RCC_FLAG_IWDGRST - if (__HAL_RCC_GET_FLAG(RCC_FLAG_IWDGRST)) { - return RESET_REASON_WATCHDOG; +#ifdef RCC_FLAG_PORRST + if (__HAL_RCC_GET_FLAG(RCC_FLAG_PORRST)) { + return RESET_REASON_POWER_ON; } #endif -#ifdef RCC_FLAG_WWDGRST - if (__HAL_RCC_GET_FLAG(RCC_FLAG_WWDGRST)) { - return RESET_REASON_WATCHDOG; +#ifdef RCC_FLAG_BORRST + if (__HAL_RCC_GET_FLAG(RCC_FLAG_BORRST)) { + return RESET_REASON_BROWN_OUT; } #endif -#ifdef RCC_FLAG_LPWRRST - if (__HAL_RCC_GET_FLAG(RCC_FLAG_LPWRRST)) { - return RESET_REASON_WAKE_LOW_POWER; +#ifdef RCC_FLAG_PINRST + if (__HAL_RCC_GET_FLAG(RCC_FLAG_PINRST)) { + return RESET_REASON_PIN_RESET; } #endif From dc1b526e4b215cfd56f51ef37764d10099c45f8e Mon Sep 17 00:00:00 2001 From: Steven Cartmell Date: Tue, 27 Mar 2018 17:32:15 +0200 Subject: [PATCH 32/62] Add text to watchdog documentation indicating that it will continue to run in sleep modes --- hal/watchdog_api.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/hal/watchdog_api.h b/hal/watchdog_api.h index 51c689eccf0..1cf4e8f8587 100644 --- a/hal/watchdog_api.h +++ b/hal/watchdog_api.h @@ -40,6 +40,10 @@ * wraps. To prevent the system reset the timer must be continually * kicked/refreshed by calling hal_watchdog_kick which will reset the countdown * to the user specified reset value. + * + * The Watchdog timer must continue to operate in low power modes. It + * must count down and trigger a reset from within both sleep and deep sleep + * modes unless the chip is woken to refresh the timer. */ typedef struct From 5046c2743b24a5b183c30e5c1bf2fe5523062fe9 Mon Sep 17 00:00:00 2001 From: Steven Cartmell Date: Tue, 27 Mar 2018 15:31:23 +0200 Subject: [PATCH 33/62] Add Watchdog and ResetReason headers to mbed.h Adding headers to mbed.h will prevent you having to manually include them when using the drivers in an application. --- mbed.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/mbed.h b/mbed.h index e247e1dfd33..f4da76478de 100644 --- a/mbed.h +++ b/mbed.h @@ -76,6 +76,8 @@ #include "drivers/QSPI.h" // mbed Internal components +#include "drivers/ResetReason.h" +#include "drivers/Watchdog.h" #include "drivers/Timer.h" #include "drivers/Ticker.h" #include "drivers/Timeout.h" From c17d8774beaa37f0377a587715ae4200f92097f9 Mon Sep 17 00:00:00 2001 From: Steven Cooreman Date: Tue, 27 Mar 2018 17:26:20 +0200 Subject: [PATCH 34/62] Add support for watchdog on Silicon Labs devices --- .../TARGET_EFM32/watchdog_api.c | 100 ++++++++++++++++++ targets/targets.json | 30 ++++-- 2 files changed, 120 insertions(+), 10 deletions(-) create mode 100644 targets/TARGET_Silicon_Labs/TARGET_EFM32/watchdog_api.c diff --git a/targets/TARGET_Silicon_Labs/TARGET_EFM32/watchdog_api.c b/targets/TARGET_Silicon_Labs/TARGET_EFM32/watchdog_api.c new file mode 100644 index 00000000000..72a64a99d61 --- /dev/null +++ b/targets/TARGET_Silicon_Labs/TARGET_EFM32/watchdog_api.c @@ -0,0 +1,100 @@ +/***************************************************************************//** + * @file watchdog_api.c + ******************************************************************************* + * @section License + * (C) Copyright 2018 Silicon Labs, http://www.silabs.com + ******************************************************************************* + * + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ******************************************************************************/ + +#include "device.h" +#include "watchdog_api.h" + +#if DEVICE_WATCHDOG + +#include "clocking.h" +#include "em_cmu.h" +#include "em_wdog.h" + +watchdog_status_t hal_watchdog_init(const watchdog_config_t *config) +{ + if (config == 0 || config->timeout_ms > 262145 || config->timeout_ms == 0) { + return WATCHDOG_STATUS_INVALID_ARGUMENT; + } + + uint32_t timeout = config->timeout_ms; + if (timeout <= 9) { + timeout = 0; + } else { + timeout -= 2; + /* get bit position of highest bit set */ + timeout = 31 - __CLZ(timeout); + /* need to go one over */ + timeout += 1; + /* convert to wdog setting. if bit 4 is the highest, then the + * watchdog setting == 1. That means watchdog setting 0xF == 2^18 = 256k */ + if (timeout > 18) { + return WATCHDOG_STATUS_INVALID_ARGUMENT; + } + + timeout -= 3; + } + + WDOG_Init_TypeDef wdog_init = WDOG_INIT_DEFAULT; + wdog_init.clkSel = wdogClkSelULFRCO; + wdog_init.em2Run = true; + wdog_init.em3Run = true; + wdog_init.perSel = timeout; + + WDOGn_Init(DEFAULT_WDOG, &wdog_init); + + return WATCHDOG_STATUS_OK; +} + +void hal_watchdog_kick(void) +{ + WDOGn_Feed(DEFAULT_WDOG); +} + +watchdog_status_t hal_watchdog_stop(void) +{ + WDOGn_Enable(DEFAULT_WDOG, false); + return WATCHDOG_STATUS_OK; +} + +uint32_t hal_watchdog_get_reload_value(void) +{ + uint32_t period = (DEFAULT_WDOG->CTRL & _WDOG_CTRL_PERSEL_MASK) >> _WDOG_CTRL_PERSEL_SHIFT; + if (period == 0) { + return 9; + } else { + period += 3; + return (1U << period) + 1; + } +} + +watchdog_features_t hal_watchdog_get_platform_features(void) +{ + watchdog_features_t feat = { + .max_timeout = 262145, + .update_config = true, + .disable_watchdog = true + }; + return feat; +} + +#endif /* DEVICE_WATCHDOG */ diff --git a/targets/targets.json b/targets/targets.json index 9a3b9774f2f..edfa6fdcca8 100644 --- a/targets/targets.json +++ b/targets/targets.json @@ -5256,7 +5256,8 @@ "USTICKER", "FLASH", "ITM", - "MPU" + "MPU", + "WATCHDOG" ], "forced_reset_timeout": 2, "config": { @@ -5332,7 +5333,8 @@ "STDIO_MESSAGES", "USTICKER", "FLASH", - "MPU" + "MPU", + "WATCHDOG" ], "forced_reset_timeout": 2, "device_name": "EFM32LG990F256", @@ -5410,7 +5412,8 @@ "STDIO_MESSAGES", "USTICKER", "FLASH", - "MPU" + "MPU", + "WATCHDOG" ], "forced_reset_timeout": 2, "config": { @@ -5483,7 +5486,8 @@ "SPISLAVE", "SPI_ASYNCH", "STDIO_MESSAGES", - "USTICKER" + "USTICKER", + "WATCHDOG" ], "forced_reset_timeout": 2, "config": { @@ -5556,7 +5560,8 @@ "SPISLAVE", "SPI_ASYNCH", "STDIO_MESSAGES", - "USTICKER" + "USTICKER", + "WATCHDOG" ], "forced_reset_timeout": 2, "config": { @@ -5632,7 +5637,8 @@ "STDIO_MESSAGES", "USTICKER", "FLASH", - "MPU" + "MPU", + "WATCHDOG" ], "forced_reset_timeout": 2, "config": { @@ -5731,7 +5737,8 @@ "STDIO_MESSAGES", "USTICKER", "FLASH", - "MPU" + "MPU", + "WATCHDOG" ], "forced_reset_timeout": 2, "config": { @@ -5801,7 +5808,8 @@ "STDIO_MESSAGES", "USTICKER", "FLASH", - "MPU" + "MPU", + "WATCHDOG" ], "forced_reset_timeout": 5, "config": { @@ -5879,7 +5887,8 @@ "USTICKER", "TRNG", "FLASH", - "MPU" + "MPU", + "WATCHDOG" ], "forced_reset_timeout": 2, "config": { @@ -5967,7 +5976,8 @@ "USTICKER", "TRNG", "FLASH", - "MPU" + "MPU", + "WATCHDOG" ], "forced_reset_timeout": 5, "config": { From c3e94805087bafe68793cbb4acf3225cac7ddd8e Mon Sep 17 00:00:00 2001 From: Steven Cooreman Date: Tue, 27 Mar 2018 17:57:26 +0200 Subject: [PATCH 35/62] Add implementation of reset reason on Silicon Labs parts --- .../TARGET_EFM32/resetreason_api.c | 132 ++++++++++++++++++ targets/targets.json | 10 ++ 2 files changed, 142 insertions(+) create mode 100644 targets/TARGET_Silicon_Labs/TARGET_EFM32/resetreason_api.c diff --git a/targets/TARGET_Silicon_Labs/TARGET_EFM32/resetreason_api.c b/targets/TARGET_Silicon_Labs/TARGET_EFM32/resetreason_api.c new file mode 100644 index 00000000000..e0fd55135b3 --- /dev/null +++ b/targets/TARGET_Silicon_Labs/TARGET_EFM32/resetreason_api.c @@ -0,0 +1,132 @@ +/***************************************************************************//** + * @file resetreason_api.c + ******************************************************************************* + * @section License + * (C) Copyright 2018 Silicon Labs, http://www.silabs.com + ******************************************************************************* + * + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ******************************************************************************/ + +#include "device.h" +#include "reset_reason_api.h" + +#if DEVICE_RESET_REASON + +#include "em_rmu.h" + +reset_reason_t hal_reset_reason_get(void) +{ + uint32_t reasonmask = RMU_ResetCauseGet(); + + /* Only care about the upper bit, since that is 'most significant' reset reason */ + reasonmask = 1 << (31 - __CLZ(reasonmask)); + + if (reasonmask & RMU_RSTCAUSE_PORST) { + return RESET_REASON_POWER_ON; + } +#if defined(RMU_RSTCAUSE_BODUNREGRST) + if (reasonmask & RMU_RSTCAUSE_BODUNREGRST) { + return RESET_REASON_BROWN_OUT; + } +#endif +#if defined(RMU_RSTCAUSE_BODREGRST) + if (reasonmask & RMU_RSTCAUSE_BODREGRST) { + return RESET_REASON_BROWN_OUT; + } +#endif +#if defined(RMU_RSTCAUSE_AVDDBOD) + if (reasonmask & RMU_RSTCAUSE_AVDDBOD) { + return RESET_REASON_BROWN_OUT; + } +#endif +#if defined(RMU_RSTCAUSE_DVDDBOD) + if (reasonmask & RMU_RSTCAUSE_DVDDBOD) { + return RESET_REASON_BROWN_OUT; + } +#endif +#if defined(RMU_RSTCAUSE_DECBOD) + if (reasonmask & RMU_RSTCAUSE_DECBOD) { + return RESET_REASON_BROWN_OUT; + } +#endif + if (reasonmask & RMU_RSTCAUSE_EXTRST) { + return RESET_REASON_PIN_RESET; + } + if (reasonmask & RMU_RSTCAUSE_WDOGRST) { + return RESET_REASON_WATCHDOG; + } + if (reasonmask & RMU_RSTCAUSE_LOCKUPRST) { + return RESET_REASON_LOCKUP; + } + if (reasonmask & RMU_RSTCAUSE_SYSREQRST) { + return RESET_REASON_SOFTWARE; + } +#if defined(RMU_RSTCAUSE_EM4RST) + if (reasonmask & RMU_RSTCAUSE_EM4RST) { + return RESET_REASON_WAKE_LOW_POWER; + } +#endif +#if defined(RMU_RSTCAUSE_EM4WURST) + if (reasonmask & RMU_RSTCAUSE_EM4WURST) { + return RESET_REASON_WAKE_LOW_POWER; + } +#endif +#if defined(RMU_RSTCAUSE_BODAVDD0) + if (reasonmask & RMU_RSTCAUSE_BODAVDD0) { + return RESET_REASON_BROWN_OUT; + } +#endif +#if defined(RMU_RSTCAUSE_BODAVDD1) + if (reasonmask & RMU_RSTCAUSE_BODAVDD1) { + return RESET_REASON_BROWN_OUT; + } +#endif +#if defined(BU_PRESENT) && defined(_SILICON_LABS_32B_SERIES_0) + if (reasonmask & RMU_RSTCAUSE_BUBODVDDDREG) { + return RESET_REASON_BROWN_OUT; + } + if (reasonmask & RMU_RSTCAUSE_BUBODBUVIN) { + return RESET_REASON_BROWN_OUT; + } + if (reasonmask & RMU_RSTCAUSE_BUBODUNREG) { + return RESET_REASON_BROWN_OUT; + } + if (reasonmask & RMU_RSTCAUSE_BUBODREG) { + return RESET_REASON_BROWN_OUT; + } + if (reasonmask & RMU_RSTCAUSE_BUMODERST) { + return RESET_REASON_PLATFORM; + } +#elif defined(RMU_RSTCAUSE_BUMODERST) + if (reasonmask & RMU_RSTCAUSE_BUMODERST) { + return RESET_REASON_PLATFORM; + } +#endif + return RESET_REASON_UNKNOWN; +} + +uint32_t hal_reset_reason_get_raw(void) +{ + return RMU->RSTCAUSE; +} + +void hal_reset_reason_clear(void) +{ + RMU_ResetCauseClear(); +} + +#endif /* DEVICE_RESET_REASON */ diff --git a/targets/targets.json b/targets/targets.json index edfa6fdcca8..65bf1340f97 100644 --- a/targets/targets.json +++ b/targets/targets.json @@ -5245,6 +5245,7 @@ "PORTINOUT", "PORTOUT", "PWMOUT", + "RESET_REASON", "RTC", "SERIAL", "SERIAL_ASYNCH", @@ -5323,6 +5324,7 @@ "PORTINOUT", "PORTOUT", "PWMOUT", + "RESET_REASON", "RTC", "SERIAL", "SERIAL_ASYNCH", @@ -5402,6 +5404,7 @@ "PORTINOUT", "PORTOUT", "PWMOUT", + "RESET_REASON", "RTC", "SERIAL", "SERIAL_ASYNCH", @@ -5479,6 +5482,7 @@ "PORTINOUT", "PORTOUT", "PWMOUT", + "RESET_REASON", "SERIAL", "SERIAL_ASYNCH", "SLEEP", @@ -5553,6 +5557,7 @@ "PORTINOUT", "PORTOUT", "PWMOUT", + "RESET_REASON", "SERIAL", "SERIAL_ASYNCH", "SLEEP", @@ -5627,6 +5632,7 @@ "PORTINOUT", "PORTOUT", "PWMOUT", + "RESET_REASON", "RTC", "SERIAL", "SERIAL_ASYNCH", @@ -5727,6 +5733,7 @@ "PORTINOUT", "PORTOUT", "PWMOUT", + "RESET_REASON", "RTC", "SERIAL", "SERIAL_ASYNCH", @@ -5798,6 +5805,7 @@ "PORTINOUT", "PORTOUT", "PWMOUT", + "RESET_REASON", "RTC", "SERIAL", "SERIAL_ASYNCH", @@ -5876,6 +5884,7 @@ "PORTINOUT", "PORTOUT", "PWMOUT", + "RESET_REASON", "RTC", "SERIAL", "SERIAL_ASYNCH", @@ -5965,6 +5974,7 @@ "PORTINOUT", "PORTOUT", "PWMOUT", + "RESET_REASON", "RTC", "SERIAL", "SERIAL_ASYNCH", From b09129dcc94651df931f42e12d8496ace468947b Mon Sep 17 00:00:00 2001 From: Lukas Mandak Date: Wed, 28 Mar 2018 18:57:05 +0200 Subject: [PATCH 36/62] NCS36510: Added watchdog implementation. --- .../TARGET_NCS36510/watchdog_api.c | 114 ++++++++++++++++++ targets/targets.json | 1 + 2 files changed, 115 insertions(+) create mode 100644 targets/TARGET_ONSEMI/TARGET_NCS36510/watchdog_api.c diff --git a/targets/TARGET_ONSEMI/TARGET_NCS36510/watchdog_api.c b/targets/TARGET_ONSEMI/TARGET_NCS36510/watchdog_api.c new file mode 100644 index 00000000000..02c98c71f7a --- /dev/null +++ b/targets/TARGET_ONSEMI/TARGET_NCS36510/watchdog_api.c @@ -0,0 +1,114 @@ +/** + ******************************************************************************* + * @file watchdog_api.c + * @brief Implementation of watchdog_api + * @internal + * @author ON Semiconductor + ****************************************************************************** + * Copyright 2018 Semiconductor Components Industries LLC (d/b/a “ON Semiconductor”). + * All rights reserved. This software and/or documentation is licensed by ON Semiconductor + * under limited terms and conditions. The terms and conditions pertaining to the software + * and/or documentation are available at http://www.onsemi.com/site/pdf/ONSEMI_T&C.pdf + * (“ON Semiconductor Standard Terms and Conditions of Sale, Section 8 Software”) and + * if applicable the software license agreement. Do not use this software and/or + * documentation unless you have carefully read and you agree to the limited terms and + * conditions. By using this software and/or documentation, you agree to the limited + * terms and conditions. + * + * THIS SOFTWARE IS PROVIDED "AS IS". NO WARRANTIES, WHETHER EXPRESS, IMPLIED + * OR STATUTORY, INCLUDING, BUT NOT LIMITED TO, IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. + * ON SEMICONDUCTOR SHALL NOT, IN ANY CIRCUMSTANCES, BE LIABLE FOR SPECIAL, + * INCIDENTAL, OR CONSEQUENTIAL DAMAGES, FOR ANY REASON WHATSOEVER. + * @endinternal + * + */ +#include "watchdog_api.h" +#if DEVICE_WATCHDOG + +#include "clock.h" // Peripheral clock control definitions. +#include "wdt_map.h" // Watchdog hardware register definitions. +#include "memory_map.h" // Pointer to watchdog peripheral in memory. + + +// watchdog_api feature definitions +#define WDT_MAX_TIMEOUT_MS ((uint32_t)8000) +#define WDT_CAN_UPDATE ((boolean)True) +#define WDT_CAN_STOP ((boolean)True) + +// WDT LOAD register definitions +#define WDT_MAX_LOAD_VAL ((uint32_t)0x3FFFF) +#define WDT_TICKS_PER_MS (WDT_MAX_LOAD_VAL / WDT_MAX_TIMEOUT_MS) + +// WDT KICK register definitions +#define WDT_KICK_VAL ((uint32_t)1) + +// WDT LOCK register definitions +#define WDT_LOCK_DISABLE ((uint32_t)0x1ACCE551) +#define WDT_LOCK_ENABLE ((uint32_t)0x00000000) + + +watchdog_status_t hal_watchdog_init(const watchdog_config_t *config) +{ + if (!config || config->timeout_ms > WDT_MAX_TIMEOUT_MS || config->timeout_ms == 0) { + return WATCHDOG_STATUS_INVALID_ARGUMENT; + } + + if (!CLOCK_IS_ENABLED(CLOCK_WDOG)) { + CLOCK_ENABLE(CLOCK_WDOG); + } + + // Disable write lock in case WDT is being reconfigured. + WDTREG->LOCK = WDT_LOCK_DISABLE; + + while (WDTREG->STATUS.BITS.WRITE_BUSY_ANY); + WDTREG->LOAD = config->timeout_ms * WDT_TICKS_PER_MS; + + while (WDTREG->STATUS.BITS.WRITE_BUSY_LOAD); + WDTREG->CONTROL.BITS.WDT_EN = True; + + while (WDTREG->STATUS.BITS.WRITE_BUSY_CONTROL); + WDTREG->LOCK = WDT_LOCK_ENABLE; + + return WATCHDOG_STATUS_OK; +} + +void hal_watchdog_kick(void) +{ + // Write any value to kick watchdog. + WDTREG->KICK = WDT_KICK_VAL; +} + +watchdog_status_t hal_watchdog_stop(void) +{ + WDTREG->LOCK = WDT_LOCK_DISABLE; + + while (WDTREG->STATUS.BITS.WRITE_BUSY_ANY); + WDTREG->CONTROL.BITS.WDT_EN = False; + + while (WDTREG->STATUS.BITS.WRITE_BUSY_ANY); + CLOCK_DISABLE(CLOCK_WDOG); + + return WATCHDOG_STATUS_OK; +} + +uint32_t hal_watchdog_get_reload_value(void) +{ + while (WDTREG->STATUS.BITS.WRITE_BUSY_LOAD); + return WDTREG->LOAD / WDT_TICKS_PER_MS; +} + +watchdog_features_t hal_watchdog_get_platform_features(void) +{ + const watchdog_features_t features = { + .max_timeout = WDT_MAX_TIMEOUT_MS, + .update_config = WDT_CAN_UPDATE, + .disable_watchdog = WDT_CAN_STOP + }; + + return features; +} + + +#endif // DEVICE_WATCHDOG + diff --git a/targets/targets.json b/targets/targets.json index 65bf1340f97..eb64913d9f6 100644 --- a/targets/targets.json +++ b/targets/targets.json @@ -6882,6 +6882,7 @@ "SPI", "TRNG", "SPISLAVE", + "WATCHDOG", "802_15_4_PHY", "MPU" ], From c458c2bb5de9d0f7d7c860bce7ad66eab5c70bad Mon Sep 17 00:00:00 2001 From: jeromecoutant Date: Tue, 27 Mar 2018 14:54:40 +0200 Subject: [PATCH 37/62] STM32 Watchdog : move API file to STM family level --- targets/TARGET_STM/{TARGET_STM32F4 => }/watchdog_api.c | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename targets/TARGET_STM/{TARGET_STM32F4 => }/watchdog_api.c (100%) diff --git a/targets/TARGET_STM/TARGET_STM32F4/watchdog_api.c b/targets/TARGET_STM/watchdog_api.c similarity index 100% rename from targets/TARGET_STM/TARGET_STM32F4/watchdog_api.c rename to targets/TARGET_STM/watchdog_api.c From 7d46c96fe31657784ded9555aadf72bf1bb039b6 Mon Sep 17 00:00:00 2001 From: jeromecoutant Date: Tue, 27 Mar 2018 17:36:05 +0200 Subject: [PATCH 38/62] STM32 WATCHDOG : compilation issue with typed define --- targets/TARGET_STM/TARGET_STM32L0/device/stm32l0xx_hal_conf.h | 2 +- targets/TARGET_STM/TARGET_STM32L4/device/stm32l4xx_hal_conf.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/targets/TARGET_STM/TARGET_STM32L0/device/stm32l0xx_hal_conf.h b/targets/TARGET_STM/TARGET_STM32L0/device/stm32l0xx_hal_conf.h index b157dc88ee5..364c00cbe74 100644 --- a/targets/TARGET_STM/TARGET_STM32L0/device/stm32l0xx_hal_conf.h +++ b/targets/TARGET_STM/TARGET_STM32L0/device/stm32l0xx_hal_conf.h @@ -132,7 +132,7 @@ * @brief Internal Low Speed oscillator (LSI) value. */ #if !defined (LSI_VALUE) - #define LSI_VALUE ((uint32_t)37000U) /*!< LSI Typical Value in Hz*/ + #define LSI_VALUE (37000U) /*!< LSI Typical Value in Hz*/ #endif /* LSI_VALUE */ /*!< Value of the Internal Low Speed oscillator in Hz The real value may vary depending on the variations in voltage and temperature.*/ diff --git a/targets/TARGET_STM/TARGET_STM32L4/device/stm32l4xx_hal_conf.h b/targets/TARGET_STM/TARGET_STM32L4/device/stm32l4xx_hal_conf.h index 5ad54eb7133..ae27ce2da11 100644 --- a/targets/TARGET_STM/TARGET_STM32L4/device/stm32l4xx_hal_conf.h +++ b/targets/TARGET_STM/TARGET_STM32L4/device/stm32l4xx_hal_conf.h @@ -148,7 +148,7 @@ * @brief Internal Low Speed oscillator (LSI) value. */ #if !defined (LSI_VALUE) - #define LSI_VALUE ((uint32_t)32000U) /*!< LSI Typical Value in Hz*/ + #define LSI_VALUE (32000U) /*!< LSI Typical Value in Hz*/ #endif /* LSI_VALUE */ /*!< Value of the Internal Low Speed oscillator in Hz The real value may vary depending on the variations in voltage and temperature.*/ From 0e74158e071f701a51d6992a5cf6a1b8daab642a Mon Sep 17 00:00:00 2001 From: jeromecoutant Date: Tue, 27 Mar 2018 19:42:12 +0200 Subject: [PATCH 39/62] STM32 WATCHDOG : update STM32L0 HAL_IWDG_Init to a newest version --- .../TARGET_STM/TARGET_STM32L0/device/stm32l0xx_hal_iwdg.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/targets/TARGET_STM/TARGET_STM32L0/device/stm32l0xx_hal_iwdg.c b/targets/TARGET_STM/TARGET_STM32L0/device/stm32l0xx_hal_iwdg.c index 6310686cd80..9e45c4a8219 100644 --- a/targets/TARGET_STM/TARGET_STM32L0/device/stm32l0xx_hal_iwdg.c +++ b/targets/TARGET_STM/TARGET_STM32L0/device/stm32l0xx_hal_iwdg.c @@ -197,7 +197,7 @@ HAL_StatusTypeDef HAL_IWDG_Init(IWDG_HandleTypeDef *hiwdg) /* Check pending flag, if previous update not done, return timeout */ tickstart = HAL_GetTick(); - /* Wait for register to be updated */ + /* Wait for register to be updated */ while(hiwdg->Instance->SR != RESET) { if((HAL_GetTick() - tickstart ) > HAL_IWDG_DEFAULT_TIMEOUT) @@ -206,12 +206,12 @@ HAL_StatusTypeDef HAL_IWDG_Init(IWDG_HandleTypeDef *hiwdg) } } - /* If window parameter is different than current value, modify window + /* If window parameter is different than current value, modify window register */ if(hiwdg->Instance->WINR != hiwdg->Init.Window) { /* Write to IWDG WINR the IWDG_Window value to compare with. In any case, - even if window feature is disabled, Watchdog will be reloaded by writing + even if window feature is disabled, Watchdog will be reloaded by writing windows register */ hiwdg->Instance->WINR = hiwdg->Init.Window; } From 3d2f34bac349d592ff05a511b95bb1de85427bfb Mon Sep 17 00:00:00 2001 From: jeromecoutant Date: Tue, 27 Mar 2018 19:43:06 +0200 Subject: [PATCH 40/62] STM32 WATCHDOG : use ST HAL in order to make code commun for all STM32 --- targets/TARGET_STM/watchdog_api.c | 51 +++++++++++-------------------- 1 file changed, 18 insertions(+), 33 deletions(-) diff --git a/targets/TARGET_STM/watchdog_api.c b/targets/TARGET_STM/watchdog_api.c index 3a0060996b7..47da70cc6c9 100644 --- a/targets/TARGET_STM/watchdog_api.c +++ b/targets/TARGET_STM/watchdog_api.c @@ -1,5 +1,5 @@ /* mbed Microcontroller Library - * Copyright (c) 2006-2017 ARM Limited + * Copyright (c) 2006-2018 ARM Limited * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -14,17 +14,15 @@ * limitations under the License. */ -#include "watchdog_api.h" - -#include "reset_reason_api.h" #ifdef DEVICE_WATCHDOG +#include "watchdog_api.h" +#include "reset_reason_api.h" #include "device.h" - +#include "mbed_error.h" #include -#define LSI_RC_HZ 32000 // Frequency of the low-speed internal RC oscillator that drives IWDG #define MAX_IWDG_PR 0x6 // Max value of Prescaler_divider bits (PR) of Prescaler_register (IWDG_PR) #define MAX_IWDG_RL 0xFFFUL // Max value of Watchdog_counter_reload_value bits (RL) of Reload_register (IWDG_RLR). @@ -36,12 +34,12 @@ // and Watchdog_counter_reload_value bits (RL) of Reload_register (IWDG_RLR) // to a timeout value [ms]. #define PR_RL2UINT64_TIMEOUT_MS(PR_BITS, RL_BITS) \ - ((PR2PRESCALER_DIV(PR_BITS)) * (RL_BITS) * 1000ULL / (LSI_RC_HZ)) + ((PR2PRESCALER_DIV(PR_BITS)) * (RL_BITS) * 1000ULL / (LSI_VALUE)) // Convert Prescaler_divider bits (PR) of Prescaler_register (IWDG_PR) and a timeout value [ms] // to Watchdog_counter_reload_value bits (RL) of Reload_register (IWDG_RLR) #define PR_TIMEOUT_MS2RL(PR_BITS, TIMEOUT_MS) \ - ((TIMEOUT_MS) * (LSI_RC_HZ) / (PR2PRESCALER_DIV(PR_BITS)) / 1000UL) + ((TIMEOUT_MS) * (LSI_VALUE) / (PR2PRESCALER_DIV(PR_BITS)) / 1000UL) #define MAX_TIMEOUT_MS_UINT64 PR_RL2UINT64_TIMEOUT_MS(MAX_IWDG_PR, MAX_IWDG_RL) #if (MAX_TIMEOUT_MS_UINT64 > UINT32_MAX) @@ -64,6 +62,8 @@ static uint8_t pick_min_iwdg_pr(const uint32_t timeout_ms) { return INVALID_IWDG_PR; } +IWDG_HandleTypeDef IwdgHandle; + watchdog_status_t hal_watchdog_init(const watchdog_config_t *config) { const uint8_t pr = pick_min_iwdg_pr(config->timeout_ms); @@ -72,40 +72,25 @@ watchdog_status_t hal_watchdog_init(const watchdog_config_t *config) } const uint32_t rl = PR_TIMEOUT_MS2RL(pr, config->timeout_ms); - // Set the Key_value bits (KEY) of Key_register (IWDG_KR) to 0x5555 - // in order to enable write access to IWDG_PR and IWDG_RLR registers. - MODIFY_REG(IWDG->KR, IWDG_KR_KEY_Msk, (IWDG_KR_KEY_Msk & (0x5555U << IWDG_KR_KEY_Pos))); + IwdgHandle.Instance = IWDG; - // Wait for the Watchdog_prescaler_value_update bit (PVU) of - // Status_register (IWDG_SR) to be reset. - while (READ_BIT(IWDG->SR, IWDG_SR_PVU)) { - } - // Set the Prescaler_divider bits (PR) of Prescaler_register (IWDG_PR). - MODIFY_REG(IWDG->PR, IWDG_PR_PR_Msk, (IWDG_PR_PR_Msk & (pr << IWDG_PR_PR_Pos))); + IwdgHandle.Init.Prescaler = pr; + IwdgHandle.Init.Reload = rl; +#if defined IWDG_WINR_WIN + IwdgHandle.Init.Window = IWDG_WINDOW_DISABLE; +#endif - // Wait for the Watchdog_counter_reload_value_update bit (RVU) of - // Status_register (IWDG_SR) to be reset. - while (READ_BIT(IWDG->SR, IWDG_SR_RVU)) { + if (HAL_IWDG_Init(&IwdgHandle) != HAL_OK) + { + error("HAL_IWDG_Init error\n"); } - // Set the Watchdog_counter_reload_value bits (RL) of Reload_register (IWDG_RLR). - MODIFY_REG(IWDG->RLR, IWDG_RLR_RL_Msk, (IWDG_RLR_RL_Msk & (rl << IWDG_RLR_RL_Pos))); - - // Set the Key_value bits (KEY) of Key_register (IWDG_KR) to 0xAAAA - // in order to reload IWDG_RLR register value. - MODIFY_REG(IWDG->KR, IWDG_KR_KEY_Msk, (IWDG_KR_KEY_Msk & (0xAAAAU << IWDG_KR_KEY_Pos))); - - // Set the Key_value bits (KEY) of Key_register (IWDG_KR) to 0xCCCC - // in order to start the watchdog. - MODIFY_REG(IWDG->KR, IWDG_KR_KEY_Msk, (IWDG_KR_KEY_Msk & (0xCCCCU << IWDG_KR_KEY_Pos))); return WATCHDOG_STATUS_OK; } void hal_watchdog_kick(void) { - // Set the Key_value bits (KEY) of Key_register (IWDG_KR) to 0xAAAA - // in order to reload IWDG_RLR register value. - MODIFY_REG(IWDG->KR, IWDG_KR_KEY_Msk, (IWDG_KR_KEY_Msk & (0xAAAAU << IWDG_KR_KEY_Pos))); + HAL_IWDG_Refresh(&IwdgHandle); } watchdog_status_t hal_watchdog_stop(void) From bfcfbae584618ee5b4665e8d4cd75a1fd5057510 Mon Sep 17 00:00:00 2001 From: jeromecoutant Date: Thu, 29 Mar 2018 10:56:54 +0200 Subject: [PATCH 41/62] STM32 WATCHDOG : increase timeout value --- .../TARGET_STM/TARGET_STM32F0/device/stm32f0xx_hal_iwdg.c | 6 ++---- .../TARGET_STM/TARGET_STM32F1/device/stm32f1xx_hal_iwdg.c | 1 + .../TARGET_STM/TARGET_STM32F2/device/stm32f2xx_hal_iwdg.c | 6 ++---- .../TARGET_STM/TARGET_STM32F3/device/stm32f3xx_hal_iwdg.c | 6 ++---- .../TARGET_STM/TARGET_STM32F4/device/stm32f4xx_hal_iwdg.c | 6 ++---- .../TARGET_STM/TARGET_STM32F7/device/stm32f7xx_hal_iwdg.c | 6 ++---- .../TARGET_STM/TARGET_STM32L1/device/stm32l1xx_hal_iwdg.c | 6 ++---- .../TARGET_STM/TARGET_STM32L4/device/stm32l4xx_hal_iwdg.c | 6 ++---- 8 files changed, 15 insertions(+), 28 deletions(-) diff --git a/targets/TARGET_STM/TARGET_STM32F0/device/stm32f0xx_hal_iwdg.c b/targets/TARGET_STM/TARGET_STM32F0/device/stm32f0xx_hal_iwdg.c index 1899f1f862d..c0be82e22e1 100644 --- a/targets/TARGET_STM/TARGET_STM32F0/device/stm32f0xx_hal_iwdg.c +++ b/targets/TARGET_STM/TARGET_STM32F0/device/stm32f0xx_hal_iwdg.c @@ -124,10 +124,8 @@ /** @defgroup IWDG_Private_Defines IWDG Private Defines * @{ */ -/* Status register need 5 RC LSI divided by prescaler clock to be updated. With - higher prescaler (256), and according to LSI variation, we need to wait at - least 6 cycles so 39 ms. */ -#define HAL_IWDG_DEFAULT_TIMEOUT 39U +/* MBED */ +#define HAL_IWDG_DEFAULT_TIMEOUT 96u /** * @} */ diff --git a/targets/TARGET_STM/TARGET_STM32F1/device/stm32f1xx_hal_iwdg.c b/targets/TARGET_STM/TARGET_STM32F1/device/stm32f1xx_hal_iwdg.c index d654662cc5d..b762736e78c 100644 --- a/targets/TARGET_STM/TARGET_STM32F1/device/stm32f1xx_hal_iwdg.c +++ b/targets/TARGET_STM/TARGET_STM32F1/device/stm32f1xx_hal_iwdg.c @@ -121,6 +121,7 @@ higher prescaler (256), and according to HSI variation, we need to wait at least 6 cycles so 48 ms. */ #define HAL_IWDG_DEFAULT_TIMEOUT 48U + /** * @} */ diff --git a/targets/TARGET_STM/TARGET_STM32F2/device/stm32f2xx_hal_iwdg.c b/targets/TARGET_STM/TARGET_STM32F2/device/stm32f2xx_hal_iwdg.c index b680c070fdd..f75e2eac66c 100644 --- a/targets/TARGET_STM/TARGET_STM32F2/device/stm32f2xx_hal_iwdg.c +++ b/targets/TARGET_STM/TARGET_STM32F2/device/stm32f2xx_hal_iwdg.c @@ -119,10 +119,8 @@ /** @defgroup IWDG_Private_Defines IWDG Private Defines * @{ */ -/* Status register need 5 RC LSI divided by prescaler clock to be updated. With - higher prescaler (256), and according to HSI variation, we need to wait at - least 6 cycles so 48 ms. */ -#define HAL_IWDG_DEFAULT_TIMEOUT 48U +/* MBED */ +#define HAL_IWDG_DEFAULT_TIMEOUT 96u /** * @} */ diff --git a/targets/TARGET_STM/TARGET_STM32F3/device/stm32f3xx_hal_iwdg.c b/targets/TARGET_STM/TARGET_STM32F3/device/stm32f3xx_hal_iwdg.c index 479f4d95072..b576778df2c 100644 --- a/targets/TARGET_STM/TARGET_STM32F3/device/stm32f3xx_hal_iwdg.c +++ b/targets/TARGET_STM/TARGET_STM32F3/device/stm32f3xx_hal_iwdg.c @@ -124,10 +124,8 @@ /** @defgroup IWDG_Private_Defines IWDG Private Defines * @{ */ -/* Status register need 5 RC LSI divided by prescaler clock to be updated. With - higher prescaler (256U), and according to HSI variation, we need to wait at - least 6 cycles so 48 ms. */ -#define HAL_IWDG_DEFAULT_TIMEOUT 48u +/* MBED */ +#define HAL_IWDG_DEFAULT_TIMEOUT 96u /** * @} */ diff --git a/targets/TARGET_STM/TARGET_STM32F4/device/stm32f4xx_hal_iwdg.c b/targets/TARGET_STM/TARGET_STM32F4/device/stm32f4xx_hal_iwdg.c index 672aad16246..721f6011b30 100644 --- a/targets/TARGET_STM/TARGET_STM32F4/device/stm32f4xx_hal_iwdg.c +++ b/targets/TARGET_STM/TARGET_STM32F4/device/stm32f4xx_hal_iwdg.c @@ -117,10 +117,8 @@ /** @defgroup IWDG_Private_Defines IWDG Private Defines * @{ */ -/* Status register need 5 RC LSI divided by prescaler clock to be updated. With - higher prescaler (256), and according to HSI variation, we need to wait at - least 6 cycles so 48 ms. */ -#define HAL_IWDG_DEFAULT_TIMEOUT 48U +/* MBED */ +#define HAL_IWDG_DEFAULT_TIMEOUT 96u /** * @} */ diff --git a/targets/TARGET_STM/TARGET_STM32F7/device/stm32f7xx_hal_iwdg.c b/targets/TARGET_STM/TARGET_STM32F7/device/stm32f7xx_hal_iwdg.c index 4a2dda8465f..85dc4794462 100644 --- a/targets/TARGET_STM/TARGET_STM32F7/device/stm32f7xx_hal_iwdg.c +++ b/targets/TARGET_STM/TARGET_STM32F7/device/stm32f7xx_hal_iwdg.c @@ -124,10 +124,8 @@ /** @defgroup IWDG_Private_Defines IWDG Private Defines * @{ */ -/* Status register need 5 RC LSI divided by prescaler clock to be updated. With - higher prescaler (256), and according to LSI variation, we need to wait at - least 6 cycles so 48 ms. */ -#define HAL_IWDG_DEFAULT_TIMEOUT 48u +/* MBED */ +#define HAL_IWDG_DEFAULT_TIMEOUT 96u /** * @} */ diff --git a/targets/TARGET_STM/TARGET_STM32L1/device/stm32l1xx_hal_iwdg.c b/targets/TARGET_STM/TARGET_STM32L1/device/stm32l1xx_hal_iwdg.c index 7f89b5611aa..c057cff97c6 100644 --- a/targets/TARGET_STM/TARGET_STM32L1/device/stm32l1xx_hal_iwdg.c +++ b/targets/TARGET_STM/TARGET_STM32L1/device/stm32l1xx_hal_iwdg.c @@ -118,10 +118,8 @@ /** @defgroup IWDG_Private_Defines IWDG Private Defines * @{ */ -/* Status register need 5 RC LSI divided by prescaler clock to be updated. With - higher prescaler (256), and according to HSI variation, we need to wait at - least 6 cycles so 48 ms. */ -#define HAL_IWDG_DEFAULT_TIMEOUT 48u +/* MBED */ +#define HAL_IWDG_DEFAULT_TIMEOUT 96u /** * @} */ diff --git a/targets/TARGET_STM/TARGET_STM32L4/device/stm32l4xx_hal_iwdg.c b/targets/TARGET_STM/TARGET_STM32L4/device/stm32l4xx_hal_iwdg.c index e5080c41b1e..a415996a538 100644 --- a/targets/TARGET_STM/TARGET_STM32L4/device/stm32l4xx_hal_iwdg.c +++ b/targets/TARGET_STM/TARGET_STM32L4/device/stm32l4xx_hal_iwdg.c @@ -124,10 +124,8 @@ /** @defgroup IWDG_Private_Defines IWDG Private Defines * @{ */ -/* Status register need 5 RC LSI divided by prescaler clock to be updated. With - higher prescaler (256), and according to HSI variation, we need to wait at - least 6 cycles so 48 ms. */ -#define HAL_IWDG_DEFAULT_TIMEOUT 48u +/* MBED */ +#define HAL_IWDG_DEFAULT_TIMEOUT 96u /** * @} */ From 2b0fc64e7457eafae2c81d0390123df2a9b4db65 Mon Sep 17 00:00:00 2001 From: Qinghao Shi Date: Tue, 26 Jun 2018 10:49:12 +0100 Subject: [PATCH 42/62] fix bugs introduced on rebase --- targets/targets.json | 1 + 1 file changed, 1 insertion(+) diff --git a/targets/targets.json b/targets/targets.json index eb64913d9f6..a579102b3f2 100644 --- a/targets/targets.json +++ b/targets/targets.json @@ -1469,6 +1469,7 @@ "PORTINOUT", "PORTOUT", "PWMOUT", + "RESET_REASON", "SERIAL", "SERIAL_FC", "SERIAL_ASYNCH", From b75f96961b7aa7df8526709e3940b98b79f7d217 Mon Sep 17 00:00:00 2001 From: ccli8 Date: Tue, 17 Jul 2018 14:47:29 +0800 Subject: [PATCH 43/62] [NUC472] Fix WDT driver in BSP --- .../TARGET_NUC472/device/StdDriver/nuc472_wdt.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/targets/TARGET_NUVOTON/TARGET_NUC472/device/StdDriver/nuc472_wdt.c b/targets/TARGET_NUVOTON/TARGET_NUC472/device/StdDriver/nuc472_wdt.c index 41905b792d3..4a9c34ac67e 100644 --- a/targets/TARGET_NUVOTON/TARGET_NUC472/device/StdDriver/nuc472_wdt.c +++ b/targets/TARGET_NUVOTON/TARGET_NUC472/device/StdDriver/nuc472_wdt.c @@ -1,8 +1,8 @@ /**************************************************************************//** * @file wdt.c * @version V1.00 - * $Revision: 6 $ - * $Date: 14/10/02 7:19p $ + * $Revision: 9 $ + * $Date: 15/11/12 9:49a $ * @brief NUC472/NUC442 WDT driver source file * * @note @@ -49,9 +49,10 @@ void WDT_Open(uint32_t u32TimeoutInterval, uint32_t u32EnableWakeup) { - WDT->CTL = u32TimeoutInterval | u32ResetDelay | WDT_CTL_WDTEN_Msk | + WDT->CTL = u32TimeoutInterval | WDT_CTL_WDTEN_Msk | (u32EnableReset << WDT_CTL_RSTEN_Pos) | (u32EnableWakeup << WDT_CTL_WKEN_Pos); + WDT->ALTCTL = u32ResetDelay; return; } From 09c97907714f5cd63bd320fd2af25cd82603e8a6 Mon Sep 17 00:00:00 2001 From: ccli8 Date: Thu, 12 Jul 2018 17:39:29 +0800 Subject: [PATCH 44/62] [Nuvoton] Support reset reason --- .../TARGET_NUVOTON/TARGET_M451/reset_reason.c | 106 ++++++++++++++++++ .../TARGET_NUVOTON/TARGET_M480/reset_reason.c | 106 ++++++++++++++++++ .../TARGET_NANO100/reset_reason.c | 87 ++++++++++++++ .../TARGET_NUC472/reset_reason.c | 93 +++++++++++++++ targets/targets.json | 4 + 5 files changed, 396 insertions(+) create mode 100644 targets/TARGET_NUVOTON/TARGET_M451/reset_reason.c create mode 100644 targets/TARGET_NUVOTON/TARGET_M480/reset_reason.c create mode 100644 targets/TARGET_NUVOTON/TARGET_NANO100/reset_reason.c create mode 100644 targets/TARGET_NUVOTON/TARGET_NUC472/reset_reason.c diff --git a/targets/TARGET_NUVOTON/TARGET_M451/reset_reason.c b/targets/TARGET_NUVOTON/TARGET_M451/reset_reason.c new file mode 100644 index 00000000000..91c29b6512a --- /dev/null +++ b/targets/TARGET_NUVOTON/TARGET_M451/reset_reason.c @@ -0,0 +1,106 @@ +/* mbed Microcontroller Library + * Copyright (c) 2017-2018 Nuvoton + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "reset_reason_api.h" + +#if DEVICE_RESET_REASON + +#include "cmsis.h" + +/* All reset source flags */ +#define SYS_RSTSTS_ALLRF_Msk \ + (SYS_RSTSTS_PORF_Msk | \ + SYS_RSTSTS_PINRF_Msk | \ + SYS_RSTSTS_WDTRF_Msk | \ + SYS_RSTSTS_LVRF_Msk | \ + SYS_RSTSTS_BODRF_Msk | \ + SYS_RSTSTS_SYSRF_Msk | \ + SYS_RSTSTS_CPURF_Msk | \ + SYS_RSTSTS_CPULKRF_Msk) + +reset_reason_t hal_reset_reason_get(void) +{ + uint32_t reset_reason_raw = hal_reset_reason_get_raw(); + reset_reason_t reset_reason_cast; + uint32_t reset_reason_count = 0; + + if (SYS_IS_POR_RST()) { + reset_reason_cast = RESET_REASON_POWER_ON; + reset_reason_count ++; + } + + if (SYS_IS_RSTPIN_RST()) { + reset_reason_cast = RESET_REASON_PIN_RESET; + reset_reason_count ++; + } + + if (SYS_IS_WDT_RST()) { + reset_reason_cast = RESET_REASON_WATCHDOG; + reset_reason_count ++; + } + + if (SYS_IS_LVR_RST()) { + reset_reason_cast = RESET_REASON_PLATFORM; + reset_reason_count ++; + } + + if (SYS_IS_BOD_RST()) { + reset_reason_cast = RESET_REASON_BROWN_OUT; + reset_reason_count ++; + } + + /* This MCU supports MKROM and we need to take care of bootloader/SYSRESETREQ flow. */ + if (SYS_IS_SYSTEM_RST()) { + if (reset_reason_raw & (SYS_RSTSTS_ALLRF_Msk & ~SYS_RSTSTS_SYSRF_Msk)) { + /* We may boot from bootloader which would reset to go to LDROM/APROM at its end + * through writing 1 to SYSRESETREQ bit. If there are other reset reasons, we think + * it is just the case and ignore the reset reason with SYSRESETREQ. */ + } else { + reset_reason_cast = RESET_REASON_SOFTWARE; + reset_reason_count ++; + } + } + + if (SYS_IS_CPU_RST()) { + reset_reason_cast = RESET_REASON_PLATFORM; + reset_reason_count ++; + } + + if (reset_reason_raw & SYS_RSTSTS_CPULKRF_Msk) { + reset_reason_cast = RESET_REASON_LOCKUP; + reset_reason_count ++; + } + + if (reset_reason_count == 0) { + reset_reason_cast = RESET_REASON_UNKNOWN; + } else if (reset_reason_count >= 2) { + reset_reason_cast = RESET_REASON_MULTIPLE; + } + + return reset_reason_cast; +} + +uint32_t hal_reset_reason_get_raw(void) +{ + return (SYS->RSTSTS & SYS_RSTSTS_ALLRF_Msk); +} + +void hal_reset_reason_clear(void) +{ + SYS_CLEAR_RST_SOURCE(SYS->RSTSTS); +} + +#endif diff --git a/targets/TARGET_NUVOTON/TARGET_M480/reset_reason.c b/targets/TARGET_NUVOTON/TARGET_M480/reset_reason.c new file mode 100644 index 00000000000..91c29b6512a --- /dev/null +++ b/targets/TARGET_NUVOTON/TARGET_M480/reset_reason.c @@ -0,0 +1,106 @@ +/* mbed Microcontroller Library + * Copyright (c) 2017-2018 Nuvoton + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "reset_reason_api.h" + +#if DEVICE_RESET_REASON + +#include "cmsis.h" + +/* All reset source flags */ +#define SYS_RSTSTS_ALLRF_Msk \ + (SYS_RSTSTS_PORF_Msk | \ + SYS_RSTSTS_PINRF_Msk | \ + SYS_RSTSTS_WDTRF_Msk | \ + SYS_RSTSTS_LVRF_Msk | \ + SYS_RSTSTS_BODRF_Msk | \ + SYS_RSTSTS_SYSRF_Msk | \ + SYS_RSTSTS_CPURF_Msk | \ + SYS_RSTSTS_CPULKRF_Msk) + +reset_reason_t hal_reset_reason_get(void) +{ + uint32_t reset_reason_raw = hal_reset_reason_get_raw(); + reset_reason_t reset_reason_cast; + uint32_t reset_reason_count = 0; + + if (SYS_IS_POR_RST()) { + reset_reason_cast = RESET_REASON_POWER_ON; + reset_reason_count ++; + } + + if (SYS_IS_RSTPIN_RST()) { + reset_reason_cast = RESET_REASON_PIN_RESET; + reset_reason_count ++; + } + + if (SYS_IS_WDT_RST()) { + reset_reason_cast = RESET_REASON_WATCHDOG; + reset_reason_count ++; + } + + if (SYS_IS_LVR_RST()) { + reset_reason_cast = RESET_REASON_PLATFORM; + reset_reason_count ++; + } + + if (SYS_IS_BOD_RST()) { + reset_reason_cast = RESET_REASON_BROWN_OUT; + reset_reason_count ++; + } + + /* This MCU supports MKROM and we need to take care of bootloader/SYSRESETREQ flow. */ + if (SYS_IS_SYSTEM_RST()) { + if (reset_reason_raw & (SYS_RSTSTS_ALLRF_Msk & ~SYS_RSTSTS_SYSRF_Msk)) { + /* We may boot from bootloader which would reset to go to LDROM/APROM at its end + * through writing 1 to SYSRESETREQ bit. If there are other reset reasons, we think + * it is just the case and ignore the reset reason with SYSRESETREQ. */ + } else { + reset_reason_cast = RESET_REASON_SOFTWARE; + reset_reason_count ++; + } + } + + if (SYS_IS_CPU_RST()) { + reset_reason_cast = RESET_REASON_PLATFORM; + reset_reason_count ++; + } + + if (reset_reason_raw & SYS_RSTSTS_CPULKRF_Msk) { + reset_reason_cast = RESET_REASON_LOCKUP; + reset_reason_count ++; + } + + if (reset_reason_count == 0) { + reset_reason_cast = RESET_REASON_UNKNOWN; + } else if (reset_reason_count >= 2) { + reset_reason_cast = RESET_REASON_MULTIPLE; + } + + return reset_reason_cast; +} + +uint32_t hal_reset_reason_get_raw(void) +{ + return (SYS->RSTSTS & SYS_RSTSTS_ALLRF_Msk); +} + +void hal_reset_reason_clear(void) +{ + SYS_CLEAR_RST_SOURCE(SYS->RSTSTS); +} + +#endif diff --git a/targets/TARGET_NUVOTON/TARGET_NANO100/reset_reason.c b/targets/TARGET_NUVOTON/TARGET_NANO100/reset_reason.c new file mode 100644 index 00000000000..a2ea29c464c --- /dev/null +++ b/targets/TARGET_NUVOTON/TARGET_NANO100/reset_reason.c @@ -0,0 +1,87 @@ +/* mbed Microcontroller Library + * Copyright (c) 2017-2018 Nuvoton + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "reset_reason_api.h" + +#if DEVICE_RESET_REASON + +#include "cmsis.h" + +/* All reset source flags */ +#define SYS_RST_SRC_ALL_Msk \ + (SYS_RST_SRC_RSTS_POR_Msk | \ + SYS_RST_SRC_RSTS_PAD_Msk | \ + SYS_RST_SRC_RSTS_WDT_Msk | \ + SYS_RST_SRC_RSTS_BOD_Msk | \ + SYS_RST_SRC_RSTS_SYS_Msk | \ + SYS_RST_SRC_RSTS_CPU_Msk) + +reset_reason_t hal_reset_reason_get(void) +{ + reset_reason_t reset_reason_cast; + uint32_t reset_reason_count = 0; + + if (SYS_IS_POR_RST()) { + reset_reason_cast = RESET_REASON_POWER_ON; + reset_reason_count ++; + } + + if (SYS_IS_RSTPIN_RST()) { + reset_reason_cast = RESET_REASON_PIN_RESET; + reset_reason_count ++; + } + + if (SYS_IS_WDT_RST()) { + reset_reason_cast = RESET_REASON_WATCHDOG; + reset_reason_count ++; + } + + if (SYS_IS_BOD_RST()) { + reset_reason_cast = RESET_REASON_BROWN_OUT; + reset_reason_count ++; + } + + /* This MCU doesn't support MKROM and we needn't take care of bootloader/SYSRESETREQ flow. */ + if (SYS_IS_SYSTEM_RST()) { + reset_reason_cast = RESET_REASON_SOFTWARE; + reset_reason_count ++; + } + + if (SYS_IS_CPU_RST()) { + reset_reason_cast = RESET_REASON_PLATFORM; + reset_reason_count ++; + } + + if (reset_reason_count == 0) { + reset_reason_cast = RESET_REASON_UNKNOWN; + } else if (reset_reason_count >= 2) { + reset_reason_cast = RESET_REASON_MULTIPLE; + } + + return reset_reason_cast; +} + +uint32_t hal_reset_reason_get_raw(void) +{ + return (SYS->RST_SRC & SYS_RST_SRC_ALL_Msk); +} + +void hal_reset_reason_clear(void) +{ + SYS_CLEAR_RST_SOURCE(SYS->RST_SRC); +} + +#endif diff --git a/targets/TARGET_NUVOTON/TARGET_NUC472/reset_reason.c b/targets/TARGET_NUVOTON/TARGET_NUC472/reset_reason.c new file mode 100644 index 00000000000..2f8f5bc5158 --- /dev/null +++ b/targets/TARGET_NUVOTON/TARGET_NUC472/reset_reason.c @@ -0,0 +1,93 @@ +/* mbed Microcontroller Library + * Copyright (c) 2017-2018 Nuvoton + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "reset_reason_api.h" + +#if DEVICE_RESET_REASON + +#include "cmsis.h" + +/* All reset source flags */ +#define SYS_RSTSTS_ALLRF_Msk \ + (SYS_RSTSTS_PORF_Msk | \ + SYS_RSTSTS_PINRF_Msk | \ + SYS_RSTSTS_WDTRF_Msk | \ + SYS_RSTSTS_LVRF_Msk | \ + SYS_RSTSTS_BODRF_Msk | \ + SYS_RSTSTS_SYSRF_Msk | \ + SYS_RSTSTS_CPURF_Msk) + +reset_reason_t hal_reset_reason_get(void) +{ + reset_reason_t reset_reason_cast; + uint32_t reset_reason_count = 0; + + if (SYS_IS_POR_RST()) { + reset_reason_cast = RESET_REASON_POWER_ON; + reset_reason_count ++; + } + + if (SYS_IS_RSTPIN_RST()) { + reset_reason_cast = RESET_REASON_PIN_RESET; + reset_reason_count ++; + } + + if (SYS_IS_WDT_RST()) { + reset_reason_cast = RESET_REASON_WATCHDOG; + reset_reason_count ++; + } + + if (SYS_IS_LVR_RST()) { + reset_reason_cast = RESET_REASON_PLATFORM; + reset_reason_count ++; + } + + if (SYS_IS_BOD_RST()) { + reset_reason_cast = RESET_REASON_BROWN_OUT; + reset_reason_count ++; + } + + /* This MCU doesn't support MKROM and we needn't take care of bootloader/SYSRESETREQ flow. */ + if (SYS_IS_SYSTEM_RST()) { + reset_reason_cast = RESET_REASON_SOFTWARE; + reset_reason_count ++; + } + + if (SYS_IS_CPU_RST()) { + reset_reason_cast = RESET_REASON_PLATFORM; + reset_reason_count ++; + } + + if (reset_reason_count == 0) { + reset_reason_cast = RESET_REASON_UNKNOWN; + } else if (reset_reason_count >= 2) { + reset_reason_cast = RESET_REASON_MULTIPLE; + } + + return reset_reason_cast; +} + +uint32_t hal_reset_reason_get_raw(void) +{ + return (SYS->RSTSTS & SYS_RSTSTS_ALLRF_Msk); +} + +void hal_reset_reason_clear(void) +{ + SYS_CLEAR_RST_SOURCE(SYS->RSTSTS); +} + +#endif diff --git a/targets/targets.json b/targets/targets.json index a579102b3f2..e531b7f1bd1 100644 --- a/targets/targets.json +++ b/targets/targets.json @@ -6570,6 +6570,7 @@ "PORTINOUT", "PORTOUT", "PWMOUT", + "RESET_REASON", "SERIAL", "SERIAL_ASYNCH", "SERIAL_FC", @@ -6692,6 +6693,7 @@ "PORTINOUT", "PORTOUT", "PWMOUT", + "RESET_REASON", "SERIAL", "SERIAL_ASYNCH", "SERIAL_FC", @@ -6806,6 +6808,7 @@ "PORTINOUT", "PORTOUT", "PWMOUT", + "RESET_REASON", "SERIAL", "SERIAL_ASYNCH", "SERIAL_FC", @@ -7001,6 +7004,7 @@ "PORTINOUT", "PORTOUT", "PWMOUT", + "RESET_REASON", "SERIAL", "SERIAL_ASYNCH", "SERIAL_FC", From 2904947570dced343cc546d8eaedcc4fb22e9bc7 Mon Sep 17 00:00:00 2001 From: ccli8 Date: Mon, 16 Jul 2018 16:33:17 +0800 Subject: [PATCH 45/62] [Nuvoton] Support watchdog timer --- .../TARGET_NUVOTON/TARGET_M451/watchdog_api.c | 205 +++++++++++++++++ .../TARGET_NUVOTON/TARGET_M480/watchdog_api.c | 205 +++++++++++++++++ .../TARGET_NANO100/watchdog_api.c | 211 ++++++++++++++++++ .../TARGET_NUC472/watchdog_api.c | 205 +++++++++++++++++ targets/targets.json | 17 +- 5 files changed, 842 insertions(+), 1 deletion(-) create mode 100644 targets/TARGET_NUVOTON/TARGET_M451/watchdog_api.c create mode 100644 targets/TARGET_NUVOTON/TARGET_M480/watchdog_api.c create mode 100644 targets/TARGET_NUVOTON/TARGET_NANO100/watchdog_api.c create mode 100644 targets/TARGET_NUVOTON/TARGET_NUC472/watchdog_api.c diff --git a/targets/TARGET_NUVOTON/TARGET_M451/watchdog_api.c b/targets/TARGET_NUVOTON/TARGET_M451/watchdog_api.c new file mode 100644 index 00000000000..96150ae7e7f --- /dev/null +++ b/targets/TARGET_NUVOTON/TARGET_M451/watchdog_api.c @@ -0,0 +1,205 @@ +/* mbed Microcontroller Library + * Copyright (c) 2017-2018 Nuvoton + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "watchdog_api.h" + +#if DEVICE_WATCHDOG + +#include "cmsis.h" + +/* Micro seconds per second */ +#define NU_US_PER_SEC 1000000 + +/* Watchdog clock per second */ +#define NU_WDTCLK_PER_SEC (__LIRC) + +/* Convert watchdog clock to nearest ms */ +#define NU_WDTCLK2MS(WDTCLK) (((WDTCLK) * 1000 + ((NU_WDTCLK_PER_SEC) / 2)) / (NU_WDTCLK_PER_SEC)) + +/* Convert ms to nearest watchdog clock */ +#define NU_MS2WDTCLK(MS) (((MS) * (NU_WDTCLK_PER_SEC) + 500) / 1000) + +/* List of hardware-supported watchdog timeout in clocks */ +#define NU_WDT_16CLK 16 +#define NU_WDT_64CLK 64 +#define NU_WDT_256CLK 256 +#define NU_WDT_1024CLK 1024 +#define NU_WDT_4096CLK 4096 +#define NU_WDT_16384CLK 16384 +#define NU_WDT_65536CLK 65536 +#define NU_WDT_262144CLK 262144 + +/* Watchdog reset delay */ +#define NU_WDT_RESET_DELAY_RSTDSEL WDT_RESET_DELAY_3CLK + +/* Support watchdog timeout values beyond H/W + * + * Watchdog Timer H/W just supports timeout values of 2^4, 2^6, ..., 2^18 clocks. + * To extend the support range to 1 and UINT32_MAX, we cascade multiple small timeouts to + * reach one large timeout specified in hal_watchdog_init. + */ + +/* Track if WDT H/W has been initialized */ +static bool wdt_hw_inited = 0; +/* Hold initially-configured timeout in hal_watchdog_init */ +static uint32_t wdt_timeout_reload_ms = 0; +/* Track remaining timeout for cascading */ +static uint32_t wdt_timeout_rmn_clk = 0; + +static void watchdog_setup_cascade_timeout(void); +static void WDT_IRQHandler(void); + +watchdog_status_t hal_watchdog_init(const watchdog_config_t *config) +{ + /* Check validity of arguments */ + if (! config || ! config->timeout_ms) { + return WATCHDOG_STATUS_INVALID_ARGUMENT; + } + + wdt_timeout_reload_ms = config->timeout_ms; + wdt_timeout_rmn_clk = NU_MS2WDTCLK(wdt_timeout_reload_ms); + + if (! wdt_hw_inited) { + wdt_hw_inited = 1; + + /* Enable IP module clock */ + CLK_EnableModuleClock(WDT_MODULE); + + /* Select IP clock source */ + CLK_SetModuleClock(WDT_MODULE, CLK_CLKSEL1_WDTSEL_LIRC, 0); + + /* Set up IP interrupt */ + NVIC_SetVector(WDT_IRQn, (uint32_t) WDT_IRQHandler); + NVIC_EnableIRQ(WDT_IRQn); + } + + watchdog_setup_cascade_timeout(); + + return WATCHDOG_STATUS_OK; +} + +void hal_watchdog_kick(void) +{ + wdt_timeout_rmn_clk = NU_MS2WDTCLK(wdt_timeout_reload_ms); + watchdog_setup_cascade_timeout(); +} + +watchdog_status_t hal_watchdog_stop(void) +{ + SYS_UnlockReg(); + + /* Clear all flags & Disable interrupt & Disable WDT */ + WDT->CTL = (WDT->CTL & ~(WDT_CTL_WDTEN_Msk | WDT_CTL_INTEN_Msk)) | (WDT_CTL_WKF_Msk | WDT_CTL_IF_Msk | WDT_CTL_RSTF_Msk); + + SYS_LockReg(); + + return WATCHDOG_STATUS_OK; +} + +uint32_t hal_watchdog_get_reload_value(void) +{ + return wdt_timeout_reload_ms; +} + +watchdog_features_t hal_watchdog_get_platform_features(void) +{ + watchdog_features_t wdt_feat; + + /* We can support timeout values between 1 and UINT32_MAX by cascading. */ + wdt_feat.max_timeout = UINT32_MAX; + /* Support re-configuring watchdog timer */ + wdt_feat.update_config = 1; + /* Support stopping watchdog timer */ + wdt_feat.disable_watchdog = 1; + + return wdt_feat; +} + +static void watchdog_setup_cascade_timeout(void) +{ + uint32_t wdt_timeout_clk_toutsel; + + if (wdt_timeout_rmn_clk >= NU_WDT_262144CLK) { + wdt_timeout_rmn_clk -= NU_WDT_262144CLK; + wdt_timeout_clk_toutsel = WDT_TIMEOUT_2POW18; + } else if (wdt_timeout_rmn_clk >= NU_WDT_65536CLK) { + wdt_timeout_rmn_clk -= NU_WDT_65536CLK; + wdt_timeout_clk_toutsel = WDT_TIMEOUT_2POW16; + } else if (wdt_timeout_rmn_clk >= NU_WDT_16384CLK) { + wdt_timeout_rmn_clk -= NU_WDT_16384CLK; + wdt_timeout_clk_toutsel = WDT_TIMEOUT_2POW14; + } else if (wdt_timeout_rmn_clk >= NU_WDT_4096CLK) { + wdt_timeout_rmn_clk -= NU_WDT_4096CLK; + wdt_timeout_clk_toutsel = WDT_TIMEOUT_2POW12; + } else if (wdt_timeout_rmn_clk >= NU_WDT_1024CLK) { + wdt_timeout_rmn_clk -= NU_WDT_1024CLK; + wdt_timeout_clk_toutsel = WDT_TIMEOUT_2POW10; + } else if (wdt_timeout_rmn_clk >= NU_WDT_256CLK) { + wdt_timeout_rmn_clk -= NU_WDT_256CLK; + wdt_timeout_clk_toutsel = WDT_TIMEOUT_2POW8; + } else if (wdt_timeout_rmn_clk >= NU_WDT_64CLK) { + wdt_timeout_rmn_clk -= NU_WDT_64CLK; + wdt_timeout_clk_toutsel = WDT_TIMEOUT_2POW6; + } else if (wdt_timeout_rmn_clk >= NU_WDT_16CLK) { + wdt_timeout_rmn_clk -= NU_WDT_16CLK; + wdt_timeout_clk_toutsel = WDT_TIMEOUT_2POW4; + } else if (wdt_timeout_rmn_clk) { + wdt_timeout_rmn_clk = 0; + wdt_timeout_clk_toutsel = WDT_TIMEOUT_2POW4; + } else { + /* WDT has timed-out and will restart system soon. We just disable interrupt to escape + * getting stuck in WDT ISR. */ + SYS_UnlockReg(); + + /* Clear all flags & Disable interrupt */ + WDT->CTL = (WDT->CTL & ~WDT_CTL_INTEN_Msk) | (WDT_CTL_WKF_Msk | WDT_CTL_IF_Msk | WDT_CTL_RSTF_Msk); + + SYS_LockReg(); + return; + } + + SYS_UnlockReg(); + + /* Configure reset delay on timeout */ + WDT->ALTCTL = NU_WDT_RESET_DELAY_RSTDSEL; + + /* Configure another piece of cascaded WDT timeout */ + WDT->CTL = wdt_timeout_clk_toutsel | // Timeout interval + WDT_CTL_WDTEN_Msk | // Enable watchdog timer + WDT_CTL_INTEN_Msk | // Enable interrupt + WDT_CTL_WKF_Msk | // Clear wake-up flag + WDT_CTL_WKEN_Msk | // Enable wake-up on timeout + WDT_CTL_IF_Msk | // Clear interrupt flag + WDT_CTL_RSTF_Msk | // Clear reset flag + (wdt_timeout_rmn_clk ? 0 : WDT_CTL_RSTEN_Msk) | // Enable reset on last cascaded timeout + WDT_CTL_RSTCNT_Msk; // Reset watchdog timer + + SYS_LockReg(); +} + +void WDT_IRQHandler(void) +{ + /* Check WDT interrupt flag */ + if (WDT_GET_TIMEOUT_INT_FLAG()) { + /* Continue another piece of cascaded WDT timeout */ + watchdog_setup_cascade_timeout(); + } else { + /* Clear all flags */ + WDT->CTL |= (WDT_CTL_WKF_Msk | WDT_CTL_IF_Msk | WDT_CTL_RSTF_Msk); + } +} + +#endif diff --git a/targets/TARGET_NUVOTON/TARGET_M480/watchdog_api.c b/targets/TARGET_NUVOTON/TARGET_M480/watchdog_api.c new file mode 100644 index 00000000000..96150ae7e7f --- /dev/null +++ b/targets/TARGET_NUVOTON/TARGET_M480/watchdog_api.c @@ -0,0 +1,205 @@ +/* mbed Microcontroller Library + * Copyright (c) 2017-2018 Nuvoton + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "watchdog_api.h" + +#if DEVICE_WATCHDOG + +#include "cmsis.h" + +/* Micro seconds per second */ +#define NU_US_PER_SEC 1000000 + +/* Watchdog clock per second */ +#define NU_WDTCLK_PER_SEC (__LIRC) + +/* Convert watchdog clock to nearest ms */ +#define NU_WDTCLK2MS(WDTCLK) (((WDTCLK) * 1000 + ((NU_WDTCLK_PER_SEC) / 2)) / (NU_WDTCLK_PER_SEC)) + +/* Convert ms to nearest watchdog clock */ +#define NU_MS2WDTCLK(MS) (((MS) * (NU_WDTCLK_PER_SEC) + 500) / 1000) + +/* List of hardware-supported watchdog timeout in clocks */ +#define NU_WDT_16CLK 16 +#define NU_WDT_64CLK 64 +#define NU_WDT_256CLK 256 +#define NU_WDT_1024CLK 1024 +#define NU_WDT_4096CLK 4096 +#define NU_WDT_16384CLK 16384 +#define NU_WDT_65536CLK 65536 +#define NU_WDT_262144CLK 262144 + +/* Watchdog reset delay */ +#define NU_WDT_RESET_DELAY_RSTDSEL WDT_RESET_DELAY_3CLK + +/* Support watchdog timeout values beyond H/W + * + * Watchdog Timer H/W just supports timeout values of 2^4, 2^6, ..., 2^18 clocks. + * To extend the support range to 1 and UINT32_MAX, we cascade multiple small timeouts to + * reach one large timeout specified in hal_watchdog_init. + */ + +/* Track if WDT H/W has been initialized */ +static bool wdt_hw_inited = 0; +/* Hold initially-configured timeout in hal_watchdog_init */ +static uint32_t wdt_timeout_reload_ms = 0; +/* Track remaining timeout for cascading */ +static uint32_t wdt_timeout_rmn_clk = 0; + +static void watchdog_setup_cascade_timeout(void); +static void WDT_IRQHandler(void); + +watchdog_status_t hal_watchdog_init(const watchdog_config_t *config) +{ + /* Check validity of arguments */ + if (! config || ! config->timeout_ms) { + return WATCHDOG_STATUS_INVALID_ARGUMENT; + } + + wdt_timeout_reload_ms = config->timeout_ms; + wdt_timeout_rmn_clk = NU_MS2WDTCLK(wdt_timeout_reload_ms); + + if (! wdt_hw_inited) { + wdt_hw_inited = 1; + + /* Enable IP module clock */ + CLK_EnableModuleClock(WDT_MODULE); + + /* Select IP clock source */ + CLK_SetModuleClock(WDT_MODULE, CLK_CLKSEL1_WDTSEL_LIRC, 0); + + /* Set up IP interrupt */ + NVIC_SetVector(WDT_IRQn, (uint32_t) WDT_IRQHandler); + NVIC_EnableIRQ(WDT_IRQn); + } + + watchdog_setup_cascade_timeout(); + + return WATCHDOG_STATUS_OK; +} + +void hal_watchdog_kick(void) +{ + wdt_timeout_rmn_clk = NU_MS2WDTCLK(wdt_timeout_reload_ms); + watchdog_setup_cascade_timeout(); +} + +watchdog_status_t hal_watchdog_stop(void) +{ + SYS_UnlockReg(); + + /* Clear all flags & Disable interrupt & Disable WDT */ + WDT->CTL = (WDT->CTL & ~(WDT_CTL_WDTEN_Msk | WDT_CTL_INTEN_Msk)) | (WDT_CTL_WKF_Msk | WDT_CTL_IF_Msk | WDT_CTL_RSTF_Msk); + + SYS_LockReg(); + + return WATCHDOG_STATUS_OK; +} + +uint32_t hal_watchdog_get_reload_value(void) +{ + return wdt_timeout_reload_ms; +} + +watchdog_features_t hal_watchdog_get_platform_features(void) +{ + watchdog_features_t wdt_feat; + + /* We can support timeout values between 1 and UINT32_MAX by cascading. */ + wdt_feat.max_timeout = UINT32_MAX; + /* Support re-configuring watchdog timer */ + wdt_feat.update_config = 1; + /* Support stopping watchdog timer */ + wdt_feat.disable_watchdog = 1; + + return wdt_feat; +} + +static void watchdog_setup_cascade_timeout(void) +{ + uint32_t wdt_timeout_clk_toutsel; + + if (wdt_timeout_rmn_clk >= NU_WDT_262144CLK) { + wdt_timeout_rmn_clk -= NU_WDT_262144CLK; + wdt_timeout_clk_toutsel = WDT_TIMEOUT_2POW18; + } else if (wdt_timeout_rmn_clk >= NU_WDT_65536CLK) { + wdt_timeout_rmn_clk -= NU_WDT_65536CLK; + wdt_timeout_clk_toutsel = WDT_TIMEOUT_2POW16; + } else if (wdt_timeout_rmn_clk >= NU_WDT_16384CLK) { + wdt_timeout_rmn_clk -= NU_WDT_16384CLK; + wdt_timeout_clk_toutsel = WDT_TIMEOUT_2POW14; + } else if (wdt_timeout_rmn_clk >= NU_WDT_4096CLK) { + wdt_timeout_rmn_clk -= NU_WDT_4096CLK; + wdt_timeout_clk_toutsel = WDT_TIMEOUT_2POW12; + } else if (wdt_timeout_rmn_clk >= NU_WDT_1024CLK) { + wdt_timeout_rmn_clk -= NU_WDT_1024CLK; + wdt_timeout_clk_toutsel = WDT_TIMEOUT_2POW10; + } else if (wdt_timeout_rmn_clk >= NU_WDT_256CLK) { + wdt_timeout_rmn_clk -= NU_WDT_256CLK; + wdt_timeout_clk_toutsel = WDT_TIMEOUT_2POW8; + } else if (wdt_timeout_rmn_clk >= NU_WDT_64CLK) { + wdt_timeout_rmn_clk -= NU_WDT_64CLK; + wdt_timeout_clk_toutsel = WDT_TIMEOUT_2POW6; + } else if (wdt_timeout_rmn_clk >= NU_WDT_16CLK) { + wdt_timeout_rmn_clk -= NU_WDT_16CLK; + wdt_timeout_clk_toutsel = WDT_TIMEOUT_2POW4; + } else if (wdt_timeout_rmn_clk) { + wdt_timeout_rmn_clk = 0; + wdt_timeout_clk_toutsel = WDT_TIMEOUT_2POW4; + } else { + /* WDT has timed-out and will restart system soon. We just disable interrupt to escape + * getting stuck in WDT ISR. */ + SYS_UnlockReg(); + + /* Clear all flags & Disable interrupt */ + WDT->CTL = (WDT->CTL & ~WDT_CTL_INTEN_Msk) | (WDT_CTL_WKF_Msk | WDT_CTL_IF_Msk | WDT_CTL_RSTF_Msk); + + SYS_LockReg(); + return; + } + + SYS_UnlockReg(); + + /* Configure reset delay on timeout */ + WDT->ALTCTL = NU_WDT_RESET_DELAY_RSTDSEL; + + /* Configure another piece of cascaded WDT timeout */ + WDT->CTL = wdt_timeout_clk_toutsel | // Timeout interval + WDT_CTL_WDTEN_Msk | // Enable watchdog timer + WDT_CTL_INTEN_Msk | // Enable interrupt + WDT_CTL_WKF_Msk | // Clear wake-up flag + WDT_CTL_WKEN_Msk | // Enable wake-up on timeout + WDT_CTL_IF_Msk | // Clear interrupt flag + WDT_CTL_RSTF_Msk | // Clear reset flag + (wdt_timeout_rmn_clk ? 0 : WDT_CTL_RSTEN_Msk) | // Enable reset on last cascaded timeout + WDT_CTL_RSTCNT_Msk; // Reset watchdog timer + + SYS_LockReg(); +} + +void WDT_IRQHandler(void) +{ + /* Check WDT interrupt flag */ + if (WDT_GET_TIMEOUT_INT_FLAG()) { + /* Continue another piece of cascaded WDT timeout */ + watchdog_setup_cascade_timeout(); + } else { + /* Clear all flags */ + WDT->CTL |= (WDT_CTL_WKF_Msk | WDT_CTL_IF_Msk | WDT_CTL_RSTF_Msk); + } +} + +#endif diff --git a/targets/TARGET_NUVOTON/TARGET_NANO100/watchdog_api.c b/targets/TARGET_NUVOTON/TARGET_NANO100/watchdog_api.c new file mode 100644 index 00000000000..376d2cb6393 --- /dev/null +++ b/targets/TARGET_NUVOTON/TARGET_NANO100/watchdog_api.c @@ -0,0 +1,211 @@ +/* mbed Microcontroller Library + * Copyright (c) 2017-2018 Nuvoton + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "watchdog_api.h" + +#if DEVICE_WATCHDOG + +#include "cmsis.h" + +/* Micro seconds per second */ +#define NU_US_PER_SEC 1000000 + +/* Watchdog clock per second */ +#define NU_WDTCLK_PER_SEC (__LIRC) + +/* Convert watchdog clock to nearest ms */ +#define NU_WDTCLK2MS(WDTCLK) (((WDTCLK) * 1000 + ((NU_WDTCLK_PER_SEC) / 2)) / (NU_WDTCLK_PER_SEC)) + +/* Convert ms to nearest watchdog clock */ +#define NU_MS2WDTCLK(MS) (((MS) * (NU_WDTCLK_PER_SEC) + 500) / 1000) + +/* List of hardware-supported watchdog timeout in clocks */ +#define NU_WDT_16CLK 16 +#define NU_WDT_64CLK 64 +#define NU_WDT_256CLK 256 +#define NU_WDT_1024CLK 1024 +#define NU_WDT_4096CLK 4096 +#define NU_WDT_16384CLK 16384 +#define NU_WDT_65536CLK 65536 +#define NU_WDT_262144CLK 262144 + +/* Watchdog reset delay */ +#define NU_WDT_RESET_DELAY_RSTDSEL WDT_RESET_DELAY_3CLK + +/* Support watchdog timeout values beyond H/W + * + * Watchdog Timer H/W just supports timeout values of 2^4, 2^6, ..., 2^18 clocks. + * To extend the support range to 1 and UINT32_MAX, we cascade multiple small timeouts to + * reach one large timeout specified in hal_watchdog_init. + */ + +/* Track if WDT H/W has been initialized */ +static bool wdt_hw_inited = 0; +/* Hold initially-configured timeout in hal_watchdog_init */ +static uint32_t wdt_timeout_reload_ms = 0; +/* Track remaining timeout for cascading */ +static uint32_t wdt_timeout_rmn_clk = 0; + +static void watchdog_setup_cascade_timeout(void); +/* NOTE: Don't add static modifier here. These IRQ handler symbols are for linking. + Vector table relocation is not actually supported for low-resource target. */ +void WDT_IRQHandler(void); + +watchdog_status_t hal_watchdog_init(const watchdog_config_t *config) +{ + /* Check validity of arguments */ + if (! config || ! config->timeout_ms) { + return WATCHDOG_STATUS_INVALID_ARGUMENT; + } + + wdt_timeout_reload_ms = config->timeout_ms; + wdt_timeout_rmn_clk = NU_MS2WDTCLK(wdt_timeout_reload_ms); + + if (! wdt_hw_inited) { + wdt_hw_inited = 1; + + /* Enable IP module clock */ + CLK_EnableModuleClock(WDT_MODULE); + + /* Select IP clock source */ + CLK_SetModuleClock(WDT_MODULE, 0, 0); + + /* Set up IP interrupt */ + NVIC_SetVector(WDT_IRQn, (uint32_t) WDT_IRQHandler); + NVIC_EnableIRQ(WDT_IRQn); + } + + watchdog_setup_cascade_timeout(); + + return WATCHDOG_STATUS_OK; +} + +void hal_watchdog_kick(void) +{ + wdt_timeout_rmn_clk = NU_MS2WDTCLK(wdt_timeout_reload_ms); + watchdog_setup_cascade_timeout(); +} + +watchdog_status_t hal_watchdog_stop(void) +{ + SYS_UnlockReg(); + + /* Clear all flags */ + WDT->ISR = WDT_ISR_IS_Msk | WDT_ISR_RST_IS_Msk | WDT_ISR_WAKE_IS_Msk; + /* Disable interrupt */ + WDT->IER &= ~WDT_IER_IE_Msk; + /* Disable WDT */ + WDT->CTL &= ~WDT_CTL_WTE_Msk; + + SYS_LockReg(); + + return WATCHDOG_STATUS_OK; +} + +uint32_t hal_watchdog_get_reload_value(void) +{ + return wdt_timeout_reload_ms; +} + +watchdog_features_t hal_watchdog_get_platform_features(void) +{ + watchdog_features_t wdt_feat; + + /* We can support timeout values between 1 and UINT32_MAX by cascading. */ + wdt_feat.max_timeout = UINT32_MAX; + /* Support re-configuring watchdog timer */ + wdt_feat.update_config = 1; + /* Support stopping watchdog timer */ + wdt_feat.disable_watchdog = 1; + + return wdt_feat; +} + +static void watchdog_setup_cascade_timeout(void) +{ + uint32_t wdt_timeout_clk_toutsel; + + if (wdt_timeout_rmn_clk >= NU_WDT_262144CLK) { + wdt_timeout_rmn_clk -= NU_WDT_262144CLK; + wdt_timeout_clk_toutsel = WDT_TIMEOUT_2POW18; + } else if (wdt_timeout_rmn_clk >= NU_WDT_65536CLK) { + wdt_timeout_rmn_clk -= NU_WDT_65536CLK; + wdt_timeout_clk_toutsel = WDT_TIMEOUT_2POW16; + } else if (wdt_timeout_rmn_clk >= NU_WDT_16384CLK) { + wdt_timeout_rmn_clk -= NU_WDT_16384CLK; + wdt_timeout_clk_toutsel = WDT_TIMEOUT_2POW14; + } else if (wdt_timeout_rmn_clk >= NU_WDT_4096CLK) { + wdt_timeout_rmn_clk -= NU_WDT_4096CLK; + wdt_timeout_clk_toutsel = WDT_TIMEOUT_2POW12; + } else if (wdt_timeout_rmn_clk >= NU_WDT_1024CLK) { + wdt_timeout_rmn_clk -= NU_WDT_1024CLK; + wdt_timeout_clk_toutsel = WDT_TIMEOUT_2POW10; + } else if (wdt_timeout_rmn_clk >= NU_WDT_256CLK) { + wdt_timeout_rmn_clk -= NU_WDT_256CLK; + wdt_timeout_clk_toutsel = WDT_TIMEOUT_2POW8; + } else if (wdt_timeout_rmn_clk >= NU_WDT_64CLK) { + wdt_timeout_rmn_clk -= NU_WDT_64CLK; + wdt_timeout_clk_toutsel = WDT_TIMEOUT_2POW6; + } else if (wdt_timeout_rmn_clk >= NU_WDT_16CLK) { + wdt_timeout_rmn_clk -= NU_WDT_16CLK; + wdt_timeout_clk_toutsel = WDT_TIMEOUT_2POW4; + } else if (wdt_timeout_rmn_clk) { + wdt_timeout_rmn_clk = 0; + wdt_timeout_clk_toutsel = WDT_TIMEOUT_2POW4; + } else { + /* WDT has timed-out and will restart system soon. We just disable interrupt to escape + * getting stuck in WDT ISR. */ + SYS_UnlockReg(); + + /* Clear all flags */ + WDT->ISR = WDT_ISR_IS_Msk | WDT_ISR_RST_IS_Msk | WDT_ISR_WAKE_IS_Msk; + /* Disable interrupt */ + WDT->IER &= ~WDT_IER_IE_Msk; + + SYS_LockReg(); + return; + } + + SYS_UnlockReg(); + + /* Clear all flags */ + WDT->ISR = WDT_ISR_IS_Msk | WDT_ISR_RST_IS_Msk | WDT_ISR_WAKE_IS_Msk; + /* Enable interrupt */ + WDT->IER = WDT_IER_IE_Msk; + /* Configure another piece of cascaded WDT timeout */ + WDT->CTL = NU_WDT_RESET_DELAY_RSTDSEL | // Reset delay on timeout + wdt_timeout_clk_toutsel | // Timeout interval + WDT_CTL_WTE_Msk | // Enable watchdog timer + WDT_CTL_WTWKE_Msk | // Enable wake-up on timeout + (wdt_timeout_rmn_clk ? 0 : WDT_CTL_WTRE_Msk) | // Enable reset on last cascaded timeout + WDT_CTL_WTR_Msk; // Reset watchdog timer + + SYS_LockReg(); +} + +void WDT_IRQHandler(void) +{ + /* Check WDT interrupt flag */ + if (WDT_GET_TIMEOUT_INT_FLAG()) { + /* Continue another piece of cascaded WDT timeout */ + watchdog_setup_cascade_timeout(); + } else { + /* Clear all flags */ + WDT->ISR = WDT_ISR_IS_Msk | WDT_ISR_RST_IS_Msk | WDT_ISR_WAKE_IS_Msk; + } +} + +#endif diff --git a/targets/TARGET_NUVOTON/TARGET_NUC472/watchdog_api.c b/targets/TARGET_NUVOTON/TARGET_NUC472/watchdog_api.c new file mode 100644 index 00000000000..96150ae7e7f --- /dev/null +++ b/targets/TARGET_NUVOTON/TARGET_NUC472/watchdog_api.c @@ -0,0 +1,205 @@ +/* mbed Microcontroller Library + * Copyright (c) 2017-2018 Nuvoton + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "watchdog_api.h" + +#if DEVICE_WATCHDOG + +#include "cmsis.h" + +/* Micro seconds per second */ +#define NU_US_PER_SEC 1000000 + +/* Watchdog clock per second */ +#define NU_WDTCLK_PER_SEC (__LIRC) + +/* Convert watchdog clock to nearest ms */ +#define NU_WDTCLK2MS(WDTCLK) (((WDTCLK) * 1000 + ((NU_WDTCLK_PER_SEC) / 2)) / (NU_WDTCLK_PER_SEC)) + +/* Convert ms to nearest watchdog clock */ +#define NU_MS2WDTCLK(MS) (((MS) * (NU_WDTCLK_PER_SEC) + 500) / 1000) + +/* List of hardware-supported watchdog timeout in clocks */ +#define NU_WDT_16CLK 16 +#define NU_WDT_64CLK 64 +#define NU_WDT_256CLK 256 +#define NU_WDT_1024CLK 1024 +#define NU_WDT_4096CLK 4096 +#define NU_WDT_16384CLK 16384 +#define NU_WDT_65536CLK 65536 +#define NU_WDT_262144CLK 262144 + +/* Watchdog reset delay */ +#define NU_WDT_RESET_DELAY_RSTDSEL WDT_RESET_DELAY_3CLK + +/* Support watchdog timeout values beyond H/W + * + * Watchdog Timer H/W just supports timeout values of 2^4, 2^6, ..., 2^18 clocks. + * To extend the support range to 1 and UINT32_MAX, we cascade multiple small timeouts to + * reach one large timeout specified in hal_watchdog_init. + */ + +/* Track if WDT H/W has been initialized */ +static bool wdt_hw_inited = 0; +/* Hold initially-configured timeout in hal_watchdog_init */ +static uint32_t wdt_timeout_reload_ms = 0; +/* Track remaining timeout for cascading */ +static uint32_t wdt_timeout_rmn_clk = 0; + +static void watchdog_setup_cascade_timeout(void); +static void WDT_IRQHandler(void); + +watchdog_status_t hal_watchdog_init(const watchdog_config_t *config) +{ + /* Check validity of arguments */ + if (! config || ! config->timeout_ms) { + return WATCHDOG_STATUS_INVALID_ARGUMENT; + } + + wdt_timeout_reload_ms = config->timeout_ms; + wdt_timeout_rmn_clk = NU_MS2WDTCLK(wdt_timeout_reload_ms); + + if (! wdt_hw_inited) { + wdt_hw_inited = 1; + + /* Enable IP module clock */ + CLK_EnableModuleClock(WDT_MODULE); + + /* Select IP clock source */ + CLK_SetModuleClock(WDT_MODULE, CLK_CLKSEL1_WDTSEL_LIRC, 0); + + /* Set up IP interrupt */ + NVIC_SetVector(WDT_IRQn, (uint32_t) WDT_IRQHandler); + NVIC_EnableIRQ(WDT_IRQn); + } + + watchdog_setup_cascade_timeout(); + + return WATCHDOG_STATUS_OK; +} + +void hal_watchdog_kick(void) +{ + wdt_timeout_rmn_clk = NU_MS2WDTCLK(wdt_timeout_reload_ms); + watchdog_setup_cascade_timeout(); +} + +watchdog_status_t hal_watchdog_stop(void) +{ + SYS_UnlockReg(); + + /* Clear all flags & Disable interrupt & Disable WDT */ + WDT->CTL = (WDT->CTL & ~(WDT_CTL_WDTEN_Msk | WDT_CTL_INTEN_Msk)) | (WDT_CTL_WKF_Msk | WDT_CTL_IF_Msk | WDT_CTL_RSTF_Msk); + + SYS_LockReg(); + + return WATCHDOG_STATUS_OK; +} + +uint32_t hal_watchdog_get_reload_value(void) +{ + return wdt_timeout_reload_ms; +} + +watchdog_features_t hal_watchdog_get_platform_features(void) +{ + watchdog_features_t wdt_feat; + + /* We can support timeout values between 1 and UINT32_MAX by cascading. */ + wdt_feat.max_timeout = UINT32_MAX; + /* Support re-configuring watchdog timer */ + wdt_feat.update_config = 1; + /* Support stopping watchdog timer */ + wdt_feat.disable_watchdog = 1; + + return wdt_feat; +} + +static void watchdog_setup_cascade_timeout(void) +{ + uint32_t wdt_timeout_clk_toutsel; + + if (wdt_timeout_rmn_clk >= NU_WDT_262144CLK) { + wdt_timeout_rmn_clk -= NU_WDT_262144CLK; + wdt_timeout_clk_toutsel = WDT_TIMEOUT_2POW18; + } else if (wdt_timeout_rmn_clk >= NU_WDT_65536CLK) { + wdt_timeout_rmn_clk -= NU_WDT_65536CLK; + wdt_timeout_clk_toutsel = WDT_TIMEOUT_2POW16; + } else if (wdt_timeout_rmn_clk >= NU_WDT_16384CLK) { + wdt_timeout_rmn_clk -= NU_WDT_16384CLK; + wdt_timeout_clk_toutsel = WDT_TIMEOUT_2POW14; + } else if (wdt_timeout_rmn_clk >= NU_WDT_4096CLK) { + wdt_timeout_rmn_clk -= NU_WDT_4096CLK; + wdt_timeout_clk_toutsel = WDT_TIMEOUT_2POW12; + } else if (wdt_timeout_rmn_clk >= NU_WDT_1024CLK) { + wdt_timeout_rmn_clk -= NU_WDT_1024CLK; + wdt_timeout_clk_toutsel = WDT_TIMEOUT_2POW10; + } else if (wdt_timeout_rmn_clk >= NU_WDT_256CLK) { + wdt_timeout_rmn_clk -= NU_WDT_256CLK; + wdt_timeout_clk_toutsel = WDT_TIMEOUT_2POW8; + } else if (wdt_timeout_rmn_clk >= NU_WDT_64CLK) { + wdt_timeout_rmn_clk -= NU_WDT_64CLK; + wdt_timeout_clk_toutsel = WDT_TIMEOUT_2POW6; + } else if (wdt_timeout_rmn_clk >= NU_WDT_16CLK) { + wdt_timeout_rmn_clk -= NU_WDT_16CLK; + wdt_timeout_clk_toutsel = WDT_TIMEOUT_2POW4; + } else if (wdt_timeout_rmn_clk) { + wdt_timeout_rmn_clk = 0; + wdt_timeout_clk_toutsel = WDT_TIMEOUT_2POW4; + } else { + /* WDT has timed-out and will restart system soon. We just disable interrupt to escape + * getting stuck in WDT ISR. */ + SYS_UnlockReg(); + + /* Clear all flags & Disable interrupt */ + WDT->CTL = (WDT->CTL & ~WDT_CTL_INTEN_Msk) | (WDT_CTL_WKF_Msk | WDT_CTL_IF_Msk | WDT_CTL_RSTF_Msk); + + SYS_LockReg(); + return; + } + + SYS_UnlockReg(); + + /* Configure reset delay on timeout */ + WDT->ALTCTL = NU_WDT_RESET_DELAY_RSTDSEL; + + /* Configure another piece of cascaded WDT timeout */ + WDT->CTL = wdt_timeout_clk_toutsel | // Timeout interval + WDT_CTL_WDTEN_Msk | // Enable watchdog timer + WDT_CTL_INTEN_Msk | // Enable interrupt + WDT_CTL_WKF_Msk | // Clear wake-up flag + WDT_CTL_WKEN_Msk | // Enable wake-up on timeout + WDT_CTL_IF_Msk | // Clear interrupt flag + WDT_CTL_RSTF_Msk | // Clear reset flag + (wdt_timeout_rmn_clk ? 0 : WDT_CTL_RSTEN_Msk) | // Enable reset on last cascaded timeout + WDT_CTL_RSTCNT_Msk; // Reset watchdog timer + + SYS_LockReg(); +} + +void WDT_IRQHandler(void) +{ + /* Check WDT interrupt flag */ + if (WDT_GET_TIMEOUT_INT_FLAG()) { + /* Continue another piece of cascaded WDT timeout */ + watchdog_setup_cascade_timeout(); + } else { + /* Clear all flags */ + WDT->CTL |= (WDT_CTL_WKF_Msk | WDT_CTL_IF_Msk | WDT_CTL_RSTF_Msk); + } +} + +#endif diff --git a/targets/targets.json b/targets/targets.json index e531b7f1bd1..2c7ecfaa587 100644 --- a/targets/targets.json +++ b/targets/targets.json @@ -6821,7 +6821,8 @@ "CAN", "FLASH", "EMAC", - "MPU" + "MPU", + "WATCHDOG" ], "release_versions": ["5"], "device_name": "NUC472HI8AE", @@ -6923,6 +6924,7 @@ }, "inherits": ["Target"], "macros_add": ["LPTICKER_DELAY_TICKS=3"], +<<<<<<< HEAD "progen": { "target": "numaker-pfm-m453" }, "device_has": [ "USTICKER", @@ -6950,6 +6952,10 @@ "FLASH", "MPU" ], +======= + "progen": {"target": "numaker-pfm-m453"}, + "device_has": ["USTICKER", "LPTICKER", "RTC", "ANALOGIN", "I2C", "I2CSLAVE", "I2C_ASYNCH", "INTERRUPTIN", "PORTIN", "PORTINOUT", "PORTOUT", "PWMOUT", "SERIAL", "SERIAL_ASYNCH", "SERIAL_FC", "STDIO_MESSAGES", "SLEEP", "SPI", "SPISLAVE", "SPI_ASYNCH", "CAN", "FLASH", "RESET_REASON", "WATCHDOG"], +>>>>>>> [Nuvoton] Support watchdog timer "release_versions": ["2", "5"], "device_name": "M453VG6AE", "bootloader_supported": true @@ -6984,6 +6990,7 @@ } }, "inherits": ["Target"], +<<<<<<< HEAD "macros": [ "CMSIS_VECTAB_VIRTUAL", "CMSIS_VECTAB_VIRTUAL_HEADER_FILE=\"cmsis_nvic.h\"", @@ -7014,6 +7021,10 @@ "SPISLAVE", "SPI_ASYNCH" ], +======= + "macros": ["CMSIS_VECTAB_VIRTUAL", "CMSIS_VECTAB_VIRTUAL_HEADER_FILE=\"cmsis_nvic.h\"","MBED_FAULT_HANDLER_DISABLED", "LPTICKER_DELAY_TICKS=3"], + "device_has": ["USTICKER", "LPTICKER", "RTC", "ANALOGIN", "I2C", "I2CSLAVE", "I2C_ASYNCH", "INTERRUPTIN", "PORTIN", "PORTINOUT", "PORTOUT", "PWMOUT", "SERIAL", "SERIAL_ASYNCH", "SERIAL_FC", "STDIO_MESSAGES", "SLEEP", "SPI", "SPISLAVE", "SPI_ASYNCH", "RESET_REASON", "WATCHDOG"], +>>>>>>> [Nuvoton] Support watchdog timer "release_versions": ["5"], "device_name": "NANO130KE3BN" }, @@ -7325,6 +7336,10 @@ "EMAC", "MPU" ], +======= + "device_has": ["USTICKER", "LPTICKER", "RTC", "ANALOGIN", "I2C", "I2CSLAVE", "I2C_ASYNCH", "INTERRUPTIN", "PORTIN", "PORTINOUT", "PORTOUT", "PWMOUT", "SERIAL", "SERIAL_ASYNCH", "SERIAL_FC", "STDIO_MESSAGES", "SLEEP", "SPI", "SPISLAVE", "SPI_ASYNCH", "TRNG", "FLASH", "CAN", "EMAC", "RESET_REASON", "WATCHDOG"], + "features": ["LWIP"], +>>>>>>> [Nuvoton] Support watchdog timer "release_versions": ["5"], "bootloader_supported": true, "overrides": { From a99f311a97f6db7fbd3092a9c8137946ed975dc2 Mon Sep 17 00:00:00 2001 From: ccli8 Date: Mon, 23 Jul 2018 11:42:20 +0800 Subject: [PATCH 46/62] Enlarge wait time for flushing serial buffer in Greentea test code Original wait time is not enough for UART to flush out before deepsleep/reset on some targets. --- TESTS/mbed_hal/reset_reason/main.cpp | 20 ++++++++++++++++++-- TESTS/mbed_hal/watchdog/main.cpp | 18 +++++++++++++++++- TESTS/mbed_hal/watchdog_reset/main.cpp | 18 +++++++++++++++++- 3 files changed, 52 insertions(+), 4 deletions(-) diff --git a/TESTS/mbed_hal/reset_reason/main.cpp b/TESTS/mbed_hal/reset_reason/main.cpp index 20f21a94091..c2759a387f3 100644 --- a/TESTS/mbed_hal/reset_reason/main.cpp +++ b/TESTS/mbed_hal/reset_reason/main.cpp @@ -49,6 +49,22 @@ #define MSG_KEY_RESET_REASON "reason" #define MSG_KEY_DEVICE_RESET "reset" +/* Flush serial buffer before deep sleep/reset + * + * Since deepsleep()/reset would shut down the UART peripheral, we wait for some time + * to allow for hardware serial buffers to completely flush. + * + * Take NUMAKER_PFM_NUC472 as an example: + * Its UART peripheral has 16-byte Tx FIFO. With baud rate set to 9600, flush + * Tx FIFO would take: 16 * 8 * 1000 / 9600 = 13.3 (ms). So set wait time to + * 20ms here for safe. + * + * This should be replaced with a better function that checks if the + * hardware buffers are empty. However, such an API does not exist now, + * so we'll use the wait_ms() function for now. + */ +#define SERIAL_FLUSH_TIME_MS 20 + typedef enum { CMD_STATUS_CONTINUE, CMD_STATUS_ERROR @@ -85,7 +101,7 @@ static cmd_status_t handle_command(const char *key, const char *value) if (strcmp(key, MSG_KEY_DEVICE_RESET) == 0 && strcmp(value, MSG_VALUE_DEVICE_RESET_NVIC) == 0) { greentea_send_kv(MSG_KEY_DEVICE_RESET, MSG_VALUE_DEVICE_RESET_ACK); - wait_ms(10); // Wait for the serial buffers to flush. + wait_ms(SERIAL_FLUSH_TIME_MS); // Wait for the serial buffers to flush. NVIC_SystemReset(); TEST_ASSERT_MESSAGE(0, "NVIC_SystemReset did not reset the device as expected."); return CMD_STATUS_ERROR; @@ -94,7 +110,7 @@ static cmd_status_t handle_command(const char *key, const char *value) #if DEVICE_WATCHDOG if (strcmp(key, MSG_KEY_DEVICE_RESET) == 0 && strcmp(value, MSG_VALUE_DEVICE_RESET_WATCHDOG) == 0) { greentea_send_kv(MSG_KEY_DEVICE_RESET, MSG_VALUE_DEVICE_RESET_ACK); - wait_ms(10); // Wait for the serial buffers to flush. + wait_ms(SERIAL_FLUSH_TIME_MS); // Wait for the serial buffers to flush. watchdog_config_t config = { .timeout_ms = WDG_TIMEOUT_MS }; if (hal_watchdog_init(&config) != WATCHDOG_STATUS_OK) { TEST_ASSERT_MESSAGE(0, "hal_watchdog_init() error."); diff --git a/TESTS/mbed_hal/watchdog/main.cpp b/TESTS/mbed_hal/watchdog/main.cpp index bbb2dd7fbbc..a4434ab2230 100644 --- a/TESTS/mbed_hal/watchdog/main.cpp +++ b/TESTS/mbed_hal/watchdog/main.cpp @@ -41,6 +41,22 @@ #define MSG_KEY_START_CASE "start_case" #define MSG_KEY_DEVICE_RESET "reset_on_case_teardown" +/* Flush serial buffer before deep sleep/reset + * + * Since deepsleep()/reset would shut down the UART peripheral, we wait for some time + * to allow for hardware serial buffers to completely flush. + * + * Take NUMAKER_PFM_NUC472 as an example: + * Its UART peripheral has 16-byte Tx FIFO. With baud rate set to 9600, flush + * Tx FIFO would take: 16 * 8 * 1000 / 9600 = 13.3 (ms). So set wait time to + * 20ms here for safe. + * + * This should be replaced with a better function that checks if the + * hardware buffers are empty. However, such an API does not exist now, + * so we'll use the wait_ms() function for now. + */ +#define SERIAL_FLUSH_TIME_MS 20 + int CASE_INDEX_START; int CASE_INDEX_CURRENT; @@ -128,7 +144,7 @@ utest::v1::status_t case_teardown_sync_on_reset(const Case * const source, const } greentea_send_kv(MSG_KEY_DEVICE_RESET, CASE_INDEX_START + CASE_INDEX_CURRENT); utest_printf("The device will now restart.\n"); - wait_ms(10); // Wait for the serial buffers to flush. + wait_ms(SERIAL_FLUSH_TIME_MS); // Wait for the serial buffers to flush. NVIC_SystemReset(); return status; // Reset is instant so this line won't be reached. } diff --git a/TESTS/mbed_hal/watchdog_reset/main.cpp b/TESTS/mbed_hal/watchdog_reset/main.cpp index edaf66dea2e..5336ca57c30 100644 --- a/TESTS/mbed_hal/watchdog_reset/main.cpp +++ b/TESTS/mbed_hal/watchdog_reset/main.cpp @@ -38,6 +38,22 @@ #define MSG_KEY_START_CASE "start_case" #define MSG_KEY_DEVICE_RESET "dev_reset" +/* Flush serial buffer before deep sleep/reset + * + * Since deepsleep()/reset would shut down the UART peripheral, we wait for some time + * to allow for hardware serial buffers to completely flush. + * + * Take NUMAKER_PFM_NUC472 as an example: + * Its UART peripheral has 16-byte Tx FIFO. With baud rate set to 9600, flush + * Tx FIFO would take: 16 * 8 * 1000 / 9600 = 13.3 (ms). So set wait time to + * 20ms here for safe. + * + * This should be replaced with a better function that checks if the + * hardware buffers are empty. However, such an API does not exist now, + * so we'll use the wait_ms() function for now. + */ +#define SERIAL_FLUSH_TIME_MS 20 + using utest::v1::Case; using utest::v1::Specification; using utest::v1::Harness; @@ -149,7 +165,7 @@ void test_deepsleep_reset() } TEST_ASSERT_EQUAL(WATCHDOG_STATUS_OK, hal_watchdog_init(&config)); lp_timeout.attach_us(mbed::callback(release_sem, &sem), 1000ULL * (TIMEOUT_MS + TIMEOUT_DELTA_MS)); - wait_ms(10); // Wait for the serial buffers to flush. + wait_ms(SERIAL_FLUSH_TIME_MS); // Wait for the serial buffers to flush. if (!sleep_manager_can_deep_sleep()) { TEST_ASSERT_MESSAGE(0, "Deepsleep should be allowed."); } From 16d0f82b0bd3d5f43b251aa2a06daf4bff514616 Mon Sep 17 00:00:00 2001 From: ccli8 Date: Mon, 23 Jul 2018 13:48:27 +0800 Subject: [PATCH 47/62] Fix NUMAKER_PFM_NANO130 cannot pass mbed_hal/watchdog_reset test On NUMAKER_PFM_NANO130 target, WDT's clock source is fixed to LIRC, which is much less accurate than other targets. Enlarge delta define to pass this test. --- TESTS/mbed_hal/watchdog_reset/main.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/TESTS/mbed_hal/watchdog_reset/main.cpp b/TESTS/mbed_hal/watchdog_reset/main.cpp index 5336ca57c30..c4e179e65c9 100644 --- a/TESTS/mbed_hal/watchdog_reset/main.cpp +++ b/TESTS/mbed_hal/watchdog_reset/main.cpp @@ -25,7 +25,13 @@ #include "mbed.h" #define TIMEOUT_MS 500UL +#if TARGET_NUMAKER_PFM_NANO130 +/* On NUMAKER_PFM_NANO130 target, WDT's clock source is fixed to LIRC, which is more + * inaccurate than other targets. Enlarge this delta define to pass this test. */ +#define TIMEOUT_DELTA_MS 100UL +#else #define TIMEOUT_DELTA_MS 50UL +#endif #define MSG_VALUE_DUMMY "0" #define CASE_DATA_INVALID 0xffffffffUL From 022d1720b49ba756baf58dcbdf5e8fe6d7ffe051 Mon Sep 17 00:00:00 2001 From: Ganesh Ramachandran Date: Fri, 26 Oct 2018 12:49:37 +0530 Subject: [PATCH 48/62] Added reset_reason feature for TMPM066 & TMPM46B --- .../TARGET_TMPM066/reset_reason_api.c | 123 ++++++++++++++++++ .../TARGET_TMPM46B/reset_reason_api.c | 89 +++++++++++++ targets/targets.json | 25 ++-- 3 files changed, 220 insertions(+), 17 deletions(-) create mode 100644 targets/TARGET_TOSHIBA/TARGET_TMPM066/reset_reason_api.c create mode 100644 targets/TARGET_TOSHIBA/TARGET_TMPM46B/reset_reason_api.c diff --git a/targets/TARGET_TOSHIBA/TARGET_TMPM066/reset_reason_api.c b/targets/TARGET_TOSHIBA/TARGET_TMPM066/reset_reason_api.c new file mode 100644 index 00000000000..f5bd6230ce6 --- /dev/null +++ b/targets/TARGET_TOSHIBA/TARGET_TMPM066/reset_reason_api.c @@ -0,0 +1,123 @@ +/* mbed Microcontroller Library + * (C)Copyright TOSHIBA ELECTRONIC DEVICES & STORAGE CORPORATION 2017 All rights reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include +#include "reset_reason_api.h" +#include "TMPM066.h" + +#define MAXRSTREASON 6 + +static uint8_t set_bit_count(uint32_t reg); +static uint8_t bit_pos(uint32_t reg); +static bool bit_status(uint32_t reg, uint8_t bit_no); + +static reset_reason_t reset_reason1[MAXRSTREASON] = { + RESET_REASON_POWER_ON, + RESET_REASON_UNKNOWN, + RESET_REASON_UNKNOWN, + RESET_REASON_PIN_RESET, + RESET_REASON_UNKNOWN, + RESET_REASON_BROWN_OUT +}; + +static reset_reason_t reset_reason2[MAXRSTREASON] = { + RESET_REASON_SOFTWARE, + RESET_REASON_UNKNOWN, + RESET_REASON_WATCHDOG +}; + +void hal_reset_reason_clear(void) +{ + TSB_AOREG->RSTFLG = 0x00; + TSB_AOREG->RSTFLG1 = 0x00; +} + +uint32_t hal_reset_reason_get_raw(void) +{ + uint32_t ret = 0x00; + + ret = (((TSB_AOREG->RSTFLG1 & 0xFF) << 8) | (TSB_AOREG->RSTFLG & 0xFF)); + + return ret; +} + +reset_reason_t hal_reset_reason_get(void) +{ + reset_reason_t ret; + + uint8_t NoOfSetBitCountReg1 = set_bit_count(TSB_AOREG->RSTFLG); + uint8_t NoOfSetBitCountReg2 = set_bit_count(TSB_AOREG->RSTFLG1); + + if (NoOfSetBitCountReg1 != 0x00) { + if (NoOfSetBitCountReg1 > 0x01) { + if (bit_status(TSB_AOREG->RSTFLG, 0) && bit_status(TSB_AOREG->RSTFLG, 3)) { + ret = RESET_REASON_POWER_ON; + } else { + ret = RESET_REASON_MULTIPLE; + } + } else { + ret = reset_reason1[bit_pos(TSB_AOREG->RSTFLG)]; + } + } else if (NoOfSetBitCountReg2 != 0x00) { + if (NoOfSetBitCountReg2 > 0x01) { + ret = RESET_REASON_MULTIPLE; + } else { + ret = reset_reason2[bit_pos(TSB_AOREG->RSTFLG1)]; + } + } else { + ret = RESET_REASON_UNKNOWN; + } + + return ret; +} + +static bool bit_status(uint32_t reg, uint8_t bit_no) +{ + bool status = false; + + if (reg & (1 << bit_no)) { + status = true; + } + + return status; +} + +static uint8_t set_bit_count(uint32_t reg) +{ + uint8_t count = 0; + int8_t index = 0; + + for (index = 0; index < (sizeof(uint32_t) * 8); index++) { + if (reg & (1 << index)) { + count++; + if (count > 0x01) { + break; + } + } + } + + return count; +} + +static uint8_t bit_pos(uint32_t reg) +{ + uint8_t bit_no = 0; + + for (bit_no = 0; bit_no < (sizeof(uint32_t) * 8); bit_no++) { + if (reg & (1 << bit_no)) { + return bit_no; + } + } +} diff --git a/targets/TARGET_TOSHIBA/TARGET_TMPM46B/reset_reason_api.c b/targets/TARGET_TOSHIBA/TARGET_TMPM46B/reset_reason_api.c new file mode 100644 index 00000000000..af94dc4f55a --- /dev/null +++ b/targets/TARGET_TOSHIBA/TARGET_TMPM46B/reset_reason_api.c @@ -0,0 +1,89 @@ +/* mbed Microcontroller Library + * (C)Copyright TOSHIBA ELECTRONIC DEVICES & STORAGE CORPORATION 2018 All rights reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include +#include "reset_reason_api.h" +#include "TMPM46B.h" + +static uint8_t set_bit_count(uint32_t reg); +static uint8_t bit_pos(uint32_t reg); + +static reset_reason_t reset_reason[7] = { + RESET_REASON_PIN_RESET, + RESET_REASON_UNKNOWN, + RESET_REASON_WATCHDOG, + RESET_REASON_WAKE_LOW_POWER, + RESET_REASON_SOFTWARE, + RESET_REASON_UNKNOWN, + RESET_REASON_BROWN_OUT +}; + +void hal_reset_reason_clear(void) +{ + TSB_CG->RSTFLG = 0x00; +} + +uint32_t hal_reset_reason_get_raw(void) +{ + uint32_t ret = 0; + + ret = TSB_CG->RSTFLG; + + return ret; +} + +reset_reason_t hal_reset_reason_get(void) +{ + reset_reason_t ret; + + uint8_t NoOfSetBitCountReg = set_bit_count(TSB_CG->RSTFLG); + + if (NoOfSetBitCountReg != 0x00) { + if (NoOfSetBitCountReg > 0x01) { + ret = RESET_REASON_MULTIPLE; + } else { + ret = reset_reason[bit_pos(TSB_CG->RSTFLG)]; + } + } else { + ret = RESET_REASON_UNKNOWN; + } + + return ret; +} + +static uint8_t set_bit_count(uint32_t reg) +{ + uint8_t count = 0; + int8_t index = 0; + + for (index = 0; index < (sizeof(uint32_t) * 8); index++) { + if ((reg & (1 << index)) && index != 1) { + count++; + } + } + + return count; +} + +static uint8_t bit_pos(uint32_t reg) +{ + uint8_t bit_no = 0; + + for (bit_no = 0; bit_no < (sizeof(uint32_t) * 8); bit_no++) { + if ((reg & (1 << bit_no)) && bit_no != 1) { + return bit_no; + } + } +} diff --git a/targets/targets.json b/targets/targets.json index 2c7ecfaa587..7b0c388174b 100644 --- a/targets/targets.json +++ b/targets/targets.json @@ -6924,7 +6924,6 @@ }, "inherits": ["Target"], "macros_add": ["LPTICKER_DELAY_TICKS=3"], -<<<<<<< HEAD "progen": { "target": "numaker-pfm-m453" }, "device_has": [ "USTICKER", @@ -6950,12 +6949,9 @@ "SPI_ASYNCH", "CAN", "FLASH", - "MPU" + "MPU", + "WATCHDOG" ], -======= - "progen": {"target": "numaker-pfm-m453"}, - "device_has": ["USTICKER", "LPTICKER", "RTC", "ANALOGIN", "I2C", "I2CSLAVE", "I2C_ASYNCH", "INTERRUPTIN", "PORTIN", "PORTINOUT", "PORTOUT", "PWMOUT", "SERIAL", "SERIAL_ASYNCH", "SERIAL_FC", "STDIO_MESSAGES", "SLEEP", "SPI", "SPISLAVE", "SPI_ASYNCH", "CAN", "FLASH", "RESET_REASON", "WATCHDOG"], ->>>>>>> [Nuvoton] Support watchdog timer "release_versions": ["2", "5"], "device_name": "M453VG6AE", "bootloader_supported": true @@ -6990,7 +6986,6 @@ } }, "inherits": ["Target"], -<<<<<<< HEAD "macros": [ "CMSIS_VECTAB_VIRTUAL", "CMSIS_VECTAB_VIRTUAL_HEADER_FILE=\"cmsis_nvic.h\"", @@ -7019,12 +7014,9 @@ "SLEEP", "SPI", "SPISLAVE", - "SPI_ASYNCH" + "SPI_ASYNCH", + "WATCHDOG" ], -======= - "macros": ["CMSIS_VECTAB_VIRTUAL", "CMSIS_VECTAB_VIRTUAL_HEADER_FILE=\"cmsis_nvic.h\"","MBED_FAULT_HANDLER_DISABLED", "LPTICKER_DELAY_TICKS=3"], - "device_has": ["USTICKER", "LPTICKER", "RTC", "ANALOGIN", "I2C", "I2CSLAVE", "I2C_ASYNCH", "INTERRUPTIN", "PORTIN", "PORTINOUT", "PORTOUT", "PWMOUT", "SERIAL", "SERIAL_ASYNCH", "SERIAL_FC", "STDIO_MESSAGES", "SLEEP", "SPI", "SPISLAVE", "SPI_ASYNCH", "RESET_REASON", "WATCHDOG"], ->>>>>>> [Nuvoton] Support watchdog timer "release_versions": ["5"], "device_name": "NANO130KE3BN" }, @@ -7334,12 +7326,9 @@ "FLASH", "CAN", "EMAC", - "MPU" + "MPU", + "WATCHDOG" ], -======= - "device_has": ["USTICKER", "LPTICKER", "RTC", "ANALOGIN", "I2C", "I2CSLAVE", "I2C_ASYNCH", "INTERRUPTIN", "PORTIN", "PORTINOUT", "PORTOUT", "PWMOUT", "SERIAL", "SERIAL_ASYNCH", "SERIAL_FC", "STDIO_MESSAGES", "SLEEP", "SPI", "SPISLAVE", "SPI_ASYNCH", "TRNG", "FLASH", "CAN", "EMAC", "RESET_REASON", "WATCHDOG"], - "features": ["LWIP"], ->>>>>>> [Nuvoton] Support watchdog timer "release_versions": ["5"], "bootloader_supported": true, "overrides": { @@ -7372,6 +7361,7 @@ "PORTIN", "PORTINOUT", "PORTOUT", + "RESET_REASON", "SERIAL", "SLEEP", "I2C", @@ -7432,6 +7422,7 @@ "PORTINOUT", "PORTOUT", "PWMOUT", + "RESET_REASON", "SERIAL", "SERIAL_FC", "SPI", From 4edc78ad921a12c7ff6714af2c93e1fd67b2e5ce Mon Sep 17 00:00:00 2001 From: Ganesh Ramachandran Date: Fri, 26 Oct 2018 12:51:51 +0530 Subject: [PATCH 49/62] Added reset_reason feature for TMPM3H6 & TMPM4G9 --- .../TARGET_TMPM3H6/reset_reason_api.c | 120 +++++++++++++++++ .../TARGET_TMPM4G9/reset_reason_api.c | 123 ++++++++++++++++++ targets/targets.json | 2 + 3 files changed, 245 insertions(+) create mode 100644 targets/TARGET_TOSHIBA/TARGET_TMPM3H6/reset_reason_api.c create mode 100644 targets/TARGET_TOSHIBA/TARGET_TMPM4G9/reset_reason_api.c diff --git a/targets/TARGET_TOSHIBA/TARGET_TMPM3H6/reset_reason_api.c b/targets/TARGET_TOSHIBA/TARGET_TMPM3H6/reset_reason_api.c new file mode 100644 index 00000000000..6531df6458c --- /dev/null +++ b/targets/TARGET_TOSHIBA/TARGET_TMPM3H6/reset_reason_api.c @@ -0,0 +1,120 @@ +/* mbed Microcontroller Library + * (C)Copyright TOSHIBA ELECTRONIC DEVICES & STORAGE CORPORATION 2018 All rights reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include +#include "reset_reason_api.h" +#include "TMPM3H6.h" + +static uint8_t set_bit_count(uint32_t reg); +static uint8_t bit_pos(uint32_t reg); +static bool bit_status(uint32_t reg, uint8_t bit_no); + +static reset_reason_t reset_reason1[6] = { + RESET_REASON_POWER_ON, + RESET_REASON_UNKNOWN, + RESET_REASON_UNKNOWN, + RESET_REASON_PIN_RESET, + RESET_REASON_WAKE_LOW_POWER, + RESET_REASON_BROWN_OUT +}; + +static reset_reason_t reset_reason2[4] = { + RESET_REASON_SOFTWARE, + RESET_REASON_LOCKUP, + RESET_REASON_WATCHDOG, + RESET_REASON_PLATFORM +}; + +void hal_reset_reason_clear(void) +{ + TSB_RLM->RSTFLG0 = 0; + TSB_RLM->RSTFLG1 = 0; +} + +uint32_t hal_reset_reason_get_raw(void) +{ + uint32_t ret = (((TSB_RLM->RSTFLG1 & 0xFF) << 8) | (TSB_RLM->RSTFLG0 & 0xFF)); + return ret; +} + +reset_reason_t hal_reset_reason_get(void) +{ + char multi_flag = 0; + reset_reason_t ret; + + uint8_t NoOfSetBitCountReg1 = set_bit_count(TSB_RLM->RSTFLG0); + uint8_t NoOfSetBitCountReg2 = set_bit_count(TSB_RLM->RSTFLG1); + + if (NoOfSetBitCountReg1 != 0x00) { + if (NoOfSetBitCountReg1 > 0x01) { + if (bit_status(TSB_RLM->RSTFLG0, 3)) { + ret = RESET_REASON_POWER_ON; + } else { + ret = RESET_REASON_MULTIPLE; + } + } else { + ret = reset_reason1[bit_pos(TSB_RLM->RSTFLG0)]; + } + } else if (NoOfSetBitCountReg2 != 0x00) { + if (NoOfSetBitCountReg2 > 0x01) { + ret = RESET_REASON_MULTIPLE; + } else { + ret = reset_reason2[bit_pos(TSB_RLM->RSTFLG1)]; + } + } else { + ret = RESET_REASON_UNKNOWN; + } + + return ret; +} + +static bool bit_status(uint32_t reg, uint8_t bit_no) +{ + bool status = false; + + if (reg & (1 << bit_no)) { + status = true; + } + + return status; +} + +static uint8_t set_bit_count(uint32_t reg) +{ + uint8_t count = 0; + int8_t index = 0; + + for (index = 0; index < (sizeof(uint32_t) * 8); index++) { + if (reg & (1 << index)) { + count++; + if (count > 0x01) { + break; + } + } + } + + return count; +} + +static uint8_t bit_pos(uint32_t reg) +{ + uint8_t bit_no = 0; + + for (bit_no = 0; bit_no < (sizeof(uint32_t) * 8); bit_no++) { + if (reg & (1 << bit_no)) { + return bit_no; + } + } +} diff --git a/targets/TARGET_TOSHIBA/TARGET_TMPM4G9/reset_reason_api.c b/targets/TARGET_TOSHIBA/TARGET_TMPM4G9/reset_reason_api.c new file mode 100644 index 00000000000..e02974aedc7 --- /dev/null +++ b/targets/TARGET_TOSHIBA/TARGET_TMPM4G9/reset_reason_api.c @@ -0,0 +1,123 @@ +/* mbed Microcontroller Library + * (C)Copyright TOSHIBA ELECTRONIC DEVICES & STORAGE CORPORATION 2018 All rights reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include +#include "reset_reason_api.h" +#include "TMPM4G9.h" + +static uint8_t set_bit_count(uint32_t reg); +static uint8_t bit_pos(uint32_t reg); +static bool bit_status(uint32_t reg, uint8_t bit_no); + +static reset_reason_t reset_reason1[6] = { + RESET_REASON_POWER_ON, + RESET_REASON_UNKNOWN, + RESET_REASON_UNKNOWN, + RESET_REASON_PIN_RESET, + RESET_REASON_WAKE_LOW_POWER, + RESET_REASON_BROWN_OUT +}; + +static reset_reason_t reset_reason2[4] = { + RESET_REASON_SOFTWARE, + RESET_REASON_LOCKUP, + RESET_REASON_WATCHDOG, + RESET_REASON_PLATFORM +}; + +void hal_reset_reason_clear(void) +{ + TSB_RLM->RSTFLG0 = 0; + TSB_RLM->RSTFLG1 = 0; +} + +uint32_t hal_reset_reason_get_raw(void) +{ + uint32_t ret = 0; + + ret = (((TSB_RLM->RSTFLG1 & 0xFF) << 8) | (TSB_RLM->RSTFLG0 & 0xFF)); + + return ret; +} + +reset_reason_t hal_reset_reason_get(void) +{ + char multi_flag = 0; + reset_reason_t ret; + + uint8_t NoOfSetBitCountReg1 = set_bit_count(TSB_RLM->RSTFLG0); + uint8_t NoOfSetBitCountReg2 = set_bit_count(TSB_RLM->RSTFLG1); + + if (NoOfSetBitCountReg1 != 0x00) { + if (NoOfSetBitCountReg1 > 0x01) { + if (bit_status(TSB_RLM->RSTFLG0, 3)) { + ret = RESET_REASON_POWER_ON; + } else { + ret = RESET_REASON_MULTIPLE; + } + } else { + ret = reset_reason1[bit_pos(TSB_RLM->RSTFLG0)]; + } + } else if (NoOfSetBitCountReg2 != 0x00) { + if (NoOfSetBitCountReg2 > 0x01) { + ret = RESET_REASON_MULTIPLE; + } else { + ret = reset_reason2[bit_pos(TSB_RLM->RSTFLG1)]; + } + } else { + ret = RESET_REASON_UNKNOWN; + } + + return ret; +} + +static bool bit_status(uint32_t reg, uint8_t bit_no) +{ + bool status = false; + + if (reg & (1 << bit_no)) { + status = true; + } + + return status; +} + +static uint8_t set_bit_count(uint32_t reg) +{ + uint8_t count = 0; + int8_t index = 0; + + for (index = 0; index < (sizeof(uint32_t) * 8); index++) { + if (reg & (1 << index)) { + count++; + if (count > 0x01) { + break; + } + } + } + + return count; +} + +static uint8_t bit_pos(uint32_t reg) +{ + uint8_t bit_no = 0; + + for (bit_no = 0; bit_no < (sizeof(uint32_t) * 8); bit_no++) { + if (reg & (1 << bit_no)) { + return bit_no; + } + } +} diff --git a/targets/targets.json b/targets/targets.json index 7b0c388174b..78a6c119ad8 100644 --- a/targets/targets.json +++ b/targets/targets.json @@ -7388,6 +7388,7 @@ "PORTINOUT", "PORTOUT", "PWMOUT", + "RESET_REASON", "SERIAL", "SLEEP", "SPI", @@ -7611,6 +7612,7 @@ "PORTINOUT", "PORTOUT", "PWMOUT", + "RESET_REASON", "SERIAL", "SPI", "I2C", From a3ea8a6786f6ded054b266209536146f830a8057 Mon Sep 17 00:00:00 2001 From: Steve Cartmell Date: Mon, 29 Oct 2018 17:00:40 +0000 Subject: [PATCH 50/62] test(api-watchdog): Fix errors in compiling watchdog greentea tests The latest rebase of the watchdog feature branch introduced errors in compiling watchdog tests due to missing headers. - Watchdog HAL API test Include missing header files to main.cpp (mbed_wait_api.h, stdlib.h). - Watchdog HAL API timing test Include missing header files to main.cpp (us_ticker_api.h). - Watchdog Driver API test Include missing header files to main.cpp (mbed_wait_api.h, stdlib.h). Inject mbed namespace into main.cpp to fix Watchdog name resolution. --- TESTS/mbed_drivers/watchdog/main.cpp | 11 ++++++++--- TESTS/mbed_hal/watchdog/main.cpp | 7 +++++-- TESTS/mbed_hal/watchdog_timing/main.cpp | 5 +++-- 3 files changed, 16 insertions(+), 7 deletions(-) diff --git a/TESTS/mbed_drivers/watchdog/main.cpp b/TESTS/mbed_drivers/watchdog/main.cpp index 386593e172d..a54ac669742 100644 --- a/TESTS/mbed_drivers/watchdog/main.cpp +++ b/TESTS/mbed_drivers/watchdog/main.cpp @@ -18,13 +18,16 @@ #endif #define __STDC_LIMIT_MACROS -#include +#include "drivers/Watchdog.h" #include "greentea-client/test_env.h" -#include "utest/utest.h" +#include "mbed_wait_api.h" #include "unity/unity.h" -#include "drivers/Watchdog.h" +#include "utest/utest.h" #include "Watchdog_tests.h" +#include +#include + /* This is platform specific and depends on the watchdog timer implementation, * e.g. STM32F4 uses 32kHz internal RC oscillator to clock the IWDG, so * when the prescaler divider is set to max value of 256 the resolution @@ -50,6 +53,8 @@ using utest::v1::Case; using utest::v1::Specification; using utest::v1::Harness; +using namespace mbed; + void test_max_timeout_is_valid() { Watchdog watchdog; diff --git a/TESTS/mbed_hal/watchdog/main.cpp b/TESTS/mbed_hal/watchdog/main.cpp index a4434ab2230..611da95280b 100644 --- a/TESTS/mbed_hal/watchdog/main.cpp +++ b/TESTS/mbed_hal/watchdog/main.cpp @@ -18,11 +18,14 @@ #endif #include "greentea-client/test_env.h" -#include "utest/utest.h" -#include "unity/unity.h" #include "hal/watchdog_api.h" +#include "mbed_wait_api.h" +#include "unity/unity.h" +#include "utest/utest.h" #include "watchdog_api_tests.h" +#include + /* This is platform specific and depends on the watchdog timer implementation, * e.g. STM32F4 uses 32kHz internal RC oscillator to clock the IWDG, so * when the prescaler divider is set to max value of 256 the resolution diff --git a/TESTS/mbed_hal/watchdog_timing/main.cpp b/TESTS/mbed_hal/watchdog_timing/main.cpp index 38711e76090..a20312423cf 100644 --- a/TESTS/mbed_hal/watchdog_timing/main.cpp +++ b/TESTS/mbed_hal/watchdog_timing/main.cpp @@ -18,9 +18,10 @@ #endif #include "greentea-client/test_env.h" -#include "utest/utest.h" -#include "unity/unity.h" #include "hal/watchdog_api.h" +#include "unity/unity.h" +#include "us_ticker_api.h" +#include "utest/utest.h" #include "watchdog_timing_tests.h" #define MSG_VALUE_DUMMY "0" From 0e1dbcc6c48b11308b75075782fa90f17c26c676 Mon Sep 17 00:00:00 2001 From: Steve Cartmell Date: Tue, 30 Oct 2018 12:04:50 +0000 Subject: [PATCH 51/62] fix(hal-watchdog): Add feature guards to K64F watchdog implementation --- .../TARGET_MCUXpresso_MCUS/TARGET_MCU_K64F/reset_reason.c | 4 ++++ .../TARGET_MCUXpresso_MCUS/TARGET_MCU_K64F/watchdog_api.c | 5 +++++ 2 files changed, 9 insertions(+) diff --git a/targets/TARGET_Freescale/TARGET_MCUXpresso_MCUS/TARGET_MCU_K64F/reset_reason.c b/targets/TARGET_Freescale/TARGET_MCUXpresso_MCUS/TARGET_MCU_K64F/reset_reason.c index 1a5eb42909c..6a646211d81 100644 --- a/targets/TARGET_Freescale/TARGET_MCUXpresso_MCUS/TARGET_MCU_K64F/reset_reason.c +++ b/targets/TARGET_Freescale/TARGET_MCUXpresso_MCUS/TARGET_MCU_K64F/reset_reason.c @@ -15,6 +15,8 @@ */ #include "reset_reason_api.h" +#if DEVICE_RESET_REASON + #include "fsl_rcm.h" reset_reason_t hal_reset_reason_get(void) @@ -102,3 +104,5 @@ void hal_reset_reason_clear(void) RCM_ClearStickyResetSources(RCM, kRCM_SourceAll); #endif } + +#endif // DEVICE_RESET_REASON diff --git a/targets/TARGET_Freescale/TARGET_MCUXpresso_MCUS/TARGET_MCU_K64F/watchdog_api.c b/targets/TARGET_Freescale/TARGET_MCUXpresso_MCUS/TARGET_MCU_K64F/watchdog_api.c index 22006d91773..1b2f72feb45 100644 --- a/targets/TARGET_Freescale/TARGET_MCUXpresso_MCUS/TARGET_MCU_K64F/watchdog_api.c +++ b/targets/TARGET_Freescale/TARGET_MCUXpresso_MCUS/TARGET_MCU_K64F/watchdog_api.c @@ -14,6 +14,9 @@ * limitations under the License. */ #include "watchdog_api.h" + +#if DEVICE_WATCHDOG + #include "reset_reason_api.h" #include "fsl_wdog.h" #include "fsl_clock.h" @@ -123,3 +126,5 @@ watchdog_features_t hal_watchdog_get_platform_features(void) return features; } + +#endif // DEVICE_WATCHDOG From fed02b0fa80a2b8e655047b2da47f366daddb8f9 Mon Sep 17 00:00:00 2001 From: Donatien Garnier Date: Mon, 19 Nov 2018 16:55:27 +0000 Subject: [PATCH 52/62] Update license headers --- TESTS/host_tests/reset_reason.py | 4 ++-- TESTS/host_tests/watchdog_reset.py | 4 ++-- TESTS/mbed_drivers/reset_reason/ResetReason_tests.h | 1 + TESTS/mbed_drivers/reset_reason/main.cpp | 1 + TESTS/mbed_drivers/watchdog/Watchdog_tests.h | 1 + TESTS/mbed_drivers/watchdog/main.cpp | 1 + TESTS/mbed_drivers/watchdog_reset/Watchdog_reset_tests.h | 1 + TESTS/mbed_drivers/watchdog_reset/main.cpp | 1 + TESTS/mbed_hal/reset_reason/main.cpp | 3 ++- TESTS/mbed_hal/reset_reason/reset_reason_api_tests.h | 3 ++- TESTS/mbed_hal/watchdog/main.cpp | 3 ++- TESTS/mbed_hal/watchdog/watchdog_api_tests.h | 3 ++- TESTS/mbed_hal/watchdog_reset/main.cpp | 3 ++- TESTS/mbed_hal/watchdog_reset/watchdog_reset_tests.h | 3 ++- TESTS/mbed_hal/watchdog_timing/main.cpp | 1 + TESTS/mbed_hal/watchdog_timing/watchdog_timing_tests.h | 1 + drivers/ResetReason.cpp | 3 ++- drivers/ResetReason.h | 3 ++- drivers/Watchdog.cpp | 3 ++- drivers/Watchdog.h | 3 ++- 20 files changed, 32 insertions(+), 14 deletions(-) diff --git a/TESTS/host_tests/reset_reason.py b/TESTS/host_tests/reset_reason.py index 2cfe131cb70..9ba0c3815dd 100644 --- a/TESTS/host_tests/reset_reason.py +++ b/TESTS/host_tests/reset_reason.py @@ -1,6 +1,6 @@ """ -mbed SDK -Copyright (c) 2017 ARM Limited +Copyright (c) 2018 ARM Limited +SPDX-License-Identifier: Apache-2.0 Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/TESTS/host_tests/watchdog_reset.py b/TESTS/host_tests/watchdog_reset.py index c8f32168213..605e03d03d5 100644 --- a/TESTS/host_tests/watchdog_reset.py +++ b/TESTS/host_tests/watchdog_reset.py @@ -1,6 +1,6 @@ """ -mbed SDK -Copyright (c) 2017 ARM Limited +Copyright (c) 2018 ARM Limited +SPDX-License-Identifier: Apache-2.0 Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/TESTS/mbed_drivers/reset_reason/ResetReason_tests.h b/TESTS/mbed_drivers/reset_reason/ResetReason_tests.h index 80671d8526f..a500b252c7d 100644 --- a/TESTS/mbed_drivers/reset_reason/ResetReason_tests.h +++ b/TESTS/mbed_drivers/reset_reason/ResetReason_tests.h @@ -1,5 +1,6 @@ /* mbed Microcontroller Library * Copyright (c) 2018 ARM Limited + * SPDX-License-Identifier: Apache-2.0 * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/TESTS/mbed_drivers/reset_reason/main.cpp b/TESTS/mbed_drivers/reset_reason/main.cpp index 5ca38feec1c..2f32b75d7c2 100644 --- a/TESTS/mbed_drivers/reset_reason/main.cpp +++ b/TESTS/mbed_drivers/reset_reason/main.cpp @@ -1,5 +1,6 @@ /* mbed Microcontroller Library * Copyright (c) 2018 ARM Limited + * SPDX-License-Identifier: Apache-2.0 * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/TESTS/mbed_drivers/watchdog/Watchdog_tests.h b/TESTS/mbed_drivers/watchdog/Watchdog_tests.h index cf2d6da30a5..6d76c56724e 100644 --- a/TESTS/mbed_drivers/watchdog/Watchdog_tests.h +++ b/TESTS/mbed_drivers/watchdog/Watchdog_tests.h @@ -1,5 +1,6 @@ /* mbed Microcontroller Library * Copyright (c) 2018 ARM Limited + * SPDX-License-Identifier: Apache-2.0 * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/TESTS/mbed_drivers/watchdog/main.cpp b/TESTS/mbed_drivers/watchdog/main.cpp index a54ac669742..dd8ee4bdc93 100644 --- a/TESTS/mbed_drivers/watchdog/main.cpp +++ b/TESTS/mbed_drivers/watchdog/main.cpp @@ -1,5 +1,6 @@ /* mbed Microcontroller Library * Copyright (c) 2018 ARM Limited + * SPDX-License-Identifier: Apache-2.0 * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/TESTS/mbed_drivers/watchdog_reset/Watchdog_reset_tests.h b/TESTS/mbed_drivers/watchdog_reset/Watchdog_reset_tests.h index e4add3a50a8..3597621a584 100644 --- a/TESTS/mbed_drivers/watchdog_reset/Watchdog_reset_tests.h +++ b/TESTS/mbed_drivers/watchdog_reset/Watchdog_reset_tests.h @@ -1,5 +1,6 @@ /* mbed Microcontroller Library * Copyright (c) 2018 ARM Limited + * SPDX-License-Identifier: Apache-2.0 * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/TESTS/mbed_drivers/watchdog_reset/main.cpp b/TESTS/mbed_drivers/watchdog_reset/main.cpp index 45d8e941c85..983e0687114 100644 --- a/TESTS/mbed_drivers/watchdog_reset/main.cpp +++ b/TESTS/mbed_drivers/watchdog_reset/main.cpp @@ -1,5 +1,6 @@ /* mbed Microcontroller Library * Copyright (c) 2018 ARM Limited + * SPDX-License-Identifier: Apache-2.0 * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/TESTS/mbed_hal/reset_reason/main.cpp b/TESTS/mbed_hal/reset_reason/main.cpp index c2759a387f3..891e0398ca4 100644 --- a/TESTS/mbed_hal/reset_reason/main.cpp +++ b/TESTS/mbed_hal/reset_reason/main.cpp @@ -1,5 +1,6 @@ /* mbed Microcontroller Library - * Copyright (c) 2017 ARM Limited + * Copyright (c) 2018 ARM Limited + * SPDX-License-Identifier: Apache-2.0 * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/TESTS/mbed_hal/reset_reason/reset_reason_api_tests.h b/TESTS/mbed_hal/reset_reason/reset_reason_api_tests.h index c9f9efc0644..b515f97f10c 100644 --- a/TESTS/mbed_hal/reset_reason/reset_reason_api_tests.h +++ b/TESTS/mbed_hal/reset_reason/reset_reason_api_tests.h @@ -1,5 +1,6 @@ /* mbed Microcontroller Library - * Copyright (c) 2017 ARM Limited + * Copyright (c) 2018 ARM Limited + * SPDX-License-Identifier: Apache-2.0 * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/TESTS/mbed_hal/watchdog/main.cpp b/TESTS/mbed_hal/watchdog/main.cpp index 611da95280b..24a262ff2fd 100644 --- a/TESTS/mbed_hal/watchdog/main.cpp +++ b/TESTS/mbed_hal/watchdog/main.cpp @@ -1,5 +1,6 @@ /* mbed Microcontroller Library - * Copyright (c) 2017 ARM Limited + * Copyright (c) 2018 ARM Limited + * SPDX-License-Identifier: Apache-2.0 * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/TESTS/mbed_hal/watchdog/watchdog_api_tests.h b/TESTS/mbed_hal/watchdog/watchdog_api_tests.h index 82dfd5795d1..dad785e9443 100644 --- a/TESTS/mbed_hal/watchdog/watchdog_api_tests.h +++ b/TESTS/mbed_hal/watchdog/watchdog_api_tests.h @@ -1,5 +1,6 @@ /* mbed Microcontroller Library - * Copyright (c) 2017 ARM Limited + * Copyright (c) 2018 ARM Limited + * SPDX-License-Identifier: Apache-2.0 * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/TESTS/mbed_hal/watchdog_reset/main.cpp b/TESTS/mbed_hal/watchdog_reset/main.cpp index c4e179e65c9..1cc772c4f24 100644 --- a/TESTS/mbed_hal/watchdog_reset/main.cpp +++ b/TESTS/mbed_hal/watchdog_reset/main.cpp @@ -1,5 +1,6 @@ /* mbed Microcontroller Library - * Copyright (c) 2017 ARM Limited + * Copyright (c) 2018 ARM Limited + * SPDX-License-Identifier: Apache-2.0 * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/TESTS/mbed_hal/watchdog_reset/watchdog_reset_tests.h b/TESTS/mbed_hal/watchdog_reset/watchdog_reset_tests.h index a90e0b95a2e..7dd2d1a0180 100644 --- a/TESTS/mbed_hal/watchdog_reset/watchdog_reset_tests.h +++ b/TESTS/mbed_hal/watchdog_reset/watchdog_reset_tests.h @@ -1,5 +1,6 @@ /* mbed Microcontroller Library - * Copyright (c) 2017 ARM Limited + * Copyright (c) 2018 ARM Limited + * SPDX-License-Identifier: Apache-2.0 * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/TESTS/mbed_hal/watchdog_timing/main.cpp b/TESTS/mbed_hal/watchdog_timing/main.cpp index a20312423cf..513d39d0316 100644 --- a/TESTS/mbed_hal/watchdog_timing/main.cpp +++ b/TESTS/mbed_hal/watchdog_timing/main.cpp @@ -1,5 +1,6 @@ /* mbed Microcontroller Library * Copyright (c) 2018 ARM Limited + * SPDX-License-Identifier: Apache-2.0 * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/TESTS/mbed_hal/watchdog_timing/watchdog_timing_tests.h b/TESTS/mbed_hal/watchdog_timing/watchdog_timing_tests.h index 7ea8bdf4753..72f5bb68921 100644 --- a/TESTS/mbed_hal/watchdog_timing/watchdog_timing_tests.h +++ b/TESTS/mbed_hal/watchdog_timing/watchdog_timing_tests.h @@ -1,5 +1,6 @@ /* mbed Microcontroller Library * Copyright (c) 2018 ARM Limited + * SPDX-License-Identifier: Apache-2.0 * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/drivers/ResetReason.cpp b/drivers/ResetReason.cpp index 7070cef4901..9614fb82627 100644 --- a/drivers/ResetReason.cpp +++ b/drivers/ResetReason.cpp @@ -1,5 +1,6 @@ /* mbed Microcontroller Library - * Copyright (c) 2017 ARM Limited + * Copyright (c) 2018 ARM Limited + * SPDX-License-Identifier: Apache-2.0 * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/drivers/ResetReason.h b/drivers/ResetReason.h index 54f4ff102d7..fa8736a2684 100644 --- a/drivers/ResetReason.h +++ b/drivers/ResetReason.h @@ -1,5 +1,6 @@ /* mbed Microcontroller Library - * Copyright (c) 2017 ARM Limited + * Copyright (c) 2018 ARM Limited + * SPDX-License-Identifier: Apache-2.0 * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/drivers/Watchdog.cpp b/drivers/Watchdog.cpp index 36a6dd2e18e..0d655b0a219 100644 --- a/drivers/Watchdog.cpp +++ b/drivers/Watchdog.cpp @@ -1,5 +1,6 @@ /* mbed Microcontroller Library - * Copyright (c) 2017 ARM Limited + * Copyright (c) 2018 ARM Limited + * SPDX-License-Identifier: Apache-2.0 * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/drivers/Watchdog.h b/drivers/Watchdog.h index 66cefcaed78..f09503372f7 100644 --- a/drivers/Watchdog.h +++ b/drivers/Watchdog.h @@ -1,5 +1,6 @@ /* mbed Microcontroller Library - * Copyright (c) 2017 ARM Limited + * Copyright (c) 2018 ARM Limited + * SPDX-License-Identifier: Apache-2.0 * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. From dbf3be90bcec9b9bb81240946bfd0046ff4bb639 Mon Sep 17 00:00:00 2001 From: Donatien Garnier Date: Mon, 19 Nov 2018 17:12:55 +0000 Subject: [PATCH 53/62] Apply new astyle config style --- TESTS/mbed_drivers/reset_reason/main.cpp | 2 +- TESTS/mbed_drivers/watchdog/main.cpp | 6 +-- TESTS/mbed_drivers/watchdog_reset/main.cpp | 2 +- TESTS/mbed_hal/reset_reason/main.cpp | 2 +- TESTS/mbed_hal/watchdog/main.cpp | 10 ++-- TESTS/mbed_hal/watchdog_reset/main.cpp | 2 +- TESTS/mbed_hal/watchdog_timing/main.cpp | 4 +- drivers/ResetReason.h | 6 +-- drivers/Watchdog.cpp | 3 +- drivers/Watchdog.h | 3 +- hal/reset_reason_api.h | 24 +++++----- hal/watchdog_api.h | 56 +++++++++++----------- 12 files changed, 57 insertions(+), 63 deletions(-) diff --git a/TESTS/mbed_drivers/reset_reason/main.cpp b/TESTS/mbed_drivers/reset_reason/main.cpp index 2f32b75d7c2..4b1eaa8e3a7 100644 --- a/TESTS/mbed_drivers/reset_reason/main.cpp +++ b/TESTS/mbed_drivers/reset_reason/main.cpp @@ -61,7 +61,7 @@ static cmd_status_t handle_command(const char *key, const char *value) uint32_t raw_reason = ResetReason::get_raw(); char raw_reason_hex_str[9] = { }; int raw_reason_hex_str_len = snprintf(raw_reason_hex_str, - sizeof raw_reason_hex_str, "%08lx", raw_reason); + sizeof raw_reason_hex_str, "%08lx", raw_reason); if (raw_reason_hex_str_len != (sizeof raw_reason_hex_str) - 1) { TEST_ASSERT_MESSAGE(0, "Failed to compose raw reset reason hex string."); diff --git a/TESTS/mbed_drivers/watchdog/main.cpp b/TESTS/mbed_drivers/watchdog/main.cpp index dd8ee4bdc93..cc813f9beba 100644 --- a/TESTS/mbed_drivers/watchdog/main.cpp +++ b/TESTS/mbed_drivers/watchdog/main.cpp @@ -204,15 +204,15 @@ Case cases[] = { Case("max_timeout is valid", test_max_timeout_is_valid), Case("Stop", test_stop), Case("Restart multiple times", (utest::v1::case_setup_handler_t) case_setup_sync_on_reset, - test_restart, (utest::v1::case_teardown_handler_t) case_teardown_sync_on_reset), + test_restart, (utest::v1::case_teardown_handler_t) case_teardown_sync_on_reset), // Do not set watchdog timeout shorter than 500 ms as it may cause the // host-test-runner return 'TIMEOUT' instead of 'FAIL' / 'PASS' if watchdog // performs reset during test suite teardown. Case("Start, 500 ms", (utest::v1::case_setup_handler_t) case_setup_sync_on_reset, - test_start<500UL>, (utest::v1::case_teardown_handler_t) case_teardown_sync_on_reset), + test_start<500UL>, (utest::v1::case_teardown_handler_t) case_teardown_sync_on_reset), Case("Start, max_timeout", (utest::v1::case_setup_handler_t) case_setup_sync_on_reset, - test_start_max_timeout, (utest::v1::case_teardown_handler_t) case_teardown_sync_on_reset), + test_start_max_timeout, (utest::v1::case_teardown_handler_t) case_teardown_sync_on_reset), Case("Start, 0 ms", test_start_zero), Case("Start, max_timeout exceeded", test_start_max_timeout_exceeded), diff --git a/TESTS/mbed_drivers/watchdog_reset/main.cpp b/TESTS/mbed_drivers/watchdog_reset/main.cpp index 983e0687114..1011d780876 100644 --- a/TESTS/mbed_drivers/watchdog_reset/main.cpp +++ b/TESTS/mbed_drivers/watchdog_reset/main.cpp @@ -261,7 +261,7 @@ int testsuite_setup(const size_t number_of_cases) } utest_printf("This test suite is composed of %i test cases. Starting at index %i.\n", number_of_cases, - current_case.start_index); + current_case.start_index); return current_case.start_index; } diff --git a/TESTS/mbed_hal/reset_reason/main.cpp b/TESTS/mbed_hal/reset_reason/main.cpp index 891e0398ca4..4a10c9b02ad 100644 --- a/TESTS/mbed_hal/reset_reason/main.cpp +++ b/TESTS/mbed_hal/reset_reason/main.cpp @@ -77,7 +77,7 @@ static cmd_status_t handle_command(const char *key, const char *value) uint32_t raw_reason = hal_reset_reason_get_raw(); char raw_reason_hex_str[9] = { }; int raw_reason_hex_str_len = snprintf(raw_reason_hex_str, - sizeof raw_reason_hex_str, "%08lx", raw_reason); + sizeof raw_reason_hex_str, "%08lx", raw_reason); if (raw_reason_hex_str_len != (sizeof raw_reason_hex_str) - 1) { TEST_ASSERT_MESSAGE(0, "Failed to compose raw reset reason hex string."); diff --git a/TESTS/mbed_hal/watchdog/main.cpp b/TESTS/mbed_hal/watchdog/main.cpp index 24a262ff2fd..e8365ed8119 100644 --- a/TESTS/mbed_hal/watchdog/main.cpp +++ b/TESTS/mbed_hal/watchdog/main.cpp @@ -217,17 +217,17 @@ Case cases[] = { Case("Watchdog can be stopped", test_stop), Case("Update config with multiple init calls", - (utest::v1::case_setup_handler_t) case_setup_sync_on_reset, - test_update_config, - (utest::v1::case_teardown_handler_t) case_teardown_wdg_stop_or_reset), + (utest::v1::case_setup_handler_t) case_setup_sync_on_reset, + test_update_config, + (utest::v1::case_teardown_handler_t) case_teardown_wdg_stop_or_reset), // Do not set watchdog timeout shorter than 500 ms as it may cause the // host-test-runner return 'TIMEOUT' instead of 'FAIL' / 'PASS' if watchdog // performs reset during test suite teardown. Case("Init, 500 ms", (utest::v1::case_setup_handler_t) case_setup_sync_on_reset, - test_init<500UL>, (utest::v1::case_teardown_handler_t) case_teardown_sync_on_reset), + test_init<500UL>, (utest::v1::case_teardown_handler_t) case_teardown_sync_on_reset), Case("Init, max_timeout", (utest::v1::case_setup_handler_t) case_setup_sync_on_reset, - test_init_max_timeout, (utest::v1::case_teardown_handler_t) case_teardown_sync_on_reset), + test_init_max_timeout, (utest::v1::case_teardown_handler_t) case_teardown_sync_on_reset), }; Specification specification((utest::v1::test_setup_handler_t) testsuite_setup_sync_on_reset, cases); diff --git a/TESTS/mbed_hal/watchdog_reset/main.cpp b/TESTS/mbed_hal/watchdog_reset/main.cpp index 1cc772c4f24..9b121c4bc5b 100644 --- a/TESTS/mbed_hal/watchdog_reset/main.cpp +++ b/TESTS/mbed_hal/watchdog_reset/main.cpp @@ -284,7 +284,7 @@ int testsuite_setup(const size_t number_of_cases) } utest_printf("This test suite is composed of %i test cases. Starting at index %i.\n", number_of_cases, - current_case.start_index); + current_case.start_index); return current_case.start_index; } diff --git a/TESTS/mbed_hal/watchdog_timing/main.cpp b/TESTS/mbed_hal/watchdog_timing/main.cpp index 513d39d0316..ba7412807cf 100644 --- a/TESTS/mbed_hal/watchdog_timing/main.cpp +++ b/TESTS/mbed_hal/watchdog_timing/main.cpp @@ -77,7 +77,7 @@ void test_timing() } int str_len = snprintf(msg_value, sizeof msg_value, "%02x,%08lx", current_case.start_index + current_case.index, - (uint32_t) current_ts); + (uint32_t) current_ts); if (str_len != (sizeof msg_value) - 1) { utest_printf("Failed to compose a value string to be sent to host."); return; @@ -130,7 +130,7 @@ int testsuite_setup(const size_t number_of_cases) } utest_printf("This test suite is composed of %i test cases. Starting at index %i.\n", number_of_cases, - current_case.start_index); + current_case.start_index); return current_case.start_index; } diff --git a/drivers/ResetReason.h b/drivers/ResetReason.h index fa8736a2684..7bc74255b34 100644 --- a/drivers/ResetReason.h +++ b/drivers/ResetReason.h @@ -21,8 +21,7 @@ #include "reset_reason_api.h" -namespace mbed -{ +namespace mbed { /** \addtogroup drivers */ /** ResetReason API. When the system is restarted, the reason for the restart is * contained in the system registers at boot time in a platform specific manner, @@ -30,8 +29,7 @@ namespace mbed * * @ingroup drivers */ -class ResetReason -{ +class ResetReason { public: /** Get the platform-independent reason code for the last system reset. * diff --git a/drivers/Watchdog.cpp b/drivers/Watchdog.cpp index 0d655b0a219..0214173e456 100644 --- a/drivers/Watchdog.cpp +++ b/drivers/Watchdog.cpp @@ -18,8 +18,7 @@ #include "Watchdog.h" -namespace mbed -{ +namespace mbed { watchdog_status_t Watchdog::start(const uint32_t timeout) { diff --git a/drivers/Watchdog.h b/drivers/Watchdog.h index f09503372f7..a154f9abf58 100644 --- a/drivers/Watchdog.h +++ b/drivers/Watchdog.h @@ -44,8 +44,7 @@ namespace mbed { * @endcode * @ingroup drivers */ -class Watchdog -{ +class Watchdog { public: Watchdog() {} diff --git a/hal/reset_reason_api.h b/hal/reset_reason_api.h index e9d0d793984..b43b2fbcabc 100644 --- a/hal/reset_reason_api.h +++ b/hal/reset_reason_api.h @@ -34,18 +34,18 @@ extern "C" { /** Definitions of different reset reasons */ typedef enum { - RESET_REASON_POWER_ON, /**< Set when power is initially applied to the board. The power-on-reset circuit causes a POWER_ON reset when this occurs */ - RESET_REASON_PIN_RESET, /**< Set when a reset is triggered by the hardware pin on the board */ - RESET_REASON_BROWN_OUT, /**< Triggered when the voltage drops below the low voltage detect (LVD) threshold the system will be held in a reset until the voltage rises above the threshold */ - RESET_REASON_SOFTWARE, /**< Set during software reset, typically triggered by writing the SYSRESETREQ bit in the Application Interrupt and Reset Control register */ - RESET_REASON_WATCHDOG, /**< Set when a running watchdog timer fails to be refreshed */ - RESET_REASON_LOCKUP, /**< Set when the core is locked because of an unrecoverable exception */ - RESET_REASON_WAKE_LOW_POWER, /**< Set when waking from deep sleep mode */ - RESET_REASON_ACCESS_ERROR, /**< Umbrella value that encompasses any access related reset */ - RESET_REASON_BOOT_ERROR, /**< Umbrella value that encompasses any boot related reset */ - RESET_REASON_MULTIPLE, /**< Set if multiple reset reasons are set within the board. Occurs when the reset reason registers aren't cleared between resets */ - RESET_REASON_PLATFORM, /**< Platform specific reset reason not captured in this enum */ - RESET_REASON_UNKNOWN /**< Unknown or unreadable reset reason **/ + RESET_REASON_POWER_ON, /**< Set when power is initially applied to the board. The power-on-reset circuit causes a POWER_ON reset when this occurs */ + RESET_REASON_PIN_RESET, /**< Set when a reset is triggered by the hardware pin on the board */ + RESET_REASON_BROWN_OUT, /**< Triggered when the voltage drops below the low voltage detect (LVD) threshold the system will be held in a reset until the voltage rises above the threshold */ + RESET_REASON_SOFTWARE, /**< Set during software reset, typically triggered by writing the SYSRESETREQ bit in the Application Interrupt and Reset Control register */ + RESET_REASON_WATCHDOG, /**< Set when a running watchdog timer fails to be refreshed */ + RESET_REASON_LOCKUP, /**< Set when the core is locked because of an unrecoverable exception */ + RESET_REASON_WAKE_LOW_POWER, /**< Set when waking from deep sleep mode */ + RESET_REASON_ACCESS_ERROR, /**< Umbrella value that encompasses any access related reset */ + RESET_REASON_BOOT_ERROR, /**< Umbrella value that encompasses any boot related reset */ + RESET_REASON_MULTIPLE, /**< Set if multiple reset reasons are set within the board. Occurs when the reset reason registers aren't cleared between resets */ + RESET_REASON_PLATFORM, /**< Platform specific reset reason not captured in this enum */ + RESET_REASON_UNKNOWN /**< Unknown or unreadable reset reason **/ } reset_reason_t; /** Fetch the reset reason for the last system reset diff --git a/hal/watchdog_api.h b/hal/watchdog_api.h index 1cf4e8f8587..e7fe9da6d71 100644 --- a/hal/watchdog_api.h +++ b/hal/watchdog_api.h @@ -46,45 +46,43 @@ * modes unless the chip is woken to refresh the timer. */ -typedef struct -{ - /** - * Refresh value for the watchdog in milliseconds. The maximum value of this - * setting is platform dependent, to find the maximum value for the current - * platform call hal_watchdog_get_features() and check the timeout value - * member. The minimum valid value for this setting is 1, attempting to - * initialise the watchdog with a timeout of 0ms will return - * WATCHDOG_STATUS_INVALID_ARGUMENT. - */ - uint32_t timeout_ms; +typedef struct { + /** + * Refresh value for the watchdog in milliseconds. The maximum value of this + * setting is platform dependent, to find the maximum value for the current + * platform call hal_watchdog_get_features() and check the timeout value + * member. The minimum valid value for this setting is 1, attempting to + * initialise the watchdog with a timeout of 0ms will return + * WATCHDOG_STATUS_INVALID_ARGUMENT. + */ + uint32_t timeout_ms; } watchdog_config_t; -typedef struct -{ - /** - * Maximum timeout value for the watchdog in milliseconds. - */ - uint32_t max_timeout; - /** - * Watchdog configuration can be updated after the watchdog has been started - */ - bool update_config; - /** - * Watchdog can be stopped after it is started without a reset - */ - bool disable_watchdog; +typedef struct { + /** + * Maximum timeout value for the watchdog in milliseconds. + */ + uint32_t max_timeout; + /** + * Watchdog configuration can be updated after the watchdog has been started + */ + bool update_config; + /** + * Watchdog can be stopped after it is started without a reset + */ + bool disable_watchdog; } watchdog_features_t; typedef enum { - WATCHDOG_STATUS_OK, - WATCHDOG_STATUS_NOT_SUPPORTED, - WATCHDOG_STATUS_INVALID_ARGUMENT + WATCHDOG_STATUS_OK, + WATCHDOG_STATUS_NOT_SUPPORTED, + WATCHDOG_STATUS_INVALID_ARGUMENT } watchdog_status_t; #ifdef __cplusplus - extern "C" { +extern "C" { #endif /** Initialise and start a watchdog timer with the given configuration. From 09d755ed071667698217c21405acae5b1a45a0c8 Mon Sep 17 00:00:00 2001 From: Donatien Garnier Date: Mon, 19 Nov 2018 18:36:54 +0000 Subject: [PATCH 54/62] Fix more astyle failures --- TESTS/mbed_drivers/watchdog/main.cpp | 6 +++--- TESTS/mbed_drivers/watchdog_reset/main.cpp | 4 ++-- TESTS/mbed_hal/watchdog/main.cpp | 10 +++++----- TESTS/mbed_hal/watchdog_reset/main.cpp | 4 ++-- TESTS/mbed_hal/watchdog_timing/main.cpp | 4 ++-- 5 files changed, 14 insertions(+), 14 deletions(-) diff --git a/TESTS/mbed_drivers/watchdog/main.cpp b/TESTS/mbed_drivers/watchdog/main.cpp index cc813f9beba..8e8ebcfe833 100644 --- a/TESTS/mbed_drivers/watchdog/main.cpp +++ b/TESTS/mbed_drivers/watchdog/main.cpp @@ -109,14 +109,14 @@ void test_restart() TEST_ASSERT_UINT32_WITHIN(WORST_TIMEOUT_RESOLUTION_MS, watchdog.max_timeout(), watchdog.reload_value()); } -utest::v1::status_t case_setup_sync_on_reset(const Case * const source, const size_t index_of_case) +utest::v1::status_t case_setup_sync_on_reset(const Case *const source, const size_t index_of_case) { CASE_INDEX_CURRENT = index_of_case; return utest::v1::greentea_case_setup_handler(source, index_of_case); } -utest::v1::status_t case_teardown_sync_on_reset(const Case * const source, const size_t passed, const size_t failed, - const utest::v1::failure_t failure) +utest::v1::status_t case_teardown_sync_on_reset(const Case *const source, const size_t passed, const size_t failed, + const utest::v1::failure_t failure) { utest::v1::status_t status = utest::v1::greentea_case_teardown_handler(source, passed, failed, failure); if (failed) { diff --git a/TESTS/mbed_drivers/watchdog_reset/main.cpp b/TESTS/mbed_drivers/watchdog_reset/main.cpp index 1011d780876..7c30f034d24 100644 --- a/TESTS/mbed_drivers/watchdog_reset/main.cpp +++ b/TESTS/mbed_drivers/watchdog_reset/main.cpp @@ -56,7 +56,7 @@ void release_sem(Semaphore *sem) testcase_data current_case; -bool send_reset_notification(testcase_data * tcdata, uint32_t delay_ms) +bool send_reset_notification(testcase_data *tcdata, uint32_t delay_ms) { char msg_value[12]; int str_len = snprintf(msg_value, sizeof msg_value, "%02x,%08lx", tcdata->start_index + tcdata->index, delay_ms); @@ -229,7 +229,7 @@ void test_kick_reset() TEST_ASSERT_MESSAGE(0, "Watchdog did not reset the device as expected."); } -utest::v1::status_t case_setup(const Case * const source, const size_t index_of_case) +utest::v1::status_t case_setup(const Case *const source, const size_t index_of_case) { current_case.index = index_of_case; return utest::v1::greentea_case_setup_handler(source, index_of_case); diff --git a/TESTS/mbed_hal/watchdog/main.cpp b/TESTS/mbed_hal/watchdog/main.cpp index e8365ed8119..2aa1202e54e 100644 --- a/TESTS/mbed_hal/watchdog/main.cpp +++ b/TESTS/mbed_hal/watchdog/main.cpp @@ -125,14 +125,14 @@ void test_update_config() TEST_ASSERT_UINT32_WITHIN(WORST_TIMEOUT_RESOLUTION_MS, config.timeout_ms, hal_watchdog_get_reload_value()); } -utest::v1::status_t case_setup_sync_on_reset(const Case * const source, const size_t index_of_case) +utest::v1::status_t case_setup_sync_on_reset(const Case *const source, const size_t index_of_case) { CASE_INDEX_CURRENT = index_of_case; return utest::v1::greentea_case_setup_handler(source, index_of_case); } -utest::v1::status_t case_teardown_sync_on_reset(const Case * const source, const size_t passed, const size_t failed, - const utest::v1::failure_t failure) +utest::v1::status_t case_teardown_sync_on_reset(const Case *const source, const size_t passed, const size_t failed, + const utest::v1::failure_t failure) { utest::v1::status_t status = utest::v1::greentea_case_teardown_handler(source, passed, failed, failure); if (failed) { @@ -153,8 +153,8 @@ utest::v1::status_t case_teardown_sync_on_reset(const Case * const source, const return status; // Reset is instant so this line won't be reached. } -utest::v1::status_t case_teardown_wdg_stop_or_reset(const Case * const source, const size_t passed, const size_t failed, - const utest::v1::failure_t failure) +utest::v1::status_t case_teardown_wdg_stop_or_reset(const Case *const source, const size_t passed, const size_t failed, + const utest::v1::failure_t failure) { watchdog_features_t features = hal_watchdog_get_platform_features(); if (features.disable_watchdog) { diff --git a/TESTS/mbed_hal/watchdog_reset/main.cpp b/TESTS/mbed_hal/watchdog_reset/main.cpp index 9b121c4bc5b..7f24060d108 100644 --- a/TESTS/mbed_hal/watchdog_reset/main.cpp +++ b/TESTS/mbed_hal/watchdog_reset/main.cpp @@ -78,7 +78,7 @@ void release_sem(Semaphore *sem) testcase_data current_case; -bool send_reset_notification(testcase_data * tcdata, uint32_t delay_ms) +bool send_reset_notification(testcase_data *tcdata, uint32_t delay_ms) { char msg_value[12]; int str_len = snprintf(msg_value, sizeof msg_value, "%02x,%08lx", tcdata->start_index + tcdata->index, delay_ms); @@ -252,7 +252,7 @@ void test_kick_reset() TEST_ASSERT_MESSAGE(0, "Watchdog did not reset the device as expected."); } -utest::v1::status_t case_setup(const Case * const source, const size_t index_of_case) +utest::v1::status_t case_setup(const Case *const source, const size_t index_of_case) { current_case.index = index_of_case; return utest::v1::greentea_case_setup_handler(source, index_of_case); diff --git a/TESTS/mbed_hal/watchdog_timing/main.cpp b/TESTS/mbed_hal/watchdog_timing/main.cpp index ba7412807cf..fba5a95d914 100644 --- a/TESTS/mbed_hal/watchdog_timing/main.cpp +++ b/TESTS/mbed_hal/watchdog_timing/main.cpp @@ -60,7 +60,7 @@ void test_timing() // Phase 1. -- run the test code. // Send heartbeat messages to host until the watchdeg resets the device. - const ticker_data_t * const us_ticker = get_us_ticker_data(); + const ticker_data_t *const us_ticker = get_us_ticker_data(); us_timestamp_t current_ts, next_ts, expected_reset_ts, divider, ts_increment; char msg_value[12]; @@ -98,7 +98,7 @@ void test_timing() } } -utest::v1::status_t case_setup(const Case * const source, const size_t index_of_case) +utest::v1::status_t case_setup(const Case *const source, const size_t index_of_case) { current_case.index = index_of_case; return utest::v1::greentea_case_setup_handler(source, index_of_case); From 5cb3eb878cff58798d83d46aefffbe9d53a180ee Mon Sep 17 00:00:00 2001 From: Filip Jagodzinski Date: Thu, 22 Nov 2018 20:43:17 +0100 Subject: [PATCH 55/62] Tests: Watchdog: Fix config access in the host script Move the calls to get_config_item() to the setup() method. The config is not available in the initializer yet. --- TESTS/host_tests/reset_reason.py | 5 +++-- TESTS/host_tests/sync_on_reset.py | 5 +++-- TESTS/host_tests/watchdog_reset.py | 5 +++-- 3 files changed, 9 insertions(+), 6 deletions(-) diff --git a/TESTS/host_tests/reset_reason.py b/TESTS/host_tests/reset_reason.py index 9ba0c3815dd..16ee7ffbe29 100644 --- a/TESTS/host_tests/reset_reason.py +++ b/TESTS/host_tests/reset_reason.py @@ -68,13 +68,14 @@ def __init__(self): super(ResetReasonTest, self).__init__() self.device_has_watchdog = None self.raw_reset_reasons = set() - cycle_s = self.get_config_item('program_cycle_s') - self.program_cycle_s = cycle_s if cycle_s is not None else DEFAULT_CYCLE_PERIOD + self.program_cycle_s = DEFAULT_CYCLE_PERIOD self.test_steps_sequence = self.test_steps() # Advance the coroutine to it's first yield statement. self.test_steps_sequence.send(None) def setup(self): + cycle_s = self.get_config_item('program_cycle_s') + self.program_cycle_s = cycle_s if cycle_s is not None else DEFAULT_CYCLE_PERIOD self.register_callback(MSG_KEY_DEVICE_READY, self.cb_device_ready) self.register_callback(MSG_KEY_RESET_REASON_RAW, self.cb_reset_reason_raw) self.register_callback(MSG_KEY_RESET_REASON, self.cb_reset_reason) diff --git a/TESTS/host_tests/sync_on_reset.py b/TESTS/host_tests/sync_on_reset.py index 134f3c53351..57e2e454150 100644 --- a/TESTS/host_tests/sync_on_reset.py +++ b/TESTS/host_tests/sync_on_reset.py @@ -47,10 +47,11 @@ class SyncOnReset(BaseHostTest): def __init__(self): super(SyncOnReset, self).__init__() self.test_case_num = 0 - cycle_s = self.get_config_item('program_cycle_s') - self.program_cycle_s = cycle_s if cycle_s is not None else DEFAULT_CYCLE_PERIOD + self.program_cycle_s = DEFAULT_CYCLE_PERIOD def setup(self): + cycle_s = self.get_config_item('program_cycle_s') + self.program_cycle_s = cycle_s if cycle_s is not None else DEFAULT_CYCLE_PERIOD self.register_callback(MSG_KEY_DEVICE_READY, self.cb_device_ready) self.register_callback(MSG_KEY_DEVICE_RESET, self.cb_device_reset) diff --git a/TESTS/host_tests/watchdog_reset.py b/TESTS/host_tests/watchdog_reset.py index 605e03d03d5..cc9b3bc2c47 100644 --- a/TESTS/host_tests/watchdog_reset.py +++ b/TESTS/host_tests/watchdog_reset.py @@ -49,8 +49,7 @@ def __init__(self): super(WatchdogReset, self).__init__() self.current_case = TestCaseData(0, CASE_DATA_INVALID) self.__handshake_timer = None - cycle_s = self.get_config_item('program_cycle_s') - self.program_cycle_s = cycle_s if cycle_s is not None else DEFAULT_CYCLE_PERIOD + self.program_cycle_s = DEFAULT_CYCLE_PERIOD self.drop_heartbeat_messages = True self.hb_timestamps_us = [] @@ -94,6 +93,8 @@ def heartbeat_timeout_handler(self): self.current_case = TestCaseData(self.current_case.index, dev_data) def setup(self): + cycle_s = self.get_config_item('program_cycle_s') + self.program_cycle_s = cycle_s if cycle_s is not None else DEFAULT_CYCLE_PERIOD self.register_callback(MSG_KEY_DEVICE_READY, self.cb_device_ready) self.register_callback(MSG_KEY_DEVICE_RESET, self.cb_device_reset) self.register_callback(MSG_KEY_HEARTBEAT, self.cb_heartbeat) From 78c0a3e452481b37793af5384bb4d9198b7245c5 Mon Sep 17 00:00:00 2001 From: Filip Jagodzinski Date: Thu, 22 Nov 2018 20:58:13 +0100 Subject: [PATCH 56/62] Tests: Watchdog: Update the reset-to-sync delay Change the config parameter used as a delay before sending the sync packet after the device reset in watchdog and reset_reason tests. Use 'forced_reset_timeout' instead of 'program_cycle_s'. --- TESTS/host_tests/reset_reason.py | 12 ++++++------ TESTS/host_tests/sync_on_reset.py | 10 +++++----- TESTS/host_tests/watchdog_reset.py | 12 ++++++------ 3 files changed, 17 insertions(+), 17 deletions(-) diff --git a/TESTS/host_tests/reset_reason.py b/TESTS/host_tests/reset_reason.py index 16ee7ffbe29..c8769e22a20 100644 --- a/TESTS/host_tests/reset_reason.py +++ b/TESTS/host_tests/reset_reason.py @@ -18,7 +18,7 @@ from mbed_host_tests import BaseHostTest from mbed_host_tests.host_tests_runner.host_test_default import DefaultTestSelector -DEFAULT_CYCLE_PERIOD = 4.0 +DEFAULT_SYNC_DELAY = 4.0 MSG_VALUE_WATCHDOG_PRESENT = 'wdg_present' MSG_VALUE_DUMMY = '0' @@ -68,14 +68,14 @@ def __init__(self): super(ResetReasonTest, self).__init__() self.device_has_watchdog = None self.raw_reset_reasons = set() - self.program_cycle_s = DEFAULT_CYCLE_PERIOD + self.sync_delay = DEFAULT_SYNC_DELAY self.test_steps_sequence = self.test_steps() # Advance the coroutine to it's first yield statement. self.test_steps_sequence.send(None) def setup(self): - cycle_s = self.get_config_item('program_cycle_s') - self.program_cycle_s = cycle_s if cycle_s is not None else DEFAULT_CYCLE_PERIOD + sync_delay = self.get_config_item('forced_reset_timeout') + self.sync_delay = sync_delay if sync_delay is not None else DEFAULT_SYNC_DELAY self.register_callback(MSG_KEY_DEVICE_READY, self.cb_device_ready) self.register_callback(MSG_KEY_RESET_REASON_RAW, self.cb_reset_reason_raw) self.register_callback(MSG_KEY_RESET_REASON, self.cb_reset_reason) @@ -134,7 +134,7 @@ def test_steps(self): # Request a NVIC_SystemReset() call. self.send_kv(MSG_KEY_DEVICE_RESET, MSG_VALUE_DEVICE_RESET_NVIC) __ignored_reset_ack = yield - time.sleep(self.program_cycle_s) + time.sleep(self.sync_delay) self.send_kv(MSG_KEY_SYNC, MSG_VALUE_DUMMY) reset_reason = yield raise_if_different(RESET_REASONS['SOFTWARE'], reset_reason, 'Wrong reset reason. ') @@ -154,7 +154,7 @@ def test_steps(self): else: self.send_kv(MSG_KEY_DEVICE_RESET, MSG_VALUE_DEVICE_RESET_WATCHDOG) __ignored_reset_ack = yield - time.sleep(self.program_cycle_s) + time.sleep(self.sync_delay) self.send_kv(MSG_KEY_SYNC, MSG_VALUE_DUMMY) reset_reason = yield raise_if_different(RESET_REASONS['WATCHDOG'], reset_reason, 'Wrong reset reason. ') diff --git a/TESTS/host_tests/sync_on_reset.py b/TESTS/host_tests/sync_on_reset.py index 57e2e454150..de3cbc0ae35 100644 --- a/TESTS/host_tests/sync_on_reset.py +++ b/TESTS/host_tests/sync_on_reset.py @@ -17,7 +17,7 @@ import time from mbed_host_tests import BaseHostTest -DEFAULT_CYCLE_PERIOD = 4.0 +DEFAULT_SYNC_DELAY = 4.0 MSG_VALUE_DUMMY = '0' MSG_KEY_DEVICE_READY = 'ready' @@ -47,11 +47,11 @@ class SyncOnReset(BaseHostTest): def __init__(self): super(SyncOnReset, self).__init__() self.test_case_num = 0 - self.program_cycle_s = DEFAULT_CYCLE_PERIOD + self.sync_delay = DEFAULT_SYNC_DELAY def setup(self): - cycle_s = self.get_config_item('program_cycle_s') - self.program_cycle_s = cycle_s if cycle_s is not None else DEFAULT_CYCLE_PERIOD + sync_delay = self.get_config_item('forced_reset_timeout') + self.sync_delay = sync_delay if sync_delay is not None else DEFAULT_SYNC_DELAY self.register_callback(MSG_KEY_DEVICE_READY, self.cb_device_ready) self.register_callback(MSG_KEY_DEVICE_RESET, self.cb_device_reset) @@ -69,5 +69,5 @@ def cb_device_reset(self, key, value, timestamp): except ValueError: pass self.test_case_num += 1 - time.sleep(self.program_cycle_s) + time.sleep(self.sync_delay) self.send_kv(MSG_KEY_SYNC, MSG_VALUE_DUMMY) diff --git a/TESTS/host_tests/watchdog_reset.py b/TESTS/host_tests/watchdog_reset.py index cc9b3bc2c47..4f12d420f82 100644 --- a/TESTS/host_tests/watchdog_reset.py +++ b/TESTS/host_tests/watchdog_reset.py @@ -20,7 +20,7 @@ TestCaseData = collections.namedtuple('TestCaseData', ['index', 'data_to_send']) -DEFAULT_CYCLE_PERIOD = 4.0 +DEFAULT_SYNC_DELAY = 4.0 MAX_HB_PERIOD = 2.5 # [s] Max expected heartbeat period. MSG_VALUE_DUMMY = '0' @@ -49,7 +49,7 @@ def __init__(self): super(WatchdogReset, self).__init__() self.current_case = TestCaseData(0, CASE_DATA_INVALID) self.__handshake_timer = None - self.program_cycle_s = DEFAULT_CYCLE_PERIOD + self.sync_delay = DEFAULT_SYNC_DELAY self.drop_heartbeat_messages = True self.hb_timestamps_us = [] @@ -93,8 +93,8 @@ def heartbeat_timeout_handler(self): self.current_case = TestCaseData(self.current_case.index, dev_data) def setup(self): - cycle_s = self.get_config_item('program_cycle_s') - self.program_cycle_s = cycle_s if cycle_s is not None else DEFAULT_CYCLE_PERIOD + sync_delay = self.get_config_item('forced_reset_timeout') + self.sync_delay = sync_delay if sync_delay is not None else DEFAULT_SYNC_DELAY self.register_callback(MSG_KEY_DEVICE_READY, self.cb_device_ready) self.register_callback(MSG_KEY_DEVICE_RESET, self.cb_device_reset) self.register_callback(MSG_KEY_HEARTBEAT, self.cb_heartbeat) @@ -123,7 +123,7 @@ def cb_device_reset(self, key, value, timestamp): self.handshake_timer_cancel() case_num, dev_reset_delay_ms = (int(i, base=16) for i in value.split(',')) self.current_case = TestCaseData(case_num, CASE_DATA_PHASE2_OK) - self.handshake_timer_start(self.program_cycle_s + dev_reset_delay_ms / 1000.0) + self.handshake_timer_start(self.sync_delay + dev_reset_delay_ms / 1000.0) def cb_heartbeat(self, key, value, timestamp): """Save the timestamp of a heartbeat message. @@ -141,5 +141,5 @@ def cb_heartbeat(self, key, value, timestamp): self.current_case = TestCaseData(case_num, CASE_DATA_INVALID) self.hb_timestamps_us.append(timestamp_us) self.handshake_timer_start( - seconds=(MAX_HB_PERIOD + self.program_cycle_s), + seconds=(MAX_HB_PERIOD + self.sync_delay), pre_sync_fun=self.heartbeat_timeout_handler) From 391c76132d8222d909246f3e1e0679c96f16c0e8 Mon Sep 17 00:00:00 2001 From: Ganesh Ramachandran Date: Fri, 23 Nov 2018 12:27:38 +0530 Subject: [PATCH 57/62] Added reset_reason feature for TMPM3HQ --- .../TARGET_TMPM3HQ/reset_reason_api.c | 120 ++++++++++++++++++ targets/targets.json | 1 + 2 files changed, 121 insertions(+) create mode 100644 targets/TARGET_TOSHIBA/TARGET_TMPM3HQ/reset_reason_api.c diff --git a/targets/TARGET_TOSHIBA/TARGET_TMPM3HQ/reset_reason_api.c b/targets/TARGET_TOSHIBA/TARGET_TMPM3HQ/reset_reason_api.c new file mode 100644 index 00000000000..5d9c5175d34 --- /dev/null +++ b/targets/TARGET_TOSHIBA/TARGET_TMPM3HQ/reset_reason_api.c @@ -0,0 +1,120 @@ +/* mbed Microcontroller Library + * (C)Copyright TOSHIBA ELECTRONIC DEVICES & STORAGE CORPORATION 2018 All rights reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include +#include "reset_reason_api.h" +#include "TMPM3HQ.h" + +static uint8_t set_bit_count(uint32_t reg); +static uint8_t bit_pos(uint32_t reg); +static bool bit_status(uint32_t reg, uint8_t bit_no); + +static reset_reason_t reset_reason1[6] = { + RESET_REASON_POWER_ON, + RESET_REASON_UNKNOWN, + RESET_REASON_UNKNOWN, + RESET_REASON_PIN_RESET, + RESET_REASON_WAKE_LOW_POWER, + RESET_REASON_BROWN_OUT +}; + +static reset_reason_t reset_reason2[4] = { + RESET_REASON_SOFTWARE, + RESET_REASON_LOCKUP, + RESET_REASON_WATCHDOG, + RESET_REASON_PLATFORM +}; + +void hal_reset_reason_clear(void) +{ + TSB_RLM->RSTFLG0 = 0; + TSB_RLM->RSTFLG1 = 0; +} + +uint32_t hal_reset_reason_get_raw(void) +{ + uint32_t ret = (((TSB_RLM->RSTFLG1 & 0xFF) << 8) | (TSB_RLM->RSTFLG0 & 0xFF)); + return ret; +} + +reset_reason_t hal_reset_reason_get(void) +{ + char multi_flag = 0; + reset_reason_t ret; + + uint8_t NoOfSetBitCountReg1 = set_bit_count(TSB_RLM->RSTFLG0); + uint8_t NoOfSetBitCountReg2 = set_bit_count(TSB_RLM->RSTFLG1); + + if (NoOfSetBitCountReg1 != 0x00) { + if (NoOfSetBitCountReg1 > 0x01) { + if (bit_status(TSB_RLM->RSTFLG0, 3)) { + ret = RESET_REASON_POWER_ON; + } else { + ret = RESET_REASON_MULTIPLE; + } + } else { + ret = reset_reason1[bit_pos(TSB_RLM->RSTFLG0)]; + } + } else if (NoOfSetBitCountReg2 != 0x00) { + if (NoOfSetBitCountReg2 > 0x01) { + ret = RESET_REASON_MULTIPLE; + } else { + ret = reset_reason2[bit_pos(TSB_RLM->RSTFLG1)]; + } + } else { + ret = RESET_REASON_UNKNOWN; + } + + return ret; +} + +static bool bit_status(uint32_t reg, uint8_t bit_no) +{ + bool status = false; + + if (reg & (1 << bit_no)) { + status = true; + } + + return status; +} + +static uint8_t set_bit_count(uint32_t reg) +{ + uint8_t count = 0; + int8_t index = 0; + + for (index = 0; index < (sizeof(uint32_t) * 8); index++) { + if (reg & (1 << index)) { + count++; + if (count > 0x01) { + break; + } + } + } + + return count; +} + +static uint8_t bit_pos(uint32_t reg) +{ + uint8_t bit_no = 0; + + for (bit_no = 0; bit_no < (sizeof(uint32_t) * 8); bit_no++) { + if (reg & (1 << bit_no)) { + return bit_no; + } + } +} diff --git a/targets/targets.json b/targets/targets.json index 78a6c119ad8..af454df9d66 100644 --- a/targets/targets.json +++ b/targets/targets.json @@ -7585,6 +7585,7 @@ "PORTINOUT", "PORTOUT", "PWMOUT", + "RESET_REASON", "SERIAL", "SLEEP", "SPI", From a2f7ba7ad7f881557e904cab43ac051f64ca893e Mon Sep 17 00:00:00 2001 From: Amanda Butler Date: Mon, 26 Nov 2018 14:26:28 -0600 Subject: [PATCH 58/62] Edit ResetReason_tests.h Make minor grammar edits. --- TESTS/mbed_drivers/reset_reason/ResetReason_tests.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/TESTS/mbed_drivers/reset_reason/ResetReason_tests.h b/TESTS/mbed_drivers/reset_reason/ResetReason_tests.h index a500b252c7d..549e53a9398 100644 --- a/TESTS/mbed_drivers/reset_reason/ResetReason_tests.h +++ b/TESTS/mbed_drivers/reset_reason/ResetReason_tests.h @@ -27,9 +27,9 @@ /** Test the ResetReason driver API * - * Given a device supporting a ResetReason API - * When the device is restarted using various methods - * Then the device returns a correct reset reason for every restart + * Given a device supporting a ResetReason API, + * when the device is restarted, + * then the device returns a correct reset reason for every restart. */ void test_reset_reason(); From 425fc1a665be24c37f2531799ada91ebf26e1b88 Mon Sep 17 00:00:00 2001 From: Steve Cartmell Date: Tue, 11 Dec 2018 11:02:57 +0000 Subject: [PATCH 59/62] fix: Remove excess comma from device_has key in targets.json --- targets/targets.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/targets/targets.json b/targets/targets.json index af454df9d66..f1411a422e8 100644 --- a/targets/targets.json +++ b/targets/targets.json @@ -2680,7 +2680,7 @@ "TRNG", "FLASH", "MPU", - "WATCHDOG", + "WATCHDOG" ], "detect_code": ["0797"], "release_versions": ["2", "5"], From ef8e682732bdefe27dc8f07276db348775cfc196 Mon Sep 17 00:00:00 2001 From: Steve Cartmell Date: Tue, 18 Dec 2018 11:42:45 +0000 Subject: [PATCH 60/62] fix(hal-watchdog): Remove 'RESET_REASON' flags from unsupported devices --- targets/targets.json | 3 --- 1 file changed, 3 deletions(-) diff --git a/targets/targets.json b/targets/targets.json index f1411a422e8..c69789c7f76 100644 --- a/targets/targets.json +++ b/targets/targets.json @@ -1760,7 +1760,6 @@ "PORTIN", "PORTINOUT", "PORTOUT", - "RESET_REASON", "PWMOUT", "SERIAL", "SLEEP", @@ -6570,7 +6569,6 @@ "PORTINOUT", "PORTOUT", "PWMOUT", - "RESET_REASON", "SERIAL", "SERIAL_ASYNCH", "SERIAL_FC", @@ -6693,7 +6691,6 @@ "PORTINOUT", "PORTOUT", "PWMOUT", - "RESET_REASON", "SERIAL", "SERIAL_ASYNCH", "SERIAL_FC", From f89239e1f5a96536a69eba532cc1b7d551b017be Mon Sep 17 00:00:00 2001 From: Steve Cartmell Date: Tue, 18 Dec 2018 16:13:02 +0000 Subject: [PATCH 61/62] fix(hal-watchdog): Add 'RESET_REASON' flags to supported devices --- targets/targets.json | 1 + 1 file changed, 1 insertion(+) diff --git a/targets/targets.json b/targets/targets.json index c69789c7f76..104bee49ff6 100644 --- a/targets/targets.json +++ b/targets/targets.json @@ -7789,6 +7789,7 @@ "PORTINOUT", "PORTOUT", "PWMOUT", + "RESET_REASON", "SERIAL", "SLEEP", "SPI", From 34b1acd00f4a1b1871633d021e76c94ea9d2352c Mon Sep 17 00:00:00 2001 From: Steve Cartmell Date: Tue, 18 Dec 2018 16:13:58 +0000 Subject: [PATCH 62/62] fix(hal-watchdog): Guard TMPM 'ResetReason' code behind feature flag --- targets/TARGET_TOSHIBA/TARGET_TMPM066/reset_reason_api.c | 7 ++++++- targets/TARGET_TOSHIBA/TARGET_TMPM3H6/reset_reason_api.c | 7 ++++++- targets/TARGET_TOSHIBA/TARGET_TMPM3HQ/reset_reason_api.c | 7 ++++++- targets/TARGET_TOSHIBA/TARGET_TMPM46B/reset_reason_api.c | 7 ++++++- targets/TARGET_TOSHIBA/TARGET_TMPM4G9/reset_reason_api.c | 7 ++++++- 5 files changed, 30 insertions(+), 5 deletions(-) diff --git a/targets/TARGET_TOSHIBA/TARGET_TMPM066/reset_reason_api.c b/targets/TARGET_TOSHIBA/TARGET_TMPM066/reset_reason_api.c index f5bd6230ce6..817a1f489fa 100644 --- a/targets/TARGET_TOSHIBA/TARGET_TMPM066/reset_reason_api.c +++ b/targets/TARGET_TOSHIBA/TARGET_TMPM066/reset_reason_api.c @@ -13,9 +13,12 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -#include #include "reset_reason_api.h" + +#ifdef DEVICE_RESET_REASON + #include "TMPM066.h" +#include #define MAXRSTREASON 6 @@ -121,3 +124,5 @@ static uint8_t bit_pos(uint32_t reg) } } } + +#endif // DEVICE_RESET_REASON diff --git a/targets/TARGET_TOSHIBA/TARGET_TMPM3H6/reset_reason_api.c b/targets/TARGET_TOSHIBA/TARGET_TMPM3H6/reset_reason_api.c index 6531df6458c..d5b50a952b4 100644 --- a/targets/TARGET_TOSHIBA/TARGET_TMPM3H6/reset_reason_api.c +++ b/targets/TARGET_TOSHIBA/TARGET_TMPM3H6/reset_reason_api.c @@ -13,9 +13,12 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -#include #include "reset_reason_api.h" + +#ifdef DEVICE_RESET_REASON + #include "TMPM3H6.h" +#include static uint8_t set_bit_count(uint32_t reg); static uint8_t bit_pos(uint32_t reg); @@ -118,3 +121,5 @@ static uint8_t bit_pos(uint32_t reg) } } } + +#endif // DEVICE_RESET_REASON diff --git a/targets/TARGET_TOSHIBA/TARGET_TMPM3HQ/reset_reason_api.c b/targets/TARGET_TOSHIBA/TARGET_TMPM3HQ/reset_reason_api.c index 5d9c5175d34..f5873ea798b 100644 --- a/targets/TARGET_TOSHIBA/TARGET_TMPM3HQ/reset_reason_api.c +++ b/targets/TARGET_TOSHIBA/TARGET_TMPM3HQ/reset_reason_api.c @@ -13,9 +13,12 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -#include #include "reset_reason_api.h" + +#ifdef DEVICE_RESET_REASON + #include "TMPM3HQ.h" +#include static uint8_t set_bit_count(uint32_t reg); static uint8_t bit_pos(uint32_t reg); @@ -118,3 +121,5 @@ static uint8_t bit_pos(uint32_t reg) } } } + +#endif // DEVICE_RESET_REASON diff --git a/targets/TARGET_TOSHIBA/TARGET_TMPM46B/reset_reason_api.c b/targets/TARGET_TOSHIBA/TARGET_TMPM46B/reset_reason_api.c index af94dc4f55a..1d6546fceb5 100644 --- a/targets/TARGET_TOSHIBA/TARGET_TMPM46B/reset_reason_api.c +++ b/targets/TARGET_TOSHIBA/TARGET_TMPM46B/reset_reason_api.c @@ -13,9 +13,12 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -#include #include "reset_reason_api.h" + +#ifdef DEVICE_RESET_REASON + #include "TMPM46B.h" +#include static uint8_t set_bit_count(uint32_t reg); static uint8_t bit_pos(uint32_t reg); @@ -87,3 +90,5 @@ static uint8_t bit_pos(uint32_t reg) } } } + +#endif // DEVICE_RESET_REASON diff --git a/targets/TARGET_TOSHIBA/TARGET_TMPM4G9/reset_reason_api.c b/targets/TARGET_TOSHIBA/TARGET_TMPM4G9/reset_reason_api.c index e02974aedc7..36a2144ca82 100644 --- a/targets/TARGET_TOSHIBA/TARGET_TMPM4G9/reset_reason_api.c +++ b/targets/TARGET_TOSHIBA/TARGET_TMPM4G9/reset_reason_api.c @@ -13,9 +13,12 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -#include #include "reset_reason_api.h" + +#ifdef DEVICE_RESET_REASON + #include "TMPM4G9.h" +#include static uint8_t set_bit_count(uint32_t reg); static uint8_t bit_pos(uint32_t reg); @@ -121,3 +124,5 @@ static uint8_t bit_pos(uint32_t reg) } } } + +#endif // DEVICE_RESET_REASON