Need Help Optimizing Memory Usage for Arduino Nano

Hi Arduino Community,
I'm working on a project with an Arduino Nano and am facing issues related to memory usage and display output. My code currently manages an oled display, handles button inputs, and controls actuators. However, I'm running into memory limitations with the Nano, and the menu display isn’t working as expected. I dont know what to do, please help - its my master thesis project :sob:

#include <splash.h>
#include <Adafruit_SSD1306.h>
#include <Adafruit_GFX.h>

#include <Wire.h>       // I2C für RTC

#define SCREEN_WIDTH 128 // OLED display width, in pixels
#define SCREEN_HEIGHT 64 // OLED display height, in pixels
#define OLED_RESET     -1 // Reset pin # (or -1 if sharing Arduino reset pin)
/* nett am Rande: Mein Display hat die Adresse 0x3C _UND_ 64 Zeilen... */
#define SCREEN_ADDRESS 0x3C ///< See datasheet for Address; 0x3D for 128x64, 0x3C for 128x32

// Pins für drei Buttons
#define BUTTON_LEFT 10
#define BUTTON_MIDDLE 9
#define BUTTON_RIGHT 8

// Pins für Aktuatoren
#define H2VALVE 2
#define O2VALVE 3
#define MOTOR 4

// Display-Objekt
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);

const uint8_t itemCount = 5;     // Anzahl der Menü-Einträge
const uint8_t numShowing = 5;     // Anzahl gleichzeitig angezeigter Einträge
uint8_t firstShown = 1;  // oberster angezeigter Eintrag
uint8_t selectedItem = 1;// aktiver Eintrag

// Beschriftung, aus ästhetischen Gründen ein Dummyeintrag auf Position 0
String menuItems[itemCount+1] = {
  "", 
  "temperature  ", 
  "pressure     ",
  "voltage      ",
  "current      ",
  "power        ",
 };

bool showMenu = true;  // true, wenn das Menü angezeigt wird

String title = "fc-control";

/* actuator states */
bool h2open = false;
bool o2open = false;
bool motor_running = false;

/*
--------------------------------------------------------------------------------------------------------
setup
--------------------------------------------------------------------------------------------------------
*/
void setup() {
    Serial.begin(9600);                   // backup, nicht essentiell
    pinMode(BUTTON_LEFT, INPUT_PULLUP);
    pinMode(BUTTON_MIDDLE, INPUT_PULLUP);
    pinMode(BUTTON_RIGHT, INPUT_PULLUP);

    pinMode(H2VALVE, OUTPUT);
    pinMode(O2VALVE, OUTPUT);
    pinMode(MOTOR, OUTPUT);
    
    // SSD1306_SWITCHCAPVCC = generate display voltage from 3.3V internally
    display.begin(SSD1306_SWITCHCAPVCC, SCREEN_ADDRESS);
    display.setTextColor(SSD1306_WHITE, SSD1306_BLACK); // Draw white text
    initializeDevice(); // init-Prozedur der Brennstoffzelle starten
}

/* Hilfsfunktion: Zeigt Text und einen Countdown an */
void showCountdown(String text, int dt) {
  for (uint16_t i=dt; i>0; i--) {
    makeTitle();
    display.println(text + "\n");
    display.print(String(i) + "s");
    display.display();
    delay(1000);             
  }  
}

void makeTitle() {
  display.setTextSize(2);  
  display.clearDisplay();
  display.setCursor(0,0);
  display.println(title);
  display.setTextSize(1);  
}

/* init-Prozedur der Brennstoffzelle */
void initializeDevice() {
  makeTitle();
  display.println("\nphase 1:\nconnect to cell");
  display.display();
  delay(2000);

  digitalWrite(H2VALVE, HIGH);
  showCountdown("\nphase 2:\nflushing H2", 10);
  digitalWrite(H2VALVE, LOW);

  digitalWrite(O2VALVE, HIGH);
  showCountdown("\nphase 3:\nflushing O2", 5);
  digitalWrite(O2VALVE, LOW);

  digitalWrite(MOTOR, HIGH);
  showCountdown("\nphase 4:\nmotor check", 2);
  digitalWrite(MOTOR, LOW);
  
}

void updateActuators() {
  digitalWrite(H2VALVE, (h2open?HIGH:LOW));
  digitalWrite(O2VALVE, (o2open?HIGH:LOW));
  digitalWrite(MOTOR, (motor_running?HIGH:LOW));  
}

/* Prozedur für die Anzeige nach der Initialisierung */
void updateDisplay() {
  /* Überschrift */
  makeTitle();
  display.println();   
  if (showMenu) {  
    /* Menü anzeigen */            
    for (uint8_t i=firstShown; i<=itemCount && i - firstShown < numShowing; i++) {           
      if (i == selectedItem) display.setTextColor(SSD1306_BLACK, SSD1306_WHITE); // Draw white text    
      display.println((i<10?"  ":" ") + String(i) + " " + menuItems[i]);
      display.setTextColor(SSD1306_WHITE, SSD1306_BLACK);
    }
  } else {
    String output;
    /* Details für aktiven Menüeintrag anzeigen */
    display.println("\n" + menuItems[selectedItem] + "\n");
    display.setTextSize(2);
    switch(selectedItem) {
      case 1 : display.print("24.8 "); 
               display.print(char(247));
               display.println("C");
        break;
      case 2 : display.println("1039 hPa");
        break;
      case 3 : display.println(String(5.0 * analogRead(A0) / 1023, 2) + " V");
        break;
      case 4 : display.println(String(5.0 * analogRead(A0) / 255, 2) + " mA");
        break;
      case 5 : display.println(String(50.0 * analogRead(A0) / 1023, 2) + " mW");
        break;
    }
  }
  display.display();
}


/* 
--------------------------------------------------------------------------------------------------------
loop
--------------------------------------------------------------------------------------------------------
*/
void loop() {
    /* "up"-Button */
    if (showMenu && !digitalRead(BUTTON_LEFT)) {
      delay(50);
      selectedItem = --selectedItem;
      if (selectedItem < 1) selectedItem = 1;
      while (selectedItem < firstShown) firstShown--; 
    }

    /* "down"-Button */
    if (showMenu && !digitalRead(BUTTON_MIDDLE)) {
      delay(50);
      selectedItem = ++selectedItem;
      if (selectedItem > itemCount) selectedItem = itemCount;
      while (selectedItem > firstShown + numShowing - 1) firstShown++;
    }

    /* Detailanzeige ein- und abschalten */
    if (!digitalRead(BUTTON_RIGHT)) {
      delay(50);
      switch (selectedItem) {
        // 1-5 sind Anzeigen
        case 1:
        case 2:
        case 3:
        case 4:
        case 5: showMenu = !showMenu;
          break;
      }
    }
    updateActuators();
    updateDisplay();
    delay(50);
}


You seem to be only using text on the display. Search the library manager for "1306", select a library that is memory-friendly.

1 Like

Hallo solvej

Take a search engine of your choice and ask the WWW for "F macro +arduino" to get some ideas to be sorted out to get the information needed.

1 Like

Are the memory limitations explained in a compile message? If so, please post that information. Your verbal interpretation of what the compiler might be saying isn't sufficient.

1 Like

The text-only SSD1306Ascii library uses very little dynamic memory, whereas the one you are currently using takes up half of it, on the classic Nano.

Of course, you will not be able to use the GFX library with the text-only display library.

1 Like

The compiler is already specifying minimum memory, so you will need to rethink some of your design. As one other poster pointed out, check what the F macro will do.
Masters? GHU!

1 Like

@solvej I'm sure you're in a hurry, but you're not getting much help, because you ignored:

I suggest you take a deep breath and read it. Your asking a bunch of volunteers for help, it's best to try to ease things for us by providing the information required to help you.
Thanks

1 Like

You would be advised to eliminate the use of capital S strings.

If you can't, some of your current use needlessly invokes processing that can make Strings an unfortunate choice.

Instead of expressions building Strings for print

    display.print(String(i) + "s");

just print the terms as they already exist, viz:

    display.print(String(i));
    display.print("s");

This will mean fewer intermediate Strings are being created and thrown away; ideally all your use of Strings could be made as trouble free.

I did not look to see other places you use addition on Strings. It may not be any part of your problem, but in the long run learning how to use small s strings, character arrays in C/C++ is worth the time it will take. It's not terribly difficult, just a wee bit less high level and convenient.

a7

1 Like

I missed this kinda thing:

 display.print(String(i));

No need to make a String to print an integer, just

 display.print(i);

a7

1 Like

Thank you! Using F macro worked

1 Like

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.