Add Watchdog driver API

pull/10657/head
Steven Cartmell 2017-11-28 14:00:56 +00:00 committed by Filip Jagodzinski
parent 3c18dcb882
commit 8fa38bb25b
6 changed files with 278 additions and 38 deletions

View File

@ -40,7 +40,7 @@ public:
* const reset_reason_t reason = ResetReason::get();
*
* if (reason == RESET_REASON_WATCHDOG) {
* std::cout << "Watchdog reset" << std::endl;
* printf("Watchdog reset\n");
* rollback();
* }
* @endcode

68
drivers/Watchdog.cpp Normal file
View File

@ -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

137
drivers/Watchdog.h Normal file
View File

@ -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 <cstdio>
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

View File

@ -21,10 +21,6 @@
#if DEVICE_WATCHDOG
#if !(DEVICE_RESET_REASON)
#error "Watchdog feature depends on reset reason API also being implemented"
#endif
#include <stdbool.h>
#include <stdint.h>
@ -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.
/** Get information on the current platforms supported watchdog functionality
*
* @return True if last reset was triggered by a watchdog, False if not.
* @return watchdog_feature_t indicating supported watchdog features on the
* current platform
*/
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);
watchdog_features_t hal_watchdog_get_platform_features(void);
/**@}*/

View File

@ -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;
}

View File

@ -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)
watchdog_features_t hal_watchdog_get_max_timeout(void)
{
return (hal_reset_reason_get() == RESET_REASON_WATCHDOG);
}
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;
uint32_t hal_watchdog_get_max_timeout(void)
{
return MAX_TIMEOUT_MS;
return features;
}