Show Posts
Pages: [1] 2
1  Using Arduino / Programming Questions / Re: Function calls and memory usage on: August 05, 2011, 09:54:57 pm
Thanks all for your help, I'll be changing the layout of a lot of this now that I have a better understanding of how function calls, and stack allocation work.


@Nick Gammon: That suggestion would work in this particular instance, but the program has many more menus and dialogs separated into functions and their start and end points aren't always so conveniently sequential - I'll have to do a fairly major overhaul to fix it. Thanks for the advice anyway.  smiley
2  Using Arduino / Programming Questions / Re: Function calls and memory usage on: August 05, 2011, 06:41:27 pm
Actually... Would it be possible to get around this issue using memory allocation?
3  Using Arduino / Programming Questions / Re: Function calls and memory usage on: August 05, 2011, 06:36:56 pm
Looks like I have a lot of restructuring work ahead of me then... Thanks for the help.
4  Using Arduino / Programming Questions / Re: Function calls and memory usage on: August 05, 2011, 05:48:41 pm
Here is a portion that exhibits the problem:


Code:
void startmenu() {
menusize = 3;
GLCD.DrawRoundRect(0, 0, 126, 20, 5);
ptitle(28, 4, ("Main Menu"));
pnorm(3, 4, ("Start Run"));
pnorm(3, 5, ("Run Options"));
pnorm(3, 6, ("System Options"));
pnorm(3, 3, ("Pressure: "));
ListMenu.print(analogRead(6));
pnorm(0, cursor+3, ("->"));

while (1) {
buttons();
if (down == 1) {
scrolldown();
GLCD.FillRect(0,22,10,50,WHITE);
pnorm(0, cursor+3, ("->"));
ListMenu.CursorTo(0,7); ListMenu.print(freeMemory());}
if (up == 1) {
scrollup();
GLCD.FillRect(0,22,10,50,WHITE);
pnorm(0, cursor+3, ("->"));
ListMenu.CursorTo(0,7); ListMenu.print(freeMemory());}
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 optionsmenu() {
menusize = 5;
GLCD.DrawRoundRect(0, 0, 126, 20, 5);
ptitle(40,4, ("Options"));
pnorm(3,3, (readoptions(menupos-1)));
pnorm(3,4, (readoptions(menupos)));
pnorm(3,5, (readoptions(menupos+1)));
pnorm(3,6, (readoptions(menupos+2)));
pnorm(3,7, (readoptions(menupos+3)));
pnorm(0,cursor-menupos+3, "->");
while (1) {
buttons();
if (down == 1){
scrolldown();
GLCD.FillRect(0,22,10,63,WHITE);
pnorm(0,cursor-menupos+3, "->");
ListMenu.CursorTo(0,7); ListMenu.print(freeMemory());}
if (up == 1){
scrollup();
GLCD.FillRect(0,22,10,63,WHITE);
pnorm(0,cursor-menupos+3, "->");
ListMenu.CursorTo(0,7); ListMenu.print(freeMemory());}
if (select == 1) {
switch(cursor) {
case 1: GLCD.ClearScreen(); extract();
case 2: foampurge();
case 3: decon();
case 4:
pnorm(0,cursor-menupos+3, "  ");
cursorlast = cursor;
menuposlast = menupos;
cursor = extsize;
extractvolume();
case 5:
GLCD.ClearScreen();
cursor = 2;
startmenu();
}
}
}
}

It's part of an LCD interface, it's fairly straightfoward. Each function declares the size of the menu(for scrolling etc), prints all the necessary lines, then checks for button presses. If I go back and forth between startmenu() and optionsmenu() (or to any other of the several similar functions the program has), it uses up a few bytes of RAM. If I understand what you are saying correctly, there is no way to free this memory? Apparently I still have a lot to learn then.
5  Using Arduino / Programming Questions / Re: Function calls and memory usage on: August 05, 2011, 04:24:50 pm
Thanks for the info wildbill, but this goes against all the other places I've read and also my own testing - are you sure the memory is made available again once another function is called from inside a function?

Just to be clear, none of my functions fall out the bottom - all of them end either with return statements or another function call.

Function A will call function B and function B will call function F and function F will call function E... etc. And using the memory test available from here I can see memory being used only when calling a function that returns nothing - calling functions with returns doesn't hold memory the way that functions without returns do. I'll post some code later if possible.
6  Using Arduino / Programming Questions / Function calls and memory usage on: August 05, 2011, 03:48:51 pm
I recently made a thread about this issue, assuming that it was caused by a memory leak relating to string usage, however after much testing and learning I've found that the problem is instead much more plain: function calls.

I have a fairly large program that uses a lot of void functions, calling between each other constantly, most of the time not returning anything - at first I thought this was fine, but now I've learned that every time a function is called, it allocates memory in the stack that is not freed up until the call is returned. The problem is, on void functions, there's nothing to return and that would make the flow of the program an impossibility. The problem is that every time a function is called without being returned (Only a few of the functions in the program need to return) it uses up a few bytes of RAM. Sadly, this adds up really quick and after a enough function calls are made the Arduino runs out of memory and proceeds to bug out in a variety of annoying ways.

So my question is: Is there any way to free up the stack space from all the function calls that never get returned? Restructuring the program at this point is pretty much out of the question, it's too complex and intertwined and I'm not sure if the program could be fundamentally restructured without separation into functions as it is now. Or is there any way to 'trick' Arduino into dumping the memory without actually doing a return?

Why do voids work like this? You would expect a function that doesn't return anything to work fundamentally under that assumption - namely that it shouldn't hold RAM space that it will never use forever.

Hope someone can help, thanks in advance.
7  Using Arduino / Installation & Troubleshooting / Re: Program corruption? Inconsistent and odd failures mid-program on: July 27, 2011, 01:13:29 pm
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.
8  Using Arduino / Displays / Re: GLCD library version 3 on: July 26, 2011, 03:38:49 pm
Thanks very much for the help! "GLCD.printFlash(flashString("string"));" didn't work, however changing "flashString" to "flashStr" fixed it. It's a tad convoluted, but it does the trick, thanks for the help.  smiley
9  Using Arduino / Displays / Re: GLCD library version 3 on: July 26, 2011, 10:36:33 am
I've been having a bit of a problem with the library recently. Due to some memory issues, I'm trying to migrate all my strings to flash space, initially I thought this would be simple due to the built-in commands that move strings from print commands to the flash space, but I've been getting errors on the ones I need:

With "GLCD.print(flashStr(""));" I get this error: "error: call of overloaded 'print(_FlashString*)' is ambiguous"
With "GLCD.printFlash("");" I get this: "error: no matching function for call to 'glcd::printFlash(const char [17])'"

"printf_P(PSTR(" does work, however, but it can't be used for the majority of my strings, as you can imagine. Any ideas what could be causing this, and how to fix it?
10  Using Arduino / Installation & Troubleshooting / Re: Program corruption? Inconsistent and odd failures mid-program on: July 25, 2011, 09:53:50 am
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.
11  Using Arduino / Installation & Troubleshooting / Re: Program corruption? Inconsistent and odd failures mid-program on: July 25, 2011, 09:06:02 am
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.
12  Using Arduino / Installation & Troubleshooting / Re: Program corruption? Inconsistent and odd failures mid-program on: July 22, 2011, 12:58:14 pm
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.
13  Using Arduino / Installation & Troubleshooting / Re: Program corruption? Inconsistent and odd failures mid-program on: July 22, 2011, 12:12:20 pm
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.  smiley-red


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:

Code:
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.
14  Using Arduino / Installation & Troubleshooting / Re: Program corruption? Inconsistent and odd failures mid-program on: July 22, 2011, 11:09:19 am
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:

Code:
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.  smiley

Thanks a lot for all your help, everyone.
15  Using Arduino / Installation & Troubleshooting / Re: Program corruption? Inconsistent and odd failures mid-program on: July 22, 2011, 09:17:25 am

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)

- http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1213583720 - describes how to test freeRAM  Post #18 (page2)

Quote
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.

Quote
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.
Pages: [1] 2