Merge branch 'bugfix-2.1.x' of https://github.com/MarlinFirmware/Marlin into bugfix-2.1.x-March2

This commit is contained in:
classicrocker883 2025-01-12 08:18:05 -05:00
commit 8fd091ac0d
170 changed files with 3271 additions and 47580 deletions

View file

@ -599,6 +599,10 @@
#define MAX31865_SENSOR_OHMS_2 100
#define MAX31865_CALIBRATION_OHMS_2 430
#endif
#if TEMP_SENSOR_IS_MAX_TC(BED)
#define MAX31865_SENSOR_OHMS_BED 100
#define MAX31865_CALIBRATION_OHMS_BED 430
#endif
#if HAS_E_TEMP_SENSOR
#define TEMP_RESIDENCY_TIME 10 // (seconds) Time to wait for hotend to "settle" in M109
@ -1646,15 +1650,15 @@
// with NOZZLE_AS_PROBE this can be negative for a wider probing area.
#define PROBING_MARGIN 10
// X and Y axis travel speed (mm/min) between probes.
// X and Y axis travel speed between probes.
// Leave undefined to use the average of the current XY homing feedrate.
#define XY_PROBE_FEEDRATE (133*60)
#define XY_PROBE_FEEDRATE (133*60) // (mm/min)
// Feedrate (mm/min) for the first approach when double-probing (MULTIPLE_PROBING == 2)
#define Z_PROBE_FEEDRATE_FAST (4*60)
// Feedrate for the first approach when double-probing (MULTIPLE_PROBING == 2)
#define Z_PROBE_FEEDRATE_FAST (4*60) // (mm/min)
// Feedrate (mm/min) for the "accurate" probe of each point
#define Z_PROBE_FEEDRATE_SLOW (Z_PROBE_FEEDRATE_FAST / 2)
// Feedrate for the "accurate" probe of each point
#define Z_PROBE_FEEDRATE_SLOW (Z_PROBE_FEEDRATE_FAST / 2) // (mm/min)
/**
* Probe Activation Switch
@ -2104,6 +2108,12 @@
//#define AUTO_BED_LEVELING_UBL
//#define MESH_BED_LEVELING
/**
* Commands to execute at the start of G29 probing,
* after switching to the PROBING_TOOL.
*/
//#define EVENT_GCODE_BEFORE_G29 "M300 P440 S200"
/**
* Commands to execute at the end of G29 probing.
* Useful to retract or move the Z probe out of the way.

View file

@ -174,9 +174,10 @@
* Thermocouple Options for MAX6675 (-2), MAX31855 (-3), and MAX31865 (-5).
*/
//#define TEMP_SENSOR_FORCE_HW_SPI // Ignore SCK/MOSI/MISO pins; use CS and the default SPI bus.
//#define MAX31865_SENSOR_WIRES_0 2 // (2-4) Number of wires for the probe connected to a MAX31865 board.
//#define MAX31865_SENSOR_WIRES_1 2
//#define MAX31865_SENSOR_WIRES_2 2
//#define MAX31865_SENSOR_WIRES_0 2 // (2-4) Number of wires for the probe connected to a MAX31865 board.
//#define MAX31865_SENSOR_WIRES_1 2
//#define MAX31865_SENSOR_WIRES_2 2
//#define MAX31865_SENSOR_WIRES_BED 2
//#define MAX31865_50HZ_FILTER // Use a 50Hz filter instead of the default 60Hz.
//#define MAX31865_USE_READ_ERROR_DETECTION // Treat value spikes (20°C delta in under 1s) as read errors.
@ -188,6 +189,7 @@
//#define MAX31865_WIRE_OHMS_0 0.95f // For 2-wire, set the wire resistances for more accurate readings.
//#define MAX31865_WIRE_OHMS_1 0.0f
//#define MAX31865_WIRE_OHMS_2 0.0f
//#define MAX31865_WIRE_OHMS_BED 0.0f
/**
* Hephestos 2 24V heated bed upgrade kit.
@ -211,18 +213,19 @@
//
// Heated Chamber options
//
#if DISABLED(PIDTEMPCHAMBER)
#define CHAMBER_CHECK_INTERVAL 5000 // (ms) Interval between checks in bang-bang control
#if ENABLED(CHAMBER_LIMIT_SWITCHING)
#define CHAMBER_HYSTERESIS 2 // (°C) Only set the relevant heater state when ABS(T-target) > CHAMBER_HYSTERESIS
#endif
#endif
#if TEMP_SENSOR_CHAMBER
//#define HEATER_CHAMBER_PIN P2_04 // Required heater on/off pin (example: SKR 1.4 Turbo HE1 plug)
//#define HEATER_CHAMBER_INVERTING false
//#define FAN1_PIN -1 // Remove the fan signal on pin P2_04 (example: SKR 1.4 Turbo HE1 plug)
#if DISABLED(PIDTEMPCHAMBER)
#define CHAMBER_CHECK_INTERVAL 5000 // (ms) Interval between checks in bang-bang control
#if ENABLED(CHAMBER_LIMIT_SWITCHING)
#define CHAMBER_HYSTERESIS 2 // (°C) Only set the relevant heater state when ABS(T-target) > CHAMBER_HYSTERESIS
#endif
#endif
//#define CHAMBER_FAN // Enable a fan on the chamber
#if ENABLED(CHAMBER_FAN)
//#define CHAMBER_FAN_INDEX 2 // Index of a fan to repurpose as the chamber fan. (Default: first unused fan)
@ -1019,7 +1022,7 @@
#endif // BLTOUCH
// @section calibration
// @section calibrate
/**
* Z Steppers Auto-Alignment
@ -2034,17 +2037,17 @@
//#define STATUS_HEAT_PERCENT // Show heating in a progress bar
//#define STATUS_HEAT_POWER // Show heater output power as a vertical bar
// Frivolous Game Options
//#define MARLIN_BRICKOUT
//#define MARLIN_INVADERS
//#define MARLIN_SNAKE
//#define GAMES_EASTER_EGG // Add extra blank lines above the "Games" sub-menu
#endif // HAS_MARLINUI_U8GLIB
#if HAS_MARLINUI_U8GLIB || IS_DWIN_MARLINUI
#define MENU_HOLLOW_FRAME // Enable to save many cycles by drawing a hollow frame on Menu Screens
//#define OVERLAY_GFX_REVERSE // Swap the CW/CCW indicators in the graphics overlay
// Frivolous Game Options
//#define MARLIN_BRICKOUT
//#define MARLIN_INVADERS
//#define MARLIN_SNAKE
//#define GAMES_EASTER_EGG // Add extra blank lines above the "Games" sub-menu
#endif
//

View file

@ -41,7 +41,7 @@
* here we define this default string as the date where the latest release
* version was tagged.
*/
//#define STRING_DISTRIBUTION_DATE "2024-11-21"
//#define STRING_DISTRIBUTION_DATE "2025-01-12"
/**
* The protocol for communication to the host. Protocol indicates communication

View file

@ -62,6 +62,11 @@ motherboard = BOARD_RAMPS_14_EFB
serial_port = 0
baudrate = 250000
string_config_h_author = "(default from config.ini)"
capabilities_report = on
extended_capabilities_report = on
use_watchdog = on
thermal_protection_hotends = on
thermal_protection_hysteresis = 4
@ -77,9 +82,7 @@ temp_sensor_0 = 1
temp_hysteresis = 3
heater_0_mintemp = 5
heater_0_maxtemp = 275
preheat_1_temp_hotend = 180
bang_max = 255
pidtemp = on
pid_k1 = 0.95
pid_max = 255
@ -89,6 +92,14 @@ default_kp = 22.20
default_ki = 1.08
default_kd = 114.00
temp_sensor_bed = 1
bed_mintemp = 5
bed_maxtemp = 150
thermal_protection_bed = on
thermal_protection_bed_hysteresis = 2
thermal_protection_bed_period = 20
x_driver_type = A4988
y_driver_type = A4988
z_driver_type = A4988
@ -121,10 +132,10 @@ default_max_acceleration = { 3000, 3000, 100, 10000 }
homing_feedrate_mm_m = { (50*60), (50*60), (4*60) }
homing_bump_divisor = { 2, 2, 4 }
x_enable_on = 0
y_enable_on = 0
z_enable_on = 0
e_enable_on = 0
x_enable_on = LOW
y_enable_on = LOW
z_enable_on = LOW
e_enable_on = LOW
invert_x_dir = false
invert_y_dir = true
@ -136,11 +147,6 @@ step_state_x = HIGH
step_state_y = HIGH
step_state_z = HIGH
disable_x = off
disable_y = off
disable_z = off
disable_e = off
proportional_font_ratio = 1.0
default_nominal_filament_dia = 1.75
@ -153,18 +159,13 @@ default_retract_acceleration = 3000
default_minimumfeedrate = 0.0
default_mintravelfeedrate = 0.0
minimum_planner_speed = 0.05
min_steps_per_segment = 6
default_minsegmenttime = 20000
[config:basic]
bed_overshoot = 10
busy_while_heating = on
default_ejerk = 5.0
default_keepalive_interval = 2
default_leveling_fade_height = 0.0
disable_other_extruders = on
display_charset_hd44780 = JAPANESE
eeprom_boot_silent = on
eeprom_chitchat = on
endstoppullups = on
@ -173,10 +174,8 @@ extrude_mintemp = 170
host_keepalive_feature = on
hotend_overshoot = 15
jd_handle_small_segments = on
lcd_info_screen_style = 0
lcd_language = en
max_bed_power = 255
mesh_inset = 0
min_software_endstops = on
max_software_endstops = on
min_software_endstop_x = on
@ -185,50 +184,48 @@ min_software_endstop_z = on
max_software_endstop_x = on
max_software_endstop_y = on
max_software_endstop_z = on
preheat_1_fan_speed = 0
preheat_1_label = "PLA"
preheat_1_temp_hotend = 180
preheat_1_temp_bed = 70
preheat_1_fan_speed = 0
preheat_2_label = "ABS"
preheat_2_temp_hotend = 240
preheat_2_temp_bed = 110
preheat_2_fan_speed = 0
prevent_cold_extrusion = on
prevent_lengthy_extrude = on
printjob_timer_autostart = on
probing_margin = 10
show_bootscreen = on
soft_pwm_scale = 0
string_config_h_author = "(none, default config)"
temp_bed_hysteresis = 3
temp_bed_residency_time = 10
temp_bed_window = 1
temp_residency_time = 10
temp_window = 1
validate_homing_endstops = on
xy_probe_feedrate = (133*60)
z_clearance_between_probes = 5
z_clearance_deploy_probe = 10
z_clearance_multi_probe = 5
editable_steps_per_unit = on
[config:advanced]
arc_support = on
auto_report_temperatures = on
autotemp = on
autotemp_min = 210
autotemp_max = 250
autotemp_factor = 0.1f
autotemp_oldweight = 0.98
bed_check_interval = 5000
default_stepper_timeout_sec = 120
default_volumetric_extruder_limit = 0.00
disable_idle_x = on
disable_idle_y = on
disable_idle_z = on
disable_idle_e = on
e0_auto_fan_pin = -1
encoder_100x_steps_per_sec = 80
encoder_10x_steps_per_sec = 30
encoder_rate_multiplier = on
extended_capabilities_report = on
extruder_auto_fan_speed = 255
extruder_auto_fan_temperature = 50
fanmux0_pin = -1
fanmux1_pin = -1
fanmux2_pin = -1
faster_gcode_parser = on
debug_flags_gcode = on
homing_bump_mm = { 5, 5, 2 }
max_arc_segment_mm = 1.0
min_arc_segment_mm = 0.1
@ -237,11 +234,11 @@ n_arc_correction = 25
serial_overrun_protection = on
slowdown = on
slowdown_divisor = 2
temp_sensor_bed = 0
thermal_protection_bed_hysteresis = 2
thermocouple_max_errors = 15
tx_buffer_size = 0
bed_check_interval = 5000
watch_bed_temp_increase = 2
watch_bed_temp_period = 60
watch_temp_increase = 2
watch_temp_period = 20
watch_temp_period = 40

View file

@ -21,11 +21,12 @@
*/
#ifdef ARDUINO_ARCH_ESP32
#include "../../core/serial.h"
#include "../../inc/MarlinConfigPre.h"
#if ENABLED(WIFISUPPORT)
#include "../../core/serial.h"
#include <WiFi.h>
#include <ESPmDNS.h>
#include <ESPAsyncWebServer.h>

View file

@ -30,7 +30,6 @@
#include "../../inc/MarlinConfig.h"
#include "../../core/macros.h"
#include "../shared/Marduino.h"
#include "../shared/math_32bit.h"
#include "../shared/HAL_SPI.h"
@ -39,8 +38,6 @@
#include "timers.h"
#include "MarlinSerial.h"
#include <stdint.h>
//
// Serial Ports
//

View file

@ -11,7 +11,7 @@ The HC32F460 HAL is designed to be generic enough for any HC32F460-based board.
- Examine the board's main processor. (Refer the naming key in `hc32.ini`.)
- Extend the `HC32F460C_common` base env for 256K, or `HC32F460E_common` for 512K.
3. Determine your board's application start address (see [below](#finding-the-application-start-address))
4. Set `board_build.ld_args.flash_start` to the app start address once you've found it. If your board doesn't use a bootloader, you may be able to use the "ICSP" header or DFU. This document will be updated once we have more information about flashing without a bootloader.
4. Set `board_upload.offset_address` to the app start address once you've found it. If your board doesn't use a bootloader, you may be able to use the "ICSP" header or DFU. This document will be updated once we have more information about flashing without a bootloader.
### Finding the application start address

View file

@ -8,6 +8,7 @@
#define _HC32_APP_CONFIG_H_
#include "../../inc/MarlinConfigPre.h"
#include "sysclock.h"
//
// dev mode
@ -64,12 +65,8 @@
// redirect printf to host serial
#define REDIRECT_PRINTF_TO_SERIAL 1
// F_CPU must be known at compile time, but on HC32F460 it's not.
// Thus we assume HCLK to be 200MHz, as that's what is configured in
// 'core_hook_sysclock_init' in 'sysclock.cpp'.
// If you face issues with this assumption, please double-check with the values
// printed by 'MarlinHAL::HAL_clock_frequencies_dump'.
// see also: HAL_TIMER_RATE in timers.h
#define F_CPU 200000000 // 200MHz HCLK
// F_CPU is F_HCLK, as that's the main CPU core's clock.
// see 'sysclock.h' for more information.
#define F_CPU F_HCLK
#endif // _HC32_APP_CONFIG_H_

View file

@ -94,7 +94,7 @@
#error "SERIAL_DMA requires USART_RX_DMA_SUPPORT to be enabled in the arduino core."
#endif
// Before arduino core version 1.2.0, USART_RX_DMA_SUPPORT did not implement
// Before arduino core version 1.2.0, USART_RX_DMA_SUPPORT did not implement
// core_hook_usart_rx_irq, which is required for the emergency parser.
// With 1.2.0, this was fixed (see https://github.com/shadow578/framework-arduino-hc32f46x/pull/25).
#if ENABLED(EMERGENCY_PARSER) && ARDUINO_CORE_VERSION_INT < GET_VERSION_INT(1, 2, 0)

View file

@ -26,64 +26,144 @@
#ifdef ARDUINO_ARCH_HC32
// Get BOARD_XTAL_FREQUENCY from configuration / pins
#include "../../inc/MarlinConfig.h"
#include "sysclock.h"
#include <core_hooks.h>
#include <drivers/sysclock/sysclock_util.h>
/***
* @brief Automatically calculate M, N, P values for the MPLL to reach a target frequency.
* @param input_frequency The input frequency.
* @param target_frequency The target frequency.
* @return The MPLL configuration structure. Q and R are not set.
*
* @note
* Simplified MPLL block diagram, with intermediary clocks (1) = VCO_in, (2) = VCO_out:
*
* INPUT -> [/ M] -(1)-> [* N] -(2)-|-> [/ P] -> MPLL-P
*/
constexpr stc_clk_mpll_cfg_t get_mpll_config(double input_frequency, double target_frequency) {
// PLL input clock divider: M in [1, 24]
for (uint32_t M = 1; M <= 24; M++) {
double f_vco_in = input_frequency / M;
// 1 <= VCO_in <= 25 MHz
if (f_vco_in < 1e6 || f_vco_in > 25e6) continue;
// VCO multiplier: N in [20, 480]
for (uint32_t N = 20; N <= 480; N++) {
double f_vco_out = f_vco_in * N;
// 240 <= VCO_out <= 480 MHz
if (f_vco_out < 240e6 || f_vco_out > 480e6) continue;
// Output "P" divider: P in [2, 16]
for (uint32_t P = 2; P <= 16; P++) {
double f_calculated_out = f_vco_out / P;
if (f_calculated_out == target_frequency) {
// Found a match, return it
return {
.PllpDiv = P,
.PllqDiv = P, // Don't care for Q and R
.PllrDiv = P, // "
.plln = N,
.pllmDiv = M
};
}
}
}
}
// If no valid M, N, P found, return invalid config
return { 0, 0, 0, 0, 0 };
}
/**
* @brief Get the division factor required to get the target frequency from the input frequency.
* @tparam input_freq The input frequency.
* @tparam target_freq The target frequency.
* @return The division factor.
*/
template <uint32_t input_freq, uint32_t target_freq>
constexpr en_clk_sysclk_div_factor_t get_division_factor() {
// Calculate the divider to get the target frequency
constexpr float fdivider = static_cast<float>(input_freq) / static_cast<float>(target_freq);
constexpr int divider = static_cast<int>(fdivider);
// divider must be an integer
static_assert(fdivider == divider, "Target frequency not achievable, divider must be an integer");
// divider must be between 1 and 64 (enum range), and must be a power of 2
static_assert(divider >= 1 && divider <= 64, "Invalid divider, out of range");
static_assert((divider & (divider - 1)) == 0, "Invalid divider, not a power of 2");
// return the divider
switch (divider) {
case 1: return ClkSysclkDiv1;
case 2: return ClkSysclkDiv2;
case 4: return ClkSysclkDiv4;
case 8: return ClkSysclkDiv8;
case 16: return ClkSysclkDiv16;
case 32: return ClkSysclkDiv32;
case 64: return ClkSysclkDiv64;
}
}
/**
* @brief Validate the runtime clocks match the expected values.
*/
void validate_system_clocks() {
#define CLOCK_ASSERT(expected, actual) \
if (expected != actual) { \
SERIAL_ECHOPGM( \
"Clock Mismatch for " #expected ": " \
"expected ", expected, \
", got ", actual \
); \
CORE_ASSERT_FAIL("Clock Mismatch: " #expected); \
}
update_system_clock_frequencies();
CLOCK_ASSERT(F_SYSTEM_CLOCK, SYSTEM_CLOCK_FREQUENCIES.system);
CLOCK_ASSERT(F_HCLK, SYSTEM_CLOCK_FREQUENCIES.hclk);
CLOCK_ASSERT(F_EXCLK, SYSTEM_CLOCK_FREQUENCIES.exclk);
CLOCK_ASSERT(F_PCLK0, SYSTEM_CLOCK_FREQUENCIES.pclk0);
CLOCK_ASSERT(F_PCLK1, SYSTEM_CLOCK_FREQUENCIES.pclk1);
CLOCK_ASSERT(F_PCLK2, SYSTEM_CLOCK_FREQUENCIES.pclk2);
CLOCK_ASSERT(F_PCLK3, SYSTEM_CLOCK_FREQUENCIES.pclk3);
CLOCK_ASSERT(F_PCLK4, SYSTEM_CLOCK_FREQUENCIES.pclk4);
}
/**
* @brief Configure HC32 system clocks.
*
* This function is called by the Arduino core early in the startup process, before setup() is called.
* It is used to configure the system clocks to the desired state.
*
* See https://github.com/MarlinFirmware/Marlin/pull/27099 for more information.
*/
void core_hook_sysclock_init() {
// Set wait cycles, as we are about to switch to 200 MHz HCLK
sysclock_configure_flash_wait_cycles();
sysclock_configure_sram_wait_cycles();
// Configure MPLLp to 200 MHz output, with different settings depending on XTAL availability
#if BOARD_XTAL_FREQUENCY == 8000000 // 8 MHz XTAL
// - M = 1 => 8 MHz / 1 = 8 MHz
// - N = 50 => 8 MHz * 50 = 400 MHz
// - P = 2 => 400 MHz / 2 = 200 MHz (sysclk)
// - Q,R = 4 => 400 MHz / 4 = 100 MHz (dont care)
stc_clk_mpll_cfg_t pllConf = {
.PllpDiv = 2u, // P
.PllqDiv = 4u, // Q
.PllrDiv = 4u, // R
.plln = 50u, // N
.pllmDiv = 1u, // M
};
sysclock_configure_xtal();
sysclock_configure_mpll(ClkPllSrcXTAL, &pllConf);
// Select MPLL input frequency based on clock availability
#if BOARD_XTAL_FREQUENCY == 8000000 || BOARD_XTAL_FREQUENCY == 16000000 // 8 MHz or 16 MHz XTAL
constexpr uint32_t mpll_input_clock = BOARD_XTAL_FREQUENCY;
#elif BOARD_XTAL_FREQUENCY == 16000000 // 16 MHz XTAL
// - M = 1 => 16 MHz / 1 = 16 MHz
// - N = 50 => 16 MHz * 25 = 400 MHz
// - P = 2 => 400 MHz / 2 = 200 MHz (sysclk)
// - Q,R = 4 => 400 MHz / 4 = 100 MHz (dont care)
stc_clk_mpll_cfg_t pllConf = {
.PllpDiv = 2u, // P
.PllqDiv = 4u, // Q
.PllrDiv = 4u, // R
.plln = 50u, // N
.pllmDiv = 1u, // M
};
sysclock_configure_xtal();
sysclock_configure_mpll(ClkPllSrcXTAL, &pllConf);
#warning "HC32F460 with 16 MHz XTAL has not been tested."
#if BOARD_XTAL_FREQUENCY == 16000000
#warning "HC32F460 with 16 MHz XTAL has not been tested."
#endif
#else // HRC (16 MHz)
// - M = 1 => 16 MHz / 1 = 16 MHz
// - N = 25 => 16 MHz * 25 = 400 MHz
// - P = 2 => 400 MHz / 2 = 200 MHz (sysclk)
// - Q,R = 4 => 400 MHz / 4 = 100 MHz (dont care)
stc_clk_mpll_cfg_t pllConf = {
.PllpDiv = 2u, // P
.PllqDiv = 4u, // Q
.PllrDiv = 4u, // R
.plln = 25u, // N
.pllmDiv = 1u, // M
};
constexpr uint32_t mpll_input_clock = 16000000;
sysclock_configure_hrc();
sysclock_configure_mpll(ClkPllSrcHRC, &pllConf);
// HRC could have been configured by ICG to 20 MHz
// TODO: handle gracefully if HRC is not 16 MHz
@ -91,29 +171,56 @@ void core_hook_sysclock_init() {
panic("HRC is not 16 MHz");
}
#ifdef BOARD_XTAL_FREQUENCY
#if defined(BOARD_XTAL_FREQUENCY)
#warning "No valid XTAL frequency defined, falling back to HRC."
#endif
#endif
// sysclk is now configured according to F_CPU (i.e., 200MHz PLL output)
const uint32_t sysclock = F_CPU;
// Automagically calculate MPLL configuration
constexpr stc_clk_mpll_cfg_t pllConf = get_mpll_config(mpll_input_clock, F_SYSTEM_CLOCK);
static_assert(pllConf.pllmDiv != 0 && pllConf.plln != 0 && pllConf.PllpDiv != 0, "MPLL auto-configuration failed");
sysclock_configure_mpll(ClkPllSrcXTAL, &pllConf);
// Setup clock divisors for sysclk = 200 MHz
// Note: PCLK1 is used for step+temp timers, and need to be kept at 50 MHz (until there is a better solution)
// Setup clock divisors
constexpr stc_clk_sysclk_cfg_t sysClkConf = {
.enHclkDiv = ClkSysclkDiv1, // HCLK = 200 MHz (CPU)
.enExclkDiv = ClkSysclkDiv2, // EXCLK = 100 MHz (SDIO)
.enPclk0Div = ClkSysclkDiv2, // PCLK0 = 100 MHz (Timer6 (not used))
.enPclk1Div = ClkSysclkDiv4, // PCLK1 = 50 MHz (USART, SPI, I2S, Timer0 (step+temp), TimerA (Servo))
.enPclk2Div = ClkSysclkDiv8, // PCLK2 = 25 MHz (ADC)
.enPclk3Div = ClkSysclkDiv8, // PCLK3 = 25 MHz (I2C, WDT)
.enPclk4Div = ClkSysclkDiv2, // PCLK4 = 100 MHz (ADC ctl)
.enHclkDiv = get_division_factor<F_SYSTEM_CLOCK, F_HCLK>(),
.enExclkDiv = get_division_factor<F_SYSTEM_CLOCK, F_EXCLK>(),
.enPclk0Div = get_division_factor<F_SYSTEM_CLOCK, F_PCLK0>(),
.enPclk1Div = get_division_factor<F_SYSTEM_CLOCK, F_PCLK1>(),
.enPclk2Div = get_division_factor<F_SYSTEM_CLOCK, F_PCLK2>(),
.enPclk3Div = get_division_factor<F_SYSTEM_CLOCK, F_PCLK3>(),
.enPclk4Div = get_division_factor<F_SYSTEM_CLOCK, F_PCLK4>(),
};
sysclock_set_clock_dividers(&sysClkConf);
// Set power mode, before switch
power_mode_update_pre(F_SYSTEM_CLOCK);
// Switch to MPLL-P as system clock source
CLK_SetSysClkSource(CLKSysSrcMPLL);
// Set power mode, after switch
power_mode_update_post(F_SYSTEM_CLOCK);
// Verify clocks match expected values (at runtime)
#if ENABLED(MARLIN_DEV_MODE) || ENABLED(ALWAYS_VALIDATE_CLOCKS)
validate_system_clocks();
#endif
// Verify clock configuration (at compile time)
#if ARDUINO_CORE_VERSION_INT >= GET_VERSION_INT(1, 2, 0)
assert_mpll_config_valid<
mpll_input_clock,
pllConf.pllmDiv,
pllConf.plln,
pllConf.PllpDiv,
pllConf.PllqDiv,
pllConf.PllrDiv
>();
assert_system_clocks_valid<
sysclock,
F_SYSTEM_CLOCK,
sysClkConf.enHclkDiv,
sysClkConf.enPclk0Div,
sysClkConf.enPclk1Div,
@ -122,18 +229,14 @@ void core_hook_sysclock_init() {
sysClkConf.enPclk4Div,
sysClkConf.enExclkDiv
>();
static_assert(get_mpll_output_clock(
mpll_input_clock,
pllConf.pllmDiv,
pllConf.plln,
pllConf.PllpDiv
) == F_SYSTEM_CLOCK, "actual MPLL output clock does not match F_SYSTEM_CLOCK");
#endif
sysclock_set_clock_dividers(&sysClkConf);
// Set power mode
power_mode_update_pre(sysclock);
// Switch to MPLL as sysclk source
CLK_SetSysClkSource(CLKSysSrcMPLL);
// Set power mode
power_mode_update_post(sysclock);
}
#endif // ARDUINO_ARCH_HC32

View file

@ -0,0 +1,65 @@
/**
* Marlin 3D Printer Firmware
* Copyright (c) 2024 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 <https://www.gnu.org/licenses/>.
*
*/
#pragma once
/**
* HC32F460 system clock configuration.
*
* With the HC32 HAL, the various peripheral clocks (including the CPU clock) are derived
* from the main PLL (MPLL-P) output (referred to at F_SYSTEM_CLOCK).
*
* F_SYSTEM_CLOCK is the target frequency of the main PLL, and the PLL is automatically configured
* to achieve this frequency.
*
* The peripheral clocks are the result of integer division of F_SYSTEM_CLOCK.
* Their target frequencies are defined here, and the required division factors are calculated automatically.
* Note that the division factor must be a power of 2 between 1 and 64.
* If the target frequency is not achievable, a compile-time error will be generated.
*
* Additionally, there are interdependencies between the peripheral clocks, which are described in
* Section 4.4 "Working Clock Specifications" of the HC32F460 Reference Manual.
* With Arduino core >= 1.2.0, these interdependencies are checked at compile time.
* On earlier versions, you are on your own.
*
* For all clock frequencies, they can be checked at runtime by enabling the 'ALWAYS_VALIDATE_CLOCKS' define.
* In MARLIN_DEV_MODE, they will also be printed to the serial console by 'MarlinHAL::HAL_clock_frequencies_dump'.
*
* See https://github.com/MarlinFirmware/Marlin/pull/27099 for more information.
*/
// Target peripheral clock frequencies, must be integer divisors of F_SYSTEM_CLOCK.
// Changing the frequency here will automagically update everything else.
#define F_HCLK 200000000UL // 200 MHz; CPU
#define F_EXCLK (F_HCLK / 2) // 100 MHz; SDIO
#define F_PCLK0 (F_HCLK / 2) // 100 MHz; Timer6 (unused)
#define F_PCLK1 (F_HCLK / 4) // 50 MHz; USART, SPI, Timer0 (step + temp), TimerA (Servo)
#define F_PCLK2 (F_HCLK / 8) // 25 MHz; ADC Sampling
#define F_PCLK3 (F_HCLK / 8) // 25 MHz; I2C, WDT
#define F_PCLK4 (F_HCLK / 2) // 100 MHz; ADC Control
// MPLL-P clock target frequency. This must be >= the highest peripheral clock frequency.
// PLL config is automatically calculated based on this value.
#define F_SYSTEM_CLOCK F_HCLK
// The Peripheral clocks are only checked at runtime if this is enabled OR MARLIN_DEV_MODE is enabled.
// Compile time checks are always performed with Arduino core version >= 1.2.0.
#define ALWAYS_VALIDATE_CLOCKS 1

View file

@ -20,6 +20,7 @@
#pragma once
#include <stdint.h>
#include <Timer0.h>
#include "sysclock.h"
//
// Timer Types
@ -42,17 +43,15 @@ extern Timer0 step_timer;
* HAL_TIMER_RATE must be known at compile time since it's used to calculate
* STEPPER_TIMER_RATE, which is used in 'constexpr' calculations.
* On the HC32F460 the timer rate depends on PCLK1, which is derived from the
* system clock configured at runtime. As a workaround, we use the existing
* assumption of a 200MHz clock, defining F_CPU as 200000000, then configure PCLK1
* as F_CPU with a divider of 4 in 'sysclock.cpp::core_hook_sysclock_init'.
* system clock configured at runtime.
* Thus we use the 'F_PCLK1' constant defined in 'sysclock.h'.
*
* If you face issues with this assumption, please double-check with the values
* printed by 'MarlinHAL::HAL_clock_frequencies_dump'.
* See https://github.com/MarlinFirmware/Marlin/pull/27099 for more information.
*
* TODO: If the 'constexpr' requirement is ever lifted, use TIMER0_BASE_FREQUENCY instead
* NOTE: If the 'constexpr' requirement is ever lifted, TIMER0_BASE_FREQUENCY could
* be used instead. Tho this would probably not make any noticable difference.
*/
#define HAL_TIMER_RATE (F_CPU / 4) // i.e., 50MHz
//#define HAL_TIMER_RATE TIMER0_BASE_FREQUENCY
#define HAL_TIMER_RATE F_PCLK1
// Temperature timer
#define TEMP_TIMER_NUM (&temp_timer)

View file

@ -37,7 +37,7 @@ if pioutil.is_pio_build():
#
# platformio.ini will accept this for a Windows upload port designation: 'upload_port = L:'
# Windows - doesn't care about the disk's name, only cares about the drive letter
import subprocess,string
import subprocess, string
from ctypes import windll
from pathlib import PureWindowsPath

Binary file not shown.

View file

@ -74,13 +74,13 @@
#define EEPROM_SLOTS ((FLASH_UNIT_SIZE) / (MARLIN_EEPROM_SIZE))
#define SLOT_ADDRESS(slot) (FLASH_ADDRESS_START + (slot * (MARLIN_EEPROM_SIZE)))
#define UNLOCK_FLASH() if (!flash_unlocked) { \
HAL_FLASH_Unlock(); \
__HAL_FLASH_CLEAR_FLAG(FLASH_FLAG_EOP | FLASH_FLAG_OPERR | FLASH_FLAG_WRPERR | \
FLASH_FLAG_PGAERR | FLASH_FLAG_PGPERR | FLASH_FLAG_PGSERR); \
flash_unlocked = true; \
}
#define LOCK_FLASH() if (flash_unlocked) { HAL_FLASH_Lock(); flash_unlocked = false; }
#ifdef STM32H7xx
#define FLASHWORD_SIZE 32U // STM32H7xx a FLASHWORD is 32 bytes (256 bits)
#define FLASH_FLAGS_TO_CLEAR (FLASH_FLAG_EOP | FLASH_FLAG_OPERR | FLASH_FLAG_WRPERR | FLASH_FLAG_PGSERR)
#else
#define FLASHWORD_SIZE 4U // STM32F4xx a FLASHWORD is 4 bytes sizeof(uint32_t)
#define FLASH_FLAGS_TO_CLEAR (FLASH_FLAG_EOP | FLASH_FLAG_OPERR | FLASH_FLAG_WRPERR | FLASH_FLAG_PGAERR | FLASH_FLAG_PGPERR | FLASH_FLAG_PGSERR)
#endif
#define EMPTY_UINT32 ((uint32_t)-1)
#define EMPTY_UINT8 ((uint8_t)-1)
@ -88,7 +88,7 @@
static uint8_t ram_eeprom[MARLIN_EEPROM_SIZE] __attribute__((aligned(4))) = {0};
static int current_slot = -1;
static_assert(0 == MARLIN_EEPROM_SIZE % 4, "MARLIN_EEPROM_SIZE must be a multiple of 4"); // Ensure copying as uint32_t is safe
static_assert(0 == MARLIN_EEPROM_SIZE % FLASHWORD_SIZE, "MARLIN_EEPROM_SIZE must be a multiple of the FLASHWORD size"); // Ensure copying as uint32_t is safe
static_assert(0 == FLASH_UNIT_SIZE % MARLIN_EEPROM_SIZE, "MARLIN_EEPROM_SIZE must divide evenly into your FLASH_UNIT_SIZE");
static_assert(FLASH_UNIT_SIZE >= MARLIN_EEPROM_SIZE, "FLASH_UNIT_SIZE must be greater than or equal to your MARLIN_EEPROM_SIZE");
static_assert(IS_FLASH_SECTOR(FLASH_SECTOR), "FLASH_SECTOR is invalid");
@ -147,11 +147,15 @@ bool PersistentStore::access_start() {
bool PersistentStore::access_finish() {
if (eeprom_data_written) {
#ifdef STM32F4xx
// MCU may come up with flash error bits which prevent some flash operations.
// Clear flags prior to flash operations to prevent errors.
__HAL_FLASH_CLEAR_FLAG(FLASH_FLAG_OPERR | FLASH_FLAG_WRPERR | FLASH_FLAG_PGAERR | FLASH_FLAG_PGPERR | FLASH_FLAG_PGSERR);
#endif
#ifdef STM32H7xx
__HAL_FLASH_CLEAR_FLAG(FLASH_FLAG_OPERR | FLASH_FLAG_WRPERR | FLASH_FLAG_PGSERR);
#endif
#if ENABLED(FLASH_EEPROM_LEVELING)
@ -170,7 +174,12 @@ bool PersistentStore::access_finish() {
EraseInitStruct.NbSectors = 1;
current_slot = EEPROM_SLOTS - 1;
UNLOCK_FLASH();
if (!flash_unlocked) {
HAL_FLASH_Unlock();
__HAL_FLASH_CLEAR_FLAG(FLASH_FLAGS_TO_CLEAR);
flash_unlocked = true;
}
TERN_(HAS_PAUSE_SERVO_OUTPUT, PAUSE_SERVO_OUTPUT());
hal.isr_off();
@ -181,26 +190,37 @@ bool PersistentStore::access_finish() {
DEBUG_ECHOLNPGM("HAL_FLASHEx_Erase=", status);
DEBUG_ECHOLNPGM("GetError=", HAL_FLASH_GetError());
DEBUG_ECHOLNPGM("SectorError=", SectorError);
LOCK_FLASH();
if (flash_unlocked) {
HAL_FLASH_Lock();
flash_unlocked = false;
}
return false;
}
}
UNLOCK_FLASH();
if (!flash_unlocked) {
HAL_FLASH_Unlock();
__HAL_FLASH_CLEAR_FLAG(FLASH_FLAGS_TO_CLEAR);
flash_unlocked = true;
}
uint32_t offset = 0,
address = SLOT_ADDRESS(current_slot),
address_end = address + MARLIN_EEPROM_SIZE,
data = 0;
address_end = address + MARLIN_EEPROM_SIZE;
bool success = true;
while (address < address_end) {
memcpy(&data, ram_eeprom + offset, sizeof(data));
status = HAL_FLASH_Program(FLASH_TYPEPROGRAM_WORD, address, data);
#ifdef STM32H7xx
status = HAL_FLASH_Program(FLASH_TYPEPROGRAM_FLASHWORD, address, uint32_t(ram_eeprom + offset));
#else
//memcpy(&data, ram_eeprom + offset, sizeof(data)); // IRON, IMPROVED
//status = HAL_FLASH_Program(FLASH_TYPEPROGRAM_WORD, address, data);
status = HAL_FLASH_Program(FLASH_TYPEPROGRAM_WORD, address, *(uint32_t*)(ram_eeprom + offset)); // IRON, OPTIMIZED
#endif
if (status == HAL_OK) {
address += sizeof(uint32_t);
offset += sizeof(uint32_t);
address += FLASHWORD_SIZE;
offset += FLASHWORD_SIZE;
}
else {
DEBUG_ECHOLNPGM("HAL_FLASH_Program=", status);
@ -211,7 +231,10 @@ bool PersistentStore::access_finish() {
}
}
LOCK_FLASH();
if (flash_unlocked) {
HAL_FLASH_Lock();
flash_unlocked = false;
}
if (success) {
eeprom_data_written = false;

View file

@ -77,6 +77,7 @@ void FastIO_init(); // Must be called before using fast io macros
#define SET_INPUT_PULLUP(IO) _SET_MODE(IO, INPUT_PULLUP) //!< Input with Pull-up activation
#define SET_INPUT_PULLDOWN(IO) _SET_MODE(IO, INPUT_PULLDOWN) //!< Input with Pull-down activation
#define SET_OUTPUT(IO) OUT_WRITE(IO, LOW)
#define SET_OUTPUT_OD(IO) OUT_WRITE_OD(IO, LOW)
#define SET_PWM(IO) _SET_MODE(IO, PWM)
#define IS_INPUT(IO)

View file

@ -36,8 +36,8 @@
#error "SDCARD_EEPROM_EMULATION requires SDSUPPORT. Enable SDSUPPORT or choose another EEPROM emulation."
#endif
#if !defined(STM32F4xx) && ENABLED(FLASH_EEPROM_LEVELING)
#error "FLASH_EEPROM_LEVELING is currently only supported on STM32F4 hardware."
#if NONE(STM32F4xx, STM32H7xx) && ENABLED(FLASH_EEPROM_LEVELING)
#error "FLASH_EEPROM_LEVELING is currently only supported on STM32F4/H7 hardware." // IRON
#endif
#if ENABLED(SERIAL_STATS_MAX_RX_QUEUED)

View file

@ -44,6 +44,7 @@
#define SET_INPUT_PULLUP(IO) _SET_MODE(IO, GPIO_INPUT_PU)
#define SET_INPUT_PULLDOWN(IO) _SET_MODE(IO, GPIO_INPUT_PD)
#define SET_OUTPUT(IO) OUT_WRITE(IO, LOW)
#define SET_OUTPUT_OD(IO) OUT_WRITE_OD(IO, LOW)
#define SET_PWM(IO) pinMode(IO, PWM) // do{ gpio_set_mode(PIN_MAP[pin].gpio_device, PIN_MAP[pin].gpio_bit, GPIO_AF_OUTPUT_PP); timer_set_mode(PIN_MAP[pin].timer_device, PIN_MAP[pin].timer_channel, TIMER_PWM); }while(0)
#define SET_PWM_OD(IO) pinMode(IO, PWM_OPEN_DRAIN)

View file

@ -174,6 +174,9 @@ void calibrate_delay_loop();
// Delay in microseconds
#define DELAY_US(x) DELAY_CYCLES((x) * ((F_CPU) / 1000000UL))
#define DELAY_CYCLES_VAR DELAY_CYCLES
#else
#error "Unsupported MCU architecture"

View file

@ -1260,7 +1260,7 @@ void setup() {
SETUP_RUN(runout.setup());
#endif
#if HAS_TMC220x
#if HAS_TMC_UART
SETUP_RUN(tmc_serial_begin());
#endif

View file

@ -472,6 +472,7 @@
#define BOARD_MELLOW_FLY_E3_V2 5250 // Mellow Fly E3 V2 (STM32F407VG)
#define BOARD_BLACKBEEZMINI_V1 5251 // BlackBeezMini V1 (STM32F401CCU6)
#define BOARD_XTLW_CLIMBER_8TH 5252 // XTLW Climber-8th (STM32F407VGT6)
#define BOARD_FLY_RRF_E3_V1 5253 // Fly RRF E3 V1.0 (STM32F407VG)
//
// Other ARM Cortex-M4

View file

@ -346,7 +346,7 @@ enum AxisEnum : uint8_t {
#define LOOP_DISTINCT_E(VAR) for (uint8_t VAR = 0; VAR < DISTINCT_E; ++VAR)
//
// feedRate_t is just a humble float
// feedRate_t is just a humble float that can represent mm/s or mm/min
//
typedef float feedRate_t;

View file

@ -297,7 +297,13 @@ G29_parameters_t unified_bed_leveling::param;
void unified_bed_leveling::G29() {
bool probe_deployed = false;
#ifdef EVENT_GCODE_AFTER_G29
bool probe_deployed = false;
#define SET_PROBE_DEPLOYED(N) probe_deployed = N
#else
#define SET_PROBE_DEPLOYED(N)
#endif
if (G29_parse_parameters()) return; // Abort on parameter error
const uint8_t p_val = parser.byteval('P');
@ -316,6 +322,11 @@ void unified_bed_leveling::G29() {
#endif
probe.use_probing_tool();
#ifdef EVENT_GCODE_BEFORE_G29
if (DEBUGGING(LEVELING)) DEBUG_ECHOLNPGM("Before G29 G-code: ", EVENT_GCODE_BEFORE_G29);
gcode.process_subcommands_now(F(EVENT_GCODE_BEFORE_G29));
#endif
// Position bed horizontally and Z probe vertically.
#if HAS_SAFE_BED_LEVELING
xyze_pos_t safe_position = current_position;
@ -430,7 +441,7 @@ void unified_bed_leveling::G29() {
do_blocking_move_to_xy(0.5f * ((MESH_MIN_X) + (MESH_MAX_X)), 0.5f * ((MESH_MIN_Y) + (MESH_MAX_Y)));
#endif
report_current_position();
probe_deployed = true;
SET_PROBE_DEPLOYED(true);
}
#endif // HAS_BED_PROBE
@ -465,7 +476,7 @@ void unified_bed_leveling::G29() {
probe_entire_mesh(param.XY_pos, parser.seen_test('T'), parser.seen_test('E'), parser.seen_test('U'));
report_current_position();
probe_deployed = true;
SET_PROBE_DEPLOYED(true);
} break;
#endif // HAS_BED_PROBE
@ -503,7 +514,7 @@ void unified_bed_leveling::G29() {
SERIAL_ECHOLNPGM("?Error in Business Card measurement.");
return;
}
probe_deployed = true;
SET_PROBE_DEPLOYED(true);
}
if (!position_is_reachable(param.XY_pos)) {
@ -681,13 +692,11 @@ void unified_bed_leveling::G29() {
#endif
#ifdef EVENT_GCODE_AFTER_G29
if (DEBUGGING(LEVELING)) DEBUG_ECHOLNPGM("Z Probe End Script: ", EVENT_GCODE_AFTER_G29);
if (DEBUGGING(LEVELING)) DEBUG_ECHOLNPGM("After G29 G-code: ", EVENT_GCODE_AFTER_G29);
if (probe_deployed) {
planner.synchronize();
gcode.process_subcommands_now(F(EVENT_GCODE_AFTER_G29));
}
#else
UNUSED(probe_deployed);
#endif
probe.use_probing_tool(false);

View file

@ -28,10 +28,6 @@
Mixer mixer;
#ifdef MIXER_NORMALIZER_DEBUG
#include "../core/serial.h"
#endif
// Used up to Planner level
uint_fast8_t Mixer::selected_vtool = 0;
float Mixer::collector[MIXING_STEPPERS]; // mix proportion. 0.0 = off, otherwise <= COLOR_A_MASK.

View file

@ -219,14 +219,14 @@ bool load_filament(const_float_t slow_load_length/*=0*/, const_float_t fast_load
while (wait_for_user) {
impatient_beep(max_beep_count);
#if ALL(FILAMENT_CHANGE_RESUME_ON_INSERT, FILAMENT_RUNOUT_SENSOR)
#if ALL(HAS_FILAMENT_SENSOR, FILAMENT_CHANGE_RESUME_ON_INSERT)
#if MULTI_FILAMENT_SENSOR
#define _CASE_INSERTED(N) case N-1: if (READ(FIL_RUNOUT##N##_PIN) != FIL_RUNOUT##N##_STATE) wait_for_user = false; break;
switch (active_extruder) {
REPEAT_1(NUM_RUNOUT_SENSORS, _CASE_INSERTED)
}
#else
if (READ(FIL_RUNOUT_PIN) != FIL_RUNOUT_STATE) wait_for_user = false;
if (!FILAMENT_IS_OUT()) wait_for_user = false;
#endif
#endif
idle_no_sleep();

View file

@ -28,8 +28,9 @@
#if ENABLED(POWER_LOSS_RECOVERY)
#include "../inc/MarlinConfig.h"
#include "powerloss.h"
#include "../core/macros.h"
#if ENABLED(EXTENSIBLE_UI)
#include "../lcd/extui/ui_api.h"
@ -60,7 +61,6 @@ uint32_t PrintJobRecovery::cmd_sdpos, // = 0
#include "../module/planner.h"
#include "../module/printcounter.h"
#include "../module/temperature.h"
#include "../core/serial.h"
#if HOMING_Z_WITH_PROBE
#include "../module/probe.h"

View file

@ -51,6 +51,8 @@
#define HAS_FILAMENT_SWITCH 1
#endif
#define FILAMENT_IS_OUT() (READ(FIL_RUNOUT_PIN) == FIL_RUNOUT_STATE)
typedef Flags<
#if NUM_MOTION_SENSORS > NUM_RUNOUT_SENSORS
NUM_MOTION_SENSORS

View file

@ -614,9 +614,10 @@
default: break;
}
}
#endif
#endif // TMC2160 || TMC5160
#if HAS_TMC220x
static void _tmc_status(TMC2208Stepper &st, const TMC_debug_enum i) {
switch (i) {
case TMC_PWM_SCALE_SUM: SERIAL_ECHO(st.pwm_scale_sum()); break;
@ -664,7 +665,8 @@
}
}
#endif
#endif
#endif // HAS_TMC220x
#if HAS_DRIVER(TMC2660)
static void _tmc_parse_drv_status(TMC2660Stepper, const TMC_drv_status_enum) { }

View file

@ -29,7 +29,7 @@
#include <TMCStepper.h>
#include "../module/planner.h"
#define CHOPPER_DEFAULT_12V { 3, -1, 1 }
#define CHOPPER_DEFAULT_12V { 3, -1, 1 } // { toff, hend, hstrt }
#define CHOPPER_DEFAULT_19V { 4, 1, 1 }
#define CHOPPER_DEFAULT_24V { 4, 2, 1 }
#define CHOPPER_DEFAULT_36V { 5, 2, 4 }

View file

@ -287,6 +287,11 @@ G29_TYPE GcodeSuite::G29() {
probe.use_probing_tool();
#ifdef EVENT_GCODE_BEFORE_G29
if (DEBUGGING(LEVELING)) DEBUG_ECHOLNPGM("Before G29 G-code: ", EVENT_GCODE_BEFORE_G29);
gcode.process_subcommands_now(F(EVENT_GCODE_BEFORE_G29));
#endif
#if ANY(PROBE_MANUALLY, AUTO_BED_LEVELING_LINEAR)
abl.abl_probe_index = -1;
#endif
@ -392,7 +397,12 @@ G29_TYPE GcodeSuite::G29() {
#if ABL_USES_GRID
constexpr feedRate_t min_probe_feedrate_mm_s = XY_PROBE_FEEDRATE_MIN;
xy_probe_feedrate_mm_s = MMM_TO_MMS(parser.linearval('S', XY_PROBE_FEEDRATE));
if (xy_probe_feedrate_mm_s < min_probe_feedrate_mm_s) {
xy_probe_feedrate_mm_s = min_probe_feedrate_mm_s;
SERIAL_ECHOLNPGM(GCODE_ERR_MSG("Feedrate (S) too low. (Using ", min_probe_feedrate_mm_s, ")"));
}
const float x_min = probe.min_x(), x_max = probe.max_x(),
y_min = probe.min_y(), y_max = probe.max_y();
@ -1003,7 +1013,7 @@ G29_TYPE GcodeSuite::G29() {
TERN_(Z_AFTER_PROBING, probe.move_z_after_probing());
#ifdef EVENT_GCODE_AFTER_G29
if (DEBUGGING(LEVELING)) DEBUG_ECHOLNPGM("Z Probe End Script: ", EVENT_GCODE_AFTER_G29);
if (DEBUGGING(LEVELING)) DEBUG_ECHOLNPGM("After G29 G-code: ", EVENT_GCODE_AFTER_G29);
planner.synchronize();
process_subcommands_now(F(EVENT_GCODE_AFTER_G29));
#endif

View file

@ -22,7 +22,6 @@
#include "../gcode.h"
#include "../../module/settings.h"
#include "../../core/serial.h"
#include "../../inc/MarlinConfig.h"
#if ENABLED(CONFIGURATION_EMBEDDING)

View file

@ -155,7 +155,7 @@ void GcodeSuite::M115() {
cap_line(F("AUTOLEVEL"), ENABLED(HAS_AUTOLEVEL));
// RUNOUT (M412, M600)
cap_line(F("RUNOUT"), ENABLED(FILAMENT_RUNOUT_SENSOR));
cap_line(F("RUNOUT"), ENABLED(HAS_FILAMENT_SENSOR));
// Z_PROBE (G30)
cap_line(F("Z_PROBE"), ENABLED(HAS_BED_PROBE));

View file

@ -29,10 +29,6 @@
#include "../../module/probe.h"
#include "../../module/planner.h"
#if ENABLED(BABYSTEP_ZPROBE_OFFSET)
#include "../../core/serial.h"
#endif
#if ENABLED(MESH_BED_LEVELING)
#include "../../feature/bedlevel/bedlevel.h"
#endif

View file

@ -21,7 +21,6 @@
*/
#include "../gcode.h"
#include "../../core/serial.h"
#include "../../module/printcounter.h"
#include "../../libs/duration_t.h"
#include "../../lcd/marlinui.h"

View file

@ -67,6 +67,7 @@
#undef MECHANICAL_SWITCHING_NOZZLE
#undef MIXING_EXTRUDER
#undef HOTEND_IDLE_TIMEOUT
#undef HOTEND_OVERSHOOT
#undef DISABLE_E
#undef PREVENT_LENGTHY_EXTRUDE
#undef FILAMENT_RUNOUT_SENSOR

View file

@ -585,7 +585,7 @@
#endif
#endif
#if ANY(HAS_WIRED_LCD, EXTENSIBLE_UI, DWIN_LCD_PROUI, DWIN_CREALITY_LCD_JYERSUI)
#if ANY(HAS_WIRED_LCD, EXTENSIBLE_UI, HAS_DWIN_E3V2)
/**
* HAS_DISPLAY indicates the display uses these MarlinUI methods...
* - update
@ -605,10 +605,8 @@
* (calling advance_status_scroll, status_and_len for a scrolling status message)
*/
#define HAS_DISPLAY 1
#endif
#if ANY(HAS_DISPLAY, DWIN_CREALITY_LCD)
#define HAS_UI_UPDATE 1
#define HAS_STATUS_MESSAGE 1
#endif
#if HAS_WIRED_LCD && !HAS_GRAPHICAL_TFT && !IS_DWIN_MARLINUI
@ -619,10 +617,6 @@
#define HAS_UTF8_UTILS 1
#endif
#if ANY(HAS_DISPLAY, HAS_DWIN_E3V2)
#define HAS_STATUS_MESSAGE 1
#endif
#if IS_ULTIPANEL && DISABLED(NO_LCD_MENUS)
#define HAS_MARLINUI_MENU 1
#endif

View file

@ -71,17 +71,19 @@
#undef TEMP_SENSOR_BED
#undef THERMAL_PROTECTION_BED
#undef MAX_BED_POWER
#undef PREHEAT_1_TEMP_BED
#undef PREHEAT_2_TEMP_BED
#endif
#if !TEMP_SENSOR_CHAMBER
#undef TEMP_SENSOR_CHAMBER
#undef THERMAL_PROTECTION_CHAMBER
#undef CHAMBER_AUTO_FAN_PIN
#undef MAX_CHAMBER_POWER
#undef PREHEAT_1_TEMP_CHAMBER
#undef PREHEAT_2_TEMP_CHAMBER
#endif
#if !TEMP_SENSOR_COOLER
#undef TEMP_SENSOR_COOLER
#undef THERMAL_PROTECTION_COOLER
#undef COOLER_AUTO_FAN_PIN
#endif
#if !TEMP_SENSOR_PROBE
#undef TEMP_SENSOR_PROBE
@ -442,6 +444,7 @@
#else
// Clear probe pin settings when no probe is selected
#undef Z_MIN_PROBE_USES_Z_MIN_ENDSTOP_PIN
#undef Z_MIN_PROBE_ENDSTOP_HIT_STATE
#undef USE_PROBE_FOR_Z_HOMING
#undef Z_MIN_PROBE_REPEATABILITY_TEST
#undef HOMING_Z_WITH_PROBE
@ -490,6 +493,9 @@
#endif
#if ANY(AUTO_BED_LEVELING_LINEAR, AUTO_BED_LEVELING_BILINEAR)
#define ABL_USES_GRID 1
#ifndef XY_PROBE_FEEDRATE_MIN
#define XY_PROBE_FEEDRATE_MIN 60 // Minimum mm/min value for 'G29 S<feedrate>'
#endif
#endif
#if ANY(AUTO_BED_LEVELING_LINEAR, AUTO_BED_LEVELING_BILINEAR, AUTO_BED_LEVELING_3POINT)
#define HAS_ABL_NOT_UBL 1

View file

@ -51,39 +51,39 @@
#define NUM_SERVOS 0
#if HAS_Z_SERVO_PROBE && NUM_SERVOS <= Z_PROBE_SERVO_NR
#undef NUM_SERVOS
#define NUM_SERVOS (Z_PROBE_SERVO_NR + 1)
#define NUM_SERVOS INCREMENT(Z_PROBE_SERVO_NR)
#endif
#if ENABLED(CHAMBER_VENT) && NUM_SERVOS <= CHAMBER_VENT_SERVO_NR
#undef NUM_SERVOS
#define NUM_SERVOS (CHAMBER_VENT_SERVO_NR + 1)
#define NUM_SERVOS INCREMENT(CHAMBER_VENT_SERVO_NR)
#endif
#if ENABLED(SWITCHING_TOOLHEAD) && NUM_SERVOS <= SWITCHING_TOOLHEAD_SERVO_NR
#undef NUM_SERVOS
#define NUM_SERVOS (SWITCHING_TOOLHEAD_SERVO_NR + 1)
#define NUM_SERVOS INCREMENT(SWITCHING_TOOLHEAD_SERVO_NR)
#endif
#if ENABLED(SWITCHING_NOZZLE)
#if NUM_SERVOS <= SWITCHING_NOZZLE_SERVO_NR
#undef NUM_SERVOS
#define NUM_SERVOS (SWITCHING_NOZZLE_SERVO_NR + 1)
#define NUM_SERVOS INCREMENT(SWITCHING_NOZZLE_SERVO_NR)
#endif
#if NUM_SERVOS <= SWITCHING_NOZZLE_E1_SERVO_NR
#undef NUM_SERVOS
#define NUM_SERVOS (SWITCHING_NOZZLE_E1_SERVO_NR + 1)
#define NUM_SERVOS INCREMENT(SWITCHING_NOZZLE_E1_SERVO_NR)
#endif
#endif
#if ENABLED(SWITCHING_EXTRUDER)
#if NUM_SERVOS <= SWITCHING_EXTRUDER_SERVO_NR
#undef NUM_SERVOS
#define NUM_SERVOS (SWITCHING_EXTRUDER_SERVO_NR + 1)
#define NUM_SERVOS INCREMENT(SWITCHING_EXTRUDER_SERVO_NR)
#endif
#if NUM_SERVOS <= SWITCHING_EXTRUDER_E23_SERVO_NR
#undef NUM_SERVOS
#define NUM_SERVOS (SWITCHING_EXTRUDER_E23_SERVO_NR + 1)
#define NUM_SERVOS INCREMENT(SWITCHING_EXTRUDER_E23_SERVO_NR)
#endif
#endif
#if ENABLED(SPINDLE_SERVO) && NUM_SERVOS <= SPINDLE_SERVO_NR
#undef NUM_SERVOS
#define NUM_SERVOS (SPINDLE_SERVO_NR + 1)
#define NUM_SERVOS INCREMENT(SPINDLE_SERVO_NR)
#endif
#endif // !defined(NUM_SERVOS)
@ -233,6 +233,14 @@
#undef STEALTHCHOP_E
#endif
#if !TEMP_SENSOR_CHAMBER
#undef CHAMBER_CHECK_INTERVAL
#undef CHAMBER_AUTO_FAN_PIN
#endif
#if !TEMP_SENSOR_COOLER
#undef COOLER_AUTO_FAN_PIN
#endif
#if ENABLED(DISABLE_X) && !defined(DISABLE_IDLE_X)
#define DISABLE_IDLE_X
#endif
@ -821,7 +829,12 @@
#undef TEMP_SENSOR_AD8495_GAIN
#undef TEMP_SENSOR_AD8495_OFFSET
#endif
#if !ANY_THERMISTOR_IS(998)
#undef DUMMY_THERMISTOR_998_VALUE
#endif
#if !ANY_THERMISTOR_IS(999)
#undef DUMMY_THERMISTOR_999_VALUE
#endif
#if !ALL(HAS_X_AXIS, HAS_HOTEND)
#undef AUTOTEMP
#endif
@ -838,6 +851,7 @@
#if !TEMP_SENSOR_BED
#undef BED_MINTEMP
#undef BED_MAXTEMP
#undef BED_OVERSHOOT
#undef CONTROLLER_FAN_BED_HEATING
#endif
#if DISABLED(THERMAL_PROTECTION_BED)
@ -861,6 +875,7 @@
#if !TEMP_SENSOR_COOLER
#undef COOLER_MINTEMP
#undef COOLER_MAXTEMP
#undef COOLER_OVERSHOOT
#endif
#if DISABLED(THERMAL_PROTECTION_COOLER)
#undef THERMAL_PROTECTION_COOLER_PERIOD

View file

@ -26,10 +26,10 @@
//
#include "MarlinConfigPre-6-type.h" // Include even with __MARLIN_DEPS__
#include "Conditionals-6-type.h"
#ifndef __MARLIN_DEPS__
#include "Conditionals-6-type.h"
#include HAL_PATH(.., inc/Conditionals_type.h)
#include "Changes.h"

View file

@ -26,5 +26,6 @@
#ifndef __MARLIN_DEPS__
#include HAL_PATH(.., inc/Conditionals_post.h)
#include "../core/types.h" // Ahead of sanity-checks
#endif
#include "../core/types.h" // Ahead of sanity-checks

View file

@ -1225,7 +1225,54 @@ static_assert(NUM_SERVOS <= NUM_SERVO_PLUGS, "NUM_SERVOS (or some servo index) i
#if 1 < 0 \
+ (DISABLED(BLTOUCH) && HAS_Z_SERVO_PROBE) \
+ COUNT_ENABLED(PROBE_MANUALLY, BLTOUCH, BD_SENSOR, FIX_MOUNTED_PROBE, NOZZLE_AS_PROBE, TOUCH_MI_PROBE, SOLENOID_PROBE, Z_PROBE_ALLEN_KEY, Z_PROBE_SLED, RACK_AND_PINION_PROBE, SENSORLESS_PROBING, MAGLEV4, MAG_MOUNTED_PROBE, BIQU_MICROPROBE_V1, BIQU_MICROPROBE_V2)
#error "Please enable only one probe option: PROBE_MANUALLY, SENSORLESS_PROBING, BLTOUCH, BD_SENSOR, FIX_MOUNTED_PROBE, NOZZLE_AS_PROBE, TOUCH_MI_PROBE, SOLENOID_PROBE, Z_PROBE_ALLEN_KEY, Z_PROBE_SLED, MAGLEV4, MAG_MOUNTED_PROBE, BIQU_MICROPROBE_V1, BIQU_MICROPROBE_V2, or Z Servo."
#error "Please enable only one probe option. See the following errors:"
#if ENABLED(BLTOUCH)
#error "(BLTOUCH is enabled.)"
#elif HAS_Z_SERVO_PROBE
#error "(Z_SERVO_PROBE is enabled.)"
#endif
#if ENABLED(PROBE_MANUALLY)
#error "(PROBE_MANUALLY is enabled.)"
#endif
#if ENABLED(BD_SENSOR)
#error "(BD_SENSOR is enabled.)"
#endif
#if ENABLED(FIX_MOUNTED_PROBE)
#error "(FIX_MOUNTED_PROBE is enabled.)"
#endif
#if ENABLED(NOZZLE_AS_PROBE)
#error "(NOZZLE_AS_PROBE is enabled.)"
#endif
#if ENABLED(TOUCH_MI_PROBE)
#error "(TOUCH_MI_PROBE is enabled.)"
#endif
#if ENABLED(SOLENOID_PROBE)
#error "(SOLENOID_PROBE is enabled.)"
#endif
#if ENABLED(Z_PROBE_ALLEN_KEY)
#error "(Z_PROBE_ALLEN_KEY is enabled.)"
#endif
#if ENABLED(Z_PROBE_SLED)
#error "(Z_PROBE_SLED is enabled.)"
#endif
#if ENABLED(RACK_AND_PINION_PROBE)
#error "(RACK_AND_PINION_PROBE is enabled.)"
#endif
#if ENABLED(SENSORLESS_PROBING)
#error "(SENSORLESS_PROBING is enabled.)"
#endif
#if ENABLED(MAGLEV4)
#error "(MAGLEV4 is enabled.)"
#endif
#if ENABLED(MAG_MOUNTED_PROBE)
#error "(MAG_MOUNTED_PROBE is enabled.)"
#endif
#if ENABLED(BIQU_MICROPROBE_V1)
#error "(BIQU_MICROPROBE_V1 is enabled.)"
#endif
#if ENABLED(BIQU_MICROPROBE_V2)
#error "(BIQU_MICROPROBE_V2 is enabled.)"
#endif
#endif
#if HAS_BED_PROBE
@ -2074,6 +2121,13 @@ static_assert(NUM_SERVOS <= NUM_SERVO_PLUGS, "NUM_SERVOS (or some servo index) i
#error "MAX31865_SENSOR_OHMS_2 and MAX31865_CALIBRATION_OHMS_2 must be set if TEMP_SENSOR_2/TEMP_SENSOR_REDUNDANT is MAX31865."
#endif
#endif
#if TEMP_SENSOR_BED_IS_MAX31865
#if !defined(MAX31865_SENSOR_WIRES_BED) || !WITHIN(MAX31865_SENSOR_WIRES_BED, 2, 4)
#error "MAX31865_SENSOR_WIRES_BED must be defined as an integer between 2 and 4."
#elif !defined(MAX31865_SENSOR_OHMS_BED) || !defined(MAX31865_CALIBRATION_OHMS_BED)
#error "MAX31865_SENSOR_OHMS_BED and MAX31865_CALIBRATION_OHMS_BED must be set if TEMP_SENSOR_BED is MAX31865."
#endif
#endif
/**
* Redundant temperature sensor config

View file

@ -42,7 +42,7 @@
* version was tagged.
*/
#ifndef STRING_DISTRIBUTION_DATE
#define STRING_DISTRIBUTION_DATE "2024-11-21"
#define STRING_DISTRIBUTION_DATE "2025-01-12"
#endif
/**

View file

@ -919,13 +919,6 @@
#warning "EDITABLE_STEPS_PER_UNIT is required to enable G92 runtime configuration of steps-per-unit."
#endif
/**
* HC32 clock speed is hard-coded in Marlin
*/
#if defined(ARDUINO_ARCH_HC32) && F_CPU == 200000000
#warning "HC32 clock is assumed to be 200MHz. If this isn't the case for your board please submit a report so we can add support."
#endif
/**
* Peltier with PIDTEMPBED
*/

View file

@ -0,0 +1,80 @@
/**
* Marlin 3D Printer Firmware
* Copyright (c) 2025 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 <https://www.gnu.org/licenses/>.
*
*/
#include "../../inc/MarlinConfigPre.h"
#if HAS_MARLINUI_U8GLIB && HAS_GAMES
#include "../menu/game/types.h" // includes dogm/game.h
void MarlinGame::frame_start() {
set_color(color::WHITE);
}
void MarlinGame::frame_end() {}
void MarlinGame::set_color(const color color) {
switch (color) {
default:
case color::WHITE: u8g.setColorIndex(1); break;
case color::BLACK: u8g.setColorIndex(0); break;
}
}
void MarlinGame::draw_hline(const game_dim_t x, const game_dim_t y, const game_dim_t w) {
u8g.drawHLine(x, y, w);
}
void MarlinGame::draw_vline(const game_dim_t x, const game_dim_t y, const game_dim_t h) {
u8g.drawVLine(x, y, h);
}
void MarlinGame::draw_frame(const game_dim_t x, const game_dim_t y, const game_dim_t w, const game_dim_t h) {
u8g.drawFrame(x, y, w, h);
}
void MarlinGame::draw_box(const game_dim_t x, const game_dim_t y, const game_dim_t w, const game_dim_t h) {
u8g.drawBox(x, y, w, h);
}
void MarlinGame::draw_pixel(const game_dim_t x, const game_dim_t y) {
u8g.drawPixel(x, y);
}
void MarlinGame::draw_bitmap(const game_dim_t x, const game_dim_t y, const game_dim_t bytes_per_row, const game_dim_t rows, const pgm_bitmap_t bitmap) {
u8g.drawBitmapP(x, y, bytes_per_row, rows, bitmap);
}
int MarlinGame::draw_string(const game_dim_t x, const game_dim_t y, const char* str) {
lcd_moveto(x, y);
return lcd_put_u8str_P(str);
}
int MarlinGame::draw_string(const game_dim_t x, const game_dim_t y, FSTR_P const fstr) {
lcd_moveto(x, y);
return lcd_put_u8str(fstr);
}
void MarlinGame::draw_int(const game_dim_t x, const game_dim_t y, const int value) {
lcd_put_int(x, y, value);
}
#endif // HAS_MARLINUI_U8GLIB && HAS_GAMES

View file

@ -0,0 +1,33 @@
/**
* Marlin 3D Printer Firmware
* Copyright (c) 2025 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 <https://www.gnu.org/licenses/>.
*
*/
#pragma once
#include "marlinui_DOGM.h"
#include "../lcdprint.h"
typedef uint8_t game_dim_t;
typedef const u8g_pgm_uint8_t* pgm_bitmap_t;
constexpr game_dim_t GAME_WIDTH = LCD_PIXEL_WIDTH;
constexpr game_dim_t GAME_HEIGHT = LCD_PIXEL_HEIGHT;
constexpr game_dim_t GAME_FONT_WIDTH = MENU_FONT_WIDTH;
constexpr game_dim_t GAME_FONT_ASCENT = MENU_FONT_ASCENT;

View file

@ -158,6 +158,7 @@ void dwinFrameClear(const uint16_t color) {
}
#if DISABLED(TJC_DISPLAY)
// Draw a point
// color: point color
// width: point width 0x01-0x0F
@ -173,7 +174,67 @@ void dwinFrameClear(const uint16_t color) {
dwinWord(i, y);
dwinSend(i);
}
#endif
// Draw a map of multiple points using minimal amount of point drawing commands
// color: point color
// point_width: point width 0x01-0x0F
// point_height: point height 0x01-0x0F
// x,y: upper left point
// map_columns: columns in theh point map. each column is a byte in the map and contains 8 points
// map_rows: rows in the point map
// map: point bitmap. 2D array of points, 1 bit per point
// Note: somewhat similar to U8G's drawBitmap() function, see https://github.com/olikraus/u8glib/wiki/userreference#drawbitmap
void dwinDrawPointMap(
const uint16_t color,
const uint8_t point_width, const uint8_t point_height,
const uint16_t x, const uint16_t y,
const uint16_t map_columns, const uint16_t map_rows,
const uint8_t *map_data
) {
// At how many bytes should we flush the send buffer?
// One byte is used (hidden) for F_HONE, and we need 4 bytes when appending a point.
// So we should flush the send buffer when we have less than 5 bytes left.
constexpr size_t flush_send_buffer_at = (COUNT(dwinSendBuf) - 1 - 4);
// How long is the header of each draw command?
// => 1B CMD, 2B COLOR, 1B WIDTH, 1B HEIGHT
constexpr size_t command_header_size = 5;
size_t i = 0;
for (uint16_t row = 0; row < map_rows; row++) {
for (uint16_t col = 0; col < map_columns; col++) {
const uint8_t map_byte = map_data[(row * map_columns) + col];
for (uint8_t bit = 0; bit < 8; bit++) {
// Draw a point at this position?
if (TEST(map_byte, bit)) {
// Flush the send buffer and prepare next draw if either
// a) The buffer reached the 'should flush' state, or
// b) This is the first point to draw
if (i >= flush_send_buffer_at || i == 0) {
// Dispatch the current draw command
if (i > command_header_size) dwinSend(i);
// Prepare the next draw command
i = 0;
dwinByte(i, 0x02); // cmd: draw point(s)
dwinWord(i, color);
dwinByte(i, point_width);
dwinByte(i, point_height);
}
// Append point coordinates to draw command
dwinWord(i, x + (point_width * ((8 * col) + (7 - bit)))); // x
dwinWord(i, y + (point_height * (row))); // y
}
}
}
}
// Dispatch final draw command if the buffer contains any points
if (i > command_header_size) dwinSend(i);
}
#endif // !TJC_DISPLAY
// Draw a line
// color: Line segment color

View file

@ -164,6 +164,24 @@ inline void dwinDrawBox(uint8_t mode, uint16_t color, uint16_t xStart, uint16_t
void dwinDrawPoint(uint16_t color, uint8_t width, uint8_t height, uint16_t x, uint16_t y);
#endif
// Draw a map of multiple points using minimal amount of point drawing commands
// color: point color
// point_width: point width 0x01-0x0F
// point_height: point height 0x01-0x0F
// x,y: upper left point
// map_columns: columns in theh point map. each column is a byte in the map and contains 8 points
// map_rows: rows in the point map
// map: point bitmap. 2D array of points, 1 bit per point
#if DISABLED(TJC_DISPLAY)
void dwinDrawPointMap(
const uint16_t color,
const uint8_t point_width, const uint8_t point_height,
const uint16_t x, const uint16_t y,
const uint16_t map_columns, const uint16_t map_rows,
const uint8_t *map_data
);
#endif
// Move a screen area
// mode: 0, circle shift; 1, translation
// dir: 0=left, 1=right, 2=up, 3=down

View file

@ -128,6 +128,22 @@
#define ICON_Info_0 90
#define ICON_Info_1 91
// Extra Icons
#define ICON_Printer_0 93
#define ICON_Box 200
#define ICON_Checkbox 201
#define ICON_Fade 202
#define ICON_Mesh 203
#define ICON_Tilt 204
#define ICON_Brightness 205
#define ICON_Probe 206
#define ICON_AxisD 249
#define ICON_AxisBR 250
#define ICON_AxisTR 251
#define ICON_AxisBL 252
#define ICON_AxisTL 253
#define ICON_AxisC 254
#define ICON_Folder ICON_More
#define ICON_AdvSet ICON_Language
#define ICON_HomeOffset ICON_PrintSize

View file

@ -51,8 +51,6 @@
#include "../../../sd/cardreader.h"
#include "../../../MarlinCore.h"
#include "../../../core/serial.h"
#include "../../../core/macros.h"
#include "../../../gcode/queue.h"
#include "../../../module/temperature.h"
@ -357,6 +355,10 @@ void clearPopupArea() {
dwinDrawRectangle(1, COLOR_BG_BLACK, 0, 31, DWIN_WIDTH, DWIN_HEIGHT);
}
void drawPopupBkgd60() {
dwinDrawRectangle(1, COLOR_BG_WINDOW, 14, 60, 258, 330);
}
void drawPopupBkgd105() {
dwinDrawRectangle(1, COLOR_BG_WINDOW, 14, 105, 258, 374);
}
@ -1083,10 +1085,6 @@ void drawMotionMenu() {
#endif
void drawPopupBkgd60() {
dwinDrawRectangle(1, COLOR_BG_WINDOW, 14, 60, 258, 330);
}
#if HAS_HOTEND
void popupWindowETempTooLow() {
@ -1118,7 +1116,7 @@ void popupWindowResume() {
else {
dwinDrawString(true, font8x16, COLOR_POPUP_TEXT, COLOR_BG_WINDOW, (272 - 8 * 14) / 2, 115, GET_TEXT_F(MSG_OUTAGE_RECOVERY));
dwinDrawString(true, font8x16, COLOR_POPUP_TEXT, COLOR_BG_WINDOW, (272 - 8 * 22) / 2, 192, GET_TEXT_F(MSG_OUTAGE_RECOVERY2));
dwinDrawString(true, font8x16, COLOR_POPUP_TEXT, COLOR_BG_WINDOW, (272 - 8 * 22) / 2, 212, GET_TEXT_F(MSG_OUTAGE_RECOVERY3));
dwinDrawString(true, font8x16, COLOR_POPUP_TEXT, COLOR_BG_WINDOW, (272 - 8 * 21) / 2, 212, GET_TEXT_F(MSG_OUTAGE_RECOVERY3));
dwinIconShow(ICON, ICON_Cancel_E, 26, 307);
dwinIconShow(ICON, ICON_Continue_E, 146, 307);
}
@ -1127,7 +1125,7 @@ void popupWindowResume() {
void popupWindowHome(const bool parking/*=false*/) {
clearMainWindow();
drawPopupBkgd60();
dwinIconShow(ICON, ICON_BLTouch, 101, 105);
dwinIconShow(ICON, ICON_Printer_0, 101, 105);
if (hmiIsChinese()) {
dwinFrameAreaCopy(1, 0, 371, 33, 386, 85, 240); // Wait for Move to Complete
dwinFrameAreaCopy(1, 203, 286, 271, 302, 118, 240);
@ -1150,7 +1148,7 @@ void popupWindowHome(const bool parking/*=false*/) {
dwinFrameAreaCopy(1, 0, 389, 150, 402, 61, 280);
}
else {
dwinDrawString(true, font8x16, COLOR_POPUP_TEXT, COLOR_BG_WINDOW, (272 - 8 * 13) / 2, 230, GET_TEXT_F(MSG_BED_LEVELING));
dwinDrawString(true, font8x16, COLOR_POPUP_TEXT, COLOR_BG_WINDOW, (272 - 8 * 12) / 2, 230, GET_TEXT_F(MSG_BED_LEVELING));
dwinDrawString(true, font8x16, COLOR_POPUP_TEXT, COLOR_BG_WINDOW, (272 - 8 * 23) / 2, 260, F("Please wait until done."));
}
}
@ -1171,8 +1169,8 @@ void popupwindowPauseOrStop() {
clearMainWindow();
drawPopupBkgd60();
if (hmiIsChinese()) {
if (select_print.now == PRINT_PAUSE_RESUME) dwinFrameAreaCopy(1, 237, 338, 269, 356, 98, 150); // Pause
else if (select_print.now == PRINT_STOP) dwinFrameAreaCopy(1, 221, 320, 253, 336, 98, 150); // Stop
if (select_print.now == PRINT_PAUSE_RESUME) dwinFrameAreaCopy(1, 237, 338, 269, 356, 98, 150); // Pause
else if (select_print.now == PRINT_STOP) dwinFrameAreaCopy(1, 221, 320, 253, 336, 98, 150); // Stop
dwinFrameAreaCopy(1, 220, 304, 264, 319, 130, 150); // Print
dwinIconShow(ICON, ICON_Confirm_C, 26, 280);
dwinIconShow(ICON, ICON_Cancel_C, 146, 280);
@ -1828,6 +1826,14 @@ void MarlinUI::update() {
void MarlinUI::_set_brightness() { dwinLCDBrightness(backlight ? brightness : 0); }
#endif
void MarlinUI::kill_screen(FSTR_P const lcd_error, FSTR_P const) {
clearMainWindow();
drawPopupBkgd60();
dwinIconShow(ICON, ICON_Printer_0, 101, 105);
dwinDrawString(true, font8x16, COLOR_POPUP_TEXT, COLOR_BG_WINDOW, (272 - 8 * 15) / 2, 230, GET_TEXT_F(MSG_PRINTER_KILLED));
dwinDrawString(true, font8x16, COLOR_POPUP_TEXT, COLOR_BG_WINDOW, (272 - 8 * 20) / 2, 260, GET_TEXT_F(MSG_TURN_OFF));
}
#if ENABLED(SCROLL_LONG_FILENAMES)
char shift_name[LONG_FILENAME_LENGTH + 1];

View file

@ -1,7 +0,0 @@
# DWIN for Creality Ender-3 v2
Marlin's Ender-3 v2 support requires the `DWIN_SET` included with the Ender-3 V2 [example configuration](https://github.com/MarlinFirmware/Configurations/tree/bugfix-2.1.x/config/examples/Creality/Ender-3%20V2).
## Easy Install
Copy the `DWIN_SET` folder onto a Micro-SD card and insert the card into the slot on the DWIN screen. Cycle the machine and wait for the screen to go from blue to orange. Turn the machine off and remove the SD card. When you turn on the machine the screen will display a "Creality" loading screen.

View file

@ -46,7 +46,7 @@
#include "../../../feature/pause.h"
#endif
#if ENABLED(FILAMENT_RUNOUT_SENSOR)
#if HAS_FILAMENT_SENSOR
#include "../../../feature/runout.h"
#endif
@ -2857,7 +2857,7 @@ void JyersDWIN::menuItemHandler(const uint8_t menu, const uint8_t item, bool dra
#define ADVANCED_LOAD (ADVANCED_LA + ENABLED(ADVANCED_PAUSE_FEATURE))
#define ADVANCED_UNLOAD (ADVANCED_LOAD + ENABLED(ADVANCED_PAUSE_FEATURE))
#define ADVANCED_COLD_EXTRUDE (ADVANCED_UNLOAD + ENABLED(PREVENT_COLD_EXTRUSION))
#define ADVANCED_FILSENSORENABLED (ADVANCED_COLD_EXTRUDE + ENABLED(FILAMENT_RUNOUT_SENSOR))
#define ADVANCED_FILSENSORENABLED (ADVANCED_COLD_EXTRUDE + ENABLED(HAS_FILAMENT_SENSOR))
#define ADVANCED_FILSENSORDISTANCE (ADVANCED_FILSENSORENABLED + ENABLED(HAS_FILAMENT_RUNOUT_DISTANCE))
#define ADVANCED_POWER_LOSS (ADVANCED_FILSENSORDISTANCE + ENABLED(POWER_LOSS_RECOVERY))
#define ADVANCED_TOTAL ADVANCED_POWER_LOSS
@ -2953,7 +2953,7 @@ void JyersDWIN::menuItemHandler(const uint8_t menu, const uint8_t item, bool dra
break;
#endif
#if ENABLED(FILAMENT_RUNOUT_SENSOR)
#if HAS_FILAMENT_SENSOR
case ADVANCED_FILSENSORENABLED:
if (draw) {
drawMenuItem(row, ICON_Extruder, GET_TEXT_F(MSG_RUNOUT_SENSOR));
@ -2975,7 +2975,7 @@ void JyersDWIN::menuItemHandler(const uint8_t menu, const uint8_t item, bool dra
modifyValue(runout.runout_distance(), 0, 999, 10);
break;
#endif
#endif // FILAMENT_RUNOUT_SENSOR
#endif // HAS_FILAMENT_SENSOR
#if ENABLED(POWER_LOSS_RECOVERY)
case ADVANCED_POWER_LOSS:
@ -3830,7 +3830,7 @@ void JyersDWIN::menuItemHandler(const uint8_t menu, const uint8_t item, bool dra
#define TUNE_LA (TUNE_ZDOWN + ENABLED(LIN_ADVANCE))
#define TUNE_CHANGEFIL (TUNE_LA + ENABLED(FILAMENT_LOAD_UNLOAD_GCODES))
#define TUNE_FWRETRACT (TUNE_CHANGEFIL + ENABLED(FWRETRACT))
#define TUNE_FILSENSORENABLED (TUNE_FWRETRACT + ENABLED(FILAMENT_RUNOUT_SENSOR))
#define TUNE_FILSENSORENABLED (TUNE_FWRETRACT + ENABLED(HAS_FILAMENT_SENSOR))
#define TUNE_BACKLIGHT_OFF (TUNE_FILSENSORENABLED + 1)
#define TUNE_BACKLIGHT (TUNE_BACKLIGHT_OFF + 1)
#define TUNE_TOTAL TUNE_BACKLIGHT
@ -3950,7 +3950,7 @@ void JyersDWIN::menuItemHandler(const uint8_t menu, const uint8_t item, bool dra
break;
#endif
#if ENABLED(FILAMENT_RUNOUT_SENSOR)
#if HAS_FILAMENT_SENSOR
case TUNE_FILSENSORENABLED:
if (draw) {
drawMenuItem(row, ICON_Extruder, GET_TEXT_F(MSG_RUNOUT_SENSOR));
@ -4326,7 +4326,7 @@ void JyersDWIN::popupHandler(const PopupID popupid, const bool option/*=false*/)
case Popup_FilLoad: drawPopup(option ? F("Unloading Filament") : F("Loading Filament"), PWID, F(""), Proc_Wait, ICON_BLTouch); break;
case Popup_FilChange: drawPopup(F("Filament Change"), F("Please wait for prompt."), F(""), Proc_Wait, ICON_BLTouch); break;
case Popup_TempWarn: drawPopup(option ? F("Nozzle temp too low!") : F("Nozzle temp too high!"), F(""), F(""), Proc_Wait, option ? ICON_TempTooLow : ICON_TempTooHigh); break;
#if ENABLED(FILAMENT_RUNOUT_SENSOR)
#if HAS_FILAMENT_SENSOR
case Popup_Runout: drawPopup(F("Filament Runout"), F(""), F(""), Proc_Wait, ICON_BLTouch); break;
#endif
#if ANY(PIDTEMP, PIDTEMPBED)
@ -4953,7 +4953,7 @@ void JyersDWIN::stateUpdate() {
}
}
#endif
#if ENABLED(FILAMENT_RUNOUT_SENSOR)
#if HAS_FILAMENT_SENSOR
static bool ranout = false;
if (runout.filament_ran_out != ranout) {
ranout = runout.filament_ran_out;

View file

@ -0,0 +1,254 @@
/**
* Marlin 3D Printer Firmware
* Copyright (c) 2025 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 <https://www.gnu.org/licenses/>.
*
*/
#include "../../../inc/MarlinConfigPre.h"
#if IS_DWIN_MARLINUI && HAS_GAMES
// Enable performance counters (draw call count, frame timing) for debugging
//#define GAME_PERFORMANCE_COUNTERS
#include "../../menu/game/types.h" // includes e3v2/marlinui/game.h
#include "../../lcdprint.h"
#include "lcdprint_dwin.h"
#include "marlinui_dwin.h"
#if ENABLED(GAME_PERFORMANCE_COUNTERS)
typedef struct {
/**
* Number of draw calls sent to the LCD
*/
uint32_t draw_calls;
/**
* millis() value at the start of the current frame
*/
millis_t frame_draw_millis;
/**
* millis() value at the end of the previous frame (in frame_start)
* or time spend waiting for the next frame (in frame_end)
*/
millis_t frame_wait_millis;
} dwin_game_perf_t;
static dwin_game_perf_t dwin_game_perf;
#define COUNT_DRAW_CALLS(n) dwin_game_perf.draw_calls += n
#else // !GAME_PERFORMANCE_COUNTERS
#define COUNT_DRAW_CALLS(...) NOOP
#endif // !GAME_PERFORMANCE_COUNTERS
void MarlinGame::frame_start() {
// Clear the screen before each frame
//dwinFrameClear(CLEAR_COLOR);
// Instead of using dwinFrameClear, fill the play area with the background color
// This tends to be faster than clearing the whole screen
const uint16_t fg = dwin_font.fg;
dwin_font.fg = COLOR_BG_BLACK;
draw_box(0, 0, GAME_WIDTH, GAME_HEIGHT);
dwin_font.fg = fg;
// Ensure the correct font is selected
dwin_font.index = DWIN_FONT_MENU;
#if ENABLED(GAME_PERFORMANCE_COUNTERS)
// Reset draw call counters
dwin_game_perf.draw_calls = 0;
// Update timing information
const millis_t now = millis();
dwin_game_perf.frame_draw_millis = now;
dwin_game_perf.frame_wait_millis = now - dwin_game_perf.frame_wait_millis;
#endif
}
void MarlinGame::frame_end() {
#if ENABLED(GAME_PERFORMANCE_COUNTERS)
const millis_t now = millis();
const millis_t frame_wait_millis = dwin_game_perf.frame_wait_millis;
const millis_t frame_draw_millis = now - dwin_game_perf.frame_draw_millis;
dwin_game_perf.frame_wait_millis = now;
// Save previous font settings and set new ones
const uint16_t fg = dwin_font.fg;
const bool solid = dwin_font.solid;
set_color(color::YELLOW);
dwin_font.solid = true;
// Draw performance counters information
char perf_str[32];
sprintf_P(
perf_str,
PSTR("d%04lu w%04lu c%04lu"),
frame_draw_millis,
frame_wait_millis,
dwin_game_perf.draw_calls
);
lcd_moveto_xy(0, 0);
lcd_put_u8str(perf_str);
// Restore previous font settings
dwin_font.fg = fg;
dwin_font.solid = solid;
#endif // GAME_PERFORMANCE_COUNTERS
}
void MarlinGame::set_color(const color color) {
switch (color) {
default:
case color::WHITE: dwin_font.fg = COLOR_WHITE; break;
case color::BLACK: dwin_font.fg = COLOR_BG_BLACK; break;
// https://rgbcolorpicker.com/565/table
case color::RED: dwin_font.fg = RGB(0x1F, 0x00, 0x00); break;
case color::GREEN: dwin_font.fg = RGB(0x00, 0x3F, 0x00); break;
case color::BLUE: dwin_font.fg = RGB(0x00, 0x00, 0x1F); break;
case color::YELLOW: dwin_font.fg = RGB(0x1F, 0x3F, 0x00); break;
case color::CYAN: dwin_font.fg = RGB(0x00, 0x3F, 0x1F); break;
case color::MAGENTA:dwin_font.fg = RGB(0x1F, 0x00, 0x1F); break;
}
}
void MarlinGame::draw_hline(const game_dim_t x, const game_dim_t y, const game_dim_t w) {
// Draw lines as boxes, since DWIN lines are always 1px wide but we want to scale them
draw_box(x, y, w, 1);
COUNT_DRAW_CALLS(1);
}
void MarlinGame::draw_vline(const game_dim_t x, const game_dim_t y, const game_dim_t h) {
// Draw lines as boxes, since DWIN lines are always 1px wide but we want to scale them
draw_box(x, y, 1, h);
COUNT_DRAW_CALLS(1);
}
void MarlinGame::draw_frame(const game_dim_t x, const game_dim_t y, const game_dim_t w, const game_dim_t h) {
dwinDrawBox(
0, // mode = frame
dwin_font.fg, // color
dwin_game::game_to_screen(x) + dwin_game::x_offset,
dwin_game::game_to_screen(y) + dwin_game::y_offset,
dwin_game::game_to_screen(w),
dwin_game::game_to_screen(h)
);
COUNT_DRAW_CALLS(1);
}
void MarlinGame::draw_box(const game_dim_t x, const game_dim_t y, const game_dim_t w, const game_dim_t h) {
dwinDrawBox(
1, // mode = fill
dwin_font.fg, // color
dwin_game::game_to_screen(x) + dwin_game::x_offset,
dwin_game::game_to_screen(y) + dwin_game::y_offset,
dwin_game::game_to_screen(w),
dwin_game::game_to_screen(h)
);
COUNT_DRAW_CALLS(1);
}
void MarlinGame::draw_pixel(const game_dim_t x, const game_dim_t y) {
// Draw pixels using boxes.
// While DWIN protocol supports drawing points with different sizes, the
// 0x02 'draw point' command is slower per pixel than 0x05 'fill rectangle'
// (0.4 us vs 0.14 us per pixel)
draw_box(x, y, 1, 1);
}
void MarlinGame::draw_bitmap(const game_dim_t x, const game_dim_t y, const game_dim_t bytes_per_row, const game_dim_t rows, const pgm_bitmap_t bitmap) {
// DWIN theorethically supports bitmaps since kernel 2.1, but most screens don't support it
// (either because they use an older kernel version, or because they just (badly) emulate the DWIN protocol).
// So instead, we have to fall back to drawing points manually.
#if DISABLED(TJC_DISPLAY)
// DWIN T5UI actually supports drawing multiple points in one go using the 0x02 'draw point' command, ever since kernel 1.2.
// So we use that to draw the bitmap as a series of points, which is faster than drawing rectangles using draw_pixel.
dwinDrawPointMap(
dwin_font.fg,
dwin_game::game_to_screen(1),
dwin_game::game_to_screen(1),
dwin_game::game_to_screen(x) + dwin_game::x_offset,
dwin_game::game_to_screen(y) + dwin_game::y_offset,
bytes_per_row,
rows,
bitmap
);
COUNT_DRAW_CALLS(1);
#else // TJC_DISPLAY
// TJC displays don't seem to support the 0x02 'draw point' command, so instead we have to draw the bitmap
// as a series of rectangles using draw_pixel.
// This will absolutely suck for performance, but it's the best we can do on these screens.
for (game_dim_t row = 0; row < rows; row++) {
for (game_dim_t col = 0; col < bytes_per_row; col++) {
const uint8_t byte = bitmap[(row * bytes_per_row) + col];
for (uint8_t bit = 0; bit < 8; bit++) {
// Assuming that the drawing area was cleared before drawing
if (byte & (1 << bit)) {
draw_pixel(x + (col * 8) + (7 - bit + 1), y + row);
COUNT_DRAW_CALLS(1);
}
}
}
}
#endif // TJC_DISPLAY
}
int MarlinGame::draw_string(const game_dim_t x, const game_dim_t y, const char* str) {
COUNT_DRAW_CALLS(1);
lcd_moveto_xy(
dwin_game::game_to_screen(x) + dwin_game::x_offset,
dwin_game::game_to_screen(y) + dwin_game::y_offset
);
return lcd_put_u8str_max_P(str, PIXEL_LEN_NOLIMIT);
}
int MarlinGame::draw_string(const game_dim_t x, const game_dim_t y, FSTR_P const str) {
return draw_string(x, y, FTOP(str));
}
void MarlinGame::draw_int(const game_dim_t x, const game_dim_t y, const int value) {
COUNT_DRAW_CALLS(1);
lcd_moveto_xy(
dwin_game::game_to_screen(x) + dwin_game::x_offset,
dwin_game::game_to_screen(y) + dwin_game::y_offset
);
lcd_put_int(value);
}
#endif // IS_DWIN_MARLINUI && HAS_GAMES

View file

@ -0,0 +1,85 @@
/**
* Marlin 3D Printer Firmware
* Copyright (c) 2025 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 <https://www.gnu.org/licenses/>.
*
*/
#pragma once
#include "../marlinui/marlinui_dwin.h"
typedef uint8_t game_dim_t;
typedef uint16_t screen_dim_t;
typedef const uint8_t* pgm_bitmap_t;
namespace dwin_game {
/**
* @brief Target the renderer at 128x64 pixels to match U8G screens
*/
constexpr screen_dim_t TARGET_WIDTH = 128;
constexpr screen_dim_t TARGET_HEIGHT = 64;
constexpr int calculate_scale() {
// Use whichever is smaller: the width or height scaling factor
float scaling_factor = _MIN(
static_cast<float>(DWIN_WIDTH) / static_cast<float>(TARGET_WIDTH),
static_cast<float>(DWIN_HEIGHT) / static_cast<float>(TARGET_HEIGHT)
);
// Round DOWN to closest integer
return static_cast<int>(scaling_factor);
}
/**
* @brief Game render scale.
*/
constexpr int scale = calculate_scale();
/**
* @brief Scale a game dimension to screen dimensions
*/
constexpr game_dim_t screen_to_game(const screen_dim_t x) {
return x / scale;
}
/**
* @brief Scale a screen dimension to game dimensions
*/
constexpr screen_dim_t game_to_screen(const game_dim_t x) {
return x * scale;
}
/**
* @brief Offset of the game window on the screen. Applied after scaling.
*/
constexpr screen_dim_t x_offset = (DWIN_WIDTH - game_to_screen(TARGET_WIDTH)) / 2;
constexpr screen_dim_t y_offset = (DWIN_HEIGHT - game_to_screen(TARGET_HEIGHT)) / 2;
static_assert(game_to_screen(TARGET_WIDTH) + (x_offset * 2) <= DWIN_WIDTH, "DWIN game renderer failed to auto-scale, is too wide");
static_assert(game_to_screen(TARGET_HEIGHT) + (y_offset * 2) <= DWIN_HEIGHT, "DWIN game renderer failed to auto-scale, is too high");
} // namespace dwin_game
constexpr game_dim_t GAME_WIDTH = dwin_game::screen_to_game(DWIN_WIDTH - (dwin_game::x_offset * 2));
constexpr game_dim_t GAME_HEIGHT = dwin_game::screen_to_game(DWIN_HEIGHT - (dwin_game::y_offset * 2));
constexpr game_dim_t GAME_FONT_WIDTH = dwin_game::screen_to_game(MENU_FONT_WIDTH);
constexpr game_dim_t GAME_FONT_ASCENT = dwin_game::screen_to_game(MENU_FONT_ASCENT);
// DWIN screens don't page, so these macros are always true
#define PAGE_OVER(ya) true
#define PAGE_UNDER(yb) true
#define PAGE_CONTAINS(ya, yb) true

View file

@ -52,7 +52,9 @@ void lcd_moveto(const lcd_uint_t col, const lcd_uint_t row) {
inline void lcd_advance_cursor(const uint8_t len=1) { cursor.x += len * dwin_font.width; }
void lcd_put_int(const int i) {
// TODO: Draw an int at the cursor position, advance the cursor
char buf[12]; // 10 digits + sign + null
itoa(i, buf, 10);
lcd_put_u8str_max(buf, PIXEL_LEN_NOLIMIT);
}
int lcd_put_dwin_string() {

View file

@ -40,8 +40,6 @@
#include "../../marlinui.h"
#include "../../extui/ui_api.h"
#include "../../../MarlinCore.h"
#include "../../../core/serial.h"
#include "../../../core/macros.h"
#include "../../../module/temperature.h"
#include "../../../module/printcounter.h"
#include "../../../module/motion.h"
@ -2217,6 +2215,13 @@ void setMoveX() { hmiValue.axis = X_AXIS; setPFloatOnClick(X_MIN_POS, X_MAX_POS,
void setMoveY() { hmiValue.axis = Y_AXIS; setPFloatOnClick(Y_MIN_POS, Y_MAX_POS, UNITFDIGITS, applyMove, liveMove); }
void setMoveZ() { hmiValue.axis = Z_AXIS; setPFloatOnClick(Z_MIN_POS, Z_MAX_POS, UNITFDIGITS, applyMove, liveMove); }
#if ENABLED(Z_STEPPER_AUTO_ALIGN)
void autoZAlign() {
LCD_MESSAGE(MSG_AUTO_Z_ALIGN);
queue.inject(F("G34"));
}
#endif
#if HAS_HOTEND
void setMoveE() {
const float e_min = current_position.e - (EXTRUDE_MAXLENGTH),
@ -4121,6 +4126,9 @@ void drawMaxAccelMenu() {
#if HAS_Z_AXIS
MENU_ITEM(ICON_HomeZ, MSG_AUTO_HOME_Z, onDrawMenuItem, homeZ);
#endif
#if ENABLED(Z_STEPPER_AUTO_ALIGN)
MENU_ITEM(ICON_HomeZ, MSG_AUTO_Z_ALIGN, onDrawMenuItem, autoZAlign);
#endif
#if ENABLED(MESH_BED_LEVELING)
EDIT_ITEM(ICON_ZAfterHome, MSG_Z_AFTER_HOME, onDrawPInt8Menu, setZAfterHoming, &hmiData.zAfterHoming);
#endif

View file

@ -36,22 +36,6 @@
#include "../common/dwin_color.h"
#include "dwin_lcd.h"
// Extra Icons
#define ICON_Printer_0 93
#define ICON_Box 200
#define ICON_Checkbox 201
#define ICON_Fade 202
#define ICON_Mesh 203
#define ICON_Tilt 204
#define ICON_Brightness 205
#define ICON_Probe 206
#define ICON_AxisD 249
#define ICON_AxisBR 250
#define ICON_AxisTR 251
#define ICON_AxisBL 252
#define ICON_AxisTL 253
#define ICON_AxisC 254
#define ICON_BedSizeX ICON_PrintSize
#define ICON_BedSizeY ICON_PrintSize
#define ICON_BedTramming ICON_SetHome

View file

@ -89,7 +89,7 @@ void AnycubicTFT::onSetup() {
delay_ms(10);
// Init the state of the key pins running on the TFT
#if ENABLED(FILAMENT_RUNOUT_SENSOR)
#if HAS_FILAMENT_SENSOR
SET_INPUT_PULLUP(FIL_RUNOUT1_PIN);
#endif
@ -894,7 +894,7 @@ void AnycubicTFT::doSDCardStateCheck() {
}
void AnycubicTFT::doFilamentRunoutCheck() {
#if ENABLED(FILAMENT_RUNOUT_SENSOR)
#if HAS_FILAMENT_SENSOR
// NOTE: getFilamentRunoutState() only returns the runout state if the job is printing
// we want to actually check the status of the pin here, regardless of printstate
if (READ(FIL_RUNOUT1_PIN) == FIL_RUNOUT1_STATE) {
@ -909,7 +909,7 @@ void AnycubicTFT::doFilamentRunoutCheck() {
SENDLINE_DBG_PGM("J15", "TFT Serial Debug: Non blocking filament runout... J15");
}
}
#endif // FILAMENT_RUNOUT_SENSOR
#endif // HAS_FILAMENT_SENSOR
}
void AnycubicTFT::startPrint() {
@ -939,7 +939,7 @@ void AnycubicTFT::pausePrint() {
void AnycubicTFT::resumePrint() {
#if HAS_MEDIA
#if ENABLED(FILAMENT_RUNOUT_SENSOR)
#if HAS_FILAMENT_SENSOR
if (READ(FIL_RUNOUT1_PIN) == FIL_RUNOUT1_STATE) {
DEBUG_ECHOLNPGM("TFT Serial Debug: Resume Print with filament sensor still tripped... ");

View file

@ -45,6 +45,10 @@
#include "../../../feature/powerloss.h"
#endif
#if HAS_FILAMENT_SENSOR
#include "../../../feature/runout.h"
#endif
#define DEBUG_OUT ACDEBUGLEVEL
#include "../../../core/debug_out.h"
@ -438,7 +442,7 @@ namespace Anycubic {
}
}
#if ENABLED(FILAMENT_RUNOUT_SENSOR)
#if HAS_FILAMENT_SENSOR
void DgusTFT::filamentRunout() {
#if ACDEBUG(AC_MARLIN)
@ -453,7 +457,7 @@ namespace Anycubic {
pop_up_index = 15; // show filament lack.
if (READ(FIL_RUNOUT_PIN) == FIL_RUNOUT_STATE) {
if (FILAMENT_IS_OUT()) {
playTune(FilamentOut);
feedrate_back = getFeedrate_percent();
@ -466,7 +470,7 @@ namespace Anycubic {
}
}
#endif // FILAMENT_RUNOUT_SENSOR
#endif // HAS_FILAMENT_SENSOR
void DgusTFT::confirmationRequest(const char * const msg) {
// M108 continue
@ -598,7 +602,7 @@ namespace Anycubic {
printer_state = AC_printer_stopping_from_media_remove;
}
else {
#if ENABLED(FILAMENT_RUNOUT_SENSOR)
#if HAS_FILAMENT_SENSOR
#if ACDEBUG(AC_MARLIN)
DEBUG_ECHOLNPGM("setFilamentRunoutState: ", __LINE__);
#endif

View file

@ -406,11 +406,18 @@ const struct DGUS_VP_Variable ListOfVP[] PROGMEM = {
// Fan Data
#if HAS_FAN
#if HOTENDS <= 4
#define FAN_CONTROL HOTENDS
#elif FAN_COUNT <= 4
#define FAN_CONTROL FAN_COUNT
#else
#define FAN_CONTROL 4
#endif
#define FAN_VPHELPER(N) \
VPHELPER(VP_Fan##N##_Percentage, &thermalManager.fan_speed[N], screen.percentageToUint8, screen.sendPercentageToDisplay), \
VPHELPER(VP_FAN##N##_CONTROL, &thermalManager.fan_speed[N], screen.handleFanControl, nullptr), \
VPHELPER(VP_FAN##N##_STATUS, &thermalManager.fan_speed[N], nullptr, screen.sendFanStatusToDisplay),
REPEAT(FAN_COUNT, FAN_VPHELPER)
REPEAT(FAN_CONTROL, FAN_VPHELPER)
#endif
// Feedrate

View file

@ -399,11 +399,18 @@ const struct DGUS_VP_Variable ListOfVP[] PROGMEM = {
// Fan Data
#if HAS_FAN
#if HOTENDS <= 2
#define FAN_CONTROL HOTENDS
#elif FAN_COUNT <= 2
#define FAN_CONTROL FAN_COUNT
#else
#define FAN_CONTROL 2
#endif
#define FAN_VPHELPER(N) \
VPHELPER(VP_Fan##N##_Percentage, &thermalManager.fan_speed[N], screen.percentageToUint8, screen.sendPercentageToDisplay), \
VPHELPER(VP_FAN##N##_CONTROL, &thermalManager.fan_speed[N], screen.handleFanControl, nullptr), \
VPHELPER(VP_FAN##N##_STATUS, &thermalManager.fan_speed[N], nullptr, screen.sendFanStatusToDisplay),
REPEAT(FAN_COUNT, FAN_VPHELPER)
REPEAT(FAN_CONTROL, FAN_VPHELPER)
#endif
// Feedrate

View file

@ -602,11 +602,18 @@ const struct DGUS_VP_Variable ListOfVP[] PROGMEM = {
// Fan Data
#if HAS_FAN
#define FAN_VPHELPER(N) \
VPHELPER(VP_Fan##N##_Percentage, &thermalManager.fan_speed[N], screen.setUint8, screen.sendFanToDisplay), \
VPHELPER(VP_FAN##N##_CONTROL, &thermalManager.fan_speed[N], screen.handleFanControl, nullptr), \
#if HOTENDS <= 4
#define FAN_CONTROL HOTENDS
#elif FAN_COUNT <= 4
#define FAN_CONTROL FAN_COUNT
#else
#define FAN_CONTROL 4
#endif
#define FAN_VPHELPER(N) \
VPHELPER(VP_Fan##N##_Percentage, &thermalManager.fan_speed[N], screen.percentageToUint8, screen.sendFanToDisplay), \
VPHELPER(VP_FAN##N##_CONTROL, &thermalManager.fan_speed[N], screen.handleFanControl, nullptr), \
VPHELPER(VP_FAN##N##_STATUS, &thermalManager.fan_speed[N], nullptr, screen.sendFanStatusToDisplay),
REPEAT(FAN_COUNT, FAN_VPHELPER)
REPEAT(FAN_CONTROL, FAN_VPHELPER)
#endif
// Feedrate

View file

@ -78,7 +78,7 @@ public:
static void handleFeedRateMinChange(DGUS_VP_Variable &var, void *val_ptr);
static void handleMin_T_F(DGUS_VP_Variable &var, void *val_ptr);
#if HAS_PID_HEATING
#if ENABLED(DGUS_FILAMENT_LOADUNLOAD)
static void filamentLoadUnload(DGUS_VP_Variable &var, void *val_ptr, const int filamentDir);
static void filamentLoad(DGUS_VP_Variable &var, void *val_ptr);
static void filamentUnload(DGUS_VP_Variable &var, void *val_ptr);

View file

@ -207,11 +207,18 @@ const struct DGUS_VP_Variable ListOfVP[] PROGMEM = {
// Fan Data
#if HAS_FAN
#if HOTENDS <= 2
#define FAN_CONTROL HOTENDS
#elif FAN_COUNT <= 2
#define FAN_CONTROL FAN_COUNT
#else
#define FAN_CONTROL 2
#endif
#define FAN_VPHELPER(N) \
VPHELPER(VP_Fan##N##_Percentage, &thermalManager.fan_speed[N], screen.percentageToUint8, screen.sendPercentageToDisplay), \
VPHELPER(VP_FAN##N##_CONTROL, &thermalManager.fan_speed[N], screen.handleFanControl, nullptr), \
VPHELPER(VP_FAN##N##_STATUS, &thermalManager.fan_speed[N], nullptr, screen.sendFanStatusToDisplay),
REPEAT(FAN_COUNT, FAN_VPHELPER)
REPEAT(FAN_CONTROL, FAN_VPHELPER)
#endif
// Feedrate

View file

@ -16,10 +16,7 @@
# location: <https://www.gnu.org/licenses/>.
from __future__ import print_function
import argparse
import textwrap
import os
import zlib
import argparse, textwrap, os, zlib
def deflate(data):
return zlib.compress(data)

View file

@ -17,8 +17,7 @@
from __future__ import print_function
from PIL import Image
import argparse
import textwrap
import argparse, textwrap
def pack_rle(data):
"""Use run-length encoding to pack the bytes"""

View file

@ -17,11 +17,7 @@
from __future__ import print_function
from PIL import Image
import argparse
import textwrap
import os
import sys
import zlib
import argparse, textwrap, os, sys, zlib
class WriteSource:
def __init__(self, mode):

View file

@ -16,7 +16,7 @@
# location: <https://www.gnu.org/licenses/>.
from __future__ import print_function
import argparse,re,sys
import argparse, re, sys
from html.parser import HTMLParser

View file

@ -102,7 +102,7 @@ void AdvancedSettingsMenu::onRedraw(draw_mode_t what) {
#endif
.enabled(ENABLED(HAS_MULTI_HOTEND))
.tag(4) .button(OFFSETS_POS, GET_TEXT_F(MSG_OFFSETS_MENU))
.enabled(ANY(LIN_ADVANCE, FILAMENT_RUNOUT_SENSOR))
.enabled(ANY(LIN_ADVANCE, HAS_FILAMENT_SENSOR))
.tag(11).button(FILAMENT_POS, GET_TEXT_F(MSG_FILAMENT))
.tag(12).button(ENDSTOPS_POS, GET_TEXT_F(MSG_LCD_ENDSTOPS))
.tag(15).button(DISPLAY_POS, GET_TEXT_F(MSG_DISPLAY_MENU))
@ -122,29 +122,29 @@ bool AdvancedSettingsMenu::onTouchEnd(uint8_t tag) {
switch (tag) {
case 1: SaveSettingsDialogBox::promptToSaveSettings(); break;
#if HAS_BED_PROBE
case 2: GOTO_SCREEN(ZOffsetScreen); break;
case 2: GOTO_SCREEN(ZOffsetScreen); break;
#endif
case 3: GOTO_SCREEN(StepsScreen); break;
#if HAS_MULTI_HOTEND
case 4: GOTO_SCREEN(NozzleOffsetScreen); break;
case 4: GOTO_SCREEN(NozzleOffsetScreen); break;
#endif
case 5: GOTO_SCREEN(MaxVelocityScreen); break;
case 6: GOTO_SCREEN(DefaultAccelerationScreen); break;
case 7: GOTO_SCREEN(TERN(HAS_JUNCTION_DEVIATION, JunctionDeviationScreen, JerkScreen)); break;
#if ENABLED(BACKLASH_GCODE)
case 8: GOTO_SCREEN(BacklashCompensationScreen); break;
case 8: GOTO_SCREEN(BacklashCompensationScreen); break;
#endif
case 9: GOTO_SCREEN(InterfaceSettingsScreen); LockScreen::check_passcode(); break;
case 10: GOTO_SCREEN(RestoreFailsafeDialogBox); LockScreen::check_passcode(); break;
#if ANY(LIN_ADVANCE, FILAMENT_RUNOUT_SENSOR)
case 11: GOTO_SCREEN(FilamentMenu); break;
#if ANY(LIN_ADVANCE, HAS_FILAMENT_SENSOR)
case 11: GOTO_SCREEN(FilamentMenu); break;
#endif
case 12: GOTO_SCREEN(EndstopStatesScreen); break;
#if HAS_TRINAMIC_CONFIG
case 13: GOTO_SCREEN(StepperCurrentScreen); break;
case 13: GOTO_SCREEN(StepperCurrentScreen); break;
#endif
#if ENABLED(SENSORLESS_HOMING)
case 14: GOTO_SCREEN(StepperBumpSensitivityScreen); break;
case 14: GOTO_SCREEN(StepperBumpSensitivityScreen); break;
#endif
case 15: GOTO_SCREEN(DisplayTuningScreen); break;
case 16: GOTO_SCREEN(FlowPercentScreen); break;

View file

@ -84,12 +84,12 @@ void EndstopStatesScreen::onRedraw(draw_mode_t) {
#else
PIN_DISABLED(5, 3, PSTR(STR_Z_MIN), Z_MIN)
#endif
#if ENABLED(FILAMENT_RUNOUT_SENSOR) && PIN_EXISTS(FIL_RUNOUT)
#if HAS_FILAMENT_SENSOR && PIN_EXISTS(FIL_RUNOUT)
PIN_ENABLED (1, 4, GET_TEXT_F(MSG_RUNOUT_1), FIL_RUNOUT, FIL_RUNOUT1_STATE)
#else
PIN_DISABLED(1, 4, GET_TEXT_F(MSG_RUNOUT_1), FIL_RUNOUT)
#endif
#if ALL(HAS_MULTI_EXTRUDER, FILAMENT_RUNOUT_SENSOR) && PIN_EXISTS(FIL_RUNOUT2)
#if ALL(HAS_MULTI_EXTRUDER, HAS_FILAMENT_SENSOR) && PIN_EXISTS(FIL_RUNOUT2)
PIN_ENABLED (3, 4, GET_TEXT_F(MSG_RUNOUT_2), FIL_RUNOUT2, FIL_RUNOUT2_STATE)
#else
PIN_DISABLED(3, 4, GET_TEXT_F(MSG_RUNOUT_2), FIL_RUNOUT2)

View file

@ -58,7 +58,7 @@ void FilamentMenu::onRedraw(draw_mode_t what) {
cmd.font(font_large)
.text(TITLE_POS, GET_TEXT_F(MSG_FILAMENT))
.font(font_medium).colors(normal_btn)
.enabled(ENABLED(FILAMENT_RUNOUT_SENSOR))
.enabled(ENABLED(HAS_FILAMENT_SENSOR))
.tag(2).button(RUNOUT_SENSOR_POS, GET_TEXT_F(MSG_RUNOUT_SENSOR))
.enabled(ENABLED(LIN_ADVANCE))
.tag(3).button(LIN_ADVANCE_POS, GET_TEXT_F(MSG_LINEAR_ADVANCE))
@ -69,12 +69,12 @@ void FilamentMenu::onRedraw(draw_mode_t what) {
bool FilamentMenu::onTouchEnd(uint8_t tag) {
switch (tag) {
case 1: GOTO_PREVIOUS(); break;
#if ENABLED(FILAMENT_RUNOUT_SENSOR)
case 2: GOTO_SCREEN(FilamentRunoutScreen); break;
case 1: GOTO_PREVIOUS(); break;
#if HAS_FILAMENT_SENSOR
case 2: GOTO_SCREEN(FilamentRunoutScreen); break;
#endif
#if ENABLED(LIN_ADVANCE)
case 3: GOTO_SCREEN(LinearAdvanceScreen); break;
case 3: GOTO_SCREEN(LinearAdvanceScreen); break;
#endif
default: return false;
}

View file

@ -75,13 +75,13 @@ enum {
#if ENABLED(CASE_LIGHT_ENABLE)
CASE_LIGHT_SCREEN_CACHE,
#endif
#if ANY(LIN_ADVANCE, FILAMENT_RUNOUT_SENSOR)
#if ANY(LIN_ADVANCE, HAS_FILAMENT_SENSOR)
FILAMENT_MENU_CACHE,
#endif
#if ENABLED(LIN_ADVANCE)
LINEAR_ADVANCE_SCREEN_CACHE,
#endif
#if ENABLED(FILAMENT_RUNOUT_SENSOR)
#if HAS_FILAMENT_SENSOR
FILAMENT_RUNOUT_SCREEN_CACHE,
#endif
#if HAS_MEDIA
@ -197,11 +197,11 @@ enum {
#include "case_light_screen.h"
#endif
#if ANY(LIN_ADVANCE, FILAMENT_RUNOUT_SENSOR)
#if ANY(LIN_ADVANCE, HAS_FILAMENT_SENSOR)
#include "filament_menu.h"
#endif
#if ENABLED(FILAMENT_RUNOUT_SENSOR)
#if HAS_FILAMENT_SENSOR
#include "filament_runout_screen.h"
#endif

View file

@ -374,9 +374,9 @@ void StatusScreen::draw_interaction_buttons(draw_mode_t what) {
.button(TOOL_HEAD_POS, !ExtUI::isPrintingPaused() ? GET_TEXT_F(MSG_BUTTON_PAUSE) : GET_TEXT_F(MSG_BUTTON_RESUME))
.tag(!ExtUI::isPrintingPaused() ? 7 : 14)
.button(CHANGE_FILAMENT_POS, !ExtUI::isPrintingPaused() ? GET_TEXT_F(MSG_SPEED) : F(""));
#if ENABLED(FILAMENT_RUNOUT_SENSOR)
cmd.tag(8).button(PREHEAT_POS, GET_TEXT_F(MSG_SENSOR));
#endif
#if HAS_FILAMENT_SENSOR
cmd.tag(8).button(PREHEAT_POS, GET_TEXT_F(MSG_SENSOR));
#endif
if (ExtUI::isPrintingPaused())
draw_text_box(cmd, CHANGE_FILAMENT_POS, F("Change\nFilament"), OPT_CENTER, font_medium);
}
@ -536,7 +536,7 @@ bool StatusScreen::onTouchEnd(uint8_t tag) {
}
break;
case 7: GOTO_SCREEN(FeedratePercentScreen); break;
#if ENABLED(FILAMENT_RUNOUT_SENSOR)
#if HAS_FILAMENT_SENSOR
case 8: GOTO_SCREEN(FilamentRunoutScreen); break;
#endif
case 9: injectCommands(F("G28")); break;

View file

@ -171,7 +171,7 @@ void onUserConfirmRequired(const char *const msg) {
case PAUSE_MESSAGE_PURGE: {
rts.sendData(ExchangePageBase + 78, ExchangepageAddr);
char newMsg[40] = "Yes to ";
strcat_P(newMsg, TERN1(FILAMENT_RUNOUT_SENSOR, !ExtUI::getFilamentRunoutState() && getFilamentRunoutEnabled()) ? PSTR("Continue") : PSTR("Disable "));
strcat_P(newMsg, TERN1(HAS_FILAMENT_SENSOR, !ExtUI::getFilamentRunoutState() && getFilamentRunoutEnabled()) ? PSTR("Continue") : PSTR("Disable "));
strcat_P(newMsg, PSTR(" No to Purge"));
onStatusChanged(newMsg);
break;
@ -181,7 +181,7 @@ void onUserConfirmRequired(const char *const msg) {
case PAUSE_MESSAGE_OPTION: {
rts.sendData(ExchangePageBase + 78, ExchangepageAddr);
char newMsg[40] = "Yes to ";
strcat_P(newMsg, TERN1(FILAMENT_RUNOUT_SENSOR, !ExtUI::getFilamentRunoutState() && getFilamentRunoutEnabled()) ? PSTR("Continue") : PSTR("Disable "));
strcat_P(newMsg, TERN1(HAS_FILAMENT_SENSOR, !ExtUI::getFilamentRunoutState() && getFilamentRunoutEnabled()) ? PSTR("Continue") : PSTR("Disable "));
strcat_P(newMsg, PSTR(" No to Purge"));
onStatusChanged(newMsg);
break;

View file

@ -1435,7 +1435,7 @@ void RTS::handleData() {
// pause_resume_selected = true;
}
else {
#if ENABLED(FILAMENT_RUNOUT_SENSOR)
#if HAS_FILAMENT_SENSOR
bool runouton = false;
if (getFilamentRunoutState()) {
#if NUM_RUNOUT_SENSORS > 1

View file

@ -293,7 +293,7 @@ namespace ExtUI {
return GET_TEMP_ADJUSTMENT(thermalManager.degHotend(extruder - E0));
}
celsius_float_t getTargetTemp_celsius(const heater_t heater) {
celsius_t getTargetTemp_celsius(const heater_t heater) {
switch (heater) {
#if HAS_HEATED_BED
case BED: return GET_TEMP_ADJUSTMENT(thermalManager.degTargetBed());
@ -305,19 +305,19 @@ namespace ExtUI {
}
}
celsius_float_t getTargetTemp_celsius(const extruder_t extruder) {
celsius_t getTargetTemp_celsius(const extruder_t extruder) {
return GET_TEMP_ADJUSTMENT(thermalManager.degTargetHotend(extruder - E0));
}
//
// Fan target/actual speed
//
float getTargetFan_percent(const fan_t fan) {
uint8_t getTargetFan_percent(const fan_t fan) {
UNUSED(fan);
return TERN0(HAS_FAN, thermalManager.fanSpeedPercent(fan - FAN0));
}
float getActualFan_percent(const fan_t fan) {
uint8_t getActualFan_percent(const fan_t fan) {
UNUSED(fan);
return TERN0(HAS_FAN, thermalManager.scaledFanSpeedPercent(fan - FAN0));
}
@ -1003,7 +1003,7 @@ namespace ExtUI {
feedrate_mm_s = MMM_TO_MMS(Z_PROBE_FEEDRATE_FAST);
destination.set(current_position.x, current_position.y, Z_CLEARANCE_BETWEEN_PROBES);
prepare_line_to_destination();
feedrate_mm_s = XY_PROBE_FEEDRATE_MM_S;
if (XY_PROBE_FEEDRATE_MM_S) feedrate_mm_s = XY_PROBE_FEEDRATE_MM_S;
destination.set(x_target, y_target);
prepare_line_to_destination();
}

View file

@ -172,10 +172,10 @@ namespace ExtUI {
bool isHeaterIdle(const extruder_t);
celsius_float_t getActualTemp_celsius(const heater_t);
celsius_float_t getActualTemp_celsius(const extruder_t);
celsius_float_t getTargetTemp_celsius(const heater_t);
celsius_float_t getTargetTemp_celsius(const extruder_t);
float getActualFan_percent(const fan_t);
float getTargetFan_percent(const fan_t);
celsius_t getTargetTemp_celsius(const heater_t);
celsius_t getTargetTemp_celsius(const extruder_t);
uint8_t getActualFan_percent(const fan_t);
uint8_t getTargetFan_percent(const fan_t);
// High level positions, by Axis ID, Extruder ID
float getAxisPosition_mm(const axis_t);

View file

@ -55,10 +55,10 @@ MarlinUI ui;
#endif
#if ENABLED(LCD_PROGRESS_BAR) && !IS_TFTGLCD_PANEL
#define BASIC_PROGRESS_BAR 1
#define HAS_BASIC_PROGRESS_BAR 1
#endif
#if ANY(HAS_DISPLAY, HAS_STATUS_MESSAGE, BASIC_PROGRESS_BAR)
#if ANY(HAS_DISPLAY, HAS_STATUS_MESSAGE, HAS_BASIC_PROGRESS_BAR)
#include "../module/printcounter.h"
#endif
@ -598,7 +598,7 @@ void MarlinUI::init() {
* This is very display-dependent, so the lcd implementation draws this.
*/
#if BASIC_PROGRESS_BAR
#if HAS_BASIC_PROGRESS_BAR
millis_t MarlinUI::progress_bar_ms; // = 0
#if PROGRESS_MSG_EXPIRE > 0
millis_t MarlinUI::expire_status_ms; // = 0
@ -607,7 +607,7 @@ void MarlinUI::init() {
void MarlinUI::status_screen() {
#if BASIC_PROGRESS_BAR
#if HAS_BASIC_PROGRESS_BAR
//
// HD44780 implements the following message blinking and
@ -647,7 +647,7 @@ void MarlinUI::init() {
#endif // PROGRESS_MSG_EXPIRE
#endif // BASIC_PROGRESS_BAR
#endif // HAS_BASIC_PROGRESS_BAR
bool did_expire = status_reset_callback && (*status_reset_callback)();
@ -1592,11 +1592,11 @@ void MarlinUI::host_notify(const char * const cstr) {
#if HAS_WIRED_LCD
#if BASIC_PROGRESS_BAR || ALL(FILAMENT_LCD_DISPLAY, HAS_MEDIA)
#if HAS_BASIC_PROGRESS_BAR || ALL(FILAMENT_LCD_DISPLAY, HAS_MEDIA)
const millis_t ms = millis();
#endif
#if BASIC_PROGRESS_BAR
#if HAS_BASIC_PROGRESS_BAR
progress_bar_ms = ms;
#if PROGRESS_MSG_EXPIRE > 0
expire_status_ms = persist ? 0 : ms + PROGRESS_MSG_EXPIRE;

View file

@ -205,15 +205,6 @@ public:
static void init();
#if HAS_DISPLAY || HAS_DWIN_E3V2
static void init_lcd();
// Erase the LCD contents. Do the lowest-level thing required to clear the LCD.
static void clear_lcd();
#else
static void init_lcd() {}
static void clear_lcd() {}
#endif
static void reinit_lcd() { TERN_(REINIT_NOISY_LCD, init_lcd()); }
#if HAS_WIRED_LCD
@ -522,6 +513,11 @@ public:
#if HAS_DISPLAY
static void init_lcd();
// Erase the LCD contents. Do the lowest-level thing required to clear the LCD.
static void clear_lcd();
// Clear the LCD before new drawing. Some LCDs do nothing because they redraw frequently.
static void clear_for_drawing();
@ -635,6 +631,8 @@ public:
#else // No LCD
static void init_lcd() {}
static void clear_lcd() {}
static void clear_for_drawing() {}
static void kill_screen(FSTR_P const, FSTR_P const) {}

View file

@ -27,14 +27,14 @@
#include "game.h"
#define BRICK_H 5
#define BRICK_TOP MENU_FONT_ASCENT
#define BRICK_TOP GAME_FONT_ASCENT
#define PADDLE_H 2
#define PADDLE_VEL 3
#define PADDLE_W ((LCD_PIXEL_WIDTH) / 8)
#define PADDLE_Y (LCD_PIXEL_HEIGHT - 1 - PADDLE_H)
#define PADDLE_W ((GAME_WIDTH) / 8)
#define PADDLE_Y (GAME_HEIGHT - 1 - PADDLE_H)
#define BRICK_W ((LCD_PIXEL_WIDTH) / (BRICK_COLS))
#define BRICK_W ((GAME_WIDTH) / (BRICK_COLS))
#define BRICK_BOT (BRICK_TOP + BRICK_H * BRICK_ROWS - 1)
#define BRICK_COL(X) ((X) / (BRICK_W))
@ -53,7 +53,7 @@ void reset_ball() {
bdat.ballv = FTOF(1.3f);
bdat.ballh = -FTOF(1.25f);
uint8_t bx = bdat.paddle_x + (PADDLE_W) / 2 + ball_dist;
if (bx >= LCD_PIXEL_WIDTH - 10) { bx -= ball_dist * 2; bdat.ballh = -bdat.ballh; }
if (bx >= GAME_WIDTH - 10) { bx -= ball_dist * 2; bdat.ballh = -bdat.ballh; }
bdat.ballx = BTOF(bx);
bdat.hit_dir = -1;
}
@ -61,7 +61,7 @@ void reset_ball() {
void BrickoutGame::game_screen() {
if (game_frame()) { // Run logic twice for finer resolution
// Update Paddle Position
bdat.paddle_x = constrain(int8_t(ui.encoderPosition), 0, (LCD_PIXEL_WIDTH - (PADDLE_W)) / (PADDLE_VEL));
bdat.paddle_x = constrain(int8_t(ui.encoderPosition), 0, (GAME_WIDTH - (PADDLE_W)) / (PADDLE_VEL));
ui.encoderPosition = bdat.paddle_x;
bdat.paddle_x *= (PADDLE_VEL);
@ -70,7 +70,7 @@ void BrickoutGame::game_screen() {
// Provisionally update the ball position
const fixed_t newx = bdat.ballx + bdat.ballh, newy = bdat.bally + bdat.ballv; // current next position
if (!WITHIN(newx, 0, BTOF(LCD_PIXEL_WIDTH - 1))) { // out in x?
if (!WITHIN(newx, 0, BTOF(GAME_WIDTH - 1))) { // out in x?
bdat.ballh = -bdat.ballh; _BUZZ(5, 220); // bounce x
}
if (newy < 0) { // out in y?
@ -78,7 +78,7 @@ void BrickoutGame::game_screen() {
bdat.hit_dir = 1;
}
// Did the ball go below the bottom?
else if (newy > BTOF(LCD_PIXEL_HEIGHT)) {
else if (newy > BTOF(GAME_HEIGHT)) {
_BUZZ(500, 75);
if (--bdat.balls_left) reset_ball(); else game_state = 0;
break; // done
@ -134,32 +134,51 @@ void BrickoutGame::game_screen() {
} while (false);
}
u8g.setColorIndex(1);
frame_start();
// Draw bricks
// Draw bricks, cycling through colors for each brick
#if IS_DWIN_MARLINUI
const color brick_colors[] = { color::RED, color::CYAN, color::GREEN, color::YELLOW, color::MAGENTA, color::BLUE };
int color_index = 0;
#endif
if (PAGE_CONTAINS(BRICK_TOP, BRICK_BOT)) {
for (uint8_t y = 0; y < BRICK_ROWS; ++y) {
const uint8_t yy = y * BRICK_H + BRICK_TOP;
if (PAGE_CONTAINS(yy, yy + BRICK_H - 1)) {
for (uint8_t x = 0; x < BRICK_COLS; ++x) {
#if IS_DWIN_MARLINUI
// Cycle through colors, even if the brick is gone.
// Otherwise, bricks would change color if their neighbor is hit
set_color(brick_colors[color_index++ % COUNT(brick_colors)]);
#endif
// Draw brick if it's still there
if (TEST(bdat.bricks[y], x)) {
const uint8_t xx = x * BRICK_W;
for (uint8_t v = 0; v < BRICK_H - 1; ++v)
if (PAGE_CONTAINS(yy + v, yy + v))
u8g.drawHLine(xx, yy + v, BRICK_W - 1);
#if IS_DWIN_MARLINUI
if (PAGE_CONTAINS(yy, yy + BRICK_H - 1))
draw_box(xx, yy, BRICK_W - 1, BRICK_H - 1);
#else
for (uint8_t v = 0; v < BRICK_H - 1; ++v)
if (PAGE_CONTAINS(yy + v, yy + v))
u8g.drawHLine(xx, yy + v, BRICK_W - 1);
#endif
}
}
}
}
}
// Everything else is white
TERN_(IS_DWIN_MARLINUI, set_color(color::WHITE));
// Draw paddle
if (PAGE_CONTAINS(PADDLE_Y-1, PADDLE_Y)) {
u8g.drawHLine(bdat.paddle_x, PADDLE_Y, PADDLE_W);
draw_hline(bdat.paddle_x, PADDLE_Y, PADDLE_W);
#if PADDLE_H > 1
u8g.drawHLine(bdat.paddle_x, PADDLE_Y-1, PADDLE_W);
draw_hline(bdat.paddle_x, PADDLE_Y-1, PADDLE_W);
#if PADDLE_H > 2
u8g.drawHLine(bdat.paddle_x, PADDLE_Y-2, PADDLE_W);
draw_hline(bdat.paddle_x, PADDLE_Y-2, PADDLE_W);
#endif
#endif
}
@ -168,29 +187,30 @@ void BrickoutGame::game_screen() {
if (game_state) {
const uint8_t by = FTOB(bdat.bally);
if (PAGE_CONTAINS(by, by+1))
u8g.drawFrame(FTOB(bdat.ballx), by, 2, 2);
draw_frame(FTOB(bdat.ballx), by, 2, 2);
}
// Or draw GAME OVER
else
draw_game_over();
if (PAGE_UNDER(MENU_FONT_ASCENT)) {
if (PAGE_UNDER(GAME_FONT_ASCENT)) {
// Score Digits
//const uint8_t sx = (LCD_PIXEL_WIDTH - (score >= 10 ? score >= 100 ? score >= 1000 ? 4 : 3 : 2 : 1) * MENU_FONT_WIDTH) / 2;
//const uint8_t sx = (GAME_WIDTH - (score >= 10 ? score >= 100 ? score >= 1000 ? 4 : 3 : 2 : 1) * GAME_FONT_WIDTH) / 2;
constexpr uint8_t sx = 0;
lcd_put_int(sx, MENU_FONT_ASCENT - 1, score);
draw_int(sx, GAME_FONT_ASCENT - 1, score);
// Balls Left
lcd_moveto(LCD_PIXEL_WIDTH - MENU_FONT_WIDTH * 3, MENU_FONT_ASCENT - 1);
PGM_P const ohs = PSTR("ooo\0\0");
lcd_put_u8str_P(ohs + 3 - bdat.balls_left);
draw_string(GAME_WIDTH - GAME_FONT_WIDTH * 3, GAME_FONT_ASCENT - 1, ohs + 3 - bdat.balls_left);
}
frame_end();
// A click always exits this game
if (ui.use_click()) exit_game();
}
#define SCREEN_M ((LCD_PIXEL_WIDTH) / 2)
#define SCREEN_M ((GAME_WIDTH) / 2)
void BrickoutGame::enter_game() {
init_game(2, game_screen); // 2 = reset bricks on paddle hit

View file

@ -40,15 +40,15 @@ bool MarlinGame::game_frame() {
}
void MarlinGame::draw_game_over() {
constexpr int8_t gowide = (MENU_FONT_WIDTH) * 9,
gohigh = MENU_FONT_ASCENT - 3,
lx = (LCD_PIXEL_WIDTH - gowide) / 2,
ly = (LCD_PIXEL_HEIGHT + gohigh) / 2;
constexpr int8_t gowide = (GAME_FONT_WIDTH) * 9,
gohigh = GAME_FONT_ASCENT - 3,
lx = (GAME_WIDTH - gowide) / 2,
ly = (GAME_HEIGHT + gohigh) / 2;
if (PAGE_CONTAINS(ly - gohigh - 1, ly + 1)) {
u8g.setColorIndex(0);
u8g.drawBox(lx - 1, ly - gohigh - 1, gowide + 2, gohigh + 2);
u8g.setColorIndex(1);
if (ui.get_blink()) lcd_put_u8str(lx, ly, F("GAME OVER"));
set_color(color::BLACK);
draw_box(lx - 1, ly - gohigh - 1, gowide + 2, gohigh + 2);
set_color(color::WHITE);
if (ui.get_blink()) draw_string(lx, ly, F("GAME OVER"));
}
}

View file

@ -22,9 +22,8 @@
#pragma once
#include "../../../inc/MarlinConfigPre.h"
#include "../../dogm/marlinui_DOGM.h"
#include "../../lcdprint.h"
#include "../../marlinui.h"
#include "types.h"
//#define MUTE_GAMES

View file

@ -29,11 +29,11 @@
#define CANNON_W 11
#define CANNON_H 8
#define CANNON_VEL 4
#define CANNON_Y (LCD_PIXEL_HEIGHT - 1 - CANNON_H)
#define CANNON_Y (GAME_HEIGHT - 1 - CANNON_H)
#define INVADER_VEL 3
#define INVADER_TOP MENU_FONT_ASCENT
#define INVADER_TOP GAME_FONT_ASCENT
#define INVADERS_WIDE ((INVADER_COL_W) * (INVADER_COLS))
#define INVADERS_HIGH ((INVADER_ROW_H) * (INVADER_ROWS))
@ -48,6 +48,16 @@
#define INVADER_RIGHT ((INVADER_COLS) * (INVADER_COL_W))
#if IS_DWIN_MARLINUI
#define INVADER_COLOR { MarlinGame::color::GREEN, MarlinGame::color::CYAN, MarlinGame::color::YELLOW }
#define CANNON_COLOR MarlinGame::color::WHITE
#define LASER_COLOR MarlinGame::color::WHITE // Shot by player
#define BULLET_COLOR LASER_COLOR // Shot by invader
#define LIFE_COLOR CANNON_COLOR
#define UFO_COLOR MarlinGame::color::MAGENTA
#define EXPLOSION_COLOR MarlinGame::color::RED
#endif
// 11x8
const unsigned char invader[3][2][16] PROGMEM = {
{ { B00000110,B00000000,
@ -175,7 +185,7 @@ inline void update_invader_data() {
}
idat.leftmost = 0;
for (uint8_t i = 0; i < INVADER_COLS; ++i) { if (TEST(inv_mask, i)) break; idat.leftmost -= INVADER_COL_W; }
idat.rightmost = LCD_PIXEL_WIDTH - (INVADERS_WIDE);
idat.rightmost = GAME_WIDTH - (INVADERS_WIDE);
for (uint8_t i = INVADER_COLS; i--;) { if (TEST(inv_mask, i)) break; idat.rightmost += INVADER_COL_W; }
if (idat.count == 2) idat.dir = idat.dir > 0 ? INVADER_VEL + 1 : -(INVADER_VEL + 1);
}
@ -195,7 +205,7 @@ inline void reset_invaders() {
inline void spawn_ufo() {
idat.ufov = random(0, 2) ? 1 : -1;
idat.ufox = idat.ufov > 0 ? -(UFO_W) : LCD_PIXEL_WIDTH - 1;
idat.ufox = idat.ufov > 0 ? -(UFO_W) : GAME_WIDTH - 1;
}
inline void reset_player() {
@ -205,7 +215,7 @@ inline void reset_player() {
inline void fire_cannon() {
idat.laser.x = idat.cannon_x + CANNON_W / 2;
idat.laser.y = LCD_PIXEL_HEIGHT - CANNON_H - (LASER_H);
idat.laser.y = GAME_HEIGHT - CANNON_H - (LASER_H);
idat.laser.v = -(LASER_H);
}
@ -235,7 +245,7 @@ void InvadersGame::game_screen() {
if (ui.first_page) {
// Update Cannon Position
int16_t ep = constrain(int16_t(ui.encoderPosition), 0, (LCD_PIXEL_WIDTH - (CANNON_W)) / (CANNON_VEL));
int16_t ep = constrain(int16_t(ui.encoderPosition), 0, (GAME_WIDTH - (CANNON_W)) / (CANNON_VEL));
ui.encoderPosition = ep;
ep *= (CANNON_VEL);
@ -246,7 +256,7 @@ void InvadersGame::game_screen() {
if (game_state) do {
// Move the UFO, if any
if (idat.ufov) { idat.ufox += idat.ufov; if (!WITHIN(idat.ufox, -(UFO_W), LCD_PIXEL_WIDTH - 1)) idat.ufov = 0; }
if (idat.ufov) { idat.ufox += idat.ufov; if (!WITHIN(idat.ufox, -(UFO_W), GAME_WIDTH - 1)) idat.ufov = 0; }
if (game_state > 1) { if (--game_state == 2) { reset_invaders(); } else if (game_state == 100) { game_state = 1; } break; }
@ -326,7 +336,7 @@ void InvadersGame::game_screen() {
if (b->v) {
// Update alien bullet position
b->y += b->v;
if (b->y >= LCD_PIXEL_HEIGHT)
if (b->y >= GAME_HEIGHT)
b->v = 0; // Offscreen
else if (b->y >= CANNON_Y && WITHIN(b->x, idat.cannon_x, idat.cannon_x + CANNON_W - 1))
kill_cannon(game_state, 120); // Hit the cannon
@ -365,7 +375,7 @@ void InvadersGame::game_screen() {
if (!idat.quit_count) exit_game();
u8g.setColorIndex(1);
frame_start();
// Draw invaders
if (PAGE_CONTAINS(idat.pos.y, idat.pos.y + idat.botmost * (INVADER_ROW_H) - 2 - 1)) {
@ -375,8 +385,13 @@ void InvadersGame::game_screen() {
if (PAGE_CONTAINS(yy, yy + INVADER_H - 1)) {
int8_t xx = idat.pos.x;
for (uint8_t x = 0; x < INVADER_COLS; ++x) {
if (TEST(idat.bugs[y], x))
u8g.drawBitmapP(xx, yy, 2, INVADER_H, invader[type][idat.game_blink]);
if (TEST(idat.bugs[y], x)) {
#if IS_DWIN_MARLINUI
constexpr color invader_color[] = INVADER_COLOR;
set_color(invader_color[type]);
#endif
draw_bitmap(xx, yy, 2, INVADER_H, invader[type][idat.game_blink]);
}
xx += INVADER_COL_W;
}
}
@ -385,44 +400,59 @@ void InvadersGame::game_screen() {
}
// Draw UFO
if (idat.ufov && PAGE_UNDER(UFO_H + 2))
u8g.drawBitmapP(idat.ufox, 2, 2, UFO_H, ufo);
if (idat.ufov && PAGE_UNDER(UFO_H + 2)) {
TERN_(IS_DWIN_MARLINUI, set_color(UFO_COLOR));
draw_bitmap(idat.ufox, 2, 2, UFO_H, ufo);
}
// Draw cannon
if (game_state && PAGE_CONTAINS(CANNON_Y, CANNON_Y + CANNON_H - 1) && (game_state < 2 || (game_state & 0x02)))
u8g.drawBitmapP(idat.cannon_x, CANNON_Y, 2, CANNON_H, cannon);
if (game_state && PAGE_CONTAINS(CANNON_Y, CANNON_Y + CANNON_H - 1) && (game_state < 2 || (game_state & 0x02))) {
TERN_(IS_DWIN_MARLINUI, set_color(CANNON_COLOR));
draw_bitmap(idat.cannon_x, CANNON_Y, 2, CANNON_H, cannon);
}
// Draw laser
if (idat.laser.v && PAGE_CONTAINS(idat.laser.y, idat.laser.y + LASER_H - 1))
u8g.drawVLine(idat.laser.x, idat.laser.y, LASER_H);
if (idat.laser.v && PAGE_CONTAINS(idat.laser.y, idat.laser.y + LASER_H - 1)) {
TERN_(IS_DWIN_MARLINUI, set_color(LASER_COLOR));
draw_vline(idat.laser.x, idat.laser.y, LASER_H);
}
// Draw invader bullets
for (uint8_t i = 0; i < COUNT(idat.bullet); ++i) {
if (idat.bullet[i].v && PAGE_CONTAINS(idat.bullet[i].y - (SHOT_H - 1), idat.bullet[i].y))
u8g.drawVLine(idat.bullet[i].x, idat.bullet[i].y - (SHOT_H - 1), SHOT_H);
if (idat.bullet[i].v && PAGE_CONTAINS(idat.bullet[i].y - (SHOT_H - 1), idat.bullet[i].y)) {
TERN_(IS_DWIN_MARLINUI, set_color(BULLET_COLOR));
draw_vline(idat.bullet[i].x, idat.bullet[i].y - (SHOT_H - 1), SHOT_H);
}
}
// Draw explosion
if (idat.explod.v && PAGE_CONTAINS(idat.explod.y, idat.explod.y + 7 - 1)) {
u8g.drawBitmapP(idat.explod.x, idat.explod.y, 2, 7, explosion);
TERN_(IS_DWIN_MARLINUI, set_color(EXPLOSION_COLOR));
draw_bitmap(idat.explod.x, idat.explod.y, 2, 7, explosion);
--idat.explod.v;
}
// Everything else is white
TERN_(IS_DWIN_MARLINUI, set_color(color::WHITE));
// Blink GAME OVER when game is over
if (!game_state) draw_game_over();
if (PAGE_UNDER(MENU_FONT_ASCENT - 1)) {
// Draw Score
//const uint8_t sx = (LCD_PIXEL_WIDTH - (score >= 10 ? score >= 100 ? score >= 1000 ? 4 : 3 : 2 : 1) * MENU_FONT_WIDTH) / 2;
constexpr uint8_t sx = 0;
lcd_put_int(sx, MENU_FONT_ASCENT - 1, score);
if (PAGE_UNDER(GAME_FONT_ASCENT - 1)) {
// Draw lives
if (idat.cannons_left)
for (uint8_t i = 1; i <= idat.cannons_left; ++i)
u8g.drawBitmapP(LCD_PIXEL_WIDTH - i * (LIFE_W), 6 - (LIFE_H), 1, LIFE_H, life);
for (uint8_t i = 1; i <= idat.cannons_left; ++i) {
TERN_(IS_DWIN_MARLINUI, set_color(LIFE_COLOR));
draw_bitmap(GAME_WIDTH - i * (LIFE_W), 6 - (LIFE_H), 1, LIFE_H, life);
}
// Draw Score
//const uint8_t sx = (GAME_WIDTH - (score >= 10 ? score >= 100 ? score >= 1000 ? 4 : 3 : 2 : 1) * GAME_FONT_WIDTH) / 2;
constexpr uint8_t sx = 0;
draw_int(sx, GAME_FONT_ASCENT - 1, score);
}
frame_end();
}
void InvadersGame::enter_game() {

View file

@ -28,13 +28,13 @@
#define SNAKE_BOX 4
#define HEADER_H (MENU_FONT_ASCENT - 2)
#define HEADER_H (GAME_FONT_ASCENT - 2)
#define SNAKE_WH (SNAKE_BOX + 1)
#define IDEAL_L 2
#define IDEAL_R (LCD_PIXEL_WIDTH - 1 - 2)
#define IDEAL_R (GAME_WIDTH - 1 - 2)
#define IDEAL_T (HEADER_H + 2)
#define IDEAL_B (LCD_PIXEL_HEIGHT - 1 - 2)
#define IDEAL_B (GAME_HEIGHT - 1 - 2)
#define IDEAL_W (IDEAL_R - (IDEAL_L) + 1)
#define IDEAL_H (IDEAL_B - (IDEAL_T) + 1)
@ -43,9 +43,9 @@
#define BOARD_W ((SNAKE_WH) * (GAME_W) + 1)
#define BOARD_H ((SNAKE_WH) * (GAME_H) + 1)
#define BOARD_L ((LCD_PIXEL_WIDTH - (BOARD_W) + 1) / 2)
#define BOARD_L ((GAME_WIDTH - (BOARD_W) + 1) / 2)
#define BOARD_R (BOARD_L + BOARD_W - 1)
#define BOARD_T (((LCD_PIXEL_HEIGHT + IDEAL_T) - (BOARD_H)) / 2)
#define BOARD_T (((GAME_HEIGHT + IDEAL_T) - (BOARD_H)) / 2)
#define BOARD_B (BOARD_T + BOARD_H - 1)
#define GAMEX(X) (BOARD_L + ((X) * (SNAKE_WH)))
@ -228,15 +228,10 @@ void SnakeGame::game_screen() {
} while(0);
u8g.setColorIndex(1);
frame_start();
// Draw Score
if (PAGE_UNDER(HEADER_H)) lcd_put_int(0, HEADER_H - 1, score);
// DRAW THE PLAYFIELD BORDER
u8g.drawFrame(BOARD_L - 2, BOARD_T - 2, BOARD_R - BOARD_L + 4, BOARD_B - BOARD_T + 4);
// Draw the snake (tail)
// Draw the snake (tail) in green
TERN_(IS_DWIN_MARLINUI, set_color(color::GREEN));
#if SNAKE_WH < 2
// At this scale just draw a line
@ -245,11 +240,11 @@ void SnakeGame::game_screen() {
if (p.x == q.x) {
const int8_t y1 = GAMEY(_MIN(p.y, q.y)), y2 = GAMEY(_MAX(p.y, q.y));
if (PAGE_CONTAINS(y1, y2))
u8g.drawVLine(GAMEX(p.x), y1, y2 - y1 + 1);
draw_vline(GAMEX(p.x), y1, y2 - y1 + 1);
}
else if (PAGE_CONTAINS(GAMEY(p.y), GAMEY(p.y))) {
const int8_t x1 = GAMEX(_MIN(p.x, q.x)), x2 = GAMEX(_MAX(p.x, q.x));
u8g.drawHLine(x1, GAMEY(p.y), x2 - x1 + 1);
draw_hline(x1, GAMEY(p.y), x2 - x1 + 1);
}
}
@ -261,13 +256,13 @@ void SnakeGame::game_screen() {
if (p.x == q.x) {
const int8_t y1 = GAMEY(_MIN(p.y, q.y)), y2 = GAMEY(_MAX(p.y, q.y));
if (PAGE_CONTAINS(y1, y2 + 1))
u8g.drawFrame(GAMEX(p.x), y1, 2, y2 - y1 + 1 + 1);
draw_frame(GAMEX(p.x), y1, 2, y2 - y1 + 1 + 1);
}
else {
const int8_t py = GAMEY(p.y);
if (PAGE_CONTAINS(py, py + 1)) {
const int8_t x1 = GAMEX(_MIN(p.x, q.x)), x2 = GAMEX(_MAX(p.x, q.x));
u8g.drawFrame(x1, py, x2 - x1 + 1 + 1, 2);
draw_frame(x1, py, x2 - x1 + 1 + 1, 2);
}
}
}
@ -283,7 +278,7 @@ void SnakeGame::game_screen() {
for (int8_t i = y1; i <= y2; ++i) {
const int8_t y = GAMEY(i);
if (PAGE_CONTAINS(y, y + SNAKE_SIZ - 1))
u8g.drawBox(GAMEX(p.x), y, SNAKE_SIZ, SNAKE_SIZ);
draw_box(GAMEX(p.x), y, SNAKE_SIZ, SNAKE_SIZ);
}
}
}
@ -292,26 +287,36 @@ void SnakeGame::game_screen() {
if (PAGE_CONTAINS(py, py + SNAKE_SIZ - 1)) {
const int8_t x1 = _MIN(p.x, q.x), x2 = _MAX(p.x, q.x);
for (int8_t i = x1; i <= x2; ++i)
u8g.drawBox(GAMEX(i), py, SNAKE_SIZ, SNAKE_SIZ);
draw_box(GAMEX(i), py, SNAKE_SIZ, SNAKE_SIZ);
}
}
}
#endif
// Draw food
// Draw food in red
TERN_(IS_DWIN_MARLINUI, set_color(color::RED));
const int8_t fy = GAMEY(sdat.foody);
if (PAGE_CONTAINS(fy, fy + FOOD_WH - 1)) {
const int8_t fx = GAMEX(sdat.foodx);
u8g.drawFrame(fx, fy, FOOD_WH, FOOD_WH);
if (FOOD_WH == 5) u8g.drawPixel(fx + 2, fy + 2);
draw_frame(fx, fy, FOOD_WH, FOOD_WH);
if (FOOD_WH == 5) draw_pixel(fx + 2, fy + 2);
}
// Draw the playfield border
TERN_(IS_DWIN_MARLINUI, set_color(color::WHITE));
draw_frame(BOARD_L - 2, BOARD_T - 2, BOARD_R - BOARD_L + 4, BOARD_B - BOARD_T + 4);
// Draw Score
if (PAGE_UNDER(HEADER_H)) draw_int(0, HEADER_H - 1, score);
// Draw GAME OVER
if (!game_state) draw_game_over();
// A click always exits this game
if (ui.use_click()) exit_game();
frame_end();
}
void SnakeGame::enter_game() {

View file

@ -21,7 +21,14 @@
*/
#pragma once
#include <stdint.h>
#include "../../../inc/MarlinConfigPre.h"
#include "../../marlinui.h"
#if HAS_MARLINUI_U8GLIB
#include "../../dogm/game.h"
#elif IS_DWIN_MARLINUI
#include "../../e3v2/marlinui/game.h"
#endif
typedef struct { int8_t x, y; } pos_t;
@ -41,6 +48,125 @@ protected:
static bool game_frame();
static void draw_game_over();
static void exit_game();
public:
static void init_game(const uint8_t init_state, const screenFunc_t screen);
// Game rendering API, based on U8glib's API.
// See the @see comments for the U8glib API documentation corresponding to each function.
/**
* @brief The colors available for drawing games.
* @note Renderer implementations will map these colors to the closest
* available color on the screen, as long as that color is not black.
* Thus, black is guranteed to be black on all screens, but other colors may differ.
* On black-and-white screens, all colors but black will be white.
*/
enum class color {
BLACK, WHITE
#if IS_DWIN_MARLINUI
, RED, GREEN, BLUE, YELLOW, CYAN, MAGENTA
#endif
};
protected:
/**
* @brief Called before any draw calls in the current frame.
*/
static void frame_start();
/**
* @brief Called after all draw calls in the current frame.
*/
static void frame_end();
/**
* @brief Set the color for subsequent draw calls.
* @param color The color to use for subsequent draw calls.
*/
static void set_color(const color color);
/**
* @brief Draw a horizontal line.
* @param x The x-coordinate of the start of the line.
* @param y The y-coordinate of the line.
* @param l The length of the line.
* @see https://github.com/olikraus/u8glib/wiki/userreference#drawhline
*/
static void draw_hline(const game_dim_t x, const game_dim_t y, const game_dim_t l);
/**
* @brief Draw a vertical line.
* @param x The x-coordinate of the line.
* @param y The y-coordinate of the start of the line.
* @param l The length of the line.
* @see https://github.com/olikraus/u8glib/wiki/userreference#drawvline
*/
static void draw_vline(const game_dim_t x, const game_dim_t y, const game_dim_t l);
/**
* @brief Draw a outlined rectangle (frame).
* @param x The x-coordinate of the top-left corner of the frame.
* @param y The y-coordinate of the top-left corner of the frame.
* @param w The width of the frame.
* @param h The height of the frame.
* @see https://github.com/olikraus/u8glib/wiki/userreference#drawframe
*/
static void draw_frame(const game_dim_t x, const game_dim_t y, const game_dim_t w, const game_dim_t h);
/**
* @brief Draw a filled rectangle (box).
* @param x The x-coordinate of the top-left corner of the box.
* @param y The y-coordinate of the top-left corner of the box.
* @param w The width of the box.
* @param h The height of the box.
* @see https://github.com/olikraus/u8glib/wiki/userreference#drawbox
*/
static void draw_box(const game_dim_t x, const game_dim_t y, const game_dim_t w, const game_dim_t h);
/**
* @brief Draw a pixel.
* @param x The x-coordinate of the pixel.
* @param y The y-coordinate of the pixel.
* @see https://github.com/olikraus/u8glib/wiki/userreference#drawpixel
*/
static void draw_pixel(const game_dim_t x, const game_dim_t y);
/**
* @brief Draw a bitmap.
* @param x The x-coordinate of the top-left corner of the bitmap.
* @param y The y-coordinate of the top-left corner of the bitmap.
* @param bytes_per_row The number of bytes per row in the bitmap (Width = bytes_per_row * 8).
* @param rows The number of rows in the bitmap (= Height).
* @param bitmap The bitmap to draw.
* @see https://github.com/olikraus/u8glib/wiki/userreference#drawbitmap
*/
static void draw_bitmap(const game_dim_t x, const game_dim_t y, const game_dim_t bytes_per_row, const game_dim_t rows, const pgm_bitmap_t bitmap);
/**
* @brief Draw a string.
* @param x The x-coordinate of the string.
* @param y The y-coordinate of the string.
* @param str The string to draw.
* @see lcd_moveto + lcd_put_u8str
* @note The font size is available using the GAME_FONT_WIDTH and GAME_FONT_ASCENT constants.
*
* @note On the DWIN renderer, strings may flush the screen, which may cause flickering.
* Consider drawing strings after all other elements have been drawn.
*/
static int draw_string(const game_dim_t x, const game_dim_t y, const char *str);
static int draw_string(const game_dim_t x, const game_dim_t y, FSTR_P const str);
/**
* @brief Draw an integer.
* @param x The x-coordinate of the integer.
* @param y The y-coordinate of the integer.
* @param value The integer to draw.
* @see lcd_put_int
* @note The font size is available using the GAME_FONT_WIDTH and GAME_FONT_ASCENT constants.
*
* @note On the DWIN renderer, strings may flush the screen, which may cause flickering.
* Consider drawing strings after all other elements have been drawn.
*/
static void draw_int(const game_dim_t x, const game_dim_t y, const int value);
};

View file

@ -154,9 +154,12 @@ void menu_backlash();
#if HAS_FILAMENT_RUNOUT_DISTANCE
editable.decimal = runout.runout_distance();
EDIT_ITEM_FAST(float3, MSG_RUNOUT_DISTANCE_MM, &editable.decimal, 1, 999,
[]{ runout.set_runout_distance(editable.decimal); }, true
);
auto set_runout_distance = []{ runout.set_runout_distance(editable.decimal); };
#if ENABLED(FILAMENT_MOTION_SENSOR)
EDIT_ITEM_FAST(float31, MSG_RUNOUT_DISTANCE_MM, &editable.decimal, 0.1, 10, set_runout_distance, true);
#else
EDIT_ITEM_FAST(float3, MSG_RUNOUT_DISTANCE_MM, &editable.decimal, 1, 999, set_runout_distance, true);
#endif
#endif
END_MENU();

View file

@ -138,7 +138,7 @@ void menu_advanced_settings();
#if HAS_BED_PROBE && !HAS_DELTA_SENSORLESS_PROBING
__STOP_ITEM(GET_TEXT_F(MSG_Z_PROBE), Z_MIN_PROBE);
#endif
#if ENABLED(FILAMENT_RUNOUT_SENSOR)
#if HAS_FILAMENT_SENSOR
REPEAT_1(NUM_RUNOUT_SENSORS, FIL_ITEM)
#endif

View file

@ -72,7 +72,7 @@ void menu_motion();
void menu_temperature();
void menu_configuration();
#if HAS_LEVELING || HAS_BED_PROBE
#if ANY(HAS_LEVELING, HAS_BED_PROBE, ASSISTED_TRAMMING_WIZARD, LCD_BED_TRAMMING)
void menu_probe_level();
#endif
@ -338,7 +338,7 @@ void menu_main() {
SUBMENU(MSG_MOTION, menu_motion);
#if HAS_LEVELING || HAS_BED_PROBE
#if ANY(HAS_LEVELING, HAS_BED_PROBE, ASSISTED_TRAMMING_WIZARD, LCD_BED_TRAMMING)
SUBMENU(MSG_PROBE_AND_LEVEL, menu_probe_level);
#endif
}

View file

@ -26,7 +26,7 @@
#include "../../inc/MarlinConfigPre.h"
#if HAS_MARLINUI_MENU && (HAS_LEVELING || HAS_BED_PROBE)
#if HAS_MARLINUI_MENU && ANY(HAS_LEVELING, HAS_BED_PROBE, ASSISTED_TRAMMING_WIZARD, LCD_BED_TRAMMING)
#include "menu_item.h"
@ -44,11 +44,9 @@
#include "../../feature/babystep.h"
#endif
#if HAS_GRAPHICAL_TFT
#if ALL(TOUCH_SCREEN, HAS_GRAPHICAL_TFT)
#include "../tft/tft.h"
#if ENABLED(TOUCH_SCREEN)
#include "../tft/touch.h"
#endif
#include "../tft/touch.h"
#endif
#if ENABLED(LCD_BED_LEVELING) && ANY(PROBE_MANUALLY, MESH_BED_LEVELING)
@ -410,4 +408,4 @@ void menu_probe_level() {
END_MENU();
}
#endif // HAS_MARLINUI_MENU && (HAS_LEVELING || HAS_BED_PROBE)
#endif // HAS_MARLINUI_MENU && (HAS_LEVELING || HAS_BED_PROBE || ASSISTED_TRAMMING_WIZARD || LCD_BED_TRAMMING)

View file

@ -36,6 +36,11 @@
#define XATC_Y_POSITION ((probe.max_y() - probe.min_y())/2)
#endif
#if ALL(TOUCH_SCREEN, HAS_GRAPHICAL_TFT)
#include "../tft/tft.h"
#include "../tft/touch.h"
#endif
void _goto_manual_move_z(const_float_t);
float measured_z, z_offset;

View file

@ -39,8 +39,6 @@ RTS rts;
#include <stdio.h>
#include <string.h>
#include "../../MarlinCore.h"
#include "../../core/serial.h"
#include "../../core/macros.h"
#include "../../sd/cardreader.h"
#include "../../module/temperature.h"
#include "../../module/planner.h"
@ -55,8 +53,7 @@ RTS rts;
#include "../../feature/tmc_util.h"
#include "../../gcode/queue.h"
#include "../../gcode/gcode.h"
//#include "../marlinui.h"
//#include "../utf8.h"
#include "../marlinui.h"
#include "../../libs/BL24CXX.h"
#if ENABLED(FIX_MOUNTED_PROBE)
@ -118,7 +115,7 @@ char commandbuf[30];
static SovolPage change_page_number = ID_Startup;
uint16_t remain_time = 0;
uint32_t remain_time = 0;
static bool last_card_insert_st;
bool card_insert_st;
@ -1365,7 +1362,7 @@ void RTS::handleData() {
#if HAS_FILAMENT_SENSOR
case FilamentChange: // Automatic material
switch (recdat.data[0]) {
case 1: if (runout.filament_ran_out) break;
case 1: if (FILAMENT_IS_OUT()) break;
case 2:
updateTempE0();
wait_for_heatup = wait_for_user = false;
@ -1530,7 +1527,7 @@ void RTS::handleData() {
updateFan0();
job_percent = card.percentDone() + 1;
job_percent = ui.get_progress_percent();
if (job_percent <= 100) sendData(uint8_t(job_percent), PRINT_PROCESS_ICON_VP);
sendData(uint8_t(card.percentDone()), PRINT_PROCESS_VP);
@ -1626,13 +1623,13 @@ void RTS::onIdle() {
if (card.isPrinting() && (last_cardpercentValue != card.percentDone())) {
if (card.percentDone() > 0) {
job_percent = card.percentDone();
job_percent = ui.get_progress_percent();
if (job_percent <= 100) sendData(uint8_t(job_percent), PRINT_PROCESS_ICON_VP);
// Estimate remaining time every 20 seconds
static millis_t next_remain_time_update = 0;
if (ELAPSED(ms, next_remain_time_update)) {
if (thermalManager.degHotend(0) >= thermalManager.degTargetHotend(0) - 5) {
remain_time = elapsed.value / (job_percent * 0.01f) - elapsed.value;
remain_time = ui.get_remaining_time();
next_remain_time_update += 20 * 1000UL;
sendData(remain_time / 3600, PRINT_SURPLUS_TIME_HOUR_VP);
sendData((remain_time % 3600) / 60, PRINT_SURPLUS_TIME_MIN_VP);

View file

@ -236,7 +236,7 @@ enum SovolPage : uint8_t {
ID_AdvWarn_D = 49, ID_AdvWarn_L = 55 + ID_AdvWarn_D, // Warning when entering advanced settings
ID_KillRunaway_D = 52, ID_KillRunaway_L = 55 + ID_KillRunaway_D, // Thermal runaway
ID_KillHeat_D = 53, ID_KillHeat_L = 55 + ID_KillHeat_D, // Thermistor error
ID_KillBadTemp_D = 54, ID_KillBadTemp_L = 55 + ID_KillBadTemp_D, // Heating failed
ID_KillBadTemp_D = 54, ID_KillBadTemp_L = 55 + ID_KillBadTemp_D, // Heating failed
ID_KillHome_D = 55, ID_KillHome_L = 55 + ID_KillHome_D, // Auto-home failed
ID_Level5_D = 111, ID_Level5_L = 6 + ID_Level5_D, // Leveling screen 0.05mm
ID_DriverError_D = 112, ID_DriverError_L = 6 + ID_DriverError_D, // Driver error

View file

@ -55,30 +55,29 @@ void Buzzer::tone(const uint16_t duration, const uint16_t frequency/*=0*/) {
}
void Buzzer::tick() {
if (!ui.sound_on) return;
const millis_t now = millis();
if (!state.endtime) {
if (buffer.isEmpty()) return;
state.tone = buffer.dequeue();
state.endtime = now + state.tone.duration;
if (state.tone.frequency > 0) {
#if ENABLED(EXTENSIBLE_UI) && DISABLED(EXTUI_LOCAL_BEEPER)
CRITICAL_SECTION_START();
ExtUI::onPlayTone(state.tone.frequency, state.tone.duration);
CRITICAL_SECTION_END();
#elif ENABLED(SPEAKER)
CRITICAL_SECTION_START();
::tone(BEEPER_PIN, state.tone.frequency, state.tone.duration);
CRITICAL_SECTION_END();
#else
on();
#endif
}
if (state.endtime) {
if (ELAPSED(millis(), state.endtime)) reset();
return;
}
if (buffer.isEmpty()) return;
state.tone = buffer.dequeue();
state.endtime = millis() + state.tone.duration;
if (state.tone.frequency > 0) {
#if ENABLED(EXTENSIBLE_UI) && DISABLED(EXTUI_LOCAL_BEEPER)
CRITICAL_SECTION_START();
ExtUI::onPlayTone(state.tone.frequency, state.tone.duration);
CRITICAL_SECTION_END();
#elif ENABLED(SPEAKER)
CRITICAL_SECTION_START();
::tone(BEEPER_PIN, state.tone.frequency, state.tone.duration);
CRITICAL_SECTION_END();
#else
on();
#endif
}
else if (ELAPSED(now, state.endtime)) reset();
}
#endif // HAS_BEEPER

View file

@ -25,7 +25,6 @@
#if NEED_HEX_PRINT
#include "hex_print.h"
#include "../core/serial.h"
static char _hex[] = "0x00000000"; // 0:adr32 2:long 4:adr16 6:word 8:byte

View file

@ -27,9 +27,10 @@
#include "endstops.h"
#include "stepper.h"
#include "../sd/cardreader.h"
#include "temperature.h"
#include "../lcd/marlinui.h"
#if HAS_STATUS_MESSAGE
#include "../lcd/marlinui.h"
#endif
#if ENABLED(SOVOL_SV06_RTS)
#include "../lcd/sovol_rts/sovol_rts.h"
#endif
@ -44,6 +45,8 @@
#if ENABLED(SD_ABORT_ON_ENDSTOP_HIT)
#include "printcounter.h" // for print_job_timer
#include "temperature.h"
#include "../sd/cardreader.h"
#endif
#if ENABLED(BLTOUCH)
@ -54,6 +57,10 @@
#include "../feature/joystick.h"
#endif
#if HAS_FILAMENT_SENSOR
#include "../feature/runout.h"
#endif
#if HAS_BED_PROBE
#include "probe.h"
#endif
@ -375,13 +382,13 @@ void Endstops::event_handler() {
#endif
SERIAL_EOL();
TERN_(HAS_STATUS_MESSAGE,
#if HAS_STATUS_MESSAGE
ui.status_printf(0,
F(S_FMT GANG_N_1(NUM_AXES, " %c") " %c"),
GET_TEXT_F(MSG_LCD_ENDSTOPS),
NUM_AXIS_LIST_(chrX, chrY, chrZ, chrI, chrJ, chrK, chrU, chrV, chrW) chrP
)
);
);
#endif
#if ENABLED(SD_ABORT_ON_ENDSTOP_HIT)
if (planner.abort_on_endstop_hit) {
@ -526,7 +533,7 @@ void __O2 Endstops::report_states() {
}
#undef _CASE_RUNOUT
#elif HAS_FILAMENT_SENSOR
print_es_state(READ(FIL_RUNOUT1_PIN) != FIL_RUNOUT1_STATE, F(STR_FILAMENT));
print_es_state(!FILAMENT_IS_OUT(), F(STR_FILAMENT));
#endif
TERN_(BLTOUCH, bltouch._reset_SW_mode());

View file

@ -148,7 +148,7 @@ feedRate_t feedrate_mm_s = MMM_TO_MMS(DEFAULT_FEEDRATE_MM_M);
int16_t feedrate_percentage = 100;
#if ENABLED(EDITABLE_HOMING_FEEDRATE)
xyz_feedrate_t homing_feedrate_mm_m = HOMING_FEEDRATE_MM_M;
#endif
#endif
// Cartesian conversion result goes here:
xyz_pos_t cartes;

View file

@ -55,7 +55,7 @@
constexpr uint16_t sasn[2] = { 0 };
#endif
#ifdef Z_PROBE_SERVO_NR
#if HAS_Z_SERVO_PROBE
#if ENABLED(BLTOUCH)
#include "../feature/bltouch.h"
#undef Z_SERVO_ANGLES
@ -76,6 +76,9 @@
#ifndef SWITCHING_NOZZLE_SERVO_NR
#define SWITCHING_NOZZLE_SERVO_NR -1
#endif
#ifndef SWITCHING_NOZZLE_E1_SERVO_NR
#define SWITCHING_NOZZLE_E1_SERVO_NR -1
#endif
#ifndef Z_PROBE_SERVO_NR
#define Z_PROBE_SERVO_NR -1
#endif
@ -83,12 +86,12 @@
#define SASN(J,I) TERN(SWITCHING_NOZZLE_TWO_SERVOS, sasn[J][I], sasn[I])
#define ASRC(N,I) ( \
N == SWITCHING_EXTRUDER_SERVO_NR ? sase[I] \
: N == SWITCHING_EXTRUDER_E23_SERVO_NR ? sase[I+2] \
: N == SWITCHING_NOZZLE_SERVO_NR ? SASN(0,I) \
TERN_(SWITCHING_NOZZLE_TWO_SERVOS, : N == SWITCHING_NOZZLE_E1_SERVO_NR ? SASN(1,I)) \
: N == Z_PROBE_SERVO_NR ? sazp[I] \
: 0 )
N == SWITCHING_EXTRUDER_SERVO_NR ? sase[I] \
: N == SWITCHING_EXTRUDER_E23_SERVO_NR ? sase[I+2] \
: N == SWITCHING_NOZZLE_SERVO_NR ? SASN(0,I) \
: N == SWITCHING_NOZZLE_E1_SERVO_NR ? SASN(1,I) \
: N == Z_PROBE_SERVO_NR ? sazp[I] \
: 0 )
#if ENABLED(EDITABLE_SERVO_ANGLES)
extern uint16_t servo_angles[NUM_SERVOS][2];
@ -97,24 +100,8 @@
#define CONST_SERVO_ANGLES servo_angles
#endif
constexpr uint16_t CONST_SERVO_ANGLES [NUM_SERVOS][2] = {
{ ASRC(0,0), ASRC(0,1) }
#if NUM_SERVOS > 1
, { ASRC(1,0), ASRC(1,1) }
#if NUM_SERVOS > 2
, { ASRC(2,0), ASRC(2,1) }
#if NUM_SERVOS > 3
, { ASRC(3,0), ASRC(3,1) }
#if NUM_SERVOS > 4
, { ASRC(4,0), ASRC(4,1) }
#if NUM_SERVOS > 5
, { ASRC(5,0), ASRC(5,1) }
#endif
#endif
#endif
#endif
#endif
};
#define _ASRC_PAIR(N) { ASRC(N,0), ASRC(N,1) },
constexpr uint16_t CONST_SERVO_ANGLES [NUM_SERVOS][2] = { REPEAT(NUM_SERVOS, _ASRC_PAIR) };
#if HAS_Z_SERVO_PROBE
#define DEPLOY_Z_SERVO() servo[Z_PROBE_SERVO_NR].move(servo_angles[Z_PROBE_SERVO_NR][0])

View file

@ -314,131 +314,132 @@ xyze_int8_t Stepper::count_direction{0};
#define MAXDIR(A) (count_direction[_AXIS(A)] > 0)
#define STEPTEST(A,M,I) TERN0(USE_##A##I##_##M, !(TEST(endstops.state(), A##I##_##M) && M## DIR(A)) && !locked_ ##A##I##_motor)
#define _STEP_WRITE(A,I,V) A##I##_STEP_WRITE(V)
#define DUAL_ENDSTOP_APPLY_STEP(A,V) \
if (separate_multi_axis) { \
if (ENABLED(A##_HOME_TO_MIN)) { \
if (STEPTEST(A,MIN, )) A## _STEP_WRITE(V); \
if (STEPTEST(A,MIN,2)) A##2_STEP_WRITE(V); \
if (STEPTEST(A,MIN, )) _STEP_WRITE(A, ,V); \
if (STEPTEST(A,MIN,2)) _STEP_WRITE(A,2,V); \
} \
else if (ENABLED(A##_HOME_TO_MAX)) { \
if (STEPTEST(A,MAX, )) A## _STEP_WRITE(V); \
if (STEPTEST(A,MAX,2)) A##2_STEP_WRITE(V); \
if (STEPTEST(A,MAX, )) _STEP_WRITE(A, ,V); \
if (STEPTEST(A,MAX,2)) _STEP_WRITE(A,2,V); \
} \
} \
else { \
A##_STEP_WRITE(V); \
A##2_STEP_WRITE(V); \
_STEP_WRITE(A, ,V); \
_STEP_WRITE(A,2,V); \
}
#define DUAL_SEPARATE_APPLY_STEP(A,V) \
if (separate_multi_axis) { \
if (!locked_##A## _motor) A## _STEP_WRITE(V); \
if (!locked_##A##2_motor) A##2_STEP_WRITE(V); \
if (!locked_##A## _motor) _STEP_WRITE(A, ,V); \
if (!locked_##A##2_motor) _STEP_WRITE(A,2,V); \
} \
else { \
A##_STEP_WRITE(V); \
A##2_STEP_WRITE(V); \
_STEP_WRITE(A, ,V); \
_STEP_WRITE(A,2,V); \
}
#define TRIPLE_ENDSTOP_APPLY_STEP(A,V) \
if (separate_multi_axis) { \
if (ENABLED(A##_HOME_TO_MIN)) { \
if (STEPTEST(A,MIN, )) A## _STEP_WRITE(V); \
if (STEPTEST(A,MIN,2)) A##2_STEP_WRITE(V); \
if (STEPTEST(A,MIN,3)) A##3_STEP_WRITE(V); \
if (STEPTEST(A,MIN, )) _STEP_WRITE(A, ,V); \
if (STEPTEST(A,MIN,2)) _STEP_WRITE(A,2,V); \
if (STEPTEST(A,MIN,3)) _STEP_WRITE(A,3,V); \
} \
else if (ENABLED(A##_HOME_TO_MAX)) { \
if (STEPTEST(A,MAX, )) A## _STEP_WRITE(V); \
if (STEPTEST(A,MAX,2)) A##2_STEP_WRITE(V); \
if (STEPTEST(A,MAX,3)) A##3_STEP_WRITE(V); \
if (STEPTEST(A,MAX, )) _STEP_WRITE(A, ,V); \
if (STEPTEST(A,MAX,2)) _STEP_WRITE(A,2,V); \
if (STEPTEST(A,MAX,3)) _STEP_WRITE(A,3,V); \
} \
} \
else { \
A##_STEP_WRITE(V); \
A##2_STEP_WRITE(V); \
A##3_STEP_WRITE(V); \
_STEP_WRITE(A, ,V); \
_STEP_WRITE(A,2,V); \
_STEP_WRITE(A,3,V); \
}
#define TRIPLE_SEPARATE_APPLY_STEP(A,V) \
if (separate_multi_axis) { \
if (!locked_##A## _motor) A## _STEP_WRITE(V); \
if (!locked_##A##2_motor) A##2_STEP_WRITE(V); \
if (!locked_##A##3_motor) A##3_STEP_WRITE(V); \
if (!locked_##A## _motor) _STEP_WRITE(A, ,V); \
if (!locked_##A##2_motor) _STEP_WRITE(A,2,V); \
if (!locked_##A##3_motor) _STEP_WRITE(A,3,V); \
} \
else { \
A## _STEP_WRITE(V); \
A##2_STEP_WRITE(V); \
A##3_STEP_WRITE(V); \
_STEP_WRITE(A, ,V); \
_STEP_WRITE(A,2,V); \
_STEP_WRITE(A,3,V); \
}
#define QUAD_ENDSTOP_APPLY_STEP(A,V) \
if (separate_multi_axis) { \
if (ENABLED(A##_HOME_TO_MIN)) { \
if (STEPTEST(A,MIN, )) A## _STEP_WRITE(V); \
if (STEPTEST(A,MIN,2)) A##2_STEP_WRITE(V); \
if (STEPTEST(A,MIN,3)) A##3_STEP_WRITE(V); \
if (STEPTEST(A,MIN,4)) A##4_STEP_WRITE(V); \
if (STEPTEST(A,MIN, )) _STEP_WRITE(A, ,V); \
if (STEPTEST(A,MIN,2)) _STEP_WRITE(A,2,V); \
if (STEPTEST(A,MIN,3)) _STEP_WRITE(A,3,V); \
if (STEPTEST(A,MIN,4)) _STEP_WRITE(A,4,V); \
} \
else if (ENABLED(A##_HOME_TO_MAX)) { \
if (STEPTEST(A,MAX, )) A## _STEP_WRITE(V); \
if (STEPTEST(A,MAX,2)) A##2_STEP_WRITE(V); \
if (STEPTEST(A,MAX,3)) A##3_STEP_WRITE(V); \
if (STEPTEST(A,MAX,4)) A##4_STEP_WRITE(V); \
if (STEPTEST(A,MAX, )) _STEP_WRITE(A, ,V); \
if (STEPTEST(A,MAX,2)) _STEP_WRITE(A,2,V); \
if (STEPTEST(A,MAX,3)) _STEP_WRITE(A,3,V); \
if (STEPTEST(A,MAX,4)) _STEP_WRITE(A,4,V); \
} \
} \
else { \
A## _STEP_WRITE(V); \
A##2_STEP_WRITE(V); \
A##3_STEP_WRITE(V); \
A##4_STEP_WRITE(V); \
_STEP_WRITE(A, ,V); \
_STEP_WRITE(A,2,V); \
_STEP_WRITE(A,3,V); \
_STEP_WRITE(A,4,V); \
}
#define QUAD_SEPARATE_APPLY_STEP(A,V) \
if (separate_multi_axis) { \
if (!locked_##A## _motor) A## _STEP_WRITE(V); \
if (!locked_##A##2_motor) A##2_STEP_WRITE(V); \
if (!locked_##A##3_motor) A##3_STEP_WRITE(V); \
if (!locked_##A##4_motor) A##4_STEP_WRITE(V); \
if (!locked_##A## _motor) _STEP_WRITE(A, ,V); \
if (!locked_##A##2_motor) _STEP_WRITE(A,2,V); \
if (!locked_##A##3_motor) _STEP_WRITE(A,3,V); \
if (!locked_##A##4_motor) _STEP_WRITE(A,4,V); \
} \
else { \
A## _STEP_WRITE(V); \
A##2_STEP_WRITE(V); \
A##3_STEP_WRITE(V); \
A##4_STEP_WRITE(V); \
_STEP_WRITE(A, ,V); \
_STEP_WRITE(A,2,V); \
_STEP_WRITE(A,3,V); \
_STEP_WRITE(A,4,V); \
}
#if HAS_SYNCED_X_STEPPERS
#define X_APPLY_DIR(FWD,Q) do{ X_DIR_WRITE(FWD); X2_DIR_WRITE(INVERT_DIR(X2_VS_X, FWD)); }while(0)
#if ENABLED(X_DUAL_ENDSTOPS)
#define X_APPLY_STEP(FWD,Q) DUAL_ENDSTOP_APPLY_STEP(X,FWD)
#define X_APPLY_STEP(STATE,Q) DUAL_ENDSTOP_APPLY_STEP(X,STATE)
#else
#define X_APPLY_STEP(FWD,Q) do{ X_STEP_WRITE(FWD); X2_STEP_WRITE(FWD); }while(0)
#define X_APPLY_STEP(STATE,Q) do{ X_STEP_WRITE(STATE); X2_STEP_WRITE(STATE); }while(0)
#endif
#elif ENABLED(DUAL_X_CARRIAGE)
#define X_APPLY_DIR(FWD,ALWAYS) do{ \
if (extruder_duplication_enabled || ALWAYS) { X_DIR_WRITE(FWD); X2_DIR_WRITE((FWD) ^ idex_mirrored_mode); } \
else if (last_moved_extruder) X2_DIR_WRITE(FWD); else X_DIR_WRITE(FWD); \
}while(0)
#define X_APPLY_STEP(FWD,ALWAYS) do{ \
if (extruder_duplication_enabled || ALWAYS) { X_STEP_WRITE(FWD); X2_STEP_WRITE(FWD); } \
else if (last_moved_extruder) X2_STEP_WRITE(FWD); else X_STEP_WRITE(FWD); \
#define X_APPLY_STEP(STATE,ALWAYS) do{ \
if (extruder_duplication_enabled || ALWAYS) { X_STEP_WRITE(STATE); X2_STEP_WRITE(STATE); } \
else if (last_moved_extruder) X2_STEP_WRITE(STATE); else X_STEP_WRITE(STATE); \
}while(0)
#elif HAS_X_AXIS
#define X_APPLY_DIR(FWD,Q) X_DIR_WRITE(FWD)
#define X_APPLY_STEP(FWD,Q) X_STEP_WRITE(FWD)
#define X_APPLY_STEP(STATE,Q) X_STEP_WRITE(STATE)
#endif
#if HAS_SYNCED_Y_STEPPERS
#define Y_APPLY_DIR(FWD,Q) do{ Y_DIR_WRITE(FWD); Y2_DIR_WRITE(INVERT_DIR(Y2_VS_Y, FWD)); }while(0)
#if ENABLED(Y_DUAL_ENDSTOPS)
#define Y_APPLY_STEP(FWD,Q) DUAL_ENDSTOP_APPLY_STEP(Y,FWD)
#define Y_APPLY_STEP(STATE,Q) DUAL_ENDSTOP_APPLY_STEP(Y,STATE)
#else
#define Y_APPLY_STEP(FWD,Q) do{ Y_STEP_WRITE(FWD); Y2_STEP_WRITE(FWD); }while(0)
#define Y_APPLY_STEP(STATE,Q) do{ Y_STEP_WRITE(STATE); Y2_STEP_WRITE(STATE); }while(0)
#endif
#elif HAS_Y_AXIS
#define Y_APPLY_DIR(FWD,Q) Y_DIR_WRITE(FWD)
#define Y_APPLY_STEP(FWD,Q) Y_STEP_WRITE(FWD)
#define Y_APPLY_STEP(STATE,Q) Y_STEP_WRITE(STATE)
#endif
#if NUM_Z_STEPPERS == 4
@ -447,60 +448,60 @@ xyze_int8_t Stepper::count_direction{0};
Z3_DIR_WRITE(INVERT_DIR(Z3_VS_Z, FWD)); Z4_DIR_WRITE(INVERT_DIR(Z4_VS_Z, FWD)); \
}while(0)
#if ENABLED(Z_MULTI_ENDSTOPS)
#define Z_APPLY_STEP(FWD,Q) QUAD_ENDSTOP_APPLY_STEP(Z,FWD)
#define Z_APPLY_STEP(STATE,Q) QUAD_ENDSTOP_APPLY_STEP(Z,STATE)
#elif ENABLED(Z_STEPPER_AUTO_ALIGN)
#define Z_APPLY_STEP(FWD,Q) QUAD_SEPARATE_APPLY_STEP(Z,FWD)
#define Z_APPLY_STEP(STATE,Q) QUAD_SEPARATE_APPLY_STEP(Z,STATE)
#else
#define Z_APPLY_STEP(FWD,Q) do{ Z_STEP_WRITE(FWD); Z2_STEP_WRITE(FWD); Z3_STEP_WRITE(FWD); Z4_STEP_WRITE(FWD); }while(0)
#define Z_APPLY_STEP(STATE,Q) do{ Z_STEP_WRITE(STATE); Z2_STEP_WRITE(STATE); Z3_STEP_WRITE(STATE); Z4_STEP_WRITE(STATE); }while(0)
#endif
#elif NUM_Z_STEPPERS == 3
#define Z_APPLY_DIR(FWD,Q) do{ \
Z_DIR_WRITE(FWD); Z2_DIR_WRITE(INVERT_DIR(Z2_VS_Z, FWD)); Z3_DIR_WRITE(INVERT_DIR(Z3_VS_Z, FWD)); \
}while(0)
#if ENABLED(Z_MULTI_ENDSTOPS)
#define Z_APPLY_STEP(FWD,Q) TRIPLE_ENDSTOP_APPLY_STEP(Z,FWD)
#define Z_APPLY_STEP(STATE,Q) TRIPLE_ENDSTOP_APPLY_STEP(Z,STATE)
#elif ENABLED(Z_STEPPER_AUTO_ALIGN)
#define Z_APPLY_STEP(FWD,Q) TRIPLE_SEPARATE_APPLY_STEP(Z,FWD)
#define Z_APPLY_STEP(STATE,Q) TRIPLE_SEPARATE_APPLY_STEP(Z,STATE)
#else
#define Z_APPLY_STEP(FWD,Q) do{ Z_STEP_WRITE(FWD); Z2_STEP_WRITE(FWD); Z3_STEP_WRITE(FWD); }while(0)
#define Z_APPLY_STEP(STATE,Q) do{ Z_STEP_WRITE(STATE); Z2_STEP_WRITE(STATE); Z3_STEP_WRITE(STATE); }while(0)
#endif
#elif NUM_Z_STEPPERS == 2
#define Z_APPLY_DIR(FWD,Q) do{ Z_DIR_WRITE(FWD); Z2_DIR_WRITE(INVERT_DIR(Z2_VS_Z, FWD)); }while(0)
#if ENABLED(Z_MULTI_ENDSTOPS)
#define Z_APPLY_STEP(FWD,Q) DUAL_ENDSTOP_APPLY_STEP(Z,FWD)
#define Z_APPLY_STEP(STATE,Q) DUAL_ENDSTOP_APPLY_STEP(Z,STATE)
#elif ENABLED(Z_STEPPER_AUTO_ALIGN)
#define Z_APPLY_STEP(FWD,Q) DUAL_SEPARATE_APPLY_STEP(Z,FWD)
#define Z_APPLY_STEP(STATE,Q) DUAL_SEPARATE_APPLY_STEP(Z,STATE)
#else
#define Z_APPLY_STEP(FWD,Q) do{ Z_STEP_WRITE(FWD); Z2_STEP_WRITE(FWD); }while(0)
#define Z_APPLY_STEP(STATE,Q) do{ Z_STEP_WRITE(STATE); Z2_STEP_WRITE(STATE); }while(0)
#endif
#elif HAS_Z_AXIS
#define Z_APPLY_DIR(FWD,Q) Z_DIR_WRITE(FWD)
#define Z_APPLY_STEP(FWD,Q) Z_STEP_WRITE(FWD)
#define Z_APPLY_STEP(STATE,Q) Z_STEP_WRITE(STATE)
#endif
#if HAS_I_AXIS
#define I_APPLY_DIR(FWD,Q) I_DIR_WRITE(FWD)
#define I_APPLY_STEP(FWD,Q) I_STEP_WRITE(FWD)
#define I_APPLY_STEP(STATE,Q) I_STEP_WRITE(STATE)
#endif
#if HAS_J_AXIS
#define J_APPLY_DIR(FWD,Q) J_DIR_WRITE(FWD)
#define J_APPLY_STEP(FWD,Q) J_STEP_WRITE(FWD)
#define J_APPLY_STEP(STATE,Q) J_STEP_WRITE(STATE)
#endif
#if HAS_K_AXIS
#define K_APPLY_DIR(FWD,Q) K_DIR_WRITE(FWD)
#define K_APPLY_STEP(FWD,Q) K_STEP_WRITE(FWD)
#define K_APPLY_STEP(STATE,Q) K_STEP_WRITE(STATE)
#endif
#if HAS_U_AXIS
#define U_APPLY_DIR(FWD,Q) U_DIR_WRITE(FWD)
#define U_APPLY_STEP(FWD,Q) U_STEP_WRITE(FWD)
#define U_APPLY_STEP(STATE,Q) U_STEP_WRITE(STATE)
#endif
#if HAS_V_AXIS
#define V_APPLY_DIR(FWD,Q) V_DIR_WRITE(FWD)
#define V_APPLY_STEP(FWD,Q) V_STEP_WRITE(FWD)
#define V_APPLY_STEP(STATE,Q) V_STEP_WRITE(STATE)
#endif
#if HAS_W_AXIS
#define W_APPLY_DIR(FWD,Q) W_DIR_WRITE(FWD)
#define W_APPLY_STEP(FWD,Q) W_STEP_WRITE(FWD)
#define W_APPLY_STEP(STATE,Q) W_STEP_WRITE(STATE)
#endif
//#define E0_APPLY_DIR(FWD) do{ (FWD) ? FWD_E_DIR(0) : REV_E_DIR(0); }while(0)
@ -515,8 +516,8 @@ xyze_int8_t Stepper::count_direction{0};
#if ENABLED(MIXING_EXTRUDER)
#define E_APPLY_DIR(FWD,Q) do{ if (FWD) { MIXER_STEPPER_LOOP(j) FWD_E_DIR(j); } else { MIXER_STEPPER_LOOP(j) REV_E_DIR(j); } }while(0)
#else
#define E_APPLY_STEP(FWD,Q) E_STEP_WRITE(stepper_extruder, FWD)
#define E_APPLY_DIR(FWD,Q) do{ if (FWD) { FWD_E_DIR(stepper_extruder); } else { REV_E_DIR(stepper_extruder); } }while(0)
#define E_APPLY_STEP(STATE,Q) E_STEP_WRITE(stepper_extruder, STATE)
#endif
constexpr uint32_t cycles_to_ns(const uint32_t CYC) { return 1000UL * (CYC) / ((F_CPU) / 1000000); }
@ -1497,6 +1498,12 @@ void Stepper::apply_directions() {
*/
HAL_STEP_TIMER_ISR() {
#ifndef __AVR__
// Disable interrupts, to avoid ISR preemption while we reprogram the period
// (AVR enters the ISR with global interrupts disabled, so no need to do it here)
hal.isr_off();
#endif
HAL_timer_isr_prologue(MF_TIMER_STEP);
Stepper::isr();
@ -1514,12 +1521,6 @@ void Stepper::isr() {
static hal_timer_t nextMainISR = 0; // Interval until the next main Stepper Pulse phase (0 = Now)
#ifndef __AVR__
// Disable interrupts, to avoid ISR preemption while we reprogram the period
// (AVR enters the ISR with global interrupts disabled, so no need to do it here)
hal.isr_off();
#endif
// Program timer compare for the maximum period, so it does NOT
// flag an interrupt while this ISR is running - So changes from small
// periods to big periods are respected and the timer does not reset to 0
@ -1541,8 +1542,6 @@ void Stepper::isr() {
// We need this variable here to be able to use it in the following loop
hal_timer_t min_ticks;
do {
// Enable ISRs to reduce USART processing latency
hal.isr_on();
hal_timer_t interval = 0;
@ -1558,6 +1557,10 @@ void Stepper::isr() {
ftMotion_nextAuxISR = (STEPPER_TIMER_RATE) / 400;
}
}
// Enable ISRs to reduce latency for higher priority ISRs, or all ISRs if no prioritization.
hal.isr_on();
interval = _MIN(nextMainISR, ftMotion_nextAuxISR);
nextMainISR -= interval;
ftMotion_nextAuxISR -= interval;
@ -1585,6 +1588,9 @@ void Stepper::isr() {
if (is_babystep) nextBabystepISR = babystepping_isr();
#endif
// Enable ISRs to reduce latency for higher priority ISRs, or all ISRs if no prioritization.
hal.isr_on();
// ^== Time critical. NOTHING besides pulse generation should be above here!!!
if (!nextMainISR) nextMainISR = block_phase_isr(); // Manage acc/deceleration, get next block
@ -1780,7 +1786,7 @@ void Stepper::pulse_phase_isr() {
do {
AxisFlags step_needed{0};
#define _APPLY_STEP(AXIS, INV, ALWAYS) AXIS ##_APPLY_STEP(INV, ALWAYS)
#define _APPLY_STEP(AXIS, STATE, ALWAYS) AXIS ##_APPLY_STEP(STATE, ALWAYS)
#define _STEP_STATE(AXIS) STEP_STATE_## AXIS
// Determine if a pulse is needed using Bresenham

View file

@ -56,6 +56,7 @@ enum StealthIndex : uint8_t {
#else
#define TMC_UART_HW_DEFINE(IC, ST, L, AI) TMCMarlin<IC##Stepper, L, AI> stepper##ST(&ST##_HARDWARE_SERIAL, float(ST##_RSENSE), ST##_SLAVE_ADDRESS)
#endif
#define TMC_UART_SW_DEFINE(IC, ST, L, AI) TMCMarlin<IC##Stepper, L, AI> stepper##ST(ST##_SERIAL_RX_PIN, ST##_SERIAL_TX_PIN, float(ST##_RSENSE), ST##_SLAVE_ADDRESS)
#define _TMC_SPI_DEFINE(IC, ST, AI) __TMC_SPI_DEFINE(IC, ST, TMC_##ST##_LABEL, AI)
@ -292,7 +293,7 @@ enum StealthIndex : uint8_t {
//
// TMC2208/2209 Driver objects and inits
//
#if HAS_TMC220x
#if HAS_TMC_UART
#if AXIS_HAS_UART(X)
#ifdef X_HARDWARE_SERIAL
TMC_UART_DEFINE(HW, X, X);

View file

@ -108,7 +108,7 @@
#define CHOPPER_TIMING_E CHOPPER_TIMING
#endif
#if HAS_TMC220x
#if HAS_TMC_UART
void tmc_serial_begin();
#endif

Some files were not shown because too many files have changed in this diff Show more