Program corruption? Inconsistent and odd failures mid-program

I have a moderately complex program driving an LCD (Using the GLCD library, v3)and a few basic peripheral devices via shift registers, running on a Nano. up until yesterday everything had been working perfectly. The setup is pretty straightforward, a few LCD menus and various operations on the peripherals. Yesterday during testing however I found a strange issue, on the main run, if repeated 24 times without restarting the board, one of various strange bugs will occur:

Everything will freeze, on-screen timer shows up but doesn't count, no input will be accepted.
Certain text elements will corrupt, and instead fill the entire character area with full-block characters, no input will be accepted.
Timer will freeze, input will still be accepted but certain portions of the screen will never show text again (Possibly related to textareas with the GLCD library, I'm still trying to determine if this is the case)
Timer will fail to count and timer text will corrupt, showing only full-blocks where numbers should be. Input still works.
The program will entirely reset, and return to its splash screen.

With the exception of the last on that list, neither reseting the board manually nor power cycling it will fix anything. The programs will either fail to work at all or one of many various LCD display bugs will occur. The only way to fix any of them is to upload the program again.

This is all being done via the Arduino IDE, and everything else seems to be working perfectly fine. This is definitely stranger than anything I have encountered, and despite scouring the code I cannot find anything that would cause these bugs. I'm not even convinced that it's the code causing the issue, though, seeing as the bug only pops up after 24 perfectly normal and successful operations. The only thing I can think of at this point is that the code is somehow getting corrupted, but I don't know how that would happen nor how to fix it if it were.

Due to confidentiality reasons I can't post the entire program, but here is the portion where the bug occurs:

void startrun() { ///

	int sec = 0;
	int min = 0;
	int totalruntime;
	int flowcheckint = 500;
	int clocktime;
	long flowcheckprev = 500;
	boolean flow;
	long flowtimerprevious = millis();
	long runtime = millis();
	shiftwrite(pump, HIGH);
	Title.CursorToXY(34, 4);
	Title.print("Running...");
	
	// Check for button press, if button is pressed, end run.
	while(1) {
		buttons();
		if (select == 1) {
			shiftwrite(pump, LOW);
			totalruntime = ((millis() - runtime) / 1000);
			runminutes = totalruntime / 60;
			runseconds = totalruntime % 60;
			GLCD.ClearScreen();
			runcanceledscreen();
		}
	
	
	// Clock
		gText ClockArea;
		ClockArea.DefineArea(20, 0, 6, 1, fixednums15x31);
		ClockArea.CursorToXY(2,20);
		int lastsec;
		clocktime = (millis() - runtime) / 1000;
		sec = clocktime % 60;
		min = clocktime / 60;
		if(sec != lastsec) {
			ClockArea.Printf("%02d:%02d", min, sec);
			lastsec = sec;
		}


	// Flow buffer check
		if (flow == 1 && millis() - flowtimerprevious >= flowbuff && millis() - runtime >= 20000) {
				break;}
	
	// Check sensor, print debug, set sensor buffer timer
		if (millis() - flowcheckprev >= flowcheckint) {
			flow = flowcheck();
			flowcheckprev = millis();
			if (flow == 0) {
				flowtimerprevious = millis(); 
			}
		}
	}
	

	totalruntime = ((millis() - runtime) / 1000);
	runminutes = totalruntime / 60;
	runseconds = totalruntime % 60;
	shiftwrite(pump, LOW);
	GLCD.ClearScreen();
	runcompletescreen();}
//\

One idea that I had, but am unsure how to test, is that I may be overfilling the RAM. Is there any way to check that? The sketch size as it currently is is 21KB.

Any ideas?

Due to confidentiality reasons I can't post the entire program, but here is the portion where the bug occurs:

Then your help will be limited. While it appears the problem occurs here, the fault site isn't always the problem.

One idea that I had, but am unsure how to test, is that I may be overfilling the RAM. Is there any way to check that? The sketch size as it currently is is 21KB.

The size of the sketch really does not relate to the RAM usage. An analogy for a PC: How does used hard drive space correlate to free RAM? Hint: It doesn't.

If you search the forum there are some crude methods that can help determine how much RAM is being used. However, these methods are not perfect. In general, if you are using strings then you are probably exhausting the RAM. Constants (including String Constants) are copied to RAM before use. This is a detail many people miss.

Move all of your strings to PROGMEM. The sketch size will stay about the same but your RAM usage will drop significantly.

I have quite a few string print operations, but it was my understanding that the RAM they used was quickly dropped once they were written. Is there any way to have them go straight to flash and bypass the ram if they aren't declared as variables? i.e. I have many strings printed via "GLCD.print("blah blah");". Does this consume RAM, and if so, is there any way to force it to go to flash without separately declaring the string as a variable?

Does using 'const' use RAM? Should I replace all my const variables with #define?

I have many strings printed via "GLCD.print("blah blah");". Does this consume RAM

Yes.
Take a look at PROGMEM

Does using 'const' use RAM? Should I replace all my const variables with #define?

These both use RAM. You have to look at the PROGMEM link I already posted.

my understanding that the RAM they used was quickly dropped once they were written

Based on what? If there were a memory manager, maybe that would be the case.

The compiler takes constants and copies them to RAM. That way functions can access those constants. So methods like "const" (which just makes the complier check to see if you are modifying a variable) or #define (which is a macro that gets replaced at compile time) are effectively the same as using "Blah... blah... blah...".

The compiler doesn't really have a way to determine when a constant is or is not needed, so it cannot free the memory "automatically."

Thanks for the replies, I'll definitely be looking deeper into PROGMEM. However, based on what I can see from a quick review it looks like it would require very significant rewrite of large portions of my code, so before I take the time to do that I want to be sure that's the source of the problem. Since I'm able to run the program without a single hitch 23 times, until it breaks on the 24th run, could it actually be RAM overflow that is the source? Could there be some accidental memory leak or some other rouge memory hog pulling a little more RAM after each run?

Sorry if these seem like stupid questions, I'm just starting to get a handle of how memory allocation works.

Is the crash after 24 "steps" repeatable?
It could be that you allocate memory that is not freed again properly (could also be a bug in the libraries BTW)

The compiler doesn't really have a way to determine when a constant is or is not needed, so it cannot free the memory "automatically."

unless the constant is declared local in a function, that is the only exception I know off

it looks like it would require very significant rewrite of large portions of my code,

That shouldn't be the case - the place the strings are output would be about the only place you need to rewrite - the rest is not a "rewrite", just text substitution - the editor and/or the preprocessor can help a great deal here.

robtillaart:
Is the crash after 24 "steps" repeatable?
It could be that you allocate memory that is not freed again properly (could also be a bug in the libraries BTW)

The compiler doesn't really have a way to determine when a constant is or is not needed, so it cannot free the memory "automatically."

unless the constant is declared local in a function, that is the only exception I know off

Yes, it's repeatable, it happens on the 24th repetition consistently. Thanks for the link.

That shouldn't be the case - the place the strings are output would be about the only place you need to rewrite - the rest is not a "rewrite", just text substitution - the editor and/or the preprocessor can help a great deal here.

Well, a major portion of the code is exclusively dealing with an LCD interface, and as you can imagine there are a lot of strings involved with that. It's not insurmountable by any means, it would just require a lot of reworking due to the large number of strings.

Strings are still strings whether they're in RAM or progmem - the only things that are different is how you declare them and how you access them.
A few macros could do most of your work for you.

Ok, thanks to the MemoryFree library posted here I have been able to narrow down the problem significantly. During normal run, the program has more than enough free memory, over a KB, but more gets consumed after each repetition of the main run. So, in light of that I have a couple dumb questions. If the same function that has multiple strings gets called multiple times, would they consume more RAM on each pass or simply reuse old RAM?

Also, I have looked further into PROGMEM, and you're right AWOL, it shouldn't take a huge amount of work to implement it, I just didn't fully understand it before. Still, I want to solve this RAM issue, both for the purposes of this program and to understand what I did wrong and how to fix it later. In light of this, I'm going to post the whole thing and hope that you all can see something that I don't.

The most relevant portions are here, the function names should make the process fairly self-explanatory:

void startmenu() {
	menusize = 2;
	GLCD.DrawRoundRect(0, 0, 126, 20, 5);
	Title.CursorToXY(28,4);
	Title.print("Main Menu");
	ListMenu.CursorTo(3,4); ListMenu.print("Start Run");
	ListMenu.CursorTo(3,5); ListMenu.print("Options");
	GLCD.FillRect(0,22,10,50,WHITE);
	if (cursor == 1) {
		ListMenu.CursorTo(0,4);}
	else {
		ListMenu.CursorTo(0,5);}
	ListMenu.print("->");
		
	while (1) {
		buttons();
		if (down == 1) {
			scrolldown();
			startmenu();}
		if (up == 1) {
			scrollup();
			startmenu();}
		if (select == 1) {
			GLCD.ClearScreen();
			switch (cursor) {
				case 1: startrun();
				case 2: 
					cursor = 1;
					menupos = 1;
					optionsmenu();}}
		if (bitRead(pinvalues, butdown) == 1 && bitRead(pinvalues, butup) == 1) {
			cursor = 1;
			menupos = 1;
			engmenu();}
	}
}


void startrun() {

	// Start run variable, set timers, turn on pump
	uint8_t sec = 0;
	uint8_t min = 0;
	int totalruntime;
	int flowcheckint = 500;
	int clocktime;
	long flowcheckprev = 500;
	uint8_t flow;
	long flowtimerprevious = millis();
	long runtime = millis();
	shiftwrite(pump, HIGH);
	Title.CursorToXY(34, 4);
	Title.print("Running...");
	
	// Check for button press, if button is pressed, end run.
	while(1) {
		buttons();
		if (select == 1) {
			shiftwrite(pump, LOW);
			totalruntime = ((millis() - runtime) / 1000);
			runminutes = totalruntime / 60;
			runseconds = totalruntime % 60;
			GLCD.ClearScreen();
			runcanceledscreen();
		}
	
	
	// Clock
		gText ClockArea;
		ClockArea.DefineArea(20, 0, 6, 1, fixednums15x31);
		ClockArea.CursorToXY(2,20);
		uint8_t lastsec;
		clocktime = (millis() - runtime) / 1000;
		sec = clocktime % 60;
		min = clocktime / 60;
		if(sec != lastsec) {
			ClockArea.Printf("%02d:%02d", min, sec);
			lastsec = sec;
		}


	// Flow buffer check
		if (flow == 1 && millis() - flowtimerprevious >= flowbuff && millis() - runtime >= 20000) {
				break;}
	
	// Check sensor, print debug, set sensor buffer timer
		if (millis() - flowcheckprev >= flowcheckint) {
			flow = flowcheck();
			flowcheckprev = millis();
			if (flow == 0) {
				flowtimerprevious = millis(); 
			}
		}
	}
	totalruntime = ((millis() - runtime) / 1000);
	runminutes = totalruntime / 60;
	runseconds = totalruntime % 60;
	shiftwrite(pump, LOW);
	GLCD.ClearScreen();
	runcompletescreen();
}

void runcanceledscreen() {
	menusize = 2;
	GLCD.DrawRoundRect(0, 0, 126, 20, 5);
	Title.CursorToXY(19,4);
	Title.print("Run Canceled");
	ListMenu.CursorTo(3,4); ListMenu.print("Run time: "); 
	ListMenu.Printf("%02d:%02d", runminutes, runseconds);
	ListMenu.CursorTo(3,5); ListMenu.print("Extract");
	ListMenu.CursorTo(3,6); ListMenu.print("Home");
	GLCD.FillRect(0,22,10,50,WHITE);
	if (cursor == 1) {
		ListMenu.CursorTo(0,5);}
	else {
		ListMenu.CursorTo(0,6);}
	ListMenu.print("->");
	while (1) {
		buttons();
		if (up == 1) {
			scrollup();
			runcanceledscreen();}
		if (down == 1) {
			scrolldown();
			runcanceledscreen();}
		if (select == 1) {
			GLCD.ClearScreen();
			switch (cursor) {
				case 1: extract();
				case 2: cursor = 1; startmenu();
			}
		}
	}
}

And the entire program is here, if the problem doesn't seem to be contained in the above functions: http://pastebin.com/HXCdchcr

I'm fairly new to coding, so you'll probably find a hundred and one glaring mistakes. Even if they're unrelated, I'd love to hear any advice, I wanna make my stuff as watertight as possible. In the meantime, I'll work on implementing PROGMEM, even though I'm not sure it's entirely necessary at this point. It'll be a good learning experience. :slight_smile:

Thanks a lot for all your help, everyone.

I can't see anything obvious, but one thing I'd say is you've got a lot of comments like this:

597.} //\

Be very, very careful with backslashes in C++ comments.
Backslash is a continuation character, so you think you're writing something like

// this is my comment \
#define PIN1 12

What the compiler sees is // this is my comment #define PIN1 12

Get out of the habit now, before it causes you hair-loss.

Thanks for the heads up, I was using that for a custom folder close syntax in n++, guess it was a bad choice of characters. :blush:

On the subject of PROGMEM, I'm wondering if there's any more straightforward way than string tables, specifically any inline method. Right now I'm pretty much copying posted methods verbatim:

	prog_char options_0[] PROGMEM = "Start extract";
	prog_char options_1[] PROGMEM = "Ext. fluid prime";
	prog_char options_2[] PROGMEM = "Decon cycle";
	prog_char options_3[] PROGMEM = "Rinse Cycle";
	prog_char options_4[] PROGMEM = "Ext. size";
	prog_char options_5[] PROGMEM = "Beep vol.";
	prog_char options_6[] PROGMEM = "Return";
	
	PROGMEM const char *options_table[] = {   
	options_0,
	options_1,
	options_2,
	options_3,
	options_4,
	options_5,
	options_6, };

char* readoptions(uint8_t whichstring) {
	strcpy_P(buffer, (char*)pgm_read_word(&(options_table[whichstring])));
	return buffer;
}


blah blah.print(readoptions(3));

This works fine, it's just a little laborious, and hard to keep track of when you have a lot of unrelated strings.

I just did a more comprehensive memory test, something is definitely going wrong. Every single print action(even moving the cursor), repeated or otherwise, consumes more RAM that it never frees up again. I'm by no means an expert on this in any way, but surely that's not the way memory allocation works normally?

This means that if I have ANY strings printing in the entire program(that aren't PROGMEM), they will eventually consume all the RAM if repeated enough times. That's a pretty big problem, but at this point I don't think it's my code that's at fault. Anyone have any ideas for how to fix this? I can migrate all my strings to PROGMEM, but that's not an ideal solution, especially since it obfuscates the code even more, and I'd still like to be able to know how to fix things like this.

his means that if I have ANY strings printing in the entire program(that aren't PROGMEM), they will eventually consume all the RAM if repeated enough times

Well, since this doesn't normally happen, it's your problem.
You're doing something wrong.

Every single print action(even moving the cursor), repeated or otherwise, consumes more RAM that it never frees up again.

How are you determining that? You might be working with a flawed test (or flawed assumption).

I was using the memory test library from this page, and testing the memory after every print action. The amount of memory consumed was consistent with the number of characters in the string, and the failure rate was also consistent with my previous testing of the problem. So at this point I'm fairly confident that the problem is the RAM not being freed up after being used to print a string. I'll keep combing my code, but if anyone has any experience with this, it would be really helpful.

o at this point I'm fairly confident that the problem is the RAM not being freed up after being used to print a string.

What memory would the "print" methods use, other than the supplied buffer to be printed and stack?

I'm not entirely sure, as they're functions provided by the GLCD library, something which I'm also digging through, although I'm not sure that's the source of the problem, since I've made multiple programs using it, even ones that are very string heavy, and this has never been a problem before. I'll try to find the relevant functions in the library and post them here.

I moved all my strings to RAM using "GLCD.printFlash(flashStr("string"));" as per the suggestion of the GLCD library author, and while it freed up a few hundred bytes, it didn't change the problem. The program is still consuming large amounts of RAM every time there is a print action, and never freeing it up later. I'm clueless as to what the problem could be at this point.