Project idea
Terminal “Hole in the Wall” with zero-install setup
Game logic maps ultrasonic distance bins to player position on a scrolling wall, rendered as ASCII frames over UART.
UX Goals
- No IDE or drivers required; single binary / script
- High refresh rate with predictable frame pacing
- Responsive hand-to-display latency
- Readable monospace visuals with minimal artifacts
Key Design Decisions
- Single microcontroller for “all-in-one” constraint
- ANSI/ASCII terminal rendering to keep output lightweight
- DMA to offload CPU during frame transfers
- Hardware timers for deterministic 33.3 ms ticks
Requirements
What success looks like
Functional
- Distance measurement at 30 Hz
- Frame generation at 30 FPS
- ANSI terminal rendering of frames via TeraTerm
- Input mapped to player movement (binning)
Non-functional
- All-in-one hardware; plug-and-play over UART
- Low computation overhead for predictable timing
- Low latency from sensor read to display draw
- DMA usage wherever possible to free CPU
Constraints
- 80 × 24 terminal viewport (monospace, UTF-8)
- 40 cm reliable ultrasonic window
- No IDE requirement; single deployable binary
- Self-contained hardware package
System architecture
Timing-driven loop with DMA-backed display
Every 33.3 ms, hardware timers trigger both a new distance capture and a frame render, keeping sensing and display in lockstep.
Input
Ultrasonic sensing
Periodic trigger and echo capture; distance readings are binned into discrete player positions.
- Timer-driven 30 Hz sampling
- Range limited to 40 cm window
- Optional DMA for capture buffers
Logic
Game loop
Walls descend each frame; collision occurs when player bin overlaps wall gap.
- State machine paced at 30 FPS
- Difficulty via wall patterns & cadence
- Scoring for survival time and clears
Output
Terminal renderer
Prebuilt ASCII frames streamed over UART; DMA pushes frame buffer to minimize CPU load.
- 80 × 24 ANSI canvas
- UTF-8 characters for walls/player
- Hardware timers for frame pacing
LabFinal firmware signals
Timer + pin map
- TIM3 @ 30 Hz: heartbeats PA5 and calls
buildFrame()for each render tick - TIM2 CH3 (PB10): PWM trigger pulses for the ultrasonic transmitter
- TIM4 CH1 (PB6): dual-edge input capture for ultrasonic echo; counts overflows for long pulses
- USART2 TX + DMA1 CH7: streams frame buffer over UART without stalling the CPU
Render pipeline
Frame composition
- Frame buffer
frameStringholds ANSI cursor moves + ASCII walls and player buildFrame()draws walls at their row, then maps ultrasonic ticks (20–220) to 80 columns for the player cursorEnable_DMA()kicks DMA1 CH7 to push the buffer intoUSART2->TDR- ISR cadence: TIM3 interrupt → frame build → DMA transfer → wall positions advance
Milestones
Path to a playable demo
Display
Render moving frames at 30 Hz in the terminal; draw player at binned positions.
HMI integration
Clamp ultrasonic readings to playable range; map bins to terminal rows/columns.
Game core
Generate descending walls with gaps; add collision logic and scoring loop.
Extras
Difficulty button, game menu/options, expanded scoring and feedback polish.
Testing & validation
Measure timing, verify feel
Quantitative
- Analog Discovery 2 capture of ultrasonic I/O (period, duty)
- AD2 capture of UART Tx (period, transmission length)
- Timing budget: 33.3 ms total per loop
Qualitative
- Hand motion responsiveness versus on-screen updates
- Playtester feedback on difficulty and visual clarity
- Subjective latency checks during rapid movement
Constraints
What shapes the build
Economic
Target form factor: self-contained, could be packaged as a USB flash drive-style device.
Environmental
Indoor use; conservative ultrasonic range to avoid noisy reflections beyond 40 cm.
Team