NXP S32K146 Power Manager Component分析

Posted nininiccccc

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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封装好了,拿来就用就好。不会用可以参考官方例程。

以上是关于NXP S32K146 Power Manager Component分析的主要内容,如果未能解决你的问题,请参考以下文章

Android各种Manager

Android各种Manager-郭通

Android中五大Manager详解及使用技巧

Updating power_state in the DB to match the hypervisor

Linux系统移植:NXP 官板 uboot 移植

Linux系统移植:NXP 官板 uboot 移植