Project

General

Profile

/*******************************************************************************
* 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 */
(76-76/102)