I think I might do a little experiment with the FX library. What should be saved to the FX chip’s flash memory, and what should go on the Arduboy’s flash memory? Things like particles maybe? Or would you only save stuff to the FX chip when the Arduboy’s progmem is full?
I recommend to have a go at the examples included with the FX library.
any (read only) data that otherwise takes up precious flash program memory. Graphics are the most easiest to store. They can be drawn using the FX::drawBitmap() function that works quite similar to the Arduboy2::Sprites class.
Any read-only data other than machine code.
Graphics, sounds, text, and level data should all be possible to store off-board.
It depends what kind of game you’re making.
The graphics for the particles perhaps, but the particles themselves would need to be in RAM, otherwise they couldn’t move around.
So basically, the actual code code (like, idk, player movement?) goes to the program memory, and the drawing (and related subjects) go to the flash chip? So things like Sprites::drawOverwrite()
, arduboy.print()
, etcetera (purely as an example) should instead be stored on the flash chip?
Also, is there some sort of class reference for the FX library? Maybe I just missed it but I can’t find one in the GitHub repo.
You can’t execute code from the flash chip. You can only store data on it. It’s possible that that “data” could be executable code but you would have to have code that would read it from the flash chip and burn it into program memory for execution.
Oh, I see. So rather than the drawing, you would store the images themselves? Rather than using a .h or .ino file?
Yes, more or less. Read-only data that would normally take up space in, and be retrieved from, program memory could instead be stored in, and retrieved from, the flash chip.
Would that apply to constants as well? Since they’re read-only (right?)
To add to what @MLXXXp has said:
As far as I’m aware, this is only possible when the Arduboy is in bootloader mode and thus generally impractical. (It also uses up flash write cycles.)
A more practical approach is to write a virtual machine (VM), then the VM’s bytecode can be stored on the FX chip. The downside there is the overhead of the VM - it would require progmem space for the VM code and extra CPU cycles for decoding the VM instructions.
(If anyone ever wants to attempt such a thing, I happen to know a thing or two about writing compilers, as well as some good resources for compiler writing.)
That’s not really a good idea unless they’re large constants.
A better way to approach it is to treat the FX chip as you would a file system and store on it things that would normally be stored in and loaded from a resource file.
E.g.
- Graphics
- Music
- Text
- Particularly in larger quantities
- If you’re clever with your design you could potentially use this for localising text
- Level Data
- This will depend on the game. A 2D tile-based game would likely store a tile map, whereas a 3D game might store a BSP tree, and a rythm game might use a list of buttons and timings.
- Bytecode Scripts
- Specific to whatever VM is implemented in progmem.
As far as I’m aware, no.
You could run Doxygen to get a summarised list of functions, types, and constants, but the comments aren’t in Doxygen format so you likely wouldn’t get any documentation to go with it.
The machine code that your source code compiles to.
(Did I cover anything about how CPUs work and how compilation works when I was helping you with Flappo? I can’t remember. If not, I’m happy to go over them for you.)
You did mention compilation and how it turns everything into a big combined file and other stuff like #include, defines, etcetera. I don’t think anything about CPUs though.
If you want me to go through how CPUs work (and specifically AVR, since that’s what the Arduboy uses) then I’m happy to do so when I have the time to spare.
Sure. I don’t actually know anything (besides the obvious stuff like how they function as a computer’s brain) about CPUs other than the fact they have billions of transistors which do all the calculations and stuff, and the whole “ones and zeros” thing probably refers to the state of certain transistors.
Also, just curious, is there anything that could “go wrong” when experimenting/using the flash chip? Like, how EEPROM has limited read and writes, anything like that?
It technically has a write limit, but it’s a large-ish write limit and you’re not likely to accidentally erase a block in a loop like you might with EEPROM.
That aside, there’s not much more to worry about than you’d have to worry about when uploading to progmem (e.g. data might possibly become corrupted if the connection is interrupted at an awkward moment).
Most (modern) hardware is fairly robust and there’s not many things that can happen accidentally that would cause significant damage.
I would presume it takes more than just a transistor to build a gated data latch, but I don’t really know much about the electronic level - what I know only extends to the level above that, the logic level. (The ‘levels’ being levels of abstraction.)
Another question I have: Would you still have to use arduboy.display()
and arduboy.clear()
in the loop function? Or does FX::display(CLEAR_BUFFER)
replace all that? If so, would arduboy.pollButtons()
go before?
So basically:
void loop()
{
if (!arduboy.nextFrame())
return;
arduboy.pollButtons();
FX::display(CLEAR_BUFFER);
}
or
{
if (!arduboy.nextFrame())
return;
arduboy.clear();
arduboy.pollButtons();
FX::display(CLEAR_BUFFER);
arduboy.display();
}
This is of course being said if all assets are being loaded from the FX chip.
Thanks
The first one …
void loop()
{
if (!arduboy.nextFrame()) return;
arduboy.pollButtons();
// Do all your player / enemy movements
// Render all your stuff ..
// Lastly, display the screen ..
FX::display(CLEAR_BUFFER);
}
To give a slightly more in-depth explanation as to why FX::display
exists…
The reason you need to use FX::display
instead is because the screen and the FX chip both use SPI (‘serial peripheral interface’) for communication, and only one can use the connection at a time.
The FX::display
function temporarily redirects the SPI connection to the screen long enough to send the frame data to be sent, and then when that’s done it changes it back to how it was before so the FX chip can be used afterwards.
(My terminology might be a bit imprecise as I only have a vague idea of how it works. I.e. whether it’s merely a change of destination or whether there’s some kind of passing of control involved.)
I like to think of it (abstractly) as SPI being a train track with one branch going to the screen and one going to the FX chip, and the FX::display
function is temporarily pulling the lever at the junction.
Theoretically FX::display
should be equivalent to:
someFunctionThatPassesSPIControlToTheScreen();
arduboy.display();
someFunctionThatGivesSPIControlBackToTheFX();
(I don’t know if those functions exist in the FX library, let alone what they’d be called.)
Also, technically you can actually do arduboy.display(CLEAR_BUFFER)
, and you should be able to mix arduboy.clear()
with FX::display()
. The difference between the approaches is when the frame buffer is cleared: either at the start of the update/frame cycle or at the same time as the frame data is sent to the screen.
It wouldn’t actually matter if you’re mixing on-chip and off-chip images. All the standard drawing functions draw to the frame buffer, regardless of where the image comes from.
The only part where the fact the FX chip is in use becomes important for drawing is at the point where the frame data needs to be sent to the screen because of the aforementioned need to switch the SPI destination.
Yes, pollButtons
stays where it would normally be: after the nextFrame
check and before any updating or drawing. Button polling doesn’t interact with screen updating whatsoever. (“Separation of concerns”.)
Thanks! I have another question about the addressing:
How do you choose what address you assign stuff to (in the fx-data.h
file)? Is it random or is there a whole thought process to it? Is it possible the address you assign something (which is going to be saved to the FX chip) can overwrite existing data/flashcarts?
These things are address’, right?
You shouldn’t modify anything in the fxdata.h file. It is created by the FX build tool.
if you want to control the order of data. then you change the order of the data in the fxdata.txt file.
No as each program gets it’s own chunk of flash memory which starts at (virtual) address 0.
I’m confused. Don’t you add stuff you want to save to the FX chip to the fxdata.h
file, then you use the build tool to get the .bin
?
No, you add your stuff to the fxdata .txt file