Merge branch 'bugfix-2.1.x' into pr/25901

This commit is contained in:
Scott Lahteine 2025-11-08 17:11:49 -06:00
commit c6437024bd
328 changed files with 6536 additions and 3438 deletions

View file

@ -58,7 +58,7 @@ jobs:
- at90usb1286_dfu
# AVR Extended
- FYSETC_F6
- mega2560ext
- melzi_optiboot
- rambo
- sanguino1284p

0
.gitignore vendored Executable file → Normal file
View file

View file

@ -4,6 +4,31 @@ CONTAINER_RT_OPTS := --rm -v $(PWD):/code -v platformio-cache:/root/.platformio
CONTAINER_IMAGE := marlin-dev
UNIT_TEST_CONFIG ?= default
# Find a Python 3 interpreter
ifeq ($(OS),Windows_NT)
# Windows: use `where` fall back through the three common names
PYTHON := $(shell which python 2>nul || which python3 2>nul || which py 2>nul)
# Windows: Use cmd tools to find pins files
PINS_RAW := $(shell cmd //c "dir /s /b Marlin\src\pins\*.h 2>nul | findstr /r ".*Marlin\\\\src\\\\pins\\\\.*\\\\pins_.*\.h"")
PINS := $(subst \,/,$(PINS_RAW))
else
# POSIX: use `command -v` prefer python3 over python
PYTHON := $(shell command -v python3 2>/dev/null || command -v python 2>/dev/null)
# Unix/Linux: Use find command
PINS := $(shell find Marlin/src/pins -mindepth 2 -name 'pins_*.h')
endif
# Check that the found interpreter is Python 3
# Error if there's no Python 3 available
ifneq ($(strip $(PYTHON)),)
PYTHON_VERSION := $(shell $(PYTHON) -c "import sys; print(sys.version_info[0])" 2>/dev/null)
ifneq ($(PYTHON_VERSION),3)
$(error $(PYTHON) is not Python 3 install a Python3.x interpreter or adjust your PATH)
endif
else
$(error No Python executable found install Python 3.x and make sure it is in your PATH)
endif
help:
@echo "Tasks for local development:"
@echo "make marlin : Build Marlin for the configured board"
@ -20,7 +45,7 @@ help:
@echo "make unit-test-single-local-docker : Run unit tests for a single config locally, using docker"
@echo "make unit-test-all-local : Run all code tests locally"
@echo "make unit-test-all-local-docker : Run all code tests locally, using docker"
@echo "make setup-local-docker : Setup local docker using buildx"
@echo "make setup-local-docker : Setup local docker"
@echo ""
@echo "Options for testing:"
@echo " TEST_TARGET Set when running tests-single-*, to select the"
@ -41,6 +66,9 @@ marlin:
./buildroot/bin/mftest -a
.PHONY: marlin
clean:
rm -rf .pio/build*
tests-single-ci:
export GIT_RESET_HARD=true
$(MAKE) tests-single-local TEST_TARGET=$(TEST_TARGET) PLATFORMIO_BUILD_FLAGS=-DGITHUB_ACTION
@ -57,10 +85,10 @@ tests-single-local-docker:
$(CONTAINER_RT_BIN) run $(CONTAINER_RT_OPTS) $(CONTAINER_IMAGE) make tests-single-local TEST_TARGET=$(TEST_TARGET) VERBOSE_PLATFORMIO=$(VERBOSE_PLATFORMIO) GIT_RESET_HARD=$(GIT_RESET_HARD) ONLY_TEST="$(ONLY_TEST)"
tests-all-local:
@python -c "import yaml" 2>/dev/null || (echo 'pyyaml module is not installed. Install it with "python -m pip install pyyaml"' && exit 1)
@$(PYTHON) -c "import yaml" 2>/dev/null || (echo 'pyyaml module is not installed. Install it with "$(PYTHON) -m pip install pyyaml"' && exit 1)
export PATH="./buildroot/bin/:./buildroot/tests/:${PATH}" \
&& export VERBOSE_PLATFORMIO=$(VERBOSE_PLATFORMIO) \
&& for TEST_TARGET in $$(python $(SCRIPTS_DIR)/get_test_targets.py) ; do \
&& for TEST_TARGET in $$($(PYTHON) $(SCRIPTS_DIR)/get_test_targets.py) ; do \
if [ "$$TEST_TARGET" = "linux_native" ] && [ "$$(uname)" = "Darwin" ]; then \
echo "Skipping tests for $$TEST_TARGET on macOS" ; \
continue ; \
@ -88,18 +116,36 @@ unit-test-all-local-docker:
@if ! $(CONTAINER_RT_BIN) images -q $(CONTAINER_IMAGE) > /dev/null ; then $(MAKE) setup-local-docker ; fi
$(CONTAINER_RT_BIN) run $(CONTAINER_RT_OPTS) $(CONTAINER_IMAGE) make unit-test-all-local
setup-local-docker:
$(CONTAINER_RT_BIN) buildx build -t $(CONTAINER_IMAGE) -f docker/Dockerfile .
USERNAME := $(shell whoami)
USER_ID := $(shell id -u)
GROUP_ID := $(shell id -g)
PINS := $(shell find Marlin/src/pins -mindepth 2 -name '*.h')
.PHONY: setup-local-docker setup-local-docker-old
setup-local-docker:
@echo "Building marlin-dev Docker image..."
$(CONTAINER_RT_BIN) build -t $(CONTAINER_IMAGE) \
--build-arg USERNAME=$(USERNAME) \
--build-arg USER_ID=$(USER_ID) \
--build-arg GROUP_ID=$(GROUP_ID) \
-f docker/Dockerfile .
@echo
@echo "To run all tests in Docker:"
@echo " make tests-all-local-docker"
@echo "To run a single test in Docker:"
@echo " make tests-single-local-docker TEST_TARGET=mega2560"
setup-local-docker-old:
$(CONTAINER_RT_BIN) buildx build -t $(CONTAINER_IMAGE) -f docker/Dockerfile .
.PHONY: $(PINS) format-pins validate-pins
$(PINS): %:
@echo "Formatting pins $@"
@python $(SCRIPTS_DIR)/pinsformat.py $< $@
@$(PYTHON) $(SCRIPTS_DIR)/pinsformat.py $< $@
format-pins: $(PINS)
@echo "Processed $(words $(PINS)) pins files"
validate-pins: format-pins
@echo "Validating pins files"
@ -109,8 +155,8 @@ validate-pins: format-pins
format-lines:
@echo "Formatting all sources"
@python $(SCRIPTS_DIR)/linesformat.py buildroot
@python $(SCRIPTS_DIR)/linesformat.py Marlin
@$(PYTHON) $(SCRIPTS_DIR)/linesformat.py buildroot
@$(PYTHON) $(SCRIPTS_DIR)/linesformat.py Marlin
validate-lines:
@echo "Validating text formatting"
@ -122,4 +168,4 @@ BOARDS_FILE := Marlin/src/core/boards.h
validate-boards:
@echo "Validating boards.h file"
@python $(SCRIPTS_DIR)/validate_boards.py $(BOARDS_FILE) || (echo "\nError: boards.h file is not valid. Please check and correct it.\n" && exit 1)
@$(PYTHON) $(SCRIPTS_DIR)/validate_boards.py $(BOARDS_FILE) || (echo "\nError: boards.h file is not valid. Please check and correct it.\n" && exit 1)

View file

@ -942,7 +942,7 @@
* protect against a broken or disconnected thermistor wire.
*
* The issue: If a thermistor falls out, it will report the much lower
* temperature of the air in the room, and the the firmware will keep
* temperature of the air in the room, and the firmware will keep
* the heater on.
*
* If you get "Thermal Runaway" or "Heating failed" errors the
@ -1395,6 +1395,11 @@
* See https://github.com/synthetos/TinyG/wiki/Jerk-Controlled-Motion-Explained
*/
//#define S_CURVE_ACCELERATION
#if ENABLED(S_CURVE_ACCELERATION)
// Define to use 4th instead of 6th order motion curve
//#define S_CURVE_FACTOR 0.25 // Initial and final acceleration factor, ideally 0.1 to 0.4.
// Shouldn't generally require tuning.
#endif
//===========================================================================
//============================= Z Probe Options =============================
@ -1667,6 +1672,8 @@
//#define PROBE_TOOLCHANGE_NO_MOVE // Suppress motion on probe tool-change
#endif
//#define PROBE_WAKEUP_TIME_MS 30 // (ms) Time for the probe to wake up
// Most probes should stay away from the edges of the bed, but
// with NOZZLE_AS_PROBE this can be negative for a wider probing area.
#define PROBING_MARGIN 10
@ -3468,6 +3475,7 @@
* NOTOSANS - Default font with anti-aliasing. Supports Latin Extended and non-Latin characters.
* UNIFONT - Lightweight font, no anti-aliasing. Supports Latin Extended and non-Latin characters.
* HELVETICA - Lightweight font, no anti-aliasing. Supports Basic Latin (0x0020-0x007F) and Latin-1 Supplement (0x0080-0x00FF) characters only.
* :['NOTOSANS', 'UNIFONT', 'HELVETICA']
*/
#define TFT_FONT NOTOSANS
@ -3477,6 +3485,7 @@
* BLUE_MARLIN - Default theme with 'midnight blue' background
* BLACK_MARLIN - Theme with 'black' background
* ANET_BLACK - Theme used for Anet ET4/5
* :['BLUE_MARLIN', 'BLACK_MARLIN', 'ANET_BLACK']
*/
#define TFT_THEME BLACK_MARLIN

View file

@ -297,7 +297,7 @@
* protect against a broken or disconnected thermistor wire.
*
* The issue: If a thermistor falls out, it will report the much lower
* temperature of the air in the room, and the the firmware will keep
* temperature of the air in the room, and the firmware will keep
* the heater on.
*
* The solution: Once the temperature reaches the target, start observing.
@ -778,7 +778,7 @@
// @section endstops
// If you want endstops to stay on (by default) even when not homing
// If you want endstops to stay on (by default) even when not homing,
// enable this option. Override at any time with M120, M121.
//#define ENDSTOPS_ALWAYS_ON_DEFAULT
@ -1143,67 +1143,72 @@
/**
* Fixed-time-based Motion Control -- BETA FEATURE
* Enable/disable and set parameters with G-code M493.
* Enable/disable and set parameters with G-code M493 and M494.
* See ft_types.h for named values used by FTM options.
*/
//#define FT_MOTION
#if ENABLED(FT_MOTION)
//#define FTM_IS_DEFAULT_MOTION // Use FT Motion as the factory default?
//#define FTM_IS_DEFAULT_MOTION // Use FT Motion as the factory default?
//#define FT_MOTION_MENU // Provide a MarlinUI menu to set M493 and M494 parameters
//#define FTM_HOME_AND_PROBE // Use FT Motion for homing / probing. Disable if FT Motion breaks these functions.
#define FTM_DEFAULT_DYNFREQ_MODE dynFreqMode_DISABLED // Default mode of dynamic frequency calculation. (DISABLED, Z_BASED, MASS_BASED)
#define FTM_LINEAR_ADV_DEFAULT_ENA false // Default linear advance enable (true) or disable (false)
#define FTM_LINEAR_ADV_DEFAULT_K 0.0f // Default linear advance gain. (Acceleration-based scaling factor.)
#define FTM_DEFAULT_SHAPER_X ftMotionShaper_NONE // Default shaper mode on X axis (NONE, ZV, ZVD, ZVDD, ZVDDD, EI, 2HEI, 3HEI, MZV)
#define FTM_SHAPING_DEFAULT_FREQ_X 37.0f // (Hz) Default peak frequency used by input shapers
#define FTM_SHAPING_ZETA_X 0.1f // Zeta used by input shapers for X axis
#define FTM_SHAPING_V_TOL_X 0.05f // Vibration tolerance used by EI input shapers for X axis
#define FTM_SHAPING_DEFAULT_FREQ_X 37.0f // (Hz) Default peak frequency used by input shapers
#define FTM_SHAPING_ZETA_X 0.1f // Zeta used by input shapers for X axis
#define FTM_SHAPING_V_TOL_X 0.05f // Vibration tolerance used by EI input shapers for X axis
#define FTM_DEFAULT_SHAPER_Y ftMotionShaper_NONE // Default shaper mode on Y axis
#define FTM_SHAPING_DEFAULT_FREQ_Y 37.0f // (Hz) Default peak frequency used by input shapers
#define FTM_SHAPING_ZETA_Y 0.1f // Zeta used by input shapers for Y axis
#define FTM_SHAPING_V_TOL_Y 0.05f // Vibration tolerance used by EI input shapers for Y axis
#define FTM_SHAPING_DEFAULT_FREQ_Y 37.0f // (Hz) Default peak frequency used by input shapers
#define FTM_SHAPING_ZETA_Y 0.1f // Zeta used by input shapers for Y axis
#define FTM_SHAPING_V_TOL_Y 0.05f // Vibration tolerance used by EI input shapers for Y axis
//#define FT_MOTION_MENU // Provide a MarlinUI menu to set M493 parameters
//#define FTM_SHAPER_Z // Include Z shaping support
#define FTM_DEFAULT_SHAPER_Z ftMotionShaper_NONE // Default shaper mode on Z axis
#define FTM_SHAPING_DEFAULT_FREQ_Z 21.0f // (Hz) Default peak frequency used by input shapers
#define FTM_SHAPING_ZETA_Z 0.03f // Zeta used by input shapers for Z axis
#define FTM_SHAPING_V_TOL_Z 0.05f // Vibration tolerance used by EI input shapers for Z axis
//#define FTM_SHAPER_E // Include E shaping support
// Required to synchronize extruder with XYZ (better quality)
#define FTM_DEFAULT_SHAPER_E ftMotionShaper_NONE // Default shaper mode on Extruder axis
#define FTM_SHAPING_DEFAULT_FREQ_E 21.0f // (Hz) Default peak frequency used by input shapers
#define FTM_SHAPING_ZETA_E 0.03f // Zeta used by input shapers for E axis
#define FTM_SHAPING_V_TOL_E 0.05f // Vibration tolerance used by EI input shapers for E axis
//#define FTM_RESONANCE_TEST // Sine sweep motion for resonance study
//#define FTM_SMOOTHING // Smoothing can reduce artifacts and make steppers quieter
// on sharp corners, but too much will round corners.
#if ENABLED(FTM_SMOOTHING)
#define FTM_MAX_SMOOTHING_TIME 0.10f // (s) Maximum smoothing time. Higher values consume more RAM.
// Increase smoothing time to reduce jerky motion, ghosting and noises.
#define FTM_SMOOTHING_TIME_X 0.00f // (s) Smoothing time for X axis. Zero means disabled.
#define FTM_SMOOTHING_TIME_Y 0.00f // (s) Smoothing time for Y axis
#define FTM_SMOOTHING_TIME_Z 0.00f // (s) Smoothing time for Z axis
#define FTM_SMOOTHING_TIME_E 0.02f // (s) Smoothing time for E axis. Prevents noise/skipping from LA by
// smoothing acceleration peaks, which may also smooth curved surfaces.
#endif
#define FTM_TRAJECTORY_TYPE TRAPEZOIDAL // Block acceleration profile (TRAPEZOIDAL, POLY5, POLY6)
// TRAPEZOIDAL: Continuous Velocity. Max acceleration is respected.
// POLY5: Like POLY6 with 1.5x but uses less CPU.
// POLY6: Continuous Acceleration (aka S_CURVE).
// POLY trajectories not only reduce resonances without rounding corners, but also
// reduce extruder strain due to linear advance.
#define FTM_POLY6_ACCELERATION_OVERSHOOT 1.875f // Max acceleration overshoot factor for POLY6 (1.25 to 1.875)
/**
* Advanced configuration
*/
#define FTM_UNIFIED_BWS // DON'T DISABLE unless you use Ulendo FBS (not implemented)
#if ENABLED(FTM_UNIFIED_BWS)
#define FTM_BW_SIZE 100 // Unified Window and Batch size with a ratio of 2
#else
#define FTM_WINDOW_SIZE 200 // Custom Window size for trajectory generation needed by Ulendo FBS
#define FTM_BATCH_SIZE 100 // Custom Batch size for trajectory generation needed by Ulendo FBS
#endif
#define FTM_BUFFER_SIZE 128 // Window size for trajectory generation, must be a power of 2 (e.g 64, 128, 256, ...)
// The total buffered time in seconds is (FTM_BUFFER_SIZE/FTM_FS)
#define FTM_FS 1000 // (Hz) Frequency for trajectory generation.
#define FTM_STEPPER_FS 2'000'000 // (Hz) Time resolution of stepper I/O update. Shouldn't affect CPU much (slower board testing needed)
#define FTM_MIN_SHAPE_FREQ 20 // (Hz) Minimum shaping frequency, lower consumes more RAM
#define FTM_FS 1000 // (Hz) Frequency for trajectory generation. (Reciprocal of FTM_TS)
#define FTM_TS 0.001f // (s) Time step for trajectory generation. (Reciprocal of FTM_FS)
#if DISABLED(COREXY)
#define FTM_STEPPER_FS 20000 // (Hz) Frequency for stepper I/O update
// Use this to adjust the time required to consume the command buffer.
// Try increasing this value if stepper motion is choppy.
#define FTM_STEPPERCMD_BUFF_SIZE 3000 // Size of the stepper command buffers
#else
// CoreXY motion needs a larger buffer size. These values are based on our testing.
#define FTM_STEPPER_FS 30000
#define FTM_STEPPERCMD_BUFF_SIZE 6000
#endif
#define FTM_STEPS_PER_UNIT_TIME (FTM_STEPPER_FS / FTM_FS) // Interpolated stepper commands per unit time
#define FTM_MIN_TICKS ((STEPPER_TIMER_RATE) / (FTM_STEPPER_FS)) // Minimum stepper ticks between steps
#define FTM_MIN_SHAPE_FREQ 10 // Minimum shaping frequency
#define FTM_RATIO (FTM_FS / FTM_MIN_SHAPE_FREQ) // Factor for use in FTM_ZMAX. DON'T CHANGE.
#define FTM_ZMAX (FTM_RATIO * 2) // Maximum delays for shaping functions (even numbers only!)
// Calculate as:
// ZV : FTM_RATIO / 2
// ZVD, MZV : FTM_RATIO
// 2HEI : FTM_RATIO * 3 / 2
// 3HEI : FTM_RATIO * 2
#endif // FT_MOTION
/**
@ -1853,6 +1858,7 @@
#define SDSORT_DYNAMIC_RAM false // Use dynamic allocation (within SD menus). Least expensive option. Set SDSORT_LIMIT before use!
#define SDSORT_CACHE_VFATS 2 // Maximum number of 13-byte VFAT entries to use for sorting.
// Note: Only affects SCROLL_LONG_FILENAMES with SDSORT_CACHE_NAMES but not SDSORT_DYNAMIC_RAM.
#define SDSORT_QUICK true // Use Quick Sort as a sorting algorithm. Otherwise use Bubble Sort.
#endif
// Allow international symbols in long filenames. To display correctly, the
@ -2363,13 +2369,17 @@
* See https://marlinfw.org/docs/features/lin_advance.html for full instructions.
*/
//#define LIN_ADVANCE
#if ENABLED(LIN_ADVANCE)
#if ANY(LIN_ADVANCE, FT_MOTION)
#if ENABLED(DISTINCT_E_FACTORS)
#define ADVANCE_K { 0.22 } // (mm) Compression length per 1mm/s extruder speed, per extruder
#define ADVANCE_K { 0.22 } // (mm) Compression length per 1mm/s extruder speed, per extruder. Override with 'M900 T<tool> K<mm>'.
#else
#define ADVANCE_K 0.22 // (mm) Compression length applying to all extruders
#define ADVANCE_K 0.22 // (mm) Compression length for all extruders. Override with 'M900 K<mm>'.
#endif
//#define ADVANCE_K_EXTRA // Add a second linear advance constant, configurable with M900 L.
//#define ADVANCE_K_EXTRA // Add a second linear advance constant, configurable with 'M900 L'.
#endif
#if ENABLED(LIN_ADVANCE)
//#define LA_DEBUG // Print debug information to serial during operation. Disable for production use.
//#define EXPERIMENTAL_I2S_LA // Allow I2S_STEPPER_STREAM to be used with LA. Performance degrades as the LA step rate reaches ~20kHz.
@ -4261,7 +4271,7 @@
//#define I2CPE_ENC_1_TICKS_REV (16 * 200) // Only needed for rotary encoders; number of stepper
// steps per full revolution (motor steps/rev * microstepping)
//#define I2CPE_ENC_1_INVERT // Invert the direction of axis travel.
#define I2CPE_ENC_1_EC_METHOD I2CPE_ECM_MICROSTEP // Type of error error correction.
#define I2CPE_ENC_1_EC_METHOD I2CPE_ECM_MICROSTEP // Type of error correction.
#define I2CPE_ENC_1_EC_THRESH 0.10 // Threshold size for error (in mm) above which the
// printer will attempt to correct the error; errors
// smaller than this are ignored to minimize effects of
@ -4693,6 +4703,11 @@
//
//#define PINS_DEBUGGING
//
// M265 - I2C Scanner
//
//#define I2C_SCANNER
// Enable Tests that will run at startup and produce a report
//#define MARLIN_TEST_BUILD

View file

@ -188,15 +188,15 @@ else ifeq ($(HARDWARE_MOTHERBOARD),1033)
else ifeq ($(HARDWARE_MOTHERBOARD),1034)
# RAMPS 1.6+ (Power outputs: Hotend, Fan, Bed)
else ifeq ($(HARDWARE_MOTHERBOARD),1035)
else ifeq ($(HARDWARE_MOTHERBOARD),1040)
# RAMPS 1.6+ (Power outputs: Hotend0, Hotend1, Bed)
else ifeq ($(HARDWARE_MOTHERBOARD),1036)
else ifeq ($(HARDWARE_MOTHERBOARD),1041)
# RAMPS 1.6+ (Power outputs: Hotend, Fan0, Fan1)
else ifeq ($(HARDWARE_MOTHERBOARD),1037)
else ifeq ($(HARDWARE_MOTHERBOARD),1042)
# RAMPS 1.6+ (Power outputs: Hotend0, Hotend1, Fan)
else ifeq ($(HARDWARE_MOTHERBOARD),1038)
else ifeq ($(HARDWARE_MOTHERBOARD),1043)
# RAMPS 1.6+ (Power outputs: Spindle, Controller Fan)
else ifeq ($(HARDWARE_MOTHERBOARD),1039)
else ifeq ($(HARDWARE_MOTHERBOARD),1044)
#
# RAMPS Derivatives - ATmega1280, ATmega2560
@ -286,60 +286,62 @@ else ifeq ($(HARDWARE_MOTHERBOARD),1138)
else ifeq ($(HARDWARE_MOTHERBOARD),1139)
# Creality: CR10S, CR20, CR-X
else ifeq ($(HARDWARE_MOTHERBOARD),1140)
# Dagoma F5
# Creality CR-10 V2, CR-10 V3
else ifeq ($(HARDWARE_MOTHERBOARD),1141)
# Dagoma D6 (as found in the Dagoma DiscoUltimate V2 TMC)
# Dagoma F5
else ifeq ($(HARDWARE_MOTHERBOARD),1142)
# FYSETC F6 1.3
# Dagoma D6 (as found in the Dagoma DiscoUltimate V2 TMC)
else ifeq ($(HARDWARE_MOTHERBOARD),1143)
# FYSETC F6 1.4
# FYSETC F6 1.3
else ifeq ($(HARDWARE_MOTHERBOARD),1144)
# Wanhao Duplicator i3 Plus
# FYSETC F6 1.4
else ifeq ($(HARDWARE_MOTHERBOARD),1145)
# VORON Design
# Wanhao Duplicator i3 Plus
else ifeq ($(HARDWARE_MOTHERBOARD),1146)
# Tronxy TRONXY-V3-1.0
# VORON Design
else ifeq ($(HARDWARE_MOTHERBOARD),1147)
# Z-Bolt X Series
# Tronxy TRONXY-V3-1.0
else ifeq ($(HARDWARE_MOTHERBOARD),1148)
# TT OSCAR
# Z-Bolt X Series
else ifeq ($(HARDWARE_MOTHERBOARD),1149)
# BIQU Tango V1
# TT OSCAR
else ifeq ($(HARDWARE_MOTHERBOARD),1150)
# MKS GEN L V2
# BIQU Tango V1
else ifeq ($(HARDWARE_MOTHERBOARD),1151)
# MKS GEN L V2.1
# MKS GEN L V2
else ifeq ($(HARDWARE_MOTHERBOARD),1152)
# Copymaster 3D
# MKS GEN L V2.1
else ifeq ($(HARDWARE_MOTHERBOARD),1153)
# Ortur 4
# Copymaster 3D
else ifeq ($(HARDWARE_MOTHERBOARD),1154)
# Tenlog D3 Hero IDEX printer
# Ortur 4
else ifeq ($(HARDWARE_MOTHERBOARD),1155)
# Tenlog D3, D5, D6 IDEX Printer
# Tenlog D3 Hero IDEX printer
else ifeq ($(HARDWARE_MOTHERBOARD),1156)
# Ramps S 1.2 by Sakul.cz (Power outputs: Hotend0, Hotend1, Fan, Bed)
# Tenlog D3, D5, D6 IDEX Printer
else ifeq ($(HARDWARE_MOTHERBOARD),1157)
# Ramps S 1.2 by Sakul.cz (Power outputs: Hotend0, Hotend1, Hotend2, Bed)
# Ramps S 1.2 by Sakul.cz (Power outputs: Hotend0, Hotend1, Fan, Bed)
else ifeq ($(HARDWARE_MOTHERBOARD),1158)
# Ramps S 1.2 by Sakul.cz (Power outputs: Hotend, Fan0, Fan1, Bed)
# Ramps S 1.2 by Sakul.cz (Power outputs: Hotend0, Hotend1, Hotend2, Bed)
else ifeq ($(HARDWARE_MOTHERBOARD),1159)
# Longer LK1 PRO / Alfawise U20 Pro (PRO version)
# Ramps S 1.2 by Sakul.cz (Power outputs: Hotend, Fan0, Fan1, Bed)
else ifeq ($(HARDWARE_MOTHERBOARD),1160)
# Longer LKx PRO / Alfawise Uxx Pro (PRO version)
# Longer LK1 PRO / Alfawise U20 Pro (PRO version)
else ifeq ($(HARDWARE_MOTHERBOARD),1161)
# Pxmalion Core I3
# Longer LKx PRO / Alfawise Uxx Pro (PRO version)
else ifeq ($(HARDWARE_MOTHERBOARD),1162)
# Panowin Cutlass (as found in the Panowin F1)
# Pxmalion Core I3
else ifeq ($(HARDWARE_MOTHERBOARD),1163)
# Kodama Bardo V1.x (as found in the Kodama Trinus)
# Panowin Cutlass (as found in the Panowin F1)
else ifeq ($(HARDWARE_MOTHERBOARD),1164)
# XTLW MFF V1.0
# Kodama Bardo V1.x (as found in the Kodama Trinus)
else ifeq ($(HARDWARE_MOTHERBOARD),1165)
# XTLW MFF V2.0
# XTLW MFF V1.0
else ifeq ($(HARDWARE_MOTHERBOARD),1166)
# E3D Rumba BigBox
# XTLW MFF V2.0
else ifeq ($(HARDWARE_MOTHERBOARD),1167)
# E3D Rumba BigBox
else ifeq ($(HARDWARE_MOTHERBOARD),1168)
#
# RAMBo and derivatives
@ -408,32 +410,34 @@ else ifeq ($(HARDWARE_MOTHERBOARD),1319)
else ifeq ($(HARDWARE_MOTHERBOARD),1320)
# Geeetech GT2560 Rev B for A20(M/T/D)
else ifeq ($(HARDWARE_MOTHERBOARD),1321)
# Einstart retrofit
else ifeq ($(HARDWARE_MOTHERBOARD),1322)
# Wanhao 0ne+ i3 Mini
else ifeq ($(HARDWARE_MOTHERBOARD),1323)
# Overlord/Overlord Pro
else ifeq ($(HARDWARE_MOTHERBOARD),1324)
# ADIMLab Gantry v1
else ifeq ($(HARDWARE_MOTHERBOARD),1325)
# ADIMLab Gantry v2
else ifeq ($(HARDWARE_MOTHERBOARD),1326)
# Leapfrog Xeed 2015
else ifeq ($(HARDWARE_MOTHERBOARD),1327)
# PICA Shield (original version)
else ifeq ($(HARDWARE_MOTHERBOARD),1328)
# PICA Shield (rev C or later)
else ifeq ($(HARDWARE_MOTHERBOARD),1329)
# Intamsys 4.0 (Funmat HT)
else ifeq ($(HARDWARE_MOTHERBOARD),1330)
# Malyan M180 Mainboard Version 2 (no display function, direct G-code only)
else ifeq ($(HARDWARE_MOTHERBOARD),1331)
# Mega controller & Protoneer CNC Shield V3.00
else ifeq ($(HARDWARE_MOTHERBOARD),1332)
# WEEDO 62A board (TINA2, Monoprice Cadet, etc.)
else ifeq ($(HARDWARE_MOTHERBOARD),1333)
# Geeetech GT2560 V4.1B for A10(M/T/D)
else ifeq ($(HARDWARE_MOTHERBOARD),1322)
# Einstart retrofit
else ifeq ($(HARDWARE_MOTHERBOARD),1323)
# Wanhao 0ne+ i3 Mini
else ifeq ($(HARDWARE_MOTHERBOARD),1324)
# Wanhao D9 MK2
else ifeq ($(HARDWARE_MOTHERBOARD),1325)
# Overlord/Overlord Pro
else ifeq ($(HARDWARE_MOTHERBOARD),1326)
# ADIMLab Gantry v1
else ifeq ($(HARDWARE_MOTHERBOARD),1327)
# ADIMLab Gantry v2
else ifeq ($(HARDWARE_MOTHERBOARD),1328)
# Leapfrog Xeed 2015
else ifeq ($(HARDWARE_MOTHERBOARD),1329)
# PICA Shield (original version)
else ifeq ($(HARDWARE_MOTHERBOARD),1330)
# PICA Shield (rev C or later)
else ifeq ($(HARDWARE_MOTHERBOARD),1331)
# Intamsys 4.0 (Funmat HT)
else ifeq ($(HARDWARE_MOTHERBOARD),1332)
# Malyan M180 Mainboard Version 2
else ifeq ($(HARDWARE_MOTHERBOARD),1333)
# Mega controller & Protoneer CNC Shield V3.00
else ifeq ($(HARDWARE_MOTHERBOARD),1334)
# WEEDO 62A board (TINA2, Monoprice Cadet, etc.)
else ifeq ($(HARDWARE_MOTHERBOARD),1335)
#
# ATmega1281, ATmega2561
@ -513,7 +517,7 @@ else ifeq ($(HARDWARE_MOTHERBOARD),1511)
MCU ?= atmega1284p
PROG_MCU ?= m1284p
# ZoneStar ZMIB V2
else ifeq ($(HARDWARE_MOTHERBOARD),1511)
else ifeq ($(HARDWARE_MOTHERBOARD),1512)
HARDWARE_VARIANT ?= Sanguino
MCU ?= atmega1284p
PROG_MCU ?= m1284p
@ -627,6 +631,10 @@ else ifeq ($(HARDWARE_MOTHERBOARD),1707)
MCU ?= at90usb1286
PROG_MCU ?= usb1286
#
# SAM3X8E ARM Cortex-M3
#
# UltiMachine Archim1 (with DRV8825 drivers)
else ifeq ($(HARDWARE_MOTHERBOARD),3023)
HARDWARE_VARIANT ?= archim

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 "2025-09-26"
//#define STRING_DISTRIBUTION_DATE "2025-11-08"
/**
* The protocol for communication to the host. Protocol indicates communication

View file

@ -86,13 +86,14 @@ heater_0_maxtemp = 275
pidtemp = on
pid_k1 = 0.95
pid_max = 255
pid_functional_range = 10
pid_functional_range = 20
default_kp = 22.20
default_ki = 1.08
default_kd = 114.00
temp_sensor_bed = 1
bed_check_interval = 5000
bed_mintemp = 5
bed_maxtemp = 150
@ -163,18 +164,28 @@ min_steps_per_segment = 6
default_minsegmenttime = 20000
[config:basic]
hotend_overshoot = 15
bed_overshoot = 10
max_bed_power = 255
busy_while_heating = on
host_keepalive_feature = on
default_keepalive_interval = 2
printjob_timer_autostart = on
jd_handle_small_segments = on
validate_homing_endstops = on
editable_steps_per_unit = on
eeprom_boot_silent = on
eeprom_chitchat = on
endstoppullups = on
extrude_maxlength = 200
prevent_cold_extrusion = on
extrude_mintemp = 170
host_keepalive_feature = on
hotend_overshoot = 15
jd_handle_small_segments = on
max_bed_power = 255
prevent_lengthy_extrude = on
extrude_maxlength = 200
min_software_endstops = on
max_software_endstops = on
@ -195,21 +206,19 @@ 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
temp_bed_hysteresis = 3
temp_bed_residency_time = 10
temp_bed_window = 1
temp_residency_time = 10
temp_window = 1
validate_homing_endstops = on
editable_steps_per_unit = on
[config:advanced]
arc_support = on
min_arc_segment_mm = 0.1
max_arc_segment_mm = 1.0
min_circle_segments = 72
n_arc_correction = 25
auto_report_temperatures = on
autotemp = on
@ -223,22 +232,23 @@ disable_idle_x = on
disable_idle_y = on
disable_idle_z = on
disable_idle_e = on
e0_auto_fan_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
min_circle_segments = 72
n_arc_correction = 25
serial_overrun_protection = on
slowdown = on
slowdown_divisor = 2
tx_buffer_size = 0
multistepping_limit = 16
bed_check_interval = 5000
watch_bed_temp_increase = 2
watch_bed_temp_period = 60
serial_overrun_protection = on
tx_buffer_size = 0
watch_temp_increase = 2
watch_temp_period = 40
watch_bed_temp_increase = 2
watch_bed_temp_period = 60

View file

@ -254,7 +254,7 @@ uint16_t set_pwm_frequency_hz(const float hz, const float dca, const float dcb,
else { prescaler = 1; SET_CS(5, PRESCALER_1); }
count /= float(prescaler);
const float pwm_top = round(count); // Get the rounded count
const float pwm_top = roundf(count); // Get the rounded count
ICR5 = (uint16_t)pwm_top - 1; // Subtract 1 for TOP
OCR5A = pwm_top * ABS(dca); // Update and scale DCs
@ -280,7 +280,7 @@ uint16_t set_pwm_frequency_hz(const float hz, const float dca, const float dcb,
SET_CS(5, PRESCALER_64); // 16MHz / 64 = 250kHz
OCR5A = OCR5B = OCR5C = 0;
}
return round(count);
return roundf(count);
}
#endif

View file

@ -95,7 +95,7 @@
/**
* The Trinamic library includes SoftwareSerial.h, leading to a compile error.
*/
#if ALL(HAS_TRINAMIC_CONFIG, ENDSTOP_INTERRUPTS_FEATURE)
#if ALL(HAS_TMC_SW_SERIAL, ENDSTOP_INTERRUPTS_FEATURE)
#error "TMCStepper includes SoftwareSerial.h which is incompatible with ENDSTOP_INTERRUPTS_FEATURE. Disable ENDSTOP_INTERRUPTS_FEATURE to continue."
#endif

View file

@ -93,15 +93,15 @@ namespace AVRHelpers {
typedef T type;
};
template <typename T>
struct voltype <T, 1u> {
struct voltype <T, 1U> {
typedef uint8_t type;
};
template <typename T>
struct voltype <T, 2u> {
struct voltype <T, 2U> {
typedef uint16_t type;
};
template <typename T>
struct voltype <T, 4u> {
struct voltype <T, 4U> {
typedef uint32_t type;
};
@ -2007,7 +2007,7 @@ inline void _ATmega_resetperipherals() {
#if defined(__AVR_TRM01__) || defined(__AVR_TRM02__) || defined(__AVR_TRM03__) || defined(__AVR_TRM05__)
_EEAR._EEAR = 0;
dwrite(_EEDR, (uint8_t)0u);
dwrite(_EEDR, (uint8_t)0U);
#endif
#if defined(__AVR_TRM01__) || defined(__AVR_TRM02__) || defined(__AVR_TRM03__) || defined(__AVR_TRM04__) || defined(__AVR_TRM05__)

View file

@ -28,7 +28,7 @@
// ------------------------
typedef uint16_t hal_timer_t;
#define HAL_TIMER_TYPE_MAX 0xFFFF
#define HAL_TIMER_TYPE_MAX 0xFFFFU
// ------------------------
// Defines

View file

@ -34,7 +34,7 @@
#define FORCE_INLINE __attribute__((always_inline)) inline
typedef uint32_t hal_timer_t;
#define HAL_TIMER_TYPE_MAX 0xFFFFFFFF
#define HAL_TIMER_TYPE_MAX 0xFFFFFFFFUL
#define HAL_TIMER_PRESCALER 2
#define HAL_TIMER_RATE ((F_CPU) / (HAL_TIMER_PRESCALER)) // frequency of timers peripherals

View file

@ -64,10 +64,10 @@
#define CRITICAL_SECTION_END() portEXIT_CRITICAL(&hal.spinlock)
#define HAL_CAN_SET_PWM_FREQ // This HAL supports PWM Frequency adjustment
#define PWM_FREQUENCY 1000u // Default PWM frequency when set_pwm_duty() is called without set_pwm_frequency()
#define PWM_RESOLUTION 10u // Default PWM bit resolution
#define CHANNEL_MAX_NUM 15u // max PWM channel # to allocate (7 to only use low speed, 15 to use low & high)
#define MAX_PWM_IOPIN 33u // hardware pwm pins < 34
#define PWM_FREQUENCY 1000U // Default PWM frequency when set_pwm_duty() is called without set_pwm_frequency()
#define PWM_RESOLUTION 10U // Default PWM bit resolution
#define CHANNEL_MAX_NUM 15U // max PWM channel # to allocate (7 to only use low speed, 15 to use low & high)
#define MAX_PWM_IOPIN 33U // hardware pwm pins < 34
#ifndef MAX_EXPANDER_BITS
#define MAX_EXPANDER_BITS 32 // I2S expander bit width (max 32)
#endif

View file

@ -35,7 +35,7 @@ Servo::Servo() {}
int8_t Servo::attach(const int inPin) {
if (inPin > 0) pin = inPin;
channel = get_pwm_channel(pin, 50u, 16u);
channel = get_pwm_channel(pin, 50U, 16U);
return channel; // -1 if no PWM avail.
}

View file

@ -78,8 +78,8 @@ void IRAM_ATTR timer_isr(void *para) {
/**
* Enable and initialize the timer
* @param timer_num timer number to initialize
* @param frequency frequency of the timer
* @param timer_num timer number to initialize
* @param frequency frequency of the timer
*/
void HAL_timer_start(const uint8_t timer_num, const uint32_t frequency) {
const tTimerConfig timer = timer_config[timer_num];

View file

@ -30,7 +30,7 @@
#define FORCE_INLINE __attribute__((always_inline)) inline
typedef uint64_t hal_timer_t;
#define HAL_TIMER_TYPE_MAX 0xFFFFFFFFFFFFFFFFULL
#define HAL_TIMER_TYPE_MAX 0xFFFF'FFFF'FFFF'FFFFULL
#ifndef MF_TIMER_STEP
#define MF_TIMER_STEP 0 // Timer Index for Stepper
@ -52,12 +52,12 @@ typedef uint64_t hal_timer_t;
#if ENABLED(I2S_STEPPER_STREAM)
#define STEPPER_TIMER_PRESCALE 1
#define STEPPER_TIMER_RATE 250000 // 250khz, 4µs pulses of i2s word clock
#define STEPPER_TIMER_RATE 250'000 // 250khz, 4µs pulses of i2s word clock
#else
#define STEPPER_TIMER_PRESCALE 40
#define STEPPER_TIMER_RATE ((HAL_TIMER_RATE) / (STEPPER_TIMER_PRESCALE)) // frequency of stepper timer, 2MHz
#endif
#define STEPPER_TIMER_TICKS_PER_US ((STEPPER_TIMER_RATE) / 1000000) // stepper timer ticks per µs
#define STEPPER_TIMER_TICKS_PER_US ((STEPPER_TIMER_RATE) / 1'000'000) // stepper timer ticks per µs
#define STEP_TIMER_MIN_INTERVAL 8 // minimum time in µs between stepper interrupts

View file

@ -53,12 +53,15 @@ uint16_t MarlinHAL::adc_result;
// Initializes the Marlin HAL
void MarlinHAL::init() {
// Ensure F_CPU is a constant expression.
// If the compiler breaks here, it means that delay code that should compute at compile time will not work.
// So better safe than sorry here.
constexpr unsigned int cpuFreq = F_CPU;
UNUSED(cpuFreq);
#if PIN_EXISTS(LED)
OUT_WRITE(LED_PIN, LOW);
#endif
#if PIN_EXISTS(LED)
OUT_WRITE(LED_PIN, LOW);
#endif
SetTimerInterruptPriorities();

View file

@ -26,4 +26,4 @@
#define TS_TYPICAL_SLOPE 4.5
// TODO: Implement voltage scaling (calibrated Vrefint) and ADC resolution scaling (when applicable)
#define TEMP_SOC_SENSOR(RAW) ((TS_TYPICAL_V - (RAW) / float(OVERSAMPLENR) / float(HAL_ADC_RANGE) * (float(ADC_VREF_MV) / 1000.0f)) / ((TS_TYPICAL_SLOPE) / 1000.0f) + TS_TYPICAL_TEMP)
#define TEMP_SOC_SENSOR(RAW) ((TS_TYPICAL_V - (RAW) / float(OVERSAMPLENR) / float(HAL_ADC_RANGE) * (float(ADC_VREF_MV) * 0.001f)) / ((TS_TYPICAL_SLOPE) * 0.001f) + TS_TYPICAL_TEMP)

View file

@ -37,9 +37,9 @@ public:
MarlinServo();
/**
* @brief attach the pin to the servo, set pin mode, return channel number
* @param pin pin to attach to
* @return channel number, -1 if failed
* @brief attach the pin to the servo, set pin mode, return channel number
* @param pin pin to attach to
* @return channel number, -1 if failed
*/
int8_t attach(const pin_t apin);

View file

@ -27,7 +27,7 @@
//
typedef Timer0 *timer_channel_t;
typedef uint16_t hal_timer_t;
#define HAL_TIMER_TYPE_MAX 0xFFFF
#define HAL_TIMER_TYPE_MAX 0xFFFFU
//
// Timer instances

View file

@ -34,7 +34,7 @@
#define FORCE_INLINE __attribute__((always_inline)) inline
typedef uint32_t hal_timer_t;
#define HAL_TIMER_TYPE_MAX 0xFFFFFFFF
#define HAL_TIMER_TYPE_MAX 0xFFFFFFFFUL
#define HAL_TIMER_RATE ((SystemCoreClock) / 4) // frequency of timers peripherals

View file

@ -29,6 +29,6 @@
// LPC1768 boards seem to lose steps when saving to EEPROM during print (issue #20785)
// TODO: Which other boards are incompatible?
#if defined(MCU_LPC1768) && ENABLED(FLASH_EEPROM_EMULATION) && PRINTCOUNTER_SAVE_INTERVAL > 0
#if ALL(MCU_LPC1768, FLASH_EEPROM_EMULATION) && PRINTCOUNTER_SAVE_INTERVAL > 0
#define PRINTCOUNTER_SYNC
#endif

View file

@ -57,7 +57,7 @@
#define _HAL_TIMER_ISR(T) __HAL_TIMER_ISR(T)
typedef uint32_t hal_timer_t;
#define HAL_TIMER_TYPE_MAX 0xFFFFFFFF
#define HAL_TIMER_TYPE_MAX 0xFFFFFFFFUL
#define HAL_TIMER_RATE ((F_CPU) / 4) // frequency of timers peripherals

View file

@ -27,7 +27,7 @@
*
* Couldn't just call exact copies because the overhead killed the LCD update speed
* With an intermediate level the softspi was running in the 10-20kHz range which
* resulted in using about about 25% of the CPU's time.
* resulted in using about 25% of the CPU's time.
*/
#ifdef TARGET_LPC1768

View file

@ -28,7 +28,7 @@
*
* Couldn't just call exact copies because the overhead killed the LCD update speed
* With an intermediate level the softspi was running in the 10-20kHz range which
* resulted in using about about 25% of the CPU's time.
* resulted in using about 25% of the CPU's time.
*/
void u8g_SetPinOutput(uint8_t internal_pin_number);

View file

@ -28,6 +28,8 @@
#include "../shared/Marduino.h"
#include <pinmapping.h>
#define NO_COMPILE_TIME_PWM
#define SET_DIR_INPUT(IO) Gpio::setDir(IO, 1)
#define SET_DIR_OUTPUT(IO) Gpio::setDir(IO, 0)

View file

@ -34,7 +34,7 @@
#define FORCE_INLINE __attribute__((always_inline)) inline
typedef uint64_t hal_timer_t;
#define HAL_TIMER_TYPE_MAX 0xFFFFFFFFFFFFFFFF
#define HAL_TIMER_TYPE_MAX 0xFFFF'FFFF'FFFF'FFFFULL
#define HAL_TIMER_RATE ((SystemCoreClock) / 4) // frequency of timers peripherals
@ -52,11 +52,11 @@ typedef uint64_t hal_timer_t;
#endif
#define SYSTICK_TIMER_FREQUENCY 1000
#define TEMP_TIMER_RATE 1000000
#define TEMP_TIMER_FREQUENCY 1000 // temperature interrupt frequency
#define TEMP_TIMER_RATE 1'000'000
#define TEMP_TIMER_FREQUENCY 1000 // temperature interrupt frequency
#define STEPPER_TIMER_RATE HAL_TIMER_RATE // frequency of stepper timer (HAL_TIMER_RATE / STEPPER_TIMER_PRESCALE)
#define STEPPER_TIMER_TICKS_PER_US ((STEPPER_TIMER_RATE) / 1000000) // stepper timer ticks per µs
#define STEPPER_TIMER_TICKS_PER_US ((STEPPER_TIMER_RATE) / 1'000'000) // stepper timer ticks per µs
#define STEPPER_TIMER_PRESCALE (CYCLES_PER_MICROSECOND / STEPPER_TIMER_TICKS_PER_US)
#define PULSE_TIMER_RATE STEPPER_TIMER_RATE // frequency of pulse timer

View file

@ -27,7 +27,7 @@
*
* Couldn't just call exact copies because the overhead killed the LCD update speed
* With an intermediate level the softspi was running in the 10-20kHz range which
* resulted in using about about 25% of the CPU's time.
* resulted in using about 25% of the CPU's time.
*/
#ifdef __PLAT_NATIVE_SIM__

View file

@ -28,7 +28,7 @@
*
* Couldn't just call exact copies because the overhead killed the LCD update speed
* With an intermediate level the softspi was running in the 10-20kHz range which
* resulted in using about about 25% of the CPU's time.
* resulted in using about 25% of the CPU's time.
*/
#ifdef __cplusplus

View file

@ -56,7 +56,7 @@ void MarlinHAL::init() {
// Ensure F_CPU is a constant expression.
// If the compiler breaks here, it means that delay code that should compute at compile time will not work.
// So better safe than sorry here.
constexpr int cpuFreq = F_CPU;
constexpr unsigned int cpuFreq = F_CPU;
UNUSED(cpuFreq);
#if HAS_MEDIA && DISABLED(ONBOARD_SDIO) && PIN_EXISTS(SD_SS)

View file

@ -41,9 +41,9 @@
#define _HAL_TIMER_ISR(T) __HAL_TIMER_ISR(T)
typedef uint64_t hal_timer_t;
#define HAL_TIMER_TYPE_MAX 0xFFFFFFFFFFFFFFFF
#define HAL_TIMER_TYPE_MAX 0xFFFF'FFFF'FFFF'FFFFULL
#define HAL_TIMER_RATE (1000000ull) // fixed value as we use a microsecond timesource
#define HAL_TIMER_RATE (1'000'000ULL) // fixed value as we use a microsecond timesource
#ifndef MF_TIMER_STEP
#define MF_TIMER_STEP 0 // Timer Index for Stepper
#endif

View file

@ -83,7 +83,7 @@ bool PersistentStore::access_start() {
NVMCTRL->CTRLA.reg = NVMCTRL_CTRLA_CMDEX_KEY | NVMCTRL_CTRLA_CMD_PBC;
while (NVMCTRL->INTFLAG.bit.READY == 0) { }
PAGE_SIZE = pow(2,3 + NVMCTRL->PARAM.bit.PSZ);
PAGE_SIZE = POW(2, 3 + NVMCTRL->PARAM.bit.PSZ);
ROW_SIZE= PAGE_SIZE * 4;
/*NVMCTRL->SEECFG.reg = NVMCTRL_SEECFG_WMODE_BUFFERED; // Buffered mode and segment reallocation active
if (NVMCTRL->SEESTAT.bit.RLOCK)

View file

@ -33,7 +33,7 @@
// --------------------------------------------------------------------------
typedef uint32_t hal_timer_t;
#define HAL_TIMER_TYPE_MAX 0xFFFFFFFF
#define HAL_TIMER_TYPE_MAX 0xFFFFFFFFUL
#define HAL_TIMER_RATE F_CPU // frequency of timers peripherals

View file

@ -32,7 +32,7 @@
*
* Couldn't just call exact copies because the overhead killed the LCD update speed
* With an intermediate level the softspi was running in the 10-20kHz range which
* resulted in using about about 25% of the CPU's time.
* resulted in using about 25% of the CPU's time.
*/
#ifdef __SAMD21__

View file

@ -33,7 +33,7 @@
*
* Couldn't just call exact copies because the overhead killed the LCD update speed
* With an intermediate level the softspi was running in the 10-20kHz range which
* resulted in using about about 25% of the CPU's time.
* resulted in using about 25% of the CPU's time.
*/
void u8g_SetPinOutput(uint8_t internal_pin_number);

View file

@ -32,7 +32,7 @@
// --------------------------------------------------------------------------
typedef uint32_t hal_timer_t;
#define HAL_TIMER_TYPE_MAX 0xFFFFFFFF
#define HAL_TIMER_TYPE_MAX 0xFFFFFFFFUL
#define HAL_TIMER_RATE F_CPU // frequency of timers peripherals

View file

@ -66,7 +66,7 @@ void MarlinHAL::init() {
// Ensure F_CPU is a constant expression.
// If the compiler breaks here, it means that delay code that should compute at compile time will not work.
// So better safe than sorry here.
constexpr int cpuFreq = F_CPU;
constexpr unsigned int cpuFreq = F_CPU;
UNUSED(cpuFreq);
#if HAS_MEDIA && DISABLED(ONBOARD_SDIO) && PIN_EXISTS(SD_SS)

View file

@ -39,8 +39,8 @@ static_assert(COUNT(servoDelay) == NUM_SERVOS, "SERVO_DELAY must be an array NUM
static uint32_t servo_interrupt_priority = NVIC_EncodePriority(NVIC_GetPriorityGrouping(), TIM_IRQ_PRIO, TIM_IRQ_SUBPRIO);
// This must be called after the STM32 Servo class has initialized the timer.
// It may only be needed after the first call to attach(), but it is possible
// that is is necessary after every detach() call. To be safe this is currently
// It may only be needed after the first call to attach(), but it's possible
// that this is needed after every detach() call. To be safe this is currently
// called after every call to attach().
static void fixServoTimerInterruptPriority() {
NVIC_SetPriority(getTimerUpIrq(TIMER_SERVO), servo_interrupt_priority);

View file

@ -29,6 +29,6 @@
#endif
// Some STM32F4 boards may lose steps when saving to EEPROM during print (PR #17946)
#if defined(STM32F4xx) && ENABLED(FLASH_EEPROM_EMULATION) && PRINTCOUNTER_SAVE_INTERVAL > 0
#if ALL(STM32F4xx, FLASH_EEPROM_EMULATION) && PRINTCOUNTER_SAVE_INTERVAL > 0
#define PRINTCOUNTER_SYNC
#endif

View file

@ -132,6 +132,9 @@ void TFT_FSMC::init() {
DMAtx.Init.Priority = DMA_PRIORITY_HIGH;
LCD = (LCD_CONTROLLER_TypeDef *)controllerAddress;
DMAtx.Init.PeriphInc = DMA_PINC_DISABLE;
HAL_DMA_Init(&DMAtx);
}
uint32_t TFT_FSMC::getID() {
@ -179,15 +182,19 @@ void TFT_FSMC::abort() {
}
void TFT_FSMC::transmitDMA(uint32_t memoryIncrease, uint16_t *data, uint16_t count) {
DMAtx.Init.PeriphInc = memoryIncrease;
HAL_DMA_Init(&DMAtx);
if (!__IS_DMA_CONFIGURED(&DMAtx) || DMAtx.Init.PeriphInc != memoryIncrease) {
DMAtx.Init.PeriphInc = memoryIncrease;
HAL_DMA_Init(&DMAtx);
}
HAL_DMA_Start(&DMAtx, (uint32_t)data, (uint32_t)&(LCD->RAM), count);
TERN_(TFT_SHARED_IO, while (isBusy()));
}
void TFT_FSMC::transmit(uint32_t memoryIncrease, uint16_t *data, uint16_t count) {
DMAtx.Init.PeriphInc = memoryIncrease;
HAL_DMA_Init(&DMAtx);
if (!__IS_DMA_CONFIGURED(&DMAtx) || DMAtx.Init.PeriphInc != memoryIncrease) {
DMAtx.Init.PeriphInc = memoryIncrease;
HAL_DMA_Init(&DMAtx);
}
dataTransferBegin();
HAL_DMA_Start(&DMAtx, (uint32_t)data, (uint32_t)&(LCD->RAM), count);
HAL_DMA_PollForTransfer(&DMAtx, HAL_DMA_FULL_TRANSFER, HAL_MAX_DELAY);

View file

@ -30,3 +30,6 @@ uint8_t u8g_com_HAL_STM32_sw_spi_fn(u8g_t *u8g, uint8_t msg, uint8_t arg_val, vo
uint8_t u8g_com_stm32duino_hw_spi_fn(u8g_t *u8g, uint8_t msg, uint8_t arg_val, void *arg_ptr); // See U8glib-HAL
#define U8G_COM_HAL_HW_SPI_FN u8g_com_stm32duino_hw_spi_fn
uint8_t u8g_com_stm32duino_ssd_i2c_fn(u8g_t *u8g, uint8_t msg, uint8_t arg_val, void *arg_ptr); // u8g_com_stm32duino_ssd_i2c.cpp
#define U8G_COM_SSD_I2C_HAL u8g_com_stm32duino_ssd_i2c_fn

View file

@ -0,0 +1,194 @@
/**
* 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/>.
*
*/
/**
* 2-Wire I2C COM Driver
*
* Handles both Hardware and Software I2C so any pins can be used as SDA and SLC.
* Wire library is used for Hardware I2C.
* SlowSoftWire is used for Software I2C.
*
* Wire / SoftWire library selection can be done automatically at runtime.
*
* SDA and SLC pins must be named DOGLCD_SDA_PIN, DOGLCD_SCL_PIN to distinguish
* from other I2C devices (e.g., EEPROM) that use I2C_SDA_PIN, I2C_SLC_PIN.
*/
#ifdef ARDUINO_ARCH_STM32
#include "../../../inc/MarlinConfig.h"
#if HAS_U8GLIB_I2C_OLED
#include <U8glib-HAL.h>
#if ENABLED(U8G_USES_HW_I2C)
#include <Wire.h>
#ifndef MASTER_ADDRESS
#define MASTER_ADDRESS 0x01
#endif
#endif
#if ENABLED(U8G_USES_SW_I2C)
#include <SlowSoftI2CMaster.h>
#include <SlowSoftWire.h>
#endif
/**
* BUFFER_LENGTH is defined in libraries\Wire\utility\WireBase.h
* Default value is 32
* Increase this value to 144 to send U8G_COM_MSG_WRITE_SEQ in single block
*/
#ifndef BUFFER_LENGTH
#define BUFFER_LENGTH 32
#endif
#if BUFFER_LENGTH > 144
#error "BUFFER_LENGTH should not be greater than 144."
#endif
#define I2C_MAX_LENGTH (BUFFER_LENGTH - 1)
uint8_t u8g_com_stm32duino_ssd_i2c_fn(u8g_t *u8g, uint8_t msg, uint8_t arg_val, void *arg_ptr) {
// Hardware I2C flag
#ifdef COMPILE_TIME_I2C_IS_HARDWARE
constexpr bool isHardI2C = ENABLED(COMPILE_TIME_I2C_IS_HARDWARE);
#else
static bool isHardI2C = false;
static bool i2c_initialized = false; // Flag to only run init/linking code once
if (!i2c_initialized) { // Init runtime linkages
i2c_initialized = true; // Only do this once
I2C_TypeDef *i2cInstance1 = (I2C_TypeDef *)pinmap_peripheral(digitalPinToPinName(DOGLCD_SDA_PIN), PinMap_I2C_SDA);
I2C_TypeDef *i2cInstance2 = (I2C_TypeDef *)pinmap_peripheral(digitalPinToPinName(DOGLCD_SCL_PIN), PinMap_I2C_SCL);
isHardI2C = (i2cInstance1 && (i2cInstance1 == i2cInstance2)); // Found hardware I2C controller
}
#endif
static uint8_t msgInitCount = 0; // Ignore all messages until 2nd U8G_COM_MSG_INIT
if (msgInitCount) {
if (msg == U8G_COM_MSG_INIT) msgInitCount--;
if (msgInitCount) return -1;
}
static uint8_t control;
if (isHardI2C) { // Found hardware I2C controller
#if ENABLED(U8G_USES_HW_I2C)
static TwoWire wire2; // A TwoWire object for use below
switch (msg) {
case U8G_COM_MSG_INIT:
wire2.setClock(400000);
wire2.setSCL(DOGLCD_SCL_PIN);
wire2.setSDA(DOGLCD_SDA_PIN);
wire2.begin(MASTER_ADDRESS, 0); // Start as master
break;
case U8G_COM_MSG_ADDRESS: // Define cmd (arg_val = 0) or data mode (arg_val = 1)
control = arg_val ? 0x40 : 0x00;
break;
case U8G_COM_MSG_WRITE_BYTE:
wire2.beginTransmission(0x3C);
wire2.write(control);
wire2.write(arg_val);
wire2.endTransmission();
break;
case U8G_COM_MSG_WRITE_SEQ: {
uint8_t* dataptr = (uint8_t*)arg_ptr;
#ifdef I2C_MAX_LENGTH
while (arg_val > 0) {
wire2.beginTransmission(0x3C);
wire2.write(control);
if (arg_val <= I2C_MAX_LENGTH) {
wire2.write(dataptr, arg_val);
arg_val = 0;
}
else {
wire2.write(dataptr, I2C_MAX_LENGTH);
arg_val -= I2C_MAX_LENGTH;
dataptr += I2C_MAX_LENGTH;
}
wire2.endTransmission();
}
#else
wire2.beginTransmission(0x3C);
wire2.write(control);
wire2.write(dataptr, arg_val);
wire2.endTransmission();
#endif // I2C_MAX_LENGTH
break;
}
}
#endif // U8G_USES_HW_I2C
}
else { // Software I2C
#if ENABLED(U8G_USES_SW_I2C)
static SlowSoftWire sWire = SlowSoftWire(DOGLCD_SDA_PIN, DOGLCD_SCL_PIN);
switch (msg) {
case U8G_COM_MSG_INIT:
sWire.setClock(400000);
sWire.begin(); // Start as master
break;
case U8G_COM_MSG_ADDRESS: // Define cmd (arg_val = 0) or data mode (arg_val = 1)
control = arg_val ? 0x40 : 0x00;
break;
case U8G_COM_MSG_WRITE_BYTE:
sWire.beginTransmission((uint8_t)0x3C);
sWire.write((uint8_t)control);
sWire.write((uint8_t)arg_val);
sWire.endTransmission();
break;
case U8G_COM_MSG_WRITE_SEQ: {
uint8_t* dataptr = (uint8_t*)arg_ptr;
#ifdef I2C_MAX_LENGTH
while (arg_val > 0) {
sWire.beginTransmission((uint8_t)0x3C);
sWire.write((uint8_t)control);
if (arg_val <= I2C_MAX_LENGTH) {
sWire.write((const uint8_t *)dataptr, (size_t)arg_val);
arg_val = 0;
}
else {
sWire.write((const uint8_t *)dataptr, I2C_MAX_LENGTH);
arg_val -= I2C_MAX_LENGTH;
dataptr += I2C_MAX_LENGTH;
}
sWire.endTransmission();
}
#else
sWire.beginTransmission((uint8_t)0x3C);
sWire.write((uint8_t)control);
sWire.write((const uint8_t *)dataptr, (size_t)arg_val);
sWire.endTransmission();
#endif // I2C_MAX_LENGTH
break;
}
}
#endif // U8G_USES_SW_I2C
}
return 1;
}
#endif // HAS_U8GLIB_I2C_OLED
#endif // ARDUINO_ARCH_STM32

View file

@ -800,7 +800,7 @@ void ADC_StartCalibration(ADC_Module* NS_ADCx);
void ADC_EnableDMA(ADC_Module* NS_ADCx, uint32_t Cmd);
/**================================================================
* Configure ADC interrupt enable enable
* Configure ADC interrupt enable
================================================================*/
void ADC_ConfigInt(ADC_Module* NS_ADCx, uint16_t ADC_IT, uint32_t Cmd);

View file

@ -92,7 +92,7 @@ void install_min_serial() {
HAL_min_serial_out = &TX;
}
#if DISABLED(DYNAMIC_VECTORTABLE) && DISABLED(STM32F0xx) // Cortex M0 can't branch to a symbol that's too far, so we have a specific hack for them
#if NONE(DYNAMIC_VECTORTABLE, STM32F0xx) // Cortex M0 can't branch to a symbol that's too far, so we have a specific hack for them
extern "C" {
__attribute__((naked)) void JumpHandler_ASM() {
__asm__ __volatile__ (

View file

@ -47,14 +47,14 @@ static uint8_t ram_eeprom[MARLIN_EEPROM_SIZE] __attribute__((aligned(4))) = {0};
static bool eeprom_dirty = false;
bool PersistentStore::access_start() {
const uint32_t *source = reinterpret_cast<const uint32_t*>(EEPROM_PAGE0_BASE);
uint32_t *destination = reinterpret_cast<uint32_t*>(ram_eeprom);
const uint32_t *src = reinterpret_cast<const uint32_t*>(EEPROM_PAGE0_BASE);
uint32_t *dst = reinterpret_cast<uint32_t*>(ram_eeprom);
static_assert(0 == (MARLIN_EEPROM_SIZE) % 4, "MARLIN_EEPROM_SIZE is corrupted. (Must be a multiple of 4.)"); // Ensure copying as uint32_t is safe
constexpr size_t eeprom_size_u32 = (MARLIN_EEPROM_SIZE) / 4;
for (size_t i = 0; i < eeprom_size_u32; ++i, ++destination, ++source)
*destination = *source;
for (size_t i = 0; i < eeprom_size_u32; ++i, ++dst, ++src)
*dst = *src;
eeprom_dirty = false;
return true;
@ -80,9 +80,9 @@ bool PersistentStore::access_finish() {
status = FLASH_ErasePage(EEPROM_PAGE1_BASE);
if (status != FLASH_COMPLETE) ACCESS_FINISHED(true);
const uint16_t *source = reinterpret_cast<const uint16_t*>(ram_eeprom);
for (size_t i = 0; i < long(MARLIN_EEPROM_SIZE); i += 2, ++source) {
if (FLASH_ProgramHalfWord(EEPROM_PAGE0_BASE + i, *source) != FLASH_COMPLETE)
const uint16_t *src = reinterpret_cast<const uint16_t*>(ram_eeprom);
for (size_t i = 0; i < long(MARLIN_EEPROM_SIZE); i += 2, ++src) {
if (FLASH_ProgramHalfWord(EEPROM_PAGE0_BASE + i, *src) != FLASH_COMPLETE)
ACCESS_FINISHED(false);
}

View file

@ -86,7 +86,6 @@ __attribute__((always_inline)) __STATIC_INLINE void __DSB() {
#define FSMC_ADDRESS_SETUP_TIME 15 // AddressSetupTime
#define FSMC_DATA_SETUP_TIME 15 // DataSetupTime
static uint8_t fsmcInit = 0;
void TFT_FSMC::init() {
uint8_t cs = FSMC_CS_PIN, rs = FSMC_RS_PIN;
uint32_t controllerAddress;
@ -99,8 +98,9 @@ void TFT_FSMC::init() {
struct fsmc_nor_psram_reg_map* fsmcPsramRegion;
static bool fsmcInit = false;
if (fsmcInit) return;
fsmcInit = 1;
fsmcInit = true;
switch (cs) {
case FSMC_CS_NE1: controllerAddress = (uint32_t)FSMC_NOR_PSRAM_REGION1; fsmcPsramRegion = FSMC_NOR_PSRAM1_BASE; break;

View file

@ -40,7 +40,7 @@
*/
typedef uint16_t hal_timer_t;
#define HAL_TIMER_TYPE_MAX 0xFFFF
#define HAL_TIMER_TYPE_MAX 0xFFFFU
#define HAL_TIMER_RATE uint32_t(F_CPU) // frequency of timers peripherals

View file

@ -34,7 +34,7 @@
#define FORCE_INLINE __attribute__((always_inline)) inline
typedef uint32_t hal_timer_t;
#define HAL_TIMER_TYPE_MAX 0xFFFFFFFF
#define HAL_TIMER_TYPE_MAX 0xFFFFFFFFUL
#define FTM0_TIMER_PRESCALE 8
#define FTM1_TIMER_PRESCALE 4

View file

@ -34,7 +34,7 @@
#define FORCE_INLINE __attribute__((always_inline)) inline
typedef uint32_t hal_timer_t;
#define HAL_TIMER_TYPE_MAX 0xFFFFFFFF
#define HAL_TIMER_TYPE_MAX 0xFFFFFFFFUL
#define FTM0_TIMER_PRESCALE 8
#define FTM1_TIMER_PRESCALE 4

View file

@ -98,7 +98,7 @@ void MarlinHAL::clear_reset_source() {
#define WDT_TIMEOUT TERN(WATCHDOG_DURATION_8S, 8, 4) // 4 or 8 second timeout
constexpr uint8_t timeoutval = (WDT_TIMEOUT - 0.5f) / 0.5f;
constexpr uint8_t timeoutval = (WDT_TIMEOUT - 0.5f) * 2.0f;
void MarlinHAL::watchdog_init() {
CCM_CCGR3 |= CCM_CCGR3_WDOG1(3); // enable WDOG1 clocks

View file

@ -34,7 +34,7 @@
#define FORCE_INLINE __attribute__((always_inline)) inline
typedef uint32_t hal_timer_t;
#define HAL_TIMER_TYPE_MAX 0xFFFFFFFE
#define HAL_TIMER_TYPE_MAX 0xFFFFFFFEUL
#define GPT_TIMER_RATE (F_CPU / 4) // 150MHz (Can't use F_BUS_ACTUAL because it's extern volatile)

View file

@ -414,7 +414,7 @@ UnwResult UnwStartArm(UnwState * const state) {
/* S indicates that banked registers (untracked) are used, unless
* this is a load including the PC when the S-bit indicates that
* that CPSR is loaded from SPSR (also untracked, but ignored).
* CPSR is loaded from SPSR (also untracked, but ignored).
*/
if (S && (!L || (regList & (0x01 << 15)) == 0)) {
UnwPrintd1("\nError:S-bit set requiring banked registers\n");
@ -431,7 +431,7 @@ UnwResult UnwStartArm(UnwState * const state) {
/* Check if ascending or descending.
* Registers are loaded/stored in order of address.
* i.e. r0 is at the lowest address, r15 at the highest.
* i.e., r0 is at the lowest address, r15 at the highest.
*/
r = U ? 0 : 15;
do {

View file

@ -28,6 +28,7 @@
#include "macros.h"
#define BOARD_ERROR -2
#define BOARD_UNKNOWN -1
//
@ -54,11 +55,11 @@
#define BOARD_RAMPS_PLUS_EEF 1033 // RAMPS Plus 3DYMY (Power outputs: Hotend0, Hotend1, Fan)
#define BOARD_RAMPS_PLUS_SF 1034 // RAMPS Plus 3DYMY (Power outputs: Spindle, Controller Fan)
#define BOARD_RAMPS_BTT_16_PLUS_EFB 1035 // RAMPS 1.6+ (Power outputs: Hotend, Fan, Bed)
#define BOARD_RAMPS_BTT_16_PLUS_EEB 1036 // RAMPS 1.6+ (Power outputs: Hotend0, Hotend1, Bed)
#define BOARD_RAMPS_BTT_16_PLUS_EFF 1037 // RAMPS 1.6+ (Power outputs: Hotend, Fan0, Fan1)
#define BOARD_RAMPS_BTT_16_PLUS_EEF 1038 // RAMPS 1.6+ (Power outputs: Hotend0, Hotend1, Fan)
#define BOARD_RAMPS_BTT_16_PLUS_SF 1039 // RAMPS 1.6+ (Power outputs: Spindle, Controller Fan)
#define BOARD_RAMPS_BTT_16_PLUS_EFB 1040 // RAMPS 1.6+ (Power outputs: Hotend, Fan, Bed)
#define BOARD_RAMPS_BTT_16_PLUS_EEB 1041 // RAMPS 1.6+ (Power outputs: Hotend0, Hotend1, Bed)
#define BOARD_RAMPS_BTT_16_PLUS_EFF 1042 // RAMPS 1.6+ (Power outputs: Hotend, Fan0, Fan1)
#define BOARD_RAMPS_BTT_16_PLUS_EEF 1043 // RAMPS 1.6+ (Power outputs: Hotend0, Hotend1, Fan)
#define BOARD_RAMPS_BTT_16_PLUS_SF 1044 // RAMPS 1.6+ (Power outputs: Spindle, Controller Fan)
//
// RAMPS Derivatives - ATmega1280, ATmega2560
@ -175,16 +176,17 @@
#define BOARD_GT2560_V41B 1322 // Geeetech GT2560 V4.1B for A10(M/T/D)
#define BOARD_EINSTART_S 1323 // Einstart retrofit
#define BOARD_WANHAO_ONEPLUS 1324 // Wanhao 0ne+ i3 Mini
#define BOARD_OVERLORD 1325 // Overlord/Overlord Pro
#define BOARD_HJC2560C_REV1 1326 // ADIMLab Gantry v1
#define BOARD_HJC2560C_REV2 1327 // ADIMLab Gantry v2
#define BOARD_LEAPFROG_XEED2015 1328 // Leapfrog Xeed 2015
#define BOARD_PICA_REVB 1329 // PICA Shield (original version)
#define BOARD_PICA 1330 // PICA Shield (rev C or later)
#define BOARD_INTAMSYS40 1331 // Intamsys 4.0 (Funmat HT)
#define BOARD_MALYAN_M180 1332 // Malyan M180 Mainboard Version 2 (no display function, direct G-code only)
#define BOARD_PROTONEER_CNC_SHIELD_V3 1333 // Mega controller & Protoneer CNC Shield V3.00
#define BOARD_WEEDO_62A 1334 // WEEDO 62A board (TINA2, Monoprice Cadet, etc.)
#define BOARD_WANHAO_D9 1325 // Wanhao D9 MK2
#define BOARD_OVERLORD 1326 // Overlord/Overlord Pro
#define BOARD_HJC2560C_REV1 1327 // ADIMLab Gantry v1
#define BOARD_HJC2560C_REV2 1328 // ADIMLab Gantry v2
#define BOARD_LEAPFROG_XEED2015 1329 // Leapfrog Xeed 2015
#define BOARD_PICA_REVB 1330 // PICA Shield (original version)
#define BOARD_PICA 1331 // PICA Shield (rev C or later)
#define BOARD_INTAMSYS40 1332 // Intamsys 4.0 (Funmat HT)
#define BOARD_MALYAN_M180 1333 // Malyan M180 Mainboard Version 2 (no display function, direct G-code only)
#define BOARD_PROTONEER_CNC_SHIELD_V3 1334 // Mega controller & Protoneer CNC Shield V3.00
#define BOARD_WEEDO_62A 1335 // WEEDO 62A board (TINA2, Monoprice Cadet, etc.)
//
// ATmega1281, ATmega2561
@ -435,67 +437,68 @@
// STM32 ARM Cortex-M4F
//
#define BOARD_ARMED 5200 // Arm'ed STM32F4-based controller
#define BOARD_RUMBA32_V1_0 5201 // RUMBA32 STM32F446VE based controller from Aus3D
#define BOARD_RUMBA32_V1_1 5202 // RUMBA32 STM32F446VE based controller from Aus3D
#define BOARD_RUMBA32_MKS 5203 // RUMBA32 STM32F446VE based controller from Makerbase
#define BOARD_RUMBA32_BTT 5204 // RUMBA32 STM32F446VE based controller from BIGTREETECH
#define BOARD_BLACK_STM32F407VE 5205 // Black STM32F407VE development board
#define BOARD_BLACK_STM32F407ZE 5206 // Black STM32F407ZE development board
#define BOARD_BTT_SKR_MINI_E3_V3_0_1 5207 // BigTreeTech SKR Mini E3 V3.0.1 (STM32F401RC)
#define BOARD_BTT_SKR_PRO_V1_1 5208 // BigTreeTech SKR Pro v1.1 (STM32F407ZG)
#define BOARD_BTT_SKR_PRO_V1_2 5209 // BigTreeTech SKR Pro v1.2 (STM32F407ZG)
#define BOARD_BTT_BTT002_V1_0 5210 // BigTreeTech BTT002 v1.0 (STM32F407VG)
#define BOARD_BTT_E3_RRF 5211 // BigTreeTech E3 RRF (STM32F407VG)
#define BOARD_BTT_SKR_V2_0_REV_A 5212 // BigTreeTech SKR v2.0 Rev A (STM32F407VG)
#define BOARD_BTT_SKR_V2_0_REV_B 5213 // BigTreeTech SKR v2.0 Rev B (STM32F407VG/STM32F429VG)
#define BOARD_BTT_GTR_V1_0 5214 // BigTreeTech GTR v1.0 (STM32F407IGT)
#define BOARD_BTT_OCTOPUS_V1_0 5215 // BigTreeTech Octopus v1.0 (STM32F446ZE)
#define BOARD_BTT_OCTOPUS_V1_1 5216 // BigTreeTech Octopus v1.1 (STM32F446ZE)
#define BOARD_BTT_OCTOPUS_PRO_V1_0 5217 // BigTreeTech Octopus Pro v1.0 (STM32F446ZE / STM32F429ZG)
#define BOARD_LERDGE_K 5218 // Lerdge K (STM32F407ZG)
#define BOARD_LERDGE_S 5219 // Lerdge S (STM32F407VE)
#define BOARD_LERDGE_X 5220 // Lerdge X (STM32F407VE)
#define BOARD_FYSETC_S6 5221 // FYSETC S6 (STM32F446VE)
#define BOARD_FYSETC_S6_V2_0 5222 // FYSETC S6 v2.0 (STM32F446VE)
#define BOARD_FYSETC_SPIDER 5223 // FYSETC Spider (STM32F446VE)
#define BOARD_FYSETC_SPIDER_V2_2 5224 // FYSETC Spider V2.2 (STM32F446VE)
#define BOARD_FLYF407ZG 5225 // FLYmaker FLYF407ZG (STM32F407ZG)
#define BOARD_MKS_ROBIN2 5226 // MKS Robin2 V1.0 (STM32F407ZE)
#define BOARD_MKS_ROBIN_PRO_V2 5227 // MKS Robin Pro V2 (STM32F407VE)
#define BOARD_MKS_ROBIN_NANO_V3 5228 // MKS Robin Nano V3 (STM32F407VG)
#define BOARD_MKS_ROBIN_NANO_V3_1 5229 // MKS Robin Nano V3.1 (STM32F407VE)
#define BOARD_MKS_MONSTER8_V1 5230 // MKS Monster8 V1 (STM32F407VE)
#define BOARD_MKS_MONSTER8_V2 5231 // MKS Monster8 V2 (STM32F407VE)
#define BOARD_ANET_ET4 5232 // ANET ET4 V1.x (STM32F407VG)
#define BOARD_ANET_ET4P 5233 // ANET ET4P V1.x (STM32F407VG)
#define BOARD_FYSETC_CHEETAH_V20 5234 // FYSETC Cheetah V2.0 (STM32F401RC)
#define BOARD_FYSETC_CHEETAH_V30 5235 // FYSETC Cheetah V3.0 (STM32F446RC)
#define BOARD_TH3D_EZBOARD_V2 5236 // TH3D EZBoard v2.0 (STM32F405RG)
#define BOARD_OPULO_LUMEN_REV3 5237 // Opulo Lumen PnP Controller REV3 (STM32F407VE / STM32F407VG)
#define BOARD_OPULO_LUMEN_REV4 5238 // Opulo Lumen PnP Controller REV4 (STM32F407VE / STM32F407VG)
#define BOARD_MKS_ROBIN_NANO_V1_3_F4 5239 // MKS Robin Nano V1.3 and MKS Robin Nano-S V1.3 (STM32F407VE)
#define BOARD_MKS_EAGLE 5240 // MKS Eagle (STM32F407VE)
#define BOARD_ARTILLERY_RUBY 5241 // Artillery Ruby (STM32F401RC)
#define BOARD_CREALITY_V24S1_301F4 5242 // Creality v2.4.S1_301F4 (STM32F401RC) as found in the Ender-3 S1 F4
#define BOARD_CREALITY_CR4NTXXC10 5243 // Creality E3 Free-runs Silent Motherboard (STM32F401RET6)
#define BOARD_FYSETC_SPIDER_KING407 5244 // FYSETC Spider King407 (STM32F407ZG)
#define BOARD_MKS_SKIPR_V1 5245 // MKS SKIPR v1.0 all-in-one board (STM32F407VE)
#define BOARD_TRONXY_CXY_446_V10 5246 // TRONXY CXY-446-V10-220413/CXY-V6-191121 (STM32F446ZE)
#define BOARD_CREALITY_F401RE 5247 // Creality CR4NS200141C13 (STM32F401RE) as found in the Ender-5 S1
#define BOARD_BLACKPILL_CUSTOM 5248 // Custom board based on STM32F401CDU6.
#define BOARD_I3DBEEZ9_V1 5249 // I3DBEEZ9 V1 (STM32F407ZG)
#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)
#define BOARD_FLY_SUPER8 5254 // Fly SUPER8 (STM32F407ZGT6)
#define BOARD_FLY_D8 5255 // FLY D8 (STM32F407VG)
#define BOARD_FLY_CDY_V3 5256 // FLY CDY V3 (STM32F407VGT6)
#define BOARD_ZNP_ROBIN_NANO 5257 // Elegoo Neptune 2 v1.2 board
#define BOARD_ZNP_ROBIN_NANO_V1_3 5258 // Elegoo Neptune 2 v1.3 board
#define BOARD_MKS_NEPTUNE_X 5259 // Elegoo Neptune X
#define BOARD_MKS_NEPTUNE_3 5260 // Elegoo Neptune 3
#define BOARD_ARMED 5200 // Arm'ed STM32F4-based controller
#define BOARD_RUMBA32_V1_0 5201 // RUMBA32 STM32F446VE based controller from Aus3D
#define BOARD_RUMBA32_V1_1 5202 // RUMBA32 STM32F446VE based controller from Aus3D
#define BOARD_RUMBA32_MKS 5203 // RUMBA32 STM32F446VE based controller from Makerbase
#define BOARD_RUMBA32_BTT 5204 // RUMBA32 STM32F446VE based controller from BIGTREETECH
#define BOARD_BLACK_STM32F407VE 5205 // Black STM32F407VE development board
#define BOARD_BLACK_STM32F407ZE 5206 // Black STM32F407ZE development board
#define BOARD_BTT_SKR_MINI_E3_V3_0_1 5207 // BigTreeTech SKR Mini E3 V3.0.1 (STM32F401RC)
#define BOARD_BTT_SKR_PRO_V1_1 5208 // BigTreeTech SKR Pro v1.1 (STM32F407ZG)
#define BOARD_BTT_SKR_PRO_V1_2 5209 // BigTreeTech SKR Pro v1.2 (STM32F407ZG)
#define BOARD_BTT_BTT002_V1_0 5210 // BigTreeTech BTT002 v1.0 (STM32F407VG)
#define BOARD_BTT_E3_RRF 5211 // BigTreeTech E3 RRF (STM32F407VG)
#define BOARD_BTT_SKR_V2_0_REV_A 5212 // BigTreeTech SKR v2.0 Rev A (STM32F407VG)
#define BOARD_BTT_SKR_V2_0_REV_B 5213 // BigTreeTech SKR v2.0 Rev B (STM32F407VG/STM32F429VG)
#define BOARD_BTT_GTR_V1_0 5214 // BigTreeTech GTR v1.0 (STM32F407IGT)
#define BOARD_BTT_OCTOPUS_V1_0 5215 // BigTreeTech Octopus v1.0 (STM32F446ZE)
#define BOARD_BTT_OCTOPUS_V1_1 5216 // BigTreeTech Octopus v1.1 (STM32F446ZE)
#define BOARD_BTT_OCTOPUS_PRO_V1_0 5217 // BigTreeTech Octopus Pro v1.0 (STM32F446ZE / STM32F429ZG)
#define BOARD_LERDGE_K 5218 // Lerdge K (STM32F407ZG)
#define BOARD_LERDGE_S 5219 // Lerdge S (STM32F407VE)
#define BOARD_LERDGE_X 5220 // Lerdge X (STM32F407VE)
#define BOARD_FYSETC_S6 5221 // FYSETC S6 (STM32F446VE)
#define BOARD_FYSETC_S6_V2_0 5222 // FYSETC S6 v2.0 (STM32F446VE)
#define BOARD_FYSETC_SPIDER 5223 // FYSETC Spider (STM32F446VE)
#define BOARD_FYSETC_SPIDER_V2_2 5224 // FYSETC Spider V2.2 (STM32F446VE)
#define BOARD_FLYF407ZG 5225 // FLYmaker FLYF407ZG (STM32F407ZG)
#define BOARD_MKS_ROBIN2 5226 // MKS Robin2 V1.0 (STM32F407ZE)
#define BOARD_MKS_ROBIN_PRO_V2 5227 // MKS Robin Pro V2 (STM32F407VE)
#define BOARD_MKS_ROBIN_NANO_V3 5228 // MKS Robin Nano V3 (STM32F407VG)
#define BOARD_MKS_ROBIN_NANO_V3_1 5229 // MKS Robin Nano V3.1 (STM32F407VE)
#define BOARD_MKS_MONSTER8_V1 5230 // MKS Monster8 V1 (STM32F407VE)
#define BOARD_MKS_MONSTER8_V2 5231 // MKS Monster8 V2 (STM32F407VE)
#define BOARD_ANET_ET4 5232 // ANET ET4 V1.x (STM32F407VG)
#define BOARD_ANET_ET4P 5233 // ANET ET4P V1.x (STM32F407VG)
#define BOARD_FYSETC_CHEETAH_V20 5234 // FYSETC Cheetah V2.0 (STM32F401RC)
#define BOARD_FYSETC_CHEETAH_V30 5235 // FYSETC Cheetah V3.0 (STM32F446RC)
#define BOARD_TH3D_EZBOARD_V2 5236 // TH3D EZBoard v2.0 (STM32F405RG)
#define BOARD_OPULO_LUMEN_REV3 5237 // Opulo Lumen PnP Controller REV3 (STM32F407VE / STM32F407VG)
#define BOARD_OPULO_LUMEN_REV4 5238 // Opulo Lumen PnP Controller REV4 (STM32F407VE / STM32F407VG)
#define BOARD_MKS_ROBIN_NANO_V1_3_F4 5239 // MKS Robin Nano V1.3 and MKS Robin Nano-S V1.3 (STM32F407VE)
#define BOARD_MKS_EAGLE 5240 // MKS Eagle (STM32F407VE)
#define BOARD_ARTILLERY_RUBY 5241 // Artillery Ruby (STM32F401RC)
#define BOARD_CREALITY_V24S1_301F4 5242 // Creality v2.4.S1_301F4 (STM32F401RC) as found in the Ender-3 S1 F4
#define BOARD_CREALITY_CR4NTXXC10 5243 // Creality E3 Free-runs Silent Motherboard (STM32F401RET6)
#define BOARD_FYSETC_SPIDER_KING_V1_F407 5244 // FYSETC Spider King v1 (STM32F407ZG)
#define BOARD_FYSETC_SPIDER_KING_V1_1_F407 5245 // FYSETC Spider King v1.1 (STM32F407ZG)
#define BOARD_MKS_SKIPR_V1 5246 // MKS SKIPR v1.0 all-in-one board (STM32F407VE)
#define BOARD_TRONXY_CXY_446_V10 5247 // TRONXY CXY-446-V10-220413/CXY-V6-191121 (STM32F446ZE)
#define BOARD_CREALITY_F401RE 5248 // Creality CR4NS200141C13 (STM32F401RE) as found in the Ender-5 S1
#define BOARD_BLACKPILL_CUSTOM 5249 // Custom board based on STM32F401CDU6.
#define BOARD_I3DBEEZ9_V1 5250 // I3DBEEZ9 V1 (STM32F407ZG)
#define BOARD_MELLOW_FLY_E3_V2 5251 // Mellow Fly E3 V2 (STM32F407VG)
#define BOARD_BLACKBEEZMINI_V1 5252 // BlackBeezMini V1 (STM32F401CCU6)
#define BOARD_XTLW_CLIMBER_8TH 5253 // XTLW Climber-8th (STM32F407VGT6)
#define BOARD_FLY_RRF_E3_V1 5254 // Fly RRF E3 V1.0 (STM32F407VG)
#define BOARD_FLY_SUPER8 5255 // Fly SUPER8 (STM32F407ZGT6)
#define BOARD_FLY_D8 5256 // FLY D8 (STM32F407VG)
#define BOARD_FLY_CDY_V3 5257 // FLY CDY V3 (STM32F407VGT6)
#define BOARD_ZNP_ROBIN_NANO 5258 // Elegoo Neptune 2 v1.2 board
#define BOARD_ZNP_ROBIN_NANO_V1_3 5259 // Elegoo Neptune 2 v1.3 board
#define BOARD_MKS_NEPTUNE_X 5260 // Elegoo Neptune X
#define BOARD_MKS_NEPTUNE_3 5261 // Elegoo Neptune 3
//
// Other ARM Cortex-M4
@ -506,21 +509,24 @@
// ARM Cortex-M7
//
#define BOARD_REMRAM_V1 6000 // RemRam v1
#define BOARD_NUCLEO_F767ZI 6001 // ST NUCLEO-F767ZI Dev Board
#define BOARD_BTT_SKR_SE_BX_V2 6002 // BigTreeTech SKR SE BX V2.0 (STM32H743II)
#define BOARD_BTT_SKR_SE_BX_V3 6003 // BigTreeTech SKR SE BX V3.0 (STM32H743II)
#define BOARD_BTT_SKR_V3_0 6004 // BigTreeTech SKR V3.0 (STM32H743VI / STM32H723VG)
#define BOARD_BTT_SKR_V3_0_EZ 6005 // BigTreeTech SKR V3.0 EZ (STM32H743VI / STM32H723VG)
#define BOARD_BTT_OCTOPUS_MAX_EZ_V1_0 6006 // BigTreeTech Octopus Max EZ V1.0 (STM32H723ZE)
#define BOARD_BTT_OCTOPUS_PRO_V1_0_1 6007 // BigTreeTech Octopus Pro v1.0.1 (STM32H723ZE)
#define BOARD_BTT_OCTOPUS_PRO_V1_1 6008 // BigTreeTech Octopus Pro v1.1 (STM32H723ZE)
#define BOARD_BTT_MANTA_M8P_V2_0 6009 // BigTreeTech Manta M8P V2.0 (STM32H723ZE)
#define BOARD_BTT_KRAKEN_V1_0 6010 // BigTreeTech Kraken v1.0 (STM32H723ZG)
#define BOARD_TEENSY41 6011 // Teensy 4.1
#define BOARD_T41U5XBB 6012 // T41U5XBB Teensy 4.1 breakout board
#define BOARD_FLY_D8_PRO 6013 // FLY_D8_PRO (STM32H723VG)
#define BOARD_FLY_SUPER8_PRO 6014 // FLY SUPER8 PRO (STM32H723ZG)
#define BOARD_REMRAM_V1 6000 // RemRam v1
#define BOARD_NUCLEO_F767ZI 6001 // ST NUCLEO-F767ZI Dev Board
#define BOARD_BTT_SKR_SE_BX_V2 6002 // BigTreeTech SKR SE BX V2.0 (STM32H743II)
#define BOARD_BTT_SKR_SE_BX_V3 6003 // BigTreeTech SKR SE BX V3.0 (STM32H743II)
#define BOARD_BTT_SKR_V3_0 6004 // BigTreeTech SKR V3.0 (STM32H743VI / STM32H723VG)
#define BOARD_BTT_SKR_V3_0_EZ 6005 // BigTreeTech SKR V3.0 EZ (STM32H743VI / STM32H723VG)
#define BOARD_BTT_OCTOPUS_MAX_EZ_V1_0 6006 // BigTreeTech Octopus Max EZ V1.0 (STM32H723ZE)
#define BOARD_BTT_OCTOPUS_PRO_V1_0_1 6007 // BigTreeTech Octopus Pro v1.0.1 (STM32H723ZE)
#define BOARD_BTT_OCTOPUS_PRO_V1_1 6008 // BigTreeTech Octopus Pro v1.1 (STM32H723ZE)
#define BOARD_BTT_MANTA_M8P_V2_0 6009 // BigTreeTech Manta M8P V2.0 (STM32H723ZE)
#define BOARD_BTT_KRAKEN_V1_0 6010 // BigTreeTech Kraken v1.0 (STM32H723ZG)
#define BOARD_TEENSY40 6011 // Teensy 4.0
#define BOARD_TEENSY41 6012 // Teensy 4.1
#define BOARD_T41U5XBB 6013 // T41U5XBB Teensy 4.1 breakout board
#define BOARD_FLY_D8_PRO 6014 // FLY_D8_PRO (STM32H723VG)
#define BOARD_FLY_SUPER8_PRO 6015 // FLY SUPER8 PRO (STM32H723ZG)
#define BOARD_FYSETC_SPIDER_KING_V1_H723 6016 // FYSETC Spider King v1 (STM32H723ZG)
#define BOARD_FYSETC_SPIDER_KING_V1_1_H723 6017 // FYSETC Spider King v1.1 (STM32H723ZG)
//
// Espressif ESP32 WiFi

View file

@ -296,6 +296,7 @@
#define STR_TOOL_CHANGING "Tool-changing"
#define STR_HOTEND_OFFSETS "Hotend offsets"
#define STR_SERVO_ANGLES "Servo Angles"
#define STR_AUTOTEMP "Auto Temp Control"
#define STR_HOTEND_PID "Hotend PID"
#define STR_BED_PID "Bed PID"
#define STR_CHAMBER_PID "Chamber PID"
@ -358,6 +359,21 @@
#define STR_Z2 STR_C "2"
#define STR_Z3 STR_C "3"
#define STR_Z4 STR_C "4"
#if CORE_IS_XY || CORE_IS_XZ
#define STEPPER_A_NAME 'A'
#else
#define STEPPER_A_NAME 'X'
#endif
#if CORE_IS_XY || CORE_IS_YZ
#define STEPPER_B_NAME 'B'
#else
#define STEPPER_B_NAME 'Y'
#endif
#if CORE_IS_XZ || CORE_IS_YZ
#define STEPPER_C_NAME 'C'
#else
#define STEPPER_C_NAME 'Z'
#endif
//
// Endstop Names used by Endstops::report_states

View file

@ -58,6 +58,7 @@
// Macros to make a string from a macro
#define STRINGIFY_(M) #M
#define STRINGIFY(M) STRINGIFY_(M)
#define CHARIFY(M) STRINGIFY(M)[0]
#define A(CODE) " " CODE "\n\t"
#define L(CODE) CODE ":\n\t"

View file

@ -228,7 +228,7 @@ struct SerialBase {
// Handle negative numbers
if (number < 0.0) {
write('-');
number = -number;
number *= -1;
}
// Round correctly so that print(1.999, 2) prints as "2.00"

View file

@ -167,6 +167,21 @@ template <class L, class R> struct IF<true, L, R> { typedef L type; };
#define GANG_ITEM_E(N)
#endif
// Emitters for code that only cares about XYZE and not IJKUVW
#define CARTES_COUNT TERN(HAS_EXTRUDERS, INCREMENT(XYZ_COUNT), XYZ_COUNT)
#define CARTES_LIST(x,y,z,e) XYZ_LIST(x,y,z) LIST_ITEM_E(e)
#define CARTES_PAIRED_LIST(V...) LIST_N(DOUBLE(CARTES_COUNT), V)
#define CARTES_ARRAY(x,y,z,e) { CARTES_LIST(x,y,z,e) }
#define CARTES_CODE(x,y,z,e) XYZ_CODE(x,y,z) CODE_ITEM_E(e)
#define CARTES_GANG(x,y,z,e) XYZ_GANG(x,y,z) GANG_ITEM_E(e)
#define CARTES_AXIS_NAMES CARTES_LIST(X,Y,Z,E)
#define CARTES_MAP(F) MAP(F, CARTES_AXIS_NAMES)
#if CARTES_COUNT
#define CARTES_COMMA ,
#else
#define CARTES_COMMA
#endif
#define AXIS_COLLISION(L) (AXIS4_NAME == L || AXIS5_NAME == L || AXIS6_NAME == L || AXIS7_NAME == L || AXIS8_NAME == L || AXIS9_NAME == L)
// Helpers
@ -223,6 +238,24 @@ struct Flags<N, false> {
FI bool operator[](const int n) const { return test(n); }
FI int size() const { return sizeof(b); }
FI operator bool() const { return b != 0; }
FI Flags<N>& operator|=(Flags<N> &p) const { b |= p.b; return *this; }
FI Flags<N>& operator&=(Flags<N> &p) const { b &= p.b; return *this; }
FI Flags<N>& operator^=(Flags<N> &p) const { b ^= p.b; return *this; }
FI Flags<N>& operator|=(const flagbits_t &p) { b |= flagbits_t(p); return *this; }
FI Flags<N>& operator&=(const flagbits_t &p) { b &= flagbits_t(p); return *this; }
FI Flags<N>& operator^=(const flagbits_t &p) { b ^= flagbits_t(p); return *this; }
FI Flags<N> operator|(Flags<N> &p) const { return Flags<N>(b | p.b); }
FI Flags<N> operator&(Flags<N> &p) const { return Flags<N>(b & p.b); }
FI Flags<N> operator^(Flags<N> &p) const { return Flags<N>(b ^ p.b); }
FI Flags<N> operator~() const { return Flags<N>(~b); }
FI flagbits_t operator|(const flagbits_t &p) const { return b | flagbits_t(p); }
FI flagbits_t operator&(const flagbits_t &p) const { return b & flagbits_t(p); }
FI flagbits_t operator^(const flagbits_t &p) const { return b ^ flagbits_t(p); }
};
// Flag bits for more than 64 states
@ -371,7 +404,7 @@ typedef IF<TERN0(ABL_USES_GRID, (GRID_MAX_POINTS > 255)), uint16_t, uint8_t>::ty
#define MMS_TO_MMM(MM_S) (static_cast<float>(MM_S) * 60.0f)
// Packaged character for C macro and other usage
typedef struct SerialChar { char c; SerialChar(char n) : c(n) { } } serial_char_t;
typedef struct SerialChar { char c; SerialChar(const char n) : c(n) { } } serial_char_t;
#define C(c) serial_char_t(c)
// Packaged types: float with precision and/or width; a repeated space/character
@ -477,7 +510,7 @@ typedef ab_float_t ab_pos_t;
typedef abc_float_t abc_pos_t;
typedef abce_float_t abce_pos_t;
// External conversion methods
// External conversion methods (motion.h)
void toLogical(xy_pos_t &raw);
void toLogical(xyz_pos_t &raw);
void toLogical(xyze_pos_t &raw);
@ -532,13 +565,18 @@ struct XYval {
FI constexpr T large() const { return _MAX(x, y); }
// Explicit copy and copies with conversion
FI constexpr XYval<T> copy() const { return *this; }
FI constexpr XYval<T> ABS() const { return { T(_ABS(x)), T(_ABS(y)) }; }
FI constexpr XYval<int16_t> asInt() const { return { int16_t(x), int16_t(y) }; }
FI constexpr XYval<int32_t> asLong() const { return { int32_t(x), int32_t(y) }; }
FI constexpr XYval<int32_t> ROUNDL() const { return { int32_t(LROUND(x)), int32_t(LROUND(y)) }; }
FI constexpr XYval<float> asFloat() const { return { static_cast<float>(x), static_cast<float>(y) }; }
FI constexpr XYval<float> reciprocal() const { return { _RECIP(x), _RECIP(y) }; }
FI constexpr XYval<T> copy() const { return *this; }
FI constexpr XYval<T> ABS() const { return { T(_ABS(x)), T(_ABS(y)) }; }
FI constexpr XYval<int32_t> ROUNDL() const { return { int32_t(LROUND(x)), int32_t(LROUND(y)) }; }
FI constexpr XYval<float> reciprocal() const { return { _RECIP(x), _RECIP(y) }; }
// Conversion to other types
FI constexpr XYval<int16_t> asInt16() const { return { int16_t(x), int16_t(y) }; }
FI constexpr XYval<int32_t> asInt32() const { return { int32_t(x), int32_t(y) }; }
FI constexpr XYval<uint32_t> asUInt32() const { return { uint32_t(x), uint32_t(y) }; }
FI constexpr XYval<int64_t> asInt64() const { return { int64_t(x), int64_t(y) }; }
FI constexpr XYval<uint64_t> asUInt64() const { return { uint64_t(x), uint64_t(y) }; }
FI constexpr XYval<float> asFloat() const { return { static_cast<float>(x), static_cast<float>(y) }; }
// Marlin workspace shifting is done with G92 and M206
FI XYval<float> asLogical() const { XYval<float> o = asFloat(); toLogical(o); return o; }
@ -610,6 +648,26 @@ struct XYval {
FI bool operator!=(const XYval<T> &rs) const { return !operator==(rs); }
FI bool operator!=(const XYZval<T> &rs) const { return !operator==(rs); }
FI bool operator!=(const XYZEval<T> &rs) const { return !operator==(rs); }
// Exact comparison to a single value
FI bool operator==(const T &p) const { return x == p && y == p; }
FI bool operator!=(const T &p) const { return !operator==(p); }
FI bool operator< (const XYval<T> &rs) const { return x < rs.x && y < rs.y; }
FI bool operator<=(const XYval<T> &rs) const { return x <= rs.x && y <= rs.y; }
FI bool operator> (const XYval<T> &rs) const { return x > rs.x && y > rs.y; }
FI bool operator>=(const XYval<T> &rs) const { return x >= rs.x && y >= rs.y; }
FI bool operator< (const XYZval<T> &rs) const { return true XY_GANG(&& x < rs.x, && y < rs.y); }
FI bool operator<=(const XYZval<T> &rs) const { return true XY_GANG(&& x <= rs.x, && y <= rs.y); }
FI bool operator> (const XYZval<T> &rs) const { return true XY_GANG(&& x > rs.x, && y > rs.y); }
FI bool operator>=(const XYZval<T> &rs) const { return true XY_GANG(&& x >= rs.x, && y >= rs.y); }
FI bool operator< (const XYZEval<T> &rs) const { return true XY_GANG(&& x < rs.x, && y < rs.y); }
FI bool operator<=(const XYZEval<T> &rs) const { return true XY_GANG(&& x <= rs.x, && y <= rs.y); }
FI bool operator> (const XYZEval<T> &rs) const { return true XY_GANG(&& x > rs.x, && y > rs.y); }
FI bool operator>=(const XYZEval<T> &rs) const { return true XY_GANG(&& x >= rs.x, && y >= rs.y); }
};
//
@ -686,12 +744,17 @@ struct XYZval {
// Explicit copy and copies with conversion
FI constexpr XYZval<T> copy() const { XYZval<T> o = *this; return o; }
FI constexpr XYZval<T> ABS() const { return NUM_AXIS_ARRAY(T(_ABS(x)), T(_ABS(y)), T(_ABS(z)), T(_ABS(i)), T(_ABS(j)), T(_ABS(k)), T(_ABS(u)), T(_ABS(v)), T(_ABS(w))); }
FI constexpr XYZval<int16_t> asInt() const { return NUM_AXIS_ARRAY(int16_t(x), int16_t(y), int16_t(z), int16_t(i), int16_t(j), int16_t(k), int16_t(u), int16_t(v), int16_t(w)); }
FI constexpr XYZval<int32_t> asLong() const { return NUM_AXIS_ARRAY(int32_t(x), int32_t(y), int32_t(z), int32_t(i), int32_t(j), int32_t(k), int32_t(u), int32_t(v), int32_t(w)); }
FI constexpr XYZval<int32_t> ROUNDL() const { return NUM_AXIS_ARRAY(int32_t(LROUND(x)), int32_t(LROUND(y)), int32_t(LROUND(z)), int32_t(LROUND(i)), int32_t(LROUND(j)), int32_t(LROUND(k)), int32_t(LROUND(u)), int32_t(LROUND(v)), int32_t(LROUND(w))); }
FI constexpr XYZval<float> asFloat() const { return NUM_AXIS_ARRAY(static_cast<float>(x), static_cast<float>(y), static_cast<float>(z), static_cast<float>(i), static_cast<float>(j), static_cast<float>(k), static_cast<float>(u), static_cast<float>(v), static_cast<float>(w)); }
FI constexpr XYZval<float> reciprocal() const { return NUM_AXIS_ARRAY(_RECIP(x), _RECIP(y), _RECIP(z), _RECIP(i), _RECIP(j), _RECIP(k), _RECIP(u), _RECIP(v), _RECIP(w)); }
// Conversion to other types
FI constexpr XYZval<int16_t> asInt16() const { return NUM_AXIS_ARRAY(int16_t(x), int16_t(y), int16_t(z), int16_t(i), int16_t(j), int16_t(k), int16_t(u), int16_t(v), int16_t(w)); }
FI constexpr XYZval<int32_t> asInt32() const { return NUM_AXIS_ARRAY(int32_t(x), int32_t(y), int32_t(z), int32_t(i), int32_t(j), int32_t(k), int32_t(u), int32_t(v), int32_t(w)); }
FI constexpr XYZval<uint32_t> asUInt32() const { return NUM_AXIS_ARRAY(uint32_t(x), uint32_t(y), uint32_t(z), uint32_t(i), uint32_t(j), uint32_t(k), uint32_t(u), uint32_t(v), uint32_t(w)); }
FI constexpr XYZval<int64_t> asInt64() const { return NUM_AXIS_ARRAY(int64_t(x), int64_t(y), int64_t(z), int64_t(i), int64_t(j), int64_t(k), int64_t(u), int64_t(v), int64_t(w)); }
FI constexpr XYZval<uint64_t> asUInt64() const { return NUM_AXIS_ARRAY(uint64_t(x), uint64_t(y), uint64_t(z), uint64_t(i), uint64_t(j), uint64_t(k), uint64_t(u), uint64_t(v), uint64_t(w)); }
FI constexpr XYZval<float> asFloat() const { return NUM_AXIS_ARRAY(static_cast<float>(x), static_cast<float>(y), static_cast<float>(z), static_cast<float>(i), static_cast<float>(j), static_cast<float>(k), static_cast<float>(u), static_cast<float>(v), static_cast<float>(w)); }
// Marlin workspace shifting is done with G92 and M206
FI XYZval<float> asLogical() const { XYZval<float> o = asFloat(); toLogical(o); return o; }
FI XYZval<float> asNative() const { XYZval<float> o = asFloat(); toNative(o); return o; }
@ -757,8 +820,23 @@ struct XYZval {
FI XYZval<T>& operator<<=(const int &p) { NUM_AXIS_CODE(_LSE(x), _LSE(y), _LSE(z), _LSE(i), _LSE(j), _LSE(k), _LSE(u), _LSE(v), _LSE(w)); return *this; }
// Exact comparisons. For floats a "NEAR" operation may be better.
FI bool operator==(const XYZEval<T> &rs) const { return true NUM_AXIS_GANG(&& x == rs.x, && y == rs.y, && z == rs.z, && i == rs.i, && j == rs.j, && k == rs.k, && u == rs.u, && v == rs.v, && w == rs.w); }
FI bool operator==(const XYZEval<T> &rs) const { return ENABLED(HAS_X_AXIS) NUM_AXIS_GANG(&& x == rs.x, && y == rs.y, && z == rs.z, && i == rs.i, && j == rs.j, && k == rs.k, && u == rs.u, && v == rs.v, && w == rs.w); }
FI bool operator!=(const XYZEval<T> &rs) const { return !operator==(rs); }
// Exact comparison to a single value
FI bool operator==(const T &p) const { return ENABLED(HAS_X_AXIS) NUM_AXIS_GANG(&& x == p, && y == p, && z == p, && i == p, && j == p, && k == p, && u == p, && v == p, && w == p); }
FI bool operator!=(const T &p) const { return !operator==(p); }
FI bool operator< (const XYZval<T> &rs) const { return true NUM_AXIS_GANG(&& x < rs.x, && y < rs.y, && z < rs.z, && i < rs.i, && j < rs.j, && k < rs.k, && u < rs.u, && v < rs.v, && w < rs.w); }
FI bool operator<=(const XYZval<T> &rs) const { return true NUM_AXIS_GANG(&& x <= rs.x, && y <= rs.y, && z <= rs.z, && i <= rs.i, && j <= rs.j, && k <= rs.k, && u <= rs.u, && v <= rs.v, && w <= rs.w); }
FI bool operator> (const XYZval<T> &rs) const { return true NUM_AXIS_GANG(&& x > rs.x, && y > rs.y, && z > rs.z, && i > rs.i, && j > rs.j, && k > rs.k, && u > rs.u, && v > rs.v, && w > rs.w); }
FI bool operator>=(const XYZval<T> &rs) const { return true NUM_AXIS_GANG(&& x >= rs.x, && y >= rs.y, && z >= rs.z, && i >= rs.i, && j >= rs.j, && k >= rs.k, && u >= rs.u, && v >= rs.v, && w >= rs.w); }
FI bool operator< (const XYZEval<T> &rs) const { return true NUM_AXIS_GANG(&& x < rs.x, && y < rs.y, && z < rs.z, && i < rs.i, && j < rs.j, && k < rs.k, && u < rs.u, && v < rs.v, && w < rs.w); }
FI bool operator<=(const XYZEval<T> &rs) const { return true NUM_AXIS_GANG(&& x <= rs.x, && y <= rs.y, && z <= rs.z, && i <= rs.i, && j <= rs.j, && k <= rs.k, && u <= rs.u, && v <= rs.v, && w <= rs.w); }
FI bool operator> (const XYZEval<T> &rs) const { return true NUM_AXIS_GANG(&& x > rs.x, && y > rs.y, && z > rs.z, && i > rs.i, && j > rs.j, && k > rs.k, && u > rs.u, && v > rs.v, && w > rs.w); }
FI bool operator>=(const XYZEval<T> &rs) const { return true NUM_AXIS_GANG(&& x >= rs.x, && y >= rs.y, && z >= rs.z, && i >= rs.i, && j >= rs.j, && k >= rs.k, && u >= rs.u, && v >= rs.v, && w >= rs.w); }
};
//
@ -789,7 +867,7 @@ struct XYZEval {
FI void set(const XYZval<T> &pxyz, const T pe) { set(pxyz); e = pe; }
FI void set(LOGICAL_AXIS_ARGS_LC(const T)) { LOGICAL_AXIS_CODE(_e = e, a = x, b = y, c = z, _i = i, _j = j, _k = k, _u = u, _v = v, _w = w); }
#if DISTINCT_AXES > LOGICAL_AXES
FI void set(const T (&arr)[DISTINCT_AXES]) { LOGICAL_AXIS_CODE(e = arr[LOGICAL_AXES-1], x = arr[0], y = arr[1], z = arr[2], i = arr[3], j = arr[4], k = arr[5], u = arr[6], v = arr[7], w = arr[8]); }
FI void set(const T (&arr)[DISTINCT_AXES], const uint8_t eindex) { LOGICAL_AXIS_CODE(e = arr[LOGICAL_AXES-1 + eindex], x = arr[0], y = arr[1], z = arr[2], i = arr[3], j = arr[4], k = arr[5], u = arr[6], v = arr[7], w = arr[8]); }
#endif
#endif
@ -834,13 +912,18 @@ struct XYZEval {
FI constexpr T large() const { return _MAX(LOGICAL_AXIS_LIST(e, x, y, z, i, j, k, u, v, w)); }
// Explicit copy and copies with conversion
FI constexpr XYZEval<T> copy() const { XYZEval<T> v = *this; return v; }
FI constexpr XYZEval<T> ABS() const { return LOGICAL_AXIS_ARRAY(T(_ABS(e)), T(_ABS(x)), T(_ABS(y)), T(_ABS(z)), T(_ABS(i)), T(_ABS(j)), T(_ABS(k)), T(_ABS(u)), T(_ABS(v)), T(_ABS(w))); }
FI constexpr XYZEval<int16_t> asInt() const { return LOGICAL_AXIS_ARRAY(int16_t(e), int16_t(x), int16_t(y), int16_t(z), int16_t(i), int16_t(j), int16_t(k), int16_t(u), int16_t(v), int16_t(w)); }
FI constexpr XYZEval<int32_t> asLong() const { return LOGICAL_AXIS_ARRAY(int32_t(e), int32_t(x), int32_t(y), int32_t(z), int32_t(i), int32_t(j), int32_t(k), int32_t(u), int32_t(v), int32_t(w)); }
FI constexpr XYZEval<int32_t> ROUNDL() const { return LOGICAL_AXIS_ARRAY(int32_t(LROUND(e)), int32_t(LROUND(x)), int32_t(LROUND(y)), int32_t(LROUND(z)), int32_t(LROUND(i)), int32_t(LROUND(j)), int32_t(LROUND(k)), int32_t(LROUND(u)), int32_t(LROUND(v)), int32_t(LROUND(w))); }
FI constexpr XYZEval<float> asFloat() const { return LOGICAL_AXIS_ARRAY(static_cast<float>(e), static_cast<float>(x), static_cast<float>(y), static_cast<float>(z), static_cast<float>(i), static_cast<float>(j), static_cast<float>(k), static_cast<float>(u), static_cast<float>(v), static_cast<float>(w)); }
FI constexpr XYZEval<float> reciprocal() const { return LOGICAL_AXIS_ARRAY(_RECIP(e), _RECIP(x), _RECIP(y), _RECIP(z), _RECIP(i), _RECIP(j), _RECIP(k), _RECIP(u), _RECIP(v), _RECIP(w)); }
FI constexpr XYZEval<T> copy() const { XYZEval<T> v = *this; return v; }
FI constexpr XYZEval<T> ABS() const { return LOGICAL_AXIS_ARRAY(T(_ABS(e)), T(_ABS(x)), T(_ABS(y)), T(_ABS(z)), T(_ABS(i)), T(_ABS(j)), T(_ABS(k)), T(_ABS(u)), T(_ABS(v)), T(_ABS(w))); }
FI constexpr XYZEval<int32_t> ROUNDL() const { return LOGICAL_AXIS_ARRAY(int32_t(LROUND(e)), int32_t(LROUND(x)), int32_t(LROUND(y)), int32_t(LROUND(z)), int32_t(LROUND(i)), int32_t(LROUND(j)), int32_t(LROUND(k)), int32_t(LROUND(u)), int32_t(LROUND(v)), int32_t(LROUND(w))); }
FI constexpr XYZEval<float> reciprocal() const { return LOGICAL_AXIS_ARRAY(_RECIP(e), _RECIP(x), _RECIP(y), _RECIP(z), _RECIP(i), _RECIP(j), _RECIP(k), _RECIP(u), _RECIP(v), _RECIP(w)); }
// Conversion to other types
FI constexpr XYZEval<int16_t> asInt16() const { return LOGICAL_AXIS_ARRAY(int16_t(e), int16_t(x), int16_t(y), int16_t(z), int16_t(i), int16_t(j), int16_t(k), int16_t(u), int16_t(v), int16_t(w)); }
FI constexpr XYZEval<int32_t> asInt32() const { return LOGICAL_AXIS_ARRAY(int32_t(e), int32_t(x), int32_t(y), int32_t(z), int32_t(i), int32_t(j), int32_t(k), int32_t(u), int32_t(v), int32_t(w)); }
FI constexpr XYZEval<uint32_t> asUInt32() const { return LOGICAL_AXIS_ARRAY(uint32_t(e), uint32_t(x), uint32_t(y), uint32_t(z), uint32_t(i), uint32_t(j), uint32_t(k), uint32_t(u), uint32_t(v), uint32_t(w)); }
FI constexpr XYZEval<int64_t> asInt64() const { return LOGICAL_AXIS_ARRAY(int64_t(e), int64_t(x), int64_t(y), int64_t(z), int64_t(i), int64_t(j), int64_t(k), int64_t(u), int64_t(v), int64_t(w)); }
FI constexpr XYZEval<uint64_t> asUInt64() const { return LOGICAL_AXIS_ARRAY(uint64_t(e), uint64_t(x), uint64_t(y), uint64_t(z), uint64_t(i), uint64_t(j), uint64_t(k), uint64_t(u), uint64_t(v), uint64_t(w)); }
FI constexpr XYZEval<float> asFloat() const { return LOGICAL_AXIS_ARRAY(static_cast<float>(e), static_cast<float>(x), static_cast<float>(y), static_cast<float>(z), static_cast<float>(i), static_cast<float>(j), static_cast<float>(k), static_cast<float>(u), static_cast<float>(v), static_cast<float>(w)); }
// Marlin workspace shifting is done with G92 and M206
FI XYZEval<float> asLogical() const { XYZEval<float> o = asFloat(); toLogical(o); return o; }
@ -874,7 +957,10 @@ struct XYZEval {
FI constexpr XYZEval<T> operator- (const XYZEval<T> &rs) const { return LOGICAL_AXIS_ARRAY(T(e - rs.e), T(x - rs.x), T(y - rs.y), T(z - rs.z), T(i - rs.i), T(j - rs.j), T(k - rs.k), T(u - rs.u), T(v - rs.v), T(w - rs.w)); }
FI constexpr XYZEval<T> operator* (const XYZEval<T> &rs) const { return LOGICAL_AXIS_ARRAY(T(e * rs.e), T(x * rs.x), T(y * rs.y), T(z * rs.z), T(i * rs.i), T(j * rs.j), T(k * rs.k), T(u * rs.u), T(v * rs.v), T(w * rs.w)); }
FI constexpr XYZEval<T> operator/ (const XYZEval<T> &rs) const { return LOGICAL_AXIS_ARRAY(T(e / rs.e), T(x / rs.x), T(y / rs.y), T(z / rs.z), T(i / rs.i), T(j / rs.j), T(k / rs.k), T(u / rs.u), T(v / rs.v), T(w / rs.w)); }
FI constexpr XYZEval<T> operator+ (const uint32_t &p) const { return LOGICAL_AXIS_ARRAY(T(e + p), T(x + p), T(y + p), T(z + p), T(i + p), T(j + p), T(k + p), T(u + p), T(v + p), T(w + p)); }
FI constexpr XYZEval<T> operator* (const float &p) const { return LOGICAL_AXIS_ARRAY(T(e * p), T(x * p), T(y * p), T(z * p), T(i * p), T(j * p), T(k * p), T(u * p), T(v * p), T(w * p)); }
FI constexpr XYZEval<T> operator* (const uint32_t &p) const { return LOGICAL_AXIS_ARRAY(T(e * p), T(x * p), T(y * p), T(z * p), T(i * p), T(j * p), T(k * p), T(u * p), T(v * p), T(w * p)); }
FI constexpr XYZEval<T> operator& (const int64_t &p) const { return LOGICAL_AXIS_ARRAY(T(e & p), T(x & p), T(y & p), T(z & p), T(i & p), T(j & p), T(k & p), T(u & p), T(v & p), T(w & p)); }
FI constexpr XYZEval<T> operator* (const int &p) const { return LOGICAL_AXIS_ARRAY(e * p, x * p, y * p, z * p, i * p, j * p, k * p, u * p, v * p, w * p); }
FI constexpr XYZEval<T> operator/ (const float &p) const { return LOGICAL_AXIS_ARRAY(T(e / p), T(x / p), T(y / p), T(z / p), T(i / p), T(j / p), T(k / p), T(u / p), T(v / p), T(w / p)); }
FI constexpr XYZEval<T> operator/ (const int &p) const { return LOGICAL_AXIS_ARRAY(e / p, x / p, y / p, z / p, i / p, j / p, k / p, u / p, v / p, w / p); }
@ -905,14 +991,32 @@ struct XYZEval {
FI XYZEval<T>& operator<<=(const int &p) { LOGICAL_AXIS_CODE(_LSE(e), _LSE(x), _LSE(y), _LSE(z), _LSE(i), _LSE(j), _LSE(k), _LSE(u), _LSE(v), _LSE(w)); return *this; }
// Exact comparisons. For floats a "NEAR" operation may be better.
FI bool operator==(const XYZval<T> &rs) const { return true NUM_AXIS_GANG(&& x == rs.x, && y == rs.y, && z == rs.z, && i == rs.i, && j == rs.j, && k == rs.k, && u == rs.u, && v == rs.v, && w == rs.w); }
FI bool operator==(const XYZEval<T> &rs) const { return true LOGICAL_AXIS_GANG(&& e == rs.e, && x == rs.x, && y == rs.y, && z == rs.z, && i == rs.i, && j == rs.j, && k == rs.k, && u == rs.u, && v == rs.v, && w == rs.w); }
FI bool operator==(const XYZval<T> &rs) const { return ENABLED(HAS_X_AXIS) NUM_AXIS_GANG(&& x == rs.x, && y == rs.y, && z == rs.z, && i == rs.i, && j == rs.j, && k == rs.k, && u == rs.u, && v == rs.v, && w == rs.w); }
FI bool operator==(const XYZEval<T> &rs) const { return ANY(HAS_X_AXIS, HAS_EXTRUDERS) LOGICAL_AXIS_GANG(&& e == rs.e, && x == rs.x, && y == rs.y, && z == rs.z, && i == rs.i, && j == rs.j, && k == rs.k, && u == rs.u, && v == rs.v, && w == rs.w); }
FI bool operator!=(const XYZval<T> &rs) const { return !operator==(rs); }
FI bool operator!=(const XYZEval<T> &rs) const { return !operator==(rs); }
// Exact comparison to a single value
FI bool operator==(const T &p) const { return ENABLED(HAS_X_AXIS) LOGICAL_AXIS_GANG(&& e == p, && x == p, && y == p, && z == p, && i == p, && j == p, && k == p, && u == p, && v == p, && w == p); }
FI bool operator!=(const T &p) const { return !operator==(p); }
FI bool operator< (const XYZEval<T> &rs) const { return true LOGICAL_AXIS_GANG(&& e < rs.e, && x < rs.x, && y < rs.y, && z < rs.z, && i < rs.i, && j < rs.j, && k < rs.k, && u < rs.u, && v < rs.v, && w < rs.w); }
FI bool operator<=(const XYZEval<T> &rs) const { return true LOGICAL_AXIS_GANG(&& e <= rs.e, && x <= rs.x, && y <= rs.y, && z <= rs.z, && i <= rs.i, && j <= rs.j, && k <= rs.k, && u <= rs.u, && v <= rs.v, && w <= rs.w); }
FI bool operator> (const XYZEval<T> &rs) const { return true LOGICAL_AXIS_GANG(&& e > rs.e, && x > rs.x, && y > rs.y, && z > rs.z, && i > rs.i, && j > rs.j, && k > rs.k, && u > rs.u, && v > rs.v, && w > rs.w); }
FI bool operator>=(const XYZEval<T> &rs) const { return true LOGICAL_AXIS_GANG(&& e >= rs.e, && x >= rs.x, && y >= rs.y, && z >= rs.z, && i >= rs.i, && j >= rs.j, && k >= rs.k, && u >= rs.u, && v >= rs.v, && w >= rs.w); }
FI bool operator< (const XYZval<T> &rs) const { return true NUM_AXIS_GANG(&& x < rs.x, && y < rs.y, && z < rs.z, && i < rs.i, && j < rs.j, && k < rs.k, && u < rs.u, && v < rs.v, && w < rs.w); }
FI bool operator<=(const XYZval<T> &rs) const { return true NUM_AXIS_GANG(&& x <= rs.x, && y <= rs.y, && z <= rs.z, && i <= rs.i, && j <= rs.j, && k <= rs.k, && u <= rs.u, && v <= rs.v, && w <= rs.w); }
FI bool operator> (const XYZval<T> &rs) const { return true NUM_AXIS_GANG(&& x > rs.x, && y > rs.y, && z > rs.z, && i > rs.i, && j > rs.j, && k > rs.k, && u > rs.u, && v > rs.v, && w > rs.w); }
FI bool operator>=(const XYZval<T> &rs) const { return true NUM_AXIS_GANG(&& x >= rs.x, && y >= rs.y, && z >= rs.z, && i >= rs.i, && j >= rs.j, && k >= rs.k, && u >= rs.u, && v >= rs.v, && w >= rs.w); }
};
#include <string.h> // for memset
//
// Axis indexed arrays of type T (x[SIZE], y[SIZE], etc.)
//
template<typename T, int SIZE>
struct XYZarray {
typedef T el[SIZE];
@ -1012,6 +1116,9 @@ struct XYZEarray {
FI XYZEval<T> operator[](const int n) const { return XYZval<T>(LOGICAL_AXIS_ARRAY(e[n], x[n], y[n], z[n], i[n], j[n], k[n], u[n], v[n], w[n])); }
};
//
// Axes mapped to bits in a mask of minimum size, bits_t(NUM_AXIS_HEADS)
//
class AxisBits {
public:
typedef bits_t(NUM_AXIS_HEADS) el;
@ -1209,6 +1316,7 @@ public:
FI AxisBits operator|(const AxisBits &p) const { return AxisBits(bits | p.bits); }
FI AxisBits operator&(const AxisBits &p) const { return AxisBits(bits & p.bits); }
FI AxisBits operator^(const AxisBits &p) const { return AxisBits(bits ^ p.bits); }
FI AxisBits operator~() const { return AxisBits(~bits); }
FI operator bool() const { return !!bits; }
FI operator uint16_t() const { return uint16_t(bits & 0xFFFF); }

View file

@ -143,7 +143,7 @@ void safe_delay(millis_t ms) {
SERIAL_ECHOPGM("ABL Adjustment");
LOOP_NUM_AXES(a) {
SERIAL_ECHOPGM_P((PGM_P)pgm_read_ptr(&SP_AXIS_STR[a]));
serial_offset(planner.get_axis_position_mm(AxisEnum(a)) - current_position[a]);
serial_offset(planner.get_axis_position_mm((AxisEnum)a) - current_position[a]);
}
#else
#if ENABLED(AUTO_BED_LEVELING_UBL)

View file

@ -26,7 +26,7 @@
#include "babystep.h"
#include "../MarlinCore.h"
#include "../module/motion.h" // for axes_should_home(), BABYSTEP_ALLOWED
#include "../module/motion.h" // for axis_should_home(), BABYSTEP_ALLOWED
#include "../module/planner.h" // for axis_steps_per_mm[]
#include "../module/stepper.h"
@ -49,7 +49,7 @@ int16_t Babystep::accum;
void Babystep::step_axis(const AxisEnum axis) {
const int16_t curTodo = steps[BS_AXIS_IND(axis)]; // get rid of volatile for performance
if (curTodo) {
stepper.do_babystep((AxisEnum)axis, curTodo > 0);
stepper.do_babystep(axis, curTodo > 0);
if (curTodo > 0) steps[BS_AXIS_IND(axis)]--; else steps[BS_AXIS_IND(axis)]++;
}
}

View file

@ -101,7 +101,7 @@ bool BDS_Leveling::check(const uint16_t data, const bool raw_data/*=false*/, con
}
float BDS_Leveling::interpret(const uint16_t data) {
return (data & 0x3FF) / 100.0f;
return (data & 0x3FF) * 0.01f;
}
float BDS_Leveling::read() {

View file

@ -48,7 +48,7 @@
#include "../hilbert_curve.h"
#endif
#if FT_MOTION_DISABLE_FOR_PROBING
#if ENABLED(FT_MOTION)
#include "../../../module/ft_motion.h"
#endif
@ -313,9 +313,8 @@ void unified_bed_leveling::G29() {
const uint8_t p_val = parser.byteval('P');
const bool may_move = p_val == 1 || p_val == 2 || p_val == 4 || parser.seen_test('J');
#if FT_MOTION_DISABLE_FOR_PROBING
FTMotionDisableInScope FT_Disabler; // Disable Fixed-Time Motion for probing
#endif
// Potentially disable Fixed-Time Motion for probing
TERN_(FT_MOTION, FTM_DISABLE_IN_SCOPE());
// Check for commands that require the printer to be homed
if (may_move) {
@ -398,7 +397,7 @@ void unified_bed_leveling::G29() {
if (parser.seen('Q')) {
const int16_t test_pattern = parser.has_value() ? parser.value_int() : -99;
if (!WITHIN(test_pattern, TERN0(UBL_DEVEL_DEBUGGING, -1), 2)) {
SERIAL_ECHOLNPGM("?Invalid (Q) test pattern. (" TERN(UBL_DEVEL_DEBUGGING, "-1", "0") " to 2)\n");
SERIAL_ECHOLN(F("?Invalid "), F("(Q) test pattern. (" TERN(UBL_DEVEL_DEBUGGING, "-1", "0") " to 2)\n"));
return;
}
SERIAL_ECHOLNPGM("Applying test pattern.\n");
@ -649,7 +648,7 @@ void unified_bed_leveling::G29() {
}
if (!WITHIN(param.KLS_storage_slot, 0, a - 1)) {
SERIAL_ECHOLNPGM("?Invalid storage slot.\n?Use 0 to ", a - 1);
SERIAL_ECHOLN(F("?Invalid "), F("storage slot.\n?Use 0 to "), a - 1);
return;
}
@ -677,7 +676,7 @@ void unified_bed_leveling::G29() {
}
if (!WITHIN(param.KLS_storage_slot, 0, a - 1)) {
SERIAL_ECHOLNPGM("?Invalid storage slot.\n?Use 0 to ", a - 1);
SERIAL_ECHOLN(F("?Invalid "), F("storage slot.\n?Use 0 to "), a - 1);
goto LEAVE;
}
@ -782,7 +781,7 @@ void unified_bed_leveling::shift_mesh_height(const float zoffs) {
const grid_count_t point_num = (GRID_MAX_POINTS - count) + 1;
SERIAL_ECHOLNPGM("Probing mesh point ", point_num, "/", GRID_MAX_POINTS, ".");
TERN_(HAS_STATUS_MESSAGE, ui.status_printf(0, F(S_FMT " %i/%i"), GET_TEXT_F(MSG_PROBING_POINT), point_num, int(GRID_MAX_POINTS)));
TERN_(HAS_STATUS_MESSAGE, ui.status_printf(0, F(S_FMT " %i/%i"), GET_TEXT(MSG_PROBING_POINT), point_num, int(GRID_MAX_POINTS)));
TERN_(HAS_BACKLIGHT_TIMEOUT, ui.refresh_backlight_timeout());
#if HAS_MARLINUI_MENU
@ -1183,7 +1182,7 @@ bool unified_bed_leveling::G29_parse_parameters() {
#if HAS_BED_PROBE
param.J_grid_size = parser.value_byte();
if (param.J_grid_size && !WITHIN(param.J_grid_size, 2, 9)) {
SERIAL_ECHOLNPGM("?Invalid grid size (J) specified (2-9).\n");
SERIAL_ECHOLN(F("?Invalid "), F("grid size (J) specified (2-9).\n"));
err_flag = true;
}
#else
@ -1511,7 +1510,7 @@ void unified_bed_leveling::smart_fill_mesh() {
for (uint8_t i = 0; i < 3; ++i) {
SERIAL_ECHOLNPGM("Tilting mesh (", i + 1, "/3)");
TERN_(HAS_STATUS_MESSAGE, ui.status_printf(0, F(S_FMT " %i/3"), GET_TEXT_F(MSG_LCD_TILTING_MESH), i + 1));
TERN_(HAS_STATUS_MESSAGE, ui.status_printf(0, F(S_FMT " %i/3"), GET_TEXT(MSG_LCD_TILTING_MESH), i + 1));
measured_z = probe.probe_at_point(points[i], i < 2 ? PROBE_PT_RAISE : PROBE_PT_LAST_STOW, param.V_verbosity);
if ((abort_flag = isnan(measured_z))) break;
@ -1567,7 +1566,7 @@ void unified_bed_leveling::smart_fill_mesh() {
#endif
SERIAL_ECHOLNPGM("Tilting mesh point ", point_num, "/", total_points, "\n");
TERN_(HAS_STATUS_MESSAGE, ui.status_printf(0, F(S_FMT " %i/%i"), GET_TEXT_F(MSG_LCD_TILTING_MESH), point_num, total_points));
TERN_(HAS_STATUS_MESSAGE, ui.status_printf(0, F(S_FMT " %i/%i"), GET_TEXT(MSG_LCD_TILTING_MESH), point_num, total_points));
measured_z = probe.probe_at_point(rpos, parser.seen_test('E') ? PROBE_PT_STOW : PROBE_PT_RAISE, param.V_verbosity); // TODO: Needs error handling
@ -1852,7 +1851,7 @@ void unified_bed_leveling::smart_fill_mesh() {
}
if (!parser.has_value() || !WITHIN(parser.value_int(), 0, a - 1)) {
SERIAL_ECHOLNPGM("?Invalid storage slot.\n?Use 0 to ", a - 1);
SERIAL_ECHOLN(F("?Invalid "), F("storage slot.\n?Use 0 to "), a - 1);
return;
}

View file

@ -68,7 +68,7 @@ void StepperDAC::set_current_value(const uint8_t channel, uint16_t val) {
}
void StepperDAC::set_current_percent(const uint8_t channel, float val) {
set_current_value(channel, _MIN(val, 100.0f) * (DAC_STEPPER_MAX) / 100.0f);
set_current_value(channel, _MIN(val, 100.0f) * (DAC_STEPPER_MAX) * 0.01f);
}
static float dac_perc(int8_t n) { return mcp4728.getDrvPct(dac_order[n]); }
@ -87,7 +87,7 @@ void StepperDAC::print_values() {
LOOP_LOGICAL_AXES(a) {
SERIAL_CHAR(' ', IAXIS_CHAR(a), ':');
SERIAL_ECHO(dac_perc(a));
SERIAL_ECHOPGM_P(PSTR(" ("), dac_amps(AxisEnum(a)), PSTR(")"));
SERIAL_ECHOPGM_P(PSTR(" ("), dac_amps((AxisEnum)a), PSTR(")"));
}
#if HAS_EXTRUDERS
SERIAL_ECHOLNPGM_P(SP_E_LBL, dac_perc(E_AXIS), PSTR(" ("), dac_amps(E_AXIS), PSTR(")"));

View file

@ -33,6 +33,9 @@
// Static data members
bool EmergencyParser::killed_by_M112, // = false
EmergencyParser::quickstop_by_M410,
#if ENABLED(FTM_RESONANCE_TEST)
EmergencyParser::rt_stop_by_M496, // = false
#endif
#if HAS_MEDIA
EmergencyParser::sd_abort_by_M524,
#endif
@ -147,9 +150,22 @@ void EmergencyParser::update(EmergencyParser::State &state, const uint8_t c) {
case EP_M10: state = (c == '8') ? EP_M108 : EP_IGNORE; break;
case EP_M11: state = (c == '2') ? EP_M112 : EP_IGNORE; break;
case EP_M4: state = (c == '1') ? EP_M41 : EP_IGNORE; break;
case EP_M4:
switch (c) {
case '1' :state = EP_M41; break;
#if ENABLED(FT_MOTION_RESONANCE_TEST)
case '9': state = EP_M49; break;
#endif
default: state = EP_IGNORE;
}
break;
case EP_M41: state = (c == '0') ? EP_M410 : EP_IGNORE; break;
#if ENABLED(FTM_RESONANCE_TEST)
case EP_M49: state = (c == '6') ? EP_M496 : EP_IGNORE; break;
#endif
#if HAS_MEDIA
case EP_M5: state = (c == '2') ? EP_M52 : EP_IGNORE; break;
case EP_M52: state = (c == '4') ? EP_M524 : EP_IGNORE; break;
@ -195,6 +211,9 @@ void EmergencyParser::update(EmergencyParser::State &state, const uint8_t c) {
case EP_M108: wait_for_user = wait_for_heatup = false; break;
case EP_M112: killed_by_M112 = true; break;
case EP_M410: quickstop_by_M410 = true; break;
#if ENABLED(FTM_RESONANCE_TEST)
case EP_M496: rt_stop_by_M496 = true; break;
#endif
#if ENABLED(EP_BABYSTEPPING)
case EP_M293: babystep.ep_babysteps++; break;
case EP_M294: babystep.ep_babysteps--; break;

View file

@ -43,6 +43,9 @@ public:
#if HAS_MEDIA
EP_M5, EP_M52, EP_M524,
#endif
#if ENABLED(FTM_RESONANCE_TEST)
EP_M49, EP_M496,
#endif
#if ENABLED(EP_BABYSTEPPING)
EP_M2, EP_M29, EP_M293, EP_M294,
#endif
@ -64,6 +67,10 @@ public:
static bool killed_by_M112;
static bool quickstop_by_M410;
#if ENABLED(FTM_RESONANCE_TEST)
static bool rt_stop_by_M496;
#endif
#if HAS_MEDIA
static bool sd_abort_by_M524;
#endif

View file

@ -801,7 +801,7 @@ void I2CPositionEncodersMgr::M860() {
if (I2CPE_idx == 0xFF) {
LOOP_LOGICAL_AXES(i) {
if (!I2CPE_anyaxis || parser.seen_test(AXIS_CHAR(i))) {
const uint8_t idx = idx_from_axis(AxisEnum(i));
const uint8_t idx = idx_from_axis((AxisEnum)i);
if ((int8_t)idx >= 0) report_position(idx, hasU, hasO);
}
}
@ -828,7 +828,7 @@ void I2CPositionEncodersMgr::M861() {
if (I2CPE_idx == 0xFF) {
LOOP_LOGICAL_AXES(i) {
if (!I2CPE_anyaxis || parser.seen(AXIS_CHAR(i))) {
const uint8_t idx = idx_from_axis(AxisEnum(i));
const uint8_t idx = idx_from_axis((AxisEnum)i);
if ((int8_t)idx >= 0) report_status(idx);
}
}
@ -856,7 +856,7 @@ void I2CPositionEncodersMgr::M862() {
if (I2CPE_idx == 0xFF) {
LOOP_LOGICAL_AXES(i) {
if (!I2CPE_anyaxis || parser.seen(AXIS_CHAR(i))) {
const uint8_t idx = idx_from_axis(AxisEnum(i));
const uint8_t idx = idx_from_axis((AxisEnum)i);
if ((int8_t)idx >= 0) test_axis(idx);
}
}
@ -887,7 +887,7 @@ void I2CPositionEncodersMgr::M863() {
if (I2CPE_idx == 0xFF) {
LOOP_LOGICAL_AXES(i) {
if (!I2CPE_anyaxis || parser.seen(AXIS_CHAR(i))) {
const uint8_t idx = idx_from_axis(AxisEnum(i));
const uint8_t idx = idx_from_axis((AxisEnum)i);
if ((int8_t)idx >= 0) calibrate_steps_mm(idx, iterations);
}
}
@ -963,7 +963,7 @@ void I2CPositionEncodersMgr::M865() {
if (!I2CPE_addr) {
LOOP_LOGICAL_AXES(i) {
if (!I2CPE_anyaxis || parser.seen(AXIS_CHAR(i))) {
const uint8_t idx = idx_from_axis(AxisEnum(i));
const uint8_t idx = idx_from_axis((AxisEnum)i);
if ((int8_t)idx >= 0) report_module_firmware(encoders[idx].get_address());
}
}
@ -994,12 +994,12 @@ void I2CPositionEncodersMgr::M866() {
if (I2CPE_idx == 0xFF) {
LOOP_LOGICAL_AXES(i) {
if (!I2CPE_anyaxis || parser.seen(AXIS_CHAR(i))) {
const uint8_t idx = idx_from_axis(AxisEnum(i));
const uint8_t idx = idx_from_axis((AxisEnum)i);
if ((int8_t)idx >= 0) {
if (hasR)
reset_error_count(idx, AxisEnum(i));
reset_error_count(idx, (AxisEnum)i);
else
report_error_count(idx, AxisEnum(i));
report_error_count(idx, (AxisEnum)i);
}
}
}
@ -1032,10 +1032,10 @@ void I2CPositionEncodersMgr::M867() {
if (I2CPE_idx == 0xFF) {
LOOP_LOGICAL_AXES(i) {
if (!I2CPE_anyaxis || parser.seen(AXIS_CHAR(i))) {
const uint8_t idx = idx_from_axis(AxisEnum(i));
const uint8_t idx = idx_from_axis((AxisEnum)i);
if ((int8_t)idx >= 0) {
const bool ena = onoff == -1 ? !encoders[I2CPE_idx].get_ec_enabled() : !!onoff;
enable_ec(idx, ena, AxisEnum(i));
enable_ec(idx, ena, (AxisEnum)i);
}
}
}
@ -1068,7 +1068,7 @@ void I2CPositionEncodersMgr::M868() {
if (I2CPE_idx == 0xFF) {
LOOP_LOGICAL_AXES(i) {
if (!I2CPE_anyaxis || parser.seen(AXIS_CHAR(i))) {
const uint8_t idx = idx_from_axis(AxisEnum(i));
const uint8_t idx = idx_from_axis((AxisEnum)i);
if ((int8_t)idx >= 0) {
if (newThreshold != -9999)
set_ec_threshold(idx, newThreshold, encoders[idx].get_axis());
@ -1102,7 +1102,7 @@ void I2CPositionEncodersMgr::M869() {
if (I2CPE_idx == 0xFF) {
LOOP_LOGICAL_AXES(i) {
if (!I2CPE_anyaxis || parser.seen(AXIS_CHAR(i))) {
const uint8_t idx = idx_from_axis(AxisEnum(i));
const uint8_t idx = idx_from_axis((AxisEnum)i);
if ((int8_t)idx >= 0) report_error(idx);
}
}

View file

@ -67,7 +67,7 @@ public:
}
// Convert raw measurement to mm
static float raw_to_mm(const uint16_t v) { return v * (float(ADC_VREF_MV) / 1000.0f) * RECIPROCAL(float(MAX_RAW_THERMISTOR_VALUE)); }
static float raw_to_mm(const uint16_t v) { return v * (float(ADC_VREF_MV) * 0.001f) * RECIPROCAL(float(MAX_RAW_THERMISTOR_VALUE)); }
static float raw_to_mm() { return raw_to_mm(raw); }
// A scaled reading is ready

View file

@ -164,9 +164,8 @@ void FWRetract::retract(const bool retracting E_OPTARG(bool swapping/*=false*/))
current_retract[active_extruder] = 0;
// Recover E, set_current_to_destination
prepare_internal_move_to_destination(
MUL_TERN(RETRACT_SYNC_MIXING, swapping ? settings.swap_retract_recover_feedrate_mm_s : settings.retract_recover_feedrate_mm_s, MIXING_STEPPERS)
);
const feedRate_t fr_mm_s = swapping ? settings.swap_retract_recover_feedrate_mm_s : settings.retract_recover_feedrate_mm_s;
prepare_internal_move_to_destination(MUL_TERN(RETRACT_SYNC_MIXING, fr_mm_s, MIXING_STEPPERS));
}
TERN_(RETRACT_SYNC_MIXING, mixer.T(old_mixing_tool)); // Restore original mixing tool

View file

@ -7,9 +7,9 @@ When initialized, MMU sends
We follow with
- MMU <= 'S1\n'
- MMU => 'ok*Firmware version*\n'
- MMU => 'ok<_Firmware version_>\n'
- MMU <= 'S2\n'
- MMU => 'ok*Build number*\n'
- MMU => 'ok<_Build number_>\n'
#if (12V_mode)
@ -19,25 +19,25 @@ We follow with
#endif
- MMU <= 'P0\n'
- MMU => '_FINDA status_\n'
- MMU => '<_FINDA status_>\n'
Now we are sure MMU is available and ready. If there was a timeout or other communication problem somewhere, printer will be killed.
- _Firmware version_ is an integer value, but we don't care about it
- _Build number_ is an integer value and has to be >=126, or =>132 if 12V mode is enabled
- _FINDA status_ is 1 if the filament is loaded to the extruder, 0 otherwise
- <_Firmware version_> is an integer value, but we don't care about it.
- <_Build number_> is an integer value and has to be >=126, or =>132 if 12V mode is enabled.
- <_FINDA status_> is 1 if the filament is loaded to the extruder, 0 otherwise.
_Build number_ is checked against the required value, if it does not match, printer is halted.
<_Build number_> is checked against the required value, if it does not match, printer is halted.
# Toolchange
- MMU <= 'T*Filament index*\n'
- MMU <= 'T<_Filament index_>\n'
MMU sends
- MMU => 'ok\n'
as soon as the filament is fed down to the extruder. We follow with
as soon as the filament is fed down to the extruder. We follow with:
- MMU <= 'C0\n'
@ -52,15 +52,15 @@ be one or more extruder moves to feed the filament into the hotend.
# FINDA status
- MMU <= 'P0\n'
- MMU => '_FINDA status_\n'
- MMU => '<_FINDA status_>\n'
_FINDA status_ is 1 if the is filament loaded to the extruder, 0 otherwise. This could be used as filament runout sensor if probed regularly.
# Load filament
- MMU <= 'L*Filament index*\n'
- MMU <= 'L<_Filament index_>\n'
MMU will feed filament down to the extruder, when done
MMU will feed filament down to the extruder, when done:
- MMU => 'ok\n'
@ -68,11 +68,11 @@ MMU will feed filament down to the extruder, when done
- MMU <= 'U0\n'
MMU will retract current filament from the extruder, when done
MMU will retract current filament from the extruder, when done:
- MMU => 'ok\n'
# Eject filament
- MMU <= 'E*Filament index*\n'
- MMU <= 'E<_Filament index_>\n'
- MMU => 'ok\n'

View file

@ -255,7 +255,7 @@ namespace MMU3 {
uint8_t block_index = planner.block_buffer_tail;
while (block_index != planner.block_buffer_head) {
block = &planner.block_buffer[block_index];
if (block->steps[E_AXIS] != 0) e_active++;
if (block->steps.e != 0) e_active++;
block_index = (block_index + 1) & (BLOCK_BUFFER_SIZE - 1);
}
}
@ -760,10 +760,10 @@ namespace MMU3 {
LogEchoEvent(F("Resuming XYZ"));
// Move XY to starting position, then Z
motion_do_blocking_move_to_xy(resume_position.x, resume_position.x, feedRate_t(NOZZLE_PARK_XY_FEEDRATE));
motion_blocking_move_xy(resume_position.x, resume_position.y, feedRate_t(NOZZLE_PARK_XY_FEEDRATE));
// Move Z_AXIS to saved position
motion_do_blocking_move_to_z(resume_position.z, feedRate_t(NOZZLE_PARK_Z_FEEDRATE));
motion_blocking_move_z(resume_position.z, feedRate_t(NOZZLE_PARK_Z_FEEDRATE));
// From this point forward, power panic should not use
// the partial backup in RAM since the extruder is no
@ -867,7 +867,7 @@ namespace MMU3 {
nozzle_timer.start();
LogEchoEvent(F("Cooling Timeout started"));
}
else if (nozzle_timer.duration() > (PAUSE_PARK_NOZZLE_TIMEOUT * 1000ul)) { // mins->msec.
else if (nozzle_timer.duration() > (PAUSE_PARK_NOZZLE_TIMEOUT * 1000UL)) { // mins->msec.
mmu_print_saved &= ~(SavedState::CooldownPending);
mmu_print_saved |= SavedState::Cooldown;
thermal_setTargetHotend(0);

View file

@ -46,8 +46,8 @@ namespace MMU3 {
void planner_set_current_position_E(float e);
xyz_pos_t planner_current_position();
void motion_do_blocking_move_to_xy(float rx, float ry, float feedRate_mm_s);
void motion_do_blocking_move_to_z(float z, float feedRate_mm_s);
void motion_blocking_move_xy(float rx, float ry, float feedRate_mm_s);
void motion_blocking_move_z(float z, float feedRate_mm_s);
void nozzle_park();

View file

@ -103,14 +103,13 @@ namespace MMU3 {
return xyz_pos_t(current_position);
}
void motion_do_blocking_move_to_xy(float rx, float ry, float feedRate_mm_s) {
current_position[X_AXIS] = rx;
current_position[Y_AXIS] = ry;
void motion_blocking_move_xy(float rx, float ry, float feedRate_mm_s) {
current_position.set(rx, ry);
planner_line_to_current_position_sync(feedRate_mm_s);
}
void motion_do_blocking_move_to_z(float z, float feedRate_mm_s) {
current_position[Z_AXIS] = z;
void motion_blocking_move_z(float z, float feedRate_mm_s) {
current_position.z = z;
planner_line_to_current_position_sync(feedRate_mm_s);
}
@ -152,34 +151,18 @@ namespace MMU3 {
#endif
}
int16_t thermal_degTargetHotend() {
return thermalManager.degTargetHotend(0);
}
int16_t thermal_degHotend() {
return thermalManager.degHotend(0);
}
void thermal_setExtrudeMintemp(int16_t t) {
thermalManager.extrude_min_temp = t;
}
void thermal_setTargetHotend(int16_t t) {
thermalManager.setTargetHotend(t, 0);
}
int16_t thermal_degTargetHotend() { return thermalManager.degTargetHotend(0); }
int16_t thermal_degHotend() { return thermalManager.degHotend(0); }
void thermal_setExtrudeMintemp(int16_t t) { thermalManager.extrude_min_temp = t; }
void thermal_setTargetHotend(int16_t t) { thermalManager.setTargetHotend(t, 0); }
void safe_delay_keep_alive(uint16_t t) {
idle(true);
safe_delay(t);
}
void Enable_E0() {
stepper.enable_extruder(TERN_(HAS_EXTRUDERS, 0));
}
void Disable_E0() {
stepper.disable_extruder(TERN_(HAS_EXTRUDERS, 0));
}
void Enable_E0() { stepper.enable_extruder(TERN_(HAS_EXTRUDERS, 0)); }
void Disable_E0() { stepper.disable_extruder(TERN_(HAS_EXTRUDERS, 0)); }
bool xy_are_trusted() {
return axis_is_trusted(X_AXIS) && axis_is_trusted(Y_AXIS);

View file

@ -707,7 +707,7 @@ namespace MMU3 {
}
bool ProtocolLogic::Elapsed(uint32_t timeout) const {
return _millis() >= (lastUARTActivityMs + timeout);
return ELAPSED(_millis(), lastUARTActivityMs + timeout);
}
void ProtocolLogic::RecordUARTActivity() {
@ -716,7 +716,7 @@ namespace MMU3 {
void ProtocolLogic::RecordReceivedByte(uint8_t c) {
lastReceivedBytes[lrb] = c;
lrb = (lrb + 1) % lastReceivedBytes.size();
lrb = (lrb + 1) % COUNT(lastReceivedBytes);
}
constexpr char NibbleToChar(uint8_t c) {
@ -728,13 +728,13 @@ namespace MMU3 {
}
void ProtocolLogic::FormatLastReceivedBytes(char *dst) {
for (uint8_t i = 0; i < lastReceivedBytes.size(); ++i) {
uint8_t b = lastReceivedBytes[(lrb - i - 1) % lastReceivedBytes.size()];
for (uint8_t i = 0; i < COUNT(lastReceivedBytes); ++i) {
uint8_t b = lastReceivedBytes[(COUNT(lastReceivedBytes) - 1 + (lrb - i)) % COUNT(lastReceivedBytes)];
dst[i * 3] = NibbleToChar(b >> 4);
dst[i * 3 + 1] = NibbleToChar(b & 0xf);
dst[i * 3 + 2] = ' ';
}
dst[(lastReceivedBytes.size() - 1) * 3 + 2] = 0; // terminate properly
dst[(COUNT(lastReceivedBytes) - 1) * 3 + 2] = 0; // terminate properly
}
void ProtocolLogic::FormatLastResponseMsgAndClearLRB(char *dst) {
@ -777,18 +777,18 @@ namespace MMU3 {
}
void ProtocolLogic::LogError(const char *reason_P) {
char lrb[lastReceivedBytes.size() * 3];
FormatLastReceivedBytes(lrb);
char _lrb[COUNT(lastReceivedBytes) * 3];
FormatLastReceivedBytes(_lrb);
MMU2_ERROR_MSGRPGM(reason_P);
SERIAL_ECHOPGM(", last bytes: ");
SERIAL_ECHOLN(lrb);
SERIAL_ECHOLN(_lrb);
}
void ProtocolLogic::LogResponse() {
char lrb[lastReceivedBytes.size()];
FormatLastResponseMsgAndClearLRB(lrb);
MMU2_ECHO_MSGLN(lrb);
char _lrb[COUNT(lastReceivedBytes)];
FormatLastResponseMsgAndClearLRB(_lrb);
MMU2_ECHO_MSGLN(_lrb);
}
StepStatus ProtocolLogic::SuppressShortDropOuts(const char *msg_P, StepStatus ss) {

View file

@ -36,24 +36,8 @@
#include "mmu_hw/buttons.h"
#include "mmu_hw/registers.h"
#include "mmu3_protocol.h"
// #include <array> std array is not available on AVR ... we need to "fake" it
namespace std {
template <typename T, uint8_t N>
class array {
T data[N];
public:
array() = default;
inline constexpr T *begin() const { return data; }
inline constexpr T *end() const { return data + N; }
static constexpr uint8_t size() { return N; }
inline T &operator[](uint8_t i) { return data[i]; }
};
} // std
#else // !__AVR__
#include <array>
#include "mmu_hw/error_codes.h"
#include "mmu_hw/progress_codes.h"
@ -351,8 +335,7 @@ namespace MMU3 {
Protocol protocol; //!< protocol codec
std::array<uint8_t, 16> lastReceivedBytes; //!< remembers the last few bytes of incoming communication for diagnostic purposes
uint8_t lrb;
uint8_t lrb, lastReceivedBytes[16]; //!< keep the last few bytes of incoming communication for diagnostic purposes
ErrorCode errorCode; //!< last received error code from the MMU
ProgressCode progressCode; //!< last received progress code from the MMU

View file

@ -221,7 +221,7 @@ void PrintJobRecovery::save(const bool force/*=false*/, const float zraise/*=POW
TERN_(HAS_WORKSPACE_OFFSET, info.workspace_offset = workspace_offset);
E_TERN_(info.active_extruder = active_extruder);
#if DISABLED(NO_VOLUMETRICS)
#if HAS_VOLUMETRIC_EXTRUSION
info.flag.volumetric_enabled = parser.volumetric_enabled;
#if HAS_MULTI_EXTRUDER
COPY(info.filament_size, planner.filament_size);
@ -496,7 +496,7 @@ void PrintJobRecovery::resume() {
#endif
// Recover volumetric extrusion state
#if DISABLED(NO_VOLUMETRICS)
#if HAS_VOLUMETRIC_EXTRUSION
#if HAS_MULTI_EXTRUDER
EXTRUDER_LOOP()
PROCESS_SUBCOMMANDS_NOW(TS(F("M200T"), e, F("D"), p_float_t(info.filament_size[e], 3)));
@ -659,7 +659,7 @@ void PrintJobRecovery::resume() {
DEBUG_ECHOLNPGM("active_extruder: ", info.active_extruder);
#endif
#if DISABLED(NO_VOLUMETRICS)
#if HAS_VOLUMETRIC_EXTRUSION
DEBUG_ECHOPGM("filament_size:");
EXTRUDER_LOOP() DEBUG_ECHOLNPGM(" ", info.filament_size[e]);
DEBUG_EOL();
@ -725,7 +725,7 @@ void PrintJobRecovery::resume() {
DEBUG_ECHOLNPGM("flag.dryrun: ", AS_DIGIT(info.flag.dryrun));
DEBUG_ECHOLNPGM("flag.allow_cold_extrusion: ", AS_DIGIT(info.flag.allow_cold_extrusion));
#if DISABLED(NO_VOLUMETRICS)
#if HAS_VOLUMETRIC_EXTRUSION
DEBUG_ECHOLNPGM("flag.volumetric_enabled: ", AS_DIGIT(info.flag.volumetric_enabled));
#endif
}

View file

@ -88,7 +88,7 @@ typedef struct {
uint8_t active_extruder;
#endif
#if DISABLED(NO_VOLUMETRICS)
#if HAS_VOLUMETRIC_EXTRUSION
float filament_size[EXTRUDERS];
#endif
@ -140,7 +140,7 @@ typedef struct {
#if HAS_LEVELING
bool leveling:1; // M420 S
#endif
#if DISABLED(NO_VOLUMETRICS)
#if HAS_VOLUMETRIC_EXTRUSION
bool volumetric_enabled:1; // M200 S D
#endif
} flag;

View file

@ -212,7 +212,7 @@ void ProbeTempComp::compensate_measurement(const TempSensorID tsi, const celsius
}
// convert offset to mm and apply it
meas_z -= offset / 1000.0f;
meas_z -= offset * 0.001f;
}
bool ProbeTempComp::linear_regression(const TempSensorID tsi, float &k, float &d) {

View file

@ -60,7 +60,7 @@ public:
// Convert configured power range to a percentage
static constexpr cutter_cpower_t power_floor = TERN(CUTTER_POWER_RELATIVE, SPEED_POWER_MIN, 0);
static constexpr uint8_t cpwr_to_pct(const cutter_cpower_t cpwr) {
return cpwr ? round(100.0f * (cpwr - power_floor) / (SPEED_POWER_MAX - power_floor)) : 0;
return cpwr ? LROUND(100.0f * (cpwr - power_floor) / (SPEED_POWER_MAX - power_floor)) : 0;
}
// Convert config defines from RPM to %, angle or PWM when in Spindle mode
@ -164,7 +164,7 @@ public:
*/
static cutter_power_t power_to_range(const cutter_power_t pwr, const uint8_t pwrUnit=_CUTTER_POWER(CUTTER_POWER_UNIT)) {
static constexpr float
min_pct = TERN(CUTTER_POWER_RELATIVE, 0, TERN(SPINDLE_FEATURE, round(100.0f * (SPEED_POWER_MIN) / (SPEED_POWER_MAX)), SPEED_POWER_MIN)),
min_pct = TERN(CUTTER_POWER_RELATIVE, 0, TERN(SPINDLE_FEATURE, roundf(100.0f * (SPEED_POWER_MIN) / (SPEED_POWER_MAX)), SPEED_POWER_MIN)),
max_pct = TERN(SPINDLE_FEATURE, 100, SPEED_POWER_MAX);
if (pwr <= 0) return 0;
cutter_power_t upwr;

View file

@ -31,7 +31,7 @@ static uint32_t axis_plug_backward = 0;
void stepper_driver_backward_error(FSTR_P const fstr) {
SERIAL_ERROR_START();
SERIAL_ECHOLN(fstr, F(" driver is backward!"));
ui.status_printf(2, F(S_FMT S_FMT), FTOP(fstr), GET_TEXT_F(MSG_DRIVER_BACKWARD));
ui.status_printf(2, F(S_FMT S_FMT), FTOP(fstr), GET_TEXT(MSG_DRIVER_BACKWARD));
}
void stepper_driver_backward_check() {

View file

@ -973,14 +973,14 @@
TMC_REPORT("[mm/s]\t", TMC_TPWMTHRS_MMS);
TMC_REPORT("OT prewarn", TMC_DEBUG_OTPW);
#if ENABLED(MONITOR_DRIVER_STATUS)
TMC_REPORT("triggered\n OTP\t", TMC_OTPW_TRIGGERED);
TMC_REPORT("OTPW trig.\t", TMC_OTPW_TRIGGERED);
#endif
#if HAS_TMC220x
TMC_REPORT("pwm scale sum", TMC_PWM_SCALE_SUM);
TMC_REPORT("pwm scale auto", TMC_PWM_SCALE_AUTO);
TMC_REPORT("pwm offset auto", TMC_PWM_OFS_AUTO);
TMC_REPORT("pwm grad auto", TMC_PWM_GRAD_AUTO);
TMC_REPORT("pwm scale sum", TMC_PWM_SCALE_SUM);
TMC_REPORT("pwm scale auto", TMC_PWM_SCALE_AUTO);
TMC_REPORT("pwm offset auto", TMC_PWM_OFS_AUTO);
TMC_REPORT("pwm grad auto", TMC_PWM_GRAD_AUTO);
#endif
TMC_REPORT("off time", TMC_TOFF);

View file

@ -663,7 +663,7 @@ void GcodeSuite::G26() {
do_z_clearance(Z_CLEARANCE_BETWEEN_PROBES);
#if DISABLED(NO_VOLUMETRICS)
#if HAS_VOLUMETRIC_EXTRUSION
bool volumetric_was_enabled = parser.volumetric_enabled;
parser.volumetric_enabled = false;
planner.calculate_volumetric_multipliers();
@ -856,7 +856,7 @@ void GcodeSuite::G26() {
destination.z = Z_CLEARANCE_BETWEEN_PROBES;
move_to(destination, 0); // Raise the nozzle
#if DISABLED(NO_VOLUMETRICS)
#if HAS_VOLUMETRIC_EXTRUSION
parser.volumetric_enabled = volumetric_was_enabled;
planner.calculate_volumetric_multipliers();
#endif

View file

@ -59,7 +59,7 @@
#define DEBUG_OUT ENABLED(DEBUG_LEVELING_FEATURE)
#include "../../../core/debug_out.h"
#if DISABLED(PROBE_MANUALLY) && FT_MOTION_DISABLE_FOR_PROBING
#if DISABLED(PROBE_MANUALLY) && ENABLED(FT_MOTION)
#include "../../../module/ft_motion.h"
#endif
@ -275,8 +275,9 @@ G29_TYPE GcodeSuite::G29() {
// Set and report "probing" state to host
TERN_(FULL_REPORT_TO_HOST_FEATURE, set_and_report_grblstate(M_PROBE, false));
#if DISABLED(PROBE_MANUALLY) && FT_MOTION_DISABLE_FOR_PROBING
FTMotionDisableInScope FT_Disabler; // Disable Fixed-Time Motion for probing
#if DISABLED(PROBE_MANUALLY)
// Potentially disable Fixed-Time Motion for probing
TERN_(FT_MOTION, FTM_DISABLE_IN_SCOPE());
#endif
/**
@ -708,7 +709,7 @@ G29_TYPE GcodeSuite::G29() {
if (TERN0(IS_KINEMATIC, !probe.can_reach(abl.probePos))) continue;
if (abl.verbose_level) SERIAL_ECHOLNPGM("Probing mesh point ", pt_index, "/", abl.abl_points, ".");
TERN_(HAS_STATUS_MESSAGE, ui.status_printf(0, F(S_FMT " %i/%i"), GET_TEXT_F(MSG_PROBING_POINT), int(pt_index), int(abl.abl_points)));
TERN_(HAS_STATUS_MESSAGE, ui.status_printf(0, F(S_FMT " %i/%i"), GET_TEXT(MSG_PROBING_POINT), int(pt_index), int(abl.abl_points)));
#if ENABLED(BD_SENSOR_PROBE_NO_STOP)
if (PR_INNER_VAR == inStart) {
@ -813,7 +814,7 @@ G29_TYPE GcodeSuite::G29() {
for (uint8_t i = 0; i < 3; ++i) {
if (abl.verbose_level) SERIAL_ECHOLNPGM("Probing point ", i + 1, "/3.");
TERN_(HAS_STATUS_MESSAGE, ui.status_printf(0, F(S_FMT " %i/3"), GET_TEXT_F(MSG_PROBING_POINT), int(i + 1)));
TERN_(HAS_STATUS_MESSAGE, ui.status_printf(0, F(S_FMT " %i/3"), GET_TEXT(MSG_PROBING_POINT), int(i + 1)));
// Retain the last probe position
abl.probePos = xy_pos_t(points[i]);

View file

@ -45,7 +45,7 @@
#define DEBUG_OUT ENABLED(DEBUG_LEVELING_FEATURE)
#include "../../../core/debug_out.h"
#if FT_MOTION_DISABLE_FOR_PROBING
#if ENABLED(FT_MOTION)
#include "../../module/ft_motion.h"
#endif
@ -67,9 +67,8 @@ inline void echo_not_entered(const char c) { SERIAL_CHAR(c); SERIAL_ECHOLNPGM("
*/
void GcodeSuite::G29() {
#if FT_MOTION_DISABLE_FOR_PROBING
FTMotionDisableInScope FT_Disabler; // Disable Fixed-Time Motion for probing
#endif
// Potentially disable Fixed-Time Motion for probing
TERN_(FT_MOTION, FTM_DISABLE_IN_SCOPE());
DEBUG_SECTION(log_G29, "G29", true);
@ -261,7 +260,7 @@ void GcodeSuite::G29() {
if (state == MeshNext) {
SERIAL_ECHOLNPGM("MBL G29 point ", _MIN(mbl_probe_index, GRID_MAX_POINTS), " of ", GRID_MAX_POINTS);
if (mbl_probe_index > 0) TERN_(HAS_STATUS_MESSAGE, ui.status_printf(0, F(S_FMT " %i/%i"), GET_TEXT_F(MSG_PROBING_POINT), _MIN(mbl_probe_index, GRID_MAX_POINTS), int(GRID_MAX_POINTS)));
if (mbl_probe_index > 0) TERN_(HAS_STATUS_MESSAGE, ui.status_printf(0, F(S_FMT " %i/%i"), GET_TEXT(MSG_PROBING_POINT), _MIN(mbl_probe_index, GRID_MAX_POINTS), int(GRID_MAX_POINTS)));
}
report_current_position();

View file

@ -52,7 +52,7 @@
#include "../../feature/bltouch.h"
#endif
#if FT_MOTION_DISABLE_FOR_PROBING
#if ENABLED(FT_MOTION)
#include "../../module/ft_motion.h"
#endif
@ -130,9 +130,8 @@
inline void home_z_safely() {
#if FT_MOTION_DISABLE_FOR_PROBING
FTMotionDisableInScope FT_Disabler; // Disable Fixed-Time Motion for homing
#endif
// Potentially disable Fixed-Time Motion for homing
TERN_(FT_MOTION, FTM_DISABLE_IN_SCOPE());
DEBUG_SECTION(log_G28, "home_z_safely", DEBUGGING(LEVELING));
@ -290,9 +289,8 @@ void GcodeSuite::G28() {
motion_state_t saved_motion_state = begin_slow_homing();
#endif
#if FT_MOTION_DISABLE_FOR_PROBING
FTMotionDisableInScope FT_Disabler; // Disable Fixed-Time Motion for homing
#endif
// Potentially disable Fixed-Time Motion for homing
TERN_(FT_MOTION, FTM_DISABLE_IN_SCOPE());
// Always home with tool 0 active
#if HAS_MULTI_HOTEND

View file

@ -154,7 +154,7 @@ static float std_dev_points(float z_pt[NPP + 1], const bool _0p_cal, const bool
S2 += sq(z_pt[rad]);
N++;
}
return LROUND(SQRT(S2 / N) * 1000.0f) / 1000.0f + 0.00001f;
return LROUND(SQRT(S2 / N) * 1000.0f) * 0.001f + 0.00001f;
}
}
return 0.00001f;
@ -315,7 +315,7 @@ static void calc_kinematics_diff_probe_points(float z_pt[NPP + 1], const float d
static float auto_tune_h(const float dcr) {
const float r_quot = dcr / delta_radius;
return RECIPROCAL(r_quot / (2.0f / 3.0f)); // (2/3)/CR
return RECIPROCAL(r_quot * (3.0f / 2.0f)); // (2/3)/CR
}
static float auto_tune_r(const float dcr) {
@ -490,7 +490,7 @@ void GcodeSuite::G33() {
float z_at_pt[NPP + 1] = { 0.0f };
test_precision = zero_std_dev_old != 999.0f ? (zero_std_dev + zero_std_dev_old) / 2.0f : zero_std_dev;
test_precision = zero_std_dev_old != 999.0f ? (zero_std_dev + zero_std_dev_old) * 0.5f : zero_std_dev;
iterations++;
// Probe the points
@ -527,7 +527,7 @@ void GcodeSuite::G33() {
* - Definition of the matrix scaling parameters
* - Matrices for 4 and 7 point calibration
*/
#define ZP(N,I) ((N) * z_at_pt[I] / 4.0f) // 4.0 = divider to normalize to integers
#define ZP(N,I) ((N) * z_at_pt[I] * 0.25f) // 4.0 = divider to normalize to integers
#define Z12(I) ZP(12, I)
#define Z4(I) ZP(4, I)
#define Z2(I) ZP(2, I)

View file

@ -236,10 +236,8 @@ void GcodeSuite::G34() {
Z_TWEEN_SAFE_CLEARANCE // z_clearance
);
if (DEBUGGING(LEVELING)) {
DEBUG_ECHOLNPGM_P(PSTR("Probing X"), ppos.x, SP_Y_STR, ppos.y);
DEBUG_ECHOLNPGM("Height = ", z_probed_height);
}
if (DEBUGGING(LEVELING))
DEBUG_ECHOLN(F("Probing X"), ppos.x, FPSTR(SP_Y_STR), ppos.y, F(" Height = "), z_probed_height);
if (isnan(z_probed_height)) {
SERIAL_ECHOLNPGM(STR_ERR_PROBING_FAILED);
@ -392,7 +390,7 @@ void GcodeSuite::G34() {
// Decreasing accuracy was detected so move was inverted.
// Will match reversed Z steppers on dual steppers. Triple will need more work to map.
if (adjustment_reverse) {
z_align_move = -z_align_move;
z_align_move *= -1;
if (DEBUGGING(LEVELING)) DEBUG_ECHOLNPGM("> Z", zstepper + 1, " correction reversed to ", z_align_move);
}
#endif

View file

@ -320,7 +320,7 @@
*/
void GcodeSuite::M871() {
if (parser.seen('R')) {
if (parser.seen_test('R')) {
// Reset z-probe offsets to factory defaults
ptc.clear_all_offsets();
SERIAL_ECHOLNPGM("Offsets reset to default.");

View file

@ -94,7 +94,7 @@ void GcodeSuite::M425() {
#if ENABLED(MEASURE_BACKLASH_WHEN_PROBING)
SERIAL_ECHOPGM(" Average measured backlash (mm):");
if (backlash.has_any_measurement()) {
LOOP_NUM_AXES(a) if (axis_can_calibrate(a) && backlash.has_measurement(AxisEnum(a))) {
LOOP_NUM_AXES(a) if (axis_can_calibrate(a) && backlash.has_measurement((AxisEnum)a)) {
SERIAL_ECHOPGM_P((PGM_P)pgm_read_ptr(&SP_AXIS_STR[a]), backlash.get_measurement((AxisEnum)a));
}
}

View file

@ -149,7 +149,7 @@ void GcodeSuite::M48() {
for (uint8_t n = 0; n < n_samples; ++n) {
#if HAS_STATUS_MESSAGE
// Display M48 progress in the status bar
ui.status_printf(0, F(S_FMT ": %d/%d"), GET_TEXT_F(MSG_M48_POINT), int(n + 1), int(n_samples));
ui.status_printf(0, F(S_FMT ": %d/%d"), GET_TEXT(MSG_M48_POINT), int(n + 1), int(n_samples));
#endif
// When there are "legs" of movement move around the point before probing

View file

@ -24,7 +24,7 @@
#include "../../MarlinCore.h"
#include "../../module/planner.h"
#if DISABLED(NO_VOLUMETRICS)
#if HAS_VOLUMETRIC_EXTRUSION
/**
* M200: Set filament diameter and set E axis units to cubic units
@ -107,7 +107,7 @@
#endif
}
#endif // !NO_VOLUMETRICS
#endif // HAS_VOLUMETRIC_EXTRUSION
/**
* M201: Set max acceleration in units/s^2 for print moves.

View file

@ -48,31 +48,31 @@ void GcodeSuite::M210() {
return M210_report();
#if HAS_X_AXIS
if (parser.floatval('X') > 0) homing_feedrate_mm_m.x = parser.value_axis_units(X_AXIS);
if (parser.floatval(AXIS1_PARAM) > 0) homing_feedrate_mm_m.x = parser.value_axis_units(X_AXIS);
#endif
#if HAS_Y_AXIS
if (parser.floatval('Y') > 0) homing_feedrate_mm_m.y = parser.value_axis_units(Y_AXIS);
if (parser.floatval(AXIS2_PARAM) > 0) homing_feedrate_mm_m.y = parser.value_axis_units(Y_AXIS);
#endif
#if HAS_Z_AXIS
if (parser.floatval('Z') > 0) homing_feedrate_mm_m.z = parser.value_axis_units(Z_AXIS);
if (parser.floatval(AXIS3_PARAM) > 0) homing_feedrate_mm_m.z = parser.value_axis_units(Z_AXIS);
#endif
#if HAS_I_AXIS
if (parser.floatval(AXIS4_NAME) > 0) homing_feedrate_mm_m.i = parser.value_axis_units(I_AXIS);
if (parser.floatval(AXIS4_PARAM) > 0) homing_feedrate_mm_m.i = parser.value_axis_units(I_AXIS);
#endif
#if HAS_J_AXIS
if (parser.floatval(AXIS5_NAME) > 0) homing_feedrate_mm_m.j = parser.value_axis_units(J_AXIS);
if (parser.floatval(AXIS5_PARAM) > 0) homing_feedrate_mm_m.j = parser.value_axis_units(J_AXIS);
#endif
#if HAS_K_AXIS
if (parser.floatval(AXIS6_NAME) > 0) homing_feedrate_mm_m.k = parser.value_axis_units(K_AXIS);
if (parser.floatval(AXIS6_PARAM) > 0) homing_feedrate_mm_m.k = parser.value_axis_units(K_AXIS);
#endif
#if HAS_U_AXIS
if (parser.floatval(AXIS7_NAME) > 0) homing_feedrate_mm_m.u = parser.value_axis_units(U_AXIS);
if (parser.floatval(AXIS7_PARAM) > 0) homing_feedrate_mm_m.u = parser.value_axis_units(U_AXIS);
#endif
#if HAS_V_AXIS
if (parser.floatval(AXIS8_NAME) > 0) homing_feedrate_mm_m.v = parser.value_axis_units(V_AXIS);
if (parser.floatval(AXIS8_PARAM) > 0) homing_feedrate_mm_m.v = parser.value_axis_units(V_AXIS);
#endif
#if HAS_W_AXIS
if (parser.floatval(AXIS9_NAME) > 0) homing_feedrate_mm_m.w = parser.value_axis_units(W_AXIS);
if (parser.floatval(AXIS9_PARAM) > 0) homing_feedrate_mm_m.w = parser.value_axis_units(W_AXIS);
#endif
}

View file

@ -154,37 +154,36 @@ inline void servo_probe_test() {
SET_INPUT_PULLUP(PROBE_TEST_PIN);
// First, check for a probe that recognizes an advanced BLTouch sequence.
// In addition to STOW and DEPLOY, it uses SW MODE (and RESET in the beginning)
// to see if this is one of the following: BLTOUCH Classic 1.2, 1.3, or
// BLTouch Smart 1.0, 2.0, 2.2, 3.0, 3.1. But only if the user has actually
// configured a BLTouch as being present. If the user has not configured this,
// the BLTouch will be detected in the last phase of these tests (see further on).
bool blt = false;
// This code will try to detect a BLTouch probe or clone
/**
* This code will try to detect a BLTouch probe or clone.
* First, check for a probe that recognizes an advanced BLTouch sequence.
* In addition to STOW and DEPLOY, it uses SW MODE (and RESET in the beginning)
* to see if this is one of the following: BLTOUCH Classic 1.2, 1.3, or
* BLTouch Smart 1.0, 2.0, 2.2, 3.0, 3.1. But only if the user has actually
* configured a BLTouch as being present. If the user has not configured this,
* the BLTouch will be detected in the last phase of these tests (see further on).
*/
#if ENABLED(BLTOUCH)
SERIAL_ECHOLNPGM(". Check for BLTOUCH");
bltouch._reset();
bltouch._stow();
if (!PROBE_TRIGGERED()) {
bltouch._set_SW_mode();
if (PROBE_TRIGGERED()) {
bltouch._deploy();
if (!PROBE_TRIGGERED()) {
bltouch._stow();
SERIAL_ECHOLNPGM("= BLTouch Classic 1.2, 1.3, Smart 1.0, 2.0, 2.2, 3.0, 3.1 detected.");
// Check for a 3.1 by letting the user trigger it, later
blt = true;
}
}
}
bool blt = false;
do {
SERIAL_ECHOLNPGM(". Check for BLTOUCH");
bltouch._reset();
bltouch._stow(); if ( PROBE_TRIGGERED()) break;
bltouch._set_SW_mode(); if (!PROBE_TRIGGERED()) break;
bltouch._deploy(); if ( PROBE_TRIGGERED()) break;
bltouch._stow();
SERIAL_ECHOLNPGM("= BLTouch Classic 1.2, 1.3, Smart 1.0, 2.0, 2.2, 3.0, 3.1 detected.");
blt = true; // Check for a 3.1 by letting the user trigger it, later
} while(0);
#else
static constexpr bool blt = false;
#endif
// The following code is common to all kinds of servo probes.
// Since it could be a real servo or a BLTouch (any kind) or a clone,
// use only "common" functions - i.e. SERVO_MOVE. No bltouch.xxxx stuff.
// If it is already recognised as a being a BLTouch, no need for this test
// If it is already recognized as a being a BLTouch, no need for this test
if (!blt) {
// DEPLOY and STOW 4 times and see if the signal follows
// Then it is a mechanical switch

View file

@ -78,7 +78,7 @@ void do_enable(const stepper_flags_t to_enable) {
// Enable all flagged axes
LOOP_NUM_AXES(a) {
if (TEST(shall_enable, a)) {
stepper.enable_axis(AxisEnum(a)); // Mark and enable the requested axis
stepper.enable_axis((AxisEnum)a); // Mark and enable the requested axis
DEBUG_ECHOLNPGM("Enabled ", AXIS_CHAR(a), " (", a, ") with overlap ", hex_word(enable_overlap[a]), " ... Enabled: ", hex_word(stepper.axis_enabled.bits));
also_enabled |= enable_overlap[a];
}
@ -153,7 +153,7 @@ void try_to_disable(const stepper_flags_t to_disable) {
LOOP_NUM_AXES(a)
if (TEST(to_disable.bits, a)) {
DEBUG_ECHOPGM("Try to disable ", AXIS_CHAR(a), " (", a, ") with overlap ", hex_word(enable_overlap[a]), " ... ");
if (stepper.disable_axis(AxisEnum(a))) { // Mark the requested axis and request to disable
if (stepper.disable_axis((AxisEnum)a)) { // Mark the requested axis and request to disable
DEBUG_ECHOPGM("OK");
still_enabled &= ~(_BV(a) | enable_overlap[a]); // If actually disabled, clear one or more tracked bits
}

View file

@ -22,7 +22,7 @@
#include "../../../inc/MarlinConfig.h"
#if ENABLED(LIN_ADVANCE)
#if HAS_LIN_ADVANCE_K
#include "../../gcode.h"
#include "../../../module/planner.h"
@ -41,6 +41,9 @@
* With ADVANCE_K_EXTRA:
* S<0/1> Activate slot 0 or 1.
* L<factor> Set secondary advance K factor (Slot 1).
*
* With SMOOTH_LIN_ADVANCE:
* U<tau> Set a tau value for LA smoothing
*/
void GcodeSuite::M900() {
@ -191,4 +194,4 @@ void GcodeSuite::M900_report(const bool forReplay/*=true*/) {
}
}
#endif // LIN_ADVANCE
#endif // HAS_LIN_ADVANCE_K

View file

@ -47,7 +47,7 @@ void GcodeSuite::M486() {
if (parser.seenval('S'))
cancelable.set_active_object(parser.value_int());
if (parser.seen('C')) cancelable.cancel_active_object();
if (parser.seen_test('C')) cancelable.cancel_active_object();
if (parser.seenval('P')) cancelable.cancel_object(parser.value_int());

View file

@ -28,8 +28,9 @@
#include "../../../module/ft_motion.h"
#include "../../../module/stepper.h"
void say_shaper_type(const AxisEnum a) {
SERIAL_ECHOPGM(" axis ");
void say_shaper_type(const AxisEnum a, bool &sep, const char axis_name) {
if (sep) SERIAL_ECHOPGM(" ; ");
SERIAL_CHAR(axis_name, '=');
switch (ftMotion.cfg.shaper[a]) {
default: break;
case ftMotionShaper_ZV: SERIAL_ECHOPGM("ZV"); break;
@ -41,49 +42,36 @@ void say_shaper_type(const AxisEnum a) {
case ftMotionShaper_3HEI: SERIAL_ECHOPGM("3 Hump EI"); break;
case ftMotionShaper_MZV: SERIAL_ECHOPGM("MZV"); break;
}
SERIAL_ECHOPGM(" shaping");
sep = true;
}
#if CORE_IS_XY || CORE_IS_XZ
#define AXIS_0_NAME "A"
#else
#define AXIS_0_NAME "X"
#endif
#if CORE_IS_XY || CORE_IS_YZ
#define AXIS_1_NAME "B"
#else
#define AXIS_1_NAME "Y"
#endif
void say_shaping() {
const ft_config_t &c = ftMotion.cfg;
// FT Enabled
SERIAL_ECHO_TERNARY(ftMotion.cfg.active, "Fixed-Time Motion ", "en", "dis", "abled");
SERIAL_ECHO_TERNARY(c.active, "Fixed-Time Motion ", "en", "dis", "abled");
// FT Shaping
#if HAS_X_AXIS
if (AXIS_IS_SHAPING(X)) {
SERIAL_ECHOPGM(" with " AXIS_0_NAME);
say_shaper_type(X_AXIS);
}
#endif
#if HAS_Y_AXIS
if (AXIS_IS_SHAPING(Y)) {
SERIAL_ECHOPGM(" and with " AXIS_1_NAME);
say_shaper_type(Y_AXIS);
}
#endif
const bool is_shaping = AXIS_IS_SHAPING(X) || AXIS_IS_SHAPING(Y) || AXIS_IS_SHAPING(Z) || AXIS_IS_SHAPING(E);
bool sep = false;
if (is_shaping) {
#define STEPPER_E_NAME 'E'
#define _SAY_SHAPER(A) if (AXIS_IS_SHAPING(A)) say_shaper_type(_AXIS(A), sep, STEPPER_##A##_NAME);
SERIAL_ECHOPGM(" (");
SHAPED_CODE(_SAY_SHAPER(A), _SAY_SHAPER(B), _SAY_SHAPER(C), _SAY_SHAPER(E));
SERIAL_CHAR(')');
}
SERIAL_EOL();
SERIAL_ECHOLNPGM(".");
const bool z_based = TERN0(HAS_DYNAMIC_FREQ_MM, ftMotion.cfg.dynFreqMode == dynFreqMode_Z_BASED),
g_based = TERN0(HAS_DYNAMIC_FREQ_G, ftMotion.cfg.dynFreqMode == dynFreqMode_MASS_BASED),
const bool z_based = TERN0(HAS_DYNAMIC_FREQ_MM, c.dynFreqMode == dynFreqMode_Z_BASED),
g_based = TERN0(HAS_DYNAMIC_FREQ_G, c.dynFreqMode == dynFreqMode_MASS_BASED),
dynamic = z_based || g_based;
// FT Dynamic Frequency Mode
if (AXIS_IS_SHAPING(X) || AXIS_IS_SHAPING(Y)) {
if (is_shaping) {
#if HAS_DYNAMIC_FREQ
SERIAL_ECHOPGM("Dynamic Frequency Mode ");
switch (ftMotion.cfg.dynFreqMode) {
switch (c.dynFreqMode) {
default:
case dynFreqMode_DISABLED: SERIAL_ECHOPGM("disabled"); break;
#if HAS_DYNAMIC_FREQ_MM
@ -97,31 +85,35 @@ void say_shaping() {
#endif
#if HAS_X_AXIS
SERIAL_ECHO_TERNARY(dynamic, AXIS_0_NAME " ", "base dynamic", "static", " shaper frequency: ");
SERIAL_ECHO(p_float_t(ftMotion.cfg.baseFreq.x, 2), F("Hz"));
SERIAL_CHAR(STEPPER_A_NAME);
SERIAL_ECHO_TERNARY(dynamic, " ", "base dynamic", "static", " shaper frequency: ");
SERIAL_ECHO(p_float_t(c.baseFreq.x, 2), F("Hz"));
#if HAS_DYNAMIC_FREQ
if (dynamic) SERIAL_ECHO(F(" scaling: "), p_float_t(ftMotion.cfg.dynFreqK.x, 2), F("Hz/"), z_based ? F("mm") : F("g"));
if (dynamic) SERIAL_ECHO(F(" scaling: "), p_float_t(c.dynFreqK.x, 2), F("Hz/"), z_based ? F("mm") : F("g"));
#endif
SERIAL_EOL();
#endif
#if HAS_Y_AXIS
SERIAL_ECHO_TERNARY(dynamic, AXIS_1_NAME " ", "base dynamic", "static", " shaper frequency: ");
SERIAL_ECHO(p_float_t(ftMotion.cfg.baseFreq.y, 2), F(" Hz"));
SERIAL_CHAR(STEPPER_B_NAME);
SERIAL_ECHO_TERNARY(dynamic, " ", "base dynamic", "static", " shaper frequency: ");
SERIAL_ECHO(p_float_t(c.baseFreq.y, 2), F(" Hz"));
#if HAS_DYNAMIC_FREQ
if (dynamic) SERIAL_ECHO(F(" scaling: "), p_float_t(ftMotion.cfg.dynFreqK.y, 2), F("Hz/"), z_based ? F("mm") : F("g"));
if (dynamic) SERIAL_ECHO(F(" scaling: "), p_float_t(c.dynFreqK.y, 2), F("Hz/"), z_based ? F("mm") : F("g"));
#endif
SERIAL_EOL();
#endif
#if ENABLED(FTM_SHAPER_Z)
SERIAL_CHAR(STEPPER_C_NAME);
SERIAL_ECHO_TERNARY(dynamic, " ", "base dynamic", "static", " shaper frequency: ");
SERIAL_ECHO(p_float_t(c.baseFreq.z, 2), F(" Hz"));
#if HAS_DYNAMIC_FREQ
if (dynamic) SERIAL_ECHO(F(" scaling: "), p_float_t(c.dynFreqK.z, 2), F("Hz/"), z_based ? F("mm") : F("g"));
#endif
SERIAL_EOL();
#endif
}
#if HAS_EXTRUDERS
SERIAL_ECHO_TERNARY(ftMotion.cfg.linearAdvEna, "Linear Advance ", "en", "dis", "abled");
if (ftMotion.cfg.linearAdvEna)
SERIAL_ECHOLNPGM(". Gain: ", ftMotion.cfg.linearAdvK);
else
SERIAL_EOL();
#endif
}
void GcodeSuite::M493_report(const bool forReplay/*=true*/) {
@ -129,26 +121,31 @@ void GcodeSuite::M493_report(const bool forReplay/*=true*/) {
report_heading_etc(forReplay, F(STR_FT_MOTION));
const ft_config_t &c = ftMotion.cfg;
SERIAL_ECHOPGM(" M493 S", c.active);
#if HAS_X_AXIS
SERIAL_ECHOPGM(" A", c.baseFreq.x);
#if HAS_Y_AXIS
SERIAL_ECHOPGM(" B", c.baseFreq.y);
SERIAL_ECHOLNPGM(
" M493 S", c.active
#if HAS_DYNAMIC_FREQ
, " D", c.dynFreqMode
#endif
#endif
// Axis Synchronization
, " H", c.axis_sync_enabled
);
#if HAS_DYNAMIC_FREQ
SERIAL_ECHOPGM(" D", c.dynFreqMode);
#if HAS_X_AXIS
SERIAL_ECHOPGM(" F", c.dynFreqK.x);
#if HAS_Y_AXIS
SERIAL_ECHOPGM(" H", c.dynFreqK.y);
#endif
#endif
#define F_REPORT(A) , F(" F"), c.dynFreqK.A
#else
#define F_REPORT(A)
#endif
#if HAS_EXTRUDERS
SERIAL_ECHOPGM(" P", c.linearAdvEna, " K", c.linearAdvK);
#endif
SERIAL_EOL();
#define _REPORT_M493_AXIS(A) \
SERIAL_ECHOLN(F(" M493 "), C(AXIS_CHAR(_AXIS(A))) \
, F(" C"), c.shaper.A \
, F(" A"), c.baseFreq.A \
F_REPORT(A) \
, F(" I"), c.zeta.A \
, F(" Q"), c.vtol.A \
);
// Shaper type for each axis
SHAPED_MAP(_REPORT_M493_AXIS);
}
/**
@ -158,8 +155,23 @@ void GcodeSuite::M493_report(const bool forReplay/*=true*/) {
* 0: Fixed-Time Motion OFF (Standard Motion)
* 1: Fixed-Time Motion ON
*
* X/Y<mode> Set the vibration compensator [input shaper] mode for X / Y axis.
* Users / slicers must remember to set the mode for both axes!
* V Flag to request version (Version 2+). (No reply = Version < 2)
*
* H<bool> Enable (1) or Disable (0) Axis Synchronization.
*
* Linear / Pressure Advance:
*
* P<bool> Enable (1) or Disable (0) Linear Advance pressure control
*
* Specifying Axes (for A,C,F,I,Q):
*
* X/Y/Z/E : Flag the axes (or core steppers) on which to apply the given parameters
* If none are given then XY is assumed.
*
* Compensator / Input Shaper:
*
* C<mode> Set Compensator Mode (Input Shaper) for the specified axes
* Users / slicers must remember to set the mode for all relevant axes!
* 0: NONE : No input shaper
* 1: ZV : Zero Vibration
* 2: ZVD : Zero Vibration and Derivative
@ -170,26 +182,27 @@ void GcodeSuite::M493_report(const bool forReplay/*=true*/) {
* 7: 3HEI : 3-Hump Extra-Intensive
* 8: MZV : Mass-based Zero Vibration
*
* P<bool> Enable (1) or Disable (0) Linear Advance pressure control
* A<Hz> Set static/base frequency for the specified axes
* I<flt> Set damping ratio for the specified axes
* Q<flt> Set vibration tolerance (vtol) for the specified axes
*
* K<gain> Set Linear Advance gain
* Dynamic Frequency Mode:
*
* D<mode> Set Dynamic Frequency mode
* D<mode> Set Dynamic Frequency mode (for all axis compensators)
* 0: DISABLED
* 1: Z-based (Requires a Z axis)
* 2: Mass-based (Requires X and E axes)
*
* A<Hz> Set static/base frequency for the X axis
* F<Hz> Set frequency scaling for the X axis
* I 0.0 Set damping ratio for the X axis
* Q 0.00 Set the vibration tolerance for the X axis
* F<Hz> Set frequency scaling for the specified axes
*
* B<Hz> Set static/base frequency for the Y axis
* H<Hz> Set frequency scaling for the Y axis
* J 0.0 Set damping ratio for the Y axis
* R 0.00 Set the vibration tolerance for the Y axis
*/
void GcodeSuite::M493() {
// Request version of FTM. (No response = Version < 2)
if (parser.seen('V') && !parser.has_value()) {
SERIAL_ECHOLNPGM("FTM V" STRINGIFY(FTM_VERSION));
return;
}
struct { bool update:1, report:1; } flag = { false };
if (!parser.seen_any())
@ -205,65 +218,42 @@ void GcodeSuite::M493() {
}
}
#if HAS_X_AXIS
auto set_shaper = [&](const AxisEnum axis, const char c) {
const ftMotionShaper_t newsh = (ftMotionShaper_t)parser.value_byte();
#if NUM_AXES_SHAPED > 0
const bool seenC = parser.seenval('C');
const ftMotionShaper_t shaperVal = seenC ? (ftMotionShaper_t)parser.value_byte() : ftMotionShaper_NONE;
const bool goodShaper = WITHIN(shaperVal, ftMotionShaper_NONE, ftMotionShaper_MZV);
if (seenC && !goodShaper) {
SERIAL_ECHOLN(F("?Invalid "), F("(C)ompensator value. (0-"), int(ftMotionShaper_MZV));
return;
}
auto set_shaper = [&](const AxisEnum axis, ftMotionShaper_t newsh) {
if (newsh != ftMotion.cfg.shaper[axis]) {
switch (newsh) {
default: SERIAL_ECHOLNPGM("?Invalid [", C(c), "] shaper."); return true;
case ftMotionShaper_NONE:
case ftMotionShaper_ZV:
case ftMotionShaper_ZVD:
case ftMotionShaper_ZVDD:
case ftMotionShaper_ZVDDD:
case ftMotionShaper_EI:
case ftMotionShaper_2HEI:
case ftMotionShaper_3HEI:
case ftMotionShaper_MZV:
ftMotion.cfg.shaper[axis] = newsh;
flag.update = flag.report = true;
break;
}
ftMotion.cfg.shaper[axis] = newsh;
flag.update = flag.report = true;
}
return false;
};
if (seenC) {
#define _SET_SHAPER(A) set_shaper(_AXIS(A), shaperVal);
SHAPED_MAP(_SET_SHAPER);
}
if (parser.seenval('X') && set_shaper(X_AXIS, 'X')) return; // Parse 'X' mode parameter
#endif // NUM_AXES_SHAPED > 0
#if HAS_Y_AXIS
if (parser.seenval('Y') && set_shaper(Y_AXIS, 'Y')) return; // Parse 'Y' mode parameter
#endif
#endif // HAS_X_AXIS
#if HAS_EXTRUDERS
// Pressure control (linear advance) parameter.
if (parser.seen('P')) {
const bool val = parser.value_bool();
ftMotion.cfg.linearAdvEna = val;
// Parse 'H' Axis Synchronization parameter.
if (parser.seenval('H')) {
const bool enabled = parser.value_bool();
if (enabled != ftMotion.cfg.axis_sync_enabled) {
ftMotion.cfg.axis_sync_enabled = enabled;
flag.report = true;
SERIAL_ECHO_TERNARY(val, "Linear Advance ", "en", "dis", "abled.\n");
}
// Pressure control (linear advance) gain parameter.
if (parser.seenval('K')) {
const float val = parser.value_float();
if (WITHIN(val, 0.0f, 10.0f)) {
ftMotion.cfg.linearAdvK = val;
flag.report = true;
}
else // Value out of range.
SERIAL_ECHOLNPGM("Linear Advance gain out of range.");
}
#endif // HAS_EXTRUDERS
}
#if HAS_DYNAMIC_FREQ
// Dynamic frequency mode parameter.
if (parser.seenval('D')) {
if (AXIS_IS_SHAPING(X) || AXIS_IS_SHAPING(Y)) {
if (AXIS_IS_SHAPING(X) || AXIS_IS_SHAPING(Y) || AXIS_IS_SHAPING(Z) || AXIS_IS_SHAPING(E)) {
const dynFreqMode_t val = dynFreqMode_t(parser.value_byte());
switch (val) {
#if HAS_DYNAMIC_FREQ_MM
@ -277,12 +267,12 @@ void GcodeSuite::M493() {
flag.report = true;
break;
default:
SERIAL_ECHOLNPGM("?Invalid Dynamic Frequency Mode [D] value.");
SERIAL_ECHOLN(F("?Invalid "), F("(D)ynamic Frequency Mode value."));
break;
}
}
else {
SERIAL_ECHOLNPGM("?Wrong shaper for [D] Dynamic Frequency mode.");
SERIAL_ECHOLNPGM("?Wrong shaper for (D)ynamic Frequency Mode ", ftMotion.cfg.dynFreqMode, ".");
}
}
@ -293,129 +283,242 @@ void GcodeSuite::M493() {
#endif // HAS_DYNAMIC_FREQ
// Frequency parameter
const bool seenA = parser.seenval('A');
const float baseFreqVal = seenA ? parser.value_float() : 0.0f;
const bool goodBaseFreq = seenA && WITHIN(baseFreqVal, FTM_MIN_SHAPE_FREQ, (FTM_FS) / 2);
if (seenA && !goodBaseFreq)
SERIAL_ECHOLN(F("?Invalid "), F("(A) Base Frequency value. ("), int(FTM_MIN_SHAPE_FREQ), C('-'), int((FTM_FS) / 2), C(')'));
#if HAS_DYNAMIC_FREQ
// Dynamic Frequency parameter
const bool seenF = parser.seenval('F');
const float baseDynFreqVal = seenF ? parser.value_float() : 0.0f;
if (seenF && !modeUsesDynFreq)
SERIAL_ECHOLNPGM("?Wrong mode for (F)requency scaling.");
#endif
// Zeta parameter
const bool seenI = parser.seenval('I');
const float zetaVal = seenI ? parser.value_float() : 0.0f;
const bool goodZeta = seenI && WITHIN(zetaVal, 0.01f, 1.0f);
if (seenI && !goodZeta)
SERIAL_ECHOLN(F("?Invalid "), F("(I) Zeta value. (0.01-1.0)")); // Zeta out of range
// Vibration Tolerance parameter
const bool seenQ = parser.seenval('Q');
const float vtolVal = seenQ ? parser.value_float() : 0.0f;
const bool goodVtol = seenQ && WITHIN(vtolVal, 0.00f, 1.0f);
if (seenQ && !goodVtol)
SERIAL_ECHOLN(F("?Invalid "), F("(Q) Vibration Tolerance value. (0.0-1.0)")); // VTol out of range
const bool apply_xy = !parser.seen("XYZE");
#if HAS_X_AXIS
// Parse frequency parameter (X axis).
if (parser.seenval('A')) {
if (AXIS_IS_SHAPING(X)) {
const float val = parser.value_float();
// TODO: Frequency minimum is dependent on the shaper used; the above check isn't always correct.
if (WITHIN(val, FTM_MIN_SHAPE_FREQ, (FTM_FS) / 2)) {
ftMotion.cfg.baseFreq.x = val;
flag.update = flag.report = true;
}
else // Frequency out of range.
SERIAL_ECHOLNPGM("Invalid [", C('A'), "] frequency value.");
}
else // Mode doesn't use frequency.
SERIAL_ECHOLNPGM("Wrong mode for [", C('A'), "] frequency.");
}
if (apply_xy || parser.seen_test('X')) {
#if HAS_DYNAMIC_FREQ
// Parse frequency scaling parameter (X axis).
if (parser.seenval('F')) {
if (modeUsesDynFreq) {
ftMotion.cfg.dynFreqK.x = parser.value_float();
// Parse X frequency parameter
if (seenA) {
if (AXIS_IS_SHAPING(X)) {
// TODO: Frequency minimum is dependent on the shaper used; the above check isn't always correct.
if (goodBaseFreq) {
ftMotion.cfg.baseFreq.x = baseFreqVal;
flag.update = flag.report = true;
}
}
else // Mode doesn't use frequency.
SERIAL_ECHOLNPGM("?Wrong mode for ", C(STEPPER_A_NAME), " [A] frequency.");
}
#if HAS_DYNAMIC_FREQ
// Parse X frequency scaling parameter
if (seenF && modeUsesDynFreq) {
ftMotion.cfg.dynFreqK.x = baseDynFreqVal;
flag.report = true;
}
else
SERIAL_ECHOLNPGM("Wrong mode for [", C('F'), "] frequency scaling.");
}
#endif
#endif
// Parse zeta parameter (X axis).
if (parser.seenval('I')) {
const float val = parser.value_float();
if (AXIS_IS_SHAPING(X)) {
if (WITHIN(val, 0.01f, 1.0f)) {
ftMotion.cfg.zeta[0] = val;
flag.update = true;
// Parse X zeta parameter
if (seenI) {
if (AXIS_IS_SHAPING(X)) {
if (goodZeta) {
ftMotion.cfg.zeta.x = zetaVal;
flag.update = true;
}
}
else
SERIAL_ECHOLNPGM("Invalid X zeta [", C('I'), "] value."); // Zeta out of range.
SERIAL_ECHOLNPGM("?Wrong mode for ", C(STEPPER_A_NAME), " zeta parameter.");
}
else
SERIAL_ECHOLNPGM("Wrong mode for zeta parameter.");
}
// Parse vtol parameter (X axis).
if (parser.seenval('Q')) {
const float val = parser.value_float();
if (AXIS_IS_EISHAPING(X)) {
if (WITHIN(val, 0.00f, 1.0f)) {
ftMotion.cfg.vtol[0] = val;
flag.update = true;
// Parse X vtol parameter
if (seenQ) {
if (AXIS_IS_EISHAPING(X)) {
if (goodVtol) {
ftMotion.cfg.vtol.x = vtolVal;
flag.update = true;
}
}
else
SERIAL_ECHOLNPGM("Invalid X vtol [", C('Q'), "] value."); // VTol out of range.
SERIAL_ECHOLNPGM("?Wrong mode for ", C(STEPPER_A_NAME), " vtol parameter.");
}
else
SERIAL_ECHOLNPGM("Wrong mode for vtol parameter.");
}
#endif // HAS_X_AXIS
#if HAS_Y_AXIS
// Parse frequency parameter (Y axis).
if (parser.seenval('B')) {
if (AXIS_IS_SHAPING(Y)) {
const float val = parser.value_float();
if (WITHIN(val, FTM_MIN_SHAPE_FREQ, (FTM_FS) / 2)) {
ftMotion.cfg.baseFreq.y = val;
flag.update = flag.report = true;
}
else // Frequency out of range.
SERIAL_ECHOLNPGM("Invalid frequency [", C('B'), "] value.");
}
else // Mode doesn't use frequency.
SERIAL_ECHOLNPGM("Wrong mode for [", C('B'), "] frequency.");
}
if (apply_xy || parser.seen_test('Y')) {
#if HAS_DYNAMIC_FREQ
// Parse frequency scaling parameter (Y axis).
if (parser.seenval('H')) {
if (modeUsesDynFreq) {
ftMotion.cfg.dynFreqK.y = parser.value_float();
// Parse Y frequency parameter
if (seenA) {
if (AXIS_IS_SHAPING(Y)) {
if (goodBaseFreq) {
ftMotion.cfg.baseFreq.y = baseFreqVal;
flag.update = flag.report = true;
}
}
else // Mode doesn't use frequency.
SERIAL_ECHOLNPGM("?Wrong mode for ", C(STEPPER_B_NAME), " [A] frequency.");
}
#if HAS_DYNAMIC_FREQ
// Parse Y frequency scaling parameter
if (seenF && modeUsesDynFreq) {
ftMotion.cfg.dynFreqK.y = baseDynFreqVal;
flag.report = true;
}
else
SERIAL_ECHOLNPGM("Wrong mode for [", C('H'), "] frequency scaling.");
}
#endif
#endif
// Parse zeta parameter (Y axis).
if (parser.seenval('J')) {
const float val = parser.value_float();
if (AXIS_IS_SHAPING(Y)) {
if (WITHIN(val, 0.01f, 1.0f)) {
ftMotion.cfg.zeta[1] = val;
flag.update = true;
// Parse Y zeta parameter
if (seenI) {
if (AXIS_IS_SHAPING(Y)) {
if (goodZeta) {
ftMotion.cfg.zeta.y = zetaVal;
flag.update = true;
}
}
else
SERIAL_ECHOLNPGM("Invalid Y zeta [", C('J'), "] value."); // Zeta Out of range
SERIAL_ECHOLNPGM("?Wrong mode for ", C(STEPPER_B_NAME), " zeta parameter.");
}
else
SERIAL_ECHOLNPGM("Wrong mode for zeta parameter.");
}
// Parse vtol parameter (Y axis).
if (parser.seenval('R')) {
const float val = parser.value_float();
if (AXIS_IS_EISHAPING(Y)) {
if (WITHIN(val, 0.00f, 1.0f)) {
ftMotion.cfg.vtol[1] = val;
flag.update = true;
// Parse Y vtol parameter
if (seenQ) {
if (AXIS_IS_EISHAPING(Y)) {
if (goodVtol) {
ftMotion.cfg.vtol.y = vtolVal;
flag.update = true;
}
}
else
SERIAL_ECHOLNPGM("Invalid Y vtol [", C('R'), "] value."); // VTol out of range.
SERIAL_ECHOLNPGM("?Wrong mode for ", C(STEPPER_B_NAME), " vtol parameter.");
}
else
SERIAL_ECHOLNPGM("Wrong mode for vtol parameter.");
}
#endif // HAS_Y_AXIS
#if ENABLED(FTM_SHAPER_Z)
if (parser.seen_test('Z')) {
// Parse Z frequency parameter
if (seenA) {
if (AXIS_IS_SHAPING(Z)) {
if (goodBaseFreq) {
ftMotion.cfg.baseFreq.z = baseFreqVal;
flag.update = flag.report = true;
}
}
else // Mode doesn't use frequency.
SERIAL_ECHOLNPGM("?Wrong mode for ", C(STEPPER_C_NAME), " [A] frequency.");
}
#if HAS_DYNAMIC_FREQ
// Parse Z frequency scaling parameter
if (seenF && modeUsesDynFreq) {
ftMotion.cfg.dynFreqK.z = baseDynFreqVal;
flag.report = true;
}
#endif
// Parse Z zeta parameter
if (seenI) {
if (AXIS_IS_SHAPING(Z)) {
if (goodZeta) {
ftMotion.cfg.zeta.z = zetaVal;
flag.update = true;
}
}
else
SERIAL_ECHOLNPGM("?Wrong mode for ", C(STEPPER_C_NAME), " zeta parameter.");
}
// Parse Z vtol parameter
if (seenQ) {
if (AXIS_IS_EISHAPING(Z)) {
if (goodVtol) {
ftMotion.cfg.vtol.z = vtolVal;
flag.update = true;
}
}
else
SERIAL_ECHOLNPGM("?Wrong mode for ", C(STEPPER_C_NAME), " vtol parameter.");
}
}
#endif // FTM_SHAPER_Z
#if ENABLED(FTM_SHAPER_E)
if (parser.seen_test('E')) {
// Parse E frequency parameter
if (seenA) {
if (AXIS_IS_SHAPING(E)) {
if (goodBaseFreq) {
ftMotion.cfg.baseFreq.e = baseFreqVal;
flag.update = flag.report = true;
}
}
else // Mode doesn't use frequency.
SERIAL_ECHOLNPGM("?Wrong mode for ", C('E'), " [A] frequency.");
}
#if HAS_DYNAMIC_FREQ
// Parse E frequency scaling parameter
if (seenF && modeUsesDynFreq) {
ftMotion.cfg.dynFreqK.e = baseDynFreqVal;
flag.report = true;
}
#endif
// Parse E zeta parameter
if (seenI) {
if (AXIS_IS_SHAPING(E)) {
if (goodZeta) {
ftMotion.cfg.zeta.e = zetaVal;
flag.update = true;
}
}
else
SERIAL_ECHOLNPGM("?Wrong mode for ", C('E'), " zeta parameter.");
}
// Parse E vtol parameter
if (seenQ) {
if (AXIS_IS_EISHAPING(E)) {
if (goodVtol) {
ftMotion.cfg.vtol.e = vtolVal;
flag.update = true;
}
}
else
SERIAL_ECHOLNPGM("?Wrong mode for ", C('E'), " vtol parameter.");
}
}
#endif // FTM_SHAPER_E
if (flag.update) ftMotion.update_shaping_params();
if (flag.report) say_shaping();

View file

@ -0,0 +1,137 @@
/**
* 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 ENABLED(FT_MOTION)
#include "../../gcode.h"
#include "../../../module/ft_motion.h"
#include "../../../module/stepper.h"
#include "../../../module/planner.h"
static FSTR_P get_trajectory_type_name() {
switch (ftMotion.getTrajectoryType()) {
default:
case TrajectoryType::TRAPEZOIDAL: return GET_TEXT_F(MSG_FTM_TRAPEZOIDAL);
case TrajectoryType::POLY5: return GET_TEXT_F(MSG_FTM_POLY5);
case TrajectoryType::POLY6: return GET_TEXT_F(MSG_FTM_POLY6);
}
}
void say_ftm_settings() {
SERIAL_ECHOLN(F(" Trajectory: "), get_trajectory_type_name(), C('('), (uint8_t)ftMotion.getTrajectoryType(), C(')'));
const ft_config_t &c = ftMotion.cfg;
if (ftMotion.getTrajectoryType() == TrajectoryType::POLY6)
SERIAL_ECHOLNPGM(" Poly6 Overshoot: ", p_float_t(c.poly6_acceleration_overshoot, 3));
#if ENABLED(FTM_SMOOTHING)
#define _SMOO_REPORT(A) SERIAL_ECHOLN(F(" "), C(IAXIS_CHAR(_AXIS(A))), F(" smoothing time: "), p_float_t(c.smoothingTime.A, 3), C('s'));
CARTES_MAP(_SMOO_REPORT);
#endif
}
void GcodeSuite::M494_report(const bool forReplay/*=true*/) {
TERN_(MARLIN_SMALL_BUILD, return);
const ft_config_t &c = ftMotion.cfg;
report_heading_etc(forReplay, F("FT Motion"));
SERIAL_ECHOPGM(" M494 T", (uint8_t)ftMotion.getTrajectoryType());
#if ENABLED(FTM_SMOOTHING)
SERIAL_ECHOPGM(
CARTES_PAIRED_LIST(
" X", c.smoothingTime.X, " Y", c.smoothingTime.Y,
" Z", c.smoothingTime.Z, " E", c.smoothingTime.E
)
);
#endif
if (ftMotion.getTrajectoryType() == TrajectoryType::POLY6)
SERIAL_ECHOPGM(" O", c.poly6_acceleration_overshoot);
SERIAL_EOL();
}
/**
* M494: Set Fixed-time Motion Control parameters
*
* Parameters:
* T<type> Set trajectory generator type (0=TRAPEZOIDAL, 1=POLY5, 2=POLY6)
* O<overshoot> Set acceleration overshoot for POLY6 (1.25-1.875)
* X<time> Set smoothing time for the X axis
* Y<time> Set smoothing time for the Y axis
* Z<time> Set smoothing time for the Z axis
* E<time> Set smoothing time for the E axis
*/
void GcodeSuite::M494() {
bool report = !parser.seen_any();
// Parse trajectory type parameter.
if (parser.seenval('T')) {
const int val = parser.value_int();
if (WITHIN(val, 0, 2)) {
planner.synchronize();
ftMotion.setTrajectoryType((TrajectoryType)val);
report = true;
}
else
SERIAL_ECHOLN(F("?Invalid "), F("trajectory type [T] value. Use 0=TRAPEZOIDAL, 1=POLY5, 2=POLY6"));
}
// Parse overshoot parameter.
if (parser.seenval('O')) {
const float val = parser.value_float();
if (WITHIN(val, 1.25f, 1.875f)) {
ftMotion.cfg.poly6_acceleration_overshoot = val;
report = true;
}
else
SERIAL_ECHOLN(F("?Invalid "), F("overshoot [O] value. Range 1.25-1.875"));
}
#if ENABLED(FTM_SMOOTHING)
#define SMOOTH_SET(A,N) \
if (parser.seenval(CHARIFY(A))) { \
const float val = parser.value_float(); \
if (WITHIN(val, 0.0f, FTM_MAX_SMOOTHING_TIME)) { \
ftMotion.set_smoothing_time(_AXIS(A), val); \
report = true; \
} \
else \
SERIAL_ECHOLN("?Invalid ", C(N), " smoothing time [", C(CHARIFY(A)), "] value."); \
}
CARTES_GANG(
SMOOTH_SET(X, STEPPER_A_NAME), SMOOTH_SET(Y, STEPPER_B_NAME),
SMOOTH_SET(Z, STEPPER_C_NAME), SMOOTH_SET(E, 'E')
);
#endif // FTM_SMOOTHING
if (report) say_ftm_settings();
}
#endif // FT_MOTION

View file

@ -0,0 +1,186 @@
/**
* 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/MarlinConfig.h"
#if ENABLED(FTM_RESONANCE_TEST)
#include "../../gcode.h"
#include "../../../module/ft_motion.h"
#include "../../../module/ft_motion/resonance_generator.h"
void say_resonance_test() {
const ftm_resonance_test_params_t &p = ftMotion.rtg.rt_params;
SERIAL_ECHO_START();
SERIAL_ECHOLN(F("M495 "), F("Resonance Test"));
SERIAL_ECHOLNPGM(" Axis: ", p.axis == NO_AXIS_ENUM ? C('-') : C(AXIS_CHAR(p.axis)));
SERIAL_ECHOLNPGM(" Freq Range (F..T): ", p.min_freq, " .. ", p.max_freq, " Hz");
SERIAL_ECHOLNPGM(" Octave Duration (O): ", p.octave_duration, " s");
SERIAL_ECHOLNPGM(" Accel/Hz (A): ", p.accel_per_hz);
}
/**
* M495: Configure and run the resonance test.
* With no parameters report the current settings.
*
* Parameters:
* A<accel/Hz> Accel per Hz. (Default 60)
* F<Hz> Start frequency. (Default 5.0)
* S Start the test.
* T<Hz> End frequency. (Default 100.0f)
* O<float> Octave duration for logarithmic progression
* C<int> Amplitude correction factor. (Default 5)
* X Flag to select the X axis.
* Y Flag to select the Y axis.
* Z Flag to select the Z axis.
* H<float> Get the Resonance Frequency from Timeline value. (Default 0)
*
* Examples:
* M495 S : Start the test with default or last-used parameters
* M495 X S : Start the test on the X axis with default or last-used parameters
* M495 H<val> : Get Resonance Frequency from Timeline value
*
*/
void GcodeSuite::M495() {
if (!parser.seen_any()) return say_resonance_test();
ftm_resonance_test_params_t &p = ftMotion.rtg.rt_params;
const bool seenX = parser.seen_test('X'), seenY = parser.seen_test('Y'), seenZ = parser.seen_test('Z');
if (seenX + seenY + seenZ == 1) {
const AxisEnum a = seenX ? X_AXIS : seenY ? Y_AXIS : Z_AXIS;
p.axis = a;
SERIAL_ECHOLN(C(AXIS_CHAR(a)), F("-axis selected"), F(" for "), F("Resonance Test"));
}
else if (seenX + seenY + seenZ > 1) {
SERIAL_ECHOLN(F("?Specify X, Y, or Z axis"), F(" for "), F("Resonance Test"));
return;
}
if (parser.seenval('A')) {
const float val = parser.value_float();
if (p.axis == Z_AXIS && val > 15.0f) {
p.accel_per_hz = 15.0f;
SERIAL_ECHOLNPGM("Accel/Hz set to max 15 mm/s for Z Axis");
}
else {
p.accel_per_hz = val;
SERIAL_ECHOLNPGM("Accel/Hz set to ", p.accel_per_hz);
}
}
if (parser.seenval('F')) {
const float val = parser.value_float();
if (val >= 5.0f) {
p.min_freq = val;
SERIAL_ECHOLNPGM("Start Frequency set to ", p.min_freq, " Hz");
}
else {
SERIAL_ECHOLN(F("?Invalid "), F("Start [F]requency. (minimum 5.0 Hz)"));
}
}
if (parser.seenval('T')) {
const float val = parser.value_float();
if (val > p.min_freq && val <= 200.0f) {
p.max_freq = val;
SERIAL_ECHOLNPGM("End Frequency set to ", p.max_freq, " Hz");
}
else {
SERIAL_ECHOLN(F("?Invalid "), F("End Frequency [T]. (StartFreq .. 200 Hz)"));
}
}
if (parser.seenval('O')) {
const float val = parser.value_float();
if (WITHIN(val, 20, 60)) {
p.octave_duration = val;
SERIAL_ECHOLNPGM("Octave Duration set to ",p.octave_duration, " s");
}
else {
SERIAL_ECHOLN(F("?Invalid "), F("octave duration [O]. (20..60 s)"));
}
}
if (parser.seenval('C')) {
const int val = parser.value_int();
if (WITHIN(val, 1, 8)) {
p.amplitude_correction = val;
SERIAL_ECHOLNPGM("Amplitude Correction Factor set to ", p.amplitude_correction);
}
else {
SERIAL_ECHOLN(F("?Invalid "), F("Amplitude [C]orrection Factor. (1..8)"));
}
}
if (parser.seenval('G')) {
const float val = parser.value_float();
if (WITHIN(val, 0, 100)) {
ftMotion.rtg.timeline = val;
SERIAL_ECHOLNPGM("Resonance Frequency set to ", ftMotion.rtg.getFrequencyFromTimeline(), " Hz");
}
else {
SERIAL_ECHOLN(F("?Invalid "), F("Timeline value (0..100 s)"));
}
}
if (parser.seen_test('S')) {
if (ftMotion.cfg.active) {
if (p.axis != NO_AXIS_ENUM) {
if (p.max_freq > p.min_freq) {
SERIAL_ECHOLN(F("Starting "), F("Resonance Test"));
ftMotion.start_resonance_test();
// The function returns immediately, the test runs in the background.
}
else {
SERIAL_ECHOLNPGM("?End Frequency must be greater than Start Frequency");
}
}
else {
SERIAL_ECHOLN(F("?Specify X, Y, or Z axis"), F(" first"));
}
}
else {
SERIAL_ECHOLN(F("?Activate FT Motion to run the "), F("Resonance Test"));
}
}
}
/**
* M496: Abort the resonance test (via Emergency Parser)
*/
void GcodeSuite::M496() {
if (ftMotion.rtg.isActive()) {
ftMotion.rtg.abort();
EmergencyParser::rt_stop_by_M496 = false;
#if DISABLED(MARLIN_SMALL_BUILD)
SERIAL_ECHOLN(F("Resonance Test"), F(" aborted."));
#endif
return;
}
#if DISABLED(MARLIN_SMALL_BUILD)
SERIAL_ECHOLN(F("No active "), F("Resonance Test"), F(" to abort."));
#endif
}
#endif // FTM_RESONANCE_TEST

View file

@ -40,8 +40,8 @@
* M260 B<byte-2 value in base 10>
* M260 B<byte-3 value in base 10>
*
* M260 S1 ; Send the buffered data and reset the buffer
* M260 R1 ; Reset the buffer without sending data
* M260 S ; Send the buffered data and reset the buffer
* M260 R ; Reset the buffer without sending data
*/
void GcodeSuite::M260() {
// Set the target address
@ -51,10 +51,10 @@ void GcodeSuite::M260() {
if (parser.seenval('B')) i2c.addbyte(parser.value_byte());
// Flush the buffer to the bus
if (parser.seen('S')) i2c.send();
if (parser.seen_test('S')) i2c.send();
// Reset and rewind the buffer
else if (parser.seen('R')) i2c.reset();
else if (parser.seen_test('R')) i2c.reset();
}
/**

View file

@ -0,0 +1,69 @@
/**
* 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/MarlinConfig.h"
#if ENABLED(I2C_SCANNER)
#include "../../../libs/hex_print.h"
#include "../../gcode.h"
#include <Wire.h> // Include Wire library for I2C communication
/**
* M265: I2C Scanner - Scan for I2C devices on DOGLCD I2C pins
*
* Usage: M265
*
* Scans I2C addresses 0x08 to 0x77 and reports any responding devices.
*/
void GcodeSuite::M265() {
Wire.begin();
int device_count = 0;
SERIAL_ECHOLNPGM("Scanning I2C (0x08-0x77)...");
for (uint8_t address = 0x08; address <= 0x77; address++) {
Wire.beginTransmission(address);
const uint8_t error = Wire.endTransmission();
if (error == 0) {
// Device found
device_count++;
SERIAL_ECHOLNPGM("I2C device found at address 0x", hex_byte(address));
}
else if (error == 4)
SERIAL_ECHOLNPGM("Unknown error at address 0x", hex_byte(address));
safe_delay(5); // Small delay between scans
}
SERIAL_ECHOPGM("I2C scan complete. ");
if (device_count == 0)
SERIAL_ECHOLNPGM("No I2C devices found");
else {
SERIAL_ECHOLN("Found ", device_count, " device");
if (device_count > 1) SERIAL_CHAR('s');
SERIAL_EOL();
}
}
#endif // I2C_SCANNER

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