Arduino Forum

Community => Exhibition / Gallery => Topic started by: ph77 on Nov 08, 2013, 06:10 pm

Title: Toorum's Quest II - ATmega328P based retro video game with 256 color graphics
Post by: ph77 on Nov 08, 2013, 06:10 pm
Hi!

EDIT: new video with music and sound effects!

http://www.youtube.com/watch?v=sLvgW_zb6bQ

Visit my blog at http://petenpaja.blogspot.fi for schematic, source code and technical info!

---


I'm finally ready to show you a project I've been working on and off for several months. It's a 8-bit retro video game based on Arduino and ATmega328P. The project is not yet finished -- I'm working on music playback which is still missing on the video.

Attached images: titlescreen, arduino based proto version, final standalone hardware.

Features:

Tile graphics mode with sprites. Up to three sprites per scanline, unlimited number of sprites vertically. Display resolution 104x80 with 256 colors. NES controller support. 4 audio channels with triangle, pulse, sawtooth and noise waveforms.

Music is still work in progress and not present in this early video footage.

Video signal is generated by the microcontroller by outputting 8-bit RGB values. The program has been heavily optimized and written in assembler, so that the ATmega328 outputs a new pixel exactly every 6th clock cycle. RGB values are converted to NTSC composite signal by AD725 chip.

Audio is generated in software by mixing 4 waveforms together. This should allow C64 SID quality music once the playroutine is finalized and music is composed.

The game is fully playable and has 15 rooms.

Atmega328P has only so many bytes of memory, so several tricks are needed to squeeze everything into memory. For example room data is compressed in flash and inactive rooms use only 1 byte of RAM to store the state of objects when the player is not around.

I'll probably do a full write up with schematics when music is done if people are interested in this.

Credits:

Hardware & software by Petri Häkkinen
Graphics tiles by Antti Tiihonen
Titlescreen by Juho Salila
Title: Re: Toorum's Quest II - ATmega328P based retro video game with 256 color graphics
Post by: janost on Nov 08, 2013, 08:07 pm
Nice :)
Title: Re: Toorum's Quest II - ATmega328P based retro video game with 256 color graphics
Post by: ph77 on Nov 08, 2013, 08:12 pm
Thanks! I noticed you're working on something similar. It's interesting to compare different approaches to video signal generation :)
Title: Re: Toorum's Quest II - ATmega328P based retro video game with 256 color graphics
Post by: janost on Nov 08, 2013, 08:24 pm
My work was aimed at making the screen work for my VIC-20/C64 emulator but turned out to be a better TVout solution :)
Still going to use it for my emulator even if it will be released as a library.

I have looked into overclocking the ATmega8 to 32.2MHz for generating NTSC color straight without addon circuits.
It is possible with 32MIPS.
Title: Re: Toorum's Quest II - ATmega328P based retro video game with 256 color graphics
Post by: ph77 on Nov 08, 2013, 08:39 pm
You don't need 32 Mhz for that. Linus Åkesson did it with 17.73447 MHz :)

Anyway, getting control of colors is difficult with bitbanging because it's impossible to finetune the necessary frequencies. One of the reason why I decided to use the AD725 chip.

Overclocking is an interesting subject because it makes it possible to have higher resolutions.
Title: Re: Toorum's Quest II - ATmega328P based retro video game with 256 color graphics
Post by: nickgammon on Nov 08, 2013, 11:43 pm
Very interesting. I've ordered some AD725 chips to try to do something like this.

Can you release the code please? I'd be interested to see how you got the video and sound throughput, plus game logic, in what is probably a tight amount of time.
Title: Re: Toorum's Quest II - ATmega328P based retro video game with 256 color graphics
Post by: fungus on Nov 09, 2013, 12:25 am

I'm finally ready to show you a project I've been working on and off for several months. It's a 8-bit retro video game based on Arduino and ATmega328P. The project is not yet finished -- I'm working on music playback which is still missing on the video.


Impressive...!
Title: Re: Toorum's Quest II - ATmega328P based retro video game with 256 color graphics
Post by: nickgammon on Nov 09, 2013, 12:56 am
How did you generate the 4FSC Clock Input at 14.318180 MHz? I see from the video you appear to have an oscillator on board. Is that all that is required, or is there more to it than that?

Would a simple 14.318 MHz crystal do? Or not? There seem to be plenty of those on eBay for like $10 for 100 of them.
Title: Re: Toorum's Quest II - ATmega328P based retro video game with 256 color graphics
Post by: ph77 on Nov 09, 2013, 12:18 pm
Thanks for the interest and kind words! They make the endless hours spent on the project worthwhile :)

Nick, a crystal can't directly produce the needed frequency for the AD725. The chip needs a strong (buffered) clock signal. The AD725 datasheet has a reference schematic for the oscillator, or you can simply use a crystal oscillator like I did, although they are more expensive and maybe harder to find.

Sure I can release the source code. Just give me a few days to clean up the code and add the playback routine. The code is in a pretty messy state because of many optimizations and because I wanted to release the video as soon as possible.

Here's a few things worth mentioning to maybe get you an idea what's going on:

The hardest part was getting sprites to work. I had to painfully cycle count the scanline routine so that it fetches tile data and masks sprites on top of the scanline while outputting a pixel every 6 cycles. After pulling in tile indices from RAM and tile graphics from ROM, there is hardly any time left to do sprites...

Audio is double buffered, so that at the start of each scanline video generation routine pulls a byte from an audio buffer. An assembly routine mixes 4 audio channels and fills up another buffer during vblank. The buffers are swapped at vsync. Timing needs to be precise, otherwise pops and clicks can be heard.

Audio mix + game logic takes around 40 scanlines so it just fits to the vblank period. There is hardly any cycles left during screen refresh.
Title: Re: Toorum's Quest II - ATmega328P based retro video game with 256 color graphics
Post by: RobvdVeer on Nov 09, 2013, 12:44 pm
I'm very much impressed.

Still its magical what they did in the 80's with C64, only 1mhz (with the sid chip of course).
Title: Re: Toorum's Quest II - ATmega328P based retro video game with 256 color graphics
Post by: fungus on Nov 09, 2013, 01:58 pm

There is hardly any cycles left during screen refresh.


Are there any left at all? Surely at some point it's better to just take over completely. The cycles spent responding to interrupts and saving/restoring state could be used for audio mixing, etc.
Title: Re: Toorum's Quest II - ATmega328P based retro video game with 256 color graphics
Post by: ph77 on Nov 09, 2013, 02:39 pm

Still its magical what they did in the 80's with C64, only 1mhz (with the sid chip of course).

C64 also had a dedicated graphics chip, the VIC-II, which has 8 hardware sprites, for instance. The 6510 CPU alone is hardly powerful enough to produce a NTSC/PAL video signal.
Title: Re: Toorum's Quest II - ATmega328P based retro video game with 256 color graphics
Post by: ph77 on Nov 09, 2013, 02:43 pm


There is hardly any cycles left during screen refresh.

Are there any left at all? Surely at some point it's better to just take over completely. The cycles spent responding to interrupts and saving/restoring state could be used for audio mixing, etc.

Yes, I have thought about this idea, to output the video signal directly without interrupts. But then *everything* has to be timed to the video signal and it becomes a huge PITA. I agree that to get the last few cycles out of the MCU it's the only way...
Title: Re: Toorum's Quest II - ATmega328P based retro video game with 256 color graphics
Post by: janost on Nov 09, 2013, 03:00 pm
Its better to squeez all cycles out if during the active lines and run the game updates during inactive lines.
In my videoblaster it uses all of the CPU when outputing pixels on 200 lines and and nothing during 112 lines.

That equals to an AVR running at 6MHz and that is fast comparing to 6502s.
Title: Re: Toorum's Quest II - ATmega328P based retro video game with 256 color graphics
Post by: fungus on Nov 09, 2013, 05:23 pm

That equals to an AVR running at 6MHz and that is fast comparing to 6502s.


Probably equivalent to a 12MHz 6502.
Title: Re: Toorum's Quest II - ATmega328P based retro video game with 256 color graphics
Post by: nickgammon on Nov 09, 2013, 09:24 pm

Nick, a crystal can't directly produce the needed frequency for the AD725. The chip needs a strong (buffered) clock signal. The AD725 datasheet has a reference schematic for the oscillator, or you can simply use a crystal oscillator like I did, although they are more expensive and maybe harder to find.


Ah yes, I see it now. Actually I had an idea that a crystal could be used by simply hooking it up to an AVR chip (hopefully a small one like an Attiny45) and then setting the CLKOUT fuse. That simply take the clock an outputs it on one of the pins. You wouldn't need a sketch running, simply for the processor to be active. Although if I wanted PAL output (which we use in Australia) I could simply clock the Atmega328 at 17.734475 MHz from the crystal, set the CLKOUT fuse, and connect that directly to the AD725. That way the main processor runs a bit faster than usual and I get the clock signal as well.

BTW I found 100 x crystals from eBay for $10, so I thought that was nice and cheap. :) We'll see if they actually work. :P

I remember sprites from the C64, my GPascal compiler had various supporting functions for them. You set up the bitmap, location, etc. and the chip did the rest. It also reported collisions, which I will be interested to see how you handled.

I am impressed by the fact that even though you say you can handle 3 sprites per scan line, the images you posted usually look "busier" than that. It's quite impressive how there can be a lot happening on the screen, with the minimal hardware you used.
Title: Re: Toorum's Quest II - ATmega328P based retro video game with 256 color graphics
Post by: ph77 on Nov 09, 2013, 10:00 pm

Although if I wanted PAL output (which we use in Australia) I could simply clock the Atmega328 at 17.734475 MHz from the crystal, set the CLKOUT fuse, and connect that directly to the AD725. That way the main processor runs a bit faster than usual and I get the clock signal as well.

Good idea! That should work. Just make sure that you can generate frequencies close enough to the needed vertical and horizontal syncs.

btw. we use PAL here in Finland too, but TVs and monitors these days seem to accept PAL and NTSC.


I remember sprites from the C64, my GPascal compiler had various supporting functions for them. You set up the bitmap, location, etc. and the chip did the rest. It also reported collisions, which I will be interested to see how you handled.


Collisions are handled by the game logic. I simply check if the bounding rectangle of the player collides with the bounding rectangle of the enemies.


I am impressed by the fact that even though you say you can handle 3 sprites per scan line, the images you posted usually look "busier" than that. It's quite impressive how there can be a lot happening on the screen, with the minimal hardware you used.


Yes, there are a few tricks at play :) There can only be three sprites per scanline but I do multiplexing so that I have different set of three sprites per scanline. There can be virtually any number of sprites on the screen vertically. Also, collectable items like gold and hearts are technically background tiles. I just animate the tiles, i.e. swap their tile pointers in RAM. I divide the screen vertically to regions and scan one region each frame. If the tile is a heart or gold I update its pointer. This way updating the tiles is quite efficient.

Title: Re: Toorum's Quest II - ATmega328P based retro video game with 256 color graphics
Post by: janost on Nov 09, 2013, 10:07 pm
The mistake you did, Nick, with your 17cycles and the 9th bit was not the hardware but not checking your software.

A 16MHz AVR can do a heck of a lot more than displaying 20char/per line VGA.
Title: Re: Toorum's Quest II - ATmega328P based retro video game with 256 color graphics
Post by: fungus on Nov 09, 2013, 10:38 pm

Yes, there are a few tricks at play :) There can only be three sprites per scanline but I do multiplexing so that I have different set of three sprites per scanline. There can be virtually any number of sprites on the screen vertically. Also, collectable items like gold and hearts are technically background tiles. I just animate the tiles, i.e. swap their tile pointers in RAM. I divide the screen vertically to regions and scan one region each frame. If the tile is a heart or gold I update its pointer. This way updating the tiles is quite efficient.



Does it render directly from tiles? (ie. no charmap...)
Title: Re: Toorum's Quest II - ATmega328P based retro video game with 256 color graphics
Post by: nickgammon on Nov 10, 2013, 02:51 am

The mistake you did, Nick, with your 17cycles and the 9th bit was not the hardware but not checking your software.

A 16MHz AVR can do a heck of a lot more than displaying 20char/per line VGA.


I would be interested to hear how, excluding external hardware, given that 20 characters is 160 pixels (at 8 pixels per character).

According to my calculations as described here (http://www.gammon.com.au/forum/?id=11608) you have 31.74 µS for each horizontal scan line (using 525 lines at 60 Hz).

Code: [Select]

(1/60) / 525 * 1e6 = 31.74 uS


Divide that by 800 pixels for one line including the pulse width (96 pixels) the back porch (48 pixels) and the front porch (16 pixels).

Code: [Select]

((1/60) / 525 * 1e9) / 800 = 39.68  nS


So that is 39.68 nS per pixel.

Now clearly we can't clock out a pixel every 39.68 nS with a CPU clocking at 62.5 nS per clock pulse.

You can't clock out a pixel in a single clock cycle (I don't think, unless you clock out a fixed value), so you need two clock cycles for the SPI hardware to do it. Now the closest you get then is:

Code: [Select]
125 / 39.68 = 3.15

So, rounding up, four "VGA" pixels in that time. That is, each pixel is stretched 4 x horizontally.

So if you can demonstrate where my calculations are wrong, and you can send "a heck of a lot more" I would be pleased to hear it.
Title: Re: Toorum's Quest II - ATmega328P based retro video game with 256 color graphics
Post by: nickgammon on Nov 10, 2013, 06:38 am

The hardest part was getting sprites to work. I had to painfully cycle count the scanline routine so that it fetches tile data and masks sprites on top of the scanline while outputting a pixel every 6 cycles.


I've been trying to guess your timing figures, and from the quoted 104 horizontal resolution, and the NTSC standard of 51.5 µS for the visible portion of the line I am estimating that you have 8 clock cycles per pixel:

Code: [Select]

8 * 62.5 * 104 = 52000 nS


Does that sound right? It can't, of course, because you said a pixel every 6 clock cycles, so where did I go wrong?
Title: Re: Toorum's Quest II - ATmega328P based retro video game with 256 color graphics
Post by: cjdelphi on Nov 10, 2013, 06:51 am
I thought I'd do quick search on the rgb / ntsc chip...

http://belogic.com/uzebox/index.asp

It seems there's quite a lot going on!
Title: Re: Toorum's Quest II - ATmega328P based retro video game with 256 color graphics
Post by: ph77 on Nov 10, 2013, 08:13 am

Does it render directly from tiles? (ie. no charmap...)

I have a 13x10 buffer of tile pointers in RAM. Each entry in the buffer points to the start of a tile in ROM. Storing addresses rather than tile indices is much faster..
Title: Re: Toorum's Quest II - ATmega328P based retro video game with 256 color graphics
Post by: ph77 on Nov 10, 2013, 08:25 am

I've been trying to guess your timing figures, and from the quoted 104 horizontal resolution, and the NTSC standard of 51.5 µS for the visible portion of the line I am estimating that you have 8 clock cycles per pixel:
Code: [Select]

8 * 62.5 * 104 = 52000 nS

Does that sound right? It can't, of course, because you said a pixel every 6 clock cycles, so where did I go wrong?


I'm not filling the entire scanline with graphics. I output 104 pixels, 1 pixel per 6 cycles. That leaves time just enough time for processing sprites etc. In the 80s they did the same trick and called the longer horizontal blank "borders" :)

Also, one consideration is that using 8 cycles per pixel vs. 6 cycles per pixel results in blockier graphics, which I wanted to avoid. With 6 cycles and doubled scanlines, the pixels are closer to being squares rather than wide rectangles.

Note that the actual implementation is much more complex than this: there is actually three "threads" of execution going on on each scanline. One thread does the background tiles, one thread blends sprites on top of the tiles, and one thread outputs the pixels. Because I have to output a pixel every 6th cycle, the threads have to be interleaved.
Title: Re: Toorum's Quest II - ATmega328P based retro video game with 256 color graphics
Post by: ph77 on Nov 10, 2013, 08:30 am

I thought I'd do quick search on the rgb / ntsc chip...
http://belogic.com/uzebox/index.asp
It seems there's quite a lot going on!


Uzebox is an impressive feat indeed, but they also use a more powerful microcontroller with double amount of RAM and ROM, and almost twice the clock frequency.  My project was based on Arduino UNO. We both use the same AD725 chip for RGB -> NTSC though.
Title: Re: Toorum's Quest II - ATmega328P based retro video game with 256 color graphics
Post by: fungus on Nov 10, 2013, 08:56 pm

Uzebox is an impressive feat indeed


Yep. I hadn't seen those before. They look ideal for a project I'm thinking about (I need 240x224 graphics for it) but they're really really expensive. $74 for a kit? Ouch!

I can get two Raspberry Pis +change for that (or even an Arduino Uno+Gameduino).
Title: Re: Toorum's Quest II - ATmega328P based retro video game with 256 color graphics
Post by: ph77 on Nov 23, 2013, 10:24 pm
New version with music and sound effects!
http://www.youtube.com/watch?v=sLvgW_zb6bQ

I also wrote a technical writeup and released the source code:
http://petenpaja.blogspot.fi

I'll happily answer any questions about the design or source code.
Title: Re: Toorum's Quest II - ATmega328P based retro video game with 256 color graphics
Post by: ph77 on Nov 27, 2013, 11:38 am
I know that at least Nick was interested to see the source code, so I'm bumping this one time in case the update was unnoticed.
Title: Re: Toorum's Quest II - ATmega328P based retro video game with 256 color graphics
Post by: janost on Nov 29, 2013, 09:14 am

So if you can demonstrate where my calculations are wrong, and you can send "a heck of a lot more" I would be pleased to hear it.


A VGA line is 256pixels long using an 8MHz pixelclock.
That is 32characters minus a few for sync and porch.

24 or 25 char per line should be possible.
It's not "a heck of alot more" but reaching Arcade Graphics level.
Title: Re: Toorum's Quest II - ATmega328P based retro video game with 256 color graphics
Post by: fungus on Nov 29, 2013, 12:20 pm
I just saw this on Hackaday. Well done.
Title: Re: Toorum's Quest II - ATmega328P based retro video game with 256 color graphics
Post by: nickgammon on Nov 30, 2013, 03:38 am

I know that at least Nick was interested to see the source code, so I'm bumping this one time in case the update was unnoticed.


I just got my AD725 chip in the mail yesterday so I'll try to get your demo working. Thanks for all the info.
Title: Re: Toorum's Quest II - ATmega328P based retro video game with 256 color graphics
Post by: nickgammon on Nov 30, 2013, 06:29 am
OK, I got that to work more-or-less. Proof:

(http://www.gammon.com.au/images/Arduino/Arduino_forum_197983.jpg)

(http://www.gammon.com.au/images/Arduino/Arduino_forum_197983b.jpg)

The screen is slightly noisy because I had a long cable run to the TV and also assembled it on a breadboard. One slight snag, I don't have an NES controller so I can't actually move my character around. I'll order one from eBay, but what sort do I want exactly? Just a classic NES controller?

Errata:



By the way, I didn't have a 14.31818 MHz oscillator (waiting on a delivery) so I used the 17.734475 MHz one which had arrived. I tied pin 1 to Gnd rather than +5V (to indicate PAL) and it works fine.

I haven't tested the sound yet.

It's ultra cool however. I'm really impressed you managed to squeeze this sort of performance out of it. Once I get my controller I'll be able to give it a real test.
Title: Re: Toorum's Quest II - ATmega328P based retro video game with 256 color graphics
Post by: nickgammon on Nov 30, 2013, 07:08 am
Got the sound working, that sounds good. Maybe I can make an NES emulator with a Wii nunchuk. Hmm, I wonder what the NES protocol is? I could have a second Arduino reading the nunchuk and outputting the appropriate serial stream.

Hmm, a bit of Google-fu seems to indicate that the emulator needs to respond to a /LATCH and then respond with 8 bits upon receiving a clock signal. An SPI slave configuration might achieve that quite nicely.

Oh well, that might be tomorrow's project. :)
Title: Re: Toorum's Quest II - ATmega328P based retro video game with 256 color graphics
Post by: ph77 on Nov 30, 2013, 08:35 am
Wow, you got it running already! That was fast! To my knowledge you're the first one.

It's hard to say from the photo but it looks like the colors are somehow wrong, too much red in highlights. Maybe the color signals are wired incorrectly or maybe the resistor values are inaccurate. Or maybe it's just the photo? Also, please change aspect ratio of your TV to 4:3, it looks much better that way.

About the image quality in general. I couldn't get a high quality video signal until I built it on PCB. On PCB the signal is very clean. I guess the breadboard and all the wires cause too much interference.

Yes, the project uses a standard NES controller (not SNES). The NES controller has a 8-bit shift register, so it's a matter of reading the bits one by one. See gamepad.cpp for details.

Thank you for the corrections. I will update the schematic.
Title: Re: Toorum's Quest II - ATmega328P based retro video game with 256 color graphics
Post by: ph77 on Nov 30, 2013, 08:52 am
Oh, I just realized that you're running the  AD725 in PAL mode but the video signal is synced to NTSC. Your TV is probably confused about this and tries to interpret the colors as if it were receiving a NTSC signal? This might be the culprit for the strange colors… or maybe not, I would expect the colors to be totally off...
Title: Re: Toorum's Quest II - ATmega328P based retro video game with 256 color graphics
Post by: nickgammon on Nov 30, 2013, 09:13 am
Quote

It's hard to say from the photo but it looks like the colors are somehow wrong, too much red in highlights.


Well, I have *cough* not put in all the resistors yet. I was testing to make sure it worked. I haven't put in the 3k ones. I note that you only have 2 x 3k resistors, and therefore the blue signal won't be quite the same as the red and green ones (no doubt so you could output everything through PORTD).

Quote

Oh, I just realized that you're running the  AD725 in PAL mode but the video signal is synced to NTSC.


I was pleasantly surprised that it worked at all. I expected to have to wade through the code and made modifications to allow for the different pixel rate.

Quote

I couldn't get a high quality video signal until I built it on PCB.


I must confess that my PCB building skills are almost non-existent. I managed to make once a while back but couldn't drill the holes into it in any sort of straight line.

Quote

The NES controller has a 8-bit shift register, so it's a matter of reading the bits one by one. See gamepad.cpp for details.


My controller emulator is not exactly working, I am debugging that right now.
Title: Re: Toorum's Quest II - ATmega328P based retro video game with 256 color graphics
Post by: ph77 on Nov 30, 2013, 09:34 am

Well, I have *cough* not put in all the resistors yet. I was testing to make sure it worked. I haven't put in the 3k ones. I note that you only have 2 x 3k resistors, and therefore the blue signal won't be quite the same as the red and green ones (no doubt so you could output everything through PORTD).


Oh, that explains it :)

Blue has only 2 bits so that colors fit into 8 bits -- the human eye is least responsive to blue, so that's why red and green have more bits.

btw. the values of resistors are critical to get linear distribution of color bits. Resistors values are 806, 1.58K and 3.16K. Each value is approximately x2 the previous one. You can use other values as long as they follow the same pattern: x1, x2, x4.
Title: Re: Toorum's Quest II - ATmega328P based retro video game with 256 color graphics
Post by: nickgammon on Nov 30, 2013, 11:38 pm
Right, I made a NES controller emulator using a Wii nunchuk. The protocol was a tiny bit obscure (one latch pulse and seven clock pulses) but I got there. For timing reasons I made a tight loop where it waited for latch, and then clocked out the 8 values. Then in the 1/60th of a second I should have available I read the nunchuk ready for next time.

Code: [Select]

// NES controller emulator using Wii nunchuk
// Author: Nick Gammon
// Date:   1st December 2013

#include <Nunchuk.h>
#include <Wire.h>

const byte JOYSTICK_LOW_THESHOLD = 100;
const byte JOYSTICK_HIGH_THESHOLD = 200;

void setup ()
{
 // don't have bogus initial data
 pinMode (12, INPUT_PULLUP);
 
 // initialize nunchuk
 Nunchuk::begin ();
 // first read
 Nunchuk::read ();
 
}  // end of setup

byte reply [8]; // A, B, SELECT, START, UP, DOWN, LEFT, RIGHT

void loop ()
{
 reply [0] = Nunchuk::z_button;  // A
 reply [1] = Nunchuk::c_button;  // B
 reply [2] = 0;   // SELECT  ??
 reply [3] = Nunchuk::c_button && Nunchuk::z_button;  // START (both Z and C buttons together)
 reply [4] = Nunchuk::joy_y_axis > JOYSTICK_HIGH_THESHOLD;  // UP
 reply [5] = Nunchuk::joy_y_axis < JOYSTICK_LOW_THESHOLD;   // DOWN
 reply [6] = Nunchuk::joy_x_axis < JOYSTICK_LOW_THESHOLD;   // LEFT
 reply [7] = Nunchuk::joy_x_axis > JOYSTICK_HIGH_THESHOLD;  // RIGHT
 
  noInterrupts ();

 // wait for LATCH (pin 10) to go high
 while ((PINB & bit(2)) == 0)
   { }
   
 PORTB |= bit (4); // start off with HIGH output
 DDRB |= bit (4);  // set MISO (pin 12) to output
 
 // wait for LATCH (pin 10) to go low again
 while (PINB & bit(2))
   { }

 // After LATCH we immediately output the first bit
 
 // set MISO (pin 12) to appropriate value for the "A" button
 if (reply [0])
   PORTB &= ~bit (4);
 else
   PORTB |= bit (4);

 // do 7 more data pulses
 for (byte i = 1; i < 8; i++)
   {
   // wait for CLOCK (pin 13) to go high
   while ((PINB & bit(5)) == 0)
     { }
     
   // set MISO (pin 12) to appropriate value
   if (reply [i])
     PORTB &= ~bit (4);
   else
     PORTB |= bit (4);

   // wait for CLOCK (pin 13) to go low
   while (PINB & bit(5))
     { }
   }  // end of 8 pulses

 PORTB |= bit (4); // end off with HIGH output
 DDRB &= ~bit (4);  // set MISO (pin 12) to input
 
  interrupts ();

 // read for next time around
 Nunchuk::read ();
}  // end of loop


(http://www.gammon.com.au/images/Arduino/Arduino_forum_197983e.jpg)

With the assistance of that I was able to play the game. Now I'll take a look at how the code works. :)
Title: Re: Toorum's Quest II - ATmega328P based retro video game with 256 color graphics
Post by: nickgammon on Dec 01, 2013, 12:10 am
Once again, I think this is an incredible feat of code optimization to fit all this into an Atmega328P.

Not only do you have 256-colour output, but also sound, an introductory screen, and explanatory text. It runs on both NTSC and PAL, as I proved. It also interfaces with the NES controller, so you can have A, B, SELECT, START, UP, DOWN, LEFT, and RIGHT buttons.

The output is jitter free, I personally have a bit of noise but that would be from the breadboard, and the fact that there is no shielding.

The code just fits:

Code: [Select]

Binary sketch size: 31,986 bytes (of a 32,256 byte maximum)


If you ran it on a larger processor like the Atmega1280 (for example the Bobuino, or just the bare chip, which is available in DIP format) you would have access to a lot more program memory (128 kB) which would allow for a lot more sprites, rooms, game logic etc.

It would be nice if you could document the room data layout. A lot of us (including me) would find it challenging to modify or improve the code, but no doubt would have fun adding extra rooms or changing the layout.

If this sort of stuff was documented:

Code: [Select]

const PROGMEM prog_uchar rooms[] = {
0x10,0xc1,0x10,0xc1,0x10,0xc1,0x10,0xc1,0x10,0xc2,0x10,0x11,0x13,0x10,0x51,0x10,0x31,0x10,0x14,0x15,
0x10,0x51,0x10,0x31,0x10,0x14,0x12,0x10,0x11,0x16,0x31,0x17,0x31,0x10,0x14,0x20,0x92,0xf1,0x61,0x18,
0x91,0x32,0x91,0x12,0x10,0x15,0x61,0x42,0x20,0x72,0x51,0x20,0xb1,0x10,0x21,0x18,0x19,0x61,0x14,0x11,
0x10,0x11,0x15,0x51,0x32,0x14,0x12,0x10,0x72,0xf1,0xf1,0xf1,0x71,0x52,0x11,0x42,0x11,0x22,0x31,0x20,
0x11,0x30,0x31,0x10,0x81,0x10,0x11,0x12,0x11,0x10,0x41,0x3a,0x51,0x10,0xa2,0x14,0x12,0x10,0xc1,0x10,
...


That would be great! And how did you draw the graphics? I can imagine using Photoshop (or similar) in indexed colour mode, and outputting raw data, to draw tiles and suchlike.
Title: Re: Toorum's Quest II - ATmega328P based retro video game with 256 color graphics
Post by: nickgammon on Dec 01, 2013, 04:31 am
I've managed to deduce a bit of the dungeon layout.

First, the room directions:

Code: [Select]

const PROGMEM prog_uchar roomadj[] = {

//  Left  Right   Up  Down      Room
     0,   1,    0,    4,    //   0  
     0,   2, 0xFF,    5,    //   1  
     1,   3,    0,    6,    //   2  
     2,   0,    0,    7,    //   3  
     0,   5,    0,    9,    //   4  
     4,   6,    1,   10,    //   5  
     5,   7,    2,   11,    //   6  
     6,   8,    3,   12,    //   7  
     7,   0,    0,   13,    //   8  
     0,  10,    4,    0,    //   9  
     9,  11,    5,    0,    //  10  
    10,  12,    6,    0,    //  11  
    11,  13,    7,    0,    //  12  
    12,  14,    8,    0,    //  13  
    13,   0,    0,    0,    //  14  
 };

/*
Room layout:

  0  1  2  3
  4  5  6  7  8
  9 10 11 12 13 14
 
*/


Next the room encoding. Let's use this to make it easier:

Code: [Select]


const PROGMEM prog_uchar roomNibbleToByte[] = {
 TILE_WALL_DARK,
 TILE_EMPTY,
 TILE_WALL,
 TILE_KEY,
 TILE_LADDER,
 TILE_GOLD,
 TILE_PRINCESS,
 TILE_DOOR,
 TILE_WYVERN,
 TILE_WYVERN_2ND,
 TILE_SPIKES,
 TILE_GHOST_RIGHT,
 TILE_GHOST_LEFT,
 TILE_GHOST_LEFT_2ND,
 TILE_HEART,
};


So for example:

Code: [Select]

const PROGMEM prog_uchar rooms[] = {
0x10,0xc1,0x10


That is:

Code: [Select]

1 x Dark tile
12 x empty tiles
1 x Dark tile


Decoding the room layout gives this:

Code: [Select]

Room 0

|
|
|
|
| - - - - - - - - - - - -
|   K |           |
| = * |           |
| = - |   P       #
| = | | - - - - - - - - -




Room 1


               W
         - - -
       - | *
- - - - | | - - - - - - -
         | |
         |     W w
     =   |   *
- - - = - | - - - - - - -




Room 2





- - - - -   - - - -   - -
     | |   | | |       |
               |   -   |
       ! ! !           |
- - - - - - - - - - = - |
                       |



Room 3

                       |
                       |
                       |
               G   *   |
- - - - - - - - - - - - |
| | | | | | | | | | | | |
| | | | | | | | | | | | |
| | | | | | | | | | | | |
| | | | | | | | | | | | |
| = | | | | | | | | | | |



Room 4

| = | | | | | | | | | | |
| =
| =
| =     g           w
| =   - - - w   -
| =     |             - -
| =                   | |
| = g     ! ! ! !   = | |
| - - - - - - - - - = | |
| | | = | | | | | | | | |



Room 5

| | | = | | | | | | | | |
   | = |   | | | = | | |
   # = |         g   K |
   - - | w - = - - - - |
             = | *
-           - - | -
|   -             |   -
| z @   - G       | -
| - - - | - = - - | - - -
| | | | | | | | | | = | |



Room 6

| | | | | | | | | | = | |
|     * |           = | |
|     - | W         = | |
| -           - - - - | |
 | - - - -       | K   |
 |       #       | - = |
         - - -       = |
 -   G       = - - - - |
- | - - - - - = | | | | |
| | | | | | | | | | | | |



Room 7

| | | | | | | | | | | | |
|
| W   *
|     -                 -
| -           -       - |
|       G             | |
|   - - - -       - - | |
|   # = | K   !   * | | |
| - - = | - - - - - | | |
| | | | | | | | | | | | |



Room 8

| | | | | | | | | | | | |
             |         |
             #       - |
-   - - W - - - - - = | |
|                   = | |
|         - = -     =   |
|       * | = | -   =   |
| ! ! ! - | = | | g = K |
| - - - | | = | | - - - |
| | | | | | | | | | = | |



Room 9

| | | | | | | | | | = | |
|                 | = #
|                   - -
|           -
|     W       -         -
| K     -   * |       - |
| - -   | ! - |   -   | |
| | | ! | - | | ! | ! | |
| | | - | | | | - | - | |
| | | | | | = | | | | | |



Room 10

| | | | | | = | | | | | |
         | = * |       |
         | = - |       |
                 W     |
- - -
| G
| - - -           - - - -
| | |     ! ! !   g   | |
| | | - - - - - - - - | |
| | | | | | | = | | | | |



Room 11

| | | | | | | = | | | | |
|       | | | =       K
| *           G       -
| - w - - = - -       | -
 |       =
 #       g     ! !
- -     - - -   - - -
| @           !
| - - - - - - - - - - - -
| | | = | | | | | |



Room 12

| | | = | | | | | |
     = | | | | | | - - -
   - -                 |
- - |                   |

       -           w
     - | W   - -     -
   - | * ! ! ! ! ! !
- - | | - - - - - - - - -
| | | | | | = | | | | | |



Room 13

| | | | | | = | | | | | |
| K | | | | = | | |     #
|   g       =           -
| - - - - - - - - - = - |
     |             = | |
     | * W   w     = | |
     | -   -   -   = | |
                   = | |
- - - - - - - - - - - | |
| | | | | | | | | | | | |



Room 14

| | | | | | | | | | | | |
                 | | | |
-                 | | | |
|     - - W     @ | | | |
|   - | |       - | | | |
|         g   *   | | | |
| - - - - - - - - | | | |
| | | | | | | | | | | | |
| | | | | | | | | | | | |
g g g g g g g | | z z G G


Using the following legend:

Code: [Select]

WALL_DARK =      |
EMPTY =         
WALL =           _
KEY =            K
LADDER =         =
GOLD =           *
PRINCESS =       P
DOOR =           #
WYVERN =         W
WYVERN_2ND =     w
SPIKES =         !
GHOST_RIGHT =    G
GHOST_LEFT =     g
GHOST_LEFT_2ND = z
HEART =          @
Title: Re: Toorum's Quest II - ATmega328P based retro video game with 256 color graphics
Post by: nickgammon on Dec 01, 2013, 04:42 am
And now put it all together:

Code: [Select]


|                                                                                                     |
|                                         W                                                           |
|                                   - - -                                                             |
| Start                           - | *                                                       G   *   |
| - - - - - - - - - - - - - - - - | | - - - - - - - - - - - -   - - - -   - - - - - - - - - - - - - - |
|   K |           |                 | |                   | |   | | |       | | | | | | | | | | | | | |
| = * |           |                 |     W w                       |   -   | | | | | | | | | | | | | |
| = - |   P       #             =   |   *                   ! ! !           | | | | | | | | | | | | | |
| = | | - - - - - - - - - - - - = - | - - - - - - - - - - - - - - - - - = - | | | | | | | | | | | | | |
| = | | | | | | | | | | | | | | = | | | | | | | | | | | | | | | | | | | = | | | | | | | | | | | | | | | | | | | | | | | | | | | |           
| =                           | = |   | | | = | | | |     * |           = | | |                                       |         |
| =                           # = |         g   K | |     - | W         = | | | W   *                                 #       - |
| =     g           w         - - | w - = - - - - | | -           - - - - | | |     -                 - -   - - W - - - - - = | |
| =   - - - w   -                       = | *         | - - - -       | K   | | -           -       - | |                   = | |
| =     |             - - -           - - | -         |       #       | - = | |       G             | | |         - = -     =   |
| =                   | | |   -             |   -             - - -       = | |   - - - -       - - | | |       * | = | -   =   |
| = g     ! ! ! !   = | | | z @   - G       | -       -   G       = - - - - | |   # = | K   !   * | | | | ! ! ! - | = | | g = K |
| - - - - - - - - - = | | | - - - | - = - - | - - - - | - - - - - = | | | | | | - - = | - - - - - | | | | - - - | | = | | - - - |
| | | = | | | | | | | | | | | | | | | | | | | = | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | = | |
| | | | | | | | | | = | | | | | | | | = | | | | | | | | | | | | | = | | | | | | | | = | | | | | |       | | | | | | = | | | | | | | | | | | | | | | | | | |
|                 | = #             | = * |       | |       | | | =       K         = | | | | | | - - - | K | | | | = | | |     #                   | | | |
|                   - -             | = - |       | | *           G       -       - -                 | |   g       =           - -                 | | | |
|           -                               W     | | - w - - = - -       | - - - |                   | | - - - - - - - - - = - | |     - - W     @ | | | |
|     W       -         - - - -                       |       =                                               |             = | | |   - | |       - | | | |
| K     -   * |       - | | G                         #       g     ! !               -           w           | * W   w     = | | |         g   *   | | | |
| - -   | ! - |   -   | | | - - -           - - - - - -     - - -   - - -           - | W   - -     -         | -   -   -   = | | | - - - - - - - - | | | |
| | | ! | - | | ! | ! | | | | |     ! ! !   g   | | | @           !               - | * ! ! ! ! ! !                         = | | | | | | | | | | | | | | |
| | | - | | | | - | - | | | | | - - - - - - - - | | | - - - - - - - - - - - - - - | | - - - - - - - - - - - - - - - - - - - - | | | | | | | | | | | | | | |
| | | | | | = | | | | | | | | | | | | | = | | | | | | | | = | | | | | |       | | | | | | = | | | | | | | | | | | | | | | | | | |
Title: Re: Toorum's Quest II - ATmega328P based retro video game with 256 color graphics
Post by: nickgammon on Dec 01, 2013, 05:04 am
More screenshots:

(http://www.gammon.com.au/images/Arduino/Arduino_forum_197983c.jpg)

(http://www.gammon.com.au/images/Arduino/Arduino_forum_197983d.jpg)

It looks better than that in real life. The camera tends to make the screen look washed out.
Title: Re: Toorum's Quest II - ATmega328P based retro video game with 256 color graphics
Post by: ph77 on Dec 01, 2013, 10:12 am
I was away for a few hours and you have already made a NES controller emulator and reverse engineered the room layout!  :smiley-eek:

Quote

If you ran it on a larger processor like the Atmega1280 (for example the Bobuino, or just the bare chip, which is available in DIP format) you would have access to a lot more program memory (128 kB) which would allow for a lot more sprites, rooms, game logic etc.

Sure. However, the idea was to see what could be done with the ATmega328P / Arduino Uno. It's always possible to throw more hardware at the problem, but it leads to a never ending loop… what comes next when the Atmega1280 is full? I think that limitations are ultimately good and bring out the creativity in us.

Also, it's possible to add more stuff to the game by using better compression schemes and optimizing the code further. For example, the titlescreen could be made to use the tiled graphics mode, so that the custom video mode for the titlescreen could be removed. This would free up almost 1KB. Also the titlescreen image alone takes 10KB (it's an uncompressed 128x80 bitmap). So making it smaller would free up memory to be used for rooms, sounds, whatever.

Quote
And how did you draw the graphics?

Graphics were made using Photoshop by my friend Antti. All tiles are contained in a single image. I made a Lua script which reads the file and writes out a C header file. The music was made, also by Antti, with a music tracker software I programmed.

I see you have already reverse engineered the room data. Well done! :) If you need more info on the format of the data or anything else, I'm happy to answer.

And thank you for looking into this and building the console!
Title: Re: Toorum's Quest II - ATmega328P based retro video game with 256 color graphics
Post by: nickgammon on Dec 01, 2013, 12:00 pm
Quote

I made a Lua script which reads the file and writes out a C header file.


Excellent choice. When I was playing with fonts and I needed to reverse rows/columns or do similar stuff I used Lua.

Quote

I think that limitations are ultimately good and bring out the creativity in us.


I agree in principle. The concept of solving slow execution by just getting a faster processor (or more RAM) means you aren't actually attempting to find better ways of using existing hardware.
Title: Re: Toorum's Quest II - ATmega328P based retro video game with 256 color graphics
Post by: JO3RI on Dec 20, 2013, 03:48 pm
This is really nicly done ! I would love to learn more on the music and sound part. Can we use your music software tracker? Do you have a music player for Arduino?

I ask this because we (TEAM a.r.g.) are creating 8-bit games for the Gamby shield http://logicalzero.com/gamby/ (http://logicalzero.com/gamby/) and the Video shield (http://www.wayneandlayne.com/projects/video-game-shield/) and are still struggling with the sound engine.

TEAM a.r.g. http://www.team-arg.org (http://www.team-arg.org)
Title: Re: Toorum's Quest II - ATmega328P based retro video game with 256 color graphics
Post by: ph77 on Jan 02, 2014, 10:28 am

This is really nicly done ! I would love to learn more on the music and sound part. Can we use your music software tracker? Do you have a music player for Arduino?


Thanks! The music playroutine is included in the sources. I synthesize and mix 4 waveforms together in audio.cpp. The waveforms supported are triangle, pulse (with variable pulse width), sawtooth and noise. Volumes are controlled with ADSR envelopes.

A four channel tracker controls the waveforms. Some basic channel effects are implemented, like arpeggios, portamento, vibrato and Hubbard style drum bits. The music playroutine can be found in playroutine.cpp.

Hope this helps! The code is under MIT license, so you can use it as long as you give me credits and include the copyright notice in your work.
Title: Re: Toorum's Quest II - ATmega328P based retro video game with 256 color graphics
Post by: mcnobby on Oct 29, 2014, 08:47 am
This is a BRILLIANT read !!

Thank you Nick for bringing this to my attention from another thread !

Petri, you are a genius !

This just shows me how poorly optimised my VGA application must be :(