Archive of the Gamebuino Classic wiki, recovered from the Wayback Machine (capture 2020-09-08). Read-only.
Grey-scale rendering
The following is outdated as the GREY color is now part of the core library. Please refer to gb.display.setColor.
The following code shows how to display 3 colors on the Gamebuino LCD: black, white and grey. It achieves this by alternating the color of the grey pixels across subsequent frames. The demo also scrolls the background to show that real-time flicker-free full-screen rendering is indeed possible.
The image in this demo was provided by Gamebuino Forum user Erico and is a concept mock-up of a "Moon Patrol" style game. A video of this demo in action can be found at https://www.youtube.com/watch?v=JHqHEXQQD6M
// Gamebuino full-screen grey-scale rendering demo - by Mark Feldman (aka "Myndale")
//
// Based on the PCD8544 display code at http://playground.arduino.cc/Code/PCD8544
#include <TimerOne.h>
// enable this to scroll the image horizontally every frame
#define SCROLLING
// when this is enable only the bottom 40 rows are scrolled
#define SCORE_BAR
// how often to update the screen, 41 seems to be the magic number to minimize flicker
#define FRAME_RATE 41
#define PIN_SCE A1
#define PIN_RESET A0
#define PIN_DC A2
#define PIN_SDIN 11
#define PIN_SCLK 13
#define PIN_BACKLIGHT 5
#define PORT_SCLK PORTB
#define SCLK_BIT 5
#define PORT_SDIN PORTB
#define SDIN_BIT 3
#define LCD_C LOW
#define LCD_D HIGH
#define LCD_X 84
#define LCD_Y 48
#define LCD_CMD 0
int frame = 0; // which of the two buffer's we're displaying
int ofs = 0; // horizontal offset, mainly used for scrolling
// declare two display buffers, the interrupt will use then to update the LCD
// this isn't the most memory-efficient way of representing a 3-color screen
// but it'll work fine for this demo
byte buffers[2][LCD_X*LCD_Y/8] =
{
{
0xef,0xef,0xef,0xef,0xef,0xef,0xef,0xef,0xef,0xef,0xef,0xef,0xef,0xef,0xef,0xef,0xef,0xef,0xef,0xef,0xef,
0xef,0xef,0xef,0xef,0xef,0xef,0xef,0xef,0xef,0xef,0x0f,0x0f,0xef,0xaf,0xef,0x0f,0xef,0xaf,0xef,0x0f,0x2f,
0xef,0x2f,0x0f,0x0f,0xef,0xef,0xef,0xef,0xef,0xef,0xef,0xef,0xef,0xef,0xef,0xef,0xef,0x0f,0x0f,0xcf,0x4f,
0xef,0x0f,0x2f,0xef,0x2f,0x0f,0x2f,0xef,0x8f,0x0f,0xef,0x6f,0x6f,0x0f,0x6f,0xef,0xef,0x0f,0xef,0xaf,0xef,
0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xef,
0xd7,0xc7,0xd7,0xc7,0xd7,0xef,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xfa,0xff,0xff,0xff,
0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xdf,0xef,0xe7,0xfb,0xbf,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
0xff,0xff,0xff,0xef,0xcf,0xbf,0x9f,0xbf,0xcf,0xef,0xff,0xff,0xff,0xff,0xfe,0xfd,0xfc,0xfd,0xfe,0xff,0xff,
0xff,0xff,0xff,0xff,0xff,0xff,0xf9,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x7f,0xff,0x7f,0xff,0x7f,0xff,
0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
0xff,0xfe,0xff,0xfe,0xfd,0xfa,0xfc,0xf8,0xf8,0xfc,0xfe,0xfe,0xfe,0x7f,0x7f,0xff,0xff,0xff,0x7f,0x7f,0xfe,
0xff,0xfe,0xfd,0xfa,0xf0,0xf8,0xf8,0xc8,0xfd,0xfc,0xfe,0xfe,0xfe,0xfe,0xfe,0xfe,0xfe,0xfe,0xfe,0xfe,0xfe,
0xfc,0xfe,0xfc,0xfe,0xfc,0xfc,0xf8,0xf4,0xf8,0xf4,0xf8,0xf0,0xe8,0xf0,0xc0,0x80,0xc0,0xf0,0xf8,0xfc,0xfe,
0xfe,0xfe,0xfe,0xfe,0xfe,0xfc,0xfa,0xe0,0xf0,0xf8,0xfc,0xfe,0xfe,0xfe,0xff,0xff,0xff,0xff,0xfe,0xfe,0xfe,
0x00,0x00,0x00,0x00,0x07,0x01,0x3f,0x03,0x07,0x05,0x05,0x02,0x02,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x19,0x00,0x01,0x01,0x01,0x01,0x01,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x1f,0x1f,0x1f,0x7f,0xff,0xff,0xff,0xbf,0xbf,0xbf,0xff,0xbf,0xbf,0x3f,0x9f,0x7f,0x1f,0x1f,0x1f,0x1f,0x1f,
0x1f,0x1f,0x1f,0x0f,0x0f,0x0f,0x0f,0x0f,0xdf,0xef,0xff,0xef,0xff,0x6f,0x5f,0xcf,0x0f,0x0f,0x4f,0xaf,0x4f,
0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x0f,0x07,0x01,0x00,0x00,0x00,0x00,0x00,
0x00,0x01,0x07,0x0f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x0f,0x0f,0x0f,0x1f,0x1f,0x1f,
},
{
0xef,0x4f,0x4f,0x4f,0x4f,0x4f,0xcf,0x4f,0x4f,0x4f,0x0f,0x0f,0x8f,0x0f,0x0f,0x0f,0x0f,0x0f,0x8f,0x0f,0x0f,
0x0f,0x0f,0x0f,0x8f,0x0f,0x0f,0x0f,0x0f,0x0f,0x8f,0x0f,0x0f,0xef,0xaf,0xef,0x0f,0xef,0xaf,0xef,0x0f,0x2f,
0xef,0x2f,0x0f,0x0f,0x0f,0x2f,0x6f,0x2f,0x0f,0x2f,0x6f,0x2f,0x0f,0x2f,0x6d,0x2f,0x0f,0x0f,0x0f,0xcf,0x4f,
0xef,0x0f,0x2f,0xef,0x2f,0x0f,0x2f,0xef,0x8f,0x0f,0xef,0x6f,0x6f,0x0f,0x6f,0xef,0xef,0x0f,0xef,0xaf,0xef,
0xff,0xff,0xff,0xff,0xff,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xef,
0xd7,0xc7,0xc7,0xc7,0xd7,0xef,0xff,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
0xff,0xff,0xff,0xff,0xff,0xff,0xfd,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xf8,0xf8,0xff,0xff,0xff,
0xff,0xff,0xff,0xff,0xff,0xff,0xcf,0xcf,0xe7,0xe1,0x99,0x9f,0xff,0xff,0xff,0xff,0xff,0xf7,0xff,0xff,0xff,
0xff,0xff,0xff,0xef,0xcf,0x9f,0x9f,0x9f,0xcf,0xef,0xff,0xff,0xff,0xff,0xfe,0xbc,0xfc,0xfc,0xfe,0xff,0xff,
0xff,0xff,0xff,0xff,0xff,0xff,0xf9,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x3f,0x3f,0x7f,0x7f,0x3f,0x3f,0xff,
0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfb,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
0xfe,0xfc,0xdc,0xf8,0xf8,0xf8,0xf8,0xf8,0xf8,0xfc,0xfe,0xfe,0xfe,0x7f,0x7f,0xff,0xff,0xfe,0x7e,0x7e,0xfc,
0xfc,0xf8,0xf0,0xf0,0xf0,0xf8,0xf8,0xc8,0xfd,0xfc,0xfe,0xfe,0xfe,0xfe,0xfe,0xfe,0xfe,0x7e,0xfc,0xfc,0xfc,
0xfc,0xfc,0xf8,0xf8,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xe0,0xe0,0xc0,0xc0,0x80,0x80,0xc0,0xf0,0xf8,0xfc,0xfe,
0xfe,0xfe,0xfc,0xfc,0xf8,0xf0,0xe0,0xe0,0xf0,0xf8,0xfc,0xfe,0xfe,0xfe,0xff,0xff,0xff,0xff,0xfe,0xfe,0xfe,
0x00,0x00,0x00,0x00,0x07,0x01,0x3f,0x02,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x19,0x00,0x00,0x01,0x01,0x01,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x1f,0x1e,0x1d,0x7e,0xfd,0xda,0x14,0x08,0x12,0x08,0x00,0x10,0x00,0x10,0x00,0x10,0x10,0x10,0x10,0x18,0x10,
0x10,0x18,0x10,0x08,0x08,0x08,0x08,0x08,0x58,0xe8,0x58,0xe8,0xd8,0x68,0x58,0xc8,0x08,0x08,0x48,0xa8,0x48,
0x10,0x18,0x10,0x10,0x18,0x10,0x10,0x10,0x18,0x12,0x10,0x1a,0x15,0x0b,0x07,0x01,0x00,0x00,0x00,0x00,0x00,
0x00,0x01,0x07,0x0b,0x15,0x1a,0x10,0x12,0x18,0x10,0x18,0x10,0x10,0x18,0x10,0x08,0x08,0x08,0x10,0x18,0x10
}
};
void LcdClear(void) {
for (int index = 0; index < LCD_X * LCD_Y / 8; index++)
{
LcdWrite(LCD_D, 0x00);
}
}
void LcdInitialise(void) {
pinMode(PIN_SCE, OUTPUT);
pinMode(PIN_RESET, OUTPUT);
pinMode(PIN_DC, OUTPUT);
pinMode(PIN_SDIN, OUTPUT);
pinMode(PIN_SCLK, OUTPUT);
digitalWrite(PIN_RESET, LOW);
digitalWrite(PIN_RESET, HIGH);
LcdWrite( LCD_CMD, 0x21 ); // LCD Extended Commands.
LcdWrite( LCD_CMD, 0xB9 ); // Set LCD Vop (Contrast). //B1
LcdWrite( LCD_CMD, 0x04 ); // Set Temp coefficent. //0x04
LcdWrite( LCD_CMD, 0x14 ); // LCD bias mode 1:48. //0x13
LcdWrite( LCD_CMD, 0x0C ); // LCD in normal mode. 0x0d for inverse
LcdWrite(LCD_C, 0x20);
LcdWrite(LCD_C, 0x0C);
}
void LcdWrite(byte dc, byte data) {
digitalWrite(PIN_DC, dc);
digitalWrite(PIN_SCE, LOW);
shiftOut(PIN_SDIN, PIN_SCLK, MSBFIRST, data);
digitalWrite(PIN_SCE, HIGH);
}
void gotoXY(int x, int y) {
LcdWrite( 0, 0x80 | x); // Column.
LcdWrite( 0, 0x40 | y); // Row.
}
void setup(void) {
LcdInitialise();
LcdClear();
pinMode(PIN_BACKLIGHT, OUTPUT);
digitalWrite(PIN_BACKLIGHT, HIGH);
Timer1.initialize(1000000/FRAME_RATE); // initialize timer1, and set a 1/2 second period
Timer1.pwm(9, 512); // setup pwm on pin 9, 50% duty cycle
Timer1.attachInterrupt(callback); // attaches callback() as a timer overflow interrupt
}
/* this code works but digitalWrite is much slower than directly writing to the port
#define bitOut(val, bit) { \
digitalWrite(PIN_SDIN, !!(val & (1 << bit))); \
digitalWrite(PIN_SCLK, HIGH); \
digitalWrite(PIN_SCLK, LOW); \
}
*/
#define bitOut(val, bit) { \
if (val & (1 << bit)) \
PORT_SDIN |= _BV(SDIN_BIT); \
else \
PORT_SDIN &= ~_BV(SDIN_BIT); \
PORT_SCLK |= _BV(SCLK_BIT); \
PORT_SCLK &= ~_BV(SCLK_BIT); \
}
inline void byteOut(byte val)
{
bitOut(val, 0);
bitOut(val, 1);
bitOut(val, 2);
bitOut(val, 3);
bitOut(val, 4);
bitOut(val, 5);
bitOut(val, 6);
bitOut(val, 7);
}
void callback() {
digitalWrite(PIN_DC, LCD_D);
digitalWrite(PIN_SCE, LOW);
for (int i=0; i<504; i++)
byteOut(buffers[frame][i+ofs]);
digitalWrite(PIN_SCE, HIGH);
frame = 1 - frame;
#ifdef SCROLLING
if (frame == 0)
scrollBuffers();
#endif // SCROLLING
}
void scrollBuffers() {
for (int frame=0; frame<2; frame++)
{
#ifdef SCORE_BAR
int y = 1;
#else
int y = 0;
#endif
byte * buffer = buffers[frame] + y*84;
for (; y<(LCD_Y/8); y++, buffer+=LCD_X)
{
byte start = *buffer;
for (int x=0; x<LCD_X-1; x++)
buffer[x] = buffer[x+1];
buffer[LCD_X-1] = start;
}
}
}
void loop(void) {
// loop still gets called, and the LCD is being updated via an interrupt
// so put your game code here and update the display buffers at whatever
// frame rate you like
}