/*
LUFA Library
- Copyright (C) Dean Camera, 2018.
+ Copyright (C) Dean Camera, 2021.
dean [at] fourwalledcubicle [dot] com
www.lufa-lib.org
*/
/*
- Copyright 2018 Dean Camera (dean [at] fourwalledcubicle [dot] com)
+ Copyright 2021 Dean Camera (dean [at] fourwalledcubicle [dot] com)
Permission to use, copy, modify, distribute, and sell this
software and its documentation for any purpose is hereby granted
/* Re-enable JTAG debugging */
JTAG_ENABLE();
+ #elif ((BOARD == BOARD_PROMICRO) || (BOARD == BOARD_MICRO))
+ /* Pro-Micro and Arduino Micro board use power-on reset, but no external reset. Both boards have
+ * the hardware bootloader pin HWBE enabled. Unfortunately only the external reset allows together
+ * with an enabled HWBE that the CPU start at the bootloader address independent of the FUSE_BOOTRST.
+ * That means the power-on reset will start just controlled by the FUSE_BOOTRST the bootloader or
+ * direct in the application and cannot be overridden by HWBE signal. Therfore FUSE_BOOTRST shall
+ * be enabled, otherwise the bootloader will not be reached for these boards.
+ * The bootloader checks FUSE_HWBE as *unprogammed* instead of FUSE_BOOTRST as programmed on other
+ * board variants to decide fast application start, without waiting the dedicted bootloader timeout
+ * in case of a USB, watchdog, brown-out or JTAG reset. If the watchdog reset was initiated from
+ * the bootloader marked with the MAGIC_BOOT_KEY this reset flag is reset. All other reset flags
+ * are left untouched to allow the application code checking the reset signals, especially in case
+ * of application fast start.
+ * The bootloader is entered always for external reset and power-on reset. But the bootloader is
+ * anyway exited after that dedicted timeout, if a reset-vector to the application is programmed.
+ * Once a DFU program interacts this the bootloader during this dedicted timeout, the timer stops
+ * and the application needs to be started by DFU bootloader command manually or using a reset.
+ */
+
+ /* Check if the device's forced Bootloader via Hardware Bootenable is unprogrammed */
+ if (BootloaderAPI_ReadFuse(GET_EXTENDED_FUSE_BITS) & ~FUSE_HWBE)
+ {
+ /* If the reset source was not an external or power-on reset jump to the application */
+ if (!(MCUSR & ((1 << EXTRF) || (1 << PORF))))
+ JumpToApplication = true;
+ }
+ /* If the reset source was the bootloader and the key is correct, clear it and jump to the application;
+ * this can happen in the HWBE fuse is set, and the HBE pin is low during the watchdog reset */
+ if ((MCUSR & (1 << WDRF)) && (MagicBootKey == MAGIC_BOOT_KEY))
+ {
+ JumpToApplication = true;
+
+ /* Clear reset source */
+ MCUSR &= ~(1 << WDRF);
+ }
#else
/* Check if the device's BOOTRST fuse is set */
- if (BootloaderAPI_ReadFuse(GET_HIGH_FUSE_BITS) & FUSE_BOOTRST)
+ if (!(BootloaderAPI_ReadFuse(GET_HIGH_FUSE_BITS) & ~FUSE_BOOTRST))
{
/* If the reset source was not an external reset or the key is correct, clear it and jump to the application */
if (!(MCUSR & (1 << EXTRF)) || (MagicBootKey == MAGIC_BOOT_KEY))
}
#endif
+ /* Clear the boot key in any case */
+ MagicBootKey = 0;
+
/* Don't run the user application if the reset vector is blank (no app loaded) */
bool ApplicationValid = (pgm_read_word_near(0) != 0xFFFF);
if (JumpToApplication && ApplicationValid)
{
/* Turn off the watchdog */
- MCUSR &= ~(1 << WDRF);
wdt_disable();
- /* Clear the boot key and jump to the user application */
- MagicBootKey = 0;
-
// cppcheck-suppress constStatement
((void (*)(void))0x0000)();
}
}
+
+static volatile bool stayinbootloader;
+
/** Main program entry point. This routine configures the hardware required by the bootloader, then continuously
* runs the bootloader processing routine until instructed to soft-exit, or hard-reset via the watchdog to start
* the loaded application code.
GlobalInterruptEnable();
/* Run the USB management task while the bootloader is supposed to be running */
+ stayinbootloader = false;
+
+ uint16_t i = 0;
while (RunBootloader || WaitForExit)
- USB_USBTask();
+ {
+ USB_USBTask();
+
+ if (!stayinbootloader)
+ {
+ Delay_MS(1);
+ if (i++ > 5000)
+ {
+ if (pgm_read_word_near(0) != 0xFFFF)
+ break;
+ else
+ i = 0;
+ }
+ }
+ else
+ {
+ i = 0;
+ }
+ }
/* Wait a short time to end all USB transactions and then disconnect */
_delay_us(1000);
return;
}
+stayinbootloader = true;
+
/* Activity - toggle indicator LEDs */
LEDs_ToggleLEDs(LEDS_LED1 | LEDS_LED2);
else // Start via jump
{
/* Set the flag to terminate the bootloader at next opportunity if a valid application has been loaded */
- if (pgm_read_word_near(0) == 0xFFFF)
+ if (pgm_read_word_near(0) != 0xFFFF)
RunBootloader = false;
}
}