So I’ve spent some time looking at adding a save and restore of the bootloader magic number to flashlight mode, as discussed above. I’m confused with what I’m seeing.
Before actually modifying the library, I decided to write a sketch that reads the magic number, to confirm the location and value and make sure it can be read and written.
As I understand it, RAM address 0x800 is the magic number location, which should contain a value of 0x7777 unless it’s been overwritten by a sketch that uses a large amount of RAM. Newer versions of the bootloader and USB code have been modified to put the magic number in the last two bytes of RAM, at 0xAFE and 0xAFF. From what I’m seeing this is not the case.
Instead, at the end of RAM there is a value that changes depending on the sketch code. Based on my research, I believe this is the return address for a call to function main(). At address 0x800 I get either 0x0000 or the same value as at the end of RAM, depending on if the USB port is connected to the PC. Each time the Arduboy is attached to the PC the RAM end value will be copied to the magic number location. In no case have I ever seen either location be 0x7777.
Can anyone shed some light on what’s happening here?
The following is my latest test sketch. It just continually displays the values at 0x800 (MAGIC_KEY_POS) and the end of RAM (RAMEND - 1). You can press the A button or B button to change their values.
#include <Arduboy2.h>
Arduboy2 arduboy;
void setup() {
arduboy.begin();
arduboy.setFrameRate(15);
}
void loop() {
if (!arduboy.nextFrame()) {
return;
}
arduboy.pollButtons();
if (arduboy.justPressed(A_BUTTON)) {
(*(uint8_t*) MAGIC_KEY_POS)++;
(*(uint8_t*) (MAGIC_KEY_POS + 1))--;
}
if (arduboy.justPressed(B_BUTTON)) {
(*(uint8_t*) (RAMEND - 1))--;
(*(uint8_t*) RAMEND)++;
}
showValues();
}
void showValues() {
arduboy.clear();
arduboy.print("MAGIC_KEY_POS: 0x");
hexPrint4(MAGIC_KEY_POS);
arduboy.print("\nValue: 0x");
hexPrint4(*(uint16_t*) MAGIC_KEY_POS);
arduboy.print("\n\nRAMEND - 1: 0x");
hexPrint4(RAMEND - 1);
arduboy.print("\nValue: 0x");
hexPrint4(*(uint16_t*) (RAMEND - 1));
arduboy.display();
}
void hexPrint4(uint16_t val) {
if (val < 0x1000) {
arduboy.print('0');
}
if (val < 0x100) {
arduboy.print('0');
}
if (val < 0x10) {
arduboy.print('0');
}
arduboy.print(val, HEX);
}
I haven’t found a case where I’ve actually “bricked” the Arduboy by changing the values.
The code I’ve found so far that defines, tests or manipulates the magic number is in files Caterina.c, USBcore.h, USBcore.cpp and CDC.cpp
I’ll continue to look at this tomorrow, but any help would be appreciated.
My plan is to temporarily save whatever is at the magic number location when flashlight mode is entered, replace it with the magic number, then restore the saved value before exiting flashlight mode. To do this I need to know the magic number location (which appears to be 0x800) and the value to put there (which should be 0x7777 but doesn’t appear to be), with the intent that the bootloader will see the proper magic number and remain active to allow sketch upload.