/* VLPR mode entry routine. Puts the processor into very low power * run mode. In this mode all clocks are enabled, but the core, bus, * and peripheral clocks are limited to 2MHz or less. The flash * clock is limited to 1MHz or less. * * Mode transitions: * RUN -> VLPR * * exit_vlpr() function or an interrupt with LPWUI set can be used * to switch from VLPR back to RUN. The enable_lpwui() and disable_lpwui() * functions can be used to set LPWUI to the desired option prior to * calling enter_vlpr(). * * Parameters: * none */ void enter_vlpr(char lpwui_value) { if ((SMC_PMSTAT & SMC_PMSTAT_PMSTAT_MASK)== 4){ printf(" \n[enter_vlpr] Already in VLPR Mode ! "); return; } SMC_PMPROT = SMC_PMPROT_AVLP_MASK; // write oneif not all set make sure all enabled //this write-once bit allows the MCU to enter the //very low power modes: VLPR, VLPW, and VLPS. if(lpwui_value){ SMC_PMCTRL = SMC_PMCTRL_LPWUI_MASK | SMC_PMCTRL_RUNM(2); } else { SMC_PMCTRL = (~SMC_PMCTRL_LPWUI_MASK) & SMC_PMCTRL_RUNM(2); } /* Wait for VLPS regulator mode to be confirmed */ while((PMC_REGSC & PMC_REGSC_REGONS_MASK) ==0x04){ printf(" \n[enter_vlpr] Waiting on REGONS to clear ! "); } // 0 Regulator in stop Reg mode // 1 MCU is in Run regulation mode printf("[enter_vlpr] Now in VLPR at 19200 baud \r\n"); while((SMC_PMSTAT & SMC_PMSTAT_PMSTAT_MASK) != 4){ printf(" \n[enter_vlpr] HALT PMSTAT does not indicate in VLPR Mode ! "); } }
inline void enter_vlpr( void ) { if ( SMC_PMSTAT & SMC_PMSTAT_VLPR ) return; SMC_PMCTRL = SMC_PMCTRL_RUNM( 0 ); ( void ) SMC_PMCTRL; while( !( SMC_PMSTAT & SMC_PMSTAT_RUN ) ); SMC_PMCTRL = SMC_PMCTRL_RUNM( 2 ); ( void ) SMC_PMCTRL; // Wait for VLPS regulator mode to be confirmed while( ( PMC_REGSC & PMC_REGSC_REGONS ) ); // 0 Regulator in stop Reg mode // 1 MCU is in Run regulation mode while( !( SMC_PMSTAT & SMC_PMSTAT_VLPR ) ); }
inline void vlps( void ) { #if defined(__MK66FX1M0__) #if F_CPU > 120000000 kinetis_hsrun_disable( ); SMC_PMCTRL = SMC_PMCTRL_RUNM( 0x02 ) | SMC_PMCTRL_STOPM( 0x02 ); ( void ) SMC_PMCTRL; #else SMC_PMCTRL = SMC_PMCTRL_RUNM( 0x02 ) | SMC_PMCTRL_STOPM( 0x02 ); ( void ) SMC_PMCTRL; #endif #else SMC_PMCTRL = SMC_PMCTRL_STOPM( 0x02 ) ; ( void ) SMC_PMCTRL; #endif // Now execute the stop instruction to go into VLPS stop( ); }
static void SetPowerRegisters() { SMC->PMPROT = ((1<<SMC_PMPROT_AVLP_SHIFT)|SMC_PMPROT_AVLP_MASK)|((0<<SMC_PMPROT_AVLLS_SHIFT)|SMC_PMPROT_AVLLS_MASK);//allow low power modes to be entered via PMCTRL SMC->PMCTRL = SMC_PMCTRL_RUNM(2)|SMC_PMCTRL_STOPM(2);//run in VLPR mode, entering sleep will put us in VLPS mode return; }
inline void exit_vlpr( void ) { // check to make sure in VLPR before exiting if ( !( SMC_PMSTAT & SMC_PMSTAT_VLPR ) ) return; // Clear RUNM #if defined(__MK66FX1M0__) #if F_CPU > 120000000 SMC_PMCTRL = SMC_PMCTRL_RUNM( 0 ); ( void ) SMC_PMCTRL; while( !( SMC_PMSTAT & SMC_PMSTAT_RUN ) ); SMC_PMCTRL = SMC_PMCTRL_RUNM( 0x03 ); ( void ) SMC_PMCTRL; #else SMC_PMCTRL = SMC_PMCTRL_RUNM( 0x00 ); ( void ) SMC_PMCTRL; #endif #else SMC_PMCTRL = SMC_PMCTRL_RUNM( 0x00 ); ( void ) SMC_PMCTRL; #endif // Wait for normal RUN regulation mode to be confirmed // 0 MCU is not in run regulation mode // 1 MCU is in run regulation mode while( !( PMC_REGSC & PMC_REGSC_REGONS ) ); #if defined(__MK66FX1M0__) #if F_CPU > 120000000 while( !( SMC_PMSTAT & SMC_PMSTAT_HSRUN ) ); #else while( !( SMC_PMSTAT & SMC_PMSTAT_RUN ) ); #endif #else while( !( SMC_PMSTAT & SMC_PMSTAT_RUN ) ); #endif }
/* VLPR mode exit routine. Puts the processor into normal run mode * from VLPR mode. You can transition from VLPR to normal run using * this function or an interrupt with LPWUI set. The enable_lpwui() * and disable_lpwui() functions can be used to set LPWUI to the * desired option prior to calling enter_vlpr(). * * Mode transitions: * VLPR -> RUN * * Parameters: * none */ void exit_vlpr(void) { /* check to make sure in VLPR before exiting */ if ((SMC_PMSTAT & SMC_PMSTAT_PMSTAT_MASK)== 4) { /* Clear RUNM */ SMC_PMCTRL &= ~(SMC_PMCTRL_RUNM(0x3)); /* Wait for normal RUN regulation mode to be confirmed */ // 0 MCU is not in run regulation mode // 1 MCU is in run regulation mode while(!(PMC_REGSC & PMC_REGSC_REGONS_MASK)){ printf(" \n[exit_vlpr] Waiting on REGONS bit to set to indicate Run regulation mode ! "); } } //if in VLPR mode // else if not in VLPR ignore call }
inline void vlls0_nopor( void ) { #if defined(__MK66FX1M0__) #if F_CPU > 120000000 SMC_PMCTRL = SMC_PMCTRL_RUNM( 0x03 ) | SMC_PMCTRL_STOPM( 0x04 ); ( void ) SMC_PMCTRL; #else SMC_PMCTRL = SMC_PMCTRL_STOPM( 0x03 ) ; ( void ) SMC_PMCTRL; #endif #else SMC_PMCTRL = SMC_PMCTRL_STOPM( 0x03 ) ; ( void ) SMC_PMCTRL; #endif SMC_VLLSCTRL = SMC_VLLSCTRL_VLLSM( 0x00 );// set VLLSM = 0b00 ( void ) SMC_VLLSCTRL; // Now execute the stop instruction to go into VLLS0 #if defined(__MK66FX1M0__) kinetis_hsrun_enable( ); #endif }
/* VLPR mode entry routine.Puts the processor into very low power * run mode. In this mode all clocks are enabled, but the core clock limited. * The flash clock is limited to 1MHz or less. * * Mode transitions: * RUN -> VLPR * * exit_vlpr() function can be used * to switch from VLPR back to RUN. * * while in VLPR,VLPW or VLPS the exit to VLPR is not possible * * * Parameters: * Return value : PMSTAT value or error code * PMSTAT = return_value = PMSTAT * 000_0001 Current power mode is RUN * 000_0100 Current power mode is VLPR * ERROR Code = 0x14 - already in VLPR mode * = 0x24 - REGONS never clear indicating stop regulation */ int enter_vlpr(void) { int i; unsigned int return_value = 0; if ((SMC_PMSTAT & SMC_PMSTAT_PMSTAT_MASK)== 4){ return_value = 0x14; } /* The PMPROT register may have already been written by init code If so then this next write is not done. PMPROT is write once after RESET this write-once bit allows the MCU to enter the very low power modes: VLPR, VLPW, and VLPS */ SMC_PMPROT = SMC_PMPROT_AVLP_MASK; /* Set the (for MC1)LPLLSM or (for MC2)STOPM field to 0b010 for VLPS mode - and RUNM bits to 0b010 for VLPR mode */ SMC_PMCTRL &= ~SMC_PMCTRL_RUNM_MASK; SMC_PMCTRL |= SMC_PMCTRL_RUNM(0x2); /* Wait for VLPS regulator mode to be confirmed */ for (i = 0 ; i < 10000 ; i++) { /* check that the value of REGONS bit is not 0 once it is a zero we can stop checking */ if ((PMC_REGSC & PMC_REGSC_REGONS_MASK) ==0x04){ /* 0 Regulator is in stop regulation or in transition to/from it 1 MCU is in Run regulation mode */ } else break; } if ((PMC_REGSC & PMC_REGSC_REGONS_MASK) ==0x04) { return_value = 0x24; } /* SMC_PMSTAT register only exist in Mode Controller 2 MCU versions */ if ((SMC_PMSTAT & SMC_PMSTAT_PMSTAT_MASK) == 4) { return_value = SMC_PMSTAT; } return (return_value); }
bool _lpm_idle_sleep_check ( void ) { _mqx_uint pmctrl, stop; pmctrl = SMC_PMCTRL; stop = SIM_SOPT4 & (SIM_SOPT4_WAITE_MASK | SIM_SOPT4_STOPE_MASK); /* Idle sleep is available only in normal RUN/WAIT and VLPR/VLPW with LPWUI disabled */ if (((SIM_SOPT4_WAITE_MASK | SIM_SOPT4_STOPE_MASK) == stop) && (0 == (pmctrl & SMC_PMCTRL_STOPM_MASK)) && (! ((SMC_PMCTRL_LPWUI_MASK | SMC_PMCTRL_RUNM(2)) == (pmctrl & (SMC_PMCTRL_LPWUI_MASK | SMC_PMCTRL_RUNM_MASK))))) { return TRUE; } return FALSE; }
SMC_PMCTRL_LPWUI_MASK, // Mode PMCTRL register == voltage regulator ON after wakeup 0, // Mode flags == clear settings }, // WAIT { SMC_PMCTRL_LPWUI_MASK, // Mode PMCTRL register == voltage regulator ON after wakeup LPM_CPU_POWER_MODE_FLAG_WAITE, // Mode flags == execute WFI }, // STOP { SMC_PMCTRL_LPWUI_MASK, // Mode PMCTRL register == voltage regulator ON after wakeup LPM_CPU_POWER_MODE_FLAG_STOPE, // Mode flags == deepsleep, execute WFI }, // VLPR { SMC_PMCTRL_RUNM(2), // Mode PMCTRL register == VLPR 0, // Mode flags == clear settings }, // VLPW { SMC_PMCTRL_RUNM(2), // Mode PMCTRL register == VLPW LPM_CPU_POWER_MODE_FLAG_WAITE, // Mode flags == execute WFI }, // VLPS { SMC_PMCTRL_STOPM(2), // Mode PMCTRL register == VLPS LPM_CPU_POWER_MODE_FLAG_STOPE, // Mode flags == deepsleep, execute WFI }, // LLS { SMC_PMCTRL_LPWUI_MASK | SMC_PMCTRL_STOPM(4), // Mode PMCTRL register == voltage regulator ON after wakeup, LLS
SMC_PMCTRL_LPWUI_MASK, /* Mode PMCTRL register == voltage regulator ON after wakeup*/ 0, /* Mode flags == clear settings*/ }, /* Kinetis WAIT*/ { SMC_PMCTRL_LPWUI_MASK, /* Mode PMCTRL register == voltage regulator ON after wakeup*/ LPM_CPU_POWER_MODE_FLAG_USE_WFI, /* Mode flags == execute WFI*/ }, /* Kinetis STOP*/ { SMC_PMCTRL_LPWUI_MASK, /* Mode PMCTRL register == voltage regulator ON after wakeup*/ LPM_CPU_POWER_MODE_FLAG_DEEP_SLEEP | LPM_CPU_POWER_MODE_FLAG_USE_WFI, /* Mode flags == deepsleep, execute WFI*/ }, /* Kinetis VLPR*/ { SMC_PMCTRL_RUNM(2), /* Mode PMCTRL register == VLPR*/ 0, /* Mode flags == clear settings*/ }, /* Kinetis VLPW*/ { SMC_PMCTRL_RUNM(2), /* Mode PMCTRL register == VLPW*/ LPM_CPU_POWER_MODE_FLAG_USE_WFI, /* Mode flags == execute WFI*/ }, /* Kinetis VLPS*/ { SMC_PMCTRL_STOPM(2), /* Mode PMCTRL register == VLPS*/ LPM_CPU_POWER_MODE_FLAG_DEEP_SLEEP | LPM_CPU_POWER_MODE_FLAG_USE_WFI, /* Mode flags == deepsleep, execute WFI*/ }, /* Kinetis LLS*/ { SMC_PMCTRL_LPWUI_MASK | SMC_PMCTRL_STOPM(3), /* Mode PMCTRL register == voltage regulator ON after wakeup, LLS*/
/*---------------------------------------------------------------------------- MAIN function *----------------------------------------------------------------------------*/ int main (void) { #if USE_VLPR == 1 // enter low power run SIM->CLKDIV1 = (0x1 << SIM_CLKDIV1_OUTDIV1_SHIFT) | (0x5 << SIM_CLKDIV1_OUTDIV4_SHIFT); // reduce core clock < 4 MHz and flash < 1 MHz MCG->C6 &= ~MCG_C6_CME0_MASK; // disable MCG clock monitor MCG->C2 |= MCG_C2_IRCS_MASK; // don't use slow internal reference clock MCG->C1 |= MCG_C1_CLKS(2); // enter BLPE mode MCG->C1 &= ~MCG_C1_IREFS_MASK; MCG->C6 &= ~MCG_C6_PLLS_MASK; while(!(MCG->S & MCG_S_IREFST_MASK >> MCG_S_IREFST_SHIFT)); // wait to ensure clock change MCG->C2 |= MCG_C2_LP_MASK; #endif Init_RGB_LEDs(); #if DEBUG_SIGNALS == 1 Init_Debug_Signals(); #endif // I2C and MMA i2c_init(); /* init i2c */ if (!init_mma()) { /* init mma peripheral */ Control_RGB_LEDs(1, 0, 0); /* Light red error LED */ while (1) /* not able to initialize mma */ ; } #if RUN_I2C_FAST == 1 // increase i2c baud rate I2C_DISABLE; I2C0->F = (I2C_F_ICR(0x00) | I2C_F_MULT(0)); I2C_ENABLE; #endif // configure low power modes SMC->PMPROT = SMC_PMPROT_ALLS_MASK | SMC_PMPROT_AVLP_MASK; // allow low leakage stop mode SMC->PMCTRL = SMC_PMCTRL_RUNM(2) | SMC_PMCTRL_STOPM(3); // enable low power run mode (10) and low leakage stop mode (011) SMC->STOPCTRL = SMC_STOPCTRL_PSTOPO(0) | SMC_STOPCTRL_VLLSM(3); // normal stop mode and VLL stop3 (not needed?) // configure low leakage wakeup unit (LLWU) LLWU->ME |= LLWU_ME_WUME0_MASK; // internal module 0 is wakeup source which is apparently the LPTMR // enable stop mode (deep sleep) SCB->SCR |= SCB_SCR_SLEEPDEEP_Msk; // LPTMR Init_LPTMR(); Start_LPTMR(); __enable_irq(); while (1) { // read acceleration every 100 ms if (run_Read_Accel){ run_Read_Accel = 0; Read_Accel(); } // update LEDs every 500 ms; keep them on for 10 ms if (run_Update_LEDs){ run_Update_LEDs = 0; Update_LEDs(); #if USE_PWM == 1 #if PWM_SLEEP == 1 SCB->SCR &= ~SCB_SCR_SLEEPDEEP_Msk; // switch to regular sleep mode #if USE_SLEEP_MODES == 1 #if DEBUG_SIGNALS == 1 PTE->PSOR |= MASK(30); #endif __wfi(); // PWM does not work in LLS mode #endif SCB->SCR |= SCB_SCR_SLEEPDEEP_Msk; // switch back to LLS mode #else while(led_on_period); // poll -> bad solution #endif #endif } #if USE_SLEEP_MODES == 1 #if DEBUG_SIGNALS == 1 PTE->PSOR |= MASK(30); #endif __wfi(); // go to sleep #endif } }
/* ** =================================================================== ** Method : Cpu_SetOperationMode (component MK22FN512VDC12) ** ** Description : ** This method requests to change the component's operation ** mode (RUN, WAIT, SLEEP, STOP). The target operation mode ** will be entered immediately. ** See <Operation mode settings> for further details of the ** operation modes mapping to low power modes of the cpu. ** Parameters : ** NAME - DESCRIPTION ** OperationMode - Requested driver ** operation mode ** ModeChangeCallback - Callback to ** notify the upper layer once a mode has been ** changed. Parameter is ignored, only for ** compatibility of API with other components. ** * ModeChangeCallbackParamPtr ** - Pointer to callback parameter to notify ** the upper layer once a mode has been ** changed. Parameter is ignored, only for ** compatibility of API with other components. ** Returns : ** --- - Error code ** ERR_OK - OK ** ERR_PARAM_MODE - Invalid operation mode ** =================================================================== */ LDD_TError Cpu_SetOperationMode(LDD_TDriverOperationMode OperationMode, LDD_TCallback ModeChangeCallback, LDD_TCallbackParam *ModeChangeCallbackParamPtr) { (void) ModeChangeCallback; /* Parameter is not used, suppress unused argument warning */ (void) ModeChangeCallbackParamPtr; /* Parameter is not used, suppress unused argument warning */ switch (OperationMode) { case DOM_HSRUN: SMC_PMPROT = SMC_PMPROT_AHSRUN_MASK; SMC_PMCTRL |= SMC_PMCTRL_RUNM(3); /*HS RUN */ while((SMC_PMSTAT & SMC_PMSTAT_PMSTAT_MASK) != SMC_PMSTAT_PMSTAT(0x80)) { /* HS RUN status */ }; /* SCB_SCR: SLEEPDEEP=0,SLEEPONEXIT=0 */ SCB_SCR &= (uint32_t)~(uint32_t)( SCB_SCR_SLEEPDEEP_MASK | SCB_SCR_SLEEPONEXIT_MASK ); if (ClockConfigurationID != 2U) { if ((MCG_S & MCG_S_CLKST_MASK) != MCG_S_CLKST(3)) { /* If in PBE mode, switch to PEE. PEE to PBE transition was caused by wakeup from low power mode. */ /* MCG_C1: CLKS=0,IREFS=0 */ MCG_C1 &= (uint8_t)~(uint8_t)((MCG_C1_CLKS(0x03) | MCG_C1_IREFS_MASK)); while( (MCG_S & MCG_S_LOCK0_MASK) == 0x00U) { /* Wait for PLL lock */ } } } break; case DOM_RUN: SMC_PMCTRL &= ~(SMC_PMCTRL_RUNM(3)); /*Normal RUN */ while((SMC_PMSTAT & SMC_PMSTAT_PMSTAT_MASK) != SMC_PMSTAT_PMSTAT(0x1)) { /* Normal RUN status */ }; /* SCB_SCR: SLEEPDEEP=0,SLEEPONEXIT=0 */ SCB_SCR &= (uint32_t)~(uint32_t)( SCB_SCR_SLEEPDEEP_MASK | SCB_SCR_SLEEPONEXIT_MASK ); if (ClockConfigurationID != 2U) { if ((MCG_S & MCG_S_CLKST_MASK) != MCG_S_CLKST(3)) { /* If in PBE mode, switch to PEE. PEE to PBE transition was caused by wakeup from low power mode. */ /* MCG_C1: CLKS=0,IREFS=0 */ MCG_C1 &= (uint8_t)~(uint8_t)((MCG_C1_CLKS(0x03) | MCG_C1_IREFS_MASK)); while( (MCG_S & MCG_S_LOCK0_MASK) == 0x00U) { /* Wait for PLL lock */ } } } break; case DOM_WAIT: /* SCB_SCR: SLEEPDEEP=0 */ SCB_SCR &= (uint32_t)~(uint32_t)(SCB_SCR_SLEEPDEEP_MASK); /* SCB_SCR: SLEEPONEXIT=0 */ SCB_SCR &= (uint32_t)~(uint32_t)(SCB_SCR_SLEEPONEXIT_MASK); PE_WFI(); break; case DOM_SLEEP: /* SCB_SCR: SLEEPDEEP=1 */ SCB_SCR |= SCB_SCR_SLEEPDEEP_MASK; /* SMC_PMCTRL: STOPM=0 */ SMC_PMCTRL &= (uint8_t)~(uint8_t)(SMC_PMCTRL_STOPM(0x07)); (void)(SMC_PMCTRL == 0U); /* Dummy read of SMC_PMCTRL to ensure the register is written before enterring low power mode */ /* SCB_SCR: SLEEPONEXIT=1 */ SCB_SCR |= SCB_SCR_SLEEPONEXIT_MASK; PE_WFI(); break; case DOM_STOP: break; default: return ERR_PARAM_MODE; } return ERR_OK; }
SMC_PMCTRL_LPWUI_MASK, // Mode PMCTRL register == voltage regulator ON after wakeup 0, // Mode flags == clear settings }, // WAIT { SMC_PMCTRL_LPWUI_MASK, // Mode PMCTRL register == voltage regulator ON after wakeup LPM_CPU_POWER_MODE_FLAG_WAITE, // Mode flags == execute WFI }, // STOP { SMC_PMCTRL_LPWUI_MASK, // Mode PMCTRL register == voltage regulator ON after wakeup LPM_CPU_POWER_MODE_FLAG_STOPE, // Mode flags == deepsleep, execute WFI }, // VLPR { SMC_PMCTRL_RUNM(2), // Mode PMCTRL register == VLPR 0, // Mode flags == clear settings }, // VLPW { SMC_PMCTRL_RUNM(2), // Mode PMCTRL register == VLPW LPM_CPU_POWER_MODE_FLAG_WAITE, // Mode flags == execute WFI }, // VLPS { SMC_PMCTRL_RUNM(2), // Mode PMCTRL register == VLPS LPM_CPU_POWER_MODE_FLAG_STOPE, // Mode flags == deepsleep, execute WFI }, // LLS { SMC_PMCTRL_LPWUI_MASK | SMC_PMCTRL_RUNM(3), // Mode PMCTRL register == voltage regulator ON after wakeup, LLS