SRAM overflow

Hi all!

my name is Toni. Long time reading here but this is my first post, so hello to all.

I’m working on a pressure sensor matrix based on Hannah’s work:

http://www.plusea.at/?p=2255

and since few months I’m playing with my first arduino project, a 16x16 sensor pressure matrix. To simplificate, please consider int SIG_pin as a variable potientiometer, it is velostat.

The code I’m working:

//Mux reader signal
int s0 = 8;
int s1 = 9;
int s2 = 10;
int s3 = 11;
int SIG_pin = A0;

//Mux apply voltage
int v1 = 4;
int v2 = 5;
int v3 = 6;
int v4 = 7;
int VOL_pin = 3;

int r0 = 0;
int r1 = 0;
int r2 = 0;
int r3 = 0;

int rowCount = 0;
int colCount = 0;

int matrixValues[16];
int matrixSize = 1*16;

int val [16][16]; //declare array for a 16x16 analog matrix sensor

int ledPin = 13; //to check that all runs

int maxVal [16][16]; // needs to declare = 0, but done by default
int minVal [16][16]; // needs to be declared as 1023, still don’t know how
// so ensure good pressure when calibrating !!!

void setup(){

pinMode(s0, OUTPUT);
pinMode(s1, OUTPUT);
pinMode(s2, OUTPUT);
pinMode(s3, OUTPUT);
pinMode (SIG_pin, INPUT);

digitalWrite(s0, LOW);
digitalWrite(s1, LOW);
digitalWrite(s2, LOW);
digitalWrite(s3, LOW);

pinMode(v1, OUTPUT);
pinMode(v2, OUTPUT);
pinMode(v3, OUTPUT);
pinMode(v4, OUTPUT);
pinMode (VOL_pin, OUTPUT);

digitalWrite(v1, LOW);
digitalWrite(v2, LOW);
digitalWrite(v3, LOW);
digitalWrite(v4, LOW);
analogWrite (VOL_pin, LOW);

pinMode (ledPin, OUTPUT);

Serial.begin(57600);

for (rowCount=0; rowCount<16; rowCount++) {

r0 = bitRead(rowCount,0);
r1 = bitRead(rowCount,1);
r2 = bitRead(rowCount,2);
r3 = bitRead(rowCount,3);

digitalWrite(v1, r0);
digitalWrite(v2, r1);
digitalWrite(v3, r2);
digitalWrite(v4, r3);

analogWrite (VOL_pin, HIGH);

for (colCount=0; colCount<16; colCount++) {
// select the bit
r0 = bitRead(colCount,0);
r1 = bitRead(colCount,1);
r2 = bitRead(colCount,2);
r3 = bitRead(colCount,3);

digitalWrite(s0, r0);
digitalWrite(s1, r1);
digitalWrite(s2, r2);
digitalWrite(s3, r3);
digitalWrite(ledPin, HIGH);

Serial.print (“Calibrating sensor “);
Serial.print (colCount);
Serial.print(”,”);
Serial.print (rowCount);
Serial.println("");

int time = millis ();

while (millis () < time + 50) {
val [colCount][rowCount]= analogRead (SIG_pin);
if (val [colCount][rowCount] > maxVal [colCount][rowCount]) {
maxVal [colCount][rowCount] = val [colCount][rowCount];
}
if (val [colCount][rowCount] < minVal [colCount][rowCount]){
minVal [colCount][rowCount] = val [colCount][rowCount];
}
}

digitalWrite (ledPin, LOW);
delay (10);

}
}
}

void loop () {

for (rowCount=0; rowCount<16; rowCount++) {

// select the bit

r0 = bitRead(rowCount,0);
r1 = bitRead(rowCount,1);
r2 = bitRead(rowCount,2);
r3 = bitRead(rowCount,3);

digitalWrite(v1, r0);
digitalWrite(v2, r1);
digitalWrite(v3, r2);
digitalWrite(v4, r3);
digitalWrite (ledPin, LOW);
analogWrite (VOL_pin, HIGH);

Serial.print(rowCount);
Serial.print(",");

for (colCount=0; colCount<16; colCount++) {

r0 = bitRead(colCount,0);
r1 = bitRead(colCount,1);
r2 = bitRead(colCount,2);
r3 = bitRead(colCount,3);

digitalWrite(s0, r0);
digitalWrite(s1, r1);
digitalWrite(s2, r2);
digitalWrite(s3, r3);

val [colCount][rowCount]= analogRead (SIG_pin);
matrixValues [colCount]= map(val [colCount][rowCount], minVal [colCount][rowCount], maxVal [colCount][rowCount], 0, 255);
}
for (int i=0; i<16; i++){

Serial.print(matrixValues*);*

  • if (i < matrixSize - 1) Serial.print(",");*

  • } *

  • Serial.println();*

  • delay(20);*

  • }*
    }
    /#
    (hope to posted it correct!)
    BTW, million of thanks to Hannah Parker, Tom Igoe, and all open community.
    As is, the code runs smoothly.
    The problem: when you rise time during calibrating (ie. <time + 5000), seems to overflow SRAM. This should be need when real calibration process.
    The solution: do calibration with a for function. Also for other reasons, the way I’m looking on now.
    but also I’m reading this:
    http://arduino.cc/forum/index.php/topic,95914
    because I’m asking for a solution to work with the first calibration approach.
    Also I’m asking how many times a sensor is calibrated during while function.
    Any idea or direction is welcome.
    Thanks a lot.
    Toni Ventura

Please read the sticky thread at the top of this section.

int val [16][16]; //declare array for a 16x16 analog matrix sensor
int maxVal [16][16]; // needs to declare = 0, but done by default
int minVal [16][16]; // needs to be declared as 1023, still don't know how

those 3 arrays take up 1.5kB from the 2kB on the chip - if you can make them smaller (byte rather than int?) you'll save a lot of RAM space... Do you really need all 3 arrays?

And do use the code tags as above please.

uops! sorry, I have to check it with "preview"...

thanks for the reply, but yes, I need these matrices. It's based on calibration tutorial. I can imagine another ways to obtain them, but I need it!

I'm trying now the memalloc() function that is proposed in the forum.

thanks again.

toni

Here are some ways to save RAM space in your sketch, apart from making the arrays smaller:

  1. Define your pin numbers and other unchanging values as "const int" instead of plain "int".

  2. When you want to print a string literal, use Serial.print(F("a string")) instead of Serial.print("a string"). To write a single character, use e.g. Serial.write(',') instead of Serial.print(",").

  3. Where you use variables only locally, declare them locally, not at the global level. For example, you should declare rowCount and colCount in the for-loops that use them, not as global variables. Similarly for r0, r1, r2 and r3.

Using malloc() in your code will not help, it is more likely to make the problem worse.

Seems to me the maxval and minval are filled in setup and their values don't change for the duration of the program. If this is the case, then store them in EEPROM. There is 1KB of EEPROM on arduino, which is exactly how much you need to store maxval and minval both.

Since the data you are storing in the arrays comprises 10-bit values from analogRead, you could pack 2 readings into 3 bytes (instead of 4 bytes), reducing the memory requirement by 25%. Or you could pack 3 readings into 4 bytes (instead of 6 bytes), reducing the memory requirement by 33%.

dc42: Since the data you are storing in the arrays comprises 10-bit values from analogRead, you could pack 2 readings into 3 bytes (instead of 4 bytes), reducing the memory requirement by 25%. Or you could pack 3 readings into 4 bytes (instead of 6 bytes), reducing the memory requirement by 33%.

Depending on the largest variation of minval, if it is less than +-128, you can just store the averago of minval and have a matrix of just variations. You reduce 50% memory cost. Same goes with maxval.

Perhaps 8 bit resolution is OK - use byte val = (byte) (analogRead() >> 2) and all arrays can then be byte arrays?

uau! thanks a lot for the replies!

MarkT: Perhaps 8 bit resolution is OK - use byte val = (byte) (analogRead() >> 2) and all arrays can then be byte arrays?

yes, this is the way. And have to store them (at eeprom or flash?) in order to load calibration pattern when restarting.

liudr: Seems to me the maxval and minval are filled in setup and their values don't change for the duration of the program. If this is the case, then store them in EEPROM. There is 1KB of EEPROM on arduino, which is exactly how much you need to store maxval and minval both.

yes, I agree. In fact, due practical uses, I'm changing the code to calibrate in another way (with known times that every sensor will be tested). But I still want to solve this.

And the solution seems to come again with malloc().

At this moment I followed instructions from:

http://arduino.cc/forum/index.php/topic,95914.msg722142.html#msg722142

but I'm still trying to make the correct modifications (I'm a newbie ;)

Thank you a lot guys, I'm learning a lot these weeks!

best regards,

toni

And the solution seems to come again with malloc().

Not possible. If you can't fit a statically sized array in SRAM, there is no way to fit an identically sized, dynamically allocated on in SRAM.

PaulS:

And the solution seems to come again with malloc().

Not possible. If you can't fit a statically sized array in SRAM, there is no way to fit an identically sized, dynamically allocated on in SRAM.

well, in fact, with the duration times in the original code, the program runs smooth, so it can.

The problem comes when I rise the duration of calibration because I fill the memory with more "tests" as ardu is reading the sensor in its full frequency (the while () loop) ...still don't know how many times is. I use a CD4067, must read again the spreadsheet...

thanks anyway!

well, in fact, with the duration times in the original code, the program runs smooth, so it can.

Well, in fact it can't. If your program is running fine, that is either because you are not dynamically allocating as much memory as you were statically allocating, or because you haven't found where the data is being trashed yet.

It is not because malloc() is somehow able to manufacture memory for you.

vinot:

PaulS:
If you can’t fit a statically sized array in SRAM, there is no way to fit an identically sized, dynamically allocated on in SRAM.

well, in fact, with the duration times in the original code, the program runs smooth, so it can.

If you have evidence that you think disproves what PaulS wrote, then either the evidence is wrong, or you are misinterpreting it. What PaulS wrote is absolutely and fundamentally correct.

Listen to Paul. malloc is allocating the same SRAM that you are running out of so running malloc is not helping.

maybe I said it wrong... I agree what PaulS says.

What I mean is that with a short time calibration there is not enough time to fullfill the memory while reading for calibration. That's why the program then runs as a sensor reading (256 analog sensors) with no problem. In this way two matrices have been calculated, so I guess I will be able to save them. Still to do...

anyway, there's something I still don't understand... seems that while() stores not one minVal array, but lot of them (the same with maxVal), as if I rise up to 50000 milliseconds the system crashes. And here is where I suposed alloc() could help. At this point must say that minVal (the minimal value from pressure) is a changing value ranged from 50 to 53 (depending on resistors and op-amp), so there is a practical infinite diferent matrices that can be calculated and stored.

thanks

toni

If it's sensitive to the length of time spent doing the calibration then I think you are only just running out of memory. Did you try the suggestions I made in reply #4 ? They are all very easy to implement.

Hi,

dc42:
If it’s sensitive to the length of time spent doing the calibration then I think you are only just running out of memory. Did you try the suggestions I made in reply #4 ? They are all very easy to implement.

thanks. Yes, it seems it’s time sensitive. Regarding “good practices” about programming, I’m a totally newbie… But trying it. There’s lot of errors, but now the code works:

// First multiplexer CD4067 for rows
// where analogRead (3) collects signals
// Mux reader signal
int s0 = 8;
int s1 = 9;
int s2 = 10;
int s3 = 11;
int SIG_pin = A0;

// Second mux CD4067 for columns
// where voltage is applied
// Mux apply voltage
int v1 = 4;
int v2 = 5;
int v3 = 6;
int v4 = 7;
int VOL_pin = 3;

//Counting for digital select pins of mux
int r0 = 0;      
int r1 = 0;      
int r2 = 0;    
int r3 = 0;

int rowCount = 0;
int colCount = 0;

//there are 16x16 intersections, so 256 sensors
int matrixValues[16];
int matrixSize = 1*16;

int val [16][16]; //declare array for a 16x16 analog matrix calibration sensor

int ledPin = 13; //to check that all runs

int maxVal [16][16]; // needs to declare = 0, but done by default
int minVal [16][16]; // needs to be declared as 1023, still don't know how
                     // so ensure good pressure when calibrating !!!
                     
void setup(){


  
  pinMode(s0, OUTPUT);
  pinMode(s1, OUTPUT);
  pinMode(s2, OUTPUT);
  pinMode(s3, OUTPUT); 
  pinMode (SIG_pin, INPUT);
  
  digitalWrite(s0, LOW);
  digitalWrite(s1, LOW);
  digitalWrite(s2, LOW);
  digitalWrite(s3, LOW);

  pinMode(v1, OUTPUT);
  pinMode(v2, OUTPUT);
  pinMode(v3, OUTPUT);
  pinMode(v4, OUTPUT);
  pinMode (VOL_pin, OUTPUT);
  
  digitalWrite(v1, LOW);
  digitalWrite(v2, LOW);
  digitalWrite(v3, LOW);
  digitalWrite(v4, LOW);
  analogWrite (VOL_pin, LOW);
  
  pinMode (ledPin, OUTPUT);
    
  
  Serial.begin(57600);
 
    
// Starts minim calibration

      for (rowCount=0; rowCount<16; rowCount++) {

      r0 = bitRead(rowCount,0);  
      r1 = bitRead(rowCount,1);    
      r2 = bitRead(rowCount,2);    
      r3 = bitRead(rowCount,3);

       digitalWrite(v1, r0);
       digitalWrite(v2, r1);
       digitalWrite(v3, r2);
       digitalWrite(v4, r3);
    
       analogWrite (VOL_pin, HIGH);
  
        for (colCount=0; colCount<16; colCount++) {
            // select the bit  
            r0 = bitRead(colCount,0);   
            r1 = bitRead(colCount,1);   
            r2 = bitRead(colCount,2); 
            r3 = bitRead(colCount,3);

            digitalWrite(s0, r0);
            digitalWrite(s1, r1);
            digitalWrite(s2, r2);
            digitalWrite(s3, r3);
                        
         Serial.print ("Calibrating min sensor ");
         Serial.print (colCount);
         Serial.print(",");
         Serial.print (rowCount);  
         Serial.println("");
         
           for (int i=0; i< 5; i++) {
             digitalWrite(ledPin, HIGH); //to ensure that every cycle runs
             delay (1);
             digitalWrite(ledPin, LOW);
             val [colCount][rowCount]= analogRead (SIG_pin);
             if (val [colCount][rowCount] < minVal [colCount][rowCount]){
            minVal [colCount][rowCount] = val [colCount][rowCount];}
           }     
        }
      }
 while(Serial.available() == 0); {
    if (Serial.available()) {
    
    int ser = Serial.read();
    
    if(ser == 'c') {
    int rowCount = 0;
    int colCount = 0;
      
      for (rowCount=0; rowCount<16; rowCount++) {

      r0 = bitRead(rowCount,0);  
      r1 = bitRead(rowCount,1);    
      r2 = bitRead(rowCount,2);    
      r3 = bitRead(rowCount,3);

       digitalWrite(v1, r0);
       digitalWrite(v2, r1);
       digitalWrite(v3, r2);
       digitalWrite(v4, r3);
    
       analogWrite (VOL_pin, HIGH);
      
      for (colCount=0; colCount<16; colCount++) {
            // select the bit  
            r0 = bitRead(colCount,0);   
            r1 = bitRead(colCount,1);   
            r2 = bitRead(colCount,2); 
            r3 = bitRead(colCount,3);

            digitalWrite(s0, r0);
            digitalWrite(s1, r1);
            digitalWrite(s2, r2);
            digitalWrite(s3, r3);
                        
         Serial.print ("Calibrating max sensor ");
         Serial.print (colCount);
         Serial.print(",");
         Serial.print (rowCount);  
         Serial.println("");
         
         while(Serial.available() == 0); {
    if (Serial.available()) {
             int ser2 = Serial.read();   
            if(ser2 == 'n') {
              
             for (int i=0; i< 5; i++) {
             digitalWrite(ledPin, HIGH); //to ensure that every cycle runs
             delay (1);
             digitalWrite(ledPin, LOW);
             val [colCount][rowCount]= analogRead (SIG_pin);
             if (val [colCount][rowCount] < maxVal [colCount][rowCount]){
            maxVal [colCount][rowCount] = val [colCount][rowCount];}
           }     
        }
       }
      }
    }
    }
}
 }
}
}


void loop () {
  
   for (rowCount=0; rowCount<16; rowCount++) {

     // select the bit   

    r0 = bitRead(rowCount,0);  
    r1 = bitRead(rowCount,1);    
    r2 = bitRead(rowCount,2);    
    r3 = bitRead(rowCount,3);

     digitalWrite(v1, r0);
     digitalWrite(v2, r1);
     digitalWrite(v3, r2);
     digitalWrite(v4, r3);
     digitalWrite (ledPin, LOW);
       analogWrite (VOL_pin, HIGH);
  
         Serial.print(rowCount);
         Serial.print(",");
       
         for (colCount=0; colCount<16; colCount++) {
            
            r0 = bitRead(colCount,0);   
            r1 = bitRead(colCount,1);   
            r2 = bitRead(colCount,2); 
            r3 = bitRead(colCount,3);

        digitalWrite(s0, r0);
        digitalWrite(s1, r1);
        digitalWrite(s2, r2);
        digitalWrite(s3, r3);
    
          val [colCount][rowCount]= analogRead (SIG_pin);
          matrixValues [colCount]= map(val [colCount][rowCount], minVal [colCount][rowCount], maxVal [colCount][rowCount], 0, 255);        
         }         
          for (int i=0; i<16; i++){
            
            Serial.print(matrixValues[i]);
            if (i < matrixSize - 1) Serial.print(",");
        }  
    
      Serial.println();
    delay(20);
  }
}

In this way I solve the overflow. Anyway, there’s a lot of things I’m learning now that will require different code, so I hope to make some progress while trying it. And at least this code is just one concept. Now I’m working with another code with some different aproach.

Thanks a lot,

toni