Optiboot doesn't prevent infinite Watchdog Reset Loop

Hi all,

I'm having a problem with an infinite watchdog Reset loop in my Arduino nano.

My main starts with the following code:

int main(void){ 
  
      //WDT_off(0);
      //WDT_Prescaler_Change(0);
      MCUSR &= ~(1 << WDRF);
      wdt_disable();
      setPWMOutput();
      uart_init();
      state = 1;
  
      _delay_ms(5);
      printf("wdt off..\n");
      _delay_ms(5);
      setTimers();
          
      nrf24_init();
      nrf24_start_listening();
     //....

I'm aware of the infinite reset loop bug on the old Arduino bootloader. Therefore, I downloaded the latest Optiboot (8.0 from 2018 here GitHub - Optiboot/optiboot: Small and Fast Bootloader for Arduino and other Atmel AVR chips).
Since I'm using the Arduino nano, I burned the optiboot with the following settings:

  • Optiboot on 32-bit cpus
  • Atmega328p
  • CPU Speed : 16MHz
  • ATMEL-ICE programmer (I'm using this programmer)

By the way, I get a verification error when the optiboot is burned:

avrdude: 1 bytes of lock written
avrdude: verifying lock memory against 0x2F:
avrdude: load data lock data from input file 0x2F:
avrdude: input file 0x2F contains 1 bytes
avrdude: reading on-chip lock data:

Reading | ################################################## | 100% 0.01s

avrdude: verifying ...
avrdude: verification error, first mismatch at byte 0x0000
         0xff != 0x2f
avrdude: verification error; content mismatch

However, looking it up on the internet, it appears that it doesn't prevent the optiboot being burned into the chip.

The file containing the main() above is compiled and then uploaded with the following command:

avrdude -v -p atmega328p -c arduino -P /dev/ttyUSB0 -b 115200 -D -U flash:w:RX_bike.hex:i

Unfortunately, if I open the USB0 port with CuteCom, I see that the line "printf("wdt off...\n")" gets printed indefinitely in a loop.

I can't exactly tell what I'm doing wrong. Could I get some help? I've been stuck on this for days already

It seems to work OK here. The following sketch behaves as it ought to: about 2s worth of "wdt disabled" messages, followed by 1s worth of "wdt enabled" messages (at which point the WDT fires and it resets and starts over.) (This is with optiboot 8.3.)

#include <avr/wdt.h>

void setup() {
  MCUSR &= ~(1 << WDRF);
  wdt_disable();
  Serial.begin(115200);
  Serial.println("Setup Complete");
  for (int i = 0; i < 10; i++) {
    Serial.println("delaying with WDT disabled");
    delay(200);
  }
  Serial.println("enabling WDT 1S");
  wdt_enable(WDTO_1S);

}

void loop() {
  Serial.println("wdt enabled");
  delay(300);
}

Could you post a complete, minimal program that exhibits the problem - the the snippet you showed in the OP, I don't see where the WDT is ever turned on, for example.

Also, how are you burning Optiboot? These days, the preferred method would be to use MCUDude's "MiniCore" and the "burn bootloader" command after setting the (much larger) set of board parameters correctly.

A full log from the burn process might be helpful, as well.

Hi westfw, many thanks for your reply.
I tried reducing my program to something minimal to reproduce the problem. However, I was not able to reproduced it.

I just wrote it like this:

int main(void){ 

    //WDT_off(0);
    //WDT_Prescaler_Change(0);
    MCUSR &= ~(1 << WDRF);
    wdt_disable();
    uart_init();
    state = 1;

    _delay_ms(5);
    printf("wdt off..\n");
    _delay_ms(5);
    setTimers();

    while(1){

        _delay_ms(2);
        printf("while..\n");
        _delay_ms(2);
    }   
}

The printf line within the while-loop was being printed indefinitely instead of the "wdt off", which is the expected behavior.

Upon double checking the differences between my program and this one, I found that this line is the culprit:

setPWMOutput()

My receiver needs to send a PWM signal into a buzzer when it receives data via the nrf24l01. I defined this function as follows:

static inline void setPWMOutput(void){
    //TCCR1A
    //Toggle OC1A/OC1B on compare match
    //Fast PWM
    // In non-inverting compare output mode, output compare OC1A is cleared
    // on the compare match and cleared at BOTTOM.
    TCCR1A = (1 << COM1A0) | (0 << COM1A1);

    //WGM13:WGM10 = 15
    //15 = 0b1111
    //When 15 = TOP=OCR1A
    TCCR1A |= (1 << WGM11) | (1 << WGM10);
    TCCR1B = (1 << WGM13) | (1 << WGM12);
    
    // Play a Treble Do = 523.251Hz
    // fclk/Do = 30578
    // N*(1+TOP) = 30578
    // Set divider to 64
    // 30578/64 = (1+TOP)
    // 477.478 = (1+TOP)
    // TOP = 476 ~480

    //Set pre-scaler to CLK/64
    TCCR1B |= (1 << CS11) | (1 << CS10);

    //Set TOP 
    writeOCR1A(480);

    //Since we have set the counter to compare against OCR1A...
    //Set OCIE1A to enable the the Output Compare A Match Interrupt Enable

    TIMSK1 |= (1 << OCIE1A);
    //execute ISR for this interrupt vector

}

Basically, if I delete this call from my original main() program, the wdt_off isn't being printed indefinitely.

Another thing that might be of relevance is that I noticed the red LED (that flickers when you press reset) is completely turned off while these "wdt off" lines are being printed indefinitely (when that PWM function is called). If I understood correctly, the WDT reset everyone talks about means that the uC is being reset indefenitely, which means that this red LED should be flickering all the time. Perhaps I'm looking at some different problem here?

With regards to the burning of the Optiboot, I use the settings I wrote in my original post and burn it via the "burn bootloader" function of the Arduino IDE (v1.8.15).

Here's the full log:

snap/arduino/61/hardware/tools/avr/bin/avrdude -C/snap/arduino/61/hardware/tools/avr/etc/avrdude.conf -v -patmega328p -catmelice_isp -Pusb -e -Ulock:w:0x3F:m -Uefuse:w:0x05:m -Uhfuse:w:0xDE:m -Ulfuse:w:0xF7:m 

avrdude: Version 6.3-20190619
         Copyright (c) 2000-2005 Brian Dean, http://www.bdmicro.com/
         Copyright (c) 2007-2014 Joerg Wunsch

         System wide configuration file is "/snap/arduino/61/hardware/tools/avr/etc/avrdude.conf"
         User configuration file is "/home/ernesto/snap/arduino/61/.avrduderc"
         User configuration file does not exist or is not a regular file, skipping

         Using Port                    : usb
         Using Programmer              : atmelice_isp
avrdude: usbdev_open(): Found Atmel-ICE CMSIS-DAP, serno: J42700017959
avrdude: usbdev_open(): WARNING: failed to set configuration 1: Device or resource busy
avrdude: Found CMSIS-DAP compliant device, using EDBG protocol
         AVR Part                      : ATmega328P
         Chip Erase delay              : 9000 us
         PAGEL                         : PD7
         BS2                           : PC2
         RESET disposition             : dedicated
         RETRY pulse                   : SCK
         serial program mode           : yes
         parallel program mode         : yes
         Timeout                       : 200
         StabDelay                     : 100
         CmdexeDelay                   : 25
         SyncLoops                     : 32
         ByteDelay                     : 0
         PollIndex                     : 3
         PollValue                     : 0x53
         Memory Detail                 :

                                  Block Poll               Page                       Polled
           Memory Type Mode Delay Size  Indx Paged  Size   Size #Pages MinW  MaxW   ReadBack
           ----------- ---- ----- ----- ---- ------ ------ ---- ------ ----- ----- ---------
           eeprom        65    20     4    0 no       1024    4      0  3600  3600 0xff 0xff
           flash         65     6   128    0 yes     32768  128    256  4500  4500 0xff 0xff
           lfuse          0     0     0    0 no          1    0      0  4500  4500 0x00 0x00
           hfuse          0     0     0    0 no          1    0      0  4500  4500 0x00 0x00
           efuse          0     0     0    0 no          1    0      0  4500  4500 0x00 0x00
           lock           0     0     0    0 no          1    0      0  4500  4500 0x00 0x00
           calibration    0     0     0    0 no          1    0      0     0     0 0x00 0x00
           signature      0     0     0    0 no          3    0      0     0     0 0x00 0x00

         Programmer Type : JTAG3_ISP
         Description     : Atmel-ICE (ARM/AVR) in ISP mode
         Vtarget         : 4.8 V
         SCK period      : 125.00 us

avrdude: AVR device initialized and ready to accept instructions

Reading | ################################################## | 100% 0.01s

avrdude: Device signature = 0x1e950f (probably m328p)
avrdude: erasing chip
avrdude: reading input file "0x3F"
avrdude: writing lock (1 bytes):

Writing | ################################################## | 100% 0.00s

avrdude: 1 bytes of lock written
avrdude: verifying lock memory against 0x3F:
avrdude: load data lock data from input file 0x3F:
avrdude: input file 0x3F contains 1 bytes
avrdude: reading on-chip lock data:

Reading | ################################################## | 100% 0.01s

avrdude: verifying ...
avrdude: WARNING: invalid value for unused bits in fuse "lock", should be set to 1 according to datasheet
This behaviour is deprecated and will result in an error in future version
You probably want to use 0xff instead of 0x3f (double check with your datasheet first).
avrdude: 1 bytes of lock verified
avrdude: reading input file "0x05"
avrdude: writing efuse (1 bytes):

Writing | ################################################## | 100% 0.09s

avrdude: 1 bytes of efuse written
avrdude: verifying efuse memory against 0x05:
avrdude: load data efuse data from input file 0x05:
avrdude: input file 0x05 contains 1 bytes
avrdude: reading on-chip efuse data:

Reading | ################################################## | 100% 0.00s

avrdude: verifying ...
avrdude: WARNING: invalid value for unused bits in fuse "efuse", should be set to 1 according to datasheet
This behaviour is deprecated and will result in an error in future version
You probably want to use 0xfd instead of 0x05 (double check with your datasheet first).
avrdude: 1 bytes of efuse verified
avrdude: reading input file "0xDE"
avrdude: writing hfuse (1 bytes):

Writing | ################################################## | 100% 0.09s

avrdude: 1 bytes of hfuse written
avrdude: verifying hfuse memory against 0xDE:
avrdude: load data hfuse data from input file 0xDE:
avrdude: input file 0xDE contains 1 bytes
avrdude: reading on-chip hfuse data:

Reading | ################################################## | 100% 0.00s

avrdude: verifying ...
avrdude: 1 bytes of hfuse verified
avrdude: reading input file "0xF7"
avrdude: writing lfuse (1 bytes):

Writing | ################################################## | 100% 0.09s

avrdude: 1 bytes of lfuse written
avrdude: verifying lfuse memory against 0xF7:
avrdude: load data lfuse data from input file 0xF7:
avrdude: input file 0xF7 contains 1 bytes
avrdude: reading on-chip lfuse data:

Reading | ################################################## | 100% 0.01s

avrdude: verifying ...
avrdude: 1 bytes of lfuse verified

avrdude done.  Thank you.

/snap/arduino/61/hardware/tools/avr/bin/avrdude -C/snap/arduino/61/hardware/tools/avr/etc/avrdude.conf -v -patmega328p -catmelice_isp -Pusb -Uflash:w:/home/ernesto/snap/arduino/61/.arduino15/packages/Optiboot/hardware/avr/0.8.0/bootloaders/optiboot/optiboot_atmega328.hex:i -Ulock:w:0x2F:m 

avrdude: Version 6.3-20190619
         Copyright (c) 2000-2005 Brian Dean, http://www.bdmicro.com/
         Copyright (c) 2007-2014 Joerg Wunsch

         System wide configuration file is "/snap/arduino/61/hardware/tools/avr/etc/avrdude.conf"
         User configuration file is "/home/ernesto/snap/arduino/61/.avrduderc"
         User configuration file does not exist or is not a regular file, skipping

         Using Port                    : usb
         Using Programmer              : atmelice_isp
avrdude: usbdev_open(): Found Atmel-ICE CMSIS-DAP, serno: J42700017959
avrdude: Found CMSIS-DAP compliant device, using EDBG protocol
         AVR Part                      : ATmega328P
         Chip Erase delay              : 9000 us
         PAGEL                         : PD7
         BS2                           : PC2
         RESET disposition             : dedicated
         RETRY pulse                   : SCK
         serial program mode           : yes
         parallel program mode         : yes
         Timeout                       : 200
         StabDelay                     : 100
         CmdexeDelay                   : 25
         SyncLoops                     : 32
         ByteDelay                     : 0
         PollIndex                     : 3
         PollValue                     : 0x53
         Memory Detail                 :

                                  Block Poll               Page                       Polled
           Memory Type Mode Delay Size  Indx Paged  Size   Size #Pages MinW  MaxW   ReadBack
           ----------- ---- ----- ----- ---- ------ ------ ---- ------ ----- ----- ---------
           eeprom        65    20     4    0 no       1024    4      0  3600  3600 0xff 0xff
           flash         65     6   128    0 yes     32768  128    256  4500  4500 0xff 0xff
           lfuse          0     0     0    0 no          1    0      0  4500  4500 0x00 0x00
           hfuse          0     0     0    0 no          1    0      0  4500  4500 0x00 0x00
           efuse          0     0     0    0 no          1    0      0  4500  4500 0x00 0x00
           lock           0     0     0    0 no          1    0      0  4500  4500 0x00 0x00
           calibration    0     0     0    0 no          1    0      0     0     0 0x00 0x00
           signature      0     0     0    0 no          3    0      0     0     0 0x00 0x00

         Programmer Type : JTAG3_ISP
         Description     : Atmel-ICE (ARM/AVR) in ISP mode
         Vtarget         : 4.9 V
         SCK period      : 125.00 us

avrdude: AVR device initialized and ready to accept instructions

Reading | ################################################## | 100% 0.02s

avrdude: Device signature = 0x1e950f (probably m328p)
avrdude: NOTE: "flash" memory has been specified, an erase cycle will be performed
         To disable this feature, specify the -D option.
avrdude: erasing chip
avrdude: reading input file "/home/ernesto/snap/arduino/61/.arduino15/packages/Optiboot/hardware/avr/0.8.0/bootloaders/optiboot/optiboot_atmega328.hex"
avrdude: writing flash (32768 bytes):

Writing | ################################################## | 100% 0.00s

avrdude: 32768 bytes of flash written
avrdude: verifying flash memory against /home/ernesto/snap/arduino/61/.arduino15/packages/Optiboot/hardware/avr/0.8.0/bootloaders/optiboot/optiboot_atmega328.hex:
avrdude: load data flash data from input file /home/ernesto/snap/arduino/61/.arduino15/packages/Optiboot/hardware/avr/0.8.0/bootloaders/optiboot/optiboot_atmega328.hex:
avrdude: input file /home/ernesto/snap/arduino/61/.arduino15/packages/Optiboot/hardware/avr/0.8.0/bootloaders/optiboot/optiboot_atmega328.hex contains 32768 bytes
avrdude: reading on-chip flash data:

Reading | ################################################## | 100% 0.00s

avrdude: verifying ...
avrdude: 32768 bytes of flash verified
avrdude: reading input file "0x2F"
avrdude: writing lock (1 bytes):

Writing | ################################################## | 100% 0.00s

avrdude: 1 bytes of lock written
avrdude: verifying lock memory against 0x2F:
avrdude: load data lock data from input file 0x2F:
avrdude: input file 0x2F contains 1 bytes
avrdude: reading on-chip lock data:

Reading | ################################################## | 100% 0.01s

avrdude: verifying ...
avrdude: verification error, first mismatch at byte 0x0000
         0xff != 0x2f
avrdude: verification error; content mismatch

avrdude done.  Thank you.

Error while burning bootloader.

I think that means that this is neither an optiboot nor a watchdog problem!
Probably you have mis-named or left out the ISR() function for the OCR1A interrupt; the compiler fills in all of the vectors that it thinks are "unused" with a jump to "__bad_intrrupt", which reads:

00000930 <__bad_interrupt>:
     930:       0c 94 00 00     jmp     0       ; 0x0 <__vectors>

That will have the effect of re-starting your program, similar to a WDT reset.

You could check for sure by changing the start of your code to:

int main(void) { 
    MCUSR &= ~(1 << WDRF);
    wdt_disable();
    uart_init();
    state = 1;

    _delay_ms(5);
    printf("Program start..\n");
    _delay_ms(9000);
    printf("past 8000ms WDT period");
      :

(If there's a WDT problem, you'd get repeated "Program Start" messages. If you get the "past 8000ms" message, then it's something else.)

(But it's probably a better use of time to check the ISR definition first. I believe you'd need to have an ISR(TIMER1_COMPA_vect) { } function somewhere. If you miss-spell or incorrectly capitalize it, the compiler might not be very good about indicating the error. And it's completely silent if you just forgot it.)

2 Likes