My draw() function on my LED matrix code stops running

I just built my first 3x3 LED matrix following this tutorial:

I adapted it a little to make for multiple “images” for animation. Everything works great, but my LED’s just turn off after like 20 seconds or so. To debug, I put a println(“TEST”) in my loop(). TEST is printed out every 1.6 seconds as expected, but once my LED’s stop, TEST is printed like crazy. Actually, I counted and TEST is printed slowly 21 times before it goes super fast. This tells me that my draw() calls are either being skipped or something is wrong with them after 21 loops. I can’t figure out what.

EDIT
I changed my start variable (for timing duration) from an int to a long. I think the data type limits is cutting my loop off inside my draw() function. Changing it to a long is making it go for a long time now, but I’m guessing it wont be forever. How can I make it run forever without running out of data type size?

Here’s my code

byte column_pins[3] = {4,3,2};
byte row_pins[3] = {10,9,8};
int delay_time = 100;

byte a[3][3] =       {{0,0,0},
                      {1,0,0},
                      {0,0,0}};
byte b[3][3] =       {{1,0,0},
                      {1,1,0},
                      {1,0,0}};
byte c[3][3] =       {{0,1,0},
                      {1,1,1},
                      {0,1,0}};
byte d[3][3] =       {{0,0,1},
                      {1,1,1},
                      {0,0,1}};
byte e[3][3] =       {{0,0,0},
                      {1,1,1},
                      {0,0,0}};
byte f[3][3] =       {{0,0,0},
                      {0,1,1},
                      {0,0,0}};
byte g[3][3] =       {{0,0,0},
                      {0,0,1},
                      {0,0,0}};
byte h[3][3] =       {{0,0,0},
                      {0,0,0},
                      {0,0,0}};

void setup()
{
  Serial.begin(9600);
  for(int x = 0; x < 3; x++)
  {
    pinMode(column_pins[x],OUTPUT);
    digitalWrite(column_pins[x],LOW);
  }
  for(int y = 0; y < 3; y++)
  {
    pinMode(row_pins[y],OUTPUT);
    digitalWrite(row_pins[y],HIGH);
  }
}

void loop()
{
  draw(a,200);
  draw(b,200);
  draw(c,200);
  draw(d,200);
  draw(e,200);
  draw(f,200);
  draw(g,200);
  draw(h,200);
  Serial.println("TEST");
}

void draw(byte buffer[3][3], int duration)
{
  int start = millis();
  while(millis() - start < duration)
  {
    for(int row=0; row < 3; row++)
    {
      for(int column = 0; column < 3; column++)
      {
        digitalWrite(column_pins[column], buffer[row][column]);
      }
      digitalWrite(row_pins[row],LOW);
      digitalWrite(row_pins[row],HIGH);
    }
  }
}

millis() is how many milliseconds the Arduino has been running since startup. It will increment 1,000 times per second.

In an Arduino an 'int' is a 16 bit signed value, so it store numbers up to roughly 33,000.

So, with your code using 'start' as an int, your function will only work for about the first 33 seconds. Past that, mills() will be larger than start can hold and the value will get chopped down to fit. The upshot of this is "millis() - start" will always be larger than 200, so the while loop will never run, exactly what you're seeing. 21 loops * 1.6 seconds = 33,600 which makes sense; that's the first time millis() will exceed what a 16 bit signed variable can store.

Changing 'start' to a long is (almost) the correct way to go. On an Arduino a 'long' is 32 bits, which means it can hold values up to slightly over two billion. This means your program would work fine for up to just over two million seconds, which is roughly 25 days.

The actual correct method is for start to use the same data type that millis() itself uses: unsigned long. This gets rid of the positive / negative capability of start, but since you're never dealing with negative time, is actually what you want. The upshot will be start can count up to about four billion, or 50 days, but after that millis() will have also looped around because it's using the same data type. So your program will run for infinity.

Or until you remove power. Whichever comes first.

Good luck!

PS Go Cowboys.