At a loss debugging...

Hi,

So I've been working on a project to force myself to learn to code better. I built a multiplexed 8x8 LED matrix and have been trying to program an extremely primitive Tetris game on it. My last completely successful upload was a small-scale simulation wherein rows of LEDs fall and stack until they reach the top, and "GAME OVER" scrolls across.

Because I have no idea where/how to debug an Arduino program line-by-line (will accept advice here as well), so I transcribed my code into java and used Netbeans to debug it. Once I fixed everything I needed to get it to a checkpoint (just enough to stack random pieces down the middle until game over), I tried to upload it. Unfortunately, the matrix remains blank. I didn't change anything in the shift register or digital write functions, so I've pretty much hit a wall. Any suggestions?

int Latch = 11; 
int Data = 12;  
int Clock = 10; 

int OE = 13;
int C1 = 8;
int C2 = 9;
int C3 = 2;
int C4 = 3;
int C5 = 4;
int C6 = 5;
int C7 = 6;
int C8 = 7;
int CPins[] = {
  C1, C2, C3, C4, C5, C6, C7, C8};
int shiftCount = 0;
int letter = 0;
int newRow = 1;
int contGame = 1;
int pointer[2] = {
  4,0};
int maxPiece = 0;
int posInd = 0;
int id = 0;
int count = 0;


//Set clear board starting point and letter templates
int allRows[11][11]={ ... };

int tempRows[11][11]={ ... };

int letterG[8][8] = {
  {0,0,1,1,0,0,0,0  }
 ,{0,1,0,0,1,0,0,0  }
 ,{1,0,0,0,0,0,0,0  }
 ,{1,0,0,0,0,0,0,0  }
 ,{1,0,0,1,1,0,0,0  }
 ,{1,0,0,0,1,0,0,0  }
 ,{0,1,0,0,1,0,0,0  }
 ,{0,0,1,1,1,0,0,0  }
};

*Instantiate the rest of the letters*

//Create pieces in all positions
int pieceT[4][4][4] = {{
    {1,1,1,0}
   ,{0,1,0,0}
   ,{0,0,0,0}
   ,{0,0,0,0}}
 ,{
    {0,1,0,0}
   ,{1,1,0,0}
   ,{0,1,0,0}
   ,{0,0,0,0}}
 ,{
    {0,1,0,0}
   ,{1,1,1,0}
   ,{0,0,0,0}
   ,{0,0,0,0}}
 ,{
    {1,0,0,0}
   ,{1,1,0,0}
   ,{1,0,0,0}
   ,{0,0,0,0}
  }
};

*Instantiate the other 6 Tetris pieces*

//How many shift register?
#define number_of_74hc595s 1

//Pins on this shift register
#define numOfRegisterPins number_of_74hc595s * 8

int val = 0;     //val will be used to store the row
int row = 0;            //of the input pin
int oldVal = 0;  

boolean registers[numOfRegisterPins];

void setup() {
  pinMode(Data, OUTPUT);    //tell Arduino LED is an output
  pinMode(Latch, OUTPUT);
  pinMode(Clock, OUTPUT);
  pinMode(OE, OUTPUT);
  pinMode(C1, OUTPUT);
  pinMode(C2, OUTPUT);
  pinMode(C3, OUTPUT);
  pinMode(C4, OUTPUT);
  pinMode(C5, OUTPUT);
  pinMode(C6, OUTPUT);
  pinMode(C7, OUTPUT);
  pinMode(C8, OUTPUT);
  pinMode(14, INPUT);
  pinMode(15, INPUT);
  pinMode(16, INPUT);

  //reset all register pins
  clearRegisters();
  writeRegisters();
  Serial.begin(9600);
}

//Sets a proxy 
void setTemp(){
  for(int i = 0; i<=10; i++){
    for(int j = 0; j<=10; j++){
      tempRows[i][j]=allRows[i][j];
    }
  }
}

//Set all register pins to LOW
void clearRegisters(){
  for(int i = numOfRegisterPins - 1; i>= 0; i--){
    registers[i] = LOW;
  }
}

boolean collisionDetection(){
  for(int i = 0; i<=10; i++){
    for(int j = 0; j<=10; j++){
      if(tempRows[i][j]>maxPiece){
        maxPiece = tempRows[i][j];
      }
    }
  }
  if(maxPiece>=2){
    return true;
  }else{
    return false;
  }
}

//Checks to see if piece has finished falling
/*void endCheck(){
  for(int i = 3; i<=10; i++){
    for(int j = 3; j<=10; j++){
      if(tempRows[i][j]>maxPiece){
        maxPiece = tempRows[i][j];
      }
    }
  }
  if(maxPiece>=2){
    newRow = 1;
  }else{
    newRow = 0;
  }
}*/

//Sets active piece randomly
void newPiece(){
  posInd = 0;
  id = abs(rand()%7);
  for(int i = 0; i<=3; i++){
    for(int j = 0; j<=3; j++){
      for(int k = 0; k<=3; k++){
      switch(id){
        case 0:  
          activePiece[i][j][k] = pieceT[i][j][k];
          break;
        case 1:  
          activePiece[i][j][k] = pieceL[i][j][k];
          break;
        case 2:  
          activePiece[i][j][k] = pieceBackL[i][j][k];
          break;
        case 3:  
          activePiece[i][j][k] = pieceZ[i][j][k];
          break;
        case 4:  
          activePiece[i][j][k] = pieceBackZ[i][j][k];
          break;
        case 5:
          activePiece[i][j][k] = pieceI[i][j][k];
          break;
        case 6:
          activePiece[i][j][k] = pieceSq[i][j][k];
          break;
        }
      }
    }
  }   
}

//Makes active piece fall
void fallingPiece(){
  if(newRow==1){
    newRow = 0;
    setTemp();
    newPiece();
    pointer[0] = 0;
    pointer[1] = 4;
    for(int i = 0; i<=3; i++){
      for(int j = 0; j<=3; j++){
        //put new piece at top
        tempRows[pointer[0]+i][pointer[1]+j]=tempRows[pointer[0]+i][pointer[1]+j]+activePiece[posInd][i][j];
      }
    }
    if(collisionDetection()==false){
      if((allRows[10][0]+allRows[10][1]+allRows[10][2]+allRows[10][3]+allRows[10][4]+allRows[10][5]+allRows[10][6]+allRows[10][7])<
                (tempRows[10][0]+tempRows[10][1]+tempRows[10][2]+tempRows[10][3]+tempRows[10][4]+tempRows[10][5]+tempRows[10][6]+tempRows[10][7])){
            newRow=1;
        }
      for(int i = 0; i<=10; i++){
        for(int j = 0; j<=10; j++){
          allRows[i][j] = tempRows[i][j];
        }
      }
    }else{
      contGame = 0;
    }
  }else{
    pointer[0]++;
    for(int i = 0; i<=3; i++){
      for(int j = 0; j<=3; j++){
        //Put new piece a row down
        if(pointer[0]+i<=10){
          tempRows[pointer[0]+i][pointer[1]+j]=tempRows[pointer[0]+i][pointer[1]+j]+activePiece[posInd][i][j];
        }
        //Remove new piece from row above
        if(pointer[0]<=10){
          tempRows[(pointer[0]-1)+i][pointer[1]+j]=tempRows[(pointer[0]-1)+i][pointer[1]+j]-activePiece[posInd][i][j];
        }
      }
    }
    if(collisionDetection()==false){
      maxPiece = 0;
      for(int i = 0; i<=10; i++){
        for(int j = 0; j<=10; j++){
          allRows[i][j] = tempRows[i][j];
        }
      }
    }else{
      newRow = 1;
    }
  }
}

//When game ends, scrolls "GAME OVER"
void gameOver(){
  int temp[8];
  for(int i = 0; i<8; i++){
    for(int j = 0; j<8; j++){
      temp[j]=allRows[i+3][j];
    }
    for(int j = 0; j<7; j++){
      allRows[i+3][j]=temp[(j+1)%8];
    }
    switch(letter){
    case 0:  
      allRows[i+3][7] = letterG[i][shiftCount];
      break;
    case 1:  
      allRows[i+3][7] = letterA[i][shiftCount];
      break;
    case 2:  
      allRows[i+3][7] = letterM[i][shiftCount];
      break;
    case 3:  
      allRows[i+3][7] = letterE[i][shiftCount];
      break;
    case 4:  
      allRows[i+3][7] = 0;
      break; 
    case 5:
      allRows[i+3][7] = letterO[i][shiftCount];
      break;
    case 6:
      allRows[i+3][7] = letterV[i][shiftCount];
      break;
    case 7:
      allRows[i+3][7] = letterE[i][shiftCount];
      break;
    case 8:
      allRows[i+3][7] = letterR[i][shiftCount];
      break;  
    case 9:
      allRows[i+3][7] = 0;
      break;
    }       
  }
  shiftCount = (shiftCount + 1) % 8;
  if(shiftCount==0){
    letter=(letter+1)%10;
  }
}



//Set and display registers
//Only call AFTER all values are set how you would like (slow otherwise)
void writeRegisters(){
  digitalWrite(OE, LOW);
  digitalWrite(Latch, LOW);

  for(int i = numOfRegisterPins - 1; i>= 0; i--){
    digitalWrite(Clock, LOW);

    int val = registers[i];

    digitalWrite(Data, val);
    digitalWrite(Clock, HIGH);

  }
  digitalWrite(Latch, HIGH);
  digitalWrite(OE, HIGH);

}

void clearColumns(){
  for(int i = 0; i < 8; i++){
    digitalWrite(CPins[i], LOW);
  }
}
//set an individual pin HIGH or LOW
void setRegisterPin(int index, int value){
  registers[index] = value;
}

void loop()  {

  for(int i=0;i<8;i++){
    clearRegisters();
    writeRegisters();
    for(int j=0;j<8;j++){
      setRegisterPin(j,allRows[i+3][j]);

    }

    clearColumns();
    writeRegisters();

    digitalWrite(CPins[i], HIGH);
  }

  if(count == 25){
    if(contGame == 1){
      //endCheck();
      fallingPiece();
    }else{
      clearRegisters();
      writeRegisters();
      gameOver();
    }
    count=0;
  }

  }
  count++;
}

First, I'd guess you are running out of SRAM space. With the Arduino, memory is very scarce. You are using the int data type when you should probably be using the byte data type for the array. This will cut down your memory use by half for the arrays. If you can, add the function below and see what kind of free space you have after the arrays are all defined:

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

In your setup() function, you can use something like:

Serial.being(9600);
Serial.print("Free returns: ");
Serial.println(freeRam());

You should do this after the arrays are defined.

int letterG[8][8] = {

That's crazy - you're using sixteen bits of RAM to store 1 bit of data.

econjack:
First, I'd guess you are running out of SRAM space. With the Arduino, memory is very scarce. You are using the int data type when you should probably be using the byte data type for the array. This will cut down your memory use by half for the arrays. If you can, add the function below and see what kind of free space you have after the arrays are all defined:

int freeRam()

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




In your *setup()* function, you can use something like:



Serial.being(9600);
Serial.print("Free returns: ");
Serial.println(freeRam());




You should do this after the arrays are defined.

Okay, so first of all, changing the arrays from "int" to "byte" dropped the sketch size from about 7,200 bytes to about 6,400, which probably helps, so right off the bat, thanks for that.

Second, I added the RAM printout to the code and ran it before changing the assignments to byte (-661) and after (541). I assume the fact that it went from negative to positive is a good thing, but the matrix is still blank. Anything I'm missing logistically?

EGibbs87:
Anything I'm missing logistically?

With systems like this where you start with no idea what's working and what isn't, you need to learn to narrow the problem down. Have you proved that the hardware works correctly yet?

PeterH:

EGibbs87:
Anything I'm missing logistically?

With systems like this where you start with no idea what's working and what isn't, you need to learn to narrow the problem down. Have you proved that the hardware works correctly yet?

Yessir. As stated in the OP, I've (1) run the simulation (which has identical write and setup functions), which still loads and displays properly, and (2) translated the code into java to debug line-by-line, which now runs successfully. I took the edits I made during the java debugging and applied them in the Arduino IDE. It compiles with no problem, but the upload leaves the matrix blank.

EGibbs87:

PeterH:
With systems like this where you start with no idea what's working and what isn't, you need to learn to narrow the problem down. Have you proved that the hardware works correctly yet?

Yessir. As stated in the OP, I've (1) run the simulation (which has identical write and setup functions), which still loads and displays properly, and (2) translated the code into java to debug line-by-line, which now runs successfully. I took the edits I made during the java debugging and applied them in the Arduino IDE. It compiles with no problem, but the upload leaves the matrix blank.

So you ran a simulation on a completely different processor, and that proves the Arduino hardware works? I want one of those remote hardware checkin' thing, I do!

I suggest getting one LED to light, with a minimal sketch. Then get a column to light the way you want, then a row, etc. Build on what works.

lar3ry:

EGibbs87:

PeterH:
With systems like this where you start with no idea what's working and what isn't, you need to learn to narrow the problem down. Have you proved that the hardware works correctly yet?

Yessir. As stated in the OP, I've (1) run the simulation (which has identical write and setup functions), which still loads and displays properly, and (2) translated the code into java to debug line-by-line, which now runs successfully. I took the edits I made during the java debugging and applied them in the Arduino IDE. It compiles with no problem, but the upload leaves the matrix blank.

So you ran a simulation on a completely different processor, and that proves the Arduino hardware works? I want one of those remote hardware checkin' thing, I do!

I suggest getting one LED to light, with a minimal sketch. Then get a column to light the way you want, then a row, etc. Build on what works.

No, the stacking simulation is run on all the same hardware. The LEDs work perfectly, the shift register is working properly, etc. It's just a different sketch in my sketchbook. The thing that was run on a different processor was the debugging transcript that I did in java just to see that the logic follows properly.

I apologize. I did not realize you could run Java on the Arduino (well, I guess I thought it was possible, but never heard of anyone doing it).

lar3ry:
I apologize. I did not realize you could run Java on the Arduino (well, I guess I thought it was possible, but never heard of anyone doing it).

Can't tell if you're being sincere or sarcastic....

  1. In C++, I successfully wrote and uploaded a program that would drop rows of LEDs in my matrix and stack them until the matrix was full, at which point it would scroll "GAME OVER" through the LEDs.
  2. I tried to extend that code to, instead of dropping rows, actually drop pieces. When I uploaded the code, the matrix remained blank.
  3. I searched for a way to debug C++ code line-by-line, but to no avail.
  4. I translated the code into java (only slight variations were necessary) so that I could use Netbeans to debug line-by-line to find where the logical errors were, as I thought that was what was causing the blank matrix.
  5. I finished debugging and taking notes of the things I changed. In Netbeans, the output hinted that the code should be working as intended.
  6. I then applied those notes to the existing C++ code.
  7. The matrix remains blank. If I upload step 1, it works fine, and the LEDs illuminate.

EGibbs87:
Can't tell if you're being sincere or sarcastic....

Sincere, of course. I haven't programmed in Java since about 1996, and I never did hear of anyone doing so on an Arduino.

  1. I translated the code into java (only slight variations were necessary) so that I could use Netbeans to debug line-by-line to find where the logical errors were, as I thought that was what was causing the blank matrix.

Just to be sure we are on the same page... You were running the Java code and Netbeans (no idea what that is), on the Arduino, right?

  1. I finished debugging and taking notes of the things I changed. In Netbeans, the output hinted that the code should be working as intended.
  2. I then applied those notes to the existing C++ code.

If the answer to my question regarding #4 is "Yes" then I would suspect that the Java and the parts translated into C++ differ in some way. I have no idea whether it's a difference in code, or perhaps a difference in speed, register usage, memory usage/fragmentation, or what, but a difference there must be.

@Iar3y, I think the OP means that he wrote an "identical" program in Java on a PC as the PC environment provides an easier way to check that the logic is correct. I can empathize with that approach (although I find Java even more obscure than Arduino C++).

Of course it is also perfectly valid to wonder how many errors crept in while the code was converted from Java to C++.

@EGibbs87, perhaps you were not as clear as you could have been, and you may not be aware that there are many threads here in which ill-informed people wonder if it's possible to run Java on an Arduino.

Also, I think your biggest problem is that your project is just too complex to get useful advice here, and perhaps, for you (or anyone else) to debug. If it was my project I would break it down into small parts as others have suggested. I would also design any complex project with many debugging features built in from the start. That involves trying to envisage the problems that will arise before you write the code.

If, by "line by line" debugging you mean single-stepping through the code, that just isn't possible with the Arduino (except perhaps with some esoteric hardware and software). Which is another reason why a complex project has to have debugging built in. The normal way to debug Arduino code is to use Serial.println() in various places (perhaps many places) so you can follow the logic and check intermediate values are what they should be.

It would take me at least a few hours to make any sense of your long code. And there are dozens of other people with questions.

...R

I'd look at getting the RAM usage down - "byte" instead of "int" for the large arrays at the very least.

@Iar3y, I think the OP means that he wrote an "identical" program in Java on a PC as the PC environment provides an easier way to check that the logic is correct. I can empathize with that approach (although I find Java even more obscure than Arduino C++).

That makes sense. And of course it changes the whole discussion. If there's one thing I know about simulations, it is that they are JUST simulations, and the quality of the data gathered from them is not always a true picture of whatever they are simulating.

So yes, the OP has not verified that the hardware is OK by running the simulation, in that the hardware probably has a limitation not taken into account.

I agree with AWOL. Reduce the RAM usage.

EGibbs87:
Yessir.

I understand you've already run other sketches which proves the hardware. This confirms that you are looking at a software problem. Given the quantity of data you're using, running out of memory is a very likely cause but it could also be a logic fault.

I suggest you start with a minimal sketch that does the simplest thing you can think of out of your overall functionality. For example, turn on specified LED on and off. Run that and see how much memory you have. Extend the sketch to do something slightly more complex, for example display a single shape in a fixed location. Again, get it working and check how much memory you have. Now add in another feature, for example the ability to move the shape. You get the idea. Get each part working before you move on to the next part, and keep an eye on your remaining program and data memory so you know when you're approaching trouble. I would never try to debug something this big in one go - it's far quicker and easier to build it up piece by piece, testing as you go. If you develop your early code with the final result in mind, you should find that a lot of your higher level features can be built on top of the primitive ones and you don't end up throwing a lot of code away.

lar3ry:
Sincere, of course. I haven't programmed in Java since about 1996, and I never did hear of anyone doing so on an Arduino.

Just to be sure we are on the same page... You were running the Java code and Netbeans (no idea what that is), on the Arduino, right?

If the answer to my question regarding #4 is "Yes" then I would suspect that the Java and the parts translated into C++ differ in some way. I have no idea whether it's a difference in code, or perhaps a difference in speed, register usage, memory usage/fragmentation, or what, but a difference there must be.

Okay, I think that's where a lot of the miscommunication is. Netbeans is a separate IDE, and I translated to java because I know that that IDE allows for running the code line-by-line in java. I tried in C++, but I couldn't get gdb (C++ debugger) to work properly.

AWOL:
I'd look at getting the RAM usage down - "byte" instead of "int" for the large arrays at the very least.

I did that at the suggestion of one of the earlier posters. It helped a lot in terms of total memory used, but still hasn't resolved the issue.

Robin2:
@Iar3y, I think the OP means that he wrote an "identical" program in Java on a PC as the PC environment provides an easier way to check that the logic is correct. I can empathize with that approach (although I find Java even more obscure than Arduino C++).

Of course it is also perfectly valid to wonder how many errors crept in while the code was converted from Java to C++.

I actually kept them separate. I copied my C++ code from Arduino IDE into a java application in Netbeans and went through to fix all the programmatic problems (e.g. changing "int temp[8];" to "int[] temp = new int[8];" So I then went through and got the printout to be as I thought it should, taking notes of everything I had to change. Then, instead of copying the code over and re-translating it, I just went through my notes one-by-one and implemented them in C++, so there's no way any java "crept in."

Robin2:
If, by "line by line" debugging you mean single-stepping through the code, that just isn't possible with the Arduino (except perhaps with some esoteric hardware and software). Which is another reason why a complex project has to have debugging built in. The normal way to debug Arduino code is to use Serial.println() in various places (perhaps many places) so you can follow the logic and check intermediate values are what they should be.

I honestly didn't know about printing to Serial until this thread, so I'll definitely give that a shot next. Thanks!

I honestly didn't know about printing to Serial until this thread,

Just be careful that printing doesn't tip you further into the brown stuff.
Keep your debug labels short, and preferably keep the constant ones in flash memory using the F() macro.

AWOL:

I honestly didn't know about printing to Serial until this thread,

Just be careful that printing doesn't tip you further into the brown stuff.
Keep your debug labels short, and preferably keep the constant ones in flash memory using the F() macro.

Thank you, I'll keep that in mind when I can get back to it.