Skip to content

Conversation

daniel-k
Copy link
Member

The at86rf2xx driver can now reach the SLEEP state by setting its state via netapi to NETOPT_STATE_SLEEP. Everything except the framebuffer is retained in the power mode. Wake up takes approx. 300us, power consumption is about 0.2uA.

The netapi is blocked in sleep mode except for setting and getting the state. But using some driver functions directly by including the header file might lead to a deadlock. On the other hand putting a at86rf2xx_assert_awake() everywhere seems wrong too.

@daniel-k daniel-k added Type: enhancement The issue suggests enhanceable parts / The PR enhances parts of the codebase / documentation Discussion: RFC The issue/PR is used as a discussion starting point about the item of the issue/PR Area: drivers Area: Device drivers labels Sep 16, 2015
@@ -25,6 +25,7 @@
#include "at86rf2xx_internal.h"
#include "at86rf2xx_registers.h"
#include "periph/spi.h"
#include "xtimer.h"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not used.

@jnohlgard
Copy link
Member

I assume this will be used as a part of your work on a MAC protocol.
The change looks good, I have not yet tested it on hardware though. How do I test this? is it currently possible to switch to/from sleep mode from one of the example applications?

@daniel-k
Copy link
Member Author

Yes. Switching to sleep mode only introduces a 300us wakeup delay and flushes the internal packet buffer.

There's no example for state switching though.

if( (at86rf2xx_get_status(dev) == AT86RF2XX_STATE_SLEEP) &&
(opt != NETOPT_STATE) ) {
return -ECANCELED;
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am not sure about this. Shouldn't we maybe wake the device up, to get/set options, and put it to sleep then again? I could imagine the MAC protocol awakes the device only when it expects receive/send actions and in this case it could be an advantage to be able to change options when there is nothing to do instead.

@daniel-k
Copy link
Member Author

I guess that my current implementation may also lead to weird behavior with ifconfig on the shell.

Waking up and putting to sleep should work. But that should be a more generic question about netapi and devices sleeping. Is there already a driver that has the same problem?

@daniel-k
Copy link
Member Author

I guess that my current implementation may also lead to weird behavior with ifconfig on the shell.

At least this is not the case. ifconfig is behaving nicely with a sleepy device, that only responds to the state option.

> ifconfig 4 set state sleep
ifconfig 4 set state sleep
success: set state of interface 4 to SLEEP
> ifconfig
ifconfig
Iface  4   State: SLEEP

> 

@daniel-k
Copy link
Member Author

So it seems that only drivers/kw2xrf and cpu/nrf51/radio implement NETOPT_STATE_SLEEP and both implementations don't block the netapi interface. Therefore I'd say I'll do it like @thomaseichinger proposed.

@daniel-k daniel-k added the CI: needs squashing Commits in this PR need to be squashed; If set, CI systems will mark this PR as unmergable label Sep 17, 2015
@jnohlgard
Copy link
Member

I agree, it is also more user friendly to do what Thomas proposed.
On Sep 17, 2015 1:34 PM, "Daniel Krebs" notifications@github.com wrote:

So it seems that only drivers/kw2xrf and cpu/nrf51/radio implement
NETOPT_STATE_SLEEP and both implementations don't block the netapi
interface. Therefore I'd say I'll do it like @thomaseichinger
https://github.com/thomaseichinger proposed.


Reply to this email directly or view it on GitHub
#3867 (comment).

@daniel-k
Copy link
Member Author

I'm not really happy with either solution :/ With this PR NETOPT_STATE_SLEEP puts the transceiver to SLEEP instead of TRX_OFF, which was a nice power saving state that still permitted setting options (@ 300uA). There was the option to map NETOPT_STATE_OFF to transceiver SLEEP, but IMO you can't assume, that the device keeps it's configuration, i.e. initializing is required after transition to NETOPT_STATE_OFF. Which doesn't map for our SLEEP state.

I think the API lacks a state between SLEEP and IDLE that has communications disabled, but provides device access and low latency transition to IDLE.

Automatically waking up and putting to sleep again feels like to much magic somehow. And not that netapi calls are already quite expensive (execution time wise), waking up introduces another 300us at least. That doesn't sound like power saving or transparent APIs to me.

@jnohlgard
Copy link
Member

@daniel-k Do you have a use case where you want to linger in TRX_OFF instead of going to SLEEP or remaining in RX_AACK_ON?
I understand that 300 us is a long time to wait for a response for modifying settings, but what is the concrete use case for a low latency switch between idle/deaf to RX listening?
Several hundred µA is a lot of power for a battery powered device if we are just waiting without doing any communications over the transceiver. Will there be any noticeable gains in overall battery life time if we go to TRX_OFF while doing some internal computations after an RX packet instead of remaining in RX_AACK_ON, or instead of putting the transceiver to proper sleep?

@daniel-k
Copy link
Member Author

@gebart

Do you have a use case where you want to linger in TRX_OFF instead of going to SLEEP or remaining in RX_AACK_ON?

Actually no apart from configuring the device at startup. Or configuring the device in genral without the need to wakeup. Maybe if there's a short time frame where you don't want to receive new packets for whatever reason.

Will there be any noticeable gains in overall battery life time if we go to TRX_OFF while doing some internal computations after an RX packet instead of remaining in RX_AACK_ON, or instead of putting the transceiver to proper sleep?

I think this really depends on the use case, i.e. on the time it takes for the computations.

Maybe you're right that we don't really need such a state.

@daniel-k
Copy link
Member Author

@gebart @thomaseichinger

Addressed temporarily wake up in 5b0c737

@jnohlgard
Copy link
Member

@thomaseichinger, @haukepetersen, @authmillenon, @OlegHahm, @kaspar030 etc.

What is the general opinion on this regarding introducing a separate state for "device powered and fully responding towards the MCU, but RF components switched off" (i.e. deaf and mute)?

We could introduce another state (NETOPT_STATE_STANDBY or something), and let that map to TRX_OFF. Do the other supported transceiver hardware device have similar states as the at86rf2xx which could map to this new state as well?
The downside is that adding more states may make the API more confusing/complex for new developers to learn.

@jnohlgard
Copy link
Member

@daniel-k 5b0c737
Some of the queries unnecessarily wakes the radio from sleep, e.g. NETOPT_SRC_LEN, NETOPT_ADDR_LEN, NETOPT_NID
Could you move things around so that the simple constant replies or values taken straight from MCU RAM are handled without waking the radio?

@daniel-k
Copy link
Member Author

@gebart

Some of the queries unnecessarily wakes the radio from sleep, e.g. NETOPT_SRC_LEN, NETOPT_ADDR_LEN, NETOPT_NID
Could you move things around so that the simple constant replies or values taken straight from MCU RAM are handled without waking the radio?

Done, see 004371b.

Edit: forgot about the going back to sleep. But it does no harm as at86rf2xx_set_state() directly returns when setting the current state again.

@jnohlgard
Copy link
Member

@daniel-k That works,
For even more efficient handling it can be split into two switch statements, one first which handles all of the variables which do not need any radio interaction, they can even return immediately just like they did before this PR, followed by check of the state and a wake from sleep, and a second switch which is takes care of all the getters requiring interaction with the chip.

@daniel-k
Copy link
Member Author

@gebart
I like that idea, see 417ea8b 78820e3 (indention was off)

@daniel-k daniel-k force-pushed the pr/at86rf2xx_sleep_mode branch from 417ea8b to 78820e3 Compare September 18, 2015 10:26
@thomaseichinger
Copy link
Member

@gebart @daniel-k

We could introduce another state (NETOPT_STATE_STANDBY or something), and let that map to TRX_OFF. Do the other supported transceiver hardware device have similar states as the at86rf2xx which could map to this new state as well?
The downside is that adding more states may make the API more confusing/complex for new developers to learn.

I wonder if we can't already map this with the existing states. To my knowledge, on most boards you can't really power off the radio module completely. So how about we change the states' descriptions to:

netopt_state_t radio state
NETOPT_STATE_OFF (deep) sleep, the module is not reachable by the MCU. From a MCU perspective this is comparable to OFF.
NETOPT_STATE_SLEEP turn off radio synthesizer but reachable by the MCU

@daniel-k
Copy link
Member Author

@thomaseichinger
This would be possible, but it doesn't match the SLEEP state of at86rf2xx, which is more important than TRX_OFF and DEEP_SLEEP. I would assume that when I set a device to NETOPT_STATE_OFF that it needs reinitialization because all configuration is lost, whereas NETOPT_STATE_SLEEP would mean save the most power possible without losing state.

@jnohlgard
Copy link
Member

@thomaseichinger I agree with @daniel-k. OFF should be the lowest possible state, i.e. no state can be assumed to be retained after switching to OFF.

A use case for the OFF state even if the chip itself does not support such a state is a platform/board where the power to the radio transceiver is controlled by an external circuit, that can be turned on and off from software. For example, 1 is an IC that we (Eistec) have used in multiple projects for controlling power to different sections of the board or even individual components in order to save power.

@daniel-k
Copy link
Member Author

@gebart @thomaseichinger
So how do we proceed? Leave it as is? What about the release? I guess we wouldn't merge this before the release, but maybe we can get it green and ACKed until then.

@daniel-k daniel-k force-pushed the pr/at86rf2xx_sleep_mode branch from 5ff7cea to 173fe42 Compare September 21, 2015 17:09
@daniel-k
Copy link
Member Author

@gebart

Do you have a use case where you want to linger in TRX_OFF instead of going to SLEEP or remaining in RX_AACK_ON?

I just found one :-( At some point in time I decide to put the transceiver to sleep. Just before that moment something happens and an IRQ is generated that queues a message for the (no)mac thread. There are 2 bad situations now:

  • servicing the ISR is not possible, because the transceiver is sleeping
  • I don't care about anything that happend after I put it to sleep, but without servicing the ISR this gets retained until it wakes up the next time.

To get rid of this situation I would like to clear the current state of transceiver and put it back to sleep as soon as possible. Apart from the fact that there's no API for discarding IRQs, when putting the transceiver back to IDLE which means active listening, new frames can arrive and complicate stuff further, although I don't want to receive anything at that point, but let it sleep as soon as possible.

Hope that is not too confusing :)

@jnohlgard
Copy link
Member

Your problem statement was very clear and understandable, thank you. However, does it actually help to have one more state in this case or will the fix be all internal to the IRQ handling function of the driver?
I mean, you are talking about switching to TRX_OFF and back again as soon as the IRQ register has been read.

@daniel-k
Copy link
Member Author

However, does it actually help to have one more state in this case or will the fix be all internal to the IRQ handling function of the driver?

I guess no. As long as this is the only case it's not worth changing a system-wide API. But I'm thinking now how to implement this. I see 2 possiblities:

  • adding another NETOPT_ option. But as the name says it's an option, not a command (like "discard state)
  • clear interrupts flag when going to sleep. That would help in my particular case, but doesn't seem to be a good idea for the general case

Any ideas?

@OlegHahm OlegHahm added this to the Release NEXT MAJOR milestone Sep 24, 2015
@jnohlgard
Copy link
Member

@daniel-k

However, does it actually help to have one more state in this case or will the fix be all internal to the IRQ handling function of the driver?

I guess no. As long as this is the only case it's not worth changing a system-wide API. But I'm thinking now how to implement this. I see 2 possiblities:

  • adding another NETOPT_ option. But as the name says it's an option, not a command (like "discard state)
  • clear interrupts flag when going to sleep. That would help in my particular case, but doesn't seem to be a good idea for the general case

Any ideas?

Actually, I would vote for aborting if an RX interrupt occurs before the state transition to sleep has finished.

@daniel-k
Copy link
Member Author

Actually, I would vote for aborting if an RX interrupt occurs before the state transition to sleep has finished.

You mean abort going to sleep? That implies that you can't put your radio to sleep if someone hammers you with packets.
On the other hand this doesn't work as the interrupt serving is handled in the same thread as setting the sleep state. That's actually the root of the problem.

@daniel-k
Copy link
Member Author

daniel-k commented Oct 9, 2015

@gebart
I'm using my second proposal (discarding IRQs when going to sleep) for some time now (see daniel-k@25ea950) and it seems to work well so long. I just added 13c58bd so that you can omit the check in the user code without sacrificing too much performance.

For this particular transceiver putting it to sleep means that the framebuffer is lost anyway. So when the user decides to put it to sleep, it already implies that any incoming frame is lost. And given the just arriving frame would have come in only a moment later, it would have been lost too.

@daniel-k daniel-k force-pushed the pr/at86rf2xx_sleep_mode branch from b449564 to 1370afb Compare October 12, 2015 14:30
@daniel-k
Copy link
Member Author

Rebased on master

@daniel-k daniel-k force-pushed the pr/at86rf2xx_sleep_mode branch from 1370afb to f6a7adc Compare October 12, 2015 14:52
@jnohlgard
Copy link
Member

nitpick: Remove #include "xtimer.h" in drivers/at86rf2xx/at86rf2xx.c

ACK, let's defer the decision regarding adding extra modes for "awake for MCU commands but not listening on radio" to a separate PR/issue

@jnohlgard
Copy link
Member

OK to squash

@daniel-k daniel-k force-pushed the pr/at86rf2xx_sleep_mode branch from ad9981b to 502786b Compare October 13, 2015 13:06
@daniel-k daniel-k added CI: ready for build If set, CI server will compile all applications for all available boards for the labeled PR and removed CI: needs squashing Commits in this PR need to be squashed; If set, CI systems will mark this PR as unmergable Discussion: RFC The issue/PR is used as a discussion starting point about the item of the issue/PR labels Oct 13, 2015
@jnohlgard
Copy link
Member

Travis is happy -> go!

jnohlgard pushed a commit that referenced this pull request Oct 13, 2015
@jnohlgard jnohlgard merged commit 7b5ed7c into RIOT-OS:master Oct 13, 2015
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Area: drivers Area: Device drivers CI: ready for build If set, CI server will compile all applications for all available boards for the labeled PR Type: enhancement The issue suggests enhanceable parts / The PR enhances parts of the codebase / documentation
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants