How does the Arduboy FX... actually work?

It’ll be a while before I receive mine, and I know if I just wait for it to come it might make more sense, but I like thinking about/understanding stuff and it’s been bugging me.

I’ve been reading around on the forums, reading the READMEs on stuff like GitHub - MrBlinky/Arduboy-FX-mod-chip: Self updating bootloader for Arduboy FX and various threads about how to add games and all that, and the quickstart guide mentions you can still use the Arduboy FX like a normal Arduboy where you just flash your game to it but like… what the heck is going on to make all that work?

So there’s the ATMega32u4 with the 32kb flash, it’s the microcontroller that has most of the stuff. And then there’s the FX modchip builtin that has its own MCU and some significantly larger 16mb flash memory.

  • Is there any real difference between an Arduboy FX and an original Arduboy with a properly installed FX modchip?
  • With a stock Arduboy FX new out of the box, what is in the 32kb flash? Does it matter?
  • When the Arduboy is powered on, does the ATMega32u4 immediately begin running the program from the 32kb flash? Or is the FX MCU somehow involved?
  • When you select a game from the FX bootloader menu, I assume it’s flashed into the ATMega32u4. When you power down the device, I assume it persists there? When you next power on the Arduboy FX, by default, I assume it loads the menu again? If so, how does that work? Does the FX MCU flash the FX bootloader into the 32kb flash every time it powers on? I know this question is basically the crux of all the other questions…
  • When you flash your own program to an Arduboy FX using the Arduino software like in the quickstart guide, I assume it does not touch anything inside the FX modchip (although please let me know if that’s wrong). Does it just dump it directly into the 32kb flash and start running it? And so, if I power off/on the device, my program is wiped in order to make the FX bootloader function again (if it does)?

I guess, maybe just an explanation of what happens on power on, and how the FX chip as a whole interacts with the ATMega32u4 (whether at the start or any other time, such as swapping the game) would be super cool.

Arduboy with mod chip = Arduboy FX (as far as I know)

I don’t remember, perhaps the demo game. It doesn’t matter of course.

The bootloader menu always pops up first when you turn on the Arduboy.

Yes, it is flashed. There’s a cute little loading bar as well!

Games are flashed to the Arduboy’s MCU, so yes, games will stay.

Yes, it loads the menu on start-up. Idk how it works, but there’s an option in @Mr.Blinky 's homemade package to skip that and just load up the game on start-up, but I think that is for the bootloader burning and stuff only.

No. It gets flashed once to the MCU, then it stays there forever until you flash another game.

Yes, uploading your own program (provided it does not use the FX library) will not affect the FX chip.

I think so yeah.

It does not wipe the program, it simply just loads the menu. On the first menu screen, just press A or B to enter your game. No wiping; everything stays, just the bootloader screen pops up.

:flushed:

@MLXXXp might be a better person to ask, he made (assuming from the class reference site’s url and the GitHub repo) the Arduboy2 library which is the standard nowadays.

1 Like

Hello you can learn more here:

The Arduboy FX is just a built in version of what @Mr.Blinky built as his flash cartridge. It took me a while to catch on but once I did I turned it into a mod-chip which included an attiny to reflash the bootloader he made as well as the external memory.

Short version is he made a boot loader that looks at the external memory chip and the “fx menu” is entirely within the bootloader. Once you select a game it flashes the game from external memory onto the atmegas internal memory and resets the chip into the game.

3 Likes

Thank you @Ard_Flamingo, that answers a lot of my questions about what it does.

@bateske Ah, so when you turn on the Arduboy FX, is it actually going into the ATTiny for the bootloader? Is that why you’re able to load into the last game you flashed simply by pressing a button in the menu? It just jumps into the ATMega without flashing anything?

So, does that mean that if I flash one of my programs into the ATMega using the Arduino software, when I reboot the Arduboy FX later and it goes into the FX bootloader, pressing a button at the start will take me back into my program, because it’s still untouched within the ATMega flash? It’s like… the FX mod chip just stands in front of the original Arduboy and lets you select what to do with it?

No the attiny on the mod chip just reprograms the bootloader of an original arduboy. It’s only run once.

The FX comes with the bootloader pre installed. A normal arduino bootloader just loads whatever is in atmega flash, the fx bootloader pauses, and has the menu that negotiates with the external flash. It’s really a work of art that it’s even possible @Mr.Blinky deserves a ton of credit on it.

yep!

Ah ok. I went and read up more on Arduino, I guess I should’ve done that before, but I wasn’t looking for the right info. I didn’t realize they reserved a section of flash for their own bootloader; I guess I just wasn’t thinking. Well… that all makes a lot more sense now actually, thank you!

3 Likes

I’m probably going to end up repeating some of the things others have said, but for the sake of giving direct answers to individual questions and helping others who may stumble upon this thread in future…


First off: regardless of the version of Arduboy, the 32KB (32,768 bytes) of flash memory contains a bootloader, and the remaining space is for user code (i.e. the actual loaded game).

On the original Arduboy the bootloader is 4KB (4,096 bytes) in size.

I believe the bootloader on the Arduboy FX is 3KB (3,072 bytes) in size. It’s this bootloader that reads the FX chip and displays the FX menu. The original has no such menu.

The extra chip that is used by the FX mod to change the default bootloader to the new FX bootloader. Other than that and possibly where the components are placed on the board, there should be little difference - the rest of the hardware is the same.

The new bootloader for certain.
Possibly a game, but which one probably isn’t important.

The bootloader does. The user code doesn’t because it’s easily replaced.

When the power is turned on, the bootloader runs.

On the original Arduboy the bootloader doesn’t really do anything of importance and boots straight into the program.

On the Arduboy FX the new bootloader tends to boot into the menu first, though I believe it can be configured to pass control to the loaded user code straight away without stopping on the menu.

No. As far as I remember that exists only for flashing the bootloader, and it’s only part of the FX mod for upgrading an original Arduboy - it’s not present on Arduboy FX units because they already have the new bootloader.

Yes.

Yes. Flash memory is non-volatile, and there’s no reason to reflash the game every time, that would waste write cycles.

It depends on what you have it configured to do, but typically yes, the bootloader will display the game selection menu.

Regardless of how it’s configured, the bootloader always runs first.

Likely not, that would be a waste of write cycles.

No, Arduino’s software is entirely unaware of the FX chip’s existance.

Data is flashed to the FX chip via a program that communicates with the bootloader, which instructs the bootloader as to what data is to be placed where on the FX chip.

The Arduino IDE and its default toolchain merely writes compiled code to the ATmega32u4’s user memory. After the upload the device resets and boots as normal.

Once again, any interaction with the FX chip must be done through custom software that is aware of the extra set of bootloader commands.

No.


As mentioned above, when the power is turned on the ATmega32u4 processor inside the Arduboy boots into its bootloader, and depending on the bootloader (i.e. whether it is the original bootloader or the FX bootloader) it will behave differently.

The ordinary bootloader will immediately launch the user code.

The FX bootloader will either display the FX menu or launch into user code, depending on how it has been configured.

The FX chip does nothing other than respond to commands from the ATmega32u4, sent over SPI. Those commands control the reading, writing, and erasing of data on the FX chip. The FX library is a wrapper around code that sends the relevant commands to the FX chip over SPI.

Crucially, the FX chip is incapable of manipulating the ATmega32u4 in any way. It is a data store and nothing more.

As mentioned before, the other processor that exists on the FX mod is intended for upgrading the bootloader once and does little else. I don’t know if it can be manipulated into doing other things, but it only exists on some units so anything it can be made to do would have a limited audience.

Some other relevant facts:

  • The ATmega32u4 can only run machine code that is loaded into its internal flash memory (commonly referred to as progmem). It cannot run machine code directly off the FX chip, though it can read memory directly from the FX chip, and the software on the internal memory can decide what to do with the data read.
  • The screen and the FX chip cannot be used simultaneously as they both use SPI, they must be switched between as necessary. This isn’t an obstancle though, as all drawing on the Arduboy (at least, that done via the Arduboy2 library or FX library) is done to a frame buffer. The screen itself is typically only accessed once per frame, to copy the frame buffer to the screen, and for no other reason.
    • The screen is also sent a few commands in arduboy.begin(), simply to initialise it, but it’s uncommon for a game to try to send anything other than frame data to the screen after that initialisation.
  • It is possibly to write to the FX during gameplay, but there are limitations. ‘Writing’ can only toggle 1 bits to 0 bits. To turn a 0 bit into a 1 bit, and entire ‘page’ (4,096 bytes) must be ‘erased’ (i.e. the entire page is reset back to all 1 bits - the default state of every page of memory). Hence if you plan to use the FX chip to store data generated as the game runs, you need to think carefully about how you plan to use it (though there is now a library feature for that I believe).
3 Likes

There sure is and it makes it trivial to use.

In the setup(), you need to initialise the FX library a little differently:

void setup() {

    arduboy.begin();

    FX::begin(FX_DATA_PAGE, FX_SAVE_PAGE);
    FX::loadGameState((uint8_t*)&cookie, sizeof(cookie));
...

Then when you want to save or load state:

FX::saveGameState((uint8_t*)&cookie, sizeof(cookie));

FX::loadGameState((uint8_t*)&cookie, sizeof(cookie));

Where the cookie is a POJO (oops, wrong language!) I meant a simple structure.

That cast and sizeof really shouldn’t be necessary.
A basic template could get rid of that burden.

template<typename Type>
void saveGameState(const Type & object)
{
	FX::saveGameState(reinterpret_cast<const unsigned char *>(&object), sizeof(object));
}

template<typename Type>
void loadGameState(Type & object)
{
	FX::loadGameState(reinterpret_cast<unsigned char *>(&object), sizeof(object));
}

I may have to look into modifying the library if I get time.

I find it odd that there’s no mention of a position in those functions though. I would have expected (or at least hoped) for it to be possible to use the function in more than one place to save more than one block of data.

The C++ term is ‘POD type’ (‘plain old data’). (There’s a nice straightforward explanation of the meaning here.)

I think it used to be mostly a colloquial term, but it became official in C++11 with the introduction of std::is_pod. (Though that was deprecated in 2020 for some reason.)

(Other relevant concepts are the more formal ‘trivial type’ and ‘standard layout type’.)

1 Like

Our template master has spoken. This is the way. :slight_smile:

I’ll (try to) add the template to the library.

These functions are ment as a simple way to save and load data to ram. All manipulation will be done in ram (results in less progmem use). More complex features will come in future functions :wink:

Didn’t know about that. did find std::any but that one isn’t supported by Arduino included AVR compiller.

1 Like

I understood that the data is progressively written ‘across’ the page until the page is full. Once full, the next write will erase and start the process again.

If you want multiple blocks of data to be saved, you almost need to be able to specify a ‘page’ index or something so that you can write the cookies out to separate pages.

If there’s a limit on the object size then you may want to add a static_assert so it refuses to compile if someone passes an object that’s too large. E.g. static_assert(sizeof(object) >= objectSizeLimit, "object is too large for saveGameState").

I gathered that much, but the programmer may want e.g. to be able to save more than one profile, or save more than one type of object, in which case specifying an offset into FX memory would be useful.

Technically none of the C++ library is, mainly due to expense (e.g. need for dynamic allocation or exceptions), though much of the more lightweight features (such as <type_traits>, <utility> and <limits>) could be.

Incidentally, std::is_pod is from <type_traits>. More or less all of the type traits classes are intended to be used for making decisions about types at compile time, such as selecting an appropriate function to call (at compile time, i.e. no function pointers) or refusing to accept a type that doesn’t meet certain criteria. In the case of GCC I happen to know that is_pod is implemented with a compiler intrinsic and can be implemented in Arduboy code if you have need for it.

You likely wouldn’t want to use that on AVR even if it were available.

Any (non-templated) type that professes to be able to store an object of an arbitrary type will very likely be using type erasure, which inevitably requires storing a pointer to the heap simply because no object can exist without its size being known.

I had a quick sift through the GCC implementation and in addition to using dynamic allocation it also relies on function pointers, so it would be doubly poor on AVR (though possibly alright on a decently sized ARM chip). It can avoid using RTTI (runtime type information) at least.


This is the sort of thing I mean.

I’m thinking in terms of saving multiple ‘user profiles’; or really any kind of data where you might want only one loaded in RAM at once, but multiple copies saved onto the FX chip.

Or at the extreme end of usage, different types of objects that might exist in RAM at different times. (Think tagged union.) That might seem crazy now, but I expect eventually people will try pushing the limits. Besides which, I like to imagine what’s possible, not merely what’s obvious.

The amount of free ram is the limit so an assert wouldn’t be needed.

That will be one for the future functions :slight_smile:

The programmer can put multiple those objects in the game state structure.

Fair enough.

Yes, but then all of those objects have to exist in RAM at the same time. I’m thinking of a scenario where the user would keep only one object in RAM at a given time, as would be the case with having different ‘save games’ or ‘user profiles’.

For comparison, see the multiple profiles trick I brought up when I was working on the EEPROM API a while back. (I haven’t forgotten about it - I just haven’t had time to write a test for it and discuss finalising it.)

The idea of the objects being different types is less important than the idea that they shouldn’t coexist in RAM due to size constraints, as might be the case in a (tagged) union - the example I gave to Filmote.

@Pharap Thank you! Hearing things explained differently usually helps in understanding, and I greatly appreciate the rundown of what happens on power-up and the additional information!

1 Like

Speaking of the FX library, I’m a little confused about how that works too in tandem with the FX bootloader. I read through most of the posts in Arduboy FX library but couldn’t find anything (maybe I missed it).

I guess my basic questions are:

  • Does an FX game (basically any game using the FX library for data) work concurrently with the “hundreds of games/cart/csv list” thing? Or is it that you have to pick between having a bunch of games or having one game? Or is it up to the developer to set that up correctly?
  • If you can have multiple FX-data games within the FX flash, how does that work? Was the format of the individual game storage on the flash chip pre-designed with additional room for FX data? Something else?
  • If it’s not like that and the expectation is one FX game at a time, what are the hurdles that prevented multiple games at the same time?
  • Regardless of how it works, I assume the FX bootloader has stayed the same? How does that work; doesn’t the bootloader require some known section of the flash to contain that specially-formatted blob or “cart” or whatever with all the programs? How does the FX library avoid collisions with that?

Sorry if the questions are stupid, I have really been trying to find the answers and I’ve looked through hundreds of posts and always read through the repos that are involved (including the FX library posted in the above link) but it feels like the knowledge is just intrinsically known by everyone so posts assume prior knowledge (which is fine). Plus it evolves over time and it’s totally understandable that there isn’t a place with just all the info, maintaining that as it changes is a lot of work.

Edit: I’m aware the existence of the FX game jam should preclude the notion that it’s “one game at a time” on the FX chip, but I’ve been bitten by assumptions like that before so I’d rather just ask lol

It probably has been said in above messages already but I’d like to go over the bootloader once again as it looks it’s not fully clear yet.

On a normal Arduboy the bootloader is the standard bootloader that is also used by Arduino (Leonardo, micro etc) this bootloader handles receiving a program over USB and programming it into program (application) flash. Without it, a program could only be programmed using special hardware.

The Arduboy FX has a custom bootloader that does not only do the above but also allows it to upload data over USB to the external flash chip (FX chip) and select a game from the external flashchip and program it into the program area of the MCU.

Where the original bootloader starts the game that was previously programmed. The Arduboy FX starts with the bootloader menu. Pressing A or B on the menu screen starts the previously programmed game. Pressing A or B when a game is selected flashes the game and runs it. Whater you do the bootloader program remains unchanged.

Yes. The FX chip has a simple filesystem and can contain programs, program data, save data and development data.

you only would have to choose one game if that game uses up all of the available space. Currently there is no such game. There are 383 programs including some FX games and together they use up about 8.3MB of the available 16MB space.

The tool that creates a flash image will patch the games program so it knows where it’s data is. Each program has it’s own unique data area.

Yes.

Yes

The bootloader gets it’s info from the 256 byte file header stored for each program. check out the Flash Cart thread for more info.

There are two cases:

  • The game is part of a flash image
  • the game is uploaded directly (through Arduino IDE or other tool)

In the first case the flash builder tool patches the program.

In the 2nd case it’s the fxdata build tool that creates a special include file for compilation. In this case the fxdata is always stored at the end of external flash memory
so a user can develop or try out a FX game without changing an existing flash image.

5 Likes

Wow that… answers all my questions! Thank you so much! And thanks for linking the thread; it’s hard to know what’s still valid and what’s not. I’m used to these kinds of things (software in general, hobbyist stuff, etc) moving on, making leftover threads invalid. I had looked at that thread but didn’t dive too deep into it because I was worried if it was still valid; good to know it is.