CAT2 Peripheral Driver Library
SysPm (System Power Management)

Use the System Power Management (SysPm) driver to change power modes and reduce system power consumption in power sensitive designs. More...

Modules

 Macros
 
 Functions
 
 Data Structures
 
 Enumerated Types
 

Detailed Description

Use the System Power Management (SysPm) driver to change power modes and reduce system power consumption in power sensitive designs.

The functions and other declarations used in this driver are in cy_syspm.h. You can include cy_pdl.h to get access to all functions and declarations in the PDL.

Configuration Considerations

Power Modes

PSoC 4 MCUs support three CPU power modes. These power modes are intended to minimize average power consumption in an application.

The CPU Active, Sleep and Deep Sleep power modes are Arm-defined power modes supported by the Arm CPU instruction set architecture (ISA).

Switching CPU into Sleep

All pending interrupts must be cleared before the CPU is put into a Sleep mode, even if they are masked.

Switching into Deep Sleep

All pending interrupts must be cleared before the system is put into a Deep Sleep mode, even if they are masked.

Waking Up from Sleep or Deep Sleep

For Arm-based devices, an interrupt is required for the CPU to wake up.

SysPm Callbacks

The SysPm driver handles low power callbacks declared in the application.

If there are no callbacks registered, the device executes the power mode transition. However, frequently your application firmware must make modifications for low power mode. For example, you may need to disable a peripheral, or ensure that a message is not being transmitted or received.

To enable this, the SysPm driver implements a callback mechanism. When a lower power mode transition is about to take place (either entering or exiting Power Modes), the registered callbacks for that transition are called.

The SysPm driver organizes all the callbacks into a linked list. While entering a low power mode, SysPm goes through that linked list from first to last, executing the callbacks one after another. While exiting low power mode, SysPm goes through that linked list again, but in the opposite direction from last to first. This ordering supports prioritization of callbacks relative to the transition event.

For example, the picture below shows three callback structures organized into a linked list: myDeepSleep1, myDeepSleep2, myDeepSleep3 (represented with the cy_stc_syspm_callback_t configuration structure). Each structure contains, among other fields, the address of the callback function. The code snippets below set this up so that myDeepSleep1 is called first when entering the low power mode. This also means that myDeepSleep1 will be the last one to execute when exiting the low power mode.

The callback structures after registration:

syspm_register_eq.png

Your application must register each callback, so that SysPm can execute it. Upon registration, the linked list is built by the SysPm driver. Notice the &myDeepSleep1 address in the myDeepSleep1 cy_stc_syspm_callback_t structure. This is filled in by the SysPm driver, when you register myDeepSleep1. The cy_stc_syspm_callback_t.order element defines the order of their execution by the SysPm driver. Call Cy_SysPm_RegisterCallback() to register each callback function.

A callback function is typically associated with a particular driver that handles the peripheral. So the callback mechanism enables a peripheral to prepare for a low power mode (for instance, shutting down the analog part); or to perform tasks while exiting a low power mode (like enabling the analog part again).

With the callback mechanism you can prevent switching into a low power mode if a peripheral is not ready. For example, driver X is in the process of receiving a message. In the callback function implementation simply return CY_SYSPM_FAIL in a response to CY_SYSPM_CHECK_READY.

If success is returned while executing a callback, the SysPm driver calls the next callback and so on to the end of the list. If at some point a callback returns CY_SYSPM_FAIL in response to the CY_SYSPM_CHECK_READY step, all the callbacks that have already executed are executed in reverse order, with the CY_SYSPM_CHECK_FAIL mode parameter. This allows each callback to know that entering the low power mode has failed. The callback can then undo whatever it did to prepare for low power mode, if required. For example, if the driver X callback shut down the analog part, it can re-enable the analog part.

Let's switch to an example explaining the implementation, setup, and registration of three callbacks (myDeepSleep1, myDeepSleep2, myDeepSleep2) in the application. The Callback Configuration Considerations are provided after the SysPm Callbacks Example.

SysPm Callbacks Example

The following code snippets demonstrate how use the SysPm callbacks mechanism. We will build the prototype for an application that registers three callback functions:

  1. MyDeepSleepFunc1 - Handles CPU Deep Sleep.
  2. MyDeepSleepFunc2 - Handles CPU Deep Sleep and is associated with peripheral HW1_address.
  3. MyDeepSleepFunc3 - Handles entering and exiting system Deep Sleep and is associated with peripheral HW2_address.

We set the myDeepSleep1 and myDeepSleep2 callbacks structures to do nothing while entering the low power mode (skip on CY_SYSPM_SKIP_BEFORE_TRANSITION - see Callback Function Implementation in Callback Configuration Considerations). Skipping the actions while entering low power might be useful if you need to save time while switching low power modes. This is because the callback function with a skipped mode is not even called avoiding the call and return overhead.

Let's first declare the callback functions. Each gets the pointer to the cy_stc_syspm_callback_params_t structure as the argument.

/* Scenario: There is a need to have three callbacks for the CPU Deep Sleep
* mode. MyDeepSleepFunc1 and MyDeepSleepFunc2 callback function skip
* CY_SYSPM_BEFORE_TRANSITION mode.
* MyDeepSleepFunc3 executes all four modes.
*/
/******************************************************************************
* Callback prototypes
******************************************************************************/

Now we setup the cy_stc_syspm_callback_params_t structures that we will pass to the callback functions. Note that for the MyDeepSleepFunc2 and MyDeepSleepFunc3 callbacks we also pass pointers to the peripherals related to that callback. The configuration considerations related to this structure are described in Callback Function Parameters in Callback Configuration Considerations.

/******************************************************************************
* Parameter structures for callback functions
******************************************************************************/
{
/* .base */ NULL,
/* .context */ NULL
};
{
/* .base */ &HW1_address,
/* .context */ &SysPmContext
};
{
/* .base */ &HW2_address,
/* .context */ NULL
};

Now we setup the actual callback configuration structures. Each of these contains, among the other fields, the address of the cy_stc_syspm_callback_params_t we just set up. We will use the callback configuration structures later in the code to register the callbacks in the SysPm driver. Again, we set things up so that the MyDeepSleepFunc1 and MyDeepSleepFunc2 callbacks do nothing while entering the low power mode (skip on CY_SYSPM_SKIP_BEFORE_TRANSITION) - see Callback Function Implementation in Callback Configuration Considerations.

/******************************************************************************
* Callbacks structures
******************************************************************************/
{
/* .callback */ &MyDeepSleepFunc1,
/* .type */ CY_SYSPM_DEEPSLEEP,
/* .callbackParams */ &deepSleepParam1,
/* .prevItm */ NULL,
/* .nextItm */ NULL,
/* .order */ 0
};
{
/* .callback */ &MyDeepSleepFunc2,
/* .type */ CY_SYSPM_DEEPSLEEP,
/* .callbackParams */ &deepSleepParam2,
/* .prevItm */ NULL,
/* .nextItm */ NULL,
/* .order */ 0
};
{
/* .callback */ &MyDeepSleepFunc3,
/* .type */ CY_SYSPM_DEEPSLEEP,
/* .skipMode */ 0U,
/* .callbackParams */ &deepSleepParam3,
/* .prevItm */ NULL,
/* .nextItm */ NULL,
/* .order */ 0
};

Note that in each case the last two fields are NULL. These are fields used by the SysPm driver to set up the linked list of callback functions.

The callback structures are now defined and allocated in the user's memory space:

syspm_before_registration.png

Now we implement the callback functions. See Callback Function Implementation in Callback Configuration Considerations for the instructions on how the callback functions should be implemented.

/******************************************************************************
* MyDeepSleepFunc1 implementation
******************************************************************************/
{
if (callbackParams != NULL)
{
/* In this use case we do not need to use HW address or context
* So, need to add code to some switch case with callbackParams to avoid
* compiler warnings
*/
}
switch(mode)
{
/* In this case ensure that firmware/hardware is ready for CPU
* Deep Sleep mode */
if(true/* system is ready */)
{
/* Process the "check ready" condition */
retVal = CY_SYSPM_SUCCESS;
}
break;
/* One of the registered callback that was executed after this callback
* returned CY_SYSPM_FAIL, need to revert changes (if any) performed in
* the CY_SYSPM_CHECK_READY case.
*/
{
/* Revert changes done in the CY_SYSPM_CHECK_READY case */
retVal = CY_SYSPM_SUCCESS;
}
break;
/* This case will be skipped during callbacks execution */
break;
/* This case is executed after wakeup from system Deep Sleep */
{
/* Perform actions, if required, after wakeup from the
* system Deep Sleep mode */
retVal = CY_SYSPM_SUCCESS;
}
break;
default:
break;
}
return (retVal);
}
/******************************************************************************
* MyDeepSleepFunc2 implementation
******************************************************************************/
{
CySCB_Type *hwBase = (CySCB_Type *) callbackParams->base;
cy_stc_scb_spi_context_t *stcPmContext = (cy_stc_scb_spi_context_t *) callbackParams->context;
switch(mode)
{
/* Check is the HW1 ready to enter CPU Deep Sleep */
{
/* ... */
if (0UL == (CY_SCB_SPI_TRANSFER_ACTIVE & Cy_SCB_SPI_GetTransferStatus(hwBase, stcPmContext)))
{
/* There are no active actions so we can enter CPU Deep Sleep */
retVal = CY_SYSPM_SUCCESS;
}
break;
}
default:
retVal = CY_SYSPM_FAIL;
break;
}
return (retVal);
}
/******************************************************************************
* MyDeepSleepFunc3 implementation
******************************************************************************/
{
CySCB_Type *hwBase = (CySCB_Type *) callbackParams->base;
switch(mode)
{
/* Check is the HW2 ready to enter into CPU Deep Sleep */
{
if (!Cy_SCB_SPI_IsBusBusy(hwBase))
{
/* Process the "check ready" condition */
retVal = CY_SYSPM_SUCCESS;
}
break;
}
{
/* Switch - Turn off SCB SPI */
retVal = CY_SYSPM_SUCCESS;
break;
}
{
/* Switch - Turn on SCB SPI */
retVal = CY_SYSPM_SUCCESS;
break;
}
{
/* Revert changes made in CY_SYSPM_CHECK_READY switch case (if any) */
break;
}
default:
break;
}
return (retVal);
}

Finally, we register the callbacks so that the SysPm driver knows about them. The order in which the callbacks will be called depends upon the order in which the callbacks are registered. If there are no callbacks registered, the device just executes the power mode transition, without additional interruptions.

Callbacks that reconfigure global resources, such as clock frequencies, should be registered last. They then modify global resources as the final step before entering the low power mode, and restore those resources first, as the system returns from low power mode.

/* Register myDeepSleep1 */
if (true != Cy_SysPm_RegisterCallback(&myDeepSleep1))
{
/* Insert error handling */
}
/* Register myDeepSleep2 */
if (true != Cy_SysPm_RegisterCallback(&myDeepSleep2))
{
/* Insert error handling */
}
/* Register myDeepSleep3 */
if (true != Cy_SysPm_RegisterCallback(&myDeepSleep3))
{
/* Insert error handling */
}

We are done configuring three callbacks. Now the SysPm driver will execute the callbacks appropriately whenever there is a call to a power mode transition function: Cy_SysPm_CpuEnterSleep(), Cy_SysPm_CpuEnterDeepSleep().

Refer to Callback Unregistering in Callback Configuration Considerations to learn what to do if you need to remove the callback from the linked list. You might want to unregister the callback for debug purposes.

Refer to Callbacks Execution Flow in Callback Configuration Considerations to learn about how the SysPm processes the callbacks.

Callback Configuration Considerations

Callback Function Parameters

The callbackParams parameter of the callback function is a cy_stc_syspm_callback_params_t structure. The second parameter (mode) is for internal use. In the example code we used a dummy value CY_SYSPM_CHECK_READY to eliminate compilation errors associated with the enumeration. The driver sets the mode field to the correct value when calling the callback functions (the mode is referred to as step in the Callback Function Implementation). The callback function reads the value and executes code based on the mode set by the SysPm driver. The base and context fields are optional and can be NULL. Some drivers require a base hardware address and context to store information about the mode transition. If your callback routine requires access to the driver registers or context, provide those values. Be aware of MISRA warnings if these parameters are NULL.

Callback Function Structure

For each callback, provide a cy_stc_syspm_callback_t structure. Some fields in this structure are maintained by the driver. Use NULL for cy_stc_syspm_callback_t.prevItm and cy_stc_syspm_callback_t.nextItm. Driver uses these fields to build a linked list of callback functions. The value of cy_stc_syspm_callback_t.order element is used to define the order how the callbacks are put into linked list, and sequentially, how the callbacks are executed. See Callback Registering section.

Warning
The Cy_SysPm_RegisterCallback() function stores a pointer to the cy_stc_syspm_callback_t structure. Do not modify elements of the cy_stc_syspm_callback_t structure after the callback is registered. You are responsible for ensuring that the structure remains in scope. Typically the structure is declared as a global or static variable, or as a local variable in the main() function.

Callback Function Implementation

Every callback function should handle four possible steps (referred to as "mode") defined in cy_en_syspm_callback_mode_t :

A callback function can skip steps (see Defines to skip the callbacks modes). In our example myDeepSleep1 and myDeepSleep2 callbacks do nothing while entering the low power mode (skip on CY_SYSPM_BEFORE_TRANSITION). If there is anything preventing low power mode entry - return CY_SYSPM_FAIL in response to CY_SYSPM_CHECK_READY in your callback implementation. Note that the callback should return CY_SYSPM_FAIL only in response to CY_SYSPM_CHECK_READY. The callback function should always return CY_SYSPM_PASS for other modes: CY_SYSPM_CHECK_FAIL, CY_SYSPM_BEFORE_TRANSITION, and CY_SYSPM_AFTER_TRANSITION (see Callbacks Execution Flow).

Callbacks Execution Flow

This section explains what happens during a power transition, when callbacks are implemented and set up correctly. The following discussion assumes:

User calls Cy_SysPm_CpuEnterSleep() or Cy_SysPm_CpuEnterDeepSleep(). It calls each callback with the mode set to CY_SYSPM_CHECK_READY. This triggers execution of the code for that mode inside of each user callback.

The intent of CY_SYSPM_CHECK_READY is to only signal if the resources is ready to transition. Ideally, no transition changes should be made at this time. In some cases a small change may be required. For example a communication resource callback may set a flag telling firmware not to start any new transition.

If that process is successful for all callbacks, then Cy_SysPm_ExecuteCallback() calls each callback with the mode set to CY_SYSPM_BEFORE_TRANSITION. This triggers execution of the code for that mode inside each user callback. We then enter the low power mode after all callback are executed.

When exiting the low power mode, the SysPm driver executes Cy_SysPm_ExecuteCallback() again. This time it calls each callback in reverse order, with the mode set to CY_SYSPM_AFTER_TRANSITION. This triggers execution of the code for that mode inside each user callback.

A callback can return CY_SYSPM_FAIL only while executing the CY_SYSPM_CHECK_READY mode. If that happens, then the remaining callbacks are not executed. Any callbacks that have already executed are called again, in reverse order, with CY_SYSPM_CHECK_FAIL. This allows the system to return to the previous state. If a callback returns a fail then any of the functions (Cy_SysPm_CpuEnterSleep(), Cy_SysPm_CpuEnterDeepSleep()) that attempt to switch the device into a low power mode will also return CY_SYSPM_FAIL.

Callbacks that reconfigure global resources, such as clock frequencies, should be registered last. They then modify global resources as the final step before entering the low power mode, and restore those resources first, as the system returns from low power mode.

Callback Registering

While registration the callback is put into the linked list. The place where the callback structure is put into the linked list is based on cy_stc_syspm_callback_t.order. The callback with the lowest cy_stc_syspm_callback_t.order value will be placed at the beginning of linked list. The callback with the highest cy_stc_syspm_callback_t.order value will be placed at the end of the linked list. If there is already a callback structure in the linked list with the same cy_stc_syspm_callback_t.order value as you attend to register, then your callback will be placed right after such a callback.

Such a registration order defines how the callbacks are executed:

/* Register myDeepSleep1 */
if (true != Cy_SysPm_RegisterCallback(&myDeepSleep1))
{
/* Insert error handling */
}
/* Register myDeepSleep2 */
if (true != Cy_SysPm_RegisterCallback(&myDeepSleep2))
{
/* Insert error handling */
}
/* Register myDeepSleep3 */
if (true != Cy_SysPm_RegisterCallback(&myDeepSleep3))
{
/* Insert error handling */
}

Callbacks with equal cy_stc_syspm_callback_t.order values are registered in the same order as they are registered:

syspm_register_eq.png

Callbacks with a different cy_stc_syspm_callback_t.order value will be stored based on the cy_stc_syspm_callback_t.order value, with no matter when they when registered:

syspm_register_dif.png

This can be useful to ensure that system resources (clock dividers, etc) are changed right before entering low power mode and immediately after exiting from low power.

Callback Unregistering

Unregistering the callback might be useful when you need to dynamically manage the callbacks.

/* Scenario: There is a need to unregister a previously registered callback */
if (true != Cy_SysPm_UnregisterCallback(&myDeepSleep2))
{
/* Insert error handler */
}

The callback structures after myDeepSleep2 callback is unregistered:

syspm_unregistration.png

More Information

For more information on the SysPm driver, refer to the technical reference manual (TRM).

Changelog

VersionChangesReason for Change
3.0 Added Cy_SysPm_CpuEnterSleepNoCallbacks() and Cy_SysPm_CpuEnterDeepSleepNoCallbacks(). Alternative to Cy_SysPm_CpuEnterSleep() and Cy_SysPm_CpuEnterDeepSleep() but without execution of registered callbacks. The newly added functions can be used for minimization of flash memory consumption and/or speed-up of the Low-power mode entry/exit. The application is responsible for preparing a device for entering Low-power mode and restoring its state on a wakeup. Flash memory consumption optimization
Removed unused status macros. Code cleanup.
2.10.1 Update the paths to the code snippets. PDL structure update.
2.10 Corrected the size of the internal callback array to match the number of the supported low power modes. Implementation enhancement.
2.0 Cy_SysPm_CpuEnterDeepSleep is changed so that the Cy_SysClk_DeepSleepCallback registration is needed. The clock tree manipulation code is removed. SysClk enhancement, see Low Power Callback
1.0 Initial version