Arduboy custom bootloader

I’m having some fun playing around with the caterina bootloader and made a few changes specifically for Arduboy.
Instead of breating an unimplemented LED the RGB LED breathes alternately read, green, blue. Holding down the A or B button will keep the Arduboy in bootloader mode too.

I’ve made 3 versions with different default timeouts 5 seconds, 7.5 seconds and 10 seconds. Since zip files can’t be uploaded here, here’s an external link


Latest info will be put here

  • You can download the latest Cathy3K bootloader from here

  • High fuses must be set to 0xD2 for Cathy3K bootloader

  • don’t want to worry about fusesettings? then flash the bootloader using the Arduino IDE with the Homemade package Installed

  • A demonstration of using the new Arduboy specific display, button and LED features


Using the custom bootloader requires a change of fuse settings. Burning fuses without knowing what you are doing may brick your Arduboy or Arduino board.

Bootloader commands

The bootloader is a serial device using a subset of the AVR109 protocol.

Standard Caterina supported AVR109 commands:

(these commands are used when uploading using the Arduino IDE)

'A'               set current address
'a'               get auto address increment support
'B' 0x00 0x80 'F' write block to flash page (auto erases page)
'E'               Exit bootloader (after 500msec)
'g' MSB  LSB  'F' read block of flash
'L'               leave programming mode
'P'               enter programming mode
'p'               get programmer type
'S'               get software ID string
's'               read avr signature 
'T' byte          select device
't'               get supported device types list
'V'               get software version 
0x1B              escape

(following commands are supported but not used when uploading with the Arduino IDE)

'B' MSB  LSB  'E' write block to EEPROM
'C' byte          Write high byte to page buffer
'c' byte          Write low byte to page buffer
'D' byte          write EEPROM byte
'd'               Read EEPROM byte
'e'               erase chip (erases application flash area only)
'F'               Get low fuse bits
'g' MSB  LSB  'E' read EEPROM
'm'               Flash pagebuffer
'N'               Get high fuse bits
'R'               Read flash word
'r'               Get lock bits
'Q'               Get extended fuse bits
Cathy 3K specific Arduboy commands:
'B' MSB  LSB  'C' write block to flash cart (Cathy3K v1.3)
'B' MSB  LSB  'D' write block to display
'g' MSB  LSB  'C' read block from flash cart (Cathy3K v1.3)
'j'               get flash cart JEDEC ID (Cathy3K v1.3)
'v'               get button states (AVR109 hardware version command)
'x'               set LEDs

giant green oled for the win


If you want to get ambitious, look into moving the bootloader “magic key” to the end of RAM, to fix the magic key overwrite problem.

I believe you do this by indicating that it’s a LUFA bootloader by putting a LUFA signature value (0xDCFB) at the end of flash (FLASHEND -1) and then looking for the magic key at RAMEND - 1 instead of at location 0x800.

For more info, see USBCore.h, USBCore.cpp and CDC.cpp here:

You want to look at the code that deals with NEW_LUFA_SIGNATURE, MAGIC_KEY_POS and MAGIC_KEY. Also the equivalents: bootkey and bootkeyPtr in the Caterina bootloader itself.

Also see the commit that added this capability:

1 Like

Interesting! I didn’t pay much attention to that code bit in USBCore.cpp. But now I get it. Thanks for the links. I’ll look into it.

I looked through the arduino code and it comes down to single check if the last two bytes of flash contain the word 0xDCFB and when it does, RAMEND-1 is used for magic_key_pos. I checked for references to any of the other the BootloaderAPI_Signature in that other link but didn’t find any so for a bare minimum setting FLASHEND-1 to 0xDCFB should do the trick.

The only problem I see is that in case of a burned protect fuse that disallowes reading the bootloader area. The Arduino IDE will fail to read the signature and will fall back using the old address (0x0800). So maybe the bootloader should check both key positions.

Now I need to find out a nice way how to define a section in the makefile to point to the last two bytes for some testing

from USBCore.h:

#ifndef MAGIC_KEY
#define MAGIC_KEY 0x7777

#define MAGIC_KEY_POS 0x0800


from USBcore.cpp > USBDevice_::attach():

	if (pgm_read_word(FLASHEND - 1) == NEW_LUFA_SIGNATURE) {
		_updatedLUFAbootloader = true;

from CDC.cpp

			// For future boards save the key in the inproblematic RAMEND
			// Which is reserved for the main() return value (which will never return)
			if (_updatedLUFAbootloader) {
				// horray, we got a new bootloader!
				magic_key_pos = (RAMEND-1);

Hmm I just noticed this from the bootloader disassembly:

000070ac <__ctors_end>: (Reset Vector)
    70b0:	cf ef          	ldi	r28, 0xFF	; SP = 0x0AFF = RAMEND
    70b2:	da e0       	ldi	r29, 0x0A
    70de:	a6 d3       	rcall	.+1868   	; 0x782c <main>

The call to main will overwrite the magic key before we get a chance to save it. Not sure how to handle that in C++.

OK I turned to my reversed assembly version and added the DCFB signature at the end of flash. the bootloader checks for the magic key at RAMEND-1 and when it fails it will also check the old location 0x0800 for sketches using the old boot key pos. I also did some minor optimizing and the size is down to 3900 bytes

Updated the above zip file with this new test version: arduboy-bootloader-leonardo-7.5-sec-timeout-dual-bootkey.hex

Arduino boards, including the Arduboy, only protect the bootloader from being written, not read.
I don’t think there would be a problem with checking 0x0800 after RAMEND-1, though.

Me neither as the Magic key check is only performed when the watchdog timer was triggered.

I’ve added another button test while in bootmode. Besides pressing the A or B button to remain in bootloader mode, pressing any of the D-Pad buttons will exit bootloader mode and run the sketch. But while I’m typing this I’m wondering if I should limit buttons support . I read about the flashlight and config options by pressing a button (sequence) on startup. But not sure which they are.

They’re not in the bootloader, they’re part of the Arduboy2 library.

1 Like

I knew it was in the library. but I didn’t look into it yet. Thanks for the quick links.

I see I’d better change the button combos. Will need to change the B button from ‘stay in bootloader mode’ otherwise it would be near impossible to trigger the systemsounds optionwhen exiting bootloader mode.

I also realize now that it is’nt really handy to include all buttons in the test. we might wanna use a few combos in future for new features. Thinking about trying the following for the next test:

power on:
DOWN enter bootloader instead of starting sketch (shouldn’t be a problem with system sound as you’d press B first and then B+ UP/DOWN if I understand it correctly)

bootloader mode:
DOWN freeze bootloader timeout timer until button released (again shouldn’t be a problem with system sound feature)
B exit bootloader

1 Like

This use of the DOWN buttons looks good. This shouldn’t conflict with the Arduboy2 library.

If holding DOWN freezes the timeout until it’s released, why do you need to use the B button to exit the bootloader? Once DOWN is released wouldn’t it exit anyway?

@Pharap, you missed one:

Pressing the RIGHT button before or during the ARDUBOY logo scrolling down will abort the logo sequence.

Yes it would after the standard timeout (I’m using 7.5 seconds instead of 8 for the RGB sequence) times out. When DOWN is pressed the timeout counter is simply not updated. When DOWN is released it continues counting towards it’s timeout value. It’s convenient this way and when you accidentally release the button it won’t leave bootloader mode right away.

However when your testing sketches a lot, after each upload it takes another 7.5 seconds to exit bootloader mode and start the sketch (timeout value gets reset during uploading). By pressing the B button after a successful upload, you can start the sketch immediately

Wouldn’t the sketch start immediately after a successful upload anyway? That is, as long as no button was being held. I assume if you were holding the UP button, you would release it as soon as you saw the TX and RX lights flashing, indicating that an upload had started.

If you’ve moved the magic key to RAMEND-1, then I’d think times that powering up into the bootloader and/or extending it’s timeout would be required would be extremely rare. I don’t even see the necessity of needing to extend the current timeout value.

No, because there is no execute command (see CDCtask caterina.c). the bootloader relies on timing out to start the sketch. Both the programming and read commands reset the timeout counter. so when the upload and verify are complete the sketch won’t start until the timeout period has passed.

Oops! I forgot the E command is issued and sets timeout to half a second .:blush:

I agree. But I think it’s a a nice little 4 byte feature for Arduboys with broken reset buttons or for anyone not having a toothpick at hand when an application bricked Arduboy.:

		sbis	PINF,4		;test DOWN button
		rjmp	run_bootloader	;button pressed, enter bootloader
1 Like

So it sounds like you just need:

  • If DOWN is pressed when powering up then start the bootloader instead of the sketch.
  • If DOWN is detected as pressed when you would increment the timeout counter then don’t increment it.
  • (Detecting B or any other button to exit the bootloader isn’t required.)

Yes I see the B button feature is not really worth it. Better save those 10 bytes of code for something more useful. Just made a new test version with the updated features and added it to the zip file


The features:

  • 7.5 second timeout where the RGB LED breathes Red, Green , Blue and off 3 times.
    *double MAGIC KEY check + boot signature to enter bootloader mode from opening and closing USB port at 1200baud.
  • Pressing DOWN button in bootloader mode will hold the bootloader timeout period for as long as the button is held down.
  • Pressing DOWN while turing on Arduboy put’s it in bootloader mode instead of running the sketch.

Behind the curtain changes:

  • Identifies it self as ‘ARDUBOY’ programmer instead of ‘CATERIN’ to distinguish itself from the standard bootloader.
  • minor optimized code (3886 bytes atm)

Okay I thought it was time to test it on the real thing. so I quickly made an ICSP clip for Arduboy and burned the bootloader…

After I turned it on it always ended up in bootloader mode. Having a quick look at the main code I realized that SetupHardware was called after I tried reading the DOWN button :stuck_out_tongue: Putting the port initializing code in the right order made ik work as it should :smiley:

I removed all the previous test versions and just kept the best version



Managed to kick out just over half a K (526 bytes to be exact) so there are now 562 bytes for new code :sunny:
The RGB LED breathing is a bit faster now due to the code optimalisation. There are now 5 RGB cycles with the original 8 seconds timeout.

added arduboy-bootloader-leonardo-8-sec-timeout-dual-bootkey-down-button-v3.hex to the zip file


Sounds great! Is there a repo where your changes to the bootloader can be followed/reviewed? It’s mostly curiosity on my part at this stage but I think it would be useful to have traceability back to the “original” Caterina source for a potential substitute bootloader. Thanks!