Figure out what woke the device up

I’m working on an application that is supposed to use the deep sleep mode of the Imp and wait for wake up on pin 1, then do some work, then go back to sleep. It’s also supposed to wake up every 2 hours or so and just say “hi” to the server (to make sure it’s not dead).

It all works fine, it wakes up when pin 1 goes high as well as after 2 hours, but how do I tell the two events apart? The signal on pin 1 is quite short so by the time the Imp boots up and loads its firmware, it’s back to low. There’s also a third case when the Imp has just booted up (due to a power failure or something).

How do I detect these three situations (cold boot due to lost power, wake up due to RTC and wake up due to pin 1 going high) to handle them differently?

Boot time will be significantly improved in the future (wifi won’t come up by default, so code should be running in tens of milliseconds from a wake) but the real solution is for us to tell you why we woke.

I believe we have a way to do this and there’s a feature request filed. We already know when we’ve cold booted, we just haven’t exposed this to squirrel yet. A workaround for the cold boot detection is to store something in the “nv” table (which is stored in the SRAM which is lost on card removal) and look for it at boot.

Unfortunately this is one of the very few instances where the underlying hardware doesn’t do quite what we want. The imp knows when it’s been woken by a timer, but it doesn’t specifically know when it’s been woken by Pin 1 – so, if both happen at once (or within the window between the first event and the code running), the Pin 1 event is lost. There are steps we can take to minimise the size of that window, but it can’t be completely eliminated.

Peter

We’ll characterize the possible window here, but in the meantime you can always stretch the rising edge with a diode and cap (signal->diode->cap with drain resistor->pin1 so that the cap charges fast when the line is high but falls slowly (RC time constant)).

That’s a temporary workaround but would allow you to read pin 1 even for a short transient.

Well, I can probably live with the chance of the two events happening at the same time, this should be very rare. The pin wakeup is an alert (motion detected, etc) while the timer is just a way of making sure the imp is still alive (so the alarm system is still up and running). So I could make it wake up at random intervals, so that an attacker doesn’t know when it’s safe to trigger the pin1 alert. But how do I tell it’s a timer wakeup? I guess if I make it wake up after a random number of seconds, I could save the original time, then substract it from the current time and see if that’s within +/- 10 seconds from the time it’s supposed to be for a timer wakeup. But that’s obviously a hack, it would make a lot of sense to know when it’s a timer wakeup, even if it overlaps with a pin1 wakeup.

The uncertainty window is likely to be milliseconds; PIRs tend to trigger for multiple seconds (just due to the way they work with long term averaging) so you should have no problem distinguishing a PIR event causing a wake?

it would make a lot of sense to know when it’s a timer wakeup, even if it overlaps with a pin1 wakeup

Yes, we’ll be implementing that anyway. I was just warning that for certain applications (very short pulses) the pin1 detection might not be 100% accurate. But it sounds like in your application it would work fine.

Peter

Thank you Peter, I’ll keep an eye out for the firmware update then. For now, I’ll just skip the timed wakeups and use the “nv” table to detect a cold boot.

Hugo, I was planning to use a simple door contact, not a PIR, at least for demo purposes. As far as I understand, that’s a simple on/off switch. Also, not all PIRs hold the signal, see http://youtu.be/xZGYn-oipQc?hd=1 - of the two models they are testing, one does and one doesn’t. Both models are sold by Sparkfun.

Thanks again!
Razvan

On the PIR video: The sweep on the scope in that video is very, very slow - in my opinion, even the “jumpy” one is within the range that we would be able to pick up.

Either of those would require an inverter (to get a rising edge) and so you could add the pulse stretcher circuit to that output.

A door contact is even more likely to keep in the “triggered” state for a long time, as you can’t open/close a door that fast. If the contact is a real mechanical one (vs a hall effect) you may see some bouncing due to the contacts, but that is generally over within 50ms.

Well, the “wakeup from deep sleep” times I see are around 3-4 seconds (the whitepaper on the Wiki says typical wakeup time is 1 second but I’ve only seen it wake up that fast once or twice - most of the times it’s 3-4 seconds before it runs my code). I can definitely open and close a door in 3 seconds.

Quick question: if I use imp.wakeup() instead of server.sleepfor(), should I see power consumption around 1mA at 3.3V, as described in the whitepaper? Or is that only for imp.sleep()? With imp.wakeup() I am able to code everything I need (I get a callback when the time expires and I also get a callback when the pin goes high). With my 19Ah battery I should be able to get about 2.5 years at 3.3mW, so it’s still good enough.

The 3-4 seconds is until the Squirrel code is running, and includes the wifi join, the DHCP, and a few round-trip-times to the server. The implementation of this feature, when it’s done, will check the wakeup cause as soon as the C++ firmware is running, which should be in the low tens of milliseconds.

Peter

@drazvan: as you’re in Europe (where Peter is), you currently see longer boot times, partially due to the fact the only server is in California right now. We will be setting up hosts in Europe in the next few months, which will improve cold boot times significantly - and also implementing wifi-less wakes which allow you to run squirrel code on wake without waiting for wifi to be up.

imp.wakeup() will generally cause the CPU to idle, but actually the main power draw is coming from wifi so it doesn’t help much with overall power consumption right now. The ~2mA target number is also dependent on what peripherals you’re using - eg if you use a UART we have to keep most of the busses up in order to ensure we don’t miss data, so you won’t get down that low.

Thanks Peter and Hugo! I guess I’ll have to wait, both for the firmware to be modified to be able to tell when it’s a timer wake vs a pin 1 wake, as well as for servers to appear in Europe.

About power consumption, the whitepaper on the Wiki indicated that 1mA figure. It says (and I quote): “Wake in ~1us on GPIO transition or timer”, CPU Sleep, Radio Off, Current 1mA / Power 3.3mW. What mode is it talking about? That looks perfect for our app (especially the 1 microsecond wakeup time on GPIO with radio off).

This mode is not yet available to squirrel code, sorry. It’s coming soon. To enter it you’d turn wifi off (command not available yet) and just fall off the end of your function/main block. The system takes care of the rest.

Hi Hugo,

Is any of these implemented in Release 10? I’m still looking for a way to wake up on pin transition and sleep (as deeply as possible) for the rest of the time. I currently use sleepfor() but that wakes up at least once every 24 hours and as far as I can tell there still isn’t a way to tell that this was a timed wakeup and not a pin transition wakeup.

release-10 has “imp.setpowersave(true)” which will reduce power to around 5mA whilst still being on wifi - that way you’re still running and hence all the usual GPIO event handlers work.

Is that low enough for you until the real wake reason handler is in there?

5mA is nice and will most probably work for now. However, I would really like to use the deep sleep mode since the alarms that trigger the wakeup are very rare and keeping the module connected and awake seems like an awful waste of power (even if we use our current packs - 7.2V at 14Ah - that would keep the module up in power saving mode for about 250 days).

Use the current pack and we’ll have a software update with the non-wifi wake ready before your current pack runs out :slight_smile:

I have read a bunch of posts on this and cant figure out why my stripped down code is nt working. My imp wakes up immediately after being put to sleep:

November 13, 2012 4:18:22 PM PST: Device booting
November 13, 2012 4:18:22 PM PST: Device configured to be "sleeping server"
November 13, 2012 4:18:22 PM PST: show: 3312
November 13, 2012 4:18:22 PM PST: sleeping until 1352852426000
November 13, 2012 4:18:22 PM PST: Power state: online=>asleep
November 13, 2012 4:18:24 PM PST: Power state: asleep=>online
November 13, 2012 4:18:24 PM PST: Device booting
November 13, 2012 4:18:24 PM PST: Device configured to be "sleeping server"
November 13, 2012 4:18:24 PM PST: show: 11906
November 13, 2012 4:18:24 PM PST: sleeping until 1352852428000
November 13, 2012 4:18:24 PM PST: Power state: online=>asleep
November 13, 2012 4:18:25 PM PST: Power state: asleep=>online
November 13, 2012 4:18:25 PM PST: Device booting
November 13, 2012 4:18:25 PM PST: Device configured to be "sleeping server"
November 13, 2012 4:18:25 PM PST: show: 4032
November 13, 2012 4:18:25 PM PST: sleeping until 1352852429000
November 13, 2012 4:18:25 PM PST: Power state: online=>asleep
November 13, 2012 4:18:27 PM PST: Power state: asleep=>online
November 13, 2012 4:18:27 PM PST: Device booting
November 13, 2012 4:18:27 PM PST: Device configured to be "sleeping server"
November 13, 2012 4:18:27 PM PST: show: 3024
November 13, 2012 4:18:27 PM PST: sleeping until 1352852431000
November 13, 2012 4:18:27 PM PST: Power state: online=>asleep
November 13, 2012 4:18:28 PM PST: Power state: asleep=>online
November 13, 2012 4:18:28 PM PST: Device booting
November 13, 2012 4:18:28 PM PST: Device configured to be "sleeping server"
November 13, 2012 4:18:28 PM PST: show: 4881
November 13, 2012 4:18:28 PM PST: sleeping until 1352852432000
November 13, 2012 4:18:28 PM PST: Power state: online=>asleep
November 13, 2012 4:18:29 PM PST: Power state: asleep=>online

Code:
// Register with the server
imp.configure(“sleeping server”, [], []);
// setup pin7 as analog input
hardware.pin7.configure(ANALOG_IN);

function scanonce()
{
// Send pin7 voltage to server
server.show(hardware.pin7.read());
}

function onidle()
{
//from Hugo’s code example
server.sleepfor(2*60);
}

scanonce();
// again, from Hugo’s example
imp.wakeup(0.1, onidle);

// End of code.

I must be missing something simple here…arg.

That code looks fine, an indeed on an imp here works just fine. You’re running the same release as me, too.

Can you try adding server.log(“time=”+time()); just after you call scanonce()?