Go Down

Topic: Toorum's Quest II - ATmega328P based retro video game with 256 color graphics (Read 23869 times) previous topic - next topic

nickgammon


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.
Please post technical questions on the forum, not by personal message. Thanks!

More info: http://www.gammon.com.au/electronics

ph77


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.


janost

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.

fungus


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...)
No, I don't answer questions sent in private messages (but I do accept thank-you notes...)

nickgammon


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 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.
Please post technical questions on the forum, not by personal message. Thanks!

More info: http://www.gammon.com.au/electronics

nickgammon


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?
Please post technical questions on the forum, not by personal message. Thanks!

More info: http://www.gammon.com.au/electronics

cjdelphi

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!

ph77


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

ph77


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.

ph77


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.

fungus


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).
No, I don't answer questions sent in private messages (but I do accept thank-you notes...)

ph77

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.

ph77

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.

janost


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.

fungus

No, I don't answer questions sent in private messages (but I do accept thank-you notes...)

Go Up