WDT+switch case error; Strangest behavior ever

As for the title, this is the strangest thing I have seen so far. Anyway, I will try to explain as clear as possible. First what the program is supposed to do, then the problem, then the code, finally some of my experiences so far. Bear with me.

What the program is supposed to do:
The program, on ARDUINO FIO/using 1.04, is meant to perform measurements periodically and send them over through an XBEE radio, every 10 minutes. To achieve this, the Watch Dog Timer (WDT) is configured as a wake up interrupt, and by counting interrupts, I can do approximate 10 min interval measurements.

Because the WDT can be horribly inaccurate (10% off in timing is common), I do a small calibrate method at the beginning of the program and every 3 hours, or whenever it needs to. This is done by timing one or more WDT interrupts with the millis() function, after which the number of interrupts is adjusted to achieve 10 min. intervals.

Because the interval setting for the calibration is shorter than the sleep interval setting, I wrote one method that takes an integer as argument, after which a switch statement sets the WDT to the interval specified by that integer, which represents seconds (can be 1,2,4 or 8, default is 8 ).

Now for something on the WDT of the 328P. For those in the know, you can probably skip to the next paragraph.

The WDT is set primarily by setting the WDTCSR register on the ATMEL, together with one bit in the MUCSR. This last register holds reset flags of various sub-systems, and the WDRF flag (bit3) signals a system reset by the WDT. The setting of this bit is a common cause for those dreaded WDT infinite reset loops.

The WDTCSR contains the following 8 bits with their respective functions (Im mentioning only the ones I use):
-WDE/WDIE (WD enable/WD interrupt enable) The setting of these bits determines the state of the WDT. This can be off (0-0), interrupt only (0-1), system reset (1-0), or interrrupt->system reset (1-1). As I use the WDT as a sleep interrupt I only set WDIE to 1 when in use. Note that WDE is overwritten by WDRF in register MUCSR, switching the WDT to one of the reset modes.
-WDCE (WD change enable) This is bit is set to signal a change to the WDT settings. It is cleared automatically again after the changes.
-WDP(0-3) (WD prescaler) These four bits determine the time-out of the WDT, i.e. when an interrupt or reset is triggered. This can be between 8 secs and 16 ms. Ill save you the table. For a more detailed look into the 328P and the WDT, here's the datasheet: http://www.atmel.com/Images/doc8161.pdf (page 50 for WDT)

The problem:
Now, some time ago I started experiencing those dreaded WDT infinite reset loops. After printing a whole bunch of debug statements, I traced the problem to the WDTCSR register being set incorrectly. In fact, besides the timing bits being of some times, the biggest problem was that for some reason the WDE bit was set, causing the program to go into reset-mode.

I started playing with the lines defining the WDT in the switch case, added and removed delays surrounding them, all to figure out what caused it and to prevent it. After all of it, my conclusion, however strange it might sound, is that the code in one switch case (which is not being called upon) is interfering with the switch case that is being used! Not only that, but that it also only happens when using certain settings for the WDT. The code will probably explain this better.

My code:
The following is just a small part of the code I use, the relevant parts. Its semi pseudo, but that should make it more readable:
PLease note that testable, functional code can be found in Reply#5...please test! :slight_smile:

const int WDTInterval     = x;     //Specifies the WDT interval (seconds) when the main program is running
const int WDTCalInterval = y;     //Specifies the WDT interval (seconds) during calibration. Both x and y can be {1,2,4,8}

setup(){
   ....other stuff
   calibrateWDT();
}

loop(){
   if(>10 minutes){
      measure();
   }
   sleep();
}

calibrateWDT(){
   setWDT( WDTCalInterval );                    //Set bits to calibrate settings (not switching WDT on)
   delay(10,000);                                    //delay added during debugging, relevant later on
   ...measure interrupts                           //WDT on, measure millis(), WDT off    (by toggling WDIE);
   ...adjust some settings accordingly         //Like interrupts before measuring, etc
   setWDT( WDTInterval );                        //Set bits to normal setting (not switching WDT on yet)
}

setWDT(int seconds){
  int testInt = seconds;

  switch(testInt){
   case 1:
     WDTCSR &= ~_BV(WDIE);                       //Make sure the WDT is switched off by setting WDIE to zero                    
     MCUSR  &= ~(1<<WDRF);                       //Clearing the WD reset flag from MCUSR  
     WDTCSR |=  (1<<WDCE) | (1<<WDE);              //Signal coming change (WDCE) and setting WDE which MUST be done. Afterwards, 4 clockcyles to set the WDP bits
     WDTCSR  =   1<<WDP1  |  1<<WDP2;            //Bit settings for 1 second interval

   break;
   case 2:
     ...same as above   
     WDTCSR  =   1<<WDP0  |  1<<WDP1 |  1<<WDP2;        //Bit settings for 2 second interval

   break;
   case 4:
     ...same as above    
     WDTCSR  =   1<<WDP3;                          //Bit settings for 4 second interval

   break;
   case 8:
     ...same as above   
     WDTCSR  =   1<<WDP3 | 1<<WDP0;                          //Bit settings for 8 second interval

   break;
   default:
     ...same as above    
     WDTCSR  =   1<<WDP3 | 1<<WDP0;                          //Bit settings for 8 second interval as default case           
   }

}

My experiences:
Now, most importantly, my experiences and observations of the behavior:

STEP A-The problems started when I used 8 secs and 4 secs for the settings. Using 8 for calibration and 4 for normal operation (testing purposes), the WDE bit got set, but the program would still continue on. When using 4 sec for the calibration: immediate crash on first call to setWDT();. Same when setting both calls to 4 secs. (This last one turned out very interesting later on)

STEP B-Noticing the 4 second setting seemed to give the problems I decided to change the WDP bit settings in the statements of the switch case. (I did try more things but to no avail)
These are some of the results:
-Making all statements/cases program the bits to 2 seconds : Works every time, no matter what x or y (see code)
-Making all statements/cases program the bits to 8 seconds : Works every time, no matter what x or y (see code)
-Making all statements/cases program the bits to 4 seconds : Works every time, no matter what x or y (see code)

STEP C-Building on the above results, I decided to return ONLY THE STATEMENT FOR 8 SECONDS to its original code (WDP3 and WDP0 =1). So all other statements still set the WDT to 4 seconds. Results as follows:
case: (a)(b)(c)(d)
calibrationInterval(y) = 8 8 4 4
normalInterval(x) = 8 4 8 4
result = V X X X

Only case (a) performed as intended. Case (b) is most interesting. During this test, the WDE bit apparently got set wrongfully (seen by printing WDTCSR a number of times throughout). The program would however continue operating as intended. This changed when I added a print of WDTCSR in the switch statement for 4 seconds, after setting the bits. This resulted in an immediate crash.
Cases (c) and (d) also crashed immediately.

STEP D-Not knowing the exact reasons yet, I started adding delays() in the code at certain points. This was mainly because following the execution without delays is impossible. Few second delays made it possible to see whether the program would hang before or after a block of code. Normally, printlns would also do that job, but as they return immediately, they arent reliable at ms timing.
-The first major delay was the 10 second delay after setting the WDT for the first time for calibration (see code). It didnt solve the problem, but helped diagnosing cases b,c and d from step C.

  • Next I added a small delay(100) IN the switch statement case for setting it to four seconds, AFTER setting the bits. HOORAY, for some reason this worked, solving the wrongful setting of the WDE bit.
    -Following the above result, I thought it might be useful to pull the delay out of the four second case, and put it after the switch statement, so that all cases might benefit....You guessed it, the problem returned.... sigh

STEP E -I tried using an if/else cascade instead of a switch case.....didnt help...

CONCLUSIONS(apparent or otherwise)
-From step A: The problem seems to be caused by configuring the WDT to four second intervals.
-From step B: The conclusion is that the problem cannot be caused by the WDT code itself it seems here. Every possibility seems to work. This conflicts with the conclusion from A, which seems to point to the WDT code of four seconds. Instead, the suspect now appears to be the SWITCH CASE ITSELF!
-From step C: Conclusion seems to be that somehow, SOMEHOW, the code in the last case block (8 seconds, default not included) is interfering with the 4 second block!! Extremely weird is case (d) from step C, which (setting wise) worked in step B (4 secs for both x and y). So by changing the code in the block for 8 seconds, a case WHICH IS NOT CALLED, the program broke.
-From step D: Adding a small delay right after setting the bits for four second interval seemed to help. What is important is to realize that not only should the delay be directly sequential in time after setting the bits, IT MUST be written directly after setting the bits IN THE CODE. This seems evident from the fact that adding the small delay after the entire switch statement, as well as the large delay following setWDT() in calibrateWDT() didnt help at all.
-From step E: From this it seems the problem might not even be the SWITCH CASE ITSELF, but more the flow of the program following the setting of the WDT.

SO...LIKE....WHAT IS GOING ON HERE!!!!!!!!????????
Please let there be someone who can point me in the right direction. I simply can NOT find ANY reasonable explanation for this behavior. Especially the conclusion from step C above is making me doubt my insanity. Could it be that the code is written to memory in a wrong way? I dont know....but I hope some of you will. Im even hopeful at the moment I made a GIANT GIANT N00b error....I can live with the shame, not with this ridiculous behavior....

Rather than showing an extract of your sketch containing the parts that you think are relevant, please post a complete sketch that compiles, runs and demonstrates the problem. This will probably be very similar to the pseudocode you already posted.

Ok, so here is another perfect example of the problem. Remember the basic program from above (even more stripped down, minor changes):

const int WDTInterval     = 4; //WDT timer settings in seconds during normal operation
const int WDTCalInterval = 4; //WDT timer settings in seconds during calibration

setup(){
  ...
  calibrateWDT();
}

calibrateWDT(){
  delay(10000);                                    //Added this delay
  setWDT( WDTCalInterval );
  delay(10000);
  ....                                                 //Crash has already occurred here
 setWDT( WDTInterval );
}

setWDT(int seconds){
   ...switch statement....                  //Sets the WDT settings according to the value given. See above to notice that both ints are set to 4;
}

If I write the switch statement as follows, the program works as intended. Note that case 4 is the only case being used here:

setWDT( int seconds){
  int testInt = seconds;
  
  switch (testInt) {
    case 1:
        WDTCSR &= ~_BV(WDIE);                         //Disable WDT before setting to proper value again
        MCUSR  &= ~(1<<WDRF);                         //Clear the WDT reset flag from the MCU register
        WDTCSR |=  (1<<WDCE) | (1<<WDE);              //Prepare register for changing WDT prescaler
        WDTCSR  =   1<<WDP1  |  1<<WDP2;
      break;
    case 2:
        WDTCSR &= ~_BV(WDIE);                         
        MCUSR  &= ~(1<<WDRF);                         
        WDTCSR |=  (1<<WDCE) | (1<<WDE);               
        WDTCSR  =   1<<WDP3;                                         //THIS CASE IS HERE CONFIGURED WRONG, IT ACTUALLY CONFIGURES THE WDT FOR FOUR SECONDS
       break;
    case 4:
        WDTCSR &= ~_BV(WDIE);                        
        MCUSR  &= ~(1<<WDRF);                        
        WDTCSR |=  (1<<WDCE) | (1<<WDE);   
        WDTCSR  =   1<<WDP3;  

      break;
    case 8:

        WDTCSR &= ~_BV(WDIE);                         
        MCUSR  &= ~(1<<WDRF);                         
        WDTCSR |=  (1<<WDCE) | (1<<WDE);               
        WDTCSR  =   1<<WDP3  |  1<<WDP0;

      break;  
    default: 
        WDTCSR &= ~_BV(WDIE);                         
        MCUSR  &= ~(1<<WDRF);                         
        WDTCSR |=  (1<<WDCE) | (1<<WDE);               
        WDTCSR  =   1<<WDP3  |  1<<WDP0;
        Serial.println("error");
  }

  delay(100);
  }

IF, however, I fix case 2 so that it configures the WDT for 2 seconds (as it should), like this:

setWDT( int seconds){
  int testInt = seconds;
  
  switch (testInt) {
    case 1:
        WDTCSR &= ~_BV(WDIE);                         //Disable WDT before setting to proper value again
        MCUSR  &= ~(1<<WDRF);                         //Clear the WDT reset flag from the MCU register
        WDTCSR |=  (1<<WDCE) | (1<<WDE);              //Prepare register for changing WDT prescaler
        WDTCSR  =   1<<WDP1  |  1<<WDP2;
      break;
    case 2:
        WDTCSR &= ~_BV(WDIE);                         
        MCUSR  &= ~(1<<WDRF);                         
        WDTCSR |=  (1<<WDCE) | (1<<WDE);               
        WDTCSR  =   1<<WDP1  |  1<<WDP2 | 1<<WDP0;               //<<<<<<<<<<<<<<<<<<<<The ONLY thing that has changed!!!
       break;
    case 4:
        WDTCSR &= ~_BV(WDIE);                        
        MCUSR  &= ~(1<<WDRF);                        
        WDTCSR |=  (1<<WDCE) | (1<<WDE);   
        WDTCSR  =   1<<WDP3;  

      break;
    case 8:

        WDTCSR &= ~_BV(WDIE);                         
        MCUSR  &= ~(1<<WDRF);                         
        WDTCSR |=  (1<<WDCE) | (1<<WDE);               
        WDTCSR  =   1<<WDP3  |  1<<WDP0;

      break;  
    default: 
        WDTCSR &= ~_BV(WDIE);                         
        MCUSR  &= ~(1<<WDRF);                         
        WDTCSR |=  (1<<WDCE) | (1<<WDE);               
        WDTCSR  =   1<<WDP3  |  1<<WDP0;
        Serial.println("error");
  }

  delay(100);
  }

The program breaks again, going into reset right after the first 10 second delay. So once again, changing what seems to be irrelevant pieces of code, in a switch statement case which is NOT USED OR CALLED, EVER, affects the behavior or outcome of another case statement........I cannot describe this any more clearer...quickly loosing sanity

jzuidema:
Ok, so here is another perfect example of the problem.

Did you see my comment about posting an actual sketch that demonstrates the problem? You're still posting pseudocode and fragments.

Sorry I missed your earlier message. Here is a VERY VERY barebones version of my complete program (No XBEE/I2C/sensors/anything). Basically I stripped everything but what I mentioned in my pseudo code:

#include <avr/interrupt.h>        // interrupt routines
#include <avr/wdt.h>              // watchdogtimer functionality

const int measuring_interval = 1;              //Defines the number of minutes between each measurement
const int WDTInterval        = 4 ;             //Preferred number of seconds between WD interrupts
int WDTInterruptsNeeded;                       //The number of calibrated interrupts to achieve the approximate minutes interval of 'measuring_interval'
                                               //Established through calibrateAndSetWDT()
                                               
const int WDTCalInterval = 4;                  //Number of seconds between WDT interrupts during calibration of the WDT
const int WDTCalCycles = 2;                    //The number of WDT interrupts (during calibration), to base calibration ratios upon


volatile int WDTCounter;                       //Keep track of number of WDT interrupts. Reset after measurement
volatile int WDTCalCount;                      //Keep track of larger number of interrupts to signal WDT recalibration
volatile boolean calibrating;                  //Flag which tells the WDT interrupt whether calibration is being done


int caliInt;                                   //Stores number of interrupts while calibrating WDT
int calibrateTimeHours;                        //Time in hours between calibrating the WDT timer
int calTimeHoursToInterrupt;                   //Number of interrupts to reach calibrateTimeHours



  void setup(){  
    
    WDTCounter           = 0;                          //Initialize the interrupt counter for measurements
    WDTCalCount          = 0;                          //Initialize WDT recalibration interrupt counter
    caliInt              = 0;                          //Initialize WDT calibration interrupt counter
   
    Serial.begin(9600);                                                //Enable serial communication at 9600 BAUD rate

    

    calibrateAndSetWDT();                         //Initial calibration and configuration of the WDT


    
  }

  void loop(){ }


  void calibrateAndSetWDT(){
    
    delay(10000);
    configureWDT(WDTCalInterval);
    delay(10000);
    
    configureWDT(WDTInterval);
    Serial.println(WDTCSR);
    delay(100);
  }
  
  
  
 void configureWDT(int seconds){
  
   int testInt = seconds;
  
  switch (testInt) {
    case 1:
        WDTCSR &= ~_BV(WDIE);                         //Disable WDT before setting to proper value again
        MCUSR  &= ~(1<<WDRF);                         //Clear the WDT reset flag from the MCU register
        WDTCSR |=  (1<<WDCE) | (1<<WDE);              //Prepare register for changing WDT prescaler
        WDTCSR  =   1<<WDP1  |  1<<WDP2;
      break;
    case 2:
        WDTCSR &= ~_BV(WDIE);                         
        MCUSR  &= ~(1<<WDRF);                         
        WDTCSR |=  (1<<WDCE) | (1<<WDE);               
        WDTCSR  =   1<<WDP3; //<<<<<<<<<<<<<<<<<<<<<<<<<<<<<CHANGE HIS TO: 1<<WDP0 | 1<<WDP1  |  1<<WDP2;  (normal setting for 2 seconds)
       break;
    case 4:
        WDTCSR &= ~_BV(WDIE);                        
        MCUSR  &= ~(1<<WDRF);                        
        WDTCSR |=  (1<<WDCE) | (1<<WDE);   
        WDTCSR  =   1<<WDP3;  

      break;
    case 8:

        WDTCSR &= ~_BV(WDIE);                         
        MCUSR  &= ~(1<<WDRF);                         
        WDTCSR |=  (1<<WDCE) | (1<<WDE);               
        WDTCSR  =   1<<WDP3  |  1<<WDP0;

      break;  
    default: 
        WDTCSR &= ~_BV(WDIE);                         
        MCUSR  &= ~(1<<WDRF);                         
        WDTCSR |=  (1<<WDCE) | (1<<WDE);               
        WDTCSR  =   1<<WDP3  |  1<<WDP0;
        Serial.println("error");
  }
  delay(100);
  } 
  
  
  

  ISR(WDT_vect){
   
    if(calibrating==false){
      
      WDTCounter++;
      WDTCalCount++;
    }else{
      
      caliInt++;
      
      if(caliInt>=WDTCalCycles){ 
        calibrating=false;
      }
      
    }
    
  }   
  
  
  
  void enableWDT(){
        WDTCSR |= _BV(WDIE);              
  
  }   

                                                  
  void disableWDT(){                                      
        WDTCSR &= ~_BV(WDIE);                        
        MCUSR  &= ~(1<<WDRF);                        
  }

When I upload this, this sucker works (ARDUINO FIO). When I change case 2 as described....resetloop...goodluck and Im very curious!

Just to be absolutely sure, I uploaded above code on a pristine, out-of-the-box Arduino FIO, to rule out hardware failure, but the problem still persisted.

Code as given runs, when changing case 2 it goes into reset-loop.....pfff

And sorry about not posting code sooner. I somehow didnt see the first message and was doing the code while the second was posted...Guess I was just hoping I made some dumb typo in the code somewhere...

EDIT: Ok I guess Ill edit this post with more results.

The code above: I upload it with 'case 2' as it should be, which results in the crash. Now, like I said in my opening post(s), adding a small delay to 'case 4' (the case being called upon), removes the problem. I just found out that the same delay put in 'case 2' also prevents the reset-loop.

Sick of it all, I replaced the entire switch case in the give program with four separate voids to set each timer setting, per:

  void WDTset1(){
        WDTCSR &= ~_BV(WDIE);                         
        MCUSR  &= ~(1<<WDRF);                         
        WDTCSR |=  (1<<WDCE) | (1<<WDE);               
        WDTCSR  =   B00000110;                             //Slightly different way of doing it, though no difference
  }
  void WDTset2(){
        WDTCSR &= ~_BV(WDIE);                         
        MCUSR  &= ~(1<<WDRF);                         
        WDTCSR |=  (1<<WDCE) | (1<<WDE);               
        WDTCSR  =   B00000111;
  }
  void WDTset4(){
        WDTCSR &= ~_BV(WDIE);                        
        MCUSR  &= ~(1<<WDRF);                        
        WDTCSR |=  (1<<WDCE) | (1<<WDE);   
        WDTCSR  =   B00100000;
  }
  void WDTset8(){
        WDTCSR &= ~_BV(WDIE);                         
        MCUSR  &= ~(1<<WDRF);                         
        WDTCSR |=  (1<<WDCE) | (1<<WDE);               
        WDTCSR  =   B00100001;
  }

(Note that I changed the method of coding the register settings for the WDP bits. But dont worry, I also already did that earlier on and did NOT influence the errors.)

And then of course replaced the function calls in the main program. This solved the problem. I can pick any combination for the 2 calls and it works.

So for now, the problem must indeed be sought with the case switch itself it seems.

Coming half hour I will try to break the program again with delays and Serialprints....wish me luck :sweat_smile:

EDIT: No luck in breaking the separate methods version. Going back to the switch-case version, the following way of coding the ConfigureWDT(int seconds) method works:

 void configureWDT(int seconds){
  
   int testInt = seconds;
  
  switch (testInt) {
    case 1:
    Serial.println("setting 1 second");
    Serial.println(WDTCSR);
        WDTCSR &= ~_BV(WDIE);                         
        MCUSR  &= ~(1<<WDRF);                         
        WDTCSR |=  (1<<WDCE) | (1<<WDE);              
        WDTCSR  =   B00000110;
        Serial.println(WDTCSR);
      break;
    case 2:
    Serial.println("setting 2 second");
    Serial.println(WDTCSR);
        WDTCSR &= ~_BV(WDIE);                         
        MCUSR  &= ~(1<<WDRF);                         
        WDTCSR |=  (1<<WDCE) | (1<<WDE);               
        WDTCSR  =   B00000111;
        Serial.println(WDTCSR);
       break;
    case 4:
    Serial.println("setting 4 second");
    Serial.println(WDTCSR);
        WDTCSR &= ~_BV(WDIE);                        
        MCUSR  &= ~(1<<WDRF);                        
        WDTCSR |=  (1<<WDCE) | (1<<WDE);   
        WDTCSR  =   B00100000; 
        Serial.println(WDTCSR);
      break;
    case 8:
    Serial.println("setting 8 second");
    Serial.println(WDTCSR);
        WDTCSR &= ~_BV(WDIE);                         
        MCUSR  &= ~(1<<WDRF);                         
        WDTCSR |=  (1<<WDCE) | (1<<WDE);               
        WDTCSR  =   B00100001;
        Serial.println(WDTCSR);
      break;  
    default:
    ; 
    
       
  }
  
  }

The difference being here that the default case is emptied. Substituting the case 8 code in the default case, which I would like to have, breaks it again.

Why aren't you using wdt_enable()?

PeterH:
Why aren't you using wdt_enable()?

No real reason. I assume btw you are talking about the given library function, not my own function for it? When I got into making the FIO as energy-efficient as possible, I learned a lot about the deeper coding, behind the methods. I looked a lot into the 328P datasheet, which is very extensive, and some very nice project examples utilizing all possible power saving options. I think I implemented all but the wasteful standard voltage regulator on the FIO.

Anyway, this was the way I learned it myself, and it helps to understand what is actually being done and why. I also think that it should work as expected, given that I am pretty sure im coding things as supposed to be coded. Running into problems isnt a problem itself and can be fun and challenging, but this kind of totally unexpected/unpredictable behavior is annoying.

So while we are on the topic, did you have any luck putting it on a FIO and running the code?

I suggest you start by replacing your DIY implementation with the Arduino standard function, and see if that works correctly.

If it does, then compare the Arduino implementation against your one and see if you can spot your mistake.

I don't have an FIO available to test your code but I see no reason it would work any better for me than it does for you. Since your code accesses the hardware directly it's not inherently portable and I don't think that tests on a different Arduino variant will prove anything useful.

PeterH:
I suggest you start by replacing your DIY implementation with the Arduino standard function, and see if that works correctly.

If it does, then compare the Arduino implementation against your one and see if you can spot your mistake.

The line "...and see if you can spot your mistake." could sound like you know what might or is the problem? If so, could you elaborate?

As for your first point. I wouldnt have any problems switching to higher level implementations. The thing is, there shouldnt theoretically be anything wrong with it, im just following the datasheets. Many people have done it like I did (WDT part at least) and it also works for me...UNLESS its in that dreaded switch case. Besides, the libraries, again in theory because I didnt go through the WDT lib yet, SHOULD at its core do the exact same thing im doing.

If there were grave mistakes, the problem should occur more. Right now, the behavior is highly unpredictable....it might be some deeper lying error in the Arduino architecture for all I know....thats what Im trying to figure out. So, do you see, at the moment, any reason why my method doesnt work and behaves as described??

In my free time, Ill get to implementing the wdt lib and check back here.

I don't have an FIO available to test your code but I see no reason it would work any better for me than it does for you. Since your code accesses the hardware directly it's not inherently portable and I don't think that tests on a different Arduino variant will prove anything useful.

If you have an UNO around, it has the same ATMEGA chip (and thus watchdog version), maybe try that? Thats why you asked for the code right? Even though I expect the code to not work with your setup as well, what if it does? At least it will be a clue as to what is causing the problem. Maybe my hardware is busted afterall, even though I tested it on four FIO's, including out-of-the-box ones.

In short, Ill come back with results of the WDT lib, but in the meantime, if you or someone else could please comment on, or test my implementation, that would be great!

Thanks in advance!

Sorry, I didn't mean to imply that I knew the answer, although I can see how you interpreted it that way. If I knew the answer, I'd tell you.

I think it's likely that your manipulation of the hardware registers is wrong. I am prepared to take it on trust that the library implementation works correctly, implying that the problem is caused by a fault in your implementation. The easiest way IMO to locate the cause will be to compare the broken and working implementations.

I see the same symptoms - the behaviour is affected by trivial changes to the code that logically should not have any effect. I can reproduce the behaviour in a simpler sketch (shown below) which has the calibration logic removed.

For example, commenting out case 1 or the default case stopped the problem. Adding print statements to cases that weren't executed stopped the problem. (Commenting out case 8 did not stop the problem.)

Memory corruption might possibly cause erratic behaviour like this, but I can't see anything likely to cause memory corruption.

The only explanation I can think of is that the compiler is generating incorrect code (for example, assuming instruction alignment which does not occur) - unlikely as that seems.

I don't think it gets you much closer to understanding the problem, but if it's any consolation you are not alone in seeing and being baffled by this behaviour.

#include <avr/interrupt.h>        // interrupt routines
#include <avr/wdt.h>              // watchdogtimer functionality

const int WDTInterval = 4;
volatile byte ISR_FLAG = 0;

void setup()
{  
  Serial.begin(9600);
  Serial.println(__FILE__ " starting");
  configureWDT(WDTInterval);
}

void loop()
{
  Serial.println("Loop running");
  if(ISR_FLAG > 0)
  {
    ISR_FLAG = 0;
    Serial.println("ISR_FLAG was set");
  }
  delay(1000);
}

void configureWDT(int seconds)
{
  Serial.println("start configureWDT()"); delay(200);
  switch (seconds)
  {
  // commenting out case 1 clears the problem
  case 1: 
    WDTCSR &= ~_BV(WDIE);                         //Disable WDT before setting to proper value again
    MCUSR  &= ~(1<<WDRF);                         //Clear the WDT reset flag from the MCU register
    WDTCSR |=  (1<<WDCE) | (1<<WDE);              //Prepare register for changing WDT prescaler
    WDTCSR  =  (1<<WDP1) | (1<<WDP2);
    break;
    
  case 2:
    WDTCSR &= ~_BV(WDIE);                         
    MCUSR  &= ~(1<<WDRF);                         
    WDTCSR |=  (1<<WDCE) | (1<<WDE);               
    // commenting out Version B and uncommenting Version A clears the problem
    //WDTCSR  =   1<<WDP3; // version A 
    WDTCSR  =  (1<<WDP0) | (1<<WDP1) | (1<<WDP2); // Version B 
    break;
    
  case 4:
    WDTCSR &= ~_BV(WDIE);                        
    MCUSR  &= ~(1<<WDRF);                        
    WDTCSR |=  (1<<WDCE) | (1<<WDE);   
    WDTCSR  =   (1<<WDP3);  
    break;
/*
  // commenting out case 8 does not clear the problem
  case 8:
    WDTCSR &= ~_BV(WDIE);                         
    MCUSR  &= ~(1<<WDRF);                         
    WDTCSR |=  (1<<WDCE) | (1<<WDE);               
    WDTCSR  =  (1<<WDP3) | (1<<WDP0);
    break;  
*/    

  // commenting out the default case clears the problem
  default: 
    WDTCSR &= ~_BV(WDIE);                         
    MCUSR  &= ~(1<<WDRF);                         
    WDTCSR |=  (1<<WDCE) | (1<<WDE);               
    WDTCSR  =  (1<<WDP3) | (1<<WDP0);
    Serial.println("error");
   
}
  Serial.println("end configureWDT()"); delay(200);
} 

ISR(WDT_vect)
{
  ISR_FLAG = 1;
}

Thanks for the reply and the testing! If indeed the problem is somewhere deep in the compiler creating the machine code, I guess there is nothing left to do but work with other solutions and perhaps notify the Arduino developers of this problem. Too bad it turned out that way.

I will come back as soon as possible with the testing results of the WDT lib. I will try to use the exact same setup as described, but simply switch the register flipping with the lib function calls and see if that works.