| /******************************************************************************* | |
| * (c) Copyright 2009 Actel Corporation. All rights reserved. | |
| * | |
| * SmartFusion Microcontroller Subsystem (MSS) Watchdog bare metal software | |
| * driver. | |
| * | |
| * SVN $Revision: 1888 $ | |
| * SVN $Date: 2009-12-18 10:58:42 +0000 (Fri, 18 Dec 2009) $ | |
| */ | |
| /*=========================================================================*//** | |
| @section intro_sec Introduction | |
| The SmartFusion microcontroller subsystem (MSS) includes a watchdog timer used | |
| to detect system lockups. | |
| This driver provides a set of functions for controlling the MSS watchdog as | |
| part of a bare metal system where no operating system is available. These | |
| drivers can be adapted for use as part of an operating system but the | |
| implementation of the adaptation layer between this driver and the operating | |
| system's driver model is outside the scope of this driver. | |
| @section hw_dependencies Hardware Flow Dependencies | |
| The configuration of all features of the MSS watchdog is covered by this | |
| driver. There are no dependencies on the hardware flow for configuring the | |
| SmartFusion MSS watchdog timer. | |
| @section theory_op Theory of Operation | |
| The watchdog driver uses the SmartFusion "Cortex Microcontroler Software | |
| Interface Standard - Peripheral Access Layer" (CMSIS-PAL) to access hadware | |
| registers. You must ensure that the SmartFusion CMSIS-PAL is either included | |
| in the software toolchain used to build your project or is included in your | |
| project. The most up-to-date SmartFusion CMSIS-PAL files can be obtained using | |
| the Actel Firmware Catalog. | |
| The watchdog driver functions are grouped into the following categories: | |
| - Initialization and cnfiguration | |
| - Reading the watchdog timer current value and status | |
| - Refreshing the watchdog timer value | |
| - Time-out and wake-up interrupts control | |
| The watchdog driver is initialized and configured through a call to the | |
| MSS_WD_init() function. The parameters passed to MSS_WD_init() function | |
| specify the watchdog timer configuration. The configuration parameters include | |
| the value that will be reloaded into the watchdog timer down counter every | |
| time the watchdog is refreshed. Also included as part of the configuration | |
| parameters is the optional allowed refresh window. The allowed refresh window | |
| specifies the maximum allowed current value of the watchdog timer at the time | |
| of the watchdog is relaoded. Attempting to reload the watchdog timer when its | |
| value is larger than the allowed refresh window will cause a reset or | |
| interrupt depending on the watchdog configuration. The allowed refresh window | |
| can be disabled by specifying an allowed refesh window equal or higher than | |
| the watchdog reload value. | |
| The MSS_WD_init() function must be called before any other watchdog driver | |
| functions can be called with the exception of the MSS_WD_disable() function. | |
| The watchdog timer can be disabled using the MSS_WD_disable() function. Once | |
| disabled, the watchdog timer can only be reenabled by a power-on reset. | |
| The watchdog timer current value can be read using the MSS_WD_current_value() | |
| function. The watchdog status can be read using the MSS_WD_status() function. | |
| These functions are typically required when using the watchdog configured with | |
| an allowed refresh window to check if a watchdog reload is currently allowed. | |
| The watchdog timer value is reloaded using the MSS_WD_reload() function. The | |
| value reloaded into the watchdog timer down counter is the value specified as | |
| parameter to the MSS_WD_init() function. | |
| The watchdog timer can generate interrupts instead of resetting the system | |
| when its down-counter timer expires. These time-out interrupts are controlled | |
| using the following functions: | |
| - MSS_WD_enable_timeout_irq | |
| - MSS_WD_disable_timeout_irq | |
| - MSS_WD_clear_timeout_irq | |
| The watchdog timer is external to the Cortex-M3 processor core and operates | |
| even when the Cortex-M3 is in sleep mode. A wakeup interrupt can be generated | |
| by the watchdog timer to wakeup the Cortext-M3 when the watchdog timer value | |
| reaches the allowed refresh window while the Cortex-M3 is in sleep mode. The | |
| watchdog driver provides the following functions to control wakeup interrupts: | |
| - MSS_WD_enable_wakeup_irq | |
| - MSS_WD_disable_wakeup_irq | |
| - MSS_WD_clear_wakeup_irq | |
| *//*=========================================================================*/ | |
| #ifndef MSS_WATCHDOG_H_ | |
| #define MSS_WATCHDOG_H_ | |
| #ifdef __cplusplus | |
| extern "C" { | |
| #endif | |
| #include "../../CMSIS/a2fxxxm3.h" | |
| /***************************************************************************//** | |
| * The MSS_WDOG_RESET_ON_TIMEOUT_MODE macro is one of the possible values for the | |
| * mode parameter of the WD_init() function. It is used to specify that a reset | |
| * should occur when the watchdog down counter times out. | |
| */ | |
| #define MSS_WDOG_RESET_ON_TIMEOUT_MODE (uint32_t)0x00000000U | |
| /***************************************************************************//** | |
| * The MSS_WDOG_INTERRUPT_ON_TIMEOUT_MODE macro is one of the possible values for | |
| * the mode parameter of function the WD_init() function. It is used to specify | |
| * that a time out interrupt should occur when the watchdog down counter expires. | |
| */ | |
| #define MSS_WDOG_INTERRUPT_ON_TIMEOUT_MODE (uint32_t)0x00000004U | |
| /***************************************************************************//** | |
| * The MSS_WDOG_NO_WINDOW macro can be used as the value for the reload_window | |
| * parameter of the WD_init() function. It is used to specify that no forbidden | |
| * window will exist for the reload of the watchdog down counter. | |
| */ | |
| #define MSS_WDOG_NO_WINDOW (uint32_t)0xFFFFFFFFU | |
| /***************************************************************************//** | |
| * The MSS_WDOG_CTRL_MODE_BIT_MASK macro is a bit mask specifying the bit used to | |
| * set the watchdog's operating mode within the wathcdog's WDOGCONTROL register. | |
| */ | |
| #define MSS_WDOG_CTRL_MODE_BIT_MASK (uint32_t)0x00000004U | |
| /***************************************************************************//** | |
| * The MSS_WDOG_TIMEOUT_IRQ_ENABLE_BIT_MASK macro is a bit mask specifying the bit | |
| * used to enable the time out interrupt within the watchdog's WDOGCONTROL | |
| * register. | |
| */ | |
| #define MSS_WDOG_TIMEOUT_IRQ_ENABLE_BIT_MASK (uint32_t)0x00000001U | |
| /***************************************************************************//** | |
| The MSS_WDOG_WAKEUP_IRQ_ENABLE_BIT_MASK macro is a bit mask specifying the bit | |
| used to enable the wake up interrupt within the watchdog's WDOGCONTROL | |
| register. | |
| */ | |
| #define MSS_WDOG_WAKEUP_IRQ_ENABLE_BIT_MASK (uint32_t)0x00000002U | |
| /***************************************************************************//** | |
| The MSS_WDOG_TIMEOUT_IRQ_CLEAR_BIT_MASK macro is a bit mask specifying the bit | |
| used to clear the time out interrupt within the watchdog's WDOGRIS register. | |
| */ | |
| #define MSS_WDOG_TIMEOUT_IRQ_CLEAR_BIT_MASK (uint32_t)0x00000001U | |
| /***************************************************************************//** | |
| The MSS_WDOG_WAKEUP_IRQ_CLEAR_BIT_MASK macro is a bit mask specifying the bit | |
| used to clear the wake up interrupt within the watchdog's WDOGRIS register. | |
| */ | |
| #define MSS_WDOG_WAKEUP_IRQ_CLEAR_BIT_MASK (uint32_t)0x00000002U | |
| /***************************************************************************//** | |
| The MSS_WDOG_REFRESH_KEY macro holds the magic value which will cause a reload | |
| of the watchdog's down counter when written to the watchdog's WDOGREFRESH | |
| register. | |
| */ | |
| #define MSS_WDOG_REFRESH_KEY (uint32_t)0xAC15DE42U | |
| /***************************************************************************//** | |
| The MSS_WDOG_DISABLE_KEY macro holds the magic value which will disable the | |
| watchdog if written to the watchdog's WDOGENABLE register. | |
| */ | |
| #define MSS_WDOG_DISABLE_KEY (uint32_t)0x4C6E55FAU | |
| /***************************************************************************//** | |
| The MSS_WD_init() function initializes and configures the watchdog timer. | |
| @param load_value | |
| The load_value parameter specifies the value that will be loaded into the | |
| watchdog's down counter when the reload command is issued through a call to | |
| MSS_WD_reload(). | |
| @param reload_window | |
| The reload_window parameter specifies the time window during which a reload | |
| of the watchdog counter is allowed. A reload of the watchdog counter should | |
| only be performed when the watchdog counter value is below the value of the | |
| reload_window. Reloading the watchdog down counter value before it has | |
| reached the reload_window will result in an interrupt or reset depending on | |
| the watchdog's mode. | |
| The reload window can be disabled by using WDOG_NO_WINDOW for this parameter. | |
| @param mode | |
| The mode parameter specifies the watchdog's operating mode. It can be either | |
| MSS_WDOG_RESET_ON_TIMEOUT_MODE or MSS_WDOG_INTERRUPT_ON_TIMEOUT_MODE. | |
| MSS_WDOG_RESET_ON_TIMEOUT_MODE: a reset will occur if the watchdog timer | |
| expires. | |
| MSS_WDOG_INTERRUPT_ON_TIMEOUT_MODE: an NMI interrupt will occur if the | |
| watchdog timer expires. | |
| @return | |
| This function does not return a value. | |
| */ | |
| static __INLINE void MSS_WD_init | |
| ( | |
| uint32_t load_value, | |
| uint32_t reload_window, | |
| uint32_t mode | |
| ) | |
| { | |
| /* Disable interrupts. */ | |
| WATCHDOG->WDOGCONTROL &= ~(MSS_WDOG_TIMEOUT_IRQ_ENABLE_BIT_MASK | MSS_WDOG_WAKEUP_IRQ_CLEAR_BIT_MASK); | |
| /* Clear any existing interrupts. */ | |
| WATCHDOG->WDOGRIS = MSS_WDOG_TIMEOUT_IRQ_CLEAR_BIT_MASK | MSS_WDOG_WAKEUP_IRQ_CLEAR_BIT_MASK; | |
| /* Configure watchdog with new configuration passed as parameter. */ | |
| WATCHDOG->WDOGMVRP = MSS_WDOG_NO_WINDOW; | |
| WATCHDOG->WDOGLOAD = load_value; | |
| WATCHDOG->WDOGCONTROL = (WATCHDOG->WDOGCONTROL & ~MSS_WDOG_CTRL_MODE_BIT_MASK) | (mode & MSS_WDOG_CTRL_MODE_BIT_MASK); | |
| /* Reload watchdog with new load value. */ | |
| WATCHDOG->WDOGREFRESH = MSS_WDOG_REFRESH_KEY; | |
| /* Set allowed window. */ | |
| WATCHDOG->WDOGMVRP = reload_window; | |
| } | |
| /***************************************************************************//** | |
| The MSS_WD_reload() function causes the watchdog to reload its down counter timer | |
| with the load value configured through the call to WD_init(). This function | |
| must be called regularly to avoid a system reset. | |
| @return | |
| This function does not return a value. | |
| */ | |
| static __INLINE void MSS_WD_reload( void ) | |
| { | |
| WATCHDOG->WDOGREFRESH = MSS_WDOG_REFRESH_KEY; | |
| } | |
| /***************************************************************************//** | |
| The MSS_WD_disable() function disables the watchdog. | |
| Please note that the watchdog can only be reenabled as a result of a power-on | |
| reset. | |
| @return | |
| This function does not return a value. | |
| */ | |
| static __INLINE void MSS_WD_disable( void ) | |
| { | |
| WATCHDOG->WDOGENABLE = MSS_WDOG_DISABLE_KEY; | |
| } | |
| /***************************************************************************//** | |
| The MSS_WD_current_value() function returns the current value of the watchdog's | |
| down counter. | |
| @return | |
| This function returns the current value of the watchdog down counter. | |
| */ | |
| static __INLINE uint32_t MSS_WD_current_value( void ) | |
| { | |
| return WATCHDOG->WDOGVALUE; | |
| } | |
| /***************************************************************************//** | |
| The MSS_WD_status() function returns the status of the watchdog. | |
| @return | |
| The MSS_WD_status() function returns the status of the watchdog. A value of | |
| 0 indicates that watchdog counter has reached the forbidden window and that | |
| a reload should not be done. A value of 1 indicates that the watchdog counter | |
| is within the permitted window and that a reload is allowed. | |
| */ | |
| static __INLINE uint32_t MSS_WD_status( void ) | |
| { | |
| return WATCHDOG->WDOGSTATUS; | |
| } | |
| /***************************************************************************//** | |
| The MSS_WD_enable_timeout_irq() function enables the watchdogs time out | |
| interrupt which is connected to the Cortex-M3 NMI interrupt. | |
| The NMI_Handler() function will be called when a watchdog time out occurs. You | |
| must provide the implementation of the NMI_Handler() function to suit your | |
| application. | |
| @return | |
| This function does not return a value. | |
| Example: | |
| @code | |
| #include "mss_watchdog.h" | |
| int main( void ) | |
| { | |
| MSS_WD_init( 0x10000000, MSS_WDOG_NO_WINDOW, MSS_WDOG_INTERRUPT_ON_TIMEOUT_MODE ); | |
| MSS_WD_enable_timeout_irq(); | |
| for (;;) | |
| { | |
| main_task(); | |
| } | |
| } | |
| void NMI_Handler( void ) | |
| { | |
| process_timeout(); | |
| MSS_WD_clear_timeout_irq(); | |
| } | |
| @endcode | |
| */ | |
| static __INLINE void MSS_WD_enable_timeout_irq( void ) | |
| { | |
| WATCHDOG->WDOGCONTROL |= MSS_WDOG_TIMEOUT_IRQ_ENABLE_BIT_MASK; | |
| } | |
| /***************************************************************************//** | |
| The WD_disable_timeout_irq() function disables the generation of the NMI | |
| interrupt when the watchdog times out. | |
| @return | |
| This function does not return a value. | |
| */ | |
| static __INLINE void MSS_WD_disable_timeout_irq( void ) | |
| { | |
| WATCHDOG->WDOGCONTROL &= ~MSS_WDOG_TIMEOUT_IRQ_ENABLE_BIT_MASK; | |
| } | |
| /***************************************************************************//** | |
| The MSS_WD_enable_wakeup_irq() function enables the SmartFusion wakeup | |
| interrupt. The WdogWakeup_IRQHandler() function will be called when a wake up | |
| interrupt occurs. You must provide the implementation of the WdogWakeup_IRQHandler() | |
| function to suit your application. | |
| @return | |
| This function does not return a value. | |
| Example: | |
| @code | |
| #include "mss_watchdog.h" | |
| int main( void ) | |
| { | |
| MSS_WD_init( 0x10000000, MSS_WDOG_NO_WINDOW, MSS_WDOG_INTERRUPT_ON_TIMEOUT_MODE ); | |
| MSS_WD_enable_wakeup_irq(); | |
| for (;;) | |
| { | |
| main_task(); | |
| cortex_sleep(); | |
| } | |
| } | |
| void WdogWakeup_IRQHandler( void ) | |
| { | |
| process_wakeup(); | |
| MSS_WD_clear_wakeup_irq(); | |
| } | |
| @endcode | |
| */ | |
| static __INLINE void MSS_WD_enable_wakeup_irq( void ) | |
| { | |
| WATCHDOG->WDOGCONTROL |= MSS_WDOG_WAKEUP_IRQ_ENABLE_BIT_MASK; | |
| NVIC_EnableIRQ( WdogWakeup_IRQn ); | |
| } | |
| /***************************************************************************//** | |
| The MSS_WD_disable_wakeup_irq() function disables the SmartFusion wakeup | |
| interrupt. | |
| @return | |
| This function does not return a value. | |
| */ | |
| static __INLINE void MSS_WD_disable_wakeup_irq( void ) | |
| { | |
| WATCHDOG->WDOGCONTROL &= ~MSS_WDOG_WAKEUP_IRQ_ENABLE_BIT_MASK; | |
| } | |
| /***************************************************************************//** | |
| The MSS_WD_clear_timeout_irq() function clears the watchdogs time out | |
| interrupt which is connected to the Cortex-M3 NMI interrupt. | |
| Calling MSS_WD_clear_timeout_irq() results in clearing the Cortex-M3 NMI interrupt. | |
| Note: The MSS_WD_clear_timeout_irq() function must be called as part of the | |
| timeout interrupt service routine (ISR) in order to prevent the same interrupt | |
| event retriggering a call to the wakeup ISR. | |
| @return | |
| The example below demonstrates the use of the MSS_WD_clear_timeout_irq() | |
| function as part of the NMI interrupt service routine. | |
| Example: | |
| @code | |
| void NMI_Handler( void ) | |
| { | |
| process_timeout(); | |
| MSS_WD_clear_timeout_irq(); | |
| } | |
| @endcode | |
| */ | |
| static __INLINE void MSS_WD_clear_timeout_irq( void ) | |
| { | |
| WATCHDOG->WDOGRIS = MSS_WDOG_TIMEOUT_IRQ_CLEAR_BIT_MASK; | |
| /* | |
| * Perform a second write to ensure that the first write completed before | |
| * returning from this function. This is to account for posted writes across | |
| * the AHB matrix. The second write ensures that the first write has | |
| * completed and that the interrupt line has been de-asserted by the time | |
| * the function returns. Omitting the second write may result in a delay | |
| * in the de-assertion of the interrupt line going to the Cortex-M3 and a | |
| * retriggering of the interrupt. | |
| */ | |
| WATCHDOG->WDOGRIS = MSS_WDOG_TIMEOUT_IRQ_CLEAR_BIT_MASK; | |
| } | |
| /***************************************************************************//** | |
| The MSS_WD_clear_wakeup_irq() function clears the wakeup interrupt. | |
| Note: The MSS_WD_clear_wakeup_irq() function must be called as part of the | |
| wakeup interrupt service routine (ISR) in order to prevent the same interrupt | |
| event retriggering a call to the wakeup ISR. This function also clears the | |
| interrupt in the Cortex-M3 interrupt controller through a call to | |
| NVIC_ClearPendingIRQ(). | |
| @return | |
| This function does not return a value. | |
| Example: | |
| The example below demonstrates the use of the MSS_WD_clear_wakeup_irq() function | |
| as part of the wakeup interrupt service routine. | |
| @code | |
| void WdogWakeup_IRQHandler( void ) | |
| { | |
| do_interrupt_processing(); | |
| MSS_WD_clear_wakeup_irq(); | |
| } | |
| @endcode | |
| */ | |
| static __INLINE void MSS_WD_clear_wakeup_irq( void ) | |
| { | |
| WATCHDOG->WDOGRIS = MSS_WDOG_WAKEUP_IRQ_CLEAR_BIT_MASK; | |
| NVIC_ClearPendingIRQ( WdogWakeup_IRQn ); | |
| } | |
| #ifdef __cplusplus | |
| } | |
| #endif | |
| #endif /* MSS_WATCHDOG_H_ */ |