Watchdog timer reset on Arduino Micro (32u4) board

In my project I am using a watchdog timer to reset the board in response to a user command. The board is likely to be sitting at the back of instrumentation so the reset button may not be easily accessible, so it seemed prudent to provide the user with a means to remotely reset the board.

The code is quite simple. It defines a 3 second delay, enabled the watchdog and waits for the reset to occur. On non-AVR boards (which may not support watchdog), for the present, execution jumps to address zero and restarts the sketch.

On the Uno, Nano and Mega 2560 this works just fine. However, on the 32u4 based Micro, as expected, the terminal session is dropped, but the serial port (/dev/ttyACM0 on Linux) is dropped but not re-established on the PC so it is not possible to connect back in to the board over USB. The board is left with the two activity lights flashing rapidly. It has to be physically disconnected from USB and plugged back in again to reset it properly.

While power cycling is one way around the problem, I was wondering whether there is a neater solution that would allow the MCU to come back up and re-establish the serial port?

#ifdef __AVR__
  #include <avr/wdt.h>
#endif

void rst_h() {
#ifdef WDTO_60MS
  // Where defined, reset controller using watchdog timeout
  unsigned long tout;
  tout = millis() + 3000;
  wdt_enable(WDTO_60MS);
  while (millis() < tout) {};
  // Should never reach here....
  if (isVerb) {
    Serial.println(F("Reset FAILED."));
  };
#else
  // Otherwise restart program
  resetProg();
#endif
}
void(* resetProg) (void) = 0;//declare reset function at address 0

I should also perhaps point out that at present I have no bootloader installed on the Micro as I am uploading the sketch with a USBASP programmer. I have not been able to program the board via USB from the Arduino IDE. I can burn the bootloader, but not upload the sketch.

While power cycling is one way around the problem, I was wondering whether there is a neater solution that would allow the MCU to come back up and re-establish the serial port?

What bootloader are you using? Was it compiled with the new LUFA drivers? If you got a board with the old bootloader it might get stuck in the bootloader code never reaching the main sketch code.

I should also perhaps point out that at present I have no bootloader installed on the Micro as I am uploading the sketch with a USBASP programmer. I have not been able to program the board via USB from the Arduino IDE. I can burn the bootloader, but not upload the sketch.

Current IDEs offer the option to upload the sketch including the bootloader with an ICSP programmer.
Was the inability to upload a sketch before you removed the bootloader or was the bootloader not working?

If you have not bootloader installed, does your sketch (at first, before anything else) disable the WDT? Otherwise the WDT will reset the Arduino in a loop!

Thanks for the reply.

pylon:
What bootloader are you using? Was it compiled with the new LUFA drivers? If you got a board with the old bootloader it might get stuck in the bootloader code never reaching the main sketch code.

Sorry, I am not familiar with LUFA drivers and have no way of knowing whether the bootloader that came with the board was compiled with such a driver. I am not using LUFA drivers myself or compiling a custom bootloader. I was able to "rescue" the board using a usbasp AVR programmer by means of the 'Burn Bootloader' option under the Tools menu in IDE version 1.8.9. After the "rescue" it would have used whatever came with this version of the IDE.

pylon:
Current IDEs offer the option to upload the sketch including the bootloader with an ICSP programmer.
Was the inability to upload a sketch before you removed the bootloader or was the bootloader not working?

It crashed the very first time I tried to upload a sketch from the Arduino IDE via USB. I am using the 'Genuino Micro' board option. So, yes, the inability to upload the sketch was there from the start. It seems that these boards might require the reset button to be pressed before or during the upload, but I tried that multiple times as well with different timings for the reset. I would attach a file with details of the errors, but it seems that I can't do attachments on here.

I can see the option under Tools to 'Burn Bootloader' and the separate option under Sketch to 'Upload using programmer', but I don't see an option to upload both together in version 1.8.9 or 1.8.10. Of course, I may be missing something. It was my understanding that 'Upload using programmer' wipes the memory and then uploads only the sketch without bootloader.

pylon:
If you have not bootloader installed, does your sketch (at first, before anything else) disable the WDT? Otherwise the WDT will reset the Arduino in a loop!

No, my sketch does not disable WDT anywhere. The only bit of WDT code I have is shown above.
I have read about the loop problem, but that was in older posts and I thought that it affected older bootloaders?

UPDATE: I added wdt_disable(); at the beginning of void setup() but this has made no difference.

I have read about the loop problem, but that was in older posts and I thought that it affected older bootloaders?

Yes, older bootloaders as they didn't disable the WDT. If you don't have a bootloader but use the WDT you have to disable it, otherwise it will hit again and again.

I can see the option under Tools to 'Burn Bootloader' and the separate option under Sketch to 'Upload using programmer', but I don't see an option to upload both together in version 1.8.9 or 1.8.10. Of course, I may be missing something. It was my understanding that 'Upload using programmer' wipes the memory and then uploads only the sketch without bootloader.

Correct. That was another function I had in mind. If you export your binary you get both versions, with and without bootloader.

UPDATE: I added wdt_disable(); at the beginning of void setup() but this has made no difference.

What happens if you make the WDT timeout longer (p.e. 1sec.)?

pylon:
Correct. That was another function I had in mind. If you export your binary you get both versions, with and without bootloader.

Sorry, I had completely missed that! Since there was no save dialog, at first I thought this didn't do anything, although something does seem to happen in the background. I then discovered that it places the two binary version files in the same directory as the source. Thanks for pointing that out.

pylon:
What happens if you make the WDT timeout longer (p.e. 1sec.)?

I tried that, and this time both with and without the bootloader. The good news is that with the version of the binary that contains the bootloader it does now work. The serial session is dropped, but the LEDs remain stable. I can then connect back in whereupon the sketch re-starts and runs.

Without the bootloader it still hangs. I placed the wdt_disable(); statement as the fist command in void setup(), which is the earliest point where it can be inserted. It is not possible to place calls to functions before that and outside of a function. I also extended the timeout to 8 seconds and the wait loop to something a little above that. All this seemed to do was insert a delay between the reset command being issued and the rapidly flashing lights kicking in. I also tried just calling the zero address to restart the sketch, but that just seems to 'hangs' the board and it becomes unresponsive.

The upshot is that at least it works with the bootloader, so thank you for that. I wonder whether the bootloader does something to set up or re-initialise the USB stack that my sketch is missing?

The upshot is that at least it works with the bootloader, so thank you for that. I wonder whether the bootloader does something to set up or re-initialise the USB stack that my sketch is missing?

Yes, it calls the initialization code of the LUFA driver. I don't know what exactly that one does differently than the Arduiono CDC code but don't find the time to compare the code in detail.

I’ve been struggling through a similar problem on a custom board running with a 32u4.
I am programming the board with a sparkfun AVR pocket-programmer, using avrdude command line.

For me, the WDT reset worked as expected when I had a bootloader installed. However if i programmed without a bootloader, the controller would seize up somewhere after the first timeout.

In my setup() function, I had previously initialized the WDT like this:

void setup(void) {
 wdt_disable();
 // other setup code
 cli(); 
 wdt_reset();
 WDTCSR |= B00011000; 
 WDTCSR = (1<<WDE)|(1<<WDP2)|(1<<WDP1);
 sei();
}

In my loop I used a button to simulate a seize-up to make sure the WDT works (only called wdt_reset() if the button was in the “up” state, so I could have it time-out by holding the button down). One obvious solution is to just keep the bootloader on there, but for our application we just can’t do that for various reasons.

After plenty of digging and reading about Fuses and Reset Vectors … I got it to work with the following setup function:

void setup(void) {
 wdt_enable(WDTO_1S);
 MCUSR = 0x00;
 // other setup code
 cli(); 
 wdt_reset();
 WDTCSR |= B00011000; 
 WDTCSR = (1<<WDE)|(1<<WDP2)|(1<<WDP1);
 sei();
}

I’m not sure which part got it to work, but it works now.
Give it a try, hopefully it can help.

Thank you for the suggestion and sorry for the very delayed reply. I tried the code in the second snippet but found that the board goes into a reset loop. The key I think is to understanding what happens when the board goes into that state where the two leds are flashing rapidly and what goes on within the bootloader to prevent that.