Fix flashlight() and safeMode() for boot problem

- Timer 0 is disabled in flashlight() and safeMode() in case its
  variables overlap the bootloader "magic key" location.
- Flashlight mode never exits if invoked.
- Made safeMode() public for use as a smaller code size alternative
  to flashlight().
This commit is contained in:
Scott Allen 2017-03-24 15:53:35 -04:00
parent 1e7f251ce0
commit f294a045e0
5 changed files with 57 additions and 34 deletions

View File

@ -67,6 +67,7 @@ pollButtons KEYWORD2
pressed KEYWORD2 pressed KEYWORD2
readUnitID KEYWORD2 readUnitID KEYWORD2
readUnitName KEYWORD2 readUnitName KEYWORD2
safeMode KEYWORD2
saveOnOff KEYWORD2 saveOnOff KEYWORD2
setCursor KEYWORD2 setCursor KEYWORD2
setFrameRate KEYWORD2 setFrameRate KEYWORD2

View File

@ -54,22 +54,25 @@ void Arduboy2Base::begin()
void Arduboy2Base::flashlight() void Arduboy2Base::flashlight()
{ {
if(!pressed(UP_BUTTON)) { if (!pressed(UP_BUTTON)) {
return; return;
} }
sendLCDCommand(OLED_ALL_PIXELS_ON); // smaller than allPixelsOn() sendLCDCommand(OLED_ALL_PIXELS_ON); // smaller than allPixelsOn()
digitalWriteRGB(RGB_ON, RGB_ON, RGB_ON); digitalWriteRGB(RGB_ON, RGB_ON, RGB_ON);
while (!pressed(DOWN_BUTTON)) { // prevent the bootloader magic number from being overwritten by timer 0
// when a timer variable overlaps the magic number location, for when
// flashlight mode is used for upload problem recovery
power_timer0_disable();
while (true) {
idle(); idle();
} }
digitalWriteRGB(RGB_OFF, RGB_OFF, RGB_OFF);
sendLCDCommand(OLED_PIXELS_FROM_RAM);
} }
void Arduboy2Base::systemButtons() { void Arduboy2Base::systemButtons()
{
while (pressed(B_BUTTON)) { while (pressed(B_BUTTON)) {
digitalWriteRGB(BLUE_LED, RGB_ON); // turn on blue LED digitalWriteRGB(BLUE_LED, RGB_ON); // turn on blue LED
sysCtrlSound(UP_BUTTON + B_BUTTON, GREEN_LED, 0xff); sysCtrlSound(UP_BUTTON + B_BUTTON, GREEN_LED, 0xff);
@ -80,7 +83,8 @@ void Arduboy2Base::systemButtons() {
digitalWriteRGB(BLUE_LED, RGB_OFF); // turn off blue LED digitalWriteRGB(BLUE_LED, RGB_OFF); // turn off blue LED
} }
void Arduboy2Base::sysCtrlSound(uint8_t buttons, uint8_t led, uint8_t eeVal) { void Arduboy2Base::sysCtrlSound(uint8_t buttons, uint8_t led, uint8_t eeVal)
{
if (pressed(buttons)) { if (pressed(buttons)) {
digitalWriteRGB(BLUE_LED, RGB_OFF); // turn off blue LED digitalWriteRGB(BLUE_LED, RGB_OFF); // turn off blue LED
delay(200); delay(200);

View File

@ -195,16 +195,30 @@ class Arduboy2Base : public Arduboy2Core
void begin(); void begin();
/** \brief /** \brief
* Flashlight mode turns the RGB LED and display fully on. * Turn the RGB LED and display fully on to act as a small flashlight/torch.
* *
* \details * \details
* Checks if the UP button is pressed and if so turns the RGB LED and all * Checks if the UP button is pressed and if so turns the RGB LED and all
* display pixels fully on. Pressing the DOWN button will exit flashlight mode. * display pixels fully on. If the UP button is detected, this function
* does not exit. The Arduboy must be restarted after flashlight mode is used.
* *
* This function is called by `begin()` and can be called by a sketch * This function is called by `begin()` and can be called by a sketch
* after `boot()`. * after `boot()`.
* *
* \see begin() boot() * \note
* \parblock
* This function also contains code to address a problem with uploading a new
* sketch, for sketches that interfere with the bootloader "magic number".
* This problem occurs with certain sketches that use large amounts of RAM.
* Being in flashlight mode when uploading a new sketch can fix this problem.
*
* Therefore, for sketches that potentially could cause this problem, and use
* `boot()` instead of `begin()`, it is recommended that a call to
* `flashlight()` be included after calling `boot()`. If program space is
* limited, `safeMode()` can be used instead of `flashlight()`.
* \endparblock
*
* \see begin() boot() safeMode()
*/ */
void flashlight(); void flashlight();

View File

@ -82,12 +82,6 @@ void Arduboy2Core::boot()
bootPins(); bootPins();
bootOLED(); bootOLED();
#ifdef SAFE_MODE
if (buttonsState() == (LEFT_BUTTON | UP_BUTTON))
safeMode();
#endif
bootPowerSaving(); bootPowerSaving();
} }
@ -240,9 +234,15 @@ void Arduboy2Core::SPItransfer(uint8_t data)
void Arduboy2Core::safeMode() void Arduboy2Core::safeMode()
{ {
blank(); // too avoid random gibberish if (buttonsState() == UP_BUTTON)
while (true) { {
asm volatile("nop \n"); digitalWriteRGB(RED_LED, RGB_ON);
// prevent the bootloader magic number from being overwritten by timer 0
// when a timer variable overlaps the magic number location
power_timer0_disable();
while (true) { }
} }
} }

View File

@ -32,11 +32,6 @@
// #define AB_DEVKIT //< compile for the official dev kit // #define AB_DEVKIT //< compile for the official dev kit
#endif #endif
#ifdef AB_DEVKIT
#define SAFE_MODE //< include safe mode (44 bytes)
#endif
#define RGB_ON LOW /**< For digitially setting an RGB LED on using digitalWriteRGB() */ #define RGB_ON LOW /**< For digitially setting an RGB LED on using digitalWriteRGB() */
#define RGB_OFF HIGH /**< For digitially setting an RGB LED off using digitalWriteRGB() */ #define RGB_OFF HIGH /**< For digitially setting an RGB LED off using digitalWriteRGB() */
@ -619,19 +614,28 @@ class Arduboy2Core
*/ */
void static boot(); void static boot();
protected: /** \brief
/* * Allow upload when the bootloader "magic number" could be corrupted.
* Safe Mode is engaged by holding down both the LEFT button and UP button
* when plugging the device into USB. It puts your device into a tight
* loop and allows it to be reprogrammed even if you have uploaded a very
* broken sketch that interferes with the normal USB triggered auto-reboot
* functionality of the device.
* *
* This is most useful on Devkits because they lack a built-in reset * \details
* button. * If the UP button is held when this function is entered, the RGB LED
* will be lit and timer 0 will be disabled, then the sketch will remain
* in a tight loop. This is to address a problem with uploading a new
* sketch, for sketches that interfere with the bootloader "magic number".
* The problem occurs with certain sketches that use large amounts of RAM.
*
* This function should be called after `boot()` in sketches that
* potentially could cause the problem.
*
* It is intended to replace the `flashlight()` function when more
* program space is required. If possible, it is more desirable to use
* `flashlight()`, so that the actual flashlight feature isn't lost.
*
* \see Arduboy2Base::flashlight() boot()
*/ */
void static inline safeMode() __attribute__((always_inline)); void static safeMode();
protected:
// internals // internals
void static inline setCPUSpeed8MHz() __attribute__((always_inline)); void static inline setCPUSpeed8MHz() __attribute__((always_inline));
void static inline bootOLED() __attribute__((always_inline)); void static inline bootOLED() __attribute__((always_inline));