The pitfalls of CLPKR for power saving.

My program is running is on a Mega2560. It’s a datalogging program with SPI, I2C and several serial devices. I sample and record to SD every minute. This takes about 5 seconds, so for the other 55 I wanted to save batteries and implemented this:

void lowPowerDelay(uint16_t delay_secs) {
  Serial.print("delaying "); Serial.print(delay_secs);
  uint16_t oldClkPr = CLKPR;  // save old system clock prescale
  delay(1000); // Allow time for things to flush and write?
  CLKPR = 0x80;    // Tell the AtMega we want to change the system clock
  CLKPR = 0x08;    // 1/256 prescaler = 60KHz for a 16MHz crystal
  delay((delay_secs  - 1 )* 4);  // since the clock is slowed way down, delay(n) now acts like delay(n*256)
  CLKPR = 0x80;    // Tell the AtMega we want to change the system clock
  CLKPR = oldClkPr ;    // Restore old system clock prescale
}

This will run fine for a while. Hours sometimes, but at some point it will never leave this function. Looking at the output I can see the value passed is always about 55. Even when it hangs.

I’ve read some cryptic warnings about problems changing clock speeds, but nothing specific. I tried turning off interrupts, but then delay doesn’t work. Any ideas are welcome.