Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
Expand Up @@ -4,53 +4,55 @@ A wireless arcade game controller built with Rust and Embassy on STM32 Nucleo-U5
:::info

**Author:** Ene Vlad-Mihnea
**GitHub Project Link:** [link_to_github](https://github.com/UPB-PMRust-Students/acs-project-2026-enevlad)
**GitHub Project Link:** [RustPad](https://github.com/UPB-PMRust-Students/acs-project-2026-enevlad)

:::

## Description

THe project is a wireless game controller based on the STM32 Nucleo-U545RE-Q microcontroller,
RustPad is a wireless game controller based on the STM32 Nucleo-U545RE-Q microcontroller,
programmed in Rust using the Embassy async framework. It features an analog joystick, four
digital action buttons, an SSD1306 OLED display showing battery level and Bluetooth status,
rumble feedback via a vibration motor, and wireless communication over Bluetooth (HC-05).
Power is provided by a LiPo battery with a TP4056 charging module. All components are mounted
on an open acrylic frame, making the hardware fully visible and accessible.
digital action buttons, an SSD1306 OLED display showing Bluetooth connection status,
rumble feedback via a PWM vibration motor module, and wireless communication over Bluetooth
(HC-05). The controller is recognised by any game on Linux through a virtual gamepad created
with uinput, bridged by a companion Rust application running on the host PC.

## Motivation

My motivation for this project stems directly from my passion/hobby for gaming. Building one from scratch in Rust
provides hands-on experience with ADC sampling, GPIO interrupts, UART-based wireless protocols,
and async embedded programming — all within a single cohesive project. Rust's ownership model
makes it especially suitable for embedded development: memory safety without a runtime and
strong type guarantees that catch peripheral misconfigurations at compile time.
My motivation for this project stems directly from my passion for gaming. Building a controller
from scratch in Rust provides hands-on experience with ADC sampling, GPIO interrupts,
UART-based wireless protocols, and async embedded programming — all within a single cohesive
project. Rust's ownership model makes it especially suitable for embedded development: memory
safety without a runtime and strong type guarantees that catch peripheral misconfigurations at
compile time.

## Architecture

The system is split into four main components:
The system is split into two main parts: **firmware** running on the Nucleo and a **bridge
application** running on the host PC.

**Input Layer** — The KY-023 analog joystick sampled via ADC and four tactile buttons read via
GPIO interrupts. All input state is collected into a shared data structure protected by an
Embassy Mutex.
**Input Layer** — The KY-023 analog joystick is sampled via ADC on PA0 and PA1. Four tactile
buttons are read via GPIO with internal pull-ups on PB0–PB3. Input state is collected every
20 ms in the main Embassy loop.

**Processing Layer** — The STM32 Nucleo-U545RE-Q runs an Embassy async executor with separate
tasks for ADC sampling, button handling, display updates, battery monitoring, and Bluetooth
transmission.
**Communication Layer** — The HC-05 Bluetooth module communicates with the MCU over USART1 at
115200 baud. Controller frames (`X:50 Y:-30 BTN:0101`) are sent to the host PC every 20 ms.
The HC-05 STATE pin on PC0 is used to detect Bluetooth connection status.

**Communication Layer** — An HC-05 Bluetooth module receives serialised controller frames over
USART every 10 ms and forwards them to the host PC wirelessly. On the PC side, a Python script
reads the frames from the Bluetooth COM port and forwards them to a vJoy virtual gamepad,
making the controller recognised by any game with gamepad support.
**Output Layer** — An SSD1306 OLED display shows connection status over I²C (updated only on
BT status change). A PWM vibration motor module on PA8 provides haptic feedback, triggered
either by button press or by a rumble command (`V`) received from the host.

**Output Layer** — An SSD1306 OLED display shows Bluetooth connection status and battery level
over I²C. A coin vibration motor driven via PWM through an N-MOSFET provides haptic feedback.
**Host Bridge** — A Rust application on the PC connects to the HC-05 via Bluetooth RFCOMM,
parses controller frames and forwards them to a uinput virtual gamepad, making the controller
recognised by any Linux game.

## Log

### Week 5 - 11 May

Selected project components and ordered hardware. Set up the Rust/Embassy development
environment with the correct toolchain (1.90) and probe-rs for flashing. Tested basic
Selected project components and ordered hardware. Set up the Rust/Embassy development
environment with the correct toolchain (1.90) and probe-rs for flashing. Tested basic
project compilation for the STM32 Nucleo-U545RE-Q target.

### Week 12 - 18 May
Expand All @@ -61,14 +63,20 @@ All components confirmed working. Created EasyEDA schematic with all connections

### Week 19 - 25 May

Integrated all components into the main controller firmware. Implemented Bluetooth communication
at 115200 baud (after AT command reconfiguration of HC-05). Developed the host bridge
application in Rust using bluer and evdev. Tested full controller functionality in SuperTuxKart
on Linux. Implemented haptic feedback via vibration motor triggered by button press.

## Hardware

The controller is built around the **STM32 Nucleo-U545RE-Q** (ARM Cortex-M33, 160 MHz). Input
comes from a **KY-023 analog joystick module** connected to two ADC channels and four
**tactile push buttons** on GPIO pins with internal pull-ups. Wireless communication is handled
by an **HC-05 Bluetooth module** over USART. An **SSD1306 OLED 128×64** display is connected
via I²C and shows battery level and connection status. A **PWM vibration motor module**
(3–5V, with integrated driver) provides rumble feedback.
comes from a **KY-023 analog joystick module** connected to two ADC channels (PA0, PA1) and
four **tactile push buttons** on GPIO pins PB0–PB3 with internal pull-ups. Wireless
communication is handled by an **HC-05 Bluetooth module** over USART1 (PA9/PA10) at 115200
baud. An **SSD1306 OLED 128×64** display is connected via I²C (PB6/PB7) and shows Bluetooth
connection status. A **PWM vibration motor module** (3–5V, integrated driver) on PA8 provides
haptic feedback.

## Schematics

Expand All @@ -79,32 +87,39 @@ via I²C and shows battery level and connection status. A **PWM vibration motor
| Device | Usage | Price |
|--------|-------|-------|
| [STM32 Nucleo-U545RE-Q](https://www.st.com/en/evaluation-tools/nucleo-u545re-q.html) | Main microcontroller | ~60 RON |
| [KY-023 Analog Joystick](https://www.optimusdigital.ro) × 2 | Analog axis input | ~10 RON |
| [KY-023 Analog Joystick](https://www.optimusdigital.ro) | Analog axis input (X/Y) | ~5 RON |
| [HC-05 Bluetooth Module](https://www.optimusdigital.ro) | Wireless UART communication | ~18 RON |
| [SSD1306 OLED 128×64 I²C](https://www.optimusdigital.ro) | Battery + BT status display | ~15 RON |
| [Tactile push buttons](https://www.optimusdigital.ro) × 6 | Action buttons | ~3 RON |
| [Modul motor vibratii PWM 3-5V](https://sigmanortec.ro/modul-motor-vibratii-dc-control-pwm-3-5v) | Rumble / haptic feedback | ~5 RON |
| [TP4056 Charger Module](https://www.optimusdigital.ro) | LiPo USB charging + protection | ~6 RON |
| LiPo Battery 3.7V 1000mAh | Power source | ~20 RON |
| AMS1117-3.3 LDO Regulator | 3.3V power supply | ~2 RON |
| Perfboard + wires + resistors | Wiring and assembly | ~10 RON |
| [SSD1306 OLED 128×64 I²C](https://www.optimusdigital.ro) | BT status display | ~15 RON |
| [Tactile push buttons](https://www.optimusdigital.ro) × 4 | Action buttons | ~2 RON |
| [Modul motor vibratii PWM 3-5V](https://sigmanortec.ro/modul-motor-vibratii-dc-control-pwm-3-5v) | Rumble / haptic feedback | ~10 RON |
| Breadboard + wires | Wiring and assembly | ~10 RON |

## Software

### Firmware (STM32 Nucleo)

| Library | Description | Usage |
|---------|-------------|-------|
| [embassy-stm32](https://github.com/embassy-rs/embassy) | Async HAL for STM32 | ADC, GPIO, USART, I²C, PWM peripherals |
| [embassy-executor](https://github.com/embassy-rs/embassy) | Async task executor for embedded | Running concurrent tasks on the MCU |
| [ssd1306](https://github.com/jamwaffles/ssd1306) | Display driver for SSD1306 OLED | Rendering battery level and BT status |
| [embedded-graphics](https://github.com/embedded-graphics/embedded-graphics) | 2D graphics library | Drawing text and shapes to the OLED |
| [embassy-executor](https://github.com/embassy-rs/embassy) | Async task executor for embedded | Main async loop on the MCU |
| [embassy-time](https://github.com/embassy-rs/embassy) | Time abstractions for embedded | Timers and delays |
| [ssd1306](https://github.com/jamwaffles/ssd1306) | Display driver for SSD1306 OLED | Rendering BT status on the display |
| [embedded-graphics](https://github.com/embedded-graphics/embedded-graphics) | 2D graphics library | Drawing text to the OLED |
| [embedded-hal](https://github.com/rust-embedded/embedded-hal) | Hardware abstraction traits | PWM control for vibration motor |
| [defmt](https://github.com/knurling-rs/defmt) | Logging framework for embedded Rust | Debug output via probe-rs |
| [pyserial](https://pypi.org/project/pyserial/) (PC) | Serial communication in Python | Reading Bluetooth frames on the host PC |
| [vJoy](https://github.com/njz3/vJoy/) (PC) | Virtual gamepad driver | Exposing controller as HID gamepad to games |
| [heapless](https://github.com/rust-embedded/heapless) | Static data structures | String formatting without heap |

## Links
### Host Bridge (Linux PC)

<!-- Add a few links that inspired you and that you think you will use for your project -->
| Library | Description | Usage |
|---------|-------------|-------|
| [bluer](https://github.com/bluez/bluer) | Bluetooth library for Rust | RFCOMM connection to HC-05 |
| [evdev](https://github.com/emberian/evdev) | Linux input device library | Creating virtual gamepad via uinput |
| [tokio](https://tokio.rs) | Async runtime for Rust | Async Bluetooth I/O on the host |

## Links

1. [link](https://example.com)
2. [link](https://example3.com)
...
1. [Embassy Framework](https://embassy.dev)
2. [STM32 Nucleo-U545RE-Q User Manual](https://www.st.com/resource/en/user_manual/um3062-stm32u3u5-nucleo64-boards-mb1841-stmicroelectronics.pdf)
3. [SSD1306 Datasheet](https://cdn-shop.adafruit.com/datasheets/SSD1306.pdf)
4. [HC-05 AT Commands Reference](https://www.instructables.com/AT-command-mode-of-HC-05-Bluetooth-module/)
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading