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

There is a use case for a fast deep sleep feature #1776

Closed
eyaleb opened this issue Feb 3, 2017 · 9 comments
Closed

There is a use case for a fast deep sleep feature #1776

eyaleb opened this issue Feb 3, 2017 · 9 comments

Comments

@eyaleb
Copy link

eyaleb commented Feb 3, 2017

Missing feature

Ability to enter dsleep quickly.

Justification

I have an app that completes in under 500ms. node.dsleep() takes about 100ms extra which is a significant cost in battery power.

I now added a node.dsleepInstant() lua function with an implementation that is almost identical to node.dsleep(). I copied node.c:node_deepsleep() except for this small change:

      system_deep_sleep( us );
is replaced with
      {
        void system_deep_sleep_instant(uint32 time_in_us);
        system_deep_sleep_instant( us );
      }

Deep sleep is entered in 1-2ms and uses the same low power.

This feature is documented in section 4.5 of 9b-esp8266_low_power_solutions_en.pdf.

BTW, I wonder if the rtctime module, which has a private fast dsleep routine, can use this feature too.

@eyaleb
Copy link
Author

eyaleb commented Feb 8, 2017

Anyone? I need this feature so I now use a modified node.c, however I feel that this small addition is of use for anyone attempting an optimised low power app.

@jmattsson
Copy link
Member

Ooh, interesting stuff! I don't see any discussion of what the potential draw-backs are of using the instant version, have you found any more information on that? I would guess there'd be something about not leaving the WiFi nicely or some such.

I'd certainly be in favour of getting this feature merged in. Could I suggest making it an optional third argument so we get node.dsleep(us, opt, instant)?

@eyaleb
Copy link
Author

eyaleb commented Feb 8, 2017

I would guess there'd be something ... or some such.

Yes, using the instant variety means the caller is responsible to not have processes in flight. For example, when my app runs in verbose mode I delay the instant deep sleep by 5ms to ensure the last message shows on the console.

Could I suggest making it an optional third argument so we get node.dsleep(us, opt, instant)?

Looks good, and we should allow a nil opt value (I think we already do).

@NicolSpies
Copy link

A slightly off the topic observation. The other two sleep modes (modem and light) detailed in the Espressif solutions document are exposed in wifi.sta.sleeptype().

It appears as if the light sleep external GPIO wakeup definition is not exposed. This does not the affect node.dsleep() external wakeup activated via the RST pin.

@jmattsson
Copy link
Member

@eyaleb I finally had some time to sit down with this, only to realise that my ESP8266 board here at home isn't wired to support deep sleep... ./facepalm

So, here is a completely untested branch which supports node.dsleep(<us>, <opt>, 1) for instant deep sleep. Please give it a try; I won't raise a PR until someone ok's it since I haven't tested it myself.

@eyaleb
Copy link
Author

eyaleb commented Mar 11, 2017

I will test it (timing and power), but for starters we do need an explicit prototype added:

      if (instant) {
        void system_deep_sleep_instant(uint32 time_in_us);
        system_deep_sleep_instant(us);
      } else
        system_deep_sleep( us );

The test program (sleep 2s in a loop):

gpio.mode (1, gpio.INPUT, gpio.PULLUP)  -- gpio5 = D1
if 0 == gpio.read (1) then
        print ("aborting by magic")
else
        local code, reason = node.bootreason()
        print(("code %d, reason %d"):format(code, reason))
        tmr.alarm(1, 5, tmr.ALARM_SINGLE, function()
                node.dsleep(2*1000000, 4, 1)     -- no WiFi
        end)
end

[later] First thing, I see we have the correct boot reason now REASON_DEEP_SLEEP_AWAKE = 5. Good.

NodeMCU 2.0.0 build dev-20170311-2305-512k-ow-jm powered by Lua 5.1.4 on SDK 2.0.0(656edbf)
code 2, reason 5

[even later] Power usage of instant is the same as normal dsleep. Good.

Timing is as expected. The test program is active (using a DSO) around 300ms with normal dsleep, and about 200ms with the instant. Good.

@jmattsson
Copy link
Member

Thanks for the testing!

We do have a function prototype - look in sdk-overrides/include/user_interface.h.

Since you have a DSO available, would you mind adding a gpio output to the test? Just set it high at the start, then pull it low right before node.dsleep(). If you probe that line together with power (which I assume is what you're doing?), you should get a decent reading on just how much time the "instant" function really takes.

@eyaleb
Copy link
Author

eyaleb commented Mar 12, 2017

@jmattsson RE prototype, OK. I grabbed only node.c to avoid other distractions, so my bad.

Here is the new program.

gpio.mode (1, gpio.INPUT, gpio.PULLUP)          -- gpio5 = D1
if 0 == gpio.read (1) then
        print ("aborting by magic")
else
        local out_pin = 5                       -- gpio14 = D5
        gpio.mode (out_pin, gpio.OUTPUT)
        gpio.write(out_pin, gpio.LOW)           -- short bleep
        gpio.write(out_pin, gpio.HIGH)

        local code, reason = node.bootreason()
        print(("code %d, reason %d"):format(code, reason))
        tmr.alarm(1, 5, tmr.ALARM_SINGLE, function()
                gpio.write(out_pin, gpio.LOW)   -- dsleep start
                node.dsleep(2*1000000,4, 0)     -- no WiFi
        end)
end

Presented here are two traces for the modified program. There are two low bleeps in each trace. The first, very short one marks the program start, the second (long) is the dsleep preparation. When deep sleep finally starts the pin goes high.

The program imposes a 5ms delay before the dsleep starts to allow the print to show (not important this time).

A standard (slow) test. Note the scale is 20ms/div so dsleep takes just over 100ms to start.

dev-jm-dsleep-slow

Now a test with an instant dsleep. The scale is 2ms/div and dsleep starts in under 3ms.

dev-jm-dsleep-fast

@eyaleb eyaleb closed this as completed Mar 12, 2017
@eyaleb eyaleb reopened this Mar 12, 2017
@jmattsson
Copy link
Member

Great, thanks! I'll do a PR right away then :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

4 participants