The maple ide v0.0.12 uses an asm spin loop to implement delay(). delay() on DUE, teensy, and pyboard (to name a few ARM-based boards) spin waiting for milliseconds to advance. With these it is possible to add a sleep option (asm("wfi")) to reduce power between the systick millisecond interrupts. The maple core library could be upgraded to support this low power delay(). Here is proof-of-principle sketch that demonstrates delay with wfi
https://github.com/manitou48/maple/blob/master/delaywfi.pde
On a RET6 with normal delay(), the 5 second LED off/on consumes 46.4/47.2 ma, with the delaywfi(), it is 28.4/29.2 ma.
wfi and low power delay()
(10 posts) (3 voices)-
Posted 10 months ago #
-
@manitou - Half power! Sneaky ;-)
Let me check I understand:
The wfi (Wait For Interrupt) routine, goes into a lower power mode, and whenever anything (clock or other interrupt source) happens, it wakes up and continues. The if test is trying to ensure there is *always* going to be at least one interrupt to wake the delay() up.Yes?
All I can think of to worry about is their may be a race condition.
If the next clock interrupt happens after the call to micros(), during the evaluation of the if, then (very, very occasionally) delay will be 1ms longer than expected. This could probably be guarded against (at some small reduction in power saving) by increasing the test
if ((micros() - start) >= 1000)
to something a little bigger, say
if ((micros() - start) >= 1002)
This might not be exactly the right value, but I guess it's close.
Otherwise it looks great.
Posted 10 months ago # -
Maybe DUE's delay() is cleaner
void delay( uint32_t ms ) { if (ms == 0) return; uint32_t start = GetTickCount(); do { yield(); } while (GetTickCount() - start < ms); }
DUE's yield() is a weak reference, you could define your own yield() containing the wfi, or just
replace the yield() with asm("wfi") ...Me thinks, no matter what, the wfi-based delay will not be as precise, and as you note up to a ms off. So maybe it is enough that the user knows he can trade precise delays for low power delays. The "weak" yield() is a possible implementation.
Posted 10 months ago # -
@manitou - Yes the yield() is a nice idea.
I assume the wfi has a consistent startup time, so maybe it just looks like a consistent offset and not jitter.
A factor of 2 is a pretty significant power saving, and avoids the rigamarole of directly controlling power for peripherals and buses.
Thanks for sharing.
Posted 10 months ago # -
I looked at how the delay is implemented using assembler and it looks like leaflabs put considerable effort into getting the timing as accurate as possible.
It seems odd that they would have ruled out using tick count for no reason.
You could post an issue on the libmaple repo in GitHub and Marti may be able to tell you why they did it that way.
Posted 9 months ago # -
@rogerclark - It's news to me that delay is accurate (sarcasm, sorry).
It was not accurate in the past, and the LeafLabs repo for delay_us hasn't changed since Aug 22, 2012, delay is unchanged since Apr 11, 2012. IIRC there is an old thread about its inaccuracy.The old Arduino delayMicroseconds was an assembler loop, so I have always believed LeafLabs did a translation.
It is partly inaccurate because LeafLabs use the SysTick timer interrupt, which can introduce jitter into the instruction-timing based delay_us. Doh!
There are several implementations of delay floating around. IIRC the more accurate implementation is based on a more recent Arduino implementation.AFAIK, no one has ever got around to having delay_us use the sub-microsecond accurate, jitter free, SysTick timer.
Posted 9 months ago # -
@gbulmer
Thanks for the heads up on delay us.
I must admit I was just going on looking at the code (assembly code) and the statements made by leaflabs in some of their docs.
I did think that repeatedly calling the micro second delay to get the millisecond delay seemed a strange way to do it
Do you know of any better implementing that I could use instead, e.g. Any contribs that improved this?
Posted 9 months ago # -
@rogerclark - I've had a quick search, but can''t find the thread, delay() is mentioned in a lot of posts.
There were a couple of threads where people identified a bug in a systick-based delay.
That delay was implemented using SysTick timer, and was pretty stable, ie. immune from jitter caused by interrupts, but had a race condition, which got fixed and regressed a couple of times.
The code in LeafLabs github libmaple repo no longer uses the SysTick timer, but instead uses 'busy-wait', or spin-loops to delay, which are jittered by interrupts.
I vaguely remember several threads where people wanted an interrupt-free form of delay, but I don't remember when delay() itself became purely busy-wait. (I have stayed with the old SysTick code, and fiddled around in corners.)
There was some work done on quantifying the error in delay:
http://forums.leaflabs.com/topic.php?id=168#post-1113Posted 9 months ago # -
@gbulmer
Thanks
I'll need to put that on the todo list for my version ;-)
Posted 9 months ago # -
@rogerclark - I think both Sysick and busy-wait approaches have good use-cases.
IIRC, the threads about busy-wait were about using a delay, and removing every possible interrupt, so that code ran very predictably. I think people disabled USB in those use-cases.
The SysTick timer gives a reasonably good timer over longer periods than 1ms, and is okay for short delays, but it causes code to experience interrupt jitter.
I thought at the time that both made sense. However, I didn't think of a tidy way of having both options, other than having both implementations with different names. I didn't do much with that thought.
Posted 9 months ago #
Reply
You must log in to post.