Reducing PROGMEM and RAM Usage: Difference between revisions

From Arduboy Wiki
Jump to navigation Jump to search
Line 23: Line 23:


    arduboy.begin();
    arduboy.begin();
    arduboy.setFrameRate(10);
    arduboy.setFrameRate(10);


Line 30: Line 29:
void loop() {
void loop() {


    if (!arduboy.nextFrame())
    if (!arduboy.nextFrame()) return;
 
        return;


    arduboy.clear();
    arduboy.clear();
    x++;
    x++;


    arduboy.print(x / 10);
    arduboy.print(x / 10);
    arduboy.display();
    arduboy.display();


}
}
</pre>
</pre>
** That small modification will save us thousands of bytes!
** That small modification will save us thousands of bytes!
* Use [https://godbolt.org/#g:!((g:!((g:!((h:codeEditor,i:(filename:'1',fontScale:14,fontUsePx:'0',j:1,lang:c%2B%2B,selection:(endColumn:2,endLineNumber:7,positionColumn:2,positionLineNumber:7,selectionStartColumn:2,selectionStartLineNumber:7,startColumn:2,startLineNumber:7),source:'//+Type+your+code+here,+or+load+an+example.%0A%23include+%3Cstdint.h%3E%0A%0Auint8_t+div_thousand(uint32_t+x)+%7B%0A%0A++++return+x+/+1024%3B%0A%7D'),l:'5',n:'1',o:'C%2B%2B+source+%231',t:'0')),k:50,l:'4',n:'0',o:'',s:0,t:'0'),(g:!((h:compiler,i:(compiler:avrg1410,filters:(b:'0',binary:'1',binaryObject:'1',commentOnly:'0',debugCalls:'1',demangle:'0',directives:'0',execute:'1',intel:'0',libraryCode:'0',trim:'1',verboseDemangling:'0'),flagsViewOpen:'1',fontScale:14,fontUsePx:'0',j:1,lang:c%2B%2B,libs:!(),options:'-O2+-mmcu%3Datmega32u4',overrides:!(),selection:(endColumn:1,endLineNumber:1,positionColumn:1,positionLineNumber:1,selectionStartColumn:1,selectionStartLineNumber:1,startColumn:1,startLineNumber:1),source:1),l:'5',n:'0',o:'+AVR+gcc+14.1.0+(Editor+%231)',t:'0')),k:50,l:'4',n:'0',o:'',s:0,t:'0')),l:'2',n:'0',o:'',t:'0')),version:4 Godbolt] to see the assembly that the provided code will generate. You don't need to know assembly, the most important thing is if you see a function call to do an arithmetic operation, you may be able to avoid it. This is helpful to avoid division and mod, as discussed below.
* Use [https://godbolt.org/#g:!((g:!((g:!((h:codeEditor,i:(filename:'1',fontScale:14,fontUsePx:'0',j:1,lang:c%2B%2B,selection:(endColumn:2,endLineNumber:7,positionColumn:2,positionLineNumber:7,selectionStartColumn:2,selectionStartLineNumber:7,startColumn:2,startLineNumber:7),source:'//+Type+your+code+here,+or+load+an+example.%0A%23include+%3Cstdint.h%3E%0A%0Auint8_t+div_thousand(uint32_t+x)+%7B%0A%0A++++return+x+/+1024%3B%0A%7D'),l:'5',n:'1',o:'C%2B%2B+source+%231',t:'0')),k:50,l:'4',n:'0',o:'',s:0,t:'0'),(g:!((h:compiler,i:(compiler:avrg1410,filters:(b:'0',binary:'1',binaryObject:'1',commentOnly:'0',debugCalls:'1',demangle:'0',directives:'0',execute:'1',intel:'0',libraryCode:'0',trim:'1',verboseDemangling:'0'),flagsViewOpen:'1',fontScale:14,fontUsePx:'0',j:1,lang:c%2B%2B,libs:!(),options:'-O2+-mmcu%3Datmega32u4',overrides:!(),selection:(endColumn:1,endLineNumber:1,positionColumn:1,positionLineNumber:1,selectionStartColumn:1,selectionStartLineNumber:1,startColumn:1,startLineNumber:1),source:1),l:'5',n:'0',o:'+AVR+gcc+14.1.0+(Editor+%231)',t:'0')),k:50,l:'4',n:'0',o:'',s:0,t:'0')),l:'2',n:'0',o:'',t:'0')),version:4 Godbolt] to see the assembly that the provided code will generate. You don't need to know assembly, the most important thing is if you see a function call to do an arithmetic operation, you may be able to avoid it. This is helpful to avoid division and mod, as discussed below.

Revision as of 05:25, 14 July 2024

Overview

The Arduboy only has 28KiB or 29KiB (FX) of PROGMEM and 2.5KiB of RAM. While making a game, these can run out very quickly. This page aims to help you recover some of your precious PROGMEM and RAM.

Tips for Reducing PROGMEM

  • Look through your code in Ardens for large functions that shouldn't be there. Here is a step-by-step example: (Note: this will only work with .elf files, .hex files don't provide enough information.)
    • Launch Ardens and drag your .elf file on it.
    • Open the disassembly tab (Windows>Debugger>Disassembly)
      Opening the disassembly tab.
    • Click on the "Jump to Function" dropdown.
      The example contents of the Jump to Function dropdown. Note the amount of floating-point functions present.
    • Scan the dropdown for anything unexpected.
    • In our example, there are a huge amount of float functions that are taking up a lot of space.
    • How can we fix this? In our source code, we can change x from a float to a uint8_t:
#include <Arduboy2.h>

Arduboy2 arduboy;

-- float x;

++ uint8_t x;

void setup() {

    arduboy.begin();
    arduboy.setFrameRate(10);

}

void loop() {

    if (!arduboy.nextFrame()) return;

    arduboy.clear();
    x++;

    arduboy.print(x / 10);
    arduboy.display();

}

Tips for Reducing RAM

  • Put PROGMEM on arrays/data that will not change. Note you will have to use pgm_read_byte(&array[index]) or some variant of it (see documentation here).
  • Declare variables constexpr if they do not change.
  • Put string literals in PROGMEM by surrounding them with the F("string literal here") macro. Pharap's FlashStringHelper library is very helpful when dealing with strings in PROGMEM.
  • Use locals instead of globals when possible. Locals are stored on the stack and exist only in a scope, while globals are stored for the entire lifetime of the program.
  • Pack variables into bits as much as possible. For example, instead of using an array of 8 bools, use 1 byte with each bit representing a bool. Reading and writing bits can be done with bitRead(number, bit) and bitWrite(number, bit, value).