276 lines
8.9 KiB
C
276 lines
8.9 KiB
C
/*
|
|
* Copyright (c) 2016, Freescale Semiconductor, Inc.
|
|
* Copyright 2016-2020 NXP
|
|
* All rights reserved.
|
|
*
|
|
* SPDX-License-Identifier: BSD-3-Clause
|
|
*/
|
|
|
|
#include "fsl_wwdt.h"
|
|
|
|
/* Component ID definition, used by tools. */
|
|
#ifndef FSL_COMPONENT_ID
|
|
#define FSL_COMPONENT_ID "platform.drivers.wwdt"
|
|
#endif
|
|
|
|
#define FREQUENCY_3MHZ (3000000U)
|
|
/*******************************************************************************
|
|
* Prototypes
|
|
******************************************************************************/
|
|
|
|
/*!
|
|
* @brief Gets the instance from the base address
|
|
*
|
|
* @param base WWDT peripheral base address
|
|
*
|
|
* @return The WWDT instance
|
|
*/
|
|
static uint32_t WWDT_GetInstance(WWDT_Type *base);
|
|
|
|
/*******************************************************************************
|
|
* Variables
|
|
******************************************************************************/
|
|
/*! @brief Pointers to WWDT bases for each instance. */
|
|
static WWDT_Type *const s_wwdtBases[] = WWDT_BASE_PTRS;
|
|
|
|
#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
|
|
/*! @brief Pointers to WWDT clocks for each instance. */
|
|
static const clock_ip_name_t s_wwdtClocks[] = WWDT_CLOCKS;
|
|
#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
|
|
|
|
#if !(defined(FSL_SDK_DISABLE_DRIVER_RESET_CONTROL) && FSL_SDK_DISABLE_DRIVER_RESET_CONTROL)
|
|
#if !(defined(FSL_FEATURE_WWDT_HAS_NO_RESET) && FSL_FEATURE_WWDT_HAS_NO_RESET)
|
|
/*! @brief Pointers to WWDT resets for each instance. */
|
|
static const reset_ip_name_t s_wwdtResets[] = WWDT_RSTS;
|
|
#endif
|
|
#endif /* FSL_SDK_DISABLE_DRIVER_RESET_CONTROL */
|
|
|
|
/*******************************************************************************
|
|
* Code
|
|
******************************************************************************/
|
|
static uint32_t WWDT_GetInstance(WWDT_Type *base)
|
|
{
|
|
uint32_t instance;
|
|
uint32_t wwdtArrayCount = (sizeof(s_wwdtBases) / sizeof(s_wwdtBases[0]));
|
|
|
|
/* Find the instance index from base address mappings. */
|
|
for (instance = 0; instance < wwdtArrayCount; instance++)
|
|
{
|
|
if (s_wwdtBases[instance] == base)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
assert(instance < wwdtArrayCount);
|
|
|
|
return instance;
|
|
}
|
|
|
|
/*******************************************************************************
|
|
* Code
|
|
******************************************************************************/
|
|
|
|
/*!
|
|
* brief Initializes WWDT configure structure.
|
|
*
|
|
* This function initializes the WWDT configure structure to default value. The default
|
|
* value are:
|
|
* code
|
|
* config->enableWwdt = true;
|
|
* config->enableWatchdogReset = false;
|
|
* config->enableWatchdogProtect = false;
|
|
* config->enableLockOscillator = false;
|
|
* config->windowValue = 0xFFFFFFU;
|
|
* config->timeoutValue = 0xFFFFFFU;
|
|
* config->warningValue = 0;
|
|
* endcode
|
|
*
|
|
* param config Pointer to WWDT config structure.
|
|
* see wwdt_config_t
|
|
*/
|
|
void WWDT_GetDefaultConfig(wwdt_config_t *config)
|
|
{
|
|
assert(NULL != config);
|
|
|
|
/* Initializes the configure structure to zero. */
|
|
(void)memset(config, 0, sizeof(*config));
|
|
|
|
/* Enable the watch dog */
|
|
config->enableWwdt = true;
|
|
/* Disable the watchdog timeout reset */
|
|
config->enableWatchdogReset = false;
|
|
/* Disable the watchdog protection for updating the timeout value */
|
|
config->enableWatchdogProtect = false;
|
|
#if !(defined(FSL_FEATURE_WWDT_HAS_NO_OSCILLATOR_LOCK) && FSL_FEATURE_WWDT_HAS_NO_OSCILLATOR_LOCK)
|
|
/* Do not lock the watchdog oscillator */
|
|
config->enableLockOscillator = false;
|
|
#endif
|
|
/* Windowing is not in effect */
|
|
config->windowValue = 0xFFFFFFU;
|
|
/* Set the timeout value to the max */
|
|
config->timeoutValue = 0xFFFFFFU;
|
|
/* No warning is provided */
|
|
config->warningValue = 0;
|
|
/* Set clock frequency. */
|
|
config->clockFreq_Hz = 0U;
|
|
}
|
|
|
|
/*!
|
|
* brief Initializes the WWDT.
|
|
*
|
|
* This function initializes the WWDT. When called, the WWDT runs according to the configuration.
|
|
*
|
|
* Example:
|
|
* code
|
|
* wwdt_config_t config;
|
|
* WWDT_GetDefaultConfig(&config);
|
|
* config.timeoutValue = 0x7ffU;
|
|
* WWDT_Init(wwdt_base,&config);
|
|
* endcode
|
|
*
|
|
* param base WWDT peripheral base address
|
|
* param config The configuration of WWDT
|
|
*/
|
|
void WWDT_Init(WWDT_Type *base, const wwdt_config_t *config)
|
|
{
|
|
assert(NULL != config);
|
|
|
|
uint32_t value = 0U;
|
|
uint32_t DelayUs = 0U;
|
|
uint32_t primaskValue = 0U;
|
|
|
|
#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
|
|
/* Enable the WWDT clock */
|
|
CLOCK_EnableClock(s_wwdtClocks[WWDT_GetInstance(base)]);
|
|
#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
|
|
|
|
#if !(defined(FSL_SDK_DISABLE_DRIVER_RESET_CONTROL) && FSL_SDK_DISABLE_DRIVER_RESET_CONTROL)
|
|
#if !(defined(FSL_FEATURE_WWDT_HAS_NO_RESET) && FSL_FEATURE_WWDT_HAS_NO_RESET)
|
|
/* Reset the module. */
|
|
RESET_PeripheralReset(s_wwdtResets[WWDT_GetInstance(base)]);
|
|
#endif
|
|
|
|
#if defined(FSL_FEATURE_WWDT_WDTRESET_FROM_PMC) && (FSL_FEATURE_WWDT_WDTRESET_FROM_PMC)
|
|
/* PMC RESETCAUSE: set bit to clear it by write 1. */
|
|
PMC->RESETCAUSE = PMC_RESETCAUSE_WDTRESET_MASK;
|
|
/* Enable the watchdog reset event to affect the system in the Power Management Controller */
|
|
PMC->CTRL |= PMC_CTRL_WDTRESETENABLE_MASK;
|
|
#endif /*FSL_FEATURE_WWDT_WDTRESET_FROM_PMC*/
|
|
|
|
#endif /* FSL_SDK_DISABLE_DRIVER_RESET_CONTROL */
|
|
|
|
#if !(defined(FSL_FEATURE_WWDT_HAS_NO_OSCILLATOR_LOCK) && FSL_FEATURE_WWDT_HAS_NO_OSCILLATOR_LOCK)
|
|
value = WWDT_MOD_WDEN(config->enableWwdt) | WWDT_MOD_WDRESET(config->enableWatchdogReset) |
|
|
WWDT_MOD_LOCK(config->enableLockOscillator);
|
|
#else
|
|
value = WWDT_MOD_WDEN(config->enableWwdt) | WWDT_MOD_WDRESET(config->enableWatchdogReset);
|
|
#endif
|
|
/* Clear legacy flag in the MOD register by software writing a "1" to this bit field.. */
|
|
if (0U != (base->MOD & WWDT_MOD_WDINT_MASK))
|
|
{
|
|
value |= WWDT_MOD_WDINT_MASK;
|
|
}
|
|
/* Set configuration */
|
|
primaskValue = DisableGlobalIRQ();
|
|
base->TC = WWDT_TC_COUNT(config->timeoutValue);
|
|
base->MOD = value;
|
|
base->WINDOW = WWDT_WINDOW_WINDOW(config->windowValue);
|
|
base->WARNINT = WWDT_WARNINT_WARNINT(config->warningValue);
|
|
/* Refreshes the WWDT timer. */
|
|
base->FEED = WWDT_FIRST_WORD_OF_REFRESH;
|
|
base->FEED = WWDT_SECOND_WORD_OF_REFRESH;
|
|
EnableGlobalIRQ(primaskValue);
|
|
/* Read counter value to wait wwdt timer start*/
|
|
if (config->enableWwdt)
|
|
{
|
|
while (base->TV == 0xFFUL)
|
|
{
|
|
}
|
|
}
|
|
|
|
/* This WDPROTECT bit can be set once by software and is only cleared by a reset */
|
|
if (config->enableWatchdogProtect && (0U == (base->MOD & WWDT_MOD_WDPROTECT_MASK)))
|
|
{
|
|
/* The config->clockFreq_Hz must be set in order to config the delay time. */
|
|
assert(0U != config->clockFreq_Hz);
|
|
|
|
/* Set the WDPROTECT bit after the Feed Sequence (0xAA, 0x55) with 3 WDCLK delay */
|
|
DelayUs = FREQUENCY_3MHZ / config->clockFreq_Hz + 1U;
|
|
SDK_DelayAtLeastUs(DelayUs, SDK_DEVICE_MAXIMUM_CPU_CLOCK_FREQUENCY);
|
|
|
|
base->MOD |= WWDT_MOD_WDPROTECT(1U);
|
|
}
|
|
}
|
|
|
|
/*!
|
|
* brief Shuts down the WWDT.
|
|
*
|
|
* This function shuts down the WWDT.
|
|
*
|
|
* param base WWDT peripheral base address
|
|
*/
|
|
void WWDT_Deinit(WWDT_Type *base)
|
|
{
|
|
#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
|
|
/* Disable the WWDT clock */
|
|
CLOCK_DisableClock(s_wwdtClocks[WWDT_GetInstance(base)]);
|
|
#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
|
|
}
|
|
|
|
/*!
|
|
* brief Refreshes the WWDT timer.
|
|
*
|
|
* This function feeds the WWDT.
|
|
* This function should be called before WWDT timer is in timeout. Otherwise, a reset is asserted.
|
|
*
|
|
* param base WWDT peripheral base address
|
|
*/
|
|
void WWDT_Refresh(WWDT_Type *base)
|
|
{
|
|
uint32_t primaskValue = 0U;
|
|
|
|
/* Disable the global interrupt to protect refresh sequence */
|
|
primaskValue = DisableGlobalIRQ();
|
|
base->FEED = WWDT_FIRST_WORD_OF_REFRESH;
|
|
base->FEED = WWDT_SECOND_WORD_OF_REFRESH;
|
|
EnableGlobalIRQ(primaskValue);
|
|
}
|
|
|
|
/*!
|
|
* brief Clear WWDT flag.
|
|
*
|
|
* This function clears WWDT status flag.
|
|
*
|
|
* Example for clearing warning flag:
|
|
* code
|
|
* WWDT_ClearStatusFlags(wwdt_base, kWWDT_WarningFlag);
|
|
* endcode
|
|
* param base WWDT peripheral base address
|
|
* param mask The status flags to clear. This is a logical OR of members of the
|
|
* enumeration ::_wwdt_status_flags_t
|
|
*/
|
|
void WWDT_ClearStatusFlags(WWDT_Type *base, uint32_t mask)
|
|
{
|
|
/* Clear the WDINT bit so that we don't accidentally clear it */
|
|
uint32_t reg = (base->MOD & (~WWDT_MOD_WDINT_MASK));
|
|
|
|
/* Clear timeout by writing a zero */
|
|
if (0U != (mask & (uint32_t)kWWDT_TimeoutFlag))
|
|
{
|
|
reg &= ~WWDT_MOD_WDTOF_MASK;
|
|
#if defined(FSL_FEATURE_WWDT_WDTRESET_FROM_PMC) && (FSL_FEATURE_WWDT_WDTRESET_FROM_PMC)
|
|
/* PMC RESETCAUSE: set bit to clear it */
|
|
PMC->RESETCAUSE = PMC_RESETCAUSE_WDTRESET_MASK;
|
|
#endif /*FSL_FEATURE_WWDT_WDTRESET_FROM_PMC*/
|
|
}
|
|
|
|
/* Clear warning interrupt flag by writing a one */
|
|
if (0U != (mask & (uint32_t)kWWDT_WarningFlag))
|
|
{
|
|
reg |= WWDT_MOD_WDINT_MASK;
|
|
}
|
|
|
|
base->MOD = reg;
|
|
}
|