Mbed-os: Sleep / Deepsleep notifications

Created on 12 Feb 2019  路  18Comments  路  Source: ARMmbed/mbed-os

Description

Is there a way , like a notification or callback that we can use to know if we are about to enter sleep/deepsleep and just woke up from sleep/deepsleep?

Asking this for a custom board based on PSOC6.

Issue request type

[x ] Question
[ ] Enhancement
[ ] Bug
CLOSED mirrored

Most helpful comment

Hi,

Ideally we want to implement a low power mode callback framework which potentially could be used by modules which need notification before entering the low power mode by registering its own callback function. This would be a more generic way.
This was one of the suggestions provided earlier in this thread.

Thanks.

All 18 comments

We currently only provide stats (to keep track of sleep patterns) but no callback notify support.

What can help you to override default idle loop and add this callbacks there rtos/rtos_idle.h. Attach your own hook, and implement your own idle loop.

I would like to know more the use case you are after.

Thanks Martin for the reply.
My use case is simple, we used serial attach function to receive serial data from host PC, and currently serial attach is blocking the deepsleep, as it acquires the lock , what we are looking at is we dont want to block the deepsleep by serial, we dont want to wakeup due to serial, and at the same time we wanted serial to receive data from host when cpu is awake.

For a simple custom solution for your scenario, you can modify SerialBase::attach to not acquire the deep sleep lock when an RX interrupt handler is attached.

As long as someone else is holding the deep sleep lock for the times when you do want to receive serial data, that should be fine.

Something like:

const bool lock_deep_sleep_for_irq[IrqCnt] = { /* RxIrq */ false, /* TxIrq */ true };

if (lock_deep_sleep_for_irq[type] && !_irq[type]) {{
     sleep_manager_lock_deep_sleep();
}
...
if (lock_deep_sleep_for_irq[type] && _irq[type]) {{
     sleep_manager_unlock_deep_sleep();
}

That may be a bit unpredictable though - whether you receive data or not is rather out of control of the code using the serial port. While actively running you would receive, but the simple act of putting a ThisThread::wait_for(100) or Semaphore::wait() somewhere in the system might lose you data. This could be very confusing. You could end up with code that only works if no-one blocks, unless you know the deep sleep lock is held by someone.

It would have to be a known design feature of the application - deep sleep lock must be held manually at certain times.

Now, if you have to know what those certain times are to hold the deep sleep lock, you might as well only attach the UART RX interrupt handler during those times, which would have the same effect, and it would be predictable when you would and wouldn't receive data.

We're looking at a global system suspend API to achieve the same sort of effect system-wide - full system suspend independent of active devices or threads, with limited wakeup sources.

Thanks kjbracey-arm for the answer, based on your points we will look on how to make our use case fit in to the current mbed.

Hi,
We are exploring the option of using our own idle code hooked to idle thread. We want to pic the implementation of default idle code i.e. default_idle_hook function and want to add callback function to let know that the system is going to sleep/deepsleep. However, when we created another function which is same was default_idle_hook function and hooked it to the idle framework by calling rtos_attach_idle_hook function, we see an issue related to the os_timer which creates another instance of the rtos::internal::SysTimer object. This is resulting in crash. We need the MBED_TICKLESS mode enabled. Do you have any suggestion on how to handle this?
Thanks.

There are already some points where sleep/deep sleep is monitored for stats purposes - see MBED_SLEEP_TRACING_ENABLED.

If you want to monitor that, it's best to hook into the same place - actually where the "sleep" calls to the HAL are made, which is more to the point. (Idle might not lead to HAL sleep, or HAL sleep might in principle be requested for other reasons than OS idle, eg suspend or shutdown).

Or just hook into the HAL's own hal_sleep/hal_deepsleep calls directly.

Hi,

Ideally we want to implement a low power mode callback framework which potentially could be used by modules which need notification before entering the low power mode by registering its own callback function. This would be a more generic way.
This was one of the suggestions provided earlier in this thread.

Thanks.

@kjbracey-arm

If you want to monitor that, it's best to hook into the same place - actually where the "sleep" calls to the HAL are made, which is more to the point. (Idle might not lead to HAL sleep, or HAL sleep might in principle be requested for other reasons than OS idle, eg suspend or shutdown).

  • For this we definitely need to touch the code in mbed_sleep_manager.c , which we feel is not correct because we shouldn't disturb mainline code, we want to be in line with mainline code going forward.

Or just hook into the HAL's own hal_sleep/hal_deepsleep calls directly.

  • looks like it cannot be, For example, it attach is done , then it will always allow hal_sleep, even if we insert our notification logic in hal_deepsleep , it will not get triggered, because the decision of going to sleep is made already(in mbed_sleep_manager), our idea of notifications is to detach/attach in the deepsleeep enter and exit , so that UART will not mingle with deep sleep decisions.

The mainline code currently offer a good hook for this purpose, so if you're trying to do it as-is, then the idle hook is all you have, I guess.

The problem is that the implementation of the default idle hook is quite intricate, so if you choose to replace it, you're kind of forking from mainline anyway - if we add any new facilities there in future, your replacement hook ends up overriding them.

I admire your attempt to avoid touching the mainline code, but I fear that your approach will just end up fragile and need to be adjusted with each new Mbed OS release anyway.

What would nearly work, if just trying to bend the "stay on for UART RX" rule, would be to just call sleep_manager_unlock_deep_sleep after the serial is enabled and has installed its IRQ handler. That would counteract its lock claim. Failure case is if the RX buffer ever gets full and makes it uninstall its IRQ handler and release the lock - that would underflow the counter, and we fault that rather than permit it. (I kind of wonder if we should permit it...)

Really though, I just feel the overall concept of "receive while on" is just too fuzzy to be good approach, if your definition of on is just "not idle". Anyone can make you idle. "Blinky" spends its whole time idle. You'd only be receiving while the CPU is actively spinning, or someone else was holding the deep sleep lock. You might find it very hard to figure out when you could reliably expect to receive anything.

I think you would do better to explicitly enable and disable serial reception at clear points in your application. If you are turning on and off something else taking deep sleep locks, do it at the same time. If no-one else is taking deep sleep locks, you really are going to struggle to receive anything.

Or is the use case so limited that you're not really expecting to receive arbitrary data, but maybe just the occasional lone character as a kind of "signal"?

And on the issue of two sys_timers when you do try copying the idle hook - yes, I can't see a way around that without changing the mainline code. You can only replace the idle hook, you can't stop the OS_Timer using its own SysTimer, and you can't get at that SysTimer yourself to make a forked version of default_idle_hook. :(

thanks @kjbracey-arm for the help you provided, it helped us understanding more.
As of now we will thinking to proceed with unlocking the deepsleep lock immediately after the serial attach function, with this change things moved , but one blocker we are seeing , as you asked previously there is no way target will know when the host will send so that we can hold the lock and release after responding, once we receive we are holding lock and responding, but it should fall when target is in wake state, since most of the time blinky kind of an app is in sleep with little wake , we are missing almost all the packets sent by host and they are not falling in the wake time of target.

To overcome this what we thought is , push all the information that target knows to host when it just wakes up by holding the locks for a minimal amount of time, but for this what is the best way to know that target just woke up and transfer data by holding the locks.

Hi Kevin,

If we have support for power mode change notification through a callback notification framework then it would really help address such issues and also many developers may be interested in getting notified about it.

Can Arm consider this request and add it in the next mbed release ?

Thank you.

We have internal ticket for this, not ETA

We have internal ticket for this, not ETA

@0xc0170 If you're talking about MBOCUSTRIA-852, it's closed because this GH issue is closed.
I think we need to create a new GH issue for the feature request.

To overcome this what we thought is , push all the information that target knows to host when it just wakes up by holding the locks for a minimal amount of time, but for this what is the best way to know that target just woke up and transfer data by holding the locks.

This would normally be done in a higher-level way. The "idling" of the CPU is a low-level function, and kind of happens automatically and unpredicatably. A higher-level comms concept is needed - an agreement between your application/protocol and the other end. An example is LoRAWAN where there's an agreement that exactly 1 second after finishing sending a packet to the network, the device will be awake to try to receive a reply.

So the behaviour there is:

  • Wake (for whatever reason), turn on radio, send message to network
  • Device active, waiting for TX complete interrupt
  • On TX complete interrupt, start 1 second timer
  • Shut down radio - device can now deep sleep for that 1 second sleep
  • When 1 second timer expires, turn on radio, check for radio preamble
  • If no radio preamble, turn it back off - can now deep sleep again (can happen within milliseconds)
  • If radio preamble, stay on until RX complete

You need a clearly defined "active" window like that where other people can deduce you will be able to receive, based on some sort of externally visible timing condition. Then you can save power at all other times.

And note that idle conditions can be decided on quite quickly - short timescale compared to serial. Even if you caught a character while running, with no lock, you'd probably just enter idle waiting for the next character, and then sleep through it.

You might conceivably be able to do something with software or hardware flow control signals, or else you could maybe just send a character as a cue to indicate "I'm ready to receive now, and I'll keep my serial port on to receive data with a X ms timeout". Literally closing/opening detaching/attaching the serial port is the equivalent of turning off the radio like in LoRAWAN. (And in principle turning something off properly could save more power than just leaving it on but not listening, although I'm not sure the HAL supports serial shutdown?)

thanks @kjbracey-arm for working on this and sharing all the possibilities, we will take a look at them, also looks like we have a notification logic inside our target specific code ,which will trigger before and after going to sleep/deepsleep, so we are planning to make use of it

This PR may be of interest: https://github.com/ARMmbed/mbed-os/pull/9797

Was this page helpful?
0 / 5 - 0 ratings

Related issues

sarahmarshy picture sarahmarshy  路  4Comments

rbonghi picture rbonghi  路  3Comments

ashok-rao picture ashok-rao  路  4Comments

neilt6 picture neilt6  路  4Comments

ghost picture ghost  路  4Comments