Repository navigation
4. Wheel Emulator
The wheel emulator replaces the original STM32-based wheel PCB and emulates the T248 communication protocol using a Raspberry Pi Pico (RP2040). Other 3.3 V microcontrollers may be used, but voltage compatibility must be ensured to avoid damaging the wheelbase.
Its primary purpose is to allow fully custom-built steering wheels to operate with a stock T248 wheelbase.
The development process was intentionally iterative, allowing features to be reverse-engineered and validated step by step:
- V1.x – incremental versions for testing individual protocol features
- V2.0 – the first fully functional, stable wheel emulator
Earlier in the project, a separate USB-only custom wheel implementation was created.
Implements:
- Startup sequence
- Periodic keep-alive messages
- Button state messages
This version prevents the wheelbase from continuously generating phantom DPAD-Up inputs when no wheel is connected.
Hardware notes:
- UART RX/TX must be connected to the wheelbase
- Wheelbase 3.3 V is connected to GPIO 11 as an enable signal
(external pull-down resistor required) - The Pico must be powered before the wheelbase
- The Pico must be connected to a separate USB port for power
Adds interactive button control via the USB serial console.
Commands:
-
'1'–'10','13','22','23'→ normal buttons -
'dr','du','dl','dd'→ DPAD directions -
'elu','eld','eru','erd'→ encoder directions
(example:elu= encoder left up) -
'display'→ display button -
'mode'→ mode button
Using the Display and Mode buttons can modify wheel settings
without visual feedback. Use with caution.
At this stage, buttons were toggled.
This caused encoder-related inputs (eru, erd) to appear as
periodic pulses in Windows after some time.
Introduces:
-
void sendButtons(bool full)function
Behavior:
-
full = true→ sends both B0 and B1 frames -
full = false→ sends only B0
Additionally, the B0 frame is transmitted immediately after a serial command.
Implements:
- UART receive state machine to parse multiple frame types
- Buttons are now momentary presses (100 ms) instead of toggles
- Screen data is forwarded to the serial console for debugging
- Encoder data decoding based on selected bits from the F3 frame
Changes:
- Switched from
uart1 (Serial2)touart0 (Serial1)to match an existing USB steering wheel design - Wheelbase reset line is now used to control Pico startup
Reset signal inversion:
- Wheelbase RESET is active high
- Pico RUN pin is active low
Implemented using a BC548B NPN transistor:
- Collector → Pico RUN
- Emitter → GND
- Base → wheelbase RESET via 10 kΩ resistor
Additionally:
- Implemented responses to screen data frames
(no observable effect on wheelbase behavior)
Adds:
- Physical rotary encoder as encoder input
- 32×128 OLED display to show current encoder layer
Encoder layers renamed to:
- TC
- ABS
- BB
- ECU
(The Display EXP encoder position is not used.)
Required libraries:
Adds:
- Validation of the wheelbase acknowledgment after startup
- If not received, the Pico reboots
(Note: likely redundant, as the wheelbase usually requires a reboot as well.)
Implements:
- Timeout-based reset of the UART receive state machine
- Prevents lock-ups caused by incomplete or corrupted frames
Adds support for:
- Buttons 1–10, 13, 22, 23
- Full DPAD support
Details:
- Buttons 1 and 2 use interrupts (preferred for shift paddles)
- I²C pins changed to GPIO 8 and 9
Finalized version with:
- Shortened interrupt service routines
- Fixed multiple potential race conditions and edge cases
- Added preprocessor flag
DEBUG- Allows all debug output and serial commands to be disabled
This version is considered the first working emulator and is suitable for use with a custom-built steering wheel.
Required libraries:
And the arduino-pico core from earlephilhower
USB-only custom steering wheel implementation.
Characteristics:
- Based on V1.8 logic
- Enumerates as a USB gamepad using the Joystick library
Known limitations:
- Long interrupt service routines
- Not as optimized as V2.0
Despite these drawbacks, it worked reliably for multiple month.
Needed Components:
- Raspberry Pi Pico or Pico 2
- SSD1306 32x128 I2C OLED display
- Rotary encoder breakout board
- NPN BJT Transistor eg. BC548 or similar
- Buttons
- for debounce circuit 10 kΩ pull-up + 100 nF capacitor
- Some Resistors for Transistor, Uart TX and Pull-up
Notes:
- Every button should have an debouncing circuit, because there is no software debouncing (exept the Encoder Button).
- The button mappings can be changed in the code. These button mapping show my implementation for my wheel.
- The not connected pin in the wheelbase connector is the PA14 pin, which is probably only used during firmware update of the original wheel.
- The pullup resistors for the encoder are already on most encoder breakout boards.
For protocol details see:
For hardware mapping see: