Idea: Remove the USB stack and regain 3,000 bytes of Flash


When you said:

I took “brick your device in this manner” to mean truly bricking the Arduboy by overwriting the bootloader (as @JayGarcia had done by uploading using the CLI), not just requiring the reset button to be pressed at the proper time.

1 Like

CLI tool will report the wrong size because it doesn’t pick up the Leonardo variant info but my understanding was that with fuses protecting the bootloader bricking cannot happen even when flashing oversized .hex using CLI tools, am I correct? Also, as far as I can tell from the source code, the avrdude command line options used by the game upload script do not overwrite fuses.

EDIT: my OS autocorrect feature thinks “flossing” is a more appropriate spelling of “flashing”. Gotta love context-less word substitution …

1 Like

That’s the idea.
But there’s a large batch that left the factory without the fuses set properly.


Crazy to me that not a single problem was posted on the game thread. I would have gladly helped.


While I’m working on optimizing the Arduino core file wiring.c I have a new idea for the bootloader key combo.
it can be included in the timer0 ISR. This way it doesn’t need to be in the Arduboy library. One could just add one of cores (Normal, Arduboy Safe, Arduboy No USB Safe) to the sketch just as it was done with Evade 2 or even better select an ‘Arduboy Safe’ or Arduboy No USB safe’ board from the tools menu. Need to figure out this last bit though.

1 Like

OK I added a enter bootloader mode to the timer0 ISR and as a bonus I also added a reset feature.

  • Press and hold LEFT + UP + A +B for two seconds and the bootloader will be entered.

  • Press and hold RIGHT + UP + A +B for two seconds and Arduboy will be reset. Yay! we can watch the splash screens over and over again :stuck_out_tongue:

You don’t have to worry about increased code size. The features code takes up 66 bytes but I freed 104 bytes in the ISR and init() routines together so a sketch size will be decreased by 38 bytes.

For testing I forked Evade 2 and made a new branch with the new wiring.h in I hope @JayGarcia will approve and take it to the master.

I’ll save optimizing micros and delay for another day :slight_smile:

Here’s a video showing it in action.

To prevent any confusion, the breathing RGB LED and USB icon in the video are part of my custom bootloader

The reset button combo will be changed to RIGHT + DOWN + A +B for two seconds so there will be no confilict with the flashlight feature.


Woah dude. This is slamming!!!

1 Like

I’m on travel through Saturday and can’t test anything until then. Thank you so much for doing this for the community. =)

NP I might have another update. Just added button support for the DevKit and I might have a go on micros and delay after all.

I like the idea of a standardised key-combo to invoke the bootloader. I can see why you added it to TIMER0_OVF_vect but I am not 100% convinced it belongs in the interrupt handler.

<thinking out loud>
I’d keep the watchdog running instead this would take care of invoking the bootloader when the application is stuck and let the application handle key combos in normal conditions. This does not increase the responsibilities of the interrupt handler nor requires an extra SRAM byte to store the button state for the ISR (separately from the state the application will also have to store).
</thinking out loud> EDIT: escaped angle-brackets

Implementation details aside it has become painfully obvious to me how Arduino IDE, its build-system and core libraries/conventions make development unnecessarily painful and negatively impact the quality of the result. I am thinking of:

  • Arduino core bloat like the USB reset feature taking up 10% of precious (leftover) progmem (and some SRAM) when it can probably be made to fit half a kb.
  • Arduino IDE UX is awful
  • Arduino IDE build system hides “knobs” that should not be hidden to do the job well

I am wondering if interested parties would like to form a working group to figure out how to improve the situation with the goal of providing an alternative set of easy to use minimal arduboy specific core libraries relying on avr-libc and makefile/project templates.

I wasn’t sure at first because of wasting bytes for a ‘duplicate’ buttosstate code of 14 bytes. But then I realized it’s the best location. If a sketch freezes up due to an mistake or doesn’t reach the exittobootloader check in buttonsstate or anywhere else you’d have to reset it the old way. For new comers to the Arduboy whom are prone to make lots of mistakes and freeze up their Arduboy will certainly appreciate this feature.
Even with an empty sketch with NoUSB (takes 560 bytes now :slight_smile: ) uploaded you can enter the bootloader.

Do you mean execute time? The new version with bootloader check is actually a few cycles faster.

Hmm I could use RAMEND and free that byte.

It takes effort to add that to a sketch and has to be placed at strategic places. It doesn’t return to bootloader though as the MAGIC_KEY is missing.

Yeah the bulky USB core is a pain. A basic reset bootloader would be smaller. I didn’t realy look into it but rougly seeing how much still is required for that basic feature. I’d rougly guess 1 - 1.5K so 0.5K would be impressive.

The thing I most dislike of the Arduino IDE is that it doesn’t auto select the proper COM port. On windows two diferent com ports will be assigned. one for bootloader and one for application mode. It would also be nice if it would support plug-ins

Using RAMEND now. A nice extra of of this is that it mimicing a reset. The application will be kept reset until the button combo is released in 97% the cases in the other 3% it will instantly restart the sketch

That’s what a hardware watchdog is for. The key-combo is a (IMO very) convenient feature to avoid using the hardware reset button but it does not protect you from a misbehaving firmware. Putting the key combo detection in the ISR doesn’t buy you much protection (the watchdog will take care of more cases and is cheaper in both RAM and instructions) but you are adding code to the timer ISR that doesn’t need to be there.

Consider this: before this change people who did’t want the key combo just needed to avoid calling a specific library function. After your change, they have to hack an interrupt handler in the core library source.

No, I was talking about separation of concerns. The function of that ISR (right now) is timekeeping and wake-up from powersave, neither of which strictly requires the ISR to be present. IMO if something is not required it should be made optional, but if you make the ISR do more things it will be harder to make it go away.

Isn’t that reserved for MAGIC_KEY on new boot loaders?

One call (or store instruction?) in the main loop will cover most cases, it can be even hidden behind the scenes.

There is a 512 bytes HID based bootloader for atmega32u4 which supports flashing a firmware. I believe supporting the Leonardo CDC reset protocol used by the IDE is simpler than that so it should be possible.

You can’t start the bootloader without the MAGIC_KEY set. With the stock bootloader it has to be at 0x800 and is most likely used by the application.

I’ll make two versions one optimized only and one with the feature. I’m not forcing anything. You have to add it to your sketch folder. When I’ve figured out how to add it to my board package it will be an option from the tools menu so you can choose whether you want Normal/Lile or Lite+safe.

Right! so I do need that extra byte afterall.

Ouch, true. They screwed that one up real good. Maybe the bootloader checks both 0x800 and RAMEND-1? I’m crossing my fingers …

After struggeling with inline assembly and the compiler I finally managed to squeeze out 74 more bytes out of micros() and delay() functions in wiring.c It has the Bootloader + Reset buttons feature and 118 more free bytes as a bonus :smiley: ( @JayGarcia I made a pull request for Evade 2 )

I forgot to mention before that I also added button support for the DevKit. When building for devkit you’ll have 4 less bytes due to the different button implementation.

I’ve also added it to my board package with options Arduboy/Arduboy Safe and Arduboy no USB) and works like a treat. Just need to update my adapted Arduboy 2 library before a release. @MLXXXp are you planning any updates to Arduboy2 master soon?

1 Like

Hard core. :slight_smile: That’s impressive.

1 Like

I’ve been a bit busy during the holiday season but I’d like to get a new release out soon, with at least the unreleased changes/fixes in the master branch, and also @Pharap’s refactored drawCompressed() PR #19, if my testing doesn’t show any problems.

I was also hoping to look at your PR #17 to see if there are any optimisations that would apply, while still only supporting official Arduboy hardware.

I’m still not sure about including USB stack removal functions.


You’ll sure want to copy my buttonsState() function. It saves 42 more bytes :slight_smile:
I need to have a look at my fast display code again to see if it also saves a few bytes extra bytes besides clocking out data at a steady 18 clock cycles per byte.
Besides the extra OLED and resolution support there where a few minor ones like putting OLED chip/data/cmd selects inline. I haven’t

Here’s the optimized buttonsState. It may look much but thanks to SBIS instructions and removing the wastefull << operator, it compiles to 14 bytes.

uint8_t Arduboy2Core::buttonsState()
  uint8_t buttons;
  static uint8_t button_hold;

  // using ports here is ~100 bytes smaller than digitalRead()
#ifdef AB_DEVKIT
  // down, left, up
  buttons = ((~PINB) & B01110000);
  // right button
  if ((PINC & _BV(6)) == 0) buttons |= RIGHT_BUTTON; //using this notation compiles to shorter code
  // A and B
  if ((PINF & _BV(7)) == 0) buttons |= A_BUTTON;
  if ((PINF & _BV(6)) == 0) buttons |= B_BUTTON;
#elif defined(ARDUBOY_10)
  // up, right, left, down
  buttons = ((~PINF) & B11110000);
  // A (left)
if ((PINE & _BV(6)) == 0) {buttons |= A_BUTTON;}
  // B (right)
  if ((PINB & _BV(4)) == 0) {buttons |= B_BUTTON;}
  return buttons;

EDIT: I did a quick comparison:

  • display() originally takes 20 bytes vs mine taking 42 bytes
  • display(true) originally takes 40 bytes vs mine taking 42 bytes

I sacrificed these 22/2 bytes for a considerable speed gain. both display() and display(true) also take the same amount of time.


Hy @Mr.Blinky, I believe you created a PR for the forked repo versus a PR to pull into Evade2’s repo. :smiley: <-- Pull ID 1 :stuck_out_tongue:

Sorry. I’m not used to using github. The browser version doesn’t seem to have a synching option to synch with the master.


Hopefully I pulled the right request now :smile: