NXP S32K146 Power Manager Component分析

今天分析一下,NXP S32K1系列的电源管理,先翻译一下S32K-RM的Chapter 39 Power Management P1141。

  1. 电源模式描述
    电源管理控制器(PMC)提供了多个电源选项,允许用户根据需要的功能级别优化功耗。
    根据用户应用程序的停止需求,有多种停止模式可供选择,它们提供某些逻辑和/或内存的状态保持、部分断电或完全断电。
    对于运行模式和极低功耗运行(VLPR)模式,有相应的停止模式。 停止模式(VLPS, STOP1, STOP2)类似于Arm睡眠深度模式。 当不需要最大总线频率来支持应用需求时,VLPR工作模式可以降低运行时功耗。
    该芯片不能直接从高速运行(HSRUN)模式进入停止模式。 要从HSRUN进入停止模式,芯片必须首先切换到正常运行模式。之后,它可以进入停止模式。
    两种主要的操作模式是运行、停止。 等待中断(WFI)指令为芯片调用停止模式。 可用的功率模式允许应用程序只消耗执行所需的功率。 下面比较了不同的功率模式

Normal Run
默认模式退出复位; 片上电压调节器打开。
High Speed Run(HSRUN)
允许芯片的最大性能。 在这种模式下,芯片可以运行在一个更高的频率相比正常运行模式,但功能受限。 有关详细信息,请参阅模块在可用电源模式下的操作。 有关详细信息,请参阅内部时钟要求。
Normal Stop (通过WFI 指令)
将芯片置于静态状态。 在这种电源模式下,所有寄存器被保留,LVD保护被保持。 禁用NVIC。 AWIC用于从中断中唤醒。 一些外围时钟停止。 有关详细信息,请参阅模块在可用电源模式下的操作。 |
Very Low PowerRun (VLPR)
片上电压调节器处于低功耗模式,只提供足够的功率以降低频率运行芯片。 降低频率的闪存访问模式(1 MHz) LVD关 SIRC为核心、总线和外围时钟提供了一个低功耗4 MHz的源。
Very Low Power Stop (VLPS, (通过WFI 指令)
关闭低电压检测(LVD),将芯片置于静态状态。 这是可以使用引脚中断的最低功耗模式。 一些外围时钟停止。 请参见模块在各种电源模式下的运行。 支持LPTMR、RTC、CMP。 禁用NVIC。 AWIC用于从中断中唤醒。 片上电压调节器处于低功耗模式,仅提供芯片在降低频率下运行所需的功率。 所有SRAM是可操作的(内容保留和I/O状态保持)。
参阅模块在可用电源模式下的操作(Module operation in available power modes)
在这里插入图片描述
在这里插入图片描述
电源模式的切换和退出
WFI指令调用芯片的停止模式。 处理器通过中断退出低功耗模式。 关于中断操作和哪些外设可以导致中断的描述,请参见嵌套向量中断控制器(NVIC)配置。

Chapter 40
System Mode Controller (SMC)
系统模式控制器(SMC)负责排序系统进入和退出所有低功率停止和运行模式。
本章描述了所有可用的低功耗模式,进入/退出每种模式的顺序,以及每种模式下可用的功能。 SMC甚至可以在最深的低功耗模式下工作。 有关使用SMC的详细信息,请参阅AN4503: Kinetis mcu的电源管理。

模式转换这里是引用>

//
#define SMC_PMCTRL_RUNM(x)                       (((uint32_t)(((uint32_t)(x))<<SMC_PMCTRL_RUNM_SHIFT))&SMC_PMCTRL_RUNM_MASK)
/* STOPCTRL Bit Fields */
static inline void SMC_SetRunModeControl(SMC_Type * const baseAddr,
                                         const smc_run_mode_t runMode)
{
    uint32_t regValue = baseAddr->PMCTRL;
    regValue &= ~(SMC_PMCTRL_RUNM_MASK);
    regValue |= SMC_PMCTRL_RUNM(runMode);
    baseAddr->PMCTRL = regValue;
}



 
status_t SMC_SetPowerMode(SMC_Type * const baseAddr,
                          const smc_power_mode_config_t * const powerModeConfig)
{
    status_t retCode;
    smc_stop_mode_t stopMode;
    power_manager_modes_t powerModeName = powerModeConfig->powerModeName;
    /* Branch based on power mode name*/
    switch (powerModeName)
    {
        case POWER_MANAGER_RUN:
            /* Set to RUN mode. */
            SMC_SetRunModeControl(baseAddr, SMC_RUN);
            /* Wait for stat change */
            if (!SMC_WaitForStatChange(baseAddr, STAT_RUN, SMC_TIMEOUT))
            {
                /* Timeout for power mode change expired. */
                retCode = STATUS_MCU_TRANSITION_FAILED;
            }
            else
            {
                retCode = STATUS_SUCCESS;
            }
            break;

        case POWER_MANAGER_VLPR:
            /* Set power mode to VLPR*/
            SMC_SetRunModeControl(baseAddr, SMC_VLPR);
            /* Wait for stat change */
            if (!SMC_WaitForStatChange(baseAddr, STAT_VLPR, SMC_TIMEOUT))
            {
                /* Timeout for power mode change expired. */
                retCode = STATUS_MCU_TRANSITION_FAILED;
            }
            else
            {
                retCode = STATUS_SUCCESS;
            }
            break;

#if FEATURE_SMC_HAS_HIGH_SPEED_RUN_MODE
        case POWER_MANAGER_HSRUN:
            /* Set power mode to HSRUN */
            SMC_SetRunModeControl(baseAddr, SMC_HSRUN);
            /* Wait for stat change */
            if (!SMC_WaitForStatChange(baseAddr, STAT_HSRUN, SMC_TIMEOUT))
            {
                /* Timeout for power mode change expired. */
                retCode = STATUS_MCU_TRANSITION_FAILED;
            }
            else
            {
                retCode = STATUS_SUCCESS;
            }

            break;
#endif /* if FEATURE_SMC_HAS_HIGH_SPEED_RUN_MODE */
#if FEATURE_SMC_HAS_WAIT_VLPW
        case POWER_MANAGER_WAIT:
        /* Fall-through */
        case POWER_MANAGER_VLPW:
            /* Clear the SLEEPDEEP bit to disable deep sleep mode - WAIT */
            S32_SCB->SCR &= ~S32_SCB_SCR_SLEEPDEEP_MASK;

            /* Cpu is going into sleep state */
            STANDBY();

            retCode = STATUS_SUCCESS;
            break;
#endif /* if FEATURE_SMC_HAS_WAIT_VLPW */
        case POWER_MANAGER_STOP1:
        /* Fall-through */
        case POWER_MANAGER_STOP2:
        /* Fall-through */
        case POWER_MANAGER_VLPS:
            if ((powerModeName == POWER_MANAGER_STOP1) || (powerModeName == POWER_MANAGER_STOP2))
            {
                stopMode = SMC_STOP;
#if FEATURE_SMC_HAS_STOPO
                SMC_SetStopOption(baseAddr, powerModeConfig->stopOptionValue);
#endif
#if FEATURE_SMC_HAS_PSTOPO
                SMC_SetPStopOption(baseAddr, powerModeConfig->pStopOptionValue);
#endif
            }
            else
            {
                stopMode = SMC_VLPS;
            }

            /* Set power mode to specified STOP mode*/
            SMC_SetStopModeControl(baseAddr, stopMode);

            /* Set the SLEEPDEEP bit to enable deep sleep mode (STOP)*/
            S32_SCB->SCR |= S32_SCB_SCR_SLEEPDEEP_MASK;

            /* Cpu is going into deep sleep state */
            STANDBY();
            retCode = STATUS_SUCCESS;
            break;
        default:
            retCode = STATUS_UNSUPPORTED;
            break;
    }

    return retCode;
}

static status_t POWER_SYS_SwitchToRunningPowerMode(const power_manager_user_config_t * const configPtr)
{
    smc_power_mode_config_t modeConfig; /* SMC hardware layer configuration structure */
    power_mode_stat_t currentMode = SMC_GetPowerModeStatus(SMC);
    status_t returnCode = STATUS_SUCCESS;

    /* Configure the running mode */
    switch (configPtr->powerMode)
    {
#if FEATURE_SMC_HAS_HIGH_SPEED_RUN_MODE
        /* High speed run mode */
        case POWER_MANAGER_HSRUN:
            /* High speed run mode can be entered only from Run mode */
            if (currentMode != STAT_HSRUN)
            {
                if (currentMode != STAT_RUN)
                {
                    modeConfig.powerModeName = POWER_MANAGER_RUN;
                    /* Switch the mode */
                    returnCode = SMC_SetPowerMode(SMC, &modeConfig);
                }
                if (returnCode == STATUS_SUCCESS)
                {
                    returnCode = POWER_SYS_EnterHsrunMode();
                }
            }
            else
            {
                returnCode = STATUS_SUCCESS;
            }
            break;
#endif /* if FEATURE_SMC_HAS_HIGH_SPEED_RUN_MODE */
        /* Run mode */
        case POWER_MANAGER_RUN:
            if (currentMode != STAT_RUN)
            {
                modeConfig.powerModeName = POWER_MANAGER_RUN;
                /* Switch the mode */
                returnCode = SMC_SetPowerMode(SMC, &modeConfig);
            }
            if ((returnCode == STATUS_SUCCESS) && changeClkVlp)
            {
                /* Enable all clock source */
                POWER_DRV_EnableVlpClockSrc();
                /* Update initialize clock configuration */
                returnCode = POWER_DRV_UpdateInitClk(&sysClkConfig);
                if (returnCode == STATUS_SUCCESS)
                {
                    changeClkVlp = false;
                }
            }

            break;
        /* Very low power run mode */
        case POWER_MANAGER_VLPR:
            if (currentMode != STAT_VLPR)
            {
                /* Very low power run mode can be entered only from Run mode */
                if (SMC_GetPowerModeStatus(SMC) != STAT_RUN)
                {
                    modeConfig.powerModeName = POWER_MANAGER_RUN;
                    /* Switch the mode */
                    returnCode = SMC_SetPowerMode(SMC, &modeConfig);
                }
                if (STATUS_SUCCESS == returnCode)
                {
                    if (!changeClkVlp)
                    {
                        CLOCK_DRV_GetSystemClockSource(&sysClkConfig);
                    }
                    returnCode = POWER_DRV_SwitchVlprClk(&sysClkConfig);
                    if (STATUS_SUCCESS == returnCode)
                    {
                        changeClkVlp = true;
                        modeConfig.powerModeName = POWER_MANAGER_VLPR;
                        /* Disable all clock source except SIRC */
                        POWER_DRV_DisableVlpClockSrc();
                        /* Switch the mode */
                        returnCode = SMC_SetPowerMode(SMC, &modeConfig);
                    }
                }
            }
            else
            {
                returnCode = STATUS_SUCCESS;
            }

            break;
        /* Wait mode */
        default:
            /* invalid power mode */
            returnCode = STATUS_UNSUPPORTED;
            modeConfig.powerModeName = POWER_MANAGER_MAX;
            break;
    }

    return returnCode;
}

status_t POWER_SYS_DoSetMode(const power_manager_user_config_t * const configPtr)
{
    status_t returnCode; /* Function return */

    /* Check whether the power mode is a sleeping or a running power mode */
    if (configPtr->powerMode <= POWER_MANAGER_VLPR)
    {
        /* Switch to a running power mode */
        returnCode = POWER_SYS_SwitchToRunningPowerMode(configPtr);
    }
    else
    {
        /* Switch to a sleeping power mode */
        returnCode = POWER_SYS_SwitchToSleepingPowerMode(configPtr);
    }

    return returnCode;
}


status_t POWER_SYS_SetMode(uint8_t powerModeIndex,
                           power_manager_policy_t policy)
{
    power_manager_user_config_t * configPtr; /* Local pointer to the requested user-defined power mode configuration */
    status_t returnCode; /* Function return */
    status_t errorCode;
    bool successfulSwitch;                                 /* Power mode switch is successful or not */
    uint8_t currentStaticCallback = 0U;                    /* Index to array of statically registered call-backs */
    power_manager_notify_struct_t notifyStruct;            /* Callback notification structure */

    /* Driver is already initialized. */
    DEV_ASSERT(gPowerManagerState.configs != NULL);
    DEV_ASSERT(gPowerManagerState.configsNumber != 0U);

    /* Power mode index is valid. */
    DEV_ASSERT(powerModeIndex < gPowerManagerState.configsNumber);

    /* Initialization of local pointer to the requested user-defined power mode configuration */
    configPtr = (*gPowerManagerState.configs)[powerModeIndex];

    /* Reference to the requested user-defined power mode configuration is valid. */
    DEV_ASSERT(configPtr != NULL);

    /* Default value of handle of last call-back that returned error */
    gPowerManagerState.errorCallbackIndex = gPowerManagerState.staticCallbacksNumber;

    /* Set the transaction policy in the notification structure */
    notifyStruct.policy = policy;

    /* Set the target power mode configuration in the notification structure */
    notifyStruct.targetPowerConfigIndex = powerModeIndex;
    notifyStruct.targetPowerConfigPtr = configPtr;

    /* Notify those which asked to be called before the power mode change */
    notifyStruct.notifyType = POWER_MANAGER_NOTIFY_BEFORE;
    returnCode = POWER_SYS_CallbacksManagement(&notifyStruct, &currentStaticCallback, policy);

    /* Power mode switch */
    /* In case that any call-back returned error code and  policy doesn't force the mode switch go to after switch call-backs */
    if ((policy == POWER_MANAGER_POLICY_FORCIBLE) || (returnCode == STATUS_SUCCESS))
    {
        returnCode = POWER_SYS_DoSetMode(configPtr);
        successfulSwitch = (STATUS_SUCCESS == returnCode);
    }
    else
    {
        /* Unsuccessful switch */
        successfulSwitch = false;
    }

    if (successfulSwitch)
    {
        /* End of successful switch */

        /* Update current configuration index */
        gPowerManagerState.currentConfig = powerModeIndex;

        /* Notify those which asked to be called after the power mode change */
        notifyStruct.notifyType = POWER_MANAGER_NOTIFY_AFTER;
        returnCode = POWER_SYS_CallbacksManagement(&notifyStruct, &currentStaticCallback, POWER_MANAGER_POLICY_FORCIBLE);
    }
    else
    {
        /* End of unsuccessful switch */

        /* Notify those which have been called before the power mode change */
        notifyStruct.notifyType = POWER_MANAGER_NOTIFY_RECOVER;
        errorCode = POWER_SYS_CallbacksManagement(&notifyStruct, &currentStaticCallback, POWER_MANAGER_POLICY_FORCIBLE);
        (void)(errorCode);
    }

    return returnCode;
}

关于函数全部在SDK封装好了,拿来就用就好。不会用可以参考官方例程。
在这里插入图片描述

本图文内容来源于网友网络收集整理提供,作为学习参考使用,版权属于原作者。
THE END
分享
二维码

)">
< <上一篇
下一篇>>