ABSTRACT
This report presents the design and implementation of a Space Shooter arcade game developed entirely in bare- metal C on the Texas Instruments TM4C123GH6PM (Tiva C) microcontroller. The game runs on a 320×240 SSD2119 LCD driven via SSI2, with player input from a 4×4 matrix keypad wired to the EduARM4 trainer board. The display is software-rotated 90◦ to give a portrait play area of 240×320 pixels. Features include five difficulty levels, a moving booster power-up with triple-shot capability, an animated starfield back- ground, explosion sparkle effects, a high-score system, and an aesthetic menu screen. The project demonstrates direct hardware register access, interrupt-driven timing, matrix scanning, selective pixel redraw, and modular game-state design without any operating system or graphics library.
I.INTRODUCTION
Embedded systems offer a compelling platform for real- time interactive applications because every hardware re- source is directly accessible and latencies are fully deterministic. This project implements a classic vertical- scrolling space shooter on a bare-metal ARM Cortex-M4 microcontroller, requiring simultaneous management of display rendering, keypad input, game physics, and timing all within a single-core, polling-based loop synchronised by a SysTick interrupt. The game is rendered on a 320×240 SSD2119 TFT LCD connected through the SSI2 peripheral. Because the display is physically mounted in landscape orientation while the game is designed for portrait play, a software coordinate transform rotates every pixel write by 90◦ in firmware, eliminating any hardware re-configuration. Player interaction is provided through a standard 4×4 matrix keypad whose rows and columns are wired to GPIO Port E and Port C on the EduARM4 trainer board. The remainder of this report is organised as follows: Section II describes the motivation, Section III lists the hardware and software components, Sections IV through VII detail the features implemented and the logic behind each, Section VIII describes the overall program flow, and Section IX concludes.
II.MOTIVATION
• Hardware Mastery: Developed register-level understanding of GPIO, SSI, SysTick, and ADC peripherals without using an operating system.
• Real-Time Constraints: Learned timing control through non-blocking keypad debounce, smooth dis- play refresh, and accurate enemy movement.
• Signal Integrity Context: Gained practical knowledge of SPI communication, CS/DC timing, FIFO handling, and display data reliability.
• Progressive Complexity: Built the project step- by-step from basic sprites to a complete game with enemies, collisions, levels, and power-ups.
III.COMPONENTS USED
3.1 Hardware
- TM4C123GH6PM LaunchPad — ARM Cortex- M4F at 50 MHz. Provides GPIO, SSI2, SysTick, ADC0, and NVIC used by the game.
- EduARM4 Trainer Board — Hosts the Launch- Pad, 4×4 matrix keypad (rows PE0–PE3, columns PC4–PC7), and jumper headers J5–J10. Jumpers J7–J10 must be open for keypad operation.
- BOOSTXL-K350QVG-S1 / SSD2119 LCD — 320×240 colour TFT, driven via SSI2 (PB4 = CLK, PB7 = MOSI). CS on PA4, DC on PA5, reset on PD7, backlight on PF2. Pixel colour format is RGB565.
3.2 Software
- Code Composer Studio 12 — IDE with GNU ARM 9.2.1 (Linaro) toolchain.
- TivaWare DriverLib — Used only for peripheral enable, SysTick, SSI configuration, GPIO pad config, and No graphics library is used; all pixel writes are done directly.
- Bare-metal C (C99) — The entire game logic, rendering, input, and state machine are implemented in a single main.c file.
IV.FEATURES IMPLEMENTED
4.1 Display Initialisation and Software Rotation
The SSD2119 is initialised with its original landscape entry-mode registers (0x30EF / 0x6830). A software co- ordinate transform in set pixel hw() maps every logical (x, y) to physical coordinates:
xphys = ylogical, yphys = 239 − xlogical (1)
This achieves a 90◦ counter-clockwise rotation so the game renders in portrait (240×320 logical pixels) aligned with the keypad.
4.2 Starfield Background with Twinkling
Sixty stars are placed at random positions during initialisation using an LCG pseudo-random number generator seeded from ADC noise on a floating PE5 pin. Every 300 ms one randomly chosen star toggles between full- white and dim-grey, creating a continuous twinkling effect without redrawing the background. Whenever a sprite erases pixels, stars restore() checks whether any star’s coordinate falls inside the erased bounding box and re- draws it.
4.3 Selective Redraw (Dirty-Rectangle)
The entire 320×240 framebuffer is never cleared between frames. Instead, each sprite is erased by drawing its bounding box in black before being redrawn at its new position. This minimises SPI transactions and allows smooth animation within the constraints of a 10 MHz SPI bus.
4.4 Five Difficulty Levels
The game automatically advances through five levels as the score increases by 80 points per level. Table 1 summarises the parameters.

Table 1: Level Parameters
On level-up, a splash screen is displayed, all active booster effects are cancelled, and the enemy speed timer is updated.
4.5 Enemy Spawning with PRNG
Enemies spawn at the top of the screen in waves of 1–3, each at a random X position. An AABB overlap check prevents two enemies in the same wave from being placed within MIN GAP pixels of each other. Enemies move down- ward on a fixed timer; if they reach the player line a life is deducted.
4.6 Booster Power-Up
A purple diamond-shaped booster plane spawns once every 30 score points at a random X position at the top of the screen and descends like a regular enemy. Shooting it awards 25 bonus points and activates triple-shot mode for the next three fire presses. During boost, three gold bullets fan out at angles −1, 0, +1 pixels per frame in X while travelling upward at the same speed as normal bullets. The boost does not carry forward across level boundaries.
4.7 Collision Detection (AABB)
Axis-aligned bounding box collision is used for all bullet– enemy and bullet–booster checks:
![]()
On a confirmed hit the enemy (or booster) is erased, a sparkle explosion is spawned, the bullet is fully erased including the trailing dirty-rect strip, and the score is updated.
4.8 Explosion Sparkle Effect
Eight single-pixel sparks are spawned at the centre of a destroyed enemy. Each spark travels in one of the eight compass directions at one pixel per frame and lives for 350 ms before being erased. Three colours (yellow, or- ange, magenta) cycle across the sparks.
4.9 Menu and High-Score System
On power-on the game shows a styled menu with nebula blobs, a twinkling starfield, scan-line stripes, and a double-size title rendered from the same 5×7 bitmap font used for the HUD. Navigation uses keys 2/8/5. A separate high-score screen persists across games within the same session. The game-over screen displays the final score and flags a new high score in green.
4.10 Matrix Keypad with Non-Blocking Debounce
Rows PE0–PE3 are configured as open-drain GPIO out- puts. Columns PC4–PC7 are inputs with internal pull- ups. The scan function drives one row low at a time and reads all four columns. A 500 µs propagation delay (SysCtlDelay(8000)) ensures reliable contact detection for light key presses. Debounce is implemented in soft- ware using the SysTick millisecond counter with an 30 ms hold time, making it fully non-blocking so the game loop never stalls.
V.LOGIC USED FOR KEY FEATURES
5.1 SysTick-Based Frame Rate and Timing
SysTick is configured at 1 kHz (period = 50000 cycles at 50 MHz). The ISR increments g tick ms. The main loop compares elapsed milliseconds against each timer thresh- old independently:
- Frame cap: execute game logic only if ∆t ≥ 16 ms (≈62 fps).
- Enemy step: move enemies only if ∆t ≥g_enemy_move_ms.
- Wave spawn: spawn a new wave only if ∆t ≥g_spawn_ms.
- Debounce: report key only after a 30 ms stable
- Twinkle: toggle one star every 300
All thresholds run concurrently from the single counter, enabling cooperative multi-tasking without an RTOS.
5.2 PRNG Seeded from ADC Noise
The LCG generator uses parameters from Numerical Recipes (a = 1664525, c = 1013904223, m = 232)
Xn+1 = (1664525 · Xn + 1013904223) mod 232 (3)
The seed is XOR’d with a reading from ADC0 channel 8 (PE5 floating) at boot, ensuring different enemy patterns on each power cycle. The seed is also continuously XOR’d with g tick ms at each wave spawn.
5.3 SSI RX FIFO Drain Fix
Every SSIDataPut() clocks in a dummy byte from MISO into the 8-entry RX FIFO. Without draining, the FIFO fills and SSIDataPut() stalls mid-transaction while the DC/CS lines have already been toggled for the next command, corrupting the byte framing and producing garbled pixels. The fix is one line after each transaction:
while(SSIDataGetNonBlocking(SSI2_BASE, &d));
5.4 Boost Triple-Shot Geometry
The three boost bullets are fired simultaneously from the ship centre with horizontal drift offsets ∆x ∈ {−1, 0, +1} applied every frame. After n frames a bullet’s X displacement is n · ∆x, forming a 45◦ diagonal trajectory for the outer two bullets against the vertical BULLET SPEED of 12 pixels/frame.
VI.PROGRAM FLOW
The overall execution flow is described below.
6.1 Initialisation Sequence
- Set system clock to 50 MHz via
- Configure SysTick at 1 kHz; enable global
- Unlock PD7 (NMI-protected pin); configure GPIO
- Initialise SSI2 at 10 MHz, 8-bit Motorola mode
- Hardware-reset the SSD2119; send initialisation reg- ister sequence.
- Seed PRNG from ADC0 channel
- Configure keypad rows (open-drain output) and columns (input, pull-up).
- Clear LCD; draw menu
6.2 Main Loop State Machine
The while(1) loop dispatches on g state:
• STATE MENU — Poll debounced keypad. Keys 2/8 scroll the selector; 5 calls game init() or transitions to STATE HISCORE.
• STATE HISCORE — Display high-score screen; # returns to menu.
• STATE PLAYING — Each iteration:
1.Check level-up threshold; if triggered, cancel boost, show splash, redraw.
2.Read debounced key; update player X; call fire() if ’5’.
3.Advance bullet Y; kill if off-screen.
4.Run AABB collision for all bullet types vs all enemies and booster.
5.On enemy-move timer: erase, translate, check bottom boundary, redraw each enemy.
6.On booster-move timer: erase, translate, check bottom, redraw booster.
7.On score-threshold: spawn booster at random X.
8.On spawn timer: call spawn wave() if alive count < g max alive.
9.On twinkle timer: toggle one star.
10.Update all active sparks.
11.Dirty-rect erase/redraw player if moved; dirty- rect erase/redraw bullet.
12.Spin-wait until 16 ms elapsed since last frame.
• STATE GAME OVER — Display game-over screen with final score; # returns to menu and up- dates high score.
VII.CONCLUSION
This project successfully demonstrates a feature-complete embedded arcade game implemented entirely in bare- metal C on the TM4C123GH6PM. The design achieves smooth animation through selective dirty-rectangle rendering, reliable input through non-blocking SysTick- based debounce, and varied gameplay through an LCG- seeded random enemy spawner, five escalating difficulty levels, and a booster power-up mechanic. All hardware is accessed directly at the register level, reinforcing practical understanding of SSI, GPIO, SysTick, and ADC peripherals. Future enhancements could include DMA-accelerated SPI transfers, a persistent EEPROM high-score store, and audio feedback via PWM.
Recent Comments