Static variable doesn't work + Array corrupted

Hi, I’ve a code that communicate with three Maxim 6956 via I2C to drive an 11x11 rgb led matrix. I’ve some problem with a static variable that doesn’t work as C expected.

This is the loop function:

void loop()
{
   byte i, k;
  // clear the matrix 
  for (i=0; i<=maxy; i++) { for (k=0; k<=maxx; k++) { Pone.LedColor(k,i,0,0,0); }  }
  
    //         x y  r  g  b
 // matrix assignment (x,y) and Red Green Blue component
 // 0=off 15=max bright
 Pone.LedColor(0,0,15, 0, 0);
 Pone.LedColor(0,1,15 ,0, 0);
 Pone.LedColor(0,2, 0, 0, 0); 
 Pone.LedColor(0,3, 0 ,0,15);

 Pone.LedColor(1,0, 0, 0,15);
 Pone.LedColor(1,1, 0, 0,15);
 Pone.LedColor(1,2, 0,15, 0); 
 Pone.LedColor(1,3, 0,15, 0);

 AggiornaDisplay();
}

The loop function also sets Pone that is an instance od the class named Display. The class manipulate one bidimensional array:

struct MatriceRGB 
   {
    // index della matrice +1 = nr del led
    byte red;    // valori 0-16 corrispondenti al livello di corrente
    byte green;
    byte blue;
   };

(...)

class Display
{
  public:
    Display();
    void LedColor(byte x, byte y, byte colR, byte colG, byte colB);  // imposta un colore RGB per un singolo led
    byte RColor(byte x, byte y); // restituisce il colore R di un led
    byte GColor(byte x, byte y); // restituisce il colore G di un led
    byte BColor(byte x, byte y); // restituisce il colore B di un led
  protected:
     MatriceRGB Mtx[maxx][maxy];

  };


Display::Display()
{
  byte i; byte k;
  
  for (i=0; i<=maxy; i++) { for (k=0; k<=maxx; k++) { Mtx[k][i].red=0; Mtx[k][i].green=0; Mtx[k][i].blue=0; }  }

}

void Display::LedColor(byte x, byte y, byte colR, byte colG, byte colB)
{ 
  if ((x>=0 && x<=maxx) && (y>=0 && y<=maxy))
    { 
      Mtx[x][y].red=colR;
      Mtx[x][y].green=colG;
      Mtx[x][y].blue=colB;
    }
}

byte Display::RColor(byte x, byte y) // restituisce il colore R di un led
{ 
 if ((x>=0 && x<=maxx) && (y>=0 && y<=maxy)) {  return Mtx[x][y].red; } 
}

byte Display::GColor(byte x, byte y) // restituisce il colore G di un led
{ 
 if ((x>=0 && x<=maxx) && (y>=0 && y<=maxy)) {  return Mtx[x][y].green; } 
}

byte Display::BColor(byte x, byte y) // restituisce il colore B di un led
{ 
 if ((x>=0 && x<=maxx) && (y>=0 && y<=maxy)) {  return Mtx[x][y].blue; } 
}

When the AggiornaDisplay() fuction is called it store the value of SezioneTimer that represents the Row that must be refreshed, but with the serial monitor I seen that the value of this variables is 0 every time, also if it was declared as static.

But, if I declare the variable in the main program the program works correctly (for this aspect):

#include <Wire.h>
#include <LiquidCrystal.h>
#include <avr/interrupt.h>
#include <EventFuse.h>

// variabili e costanti

byte SezioneTimer;  // <<<<<< using this It's all OK!

This is the code of the AggiornaDisplay() function that only check the content of the Pone array and sends some setup byte to the Maxim 6956 chips, and where the static variables SezioneTimer doesn’t work:

void AggiornaDisplay()
{
 
 static byte SezioneTimer; // <<<<<<<<<<<<<<<< doesn't work as static variables why?????!!!!!
 byte i;

 if (SezioneTimer>=0 && SezioneTimer<=10) 
  {

        Tx(Max0, 0x16, Pone.RColor(SezioneTimer,1)*16+Pone.RColor(SezioneTimer,0));
        Tx(Max0, 0x17, Pone.RColor(SezioneTimer,3)*16+Pone.RColor(SezioneTimer,2));
    
       (...)


        // set porte 1 se il segmento è attivo (corrente almeno 1/16), altrimenti 0 se è spento
        Wire.beginTransmission(Max0);
        for (i=0; i<=maxy; i++)
        {  
          if (Pone.RColor(SezioneTimer, i)!=0) {TxN(Max0,   i+0x2C, 1); }   // segmenti red
          if (i<=8) { if (Pone.GColor(SezioneTimer, i)!=0) {TxN(Max0,   i+0x37, 1); } } // segmenti green 0-8
        }
        Wire.endTransmission();



        for (i=0; i<=maxy; i++)
        {
          //if (i>=9) { if (Pone.GColor(SezioneTimer, i)>0) {Tx(Max1, i-9+0x2C, 1); } } // segmenti green 9-10
          
          if (Pone.BColor(SezioneTimer, i)>0) {Tx(Max1,   i+0x2E, 1); }   // segmenti blue

        Serial.print (SezioneTimer,DEC); Serial.print (i,DEC);
        Serial.print (Pone.BColor(SezioneTimer, i),DEC); Serial.println(); 
          
        } 

Serial.println();

        // attiva la colonna dei led corrispondente alla sezione di timer eseguita
        Tx(Max2, SezioneTimer+0x2C, 0);
       

        // la prox volta attiva la sezione successiva

        SezioneTimer++;  // <<<<<<<<<< never increments, no "999" (see after) read by the serial monitor
        if (SezioneTimer==2) {SezioneTimer=0; flash(); Serial.print (999,DEC);}  // ==11
  }   

  else
 
  { SezioneTimer=0; } 

 }

The other strange things is that the array manipulated by the class isn’t equal to the array read by the AggiornaDisplay() function. In fact, using the serial monitor I see that this is the array’s content:

X,Y,value
0,0,0
0,1,0
0,2,0
0,3,15
0,4,0
0,5,0
0,6,0
0,7,0
0,8,0
0,9,0
0,10,15

This doesn’t match with the array assignment, but why? The array was cleared when the class was called, and re-cleared via a double for cycle in the loop function before the Pone(x,y,r,g,b) assignment was done. Some ideas??

Hopefully someone can find the time to go through all that code but if not, perhaps you can create a small sketch that has the minimum lines needed to demonstrate the problem.

OK! :wink: I’m so sorry…

This is a simple sketch, comment or uncomment the “byte SezioneTimer;” and the “static byte SezioneTimer;” declaration (row 7 and 88) to see the problem using the serial monitor.

The problem with the wrong content of the Pone object still persists in all cases:

// P1

// variabili e costanti
#define maxx 10   // 0-10 = 11 righe/colonne
#define maxy 10

// byte SezioneTimer;    // <<<<<<<<<<<<<<<<<< using this the SezioneTimer is correctly managed by the AggiornaDisplay() function (like every public variable)

// struttura dati della matrice rgb
struct MatriceRGB 
   {
    // index della matrice +1 = nr del led
    byte red;    // valori 0-16 corrispondenti al livello di corrente
    byte green;
    byte blue;
   };

// classe principale
class Display
{
  public:
    Display();
    void LedColor(byte x, byte y, byte colR, byte colG, byte colB);  // imposta un colore RGB per un singolo led
    byte RColor(byte x, byte y); // restituisce il colore R di un led
    byte GColor(byte x, byte y); // restituisce il colore G di un led
    byte BColor(byte x, byte y); // restituisce il colore B di un led
  protected:
  MatriceRGB Mtx[maxx][maxy];
};

// init classe = init matrice di definizione della matrice rgb
Display::Display()
{
  byte i; byte k;
  for (i=0; i<=maxy; i++) { for (k=0; k<=maxx; k++) { Mtx[k][i].red=0; Mtx[k][i].green=0; Mtx[k][i].blue=0; }  }
}


////////////////////// setta il colore rgb di un led
void Display::LedColor(byte x, byte y, byte colR, byte colG, byte colB)
{ 
  if ((x>=0 && x<=maxx) && (y>=0 && y<=maxy))
    { 
      Mtx[x][y].red=colR;
      Mtx[x][y].green=colG;
      Mtx[x][y].blue=colB;
    }
}

////////////////////// legge il colore r g b di un led
byte Display::RColor(byte x, byte y) // restituisce il colore R di un led
{  if ((x>=0 && x<=maxx) && (y>=0 && y<=maxy)) {  return Mtx[x][y].red; } }

byte Display::GColor(byte x, byte y) // restituisce il colore G di un led
{  if ((x>=0 && x<=maxx) && (y>=0 && y<=maxy)) {  return Mtx[x][y].green; } }

byte Display::BColor(byte x, byte y) // restituisce il colore B di un led
{  if ((x>=0 && x<=maxx) && (y>=0 && y<=maxy)) {  return Mtx[x][y].blue; } }

// oggetto paletta di tipo display
Display Pone;

// *******************************************************************
void setup()
{  Serial.begin( 9600 ); }

// *****************************************************************
void loop()
{
   byte i, k;
   for (i=0; i<=maxy; i++) { for (k=0; k<=maxx; k++) { Pone.LedColor(k,i,0,0,0); }  }
  
    //         x y  r  g  b
    Pone.LedColor(0,0,15, 0, 0);  // elements that aren't correctly read  
    Pone.LedColor(0,1,15 ,0, 0);
    Pone.LedColor(0,2, 0, 0, 0); 
    Pone.LedColor(0,3, 0 ,0,15);
    Pone.LedColor(1,0, 0, 0,15);
    Pone.LedColor(1,1, 0, 0,15);
    Pone.LedColor(1,2, 0,15, 0); 
    Pone.LedColor(1,3, 0,15, 0);
    AggiornaDisplay();
}


void AggiornaDisplay()
{
 static byte SezioneTimer;   // <<<<<<<<<<<<<<< doesn't work, it seems to be always reset to ZERO like a normal variable
 byte i; 

 if (SezioneTimer>=0 && SezioneTimer<=10) 
  {
        for (i=0; i<=maxy; i++)
        {
        Serial.print ("X= "); Serial.print (SezioneTimer,DEC); Serial.print (" Y="); Serial.print (i,DEC);
        Serial.print (" Pone.BColor(X,Y)="); Serial.print (Pone.BColor(SezioneTimer, i),DEC); Serial.println(); 
        } 

        Serial.println();

        // la prox volta attiva la sezione successiva
        SezioneTimer++;    /// <<<<<<<<<<<<<<<<<<<< 
        // ^^^ the increment is not stored if the variable is declared as static
        if (SezioneTimer==2) {SezioneTimer=0; Serial.print ("999 ok it works!!!"); Serial.println();}
  }   
  else
  { SezioneTimer=0; } 
 }

So, zipping the problem I have a static variable that doesn’t works as expected in a function:

void AggiornaDisplay()
{

 static byte SezioneTimer; // <<<<<<<<<<<<<<<< doesn't work as static variables why?????!!!!! every time the program enter this function the variable is == 0;

 if (SezioneTimer>=0 && SezioneTimer<=10)
  {
        Serial.print (SezioneTimer,DEC); Serial.print (i,DEC);
        Serial.print (Pone.BColor(SezioneTimer, i),DEC); Serial.println();
   }

        SezioneTimer++;  // <<<<<<<<<< no "999" (see after) read by the serial monitor
        if (SezioneTimer==2) {SezioneTimer=0; flash(); Serial.print (999,DEC);}  // ==11
  }  

  else

  { SezioneTimer=0; }

 }

The variables increments only if I declare it in the main program:

// variabili e costanti

byte SezioneTimer;  // <<<<<< using this It's all OK!

void setup() { //setup things }

void loop() { //loop things }

The second big problem was in a small array (11x11 byte elements) that was used by an instance of the Display class (Pone object) to save the RGB components of the rgb leds matrix:

void Display::LedColor(byte x, byte y, byte colR, byte colG, byte colB)
{
  if ((x>=0 && x<=maxx) && (y>=0 && y<=maxy))
    {
      Mtx[x][y].red=colR;
      Mtx[x][y].green=colG;
      Mtx[x][y].blue=colB;
    }
}

The array was defined by this instructions:

void loop()
{
   byte i, k;
  // clear the matrix (even made in class init function)
  for (i=0; i<=maxy; i++) { for (k=0; k<=maxx; k++) { Pone.LedColor(k,i,0,0,0); }  }
  
    //         x y  r  g  b
 // matrix assignment (x,y) and Red Green Blue component
 // 0=off 15=max bright
 Pone.LedColor(0,0,15, 0, 0);
 Pone.LedColor(0,1,15 ,0, 0);
 Pone.LedColor(0,2, 0, 0, 0);
 Pone.LedColor(0,3, 0 ,0,15);

 Pone.LedColor(1,0, 0, 0,15);
 Pone.LedColor(1,1, 0, 0,15);
 Pone.LedColor(1,2, 0,15, 0);
 Pone.LedColor(1,3, 0,15, 0);

 AggiornaDisplay();
}

But the serial monitor say that this is the content of the array:

X,Y,value
0,0,0
0,1,0
0,2,0
0,3,15
0,4,0
0,5,0
0,6,0
0,7,0
0,8,0
0,9,0
0,10,15

Are you running out of RAM? Perhaps try it with smaller values for maxx and maxy

I set maxx= 10 and maxy=10 and the array I used (Mtx[0-maxx][0-maxy]) is so only 11x11 elements (byte type)… that is less than 200 bytes of ram.

edit:
I tried with maxx=maxy=3 and the array seems to be OK. I’m using an Arduino Duemilanove with ATMega168.

Trying with maxx=maxy=20 I have no response by the serial monitor.

With maxx=maxy=15 I still read one wrong data:

X= 0 Y=10 Pone.BColor(X,Y)=0
X= 0 Y=11 Pone.BColor(X,Y)=0
X= 0 Y=12 Pone.BColor(X,Y)=0
X= 0 Y=13 Pone.BColor(X,Y)=0
X= 0 Y=14 Pone.BColor(X,Y)=0
X= 0 Y=15 Pone.BColor(X,Y)=15  <<<<< wrong: it has to be ZERO as set in the loop function

Hi, I think what mem meant by use-case is somthing like this

void setup(){
Serial.begin(57600);
}

void counter() {
  static int counterval=0;
  Serial.println(counterval);
  counterval++;
}

void loop() {
   counter();
}

This code works, it prints incremented values of counterval all the time.

Just a guess for your problem: You did not initialize the static variable. You have to do this for a static one too. (see my code)

Eberhard

I am pretty sure the compiler inits all static variables to zero.

This works also:

void setup(){
Serial.begin(57600);
}

void counter() {
  static int counterval=0;
  static int counter2;
  Serial.print(counterval); Serial.print(","); Serial.println(counter2);
  counterval++;
  counter2++;
}

void loop() {
   counter();
}

tattik, your rgb struct has three bytes, whay do you think that is 200 bytes total

Ops, I was wrong :

11 col x 11 row x 3 colors = 363 bytes

Tattik,, that plus the buffers in the Serial and wire libraries. Plus LiquidCrystal and whatever strings and values you are printing, I would think your problem will go away if you replace the 168 with a 328 .

Just a guess for your problem: You did not initialize the static variable. You have to do this for a static one too. (see my code)

Eberhard

I also tried with a "static byte SezioneTimer=0;" but with no results and your code without the "=0" init also works great.

Tattik,, that plus the buffers in the Serial and wire libraries. Plus LiquidCrystal and whatever strings and values you are printing, I would think your problem will go away if you replace the 168 with a 328 .

This is a bad news ;)

Yes, It's true: I'm using a lot of libraries and It was possible I'm out of ram... but I'm surprised that it could be a ram shortage... It will be useful a some sort of indicator compiling the program to see how many of the 1K ram are used by the program (libraries+user code).

I'll try with a less-than-small sketch to see why the array was corrupted and if it can be due to an overlapping problem over the ram locations.

There are some ways for looking at the memory usage, but until the tools are built into the Arduino IDE this is not easy to do.

This is one of the threads that covers this topic : http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1224729260/all