Enhance USB Interrupt responsibility
[pub/lufa.git] / Bootloaders / DFU / BootloaderDFU.c
index 3e2f330..ce76abe 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)();
        }
@@ -174,22 +219,12 @@ int main(void)
        SetupHardware();
 
        /* Turn on first LED on the board to indicate that the bootloader has started */
-       //LEDs_SetAllLEDs(LEDS_LED1);
+       LEDs_SetAllLEDs(LEDS_LED1);
 
        /* Enable global interrupts so that the USB stack can function */
        GlobalInterruptEnable();
 
        /* Run the USB management task while the bootloader is supposed to be running */
-       /*if bit_is_clear(PINB,PB5)     // PB5 is Digital 9 on Arduino Pro Micro
-       {
-               loop_until_bit_is_set(PINB,PB5);
-
-               while ((RunBootloader || WaitForExit) && bit_is_set(PINB,PB5))
-                       USB_USBTask();
-
-               loop_until_bit_is_clear(PINB,PB5);
-       }*/
-
        stayinbootloader = false;
 
        uint16_t i = 0;
@@ -199,10 +234,13 @@ int main(void)
 
                if (!stayinbootloader)
                {
-                       _delay_ms(1);
+                       Delay_MS(1);
                        if (i++ > 5000)
                        {
-                               break;
+                               if (pgm_read_word_near(0) != 0xFFFF)
+                                       break;
+                               else
+                                       i = 0;
                        }
                }
                else
@@ -237,11 +275,7 @@ static void SetupHardware(void)
 
        /* Initialize the USB and other board hardware drivers */
        USB_Init();
-       //LEDs_Init();
-       DDRB = 1;
-       PORTB = _BV(PB5);
-       DDRD = 0b00100000;
-       PORTD = 0;
+       LEDs_Init();
 
        /* Bootloader active LED toggle timer initialization */
        TIMSK1 = (1 << TOIE1);
@@ -253,11 +287,7 @@ static void ResetHardware(void)
 {
        /* Shut down the USB and other board hardware drivers */
        USB_Disable();
-       //LEDs_Disable();
-       DDRB = 0;
-       PORTB = 0;
-       DDRD = 0;
-       PORTD = 0;
+       LEDs_Disable();
 
        /* Disable Bootloader active LED toggle timer */
        TIMSK1 = 0;
@@ -271,10 +301,7 @@ static void ResetHardware(void)
 /** ISR to periodically toggle the LEDs on the board to indicate that the bootloader is active. */
 ISR(TIMER1_OVF_vect, ISR_BLOCK)
 {
-       //LEDs_ToggleLEDs(LEDS_LED1 | LEDS_LED2);
-       PORTB &= ~_BV(PB0);
-       _delay_ms(5);
-       PORTB |= _BV(PB0);
+       LEDs_ToggleLEDs(LEDS_LED1 | LEDS_LED2);
 }
 
 /** Event handler for the USB_ControlRequest event. This is used to catch and process control requests sent to
@@ -293,10 +320,7 @@ void EVENT_USB_Device_ControlRequest(void)
 stayinbootloader = true;
 
        /* Activity - toggle indicator LEDs */
-       //LEDs_ToggleLEDs(LEDS_LED1 | LEDS_LED2);
-       PORTB &= ~_BV(PB0);
-       _delay_ms(5);
-       PORTB |= _BV(PB0);
+       LEDs_ToggleLEDs(LEDS_LED1 | LEDS_LED2);
 
        /* Get the size of the command and data from the wLength value */
        SentCommand.DataSize = USB_ControlRequest.wLength;
@@ -815,7 +839,7 @@ static void ProcessWriteCommand(void)
                        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;
                        }
                }