Program optimize advice, used 96% storage space

Hi coding community. In advance i like to thank you for any advice on improving storage use. This is my first post about coding ever and on arduino.cc . Was lurking around on this forum for a few months, did find many answers, many thanks for the solutions & codes.

But now I run in to potential program storage space problems on this UNO. It has a heavy burden with a tft 2.8" touchscreen shield on top. It is used as a display console. Works pretty well, decoding i2c data and the display does what it should do.

But here is the challenge; reducing storage use, its on the limit 96%

Sketch uses 30986 bytes (96%) of program storage space. Maximum is 32256 bytes.
Global variables use 646 bytes (31%) of dynamic memory, leaving 1402 bytes for local variables. Maximum is 2048 bytes.

In the code hereunder case 10 is where I worked on before noticing the high storage use. Removing the font library will solve the problem, but that's not the challenge and I will end up with that dreadful default font.

Any suggestions?
Thanks Ray

:o The message exceeds the maximum allowed length (9000 characters)
Its not a big sketch, ill attached it, so no code tags, i was so looking forward to use the frickin tags :smiley:

HAL_2020.0.2.ino (14.2 KB)

Is your program finished? If it is, 96% is fine - I have had 100% exactly, and it worked fine.

Why do you need to reduce the program storage space ?

That its at 96% will not affect the operation of the program.

As has been said, it doesn't matter unless you need to add more functionality.

I noticed one easy win though - this code appears twice:

        tft.setCursor(5, 250);
        tft.setTextColor(BLACK);
        tft.print(F("Lb: "));
        tft.println(PrLbFl, 0);
        tft.setCursor(5, 250);
        tft.setTextColor(WHITE);
        tft.print(F("Lb: "));
        tft.println(LbFl, 0);
        PrLbFl = LbFl;

Make a function that does that instead. I'll guess that isn't the only duplication, but I didn't actually check.

Check the Adafruit library for the display, some of their libraries include a logo image that gets preloaded into the display buffer, that can be easily removed.

srnet:
Why do you need to reduce the program storage space ?

That its at 96% will not affect the operation of the program.

Even when it uses the String class? :wink:

wildbill:
Make a function that does that instead. I'll guess that isn't the only duplication, but I didn't actually check.

A quick check shows at least twenty-three occurrences of that basic sequence - with slightly varying coordinates and text to be printed.

Thanks for all the quick responses :slight_smile:

missdrew:
Is your program finished? If it is, 96% is fine - I have had 100% exactly, and it worked fine.

Missdrew, No its not finished, the other cases need other floats

srnet:
Why do you need to reduce the program storage space ?

That its at 96% will not affect the operation of the program.

Srnet, I know but there is more to be added, the sketch is not finished, because i was worried about the storage use.

wildbill:
As has been said, it doesn't matter unless you need to add more functionality.

I noticed one easy win though - this code appears twice:

Make a function that does that instead. I'll guess that isn't the only duplication, but I didn't actually check.

Aha will look in to this suggestion, there are indeed duplicates, thanks. I did only build case 10 the other cases are placeholders to changed and probably have duplicates like the back & next buttons.

david_2018:
Check the Adafruit library for the display, some of their libraries include a logo image that gets preloaded into the display buffer, that can be easily removed.

Thanks David, that i did not expect this, not sure how to remove this logo, but will find out :slight_smile:

dougp:
A quick check shows at least twenty-three occurrences of that basic sequence - with slightly varying coordinates and text to be printed.

I will add some functions thanks dougp

Even when it uses the String class? :wink:

if used once it takes up program space, and any function used does, but i would feel confident with the amount of RAM left. That being said, i do object to the way it is being used here :

 receiveString = "";
  // Serial.println((String)"bytes: " + bytes + " "); // max 32 bytes
  for (int i = 0; i < bytes; i++) {
    dataArray[i] = Wire.read();  
    char c = (char)dataArray[i];
    receiveString += c;
  }

  // Serial.println((String)"string:" + receiveString + " ");
  string = receiveString.substring(0, 2);
  TSt = receiveString.substring(2, 6);
  HSt = receiveString.substring(7, 11);
  LSt = receiveString.substring(12, 20);
  TSt.toCharArray(TStAr, sizeof(TStAr));
  HSt.toCharArray(HStAr, sizeof(HStAr));
  LSt.toCharArray(LStAr, sizeof(LStAr));

If you first have a single byte (which is a char ! ) to built up a 'String' and then use .substring() to parse it, after which you convert it back to char (array) just to use atof().
How about just declaring 4 c-strings and leave the 'String-class' out. that will save a bit.
And this

if (p.z > ts.pressureThreshhold && (px > 155 && px < 233 && py > 10 && py < 40)) {
        displayCase40 = true;
        displayCase = 40;
        delay(200);
      }

this is rather wasteful. Particularly the condition. Also if it the result is always a sort of a up & down button, i am quite sure you can combine that whole thing (both button presses) into a function In fact it doesn't need to be within the switch-case at all.
The case is should only be for different data-display, you respond to up or down, regardless of the state, and simply keep 'displayCase' within it's boundaries.
I also don't see a need for 4 different variables to determine if the screen needs to be redrawn. You do this is 'displayCase' changes value. And what the other guys said. Create functions for the display function. I don't think it will save you an awful lot, They are only calls to functions, with arguments, but every little bit helps. The libraries take up the bulk of the space, and so does the font, so you will have to minimize all the other stuff. Please show us how you get on. You should for sure be able to use code-tags for the result.

In fact, The whole switch-case is only required for what you are displaying, not the values. You should print the values if they change, sure, but regardless of the 'state' of 'displayCase'.

Deva_Rishi:
You should for sure be able to use code-tags for the result.

Thank you Deva, I'll add my progress in this thread

You can reduce the code footprint and getting rid of repetition is certainly worth it just for code clarity. However, you can get far more capable hardware cheaply, so don't drive yourself crazy trying to fit a quart into a pint pot.

Also be aware that the compiler does not recognize when the F() macro has identical text, so will create a separate string in program memory with each use.
Better to create a char array with the text, then print from that.

Deva_Rishi:
if used once it takes up program space, and any function used does, but i would feel confident with the amount of RAM left.

Oh, right... it's flash that is almost full... missed that...

aquaponicsray:
I will add some functions thanks dougp

I think that is definitely the solution in this case.

That zero-element array (dataArray) is going to get you into trouble.

byte dataArray[0];
void receiveEvent(int bytes) {
  receiveString = "";
  // Serial.println((String)"bytes: " + bytes + " "); // max 32 bytes
  for (int i = 0; i < bytes; i++) {
    dataArray[i] = Wire.read();
    char c = (char)dataArray[i];
    receiveString += c;
  }

That zero-element array (dataArray) is going to get you into trouble.

For sure, though i am pretty sure it got optimized out completely in this case.

Ok, why did i put a zero array in there is a mystery. So I checked data type array, indeed its asking for trouble

// byte dataArray[0]; // never use zero-element array
byte dataArray[22]; // The array never get larger than 21

The array never get larger than 21, so dataArray[22] should be ok.

Thanks

edit: but it will add 1+22 bits :slight_smile:

Update:

Ok, made two functions Title() and prevNext() gained 13%
Removed F() basically moved the text from Flash to dynamic memory 3%

Sketch uses 25494 bytes (79%) of program storage space. Maximum is 32256 bytes.
Global variables use 703 bytes (34%) of dynamic memory, leaving 1345 bytes for local variables. Maximum is 2048 bytes.

For now I am happy with the results and learned a few things.

   case 10 :
      if (displayCase) {
        displayCase = false;
        Title("Welkom!");
      }
      if (TkFl != PrTkFl) {
        tft.setCursor(5, 100);
        tft.setTextColor(BLACK);
        tft.print("Tk: ");
        tft.println(PrTkFl);
        tft.setCursor(5, 100);
        tft.setTextColor(WHITE);
        tft.print("Tk: ");
        tft.println(TkFl);
        PrTkFl = TkFl;
      }
      if (HkFl != PrHkFl) {
        tft.setCursor(5, 130);
        tft.setTextColor(BLACK);
        tft.print("Hk: ");
        tft.println(PrHkFl);
        tft.setCursor(5, 130);
        tft.setTextColor(WHITE);
        tft.print("Hk: ");
        tft.println(HkFl);
        PrHkFl = HkFl;
      }
      if (LkFl != PrLkFl) {
        tft.setCursor(5, 160);
        tft.setTextColor(BLACK);
        tft.print("Lk: ");
        tft.println(PrLkFl, 0);
        tft.setCursor(5, 160);
        tft.setTextColor(WHITE);
        tft.print("Lk: ");
        tft.println(LkFl, 0);
        PrLkFl = LkFl;
      }
      if (TbFl != PrTbFl) {
        tft.setCursor(5, 190);
        tft.setTextColor(BLACK);
        tft.print("Tb: ");
        tft.println(PrTbFl);
        tft.setCursor(5, 190);
        tft.setTextColor(WHITE);
        tft.print("Tb: ");
        tft.println(TbFl);
        PrTbFl = TbFl;
      }
      if (HbFl != PrHbFl) {
        tft.setCursor(5, 220);
        tft.setTextColor(BLACK);
        tft.print("Hb: ");
        tft.println(PrHbFl);
        tft.setCursor(5, 220);
        tft.setTextColor(WHITE);
        tft.print("Hb: ");
        tft.println(HbFl);
        PrHbFl = HbFl;
      }
      if (LbFl != PrLbFl) {
        tft.setCursor(5, 250);
        tft.setTextColor(BLACK);
        tft.print("Lb: ");
        tft.println(PrLbFl, 0);
        tft.setCursor(5, 250);
        tft.setTextColor(WHITE);
        tft.print("Lb: ");
        tft.println(LbFl, 0);
        PrLbFl = LbFl;
      }
      prevNext(40, 20);
      break;
void Title(String title) {
  tft.fillScreen(BLACK);
  tft.setFont(&FreeMonoBold18pt7b);
  tft.setTextColor(WHITE);
  tft.setTextSize(1);
  tft.setCursor(40, 45);
  tft.print(title);
  tft.fillRect(10, 270, 100, 40, RED);
  tft.drawRect(10, 270, 100, 40, WHITE);
  tft.setTextColor(WHITE);
  tft.setCursor(30, 298);
  tft.print("<<<");
  tft.fillRect(133, 270, 100, 40, RED);
  tft.drawRect(133, 270, 100, 40, WHITE);
  tft.setCursor(155, 298);
  tft.print(">>>");
}

void prevNext(byte prev, byte next) {
  TSPoint p = ts.getPoint();
  //    map(val, fromLow, fromHigh, toLow, toHigh)
  py =  map(p.x, TS_LEFT,    TS_RT,     0, tft.height()); // 320
  px =  map(p.y,  TS_BOT,   TS_TOP,     0, tft.width());  // 243
  /*
    if (p.z > ts.pressureThreshhold) {
      Serial.println((String)"X = " + px + "");
      Serial.println((String)"Y = " + py + "");
      Serial.println((String)"Pressure = " + p.z + "");
    }
  */
  if (p.z > ts.pressureThreshhold && (px > 10 && px < 180 && py > 10 && py < 40)) {
    displayCase = true;
    displayCase = prev;
    delay(200);
  }
  if (p.z > ts.pressureThreshhold && (px > 155 && px < 233 && py > 10 && py < 40)) {
    displayCase = true;
    displayCase = next;
    delay(200);
  }
}

Thank you all,
Ray

HAL_2020_0_3.ino (11.8 KB)