arduino-libraries / ArduinoLowPower

Powersave features for SAMD boards
GNU Lesser General Public License v2.1
81 stars 57 forks source link

Fix SysTick timer lockup when waking from sleep #17

Closed sslupsky closed 5 years ago

sslupsky commented 5 years ago

While researching some low power issues I came across a discussion regarding a situation that can lead to a lockup and hard fault when waking from sleep. The issue is discussed on this AVRFreaks thread:

https://www.avrfreaks.net/forum/samd21-samd21e16b-sporadically-locks-and-does-not-wake-standby-sleep-mode

Microchip has acknowledged to problem:

We have identified the issue with WDT reset. It happens due to SysTick timer.

Issue is that WDT initiates the wake up, but then SysTick interrupt starts to get handled first before system is actually ready. Basically, what happens is that SysTick interrupt does not wait for the RAM to properly wake up from sleep.

So if you wake up from WDT, the system will wait for the RAM, but the core clock will actually be running, so SysTick interrupt may happen too. SysTick interrupt does not wait on the RAM, so the core attempts to run the SysTick handler and fails, since RAM is not ready. This causes a Hard Fault (in our testing SRAM is so slow to wake up even Hard Fault handler).

This mean that device wakes up, getting into the Hard Fault, stay there until WDT fully expires.

You can reproduce the issue quicker by running SysTick timer faster, and WDT wake ups also quicker.

The solution for the customer is to disable SysTick interrupt before going to sleep and enable it back after the sleep.

// Disable systick interrupt
SysTick->CTRL &= ~SysTick_CTRL_TICKINT_Msk;
// Deep sleep
sleepmgr_sleep(SLEEPMGR_STANDBY);
// Enable systick interrupt
SysTick->CTRL |= SysTick_CTRL_TICKINT_Msk;

The attached PR includes these changes to the sleep() method.

facchinm commented 5 years ago

LGTM! Merging, thanks for the contribution!