From f2b7f37b7ccd39ae9590c55faa4a785c10ec82a7 Mon Sep 17 00:00:00 2001 From: Vlad Ene Date: Mon, 27 Apr 2026 12:46:25 +0300 Subject: [PATCH 1/5] Add documentation --- .../2026/vlad_mihnea.ene/architecture.svg | 4 + .../project/2026/vlad_mihnea.ene/index.md | 106 ++++++++++++++++++ .../2026/vlad_mihnea.ene/schematic.svg | 4 + 3 files changed, 114 insertions(+) create mode 100644 website/versioned_docs/version-acs_cc/project/2026/vlad_mihnea.ene/architecture.svg create mode 100644 website/versioned_docs/version-acs_cc/project/2026/vlad_mihnea.ene/index.md create mode 100644 website/versioned_docs/version-acs_cc/project/2026/vlad_mihnea.ene/schematic.svg diff --git a/website/versioned_docs/version-acs_cc/project/2026/vlad_mihnea.ene/architecture.svg b/website/versioned_docs/version-acs_cc/project/2026/vlad_mihnea.ene/architecture.svg new file mode 100644 index 00000000000..c4bce1e1ef3 --- /dev/null +++ b/website/versioned_docs/version-acs_cc/project/2026/vlad_mihnea.ene/architecture.svg @@ -0,0 +1,4 @@ + + + Architecture Diagram - Coming Soon + diff --git a/website/versioned_docs/version-acs_cc/project/2026/vlad_mihnea.ene/index.md b/website/versioned_docs/version-acs_cc/project/2026/vlad_mihnea.ene/index.md new file mode 100644 index 00000000000..f11f1e336e4 --- /dev/null +++ b/website/versioned_docs/version-acs_cc/project/2026/vlad_mihnea.ene/index.md @@ -0,0 +1,106 @@ +# Wireless Arcade Controller +A wireless arcade game controller built with Rust and Embassy on STM32 Nucleo-U545RE-Q. + +:::info + +**Author:** Ene Vlad-Mihnea +**GitHub Project Link:** [link_to_github](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, +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. + +## 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. + +## Architecture + +The system is split into four main components: + +**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. + +**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** — 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 Bluetooth connection status and battery level +over I²C. A coin vibration motor driven via PWM through an N-MOSFET provides haptic feedback. + +![Architecture Diagram](architecture.svg) + +## Log + +### Week 5 - 11 May + +### Week 12 - 18 May + +### Week 19 - 25 May + +## Hardware + +The controller is built around the **STM32 Nucleo-U545RE-Q** (ARM Cortex-M33, 160 MHz). Input +comes from two **KY-023 analog joystick modules** connected to four ADC channels and six +**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 **coin vibration motor** driven by a +**2N7000 MOSFET** provides rumble feedback. Power comes from a **3.7 V LiPo battery** managed +by a **TP4056 charging module** and a **3.3 V AMS1117 LDO regulator**. All components are +mounted on an open **acrylic plate** (~200×150 mm) using M3 standoffs and screws. + +## Schematics + +![KiCad Schematic](schematic.svg) + +## Bill of Materials + +| 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 | +| [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 | + +## Software + +| 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 | +| [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 | + +## Links + + + +1. [link](https://example.com) +2. [link](https://example3.com) +... \ No newline at end of file diff --git a/website/versioned_docs/version-acs_cc/project/2026/vlad_mihnea.ene/schematic.svg b/website/versioned_docs/version-acs_cc/project/2026/vlad_mihnea.ene/schematic.svg new file mode 100644 index 00000000000..92b3f94421a --- /dev/null +++ b/website/versioned_docs/version-acs_cc/project/2026/vlad_mihnea.ene/schematic.svg @@ -0,0 +1,4 @@ + + + KiCad Schematic - Coming Soon + From 4d3b95b26b70db9e872f2e78ce7e4bd7acd23c03 Mon Sep 17 00:00:00 2001 From: Vlad Ene Date: Tue, 28 Apr 2026 08:24:50 +0300 Subject: [PATCH 2/5] Update documentation --- .../2026/vlad_mihnea.ene/architecture.svg | 4 - .../project/2026/vlad_mihnea.ene/index.md | 2 - .../2026/vlad_mihnea.ene/schematic.svg | 107 +++++++++++++++++- 3 files changed, 104 insertions(+), 9 deletions(-) delete mode 100644 website/versioned_docs/version-acs_cc/project/2026/vlad_mihnea.ene/architecture.svg diff --git a/website/versioned_docs/version-acs_cc/project/2026/vlad_mihnea.ene/architecture.svg b/website/versioned_docs/version-acs_cc/project/2026/vlad_mihnea.ene/architecture.svg deleted file mode 100644 index c4bce1e1ef3..00000000000 --- a/website/versioned_docs/version-acs_cc/project/2026/vlad_mihnea.ene/architecture.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - Architecture Diagram - Coming Soon - diff --git a/website/versioned_docs/version-acs_cc/project/2026/vlad_mihnea.ene/index.md b/website/versioned_docs/version-acs_cc/project/2026/vlad_mihnea.ene/index.md index f11f1e336e4..bdb763da8b1 100644 --- a/website/versioned_docs/version-acs_cc/project/2026/vlad_mihnea.ene/index.md +++ b/website/versioned_docs/version-acs_cc/project/2026/vlad_mihnea.ene/index.md @@ -45,8 +45,6 @@ making the controller recognised by any game with gamepad support. **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. -![Architecture Diagram](architecture.svg) - ## Log ### Week 5 - 11 May diff --git a/website/versioned_docs/version-acs_cc/project/2026/vlad_mihnea.ene/schematic.svg b/website/versioned_docs/version-acs_cc/project/2026/vlad_mihnea.ene/schematic.svg index 92b3f94421a..65e89b085ea 100644 --- a/website/versioned_docs/version-acs_cc/project/2026/vlad_mihnea.ene/schematic.svg +++ b/website/versioned_docs/version-acs_cc/project/2026/vlad_mihnea.ene/schematic.svg @@ -1,4 +1,105 @@ - - - KiCad Schematic - Coming Soon + +RustPad Hardware Schematic + + + + + + + + + + + + +STM32 Nucleo-U545RE-Q +Embassy async executor +ADC x2 +GPIO x4 +I2C +USART +PWM +3.3V rail + + + +Joystick +KY-023 — ADC x2 + + + +Buttons x4 +GPIO — pull-up + + + +HC-05 Bluetooth +USART — SPP + + + +OLED SSD1306 +I2C — 128x64 + + + +Vibration Motor +PWM module + + + +LiPo 3.7V +1000 mAh + + +TP4056 +USB-C charger + + +AMS1117-3.3 +LDO regulator + + + +ADC + + +GPIO + + + +USART + + +I2C + + +PWM + + + + + +3.3V + + + +Host PC +vJoy + Python + + + +BT From fcdf0d9c3adeed80bfc571f21892d2b13cb7ece0 Mon Sep 17 00:00:00 2001 From: Vlad Ene Date: Tue, 12 May 2026 20:26:15 +0300 Subject: [PATCH 3/5] Documentation - fix schematic.svg --- .../version-acs_cc/project/2026/vlad_mihnea.ene/index.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/website/versioned_docs/version-acs_cc/project/2026/vlad_mihnea.ene/index.md b/website/versioned_docs/version-acs_cc/project/2026/vlad_mihnea.ene/index.md index bdb763da8b1..4b2c8043f23 100644 --- a/website/versioned_docs/version-acs_cc/project/2026/vlad_mihnea.ene/index.md +++ b/website/versioned_docs/version-acs_cc/project/2026/vlad_mihnea.ene/index.md @@ -101,4 +101,4 @@ mounted on an open **acrylic plate** (~200×150 mm) using M3 standoffs and screw 1. [link](https://example.com) 2. [link](https://example3.com) -... \ No newline at end of file +... From d1bf6010ed65c02506555f106568aab697fc2bc6 Mon Sep 17 00:00:00 2001 From: Vlad Ene Date: Wed, 13 May 2026 17:40:13 +0300 Subject: [PATCH 4/5] Documentation - add new schematic --- .../project/2026/vlad_mihnea.ene/index.md | 16 ++- .../2026/vlad_mihnea.ene/schematic.svg | 108 +----------------- 2 files changed, 15 insertions(+), 109 deletions(-) diff --git a/website/versioned_docs/version-acs_cc/project/2026/vlad_mihnea.ene/index.md b/website/versioned_docs/version-acs_cc/project/2026/vlad_mihnea.ene/index.md index 4b2c8043f23..9fae999d2ad 100644 --- a/website/versioned_docs/version-acs_cc/project/2026/vlad_mihnea.ene/index.md +++ b/website/versioned_docs/version-acs_cc/project/2026/vlad_mihnea.ene/index.md @@ -49,20 +49,26 @@ over I²C. A coin vibration motor driven via PWM through an N-MOSFET provides ha ### 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 +project compilation for the STM32 Nucleo-U545RE-Q target. + ### Week 12 - 18 May +Tested all hardware components individually: analog joystick (ADC), tactile buttons (GPIO), +SSD1306 OLED display (I2C), HC-05 Bluetooth module (USART), and vibration motor (PWM). +All components confirmed working. Created EasyEDA schematic with all connections. + ### Week 19 - 25 May ## Hardware The controller is built around the **STM32 Nucleo-U545RE-Q** (ARM Cortex-M33, 160 MHz). Input -comes from two **KY-023 analog joystick modules** connected to four ADC channels and six +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 **coin vibration motor** driven by a -**2N7000 MOSFET** provides rumble feedback. Power comes from a **3.7 V LiPo battery** managed -by a **TP4056 charging module** and a **3.3 V AMS1117 LDO regulator**. All components are -mounted on an open **acrylic plate** (~200×150 mm) using M3 standoffs and screws. +via I²C and shows battery level and connection status. A **PWM vibration motor module** +(3–5V, with integrated driver) provides rumble feedback. ## Schematics diff --git a/website/versioned_docs/version-acs_cc/project/2026/vlad_mihnea.ene/schematic.svg b/website/versioned_docs/version-acs_cc/project/2026/vlad_mihnea.ene/schematic.svg index 65e89b085ea..7f214d5e57e 100644 --- a/website/versioned_docs/version-acs_cc/project/2026/vlad_mihnea.ene/schematic.svg +++ b/website/versioned_docs/version-acs_cc/project/2026/vlad_mihnea.ene/schematic.svg @@ -1,105 +1,5 @@ - -RustPad Hardware Schematic - \ No newline at end of file From 489f3bb03d3b918d7c6e0b48c65359c19f8d07ec Mon Sep 17 00:00:00 2001 From: Vlad Ene Date: Wed, 20 May 2026 15:47:40 +0300 Subject: [PATCH 5/5] Update documentation --- .../2026/vlad_mihnea.ene/controller.webp | Bin 0 -> 45424 bytes .../project/2026/vlad_mihnea.ene/index.md | 113 ++++++++++-------- .../2026/vlad_mihnea.ene/schematic.svg | 2 +- 3 files changed, 65 insertions(+), 50 deletions(-) create mode 100644 website/versioned_docs/version-acs_cc/project/2026/vlad_mihnea.ene/controller.webp diff --git a/website/versioned_docs/version-acs_cc/project/2026/vlad_mihnea.ene/controller.webp b/website/versioned_docs/version-acs_cc/project/2026/vlad_mihnea.ene/controller.webp new file mode 100644 index 0000000000000000000000000000000000000000..5a254f2d8d5c1e560897f60803cdeecf14461729 GIT binary patch literal 45424 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 literal 0 HcmV?d00001 diff --git a/website/versioned_docs/version-acs_cc/project/2026/vlad_mihnea.ene/index.md b/website/versioned_docs/version-acs_cc/project/2026/vlad_mihnea.ene/index.md index 9fae999d2ad..41913ce666a 100644 --- a/website/versioned_docs/version-acs_cc/project/2026/vlad_mihnea.ene/index.md +++ b/website/versioned_docs/version-acs_cc/project/2026/vlad_mihnea.ene/index.md @@ -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 @@ -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. All components are mounted on an open breadboard frame. ## Schematics @@ -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) - +| 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/) \ No newline at end of file diff --git a/website/versioned_docs/version-acs_cc/project/2026/vlad_mihnea.ene/schematic.svg b/website/versioned_docs/version-acs_cc/project/2026/vlad_mihnea.ene/schematic.svg index 7f214d5e57e..00e68953646 100644 --- a/website/versioned_docs/version-acs_cc/project/2026/vlad_mihnea.ene/schematic.svg +++ b/website/versioned_docs/version-acs_cc/project/2026/vlad_mihnea.ene/schematic.svg @@ -2,4 +2,4 @@ path, polyline, polygon {stroke-linejoin:round;} rect, circle, ellipse, polyline, line, polygon, path {shape-rendering:crispEdges;} -AAAABBCCDD1122334455TITLE:Sheet_1REV:1.0Date:2026-05-13Sheet:1/1Drawn By:Ene Vlad-MihneaCompany:Your CompanyKY-023_TLMD1GND1VCC2VRX3VRY4SW5KY-023WIRELESS-BLUETOOTH-HC-051STATE1RX2TX3GND4+5V5EN6Vibration MotorM1IN3VCC2GND1VIBRATION MOTORSSD1306U2SDA1SCL2VCC3GND4button2C3A1button3C3A1button4C3A1button5C3A1button6C3A1Nucleo STM32F401REU3PC10001PC12003VDD005BOOT0007NC009NC011PA13013PA14015PA15017GND019PB7021PC13023PC14025PC15027PH0029PH1031VBAT033PC2035PC3037PC11002PD2004E5V006GND008NC010IOREF012RESET0143V30165V018GND020GND022VIN024NC026PA0028PA1030PA4032PB0034PC1036PC0038PC9101PB8103PB9105AVDD107GND109PA5111PA6113PA7115PB6117PC7119PA9121PA8123PB10125PB4127PB5129PB3131PA10133PA2135PA3137PC8102PC6104PC5106U5V108NC110PA12112PA11114PB12116NC118GND120PB2122PB1124PB15126PB14128PB13130AGND132PC4134NC136NC138 \ No newline at end of file +AAAABBCCDD1122334455TITLE:Sheet_1REV:1.0Date:2026-05-13Sheet:1/1Drawn By:Ene Vlad-MihneaCompany:Your CompanyKY-023_TLMD1GND1VCC2VRX3VRY4SW5KY-023WIRELESS-BLUETOOTH-HC-051STATE1RX2TX3GND4+5V5EN6Vibration MotorM1IN3VCC2GND1VIBRATION MOTORSSD1306U2SDA1SCL2VCC3GND4button2C3A1button3C3A1button4C3A1button5C3A1button6C3A1Nucleo STM32F401REU3PC10001PC12003VDD005BOOT0007NC009NC011PA13013PA14015PA15017GND019PB7021PC13023PC14025PC15027PH0029PH1031VBAT033PC2035PC3037PC11002PD2004E5V006GND008NC010IOREF012RESET0143V30165V018GND020GND022VIN024NC026PA0028PA1030PA4032PB0034PC1036PC0038PC9101PB8103PB9105AVDD107GND109PA5111PA6113PA7115PB6117PC7119PA9121PA8123PB10125PB4127PB5129PB3131PA10133PA2135PA3137PC8102PC6104PC5106U5V108NC110PA12112PA11114PB12116NC118GND120PB2122PB1124PB15126PB14128PB13130AGND132PC4134NC136NC138 \ No newline at end of file