Atmega328 SRAM problems

…I have problems with code I’m just writing for my first own PCB with Atmega328 (programmed via programmer).
Beside “setup” and “loop” the program consists of two functions (“attractMode” and “runShip”).
Both functions are independent of each other and they individually need less than 2kB of ram.
They are called in “loop” sequentially. When I uncomment one of the functions, the other one runs without problems, but when both are used the program crashes!
For me this looks like a problem with SRAM!
As the complete code is too big to post here, I only post the function’s variable declaration parts and the “loop”-function!
It might be of importance to inform you that the functions make use of “Wire” and “Serial”-library functions!

#include "Arduino.h"
#include <Wire.h>

#define LEDANIMSTARTADDRESSSD 1997952000
#define DISPLAY_RESET A1
#define MOTOR_ENABLE 2
#define MOTOR_ROTATING_DIRECTION_1 4
#define MOTOR_ROTATING_DIRECTION_2 8
#define STROBO_LEDS 9
#define PIR A7
#define COMPARATOR_IN1 6
#define COMPARATOR_IN2 7
#define WAITLOOP -1
#define BRAKE -2
#define SCALE 1
#define PHOTOTRANSISTOR A6
#define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit))
#define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit))

byte numLedAnims = 0, numVideos = 0;
unsigned long ledAnim[70], videoStartSector[] = {0x48, 0x94e, 0xdf52, 0xbcf, 0x3c59, 0xbdd, 0x35911, 0x802, 0x41942, 0x136a, 0},
              ledAnimStartAddressSD = LEDANIMSTARTADDRESSSD, minTime2WaitNextRun = 0;
void setup()
{
byte i;
word i_w;
.
.
.
}
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void loop()
{
  attractMode();
  runShip();
}
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void attractMode()
{
byte animChoosen[70], dimCnt = 0, ledFrameBuffer[32] = {0}, pir = 0,
     ledAnimData[2 * 512], i, j = 4, ledCnt = 0, bufferFilled = 0, waitForACK = 0,
     remainingLedAnims = 0, zeroOrOne = 0,
     videoFrame[] = {0x40, 0x49, 0x00, 0x00, 0x60, 0x40, 0x10, 0x00, 0x00, 0x00};
word i_w = 0, j_w = 0, videoFrameCnt = 0;
unsigned long ledAnimLastSector, time, time2waitLed = 0, time2waitVidFrame = 0, videoCurrentFrameSector, longEnough = 0, cnt = 0;
.
.
.
}
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void runShip()
{
int shipAnimSeq[] = {
WAITLOOP, 150*SCALE,
500, 100*SCALE,
BRAKE, 500/SCALE,
5000, 500*SCALE,
WAITLOOP, 100*SCALE,
1000, 200*SCALE,
BRAKE, 1000/SCALE,
6000, 200*SCALE,
WAITLOOP, 100*SCALE,
3000, 400*SCALE,
BRAKE, 800/SCALE,
WAITLOOP, 100*SCALE,
1500, 200*SCALE,
BRAKE, 2000/SCALE,
3000, 500*SCALE,
0, 0};
int stroboAnimSeq[] = {WAITLOOP,WAITLOOP,3000,20,WAITLOOP,3500,20,0,0};
boolean HighLow = LOW, Loop = 0, stroboState = 0;
byte i;
int shipAnimCounter = 0, powerDelay = 0, stroboAnimCounter = 0, stroboWAITLOOPcontinue;
unsigned long time1WAITLOOP = 0, time2WAITLOOP = 0, powerWait1 = 0, powerWait2 = 0, diffTimeWAITLOOP, shipAnimTime = 0, time,
              stroboWAITLOOPstate = 0, stroboAnimTime1, stroboAnimTime2;
.
.
.
}

Thanks for answers in advance!

Yes, if the total SRAM requirement exceeds 2K the program will fall over.

If you want to reuse some RAM between different functions (because you know they won't be active at the same time), then I'd suggest using the same byte array variable as a "workspace", or use stack-allocated arrays.

Since you haven't posted all the code there's no way of knowing which functions reference the global arrays. If they can be stack allocated (ie local variables), and you assume no persistence of state between calls then the max RAM usage ought to be the maximum of the two functions (rather than the sum).

MarkT: ...or use stack-allocated arrays.

I always thought that arrays within functions are automatically allocated on the stack!?

…except when the “static”-keyword is used!?

Yes, locally-scoped variables are stack-allocated in C. I'm using the phrase to contrast statically allocated or heap-allocated.

...my problem is to understand why the Atmega328 runs out of SRAM although none of the used functions needs more than (together with the global variables) 2k of it ! I would like to post the entire code, but the code has more than the allowed number of characters! If I could post the entire code I also could tell you the line where the CPU crashes/hangs!

you can attach your .ino file, using "additional options" just below the place where you write your post ;)

…here is the entire code!
The program crashes/hangs, when both functions (“attractMode” and “runShip”) are used, at line 148 (“while (!Serial.available());”). An alternative to uncomment a whole of the two functions to make the program work is e.g. to uncomment only the part of code between “//Strobo-----------------------” and “//Schiff-Animationsende---------------------”!

SRAM_problem.ino (16.1 KB)

...seems that the problem has nothing to do with SRAM-problems. I found out that if I add the following lines of code after "//Strobo----------" (line 423)

stroboWAITLOOPcontinue = 12;
stroboAnimCounter = 14;

the program runs (does not hang in line 148) -> That does not make sense! If I add instead of the two lines the following four lines of code (which include the previous two lines) the code does hang in line 148.

if (!time)
{
  stroboWAITLOOPcontinue = 12;
  stroboAnimCounter = 14;
}

That does not make any sense, because when the program reaches line 148 it never reached the code with the added lines! The code changes also do not change anything regarding memory usage (in my opinion)!

...or might it still be a memory problem, because I found that if I reduce the array "shipAnimSeq[] = {..." to only four values, the program runs even without any added code (but also with added code)! The thing is that there should be ebough memory left!?

The thing is that there should be ebough memory left!?

Based on what assumption? You have a lot of function calls going on. Each function call consumes stack space, in SRAM.

Add to the above, you have only shown part of your code. Statements such as

Serial.print(" debug statement");

also consume SRAM.

Mark

holmes4: Add to the above, you have only shown part of your code. Statements such as

Serial.print(" debug statement");

also consume SRAM.

Mark

...no, at "Reply #7" I posted the entire code (.ino-file)!

PaulS: Based on what assumption? You have a lot of function calls going on. Each function call consumes stack space, in SRAM.

...the thing is, that each function separately, with the other one uncommented, works fine, but both together (sequentially called) do not work. When a function is quitting all space used for the local variables should be freed (stackpointer set back) so that if the functions work when used alone I can't see a reason (beside a compilation bug) why they shouldn't work sequentially called!?

Don't forget all the strings consume SRAM even if the function that references them is not currently active, they are effectively statically allocated.

If you can reduce the size of the big arrays and then the thing works, that would be strong evidence of memory running out - there is some code knocking around for measuring free RAM too.

there is some code knocking around for measuring free RAM too.

http://playground.arduino.cc/Code/AvailableMemory

MarkT:
Don’t forget all the strings consume SRAM even if the function that references them is not
currently active, they are effectively statically allocated.

What do you mean with “strings”?

He means "strings" not "Strings" which are on the heap but still use up SRAM.

Mark

PaulS:

there is some code knocking around for measuring free RAM too.

http://playground.arduino.cc/Code/AvailableMemory

..I used this code to determine the amount of free SRAM:

int freeRam()
{
  extern int __heap_start, *__brkval; 
  int v; 
  return (int) &v - (__brkval == 0 ? (int) &__heap_start : (int) __brkval); 
}

If I use that code within the main "loop" it tells me to have about 1.3 kB of free SRAM. If I use that within the "attractMode"-function the program crashes. If I reduce the size of the ledAnimData array from 2 * 512 to 512 (bytes) and then use the "freeRam"-function it tells me to have 554 bytes free, 42 bytes more than needed for the 2 * 512 array. That still should be enough, but is so little that it is an indication that the problems will have something to do with SRAM usage. Seems that the ARDUINO-library functions need more space than I expected, because if I count the space that is needed by the variables which I created (global+local) in the "attractMode" function there should be 487 bytes left (with the 2*512 array), but there are only 42 bytes left, meaning that the library functions take 445 bytes!

Thanks to all of you who tried to help!

meaning that the library functions take 445 bytes!

No. The library functions may need some space. But, so does calling the function. C, and C++, are call-by-value languages. If you have a function that takes 6 integer arguments, and returns an int, the function call takes 14 bytes of stack space, If that function calls another function that takes 4 ints, and returns a float, another 12 bytes of stack space are used, for a total of 26.

You have some pretty deeply nested function calls going on, where you may be 8 or 9 levels deep. The stack space used by the deepest call may be more than you have available.