/** Main program entry point. This routine configures the hardware required by the bootloader, then continuously * runs the bootloader processing routine until it times out or is instructed to exit. */ int main(void) { /* Save the value of the boot key memory before it is overwritten */ uint16_t bootKeyPtrVal = *bootKeyPtr; *bootKeyPtr = 0; /* Check the reason for the reset so we can act accordingly */ uint8_t mcusr_state = MCUSR; // store the initial state of the Status register MCUSR = 0; // clear all reset flags /* Watchdog may be configured with a 15 ms period so must disable it before going any further */ wdt_disable(); #if DEVICE_PID == 0x606C // Only on the BlinkyTape // Put the user button (B6) in input_pullup mode, so we can read the button state DDRB &= ~(1<<DDB6); PORTB |= (1<<DDB6); #endif if (mcusr_state & (1<<EXTRF)) { // External reset - we should continue to self-programming mode. #if DEVICE_PID == 0x606C // Only on the BlinkyTape } else if (!(PINB & (1<<DDB6))) { // User button held low- Jump into the bootloader, in case the application is borked. #endif } else if ((mcusr_state & (1<<PORF)) && (pgm_read_word(0) != 0xFFFF)) { // After a power-on reset skip the bootloader and jump straight to sketch // if one exists. StartSketch(); } else if ((mcusr_state & (1<<WDRF)) && (bootKeyPtrVal != bootKey) && (pgm_read_word(0) != 0xFFFF)) { // If it looks like an "accidental" watchdog reset then start the sketch. StartSketch(); } /* Setup hardware required for the bootloader */ SetupHardware(); /* Enable global interrupts so that the USB stack can function */ sei(); Timeout = 0; while (RunBootloader) { CDC_Task(); USB_USBTask(); /* Time out and start the sketch if one is present */ if (Timeout > TIMEOUT_PERIOD) RunBootloader = false; LEDPulse(); } /* Disconnect from the host - USB interface will be reset later along with the AVR */ USB_Detach(); /* Jump to beginning of application space to run the sketch - do not reset */ StartSketch(); }
/** Main program entry point. This routine configures the hardware required by the bootloader, then continuously * runs the bootloader processing routine until it times out or is instructed to exit. */ int main(void) { /* Save the value of the boot key memory before it is overwritten */ uint16_t bootKeyPtrVal = *bootKeyPtr; *bootKeyPtr = 0; /* Check the reason for the reset so we can act accordingly */ uint8_t mcusr_state = MCUSR; // store the initial state of the Status register MCUSR = 0; // clear all reset flags /* Watchdog may be configured with a 15 ms period so must disable it before going any further */ wdt_disable(); // init HWB pin, wait a ms to allow caps to charge HWB_SETUP(); _delay_ms(1); if ((mcusr_state & (1<<EXTRF)) && HWB_STATUS() && (pgm_read_word(0) != 0xFFFF)) { // External reset - start the sketch if there is one and HWB jumper is not installed (HWB pin is read high) StartSketch(); } else if ((mcusr_state & (1<<PORF)) && (pgm_read_word(0) != 0xFFFF)) { // After a power-on reset skip the bootloader and jump straight to sketch // if one exists. StartSketch(); } else if ((mcusr_state & (1<<WDRF)) && (bootKeyPtrVal != bootKey) && (pgm_read_word(0) != 0xFFFF)) { // If it looks like an "accidental" watchdog reset then start the sketch. StartSketch(); } // so only start programmimg mode when reset came from autoreset = watchdog reset and bootkey matches /* Setup hardware required for the bootloader */ SetupHardware(); /* Enable global interrupts so that the USB stack can function */ sei(); Timeout = 0; while (RunBootloader) { CDC_Task(); USB_USBTask(); /* Time out and start the sketch if one is present */ if (Timeout > TIMEOUT_PERIOD) RunBootloader = false; LEDPulse(); } /* Disconnect from the host - USB interface will be reset later along with the AVR */ USB_Detach(); /* Jump to beginning of application space to run the sketch - do not reset */ StartSketch(); }
/** Main program entry point. This routine configures the hardware required by the bootloader, then continuously * runs the bootloader processing routine until it times out or is instructed to exit. */ int main(void) { /* Save the value of the boot key memory before it is overwritten */ uint16_t bootKeyPtrVal = *bootKeyPtr; *bootKeyPtr = 0; /* Check the reason for the reset so we can act accordingly */ uint8_t mcusr_state = MCUSR; // store the initial state of the Status register MCUSR = 0; // clear all reset flags /* Watchdog may be configured with a 15 ms period so must disable it before going any further */ wdt_disable(); /* Jump to bootloader only if correct key is present in eeprom */ if ((eeprom_read_word((uint16_t*)EEP_BOOTKEY_ADDR) != BOOTLOADER_BOOTKEY) && (eeprom_read_word((uint16_t*)EEP_BACKUP_BOOTKEY_ADDR) != BOOTLOADER_BOOTKEY)) { StartSketch(); } /* Setup hardware required for the bootloader */ SetupHardware(); /* Enable global interrupts so that the USB stack can function */ sei(); Timeout = 0; while (RunBootloader) { CDC_Task(); USB_USBTask(); /* Time out and start the sketch if one is present */ if (Timeout > TIMEOUT_PERIOD) RunBootloader = false; LEDPulse(); } /* Disconnect from the host - USB interface will be reset later along with the AVR */ USB_Detach(); /* Jump to beginning of application space to run the sketch - do not reset */ StartSketch(); }
/** Main program entry point. This routine configures the hardware required by the bootloader, then continuously * runs the bootloader processing routine until it times out or is instructed to exit. */ int main(void) { /* Save the value of the boot key memory before it is overwritten */ uint8_t bootKeyPtrVal = *bootKeyPtr; *bootKeyPtr = 0; /* Check the reason for the reset so we can act accordingly */ uint8_t mcusr_state = MCUSR; // store the initial state of the Status register MCUSR = 0; // clear all reset flags /* Watchdog may be configured with a 15 ms period so must disable it before going any further */ // MAH 8/15/12- I removed this because wdt_disable() is the first thing SetupHardware() does- why // do it twice right in a row? //wdt_disable(); /* Setup hardware required for the bootloader */ // MAH 8/15/12- Moved this up to before the bootloader go/no-go decision tree so I could use the // timer in that decision tree. Removed the USBInit() call from it; if I'm not going to stay in // the bootloader, there's no point spending the time initializing the USB. // SetupHardware(); wdt_disable(); // Disable clock division clock_prescale_set(clock_div_1); // Relocate the interrupt vector table to the bootloader section MCUCR = (1 << IVCE); MCUCR = (1 << IVSEL); LED_SETUP(); CPU_PRESCALE(0); L_LED_OFF(); TX_LED_OFF(); RX_LED_OFF(); // Initialize TIMER1 to handle bootloader timeout and LED tasks. // With 16 MHz clock and 1/64 prescaler, timer 1 is clocked at 250 kHz // Our chosen compare match generates an interrupt every 1 ms. // This interrupt is disabled selectively when doing memory reading, erasing, // or writing since SPM has tight timing requirements. OCR1AH = 0; OCR1AL = 250; TIMSK1 = (1 << OCIE1A); // enable timer 1 output compare A match interrupt TCCR1B = ((1 << CS11) | (1 << CS10)); // 1/64 prescaler on timer 1 input // MAH 8/15/12- this replaces bulky pgm_read_word(0) calls later on, to save memory. if (pgm_read_word(0) != 0xFFFF) sketchPresent = true; // MAH 8/15/12- quite a bit changed in this section- let's just pretend nothing has been reserved // and all comments throughout are from me. // First case: external reset, bootKey NOT in memory. We'll put the bootKey in memory, then spin // our wheels for about 750ms, then proceed to the sketch, if there is one. If, during that 750ms, // another external reset occurs, on the next pass through this decision tree, execution will fall // through to the bootloader. if ( (mcusr_state & (1<<EXTRF)) && (bootKeyPtrVal != bootKey) ) { *bootKeyPtr = bootKey; sei(); while (RunBootloader) { if (resetTimeout > EXT_RESET_TIMEOUT_PERIOD) RunBootloader = false; } cli(); *bootKeyPtr = 0; RunBootloader = true; if (sketchPresent) StartSketch(); } // On a power-on reset, we ALWAYS want to go to the sketch. If there is one. else if ( (mcusr_state & (1<<PORF)) && sketchPresent) { StartSketch(); } // On a watchdog reset, if the bootKey isn't set, and there's a sketch, we should just // go straight to the sketch. else if ( (mcusr_state & (1<<WDRF) ) && (bootKeyPtrVal != bootKey) && sketchPresent) { // If it looks like an "accidental" watchdog reset then start the sketch. StartSketch(); } // END ALL COMMENTS ON THIS SECTION FROM MAH. /* Initialize USB Subsystem */ USB_Init(); /* Enable global interrupts so that the USB stack can function */ sei(); Timeout = 0; while (RunBootloader) { CDC_Task(); USB_USBTask(); /* Time out and start the sketch if one is present */ if (Timeout > TIMEOUT_PERIOD) RunBootloader = false; // MAH 8/15/12- This used to be a function call- inlining it saves a few bytes. LLEDPulse++; uint8_t p = LLEDPulse >> 8; if (p > 127) p = 254-p; p += p; if (((uint8_t)LLEDPulse) > p) L_LED_OFF(); else L_LED_ON(); } /* Disconnect from the host - USB interface will be reset later along with the AVR */ USB_Detach(); /* Jump to beginning of application space to run the sketch - do not reset */ StartSketch(); }
/** Main program entry point. This routine configures the hardware required by the bootloader, then continuously * runs the bootloader processing routine until it times out or is instructed to exit. */ int main(void) { /* Save the value of the boot key memory before it is overwritten */ uint16_t bootKeyPtrVal = *bootKeyPtr; *bootKeyPtr = 0; /* Check the reason for the reset so we can act accordingly */ uint8_t mcusr_state = MCUSR; // store the initial state of the Status register MCUSR &= ~((1 << PORF) | (1 << EXTRF) | (1 << WDRF)); // clear reset flags that are used by the bootloader /* Watchdog may be configured with a 15 ms period so must disable it before going any further */ wdt_disable(); if (pgm_read_word(0) != 0xFFFF) { // There is a sketch (otherwise, skip these checks and just run the bootloader). if (mcusr_state & (1 << PORF)) { // After power-on reset, clear BORF so sketch can tell it wasn't a brown-out reset, // then start the sketch. MCUSR &= ~(1 << BORF); StartSketch(); } else if (mcusr_state & (1 << EXTRF)) { // External reset. if (bootKeyPtrVal != bootKey) { // First reset button press. Set boot key for 750 ms so second reset button press // can be detected, then start the sketch if there isn't another reset. *bootKeyPtr = bootKey; _delay_ms(750); *bootKeyPtr = 0; StartSketch(); } else { // Second reset button press; boot key was already set. Fall through to bootloader. } } else if ((mcusr_state & (1 << WDRF)) && (bootKeyPtrVal == bootKey)) { // Watchdog reset triggered by sketch to start bootloader. Fall through. } else { // Reset happened for some other reason; start the sketch. StartSketch(); } } // Clear remaining reset flags so the sketch doesn't see info about an old reset when it runs later. MCUSR = 0; /* Setup hardware required for the bootloader */ SetupHardware(); /* Enable global interrupts so that the USB stack can function */ sei(); Timeout = 0; while (RunBootloader) { CDC_Task(); USB_USBTask(); /* Time out and start the sketch if one is present */ if (Timeout > TIMEOUT_PERIOD) RunBootloader = false; LEDPulse(); } /* Disconnect from the host - USB interface will be reset later along with the AVR */ USB_Detach(); /* Jump to beginning of application space to run the sketch - do not reset */ StartSketch(); }
/** Main program entry point. This routine configures the hardware required by the bootloader, then continuously * runs the bootloader processing routine until it times out or is instructed to exit. */ int main(void) { /* Save the value of the boot key memory before it is overwritten */ uint8_t bootKeyPtrVal = *bootKeyPtr; *bootKeyPtr = 0; /* Check the reason for the reset so we can act accordingly */ uint8_t mcusr_state = MCUSR; // store the initial state of the Status register MCUSR = 0; // clear all reset flags /* Watchdog may be configured with a 15 ms period so must disable it before going any further */ // MAH 8/15/12- I removed this because wdt_disable() is the first thing SetupHardware() does- why // do it twice right in a row? //wdt_disable(); /* Setup hardware required for the bootloader */ // MAH 8/15/12- Moved this up to before the bootloader go/no-go decision tree so I could use the // timer in that decision tree. Removed the USBInit() call from it; if I'm not going to stay in // the bootloader, there's no point spending the time initializing the USB. // SetupHardware(); wdt_disable(); // Disable clock division clock_prescale_set(clock_div_1); // Relocate the interrupt vector table to the bootloader section MCUCR = (1 << IVCE); MCUCR = (1 << IVSEL); LED_SETUP(); CPU_PRESCALE(0); L_LED_OFF(); TX_LED_OFF(); RX_LED_OFF(); // Initialize TIMER1 to handle bootloader timeout and LED tasks. // With 16 MHz clock and 1/64 prescaler, timer 1 is clocked at 250 kHz // Our chosen compare match generates an interrupt every 1 ms. // This interrupt is disabled selectively when doing memory reading, erasing, // or writing since SPM has tight timing requirements. OCR1AH = 0; OCR1AL = 250; TIMSK1 = (1 << OCIE1A); // enable timer 1 output compare A match interrupt TCCR1B = ((1 << CS11) | (1 << CS10)); // 1/64 prescaler on timer 1 input // MAH 8/15/12- this replaces bulky pgm_read_word(0) calls later on, to save memory. if (pgm_read_word(0) != 0xFFFF) sketchPresent = true; // MAH 26 Oct 2012- The "bootload or not?" section has been modified since the code released // with Arduino 1.0.1. The simplest modification is the replacement of equivalence checks on // the reset bits with masked checks, so if more than one reset occurs before the register is // checked, the check doesn't fail and fall through to the bootloader unnecessarily. // The second, more in depth modification addresses behavior after an external reset (i.e., // user pushes the reset button). The Leonardo treats all external resets as requests to // re-enter the bootloader and wait for code to be loaded. It remains in bootloader mode for // 8 seconds before continuing on to the sketch (if one is present). By defining RESET_DELAY // equal to 1, this behavior will persist. // However, if RESET_DELAY is defined to 0, the reset timeout before loading the sketch drops // to 750ms. If, during that 750ms, another external reset occurs, THEN an 8-second delay // in the bootloader will occur. // This is the "no-8-second-delay" code. If this is the first time through the loop, we // don't expect to see the bootKey in memory. if ( (mcusr_state & (1<<EXTRF)) && (bootKeyPtrVal != bootKey) ) { *bootKeyPtr = bootKey; // Put the bootKey in memory so if we get back to this // point again, we know to jump into the bootloader sei(); // Enable interrupts, so we can use timer1 to track our time in the bootloader while (RunBootloader) { if (resetTimeout > EXT_RESET_TIMEOUT_PERIOD) // resetTimeout is getting incremeted RunBootloader = false; // in the timer1 ISR. } // If we make it past that while loop, it's sketch loading time! *bootKeyPtr = 0; // clear out the bootKey; from now on, we want to treat a reset like // a normal reset. cli(); // Disable interrupts, in case no sketch is present. RunBootloader = true; // We want to hang out in the bootloader if no sketch is present. if (sketchPresent) StartSketch(); // If a sketch is present, go! Otherwise, wait around // in the bootloader until one is uploaded. } // On a power-on reset, we ALWAYS want to go to the sketch. If there is one. // This is a place where the old code had an equivalence and now there is a mask. else if ( (mcusr_state & (1<<PORF)) && sketchPresent) { StartSketch(); } // On a watchdog reset, if the bootKey isn't set, and there's a sketch, we should just // go straight to the sketch. // This is a place where the old code had an equivalence and now there is a mask. else if ( (mcusr_state & (1<<WDRF) ) && (bootKeyPtrVal != bootKey) && sketchPresent) { // If it looks like an "accidental" watchdog reset then start the sketch. StartSketch(); } /* Initialize USB Subsystem */ USB_Init(); /* Enable global interrupts so that the USB stack can function */ sei(); Timeout = 0; while (RunBootloader) { CDC_Task(); USB_USBTask(); /* Time out and start the sketch if one is present */ if (Timeout > TIMEOUT_PERIOD) RunBootloader = false; // MAH 8/15/12- This used to be a function call- inlining it saves a few bytes. LLEDPulse++; uint8_t p = LLEDPulse >> 8; if (p > 127) p = 254-p; p += p; if (((uint8_t)LLEDPulse) > p) L_LED_OFF(); else L_LED_ON(); } /* Disconnect from the host - USB interface will be reset later along with the AVR */ USB_Detach(); /* Jump to beginning of application space to run the sketch - do not reset */ StartSketch(); }