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

Loopless / low power examples. #262

Open
wants to merge 1 commit into
base: master
Choose a base branch
from

Conversation

MacGyverNL
Copy link
Contributor

A set of examples that demonstrate basic use of timers, interrupts, and
tasks. Based on and tested on the nRF52840, but also compiles on the
nRF52832 -- although you'll need an external button there.

They're not necessarily all finished -- especially Button_interrupt_direct_to_task uses freeRTOS API directly, which on the one hand is nice to demonstrate what is possible, but on the other hand might be undesirable from a consistency point of view. But in that case, there's clearly functionality missing that I think we'd like to have. So I don't know what your standard practice is w.r.t. new examples, maybe this needs to go in develop first?

A set of examples that demonstrate basic use of timers, interrupts, and
tasks. Based on and tested on the nRF52840, but also compiles on the
nRF52832 -- although you'll need an external button there.
@MacGyverNL MacGyverNL marked this pull request as ready for review May 4, 2019 02:40
@wb8wka
Copy link

wb8wka commented May 5, 2019

@MacGyverNL

Great job. I've had good luck after alot of trial and error with loop, but this is so much more elegant. I should have time to port over my "loop" low power application to this next week and will let you know how it goes.

Question, I'm changing the FreeRtos default tick rate from 1024 to 4 ticks per second. Any issues here besides needing to rescale? Doing this gave me a substantial power savings as others discussed.

@MacGyverNL
Copy link
Contributor Author

MacGyverNL commented May 5, 2019

Question, I'm changing the FreeRtos default tick rate from 1024 to 4 ticks per second. Any issues here besides needing to rescale? Doing this gave me a substantial power savings as others discussed.

As I've mentioned in #165 (comment), doing so may very well prevent the device from ever entering its tickless sleep mode. Also, I believe it'll tank the accuracy of the software timers, deferred interrupts (unless you explicitly tell the scheduler to run when a higher priority task wakes), as well as starving same-priority tasks for CPU time; but those are all functional issues, not energy issues. Unfortunately, I do not have the hardware to measure actual power consumption, I've mostly been going off toggling an LED in the idle task callback (which gets run once right before the system decides to sleep, afaict).

@wb8wka
Copy link

wb8wka commented May 5, 2019 via email

@MacGyverNL
Copy link
Contributor Author

This comment is not relevant to this PR, and we should move subsequent discussion to either the power-issue or to the Adafruit forum, but I feel it's important to provide context here.

It was a substantial power savings going to 4 ticks even from 16. Around 4.5 ua average with a 4dBm beacon once every 2000ms reading a sht31 once every 30 second.

Why that saving happens is going to depend a lot on what code you're actually running. Simplifying the mechanism a bit, freeRTOS runs "tasks" in a similar way that a desktop operating system runs processes. These tasks have priorities. There is a scheduler dividing processor time between the tasks, and the rule is basically that higher priority tasks are always serviced before lower priority tasks. Furthermore, if there are multiple same-priority tasks runnable, and no higher-priority task is runnable, then the scheduler divides the processor time between tasks. However, the scheduler is not some magical thing that is always running parallel to your tasks, that's impossible. That's where the systick comes in. Whenever the systick ticks, it fires an interrupt that invokes the scheduler, and this makes the decision what to give the next "slice" of CPU time to. (Unless a task yields explicitly, or requests a scheduler invocation explicitly, or an interrupt happens... It's a bit more complex but this is the basic idea.) Hence, if you lower the systick frequency, what you're really doing is lowering the number of times the scheduler gets to take a look and see it should actually give CPU time to another task, or resume executing the current task, or sleep the system altogether.

Of course, all this isn't free -- if the scheduler decides the same task that was already running gets the next CPU timeslice, then it just returns. But if not, it has to do a context switch. Still, that's not as expensive as one might think. But lowering the tick rate on a system that only ever runs one task will reduce the number of scheduler interrupts. The problem with this is that hardly any system is ever really running just one task - there will often be some background task that needs to run once every 5 minutes, or some deferred ISR, or somesuch, and then the inaccuracy of a 4Hz tickrate is going to be annoying.

Note that if the system has nothing to do (i.e. is just waiting for an interrupt or timer to fire), it will just stop the system tick entirely by itself, and then go to sleep -- but only if at least 2 tick periods of idleness is expected. So on a 4Hz tick rate, it'd have to expect to sleep for at least half a second. On a 1024Hz tick rate, only 2ms -- much easier to achieve. And it will go to sleep potentially for a lot longer than the 250ms that a 4Hz systick will cause. This is why I expect, and believe, that properly designing our systems to make use of this mechanism can lead to way better power savings than lowering the tick rate.

@jpconstantineau
Copy link
Contributor

Great examples. they are quite useful Thanks

@@ -0,0 +1,60 @@
/*
Blink_loopless
Copy link
Contributor

@Montvydas Montvydas Apr 14, 2020

Choose a reason for hiding this comment

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

change name to Blink2_loopless?

*/

// On the nRF52840, pin 7 is the UserSW/DFU switch.
int interruptPin = 7;
Copy link
Contributor

Choose a reason for hiding this comment

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

Probs can just use the defined PIN_BUTTON1


// the setup function runs once when you press reset or power the board
void setup(void) {
pinMode(LED_RED, OUTPUT);
Copy link
Contributor

Choose a reason for hiding this comment

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

This is already defined as per your other examples

*/

// On the nRF52840, pin 7 is the UserSW/DFU switch.
int interruptPin = 7;
Copy link
Contributor

Choose a reason for hiding this comment

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

PIN_BUTTON1

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

Successfully merging this pull request may close these issues.

None yet

4 participants