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

I think developers should play with this first and get a feel for how annoying it would (or wouldn’t be). I won’t have much time next week but after that I’ll whip up a quick demo (unless someone wants to beat me to it) of invoking the bootloader from software. Should be as simple as jumping to it (with asm) or more authentically setting the magic memory location and then triggering a watchdog reset.

How many different languages should we support for these instructions? :wink:
So far, the executable code in the library is language agnostic. There’s no hard coded output text anywhere.

On thing to consider is that once the bootloader is invoked you would only have the 8 second window to manually start your compile/upload. Therefore, you would be faced with all the timing problems that you get when using the reset button.

With the “old way” (even if flashlight mode is necessary), you don’t have timing problems because the loader on the PC is able to issue a reset, to invoke the bootloader, at the exact time required.

It’s probably best to look at the USB code we’re removing to see how it invokes the bootloader, and use the same technique.

That might prove a requirement - I’d have to look at the bootloader code again. It might check for the type of boot.

Yeah, that is actually the most annoying thing. There is a way to fix that (and have an unlimited delay) but it would require having the program “destroy itself” by writing 0xFFFF to the beginning of Flash. That permanently enables bootloader mode with no timeout.

What I’m learning is that there is a lot to like about the Arduinos with dedicated USB co-processors.

My thought is that it’s ok to build out this functionality but its use should be deemed “experimental” or “alternative” as mentioned previously, it can create confusion for some users. The main concept is user experience.

It sets a magic number in ram and invokes the AVR command for watchdog reset AFAIK

1 Like

Yes, but that there may be smaller ways to accomplish the same thing… like setting the magic # and jumping.

Yes, you may be able to get away with this. I believe the reason for using the watchdog timer is to provide a 120ms delay for the USB sessions to clean up properly before invoking the bootloader. Since we’re eliminating the USB code, we wouldn’t need this delay, so could just jump to the bootloader immediately.

Sorry for bumping this topic. But it’s a great way of gaining ~3K of space. Maybe it gives the Arduventure guys a break on byte crunching?

I looked into catarina bootloader,avr documentation, played around a while and came to the conclusion that using the watchdog timer to trigger the reset is the most convenient way (considering different size bootloaders). I came up with the following code and added it to ButtonsState() in arduboy2core.cpp

Added include at the top:

#include <avr/wdt.h>

Added code to buttonsState():

  //bootloader button combo
  if (buttons == (LEFT_BUTTON | UP_BUTTON | A_BUTTON | B_BUTTON))
  { //set magic boot key
    *(uint8_t *)0x0800 = 0x77;
	*(uint8_t *)0x0801 = 0x77;
	//enable and trigger watchdog by timeout
	for (;;);

Pressing LEFT+UP+A+B will reset the Arduboy into bootloader mode. The above code compiles to 36 bytes (in combination with my optimized buttonsState() version)

My new version of buttonsState() looks like this:

uint8_t Arduboy2Core::buttonsState()
  uint8_t buttons;

  // using ports here is ~100 bytes smaller than digitalRead()
#ifdef AB_DEVKIT
  // down, left, up
  buttons = ((~PINB) & B01110000);
  // right button
  //buttons = buttons | (((~PINC) & B01000000) >> 4);
  if ((PINC & B01000000) == 0) buttons |= 0x04; //compiles to shorter and faster code
  // A and B
  //buttons = buttons | (((~PINF) & B11000000) >> 6);
  if ((PINF & B10000000) == 0) buttons |= 0x02; //compiles to shorter and faster code
  if ((PINF & B01000000) == 0) buttons |= 0x01; 
#elif defined(ARDUBOY_10)
  // up, right, left, down
  buttons = ((~PINF) & B11110000);
  // A (left)
  //buttons = buttons | (((~PINE) & B01000000) >> 3);
  if ((PINE & B01000000) == 0) {buttons |= 0x08;} //compiles to shorter and faster code
  // B (right)
  // buttons = buttons | (((~PINB) & B00010000) >> 2);
  if ((PINB & B00010000) == 0) {buttons |= 0x04;} //compiles to shorter and faster code
  //bootloader button combo
  if (buttons == (LEFT_BUTTON | UP_BUTTON | A_BUTTON | B_BUTTON))
  { //set magic boot key
    *(uint8_t *)0x0800 = 0x77;
	*(uint8_t *)0x0801 = 0x77;
	//enable and trigger watchdog by timeout
	for (;;);
  return buttons;

I think the plan there is to have a menu option to set it into bootloader mode?

But really the reset duration window is really small, a lot of users have problems trying to actually find the timing correctly when using the reset button. This is a bit scary from a UX perspective because there will undoubtedly be a lot of people complaining they aren’t able to reload different code on their device.

One thing I’ve been considering, and maybe if this is needed for Arduventure, but to completely remove the bootloader timeout from within the reset mode, so that if you press the reset button, it stays in bootloader mode indefinitely. Potentially also flashing our RGB led to further indicate it’s state.

1 Like

This would be good but the problem is that there are thousands of Arduboys already out there without this feature in the bootloader. Arduventure has been promised to run on current hardware, so any solution that requires a modified bootloader isn’t viable.

I guess in the suggested implementation for Arduventure relying on flashlight mode may be an option

1 Like

Flashlight mode only addresses the bootloader magic number problem. If a sketch doesn’t overwrite the magic number (which is the majority of sketches), flashlight mode does nothing for you (except give you a flaslight/torch, which is its original purpose :wink:)

Well, if you eliminate the USB stack, the system won’t auto-reset or set the magic number so, in the scope of this discussion isn’t it still viable?

If you eliminate USB (what this topic is discussing), the IDE is no longer able to signal the Arduboy to reset to the bootloader, to allow uploading a new sketch. You need some other way to get into the bootloader, such as using the reset button or having the user somehow trigger the sketch to do it.

Flashlight mode has no capability to do this, so it’s not relevant.

I like that idea.I’m imagening you’d select it from the main (options) menu and select bootmode. Then of a press of the A or B button it is triggered. It would take more code to implement but it’s easier to find the bootloader option (compared to finding out what the button combo is) and it’s easier to trigger (not needing to press multiple buttons awkwardly)

I don’t think that is a problem. The only difference is that with new Arduboys after pressing reset. Arduboy remains into bootloader mode where older Arduboys leave the bootloader mode after 8 seconds.
There should be a redundant software option to enter bootmode though for In case the reset button breaks for some reason.

The software version could be during start up. But It would be better to have it accessible from within the sketch so the on off switch doesn’t has to be used excessively in order to trigger the bootloader by software.

The USB stack should only be left out when the extra space is required. In all other cases it should be included for the convenience of auto-resetting using the Arduino IDE.

In case of an indefinite (or longer) bootloader loop, I prefer to have an option to start the sketch by button press. So in cases where the bootloader was triggered by accident (thinking about watchdog timer here) you don’t have to use the power switch to start the sketch again.

1 Like

I’ve just flashed my test Leonardo with a modified bootloader with no timeout and the idea doesn’t turn out so well because after a sketch is uploaded it’s the timeout that ends programming mode and runs the a sketch. With no timeout you need to turn it off and on again to run the sketch.

Which Arduboys would these “new” ones be?

Newly produced Arduboy’s and possible new versions with or without new features I’d imagine.

@bateske Is this true? Are some Arduboys shipping with a new bootloader? If so where can I find the source?