diff --git a/Marlin/src/inc/Conditionals_LCD.h b/Marlin/src/inc/Conditionals_LCD.h index a3756217e660..2a8c02f912a6 100644 --- a/Marlin/src/inc/Conditionals_LCD.h +++ b/Marlin/src/inc/Conditionals_LCD.h @@ -893,10 +893,11 @@ #endif #endif -// FSMC/SPI TFT Panels (LVGL) +// FSMC/SPI TFT Panels (LVGL) with encoder click wheel #if ENABLED(TFT_LVGL_UI) #define HAS_TFT_LVGL_UI 1 #define SERIAL_RUNTIME_HOOK 1 + #define STD_ENCODER_PULSES_PER_STEP 4 #endif // FSMC/SPI TFT Panels @@ -976,6 +977,17 @@ #define DETECT_I2C_LCD_DEVICE 1 #endif +/** + * Ender-3 V2 DWIN with Encoder + */ +#if ANY(DWIN_CREALITY_LCD, DWIN_LCD_PROUI) + #define HAS_DWIN_E3V2_BASIC 1 +#endif +#if ANY(HAS_DWIN_E3V2_BASIC, DWIN_CREALITY_LCD_JYERSUI) + #define HAS_DWIN_E3V2 1 + #define STD_ENCODER_PULSES_PER_STEP 4 +#endif + // Encoder behavior #ifndef STD_ENCODER_PULSES_PER_STEP #if ENABLED(TOUCH_SCREEN) @@ -997,10 +1009,12 @@ #define ENCODER_FEEDRATE_DEADZONE 6 #endif -// Shift register panels -// --------------------- -// 2 wire Non-latching LCD SR from: -// https://github.com/fmalpartida/New-LiquidCrystal/wiki/schematics#user-content-ShiftRegister_connection +/** + * Shift register panels + * --------------------- + * 2 wire Non-latching LCD SR from: + * https://github.com/fmalpartida/New-LiquidCrystal/wiki/schematics#user-content-ShiftRegister_connection + */ #if ENABLED(FF_INTERFACEBOARD) #define SR_LCD_3W_NL // Non latching 3 wire shift register #define IS_ULTIPANEL 1 @@ -1040,11 +1054,6 @@ #define EXTENSIBLE_UI #endif -// Aliases for LCD features -#if ANY(DWIN_CREALITY_LCD, DWIN_LCD_PROUI, DWIN_CREALITY_LCD_JYERSUI) - #define HAS_DWIN_E3V2 1 -#endif - // E3V2 extras #if HAS_DWIN_E3V2 || IS_DWIN_MARLINUI #define SERIAL_CATCHALL 0 diff --git a/Marlin/src/lcd/buttons.h b/Marlin/src/lcd/buttons.h index 601e8a70ae05..2bd5fd7b35ef 100644 --- a/Marlin/src/lcd/buttons.h +++ b/Marlin/src/lcd/buttons.h @@ -24,9 +24,9 @@ #include "../inc/MarlinConfig.h" #if ((!HAS_ADC_BUTTONS && IS_NEWPANEL) || BUTTONS_EXIST(EN1, EN2)) && !IS_TFTGLCD_PANEL - #define HAS_ENCODER_WHEEL 1 + #define HAS_MARLINUI_ENCODER 1 #endif -#if (HAS_ENCODER_WHEEL || ANY_BUTTON(ENC, BACK, UP, DOWN, LEFT, RIGHT)) && DISABLED(TOUCH_UI_FTDI_EVE) +#if (HAS_MARLINUI_ENCODER || ANY_BUTTON(ENC, BACK, UP, DOWN, LEFT, RIGHT)) && DISABLED(TOUCH_UI_FTDI_EVE) #define HAS_DIGITAL_BUTTONS 1 #endif #if !HAS_ADC_BUTTONS && (IS_RRW_KEYPAD || (HAS_WIRED_LCD && !IS_NEWPANEL)) diff --git a/Marlin/src/lcd/e3v2/common/encoder.cpp b/Marlin/src/lcd/e3v2/common/encoder.cpp index 5825fb0f7753..889d1c61f3f5 100644 --- a/Marlin/src/lcd/e3v2/common/encoder.cpp +++ b/Marlin/src/lcd/e3v2/common/encoder.cpp @@ -42,10 +42,6 @@ #include -#ifndef ENCODER_PULSES_PER_STEP - #define ENCODER_PULSES_PER_STEP 4 -#endif - EncoderRate encoderRate; // TODO: Replace with ui.quick_feedback @@ -53,32 +49,12 @@ void Encoder_tick() { TERN_(HAS_BEEPER, if (ui.sound_on) buzzer.click(10)); } -// Encoder initialization -void encoderConfiguration() { - #if BUTTON_EXISTS(EN1) - SET_INPUT_PULLUP(BTN_EN1); - #endif - #if BUTTON_EXISTS(EN2) - SET_INPUT_PULLUP(BTN_EN2); - #endif - #if BUTTON_EXISTS(ENC) - SET_INPUT_PULLUP(BTN_ENC); - #endif - #if HAS_BEEPER - SET_OUTPUT(BEEPER_PIN); // TODO: Use buzzer.h which already inits this - #endif -} - // Analyze encoder value and return state EncoderState encoderReceiveAnalyze() { const millis_t now = millis(); - static uint8_t lastEncoderBits; - uint8_t newbutton = 0; - static signed char temp_diff = 0; + static int8_t temp_diff = 0; // Cleared on each full step, as configured EncoderState temp_diffState = ENCODER_DIFF_NO; - if (BUTTON_PRESSED(EN1)) newbutton |= EN_A; - if (BUTTON_PRESSED(EN2)) newbutton |= EN_B; if (BUTTON_PRESSED(ENC)) { static millis_t next_click_update_ms; if (ELAPSED(now, next_click_update_ms)) { @@ -98,71 +74,47 @@ EncoderState encoderReceiveAnalyze() { } else return ENCODER_DIFF_NO; } - if (newbutton != lastEncoderBits) { - switch (newbutton) { - case 0: - if (lastEncoderBits == 1) temp_diff++; - else if (lastEncoderBits == 2) temp_diff--; - break; - case 2: - if (lastEncoderBits == 0) temp_diff++; - else if (lastEncoderBits == 3) temp_diff--; - break; - case 3: - if (lastEncoderBits == 2) temp_diff++; - else if (lastEncoderBits == 1) temp_diff--; - break; - case 1: - if (lastEncoderBits == 3) temp_diff++; - else if (lastEncoderBits == 0) temp_diff--; - break; - } - lastEncoderBits = newbutton; - } - if (ABS(temp_diff) >= ENCODER_PULSES_PER_STEP) { - if (temp_diff > 0) temp_diffState = TERN(REVERSE_ENCODER_DIRECTION, ENCODER_DIFF_CCW, ENCODER_DIFF_CW); - else temp_diffState = TERN(REVERSE_ENCODER_DIRECTION, ENCODER_DIFF_CW, ENCODER_DIFF_CCW); + temp_diff += ui.get_encoder_delta(); + + const int8_t abs_diff = ABS(temp_diff); + if (abs_diff >= ENCODER_PULSES_PER_STEP) { + temp_diffState = temp_diff > 0 + ? TERN(REVERSE_ENCODER_DIRECTION, ENCODER_DIFF_CCW, ENCODER_DIFF_CW) + : TERN(REVERSE_ENCODER_DIRECTION, ENCODER_DIFF_CW, ENCODER_DIFF_CCW); + + int32_t encoder_multiplier = 1; #if ENABLED(ENCODER_RATE_MULTIPLIER) - millis_t ms = millis(); - int32_t encoder_multiplier = 1; + const millis_t ms = millis(); - // if must encoder rati multiplier + // Encoder rate multiplier if (encoderRate.enabled) { - const float abs_diff = ABS(temp_diff), - encoderMovementSteps = abs_diff / (ENCODER_PULSES_PER_STEP); - if (encoderRate.lastEncoderTime) { - // Note that the rate is always calculated between two passes through the - // loop and that the abs of the temp_diff value is tracked. - const float encoderStepRate = encoderMovementSteps / float(ms - encoderRate.lastEncoderTime) * 1000; - if (ENCODER_100X_STEPS_PER_SEC > 0 && encoderStepRate >= ENCODER_100X_STEPS_PER_SEC) - encoder_multiplier = 100; - else if (ENCODER_10X_STEPS_PER_SEC > 0 && encoderStepRate >= ENCODER_10X_STEPS_PER_SEC) - encoder_multiplier = 10; - else if (ENCODER_5X_STEPS_PER_SEC > 0 && encoderStepRate >= ENCODER_5X_STEPS_PER_SEC) - encoder_multiplier = 5; - } + // Note that the rate is always calculated between two passes through the + // loop and that the abs of the temp_diff value is tracked. + const float encoderStepRate = ((float(abs_diff) / float(ENCODER_PULSES_PER_STEP)) * 1000.0f) / float(ms - encoderRate.lastEncoderTime); encoderRate.lastEncoderTime = ms; + if (ENCODER_100X_STEPS_PER_SEC > 0 && encoderStepRate >= ENCODER_100X_STEPS_PER_SEC) + encoder_multiplier = 100; + else if (ENCODER_10X_STEPS_PER_SEC > 0 && encoderStepRate >= ENCODER_10X_STEPS_PER_SEC) + encoder_multiplier = 10; + else if (ENCODER_5X_STEPS_PER_SEC > 0 && encoderStepRate >= ENCODER_5X_STEPS_PER_SEC) + encoder_multiplier = 5; } - #else - - constexpr int32_t encoder_multiplier = 1; - #endif - // encoderRate.encoderMoveValue += (temp_diff * encoder_multiplier) / (ENCODER_PULSES_PER_STEP); - encoderRate.encoderMoveValue = (temp_diff * encoder_multiplier) / (ENCODER_PULSES_PER_STEP); - if (encoderRate.encoderMoveValue < 0) encoderRate.encoderMoveValue = -encoderRate.encoderMoveValue; + encoderRate.encoderMoveValue = abs_diff * encoder_multiplier / (ENCODER_PULSES_PER_STEP); temp_diff = 0; } + if (temp_diffState != ENCODER_DIFF_NO) { TERN_(HAS_BACKLIGHT_TIMEOUT, ui.refresh_backlight_timeout()); if (!ui.backlight) ui.refresh_brightness(); } + return temp_diffState; } diff --git a/Marlin/src/lcd/e3v2/common/encoder.h b/Marlin/src/lcd/e3v2/common/encoder.h index ce431c9811b1..428193ca658c 100644 --- a/Marlin/src/lcd/e3v2/common/encoder.h +++ b/Marlin/src/lcd/e3v2/common/encoder.h @@ -47,9 +47,6 @@ typedef enum { #define ENCODER_WAIT_MS TERN(DWIN_LCD_PROUI, 10, 20) -// Encoder initialization -void encoderConfiguration(); - // Analyze encoder value and return state EncoderState encoderReceiveAnalyze(); diff --git a/Marlin/src/lcd/e3v2/creality/dwin.cpp b/Marlin/src/lcd/e3v2/creality/dwin.cpp index 9ecfbfe1faed..7f057137d8a0 100644 --- a/Marlin/src/lcd/e3v2/creality/dwin.cpp +++ b/Marlin/src/lcd/e3v2/creality/dwin.cpp @@ -4078,7 +4078,6 @@ void hmiInit() { } void dwinInitScreen() { - encoderConfiguration(); hmiInit(); hmiSetLanguageCache(); hmiStartFrame(true); diff --git a/Marlin/src/lcd/e3v2/jyersui/dwin.cpp b/Marlin/src/lcd/e3v2/jyersui/dwin.cpp index a29f5fc42fb5..c9191dd31df3 100644 --- a/Marlin/src/lcd/e3v2/jyersui/dwin.cpp +++ b/Marlin/src/lcd/e3v2/jyersui/dwin.cpp @@ -5143,7 +5143,6 @@ void MarlinUI::init_lcd() { if (dwinHandshake()) SERIAL_ECHOLNPGM("ok."); else SERIAL_ECHOLNPGM("error."); dwinFrameSetDir(1); // Orientation 90° dwinUpdateLCD(); // Show bootscreen (first image) - encoderConfiguration(); for (uint16_t t = 0; t <= 100; t += 2) { dwinIconShow(ICON, ICON_Bar, 15, 260); dwinDrawRectangle(1, COLOR_BG_BLACK, 15 + t * 242 / 100, 260, 257, 280); diff --git a/Marlin/src/lcd/e3v2/proui/dwin.cpp b/Marlin/src/lcd/e3v2/proui/dwin.cpp index 4c5f91e03222..a89554149482 100644 --- a/Marlin/src/lcd/e3v2/proui/dwin.cpp +++ b/Marlin/src/lcd/e3v2/proui/dwin.cpp @@ -1909,7 +1909,6 @@ void MarlinUI::init_lcd() { const bool hs = dwinHandshake(); UNUSED(hs); dwinFrameSetDir(1); dwinJPGCacheTo1(Language_English); - encoderConfiguration(); } void dwinInitScreen() { diff --git a/Marlin/src/lcd/extui/mks_ui/tft_lvgl_configuration.cpp b/Marlin/src/lcd/extui/mks_ui/tft_lvgl_configuration.cpp index a10d0119f0e9..f8dda5bd7b93 100644 --- a/Marlin/src/lcd/extui/mks_ui/tft_lvgl_configuration.cpp +++ b/Marlin/src/lcd/extui/mks_ui/tft_lvgl_configuration.cpp @@ -216,7 +216,6 @@ void tft_lvgl_init() { tft_style_init(); filament_pin_setup(); - lv_encoder_pin_init(); #if ENABLED(MKS_WIFI_MODULE) mks_esp_wifi_init(); @@ -331,12 +330,12 @@ bool my_touchpad_read(lv_indev_drv_t * indev_driver, lv_indev_data_t * data) { } int16_t enc_diff = 0; -lv_indev_state_t state = LV_INDEV_STATE_REL; +lv_indev_state_t indev_enc_state = LV_INDEV_STATE_REL; // ENC button is pressed or released bool my_mousewheel_read(lv_indev_drv_t * indev_drv, lv_indev_data_t * data) { - (void) indev_drv; // Unused + UNUSED(indev_drv); - data->state = state; + data->state = indev_enc_state; data->enc_diff = enc_diff; enc_diff = 0; @@ -446,101 +445,49 @@ lv_fs_res_t sd_tell_cb(lv_fs_drv_t * drv, void * file_p, uint32_t * pos_p) { return LV_FS_RES_OK; } -void lv_encoder_pin_init() { - #if BUTTON_EXISTS(EN1) - SET_INPUT_PULLUP(BTN_EN1); +void lv_update_encoder() { + + #if ANY_BUTTON(EN1, EN2) + constexpr uint8_t epps = ENCODER_PULSES_PER_STEP; // We can fill in + static uint8_t pulse_count; + pulse_count += ui.get_encoder_delta(); + const int8_t fullSteps = pulse_count / epps; + pulse_count -= fullSteps * epps; + enc_diff += fullSteps; #endif - #if BUTTON_EXISTS(EN2) - SET_INPUT_PULLUP(BTN_EN2); + + #if ANY_BUTTON(ENC, BACK, UP, DOWN, LEFT, RIGHT) + static millis_t last_encoder_ms; + const millis_t now = millis(), diffTime = getTickDiff(now, last_encoder_ms); + if (diffTime <= 50) return; #endif + #if BUTTON_EXISTS(ENC) - SET_INPUT_PULLUP(BTN_ENC); + static uint8_t old_button_enc = LV_INDEV_STATE_REL; + const uint8_t enc_c = BUTTON_PRESSED(ENC) ? LV_INDEV_STATE_PR : LV_INDEV_STATE_REL; + if (enc_c != old_button_enc) { + indev_enc_state = enc_c ? LV_INDEV_STATE_PR : LV_INDEV_STATE_REL; + old_button_enc = enc_c; + } #endif #if BUTTON_EXISTS(BACK) - SET_INPUT_PULLUP(BTN_BACK); + if (BUTTON_PRESSED(BACK)) {} #endif - #if BUTTON_EXISTS(UP) - SET_INPUT(BTN_UP); + if (BUTTON_PRESSED(UP)) {} #endif #if BUTTON_EXISTS(DOWN) - SET_INPUT(BTN_DOWN); + if (BUTTON_PRESSED(DOWN)) {} #endif #if BUTTON_EXISTS(LEFT) - SET_INPUT(BTN_LEFT); + if (BUTTON_PRESSED(LEFT)) {} #endif #if BUTTON_EXISTS(RIGHT) - SET_INPUT(BTN_RIGHT); + if (BUTTON_PRESSED(RIGHT)) {} #endif -} - -#if 1 // HAS_ENCODER_ACTION - - void lv_update_encoder() { - static uint32_t encoder_time1; - uint32_t tmpTime, diffTime = 0; - tmpTime = millis(); - diffTime = getTickDiff(tmpTime, encoder_time1); - if (diffTime > 50) { - - #if HAS_ENCODER_WHEEL - - #if ANY_BUTTON(EN1, EN2, ENC, BACK) - - uint8_t newbutton = 0; - if (BUTTON_PRESSED(EN1)) newbutton |= EN_A; - if (BUTTON_PRESSED(EN2)) newbutton |= EN_B; - if (BUTTON_PRESSED(ENC)) newbutton |= EN_C; - if (BUTTON_PRESSED(BACK)) newbutton |= EN_D; - - #else - - constexpr uint8_t newbutton = 0; - - #endif - - static uint8_t buttons = 0; - buttons = newbutton; - static uint8_t lastEncoderBits; - - #define encrot0 0 - #define encrot1 1 - #define encrot2 2 - - uint8_t enc = 0; - if (buttons & EN_A) enc |= B01; - if (buttons & EN_B) enc |= B10; - if (enc != lastEncoderBits) { - switch (enc) { - case encrot1: - if (lastEncoderBits == encrot0) { - enc_diff--; - encoder_time1 = tmpTime; - } - break; - case encrot2: - if (lastEncoderBits == encrot0) { - enc_diff++; - encoder_time1 = tmpTime; - } - break; - } - lastEncoderBits = enc; - } - static uint8_t last_button_state = LV_INDEV_STATE_REL; - const uint8_t enc_c = (buttons & EN_C) ? LV_INDEV_STATE_PR : LV_INDEV_STATE_REL; - if (enc_c != last_button_state) { - state = enc_c ? LV_INDEV_STATE_PR : LV_INDEV_STATE_REL; - last_button_state = enc_c; - } - - #endif // HAS_ENCODER_WHEEL - - } // encoder_time1 - } -#endif // HAS_ENCODER_ACTION +} #ifdef __PLAT_NATIVE_SIM__ #include diff --git a/Marlin/src/lcd/extui/mks_ui/tft_lvgl_configuration.h b/Marlin/src/lcd/extui/mks_ui/tft_lvgl_configuration.h index d847cfb1933b..43e82bd34dd6 100644 --- a/Marlin/src/lcd/extui/mks_ui/tft_lvgl_configuration.h +++ b/Marlin/src/lcd/extui/mks_ui/tft_lvgl_configuration.h @@ -41,7 +41,6 @@ bool my_touchpad_read(lv_indev_drv_t * indev_driver, lv_indev_data_t * data); bool my_mousewheel_read(lv_indev_drv_t * indev_drv, lv_indev_data_t * data); void lcdClear(uint16_t color); -void lv_encoder_pin_init(); void lv_update_encoder(); lv_fs_res_t spi_flash_open_cb(lv_fs_drv_t * drv, void * file_p, const char * path, lv_fs_mode_t mode); diff --git a/Marlin/src/lcd/marlinui.cpp b/Marlin/src/lcd/marlinui.cpp index dca18f2125ff..a48e1b4ef963 100644 --- a/Marlin/src/lcd/marlinui.cpp +++ b/Marlin/src/lcd/marlinui.cpp @@ -227,34 +227,32 @@ void MarlinUI::init() { init_lcd(); - #if HAS_DIGITAL_BUTTONS - #if BUTTON_EXISTS(EN1) - SET_INPUT_PULLUP(BTN_EN1); - #endif - #if BUTTON_EXISTS(EN2) - SET_INPUT_PULLUP(BTN_EN2); - #endif - #if BUTTON_EXISTS(ENC) - SET_INPUT_PULLUP(BTN_ENC); - #endif - #if BUTTON_EXISTS(ENC_EN) - SET_INPUT_PULLUP(BTN_ENC_EN); - #endif - #if BUTTON_EXISTS(BACK) - SET_INPUT_PULLUP(BTN_BACK); - #endif - #if BUTTON_EXISTS(UP) - SET_INPUT(BTN_UP); - #endif - #if BUTTON_EXISTS(DOWN) - SET_INPUT(BTN_DOWN); - #endif - #if BUTTON_EXISTS(LFT) - SET_INPUT(BTN_LEFT); - #endif - #if BUTTON_EXISTS(RT) - SET_INPUT(BTN_RIGHT); - #endif + #if BUTTON_EXISTS(EN1) + SET_INPUT_PULLUP(BTN_EN1); + #endif + #if BUTTON_EXISTS(EN2) + SET_INPUT_PULLUP(BTN_EN2); + #endif + #if BUTTON_EXISTS(ENC) + SET_INPUT_PULLUP(BTN_ENC); + #endif + #if BUTTON_EXISTS(ENC_EN) + SET_INPUT_PULLUP(BTN_ENC_EN); + #endif + #if BUTTON_EXISTS(BACK) + SET_INPUT_PULLUP(BTN_BACK); + #endif + #if BUTTON_EXISTS(UP) + SET_INPUT(BTN_UP); + #endif + #if BUTTON_EXISTS(DOWN) + SET_INPUT(BTN_DOWN); + #endif + #if BUTTON_EXISTS(LFT) + SET_INPUT(BTN_LEFT); + #endif + #if BUTTON_EXISTS(RT) + SET_INPUT(BTN_RIGHT); #endif #if HAS_SHIFT_ENCODER @@ -1026,72 +1024,56 @@ void MarlinUI::init() { if (TERN0(IS_RRW_KEYPAD, handle_keypad())) reset_status_timeout(ms); - 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. - } - if (lastEncoderDiff != encoderDiff) wake_display(); - lastEncoderDiff = encoderDiff; - #endif + static int8_t lastEncoderDiff; + if (lastEncoderDiff != encoderDiff) wake_display(); + lastEncoderDiff = encoderDiff; + const uint8_t abs_diff = ABS(encoderDiff); const bool encoderPastThreshold = (abs_diff >= epps); - if (encoderPastThreshold || lcd_clicked) { - if (encoderPastThreshold && TERN1(IS_TFTGLCD_PANEL, !external_control)) { - - #if ALL(HAS_MARLINUI_MENU, ENCODER_RATE_MULTIPLIER) - - int32_t encoder_multiplier = 1; - - if (encoder_multiplier_enabled) { - // Note that the rate is always calculated between two passes through the - // loop and that the abs of the encoderDiff value is tracked. - static millis_t encoder_mult_prev_ms = 0; - const float encoderStepRate = ((float(abs_diff) / float(epps)) * 1000.0f) / float(ms - encoder_mult_prev_ms); - encoder_mult_prev_ms = ms; - - if (ENCODER_100X_STEPS_PER_SEC > 0 && encoderStepRate >= ENCODER_100X_STEPS_PER_SEC) - encoder_multiplier = 100; - else if (ENCODER_10X_STEPS_PER_SEC > 0 && encoderStepRate >= ENCODER_10X_STEPS_PER_SEC) - encoder_multiplier = 10; - else if (ENCODER_5X_STEPS_PER_SEC > 0 && encoderStepRate >= ENCODER_5X_STEPS_PER_SEC) - encoder_multiplier = 5; - - // Enable to output the encoder steps per second value - //#define ENCODER_RATE_MULTIPLIER_DEBUG - #if ENABLED(ENCODER_RATE_MULTIPLIER_DEBUG) - SERIAL_ECHO_MSG( - "Enc Step Rate: ", encoderStepRate, - " Mult: ", encoder_multiplier, - " 5X Steps: ", ENCODER_5X_STEPS_PER_SEC, - " 10X Steps: ", ENCODER_10X_STEPS_PER_SEC, - " 100X Steps: ", ENCODER_100X_STEPS_PER_SEC - ); - #endif - } - - #else - - constexpr int32_t encoder_multiplier = 1; - - #endif // ENCODER_RATE_MULTIPLIER + if (encoderPastThreshold && TERN1(IS_TFTGLCD_PANEL, !external_control)) { + + int32_t encoder_multiplier = 1; + + #if ALL(HAS_MARLINUI_MENU, ENCODER_RATE_MULTIPLIER) + + if (encoder_multiplier_enabled) { + // Note that the rate is always calculated between two passes through the + // loop and that the abs of the encoderDiff value is tracked. + static millis_t encoder_mult_prev_ms = 0; + const float encoderStepRate = ((float(abs_diff) / float(epps)) * 1000.0f) / float(ms - encoder_mult_prev_ms); + encoder_mult_prev_ms = ms; + + if (ENCODER_100X_STEPS_PER_SEC > 0 && encoderStepRate >= ENCODER_100X_STEPS_PER_SEC) + encoder_multiplier = 100; + else if (ENCODER_10X_STEPS_PER_SEC > 0 && encoderStepRate >= ENCODER_10X_STEPS_PER_SEC) + encoder_multiplier = 10; + else if (ENCODER_5X_STEPS_PER_SEC > 0 && encoderStepRate >= ENCODER_5X_STEPS_PER_SEC) + encoder_multiplier = 5; + + // Enable to output the encoder steps per second value + //#define ENCODER_RATE_MULTIPLIER_DEBUG + #if ENABLED(ENCODER_RATE_MULTIPLIER_DEBUG) + SERIAL_ECHO_MSG( + "Enc Step Rate: ", encoderStepRate, + " Mult: ", encoder_multiplier, + " 5X Steps: ", ENCODER_5X_STEPS_PER_SEC, + " 10X Steps: ", ENCODER_10X_STEPS_PER_SEC, + " 100X Steps: ", ENCODER_100X_STEPS_PER_SEC + ); + #endif + } - if (can_encode()) encoderPosition += (encoderDiff * encoder_multiplier) / epps; + #endif // ENCODER_RATE_MULTIPLIER - encoderDiff = 0; + const int8_t fullSteps = encoderDiff / epps; + if (fullSteps != 0) { + encoderDiff -= fullSteps * epps; + if (can_encode() && !lcd_clicked) + encoderPosition += (fullSteps * encoder_multiplier); } + } + if (encoderPastThreshold || lcd_clicked) { reset_status_timeout(ms); #if HAS_BACKLIGHT_TIMEOUT @@ -1312,123 +1294,155 @@ void MarlinUI::init() { */ void MarlinUI::update_buttons() { const millis_t now = millis(); - if (ELAPSED(now, next_button_update_ms)) { - #if HAS_DIGITAL_BUTTONS + #if HAS_MARLINUI_ENCODER - #if ANY_BUTTON(EN1, EN2, ENC, BACK) + const int8_t delta = get_encoder_delta(now); + if (delta) { + encoderDiff += delta * encoderDirection; + #if ALL(HAS_MARLINUI_MENU, AUTO_BED_LEVELING_UBL) + external_encoder(); + #endif + } - uint8_t newbutton = 0; - if (BUTTON_PRESSED(EN1)) newbutton |= EN_A; - if (BUTTON_PRESSED(EN2)) newbutton |= EN_B; - if (can_encode() && BUTTON_PRESSED(ENC)) newbutton |= EN_C; - if (BUTTON_PRESSED(BACK)) newbutton |= EN_D; + #endif - #else + if (PENDING(now, next_button_update_ms)) return; + + #if HAS_DIGITAL_BUTTONS + + uint8_t newbuttons = 0; + #if ANY_BUTTON(ENC, BACK) + if (can_encode() && BUTTON_PRESSED(ENC)) newbuttons |= EN_C; + if (BUTTON_PRESSED(BACK)) newbuttons |= EN_D; + #endif + + // + // Directional buttons + // + #if ANY_BUTTON(UP, DOWN, LEFT, RIGHT) + + const int8_t pulses = epps * encoderDirection; + + if (BUTTON_PRESSED(UP)) { + encoderDiff = (ENCODER_STEPS_PER_MENU_ITEM) * pulses; + next_button_update_ms = now + 300; + } + else if (BUTTON_PRESSED(DOWN)) { + encoderDiff = -(ENCODER_STEPS_PER_MENU_ITEM) * pulses; + next_button_update_ms = now + 300; + } + else if (BUTTON_PRESSED(LEFT)) { + encoderDiff = -pulses; + next_button_update_ms = now + 300; + } + else if (BUTTON_PRESSED(RIGHT)) { + encoderDiff = pulses; + next_button_update_ms = now + 300; + } - constexpr uint8_t newbutton = 0; + #endif // UP || DOWN || LEFT || RIGHT + buttons = (newbuttons | TERN0(HAS_SLOW_BUTTONS, slow_buttons) + #if ALL(HAS_TOUCH_BUTTONS, HAS_ENCODER_ACTION) + | (touch_buttons & TERN(HAS_MARLINUI_ENCODER, ~(EN_A | EN_B), 0xFF)) #endif + ); - // - // Directional buttons - // - #if ANY_BUTTON(UP, DOWN, LEFT, RIGHT) + #elif HAS_ADC_BUTTONS - const int8_t pulses = epps * encoderDirection; + buttons = 0; - if (BUTTON_PRESSED(UP)) { - encoderDiff = (ENCODER_STEPS_PER_MENU_ITEM) * pulses; - next_button_update_ms = now + 300; - } - else if (BUTTON_PRESSED(DOWN)) { - encoderDiff = -(ENCODER_STEPS_PER_MENU_ITEM) * pulses; - next_button_update_ms = now + 300; - } - else if (BUTTON_PRESSED(LEFT)) { - encoderDiff = -pulses; - next_button_update_ms = now + 300; - } - else if (BUTTON_PRESSED(RIGHT)) { - encoderDiff = pulses; - next_button_update_ms = now + 300; - } + #endif - #endif // UP || DOWN || LEFT || RIGHT + #if HAS_ADC_BUTTONS + if (keypad_buttons == 0) { + const uint8_t b = get_ADC_keyValue(); + if (WITHIN(b, 1, 8)) keypad_buttons = _BV(b - 1); + } + #endif - buttons = (newbutton | TERN0(HAS_SLOW_BUTTONS, slow_buttons) - #if ALL(HAS_TOUCH_BUTTONS, HAS_ENCODER_ACTION) - | (touch_buttons & TERN(HAS_ENCODER_WHEEL, ~(EN_A | EN_B), 0xFF)) - #endif - ); + #if HAS_SHIFT_ENCODER + /** + * Set up Rotary Encoder bit values (for two pin encoders to indicate movement). + * These values are independent of which pins are used for EN_A / EN_B indications. + * The rotary encoder part is also independent of the LCD chipset. + */ + uint8_t val = 0; + WRITE(SHIFT_LD_PIN, LOW); + WRITE(SHIFT_LD_PIN, HIGH); + for (uint8_t i = 0; i < 8; ++i) { + val >>= 1; + if (READ(SHIFT_OUT_PIN)) SBI(val, 7); + WRITE(SHIFT_CLK_PIN, HIGH); + WRITE(SHIFT_CLK_PIN, LOW); + } + TERN(REPRAPWORLD_KEYPAD, keypad_buttons, buttons) = ~val; + #endif - #elif HAS_ADC_BUTTONS + #if IS_TFTGLCD_PANEL + next_button_update_ms = now + (LCD_UPDATE_INTERVAL / 2); + buttons = slow_buttons; + TERN_(AUTO_BED_LEVELING_UBL, external_encoder()); + #endif - buttons = 0; + } // update_buttons - #endif + #endif // HAS_ENCODER_ACTION - #if HAS_ADC_BUTTONS - if (keypad_buttons == 0) { - const uint8_t b = get_ADC_keyValue(); - if (WITHIN(b, 1, 8)) keypad_buttons = _BV(b - 1); - } - #endif +#endif // HAS_WIRED_LCD - #if HAS_SHIFT_ENCODER - /** - * Set up Rotary Encoder bit values (for two pin encoders to indicate movement). - * These values are independent of which pins are used for EN_A / EN_B indications. - * The rotary encoder part is also independent of the LCD chipset. - */ - uint8_t val = 0; - WRITE(SHIFT_LD_PIN, LOW); - WRITE(SHIFT_LD_PIN, HIGH); - for (uint8_t i = 0; i < 8; ++i) { - val >>= 1; - if (READ(SHIFT_OUT_PIN)) SBI(val, 7); - WRITE(SHIFT_CLK_PIN, HIGH); - WRITE(SHIFT_CLK_PIN, LOW); - } - TERN(REPRAPWORLD_KEYPAD, keypad_buttons, buttons) = ~val; - #endif +#if MARLINUI_ENCODER_DELTA - #if IS_TFTGLCD_PANEL - next_button_update_ms = now + (LCD_UPDATE_INTERVAL / 2); - buttons = slow_buttons; - TERN_(AUTO_BED_LEVELING_UBL, external_encoder()); - #endif + #define ENCODER_DEBOUNCE_MS 2 - } // next_button_update_ms + /** + * Get the encoder delta (-2 -1 0 +1 +2) since the last call, reading the live encoder state. + * Pins may be debounced to filter noise. + */ + int8_t MarlinUI::get_encoder_delta(const millis_t &now/*=millis()*/) { - #if HAS_ENCODER_WHEEL - static uint8_t lastEncoderBits; + typedef struct { bool a:1, b:1; } enc_t; - // Manage encoder rotation - #define ENCODER_SPIN(_E1, _E2) switch (lastEncoderBits) { case _E1: encoderDiff += encoderDirection; break; case _E2: encoderDiff -= encoderDirection; } + const enc_t live_enc = { BUTTON_PRESSED(EN1), BUTTON_PRESSED(EN2) }; - uint8_t enc = 0; - if (buttons & EN_A) enc |= B01; - if (buttons & EN_B) enc |= B10; - if (enc != lastEncoderBits) { - switch (enc) { - case 0: ENCODER_SPIN(1, 2); break; - case 2: ENCODER_SPIN(0, 3); break; - case 3: ENCODER_SPIN(2, 1); break; - case 1: ENCODER_SPIN(3, 0); break; - } - #if ALL(HAS_MARLINUI_MENU, AUTO_BED_LEVELING_UBL) - external_encoder(); - #endif - lastEncoderBits = enc; - } + #if ENCODER_DEBOUNCE_MS + + static enc_t enc; + static enc_t old_live; + + static millis_t en_A_bounce_ms; + if (old_live.a != live_enc.a) en_A_bounce_ms = now + (ENCODER_DEBOUNCE_MS); + else if (ELAPSED(now, en_A_bounce_ms)) enc.a = live_enc.a; - #endif // HAS_ENCODER_WHEEL + static millis_t en_B_bounce_ms; + if (old_live.b != live_enc.b) en_B_bounce_ms = now + (ENCODER_DEBOUNCE_MS); + else if (ELAPSED(now, en_B_bounce_ms)) enc.b = live_enc.b; + + old_live = live_enc; + + #else + + const enc_t &enc = live_enc; + + #endif + + static uint8_t old_pos; + const uint8_t pos = (enc.a ^ enc.b) | (enc.a << 1); // 0:00 1:10 2:11 3:01 + int8_t delta = 0; + if (pos != old_pos) { + delta = (pos - old_pos + 4 + 1) % 4 - 1; + old_pos = pos; + + static int8_t last_dir; + if (delta == 2) delta = last_dir * 2; + else last_dir = delta; } + return delta; - #endif // HAS_ENCODER_ACTION + } // get_encoder_delta -#endif // HAS_WIRED_LCD +#endif // MARLINUI_ENCODER_DELTA void MarlinUI::completion_feedback(const bool good/*=true*/) { wake_display(); // Wake the screen for all audio feedback diff --git a/Marlin/src/lcd/marlinui.h b/Marlin/src/lcd/marlinui.h index f21d2565bef6..ad4be0390060 100644 --- a/Marlin/src/lcd/marlinui.h +++ b/Marlin/src/lcd/marlinui.h @@ -254,6 +254,11 @@ class MarlinUI { } #endif + #if (HAS_WIRED_LCD && HAS_ENCODER_ACTION && HAS_MARLINUI_ENCODER) || HAS_DWIN_E3V2 || HAS_TFT_LVGL_UI + #define MARLINUI_ENCODER_DELTA 1 + static int8_t get_encoder_delta(const millis_t &now=millis()); + #endif + #if HAS_MEDIA #define MEDIA_MENU_GATEWAY TERN(PASSWORD_ON_SD_PRINT_MENU, password.media_gatekeeper, menu_media) static void media_changed(const uint8_t old_stat, const uint8_t stat); diff --git a/Marlin/src/lcd/menu/menu_main.cpp b/Marlin/src/lcd/menu/menu_main.cpp index 622b03379a5d..460305f5d4d1 100644 --- a/Marlin/src/lcd/menu/menu_main.cpp +++ b/Marlin/src/lcd/menu/menu_main.cpp @@ -246,7 +246,7 @@ void menu_main() { START_MENU(); BACK_ITEM(MSG_INFO_SCREEN); - #if HAS_MEDIA && !defined(MEDIA_MENU_AT_TOP) && !HAS_ENCODER_WHEEL + #if HAS_MEDIA && !defined(MEDIA_MENU_AT_TOP) && !HAS_MARLINUI_ENCODER #define MEDIA_MENU_AT_TOP #endif