Project 7: Timer-Driven Animation
Use timer interrupts for stable animation.
Quick Reference
| Attribute | Value |
|---|---|
| Difficulty | Level 3 |
| Time Estimate | 1-2 weeks |
| Main Programming Language | Game Boy Assembly (SM83/LR35902) |
| Alternative Programming Languages | C (GBDK-2020), C++ (GBDK-2020) |
| Coolness Level | Level 4 |
| Business Potential | Level 1 |
| Prerequisites | DMG memory map, VBlank timing, basic assembly concepts |
| Key Topics | timers, TIMA/TMA/TAC, animation timing |
1. Learning Objectives
By completing this project, you will:
- Build and verify a working timer-driven animation system.
- Apply DMG hardware constraints (timing, memory, and I/O rules).
- Create repeatable validation steps using emulator tooling.
- Document decisions and trade-offs for future projects.
2. All Theory Needed (Per-Concept Breakdown)
Timers and Deterministic Animation
Fundamentals The DMG timer provides a hardware-driven tick that you can use for animation, music, and periodic logic. A timer-driven system is more stable than frame counting.
Deep Dive into the concept The DIV register increments at a fixed rate, and the timer counter (TIMA) increments based on a selectable divider. When TIMA overflows, it reloads from TMA and triggers a timer interrupt. This mechanism provides a consistent tick independent of workload. For animation, you can increment a tick counter on each timer interrupt and advance frames when the counter reaches a threshold. This ensures animation speed remains stable even if the main loop workload fluctuates. Timer-driven systems also simplify music scheduling, AI updates, and periodic effects. The key is to configure TAC for an appropriate frequency, handle overflow consistently, and keep the interrupt handler lightweight.
How this fit on projects This concept is central to Timer-Driven Animation. It informs the build pipeline, timing discipline, and verification steps used throughout the project.
Definitions & key terms
- DIV: Divider register that increments continuously.
- TIMA: Timer counter that increments at a selectable rate.
- TMA: Timer modulo value loaded on overflow.
Mental model diagram
DIV -> TIMA -> overflow -> Timer Interrupt
How it works (step-by-step)
- Configure TAC for desired frequency.
- TIMA increments based on DIV.
- On overflow, TIMA reloads from TMA and fires interrupt.
- Interrupt handler updates animation or logic ticks.
Minimal concrete example (pseudocode)
on_timer_tick(): increment_animation_timer()
Common misconceptions
- “Frame count is enough” -> timers decouple animation from frame load.
Check-your-understanding questions
- Why does TIMA reload from TMA?
- How does a timer tick improve animation stability?
- Predict what happens if the interrupt handler is too long.
Check-your-understanding answers
- It creates a periodic tick at a stable interval.
- It prevents animation speed from drifting with frame load.
- Timing jitter or missed interrupts.
Real-world applications
- Animation pacing
- Music sequencing
Where you’ll apply it You’ll apply it in Section 3.1 and Section 5.10. Also used in: P08 Audio Driver Mini.
References
- Pan Docs: Timer and Divider Registers
Key insights Timers turn inconsistent loops into consistent systems.
Summary Timer interrupts provide a stable tick for animation and music.
Homework/Exercises to practice the concept
- Compute ticks for a 0.5s animation cycle.
Solutions to the homework/exercises
- Use timer frequency to compute ticks per cycle.
3. Project Specification
3.1 What You Will Build
You will build a DMG project component focused on Timer-Driven Animation. It will be functional, repeatable, and verifiable in strict emulators. It will include clear output signals (visual or logged) and a documented validation process. It will exclude advanced extras beyond scope, such as CGB-only features.
3.2 Functional Requirements
- Core functionality: Implement the primary system described in Timer-Driven Animation.
- Deterministic output: Provide a repeatable visible or logged result.
- Hardware constraints: Respect VRAM/OAM timing and memory map rules.
3.3 Non-Functional Requirements
- Performance: Must stay within a safe per-frame budget.
- Reliability: Must behave consistently across two emulators.
- Usability: Clear on-screen or logged indicators for success.
3.4 Example Usage / Output
Build:
$ rgbasm -o build/main.o src/main.asm
$ rgblink -o build/game.gb build/main.o
$ rgbfix -v -p 0 build/game.gb
Run:
$ sameboy build/game.gb
Expected:
- No header warnings
- Stable on-screen indicator or log output
Exit Codes:
- 0 = success
- 1 = build failure
- 2 = header validation failure
3.5 Data Formats / Schemas / Protocols
StateRecord (pseudocode shape):
- frame_counter: u16
- input_mask: u8
- flags: u8
AssetIndex (pseudocode shape):
- bank_id: u8
- offset: u16
- length: u16
UpdateQueue item:
- target: VRAM/OAM
- dest: address
- size: bytes
3.6 Edge Cases
- VRAM/OAM access outside safe windows
- Bank switch not restored
- Input sampled multiple times per frame
3.7 Real World Outcome
A stable, reproducible DMG component that can be verified visually or via emulator logs, with no flicker or corruption.
3.7.1 How to Run (Copy/Paste)
$ rgbasm -o build/main.o src/main.asm
$ rgblink -o build/game.gb build/main.o
$ rgbfix -v -p 0 build/game.gb
$ sameboy build/game.gb
Exit Codes:
- 0 = success
- 1 = build failure
- 2 = header validation failure
3.7.2 Golden Path Demo (Deterministic)
- Load ROM
- Observe the expected on-screen state or log output
- Confirm stability for 30 seconds
3.7.3 Failure Demo (Deterministic)
- Force a known invalid state (e.g., wrong bank selected)
- Observe expected failure behavior (visual corruption or emulator warning)
4. Solution Architecture
4.1 High-Level Design
Input/Timer -> Core Logic -> Render/Sound Updates -> Validation
4.2 Key Components
| Component | Responsibility | Key Decisions |
|---|---|---|
| Input/Timing | Stable cadence | VBlank-driven loop |
| Data/Assets | Storage & layout | Fixed bank + banked assets |
| Renderer | Safe updates | VBlank/STAT windows |
4.4 Data Structures (No Full Code)
- State: counters, flags, and last-input snapshot
- Asset tables: offsets + bank IDs
- Update queue: list of VRAM/OAM updates
4.4 Algorithm Overview
Key Algorithm: Frame Update
- Wait for VBlank
- Read input and update state
- Apply safe VRAM/OAM updates
- Render or log output
Complexity Analysis:
- Time: O(n) over visible entities or updates
- Space: O(n) for entity/state tables
5. Implementation Guide
5.1 Development Environment Setup
Install RGBDS
Install DMG-accurate emulator
Set up project folder
5.2 Project Structure
project-root/
|---- src/
| |---- main.asm
| |---- hardware.asm
| `---- assets.asm
|---- build/
|---- tools/
`---- README.md
5.3 The Core Question You’re Answering
“How do I build timer-driven animation that behaves correctly under DMG hardware constraints?”
5.4 Concepts You Must Understand First
Stop and research these before coding:
- Timers and Deterministic Animation
- What parts are most timing-sensitive?
- Why does DMG hardware enforce this?
- Book Reference: “Game Boy Coding Adventure” - relevant chapters
5.5 Questions to Guide Your Design
- Timing and Safety
- Where are the safe update windows?
- How will you ensure you only write during those windows?
- Validation
- What will you see or log when it works?
- How will you reproduce the result exactly?
5.6 Thinking Exercise
Draw the Timing Window
Sketch a frame timeline and mark exactly where your updates will occur.
5.7 The Interview Questions They’ll Ask
Prepare to answer these:
- “What hardware constraints drive your design?”
- “How do you validate correctness on DMG?”
- “What makes your updates deterministic?”
- “How do you avoid timing glitches?”
- “How do you debug errors when you have no OS?”
5.8 Hints in Layers
Hint 1: Start with a stable VBlank loop Build the simplest loop that waits for VBlank and updates a single state.
Hint 2: Add one subsystem at a time Layer in input, rendering, or audio only after the base loop is stable.
Hint 3: Validate with emulator tools Use VRAM/OAM viewers and breakpoints to confirm data correctness.
Hint 4: Stress test timing Intentionally add workload and watch for corruption or flicker.
5.9 Books That Will Help
| Topic | Book | Chapter |
|---|---|---|
| DMG fundamentals | “Game Boy Coding Adventure” | Ch. 1-5 |
| Low-level systems | “The Art of Assembly Language” | Ch. 1-6 |
5.10 Implementation Phases
Phase 1: Foundation (2-4 days)
Goals:
- Build a bootable ROM and stable loop
- Create a minimal visible output
Tasks:
- Set up toolchain and build pipeline
- Display a simple on-screen indicator
Checkpoint: Emulator shows stable output without warnings
Phase 2: Core Functionality (1 week)
Goals:
- Implement the core system for Timer-Driven Animation
- Add validation logs or overlays
Tasks:
- Build the main subsystem
- Verify correctness with emulator tools
Checkpoint: System behaves correctly for 30 seconds
Phase 3: Polish & Edge Cases (3-5 days)
Goals:
- Handle edge cases and timing failures
- Document limitations and fixes
Tasks:
- Add edge case handling
- Stress test and refine
Checkpoint: No flicker/corruption under stress test
5.11 Key Implementation Decisions
| Decision | Options | Recommendation | Rationale |
|---|---|---|---|
| Update timing | VBlank only / HBlank | VBlank only | Safest for DMG |
| Data layout | Dense / Aligned | Aligned | Easier debugging |
6. Testing Strategy
6.1 Test Categories
| Category | Purpose | Examples |
|---|---|---|
| Unit Tests | Validate small routines | Input decoding, counters |
| Integration Tests | Subsystem behavior | Loop + rendering |
| Edge Case Tests | Timing stress | Max sprites, heavy updates |
6.2 Critical Test Cases
- Baseline run: ROM boots and shows stable output.
- Stress test: Maximum updates without flicker.
- Regression test: Repeat run after changes and compare results.
6.3 Test Data
Input sequence: Up, Up, A, Start
Expected: deterministic state changes and stable display
7. Common Pitfalls & Debugging
7.1 Frequent Mistakes
| Pitfall | Symptom | Solution |
|---|---|---|
| Wrong update timing | Flicker or corruption | Move writes to VBlank |
| Bank not restored | Random crashes | Save/restore bank state |
| Incorrect register setup | Blank screen | Verify I/O writes |
7.2 Debugging Strategies
- Use emulator VRAM/OAM viewers: confirm data and timing.
- Log state changes: compare expected vs actual frames.
7.3 Performance Traps
Overloading a frame with too many updates causes missed safe windows. Cap work per frame.
8. Extensions & Challenges
8.1 Beginner Extensions
- Add a visual status indicator for success
- Add a simple on-screen counter
8.2 Intermediate Extensions
- Add a debug toggle for extra metrics
- Add a second validation scenario
8.3 Advanced Extensions
- Run the ROM on real hardware via flash cart
- Add a small automated test harness
9. Real-World Connections
9.1 Industry Applications
- Embedded firmware: fixed timing loops and I/O constraints
- Retro toolchains: reproducible builds for constrained devices
9.2 Related Open Source Projects
- RGBDS: https://rgbds.gbdev.io/ - DMG assembler/linker
- SameBoy: https://sameboy.github.io/ - Accurate DMG emulator
9.3 Interview Relevance
- Hardware timing questions
- Memory map and register-level reasoning
10. Resources
10.1 Essential Reading
- Game Boy Coding Adventure by Maximilien Dagois - DMG fundamentals
- The Art of Assembly Language by Randall Hyde - registers and timing
10.2 Video Resources
- DMG dev walkthroughs (YouTube) - focus on timing and VRAM rules
10.3 Tools & Documentation
- Pan Docs: https://gbdev.io/pandocs/ - hardware reference
- RGBDS: https://rgbds.gbdev.io/ - toolchain docs
10.4 Related Projects in This Series
- Previous Project: Save RAM + Banking
- Next Project: Audio Driver Mini
11. Self-Assessment Checklist
11.1 Understanding
- I can explain the core hardware constraints behind this project
- I can describe why the chosen timing model works
- I can explain one trade-off I made
11.2 Implementation
- All functional requirements are met
- All test cases pass in two emulators
- The output is stable and deterministic
11.3 Growth
- I can explain this project in an interview
- I documented what I would do differently next time
12. Submission / Completion Criteria
Minimum Viable Completion:
- Core functionality works and is visible
- ROM builds without warnings
- Behavior is reproducible
Full Completion:
- All edge cases handled
- Performance budget respected
Excellence (Going Above & Beyond):
- Verified on real hardware
- Includes automated validation steps