Skip to content

Fix encoder ghost HID output on partial rotation#268

Open
RMSSimRacing wants to merge 3 commits into
FreeJoy-Team:masterfrom
RMSSimRacing:RMSSimRacing-patch-1
Open

Fix encoder ghost HID output on partial rotation#268
RMSSimRacing wants to merge 3 commits into
FreeJoy-Team:masterfrom
RMSSimRacing:RMSSimRacing-patch-1

Conversation

@RMSSimRacing

@RMSSimRacing RMSSimRacing commented May 8, 2026

Copy link
Copy Markdown

Problem

The original encoder implementation had multiple issues:

1. Ghost HID output on partial rotation
When using rotary encoders configured as ENCODER_CONF_1x, a ghost HID output
was generated when the user partially rotated the encoder and released it before
completing the full quadrature cycle.

2. Lost pulses on EC11 encoders
The original code blocked pulses based on time (50ms) and direction history,
causing EC11 encoders to lose steps during normal use.

3. First step lost when changing direction quickly
When rotating in one direction and immediately reversing, the first step in the
new direction was lost.

Root Cause

The original lookup table logic used time-based filtering and direction history
(last_dir) to debounce encoders. This approach works for some encoders but
fails on others, particularly EC11, which has different timing characteristics.

Solution

Replaced the original lookup table with a full quadrature FSM (Finite State
Machine) for ENCODER_CONF_1x and ENCODER_CONF_2x modes.

  • Bounce rejection is handled structurally by the FSM — only complete valid
    quadrature cycles generate HID output
  • Direction changes are detected immediately without losing the first step
  • No time-based filtering that could block valid pulses
  • ENCODER_CONF_4x retains the original enc_array_4 logic, required for encoders
    like the ALPS RKJXT1F42001 that have detents at AB=00

Modified files

  • application/Src/encoders.c — FSM implementation + refactored EmitEncoderPulse
  • application/Inc/common_types.h — added fsm_state field to encoder_state_t

Tested on

  • EC16 configured as ENCODER_CONF_1x ✓
  • EC11 configured as ENCODER_CONF_1x ✓
  • ALPS RKJXT1F42001 configured as ENCODER_CONF_4x ✓

Pre-compiled firmware

Pre-compiled .bin and .hex files are available in the releases section for
direct flashing without the need to compile.

@ArtCodeZen

ArtCodeZen commented May 20, 2026

Copy link
Copy Markdown
Contributor

I also experienced a similar issue.

When I rotated to the right and then quickly rotated to the left, the steering sometimes continued moving to the right.

I tested a small change on line 240:

encoders_state[i].cnt += encoders_state[i].last_dir; // old

changed to:

encoders_state[i].cnt += encoders_state[i].dir; // test works well

After this modification, the behavior became much more stable in my tests and the wrong direction issue seems to be gone.

However, I think your complete modification to the encoder code structure is more appropriate, since it removes obsolete legacy logic and provides a cleaner solution overall.

@RMSSimRacing

Copy link
Copy Markdown
Author

Thank you for the feedback and for testing!

You are right that the last_dir → dir change would fix that specific case,
but the FSM approach addresses the root cause more structurally — no time-based
filtering, no direction history dependency.

Pre-compiled firmware is available for testing:
https://github.com/RMSSimRacing/FreeJoy/releases/tag/encoder-fix-FSM-quadrature

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants