interchanging dynamic memory and program space

This might be a really stupid question, but please bear with me... I'm not the best :slight_smile:

Is there any possible way to use dynamic memory for program space? My program space is at 101% and my dynamic memory is at 60%. I desperately need more program space.

If this is not possible and if what i am proposing is complete nonsense then does anyone have any tips on how best to improve program space. I need atleast another 10-20% of program space. I'm using a Qduino mini board which has 32KB flash storage and 2.5kb SRAM.

any advice/tips would be greatly appreciated

thanks! :slight_smile:

Thanks for the reply,
I'm creating an arduino based smart watch using the Freetronics OLED (128x128) screen.

One of the biggest issues is the size of the code that displays BMPs in a sequence one after another.

I''m not really sure if i can improve this further since it was created by the engineers at Freetronics and im sure they tried to optimize it as much as they could, here is the code anyway;

while(digitalRead(button) == HIGH) {
uint32_t start = millis();
  for(int i = 0; i < FRAME_COUNT2; i++) {
    char filename[20];
    snprintf(filename, sizeof(filename), "frames3/%03d.bmp", i);
    File frame = SD.open(filename);
      oled.displayBMP(frame, 0, 0);
    frame.close();
  }
  }

I also think they way in which i am displaying messages onto the screen is probably very inefficient, this is how i am doing it. The way in which i am counting down can probably be shortened any ideas would be great.

void breathing_tech()
{     
oled.selectFont(Droid_Sans_24);  
oled.drawFilledBox(0,0,128,128,BLUE);
oled.drawString(0,64, "   Program begins\n     in\n     1", WHITE, BLUE);
digitalWrite(motor, HIGH);
delay(2000);
oled.drawString(0,64, "   Program begins\n     in\n     2", WHITE, BLUE);
digitalWrite(motor, HIGH);
delay(2000);
oled.drawString(0,64, "   Program begins\n     in\n     3", WHITE, BLUE);
digitalWrite(motor, HIGH);
delay(2000);
digitalWrite(motor, LOW);
oled.clearScreen();
oled.drawFilledBox(0,0,128,128,GREEN);
oled.drawString(0,64, "    Hold\n     \n     1", WHITE, GREEN);
delay(2000);
oled.drawString(0,64, "    Hold\n     \n     2", WHITE, GREEN);
delay(2000);
oled.drawString(0,64, "    Hold\n     \n     3", WHITE, GREEN);
delay(2000);
oled.drawFilledBox(0,0,128,128,BLUE);
oled.drawString(0,64, "   Move\n    out\n     1", WHITE, BLUE);
digitalWrite(motor, HIGH);
delay(2000);
oled.drawString(0,64, "   Move\n    out\n     2", WHITE, BLUE);
digitalWrite(motor, HIGH);
delay(2000);
oled.drawString(0,64, "   Move\n    out\n     3", WHITE, BLUE);
digitalWrite(motor, HIGH);
delay(2000);
oled.clearScreen();
oled.drawFilledBox(0,0,128,128,BLUE);
digitalWrite(motor, LOW);
oled.selectFont(Droid_Sans_24);
oled.drawString(0, 80, " Rest. . .", WHITE, BLUE);
oled.selectFont(SystemFont5x7);
oled.drawString(10, 70,"To change exercises\nhold the\nbutton down\n  \nPress nothing to\ncontinue breathing", WHITE, BLUE);
delay(6000);
}

Also the way in which the user cycles through each different menu on the smart watch is listed below. Once again i can probably do this in a more efficient manner:

void loop()
{
if (buttonstate2 == LOW) 
 {
  oled.clearScreen();
  oled.drawFilledBox(0,0,128,128,BLACK);
  while(digitalRead(button2)== HIGH) 
  {
  menu();} oled.clearScreen(); }
else 
 {  
mainclock();
  }

}
void menu ()
{
  oled.selectFont(SystemFont5x7);
  oled.drawString(0,120, "Settings", WHITE, BLACK);
  oled.drawString(0,64, "Biometrics", WHITE, BLACK);
  oled.drawString(90,120, "Advice\n& Tips", WHITE, BLACK);//possibly change to something else
  oled.drawString(0,0, "Back", WHITE, BLACK);
   if (digitalRead(button3) == LOW)
  {
    oled.clearScreen();
    while(digitalRead(button2) == HIGH) {
    settings();
    if (digitalRead(button4) == LOW) 
    {
      oled.clearScreen();
      while(digitalRead(button2) == HIGH){
      oled.selectFont(SystemFont5x7);  
      oled.drawString(0,120, "Min\n  +", BLUE, BLACK);
      oled.drawString(0,64, "Min\n  -", BLUE, BLACK);
      oled.drawString(90,120, "Set\nDate", WHITE, BLACK);
      oled.drawString(0,0, "Back", WHITE, BLACK);
  if (digitalRead(button3) == LOW)
  {   }
    }
    oled.clearScreen();
    settings();
    }
    }
    oled.clearScreen();
    menu();
  }
}
void settings()
{
  oled.selectFont(SystemFont5x7);
  oled.drawString(90,120, "Fitness\n Mode", WHITE, BLACK); 
  oled.drawString(0,64, "Set\nTime\nDate", WHITE, BLACK);
  oled.drawString(0,0, "Back", WHITE, BLACK);


}

Any help would be great!
Thanks :slight_smile:

What version of Arduino IDE are you using? If you're using something from before 1.6.12, update to latest version - thats when they added LTO - "link time optimization". It significantly reduces the size of the compiled binary (though it only helps with code, not raw data like bitmaps)

DrAzzy:
What version of Arduino IDE are you using? If you're using something from before 1.6.12, update to latest version - thats when they added LTO - "link time optimization". It significantly reduces the size of the compiled binary (though it only helps with code, not raw data like bitmaps)

I've got Arduino 1.8.1 does it do it by itself? or do i need to enable something?

some ideas:

1: do not spend resources to spaces and returns
oled.drawString(0,64, " Program begins\n in\n 1", WHITE, BLUE);
could possibly be replaced by 3 calls to drawString, one per line.

2: make messages as short as possible
instead of "Program begins" just use "Start"

3: make datatypes as small as possible
(don't know if this is a valid candidate but it will save a byte )

for(int i = 0; i < FRAME_COUNT2; i++) {
==>
for(uint8_t i = 0; i < FRAME_COUNT2; i++) {

I''m not really sure if i can improve this further since it was created by the engineers at Freetronics and im sure they tried to optimize it as much as they could, here is the code anyway;

I'm sure there will be people around able to squeeze code. Most libraries are a balance between speed and size and maintainability. Optimizing one parameter often degrades the other.

Can you provide a link to the libs used?

Thanks for the advice, much appreciated.
Here are the links to the libraries used:
OLED Screen: GitHub - freetronics/FTOLED: Arduino software library to drive OLED display modules

RTC module library: GitHub - adafruit/RTClib: A fork of Jeelab's fantastic RTC Arduino library

these are the libraries used in my code:

#include <SPI.h>
#include <SD.h>
#include <FTOLED.h>
#include <fonts/SystemFont5x7.h>
#include <fonts/Droid_Sans_24.h>
#include <Wire.h>
#include "RTClib.h"

Something else that i might be able to do is remove any font colours that i am not using.
The Freetronics FTOLED lib contains a large amount of different font sizes and colours.
Do you think removing the colours and fonts that I am not using will save more space?

the standard SDlib might also be a memory eater ...

you might check sdfat library from - GitHub - greiman/SdFat: Arduino FAT16/FAT32 exFAT Library

The FTOLED_TextBox.cpp has no obvious memory hogs. Only thing I found is it contains code to dynamically adjust buffersize, making its runtime behavior less predictable. A fixed buffer < 256 bytes could reduce some administration from the lib and makes indices fit in an 8 bit int iso 16 bit .

  // Check the buffer has enough space for this new character, grow it if not
  uint16_t old_len = this->buffer ? strlen(this->buffer) : 0;
  if(this->buf_sz == 0 || old_len > this->buf_sz - 2) {
    this->buf_sz += 8;
    this->buffer = (char *)realloc(this->buffer, this->buf_sz);
  }
  this->buffer[old_len] = character;
  this->buffer[old_len+1] = 0;

if you have only one type of BMP files you might create a stripped version of FTOLED_BMP.cpp
and remove all compressions not used. If you do not have graphics at all you might strip all BMP related stuff.

oled.drawString(0,64, "    Hold\n     \n     1", WHITE, GREEN);
delay(2000);
oled.drawString(0,64, "    Hold\n     \n     2", WHITE, GREEN);
delay(2000);
oled.drawString(0,64, "    Hold\n     \n     3", WHITE, GREEN);

3 almost similar lines can be minimized by printing the fixed part once and only the changing part when needed. Also using a loop instead of 3 calls might reduce code a bit.

are you using the String class or the sscanf() function somewhere else in your code? watch for some simple calls that adds tons of code into your program.

Thankyou so much for the help,
I'll see if i can cut down the libs. I'm using BMP images (8 bit) all throughout my code, so I'm not sure how much i can remove but i'll play around with it.

And yes, i'm using the string class for my clock and timing program listed below;

void mainclock()
{

  oled.selectFont(SystemFont5x7);
  oled.drawString(0, 20,F( "Menu"), WHITE, BLACK);
  oled.drawString(100, 120,F( "Fitness\nmode"), BLUE, BLACK); 
 char writeString[20];
   DateTime now = rtc.now();
   time.setForegroundColour(WHITE);
   strcat(writeString, (now.hour()));
   strcat(writeString, ":");
   strcat(writeString, (now.minute()));
   oled.selectFont(Droid_Sans_24);
   time.print(writeString);
   time.reset();

   
  strcat(writeString, (now.day()));
  strcat(writeString, "/");
  strcat(writeString, (now.month()));
  strcat(writeString, "/");
  strcat(writeString, (now.year()));
   date.setForegroundColour(WHITE);
  oled.selectFont(SystemFont5x7);
  date.print(writeString);
  date.reset();

}

that's not the String class (with a capital S), that's the standard c-string (good)

using F("xxx") is actually storing the "xxx" string in program memory. usually it's desirable as most developers are short on RAM and not program memory. you might want to get rid of all the F("xxx") macros and just use "xxx" instead; for every character that will free up a byte in your program space (and trailing '\0' for every string).

EDIT: note to self. more coffee needed before making comments :slight_smile:

usually it's desirable

sp. "always it's necessary"

can we go for "Often it's necessary" ? :slight_smile: (I like freedom of choice)

EDIT - freedom of choice is good, freedom to write stupid things for posterity and being corrected is good too :slight_smile:

No, always.

They always originate in flash memory - whether or not they also use up RAM is a choice for the programmer.

AWOL:
No, always.

They always originate in flash memory - whether or not they also use up RAM is a choice for the programmer.

right - dumb of me - more coffee needed :slight_smile: