ERTOtech Refleks Lite Arcade Stick

This directory contains the hardware and firmware files for the ERTOtech Refleks Lite arcade stick project.

codespid/
├── ArcadeStick_hardware/     PCB and hardware design files
└── arcadestick_software/     STM32 firmware, bootloader, and USB code

Architecture

The board uses an STM32F103RBT6. Its 128 KB flash is divided into three regions:

Region Start address Size USB VID:PID
Bootloader / DFU 0x08000000 24 KB 1209:E667
App1 / XInput 0x08006000 52 KB 1209:E668
App2 / DInput 0x08013000 52 KB 1209:E669

The USB manufacturer string is ERTOtech.

Boot and firmware selection

The bootloader runs after every reset, reads the slide switch, and jumps to the selected application's vector table.

The current electrical switch logic is:

  • PA4 LOW, PA5 HIGH: run XInput App1.
  • PA4 HIGH, PA5 LOW: run DInput App2.
  • If both inputs have the same level, the selection is invalid and DFU starts.
  • Holding START during reset starts DFU regardless of the switch position.
  • If the selected application's stack pointer or reset vector is invalid, the bootloader remains in DFU mode.

When the switch is moved while an application is running, the new state must remain stable for 50 ms. USB is then stopped, the firmware waits 100 ms, and calls NVIC_SystemReset(). After reset, the bootloader starts the application selected by the new switch position.

DInput application

DInput runs as a standard USB HID game pad. Its input report is 9 bytes:

Bytes 0..1: 11 buttons plus padding
Byte 2:      4-bit hat switch plus padding
Bytes 3..8: X, Y, Z, Rx, Ry, and Rz (unsigned 8-bit axes)

The neutral hat value is 8; directions use HID hat-switch values 0..7. The six neutral axis values are 0x80. Physical buttons are active LOW and use GPIO pull-ups. Button 11 is present in the descriptor but is not connected to a physical input.

The DInput USB configuration contains three interfaces:

Interface Purpose Endpoints Behavior
IF0 Gamepad HID 0x81 IN Functional 9-byte input reports
IF1 Setup HID 0x82 IN, 0x02 OUT Compatibility stub
IF2 Raw HID 0x83 IN Compatibility stub

The Setup and Raw report descriptors match the original device layout, but the original configuration protocol is not implemented. Unsupported control requests are stalled, unused IN endpoints remain at NAK, and Setup OUT data is accepted and discarded.

XInput application

XInput uses a vendor-specific Xbox 360 wired-controller interface:

Interface class    : 0xFF
Interface subclass : 0x5D
Interface protocol : 0x01
IN endpoint         : 0x81, interrupt, 64 bytes
OUT endpoint        : 0x02, interrupt, 64 bytes
Input report        : 20 bytes

The 20-byte input report carries the D-pad, Start, Back, A/B/X/Y, LB/RB, and digital LT/RT values. LT and RT send 0xFF while pressed and 0x00 while released. Eight-byte rumble packets received through the OUT endpoint are parsed and the left/right motor values are stored. Unless motor outputs are connected, those values remain software-only.

The XInput configuration also exposes Setup HID on IF1 (0x83 IN and 0x03 OUT) and Raw HID on IF2 (0x84 IN). These are compatibility stubs with the same behavior described for DInput.

There are no Microsoft OS, compatible-ID, MSFT100, or WinUSB descriptors in the XInput application. Windows currently binds IF0 to xusb22.inf by its class/subclass/protocol match. Xbox console authentication is not implemented; the target is Windows/PC.

GPIO mapping

All arcade inputs are active LOW and configured with pull-ups.

Function Pin
Up PC0
Down PC1
Right PC2
Left PC3
A PC4
B PC5
Y PC6
X PC7
RB PC8
RT PC9
LB PC10
LT PC11
Start PC14
Select / Back PA2
Switch input 1 PA4
Switch input 2 PA5
USB D- PA11
USB D+ PA12

Building

The project uses the VS Code STM32Cube and CMake tools. In VS Code, press Ctrl+Shift+B and run CMake: build to build the bootloader, both applications, and the combined package.

The CMake presets can also be used from a terminal:

cube-cmake --preset Debug
cube-cmake --build --preset Debug

cube-cmake --preset Release
cube-cmake --build --preset Release

Main CMake targets:

Target Description
arcadestick_bootloader USB DFU bootloader
arcadestick_xinput App1 XInput firmware
arcadestick App2 DInput firmware
arcadestick_package Combines all three firmware images into one BIN/HEX

Each firmware target produces .elf, .hex, and .bin files.

Initial programming

For a blank MCU, program the following combined image with an ST-Link:

arcadestick_software/build/Release/arcadestick_full.hex

This HEX contains the bootloader, XInput App1, and DInput App2 at their correct flash addresses. The combined BIN is exactly 128 KB:

arcadestick_software/build/Release/arcadestick_full.bin

Updating with USB DFU

To enter DFU, hold START while resetting the board. The USB device appears as ERTOtech Refleks Lite DFU with VID:PID 1209:E667.

The bootloader uses standard DFU 1.1 and does not use DfuSe address commands. Select the destination firmware with the alternate interface number:

# Update XInput App1
dfu-util -d 1209:e667 -a 0 `
  -D arcadestick_software/build/Release/arcadestick_xinput.bin

# Update DInput App2
dfu-util -d 1209:e667 -a 1 `
  -D arcadestick_software/build/Release/arcadestick.bin
  • -a 0 writes only the XInput slot.
  • -a 1 writes only the DInput slot.
  • The bootloader region cannot be written through DFU.
  • Data is received in 1024-byte blocks. The corresponding 1 KB flash page is erased and programmed as half-words.
  • A zero-length DFU packet at the end of the download completes the update. The bootloader resets after approximately 100 ms.
  • The slide switch's current position, not the downloaded file, determines which application runs after reset.

Windows driver setup

This DFU bootloader does not expose Microsoft OS or automatic WinUSB descriptors. On each Windows computer, WinUSB must therefore be installed once for Refleks Lite DFU (1209:E667) before dfu-util can access the device.

Use Zadig as follows:

  1. Start the board in DFU mode and open Zadig.
  2. Select Options > List All Devices.
  3. Select only Refleks Lite DFU (1209:E667).
  4. Select WinUSB as the target driver and click Install Driver.

Do not replace the drivers of the XInput (1209:E668), DInput (1209:E669), ST-Link, or any other USB device. The Zadig operation is required only once per Windows computer unless the driver is later removed. dfu-util must also be installed and available in PATH.

If an update is interrupted, hold START during reset to re-enter DFU. This simple bootloader does not provide atomic or power-fail-safe updates; do not remove power while an update is in progress.

Debugging with VS Code

The Run and Debug list contains:

  • STM32: Debug Arcade Stick (ST-Link): DInput App2
  • STM32: Debug Arcade Stick XInput (ST-Link): XInput App1
  • STM32: Debug Arcade Stick Bootloader (ST-Link): bootloader

The applications no longer begin at the start of flash. The bootloader must already be programmed before debugging App1 or App2. While debugging the bootloader, hold START to prevent it from jumping immediately to an app and to keep execution in main().

Place XInput breakpoints in XInput_AppProcess() in Core/Src/xinput_app.c. Place DInput breakpoints in DInput_AppProcess() in Core/Src/dinput_app.c.

CubeMX code generation

The main CubeMX project file is:

arcadestick_software/arcadestick.ioc

The custom DInput, XInput, and DFU classes are stored in project-owned source files. The root CMakeLists.txt replaces CubeMX's single-interface HID application source list with the custom composite DInput sources. No post-generation repair script is required.

Important source files

File Purpose
Core/Src/bootloader_main.c Boot selection, app validation, and jump
Core/Src/main.c Shared app startup and switch reset control
Core/Src/xinput_app.c XInput button/report mapping
Core/Src/dinput_app.c DInput button/report mapping
USB_DEVICE/App/usbd_xinput.c Composite XInput USB class and rumble OUT handling
USB_DEVICE/App/usbd_dinput.c Composite DInput USB class
USB_DEVICE/App/usbd_dfu_bootloader.c DFU state machine and flash programming
STM32F103xx_FLASH.ld Parameterized flash/RAM linker layout
CMakeLists.txt Bootloader, App1, App2, and package targets
tools/package_firmware.ps1 Creates the combined 128 KB firmware package

Known limitations

  • Do not distribute products with these PID values until they are formally assigned by pid.codes.
  • Xbox console authentication/security is not implemented.
  • The Setup and Raw HID interfaces are compatibility stubs; the original device configuration protocol is not implemented.
  • The XInput application does not expose Microsoft OS or compatible-ID descriptors.
  • DFU has no redundant image or rollback protection against power loss.
  • Do not confuse the switch signal names with the observed LOW pins: on the current board, XInput is PA4 LOW and DInput is PA5 LOW.

Licensing

  • Project-authored firmware: MIT License
  • Hardware design sources: CERN-OHL-P-2.0
  • STM32 HAL, CMSIS, and other third-party components: their respective upstream licenses

See the root LICENSE file and the component-specific license files for the complete terms.

Description
No description provided
Readme 2.7 MiB
Languages
C 99.2%
CMake 0.5%
Assembly 0.3%