ee-quipment/ZeroPowerManager

I think there is a need to turn off systick interrupts during sleep

Opened this issue · 2 comments

I found that without the mod for SysTick, the system from time to time will hang (perhaps one time out of a thousand) at least for the code I was running. There is an errata in the ATSAMD21 datasheet that confirms that systick interrupts needs to be disabled during sleep.

void zpmSleep(void) {
NVMCTRL->CTRLB.bit.SLEEPPRM = NVMCTRL_CTRLB_SLEEPPRM_DISABLED_Val; //cth - make sure FLASH does not pwoer all the way down in sleep
SysTick->CTRL &= ~SysTick_CTRL_TICKINT_Msk; //cth to fix hangs
SCB->SCR |= SCB_SCR_SLEEPDEEP_Msk;
PM->SLEEP.reg = 2; //idle mode
__DSB();
__WFI();
SysTick->CTRL |= SysTick_CTRL_TICKINT_Msk; //restore
}

I found that without the mod for SysTick, the system from time to time will hang (perhaps one time out of a thousand) at least for the code I was running. There is an errata in the ATSAMD21 datasheet that confirms that systick interrupts needs to be disabled during sleep.

void zpmSleep(void) { NVMCTRL->CTRLB.bit.SLEEPPRM = NVMCTRL_CTRLB_SLEEPPRM_DISABLED_Val; //cth - make sure FLASH does not pwoer all the way down in sleep SysTick->CTRL &= ~SysTick_CTRL_TICKINT_Msk; //cth to fix hangs SCB->SCR |= SCB_SCR_SLEEPDEEP_Msk; PM->SLEEP.reg = 2; //idle mode __DSB(); __WFI(); SysTick->CTRL |= SysTick_CTRL_TICKINT_Msk; //restore }

Chris -

Thank you for taking the time to diagnose/document/fix this issue. It's been a while since I've looked at this code so I may need you to guide me through this a little.

So that we are both on the same page, I assume this is the errata you are referring to?
1.5.7 Potential Lockup on Standby Entry
When the Systick interrupt is enabled, a device lockup can occur when the Systick interrupt coincides with the
standby entry.
Workaround
Disable the Systick interrupt before entering standby and re-enable it after wake up.

I agree, this could certainly be a problem.

So far, I understand disabling/re-enabling the systick interrupt in your code.
SysTick->CTRL &= ~SysTick_CTRL_TICKINT_Msk; //cth to fix hangs
SysTick->CTRL |= SysTick_CTRL_TICKINT_Msk; //restore

I'm not clear on why you added this.
PM->SLEEP.reg = 2; //idle mode
My understanding is that setting SLEEPDEEP supercedes this. I experimented with the idle modes back when I wrote this and found they don't really make much of a difference in power consumption.

This leaves powering down the flash.
NVMCTRL->CTRLB.bit.SLEEPPRM = NVMCTRL_CTRLB_SLEEPPRM_DISABLED_Val; //cth - make sure FLASH does not pwoer all the way down in sleep
Is this because of errata 1.5.8 ?

Potential Lockup on Standby Wakeup with Arm Core PRIMASK=1
Upon wake up from standby with Arm Core register PRIMASK = 1, the first instruction fetched by the CPU in
Flash memory will be the first instruction following the WFI. This instruction may be returned corrupted and lead to
unpredictable behavior.
If PRIMASK = 0, the first instruction fetched by the CPU will be the first instruction of the interrupt handler. This one
will be correctly returned to the CPU.

I believe we are okay here because we only exit sleep through an interrupt and so PRIMASK must be 0 unless we are catching an NMI. So, I guess to be safe we would need to keep the flash from sleeping. I would like to make some measurements before making this the default configuration. I was quite pleased with achieving 6 uA of sleep current and if keeping the flash ouf of sleep is going to make a significant difference maybe make an NMI sleep function and a non-NMI function.

Let me know your thoughts on this and thanks again.