nxf56274
mjbcswitzerland
Da Li,
I used the power_mode_switch example for my code - I used all of the flow for configuration of the SMC, LLWU pin for wakeup, and entry into LLS mode. I'm not using a FRDM board, so I will have to see if I can modify the project to work with my PCB.
Mark,
I included the LLWU setup code in my previous reply just to show that the pin was set correctly for waking from LLS, I get that it doesn't affect LLS entry.
Regarding the code snippet you included:
I confirmed that PMPROT is being set correctly. Reading the register directly before LLS entry shows that it is set to 0xAA, which per the reference manual means that HSRUN, VLP, VLLS, and LLS modes are allowed. In any case, I believe that if I tried to enter into a dis-allowed power mode the STOPA stop abort bit would be getting set when the PMCTRL stop mode control bits were set, and I'm not seeing that.
Digging into the SMC_SetPowerModeLls() function from the SDK, it is basically following the code you posted. Your code explicitly sets the run mode control bits to run, and the stop mode bits to LLS, where the the SetPowerMode code just keeps the current run mode bits and sets the stop mode bits to LLS.
Next, it sets the SCR SLEEPDEEP bit, again so far so good.
Finally, it calls the SMC_EnterStopModeRamFunc. This one confused me for a second, but it's actually pretty clever. According to the comments, entering a stop mode can cause pre-fetched instructions or data from flash to become corrupted, so as a workaround, it loads and then executes a short assembly routine from RAM.
/*
* The ram function code is:
*
* uint32_t i;
* for (i=0; i<0x8; i++)
* {
* __NOP();
* }
* __DSB();
* __WFI();
* __ISB();
*
* When entring the stop modes, the flash prefetch might be interrupted, thus
* the prefetched code or data might be broken. To make sure the flash is idle
* when entring the stop modes, the code is moved to ram. And delay for a while
* before WFI to make sure previous flash prefetch is finished.
*
* Only need to do like this when code is in flash, if code is in rom or ram,
* this is not necessary.
*/
static uint16_t s_stopRamFuncArray[] = {
0x2000, /* MOVS R0, #0 */
0x2808, /* CMP R0, #8 */
0xD202, /* BCS.N */
0xBF00, /* NOP */
0x1C40, /* ADDS R0, R0, #1 */
0xE7FA, /* B.N */
0xF3BF, 0x8F4F, /* DSB */
0xBF30, /* WFI */
0xF3BF, 0x8F6F, /* ISB */
0x4770, /* BX LR */
};
/*******************************************************************************
* Code
******************************************************************************/
static void SMC_EnterStopRamFunc(void)
{
uint32_t ramFuncEntry = ((uint32_t)(s_stopRamFuncArray)) + 1U;
smc_stop_ram_func_t stopRamFunc = (smc_stop_ram_func_t)ramFuncEntry;
stopRamFunc();
}
The routine just loops a NOP until flash should be idle, then executes a WFI instruction.
Finally, the function checks the PMCTRL register for the STOPA stop abort bit to see if entry into the stop mode was aborted, presumably in the case that the stop mode was not one of the allowed power modes per the PMPROT register settings. This is returning no error, and I verified by manually checking PMCTRL. STOPA is a read only register that is persistent until the next time you write the stop mode control bits.
So, it looks like the SDK is already doing everything you suggested, although with a little fancy detour for running the subroutine from RAM to prevent flash corruption.
Just to see if there was something funny going on with the SDK code, I commented it all out and went with your suggested snippet.
I had to modify it a little, because I apparently don't have the same defines you used.
SMC->PMCTRL = 0x03;
SCB->SCR |= SCB_SCR_SLEEPDEEP_Msk;
asm("wfi");
The PMPROT register is being written right after power up, so I omitted it from the code above. Setting PMCTRL to 0x03 just configures the run mode bits for normal run mode, and the sleep mode bits for LLS. SCB_SCR_SLEEPDEEP_Msk is defined as 0x04, which is correct according to the Cortex M4 user guide.
Cortex-M4 Devices Generic User Guide | System Control Register – Arm Developer
I'm getting the same behavior - no sleep. I'm a little stumped at this point. If you want to shoot me that binary, I'm using UART0 - RX on pin 23, TX on pin 24. My wakeup pin is LLWU 3, pin 26 on the package. Again, my part is MK22FN256VLH12, the LQFP 64 package.
Thanks,
Devin