Use a board specific bootloader and application start
authorPeter Henn <Peter.Henn@web.de>
Fri, 31 Dec 2021 04:35:47 +0000 (04:35 +0000)
committerPeter Henn <Peter.Henn@web.de>
Fri, 7 Jan 2022 12:14:48 +0000 (12:14 +0000)
- Add board specific Application_Jump_Check match for Pro-Micro
  and Micro boards
- Add in fixed FUSE_BOOTRST check in Application_Jump_Check for
  all other boards
- Enhance MagicBootKey handling
- Let Reset flags untouched for application code if reset was not
  forced by the bootloader

Bootloaders/DFU/BootloaderDFU.c

index eb6c069..ec8f0fa 100644 (file)
@@ -131,7 +131,53 @@ void Application_Jump_Check(void)
 
                /* 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 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))
+                         JumpToApplication = true;
+
+                       /* Clear reset source */
+                       MCUSR &= ~(1 << EXTRF);
+               }
+               else
                {
                        /* 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 */
@@ -143,6 +189,9 @@ void Application_Jump_Check(void)
                }
        #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);
 
@@ -150,12 +199,8 @@ void Application_Jump_Check(void)
        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)();
        }