/** Configures all hardware required for the bootloader. */ void SetupHardware(void) { /* Disable watchdog if enabled by bootloader/fuses */ MCUSR &= ~(1 << WDRF); 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 /* Initialize USB Subsystem */ USB_Init(); }
void StartSketch(void) { cli(); /* Undo TIMER1 setup and clear the count before running the sketch */ TIMSK1 = 0; TCCR1B = 0; // MAH 8/15/12 this clear is removed to save memory. Okay, it // introduces some inaccuracy in the timer in the sketch, but // not enough that it really matters. //TCNT1H = 0; // 16-bit write to TCNT1 requires high byte be written first //TCNT1L = 0; /* Relocate the interrupt vector table to the application section */ MCUCR = (1 << IVCE); MCUCR = 0; L_LED_OFF(); TX_LED_OFF(); RX_LED_OFF(); /* jump to beginning of application space */ __asm__ volatile("jmp 0x0000"); }
void LEDPulse(void) { 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(); }
// StartSketch() is called to clean up our mess before passing execution to the sketch. void StartSketch(void) { cli(); /* Undo TIMER1 setup and clear the count before running the sketch */ TIMSK1 = 0; TCCR1B = 0; /* Relocate the interrupt vector table to the application section */ MCUCR = (1 << IVCE); MCUCR = 0; L_LED_OFF(); TX_LED_OFF(); RX_LED_OFF(); /* jump to beginning of application space */ __asm__ volatile("jmp 0x0000"); }
void StartSketch(void) { cli(); /* Undo TIMER1 setup and clear the count before running the sketch */ TIMSK1 = 0; TCCR1B = 0; TCNT1H = 0; // 16-bit write to TCNT1 requires high byte be written first TCNT1L = 0; /* Relocate the interrupt vector table to the application section */ MCUCR = (1 << IVCE); MCUCR = 0; L_LED_OFF(); // TX_LED_OFF(); // RX_LED_OFF(); /* jump to beginning of application space */ __asm__ volatile("jmp 0x0000"); }
/** 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 */ 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(); }