Go Down

Topic: safe way to prevent millis() wrap? (Read 3682 times) previous topic - next topic

Fjornir

Quote
I think you'll agree the code I just posted above is about the easiest thing that can be done here with a one-shot use of a time, that happens to hinge on using millis(), a timer is already built in arduino base.


Except for the fact that the code you posted won't compile because timer0_millis isn't in scope where you're trying to zero it out. And the fact that mucking about with the the state variables used by millis() is a bad idea because it is very likely to break any other library functions which rely on millis() working correctly... And the fact that zeroing a long isn't atomic so even if the code you posted DID compile the results you'd see would be very inconsistent with what you'd expect...

...oh yeah, and just coping with overflow is easy anyways.

Good luck!

scottmcphee

#16
Nov 04, 2009, 12:35 am Last Edit: Nov 04, 2009, 05:08 pm by scottmcphee Reason: 1
No access, scope!  Agh.  Extern solves that.


But

cli();
timer0_millis = 0;
sei();

makes it a little more atomic, don't you think?

Coding Badly

Quote
makes it a little more atomic


It does.  For what you're trying to do, the code will work.  

There's also a flaw that prevents your code from being generally usable.  For anyone reading this thread, please take BenF's, Fjornir's, and my advice: don't reset millis.  It isn't worth the risks.  There's an abundance of ready-to-use one-shot code available in this thread and in the this forum and in the Playground and in the examples and on the internet at-large.

scottmcphee

#18
Nov 04, 2009, 05:03 pm Last Edit: Nov 04, 2009, 05:17 pm by scottmcphee Reason: 1
This compiles:


// whack-a-millis

void setup(){
}

void loop() {

 extern volatile unsigned long timer0_millis ;
 cli();
 timer0_millis = 0 ;
 sei();

 // Groundhog Day

}


If arduino provided a general timer library, I'd use that instead.    I'd prefer to have a countdown timer and set its value in milliseconds, and then check it for zero.

C.Badly, "There's an abundance of ready-to-use one-shot code available in this thread and in the this forum and in the Playground and in the examples and on the internet at-large."   You're a very elusive poster... holding secrets back... if you know stuff, post stuff / links.   Save me from shooting my foot off!  Thanks.

scottmcphee

#19
Nov 04, 2009, 06:32 pm Last Edit: Nov 05, 2009, 05:01 pm by scottmcphee Reason: 1
I just found MsTimer2 in the playground, this should also work for my case.

#include <MsTimer2.h>

//declare a software reset function, begins execution at address 0
void(* resetFunc) (void) = 0;

setup()
{
// quiesce chip features, change I/O pins, and enable power saves
// setup external interrupt buttons (low level interrupt)
// sleep (power down mode)
// wakes up here
...
// setup the way I need things
// do my job (transmit information - one shot)

 MsTimer2::set(1000, resetFunc);  // set fuse length 1s on "reset bomb"
 MsTimer2::start(); // light the fuse

}

loop()
{
// listen for echo (if serial.Available() > 0) and act on it

// ..when the time is right (as a background process) MsTimer2 calls reset
}


Much cleaner.  Pretty much exactly what I want but better! I don't even have to check for zero, that runs as a background task.  

using millis method for my program makes it:
Binary sketch size: 3860 bytes (of a 30720 byte maximum)

using MsTimer2 instead makes it:
Binary sketch size: 4214 bytes (of a 30720 byte maximum)

10% bigger!  Sure this uses much more code space that twisting millis, but I'm only using around 14% of my 328P, so I'm not needing optimization at this juncture.

It turns out the safest way to prevent millis() from wrapping is not to play that game at all.  



Go Up