Archive of the Gamebuino Classic forum (2014-2018), rebuilt from the pages kept by the Wayback Machine: only part of the topics and pages were captured. Read-only. Removal on request: hi@gamebuino.com.
[Weird] Problems With Large Matrices
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:
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?
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?
Sorunome Mon Mar 21, 2016 10:39 pm Re: Large Matrices for user-bitmapping
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
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
Montiey Fri Mar 25, 2016 1:20 am Re: Large Matrices for user-bitmapping
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);
}
Sorunome Fri Mar 25, 2016 9:24 am Re: Large Matrices for user-bitmapping
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.
Montiey Sat Mar 26, 2016 12:21 am Re: Large Matrices for user-bitmapping
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!
Sorunome Sat Mar 26, 2016 9:29 am Re: Large Matrices for user-bitmapping
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.
Montiey Sun Mar 27, 2016 1:40 pm Re: Large Matrices for user-bitmapping
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:
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?
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?