Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Encoder improvements #26501

Merged
merged 15 commits into from
Dec 9, 2023
7 changes: 7 additions & 0 deletions Marlin/Configuration_adv.h
Original file line number Diff line number Diff line change
Expand Up @@ -1583,6 +1583,13 @@
//#define DOUBLE_LCD_FRAMERATE // Not recommended for slow boards.
#endif

//#define BEEP_ON_SCROLL // Beep when any menu is scrolled
#if ENABLED(BEEP_ON_SCROLL)
#define SCROLL_BEEP_DURATION 2
#define SCROLL_BEEP_FREQUENCY 15000
#endif
thinkyhead marked this conversation as resolved.
Show resolved Hide resolved


// The timeout to return to the status screen from sub-menus
//#define LCD_TIMEOUT_TO_STATUS 15000 // (ms)

Expand Down
53 changes: 32 additions & 21 deletions Marlin/src/lcd/marlinui.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
#include "../inc/MarlinConfig.h"

#include "../MarlinCore.h" // for printingIsPaused
#include "src/core/macros.h"

#if LED_POWEROFF_TIMEOUT > 0 || ALL(HAS_WIRED_LCD, PRINTER_EVENT_LEDS) || (defined(LCD_BACKLIGHT_TIMEOUT_MINS) && defined(NEOPIXEL_BKGD_INDEX_FIRST))
#include "../feature/leds/leds.h"
Expand Down Expand Up @@ -67,6 +68,8 @@ MarlinUI ui;

constexpr uint8_t epps = ENCODER_PULSES_PER_STEP;

#define BLOCK_CLICK_AFTER_MOVEMENT_MS 100

#if HAS_STATUS_MESSAGE
#if ENABLED(STATUS_MESSAGE_SCROLLING) && ANY(HAS_WIRED_LCD, DWIN_LCD_PROUI)
uint8_t MarlinUI::status_scroll_offset; // = 0
Expand Down Expand Up @@ -932,6 +935,7 @@ void MarlinUI::init() {
void MarlinUI::update() {

static uint16_t max_display_update_time = 0;
static millis_t last_encoder_full_step_movement = 0;
millis_t ms = millis();

#if LED_POWEROFF_TIMEOUT > 0
Expand Down Expand Up @@ -982,7 +986,12 @@ void MarlinUI::init() {
if (!touch_buttons) {
// Integrated LCD click handling via button_pressed
if (!external_control && button_pressed()) {
if (!wait_for_unclick) do_click(); // Handle the click
if (!wait_for_unclick) {
if (ELAPSED(ms, last_encoder_full_step_movement + BLOCK_CLICK_AFTER_MOVEMENT_MS))
do_click(); // Handle the click
else
wait_for_unclick = true;
}
}
else
wait_for_unclick = false;
Expand Down Expand Up @@ -1019,35 +1028,22 @@ void MarlinUI::init() {
uint8_t abs_diff = ABS(encoderDiff);

#if ENCODER_PULSES_PER_STEP > 1
// When reversing the encoder direction, a movement step can be missed because
// encoderDiff has a non-zero residual value, making the controller unresponsive.
// The fix clears the residual value when the encoder is idle.
// Also check if past half the threshold to compensate for missed single steps.
static int8_t lastEncoderDiff;

// Timeout? No decoder change since last check. 10 or 20 times per second.
if (encoderDiff == lastEncoderDiff && abs_diff <= epps / 2) // Same direction & size but not over a half-step?
encoderDiff = 0; // Clear residual pulses.
else if (WITHIN(abs_diff, epps / 2 + 1, epps - 1)) { // Past half of threshold?
abs_diff = epps; // Treat as a full step size
encoderDiff = (encoderDiff < 0 ? -1 : 1) * abs_diff; // ...in the spin direction.
}
TERN_(HAS_TOUCH_SLEEP, if (lastEncoderDiff != encoderDiff) wakeup_screen());
lastEncoderDiff = encoderDiff;
#endif

const bool encoderPastThreshold = (abs_diff >= epps);
if (encoderPastThreshold || lcd_clicked) {
if (encoderPastThreshold) {
if (encoderPastThreshold && TERN1(IS_TFTGLCD_PANEL, !external_control)) {

#if ALL(HAS_MARLINUI_MENU, ENCODER_RATE_MULTIPLIER)

int32_t encoderMultiplier = 1;

if (encoderRateMultiplierEnabled) {
const float encoderMovementSteps = float(abs_diff) / epps;

if (lastEncoderMovementMillis) {
const float encoderMovementSteps = float(abs_diff) / epps;
// Note that the rate is always calculated between two passes through the
// loop and that the abs of the encoderDiff value is tracked.
const float encoderStepRate = encoderMovementSteps / float(ms - lastEncoderMovementMillis) * 1000;
Expand Down Expand Up @@ -1076,9 +1072,23 @@ void MarlinUI::init() {

#endif // ENCODER_RATE_MULTIPLIER

if (can_encode()) encoderPosition += (encoderDiff * encoderMultiplier) / epps;

encoderDiff = 0;
const int8_t fullSteps = encoderDiff / epps;
if (fullSteps != 0) {
static int8_t lastDir;
int8_t dir = SIGN(fullSteps);
if (encoderMultiplier != 1 && dir != lastDir) {
// Changed direction at high speed.
// This is most likely an artifact of skipped steps, keep previous direction instead.
encoderMultiplier *= -1;
} else {
lastDir = dir;
}
last_encoder_full_step_movement = ms;
encoderDiff -= fullSteps * epps;
if (can_encode() && !lcd_clicked) {
encoderPosition += (fullSteps * encoderMultiplier);
}
}
}

reset_status_timeout(ms);
Expand Down Expand Up @@ -1393,9 +1403,10 @@ void MarlinUI::init() {

#if HAS_ENCODER_WHEEL
static uint8_t lastEncoderBits;
bool ignore = false;

// Manage encoder rotation
#define ENCODER_SPIN(_E1, _E2) switch (lastEncoderBits) { case _E1: encoderDiff += encoderDirection; break; case _E2: encoderDiff -= encoderDirection; }
#define ENCODER_SPIN(_E1, _E2) switch (lastEncoderBits) { case _E1: encoderDiff += encoderDirection; break; case _E2: encoderDiff -= encoderDirection; break; default: ignore = true; }

uint8_t enc = 0;
if (buttons & EN_A) enc |= B01;
Expand All @@ -1410,7 +1421,7 @@ void MarlinUI::init() {
#if ALL(HAS_MARLINUI_MENU, AUTO_BED_LEVELING_UBL)
external_encoder();
#endif
lastEncoderBits = enc;
if (!ignore) lastEncoderBits = enc;
}

#endif // HAS_ENCODER_WHEEL
Expand Down
7 changes: 7 additions & 0 deletions Marlin/src/lcd/menu/menu.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -269,6 +269,13 @@ void scroll_screen(const uint8_t limit, const bool is_menu) {
}
else
encoderTopLine = encoderLine;
#ifdef BEEP_ON_SCROLL
static int8_t last_encoderLine = encoderLine;
if (encoderLine != last_encoderLine) {
BUZZ(SCROLL_BEEP_DURATION, SCROLL_BEEP_FREQUENCY);
last_encoderLine = encoderLine;
}
#endif
}

#if HAS_LINE_TO_Z
Expand Down
1 change: 1 addition & 0 deletions buildroot/tests/mega2560
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ opt_enable AUTO_BED_LEVELING_UBL AVOID_OBSTACLES RESTORE_LEVELING_AFTER_G28 DEBU
EMERGENCY_PARSER MULTI_NOZZLE_DUPLICATION CLASSIC_JERK LIN_ADVANCE ADVANCE_K_EXTRA QUICK_HOME \
SET_PROGRESS_MANUALLY SET_PROGRESS_PERCENT PRINT_PROGRESS_SHOW_DECIMALS SHOW_REMAINING_TIME \
ENCODER_NOISE_FILTER BABYSTEPPING BABYSTEP_XY NANODLP_Z_SYNC I2C_POSITION_ENCODERS M114_DETAIL
opt_disable ENCODER_RATE_MULTIPLIER
exec_test $1 $2 "Azteeg X3 Pro | EXTRUDERS 5 | RRDFGSC | UBL | LIN_ADVANCE ..." "$3"

#
Expand Down
Loading