Electronic – How do devices like the Game Boy Advance achieve their frame rate

atmega1284pavrgraphicsoled

I've been designing my own handheld gaming device based around an AVR microcontroller and a small OLED display.

I started off with a monochrome display 128×64 pixels and can comfortably draw to it at over 60 frames per second.

I recently reworked it to use an RGB OLED, 128×128 pixels without really thinking too much only to find I could only achieve about 4 FPS. After some thought and careful refactoring I can get that up to ~12fps if I don't care too much about doing anything else!

My question is – how did a device like the GBA (Game Boy Advance) achieve a frame rate of nearly 60fps? I thought about having a separate 'graphics processor' but realised I would still be bottlenecked transferring the display data to that.

I also wondered about using the vestigial 8-bit parallel interface most of these screens tend to have, which might net me an 8x speed up, except that modern MCUs don't tend to have hardware parallel interfaces like they do for serial and bit-banging will likely eat up a lot of the speed gain.

What other options exist?

I'm currently using an ATmega1284P connected to an SSD1306 OLED controller via USART-SPI. That's the monochrome version.

The colour screen was an SSD1351, not originally connected to hardware SPI. I wasn't convinced it would make enough difference, it's just too slow overall

I know I can get faster MCUs, but I want to know what other options I could explore – the GBA processor is much slower than my 1284!

Best Answer

Other answers cover your question pretty well at an abstract level (hardware), but having actual experience with the GBA in particular I figured a more detailed explanation may be worth while.

The GBA had many drawing modes and settings which could be used to control how the graphics processor interpreted the video RAM, but one thing was inescapable: the frame rate. The graphic processor was drawing to the screen in a nearly (more on this below) constant loop. (This is likely the most relevant bit for your question.)

It would draw one line at a time taking a very short break between each. After drawing the last line for the frame it would take a break roughly equal to the time it takes to draw 30 lines. Then start again. The timing of each line, and the timing of each frame were all predetermined and set in stone. In a lot of ways the graphics processor was really the master of that system and you needed to write your games around its behavior, because it would continue doing what it did whether you were ready or not.

Roughly 75-80% of the time it was actively pushing to the screen. What frame rates could you accomplish if you were doing the same?

That 80% of the time was also what the CPU had to process user input, calculate game state, and load sprites/tiles to areas of VRAM that were currently off screen (or at least not included in the current line being drawn).

The 20% between frames, was all the CPU had to tweak video settings or RAM that would impact the whole next frame.

At the end of each line, the graphics processor would send a line sync interrupt to the CPU. This interrupt could be used to tweak settings on a few sprites, or a few background layers (this is how you can get an effect like a conical spotlight, by changing the size and location of one of the rectangular masks between each line drawn. As far as the hardware is concerned all those regions are rectangular.). You have to be careful to keep these updates small and finish before the graphic processor starts drawing the next line or you can get ugly results. Any time spent processing these interrupts also cut into that 80% of the CPU's processing time...

For games that got the most out of this system, neither the CPU nor the graphic processor ever took a real break; each were chasing the other around the loop updating what the other wasn't currently looking at.