Switch to full style
Understanding the language, error messages, etc.
Post a reply

[Weird] Problems With Large Matrices

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:
#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.

Re: Large Matrices for user-bitmapping

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

Re: Large Matrices for user-bitmapping

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:
#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);
}

Re: Large Matrices for user-bitmapping

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.

Re: Large Matrices for user-bitmapping

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!

Re: Large Matrices for user-bitmapping

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.

Re: Large Matrices for user-bitmapping

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:
#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?
Post a reply