Skip to content

Infinite WDT Reset Loop After Software Jump into Bootloader #386

@GregorB54321

Description

@GregorB54321

Issue: Infinite WDT Reset Loop After Software Jump into Bootloader

Summary

When an application forces a jump into Optiboot via software (after clearing MCUSR), Optiboot runs and waits for STK500 traffic. If a timeout occurs, Optiboot correctly triggers a Watchdog Timer (WDT) reset. However, after this reset, Optiboot evaluates the WDRF flag, decides to immediately jump back to the application (APP_START_REASONS), but fails to disable the watchdog before doing so. This traps the application in a rapid ~15ms WDT reset loop unless the application itself explicitly calls wdt_disable() extremely early during initialization.

Scenario Description

Step 1: Application Initiates Jump

The application requests the bootloader by clearing MCUSR and jumping to the bootloader section:

MCUSR = 0;
// Example: jump to (FLASHEND - 511) >> 1
jumpToBootloader();

Step 2: Optiboot Runs

  • Optiboot initializes normally (LED flashes).
  • Optiboot waits for STK500 protocol communication (usually a 1-second timeout).

Step 3: Timeout Occurs → WDT Reset Triggered

With no upload traffic arriving, the WDT expires. The MCU resets and returns to Optiboot.

Step 4: The Problem

Upon this reset, MCUSR contains WDRF (but not EXTRF). Based on the Optiboot logic, Optiboot decides to skip the bootloader and jump straight to the application. Critical Error: In this specific code path, the watchdog is not reliably disabled before handing control back to the application.

Actual Behavior

Optiboot jumps to the application while the 15ms watchdog is still armed and ticking. The MCU behaves as follows:

  1. Application starts.
  2. ~15ms later: WDT triggers a reset.
  3. Optiboot checks MCUSR, sees WDRF again, and jumps straight back to the application.
  4. ~15ms later: WDT triggers a reset.
    (Result: Infinite rapid reset loop, observable as a ~15Hz flickering LED)

Expected Behavior

Whenever Optiboot decides to hand control back to the application, it must ensure a pristine environment—this strictly includes disabling the Watchdog Timer, exactly as it does on a normal successful upload or when exiting via other paths.

Root Cause Analysis in Optiboot Source

Optiboot attempts to disable the watchdog via WDTCSR but does not reliably clear WDRF in MCUSR on all code paths that jump to the application. On some AVR hardware states, if WDRF is set in MCUSR, the watchdog remains effectively active even if WDTCSR writes attempt to clear WDE. As a result, Optiboot may hand control back to the application with a still-armed short-period watchdog.

Steps to Reproduce

  1. Flash an ATmega328P with standard Optiboot.
  2. Upload a sketch that does NOT implement an early .init3 watchdog disable routine.
  3. Trigger a software bootloader jump (MCUSR = 0; asm("jmp 0x7E00");).
  4. Wait 1 second for the Optiboot timeout.
  5. Observe the MCU enter a rapid reset loop (LED pulsing at high frequency).
  6. Press the physical RESET button (sets EXTRF). The application will then boot normally because EXTRF fulfills the condition that allows Optiboot to properly disable the WDT.

Suggested Fix

Optiboot must ensure the watchdog is disabled before jumping to the application in all exit paths. Possible remedies:

  • Unconditionally clear WDRF from MCUSR before calling watchdogConfig(WATCHDOG_OFF) and before any direct appstart jump.
  • Or, add an explicit watchdogConfig(WATCHDOG_OFF) sequence that is guaranteed to take effect even when WDRF is present (for example, using the documented sequence to disable WDT on affected AVR devices).

Notes

This issue arises specifically when the bootloader has been reached via a software-initiated jump and then times out waiting for STK500 traffic. Physical RESET (EXTRF) or a normal bootloader upload path do not show the same loop because the reset reason and clearing sequence differ.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions