RAM efficient way of sending string to class function

So my current code works but is starting to consume large amounts of RAM. I am building a display library that contains all the commands/function required for my Arduino to interact with my Nextion interface.

One example: a function in my library class that sends a change of txt value command to any component on the Nextion:

void SAVC_Display::SendText(uint8_t page, char *objectName, char *text) {
    SendPage_Object(page, objectName);
    _DISPLAY.print(F(".txt=\""));
    _DISPLAY.print(text);
    _DISPLAY.print(F("\""));
    SendCommandEnd();
}

In my main c++ file i call this in various different ways: (Screen is my class instance)

Screen.SendText(0, "tYes_Season", "Spring");
Screen.SendText(0, "tHeaderTitle", title);  //title is a char[31] array

I am assuming that by passing these to the function as a literal string (which I want to get away from) it puts the literal string value into RAM at start up or something?

One idea was to create a list of PROGMEM variables to store all the component names. But that test didn’t work as you can’t point to it. I also have over 150 components on my Nextion pages so a little impractical.

I may be missing something obvious here or just being a complete noob.

Any advice/guidance would be greatly appreciated.

Sure you can:

void printProgmemString(const __FlashStringHelper *p);

const char myString[] PROGMEM = "Hello World";

void setup() {
	Serial.begin(115200);
	delay(1000);
	printProgmemString((__FlashStringHelper *) myString);
}

void loop() {
}

void printProgmemString(const __FlashStringHelper *p) {
	Serial.println(p);
}

I’m sure someone can post similar code using one of the fancy C++ specific casting methods. But, quite frankly, I can never keep them straight.

That seems like a feasible solution for solving the usage of RAM.

However as I have over 150 components i’d have to create a PROGMEM variable for every one.

Are there any other solutions?

Why don’t you use an array?

void printProgmemString(const __FlashStringHelper *p);

const char myString[] PROGMEM = "Hello World";
const char stringArray[][10] PROGMEM {
		"String 0",
		"String 1",
		"String 2"
};

const size_t numStrings = sizeof(stringArray) / sizeof(stringArray[0]);

void setup() {
	Serial.begin(115200);
	delay(1000);
	for (size_t i = 0; i < numStrings; i++) {
		printProgmemString((__FlashStringHelper *) stringArray[i]);
	}
}

void loop() {
}

void printProgmemString(const __FlashStringHelper *p) {
	Serial.println(p);
}

Ok, so with your help on the FlashStringHelper casting i actually come up with a solution similar to yours but without the need to declare every single component name as a PROGMEM variable.

So now my class looks like this:

void SAVC_Display::SendText(uint8_t page, const __FlashStringHelper *objectName, char *text) {
    SendPage_Object(page, objectName);
    _DISPLAY.print(F(".txt=\""));
    _DISPLAY.print(text);
    _DISPLAY.print(F("\""));
    SendCommandEnd();
}

and I call the function like so:

Screen.SendText(0, F("tYes_Season"), "Spring");
Screen.SendText(0, F("tHeaderTitle"), title);  //title is a char[31] array

That stores the string into PROGMEM instead of RAM and will pass a pointer to the function. Works a treat.

Just changing this over on that once function has had a huge impact to my RAM usage:

BEFORE
RAM: [== ] 22.4% (used 1832 bytes from 8192 bytes)
Flash: [= ] 13.1% (used 33250 bytes from 253952 bytes)

AFTER
RAM: [== ] 17.9% (used 1468 bytes from 8192 bytes)
Flash: [= ] 13.1% (used 33368 bytes from 253952 bytes)

EDIT:
After changing all the functions that used the methodology in my original post I have saved over 700 bytes of RAM.

RAM: [= ] 14.4% (used 1178 bytes from 8192 bytes)
Flash: [= ] 13.3% (used 33750 bytes from 253952 bytes)

I’ve given you the solution for this one as it was your code that inspired the final solution. Thanks again!

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