From d9ae779a37f5d9efe5f18035f746420dd35306e1 Mon Sep 17 00:00:00 2001 From: Borys Jelenski Date: Sun, 7 Feb 2021 23:21:29 +0100 Subject: [PATCH] [EGD-5503] Add watchdog implementation The system watchdog monitors whether there is message traffic on the Bus. If no message was sent for an extended period of time, a reset will occur. It should also protect against system-wide hangs. On Linux, watchdog is simulated by a FreeRTOS task that will call exit on timeout. --- .../linux/watchdog/software_watchdog.cpp | 59 +++ .../linux/watchdog/software_watchdog.hpp | 28 ++ module-bsp/board/linux/watchdog/watchdog.cpp | 21 +- module-bsp/board/rt1051/bsp/lpm/RT1051LPM.cpp | 3 +- .../board/rt1051/bsp/watchdog/watchdog.cpp | 63 ++- .../rt1051/common/fsl_drivers/fsl_rtwdog.c | 151 +++++++ .../rt1051/common/fsl_drivers/fsl_rtwdog.h | 425 ++++++++++++++++++ .../rt1051/common/startup_mimxrt1052.cpp | 52 +-- .../board/rt1051/common/system_MIMXRT1051.c | 29 +- .../board/rt1051/common/system_MIMXRT1051.h | 7 +- module-bsp/bsp/watchdog/watchdog.hpp | 19 +- module-bsp/bsp/watchdog/watchdog_weak.cpp | 0 module-bsp/targets/Target_Linux.cmake | 2 + module-bsp/targets/Target_RT1051.cmake | 1 + module-sys/CMakeLists.txt | 1 + module-sys/Service/BusProxy.cpp | 17 +- module-sys/Service/BusProxy.hpp | 4 +- module-sys/Service/Service.cpp | 11 +- module-sys/Service/Service.hpp | 31 +- module-sys/Service/Watchdog.hpp | 13 + module-sys/Service/details/bus/Bus.cpp | 1 + module-sys/SystemWatchdog/SystemWatchdog.cpp | 75 ++++ module-sys/SystemWatchdog/SystemWatchdog.hpp | 59 +++ source/main.cpp | 8 + 24 files changed, 944 insertions(+), 136 deletions(-) create mode 100644 module-bsp/board/linux/watchdog/software_watchdog.cpp create mode 100644 module-bsp/board/linux/watchdog/software_watchdog.hpp create mode 100644 module-bsp/board/rt1051/common/fsl_drivers/fsl_rtwdog.c create mode 100644 module-bsp/board/rt1051/common/fsl_drivers/fsl_rtwdog.h delete mode 100644 module-bsp/bsp/watchdog/watchdog_weak.cpp create mode 100644 module-sys/Service/Watchdog.hpp create mode 100644 module-sys/SystemWatchdog/SystemWatchdog.cpp create mode 100644 module-sys/SystemWatchdog/SystemWatchdog.hpp diff --git a/module-bsp/board/linux/watchdog/software_watchdog.cpp b/module-bsp/board/linux/watchdog/software_watchdog.cpp new file mode 100644 index 0000000000000000000000000000000000000000..1c7d083b7f7506bc0691d6e41ec47f4b566fb6d3 --- /dev/null +++ b/module-bsp/board/linux/watchdog/software_watchdog.cpp @@ -0,0 +1,59 @@ +// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved. +// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md + +#include "software_watchdog.hpp" +#include +#include +#include +#include +#include + +namespace bsp::watchdog +{ + using namespace cpp_freertos; + + static constexpr uint16_t stackDepthWords = 256; + + SoftwareWatchdog::SoftwareWatchdog() + : Thread("SW_Watchdog", stackDepthWords, static_cast(sys::ServicePriority::Realtime)) + {} + + bool SoftwareWatchdog::init(TickType_t timeoutPeriodMs) + { +#ifdef DISABLE_WATCHDOG + return true; +#else + timeoutPeriod = pdMS_TO_TICKS(timeoutPeriodMs); + const auto started = Start(); + + if (started) { + refresh(); + } + + return started; +#endif + } + + void SoftwareWatchdog::refresh() + { +#ifndef DISABLE_WATCHDOG + // Critical section not required (atomic 32-bit writes) + lastRefreshTimestamp = Ticks::GetTicks(); +#endif + } + + void SoftwareWatchdog::Run() + { + TickType_t lastTimeoutTimestamp = xTaskGetTickCount(); + + while (true) { + vTaskDelayUntil(&lastTimeoutTimestamp, timeoutPeriod); + + // Critical section not required (atomic 32-bit reads) + if (lastTimeoutTimestamp - lastRefreshTimestamp >= timeoutPeriod) { + LOG_FATAL("!!! Software watchdog timeout, exiting !!!"); + exit(EXIT_FAILURE); + } + } + } +} // namespace bsp::watchdog diff --git a/module-bsp/board/linux/watchdog/software_watchdog.hpp b/module-bsp/board/linux/watchdog/software_watchdog.hpp new file mode 100644 index 0000000000000000000000000000000000000000..593b7e748214d53c41c3a4daf708987454b1656a --- /dev/null +++ b/module-bsp/board/linux/watchdog/software_watchdog.hpp @@ -0,0 +1,28 @@ +// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved. +// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md + +#pragma once + +#include + +namespace bsp::watchdog +{ + class SoftwareWatchdog : private cpp_freertos::Thread + { + public: + SoftwareWatchdog(); + SoftwareWatchdog(const SoftwareWatchdog &) = delete; + SoftwareWatchdog(SoftwareWatchdog &&) = delete; + SoftwareWatchdog &operator=(const SoftwareWatchdog &) = delete; + SoftwareWatchdog &operator=(SoftwareWatchdog &&) = delete; + + bool init(TickType_t timeoutPeriodMs); + void refresh(); + + private: + void Run() final; + + TickType_t timeoutPeriod = 0; + TickType_t lastRefreshTimestamp = 0; + }; +} // namespace bsp::watchdog diff --git a/module-bsp/board/linux/watchdog/watchdog.cpp b/module-bsp/board/linux/watchdog/watchdog.cpp index 6e1716436f7a5aa9e6f489a1fcfcdb37c0e6ec04..e46fc8ce0f3088f1ad00f9fc810d3354d865be3e 100644 --- a/module-bsp/board/linux/watchdog/watchdog.cpp +++ b/module-bsp/board/linux/watchdog/watchdog.cpp @@ -1,18 +1,21 @@ -// Copyright (c) 2017-2020, Mudita Sp. z.o.o. All rights reserved. +// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved. // For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md +#include "bsp/watchdog/watchdog.hpp" +#include "software_watchdog.hpp" #include namespace bsp::watchdog { - __attribute__((weak)) void init() - {} - __attribute__((weak)) void system_reset() - {} - __attribute__((weak)) void pet() - {} - __attribute__((weak)) std::string reset_cause() + static SoftwareWatchdog swWatchdog; + + bool init(unsigned int timeoutMs) + { + return swWatchdog.init(static_cast(timeoutMs)); + } + + void refresh() { - return {}; + swWatchdog.refresh(); } } // namespace bsp::watchdog diff --git a/module-bsp/board/rt1051/bsp/lpm/RT1051LPM.cpp b/module-bsp/board/rt1051/bsp/lpm/RT1051LPM.cpp index ec1389103d4339a7fdf10cfe3079c56ec9d710cf..7909cede1e3f027a4348629ac099695d285b4245 100644 --- a/module-bsp/board/rt1051/bsp/lpm/RT1051LPM.cpp +++ b/module-bsp/board/rt1051/bsp/lpm/RT1051LPM.cpp @@ -40,8 +40,7 @@ namespace bsp int32_t RT1051LPM::Reboot() { - bsp::watchdog::init(); - bsp::watchdog::system_reset(); + NVIC_SystemReset(); return 0; } diff --git a/module-bsp/board/rt1051/bsp/watchdog/watchdog.cpp b/module-bsp/board/rt1051/bsp/watchdog/watchdog.cpp index 5928645709d37d86c0827b277dad79e3539354f5..bb672afa237fee96adc9801cd787aa9dab5f53d8 100644 --- a/module-bsp/board/rt1051/bsp/watchdog/watchdog.cpp +++ b/module-bsp/board/rt1051/bsp/watchdog/watchdog.cpp @@ -1,50 +1,45 @@ -// Copyright (c) 2017-2020, Mudita Sp. z.o.o. All rights reserved. +// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved. // For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md #include "bsp/watchdog/watchdog.hpp" extern "C" { -#include "../../common/fsl_drivers/fsl_wdog.h" +#include "fsl_rtwdog.h" } -#include - -#define WDOG_1_BASE WDOG1 -#define DEMO_WDOG_IRQHandler RTWDOG +#include namespace bsp::watchdog { - void init() - { - wdog_config_t config; - WDOG_GetDefaultConfig(&config); - config.timeoutValue = 0xFF; /* Timeout value is (0xFF + 1)/2 = 125 sec. */ - WDOG_Init(WDOG_1_BASE, &config); - LOG_INFO("wdog init done-"); - } - void system_reset() + bool init(unsigned int timeoutMs) { - LOG_DEBUG("request system reset to watchdog"); - WDOG_TriggerSystemSoftwareReset(WDOG_1_BASE); - } + // 32.768kHz source clock divided by 256 prescaler + static constexpr unsigned int clockFreqHz = 32768 / 256; - void pet() - { - WDOG_Refresh(WDOG_1_BASE); + const unsigned int timeoutValueTicks = timeoutMs * clockFreqHz / 1000; + if (timeoutValueTicks > std::numeric_limits::max()) { + return false; + } + + rtwdog_config_t config = {0}; + config.enableRtwdog = true; + config.clockSource = kRTWDOG_ClockSource1; // LPO_CLK clock (32.768kHz) + config.prescaler = kRTWDOG_ClockPrescalerDivide256; // 256 prescaler (effectively 128Hz clock) + config.workMode.enableWait = false; + config.workMode.enableStop = false; + config.workMode.enableDebug = false; // If true, RTWDOG will run when target is halted + config.testMode = kRTWDOG_TestModeDisabled; + config.enableUpdate = true; + config.enableInterrupt = false; + config.enableWindowMode = false; + config.windowValue = 0; + config.timeoutValue = static_cast(timeoutValueTicks); + RTWDOG_Init(RTWDOG, &config); + + return true; } - // taken straight from example wdog.c in NXP mcuxpresso - std::string reset_cause() + void refresh() { - auto resetFlag = WDOG_GetStatusFlags(WDOG_1_BASE); - switch (resetFlag & (kWDOG_PowerOnResetFlag | kWDOG_TimeoutResetFlag | kWDOG_SoftwareResetFlag)) { - case kWDOG_PowerOnResetFlag: - return ("Power On Reset"); - case kWDOG_TimeoutResetFlag: - return ("Time Out Reset!"); - case kWDOG_SoftwareResetFlag: - return ("Software Reset!"); - default: - return ("Error status!"); - } + RTWDOG_Refresh(RTWDOG); } } // namespace bsp::watchdog diff --git a/module-bsp/board/rt1051/common/fsl_drivers/fsl_rtwdog.c b/module-bsp/board/rt1051/common/fsl_drivers/fsl_rtwdog.c new file mode 100644 index 0000000000000000000000000000000000000000..deb870d69d0170b92b85b37d5fceac6dba22fecf --- /dev/null +++ b/module-bsp/board/rt1051/common/fsl_drivers/fsl_rtwdog.c @@ -0,0 +1,151 @@ +// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved. +// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md + +/* + * Copyright (c) 2016, Freescale Semiconductor, Inc. + * Copyright 2016-2019 NXP + * All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include "fsl_rtwdog.h" + +/* Component ID definition, used by tools. */ +#ifndef FSL_COMPONENT_ID +#define FSL_COMPONENT_ID "platform.drivers.rtwdog" +#endif + +/******************************************************************************* + * Code + ******************************************************************************/ + +/*! + * brief Clears the RTWDOG flag. + * + * This function clears the RTWDOG status flag. + * + * Example to clear an interrupt flag: + * code + * RTWDOG_ClearStatusFlags(wdog_base,kRTWDOG_InterruptFlag); + * endcode + * param base RTWDOG peripheral base address. + * param mask The status flags to clear. + * The parameter can be any combination of the following values: + * arg kRTWDOG_InterruptFlag + */ +void RTWDOG_ClearStatusFlags(RTWDOG_Type *base, uint32_t mask) +{ + if ((mask & (uint32_t)kRTWDOG_InterruptFlag) != 0U) + { + base->CS |= RTWDOG_CS_FLG_MASK; + } +} + +/*! + * brief Initializes the RTWDOG configuration structure. + * + * This function initializes the RTWDOG configuration structure to default values. The default + * values are: + * code + * rtwdogConfig->enableRtwdog = true; + * rtwdogConfig->clockSource = kRTWDOG_ClockSource1; + * rtwdogConfig->prescaler = kRTWDOG_ClockPrescalerDivide1; + * rtwdogConfig->workMode.enableWait = true; + * rtwdogConfig->workMode.enableStop = false; + * rtwdogConfig->workMode.enableDebug = false; + * rtwdogConfig->testMode = kRTWDOG_TestModeDisabled; + * rtwdogConfig->enableUpdate = true; + * rtwdogConfig->enableInterrupt = false; + * rtwdogConfig->enableWindowMode = false; + * rtwdogConfig->windowValue = 0U; + * rtwdogConfig->timeoutValue = 0xFFFFU; + * endcode + * + * param config Pointer to the RTWDOG configuration structure. + * see rtwdog_config_t + */ +void RTWDOG_GetDefaultConfig(rtwdog_config_t *config) +{ + assert(config != NULL); + + /* Initializes the configure structure to zero. */ + (void)memset(config, 0, sizeof(*config)); + + config->enableRtwdog = true; + config->clockSource = kRTWDOG_ClockSource1; + config->prescaler = kRTWDOG_ClockPrescalerDivide1; + config->workMode.enableWait = true; + config->workMode.enableStop = false; + config->workMode.enableDebug = false; + config->testMode = kRTWDOG_TestModeDisabled; + config->enableUpdate = true; + config->enableInterrupt = false; + config->enableWindowMode = false; + config->windowValue = 0U; + config->timeoutValue = 0xFFFFU; +} + +/*! + * brief Initializes the RTWDOG module. + * + * This function initializes the RTWDOG. + * To reconfigure the RTWDOG without forcing a reset first, enableUpdate must be set to true + * in the configuration. + * + * Example: + * code + * rtwdog_config_t config; + * RTWDOG_GetDefaultConfig(&config); + * config.timeoutValue = 0x7ffU; + * config.enableUpdate = true; + * RTWDOG_Init(wdog_base,&config); + * endcode + * + * param base RTWDOG peripheral base address. + * param config The configuration of the RTWDOG. + */ +void RTWDOG_Init(RTWDOG_Type *base, const rtwdog_config_t *config) +{ + assert(NULL != config); + + uint32_t value = 0U; + uint32_t primaskValue = 0U; + + value = RTWDOG_CS_EN(config->enableRtwdog) | RTWDOG_CS_CLK(config->clockSource) | + RTWDOG_CS_INT(config->enableInterrupt) | RTWDOG_CS_WIN(config->enableWindowMode) | + RTWDOG_CS_UPDATE(config->enableUpdate) | RTWDOG_CS_DBG(config->workMode.enableDebug) | + RTWDOG_CS_STOP(config->workMode.enableStop) | RTWDOG_CS_WAIT(config->workMode.enableWait) | + RTWDOG_CS_PRES(config->prescaler) | RTWDOG_CS_CMD32EN(1U) | RTWDOG_CS_TST(config->testMode); + + /* Disable the global interrupts. Otherwise, an interrupt could effectively invalidate the unlock sequence + * and the WCT may expire. After the configuration finishes, re-enable the global interrupts. */ + primaskValue = DisableGlobalIRQ(); + RTWDOG_Unlock(base); + base->WIN = config->windowValue; + base->TOVAL = config->timeoutValue; + base->CS = value; + while ((base->CS & RTWDOG_CS_RCS_MASK) == 0U) + { + } + EnableGlobalIRQ(primaskValue); +} + +/*! + * brief De-initializes the RTWDOG module. + * + * This function shuts down the RTWDOG. + * Ensure that the WDOG_CS.UPDATE is 1, which means that the register update is enabled. + * + * param base RTWDOG peripheral base address. + */ +void RTWDOG_Deinit(RTWDOG_Type *base) +{ + uint32_t primaskValue = 0U; + + /* Disable the global interrupts */ + primaskValue = DisableGlobalIRQ(); + RTWDOG_Unlock(base); + RTWDOG_Disable(base); + EnableGlobalIRQ(primaskValue); +} diff --git a/module-bsp/board/rt1051/common/fsl_drivers/fsl_rtwdog.h b/module-bsp/board/rt1051/common/fsl_drivers/fsl_rtwdog.h new file mode 100644 index 0000000000000000000000000000000000000000..5eecb5a23b72f15316f917d17afd6eded4f20b3d --- /dev/null +++ b/module-bsp/board/rt1051/common/fsl_drivers/fsl_rtwdog.h @@ -0,0 +1,425 @@ +/* + * Copyright (c) 2016, Freescale Semiconductor, Inc. + * Copyright 2016-2020 NXP + * All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ +#ifndef _FSL_RTWDOG_H_ +#define _FSL_RTWDOG_H_ + +#include "fsl_common.h" + +/*! + * @addtogroup rtwdog + * @{ + */ + +/******************************************************************************* + * Definitions + *******************************************************************************/ +/*! @name Unlock sequence */ +/*@{*/ +#define WDOG_FIRST_WORD_OF_UNLOCK (RTWDOG_UPDATE_KEY & 0xFFFFU) /*!< First word of unlock sequence */ +#define WDOG_SECOND_WORD_OF_UNLOCK ((RTWDOG_UPDATE_KEY >> 16U) & 0xFFFFU) /*!< Second word of unlock sequence */ +/*@}*/ + +/*! @name Refresh sequence */ +/*@{*/ +#define WDOG_FIRST_WORD_OF_REFRESH (RTWDOG_REFRESH_KEY & 0xFFFFU) /*!< First word of refresh sequence */ +#define WDOG_SECOND_WORD_OF_REFRESH ((RTWDOG_REFRESH_KEY >> 16U) & 0xFFFFU) /*!< Second word of refresh sequence */ +/*@}*/ +/*! @name Driver version */ +/*@{*/ +/*! @brief RTWDOG driver version 2.1.2. */ +#define FSL_RTWDOG_DRIVER_VERSION (MAKE_VERSION(2, 1, 2)) +/*@}*/ + +/*! @brief Describes RTWDOG clock source. */ +typedef enum _rtwdog_clock_source +{ + kRTWDOG_ClockSource0 = 0U, /*!< Clock source 0 */ + kRTWDOG_ClockSource1 = 1U, /*!< Clock source 1 */ + kRTWDOG_ClockSource2 = 2U, /*!< Clock source 2 */ + kRTWDOG_ClockSource3 = 3U, /*!< Clock source 3 */ +} rtwdog_clock_source_t; + +/*! @brief Describes the selection of the clock prescaler. */ +typedef enum _rtwdog_clock_prescaler +{ + kRTWDOG_ClockPrescalerDivide1 = 0x0U, /*!< Divided by 1 */ + kRTWDOG_ClockPrescalerDivide256 = 0x1U, /*!< Divided by 256 */ +} rtwdog_clock_prescaler_t; + +/*! @brief Defines RTWDOG work mode. */ +typedef struct _rtwdog_work_mode +{ + bool enableWait; /*!< Enables or disables RTWDOG in wait mode */ + bool enableStop; /*!< Enables or disables RTWDOG in stop mode */ + bool enableDebug; /*!< Enables or disables RTWDOG in debug mode */ +} rtwdog_work_mode_t; + +/*! @brief Describes RTWDOG test mode. */ +typedef enum _rtwdog_test_mode +{ + kRTWDOG_TestModeDisabled = 0U, /*!< Test Mode disabled */ + kRTWDOG_UserModeEnabled = 1U, /*!< User Mode enabled */ + kRTWDOG_LowByteTest = 2U, /*!< Test Mode enabled, only low byte is used */ + kRTWDOG_HighByteTest = 3U, /*!< Test Mode enabled, only high byte is used */ +} rtwdog_test_mode_t; + +/*! @brief Describes RTWDOG configuration structure. */ +typedef struct _rtwdog_config +{ + bool enableRtwdog; /*!< Enables or disables RTWDOG */ + rtwdog_clock_source_t clockSource; /*!< Clock source select */ + rtwdog_clock_prescaler_t prescaler; /*!< Clock prescaler value */ + rtwdog_work_mode_t workMode; /*!< Configures RTWDOG work mode in debug stop and wait mode */ + rtwdog_test_mode_t testMode; /*!< Configures RTWDOG test mode */ + bool enableUpdate; /*!< Update write-once register enable */ + bool enableInterrupt; /*!< Enables or disables RTWDOG interrupt */ + bool enableWindowMode; /*!< Enables or disables RTWDOG window mode */ + uint16_t windowValue; /*!< Window value */ + uint16_t timeoutValue; /*!< Timeout value */ +} rtwdog_config_t; + +/*! + * @brief RTWDOG interrupt configuration structure. + * + * This structure contains the settings for all of the RTWDOG interrupt configurations. + */ +enum _rtwdog_interrupt_enable_t +{ + kRTWDOG_InterruptEnable = RTWDOG_CS_INT_MASK, /*!< Interrupt is generated before forcing a reset */ +}; + +/*! + * @brief RTWDOG status flags. + * + * This structure contains the RTWDOG status flags for use in the RTWDOG functions. + */ +enum _rtwdog_status_flags_t +{ + kRTWDOG_RunningFlag = RTWDOG_CS_EN_MASK, /*!< Running flag, set when RTWDOG is enabled */ + kRTWDOG_InterruptFlag = RTWDOG_CS_FLG_MASK, /*!< Interrupt flag, set when interrupt occurs */ +}; + +/******************************************************************************* + * API + *******************************************************************************/ + +#if defined(__cplusplus) +extern "C" { +#endif /* __cplusplus */ + +/*! + * @name RTWDOG Initialization and De-initialization + * @{ + */ + +/*! + * @brief Initializes the RTWDOG configuration structure. + * + * This function initializes the RTWDOG configuration structure to default values. The default + * values are: + * @code + * rtwdogConfig->enableRtwdog = true; + * rtwdogConfig->clockSource = kRTWDOG_ClockSource1; + * rtwdogConfig->prescaler = kRTWDOG_ClockPrescalerDivide1; + * rtwdogConfig->workMode.enableWait = true; + * rtwdogConfig->workMode.enableStop = false; + * rtwdogConfig->workMode.enableDebug = false; + * rtwdogConfig->testMode = kRTWDOG_TestModeDisabled; + * rtwdogConfig->enableUpdate = true; + * rtwdogConfig->enableInterrupt = false; + * rtwdogConfig->enableWindowMode = false; + * rtwdogConfig->windowValue = 0U; + * rtwdogConfig->timeoutValue = 0xFFFFU; + * @endcode + * + * @param config Pointer to the RTWDOG configuration structure. + * @see rtwdog_config_t + */ +void RTWDOG_GetDefaultConfig(rtwdog_config_t *config); + +/*! + * @brief Initializes the RTWDOG module. + * + * This function initializes the RTWDOG. + * To reconfigure the RTWDOG without forcing a reset first, enableUpdate must be set to true + * in the configuration. + * + * Example: + * @code + * rtwdog_config_t config; + * RTWDOG_GetDefaultConfig(&config); + * config.timeoutValue = 0x7ffU; + * config.enableUpdate = true; + * RTWDOG_Init(wdog_base,&config); + * @endcode + * + * @param base RTWDOG peripheral base address. + * @param config The configuration of the RTWDOG. + */ + +#if defined(DOXYGEN_OUTPUT) && DOXYGEN_OUTPUT +void RTWDOG_Init(RTWDOG_Type *base, const rtwdog_config_t *config); +#else +AT_QUICKACCESS_SECTION_CODE(void RTWDOG_Init(RTWDOG_Type *base, const rtwdog_config_t *config)); +#endif + +/*! + * @brief De-initializes the RTWDOG module. + * + * This function shuts down the RTWDOG. + * Ensure that the WDOG_CS.UPDATE is 1, which means that the register update is enabled. + * + * @param base RTWDOG peripheral base address. + */ +void RTWDOG_Deinit(RTWDOG_Type *base); + +/* @} */ + +/*! + * @name RTWDOG functional Operation + * @{ + */ + +/*! + * @brief Enables the RTWDOG module. + * + * This function writes a value into the WDOG_CS register to enable the RTWDOG. + * The WDOG_CS register is a write-once register. Ensure that the WCT window is still open and + * this register has not been written in this WCT while the function is called. + * + * @param base RTWDOG peripheral base address. + */ +static inline void RTWDOG_Enable(RTWDOG_Type *base) +{ + base->CS |= RTWDOG_CS_EN_MASK; +} + +/*! + * @brief Disables the RTWDOG module. + * + * This function writes a value into the WDOG_CS register to disable the RTWDOG. + * The WDOG_CS register is a write-once register. Ensure that the WCT window is still open and + * this register has not been written in this WCT while the function is called. + * + * @param base RTWDOG peripheral base address + */ +static inline void RTWDOG_Disable(RTWDOG_Type *base) +{ + base->CS &= ~RTWDOG_CS_EN_MASK; +} + +/*! + * @brief Enables the RTWDOG interrupt. + * + * This function writes a value into the WDOG_CS register to enable the RTWDOG interrupt. + * The WDOG_CS register is a write-once register. Ensure that the WCT window is still open and + * this register has not been written in this WCT while the function is called. + * + * @param base RTWDOG peripheral base address. + * @param mask The interrupts to enable. + * The parameter can be a combination of the following source if defined: + * @arg kRTWDOG_InterruptEnable + */ +static inline void RTWDOG_EnableInterrupts(RTWDOG_Type *base, uint32_t mask) +{ + base->CS |= mask; +} + +/*! + * @brief Disables the RTWDOG interrupt. + * + * This function writes a value into the WDOG_CS register to disable the RTWDOG interrupt. + * The WDOG_CS register is a write-once register. Ensure that the WCT window is still open and + * this register has not been written in this WCT while the function is called. + * + * @param base RTWDOG peripheral base address. + * @param mask The interrupts to disabled. + * The parameter can be a combination of the following source if defined: + * @arg kRTWDOG_InterruptEnable + */ +static inline void RTWDOG_DisableInterrupts(RTWDOG_Type *base, uint32_t mask) +{ + base->CS &= ~mask; +} + +/*! + * @brief Gets the RTWDOG all status flags. + * + * This function gets all status flags. + * + * Example to get the running flag: + * @code + * uint32_t status; + * status = RTWDOG_GetStatusFlags(wdog_base) & kRTWDOG_RunningFlag; + * @endcode + * @param base RTWDOG peripheral base address + * @return State of the status flag: asserted (true) or not-asserted (false). @see _rtwdog_status_flags_t + * - true: related status flag has been set. + * - false: related status flag is not set. + */ +static inline uint32_t RTWDOG_GetStatusFlags(RTWDOG_Type *base) +{ + return (base->CS & (RTWDOG_CS_EN_MASK | RTWDOG_CS_FLG_MASK)); +} + +/*! + * @brief Enables/disables the window mode. + * + * @param base RTWDOG peripheral base address. + * @param enable Enables(true) or disables(false) the feature. + */ +static inline void RTWDOG_EnableWindowMode(RTWDOG_Type *base, bool enable) +{ + if (enable) + { + base->CS |= RTWDOG_CS_WIN_MASK; + } + else + { + base->CS &= ~RTWDOG_CS_WIN_MASK; + } +} + +/*! + * @brief Converts raw count value to millisecond. + * + * Note that if the clock frequency is too high the timeout period can be less than 1 ms. + * In this case this api will return 0 value. + * + * @param base RTWDOG peripheral base address. + * @param count Raw count value. + * @param clockFreqInHz The frequency of the clock source RTWDOG uses. + */ +static inline uint32_t RTWDOG_CountToMesec(RTWDOG_Type *base, uint32_t count, uint32_t clockFreqInHz) +{ + if ((base->CS & RTWDOG_CS_PRES_MASK) != 0U) + { + clockFreqInHz /= 256U; + } + return count * 1000U / clockFreqInHz; +} + +/*! + * @brief Clears the RTWDOG flag. + * + * This function clears the RTWDOG status flag. + * + * Example to clear an interrupt flag: + * @code + * RTWDOG_ClearStatusFlags(wdog_base,kRTWDOG_InterruptFlag); + * @endcode + * @param base RTWDOG peripheral base address. + * @param mask The status flags to clear. + * The parameter can be any combination of the following values: + * @arg kRTWDOG_InterruptFlag + */ +void RTWDOG_ClearStatusFlags(RTWDOG_Type *base, uint32_t mask); + +/*! + * @brief Sets the RTWDOG timeout value. + * + * This function writes a timeout value into the WDOG_TOVAL register. + * The WDOG_TOVAL register is a write-once register. Ensure that the WCT window is still open and + * this register has not been written in this WCT while the function is called. + * + * @param base RTWDOG peripheral base address + * @param timeoutCount RTWDOG timeout value, count of RTWDOG clock ticks. + */ +static inline void RTWDOG_SetTimeoutValue(RTWDOG_Type *base, uint16_t timeoutCount) +{ + base->TOVAL = timeoutCount; +} + +/*! + * @brief Sets the RTWDOG window value. + * + * This function writes a window value into the WDOG_WIN register. + * The WDOG_WIN register is a write-once register. Ensure that the WCT window is still open and + * this register has not been written in this WCT while the function is called. + * + * @param base RTWDOG peripheral base address. + * @param windowValue RTWDOG window value. + */ +static inline void RTWDOG_SetWindowValue(RTWDOG_Type *base, uint16_t windowValue) +{ + base->WIN = windowValue; +} + +/*! + * @brief Unlocks the RTWDOG register written. + * + * This function unlocks the RTWDOG register written. + * + * Before starting the unlock sequence and following the configuration, disable the global interrupts. + * Otherwise, an interrupt could effectively invalidate the unlock sequence and the WCT may expire. + * After the configuration finishes, re-enable the global interrupts. + * + * @param base RTWDOG peripheral base address + */ +__STATIC_FORCEINLINE void RTWDOG_Unlock(RTWDOG_Type *base) +{ + if (((base->CS) & RTWDOG_CS_CMD32EN_MASK) != 0U) + { + base->CNT = RTWDOG_UPDATE_KEY; + } + else + { + base->CNT = WDOG_FIRST_WORD_OF_UNLOCK; + base->CNT = WDOG_SECOND_WORD_OF_UNLOCK; + } + while ((base->CS & RTWDOG_CS_ULK_MASK) == 0U) + { + } +} + +/*! + * @brief Refreshes the RTWDOG timer. + * + * This function feeds the RTWDOG. + * This function should be called before the Watchdog timer is in timeout. Otherwise, a reset is asserted. + * + * @param base RTWDOG peripheral base address + */ +static inline void RTWDOG_Refresh(RTWDOG_Type *base) +{ + uint32_t primaskValue = 0U; + primaskValue = DisableGlobalIRQ(); + if (((base->CS) & RTWDOG_CS_CMD32EN_MASK) != 0U) + { + base->CNT = RTWDOG_REFRESH_KEY; + } + else + { + base->CNT = WDOG_FIRST_WORD_OF_REFRESH; + base->CNT = WDOG_SECOND_WORD_OF_REFRESH; + } + EnableGlobalIRQ(primaskValue); +} + +/*! + * @brief Gets the RTWDOG counter value. + * + * This function gets the RTWDOG counter value. + * + * @param base RTWDOG peripheral base address. + * @return Current RTWDOG counter value. + */ +static inline uint16_t RTWDOG_GetCounterValue(RTWDOG_Type *base) +{ + return (uint16_t)base->CNT; +} + +/*@}*/ + +#if defined(__cplusplus) +} +#endif /* __cplusplus */ + +/*! @}*/ + +#endif /* _FSL_RTWDOG_H_ */ diff --git a/module-bsp/board/rt1051/common/startup_mimxrt1052.cpp b/module-bsp/board/rt1051/common/startup_mimxrt1052.cpp index 46bba6098fa25bf0d6d7a7a5a4e15cd53b202be5..5c7b0d95452dbc22e6e97f2ff1a2cbc9b0fabb0a 100644 --- a/module-bsp/board/rt1051/common/startup_mimxrt1052.cpp +++ b/module-bsp/board/rt1051/common/startup_mimxrt1052.cpp @@ -1,6 +1,3 @@ -// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved. -// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md - //***************************************************************************** // MIMXRT1052 startup code for use with MCUXpresso IDE // @@ -72,17 +69,15 @@ extern "C" { #endif -//***************************************************************************** -// Variable to store CRP value in. Will be placed automatically -// by the linker when "Enable Code Read Protect" selected. -// See crp.h header for more information -//***************************************************************************** -//***************************************************************************** -// Declaration of external SystemInit function -//***************************************************************************** -#if defined(__USE_CMSIS) + //***************************************************************************** + // Variable to store CRP value in. Will be placed automatically + // by the linker when "Enable Code Read Protect" selected. + // See crp.h header for more information + //***************************************************************************** + //***************************************************************************** + // Declaration of external SystemInit function + //***************************************************************************** extern void SystemInit(void); -#endif // (__USE_CMSIS) //***************************************************************************** // Forward declaration of the core exception handlers. @@ -703,24 +698,7 @@ __attribute__((section(".after_vectors.reset"))) void ResetISR(void) // Disable interrupts __asm volatile("cpsid i"); -#if defined(__USE_CMSIS) - // If __USE_CMSIS defined, then call CMSIS SystemInit code SystemInit(); -#else - // Disable Watchdog - volatile unsigned int *WDOG1_WCR = (unsigned int *)0x400B8000; - *WDOG1_WCR = *WDOG1_WCR & ~(1 << 2); - volatile unsigned int *WDOG2_WCR = (unsigned int *)0x400D0000; - *WDOG2_WCR = *WDOG2_WCR & ~(1 << 2); - // Write watchdog update key to unlock - *((volatile unsigned int *)0x400BC004) = 0xD928C520; - // Set timeout value - *((volatile unsigned int *)0x400BC008) = 0xFFFF; - // Now disable watchdog via control register - volatile unsigned int *RTWDOG_CS = (unsigned int *)0x400BC000; - *RTWDOG_CS = (*RTWDOG_CS & ~(1 << 7)) | (1 << 5); - -#endif // (__USE_CMSIS) unsigned int LoadAddr, ExeAddr, SectionLen; unsigned int *SectionTableAddr; @@ -747,20 +725,6 @@ __attribute__((section(".after_vectors.reset"))) void ResetISR(void) bss_init(ExeAddr, SectionLen); } -#if !defined(__USE_CMSIS) - // Assume that if __USE_CMSIS defined, then CMSIS SystemInit code - // will setup the VTOR register - - // Check to see if we are running the code from a non-zero - // address (eg RAM, external flash), in which case we need - // to modify the VTOR register to tell the CPU that the - // vector table is located at a non-0x0 address. - unsigned int *pSCB_VTOR = (unsigned int *)0xE000ED08; - if ((unsigned int *)g_pfnVectors != (unsigned int *)0x00000000) { - *pSCB_VTOR = (unsigned int)g_pfnVectors; - } -#endif // (__USE_CMSIS) - #if defined(__cplusplus) // // Call C++ library initialisation diff --git a/module-bsp/board/rt1051/common/system_MIMXRT1051.c b/module-bsp/board/rt1051/common/system_MIMXRT1051.c index d469490a24b1ddb8f52c2f88a88f5177124a1da1..f463ecd86bf0968914b0c8ef68aed2cc983f1eec 100644 --- a/module-bsp/board/rt1051/common/system_MIMXRT1051.c +++ b/module-bsp/board/rt1051/common/system_MIMXRT1051.c @@ -1,3 +1,6 @@ +// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved. +// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md + /* ** ################################################################### ** Processors: MIMXRT1051CVJ5B @@ -96,23 +99,35 @@ void SystemInit(void) extern uint32_t g_pfnVectors[]; // Vector table defined in startup code SCB->VTOR = (uint32_t)g_pfnVectors; - /* Disable Watchdog Power Down Counter */ + // Disable WDOGx Power Down Counter WDOG1->WMCR &= ~WDOG_WMCR_PDE_MASK; WDOG2->WMCR &= ~WDOG_WMCR_PDE_MASK; - /* Watchdog disable */ - -#if (DISABLE_WDOG) + // Disable WDOGx watchdogs timers if (WDOG1->WCR & WDOG_WCR_WDE_MASK) { WDOG1->WCR &= ~WDOG_WCR_WDE_MASK; } if (WDOG2->WCR & WDOG_WCR_WDE_MASK) { WDOG2->WCR &= ~WDOG_WCR_WDE_MASK; } - RTWDOG->CNT = 0xD928C520U; /* 0xD928C520U is the update key */ + +#if defined(DISABLE_WATCHDOG) + // Write watchdog update key to unlock + RTWDOG->CNT = 0xD928C520U; + // Disable RTWDOG and allow configuration updates RTWDOG->TOVAL = 0xFFFF; - RTWDOG->CS = (uint32_t)((RTWDOG->CS) & ~RTWDOG_CS_EN_MASK) | RTWDOG_CS_UPDATE_MASK; -#endif /* (DISABLE_WDOG) */ + RTWDOG->CS = (uint32_t)(((RTWDOG->CS) & ~RTWDOG_CS_EN_MASK) | RTWDOG_CS_UPDATE_MASK); +#else + // + // Perform preliminary RTWDOG configuration + // + // Write RTWDOG update key to unlock + RTWDOG->CNT = 0xD928C520U; + // Set timeout value (16s, assuming 128Hz clock - 32.768kHz after 256 prescaler) + RTWDOG->TOVAL = 2048; + // Enable RTWDOG, set 256 clock prescaler and allow configuration updates + RTWDOG->CS = (uint32_t)((RTWDOG->CS) | RTWDOG_CS_EN_MASK | RTWDOG_CS_UPDATE_MASK | RTWDOG_CS_PRES_MASK); +#endif // (DISABLE_WATCHDOG) /* Disable Systick which might be enabled by bootrom */ if (SysTick->CTRL & SysTick_CTRL_ENABLE_Msk) { diff --git a/module-bsp/board/rt1051/common/system_MIMXRT1051.h b/module-bsp/board/rt1051/common/system_MIMXRT1051.h index fdedd9e87190d000f44122a1cdb7049c31d5f982..778301afb1ba3efe86eab983fdb66bffe0d4a4fc 100644 --- a/module-bsp/board/rt1051/common/system_MIMXRT1051.h +++ b/module-bsp/board/rt1051/common/system_MIMXRT1051.h @@ -1,3 +1,6 @@ +// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved. +// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md + /* ** ################################################################### ** Processors: MIMXRT1051CVJ5B @@ -84,10 +87,6 @@ extern "C" #include -#ifndef DISABLE_WDOG -#define DISABLE_WDOG 1 -#endif - /* Define clock source values */ #define CPU_XTAL_CLK_HZ 24000000UL /* Value of the external crystal or oscillator clock frequency in Hz */ diff --git a/module-bsp/bsp/watchdog/watchdog.hpp b/module-bsp/bsp/watchdog/watchdog.hpp index c3bff38ee55a38e3ade56abc6dbb6a0a0cf43366..df4d62cf25e1efdb4fd8ad8cf00c3a2e6f668ae6 100644 --- a/module-bsp/bsp/watchdog/watchdog.hpp +++ b/module-bsp/bsp/watchdog/watchdog.hpp @@ -1,19 +1,10 @@ -#pragma once +// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved. +// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md -#include +#pragma once namespace bsp::watchdog { - /// initializes and starts watchdog - /// - for linux - does nothing - /// - for rt1051 debug - initializes with maximum value (125 sec) - /// - for rt1051 release - initializes with maximum value (125 sec) - void init(); - /// resets system - /// - for linux - does nothing - consider just exit(0) - void system_reset(); - /// update watchdog, so that it won't kick us - void pet(); - /// get watchdog reset cause - std::string reset_cause(); + bool init(unsigned int timeoutMs); + void refresh(); } diff --git a/module-bsp/bsp/watchdog/watchdog_weak.cpp b/module-bsp/bsp/watchdog/watchdog_weak.cpp deleted file mode 100644 index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..0000000000000000000000000000000000000000 diff --git a/module-bsp/targets/Target_Linux.cmake b/module-bsp/targets/Target_Linux.cmake index 3061ec84181aea325d3605c3be95bf7e26d26d86..1bf9e40bfe288ad6caa4893e50557622fe5d9b0a 100644 --- a/module-bsp/targets/Target_Linux.cmake +++ b/module-bsp/targets/Target_Linux.cmake @@ -30,6 +30,8 @@ set(BOARD_SOURCES "${CMAKE_CURRENT_SOURCE_DIR}/board/linux/light_sensor/light_sensor.cpp" + "${CMAKE_CURRENT_SOURCE_DIR}/board/linux/watchdog/software_watchdog.cpp" + "${CMAKE_CURRENT_SOURCE_DIR}/board/linux/watchdog/watchdog.cpp" CACHE INTERNAL "") diff --git a/module-bsp/targets/Target_RT1051.cmake b/module-bsp/targets/Target_RT1051.cmake index e9b73aaf285f39d2c04324a63865b9abac4f9a95..1b65e27b8a787d19a9f439db5e7d49b06176a918 100644 --- a/module-bsp/targets/Target_RT1051.cmake +++ b/module-bsp/targets/Target_RT1051.cmake @@ -32,6 +32,7 @@ set(BOARD_SOURCES ${BOARD_SOURCES} "${CMAKE_CURRENT_SOURCE_DIR}/board/rt1051/common/fsl_drivers/fsl_dmamux.c" "${CMAKE_CURRENT_SOURCE_DIR}/board/rt1051/common/fsl_drivers/fsl_edma.c" "${CMAKE_CURRENT_SOURCE_DIR}/board/rt1051/common/fsl_drivers/fsl_wdog.c" + "${CMAKE_CURRENT_SOURCE_DIR}/board/rt1051/common/fsl_drivers/fsl_rtwdog.c" "${CMAKE_CURRENT_SOURCE_DIR}/board/rt1051/common/fsl_drivers/fsl_pwm.c" "${CMAKE_CURRENT_SOURCE_DIR}/board/rt1051/common/irq/irq_gpio.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/board/rt1051/common/audio.cpp" diff --git a/module-sys/CMakeLists.txt b/module-sys/CMakeLists.txt index 88fbed922c8df52ed41781c5216c0950d8241928..24a48528ae9544f1d8393754ba4e559ab79bb046 100644 --- a/module-sys/CMakeLists.txt +++ b/module-sys/CMakeLists.txt @@ -23,6 +23,7 @@ set(SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/SystemManager/DeviceManager.cpp ${CMAKE_CURRENT_SOURCE_DIR}/SystemManager/CpuGovernor.cpp ${CMAKE_CURRENT_SOURCE_DIR}/SystemManager/graph/TopologicalSort.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/SystemWatchdog/SystemWatchdog.cpp ) diff --git a/module-sys/Service/BusProxy.cpp b/module-sys/Service/BusProxy.cpp index acef9cbba2bd9634b634aa6df2d173c7d387590e..0a4e8221e198deb47ca4fbc3f03c25e72615f696 100644 --- a/module-sys/Service/BusProxy.cpp +++ b/module-sys/Service/BusProxy.cpp @@ -7,7 +7,8 @@ namespace sys { - BusProxy::BusProxy(Service *owner) : owner{owner}, busImpl{std::make_unique()} + BusProxy::BusProxy(Service *owner, Watchdog &watchdog) + : owner{owner}, watchdog{watchdog}, busImpl{std::make_unique()} { channels.push_back(BusChannel::System); // Mandatory for each service. } @@ -16,22 +17,32 @@ namespace sys bool BusProxy::sendUnicast(std::shared_ptr message, const std::string &targetName) { - return busImpl->SendUnicast(std::move(message), targetName, owner); + auto ret = busImpl->SendUnicast(std::move(message), targetName, owner); + if (ret) { + watchdog.refresh(); + } + return ret; } SendResult BusProxy::sendUnicast(std::shared_ptr message, const std::string &targetName, uint32_t timeout) { - return busImpl->SendUnicast(std::move(message), targetName, owner, timeout); + auto ret = busImpl->SendUnicast(std::move(message), targetName, owner, timeout); + if (ret.first != ReturnCodes::Failure) { + watchdog.refresh(); + } + return ret; } void BusProxy::sendMulticast(std::shared_ptr message, BusChannel channel) { busImpl->SendMulticast(std::move(message), channel, owner); + watchdog.refresh(); } void BusProxy::sendBroadcast(std::shared_ptr message) { busImpl->SendBroadcast(std::move(message), owner); + watchdog.refresh(); } void BusProxy::sendResponse(std::shared_ptr response, std::shared_ptr request) diff --git a/module-sys/Service/BusProxy.hpp b/module-sys/Service/BusProxy.hpp index 7b7cbb42037ad05459b446cff6e288e5f581bc3b..42d099478a62fdc2386f7039f85f2efe77dcbed7 100644 --- a/module-sys/Service/BusProxy.hpp +++ b/module-sys/Service/BusProxy.hpp @@ -4,6 +4,7 @@ #pragma once #include "Message.hpp" +#include "Watchdog.hpp" #include #include @@ -31,13 +32,14 @@ namespace sys private: friend class Service; - explicit BusProxy(Service *owner); + explicit BusProxy(Service *owner, Watchdog &watchdog); void sendResponse(std::shared_ptr response, std::shared_ptr request); void connect(); void disconnect(); Service *owner; + Watchdog &watchdog; std::unique_ptr busImpl; }; } // namespace sys diff --git a/module-sys/Service/Service.cpp b/module-sys/Service/Service.cpp index f60c0fd28cdf922b4d3838f23ca39ab53de7e2fa..6f3bd958ac72b8bd4c5dfcf739ab2d2f07c862f6 100644 --- a/module-sys/Service/Service.cpp +++ b/module-sys/Service/Service.cpp @@ -49,11 +49,12 @@ namespace sys using namespace cpp_freertos; using namespace std; - Service::Service(std::string name, std::string parent, uint32_t stackDepth, ServicePriority priority) + Service::Service( + std::string name, std::string parent, uint32_t stackDepth, ServicePriority priority, Watchdog &watchdog) : cpp_freertos::Thread(name, stackDepth / 4 /* Stack depth in bytes */, static_cast(priority)), - parent(parent), bus{this}, mailbox(this), pingTimestamp(UINT32_MAX), isReady(false), enableRunLoop(false) - { - } + parent(parent), bus(this, watchdog), mailbox(this), watchdog(watchdog), pingTimestamp(UINT32_MAX), + isReady(false), enableRunLoop(false) + {} Service::~Service() { @@ -148,7 +149,7 @@ namespace sys bool Service::connect(const type_info &type, MessageHandler handler) { - auto idx = type_index(type); + auto idx = type_index(type); if (message_handlers.find(idx) == message_handlers.end()) { LOG_DEBUG("Registering new message handler on %s", type.name()); message_handlers[idx] = handler; diff --git a/module-sys/Service/Service.hpp b/module-sys/Service/Service.hpp index 700a9d2f734f91146ba62432941338ecb56225d1..3d12716766e1d3900ff57663597aa78cd5c9c608 100644 --- a/module-sys/Service/Service.hpp +++ b/module-sys/Service/Service.hpp @@ -9,18 +9,20 @@ #include "Mailbox.hpp" // for Mailbox #include "Message.hpp" // for MessagePointer #include "ServiceManifest.hpp" -#include "thread.hpp" // for Thread -#include // for find, max -#include // for uint32_t, uint64_t -#include // for function -#include // for end -#include // for map -#include // for allocator, shared_ptr, enable_shared_from_this -#include // for string -#include // for type_index -#include // for pair -#include // for vector<>::iterator, vector -#include // for connect by type +#include "Watchdog.hpp" +#include "thread.hpp" // for Thread +#include // for SystemWatchdog +#include // for find, max +#include // for uint32_t, uint64_t +#include // for function +#include // for end +#include // for map +#include // for allocator, shared_ptr, enable_shared_from_this +#include // for string +#include // for type_index +#include // for pair +#include // for vector<>::iterator, vector +#include // for connect by type namespace sys { @@ -41,7 +43,8 @@ namespace sys Service(std::string name, std::string parent = "", uint32_t stackDepth = 4096, - ServicePriority priority = ServicePriority::Idle); + ServicePriority priority = ServicePriority::Idle, + Watchdog &watchdog = SystemWatchdog::getInstance()); ~Service() override; @@ -77,6 +80,8 @@ namespace sys Mailbox> mailbox; + Watchdog &watchdog; + uint32_t pingTimestamp; bool isReady; diff --git a/module-sys/Service/Watchdog.hpp b/module-sys/Service/Watchdog.hpp new file mode 100644 index 0000000000000000000000000000000000000000..d738c243f11d9890b70f2a234cabcdc1f59cf2f0 --- /dev/null +++ b/module-sys/Service/Watchdog.hpp @@ -0,0 +1,13 @@ +// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved. +// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md + +#pragma once + +namespace sys +{ + class Watchdog + { + public: + virtual void refresh() = 0; + }; +} // namespace sys diff --git a/module-sys/Service/details/bus/Bus.cpp b/module-sys/Service/details/bus/Bus.cpp index 0bb66c3a66ea4214bf21fa13db800258f059f236..17d90004109b9fe75ca51fbac5acbf135f487390 100644 --- a/module-sys/Service/details/bus/Bus.cpp +++ b/module-sys/Service/details/bus/Bus.cpp @@ -7,6 +7,7 @@ #include "Bus.hpp" #include "module-sys/Service/Service.hpp" +#include "module-sys/SystemWatchdog/SystemWatchdog.hpp" #include "module-os/CriticalSectionGuard.hpp" #include "ticks.hpp" diff --git a/module-sys/SystemWatchdog/SystemWatchdog.cpp b/module-sys/SystemWatchdog/SystemWatchdog.cpp new file mode 100644 index 0000000000000000000000000000000000000000..0611e6dfb1cf82cd09273e556f5b8ba10d706c84 --- /dev/null +++ b/module-sys/SystemWatchdog/SystemWatchdog.cpp @@ -0,0 +1,75 @@ +// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved. +// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md + +#include "SystemWatchdog.hpp" +#include "Service/Common.hpp" +#include "critical.hpp" +#include "ticks.hpp" +#include "bsp/watchdog/watchdog.hpp" +#include "log/log.hpp" + +namespace sys +{ + using namespace cpp_freertos; + + static constexpr uint16_t stackDepthWords = 256; + + SystemWatchdog::SystemWatchdog() + : Thread(threadName, stackDepthWords, static_cast(ServicePriority::High)) + {} + + SystemWatchdog &SystemWatchdog::getInstance() + { + static SystemWatchdog watchdog; + return watchdog; + } + + bool SystemWatchdog::init() + { +#ifdef DISABLE_WATCHDOG + return true; +#else + if (!bsp::watchdog::init(watchdogTimeoutPeriod)) { + return false; + } + bsp::watchdog::refresh(); + + if (!Start()) { + return false; + } + + refresh(); + + return true; +#endif + } + + void SystemWatchdog::refresh() + { +#ifndef DISABLE_WATCHDOG + // Critical section not required (atomic 32-bit writes) + lastRefreshTimestamp = Ticks::GetTicks(); +#endif + } + + void SystemWatchdog::Run() + { + while (true) { + vTaskDelay(checkPeriod); + + if (timeout_occurred) { + continue; + } + + // Critical section not required (atomic 32-bit reads) + if (Ticks::GetTicks() - lastRefreshTimestamp >= refreshTimeoutPeriod) { + // Allow HW watchdog timeout to occur + timeout_occurred = true; + LOG_FATAL("!!! System watchdog timeout, system will be resetted soon !!!"); + } + else { + bsp::watchdog::refresh(); + } + } + } +} // namespace sys diff --git a/module-sys/SystemWatchdog/SystemWatchdog.hpp b/module-sys/SystemWatchdog/SystemWatchdog.hpp new file mode 100644 index 0000000000000000000000000000000000000000..df399f05651eaf376b64bf271d47bfc5889ed168 --- /dev/null +++ b/module-sys/SystemWatchdog/SystemWatchdog.hpp @@ -0,0 +1,59 @@ +// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved. +// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md + +#pragma once + +#include +#include "thread.hpp" + +namespace sys +{ + // + // System watchdog + // + // System watchdog works in cooperation with an actual watchdog + // (HW or simulated). After initialization, it expects to be continually + // refreshed within a certain period of time. + // + // As long as its timing requirements are satisfied, it takes care + // of refreshing the actual watchdog so a reset will not occur. Otherwise, + // it will allow the actual watchdog to timeout causing a system reset. + // + class SystemWatchdog : public Watchdog, private cpp_freertos::Thread + { + public: + static constexpr auto threadName = "System_Watchdog"; + + SystemWatchdog(const SystemWatchdog &) = delete; + SystemWatchdog(SystemWatchdog &&) = delete; + SystemWatchdog &operator=(const SystemWatchdog &) = delete; + SystemWatchdog &operator=(SystemWatchdog &&) = delete; + + static SystemWatchdog &getInstance(); + + // Initialize the actual watchdog and start the thread + bool init(); + + void refresh() override; + + private: + SystemWatchdog(); + + // Timeout period for refresh + static constexpr TickType_t refreshTimeoutPeriod = pdMS_TO_TICKS(90000); + // Timeout period for the actual watchdog + static constexpr TickType_t watchdogTimeoutPeriod = pdMS_TO_TICKS(16000); + // Period of actual watchdog refresh + static constexpr TickType_t checkPeriod = pdMS_TO_TICKS(8000); + + void Run() final; + + TickType_t lastRefreshTimestamp = 0; + bool timeout_occurred = false; + + static_assert(sizeof(lastRefreshTimestamp) == 4 && alignof(decltype(lastRefreshTimestamp)) == 4, + "SystemWatchdog::lastRefreshTimestamp must be 32-bit long and properly aligned otherwise data " + "races may occur"); + }; + +} // namespace sys diff --git a/source/main.cpp b/source/main.cpp index ad28b267634b64e075caf6d8284c1990824b4d25..42b94f6e05391207046dabb81d5ebba14ae58ae0 100644 --- a/source/main.cpp +++ b/source/main.cpp @@ -51,6 +51,7 @@ #include #include #include +#include #include #include @@ -73,6 +74,13 @@ int main() bsp::BoardInit(); + if (!sys::SystemWatchdog::getInstance().init()) { + LOG_ERROR("System watchdog failed to initialize"); + // wait for the hardware watchdog (initialized in reset ISR) to reset the system + while (1) + ; + } + std::vector> systemServices; systemServices.emplace_back(sys::CreatorFor()); #if ENABLE_FILEINDEXER_SERVICE