[Weird] Problems With Large Matrices

Understanding the language, error messages, etc.

[Weird] Problems With Large Matrices

Postby Montiey » Mon Mar 21, 2016 9:22 pm

I'm trying to make a simple paint program, basically choose which pixels are black or white.

This is my code currently:

Code: Select all
#include <SPI.h>
#include <Gamebuino.h>
Gamebuino gb;

const unsigned char PROGMEM player[] = {
  8,8,
  B00000000,
  B01111000,
  B01100000,
  B01010000,
  B01001000,
  B00000100,
  B00000010,
  B00000001,
};

int player_x = 0;
int player_y = 0;
int player_size = 8;      //width, height
int button_repeat = 5;
int paintMap[8][8];

void setup(){
  gb.begin();
  gb.titleScreen(F("Jason's" ));
}

void loop(){
  if(gb.update()){
    for(int x = 0; x < 8; x++){
      for(int y = 0; y < 8; y++){
        gb.display.setColor(paintMap[x][y]);    //choose color at possition
        gb.display.drawPixel(x, y);             //draw that pixel
      }
    }
    moveWithButtons(1);                         //move the cursor
    paintWithButtons();                         //set value in matrix on button press
  }
}

int paintWithButtons(){
  if(gb.buttons.repeat(BTN_A, button_repeat)){
    paintMap[player_x][player_y] = 1;
  }
  if(gb.buttons.repeat(BTN_B, button_repeat)){
    paintMap[player_x][player_y] = 0;
  }
}

int moveWithButtons(int velocity){
  if(gb.buttons.repeat(BTN_RIGHT, button_repeat)){
    player_x = player_x + velocity;
  }
  if(gb.buttons.repeat(BTN_LEFT, button_repeat)){
    player_x = player_x - velocity;
  }
  if(gb.buttons.repeat(BTN_UP, button_repeat)){
    player_y = player_y - velocity;
  }
  if(gb.buttons.repeat(BTN_DOWN, button_repeat)){
    player_y = player_y + velocity;
  }
 
  if((player_x) > LCDWIDTH){                          //keep cursor on screen
    player_x = LCDWIDTH;
  }
  if(player_x < 0){
    player_x = 0;
  }
  if(player_y < 0){
    player_y = 0;
  }
  if((player_y) > LCDHEIGHT){
    player_y = LCDHEIGHT;
  }
 
  gb.display.setColor(1);
  gb.display.drawBitmap(player_x, player_y, player);
}


It does some pretty weird things, but really you'd need to play it yourself to see.

If the size of the matrix is much larger than 20 * 20, the gamebuino either displays a corrupt image on startup, plays a buzzing when B is pressed (on startup), or cycles in a reboot loop.
Setting it to something like 8*8 works "well". Sometimes while creating a magnificent 64 pixel masterpiece I will get a low battery alarm. These have usually registered at 4.1 volts, or 4157mV as actually reported. Thats definitely not a drained battery of any sorts, so maybe some sort of spike due to high CPU load? I can't really see how i'm pushing the limits with a 20*20 matrix when the same device, but i'm sure there's a reason.
Have any ideas? I found the For Loop structure in a matrix example somewhere, maybe there is a more efficient way to store the pixel values?
Last edited by Montiey on Mon Mar 28, 2016 8:22 pm, edited 1 time in total.
User avatar
Montiey
 
Posts: 68
Joined: Sat Jan 17, 2015 5:38 pm

Re: Large Matrices for user-bitmapping

Postby Sorunome » Mon Mar 21, 2016 10:39 pm

Some of those issues you described seem to me as if you use too much ram (random sound etc.)
If you are using a 20x20 matrix you are using 800 bytes of ram as you set it to variable type 'int'.
As you only store colors in it which are within the 0-255 range you should try using type 'byte' instead.
I'd recommend taking a look at this: http://gamebuino.com/wiki/index.php?tit ... #Variables
User avatar
Sorunome
 
Posts: 629
Joined: Sun Mar 01, 2015 1:58 pm

Re: Large Matrices for user-bitmapping

Postby Montiey » Fri Mar 25, 2016 1:20 am

Using byte seemed to help, but I still can't get the matrix up above 20*20. It seems like some of my problems come from when the cursor leave the "canvas" area. I guess this could cause some rapid looping in the for loops. What you you noted that I had previously said still seems to be a problem; Random buzzing, intermittent backlight, and the battery status indicator disappearing / corrupted. The Arduino IDE says that I use about 11 kilobytes, but maybe only a small portion available is RAM?

Code: Select all
#include <SPI.h>
#include <Gamebuino.h>
Gamebuino gb;

const unsigned char PROGMEM player[] = {
  8,8,
  B00000000,
  B01111000,
  B01100000,
  B01010000,
  B01001000,
  B00000100,
  B00000010,
  B00000001,
};

int player_x = 0;
int player_y = 0;
int player_size = 8;      //width, height
int button_repeat = 5;

const unsigned canvas_x_size = 20;
const unsigned canvas_y_size = 20;

byte paintMap[canvas_x_size][canvas_y_size];

void setup(){
  gb.begin();
  gb.titleScreen(F("Jason's" ));
}

void loop(){
  if(gb.update()){
    if(player_x < canvas_y_size && player_y < canvas_x_size){
      for(int x = 0; x < canvas_x_size; x++){
        for(int y = 0; y < canvas_y_size; y++){
          gb.display.setColor(paintMap[x][y]);    //choose color at possition
          gb.display.drawPixel(x, y);             //draw that pixel
        }
      }
    }
    moveWithButtons(1);                         //move the cursor
    paintWithButtons();                         //set value in matrix on button press
  }
}

int paintWithButtons(){
  if(gb.buttons.repeat(BTN_A, button_repeat)){
    paintMap[player_x][player_y] = 1;
  }
  if(gb.buttons.repeat(BTN_B, button_repeat)){
    paintMap[player_x][player_y] = 0;
  }
}

int moveWithButtons(int velocity){
  if(gb.buttons.repeat(BTN_RIGHT, button_repeat)){
    player_x = player_x + velocity;
  }
  if(gb.buttons.repeat(BTN_LEFT, button_repeat)){
    player_x = player_x - velocity;
  }
  if(gb.buttons.repeat(BTN_UP, button_repeat)){
    player_y = player_y - velocity;
  }
  if(gb.buttons.repeat(BTN_DOWN, button_repeat)){
    player_y = player_y + velocity;
  }
 
  if((player_x) > LCDWIDTH){                          //keep cursor on screen
    player_x = LCDWIDTH;
  }
  if(player_x < 0){
    player_x = 0;
  }
  if(player_y < 0){
    player_y = 0;
  }
  if((player_y) > LCDHEIGHT){
    player_y = LCDHEIGHT;
  }
 
  gb.display.setColor(1);
  gb.display.drawBitmap(player_x, player_y, player);
}
User avatar
Montiey
 
Posts: 68
Joined: Sat Jan 17, 2015 5:38 pm

Re: Large Matrices for user-bitmapping

Postby Sorunome » Fri Mar 25, 2016 9:24 am

I just notice you limit the cursor to LCDWIDTH/LCDHEIGHT, but you need to limit it to your matrix. Else you'll be overwriting random ram areas resulting in random stuff.
User avatar
Sorunome
 
Posts: 629
Joined: Sun Mar 01, 2015 1:58 pm

Re: Large Matrices for user-bitmapping

Postby Montiey » Sat Mar 26, 2016 12:21 am

Is that what happens when you write to coords that are outside of the bounds? I'd assume that it would just return 0 or something, but I guess I should disable writing to the matrix if the cursor is outside of the canvas. Good thinking!
User avatar
Montiey
 
Posts: 68
Joined: Sat Jan 17, 2015 5:38 pm

Re: Large Matrices for user-bitmapping

Postby Sorunome » Sat Mar 26, 2016 9:29 am

Yes, C/C++ is known for not checking array offsets/where pointers actually point, so you, the programmer, has to make sure that nothing is violated.
User avatar
Sorunome
 
Posts: 629
Joined: Sun Mar 01, 2015 1:58 pm

Re: Large Matrices for user-bitmapping

Postby Montiey » Sun Mar 27, 2016 1:40 pm

Well, I have absolutely not worked out all the quirks yet.
I've gotten the code to export the images to the serial monitor, and also added some (currently non-functional) sidebar buttons. That's where the fun begins:
Code: Select all
#include <SPI.h>
#include <Gamebuino.h>
Gamebuino gb;

const unsigned char PROGMEM player[] = {
  8,8,
  B00000000,
  B01111000,
  B01100000,
  B01010000,
  B01001000,
  B00000100,
  B00000000,
  B00000000,
};

const unsigned char PROGMEM smallBrush[] = {
  8,8,
  B00111111,
  B01000000,
  B10000000,
  B10001100,
  B10001100,
  B10000000,
  B01000000,
  B00111111,
};

const unsigned char PROGMEM largeBrush[] = {
  8,8,
  B00111111,
  B01000000,
  B10001100,
  B10011110,
  B10011110,
  B10001100,
  B01000000,
  B00111111,
};

const unsigned char PROGMEM smallEraser[] = {
  8,8,
  B00111111,
  B01000000,
  B10001100,
  B10010010,
  B10010010,
  B10001100,
  B01000000,
  B00111111,
};

const unsigned char PROGMEM largeEraser[] = {
  8,8,
  B00111111,
  B01001100,
  B10010010,
  B10100001,
  B10100001,
  B10010010,
  B01001100,
  B00111111,
};

#define canvas_x_size 20                      //define, not int to save memory (maybe?)
#define canvas_y_size 20
#define player_size 8
#define button_repeat 2

////////////////////////////////////////
////////////////////////////////////////

int player_x = 0;
int player_y = 0;
int activeIcon = 1;                              //which tool is active at start
byte activeIconOffset[4];                        //the offset distance at any (4) given position(s)
byte canvas[canvas_x_size][canvas_y_size];

void setup(){
  gb.begin();
  Serial.begin(19200);
  gb.battery.show = false;
  activeIconOffset[1] = 2;
}

void loop(){
  if(gb.update()){
    updateCanvas();                             //draw the pixels in the matrix (once per frame)
    moveWithButtons(1);                         //move the player
   
    if(gb.buttons.repeat(BTN_A, 1)){            //set value in matrix on button press
      canvas[player_x][player_y] = 1;
    }
   
    exportMatrix();                             //experamental
    updateIcons();                              //draw & set state of tool indicators
  }
}

////////////////////////////////////////
////////////////////////////////////////

int updateIcons(){
  if(gb.buttons.pressed(BTN_B)){
    activeIconOffset[activeIcon] = 0;
    if(activeIcon < 4){                         //only if not on the last one!
      activeIconOffset[activeIcon + 1] = 2;
    }
    activeIcon++;                               //move to next tool
    if(activeIcon > 4){
      activeIcon = 1;                           //go back to first tool
      activeIconOffset[1] = 2;                  //imediately set its offset to 2
    }
    Serial.println();
    Serial.println(activeIcon);
    Serial.println();
    Serial.println(activeIconOffset[1]);
    Serial.println(activeIconOffset[2]);
    Serial.println(activeIconOffset[3]);
    Serial.println(activeIconOffset[4]);
  }
  gb.display.drawBitmap(LCDWIDTH - activeIconOffset[1] - 8, 4, smallBrush);           //position the icons according to set values in the array
  gb.display.drawBitmap(LCDWIDTH - activeIconOffset[2] - 8, 13, largeBrush);
  gb.display.drawBitmap(LCDWIDTH - activeIconOffset[3] - 8, 22, smallEraser);
  gb.display.drawBitmap(LCDWIDTH - activeIconOffset[4] - 8, 31, largeEraser);
}

int updateCanvas(){
  for(int x = 0; x < canvas_x_size; x++){
    for(int y = 0; y < canvas_y_size; y++){
      gb.display.setColor(canvas[x][y]);    //get corosponding color at position
      gb.display.drawPixel(x, y);             //draw that pixel for the current frame
    }
  }
}

int exportMatrix(){                               //start the serial monitor before you paint something
  if(gb.buttons.repeat(BTN_C, 1000)){
    for(int y = 0; y < canvas_x_size; y++){       //row-scanning export
      Serial.println();
      for(int x = 0; x < canvas_y_size; x++){
        Serial.print(canvas[x][y]);              //makes the picture look better via double print
        Serial.print(canvas[x][y]);
      }
    }
    Serial.println();
  }
}

int moveWithButtons(int velocity){
  if(gb.buttons.repeat(BTN_RIGHT, button_repeat)){
    player_x = player_x + velocity;
  }
  if(gb.buttons.repeat(BTN_LEFT, button_repeat)){
    player_x = player_x - velocity;
  }
  if(gb.buttons.repeat(BTN_UP, button_repeat)){
    player_y = player_y - velocity;
  }
  if(gb.buttons.repeat(BTN_DOWN, button_repeat)){
    player_y = player_y + velocity;
  }
 
  if((player_x) > LCDWIDTH){                          //keep the cursor on screen
    player_x = LCDWIDTH;
  }
  if(player_x < 0){
    player_x = 0;
  }
  if(player_y < 0){
    player_y = 0;
  }
  if((player_y) > LCDHEIGHT){
    player_y = LCDHEIGHT;
  }
 
  gb.display.setColor(1);
  gb.display.drawBitmap(player_x, player_y, player);
}


For some reason, somehow, the X position of the lower sidebar icon (#4) is linked to the Y position of the cursor! I've looked through the code at least 10 times now looking for anything that could this, but I think it has something to to with memory again. Maybe it looses track of which one is which somewhere, and starts controlling both with the same values?
User avatar
Montiey
 
Posts: 68
Joined: Sat Jan 17, 2015 5:38 pm


Return to Programming Questions

Who is online

Users browsing this forum: No registered users and 12 guests

cron