Skip to content

Commit d84a78c

Browse files
authored
fix(radio): issues with rotary encoder (#5194)
- detection of initial direction of encoder after startup - change of direction issue on radios with incorrectly wired encoder - handle all wiring variations (without needing special #defines) - handle the case when the radio is started with the encoder not on a detent position
1 parent cc63003 commit d84a78c

File tree

6 files changed

+84
-85
lines changed

6 files changed

+84
-85
lines changed

radio/src/gui/colorlcd/LvglWrapper.cpp

+3-3
Original file line numberDiff line numberDiff line change
@@ -272,14 +272,14 @@ static void rotaryDriverRead(lv_indev_drv_t *drv, lv_indev_data_t *data)
272272
static int8_t prevDir = 0;
273273
static uint32_t lastDt = 0;
274274

275-
rotenc_t newPos = rotaryEncoderGetRawValue();
276-
rotenc_t diff = (newPos - prevPos) / ROTARY_ENCODER_GRANULARITY;
277-
prevPos += diff * ROTARY_ENCODER_GRANULARITY;
275+
rotenc_t newPos = rotaryEncoderGetValue();
276+
rotenc_t diff = newPos - prevPos;
278277

279278
data->enc_diff = (int16_t)diff;
280279
data->state = LV_INDEV_STATE_RELEASED;
281280

282281
if (diff != 0) {
282+
prevPos = newPos;
283283
reset_inactivity();
284284

285285
int8_t dir = 0;

radio/src/hal/rotary_encoder.h

-4
Original file line numberDiff line numberDiff line change
@@ -40,9 +40,5 @@ void rotaryEncoderInit();
4040
// return impulses / granularity
4141
rotenc_t rotaryEncoderGetValue();
4242

43-
// returns raw # impulses
44-
rotenc_t rotaryEncoderGetRawValue();
45-
46-
4743
int8_t rotaryEncoderGetAccel();
4844
void rotaryEncoderResetAccel();

radio/src/targets/common/arm/stm32/rotary_encoder_driver.cpp

+81-69
Original file line numberDiff line numberDiff line change
@@ -35,106 +35,114 @@
3535
#include "opentx.h"
3636
#endif
3737

38+
#if ROTARY_ENCODER_GRANULARITY == 2
39+
#define ON_DETENT(p) ((p == 3) || (p == 0))
40+
#elif ROTARY_ENCODER_GRANULARITY == 4
41+
#define ON_DETENT(p) (p == 3)
42+
#elif
43+
#error "Unknown ROTARY_ENCODER_GRANULARITY"
44+
#endif
45+
3846
volatile rotenc_t rotencValue = 0;
3947
volatile uint32_t rotencDt = 0;
4048

41-
#if defined(BOOT)
42-
#define INC_ROT 1
43-
#define INC_ROT_2 2
44-
#else
45-
#define INC_ROT \
46-
(g_eeGeneral.rotEncMode == ROTARY_ENCODER_MODE_INVERT_BOTH ? -1 : 1);
47-
#define INC_ROT_2 \
48-
(g_eeGeneral.rotEncMode == ROTARY_ENCODER_MODE_INVERT_BOTH ? -2 : 2);
49-
#endif
49+
// Last encoder pins state
50+
static uint8_t lastPins = 0;
51+
// Record encoder position change between detents
52+
int8_t reChgPos = 0;
53+
// Used on start to ignore movement until encoder position on detent
54+
bool skipUntilDetent = false;
5055

5156
rotenc_t rotaryEncoderGetValue()
52-
{
53-
return rotencValue / ROTARY_ENCODER_GRANULARITY;
54-
}
55-
56-
rotenc_t rotaryEncoderGetRawValue()
5757
{
5858
return rotencValue;
5959
}
6060

6161
void rotaryEncoderCheck()
6262
{
63-
static uint8_t state = 0;
64-
static uint8_t re_count = 0;
63+
// Value increment for each state transition of the RE pins
64+
#if defined(ROTARY_ENCODER_INVERTED)
65+
static int8_t reInc[4][4] = {
66+
// Prev = 0
67+
{ 0, -1, 1, -2 },
68+
// Prev = 1
69+
{ 1, 0, 0, -1 },
70+
// Prev = 2
71+
{ -1, 0, 0, 1 },
72+
// Prev = 3
73+
{ 2, 1, -1, 0 },
74+
};
75+
#else
76+
static int8_t reInc[4][4] = {
77+
// Prev = 0
78+
{ 0, 1, -1, 2 },
79+
// Prev = 1
80+
{ -1, 0, 0, 1 },
81+
// Prev = 2
82+
{ 1, 0, 0, -1 },
83+
// Prev = 3
84+
{ -2, -1, 1, 0 },
85+
};
86+
#endif
87+
6588
uint8_t pins = ROTARY_ENCODER_POSITION();
6689

67-
#if defined(ROTARY_ENCODER_SUPPORT_BUGGY_WIRING)
68-
if (pins != (state & 0x03) && !(readKeys() & (1 << KEY_ENTER))) {
69-
if (re_count == 0) {
70-
// Need at least 2 values to correctly determine initial direction
71-
re_count = 1;
72-
} else {
73-
if ((pins ^ (state & 0x03)) == 0x03) {
74-
if (pins == 3) {
75-
rotencValue += INC_ROT_2;
76-
} else {
77-
rotencValue -= INC_ROT_2;
78-
}
79-
} else {
80-
if ((state & 0x01) ^ ((pins & 0x02) >> 1)) {
81-
rotencValue -= INC_ROT;
82-
} else {
83-
rotencValue += INC_ROT;
84-
}
85-
}
86-
87-
if (re_count == 1)
88-
{
89-
re_count = 2;
90-
// Assume 1st value is same direction as 2nd value
91-
rotencValue = rotencValue * 2;
92-
}
90+
// No change - do nothing
91+
if (pins == lastPins) {
92+
return;
93+
}
94+
95+
// Handle case where radio started with encoder not on detent position
96+
if (skipUntilDetent) {
97+
if (ON_DETENT(pins)) {
98+
lastPins = pins;
99+
skipUntilDetent = false;
93100
}
94-
state &= ~0x03;
95-
state |= pins;
101+
return;
96102
}
97-
#else
98-
if (pins != state && !(readKeys() & (1 << KEY_ENTER))) {
99-
if (re_count == 0) {
100-
// Need at least 2 values to correctly determine initial direction
101-
re_count = 1;
102-
} else {
103-
#if defined(ROTARY_ENCODER_INVERTED)
104-
if (!(state & 0x01) ^ ((pins & 0x02) >> 1)) {
105-
#else
106-
if ((state & 0x01) ^ ((pins & 0x02) >> 1)) {
103+
104+
// Get increment value for pin state transition
105+
int inc = reInc[lastPins][pins];
106+
107+
#if !defined(BOOT)
108+
if (g_eeGeneral.rotEncMode == ROTARY_ENCODER_MODE_INVERT_BOTH)
109+
inc = -inc;
107110
#endif
108-
rotencValue -= INC_ROT;
109-
} else {
110-
rotencValue += INC_ROT;
111-
}
112-
113-
if (re_count == 1)
114-
{
115-
re_count = 2;
116-
// Assume 1st value is same direction as 2nd value
117-
rotencValue = rotencValue * 2;
118-
}
111+
112+
// Update position change between detents
113+
reChgPos += inc;
114+
115+
// Update reported value on full detent change
116+
if (reChgPos >= ROTARY_ENCODER_GRANULARITY) {
117+
// If ENTER pressed - ignore scrolling
118+
if ((readKeys() & (1 << KEY_ENTER)) == 0) {
119+
rotencValue += 1;
120+
}
121+
reChgPos -= ROTARY_ENCODER_GRANULARITY;
122+
} else if (reChgPos <= -ROTARY_ENCODER_GRANULARITY) {
123+
// If ENTER pressed - ignore scrolling
124+
if ((readKeys() & (1 << KEY_ENTER)) == 0) {
125+
rotencValue -= 1;
119126
}
120-
state = pins;
127+
reChgPos += ROTARY_ENCODER_GRANULARITY;
121128
}
122-
#endif
129+
130+
lastPins = pins;
123131

124132
#if !defined(BOOT) && defined(COLORLCD)
125133
static uint32_t last_tick = 0;
126134
static rotenc_t last_value = 0;
127135

128136
rotenc_t value = rotencValue;
129-
rotenc_t diff = (value - last_value) / ROTARY_ENCODER_GRANULARITY;
137+
rotenc_t diff = (value - last_value);
130138

131139
if (diff != 0) {
132140
uint32_t now = RTOS_GET_MS();
133141
uint32_t dt = now - last_tick;
134142
// pre-compute accumulated dt (dx/dt is done later in LVGL driver)
135143
rotencDt += dt;
136144
last_tick = now;
137-
last_value += diff * ROTARY_ENCODER_GRANULARITY;
145+
last_value = value;
138146
}
139147
#endif
140148
}
@@ -181,6 +189,10 @@ void rotaryEncoderInit()
181189

182190
NVIC_EnableIRQ(ROTARY_ENCODER_TIMER_IRQn);
183191
NVIC_SetPriority(ROTARY_ENCODER_TIMER_IRQn, 7);
192+
193+
// Get initial position
194+
lastPins = ROTARY_ENCODER_POSITION();
195+
skipUntilDetent = !ON_DETENT(lastPins);
184196
}
185197

186198
extern "C" void ROTARY_ENCODER_TIMER_IRQHandler(void)

radio/src/targets/horus/hal.h

-4
Original file line numberDiff line numberDiff line change
@@ -111,10 +111,6 @@
111111
#define ROTARY_ENCODER_INVERTED
112112
#endif
113113

114-
#if defined(RADIO_FAMILY_T16) && !defined(RADIO_T18) && !defined(RADIO_T15)
115-
#define ROTARY_ENCODER_SUPPORT_BUGGY_WIRING
116-
#endif
117-
118114
// Switches
119115
#if defined(RADIO_T15)
120116
#define STORAGE_SWITCH_A

radio/src/targets/simu/simpgmspace.cpp

-2
Original file line numberDiff line numberDiff line change
@@ -63,8 +63,6 @@ rotenc_t rotaryEncoderGetValue()
6363
return rotencValue / ROTARY_ENCODER_GRANULARITY;
6464
}
6565

66-
rotenc_t rotaryEncoderGetRawValue() { return rotencValue; }
67-
6866
// TODO: remove all STM32 defs
6967

7068
extern const etx_hal_adc_driver_t simu_adc_driver;

radio/src/targets/taranis/hal.h

-3
Original file line numberDiff line numberDiff line change
@@ -303,9 +303,6 @@
303303
#define USE_EXTI15_10_IRQ
304304
#define EXTI15_10_IRQ_Priority 5
305305
#endif
306-
#if defined(RADIO_TX12)
307-
#define ROTARY_ENCODER_SUPPORT_BUGGY_WIRING
308-
#endif
309306
#if defined(RADIO_TX12MK2) || defined(RADIO_BOXER) || defined(RADIO_ZORRO) || defined(RADIO_MT12) || defined(RADIO_POCKET) || defined(RADIO_T14)
310307
#define ROTARY_ENCODER_INVERTED
311308
#endif

0 commit comments

Comments
 (0)