Out of RAM! How to get more? (optimize code help for a noob?)

Hey gang-

I think the other/original thread has proven this was a OUT OF RAM problem… and not really a logic problem in the sketch…

Disclaimer:
I have coded things the best I know/thought was the best way… (so if you ask “WHY” I didnt something this way or that… its because I didnt know any better and didnt what worked or what I thought was best practice) :slight_smile:

Summary:
Stage prop/project, Sci-FI blaster
Arduino, WaveShield, 2 x MAX7219 chips (led bargraph & 3-digit 7-segment display)

Problem:
Things are/were working as I believe they should…
when adding in NEW/MORE code, I got odd behavior… Code/routines/functions that previously worked, stopped/or acted oddly, … even though the newly added code/snippets didnt even pertain to the portions that stopped working…

After some clean-up, and the addition of using the F() macro for string literals/Serial.print() stuff…

I got more “FREE RAM” back… and the newly added code snippets started working. Leading me to believe its a RAM issue, and setting out to learn more/discuss ways I can improve this sketch of mine.

I am not very experienced in coding in C/C++ (for Arduino)… so I doubt VERY advanced stuff will work (direct port manipulation and other very advanced approaches may be wasted here?)

However I am open to discussing anything. :slight_smile:

As of now…
the only external libs I am importing are:

#include “LedControl.h”
#include “WaveUtil.h”
#include “WaveHC.h”

*the WaveHC/Util libs are for the audio playback…

*the ledControl lib is for working with the MAX7219 chip(s). 1 for the 3-digit/7-segment display… and 1 for the 30 x SMD 1206 LED bargraph

Being as I have never run into this type of problem before (running out of RAM)…
I want to be clear on the difference of
SKETCH size… (32kb of space for this)
vs
2K of RAM…

when uploading… my sketch size says Im under HALF (around 12-13000+ bytes out of 32256 max)…

yet when I upload things… and have the freeRAM() function spit out the data… Im only (at best) around 195 left! YIKES!!!

I’d like to get suggestions & help on some BASIC tricks/tips people can do to optimize? (or if there is a link/article/tutorial somewhere)…

I’d also like to discuss any more advanced suggestions as well. :slight_smile:

here are some random thoughts I had, but not sure how relevant they are)

1.) removing some of the functions in the sketch? good for only sketch size? or help reduce the free RAM too? (the sdError() & freeRAM() functions for example?)

2.) editing some of the libraries directly? Maybe if Im not using some of the public functions… remove them? Is this ‘only’ good for sketch size again? or helps with RAM?

3.) Maybe changing the data types or way I defined variables?

I still need to add more code/functionality to this sketch…but am hitting a wall without some advanced/divine intervention… LOL

I still need to do the following:

1.) change the ammo counter/display workings (needs to start @ 300 max ammo… go to 240 (-60)…then reload… then down to 180 (-60), reload…then down to 120 (-60)…etc… down to zero!.. where you reload again (and go back to full max ammo count of 300)…

Im assuming thats going to cost me some space/lines of code to implements…

*it already work from counting down from 300-0, so there is SOME code for it, but it’ll need to be changed up.

(*dont ask why it has to be like that… it makes NO sense… but Im trying o replicate ‘game play’ from some video game on this project/prop, and thats how it behaves) :slight_smile:

**2.)**In addition to the 3-digit, 7-segement display I’m updating now, I’ll have another daisey chained MAX chip… that consists of 30 x SMD leds… in a bargraph configuration… (which again will require more code, and space which I’m obviously running out of?) that will dim 1 x led for every 2 shots… (ie: depleting the bargraph when the counter goes down 60 shots ‘per’ reload)

So I need to re-group and ask/learn about how I can optimize/streamline my code to make it smaller/compact…

Being a beginner, and not formally trained/taken classes… I’m not sure if there is a place to start?

sketch attached:

thanks!

DC_17_OSv4_forum_3.ino (15.7 KB)

//make button array for easy looping/checking
int buttons[] = {mainTrigger, reloadButton, grenadeButton};

// This handy macro lets us determine how big the array up above is, by checking the size
#define NUMBUTTONS sizeof(buttons)

Since 'buttons are integers and sizeof calculates in bytes you are setting 'NUMBUTTONS' to 6, not 3. That means your various arrays of are twice the necessary size and I;m guessing some of your loops run long.

Try:

 const int NUMBUTTONS = sizeof buttons / sizeof buttons[0];

johnwasser-

thanks!

the original code this is based off of, is a '6' button WaveShield/WaveHC examples from Adafruit tutorials...

your post got ill-formatted..

this is what you want me to alter it to:

const int NUMBUTTONS = sizeof buttons / sizeof buttons[0]

Im not following the button[0] part at the end?

couldnt I also hardcode it? if it makes ti faster/easier/less space?

(I'm open for that)

I'll try after dinner! (1 about 1 hour)

thanks!

xl97:
Im not following the button[0] part at the end?

This is the recommended technique for calculating the number of elements in the array: the size of the whole array in bytes, divided by the size of an individual element in bytes. You can hard-code the value instead, but that introduces the possibility of maintenance-induced errors since you have to remember to update the hard-coded value every time you alter the array size. One of the fundamental principles of good coding is that you should eliminate duplication - each thing should only be defined once. By calculating the array size rather than hard-coding it, you avoid having the array length defined in two places.

got it..

(suggested hard coding for maybe more RAM available in the end?)

geez.. Im used to just being about to:

var someArray:Array = ["one", "two", "three"];
var arrayLength:Number = someArray.length; //prints 3

just spoiled/sloppy web programming practices I guess. :slight_smile:

I will alter that..

any other suggestions?

Im going to need more I think.. every bit helps! :wink:

thanks!

PeterH gave you the right way to do it:

int myArray[20];
int myArraySize = sizeof(myArray) / sizeof(myArray[0]);

which calculates the total bytes allocated to the array and divides it by the number of bytes allocated to a single element of the array. It's low maintenance in that you can change either the the number of elements in the array or the data type of the array, or both, and myArraySize will remain correct.

Look at using a Bobuino
SRAM: 16Kbytes

http://www.crossroadsfencing.com/BobuinoRev17/
http://www.atmel.ca/devices/ATMEGA1284.aspx

econjack:
PeterH gave you the right way to do it:

int myArray[20];

int myArraySize = sizeof(myArray) / sizeof(myArray[0]);




which calculates the total bytes allocated to the array and divides it by the number of bytes allocated to a single element of the array. It's low maintenance in that you can change either the the number of elements in the array or the data type of the array, or both, and *myArraySize* will remain correct.

ok..

thanks..

I said I'd try it.. and see how much/if any change it gives me.

@ LarryD-

not an option Im afraid.

thanks though! :slight_smile:

Using more appropriately-sized variables may save RAM

const byte modeSelect_btn =  2;
const byte mainTrigger =  18;
const byte reloadButton =  16;
const byte grenadeButton = 19;
byte buttons[] = {
  mainTrigger, reloadButton, grenadeButton};

(which should almost certainly be a "const" anyway)

volatile byte pressed[NUMBUTTONS], justpressed[NUMBUTTONS], justreleased[NUMBUTTONS]; could be expressed in three (two, at a push) bytes, not nine, but I suspect bigger savings than these are required.

AWOL:
Using more appropriately-sized variables may save RAM

const byte modeSelect_btn =  2;

const byte mainTrigger =  18;
const byte reloadButton =  16;
const byte grenadeButton = 19;





byte buttons = {
 mainTrigger, reloadButton, grenadeButton};


(which should almost certainly be a "const" anyway)

`volatile byte pressed[NUMBUTTONS], justpressed[NUMBUTTONS], justreleased[NUMBUTTONS];` could be expressed in three (two, at a push) bytes, not nine, but I suspect bigger savings than these are required.

ok.. giving it a try now. :slight_smile:

@AWOL-

Using more appropriately-sized variables may save RAM

do you mean by define/declaring them as const 'byte' vs, const 'int'?

to summarize.

changes being made:

1.)

//#define NUMBUTTONS sizeof(buttons)
const int NUMBUTTONS = sizeof buttons / sizeof buttons[0]

2.)

// here is where we define the buttons that we'll use.
/*
const int modeSelect_btn =  2;
const int mainTrigger =  18;
const int reloadButton =  16;
const int grenadeButton = 19;
*/
const byte modeSelect_btn =  2;
const byte mainTrigger =  18;
const byte reloadButton =  16;
const byte grenadeButton = 19;

3.)

//make button array for easy looping/checking
int buttons[] = {mainTrigger, reloadButton, grenadeButton};
byte buttons[] = {mainTrigger, reloadButton, grenadeButton};
//or
const byte buttons[] = {mainTrigger, reloadButton, grenadeButton};

4.)

could be expressed in three (two, at a push) bytes, not nine, but I suspect bigger savings than these are required.

not sure what you mean/how to alter it so I am compliant with your suggestion?

I have now made those changes...

looks like very bit helps.. :slight_smile:
Binary sketch size: 13282 bytes (of a 32256 byte maximum)
Free RAM: 218

not sure where to go from here on getting more RAM?

here are the the last 3 sketches, with minimal changes.. and the results:

*Serial Enabled
*Serial.print()'s using F() macro
*data type/casting change to byte vs int
Binary sketch size: 13282 bytes (of a 32256 byte maximum)
Free RAM: 218


*Serial Enabled
*Serial.print()'s using F() macro
Binary sketch size: 13308 bytes (of a 32256 byte maximum)
Free RAM: 199


*Serial Enabled
*Serial.print()'s using F() macro
*putstring() & putstinrg_nl() still used
Binary sketch size: 13172 bytes (of a 32256 byte maximum)
Free RAM: 199

At least I am @ 218.. which is bit a better than the 170-150 range I was in previously..

any other things that may be creating overhead and eating up RAM?

From a quick look, I don't see your sketch using much RAM at all, so it must be the libraries. You might do some analysis of how much RAM each library sucks up, as a starting point. Remove a library, comment out the associated code, and see how the RAM usage changes. Might be in for a shock.

Im sure your right/correct..

but Im not sure where to begin to be able to 'fix' that?

example:

I had the same idea previously...

I had commented out the ledControl lib....

then commented out all start-up/initialization code for the lib/chip.. and all code. (which wasnt much, some inital display settings..and a call to an updateDisplay() function.. every time I need to parse the ammoCount and update the 7-segmnt display)

if I recall correctly.. it gave me like another 200 or so in freeRam()?

I know you can send data to the MAX chips using SPI.... but:
1.) still need to import the SPI lib then...yes? (that much less that the ledControl lib?.. vs. ease of use for ledControl lib?)

2.) Im not sure what parts can be edited from the WaveHC lib... (or the WaveUtil lib)? Kinda just walking a fine line between what can go and what can stay??

Im still learning I guess the balance between RAM and SKETCH size stuff..

example:
I already have all those libs imported.. my sketch size is under HALF......

I add another few lines of code (make a new switch variable name... add that name/var to the buttons Array()...

and then a another else if() to watch for the new button to be pressed... (which the routine is already checking a few other buttons,..array was already created, just less 1 index)..

but that simple addition took up RAM.. and hence made the sketch break/not act as expected... Im a bit 'gun shy' on how much I can even add to this sketch as it is?

example 2:

I commented out importing the WaveUtils lib in the sketch... saved, uploaded...

work as normal? what does it do? why is it needed? (I have it because its in all the WaveHC examples)
doesnt seem to have effect the sketch size, nor the freeRam available?

both report the same:
*Serial Enabled
*Serial.print()'s using F() macro
*data type/casting change to byte vs int
*commented out importing WaveUtils library

Binary sketch size: 13282 bytes (of a 32256 byte maximum)
Free RAM: 218

thanks!

Since there are a couple of libraries, I would first determine how much RAM each one commandeers, as I mentioned.

Then, I would go in and reverse-engineer them - ie, figure out what the heck they are doing, and how the RAM is used. Certainly the wave files use good-sized RAM buffers, so it just may be a matter of making them a little smaller. The 328 chip with only 2KB of RAM is really rather skimpy for sound processing, etc. This is why I use the 1284 chip for almost everything I do anymore.

Unfortunately, reverse-engineering libraries can tend to be a nasty task. I've been completely underwater for weeks, trying to "fix" the RFM12 libraries. Countless problems, which is why people have so much trouble with them in the first place. Hopefully, wave won't be so bad.

Worth a shot!
thats for the positive comments/encouragement..

Looks like the WaveUtils library does..... nothing? (LMAO)..

I edited it out.. nothing changed.. and sketch still seemed to work?

so the only two libs I am using/importing are the WaveHC lib... and the ledControl lib..

Yeah Im learning/seeing the memory limitations rather quickly when using the 328P-PU/AU chips..
but this chip/Arduino in general, is really my first step into electronics/embedded electronics..etc.. and for my project the smallest footprint possibly is always the goal..

so I guess I'll peek into the mysterious .h & .cpp files? (Ive never even made my own library before!!?)

I just added in a few more lines.. (grabbing/parse the color parameter from the .txt file from SD card.. which Im already doing..just wanted to parse another named pair value for the 'grenade color'.. and took like 10bytes in the freeRAM already!!!!!!

Im dead for adding in a new ammo counter routine.. as using another ledControl() function (even though the lib/methods are already in use) :frowning: