Library for communicating with a Gameduino shield. Provides colour VGA display, hardware sprites with collision detection and stero sound. See http://excamera.com/sphinx/gameduino/ for more details.

Dependents:   GameduinoTest SimpleGameduinoTest RobotRic

Note that to use this library you must also import the CommonTypes library because this library uses it.

To get an mbed talking to a Gameduino shield all you really have to do is connect the Gameduino to the SPI bus. I did it using an LPC11U24 mbed and wired it to the Gameduino as follows:

  • mbed pin...................Gameduino pin
  • 5 (MOSI)...................11 (MOSI)
  • 6 (MISO)...................12 (MISO)
  • 7 (SCK)....................13 (SCK)
  • 8..........................9 (SEL)
  • 40 (VOUT)..................5V and 3.3V
  • 1 (GND)....................GND

mbed pins 5, 6 and 7 make up the SPI datalink. mbed pin 8 should be configured as a digital output and is driven low to communicate with the Gameduino.

Probably best to run the whole lot off a regulated 5V supply rather than relying on the 5V supply from the USB cable. I have had problems with the mbed's 3.3V VOUT supply. If the USB voltage is very low (nearer 4V than 5V) then the mbed's 3.3V regulator won't work properly and can't provide much current. I struggled to draw 10 mA for an LED. These problems go away if you power everything off an external 5V supply. It also means you can unplug the mbed from your computer of course.

Mounting the Gameduino is a bit awkward. I put it on some stripboard using 3 SIL sockets designed for an Arduino. Then I mounted the mbed alongside using two 20 pin SIL sockets. Unfortunately Arduino shields like the Gameduino don't fit nicely on a 0.1 inch grid (like the mbed does) so some connections have to be made using flying wires.

Here are some screenshots:

/media/uploads/RichardE/_scaled_img_0055_compressed.jpg

/media/uploads/RichardE/_scaled_img_0057_compressed.jpg

The code for generating this last display is found here:

Import programGameduinoTest

More complicated test program that generates text, coloured sprites and sound.

Here's the games console:

/media/uploads/RichardE/_scaled_img_0058_compressed.jpg

and the insides. Don't worry about the cables and the 8 pin chips. You don't need them if all you want is a display. They are an RS485 chip and a serial EEPROM.

/media/uploads/RichardE/_scaled_img_0059_compressed.jpg

Gameduino.cpp

Committer:
RichardE
Date:
2013-06-05
Revision:
5:d614b857b940
Parent:
4:f6a33c5f0f7f

File content as of revision 5:d614b857b940:

/*
 * SOURCE FILE : Gameduino.cpp
 *
 * Definition of class Gameduino.
 * Each instance of this class allows communication with
 * a Gameduino shield over an SPI communications link.
 *
 */

#include "Gameduino.h"      // this module's prototypes
#include "font8x8.h"        // default font

/***************/
/* CONSTRUCTOR */
/***************/
// Pass pointer to SPI datalink in spi.
// Pass pointer to chip select in cs.
Gameduino::Gameduino( SPI *spi, DigitalOut *cs ) :
    spr( 0 ),
    spi( spi ),
    cs( cs )
{
}

/**************/
/* DESTRUCTOR */
/**************/
Gameduino::~Gameduino() {
}

/*****************************************************/
/* INITIALISE CONNECTION TO ADAPTER AND RESET THINGS */
/*****************************************************/
void Gameduino::begin( void ) {
    // Wait a bit to allow Gameduino to boot.
    wait_ms( 250 );
    // Deselect the Gameduino.
    *cs = 1;
    wr( J1_RESET, 1 );               // HALT coprocessor
    wr( VIDEO_MODE, MODE_800x600_72 );
    HideAllSprites();
    fill( RAM_PIC, 0, 1024 * 10 );  // Zero all character RAM
    fill( RAM_SPRPAL, 0, 2048 );    // Sprite palletes black
    fill( RAM_SPRIMG, 0, 64 * 256 );// Clear all sprite data
    fill( VOICES, 0, 256 );         // Silence
    fill( PALETTE16A, 0, 128 );     // Black 16-, 4-palletes and COMM
    wr16( SCROLL_X, 0 );
    wr16( SCROLL_Y, 0 );
    wr( JK_MODE, 0 );
    wr( SPR_DISABLE, 0 );
    wr( SPR_PAGE, 0 );
    wr( IOMODE, 0 );
    wr16( BG_COLOR, 0 );
    wr16( SAMPLE_L, 0 );
    wr16( SAMPLE_R, 0 );
    wr16( SCREENSHOT_Y, 0 );
    wr( MODULATOR, 64 );
}

static const UInt8 stretch[16] = {
  0x00, 0x03, 0x0c, 0x0f,
  0x30, 0x33, 0x3c, 0x3f,
  0xc0, 0xc3, 0xcc, 0xcf,
  0xf0, 0xf3, 0xfc, 0xff
};

/***********************************************/
/* SET DEFAULT ASCII CHARACTER SET AND PALETTE */
/***********************************************/
void Gameduino::ascii( void ) {
    UInt8 b, h, l;
    UInt16 address;
    const UInt8 *ptr = font8x8;
    for( UInt16 i = 0; i < 768; ++i ) {
        b = *ptr++;
        h = stretch[ b >> 4 ];
        l = stretch[ b & 0xf ];
        address = RAM_CHR + ( ' ' << 4 ) + ( i << 1 );
        wr( address++, h );
        wr( address, l );
    }
    for( UInt16 i = 0x20; i < 0x80; ++ i) {
        setpal( 4 * i + 0, TRANSPARENT );
        setpal( 4 * i + 3, RGB (255, 255, 255 ) );
    }
    fill( RAM_PIC, ' ', 4096 );
}

/****************************/
/* START AN SPI TRANSACTION */
/****************************/
// Pass address to read or write to in address.
// Bit 15 must be set for a write.
void Gameduino::__start( UInt16 address ) {
    *cs = 0;                                // select Gameduino
    spi->write( ( address >> 8 ) & 0xFF );  // send bits 8 to 15 of address
    spi->write( address & 0xFF );           // send bits 0 to 7 of address
}

/**********************************/
/* START AN SPI WRITE TRANSACTION */
/**********************************/
// Pass address write to in address.
void Gameduino::__wstart( UInt16 address ) {
    __start( 0x8000 | address );
}

/******************************/
/* START A SPRITE TRANSACTION */
/******************************/
// Use this before calling xhide, xsprite or TransferSprite.
// Pass sprite number to start at in sprnum.
void Gameduino::__wstartspr( UInt8 sprnum ) {
    __wstart( RAM_SPR + ( sprnum << 2 ) );
    spr = 0;
}

/*************************/
/* TRANSFER BYTE VIA SPI */
/*************************/
// Use only after a call to __start or __wstart.
// Pass data to send in data.
UInt8 Gameduino::__tr8( UInt8 data ) {
    return (UInt8)spi->write( data );
}

/********************************/
/* TRANSFER 16 BIT WORD VIA SPI */
/********************************/
// Use only after a call to __start or __wstart.
// Pass data to send in data.
UInt8 Gameduino::__tr16( UInt16 data ) {
    UInt16 result;
    result = spi->write( data & 0xFF );                         // send and get bits 0 to 7
    result |= ( spi->write( ( data >> 8 ) & 0xFF ) << 8 );      // send and get bits 8 to 15
    return result;                          // return word read    
}

/**************************/
/* END AN SPI TRANSACTION */
/**************************/
void Gameduino::__end( void ) {
    *cs = 1;                                // deselect Gameduino
}
    
/***************/
/* READ A BYTE */
/***************/
// Pass address in Gameduino memory to read from.
// Returns byte at that address.    
UInt8 Gameduino::rd( UInt16 address ) {
    __start( address );                     // start SPI read operation
    UInt8 data = __tr8( 0 );                // read byte from Gameduino
    __end();                                // end of SPI operation
    return data;                            // return byte read
}

/**********************/
/* READ A 16 BIT WORD */
/**********************/
// Pass address in Gameduino memory to read from.
// Returns byte at that address.    
UInt16 Gameduino::rd16( UInt16 address ) {
    __start( address );                     // start SPI read operation
    UInt16 data = __tr16( 0 );
    __end();                                // end of SPI operation
    return data;                            // return word read    
}

/****************/
/* WRITE A BYTE */
/****************/
// Pass address to write to in address.
// Pass data to write in data.
void Gameduino::wr( UInt16 address, UInt8 data ) {
    __wstart( address );                    // start SPI write operation
    __tr8( data );
    __end();                                // end of SPI operation
}

/***********************/
/* WRITE A 16 BIT WORD */
/***********************/
// Pass address to write to in address.
// Pass data to write in data.
void Gameduino::wr16( UInt16 address, UInt16 data ) {
    __wstart( address );
    __tr16( data );
    __end();
}

/*********************************/
/* FILL AREA OF GAMEDUINO MEMORY */
/*********************************/
// Pass address to write to in address.
// Pass data to write to entire area in data.
// Pass number of bytes to write in count.
void Gameduino::fill( UInt16 address, UInt8 data, UInt16 count ) {
    __wstart( address );
    while( count-- ) {
        __tr8( data );
    }
    __end();
}

/***********************************/
/* COPY DATA INTO GAMEDUINO MEMORY */
/***********************************/
// Pass address to write to in address.
// Pass pointer to source of data in src.
// Pass number of bytes to copy in count.
void Gameduino::copy( UInt16 address, const UInt8 *src, UInt16 count ) {
    __wstart( address );
    while( count-- ) {
        __tr8( *src++ );
    }
    __end();
}

/*****************/
/* HIDE A SPRITE */
/*****************/
// Use only after specifying address to write to.
// Basically just writes 400 twice to SPI.
void Gameduino::xhide( void ) {
    __tr16( 400 );
    __tr16( 400 );
    spr++;
}

/****************************************/
/* SEND SPRITE INFORMATION TO GAMEDUINO */
/****************************************/
// Use only after specifying address to write to.
// Pass coordinates in x and y.
// Pass sprite image number in image.
// Pass palette selection information in palette (use 0 for 256 colour palette).
// Pass rotation and flip setting in rot.
// Pass JK collision information in jk (0 or 1).
void Gameduino::TransferSprite( Int16 x, Int16 y, UInt8 image, UInt8 palette, Rotation rot, UInt8 jk ) {
    __tr8( x & 0xFF );
    __tr8( ( palette << 4 ) | ( rot << 1 ) | ( ( x >> 8 ) & 1 ) );
    __tr8( y & 0xFF );
    __tr8( ( jk << 7 ) | ( image << 1 ) | ( ( y >> 8 ) & 1 ) );
}

/**************************************************************************/
/* DRAW A SPRITE AT AN OFFSET FROM AN ORIGIN TAKING INTO ACCOUNT ROTATION */
/**************************************************************************/
// Use only after specifying address to write to.
// Pass origin coordinates in ox and oy.
// Pass offset from origin in x and y.
// Pass sprite image number in image.
// Pass palette selection information in palette (use 0 for 256 colour palette).
// Pass rotation and flip setting in rot.
// Pass JK collision information in jk (0 or 1).
void Gameduino::xsprite( Int16 ox, Int16 oy, Int8 x, Int8 y, UInt8 image, UInt8 palette, Rotation rot, UInt8 jk ) {
    if( rot & 2 ) {
        // Flip X.
        x = -16 - x;
    }
    if( rot & 4 ) {
        // Flip Y.
        y = -16 - y;
    }
    if( rot & 1 ) {
        // Swap X and Y.
        int s;
        s = x; x = y; y = s;
    }
    ox += x;
    oy += y;
    TransferSprite( ox, oy, image, palette, rot, jk );
    spr++;
}

/***********************/
/* CONSTRUCT RGB VALUE */
/***********************/
// Pass red level in r.
// Pass green level in g.
// Pass blue level in b.
// Returns RGB value.
UInt16 Gameduino::RGB( UInt8 r, UInt8 g, UInt8 b ) {
    return ((((r) >> 3) << 10) | (((g) >> 3) << 5) | ((b) >> 3));
}

/*********************/
/* SET PALETTE ENTRY */
/*********************/
// Pass pallete entry to set in pal.
// Pass RGB value to store in rgb.
void Gameduino::setpal( UInt16 pal, UInt16 rgb ) {
    wr16( RAM_PAL + ( pal << 1 ), rgb );
}

/***********************************************/
/* WRITE SINGLE CHARACTER AT GIVEN COORDINATES */
/***********************************************/
// Pass X coordinate in x.
// Pass Y coordinate in y.
// Pass pointer to zero terminated text in s.
void Gameduino::putchar( UInt8 x, UInt8 y, char c ) {
    __wstart( RAM_PIC + ( y << 6 ) + x );
    __tr8( c );
    __end();
}

/***********************************/
/* WRITE TEXT AT GIVEN COORDINATES */
/***********************************/
// Pass X coordinate in x.
// Pass Y coordinate in y.
// Pass pointer to zero terminated text in s.
void Gameduino::putstr( UInt8 x, UInt8 y, const char *s ) {
    __wstart( RAM_PIC + ( y << 6 ) + x );
    while( *s ) {
        __tr8( *s++ );
    }
    __end();
}

/*********************/
/* POSITION A SPRITE */
/*********************/
// Pass sprite number in spr.
// Pass X and Y coordinates in x and y.
// Pass sprite image number in image.
// Pass palette selection information in palette (use 0 for 256 colour palette).
// Pass rotation and flip setting in rot.
// Pass JK collision information in jk (0 or 1).
void Gameduino::sprite( UInt8 spr, Int16 x, Int16 y, UInt8 image, UInt8 palette, Rotation rot, UInt8 jk ) {
    __wstart( RAM_SPR + ( spr << 2 ) );
    TransferSprite( x, y, image, palette, rot, jk );
    __end();
}

/***********************************/
/* DRAW 4 SPRITES AS A 2 X 2 BLOCK */
/***********************************/
// Pass sprite number for first sprite in spr.
// Pass X and Y coordinates in x and y. These are coordinates of centre of group.
// Pass sprite image number for first image in image.
// Pass palette selection information in palette (use 0 for 256 colour palette).
// Pass rotation and flip setting in rot.
// Pass JK collision information in jk (0 or 1).
void Gameduino::sprite2x2( UInt8 spr, Int16 x, Int16 y, UInt8 image, UInt8 palette, Rotation rot, UInt8 jk ) {
    __wstart( RAM_SPR + ( spr << 2 ) );
    xsprite( x, y, -16, -16, image + 0, palette, rot, jk );
    xsprite( x, y,   0, -16, image + 1, palette, rot, jk );
    xsprite( x, y, -16,   0, image + 2, palette, rot, jk );
    xsprite( x, y,   0,   0, image + 3, palette, rot, jk );
    __end();
}

/**************************************************/
/* PLOT A NUMBER OF SPRITES RELATIVE TO AN ORIGIN */
/**************************************************/
// Use only after calling __wstartspr.
// Pass X and Y coordinates of origin in ox and oy.
// Pass pointer to an array of sprplot structures in psp.
// Pass number of structures in array in count.
// Pass rotation and flip setting in rot.
// Pass JK collision information in jk (0 or 1).
void Gameduino::plots( Int16 ox, Int16 oy, const sprplot *psp, UInt8 count, Rotation rot, UInt8 jk ) {
    while( count-- ) {
        xsprite( ox, oy, psp->x, psp->y, psp->image, psp->palette, rot, jk );
        psp++;
    }
}

/******************************/
/* WAIT FOR VERTICAL BLANKING */
/******************************/
void Gameduino::waitvblank( void ) {
    // Wait until VBLANK register is zero.
    while( rd( VBLANK ) ) {
        // do nothing.
    }
    // Wait until VBLANK register is non-zero.
    while( ! rd( VBLANK ) ) {
        // do nothing.
    }
    // Exit just at the moment VBLANK goes from zero to non-zero.
}

/****************/
/* MAKE A NOISE */
/****************/
// Pass voice number in v.
// Pass waveform type in wave.
// Pass frequency in quarter Hz (so 100 Hz is 400) in freq.
// Pass amplitude for left channel in lamp.
// Pass amplitude for right channel in ramp.
void Gameduino::voice( UInt8 v, WaveForm wave, UInt16 freq, UInt8 lamp, UInt8 ramp ) {
    __wstart( VOICES + ( v << 2 ) );
    __tr8( freq & 0xFF );
    __tr8( ( ( freq >> 8 ) & 0xFF ) | ( wave << 7 ) );
    __tr8( lamp );
    __tr8( ramp );
    __end();
}

/********************/
/* HIDE ALL SPRITES */
/********************/
void Gameduino::HideAllSprites( void ) {
    __wstart( RAM_SPR );             // Hide all sprites
    for( int i = 0; i < 512; i++ ) {
        xhide();
    }
    __end();
}