diff --git a/website/versioned_docs/version-acs_cc/project/2026/mihai.topa/index.md b/website/versioned_docs/version-acs_cc/project/2026/mihai.topa/index.md index 36f1828afe4..7156331385a 100644 --- a/website/versioned_docs/version-acs_cc/project/2026/mihai.topa/index.md +++ b/website/versioned_docs/version-acs_cc/project/2026/mihai.topa/index.md @@ -21,9 +21,9 @@ The controller features: - **4 face buttons** (A, B, X, Y) - **D-Pad** (4 directions) - **Shoulder buttons** (L1, R1) -- **System buttons** (Start, Select, Home) - **Vibration motor** for haptic feedback, PWM-controlled - USB-C powered — no batteries needed +- Fully recognized by **Steam** (Steam Input) — all axes, buttons, and triggers work correctly I initially planned a two-microcontroller architecture (STM32 + ESP32-C3) communicating over Bluetooth LE, but decided against it — coordinating BLE HID between two microcontrollers turned out to be quite complex. The final design uses a **single STM32 Nucleo-U545RE-Q** that reads all inputs and connects directly to the host as a USB HID gamepad. @@ -41,14 +41,14 @@ As an avid gamer, I wanted to understand how a controller works from the ground ┌─────────────────────────────────────────────────────────────┐ │ INPUT LAYER │ │ [Joystick L] [Joystick R] [Trigger L] [Trigger R] │ -│ [Buttons x18] [Vibration Motor] │ +│ [Buttons x12] [Vibration Motor] │ └───────────────────────┬─────────────────────────────────────┘ │ ADC / GPIO / PWM ▼ ┌─────────────────────────────────────────────────────────────┐ │ STM32 Nucleo-U545RE-Q │ │ - Reads ADC: 4 joystick axes + 2 triggers │ -│ - Reads GPIO: 18 buttons │ +│ - Reads GPIO: 12 buttons │ │ - Controls vibration motor via PWM │ │ - Acts as USB HID Gamepad │ └───────────────────────┬─────────────────────────────────────┘ @@ -77,6 +77,7 @@ As an avid gamer, I wanted to understand how a controller works from the ground - Wired the potentiometers for the analog triggers. - Wired the vibration motor and tested PWM control. - Full integration test. +- Added the controller to Steam and configured it using Steam Input. Steam correctly detects all axes, buttons, and triggers. The controller is fully functional in Steam. --- @@ -88,9 +89,9 @@ As an avid gamer, I wanted to understand how a controller works from the ground The only microcontroller in the project. Reads all inputs, controls the vibration motor, and communicates with the host via USB HID. - 6 ADC channels: Joystick L (X, Y), Joystick R (X, Y), Trigger L, Trigger R -- 18 GPIO pins for buttons -- 1 PWM output for the vibration motor -- USB Full Speed via USB-C (CN3) to the host +- 12 GPIO pins for buttons +- 1 PWM output for the vibration motor (TIM3 CH1) +- USB Full Speed via USB-C (PA11/PA12) to the host - Powered via USB-C; provides 3.3V on Morpho pins (CN7) for peripherals #### 2. Analog Joysticks PS2 Module (×2) @@ -99,8 +100,8 @@ Standard XY joystick modules with integrated push-button (L3/R3). Each module: V - VRx/VRy → 2 ADC channels per joystick - SW → GPIO with internal pull-up -#### 3. Tactile Buttons 12×12mm (×20) -A, B, X, Y, L1, R1, Start, Select, Home, D-Pad ×4, L3, R3 + 2 spare. +#### 3. Tactile Buttons 12×12mm (×12) +A, B, X, Y, L1, R1, D-Pad ×4, L3, R3. - Wired between GPIO and GND, internal pull-up enabled in firmware @@ -135,32 +136,45 @@ The schematic covers the following connections: **Joysticks (×2)** | Signal | STM32 Pin | |--------|-----------| -| Joystick L — VRx | ADC channel (TBD) | -| Joystick L — VRy | ADC channel (TBD) | -| Joystick L — SW | GPIO (TBD) | -| Joystick R — VRx | ADC channel (TBD) | -| Joystick R — VRy | ADC channel (TBD) | -| Joystick R — SW | GPIO (TBD) | +| Joystick L — VRx | PA0 (ADC1) | +| Joystick L — VRy | PA1 (ADC1) | +| Joystick L — SW (L3) | PB13 | +| Joystick R — VRx | PA4 (ADC1) | +| Joystick R — VRy | PB0 (ADC1) | +| Joystick R — SW (R3) | PB14 | **Triggers (×2)** | Signal | STM32 Pin | |--------|-----------| -| Trigger L — wiper | ADC channel (TBD) | -| Trigger R — wiper | ADC channel (TBD) | +| Trigger L2 — wiper | PC1 (ADC1) | +| Trigger R2 — wiper | PC0 (ADC1) | -**Buttons (×18)** +**Buttons (×12)** | Button | STM32 Pin | |--------|-----------| -| A, B, X, Y | GPIO (TBD) | -| L1, R1 | GPIO (TBD) | -| Start, Select, Home | GPIO (TBD) | -| D-Pad ×4 | GPIO (TBD) | -| L3, R3 | GPIO (TBD) | +| A | PA3 | +| B | PA2 | +| X | PC6 | +| Y | PB10 | +| L1 | PC9 | +| R1 | PC10 | +| D-Up | PB8 | +| D-Down | PA8 | +| D-Left | PC8 | +| D-Right | PC7 | +| L3 | PB13 | +| R3 | PB14 | **Vibration Motor** | Signal | STM32 Pin | |--------|-----------| -| PWM control | TIM channel (TBD) | +| PWM control | PB4 (TIM3 CH1) | + +**USB** +| Signal | STM32 Pin | +|--------|-----------| +| USB D- | PA11 | +| USB D+ | PA12 | --- @@ -170,26 +184,47 @@ The schematic covers the following connections: |--------|-------|-------| | STM32 Nucleo-U545RE-Q | Main microcontroller + USB HID | ~110 RON *(owned)* | | Joystick Module 2-Axis XY ×2 | Left + right joystick with L3/R3 | 5.45 RON × 2 | -| Tactile Button PCB 12×12×7.3mm ×20 | A, B, X, Y, D-Pad, L1, R1, Start, Select, Home | 1.33 RON × 20 | +| Tactile Button PCB 12×12×7.3mm ×12 | A, B, X, Y, D-Pad ×4, L1, R1, L3, R3 | 1.33 RON × 12 | | Linear Potentiometer Module 10K ×2 | Analog triggers L2 and R2 | 12.52 RON × 2 | | Vibration Motor Module DC PWM 3–5V | Haptic feedback | 5.36 RON | -| Breadboard 400p ×3 | Prototyping base | 6.62 RON × 3 | +| Breadboard 800p ×1 | Prototyping base | ~14 RON | | Dupont Wire 30cm M-M ×2 (40pcs/set) | Breadboard connections | 8.39 RON × 2 | | Dupont Wire 30cm M-F ×1 (40pcs/set) | Module connections | 7.59 RON | | Ceramic Capacitor Set 300pcs | VCC / ADC decoupling | 12.55 RON | | Resistor Kit 30 values 600pcs | Pull-up / protection | 15.16 RON | -| | Subtotal (components) | 139.84 RON | +| | Subtotal (components) | 123.34 RON | | | Delivery | 15.15 RON | -| | **Total (cart incl. VAT)** | **154.99 RON** | -| | **Grand Total (incl. Nucleo)** | **~265 RON** | +| | **Total (cart incl. VAT)** | **138.49 RON** | +| | **Grand Total (incl. Nucleo)** | **~248 RON** | --- ## Software -*(To be developed)* +Firmware is written in **Rust** using the **Embassy** async framework for STM32. + +### Key components + +- **USB HID** — `embassy-usb` with a custom 8-byte gamepad report descriptor (12 buttons + 4 axes + 2 triggers). The device presents itself as a Game Pad (Usage Page 0x01, Usage 0x05) for maximum OS compatibility. +- **ADC** — `embassy-stm32` ADC1, blocking reads at ~19.5 cycles sample time. Raw 14-bit values mapped to signed 8-bit axis values via `adc_to_axis()`. +- **GPIO** — 12 buttons, active-low with internal pull-up. Press events detected on falling edge (bit was 0, now 1). +- **PWM** — TIM3 CH1 on PB4 drives the vibration motor. Duty cycle: 100% when R2 trigger is maxed out, 70% for 500 ms every 10 seconds otherwise. +- **Clocks** — HSI @ 16 MHz for the CPU; HSI48 (synced from USB SOF) for the USB peripheral; SYS clock routed to ADC. + +### HID report layout (8 bytes) + +| Byte | Content | +|------|---------| +| 0 | Buttons 0–7 (A, B, X, Y, L1, R1, D-Up, D-Down) | +| 1 | Buttons 8–11 (D-Left, D-Right, L3, R3) + 4-bit padding | +| 2 | LX axis (i8) | +| 3 | LY axis (i8) | +| 4 | RX axis (i8) | +| 5 | RY axis (i8) | +| 6 | L2 trigger (u8, 0–255) | +| 7 | R2 trigger (u8, 0–255) | -Firmware will be written in **Rust** using the **Embassy** async framework for STM32. Implementation details will be added as development progresses. +The main loop runs at ~200 Hz (5 ms `Timer::after`). USB HID and USB stack are joined as two concurrent async tasks via `embassy-futures::join`. --- diff --git a/website/versioned_docs/version-acs_cc/project/2026/mihai.topa/schematic.svg b/website/versioned_docs/version-acs_cc/project/2026/mihai.topa/schematic.svg index 0b62b75f25c..ac749a1cedc 100644 --- a/website/versioned_docs/version-acs_cc/project/2026/mihai.topa/schematic.svg +++ b/website/versioned_docs/version-acs_cc/project/2026/mihai.topa/schematic.svg @@ -1 +1 @@ - \ No newline at end of file +SVG Image created as Schematic.svg date 2026-05-17T13:53:06 Image generated by Eeschema-SVG123456123456ABCDABCDDate:KiCad E.D.A. 10.0.1Rev:Size: A4Id: 1/1Title:File: schematic.kicad_schSheet: /SW3XPWR_FLAGGND+3V3+3V3+3V3+3V3+3V3+3V3SW7D-UpGNDGNDGNDSW12R3VBAT1PC132PC143PC154PH05PH16NRST7PC08PC19PC210PC311VSSA12VDDA13PA014PA115PA216PA317VSS18VDD19PA420PA521PA622PA723PC424PC525PB026PB127PB228PB1029VCAP30VDD32PB1233PB1334PB1435PB1536PC637PC738PC839PC940PA841PA942PA1043PA1144PA1245PA1346VDDUSB48PA1449PA1550PC1051PC1152PC1253PD254PB355PB456PB557PB658PB759PH360PB861PB962VDD64U1STM32U545RETxGNDGNDPWR_FLAG123J5Vibration_Motor+3V3SW4YGNDGNDSW1B+3V3GNDGNDSW11L3GNDGND+3V3123J3Trigger_L2123J4Trigger_R2SW9D-LeftGNDSW2ASW8D-DownGNDGNDSW10D-Right+3V3+3V3GND12345J2Joystick_Right12345J1Joystick_LeftGNDSW6R1GNDSW5L1GNDSW1B+3V3GNDGNDSW2ASW8D-DownGNDGND+3V3J2Joystick_Right12345J1Joystick_Left12345GNDSW3XGNDSW5L1GNDSW6R1GND+3V3GNDSW10D-RightGNDSW9D-LeftJ4Trigger_R2123J3Trigger_L2123+3V3GNDGNDSW11L3GNDGNDSW4Y+3V3J5Vibration_Motor123PWR_FLAGGNDGNDU1STM32U545RETxVBAT1PC132PC143PC154PH05PH16NRST7PC08PC19PC210PC311VSSA12VDDA13PA014PA115PA216PA317VSS18VDD19PA420PA521PA622PA723PC424PC525PB026PB127PB228PB1029VCAP30VDD32PB1233PB1334PB1435PB1536PC637PC738PC839PC940PA841PA942PA1043PA1144PA1245PA1346VDDUSB48PA1449PA1550PC1051PC1152PC1253PD254PB355PB456PB557PB658PB759PH360PB861PB962VDD64SW12R3GNDGNDGNDSW7D-Up+3V3+3V3+3V3+3V3+3V3+3V3PWR_FLAG