Double-time using a constructor

I'm writing a library to support multiple callbacks using MsTimer2 to provide the internal heartbeat. I've got it working but have hit an odd difference in the timing of the heartbeat. A stripped-down version of the code with the bare essentials is here:

#include "MsTimer2.h"  
  
const unsigned long DEFAULTHEARTBEAT = 1000;			// mS heartbeat from MsTimer2

class WAKEUP {
public:
  WAKEUP();
  void timerISR();
  void setHeartbeat(unsigned long heartbeat);
  void wakeMe( void (*f)());			
  void (*_sleeper)();
};


WAKEUP::WAKEUP() {
  setHeartbeat(DEFAULTHEARTBEAT);         // Exhibit A: establish heartbeat in constructor 
}

void WAKEUP::setHeartbeat(unsigned long heartbeat) {
  MsTimer2::set(heartbeat, timerISRWrapper);    // Set timer and function to call when done 
  MsTimer2::start();							// Start the timer
}

void WAKEUP::wakeMe( void (*f)()) {
  _sleeper = f;					// Store the function pointer to the sleeper
}

void WAKEUP::timerISR() {      
      _sleeper();				// Time's up; wake up the sleeper
}

WAKEUP wakeup;					// Instantiate one instance

void timerISRWrapper() {		// Use non-member function as stable function reference for MsTimer2::set call
  wakeup.timerISR();			// See http://www.parashift.com/c++-faq-lite/pointers-to-members.html#faq-33.2
}


  
void setup(void)
{
  Serial.begin(9600); 
 
  wakeup.wakeMe(sleeper0);      // Register function to be called on heartbeat

 // wakeup.setHeartbeat(DEFAULTHEARTBEAT);   // Exhibit B: establish heartbeat with call from main code.  Commented out here
}

void sleeper0() {
  Serial.println(millis());
}


void loop() {
}

This should result in a heartbeat of DEFAULTHEARTBEAT (1000mS) being set. However, when called from the class constructor (Exhibit A) the millis() readout from sleeper0 is every 2 seconds, not every 1 second.

If I then uncomment the heartbeat call at Exhibit B then the readout from sleeper0 is every 1 second, as intended.

On the face of it I'm calling the same member function (setHeartbeat) with the same value (verified with debug code, removed from the above), the only difference being what's called the function. I'm sure there's something I'm missing, but I can't see it.

Can anyone spot what I'm doing wrong?

You know when your constructor is called. But, do you know when the MsTimer2 constructor is called? Is the MsTimer2 instance ready to be initialized when your constructor is called?

Does the MsTimer2 class have a method to get the interval? Is that interval the same with both approaches?

WAKEUP wakeup;					// Instantiate one instance

I wouldn't instantiate classes as static members.

See "How do I prevent the "static initialization order fiasco"?" ...

http://www.parashift.com/c++-faq-lite/ctors.html#faq-10.15

I agree with Nick, it's probably the undefined order of initialization of static objects that is causing the problem. The MsTimer2::set and MsTimer2::start functions write to a number of mcu registers that control the timer. It may be that something in the Arduino base libraries writes to the same registers.

Great advice. Added a method to MsTimer2 to extract TCNT2 and the answer's different with the two approaches. When initialised from Setup TCNT2 is 6 (and correctly yields a 1000mS interrupt), but when initialised from the constructor TCNT2 is 32 and yields a 2000mS interrupt (don't quite understand the non-linear relationship here, but nevermind it works).

so much to learn!

Thanks so much for the help.