/****************************************************************************** * $Revision: 423 $ * $Date:: 2017-04-07 16:03:30 +0900#$ *****************************************************************************/ /* __DISCLAIMER_START__ */ /****************************************************************************** * (c)2017, Cypress Semiconductor Corporation * or a subsidiary of Cypress Semiconductor Corporation. All rights * reserved. * * This software, including source code, documentation and related * materials ( "Software" ), is owned by Cypress Semiconductor * Corporation or one of its subsidiaries ( "Cypress" ) and is protected by * and subject to worldwide patent protection (United States and foreign), * United States copyright laws and international treaty provisions. * Therefore, you may use this Software only as provided in the license * agreement accompanying the software package from which you * obtained this Software ( "EULA" ). * * If no EULA applies, Cypress hereby grants you a personal, nonexclusive, * non-transferable license to copy, modify, and compile the * Software source code solely for use in connection with Cypress' s * integrated circuit products. Any reproduction, modification, translation, * compilation, or representation of this Software except as specified * above is prohibited without the express written permission of Cypress. * * Disclaimer: THIS SOFTWARE IS PROVIDED AS-IS, WITH NO * WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING, * BUT NOT LIMITED TO, NONINFRINGEMENT, IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * PARTICULAR PURPOSE. Cypress reserves the right to make * changes to the Software without notice. Cypress does not assume any * liability arising out of the application or use of the Software or any * product or circuit described in the Software. Cypress does not * authorize its products for use in any products where a malfunction or * failure of the Cypress product may reasonably be expected to result in * significant property damage, injury or death ( "High Risk Product" ). By * including Cypress' s product in a High Risk Product, the manufacturer * of such system or application assumes all risk of such use and in doing * so agrees to indemnify Cypress against all liability. ******************************************************************************/ /* __DISCLAIMER_END__ */ /***************************************************************************** ** \file swdg.c ** ** A detailed description is available at ** @link SwdgGroup Software Watchdog Module description @endlink ** ** History: ** - 2014-05-16 0.01 HS Initial version for Traveo *****************************************************************************/ /*****************************************************************************/ /* Include files */ /*****************************************************************************/ #include "abstract.h" #include "interrupts.h" #if defined( PDL_PERIPHERAL_SWDG_ACTIVE ) /** ***************************************************************************** ** \addtogroup SwdgGroup *****************************************************************************/ /*! @{ */ /*****************************************************************************/ /* Local pre-processor symbols/macros ('#define') */ /*****************************************************************************/ /*! key for unlocking SW-WDG regs */ #define SWDG_PROT_UNLOCK (0xEDACCE55) /*! trigger value for updating RUN profile */ #define SYSC_TRGRUNCNTR_APPLY_PROFILE (0xAB) /*! key for unlocking SYSC */ #define SYSC_PROTKEYR_UNLOCK (0x5CACCE55) /*****************************************************************************/ /* Global variable definitions (declared in header file with 'extern') */ /*****************************************************************************/ /*****************************************************************************/ /* Local type definitions ('typedef') */ /*****************************************************************************/ /** ***************************************************************************** ** \brief Data needed by SWDG module for operation *****************************************************************************/ typedef struct stc_swdg_intern_data { func_ptr_t pfnPreWarnCallback; /*!< Callback for SWDG prior warning interrupt */ func_ptr_t pfnNmiCallback; /*!< Callback for SWDG NMI interrupt */ } stc_swdg_intern_data_t; /*****************************************************************************/ /* Local function prototypes ('static') */ /*****************************************************************************/ /*****************************************************************************/ /* Local variable definitions ('static') */ /*****************************************************************************/ static stc_swdg_intern_data_t m_stcSwdgInternData; /*****************************************************************************/ /* Function implementation - global ('extern') and local ('static') */ /*****************************************************************************/ /** ***************************************************************************** ** \brief ISR for SWDG pre warning interrupt. ** ** This ISR calls the callback function that has been given configuration ** (see Swdg_Init() and #stc_swdg_config_t). *****************************************************************************/ FN_IRQ_DEFINE_BEGIN(Swdg_Isr_PreWarn, INTERRUPTS_IRQ_NUMBER_3) { /* Clear prior warning interrupt flag. Registers need to be unlocked for */ /* writing first. */ SWDG_PROT = SWDG_PROT_UNLOCK; PDL_WRITE_REG_SYNC(SWDG_INTCLR_IRQCLR, 1); /* Call registered interrupt callback function if available. */ /* If no callback is registered, the interrupt should not be enabled anyway. */ /* The NULL pointer check is done just for safety reasons. */ if (m_stcSwdgInternData.pfnPreWarnCallback != NULL) { m_stcSwdgInternData.pfnPreWarnCallback(); } } FN_IRQ_DEFINE_END() /** ***************************************************************************** ** \brief ISR for SWDG NMI. ** ** This ISR calls the callback function that has been given configuration ** (see Swdg_Init() and #stc_swdg_config_t). *****************************************************************************/ FN_NMI_DEFINE_BEGIN(Swdg_Isr_NMI, INTERRUPTS_NMI_NUMBER_7) { /* Clear prior warning interrupt flag. Registers need to be unlocked for */ /* writing first. */ SWDG_PROT = SWDG_PROT_UNLOCK; PDL_WRITE_REG_SYNC(SWDG_INTCLR_NMICLR, 1); /* Call registered interrupt callback function if available. */ /* If no callback is registered, the interrupt should not be enabled anyway. */ /* The NULL pointer check is done just for safety reasons. */ if (m_stcSwdgInternData.pfnNmiCallback != NULL) { m_stcSwdgInternData.pfnNmiCallback(); } } FN_NMI_DEFINE_END() /** ***************************************************************************** ** \brief Initialize software WDG ** ** This function initializes the software WDG module. After a reset, ** the SWDG can be initialized exactly once. 0nce started the WDG ** cannot be stopped. After calling Swdg_Init() the WDG is locked. ** The last WDG reset cause will be cleared. ** If get the last reset cause, please use Swdg_GetResetCause() ** before calling this function. ** ** \note This function can be called only once during startup. Afterwards the ** WDG is locked. ** ** \pre Must be run from privileged mode and be run after the source ** clock setting is completed. ** ** \param [in] pstcConfig SWDG configuration ** ** \retval Ok Initialization of SWDG module successful ** \retval Error If following conditions are met: ** - SWDG module has already been initialized ** - Selected source clock oscillation is disabled ** - RUN profile has not been completed yet ** \retval ErrorInvalidParameter If following conditions are met: ** - pstcConfig is NULL ** - pstcConfig->u32WindowLowerLimit greater or equal ** pstcConfig->u32WindowUpperLimit (either RUN or PSS) ** \retval ErrorAccessRights If called from non-privileged mode *****************************************************************************/ en_result_t Swdg_Init(const stc_swdg_config_t *pstcConfig) { boolean_t bPrivilegedMode; un_swdg_int_t unInt = { 0 }; un_swdg_cfg_t unCfg = { 0 }; /* --------------- Check parameters and conditions ---------------- */ /* Check CPU mode */ /* WDG configurations can be set only when CPU is in the privilege mode */ bPrivilegedMode = Cpu_CpuIsInPrivilegedMode(); if (bPrivilegedMode == FALSE) { return ErrorAccessRights; } /* NULL pointer check */ if (pstcConfig == NULL) { return ErrorInvalidParameter; } /* Check window limit */ /* Window upper limit should be greater than lower limit */ if ((pstcConfig->stcRunModeSettings.bWdgEnable != FALSE) && (pstcConfig->stcRunModeSettings.u32WindowLowerLimit >= pstcConfig->stcRunModeSettings.u32WindowUpperLimit)) { return ErrorInvalidParameter; } if ((pstcConfig->stcPssModeSettings.bWdgEnable != FALSE) && (pstcConfig->stcPssModeSettings.u32WindowLowerLimit >= pstcConfig->stcPssModeSettings.u32WindowUpperLimit)) { return ErrorInvalidParameter; } /* SWDG configuration registers can be written only once */ if (SWDG_CFG_LOCK != 0) { return Error; } /* Check clock selection */ /* If selected source clock oscillation is disabled, return as error*/ switch (pstcConfig->enClockSelection) { case SwdgSlowRcClk: if (SYSC0_APPCKSRER_SCROSCEN == 0) { return Error; } break; case SwdgRcClk: if (SYSC0_APPCKSRER_CROSCEN == 0) { return Error; } break; case SwdgMainClk: if (SYSC0_APPCKSRER_MOSCEN == 0) { return Error; } break; default: return ErrorInvalidParameter; /* Should never reach */ } /* Check if profile update has not completed */ if (SYSC0_SYSSTSR_RUNSTS0 != 0) { return Error; } /* --------------- Construct register settings ---------------- */ /* Setting of SWDG_INT register */ /* If a callback for NMI was given, watchdog interrupt request (NMI) is enabled. */ unInt.stcField.u1RSTEN = (pstcConfig->pfnNmiCallback != NULL) ? 0 : 1; /* If a callback for prior warning interrupt was given, enable the interrupt */ unInt.stcField.u1IRQEN = (pstcConfig->pfnPreWarnCallback != NULL) ? 1 : 0; /* Store callback function */ m_stcSwdgInternData.pfnNmiCallback = pstcConfig->pfnNmiCallback; m_stcSwdgInternData.pfnPreWarnCallback = pstcConfig->pfnPreWarnCallback; /* Setting of SWDG_CFG register */ unCfg.stcField.u1WDENRUN = (pstcConfig->stcRunModeSettings.bWdgEnable == FALSE) ? 0 : 1; unCfg.stcField.u1WDENPSS = (pstcConfig->stcPssModeSettings.bWdgEnable == FALSE) ? 0 : 1; unCfg.stcField.u1ALLOWSTOPCLK = (pstcConfig->bAllowClockStopInPss == FALSE) ? 0 : 1; unCfg.stcField.u2CLKSEL = pstcConfig->enClockSelection; unCfg.stcField.u5OBSSEL = (pstcConfig->u8OBSSelection & 0x1F); /* --------------- Access registers ---------------- */ /* Disable IRQs for protected sequences */ IRQ_DISABLE_LOCAL(); /* Clear interrupt flags */ SWDG_PROT = SWDG_PROT_UNLOCK; SWDG_INTCLR_IRQCLR = 1; SWDG_PROT = SWDG_PROT_UNLOCK; SWDG_INTCLR_NMICLR = 1; /* Clear reset cause */ SWDG_PROT = SWDG_PROT_UNLOCK; SWDG_RSTCAUSE = 0x00000000; /* Set the configuration of the interrupt */ SWDG_PROT = SWDG_PROT_UNLOCK; SWDG_INT = unInt.u32Register; /* Set WDG trigger values */ SWDG_PROT = SWDG_PROT_UNLOCK; SWDG_TRG0CFG = pstcConfig->u8TriggerKey0; SWDG_PROT = SWDG_PROT_UNLOCK; SWDG_TRG1CFG = pstcConfig->u8TriggerKey1; /* Set window lower limit for RUN mode */ SWDG_PROT = SWDG_PROT_UNLOCK; SWDG_RUNLLS = pstcConfig->stcRunModeSettings.u32WindowLowerLimit; /* Set window upper limit for RUN mode */ SWDG_PROT = SWDG_PROT_UNLOCK; SWDG_RUNULS = pstcConfig->stcRunModeSettings.u32WindowUpperLimit; /* Set window lower limit for PSS mode */ SWDG_PROT = SWDG_PROT_UNLOCK; SWDG_PSSLLS = pstcConfig->stcPssModeSettings.u32WindowLowerLimit; /* Set window upper limit for PSS mode */ SWDG_PROT = SWDG_PROT_UNLOCK; SWDG_PSSULS = pstcConfig->stcPssModeSettings.u32WindowUpperLimit; /* Set delay cycle for Reset or NMI. */ SWDG_PROT = SWDG_PROT_UNLOCK; SWDG_RSTDLY_WDGRSTDLY = pstcConfig->u16ResetDelay; /* Set WDG configuration */ SWDG_PROT = SWDG_PROT_UNLOCK; SWDG_CFG = unCfg.u32Register; /* Lock WDG configuration */ SWDG_PROT = SWDG_PROT_UNLOCK; SWDG_CFG_LOCK = 1; /* Update RUN profile in order to switch the source clock of the SWDG */ /* Clear RUN profile done flag */ SYSC0_PROTKEYR = SYSC_PROTKEYR_UNLOCK; SYSC0_SYSICLR_RUNDFCLR0 = 1; /* Enable RUN profile update */ SYSC1_PROTKEYR = SYSC_PROTKEYR_UNLOCK; SYSC1_RUNENR_0_RUNEN1 = SYSC_TRGRUNCNTR_APPLY_PROFILE; /* Trigger to apply the RUN profile */ SYSC0_PROTKEYR = SYSC_PROTKEYR_UNLOCK; SYSC0_TRGRUNCNTR_APPLY_RUN = SYSC_TRGRUNCNTR_APPLY_PROFILE; while (SYSC0_SYSSTSR_RUNSTS0 == 1) { /* Wait until the RUN profile is applied */ } /* restore IRQ state */ IRQ_RESTORE(); /* SWDG setup completed */ return Ok; } /** ***************************************************************************** ** \brief Return the SWDG reset cause ** ** The last WDG reset cause will be cleared by Swdg_Init(). ** If this function is called after Swdg_Init(), it will always return "no cause". ** ** \pre Must be run before calling Swdg_Init() ** ** \param [out] pstcResetCause Returns previous SWDG reset cause. ** ** \retval Ok Getting of reset cause is successful ** \retval ErrorInvalidParameter If Swdg_GetResetCause#pstcResetCause is NULL *****************************************************************************/ en_result_t Swdg_GetResetCause(stc_swdg_reset_cause_t* pstcResetCause) { /* --------------- Check parameters and conditions ---------------- */ if (pstcResetCause == NULL) { return ErrorInvalidParameter; } /* --------------- Access registers ---------------- */ pstcResetCause->bSwdgTriggerWhileUnlocked = (SWDG_RSTCAUSE_RSTCAUSE4 == 0) ? FALSE : TRUE; pstcResetCause->bSwdgTriggerTooEarly = (SWDG_RSTCAUSE_RSTCAUSE3 == 0) ? FALSE : TRUE; pstcResetCause->bSwdgNotTriggered = (SWDG_RSTCAUSE_RSTCAUSE2 == 0) ? FALSE : TRUE; pstcResetCause->bSwdgTriggerSequenceViolated = (SWDG_RSTCAUSE_RSTCAUSE1 == 0) ? FALSE : TRUE; pstcResetCause->bSwdgWrongTriggerValue = (SWDG_RSTCAUSE_RSTCAUSE0 == 0) ? FALSE : TRUE; return Ok; } /** ***************************************************************************** ** \brief Clear the SWDG counter ** ** \pre Must be run after calling Swdg_Init() ** ** \param [in] u8TrgVal0,1 Trigger values of the SWDG counter clearing. ** This values must be set to the same value as ** SWDG_TRG0CFG, SWDG_TRG1CFG. ** ** \retval Ok Clearing the SWDG is successful. ** \retval Error The SWDG counter has not reached window lower limit. *****************************************************************************/ en_result_t Swdg_Clear(uint8_t u8TrgVal0, uint8_t u8TrgVal1) { uint32_t cnt; /* --------------- Check parameters and conditions ---------------- */ cnt = Swdg_GetCounterValue(); if (cnt < SWDG_RUNLLS ) { return Error; } /* --------------- Access registers ---------------- */ /* Clear SWDG */ IRQ_DISABLE_LOCAL(); SWDG_TRG0 = u8TrgVal0; SWDG_TRG1 = u8TrgVal1; IRQ_RESTORE(); return Ok; } /** ***************************************************************************** ** \brief Get SWDG counter value ** ** This function returns the current count value of the SWDG counter ** register. ** ** \retval Current watchdog counter value *****************************************************************************/ uint32_t Swdg_GetCounterValue(void) { /* --------------- Access registers ---------------- */ return SWDG_CNT; } /*! @} */ #endif /* PDL_PERIPHERAL_SWDG_ACTIVE */ /*****************************************************************************/ /* EOF (not truncated) */ /*****************************************************************************/