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>
@ -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;
}
}