/* * Copyright 2020, NXP * All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include <string.h> #include "fsl_common.h" #include "fsl_power.h" /* Component ID definition, used by tools. */ #ifndef FSL_COMPONENT_ID #define FSL_COMPONENT_ID "platform.drivers.power" #endif /* NOTE: These registers are handled by the SDK. The user should not modify the source code. Changes to the source code * can cause application failure. NXP is not responsible for any change to the code and is not obligated to provide * support. */ /******************************************************************************* * Variables ******************************************************************************/ /******************************************************************************* * Definitions ******************************************************************************/ /** * @brief LDO_FLASH_NV & LDO_EFUSE_PROG voltage settings */ typedef enum _v_ldo_flashnv_ldo_efuse { V_LDO_1P650 = 0, /*!< 1.65 V */ V_LDO_1P700 = 1, /*!< 1.7 V */ V_LDO_1P750 = 2, /*!< 1.75 V */ V_LDO_1P800 = 3, /*!< 1.8 V */ V_LDO_1P850 = 4, /*!< 1.85 V */ V_LDO_1P900 = 5, /*!< 1.9 V */ V_LDO_1P950 = 6, /*!< 1.95 V */ V_LDO_2P000 = 7 /*!< 2.0 V */ } v_ldo_flashnv_ldo_efuse_t; /** * @brief Always On and Memories LDO voltage settings */ typedef enum _v_ao { V_AO_0P700 = 1, /*!< 0.7 V */ V_AO_0P725 = 2, /*!< 0.725 V */ V_AO_0P750 = 3, /*!< 0.75 V */ V_AO_0P775 = 4, /*!< 0.775 V */ V_AO_0P800 = 5, /*!< 0.8 V */ V_AO_0P825 = 6, /*!< 0.825 V */ V_AO_0P850 = 7, /*!< 0.85 V */ V_AO_0P875 = 8, /*!< 0.875 V */ V_AO_0P900 = 9, /*!< 0.9 V */ V_AO_0P960 = 10, /*!< 0.96 V */ V_AO_0P970 = 11, /*!< 0.97 V */ V_AO_0P980 = 12, /*!< 0.98 V */ V_AO_0P990 = 13, /*!< 0.99 V */ V_AO_1P000 = 14, /*!< 1 V */ V_AO_1P010 = 15, /*!< 1.01 V */ V_AO_1P020 = 16, /*!< 1.02 V */ V_AO_1P030 = 17, /*!< 1.03 V */ V_AO_1P040 = 18, /*!< 1.04 V */ V_AO_1P050 = 19, /*!< 1.05 V */ V_AO_1P060 = 20, /*!< 1.06 V */ V_AO_1P070 = 21, /*!< 1.07 V */ V_AO_1P080 = 22, /*!< 1.08 V */ V_AO_1P090 = 23, /*!< 1.09 V */ V_AO_1P100 = 24, /*!< 1.1 V */ V_AO_1P110 = 25, /*!< 1.11 V */ V_AO_1P120 = 26, /*!< 1.12 V */ V_AO_1P130 = 27, /*!< 1.13 V */ V_AO_1P140 = 28, /*!< 1.14 V */ V_AO_1P150 = 29, /*!< 1.15 V */ V_AO_1P160 = 30, /*!< 1.16 V */ V_AO_1P220 = 31 /*!< 1.22 V */ } v_ao_t; /** * @brief DCDC voltage settings */ typedef enum _v_dcdc { V_DCDC_0P950 = 0, /*!< 0.95 V */ V_DCDC_0P975 = 1, /*!< 0.975 V */ V_DCDC_1P000 = 2, /*!< 1 V */ V_DCDC_1P025 = 3, /*!< 1.025 V */ V_DCDC_1P050 = 4, /*!< 1.050 V */ V_DCDC_1P075 = 5, /*!< 1.075 V */ V_DCDC_1P100 = 6, /*!< 1.1 V */ V_DCDC_1P125 = 7, /*!< 1.125 V */ V_DCDC_1P150 = 8, /*!< 1.150 V */ V_DCDC_1P175 = 9, /*!< 1.175 V */ V_DCDC_1P200 = 10 /*!< 1.2 V */ } v_dcdc_t; /** * @brief LDO_CORE High Power Mode voltage settings */ typedef enum _v_ldocore_hp { V_LDOCORE_HP_1P373 = 0, /*!< 1.373 V */ V_LDOCORE_HP_1P365 = 1, /*!< 1.365 V */ V_LDOCORE_HP_1P359 = 2, /*!< 1.359 V */ V_LDOCORE_HP_1P352 = 3, /*!< 1.352 V */ V_LDOCORE_HP_1P345 = 4, /*!< 1.345 V */ V_LDOCORE_HP_1P339 = 5, /*!< 1.339 V */ V_LDOCORE_HP_1P332 = 6, /*!< 1.332 V */ V_LDOCORE_HP_1P325 = 7, /*!< 1.325 V */ V_LDOCORE_HP_1P318 = 8, /*!< 1.318 V */ V_LDOCORE_HP_1P311 = 9, /*!< 1.311 V */ V_LDOCORE_HP_1P305 = 10, /*!< 1.305 V */ V_LDOCORE_HP_1P298 = 11, /*!< 1.298 V */ V_LDOCORE_HP_1P291 = 12, /*!< 1.291 V */ V_LDOCORE_HP_1P285 = 13, /*!< 1.285 V */ V_LDOCORE_HP_1P278 = 14, /*!< 1.278 V */ V_LDOCORE_HP_1P271 = 15, /*!< 1.271 V */ V_LDOCORE_HP_1P264 = 16, /*!< 1.264 V */ V_LDOCORE_HP_1P258 = 17, /*!< 1.258 V */ V_LDOCORE_HP_1P251 = 18, /*!< 1.251 V */ V_LDOCORE_HP_1P244 = 19, /*!< 1.244 V */ V_LDOCORE_HP_1P237 = 20, /*!< 1.237 V */ V_LDOCORE_HP_1P231 = 21, /*!< 1.231 V */ V_LDOCORE_HP_1P224 = 22, /*!< 1.224 V */ V_LDOCORE_HP_1P217 = 23, /*!< 1.217 V */ V_LDOCORE_HP_1P210 = 24, /*!< 1.21 V */ V_LDOCORE_HP_1P204 = 25, /*!< 1.204 V */ V_LDOCORE_HP_1P197 = 26, /*!< 1.197 V */ V_LDOCORE_HP_1P190 = 27, /*!< 1.19 V */ V_LDOCORE_HP_1P183 = 28, /*!< 1.183 V */ V_LDOCORE_HP_1P177 = 29, /*!< 1.177 V */ V_LDOCORE_HP_1P169 = 30, /*!< 1.169 V */ V_LDOCORE_HP_1P163 = 31, /*!< 1.163 V */ V_LDOCORE_HP_1P156 = 32, /*!< 1.156 V */ V_LDOCORE_HP_1P149 = 33, /*!< 1.149 V */ V_LDOCORE_HP_1P143 = 34, /*!< 1.143 V */ V_LDOCORE_HP_1P136 = 35, /*!< 1.136 V */ V_LDOCORE_HP_1P129 = 36, /*!< 1.129 V */ V_LDOCORE_HP_1P122 = 37, /*!< 1.122 V */ V_LDOCORE_HP_1P116 = 38, /*!< 1.116 V */ V_LDOCORE_HP_1P109 = 39, /*!< 1.109 V */ V_LDOCORE_HP_1P102 = 40, /*!< 1.102 V */ V_LDOCORE_HP_1P095 = 41, /*!< 1.095 V */ V_LDOCORE_HP_1P088 = 42, /*!< 1.088 V */ V_LDOCORE_HP_1P082 = 43, /*!< 1.082 V */ V_LDOCORE_HP_1P075 = 44, /*!< 1.075 V */ V_LDOCORE_HP_1P068 = 45, /*!< 1.068 V */ V_LDOCORE_HP_1P062 = 46, /*!< 1.062 V */ V_LDOCORE_HP_1P055 = 47, /*!< 1.055 V */ V_LDOCORE_HP_1P048 = 48, /*!< 1.048 V */ V_LDOCORE_HP_1P041 = 49, /*!< 1.041 V */ V_LDOCORE_HP_1P034 = 50, /*!< 1.034 V */ V_LDOCORE_HP_1P027 = 51, /*!< 1.027 V */ V_LDOCORE_HP_1P021 = 52, /*!< 1.021 V */ V_LDOCORE_HP_1P014 = 53, /*!< 1.014 V */ V_LDOCORE_HP_1P007 = 54, /*!< 1.007 V */ V_LDOCORE_HP_1P001 = 55, /*!< 1.001 V */ V_LDOCORE_HP_0P993 = 56, /*!< 0.9937 V */ V_LDOCORE_HP_0P987 = 57, /*!< 0.987 V */ V_LDOCORE_HP_0P980 = 58, /*!< 0.9802 V */ V_LDOCORE_HP_0P973 = 59, /*!< 0.9731 V */ V_LDOCORE_HP_0P966 = 60, /*!< 0.9666 V */ V_LDOCORE_HP_0P959 = 61, /*!< 0.9598 V */ V_LDOCORE_HP_0P953 = 62, /*!< 0.9532 V */ V_LDOCORE_HP_0P946 = 63, /*!< 0.946 V */ V_LDOCORE_HP_0P939 = 64, /*!< 0.9398 V */ V_LDOCORE_HP_0P932 = 65, /*!< 0.9327 V */ V_LDOCORE_HP_0P926 = 66, /*!< 0.9262 V */ V_LDOCORE_HP_0P919 = 67, /*!< 0.9199 V */ V_LDOCORE_HP_0P913 = 68, /*!< 0.9135 V */ V_LDOCORE_HP_0P907 = 69, /*!< 0.9071 V */ V_LDOCORE_HP_0P901 = 70, /*!< 0.9012 V */ V_LDOCORE_HP_0P895 = 71, /*!< 0.8953 V */ V_LDOCORE_HP_0P889 = 72, /*!< 0.8895 V */ V_LDOCORE_HP_0P883 = 73, /*!< 0.8837 V */ V_LDOCORE_HP_0P877 = 74, /*!< 0.8779 V */ V_LDOCORE_HP_0P871 = 75, /*!< 0.8719 V */ V_LDOCORE_HP_0P865 = 76, /*!< 0.8658 V */ V_LDOCORE_HP_0P859 = 77, /*!< 0.8596 V */ V_LDOCORE_HP_0P853 = 78, /*!< 0.8537 V */ V_LDOCORE_HP_0P847 = 79, /*!< 0.8474 V */ V_LDOCORE_HP_0P841 = 80, /*!< 0.8413 V */ V_LDOCORE_HP_0P835 = 81, /*!< 0.835 V */ V_LDOCORE_HP_0P828 = 82, /*!< 0.8288 V */ V_LDOCORE_HP_0P822 = 83, /*!< 0.8221 V */ V_LDOCORE_HP_0P815 = 84, /*!< 0.8158 V */ V_LDOCORE_HP_0P809 = 85, /*!< 0.8094 V */ V_LDOCORE_HP_0P802 = 86, /*!< 0.8026 V */ V_LDOCORE_HP_0P795 = 87, /*!< 0.7959 V */ V_LDOCORE_HP_0P789 = 88, /*!< 0.7893 V */ V_LDOCORE_HP_0P782 = 89, /*!< 0.7823 V */ V_LDOCORE_HP_0P775 = 90, /*!< 0.7756 V */ V_LDOCORE_HP_0P768 = 91, /*!< 0.7688 V */ V_LDOCORE_HP_0P762 = 92, /*!< 0.7623 V */ V_LDOCORE_HP_0P755 = 93, /*!< 0.7558 V */ V_LDOCORE_HP_0P749 = 94, /*!< 0.749 V */ V_LDOCORE_HP_0P742 = 95, /*!< 0.7421 V */ V_LDOCORE_HP_0P735 = 96, /*!< 0.7354 V */ V_LDOCORE_HP_0P728 = 97, /*!< 0.7284 V */ V_LDOCORE_HP_0P722 = 98, /*!< 0.722 V */ V_LDOCORE_HP_0P715 = 99 /*!< 0.715 V */ } v_ldocore_hp_t; /** * @brief LDO_CORE Low Power Mode voltage settings */ typedef enum _v_ldocore_lp { V_LDOCORE_LP_0P750 = 3, /*!< 0.75 V */ V_LDOCORE_LP_0P800 = 2, /*!< 0.8 V */ V_LDOCORE_LP_0P850 = 1, /*!< 0.85 V */ V_LDOCORE_LP_0P900 = 0 /*!< 0.9 V */ } v_ldocore_lp_t; /** * @brief System Power Mode settings */ typedef enum _v_system_power_profile { V_SYSTEM_POWER_PROFILE_LOW = 0UL, /*!< For system below or equal to 100 MHz */ V_SYSTEM_POWER_PROFILE_MEDIUM = 1UL, /*!< For system frequencies in ]100 MHz - 150 MHz] */ V_SYSTEM_POWER_PROFILE_HIGH = 2UL, /*!< For system above 150 MHz */ } v_system_power_profile_t; /** * @brief Manufacturing Process Corners */ typedef enum { PROCESS_CORNER_SSS, /**< Slow Corner Process */ PROCESS_CORNER_NNN, /**< Nominal Corner Process */ PROCESS_CORNER_FFF, /**< Fast Corner Process */ PROCESS_CORNER_OTHERS, /**< SFN, SNF, NFS, Poly Res ... Corner Process */ } lowpower_process_corner_enum; /** @brief Low Power main structure */ typedef struct { __IO uint32_t CFG; /*!< Low Power Mode Configuration, and miscallenous options */ __IO uint32_t PDCTRL[2]; /*!< Power Down control : controls power of various modules in the different Low power modes, including ROM */ __IO uint32_t SRAMRETCTRL; /*!< Power Down control : controls power SRAM instances in the different Low power modes */ __IO uint32_t CPURETCTRL; /*!< CPU0 retention control : controls CPU retention parameters in POWER DOWN modes */ __IO uint64_t VOLTAGE; /*!< Voltage control in Low Power Modes */ __IO uint32_t WAKEUPSRC[4]; /*!< Wake up sources control for sleepcon */ __IO uint32_t WAKEUPINT[4]; /*!< Wake up sources control for ARM */ __IO uint32_t HWWAKE; /*!< Interrupt that can postpone power down modes in case an interrupt is pending when the processor request deepsleep */ __IO uint32_t WAKEUPIOSRC; /*!< Wake up I/O sources in DEEP POWER-DOWN mode */ } LPC_LOWPOWER_T; #if (defined(LPC55S36_SERIES) || defined(LPC5536_SERIES) || defined(LPC5534_SERIES)) /** * @brief NMPA related Registers */ #define FLASH_NMPA_BOD_LDOCORE (*((volatile unsigned int *)(0x3FC08))) #define FLASH_NMPA_DCDC_POWER_PROFILE_LOW_ARRAY0 (*((volatile unsigned int *)(0x3FC18))) #define FLASH_NMPA_DCDC_POWER_PROFILE_LOW_ARRAY1 (*((volatile unsigned int *)(0x3FC1C))) #define FLASH_NMPA_LDO_AO (*((volatile unsigned int *)(0x3FC24))) #define FLASH_NMPA_LDO_MEM (*((volatile unsigned int *)(0x3FD60))) #define FLASH_NMPA_DCDC_POWER_PROFILE_HIGH_ARRAY0 (*((volatile unsigned int *)(0x3FCB0))) #define FLASH_NMPA_DCDC_POWER_PROFILE_HIGH_ARRAY1 (*((volatile unsigned int *)(0x3FCB4))) #define FLASH_NMPA_DCDC_POWER_PROFILE_MEDIUM_ARRAY0 (*((volatile unsigned int *)(0x3FCB8))) #define FLASH_NMPA_DCDC_POWER_PROFILE_MEDIUM_ARRAY1 (*((volatile unsigned int *)(0x3FCBC))) #define FLASH_NMPA_PVT_MONITOR_0_RINGO (*((volatile unsigned int *)(0x3FCE0))) #define FLASH_NMPA_PVT_MONITOR_1_RINGO (*((volatile unsigned int *)(0x3FCF0))) /** * @brief NMPA related masks */ #define FLASH_NMPA_BOD_LDOCORE_REGREF_1P8V_OFFSET_SHIFT (24U) #define FLASH_NMPA_BOD_LDOCORE_REGREF_1P8V_OFFSET_MASK (0xFF000000U) #define FLASH_NMPA_LDO_AO_VADJ_ACTIVE_SHIFT (0U) #define FLASH_NMPA_LDO_AO_VADJ_ACTIVE_MASK (0xFFU) #endif /** * @brief CSS related Registers */ #define CSSV2_STATUS_REG (*((volatile unsigned int *)(0x40030000))) #define CSSV2_CTRL_REG (*((volatile unsigned int *)(0x40030004))) #define SYSCON_CSS_CLK_CTRL_REG (*((volatile unsigned int *)(0x400009B0))) #define SYSCON_CSS_CLK_CTRL_SET_REG (*((volatile unsigned int *)(0x400009B4))) #define SYSCON_CSS_CLK_CTRL_CLR_REG (*((volatile unsigned int *)(0x400009B8))) /** * @brief Wake-up I/O positions */ /*!< wake-up 0 */ #define WAKEUPIO_0_PORT (1UL) #define WAKEUPIO_0_PINS (1UL) /*!< wake-up 1 */ #define WAKEUPIO_1_PORT (0UL) #define WAKEUPIO_1_PINS (28UL) /*!< wake-up 2 */ #define WAKEUPIO_2_PORT (1UL) #define WAKEUPIO_2_PINS (18UL) /*!< wake-up 3 */ #define WAKEUPIO_3_PORT (1UL) #define WAKEUPIO_3_PINS (30UL) /*!< wake-up 4 */ #define WAKEUPIO_4_PORT (0UL) #define WAKEUPIO_4_PINS (26UL) /** * @brief SRAM Low Power Modes */ #define LOWPOWER_SRAM_LPMODE_MASK (0xFUL) #define LOWPOWER_SRAM_LPMODE_ACTIVE (0x6UL) /*!< SRAM functional mode */ #define LOWPOWER_SRAM_LPMODE_SLEEP (0xFUL) /*!< SRAM Sleep mode (Data retention, fast wake up) */ #define LOWPOWER_SRAM_LPMODE_DEEPSLEEP (0x8UL) /*!< SRAM Deep Sleep mode (Data retention, slow wake up) */ #define LOWPOWER_SRAM_LPMODE_SHUTDOWN (0x9UL) /*!< SRAM Shut Down mode (no data retention) */ #define LOWPOWER_SRAM_LPMODE_POWERUP (0xAUL) /*!< SRAM is powering up */ /** * @brief SoC Low Power modes */ #define LOWPOWER_CFG_LPMODE_INDEX 0 #define LOWPOWER_CFG_LPMODE_MASK (0x3UL << LOWPOWER_CFG_LPMODE_INDEX) #define LOWPOWER_CFG_SELCLOCK_INDEX 2 #define LOWPOWER_CFG_SELCLOCK_MASK (0x1UL << LOWPOWER_CFG_SELCLOCK_INDEX) #define LOWPOWER_CFG_SELMEMSUPPLY_INDEX 3 #define LOWPOWER_CFG_SELMEMSUPPLY_MASK (0x1UL << LOWPOWER_CFG_SELMEMSUPPLY_INDEX) #define LOWPOWER_CFG_MEMLOWPOWERMODE_INDEX 4 #define LOWPOWER_CFG_MEMLOWPOWERMODE_MASK (0x1UL << LOWPOWER_CFG_MEMLOWPOWERMODE_INDEX) #define LOWPOWER_CFG_LDODEEPSLEEPREF_INDEX 5 #define LOWPOWER_CFG_LDODEEPSLEEPREF_MASK (0x1UL << LOWPOWER_CFG_LDODEEPSLEEPREF_INDEX) #define LOWPOWER_CFG_LPMODE_ACTIVE 0 /*!< ACTIVE mode */ #define LOWPOWER_CFG_LPMODE_DEEPSLEEP 1 /*!< DEEP-SLEEP mode */ #define LOWPOWER_CFG_LPMODE_POWERDOWN 2 /*!< POWER-DOWN mode */ #define LOWPOWER_CFG_LPMODE_DEEPPOWERDOWN 3 /*!< DEEP POWER-DOWN mode */ #define LOWPOWER_CFG_LPMODE_SLEEP 4 /*!< SLEEP mode */ #define LOWPOWER_CFG_SELCLOCK_1MHZ 0 /*!< The 1 MHz clock is used during the configuration of the PMC */ #define LOWPOWER_CFG_SELCLOCK_12MHZ \ 1 /*!< The 12 MHz clock is used during the configuration of the PMC (to speed up PMC configuration process)*/ #define LOWPOWER_CFG_SELMEMSUPPLY_LDOMEM 0 /*!< In DEEP SLEEP power mode, the Memories are supplied by the LDO_MEM */ #define LOWPOWER_CFG_SELMEMSUPPLY_LDODEEPSLEEP \ 1 /*!< In DEEP SLEEP power mode, the Memories are supplied by the LDO_DEEP_SLEEP (or DCDC) */ #define LOWPOWER_CFG_MEMLOWPOWERMODE_SOURCEBIASING \ 0 /*!< All SRAM instances use "Source Biasing" as low power mode technic (it is recommended to set LDO_MEM as high \ as possible -- 1.1V typical -- during low power mode) */ #define LOWPOWER_CFG_MEMLOWPOWERMODE_VOLTAGESCALING \ 1 /*!< All SRAM instances use "Voltage Scaling" as low power mode technic (it is recommended to set LDO_MEM as low \ as possible -- down to 0.7V -- during low power mode) */ /** * @brief LDO Voltage control in Low Power Modes */ #define LOWPOWER_VOLTAGE_LDO_PMU_INDEX 0 #define LOWPOWER_VOLTAGE_LDO_PMU_MASK (0x1FULL << LOWPOWER_VOLTAGE_LDO_PMU_INDEX) #define LOWPOWER_VOLTAGE_LDO_MEM_INDEX 5 #define LOWPOWER_VOLTAGE_LDO_MEM_MASK (0x1FULL << LOWPOWER_VOLTAGE_LDO_MEM_INDEX) #define LOWPOWER_VOLTAGE_LDO_PMU_BOOST_INDEX 10 #define LOWPOWER_VOLTAGE_LDO_PMU_BOOST_MASK (0x1FULL << LOWPOWER_VOLTAGE_LDO_PMU_BOOST_INDEX) #define LOWPOWER_VOLTAGE_LDO_MEM_BOOST_INDEX 15 #define LOWPOWER_VOLTAGE_LDO_MEM_BOOST_MASK (0x1FULL << LOWPOWER_VOLTAGE_LDO_MEM_BOOST_INDEX) /* CPU Retention Control*/ #define LOWPOWER_CPURETCTRL_ENA_INDEX 0 #define LOWPOWER_CPURETCTRL_ENA_MASK (0x1UL << LOWPOWER_CPURETCTRL_ENA_INDEX) #define LOWPOWER_CPURETCTRL_MEMBASE_INDEX 1 #define LOWPOWER_CPURETCTRL_MEMBASE_MASK (0x1FFFUL << LOWPOWER_CPURETCTRL_MEMBASE_INDEX) #define LOWPOWER_CPURETCTRL_RETDATALENGTH_INDEX 14 #define LOWPOWER_CPURETCTRL_RETDATALENGTH_MASK (0x3FFUL << LOWPOWER_CPURETCTRL_RETDATALENGTH_INDEX) /** * @brief SRAM Power Control Registers Code */ // LSDEL DSBDEL DSB LS #define SRAM_PWR_MODE_ACT_CODE (0x6UL) // Active | 0 1 1 0 #define SRAM_PWR_MODE_LS_CODE (0xFUL) // Light Sleep | 1 1 1 1 #define SRAM_PWR_MODE_DS_CODE (0x8UL) // Deep Sleep | 1 0 0 0 #define SRAM_PWR_MODE_SD_CODE (0x9UL) // Shut Down | 1 0 0 1 #define SRAM_PWR_MODE_MPU_CODE (0xEUL) // Matrix Power Up | 1 1 1 0 #define SRAM_PWR_MODE_FPU_CODE (0xAUL) // Full Power Up | 1 0 1 0 /** * @brief System voltage setting */ // All 3 DCDC_POWER_PROFILE_* constants below have been updated after chip characterization on ATE #define DCDC_POWER_PROFILE_LOW_MAX_FREQ_HZ \ (100000000UL) /* Maximum System Frequency allowed with DCDC Power Profile LOW */ #define DCDC_POWER_PROFILE_MEDIUM_MAX_FREQ_HZ \ (135000000UL) /* Maximum System Frequency allowed with DCDC Power Profile MEDIUM */ #define DCDC_POWER_PROFILE_HIGH_MAX_FREQ_HZ \ (150000000UL) /* Maximum System Frequency allowed with DCDC Power Profile HIGH */ /** * @brief Manufacturing Process Parameters */ // All 3 PROCESS_* constants below have been updated after chip characterization on ATE #define PROCESS_NNN_AVG_HZ (14900000UL) /* Average Ring Oscillator value for Nominal (NNN) Manufacturing Process */ #define PROCESS_NNN_STD_HZ \ (515000UL) /* Standard Deviation Ring Oscillator value for Nominal (NNN) Manufacturing Process */ #define PROCESS_NNN_LIMITS \ (2UL) /* Nominal (NNN) Manufacturing Process Ring Oscillator values limit (with respect to the Average value) */ #define PROCESS_NNN_MIN_HZ \ (PROCESS_NNN_AVG_HZ - \ (PROCESS_NNN_LIMITS * \ PROCESS_NNN_STD_HZ)) /* Minimum Ring Oscillator value for Nominal (NNN) Manufacturing Process */ #define PROCESS_NNN_MAX_HZ \ (PROCESS_NNN_AVG_HZ + \ (PROCESS_NNN_LIMITS * \ PROCESS_NNN_STD_HZ)) /* Maximum Ring OScillator value for Nominal (NNN) Manufacturing Process */ // All 9 VOLTAGE_* constants below have been updated after chip characterization on ATE #define VOLTAGE_SSS_LOW_MV (1075UL) /* Voltage Settings for : Process=SSS, DCDC Power Profile=LOW */ #define VOLTAGE_SSS_MED_MV (1175UL) /* Voltage Settings for : Process=SSS, DCDC Power Profile=MEDIUM */ #define VOLTAGE_SSS_HIG_MV (1200UL) /* Voltage Settings for : Process=SSS, DCDC Power Profile=HIGH */ #define VOLTAGE_NNN_LOW_MV (1025UL) /* Voltage Settings for : Process=NNN, DCDC Power Profile=LOW */ #define VOLTAGE_NNN_MED_MV (1100UL) /* Voltage Settings for : Process=NNN, DCDC Power Profile=MEDIUM */ #define VOLTAGE_NNN_HIG_MV (1150UL) /* Voltage Settings for : Process=NNN, DCDC Power Profile=HIGH */ #define VOLTAGE_FFF_LOW_MV (1025UL) /* Voltage Settings for : Process=FFF, DCDC Power Profile=LOW */ #define VOLTAGE_FFF_MED_MV (1100UL) /* Voltage Settings for : Process=FFF, DCDC Power Profile=MEDIUM */ #define VOLTAGE_FFF_HIG_MV (1150UL) /* Voltage Settings for : Process=FFF, DCDC Power Profile=HIGH */ /******************************************************************************* * Codes ******************************************************************************/ /******************************************************************************* * LOCAL FUNCTIONS PROTOTYPES ******************************************************************************/ static void POWER_WaitLDOCoreInit(void); static void POWER_SRAMPowerUpDelay(void); static void POWER_PowerCycleCpu(void); static void POWER_SetLowPowerMode(LPC_LOWPOWER_T *p_lowpower_cfg); static uint32_t POWER_WakeUpIOCtrl(uint32_t p_wakeup_io_ctrl); static uint32_t POWER_SetLdoAoLdoMemVoltage(uint32_t p_lp_mode); static void POWER_SetSystemPowerProfile(v_system_power_profile_t power_profile); static void POWER_SetVoltageForProcess(v_system_power_profile_t power_profile); static lowpower_process_corner_enum POWER_GetPartProcessCorner(void); static void POWER_SetSystemVoltage(uint32_t system_voltage_mv); static void POWER_SetSystemClock12MHZ(void); static void POWER_SRAMSetRegister(power_sram_index_t sram_index, uint32_t power_mode); static void POWER_SRAMActiveToLightSleep(power_sram_index_t sram_index); static void POWER_SRAMActiveToDeepSleep(power_sram_index_t sram_index); static void POWER_SRAMActiveToShutDown(power_sram_index_t sram_index); static void POWER_SRAMLightSleepToActive(power_sram_index_t sram_index); static void POWER_SRAMDeepSleepToActive(power_sram_index_t sram_index); static void POWER_SRAMShutDownToActive(power_sram_index_t sram_index); /** * brief SoC Power Management Controller initialization * return power_status_t */ power_status_t POWER_PowerInit(void) { // To speed up PMC configuration, change PMC clock from 1 MHz to 12 MHz. // Set Power Mode to "ACTIVE" (required specially when waking up from DEEP POWER-DOWN) PMC->CTRL = (PMC->CTRL | PMC_CTRL_SELCLOCK_MASK) & (~PMC_CTRL_LPMODE_MASK); // Check that no time out occured during the hardware wake-up process if (PMC->TIMEOUTEVENTS != 0UL) { // A least 1 time-out error occured. return kPOWER_Status_Fail; } // Set up wake-up IO pad control source : IOCON ((WAKEUPIO_ENABLE = 0) PMC->WAKEUPIOCTRL &= ~PMC_WAKEUPIOCTRL_WAKEUPIO_ENABLE_CTRL_MASK; // Set LDO_FLASHNV output voltage PMC->LDOFLASHNV = (PMC->LDOFLASHNV & (~PMC_LDOFLASHNV_VADJ_MASK)) | PMC_LDOFLASHNV_VADJ(V_LDO_1P850); // Set LDO_EFUSE_PROG output voltage PMC->LDOEFUSEPROG = (PMC->LDOEFUSEPROG & (~PMC_LDOEFUSEPROG_VADJ_MASK)) | PMC_LDOEFUSEPROG_VADJ(V_LDO_1P850); // Configure the voltage level of LDO CORE Low Power mode (TODO :: :: Temporarily set to 0.9V; target is 0.8 V)*/ PMC->LDOCORE0 = (PMC->LDOCORE0 & (~PMC_LDOCORE0_LPREGREFSEL_MASK)) | PMC_LDOCORE0_LPREGREFSEL(V_LDOCORE_LP_0P900); // SRAM uses Voltage Scaling in all Low Power modes PMC->SRAMCTRL = (PMC->SRAMCTRL & (~PMC_SRAMCTRL_SMB_MASK)) | PMC_SRAMCTRL_SMB(3); // Enable Analog References fast wake-up in case of wake-up from all low power modes and Hardware Pin reset PMC->REFFASTWKUP = PMC->REFFASTWKUP | PMC_REFFASTWKUP_LPWKUP_MASK | PMC_REFFASTWKUP_HWWKUP_MASK; // Enable FRO192MHz shut-off glitch suppression. // TODO :: :: Check the Power Consumption Impact of this setting during DEEP-SLEEP and POWER-DOWN. // (Supposed to be 1 to 2uA in typical conditions). If the impe // ANACTRL->OSC_TESTBUS = 0x1; return kPOWER_Status_Success; } /** * brief * return power_status_t */ power_status_t POWER_SetCorePowerSource(power_core_pwr_source_t pwr_source) { uint32_t pmc_reg_data; switch (pwr_source) { case kPOWER_CoreSrcDCDC: { // Enable DCDC (1st step) PMC->CMD = PMC_CMD_DCDCENABLE_MASK; // Wait until DCDC is enabled while ((PMC->STATUSPWR & PMC_STATUSPWR_DCDCPWROK_MASK) == 0UL) { } // Disable LDO Core Low Power Mode (2nd step) PMC->CMD = PMC_CMD_LDOCORELOWPWRDISABLE_MASK; // Disable LDO Core High Power Mode (3rd step) PMC->CMD = PMC_CMD_LDOCOREHIGHPWRDISABLE_MASK; // Check PMC Finite State Machines status pmc_reg_data = PMC->STATUS & (PMC_STATUS_FSMDCDCENABLE_MASK | PMC_STATUS_FSMLDOCOREHPENABLE_MASK | PMC_STATUS_FSMLDOCORELPENABLE_MASK | PMC_STATUS_FSMLDOCOREEXPTMRENABLE_MASK); if (pmc_reg_data != (PMC_STATUS_FSMDCDCENABLE_MASK | PMC_STATUS_FSMLDOCOREEXPTMRENABLE_MASK)) { // Error : only DCDC and LDO CORE Exponential Timer must both be enabled. return (kPOWER_Status_Fail); } } break; case kPOWER_CoreSrcLDOCoreHP: { // Enable LDO Core High Power Mode (1st step) PMC->CMD = PMC_CMD_LDOCOREHIGHPWRENABLE_MASK; // Note: Once LDO_CORE High Power Mode has been enabled, // at least 2us are required before one can reliabily sample // the LDO Low Voltage Detectore Output. POWER_WaitLDOCoreInit(); // Wait until LDO CORE High Power is enabled while ((PMC->STATUSPWR & PMC_STATUSPWR_LDOCOREPWROK_MASK) == 0UL) { } // Disable DCDC (2nd step) PMC->CMD = PMC_CMD_DCDCDISABLE_MASK; // Disable LDO Core Low Power Mode (3rd step) PMC->CMD = PMC_CMD_LDOCORELOWPWRDISABLE_MASK; // Check PMC Finite State Machines status pmc_reg_data = PMC->STATUS & (PMC_STATUS_FSMDCDCENABLE_MASK | PMC_STATUS_FSMLDOCOREHPENABLE_MASK | PMC_STATUS_FSMLDOCORELPENABLE_MASK | PMC_STATUS_FSMLDOCOREEXPTMRENABLE_MASK); if (pmc_reg_data != PMC_STATUS_FSMLDOCOREHPENABLE_MASK) { // Error : only LDO CORE High Power mode must both be enabled. return (kPOWER_Status_Fail); } } break; case kPOWER_CoreSrcLDOCoreLP: { // Enable LDO Core Low Power Mode (1st step) PMC->CMD = PMC_CMD_LDOCORELOWPWRENABLE_MASK; // Disable LDO Core High Power Mode (2nd step) PMC->CMD = PMC_CMD_LDOCOREHIGHPWRDISABLE_MASK; // Disable DCDC (3rd step) PMC->CMD = PMC_CMD_DCDCDISABLE_MASK; // Check PMC Finite State Machines status pmc_reg_data = PMC->STATUS & (PMC_STATUS_FSMDCDCENABLE_MASK | PMC_STATUS_FSMLDOCOREHPENABLE_MASK | PMC_STATUS_FSMLDOCORELPENABLE_MASK | PMC_STATUS_FSMLDOCOREEXPTMRENABLE_MASK); if (pmc_reg_data != (PMC_STATUS_FSMLDOCORELPENABLE_MASK | PMC_STATUS_FSMLDOCOREEXPTMRENABLE_MASK)) { // Error : only LDO CORE Low Power mode and LDO CORE Exponential Timer must both be enabled. return (kPOWER_Status_Fail); } } break; case kPOWER_CoreSrcExternal: { // Disable LDO Core Low Power Mode (1st step) PMC->CMD = PMC_CMD_LDOCORELOWPWRDISABLE_MASK; // Disable LDO Core High Power Mode (2nd step) PMC->CMD = PMC_CMD_LDOCOREHIGHPWRDISABLE_MASK; // Disable DCDC (3rd step) PMC->CMD = PMC_CMD_DCDCDISABLE_MASK; // Check PMC Finite State Machines status pmc_reg_data = PMC->STATUS & (PMC_STATUS_FSMDCDCENABLE_MASK | PMC_STATUS_FSMLDOCOREHPENABLE_MASK | PMC_STATUS_FSMLDOCORELPENABLE_MASK | PMC_STATUS_FSMLDOCOREEXPTMRENABLE_MASK); if (pmc_reg_data != 0UL) { // Error : All power sources must be disabled. return (kPOWER_Status_Fail); } } break; default: // Not supported return (kPOWER_Status_Fail); } // End switch (pwr_source) return (kPOWER_Status_Success); } /** * brief * @param : * return power_core_pwr_source_t */ power_core_pwr_source_t POWER_GetCorePowerSource(void) { uint32_t reg_status, reg_statuspwr; reg_status = PMC->STATUS; reg_statuspwr = PMC->STATUSPWR; if ((0UL != (reg_statuspwr & PMC_STATUSPWR_DCDCPWROK_MASK)) && (0UL != (reg_status & PMC_STATUS_FSMDCDCENABLE_MASK))) { /* DCDC */ return (kPOWER_CoreSrcDCDC); } else { if ((0UL != (reg_statuspwr & PMC_STATUSPWR_LDOCOREPWROK_MASK)) && (0UL != (reg_status & PMC_STATUS_FSMLDOCOREHPENABLE_MASK))) { /* LDO_CORE High Power Mode */ return (kPOWER_CoreSrcLDOCoreHP); } else { if (0UL != (reg_status & PMC_STATUS_FSMLDOCORELPENABLE_MASK)) { /* LDO_CORE Low Power Mode */ return (kPOWER_CoreSrcLDOCoreLP); } else { /* External */ return (kPOWER_CoreSrcExternal); } } } } /** * brief * return nothing */ power_status_t POWER_CorePowerSourceControl(power_core_pwr_source_t pwr_source, power_core_pwr_state_t pwr_state) { switch (pwr_source) { case kPOWER_CoreSrcDCDC: { if (pwr_state == kPOWER_CorePwrEnable) { // Enable DCDC PMC->CMD = PMC_CMD_DCDCENABLE_MASK; // Wait until DCDC is enabled while ((PMC->STATUSPWR & PMC_STATUSPWR_DCDCPWROK_MASK) == 0UL) { } // Check PMC Finite State Machines status if ((PMC->STATUS & PMC_STATUS_FSMDCDCENABLE_MASK) == 0UL) { // Error : DCDC not enabled. return (kPOWER_Status_Fail); } } else { // Disable DCDC PMC->CMD = PMC_CMD_DCDCDISABLE_MASK; // Check PMC Finite State Machines status if ((PMC->STATUS & PMC_STATUS_FSMDCDCENABLE_MASK) != 0UL) { // Error : DCDC is enabled. return (kPOWER_Status_Fail); } } } break; case kPOWER_CoreSrcLDOCoreHP: { if (pwr_state == kPOWER_CorePwrEnable) { // Enable LDO Core High Power Mode PMC->CMD = PMC_CMD_LDOCOREHIGHPWRENABLE_MASK; // Note: Once LDO_CORE High Power Mode has been enabled, // at least 2us are required before one can reliabily sample // the LDO Low Voltage Detector Output. POWER_WaitLDOCoreInit(); // Wait until LDO CORE High Power is enabled while ((PMC->STATUSPWR & PMC_STATUSPWR_LDOCOREPWROK_MASK) == 0UL) { } // Check PMC Finite State Machines status if ((PMC->STATUS & PMC_STATUS_FSMLDOCOREHPENABLE_MASK) == 0UL) { // Error : LDO CORE High Power mode is not enabled. return (kPOWER_Status_Fail); } } else { // Disable LDO Core High Power Mode PMC->CMD = PMC_CMD_LDOCOREHIGHPWRDISABLE_MASK; // Check PMC Finite State Machines status if ((PMC->STATUS & PMC_STATUS_FSMLDOCOREHPENABLE_MASK) != 0UL) { // Error : LDO CORE High Power mode is enabled. return (kPOWER_Status_Fail); } } } break; case kPOWER_CoreSrcLDOCoreLP: { if (pwr_state == kPOWER_CorePwrEnable) { // Enable LDO Core Low Power Mode (1st step) PMC->CMD = PMC_CMD_LDOCORELOWPWRENABLE_MASK; // Check PMC Finite State Machines status if ((PMC->STATUS & (PMC_STATUS_FSMLDOCORELPENABLE_MASK | PMC_STATUS_FSMLDOCOREEXPTMRENABLE_MASK)) != (PMC_STATUS_FSMLDOCORELPENABLE_MASK | PMC_STATUS_FSMLDOCOREEXPTMRENABLE_MASK)) { // Error : LDO CORE Low Power mode is not enabled. return (kPOWER_Status_Fail); } } else { // Disable LDO Core Low Power Mode PMC->CMD = PMC_CMD_LDOCORELOWPWRDISABLE_MASK; // Check PMC Finite State Machines status if ((PMC->STATUS & (PMC_STATUS_FSMLDOCORELPENABLE_MASK | PMC_STATUS_FSMLDOCOREEXPTMRENABLE_MASK)) != 0UL) { // Error : LDO CORE Low Power mode is enabled. return (kPOWER_Status_Fail); } } } break; default: // Not supported return (kPOWER_Status_Fail); } // End switch (pwr_source) return (kPOWER_Status_Success); } /** * brief * return */ power_sram_pwr_mode_t POWER_GetSRAMPowerMode(power_sram_index_t sram_index) { power_sram_pwr_mode_t pwr_mode; uint32_t state; uint32_t sram_ctrl_0 = PMC->SRAMCTRL0; uint32_t sram_ctrl_1 = PMC->SRAMCTRL1; switch (sram_index) { case kPOWER_SRAM_IDX_RAM_X0: { state = (sram_ctrl_0 >> PMC_SRAMCTRL0_RAM_X0_LS_SHIFT) & 0xFUL; break; } case kPOWER_SRAM_IDX_RAM_00: { state = (sram_ctrl_0 >> PMC_SRAMCTRL0_RAM_00_LS_SHIFT) & 0xFUL; break; } case kPOWER_SRAM_IDX_RAM_01: { state = (sram_ctrl_0 >> PMC_SRAMCTRL0_RAM_01_LS_SHIFT) & 0xFUL; break; } case kPOWER_SRAM_IDX_RAM_02: { state = (sram_ctrl_0 >> PMC_SRAMCTRL0_RAM_02_LS_SHIFT) & 0xFUL; break; } case kPOWER_SRAM_IDX_RAM_03: { state = (sram_ctrl_0 >> PMC_SRAMCTRL0_RAM_03_LS_SHIFT) & 0xFUL; break; } case kPOWER_SRAM_IDX_RAM_10: { state = (sram_ctrl_0 >> PMC_SRAMCTRL0_RAM_10_LS_SHIFT) & 0xFU; break; } case kPOWER_SRAM_IDX_RAM_20: { state = (sram_ctrl_0 >> PMC_SRAMCTRL0_RAM_20_LS_SHIFT) & 0xFUL; break; } case kPOWER_SRAM_IDX_RAM_30: { state = (sram_ctrl_0 >> PMC_SRAMCTRL0_RAM_30_LS_SHIFT) & 0xFUL; break; } case kPOWER_SRAM_IDX_RAM_40: { state = (sram_ctrl_1 >> PMC_SRAMCTRL1_RAM_40_LS_SHIFT) & 0xFUL; break; } case kPOWER_SRAM_IDX_RAM_41: { state = (sram_ctrl_1 >> PMC_SRAMCTRL1_RAM_41_LS_SHIFT) & 0xFUL; break; } case kPOWER_SRAM_IDX_RAM_42: { state = (sram_ctrl_1 >> PMC_SRAMCTRL1_RAM_42_LS_SHIFT) & 0xFUL; break; } case kPOWER_SRAM_IDX_RAM_43: { state = (sram_ctrl_1 >> PMC_SRAMCTRL1_RAM_43_LS_SHIFT) & 0xFUL; break; } default: // Error state = 0x6; // Active. break; } switch (state) { case 0x6: pwr_mode = kPOWER_SRAMPwrActive; break; case 0xF: pwr_mode = kPOWER_SRAMPwrLightSleep; break; case 0x8: pwr_mode = kPOWER_SRAMPwrDeepSleep; break; case 0x9: pwr_mode = kPOWER_SRAMPwrShutDown; break; default: pwr_mode = kPOWER_SRAMPwrActive; break; } return (pwr_mode); } /** * brief * return */ power_status_t POWER_SRAMPowerModeControl(power_sram_bit_t sram_inst, power_sram_pwr_mode_t pwr_mode) { power_sram_pwr_mode_t current_pwr_mode; power_sram_index_t sram_index = kPOWER_SRAM_IDX_RAM_X0; sram_inst = (power_sram_bit_t)(uint32_t)(((uint32_t)sram_inst & 0x3FFFUL)); /* Only SRAM from RAM_X0 to RAM_F3 */ while ((uint32_t)sram_inst != 0UL) { // There is a least 1 SRAM instance to be processed if (0UL != ((uint32_t)sram_inst & 0x1UL)) { // Get current SRAM state current_pwr_mode = POWER_GetSRAMPowerMode(sram_index); // The SRAM instance Power state must be updated switch (current_pwr_mode) { case kPOWER_SRAMPwrActive: { // Active switch (pwr_mode) { case kPOWER_SRAMPwrActive: { // Active ---> Active : there is nothing to do. break; } case kPOWER_SRAMPwrLightSleep: { // Active ---> Light Sleep POWER_SRAMActiveToLightSleep(sram_index); break; } case kPOWER_SRAMPwrDeepSleep: { // Active ---> Deep Sleep POWER_SRAMActiveToDeepSleep(sram_index); break; } case kPOWER_SRAMPwrShutDown: { // Active ---> Shut Down POWER_SRAMActiveToShutDown(sram_index); break; } default: // Do nothing. break; } // switch( pwr_mode ) break; } case kPOWER_SRAMPwrLightSleep: { // Light Sleep switch (pwr_mode) { case kPOWER_SRAMPwrActive: { // Light Sleep ---> Active POWER_SRAMLightSleepToActive(sram_index); break; } case kPOWER_SRAMPwrLightSleep: { // Light Sleep ---> Light Sleep : there is nothing to do. break; } default: // Light Sleep ---> Shut Down : FORBIDDEN (error) // Light Sleep ---> Deep Sleep : FORBIDDEN (error) return (kPOWER_Status_Fail); } // switch( pwr_mode ) break; } case kPOWER_SRAMPwrDeepSleep: { // Deep Sleep switch (pwr_mode) { case kPOWER_SRAMPwrActive: { // Deep Sleep ---> Active POWER_SRAMDeepSleepToActive(sram_index); break; } case kPOWER_SRAMPwrDeepSleep: { // Deep Sleep ---> Deep Sleep : there is nothing to do. break; } default: // Deep Sleep ---> Shut Down : FORBIDDEN (error) // Deep Sleep ---> Light Sleep : FORBIDDEN (error) return (kPOWER_Status_Fail); } // switch( pwr_mode ) break; } case kPOWER_SRAMPwrShutDown: { // Shutdown switch (pwr_mode) { case kPOWER_SRAMPwrActive: { // Shutdown ---> Active POWER_SRAMShutDownToActive(sram_index); break; } case kPOWER_SRAMPwrShutDown: { // Shutdown ---> Shut Down : there is nothing to do. break; } default: // Shutdown ---> Deep Sleep : FORBIDDEN (error) // Shutdown ---> Light Sleep : FORBIDDEN (error) return (kPOWER_Status_Fail); } // switch( pwr_mode ) break; } default: // Do nothing break; } // switch( current_pwr_mode ) } // if ( (uint32_t)sram_inst & 0x1 ) // Move to next SRAM index sram_inst = (power_sram_bit_t)((uint32_t)((uint32_t)sram_inst >> 1)); sram_index = (power_sram_index_t)((uint32_t)((uint32_t)sram_index + 1U)); } // while ((uint32_t)sram_inst != 0 ) return (kPOWER_Status_Success); } /** * @brief Configures and enters in SLEEP low power mode * @return Nothing */ void POWER_EnterSleep(void) { uint32_t pmsk; pmsk = __get_PRIMASK(); /* Save CORTEX-M33 interrupt configuration */ __disable_irq(); /* Disable all interrupts */ SCB->SCR &= ~SCB_SCR_SLEEPDEEP_Msk; /* CORTEX-M33 uses "Sleep" mode */ __WFI(); /* CORTEX-M33 enters "Sleep" mode */ __set_PRIMASK(pmsk); /* Restore CORTEX-M33 interrupt configuration (after wake up) */ } /** * brief PMC Deep Sleep function call * return nothing */ void POWER_EnterDeepSleep(uint32_t exclude_from_pd[2], uint32_t sram_retention_ctrl, uint32_t wakeup_interrupts[4], uint32_t hardware_wake_ctrl) { LPC_LOWPOWER_T lv_low_power_mode_cfg; /* Low Power Mode configuration structure */ uint32_t pmc_reset_ctrl; /* Clear Low Power Mode configuration variable */ (void)memset(&lv_low_power_mode_cfg, 0x0, sizeof(LPC_LOWPOWER_T)); /* Configure Low Power Mode configuration variable */ lv_low_power_mode_cfg.CFG = (uint32_t)LOWPOWER_CFG_LPMODE_DEEPSLEEP << LOWPOWER_CFG_LPMODE_INDEX; /* DEEPSLEEP mode */ /* Make sure LDO MEM & Analog references will stay powered, Shut down ROM & LDO Flash NV */ lv_low_power_mode_cfg.PDCTRL[0] = (~exclude_from_pd[0] & ~(uint32_t)kPDRUNCFG_PD_LDOMEM & ~(uint32_t)kPDRUNCFG_PD_BIAS) | (uint32_t)kPDRUNCFG_PD_ROM | (uint32_t)kPDRUNCFG_PD_LDOFLASHNV; lv_low_power_mode_cfg.PDCTRL[1] = ~exclude_from_pd[1]; // Voltage control in DeepSleep Low Power Modes lv_low_power_mode_cfg.VOLTAGE = POWER_SetLdoAoLdoMemVoltage(LOWPOWER_CFG_LPMODE_DEEPSLEEP); // SRAM retention control during DEEP-SLEEP lv_low_power_mode_cfg.SRAMRETCTRL = sram_retention_ctrl & (uint32_t)kPOWER_SRAM_DSLP_MASK; /* Interrupts that allow DMA transfers with Flexcomm without waking up the Processor */ if (0UL != (hardware_wake_ctrl & (LOWPOWER_HWWAKE_PERIPHERALS | LOWPOWER_HWWAKE_DMIC | LOWPOWER_HWWAKE_SDMA0 | LOWPOWER_HWWAKE_SDMA1 | LOWPOWER_HWWAKE_DAC))) { lv_low_power_mode_cfg.HWWAKE = (hardware_wake_ctrl & ~LOWPOWER_HWWAKE_FORCED) | LOWPOWER_HWWAKE_ENABLE_FRO192M; } // @NOTE Niobe4mini: update with new BOD reset enable management pmc_reset_ctrl = PMC->RESETCTRL; if ((pmc_reset_ctrl & (PMC_RESETCTRL_BODCORERESETENA_SECURE_MASK | PMC_RESETCTRL_BODCORERESETENA_SECURE_DP_MASK)) == ((0x1UL << PMC_RESETCTRL_BODCORERESETENA_SECURE_SHIFT) | (0x1UL << PMC_RESETCTRL_BODCORERESETENA_SECURE_DP_SHIFT))) { /* BoD CORE reset is activated, so make sure BoD Core and Biasing won't be shutdown */ lv_low_power_mode_cfg.PDCTRL[0] &= ~(uint32_t)kPDRUNCFG_PD_BODCORE & ~(uint32_t)kPDRUNCFG_PD_BIAS; } if ((pmc_reset_ctrl & (PMC_RESETCTRL_BODVDDMAINRESETENA_SECURE_MASK | PMC_RESETCTRL_BODVDDMAINRESETENA_SECURE_DP_MASK)) == ((0x1UL << PMC_RESETCTRL_BODVDDMAINRESETENA_SECURE_SHIFT) | (0x1UL << PMC_RESETCTRL_BODVDDMAINRESETENA_SECURE_DP_SHIFT))) { /* BoD VDDMAIN reset is activated, so make sure BoD VDDMAIN and Biasing won't be shutdown */ lv_low_power_mode_cfg.PDCTRL[0] &= ~(uint32_t)kPDRUNCFG_PD_BODVDDMAIN & ~(uint32_t)kPDRUNCFG_PD_BIAS; } /* CPU Wake up & Interrupt sources control */ lv_low_power_mode_cfg.WAKEUPSRC[0] = lv_low_power_mode_cfg.WAKEUPINT[0] = wakeup_interrupts[0]; lv_low_power_mode_cfg.WAKEUPSRC[1] = lv_low_power_mode_cfg.WAKEUPINT[1] = wakeup_interrupts[1]; lv_low_power_mode_cfg.WAKEUPSRC[2] = lv_low_power_mode_cfg.WAKEUPINT[2] = wakeup_interrupts[2]; lv_low_power_mode_cfg.WAKEUPSRC[3] = lv_low_power_mode_cfg.WAKEUPINT[3] = wakeup_interrupts[3]; /* Enter low power mode */ POWER_SetLowPowerMode(&lv_low_power_mode_cfg); } /** * brief PMC power Down function call * return nothing */ void POWER_EnterPowerDown(uint32_t exclude_from_pd[1], uint32_t sram_retention_ctrl, uint32_t wakeup_interrupts[4], uint32_t cpu_retention_addr) { LPC_LOWPOWER_T lv_low_power_mode_cfg; /* Low Power Mode configuration structure */ // Clear Low Power Mode configuration variable (void)memset(&lv_low_power_mode_cfg, 0x0, sizeof(LPC_LOWPOWER_T)); // Configure Low Power Mode configuration variable : POWER DOWN mode lv_low_power_mode_cfg.CFG = (uint32_t)LOWPOWER_CFG_LPMODE_POWERDOWN << LOWPOWER_CFG_LPMODE_INDEX; // Only FRO32K, XTAL32K, FRO1M, COMP, BIAS and VREF can stay powered during POWERDOWN. // LDO_MEM is enabled (because at least 1 SRAM instance will be required - for CPU state retention -) lv_low_power_mode_cfg.PDCTRL[0] = ~(exclude_from_pd[0] | (uint32_t)kPDRUNCFG_PD_LDOMEM); lv_low_power_mode_cfg.PDCTRL[1] = 0xFFFFFFFFUL; // Force Bias activation if Analog Comparator is required, otherwise, disable it. if ((lv_low_power_mode_cfg.PDCTRL[0] & (uint32_t)kPDRUNCFG_PD_COMP) == 0UL) { // Analog Comparator is required du ring power-down: Enable Biasing lv_low_power_mode_cfg.PDCTRL[0] = lv_low_power_mode_cfg.PDCTRL[0] & (~(uint32_t)kPDRUNCFG_PD_BIAS); } else { // Analog Comparator is not required du ring power-down: Disable Biasing lv_low_power_mode_cfg.PDCTRL[0] = lv_low_power_mode_cfg.PDCTRL[0] | (uint32_t)kPDRUNCFG_PD_BIAS; } // SRAM retention control during POWER-DOWN // Depending on where the user wants to locate the CPU state retention data, // the associated SRAM instance will be automatically put in retention mode. // The boundaries are defined in such a way that the area where the CPU state // will be retained does not cross any SRAM instance boundary. // Per hardware design, 1540 bytes are necessary to store the whole CPU state #define RAM_00_CPU_RET_ADDR_MIN 0x20000000UL // RAM_00 start address #define RAM_00_CPU_RET_ADDR_MAX 0x200009FCUL // RAM_00 start address + 1540 - 1 #define RAM_01_CPU_RET_ADDR_MIN 0x20001000UL // RAM_01 start address #define RAM_01_CPU_RET_ADDR_MAX 0x200019FCUL // RAM_01 start address + 1540 - 1 #define RAM_02_CPU_RET_ADDR_MIN 0x20002000UL // RAM_02 start address #define RAM_02_CPU_RET_ADDR_MAX 0x200029FCUL // RAM_02 start address + 1540 - 1 #define RAM_03_CPU_RET_ADDR_MIN 0x20003000UL // RAM_03 start address #define RAM_03_CPU_RET_ADDR_MAX 0x200039FCUL // RAM_03 start address + 1540 - 1 if ((cpu_retention_addr >= RAM_00_CPU_RET_ADDR_MIN) && (cpu_retention_addr <= RAM_00_CPU_RET_ADDR_MAX)) { // Inside RAM_00 sram_retention_ctrl |= (uint32_t)kPOWER_SRAM_RAM_00; } else { if ((cpu_retention_addr >= RAM_01_CPU_RET_ADDR_MIN) && (cpu_retention_addr <= RAM_01_CPU_RET_ADDR_MAX)) { // Inside RAM_01 sram_retention_ctrl |= (uint32_t)kPOWER_SRAM_RAM_01; } else { if ((cpu_retention_addr >= RAM_02_CPU_RET_ADDR_MIN) && (cpu_retention_addr <= RAM_02_CPU_RET_ADDR_MAX)) { // Inside RAM_02 sram_retention_ctrl |= (uint32_t)kPOWER_SRAM_RAM_02; } else { if ((cpu_retention_addr >= RAM_03_CPU_RET_ADDR_MIN) && (cpu_retention_addr <= RAM_03_CPU_RET_ADDR_MAX)) { // Inside RAM_03 sram_retention_ctrl |= (uint32_t)kPOWER_SRAM_RAM_03; } else { // Error! Therefore, we locate the retention area in RAM_00 cpu_retention_addr = 0x20000000UL; sram_retention_ctrl |= (uint32_t)kPOWER_SRAM_RAM_00; } } } } lv_low_power_mode_cfg.SRAMRETCTRL = sram_retention_ctrl & (uint32_t)kPOWER_SRAM_PDWN_MASK; // Voltage control in Low Power Modes // The Memories Voltage settings below are for voltage scaling lv_low_power_mode_cfg.VOLTAGE = POWER_SetLdoAoLdoMemVoltage(LOWPOWER_CFG_LPMODE_POWERDOWN); /* CPU0 retention Address */ lv_low_power_mode_cfg.CPURETCTRL = ((cpu_retention_addr >> 1) | LOWPOWER_CPURETCTRL_ENA_MASK) & (LOWPOWER_CPURETCTRL_MEMBASE_MASK | LOWPOWER_CPURETCTRL_ENA_MASK); /* CPU Wake up & Interrupt sources control */ lv_low_power_mode_cfg.WAKEUPSRC[0] = lv_low_power_mode_cfg.WAKEUPINT[0] = wakeup_interrupts[0] & (WAKEUP_GPIO_GLOBALINT0 | WAKEUP_GPIO_GLOBALINT1 | WAKEUP_FLEXCOMM3 | WAKEUP_ACMP | WAKEUP_RTC_ALARM_WAKEUP | WAKEUP_WAKEUP_MAILBOX); lv_low_power_mode_cfg.WAKEUPSRC[1] = lv_low_power_mode_cfg.WAKEUPINT[1] = wakeup_interrupts[1] & WAKEUP_OS_EVENT_TIMER; lv_low_power_mode_cfg.WAKEUPSRC[2] = lv_low_power_mode_cfg.WAKEUPINT[2] = 0UL; lv_low_power_mode_cfg.WAKEUPSRC[3] = lv_low_power_mode_cfg.WAKEUPINT[3] = wakeup_interrupts[3] & WAKEUP_ITRC; /* Enter low power mode */ POWER_SetLowPowerMode(&lv_low_power_mode_cfg); } /** * brief PMC Deep Power-Down function call * return nothing */ void POWER_EnterDeepPowerDown(uint32_t exclude_from_pd[1], uint32_t sram_retention_ctrl, uint32_t wakeup_interrupts[2], uint32_t wakeup_io_ctrl) { LPC_LOWPOWER_T lv_low_power_mode_cfg; /* Low Power Mode configuration structure */ // Clear Low Power Mode configuration variable (void)memset(&lv_low_power_mode_cfg, 0x0, sizeof(LPC_LOWPOWER_T)); // Configure Low Power Mode configuration variable : DEEP POWER-DOWN mode lv_low_power_mode_cfg.CFG = (uint32_t)LOWPOWER_CFG_LPMODE_DEEPPOWERDOWN << LOWPOWER_CFG_LPMODE_INDEX; // Note: only FRO32K, XTAL32K, FRO1M and LDO_MEM can stay powered during DEEP POWER-DOWN lv_low_power_mode_cfg.PDCTRL[0] = ~exclude_from_pd[0]; lv_low_power_mode_cfg.PDCTRL[1] = 0xFFFFFFFFUL; // SRAM retention control during DEEP POWER-DOWN // RAM_X0, RAM_02 and RAM_03 excluded: they are used by ROM Boot code sram_retention_ctrl = sram_retention_ctrl & (uint32_t)kPOWER_SRAM_DPWD_MASK; lv_low_power_mode_cfg.SRAMRETCTRL = sram_retention_ctrl; // Sanity check: if retention is required for any SRAM instance other than RAM_00, make sure LDO MEM will stay // powered */ if ((sram_retention_ctrl & (~(uint32_t)kPOWER_SRAM_RAM_00)) != 0UL) { // SRAM retention is required : enable LDO_MEM lv_low_power_mode_cfg.PDCTRL[0] &= ~(uint32_t)kPDRUNCFG_PD_LDOMEM; } else { // No SRAM retention required : disable LDO_MEM lv_low_power_mode_cfg.PDCTRL[0] |= (uint32_t)kPDRUNCFG_PD_LDOMEM; } // Voltage control in Low Power Modes // The Memories Voltage settings below are for voltage scaling lv_low_power_mode_cfg.VOLTAGE = POWER_SetLdoAoLdoMemVoltage(LOWPOWER_CFG_LPMODE_DEEPPOWERDOWN); // Wake up sources control lv_low_power_mode_cfg.WAKEUPSRC[0] = lv_low_power_mode_cfg.WAKEUPINT[0] = wakeup_interrupts[0] & WAKEUP_RTC_ALARM_WAKEUP; /* CPU Wake up sources control : only WAKEUP_RTC_LITE_ALARM_WAKEUP */ lv_low_power_mode_cfg.WAKEUPSRC[1] = lv_low_power_mode_cfg.WAKEUPINT[1] = wakeup_interrupts[1] & WAKEUP_OS_EVENT_TIMER; /* CPU Wake up sources control : only WAKEUP_OS_EVENT_TIMER */ lv_low_power_mode_cfg.WAKEUPSRC[2] = lv_low_power_mode_cfg.WAKEUPINT[2] = 0UL; lv_low_power_mode_cfg.WAKEUPSRC[3] = lv_low_power_mode_cfg.WAKEUPINT[3] = 0UL; /* Wake up I/O sources */ lv_low_power_mode_cfg.WAKEUPIOSRC = POWER_WakeUpIOCtrl(wakeup_io_ctrl); /* Enter low power mode */ POWER_SetLowPowerMode(&lv_low_power_mode_cfg); /*** We'll reach this point ONLY and ONLY if the DEEPPOWERDOWN has not been taken (for instance because an RTC or * OSTIMER interrupt is pending) ***/ } /** * @brief Configures the 5 wake-up pins to wake up the part in DEEP-SLEEP and POWER-DOWN low power modes. * @param wakeup_io_cfg_src : for all wake-up pins : indicates if the config is from IOCON or from PMC. * @param wakeup_io_ctrl: the 5 wake-up pins configurations (see "LOWPOWER_WAKEUPIOSRC_*" definition) * @return Nothing * * !!! IMPORTANT NOTES : * 1 - To be called just before POWER_EnterDeepSleep() or POWER_EnterPowerDown(). */ /** * brief PMC Deep Power-Down function call * return nothing */ void POWER_SetWakeUpPins(uint32_t wakeup_io_cfg_src, uint32_t wakeup_io_ctrl) { if (wakeup_io_cfg_src == (uint32_t)LOWPOWER_WAKEUPIO_CFG_SRC_IOCON) { /* All wake-up pins controls are coming from IOCON */ wakeup_io_ctrl = wakeup_io_ctrl | LOWPOWER_WAKEUPIO_PIO0_DISABLEPULLUPDOWN_MASK | LOWPOWER_WAKEUPIO_PIO1_DISABLEPULLUPDOWN_MASK | LOWPOWER_WAKEUPIO_PIO2_DISABLEPULLUPDOWN_MASK | LOWPOWER_WAKEUPIO_PIO3_DISABLEPULLUPDOWN_MASK | LOWPOWER_WAKEUPIO_PIO4_DISABLEPULLUPDOWN_MASK; /* Make sure IOCON is not modified inside POWER_WakeUpIOCtrl */ PMC->WAKEUPIOCTRL = POWER_WakeUpIOCtrl(wakeup_io_ctrl) & (~PMC_WAKEUPIOCTRL_WAKEUPIO_ENABLE_CTRL_MASK); } else { /* All wake-up pins controls are coming from PMC */ PMC->WAKEUPIOCTRL = POWER_WakeUpIOCtrl(wakeup_io_ctrl) | PMC_WAKEUPIOCTRL_WAKEUPIO_ENABLE_CTRL_MASK; } /* Release Wake up I/O reset (WAKEUPIO_RSTN = 1)*/ PMC->WAKEUPIOCTRL |= PMC_WAKEUPIOCTRL_WAKEUPIO_RSTN_MASK; } void POWER_GetWakeUpCause(power_reset_cause_t *reset_cause, power_boot_mode_t *boot_mode, power_wakeup_pin_t *wakeup_pin_cause) { uint32_t reset_cause_reg; uint32_t boot_mode_reg; uint32_t wakeupio_cause_reg; boot_mode_reg = (PMC->STATUS & PMC_STATUS_BOOTMODE_MASK) >> PMC_STATUS_BOOTMODE_SHIFT; switch (boot_mode_reg) { case 1: /* DEEP-SLEEP */ *boot_mode = kBOOT_MODE_LP_DEEP_SLEEP; break; case 2: /* POWER-DOWN */ *boot_mode = kBOOT_MODE_LP_POWER_DOWN; break; case 3: /* DEEP-POWER-DOWN */ *boot_mode = kBOOT_MODE_LP_DEEP_POWER_DOWN; break; default: /* All non Low Power Mode wake-up */ *boot_mode = kBOOT_MODE_POWER_UP; break; } wakeupio_cause_reg = PMC->WAKEIOCAUSE; if (boot_mode_reg == 0UL) { /* POWER-UP: Power On Reset, Pin reset, Brown Out Detectors, Software Reset: * PMC has been reset, so wake up pin event not expected to have happened. */ *wakeup_pin_cause = kWAKEUP_PIN_NONE; } else { switch (((wakeupio_cause_reg & PMC_WAKEIOCAUSE_WAKEUPIO_EVENTS_ORDER_MASK) >> PMC_WAKEIOCAUSE_WAKEUPIO_EVENTS_ORDER_SHIFT)) { case 0x0: *wakeup_pin_cause = kWAKEUP_PIN_NONE; break; case 0x1: *wakeup_pin_cause = kWAKEUP_PIN_0; break; case 0x2: *wakeup_pin_cause = kWAKEUP_PIN_1; break; case 0x4: *wakeup_pin_cause = kWAKEUP_PIN_2; break; case 0x8: *wakeup_pin_cause = kWAKEUP_PIN_3; break; case 0x10: *wakeup_pin_cause = kWAKEUP_PIN_4; break; default: /* Mutiple */ *wakeup_pin_cause = kWAKEUP_PIN_MULTIPLE; break; } } reset_cause_reg = PMC->AOREG1; /* * Prioritize interrupts source with respect to how critical they are. */ if (0U != (reset_cause_reg & PMC_AOREG1_CDOGRESET_MASK)) { /* Code Watchdog Reset */ *reset_cause = kRESET_CAUSE_CDOGRESET; } else { if (0UL != (reset_cause_reg & PMC_AOREG1_WDTRESET_MASK)) { /* Watchdog Timer Reset */ *reset_cause = kRESET_CAUSE_WDTRESET; } else { if (0U != (reset_cause_reg & PMC_AOREG1_SYSTEMRESET_MASK)) { /* ARM System Reset */ *reset_cause = kRESET_CAUSE_ARMSYSTEMRESET; } else { if (boot_mode_reg != 3UL) /* POWER-UP: Power On Reset, Pin reset, Brown Out Detectors, Software Reset, DEEP-SLEEP and POWER-DOWN */ { /* * Prioritise Reset causes, starting from the strongest (Power On Reset) */ if (0U != (reset_cause_reg & PMC_AOREG1_POR_MASK)) { /* Power On Reset */ *reset_cause = kRESET_CAUSE_POR; } else { if (0U != (reset_cause_reg & PMC_AOREG1_BODRESET_MASK)) { /* Brown-out Detector reset (either BODVBAT or BODCORE) */ *reset_cause = kRESET_CAUSE_BODRESET; } else { if (0U != (reset_cause_reg & PMC_AOREG1_PADRESET_MASK)) { /* Hardware Pin Reset */ *reset_cause = kRESET_CAUSE_PADRESET; } else { if (0U != (reset_cause_reg & PMC_AOREG1_SWRRESET_MASK)) { /* Software triggered Reset */ *reset_cause = kRESET_CAUSE_SWRRESET; } else { /* Unknown Reset Cause (shall never occur) */ *reset_cause = kRESET_CAUSE_NOT_DETERMINISTIC; } } } } } else /* boot_mode_reg == 3 : DEEP-POWER-DOWN */ { switch (((reset_cause_reg & PMC_AOREG1_DPD_EVENTS_ORDER_MASK) >> PMC_AOREG1_DPD_EVENTS_ORDER_SHIFT)) { case 1: *reset_cause = kRESET_CAUSE_DPDRESET_WAKEUPIO; break; case 2: *reset_cause = kRESET_CAUSE_DPDRESET_RTC; break; case 3: *reset_cause = kRESET_CAUSE_DPDRESET_WAKEUPIO_RTC; break; case 4: *reset_cause = kRESET_CAUSE_DPDRESET_OSTIMER; break; case 5: *reset_cause = kRESET_CAUSE_DPDRESET_WAKEUPIO_OSTIMER; break; case 6: *reset_cause = kRESET_CAUSE_DPDRESET_RTC_OSTIMER; break; case 7: *reset_cause = kRESET_CAUSE_DPDRESET_WAKEUPIO_RTC_OSTIMER; break; default: /* Unknown Reset Cause (shall not occur) */ *reset_cause = kRESET_CAUSE_NOT_DETERMINISTIC; break; } } // if ( boot_mode != 3 ) } // if ( reset_cause_reg & PMC_AOREG1_CDOGRESET_MASK ) } // if ( reset_cause_reg & PMC_AOREG1_WDTRESET_MASK ) } // if ( reset_cause_reg & PMC_AOREG1_SYSTEMRESET_MASK ) } /** * @brief Described in fsl_common.h * @param * @return */ void POWER_SetVoltageForFreq(uint32_t system_freq_hz) { if (system_freq_hz <= DCDC_POWER_PROFILE_LOW_MAX_FREQ_HZ) { /* [0 Hz - DCDC_POWER_PROFILE_LOW_MAX_FREQ_HZ Hz] */ POWER_SetSystemPowerProfile(V_SYSTEM_POWER_PROFILE_LOW); POWER_SetVoltageForProcess(V_SYSTEM_POWER_PROFILE_LOW); } else { if (system_freq_hz <= DCDC_POWER_PROFILE_MEDIUM_MAX_FREQ_HZ) { /* ]DCDC_POWER_PROFILE_LOW_MAX_FREQ_HZ Hz - DCDC_POWER_PROFILE_MEDIUM_MAX_FREQ_HZ Hz] */ POWER_SetSystemPowerProfile(V_SYSTEM_POWER_PROFILE_MEDIUM); POWER_SetVoltageForProcess(V_SYSTEM_POWER_PROFILE_MEDIUM); } else { /* > DCDC_POWER_PROFILE_MEDIUM_MAX_FREQ_HZ Hz */ POWER_SetSystemPowerProfile(V_SYSTEM_POWER_PROFILE_HIGH); POWER_SetVoltageForProcess(V_SYSTEM_POWER_PROFILE_HIGH); } } /* Update BoD Core */ if (0UL == Chip_GetVersion()) { /* 0A */ if (system_freq_hz <= 135000000U) { PMC->BODCORE = (PMC->BODCORE & ~PMC_BODCORE_HYST_MASK & ~PMC_BODCORE_TRIGLVL_MASK) | PMC_BODCORE_HYST(kPOWER_BodHystLevel50mv) | PMC_BODCORE_TRIGLVL(kPOWER_BodCoreLevel0A900mv); } else { PMC->BODCORE = (PMC->BODCORE & ~PMC_BODCORE_HYST_MASK & ~PMC_BODCORE_TRIGLVL_MASK) | PMC_BODCORE_HYST(kPOWER_BodHystLevel25mv) | PMC_BODCORE_TRIGLVL(kPOWER_BodCoreLevel0A950mv); } } else { /* 1B */ if (system_freq_hz < 100000000U) { PMC->BODCORE = (PMC->BODCORE & ~PMC_BODCORE_HYST_MASK & ~PMC_BODCORE_TRIGLVL_MASK) | PMC_BODCORE_HYST(kPOWER_BodHystLevel75mv) | PMC_BODCORE_TRIGLVL(kPOWER_BodCoreLevel1B929mv); } else if (system_freq_hz <= 135000000U) { PMC->BODCORE = (PMC->BODCORE & ~PMC_BODCORE_HYST_MASK & ~PMC_BODCORE_TRIGLVL_MASK) | PMC_BODCORE_HYST(kPOWER_BodHystLevel50mv) | PMC_BODCORE_TRIGLVL(kPOWER_BodCoreLevel1B984mv); } else { PMC->BODCORE = (PMC->BODCORE & ~PMC_BODCORE_HYST_MASK & ~PMC_BODCORE_TRIGLVL_MASK) | PMC_BODCORE_HYST(kPOWER_BodHystLevel25mv) | PMC_BODCORE_TRIGLVL(kPOWER_BodCoreLevel1B1038mv); } } } /** * @brief Wait at least 2us. * @param None * @return Nothing */ static void POWER_WaitLDOCoreInit(void) { /* * Note: Once LDO_CORE High Power Mode has been enabled, * at least 2us are required before one can reliabily sample * the LDO Low Voltage Detectore Output. * The PMC clock being 12 MHz, with at least 5 dummy read * operations, it is guaranteed by design that, whatever the * System/CPU clock frequency (up to 200 MHz). */ volatile uint32_t reg_data; for (int i = 0; i < 5; i++) { reg_data = PMC->STATUSPWR; /* Dummy Read */ } (void)reg_data; } /** * @brief Wait at least 2us. * @param None * @return Nothing */ static void POWER_SRAMPowerUpDelay(void) { /* * Note: Wait about 1 us * The PMC clock being 12 MHz, with at least 3 dummy read * operations, it is guaranteed by design that when this , * function is called, at least 1 us will elapse, * whatever the System/CPU clock frequency (up to 200 MHz). */ volatile uint32_t reg_data; for (int i = 0; i < 3; i++) { reg_data = PMC->STATUSPWR; /* Dummy Read */ } (void)reg_data; } /** * @brief Shut off the Flash and execute the _WFI(), then power up the Flash after wake-up event * @param None * @return Nothing */ static void POWER_PowerCycleCpu(void) { /* Switch System Clock to FRO12Mhz (the configuration before calling this function will not be restored back) */ POWER_SetSystemClock12MHZ(); /* Configure the Cortex-M33 in Deep Sleep mode */ SCB->SCR = SCB->SCR | SCB_SCR_SLEEPDEEP_Msk; /* Enter in low power mode */ __WFI(); /* Configure the Cortex-M33 in Active mode */ SCB->SCR = SCB->SCR & (~SCB_SCR_SLEEPDEEP_Msk); }; /** * @brief Configures and enters in low power mode * @param : p_lowpower_cfg * @return Nothing */ static void POWER_SetLowPowerMode(LPC_LOWPOWER_T *p_lowpower_cfg) { uint32_t i, primask, reg_data; uint32_t cpu0_nmi_enable; uint32_t cpu0_int_enable[4]; uint32_t analog_ctrl_regs[7]; /* To store Analog Controller Registers */ uint32_t vref_regs[4]; /* To store VREF Registers */ uint32_t fmccr_reg; /* FMC Configuration Register */ /* Save FMC configuration */ fmccr_reg = SYSCON->FMCCR; cpu0_nmi_enable = SYSCON->NMISRC & SYSCON_NMISRC_NMIENCPU0_MASK; /* Save the configuration of the NMI Register */ SYSCON->NMISRC &= ~SYSCON_NMISRC_NMIENCPU0_MASK; /* Disable NMI of CPU0 */ // Save the configuration of the CPU interrupt enable Registers (because they are overwritten in // POWER_SetLowPowerMode) for (i = 0; i < 4U; i++) { cpu0_int_enable[i] = NVIC->ISER[i]; } uint32_t low_power_mode = (p_lowpower_cfg->CFG & LOWPOWER_CFG_LPMODE_MASK) >> LOWPOWER_CFG_LPMODE_INDEX; /* Set the Low power mode.*/ PMC->CTRL = (PMC->CTRL & (~PMC_CTRL_LPMODE_MASK)) | PMC_CTRL_LPMODE(low_power_mode); /* SRAM in Retention modes */ PMC->SRAMRETCTRL = p_lowpower_cfg->SRAMRETCTRL; /* Configure the voltage level of the Always On domain, Memories LDO */ PMC->LDOPMU = (PMC->LDOPMU & (~PMC_LDOPMU_VADJ_PWD_MASK) & (~PMC_LDOPMU_VADJ_BOOST_PWD_MASK)) | PMC_LDOPMU_VADJ_PWD((p_lowpower_cfg->VOLTAGE & LOWPOWER_VOLTAGE_LDO_PMU_MASK) >> LOWPOWER_VOLTAGE_LDO_PMU_INDEX) | PMC_LDOPMU_VADJ_BOOST_PWD((p_lowpower_cfg->VOLTAGE & LOWPOWER_VOLTAGE_LDO_PMU_BOOST_MASK) >> LOWPOWER_VOLTAGE_LDO_PMU_BOOST_INDEX); PMC->LDOMEM = (PMC->LDOMEM & (~PMC_LDOMEM_VADJ_PWD_MASK) & (~PMC_LDOMEM_VADJ_BOOST_PWD_MASK)) | PMC_LDOMEM_VADJ_PWD((p_lowpower_cfg->VOLTAGE & LOWPOWER_VOLTAGE_LDO_MEM_MASK) >> LOWPOWER_VOLTAGE_LDO_MEM_INDEX) | PMC_LDOMEM_VADJ_BOOST_PWD((p_lowpower_cfg->VOLTAGE & LOWPOWER_VOLTAGE_LDO_MEM_BOOST_MASK) >> LOWPOWER_VOLTAGE_LDO_MEM_BOOST_INDEX); /* * Enable wake up interrupt. * Rational : we enable each interrupt (NVIC->ISER) that can wake up the CPU here (before the __disable_irq() * below): Hence, if an interrupt was pending and not treated before (for any reason), the CPU will jump to that * interrupt handler before trying to enter the low power mode. * VERY IMPORTANT : Also, any interrupt set in NVIC->ISER, even though __disable_irq(), will make the CPU * go out of the Deep Sleep mode. */ for (i = 0; i < 4U; i++) { NVIC->ISER[i] = p_lowpower_cfg->WAKEUPINT[i]; /* Enable wake-up interrupt */ SYSCON->STARTER[i] = p_lowpower_cfg->WAKEUPSRC[i]; /* Enable wake-up sources */ } /* Save the configuration of the Priority Mask Register */ primask = __get_PRIMASK(); switch (low_power_mode) { case LOWPOWER_CFG_LPMODE_DEEPSLEEP: { /* DEEP SLEEP power mode */ uint32_t bod_core_trglvl; /* BoD Core trigger level */ uint32_t css_ctrl, syscon_css_clk_ctrl, syscon_css_clk_pclk_hclk; uint32_t syscon_autoclkgateoverride_reg; /* AUTOCLKGATEOVERRIDE Configuration Register */ /* Analog Modules to be shut off */ PMC->PDSLEEPCFG0 = p_lowpower_cfg->PDCTRL[0]; PMC->PDSLEEPCFG1 = p_lowpower_cfg->PDCTRL[1]; /* Saving AUTOCLKGATEOVERRIDE register*/ syscon_autoclkgateoverride_reg = SYSCON->AUTOCLKGATEOVERRIDE; /* DMA transactions with Flexcomm during DEEP SLEEP */ SYSCON->HARDWARESLEEP = p_lowpower_cfg->HWWAKE; /* Enable autoclockgating on SDMA0 and SDMA1 during DeepSleep*/ SYSCON->AUTOCLKGATEOVERRIDE = 0xC0DE0000UL | (syscon_autoclkgateoverride_reg & (~(SYSCON_AUTOCLKGATEOVERRIDE_SDMA1_MASK | SYSCON_AUTOCLKGATEOVERRIDE_SDMA0_MASK))); /* Make sure DEEP POWER DOWN reset is disabled */ PMC->RESETCTRL = PMC->RESETCTRL & (~PMC_RESETCTRL_DPDWAKEUPRESETENABLE_MASK); /* Adjust BoD Core Trip point . Currently set to 700 mV. TODO :: :: Check this value. */ reg_data = PMC->BODCORE; bod_core_trglvl = (reg_data & PMC_BODCORE_TRIGLVL_MASK) >> PMC_BODCORE_TRIGLVL_SHIFT; PMC->BODCORE = (reg_data & (~PMC_BODCORE_TRIGLVL_MASK)) | PMC_BODCORE_TRIGLVL(kPOWER_BodCoreLevel0A700mv); // CSSV2 { syscon_css_clk_ctrl = SYSCON_CSS_CLK_CTRL_REG & (1U << 1); css_ctrl = 0U; #if (defined(LPC55S36_SERIES) || defined(LPC5536_SERIES) || defined(LPC5534_SERIES)) syscon_css_clk_pclk_hclk = SYSCON->AHBCLKCTRL2 & (0x1UL << 18); /* Check if CSS is NOT in reset AND is clocked and enable, to avoid deadlock situations or a hardfault */ if ((0UL != (CSSV2_CTRL_REG & 0x1U)) && ((SYSCON->PRESETCTRL2 & 0x40000U) == 0UL) && (0UL != syscon_css_clk_pclk_hclk)) #else syscon_css_clk_pclk_hclk = SYSCON->AHBCLKCTRL[2] & (0x1UL<< 18); /* Check if CSS is NOT in reset AND is clocked and enable, to avoid deadlock situations or a hardfault */ if (((SYSCON->PRESETCTRL[2] & 0x40000U) == 0) && syscon_css_clk_pclk_hclk && (CSSV2_CTRL_REG & 0x1U)) #endif { css_ctrl = CSSV2_CTRL_REG; /* Wait until CSS is in idle state (CSS_STATUS_BUSY_MASK) */ while (0UL != (CSSV2_STATUS_REG & 0x1UL)) { } /* Disable CSS */ CSSV2_CTRL_REG = CSSV2_CTRL_REG & 0xFFFFFFFEU; /* Swicth off i_css_clk/pclk/hclk */ SYSCON->AHBCLKCTRLCLR[2] = ((uint32_t)1U << 18); } /* Switch off DTRNG clocks */ SYSCON_CSS_CLK_CTRL_CLR_REG = (1U << 1); } /* Disable all IRQs */ __disable_irq(); /* * - Switch PMC clock to 1 MHz, * - Set LDO_MEM as SRAM supply source during DEEP-SLEEP, * - Set LDO_CORE Low Power mode as Core supply source during DEEP-SLEEP, * - Select Core Logic supply source when waking up from DEEP-SLEEP. */ reg_data = PMC->CTRL & (~PMC_CTRL_SELCLOCK_MASK) & (~PMC_CTRL_DEEPSLEEPCORESUPPLY_MASK) & (~PMC_CTRL_SELMEMSUPPLY_MASK); if (POWER_GetCorePowerSource() == kPOWER_CoreSrcDCDC) { /* Core Logic is supplied by DCDC Converter when waking up from DEEP-SLEEP */ PMC->CTRL = reg_data & (~PMC_CTRL_SELCORESUPPLYWK_MASK); } else { /* Core Logic is supplied by LDO CORE (configured in High Power mode) when waking up from DEEP-SLEEP */ PMC->CTRL = reg_data | PMC_CTRL_SELCORESUPPLYWK_MASK; } /* _WFI() */ POWER_PowerCycleCpu(); /* Switch PMC clock to 12 MHz and Configure the PMC in ACTIVE mode */ PMC->CTRL = (PMC->CTRL & (~PMC_CTRL_LPMODE_MASK)) | PMC_CTRL_SELCLOCK_MASK | PMC_CTRL_LPMODE(LOWPOWER_CFG_LPMODE_ACTIVE); /* Restore BoD Core Trip point. */ PMC->BODCORE = (PMC->BODCORE & (~PMC_BODCORE_TRIGLVL_MASK)) | PMC_BODCORE_TRIGLVL(bod_core_trglvl); // CSSV2 { /* Restore i_css_clk/pclk/hclk */ SYSCON->AHBCLKCTRLSET[2] = syscon_css_clk_pclk_hclk; /* Restore DTRNG clocks */ SYSCON_CSS_CLK_CTRL_SET_REG = syscon_css_clk_ctrl; /* Check if CSS is NOT in reset AND is clocked, to avoid deadlock situations */ #if (defined(LPC55S36_SERIES) || defined(LPC5536_SERIES) || defined(LPC5534_SERIES)) if (((SYSCON->PRESETCTRL2 & 0x40000U) == 0UL) && (0UL != syscon_css_clk_pclk_hclk) && (0UL != (css_ctrl & 0x1UL))) #else if (((SYSCON->PRESETCTRL[2] & 0x40000U) == 0UL) && (0UL != syscon_css_clk_pclk_hclk) && (0UL != (css_ctrl & 0x1UL))) #endif { /* Restore CSS */ CSSV2_CTRL_REG = css_ctrl; /* Wait until CSS is in idle state */ while (0UL != (CSSV2_STATUS_REG & 0x1UL)) { } } } /* Restore AUTOCLKGATEOVERRIDE register*/ SYSCON->AUTOCLKGATEOVERRIDE = 0xC0DE0000UL | syscon_autoclkgateoverride_reg; /* Reset Sleep Postpone configuration */ SYSCON->HARDWARESLEEP = 0; break; } case LOWPOWER_CFG_LPMODE_POWERDOWN: { uint32_t lpcac_ctrl_reg; uint32_t vref_rst_state; uint32_t vref_clk_state; uint32_t syscon_ahbclk_reg_0; uint32_t syscon_css_clk_ctrl, syscon_css_clk_pclk_hclk; /* POWER DOWN power mode */ power_core_pwr_source_t core_supply_source; /* Only FRO32K, XTAL32K, FRO1M, COMP, BIAS, LDO_MEM and can VREF stay powered during POWERDOWN */ PMC->PDSLEEPCFG0 = p_lowpower_cfg->PDCTRL[0] | (0xFFFFFFFFUL & (~((uint32_t)kPDRUNCFG_PD_FRO1M | (uint32_t)kPDRUNCFG_PD_FRO32K | (uint32_t)kPDRUNCFG_PD_XTAL32K | (uint32_t)kPDRUNCFG_PD_COMP | (uint32_t)kPDRUNCFG_PD_BIAS | (uint32_t)kPDRUNCFG_PD_LDOMEM | (uint32_t)kPDRUNCFG_PD_VREF))); PMC->PDSLEEPCFG1 = p_lowpower_cfg->PDCTRL[1]; /* Make sure DEEP POWER DOWN reset is disabled */ PMC->RESETCTRL = PMC->RESETCTRL & (~PMC_RESETCTRL_DPDWAKEUPRESETENABLE_MASK); /* Enable VREF Module (reset & clock) */ #if (defined(LPC55S36_SERIES) || defined(LPC5536_SERIES) || defined(LPC5534_SERIES)) vref_rst_state = (SYSCON->PRESETCTRL3) & SYSCON_PRESETCTRL3_VREF_RST_MASK; vref_clk_state = (SYSCON->AHBCLKCTRL3) & SYSCON_AHBCLKCTRL3_VREF_MASK; SYSCON->PRESETCTRLCLR[3] = SYSCON_PRESETCTRL3_VREF_RST_MASK; SYSCON->AHBCLKCTRLSET[3] = SYSCON_AHBCLKCTRL3_VREF_MASK; #else vref_rst_state = (*(uint32_t *)(((uint32_t *)SYSCON->RESERVED_5))) & 0x40000UL; vref_clk_state = (*(uint32_t *)(((uint32_t *)SYSCON->RESERVED_9))) & 0x40000UL; *(uint32_t *)(((uint32_t *)SYSCON->RESERVED_7)) = 0x40000UL; *(uint32_t *)(((uint32_t *)SYSCON->RESERVED_10)) = 0x40000UL; #endif /* Save VREF Module User Configuration ... */ vref_regs[0] = VREF->CSR; vref_regs[1] = VREF->UTRIM; /* Save VREF Module Factory Trimmings ... */ VREF->TEST_UNLOCK = 0x5AA5UL << 1; /* TEST_UNLOCK. Required before writting TRIM0 & TRIM1 */ vref_regs[2] = VREF->TRIM0; vref_regs[3] = VREF->TRIM1; /* ... then enable VREF Module isolation */ PMC->MISCCTRL = PMC->MISCCTRL | PMC_MISCCTRL_VREF_ISO_MASK; // CSSV2 { syscon_css_clk_ctrl = SYSCON_CSS_CLK_CTRL_REG & (1U << 1); #if (defined(LPC55S36_SERIES) || defined(LPC5536_SERIES) || defined(LPC5534_SERIES)) syscon_css_clk_pclk_hclk = SYSCON->AHBCLKCTRL2 & ((uint32_t)1U << 18); #else syscon_css_clk_pclk_hclk = SYSCON->AHBCLKCTRL[2] & ((uint32_t)1U << 18); #endif /* Switch off DTRNG clocks */ SYSCON_CSS_CLK_CTRL_CLR_REG = (1U << 1); /* Swicth off i_css_clk/pclk/hclk */ SYSCON->AHBCLKCTRLCLR[2] = ((uint32_t)1U << 18); } /* CPU0 Retention */ SYSCON->FUNCRETENTIONCTRL = (SYSCON->FUNCRETENTIONCTRL & SYSCON_FUNCRETENTIONCTRL_RET_LENTH_MASK) | p_lowpower_cfg->CPURETCTRL; /* Disable all IRQs */ __disable_irq(); /* * From here : * 1 - If an interrupt that is enable occurs, the _WFI instruction will not be executed and we won't enter * in POWER DOWN. 2 - If an interrupt that is not enable occurs, there is no consequence neither on the * execution of the low power mode nor on the behaviour of the CPU. */ /* Switch PMC clock to 1 MHz and select LDO CORE (configured in High Power mode) as Core Logic supply source * when waking up from POWER-DOWN */ PMC->CTRL = (PMC->CTRL & (~PMC_CTRL_SELCLOCK_MASK)) | PMC_CTRL_SELCORESUPPLYWK_MASK; /* Save user Core Supply Source configuration */ core_supply_source = POWER_GetCorePowerSource(); /* Store Analog Controller Registers */ analog_ctrl_regs[0] = ANACTRL->FRO192M_CTRL; analog_ctrl_regs[1] = ANACTRL->ANALOG_CTRL_CFG; analog_ctrl_regs[2] = ANACTRL->ADC_CTRL; analog_ctrl_regs[3] = ANACTRL->XO32M_CTRL; analog_ctrl_regs[4] = ANACTRL->BOD_DCDC_INT_CTRL; analog_ctrl_regs[5] = ANACTRL->LDO_XO32M; analog_ctrl_regs[6] = ANACTRL->OSC_TESTBUS; /* Save Flash Cache settings, then disable and clear it */ lpcac_ctrl_reg = SYSCON->LPCAC_CTRL; SYSCON->LPCAC_CTRL = 0x3; /* dis_lpcac = '1', clr_lpcac = '1' */ /* Save ROM clock setting, then enable it. * It is important to have the ROM clock running before entering * POWER-DOWN for the following two reasons: * 1 - In case of POWER-DOWN with CPU state retention (which is the only * option currently offered to the user), some flip-flops that depend on this clock need to be saved. * 2 - In case of POWER-DOWN without CPU state retention (which is a * hardware feature that is NOT offered to the user for the time being) * CPU reboot cannot occur if ROM clock has been shut down. */ #if (defined(LPC55S36_SERIES) || defined(LPC5536_SERIES) || defined(LPC5534_SERIES)) syscon_ahbclk_reg_0 = SYSCON->AHBCLKCTRL0; SYSCON->AHBCLKCTRLSET[0] = SYSCON_AHBCLKCTRL0_ROM_MASK; /* Enable the clock for ROM */ #else syscon_ahbclk_reg_0 = SYSCON->AHBCLKCTRL[0]; SYSCON->AHBCLKCTRLSET[0] = SYSCON_AHBCLKCTRL_ROM_MASK; /* Enable the clock for ROM */ #endif /* _WFI() */ POWER_PowerCycleCpu(); /* Restore ROM clock setting */ #if (defined(LPC55S36_SERIES) || defined(LPC5536_SERIES) || defined(LPC5534_SERIES)) SYSCON->AHBCLKCTRL0 = syscon_ahbclk_reg_0; #else SYSCON->AHBCLKCTRL[0] = syscon_ahbclk_reg_0; #endif /* Restore Flash Cache settings */ SYSCON->LPCAC_CTRL = lpcac_ctrl_reg; /* Switch PMC clock to 12 MHz and Configure the PMC in ACTIVE mode */ PMC->CTRL = (PMC->CTRL & (~PMC_CTRL_LPMODE_MASK)) | PMC_CTRL_SELCLOCK_MASK | PMC_CTRL_LPMODE(LOWPOWER_CFG_LPMODE_ACTIVE); #if (defined(LPC55S36_SERIES) || defined(LPC5536_SERIES) || defined(LPC5534_SERIES)) { /* Restore i_css_clk/pclk/hclk */ SYSCON->AHBCLKCTRLSET[2] = syscon_css_clk_pclk_hclk; /* Restore DTRNG clocks */ SYSCON_CSS_CLK_CTRL_SET_REG = syscon_css_clk_ctrl; } #endif /* Restore Analog Controller Registers */ ANACTRL->FRO192M_CTRL = analog_ctrl_regs[0] | ANACTRL_FRO192M_CTRL_WRTRIM_MASK; ANACTRL->ANALOG_CTRL_CFG = analog_ctrl_regs[1]; ANACTRL->ADC_CTRL = analog_ctrl_regs[2]; ANACTRL->XO32M_CTRL = analog_ctrl_regs[3]; ANACTRL->BOD_DCDC_INT_CTRL = analog_ctrl_regs[4]; ANACTRL->LDO_XO32M = analog_ctrl_regs[5]; ANACTRL->OSC_TESTBUS = analog_ctrl_regs[6]; /* Restore VREF Module Factory Trimmings ... */ VREF->TEST_UNLOCK = 0x5AA5UL << 1; /* TEST_UNLOCK. Required before writting TRIM0 & TRIM1 */ VREF->TRIM0 = vref_regs[2]; VREF->TRIM1 = vref_regs[3]; /* ... then restore VREF Module User Configuration */ VREF->CSR = vref_regs[0]; VREF->UTRIM = vref_regs[1]; /* Restore VREF module reset and clock state */ #if (defined(LPC55S36_SERIES) || defined(LPC5536_SERIES) || defined(LPC5534_SERIES)) SYSCON->PRESETCTRL3 = (SYSCON->PRESETCTRL3 & (~SYSCON_PRESETCTRL3_VREF_RST_MASK)) | vref_rst_state; SYSCON->AHBCLKCTRL3 = (SYSCON->AHBCLKCTRL3 & (~SYSCON_AHBCLKCTRL3_VREF_MASK)) | vref_clk_state; #else *(uint32_t *)(((uint32_t *)SYSCON->RESERVED_5)) = ((*(uint32_t *)(((uint32_t *)SYSCON->RESERVED_5))) & (~0x40000UL)) | vref_rst_state; *(uint32_t *)(((uint32_t *)SYSCON->RESERVED_9)) = ((*(uint32_t *)(((uint32_t *)SYSCON->RESERVED_9))) & (~0x40000UL)) | vref_clk_state; #endif /* Disable VREF Module isolation ... */ PMC->MISCCTRL = PMC->MISCCTRL & (~PMC_MISCCTRL_VREF_ISO_MASK); /* After wake up from Power-down, the Core supply source is LDO CORE */ /* So restore the user configuration if necessary */ if (core_supply_source == kPOWER_CoreSrcDCDC) { /* Restore DCDC Converter as Core Logic supply source */ /* NOTE: PMC must be set in ACTIVE mode first before doing this switching to DCDC */ (void)POWER_SetCorePowerSource(kPOWER_CoreSrcDCDC); } break; } case LOWPOWER_CFG_LPMODE_DEEPPOWERDOWN: { /* DEEP-POWER-DOWN power mode */ /* Configure wake-up by I/O : * - Set up wake-up IO pad control source : PMC WAKEUPIOCTRL (WAKEUPIO_ENABLE = 1) * - Reset Wake-up I/O Edge Detectors & Cause (WAKEUPIO_RSTN = 0) */ PMC->WAKEUPIOCTRL = p_lowpower_cfg->WAKEUPIOSRC | PMC_WAKEUPIOCTRL_WAKEUPIO_ENABLE_CTRL_MASK; /* Release Wake up I/O reset (WAKEUPIO_RSTN = 1)*/ PMC->WAKEUPIOCTRL |= PMC_WAKEUPIOCTRL_WAKEUPIO_RSTN_MASK; /* Only FRO1M, FRO32K, XTAL32K and LDOMEM can stay powered during DEEP POWER-DOWN */ PMC->PDSLEEPCFG0 = p_lowpower_cfg->PDCTRL[0] | (0xFFFFFFFFU & (~((uint32_t)kPDRUNCFG_PD_FRO1M | (uint32_t)kPDRUNCFG_PD_FRO32K | (uint32_t)kPDRUNCFG_PD_XTAL32K | (uint32_t)kPDRUNCFG_PD_LDOMEM))); PMC->PDSLEEPCFG1 = p_lowpower_cfg->PDCTRL[1]; /* Disable all IRQs */ __disable_irq(); /* * From here : * 1 - If an interrupt that is enabled occurs, the _WFI instruction will not be executed and we won't enter * in POWER DOWN. 2 - If an interrupt that is not enabled occurs, there is no consequence neither on the * execution of the low power mode nor on the behaviour of the CPU. */ /* clear all Reset causes */ PMC->RESETCAUSE = 0xFFFFFFFFUL; /* Enable DEEP POWER-DOWN reset */ PMC->RESETCTRL |= PMC_RESETCTRL_DPDWAKEUPRESETENABLE_MASK; /* Switch PMC clock to 1 MHz */ PMC->CTRL = PMC->CTRL & (~PMC_CTRL_SELCLOCK_MASK); /* _WFI() */ POWER_PowerCycleCpu(); /*** We should never reach this point, unless the Low Power cycle has been cancelled somehow. ***/ /* Switch PMC clock to 12 MHz and Configure the PMC in ACTIVE mode */ PMC->CTRL = (PMC->CTRL & (~PMC_CTRL_LPMODE_MASK)) | PMC_CTRL_SELCLOCK_MASK | PMC_CTRL_LPMODE(LOWPOWER_CFG_LPMODE_ACTIVE); break; } default: { /* Error */ break; } } // End switch( low_power_mode ) /* Restore FMC Configuration */ SYSCON->FMCCR = SYSCON->FMCCR | (fmccr_reg & SYSCON_FMCCR_PREFEN_MASK); /* * Restore the configuration of the Priority Mask Register. * Rational : if the interrupts were enable before entering the Low power mode, they will be re-enabled, * if they were disabled, they will stay disabled. */ __set_PRIMASK(primask); /* Restore the configuration of the NMI Register */ SYSCON->NMISRC |= cpu0_nmi_enable; /* Restore the configuration of the CPU interrupt enable Registers (because they have been overwritten inside the * low power API */ for (i = 0; i < 4U; i++) { NVIC->ISER[i] = cpu0_int_enable[i]; } } /** * @brief Configures and enters in low power mode * @param : p_lowpower_cfg * @return Nothing */ static uint32_t POWER_WakeUpIOCtrl(uint32_t p_wakeup_io_ctrl) { uint32_t wake_up_type; uint32_t wakeup_io_ctrl_reg = 0; // Enable IOCON #if (defined(LPC55S36_SERIES) || defined(LPC5536_SERIES) || defined(LPC5534_SERIES)) SYSCON->PRESETCTRLCLR[0] = SYSCON_PRESETCTRL0_IOCON_RST_MASK; SYSCON->AHBCLKCTRLSET[0] = SYSCON_AHBCLKCTRL0_IOCON_MASK; #else SYSCON->PRESETCTRLCLR[0] = SYSCON_PRESETCTRL_IOCON_RST_MASK; SYSCON->AHBCLKCTRLSET[0] = SYSCON_AHBCLKCTRL_IOCON_MASK; #endif /* Configure Pull up & Pull down based on the required wake-up edge */ /* Wake-up I/O 0 */ wake_up_type = (p_wakeup_io_ctrl & (PMC_WAKEUPIOCTRL_RISINGEDGEWAKEUP0_MASK | PMC_WAKEUPIOCTRL_FALLINGEDGEWAKEUP0_MASK)) >> LOWPOWER_WAKEUPIOSRC_PIO0_INDEX; wakeup_io_ctrl_reg |= (wake_up_type << LOWPOWER_WAKEUPIOSRC_PIO0_INDEX); if ((wake_up_type == LOWPOWER_WAKEUPIOSRC_RISING) || (wake_up_type == LOWPOWER_WAKEUPIOSRC_RISING_FALLING)) { /* Rising edge and both rising and falling edges */ if ((p_wakeup_io_ctrl & LOWPOWER_WAKEUPIO_PIO0_DISABLEPULLUPDOWN_MASK) == 0UL) { /* Internal pull up / pull down are not disabled by the user, so use them */ IOCON->PIO[WAKEUPIO_0_PORT][WAKEUPIO_0_PINS] = IOCON_PIO_DIGIMODE(1) | IOCON_PIO_MODE(1); /* Pull down */ wakeup_io_ctrl_reg |= ((uint32_t)LOWPOWER_WAKEUPIOSRC_IO_MODE_PULLDOWN << LOWPOWER_WAKEUPIOSRC_PIO0MODE_INDEX); } } else { if (wake_up_type == LOWPOWER_WAKEUPIOSRC_FALLING) { /* Falling edge only */ if ((p_wakeup_io_ctrl & LOWPOWER_WAKEUPIO_PIO0_DISABLEPULLUPDOWN_MASK) == 0U) { /* Internal pull up / pull down are not disabled by the user, so use them */ IOCON->PIO[WAKEUPIO_0_PORT][WAKEUPIO_0_PINS] = IOCON_PIO_DIGIMODE(1) | IOCON_PIO_MODE(2); /* Pull up */ wakeup_io_ctrl_reg |= ((uint32_t)LOWPOWER_WAKEUPIOSRC_IO_MODE_PULLUP << LOWPOWER_WAKEUPIOSRC_PIO0MODE_INDEX); } } else { /* Wake-up I/O is disabled : set pull-up/pull-down as required by the user */ if ((p_wakeup_io_ctrl & LOWPOWER_WAKEUPIO_PIO0_DISABLEPULLUPDOWN_MASK) != 0U) { /* Wake-up I/O is configured as Plain Input */ p_wakeup_io_ctrl &= ~LOWPOWER_WAKEUPIO_PIO0_PULLUPDOWN_MASK; wakeup_io_ctrl_reg |= ((uint32_t)LOWPOWER_WAKEUPIOSRC_IO_MODE_PLAIN << LOWPOWER_WAKEUPIOSRC_PIO0MODE_INDEX); } else { /* Wake-up I/O is configured as pull-up or pull-down */ if ((p_wakeup_io_ctrl & LOWPOWER_WAKEUPIO_PIO0_PULLUPDOWN_MASK) != 0U) { /* Wake-up I/O is configured as pull-up */ wakeup_io_ctrl_reg |= ((uint32_t)LOWPOWER_WAKEUPIOSRC_IO_MODE_PULLUP << LOWPOWER_WAKEUPIOSRC_PIO0MODE_INDEX); } else { /* Wake-up I/O is configured as pull-down */ wakeup_io_ctrl_reg |= ((uint32_t)LOWPOWER_WAKEUPIOSRC_IO_MODE_PULLDOWN << LOWPOWER_WAKEUPIOSRC_PIO0MODE_INDEX); } } } } /* Wake-up I/O 1 */ wake_up_type = (p_wakeup_io_ctrl & (PMC_WAKEUPIOCTRL_RISINGEDGEWAKEUP1_MASK | PMC_WAKEUPIOCTRL_FALLINGEDGEWAKEUP1_MASK)) >> LOWPOWER_WAKEUPIOSRC_PIO1_INDEX; wakeup_io_ctrl_reg |= (wake_up_type << LOWPOWER_WAKEUPIOSRC_PIO1_INDEX); if ((wake_up_type == LOWPOWER_WAKEUPIOSRC_RISING) || (wake_up_type == LOWPOWER_WAKEUPIOSRC_RISING_FALLING)) { /* Rising edge and both rising and falling edges */ if ((p_wakeup_io_ctrl & LOWPOWER_WAKEUPIO_PIO1_DISABLEPULLUPDOWN_MASK) == 0U) { /* Internal pull up / pull down are not disabled by the user, so use them */ IOCON->PIO[WAKEUPIO_1_PORT][WAKEUPIO_1_PINS] = IOCON_PIO_DIGIMODE(1) | IOCON_PIO_MODE(1); /* Pull down */ wakeup_io_ctrl_reg |= ((uint32_t)LOWPOWER_WAKEUPIOSRC_IO_MODE_PULLDOWN << LOWPOWER_WAKEUPIOSRC_PIO1MODE_INDEX); } } else { if (wake_up_type == LOWPOWER_WAKEUPIOSRC_FALLING) { /* Falling edge only */ if ((p_wakeup_io_ctrl & LOWPOWER_WAKEUPIO_PIO1_DISABLEPULLUPDOWN_MASK) == 0U) { /* Internal pull up / pull down are not disabled by the user, so use them */ IOCON->PIO[WAKEUPIO_1_PORT][WAKEUPIO_1_PINS] = IOCON_PIO_DIGIMODE(1) | IOCON_PIO_MODE(2); /* Pull up */ wakeup_io_ctrl_reg |= ((uint32_t)LOWPOWER_WAKEUPIOSRC_IO_MODE_PULLUP << LOWPOWER_WAKEUPIOSRC_PIO1MODE_INDEX); } } else { /* Wake-up I/O is disabled : set it as required by the user */ if ((p_wakeup_io_ctrl & LOWPOWER_WAKEUPIO_PIO1_DISABLEPULLUPDOWN_MASK) != 0U) { /* Wake-up I/O is configured as Plain Input */ p_wakeup_io_ctrl &= ~LOWPOWER_WAKEUPIO_PIO1_PULLUPDOWN_MASK; wakeup_io_ctrl_reg |= ((uint32_t)LOWPOWER_WAKEUPIOSRC_IO_MODE_PLAIN << LOWPOWER_WAKEUPIOSRC_PIO1MODE_INDEX); } else { /* Wake-up I/O is configured as pull-up or pull-down */ if ((p_wakeup_io_ctrl & LOWPOWER_WAKEUPIO_PIO1_PULLUPDOWN_MASK) != 0U) { /* Wake-up I/O is configured as pull-up */ wakeup_io_ctrl_reg |= ((uint32_t)LOWPOWER_WAKEUPIOSRC_IO_MODE_PULLUP << LOWPOWER_WAKEUPIOSRC_PIO1MODE_INDEX); } else { /* Wake-up I/O is configured as pull-down */ wakeup_io_ctrl_reg |= ((uint32_t)LOWPOWER_WAKEUPIOSRC_IO_MODE_PULLDOWN << LOWPOWER_WAKEUPIOSRC_PIO1MODE_INDEX); } } } } /* Wake-up I/O 2 */ wake_up_type = (p_wakeup_io_ctrl & (PMC_WAKEUPIOCTRL_RISINGEDGEWAKEUP2_MASK | PMC_WAKEUPIOCTRL_FALLINGEDGEWAKEUP2_MASK)) >> LOWPOWER_WAKEUPIOSRC_PIO2_INDEX; wakeup_io_ctrl_reg |= (wake_up_type << LOWPOWER_WAKEUPIOSRC_PIO2_INDEX); if ((wake_up_type == LOWPOWER_WAKEUPIOSRC_RISING) || (wake_up_type == LOWPOWER_WAKEUPIOSRC_RISING_FALLING)) { /* Rising edge and both rising and falling edges */ if ((p_wakeup_io_ctrl & LOWPOWER_WAKEUPIO_PIO2_DISABLEPULLUPDOWN_MASK) == 0U) { /* Internal pull up / pull down are not disabled by the user, so use them */ IOCON->PIO[WAKEUPIO_2_PORT][WAKEUPIO_2_PINS] = IOCON_PIO_DIGIMODE(1) | IOCON_PIO_MODE(1); /* Pull down */ wakeup_io_ctrl_reg |= ((uint32_t)LOWPOWER_WAKEUPIOSRC_IO_MODE_PULLDOWN << LOWPOWER_WAKEUPIOSRC_PIO2MODE_INDEX); } } else { if (wake_up_type == LOWPOWER_WAKEUPIOSRC_FALLING) { /* Falling edge only */ if ((p_wakeup_io_ctrl & LOWPOWER_WAKEUPIO_PIO2_DISABLEPULLUPDOWN_MASK) == 0U) { /* Internal pull up / pull down are not disabled by the user, so use them */ IOCON->PIO[WAKEUPIO_2_PORT][WAKEUPIO_2_PINS] = IOCON_PIO_DIGIMODE(1) | IOCON_PIO_MODE(2); /* Pull up */ wakeup_io_ctrl_reg |= ((uint32_t)LOWPOWER_WAKEUPIOSRC_IO_MODE_PULLUP << LOWPOWER_WAKEUPIOSRC_PIO2MODE_INDEX); } } else { /* Wake-up I/O is disabled : set it as required by the user */ if ((p_wakeup_io_ctrl & LOWPOWER_WAKEUPIO_PIO2_DISABLEPULLUPDOWN_MASK) != 0U) { /* Wake-up I/O is configured as Plain Input */ p_wakeup_io_ctrl &= ~LOWPOWER_WAKEUPIO_PIO2_PULLUPDOWN_MASK; wakeup_io_ctrl_reg |= ((uint32_t)LOWPOWER_WAKEUPIOSRC_IO_MODE_PLAIN << LOWPOWER_WAKEUPIOSRC_PIO2MODE_INDEX); } else { /* Wake-up I/O is configured as pull-up or pull-down */ if ((p_wakeup_io_ctrl & LOWPOWER_WAKEUPIO_PIO2_PULLUPDOWN_MASK) != 0U) { /* Wake-up I/O is configured as pull-up */ wakeup_io_ctrl_reg |= ((uint32_t)LOWPOWER_WAKEUPIOSRC_IO_MODE_PULLUP << LOWPOWER_WAKEUPIOSRC_PIO2MODE_INDEX); } else { /* Wake-up I/O is configured as pull-down */ wakeup_io_ctrl_reg |= ((uint32_t)LOWPOWER_WAKEUPIOSRC_IO_MODE_PULLDOWN << LOWPOWER_WAKEUPIOSRC_PIO2MODE_INDEX); } } } } /* Wake-up I/O 3 */ wake_up_type = (p_wakeup_io_ctrl & (PMC_WAKEUPIOCTRL_RISINGEDGEWAKEUP3_MASK | PMC_WAKEUPIOCTRL_FALLINGEDGEWAKEUP3_MASK)) >> LOWPOWER_WAKEUPIOSRC_PIO3_INDEX; wakeup_io_ctrl_reg |= (wake_up_type << LOWPOWER_WAKEUPIOSRC_PIO3_INDEX); if ((wake_up_type == LOWPOWER_WAKEUPIOSRC_RISING) || (wake_up_type == LOWPOWER_WAKEUPIOSRC_RISING_FALLING)) { /* Rising edge and both rising and falling edges */ if ((p_wakeup_io_ctrl & LOWPOWER_WAKEUPIO_PIO3_DISABLEPULLUPDOWN_MASK) == 0U) { /* Internal pull up / pull down are not disabled by the user, so use them */ IOCON->PIO[WAKEUPIO_3_PORT][WAKEUPIO_3_PINS] = IOCON_PIO_DIGIMODE(1) | IOCON_PIO_MODE(1); /* Pull down */ wakeup_io_ctrl_reg |= ((uint32_t)LOWPOWER_WAKEUPIOSRC_IO_MODE_PULLDOWN << LOWPOWER_WAKEUPIOSRC_PIO3MODE_INDEX); } } else { if (wake_up_type == LOWPOWER_WAKEUPIOSRC_FALLING) { /* Falling edge only */ if ((p_wakeup_io_ctrl & LOWPOWER_WAKEUPIO_PIO3_DISABLEPULLUPDOWN_MASK) == 0U) { /* Internal pull up / pull down are not disabled by the user, so use them */ IOCON->PIO[WAKEUPIO_3_PORT][WAKEUPIO_3_PINS] = IOCON_PIO_DIGIMODE(1) | IOCON_PIO_MODE(2); /* Pull up */ wakeup_io_ctrl_reg |= ((uint32_t)LOWPOWER_WAKEUPIOSRC_IO_MODE_PULLUP << LOWPOWER_WAKEUPIOSRC_PIO3MODE_INDEX); } } else { /* Wake-up I/O is disabled : set it as required by the user */ if ((p_wakeup_io_ctrl & LOWPOWER_WAKEUPIO_PIO3_DISABLEPULLUPDOWN_MASK) != 0U) { /* Wake-up I/O is configured as Plain Input */ p_wakeup_io_ctrl &= ~LOWPOWER_WAKEUPIO_PIO3_PULLUPDOWN_MASK; wakeup_io_ctrl_reg |= ((uint32_t)LOWPOWER_WAKEUPIOSRC_IO_MODE_PLAIN << LOWPOWER_WAKEUPIOSRC_PIO3MODE_INDEX); } else { /* Wake-up I/O is configured as pull-up or pull-down */ if ((p_wakeup_io_ctrl & LOWPOWER_WAKEUPIO_PIO3_PULLUPDOWN_MASK) != 0U) { /* Wake-up I/O is configured as pull-up */ wakeup_io_ctrl_reg |= ((uint32_t)LOWPOWER_WAKEUPIOSRC_IO_MODE_PULLUP << LOWPOWER_WAKEUPIOSRC_PIO3MODE_INDEX); } else { /* Wake-up I/O is configured as pull-down */ wakeup_io_ctrl_reg |= ((uint32_t)LOWPOWER_WAKEUPIOSRC_IO_MODE_PULLDOWN << LOWPOWER_WAKEUPIOSRC_PIO3MODE_INDEX); } } } } /* Wake-up I/O 4 */ wake_up_type = (p_wakeup_io_ctrl & (PMC_WAKEUPIOCTRL_RISINGEDGEWAKEUP4_MASK | PMC_WAKEUPIOCTRL_FALLINGEDGEWAKEUP4_MASK)) >> LOWPOWER_WAKEUPIOSRC_PIO4_INDEX; wakeup_io_ctrl_reg |= (wake_up_type << LOWPOWER_WAKEUPIOSRC_PIO4_INDEX); if ((wake_up_type == LOWPOWER_WAKEUPIOSRC_RISING) || (wake_up_type == LOWPOWER_WAKEUPIOSRC_RISING_FALLING)) { /* Rising edge and both rising and falling edges */ if ((p_wakeup_io_ctrl & LOWPOWER_WAKEUPIO_PIO4_DISABLEPULLUPDOWN_MASK) == 0UL) { /* Internal pull up / pull down are not disabled by the user, so use them */ IOCON->PIO[WAKEUPIO_4_PORT][WAKEUPIO_4_PINS] = IOCON_PIO_DIGIMODE(1) | IOCON_PIO_MODE(1); /* Pull down */ wakeup_io_ctrl_reg |= ((uint32_t)LOWPOWER_WAKEUPIOSRC_IO_MODE_PULLDOWN << LOWPOWER_WAKEUPIOSRC_PIO4MODE_INDEX); } } else { if (wake_up_type == LOWPOWER_WAKEUPIOSRC_FALLING) { /* Falling edge only */ if ((p_wakeup_io_ctrl & LOWPOWER_WAKEUPIO_PIO4_DISABLEPULLUPDOWN_MASK) == 0UL) { /* Internal pull up / pull down are not disabled by the user, so use them */ IOCON->PIO[WAKEUPIO_4_PORT][WAKEUPIO_4_PINS] = IOCON_PIO_DIGIMODE(1) | IOCON_PIO_MODE(2); /* Pull up */ wakeup_io_ctrl_reg |= ((uint32_t)LOWPOWER_WAKEUPIOSRC_IO_MODE_PULLUP << LOWPOWER_WAKEUPIOSRC_PIO4MODE_INDEX); } } else { /* Wake-up I/O is disabled : set it as required by the user */ if ((p_wakeup_io_ctrl & LOWPOWER_WAKEUPIO_PIO4_DISABLEPULLUPDOWN_MASK) != 0U) { /* Wake-up I/O is configured as Plain Input */ wakeup_io_ctrl_reg |= ((uint32_t)LOWPOWER_WAKEUPIOSRC_IO_MODE_PLAIN << LOWPOWER_WAKEUPIOSRC_PIO4MODE_INDEX); } else { /* Wake-up I/O is configured as pull-up or pull-down */ if ((p_wakeup_io_ctrl & LOWPOWER_WAKEUPIO_PIO4_PULLUPDOWN_MASK) != 0U) { /* Wake-up I/O is configured as pull-up */ wakeup_io_ctrl_reg |= ((uint32_t)LOWPOWER_WAKEUPIOSRC_IO_MODE_PULLUP << LOWPOWER_WAKEUPIOSRC_PIO4MODE_INDEX); } else { /* Wake-up I/O is configured as pull-down */ wakeup_io_ctrl_reg |= ((uint32_t)LOWPOWER_WAKEUPIOSRC_IO_MODE_PULLDOWN << LOWPOWER_WAKEUPIOSRC_PIO4MODE_INDEX); } } } } return (wakeup_io_ctrl_reg); } static uint32_t POWER_SetLdoAoLdoMemVoltage(uint32_t p_lp_mode) { uint32_t voltage = 0; uint32_t ldo_ao_trim = 0; uint32_t ldo_mem_trim = 0; uint32_t lv_v_ldo_pmu, lv_v_ldo_pmu_boost; uint32_t lv_v_ldo_mem, lv_v_ldo_mem_boost; #if (defined(LPC55S36_SERIES) || defined(LPC5536_SERIES) || defined(LPC5534_SERIES)) ldo_ao_trim = FLASH_NMPA_LDO_AO; ldo_mem_trim = FLASH_NMPA_LDO_MEM; #endif switch (p_lp_mode) { case LOWPOWER_CFG_LPMODE_DEEPSLEEP: { if ((ldo_ao_trim & 0x80000000UL) != 0UL) { /* Apply settings coming from Flash */ lv_v_ldo_pmu = (ldo_ao_trim >> 8) & 0x1FUL; lv_v_ldo_pmu_boost = (ldo_ao_trim >> 13) & 0x1FUL; } else { /* Apply default settings */ lv_v_ldo_pmu = (uint32_t)V_AO_0P900; lv_v_ldo_pmu_boost = (uint32_t)V_AO_0P850; } } break; case LOWPOWER_CFG_LPMODE_POWERDOWN: { if ((ldo_ao_trim & 0x80000000UL) != 0U) { /* Apply settings coming from Flash */ lv_v_ldo_pmu = (ldo_ao_trim >> 18) & 0x1FUL; lv_v_ldo_pmu_boost = (ldo_ao_trim >> 23) & 0x1FUL; } else { /* Apply default settings */ lv_v_ldo_pmu = (uint32_t)V_AO_0P800; lv_v_ldo_pmu_boost = (uint32_t)V_AO_0P750; } } break; case LOWPOWER_CFG_LPMODE_DEEPPOWERDOWN: { if ((ldo_ao_trim & 0x80000000UL) != 0UL) { /* Apply settings coming from Flash */ lv_v_ldo_pmu = (ldo_ao_trim >> 18) & 0x1FUL; lv_v_ldo_pmu_boost = (ldo_ao_trim >> 23) & 0x1FUL; } else { /* Apply default settings */ lv_v_ldo_pmu = (uint32_t)V_AO_0P800; lv_v_ldo_pmu_boost = (uint32_t)V_AO_0P750; } } break; default: /* We should never reach this point */ lv_v_ldo_pmu = (uint32_t)V_AO_1P100; lv_v_ldo_pmu_boost = (uint32_t)V_AO_1P050; break; } if ((ldo_mem_trim & 0x80000000U) != 0UL) { /* Apply settings coming from Flash */ lv_v_ldo_mem = ldo_mem_trim & 0x1FUL; lv_v_ldo_mem_boost = (ldo_mem_trim >> 8) & 0x1FUL; } else { /* Apply default settings */ lv_v_ldo_mem = (uint32_t)V_AO_0P750; /* Set to 0.75V (voltage Scaling) */ lv_v_ldo_mem_boost = (uint32_t)V_AO_0P700; /* Set to 0.7V (voltage Scaling) */ } /* The Memories Voltage settings below are for voltage scaling */ voltage = (lv_v_ldo_pmu << LOWPOWER_VOLTAGE_LDO_PMU_INDEX) | (lv_v_ldo_pmu_boost << LOWPOWER_VOLTAGE_LDO_PMU_BOOST_INDEX) | (lv_v_ldo_mem << LOWPOWER_VOLTAGE_LDO_MEM_INDEX) | (lv_v_ldo_mem_boost << LOWPOWER_VOLTAGE_LDO_MEM_BOOST_INDEX); return (voltage); } /** * @brief Configures System Power Profile * @param power_profile : Low/Medium/High * @return Nothing */ static void POWER_SetSystemPowerProfile(v_system_power_profile_t power_profile) { uint32_t dcdcTrimValue0 = 0; uint32_t dcdcTrimValue1 = 0; switch (power_profile) { case V_SYSTEM_POWER_PROFILE_MEDIUM: /* Medium */ #if (defined(LPC55S36_SERIES) || defined(LPC5536_SERIES) || defined(LPC5534_SERIES)) dcdcTrimValue0 = FLASH_NMPA_DCDC_POWER_PROFILE_MEDIUM_ARRAY0; dcdcTrimValue1 = FLASH_NMPA_DCDC_POWER_PROFILE_MEDIUM_ARRAY1; #endif if (0UL != (dcdcTrimValue0 & 0x1UL)) { /* DCDC Trimmings in Flash are valid */ dcdcTrimValue0 = (uint32_t)dcdcTrimValue0 >> 1; PMC->DCDC0 = dcdcTrimValue0; PMC->DCDC1 = dcdcTrimValue1; } else { /* DCDC Trimmings in Flash are not valid. * Set a default value */ PMC->DCDC0 = 0x0220ACF1UL >> 1; PMC->DCDC1 = 0x01D05C78UL; } break; case V_SYSTEM_POWER_PROFILE_HIGH: /* High */ #if (defined(LPC55S36_SERIES) || defined(LPC5536_SERIES) || defined(LPC5534_SERIES)) dcdcTrimValue0 = FLASH_NMPA_DCDC_POWER_PROFILE_HIGH_ARRAY0; dcdcTrimValue1 = FLASH_NMPA_DCDC_POWER_PROFILE_HIGH_ARRAY1; #endif if (0UL != (dcdcTrimValue0 & 0x1UL)) { /* DCDC Trimmings in Flash are valid */ dcdcTrimValue0 = dcdcTrimValue0 >> 1; PMC->DCDC0 = dcdcTrimValue0; PMC->DCDC1 = dcdcTrimValue1; } else { /* DCDC Trimmings in Flash are not valid. * Set a default value */ PMC->DCDC0 = 0x0228ACF9UL >> 1; PMC->DCDC1 = 0x01E05C68UL; } break; default: /* Low */ #if (defined(LPC55S36_SERIES) || defined(LPC5536_SERIES) || defined(LPC5534_SERIES)) dcdcTrimValue0 = FLASH_NMPA_DCDC_POWER_PROFILE_LOW_ARRAY0; dcdcTrimValue1 = FLASH_NMPA_DCDC_POWER_PROFILE_LOW_ARRAY1; #endif if (0UL != (dcdcTrimValue0 & 0x1UL)) { /* DCDC Trimmings in Flash are valid */ dcdcTrimValue0 = dcdcTrimValue0 >> 1; PMC->DCDC0 = dcdcTrimValue0; PMC->DCDC1 = dcdcTrimValue1; } else { /* DCDC Trimmings in Flash are not valid. * Set a default value */ PMC->DCDC0 = 0x0210CCFDUL >> 1; PMC->DCDC1 = 0x01C05C98UL; } break; } } /** * @brief Configures System Power Profile * @param power_profile : Low/Medium/High * @return Nothing */ static void POWER_SetVoltageForProcess(v_system_power_profile_t power_profile) { /* Get Sample Process Corner */ lowpower_process_corner_enum part_process_corner = POWER_GetPartProcessCorner(); switch (part_process_corner) { case PROCESS_CORNER_SSS: /* Slow Corner */ { switch (power_profile) { case V_SYSTEM_POWER_PROFILE_MEDIUM: /* Medium */ POWER_SetSystemVoltage(VOLTAGE_SSS_MED_MV); break; case V_SYSTEM_POWER_PROFILE_HIGH: /* High */ POWER_SetSystemVoltage(VOLTAGE_SSS_HIG_MV); break; default: /* V_SYSTEM_POWER_PROFILE_LOW */ POWER_SetSystemVoltage(VOLTAGE_SSS_LOW_MV); break; } // switch(power_profile) } break; case PROCESS_CORNER_FFF: /* Fast Corner */ { switch (power_profile) { case V_SYSTEM_POWER_PROFILE_MEDIUM: /* Medium */ POWER_SetSystemVoltage(VOLTAGE_FFF_MED_MV); break; case V_SYSTEM_POWER_PROFILE_HIGH: /* High */ POWER_SetSystemVoltage(VOLTAGE_FFF_HIG_MV); break; default: /* V_SYSTEM_POWER_PROFILE_LOW */ POWER_SetSystemVoltage(VOLTAGE_FFF_LOW_MV); break; } // switch(power_profile) } break; default: /* Nominal (NNN) and all others Process Corners : assume Nominal Corner */ { switch (power_profile) { case V_SYSTEM_POWER_PROFILE_MEDIUM: /* Medium */ POWER_SetSystemVoltage(VOLTAGE_NNN_MED_MV); break; case V_SYSTEM_POWER_PROFILE_HIGH: /* High */ POWER_SetSystemVoltage(VOLTAGE_NNN_HIG_MV); break; default: /* V_SYSTEM_POWER_PROFILE_LOW */ POWER_SetSystemVoltage(VOLTAGE_NNN_LOW_MV); break; } // switch(power_profile) } break; } // switch(part_process_corner) } /** * @brief * @param * @return */ static lowpower_process_corner_enum POWER_GetPartProcessCorner(void) { lowpower_process_corner_enum part_process_corner; uint32_t pvt_ringo_hz; uint32_t pvt_ringo_0 = 0; uint32_t pvt_ringo_1 = 0; #if (defined(LPC55S36_SERIES) || defined(LPC5536_SERIES) || defined(LPC5534_SERIES)) pvt_ringo_0 = FLASH_NMPA_PVT_MONITOR_0_RINGO; pvt_ringo_1 = FLASH_NMPA_PVT_MONITOR_1_RINGO; #endif /* * Check that the PVT Monitors Trimmings in flash are valid. * Note : On Customer Samples, PVT Trimmings in flash will ALWAYS be valid, * so that in the SDK, the check below could be skipped (but NOT the right shift operation) */ if (0UL != (pvt_ringo_0 & 0x1UL)) { /* PVT Trimmings in Flash are valid */ pvt_ringo_0 = pvt_ringo_0 >> 1; } else { /* PVT Trimmings in Flash are NOT valid (average value assumed) */ pvt_ringo_0 = PROCESS_NNN_AVG_HZ; } if (0UL != (pvt_ringo_1 & 0x1UL)) { /* PVT Trimmings in Flash are valid */ pvt_ringo_1 = pvt_ringo_1 >> 1; } else { /* PVT Trimmings in Flash are NOT valid (average value assumed) */ pvt_ringo_1 = PROCESS_NNN_AVG_HZ; } /* * There are 2 Ring Oscillators in the System. * We consider the worst case scenario by choosing * the minimum of the 2 Ring Oscillators values * as the final value to determine the Process Corner. */ if (pvt_ringo_1 <= pvt_ringo_0) { pvt_ringo_hz = pvt_ringo_1; } else { pvt_ringo_hz = pvt_ringo_0; } /* * Determine the process corner based on the value of the Ring Oscillator frequency */ if (pvt_ringo_hz <= PROCESS_NNN_MIN_HZ) { /* SSS Process Corner */ part_process_corner = PROCESS_CORNER_SSS; } else { if (pvt_ringo_hz <= PROCESS_NNN_MAX_HZ) { /* NNN Process Corner */ part_process_corner = PROCESS_CORNER_NNN; } else { /* FFF Process Corner */ part_process_corner = PROCESS_CORNER_FFF; } } return (part_process_corner); } /** * @brief * @param * @return */ static void POWER_SetSystemVoltage(uint32_t system_voltage_mv) { /* * Set system voltage */ uint32_t lv_ldo_ao = (uint32_t)V_AO_1P100; /* <ldo_ao> */ uint32_t lv_ldo_ao_boost = (uint32_t)V_AO_1P150; /* <ldo_ao_boost> */ uint32_t lv_dcdc = (uint32_t)V_DCDC_1P100; /* <dcdc> */ uint32_t lv_ldo_core = (uint32_t)V_LDOCORE_HP_1P102; /* <ldo_core> */ /* * Because DCDC has less code than LD_AO, we first determine the * optimum DCDC settings, then we find the closest possible settings * for LDO_AO, knowing that we want both settings to be as close as possible * (ideally, they shall be equal). */ if (system_voltage_mv <= 950UL) { lv_dcdc = (uint32_t)V_DCDC_0P950; lv_ldo_ao = (uint32_t)V_AO_0P960; lv_ldo_ao_boost = (uint32_t)V_AO_1P010; lv_ldo_core = (uint32_t)V_LDOCORE_HP_0P953; } else if (system_voltage_mv <= 975UL) { lv_dcdc = (uint32_t)V_DCDC_0P975; lv_ldo_ao = (uint32_t)V_AO_0P980; lv_ldo_ao_boost = (uint32_t)V_AO_1P030; lv_ldo_core = (uint32_t)V_LDOCORE_HP_0P980; } else if (system_voltage_mv <= 1000UL) { lv_dcdc = (uint32_t)V_DCDC_1P000; lv_ldo_ao = (uint32_t)V_AO_1P000; lv_ldo_ao_boost = (uint32_t)V_AO_1P050; lv_ldo_core = (uint32_t)V_LDOCORE_HP_1P001; } else if (system_voltage_mv <= 1025UL) { lv_dcdc = (uint32_t)V_DCDC_1P025; lv_ldo_ao = (uint32_t)V_AO_1P030; lv_ldo_ao_boost = (uint32_t)V_AO_1P080; lv_ldo_core = (uint32_t)V_LDOCORE_HP_1P027; } else if (system_voltage_mv <= 1050UL) { lv_dcdc = (uint32_t)V_DCDC_1P050; lv_ldo_ao = (uint32_t)V_AO_1P060; lv_ldo_ao_boost = (uint32_t)V_AO_1P110; lv_ldo_core = (uint32_t)V_LDOCORE_HP_1P055; } else if (system_voltage_mv <= 1075UL) { lv_dcdc = (uint32_t)V_DCDC_1P075; lv_ldo_ao = (uint32_t)V_AO_1P080; lv_ldo_ao_boost = (uint32_t)V_AO_1P130; lv_ldo_core = (uint32_t)V_LDOCORE_HP_1P075; } else if (system_voltage_mv <= 1100UL) { lv_dcdc = (uint32_t)V_DCDC_1P100; lv_ldo_ao = (uint32_t)V_AO_1P100; lv_ldo_ao_boost = (uint32_t)V_AO_1P150; lv_ldo_core = (uint32_t)V_LDOCORE_HP_1P102; } else if (system_voltage_mv <= 1125UL) { lv_dcdc = (uint32_t)V_DCDC_1P125; lv_ldo_ao = (uint32_t)V_AO_1P130; lv_ldo_ao_boost = (uint32_t)V_AO_1P160; lv_ldo_core = (uint32_t)V_LDOCORE_HP_1P027; } else if (system_voltage_mv <= 1150UL) { lv_dcdc = (uint32_t)V_DCDC_1P150; lv_ldo_ao = (uint32_t)V_AO_1P160; lv_ldo_ao_boost = (uint32_t)V_AO_1P220; lv_ldo_core = (uint32_t)V_LDOCORE_HP_1P156; } else if (system_voltage_mv <= 1175UL) { lv_dcdc = (uint32_t)V_DCDC_1P175; lv_ldo_ao = (uint32_t)V_AO_1P160; lv_ldo_ao_boost = (uint32_t)V_AO_1P220; lv_ldo_core = (uint32_t)V_LDOCORE_HP_1P177; } else { lv_dcdc = (uint32_t)V_DCDC_1P200; lv_ldo_ao = (uint32_t)V_AO_1P220; lv_ldo_ao_boost = (uint32_t)V_AO_1P220; lv_ldo_core = (uint32_t)V_LDOCORE_HP_1P204; } /* Set up LDO Always-On voltages */ #if (defined(LPC55S36_SERIES) || defined(LPC5536_SERIES) || defined(LPC5534_SERIES)) /* Apply LDO_AO Trimmings */ { int8_t ldo_ao_offset; int32_t lv_ldo_ao_signed; ldo_ao_offset = (int8_t)(uint32_t)(((FLASH_NMPA_LDO_AO & FLASH_NMPA_LDO_AO_VADJ_ACTIVE_MASK) >> FLASH_NMPA_LDO_AO_VADJ_ACTIVE_SHIFT)); lv_ldo_ao_signed = (int32_t)((int32_t)lv_ldo_ao + (int32_t)ldo_ao_offset); if (lv_ldo_ao_signed < (int32_t)V_AO_0P960) { lv_ldo_ao = (uint32_t)V_AO_0P960; } else { if (lv_ldo_ao_signed > (int32_t)V_AO_1P220) { lv_ldo_ao = (uint32_t)V_AO_1P220; } else { lv_ldo_ao = (uint32_t)lv_ldo_ao_signed; } } } // Note: In ACTIVE mode, the LDO BOOST mode is always enabled. // Therefore, the value of the "lv_ldo_ao_boost" does not really matter. // For that reason, we do not recompuete it here. #endif PMC->LDOPMU = (PMC->LDOPMU & (~PMC_LDOPMU_VADJ_MASK) & (~PMC_LDOPMU_VADJ_BOOST_MASK)) | PMC_LDOPMU_VADJ(lv_ldo_ao) | PMC_LDOPMU_VADJ_BOOST(lv_ldo_ao_boost); /* Set up DCDC voltage */ PMC->DCDC0 = (PMC->DCDC0 & (~PMC_DCDC0_VOUT_MASK)) | PMC_DCDC0_VOUT(lv_dcdc); /* Set up LDO_CORE voltage */ #if (defined(LPC55S36_SERIES) || defined(LPC5536_SERIES) || defined(LPC5534_SERIES)) /* Apply LDO_CORE Trimmings */ { int8_t ldo_core_regref_offset; int32_t lv_ldo_core_signed; ldo_core_regref_offset = (int8_t)((uint32_t)((FLASH_NMPA_BOD_LDOCORE & FLASH_NMPA_BOD_LDOCORE_REGREF_1P8V_OFFSET_MASK) >> FLASH_NMPA_BOD_LDOCORE_REGREF_1P8V_OFFSET_SHIFT)); lv_ldo_core_signed = (int32_t)((int32_t)lv_ldo_core + (int32_t)ldo_core_regref_offset); if (lv_ldo_core_signed < (int32_t)V_LDOCORE_HP_1P204) { lv_ldo_core = (uint32_t)V_LDOCORE_HP_1P204; } else { if (lv_ldo_core_signed > (int32_t)V_LDOCORE_HP_0P953) { lv_ldo_core = (uint32_t)V_LDOCORE_HP_0P953; } else { lv_ldo_core = (uint32_t)lv_ldo_core_signed; } } } #endif PMC->LDOCORE0 = (PMC->LDOCORE0 & (~PMC_LDOCORE0_REGREFTRIM_MASK)) | PMC_LDOCORE0_REGREFTRIM(lv_ldo_core); } /** * brief * return */ static void POWER_SRAMSetRegister(power_sram_index_t sram_index, uint32_t power_mode) { switch (sram_index) { case kPOWER_SRAM_IDX_RAM_X0: { PMC->SRAMCTRL0 = (PMC->SRAMCTRL0 & (~(0xFUL << PMC_SRAMCTRL0_RAM_X0_LS_SHIFT))) | (power_mode << PMC_SRAMCTRL0_RAM_X0_LS_SHIFT); break; } case kPOWER_SRAM_IDX_RAM_00: { PMC->SRAMCTRL0 = (PMC->SRAMCTRL0 & (~(0xFUL << PMC_SRAMCTRL0_RAM_00_LS_SHIFT))) | (power_mode << PMC_SRAMCTRL0_RAM_00_LS_SHIFT); break; } case kPOWER_SRAM_IDX_RAM_01: { PMC->SRAMCTRL0 = (PMC->SRAMCTRL0 & (~(0xFUL << PMC_SRAMCTRL0_RAM_01_LS_SHIFT))) | (power_mode << PMC_SRAMCTRL0_RAM_01_LS_SHIFT); break; } case kPOWER_SRAM_IDX_RAM_02: { PMC->SRAMCTRL0 = (PMC->SRAMCTRL0 & (~(0xFUL << PMC_SRAMCTRL0_RAM_02_LS_SHIFT))) | (power_mode << PMC_SRAMCTRL0_RAM_02_LS_SHIFT); break; } case kPOWER_SRAM_IDX_RAM_03: { PMC->SRAMCTRL0 = (PMC->SRAMCTRL0 & (~(0xFUL << PMC_SRAMCTRL0_RAM_03_LS_SHIFT))) | (power_mode << PMC_SRAMCTRL0_RAM_03_LS_SHIFT); break; } case kPOWER_SRAM_IDX_RAM_10: { PMC->SRAMCTRL0 = (PMC->SRAMCTRL0 & (~(0xFUL << PMC_SRAMCTRL0_RAM_10_LS_SHIFT))) | (power_mode << PMC_SRAMCTRL0_RAM_10_LS_SHIFT); break; } case kPOWER_SRAM_IDX_RAM_20: { PMC->SRAMCTRL0 = (PMC->SRAMCTRL0 & (~(0xFUL << PMC_SRAMCTRL0_RAM_20_LS_SHIFT))) | (power_mode << PMC_SRAMCTRL0_RAM_20_LS_SHIFT); break; } case kPOWER_SRAM_IDX_RAM_30: { PMC->SRAMCTRL0 = (PMC->SRAMCTRL0 & (~(0xFUL << PMC_SRAMCTRL0_RAM_30_LS_SHIFT))) | (power_mode << PMC_SRAMCTRL0_RAM_30_LS_SHIFT); break; } case kPOWER_SRAM_IDX_RAM_40: { PMC->SRAMCTRL1 = (PMC->SRAMCTRL1 & (~(0xFUL << PMC_SRAMCTRL1_RAM_40_LS_SHIFT))) | (power_mode << PMC_SRAMCTRL1_RAM_40_LS_SHIFT); break; } case kPOWER_SRAM_IDX_RAM_41: { PMC->SRAMCTRL1 = (PMC->SRAMCTRL1 & (~(0xFUL << PMC_SRAMCTRL1_RAM_41_LS_SHIFT))) | (power_mode << PMC_SRAMCTRL1_RAM_41_LS_SHIFT); break; } case kPOWER_SRAM_IDX_RAM_42: { PMC->SRAMCTRL1 = (PMC->SRAMCTRL1 & (~(0xFUL << PMC_SRAMCTRL1_RAM_42_LS_SHIFT))) | (power_mode << PMC_SRAMCTRL1_RAM_42_LS_SHIFT); break; } case kPOWER_SRAM_IDX_RAM_43: { PMC->SRAMCTRL1 = (PMC->SRAMCTRL1 & (~(0xFUL << PMC_SRAMCTRL1_RAM_43_LS_SHIFT))) | (power_mode << PMC_SRAMCTRL1_RAM_43_LS_SHIFT); break; } case kPOWER_SRAM_IDX_FLASHCACHE: { PMC->SRAMCTRL1 = (PMC->SRAMCTRL1 & (~(0xFUL << PMC_SRAMCTRL1_RAM_FLASHLPCACHE_LS_SHIFT))) | (power_mode << PMC_SRAMCTRL1_RAM_FLASHLPCACHE_LS_SHIFT); break; } case kPOWER_SRAM_IDX_FLEXSPICACHE: { PMC->SRAMCTRL1 = (PMC->SRAMCTRL1 & (~(0xFUL << PMC_SRAMCTRL1_RAM_FLEXSPILPCACHE_LS_SHIFT))) | (power_mode << PMC_SRAMCTRL1_RAM_FLEXSPILPCACHE_LS_SHIFT); break; } default: // Error break; } } /** * brief * return */ static void POWER_SRAMActiveToLightSleep(power_sram_index_t sram_index) { POWER_SRAMSetRegister(sram_index, SRAM_PWR_MODE_LS_CODE); } /** * brief * return */ static void POWER_SRAMActiveToDeepSleep(power_sram_index_t sram_index) { POWER_SRAMSetRegister(sram_index, SRAM_PWR_MODE_DS_CODE); } /** * brief * return */ static void POWER_SRAMActiveToShutDown(power_sram_index_t sram_index) { POWER_SRAMSetRegister(sram_index, SRAM_PWR_MODE_SD_CODE); } /** * brief * return */ static void POWER_SRAMLightSleepToActive(power_sram_index_t sram_index) { POWER_SRAMSetRegister(sram_index, SRAM_PWR_MODE_MPU_CODE); // Wait at least 944.90 ns (worst case, from gf40rfnv_nxp_ehlvsram_008192x032bw4c04_mh_pt_m7) POWER_SRAMPowerUpDelay(); // wait about 1 us POWER_SRAMSetRegister(sram_index, SRAM_PWR_MODE_ACT_CODE); } /** * brief * return */ static void POWER_SRAMDeepSleepToActive(power_sram_index_t sram_index) { POWER_SRAMSetRegister(sram_index, SRAM_PWR_MODE_FPU_CODE); // Wait at least 707.30 ns (worst case, from gf40rfnv_nxp_ehlvsram_008192x032bw4c04_mh_pt_m7) POWER_SRAMPowerUpDelay(); // wait about 1 us POWER_SRAMSetRegister(sram_index, SRAM_PWR_MODE_ACT_CODE); } /** * brief * return */ static void POWER_SRAMShutDownToActive(power_sram_index_t sram_index) { POWER_SRAMSetRegister(sram_index, SRAM_PWR_MODE_FPU_CODE); // Wait at least 382.80 ns (worst case, from gf40rfnv_nxp_ehlvsram_008192x032bw4c04_mh_pt_m7) POWER_SRAMPowerUpDelay(); // wait about 1 us POWER_SRAMSetRegister(sram_index, SRAM_PWR_MODE_ACT_CODE); } /** * brief * return */ static void POWER_SetSystemClock12MHZ(void) { if ((SYSCON->MAINCLKSELA != 0UL) || (SYSCON->MAINCLKSELB != 0UL) || ((SYSCON->AHBCLKDIV & SYSCON_AHBCLKDIV_DIV_MASK) != 0UL)) { /* The System is NOT running at 12 MHz: so switch the system on 12 MHz clock */ /* IMPORTANT NOTE : The assumption here is that before calling any Low Power API * the system will be running at a frequency higher or equal to 12 MHz. */ uint32_t flash_int_enable_reg; uint32_t num_wait_states = 1; /* Default to the maximum number of wait states */ /* Switch main clock to FRO12MHz ( the order of the 5 settings below is critical) */ SYSCON->MAINCLKSELA = SYSCON_MAINCLKSELA_SEL(0); /* Main clock A source select : FRO 12 MHz clock */ SYSCON->MAINCLKSELB = SYSCON_MAINCLKSELB_SEL(0); /* Main clock B source select : Main Clock A */ SYSCON->AHBCLKDIV = SYSCON_AHBCLKDIV_DIV(0); /* Main clock divided by 1 */ /* Adjust FMC waiting time cycles (num_wait_states) and disable PREFETCH * NOTE : PREFETCH disable MUST BE DONE BEFORE the flash command below. */ #if (defined(LPC55S36_SERIES) || defined(LPC5536_SERIES) || defined(LPC5534_SERIES)) SYSCON->FMCCR = (SYSCON->FMCCR & (~SYSCON_FMCCR_FLASHTIM_MASK) & (~SYSCON_FMCCR_PREFEN_MASK)) | SYSCON_FMCCR_FLASHTIM(num_wait_states); /* Adjust Flash Controller waiting time */ flash_int_enable_reg = FLASH->INTEN; /* Save INT_ENABLE register. */ FLASH->INTEN_CLR = 0x1F; /* Disable all interrupt */ FLASH->INTSTAT_CLR = 0x1F; /* Clear all status flags */ #else SYSCON->FMCCR = (SYSCON->FMCCR & (~SYSCON_FMCCR_FMCTIM_MASK) & (~SYSCON_FMCCR_PREFEN_MASK)) | SYSCON_FMCCR_FMCTIM(num_wait_states); /* Adjust Flash Controller waiting time */ flash_int_enable_reg = FLASH->INT_ENABLE; /* Save INT_ENABLE register. */ FLASH->INT_CLR_ENABLE = 0x1F; /* Disable all interrupt */ FLASH->INT_CLR_STATUS = 0x1F; /* Clear all status flags */ #endif FLASH->DATAW[0] = num_wait_states; FLASH->CMD = 0x2; /* CMD_SET_READ_MODE */ #if (defined(LPC55S36_SERIES) || defined(LPC5536_SERIES) || defined(LPC5534_SERIES)) /* Wait until the cmd is completed (without error) */ while (0UL == (FLASH->INTSTAT & FLASH_INTSTAT_DONE_MASK)) { } FLASH->INTSTAT_CLR = 0x1F; /* Clear all status flags, then ... */ FLASH->INTEN_SET = flash_int_enable_reg; /* ... restore INT_ENABLE register. */ #else /* Wait until the cmd is completed (without error) */ while (!(FLASH->INT_STATUS & FLASH_INT_STATUS_DONE_MASK)) { } FLASH->INT_CLR_STATUS = 0x1F; /* Clear all status flags, then ... */ FLASH->INT_SET_ENABLE = flash_int_enable_reg; /* ... restore INT_ENABLE register. */ #endif POWER_SetSystemPowerProfile( V_SYSTEM_POWER_PROFILE_LOW); /* Align DCDC/LDO_CORE Power profile with the 12 MHz frequency */ } else { /* The System is already running at 12 MHz: so disable FMC PREFETCH feature only */ SYSCON->FMCCR = SYSCON->FMCCR & (~SYSCON_FMCCR_PREFEN_MASK); } }