Add better bootloader-workaround for atmega32u4 based Arduinos

This commit is contained in:
Simon Budig 2019-01-04 22:36:54 +01:00
parent b90d445ce3
commit 7cc1248abf

View File

@ -1,5 +1,5 @@
/* /*
* Flaming Torch (c) 2013-2014 Simon Budig <simon@budig.de> * Flaming Torch (c) 2013-2019 Simon Budig <simon@budig.de>
*/ */
#include <EEPROM.h> #include <EEPROM.h>
@ -10,7 +10,7 @@
#define PIN_BUTTON 3 // Input pin für Button #define PIN_BUTTON 3 // Input pin für Button
#define PIN_LED 2 // Output pin für Led-Strip #define PIN_LED 2 // Output pin für Led-Strip
#define NUM_PIXELS (1 * 30) #define NUM_PIXELS (5 * 64)
#define NUM_MODES 6 #define NUM_MODES 6
@ -271,8 +271,6 @@ setup ()
// Arduino Loop function. Repeats continuously // Arduino Loop function. Repeats continuously
// (for Leonardo there is some USB-Handling implicitely inbetween,
// for some reason the bootloader isn't entered properly.
void void
loop () loop ()
@ -281,12 +279,64 @@ loop ()
static uint16_t t = 0xffff; static uint16_t t = 0xffff;
static uint8_t pressed = 0; static uint8_t pressed = 0;
static uint8_t state = 0xff; 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) if (state >= NUM_MODES)
state = EEPROM.read(0); state = EEPROM.read(0);
if (state >= NUM_MODES) if (state >= NUM_MODES)
state = 0; 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) switch (state)
{ {
case 0: case 0:
@ -295,27 +345,27 @@ loop ()
case 1: case 1:
render_blueyellow (t); render_blueyellow (t);
delay (10); delay_value = 10;
break; break;
case 2: case 2:
render_rainbow (t); render_rainbow (t);
delay (10); delay_value = 10;
break; break;
case 3: case 3:
render_redblue (t); render_redblue (t);
delay (10); delay_value = 10;
break; break;
case 4: case 4:
render_kitt (t); render_kitt (t);
delay (20); delay_value = 20;
break; break;
case 5: case 5:
render_rgbsparks (t); render_rgbsparks (t);
delay (10); delay_value = 10;
break; break;
default: default:
@ -323,6 +373,18 @@ loop ()
break; 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 // Time-Tick. Needed for moving stripes
t--; t--;
@ -354,5 +416,3 @@ loop ()
pressed = 5; pressed = 5;
} }
} }