FreeJoy, firmware that turns a cheap board into a configurable game controller
STM32F103 USB HID game device controller with flexible configuration
At a glance
- What is it?
- FreeJoy is firmware for the inexpensive STM32F103C8 board that lets you build your own HOTAS, pedal set or steering wheel, or reconfigure one you bought. It reads axes, buttons, encoders and position sensors and reports them over USB HID, and the configuration lives in a separate Qt utility.
- Who is it for?
- FreeJoy fits a sim racing or flight hobbyist who wants a device shaped for their own controls, or who owns a commercial wheel or HOTAS whose layout they would rather change, because the input map is defined in software rather than baked into the hardware.
- Can I use it commercially?
- Yes, with conditions. GPL-3.0 is a copyleft licence: if you distribute software that includes it, you must release that software's source code under the same licence. Running it internally without distributing it does not trigger that obligation.
- Is it still maintained?
- Activity is slowing. The repository last received commits 6 months ago.
- What is it written in?
- Mainly C, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 21, 2026, and from our analysis. They are not legal advice.
Editorial analysis
A controller whose shape you decide
FreeJoy is a game device controller built on the cheap STM32F103C8 microcontroller board, and the point of it is configurability. You can build your own HOTAS, your own pedals, your own steering wheel, or take a device you bought and change how it behaves. The input hardware is ordinary and inexpensive, and the personality of the device lives in the firmware, which is what makes the project interesting. It reports itself to the host as a USB HID device, so a game or a simulator sees a joystick, and the device name and other USB settings are configurable too. The audience is the sim racing and flight simulation hobbyist, and the second audience is the person with a commercial controller whose button layout does not fit them and who would rather reconfigure it than buy another one.
Eight analog axes and 128 digital inputs
The external periphery list is the spec sheet. There are 8 analog inputs with 12 bit output resolution, and 128 digital inputs for buttons, toggle switches, hat POVs and encoders, plus 5 shift modifiers and 4 hat POVs, with 16 incremental encoders on the digital side. Two shift register families, the 74HC165 and the CD4021, let a large number of buttons be read over few pins, which is how 128 inputs fits on a small board. The mapping between physical inputs and what the host sees is bidirectional. An axis can be turned into buttons, up to 12 buttons per axis, and buttons and encoders can be turned into axis movement, which is how a hat switch or a single toggle can drive a steering axis. The design point is that the input surface is fixed and the mapping is a matter of configuration, so the same board serves a wheel with a dozen axes and a panel with a hundred switches.
Position sensors, external ADCs and a lot of LEDs
The list of supported devices covers three families. There are digital position sensors, namely the TLE5010 and TLE5011, the TLE5012B, the AS5048A, the AS5600 and the MLX90393, and the whole sensor list is marked as SPI interface only, which is a real constraint if you were planning to read it over I2C. There are external ADCs, the ADS1115 and the MCP3201, MCP3202, MCP3204 and MCP3208, which is how you read extra analog sensors beyond the eight built in channels. And there is an output side for lighting, with 4 PWM channels and 24 LEDs that can be single or matrix and bound to button states or driven by host software. On top of that there are up to 50 addressable LEDs, either ws2812b or pl9823, with effects and the ability to be controlled through SimHub. For a device whose purpose is to be looked at while you use it, that lighting support is not a gimmick, it is what makes the hardware feel finished.
Every axis carries its own processing chain
The per axis settings are where the firmware does its real work, and the README lists them in full. An axis has a source and a destination, and the destinations are the standard HID set, X, Y, Z, Rx, Ry, Rz, Slider1 and Slider2. Each axis can be enabled or disabled, has its own resolution, and can be calibrated manually or automatically. There are 7 levels of smoothing, so the filter strength is a per axis choice rather than a global one. Inversion and deadband are configurable, with the deadband available in dynamic or centre form, and there is an axis offset option described as the magnet offset, which is how a magnetic sensor is zeroed. Curve shaping lets you change the response of a spring-loaded axis, and there are functions for combined axes, buttons derived from axes, and axes derived from buttons and encoders. The takeaway for an evaluator is that the mapping is not a simple pin to axis table. Each channel is a small processing chain, and the configuration file is where those chains are written down.
Ten ways to interpret a digital input
Digital inputs are configured as a type, and the README lists the types. A regular push button and an inverted push button are the obvious pair. Then there are three toggle variants, toggle switch ON/OFF, toggle ON and toggle OFF, which differ in what the host sees when the switch changes position. There is a POV hat button type, an incremental encoder input type, radio buttons, and sequential buttons, and the five shifts, which are the modifiers that let one physical control stand in for several. Inputs can also be wired in other shapes, as single inputs tied to VCC or GND, as button matrices, through the shift register inputs, and through the axis to buttons inputs, which is the mapping in the opposite direction. Taken together, the digital side is a small logic language rather than a set of pins, and the type list is the clearest evidence that the project is aimed at people building panels, not people wiring a single joystick.
Firmware, flashing and a separate configurator
The repository is the firmware and its toolchain. The top level listing shows MDK-ARM/ for the Keil project, SEGGER/ for the debugger tooling, armgcc/ for a GCC based build, a bootloader/ directory, an application/ directory with the code proper, Drivers/ for the microcontroller peripherals, utils/ for helpers, and images/ for artwork used in the documentation. Getting started is documented in a separate wiki, the FreeJoyWiki, which is where the instructions for flashing firmware to a board and configuring the device for an application live. Configuration itself is done with an external tool, the FreeJoy Configurator utility, maintained as its own repository, FreeJoyConfiguratorQt, which is a Qt application. The split matters for anyone evaluating the project, because the firmware and the configuration GUI are two codebases with two release cycles, and a configuration file written by a newer configurator may not mean the same thing to an older firmware. There is no in-firmware configuration screen in this repository.
Release cadence and what a hardware project owes you
The licence is GPL-3.0, which is the right choice for firmware that people flash onto their own boards, since it keeps derived modifications open. The repository is not archived, and the last push was on 2026-04-19. The release history is what gives you pause. The newest tag is v1.7.3b0 from 2026-02-21, and before that come v1.7.1b3 from 2022-01-11 and v1.7.0b3 from 2021-02-15, so there is a long gap between the 1.7.1 build and the 1.7.3 one, with a beta suffix on the newest tag that suggests the line is still settling. The consequence for a hardware project is specific rather than abstract. There is no upstream to patch a newly discovered protocol bug for you, and if a new wheel on the market needs a different axis mapping or a new LED protocol, the fix happens in your own fork. The one thing that makes that tolerable is the scale of the hardware, since the parts are cheap and the firmware is small enough to read.
Editorial conclusion
FreeJoy fits a sim racing or flight hobbyist who wants a device shaped for their own controls, or who owns a commercial wheel or HOTAS whose layout they would rather change, because the input map is defined in software rather than baked into the hardware. It does not fit someone who wants a plug and play controller, since you have to source a board, wire the inputs and flash the firmware, and it does not fit a team that needs a maintained upstream for new hardware, because the releases are infrequent. Verify three things first: that your chosen sensor and encoder parts are on the supported list, including the SPI only magnetic sensors, that the board you have is the STM32F103C8 the project targets, and that the configuration utility you use matches the firmware version you flash, since the two are separate repositories.
Frequently asked questions
What is FreeJoy?
It is a widely configurable game device controller based on the cheap STM32F103C8 microcontroller board, letting you build your own HOTAS, pedals or steering wheel, or customise a purchased one. The device appears to the host as a USB HID joystick.
How many inputs does FreeJoy support?
8 analog inputs with 12 bit output resolution, up to 128 digital inputs, 4 hat POVs, 16 incremental encoders, 5 shift modifiers, and shift register support for the 74HC165 and CD4021. Axes can also be converted into buttons, up to 12 per axis.
Which sensors and ADCs does FreeJoy support?
Digital position sensors include the TLE5010 and TLE5011, the TLE5012B, the AS5048A, the AS5600 and the MLX90393, where the MLX90393 is SPI interface only. External ADCs include the ADS1115 and the MCP3201, MCP3202, MCP3204 and MCP3208.
How do I configure a FreeJoy device?
Configuration is done with an external utility, the FreeJoy Configurator Qt application, which lives in its own repository. The wiki covers both flashing the firmware to your board and configuring the device for your application.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/freejoy-team-freejoy)Was this useful?