Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

System.sleep() fails with small values of seconds #1043

Closed
embedded-creations opened this issue Jun 22, 2016 · 6 comments · Fixed by #1051

Comments

@embedded-creations
Copy link
Contributor

commented Jun 22, 2016

With the addition of calls to network_* in system_sleep(), it now can take more than a few seconds from calling system_sleep() to actually entering the sleep mode. The HAL_RTC_Set_UnixAlarm() call is made before the network_* calls, so for small values of seconds, the RTC alarm will go off before calling HAL_Core_Enter_Standby_Mode() and entering the sleep mode. The end result is that you can call System.sleep() with a non-zero value for seconds and it will sleep indefinitely.

Here's some demo code (I used 0.5.1 local build to compile) to reproduce this issue, and what I see from my terminal with an Electron running 0.5.1 firmware before it goes to sleep and doesn't wake up. I'm only using Deep Sleep in my application so I haven't tested behavior with other sleep modes.

https://gist.github.com/embedded-creations/0c22db0f5deddd4f30bc2652ae0e1261

[Reconnected]
connected, going to sleep for 10 seconds

[Closed]

[Reconnected]
connected, going to sleep for 9 seconds

[Closed]

[Reconnected]
connected, going to sleep for 8 seconds

[Closed]

[Reconnected]
connected, going to sleep for 7 seconds

[Closed]

[Reconnected]
connected, going to sleep for 6 seconds

[Closed]

[Reconnected]
connected, going to sleep for 5 seconds

[Closed]

The minimum seconds value needed is variable, I found during one test run of this code that it failed (slept indefinitely) with a sleep value of 10 seconds.

An easy fix might be to make the HAL_RTC_Set_UnixAlarm() call right before entering the sleep mode, but that does change the function's behavior, adding some variable amount of time to the total time between calling System.sleep() and waking. A more complicated fix might keep track of the time spent in the function before sleeping.


Completeness:

  • Minimum test case added
  • Device, system and user firmware versions stated
  • Particle confirmed
@embedded-creations

This comment has been minimized.

Copy link
Contributor Author

commented Jun 29, 2016

It looks like this was updated to be "Particle confirmed" a few days ago, though I would have appreciated even a brief followup message so I could get a notification that someone was looking into this.

I've been doing some more research on the issue as my workarounds of setting a minimum value for seconds before going to deep sleep have been failing. I first tried a minimum value of 30 seconds in my application code, which failed, then increased it to 60 seconds (which also failed).

Looking through the system_sleep() code, when using Deep Sleep, there is always going to be a call to network_suspend() first. I can't call network_suspend() directly from an application, but I can use System.sleep(SLEEP_MODE_WLAN, 60) to call it indirectly without calling the other network_ functions.

I setup two test Electrons to connect to the cloud, and record the time elapsed to call each System.sleep(SLEEP_MODE_WLAN, 60), network_disconnect(0, 0, NULL); and network_off(0, 0, 0, NULL); in that order. One Electron is set to do a Particle.publish() directly after connecting, the other doesn't publish.

After letting both run overnight, the time it takes to call network_disconnect(0, 0, NULL); and network_off(0, 0, 0, NULL); was always 0 seconds. On the Electron that is not doing a publish, the max time to call System.sleep(SLEEP_MODE_WLAN, 60) was 18 seconds. On the Electron that is doing a publish the max time to call System.sleep(SLEEP_MODE_WLAN, 60) was 192 seconds.

Hopefully you can see this is undesirable behavior in two ways: it gives the user less control over battery usage if their Electron may stay awake an extra >3 minutes after telling it to sleep, and it may sleep indefinitely if they tell it to sleep for a "small" number of seconds (currently 192 seconds).

My current workaround in my application is to manually call network_disconnect(0, 0, NULL); and network_off(0, 0, 0, NULL); before entering Deep Sleep. I haven't traced through the code but I believe this will skip over any network_ calls in system_sleep() so the processor enters sleep mode quickly. Please let me know if you have any feedback on this workaround.

Here's the code I used for the test. You can change the #define on line 34 to set if the publish is used or not. That's the only difference between the two versions of code I used.

https://gist.github.com/embedded-creations/9c8b5c17b5de6e629c319433bd872e7a

@avtolstoy

This comment has been minimized.

Copy link
Member

commented Jun 29, 2016

@embedded-creations Thanks for additional info!
I thought I wrote a reply after looking through code, sorry for silently confirming this :) There was a similar issue with STOP mode that was fixed in #797, and the same fix wasn't applied to DEEP_SLEEP which is an oversight.

I'm currently looking into this and another System.sleep issue (#1029).

Thanks!

@embedded-creations

This comment has been minimized.

Copy link
Contributor Author

commented Jun 29, 2016

Great! Let me know if you need any more tests run. I seem to be in an area with not the best coverage. I had an electron enter listening mode last night, and another couldn't make a connection in under 90 seconds after many hours of trying last night.

@avtolstoy avtolstoy self-assigned this Jun 29, 2016

@embedded-creations

This comment has been minimized.

Copy link
Contributor Author

commented Jun 30, 2016

My workaround doesn't work: even after calling network_disconnect(0, 0, NULL); and network_off(0, 0, 0, NULL);, the call to network_process() can take a long time. The max I measured was 211 seconds. I assume that even when the network is disconnected and modem is off, calling system_sleep() with an unsent message can cause the modem to turn on and reconnect in an attempt to deliver the message before going to sleep.

My other workaround which I've been testing in parallel is to set a flag in retained memory, reset the Electron, call Cellular.on() early in setup() after seeing the flag is set (so that the firmware knows the modem needs to be turned off before sleeping), then calling System.sleep(SLEEP_MODE_DEEP, seconds). I'm currently calling network_disconnect(0, 0, NULL); and network_off(0, 0, 0, NULL); before System.sleep(SLEEP_MODE_DEEP, seconds) but I think that's unnecessary. Anyway, this workaround is complicated, but it's been working across three Electrons, each reporting roughly every three minutes for 24 hours, with 30 second sleep cycles.

I updated the Gist. The code with Line 56 enabled is what I used to measure the max of 211 seconds.

@avtolstoy avtolstoy referenced this issue Jun 30, 2016
6 of 7 tasks complete
@avtolstoy

This comment has been minimized.

Copy link
Member

commented Jun 30, 2016

@embedded-creations This should be fixed in PR #1051!

@embedded-creations

This comment has been minimized.

Copy link
Contributor Author

commented Jul 1, 2016

@avtolstoy Great! Looks like a good fix.

I'll either open a new issue or start discussing the "system_sleep() takes as long as 3.5 minutes to sleep" issue in the community so you can close this issue as needed.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
3 participants
You can’t perform that action at this time.