atmega 328 and SRAM usage

Hello, I am currently working on a project that utilizes a couple bigger sized arrays, so it is necessary to keep track of sram usage.

I'm using windows and been checking sram with:
C:\Program Files (x86)\Arduino\hardware\tools\avr\bin>avr-size.exe C:\Users*\AppData\Local\Temp\build*********************.tmp\Matrix_Dis
play_3_0_Arduino.cpp.elf

The result is:
text data bss dec hex
3626 26 994 4646 1226

Note: some of the path is replaced with * for privacy.

It appears as if I have little less than 1kb left, but if I increase my two arrays by just 50 bytes each (100 bytes total), the code doesn't work at all.
So here are my Questions:

  1. Is there a difference between sram at compile and run time?

  2. Are classes that are in separate files from the arduino sketch, but still included in the arduino sketch (#include...) , calculated in the avr-size sram count?

  3. Is there a SIMPLE better way to keep track of sram besides avr-size?

Thanks in advance. XD

  1. Yes, since the runtime will include the stack with any automatic variables.

Ok, thanks.

As for question 2. I tested it and it does include included classes.

What would be a good way to measure sram during runtime? Is this possible via a simulator?

My atmega chip is pretty old, could this affect the amount of sram? I have almost fried it on numerous occasions.

Look here for runtime memory usage (will need Serial monitor though).

Thanks, will definitely try using that.

I have used freeRam and it says that I have 952 bytes left, but when I increase my two byte arrays, the program will not run. I put a Serial.println(freeMemory()); at the beginning of setup and I am getting a repeating 6 in the serial monitor.

Note: Usually my program communicates to the computer via a C++ application, however for debugging I use the Serial monitor.

Here's the code:

#include <MemoryFree.h>

/*50 X 8 Scrolling Matrix
 Author: Kurt
 Date 2/27/14
 Version 3.0 */

#include "DisplayArduinoClass.h"
DisplayArduinoClass obj;
bool first;
  
void setup(){
  Serial.print(freeMemory());
  DisplayArduinoClass obj;
  Serial.begin(115200, SERIAL_8N2);      // Begin serial at 256000 baud and two stop bits
  obj.Setup();                           // Setup pins and set as outputs
  obj.clearByteMaps();                   // Clear message byte maps
  obj.Shift = 0;                         // Set Shift Index to zero
  obj.refresh();                         // Display message byte maps, which is nothing
  obj.confirmSerialConnection();         // Confirm the serial connection
  first = 1;
}

void loop(){
  if(first==1){               // Code to run only once in loop (Can't be in setup)
    obj.Setup();              // Setup pins and set as outputs
    first=0;                  // Make code not run again till micro-controller is reset
    obj.recieveSpeed();       // Recieve the scrolling speed
    obj.numberOfCols = 0;     // Set number of columns to five
    Serial.write(114);        // Send Ready Status
  }
  
  obj.numberOfCols = 0;       // Set number of columns to zero
  obj.recieveNumberOfCols();  // Recieve number of columns
  obj.clearByteMaps();        // Clear message byte maps
  Serial.write(114);          // Send Ready Status
  obj.recieveRmsgByteMap();   // Recieve red message byte map
  Serial.write(114);          // Send Ready Status
  obj.recieveGmsgByteMap();   // Recieve green message byte map
  Serial.print(freeMemory());
 
  obj.scrollByteMaps();       // Scroll message byte maps
  
  
}
#include "DisplayArduinoClass.h"
#include "Arduino.h"
#include <stdlib.h>


void DisplayArduinoClass::refresh(){
  byte rows;                                     
  for(byte row=0; row<8; row++){            // Switch rows so that it isn't upside down
    switch (row){
      case 0: rows = 7; break;
      case 1: rows = 6; break;
      case 2: rows = 5; break;
      case 3: rows = 4; break;
      case 4: rows = 3; break;
      case 5: rows = 2; break;
      case 6: rows = 1; break;
      case 7: rows = 0; break;
    }

    digitalWrite (rowE, HIGH);   //Turn OFF display
    digitalWrite (rclk, LOW);    //Turn OFF display

    for(byte col=0;col < 50; col++){   // For each column
      digitalWrite(gdat, LOW);         // Make sure dataPins are LOW
      digitalWrite(rdat, LOW);         // Make sure dataPins are LOW

        if (bitRead (rmsgByteMap[col+Shift], rows)){  // If bit is present in red message byte map
          digitalWrite(rdat, HIGH);                   // Then write red serial data high
        }
        else digitalWrite (rdat, LOW);                // If not, Then write red serial data low

      if (bitRead (gmsgByteMap[col+Shift], rows)){    // If bit is present in green message byte map
        digitalWrite(gdat, HIGH);                     // Then write green serial data high
      }
      else digitalWrite (gdat, LOW);                  // If not, Then write green serial data low

      digitalWrite(clk, HIGH);                        // Increment clock
      digitalWrite(clk, LOW);                         // Increment clock
    }
    digitalWrite(rclk, HIGH);                         // Increment row clock

    if bitRead(row,0) digitalWrite (row1, HIGH); else digitalWrite(row1, LOW); // Select row to turn on for multiplexing
    if bitRead(row,1) digitalWrite (row2, HIGH); else digitalWrite(row2, LOW); // Select row to turn on for multiplexing
    if bitRead(row,2) digitalWrite (row3, HIGH); else digitalWrite(row3, LOW); // Select row to turn on for multiplexing
    digitalWrite(rowE, LOW);                                                   // Turn display on
    delayMicroseconds(500);                                                    // Pause for Multiplexing
  }
}



void DisplayArduinoClass::Setup(){
  row1 = 5;     // Set micro-controller pins
  row2 = 10;    // Set micro-controller pins
  row3 = 6;     // Set micro-controller pins
  rowE = 11;    // Set micro-controller pins
  rclk = 9;     // Set micro-controller pins
  clk  = 4;     // Set micro-controller pins
  rdat = 2;     // Set micro-controller pins
  gdat = 3;     // Set micro-controller pins

  pinMode (row1, OUTPUT);   // Set pins as OUTPUTS
  pinMode (row2, OUTPUT);   // Set pins as OUTPUTS
  pinMode (row3, OUTPUT);   // Set pins as OUTPUTS
  pinMode (rowE, OUTPUT);   // Set pins as OUTPUTS
  pinMode (rclk, OUTPUT);   // Set pins as OUTPUTS
  pinMode (clk , OUTPUT);   // Set pins as OUTPUTS
  pinMode (rdat, OUTPUT);   // Set pins as OUTPUTS
  pinMode (gdat, OUTPUT);   // Set pins as OUTPUTS
  Shift = 0;
}



void DisplayArduinoClass::clearByteMaps(){
  for(int i=0;i<429;i++){rmsgByteMap[i] = 0;} // Clear rmsgByteMap   
  for(int i=0;i<429;i++){gmsgByteMap[i] = 0;} // Clear gmsgByteMap   
}



void DisplayArduinoClass::confirmSerialConnection(){
  char incomingString[6] = {0,0,0,0,0,0};               // Declare array for incoming string  
  while(!Serial.available());                           // Wait for input
  Serial.readBytesUntil(101,incomingString, 6);         // Read until termination character, read into..., read maximum of 5 bytes
  
  if (incomingString [0] == 'H' && incomingString [1] == 'o' && incomingString [2] == 'l' && incomingString [3] == 'a' && incomingString [4] == '?'){   //If recieved "Hola?"
    Serial.write("Hola!");                           // Then send back "Hola!"
  }
}



void DisplayArduinoClass::recieveSpeed(){
  while(!Serial.available());                         // Wait for input  
  Serial.readBytesUntil(101,(char*)Speed, 2);         // Read until termination character, read into..., read maximum of 2 bytes
}



void DisplayArduinoClass::recieveNumberOfCols(){
  byte val [3] ={0,0,0};          // Stores two incoming bytes
  while(!Serial.available());   // Wait for input  
  Serial.readBytesUntil(101,(char*)val, 3);         // Read until termination character, read into..., read maximum of 3 bytes
  numberOfCols = val[0] * 256 + val[1];  // Put together two bytes to form int and numberOfCols in the message
}



void DisplayArduinoClass::recieveRmsgByteMap(){
  while(!Serial.available());                                                 // Wait for input
  Serial.readBytesUntil(101,(char*)&rmsgByteMap[50], numberOfCols+1);         // Read until termination character, read into..., read maximum of numberOfCols bytes
}



void DisplayArduinoClass::recieveGmsgByteMap(){
  while(!Serial.available());                                                 // Wait for input
  Serial.readBytesUntil(101,(char*)&gmsgByteMap[50], numberOfCols+1);         // Read until termination character, read into..., read maximum of numberOfCols bytes
}



void DisplayArduinoClass::scrollByteMaps(){
  bool First = 1;
  do{
    Shift = 0;                               // Set shift index to zero
    for(int j=0;j<numberOfCols+51;j++){      // For length of message
      for(byte i=0;i<Speed[0];i++){          // For speed
      refresh();                             // display message byte maps
      }  
      Shift++;                               // Increment shift
      if (First==1){
        Serial.write(114);      // Send Ready Status 
        First=0;  
      }  
    }
  } while(!Serial.available());             // Do until user enters a new message
}
#ifndef DISPLAYARDUINOCLASS_H
#define DISPLAYARDUINOCLASS_H
#include "Arduino.h"
#include <stdlib.h>

class DisplayArduinoClass
{
public:
  byte row1; // Binary value for row select
  byte row2; // Binary value for row select
  byte row3; // Binary value for row select
  byte rowE; // Row enable; LOW ON
  byte rclk; // Register clk latch
  byte clk;  // Serial clock input
  byte rdat; // Red serial data
  byte gdat; // Green serial date

  int numberOfCols;   // Number of columns in the message 
  byte Speed [2];         // Speed that the message is dsiplayed
  int Shift;          // Shift index to scroll the message
 byte rmsgByteMap [430];    // Red message byte map
  byte gmsgByteMap [430];    // Green message byte map 

  void refresh();                  // Display bitmaps
  void Setup();                    // Set up micro-controller
  void clearByteMaps();            // Cear the ByteMaps
  void confirmSerialConnection();  // Confirm the Serial Connection
  void recieveSpeed();             // Recieve scrolling speed
  void recieveNumberOfCols();      // Recieve number of columns in message  
  void recieveRmsgByteMap();       // Receive red message byte map
  void recieveGmsgByteMap();       // Receive green message byte map
  void scrollByteMaps();           // Scroll the message byte maps
};

#endif // DISPLAYARDUINOCLASS_H

When I increase the RmsgByteMap and the GmsgByteMap my proram doesn't function, and I get a constant 6 from the serial monitor. I can't seem to figure out why. Any Ideas?

 byte rmsgByteMap [430];    // Red message byte map
  byte gmsgByteMap [430];    // Green message byte map

On an UNO, the array allocations represent 42% of SRAM... A big chunk. Are you really using ASCII values above 127, that is the upper 128 character codes? If not, you can reduce the array size by half by using 1 byte to hold both RED and GREEN.

Ray

Yes I realize that they are big. They are not ascii values they are bit maps condensed to a byte array.

Yes they need to be that big.

I need all 8 bit of data so there is no way to store red and green in one byte.

My question is if freeMemory function says I have 952 bytes left, and I increase those arrays by 50 bytes, then I should have 852 bytes left, which is plenty. But my program doesn't run and freeMemory gives me "6" over serial over and over again.

My question is if freeMemory function says I have 952 bytes left, and I increase those arrays by 50 bytes, then I should have 852 bytes left, which is plenty. But my program doesn't run and freeMemory gives me "6" over serial over and over again.

Tools gauging memory are just for estimates and may not provide accurate results always..

Build a char array and a simply for loop to reference it. Stuff some bytes into it, compile and note what your men tool says then.

Ray

I've created a super simple program like this:

#include <MemoryFree.h>

void setup(){
  Serial.begin(115200);
}
byte xByteMap [850];
byte yByteMap [850];
//int x;
void loop(){
  for(int i=0;i<850; i++){
    xByteMap[i] = 92;
    yByteMap[i] = 76;
  }
  Serial.println(freeMemory());
  delay(1000);
}

With two byte maps of 850, if I check sram pre run time I get 1899 bytes. If I check it during runtime I get 137 free bytes (2048-137 = 1911); I've changed the data type from byte to char and got the same results.

I wouldn't be surprised if somehow my problem wasn't because of sram.

UPDATE*******************

I put Serial.println(freeMemory()); in a bunch of different places. I noticed one thing: the freeMemory function gives 192 bytes of free ram anywhere in the setup. When it gets to the loop freeMemory gives 1012 bytes of free ram.

.

I noticed one thing: the freeMemory function gives 192 bytes of free ram anywhere in the setup. When it gets to the loop freeMemory gives 1012 bytes of free ram.

Well, there's a big clue that you have something "wrong" in setup()

And here it is:

#include "DisplayArduinoClass.h"
DisplayArduinoClass obj;         //   *******   11111 *******
bool first;
  
void setup(){
  Serial.print(freeMemory());
  DisplayArduinoClass obj       //  *******   22222 ******;
  obj.Setup();                  // Setup pins and set as outputs

The line I marked "1" allocates your display object. Then in setup(), you allocate ANOTHER display object with the same name, that takes precedence within setup(). setup then proceedes to initialize the extra "obj", and then it is destroyed when setup exits (giving back memory!) The rest of your program fails to work as you expect because the global "obj" was never initialized! You should do a lot better simply removing line "222"...

Thanks!!!!!!!!! 8)

I got rid of the second DisplayArduinoclass obj; and it works as expected.

Once again Thanks.