|
/*******************************************************************************
|
|
* File Name: cyPm.c
|
|
* Version 5.0
|
|
*
|
|
* Description:
|
|
* Provides an API for the power management.
|
|
*
|
|
* Note:
|
|
* Documentation of the API's in this file is located in the
|
|
* System Reference Guide provided with PSoC Creator.
|
|
*
|
|
********************************************************************************
|
|
* Copyright 2011-2015, Cypress Semiconductor Corporation. All rights reserved.
|
|
* You may use this file only in accordance with the license, terms, conditions,
|
|
* disclaimers, and limitations in the end user license agreement accompanying
|
|
* the software package with which this file was provided.
|
|
*******************************************************************************/
|
|
|
|
#include "cyPm.h"
|
|
#include "CyLib.h"
|
|
|
|
|
|
/*******************************************************************************
|
|
* Function Name: CySysPmSleep
|
|
********************************************************************************
|
|
*
|
|
* Summary:
|
|
* Puts the part into the Sleep state. This is a CPU-centric power mode.
|
|
* It means that the CPU has indicated that it is in the sleep mode and
|
|
* its main clock can be removed. It is identical to Active from a peripheral
|
|
* point of view. Any enabled interrupts can cause wakeup from the Sleep mode.
|
|
*
|
|
* Parameters:
|
|
* None
|
|
*
|
|
* Return:
|
|
* None
|
|
*
|
|
*******************************************************************************/
|
|
void CySysPmSleep(void)
|
|
{
|
|
uint8 interruptState;
|
|
|
|
interruptState = CyEnterCriticalSection();
|
|
|
|
/* CM0 enters Sleep mode upon execution of WFI */
|
|
CY_PM_CM0_SCR_REG &= (uint32) (~CY_PM_CM0_SCR_SLEEPDEEP);
|
|
|
|
/* Sleep and wait for interrupt */
|
|
CY_PM_WFI;
|
|
|
|
CyExitCriticalSection(interruptState);
|
|
}
|
|
|
|
|
|
/*******************************************************************************
|
|
* Function Name: CySysPmDeepSleep
|
|
********************************************************************************
|
|
*
|
|
* Summary:
|
|
* Puts the part into the Deep Sleep state. 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 Sleep mode
|
|
* instead and automatically enter the originally intended mode when the
|
|
* holdoff expires.
|
|
*
|
|
* The wakeup occurs when an interrupt is received from a DeepSleep or
|
|
* Hibernate peripheral. For more details, see a corresponding
|
|
* peripheral's datasheet.
|
|
*
|
|
* Parameters:
|
|
* None
|
|
*
|
|
* Return:
|
|
* None
|
|
*
|
|
*******************************************************************************/
|
|
void CySysPmDeepSleep(void)
|
|
{
|
|
uint8 interruptState;
|
|
#if(CY_IP_SRSSV2)
|
|
volatile uint32 clkSelectReg;
|
|
#endif /* (CY_IP_SRSSV2) */
|
|
|
|
interruptState = CyEnterCriticalSection();
|
|
|
|
#if(CY_IP_SRSSV2)
|
|
/* Device enters DeepSleep mode when CPU asserts SLEEPDEEP signal */
|
|
CY_PM_PWR_CONTROL_REG &= (uint32) (~CY_PM_PWR_CONTROL_HIBERNATE);
|
|
#endif /* (CY_IP_SRSSV2) */
|
|
|
|
#if (CY_PSOC4_4100 || CY_PSOC4_4200)
|
|
CY_PM_CPUSS_CONFIG_REG |= CY_PM_CPUSS_CONFIG_FLSH_ACC_BYPASS;
|
|
#endif /* (CY_PSOC4_4100 || CY_PSOC4_4200) */
|
|
|
|
/* Adjust delay to wait for references to settle on wakeup from Deep Sleep */
|
|
CY_PM_PWR_KEY_DELAY_REG = CY_SFLASH_DPSLP_KEY_DELAY_REG;
|
|
|
|
/* CM0 enters DeepSleep/Hibernate mode upon execution of WFI */
|
|
CY_PM_CM0_SCR_REG |= CY_PM_CM0_SCR_SLEEPDEEP;
|
|
|
|
#if(CY_IP_SRSSV2)
|
|
/* Preserve system clock configuration and
|
|
* reduce sysclk to <=12 MHz (Cypress ID #158710, #179888).
|
|
*/
|
|
clkSelectReg = CY_SYS_CLK_SELECT_REG;
|
|
CySysClkWriteSysclkDiv(CY_SYS_CLK_SYSCLK_DIV4);
|
|
#endif /* (CY_IP_SRSSV2) */
|
|
|
|
/* Sleep and wait for interrupt */
|
|
CY_PM_WFI;
|
|
|
|
#if(CY_IP_SRSSV2)
|
|
/* Restore system clock configuration */
|
|
CY_SYS_CLK_SELECT_REG = clkSelectReg;
|
|
#endif /* (CY_IP_SRSSV2) */
|
|
|
|
#if (CY_PSOC4_4100 || CY_PSOC4_4200)
|
|
CY_PM_CPUSS_CONFIG_REG &= (uint32) (~CY_PM_CPUSS_CONFIG_FLSH_ACC_BYPASS);
|
|
#endif /* (CY_PSOC4_4100 || CY_PSOC4_4200) */
|
|
|
|
CyExitCriticalSection(interruptState);
|
|
}
|
|
|
|
|
|
#if(CY_IP_SRSSV2)
|
|
|
|
/*******************************************************************************
|
|
* Function Name: CySysPmHibernate
|
|
********************************************************************************
|
|
*
|
|
* Summary:
|
|
* Puts the part into the Hibernate state. Only SRAM and UDBs are retained;
|
|
* most internal supplies are off. Wakeup is possible from a pin or a hibernate
|
|
* comparator only.
|
|
*
|
|
* It is expected that the firmware has already frozen the IO-Cells using
|
|
* CySysPmFreezeIo() function before the call to this function. If this is
|
|
* omitted, the IO-cells will be frozen in the same way as they are
|
|
* in the Active to Deep Sleep transition, but will lose their state on wake up
|
|
* (because of the reset occurring at that time).
|
|
*
|
|
* Because all the CPU state is lost, the CPU will start up at the reset vector.
|
|
* To save the firmware state through the Hibernate low power mode, a
|
|
* corresponding variable should be defined with CY_NOINIT attribute. It
|
|
* prevents data from being initialized to zero on startup. The interrupt
|
|
* cause of the hibernate peripheral is retained, such that it can be either
|
|
* read by the firmware or cause an interrupt after the firmware has booted and
|
|
* enabled the corresponding interrupt. To distinguish the wakeup from
|
|
* the Hibernate mode and the general Reset event, the CySysPmGetResetReason()
|
|
* function could be used.
|
|
*
|
|
* Parameters:
|
|
* None
|
|
*
|
|
* Return:
|
|
* None
|
|
*
|
|
*******************************************************************************/
|
|
void CySysPmHibernate(void)
|
|
{
|
|
uint8 interruptState;
|
|
|
|
interruptState = CyEnterCriticalSection();
|
|
|
|
/* Device enters Hibernate mode when CPU asserts SLEEPDEEP signal */
|
|
CY_PM_PWR_CONTROL_REG |= CY_PM_PWR_CONTROL_HIBERNATE;
|
|
|
|
/* Adjust delay to wait for references to settle on wakeup from hibernate */
|
|
CY_PM_PWR_KEY_DELAY_REG = CY_SFLASH_HIB_KEY_DELAY_REG;
|
|
|
|
/* CM0 enters DeepSleep/Hibernate mode upon execution of WFI */
|
|
CY_PM_CM0_SCR_REG |= CY_PM_CM0_SCR_SLEEPDEEP;
|
|
|
|
/* Save token that will retain through a STOP/WAKEUP sequence
|
|
* thus could be used by CySysPmGetResetReason() to differentiate
|
|
* WAKEUP from a general RESET event.
|
|
*/
|
|
CY_PM_PWR_STOP_REG = (CY_PM_PWR_STOP_REG & (uint32)(~CY_PM_PWR_STOP_TOKEN_MASK)) | CY_PM_PWR_STOP_TOKEN_HIB;
|
|
|
|
/* Sleep and wait for interrupt. Wakeup from Hibernate is performed
|
|
* through RESET state, causing a normal Boot procedure to occur.
|
|
* The WFI instruction doesn't put the core to sleep if its wake condition
|
|
* is true when the instruction is executed.
|
|
*/
|
|
CY_PM_WFI;
|
|
|
|
CyExitCriticalSection(interruptState);
|
|
}
|
|
|
|
|
|
/*******************************************************************************
|
|
* Function Name: CySysPmStop
|
|
********************************************************************************
|
|
*
|
|
* Summary:
|
|
* Puts the part into the Stop state. All internal supplies are off;
|
|
* no state is retained.
|
|
*
|
|
* Wakeup from Stop is performed by toggling the wakeup pin, causing
|
|
* a normal boot procedure to occur. To configure the wakeup pin,
|
|
* the Digital Input Pin component should be placed on the schematic,
|
|
* assigned to the wakeup pin, and resistively pulled up or down to the inverse
|
|
* state of the wakeup polarity. To distinguish the wakeup from the Stop mode
|
|
* and the general Reset event, CySysPmGetResetReason() function could be used.
|
|
* The wakeup pin is active low by default. The wakeup pin polarity
|
|
* could be changed with the CySysPmSetWakeupPolarity() function.
|
|
*
|
|
* This function freezes IO cells implicitly. It is not possible to enter
|
|
* the STOP mode before freezing the IO cells. The IO cells remain frozen after
|
|
* awake from the Stop mode until the firmware unfreezes them after booting
|
|
* explicitly with CySysPmUnfreezeIo() function call.
|
|
*
|
|
* Parameters:
|
|
* None
|
|
*
|
|
* Return:
|
|
* None
|
|
*
|
|
*******************************************************************************/
|
|
void CySysPmStop(void)
|
|
{
|
|
(void) CyEnterCriticalSection();
|
|
|
|
/* Update token to indicate Stop mode transition. Preserve only polarity. */
|
|
CY_PM_PWR_STOP_REG = (CY_PM_PWR_STOP_REG & CY_PM_PWR_STOP_POLARITY) | CY_PM_PWR_STOP_TOKEN_STOP;
|
|
|
|
/* Freeze IO-Cells to save IO-Cell state */
|
|
CySysPmFreezeIo();
|
|
|
|
/* Initiates transition to Stop state */
|
|
CY_PM_PWR_STOP_REG = CY_PM_PWR_STOP_REG | CY_PM_PWR_STOP_STOP;
|
|
|
|
/* Depending on the clock frequency and internal timing delays,
|
|
* the final AHB transaction may or may not complete. To guard against
|
|
* accidentally executing an unintended instruction, it is recommended
|
|
* to add 2 NOP cycles after the final write to the STOP register.
|
|
*/
|
|
CY_NOP;
|
|
CY_NOP;
|
|
|
|
/* Should never get to this WFI instruction */
|
|
CY_PM_WFI;
|
|
|
|
/* Wakeup from Stop is performed by toggling of Wakeup pin,
|
|
* causing a normal Boot procedure to occur. No need to exit
|
|
* from the critical section.
|
|
*/
|
|
}
|
|
|
|
|
|
/*******************************************************************************
|
|
* Function Name: CySysPmSetWakeupPolarity
|
|
********************************************************************************
|
|
*
|
|
* Summary:
|
|
* Wake up from the stop mode is performed by toggling the wakeup pin,
|
|
* causing a normal boot procedure to occur. This function assigns
|
|
* the wakeup pin active level. Setting the wakeup pin to this level will cause
|
|
* the wakeup from stop mode. The wakeup pin is active low by default.
|
|
*
|
|
* Parameters:
|
|
* polarity: Wakeup pin active level:
|
|
* Value Define Level
|
|
* 0 CY_PM_STOP_WAKEUP_ACTIVE_LOW Logical zero will wakeup the chip
|
|
* 1 CY_PM_STOP_WAKEUP_ACTIVE_HIGH Logical one will wakeup the chip
|
|
*
|
|
* Return:
|
|
* None
|
|
*
|
|
*******************************************************************************/
|
|
void CySysPmSetWakeupPolarity(uint32 polarity)
|
|
{
|
|
uint8 interruptState;
|
|
|
|
interruptState = CyEnterCriticalSection();
|
|
|
|
CY_PM_PWR_STOP_REG = (CY_PM_STOP_WAKEUP_ACTIVE_LOW != polarity) ?
|
|
(CY_PM_PWR_STOP_REG | CY_PM_PWR_STOP_POLARITY) :
|
|
(CY_PM_PWR_STOP_REG & (uint32) (~CY_PM_PWR_STOP_POLARITY));
|
|
|
|
CyExitCriticalSection(interruptState);
|
|
}
|
|
|
|
|
|
/*******************************************************************************
|
|
* Function Name: CySysPmGetResetReason
|
|
********************************************************************************
|
|
*
|
|
* Summary:
|
|
* Retrieves the last reset reason - transition from OFF/XRES/STOP/HIBERNATE to
|
|
* the RESET state. Note that waking up from STOP using XRES will be perceived
|
|
* as a general RESET.
|
|
*
|
|
* Parameters:
|
|
* None
|
|
*
|
|
* Return:
|
|
* Reset reason.
|
|
* CY_PM_RESET_REASON_UNKN - unknown
|
|
* CY_PM_RESET_REASON_XRES - transition from OFF/XRES to RESET
|
|
* CY_PM_RESET_REASON_WAKEUP_HIB - transition/wakeup from HIBERNATE to RESET
|
|
* CY_PM_RESET_REASON_WAKEUP_STOP - transition/wakeup from STOP to RESET
|
|
*
|
|
*******************************************************************************/
|
|
uint32 CySysPmGetResetReason(void)
|
|
{
|
|
uint32 reason = CY_PM_RESET_REASON_UNKN;
|
|
|
|
switch(CY_PM_PWR_STOP_REG & CY_PM_PWR_STOP_TOKEN_MASK)
|
|
{
|
|
/* Power up, XRES */
|
|
case CY_PM_PWR_STOP_TOKEN_XRES:
|
|
reason = CY_PM_RESET_REASON_XRES;
|
|
break;
|
|
|
|
/* Wakeup from Hibernate */
|
|
case CY_PM_PWR_STOP_TOKEN_HIB:
|
|
reason = CY_PM_RESET_REASON_WAKEUP_HIB;
|
|
break;
|
|
|
|
/* Wakeup from Stop (through WAKEUP pin assert) */
|
|
case CY_PM_PWR_STOP_TOKEN_STOP:
|
|
reason = CY_PM_RESET_REASON_WAKEUP_STOP;
|
|
break;
|
|
|
|
/* Unknown reason */
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return (reason);
|
|
}
|
|
|
|
|
|
/*******************************************************************************
|
|
* Function Name: CySysPmFreezeIo
|
|
********************************************************************************
|
|
*
|
|
* Summary:
|
|
* Freezes IO-Cells directly to save the IO-Cell state on wake up from the
|
|
* Hibernate or Stop state. It is not required to call this function before
|
|
* entering the Stop mode, since CySysPmStop() function freezes IO-Cells
|
|
* implicitly.
|
|
*
|
|
* Parameters:
|
|
* None
|
|
*
|
|
* Return:
|
|
* None
|
|
*
|
|
*******************************************************************************/
|
|
void CySysPmFreezeIo(void)
|
|
{
|
|
uint8 interruptState;
|
|
|
|
interruptState = CyEnterCriticalSection();
|
|
|
|
/* Check FREEZE state to avoid recurrent IO-Cells freeze attempt,
|
|
* since the second call to this function will cause accidental switch
|
|
* to the STOP mode (the system will enter STOP mode immediately after
|
|
* writing to STOP bit since both UNLOCK and FREEZE have been set correctly
|
|
* in a previous call to this function).
|
|
*/
|
|
if (0u == (CY_PM_PWR_STOP_REG & CY_PM_PWR_STOP_FREEZE))
|
|
{
|
|
/* Preserve last reset reason and disable overrides the next freeze command by peripherals */
|
|
CY_PM_PWR_STOP_REG = CY_PM_PWR_STOP_STOP | CY_PM_PWR_STOP_FREEZE | CY_PM_PWR_STOP_UNLOCK |
|
|
(CY_PM_PWR_STOP_REG & (CY_PM_PWR_STOP_TOKEN_MASK | CY_PM_PWR_STOP_POLARITY));
|
|
|
|
/* If reading after writing, read this register three times to delay
|
|
* enough time for internal settling.
|
|
*/
|
|
(void) CY_PM_PWR_STOP_REG;
|
|
(void) CY_PM_PWR_STOP_REG;
|
|
|
|
/* Second write causes the freeze of IO-Cells to save IO-Cell state */
|
|
CY_PM_PWR_STOP_REG = CY_PM_PWR_STOP_REG;
|
|
}
|
|
|
|
CyExitCriticalSection(interruptState);
|
|
}
|
|
|
|
|
|
/*******************************************************************************
|
|
* Function Name: CySysPmUnfreezeIo
|
|
********************************************************************************
|
|
*
|
|
* Summary:
|
|
* The IO-Cells remain frozen after awake from Hibernate or Stop mode until
|
|
* the firmware unfreezes them after booting. The call of this function
|
|
* unfreezes IO-Cells explicitly.
|
|
*
|
|
* If the firmware intent is to retain the data value on the port, then the
|
|
* value must be read and re-written to the data register before calling this
|
|
* API. Furthermore, the drive mode must be re-programmed. If this is not done,
|
|
* the pin state will change to default state the moment the freeze is removed.
|
|
*
|
|
* This API is not available for PSoC 4000 family of devices.
|
|
*
|
|
* Parameters:
|
|
* None
|
|
*
|
|
* Return:
|
|
* None
|
|
*
|
|
*******************************************************************************/
|
|
void CySysPmUnfreezeIo(void)
|
|
{
|
|
uint8 interruptState;
|
|
|
|
interruptState = CyEnterCriticalSection();
|
|
|
|
/* Preserve last reset reason and wakeup polarity. Then, unfreeze I/O:
|
|
* write PWR_STOP.FREEZE=0, .UNLOCK=0x3A, .STOP=0, .TOKEN
|
|
*/
|
|
CY_PM_PWR_STOP_REG = CY_PM_PWR_STOP_UNLOCK |
|
|
(CY_PM_PWR_STOP_REG & (CY_PM_PWR_STOP_TOKEN_MASK | CY_PM_PWR_STOP_POLARITY));
|
|
|
|
/* If reading after writing, read this register three times to delay
|
|
* enough time for internal settling.
|
|
*/
|
|
(void) CY_PM_PWR_STOP_REG;
|
|
(void) CY_PM_PWR_STOP_REG;
|
|
|
|
/* Lock STOP mode: write PWR_STOP.FREEZE=0, UNLOCK=0x00, STOP=0, .TOKEN */
|
|
CY_PM_PWR_STOP_REG &= (CY_PM_PWR_STOP_TOKEN_MASK | CY_PM_PWR_STOP_POLARITY);
|
|
|
|
CyExitCriticalSection(interruptState);
|
|
}
|
|
|
|
#else
|
|
|
|
/*******************************************************************************
|
|
* Function Name: CySysPmSetWakeupHoldoff
|
|
********************************************************************************
|
|
*
|
|
* Summary:
|
|
* Sets the Deep Sleep wakeup time by scaling the hold-off to the HFCLK
|
|
* frequency.
|
|
*
|
|
* This function must be called before increasing HFCLK clock frequency. It can
|
|
* optionally be called after lowering HFCLK clock frequency in order to improve
|
|
* Deep Sleep wakeup time.
|
|
*
|
|
* It is functionally acceptable to leave the default hold-off setting, but
|
|
* Deep Sleep wakeup time may exceed the specification.
|
|
*
|
|
* This function is applicable only for the 4000 device family.
|
|
*
|
|
* Parameters:
|
|
* uint32 hfclkFrequencyMhz: The HFCLK frequency in MHz.
|
|
*
|
|
* Return:
|
|
* None
|
|
*
|
|
*******************************************************************************/
|
|
void CySysPmSetWakeupHoldoff(uint32 hfclkFrequencyMhz)
|
|
{
|
|
CY_PM_PWR_KEY_DELAY_REG = ((((uint32)(CY_PM_PWR_KEY_DELAY_REG_DEFAULT << 16u) /
|
|
CY_PM_PWR_KEY_DELAY_FREQ_DEFAULT) * hfclkFrequencyMhz) >> 16u) + 1u;
|
|
}
|
|
|
|
#endif /* (CY_IP_SRSSV2) */
|
|
|
|
|
|
/* [] END OF FILE */
|