Skip to main content
Version: FILS English

2-Player Snake

A snake game inspired by the timeless classic that aims to bring back the good times of the past and a modern touch with a 2-player mode and touch-screen compatibility.

info

Author: Beldie Razvan-Gabriel

GitHub Project Link: https://github.com/UPB-PMRust-Students/project-IRazvannN

Description

This project implements a two-player version of the classic Snake game on an STM32 NUCLEO-F401RE microcontroller, written entirely in Rust using the Embassy asynchronous framework.The firmware handles real-time input polling from joysticks, manages game state logic, drives the SPI display using embedded-graphics, and generates PWM audio signals concurrently using Embassy's async tasks.

Motivation

The primary motivation for choosing this project was to create an engaging and enjoyable embedded system application that goes beyond basic hardware interaction. Developing a game, particularly a well-known classic like Snake, provides a fun platform that can be used and demonstrated after completion.Furthermore, the project presents several interesting technical challenges well-suited for exploring the capabilities of Rust and the Embassy framework in an embedded context

Architecture

The system architecture revolves around the NUCLEO-F401RE board acting as the central controller. It runs firmware developed in Rust using the Embassy asynchronous framework.

1.Input Subsystem:

  • Two analog joystick modules are connected to the Nucleo board. The X and Y analog outputs are routed to distinct ADC channels, while the digital switch output of each joystick is connected to a separate GPIO input pin.

  • An asynchronous Embassy task periodically polls the ADC channels and GPIO pins corresponding to both joysticks.

  • Raw ADC values are converted into directional commands (Up, Down, Left, Right) based on deviation from a center resting value. Digital button states are read directly.

  • These processed inputs are likely sent via Embassy channels or signals to the main game logic task.

2.Game Logic Subsystem (snake_game_lib):

  • This core logic resides in a separate no_std library crate.

  • It maintains the GameState, including the positions and directions of both snakes, the food location, player scores, and the game over status.

  • A central tick() function updates the game state based on the latest player inputs received from the input subsystem. This includes moving snakes, checking for collisions (wall, self, other player), handling food consumption, and managing scoring.

  • It operates independently of the specific hardware, receiving abstract input commands and outputting the game state.

3.Display Output Subsystem:

  • The ILI9341 TFT display is connected via SPI.

  • An asynchronous Embassy task is responsible for rendering. It receives the current GameState (potentially via an Embassy channel or by accessing shared state protected by a Mutex/Signal).

  • Using the embedded-graphics library and an ili9341 driver crate, this task draws the game board, snakes, food, scores, and any active menu/UI elements onto a framebuffer or directly to the display.

  • Communication with the display happens over SPI, managed by the embassy-stm32 HAL and the display driver.

4.Audio Output Subsystem:

  • A passive buzzer is connected to a PWM-capable GPIO pin.

  • An Embassy task or dedicated functions within the game logic trigger sound effects based on game events (food eaten, collision/game over, menu interaction).

  • These triggers configure and briefly enable a PWM peripheral channel on the STM32 to generate the appropriate frequency/tone on the buzzer.

5.Concurrency:

  • The Embassy executor manages multiple asynchronous tasks: one for input polling, one for the main game loop/state updates, and potentially one dedicated to rendering or sound if needed, although rendering might be part of the main loop.

  • Embassy channels (Channel, Signal) or shared state (Mutex) are used for safe communication and data sharing between tasks (e.g., sending input commands to the game logic, sending game state to the display task).

6.User Interface / State Machine:

  • The application includes different states (Main Menu, Side Select, Playing, Paused, Game Over, Leaderboard).

  • The main loop transitions between these states based on user input and game events.

Each state dictates what is drawn on the screen and how user input is interpreted.

  • what are the main components (architecture components, not hardware components)
  • how they connect with each other

Schematic diagram

Log

Week 5 - 11 May

  • Wrote the main part of the documentation milestone
  • Finally collected all the necessary components
  • Started the software base

Week 12 - 18 May

  • Finished the hardware side of things
  • Continued working on the software, implementing the display connection

Week 12 - 18 May

  • continued working on the software, mainly the game logic, and dealing with dependecies issues =======

Week 12 - 18 May

  • Finished the hardware side of things
  • Continued working on the software, implementing the display connection

Week 12 - 18 May

Week 19 - 25 May

Week 19 - 25 May

-finished the game logic -finished work on the hardware presentation

Hardware

Schematic diagram Schematic diagram Schematic diagram

This project utilizes the following hardware components:

  1. Main Controller Board: STMicroelectronics NUCLEO-F401RE
  • Features the STM32F401RE microcontroller (ARM Cortex-M4 core).

  • Provides the main processing power for running the game logic, handling inputs, and driving outputs.

  • Includes an onboard ST-LINK/V2-1 debugger for programming and debugging via USB connection to the host computer.

  • Powered via the ST-LINK USB connection during development, or optionally via an external 5V supply connected to the E5V pin (requires jumper change).

  1. Display: 2.4" SPI TFT LCD Display Module (ILI9341 Controller)
  • A 240x320 pixel color liquid-crystal display.

  • Used to render the game visuals, including the snakes, food, score, game area, and menus.

  • Interfaces with the NUCLEO board via the SPI (Serial Peripheral Interface) protocol.

  • Requires connections for SPI signals (SCK, MOSI, MISO), Chip Select (CS), Data/Command (DC), Reset (RST), Power (VCC 3.3V), Ground (GND), and Backlight (LED).

  1. Input Devices: 2x Analog Joystick Modules (XY-axis + Switch)
  • Standard "thumbstick" style modules, each providing two analog outputs (X and Y axes) and one digital output (push-button switch).

  • Used for player input to control the direction of the snakes and potentially for menu navigation/selection.

  • The analog outputs connect to ADC pins on the NUCLEO board.

  • The digital switch output connects to GPIO pins on the NUCLEO board.

  • Powered by the 3.3V output from the NUCLEO board.

  1. Audio Output: 1x Passive Buzzer
  • A simple piezoelectric buzzer that produces sound when driven by an oscillating signal.

  • Used to provide basic audio feedback for game events (e.g., eating food, game over).

  • Driven by a PWM (Pulse Width Modulation) signal generated by a timer peripheral on the NUCLEO board, connected via a GPIO pin.

Accessories:

  1. Breadboard(s): (Optional) May be used for cleanly connecting components or power rails if needed.

  2. Jumper Wires: Male-Female and Male-Male wires for connecting the display module, joysticks, and buzzer to the NUCLEO board headers.

  3. USB Cable: Standard USB-A to Mini-B cable for connecting the NUCLEO's ST-LINK port to the development laptop for power, programming, and debugging.

Schematics

Schematic diagram

Place your KiCAD schematics here.

Bill of Materials

DeviceUsagePrice
NUCLEO-F401REThe microcontroller64.99 RON
2.4" SPI TFT LCD Display Touch Panel ILI9341 240x320LCD Display22.27 RON
2 x Breadboard HQBuilding the circuit9.78 RON
ResistorsBuilding the circuit18.52 RON
Passive BuzzerFor Sound1.40 RON
Jumper wiresConnections11.92 RON
M-T wires, 30cm,Connections4.81 RON
T-T wires, 10cmConnections4.99 RON
Micro-USB CablePowering the microcontroller using the laptop4.37 RON
LEDSDebugging26.99 RON

Software

This table lists the key Rust crates and software components used in this project.

LibraryDescriptionUsage
EmbassyOverall asynchronous framework for embedded Rust.Provides the runtime, basic utilities, and HAL abstractions.
embassy-executorAn async/await executor designed for embedded usage.Manages and runs the asynchronous tasks (input, game logic, display, sound).
embassy-timeTimekeeping, delays, and timeouts integrated with the executor.Used for game loop timing, delays, and potentially timeouts.
embassy-syncSynchronization primitives (Mutex, Channels, Signals) for async tasks.Used for safe communication and sharing data between tasks (e.g., input -> game logic).
embassy-stm32Hardware Abstraction Layer (HAL) for STM32 microcontrollers within Embassy.Initializing and interacting with board peripherals (GPIO, ADC, SPI, PWM, RCC, Timers).
gpio modulePart of embassy-stm32 for General Purpose Input/Output management.Controlling joystick buttons and display control pins (DC, RST).
adc modulePart of embassy-stm32 for Analog-to-Digital Converter driver.Reading analog values from the joystick axes.
spi modulePart of embassy-stm32 for Serial Peripheral Interface communication.Communicating with the ILI9341 display.
pwm modulePart of embassy-stm32 for Pulse Width Modulation output.Driving the passive buzzer to generate sounds.
ili9341Driver crate specifically for the ILI9341 TFT LCD display controller.Used to initialize the display and send drawing commands (like clear).
display-interface-spiAdapter between display-interface and embedded-hal SPI implementations.Connects the ili9341 driver to the underlying SPI peripheral HAL adapter.
embedded-graphics2D graphics library focused on memory-constrained embedded devices.Used for drawing game elements (snakes, food, score, text, menus) onto the display.
embedded-halStandard Hardware Abstraction Layer traits (v1.0.0).Provides the common traits (OutputPin, SpiBus, DelayNs, SetDutyCycle) used by drivers.
embassy-embedded-halAdapters to bridge Embassy HAL types with embedded-hal v1.0.0 traits.Used to make Embassy's SPI/GPIO types compatible with the display driver's requirements.
defmtEfficient, deferred formatting logging framework for embedded systems.Used for debugging output over RTT/probe-rs.
panic-probePanic handler that prints backtraces over defmt.Handles program panics and provides debug information.
cortex-m / cortex-m-rtLow-level access crates for ARM Cortex-M cores and runtime setup.Provides core interrupt handling, vector table setup, and runtime initialization.
  1. Embassy Project
  2. Embassy STM32 HAL Docs
  3. ILI9341 Driver Crate (crates.io)
  4. Embedded Graphics Docs
  5. NUCLEO-F401RE Product Page
  6. STM32F401RE Reference Manual (RM0368)
  7. The Embedded Rust Book
  8. Awesome Embedded Rust