This is an old revision of the document!


Project Name: Game Console (Game Boy Replica)

Introduction

What it does:

This project is a portable video game console featuring a minimalist hardware architecture. It allows users to play 8-bit style games loaded directly from a MicroSD card, which acts as a game cartridge.

Purpose:

The primary goal is to build a fully functional gaming system from scratch. I wanted to do something that I would enjoy using and that I could really use from time to time. I'm also hoping other people might be interested in this console and try it out.

Initial Idea:

The project is heavily inspired by classic 8-bit retro systems like the original Game Boy. I always enjoyed Nintendo games, especially the ones from the old retro consoles, and I always enjoyed emulating them on my phone to play. So, the idea was to recreate that nostalgic experience using accessible, modern microcontroller components.

Utility:

For others, this project serves as an example of simple embedded programming that could be replicated with cheap components. For me, it is an opportunity to deeply understand hardware-software interfacing, memory management, and timing optimization on AVR microcontrollers. The practical utility of the console is simply enjoying gaming and having fun.

General Description

The user interacts with the console via an analog XY joystick and 2 standard buttons. The microcontroller reads these inputs (using ADC for the joystick and GPIO for the buttons) and applies software debouncing.

The core of the system relies on a shared SPI bus. Because the microcontroller has limited RAM, the game logic and graphical assets are stored on the MicroSD card. The system uses a strict Chip Select multiplexing routine to read game data sectors from the SD card, process them, and immediately push the resulting pixel framebuffer to the Nokia 5110 LCD over the same SPI lines. Audio is handled concurrently via a hardware timer generating variable PWM signals sent to a passive piezo buzzer.

Component Name Qty Role
AVR Development Board (ATmega328P) 1 Main microcontroller, handles game logic and shared SPI bus
Nokia 5110 LCD Display 1 Renders game graphics via SPI
MicroSD Card Adapter Module 1 Acts as the cartridge reader for raw game binaries
Logic Level Converter (3.3V to 5V) 1 Protects the 3.3V display from 5V logic signals
XY Analog Joystick Module 1 Provides directional movement input (D-pad)
16mm Tactile Push Buttons 2 Action inputs (A and B)
Passive Piezo Buzzer Module 1 Synthesizes 8-bit sound effects using PWM
Breadboard & Jumper Wires 1 set Used for prototyping and physical hardware connections

That is a perfect correction! The Arduino IDE is the absolute classic tool for this, and it actually makes managing libraries a lot easier for a project like this.

Here is the updated documentation with the Development Environment section completely rewritten to reflect the Arduino IDE, how it handles files (like .ino), and how it manages dependencies.

You can copy and paste this directly into your documentation!

Software Design (Firmware)

Development Environment

The firmware for this console is developed using the Arduino IDE. This environment was chosen for its high accessibility, integrated Library Manager, and straightforward compilation process for AVR microcontrollers.

The project is structured around a primary .ino sketch file which contains the core state machine, the setup(), and the loop() functions. By leveraging the Arduino IDE's automatic prototype generation and tab system, the codebase is kept organized without the need for complex makefiles or manual dependency linking, allowing for rapid iteration of game logic and hardware testing.

3rd-Party Libraries and Sources

To avoid reinventing the wheel for low-level hardware protocols while maintaining performance, the following libraries (installed via the Arduino Library Manager) are utilized:

SPI.h (Standard AVR Library): Used for managing the hardware SPI bus. This is the backbone of the console, handling high-speed communication between the ATmega328P, the MicroSD card, and the Nokia 5110 LCD.

SD.h / SdFat.h: Used to interface with the MicroSD card adapter. SdFat is preferred for its smaller memory footprint and faster read speeds, allowing the console to pull game levels, sprites, and high scores efficiently.

Adafruit_GFX.h & Adafruit_PCD8544.h: These libraries handle the low-level communication with the Nokia 5110 display. They provide primitive drawing functions (pixels, lines, rectangles) and text rendering, which saves significant development time on the graphical engine.

Algorithms and Data Structures

1. The Game Loop & State Machine

The entire software architecture is governed by a Finite State Machine (FSM). The console operates in distinct states (e.g., STATE_MENU, STATE_SNAKE, STATE_TETRIS). The main loop constantly checks the current state and routes execution to the appropriate logic blocks. This ensures the CPU isn't wasting cycles rendering the menu while a game is actively being played.

2. The Framebuffer (Graphics Architecture)

Because the Nokia 5110 LCD does not allow reading data back from its screen memory, the console uses an internal Framebuffer. This is a 504-byte array (84×48 pixels) stored in the ATmega328P's SRAM.

Algorithm: During a frame, all graphic updates (moving characters, drawing walls, rotating Tetris blocks) are written to this RAM array mathematically using bitwise operations. Once the frame is fully calculated, the entire 504-byte array is blasted over the SPI bus to the screen in one continuous burst. This prevents “screen tearing” and flickering.

3. Non-Blocking Input & Debouncing

Using delay() is strictly forbidden in the game loop, as it would freeze the graphics and audio.

Algorithm: Button presses and joystick movements are handled using a non-blocking debouncing algorithm based on the millis() timer. The system records the timestamp of a physical voltage change on the GPIO pin and ignores further changes for a short window (e.g., ~120ms for Tetris movement) to prevent “phantom double-clicks” or excessively fast piece movement.

4. SPI Bus Multiplexing

Since both the LCD and the SD card share the exact same SCK, MOSI, and MISO wires, an algorithm controls the Chip Select (CS) pins. Before the microcontroller reads a level from the SD card, it forces the LCD's CS pin HIGH (deactivating it) and the SD card's CS pin LOW (activating it). It reverses this process to draw to the screen.

5. Collision Detection

For game physics, two distinct algorithms are used depending on the game state:

Axis-Aligned Bounding Box (AABB): Used in Snake to check if the X/Y coordinate boundaries of the snake head overlap with the walls or the apple grid locations.

Matrix Overlay Checking: Used in Tetris to mathematically project the 4×4 array of a falling block onto the 10×20 boolean game board array. If any active bits in the piece array overlap with an active bit on the board array or cross the boundary limits, a collision is flagged.

Implemented Sources and Functions

Below are the core functions that drive the hardware and the game engine:

Function Signature Role & Description
void setup() Initializes the UART for debugging, configures GPIO pin modes (INPUT_PULLUP for buttons, OUTPUT for CS pins), begins the SPI bus, and primes the random seed via analog noise.
void loop() Contains the if/else logic that routes CPU execution to runMenu(), runSnake(), or runTetris() based on the active state.
void readInput() Reads the analog values from the XY joystick via analogRead() and the digital states of the push buttons. Uses millis() to throttle input speed.
void updateGame() Contains the pure math and physics of the active game. Shifts arrays (Snake tail), rotates matrices (Tetris pieces), executes collision checks, and updates the score.
void drawGame() Clears the 504-byte framebuffer array, calculates the new pixel positions for all sprites (using setPixel), and sets the respective bits in the internal array.
void renderScreen() Selects the LCD via the CS pin and pushes the complete 504-byte framebuffer array over the SPI bus to physically update the glass.
void tone() Synthesizes retro audio using the Arduino's built-in hardware timer commands to generate a square wave PWM signal on the buzzer pin at specific frequencies.
void checkTetrisLines() Scans the 10×20 Tetris array for completed rows, shifts the above rows down in memory to simulate gravity, and increments the score multiplier.
pm/prj2026/bianca.popa1106/cristian.stefan1712.1779110595.txt.gz · Last modified: 2026/05/18 16:23 by cristian.stefan1712
CC Attribution-Share Alike 3.0 Unported
www.chimeric.de Valid CSS Driven by DokuWiki do yourself a favour and use a real browser - get firefox!! Recent changes RSS feed Valid XHTML 1.0