From 7cc1248abf1365d043c4ef4a330817b6e6e5078c Mon Sep 17 00:00:00 2001 From: Simon Budig Date: Fri, 4 Jan 2019 22:36:54 +0100 Subject: [PATCH] Add better bootloader-workaround for atmega32u4 based Arduinos --- flame.ino | 82 +++++++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 71 insertions(+), 11 deletions(-) diff --git a/flame.ino b/flame.ino index 366b8ce..caa4f15 100644 --- a/flame.ino +++ b/flame.ino @@ -1,5 +1,5 @@ /* - * Flaming Torch (c) 2013-2014 Simon Budig + * Flaming Torch (c) 2013-2019 Simon Budig */ #include @@ -10,7 +10,7 @@ #define PIN_BUTTON 3 // Input pin für Button #define PIN_LED 2 // Output pin für Led-Strip -#define NUM_PIXELS (1 * 30) +#define NUM_PIXELS (5 * 64) #define NUM_MODES 6 @@ -271,8 +271,6 @@ setup () // Arduino Loop function. Repeats continuously -// (for Leonardo there is some USB-Handling implicitely inbetween, -// for some reason the bootloader isn't entered properly. void loop () @@ -281,12 +279,64 @@ loop () static uint16_t t = 0xffff; static uint8_t pressed = 0; static uint8_t state = 0xff; + uint8_t delay_value = 0; +#ifdef MAGIC_KEY_POS + // for atmega32u4 based Arduinos: + // + // check if the bootloader has been activated. + // avoid doing any rendering to prevent the + // MAGIC_KEY getting overridden which in turn + // would prevent entering the bootloader properly. + + if (*((uint16_t *) MAGIC_KEY_POS) == MAGIC_KEY && + WDTCSR & (1 << WDE)) + { + return; + } +#endif + if (state >= NUM_MODES) state = EEPROM.read(0); if (state >= NUM_MODES) state = 0; +#ifdef MAGIC_KEY_POS + // Now, this is quite unfortunate: + // + // for the atmege32u4 based arduinos (Leonardo, pro micro etc.) + // entering the bootloader is initiated in the USB interrupt + // handler (i.e. can happen at any time). + // + // This does two things: writes MAGIC_KEY to MAGIC_KEY_POS and + // enables the watchdog reset. + // + // If the watchdog fires the atmega32u4 resets and the bootloader + // code checks for the MAGIC_KEY at MAGIC_KEY_POS. If it finds + // the MAGIC_KEY it sticks in the bootloader mode. + // + // for larger LED strips it is quite likely that MAGIC_KEY_POS + // resides in the middle of the framebuffer. And if the USB interrupt + // happens while the code is rendering stuff to the framebuffer, + // it then might happen that the MAGIC_KEY immediately gets overwritten + // by the rendering code. This prevents that the bootloader gets + // entered upon the watchdog reset. For some effects the AVR is mostly + // rendering, making it basically impossible to enter the bootloader + // via the IDE. + // + // As a workaround we disable all interrupts during the rendering code + // which is quite a brute force method. This delays the writing of the + // MAGIC_KEY to the point of the sei() (since this is now the point where + // the USB interrupt gets handled), giving the MAGIC_KEY precedence over + // the rendered effect. + // + // and since we basically avoid running loop() when the + // bootloader-conditions are met (see above) the switch to the bootloader + // now is more reliable again. + + cli (); +#endif + switch (state) { case 0: @@ -295,27 +345,27 @@ loop () case 1: render_blueyellow (t); - delay (10); + delay_value = 10; break; case 2: render_rainbow (t); - delay (10); + delay_value = 10; break; case 3: render_redblue (t); - delay (10); + delay_value = 10; break; case 4: render_kitt (t); - delay (20); + delay_value = 20; break; case 5: render_rgbsparks (t); - delay (10); + delay_value = 10; break; default: @@ -323,6 +373,18 @@ loop () break; } +#ifdef MAGIC_KEY_POS + sei (); +#endif + + // the actual delay relies on interupts, hence + // we have to do the per-frame-waiting after the sei(); + + if (delay_value) + { + delay (delay_value); + } + // Time-Tick. Needed for moving stripes t--; @@ -354,5 +416,3 @@ loop () pressed = 5; } } - -