blob: 4cc1f3ddd75321e2f800f05da93e1412f45c1c5c [file] [log] [blame]
/***************************************************************************//**
* \file cy_syspm.c
* \version 2.30
*
* This driver provides the source code for API power management.
*
********************************************************************************
* \copyright
* Copyright 2016-2018, Cypress Semiconductor Corporation. All rights reserved.
* SPDX-License-Identifier: Apache-2.0
*******************************************************************************/
#include "cy_syspm.h"
#include "cy_ipc_drv.h"
#include "cy_ipc_sema.h"
#include "cy_ipc_pipe.h"
#include "cy_prot.h"
/*******************************************************************************
* Internal Variables
*******************************************************************************/
static cy_stc_syspm_callback_t* callbackRoot = NULL;
static uint32_t curRegisteredCallbacks = 0U;
static bool wasEventSent = false;
/*******************************************************************************
* Internal Functions
*******************************************************************************/
/** This internal structure stores non-retained registers in the Deep Sleep
* power mode.
*/
typedef struct
{
/* The UDB interface control register */
uint32_t CY_UDB_UDBIF_BANK_CTL_REG;
/* The UDB bank control registers */
uint32_t CY_UDB_BCTL_MDCLK_EN_REG;
uint32_t CY_UDB_BCTL_MBCLK_EN_REG;
uint32_t CY_UDB_BCTL_BOTSEL_L_REG;
uint32_t CY_UDB_BCTL_BOTSEL_U_REG;
uint32_t CY_UDB_BCTL_QCLK_EN0_REG;
uint32_t CY_UDB_BCTL_QCLK_EN1_REG;
uint32_t CY_UDB_BCTL_QCLK_EN2_REG;
} cy_stc_syspm_backup_regs_t;
static void SaveRegisters(cy_stc_syspm_backup_regs_t *regs);
static void RestoreRegisters(cy_stc_syspm_backup_regs_t const *regs);
static void EnterDeepSleep(cy_en_syspm_waitfor_t waitFor);
static void SetReadMarginTrimUlp(void);
static void SetReadMarginTrimLp(void);
static void SetWriteAssistTrimUlp(void);
static void SetWriteAssistTrimLp(void);
static bool IsVoltageChangePossible(void);
static cy_en_syspm_status_t WriteVoltageBitForFlash(uint32_t value);
#if defined(CY_DEVICE_PSOC6ABLE2) && !defined(CY_PSOC6ABLE2_REV_0A_SUPPORT_DISABLE)
static void Cy_EnterDeepSleep(cy_en_syspm_waitfor_t waitFor);
#endif /* defined(CY_DEVICE_PSOC6ABLE2) && !defined(CY_PSOC6ABLE2_REV_0A_SUPPORT_DISABLE) */
/*******************************************************************************
* Internal Defines
*******************************************************************************/
#if defined(CY_DEVICE_PSOC6ABLE2) && !defined(CY_PSOC6ABLE2_REV_0A_SUPPORT_DISABLE)
/** The internal define for clock divider */
#define SYSPM_CLK_DIVIDER (9U)
/* Mask for the fast clock divider value */
#define SYSPM_FAST_CLK_DIV_Msk (0xFF000000UL)
/* Position for the fast clock divider value */
#define SYSPM_FAST_CLK_DIV_Pos (24UL)
/* Mask for the slow clock divider value */
#define SYSPM_SLOW_CLK_DIV_Msk (0x00FF0000UL)
/* Position for the slow clock divider value */
#define SYSPM_SLOW_CLK_DIV_Pos (16UL)
#if (CY_CPU_CORTEX_M4)
#define CUR_CORE_DP_MASK (0x01UL)
#define OTHER_CORE_DP_MASK (0x02UL)
#else
#define CUR_CORE_DP_MASK (0x02UL)
#define OTHER_CORE_DP_MASK (0x01UL)
#endif
#endif /* defined(CY_DEVICE_PSOC6ABLE2) && !defined(CY_PSOC6ABLE2_REV_0A_SUPPORT_DISABLE) */
/** The define for the current active bus master */
#if (CY_CPU_CORTEX_M0P)
#define ACTIVE_BUS_MASTER CPUSS_MS_ID_CM0
#else
#define ACTIVE_BUS_MASTER CPUSS_MS_ID_CM4
#endif /* (CY_CPU_CORTEX_M0P) */
/* Slow control register */
#define TST_DDFT_SLOW_CTL_REG (*(volatile uint32_t *) 0x40260108U)
/* Fast control register */
#define TST_DDFT_FAST_CTL_REG (*(volatile uint32_t *) 0x40260104U)
/* The UDB placement on MMIO slave level */
/* NEED UPDATE FOR SL */
#define PERI_UDB_SLAVE_ENABLED ((uint32_t) (1UL << (cy_device->sysPmMmioUdbSlaveNr)))
/** The definition for the delay of the LDO after its output
* voltage is changed
*/
#define LDO_STABILIZATION_DELAY_US (9U)
/** Define to indicate that a 10 us delay is needed */
#define NEED_DELAY (0x0U)
/** Define to set the IMO to count a 10 us delay after exiting Deep Sleep */
#define TST_DDFT_SLOW_CTL_MASK (0x00001F1EU)
/** Slow output register */
#define CLK_OUTPUT_SLOW_MASK (0x06U)
/** Slow control register */
#define TST_DDFT_FAST_CTL_MASK (62U)
/** Load value for the timer to count delay after exiting Deep Sleep */
#define IMO_10US_DELAY (68U)
/** Define to indicate that the clock is finished counting */
#define CLK_CAL_CNT1_DONE ((uint32_t) ((uint32_t) 1U << CLK_CAL_CNT1_DONE_POS))
/** Define to indicate that the clock is finished counting */
#define CLK_CAL_CNT1_DONE_POS (31U)
/** Define to indicate that a 10 us delay was done after exiting Deep Sleep */
#define DELAY_DONE (0xAAAAAAAAU)
/** Define for transitional 0.95 V for the LDO regulator */
#define LDO_OUT_VOLTAGE_0_95V (0x0BU)
/** Define for transitional 1.1 V for the LDO regulator */
#define LDO_OUT_VOLTAGE_1_1V (0x17U)
/** Define for transitional 1.15 V for the LDO regulator */
#define LDO_OUT_VOLTAGE_1_15V (0x1BU)
/** The definition for the delay of the Buck supply regulator
* stabilization after it was configured with enabled Buck output 1 */
#define BUCK_INIT_STABILIZATION_US (900U)
/** The definition for the delay of the Buck supply regulator
* stabilization after it was configured with enabled Buck
* output 2 only
*/
#define BUCK_OUT2_INIT_DELAY_US (600U)
/** The definition for the delay of the Buck regulator after its output
* voltage is changed
*/
#define BUCK_OUT2_STABILIZATION_DELAY_US (200U)
/** Define for transitional 0.95 V for buck regulator */
#define BUCK_OUT1_VOLTAGE_0_95V (3U)
/* These defines will be removed and SFLASH registers used instead */
/** Trim define for ROM in LP mode */
#define CPUSS_TRIM_ROM_LP (0x00000013U)
/** Trim define for RAM in LP mode */
#define CPUSS_TRIM_RAM_LP (0x00004013U)
/** Trim define for ROM in ULP mode */
#define CPUSS_TRIM_ROM_ULP (0x00000012U)
/** Trim define for RAM in ULP mode */
#define CPUSS_TRIM_RAM_ULP (0x00006012U)
/** IPC notify bit for IPC_STRUCT0 */
#define SYSPM_IPC_NOTIFY_STRUCT0 (0x1UL << CY_IPC_INTR_SYSCALL1)
/** The define of bits position of the syscall return status */
#define SYSPM_SYSCALL_STATUS_MASK (0xFF000000U)
/** The define for the success return status of the syscall */
#define SYSPM_SYSCALL_STATUS_SUCCESS (0xA0000000U)
/* The define for device TO *B Revision ID */
#define SYSPM_DEVICE_REV_0B (0x22U)
/* The pointer to the Cy_EnterDeepSleep() function in the ROM */
#define CY_SYSPM_ROM_ENTER_DEEP_SLEEP_ADDR (*(uint32_t *) 0x00000D30UL)
/* The define to call the ROM Cy_EnterDeepSleep() function.
* The ROM Cy_EnterDeepSleep() function prepares the system for the Deep Sleep
* and restores the system after wakeup from the Deep Sleep. */
typedef void (*cy_cb_syspm_deep_sleep_t)(cy_en_syspm_waitfor_t waitFor, bool *wasEventSent);
#define EnterDeepSleepSrom(waitFor, wasEventSent) \
((cy_cb_syspm_deep_sleep_t) CY_SYSPM_ROM_ENTER_DEEP_SLEEP_ADDR)((waitFor), &(wasEventSent))
/* Mask for the read assist bits */
#define CPUSS_TRIM_RAM_CTL_RA_MASK ((uint32_t) 0x3U << 8U)
/** The define for SROM to indicate that flash voltage bit should be set */
#define SET_FLASH_VOLTAGE_BIT (0x0C000003U)
/** The define for SROM to indicate that flash voltage bit should be cleared */
#define CLEAR_FLASH_VOLTAGE_BIT (0x0C000001U)
/** The define for SROM to indicate that flash voltage bit should be set */
#define SET_FLASH_VOLTAGE_BIT_PSOC6ABLE2 (0x30000101U)
/** The define for SROM to indicate that flash voltage bit should be cleared */
#define CLEAR_FLASH_VOLTAGE_BIT_PSOC6ABLE2 (0x30000001U)
/** The wait time for transition of the device from the Active into
* the LPActive
*/
#define ACTIVE_TO_LP_DELAY_US (1U)
/** The wait delay time which occurs before the Active reference is settled.
* This delay is used in transition of the device from Active into the LPActive
* low-power mode
*/
#define LP_TO_ACTIVE_DELAY_BEFORE_TR_US (8U)
/** The wait delay time which occurs after the Active reference is settled.
* This delay is used in transition the device from Active into the LPActive
* mode
*/
#define LP_TO_ACTIVE_DELAY_AFTER_TR_US (1U)
/** The internal define of the tries number in the Cy_SysPm_ExitLowPowerMode()
* function
*/
#define WAIT_DELAY_TRYES (100U)
/** The define of retained power mode of the CM4 */
#define CM4_PWR_STS_RETAINED (2UL)
/*******************************************************************************
* Function Name: Cy_SysPm_ReadStatus
****************************************************************************//**
*
* Reads the status of the core(s).
*
* \return The current power mode. See \ref group_syspm_return_status.
*
* \funcusage
* \snippet syspm/syspm_2_20_sut_01.cydsn/main_cm4.c snippet_Cy_SysPm_ReadStatus
*
*******************************************************************************/
uint32_t Cy_SysPm_ReadStatus(void)
{
uint32_t pmStatus = 0U;
if (CY_IP_M4CPUSS != 0U)
{
/* Check whether CM4 is in Deep Sleep mode*/
if((0U != _FLD2VAL(CPUSS_CM4_STATUS_SLEEPING, CPUSS_CM4_STATUS)) &&
(0U != _FLD2VAL(CPUSS_CM4_STATUS_SLEEPDEEP, CPUSS_CM4_STATUS)))
{
pmStatus |= CY_SYSPM_STATUS_CM4_DEEPSLEEP;
}
/* Check whether CM4 is in Sleep mode*/
else if(0U != _FLD2VAL(CPUSS_CM4_STATUS_SLEEPING, CPUSS_CM4_STATUS))
{
pmStatus |= CY_SYSPM_STATUS_CM4_SLEEP;
}
else
{
pmStatus |= CY_SYSPM_STATUS_CM4_ACTIVE;
}
}
/* Check whether CM0p is in Deep Sleep mode*/
if((0U != _FLD2VAL(CPUSS_CM0_STATUS_SLEEPING, CPUSS_CM0_STATUS)) &&
(0U != _FLD2VAL(CPUSS_CM0_STATUS_SLEEPDEEP, CPUSS_CM0_STATUS)))
{
pmStatus |= (uint32_t) CY_SYSPM_STATUS_CM0_DEEPSLEEP;
}
/* Check whether CM0p is in Sleep mode*/
else if (0U != _FLD2VAL(CPUSS_CM0_STATUS_SLEEPING, CPUSS_CM0_STATUS))
{
pmStatus |= CY_SYSPM_STATUS_CM0_SLEEP;
}
else
{
pmStatus |= CY_SYSPM_STATUS_CM0_ACTIVE;
}
/* Check whether the device is in Low Power mode by reading
* the Active Reference status
*/
if(0U != (_FLD2VAL(SRSS_PWR_CTL_ACT_REF_DIS, SRSS_PWR_CTL)))
{
pmStatus |= CY_SYSPM_STATUS_SYSTEM_LOWPOWER;
}
return(pmStatus);
}
/*******************************************************************************
* Function Name: Cy_SysPm_Sleep
****************************************************************************//**
*
* Sets a CPU core to Sleep mode.
*
* Puts the core into Sleep power mode, if none of callback functions were
* registered.
*
* For more details about switching into Sleep power mode and debug,
* refer to the device TRM.
*
* If at least one callback function with the CY_SYSPM_SLEEP type was registered,
* the next algorithm is executed:
* Prior to entering Sleep mode, all callback functions of the CY_SYSPM_SLEEP
* type with the CY_SYSPM_CHECK_READY parameter are called. This allows the driver
* to signal whether it is ready to enter the Low Power mode. If any of the
* callbacks of the CY_SYSPM_SLEEP type with the CY_SYSPM_CHECK_READY parameter
* returns CY_SYSPM_FAIL, the remaining callback of the CY_SYSPM_SLEEP type with
* the CY_SYSPM_CHECK_READY parameter calls are skipped.
* After CY_SYSPM_FAIL, all the CY_SYSPM_SLEEP callbacks with
* the CY_SYSPM_CHECK_FAIL parameter are executed. These are the callbacks
* of the CY_SYSPM_SLEEP type with the CY_SYSPM_CHECK_READY
* parameter that were previously executed before getting CY_SYSPM_FAIL.
* The Sleep mode is not entered and the Cy_SysPm_Sleep() function returns
* CY_SYSPM_FAIL.
*
* If all of the callbacks of the CY_SYSPM_SLEEP type with the
* CY_SYSPM_CHECK_READY parameter calls return CY_SYSPM_SUCCESS, then all
* callbacks of the CY_SYSPM_SLEEP type with the CY_SYSPM_CHECK_FAIL parameters
* calls are skipped. Also, all callbacks of the CY_SYSPM_SLEEP type and
* CY_SYSPM_BEFORE_TRANSITION parameter calls are executed, allowing the
* peripherals to prepare for Sleep. The CPU then enters Sleep mode.
* This is a CPU-centric power mode. This means that the CPU has entered Sleep
* mode and its main clock is removed. It is identical to Active from a
* peripheral point of view. Any enabled interrupt can cause a wakeup from
* Sleep mode.
*
* After a wakeup from Sleep, all of the registered callbacks of the
* CY_SYSPM_SLEEP type and with the CY_SYSPM_AFTER_TRANSITION parameter are
* executed to return the peripherals to Active operation. The Cy_SysPm_Sleep()
* function returns CY_SYSPM_SUCCESS.
* No callbacks of the CY_SYSPM_SLEEP type with the CY_SYSPM_BEFORE_TRANSITION
* parameter or callbacks of the CY_SYSPM_SLEEP type and
* CY_SYSPM_AFTER_TRANSITION parameter callbacks are executed if Sleep mode
* is not entered.
*
* \note The last callback that returned CY_SYSPM_FAIL is not executed with the
* CY_SYSPM_CHECK_FAIL parameter because of the FAIL.
*
* The return values from executed callback functions with the
* CY_SYSPM_CHECK_FAIL, CY_SYSPM_BEFORE_TRANSITION, and CY_SYSPM_AFTER_TRANSITION
* modes are ignored.
*
* \ref cy_en_syspm_callback_mode_t, except the CY_SYSPM_CHECK_READY, are ignored
*
* \param waitFor Selects wait for action. See \ref cy_en_syspm_waitfor_t.
*
* \return
* Entered status, see \ref cy_en_syspm_status_t.
*
* \sideeffect
* This function clears the Event Register of CM4 core after wakeup from WFE.
*
* \funcusage
* \snippet syspm/syspm_2_20_sut_01.cydsn/main_cm4.c snippet_Cy_SysPm_Sleep
*
*******************************************************************************/
cy_en_syspm_status_t Cy_SysPm_Sleep(cy_en_syspm_waitfor_t waitFor)
{
uint32_t interruptState;
cy_en_syspm_status_t retVal = CY_SYSPM_SUCCESS;
CY_ASSERT_L3(CY_SYSPM_IS_WAIT_FOR_VALID(waitFor));
/* Call registered callback functions with CY_SYSPM_CHECK_READY parameter */
if(0U != curRegisteredCallbacks)
{
retVal = Cy_SysPm_ExecuteCallback(CY_SYSPM_SLEEP, CY_SYSPM_CHECK_READY);
}
/* The device (core) can switch into the sleep power mode only when
* all executed registered callback functions with the CY_SYSPM_CHECK_READY
* parameter returned CY_SYSPM_SUCCESS.
*/
if(retVal == CY_SYSPM_SUCCESS)
{
/* Call the registered callback functions with
* CY_SYSPM_BEFORE_TRANSITION parameter. The return value should be
* CY_SYSPM_SUCCESS.
*/
interruptState = Cy_SysLib_EnterCriticalSection();
if(0U != curRegisteredCallbacks)
{
(void) Cy_SysPm_ExecuteCallback(CY_SYSPM_SLEEP, CY_SYSPM_BEFORE_TRANSITION);
}
/* The CPU enters the Sleep power mode upon execution of WFI/WFE */
SCB_SCR = _CLR_SET_FLD32U((SCB_SCR), SCB_SCR_SLEEPDEEP, 0U);
if(waitFor != CY_SYSPM_WAIT_FOR_EVENT)
{
__WFI();
}
else
{
__WFE();
#if (CY_CPU_CORTEX_M4)
/* For the CM4 core, the WFE instruction is called twice.
* The second WFE call clears the Event register of CM4 core.
* Cypress ID #279077.
*/
if(wasEventSent)
{
__WFE();
}
wasEventSent = true;
#endif /* (CY_CPU_CORTEX_M4) */
}
Cy_SysLib_ExitCriticalSection(interruptState);
/* Call the registered callback functions with the
* CY_SYSPM_AFTER_TRANSITION parameter. The return value should be
* CY_SYSPM_SUCCESS.
*/
if(0U != curRegisteredCallbacks)
{
(void) Cy_SysPm_ExecuteCallback(CY_SYSPM_SLEEP, CY_SYSPM_AFTER_TRANSITION);
}
}
else
{
/* Execute callback functions with the CY_SYSPM_CHECK_FAIL parameter to
* undo everything done in the callback with the CY_SYSPM_CHECK_READY
* parameter. The return value should be CY_SYSPM_SUCCESS.
*/
(void) Cy_SysPm_ExecuteCallback(CY_SYSPM_SLEEP, CY_SYSPM_CHECK_FAIL);
retVal = CY_SYSPM_FAIL;
}
return retVal;
}
/*******************************************************************************
* Function Name: Cy_SysPm_DeepSleep
****************************************************************************//**
*
* Sets a CPU core to the Deep Sleep mode.
*
* Puts the core into the Deep Sleep power mode. Prior to entering the Deep Sleep
* mode, all callbacks of the CY_SYSPM_DEEPSLEEP type with the
* CY_SYSPM_CHECK_READY parameter registered callbacks are called, allowing the
* driver to signal whether it is ready to enter the power mode. If any
* CY_SYSPM_DEEPSLEEP type with the CY_SYSPM_CHECK_READY parameter call returns
* CY_SYSPM_FAIL, the remaining callback CY_SYSPM_DEEPSLEEP type with the
* CY_SYSPM_CHECK_READY parameter calls are skipped. After a CY_SYSPM_FAIL, all
* of the callbacks of the CY_SYSPM_DEEPSLEEP type with the CY_SYSPM_CHECK_FAIL
* parameter are executed that correspond to the callbacks with
* CY_SYSPM_DEEPSLEEP type with CY_SYSPM_CHECK_READY parameter calls that
* occurred up to the point of failure.
* The Deep Sleep mode is not entered and the Cy_SysPm_DeepSleep() function
* returns CY_SYSPM_FAIL.
*
* If all callbacks of the CY_SYSPM_DEEPSLEEP type with the CY_SYSPM_CHECK_READY
* parameter calls return CY_SYSPM_SUCCESS, then all callbacks of the
* CY_SYSPM_DEEPSLEEP type with the CY_SYSPM_CHECK_FAIL parameter calls are
* skipped and all callbacks of the CY_SYSPM_DEEPSLEEP type with the
* CY_SYSPM_BEFORE_TRANSITION parameter calls are executed, allowing the
* peripherals to prepare for Deep Sleep.
* The Deep Sleep mode is then entered. Any enabled interrupt can cause a wakeup
* from the Deep Sleep mode.
*
* \note The last callback which returned CY_SYSPM_FAIL is not executed with the
* CY_SYSPM_CHECK_FAIL parameter because of the FAIL.
*
* The return values from executed callback functions with the
* CY_SYSPM_CHECK_FAIL, CY_SYSPM_BEFORE_TRANSITION, and CY_SYSPM_AFTER_TRANSITION
* modes are ignored.
*
* If the firmware attempts to enter this mode before the system is ready (that
* is, when PWR_CONTROL.LPM_READY = 0), then the device will go into the (LP)
* Sleep mode instead and automatically enter Deep Sleep mode when the
* system is ready.
*
* The system puts the whole device into Deep Sleep mode when all the
* processor(s) is (are) in Deep Sleep, there are no busy peripherals, the
* debugger is not active, and the Deep Sleep circuits are
* ready (PWR_CONTROL.LPM_READY=1).
*
* The peripherals that do not need a clock or that receive a clock from their
* external interface (e.g. I2C/SPI) continue operating. All circuits using the
* current from Vccdpslp supply are under the current limitation, which is
* controlled by the Deep Sleep regulator.
*
* Wakeup occurs when an interrupt asserts from a Deep Sleep active peripheral.
* For more details, see the corresponding peripheral's datasheet.
*
* \note
* For multi-core devices, the second core, which did not participate in
* device wakeup, continues to execute the Deep Sleep instructions. Any Deep Sleep
* capable interrupt routed to this core can wake it.
*
* For more details about switching into the Deep Sleep power mode and debug,
* refer to the device TRM.
*
* A normal wakeup from the Deep Sleep power mode returns to either LPActive or
* Active, depending on the previous state and programmed behavior for the
* particular wakeup interrupt.
*
* After wakeup from Deep Sleep, all of the registered callbacks with
* CY_SYSPM_DEEPSLEEP type with CY_SYSPM_AFTER_TRANSITION are executed to return
* peripherals to Active operation. The Cy_SysPm_DeepSleep() function returns
* CY_SYSPM_SUCCESS. No callbacks are executed with CY_SYSPM_DEEPSLEEP type with
* CY_SYSPM_BEFORE_TRANSITION or CY_SYSPM_AFTER_TRANSITION parameter, if
* Deep Sleep mode was not entered.
*
* \param waitFor Selects wait for action. See \ref cy_en_syspm_waitfor_t.
*
* \sideeffect
* This side effect is applicable only for devices with UDB IP block available.
* You can obtain unpredictable behavior of the UDB block after the device wakeup
* from Deep Sleep.
* Unpredictable behavior scenario:
* * The first core saves non-retained UDB configuration registers and goes into
* the Deep Sleep (Cy_SysPm_DeepSleep() function).
* * These non-retained UDB configuration registers are modified in runtime by
* another (second) active core.
* * The second core saves non-retained UDB configuration registers and goes into
* the Deep Sleep (Cy_SysPm_DeepSleep() function).
* These conditions save different values of the non-retained UDB configuration
* registers. The prevented scenario: on the first core wakeup, these registers
* are restored by the values saved on the first core. After the second core
* wakeup, these registers are "reconfigured" by the values saved on the second
* core.
* Be aware of this situation.
*
* \sideeffect
* This function clears the Event Register of CM4 core after wakeup from WFE.
*
* \sideeffect
* This side effect is applicable only for rev-08 of the CY8CKIT-062.
* The function changes the slow and fast clock dividers to
* SYSPM_CLK_DIVIDER right before entering into Deep Sleep and restores
* these dividers after wakeup.
*
* \return
* Entered status, see \ref cy_en_syspm_status_t.
*
* \note
* The FLL/PLL are not restored right before the CPU starts executing the
* instructions after Deep Sleep. This can affect the peripheral which is
* driven by PLL/FLL. Ensure that the PLL/FLL were properly restored (locked)
* after the wakeup from Deep Sleep. Refer to the
* \ref group_sysclk driver documentation driver for the information how to
* read the PLL/FLL lock statuses.
*
* \funcusage
* \snippet syspm/syspm_2_20_sut_01.cydsn/main_cm4.c snippet_Cy_SysPm_DeepSleep
*
*******************************************************************************/
cy_en_syspm_status_t Cy_SysPm_DeepSleep(cy_en_syspm_waitfor_t waitFor)
{
uint32_t interruptState;
cy_en_syspm_status_t retVal = CY_SYSPM_SUCCESS;
CY_ASSERT_L3(CY_SYSPM_IS_WAIT_FOR_VALID(waitFor));
/* Call the registered callback functions with
* the CY_SYSPM_CHECK_READY parameter.
*/
if(0U != curRegisteredCallbacks)
{
retVal = Cy_SysPm_ExecuteCallback(CY_SYSPM_DEEPSLEEP, CY_SYSPM_CHECK_READY);
}
/* The device (core) can switch into the Deep Sleep power mode only when
* all executed registered callback functions with the CY_SYSPM_CHECK_READY
* parameter returned CY_SYSPM_SUCCESS.
*/
if(retVal == CY_SYSPM_SUCCESS)
{
/* Call the registered callback functions with the
* CY_SYSPM_BEFORE_TRANSITION parameter. The return value should be
* CY_SYSPM_SUCCESS.
*/
interruptState = Cy_SysLib_EnterCriticalSection();
if(0U != curRegisteredCallbacks)
{
(void) Cy_SysPm_ExecuteCallback(CY_SYSPM_DEEPSLEEP, CY_SYSPM_BEFORE_TRANSITION);
}
static cy_stc_syspm_backup_regs_t regs;
if (0U != cy_device->udbPresent)
{
/* Check whether the UDB disabled on MMIO level */
if (0UL != (PERI_GR_SL_CTL(cy_device->sysPmMmioUdbGroupNr) & PERI_UDB_SLAVE_ENABLED))
{
/* Save non-retained registers */
SaveRegisters(&regs);
}
}
/* Different device families and revisions have a different Deep Sleep entries */
if (Cy_SysLib_GetDevice() == CY_SYSLIB_DEVICE_PSOC6ABLE2)
{
#if defined(CY_DEVICE_PSOC6ABLE2) && !defined(CY_PSOC6ABLE2_REV_0A_SUPPORT_DISABLE)
if (CY_SYSLIB_DEVICE_REV_0A == (uint32_t) Cy_SysLib_GetDeviceRevision())
{
Cy_EnterDeepSleep(waitFor);
}
else
#endif /* defined(CY_DEVICE_PSOC6ABLE2) && !defined(CY_PSOC6ABLE2_REV_0A_SUPPORT_DISABLE) */
{
if ((uint32_t) Cy_SysLib_GetDeviceRevision() > SYSPM_DEVICE_REV_0B)
{
/* The core (system) enters Deep Sleep and wakes up in the SROM */
EnterDeepSleepSrom(waitFor, wasEventSent);
}
else
{
/* Set the core into Deep Sleep using RAM function */
EnterDeepSleep(waitFor);
}
}
}
else
{
#if (CY_CPU_CORTEX_M4)
/* Repeat the WFI/WFE instruction if a wake up was not intended.
* Cypress ID #272909
*/
do
{
#endif /* (CY_CPU_CORTEX_M4) */
/* The CPU enters Deep Sleep mode upon execution of WFI/WFE */
SCB_SCR |= SCB_SCR_SLEEPDEEP_Msk;
if(waitFor != CY_SYSPM_WAIT_FOR_EVENT)
{
__WFI();
}
else
{
__WFE();
#if (CY_CPU_CORTEX_M4)
/* Call the WFE instruction twice to clear the Event register
* of the CM4 core. Cypress ID #279077
*/
if(wasEventSent)
{
__WFE();
}
wasEventSent = true;
#endif /* (CY_CPU_CORTEX_M4) */
}
#if (CY_CPU_CORTEX_M4)
} while (_FLD2VAL(CPUSS_CM4_PWR_CTL_PWR_MODE, CPUSS_CM4_PWR_CTL) == CM4_PWR_STS_RETAINED);
#endif /* (CY_CPU_CORTEX_M4) */
}
if (0U != cy_device->udbPresent)
{
/* Do not restore the UDB if it is disabled on MMIO level */
if (0UL != (PERI_GR_SL_CTL(cy_device->sysPmMmioUdbGroupNr) & PERI_UDB_SLAVE_ENABLED))
{
/* Restore non-retained registers */
RestoreRegisters(&regs);
}
}
Cy_SysLib_ExitCriticalSection(interruptState);
/* Call the registered callback functions with the CY_SYSPM_AFTER_TRANSITION
* parameter. The return value should be CY_SYSPM_SUCCESS.
*/
if(0U != curRegisteredCallbacks)
{
(void) Cy_SysPm_ExecuteCallback(CY_SYSPM_DEEPSLEEP, CY_SYSPM_AFTER_TRANSITION);
}
}
else
{
/* Execute callback functions with the CY_SYSPM_CHECK_FAIL parameter to
* undo everything done in the callback with the CY_SYSPM_CHECK_READY
* parameter. The return value should be CY_SYSPM_SUCCESS.
*/
(void) Cy_SysPm_ExecuteCallback(CY_SYSPM_DEEPSLEEP, CY_SYSPM_CHECK_FAIL);
retVal = CY_SYSPM_FAIL;
}
return retVal;
}
/*******************************************************************************
* Function Name: Cy_SysPm_Hibernate
****************************************************************************//**
*
* Sets the device into Hibernate mode.
*
* Puts the core into the Hibernate power mode. Prior to entering Hibernate
* mode, all callbacks of the CY_SYSPM_HIBERNATE type are executed.
* First, callbacks of the CY_SYSPM_HIBERNATE type and with
* CY_SYSPM_CHECK_READY parameter are called, allowing the driver to signal if it
* is not ready to enter the power mode. If any of the callbacks of the
* CY_SYSPM_HIBERNATE type with the CY_SYSPM_CHECK_READY parameter call returns
* CY_SYSPM_FAIL, the remaining CY_SYSPM_HIBERNATE callbacks with the
* CY_SYSPM_CHECK_READY parameter calls are skipped. After CY_SYSPM_FAIL, all
* of the CY_SYSPM_HIBERNATE callbacks with CY_SYSPM_CHECK_FAIL parameter are
* executed that correspond to the CY_SYSPM_HIBERNATE callbacks with
* CY_SYSPM_CHECK_READY parameter calls that occurred up to the point of failure.
* Hibernate mode is not entered and the Cy_SysPm_Hibernate() function
* returns CY_SYSPM_FAIL.
*
* If all CY_SYSPM_HIBERNATE callbacks with the CY_SYSPM_CHECK_READY parameter
* calls return CY_SYSPM_SUCCESS, then all CY_SYSPM_HIBERNATE callbacks with
* CY_SYSPM_CHECK_FAIL calls are skipped and all CY_SYSPM_HIBERNATE callbacks
* CY_SYSPM_BEFORE_TRANSITION parameter calls are executed allowing the
* peripherals to prepare for Hibernate. The I/O output state is frozen and
* Hibernate mode is then entered. In Hibernate mode, all internal supplies
* are off and no internal state is retained. There is no handshake with the
* CPUs and the chip will enter Hibernate immediately.
*
* The I/O output state is frozen and Hibernate mode is then
* entered. In Hibernate mode, all internal supplies are off and no
* internal state is retained.
* For multi-core devices there is no handshake with the CPUs and the chip
* will enter Hibernate power mode immediately.
*
* \note The last callback that returned CY_SYSPM_FAIL is not executed with the
* CY_SYSPM_CHECK_FAIL parameter because of the FAIL.
*
* The return values from executed callback functions with the
* CY_SYSPM_CHECK_FAIL, CY_SYSPM_BEFORE_TRANSITION, and CY_SYSPM_AFTER_TRANSITION
* modes are ignored.
*
* A wakeup from Hibernate is triggered by toggling the wakeup pin(s), a WDT
* match, or back-up domain alarm expiration, depending on how the they were
* configured. A wakeup causes a normal boot procedure.
* To configure the wakeup pin(s), a Digital Input Pin must be configured, and
* resistively pulled up or down to the inverse state of the wakeup polarity. To
* distinguish a wakeup from Hibernate mode and a general reset event, the
* Cy_SysLib_GetResetReason() function can be used. The wakeup pin and low-power
* comparators are active-low by default. The wakeup pin or the LPComparators
* polarity can be changed with the \ref Cy_SysPm_SetHibernateWakeupSource() function.
* This function call will not return if Hibernate mode is entered.
* The CY_SYSPM_HIBERNATE callbacks with the CY_SYSPM_AFTER_TRANSITION parameter
* are never executed.
*
* This function freezes the I/O cells implicitly. Entering
* Hibernate mode before freezing the I/O cells is not possible. The I/O cells remain frozen
* after waking from Hibernate mode until the firmware unfreezes them
* with a \ref Cy_SysPm_IoUnfreeze() function call.
*
* \return
* Entered status, see \ref cy_en_syspm_status_t.
*
* \funcusage
* \snippet syspm/syspm_2_20_sut_01.cydsn/main_cm4.c snippet_Cy_SysPm_Hibernate
*
*******************************************************************************/
cy_en_syspm_status_t Cy_SysPm_Hibernate(void)
{
cy_en_syspm_status_t retVal = CY_SYSPM_SUCCESS;
/* Call the registered callback functions with the
* CY_SYSPM_CHECK_READY parameter
*/
if(0U != curRegisteredCallbacks)
{
retVal = Cy_SysPm_ExecuteCallback(CY_SYSPM_HIBERNATE, CY_SYSPM_CHECK_READY);
}
/* The device (core) can switch into Hibernate power mode only when
* all executed registered callback functions with CY_SYSPM_CHECK_READY
* parameter returned CY_SYSPM_SUCCESS.
*/
if(retVal == CY_SYSPM_SUCCESS)
{
/* Call registered callback functions with CY_SYSPM_BEFORE_TRANSITION
* parameter. Return value should be CY_SYSPM_SUCCESS.
*/
(void) Cy_SysLib_EnterCriticalSection();
if(0U != curRegisteredCallbacks)
{
(void) Cy_SysPm_ExecuteCallback(CY_SYSPM_HIBERNATE, CY_SYSPM_BEFORE_TRANSITION);
}
/* Preserve the token that will retain through a wakeup sequence
* thus could be used by Cy_SysLib_GetResetReason() to differentiate
* Wakeup from a general reset event.
* Preserve the wakeup source(s) configuration.
*/
SRSS_PWR_HIBERNATE =
(SRSS_PWR_HIBERNATE & CY_SYSPM_PWR_WAKEUP_HIB_MASK) | CY_SYSPM_PWR_TOKEN_HIBERNATE;
/* Freeze I/O-Cells to save I/O-Cell state */
Cy_SysPm_IoFreeze();
SRSS_PWR_HIBERNATE |= CY_SYSPM_PWR_SET_HIBERNATE;
/* Read register to make sure it is settled */
(void) SRSS_PWR_HIBERNATE;
/* Wait for transition */
__WFI();
/* The callback functions calls with the CY_SYSPM_AFTER_TRANSITION
* parameter in the Hibernate power mode are not applicable as device
* wake-up was made on device reboot.
*/
/* A wakeup from Hibernate is performed by toggling of the wakeup
* pins, or WDT matches, or Backup domain alarm expires. This depends on what
* item is configured in the hibernate register. After a wakeup event, a
* normal Boot procedure occurs.
* There is no need to exit from the critical section.
*/
}
else
{
/* Execute callback functions with the CY_SYSPM_CHECK_FAIL parameter to
* undo everything done in the callback with the CY_SYSPM_CHECK_READY
* parameter. The return value should be CY_SYSPM_SUCCESS.
*/
(void) Cy_SysPm_ExecuteCallback(CY_SYSPM_HIBERNATE, CY_SYSPM_CHECK_FAIL);
retVal = CY_SYSPM_FAIL;
}
return retVal;
}
/*******************************************************************************
* Function Name: Cy_SysPm_EnterLowPowerMode
****************************************************************************//**
*
* This function switches only the supply regulators into Low Power mode.
* You must configure
* clocks and/or peripherals to meet current load limitations in LP Active.
* For more details about power modes and current load limitations refer to
* the device technical reference manual (TRM).
*
* The LPActive mode is similar to the Active mode.
* The difference is that the current is limited and some functions have limited
* features/performance.
*
* The key feature of the Low Power mode is the limited current. Restrictions are
* placed on the clock frequencies and allow the peripherals to achieve
* a current limit.
*
* Before entering Low Power mode, you must configure the system so
* the total current drawn from Vccd is less that the value presented in the
* technical reference manual (TRM). Refer to the TRM for the maximum load for
* low power operation and clock limitations in Low Power mode with different
* core supply regulator voltages.
*
* * Peripherals can use the knowledge of the LPActive mode to make
* trade-offs that consume less current. For more details, see the corresponding
* peripherals' datasheet.
* * High-speed clock sources are available with the appropriate pre-divider
* settings to limit the system current.
* Refer to the TRM for the maximum frequency values for low power operation
* using different Core Regulators' output voltages.
*
* This function puts the device into Low Power mode. Prior to entering Low Power mode,
* all the registered CY_SYSPM_ENTER_LOWPOWER_MODE callbacks with CY_SYSPM_CHECK_READY
* parameter are called. This allows the driver to signal if it is not ready to
* enter Low Power mode. If any CY_SYSPM_ENTER_LOWPOWER_MODE callbacks with the
* CY_SYSPM_CHECK_READY parameter call returns CY_SYSPM_FAIL, the remaining
* CY_SYSPM_ENTER_LOWPOWER_MODE callbacks with the CY_SYSPM_CHECK_READY parameter
* calls are skipped.
*
* After a CY_SYSPM_FAIL, all of the CY_SYSPM_ENTER_LOWPOWER_MODE callbacks with
* CY_SYSPM_CHECK_FAIL parameter are executed that correspond to the
* CY_SYSPM_ENTER_LOWPOWER_MODE callbacks with CY_SYSPM_CHECK_READY parameter calls
* that occurred up to the point of failure. Low Power mode is not entered and
* the Cy_SysPm_EnterLowPowerMode() function returns CY_SYSPM_FAIL.
*
* If all CY_SYSPM_ENTER_LOWPOWER_MODE callbacks with the CY_SYSPM_CHECK_READY
* parameter calls return CY_SYSPM_SUCCESS, then all CY_SYSPM_ENTER_LOWPOWER_MODE
* callbacks with CY_SYSPM_CHECK_FAIL calls are skipped and all
* CY_SYSPM_ENTER_LOWPOWER_MODE callbacks with the CY_SYSPM_BEFORE_TRANSITION parameter
* calls are executed. This allows the peripherals to prepare for low power.
* Low Power mode is then entered.
*
* After entering Low Power mode, all of the registered
* CY_SYSPM_ENTER_LOWPOWER_MODE callbacks with the CY_SYSPM_AFTER_TRANSITION parameter
* are executed to complete preparing the peripherals for low power operation.
* The Cy_SysPm_EnterLowPowerMode() function returns CY_SYSPM_SUCCESS.
* No CY_SYSPM_ENTER_LOWPOWER_MODE callbacks with the CY_SYSPM_BEFORE_TRANSITION or
* CY_SYSPM_AFTER_TRANSITION parameter are executed, if Low Power mode is not
* entered.
*
* \note The last callback that returned CY_SYSPM_FAIL is not executed with
* the CY_SYSPM_CHECK_FAIL parameter because of the FAIL.
*
* The return values from executed callback functions with the
* CY_SYSPM_CHECK_FAIL, CY_SYSPM_BEFORE_TRANSITION, and CY_SYSPM_AFTER_TRANSITION
* modes are ignored.
*
* \note The callbacks are not executed if the device is already not in
* Low Power mode.
*
* \return
* See \ref cy_en_syspm_status_t. <br>
* CY_SYSPM_SUCCESS - Entered the LPActive mode or the device is already
* in LPActive.<br>
* CY_SYSPM_FAIL - The LPActive mode is not entered or low power circuits
* are not ready to enter Low Power mode.
*
* \funcusage
* \snippet syspm/syspm_2_20_sut_01.cydsn/main_cm4.c snippet_Cy_SysPm_EnterLowPowerMode
*
*******************************************************************************/
cy_en_syspm_status_t Cy_SysPm_EnterLowPowerMode(void)
{
uint32_t interruptState;
cy_en_syspm_status_t retVal = CY_SYSPM_SUCCESS;
/* Check whether device is in the low power mode. */
if(0U == (_FLD2VAL(SRSS_PWR_CTL_ACT_REF_DIS, SRSS_PWR_CTL)))
{
/* The entering into the low power mode is permitted when low
* power circuits are ready to enter into the low power mode.
*/
if(0U != _FLD2VAL(SRSS_PWR_CTL_LPM_READY, SRSS_PWR_CTL))
{
/* Call the registered callback functions with the
* CY_SYSPM_CHECK_READY parameter.
*/
if(0U != curRegisteredCallbacks)
{
retVal = Cy_SysPm_ExecuteCallback(CY_SYSPM_ENTER_LOWPOWER_MODE, CY_SYSPM_CHECK_READY);
}
/* The device (core) can switch into the low power mode only when
* all executed registered callback functions with the
* CY_SYSPM_CHECK_READY parameter returned CY_SYSPM_SUCCESS.
*/
if(retVal == CY_SYSPM_SUCCESS)
{
/* Call the registered callback functions with the
* CY_SYSPM_BEFORE_TRANSITION parameter. The return value
* should be CY_SYSPM_SUCCESS.
*/
interruptState = Cy_SysLib_EnterCriticalSection();
if(0U != curRegisteredCallbacks)
{
(void) Cy_SysPm_ExecuteCallback(CY_SYSPM_ENTER_LOWPOWER_MODE, CY_SYSPM_BEFORE_TRANSITION);
}
/* Configure the low-power operating mode for LDO regulator */
if(Cy_SysPm_LdoIsEnabled())
{
SRSS_PWR_CTL |= (_VAL2FLD(SRSS_PWR_CTL_LINREG_LPMODE, 1U) |
_VAL2FLD(SRSS_PWR_CTL_PORBOD_LPMODE, 1U) |
_VAL2FLD(SRSS_PWR_CTL_BGREF_LPMODE, 1U) |
_VAL2FLD(SRSS_PWR_CTL_VREFBUF_LPMODE, 1U) |
_VAL2FLD(SRSS_PWR_CTL_IREF_LPMODE, 1U));
}
else
{
/* Configure the low-power operating mode for Buck regulator */
SRSS_PWR_CTL |= (_VAL2FLD(SRSS_PWR_CTL_PORBOD_LPMODE, 1U) |
_VAL2FLD(SRSS_PWR_CTL_BGREF_LPMODE, 1U) |
_VAL2FLD(SRSS_PWR_CTL_VREFBUF_LPMODE, 1U) |
_VAL2FLD(SRSS_PWR_CTL_IREF_LPMODE, 1U));
}
/* This wait time allows the circuits to remove their dependence on
* the Active mode circuits, such as Active Reference.
*/
Cy_SysLib_DelayUs(ACTIVE_TO_LP_DELAY_US);
/* Disabling active reference */
SRSS_PWR_CTL |= _VAL2FLD(SRSS_PWR_CTL_ACT_REF_DIS, 1U);
Cy_SysLib_ExitCriticalSection(interruptState);
/* Call the registered callback functions with the
* CY_SYSPM_AFTER_TRANSITION parameter. The return value
* should be CY_SYSPM_SUCCESS.
*/
if(0U != curRegisteredCallbacks)
{
(void) Cy_SysPm_ExecuteCallback(CY_SYSPM_ENTER_LOWPOWER_MODE, CY_SYSPM_AFTER_TRANSITION);
}
}
else
{
/* Execute callback functions with the CY_SYSPM_CHECK_FAIL parameter to
* undo everything done in the callback with the CY_SYSPM_CHECK_READY
* parameter. The return value should be CY_SYSPM_SUCCESS.
*/
(void) Cy_SysPm_ExecuteCallback(CY_SYSPM_ENTER_LOWPOWER_MODE, CY_SYSPM_CHECK_FAIL);
retVal = CY_SYSPM_FAIL;
}
}
else
{
retVal = CY_SYSPM_FAIL;
}
}
else
{
/* Do nothing because the device is already in Low Power mode. */
}
return retVal;
}
/*******************************************************************************
* Function Name: Cy_SysPm_ExitLowPowerMode
****************************************************************************//**
*
* Exits the device from Low Power mode.
*
* Returns the device to the Active mode. In the Active power mode, the operating
* current can be increased to the normal mode limit. The clock frequencies also
* can be increased to the normal mode limit. Refer to the device TRM for the
* current and frequency limitations in the Active power mode.
*
* Prior to exiting Low Power mode, all the registered CY_SYSPM_EXIT_LOWPOWER_MODE
* callbacks with the CY_SYSPM_CHECK_READY parameter are called. This allows
* the driver to signal if it is not ready to exit
* Low Power mode. If any CY_SYSPM_EXIT_LOWPOWER_MODE callbacks with
* the CY_SYSPM_CHECK_READY parameter call returns CY_SYSPM_FAIL, the remaining
* CY_SYSPM_EXIT_LOWPOWER_MODE callbacks with the CY_SYSPM_CHECK_READY parameter calls
* are skipped. After a CY_SYSPM_FAIL, all of the CY_SYSPM_EXIT_LOWPOWER_MODE callbacks
* with CY_SYSPM_CHECK_FAIL parameter are executed that correspond to the
* CY_SYSPM_EXIT_LOWPOWER_MODE callbacks with CY_SYSPM_CHECK_READY parameter calls that
* occurred up to the point of failure. Active mode is not entered and the
* Cy_SysPm_ExitLowPowerMode() function returns CY_SYSPM_FAIL.
*
* If all CY_SYSPM_EXIT_LOWPOWER_MODE callbacks with CY_SYSPM_CHECK_READY calls return
* CY_SYSPM_SUCCESS, then all the CY_SYSPM_EXIT_LOWPOWER_MODE callbacks with
* the CY_SYSPM_CHECK_FAIL parameter calls are skipped and all
* CY_SYSPM_EXIT_LOWPOWER_MODE callbacks with the CY_SYSPM_BEFORE_TRANSITION parameter
* calls are executed allowing the peripherals to prepare for Active mode.
* Low Power mode is then exited.
*
* After exiting Low Power mode, all of the registered callbacks that have
* type CY_SYSPM_EXIT_LOWPOWER_MODE are executed with the CY_SYSPM_AFTER_TRANSITION
* parameter to complete preparing the peripherals for Active mode operation.
* The Cy_SysPm_ExitLowPowerMode() function returns CY_SYSPM_SUCCESS.
* No CY_SYSPM_EXIT_LOWPOWER_MODE callbacks with the CY_SYSPM_BEFORE_TRANSITION or
* CY_SYSPM_AFTER_TRANSITION parameter are executed if Low Power mode is
* not exited.
*
* \note The last callback that returned CY_SYSPM_FAIL is not executed with the
* CY_SYSPM_CHECK_FAIL parameter because of the FAIL.
*
* The return values from executed callback functions with the
* CY_SYSPM_CHECK_FAIL, CY_SYSPM_BEFORE_TRANSITION, and CY_SYSPM_AFTER_TRANSITION
* modes are ignored.
*
* \note The callbacks are not executed if the device is not already in Low
* Power mode.
*
* \return
* See \ref cy_en_syspm_status_t. <br>
* CY_SYSPM_SUCCESS - Exited from the LPActive power mode, or the device is
* already in Active mode. <br>
* CY_SYSPM_FAIL - Exit from the LPActive mode is not done.
*
* \warning This function blocks as it waits until Active Reference is ready
* to enter to the normal mode.
*
* \funcusage
* \snippet syspm/syspm_2_20_sut_01.cydsn/main_cm4.c snippet_Cy_SysPm_ExitLowPowerMode
*
*******************************************************************************/
cy_en_syspm_status_t Cy_SysPm_ExitLowPowerMode(void)
{
uint32_t interruptState;
uint32_t timeOut = WAIT_DELAY_TRYES;
cy_en_syspm_status_t retVal = CY_SYSPM_SUCCESS;
/* Check if the device is in the low power mode */
if(0U != (_FLD2VAL(SRSS_PWR_CTL_ACT_REF_DIS, SRSS_PWR_CTL)))
{
/* Call the registered callback functions with the
* CY_SYSPM_CHECK_READY parameter.
*/
if(0U != curRegisteredCallbacks)
{
retVal = Cy_SysPm_ExecuteCallback(CY_SYSPM_EXIT_LOWPOWER_MODE, CY_SYSPM_CHECK_READY);
}
/* The device (core) can switch into the Low Power mode only in the
* condition that all executed registered callback functions with the
* CY_SYSPM_CHECK_READY parameter return CY_SYSPM_SUCCESS.
*/
if(retVal == CY_SYSPM_SUCCESS)
{
/* Call the registered callback functions with the
* CY_SYSPM_BEFORE_TRANSITION parameter. The return value should be
* CY_SYSPM_SUCCESS.
*/
interruptState = Cy_SysLib_EnterCriticalSection();
if(0U != curRegisteredCallbacks)
{
(void) Cy_SysPm_ExecuteCallback(CY_SYSPM_EXIT_LOWPOWER_MODE, CY_SYSPM_BEFORE_TRANSITION);
}
/* Set the normal operation mode for LDO regulator if
* it is enabled
*/
if(Cy_SysPm_LdoIsEnabled())
{
SRSS_PWR_CTL &= ((uint32_t)~(SRSS_PWR_CTL_LINREG_LPMODE_Msk));
}
/* Configure the normal operating mode for the POR/BOD circuits and
* for the Bandgap Voltage and Current References
*/
SRSS_PWR_CTL &= ((uint32_t)~(_VAL2FLD(SRSS_PWR_CTL_PORBOD_LPMODE, 1U) |
_VAL2FLD(SRSS_PWR_CTL_ACT_REF_DIS, 1U) |
_VAL2FLD(SRSS_PWR_CTL_VREFBUF_LPMODE, 1U) |
_VAL2FLD(SRSS_PWR_CTL_IREF_LPMODE, 1U)));
/* This wait time allows setting Active Reference */
Cy_SysLib_DelayUs(LP_TO_ACTIVE_DELAY_BEFORE_TR_US);
while((0U == _FLD2VAL(SRSS_PWR_CTL_ACT_REF_OK, SRSS_PWR_CTL)) && (0U != timeOut))
{
timeOut--;
}
if(0U == timeOut)
{
retVal = CY_SYSPM_TIMEOUT;
Cy_SysLib_ExitCriticalSection(interruptState);
}
else
{
/* Configure the normal operation mode */
SRSS_PWR_CTL &= ((uint32_t) (~SRSS_PWR_CTL_BGREF_LPMODE_Msk));
/* This wait time allows setting Active Reference */
Cy_SysLib_DelayUs(LP_TO_ACTIVE_DELAY_AFTER_TR_US);
Cy_SysLib_ExitCriticalSection(interruptState);
/* Call registered callback functions with CY_SYSPM_AFTER_TRANSITION
* parameter. Return value should be CY_SYSPM_SUCCESS.
*/
if(0U != curRegisteredCallbacks)
{
(void) Cy_SysPm_ExecuteCallback(CY_SYSPM_EXIT_LOWPOWER_MODE, CY_SYSPM_AFTER_TRANSITION);
}
}
}
else
{
/* Execute callback functions with the CY_SYSPM_CHECK_FAIL parameter to
* undo everything done in the callback with the CY_SYSPM_CHECK_READY
* parameter. The return value should be CY_SYSPM_SUCCESS.
*/
(void) Cy_SysPm_ExecuteCallback(CY_SYSPM_EXIT_LOWPOWER_MODE, CY_SYSPM_CHECK_FAIL);
retVal = CY_SYSPM_FAIL;
}
}
else
{
/* Do nothing because the device is already in the Active power mode */
}
return retVal;
}
/*******************************************************************************
* Function Name: Cy_SysPm_SleepOnExit
****************************************************************************//**
*
* This function configures the Sleep-on-exit feature of the core.
*
* This API sets the SLEEPONEXIT bit of the SCR register.
*
* When the Sleep-on-exit feature is enabled (SLEEPONEXIT bit is set),
* the core wakes up to service the interrupt and then immediately goes
* back to sleep. Because of this, the unstacking process is not carried out, so
* this feature is useful for the interrupt driven application and helps to
* reduce the unnecessary stack push and pop operations.
* The core does not go to sleep if the interrupt handler returns to
* another interrupt handler (nested interrupt).
* You can use this feature in applications that require only the core to run
* when an interrupt occurs.
*
* When the Sleep-on-exit feature is disabled (SLEEPONEXIT bit is cleared),
* the core returns back to the main thread after servicing the interrupt
* without going back to sleep.
*
* Refer to the ARM documentation about the Sleep-on-exit feature and
* SLEEPONEXIT of the SCR register.
*
* \param enable
* true - enable Sleep-on-exit feature <br> false - disable
* Sleep-on-exit feature.
*
* \funcusage
* \snippet syspm/syspm_2_20_sut_01.cydsn/main_cm4.c snippet_Cy_SysPm_SleepOnExit
*
*******************************************************************************/
void Cy_SysPm_SleepOnExit(bool enable)
{
uint32_t interruptState;
interruptState = Cy_SysLib_EnterCriticalSection();
if(enable)
{
/* Enable Sleep-on-exit mode */
SCB_SCR |= _VAL2FLD(SCB_SCR_SLEEPONEXIT, 1U);
}
else
{
/* Disable Sleep-on-exit mode */
SCB_SCR &= ((uint32_t) ~(SCB_SCR_SLEEPONEXIT_Msk));
}
Cy_SysLib_ExitCriticalSection(interruptState);
}
/*******************************************************************************
* Function Name: Cy_SysPm_SetHibernateWakeupSource
****************************************************************************//**
*
* This function configures sources to wake up the device from the Hibernate
* power mode. Such sources can be wakeup pins, LPComparators, Watchdog (WDT)
* interrupt, or a Real-Time clock (RTC) alarm (interrupt).
*
* Wakeup pins:
*
* A wakeup is supported by up to two pins with programmable polarity. These pins
* may be connected to the I/O pins or on-chip peripherals under some conditions.
* Setting the wakeup pin to this level will cause a wakeup from Hibernate
* mode. The wakeup pins are active/low by default.
*
* LPComparators:
*
* A wakeup is supported by up to two LPComps with programmable polarity. These
* LPComp may be connected to the I/O pins or on-chip peripherals under some
* conditions.
* Setting the LPComp to this level will cause a wakeup from Hibernate
* mode. The wakeup LPComp are active-low by default.
*
* \note The low-power comparators should be configured and enabled before
* switching into the hibernate low power mode. Refer to the LPComp
* driver description for more details.
*
* Watchdog Timer:
*
* \note The WDT should be configured and enabled before entering into the
* Hibernate power mode.
*
* A wakeup is performed by a WDT interrupt and a normal boot procedure
* after a device reset. The device can wake up from Hibernate after a WDT
* device reset, if the WDT was configured to wake up, the device on its
* interrupt and WDT was enabled.
*
* Real-time Clock:
*
* A wakeup is performed by the RTC alarm and a normal boot procedure
* after a device reset.
* Refer to the Real-Time Clock (RTC) driver description for more details.
*
* For information about wakeup sources and their assignment in the specific
* families devices, refer to the appropriate device TRM.
*
* \param wakeupSource
* The source to be configured as a wakeup source from
* the Hibernate power mode, see \ref cy_en_syspm_hibernate_wakeup_source_t.
* The input parameters values can be ORed. For example, if you want to set
* LPComp0 (active high) and WDT, call this function:
* Cy_SysPm_SetHibernateWakeupSource(CY_SYSPM_HIBERNATE_LPCOMP0_HIGH | CY_SYSPM_HIBERNATE_WDT).
*
* \warning Do not call this function with different polarity levels for the same
* wakeup source. For example, do not call a function like this:
* Cy_SysPm_SetHibernateWakeupSource(CY_SYSPM_HIBERNATE_LPCOMP0_LOW, CY_SYSPM_HIBERNATE_LPCOMP0_HIGH);
*
* \funcusage
* \snippet syspm/syspm_2_20_sut_01.cydsn/main_cm4.c snippet_Cy_SysPm_SetHibernateWakeupSource
*
*******************************************************************************/
void Cy_SysPm_SetHibernateWakeupSource(uint32_t wakeupSource)
{
CY_ASSERT_L3(CY_SYSPM_IS_WAKE_UP_SOURCE_VALID(wakeupSource));
/* Reconfigure the wake-up pins and LPComp polarity based on the input */
if(0U != ((uint32_t) wakeupSource & CY_SYSPM_WAKEUP_LPCOMP0))
{
SRSS_PWR_HIBERNATE &=
((uint32_t) ~_VAL2FLD(SRSS_PWR_HIBERNATE_POLARITY_HIBPIN, CY_SYSPM_WAKEUP_LPCOMP0_BIT));
}
if(0U != ((uint32_t) wakeupSource & CY_SYSPM_WAKEUP_LPCOMP1))
{
SRSS_PWR_HIBERNATE &=
((uint32_t) ~_VAL2FLD(SRSS_PWR_HIBERNATE_POLARITY_HIBPIN, CY_SYSPM_WAKEUP_LPCOMP1_BIT));
}
if(0U != ((uint32_t) wakeupSource & CY_SYSPM_WAKEUP_PIN0))
{
SRSS_PWR_HIBERNATE &=
((uint32_t) ~_VAL2FLD(SRSS_PWR_HIBERNATE_POLARITY_HIBPIN, CY_SYSPM_WAKEUP_PIN0_BIT));
}
if(0U != ((uint32_t) wakeupSource & CY_SYSPM_WAKEUP_PIN1))
{
SRSS_PWR_HIBERNATE &=
((uint32_t) ~_VAL2FLD(SRSS_PWR_HIBERNATE_POLARITY_HIBPIN, CY_SYSPM_WAKEUP_PIN1_BIT));
}
SRSS_PWR_HIBERNATE |= ((uint32_t) wakeupSource);
/* Read register to make sure it is settled */
(void) SRSS_PWR_HIBERNATE;
}
/*******************************************************************************
* Function Name: Cy_SysPm_ClearHibernateWakeupSource
****************************************************************************//**
*
* This function disables a wakeup source that was previously configured to
* wake up the device from the hibernate power mode.
*
* \param wakeupSource
* For the source to be disabled, see \ref cy_en_syspm_hibernate_wakeup_source_t.
* The input parameters values can be ORed. For example, if you want to disable
* LPComp0 (active high) and WDT call this function:
* Cy_SysPm_ClearHibernateWakeupSource(CY_SYSPM_HIBERNATE_LPCOMP0_HIGH | CY_SYSPM_HIBERNATE_WDT).
*
* \funcusage
* \snippet syspm/syspm_2_20_sut_01.cydsn/main_cm4.c snippet_Cy_SysPm_ClearHibernateWakeupSource
*
*******************************************************************************/
void Cy_SysPm_ClearHibernateWakeupSource(uint32_t wakeupSource)
{
uint32_t clearWakeupSource;
CY_ASSERT_L3(CY_SYSPM_IS_WAKE_UP_SOURCE_VALID(wakeupSource));
if (0U != _FLD2VAL(SRSS_PWR_HIBERNATE_POLARITY_HIBPIN, wakeupSource))
{
/* Clear the high active level of the requested sources */
if((uint32_t) CY_SYSPM_HIBERNATE_LPCOMP0_HIGH == ((uint32_t) wakeupSource & (uint32_t) CY_SYSPM_HIBERNATE_LPCOMP0_HIGH))
{
SRSS_PWR_HIBERNATE &=
((uint32_t) ~_VAL2FLD(SRSS_PWR_HIBERNATE_POLARITY_HIBPIN, CY_SYSPM_WAKEUP_LPCOMP0_BIT));
}
if((uint32_t) CY_SYSPM_HIBERNATE_LPCOMP1_HIGH == ((uint32_t) wakeupSource & (uint32_t) CY_SYSPM_HIBERNATE_LPCOMP1_HIGH))
{
SRSS_PWR_HIBERNATE &=
((uint32_t) ~_VAL2FLD(SRSS_PWR_HIBERNATE_POLARITY_HIBPIN, CY_SYSPM_WAKEUP_LPCOMP1_BIT));
}
if((uint32_t) CY_SYSPM_HIBERNATE_PIN0_HIGH == ((uint32_t) wakeupSource & (uint32_t) CY_SYSPM_HIBERNATE_PIN0_HIGH))
{
SRSS_PWR_HIBERNATE &=
((uint32_t) ~_VAL2FLD(SRSS_PWR_HIBERNATE_POLARITY_HIBPIN, CY_SYSPM_WAKEUP_PIN0_BIT));
}
if((uint32_t) CY_SYSPM_HIBERNATE_PIN1_HIGH == ((uint32_t) wakeupSource & (uint32_t) CY_SYSPM_HIBERNATE_PIN1_HIGH))
{
SRSS_PWR_HIBERNATE &=
((uint32_t) ~_VAL2FLD(SRSS_PWR_HIBERNATE_POLARITY_HIBPIN, CY_SYSPM_WAKEUP_PIN1_BIT));
}
}
/* Remove the polarity bits from the input value */
clearWakeupSource = ((uint32_t) wakeupSource & ((uint32_t) ~ SRSS_PWR_HIBERNATE_POLARITY_HIBPIN_Msk));
SRSS_PWR_HIBERNATE &= ((uint32_t) ~ clearWakeupSource);
/* Read register to make sure it is settled */
(void) SRSS_PWR_HIBERNATE;
}
/*******************************************************************************
* Function Name: Cy_SysPm_BuckEnable
****************************************************************************//**
*
* Switch the power supply regulator to Buck regulator instead of the LDO.
* The Buck core regulator provides output voltage(s) using one external
* inductor and can supply Vccd with higher efficiency than the LDO under some
* conditions, such as high external supply voltage.
*
* Before changing from LDO to Buck, ensure that the circuit board has
* connected Vccbuck1 to Vccd and also populated the
* necessary external components for the Buck regulator, including an
* inductor and a capacitor for each output.
* Refer to the device TRM for more details.
*
* When changing from a higher voltage to a lower voltage
* (from LDO 1.1V to Buck 0.9V), ensure that:
* * The device maximum operating frequency for all the Clk_HF paths, peripheral,
* and slow clock are under the ULP limitations.
* * The total current consumption is under the ULP limitations.
*
* * The appropriate wait states values are set for the flash using
* the Cy_SysLib_SetWaitStates() function as explained below.
*
* <b>Setting wait states values for flash</b>
*
* The flash access time when the core output voltage is 0.9 V (nominal) is
* longer than at 1.1 V (nominal). Therefore, the number of the wait states must
* be adjusted. Use the Cy_SysLib_SetWaitStates() function to set the appropriate
* wait state values for flash.
*
* To change from a higher voltage (LDO 1.1 V) to a lower voltage (Buck 0.9 V),
* call the Cy_SysLib_SetWaitStates(true, hfClkFreqMz) function before changing
* the voltage, where hfClkFreqMz is the frequency of HfClk0 in MHz.
*
* To change from a lower voltage (LDO 0.9 V) to a higher voltage (Buck 1.1 V),
* calling the Cy_SysLib_SetWaitStates(false, hfClkFreqMz) function is to set
* the wait states is optional, but can be done to improve the performance.
* The clock frequency may now be increased up to LP mode for a new voltage.
*
* \note 1. The final Buck output is set to 0.9 V (nominal) - the flash works
* in the Read-only operation.
* \note 2. The final Buck output is set to 1.1 V (nominal) - the flash works
* in the Read and Write operations.
* \note 3. The actual device Vccd voltage can be different from the nominal
* voltage because the actual voltage value depends on the conditions
* including the load current.
*
* \warning There is no way to go back to the LDO after the
* Buck regulator supplies a core. The function switches off the LDO.
*
* For more details refer to the \ref group_syspm_managing_core_regulators
* section.
* Refer to the \ref group_syslib driver for more details about setting the wait
* states.
*
* \param voltage
* The desired output 1 regulator voltage (Vccbuck1).
* See \ref cy_en_syspm_buck_voltage1_t.
*
* \return
* CY_SYSPM_SUCCESS - The voltage is set<br>
* CY_SYSPM_INVALID_STATE - The voltage was not set. The voltage cannot be set
* because the protection context value is higher than zero (PC > 0) or the
* device revision does not support modifying registers via syscall<br>
* CY_SYSPM_CANCELED - Operation was canceled. Call the function again until the
* function returns CY_SYSPM_SUCCESS. <br>
* See \ref cy_en_syspm_status_t.
*
* \note
* The function is applicable for devices with the Buck regulator.
*
* Function uses a critical section to prevent interrupting the regulators
* switching.
*
* \funcusage
* \snippet syspm/syspm_2_20_sut_01.cydsn/main_cm4.c snippet_Cy_SysPm_BuckEnable
*
*******************************************************************************/
cy_en_syspm_status_t Cy_SysPm_BuckEnable(cy_en_syspm_buck_voltage1_t voltage)
{
CY_ASSERT_L3(CY_SYSPM_IS_BUCK_VOLTAGE1_VALID(voltage));
cy_en_syspm_status_t retVal = CY_SYSPM_INVALID_STATE;
/* Enable the Buck regulator only if it was not enabled previously.
* If the LDO is disabled the device is sourced by the Buck regulator
*/
if (Cy_SysPm_LdoIsEnabled())
{
uint32_t interruptState;
interruptState = Cy_SysLib_EnterCriticalSection();
/* Update the RAM and ROM trim values when final target Buck 0.9V */
if (CY_SYSPM_BUCK_OUT1_VOLTAGE_0_9V == voltage)
{
if (Cy_SysPm_LdoGetVoltage() != CY_SYSPM_LDO_VOLTAGE_0_9V)
{
retVal = Cy_SysPm_LdoSetVoltage(CY_SYSPM_LDO_VOLTAGE_0_9V);
}
else
{
retVal = CY_SYSPM_SUCCESS;
}
if (CY_SYSPM_SUCCESS == retVal)
{
/* Increase LDO output voltage to 0.95 V nominal */
SRSS_PWR_TRIM_PWRSYS_CTL = _CLR_SET_FLD32U((SRSS_PWR_TRIM_PWRSYS_CTL),
SRSS_PWR_TRIM_PWRSYS_CTL_ACT_REG_TRIM, LDO_OUT_VOLTAGE_0_95V);
}
}
/* Update the RAM and ROM trim values when the final target Buck 1.1 V */
if (CY_SYSPM_BUCK_OUT1_VOLTAGE_1_1V == voltage)
{
if (Cy_SysPm_LdoGetVoltage() != CY_SYSPM_LDO_VOLTAGE_1_1V)
{
retVal = Cy_SysPm_LdoSetVoltage(CY_SYSPM_LDO_VOLTAGE_1_1V);
}
else
{
retVal = CY_SYSPM_SUCCESS;
}
if (CY_SYSPM_SUCCESS == retVal)
{
/* Set the LDO 1.15V as final Buck output is 1.1 V */
SRSS_PWR_TRIM_PWRSYS_CTL = _CLR_SET_FLD32U((SRSS_PWR_TRIM_PWRSYS_CTL),
SRSS_PWR_TRIM_PWRSYS_CTL_ACT_REG_TRIM, LDO_OUT_VOLTAGE_1_15V);
}
}
/* Proceed only if previous settings were done successfully */
if (CY_SYSPM_SUCCESS == retVal)
{
/* A delay for the supply to stabilize at the new voltage */
Cy_SysLib_DelayUs(9U);
/* Disable the Deep Sleep, nWell, and Retention regulators */
SRSS_PWR_CTL |= (_VAL2FLD(SRSS_PWR_CTL_DPSLP_REG_DIS, 1U) |
_VAL2FLD(SRSS_PWR_CTL_RET_REG_DIS, 1U) |
_VAL2FLD(SRSS_PWR_CTL_NWELL_REG_DIS, 1U));
/* Configure the Buck regulator */
SRSS_PWR_BUCK_CTL =
_CLR_SET_FLD32U((SRSS_PWR_BUCK_CTL), SRSS_PWR_BUCK_CTL_BUCK_OUT1_SEL, (uint32_t) voltage);
SRSS_PWR_BUCK_CTL |= _VAL2FLD(SRSS_PWR_BUCK_CTL_BUCK_EN, 1U);
SRSS_PWR_BUCK_CTL |= _VAL2FLD(SRSS_PWR_BUCK_CTL_BUCK_OUT1_EN, 1U);
/* Wait until Buck output 1 is stable */
Cy_SysLib_DelayUs(BUCK_INIT_STABILIZATION_US);
/* Disable the LDO, because Vbuckout1 and LDO are shorted */
SRSS_PWR_CTL |= _VAL2FLD(SRSS_PWR_CTL_LINREG_DIS, 1U);
}
Cy_SysLib_ExitCriticalSection(interruptState);
}
else
{
/* The Buck is already enabled just update the Buck voltage */
cy_en_syspm_buck_voltage1_t curBuckVoltage = Cy_SysPm_BuckGetVoltage1();
if (voltage != curBuckVoltage)
{
retVal = Cy_SysPm_BuckSetVoltage1(voltage);
}
else
{
retVal = CY_SYSPM_SUCCESS;
}
}
return retVal;
}
/*******************************************************************************
* Function Name: Cy_SysPm_BuckSetVoltage1
****************************************************************************//**
*
* Sets the output 1 voltage for the Buck regulator that can supply core(s).
* This output can supply cores instead of the LDO.
*
* When changing from a higher voltage to a lower voltage, ensure that:
* * The device maximum operating frequency for all the Clk_HF paths, peripheral,
* and slow clock are under the \ref group_syspm_ulp_limitations.
* * The total current consumption is under the \ref group_syspm_ulp_limitations.
*
* * The appropriate wait states values are set for the flash using
* the Cy_SysLib_SetWaitStates() function as explained below.
*
* <b>Setting wait states values for flash</b>
*
* The flash access time when the core output voltage is 0.9 V (nominal) is
* longer than at 1.1 V (nominal). Therefore, the number of the wait states must
* be adjusted. Use the Cy_SysLib_SetWaitStates() function to set the appropriate
* wait state values for flash.
*
* To change from a higher voltage to a lower voltage 0.9 V (nominal),
* call the Cy_SysLib_SetWaitStates(true, hfClkFreqMz) function before changing
* the voltage, where hfClkFreqMz is the frequency of HfClk0 in MHz.
*
* To change from a lower voltage to a higher voltage 1.1 V (nominal), calling
* the Cy_SysLib_SetWaitStates(false, hfClkFreqMz) function is to set the
* wait states is optional, but can be done to improve the performance.
* The clock frequency may now be increased up to
* \ref group_syspm_lp_limitations for a new voltage.
*
* \note 1. The output is set to 0.9 V (nominal) - the flash works in the
* Read-only operation.
* \note 2. The output is set to 1.1 V (nominal) - the flash works in the Read
* and Write operations.
* \note 3. The actual device Vccd voltage can be different from the nominal
* voltage because the actual voltage value depends on the conditions
* including the load current.
*
* For more details refer to the \ref group_syspm_managing_core_regulators
* section.
* Refer to the \ref group_syslib driver for more details about setting the
* wait states.
*
* \param voltage
* The desired output 1 regulator voltage (Vccbuck1).
* See \ref cy_en_syspm_buck_voltage1_t
*
* \return
* CY_SYSPM_SUCCESS - The voltage is set<br>
* CY_SYSPM_INVALID_STATE - The voltage was not set. The voltage cannot be set
* because the protection context value is higher than zero (PC > 0) or the
* device revision does not support modifying registers via syscall<br>
* CY_SYSPM_CANCELED - Operation was canceled. Call the function again until the
* function returns CY_SYSPM_SUCCESS. See \ref cy_en_syspm_status_t.
*
* \funcusage
* \snippet syspm/syspm_2_20_sut_01.cydsn/main_cm4.c snippet_Cy_SysPm_VoltageRegulator
*
*******************************************************************************/
cy_en_syspm_status_t Cy_SysPm_BuckSetVoltage1(cy_en_syspm_buck_voltage1_t voltage)
{
CY_ASSERT_L3(CY_SYSPM_IS_BUCK_VOLTAGE1_VALID(voltage));
cy_en_syspm_status_t retVal = CY_SYSPM_INVALID_STATE;
/* Change the voltage only if protection context is set to zero (PC = 0)
* or the device revision supports modifying registers via syscall
*/
if (IsVoltageChangePossible())
{
uint32_t interruptState;
interruptState = Cy_SysLib_EnterCriticalSection();
if (CY_SYSPM_BUCK_OUT1_VOLTAGE_0_9V == voltage)
{
/* Set bit of the flash voltage control register after
* the output voltage is 1.1 V
*/
retVal = WriteVoltageBitForFlash(1U);
if (CY_SYSPM_SUCCESS == retVal)
{
/* Update read-write margin value for the ULP mode */
SetReadMarginTrimUlp();
}
}
else
{
/* Increase Buck output voltage to 0.95 V nominal */
SRSS_PWR_BUCK_CTL =
_CLR_SET_FLD32U((SRSS_PWR_BUCK_CTL), SRSS_PWR_BUCK_CTL_BUCK_OUT1_SEL, BUCK_OUT1_VOLTAGE_0_95V);
/* Wait until regulator is stable */
Cy_SysLib_DelayUs(52U);
/* Update write assist value for the LP mode */
SetWriteAssistTrimLp();
retVal = CY_SYSPM_SUCCESS;
}
/* Proceed only if previous settings were done successfully */
if (CY_SYSPM_SUCCESS == retVal)
{
/* The system may continue operating while the voltage on Vccd
* discharges to the new voltage. The time it takes to reach the
* new voltage depends on the conditions, including the load current
* on Vccd and the external capacitor size.
*/
SRSS_PWR_BUCK_CTL =
_CLR_SET_FLD32U((SRSS_PWR_BUCK_CTL), SRSS_PWR_BUCK_CTL_BUCK_OUT1_SEL, (uint32_t) voltage);
if (CY_SYSPM_BUCK_OUT1_VOLTAGE_0_9V == voltage)
{
/* Update write assist value for the ULP mode */
SetWriteAssistTrimUlp();
}
else
{
/* Delay to stabilize at the new voltage is required only
* when changing from a lower voltage to a higher voltage.
*/
Cy_SysLib_DelayUs(145U);
/* Update read-write margin value for the LP mode */
SetReadMarginTrimLp();
/* Clear bit of the flash voltage control register after
* the output voltage is 1.1 V
*/
retVal = WriteVoltageBitForFlash(0U);
}
}
Cy_SysLib_ExitCriticalSection(interruptState);
}
return retVal;
}
/*******************************************************************************
* Function Name: Cy_SysPm_BuckIsOutputEnabled
****************************************************************************//**
*
* This function gets the current output status of the Buck outputs.
*
* \param output
* The Buck regulator output. See \ref cy_en_syspm_buck_out_t.
*
* \return
* The current state of the requested output. True if the requested output
* is enabled.
* False if the requested output is disabled.
*
* \funcusage
* \snippet syspm/syspm_2_20_sut_01.cydsn/main_cm4.c snippet_Cy_SysPm_BuckIsOutputEnabled
*
*******************************************************************************/
bool Cy_SysPm_BuckIsOutputEnabled(cy_en_syspm_buck_out_t output)
{
CY_ASSERT_L3(CY_SYSPM_IS_BUCK_OUTPUT_VALID(output));
bool retVal = false;
if (output == CY_SYSPM_BUCK_VBUCK_1)
{
retVal = (_FLD2BOOL(SRSS_PWR_BUCK_CTL_BUCK_OUT1_EN, SRSS_PWR_BUCK_CTL));
}
if (0U != cy_device->sysPmSimoPresent)
{
if(output == CY_SYSPM_BUCK_VRF)
{
retVal = ((0U != _FLD2VAL(SRSS_PWR_BUCK_CTL2_BUCK_OUT2_HW_SEL, SRSS_PWR_BUCK_CTL2)) ||
(0U != _FLD2VAL(SRSS_PWR_BUCK_CTL2_BUCK_OUT2_EN, SRSS_PWR_BUCK_CTL2)));
}
}
return(retVal);
}
/*******************************************************************************
* Function Name: Cy_SysPm_BuckEnableVoltage2
****************************************************************************//**
*
* Enable the output 2 voltage (Vbuckrf) of the SIMO Buck regulator.
* The output 2 voltage (Vbuckrf) of the Buck regulator is used to supply
* the BLE HW block.
* When the Buck regulator is switched off, the function enables the
* regulator and after it, enables output 2.
*
* \note The function does not affect Buck output 1 that can supply
* a core.
*
* \warning The function does not select the Buck output 2 voltage and
* does not set/clear the HW-controlled bit for Buck output 2. Call
* Cy_SysPm_BuckSetVoltage2() or Cy_SysPm_BuckSetVoltage2HwControl() to
* configure the Buck output 2.
*
* The function is applicable for devices with the SIMO Buck regulator.
* Refer to device datasheet about information if device contains
* SIMO Buck.
*
* \funcusage
* \snippet syspm/syspm_2_20_sut_01.cydsn/main_cm4.c snippet_Cy_SysPm_BuckEnableVoltage2
*
*******************************************************************************/
void Cy_SysPm_BuckEnableVoltage2(void)
{
if(!Cy_SysPm_BuckIsEnabled())
{
/* Enable the SIMO Buck regulator */
SRSS_PWR_BUCK_CTL |= _VAL2FLD(SRSS_PWR_BUCK_CTL_BUCK_EN, 1U);
}
/* Enable the SIMO Buck output 2 */
SRSS_PWR_BUCK_CTL2 |= _VAL2FLD(SRSS_PWR_BUCK_CTL2_BUCK_OUT2_EN, 1U);
/* Wait until the output is stable */
Cy_SysLib_DelayUs(BUCK_OUT2_INIT_DELAY_US);
}
/*******************************************************************************
* Function Name: Cy_SysPm_BuckSetVoltage2
****************************************************************************//**
*
* This function sets output voltage 2 of the SIMO Buck regulator.
*
* \param voltage
* The voltage of the Buck regulator output 2.
* See \ref cy_en_syspm_buck_voltage2_t.
*
* \param waitToSettle
* True - Enable the 200 us delay after setting a higher voltage.
* False - Disable the 200 us delay after setting a higher voltage.
*
* \warning You must enable the delay (waitToSettle = true)
* while changing from a lower voltage to a higher voltage.
*
* \note The 200 us delay is required only when changing from a
* lower voltage to a higher voltage. Changing from a higher voltage to a lower one,
* the delay is not required.
*
* The function is applicable for devices with the SIMO Buck regulator.
* Refer to device datasheet about information if device contains
* SIMO Buck.
*
* \funcusage
* \snippet syspm/syspm_2_20_sut_01.cydsn/main_cm4.c snippet_Cy_SysPm_BuckSetVoltage2
*
*******************************************************************************/
void Cy_SysPm_BuckSetVoltage2(cy_en_syspm_buck_voltage2_t voltage, bool waitToSettle)
{
uint32_t curVoltage;
CY_ASSERT_L3(CY_SYSPM_IS_BUCK_VOLTAGE2_VALID(voltage));
/* Get the current voltage */
curVoltage = (uint32_t) Cy_SysPm_BuckGetVoltage2();
if((uint32_t) voltage != curVoltage)
{
SRSS_PWR_BUCK_CTL2 =
_CLR_SET_FLD32U((SRSS_PWR_BUCK_CTL2), SRSS_PWR_BUCK_CTL2_BUCK_OUT2_SEL, (uint32_t) voltage);
/* Delay to stabilize at the new voltage is required only
* when changing from a lower voltage to a higher voltage.
*/
if(waitToSettle && ((uint32_t) voltage > curVoltage))
{
Cy_SysLib_DelayUs(BUCK_OUT2_STABILIZATION_DELAY_US);
}
}
}
/*******************************************************************************
* Function Name: Cy_SysPm_LdoSetVoltage
****************************************************************************//**
*
* Set an output voltage on the LDO.
*
* When changing from a higher voltage to a lower voltage, ensure that:
* * The device maximum operating frequency for all the Clk_HF paths, peripheral,
* and slow clock are under the \ref group_syspm_ulp_limitations.
* * The total current consumption is under the \ref group_syspm_ulp_limitations.
* * The appropriate wait states values are set for the flash using
* the Cy_SysLib_SetWaitStates() function as explained below.
*
* <b>Setting wait states values for Flash</b>
*
* The flash access time when the core output voltage is 0.9 V (nominal) is
* longer than at 1.1 V (nominal). Therefore, the number of the wait states must
* be adjusted. Use the Cy_SysLib_SetWaitStates() function to set the appropriate
* wait state values for flash.
*
* To change from a higher voltage to a lower voltage 0.9 V (nominal),
* call the Cy_SysLib_SetWaitStates(true, hfClkFreqMz) function before changing
* the voltage, where hfClkFreqMz is the frequency of HfClk0 in MHz.
*
* To change from a lower voltage to a higher voltage 1.1 V (nominal), calling
* the Cy_SysLib_SetWaitStates(false, hfClkFreqMz) function is to set the
* wait states is optional, but can be done to improve the performance.
* The clock frequency may now be increased up to \ref group_syspm_lp_limitations
* for a new voltage.
*
* \note 1. The output is set to 0.9 V (nominal) - the flash works in the
* Read-only operation.
* \note 2. The output is set to 1.1 V (nominal) - the flash works in the Read
* and Write operations.
* \note 3. The actual device Vccd voltage can be different from the nominal
* voltage because the actual voltage value depends on the conditions
* including the load current.
*
* For more details refer to the \ref group_syspm_managing_core_regulators
* section.
* Refer to the \ref group_syslib driver for more details about setting the wait
* states.
*
* \param voltage
* The desired output regulator voltage.
* See \ref cy_en_syspm_ldo_voltage_t voltage
*
* \return
* CY_SYSPM_SUCCESS - The voltage is set<br>
* CY_SYSPM_INVALID_STATE - The voltage was not set. The voltage cannot be set
* because the protection context value is higher than zero (PC > 0) or the
* device revision does not support modifying registers via syscall<br>
* CY_SYSPM_CANCELED - Operation was canceled. Call the function again until the
* function returns CY_SYSPM_SUCCESS. See \ref cy_en_syspm_status_t.
*
* \funcusage
* \snippet syspm/syspm_2_20_sut_01.cydsn/main_cm4.c snippet_Cy_SysPm_VoltageRegulator
*
*******************************************************************************/
cy_en_syspm_status_t Cy_SysPm_LdoSetVoltage(cy_en_syspm_ldo_voltage_t voltage)
{
CY_ASSERT_L3(CY_SYSPM_IS_LDO_VOLTAGE_VALID(voltage));
cy_en_syspm_status_t retVal = CY_SYSPM_INVALID_STATE;
/* Change the voltage only if protection context is set to zero (PC = 0),
* or the device revision supports modifying registers via syscall
*/
if (IsVoltageChangePossible())
{
uint32_t interruptState;
uint32_t trimVoltage;
interruptState = Cy_SysLib_EnterCriticalSection();
if (CY_SYSPM_LDO_VOLTAGE_0_9V == voltage)
{
/* Remove additional wakeup delay from Deep Sleep
* for 1.1 V LDO. Cypress ID #290172.
*/
SRSS_PWR_TRIM_WAKE_CTL = 0UL;
trimVoltage = SFLASH_LDO_0P9V_TRIM;
/* Set bit of the flash voltage control register after
* the output voltage is 1.1 V
*/
retVal = WriteVoltageBitForFlash(1U);
if (CY_SYSPM_SUCCESS == retVal)
{
/* Update read-write margin value for the ULP mode */
SetReadMarginTrimUlp();
}
}
else
{
/* Configure additional wakeup delay from Deep Sleep
* for 1.1 V LDO. Cypress ID #290172.
*/
SRSS_PWR_TRIM_WAKE_CTL = SFLASH_PWR_TRIM_WAKE_CTL;
trimVoltage = SFLASH_LDO_1P1V_TRIM;
SRSS_PWR_TRIM_PWRSYS_CTL =
_CLR_SET_FLD32U((SRSS_PWR_TRIM_PWRSYS_CTL), SRSS_PWR_TRIM_PWRSYS_CTL_ACT_REG_TRIM, LDO_OUT_VOLTAGE_0_95V);
/* A delay for the supply to stabilize at the new higher voltage */
Cy_SysLib_DelayUs(3U);
/* Update write assist value for the LP mode */
SetWriteAssistTrimLp();
retVal = CY_SYSPM_SUCCESS;
}
if (CY_SYSPM_SUCCESS == retVal)
{
/* The system may continue operating while the voltage on Vccd
* discharges to the new voltage. The time it takes to reach the
* new voltage depends on the conditions, including the load current on
* Vccd and the external capacitor size
*/
SRSS_PWR_TRIM_PWRSYS_CTL =
_CLR_SET_FLD32U((SRSS_PWR_TRIM_PWRSYS_CTL), SRSS_PWR_TRIM_PWRSYS_CTL_ACT_REG_TRIM, trimVoltage);
if (CY_SYSPM_LDO_VOLTAGE_0_9V == voltage)
{
/* Update write assist value for the ULP mode */
SetWriteAssistTrimUlp();
}
else
{
/* A delay for the supply to stabilize at the new higher voltage */
Cy_SysLib_DelayUs(7U);
/* Update read-write margin value for the LP mode */
SetReadMarginTrimLp();
/* Clear bit of the flash voltage control register after
* the output voltage is 1.1 V
*/
retVal = WriteVoltageBitForFlash(0U);
}
}
Cy_SysLib_ExitCriticalSection(interruptState);
}
return retVal;
}
/*******************************************************************************
* Function Name: Cy_SysPm_RegisterCallback
****************************************************************************//**
*
* Registers a new syspm callback.
*
* A callback is a function called after an event in the driver or
* middleware module has occurred. The handler callback API will be executed if
* the specific event occurs. See \ref cy_stc_syspm_callback_t.
*
* \note The registered callbacks are executed in two orders, based on callback
* mode \ref cy_en_syspm_callback_mode_t. For modes CY_SYSPM_CHECK_READY and
* CY_SYSPM_BEFORE_TRANSITION, the order is this: the first registered callback
* will be always the first executed. And the last registered callback will be
* executed as the last callback. For modes CY_SYSPM_AFTER_TRANSITION and
* CY_SYSPM_CHECK_FAIL, the order is this: the first registered callback will be
* always the last executed. And the last registered callback will be executed
* as the first callback.
*
* \param handler
* The address of the syspm callback structure.
* See \ref cy_stc_syspm_callback_t.
* \note Do not modify the registered structure in run-time.
*
* \return
* True if a callback was registered; <br>
* False if a callback was not registered or maximum callbacks were registered.
*
* It is allowed to register up to 32 callbacks.
*
* \funcusage
* \snippet syspm/syspm_2_20_sut_01.cydsn/main_cm4.c snippet_Cy_SysPm_Callback_Func_Declaration
* \snippet syspm/syspm_2_20_sut_01.cydsn/main_cm4.c snippet_Cy_SysPm_Callback_Params_Declaration
* \snippet syspm/syspm_2_20_sut_01.cydsn/main_cm4.c snippet_Cy_SysPm_Callback_Structure_Declaration
* \snippet syspm/syspm_2_20_sut_01.cydsn/main_cm4.c snippet_Cy_SysPm_Callback_Func_Implementation
* \snippet syspm/syspm_2_20_sut_01.cydsn/main_cm4.c snippet_Cy_SysPm_RegisterCallback
*
*******************************************************************************/
bool Cy_SysPm_RegisterCallback(cy_stc_syspm_callback_t* handler)
{
uint32_t interruptState;
bool retStatus = false;
interruptState = Cy_SysLib_EnterCriticalSection();
/* Check if the maximum callbacks were registered and verify input */
retStatus = ((handler != NULL) && (curRegisteredCallbacks < CY_SYSPM_CALLBACKS_NUMBER_MAX));
if (retStatus)
{
if ((handler->callbackParams != NULL) && (handler->callback != NULL))
{
cy_stc_syspm_callback_t* curCallback = callbackRoot;
cy_stc_syspm_callback_t* lastRegCallback = NULL;
/* Search last registered callback item */
while (curCallback != NULL)
{
if (curCallback == handler)
{
/* Do not register already registered callback item */
retStatus = false;
break;
}
/* Safe callback before switching into the next item */
lastRegCallback = curCallback;
curCallback = curCallback->nextItm;
}
/* Link requested callback item to the linked list */
if (retStatus)
{
if (callbackRoot == NULL)
{
/* Link first callback item to the linked list */
callbackRoot = handler;
}
else
{
/* Link requested item to previous item */
lastRegCallback->nextItm = handler;
}
/* Update links to next and previous callback items of requested
* callback item
*/
handler->prevItm = lastRegCallback;
handler->nextItm = NULL;
/* Increment the value with number of registered callbacks */
++curRegisteredCallbacks;
}
}
else
{
retStatus = false;
}
}
Cy_SysLib_ExitCriticalSection(interruptState);
return(retStatus);
}
/*******************************************************************************
* Function Name: Cy_SysPm_UnregisterCallback
****************************************************************************//**
*
* This function unregisters a callback.
*
* The registered callback can be unregistered. Otherwise, false will be
* returned.
*
* \param handler The item that should be unregistered.
* See \ref cy_stc_syspm_callback_t.
*
* \return
* True if on success <br>
* False if it was not unregistered or no callbacks were registered.
*
* \funcusage
* \snippet syspm/syspm_2_20_sut_01.cydsn/main_cm4.c snippet_Cy_SysPm_UnregisterCallback
*
*******************************************************************************/
bool Cy_SysPm_UnregisterCallback(cy_stc_syspm_callback_t const *handler)
{
uint32_t interruptState;
bool retStatus = false;
interruptState = Cy_SysLib_EnterCriticalSection();
/* Check if there was at least one callback registered */
if (curRegisteredCallbacks > 0UL)
{
cy_stc_syspm_callback_t* curCallback = callbackRoot;
/* Search requested callback item in the linked list */
while (curCallback != NULL)
{
/* Requested callback is found */
if (curCallback == handler)
{
retStatus = true;
break;
}
/* Go to next callback item in the linked list */
curCallback = curCallback->nextItm;
}
if (retStatus)
{
/* Requested callback is first in the list */
if (callbackRoot == handler)
{
/* Check whether this the only callback registered */
if (callbackRoot->nextItm != NULL)
{
callbackRoot = callbackRoot->nextItm;
callbackRoot->prevItm = NULL;
}
}
else
{
/* Update links of related to unregistered callback items */
curCallback->prevItm->nextItm = curCallback->nextItm;
if (curCallback->nextItm != NULL)
{
curCallback->nextItm->prevItm = curCallback->prevItm;
}
}
/* Decrement the value with number of registered callbacks */
--curRegisteredCallbacks;
if (curRegisteredCallbacks == 0UL)
{
callbackRoot = NULL;
}
}
}
Cy_SysLib_ExitCriticalSection(interruptState);
return(retStatus);
}
/*******************************************************************************
* Function Name: Cy_SysPm_ExecuteCallback
****************************************************************************//**
*
* The function executes all registered callbacks with provided type and mode.
* \note This low-level function is being used by \ref Cy_SysPm_Sleep,
* \ref Cy_SysPm_DeepSleep, \ref Cy_SysPm_Hibernate, \ref Cy_SysPm_EnterLowPowerMode
* and \ref Cy_SysPm_ExitLowPowerMode API functions, however might be also useful as
* an independent API function in some custom applications.
* \note The registered callbacks will be executed in order based on
* \ref cy_en_syspm_callback_type_t value.
* The are possible two orders of callbacks execution: <br>
* * From first registered to last registered. Such order is relevant to
* callbacks with mode CY_SYSPM_CHECK_READY and CY_SYSPM_BEFORE_TRANSITION.
* * Backward flow execution: from last executed callback to the
* first registered. Such order is relevant to callbacks with mode
* CY_SYSPM_AFTER_TRANSITION and CY_SYSPM_CHECK_FAIL. Note that, the last
* registered callback function is skipped with mode CY_SYSPM_CHECK_FAIL. This
* is because the callback that returned CY_SYSPM_FAIL already knows that it failed.
*
* If no callbacks are registered, returns CY_SYSPM_SUCCESS.
*
* \param type
* The callback type. See \ref cy_en_syspm_callback_type_t.
*
* \param mode
* The callback mode. See \ref cy_en_syspm_callback_mode_t.
*
* \note
* If mode is CY_SYSPM_CHECK_READY or CY_SYSPM_BEFORE_TRANSITION the
* all required callbacks would be executed in order from first
* registered to last registered.
* If mode is CY_SYSPM_CHECK_FAIL or CY_SYSPM_AFTER_TRANSITION the
* all required callbacks would be executed in order from last executed callback
* to first registered.
*
* \return
* CY_SYSPM_SUCCESS Callback successfully completed or nor callbacks registered.
* CY_SYSPM_FAIL one of executed callback(s) returned fail.
*
* \funcusage
* \snippet syspm/syspm_2_20_sut_01.cydsn/main_cm4.c snippet_Cy_SysPm_ExecuteCallback
*
*******************************************************************************/
cy_en_syspm_status_t Cy_SysPm_ExecuteCallback(cy_en_syspm_callback_type_t type, cy_en_syspm_callback_mode_t mode)
{
static cy_stc_syspm_callback_t* lastExecutedCallback = NULL;
cy_en_syspm_status_t retVal = CY_SYSPM_SUCCESS;
cy_stc_syspm_callback_t* curCallback;
cy_stc_syspm_callback_params_t curParams;
CY_ASSERT_L3(CY_SYSPM_IS_CALLBACK_TYPE_VALID(type));
CY_ASSERT_L3(CY_SYSPM_IS_CALLBACK_MODE_VALID(mode));
if((mode == CY_SYSPM_BEFORE_TRANSITION) || (mode == CY_SYSPM_CHECK_READY))
{
/* Execute registered callbacks with order from first registered to the
* last registered. The modes defined in the .skipMode element are not
* executed
*/
curCallback = callbackRoot;
while((curCallback != NULL) && (retVal != CY_SYSPM_FAIL))
{
if((curCallback->type == type) && ((0U == curCallback->skipMode) ||
(0U == ((uint32_t) mode & curCallback->skipMode))))
{
/* Update elements for local callback parameter values */
curParams.base = curCallback->callbackParams->base;
curParams.context = curCallback->callbackParams->context;
curParams.mode = mode;
retVal = curCallback->callback(&curParams);
/* Update callback pointer with value of executed callback.
* Such update is required to execute further callbacks in
* backward order after exit from low power mode or to undo
* configuration after callback returned fail: from last executed
* to first registered.
*/
lastExecutedCallback = curCallback;
}
curCallback = curCallback->nextItm;
}
}
else
{
/* Execute registered callbacks with order from lastCallback to
* the first registered callback. Such a flow is required if previous
* callback function returned CY_SYSPM_FAIL or previous callback mode was
* CY_SYSPM_BEFORE_TRANSITION. Such an order is required to undo configurations in
* correct backward order.
*/
curCallback = lastExecutedCallback;
/* Skip last executed callback that returned CY_SYSPM_FAIL, as this
* callback already knows that it failed
*/
if ((mode == CY_SYSPM_CHECK_FAIL) && (curCallback != NULL))
{
curCallback = curCallback->prevItm;
}
/* Execute all registered callback functions with required type and mode */
while ((curCallback != NULL) && (retVal != CY_SYSPM_FAIL))
{
if ((curCallback->type == type) && ((curCallback->skipMode == 0UL) ||
(((uint32_t) mode & curCallback->skipMode) == 0UL)))
{
/* Update elements for local callback parameter values */
curParams.base = curCallback->callbackParams->base;
curParams.context = curCallback->callbackParams->context;
curParams.mode = mode;
retVal = curCallback->callback(&curParams);
}
curCallback = curCallback->prevItm;
}
}
return (retVal);
}
/** \cond INTERNAL */
/*******************************************************************************
* Function Name: Cy_SysPm_IoFreeze
****************************************************************************//**
*
* This function saves the output states and configuration of I/O cells.
*
* I/O-cell configuration can be changed while I/O-cells are frozen. The new
* configuration becomes effective only after the pins are unfrozen.
*
* Cy_SysPm_Hibernate() calls this function to freeze the I/O cells while
* entering hibernate.
*
* \funcusage
* \snippet syspm/syspm_2_20_sut_01.cydsn/main_cm4.c snippet_Cy_SysPm_Freeze
*
*******************************************************************************/
void Cy_SysPm_IoFreeze(void)
{
uint32_t interruptState;
uint32_t regValue;
interruptState = Cy_SysLib_EnterCriticalSection();
/* Check the FREEZE state to avoid a recurrent I/O-cells freeze attempt,
* because the second call to this function will cause an accidental switch
* to Hibernate mode (the system will enter Hibernate mode immediately
* after writing to the hibernate bit because both UNLOCK and FREEZE were set
* correctly in the previous call to this function).
*/
if(0U == _FLD2VAL(SRSS_PWR_HIBERNATE_FREEZE, SRSS_PWR_HIBERNATE))
{
/* Clear the unlock field for correct freeze of the I/O cells */
SRSS_PWR_HIBERNATE = _CLR_SET_FLD32U((SRSS_PWR_HIBERNATE), SRSS_PWR_HIBERNATE_UNLOCK, 0U);
/* Disable overriding by the peripherals the next pin-freeze command */
SRSS_PWR_HIBERNATE |= CY_SYSPM_PWR_SET_HIBERNATE;
/* The second write causes freeze of I/O cells to save the I/O-cell state */
regValue = SRSS_PWR_HIBERNATE;
SRSS_PWR_HIBERNATE = regValue;
}
Cy_SysLib_ExitCriticalSection(interruptState);
}
/** \endcond */
/*******************************************************************************
* Function Name: Cy_SysPm_IoUnfreeze
****************************************************************************//**
*
* This function unfreezes the I/O cells which were automatically frozen when the
* Hibernate is entered with the call to \ref Cy_SysPm_Hibernate().
*
* I/O-cells remain frozen after a wakeup from hibernate mode until the
* firmware unfreezes them, by calling this function.
*
* If the firmware must retain the data value on the port, then the
* value must be read and re-written to the data register before calling this
* function. Furthermore, the drive mode must be re-programmed before the pins
* are unfrozen. If this is not done, the pin will change to the default state
* the moment the freeze is removed.
*
* Note that I/O cell configuration can be changed while frozen. The new
* configuration becomes effective only after the pins are unfrozen.
*
* \funcusage
* \snippet syspm/syspm_2_20_sut_01.cydsn/main_cm4.c snippet_Cy_SysPm_IoUnfreeze
*
*******************************************************************************/
void Cy_SysPm_IoUnfreeze(void)
{
uint32_t interruptState;
interruptState = Cy_SysLib_EnterCriticalSection();
/* Preserve the last reset reason and wakeup polarity. Then, unfreeze I/O:
* write PWR_HIBERNATE.FREEZE=0, .UNLOCK=0x3A, .HIBERANTE=0,
*/
SRSS_PWR_HIBERNATE = (SRSS_PWR_HIBERNATE & CY_SYSPM_PWR_RETAIN_HIBERNATE_STATUS) | CY_SYSPM_PWR_HIBERNATE_UNLOCK;
/* Lock the hibernate mode:
* write PWR_HIBERNATE.HIBERNATE=0, UNLOCK=0x00, HIBERANTE=0
*/
SRSS_PWR_HIBERNATE &= CY_SYSPM_PWR_RETAIN_HIBERNATE_STATUS;
/* Read register to make sure it is settled */
(void) SRSS_PWR_HIBERNATE;
Cy_SysLib_ExitCriticalSection(interruptState);
}
/*******************************************************************************
* Function Name: WriteVoltageBitForFlash
****************************************************************************//**
*
* The internal function that changes the Vcc setting for the flash.
*
* \param value
* Value to be set in the flash voltage control register.
* This bit should be set when the voltage for the core regulators is less than
* 0.99 V.
*
* \return
* CY_SYSPM_SUCCESS - The voltage is set<br>
* CY_SYSPM_CANCELED - Operation was canceled. Call the function again until the
* function returns CY_SYSPM_SUCCESS. See \ref cy_en_syspm_status_t.
*
*******************************************************************************/
static cy_en_syspm_status_t WriteVoltageBitForFlash(uint32_t value)
{
cy_en_syspm_status_t retVal = CY_SYSPM_CANCELED;
uint16_t curDeviceRevision = Cy_SysLib_GetDeviceRevision();
uint16_t curDevice = Cy_SysLib_GetDevice();
/* Read the current protection context value. We can have a direct register
* update if protection context is = 0 */
if ((Cy_Prot_GetActivePC(ACTIVE_BUS_MASTER) == 0U) && (curDevice == CY_SYSLIB_DEVICE_PSOC6ABLE2) && (curDeviceRevision <= SYSPM_DEVICE_REV_0B))
{
FLASHC_FM_CTL_ANA_CTL0 =
_CLR_SET_FLD32U((FLASHC_FM_CTL_ANA_CTL0), FLASHC_FM_CTL_ANA_CTL0_VCC_SEL, value);
retVal = CY_SYSPM_SUCCESS;
}
else
{
uint32_t syscallCode;
/* Set required syscall code */
if (curDevice == CY_SYSLIB_DEVICE_PSOC6ABLE2)
{
syscallCode = (0U != value) ? SET_FLASH_VOLTAGE_BIT_PSOC6ABLE2 : CLEAR_FLASH_VOLTAGE_BIT_PSOC6ABLE2;
}
else
{
syscallCode = (0U != value) ? SET_FLASH_VOLTAGE_BIT : CLEAR_FLASH_VOLTAGE_BIT;
}
/* Tries to acquire the IPC structure and pass the arguments to SROM API */
if (Cy_IPC_Drv_SendMsgWord(Cy_IPC_Drv_GetIpcBaseAddress(CY_IPC_CHAN_SYSCALL),
SYSPM_IPC_NOTIFY_STRUCT0, syscallCode) == CY_IPC_DRV_SUCCESS)
{
/* Checks if the IPC structure is not locked */
while (Cy_IPC_Drv_IsLockAcquired(Cy_IPC_Drv_GetIpcBaseAddress(CY_IPC_CHAN_SYSCALL)))
{
/* Polls whether the IPC is released */
}
/* Read the return status of a syscall */
uint32_t syscallStatus = Cy_IPC_Drv_ReadDataValue(Cy_IPC_Drv_GetIpcBaseAddress(CY_IPC_CHAN_SYSCALL));
if (SYSPM_SYSCALL_STATUS_SUCCESS == (syscallStatus & SYSPM_SYSCALL_STATUS_MASK))
{
retVal = CY_SYSPM_SUCCESS;
}
}
}
return retVal;
}
/*******************************************************************************
* Function Name: SaveRegisters
****************************************************************************//**
*
* The internal function saves non-retained registers before entering Deep Sleep.
* Cypress ID #280370.
*
* \param regs
* The structure where the registers are saved before Deep Sleep.
*
*******************************************************************************/
static void SaveRegisters(cy_stc_syspm_backup_regs_t *regs)
{
/* Save the registers before deep sleep */
regs->CY_UDB_UDBIF_BANK_CTL_REG = UDB_UDBIF_BANK_CTL;
regs->CY_UDB_BCTL_MDCLK_EN_REG = UDB_BCTL_MDCLK_EN;
regs->CY_UDB_BCTL_MBCLK_EN_REG = UDB_BCTL_MBCLK_EN;
regs->CY_UDB_BCTL_BOTSEL_L_REG = UDB_BCTL_BOTSEL_L;
regs->CY_UDB_BCTL_BOTSEL_U_REG = UDB_BCTL_BOTSEL_U;
regs->CY_UDB_BCTL_QCLK_EN0_REG = UDB_BCTL_QCLK_EN_0;
regs->CY_UDB_BCTL_QCLK_EN1_REG = UDB_BCTL_QCLK_EN_1;
regs->CY_UDB_BCTL_QCLK_EN2_REG = UDB_BCTL_QCLK_EN_2;
}
/*******************************************************************************
* Function Name: RestoreRegisters
****************************************************************************//**
*
* The internal function restores the non-retained registers after
* leaving the Deep Sleep power mode. Cypress ID #280370.
*
* \param regs
* The structure with data stored into the required non-retained registers
* after Deep Sleep.
*
*******************************************************************************/
static void RestoreRegisters(cy_stc_syspm_backup_regs_t const *regs)
{
/* Restore the registers after deep sleep */
UDB_BCTL_MDCLK_EN = regs->CY_UDB_BCTL_MDCLK_EN_REG;
UDB_BCTL_MBCLK_EN = regs->CY_UDB_BCTL_MBCLK_EN_REG;
UDB_BCTL_BOTSEL_L = regs->CY_UDB_BCTL_BOTSEL_L_REG;
UDB_BCTL_BOTSEL_U = regs->CY_UDB_BCTL_BOTSEL_U_REG;
UDB_BCTL_QCLK_EN_0 = regs->CY_UDB_BCTL_QCLK_EN0_REG;
UDB_BCTL_QCLK_EN_1 = regs->CY_UDB_BCTL_QCLK_EN1_REG;
UDB_BCTL_QCLK_EN_2 = regs->CY_UDB_BCTL_QCLK_EN2_REG;
UDB_UDBIF_BANK_CTL = regs->CY_UDB_UDBIF_BANK_CTL_REG;
}
#if defined(CY_DEVICE_PSOC6ABLE2) && !defined(CY_PSOC6ABLE2_REV_0A_SUPPORT_DISABLE)
/*******************************************************************************
* Function Name: Cy_EnterDeepSleep
****************************************************************************//**
*
* The internal function that prepares the system for Deep Sleep and
* restores the system after a wakeup from Deep Sleep.
*
* \param waitFor Selects wait for action. See \ref cy_en_syspm_waitfor_t.
*
*******************************************************************************/
#if defined (__ICCARM__)
#pragma diag_suppress=Ta023
__ramfunc
#else
CY_SECTION(".cy_ramfunc") CY_NOINLINE
#endif
static void Cy_EnterDeepSleep(cy_en_syspm_waitfor_t waitFor)
{
/* Acquire the IPC to prevent changing of the shared resources at the same time */
while(0U == _FLD2VAL(IPC_STRUCT_ACQUIRE_SUCCESS, SYSPM_IPC_STC_ACQUIRE))
{
/* Wait until the IPC structure is released by another core */
}
/* Set the flag that current core entered Deep Sleep */
SYSPM_IPC_STC_DATA |= CUR_CORE_DP_MASK;
/* Change the slow and fast clock dividers only under condition that
* the other core is already in Deep Sleep. Cypress ID #284516
*/
if (0U != (SYSPM_IPC_STC_DATA & OTHER_CORE_DP_MASK))
{
/* Get the divider values of the slow and high clocks and store them into
* the IPC data register
*/
SYSPM_IPC_STC_DATA =
(SYSPM_IPC_STC_DATA & ((uint32_t) ~(SYSPM_FAST_CLK_DIV_Msk | SYSPM_SLOW_CLK_DIV_Msk))) |
(((uint32_t)(_FLD2VAL(CPUSS_CM0_CLOCK_CTL_SLOW_INT_DIV, CPUSS_CM0_CLOCK_CTL) << SYSPM_SLOW_CLK_DIV_Pos)) |
((uint32_t)(_FLD2VAL(CPUSS_CM4_CLOCK_CTL_FAST_INT_DIV, CPUSS_CM4_CLOCK_CTL) << SYSPM_FAST_CLK_DIV_Pos)));
/* Increase the clock divider for the slow and fast clocks to SYSPM_CLK_DIVIDER */
CPUSS_CM0_CLOCK_CTL =
_CLR_SET_FLD32U(CPUSS_CM0_CLOCK_CTL, CPUSS_CM0_CLOCK_CTL_SLOW_INT_DIV, SYSPM_CLK_DIVIDER);
CPUSS_CM4_CLOCK_CTL =
_CLR_SET_FLD32U(CPUSS_CM4_CLOCK_CTL, CPUSS_CM4_CLOCK_CTL_FAST_INT_DIV, SYSPM_CLK_DIVIDER);
/* Read the divider value to make sure it is set */
(void) CPUSS_CM0_CLOCK_CTL;
(void) CPUSS_CM4_CLOCK_CTL;
}
/* Release the IPC */
SYSPM_IPC_STC_RELEASE = 0U;
/* Read this register to make sure it is settled */
(void) SYSPM_IPC_STC_RELEASE;
#if (CY_CPU_CORTEX_M4)
/* Repeat the WFI/WFE instruction if a wake up was not intended.
* Cypress ID #272909
*/
do
{
#endif /* (CY_CPU_CORTEX_M4) */
/* The CPU enters Deep Sleep mode upon execution of WFI/WFE */
SCB_SCR |= SCB_SCR_SLEEPDEEP_Msk;
if(waitFor != CY_SYSPM_WAIT_FOR_EVENT)
{
__WFI();
}
else
{
__WFE();
#if (CY_CPU_CORTEX_M4)
/* Call the WFE instruction twice to clear the Event register
* of the CM4 core. Cypress ID #279077
*/
if(wasEventSent)
{
__WFE();
}
wasEventSent = true;
#endif /* (CY_CPU_CORTEX_M4) */
}
#if (CY_CPU_CORTEX_M4)
} while (_FLD2VAL(CPUSS_CM4_PWR_CTL_PWR_MODE, CPUSS_CM4_PWR_CTL) == CM4_PWR_STS_RETAINED);
#endif /* (CY_CPU_CORTEX_M4) */
/* Acquire the IPC to prevent changing of the shared resources at the same time */
while(0U == _FLD2VAL(IPC_STRUCT_ACQUIRE_SUCCESS, SYSPM_IPC_STC_ACQUIRE))
{
/* Wait until the IPC structure is released by another core */
}
/* Read and change the slow and fast clock dividers only under condition
* that the other core is already in Deep Sleep. Cypress ID #284516
*/
if(0U != (SYSPM_IPC_STC_DATA & OTHER_CORE_DP_MASK))
{
/* Restore the clock dividers for the slow and fast clocks */
CPUSS_CM0_CLOCK_CTL =
(_CLR_SET_FLD32U(CPUSS_CM0_CLOCK_CTL, CPUSS_CM0_CLOCK_CTL_SLOW_INT_DIV,
(_FLD2VAL(SYSPM_SLOW_CLK_DIV, SYSPM_IPC_STC_DATA))));
CPUSS_CM4_CLOCK_CTL =
(_CLR_SET_FLD32U(CPUSS_CM4_CLOCK_CTL, CPUSS_CM4_CLOCK_CTL_FAST_INT_DIV,
(_FLD2VAL(SYSPM_FAST_CLK_DIV, SYSPM_IPC_STC_DATA))));
}
/* Indicate that the current core is out of Deep Sleep */
SYSPM_IPC_STC_DATA &= ((uint32_t) ~CUR_CORE_DP_MASK);
/* Release the IPC */
SYSPM_IPC_STC_RELEASE = 0U;
}
#if defined (__ICCARM__)
#pragma diag_default=Ta023
#endif
#endif /* defined(CY_DEVICE_PSOC6ABLE2) && !defined(CY_PSOC6ABLE2_REV_0A_SUPPORT_DISABLE) */
/*******************************************************************************
* Function Name: EnterDeepSleep
****************************************************************************//**
*
* The internal function that prepares the system for Deep Sleep,
* sets the CPU core to the Deep Sleep, and restores the system after a
* wakeup from Deep Sleep.
*
* \param waitFor
* Selects wait for action. See \ref cy_en_syspm_waitfor_t.
*
*******************************************************************************/
#if defined (__ICCARM__)
#pragma diag_suppress=Ta023
__ramfunc
#else
CY_SECTION(".cy_ramfunc") CY_NOINLINE
#endif
static void EnterDeepSleep(cy_en_syspm_waitfor_t waitFor)
{
#if (CY_CPU_CORTEX_M4)
/* Repeat the WFI/WFE instruction if a wake up was not intended.
* Cypress ID #272909
*/
do
{
#endif /* (CY_CPU_CORTEX_M4) */
/* The CPU enters Deep Sleep mode upon execution of WFI/WFE */
SCB_SCR |= SCB_SCR_SLEEPDEEP_Msk;
if(waitFor != CY_SYSPM_WAIT_FOR_EVENT)
{
__WFI();
}
else
{
__WFE();
#if (CY_CPU_CORTEX_M4)
/* Call the WFE instruction twice to clear the Event register
* of the CM4 core. Cypress ID #279077
*/
if(wasEventSent)
{
__WFE();
}
wasEventSent = true;
#endif /* (CY_CPU_CORTEX_M4) */
}
#if (CY_CPU_CORTEX_M4)
} while (_FLD2VAL(CPUSS_CM4_PWR_CTL_PWR_MODE, CPUSS_CM4_PWR_CTL) == CM4_PWR_STS_RETAINED);
#endif /* (CY_CPU_CORTEX_M4) */
/* Acquire the IPC to prevent changing of the shared resources at the same time.
* Shared resources is the BIST_DATA[0] register.
*/
while (0U == _FLD2VAL(IPC_STRUCT_ACQUIRE_SUCCESS, SYSPM_IPC_STC_ACQUIRE))
{
/* Wait until the IPC structure is released by another core */
}
/* Set 10 uS delay only under condition that the DELAY_DONE_FLAG is
* cleared. Cypress ID #288510
*/
if (DELAY_DONE_FLAG == NEED_DELAY)
{
/* Configure the counter to be sourced by IMO */
TST_DDFT_SLOW_CTL_REG = TST_DDFT_SLOW_CTL_MASK;
SRSS_CLK_OUTPUT_SLOW = CLK_OUTPUT_SLOW_MASK;
TST_DDFT_FAST_CTL_REG = TST_DDFT_FAST_CTL_MASK;
/* Load the down-counter to count the 10 uS */
SRSS_CLK_CAL_CNT1 = IMO_10US_DELAY;
while (0U == (SRSS_CLK_CAL_CNT1 & SRSS_CLK_CAL_CNT1_CAL_COUNTER_DONE_Msk))
{
/* Wait until the counter stops counting */
}
/* Indicate that 10 uS delay was done */
DELAY_DONE_FLAG = DELAY_DONE;
}
/* Release the IPC structure in do while loop just to sure that this code
* is not optimized
*/
do
{
SYSPM_IPC_STC_RELEASE = 0U;
} while (0U != 0U);
}
#if defined (__ICCARM__)
#pragma diag_default=Ta023
#endif
/*******************************************************************************
* Function Name: SetReadMarginTrimUlp
****************************************************************************//**
*
* This is the internal function that updates the read-margin trim values for the
* RAM and ROM. The trim update is done during transition of regulator voltage
* from higher to a lower one.
*
*******************************************************************************/
static void SetReadMarginTrimUlp(void)
{
/* Update read-write margin value for the ULP mode. Cypress ID#297292 */
if (Cy_SysLib_GetDevice() == CY_SYSLIB_DEVICE_PSOC6ABLE2)
{
CPUSS_TRIM_RAM_CTL = (CPUSS_TRIM_RAM_CTL & ((uint32_t) ~CPUSS_TRIM_RAM_CTL_RM_Msk)) |
(CPUSS_TRIM_RAM_ULP & CPUSS_TRIM_RAM_CTL_RM_Msk);
CPUSS_TRIM_ROM_CTL = (CPUSS_TRIM_ROM_CTL & ((uint32_t) ~CPUSS_TRIM_ROM_CTL_RM_Msk)) |
(CPUSS_TRIM_ROM_ULP & CPUSS_TRIM_ROM_CTL_RM_Msk);
}
else
{
//CPUSS_TRIM_RAM_CTL = (SFLASH_TRIM_RAM_CTL_HALF_ULP & ((uint32_t) ~CPUSS_TRIM_RAM_CTL_RA_MASK)) |
// (CPUSS_TRIM_RAM_CTL | CPUSS_TRIM_RAM_CTL_RA_MASK);
//CPUSS_TRIM_ROM_CTL = SFLASH_TRIM_ROM_CTL_HALF_ULP;
}
}
/*******************************************************************************
* Function Name: SetReadMarginTrimLp
****************************************************************************//**
*
* The internal function which updates the read-margin trim values for the
* RAM and ROM. The trim update is done during transition of regulator voltage
* from lower to a higher one.
*
*******************************************************************************/
static void SetReadMarginTrimLp(void)
{
/* Update read-write margin value for the LP mode. Cypress ID#297292 */
if (Cy_SysLib_GetDevice() == CY_SYSLIB_DEVICE_PSOC6ABLE2)
{
CPUSS_TRIM_RAM_CTL = (CPUSS_TRIM_RAM_CTL & ((uint32_t) ~CPUSS_TRIM_RAM_CTL_RM_Msk)) |
(CPUSS_TRIM_RAM_LP & CPUSS_TRIM_RAM_CTL_RM_Msk);
CPUSS_TRIM_ROM_CTL = (CPUSS_TRIM_ROM_CTL & ((uint32_t) ~CPUSS_TRIM_ROM_CTL_RM_Msk)) |
(CPUSS_TRIM_ROM_LP & CPUSS_TRIM_ROM_CTL_RM_Msk);
}
else
{
// CPUSS_TRIM_RAM_CTL = (SFLASH_TRIM_ROM_CTL_LP & ((uint32_t) ~CPUSS_TRIM_RAM_CTL_RA_MASK)) |
// (CPUSS_TRIM_RAM_CTL | CPUSS_TRIM_RAM_CTL_RA_MASK);
//CPUSS_TRIM_ROM_CTL = SFLASH_CPUSS_TRIM_ROM_CTL_LP;
}
}
/*******************************************************************************
* Function Name: SetWriteAssistTrimUlp
****************************************************************************//**
*
* The internal function that updates the write assistant trim value for the
* RAM. The trim update is done during transition of regulator voltage
* from higher to a lower.
*
*******************************************************************************/
static void SetWriteAssistTrimUlp(void)
{
/* Update write assist value for the LP mode. Cypress ID#297292 */
if (Cy_SysLib_GetDevice() == CY_SYSLIB_DEVICE_PSOC6ABLE2)
{
CPUSS_TRIM_RAM_CTL = (CPUSS_TRIM_RAM_CTL & ((uint32_t) ~CPUSS_TRIM_RAM_CTL_WA_Msk)) |
(CPUSS_TRIM_RAM_ULP & CPUSS_TRIM_RAM_CTL_WA_Msk);
}
else
{
//CPUSS_TRIM_RAM_CTL = (SFLASH_TRIM_ROM_CTL_ULP & ((uint32_t) ~CPUSS_TRIM_RAM_CTL_RA_MASK)) |
// (CPUSS_TRIM_RAM_CTL | CPUSS_TRIM_RAM_CTL_RA_MASK);
}
}
/*******************************************************************************
* Function Name: SetWriteAssistTrimLp
****************************************************************************//**
*
* The internal function that updates the write assistant trim value for the
* RAM. The trim update is done during transition of regulator voltage
* from lower to a higher one.
*
*******************************************************************************/
static void SetWriteAssistTrimLp(void)
{
/* Update write assist value for the LP mode. Cypress ID#297292 */
if (Cy_SysLib_GetDevice() == CY_SYSLIB_DEVICE_PSOC6ABLE2)
{
CPUSS_TRIM_RAM_CTL = (CPUSS_TRIM_RAM_CTL & ((uint32_t) ~CPUSS_TRIM_RAM_CTL_WA_Msk)) |
(CPUSS_TRIM_RAM_LP & CPUSS_TRIM_RAM_CTL_WA_Msk);
}
else
{
//CPUSS_TRIM_RAM_CTL = (SFLASH_TRIM_ROM_CTL_HALF_LP & ((uint32_t) ~CPUSS_TRIM_RAM_CTL_RA_MASK)) |
// (CPUSS_TRIM_RAM_CTL | CPUSS_TRIM_RAM_CTL_RA_MASK));
//CPUSS_TRIM_ROM_CTL = SFLASH_TRIM_ROM_CTL_HALF_LP;
}
}
/*******************************************************************************
* Function Name: IsVoltageChangePossible
****************************************************************************//**
*
* The internal function that checks wherever it is possible to change the core
* voltage. The voltage change is possible only when the protection context is
* set to zero (PC = 0), or the device supports modifying registers via syscall
*
*******************************************************************************/
static bool IsVoltageChangePossible(void)
{
bool retVal = true;
if (Cy_SysLib_GetDevice() == CY_SYSLIB_DEVICE_PSOC6ABLE2)
{
uint32_t curProtContext = Cy_Prot_GetActivePC(ACTIVE_BUS_MASTER);
retVal = ((Cy_SysLib_GetDeviceRevision() > SYSPM_DEVICE_REV_0B) || (curProtContext == 0U));
}
return (retVal);
}
/* [] END OF FILE */