From 59b6b32e6e8b3746843ddc94390b9e6c80d993f3 Mon Sep 17 00:00:00 2001 From: Victor Oliveira Date: Fri, 9 Oct 2020 08:25:23 -0300 Subject: [PATCH] Support for Debug Codes - Dnnn (#19225) Co-authored-by: Scott Lahteine --- Marlin/src/HAL/AVR/HAL.h | 2 + Marlin/src/HAL/DUE/HAL.h | 2 + Marlin/src/HAL/ESP32/HAL.h | 2 + Marlin/src/HAL/LINUX/HAL.h | 2 + Marlin/src/HAL/LPC1768/HAL.h | 2 + Marlin/src/HAL/SAMD51/HAL.h | 2 + Marlin/src/HAL/STM32/HAL.h | 2 + Marlin/src/HAL/STM32F1/HAL.h | 2 + Marlin/src/HAL/STM32_F4_F7/HAL.h | 2 + Marlin/src/HAL/TEENSY31_32/HAL.h | 2 + Marlin/src/HAL/TEENSY35_36/HAL.h | 2 + Marlin/src/core/macros.h | 1 + Marlin/src/feature/e_parser.h | 11 +- Marlin/src/gcode/control/T.cpp | 2 +- Marlin/src/gcode/gcode.cpp | 4 + Marlin/src/gcode/gcode.h | 5 +- Marlin/src/gcode/gcode_d.cpp | 173 +++++++++++++++++++++++++++++++ Marlin/src/gcode/parser.cpp | 49 ++++----- Marlin/src/gcode/parser.h | 34 +++++- Marlin/src/lcd/ultralcd.cpp | 6 +- 20 files changed, 269 insertions(+), 38 deletions(-) create mode 100644 Marlin/src/gcode/gcode_d.cpp diff --git a/Marlin/src/HAL/AVR/HAL.h b/Marlin/src/HAL/AVR/HAL.h index b606d0c231..ce15ed29fb 100644 --- a/Marlin/src/HAL/AVR/HAL.h +++ b/Marlin/src/HAL/AVR/HAL.h @@ -120,6 +120,8 @@ void HAL_init(); inline void HAL_clear_reset_source() { MCUSR = 0; } inline uint8_t HAL_get_reset_source() { return MCUSR; } +inline void HAL_reboot() {} // reboot the board or restart the bootloader + #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wunused-function" extern "C" { diff --git a/Marlin/src/HAL/DUE/HAL.h b/Marlin/src/HAL/DUE/HAL.h index dbb84e2ac7..f0650e6df8 100644 --- a/Marlin/src/HAL/DUE/HAL.h +++ b/Marlin/src/HAL/DUE/HAL.h @@ -105,6 +105,8 @@ void sei(); // Enable interrupts void HAL_clear_reset_source(); // clear reset reason uint8_t HAL_get_reset_source(); // get reset reason +inline void HAL_reboot() {} // reboot the board or restart the bootloader + // // ADC // diff --git a/Marlin/src/HAL/ESP32/HAL.h b/Marlin/src/HAL/ESP32/HAL.h index aa3bcc775d..81a9a0e59d 100644 --- a/Marlin/src/HAL/ESP32/HAL.h +++ b/Marlin/src/HAL/ESP32/HAL.h @@ -96,6 +96,8 @@ void HAL_clear_reset_source(); // reset reason uint8_t HAL_get_reset_source(); +inline void HAL_reboot() {} // reboot the board or restart the bootloader + void _delay_ms(int delay); #pragma GCC diagnostic push diff --git a/Marlin/src/HAL/LINUX/HAL.h b/Marlin/src/HAL/LINUX/HAL.h index 778ba2db4d..2e545e03d6 100644 --- a/Marlin/src/HAL/LINUX/HAL.h +++ b/Marlin/src/HAL/LINUX/HAL.h @@ -101,6 +101,8 @@ uint16_t HAL_adc_get_result(); inline void HAL_clear_reset_source(void) {} inline uint8_t HAL_get_reset_source(void) { return RST_POWER_ON; } +inline void HAL_reboot() {} // reboot the board or restart the bootloader + /* ---------------- Delay in cycles */ FORCE_INLINE static void DELAY_CYCLES(uint64_t x) { Clock::delayCycles(x); diff --git a/Marlin/src/HAL/LPC1768/HAL.h b/Marlin/src/HAL/LPC1768/HAL.h index 3118aed1b2..cb637e715d 100644 --- a/Marlin/src/HAL/LPC1768/HAL.h +++ b/Marlin/src/HAL/LPC1768/HAL.h @@ -200,6 +200,8 @@ void set_pwm_duty(const pin_t pin, const uint16_t v, const uint16_t v_size=255, void HAL_clear_reset_source(void); uint8_t HAL_get_reset_source(void); +inline void HAL_reboot() {} // reboot the board or restart the bootloader + // Add strcmp_P if missing #ifndef strcmp_P #define strcmp_P(a, b) strcmp((a), (b)) diff --git a/Marlin/src/HAL/SAMD51/HAL.h b/Marlin/src/HAL/SAMD51/HAL.h index 7fd826a1b6..abc6c04a69 100644 --- a/Marlin/src/HAL/SAMD51/HAL.h +++ b/Marlin/src/HAL/SAMD51/HAL.h @@ -88,6 +88,8 @@ typedef int8_t pin_t; void HAL_clear_reset_source(); // clear reset reason uint8_t HAL_get_reset_source(); // get reset reason +inline void HAL_reboot() {} // reboot the board or restart the bootloader + // // ADC // diff --git a/Marlin/src/HAL/STM32/HAL.h b/Marlin/src/HAL/STM32/HAL.h index 37919102ec..a1f7515d6b 100644 --- a/Marlin/src/HAL/STM32/HAL.h +++ b/Marlin/src/HAL/STM32/HAL.h @@ -134,6 +134,8 @@ void HAL_clear_reset_source(); // Reset reason uint8_t HAL_get_reset_source(); +inline void HAL_reboot() {} // reboot the board or restart the bootloader + void _delay_ms(const int delay); extern "C" char* _sbrk(int incr); diff --git a/Marlin/src/HAL/STM32F1/HAL.h b/Marlin/src/HAL/STM32F1/HAL.h index 5c03593eb0..c10dea0eaf 100644 --- a/Marlin/src/HAL/STM32F1/HAL.h +++ b/Marlin/src/HAL/STM32F1/HAL.h @@ -185,6 +185,8 @@ void HAL_clear_reset_source(); // Reset reason uint8_t HAL_get_reset_source(); +inline void HAL_reboot() {} // reboot the board or restart the bootloader + void _delay_ms(const int delay); #pragma GCC diagnostic push diff --git a/Marlin/src/HAL/STM32_F4_F7/HAL.h b/Marlin/src/HAL/STM32_F4_F7/HAL.h index 88e48f0fa0..00a65de792 100644 --- a/Marlin/src/HAL/STM32_F4_F7/HAL.h +++ b/Marlin/src/HAL/STM32_F4_F7/HAL.h @@ -142,6 +142,8 @@ void HAL_clear_reset_source(); // Reset reason uint8_t HAL_get_reset_source(); +inline void HAL_reboot() {} // reboot the board or restart the bootloader + void _delay_ms(const int delay); /* diff --git a/Marlin/src/HAL/TEENSY31_32/HAL.h b/Marlin/src/HAL/TEENSY31_32/HAL.h index b434b9de76..5fc65680d3 100644 --- a/Marlin/src/HAL/TEENSY31_32/HAL.h +++ b/Marlin/src/HAL/TEENSY31_32/HAL.h @@ -93,6 +93,8 @@ void HAL_clear_reset_source(); // Get the reason for the reset uint8_t HAL_get_reset_source(); +inline void HAL_reboot() {} // reboot the board or restart the bootloader + FORCE_INLINE void _delay_ms(const int delay_ms) { delay(delay_ms); } #pragma GCC diagnostic push diff --git a/Marlin/src/HAL/TEENSY35_36/HAL.h b/Marlin/src/HAL/TEENSY35_36/HAL.h index f454e7af51..30db40dfac 100644 --- a/Marlin/src/HAL/TEENSY35_36/HAL.h +++ b/Marlin/src/HAL/TEENSY35_36/HAL.h @@ -99,6 +99,8 @@ void HAL_clear_reset_source(); // Reset reason uint8_t HAL_get_reset_source(); +inline void HAL_reboot() {} // reboot the board or restart the bootloader + FORCE_INLINE void _delay_ms(const int delay_ms) { delay(delay_ms); } #pragma GCC diagnostic push diff --git a/Marlin/src/core/macros.h b/Marlin/src/core/macros.h index 5fc1081019..72644b195c 100644 --- a/Marlin/src/core/macros.h +++ b/Marlin/src/core/macros.h @@ -215,6 +215,7 @@ #define WITHIN(N,L,H) ((N) >= (L) && (N) <= (H)) #define NUMERIC(a) WITHIN(a, '0', '9') #define DECIMAL(a) (NUMERIC(a) || a == '.') +#define HEXCHR(a) (NUMERIC(a) ? (a) - '0' : WITHIN(a, 'a', 'f') ? ((a) - 'a' + 10) : WITHIN(a, 'A', 'F') ? ((a) - 'A' + 10) : -1) #define NUMERIC_SIGNED(a) (NUMERIC(a) || (a) == '-' || (a) == '+') #define DECIMAL_SIGNED(a) (DECIMAL(a) || (a) == '-' || (a) == '+') #define COUNT(a) (sizeof(a)/sizeof(*a)) diff --git a/Marlin/src/feature/e_parser.h b/Marlin/src/feature/e_parser.h index 8d11463ecd..085cbd4eab 100644 --- a/Marlin/src/feature/e_parser.h +++ b/Marlin/src/feature/e_parser.h @@ -88,10 +88,8 @@ public: case EP_N: switch (c) { - case '0': case '1': case '2': - case '3': case '4': case '5': - case '6': case '7': case '8': - case '9': case '-': case ' ': break; + case '0' ... '9': + case '-': case ' ': break; case 'M': state = EP_M; break; default: state = EP_IGNORE; } @@ -153,10 +151,7 @@ public: case EP_M876S: switch (c) { case ' ': break; - case '0': case '1': case '2': - case '3': case '4': case '5': - case '6': case '7': case '8': - case '9': + case '0' ... '9': state = EP_M876SN; M876_reason = (uint8_t)(c - '0'); break; diff --git a/Marlin/src/gcode/control/T.cpp b/Marlin/src/gcode/control/T.cpp index 729f7f2223..d95e60ff8d 100644 --- a/Marlin/src/gcode/control/T.cpp +++ b/Marlin/src/gcode/control/T.cpp @@ -46,7 +46,7 @@ * Tx Same as T?, but nozzle doesn't have to be preheated. Tc requires a preheated nozzle to finish filament load. * Tc Load to nozzle after filament was prepared by Tc and nozzle is already heated. */ -void GcodeSuite::T(const uint8_t tool_index) { +void GcodeSuite::T(const int8_t tool_index) { DEBUG_SECTION(log_T, "T", DEBUGGING(LEVELING)); if (DEBUGGING(LEVELING)) DEBUG_ECHOLNPAIR("...(", tool_index, ")"); diff --git a/Marlin/src/gcode/gcode.cpp b/Marlin/src/gcode/gcode.cpp index 1de54259be..3d70b7c85c 100644 --- a/Marlin/src/gcode/gcode.cpp +++ b/Marlin/src/gcode/gcode.cpp @@ -923,6 +923,10 @@ void GcodeSuite::process_parsed_command(const bool no_ok/*=false*/) { case 'T': T(parser.codenum); break; // Tn: Tool Change + #if ENABLED(MARLIN_DEV_MODE) + case 'D': D(parser.codenum); break; // Dn: Debug codes + #endif + default: #if ENABLED(WIFI_CUSTOM_COMMAND) if (wifi_custom_command(parser.command_ptr)) break; diff --git a/Marlin/src/gcode/gcode.h b/Marlin/src/gcode/gcode.h index 026083bcfc..f21b7f89b1 100644 --- a/Marlin/src/gcode/gcode.h +++ b/Marlin/src/gcode/gcode.h @@ -285,6 +285,7 @@ * M995 - Touch screen calibration for TFT display * M997 - Perform in-application firmware update * M999 - Restart after being stopped by error + * D... - Custom Development G-code. Add hooks to 'gcode_D.cpp' for developers to test features. (Requires MARLIN_DEV_MODE) * * "T" Codes * @@ -408,6 +409,8 @@ public: private: + TERN_(MARLIN_DEV_MODE, static void D(const int16_t dcode)); + static void G0_G1(TERN_(HAS_FAST_MOVES, const bool fast_move=false)); TERN_(ARC_SUPPORT, static void G2_G3(const bool clockwise)); @@ -882,7 +885,7 @@ private: TERN_(CONTROLLER_FAN_EDITABLE, static void M710()); - static void T(const uint8_t tool_index); + static void T(const int8_t tool_index); }; diff --git a/Marlin/src/gcode/gcode_d.cpp b/Marlin/src/gcode/gcode_d.cpp new file mode 100644 index 0000000000..4bc3b6c6c3 --- /dev/null +++ b/Marlin/src/gcode/gcode_d.cpp @@ -0,0 +1,173 @@ +/** + * Marlin 3D Printer Firmware + * Copyright (c) 2020 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] + * + * Based on Sprinter and grbl. + * Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ +#include "../inc/MarlinConfigPre.h" + +#if ENABLED(MARLIN_DEV_MODE) + + #include "gcode.h" + #include "../module/settings.h" + #include "../libs/hex_print.h" + #include "../HAL/shared/eeprom_if.h" + + /** + * Dn: G-code for development and testing + * + * See https://reprap.org/wiki/G-code#D:_Debug_codes + * + * Put whatever else you need here to test ongoing development. + */ + void GcodeSuite::D(const int16_t dcode) { + switch (dcode) { + + case -1: + for (;;); // forever + + case 0: + HAL_reboot(); + break; + + case 1: { + // Zero or pattern-fill the EEPROM data + #if ENABLED(EEPROM_SETTINGS) + persistentStore.access_start(); + size_t total = persistentStore.capacity(); + int pos = 0; + const uint8_t value = 0x0; + while(total--) { + persistentStore.write_data(pos, &value, 1); + } + persistentStore.access_finish(); + #else + settings.reset(); + settings.save(); + #endif + HAL_reboot(); + } break; + + case 2: { // D2 Read / Write SRAM + #define SRAM_SIZE 8192 + uint8_t *pointer = parser.hex_adr_val('A'); + uint16_t len = parser.ushortval('C', 1); + uintptr_t addr = (uintptr_t)pointer; + NOMORE(addr, (size_t)(SRAM_SIZE - 1)); + NOMORE(len, SRAM_SIZE - addr); + if (parser.seenval('X')) { + // Write the hex bytes after the X + uint16_t val = parser.hex_val('X'); + while (len--) { + *pointer = val; + pointer++; + } + } + else { + while (len--) print_hex_byte(*(pointer++)); + SERIAL_EOL(); + } + } break; + + case 3: { // D3 Read / Write EEPROM + uint8_t *pointer = parser.hex_adr_val('A'); + uint16_t len = parser.ushortval('C', 1); + uintptr_t addr = (uintptr_t)pointer; + #ifndef MARLIN_EEPROM_SIZE + #define MARLIN_EEPROM_SIZE size_t(E2END + 1) + #endif + NOMORE(addr, (size_t)(MARLIN_EEPROM_SIZE - 1)); + NOMORE(len, MARLIN_EEPROM_SIZE - addr); + if (parser.seenval('X')) { + uint16_t val = parser.hex_val('X'); + #if ENABLED(EEPROM_SETTINGS) + persistentStore.access_start(); + while(len--) { + int pos = 0; + persistentStore.write_data(pos, (uint8_t *)&val, sizeof(val)); + } + SERIAL_EOL(); + persistentStore.access_finish(); + #else + SERIAL_ECHOLN("NO EEPROM"); + #endif + } + else { + while (len--) { + // Read bytes from EEPROM + #if ENABLED(EEPROM_SETTINGS) + persistentStore.access_start(); + uint8_t val; + while(len--) { + int pos = 0; + if (!persistentStore.read_data(pos, (uint8_t *)&val, sizeof(val))) { + print_hex_byte(val); + } + } + SERIAL_EOL(); + persistentStore.access_finish(); + #else + SERIAL_ECHOLN("NO EEPROM"); + #endif + } + SERIAL_EOL(); + } + } break; + + case 4: { // D4 Read / Write PIN + // const uint8_t pin = parser.byteval('P'); + // const bool is_out = parser.boolval('F'), + // val = parser.byteval('V', LOW); + if (parser.seenval('X')) { + // TODO: Write the hex bytes after the X + //while (len--) { + //} + } + else { + // while (len--) { + // TODO: Read bytes from EEPROM + // print_hex_byte(eeprom_read_byte(*(adr++)); + // } + SERIAL_EOL(); + } + } break; + + case 5: { // D4 Read / Write onboard Flash + #define FLASH_SIZE 1024 + uint8_t *pointer = parser.hex_adr_val('A'); + uint16_t len = parser.ushortval('C', 1); + uintptr_t addr = (uintptr_t)pointer; + NOMORE(addr, (size_t)(FLASH_SIZE - 1)); + NOMORE(len, FLASH_SIZE - addr); + if (parser.seenval('X')) { + // TODO: Write the hex bytes after the X + //while (len--) { + //} + } + else { + // while (len--) { + // TODO: Read bytes from EEPROM + // print_hex_byte(eeprom_read_byte(adr++)); + // } + SERIAL_EOL(); + } + } break; + } + } + +#endif diff --git a/Marlin/src/gcode/parser.cpp b/Marlin/src/gcode/parser.cpp index b3172e7f6b..9c5085b97e 100644 --- a/Marlin/src/gcode/parser.cpp +++ b/Marlin/src/gcode/parser.cpp @@ -147,22 +147,15 @@ void GCodeParser::parse(char *p) { starpos[1] = '\0'; } - #if ENABLED(GCODE_MOTION_MODES) - #if ENABLED(ARC_SUPPORT) - #define GTOP 3 - #else - #define GTOP 1 - #endif + #if ANY(MARLIN_DEV_MODE, SWITCHING_TOOLHEAD, MAGNETIC_SWITCHING_TOOLHEAD, ELECTROMAGNETIC_SWITCHING_TOOLHEAD) + #define SIGNED_CODENUM 1 #endif // Bail if the letter is not G, M, or T // (or a valid parameter for the current motion mode) switch (letter) { - case 'G': case 'M': case 'T': - #if ENABLED(CANCEL_OBJECTS) - case 'O': - #endif + case 'G': case 'M': case 'T': TERN_(MARLIN_DEV_MODE, case 'D':) // Skip spaces to get the numeric part while (*p == ' ') p++; @@ -178,22 +171,33 @@ void GCodeParser::parse(char *p) { #endif // Bail if there's no command code number - if (!NUMERIC(*p)) return; + if (!TERN(SIGNED_CODENUM, NUMERIC_SIGNED(*p), NUMERIC(*p))) return; // Save the command letter at this point // A '?' signifies an unknown command command_letter = letter; - // Get the code number - integer digits only - codenum = 0; - do { codenum *= 10, codenum += *p++ - '0'; } while (NUMERIC(*p)); + { + #if ENABLED(SIGNED_CODENUM) + int sign = 1; // Allow for a negative code like D-1 or T-1 + if (*p == '-') { sign = -1; ++p; } + #endif + + // Get the code number - integer digits only + codenum = 0; + + do { codenum = codenum * 10 + *p++ - '0'; } while (NUMERIC(*p)); + + // Apply the sign, if any + TERN_(SIGNED_CODENUM, codenum *= sign); + } // Allow for decimal point in command #if ENABLED(USE_GCODE_SUBCODES) if (*p == '.') { p++; while (NUMERIC(*p)) - subcode *= 10, subcode += *p++ - '0'; + subcode = subcode * 10 + *p++ - '0'; } #endif @@ -201,11 +205,8 @@ void GCodeParser::parse(char *p) { while (*p == ' ') p++; #if ENABLED(GCODE_MOTION_MODES) - if (letter == 'G' && (codenum <= GTOP || codenum == 5 - #if ENABLED(G38_PROBE_TARGET) - || codenum == 38 - #endif - ) + if (letter == 'G' + && (codenum <= TERN(ARC_SUPPORT, 3, 1) || codenum == 5 || TERN0(G38_PROBE_TARGET, codenum == 38)) ) { motion_mode_codenum = codenum; TERN_(USE_GCODE_SUBCODES, motion_mode_subcode = subcode); @@ -216,12 +217,12 @@ void GCodeParser::parse(char *p) { #if ENABLED(GCODE_MOTION_MODES) #if ENABLED(ARC_SUPPORT) - case 'I': case 'J': case 'R': + case 'I' ... 'J': case 'R': if (motion_mode_codenum != 2 && motion_mode_codenum != 3) return; #endif - case 'P': case 'Q': + case 'P' ... 'Q': if (motion_mode_codenum != 5) return; - case 'X': case 'Y': case 'Z': case 'E': case 'F': + case 'X' ... 'Z': case 'E' ... 'F': if (motion_mode_codenum < 0) return; command_letter = 'G'; codenum = motion_mode_codenum; @@ -247,7 +248,7 @@ void GCodeParser::parse(char *p) { #if ENABLED(EXPECTED_PRINTER_CHECK) case 16: #endif - case 23: case 28: case 30: case 33: case 117: case 118: case 928: + case 23: case 28: case 30: case 117 ... 118: case 928: string_arg = unescape_string(p); return; default: break; diff --git a/Marlin/src/gcode/parser.h b/Marlin/src/gcode/parser.h index eb614c33b4..42b85ca271 100644 --- a/Marlin/src/gcode/parser.h +++ b/Marlin/src/gcode/parser.h @@ -114,6 +114,11 @@ public: return valid_signless(p) || ((p[0] == '-' || p[0] == '+') && valid_signless(&p[1])); // [-+]?.?[0-9] } + FORCE_INLINE static bool valid_number(const char * const p) { + // TODO: With MARLIN_DEV_MODE allow HEX values starting with "x" + return valid_float(p); + } + #if ENABLED(FASTER_GCODE_PARSER) FORCE_INLINE static bool valid_int(const char * const p) { @@ -142,8 +147,12 @@ public: if (ind >= COUNT(param)) return false; // Only A-Z const bool b = TEST32(codebits, ind); if (b) { - char * const ptr = command_ptr + param[ind]; - value_ptr = param[ind] && valid_float(ptr) ? ptr : nullptr; + if (param[ind]) { + char * const ptr = command_ptr + param[ind]; + value_ptr = valid_number(ptr) ? ptr : nullptr; + } + else + value_ptr = nullptr; } return b; } @@ -198,7 +207,7 @@ public: static inline bool seen(const char c) { char *p = strgchr(command_args, c); const bool b = !!p; - if (b) value_ptr = valid_float(&p[1]) ? &p[1] : nullptr; + if (b) value_ptr = valid_number(&p[1]) ? &p[1] : nullptr; return b; } @@ -401,6 +410,25 @@ public: static inline float linearval(const char c, const float dval=0) { return seenval(c) ? value_linear_units() : dval; } static inline float celsiusval(const char c, const float dval=0) { return seenval(c) ? value_celsius() : dval; } + #if ENABLED(MARLIN_DEV_MODE) + + static inline uint8_t* hex_adr_val(const char c, uint8_t * const dval=nullptr) { + if (!seen(c) || *value_ptr != 'x') return dval; + uint8_t *out = nullptr; + for (char *vp = value_ptr + 1; HEXCHR(*vp) >= 0; vp++) + out = (uint8_t*)((uintptr_t(out) << 8) | HEXCHR(*vp)); + return out; + } + + static inline uint16_t hex_val(const char c, uint16_t const dval=0) { + if (!seen(c) || *value_ptr != 'x') return dval; + uint16_t out = 0; + for (char *vp = value_ptr + 1; HEXCHR(*vp) >= 0; vp++) + out = ((out) << 8) | HEXCHR(*vp); + return out; + } + + #endif }; extern GCodeParser parser; diff --git a/Marlin/src/lcd/ultralcd.cpp b/Marlin/src/lcd/ultralcd.cpp index de534e4023..92dd63389f 100644 --- a/Marlin/src/lcd/ultralcd.cpp +++ b/Marlin/src/lcd/ultralcd.cpp @@ -123,11 +123,15 @@ constexpr uint8_t epps = ENCODER_PULSES_PER_STEP; #include "lcdprint.h" #include "../sd/cardreader.h" -#include "../module/settings.h" + #include "../module/temperature.h" #include "../module/planner.h" #include "../module/motion.h" +#if HAS_LCD_MENU + #include "../module/settings.h" +#endif + #if ENABLED(AUTO_BED_LEVELING_UBL) #include "../feature/bedlevel/bedlevel.h" #endif