diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index 54627d462b..96d6af1932 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -38,14 +38,14 @@ "platformio.platformio-ide", "marlinfirmware.auto-build", "editorconfig.editorconfig" - ], + ] // Use 'forwardPorts' to make a list of ports inside the container available locally. - // "forwardPorts": [], + // , "forwardPorts": [] // Use 'postCreateCommand' to run commands after the container is created. - // "postCreateCommand": "pip3 install --user -r requirements.txt", + // , "postCreateCommand": "pip3 install --user -r requirements.txt" // Comment out connect as root instead. More info: https://aka.ms/vscode-remote/containers/non-root. - // "remoteUser": "vscode" + // , "remoteUser": "vscode" } diff --git a/.github/workflows/ci-build-tests.yml b/.github/workflows/ci-build-tests.yml index afe9292c19..5d53536a27 100644 --- a/.github/workflows/ci-build-tests.yml +++ b/.github/workflows/ci-build-tests.yml @@ -21,6 +21,7 @@ on: branches: - bugfix-2.1.x - 2.1.x + - release-* paths-ignore: - config/** - data/** @@ -36,6 +37,9 @@ jobs: runs-on: ubuntu-22.04 + env: + CONFIG_BRANCH: ${{ github.base_ref || github.ref_name }} + strategy: fail-fast: true matrix: @@ -54,7 +58,7 @@ jobs: - at90usb1286_dfu # AVR Extended - - FYSETC_F6 + - mega2560ext - melzi_optiboot - rambo - sanguino1284p @@ -113,7 +117,7 @@ jobs: - BTT_GTR_V1_0 - BTT_SKR_PRO - FLYF407ZG - - FYSETC_S6 + - STM32F446VE_fysetc - LERDGEK - LERDGEX - mks_robin_pro2 @@ -151,6 +155,12 @@ jobs: # HC32 - HC32F460C_aquila_101 + # GD32F3 + - GD32F303RE_creality_mfl + + # GD32F1 + - GD32F103RC_aquila_mfl + # LPC176x - Lengthy tests - LPC1768 - LPC1769 @@ -164,15 +174,20 @@ jobs: uses: actions/cache@v4 with: path: ~/.cache/pip - key: ${{ runner.os }}-pip-${{ hashFiles('**/requirements.txt') }} + key: ${{ runner.os }}-pip-build-v1 restore-keys: | - ${{ runner.os }}-pip- + ${{ runner.os }}-pip-build- - name: Cache PlatformIO uses: actions/cache@v4 with: - path: ~/.platformio - key: ${{ runner.os }}-${{ hashFiles('**/lockfiles') }} + path: | + ~/.platformio + .pio/build + .pio/libdeps + key: ${{ runner.os }}-pio-build-v1 + restore-keys: | + ${{ runner.os }}-pio-build- - name: Select Python 3.9 uses: actions/setup-python@v5 @@ -188,6 +203,7 @@ jobs: - name: Install Simulator dependencies run: | + sudo apt-get update sudo apt-get install build-essential sudo apt-get install libsdl2-dev sudo apt-get install libsdl2-net-dev diff --git a/.github/workflows/ci-unit-tests.yml b/.github/workflows/ci-unit-tests.yml index 9a311aabc6..30af812dff 100644 --- a/.github/workflows/ci-unit-tests.yml +++ b/.github/workflows/ci-unit-tests.yml @@ -46,15 +46,20 @@ jobs: uses: actions/cache@v4 with: path: ~/.cache/pip - key: ${{ runner.os }}-pip-${{ hashFiles('**/requirements.txt') }} + key: ${{ runner.os }}-pip-unit-v1 restore-keys: | - ${{ runner.os }}-pip- + ${{ runner.os }}-pip-unit- - name: Cache PlatformIO uses: actions/cache@v4 with: - path: ~/.platformio - key: ${{ runner.os }}-${{ hashFiles('**/lockfiles') }} + path: | + ~/.platformio + .pio/build + .pio/libdeps + key: ${{ runner.os }}-pio-tests-v1 + restore-keys: | + ${{ runner.os }}-pio-tests- - name: Select Python 3.9 uses: actions/setup-python@v5 diff --git a/.github/workflows/ci-validate-boards.yml b/.github/workflows/ci-validate-boards.yml index baa7b8b6e1..aa6d284f06 100644 --- a/.github/workflows/ci-validate-boards.yml +++ b/.github/workflows/ci-validate-boards.yml @@ -9,14 +9,14 @@ name: CI - Validate boards.h on: pull_request: branches: - - bugfix-2.1.x + - bugfix-2.1.x paths: - - 'Marlin/src/core/boards.h' + - "Marlin/src/core/boards.h" push: branches: - - bugfix-2.1.x + - bugfix-2.1.x paths: - - 'Marlin/src/core/boards.h' + - "Marlin/src/core/boards.h" jobs: validate_pins_files: @@ -26,23 +26,23 @@ jobs: runs-on: ubuntu-22.04 steps: - - name: Check out the PR - uses: actions/checkout@v4 + - name: Check out the PR + uses: actions/checkout@v4 - - name: Cache pip - uses: actions/cache@v4 - with: - path: ~/.cache/pip - key: ${{ runner.os }}-pip-${{ hashFiles('**/requirements.txt') }} - restore-keys: | - ${{ runner.os }}-pip- + - name: Cache pip + uses: actions/cache@v4 + with: + path: ~/.cache/pip + key: ${{ runner.os }}-pip-validation-v1 + restore-keys: | + ${{ runner.os }}-pip-validation- - - name: Select Python 3.9 - uses: actions/setup-python@v5 - with: - python-version: '3.9' - architecture: 'x64' + - name: Select Python 3.9 + uses: actions/setup-python@v5 + with: + python-version: "3.9" + architecture: "x64" - - name: Validate core/boards.h - run: | - make validate-boards -j + - name: Validate core/boards.h + run: | + make validate-boards -j diff --git a/.github/workflows/ci-validate-lines.yml b/.github/workflows/ci-validate-lines.yml new file mode 100644 index 0000000000..367db12e6c --- /dev/null +++ b/.github/workflows/ci-validate-lines.yml @@ -0,0 +1,40 @@ +# +# ci-validate-lines.yml +# Validate that all text files are unchanged by linesformat.py +# + +name: CI - Validate Source Files + +on: + pull_request: + branches: + - bugfix-2.1.x + - 2.1.x + push: + branches: + - bugfix-2.1.x + - 2.1.x + +jobs: + validate_source_files: + name: Validate Source Files + if: github.repository == 'MarlinFirmware/Marlin' + + runs-on: ubuntu-22.04 + + steps: + - name: Check out the PR + uses: actions/checkout@v4 + + - name: Cache node_modules + uses: actions/cache@v4 + with: + path: node_modules + key: ${{ runner.os }}-npm-lines-v1 + restore-keys: | + ${{ runner.os }}-npm-lines- + + - name: Validate text file formatting + run: | + npm install --save-dev prettier + make validate-lines -j diff --git a/.github/workflows/ci-validate-pins.yml b/.github/workflows/ci-validate-pins.yml index 695f8eff18..2086fea37a 100644 --- a/.github/workflows/ci-validate-pins.yml +++ b/.github/workflows/ci-validate-pins.yml @@ -8,18 +8,18 @@ name: CI - Validate Pins Files on: pull_request: branches: - - bugfix-2.1.x + - bugfix-2.1.x # Cannot be enabled on 2.1.x until it contains the unit test framework #- 2.1.x paths: - - 'Marlin/src/pins/*/**' + - "Marlin/src/pins/*/**" push: branches: - - bugfix-2.1.x + - bugfix-2.1.x # Cannot be enabled on 2.1.x until it contains the unit test framework #- 2.1.x paths: - - 'Marlin/src/pins/*/**' + - "Marlin/src/pins/*/**" jobs: validate_pins_files: @@ -29,23 +29,23 @@ jobs: runs-on: ubuntu-22.04 steps: - - name: Check out the PR - uses: actions/checkout@v4 + - name: Check out the PR + uses: actions/checkout@v4 - - name: Cache pip - uses: actions/cache@v4 - with: - path: ~/.cache/pip - key: ${{ runner.os }}-pip-${{ hashFiles('**/requirements.txt') }} - restore-keys: | - ${{ runner.os }}-pip- + - name: Cache pip + uses: actions/cache@v4 + with: + path: ~/.cache/pip + key: ${{ runner.os }}-pip-validation-v1 + restore-keys: | + ${{ runner.os }}-pip-validation- - - name: Select Python 3.9 - uses: actions/setup-python@v5 - with: - python-version: '3.9' - architecture: 'x64' + - name: Select Python 3.9 + uses: actions/setup-python@v5 + with: + python-version: "3.9" + architecture: "x64" - - name: Validate all pins files - run: | - make validate-pins -j + - name: Validate all pins files + run: | + make validate-pins -j diff --git a/.gitignore b/.gitignore old mode 100755 new mode 100644 index daa5c5c288..87d7ef47d3 --- a/.gitignore +++ b/.gitignore @@ -31,6 +31,11 @@ out-language/ *.gen *.sublime-workspace +# npm +node_modules/ +package.json +package-lock.json + # OS applet/ .DS_Store diff --git a/.prettierignore b/.prettierignore new file mode 100644 index 0000000000..62761b99e9 --- /dev/null +++ b/.prettierignore @@ -0,0 +1,10 @@ +# Prettier Ignore file +*.min.js +web-ui/ +buildroot/share/PlatformIO/boards +buildroot/share/PlatformIO/variants +*.sublime-project +*.sublime-syntax +.github +.vscode +launch.json diff --git a/Makefile b/Makefile index 83b27e566a..68c522e5b6 100644 --- a/Makefile +++ b/Makefile @@ -4,10 +4,36 @@ 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 Python‑3.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" @echo "make format-pins -j : Reformat all pins files (-j for parallel execution)" + @echo "make validate-lines -j : Validate line endings, fails on trailing whitespace, etc." @echo "make validate-pins -j : Validate all pins files, fails if any require reformatting" @echo "make validate-boards -j : Validate boards.h and pins.h for standards compliance" @echo "make tests-single-ci : Run a single test from inside the CI" @@ -17,9 +43,9 @@ help: @echo "make tests-all-local-docker : Run all tests locally, using docker" @echo "make unit-test-single-local : Run unit tests for a single config locally" @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 : 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" @@ -40,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 @@ -56,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 ; \ @@ -87,27 +116,56 @@ 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 $@" - @python $(SCRIPTS_DIR)/pinsformat.py $< $@ + @echo "Formatting pins $@" + @$(PYTHON) $(SCRIPTS_DIR)/pinsformat.py $< $@ format-pins: $(PINS) + @echo "Processed $(words $(PINS)) pins files" validate-pins: format-pins @echo "Validating pins files" @git diff --exit-code || (git status && echo "\nError: Pins files are not formatted correctly. Run \"make format-pins\" to fix.\n" && exit 1) +.PHONY: format-lines validate-lines + +format-lines: + @echo "Formatting all sources" + @$(PYTHON) $(SCRIPTS_DIR)/linesformat.py buildroot + @$(PYTHON) $(SCRIPTS_DIR)/linesformat.py Marlin + +validate-lines: + @echo "Validating text formatting" + @npx prettier --check . --editorconfig --object-wrap preserve + BOARDS_FILE := Marlin/src/core/boards.h .PHONY: validate-boards 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) diff --git a/Marlin/Configuration.h b/Marlin/Configuration.h index 7226d337d1..6441fdc278 100644 --- a/Marlin/Configuration.h +++ b/Marlin/Configuration.h @@ -129,6 +129,7 @@ // Name displayed in the LCD "Ready" message and Info menu //#define CUSTOM_MACHINE_NAME "3D Printer" +//#define CONFIGURABLE_MACHINE_NAME // Add G-code M550 to set/report the machine name // Printer's unique ID, used by some programs to differentiate between machines. // Choose your own or use a service like https://www.uuidgenerator.net/version4 @@ -147,9 +148,9 @@ * Options: A4988, A5984, DRV8825, LV8729, TB6560, TB6600, TMC2100, * TMC2130, TMC2130_STANDALONE, TMC2160, TMC2160_STANDALONE, * TMC2208, TMC2208_STANDALONE, TMC2209, TMC2209_STANDALONE, - * TMC2660, TMC2660_STANDALONE, TMC5130, TMC5130_STANDALONE, - * TMC5160, TMC5160_STANDALONE - * :['A4988', 'A5984', 'DRV8825', 'LV8729', 'TB6560', 'TB6600', 'TMC2100', 'TMC2130', 'TMC2130_STANDALONE', 'TMC2160', 'TMC2160_STANDALONE', 'TMC2208', 'TMC2208_STANDALONE', 'TMC2209', 'TMC2209_STANDALONE', 'TMC2660', 'TMC2660_STANDALONE', 'TMC5130', 'TMC5130_STANDALONE', 'TMC5160', 'TMC5160_STANDALONE'] + * TMC2240, TMC2660, TMC2660_STANDALONE, + * TMC5130, TMC5130_STANDALONE, TMC5160, TMC5160_STANDALONE + * :['A4988', 'A5984', 'DRV8825', 'LV8729', 'TB6560', 'TB6600', 'TMC2100', 'TMC2130', 'TMC2130_STANDALONE', 'TMC2160', 'TMC2160_STANDALONE', 'TMC2208', 'TMC2208_STANDALONE', 'TMC2209', 'TMC2209_STANDALONE', 'TMC2240', 'TMC2660', 'TMC2660_STANDALONE', 'TMC5130', 'TMC5130_STANDALONE', 'TMC5160', 'TMC5160_STANDALONE'] */ #define X_DRIVER_TYPE A4988 #define Y_DRIVER_TYPE A4988 @@ -259,6 +260,7 @@ #define SWITCHING_NOZZLE_SERVO_ANGLES { 0, 90 } // A pair of angles for { E0, E1 }. // For Dual Servo use two pairs: { { lower, raise }, { lower, raise } } #define SWITCHING_NOZZLE_SERVO_DWELL 2500 // Dwell time to wait for servo to make physical move + #define SWITCHING_NOZZLE_LIFT_TO_PROBE // Lift toolheads out of the way while probing #endif // Switch nozzles by bumping the toolhead. Requires EVENT_GCODE_TOOLCHANGE_#. @@ -303,6 +305,18 @@ #endif +/** + * Differential Extruder + * + * The X and E steppers work together to create a differential drive system. + * Simple : E steps = X + E ; X steps = X (E drives a loop, X stays the same) + * Balanced: E steps = X + E/2 ; X steps = X - E/2 (Dual loop system) + */ +//#define DIFFERENTIAL_EXTRUDER +#if ENABLED(DIFFERENTIAL_EXTRUDER) + //#define BALANCED_DIFFERENTIAL_EXTRUDER +#endif + /** * Switching Toolhead * @@ -486,7 +500,7 @@ * 10 : 100kΩ RS PRO 198-961 * 11 : 100kΩ Keenovo AC silicone mats, most Wanhao i3 machines - beta 3950, 1% * 12 : 100kΩ Vishay 0603 SMD NTCS0603E3104FXT (#8) - calibrated for Makibox hot bed - * 13 : 100kΩ Hisens up to 300°C - for "Simple ONE" & "All In ONE" hotend - beta 3950, 1% + * 13 : 100kΩ Hisense up to 300°C - for "Simple ONE" & "All In ONE" hotend - beta 3950, 1% * 14 : 100kΩ (R25), 4092K (beta25), 4.7kΩ pull-up, bed thermistor as used in Ender-5 S1 * 15 : 100kΩ Calibrated for JGAurora A5 hotend * 17 : 100kΩ Dagoma NTC white thermistor @@ -586,7 +600,7 @@ #define DUMMY_THERMISTOR_998_VALUE 25 #define DUMMY_THERMISTOR_999_VALUE 100 -// Resistor values when using MAX31865 sensors (-5) on TEMP_SENSOR_0 / 1 +// Resistor values when using MAX31865 sensors (-5) on TEMP_SENSOR_0 / 1 / 2 / BED #if TEMP_SENSOR_IS_MAX_TC(0) #define MAX31865_SENSOR_OHMS_0 100 // (Ω) Typically 100 or 1000 (PT100 or PT1000) #define MAX31865_CALIBRATION_OHMS_0 430 // (Ω) Typically 430 for Adafruit PT100; 4300 for Adafruit PT1000 @@ -599,6 +613,10 @@ #define MAX31865_SENSOR_OHMS_2 100 #define MAX31865_CALIBRATION_OHMS_2 430 #endif +#if TEMP_SENSOR_IS_MAX_TC(BED) + #define MAX31865_SENSOR_OHMS_BED 100 + #define MAX31865_CALIBRATION_OHMS_BED 430 +#endif #if HAS_E_TEMP_SENSOR #define TEMP_RESIDENCY_TIME 10 // (seconds) Time to wait for hotend to "settle" in M109 @@ -691,20 +709,22 @@ #define PID_K1 0.95 // Smoothing factor within any PID loop #if ENABLED(PIDTEMP) - //#define PID_DEBUG // Print PID debug data to the serial port. Use 'M303 D' to toggle activation. + //#define MIN_POWER 0 // Min power to improve PID stability (0..PID_MAX). + // Get the power from the temperature report ('M105' => @:nnn) and try P*2-20 to P*2-10. + //#define PID_DEBUG // Print PID debug data to the serial port. Use 'M303 D' to enable/disable. //#define PID_PARAMS_PER_HOTEND // Use separate PID parameters for each extruder (useful for mismatched extruders) // Set/get with G-code: M301 E[extruder number, 0-2] #if ENABLED(PID_PARAMS_PER_HOTEND) // Specify up to one value per hotend here, according to your setup. // If there are fewer values, the last one applies to the remaining hotends. - #define DEFAULT_Kp_LIST { 22.20, 22.20 } - #define DEFAULT_Ki_LIST { 1.08, 1.08 } - #define DEFAULT_Kd_LIST { 114.00, 114.00 } + #define DEFAULT_KP_LIST { 22.20, 22.20 } + #define DEFAULT_KI_LIST { 1.08, 1.08 } + #define DEFAULT_KD_LIST { 114.00, 114.00 } #else - #define DEFAULT_Kp 22.20 - #define DEFAULT_Ki 1.08 - #define DEFAULT_Kd 114.00 + #define DEFAULT_KP 22.20 + #define DEFAULT_KI 1.08 + #define DEFAULT_KD 114.00 #endif #else #define BANG_MAX 255 // Limit hotend current while in bang-bang mode; 255=full current @@ -727,7 +747,12 @@ //#define MPC_AUTOTUNE_MENU // Add MPC auto-tuning to the "Advanced Settings" menu. (~350 bytes of flash) #define MPC_MAX 255 // (0..255) Current to nozzle while MPC is active. - #define MPC_HEATER_POWER { 40.0f } // (W) Heat cartridge powers. + #define MPC_HEATER_POWER { 40.0f } // (W) Nominal heat cartridge powers. + //#define MPC_PTC // Hotend power changes with temperature (e.g., PTC heat cartridges). + #if ENABLED(MPC_PTC) + #define MPC_HEATER_ALPHA { 0.0028f } // Temperature coefficient of resistance of the heat cartridges. + #define MPC_HEATER_REFTEMP { 20 } // (°C) Reference temperature for MPC_HEATER_POWER and MPC_HEATER_ALPHA. + #endif #define MPC_INCLUDE_FAN // Model the fan speed? @@ -759,6 +784,7 @@ #define MPC_TUNING_POS { X_CENTER, Y_CENTER, 1.0f } // (mm) M306 Autotuning position, ideally bed center at first layer height. #define MPC_TUNING_END_Z 10.0f // (mm) M306 Autotuning final Z position. + //#define EVENT_GCODE_AFTER_MPC_TUNE "M84" // G-code to execute after MPC tune finished and Z raised. #endif //=========================================================================== @@ -790,14 +816,15 @@ //#define PIDTEMPBED #if ENABLED(PIDTEMPBED) - //#define MIN_BED_POWER 0 - //#define PID_BED_DEBUG // Print Bed PID debug data to the serial port. + //#define MIN_BED_POWER 0 // Min power to improve PID stability (0..MAX_BED_POWER). + // Get the power from the temperature report ('M105' => B@:nnn) and try P*2-20 to P*2-10. + //#define PID_BED_DEBUG // Print Bed PID debug data to the serial port. Use 'M303 D' to enable/disable. // 120V 250W silicone heater into 4mm borosilicate (MendelMax 1.5+) // from FOPDT model - kp=.39 Tp=405 Tdead=66, Tc set to 79.2, aggressive factor of .15 (vs .1, 1, 10) - #define DEFAULT_bedKp 10.00 - #define DEFAULT_bedKi .023 - #define DEFAULT_bedKd 305.4 + #define DEFAULT_BED_KP 10.00 + #define DEFAULT_BED_KI 0.023 + #define DEFAULT_BED_KD 305.4 // FIND YOUR OWN: "M303 E-1 C8 S90" to run autotune on the bed at 90 degreesC for 8 cycles. #else @@ -872,15 +899,15 @@ #define MAX_CHAMBER_POWER 255 // limits duty cycle to chamber heater; 255=full current #if ENABLED(PIDTEMPCHAMBER) - #define MIN_CHAMBER_POWER 0 - //#define PID_CHAMBER_DEBUG // Print Chamber PID debug data to the serial port. + //#define MIN_CHAMBER_POWER 0 // Min power to improve PID stability. (0..MAX_CHAMBER_POWER) + // Get the power from the temperature report ('M105' => C@:nnn) and try P*2-20 to P*2-10. + //#define PID_CHAMBER_DEBUG // Print Chamber PID debug data to the serial port. Use 'M303 D' to enable/disable. // Lasko "MyHeat Personal Heater" (200w) modified with a Fotek SSR-10DA to control only the heating element // and placed inside the small Creality printer enclosure tent. - // - #define DEFAULT_chamberKp 37.04 - #define DEFAULT_chamberKi 1.40 - #define DEFAULT_chamberKd 655.17 + #define DEFAULT_CHAMBER_KP 37.04 + #define DEFAULT_CHAMBER_KI 1.40 + #define DEFAULT_CHAMBER_KD 655.17 // M309 P37.04 I1.04 D655.17 // FIND YOUR OWN: "M303 E-2 C8 S50" to run autotune on the chamber at 50 degreesC for 8 cycles. @@ -891,7 +918,7 @@ #if ANY(PIDTEMP, PIDTEMPBED, PIDTEMPCHAMBER) //#define PID_OPENLOOP // Puts PID in open loop. M104/M140 sets the output power from 0 to PID_MAX //#define SLOW_PWM_HEATERS // PWM with very low frequency (roughly 0.125Hz=8s) and minimum state time of approximately 1s useful for heaters driven by a relay - #define PID_FUNCTIONAL_RANGE 10 // If the temperature difference between the target temperature and the actual temperature + #define PID_FUNCTIONAL_RANGE 20 // If the temperature difference between the target temperature and the actual temperature // is more than PID_FUNCTIONAL_RANGE then the PID will be shut off and the heater will be set to min/max. //#define PID_EDIT_MENU // Add PID editing to the "Advanced Settings" menu. (~700 bytes of flash) @@ -927,7 +954,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 @@ -1019,9 +1046,6 @@ // Print surface diameter/2 minus unreachable space (avoid collisions with vertical towers). #define PRINTABLE_RADIUS 140.0 // (mm) - // Maximum reachable area - #define DELTA_MAX_RADIUS 140.0 // (mm) - // Center-to-center distance of the holes in the diagonal push rods. #define DELTA_DIAGONAL_ROD 250.0 // (mm) @@ -1041,7 +1065,8 @@ // Delta radius and diagonal rod adjustments //#define DELTA_RADIUS_TRIM_TOWER { 0.0, 0.0, 0.0 } // (mm) //#define DELTA_DIAGONAL_ROD_TRIM_TOWER { 0.0, 0.0, 0.0 } // (mm) -#endif + +#endif // DELTA // @section scara @@ -1097,17 +1122,37 @@ #define TPARA_LINKAGE_1 120 // (mm) #define TPARA_LINKAGE_2 120 // (mm) - // TPARA tower offset (position of Tower relative to bed zero position) + // Height of the Shoulder axis (pivot) relative to the tower floor + #define TPARA_SHOULDER_AXIS_HEIGHT 135.0 // (mm) + + // The position of the last linkage relative to the robot arm origin + // (intersection of the base axis and floor) when at the home position + #define TPARA_ARM_X_HOME_POS 28.75 // (mm) Measured from shoulder axis to tool holder axis in home position + #define TPARA_ARM_Y_HOME_POS 0 // (mm) + #define TPARA_ARM_Z_HOME_POS 250.00 // (mm) Measured from tool holder axis to the floor + + // TPARA Workspace offset relative to the tower (position of workspace origin relative to robot Tower origin ) // This needs to be reasonably accurate as it defines the printbed position in the TPARA space. - #define TPARA_OFFSET_X 0 // (mm) - #define TPARA_OFFSET_Y 0 // (mm) - #define TPARA_OFFSET_Z 0 // (mm) + #define TPARA_OFFSET_X 127.0 // (mm) to coincide with minimum radius MIDDLE_DEAD_ZONE_R, and W(0,0,0) is reachable + #define TPARA_OFFSET_Y 0.0 // (mm) + #define TPARA_OFFSET_Z 0.0 // (mm) + + // TPARA tool connection point offset, relative to the tool moving frame origin which is in the last linkage axis, + // (TCP: tool center/connection point) of the robot, + // the plane of measured offset must be alligned with home position plane + #define TPARA_TCP_OFFSET_X 27.0 // (mm) Tool flange: 27 (distance from pivot to bolt holes), extruder tool: 50.0, + #define TPARA_TCP_OFFSET_Y 0.0 // (mm) + #define TPARA_TCP_OFFSET_Z -65.0 // (mm) Tool flange (bottom): -6 (caution as Z 0 posiion will crash second linkage to the floor, -35 is safe for testing with no tool), extruder tool (depends on extruder): -65.0 #define FEEDRATE_SCALING // Convert XY feedrate from mm/s to degrees/s on the fly // Radius around the center where the arm cannot reach - #define MIDDLE_DEAD_ZONE_R 0 // (mm) -#endif + // For now use a hardcoded uniform limit, although it should be calculated, or fix a limit for each axis angle + #define MIDDLE_DEAD_ZONE_R 100 // (mm) + + // Max angle between L1 and L2 + #define TPARA_MAX_L1L2_ANGLE 140.0f // (degrees) +#endif // AXEL_TPARA // @section polar @@ -1383,6 +1428,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 ============================= @@ -1507,7 +1557,6 @@ * For information about this sensor https://github.com/bigtreetech/MicroProbe * * Also requires PROBE_ENABLE_DISABLE - * With FT_MOTION requires ENDSTOP_INTERRUPTS_FEATURE */ //#define BIQU_MICROPROBE_V1 // Triggers HIGH //#define BIQU_MICROPROBE_V2 // Triggers LOW @@ -1535,6 +1584,20 @@ #define PROBE_DEPLOY_FEEDRATE (133*60) // (mm/min) Probe deploy speed #define PROBE_STOW_FEEDRATE (133*60) // (mm/min) Probe stow speed + /** + * Magnetically Mounted Probe with a Servo mechanism + * Probe Deploy and Stow both follow the same basic sequence: + * - Rotate the SERVO to its Deployed angle + * - Perform XYZ moves to deploy or stow the PROBE + * - Rotate the SERVO to its Stowed angle + */ + //#define MAG_MOUNTED_PROBE_SERVO_NR 0 // Servo Number for this probe + #ifdef MAG_MOUNTED_PROBE_SERVO_NR + #define MAG_MOUNTED_PROBE_SERVO_ANGLES { 90, 0 } // Servo Angles for Deployed, Stowed + #define MAG_MOUNTED_PRE_DEPLOY { PROBE_DEPLOY_FEEDRATE, { 15, 160, 30 } } // Safe position for servo activation + #define MAG_MOUNTED_PRE_STOW { PROBE_DEPLOY_FEEDRATE, { 15, 160, 30 } } // Safe position for servo deactivation + #endif + #define MAG_MOUNTED_DEPLOY_1 { PROBE_DEPLOY_FEEDRATE, { 245, 114, 30 } } // Move to side Dock & Attach probe #define MAG_MOUNTED_DEPLOY_2 { PROBE_DEPLOY_FEEDRATE, { 210, 114, 30 } } // Move probe off dock #define MAG_MOUNTED_DEPLOY_3 { PROBE_DEPLOY_FEEDRATE, { 0, 0, 0 } } // Extra move if needed @@ -1598,7 +1661,7 @@ * Nozzle-to-Probe offsets { X, Y, Z } * * X and Y offset - * Use a caliper or ruler to measure the distance from the tip of + * Use a caliper or ruler to measure the distance (in mm) from the tip of * the Nozzle to the center-point of the Probe in the X and Y axes. * * Z offset @@ -1634,7 +1697,7 @@ * | [-] | * O-- FRONT --+ */ -#define NOZZLE_TO_PROBE_OFFSET { 10, 10, 0 } +#define NOZZLE_TO_PROBE_OFFSET { 10, 10, 0 } // (mm) X, Y, Z distance from Nozzle tip to Probe trigger-point // Enable and set to use a specific tool for probing. Disable to allow any tool. #define PROBING_TOOL 0 @@ -1642,18 +1705,20 @@ //#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 // X and Y axis travel speed between probes. // Leave undefined to use the average of the current XY homing feedrate. -#define XY_PROBE_FEEDRATE (133*60) // (mm/min) +#define XY_PROBE_FEEDRATE (133*60) // (mm/min) -// Feedrate (mm/min) for the first approach when double-probing (MULTIPLE_PROBING == 2) -#define Z_PROBE_FEEDRATE_FAST (4*60) // (mm/min) +// Feedrate for the first approach when double-probing (MULTIPLE_PROBING == 2) +#define Z_PROBE_FEEDRATE_FAST (4*60) // (mm/min) -// Feedrate (mm/min) for the "accurate" probe of each point +// Feedrate for the "accurate" probe of each point #define Z_PROBE_FEEDRATE_SLOW (Z_PROBE_FEEDRATE_FAST / 2) // (mm/min) /** @@ -2018,8 +2083,11 @@ //#define FILAMENT_MOTION_SENSOR #if ENABLED(FILAMENT_MOTION_SENSOR) - //#define FILAMENT_SWITCH_AND_MOTION + //#define FILAMENT_SWITCH_AND_MOTION // Define separate pins below to sense motion #if ENABLED(FILAMENT_SWITCH_AND_MOTION) + + #define FILAMENT_MOTION_DISTANCE_MM 3.0 // (mm) Missing distance required to trigger runout + #define NUM_MOTION_SENSORS 1 // Number of sensors, up to one per extruder. Define a FIL_MOTION#_PIN for each. //#define FIL_MOTION1_PIN -1 @@ -2055,7 +2123,7 @@ //#define FIL_MOTION8_STATE LOW //#define FIL_MOTION8_PULLUP //#define FIL_MOTION8_PULLDOWN - #endif + #endif // FILAMENT_SWITCH_AND_MOTION #endif // FILAMENT_MOTION_SENSOR #endif // FILAMENT_RUNOUT_DISTANCE_MM #endif // FILAMENT_RUNOUT_SENSOR @@ -2104,6 +2172,12 @@ //#define AUTO_BED_LEVELING_UBL //#define MESH_BED_LEVELING +/** + * Commands to execute at the start of G29 probing, + * after switching to the PROBING_TOOL. + */ +//#define EVENT_GCODE_BEFORE_G29 "M300 P440 S200" + /** * Commands to execute at the end of G29 probing. * Useful to retract or move the Z probe out of the way. @@ -2252,7 +2326,7 @@ //=========================================================================== #define MESH_INSET 10 // Set Mesh bounds as an inset region of the bed - #define GRID_MAX_POINTS_X 3 // Don't use more than 7 points per axis, implementation limited. + #define GRID_MAX_POINTS_X 3 #define GRID_MAX_POINTS_Y GRID_MAX_POINTS_X //#define MESH_G28_REST_ORIGIN // After homing all axes ('G28' or 'G28 XYZ') rest Z at Z_MIN_POS @@ -2888,13 +2962,15 @@ // //#define MAKEBOARD_MINI_2_LINE_DISPLAY_1602 -// -// ANET and Tronxy 20x4 Controller -// -//#define ZONESTAR_LCD // Requires ADC_KEYPAD_PIN to be assigned to an analog pin. - // This LCD is known to be susceptible to electrical interference - // which scrambles the display. Pressing any button clears it up. - // This is a LCD2004 display with 5 analog buttons. +/** + * ANET and Tronxy 20x4 Controller + * LCD2004 display with 5 analog buttons. + * + * NOTE: Requires ADC_KEYPAD_PIN to be assigned to an analog pin. + * This LCD is known to be susceptible to electrical interference which + * scrambles the display. Press any button to clear it up. + */ +//#define ZONESTAR_LCD // // Generic 16x2, 16x4, 20x2, or 20x4 character-based LCD. @@ -3082,7 +3158,7 @@ // // FYSETC variant of the MINI12864 graphic controller with SD support -// https://wiki.fysetc.com/Mini12864_Panel/ +// https://wiki.fysetc.com/docs/Mini12864Panel // //#define FYSETC_MINI_12864_X_X // Type C/D/E/F. No tunable RGB Backlight by default //#define FYSETC_MINI_12864_1_2 // Type C/D/E/F. Simple RGB Backlight (always on) @@ -3171,14 +3247,14 @@ // // Tiny, but very sharp OLED display // -//#define MKS_12864OLED // Uses the SH1106 controller (default) +//#define MKS_12864OLED // Uses the SH1106 controller //#define MKS_12864OLED_SSD1306 // Uses the SSD1306 controller // // Zonestar OLED 128×64 Full Graphics Controller // //#define ZONESTAR_12864LCD // Graphical (DOGM) with ST7920 controller -//#define ZONESTAR_12864OLED // 1.3" OLED with SH1106 controller (default) +//#define ZONESTAR_12864OLED // 1.3" OLED with SH1106 controller //#define ZONESTAR_12864OLED_SSD1306 // 0.96" OLED with SSD1306 controller // @@ -3256,7 +3332,7 @@ #endif // -// Touch-screen LCD for Malyan M200/M300 printers +// LCD for Malyan M200/M300 printers // //#define MALYAN_LCD @@ -3427,20 +3503,22 @@ #if ENABLED(TFT_COLOR_UI) /** - * TFT Font for Color_UI. Choose one of the following: + * TFT Font for Color UI. Choose one of the following: * * 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 /** - * TFT Theme for Color_UI. Choose one of the following or add a new one to 'Marlin/src/lcd/tft/themes' directory + * TFT Theme for Color UI. Choose one of the following or add a new one to 'Marlin/src/lcd/tft/themes' directory * * 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 @@ -3478,6 +3556,11 @@ //#define DWIN_MARLINUI_PORTRAIT // MarlinUI (portrait orientation) //#define DWIN_MARLINUI_LANDSCAPE // MarlinUI (landscape orientation) +#if ENABLED(DWIN_CREALITY_LCD) + //#define USE_STRING_HEADINGS // Use string headings for Creality UI instead of images + //#define USE_STRING_TITLES // Use string titles for Creality UI instead of images +#endif + // // Touch Screen Settings // @@ -3512,7 +3595,9 @@ // https://reprapworld.com/products/electronics/ramps/keypad_v1_0_fully_assembled/ // //#define REPRAPWORLD_KEYPAD -//#define REPRAPWORLD_KEYPAD_MOVE_STEP 10.0 // (mm) Distance to move per key-press +#if ENABLED(REPRAPWORLD_KEYPAD) + //#define REPRAPWORLD_KEYPAD_MOVE_STEP 10.0 // (mm) Distance to move per key-press +#endif // // EasyThreeD ET-4000+ with button input and status LED @@ -3529,22 +3614,26 @@ // :[1,2,3,4,5,6,7,8] //#define NUM_M106_FANS 1 -// Use software PWM to drive the fan, as for the heaters. This uses a very low frequency -// which is not as annoying as with the hardware PWM. On the other hand, if this frequency -// is too low, you should also increment SOFT_PWM_SCALE. +/** + * Use software PWM to drive the fan, as for the heaters. This uses a very low frequency + * which is not as annoying as with the hardware PWM. On the other hand, if this frequency + * is too low, you should also increment SOFT_PWM_SCALE. + */ //#define FAN_SOFT_PWM -// Incrementing this by 1 will double the software PWM frequency, -// affecting heaters, and the fan if FAN_SOFT_PWM is enabled. -// However, control resolution will be halved for each increment; -// at zero value, there are 128 effective control positions. -// :[0,1,2,3,4,5,6,7] +/** + * Incrementing this by 1 will double the software PWM frequency, affecting heaters, and + * the fan if FAN_SOFT_PWM is enabled. However, control resolution will be halved for each + * increment; at zero value, there are 128 effective control positions. + * :[0,1,2,3,4,5,6,7] + */ #define SOFT_PWM_SCALE 0 -// If SOFT_PWM_SCALE is set to a value higher than 0, dithering can -// be used to mitigate the associated resolution loss. If enabled, -// some of the PWM cycles are stretched so on average the desired -// duty cycle is attained. +/** + * If SOFT_PWM_SCALE is set to a value higher than 0, dithering can be used to mitigate the + * associated resolution loss. If enabled, some of the PWM cycles are stretched so on average + * the desired duty cycle is attained. + */ //#define SOFT_PWM_DITHER // @section extras @@ -3554,9 +3643,11 @@ // @section lights -// Temperature status LEDs that display the hotend and bed temperature. -// If all hotends, bed temperature, and target temperature are under 54C -// then the BLUE led is on. Otherwise the RED led is on. (1C hysteresis) +/** + * Temperature status LEDs that display the hotend and bed temperature. + * If all hotends, bed temperature, and target temperature are under 54C + * the BLUE led is on. Otherwise the RED led is on. (1C hysteresis) + */ //#define TEMP_STAT_LEDS // Support for BlinkM/CyzRgb diff --git a/Marlin/Configuration_adv.h b/Marlin/Configuration_adv.h index 6c19a7545b..7b628200c1 100644 --- a/Marlin/Configuration_adv.h +++ b/Marlin/Configuration_adv.h @@ -174,9 +174,10 @@ * Thermocouple Options — for MAX6675 (-2), MAX31855 (-3), and MAX31865 (-5). */ //#define TEMP_SENSOR_FORCE_HW_SPI // Ignore SCK/MOSI/MISO pins; use CS and the default SPI bus. -//#define MAX31865_SENSOR_WIRES_0 2 // (2-4) Number of wires for the probe connected to a MAX31865 board. -//#define MAX31865_SENSOR_WIRES_1 2 -//#define MAX31865_SENSOR_WIRES_2 2 +//#define MAX31865_SENSOR_WIRES_0 2 // (2-4) Number of wires for the probe connected to a MAX31865 board. +//#define MAX31865_SENSOR_WIRES_1 2 +//#define MAX31865_SENSOR_WIRES_2 2 +//#define MAX31865_SENSOR_WIRES_BED 2 //#define MAX31865_50HZ_FILTER // Use a 50Hz filter instead of the default 60Hz. //#define MAX31865_USE_READ_ERROR_DETECTION // Treat value spikes (20°C delta in under 1s) as read errors. @@ -188,6 +189,7 @@ //#define MAX31865_WIRE_OHMS_0 0.95f // For 2-wire, set the wire resistances for more accurate readings. //#define MAX31865_WIRE_OHMS_1 0.0f //#define MAX31865_WIRE_OHMS_2 0.0f +//#define MAX31865_WIRE_OHMS_BED 0.0f /** * Hephestos 2 24V heated bed upgrade kit. @@ -295,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. @@ -413,14 +415,19 @@ // A well-chosen Kc value should add just enough power to melt the increased material volume. //#define PID_EXTRUSION_SCALING #if ENABLED(PID_EXTRUSION_SCALING) - #define DEFAULT_Kc (100) // heating power = Kc * e_speed #define LPQ_MAX_LEN 50 + #define DEFAULT_KC 100 // heating power = Kc * e_speed + #if ENABLED(PID_PARAMS_PER_HOTEND) + // Specify up to one value per hotend here, according to your setup. + // If there are fewer values, the last one applies to the remaining hotends. + #define DEFAULT_KC_LIST { DEFAULT_KC, DEFAULT_KC } // heating power = Kc * e_speed + #endif #endif /** * Add an additional term to the heater power, proportional to the fan speed. * A well-chosen Kf value should add just enough power to compensate for power-loss from the cooling fan. - * You can either just add a constant compensation with the DEFAULT_Kf value + * You can either just add a constant compensation with the DEFAULT_KF value * or follow the instruction below to get speed-dependent compensation. * * Constant compensation (use only with fan speeds of 0% and 100%) @@ -451,21 +458,26 @@ #if ENABLED(PID_FAN_SCALING_ALTERNATIVE_DEFINITION) // The alternative definition is used for an easier configuration. // Just figure out Kf at full speed (255) and PID_FAN_SCALING_MIN_SPEED. - // DEFAULT_Kf and PID_FAN_SCALING_LIN_FACTOR are calculated accordingly. + // DEFAULT_KF and PID_FAN_SCALING_LIN_FACTOR are calculated accordingly. - #define PID_FAN_SCALING_AT_FULL_SPEED 13.0 //=PID_FAN_SCALING_LIN_FACTOR*255+DEFAULT_Kf - #define PID_FAN_SCALING_AT_MIN_SPEED 6.0 //=PID_FAN_SCALING_LIN_FACTOR*PID_FAN_SCALING_MIN_SPEED+DEFAULT_Kf + #define PID_FAN_SCALING_AT_FULL_SPEED 13.0 //=PID_FAN_SCALING_LIN_FACTOR*255+DEFAULT_KF + #define PID_FAN_SCALING_AT_MIN_SPEED 6.0 //=PID_FAN_SCALING_LIN_FACTOR*PID_FAN_SCALING_MIN_SPEED+DEFAULT_KF #define PID_FAN_SCALING_MIN_SPEED 10.0 // Minimum fan speed at which to enable PID_FAN_SCALING - #define DEFAULT_Kf (255.0*PID_FAN_SCALING_AT_MIN_SPEED-PID_FAN_SCALING_AT_FULL_SPEED*PID_FAN_SCALING_MIN_SPEED)/(255.0-PID_FAN_SCALING_MIN_SPEED) - #define PID_FAN_SCALING_LIN_FACTOR (PID_FAN_SCALING_AT_FULL_SPEED-DEFAULT_Kf)/255.0 + #define DEFAULT_KF (255.0*PID_FAN_SCALING_AT_MIN_SPEED-PID_FAN_SCALING_AT_FULL_SPEED*PID_FAN_SCALING_MIN_SPEED)/(255.0-PID_FAN_SCALING_MIN_SPEED) + #define PID_FAN_SCALING_LIN_FACTOR (PID_FAN_SCALING_AT_FULL_SPEED-DEFAULT_KF)/255.0 #else #define PID_FAN_SCALING_LIN_FACTOR (0) // Power-loss due to cooling = Kf * (fan_speed) - #define DEFAULT_Kf 10 // A constant value added to the PID-tuner + #define DEFAULT_KF 10 // A constant value added to the PID-tuner #define PID_FAN_SCALING_MIN_SPEED 10 // Minimum fan speed at which to enable PID_FAN_SCALING #endif #endif + #if ENABLED(PID_PARAMS_PER_HOTEND) + // Specify up to one value per hotend here, according to your setup. + // If there are fewer values, the last one applies to the remaining hotends. + #define DEFAULT_KF_LIST { DEFAULT_KF, DEFAULT_KF } + #endif #endif /** @@ -484,15 +496,15 @@ #define AUTOTEMP #if ENABLED(AUTOTEMP) #define AUTOTEMP_OLDWEIGHT 0.98 // Factor used to weight previous readings (0.0 < value < 1.0) - #define AUTOTEMP_MIN 210 - #define AUTOTEMP_MAX 250 + #define AUTOTEMP_MIN 210 + #define AUTOTEMP_MAX 250 #define AUTOTEMP_FACTOR 0.1f // Turn on AUTOTEMP on M104/M109 by default using proportions set here //#define AUTOTEMP_PROPORTIONAL #if ENABLED(AUTOTEMP_PROPORTIONAL) - #define AUTOTEMP_MIN_P 0 // (°C) Added to the target temperature - #define AUTOTEMP_MAX_P 5 // (°C) Added to the target temperature - #define AUTOTEMP_FACTOR_P 1 // Apply this F parameter by default (overridden by M104/M109 F) + #define AUTOTEMP_MIN_P 0 // (°C) Added to the target temperature + #define AUTOTEMP_MAX_P 5 // (°C) Added to the target temperature + #define AUTOTEMP_FACTOR_P 1 // Apply this F parameter by default (overridden by M104/M109 F) #endif #endif @@ -776,7 +788,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 @@ -1020,7 +1032,7 @@ #endif // BLTOUCH -// @section calibration +// @section calibrate /** * Z Steppers Auto-Alignment @@ -1079,11 +1091,26 @@ #define G34_MAX_GRADE 5 // (%) Maximum incline that G34 will handle #define Z_STEPPER_ALIGN_ITERATIONS 5 // Number of iterations to apply during alignment #define Z_STEPPER_ALIGN_ACC 0.02 // Stop iterating early if the accuracy is better than this + #define RESTORE_LEVELING_AFTER_G34 // Restore leveling after G34 is done? + // After G34, re-home Z (G28 Z) or just calculate it from the last probe heights? // Re-homing might be more precise in reproducing the actual 'G28 Z' homing height, especially on an uneven bed. #define HOME_AFTER_G34 -#endif + + /** + * Commands to execute at the start of G34 probing, + * after switching to the PROBING_TOOL. + */ + //#define EVENT_GCODE_BEFORE_G34 "M300 P440 S200" + + /** + * Commands to execute at the end of G34 probing. + * Useful to retract or move the Z probe out of the way. + */ + //#define EVENT_GCODE_AFTER_G34 "G1 Z10 F12000\nG1 X15 Y330\nG1 Z0.5\nG1 Z10" + +#endif // Z_STEPPER_AUTO_ALIGN /** * Assisted Tramming @@ -1126,67 +1153,92 @@ /** * 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_DEFAULT_DYNFREQ_MODE dynFreqMode_DISABLED // Default mode of dynamic frequency calculation. (DISABLED, Z_BASED, MASS_BASED) + //#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 NO_STANDARD_MOTION // Disable the standard motion system entirely to save Flash and RAM + #if DISABLED(NO_STANDARD_MOTION) + //#define FTM_HOME_AND_PROBE // Use FT Motion for homing / probing. Disable if FT Motion breaks these functions. + #endif + + //#define FTM_DYNAMIC_FREQ // Enable for linear adjustment of XY shaping frequency according to Z or E + #if ENABLED(FTM_DYNAMIC_FREQ) + #define FTM_DEFAULT_DYNFREQ_MODE dynFreqMode_DISABLED // Default mode of dynamic frequency calculation. (DISABLED, Z_BASED, MASS_BASED) + #endif + + // Disable unused shapers if you need more free space + #define FTM_SHAPER_ZV + #define FTM_SHAPER_ZVD + #define FTM_SHAPER_ZVDD + #define FTM_SHAPER_ZVDDD + #define FTM_SHAPER_EI + #define FTM_SHAPER_2HEI + #define FTM_SHAPER_3HEI + #define FTM_SHAPER_MZV + #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_DEFAULT_SHAPER_Y ftMotionShaper_NONE // Default shaper mode on Y axis - #define FTM_SHAPING_DEFAULT_FREQ_X 37.0f // (Hz) Default peak frequency used by input shapers - #define FTM_SHAPING_DEFAULT_FREQ_Y 37.0f // (Hz) Default peak frequency used by input shapers - #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_SHAPING_ZETA_X 0.1f // Zeta used by input shapers for X axis - #define FTM_SHAPING_ZETA_Y 0.1f // Zeta used by 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 FTM_SHAPING_V_TOL_X 0.05f // Vibration tolerance used by EI input shapers for X axis - #define FTM_SHAPING_V_TOL_Y 0.05f // Vibration tolerance used by EI input shapers for Y axis + //#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 FT_MOTION_MENU // Provide a MarlinUI menu to set M493 parameters + //#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_POLYS // Disable POLY5/6 to save ~3k of Flash. Preserves TRAPEZOIDAL. + #if ENABLED(FTM_POLYS) + #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) + #endif /** * 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_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_CTS_COMPARE_VAL (FTM_STEPS_PER_UNIT_TIME / 2) // Comparison value used in interpolation algorithm - #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 +#endif // FT_MOTION /** * Input Shaping @@ -1340,20 +1392,20 @@ //#define CALIBRATION_SCRIPT_PRE "M117 Starting Auto-Calibration\nT0\nG28\nG12\nM117 Calibrating..." //#define CALIBRATION_SCRIPT_POST "M500\nM117 Calibration data saved" - #define CALIBRATION_FEEDRATE_SLOW 60 // mm/min - #define CALIBRATION_FEEDRATE_FAST 1200 // mm/min - #define CALIBRATION_FEEDRATE_TRAVEL 3000 // mm/min + #define CALIBRATION_FEEDRATE_SLOW 60 // (mm/min) + #define CALIBRATION_FEEDRATE_FAST 1200 // (mm/min) + #define CALIBRATION_FEEDRATE_TRAVEL 3000 // (mm/min) // The following parameters refer to the conical section of the nozzle tip. - #define CALIBRATION_NOZZLE_TIP_HEIGHT 1.0 // mm - #define CALIBRATION_NOZZLE_OUTER_DIAMETER 2.0 // mm + #define CALIBRATION_NOZZLE_TIP_HEIGHT 1.0 // (mm) + #define CALIBRATION_NOZZLE_OUTER_DIAMETER 2.0 // (mm) // Uncomment to enable reporting (required for "G425 V", but consumes flash). //#define CALIBRATION_REPORTING // The true location and dimension the cube/bolt/washer on the bed. - #define CALIBRATION_OBJECT_CENTER { 264.0, -22.0, -2.0 } // mm - #define CALIBRATION_OBJECT_DIMENSIONS { 10.0, 10.0, 10.0 } // mm + #define CALIBRATION_OBJECT_CENTER { 264.0, -22.0, -2.0 } // (mm) + #define CALIBRATION_OBJECT_DIMENSIONS { 10.0, 10.0, 10.0 } // (mm) // Comment out any sides which are unreachable by the probe. For best // auto-calibration results, all sides must be reachable. @@ -1392,7 +1444,7 @@ * Multi-stepping sends steps in bursts to reduce MCU usage for high step-rates. * This allows higher feedrates than the MCU could otherwise support. */ -#define MULTISTEPPING_LIMIT 16 //: [1, 2, 4, 8, 16, 32, 64, 128] +#define MULTISTEPPING_LIMIT 16 // :[1, 2, 4, 8, 16, 32, 64, 128] /** * Adaptive Step Smoothing increases the resolution of multi-axis moves, particularly at step frequencies @@ -1417,24 +1469,24 @@ #define MICROSTEP_MODES { 16, 16, 16, 16, 16, 16 } // [1,2,4,8,16] /** - * @section stepper motor current + * @section stepper motor current * - * Some boards have a means of setting the stepper motor current via firmware. + * Some boards have a means of setting the stepper motor current via firmware. * - * The power on motor currents are set by: - * PWM_MOTOR_CURRENT - used by MINIRAMBO & ULTIMAIN_2 - * known compatible chips: A4982 - * DIGIPOT_MOTOR_CURRENT - used by BQ_ZUM_MEGA_3D, RAMBO & SCOOVO_X9H - * known compatible chips: AD5206 - * DAC_MOTOR_CURRENT_DEFAULT - used by PRINTRBOARD_REVF & RIGIDBOARD_V2 - * known compatible chips: MCP4728 - * DIGIPOT_I2C_MOTOR_CURRENTS - used by 5DPRINT, AZTEEG_X3_PRO, AZTEEG_X5_MINI_WIFI, MIGHTYBOARD_REVE - * known compatible chips: MCP4451, MCP4018 + * The power on motor currents are set by: + * PWM_MOTOR_CURRENT - used by MINIRAMBO & ULTIMAIN_2 + * known compatible chips: A4982 + * DIGIPOT_MOTOR_CURRENT - used by BQ_ZUM_MEGA_3D, RAMBO & SCOOVO_X9H + * known compatible chips: AD5206 + * DAC_MOTOR_CURRENT_DEFAULT - used by PRINTRBOARD_REVF & RIGIDBOARD_V2 + * known compatible chips: MCP4728 + * DIGIPOT_I2C_MOTOR_CURRENTS - used by 5DPRINT, AZTEEG_X3_PRO, AZTEEG_X5_MINI_WIFI, MIGHTYBOARD_REVE + * known compatible chips: MCP4451, MCP4018 * - * Motor currents can also be set by M907 - M910 and by the LCD. - * M907 - applies to all. - * M908 - BQ_ZUM_MEGA_3D, RAMBO, PRINTRBOARD_REVF, RIGIDBOARD_V2 & SCOOVO_X9H - * M909, M910 & LCD - only PRINTRBOARD_REVF & RIGIDBOARD_V2 + * Motor currents can also be set by M907 - M910 and by the LCD. + * M907 - applies to all. + * M908 - BQ_ZUM_MEGA_3D, RAMBO, PRINTRBOARD_REVF, RIGIDBOARD_V2 & SCOOVO_X9H + * M909, M910 & LCD - only PRINTRBOARD_REVF & RIGIDBOARD_V2 */ //#define PWM_MOTOR_CURRENT { 1300, 1300, 1250 } // Values in milliamps //#define DIGIPOT_MOTOR_CURRENT { 135,135,135,135,135 } // Values 0-255 (RAMBO 135 = ~0.75A, 185 = ~1A) @@ -1549,6 +1601,7 @@ //#define LCD_INFO_MENU #if ENABLED(LCD_INFO_MENU) //#define LCD_PRINTER_INFO_IS_BOOTSCREEN // Show bootscreen(s) instead of Printer Info pages + //#define BUILD_INFO_MENU_ITEM // Add a menu item to display the build date and time #endif /** @@ -1604,7 +1657,7 @@ #if HAS_MARLINUI_U8GLIB //#define BOOT_MARLIN_LOGO_ANIMATED // Animated Marlin logo. Costs ~3260 (or ~940) bytes of flash. #endif - #if ANY(HAS_MARLINUI_U8GLIB, TOUCH_UI_FTDI_EVE, HAS_MARLINUI_HD44780) + #if ANY(HAS_MARLINUI_U8GLIB, TOUCH_UI_FTDI_EVE, HAS_MARLINUI_HD44780, HAS_GRAPHICAL_TFT) //#define SHOW_CUSTOM_BOOTSCREEN // Show the bitmap in Marlin/_Bootscreen.h on startup. #endif #endif @@ -1616,6 +1669,10 @@ //#define SOUND_MENU_ITEM // Add a mute option to the LCD menu #define SOUND_ON_DEFAULT // Buzzer/speaker default enabled state + #if ENABLED(U8GLIB_SSD1309) + //#define LCD_DOUBLE_BUFFER // Optimize display updates. Costs ~1K of SRAM. + #endif + #if HAS_WIRED_LCD //#define DOUBLE_LCD_FRAMERATE // Not recommended for slow boards. #endif @@ -1666,11 +1723,12 @@ #endif // HAS_DISPLAY -#if HAS_FEEDRATE_EDIT +// Some displays offer Feedrate / Flow editing. +#if ANY(HAS_MARLINUI_MENU, DWIN_CREALITY_LCD, DWIN_LCD_PROUI, MALYAN_LCD, TOUCH_SCREEN, ULTIPANEL_FEEDMULTIPLY) #define SPEED_EDIT_MIN 10 // (%) Feedrate percentage edit range minimum #define SPEED_EDIT_MAX 999 // (%) Feedrate percentage edit range maximum #endif -#if HAS_FLOW_EDIT +#if ANY(HAS_MARLINUI_MENU, DWIN_CREALITY_LCD, DWIN_LCD_PROUI, MALYAN_LCD, TOUCH_SCREEN) #define FLOW_EDIT_MIN 10 // (%) Flow percentage edit range minimum #define FLOW_EDIT_MAX 999 // (%) Flow percentage edit range maximum #endif @@ -1755,6 +1813,14 @@ #define PE_LEDS_COMPLETED_TIME (30*60) // (seconds) Time to keep the LED "done" color before restoring normal illumination #endif + /** + * Priming for the Remaining Time estimate + * Long processes at the start of a G-code file can skew the Remaining Time estimate. + * Enable these options to start this estimation at a later point in the G-code file. + */ + //#define REMAINING_TIME_PRIME // Provide G-code 'M75 R' to prime the Remaining Time estimate + //#define REMAINING_TIME_AUTOPRIME // Prime the Remaining Time estimate later (e.g., at the end of 'M109') + /** * Continue after Power-Loss (Creality3D) * @@ -1766,6 +1832,8 @@ //#define POWER_LOSS_RECOVERY #if ENABLED(POWER_LOSS_RECOVERY) #define PLR_ENABLED_DEFAULT false // Power-Loss Recovery enabled by default. (Set with 'M413 Sn' & M500) + //#define PLR_HEAT_BED_ON_REBOOT // Heat up bed immediately on reboot to mitigate object detaching/warping. + //#define PLR_HEAT_BED_EXTRA 0 // (°C) Relative increase of bed temperature for better adhesion (limited by max temp). //#define PLR_BED_THRESHOLD BED_MAXTEMP // (°C) Skip user confirmation at or above this bed temperature (0 to disable) //#define POWER_LOSS_PIN 44 // Pin to detect power-loss. Set to -1 to disable default pin on boards without module, or comment to use board default. @@ -1819,16 +1887,21 @@ // SD Card Sorting options #if ENABLED(SDCARD_SORT_ALPHA) - #define SDSORT_REVERSE false // Default to sorting file names in reverse order. - #define SDSORT_LIMIT 40 // Maximum number of sorted items (10-256). Costs 27 bytes each. - #define SDSORT_FOLDERS -1 // -1=above 0=none 1=below - #define SDSORT_GCODE false // Enable G-code M34 to set sorting behaviors: M34 S<-1|0|1> F<-1|0|1> - #define SDSORT_USES_RAM false // Pre-allocate a static array for faster pre-sorting. - #define SDSORT_USES_STACK false // Prefer the stack for pre-sorting to give back some SRAM. (Negated by next 2 options.) - #define SDSORT_CACHE_NAMES false // Keep sorted items in RAM longer for speedy performance. Most expensive option. - #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. + #define SDSORT_REVERSE false // Default to sorting file names in reverse order. + #define SDSORT_LIMIT 40 // Maximum number of sorted items (10-256). Costs 27 bytes each. + #define SDSORT_FOLDERS -1 // -1=above 0=none 1=below + #define SDSORT_GCODE false // Enable G-code M34 to set sorting behaviors: M34 S<-1|0|1> F<-1|0|1> + #define SDSORT_USES_STACK false // Prefer the stack for pre-sorting to give back some SRAM. (Negated by next 2 options.) + #define SDSORT_USES_RAM false // Pre-allocate a static array for faster pre-sorting. + #if ENABLED(SDSORT_USES_RAM) + #define SDSORT_CACHE_NAMES false // Keep sorted items in RAM longer for speedy performance. Most expensive option. + #if ENABLED(SDSORT_CACHE_NAMES) + #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. + #endif + #endif #endif // Allow international symbols in long filenames. To display correctly, the @@ -1867,7 +1940,7 @@ * * SCLK, MOSI, MISO --> SCLK, MOSI, MISO * INT --> SD_DETECT_PIN [1] - * SS --> SDSS + * SS --> SD_SS_PIN * * [1] On AVR an interrupt-capable pin is best for UHS3 compatibility. */ @@ -1894,7 +1967,7 @@ //#define USE_OTG_USB_HOST #if DISABLED(USE_OTG_USB_HOST) - #define USB_CS_PIN SDSS + #define USB_CS_PIN SD_SS_PIN #define USB_INTR_PIN SD_DETECT_PIN #endif #endif @@ -1931,6 +2004,9 @@ //#define CUSTOM_FIRMWARE_UPLOAD #endif + // "Over-the-air" Firmware Update with M936 - Required to set EEPROM flag + //#define OTA_FIRMWARE_UPDATE + /** * Set this option to one of the following (or the board's defaults apply): * @@ -1953,8 +2029,8 @@ #if ENABLED(MULTI_VOLUME) #define VOLUME_SD_ONBOARD #define VOLUME_USB_FLASH_DRIVE - #define DEFAULT_VOLUME SV_SD_ONBOARD - #define DEFAULT_SHARED_VOLUME SV_USB_FLASH_DRIVE + #define DEFAULT_VOLUME SD_ONBOARD // :[ 'SD_ONBOARD', 'USB_FLASH_DRIVE' ] + #define DEFAULT_SHARED_VOLUME USB_FLASH_DRIVE // :[ 'SD_ONBOARD', 'USB_FLASH_DRIVE' ] #endif #endif // HAS_MEDIA @@ -2005,7 +2081,7 @@ #if IS_U8GLIB_ST7920 // Enable this option and reduce the value to optimize screen updates. // The normal delay is 10µs. Use the lowest value that still gives a reliable display. - //#define DOGM_SPI_DELAY_US 5 + //#define DOGM_SPI_DELAY_US 5 // (µs) Delay after each SPI transfer //#define LIGHTWEIGHT_UI #if ENABLED(LIGHTWEIGHT_UI) @@ -2035,17 +2111,17 @@ //#define STATUS_HEAT_PERCENT // Show heating in a progress bar //#define STATUS_HEAT_POWER // Show heater output power as a vertical bar - // Frivolous Game Options - //#define MARLIN_BRICKOUT - //#define MARLIN_INVADERS - //#define MARLIN_SNAKE - //#define GAMES_EASTER_EGG // Add extra blank lines above the "Games" sub-menu - #endif // HAS_MARLINUI_U8GLIB #if HAS_MARLINUI_U8GLIB || IS_DWIN_MARLINUI #define MENU_HOLLOW_FRAME // Enable to save many cycles by drawing a hollow frame on Menu Screens //#define OVERLAY_GFX_REVERSE // Swap the CW/CCW indicators in the graphics overlay + + // Frivolous Game Options + //#define MARLIN_BRICKOUT + //#define MARLIN_INVADERS + //#define MARLIN_SNAKE + //#define GAMES_EASTER_EGG // Add extra blank lines above the "Games" sub-menu #endif // @@ -2224,7 +2300,7 @@ // Developer menu (accessed by touching "About Printer" copyright text) //#define TOUCH_UI_DEVELOPER_MENU -#endif +#endif // TOUCH_UI_FTDI_EVE // // Classic UI Options @@ -2258,9 +2334,11 @@ // ADC Button Debounce // #if HAS_ADC_BUTTONS - #define ADC_BUTTON_DEBOUNCE_DELAY 16 // Increase if buttons bounce or repeat too fast + #define ADC_BUTTON_DEBOUNCE_DELAY 16 // (count) Increase if buttons bounce or repeat too fast #endif +//#define FAST_BUTTON_POLLING // Poll buttons at ~1kHz on 8-bit AVR. Set to 'false' for slow polling on 32-bit. + // @section safety /** @@ -2299,7 +2377,7 @@ //#define DOUBLECLICK_FOR_Z_BABYSTEPPING // Double-click on the Status Screen for Z Babystepping. #if ENABLED(DOUBLECLICK_FOR_Z_BABYSTEPPING) - #define DOUBLECLICK_MAX_INTERVAL 1250 // Maximum interval between clicks, in milliseconds. + #define DOUBLECLICK_MAX_INTERVAL 1250 // (ms) Maximum interval between clicks. // Note: Extra time may be added to mitigate controller latency. //#define MOVE_Z_WHEN_IDLE // Jump to the move Z menu on double-click when printer is idle. #if ENABLED(MOVE_Z_WHEN_IDLE) @@ -2334,15 +2412,37 @@ * 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 K'. #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'. #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. + + //#define SMOOTH_LIN_ADVANCE // Remove limits on acceleration by gradual increase of nozzle pressure + #if ENABLED(SMOOTH_LIN_ADVANCE) + /** + * ADVANCE_TAU is also the time ahead that the smoother needs to look + * into the planner, so the planner needs to have enough blocks loaded. + * For k=0.04 at 10k acceleration and an "Orbiter 2" extruder it can be as low as 0.0075. + * Adjust by lowering the value until you observe the extruder skipping, then raise slightly. + * Higher k and higher XY acceleration may require larger ADVANCE_TAU to avoid skipping steps. + */ + #if ENABLED(DISTINCT_E_FACTORS) + #define ADVANCE_TAU { 0.02 } // (s) Smoothing time to reduce extruder acceleration, per extruder + #else + #define ADVANCE_TAU 0.02 // (s) Smoothing time to reduce extruder acceleration + #endif + #define SMOOTH_LIN_ADV_HZ 1000 // (Hz) How often to update extruder speed + #define INPUT_SHAPING_E_SYNC // Synchronize the extruder-shaped XY axes (to increase precision) + #endif #endif /** @@ -2353,6 +2453,9 @@ * For better results also enable ADAPTIVE_STEP_SMOOTHING. */ //#define NONLINEAR_EXTRUSION +#if ENABLED(NONLINEAR_EXTRUSION) + //#define NONLINEAR_EXTRUSION_DEFAULT_ON // Enable if NLE should be ON by default +#endif // @section leveling @@ -2631,19 +2734,23 @@ #define MAX_CMD_SIZE 96 #define BUFSIZE 4 -// Transmission to Host Buffer Size -// To save 386 bytes of flash (and TX_BUFFER_SIZE+3 bytes of RAM) set to 0. -// To buffer a simple "ok" you need 4 bytes. -// For ADVANCED_OK (M105) you need 32 bytes. -// For debug-echo: 128 bytes for the optimal speed. -// Other output doesn't need to be that speedy. -// :[0, 2, 4, 8, 16, 32, 64, 128, 256] +/** + * Host Transmit Buffer Size + * - Costs 386 bytes of flash and TX_BUFFER_SIZE+3 bytes of SRAM (if not 0). + * - 4 bytes required to buffer a simple "ok". + * - 32 bytes for ADVANCED_OK (M105). + * - 128 bytes for the optimal speed of 'debug-echo:' + * - Other output doesn't need to be that speedy. + * :[0, 2, 4, 8, 16, 32, 64, 128, 256] + */ #define TX_BUFFER_SIZE 0 -// Host Receive Buffer Size -// Without XON/XOFF flow control (see SERIAL_XON_XOFF below) 32 bytes should be enough. -// To use flow control, set this buffer size to at least 1024 bytes. -// :[0, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048] +/** + * Host Receive Buffer Size + * Without XON/XOFF flow control (see SERIAL_XON_XOFF below) 32 bytes should be enough. + * To use flow control, set this buffer size to at least 1024 bytes. + * :[0, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048] + */ //#define RX_BUFFER_SIZE 1024 #if RX_BUFFER_SIZE >= 1024 @@ -2962,7 +3069,7 @@ /** * Trinamic Smart Drivers * - * To use TMC2130, TMC2160, TMC2660, TMC5130, TMC5160 stepper drivers in SPI mode: + * To use TMC2130, TMC2160, TMC2240, TMC2660, TMC5130, TMC5160 stepper drivers in SPI mode: * - Connect your SPI pins to the Hardware SPI interface on the board. * Some boards have simple jumper connections! See your board's documentation. * - Define the required Stepper CS pins in your `pins_MYBOARD.h` file. @@ -2984,12 +3091,22 @@ #define HOLD_MULTIPLIER 0.5 // Scales down the holding current from run current + //#define EDITABLE_HOMING_CURRENT // Add a G-code and menu to modify the Homing Current + /** * Interpolate microsteps to 256 * Override for each driver with _INTERPOLATE settings below */ #define INTERPOLATE true + #if HAS_DRIVER(TMC2240) + #define TMC2240_RREF 12000 // (Ω) 12000 .. 60000. (FLY TMC2240 = 12300) + // Max Current. Lower for more internal resolution. Raise to run cooler. + #define TMC2240_CURRENT_RANGE 1 // :{ 0:'RMS=690mA PEAK=1A', 1:'RMS=1410mA PEAK=2A', 2:'RMS=2120mA PEAK=3A', 3:'RMS=2110mA PEAK=3A' } + // Slope Control: Lower is more silent. Higher runs cooler. + #define TMC2240_SLOPE_CONTROL 0 // :{ 0:'100V/µs', 1:'200V/µs', 2:'400V/µs', 3:'800V/µs' } + #endif + #if AXIS_IS_TMC_CONFIG(X) #define X_CURRENT 800 // (mA) RMS current. Multiply by 1.414 for peak current. #define X_CURRENT_HOME X_CURRENT // (mA) RMS current for homing. (Typically lower than *_CURRENT.) @@ -3212,7 +3329,7 @@ // @section tmc/spi /** - * Override default SPI pins for TMC2130, TMC2160, TMC2660, TMC5130 and TMC5160 drivers here. + * Override default SPI pins for TMC2130, TMC2160, TMC2240, TMC2660, TMC5130 and TMC5160 drivers here. * The default pins can be found in your board's pins file. */ //#define X_CS_PIN -1 @@ -3239,7 +3356,7 @@ //#define E7_CS_PIN -1 /** - * Software option for SPI driven drivers (TMC2130, TMC2160, TMC2660, TMC5130 and TMC5160). + * Software option for SPI driven drivers (TMC2130, TMC2160, TMC2240, TMC2660, TMC5130 and TMC5160). * The default SW SPI pins are defined the respective pins files, * but you can override or define them here. */ @@ -3298,7 +3415,7 @@ // @section tmc/stealthchop /** - * TMC2130, TMC2160, TMC2208, TMC2209, TMC5130 and TMC5160 only + * TMC2130, TMC2160, TMC2208, TMC2209, TMC2240, TMC5130 and TMC5160 only * Use Trinamic's ultra quiet stepping mode. * When disabled, Marlin will use spreadCycle stepping mode. */ @@ -3377,7 +3494,7 @@ // @section tmc/hybrid /** - * TMC2130, TMC2160, TMC2208, TMC2209, TMC5130 and TMC5160 only + * TMC2130, TMC2160, TMC2208, TMC2209, TMC2240, TMC5130 and TMC5160 only * The driver will switch to spreadCycle when stepper speed is over HYBRID_THRESHOLD. * This mode allows for faster movements at the expense of higher noise levels. * STEALTHCHOP_(XY|Z|E) must be enabled to use HYBRID_THRESHOLD. @@ -3411,20 +3528,20 @@ /** * Use StallGuard to home / probe X, Y, Z. * - * TMC2130, TMC2160, TMC2209, TMC2660, TMC5130, and TMC5160 only + * TMC2130, TMC2160, TMC2209, TMC2240, TMC2660, TMC5130, and TMC5160 only * Connect the stepper driver's DIAG1 pin to the X/Y endstop pin. * X, Y, and Z homing will always be done in spreadCycle mode. * * X/Y/Z_STALL_SENSITIVITY is the default stall threshold. * Use M914 X Y Z to set the stall threshold at runtime: * - * Sensitivity TMC2209 Others - * HIGHEST 255 -64 (Too sensitive => False positive) - * LOWEST 0 63 (Too insensitive => No trigger) + * Sensitivity TMC2209 Others + * HIGHEST 255 -64 (Too sensitive => False positive) + * LOWEST 0 63 (Too insensitive => No trigger) * * It is recommended to set HOMING_BUMP_MM to { 0, 0, 0 }. * - * SPI_ENDSTOPS *** TMC2130/TMC5160 Only *** + * SPI_ENDSTOPS *** TMC2130, TMC2240, and TMC5160 Only *** * Poll the driver through SPI to determine load when homing. * Removes the need for a wire from DIAG1 to an endstop pin. * @@ -3452,8 +3569,9 @@ //#define U_STALL_SENSITIVITY 8 //#define V_STALL_SENSITIVITY 8 //#define W_STALL_SENSITIVITY 8 - //#define SPI_ENDSTOPS // TMC2130/TMC5160 only + //#define SPI_ENDSTOPS // TMC2130, TMC2240, and TMC5160 //#define IMPROVE_HOMING_RELIABILITY + //#define SENSORLESS_STALLGUARD_DELAY 0 // (ms) Delay to allow drivers to settle #endif // @section tmc/config @@ -3669,6 +3787,8 @@ #define SPEED_POWER_MIN 5000 // (RPM) #define SPEED_POWER_MAX 30000 // (RPM) SuperPID router controller 0 - 30,000 RPM #define SPEED_POWER_STARTUP 25000 // (RPM) M3/M4 speed/power default (with no arguments) + + //#define DEFAULT_ACCELERATION_SPINDLE 1000 // (°/s/s) Default spindle acceleration (speed change with time) #endif #else @@ -3910,7 +4030,7 @@ /** * Extra options for the M114 "Current Position" report */ -//#define M114_DETAIL // Use 'M114` for details to check planner calculations +//#define M114_DETAIL // Use 'M114 D' for details to check planner calculations //#define M114_REALTIME // Real current position based on forward kinematics //#define M114_LEGACY // M114 used to synchronize on every call. Enable if needed. @@ -3939,7 +4059,7 @@ #endif /** - * M115 - Report capabilites. Disable to save ~1150 bytes of flash. + * M115 - Report capabilities. Disable to save ~1150 bytes of flash. * Some hosts (and serial TFT displays) rely on this feature. */ #define CAPABILITIES_REPORT @@ -3957,7 +4077,6 @@ * Spend 28 bytes of SRAM to optimize the G-code parser */ #define FASTER_GCODE_PARSER - #if ENABLED(FASTER_GCODE_PARSER) //#define GCODE_QUOTED_STRINGS // Support for quoted string parameters #endif @@ -4015,13 +4134,17 @@ /** * G-code Macros * - * Add G-codes M810-M819 to define and run G-code macros. - * Macros are not saved to EEPROM. + * Add G-codes M810-M819 to define and run G-code macros + * and M820 to report the current set of macros. + * Macros are not saved to EEPROM unless enabled below. */ //#define GCODE_MACROS #if ENABLED(GCODE_MACROS) #define GCODE_MACROS_SLOTS 5 // Up to 10 may be used #define GCODE_MACROS_SLOT_SIZE 50 // Maximum length of a single macro + #if ENABLED(EEPROM_SETTINGS) + //#define GCODE_MACROS_IN_EEPROM // Include macros in EEPROM + #endif #endif /** @@ -4043,22 +4166,27 @@ #define MAIN_MENU_ITEM_1_DESC "Home & UBL Info" #define MAIN_MENU_ITEM_1_GCODE "G28\nG29 W" //#define MAIN_MENU_ITEM_1_CONFIRM // Show a confirmation dialog before this action + //#define MAIN_MENU_ITEM_1_IMMEDIATE // Skip the queue and execute immediately. Rarely needed. #define MAIN_MENU_ITEM_2_DESC "Preheat for " PREHEAT_1_LABEL #define MAIN_MENU_ITEM_2_GCODE "M140 S" STRINGIFY(PREHEAT_1_TEMP_BED) "\nM104 S" STRINGIFY(PREHEAT_1_TEMP_HOTEND) //#define MAIN_MENU_ITEM_2_CONFIRM + //#define MAIN_MENU_ITEM_2_IMMEDIATE //#define MAIN_MENU_ITEM_3_DESC "Preheat for " PREHEAT_2_LABEL //#define MAIN_MENU_ITEM_3_GCODE "M140 S" STRINGIFY(PREHEAT_2_TEMP_BED) "\nM104 S" STRINGIFY(PREHEAT_2_TEMP_HOTEND) //#define MAIN_MENU_ITEM_3_CONFIRM + //#define MAIN_MENU_ITEM_3_IMMEDIATE //#define MAIN_MENU_ITEM_4_DESC "Heat Bed/Home/Level" //#define MAIN_MENU_ITEM_4_GCODE "M140 S" STRINGIFY(PREHEAT_2_TEMP_BED) "\nG28\nG29" //#define MAIN_MENU_ITEM_4_CONFIRM + //#define MAIN_MENU_ITEM_4_IMMEDIATE //#define MAIN_MENU_ITEM_5_DESC "Home & Info" //#define MAIN_MENU_ITEM_5_GCODE "G28\nM503" //#define MAIN_MENU_ITEM_5_CONFIRM + //#define MAIN_MENU_ITEM_5_IMMEDIATE #endif // @section custom config menu @@ -4075,22 +4203,27 @@ #define CONFIG_MENU_ITEM_1_DESC "Wifi ON" #define CONFIG_MENU_ITEM_1_GCODE "M118 [ESP110] WIFI-STA pwd=12345678" //#define CONFIG_MENU_ITEM_1_CONFIRM // Show a confirmation dialog before this action + //#define CONFIG_MENU_ITEM_1_IMMEDIATE // Skip the queue and execute immediately. Rarely needed. #define CONFIG_MENU_ITEM_2_DESC "Bluetooth ON" #define CONFIG_MENU_ITEM_2_GCODE "M118 [ESP110] BT pwd=12345678" //#define CONFIG_MENU_ITEM_2_CONFIRM + //#define CONFIG_MENU_ITEM_2_IMMEDIATE //#define CONFIG_MENU_ITEM_3_DESC "Radio OFF" //#define CONFIG_MENU_ITEM_3_GCODE "M118 [ESP110] OFF pwd=12345678" //#define CONFIG_MENU_ITEM_3_CONFIRM + //#define CONFIG_MENU_ITEM_3_IMMEDIATE //#define CONFIG_MENU_ITEM_4_DESC "Wifi ????" //#define CONFIG_MENU_ITEM_4_GCODE "M118 ????" //#define CONFIG_MENU_ITEM_4_CONFIRM + //#define CONFIG_MENU_ITEM_4_IMMEDIATE //#define CONFIG_MENU_ITEM_5_DESC "Wifi ????" //#define CONFIG_MENU_ITEM_5_GCODE "M118 ????" //#define CONFIG_MENU_ITEM_5_CONFIRM + //#define CONFIG_MENU_ITEM_5_IMMEDIATE #endif // @section custom buttons @@ -4107,6 +4240,7 @@ #define BUTTON1_WHEN_PRINTING false // Button allowed to trigger during printing? #define BUTTON1_GCODE "G28" #define BUTTON1_DESC "Homing" // Optional string to set the LCD status + //#define BUTTON1_IMMEDIATE // Skip the queue and execute immediately. Rarely needed. #endif //#define BUTTON2_PIN -1 @@ -4115,6 +4249,7 @@ #define BUTTON2_WHEN_PRINTING false #define BUTTON2_GCODE "M140 S" STRINGIFY(PREHEAT_1_TEMP_BED) "\nM104 S" STRINGIFY(PREHEAT_1_TEMP_HOTEND) #define BUTTON2_DESC "Preheat for " PREHEAT_1_LABEL + //#define BUTTON2_IMMEDIATE #endif //#define BUTTON3_PIN -1 @@ -4123,6 +4258,7 @@ #define BUTTON3_WHEN_PRINTING false #define BUTTON3_GCODE "M140 S" STRINGIFY(PREHEAT_2_TEMP_BED) "\nM104 S" STRINGIFY(PREHEAT_2_TEMP_HOTEND) #define BUTTON3_DESC "Preheat for " PREHEAT_2_LABEL + //#define BUTTON3_IMMEDIATE #endif #endif @@ -4195,7 +4331,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 @@ -4659,6 +4795,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 diff --git a/Marlin/Makefile b/Marlin/Makefile index 63b1029e1b..aed2506ac8 100644 --- a/Marlin/Makefile +++ b/Marlin/Makefile @@ -127,9 +127,9 @@ NEOPIXEL ?= 0 # on GCC versions: # https://www.avrfreaks.net/comment/1789106#comment-1789106 -CC_MAJ:=$(shell $(CC) -dM -E - < /dev/null | grep __GNUC__ | cut -f3 -d\ ) -CC_MIN:=$(shell $(CC) -dM -E - < /dev/null | grep __GNUC_MINOR__ | cut -f3 -d\ ) -CC_PATCHLEVEL:=$(shell $(CC) -dM -E - < /dev/null | grep __GNUC_PATCHLEVEL__ | cut -f3 -d\ ) +CC_MAJ:=$(shell $(CC) -dM -E - < /dev/null | grep __GNUC__ | cut -f3 -d' ' ) +CC_MIN:=$(shell $(CC) -dM -E - < /dev/null | grep __GNUC_MINOR__ | cut -f3 -d' ' ) +CC_PATCHLEVEL:=$(shell $(CC) -dM -E - < /dev/null | grep __GNUC_PATCHLEVEL__ | cut -f3 -d' ' ) CC_VER:=$(shell echo $$(( $(CC_MAJ) * 10000 + $(CC_MIN) * 100 + $(CC_PATCHLEVEL) ))) ifeq ($(shell test $(CC_VER) -lt 40901 && echo 1),1) $(warning This GCC version $(CC_VER) is likely broken. Enabling relocation workaround.) @@ -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,59 +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) - +# XTLW MFF V2.0 +else ifeq ($(HARDWARE_MOTHERBOARD),1167) +# E3D Rumba BigBox +else ifeq ($(HARDWARE_MOTHERBOARD),1168) # # RAMBo and derivatives @@ -407,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 @@ -512,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 @@ -626,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 @@ -798,10 +807,10 @@ endif ifeq ($(TMC), 1) LIB_CXXSRC += TMCStepper.cpp COOLCONF.cpp DRV_STATUS.cpp IHOLD_IRUN.cpp \ - CHOPCONF.cpp GCONF.cpp PWMCONF.cpp DRV_CONF.cpp DRVCONF.cpp DRVCTRL.cpp \ - DRVSTATUS.cpp ENCMODE.cpp RAMP_STAT.cpp SGCSCONF.cpp SHORT_CONF.cpp \ - SMARTEN.cpp SW_MODE.cpp SW_SPI.cpp TMC2130Stepper.cpp TMC2208Stepper.cpp \ - TMC2209Stepper.cpp TMC2660Stepper.cpp TMC5130Stepper.cpp TMC5160Stepper.cpp + CHOPCONF.cpp GCONF.cpp PWMCONF.cpp DRV_CONF.cpp DRVCONF.cpp DRVCTRL.cpp DRVSTATUS.cpp \ + GLOBAL_SCALER.cpp SLAVECONF.cpp IOIN.cpp ENCMODE.cpp RAMP_STAT.cpp SGCSCONF.cpp \ + SHORT_CONF.cpp SMARTEN.cpp SW_MODE.cpp SW_SPI.cpp TMC2130Stepper.cpp TMC2208Stepper.cpp \ + TMC2209Stepper.cpp TMC2240Stepper.cpp TMC2660Stepper.cpp TMC5130Stepper.cpp TMC5160Stepper.cpp endif ifeq ($(RELOC_WORKAROUND), 1) @@ -868,8 +877,8 @@ else ifeq ($(HARDWARE_VARIANT), archim) endif # Add all the source directories as include directories too -CINCS = ${addprefix -I ,${VPATH}} -CXXINCS = ${addprefix -I ,${VPATH}} +CINCS = ${addprefix -I, ${VPATH}} +CXXINCS = ${addprefix -I, ${VPATH}} # Silence warnings for library code (won't work for .h files, unfortunately) LIBWARN = -w -Wno-packed-bitfield-compat diff --git a/Marlin/Version.h b/Marlin/Version.h index 042bc34f24..dea1410f50 100644 --- a/Marlin/Version.h +++ b/Marlin/Version.h @@ -41,7 +41,7 @@ * here we define this default string as the date where the latest release * version was tagged. */ -//#define STRING_DISTRIBUTION_DATE "2024-12-13" +//#define STRING_DISTRIBUTION_DATE "2025-12-20" /** * The protocol for communication to the host. Protocol indicates communication diff --git a/Marlin/config.ini b/Marlin/config.ini index d6d2395e39..fd2b81062a 100644 --- a/Marlin/config.ini +++ b/Marlin/config.ini @@ -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 diff --git a/Marlin/src/HAL/AVR/HAL.cpp b/Marlin/src/HAL/AVR/HAL.cpp index 97173c63f9..4fbab8941f 100644 --- a/Marlin/src/HAL/AVR/HAL.cpp +++ b/Marlin/src/HAL/AVR/HAL.cpp @@ -119,7 +119,6 @@ void MarlinHAL::reboot() { #if ENABLED(USE_WATCHDOG) #include - #include "../../MarlinCore.h" // Initialize watchdog with 8s timeout, if possible. Otherwise, make it 4s. void MarlinHAL::watchdog_init() { @@ -154,7 +153,7 @@ void MarlinHAL::reboot() { ISR(WDT_vect) { sei(); // With the interrupt driven serial we need to allow interrupts. SERIAL_ERROR_MSG(STR_WATCHDOG_FIRED); - minkill(); // interrupt-safe final kill and infinite loop + marlin.minkill(); // interrupt-safe final kill and infinite loop } #endif diff --git a/Marlin/src/HAL/AVR/HAL.h b/Marlin/src/HAL/AVR/HAL.h index b420236956..02c5d42beb 100644 --- a/Marlin/src/HAL/AVR/HAL.h +++ b/Marlin/src/HAL/AVR/HAL.h @@ -204,9 +204,9 @@ public: static void isr_on() { sei(); } static void isr_off() { cli(); } - static void delay_ms(const int ms) { _delay_ms(ms); } + static void delay_ms(const int ms) { delay(ms); } - // Tasks, called from idle() + // Tasks, called from marlin.idle() static void idletask() {} // Reset diff --git a/Marlin/src/HAL/AVR/MarlinSerial.cpp b/Marlin/src/HAL/AVR/MarlinSerial.cpp index d070731418..750776c4be 100644 --- a/Marlin/src/HAL/AVR/MarlinSerial.cpp +++ b/Marlin/src/HAL/AVR/MarlinSerial.cpp @@ -41,7 +41,6 @@ #if !defined(USBCON) && (defined(UBRRH) || defined(UBRR0H) || defined(UBRR1H) || defined(UBRR2H) || defined(UBRR3H)) #include "MarlinSerial.h" -#include "../../MarlinCore.h" #if ENABLED(DIRECT_STEPPING) #include "../../feature/direct_stepping.h" diff --git a/Marlin/src/HAL/AVR/fastio.cpp b/Marlin/src/HAL/AVR/fastio.cpp index 5c6ef18915..98fd636ebf 100644 --- a/Marlin/src/HAL/AVR/fastio.cpp +++ b/Marlin/src/HAL/AVR/fastio.cpp @@ -241,7 +241,7 @@ uint8_t extDigitalRead(const int8_t pin) { * * DC values -1.0 to 1.0. Negative duty cycle inverts the pulse. */ -uint16_t set_pwm_frequency_hz(const_float_t hz, const float dca, const float dcb, const float dcc) { +uint16_t set_pwm_frequency_hz(const float hz, const float dca, const float dcb, const float dcc) { float count = 0; if (hz > 0 && (dca || dcb || dcc)) { count = float(F_CPU) / hz; // 1x prescaler, TOP for 16MHz base freq. @@ -254,7 +254,7 @@ uint16_t set_pwm_frequency_hz(const_float_t 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_t 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 diff --git a/Marlin/src/HAL/AVR/fastio/fastio_AT90USB.h b/Marlin/src/HAL/AVR/fastio/fastio_AT90USB.h index 2119d168ab..a9af519ff3 100644 --- a/Marlin/src/HAL/AVR/fastio/fastio_AT90USB.h +++ b/Marlin/src/HAL/AVR/fastio/fastio_AT90USB.h @@ -363,8 +363,11 @@ #define AIO7_PWM 0 #define AIO7_DDR DDRF -//-- Begin not supported by Teensyduino -//-- don't use Arduino functions on these pins pinMode/digitalWrite/etc +//-- 46-47 are not supported by Teensyduino +//-- Don't use Arduino functions (pinMode, digitalWrite, etc.) on these pins +#define PIN_E2 46 +#define PIN_E3 47 + #define DIO46_PIN PINE2 #define DIO46_RPORT PINE #define DIO46_WPORT PORTE @@ -377,10 +380,7 @@ #define DIO47_PWM 0 #define DIO47_DDR DDRE -#define TEENSY_E2 46 -#define TEENSY_E3 47 - -//-- end not supported by Teensyduino +//-- #undef PA0 #define PA0_PIN PINA0 diff --git a/Marlin/src/HAL/AVR/inc/SanityCheck.h b/Marlin/src/HAL/AVR/inc/SanityCheck.h index 85ee683685..08fe21d4f8 100644 --- a/Marlin/src/HAL/AVR/inc/SanityCheck.h +++ b/Marlin/src/HAL/AVR/inc/SanityCheck.h @@ -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 diff --git a/Marlin/src/HAL/AVR/pinsDebug.h b/Marlin/src/HAL/AVR/pinsDebug.h index e9bc09a4bf..c833964a29 100644 --- a/Marlin/src/HAL/AVR/pinsDebug.h +++ b/Marlin/src/HAL/AVR/pinsDebug.h @@ -377,16 +377,16 @@ void printPinPort(const pin_t pin) { // print port number uint8_t x; SERIAL_ECHOPGM(" Port: "); #if AVR_AT90USB1286_FAMILY - x = (pin == 46 || pin == 47) ? 'E' : digitalPinToPort_DEBUG(pin) + 64; + x = (pin == PIN_E2 || pin == PIN_E3) ? 'E' : 'A' + digitalPinToPort_DEBUG(pin) - 1; #else - x = digitalPinToPort_DEBUG(pin) + 64; + x = 'A' + digitalPinToPort_DEBUG(pin) - 1; #endif SERIAL_CHAR(x); #if AVR_AT90USB1286_FAMILY - if (pin == 46) + if (pin == PIN_E2) x = '2'; - else if (pin == 47) + else if (pin == PIN_E3) x = '3'; else { uint8_t temp = digitalPinToBitMask_DEBUG(pin); diff --git a/Marlin/src/HAL/AVR/pinsDebug_plus_70.h b/Marlin/src/HAL/AVR/pinsDebug_plus_70.h index fa479cfe8f..6565acd523 100644 --- a/Marlin/src/HAL/AVR/pinsDebug_plus_70.h +++ b/Marlin/src/HAL/AVR/pinsDebug_plus_70.h @@ -48,92 +48,92 @@ const uint8_t PROGMEM digital_pin_to_port_PGM_plus_70[] = { // PORTLIST // ------------------------ - PE , // PE 0 ** 0 ** USART0_RX - PE , // PE 1 ** 1 ** USART0_TX - PE , // PE 4 ** 2 ** PWM2 - PE , // PE 5 ** 3 ** PWM3 - PG , // PG 5 ** 4 ** PWM4 - PE , // PE 3 ** 5 ** PWM5 - PH , // PH 3 ** 6 ** PWM6 - PH , // PH 4 ** 7 ** PWM7 - PH , // PH 5 ** 8 ** PWM8 - PH , // PH 6 ** 9 ** PWM9 - PB , // PB 4 ** 10 ** PWM10 - PB , // PB 5 ** 11 ** PWM11 - PB , // PB 6 ** 12 ** PWM12 - PB , // PB 7 ** 13 ** PWM13 - PJ , // PJ 1 ** 14 ** USART3_TX - PJ , // PJ 0 ** 15 ** USART3_RX - PH , // PH 1 ** 16 ** USART2_TX - PH , // PH 0 ** 17 ** USART2_RX - PD , // PD 3 ** 18 ** USART1_TX - PD , // PD 2 ** 19 ** USART1_RX - PD , // PD 1 ** 20 ** I2C_SDA - PD , // PD 0 ** 21 ** I2C_SCL - PA , // PA 0 ** 22 ** D22 - PA , // PA 1 ** 23 ** D23 - PA , // PA 2 ** 24 ** D24 - PA , // PA 3 ** 25 ** D25 - PA , // PA 4 ** 26 ** D26 - PA , // PA 5 ** 27 ** D27 - PA , // PA 6 ** 28 ** D28 - PA , // PA 7 ** 29 ** D29 - PC , // PC 7 ** 30 ** D30 - PC , // PC 6 ** 31 ** D31 - PC , // PC 5 ** 32 ** D32 - PC , // PC 4 ** 33 ** D33 - PC , // PC 3 ** 34 ** D34 - PC , // PC 2 ** 35 ** D35 - PC , // PC 1 ** 36 ** D36 - PC , // PC 0 ** 37 ** D37 - PD , // PD 7 ** 38 ** D38 - PG , // PG 2 ** 39 ** D39 - PG , // PG 1 ** 40 ** D40 - PG , // PG 0 ** 41 ** D41 - PL , // PL 7 ** 42 ** D42 - PL , // PL 6 ** 43 ** D43 - PL , // PL 5 ** 44 ** D44 - PL , // PL 4 ** 45 ** D45 - PL , // PL 3 ** 46 ** D46 - PL , // PL 2 ** 47 ** D47 - PL , // PL 1 ** 48 ** D48 - PL , // PL 0 ** 49 ** D49 - PB , // PB 3 ** 50 ** SPI_MISO - PB , // PB 2 ** 51 ** SPI_MOSI - PB , // PB 1 ** 52 ** SPI_SCK - PB , // PB 0 ** 53 ** SPI_SS - PF , // PF 0 ** 54 ** A0 - PF , // PF 1 ** 55 ** A1 - PF , // PF 2 ** 56 ** A2 - PF , // PF 3 ** 57 ** A3 - PF , // PF 4 ** 58 ** A4 - PF , // PF 5 ** 59 ** A5 - PF , // PF 6 ** 60 ** A6 - PF , // PF 7 ** 61 ** A7 - PK , // PK 0 ** 62 ** A8 - PK , // PK 1 ** 63 ** A9 - PK , // PK 2 ** 64 ** A10 - PK , // PK 3 ** 65 ** A11 - PK , // PK 4 ** 66 ** A12 - PK , // PK 5 ** 67 ** A13 - PK , // PK 6 ** 68 ** A14 - PK , // PK 7 ** 69 ** A15 - PG , // PG 4 ** 70 ** - PG , // PG 3 ** 71 ** - PJ , // PJ 2 ** 72 ** - PJ , // PJ 3 ** 73 ** - PJ , // PJ 7 ** 74 ** - PJ , // PJ 4 ** 75 ** - PJ , // PJ 5 ** 76 ** - PJ , // PJ 6 ** 77 ** - PE , // PE 2 ** 78 ** - PE , // PE 6 ** 79 ** - PE , // PE 7 ** 80 ** - PD , // PD 4 ** 81 ** - PD , // PD 5 ** 82 ** - PD , // PD 6 ** 83 ** - PH , // PH 2 ** 84 ** - PH , // PH 7 ** 85 ** + PE, // PE 0 ** 0 ** USART0_RX + PE, // PE 1 ** 1 ** USART0_TX + PE, // PE 4 ** 2 ** PWM2 + PE, // PE 5 ** 3 ** PWM3 + PG, // PG 5 ** 4 ** PWM4 + PE, // PE 3 ** 5 ** PWM5 + PH, // PH 3 ** 6 ** PWM6 + PH, // PH 4 ** 7 ** PWM7 + PH, // PH 5 ** 8 ** PWM8 + PH, // PH 6 ** 9 ** PWM9 + PB, // PB 4 ** 10 ** PWM10 + PB, // PB 5 ** 11 ** PWM11 + PB, // PB 6 ** 12 ** PWM12 + PB, // PB 7 ** 13 ** PWM13 + PJ, // PJ 1 ** 14 ** USART3_TX + PJ, // PJ 0 ** 15 ** USART3_RX + PH, // PH 1 ** 16 ** USART2_TX + PH, // PH 0 ** 17 ** USART2_RX + PD, // PD 3 ** 18 ** USART1_TX + PD, // PD 2 ** 19 ** USART1_RX + PD, // PD 1 ** 20 ** I2C_SDA + PD, // PD 0 ** 21 ** I2C_SCL + PA, // PA 0 ** 22 ** D22 + PA, // PA 1 ** 23 ** D23 + PA, // PA 2 ** 24 ** D24 + PA, // PA 3 ** 25 ** D25 + PA, // PA 4 ** 26 ** D26 + PA, // PA 5 ** 27 ** D27 + PA, // PA 6 ** 28 ** D28 + PA, // PA 7 ** 29 ** D29 + PC, // PC 7 ** 30 ** D30 + PC, // PC 6 ** 31 ** D31 + PC, // PC 5 ** 32 ** D32 + PC, // PC 4 ** 33 ** D33 + PC, // PC 3 ** 34 ** D34 + PC, // PC 2 ** 35 ** D35 + PC, // PC 1 ** 36 ** D36 + PC, // PC 0 ** 37 ** D37 + PD, // PD 7 ** 38 ** D38 + PG, // PG 2 ** 39 ** D39 + PG, // PG 1 ** 40 ** D40 + PG, // PG 0 ** 41 ** D41 + PL, // PL 7 ** 42 ** D42 + PL, // PL 6 ** 43 ** D43 + PL, // PL 5 ** 44 ** D44 + PL, // PL 4 ** 45 ** D45 + PL, // PL 3 ** 46 ** D46 + PL, // PL 2 ** 47 ** D47 + PL, // PL 1 ** 48 ** D48 + PL, // PL 0 ** 49 ** D49 + PB, // PB 3 ** 50 ** SPI_MISO + PB, // PB 2 ** 51 ** SPI_MOSI + PB, // PB 1 ** 52 ** SPI_SCK + PB, // PB 0 ** 53 ** SPI_SS + PF, // PF 0 ** 54 ** A0 + PF, // PF 1 ** 55 ** A1 + PF, // PF 2 ** 56 ** A2 + PF, // PF 3 ** 57 ** A3 + PF, // PF 4 ** 58 ** A4 + PF, // PF 5 ** 59 ** A5 + PF, // PF 6 ** 60 ** A6 + PF, // PF 7 ** 61 ** A7 + PK, // PK 0 ** 62 ** A8 + PK, // PK 1 ** 63 ** A9 + PK, // PK 2 ** 64 ** A10 + PK, // PK 3 ** 65 ** A11 + PK, // PK 4 ** 66 ** A12 + PK, // PK 5 ** 67 ** A13 + PK, // PK 6 ** 68 ** A14 + PK, // PK 7 ** 69 ** A15 + PG, // PG 4 ** 70 ** + PG, // PG 3 ** 71 ** + PJ, // PJ 2 ** 72 ** + PJ, // PJ 3 ** 73 ** + PJ, // PJ 7 ** 74 ** + PJ, // PJ 4 ** 75 ** + PJ, // PJ 5 ** 76 ** + PJ, // PJ 6 ** 77 ** + PE, // PE 2 ** 78 ** + PE, // PE 6 ** 79 ** + PE, // PE 7 ** 80 ** + PD, // PD 4 ** 81 ** + PD, // PD 5 ** 82 ** + PD, // PD 6 ** 83 ** + PH, // PH 2 ** 84 ** + PH, // PH 7 ** 85 ** }; #define digitalPinToPort_plus_70(P) ( pgm_read_byte( digital_pin_to_port_PGM_plus_70 + (P) ) ) @@ -141,92 +141,92 @@ const uint8_t PROGMEM digital_pin_to_port_PGM_plus_70[] = { const uint8_t PROGMEM digital_pin_to_bit_mask_PGM_plus_70[] = { // PIN IN PORT // ------------------------ - _BV( 0 ) , // PE 0 ** 0 ** USART0_RX - _BV( 1 ) , // PE 1 ** 1 ** USART0_TX - _BV( 4 ) , // PE 4 ** 2 ** PWM2 - _BV( 5 ) , // PE 5 ** 3 ** PWM3 - _BV( 5 ) , // PG 5 ** 4 ** PWM4 - _BV( 3 ) , // PE 3 ** 5 ** PWM5 - _BV( 3 ) , // PH 3 ** 6 ** PWM6 - _BV( 4 ) , // PH 4 ** 7 ** PWM7 - _BV( 5 ) , // PH 5 ** 8 ** PWM8 - _BV( 6 ) , // PH 6 ** 9 ** PWM9 - _BV( 4 ) , // PB 4 ** 10 ** PWM10 - _BV( 5 ) , // PB 5 ** 11 ** PWM11 - _BV( 6 ) , // PB 6 ** 12 ** PWM12 - _BV( 7 ) , // PB 7 ** 13 ** PWM13 - _BV( 1 ) , // PJ 1 ** 14 ** USART3_TX - _BV( 0 ) , // PJ 0 ** 15 ** USART3_RX - _BV( 1 ) , // PH 1 ** 16 ** USART2_TX - _BV( 0 ) , // PH 0 ** 17 ** USART2_RX - _BV( 3 ) , // PD 3 ** 18 ** USART1_TX - _BV( 2 ) , // PD 2 ** 19 ** USART1_RX - _BV( 1 ) , // PD 1 ** 20 ** I2C_SDA - _BV( 0 ) , // PD 0 ** 21 ** I2C_SCL - _BV( 0 ) , // PA 0 ** 22 ** D22 - _BV( 1 ) , // PA 1 ** 23 ** D23 - _BV( 2 ) , // PA 2 ** 24 ** D24 - _BV( 3 ) , // PA 3 ** 25 ** D25 - _BV( 4 ) , // PA 4 ** 26 ** D26 - _BV( 5 ) , // PA 5 ** 27 ** D27 - _BV( 6 ) , // PA 6 ** 28 ** D28 - _BV( 7 ) , // PA 7 ** 29 ** D29 - _BV( 7 ) , // PC 7 ** 30 ** D30 - _BV( 6 ) , // PC 6 ** 31 ** D31 - _BV( 5 ) , // PC 5 ** 32 ** D32 - _BV( 4 ) , // PC 4 ** 33 ** D33 - _BV( 3 ) , // PC 3 ** 34 ** D34 - _BV( 2 ) , // PC 2 ** 35 ** D35 - _BV( 1 ) , // PC 1 ** 36 ** D36 - _BV( 0 ) , // PC 0 ** 37 ** D37 - _BV( 7 ) , // PD 7 ** 38 ** D38 - _BV( 2 ) , // PG 2 ** 39 ** D39 - _BV( 1 ) , // PG 1 ** 40 ** D40 - _BV( 0 ) , // PG 0 ** 41 ** D41 - _BV( 7 ) , // PL 7 ** 42 ** D42 - _BV( 6 ) , // PL 6 ** 43 ** D43 - _BV( 5 ) , // PL 5 ** 44 ** D44 - _BV( 4 ) , // PL 4 ** 45 ** D45 - _BV( 3 ) , // PL 3 ** 46 ** D46 - _BV( 2 ) , // PL 2 ** 47 ** D47 - _BV( 1 ) , // PL 1 ** 48 ** D48 - _BV( 0 ) , // PL 0 ** 49 ** D49 - _BV( 3 ) , // PB 3 ** 50 ** SPI_MISO - _BV( 2 ) , // PB 2 ** 51 ** SPI_MOSI - _BV( 1 ) , // PB 1 ** 52 ** SPI_SCK - _BV( 0 ) , // PB 0 ** 53 ** SPI_SS - _BV( 0 ) , // PF 0 ** 54 ** A0 - _BV( 1 ) , // PF 1 ** 55 ** A1 - _BV( 2 ) , // PF 2 ** 56 ** A2 - _BV( 3 ) , // PF 3 ** 57 ** A3 - _BV( 4 ) , // PF 4 ** 58 ** A4 - _BV( 5 ) , // PF 5 ** 59 ** A5 - _BV( 6 ) , // PF 6 ** 60 ** A6 - _BV( 7 ) , // PF 7 ** 61 ** A7 - _BV( 0 ) , // PK 0 ** 62 ** A8 - _BV( 1 ) , // PK 1 ** 63 ** A9 - _BV( 2 ) , // PK 2 ** 64 ** A10 - _BV( 3 ) , // PK 3 ** 65 ** A11 - _BV( 4 ) , // PK 4 ** 66 ** A12 - _BV( 5 ) , // PK 5 ** 67 ** A13 - _BV( 6 ) , // PK 6 ** 68 ** A14 - _BV( 7 ) , // PK 7 ** 69 ** A15 - _BV( 4 ) , // PG 4 ** 70 ** - _BV( 3 ) , // PG 3 ** 71 ** - _BV( 2 ) , // PJ 2 ** 72 ** - _BV( 3 ) , // PJ 3 ** 73 ** - _BV( 7 ) , // PJ 7 ** 74 ** - _BV( 4 ) , // PJ 4 ** 75 ** - _BV( 5 ) , // PJ 5 ** 76 ** - _BV( 6 ) , // PJ 6 ** 77 ** - _BV( 2 ) , // PE 2 ** 78 ** - _BV( 6 ) , // PE 6 ** 79 ** - _BV( 7 ) , // PE 7 ** 80 ** - _BV( 4 ) , // PD 4 ** 81 ** - _BV( 5 ) , // PD 5 ** 82 ** - _BV( 6 ) , // PD 6 ** 83 ** - _BV( 2 ) , // PH 2 ** 84 ** - _BV( 7 ) , // PH 7 ** 85 ** + _BV( 0 ), // PE 0 ** 0 ** USART0_RX + _BV( 1 ), // PE 1 ** 1 ** USART0_TX + _BV( 4 ), // PE 4 ** 2 ** PWM2 + _BV( 5 ), // PE 5 ** 3 ** PWM3 + _BV( 5 ), // PG 5 ** 4 ** PWM4 + _BV( 3 ), // PE 3 ** 5 ** PWM5 + _BV( 3 ), // PH 3 ** 6 ** PWM6 + _BV( 4 ), // PH 4 ** 7 ** PWM7 + _BV( 5 ), // PH 5 ** 8 ** PWM8 + _BV( 6 ), // PH 6 ** 9 ** PWM9 + _BV( 4 ), // PB 4 ** 10 ** PWM10 + _BV( 5 ), // PB 5 ** 11 ** PWM11 + _BV( 6 ), // PB 6 ** 12 ** PWM12 + _BV( 7 ), // PB 7 ** 13 ** PWM13 + _BV( 1 ), // PJ 1 ** 14 ** USART3_TX + _BV( 0 ), // PJ 0 ** 15 ** USART3_RX + _BV( 1 ), // PH 1 ** 16 ** USART2_TX + _BV( 0 ), // PH 0 ** 17 ** USART2_RX + _BV( 3 ), // PD 3 ** 18 ** USART1_TX + _BV( 2 ), // PD 2 ** 19 ** USART1_RX + _BV( 1 ), // PD 1 ** 20 ** I2C_SDA + _BV( 0 ), // PD 0 ** 21 ** I2C_SCL + _BV( 0 ), // PA 0 ** 22 ** D22 + _BV( 1 ), // PA 1 ** 23 ** D23 + _BV( 2 ), // PA 2 ** 24 ** D24 + _BV( 3 ), // PA 3 ** 25 ** D25 + _BV( 4 ), // PA 4 ** 26 ** D26 + _BV( 5 ), // PA 5 ** 27 ** D27 + _BV( 6 ), // PA 6 ** 28 ** D28 + _BV( 7 ), // PA 7 ** 29 ** D29 + _BV( 7 ), // PC 7 ** 30 ** D30 + _BV( 6 ), // PC 6 ** 31 ** D31 + _BV( 5 ), // PC 5 ** 32 ** D32 + _BV( 4 ), // PC 4 ** 33 ** D33 + _BV( 3 ), // PC 3 ** 34 ** D34 + _BV( 2 ), // PC 2 ** 35 ** D35 + _BV( 1 ), // PC 1 ** 36 ** D36 + _BV( 0 ), // PC 0 ** 37 ** D37 + _BV( 7 ), // PD 7 ** 38 ** D38 + _BV( 2 ), // PG 2 ** 39 ** D39 + _BV( 1 ), // PG 1 ** 40 ** D40 + _BV( 0 ), // PG 0 ** 41 ** D41 + _BV( 7 ), // PL 7 ** 42 ** D42 + _BV( 6 ), // PL 6 ** 43 ** D43 + _BV( 5 ), // PL 5 ** 44 ** D44 + _BV( 4 ), // PL 4 ** 45 ** D45 + _BV( 3 ), // PL 3 ** 46 ** D46 + _BV( 2 ), // PL 2 ** 47 ** D47 + _BV( 1 ), // PL 1 ** 48 ** D48 + _BV( 0 ), // PL 0 ** 49 ** D49 + _BV( 3 ), // PB 3 ** 50 ** SPI_MISO + _BV( 2 ), // PB 2 ** 51 ** SPI_MOSI + _BV( 1 ), // PB 1 ** 52 ** SPI_SCK + _BV( 0 ), // PB 0 ** 53 ** SPI_SS + _BV( 0 ), // PF 0 ** 54 ** A0 + _BV( 1 ), // PF 1 ** 55 ** A1 + _BV( 2 ), // PF 2 ** 56 ** A2 + _BV( 3 ), // PF 3 ** 57 ** A3 + _BV( 4 ), // PF 4 ** 58 ** A4 + _BV( 5 ), // PF 5 ** 59 ** A5 + _BV( 6 ), // PF 6 ** 60 ** A6 + _BV( 7 ), // PF 7 ** 61 ** A7 + _BV( 0 ), // PK 0 ** 62 ** A8 + _BV( 1 ), // PK 1 ** 63 ** A9 + _BV( 2 ), // PK 2 ** 64 ** A10 + _BV( 3 ), // PK 3 ** 65 ** A11 + _BV( 4 ), // PK 4 ** 66 ** A12 + _BV( 5 ), // PK 5 ** 67 ** A13 + _BV( 6 ), // PK 6 ** 68 ** A14 + _BV( 7 ), // PK 7 ** 69 ** A15 + _BV( 4 ), // PG 4 ** 70 ** + _BV( 3 ), // PG 3 ** 71 ** + _BV( 2 ), // PJ 2 ** 72 ** + _BV( 3 ), // PJ 3 ** 73 ** + _BV( 7 ), // PJ 7 ** 74 ** + _BV( 4 ), // PJ 4 ** 75 ** + _BV( 5 ), // PJ 5 ** 76 ** + _BV( 6 ), // PJ 6 ** 77 ** + _BV( 2 ), // PE 2 ** 78 ** + _BV( 6 ), // PE 6 ** 79 ** + _BV( 7 ), // PE 7 ** 80 ** + _BV( 4 ), // PD 4 ** 81 ** + _BV( 5 ), // PD 5 ** 82 ** + _BV( 6 ), // PD 6 ** 83 ** + _BV( 2 ), // PH 2 ** 84 ** + _BV( 7 ), // PH 7 ** 85 ** }; #define digitalPinToBitMask_plus_70(P) ( pgm_read_byte( digital_pin_to_bit_mask_PGM_plus_70 + (P) ) ) @@ -234,86 +234,86 @@ const uint8_t PROGMEM digital_pin_to_bit_mask_PGM_plus_70[] = { const uint8_t PROGMEM digital_pin_to_timer_PGM_plus_70[] = { // TIMERS // ------------------------ - NOT_ON_TIMER , // PE 0 ** 0 ** USART0_RX - NOT_ON_TIMER , // PE 1 ** 1 ** USART0_TX - TIMER3B , // PE 4 ** 2 ** PWM2 - TIMER3C , // PE 5 ** 3 ** PWM3 - TIMER0B , // PG 5 ** 4 ** PWM4 - TIMER3A , // PE 3 ** 5 ** PWM5 - TIMER4A , // PH 3 ** 6 ** PWM6 - TIMER4B , // PH 4 ** 7 ** PWM7 - TIMER4C , // PH 5 ** 8 ** PWM8 - TIMER2B , // PH 6 ** 9 ** PWM9 - TIMER2A , // PB 4 ** 10 ** PWM10 - TIMER1A , // PB 5 ** 11 ** PWM11 - TIMER1B , // PB 6 ** 12 ** PWM12 - TIMER0A , // PB 7 ** 13 ** PWM13 - NOT_ON_TIMER , // PJ 1 ** 14 ** USART3_TX - NOT_ON_TIMER , // PJ 0 ** 15 ** USART3_RX - NOT_ON_TIMER , // PH 1 ** 16 ** USART2_TX - NOT_ON_TIMER , // PH 0 ** 17 ** USART2_RX - NOT_ON_TIMER , // PD 3 ** 18 ** USART1_TX - NOT_ON_TIMER , // PD 2 ** 19 ** USART1_RX - NOT_ON_TIMER , // PD 1 ** 20 ** I2C_SDA - NOT_ON_TIMER , // PD 0 ** 21 ** I2C_SCL - NOT_ON_TIMER , // PA 0 ** 22 ** D22 - NOT_ON_TIMER , // PA 1 ** 23 ** D23 - NOT_ON_TIMER , // PA 2 ** 24 ** D24 - NOT_ON_TIMER , // PA 3 ** 25 ** D25 - NOT_ON_TIMER , // PA 4 ** 26 ** D26 - NOT_ON_TIMER , // PA 5 ** 27 ** D27 - NOT_ON_TIMER , // PA 6 ** 28 ** D28 - NOT_ON_TIMER , // PA 7 ** 29 ** D29 - NOT_ON_TIMER , // PC 7 ** 30 ** D30 - NOT_ON_TIMER , // PC 6 ** 31 ** D31 - NOT_ON_TIMER , // PC 5 ** 32 ** D32 - NOT_ON_TIMER , // PC 4 ** 33 ** D33 - NOT_ON_TIMER , // PC 3 ** 34 ** D34 - NOT_ON_TIMER , // PC 2 ** 35 ** D35 - NOT_ON_TIMER , // PC 1 ** 36 ** D36 - NOT_ON_TIMER , // PC 0 ** 37 ** D37 - NOT_ON_TIMER , // PD 7 ** 38 ** D38 - NOT_ON_TIMER , // PG 2 ** 39 ** D39 - NOT_ON_TIMER , // PG 1 ** 40 ** D40 - NOT_ON_TIMER , // PG 0 ** 41 ** D41 - NOT_ON_TIMER , // PL 7 ** 42 ** D42 - NOT_ON_TIMER , // PL 6 ** 43 ** D43 - TIMER5C , // PL 5 ** 44 ** D44 - TIMER5B , // PL 4 ** 45 ** D45 - TIMER5A , // PL 3 ** 46 ** D46 - NOT_ON_TIMER , // PL 2 ** 47 ** D47 - NOT_ON_TIMER , // PL 1 ** 48 ** D48 - NOT_ON_TIMER , // PL 0 ** 49 ** D49 - NOT_ON_TIMER , // PB 3 ** 50 ** SPI_MISO - NOT_ON_TIMER , // PB 2 ** 51 ** SPI_MOSI - NOT_ON_TIMER , // PB 1 ** 52 ** SPI_SCK - NOT_ON_TIMER , // PB 0 ** 53 ** SPI_SS - NOT_ON_TIMER , // PF 0 ** 54 ** A0 - NOT_ON_TIMER , // PF 1 ** 55 ** A1 - NOT_ON_TIMER , // PF 2 ** 56 ** A2 - NOT_ON_TIMER , // PF 3 ** 57 ** A3 - NOT_ON_TIMER , // PF 4 ** 58 ** A4 - NOT_ON_TIMER , // PF 5 ** 59 ** A5 - NOT_ON_TIMER , // PF 6 ** 60 ** A6 - NOT_ON_TIMER , // PF 7 ** 61 ** A7 - NOT_ON_TIMER , // PK 0 ** 62 ** A8 - NOT_ON_TIMER , // PK 1 ** 63 ** A9 - NOT_ON_TIMER , // PK 2 ** 64 ** A10 - NOT_ON_TIMER , // PK 3 ** 65 ** A11 - NOT_ON_TIMER , // PK 4 ** 66 ** A12 - NOT_ON_TIMER , // PK 5 ** 67 ** A13 - NOT_ON_TIMER , // PK 6 ** 68 ** A14 - NOT_ON_TIMER , // PK 7 ** 69 ** A15 - NOT_ON_TIMER , // PG 4 ** 70 ** - NOT_ON_TIMER , // PG 3 ** 71 ** - NOT_ON_TIMER , // PJ 2 ** 72 ** - NOT_ON_TIMER , // PJ 3 ** 73 ** - NOT_ON_TIMER , // PJ 7 ** 74 ** - NOT_ON_TIMER , // PJ 4 ** 75 ** - NOT_ON_TIMER , // PJ 5 ** 76 ** - NOT_ON_TIMER , // PJ 6 ** 77 ** - NOT_ON_TIMER , // PE 2 ** 78 ** - NOT_ON_TIMER , // PE 6 ** 79 ** + NOT_ON_TIMER, // PE 0 ** 0 ** USART0_RX + NOT_ON_TIMER, // PE 1 ** 1 ** USART0_TX + TIMER3B, // PE 4 ** 2 ** PWM2 + TIMER3C, // PE 5 ** 3 ** PWM3 + TIMER0B, // PG 5 ** 4 ** PWM4 + TIMER3A, // PE 3 ** 5 ** PWM5 + TIMER4A, // PH 3 ** 6 ** PWM6 + TIMER4B, // PH 4 ** 7 ** PWM7 + TIMER4C, // PH 5 ** 8 ** PWM8 + TIMER2B, // PH 6 ** 9 ** PWM9 + TIMER2A, // PB 4 ** 10 ** PWM10 + TIMER1A, // PB 5 ** 11 ** PWM11 + TIMER1B, // PB 6 ** 12 ** PWM12 + TIMER0A, // PB 7 ** 13 ** PWM13 + NOT_ON_TIMER, // PJ 1 ** 14 ** USART3_TX + NOT_ON_TIMER, // PJ 0 ** 15 ** USART3_RX + NOT_ON_TIMER, // PH 1 ** 16 ** USART2_TX + NOT_ON_TIMER, // PH 0 ** 17 ** USART2_RX + NOT_ON_TIMER, // PD 3 ** 18 ** USART1_TX + NOT_ON_TIMER, // PD 2 ** 19 ** USART1_RX + NOT_ON_TIMER, // PD 1 ** 20 ** I2C_SDA + NOT_ON_TIMER, // PD 0 ** 21 ** I2C_SCL + NOT_ON_TIMER, // PA 0 ** 22 ** D22 + NOT_ON_TIMER, // PA 1 ** 23 ** D23 + NOT_ON_TIMER, // PA 2 ** 24 ** D24 + NOT_ON_TIMER, // PA 3 ** 25 ** D25 + NOT_ON_TIMER, // PA 4 ** 26 ** D26 + NOT_ON_TIMER, // PA 5 ** 27 ** D27 + NOT_ON_TIMER, // PA 6 ** 28 ** D28 + NOT_ON_TIMER, // PA 7 ** 29 ** D29 + NOT_ON_TIMER, // PC 7 ** 30 ** D30 + NOT_ON_TIMER, // PC 6 ** 31 ** D31 + NOT_ON_TIMER, // PC 5 ** 32 ** D32 + NOT_ON_TIMER, // PC 4 ** 33 ** D33 + NOT_ON_TIMER, // PC 3 ** 34 ** D34 + NOT_ON_TIMER, // PC 2 ** 35 ** D35 + NOT_ON_TIMER, // PC 1 ** 36 ** D36 + NOT_ON_TIMER, // PC 0 ** 37 ** D37 + NOT_ON_TIMER, // PD 7 ** 38 ** D38 + NOT_ON_TIMER, // PG 2 ** 39 ** D39 + NOT_ON_TIMER, // PG 1 ** 40 ** D40 + NOT_ON_TIMER, // PG 0 ** 41 ** D41 + NOT_ON_TIMER, // PL 7 ** 42 ** D42 + NOT_ON_TIMER, // PL 6 ** 43 ** D43 + TIMER5C, // PL 5 ** 44 ** D44 + TIMER5B, // PL 4 ** 45 ** D45 + TIMER5A, // PL 3 ** 46 ** D46 + NOT_ON_TIMER, // PL 2 ** 47 ** D47 + NOT_ON_TIMER, // PL 1 ** 48 ** D48 + NOT_ON_TIMER, // PL 0 ** 49 ** D49 + NOT_ON_TIMER, // PB 3 ** 50 ** SPI_MISO + NOT_ON_TIMER, // PB 2 ** 51 ** SPI_MOSI + NOT_ON_TIMER, // PB 1 ** 52 ** SPI_SCK + NOT_ON_TIMER, // PB 0 ** 53 ** SPI_SS + NOT_ON_TIMER, // PF 0 ** 54 ** A0 + NOT_ON_TIMER, // PF 1 ** 55 ** A1 + NOT_ON_TIMER, // PF 2 ** 56 ** A2 + NOT_ON_TIMER, // PF 3 ** 57 ** A3 + NOT_ON_TIMER, // PF 4 ** 58 ** A4 + NOT_ON_TIMER, // PF 5 ** 59 ** A5 + NOT_ON_TIMER, // PF 6 ** 60 ** A6 + NOT_ON_TIMER, // PF 7 ** 61 ** A7 + NOT_ON_TIMER, // PK 0 ** 62 ** A8 + NOT_ON_TIMER, // PK 1 ** 63 ** A9 + NOT_ON_TIMER, // PK 2 ** 64 ** A10 + NOT_ON_TIMER, // PK 3 ** 65 ** A11 + NOT_ON_TIMER, // PK 4 ** 66 ** A12 + NOT_ON_TIMER, // PK 5 ** 67 ** A13 + NOT_ON_TIMER, // PK 6 ** 68 ** A14 + NOT_ON_TIMER, // PK 7 ** 69 ** A15 + NOT_ON_TIMER, // PG 4 ** 70 ** + NOT_ON_TIMER, // PG 3 ** 71 ** + NOT_ON_TIMER, // PJ 2 ** 72 ** + NOT_ON_TIMER, // PJ 3 ** 73 ** + NOT_ON_TIMER, // PJ 7 ** 74 ** + NOT_ON_TIMER, // PJ 4 ** 75 ** + NOT_ON_TIMER, // PJ 5 ** 76 ** + NOT_ON_TIMER, // PJ 6 ** 77 ** + NOT_ON_TIMER, // PE 2 ** 78 ** + NOT_ON_TIMER, // PE 6 ** 79 ** }; #define digitalPinToTimer_plus_70(P) ( pgm_read_byte( digital_pin_to_timer_PGM_plus_70 + (P) ) ) diff --git a/Marlin/src/HAL/AVR/registers.h b/Marlin/src/HAL/AVR/registers.h index 64c0955c3e..0eac4888cd 100644 --- a/Marlin/src/HAL/AVR/registers.h +++ b/Marlin/src/HAL/AVR/registers.h @@ -93,15 +93,15 @@ namespace AVRHelpers { typedef T type; }; template - struct voltype { + struct voltype { typedef uint8_t type; }; template - struct voltype { + struct voltype { typedef uint16_t type; }; template - struct voltype { + struct voltype { 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__) diff --git a/Marlin/src/HAL/AVR/spi_pins.h b/Marlin/src/HAL/AVR/spi_pins.h index 831972938a..934b6e3b14 100644 --- a/Marlin/src/HAL/AVR/spi_pins.h +++ b/Marlin/src/HAL/AVR/spi_pins.h @@ -23,43 +23,41 @@ /** * Define SPI Pins: SCK, MISO, MOSI, SS + * Platform pins have parentheses, e.g., "(53)", so we cannot use them. */ #if defined(__AVR_ATmega168__) || defined(__AVR_ATmega328__) || defined(__AVR_ATmega328P__) - #define AVR_SCK_PIN 13 - #define AVR_MISO_PIN 12 - #define AVR_MOSI_PIN 11 - #define AVR_SS_PIN 10 + #define _PIN_SPI_SCK 13 + #define _PIN_SPI_MISO 12 + #define _PIN_SPI_MOSI 11 + #define _PIN_SPI_SS 10 #elif defined(__AVR_ATmega644__) || defined(__AVR_ATmega644P__) || defined(__AVR_ATmega644PA__) || defined(__AVR_ATmega1284P__) - #define AVR_SCK_PIN 7 - #define AVR_MISO_PIN 6 - #define AVR_MOSI_PIN 5 - #define AVR_SS_PIN 4 + #define _PIN_SPI_SCK 7 + #define _PIN_SPI_MISO 6 + #define _PIN_SPI_MOSI 5 + #define _PIN_SPI_SS 4 #elif defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) - #define AVR_SCK_PIN 52 - #define AVR_MISO_PIN 50 - #define AVR_MOSI_PIN 51 - #define AVR_SS_PIN 53 + #define _PIN_SPI_SCK 52 + #define _PIN_SPI_MISO 50 + #define _PIN_SPI_MOSI 51 + #define _PIN_SPI_SS 53 #elif defined(__AVR_AT90USB1287__) || defined(__AVR_AT90USB1286__) || defined(__AVR_AT90USB646__) || defined(__AVR_AT90USB647__) - #define AVR_SCK_PIN 21 - #define AVR_MISO_PIN 23 - #define AVR_MOSI_PIN 22 - #define AVR_SS_PIN 20 + #define _PIN_SPI_SCK 21 + #define _PIN_SPI_MISO 23 + #define _PIN_SPI_MOSI 22 + #define _PIN_SPI_SS 20 #elif defined(__AVR_ATmega1281__) || defined(__AVR_ATmega2561__) - #define AVR_SCK_PIN 10 - #define AVR_MISO_PIN 12 - #define AVR_MOSI_PIN 11 - #define AVR_SS_PIN 16 + #define _PIN_SPI_SCK 10 + #define _PIN_SPI_MISO 12 + #define _PIN_SPI_MOSI 11 + #define _PIN_SPI_SS 16 #endif #ifndef SD_SCK_PIN - #define SD_SCK_PIN AVR_SCK_PIN + #define SD_SCK_PIN _PIN_SPI_SCK #endif #ifndef SD_MISO_PIN - #define SD_MISO_PIN AVR_MISO_PIN + #define SD_MISO_PIN _PIN_SPI_MISO #endif #ifndef SD_MOSI_PIN - #define SD_MOSI_PIN AVR_MOSI_PIN -#endif -#ifndef SD_SS_PIN - #define SD_SS_PIN AVR_SS_PIN + #define SD_MOSI_PIN _PIN_SPI_MOSI #endif diff --git a/Marlin/src/HAL/AVR/timers.h b/Marlin/src/HAL/AVR/timers.h index 94b17f3102..1800da0985 100644 --- a/Marlin/src/HAL/AVR/timers.h +++ b/Marlin/src/HAL/AVR/timers.h @@ -28,7 +28,7 @@ // ------------------------ typedef uint16_t hal_timer_t; -#define HAL_TIMER_TYPE_MAX 0xFFFF +#define HAL_TIMER_TYPE_MAX hal_timer_t(UINT16_MAX) // ------------------------ // Defines @@ -46,15 +46,14 @@ typedef uint16_t hal_timer_t; #define MF_TIMER_TEMP 0 #endif -#define TEMP_TIMER_FREQUENCY (((F_CPU) + 0x2000) / 0x4000) +#define TEMP_TIMER_FREQUENCY (((F_CPU) + 0x2000) / 0x4000) -#define STEPPER_TIMER_RATE HAL_TIMER_RATE -#define STEPPER_TIMER_PRESCALE 8 -#define STEPPER_TIMER_TICKS_PER_US ((STEPPER_TIMER_RATE) / 1000000) +#define STEPPER_TIMER_RATE HAL_TIMER_RATE +#define STEPPER_TIMER_PRESCALE 8 +#define STEPPER_TIMER_TICKS_PER_US ((STEPPER_TIMER_RATE) / 1000000UL) // (MHz) Stepper Timer ticks per µs -#define PULSE_TIMER_RATE STEPPER_TIMER_RATE -#define PULSE_TIMER_PRESCALE STEPPER_TIMER_PRESCALE -#define PULSE_TIMER_TICKS_PER_US STEPPER_TIMER_TICKS_PER_US +#define PULSE_TIMER_RATE STEPPER_TIMER_RATE // (Hz) Frequency of Pulse Timer +#define PULSE_TIMER_PRESCALE STEPPER_TIMER_PRESCALE #define ENABLE_STEPPER_DRIVER_INTERRUPT() SBI(TIMSK1, OCIE1A) #define DISABLE_STEPPER_DRIVER_INTERRUPT() CBI(TIMSK1, OCIE1A) @@ -111,8 +110,8 @@ FORCE_INLINE void HAL_timer_start(const uint8_t timer_num, const uint32_t) { * (otherwise, characters will be lost due to UART overflow). * Then: Stepper, Endstops, Temperature, and -finally- all others. */ -#define HAL_timer_isr_prologue(T) NOOP -#define HAL_timer_isr_epilogue(T) NOOP +inline void HAL_timer_isr_prologue(const uint8_t) {} +inline void HAL_timer_isr_epilogue(const uint8_t) {} #ifndef HAL_STEP_TIMER_ISR diff --git a/Marlin/src/HAL/AVR/u8g_com_HAL_AVR_sw_spi.cpp b/Marlin/src/HAL/AVR/u8g/u8g_com_HAL_AVR_sw_spi.cpp similarity index 98% rename from Marlin/src/HAL/AVR/u8g_com_HAL_AVR_sw_spi.cpp rename to Marlin/src/HAL/AVR/u8g/u8g_com_HAL_AVR_sw_spi.cpp index 9617c9544d..f4fa1eb428 100644 --- a/Marlin/src/HAL/AVR/u8g_com_HAL_AVR_sw_spi.cpp +++ b/Marlin/src/HAL/AVR/u8g/u8g_com_HAL_AVR_sw_spi.cpp @@ -55,12 +55,12 @@ #if defined(ARDUINO) && !defined(ARDUINO_ARCH_STM32) && !defined(ARDUINO_ARCH_SAM) -#include "../../inc/MarlinConfigPre.h" +#include "../../../inc/MarlinConfigPre.h" #if HAS_MARLINUI_U8GLIB -#include "../shared/Marduino.h" -#include "../shared/Delay.h" +#include "../../shared/Marduino.h" +#include "../../shared/Delay.h" #include diff --git a/Marlin/src/HAL/DUE/HAL.cpp b/Marlin/src/HAL/DUE/HAL.cpp index 763091cb00..19a174259a 100644 --- a/Marlin/src/HAL/DUE/HAL.cpp +++ b/Marlin/src/HAL/DUE/HAL.cpp @@ -27,7 +27,6 @@ #ifdef ARDUINO_ARCH_SAM #include "../../inc/MarlinConfig.h" -#include "../../MarlinCore.h" #include #include "usb/usb_task.h" @@ -48,7 +47,7 @@ uint16_t MarlinHAL::adc_result; void MarlinHAL::init() { #if HAS_MEDIA - OUT_WRITE(SDSS, HIGH); // Try to set SDSS inactive before any other SPI users start up + OUT_WRITE(SD_SS_PIN, HIGH); // Try to set SDSS inactive before any other SPI users start up #endif usb_task_init(); // Initialize the USB stack TERN_(POSTMORTEM_DEBUGGING, install_min_serial()); // Install the min serial handler @@ -102,6 +101,10 @@ void watchdogSetup() { #if ENABLED(USE_WATCHDOG) + #ifndef WATCHDOG_PIO_RESET + #define WATCHDOG_PIO_RESET + #endif + // 4 seconds timeout uint32_t timeout = TERN(WATCHDOG_DURATION_8S, 8000, 4000); @@ -115,15 +118,16 @@ void watchdogSetup() { timeout = 0xFFF; // We want to enable the watchdog with the specified timeout - uint32_t value = - WDT_MR_WDV(timeout) | // With the specified timeout - WDT_MR_WDD(timeout) | // and no invalid write window - #if !(SAMV70 || SAMV71 || SAME70 || SAMS70) - WDT_MR_WDRPROC | // WDT fault resets processor only - We want - // to keep PIO controller state - #endif - WDT_MR_WDDBGHLT | // WDT stops in debug state. - WDT_MR_WDIDLEHLT; // WDT stops in idle state. + uint32_t value = (0 + | WDT_MR_WDV(timeout) // With the specified timeout + | WDT_MR_WDD(timeout) // and no invalid write window + #if NONE(WATCHDOG_PIO_RESET, SAMV70, SAMV71, SAME70, SAMS70) + | WDT_MR_WDRPROC // WDT fault resets processor only with this flag. + // Omit to also reset the PIO controller. + #endif + | WDT_MR_WDDBGHLT // WDT stops in debug state. + | WDT_MR_WDIDLEHLT // WDT stops in idle state. + ); #if ENABLED(WATCHDOG_RESET_MANUAL) // We enable the watchdog timer, but only for the interrupt. diff --git a/Marlin/src/HAL/DUE/HAL.h b/Marlin/src/HAL/DUE/HAL.h index 9d00d9d11d..f83668ca9d 100644 --- a/Marlin/src/HAL/DUE/HAL.h +++ b/Marlin/src/HAL/DUE/HAL.h @@ -35,67 +35,9 @@ #include -#include "../../core/serial_hook.h" - -// ------------------------ -// Serial ports -// ------------------------ - -typedef ForwardSerial1Class< decltype(Serial) > DefaultSerial1; -typedef ForwardSerial1Class< decltype(Serial1) > DefaultSerial2; -typedef ForwardSerial1Class< decltype(Serial2) > DefaultSerial3; -typedef ForwardSerial1Class< decltype(Serial3) > DefaultSerial4; -extern DefaultSerial1 MSerial0; -extern DefaultSerial2 MSerial1; -extern DefaultSerial3 MSerial2; -extern DefaultSerial4 MSerial3; - -#define _MSERIAL(X) MSerial##X -#define MSERIAL(X) _MSERIAL(X) - -#if SERIAL_PORT == -1 || ENABLED(EMERGENCY_PARSER) - #define MYSERIAL1 customizedSerial1 -#elif WITHIN(SERIAL_PORT, 0, 3) - #define MYSERIAL1 MSERIAL(SERIAL_PORT) -#else - #error "The required SERIAL_PORT must be from 0 to 3, or -1 for USB Serial." -#endif - -#ifdef SERIAL_PORT_2 - #if SERIAL_PORT_2 == -1 || ENABLED(EMERGENCY_PARSER) - #define MYSERIAL2 customizedSerial2 - #elif WITHIN(SERIAL_PORT_2, 0, 3) - #define MYSERIAL2 MSERIAL(SERIAL_PORT_2) - #else - #error "SERIAL_PORT_2 must be from 0 to 3, or -1 for USB Serial." - #endif -#endif - -#ifdef SERIAL_PORT_3 - #if SERIAL_PORT_3 == -1 || ENABLED(EMERGENCY_PARSER) - #define MYSERIAL3 customizedSerial3 - #elif WITHIN(SERIAL_PORT_3, 0, 3) - #define MYSERIAL3 MSERIAL(SERIAL_PORT_3) - #else - #error "SERIAL_PORT_3 must be from 0 to 3, or -1 for USB Serial." - #endif -#endif - -#ifdef MMU_SERIAL_PORT - #if WITHIN(MMU_SERIAL_PORT, 0, 3) - #define MMU_SERIAL MSERIAL(MMU_SERIAL_PORT) - #else - #error "MMU_SERIAL_PORT must be from 0 to 3." - #endif -#endif - -#ifdef LCD_SERIAL_PORT - #if WITHIN(LCD_SERIAL_PORT, 0, 3) - #define LCD_SERIAL MSERIAL(LCD_SERIAL_PORT) - #else - #error "LCD_SERIAL_PORT must be from 0 to 3." - #endif -#endif +// +// Serial Ports +// #include "MarlinSerial.h" #include "MarlinSerialUSB.h" @@ -190,7 +132,7 @@ public: static void delay_ms(const int ms) { delay(ms); } - // Tasks, called from idle() + // Tasks, called from marlin.idle() static void idletask(); // Reset diff --git a/Marlin/src/HAL/DUE/HAL_SPI.cpp b/Marlin/src/HAL/DUE/HAL_SPI.cpp index c2fabb0d49..e44549357e 100644 --- a/Marlin/src/HAL/DUE/HAL_SPI.cpp +++ b/Marlin/src/HAL/DUE/HAL_SPI.cpp @@ -208,8 +208,8 @@ A("str %[sck_mask],[%[sck_port],#0x4]") /* CODR */ A("bfi %[bin],%[work],#0,#1") /* Store read bit as the bit 0 */ - : [bin]"+r"(bin), - [work]"+r"(work) + : [bin]"+r"( bin ), + [work]"+r"( work ) : [bitband_miso_port]"r"( BITBAND_MISO_PORT ), [sck_mask]"r"( SCK_MASK ), [sck_port]"r"( SCK_PORT_PLUS30 ) @@ -350,7 +350,7 @@ static void spiRxBlock0(uint8_t *ptr, uint32_t todo) { uint32_t bin = 0; uint32_t work = 0; - uint32_t BITBAND_MISO_PORT = BITBAND_ADDRESS( ((uint32_t)PORT(SD_MISO_PIN))+0x3C, PIN_SHIFT(SD_MISO_PIN)); /* PDSR of port in bitband area */ + uint32_t BITBAND_MISO_PORT = BITBAND_ADDRESS(((uint32_t)PORT(SD_MISO_PIN))+0x3C, PIN_SHIFT(SD_MISO_PIN)); /* PDSR of port in bitband area */ uint32_t SCK_PORT_PLUS30 = ((uint32_t) PORT(SD_SCK_PIN)) + 0x30; /* SODR of port */ uint32_t SCK_MASK = PIN_MASK(SD_SCK_PIN); @@ -412,10 +412,10 @@ A("strb.w %[bin], [%[ptr]], #1") /* Store read value into buffer, increment buffer pointer */ A("bne.n loop%=") /* Repeat until done */ - : [ptr]"+r"(ptr), - [todo]"+r"(todo), - [bin]"+r"(bin), - [work]"+r"(work) + : [ptr]"+r"( ptr ), + [todo]"+r"( todo ), + [bin]"+r"( bin ), + [work]"+r"( work ) : [bitband_miso_port]"r"( BITBAND_MISO_PORT ), [sck_mask]"r"( SCK_MASK ), [sck_port]"r"( SCK_PORT_PLUS30 ) @@ -600,9 +600,8 @@ OUT_WRITE(SPI_EEPROM1_CS_PIN, HIGH); OUT_WRITE(SPI_EEPROM2_CS_PIN, HIGH); OUT_WRITE(SPI_FLASH_CS_PIN, HIGH); - WRITE(SD_SS_PIN, HIGH); - - OUT_WRITE(SDSS, LOW); + OUT_WRITE(SD_SS_PIN, HIGH); + WRITE(SD_SS_PIN, LOW); PIO_Configure( g_APinDescription[SPI_PIN].pPort, @@ -767,7 +766,7 @@ // Disable PIO on A26 and A27 REG_PIOA_PDR = 0x0C000000; - OUT_WRITE(SDSS, HIGH); + OUT_WRITE(SD_SS_PIN, HIGH); // Reset SPI0 (from sam lib) SPI0->SPI_CR = SPI_CR_SPIDIS; diff --git a/Marlin/src/HAL/DUE/MarlinSerial.cpp b/Marlin/src/HAL/DUE/MarlinSerial.cpp index 90efe55fc2..2e80b4c8d1 100644 --- a/Marlin/src/HAL/DUE/MarlinSerial.cpp +++ b/Marlin/src/HAL/DUE/MarlinSerial.cpp @@ -31,7 +31,6 @@ #include "MarlinSerial.h" #include "InterruptVectors.h" -#include "../../MarlinCore.h" template typename MarlinSerial::ring_buffer_r MarlinSerial::rx_buffer = { 0, 0, { 0 } }; template typename MarlinSerial::ring_buffer_t MarlinSerial::tx_buffer = { 0 }; diff --git a/Marlin/src/HAL/DUE/MarlinSerial.h b/Marlin/src/HAL/DUE/MarlinSerial.h index b80ae21823..cee0857d2b 100644 --- a/Marlin/src/HAL/DUE/MarlinSerial.h +++ b/Marlin/src/HAL/DUE/MarlinSerial.h @@ -33,6 +33,21 @@ #include "../../core/types.h" #include "../../core/serial_hook.h" +typedef ForwardSerial1Class< decltype(Serial) > DefaultSerial1; +typedef ForwardSerial1Class< decltype(Serial1) > DefaultSerial2; +typedef ForwardSerial1Class< decltype(Serial2) > DefaultSerial3; +typedef ForwardSerial1Class< decltype(Serial3) > DefaultSerial4; +extern DefaultSerial1 MSerial0; +extern DefaultSerial2 MSerial1; +extern DefaultSerial3 MSerial2; +extern DefaultSerial4 MSerial3; + +#define SERIAL_INDEX_MIN 0 +#define SERIAL_INDEX_MAX 3 +#define EP_SERIAL_PORT(N) customizedSerial##N +#define USB_SERIAL_PORT(N) customizedSerial##N +#include "../shared/serial_ports.h" + // Define constants and variables for buffering incoming serial data. We're // using a ring buffer (I think), in which rx_buffer_head is the index of the // location to which to write the next incoming character and rx_buffer_tail diff --git a/Marlin/src/HAL/DUE/eeprom_flash.cpp b/Marlin/src/HAL/DUE/eeprom/eeprom_flash.cpp similarity index 99% rename from Marlin/src/HAL/DUE/eeprom_flash.cpp rename to Marlin/src/HAL/DUE/eeprom/eeprom_flash.cpp index 55206a0f9d..b33d15e106 100644 --- a/Marlin/src/HAL/DUE/eeprom_flash.cpp +++ b/Marlin/src/HAL/DUE/eeprom/eeprom_flash.cpp @@ -21,7 +21,7 @@ */ #ifdef ARDUINO_ARCH_SAM -#include "../../inc/MarlinConfig.h" +#include "../../../inc/MarlinConfig.h" #if ENABLED(FLASH_EEPROM_EMULATION) @@ -132,7 +132,7 @@ static uint8_t buffer[256] = {0}, // The RAM buffer to accumulate writes curGroup = 0xFF; // Current FLASH group #define DEBUG_OUT ENABLED(EE_EMU_DEBUG) -#include "../../core/debug_out.h" +#include "../../../core/debug_out.h" static void ee_Dump(const int page, const void *data) { @@ -953,7 +953,7 @@ static void ee_Init() { /* PersistentStore -----------------------------------------------------------*/ -#include "../shared/eeprom_api.h" +#include "../../shared/eeprom_api.h" #ifndef MARLIN_EEPROM_SIZE #define MARLIN_EEPROM_SIZE 0x1000 // 4KB diff --git a/Marlin/src/HAL/DUE/eeprom_wired.cpp b/Marlin/src/HAL/DUE/eeprom/eeprom_wired.cpp similarity index 95% rename from Marlin/src/HAL/DUE/eeprom_wired.cpp rename to Marlin/src/HAL/DUE/eeprom/eeprom_wired.cpp index 84338ccb4b..cf9233816c 100644 --- a/Marlin/src/HAL/DUE/eeprom_wired.cpp +++ b/Marlin/src/HAL/DUE/eeprom/eeprom_wired.cpp @@ -21,7 +21,7 @@ */ #ifdef ARDUINO_ARCH_SAM -#include "../../inc/MarlinConfig.h" +#include "../../../inc/MarlinConfig.h" #if USE_WIRED_EEPROM @@ -30,8 +30,8 @@ * with simple implementations supplied by Marlin. */ -#include "../shared/eeprom_if.h" -#include "../shared/eeprom_api.h" +#include "../../shared/eeprom_if.h" +#include "../../shared/eeprom_api.h" #ifndef MARLIN_EEPROM_SIZE #error "MARLIN_EEPROM_SIZE is required for I2C / SPI EEPROM." diff --git a/Marlin/src/HAL/DUE/fastio/G2_PWM.cpp b/Marlin/src/HAL/DUE/fastio/G2_PWM.cpp index 5cf86f147c..745e4205bc 100644 --- a/Marlin/src/HAL/DUE/fastio/G2_PWM.cpp +++ b/Marlin/src/HAL/DUE/fastio/G2_PWM.cpp @@ -40,11 +40,12 @@ * Some jitter in the Vref signal is OK so the interrupt priority is left at its default value. */ -#include "../../../inc/MarlinConfig.h" +#include "../../../inc/MarlinConfigPre.h" #if MB(PRINTRBOARD_G2) #include "G2_PWM.h" +#include "../../../module/stepper.h" #if PIN_EXISTS(MOTOR_CURRENT_PWM_X) #define G2_PWM_X 1 @@ -56,16 +57,12 @@ #else #define G2_PWM_Y 0 #endif -#if PIN_EXISTS(MOTOR_CURRENT_PWM_Z) +#if HAS_MOTOR_CURRENT_PWM_Z #define G2_PWM_Z 1 #else #define G2_PWM_Z 0 #endif -#if HAS_MOTOR_CURRENT_PWM_E - #define G2_PWM_E 1 -#else - #define G2_PWM_E 0 -#endif +#define G2_PWM_E HAS_MOTOR_CURRENT_PWM_E #define G2_MASK_X(V) (G2_PWM_X * (V)) #define G2_MASK_Y(V) (G2_PWM_Y * (V)) #define G2_MASK_Z(V) (G2_PWM_Z * (V)) @@ -80,17 +77,22 @@ PWM_map ISR_table[NUM_PWMS] = PWM_MAP_INIT; void Stepper::digipot_init() { - #if PIN_EXISTS(MOTOR_CURRENT_PWM_X) - OUT_WRITE(MOTOR_CURRENT_PWM_X_PIN, 0); // init pins + #if G2_PWM_X + OUT_WRITE(MOTOR_CURRENT_PWM_X_PIN, LOW); // init pins #endif - #if PIN_EXISTS(MOTOR_CURRENT_PWM_Y) - OUT_WRITE(MOTOR_CURRENT_PWM_Y_PIN, 0); + #if G2_PWM_Y + OUT_WRITE(MOTOR_CURRENT_PWM_Y_PIN, LOW); #endif #if G2_PWM_Z - OUT_WRITE(MOTOR_CURRENT_PWM_Z_PIN, 0); + OUT_WRITE(MOTOR_CURRENT_PWM_Z_PIN, LOW); #endif #if G2_PWM_E - OUT_WRITE(MOTOR_CURRENT_PWM_E_PIN, 0); + #if PIN_EXISTS(MOTOR_CURRENT_PWM_E) + OUT_WRITE(MOTOR_CURRENT_PWM_E_PIN, LOW); + #endif + #if PIN_EXISTS(MOTOR_CURRENT_PWM_E0) + OUT_WRITE(MOTOR_CURRENT_PWM_E0_PIN, LOW); + #endif #endif #define WPKEY (0x50574D << 8) // “PWM” in ASCII diff --git a/Marlin/src/HAL/DUE/fastio/G2_PWM.h b/Marlin/src/HAL/DUE/fastio/G2_PWM.h index 054eb2cf80..7fb2aaf7a8 100644 --- a/Marlin/src/HAL/DUE/fastio/G2_PWM.h +++ b/Marlin/src/HAL/DUE/fastio/G2_PWM.h @@ -26,10 +26,7 @@ * PR #7500. It is hardwired for the PRINTRBOARD_G2 Motor Current needs. */ -#include "../../../inc/MarlinConfigPre.h" -#include "../../../module/stepper.h" -//C:\Users\bobku\Documents\GitHub\Marlin-Bob-2\Marlin\src\module\stepper.h -//C:\Users\bobku\Documents\GitHub\Marlin-Bob-2\Marlin\src\HAL\HAL_DUE\G2_PWM.h +#include #define PWM_PERIOD_US 100 // base repetition rate in micro seconds diff --git a/Marlin/src/HAL/DUE/spi_pins.h b/Marlin/src/HAL/DUE/spi_pins.h index 7f0b1290b1..e289c8ced2 100644 --- a/Marlin/src/HAL/DUE/spi_pins.h +++ b/Marlin/src/HAL/DUE/spi_pins.h @@ -26,39 +26,36 @@ * * Available chip select pins for HW SPI are 4 10 52 77 87 */ -#if SDSS == 4 || SDSS == 10 || SDSS == 52 || SDSS == 77 || SDSS == 87 - #if SDSS == 4 - #define SPI_PIN 87 - #define SPI_CHAN 1 - #elif SDSS == 10 - #define SPI_PIN 77 - #define SPI_CHAN 0 - #elif SDSS == 52 - #define SPI_PIN 86 - #define SPI_CHAN 2 - #elif SDSS == 77 - #define SPI_PIN 77 - #define SPI_CHAN 0 - #else - #define SPI_PIN 87 - #define SPI_CHAN 1 - #endif - #define SD_SCK_PIN 76 - #define SD_MISO_PIN 74 - #define SD_MOSI_PIN 75 -#else - // defaults - #define SOFTWARE_SPI - #ifndef SD_SCK_PIN - #define SD_SCK_PIN 52 - #endif - #ifndef SD_MISO_PIN - #define SD_MISO_PIN 50 - #endif - #ifndef SD_MOSI_PIN - #define SD_MOSI_PIN 51 - #endif +#if SD_SS_PIN == 4 || SD_SS_PIN == 10 || SD_SS_PIN == 52 || SD_SS_PIN == 77 || SD_SS_PIN == 87 + #define SD_SCK_PIN 76 + #define SD_MISO_PIN 74 + #define SD_MOSI_PIN 75 #endif -/* A.28, A.29, B.21, C.26, C.29 */ -#define SD_SS_PIN SDSS +#if SD_SS_PIN == 4 + #define SPI_PIN 87 + #define SPI_CHAN 1 +#elif SD_SS_PIN == 10 + #define SPI_PIN 77 + #define SPI_CHAN 0 +#elif SD_SS_PIN == 52 + #define SPI_PIN 86 + #define SPI_CHAN 2 +#elif SD_SS_PIN == 77 + #define SPI_PIN 77 + #define SPI_CHAN 0 +#elif SD_SS_PIN == 87 + #define SPI_PIN 87 + #define SPI_CHAN 1 +#else + #define SOFTWARE_SPI + #ifndef SD_SCK_PIN + #define SD_SCK_PIN 52 + #endif + #ifndef SD_MISO_PIN + #define SD_MISO_PIN 50 + #endif + #ifndef SD_MOSI_PIN + #define SD_MOSI_PIN 51 + #endif +#endif diff --git a/Marlin/src/HAL/DUE/timers.h b/Marlin/src/HAL/DUE/timers.h index db5d83a06f..f892eac8f5 100644 --- a/Marlin/src/HAL/DUE/timers.h +++ b/Marlin/src/HAL/DUE/timers.h @@ -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 hal_timer_t(UINT32_MAX) #define HAL_TIMER_PRESCALER 2 #define HAL_TIMER_RATE ((F_CPU) / (HAL_TIMER_PRESCALER)) // frequency of timers peripherals @@ -52,19 +52,18 @@ typedef uint32_t hal_timer_t; #define MF_TIMER_TONE 6 // index of timer to use for beeper tones #endif -#define TEMP_TIMER_FREQUENCY 1000 // temperature interrupt frequency +#define TEMP_TIMER_FREQUENCY 1000 // (Hz) Temperature ISR 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_RATE HAL_TIMER_RATE // (Hz) Frequency of Stepper Timer ISR (HAL_TIMER_RATE / STEPPER_TIMER_PRESCALE) +#define STEPPER_TIMER_TICKS_PER_US ((STEPPER_TIMER_RATE) / 1000000UL) // (MHz) 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 +#define PULSE_TIMER_RATE STEPPER_TIMER_RATE // (Hz) Frequency of Pulse Timer #define PULSE_TIMER_PRESCALE STEPPER_TIMER_PRESCALE -#define PULSE_TIMER_TICKS_PER_US STEPPER_TIMER_TICKS_PER_US -#define ENABLE_STEPPER_DRIVER_INTERRUPT() HAL_timer_enable_interrupt(MF_TIMER_STEP) +#define ENABLE_STEPPER_DRIVER_INTERRUPT() HAL_timer_enable_interrupt(MF_TIMER_STEP) #define DISABLE_STEPPER_DRIVER_INTERRUPT() HAL_timer_disable_interrupt(MF_TIMER_STEP) -#define STEPPER_ISR_ENABLED() HAL_timer_interrupt_enabled(MF_TIMER_STEP) +#define STEPPER_ISR_ENABLED() HAL_timer_interrupt_enabled(MF_TIMER_STEP) #define ENABLE_TEMPERATURE_INTERRUPT() HAL_timer_enable_interrupt(MF_TIMER_TEMP) #define DISABLE_TEMPERATURE_INTERRUPT() HAL_timer_disable_interrupt(MF_TIMER_TEMP) @@ -127,4 +126,4 @@ FORCE_INLINE static void HAL_timer_isr_prologue(const uint8_t timer_num) { pConfig->pTimerRegs->TC_CHANNEL[pConfig->channel].TC_SR; } -#define HAL_timer_isr_epilogue(T) NOOP +inline void HAL_timer_isr_epilogue(const uint8_t) {} diff --git a/Marlin/src/HAL/DUE/usb/.editorconfig b/Marlin/src/HAL/DUE/usb/.editorconfig new file mode 100644 index 0000000000..f2c26de5ee --- /dev/null +++ b/Marlin/src/HAL/DUE/usb/.editorconfig @@ -0,0 +1,5 @@ +# editorconfig.org + +[{*.c,*.cpp,*.h}] +indent_style = tab +indent_size = 4 diff --git a/Marlin/src/HAL/DUE/usb/ctrl_access.c b/Marlin/src/HAL/DUE/usb/ctrl_access.c index b766ed1273..ec0e4adc4b 100644 --- a/Marlin/src/HAL/DUE/usb/ctrl_access.c +++ b/Marlin/src/HAL/DUE/usb/ctrl_access.c @@ -63,8 +63,8 @@ #include "compiler.h" #include "preprocessor.h" #ifdef FREERTOS_USED -#include "FreeRTOS.h" -#include "semphr.h" +#include +#include #endif #include "ctrl_access.h" diff --git a/Marlin/src/HAL/DUE/usb/sd_mmc_spi_mem.cpp b/Marlin/src/HAL/DUE/usb/sd_mmc_spi_mem.cpp index cf6739c5bd..74cfd9b39b 100644 --- a/Marlin/src/HAL/DUE/usb/sd_mmc_spi_mem.cpp +++ b/Marlin/src/HAL/DUE/usb/sd_mmc_spi_mem.cpp @@ -19,7 +19,7 @@ void sd_mmc_spi_mem_init() { } inline bool media_ready() { - return IS_SD_MOUNTED() && IS_SD_INSERTED() && !IS_SD_FILE_OPEN() && !IS_SD_PRINTING(); + return card.isMounted() && card.isInserted() && !card.isFileOpen() && !card.isStillPrinting(); } bool sd_mmc_spi_unload(bool) { return true; } @@ -29,11 +29,10 @@ bool sd_mmc_spi_wr_protect() { return false; } bool sd_mmc_spi_removal() { return !media_ready(); } Ctrl_status sd_mmc_spi_test_unit_ready() { - #ifdef DISABLE_DUE_SD_MMC + #if ENABLED(DISABLE_DUE_SD_MMC) return CTRL_NO_PRESENT; #endif - if (sd_mmc_spi_removal()) return CTRL_NO_PRESENT; - return CTRL_GOOD; + return sd_mmc_spi_removal() ? CTRL_NO_PRESENT : CTRL_GOOD; } // NOTE: This function is defined as returning the address of the last block @@ -58,9 +57,10 @@ uint8_t sector_buf[SD_MMC_BLOCK_SIZE]; // #define DEBUG_MMC Ctrl_status sd_mmc_spi_usb_read_10(uint32_t addr, uint16_t nb_sector) { - #ifdef DISABLE_DUE_SD_MMC + #if ENABLED(DISABLE_DUE_SD_MMC) return CTRL_NO_PRESENT; #endif + if (sd_mmc_spi_removal()) return CTRL_NO_PRESENT; #ifdef DEBUG_MMC @@ -97,9 +97,10 @@ Ctrl_status sd_mmc_spi_usb_read_10(uint32_t addr, uint16_t nb_sector) { } Ctrl_status sd_mmc_spi_usb_write_10(uint32_t addr, uint16_t nb_sector) { - #ifdef DISABLE_DUE_SD_MMC + #if ENABLED(DISABLE_DUE_SD_MMC) return CTRL_NO_PRESENT; #endif + if (sd_mmc_spi_removal()) return CTRL_NO_PRESENT; #ifdef DEBUG_MMC diff --git a/Marlin/src/HAL/DUE/usb/udc.h b/Marlin/src/HAL/DUE/usb/udc.h index aba08d956e..e8c0e7fbea 100644 --- a/Marlin/src/HAL/DUE/usb/udc.h +++ b/Marlin/src/HAL/DUE/usb/udc.h @@ -229,7 +229,7 @@ usb_iface_desc_t UDC_DESC_STORAGE *udc_get_interface_desc(void); * - USB Device Controller (UDC) provides USB chapter 9 compliance * - USB Device Interface (UDI) provides USB Class compliance * - USB Device Driver (UDD) provides USB Driver for each Atmel MCU - + * * Many USB Device applications can be implemented on Atmel MCU. * Atmel provides many application notes for different applications: * - AVR4900, provides general information about Device Stack diff --git a/Marlin/src/HAL/DUE/usb/uotghs_device_due.c b/Marlin/src/HAL/DUE/usb/uotghs_device_due.c index 01dda7e7fe..5635f2ba0c 100644 --- a/Marlin/src/HAL/DUE/usb/uotghs_device_due.c +++ b/Marlin/src/HAL/DUE/usb/uotghs_device_due.c @@ -523,7 +523,7 @@ static bool udd_ep_interrupt(void); * \internal * \brief Function called by UOTGHS interrupt to manage USB Device interrupts * - * USB Device interrupt events are splited in three parts: + * USB Device interrupt events are split in three parts: * - USB line events (SOF, reset, suspend, resume, wakeup) * - control endpoint events (setup reception, end of data transfer, underflow, overflow, stall) * - bulk/interrupt/isochronous endpoints events (end of data transfer) @@ -1567,7 +1567,7 @@ static void udd_ctrl_out_received(void) udd_ctrl_payload_buf_cnt))) { // End of reception because it is a short packet // Before send ZLP, call intermediate callback - // in case of data receiv generate a stall + // in case of data receive generate a stall udd_g_ctrlreq.payload_size = udd_ctrl_payload_buf_cnt; if (NULL != udd_g_ctrlreq.over_under_run) { if (!udd_g_ctrlreq.over_under_run()) { @@ -1808,7 +1808,7 @@ static void udd_ep_trans_done(udd_ep_id_t ep) } if (ptr_job->buf_cnt != ptr_job->buf_size) { - // Need to send or receiv other data + // Need to send or receive other data next_trans = ptr_job->buf_size - ptr_job->buf_cnt; if (UDD_ENDPOINT_MAX_TRANS < next_trans) { diff --git a/Marlin/src/HAL/ESP32/HAL.cpp b/Marlin/src/HAL/ESP32/HAL.cpp index 415e2510e2..acfec29b2f 100644 --- a/Marlin/src/HAL/ESP32/HAL.cpp +++ b/Marlin/src/HAL/ESP32/HAL.cpp @@ -34,13 +34,13 @@ #if ENABLED(WIFISUPPORT) #include - #include "wifi.h" + #include "wifi/wifi.h" #if ENABLED(OTASUPPORT) - #include "ota.h" + #include "wifi/ota.h" #endif #if ENABLED(WEBSUPPORT) - #include "spiffs.h" - #include "web.h" + #include "wifi/spiffs.h" + #include "wifi/web.h" #endif #endif @@ -175,8 +175,6 @@ uint8_t MarlinHAL::get_reset_source() { return rtc_get_reset_reason(1); } void MarlinHAL::reboot() { ESP.restart(); } -void _delay_ms(const int ms) { delay(ms); } - // return free memory between end of heap (or end bss) and whatever is current int MarlinHAL::freeMemory() { return ESP.getFreeHeap(); } @@ -244,12 +242,13 @@ void MarlinHAL::adc_init() { TERN_(HAS_TEMP_ADC_5, adc1_set_attenuation(get_channel(TEMP_5_PIN), ADC_ATTEN_11db)); TERN_(HAS_TEMP_ADC_6, adc2_set_attenuation(get_channel(TEMP_6_PIN), ADC_ATTEN_11db)); TERN_(HAS_TEMP_ADC_7, adc3_set_attenuation(get_channel(TEMP_7_PIN), ADC_ATTEN_11db)); - TERN_(HAS_HEATED_BED, adc1_set_attenuation(get_channel(TEMP_BED_PIN), ADC_ATTEN_11db)); - TERN_(HAS_TEMP_CHAMBER, adc1_set_attenuation(get_channel(TEMP_CHAMBER_PIN), ADC_ATTEN_11db)); - TERN_(HAS_TEMP_PROBE, adc1_set_attenuation(get_channel(TEMP_PROBE_PIN), ADC_ATTEN_11db)); - TERN_(HAS_TEMP_COOLER, adc1_set_attenuation(get_channel(TEMP_COOLER_PIN), ADC_ATTEN_11db)); - TERN_(HAS_TEMP_BOARD, adc1_set_attenuation(get_channel(TEMP_BOARD_PIN), ADC_ATTEN_11db)); - TERN_(FILAMENT_WIDTH_SENSOR, adc1_set_attenuation(get_channel(FILWIDTH_PIN), ADC_ATTEN_11db)); + TERN_(HAS_TEMP_ADC_BED, adc1_set_attenuation(get_channel(TEMP_BED_PIN), ADC_ATTEN_11db)); + TERN_(HAS_TEMP_ADC_CHAMBER, adc1_set_attenuation(get_channel(TEMP_CHAMBER_PIN), ADC_ATTEN_11db)); + TERN_(HAS_TEMP_ADC_PROBE, adc1_set_attenuation(get_channel(TEMP_PROBE_PIN), ADC_ATTEN_11db)); + TERN_(HAS_TEMP_ADC_COOLER, adc1_set_attenuation(get_channel(TEMP_COOLER_PIN), ADC_ATTEN_11db)); + TERN_(HAS_TEMP_ADC_BOARD, adc1_set_attenuation(get_channel(TEMP_BOARD_PIN), ADC_ATTEN_11db)); + TERN_(HAS_FILWIDTH_ADC, adc1_set_attenuation(get_channel(FILWIDTH_PIN), ADC_ATTEN_11db)); + TERN_(HAS_FILWIDTH2_ADC, adc1_set_attenuation(get_channel(FILWIDTH2_PIN), ADC_ATTEN_11db)); // Note that adc2 is shared with the WiFi module, which has higher priority, so the conversion may fail. // That's why we're not setting it up here. @@ -272,7 +271,7 @@ void MarlinHAL::adc_start(const pin_t pin) { uint32_t mv; esp_adc_cal_get_voltage((adc_channel_t)chan, &characteristics[attenuations[chan]], &mv); - adc_result = mv * isr_float_t(1023) / isr_float_t(ADC_REFERENCE_VOLTAGE) / isr_float_t(1000); + adc_result = (mv * 1023) * (1000.f / (ADC_REFERENCE_VOLTAGE)); // Change the attenuation level based on the new reading adc_atten_t atten; diff --git a/Marlin/src/HAL/ESP32/HAL.h b/Marlin/src/HAL/ESP32/HAL.h index 0acb3676a2..f48eabea0d 100644 --- a/Marlin/src/HAL/ESP32/HAL.h +++ b/Marlin/src/HAL/ESP32/HAL.h @@ -37,11 +37,11 @@ #include "i2s.h" #if ENABLED(WIFISUPPORT) - #include "WebSocketSerial.h" + #include "wifi/WebSocketSerial.h" #endif #if ENABLED(ESP3D_WIFISUPPORT) - #include "esp3dlib.h" + #include #endif #include "FlushableHardwareSerial.h" @@ -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 @@ -76,7 +76,6 @@ // Types // ------------------------ -typedef double isr_float_t; // FPU ops are used for single-precision, so use double for ISRs. typedef int16_t pin_t; typedef struct pwm_pin { @@ -165,8 +164,6 @@ int freeMemory(); #pragma GCC diagnostic pop -void _delay_ms(const int ms); - // ------------------------ // MarlinHAL Class // ------------------------ @@ -194,9 +191,9 @@ public: static void isr_on() { if (spinlock.owner != portMUX_FREE_VAL) portEXIT_CRITICAL(&spinlock); } static void isr_off() { portENTER_CRITICAL(&spinlock); } - static void delay_ms(const int ms) { _delay_ms(ms); } + static void delay_ms(const int ms) { delay(ms); } - // Tasks, called from idle() + // Tasks, called from marlin.idle() static void idletask(); // Reset diff --git a/Marlin/src/HAL/ESP32/Servo.cpp b/Marlin/src/HAL/ESP32/Servo.cpp index ca3950d07f..3a2c11832d 100644 --- a/Marlin/src/HAL/ESP32/Servo.cpp +++ b/Marlin/src/HAL/ESP32/Servo.cpp @@ -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. } diff --git a/Marlin/src/HAL/ESP32/i2s.cpp b/Marlin/src/HAL/ESP32/i2s.cpp index 4b17db3daf..f7c01730b3 100644 --- a/Marlin/src/HAL/ESP32/i2s.cpp +++ b/Marlin/src/HAL/ESP32/i2s.cpp @@ -145,7 +145,7 @@ static void IRAM_ATTR i2s_intr_handler_default(void *arg) { void stepperTask(void *parameter) { uint32_t nextMainISR = 0; #if ENABLED(LIN_ADVANCE) - uint32_t nextAdvanceISR = Stepper::LA_ADV_NEVER; + uint32_t nextAdvanceISR = stepper.LA_ADV_NEVER; #endif for (;;) { @@ -156,38 +156,43 @@ void stepperTask(void *parameter) { while (dma.rw_pos < DMA_SAMPLE_COUNT) { - #if ENABLED(FT_MOTION) + if (using_ftMotion) { - if (using_ftMotion) { + #if ENABLED(FT_MOTION) if (!nextMainISR) stepper.ftMotion_stepper(); nextMainISR = 0; - } + #endif - #endif + } + else { - if (!using_ftMotion) { - if (!nextMainISR) { - Stepper::pulse_phase_isr(); - nextMainISR = Stepper::block_phase_isr(); - } - #if ENABLED(LIN_ADVANCE) - else if (!nextAdvanceISR) { - Stepper::advance_isr(); - nextAdvanceISR = Stepper::la_interval; + #if HAS_STANDARD_MOTION + + if (!nextMainISR) { + stepper.pulse_phase_isr(); + nextMainISR = stepper.block_phase_isr(); } - #endif - else - i2s_push_sample(); + #if ENABLED(LIN_ADVANCE) + else if (!nextAdvanceISR) { + stepper.advance_isr(); + nextAdvanceISR = stepper.la_interval; + } + #endif + else + i2s_push_sample(); - nextMainISR--; + nextMainISR--; - #if ENABLED(LIN_ADVANCE) - if (nextAdvanceISR == Stepper::LA_ADV_NEVER) - nextAdvanceISR = Stepper::la_interval; + #if ENABLED(LIN_ADVANCE) + if (nextAdvanceISR == stepper.LA_ADV_NEVER) + nextAdvanceISR = stepper.la_interval; + + if (nextAdvanceISR && nextAdvanceISR != stepper.LA_ADV_NEVER) + nextAdvanceISR--; + #endif + + #endif // HAS_STANDARD_MOTION - if (nextAdvanceISR && nextAdvanceISR != Stepper::LA_ADV_NEVER) - nextAdvanceISR--; - #endif } } } diff --git a/Marlin/src/HAL/ESP32/spi_pins.h b/Marlin/src/HAL/ESP32/spi_pins.h index 58881f0ea7..b50ea725ab 100644 --- a/Marlin/src/HAL/ESP32/spi_pins.h +++ b/Marlin/src/HAL/ESP32/spi_pins.h @@ -21,7 +21,16 @@ */ #pragma once -#define SD_SS_PIN SDSS -#define SD_SCK_PIN 18 -#define SD_MISO_PIN 19 -#define SD_MOSI_PIN 23 +#define PIN_SPI_SCK 18 +#define PIN_SPI_MISO 19 +#define PIN_SPI_MOSI 23 + +#ifndef SD_SCK_PIN + #define SD_SCK_PIN PIN_SPI_SCK +#endif +#ifndef SD_MISO_PIN + #define SD_MISO_PIN PIN_SPI_MISO +#endif +#ifndef SD_MOSI_PIN + #define SD_MOSI_PIN PIN_SPI_MOSI +#endif diff --git a/Marlin/src/HAL/ESP32/timers.cpp b/Marlin/src/HAL/ESP32/timers.cpp index 743ed65f13..a2996a860f 100644 --- a/Marlin/src/HAL/ESP32/timers.cpp +++ b/Marlin/src/HAL/ESP32/timers.cpp @@ -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]; diff --git a/Marlin/src/HAL/ESP32/timers.h b/Marlin/src/HAL/ESP32/timers.h index 3f336fbfc9..d656e92224 100644 --- a/Marlin/src/HAL/ESP32/timers.h +++ b/Marlin/src/HAL/ESP32/timers.h @@ -30,41 +30,45 @@ #define FORCE_INLINE __attribute__((always_inline)) inline typedef uint64_t hal_timer_t; -#define HAL_TIMER_TYPE_MAX 0xFFFFFFFFFFFFFFFFULL +#define HAL_TIMER_TYPE_MAX hal_timer_t(UINT64_MAX) #ifndef MF_TIMER_STEP #define MF_TIMER_STEP 0 // Timer Index for Stepper #endif #ifndef MF_TIMER_PULSE - #define MF_TIMER_PULSE MF_TIMER_STEP + #define MF_TIMER_PULSE MF_TIMER_STEP // Timer Index for Pulse interval #endif #ifndef MF_TIMER_TEMP #define MF_TIMER_TEMP 1 // Timer Index for Temperature #endif #ifndef MF_TIMER_PWM - #define MF_TIMER_PWM 2 // index of timer to use for PWM outputs + #define MF_TIMER_PWM 2 // Timer Index for PWM outputs #endif #ifndef MF_TIMER_TONE - #define MF_TIMER_TONE 3 // index of timer for beeper tones + #define MF_TIMER_TONE 3 // Timer Index for beeper tones #endif -#define HAL_TIMER_RATE APB_CLK_FREQ // frequency of timer peripherals +#define HAL_TIMER_RATE APB_CLK_FREQ // Frequency of timer peripherals + +#define TEMP_TIMER_PRESCALE 1000 // Prescaler for setting Temp Timer, 72Khz +#define TEMP_TIMER_FREQUENCY 1000 // (Hz) Temperature ISR frequency #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 + #define STEPPER_TIMER_TICKS_PER_US 0.25 // (MHz) Stepper Timer ticks per µs #else #define STEPPER_TIMER_PRESCALE 40 - #define STEPPER_TIMER_RATE ((HAL_TIMER_RATE) / (STEPPER_TIMER_PRESCALE)) // frequency of stepper timer, 2MHz + #define STEPPER_TIMER_RATE ((HAL_TIMER_RATE) / (STEPPER_TIMER_PRESCALE)) // (Hz) Frequency of Stepper Timer ISR, 2MHz + #define STEPPER_TIMER_TICKS_PER_US ((STEPPER_TIMER_RATE) / 1'000'000UL) // (MHz) Stepper Timer ticks per µs #endif -#define STEPPER_TIMER_TICKS_PER_US ((STEPPER_TIMER_RATE) / 1000000) // stepper timer ticks per µs #define STEP_TIMER_MIN_INTERVAL 8 // minimum time in µs between stepper interrupts -#define TONE_TIMER_PRESCALE 1000 // Arbitrary value, no idea what i'm doing here +#define PULSE_TIMER_RATE STEPPER_TIMER_RATE // (Hz) Frequency of Pulse Timer +#define PULSE_TIMER_PRESCALE STEPPER_TIMER_PRESCALE -#define TEMP_TIMER_PRESCALE 1000 // prescaler for setting Temp timer, 72Khz -#define TEMP_TIMER_FREQUENCY 1000 // temperature interrupt frequency +#define TONE_TIMER_PRESCALE 1000 // Arbitrary value, no idea what i'm doing here #define PWM_TIMER_PRESCALE 10 #if ENABLED(FAST_PWM_FAN) @@ -74,13 +78,9 @@ typedef uint64_t hal_timer_t; #endif #define MAX_PWM_PINS 32 // Number of PWM pin-slots -#define PULSE_TIMER_RATE STEPPER_TIMER_RATE // frequency of pulse timer -#define PULSE_TIMER_PRESCALE STEPPER_TIMER_PRESCALE -#define PULSE_TIMER_TICKS_PER_US STEPPER_TIMER_TICKS_PER_US - -#define ENABLE_STEPPER_DRIVER_INTERRUPT() HAL_timer_enable_interrupt(MF_TIMER_STEP) +#define ENABLE_STEPPER_DRIVER_INTERRUPT() HAL_timer_enable_interrupt(MF_TIMER_STEP) #define DISABLE_STEPPER_DRIVER_INTERRUPT() HAL_timer_disable_interrupt(MF_TIMER_STEP) -#define STEPPER_ISR_ENABLED() HAL_timer_interrupt_enabled(MF_TIMER_STEP) +#define STEPPER_ISR_ENABLED() HAL_timer_interrupt_enabled(MF_TIMER_STEP) #define ENABLE_TEMPERATURE_INTERRUPT() HAL_timer_enable_interrupt(MF_TIMER_TEMP) #define DISABLE_TEMPERATURE_INTERRUPT() HAL_timer_disable_interrupt(MF_TIMER_TEMP) @@ -135,5 +135,5 @@ void HAL_timer_enable_interrupt(const uint8_t timer_num); void HAL_timer_disable_interrupt(const uint8_t timer_num); bool HAL_timer_interrupt_enabled(const uint8_t timer_num); -#define HAL_timer_isr_prologue(T) NOOP -#define HAL_timer_isr_epilogue(T) NOOP +inline void HAL_timer_isr_prologue(const uint8_t) {} +inline void HAL_timer_isr_epilogue(const uint8_t) {} diff --git a/Marlin/src/HAL/ESP32/u8g_esp32_spi.cpp b/Marlin/src/HAL/ESP32/u8g_esp32_spi.cpp index a4c1980adc..42903da9d3 100644 --- a/Marlin/src/HAL/ESP32/u8g_esp32_spi.cpp +++ b/Marlin/src/HAL/ESP32/u8g_esp32_spi.cpp @@ -35,7 +35,7 @@ #if HAS_MEDIA #include "../../sd/cardreader.h" #if ENABLED(ESP3D_WIFISUPPORT) - #include "sd_ESP32.h" + #include #endif #endif diff --git a/Marlin/src/HAL/ESP32/WebSocketSerial.cpp b/Marlin/src/HAL/ESP32/wifi/WebSocketSerial.cpp similarity index 99% rename from Marlin/src/HAL/ESP32/WebSocketSerial.cpp rename to Marlin/src/HAL/ESP32/wifi/WebSocketSerial.cpp index eb5b9d6039..9c8933289d 100644 --- a/Marlin/src/HAL/ESP32/WebSocketSerial.cpp +++ b/Marlin/src/HAL/ESP32/wifi/WebSocketSerial.cpp @@ -21,7 +21,7 @@ */ #ifdef ARDUINO_ARCH_ESP32 -#include "../../inc/MarlinConfigPre.h" +#include "../../../inc/MarlinConfigPre.h" #if ENABLED(WIFISUPPORT) diff --git a/Marlin/src/HAL/ESP32/WebSocketSerial.h b/Marlin/src/HAL/ESP32/wifi/WebSocketSerial.h similarity index 96% rename from Marlin/src/HAL/ESP32/WebSocketSerial.h rename to Marlin/src/HAL/ESP32/wifi/WebSocketSerial.h index 6b3e419d10..3d2fdf1e6a 100644 --- a/Marlin/src/HAL/ESP32/WebSocketSerial.h +++ b/Marlin/src/HAL/ESP32/wifi/WebSocketSerial.h @@ -21,8 +21,8 @@ */ #pragma once -#include "../../inc/MarlinConfig.h" -#include "../../core/serial_hook.h" +#include "../../../inc/MarlinConfig.h" +#include "../../../core/serial_hook.h" #include diff --git a/Marlin/src/HAL/ESP32/ota.cpp b/Marlin/src/HAL/ESP32/wifi/ota.cpp similarity index 98% rename from Marlin/src/HAL/ESP32/ota.cpp rename to Marlin/src/HAL/ESP32/wifi/ota.cpp index be5847b831..03508840a5 100644 --- a/Marlin/src/HAL/ESP32/ota.cpp +++ b/Marlin/src/HAL/ESP32/wifi/ota.cpp @@ -27,7 +27,7 @@ #undef ENABLED #undef DISABLED -#include "../../inc/MarlinConfigPre.h" +#include "../../../inc/MarlinConfigPre.h" #if ALL(WIFISUPPORT, OTASUPPORT) diff --git a/Marlin/src/HAL/ESP32/ota.h b/Marlin/src/HAL/ESP32/wifi/ota.h similarity index 100% rename from Marlin/src/HAL/ESP32/ota.h rename to Marlin/src/HAL/ESP32/wifi/ota.h diff --git a/Marlin/src/HAL/ESP32/spiffs.cpp b/Marlin/src/HAL/ESP32/wifi/spiffs.cpp similarity index 94% rename from Marlin/src/HAL/ESP32/spiffs.cpp rename to Marlin/src/HAL/ESP32/wifi/spiffs.cpp index 043ad7849a..ba891acda9 100644 --- a/Marlin/src/HAL/ESP32/spiffs.cpp +++ b/Marlin/src/HAL/ESP32/wifi/spiffs.cpp @@ -21,11 +21,11 @@ */ #ifdef ARDUINO_ARCH_ESP32 -#include "../../inc/MarlinConfigPre.h" +#include "../../../inc/MarlinConfigPre.h" #if ALL(WIFISUPPORT, WEBSUPPORT) -#include "../../core/serial.h" +#include "../../../core/serial.h" #include #include diff --git a/Marlin/src/HAL/ESP32/spiffs.h b/Marlin/src/HAL/ESP32/wifi/spiffs.h similarity index 100% rename from Marlin/src/HAL/ESP32/spiffs.h rename to Marlin/src/HAL/ESP32/wifi/spiffs.h diff --git a/Marlin/src/HAL/ESP32/web.cpp b/Marlin/src/HAL/ESP32/wifi/web.cpp similarity index 94% rename from Marlin/src/HAL/ESP32/web.cpp rename to Marlin/src/HAL/ESP32/wifi/web.cpp index 63a101595f..f08dfd87c0 100644 --- a/Marlin/src/HAL/ESP32/web.cpp +++ b/Marlin/src/HAL/ESP32/wifi/web.cpp @@ -21,11 +21,11 @@ */ #ifdef ARDUINO_ARCH_ESP32 -#include "../../inc/MarlinConfigPre.h" +#include "../../../inc/MarlinConfigPre.h" #if ALL(WIFISUPPORT, WEBSUPPORT) -#include "../../inc/MarlinConfig.h" +#include "../../../inc/MarlinConfig.h" #undef DISABLED // esp32-hal-gpio.h #include diff --git a/Marlin/src/HAL/ESP32/web.h b/Marlin/src/HAL/ESP32/wifi/web.h similarity index 100% rename from Marlin/src/HAL/ESP32/web.h rename to Marlin/src/HAL/ESP32/wifi/web.h diff --git a/Marlin/src/HAL/ESP32/wifi.cpp b/Marlin/src/HAL/ESP32/wifi/wifi.cpp similarity index 96% rename from Marlin/src/HAL/ESP32/wifi.cpp rename to Marlin/src/HAL/ESP32/wifi/wifi.cpp index aa2796adea..1f31ca1bb9 100644 --- a/Marlin/src/HAL/ESP32/wifi.cpp +++ b/Marlin/src/HAL/ESP32/wifi/wifi.cpp @@ -21,11 +21,11 @@ */ #ifdef ARDUINO_ARCH_ESP32 -#include "../../inc/MarlinConfigPre.h" +#include "../../../inc/MarlinConfigPre.h" #if ENABLED(WIFISUPPORT) -#include "../../core/serial.h" +#include "../../../core/serial.h" #include #include diff --git a/Marlin/src/HAL/ESP32/wifi.h b/Marlin/src/HAL/ESP32/wifi/wifi.h similarity index 100% rename from Marlin/src/HAL/ESP32/wifi.h rename to Marlin/src/HAL/ESP32/wifi/wifi.h diff --git a/Marlin/src/HAL/GD32_MFL/HAL.cpp b/Marlin/src/HAL/GD32_MFL/HAL.cpp new file mode 100644 index 0000000000..9ba20784f0 --- /dev/null +++ b/Marlin/src/HAL/GD32_MFL/HAL.cpp @@ -0,0 +1,123 @@ +/** + * 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 . + * + */ + +#include "../platforms.h" + +#ifdef ARDUINO_ARCH_MFL + +#include "../../inc/MarlinConfig.h" +#include "../shared/Delay.h" + +uint16_t MarlinHAL::adc_result; + +#if ENABLED(POSTMORTEM_DEBUGGING) + extern void install_min_serial(); +#endif + +#if ENABLED(MARLIN_DEV_MODE) + // Dump the clock frequencies of the system, AHB, APB1, APB2, and F_CPU. + static inline void HAL_clock_frequencies_dump() { + auto& rcuInstance = rcu::RCU::get_instance(); + uint32_t freq = rcuInstance.get_clock_frequency(rcu::Clock_Frequency::CK_SYS); + SERIAL_ECHOPGM("\nSYSTEM_CLOCK=", freq); + freq = rcuInstance.get_clock_frequency(rcu::Clock_Frequency::CK_AHB); + SERIAL_ECHOPGM("\nABH_CLOCK=", freq); + freq = rcuInstance.get_clock_frequency(rcu::Clock_Frequency::CK_APB1); + SERIAL_ECHOPGM("\nAPB1_CLOCK=", freq); + freq = rcuInstance.get_clock_frequency(rcu::Clock_Frequency::CK_APB2); + SERIAL_ECHOPGM("\nAPB2_CLOCK=", freq, + "\nF_CPU=", F_CPU); + // Done + SERIAL_ECHOPGM("\n--\n"); + } +#endif // MARLIN_DEV_MODE + +// 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 + + SetTimerInterruptPriorities(); + + // Print clock frequencies to host serial + TERN_(MARLIN_DEV_MODE, HAL_clock_frequencies_dump()); + + // Register min serial + TERN_(POSTMORTEM_DEBUGGING, install_min_serial()); +} + +// Returns the reset source based on the flags set in the RCU module +uint8_t MarlinHAL::get_reset_source() { + return + (RCU_I.get_flag(rcu::Status_Flags::FLAG_FWDGTRST)) ? RST_WATCHDOG : + (RCU_I.get_flag(rcu::Status_Flags::FLAG_SWRST)) ? RST_SOFTWARE : + (RCU_I.get_flag(rcu::Status_Flags::FLAG_EPRST)) ? RST_EXTERNAL : + (RCU_I.get_flag(rcu::Status_Flags::FLAG_PORRST)) ? RST_POWER_ON : + (RCU_I.get_flag(rcu::Status_Flags::FLAG_LPRST)) ? RST_BROWN_OUT : + 0; +} + +// Returns the amount of free memory available in bytes +int MarlinHAL::freeMemory() { + volatile char top; + return &top - reinterpret_cast(_sbrk(0)); +} + +// Watchdog Timer +#if ENABLED(USE_WATCHDOG) + #define WDT_TIMEOUT_US TERN(WATCHDOG_DURATION_8S, 8000000, 4000000) // 4 or 8 second timeout + + #include + + FWatchdogTimer& watchdogTimer = FWatchdogTimer::get_instance(); + + // Initializes the watchdog timer + void MarlinHAL::watchdog_init() { + IF_DISABLED(DISABLE_WATCHDOG_INIT, watchdogTimer.begin(WDT_TIMEOUT_US)); + } + + // Refreshes the watchdog timer to prevent system reset + void MarlinHAL::watchdog_refresh() { + watchdogTimer.reload(); + #if DISABLED(PINS_DEBUGGING) && PIN_EXISTS(LED) + TOGGLE(LED_PIN); // Heartbeat indicator + #endif + } +#endif + +extern "C" { + extern unsigned int _ebss; // End of bss section +} + +// Resets the system to initiate a firmware flash. +WEAK void flashFirmware(const int16_t) { + hal.reboot(); +} + +#endif // ARDUINO_ARCH_MFL diff --git a/Marlin/src/HAL/GD32_MFL/HAL.h b/Marlin/src/HAL/GD32_MFL/HAL.h new file mode 100644 index 0000000000..6195212028 --- /dev/null +++ b/Marlin/src/HAL/GD32_MFL/HAL.h @@ -0,0 +1,159 @@ +/** + * 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 . + * + */ +#pragma once + +#define CPU_32_BIT + +#include "../../core/macros.h" +#include "../shared/Marduino.h" +#include "../shared/math_32bit.h" +#include "../shared/HAL_SPI.h" + +#include "temp_soc.h" +#include "fastio.h" +#include "Servo.h" + +#include "../../inc/MarlinConfigPre.h" + +#include +#include +#include + +// Default graphical display delays +#define CPU_ST7920_DELAY_1 300 +#define CPU_ST7920_DELAY_2 40 +#define CPU_ST7920_DELAY_3 340 + +// Serial Ports +#include "MarlinSerial.h" + +// Interrupts +#define CRITICAL_SECTION_START() const bool irqon = !__get_PRIMASK(); __disable_irq() +#define CRITICAL_SECTION_END() if (irqon) __enable_irq() + +#define cli() __disable_irq() +#define sei() __enable_irq() + +// Alias of __bss_end__ +#define __bss_end __bss_end__ + +// Types +typedef uint8_t pin_t; // Parity with mfl platform + +// Servo +class libServo; +typedef libServo hal_servo_t; +#define PAUSE_SERVO_OUTPUT() libServo::pause_all_servos() +#define RESUME_SERVO_OUTPUT() libServo::resume_all_servos() + +// Debugging +#define JTAG_DISABLE() AFIO_I.set_remap(gpio::Pin_Remap_Select::SWJ_DP_ONLY_REMAP) +#define JTAGSWD_DISABLE() AFIO_I.set_remap(gpio::Pin_Remap_Select::SWJ_ALL_DISABLED_REMAP) +#define JTAGSWD_RESET() AFIO_I.set_remap(gpio::Pin_Remap_Select::FULL_SWJ_REMAP) + +// ADC +#ifdef ADC_RESOLUTION + #define HAL_ADC_RESOLUTION ADC_RESOLUTION +#else + #define HAL_ADC_RESOLUTION 12 +#endif + +#define HAL_ADC_VREF_MV 3300 + +// Disable Marlin's software oversampling. +// The MFL framework uses 16x hardware oversampling by default +#ifdef GD32F303RE + #define HAL_ADC_FILTERED +#endif + +#define GET_PIN_MAP_PIN(index) index +#define GET_PIN_MAP_INDEX(pin) pin +#define PARSED_PIN_INDEX(code, dval) parser.intval(code, dval) + +#ifndef PLATFORM_M997_SUPPORT + #define PLATFORM_M997_SUPPORT +#endif + +void flashFirmware(const int16_t); + +#define HAL_CAN_SET_PWM_FREQ // This HAL supports PWM Frequency adjustment + +extern "C" char* _sbrk(int incr); +extern "C" char* dtostrf(double val, signed char width, unsigned char prec, char* sout); + +// MarlinHAL Class +class MarlinHAL { +public: + // Before setup() + MarlinHAL() = default; + + // Watchdog + static void watchdog_init() IF_DISABLED(USE_WATCHDOG, {}); + static void watchdog_refresh() IF_DISABLED(USE_WATCHDOG, {}); + + static void init(); // called early in setup() + static void init_board() {} // called less early in setup() + static void reboot() { NVIC_SystemReset(); } // restart the firmware from 0x0 + + // Interrupts + static bool isr_state() { return !__get_PRIMASK(); } + static void isr_on() { sei(); } + static void isr_off() { cli(); } + static void delay_ms(const int ms) { delay(ms); } + + // Tasks called from idle() + static void idletask() {} + + // Reset + static uint8_t get_reset_source(); + static void clear_reset_source() { RCU_I.clear_all_reset_flags(); } + + // Free SRAM + static int freeMemory(); + + // ADC methods + static uint16_t adc_result; + + // Called by Temperature::init once at startup + static void adc_init() { analogReadResolution(HAL_ADC_RESOLUTION); } + + // Called by Temperature::init for each sensor at startup + static void adc_enable(const pin_t pin) { pinMode(pin, INPUT); } + + // Called from Temperature::isr to start ADC sampling on the given pin + static void adc_start(const pin_t pin) { adc_result = static_cast(analogRead(pin)); } + + // Check if ADC is ready for reading + static bool adc_ready() { return true; } + + // Current value of the ADC register + static uint16_t adc_value() { return adc_result; } + + // Set the PWM duty cycle for the pin to the given value. + // Optionally invert the duty cycle [default = false] + // Optionally change the maximum size of the provided value to enable finer PWM duty control [default = 255] + static void set_pwm_duty(const pin_t pin, const uint16_t value, const uint16_t scale = 255U, const bool invert = false); + + // Set the frequency of the timer for the given pin. + // All Timer PWM pins run at the same frequency. + static void set_pwm_frequency(const pin_t pin, const uint16_t f_desired); +}; diff --git a/Marlin/src/feature/mmu3/strlen_cx.h b/Marlin/src/HAL/GD32_MFL/MarlinSPI.h similarity index 80% rename from Marlin/src/feature/mmu3/strlen_cx.h rename to Marlin/src/HAL/GD32_MFL/MarlinSPI.h index 6ac2a84b42..d0731f9e84 100644 --- a/Marlin/src/feature/mmu3/strlen_cx.h +++ b/Marlin/src/HAL/GD32_MFL/MarlinSPI.h @@ -1,6 +1,6 @@ /** * Marlin 3D Printer Firmware - * Copyright (c) 2024 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] + * Copyright (c) 2025 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] * * Based on Sprinter and grbl. * Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm @@ -21,10 +21,6 @@ */ #pragma once -/** - * strlen_cx.h - */ +#include -constexpr inline int strlen_constexpr(const char *str) { - return *str ? 1 + strlen_constexpr(str + 1) : 0; -} +using MarlinSPI = SPIClass; diff --git a/Marlin/src/HAL/GD32_MFL/MarlinSerial.cpp b/Marlin/src/HAL/GD32_MFL/MarlinSerial.cpp new file mode 100644 index 0000000000..95ea8bea25 --- /dev/null +++ b/Marlin/src/HAL/GD32_MFL/MarlinSerial.cpp @@ -0,0 +1,97 @@ +/** + * 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 . + * + */ + +#include "../platforms.h" + +#ifdef ARDUINO_ARCH_MFL + +#include "../../inc/MarlinConfig.h" +#include "MarlinSerial.h" + +#if ENABLED(EMERGENCY_PARSER) + #include "../../feature/e_parser.h" +#endif + +using namespace arduino; + +auto MarlinSerial::get_instance(usart::USART_Base Base, pin_size_t rxPin, pin_size_t txPin) -> MarlinSerial& { + auto& serial = UsartSerial::get_instance(Base, rxPin, txPin); + return *reinterpret_cast(&serial); +} + +#if USING_HW_SERIAL0 + MSerialT MSerial0(true, MarlinSerial::get_instance(usart::USART_Base::USART0_BASE, NO_PIN, NO_PIN)); +#endif +#if USING_HW_SERIAL1 + MSerialT MSerial1(true, MarlinSerial::get_instance(usart::USART_Base::USART1_BASE, NO_PIN, NO_PIN)); +#endif +#if USING_HW_SERIAL2 + MSerialT MSerial2(true, MarlinSerial::get_instance(usart::USART_Base::USART2_BASE, NO_PIN, NO_PIN)); +#endif +#if USING_HW_SERIAL3 + MSerialT MSerial3(true, MarlinSerial::get_instance(usart::USART_Base::UART3_BASE, NO_PIN, NO_PIN)); +#endif +#if USING_HW_SERIAL4 + MSerialT MSerial4(true, MarlinSerial::get_instance(usart::USART_Base::UART4_BASE, NO_PIN, NO_PIN)); +#endif + +#if ENABLED(EMERGENCY_PARSER) + // This callback needs to access the specific MarlinSerial instance + // We'll use a static pointer to track the current instance + static MarlinSerial* current_serial_instance = nullptr; + + static void emergency_callback() { + if (!current_serial_instance) return; + const auto last_data = current_serial_instance->get_last_data(); + emergency_parser.update(current_serial_instance->emergency_state, last_data); + } + + void MarlinSerial::register_emergency_callback(void (*callback)()) { + usart_.register_interrupt_callback(usart::Interrupt_Type::INTR_RBNEIE, callback); + } +#endif + +void MarlinSerial::begin(unsigned long baudrate, uint16_t config) { + UsartSerial::begin(baudrate, config, ENABLED(SERIAL_DMA)); + #if ENABLED(EMERGENCY_PARSER) && DISABLED(SERIAL_DMA) + current_serial_instance = this; + register_emergency_callback(emergency_callback); + #endif +} + +void MarlinSerial::updateRxDmaBuffer() { + #if ENABLED(EMERGENCY_PARSER) + // Get the number of bytes available in the receive buffer + const size_t available_bytes = usart_.available_for_read(true); + + // Process only the available data + for (size_t i = 0; i < available_bytes; ++i) { + uint8_t data; + if (usart_.read_rx_buffer(data)) + emergency_parser.update(emergency_state, data); + } + #endif + // Call the base class implementation to handle any additional updates + UsartSerial::updateRxDmaBuffer(); +} + +#endif // ARDUINO_ARCH_MFL diff --git a/Marlin/src/HAL/GD32_MFL/MarlinSerial.h b/Marlin/src/HAL/GD32_MFL/MarlinSerial.h new file mode 100644 index 0000000000..6b33ce0e61 --- /dev/null +++ b/Marlin/src/HAL/GD32_MFL/MarlinSerial.h @@ -0,0 +1,75 @@ +/** + * 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 . + * + */ +#pragma once + +#include "../../inc/MarlinConfigPre.h" + +#if ENABLED(EMERGENCY_PARSER) + #include "../../feature/e_parser.h" +#endif + +#include + +#include "../../core/serial_hook.h" + +#define SERIAL_INDEX_MIN 0 +#define SERIAL_INDEX_MAX 4 + +#include "../shared/serial_ports.h" + +#if defined(LCD_SERIAL_PORT) && ANY(HAS_DGUS_LCD, EXTENSIBLE_UI) + #define LCD_SERIAL_TX_BUFFER_FREE() LCD_SERIAL.availableForWrite() +#endif + +using namespace arduino; + +struct MarlinSerial : public UsartSerial { + static auto get_instance(usart::USART_Base Base, pin_size_t rxPin = NO_PIN, pin_size_t txPin = NO_PIN) -> MarlinSerial&; + + void begin(unsigned long baudrate, uint16_t config); + inline void begin(unsigned long baudrate) { begin(baudrate, SERIAL_8N1); } + void updateRxDmaBuffer(); + + #if DISABLED(SERIAL_DMA) + FORCE_INLINE static uint8_t buffer_overruns() { return 0; } + #endif + + #if ENABLED(EMERGENCY_PARSER) + EmergencyParser::State emergency_state; + + // Accessor method to get the last received byte + auto get_last_data() -> uint8_t { return usart_.get_last_data(); } + + // Register the emergency callback + void register_emergency_callback(void (*callback)()); + #endif + +protected: + using UsartSerial::UsartSerial; +}; + +typedef Serial1Class MSerialT; +extern MSerialT MSerial0; +extern MSerialT MSerial1; +extern MSerialT MSerial2; +extern MSerialT MSerial3; +extern MSerialT MSerial4; diff --git a/Marlin/src/HAL/GD32_MFL/MinSerial.cpp b/Marlin/src/HAL/GD32_MFL/MinSerial.cpp new file mode 100644 index 0000000000..2cc79c8853 --- /dev/null +++ b/Marlin/src/HAL/GD32_MFL/MinSerial.cpp @@ -0,0 +1,163 @@ +/** + * 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 . + * + */ +#include "../platforms.h" + +#ifdef ARDUINO_ARCH_MFL + +#include "../../inc/MarlinConfigPre.h" + +#if ENABLED(POSTMORTEM_DEBUGGING) +#include "../shared/MinSerial.h" + +// Base addresses for USART peripherals +static constexpr uintptr_t USART_base[] = { + 0x40013800, // USART0 + 0x40004400, // USART1 + 0x40004800, // USART2 + 0x40004C00, // UART3 + 0x40005000 // UART4 +}; + +// Register offsets +static constexpr uint32_t STAT0_OFFSET = 0x00U; +static constexpr uint32_t DATA_OFFSET = 0x04U; +static constexpr uint32_t BAUD_OFFSET = 0x08U; +static constexpr uint32_t CTL0_OFFSET = 0x0CU; +static constexpr uint32_t CTL1_OFFSET = 0x14U; + +// Bit positions +static constexpr uint32_t TBE_BIT = 7; +static constexpr uint32_t TEN_BIT = 3; +static constexpr uint32_t UEN_BIT = 13; + +// NVIC interrupt numbers for USART +static constexpr int nvicUART[] = { 37, 38, 39, 52, 53 }; + +// RCU PCLK values for USART +static constexpr rcu::RCU_PCLK clockRegs[] = { + rcu::RCU_PCLK::PCLK_USART0, + rcu::RCU_PCLK::PCLK_USART1, + rcu::RCU_PCLK::PCLK_USART2, + rcu::RCU_PCLK::PCLK_UART3, + rcu::RCU_PCLK::PCLK_UART4 +}; + +// Memory barrier instructions +#define isb() __asm__ __volatile__ ("isb" : : : "memory") +#define dsb() __asm__ __volatile__ ("dsb" : : : "memory") +#define sw_barrier() __asm__ volatile("" : : : "memory") + +// Direct register access macros +#define USART_REG(offset) (*(volatile uint32_t*)(USART_base[SERIAL_PORT] + (offset))) +#define USART_STAT0 USART_REG(STAT0_OFFSET) +#define USART_DATA USART_REG(DATA_OFFSET) +#define USART_BAUD USART_REG(BAUD_OFFSET) +#define USART_CTL0 USART_REG(CTL0_OFFSET) +#define USART_CTL1 USART_REG(CTL1_OFFSET) + +// Bit manipulation macros +#define READ_BIT(reg, bit) (((reg) >> (bit)) & 1U) +#define SET_BIT(reg, bit) ((reg) |= (1U << (bit))) +#define CLEAR_BIT(reg, bit) ((reg) &= ~(1U << (bit))) + +// Initializes the MinSerial interface. +// This function sets up the USART interface for serial communication. +// If the selected serial port is not a hardware port, it disables the severe error reporting feature. +static void MinSerialBegin() { + #if !WITHIN(SERIAL_PORT, 0, 4) + #warning "Using POSTMORTEM_DEBUGGING requires a physical U(S)ART hardware in case of severe error." + #warning "Disabling the severe error reporting feature currently because the used serial port is not a HW port." + #else + int nvicIndex = nvicUART[SERIAL_PORT]; + + // NVIC base address for interrupt disable + struct NVICMin { + volatile uint32_t ISER[32]; + volatile uint32_t ICER[32]; + }; + NVICMin *nvicBase = (NVICMin*)0xE000E100; + + SBI32(nvicBase->ICER[nvicIndex >> 5], nvicIndex & 0x1F); + + // We require memory barriers to properly disable interrupts + // (https://dzone.com/articles/nvic-disabling-interrupts-on-arm-cortex-m-and-the) + dsb(); + isb(); + + // Get the RCU PCLK for this USART + rcu::RCU_PCLK pclk = clockRegs[SERIAL_PORT]; + + // Disable then enable usart peripheral clocks + rcu::RCU_DEVICE.set_pclk_enable(pclk, false); + rcu::RCU_DEVICE.set_pclk_enable(pclk, true); + + // Save current baudrate + uint32_t baudrate = USART_BAUD; + + // Reset USART control registers + USART_CTL0 = 0; + USART_CTL1 = 0; // 1 stop bit + + // Restore baudrate + USART_BAUD = baudrate; + + // Enable transmitter and USART (8 bits, no parity, 1 stop bit) + SET_BIT(USART_CTL0, TEN_BIT); + SET_BIT(USART_CTL0, UEN_BIT); + #endif +} + +// Writes a single character to the serial port. +static void MinSerialWrite(char c) { + #if WITHIN(SERIAL_PORT, 0, 4) + // Wait until transmit buffer is empty + while (!READ_BIT(USART_STAT0, TBE_BIT)) { + hal.watchdog_refresh(); + sw_barrier(); + } + // Write character to data register + USART_DATA = c; + #endif +} + +// Installs the minimum serial interface. +// Sets the HAL_min_serial_init and HAL_min_serial_out function pointers to MinSerialBegin and MinSerialWrite respectively. +void install_min_serial() { + HAL_min_serial_init = &MinSerialBegin; + HAL_min_serial_out = &MinSerialWrite; +} + +extern "C" { + // A low-level assembly-based jump handler. + // Unconditionally branches to the CommonHandler_ASM function. + __attribute__((naked, aligned(4))) void JumpHandler_ASM() { + __asm__ __volatile__ ("b CommonHandler_ASM\n"); + } + void __attribute__((naked, alias("JumpHandler_ASM"), nothrow)) HardFault_Handler(); + void __attribute__((naked, alias("JumpHandler_ASM"), nothrow)) BusFault_Handler(); + void __attribute__((naked, alias("JumpHandler_ASM"), nothrow)) UsageFault_Handler(); + void __attribute__((naked, alias("JumpHandler_ASM"), nothrow)) MemManage_Handler(); + void __attribute__((naked, alias("JumpHandler_ASM"), nothrow)) NMI_Handler(); +} + +#endif // POSTMORTEM_DEBUGGING +#endif // ARDUINO_ARCH_MFL diff --git a/Marlin/src/HAL/GD32_MFL/README.md b/Marlin/src/HAL/GD32_MFL/README.md new file mode 100644 index 0000000000..61800eda1c --- /dev/null +++ b/Marlin/src/HAL/GD32_MFL/README.md @@ -0,0 +1,9 @@ +# Generic GD32 HAL based on the MFL Arduino Core + +This HAL is eventually intended to act as the generic HAL for all GD32 chips using the MFL library. + +Currently it supports: + +- GD32F303RET6 + +Targeting the official [MFL Arduino Core](https://github.com/bnmguy/ArduinoCore_MFL). diff --git a/Marlin/src/HAL/GD32_MFL/Servo.cpp b/Marlin/src/HAL/GD32_MFL/Servo.cpp new file mode 100644 index 0000000000..6cbcbc049b --- /dev/null +++ b/Marlin/src/HAL/GD32_MFL/Servo.cpp @@ -0,0 +1,125 @@ +/** + * 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 . + * + */ +#include "../platforms.h" + +#ifdef ARDUINO_ARCH_MFL + +#include "../../inc/MarlinConfig.h" + +#if HAS_SERVOS + +#include "Servo.h" + +static uint_fast8_t servoCount = 0; +static libServo* servos[NUM_SERVOS] = {0}; +constexpr millis_t servoDelay[] = SERVO_DELAY; +static_assert(COUNT(servoDelay) == NUM_SERVOS, "SERVO_DELAY must be an array NUM_SERVOS long."); + +// Initialize to the default timer priority. This will be overridden by a call from timers.cpp. +// This allows all timer interrupt priorities to be managed from a single location in the HAL. +static uint32_t servo_interrupt_priority = NVIC_EncodePriority(NVIC_GetPriorityGrouping(), 12, 0); + +// This must be called after the MFL Servo class has initialized the timer. +// To be safe this is currently called after every call to attach(). +static void fixServoTimerInterruptPriority() { + auto& servoTimerIdx = GeneralTimer::get_instance(static_cast(TIMER_SERVO)); + NVIC_SetPriority(servoTimerIdx.getTimerUpIRQ(), servo_interrupt_priority); +} + +// Default constructor for libServo class. +// Initializes the servo delay, pause state, and pause value. +// Registers the servo instance in the servos array. +libServo::libServo() : + delay(servoDelay[servoCount]), + was_attached_before_pause(false), + value_before_pause(0) +{ + servos[servoCount++] = this; +} + +// Attaches a servo to a specified pin. +int8_t libServo::attach(const int pin) { + if (servoCount >= MAX_SERVOS) return -1; + if (pin > 0) servoPin = pin; + auto result = mflServo.attach(servoPin); + fixServoTimerInterruptPriority(); + return result; +} + +// Attaches a servo to a specified pin with minimum and maximum pulse widths. +int8_t libServo::attach(const int pin, const int min, const int max) { + if (servoCount >= MAX_SERVOS) return -1; + if (pin > 0) servoPin = pin; + auto result = mflServo.attach(servoPin, min, max); + fixServoTimerInterruptPriority(); + return result; +} + +// Moves the servo to a specified position. +void libServo::move(const int value) { + if (attach(0) >= 0) { + mflServo.write(value); + safe_delay(delay); + TERN_(DEACTIVATE_SERVOS_AFTER_MOVE, detach()); + } +} + +// Pause the servo by detaching it and storing its current state. +void libServo::pause() { + was_attached_before_pause = mflServo.attached(); + if (was_attached_before_pause) { + value_before_pause = mflServo.read(); + mflServo.detach(); + } +} + +// Resume a previously paused servo. +// If the servo was attached before the pause, this function re-attaches +// the servo and moves it to the position it was in before the pause. +void libServo::resume() { + if (was_attached_before_pause) { + attach(); + move(value_before_pause); + } +} + +// Pause all servos by stopping their timers. +void libServo::pause_all_servos() { + for (auto& servo : servos) + if (servo) servo->pause(); +} + +// Resume all paused servos by starting their timers. +void libServo::resume_all_servos() { + for (auto& servo : servos) + if (servo) servo->resume(); +} + +// Set the interrupt priority for the servo. +// @param preemptPriority The preempt priority level. +// @param subPriority The sub priority level. +void libServo::setInterruptPriority(uint32_t preemptPriority, uint32_t subPriority) { + servo_interrupt_priority = NVIC_EncodePriority(NVIC_GetPriorityGrouping(), preemptPriority, subPriority); +} + +#endif // HAS_SERVOS +#endif // ARDUINO_ARCH_MFL diff --git a/Marlin/src/HAL/GD32_MFL/Servo.h b/Marlin/src/HAL/GD32_MFL/Servo.h new file mode 100644 index 0000000000..80cff46ff8 --- /dev/null +++ b/Marlin/src/HAL/GD32_MFL/Servo.h @@ -0,0 +1,56 @@ +/** + * 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 . + * + */ +#pragma once + +#include + +#include "../../core/millis_t.h" + +// Inherit and expand on the official library +class libServo { +public: + libServo(); + + int8_t attach(const int pin = 0); // pin == 0 uses value from previous call + int8_t attach(const int pin, const int min, const int max); + void detach() { mflServo.detach(); } + + int read() { return mflServo.read(); } + void move(const int value); + + void pause(); + void resume(); + + static void pause_all_servos(); + static void resume_all_servos(); + + static void setInterruptPriority(uint32_t preemptPriority, uint32_t subPriority); + +private: + Servo mflServo; + + int servoPin = 0; + millis_t delay = 0; + + bool was_attached_before_pause; + int value_before_pause; +}; diff --git a/Marlin/src/HAL/GD32_MFL/dogm/u8g_com_mfl_swspi.cpp b/Marlin/src/HAL/GD32_MFL/dogm/u8g_com_mfl_swspi.cpp new file mode 100644 index 0000000000..b36cbfe44d --- /dev/null +++ b/Marlin/src/HAL/GD32_MFL/dogm/u8g_com_mfl_swspi.cpp @@ -0,0 +1,129 @@ +/** + * 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 / Ryan Power + * + * 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 . + * + */ + +#ifdef ARDUINO_ARCH_MFL + +#include "../../../inc/MarlinConfig.h" + +#if ALL(HAS_MARLINUI_U8GLIB, FORCE_SOFT_SPI) + +#include +#include "../../shared/HAL_SPI.h" + +#define nop asm volatile ("\tnop\n") + +static inline uint8_t swSpiTransfer_mode_0(uint8_t b) { + for (uint8_t i = 0; i < 8; ++i) { + const uint8_t state = (b & 0x80) ? HIGH : LOW; + WRITE(DOGLCD_SCK, HIGH); + WRITE(DOGLCD_MOSI, state); + b <<= 1; + WRITE(DOGLCD_SCK, LOW); + } + return b; +} + +static inline uint8_t swSpiTransfer_mode_3(uint8_t b) { + for (uint8_t i = 0; i < 8; ++i) { + const uint8_t state = (b & 0x80) ? HIGH : LOW; + WRITE(DOGLCD_SCK, LOW); + WRITE(DOGLCD_MOSI, state); + b <<= 1; + WRITE(DOGLCD_SCK, HIGH); + } + return b; +} + +static void u8g_sw_spi_shift_out(uint8_t val) { + #if U8G_SPI_USE_MODE_3 + swSpiTransfer_mode_3(val); + #else + swSpiTransfer_mode_0(val); + #endif +} + +static void swSpiInit() { + #if PIN_EXISTS(LCD_RESET) + SET_OUTPUT(LCD_RESET_PIN); + #endif + SET_OUTPUT(DOGLCD_A0); + OUT_WRITE(DOGLCD_SCK, LOW); + OUT_WRITE(DOGLCD_MOSI, LOW); + OUT_WRITE(DOGLCD_CS, HIGH); +} + +uint8_t u8g_com_HAL_MFL_sw_spi_fn(u8g_t *u8g, uint8_t msg, uint8_t arg_val, void *arg_ptr) { + switch (msg) { + case U8G_COM_MSG_INIT: + swSpiInit(); + break; + case U8G_COM_MSG_STOP: + break; + case U8G_COM_MSG_RESET: + #if PIN_EXISTS(LCD_RESET) + WRITE(LCD_RESET_PIN, arg_val); + #endif + break; + case U8G_COM_MSG_CHIP_SELECT: + #if U8G_SPI_USE_MODE_3 // This LCD SPI is running mode 3 while SD card is running mode 0 + if (arg_val) { // SCK idle state needs to be set to the proper idle state before + // the next chip select goes active + WRITE(DOGLCD_SCK, HIGH); // Set SCK to mode 3 idle state before CS goes active + WRITE(DOGLCD_CS, LOW); + nop; // Hold SCK high for a few ns + nop; + } + else { + WRITE(DOGLCD_CS, HIGH); + WRITE(DOGLCD_SCK, LOW); // Set SCK to mode 0 idle state after CS goes inactive + } + #else + WRITE(DOGLCD_CS, !arg_val); + #endif + break; + case U8G_COM_MSG_WRITE_BYTE: + u8g_sw_spi_shift_out(arg_val); + break; + case U8G_COM_MSG_WRITE_SEQ: { + uint8_t* ptr = (uint8_t*)arg_ptr; + while (arg_val > 0) { + u8g_sw_spi_shift_out(*ptr++); + arg_val--; + } + } break; + case U8G_COM_MSG_WRITE_SEQ_P: { + uint8_t* ptr = (uint8_t*)arg_ptr; + while (arg_val > 0) { + u8g_sw_spi_shift_out(u8g_pgm_read(ptr)); + ptr++; + arg_val--; + } + } break; + case U8G_COM_MSG_ADDRESS: // Define cmd (arg_val = 0) or data mode (arg_val = 1) + WRITE(DOGLCD_A0, arg_val); + break; + } + return 1; +} + +#endif // HAS_MARLINUI_U8GLIB && FORCE_SOFT_SPI +#endif // ARDUINO_ARCH_MFL diff --git a/Marlin/src/HAL/GD32_MFL/eeprom/eeprom_bl24cxx.cpp b/Marlin/src/HAL/GD32_MFL/eeprom/eeprom_bl24cxx.cpp new file mode 100644 index 0000000000..1053c80a41 --- /dev/null +++ b/Marlin/src/HAL/GD32_MFL/eeprom/eeprom_bl24cxx.cpp @@ -0,0 +1,93 @@ +/** + * 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 . + * + */ + +/** + * PersistentStore for Arduino-style EEPROM interface + * with simple implementations supplied by Marlin. + */ + +#include "../../platforms.h" + +#ifdef ARDUINO_ARCH_MFL + +#include "../../../inc/MarlinConfig.h" + +#if ENABLED(IIC_BL24CXX_EEPROM) + +#include "../../shared/eeprom_if.h" +#include "../../shared/eeprom_api.h" + +#ifndef MARLIN_EEPROM_SIZE + #error "MARLIN_EEPROM_SIZE is required for IIC_BL24CXX_EEPROM." +#endif + +size_t PersistentStore::capacity() { + return MARLIN_EEPROM_SIZE - eeprom_exclude_size; +} + +bool PersistentStore::access_start() { + eeprom_init(); + return true; +} + +bool PersistentStore::access_finish() { + return true; +} + +bool PersistentStore::write_data(int &pos, const uint8_t *value, size_t size, uint16_t *crc) { + uint16_t written = 0; + while (size--) { + uint8_t v = *value; + uint8_t * const p = (uint8_t * const)REAL_EEPROM_ADDR(pos); + // EPROM has only ~100,000 write cycles, + // so only write bytes that have changed! + if (v != eeprom_read_byte(p)) { + eeprom_write_byte(p, v); + if (++written & 0x7F) delay(2); else safe_delay(2); + if (eeprom_read_byte(p) != v) { + SERIAL_ECHO_MSG(STR_ERR_EEPROM_WRITE); + return true; + } + } + + crc16(crc, &v, 1); + pos++; + value++; + } + + return false; +} + +bool PersistentStore::read_data(int &pos, uint8_t *value, size_t size, uint16_t *crc, const bool writing/*=true*/) { + do { + const uint8_t c = eeprom_read_byte((uint8_t*)REAL_EEPROM_ADDR(pos)); + if (writing) *value = c; + crc16(crc, &c, 1); + pos++; + value++; + } while (--size); + + return false; +} + +#endif // IIC_BL24CXX_EEPROM +#endif // ARDUINO_ARCH_MFL diff --git a/Marlin/src/HAL/GD32_MFL/eeprom/eeprom_if_iic.cpp b/Marlin/src/HAL/GD32_MFL/eeprom/eeprom_if_iic.cpp new file mode 100644 index 0000000000..765c997e1f --- /dev/null +++ b/Marlin/src/HAL/GD32_MFL/eeprom/eeprom_if_iic.cpp @@ -0,0 +1,54 @@ +/** + * 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 . + * + */ + +/** + * Platform-independent Arduino functions for I2C EEPROM. + * Enable USE_SHARED_EEPROM if not supplied by the framework. + */ + +#include "../../platforms.h" + +#ifdef ARDUINO_ARCH_MFL + +#include "../../../inc/MarlinConfig.h" + +#if ENABLED(IIC_BL24CXX_EEPROM) + +#include "../../../libs/BL24CXX.h" +#include "../../shared/eeprom_if.h" + +void eeprom_init() { + BL24CXX::init(); +} + +void eeprom_write_byte(uint8_t *pos, uint8_t value) { + const unsigned eeprom_address = (unsigned)pos; + BL24CXX::writeOneByte(eeprom_address, value); +} + +uint8_t eeprom_read_byte(uint8_t *pos) { + const unsigned eeprom_address = (unsigned)pos; + return BL24CXX::readOneByte(eeprom_address); +} + +#endif // IIC_BL24CXX_EEPROM +#endif // ARDUINO_ARCH_MFL diff --git a/Marlin/src/HAL/GD32_MFL/eeprom/eeprom_wired.cpp b/Marlin/src/HAL/GD32_MFL/eeprom/eeprom_wired.cpp new file mode 100644 index 0000000000..8860e53a62 --- /dev/null +++ b/Marlin/src/HAL/GD32_MFL/eeprom/eeprom_wired.cpp @@ -0,0 +1,96 @@ +/** + * 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 . + * + */ +#include "../../platforms.h" + +#ifdef ARDUINO_ARCH_MFL + +#include "../../../inc/MarlinConfig.h" + +#if USE_WIRED_EEPROM + +/** + * PersistentStore for Arduino-style EEPROM interface + * with simple implementations supplied by Marlin. + */ + +#include "../../shared/eeprom_if.h" +#include "../../shared/eeprom_api.h" + +#ifndef MARLIN_EEPROM_SIZE + #define MARLIN_EEPROM_SIZE size_t(E2END + 1) +#endif + +size_t PersistentStore::capacity() { + return MARLIN_EEPROM_SIZE - eeprom_exclude_size; +} + +bool PersistentStore::access_start() { + eeprom_init(); + return true; +} + +bool PersistentStore::access_finish() { + return true; +} + +bool PersistentStore::write_data(int &pos, const uint8_t *value, size_t size, uint16_t *crc) { + uint16_t written = 0; + while (size--) { + uint8_t v = *value; + uint8_t * const p = (uint8_t * const)REAL_EEPROM_ADDR(pos); + // EEPROM has only ~100,000 write cycles, + // so only write bytes that have changed! + if (v != eeprom_read_byte(p)) { + eeprom_write_byte(p, v); + // Avoid triggering watchdog during long EEPROM writes + if (++written & 0x7F) + delay(2); + else + safe_delay(2); + if (eeprom_read_byte(p) != v) { + SERIAL_ECHO_MSG(STR_ERR_EEPROM_WRITE); + return true; + } + } + crc16(crc, &v, 1); + pos++; + value++; + } + + return false; +} + +bool PersistentStore::read_data(int &pos, uint8_t *value, size_t size, uint16_t *crc, const bool writing/*=true*/) { + do { + const uint8_t c = eeprom_read_byte((uint8_t*)REAL_EEPROM_ADDR(pos)); + if (writing) + *value = c; + crc16(crc, &c, 1); + pos++; + value++; + } while (--size); + + return false; +} + +#endif // USE_WIRED_EEPROM +#endif // ARDUINO_ARCH_MFL diff --git a/Marlin/src/HAL/GD32_MFL/endstop_interrupts.h b/Marlin/src/HAL/GD32_MFL/endstop_interrupts.h new file mode 100644 index 0000000000..175dec3959 --- /dev/null +++ b/Marlin/src/HAL/GD32_MFL/endstop_interrupts.h @@ -0,0 +1,61 @@ +/** + * 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 . + * + */ +#pragma once + +#include "../../module/endstops.h" + +// One ISR for all EXT-Interrupts +void endstop_ISR() { endstops.update(); } + +void setup_endstop_interrupts() { + #define _ATTACH(P) attachInterrupt(P, endstop_ISR, CHANGE) + TERN_(USE_X_MAX, _ATTACH(X_MAX_PIN)); + TERN_(USE_X_MIN, _ATTACH(X_MIN_PIN)); + TERN_(USE_Y_MAX, _ATTACH(Y_MAX_PIN)); + TERN_(USE_Y_MIN, _ATTACH(Y_MIN_PIN)); + TERN_(USE_Z_MAX, _ATTACH(Z_MAX_PIN)); + TERN_(USE_Z_MIN, _ATTACH(Z_MIN_PIN)); + TERN_(USE_X2_MAX, _ATTACH(X2_MAX_PIN)); + TERN_(USE_X2_MIN, _ATTACH(X2_MIN_PIN)); + TERN_(USE_Y2_MAX, _ATTACH(Y2_MAX_PIN)); + TERN_(USE_Y2_MIN, _ATTACH(Y2_MIN_PIN)); + TERN_(USE_Z2_MAX, _ATTACH(Z2_MAX_PIN)); + TERN_(USE_Z2_MIN, _ATTACH(Z2_MIN_PIN)); + TERN_(USE_Z3_MAX, _ATTACH(Z3_MAX_PIN)); + TERN_(USE_Z3_MIN, _ATTACH(Z3_MIN_PIN)); + TERN_(USE_Z4_MAX, _ATTACH(Z4_MAX_PIN)); + TERN_(USE_Z4_MIN, _ATTACH(Z4_MIN_PIN)); + TERN_(USE_Z_MIN_PROBE, _ATTACH(Z_MIN_PROBE_PIN)); + TERN_(USE_CALIBRATION, _ATTACH(CALIBRATION_PIN)); + TERN_(USE_I_MAX, _ATTACH(I_MAX_PIN)); + TERN_(USE_I_MIN, _ATTACH(I_MIN_PIN)); + TERN_(USE_J_MAX, _ATTACH(J_MAX_PIN)); + TERN_(USE_J_MIN, _ATTACH(J_MIN_PIN)); + TERN_(USE_K_MAX, _ATTACH(K_MAX_PIN)); + TERN_(USE_K_MIN, _ATTACH(K_MIN_PIN)); + TERN_(USE_U_MAX, _ATTACH(U_MAX_PIN)); + TERN_(USE_U_MIN, _ATTACH(U_MIN_PIN)); + TERN_(USE_V_MAX, _ATTACH(V_MAX_PIN)); + TERN_(USE_V_MIN, _ATTACH(V_MIN_PIN)); + TERN_(USE_W_MAX, _ATTACH(W_MAX_PIN)); + TERN_(USE_W_MIN, _ATTACH(W_MIN_PIN)); +} diff --git a/Marlin/src/HAL/GD32_MFL/fast_pwm.cpp b/Marlin/src/HAL/GD32_MFL/fast_pwm.cpp new file mode 100644 index 0000000000..9fba673efc --- /dev/null +++ b/Marlin/src/HAL/GD32_MFL/fast_pwm.cpp @@ -0,0 +1,97 @@ +/** + * 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 . + * + */ + +#include "../platforms.h" + +#ifdef ARDUINO_ARCH_MFL + +#include "../../inc/MarlinConfig.h" + +#include +#include +#include "timers.h" + +static uint16_t timer_frequency[TIMER_COUNT]; + +void MarlinHAL::set_pwm_duty(const pin_t pin, const uint16_t value, const uint16_t scale, const bool invert) { + // Calculate duty cycle based on inversion flag + const uint16_t duty = invert ? scale - value : value; + + // Check if the pin supports PWM + if (PWM_PIN(pin)) { + // Get the timer peripheral base associated with the pin + const auto timer_base = getPinOpsPeripheralBase(TIMER_PinOps, static_cast(pin)); + + // Initialize the timer instance + auto& TimerInstance = GeneralTimer::get_instance(timer_base); + + // Get channel and previous channel mode + const auto channel = getPackedPinChannel(getPackedPinOps(TIMER_PinOps, static_cast(pin))); + const InputOutputMode previous = TimerInstance.getChannelMode(channel); + + if (timer_frequency[static_cast(timer_base)] == 0) { + set_pwm_frequency(pin, PWM_FREQUENCY); + } + + // Set the PWM duty cycle + TimerInstance.setCaptureCompare(channel, duty, CCFormat::B8); + + // Configure pin as PWM output + pinOpsPinout(TIMER_PinOps, static_cast(pin)); + + // Set channel mode if not already set and start timer + if (previous != InputOutputMode::PWM0) { + TimerInstance.setChannelMode(channel, InputOutputMode::PWM0, static_cast(pin)); + TimerInstance.start(); + } + } else { + pinMode(pin, OUTPUT); + digitalWrite(pin, duty < scale / 2 ? LOW : HIGH); + } +} + +void MarlinHAL::set_pwm_frequency(const pin_t pin, const uint16_t f_desired) { + // Check if the pin supports PWM + if (!PWM_PIN(pin)) return; + + // Get the timer peripheral base associated with the pin + const auto timer_base = getPinOpsPeripheralBase(TIMER_PinOps, static_cast(pin)); + + // Guard against modifying protected timers + #ifdef STEP_TIMER + if (timer_base == static_cast(STEP_TIMER)) return; + #endif + #ifdef TEMP_TIMER + if (timer_base == static_cast(TEMP_TIMER)) return; + #endif + #if defined(PULSE_TIMER) && MF_TIMER_PULSE != MF_TIMER_STEP + if (timer_base == static_cast(PULSE_TIMER)) return; + #endif + + // Initialize the timer instance + auto& TimerInstance = GeneralTimer::get_instance(timer_base); + + TimerInstance.setRolloverValue(f_desired, TimerFormat::HERTZ); + timer_frequency[timer_base_to_index(timer_base)] = f_desired; +} + +#endif // ARDUINO_ARCH_MFL diff --git a/Marlin/src/HAL/GD32_MFL/fastio.h b/Marlin/src/HAL/GD32_MFL/fastio.h new file mode 100644 index 0000000000..11020f3e52 --- /dev/null +++ b/Marlin/src/HAL/GD32_MFL/fastio.h @@ -0,0 +1,86 @@ +/** + * 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 . + * + */ +#pragma once + +// Fast I/O interfaces for GD32 + +#include +#include +#include +#include + +template +FORCE_INLINE static void fast_write_pin_wrapper(pin_size_t IO, T V) { + const PortPinPair& pp = port_pin_map[IO]; + gpio::fast_write_pin(pp.port, pp.pin, static_cast(V)); +} + +FORCE_INLINE static auto fast_read_pin_wrapper(pin_size_t IO) -> bool { + const PortPinPair& pp = port_pin_map[IO]; + return gpio::fast_read_pin(pp.port, pp.pin); +} + +FORCE_INLINE static void fast_toggle_pin_wrapper(pin_size_t IO) { + const PortPinPair& pp = port_pin_map[IO]; + gpio::fast_toggle_pin(pp.port, pp.pin); +} + +// ------------------------ +// Defines +// ------------------------ + +#ifndef PWM + #define PWM OUTPUT +#endif + +#define _WRITE(IO, V) fast_write_pin_wrapper(IO, V) +#define _READ(IO) fast_read_pin_wrapper(IO) +#define _TOGGLE(IO) fast_toggle_pin_wrapper(IO) + +#define _GET_MODE(IO) +#define _SET_MODE(IO, M) pinMode((IO), (M)) +#define _SET_OUTPUT(IO) pinMode((IO), OUTPUT) +#define _SET_OUTPUT_OD(IO) pinMode((IO), OUTPUT_OPEN_DRAIN) + +#define WRITE(IO, V) _WRITE((IO), (V)) +#define READ(IO) _READ(IO) +#define TOGGLE(IO) _TOGGLE(IO) + +#define OUT_WRITE(IO, V) do { _SET_OUTPUT(IO); WRITE((IO), (V)); } while (0) +#define OUT_WRITE_OD(IO, V) do { _SET_OUTPUT_OD(IO); WRITE((IO), (V)); } while (0) + +#define SET_INPUT(IO) _SET_MODE((IO), INPUT) +#define SET_INPUT_PULLUP(IO) _SET_MODE((IO), INPUT_PULLUP) +#define SET_INPUT_PULLDOWN(IO) _SET_MODE((IO), INPUT_PULLDOWN) +#define SET_OUTPUT(IO) OUT_WRITE((IO), LOW) +#define SET_OUTPUT_OD(IO) OUT_WRITE_OD((IO), LOW) +#define SET_PWM(IO) _SET_MODE((IO), PWM) + +#define IS_INPUT(IO) +#define IS_OUTPUT(IO) + +#define PWM_PIN(P) isPinInPinOps(TIMER_PinOps, P) +#define NO_COMPILE_TIME_PWM + +// Wrappers for digitalRead and digitalWrite +#define extDigitalRead(IO) digitalRead(IO) +#define extDigitalWrite(IO, V) digitalWrite((IO), (V)) diff --git a/Marlin/src/HAL/GD32_MFL/inc/Conditionals_LCD.h b/Marlin/src/HAL/GD32_MFL/inc/Conditionals_LCD.h new file mode 100644 index 0000000000..379ecfa7f0 --- /dev/null +++ b/Marlin/src/HAL/GD32_MFL/inc/Conditionals_LCD.h @@ -0,0 +1,26 @@ +/** + * 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 . + * + */ +#pragma once + +#if ALL(HAS_MARLINUI_U8GLIB, FORCE_SOFT_SPI) + #define U8G_SW_SPI_MFL 1 +#endif diff --git a/Marlin/src/HAL/GD32_MFL/inc/Conditionals_adv.h b/Marlin/src/HAL/GD32_MFL/inc/Conditionals_adv.h new file mode 100644 index 0000000000..6df84f6f92 --- /dev/null +++ b/Marlin/src/HAL/GD32_MFL/inc/Conditionals_adv.h @@ -0,0 +1,26 @@ +/** + * 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 . + * + */ +#pragma once + +#if ALL(HAS_MEDIA, USBD_USE_CDC_MSC) + #define HAS_SD_HOST_DRIVE 1 +#endif diff --git a/Marlin/src/HAL/GD32_MFL/inc/Conditionals_post.h b/Marlin/src/HAL/GD32_MFL/inc/Conditionals_post.h new file mode 100644 index 0000000000..a3db122682 --- /dev/null +++ b/Marlin/src/HAL/GD32_MFL/inc/Conditionals_post.h @@ -0,0 +1,29 @@ +/** + * 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 . + * + */ +#pragma once + +// If no real or emulated EEPROM selected, fall back to SD emulation +#if USE_FALLBACK_EEPROM + #define SDCARD_EEPROM_EMULATION +#elif ANY(I2C_EEPROM, SPI_EEPROM) + #define USE_SHARED_EEPROM 1 +#endif diff --git a/Marlin/src/HAL/GD32_MFL/inc/Conditionals_type.h b/Marlin/src/HAL/GD32_MFL/inc/Conditionals_type.h new file mode 100644 index 0000000000..92cc457df5 --- /dev/null +++ b/Marlin/src/HAL/GD32_MFL/inc/Conditionals_type.h @@ -0,0 +1,22 @@ +/** + * 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 . + * + */ +#pragma once diff --git a/Marlin/src/HAL/GD32_MFL/inc/SanityCheck.h b/Marlin/src/HAL/GD32_MFL/inc/SanityCheck.h new file mode 100644 index 0000000000..366765dcd5 --- /dev/null +++ b/Marlin/src/HAL/GD32_MFL/inc/SanityCheck.h @@ -0,0 +1,97 @@ +/** + * 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 . + * + */ +#pragma once + +// Test MFL GD32 specific configuration values for errors at compile-time. +#if ENABLED(SDCARD_EEPROM_EMULATION) && !HAS_MEDIA + #undef SDCARD_EEPROM_EMULATION // avoid additional error noise + #if USE_FALLBACK_EEPROM + #warning "EEPROM type not specified. Fallback is SDCARD_EEPROM_EMULATION." + #endif + #error "SDCARD_EEPROM_EMULATION requires SDSUPPORT. Enable SDSUPPORT or choose another EEPROM emulation." +#endif + +#if ENABLED(FLASH_EEPROM_LEVELING) + #error "FLASH_EEPROM_LEVELING is not supported on GD32." +#endif + +#if ENABLED(SERIAL_STATS_MAX_RX_QUEUED) + #error "SERIAL_STATS_MAX_RX_QUEUED is not supported on GD32." +#elif ENABLED(SERIAL_STATS_DROPPED_RX) + #error "SERIAL_STATS_DROPPED_RX is not supported on GD32." +#endif + +#if TEMP_SENSOR_SOC && defined(ATEMP) && TEMP_SOC_PIN != ATEMP + #error "TEMP_SENSOR_SOC requires 'TEMP_SOC_PIN ATEMP' on GD32" +#endif + +// Check for common serial pin conflicts +#define _CHECK_SERIAL_PIN(N) (( \ + BTN_EN1 == N || BTN_EN2 == N || DOGLCD_CS == N || HEATER_BED_PIN == N || FAN0_PIN == N || \ + SDIO_D2_PIN == N || SDIO_D3_PIN == N || SDIO_CK_PIN == N || SDIO_CMD_PIN == N || \ + Y_STEP_PIN == N || Y_ENABLE_PIN == N || E0_ENABLE_PIN == N || POWER_LOSS_PIN == N \ + )) + +#define CHECK_SERIAL_PIN(T, N) defined(UART##N##_##T##_PIN) && _CHECK_SERIAL_PIN(UART##N##_##T##_PIN) + +#if SERIAL_IN_USE(0) + #if CHECK_SERIAL_PIN(TX, 0) + #error "Serial Port 0 TX IO pins conflict with another pin on the board." + #endif + #if CHECK_SERIAL_PIN(RX, 0) + #error "Serial Port 0 RX IO pins conflict with another pin on the board." + #endif +#endif +#if SERIAL_IN_USE(1) + #if CHECK_SERIAL_PIN(TX, 1) + #error "Serial Port 1 TX IO pins conflict with another pin on the board." + #endif + #if CHECK_SERIAL_PIN(RX, 1) + #error "Serial Port 1 RX IO pins conflict with another pin on the board." + #endif +#endif +#if SERIAL_IN_USE(2) + #if CHECK_SERIAL_PIN(TX, 2) + #error "Serial Port 2 TX IO pins conflict with another pin on the board." + #endif + #if CHECK_SERIAL_PIN(RX, 2) + #error "Serial Port 2 RX IO pins conflict with another pin on the board." + #endif +#endif +#if SERIAL_IN_USE(3) + #if CHECK_SERIAL_PIN(TX, 3) + #error "Serial Port 3 TX IO pins conflict with another pin on the board." + #endif + #if CHECK_SERIAL_PIN(RX, 3) + #error "Serial Port 3 RX IO pins conflict with another pin on the board." + #endif +#endif +#if SERIAL_IN_USE(4) + #if CHECK_SERIAL_PIN(TX, 4) + #error "Serial Port 4 TX IO pins conflict with another pin on the board." + #endif + #if CHECK_SERIAL_PIN(RX, 4) + #error "Serial Port 4 RX IO pins conflict with another pin on the board." + #endif +#endif +#undef CHECK_SERIAL_PIN +#undef _CHECK_SERIAL_PIN diff --git a/Marlin/src/HAL/GD32_MFL/pinsDebug.h b/Marlin/src/HAL/GD32_MFL/pinsDebug.h new file mode 100644 index 0000000000..be7e4ce1ba --- /dev/null +++ b/Marlin/src/HAL/GD32_MFL/pinsDebug.h @@ -0,0 +1,104 @@ +/** + * 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 . + * + */ +#pragma once + +/** + * Pins Debugging for GD32 + * + * - NUMBER_PINS_TOTAL + * - MULTI_NAME_PAD + * - getPinByIndex(index) + * - printPinNameByIndex(index) + * - getPinIsDigitalByIndex(index) + * - digitalPinToAnalogIndex(pin) + * - getValidPinMode(pin) + * - isValidPin(pin) + * - isAnalogPin(pin) + * - digitalRead_mod(pin) + * - pwm_status(pin) + * - printPinPWM(pin) + * - printPinPort(pin) + * - printPinNumber(pin) + * - printPinAnalog(pin) + */ + +#include "../../inc/MarlinConfig.h" +#include +#include +#include + +#ifndef TOTAL_PIN_COUNT + #error "Expected TOTAL_PIN_COUNT not found." +#endif + +#define NUM_DIGITAL_PINS TOTAL_PIN_COUNT +#define NUMBER_PINS_TOTAL TOTAL_PIN_COUNT + +#define getPinByIndex(x) pin_t(pin_array[x].pin) +#define isValidPin(P) WITHIN(P, 0, (NUM_DIGITAL_PINS - 1)) +#define digitalRead_mod(P) extDigitalRead(P) +#define printPinNumber(P) do { sprintf_P(buffer, PSTR("%3hd "), pin_t(P)); SERIAL_ECHO(buffer); } while (0) +#define printPinAnalog(P) do { sprintf_P(buffer, PSTR(" (A%2d) "), pin_t(getAdcChannelFromPin(P))); SERIAL_ECHO(buffer); } while (0) +#define printPinNameByIndex(x) do { sprintf_P(buffer, PSTR("%-" STRINGIFY(MAX_NAME_LENGTH) "s"), pin_array[x].name); SERIAL_ECHO(buffer); } while (0) + +#define MULTI_NAME_PAD 21 // Space needed to be pretty if not first name assigned to a pin + +#ifndef M43_NEVER_TOUCH + #define M43_NEVER_TOUCH(x) WITHIN(x, 9, 10) // SERIAL pins: PA9(TX) PA10(RX) +#endif + +bool isAnalogPin(const pin_t pin) { + if (!isValidPin(pin)) return false; + + if (getAdcChannel(pin) != adc::ADC_Channel::INVALID) { + const PortPinPair& pp = port_pin_map[pin]; + auto& instance = gpio::GPIO::get_instance(pp.port).value(); + return instance.get_pin_mode(pp.pin) == gpio::Pin_Mode::ANALOG && !M43_NEVER_TOUCH(pin); + } + + return false; +} + +bool getValidPinMode(const pin_t pin) { + if (!isValidPin(pin)) return false; + + const PortPinPair& pp = port_pin_map[pin]; + auto& instance = gpio::GPIO::get_instance(pp.port).value(); + gpio::Pin_Mode mode = instance.get_pin_mode(pp.pin); + + return mode != gpio::Pin_Mode::ANALOG && mode != gpio::Pin_Mode::INPUT_FLOATING && + mode != gpio::Pin_Mode::INPUT_PULLUP && mode != gpio::Pin_Mode::INPUT_PULLDOWN; +} + +bool getPinIsDigitalByIndex(const int16_t index) { + const pin_t pin = getPinByIndex(index); + return (!isAnalogPin(pin)); +} + +int8_t digitalPinToAnalogIndex(const pin_t pin) { + if (!isValidPin(pin) || !isAnalogPin(pin)) return -1; + return pin; // Analog and digital pin indexes are shared +} + +bool pwm_status(const pin_t pin) { return false; } +void printPinPWM(const pin_t pin) { /* TODO */ } +void printPinPort(const pin_t pin) { /* TODO */ } diff --git a/Marlin/src/HAL/GD32_MFL/sd/SDCard.cpp b/Marlin/src/HAL/GD32_MFL/sd/SDCard.cpp new file mode 100644 index 0000000000..2e7ba4dfd9 --- /dev/null +++ b/Marlin/src/HAL/GD32_MFL/sd/SDCard.cpp @@ -0,0 +1,1022 @@ +// +// MFL gd32f30x SDCARD using DMA through SDIO in C++ +// +// Copyright (C) 2025 B. Mourit +// +// This software is free software: you can redistribute it and/or modify it under the terms of the +// GNU Lesser General Public License as published by the Free Software Foundation, +// either version 3 of the License, or (at your option) any later version. +// +// This software 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 Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License along with this software. +// If not, see . +// + +#include "../../platforms.h" + +#ifdef ARDUINO_ARCH_MFL + +#include "../../../inc/MarlinConfig.h" +#include "../../shared/Delay.h" + +#include "SDCard.h" +#include +#include + +namespace sdio { + +auto CardDMA::get_instance() -> CardDMA& { + static CardDMA instance; + return instance; +} + +CardDMA::CardDMA() : + sdcard_csd_{0U, 0U, 0U, 0U}, + sdcard_cid_{0U, 0U, 0U, 0U}, + sdcard_scr_{0U, 0U}, + desired_clock_(Default_Desired_Clock), + total_bytes_(0U), + sdio_(SDIO::get_instance()), + config_(sdio_.get_config()), + dmaBase_(dma::DMA_Base::DMA1_BASE), + dmaChannel_(dma::DMA_Channel::CHANNEL3), + dma_(dma::DMA::get_instance(dmaBase_, dmaChannel_).value()), + sdcard_rca_(0U), + transfer_error_(SDIO_Error_Type::OK), + interface_version_(Interface_Version::UNKNOWN), + card_type_(Card_Type::UNKNOWN), + current_state_(Operational_State::READY), + transfer_end_(false), + multiblock_(false), + is_rx_(false) +{ +} + +// Initialize card and put in standby state +auto CardDMA::init() -> SDIO_Error_Type { + // Reset SDIO peripheral + sdio_.reset(); + sync_domains(); + + // Initialize SDIO peripheral + // If no SDIO_Config structure is provided the default is used. + // The default provides the parameters for initialization + // using a very low clock speed (typically <= 400KHz). + sdio_.init(); + sync_domains(); + + SDIO_Error_Type result = begin_startup_procedure(); + if (result != SDIO_Error_Type::OK) { + return result; + } + + return card_init(); +} + +// Startup command procedure according to SDIO specification +auto CardDMA::begin_startup_procedure() -> SDIO_Error_Type { + sdio_.set_power_mode(Power_Control::POWER_ON); + sdio_.set_clock_enable(true); + sync_domains(); + + // CMD0 (GO_IDLE_STATE) + if (send_command_and_check(Command_Index::CMD0, 0, Command_Response::RSP_NONE, Wait_Type::WT_NONE, [this]() { + return this->get_command_sent_result(); + }) != SDIO_Error_Type::OK) { + return SDIO_Error_Type::CMD0_FAILED; + } + + // CMD8 + if (send_command_and_check(Command_Index::CMD8, Check_Pattern, Command_Response::RSP_SHORT, Wait_Type::WT_NONE, [this]() { + return this->get_r7_result(); + }) != SDIO_Error_Type::OK) { + // V1.0 card + // CMD0 (GO_IDLE_STATE) + interface_version_ = Interface_Version::INTERFACE_V1_1; + if (send_command_and_check(Command_Index::CMD0, 0, Command_Response::RSP_NONE, Wait_Type::WT_NONE, [this]() { + return this->get_command_sent_result(); + }) != SDIO_Error_Type::OK) { + return SDIO_Error_Type::CMD0_FAILED; + } + } else { + // V2.0 card + // CMD55 + interface_version_ = Interface_Version::INTERFACE_V2_0; + if (send_command_and_check(Command_Index::CMD55, 0, Command_Response::RSP_SHORT, Wait_Type::WT_NONE, [this, cmd = Command_Index::CMD55]() { + return get_r1_result(cmd); + }) != SDIO_Error_Type::OK) { + return SDIO_Error_Type::CMD55_FAILED; + } + } + + if (send_command_and_check(Command_Index::CMD55, 0, Command_Response::RSP_SHORT, Wait_Type::WT_NONE, [this, cmd = Command_Index::CMD55]() { + return get_r1_result(cmd); + }) != SDIO_Error_Type::OK) { + return SDIO_Error_Type::CMD55_FAILED; + } + + return validate_voltage(); +} + +// Voltage validation +auto CardDMA::validate_voltage() -> SDIO_Error_Type { + uint32_t response = 0U; + uint32_t count = 0U; + bool valid_voltage = false; + + while (count < Max_Voltage_Checks && valid_voltage == false) { + if (send_command_and_check(Command_Index::CMD55, 0, Command_Response::RSP_SHORT, + Wait_Type::WT_NONE, [this, cmd = Command_Index::CMD55]() { + return get_r1_result(cmd); + }) != SDIO_Error_Type::OK) { + return SDIO_Error_Type::CMD55_FAILED; + } + + if (send_command_and_check(Command_Index::ACMD41, Voltage_Window | SDCARD_HCS | Switch_1_8V_Capacity, + Command_Response::RSP_SHORT, Wait_Type::WT_NONE, [this, cmd = Command_Index::INVALID, index = false, crc = true]() { + return check_sdio_status(cmd, index, crc); + }) != SDIO_Error_Type::OK) { + return SDIO_Error_Type::ACMD41_FAILED; + } + response = sdio_.get_response(Response_Type::RESPONSE0); + valid_voltage = ((response >> 31U) == 1U); + count++; + } + + if (count >= Max_Voltage_Checks) { + return SDIO_Error_Type::INVALID_VOLTAGE; + } + + card_type_ = (response & SDCARD_HCS) ? Card_Type::SDCARD_HIGH_CAPACITY : Card_Type::SDCARD_STANDARD_CAPACITY; + + #if ENABLED(MARLIN_DEV_MODE) + if (card_type_ == Card_Type::SDCARD_HIGH_CAPACITY) { + SERIAL_ECHOPGM("\n SDHC!"); + } else { + SERIAL_ECHOPGM("\n SDSC!"); + } + #endif + + return SDIO_Error_Type::OK; +} + +// Shutdown +void CardDMA::begin_shutdown_procedure() { + sdio_.set_power_mode(Power_Control::POWER_OFF); +} + +// Initialize card +auto CardDMA::card_init() -> SDIO_Error_Type { + if (sdio_.get_power_mode() == static_cast(Power_Control::POWER_OFF)) { + return SDIO_Error_Type::INVALID_OPERATION; + } + + // Skip CID/RCA for IO cards + if (card_type_ != Card_Type::SD_IO_CARD) { + if (send_command_and_check(Command_Index::CMD2, 0U, Command_Response::RSP_LONG, Wait_Type::WT_NONE, + [this, cmd = Command_Index::INVALID, index = false, crc = true]() { + return check_sdio_status(cmd, index, crc); + }) != SDIO_Error_Type::OK) { + return SDIO_Error_Type::CMD2_FAILED; + } + // Store CID + store_cid(); + + // Get RCA + uint16_t r6_rca; + if (send_command_and_check(Command_Index::CMD3, 0U, Command_Response::RSP_SHORT, Wait_Type::WT_NONE, + [this, cmd = Command_Index::CMD3, rca = &r6_rca]() { + return get_r6_result(cmd, rca); + }) != SDIO_Error_Type::OK) { + return SDIO_Error_Type::CMD3_FAILED; + } + // Store RCA + sdcard_rca_ = r6_rca; + if (send_command_and_check(Command_Index::CMD9, static_cast(sdcard_rca_ << RCA_Shift), + Command_Response::RSP_LONG, Wait_Type::WT_NONE, + [this, cmd = Command_Index::INVALID, index = false, crc = true]() { + return check_sdio_status(cmd, index, crc); + }) != SDIO_Error_Type::OK) { + return SDIO_Error_Type::CMD9_FAILED; + } + // Store CSD + store_csd(); + } + + Card_Info card_info; + SDIO_Error_Type result = get_card_specific_data(&card_info); + if (result != SDIO_Error_Type::OK) { + return result; + } + + if (select_deselect() != SDIO_Error_Type::OK) { + return SDIO_Error_Type::SELECT_DESELECT_FAILED; + } + + return SDIO_Error_Type::OK; +} + +auto CardDMA::store_cid() -> SDIO_Error_Type { + // Store the CID register values + sdcard_cid_[0] = sdio_.get_response(Response_Type::RESPONSE0); + sdcard_cid_[1] = sdio_.get_response(Response_Type::RESPONSE1); + sdcard_cid_[2] = sdio_.get_response(Response_Type::RESPONSE2); + sdcard_cid_[3] = sdio_.get_response(Response_Type::RESPONSE3); + + return SDIO_Error_Type::OK; +} + +auto CardDMA::store_csd() -> SDIO_Error_Type { + // Store the CSD register values + sdcard_csd_[0] = sdio_.get_response(Response_Type::RESPONSE0); + sdcard_csd_[1] = sdio_.get_response(Response_Type::RESPONSE1); + sdcard_csd_[2] = sdio_.get_response(Response_Type::RESPONSE2); + sdcard_csd_[3] = sdio_.get_response(Response_Type::RESPONSE3); + + return SDIO_Error_Type::OK; +} + +auto CardDMA::set_hardware_bus_width(Bus_Width width) -> SDIO_Error_Type { + if (card_type_ == Card_Type::SD_MMC || width == Bus_Width::WIDTH_8BIT) { + return SDIO_Error_Type::UNSUPPORTED_FUNCTION; + } + + // Retrieve SCR + SDIO_Error_Type result = get_scr(sdcard_rca_, sdcard_scr_); + if (result != SDIO_Error_Type::OK) { + return result; + } + + // Check and set bus width + // This function is only used to set a higher width than the default 1bit + // so no 1bit configuration logic is required. + if (width == Bus_Width::WIDTH_4BIT) { + // Send CMD55 (APP_CMD) + if (send_command_and_check(Command_Index::CMD55, static_cast(sdcard_rca_ << RCA_Shift), Command_Response::RSP_SHORT, + Wait_Type::WT_NONE, [this, cmd = Command_Index::CMD55]() { + return get_r1_result(cmd); + }) != SDIO_Error_Type::OK) { + return SDIO_Error_Type::CMD55_FAILED; + } + + // Send ACMD6 (SET_BUS_WIDTH) + if (send_command_and_check(Command_Index::ACMD6, 2U, Command_Response::RSP_SHORT, + Wait_Type::WT_NONE, [this, cmd = Command_Index::ACMD6]() { + return get_r1_result(cmd); + }) != SDIO_Error_Type::OK) { + return SDIO_Error_Type::ACMD6_FAILED; + } + + #if ENABLED(MARLIN_DEV_MODE) + SERIAL_ECHOPGM("\n wide bus set!"); + #endif + sdio_.set_bus_width(Bus_Width::WIDTH_4BIT); + + return SDIO_Error_Type::OK; + } + + return SDIO_Error_Type::UNSUPPORTED_FUNCTION; +} + +auto CardDMA::read(uint8_t* buf, uint32_t address, uint32_t count) -> SDIO_Error_Type { + if (current_state_ == Operational_State::READY) { + transfer_error_ = SDIO_Error_Type::OK; + current_state_ = Operational_State::BUSY; + is_rx_ = true; + multiblock_ = (count > 1); + + sdio_.clear_data_state_machine(Transfer_Direction::CARD_TO_SDIO); + + // Enable the interrupts + sdio_.set_interrupt_enable(Interrupt_Type::DTCRCERRIE, true); + sdio_.set_interrupt_enable(Interrupt_Type::DTTMOUTIE, true); + sdio_.set_interrupt_enable(Interrupt_Type::RXOREIE, true); + sdio_.set_interrupt_enable(Interrupt_Type::DTENDIE, true); + sdio_.set_interrupt_enable(Interrupt_Type::STBITEIE, true); + + total_bytes_ = BLOCK_SIZE * count; + + // Set DMA transfer parameters + set_dma_parameters(buf, (total_bytes_ / 4U), false); + sdio_.set_dma_enable(true); + + if (card_type_ != Card_Type::SDCARD_HIGH_CAPACITY) { + address *= 512U; + } + + // CMD16 set card block size + if (send_command_and_check(Command_Index::CMD16, BLOCK_SIZE, Command_Response::RSP_SHORT, + Wait_Type::WT_NONE, [this, cmd = Command_Index::CMD16]() { + return get_r1_result(cmd); + }) != SDIO_Error_Type::OK) { + sdio_.clear_multiple_interrupt_flags(clear_common_flags); + current_state_ = Operational_State::READY; + return SDIO_Error_Type::CMD16_FAILED; + } + + Block_Size block_size = get_data_block_size_index(BLOCK_SIZE); + + sdio_.set_data_state_machine_and_send(Data_Timeout, total_bytes_, block_size, + Transfer_Mode::BLOCK, Transfer_Direction::CARD_TO_SDIO, true); + + // CMD17/CMD18 (READ_SINGLE_BLOCK/READ_MULTIPLE_BLOCKS) send read command + Command_Index read_cmd = (count > 1U) ? Command_Index::CMD18 : Command_Index::CMD17; + if (send_command_and_check(read_cmd, address, + Command_Response::RSP_SHORT, Wait_Type::WT_NONE, [this, cmd = read_cmd]() { + return get_r1_result(cmd); + }) != SDIO_Error_Type::OK) { + sdio_.clear_multiple_interrupt_flags(clear_common_flags); + current_state_ = Operational_State::READY; + return (count > 1U) ? SDIO_Error_Type::CMD18_FAILED : SDIO_Error_Type::CMD17_FAILED; + } + return SDIO_Error_Type::OK; + } else { + return SDIO_Error_Type::BUSY; + } +} + +auto CardDMA::write(uint8_t* buf, uint32_t address, uint32_t count) -> SDIO_Error_Type { + // Enable the interrupts + sdio_.set_interrupt_enable(Interrupt_Type::DTCRCERRIE, true); + sdio_.set_interrupt_enable(Interrupt_Type::DTTMOUTIE, true); + sdio_.set_interrupt_enable(Interrupt_Type::STBITEIE, true); + sdio_.set_interrupt_enable(Interrupt_Type::TXUREIE, true); + + if (card_type_ != Card_Type::SDCARD_HIGH_CAPACITY) { + address *= 512U; + } + + // CMD16 + if (send_command_and_check(Command_Index::CMD16, BLOCK_SIZE, Command_Response::RSP_SHORT, + Wait_Type::WT_NONE, [this, cmd = Command_Index::CMD16]() { + return get_r1_result(cmd); + }) != SDIO_Error_Type::OK) { + sdio_.clear_multiple_interrupt_flags(clear_common_flags); + return SDIO_Error_Type::CMD16_FAILED; + } + + // CMD25/CMD24 (WRITE_MULTIPLE_BLOCK/WRITE_BLOCK) send write command + Command_Index write_cmd = (count > 1U) ? Command_Index::CMD25 : Command_Index::CMD24; + if (send_command_and_check(write_cmd, address, Command_Response::RSP_SHORT, + Wait_Type::WT_NONE, [this, cmd = write_cmd]() { + return get_r1_result(cmd); + }) != SDIO_Error_Type::OK) { + sdio_.clear_multiple_interrupt_flags(clear_common_flags); + return (count > 1U) ? SDIO_Error_Type::CMD25_FAILED : SDIO_Error_Type::CMD24_FAILED; + } + + total_bytes_ = BLOCK_SIZE * count; + // Start DMA transfer + set_dma_parameters(buf, (total_bytes_ / 4U), true); + sdio_.set_dma_enable(true); + + sdio_.clear_data_state_machine(Transfer_Direction::SDIO_TO_CARD); + Block_Size block_size = get_data_block_size_index(total_bytes_); + + sdio_.set_data_state_machine_and_send(Data_Timeout, total_bytes_, block_size, + Transfer_Mode::BLOCK, Transfer_Direction::SDIO_TO_CARD, true); + + while (dma_.get_flag(dma::Status_Flags::FLAG_FTFIF) || dma_.get_flag(dma::Status_Flags::FLAG_ERRIF)) { + // Wait for the IRQ handler to clear + } + + return SDIO_Error_Type::OK; +} + +auto CardDMA::erase(uint32_t address_start, uint32_t address_end) -> SDIO_Error_Type { + SDIO_Error_Type result = SDIO_Error_Type::OK; + + // Card command classes CSD + uint8_t temp_byte = static_cast((sdcard_csd_[1] & (0xFFU << 24U)) >> 24U); + uint16_t classes = static_cast(temp_byte << 4U); + temp_byte = static_cast((sdcard_csd_[1] & (0xFFU << 16U)) >> 16U); + classes |= static_cast((temp_byte & 0xF0U) >> 4U); + + if ((classes & (1U << static_cast(Card_Command_Class::ERASE))) == Clear) { + return SDIO_Error_Type::UNSUPPORTED_FUNCTION; + } + + uint32_t delay_time = 120000U / sdio_.get_clock_divider(); + + if (sdio_.get_response(Response_Type::RESPONSE0) & Card_Locked) { + return SDIO_Error_Type::LOCK_UNLOCK_FAILED; + } + + // Size is fixed at 512 bytes for SDHC + if (card_type_ != Card_Type::SDCARD_HIGH_CAPACITY) { + address_start *= 512U; + address_end *= 512U; + } + + if ((card_type_ == Card_Type::SDCARD_STANDARD_CAPACITY) || (card_type_ == Card_Type::SDCARD_HIGH_CAPACITY)) { + // CMD32 (ERASE_WR_BLK_START) + if (send_command_and_check(Command_Index::CMD32, address_start, Command_Response::RSP_SHORT, + Wait_Type::WT_NONE, [this, cmd = Command_Index::CMD32]() { + return get_r1_result(cmd); + }) != SDIO_Error_Type::OK) { + return SDIO_Error_Type::CMD32_FAILED; + } + // CMD33 (ERASE_WR_BLK_END) + if (send_command_and_check(Command_Index::CMD33, address_end, Command_Response::RSP_SHORT, + Wait_Type::WT_NONE, [this, cmd = Command_Index::CMD33]() { + return get_r1_result(cmd); + }) != SDIO_Error_Type::OK) { + return SDIO_Error_Type::CMD33_FAILED; + } + } + + // CMD38 (ERASE) + if (send_command_and_check(Command_Index::CMD38, 0U, Command_Response::RSP_SHORT, + Wait_Type::WT_NONE, [this, cmd = Command_Index::CMD38]() { + return get_r1_result(cmd); + }) != SDIO_Error_Type::OK) { + return SDIO_Error_Type::CMD38_FAILED; + } + + // Loop until the counter reaches the calculated time + for (uint32_t count = 0U; count < delay_time; count++) {} + + Card_State card_state; + result = get_card_state(&card_state); + while ((result == SDIO_Error_Type::OK) && ((card_state == Card_State::PROGRAMMING) || (card_state == Card_State::RECEIVE_DATA))) { + result = get_card_state(&card_state); + } + + return result; +} + +void CardDMA::handle_interrupts() { + transfer_error_ = SDIO_Error_Type::OK; + + if (sdio_.get_interrupt_flag(Interrupt_Flags::FLAG_INTR_DTEND)) { + sdio_.clear_interrupt_flag(Clear_Flags::FLAG_DTENDC); + // Disable all interrupts + disable_all_interrupts(); + sdio_.set_data_state_machine_enable(false); + + if (multiblock_ && !is_rx_) { + transfer_error_ = stop_transfer(); + if (transfer_error_ != SDIO_Error_Type::OK) { + return; + } + } + + if (!is_rx_) { + sdio_.set_dma_enable(false); + current_state_ = Operational_State::READY; + } + } else if (sdio_.get_interrupt_flag(Interrupt_Flags::FLAG_INTR_DTCRCERR) || + sdio_.get_interrupt_flag(Interrupt_Flags::FLAG_INTR_DTTMOUT) || + sdio_.get_interrupt_flag(Interrupt_Flags::FLAG_INTR_STBITE) || + sdio_.get_interrupt_flag(Interrupt_Flags::FLAG_INTR_TXURE) || + sdio_.get_interrupt_flag(Interrupt_Flags::FLAG_INTR_RXORE)) { + + if (sdio_.get_interrupt_flag(Interrupt_Flags::FLAG_INTR_DTCRCERR)) { + transfer_error_ = SDIO_Error_Type::DATA_CRC_ERROR; + } + if (sdio_.get_interrupt_flag(Interrupt_Flags::FLAG_INTR_DTTMOUT)) { + transfer_error_ = SDIO_Error_Type::DATA_TIMEOUT; + } + if (sdio_.get_interrupt_flag(Interrupt_Flags::FLAG_INTR_STBITE)) { + transfer_error_ = SDIO_Error_Type::START_BIT_ERROR; + } + if (sdio_.get_interrupt_flag(Interrupt_Flags::FLAG_INTR_TXURE)) { + transfer_error_ = SDIO_Error_Type::TX_FIFO_UNDERRUN; + } + if (sdio_.get_interrupt_flag(Interrupt_Flags::FLAG_INTR_RXORE)) { + transfer_error_ = SDIO_Error_Type::RX_FIFO_OVERRUN; + } + sdio_.clear_multiple_interrupt_flags(clear_data_flags); + sdio_.clear_interrupt_flag(Clear_Flags::FLAG_STBITEC); + disable_all_interrupts(); + + dma_.set_transfer_abandon(); + } +} + +auto CardDMA::select_deselect() -> SDIO_Error_Type { + // CMD7 (SELECT/DESELECT_CARD) + if (send_command_and_check(Command_Index::CMD7, static_cast(sdcard_rca_ << RCA_Shift), + Command_Response::RSP_SHORT, Wait_Type::WT_NONE, [this, cmd = Command_Index::CMD7]() { + return get_r1_result(cmd); + }) != SDIO_Error_Type::OK) { + return SDIO_Error_Type::CMD7_FAILED; + } + return SDIO_Error_Type::OK; +} + +auto CardDMA::get_card_interface_status(uint32_t* status) -> SDIO_Error_Type { + if (status == nullptr) return SDIO_Error_Type::INVALID_PARAMETER; + + // CMD13 (SEND_STATUS) + if (send_command_and_check(Command_Index::CMD13, static_cast(sdcard_rca_ << RCA_Shift), + Command_Response::RSP_SHORT, Wait_Type::WT_NONE, [this, cmd = Command_Index::CMD13]() { + return get_r1_result(cmd); + }) != SDIO_Error_Type::OK) { + return SDIO_Error_Type::CMD13_FAILED; + } + + *status = sdio_.get_response(Response_Type::RESPONSE0); + + return SDIO_Error_Type::OK; +} + +auto CardDMA::get_sdcard_status(uint32_t* status) -> SDIO_Error_Type { + uint32_t count = 0U; + + // CMD16 (SET_BLOCKLEN) + if (send_command_and_check(Command_Index::CMD16, 64U, + Command_Response::RSP_SHORT, Wait_Type::WT_NONE, [this, cmd = Command_Index::CMD16]() { + return get_r1_result(cmd); + }) != SDIO_Error_Type::OK) { + return SDIO_Error_Type::CMD16_FAILED; + } + + // CMD55 (APP_CMD) + if (send_command_and_check(Command_Index::CMD55, static_cast(sdcard_rca_ << RCA_Shift), + Command_Response::RSP_SHORT, Wait_Type::WT_NONE, [this, cmd = Command_Index::CMD55]() { + return get_r1_result(cmd); + }) != SDIO_Error_Type::OK) { + return SDIO_Error_Type::CMD55_FAILED; + } + + sdio_.set_data_state_machine_and_send(Data_Timeout, 64U, Block_Size::BYTES_64, Transfer_Mode::BLOCK, Transfer_Direction::CARD_TO_SDIO, true); + + // ACMD13 (SD_STATUS) + if (send_command_and_check(Command_Index::ACMD13, 0U, + Command_Response::RSP_SHORT, Wait_Type::WT_NONE, [this, cmd = Command_Index::ACMD13]() { + return get_r1_result(cmd); + }) != SDIO_Error_Type::OK) { + return SDIO_Error_Type::ACMD13_FAILED; + } + + while (!sdio_.check_scr_flags()) { + if (sdio_.get_flag(Status_Flags::FLAG_RFH)) { + for (count = 0U; count < FIFO_Half_Words; count++) { + *(status + count) = sdio_.read_fifo_word(); + } + status += FIFO_Half_Words; + } + + //SDIO_Error_Type result = SDIO_Error_Type::OK; + if (sdio_.get_flag(Status_Flags::FLAG_DTCRCERR)) { + sdio_.clear_flag(Clear_Flags::FLAG_DTCRCERRC); + return SDIO_Error_Type::DATA_CRC_ERROR; + } else if (sdio_.get_flag(Status_Flags::FLAG_DTTMOUT)) { + sdio_.clear_flag(Clear_Flags::FLAG_DTTMOUTC); + return SDIO_Error_Type::DATA_TIMEOUT; + } else if (sdio_.get_flag(Status_Flags::FLAG_RXORE)) { + sdio_.clear_flag(Clear_Flags::FLAG_RXOREC); + return SDIO_Error_Type::RX_FIFO_OVERRUN; + } else if (sdio_.get_flag(Status_Flags::FLAG_STBITE)) { + sdio_.clear_flag(Clear_Flags::FLAG_STBITEC); + return SDIO_Error_Type::START_BIT_ERROR; + } + while (sdio_.get_flag(Status_Flags::FLAG_RXDTVAL)) { + *status = sdio_.read_fifo_word(); + ++status; + } + + sdio_.clear_multiple_interrupt_flags(clear_data_flags); + status -= 16U; + for (count = 0U; count < 16U; count++) { + status[count] = ((status[count] & 0xFFU) << 24U) | + ((status[count] & (0xFFU << 8U)) << 8U) | + ((status[count] & (0xFFU << 16U)) >> 8U) | + ((status[count] & (0xFFU << 24U)) >> 24U); + } + } + + return SDIO_Error_Type::OK; +} + +void CardDMA::check_dma_complete() { + while ((dma_.get_flag(dma::Status_Flags::FLAG_FTFIF)) || (dma_.get_flag(dma::Status_Flags::FLAG_ERRIF))) { + // Wait for the IRQ handler to clear + } +} + +auto CardDMA::stop_transfer() -> SDIO_Error_Type { + // CMD12 (STOP_TRANSMISSION) + if (send_command_and_check(Command_Index::CMD12, 0, Command_Response::RSP_SHORT, Wait_Type::WT_NONE, [this, cmd = Command_Index::CMD12]() { + return get_r1_result(cmd); + }) != SDIO_Error_Type::OK) { + return SDIO_Error_Type::CMD12_FAILED; + } + return SDIO_Error_Type::OK; +} + +auto CardDMA::get_transfer_state() -> Transfer_State { + Transfer_State transfer_state = Transfer_State::IDLE; + if (sdio_.get_flag(Status_Flags::FLAG_TXRUN) | sdio_.get_flag(Status_Flags::FLAG_RXRUN)) { + transfer_state = Transfer_State::BUSY; + } + + return transfer_state; +} + +[[nodiscard]] auto CardDMA::get_card_capacity() const -> uint32_t { + auto extract_bits = [](uint32_t value, uint8_t start_bit, uint8_t length) -> uint32_t { + return (value >> start_bit) & ((1U << length) - 1U); + }; + + uint32_t capacity = 0U; + uint32_t device_size = 0U; + + if (card_type_ == Card_Type::SDCARD_STANDARD_CAPACITY) { + // Extract fields from CSD data using bit manipulation + uint8_t device_size_high = static_cast(extract_bits(sdcard_csd_[1], 8U, 2U)); // Bits [73:72] + uint8_t device_size_mid = static_cast(extract_bits(sdcard_csd_[1], 0U, 8U)); // Bits [71:64] + uint8_t device_size_low = static_cast(extract_bits(sdcard_csd_[2], 24U, 2U)); // Bits [63:62] + + device_size = static_cast((device_size_high) << 10U) | + static_cast((device_size_mid) << 2U) | + static_cast((device_size_low)); + + uint8_t device_size_multiplier_high = static_cast(extract_bits(sdcard_csd_[2], 16U, 2U)); // Bits [49:48] + uint8_t device_size_multiplier_low = static_cast(extract_bits(sdcard_csd_[2], 8U, 1U)); // Bit [47] + uint8_t device_size_multiplier = static_cast((device_size_multiplier_high << 1U) | device_size_multiplier_low); + uint8_t read_block_length = static_cast(extract_bits(sdcard_csd_[1], 16U, 4U)); // Bits [83:80] + + // Capacity = (device_size + 1) * MULT * BLOCK_LEN + uint32_t mult = static_cast(1U << (device_size_multiplier + 2U)); // MULT = 2 ^ (C_SIZE_MULT + 2) + uint32_t block_length = static_cast(1U << read_block_length); // BLOCK_LEN = 2 ^ READ_BL_LEN + + capacity = (device_size + 1U) * mult * block_length; + capacity /= KILOBYTE; // Convert capacity to kilobytes + + } else if (card_type_ == Card_Type::SDCARD_HIGH_CAPACITY) { + // High-capacity card calculation + uint8_t device_size_high = static_cast(extract_bits(sdcard_csd_[1], 0U, 6U)); // Bits [69:64] + uint8_t device_size_mid = static_cast(extract_bits(sdcard_csd_[2], 24U, 8U)); // Bits [55:48] + uint8_t device_size_low = static_cast(extract_bits(sdcard_csd_[2], 16U, 8U)); // Bits [47:40] + + device_size = static_cast((device_size_high) << 16U) | + static_cast((device_size_mid) << 8U) | + static_cast(device_size_low); + + // Capacity in kilobytes + capacity = (device_size + 1U) * BLOCK_SIZE; + } + + return capacity; +} + +auto CardDMA::get_card_specific_data(Card_Info* info) -> SDIO_Error_Type { + if (info == nullptr) return SDIO_Error_Type::INVALID_PARAMETER; + + // Store basic card information + info->type = card_type_; + info->relative_address = sdcard_rca_; + + // Helper function to convert 32-bit registers to byte array + auto convert_registers_to_bytes = [](const uint32_t* registers, uint8_t* bytes, size_t reg_count) { + for (size_t i = 0U; i < reg_count; ++i) { + for (size_t j = 0U; j < 4U; ++j) { + bytes[i * 4U + j] = (registers[i] >> (24U - j * 8U)) & 0xFFU; + } + } + }; + + // Process CID data + uint8_t cid_bytes[16]; + convert_registers_to_bytes(sdcard_cid_, cid_bytes, 4); + + info->cid = { + .manufacture_id = cid_bytes[0], + .oem_id = static_cast( + (cid_bytes[1] << 8U) | + cid_bytes[2] + ), + .name0 = static_cast( + (cid_bytes[3] << 24U) | + (cid_bytes[4] << 16U) | + (cid_bytes[5] << 8U) | + cid_bytes[6] + ), + .name1 = cid_bytes[7], + .revision = cid_bytes[8], + .serial_number = static_cast( + (cid_bytes[9] << 24U) | + (cid_bytes[10] << 16U) | + (cid_bytes[11] << 8U) | + cid_bytes[12] + ), + .manufacture_date = static_cast( + ((cid_bytes[13] & 0x0FU) << 8U) | + cid_bytes[14] + ), + .checksum = static_cast(((cid_bytes[15] & 0xFEU) >> 1U)) + }; + + // Process CSD data + uint8_t csd_bytes[16]; + convert_registers_to_bytes(sdcard_csd_, csd_bytes, 4U); + + // Fill common CSD fields + info->csd = { + .transfer_speed = csd_bytes[3], + .card_command_class = static_cast((csd_bytes[4] << 4U) | ((csd_bytes[5] & 0xF0U) >> 4U)), + }; + + // Process card-type specific CSD fields and calculate capacity + if (card_type_ == Card_Type::SDCARD_STANDARD_CAPACITY) { + process_sdsc_specific_csd(info, csd_bytes); + } else if (card_type_ == Card_Type::SDCARD_HIGH_CAPACITY) { + process_sdhc_specific_csd(info, csd_bytes); + } + + // Fill remaining common CSD fields + process_common_csd_tail(info, csd_bytes); + + return SDIO_Error_Type::OK; +} + +constexpr auto CardDMA::get_data_block_size_index(uint16_t size) -> Block_Size { + if (size < 1 || size > 16384) return Block_Size::BYTES_1; + + // Check if size is a power of two + if ((size & (size - 1)) != 0) return Block_Size::BYTES_1; + + // Count trailing zeros to find the index + uint16_t index = 0; + while ((size >>= 1) != 0) ++index; + + return static_cast(index); +} + +auto CardDMA::get_card_state(Card_State* card_state) -> SDIO_Error_Type { + // CMD13 (SEND_STATUS) + if (send_command_and_check(Command_Index::CMD13, static_cast(sdcard_rca_ << RCA_Shift), + Command_Response::RSP_SHORT, Wait_Type::WT_NONE, [this, cmd = Command_Index::CMD13]() { + return get_r1_result(cmd); + }) != SDIO_Error_Type::OK) { + return SDIO_Error_Type::CMD13_FAILED; + } + + uint32_t response = sdio_.get_response(Response_Type::RESPONSE0); + *card_state = static_cast((response >> 9U) & CardStateMask); + if ((response & All_R1_Error_Bits) == 0U) { + return SDIO_Error_Type::OK; + } + + if (response & All_R1_Error_Bits) { + for (const auto& entry : errorTableR1) { + if (TEST(response, entry.bit_position)) { + return entry.errorType; + } + } + return SDIO_Error_Type::ERROR; + } + + return SDIO_Error_Type::OK; +} + +auto CardDMA::get_command_sent_result() -> SDIO_Error_Type { + constexpr uint32_t MAX_TIMEOUT = 0x00FFFFFFU; + uint32_t timeout = MAX_TIMEOUT; + + // Wait for command sent flag or timeout + while (!sdio_.get_flag(Status_Flags::FLAG_CMDSEND) && timeout) { + --timeout; + } + + // Check if timeout occurred + if (timeout == 0U) { + return SDIO_Error_Type::RESPONSE_TIMEOUT; + } + + // Clear command flags and return success + sdio_.clear_multiple_interrupt_flags(clear_command_flags); + return SDIO_Error_Type::OK; +} + +auto CardDMA::check_sdio_status(Command_Index index, bool check_index, bool ignore_crc) -> SDIO_Error_Type { + // Wait until one of the relevant flags is set + if (!sdio_.wait_cmd_flags()) { + return SDIO_Error_Type::RESPONSE_TIMEOUT; + } + + // Check the cmd received bit first, since noise can sometimes + // cause the timeout bit to get erroneously set + // If cmd was received we can safely ignore other checks + if (sdio_.get_flag(Status_Flags::FLAG_CMDRECV)) { + // If cmd was received, check the index + // Responses that dont do an index check will send an invalid cmd index + if (check_index && (index != Command_Index::INVALID)) { + uint8_t received_idx = sdio_.get_command_index(); + if (received_idx != static_cast(index)) { + sdio_.clear_multiple_interrupt_flags(clear_command_flags); + return SDIO_Error_Type::ILLEGAL_COMMAND; + } + } + + // Command received successfully + sdio_.clear_multiple_interrupt_flags(clear_command_flags); + return SDIO_Error_Type::OK; + } + + // Check for timeout + if (sdio_.get_flag(Status_Flags::FLAG_CMDTMOUT)) { + sdio_.clear_flag(Clear_Flags::FLAG_CMDTMOUTC); + return SDIO_Error_Type::RESPONSE_TIMEOUT; + } + + // Check for CRC error if not ignored + if (!ignore_crc && sdio_.get_flag(Status_Flags::FLAG_CCRCERR)) { + sdio_.clear_flag(Clear_Flags::FLAG_CCRCERRC); + return SDIO_Error_Type::COMMAND_CRC_ERROR; + } + + // Final index check (redundant with the first check, but keeping for safety) + // This code path should rarely be taken due to the earlier checks + if (check_index && (index != Command_Index::INVALID)) { + uint8_t received_idx = sdio_.get_command_index(); + if (received_idx != static_cast(index)) { + sdio_.clear_multiple_interrupt_flags(clear_command_flags); + return SDIO_Error_Type::ILLEGAL_COMMAND; + } + } + + // Clear all flags and return success + sdio_.clear_multiple_interrupt_flags(clear_command_flags); + return SDIO_Error_Type::OK; +} + +auto CardDMA::get_r1_result(Command_Index index) -> SDIO_Error_Type { + SDIO_Error_Type result = check_sdio_status(index, true, false); + if (result != SDIO_Error_Type::OK) return result; + + // Get the R1 response and check for errors + uint32_t response = sdio_.get_response(Response_Type::RESPONSE0); + + if (response & All_R1_Error_Bits) { + for (const auto& entry : errorTableR1) { + if (TEST(response, entry.bit_position)) { + return entry.errorType; + } + } + return SDIO_Error_Type::ERROR; + } + + return SDIO_Error_Type::OK; +} + +auto CardDMA::get_r6_result(Command_Index index, uint16_t* rca) -> SDIO_Error_Type { + SDIO_Error_Type result = check_sdio_status(index, true, false); + if (result != SDIO_Error_Type::OK) return result; + + uint32_t response = sdio_.get_response(Response_Type::RESPONSE0); + + if (response & R6_Error_Bits) { + for (const auto& entry : errorTableR6) { + if (TEST(response, entry.bit_position)) { + return entry.errorType; + } + } + return SDIO_Error_Type::ERROR; + } + *rca = static_cast(response >> 16U); + + return SDIO_Error_Type::OK; +} + +auto CardDMA::get_scr(uint16_t rca, uint32_t* scr) -> SDIO_Error_Type { + uint32_t temp_scr[2] = {0U, 0U}; + uint32_t index_scr = 0U; + + // CMD16 (SET_BLOCKLEN) + if (send_command_and_check(Command_Index::CMD16, 8U, Command_Response::RSP_SHORT, + Wait_Type::WT_NONE, [this, cmd = Command_Index::CMD16]() { + return get_r1_result(cmd); + }) != SDIO_Error_Type::OK) { + return SDIO_Error_Type::CMD16_FAILED; + } + + // CMD55 (APP_CMD) + if (send_command_and_check(Command_Index::CMD55, static_cast(sdcard_rca_ << RCA_Shift), + Command_Response::RSP_SHORT, Wait_Type::WT_NONE, [this, cmd = Command_Index::CMD55]() { + return get_r1_result(cmd); + }) != SDIO_Error_Type::OK) { + return SDIO_Error_Type::CMD55_FAILED; + } + + // Set data parameters + sdio_.set_data_state_machine_and_send(Data_Timeout, 8U, Block_Size::BYTES_8, + Transfer_Mode::BLOCK, Transfer_Direction::CARD_TO_SDIO, true); + + // ACMD51 (SEND_SCR) + if (send_command_and_check(Command_Index::ACMD51, 0U, Command_Response::RSP_SHORT, + Wait_Type::WT_NONE, [this, cmd = Command_Index::ACMD51]() { + return get_r1_result(cmd); + }) != SDIO_Error_Type::OK) { + return SDIO_Error_Type::ACMD51_FAILED; + } + + // Store SCR + while (!sdio_.check_scr_flags()) { + if (sdio_.get_flag(Status_Flags::FLAG_RXDTVAL)) { + temp_scr[index_scr++] = sdio_.read_fifo_word(); + } + } + + // Check for errors + if (sdio_.get_flag(Status_Flags::FLAG_DTTMOUT)) { + sdio_.clear_flag(Clear_Flags::FLAG_DTTMOUTC); + return SDIO_Error_Type::DATA_TIMEOUT; + } + else if (sdio_.get_flag(Status_Flags::FLAG_DTCRCERR)) { + sdio_.clear_flag(Clear_Flags::FLAG_DTCRCERRC); + return SDIO_Error_Type::DATA_CRC_ERROR; + } + else if (sdio_.get_flag(Status_Flags::FLAG_RXORE)) { + sdio_.clear_flag(Clear_Flags::FLAG_RXOREC); + return SDIO_Error_Type::RX_FIFO_OVERRUN; + } + + sdio_.clear_multiple_interrupt_flags(clear_data_flags); + + constexpr uint32_t BYTE0_MASK = 0xFFU; + constexpr uint32_t BYTE1_MASK = 0xFF00U; + constexpr uint32_t BYTE2_MASK = 0xFF0000U; + constexpr uint32_t BYTE3_MASK = 0xFF000000U; + + // Byte-swap the SCR values (convert from big-endian to little-endian) + scr[0] = ((temp_scr[1] & BYTE0_MASK) << 24) | + ((temp_scr[1] & BYTE1_MASK) << 8) | + ((temp_scr[1] & BYTE2_MASK) >> 8) | + ((temp_scr[1] & BYTE3_MASK) >> 24); + + scr[1] = ((temp_scr[0] & BYTE0_MASK) << 24) | + ((temp_scr[0] & BYTE1_MASK) << 8) | + ((temp_scr[0] & BYTE2_MASK) >> 8) | + ((temp_scr[0] & BYTE3_MASK) >> 24); + + return SDIO_Error_Type::OK; +} + +// DMA for rx/tx is always DMA1 channel 3 +void CardDMA::set_dma_parameters(uint8_t* buf, uint32_t count, bool is_write) { + constexpr uint32_t flag_bits = (1U << static_cast(dma::INTF_Bits::GIF3)); + dma_.clear_flags(flag_bits); + + // Disable and reset DMA + dma_.set_channel_enable(false); + dma_.clear_channel(); + + dma_.init(dma::DMA_Config{ + .count = count, + .memory_address = static_cast(reinterpret_cast(buf)), + .peripheral_address = static_cast(reinterpret_cast(sdio_.reg_address(SDIO_Regs::FIFO))), + .peripheral_bit_width = dma::Bit_Width::WIDTH_32BIT, + .memory_bit_width = dma::Bit_Width::WIDTH_32BIT, + .peripheral_increase = dma::Increase_Mode::INCREASE_DISABLE, + .memory_increase = dma::Increase_Mode::INCREASE_ENABLE, + .channel_priority = dma::Channel_Priority::MEDIUM_PRIORITY, + .direction = is_write ? dma::Transfer_Direction::M2P : dma::Transfer_Direction::P2M + }); + + dma_.set_memory_to_memory_enable(false); + dma_.set_circulation_mode_enable(false); + + // Enable DMA interrupts for transfer complete and error + dma_.set_interrupt_enable(dma::Interrupt_Type::INTR_FTFIE, true); + dma_.set_interrupt_enable(dma::Interrupt_Type::INTR_ERRIE, true); + + // Start the DMA channel + dma_.set_channel_enable(true); +} + +auto CardDMA::wait_for_card_ready() -> SDIO_Error_Type { + constexpr uint32_t MAX_TIMEOUT = 0x00FFFFFFU; + uint32_t timeout = MAX_TIMEOUT; + uint32_t response = sdio_.get_response(Response_Type::RESPONSE0); + + // Poll until card is ready for data or timeout occurs + while (((response & static_cast(R1_Status::READY_FOR_DATA)) == 0U) && timeout) { + --timeout; + + // CMD13 (SEND_STATUS) + if (send_command_and_check(Command_Index::CMD13, static_cast(sdcard_rca_ << RCA_Shift), + Command_Response::RSP_SHORT, Wait_Type::WT_NONE, [this, cmd = Command_Index::CMD13]() { + return get_r1_result(cmd); + }) != SDIO_Error_Type::OK) { + return SDIO_Error_Type::CMD13_FAILED; + } + + // Get updated response + response = sdio_.get_response(Response_Type::RESPONSE0); + } + + // Return error if timeout occurred, otherwise success + return timeout ? SDIO_Error_Type::OK : SDIO_Error_Type::ERROR; +} + +} // namespace sdio + +sdio::CardDMA& CardDMA_I = sdio::CardDMA::get_instance(); + +#endif // ARDUINO_ARCH_MFL diff --git a/Marlin/src/HAL/GD32_MFL/sd/SDCard.h b/Marlin/src/HAL/GD32_MFL/sd/SDCard.h new file mode 100644 index 0000000000..de28c40809 --- /dev/null +++ b/Marlin/src/HAL/GD32_MFL/sd/SDCard.h @@ -0,0 +1,222 @@ +// +// MFL gd32f30x SDCARD using DMA through SDIO in C++ +// +// Copyright (C) 2025 B. Mourit +// +// This software is free software: you can redistribute it and/or modify it under the terms of the +// GNU Lesser General Public License as published by the Free Software Foundation, +// either version 3 of the License, or (at your option) any later version. +// +// This software 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 Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License along with this software. +// If not, see . +// +#pragma once + +#include "../../../inc/MarlinConfig.h" + +#include + +namespace sdio { + +class DMA; + +class CardDMA { +public: + static auto get_instance() -> CardDMA&; + + // Initialization + auto init() -> SDIO_Error_Type; + auto card_init() -> SDIO_Error_Type; + + // Startup and shutdown procedures + auto begin_startup_procedure() -> SDIO_Error_Type; + void begin_shutdown_procedure(); + + // Configuration + auto set_hardware_bus_width(Bus_Width width) -> SDIO_Error_Type; + auto send_bus_width_command(uint32_t width_value) -> SDIO_Error_Type; + + // Main read/write/erase functions + auto read(uint8_t* buf, uint32_t address, uint32_t count) -> SDIO_Error_Type; + auto write(uint8_t* buf, uint32_t address, uint32_t count) -> SDIO_Error_Type; + auto erase(uint32_t address_start, uint32_t address_end) -> SDIO_Error_Type; + + // Card select + auto select_deselect() -> SDIO_Error_Type; + + // Status and state + auto get_card_interface_status(uint32_t* status) -> SDIO_Error_Type; + auto get_sdcard_status(uint32_t* status) -> SDIO_Error_Type; + auto get_transfer_state() -> Transfer_State; + auto get_card_state(Card_State* card_state) -> SDIO_Error_Type; + auto check_sdio_status(Command_Index index = Command_Index::INVALID, bool check_index = false, bool ignore_crc = false) -> SDIO_Error_Type; + + // DMA + void set_dma_parameters(uint8_t* buf, uint32_t count, bool is_write); + void check_dma_complete(); + + // Stop transfer + auto stop_transfer() -> SDIO_Error_Type; + + // Card information + auto get_card_specific_data(Card_Info* info) -> SDIO_Error_Type; + constexpr auto get_data_block_size_index(uint16_t size) -> Block_Size; + [[nodiscard]] auto get_card_capacity() const -> uint32_t; + + // SDIO configuration + void sdio_configure(const SDIO_Config config) { sdio_.init(config); } + + // Interrupt handler + void handle_interrupts(); + + // Variable stored parameters + auto get_scr(uint16_t rca, uint32_t* scr) -> SDIO_Error_Type; + auto store_cid() -> SDIO_Error_Type; + auto store_csd() -> SDIO_Error_Type; + + // Inlined accessor methods + auto get_config() -> SDIO_Config& { return config_; } + auto get_dma_instance() -> dma::DMA& { return dma_; } + void set_data_end_interrupt() { sdio_.set_interrupt_enable(Interrupt_Type::DTENDIE, true); } + void set_sdio_dma_enable(bool enable) { sdio_.set_dma_enable(enable); } + auto get_is_sdio_rx() -> bool { return is_rx_; } + void clear_sdio_data_flags() { sdio_.clear_multiple_interrupt_flags(clear_data_flags); } + void clear_sdio_cmd_flags() { sdio_.clear_multiple_interrupt_flags(clear_command_flags); } + void clear_sdio_common_flags() { sdio_.clear_multiple_interrupt_flags(clear_common_flags); } + auto get_state() -> Operational_State { return current_state_; } + void set_state(Operational_State state) { current_state_ = state; } + void set_transfer_error(SDIO_Error_Type error) { transfer_error_ = error; } + void set_transfer_end(bool end) { transfer_end_ = end; }; + + auto set_desired_clock(uint32_t desired_clock, bool wide_bus, bool low_power) -> SDIO_Error_Type { + sdio_.init(SDIO_Config{ + .desired_clock = desired_clock, + .enable_bypass = false, + .enable_powersave = low_power, + .enable_hwclock = false, + .clock_edge = Clock_Edge::RISING_EDGE, + .width = wide_bus ? Bus_Width::WIDTH_4BIT : Bus_Width::WIDTH_1BIT + }); + + sync_domains(); + desired_clock_ = desired_clock; + + return SDIO_Error_Type::OK; + } + +private: + CardDMA(); + + // Prevent copying or assigning + CardDMA(const CardDMA&) = delete; + auto operator=(const CardDMA&) -> CardDMA& = delete; + + // Helper function + auto wait_for_card_ready() -> SDIO_Error_Type; + + // Member variables + alignas(4) uint32_t sdcard_csd_[4]; + alignas(4) uint32_t sdcard_cid_[4]; + alignas(4) uint32_t sdcard_scr_[2]; + uint32_t desired_clock_; + uint32_t total_bytes_; + SDIO& sdio_; + SDIO_Config& config_; + const dma::DMA_Base dmaBase_; + const dma::DMA_Channel dmaChannel_; + dma::DMA& dma_; + uint16_t sdcard_rca_; + SDIO_Error_Type transfer_error_; + Interface_Version interface_version_; + Card_Type card_type_; + Operational_State current_state_; + bool transfer_end_; + bool multiblock_; + bool is_rx_; + + // Private helper methods + auto validate_voltage() -> SDIO_Error_Type; + auto get_command_sent_result() -> SDIO_Error_Type; + auto get_r1_result(Command_Index index) -> SDIO_Error_Type; + auto get_r6_result(Command_Index index, uint16_t* rca) -> SDIO_Error_Type; + auto get_r7_result() -> SDIO_Error_Type { return check_sdio_status(Command_Index::INVALID, false, false); }; + void sync_domains() { delayMicroseconds(8); } + + auto validate_transfer_params(uint32_t* buf, uint16_t size) -> bool { + if (buf == nullptr) return false; + // Size must be > 0, <= 2048 and power of 2 + return size > 0U && size <= 2048U && !(size & (size - 1U)); + } + + void process_sdsc_specific_csd(Card_Info* info, const uint8_t* csd_bytes) { + const uint32_t device_size = ((csd_bytes[6] & 0x3U) << 10) | + (csd_bytes[7] << 2) | + ((csd_bytes[8] >> 6) & 0x3U); + + const uint8_t device_size_multiplier = ((csd_bytes[9] & 0x3U) << 1) | + ((csd_bytes[10] >> 7) & 0x1U); + + // Store calculated values + info->csd.device_size = device_size; + info->csd.device_size_multiplier = device_size_multiplier; + + // Calculate block size and capacity + info->block_size = 1U << info->csd.read_block_length; + info->capacity = (device_size + 1U) * + (1U << (device_size_multiplier + 2U)) * + info->block_size; + } + + void process_sdhc_specific_csd(Card_Info* info, const uint8_t* csd_bytes) { + info->csd.device_size = static_cast((csd_bytes[7] & 0x3FU) << 16) | + static_cast((csd_bytes[8]) << 8) | + static_cast(csd_bytes[9]); + + // Set block size and calculate capacity + info->block_size = BLOCK_SIZE; + info->capacity = static_cast((info->csd.device_size + 1U) * + BLOCK_SIZE * KILOBYTE); + } + + void process_common_csd_tail(Card_Info* info, const uint8_t* csd_bytes) { + // Calculate sector_size + info->csd.sector_size = static_cast(((csd_bytes[9] & 0x3FU) << 1) | + (csd_bytes[10] & 0x80U) >> 7); + + // Calculate speed_factor and write_block_length + info->csd.speed_factor = static_cast((csd_bytes[11] & 0x1CU) >> 2); + info->csd.write_block_length = static_cast(((csd_bytes[11] & 0x3U) << 2) | + ((csd_bytes[12] & 0xC0U) >> 6)); + + // Calculate checksum + info->csd.checksum = static_cast((csd_bytes[15] & 0xFEU) >> 1); + } + + void disable_all_interrupts() { + sdio_.set_interrupt_enable(Interrupt_Type::DTCRCERRIE, false); + sdio_.set_interrupt_enable(Interrupt_Type::DTTMOUTIE, false); + sdio_.set_interrupt_enable(Interrupt_Type::DTENDIE, false); + sdio_.set_interrupt_enable(Interrupt_Type::STBITEIE, false); + sdio_.set_interrupt_enable(Interrupt_Type::TFHIE, false); + sdio_.set_interrupt_enable(Interrupt_Type::RFHIE, false); + sdio_.set_interrupt_enable(Interrupt_Type::TXUREIE, false); + sdio_.set_interrupt_enable(Interrupt_Type::RXOREIE, false); + } + + template + auto send_command_and_check(Command_Index command, uint32_t argument, + Command_Response response, Wait_Type type, CheckFunc check_result) -> SDIO_Error_Type { + sdio_.set_command_state_machine(command, argument, response, type); + sync_domains(); + sdio_.set_command_state_machine_enable(true); + return check_result(); + } +}; + +} // namespace sdio + +extern sdio::CardDMA& CardDMA_I; diff --git a/Marlin/src/HAL/GD32_MFL/sd/sdio.cpp b/Marlin/src/HAL/GD32_MFL/sd/sdio.cpp new file mode 100644 index 0000000000..a474c1977e --- /dev/null +++ b/Marlin/src/HAL/GD32_MFL/sd/sdio.cpp @@ -0,0 +1,231 @@ +/** + * 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 . + * + */ + +#include "../../platforms.h" + +#ifdef ARDUINO_ARCH_MFL + +#include "../../../inc/MarlinConfig.h" + +#if ENABLED(ONBOARD_SDIO) + +#include +#include +#include "SDCard.h" +#include "sdio.h" + +using namespace sdio; + +#define TARGET_CLOCK 6000000U +#define BLOCK_SIZE 512U +#define CARD_TIMEOUT 500 // ms +#define READ_RETRIES 3U + +inline constexpr uint32_t TARGET_SDIO_CLOCK = TARGET_CLOCK; +inline constexpr uint32_t SDIO_BLOCK_SIZE = BLOCK_SIZE; +inline constexpr uint32_t SD_TIMEOUT = CARD_TIMEOUT; +inline constexpr uint8_t SDIO_READ_RETRIES = READ_RETRIES; + +Card_State cardState = Card_State::READY; + +auto SDIO_SetBusWidth(Bus_Width width) -> bool { + return (CardDMA_I.set_hardware_bus_width(width) == SDIO_Error_Type::OK); +} + +void mfl_sdio_init() { + pinOpsPinout(SD_CMD_PinOps, static_cast(SDIO_CMD_PIN)); + pinOpsPinout(SD_CK_PinOps, static_cast(SDIO_CK_PIN)); + pinOpsPinout(SD_DATA0_PinOps, static_cast(SDIO_D0_PIN)); + pinOpsPinout(SD_DATA1_PinOps, static_cast(SDIO_D1_PIN)); + pinOpsPinout(SD_DATA2_PinOps, static_cast(SDIO_D2_PIN)); + pinOpsPinout(SD_DATA3_PinOps, static_cast(SDIO_D3_PIN)); + + NVIC_EnableIRQ(DMA1_Channel3_4_IRQn); + NVIC_EnableIRQ(SDIO_IRQn); +} + +bool SDIO_Init() { + SDIO_Error_Type result = SDIO_Error_Type::OK; + uint8_t retryCount = SDIO_READ_RETRIES; + + mfl_sdio_init(); + + uint8_t retries = retryCount; + for (;;) { + hal.watchdog_refresh(); + result = CardDMA_I.init(); + if (result == SDIO_Error_Type::OK) break; + if (!--retries) return false; + } + + CardDMA_I.set_desired_clock(TARGET_SDIO_CLOCK, false, false); + + retries = retryCount; + for (;;) { + hal.watchdog_refresh(); + if (SDIO_SetBusWidth(Bus_Width::WIDTH_4BIT)) break; + if (!--retries) break; + } + + CardDMA_I.set_desired_clock(TARGET_SDIO_CLOCK, true, true); + + // Fallback + if (!retries) { + mfl_sdio_init(); + retries = retryCount; + for (;;) { + hal.watchdog_refresh(); + result = CardDMA_I.init(); + if (result == SDIO_Error_Type::OK) break; + if (!--retries) return false; + } + CardDMA_I.set_desired_clock(TARGET_SDIO_CLOCK, false, true); + } + + return true; +} + +static bool SDIO_ReadWriteBlock_DMA(uint32_t block, const uint8_t* src, uint8_t* dst) { + hal.watchdog_refresh(); + SDIO_Error_Type result = SDIO_Error_Type::OK; + + // Write + if (src) { + result = CardDMA_I.write(reinterpret_cast(const_cast(src)), block, 1); + } + // Read + else { + result = CardDMA_I.read(dst, block, 1); + } + + if (result != SDIO_Error_Type::OK) { + return false; + } + + millis_t timeout = millis() + SD_TIMEOUT; + while (CardDMA_I.get_state() != sdio::Operational_State::READY) { + if (ELAPSED(millis(), timeout)) { + return false; + } + } + + CardDMA_I.check_dma_complete(); + + timeout = millis() + SD_TIMEOUT; + do { + result = CardDMA_I.get_card_state(&cardState); + if (ELAPSED(millis(), timeout)) { + return false; + } + } while (result == SDIO_Error_Type::OK && cardState != sdio::Card_State::TRANSFER); + + return true; +} + +bool SDIO_ReadBlock(uint32_t block, uint8_t* dst) { + // Check if the address is aligned to 4 bytes + if (reinterpret_cast(dst) & 0x03) { + return false; + } + + uint8_t retries = SDIO_READ_RETRIES; + while (retries--) { + if (SDIO_ReadWriteBlock_DMA(block, nullptr, dst)) { + return true; + } + } + + return false; +} + +bool SDIO_WriteBlock(uint32_t block, const uint8_t* src) { + // Check if the address is aligned to 4 bytes + if (reinterpret_cast(src) & 0x03) { + return false; + } + + uint8_t retries = SDIO_READ_RETRIES; + while (retries--) { + if (SDIO_ReadWriteBlock_DMA(block, src, nullptr)) { + return true; + delay(10); + } + } + + return false; +} + +bool SDIO_IsReady() { + return (CardDMA_I.get_state() == sdio::Operational_State::READY); +} + +uint32_t SDIO_GetCardSize() { + return CardDMA_I.get_card_capacity(); +} + +// DMA interrupt handler +void DMA1_IRQHandler() { + auto& dma_instance = CardDMA_I.get_dma_instance(); + bool is_receive = CardDMA_I.get_is_sdio_rx(); + + // Check for Transfer Complete Interrupt + if (dma_instance.get_interrupt_flag(dma::Interrupt_Flags::INTR_FLAG_FTFIF)) { + dma_instance.set_interrupt_enable(dma::Interrupt_Type::INTR_FTFIE, false); + dma_instance.set_interrupt_enable(dma::Interrupt_Type::INTR_ERRIE, false); + dma_instance.clear_interrupt_flag(dma::Interrupt_Flags::INTR_FLAG_FTFIF); + if (is_receive) { + CardDMA_I.set_sdio_dma_enable(false); + CardDMA_I.clear_sdio_data_flags(); + CardDMA_I.set_state(sdio::Operational_State::READY); + } else { + CardDMA_I.set_data_end_interrupt(); + } + // Signal that transfer is complete + CardDMA_I.set_transfer_end(true); + } + + else if (dma_instance.get_interrupt_flag(dma::Interrupt_Flags::INTR_FLAG_ERRIF)) { + dma_instance.set_interrupt_enable(dma::Interrupt_Type::INTR_HTFIE, false); + dma_instance.set_interrupt_enable(dma::Interrupt_Type::INTR_ERRIE, false); + dma_instance.set_interrupt_enable(dma::Interrupt_Type::INTR_FTFIE, false); + // Clear all flags + dma_instance.clear_interrupt_flag(dma::Interrupt_Flags::INTR_FLAG_GIF); + // Signal that an error occurred + CardDMA_I.set_transfer_error(SDIO_Error_Type::ERROR); + CardDMA_I.set_state(sdio::Operational_State::READY); + } +} + +extern "C" { + + void SDIO_IRQHandler(void) { + CardDMA_I.handle_interrupts(); + } + + void DMA1_Channel3_4_IRQHandler(void) { + DMA1_IRQHandler(); + } + +} // extern "C" + +#endif // ONBOARD_SDIO +#endif // ARDUINO_ARCH_MFL diff --git a/Marlin/src/HAL/GD32_MFL/sd/sdio.h b/Marlin/src/HAL/GD32_MFL/sd/sdio.h new file mode 100644 index 0000000000..a39e8c7a66 --- /dev/null +++ b/Marlin/src/HAL/GD32_MFL/sd/sdio.h @@ -0,0 +1,36 @@ +/** + * 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 . + * + */ +#pragma once + +#include +#include + +#define SDIO_D0_PIN PC8 +#define SDIO_D1_PIN PC9 +#define SDIO_D2_PIN PC10 +#define SDIO_D3_PIN PC11 +#define SDIO_CK_PIN PC12 +#define SDIO_CMD_PIN PD2 + +void sdio_mfl_init(); +auto SDIO_SetBusWidth(sdio::Bus_Width width) -> bool; +void DMA1_IRQHandler(dma::DMA_Channel channel); diff --git a/Marlin/src/HAL/GD32_MFL/spi_pins.h b/Marlin/src/HAL/GD32_MFL/spi_pins.h new file mode 100644 index 0000000000..c8a5836838 --- /dev/null +++ b/Marlin/src/HAL/GD32_MFL/spi_pins.h @@ -0,0 +1,32 @@ +/** + * 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 . + */ +#pragma once + +// Define SPI Pins: SCK, MISO, MOSI +#ifndef SD_SCK_PIN + #define SD_SCK_PIN PIN_SPI_SCK +#endif +#ifndef SD_MISO_PIN + #define SD_MISO_PIN PIN_SPI_MISO +#endif +#ifndef SD_MOSI_PIN + #define SD_MOSI_PIN PIN_SPI_MOSI +#endif diff --git a/Marlin/src/HAL/GD32_MFL/temp_soc.h b/Marlin/src/HAL/GD32_MFL/temp_soc.h new file mode 100644 index 0000000000..bd78fba5b9 --- /dev/null +++ b/Marlin/src/HAL/GD32_MFL/temp_soc.h @@ -0,0 +1,29 @@ +/** + * 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 . + * + */ +#pragma once + +#define TS_TYPICAL_V 1.405 +#define TS_TYPICAL_TEMP 25 +#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) * 0.001f)) / ((TS_TYPICAL_SLOPE) * 0.001f) + TS_TYPICAL_TEMP) diff --git a/Marlin/src/HAL/GD32_MFL/timers.cpp b/Marlin/src/HAL/GD32_MFL/timers.cpp new file mode 100644 index 0000000000..3bcfdd464b --- /dev/null +++ b/Marlin/src/HAL/GD32_MFL/timers.cpp @@ -0,0 +1,237 @@ +/** + * 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 . + * + */ +#include "../platforms.h" + +#ifdef ARDUINO_ARCH_MFL + +#include "../../inc/MarlinConfig.h" +#include "timers.h" + +// ------------------------ +// Local defines +// ------------------------ + +#define SWSERIAL_TIMER_IRQ_PRIORITY_DEFAULT 1 // Requires tight bit timing to communicate reliably with TMC drivers +#define SERVO_TIMER_IRQ_PRIORITY_DEFAULT 1 // Requires tight PWM timing to control a BLTouch reliably +#define STEP_TIMER_IRQ_PRIORITY_DEFAULT 2 +#define TEMP_TIMER_IRQ_PRIORITY_DEFAULT 14 // Low priority avoids interference with other hardware and timers + +#ifndef TIMER_IRQ_PRIORITY + #define TIMER_IRQ_PRIORITY 12 +#endif + +#ifndef STEP_TIMER_IRQ_PRIORITY + #define STEP_TIMER_IRQ_PRIORITY STEP_TIMER_IRQ_PRIORITY_DEFAULT +#endif + +#ifndef TEMP_TIMER_IRQ_PRIORITY + #define TEMP_TIMER_IRQ_PRIORITY TEMP_TIMER_IRQ_PRIORITY_DEFAULT +#endif + +#if HAS_TMC_SW_SERIAL + #include + #ifndef SWSERIAL_TIMER_IRQ_PRIORITY + #define SWSERIAL_TIMER_IRQ_PRIORITY SWSERIAL_TIMER_IRQ_PRIORITY_DEFAULT + #endif +#endif + +#if HAS_SERVOS + #include "Servo.h" + #ifndef SERVO_TIMER_IRQ_PRIORITY + #define SERVO_TIMER_IRQ_PRIORITY SERVO_TIMER_IRQ_PRIORITY_DEFAULT + #endif +#endif + +#if ENABLED(SPEAKER) + // The MFL framework default timer priority is 12. The TEMP timer must have lower priority + // than this due to the long running temperature ISR, and STEP timer should higher priority. + #if !(TIMER_IRQ_PRIORITY > STEP_TIMER_IRQ_PRIORITY && TIMER_IRQ_PRIORITY < TEMP_TIMER_IRQ_PRIORITY) + #error "Default timer interrupt priority is unspecified or set to a value which may degrade performance." + #endif +#endif + +#ifndef STEP_TIMER + #define STEP_TIMER MF_TIMER_STEP +#endif +#ifndef TEMP_TIMER + #define TEMP_TIMER MF_TIMER_TEMP +#endif + +GeneralTimer& Step_Timer = GeneralTimer::get_instance(static_cast(STEP_TIMER)); +GeneralTimer& Temp_Timer = GeneralTimer::get_instance(static_cast(TEMP_TIMER)); + +bool is_step_timer_initialized = false; +bool is_temp_timer_initialized = false; + +// ------------------------ +// Public functions +// ------------------------ + +// Retrieves the clock frequency of the stepper timer +uint32_t GetStepperTimerClkFreq() { + // Cache result + static uint32_t clkFreq = Step_Timer.getTimerClockFrequency(); + return clkFreq; +} + +/** + * @brief Starts a hardware timer + * + * If the timer is not already initialized, this function will initialize it with the given frequency. + * The timer is started immediately after initialization + * + * @param timer The timer base index to start + * @param frequency The frequency at which the timer should run + * @return None + */ +void HAL_timer_start(const uint8_t timer_number, const uint32_t frequency) { + if (HAL_timer_initialized(timer_number) || (timer_number != MF_TIMER_STEP && timer_number != MF_TIMER_TEMP)) + return; + + const bool is_step = (timer_number == MF_TIMER_STEP); + const uint8_t priority = is_step ? + static_cast(STEP_TIMER_IRQ_PRIORITY) : + static_cast(TEMP_TIMER_IRQ_PRIORITY); + + // Get the reference of the timer instance + GeneralTimer& timer = is_step ? Step_Timer : Temp_Timer; + + if (is_step) { + timer.setPrescaler(STEPPER_TIMER_PRESCALE); + timer.setRolloverValue( + _MIN(HAL_TIMER_TYPE_MAX, hal_timer_t((HAL_TIMER_RATE) / (STEPPER_TIMER_PRESCALE))), + TimerFormat::TICK + ); + is_step_timer_initialized = true; + } + else { + timer.setRolloverValue(frequency, TimerFormat::HERTZ); + is_temp_timer_initialized = true; + } + + timer.setAutoReloadEnable(false); + timer.setInterruptPriority(priority, 0U); + HAL_timer_enable_interrupt(timer_number); + timer.start(); +} + +/** + * @brief Enables the interrupt for the specified timer + * + * @param handle The timer handle for which to enable the interrupt + * @return None + */ +void HAL_timer_enable_interrupt(const uint8_t timer_number) { + if (!HAL_timer_initialized(timer_number)) return; + + GeneralTimer& timer = (timer_number == MF_TIMER_STEP) ? Step_Timer : Temp_Timer; + + if (timer_number == MF_TIMER_STEP && !timer.hasInterrupt()) + timer.attachInterrupt(Step_Handler); + else if (timer_number == MF_TIMER_TEMP && !timer.hasInterrupt()) + timer.attachInterrupt(Temp_Handler); +} + +/** + * @brief Disables the interrupt for the specified timer + * + * @param handle The timer handle for which to disable the interrupt + * @return None + */ +void HAL_timer_disable_interrupt(const uint8_t timer_number) { + if (!HAL_timer_initialized(timer_number)) return; + + GeneralTimer& timer = (timer_number == MF_TIMER_STEP) ? Step_Timer : Temp_Timer; + if (timer_number == MF_TIMER_STEP || timer_number == MF_TIMER_TEMP) + timer.detachInterrupt(); +} + +/** + * @brief Checks if the interrupt is enabled for the specified timer + * + * @param handle The timer handle to check + * @return True if the interrupt is enabled, false otherwise + */ +bool HAL_timer_interrupt_enabled(const uint8_t timer_number) { + if (!HAL_timer_initialized(timer_number)) return false; + + GeneralTimer& timer = (timer_number == MF_TIMER_STEP) ? Step_Timer : Temp_Timer; + return (timer_number == MF_TIMER_STEP || timer_number == MF_TIMER_TEMP) + ? timer.hasInterrupt() + : false; +} + +// Sets the interrupt priorities for timers used by TMC SW serial and servos. +void SetTimerInterruptPriorities() { + TERN_(HAS_TMC_SW_SERIAL, SoftwareSerial::setInterruptPriority(SWSERIAL_TIMER_IRQ_PRIORITY, 0)); + TERN_(HAS_SERVOS, libServo::setInterruptPriority(SERVO_TIMER_IRQ_PRIORITY, 0)); +} + +// ------------------------ +// Detect timer conflicts +// ------------------------ + +TERN_(HAS_TMC_SW_SERIAL, static constexpr timer::TIMER_Base timer_serial[] = {static_cast(TIMER_SERIAL)}); +TERN_(SPEAKER, static constexpr timer::TIMER_Base timer_tone[] = {static_cast(TIMER_TONE)}); +TERN_(HAS_SERVOS, static constexpr timer::TIMER_Base timer_servo[] = {static_cast(TIMER_SERVO)}); + +enum TimerPurpose { + PURPOSE_SERIAL, + PURPOSE_TONE, + PURPOSE_SERVO, + PURPOSE_STEP, + PURPOSE_TEMP +}; + +// List of timers to check for conflicts +// Includes the timer purpose to ease debugging when evaluating at build-time +// This cannot yet account for timers used for PWM output, such as for fans +static constexpr struct { TimerPurpose p; int t; } timers_in_use[] = { + #if HAS_TMC_SW_SERIAL + { PURPOSE_SERIAL, timer_base_to_index(timer_serial[0]) }, // Set in variant.h + #endif + #if ENABLED(SPEAKER) + { PURPOSE_TONE, timer_base_to_index(timer_tone[0]) }, // Set in variant.h + #endif + #if HAS_SERVOS + { PURPOSE_SERVO, timer_base_to_index(timer_servo[0]) }, // Set in variant.h + #endif + { PURPOSE_STEP, MF_TIMER_STEP }, + { PURPOSE_TEMP, MF_TIMER_TEMP }, +}; + +// Verifies if there are any timer conflicts in the timers_in_use array +static constexpr bool verify_no_timer_conflicts() { + for (uint8_t i = 0; i < COUNT(timers_in_use); i++) + for (uint8_t j = i + 1; j < COUNT(timers_in_use); j++) + if (timers_in_use[i].t == timers_in_use[j].t) + return false; + + return true; +} + +// If this assertion fails at compile time, review the timers_in_use array. +// If default_envs is defined properly in platformio.ini, VSCode can evaluate the array +// when hovering over it, making it easy to identify the conflicting timers +static_assert(verify_no_timer_conflicts(), "One or more timer conflict detected. Examine \"timers_in_use\" to help identify conflict."); + +#endif // ARDUINO_ARCH_MFL diff --git a/Marlin/src/HAL/GD32_MFL/timers.h b/Marlin/src/HAL/GD32_MFL/timers.h new file mode 100644 index 0000000000..8aff77aa96 --- /dev/null +++ b/Marlin/src/HAL/GD32_MFL/timers.h @@ -0,0 +1,149 @@ +/** + * 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 . + * + */ +#pragma once + +#include "../../inc/MarlinConfig.h" + +#include + +// ------------------------ +// Defines +// ------------------------ + +// Timer instance definitions +#define MF_TIMER_STEP 3 +#define MF_TIMER_TEMP 1 +#define MF_TIMER_PULSE MF_TIMER_STEP + +typedef uint32_t hal_timer_t; +#define HAL_TIMER_TYPE_MAX hal_timer_t(UINT16_MAX) + +#ifndef HAL_TIMER_RATE + extern uint32_t GetStepperTimerClkFreq(); + #define HAL_TIMER_RATE GetStepperTimerClkFreq() +#endif + +// Timer configuration constants +#define STEPPER_TIMER_RATE 2000000 +#define TEMP_TIMER_FREQUENCY 1000 + +// Timer prescaler calculations +#define STEPPER_TIMER_PRESCALE ((HAL_TIMER_RATE) / (STEPPER_TIMER_RATE)) // Prescaler = 30 +#define STEPPER_TIMER_TICKS_PER_US ((STEPPER_TIMER_RATE) / 1000000UL) // (MHz) Stepper Timer ticks per µs + +// Pulse Timer (counter) calculations +#define PULSE_TIMER_RATE STEPPER_TIMER_RATE // (Hz) Frequency of Pulse Timer +#define PULSE_TIMER_PRESCALE STEPPER_TIMER_PRESCALE + +// Timer interrupt priorities +#define STEP_TIMER_IRQ_PRIORITY 2 +#define TEMP_TIMER_IRQ_PRIORITY 14 + +#define ENABLE_STEPPER_DRIVER_INTERRUPT() HAL_timer_enable_interrupt(MF_TIMER_STEP) +#define DISABLE_STEPPER_DRIVER_INTERRUPT() HAL_timer_disable_interrupt(MF_TIMER_STEP) +#define STEPPER_ISR_ENABLED() HAL_timer_interrupt_enabled(MF_TIMER_STEP) +#define ENABLE_TEMPERATURE_INTERRUPT() HAL_timer_enable_interrupt(MF_TIMER_TEMP) +#define DISABLE_TEMPERATURE_INTERRUPT() HAL_timer_disable_interrupt(MF_TIMER_TEMP) + +extern void Step_Handler(); +extern void Temp_Handler(); + +#ifndef HAL_STEP_TIMER_ISR + #define HAL_STEP_TIMER_ISR() void Step_Handler() +#endif +#ifndef HAL_TEMP_TIMER_ISR + #define HAL_TEMP_TIMER_ISR() void Temp_Handler() +#endif + +extern GeneralTimer& Step_Timer; +extern GeneralTimer& Temp_Timer; + +extern bool is_step_timer_initialized; +extern bool is_temp_timer_initialized; + +// Build-time mapping between timer base and index. Used in timers.cpp and fast_pwm.cpp +static inline constexpr struct {timer::TIMER_Base base; uint8_t timer_number;} base_to_index[] = { + { timer::TIMER_Base::TIMER0_BASE, 0 }, + { timer::TIMER_Base::TIMER1_BASE, 1 }, + { timer::TIMER_Base::TIMER2_BASE, 2 }, + { timer::TIMER_Base::TIMER3_BASE, 3 }, + { timer::TIMER_Base::TIMER4_BASE, 4 }, + { timer::TIMER_Base::TIMER5_BASE, 5 }, + { timer::TIMER_Base::TIMER6_BASE, 6 }, + { timer::TIMER_Base::TIMER7_BASE, 7 } +}; + +// Converts a timer base to an integer timer index. +constexpr auto timer_base_to_index(timer::TIMER_Base base) -> int { + for (const auto& timer : base_to_index) { + if (timer.base == base) { + return static_cast(timer.timer_number); + } + } + return -1; +} + +// ------------------------ +// Public functions +// ------------------------ + +void HAL_timer_start(const uint8_t timer, const uint32_t frequency); +void HAL_timer_enable_interrupt(const uint8_t timer); +void HAL_timer_disable_interrupt(const uint8_t timer); +bool HAL_timer_interrupt_enabled(const uint8_t timer); + +// Configure timer priorities for peripherals such as Software Serial or Servos. +// Exposed here to allow all timer priority information to reside in timers.cpp +void SetTimerInterruptPriorities(); + +// FORCE_INLINE because these are used in performance-critical situations +FORCE_INLINE bool HAL_timer_initialized(const uint8_t timer_number) { + return (timer_number == MF_TIMER_STEP) ? is_step_timer_initialized : + (timer_number == MF_TIMER_TEMP) ? is_temp_timer_initialized : + false; +} + +FORCE_INLINE static hal_timer_t HAL_timer_get_count(const uint8_t timer_number) { + if (!HAL_timer_initialized(timer_number)) return 0U; + + GeneralTimer& timer = (timer_number == MF_TIMER_STEP) ? Step_Timer : Temp_Timer; + + return (timer_number == MF_TIMER_STEP || timer_number == MF_TIMER_TEMP) + ? timer.getCounter(TimerFormat::TICK) + : 0U; +} + +FORCE_INLINE static void HAL_timer_set_compare(const uint8_t timer_number, const hal_timer_t value) { + if (!HAL_timer_initialized(timer_number)) return; + + const auto new_value = static_cast(value + 1U); + GeneralTimer& timer = (timer_number == MF_TIMER_STEP) ? Step_Timer : Temp_Timer; + + if (timer_number == MF_TIMER_STEP || timer_number == MF_TIMER_TEMP) { + timer.setRolloverValue(new_value, TimerFormat::TICK); + if (value < static_cast(timer.getCounter(TimerFormat::TICK))) + timer.refresh(); + } +} + +inline void HAL_timer_isr_prologue(const uint8_t) {} +inline void HAL_timer_isr_epilogue(const uint8_t) {} diff --git a/Marlin/src/HAL/GD32_MFL/u8g/LCD_defines.h b/Marlin/src/HAL/GD32_MFL/u8g/LCD_defines.h new file mode 100644 index 0000000000..720d958779 --- /dev/null +++ b/Marlin/src/HAL/GD32_MFL/u8g/LCD_defines.h @@ -0,0 +1,26 @@ +/** + * 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 . + * + */ +#pragma once + +// MFL LCD-specific defines +uint8_t u8g_com_HAL_MFL_sw_spi_fn(u8g_t* u8g, uint8_t msg, uint8_t arg_val, void* arg_ptr); // u8g_com_mfl_swspi.cpp +#define U8G_COM_HAL_SW_SPI_FN u8g_com_HAL_MFL_sw_spi_fn diff --git a/Marlin/src/HAL/HAL.h b/Marlin/src/HAL/HAL.h index f3e16cfdf1..a211dfe259 100644 --- a/Marlin/src/HAL/HAL.h +++ b/Marlin/src/HAL/HAL.h @@ -27,7 +27,7 @@ #define GCC_VERSION (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__) #endif -#include HAL_PATH(..,HAL.h) +#include HAL_PATH(.., HAL.h) extern MarlinHAL hal; #define HAL_ADC_RANGE _BV(HAL_ADC_RESOLUTION) diff --git a/Marlin/src/HAL/HC32/HAL.h b/Marlin/src/HAL/HC32/HAL.h index 3f4ba14615..f751dea091 100644 --- a/Marlin/src/HAL/HC32/HAL.h +++ b/Marlin/src/HAL/HC32/HAL.h @@ -36,60 +36,12 @@ #include "fastio.h" #include "timers.h" -#include "MarlinSerial.h" // // Serial Ports // -#define _MSERIAL(X) MSerial##X -#define MSERIAL(X) _MSERIAL(X) -#define NUM_UARTS 4 -#if SERIAL_PORT == -1 - #error "USB Serial is not supported on HC32F460" -#elif WITHIN(SERIAL_PORT, 1, NUM_UARTS) - #define MYSERIAL1 MSERIAL(SERIAL_PORT) -#else - #define MYSERIAL1 MSERIAL(1) // Dummy port - static_assert(false, "SERIAL_PORT must be from 1 to " STRINGIFY(NUM_UARTS) ".") -#endif - -#ifdef SERIAL_PORT_2 - #if SERIAL_PORT_2 == -1 - #error "USB Serial is not supported on HC32F460" - #elif WITHIN(SERIAL_PORT_2, 1, NUM_UARTS) - #define MYSERIAL2 MSERIAL(SERIAL_PORT_2) - #else - #define MYSERIAL2 MSERIAL(1) // Dummy port - static_assert(false, "SERIAL_PORT_2 must be from 1 to " STRINGIFY(NUM_UARTS) ".") - #endif -#endif - -#ifdef SERIAL_PORT_3 - #if SERIAL_PORT_3 == -1 - #error "USB Serial is not supported on HC32F460" - #elif WITHIN(SERIAL_PORT_3, 1, NUM_UARTS) - #define MYSERIAL3 MSERIAL(SERIAL_PORT_3) - #else - #define MYSERIAL3 MSERIAL(1) // Dummy port - static_assert(false, "SERIAL_PORT_3 must be from 1 to " STRINGIFY(NUM_UARTS) ".") - #endif -#endif - -#ifdef LCD_SERIAL_PORT - #if LCD_SERIAL_PORT == -1 - #error "USB Serial is not supported on HC32F460" - #elif WITHIN(LCD_SERIAL_PORT, 1, NUM_UARTS) - #define LCD_SERIAL MSERIAL(LCD_SERIAL_PORT) - #else - #define LCD_SERIAL MSERIAL(1) // Dummy port - static_assert(false, "LCD_SERIAL_PORT must be from 1 to " STRINGIFY(NUM_UARTS) ".") - #endif - - #if HAS_DGUS_LCD - #define LCD_SERIAL_TX_BUFFER_FREE() LCD_SERIAL.availableForWrite() - #endif -#endif +#include "MarlinSerial.h" // // Emergency Parser diff --git a/Marlin/src/HAL/HC32/MarlinHAL.h b/Marlin/src/HAL/HC32/MarlinHAL.h index 86dc3c7e53..ba3ac4c731 100644 --- a/Marlin/src/HAL/HC32/MarlinHAL.h +++ b/Marlin/src/HAL/HC32/MarlinHAL.h @@ -67,7 +67,7 @@ public: static void delay_ms(const int ms); - // Tasks, called from idle() + // Tasks, called from marlin.idle() static void idletask(); // Reset diff --git a/Marlin/src/HAL/HC32/MarlinSerial.h b/Marlin/src/HAL/HC32/MarlinSerial.h index bb4630eb1d..1a97805a51 100644 --- a/Marlin/src/HAL/HC32/MarlinSerial.h +++ b/Marlin/src/HAL/HC32/MarlinSerial.h @@ -24,6 +24,14 @@ #include "../../core/serial_hook.h" #include +#define SERIAL_INDEX_MIN 1 +#define SERIAL_INDEX_MAX 4 +#include "../shared/serial_ports.h" + +#if defined(LCD_SERIAL_PORT) && ANY(HAS_DGUS_LCD, EXTENSIBLE_UI) + #define LCD_SERIAL_TX_BUFFER_FREE() LCD_SERIAL.availableForWrite() +#endif + // Optionally set uart IRQ priority to reduce overflow errors //#define UART_RX_IRQ_PRIO 1 //#define UART_TX_IRQ_PRIO 1 diff --git a/Marlin/src/HAL/HC32/Servo.h b/Marlin/src/HAL/HC32/Servo.h index db2f60d190..0a9715494c 100644 --- a/Marlin/src/HAL/HC32/Servo.h +++ b/Marlin/src/HAL/HC32/Servo.h @@ -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); diff --git a/Marlin/src/HAL/HC32/eeprom_bl24cxx.cpp b/Marlin/src/HAL/HC32/eeprom/eeprom_bl24cxx.cpp similarity index 95% rename from Marlin/src/HAL/HC32/eeprom_bl24cxx.cpp rename to Marlin/src/HAL/HC32/eeprom/eeprom_bl24cxx.cpp index 59da99b3f5..a53a7c4062 100644 --- a/Marlin/src/HAL/HC32/eeprom_bl24cxx.cpp +++ b/Marlin/src/HAL/HC32/eeprom/eeprom_bl24cxx.cpp @@ -26,12 +26,12 @@ */ #ifdef ARDUINO_ARCH_HC32 -#include "../../inc/MarlinConfig.h" +#include "../../../inc/MarlinConfig.h" #if ENABLED(IIC_BL24CXX_EEPROM) -#include "../shared/eeprom_api.h" -#include "../shared/eeprom_if.h" +#include "../../shared/eeprom_api.h" +#include "../../shared/eeprom_if.h" #ifndef MARLIN_EEPROM_SIZE #error "MARLIN_EEPROM_SIZE is required for IIC_BL24CXX_EEPROM." diff --git a/Marlin/src/HAL/HC32/eeprom_if_iic.cpp b/Marlin/src/HAL/HC32/eeprom/eeprom_if_iic.cpp similarity index 89% rename from Marlin/src/HAL/HC32/eeprom_if_iic.cpp rename to Marlin/src/HAL/HC32/eeprom/eeprom_if_iic.cpp index 02b1d3fd54..0a161f23f2 100644 --- a/Marlin/src/HAL/HC32/eeprom_if_iic.cpp +++ b/Marlin/src/HAL/HC32/eeprom/eeprom_if_iic.cpp @@ -26,12 +26,12 @@ */ #ifdef ARDUINO_ARCH_HC32 -#include "../../inc/MarlinConfig.h" +#include "../../../inc/MarlinConfig.h" #if ENABLED(IIC_BL24CXX_EEPROM) -#include "../../libs/BL24CXX.h" -#include "../shared/eeprom_if.h" +#include "../../../libs/BL24CXX.h" +#include "../../shared/eeprom_if.h" void eeprom_init() { BL24CXX::init(); @@ -39,7 +39,7 @@ void eeprom_init() { void eeprom_write_byte(uint8_t *pos, unsigned char value) { const unsigned eeprom_address = (unsigned)pos; - return BL24CXX::writeOneByte(eeprom_address, value); + BL24CXX::writeOneByte(eeprom_address, value); } uint8_t eeprom_read_byte(uint8_t *pos) { diff --git a/Marlin/src/HAL/HC32/eeprom_sdcard.cpp b/Marlin/src/HAL/HC32/eeprom/eeprom_sdcard.cpp similarity index 93% rename from Marlin/src/HAL/HC32/eeprom_sdcard.cpp rename to Marlin/src/HAL/HC32/eeprom/eeprom_sdcard.cpp index 601e86dd30..759ea5722d 100644 --- a/Marlin/src/HAL/HC32/eeprom_sdcard.cpp +++ b/Marlin/src/HAL/HC32/eeprom/eeprom_sdcard.cpp @@ -25,12 +25,12 @@ */ #ifdef ARDUINO_ARCH_HC32 -#include "../../inc/MarlinConfig.h" +#include "../../../inc/MarlinConfig.h" #if ENABLED(SDCARD_EEPROM_EMULATION) -#include "../shared/eeprom_api.h" -#include "../../sd/cardreader.h" +#include "../../shared/eeprom_api.h" +#include "../../../sd/cardreader.h" #define EEPROM_FILENAME "eeprom.dat" @@ -53,7 +53,7 @@ bool PersistentStore::access_start() { int bytes_read = file.read(HAL_eeprom_data, MARLIN_EEPROM_SIZE); if (bytes_read < 0) return false; - for (; bytes_read < MARLIN_EEPROM_SIZE; bytes_read++) + for (; bytes_read < long(MARLIN_EEPROM_SIZE); bytes_read++) HAL_eeprom_data[bytes_read] = 0xFF; file.close(); diff --git a/Marlin/src/HAL/HC32/eeprom_wired.cpp b/Marlin/src/HAL/HC32/eeprom/eeprom_wired.cpp similarity index 92% rename from Marlin/src/HAL/HC32/eeprom_wired.cpp rename to Marlin/src/HAL/HC32/eeprom/eeprom_wired.cpp index d9be65b4c0..997180bd98 100644 --- a/Marlin/src/HAL/HC32/eeprom_wired.cpp +++ b/Marlin/src/HAL/HC32/eeprom/eeprom_wired.cpp @@ -2,6 +2,9 @@ * Marlin 3D Printer Firmware * Copyright (c) 2023 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 @@ -18,7 +21,7 @@ */ #ifdef ARDUINO_ARCH_HC32 -#include "../../inc/MarlinConfig.h" +#include "../../../inc/MarlinConfig.h" #if USE_WIRED_EEPROM @@ -29,8 +32,8 @@ * with simple implementations supplied by Marlin. */ -#include "../shared/eeprom_if.h" -#include "../shared/eeprom_api.h" +#include "../../shared/eeprom_if.h" +#include "../../shared/eeprom_api.h" #ifndef MARLIN_EEPROM_SIZE #error "MARLIN_EEPROM_SIZE is required for I2C / SPI EEPROM." diff --git a/Marlin/src/HAL/HC32/inc/SanityCheck.h b/Marlin/src/HAL/HC32/inc/SanityCheck.h index e38bce91e5..c6b3b221df 100644 --- a/Marlin/src/HAL/HC32/inc/SanityCheck.h +++ b/Marlin/src/HAL/HC32/inc/SanityCheck.h @@ -83,7 +83,7 @@ #error "POSTMORTEM_DEBUGGING requires CORE_DISABLE_FAULT_HANDLER to be set." #endif -#if defined(PANIC_ENABLE) +#ifdef PANIC_ENABLE #if defined(PANIC_USART1_TX_PIN) || defined(PANIC_USART2_TX_PIN) || defined(PANIC_USART3_TX_PIN) || defined(PANIC_USART3_TX_PIN) #error "HC32 HAL uses a custom panic handler. Do not define PANIC_USARTx_TX_PIN." #endif diff --git a/Marlin/src/HAL/HC32/pinsDebug.h b/Marlin/src/HAL/HC32/pinsDebug.h index e80b5a081e..9f8e23ce44 100644 --- a/Marlin/src/HAL/HC32/pinsDebug.h +++ b/Marlin/src/HAL/HC32/pinsDebug.h @@ -2,6 +2,9 @@ * Marlin 3D Printer Firmware * Copyright (c) 2023 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 diff --git a/Marlin/src/HAL/HC32/spi_pins.h b/Marlin/src/HAL/HC32/spi_pins.h index 8a8e054b9b..5f1a94e920 100644 --- a/Marlin/src/HAL/HC32/spi_pins.h +++ b/Marlin/src/HAL/HC32/spi_pins.h @@ -2,6 +2,9 @@ * Marlin 3D Printer Firmware * Copyright (c) 2023 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 diff --git a/Marlin/src/HAL/HC32/sysclock.cpp b/Marlin/src/HAL/HC32/sysclock.cpp index 493515b0e8..e98395c42e 100644 --- a/Marlin/src/HAL/HC32/sysclock.cpp +++ b/Marlin/src/HAL/HC32/sysclock.cpp @@ -171,7 +171,7 @@ void core_hook_sysclock_init() { panic("HRC is not 16 MHz"); } - #if defined(BOARD_XTAL_FREQUENCY) + #ifdef BOARD_XTAL_FREQUENCY #warning "No valid XTAL frequency defined, falling back to HRC." #endif diff --git a/Marlin/src/HAL/HC32/timers.cpp b/Marlin/src/HAL/HC32/timers.cpp index 5f7d499622..b8eab34cf7 100644 --- a/Marlin/src/HAL/HC32/timers.cpp +++ b/Marlin/src/HAL/HC32/timers.cpp @@ -35,19 +35,19 @@ Timer0 temp_timer(&TIMER02A_config, &Temp_Handler); */ Timer0 step_timer(&TIMER02B_config, &Step_Handler); -void HAL_timer_start(const timer_channel_t timer_num, const uint32_t frequency) { - if (timer_num == TEMP_TIMER_NUM) { +void HAL_timer_start(const timer_channel_t timer_ch, const uint32_t frequency) { + if (timer_ch == MF_TIMER_TEMP) { CORE_DEBUG_PRINTF("HAL_timer_start: temp timer, f=%ld\n", long(frequency)); - timer_num->start(frequency, TEMP_TIMER_PRESCALE); - timer_num->setCallbackPriority(TEMP_TIMER_PRIORITY); + timer_ch->start(frequency, TEMP_TIMER_PRESCALE); + timer_ch->setCallbackPriority(TEMP_TIMER_PRIORITY); } - else if (timer_num == STEP_TIMER_NUM) { + else if (timer_ch == MF_TIMER_STEP) { CORE_DEBUG_PRINTF("HAL_timer_start: step timer, f=%ld\n", long(frequency)); - timer_num->start(frequency, STEPPER_TIMER_PRESCALE); - timer_num->setCallbackPriority(STEP_TIMER_PRIORITY); + timer_ch->start(frequency, STEPPER_TIMER_PRESCALE); + timer_ch->setCallbackPriority(STEP_TIMER_PRIORITY); } else { - CORE_ASSERT_FAIL("HAL_timer_start: invalid timer_num") + CORE_ASSERT_FAIL("HAL_timer_start: invalid timer_ch") } } diff --git a/Marlin/src/HAL/HC32/timers.h b/Marlin/src/HAL/HC32/timers.h index c0014df604..8a4465e2d8 100644 --- a/Marlin/src/HAL/HC32/timers.h +++ b/Marlin/src/HAL/HC32/timers.h @@ -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 hal_timer_t(UINT16_MAX) // // Timer instances @@ -49,80 +49,73 @@ extern Timer0 step_timer; * See https://github.com/MarlinFirmware/Marlin/pull/27099 for more information. * * NOTE: If the 'constexpr' requirement is ever lifted, TIMER0_BASE_FREQUENCY could - * be used instead. Tho this would probably not make any noticable difference. + * be used instead. Tho this would probably not make any noticeable difference. */ #define HAL_TIMER_RATE F_PCLK1 // Temperature timer -#define TEMP_TIMER_NUM (&temp_timer) +#define MF_TIMER_TEMP (&temp_timer) #define TEMP_TIMER_PRIORITY DDL_IRQ_PRIORITY_02 -#define TEMP_TIMER_PRESCALE 16UL // 12.5MHz +#define TEMP_TIMER_PRESCALE 16UL // 12.5MHz #define TEMP_TIMER_RATE 1000 // 1kHz #define TEMP_TIMER_FREQUENCY TEMP_TIMER_RATE // 1kHz also // Stepper timer -#define STEP_TIMER_NUM (&step_timer) +#define MF_TIMER_STEP (&step_timer) #define STEP_TIMER_PRIORITY DDL_IRQ_PRIORITY_00 // Top priority, nothing else uses it -#define STEPPER_TIMER_PRESCALE 16UL // 12.5MHz +#define STEPPER_TIMER_PRESCALE 16UL // 12.5MHz -#define STEPPER_TIMER_RATE (HAL_TIMER_RATE / STEPPER_TIMER_PRESCALE) // 50MHz / 16 = 3.125MHz -#define STEPPER_TIMER_TICKS_PER_US (STEPPER_TIMER_RATE / 1000000UL) // Integer 3 +#define STEPPER_TIMER_RATE (HAL_TIMER_RATE / STEPPER_TIMER_PRESCALE) // 50MHz / 16 = 3.125MHz +#define STEPPER_TIMER_TICKS_PER_US ((STEPPER_TIMER_RATE) / 1000000UL) // Integer 3 // Pulse timer (== stepper timer) -#define PULSE_TIMER_NUM STEP_TIMER_NUM -#define PULSE_TIMER_PRESCALE STEPPER_TIMER_PRESCALE -#define PULSE_TIMER_TICKS_PER_US STEPPER_TIMER_TICKS_PER_US - -// -// Channel aliases -// -#define MF_TIMER_TEMP TEMP_TIMER_NUM -#define MF_TIMER_STEP STEP_TIMER_NUM -#define MF_TIMER_PULSE PULSE_TIMER_NUM +#define MF_TIMER_PULSE MF_TIMER_STEP +#define PULSE_TIMER_RATE STEPPER_TIMER_RATE // (Hz) Frequency of Pulse Timer +#define PULSE_TIMER_PRESCALE STEPPER_TIMER_PRESCALE // // HAL functions // -void HAL_timer_start(const timer_channel_t timer_num, const uint32_t frequency); +void HAL_timer_start(const timer_channel_t timer_ch, const uint32_t frequency); // Inlined since they are somewhat critical #define MARLIN_HAL_TIMER_INLINE_ATTR __attribute__((always_inline)) inline -MARLIN_HAL_TIMER_INLINE_ATTR void HAL_timer_enable_interrupt(const timer_channel_t timer_num) { - timer_num->resume(); +MARLIN_HAL_TIMER_INLINE_ATTR void HAL_timer_enable_interrupt(const timer_channel_t timer_ch) { + timer_ch->resume(); } -MARLIN_HAL_TIMER_INLINE_ATTR void HAL_timer_disable_interrupt(const timer_channel_t timer_num) { - timer_num->pause(); +MARLIN_HAL_TIMER_INLINE_ATTR void HAL_timer_disable_interrupt(const timer_channel_t timer_ch) { + timer_ch->pause(); } -MARLIN_HAL_TIMER_INLINE_ATTR bool HAL_timer_interrupt_enabled(const timer_channel_t timer_num) { - return timer_num->isPaused(); +MARLIN_HAL_TIMER_INLINE_ATTR bool HAL_timer_interrupt_enabled(const timer_channel_t timer_ch) { + return timer_ch->isPaused(); } -MARLIN_HAL_TIMER_INLINE_ATTR void HAL_timer_set_compare(const timer_channel_t timer_num, const hal_timer_t compare) { - timer_num->setCompareValue(compare); +MARLIN_HAL_TIMER_INLINE_ATTR void HAL_timer_set_compare(const timer_channel_t timer_ch, const hal_timer_t compare) { + timer_ch->setCompareValue(compare); } -MARLIN_HAL_TIMER_INLINE_ATTR hal_timer_t HAL_timer_get_count(const timer_channel_t timer_num) { - return timer_num->getCount(); +MARLIN_HAL_TIMER_INLINE_ATTR hal_timer_t HAL_timer_get_count(const timer_channel_t timer_ch) { + return timer_ch->getCount(); } -MARLIN_HAL_TIMER_INLINE_ATTR void HAL_timer_isr_prologue(const timer_channel_t timer_num) { - timer_num->clearInterruptFlag(); +MARLIN_HAL_TIMER_INLINE_ATTR void HAL_timer_isr_prologue(const timer_channel_t timer_ch) { + timer_ch->clearInterruptFlag(); } -MARLIN_HAL_TIMER_INLINE_ATTR void HAL_timer_isr_epilogue(const timer_channel_t timer_num) {} +inline void HAL_timer_isr_epilogue(const timer_channel_t) {} // // HAL function aliases // -#define ENABLE_STEPPER_DRIVER_INTERRUPT() HAL_timer_enable_interrupt(STEP_TIMER_NUM) -#define DISABLE_STEPPER_DRIVER_INTERRUPT() HAL_timer_disable_interrupt(STEP_TIMER_NUM) -#define STEPPER_ISR_ENABLED() HAL_timer_interrupt_enabled(STEP_TIMER_NUM) +#define ENABLE_STEPPER_DRIVER_INTERRUPT() HAL_timer_enable_interrupt(MF_TIMER_STEP) +#define DISABLE_STEPPER_DRIVER_INTERRUPT() HAL_timer_disable_interrupt(MF_TIMER_STEP) +#define STEPPER_ISR_ENABLED() HAL_timer_interrupt_enabled(MF_TIMER_STEP) -#define ENABLE_TEMPERATURE_INTERRUPT() HAL_timer_enable_interrupt(TEMP_TIMER_NUM) -#define DISABLE_TEMPERATURE_INTERRUPT() HAL_timer_disable_interrupt(TEMP_TIMER_NUM); +#define ENABLE_TEMPERATURE_INTERRUPT() HAL_timer_enable_interrupt(MF_TIMER_TEMP) +#define DISABLE_TEMPERATURE_INTERRUPT() HAL_timer_disable_interrupt(MF_TIMER_TEMP); // // HAL ISR callbacks @@ -131,8 +124,8 @@ void Step_Handler(); void Temp_Handler(); #ifndef HAL_STEP_TIMER_ISR -#define HAL_STEP_TIMER_ISR() void Step_Handler() + #define HAL_STEP_TIMER_ISR() void Step_Handler() #endif #ifndef HAL_TEMP_TIMER_ISR -#define HAL_TEMP_TIMER_ISR() void Temp_Handler() + #define HAL_TEMP_TIMER_ISR() void Temp_Handler() #endif diff --git a/Marlin/src/HAL/LINUX/HAL.h b/Marlin/src/HAL/LINUX/HAL.h index bb5fb73e05..66e4036fdc 100644 --- a/Marlin/src/HAL/LINUX/HAL.h +++ b/Marlin/src/HAL/LINUX/HAL.h @@ -124,9 +124,9 @@ public: static void isr_on() {} static void isr_off() {} - static void delay_ms(const int ms) { _delay_ms(ms); } + static void delay_ms(const int ms) { delay(ms); } - // Tasks, called from idle() + // Tasks, called from marlin.idle() static void idletask() {} // Reset diff --git a/Marlin/src/HAL/LINUX/arduino.cpp b/Marlin/src/HAL/LINUX/arduino.cpp index 0a48697a9c..0a09a11091 100644 --- a/Marlin/src/HAL/LINUX/arduino.cpp +++ b/Marlin/src/HAL/LINUX/arduino.cpp @@ -31,10 +31,8 @@ void cli() { } // Disable void sei() { } // Enable // Time functions -void _delay_ms(const int ms) { delay(ms); } - -uint32_t millis() { - return (uint32_t)Clock::millis(); +unsigned long millis() { + return (unsigned long)Clock::millis(); } // This is required for some Arduino libraries we are using diff --git a/Marlin/src/HAL/LINUX/eeprom.cpp b/Marlin/src/HAL/LINUX/eeprom.cpp index 2b9b37e66d..f665600d5e 100644 --- a/Marlin/src/HAL/LINUX/eeprom.cpp +++ b/Marlin/src/HAL/LINUX/eeprom.cpp @@ -45,7 +45,7 @@ bool PersistentStore::access_start() { fseek(eeprom_file, 0L, SEEK_END); std::size_t file_size = ftell(eeprom_file); - if (file_size < MARLIN_EEPROM_SIZE) { + if (file_size < long(MARLIN_EEPROM_SIZE)) { memset(buffer + file_size, eeprom_erase_value, MARLIN_EEPROM_SIZE - file_size); } else { diff --git a/Marlin/src/HAL/LINUX/include/Arduino.h b/Marlin/src/HAL/LINUX/include/Arduino.h index f05aaed880..87148a40b2 100644 --- a/Marlin/src/HAL/LINUX/include/Arduino.h +++ b/Marlin/src/HAL/LINUX/include/Arduino.h @@ -74,11 +74,10 @@ extern "C" { // Time functions extern "C" void delay(const int ms); -void _delay_ms(const int ms); void delayMicroseconds(unsigned long); -uint32_t millis(); +unsigned long millis(); -//IO functions +// IO functions void pinMode(const pin_t, const uint8_t); void digitalWrite(pin_t, uint8_t); bool digitalRead(pin_t); diff --git a/Marlin/src/HAL/LINUX/spi_pins.h b/Marlin/src/HAL/LINUX/spi_pins.h index 4139c8f898..221145e4b3 100644 --- a/Marlin/src/HAL/LINUX/spi_pins.h +++ b/Marlin/src/HAL/LINUX/spi_pins.h @@ -38,9 +38,3 @@ #ifndef SD_MOSI_PIN #define SD_MOSI_PIN 52 #endif -#ifndef SD_SS_PIN - #define SD_SS_PIN 53 -#endif -#ifndef SDSS - #define SDSS SD_SS_PIN -#endif diff --git a/Marlin/src/HAL/LINUX/timers.h b/Marlin/src/HAL/LINUX/timers.h index 2b29edce0b..39c76f02b5 100644 --- a/Marlin/src/HAL/LINUX/timers.h +++ b/Marlin/src/HAL/LINUX/timers.h @@ -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 hal_timer_t(UINT32_MAX) #define HAL_TIMER_RATE ((SystemCoreClock) / 4) // frequency of timers peripherals @@ -49,21 +49,20 @@ typedef uint32_t hal_timer_t; #endif #define TEMP_TIMER_RATE 1000000 -#define TEMP_TIMER_FREQUENCY 1000 // temperature interrupt frequency +#define TEMP_TIMER_FREQUENCY 1000 // (Hz) Temperature ISR 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_PRESCALE (CYCLES_PER_MICROSECOND / STEPPER_TIMER_TICKS_PER_US) +#define STEPPER_TIMER_RATE HAL_TIMER_RATE // (Hz) Frequency of Stepper Timer ISR (HAL_TIMER_RATE / STEPPER_TIMER_PRESCALE) +#define STEPPER_TIMER_TICKS_PER_US ((STEPPER_TIMER_RATE) / 1000000UL) // (MHz) 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 -#define PULSE_TIMER_PRESCALE STEPPER_TIMER_PRESCALE -#define PULSE_TIMER_TICKS_PER_US STEPPER_TIMER_TICKS_PER_US +#define PULSE_TIMER_RATE STEPPER_TIMER_RATE // (Hz) Frequency of Pulse Timer +#define PULSE_TIMER_PRESCALE STEPPER_TIMER_PRESCALE -#define ENABLE_STEPPER_DRIVER_INTERRUPT() HAL_timer_enable_interrupt(MF_TIMER_STEP) -#define DISABLE_STEPPER_DRIVER_INTERRUPT() HAL_timer_disable_interrupt(MF_TIMER_STEP) -#define STEPPER_ISR_ENABLED() HAL_timer_interrupt_enabled(MF_TIMER_STEP) +#define ENABLE_STEPPER_DRIVER_INTERRUPT() HAL_timer_enable_interrupt(MF_TIMER_STEP) +#define DISABLE_STEPPER_DRIVER_INTERRUPT() HAL_timer_disable_interrupt(MF_TIMER_STEP) +#define STEPPER_ISR_ENABLED() HAL_timer_interrupt_enabled(MF_TIMER_STEP) -#define ENABLE_TEMPERATURE_INTERRUPT() HAL_timer_enable_interrupt(MF_TIMER_TEMP) +#define ENABLE_TEMPERATURE_INTERRUPT() HAL_timer_enable_interrupt(MF_TIMER_TEMP) #define DISABLE_TEMPERATURE_INTERRUPT() HAL_timer_disable_interrupt(MF_TIMER_TEMP) #ifndef HAL_STEP_TIMER_ISR @@ -93,5 +92,5 @@ void HAL_timer_enable_interrupt(const uint8_t timer_num); void HAL_timer_disable_interrupt(const uint8_t timer_num); bool HAL_timer_interrupt_enabled(const uint8_t timer_num); -#define HAL_timer_isr_prologue(T) NOOP -#define HAL_timer_isr_epilogue(T) NOOP +inline void HAL_timer_isr_prologue(const uint8_t) {} +inline void HAL_timer_isr_epilogue(const uint8_t) {} diff --git a/Marlin/src/HAL/LPC1768/HAL.cpp b/Marlin/src/HAL/LPC1768/HAL.cpp index db9881cdd4..4b0e255f37 100644 --- a/Marlin/src/HAL/LPC1768/HAL.cpp +++ b/Marlin/src/HAL/LPC1768/HAL.cpp @@ -35,8 +35,6 @@ #include #include -DefaultSerial1 USBSerial(false, UsbSerial); - uint32_t MarlinHAL::adc_result = 0; pin_t MarlinHAL::adc_pin = 0; @@ -175,13 +173,8 @@ void MarlinHAL::init() { // HAL idle task void MarlinHAL::idletask() { #if HAS_SHARED_MEDIA - // If Marlin is using the SD card we need to lock it to prevent access from - // a PC via USB. - // Other HALs use IS_SD_PRINTING() and IS_SD_FILE_OPEN() to check for access but - // this will not reliably detect delete operations. To be safe we will lock - // the disk if Marlin has it mounted. Unfortunately there is currently no way - // to unmount the disk from the LCD menu. - // if (IS_SD_PRINTING() || IS_SD_FILE_OPEN()) + // When Marlin is using the SD Card it must be locked to prevent PC access via USB. + // For maximum safety we lock the disk if Marlin has it mounted for any reason. if (card.isMounted()) MSC_Aquire_Lock(); else diff --git a/Marlin/src/HAL/LPC1768/HAL.h b/Marlin/src/HAL/LPC1768/HAL.h index 6e0c9cff2f..052d6637c8 100644 --- a/Marlin/src/HAL/LPC1768/HAL.h +++ b/Marlin/src/HAL/LPC1768/HAL.h @@ -38,72 +38,15 @@ extern "C" volatile uint32_t _millis; #include "../shared/math_32bit.h" #include "../shared/HAL_SPI.h" #include "fastio.h" -#include "MarlinSerial.h" #include #include -#include -// ------------------------ -// Serial ports -// ------------------------ +// +// Serial Ports +// -typedef ForwardSerial1Class< decltype(UsbSerial) > DefaultSerial1; -extern DefaultSerial1 USBSerial; - -#define _MSERIAL(X) MSerial##X -#define MSERIAL(X) _MSERIAL(X) - -#if SERIAL_PORT == -1 - #define MYSERIAL1 USBSerial -#elif WITHIN(SERIAL_PORT, 0, 3) - #define MYSERIAL1 MSERIAL(SERIAL_PORT) -#else - #error "SERIAL_PORT must be from 0 to 3. You can also use -1 if the board supports Native USB." -#endif - -#ifdef SERIAL_PORT_2 - #if SERIAL_PORT_2 == -1 - #define MYSERIAL2 USBSerial - #elif WITHIN(SERIAL_PORT_2, 0, 3) - #define MYSERIAL2 MSERIAL(SERIAL_PORT_2) - #else - #error "SERIAL_PORT_2 must be from 0 to 3. You can also use -1 if the board supports Native USB." - #endif -#endif - -#ifdef SERIAL_PORT_3 - #if SERIAL_PORT_3 == -1 - #define MYSERIAL3 USBSerial - #elif WITHIN(SERIAL_PORT_3, 0, 3) - #define MYSERIAL3 MSERIAL(SERIAL_PORT_3) - #else - #error "SERIAL_PORT_3 must be from 0 to 3. You can also use -1 if the board supports Native USB." - #endif -#endif - -#ifdef MMU_SERIAL_PORT - #if MMU_SERIAL_PORT == -1 - #define MMU_SERIAL USBSerial - #elif WITHIN(MMU_SERIAL_PORT, 0, 3) - #define MMU_SERIAL MSERIAL(MMU_SERIAL_PORT) - #else - #error "MMU_SERIAL_PORT must be from 0 to 3. You can also use -1 if the board supports Native USB." - #endif -#endif - -#ifdef LCD_SERIAL_PORT - #if LCD_SERIAL_PORT == -1 - #define LCD_SERIAL USBSerial - #elif WITHIN(LCD_SERIAL_PORT, 0, 3) - #define LCD_SERIAL MSERIAL(LCD_SERIAL_PORT) - #else - #error "LCD_SERIAL_PORT must be from 0 to 3. You can also use -1 if the board supports Native USB." - #endif - #if ANY(HAS_DGUS_LCD, EXTENSIBLE_UI) - #define LCD_SERIAL_TX_BUFFER_FREE() LCD_SERIAL.available() - #endif -#endif +#include "MarlinSerial.h" // // Interrupts @@ -217,7 +160,7 @@ public: static bool watchdog_timed_out() IF_DISABLED(USE_WATCHDOG, { return false; }); static void watchdog_clear_timeout_flag() IF_DISABLED(USE_WATCHDOG, {}); - // Tasks, called from idle() + // Tasks, called from marlin.idle() static void idletask(); // Reset diff --git a/Marlin/src/HAL/LPC1768/MarlinSerial.cpp b/Marlin/src/HAL/LPC1768/MarlinSerial.cpp index f2aecf54a0..291eba68a7 100644 --- a/Marlin/src/HAL/LPC1768/MarlinSerial.cpp +++ b/Marlin/src/HAL/LPC1768/MarlinSerial.cpp @@ -25,6 +25,8 @@ #include "../../inc/MarlinConfig.h" +DefaultSerial1 USBSerial(false, UsbSerial); + #if USING_HW_SERIAL0 MarlinSerial _MSerial0(LPC_UART0); MSerialT MSerial0(true, _MSerial0); diff --git a/Marlin/src/HAL/LPC1768/MarlinSerial.h b/Marlin/src/HAL/LPC1768/MarlinSerial.h index 2fadd8209b..04110e4aff 100644 --- a/Marlin/src/HAL/LPC1768/MarlinSerial.h +++ b/Marlin/src/HAL/LPC1768/MarlinSerial.h @@ -21,6 +21,7 @@ */ #pragma once +#include #include #include @@ -30,6 +31,18 @@ #endif #include "../../core/serial_hook.h" +typedef ForwardSerial1Class< decltype(UsbSerial) > DefaultSerial1; +extern DefaultSerial1 USBSerial; + +#define SERIAL_INDEX_MIN 0 +#define SERIAL_INDEX_MAX 3 +#define USB_SERIAL_PORT(...) USBSerial +#include "../shared/serial_ports.h" + +#if defined(LCD_SERIAL_PORT) && ANY(HAS_DGUS_LCD, EXTENSIBLE_UI) + #define LCD_SERIAL_TX_BUFFER_FREE() LCD_SERIAL.available() +#endif + class MarlinSerial : public HardwareSerial { public: MarlinSerial(LPC_UART_TypeDef *UARTx) : HardwareSerial(UARTx) { } diff --git a/Marlin/src/HAL/LPC1768/Servo.h b/Marlin/src/HAL/LPC1768/Servo.h index 221001c948..d7f0a2a555 100644 --- a/Marlin/src/HAL/LPC1768/Servo.h +++ b/Marlin/src/HAL/LPC1768/Servo.h @@ -49,6 +49,8 @@ #include +#include "../../MarlinCore.h" + class libServo: public Servo { public: void move(const int value) { diff --git a/Marlin/src/HAL/LPC1768/eeprom_flash.cpp b/Marlin/src/HAL/LPC1768/eeprom/eeprom_flash.cpp similarity index 94% rename from Marlin/src/HAL/LPC1768/eeprom_flash.cpp rename to Marlin/src/HAL/LPC1768/eeprom/eeprom_flash.cpp index 9f873d5774..e24b0fdbc0 100644 --- a/Marlin/src/HAL/LPC1768/eeprom_flash.cpp +++ b/Marlin/src/HAL/LPC1768/eeprom/eeprom_flash.cpp @@ -36,11 +36,11 @@ * 16Kb I/O buffers (intended to hold DMA USB and Ethernet data, but currently * unused). */ -#include "../../inc/MarlinConfig.h" +#include "../../../inc/MarlinConfig.h" #if ENABLED(FLASH_EEPROM_EMULATION) -#include "../shared/eeprom_api.h" +#include "../../shared/eeprom_api.h" extern "C" { #include @@ -74,7 +74,7 @@ bool PersistentStore::access_start() { if (status == CMD_SUCCESS) { // sector is blank so nothing stored yet - for (int i = 0; i < MARLIN_EEPROM_SIZE; i++) ram_eeprom[i] = EEPROM_ERASE; + for (int i = 0; i < long(MARLIN_EEPROM_SIZE); i++) ram_eeprom[i] = EEPROM_ERASE; current_slot = EEPROM_SLOTS; } else { @@ -82,7 +82,7 @@ bool PersistentStore::access_start() { current_slot = first_nblank_loc / (MARLIN_EEPROM_SIZE); uint8_t *eeprom_data = SLOT_ADDRESS(EEPROM_SECTOR, current_slot); // load current settings - for (int i = 0; i < MARLIN_EEPROM_SIZE; i++) ram_eeprom[i] = eeprom_data[i]; + for (int i = 0; i < long(MARLIN_EEPROM_SIZE); i++) ram_eeprom[i] = eeprom_data[i]; } eeprom_dirty = false; diff --git a/Marlin/src/HAL/LPC1768/eeprom_sdcard.cpp b/Marlin/src/HAL/LPC1768/eeprom/eeprom_sdcard.cpp similarity index 98% rename from Marlin/src/HAL/LPC1768/eeprom_sdcard.cpp rename to Marlin/src/HAL/LPC1768/eeprom/eeprom_sdcard.cpp index 30ecb01a09..5bf2d353b6 100644 --- a/Marlin/src/HAL/LPC1768/eeprom_sdcard.cpp +++ b/Marlin/src/HAL/LPC1768/eeprom/eeprom_sdcard.cpp @@ -26,13 +26,13 @@ #ifdef TARGET_LPC1768 -#include "../../inc/MarlinConfig.h" +#include "../../../inc/MarlinConfig.h" #if ENABLED(SDCARD_EEPROM_EMULATION) //#define DEBUG_SD_EEPROM_EMULATION -#include "../shared/eeprom_api.h" +#include "../../shared/eeprom_api.h" #include #include @@ -52,7 +52,6 @@ bool eeprom_file_open = false; size_t PersistentStore::capacity() { return MARLIN_EEPROM_SIZE - eeprom_exclude_size; } bool PersistentStore::access_start() { - const char eeprom_erase_value = 0xFF; MSC_Aquire_Lock(); if (f_mount(&fat_fs, "", 1)) { MSC_Release_Lock(); @@ -65,6 +64,7 @@ bool PersistentStore::access_start() { UINT bytes_written; FSIZE_t file_size = f_size(&eeprom_file); f_lseek(&eeprom_file, file_size); + const char eeprom_erase_value = 0xFF; while (file_size < capacity() && res == FR_OK) { res = f_write(&eeprom_file, &eeprom_erase_value, 1, &bytes_written); file_size++; diff --git a/Marlin/src/HAL/LPC1768/eeprom_wired.cpp b/Marlin/src/HAL/LPC1768/eeprom/eeprom_wired.cpp similarity index 95% rename from Marlin/src/HAL/LPC1768/eeprom_wired.cpp rename to Marlin/src/HAL/LPC1768/eeprom/eeprom_wired.cpp index 3230e29afc..6a5d90bd02 100644 --- a/Marlin/src/HAL/LPC1768/eeprom_wired.cpp +++ b/Marlin/src/HAL/LPC1768/eeprom/eeprom_wired.cpp @@ -21,7 +21,7 @@ */ #ifdef TARGET_LPC1768 -#include "../../inc/MarlinConfig.h" +#include "../../../inc/MarlinConfig.h" #if USE_WIRED_EEPROM @@ -30,8 +30,8 @@ * with implementations supplied by the framework. */ -#include "../shared/eeprom_if.h" -#include "../shared/eeprom_api.h" +#include "../../shared/eeprom_if.h" +#include "../../shared/eeprom_api.h" #ifndef MARLIN_EEPROM_SIZE #define MARLIN_EEPROM_SIZE 0x8000 // 32K diff --git a/Marlin/src/HAL/LPC1768/inc/Conditionals_post.h b/Marlin/src/HAL/LPC1768/inc/Conditionals_post.h index 0b03cb2aea..a1b4dd5099 100644 --- a/Marlin/src/HAL/LPC1768/inc/Conditionals_post.h +++ b/Marlin/src/HAL/LPC1768/inc/Conditionals_post.h @@ -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 diff --git a/Marlin/src/HAL/LPC1768/inc/SanityCheck.h b/Marlin/src/HAL/LPC1768/inc/SanityCheck.h index 2782f225b0..5a5617f4ac 100644 --- a/Marlin/src/HAL/LPC1768/inc/SanityCheck.h +++ b/Marlin/src/HAL/LPC1768/inc/SanityCheck.h @@ -121,7 +121,7 @@ static_assert(DISABLED(BAUD_RATE_GCODE), "BAUD_RATE_GCODE is not yet supported o #if IS_TX1(BTN_EN2) || IS_RX1(BTN_EN1) #error "Serial port pins (1) conflict with Encoder Buttons!" #elif ANY_TX(1, SD_SCK_PIN, LCD_PINS_D4, DOGLCD_SCK, LCD_RESET_PIN, LCD_PINS_RS, SHIFT_CLK_PIN) \ - || ANY_RX(1, LCD_SDSS, LCD_PINS_RS, SD_MISO_PIN, DOGLCD_A0, SD_SS_PIN, LCD_SDSS, DOGLCD_CS, LCD_RESET_PIN, LCD_BACKLIGHT_PIN) + || ANY_RX(1, LCD_SDSS_PIN, LCD_PINS_RS, SD_MISO_PIN, DOGLCD_A0, SD_SS_PIN, DOGLCD_CS, LCD_RESET_PIN, LCD_BACKLIGHT_PIN) #error "Serial port pins (1) conflict with LCD pins!" #endif #endif @@ -211,8 +211,8 @@ static_assert(DISABLED(BAUD_RATE_GCODE), "BAUD_RATE_GCODE is not yet supported o #error "SCL0 overlaps with Encoder Button!" #elif IS_SCL0(SD_SS_PIN) #error "SCL0 overlaps with SD_SS_PIN!" - #elif IS_SCL0(LCD_SDSS) - #error "SCL0 overlaps with LCD_SDSS!" + #elif IS_SCL0(LCD_SDSS_PIN) + #error "SCL0 overlaps with LCD_SDSS_PIN!" #endif #undef PIN_IS_SDA0 #undef IS_SCL0 diff --git a/Marlin/src/HAL/LPC1768/spi_pins.h b/Marlin/src/HAL/LPC1768/spi_pins.h index e52f78a7cb..036bf0e023 100644 --- a/Marlin/src/HAL/LPC1768/spi_pins.h +++ b/Marlin/src/HAL/LPC1768/spi_pins.h @@ -32,7 +32,6 @@ //#define SD_SCK_PIN P0_07 //#define SD_MISO_PIN P0_08 //#define SD_MOSI_PIN P0_09 -//#define SD_SS_PIN P0_06 // External SD #ifndef SD_SCK_PIN @@ -44,10 +43,3 @@ #ifndef SD_MOSI_PIN #define SD_MOSI_PIN P0_18 #endif -#ifndef SD_SS_PIN - #define SD_SS_PIN P1_23 -#endif -#if !defined(SDSS) || SDSS == P_NC // gets defaulted in pins.h - #undef SDSS - #define SDSS SD_SS_PIN -#endif diff --git a/Marlin/src/HAL/LPC1768/timers.h b/Marlin/src/HAL/LPC1768/timers.h index bae01703ed..3aec2418d2 100644 --- a/Marlin/src/HAL/LPC1768/timers.h +++ b/Marlin/src/HAL/LPC1768/timers.h @@ -57,9 +57,9 @@ #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 hal_timer_t(UINT32_MAX) -#define HAL_TIMER_RATE ((F_CPU) / 4) // frequency of timers peripherals +#define HAL_TIMER_RATE ((F_CPU) / 4) // (Hz) Frequency of timers peripherals #ifndef MF_TIMER_STEP #define MF_TIMER_STEP 0 // Timer Index for Stepper @@ -74,22 +74,21 @@ typedef uint32_t hal_timer_t; #define MF_TIMER_PWM 3 // Timer Index for PWM #endif -#define TEMP_TIMER_RATE 1000000 -#define TEMP_TIMER_FREQUENCY 1000 // temperature interrupt frequency +#define TEMP_TIMER_RATE 1000000 // 1MHz +#define TEMP_TIMER_FREQUENCY 1000 // (Hz) Temperature ISR 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_PRESCALE (CYCLES_PER_MICROSECOND / STEPPER_TIMER_TICKS_PER_US) +#define STEPPER_TIMER_RATE HAL_TIMER_RATE // (Hz) Frequency of stepper timer (HAL_TIMER_RATE / STEPPER_TIMER_PRESCALE) +#define STEPPER_TIMER_TICKS_PER_US ((STEPPER_TIMER_RATE) / 1000000UL) // (MHz) 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 -#define PULSE_TIMER_PRESCALE STEPPER_TIMER_PRESCALE -#define PULSE_TIMER_TICKS_PER_US STEPPER_TIMER_TICKS_PER_US +#define PULSE_TIMER_RATE STEPPER_TIMER_RATE // (Hz) Frequency of Pulse Timer +#define PULSE_TIMER_PRESCALE STEPPER_TIMER_PRESCALE -#define ENABLE_STEPPER_DRIVER_INTERRUPT() HAL_timer_enable_interrupt(MF_TIMER_STEP) -#define DISABLE_STEPPER_DRIVER_INTERRUPT() HAL_timer_disable_interrupt(MF_TIMER_STEP) -#define STEPPER_ISR_ENABLED() HAL_timer_interrupt_enabled(MF_TIMER_STEP) +#define ENABLE_STEPPER_DRIVER_INTERRUPT() HAL_timer_enable_interrupt(MF_TIMER_STEP) +#define DISABLE_STEPPER_DRIVER_INTERRUPT() HAL_timer_disable_interrupt(MF_TIMER_STEP) +#define STEPPER_ISR_ENABLED() HAL_timer_interrupt_enabled(MF_TIMER_STEP) -#define ENABLE_TEMPERATURE_INTERRUPT() HAL_timer_enable_interrupt(MF_TIMER_TEMP) +#define ENABLE_TEMPERATURE_INTERRUPT() HAL_timer_enable_interrupt(MF_TIMER_TEMP) #define DISABLE_TEMPERATURE_INTERRUPT() HAL_timer_disable_interrupt(MF_TIMER_TEMP) #ifndef HAL_STEP_TIMER_ISR @@ -171,4 +170,4 @@ FORCE_INLINE static void HAL_timer_isr_prologue(const uint8_t timer_num) { } } -#define HAL_timer_isr_epilogue(T) NOOP +inline void HAL_timer_isr_epilogue(const uint8_t) {} diff --git a/Marlin/src/HAL/LPC1768/u8g/LCD_I2C_routines.cpp b/Marlin/src/HAL/LPC1768/u8g/LCD_I2C_routines.cpp index e714c3c16d..09603de972 100644 --- a/Marlin/src/HAL/LPC1768/u8g/LCD_I2C_routines.cpp +++ b/Marlin/src/HAL/LPC1768/u8g/LCD_I2C_routines.cpp @@ -28,7 +28,7 @@ #include "../include/i2c_util.h" #include "../../../core/millis_t.h" -extern int millis(); +uint32_t millis(); #ifdef __cplusplus extern "C" { diff --git a/Marlin/src/HAL/LPC1768/u8g/LCD_pin_routines.c b/Marlin/src/HAL/LPC1768/u8g/LCD_pin_routines.c index 466fc80203..51ad7e095b 100644 --- a/Marlin/src/HAL/LPC1768/u8g/LCD_pin_routines.c +++ b/Marlin/src/HAL/LPC1768/u8g/LCD_pin_routines.c @@ -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 diff --git a/Marlin/src/HAL/LPC1768/u8g/LCD_pin_routines.h b/Marlin/src/HAL/LPC1768/u8g/LCD_pin_routines.h index d60d93dadd..45e0610fb1 100644 --- a/Marlin/src/HAL/LPC1768/u8g/LCD_pin_routines.h +++ b/Marlin/src/HAL/LPC1768/u8g/LCD_pin_routines.h @@ -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); diff --git a/Marlin/src/HAL/LPC1768/upload_extra_script.py b/Marlin/src/HAL/LPC1768/upload_extra_script.py index ce241c4658..f9be140592 100755 --- a/Marlin/src/HAL/LPC1768/upload_extra_script.py +++ b/Marlin/src/HAL/LPC1768/upload_extra_script.py @@ -54,18 +54,25 @@ if pioutil.is_pio_build(): final_drive_name = drive + ':' # print ('disc check: {}'.format(final_drive_name)) try: - volume_info = str(subprocess.check_output('cmd /C dir ' + final_drive_name, stderr=subprocess.STDOUT)) + volume_info = str(subprocess.check_output('cmd /C vol ' + final_drive_name, stderr=subprocess.STDOUT)) except Exception as e: print ('error:{}'.format(e)) continue else: - if target_drive in volume_info and not target_file_found: # set upload if not found target file yet - target_drive_found = True + if target_drive in volume_info: # set upload upload_disk = PureWindowsPath(final_drive_name) - if target_filename in volume_info: - if not target_file_found: + target_drive_found = True + break + try: + dir_info = str(subprocess.check_output('cmd /C dir ' + final_drive_name, stderr=subprocess.STDOUT)) + except Exception as e: + print ('error:{}'.format(e)) + continue + else: + if target_filename in dir_info: upload_disk = PureWindowsPath(final_drive_name) - target_file_found = True + target_file_found = True + break elif current_OS == 'Linux': # diff --git a/Marlin/src/HAL/NATIVE_SIM/HAL.h b/Marlin/src/HAL/NATIVE_SIM/HAL.h index 020299fa5d..b3b66d54d3 100644 --- a/Marlin/src/HAL/NATIVE_SIM/HAL.h +++ b/Marlin/src/HAL/NATIVE_SIM/HAL.h @@ -52,7 +52,9 @@ uint8_t _getc(); // ------------------------ #define CPU_32_BIT -#define SHARED_SERVOS HAS_SERVOS // Use shared/servos.cpp + +class Servo; +typedef Servo hal_servo_t; #define F_CPU 100000000 #define SystemCoreClock F_CPU @@ -71,37 +73,10 @@ extern MSerialT serial_stream_2; extern MSerialT serial_stream_3; #define _MSERIAL(X) serial_stream_##X -#define MSERIAL(X) _MSERIAL(X) -#if WITHIN(SERIAL_PORT, 0, 3) - #define MYSERIAL1 MSERIAL(SERIAL_PORT) -#else - #error "SERIAL_PORT must be from 0 to 3. Please update your configuration." -#endif - -#ifdef SERIAL_PORT_2 - #if WITHIN(SERIAL_PORT_2, 0, 3) - #define MYSERIAL2 MSERIAL(SERIAL_PORT_2) - #else - #error "SERIAL_PORT_2 must be from 0 to 3. Please update your configuration." - #endif -#endif - -#ifdef MMU_SERIAL_PORT - #if WITHIN(MMU_SERIAL_PORT, 0, 3) - #define MMU_SERIAL MSERIAL(MMU_SERIAL_PORT) - #else - #error "MMU_SERIAL_PORT must be from 0 to 3. Please update your configuration." - #endif -#endif - -#ifdef LCD_SERIAL_PORT - #if WITHIN(LCD_SERIAL_PORT, 0, 3) - #define LCD_SERIAL MSERIAL(LCD_SERIAL_PORT) - #else - #error "LCD_SERIAL_PORT must be from 0 to 3. Please update your configuration." - #endif -#endif +#define SERIAL_INDEX_MIN 0 +#define SERIAL_INDEX_MAX 3 +#include "../shared/serial_ports.h" // ------------------------ // Interrupts @@ -220,9 +195,9 @@ public: static void isr_on() {} static void isr_off() {} - static void delay_ms(const int ms) { _delay_ms(ms); } + static void delay_ms(const int ms) { delay(ms); } - // Tasks, called from idle() + // Tasks, called from marlin.idle() static void idletask(); // Reset @@ -259,8 +234,10 @@ public: * No option to invert the duty cycle [default = false] * No option to change the scale of the provided value to enable finer PWM duty control [default = 255] */ - static void set_pwm_duty(const pin_t pin, const uint16_t v, const uint16_t=255, const bool=false) { - analogWrite(pin, v); + static void set_pwm_duty(const pin_t pin, const uint16_t v, const uint16_t v_size=255, const bool invert=false) { + auto value = map(v, 0, v_size, 0, UINT16_MAX); + value = invert ? UINT16_MAX - value : value; + analogWrite(pin, value); } static void set_pwm_frequency(const pin_t, int) {} diff --git a/Marlin/src/HAL/NATIVE_SIM/Servo.cpp b/Marlin/src/HAL/NATIVE_SIM/Servo.cpp new file mode 100644 index 0000000000..a15eda1bf6 --- /dev/null +++ b/Marlin/src/HAL/NATIVE_SIM/Servo.cpp @@ -0,0 +1,104 @@ +/** + * 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 . + * + */ +#include "../platforms.h" + +#ifdef __PLAT_NATIVE_SIM__ + +#include "../../inc/MarlinConfig.h" + +#if HAS_SERVOS + +#include "Servo.h" + +//#define DEBUG_SERVOS +#define DEBUG_OUT ENABLED(DEBUG_SERVOS) +#include "../../../core/debug_out.h" + +uint8_t ServoCount = 0; // the total number of attached servos + +Servo::Servo() { + // Constructor stub + DEBUG_ECHOLNPGM("Debug Servo: constructor"); + this->servoIndex = ServoCount++; // assign a servo index to this instance +} + +uint8_t Servo::attach(int pin) { + // Attach stub + DEBUG_ECHOLNPGM("Debug Servo: attach to pin ", pin, " servo index ", this->servoIndex); + return attach(pin, MIN_PULSE_WIDTH, MAX_PULSE_WIDTH); +} + +uint8_t Servo::attach(int pin, int min, int max) { + // Attach with min and max stub + DEBUG_ECHOLNPGM("Debug Servo: attach to pin ", pin, " with min ", min, " and max ", max); + if (pin > 0) servo_pin = pin; + return this->servoIndex; +} + +void Servo::detach() { + // Detach stub + DEBUG_ECHOLNPGM("Debug Servo: detach"); +} + +// If value is < 200 it is treated as an angle, otherwise as pulse width in microseconds +void Servo::write(int value) { + if (value < MIN_PULSE_WIDTH) { // treat values less than 544 as angles in degrees (valid values in microseconds are handled as microseconds) + value = map(constrain(value, 0, 180), 0, 180, SERVO_MIN_US(min), SERVO_MAX_US(max)); + } + writeMicroseconds(value); + DEBUG_ECHOLNPGM("Debug Servo: write ", value); +} + +void Servo::writeMicroseconds(int value) { + // Simulate the servo movement + this->value = value; + hal.set_pwm_duty(pin_t(this->servo_pin), (float(value) / 20000) * UINT16_MAX, UINT16_MAX); + DEBUG_ECHOLNPGM("Debug Servo: write microseconds ", value); +} + +int Servo::read() { + // Read stub + DEBUG_ECHOLNPGM("Debug Servo: read ", this->value); + return this->value; +} + +int Servo::readMicroseconds() { + // Read microseconds stub + DEBUG_ECHOLNPGM("Debug Servo: read microseconds"); + return 0; +} + +bool Servo::attached() { + // Attached stub + DEBUG_ECHOLNPGM("Debug Servo: attached"); + return false; +} + +int Servo::move(const unsigned char cmd) { + // Move stub + DEBUG_ECHOLNPGM("Debug Servo: move ", cmd); + write(cmd); + return 0; +} + +#endif // HAS_SERVOS +#endif // __PLAT_NATIVE_SIM__ diff --git a/Marlin/src/HAL/NATIVE_SIM/Servo.h b/Marlin/src/HAL/NATIVE_SIM/Servo.h new file mode 100644 index 0000000000..428871142c --- /dev/null +++ b/Marlin/src/HAL/NATIVE_SIM/Servo.h @@ -0,0 +1,48 @@ +/** + * 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 . + * + */ +#pragma once + +#define MIN_PULSE_WIDTH 544 // the shortest pulse sent to a servo +#define MAX_PULSE_WIDTH 2400 // the longest pulse sent to a servo +#define DEFAULT_PULSE_WIDTH 1500 // default pulse width when servo is attached +#define SERVO_MIN_US(v) (MIN_PULSE_WIDTH - (v) * 4) // minimum value in uS for this servo +#define SERVO_MAX_US(v) (MAX_PULSE_WIDTH - (v) * 4) // maximum value in uS for this servo + +class Servo { +public: + Servo(); + uint8_t attach(int pin); // Attach the given pin to the next free channel, set pinMode, return channel number or INVALID_SERVO if failure + uint8_t attach(int pin, int min, int max); // As above but also set min and max values for writes. + void detach(); + void write(int value); // If value is < 200 it's treated as an angle, otherwise as pulse width in microseconds + void writeMicroseconds(int value); // Write pulse width in microseconds + int read(); // Return current pulse width as an angle between 0 and 180 degrees + int readMicroseconds(); // Return current pulse width in microseconds for this servo + bool attached(); // Return true if this servo is attached, otherwise false + int move (const unsigned char cmd); +private: + uint8_t servoIndex; // Index into the channel data for this servo + int8_t min; // Minimum is this value times 4 added to MIN_PULSE_WIDTH + int8_t max; // Maximum is this value times 4 added to MAX_PULSE_WIDTH + int value; // Pulse width in microseconds for this servo + int servo_pin = 0; // pin number for this servo +}; diff --git a/Marlin/src/HAL/NATIVE_SIM/endstop_interrupts.h b/Marlin/src/HAL/NATIVE_SIM/endstop_interrupts.h new file mode 100644 index 0000000000..e74c312274 --- /dev/null +++ b/Marlin/src/HAL/NATIVE_SIM/endstop_interrupts.h @@ -0,0 +1,30 @@ +/** + * 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 . + * + */ +#pragma once + +#error "ENDSTOP_INTERRUPTS_FEATURE is not supported in this simulation environment." + +void setup_endstop_interrupts() { + // This function is a stub for setting up endstop interrupts. + // Since this is a simulation environment, actual hardware interrupts + // are not applicable. Add any necessary simulation-specific logic here. +} diff --git a/Marlin/src/HAL/NATIVE_SIM/fastio.h b/Marlin/src/HAL/NATIVE_SIM/fastio.h index f501afdbaa..e0b7af09f9 100644 --- a/Marlin/src/HAL/NATIVE_SIM/fastio.h +++ b/Marlin/src/HAL/NATIVE_SIM/fastio.h @@ -28,6 +28,8 @@ #include "../shared/Marduino.h" #include +#define NO_COMPILE_TIME_PWM + #define SET_DIR_INPUT(IO) Gpio::setDir(IO, 1) #define SET_DIR_OUTPUT(IO) Gpio::setDir(IO, 0) diff --git a/Marlin/src/HAL/NATIVE_SIM/servo_private.h b/Marlin/src/HAL/NATIVE_SIM/servo_private.h deleted file mode 100644 index e0eb30ab28..0000000000 --- a/Marlin/src/HAL/NATIVE_SIM/servo_private.h +++ /dev/null @@ -1,79 +0,0 @@ -/** - * Marlin 3D Printer Firmware - * Copyright (c) 2021 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 . - * - */ -#pragma once - -/** - * servo.h - Interrupt driven Servo library for Arduino using 16 bit timers- Version 2 - * Copyright (c) 2009 Michael Margolis. All right reserved. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ - -/** - * Based on "servo.h - Interrupt driven Servo library for Arduino using 16 bit timers - - * Version 2 Copyright (c) 2009 Michael Margolis. All right reserved. - * - * The only modification was to update/delete macros to match the LPC176x. - * - */ - -#include - -// Macros -//values in microseconds -#define MIN_PULSE_WIDTH 544 // the shortest pulse sent to a servo -#define MAX_PULSE_WIDTH 2400 // the longest pulse sent to a servo -#define DEFAULT_PULSE_WIDTH 1500 // default pulse width when servo is attached -#define REFRESH_INTERVAL 20000 // minimum time to refresh servos in microseconds - -#define MAX_SERVOS 4 - -#define INVALID_SERVO 255 // flag indicating an invalid servo index - -// Types - -typedef struct { - uint8_t nbr : 8 ; // a pin number from 0 to 254 (255 signals invalid pin) - uint8_t isActive : 1 ; // true if this channel is enabled, pin not pulsed if false -} ServoPin_t; - -typedef struct { - ServoPin_t Pin; - unsigned int pulse_width; // pulse width in microseconds -} ServoInfo_t; - -// Global variables - -extern uint8_t ServoCount; -extern ServoInfo_t servo_info[MAX_SERVOS]; diff --git a/Marlin/src/HAL/NATIVE_SIM/spi_pins.h b/Marlin/src/HAL/NATIVE_SIM/spi_pins.h index d9911bf56c..0e83e13692 100644 --- a/Marlin/src/HAL/NATIVE_SIM/spi_pins.h +++ b/Marlin/src/HAL/NATIVE_SIM/spi_pins.h @@ -32,7 +32,6 @@ //#define SD_SCK_PIN P0_07 //#define SD_MISO_PIN P0_08 //#define SD_MOSI_PIN P0_09 -//#define SD_SS_PIN P0_06 // External SD #ifndef SD_SCK_PIN @@ -44,9 +43,3 @@ #ifndef SD_MOSI_PIN #define SD_MOSI_PIN 52 #endif -#ifndef SD_SS_PIN - #define SD_SS_PIN 53 -#endif -#ifndef SDSS - #define SDSS SD_SS_PIN -#endif diff --git a/Marlin/src/HAL/NATIVE_SIM/timers.h b/Marlin/src/HAL/NATIVE_SIM/timers.h index d46e8e7b94..be59bb8676 100644 --- a/Marlin/src/HAL/NATIVE_SIM/timers.h +++ b/Marlin/src/HAL/NATIVE_SIM/timers.h @@ -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 hal_timer_t(UINT64_MAX) #define HAL_TIMER_RATE ((SystemCoreClock) / 4) // frequency of timers peripherals @@ -52,22 +52,21 @@ 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 // (Hz) Temperature Timer count rate +#define TEMP_TIMER_FREQUENCY 1000 // (Hz) Temperature ISR call 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_PRESCALE (CYCLES_PER_MICROSECOND / STEPPER_TIMER_TICKS_PER_US) +#define STEPPER_TIMER_RATE HAL_TIMER_RATE // (Hz) Frequency of Stepper Timer (HAL_TIMER_RATE / STEPPER_TIMER_PRESCALE) +#define STEPPER_TIMER_TICKS_PER_US ((STEPPER_TIMER_RATE) / 1'000'000) // (MHz) 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 -#define PULSE_TIMER_PRESCALE STEPPER_TIMER_PRESCALE -#define PULSE_TIMER_TICKS_PER_US STEPPER_TIMER_TICKS_PER_US +#define PULSE_TIMER_RATE STEPPER_TIMER_RATE // (Hz) Frequency of Pulse Timer +#define PULSE_TIMER_PRESCALE STEPPER_TIMER_PRESCALE -#define ENABLE_STEPPER_DRIVER_INTERRUPT() HAL_timer_enable_interrupt(MF_TIMER_STEP) -#define DISABLE_STEPPER_DRIVER_INTERRUPT() HAL_timer_disable_interrupt(MF_TIMER_STEP) -#define STEPPER_ISR_ENABLED() HAL_timer_interrupt_enabled(MF_TIMER_STEP) +#define ENABLE_STEPPER_DRIVER_INTERRUPT() HAL_timer_enable_interrupt(MF_TIMER_STEP) +#define DISABLE_STEPPER_DRIVER_INTERRUPT() HAL_timer_disable_interrupt(MF_TIMER_STEP) +#define STEPPER_ISR_ENABLED() HAL_timer_interrupt_enabled(MF_TIMER_STEP) -#define ENABLE_TEMPERATURE_INTERRUPT() HAL_timer_enable_interrupt(MF_TIMER_TEMP) +#define ENABLE_TEMPERATURE_INTERRUPT() HAL_timer_enable_interrupt(MF_TIMER_TEMP) #define DISABLE_TEMPERATURE_INTERRUPT() HAL_timer_disable_interrupt(MF_TIMER_TEMP) #ifndef HAL_STEP_TIMER_ISR @@ -88,5 +87,5 @@ void HAL_timer_enable_interrupt(const uint8_t timer_num); void HAL_timer_disable_interrupt(const uint8_t timer_num); bool HAL_timer_interrupt_enabled(const uint8_t timer_num); -#define HAL_timer_isr_prologue(T) NOOP -#define HAL_timer_isr_epilogue(T) NOOP +inline void HAL_timer_isr_prologue(const uint8_t) {} +inline void HAL_timer_isr_epilogue(const uint8_t) {} diff --git a/Marlin/src/HAL/NATIVE_SIM/u8g/LCD_pin_routines.cpp b/Marlin/src/HAL/NATIVE_SIM/u8g/LCD_pin_routines.cpp index 3566528079..9cb33694a3 100644 --- a/Marlin/src/HAL/NATIVE_SIM/u8g/LCD_pin_routines.cpp +++ b/Marlin/src/HAL/NATIVE_SIM/u8g/LCD_pin_routines.cpp @@ -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__ diff --git a/Marlin/src/HAL/NATIVE_SIM/u8g/LCD_pin_routines.h b/Marlin/src/HAL/NATIVE_SIM/u8g/LCD_pin_routines.h index 39af4d7e68..ab73635d28 100644 --- a/Marlin/src/HAL/NATIVE_SIM/u8g/LCD_pin_routines.h +++ b/Marlin/src/HAL/NATIVE_SIM/u8g/LCD_pin_routines.h @@ -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 diff --git a/Marlin/src/HAL/NATIVE_SIM/u8g/u8g_com_st7920_sw_spi.cpp b/Marlin/src/HAL/NATIVE_SIM/u8g/u8g_com_st7920_sw_spi.cpp index 46f2798afa..b07bc1644d 100644 --- a/Marlin/src/HAL/NATIVE_SIM/u8g/u8g_com_st7920_sw_spi.cpp +++ b/Marlin/src/HAL/NATIVE_SIM/u8g/u8g_com_st7920_sw_spi.cpp @@ -71,13 +71,13 @@ static uint8_t SPI_speed = 0; static uint8_t swSpiTransfer(uint8_t b, const uint8_t spi_speed, const pin_t sck_pin, const pin_t miso_pin, const pin_t mosi_pin) { for (uint8_t i = 0; i < 8; i++) { - WRITE_PIN(mosi_pin, !!(b & 0x80)); + WRITE_PIN(sck_pin, TERN(U8G_SPI_USE_MODE_3, LOW, HIGH)); DELAY_CYCLES(SPI_SPEED); - WRITE_PIN(sck_pin, HIGH); + WRITE_PIN(mosi_pin, !!(b & 0x80)); DELAY_CYCLES(SPI_SPEED); b <<= 1; if (miso_pin >= 0 && READ_PIN(miso_pin)) b |= 1; - WRITE_PIN(sck_pin, LOW); + WRITE_PIN(sck_pin, TERN(U8G_SPI_USE_MODE_3, HIGH, LOW)); DELAY_CYCLES(SPI_SPEED); } return b; @@ -85,7 +85,7 @@ static uint8_t swSpiTransfer(uint8_t b, const uint8_t spi_speed, const pin_t sck static uint8_t swSpiInit(const uint8_t spiRate, const pin_t sck_pin, const pin_t mosi_pin) { WRITE_PIN(mosi_pin, HIGH); - WRITE_PIN(sck_pin, LOW); + WRITE_PIN(sck_pin, TERN(U8G_SPI_USE_MODE_3, HIGH, LOW)); return spiRate; } @@ -93,11 +93,11 @@ static void u8g_com_st7920_write_byte_sw_spi(uint8_t rs, uint8_t val) { static uint8_t rs_last_state = 255; if (rs != rs_last_state) { // Transfer Data (FA) or Command (F8) - swSpiTransfer(rs ? 0x0FA : 0x0F8, SPI_speed, SCK_pin_ST7920_HAL, -1, MOSI_pin_ST7920_HAL_HAL); + swSpiTransfer(rs ? 0xFA : 0xF8, SPI_speed, SCK_pin_ST7920_HAL, -1, MOSI_pin_ST7920_HAL_HAL); rs_last_state = rs; DELAY_US(40); // Give the controller time to process the data: 20 is bad, 30 is OK, 40 is safe } - swSpiTransfer(val & 0x0F0, SPI_speed, SCK_pin_ST7920_HAL, -1, MOSI_pin_ST7920_HAL_HAL); + swSpiTransfer(val & 0xF0, SPI_speed, SCK_pin_ST7920_HAL, -1, MOSI_pin_ST7920_HAL_HAL); swSpiTransfer(val << 4, SPI_speed, SCK_pin_ST7920_HAL, -1, MOSI_pin_ST7920_HAL_HAL); } @@ -169,5 +169,32 @@ uint8_t u8g_com_ST7920_sw_spi_fn(u8g_t *u8g, uint8_t msg, uint8_t arg_val, void } #endif +#if ENABLED(LIGHTWEIGHT_UI) + + #define ST7920_CS() { WRITE(LCD_PINS_RS, HIGH); } + #define ST7920_NCS() { WRITE(LCD_PINS_RS, LOW); } + #define ST7920_SET_CMD() { ST7920_SWSPI_SND_8BIT(0xF8); } + #define ST7920_SET_DAT() { ST7920_SWSPI_SND_8BIT(0xFA); } + #define ST7920_WRITE_BYTE(a) { ST7920_SWSPI_SND_8BIT((uint8_t)((a)&0xF0u)); ST7920_SWSPI_SND_8BIT((uint8_t)((a)<<4U)); } + + #define ST7920_DAT(V) !!((V) & 0x80) + + #define ST7920_SND_BIT(...) do{ \ + WRITE(LCD_PINS_D4, LOW); \ + WRITE(LCD_PINS_EN, ST7920_DAT(val)); \ + WRITE(LCD_PINS_D4, HIGH); \ + val <<= 1; }while(0); + + void ST7920_SWSPI_SND_8BIT(uint8_t val) { + REPEAT(8, ST7920_SND_BIT); + } + + void ST7920_cs() { ST7920_CS(); } + void ST7920_ncs() { ST7920_NCS(); } + void ST7920_set_cmd() { ST7920_SET_CMD(); } + void ST7920_set_dat() { ST7920_SET_DAT(); } + void ST7920_write_byte(const uint8_t val) { ST7920_WRITE_BYTE(val); } +#endif // LIGHTWEIGHT_UI + #endif // IS_U8GLIB_ST7920 #endif // __PLAT_NATIVE_SIM__ diff --git a/Marlin/src/HAL/NATIVE_SIM/u8g/u8g_com_sw_spi.cpp b/Marlin/src/HAL/NATIVE_SIM/u8g/u8g_com_sw_spi.cpp index f984983b40..fd11e5d767 100644 --- a/Marlin/src/HAL/NATIVE_SIM/u8g/u8g_com_sw_spi.cpp +++ b/Marlin/src/HAL/NATIVE_SIM/u8g/u8g_com_sw_spi.cpp @@ -127,7 +127,7 @@ uint8_t swSpiTransfer_mode_3(uint8_t b, const uint8_t spi_speed, const pin_t sck static uint8_t SPI_speed = 0; static uint8_t swSpiInit(const uint8_t spi_speed, const uint8_t clk_pin, const uint8_t mosi_pin) { - return spi_speed; + return spi_speed; } static void u8g_sw_spi_shift_out(uint8_t dataPin, uint8_t clockPin, uint8_t val) { diff --git a/Marlin/src/HAL/RP2040/HAL.cpp b/Marlin/src/HAL/RP2040/HAL.cpp index d1af25a842..51f68648bc 100644 --- a/Marlin/src/HAL/RP2040/HAL.cpp +++ b/Marlin/src/HAL/RP2040/HAL.cpp @@ -28,21 +28,116 @@ #include "../../inc/MarlinConfig.h" #include "../shared/Delay.h" +#include "../../module/temperature.h" // For OVERSAMPLENR extern "C" { #include "pico/bootrom.h" #include "hardware/watchdog.h" + #include "pico/multicore.h" + #include "hardware/adc.h" + #include "pico/time.h" } #if HAS_SD_HOST_DRIVE #include "msc_sd.h" - #include "usbd_cdc_if.h" #endif // ------------------------ // Public Variables // ------------------------ +volatile uint32_t adc_accumulators[5] = {0}; // Accumulators for oversampling (sum of readings) +volatile uint8_t adc_counts[5] = {0}; // Count of readings accumulated per channel +volatile uint16_t adc_values[5] = {4095, 4095, 4095, 4095, 4095}; // Averaged ADC values (single reading equivalent) - initialized to max (open circuit) + +// Core monitoring for watchdog +volatile uint32_t core0_last_heartbeat = 0; // Timestamp of Core 0's last activity +volatile uint32_t core1_last_heartbeat = 0; // Timestamp of Core 1's last activity +#if ENABLED(MARLIN_DEV_MODE) + volatile bool core1_freeze_test = false; // Flag to freeze Core 1 for watchdog testing +#endif +volatile uint8_t current_pin; +volatile bool MarlinHAL::adc_has_result; +volatile uint8_t adc_channels_enabled[5] = {false}; // Track which ADC channels are enabled + +// Core 1 ADC reading task - dynamically reads all enabled channels with oversampling +void core1_adc_task() { + static uint32_t last_temp_update = 0; + + while (true) { + #if ENABLED(MARLIN_DEV_MODE) + // Check if we should freeze for watchdog test + if (core1_freeze_test) { + // Stop updating heartbeat and spin forever + while (core1_freeze_test) { + busy_wait_us(100000); // 100ms delay + } + } + #endif + + // Scan all enabled ADC channels + for (uint8_t channel = 0; channel < 5; channel++) { + if (!adc_channels_enabled[channel]) continue; + + // Enable temperature sensor if reading channel 4 + if (channel == 4) { + adc_set_temp_sensor_enabled(true); + } + + // Select and read the channel + adc_select_input(channel); + busy_wait_us(100); // Settling delay + adc_fifo_drain(); + adc_run(true); + + // Wait for conversion with timeout + uint32_t timeout = 10000; + while (adc_fifo_is_empty() && timeout--) { + busy_wait_us(1); + } + + adc_run(false); + uint16_t reading = adc_fifo_is_empty() ? 0 : adc_fifo_get(); + + // Accumulate readings for oversampling + adc_accumulators[channel] += reading; + adc_counts[channel]++; + + // When we reach the full oversampling count, calculate averaged value (Marlin ISR does its own oversampling) + if (adc_counts[channel] >= OVERSAMPLENR) { + adc_values[channel] = adc_accumulators[channel] / OVERSAMPLENR; // Return single-reading equivalent + adc_accumulators[channel] = 0; + adc_counts[channel] = 0; + } + + // Disable temp sensor after reading to save power + if (channel == 4) { + adc_set_temp_sensor_enabled(false); + } + } + + // Core 1 just provides ADC readings - don't trigger temperature updates from here + // Let Marlin's main temperature ISR on Core 0 handle the timing and updates + uint32_t now = time_us_32(); + if (now - last_temp_update >= 100000) { // 100ms = 100000 microseconds + last_temp_update = now; + #if ENABLED(USE_WATCHDOG) + // Refresh watchdog here like AVR ISR does indirectly via temperature updates + // Use 2 second delay to allow watchdog_init to be called during boot + static uint32_t core1_start_time = 0; + if (core1_start_time == 0) core1_start_time = time_us_32(); + + if (time_us_32() - core1_start_time > 2000000) { + hal.watchdog_refresh(1); // Refresh from Core 1 + } + #endif + } + + // Delay between full scan cycles + busy_wait_us(10000); // 10ms between scans + } +} + volatile uint16_t adc_result; // ------------------------ @@ -56,14 +151,11 @@ 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); - #undef SDSS - #define SDSS 2 - #define PIN_EXISTS_(P1,P2) (defined(P1##P2) && P1##P2 >= 0) - #if HAS_MEDIA && DISABLED(SDIO_SUPPORT) && PIN_EXISTS_(SDSS,) - OUT_WRITE(SDSS, HIGH); // Try to set SDSS inactive before any other SPI users start up + #if HAS_MEDIA && DISABLED(ONBOARD_SDIO) && PIN_EXISTS(SD_SS) + OUT_WRITE(SD_SS_PIN, HIGH); // Try to set SD_SS_PIN inactive before any other SPI users start up #endif #if PIN_EXISTS(LED) @@ -80,7 +172,7 @@ void MarlinHAL::init() { HAL_timer_init(); - #if ENABLED(EMERGENCY_PARSER) && USBD_USE_CDC + #if ALL(EMERGENCY_PARSER, USBD_USE_CDC) USB_Hook_init(); #endif @@ -90,7 +182,7 @@ void MarlinHAL::init() { #if PIN_EXISTS(USB_CONNECT) OUT_WRITE(USB_CONNECT_PIN, !USB_CONNECT_INVERTING); // USB clear connection - delay_ms(1000); // Give OS time to notice + delay_ms(1000); // Give OS time to notice WRITE(USB_CONNECT_PIN, USB_CONNECT_INVERTING); #endif } @@ -115,74 +207,92 @@ void MarlinHAL::reboot() { watchdog_reboot(0, 0, 1); } void MarlinHAL::watchdog_init() { #if DISABLED(DISABLE_WATCHDOG_INIT) - static_assert(WDT_TIMEOUT_US > 1000, "WDT Timout is too small, aborting"); + static_assert(WDT_TIMEOUT_US > 1000, "WDT Timeout is too small, aborting"); + // Initialize Core 0 heartbeat + core0_last_heartbeat = time_us_32(); watchdog_enable(WDT_TIMEOUT_US/1000, true); #endif } - void MarlinHAL::watchdog_refresh() { - watchdog_update(); - #if DISABLED(PINS_DEBUGGING) && PIN_EXISTS(LED) - TOGGLE(LED_PIN); // heartbeat indicator - #endif + void MarlinHAL::watchdog_refresh(const uint8_t core/*=0*/) { + if (core == 0) { + // Update Core 0 heartbeat + core0_last_heartbeat = time_us_32(); + + // Check if Core 1 is alive (2 second timeout) + if (time_us_32() - core1_last_heartbeat < 2000000) { + watchdog_update(); // Only refresh if Core 1 is responding + #if DISABLED(PINS_DEBUGGING) && PIN_EXISTS(LED) + TOGGLE(LED_PIN); // Heartbeat indicator + #endif + } + // If Core 1 is stuck, don't refresh - let watchdog reset the system + } + else { + // Update Core 1 heartbeat + core1_last_heartbeat = time_us_32(); + + // Check if Core 0 is alive (2 second timeout) + if (time_us_32() - core0_last_heartbeat < 2000000) { + watchdog_update(); // Only refresh if Core 0 is responding + #if DISABLED(PINS_DEBUGGING) && PIN_EXISTS(LED) + TOGGLE(LED_PIN); // Heartbeat indicator + #endif + } + // If Core 0 is stuck, don't refresh - let watchdog reset the system + } } -#endif +#endif // USE_WATCHDOG // ------------------------ // ADC // ------------------------ -volatile bool MarlinHAL::adc_has_result = false; - void MarlinHAL::adc_init() { analogReadResolution(HAL_ADC_RESOLUTION); ::adc_init(); adc_fifo_setup(true, false, 1, false, false); - irq_set_exclusive_handler(ADC_IRQ_FIFO, adc_exclusive_handler); - irq_set_enabled(ADC_IRQ_FIFO, true); - adc_irq_set_enabled(true); + // Launch Core 1 for continuous ADC reading + multicore_launch_core1(core1_adc_task); + adc_has_result = true; // Results are always available with continuous sampling } void MarlinHAL::adc_enable(const pin_t pin) { - if (pin >= A0 && pin <= A3) + if (pin >= A0 && pin <= A3) { adc_gpio_init(pin); - else if (pin == HAL_ADC_MCU_TEMP_DUMMY_PIN) - adc_set_temp_sensor_enabled(true); -} - -void MarlinHAL::adc_start(const pin_t pin) { - adc_has_result = false; - // Select an ADC input. 0...3 are GPIOs 26...29 respectively. - adc_select_input(pin == HAL_ADC_MCU_TEMP_DUMMY_PIN ? 4 : pin - A0); - adc_run(true); -} - -void MarlinHAL::adc_exclusive_handler() { - adc_run(false); // Disable since we only want one result - irq_clear(ADC_IRQ_FIFO); // Clear the IRQ - - if (adc_fifo_get_level() >= 1) { - adc_result = adc_fifo_get(); // Pop the result - adc_fifo_drain(); - adc_has_result = true; // Signal the end of the conversion + adc_channels_enabled[pin - A0] = true; // Mark this channel as enabled + } + else if (pin == HAL_ADC_MCU_TEMP_DUMMY_PIN) { + adc_channels_enabled[4] = true; // Mark MCU temp channel as enabled } } -uint16_t MarlinHAL::adc_value() { return adc_result; } +void MarlinHAL::adc_start(const pin_t pin) { + // Just store which pin we need to read - values are continuously updated by Core 1 + current_pin = pin; +} + +uint16_t MarlinHAL::adc_value() { + // Return the latest ADC value from Core 1's continuous readings + const uint8_t channel = (current_pin == HAL_ADC_MCU_TEMP_DUMMY_PIN) ? 4 : (current_pin - A0); + return adc_values[channel]; +} // Reset the system to initiate a firmware flash void flashFirmware(const int16_t) { hal.reboot(); } extern "C" { void * _sbrk(int incr); - extern unsigned int __bss_end__; // end of bss section + extern unsigned int __StackLimit; // Lowest address the stack can grow to } -// Return free memory between end of heap (or end bss) and whatever is current +// Return free memory between end of heap and start of stack int freeMemory() { - int free_memory, heap_end = (int)_sbrk(0); - return (int)&free_memory - (heap_end ?: (int)&__bss_end__); + void* heap_end = _sbrk(0); + // Use the linker-provided stack limit instead of a local variable + // __StackLimit is the lowest address the stack can grow to + return (char*)&__StackLimit - (char*)heap_end; } #endif // __PLAT_RP2040__ diff --git a/Marlin/src/HAL/RP2040/HAL.h b/Marlin/src/HAL/RP2040/HAL.h index fa1a35683e..a49b343899 100644 --- a/Marlin/src/HAL/RP2040/HAL.h +++ b/Marlin/src/HAL/RP2040/HAL.h @@ -29,77 +29,47 @@ #include "arduino_extras.h" #include "../../core/macros.h" -#include "../shared/Marduino.h" #include "../shared/math_32bit.h" #include "../shared/HAL_SPI.h" #include "fastio.h" -//#include "Servo.h" #include "watchdog.h" -#include "MarlinSerial.h" #include "../../inc/MarlinConfigPre.h" -#include +#if HAS_SD_HOST_DRIVE + #include "msc_sd.h" +#endif -// ------------------------ -// Serial ports -// ------------------------ +// ADC index 4 is the MCU temperature +#define HAL_ADC_MCU_TEMP_DUMMY_PIN 127 +#define TEMP_SOC_PIN HAL_ADC_MCU_TEMP_DUMMY_PIN // ADC4 is internal temp sensor +#include "temp_soc.h" -#include "../../core/serial_hook.h" -typedef ForwardSerial1Class< decltype(Serial) > DefaultSerial1; -extern DefaultSerial1 MSerial0; +// +// Serial Ports +// -#define _MSERIAL(X) MSerial##X -#define MSERIAL(X) _MSERIAL(X) +#include "MarlinSerial.h" -#if SERIAL_PORT == -1 - #define MYSERIAL1 MSerial0 -#elif WITHIN(SERIAL_PORT, 0, 6) - #define MYSERIAL1 MSERIAL(SERIAL_PORT) -#else - #error "SERIAL_PORT must be from 0 to 6. You can also use -1 if the board supports Native USB." +#if !WITHIN(SERIAL_PORT, -1, 1) + #error "SERIAL_PORT must be from -1 to 1." #endif #ifdef SERIAL_PORT_2 - #if SERIAL_PORT_2 == -1 - #define MYSERIAL2 MSerial0 - #elif WITHIN(SERIAL_PORT_2, 0, 6) - #define MYSERIAL2 MSERIAL(SERIAL_PORT_2) - #else - #error "SERIAL_PORT_2 must be from 0 to 6. You can also use -1 if the board supports Native USB." + #if !WITHIN(SERIAL_PORT_2, -1, 1) + #error "SERIAL_PORT_2 must be from -1 to 1." #endif #endif #ifdef SERIAL_PORT_3 - #if SERIAL_PORT_3 == -1 - #define MYSERIAL3 MSerial0 - #elif WITHIN(SERIAL_PORT_3, 0, 6) - #define MYSERIAL3 MSERIAL(SERIAL_PORT_3) - #else - #error "SERIAL_PORT_3 must be from 0 to 6. You can also use -1 if the board supports Native USB." - #endif -#endif - -#ifdef MMU2_SERIAL_PORT - #if MMU2_SERIAL_PORT == -1 - #define MMU2_SERIAL MSerial0 - #elif WITHIN(MMU2_SERIAL_PORT, 0, 6) - #define MMU2_SERIAL MSERIAL(MMU2_SERIAL_PORT) - #else - #error "MMU2_SERIAL_PORT must be from 0 to 6. You can also use -1 if the board supports Native USB." + #if !WITHIN(SERIAL_PORT_3, -1, 1) + #error "SERIAL_PORT_3 must be from -1 to 1." #endif #endif #ifdef LCD_SERIAL_PORT - #if LCD_SERIAL_PORT == -1 - #define LCD_SERIAL MSerial0 - #elif WITHIN(LCD_SERIAL_PORT, 0, 6) - #define LCD_SERIAL MSERIAL(LCD_SERIAL_PORT) - #else - #error "LCD_SERIAL_PORT must be from 0 to 6. You can also use -1 if the board supports Native USB." - #endif - #if HAS_DGUS_LCD - #define SERIAL_GET_TX_BUFFER_FREE() LCD_SERIAL.availableForWrite() + #if !WITHIN(LCD_SERIAL_PORT, -1, 1) + #error "LCD_SERIAL_PORT must be from -1 to 1." #endif #endif @@ -142,8 +112,6 @@ typedef libServo hal_servo_t; #else #define HAL_ADC_RESOLUTION 12 #endif -// ADC index 4 is the MCU temperature -#define HAL_ADC_MCU_TEMP_DUMMY_PIN 127 // // Pin Mapping for M42, M43, M226 @@ -185,7 +153,7 @@ public: // Watchdog static void watchdog_init() IF_DISABLED(USE_WATCHDOG, {}); - static void watchdog_refresh() IF_DISABLED(USE_WATCHDOG, {}); + static void watchdog_refresh(const uint8_t=0) IF_DISABLED(USE_WATCHDOG, {}); static void init(); // Called early in setup() static void init_board() {} // Called less early in setup() @@ -196,10 +164,10 @@ public: static void isr_on() { __enable_irq(); } static void isr_off() { __disable_irq(); } - static void delay_ms(const int ms) { ::delay(ms); } + static void delay_ms(const int ms) { delay(ms); } - // Tasks, called from idle() - static void idletask() {} + // Tasks, called from marlin.idle() + static void idletask() { TERN_(HAS_SD_HOST_DRIVE, tuh_task()); } // Reset static uint8_t get_reset_source(); @@ -221,9 +189,6 @@ public: // Begin ADC sampling on the given pin. Called from Temperature::isr! static void adc_start(const pin_t pin); - // This ADC runs a periodic task - static void adc_exclusive_handler(); - // Is the ADC ready for reading? static volatile bool adc_has_result; static bool adc_ready() { return adc_has_result; } diff --git a/Marlin/src/HAL/RP2040/HAL_MinSerial.cpp b/Marlin/src/HAL/RP2040/HAL_MinSerial.cpp index 5a65163591..dc332053bc 100644 --- a/Marlin/src/HAL/RP2040/HAL_MinSerial.cpp +++ b/Marlin/src/HAL/RP2040/HAL_MinSerial.cpp @@ -29,7 +29,6 @@ #include "../shared/HAL_MinSerial.h" - static void TXBegin() { #if !WITHIN(SERIAL_PORT, -1, 2) #warning "Using POSTMORTEM_DEBUGGING requires a physical U(S)ART hardware in case of severe error." @@ -45,15 +44,15 @@ static void TXBegin() { #endif } -static void TX(char b){ - #if SERIAL_PORT == -1 - USBSerial - #elif SERIAL_PORT == 0 - USBSerial - #elif SERIAL_PORT == 1 - Serial1 - #endif - .write(b); +static void TX(char b) { + #if SERIAL_PORT == -1 + USBSerial + #elif SERIAL_PORT == 0 + USBSerial + #elif SERIAL_PORT == 1 + Serial1 + #endif + .write(b); } // A SW memory barrier, to ensure GCC does not overoptimize loops diff --git a/Marlin/src/HAL/RP2040/MarlinSerial.cpp b/Marlin/src/HAL/RP2040/MarlinSerial.cpp index dd01edd830..5e3bf0c148 100644 --- a/Marlin/src/HAL/RP2040/MarlinSerial.cpp +++ b/Marlin/src/HAL/RP2040/MarlinSerial.cpp @@ -30,10 +30,40 @@ #include "../../feature/e_parser.h" #endif -#define _IMPLEMENT_SERIAL(X) DefaultSerial##X MSerial##X(false, Serial##X) -#define IMPLEMENT_SERIAL(X) _IMPLEMENT_SERIAL(X) -#if WITHIN(SERIAL_PORT, 0, 3) - IMPLEMENT_SERIAL(SERIAL_PORT); +#include + +// Marlin uses: -1=USB, 0=UART0, 1=UART1 +// Arduino uses: Serial=USB, Serial1=UART0, Serial2=UART1 +// +// To remap Arduino's numbering to Marlin's convention, we create MarlinSerial0/MarlinSerial1 +// as new UART instances with custom pins. +// +// We use distinct names (MarlinSerial0/MarlinSerial1) to avoid symbol conflicts with +// the Arduino framework's pre-defined Serial1/Serial2 objects, which use the same +// underlying hardware (_UART0_ and _UART1_). + +// Create Serial0 as UART0 with custom or default pins +arduino::UART MarlinSerial0( + #if PINS_EXIST(SERIAL0_TX, SERIAL0_RX) + SERIAL0_TX_PIN, SERIAL0_RX_PIN // Custom pins for UART0 (Marlin Serial0) + #else + 0, 1 // Default UART0 pins (GP0/GP1) + #endif +); + +// Not using PINS_EXIST(SERIAL1_TX, SERIAL1_RX) because SERIAL1_TX and SERIAL1_RX +// are defined in framework-arduino-mbed/variants/RASPBERRY_PI_PICO/pins_arduino.h + +// Create Serial1 as UART1 with custom or default pins +#if defined(SERIAL1_TX_PIN) && defined(SERIAL1_RX_PIN) + arduino::UART MarlinSerial1(SERIAL1_TX_PIN, SERIAL1_RX_PIN); // Custom pins for UART1 (Marlin Serial1) #endif +// Wrap the serial ports for Marlin +DefaultSerial0 MSerial0(false, MarlinSerial0); // Marlin Serial0 = UART0 +#if defined(SERIAL1_TX_PIN) && defined(SERIAL1_RX_PIN) + DefaultSerial1 MSerial1(false, MarlinSerial1); // Marlin Serial1 = UART1 +#endif +DefaultSerial2 MSerial2(false, Serial); // Marlin Serial2 = USB (-1) + #endif // __PLAT_RP2040__ diff --git a/Marlin/src/HAL/RP2040/MarlinSerial.h b/Marlin/src/HAL/RP2040/MarlinSerial.h index c5924c9062..f407a838df 100644 --- a/Marlin/src/HAL/RP2040/MarlinSerial.h +++ b/Marlin/src/HAL/RP2040/MarlinSerial.h @@ -29,24 +29,52 @@ #include "../../core/serial_hook.h" -#define Serial0 Serial -#define _DECLARE_SERIAL(X) \ - typedef ForwardSerial1Class DefaultSerial##X; \ - extern DefaultSerial##X MSerial##X -#define DECLARE_SERIAL(X) _DECLARE_SERIAL(X) +/** + * Serial Port Configuration for RP2040 (Raspberry Pi Pico) + * + * Arduino-Pico Core Serial Objects: + * - Serial: USB Serial (CDC ACM) + * - Serial1: Hardware UART0 + * - Serial2: Hardware UART1 + * - SerialUSB: Alias for Serial (USB) + * + * Marlin Serial Wrappers: + * - MSerial0: Wrapper for MarlinSerial0 (UART0), used as Serial0 + * - MSerial1: Wrapper for MarlinSerial1 (UART1), declared dynamically if used + * - MSerial2: Wrapper for Serial (USB) + * - USBSerial: Wrapper for SerialUSB (USB) + * + * How it all joins together: + * - Configuration defines SERIAL_PORT, SERIAL_PORT_2, etc. (-1 to 1 range) + * - shared/serial_ports.h maps these to MYSERIAL1, MYSERIAL2, etc. + * - MYSERIAL1 uses MSerialX based on the port index + * - USB ports (-1) use USB_SERIAL_PORT (MSerial2) + */ +// Forward declare our custom Serial objects (defined in MarlinSerial.cpp) +namespace arduino { class UART; } +extern arduino::UART MarlinSerial0; // Always declared +extern arduino::UART MarlinSerial1; // Custom Marlin Serial1 to avoid conflict + +typedef ForwardSerial1Class< decltype(MarlinSerial0) > DefaultSerial0; +extern DefaultSerial0 MSerial0; +typedef ForwardSerial1Class< decltype(MarlinSerial1) > DefaultSerial1; +extern DefaultSerial1 MSerial1; +typedef ForwardSerial1Class< decltype(Serial) > DefaultSerial2; +extern DefaultSerial2 MSerial2; typedef ForwardSerial1Class USBSerialType; extern USBSerialType USBSerial; -#define _MSERIAL(X) MSerial##X -#define MSERIAL(X) _MSERIAL(X) +#define _DECLARE_SERIAL(X) \ + typedef ForwardSerial1Class DefaultSerial##X; \ + extern DefaultSerial##X MSerial##X +#define DECLARE_SERIAL(X) _DECLARE_SERIAL(X) -#if SERIAL_PORT == -1 - // #define MYSERIAL1 USBSerial this is already done in the HAL -#elif WITHIN(SERIAL_PORT, 0, 3) - #define MYSERIAL1 MSERIAL(SERIAL_PORT) - DECLARE_SERIAL(SERIAL_PORT); -#else - #error "SERIAL_PORT must be from 0 to 3, or -1 for Native USB." +#define SERIAL_INDEX_MIN 0 +#define SERIAL_INDEX_MAX 1 +#define USB_SERIAL_PORT(...) MSerial2 +#include "../shared/serial_ports.h" + +#if defined(LCD_SERIAL_PORT) && ANY(HAS_DGUS_LCD, EXTENSIBLE_UI) + #define SERIAL_GET_TX_BUFFER_FREE() LCD_SERIAL.availableForWrite() #endif - diff --git a/Marlin/src/HAL/RP2040/eeprom_flash.cpp b/Marlin/src/HAL/RP2040/eeprom/eeprom_flash.cpp similarity index 59% rename from Marlin/src/HAL/RP2040/eeprom_flash.cpp rename to Marlin/src/HAL/RP2040/eeprom/eeprom_flash.cpp index 5b1131ed43..bf52109173 100644 --- a/Marlin/src/HAL/RP2040/eeprom_flash.cpp +++ b/Marlin/src/HAL/RP2040/eeprom/eeprom_flash.cpp @@ -19,40 +19,60 @@ * along with this program. If not, see . * */ -#include "../platforms.h" +#include "../../platforms.h" #ifdef __PLAT_RP2040__ -#include "../../inc/MarlinConfig.h" +#include "../../../inc/MarlinConfig.h" #if ENABLED(FLASH_EEPROM_EMULATION) -#include "../shared/eeprom_api.h" +#include "../../shared/eeprom_api.h" // NOTE: The Bigtreetech SKR Pico has an onboard W25Q16 flash module -// Use EEPROM.h for compatibility, for now. -#include +// RP2040 Flash-based EEPROM emulation using internal flash memory +#include +#include -static bool eeprom_data_written = false; +// Flash sector size is already defined in hardware/flash.h as FLASH_SECTOR_SIZE +// Place EEPROM emulation at the end of flash, before the filesystem +// This assumes 2MB flash, adjust if using different flash size +#define FLASH_TARGET_OFFSET (PICO_FLASH_SIZE_BYTES - FLASH_SECTOR_SIZE) #ifndef MARLIN_EEPROM_SIZE #define MARLIN_EEPROM_SIZE size_t(E2END + 1) #endif + +static uint8_t eeprom_buffer[MARLIN_EEPROM_SIZE]; +static bool eeprom_data_written = false; +static bool eeprom_initialized = false; size_t PersistentStore::capacity() { return MARLIN_EEPROM_SIZE; } bool PersistentStore::access_start() { - EEPROM.begin(); // Avoid EEPROM.h warning (do nothing) - eeprom_buffer_fill(); + if (!eeprom_initialized) { + // Read from flash into buffer + const uint8_t *flash_data = (const uint8_t *)(XIP_BASE + FLASH_TARGET_OFFSET); + memcpy(eeprom_buffer, flash_data, MARLIN_EEPROM_SIZE); + eeprom_initialized = true; + } return true; } bool PersistentStore::access_finish() { if (eeprom_data_written) { TERN_(HAS_PAUSE_SERVO_OUTPUT, PAUSE_SERVO_OUTPUT()); - hal.isr_off(); - eeprom_buffer_flush(); - hal.isr_on(); + + // Disable interrupts during flash write + const uint32_t intstate = save_and_disable_interrupts(); + + // Erase and program the sector + flash_range_erase(FLASH_TARGET_OFFSET, FLASH_SECTOR_SIZE); + flash_range_program(FLASH_TARGET_OFFSET, eeprom_buffer, MARLIN_EEPROM_SIZE); + + // Restore interrupts + restore_interrupts(intstate); + TERN_(HAS_PAUSE_SERVO_OUTPUT, RESUME_SERVO_OUTPUT()); eeprom_data_written = false; } @@ -62,8 +82,8 @@ bool PersistentStore::access_finish() { bool PersistentStore::write_data(int &pos, const uint8_t *value, size_t size, uint16_t *crc) { while (size--) { uint8_t v = *value; - if (v != eeprom_buffered_read_byte(pos)) { - eeprom_buffered_write_byte(pos, v); + if (pos < (int)MARLIN_EEPROM_SIZE && v != eeprom_buffer[pos]) { + eeprom_buffer[pos] = v; eeprom_data_written = true; } crc16(crc, &v, 1); @@ -75,7 +95,7 @@ bool PersistentStore::write_data(int &pos, const uint8_t *value, size_t size, ui bool PersistentStore::read_data(int &pos, uint8_t *value, size_t size, uint16_t *crc, const bool writing/*=true*/) { do { - const uint8_t c = eeprom_buffered_read_byte(pos); + const uint8_t c = (pos < (int)MARLIN_EEPROM_SIZE) ? eeprom_buffer[pos] : 0xFF; if (writing) *value = c; crc16(crc, &c, 1); pos++; diff --git a/Marlin/src/HAL/RP2040/eeprom_wired.cpp b/Marlin/src/HAL/RP2040/eeprom/eeprom_wired.cpp similarity index 94% rename from Marlin/src/HAL/RP2040/eeprom_wired.cpp rename to Marlin/src/HAL/RP2040/eeprom/eeprom_wired.cpp index 974f6f8dc1..7a5ca86c4c 100644 --- a/Marlin/src/HAL/RP2040/eeprom_wired.cpp +++ b/Marlin/src/HAL/RP2040/eeprom/eeprom_wired.cpp @@ -19,11 +19,11 @@ * along with this program. If not, see . * */ -#include "../platforms.h" +#include "../../platforms.h" #ifdef __PLAT_RP2040__ -#include "../../inc/MarlinConfig.h" +#include "../../../inc/MarlinConfig.h" #if USE_WIRED_EEPROM @@ -32,8 +32,8 @@ * with simple implementations supplied by Marlin. */ -#include "../shared/eeprom_if.h" -#include "../shared/eeprom_api.h" +#include "../../shared/eeprom_if.h" +#include "../../shared/eeprom_api.h" #ifndef MARLIN_EEPROM_SIZE #define MARLIN_EEPROM_SIZE size_t(E2END + 1) diff --git a/Marlin/src/HAL/RP2040/inc/Conditionals_adv.h b/Marlin/src/HAL/RP2040/inc/Conditionals_adv.h index 442639e130..b96b3baa64 100644 --- a/Marlin/src/HAL/RP2040/inc/Conditionals_adv.h +++ b/Marlin/src/HAL/RP2040/inc/Conditionals_adv.h @@ -21,7 +21,7 @@ */ #pragma once -#if ALL(SDSUPPORT, USBD_USE_CDC_MSC) && DISABLED(NO_SD_HOST_DRIVE) +#if HAS_MEDIA && DISABLED(NO_SD_HOST_DRIVE) #define HAS_SD_HOST_DRIVE 1 #endif diff --git a/Marlin/src/HAL/RP2040/inc/SanityCheck.h b/Marlin/src/HAL/RP2040/inc/SanityCheck.h index 29175f8bbb..e4b1d7ee8d 100644 --- a/Marlin/src/HAL/RP2040/inc/SanityCheck.h +++ b/Marlin/src/HAL/RP2040/inc/SanityCheck.h @@ -28,7 +28,7 @@ // #error "SPINDLE_LASER_PWM_PIN must use SERVO0, SERVO1 or SERVO3 connector" //#endif -#if ENABLED(SDCARD_EEPROM_EMULATION) && DISABLED(SDSUPPORT) +#if ENABLED(SDCARD_EEPROM_EMULATION) && !HAS_MEDIA #undef SDCARD_EEPROM_EMULATION // Avoid additional error noise #if USE_FALLBACK_EEPROM #warning "EEPROM type not specified. Fallback is SDCARD_EEPROM_EMULATION." diff --git a/Marlin/src/HAL/RP2040/msc_sd.cpp b/Marlin/src/HAL/RP2040/msc_sd.cpp index bc945c1999..b0de2241e5 100644 --- a/Marlin/src/HAL/RP2040/msc_sd.cpp +++ b/Marlin/src/HAL/RP2040/msc_sd.cpp @@ -27,109 +27,77 @@ #if HAS_SD_HOST_DRIVE -#include "../shared/Marduino.h" -#include "msc_sd.h" -#include "usbd_core.h" - #include "../../sd/cardreader.h" -#include -#include +#include // TinyUSB device stack #define BLOCK_SIZE 512 -#define PRODUCT_ID 0x29 +#define SD_MULTIBLOCK_RETRY_CNT 1 -class Sd2CardUSBMscHandler : public USBMscHandler { -public: - DiskIODriver* diskIODriver() { - #if ENABLED(MULTI_VOLUME) - #if SHARED_VOLUME_IS(SD_ONBOARD) - return &card.media_driver_sdcard; - #elif SHARED_VOLUME_IS(USB_FLASH_DRIVE) - return &card.media_driver_usbFlash; - #endif - #else - return card.diskIODriver(); +DiskIODriver* diskIODriver() { + #if HAS_MULTI_VOLUME + #if SHARED_VOLUME_IS(SD_ONBOARD) + return &card.media_driver_sdcard; + #elif SHARED_VOLUME_IS(USB_FLASH_DRIVE) + return &card.media_driver_usbFlash; #endif - } + #else + return card.diskIODriver(); + #endif +} - bool GetCapacity(uint32_t *pBlockNum, uint16_t *pBlockSize) { - *pBlockNum = diskIODriver()->cardSize(); - *pBlockSize = BLOCK_SIZE; - return true; - } +/** Callbacks used by TinyUSB MSC **/ - bool Write(uint8_t *pBuf, uint32_t blkAddr, uint16_t blkLen) { - auto sd2card = diskIODriver(); - // single block - if (blkLen == 1) { - watchdog_refresh(); - sd2card->writeBlock(blkAddr, pBuf); - return true; +extern "C" { + +bool tud_msc_ready_cb(uint8_t lun) { + return diskIODriver()->isReady(); +} + +int32_t tud_msc_read10_cb(uint8_t lun, uint32_t lba, void* buffer, uint32_t bufsize) { + const uint32_t blocks = bufsize / BLOCK_SIZE; + for (uint16_t rcount = SD_MULTIBLOCK_RETRY_CNT; rcount--; ) { + if (diskIODriver()->readBlocks(lba, (uint8_t*)buffer, blocks)) + return bufsize; // Success + } + return -1; // Failure after retries +} + +int32_t tud_msc_write10_cb(uint8_t lun, uint32_t lba, uint8_t const* buffer, uint32_t bufsize) { + const uint32_t blocks = bufsize / BLOCK_SIZE; + for (uint16_t rcount = SD_MULTIBLOCK_RETRY_CNT; rcount--; ) { + if (diskIODriver()->writeBlocks(lba, buffer, blocks)) + return bufsize; // Success + } + return -1; // Failure after retries +} + +void tud_msc_inquiry_cb(uint8_t lun, uint8_t vendor_id[8], uint8_t product_id[16], uint8_t product_rev[4]) { + memcpy(vendor_id, "MARLIN ", 8); + memcpy(product_id, "Product ", 16); + memcpy(product_rev, "0.01", 4); +} + +void tud_msc_capacity_cb(uint8_t lun, uint32_t* block_count, uint16_t* block_size) { + *block_count = diskIODriver()->cardSize(); + *block_size = BLOCK_SIZE; +} + +void tud_msc_start_stop_cb(uint8_t lun, uint8_t power_condition, bool start, bool load_eject) { + if (load_eject) { + if (start) { + // Handle media load + } else { + // Handle media eject } - - // multi block optimization - sd2card->writeStart(blkAddr, blkLen); - while (blkLen--) { - watchdog_refresh(); - sd2card->writeData(pBuf); - pBuf += BLOCK_SIZE; - } - sd2card->writeStop(); - return true; } +} - bool Read(uint8_t *pBuf, uint32_t blkAddr, uint16_t blkLen) { - auto sd2card = diskIODriver(); - // single block - if (blkLen == 1) { - watchdog_refresh(); - sd2card->readBlock(blkAddr, pBuf); - return true; - } - - // multi block optimization - sd2card->readStart(blkAddr); - while (blkLen--) { - watchdog_refresh(); - sd2card->readData(pBuf); - pBuf += BLOCK_SIZE; - } - sd2card->readStop(); - return true; - } - - bool IsReady() { - return diskIODriver()->isReady(); - } -}; - -Sd2CardUSBMscHandler usbMscHandler; - -/* USB Mass storage Standard Inquiry Data */ -uint8_t Marlin_STORAGE_Inquirydata[] = { /* 36 */ - /* LUN 0 */ - 0x00, - 0x80, - 0x02, - 0x02, - (STANDARD_INQUIRY_DATA_LEN - 5), - 0x00, - 0x00, - 0x00, - 'M', 'A', 'R', 'L', 'I', 'N', ' ', ' ', /* Manufacturer : 8 bytes */ - 'P', 'r', 'o', 'd', 'u', 'c', 't', ' ', /* Product : 16 Bytes */ - ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', - '0', '.', '0', '1', /* Version : 4 Bytes */ -}; - -USBMscHandler *pSingleMscHandler = &usbMscHandler; +} // extern "C" void MSC_SD_init() { - USBDevice.end(); - delay(200); - USBDevice.registerMscHandlers(1, &pSingleMscHandler, Marlin_STORAGE_Inquirydata); - USBDevice.begin(); + tusb_init(); + // Add USB reinitialization logic if needed } #endif // HAS_SD_HOST_DRIVE diff --git a/Marlin/src/HAL/RP2040/pinsDebug.h b/Marlin/src/HAL/RP2040/pinsDebug.h index 964fb71086..8f58089fb1 100644 --- a/Marlin/src/HAL/RP2040/pinsDebug.h +++ b/Marlin/src/HAL/RP2040/pinsDebug.h @@ -25,7 +25,7 @@ #include "HAL.h" #ifndef NUM_DIGITAL_PINS - #error "Expected NUM_DIGITAL_PINS not found" + #error "Expected NUM_DIGITAL_PINS not found." #endif /** @@ -74,6 +74,27 @@ * signal. The Arduino pin number is listed by the M43 I command. */ +/** + * Pins Debugging for RP2040 + * + * - NUMBER_PINS_TOTAL + * - MULTI_NAME_PAD + * - getPinByIndex(index) + * - printPinNameByIndex(index) + * - getPinIsDigitalByIndex(index) + * - digitalPinToAnalogIndex(pin) + * - getValidPinMode(pin) + * - isValidPin(pin) + * - isAnalogPin(pin) + * - digitalRead_mod(pin) + * - pwm_status(pin) + * - printPinPWM(pin) + * - printPinPort(pin) + * - printPinNumber(pin) + * - printPinAnalog(pin) + */ + +#define NUMBER_PINS_TOTAL NUM_DIGITAL_PINS #define NUM_ANALOG_FIRST A0 #define MODE_PIN_INPUT 0 // Input mode (reset state) @@ -81,66 +102,66 @@ #define MODE_PIN_ALT 2 // Alternate function mode #define MODE_PIN_ANALOG 3 // Analog mode -#define PIN_NUM(P) (P & 0x000F) -#define PIN_NUM_ALPHA_LEFT(P) (((P & 0x000F) < 10) ? ('0' + (P & 0x000F)) : '1') -#define PIN_NUM_ALPHA_RIGHT(P) (((P & 0x000F) > 9) ? ('0' + (P & 0x000F) - 10) : 0 ) -#define PORT_NUM(P) ((P >> 4) & 0x0007) -#define PORT_ALPHA(P) ('A' + (P >> 4)) +#define getPinByIndex(x) pin_array[x].pin +#define printPinNameByIndex(x) do{ sprintf_P(buffer, PSTR("%-" STRINGIFY(MAX_NAME_LENGTH) "s"), pin_array[x].name); SERIAL_ECHO(buffer); }while(0) +#define getPinIsDigitalByIndex(x) pin_array[x].is_digital +#define digitalPinToAnalogIndex(P) digital_pin_to_analog_pin(P) -/** - * Translation of routines & variables used by pinsDebug.h - */ -#define NUMBER_PINS_TOTAL NUM_DIGITAL_PINS -#define VALID_PIN(ANUM) (pin_t(ANUM) >= 0 && pin_t(ANUM) < NUMBER_PINS_TOTAL) -#define digitalRead_mod(Ard_num) extDigitalRead(Ard_num) // must use Arduino pin numbers when doing reads -#define PRINT_PIN(Q) -#define PRINT_PIN_ANALOG(p) do{ sprintf_P(buffer, PSTR(" (A%2d) "), DIGITAL_PIN_TO_ANALOG_PIN(pin)); SERIAL_ECHO(buffer); }while(0) -#define DIGITAL_PIN_TO_ANALOG_PIN(ANUM) -1 // will report analog pin number in the print port routine +uint8_t get_pin_mode(const pin_t pin) { + // Check if pin is in alternate function mode (I2C, SPI, etc.) + const uint32_t gpio_func = gpio_get_function(pin); -// x is a variable used to search pin_array -#define GET_ARRAY_IS_DIGITAL(x) ((bool) pin_array[x].is_digital) -#define GET_ARRAY_PIN(x) ((pin_t) pin_array[x].pin) -#define PRINT_ARRAY_NAME(x) do{ sprintf_P(buffer, PSTR("%-" STRINGIFY(MAX_NAME_LENGTH) "s"), pin_array[x].name); SERIAL_ECHO(buffer); }while(0) -#define MULTI_NAME_PAD 33 // space needed to be pretty if not first name assigned to a pin - -uint8_t get_pin_mode(const pin_t Ard_num) { - - uint dir = gpio_get_dir( Ard_num); - - if(dir) return MODE_PIN_OUTPUT; - else return MODE_PIN_INPUT; + // GPIO_FUNC_I2C is typically function 3 on RP2040 + if ( gpio_func == GPIO_FUNC_I2C + || gpio_func == GPIO_FUNC_SPI + || gpio_func == GPIO_FUNC_UART + || gpio_func == GPIO_FUNC_PWM + ) { + return MODE_PIN_ALT; + } + // For GPIO mode, check direction + return gpio_get_dir(pin) ? MODE_PIN_OUTPUT : MODE_PIN_INPUT; } -bool getValidPinMode(const pin_t Ard_num) { - const uint8_t pin_mode = get_pin_mode(Ard_num); +bool getValidPinMode(const pin_t pin) { + const uint8_t pin_mode = get_pin_mode(pin); return pin_mode == MODE_PIN_OUTPUT || pin_mode == MODE_PIN_ALT; // assume all alt definitions are PWM } -int8_t digital_pin_to_analog_pin(pin_t Ard_num) { - Ard_num -= NUM_ANALOG_FIRST; - return (Ard_num >= 0 && Ard_num < NUM_ANALOG_INPUTS) ? Ard_num : -1; +#define isValidPin(P) WITHIN(P, 0, pin_t(NUMBER_PINS_TOTAL - 1)) + +int8_t digital_pin_to_analog_pin(pin_t pin) { + pin -= NUM_ANALOG_FIRST; + return (WITHIN(pin, 0, NUM_ANALOG_INPUTS - 1)) ? pin : -1; } -bool isAnalogPin(const pin_t Ard_num) { - return digital_pin_to_analog_pin(Ard_num) != -1; +bool isAnalogPin(const pin_t pin) { + return digital_pin_to_analog_pin(pin) != -1; } -bool is_digital(const pin_t x) { - const uint8_t pin_mode = get_pin_mode(x); - return pin_mode == MODE_PIN_INPUT || pin_mode == MODE_PIN_OUTPUT; +#define digitalRead_mod(A) extDigitalRead(A) // must use Arduino pin numbers when doing reads +#define printPinNumber(P) do{ sprintf_P(buffer, PSTR("%3d "), P); SERIAL_ECHO(buffer); }while(0) +#define printPinAnalog(P) do{ sprintf_P(buffer, PSTR(" (A%2d) "), digitalPinToAnalogIndex(P)); SERIAL_ECHO(buffer); }while(0) +#define MULTI_NAME_PAD 33 // space needed to be pretty if not first name assigned to a pin + +//bool is_digital(const pin_t pin) { +// const uint8_t pin_mode = get_pin_mode(pin); +// return pin_mode == MODE_PIN_INPUT || pin_mode == MODE_PIN_OUTPUT; +//} + +bool pwm_status(const pin_t pin) { + // Check if this pin is configured for PWM + return PWM_PIN(pin) && get_pin_mode(pin) == MODE_PIN_ALT; } -void printPinPort(const pin_t Ard_num) { - SERIAL_ECHOPGM("Pin: "); - SERIAL_ECHO(Ard_num); -} - -bool pwm_status(const pin_t Ard_num) { - return get_pin_mode(Ard_num) == MODE_PIN_ALT; -} - -void printPinPWM(const pin_t Ard_num) { - if (PWM_PIN(Ard_num)) { +void printPinPWM(const pin_t pin) { + if (pwm_status(pin)) { + // RP2040 has hardware PWM on specific pins + char buffer[22]; + sprintf_P(buffer, PSTR("PWM: pin %d "), pin); + SERIAL_ECHO(buffer); } } + +void printPinPort(const pin_t pin) {} diff --git a/Marlin/src/HAL/RP2040/temp_soc.h b/Marlin/src/HAL/RP2040/temp_soc.h new file mode 100644 index 0000000000..e182fb88dc --- /dev/null +++ b/Marlin/src/HAL/RP2040/temp_soc.h @@ -0,0 +1,30 @@ +/** + * 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 . + * + */ +#pragma once + +// RP2040 internal temperature sensor +// Formula: T = 27 - (ADC_voltage - 0.706) / 0.001721 +// ADC_voltage = (RAW / OVERSAMPLENR) * 3.3 / 4096 (RAW is accumulated over OVERSAMPLENR samples) +// T = 27 - ((RAW / OVERSAMPLENR) * 3.3 / 4096 - 0.706) / 0.001721 +// Simplified: T = 437.423 - (RAW / OVERSAMPLENR) * 0.46875 + +#define TEMP_SOC_SENSOR(RAW) (437.423f - ((RAW) / OVERSAMPLENR) * 0.46875f) diff --git a/Marlin/src/HAL/RP2040/timers.h b/Marlin/src/HAL/RP2040/timers.h index 83fdc0a2fc..8d9fde57a8 100644 --- a/Marlin/src/HAL/RP2040/timers.h +++ b/Marlin/src/HAL/RP2040/timers.h @@ -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 hal_timer_t(UINT64_MAX) -#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 @@ -58,21 +58,20 @@ typedef uint64_t hal_timer_t; #endif #define TEMP_TIMER_RATE HAL_TIMER_RATE -#define TEMP_TIMER_FREQUENCY 1000 // temperature interrupt frequency +#define TEMP_TIMER_FREQUENCY 1000 // (Hz) Temperature ISR frequency #define STEPPER_TIMER_RATE HAL_TIMER_RATE / 10 // 100khz roughly #define STEPPER_TIMER_TICKS_PER_US (0.1) // fixed value as we use a microsecond timesource #define STEPPER_TIMER_PRESCALE (10) -#define PULSE_TIMER_RATE STEPPER_TIMER_RATE // frequency of pulse timer -#define PULSE_TIMER_PRESCALE STEPPER_TIMER_PRESCALE -#define PULSE_TIMER_TICKS_PER_US STEPPER_TIMER_TICKS_PER_US +#define PULSE_TIMER_RATE STEPPER_TIMER_RATE // (Hz) Frequency of Pulse Timer +#define PULSE_TIMER_PRESCALE STEPPER_TIMER_PRESCALE -#define ENABLE_STEPPER_DRIVER_INTERRUPT() HAL_timer_enable_interrupt(MF_TIMER_STEP) -#define DISABLE_STEPPER_DRIVER_INTERRUPT() HAL_timer_disable_interrupt(MF_TIMER_STEP) -#define STEPPER_ISR_ENABLED() HAL_timer_interrupt_enabled(MF_TIMER_STEP) +#define ENABLE_STEPPER_DRIVER_INTERRUPT() HAL_timer_enable_interrupt(MF_TIMER_STEP) +#define DISABLE_STEPPER_DRIVER_INTERRUPT() HAL_timer_disable_interrupt(MF_TIMER_STEP) +#define STEPPER_ISR_ENABLED() HAL_timer_interrupt_enabled(MF_TIMER_STEP) -#define ENABLE_TEMPERATURE_INTERRUPT() HAL_timer_enable_interrupt(MF_TIMER_TEMP) +#define ENABLE_TEMPERATURE_INTERRUPT() HAL_timer_enable_interrupt(MF_TIMER_TEMP) #define DISABLE_TEMPERATURE_INTERRUPT() HAL_timer_disable_interrupt(MF_TIMER_TEMP) #ifndef HAL_STEP_TIMER_ISR @@ -86,10 +85,10 @@ typedef uint64_t hal_timer_t; //#define STEP_TIMER_PTR _HAL_TIMER(MF_TIMER_STEP) //#define TEMP_TIMER_PTR _HAL_TIMER(MF_TIMER_TEMP) -extern alarm_pool_t* HAL_timer_pool_0; -extern alarm_pool_t* HAL_timer_pool_1; -extern alarm_pool_t* HAL_timer_pool_2; -extern alarm_pool_t* HAL_timer_pool_3; +extern alarm_pool_t *HAL_timer_pool_0; +extern alarm_pool_t *HAL_timer_pool_1; +extern alarm_pool_t *HAL_timer_pool_2; +extern alarm_pool_t *HAL_timer_pool_3; extern struct repeating_timer HAL_timer_0; @@ -120,30 +119,25 @@ void HAL_timer_stop(const uint8_t timer_num); FORCE_INLINE static void HAL_timer_set_compare(const uint8_t timer_num, hal_timer_t compare) { - if (timer_num == MF_TIMER_STEP){ - if (compare == HAL_TIMER_TYPE_MAX){ - HAL_timer_stop(timer_num); - return; - } + if (timer_num == MF_TIMER_STEP && compare == HAL_TIMER_TYPE_MAX) { + HAL_timer_stop(timer_num); + return; } - compare = compare *10; //Dirty fix, figure out a proper way + compare *= 10; // Dirty fix, figure out a proper way switch (timer_num) { case 0: - alarm_pool_add_alarm_in_us(HAL_timer_pool_0 ,compare , HAL_timer_alarm_pool_0_callback ,0 ,false ); + alarm_pool_add_alarm_in_us(HAL_timer_pool_0, compare, HAL_timer_alarm_pool_0_callback, 0, false); break; - case 1: - alarm_pool_add_alarm_in_us(HAL_timer_pool_1 ,compare , HAL_timer_alarm_pool_1_callback ,0 ,false ); + alarm_pool_add_alarm_in_us(HAL_timer_pool_1, compare, HAL_timer_alarm_pool_1_callback, 0, false); break; - case 2: - alarm_pool_add_alarm_in_us(HAL_timer_pool_2 ,compare , HAL_timer_alarm_pool_2_callback ,0 ,false ); + alarm_pool_add_alarm_in_us(HAL_timer_pool_2, compare, HAL_timer_alarm_pool_2_callback, 0, false); break; - case 3: - alarm_pool_add_alarm_in_us(HAL_timer_pool_3 ,compare , HAL_timer_alarm_pool_3_callback ,0 ,false ); + alarm_pool_add_alarm_in_us(HAL_timer_pool_3, compare, HAL_timer_alarm_pool_3_callback, 0, false); break; } } @@ -151,27 +145,20 @@ FORCE_INLINE static void HAL_timer_set_compare(const uint8_t timer_num, hal_time FORCE_INLINE static hal_timer_t HAL_timer_get_compare(const uint8_t timer_num) { return 0; } - FORCE_INLINE static hal_timer_t HAL_timer_get_count(const uint8_t timer_num) { if (timer_num == MF_TIMER_STEP) return 0ull; return time_us_64(); } - FORCE_INLINE static void HAL_timer_enable_interrupt(const uint8_t timer_num) { HAL_timer_irq_en[timer_num] = 1; } - FORCE_INLINE static void HAL_timer_disable_interrupt(const uint8_t timer_num) { HAL_timer_irq_en[timer_num] = 0; } - FORCE_INLINE static bool HAL_timer_interrupt_enabled(const uint8_t timer_num) { - return HAL_timer_irq_en[timer_num]; //lucky coincidence that timer_num and rp2040 irq num matches + return HAL_timer_irq_en[timer_num]; // Lucky coincidence that timer_num and rp2040 IRQ num matches } -FORCE_INLINE static void HAL_timer_isr_prologue(const uint8_t timer_num) { - return; -} - -#define HAL_timer_isr_epilogue(T) NOOP +inline void HAL_timer_isr_prologue(const uint8_t) {} +inline void HAL_timer_isr_epilogue(const uint8_t) {} diff --git a/Marlin/src/HAL/RP2040/u8g/LCD_defines.h b/Marlin/src/HAL/RP2040/u8g/LCD_defines.h new file mode 100644 index 0000000000..acdd94b477 --- /dev/null +++ b/Marlin/src/HAL/RP2040/u8g/LCD_defines.h @@ -0,0 +1,28 @@ +/** + * 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 . + * + */ +#pragma once + +/** + * RP2040 LCD-specific defines + */ +uint8_t u8g_com_rp2040_ssd_i2c_fn(u8g_t *u8g, uint8_t msg, uint8_t arg_val, void *arg_ptr); // u8g_com_rp2040_ssd_i2c.cpp +#define U8G_COM_SSD_I2C_HAL u8g_com_rp2040_ssd_i2c_fn diff --git a/Marlin/src/HAL/RP2040/u8g/u8g_com_rp2040_ssd_i2c.cpp b/Marlin/src/HAL/RP2040/u8g/u8g_com_rp2040_ssd_i2c.cpp new file mode 100644 index 0000000000..ea42bf190d --- /dev/null +++ b/Marlin/src/HAL/RP2040/u8g/u8g_com_rp2040_ssd_i2c.cpp @@ -0,0 +1,108 @@ +/** + * 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 . + * + */ + +/** + * 2-Wire I2C COM Driver + * + * Handles Hardware I2C on valid pin combinations. + * Wire library is used for Hardware I2C. + * + * Hardware I2C uses pins defined in pins_arduino.h. + */ + +#ifdef __PLAT_RP2040__ + +#include "../../../inc/MarlinConfig.h" + +#if HAS_U8GLIB_I2C_OLED + +#include + +#include +#ifndef MASTER_ADDRESS + #define MASTER_ADDRESS 0x01 +#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_rp2040_ssd_i2c_fn(u8g_t *u8g, uint8_t msg, uint8_t arg_val, void *arg_ptr) { + + // Hardware I2C flag + //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 + //} + + static uint8_t control; + // Use the global Wire instance (already initialized with correct pins for RP2040) + switch (msg) { + case U8G_COM_MSG_INIT: + Wire.setClock(400000); + // Wire already initialized in MarlinUI::init(), no need to call begin() again + 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: + ::Wire.beginTransmission(0x3C); + ::Wire.write(control); + ::Wire.write(arg_val); + ::Wire.endTransmission(); + break; + + case U8G_COM_MSG_WRITE_SEQ: { + uint8_t* dataptr = (uint8_t*)arg_ptr; + while (arg_val > 0) { + ::Wire.beginTransmission(0x3C); + ::Wire.write(control); + if (arg_val <= I2C_MAX_LENGTH) { + ::Wire.write(dataptr, arg_val); + arg_val = 0; + } + else { + ::Wire.write(dataptr, I2C_MAX_LENGTH); + arg_val -= I2C_MAX_LENGTH; + dataptr += I2C_MAX_LENGTH; + } + ::Wire.endTransmission(); + } + break; + } + } + return 1; +} + +#endif // HAS_U8GLIB_I2C_OLED +#endif // __PLAT_RP2040__ diff --git a/Marlin/src/HAL/SAMD21/HAL.cpp b/Marlin/src/HAL/SAMD21/HAL.cpp index 3656d97190..0a95366cc4 100644 --- a/Marlin/src/HAL/SAMD21/HAL.cpp +++ b/Marlin/src/HAL/SAMD21/HAL.cpp @@ -107,7 +107,7 @@ void MarlinHAL::init() { #if HAS_SD_DETECT && SD_CONNECTION_IS(ONBOARD) SET_INPUT_PULLUP(SD_DETECT_PIN); #endif - OUT_WRITE(SDSS, HIGH); // Try to set SDSS inactive before any other SPI users start up + OUT_WRITE(SD_SS_PIN, HIGH); // Try to set SDSS inactive before any other SPI users start up #endif } diff --git a/Marlin/src/HAL/SAMD21/HAL.h b/Marlin/src/HAL/SAMD21/HAL.h index 63beb29cf1..5545630ce3 100644 --- a/Marlin/src/HAL/SAMD21/HAL.h +++ b/Marlin/src/HAL/SAMD21/HAL.h @@ -36,11 +36,11 @@ // ------------------------ // Serial ports // ------------------------ + #include "../../core/serial_hook.h" typedef ForwardSerial1Class< decltype(SerialUSB) > DefaultSerial1; extern DefaultSerial1 MSerialUSB; -// Serial ports typedef ForwardSerial1Class< decltype(Serial1) > DefaultSerial2; typedef ForwardSerial1Class< decltype(Serial2) > DefaultSerial3; @@ -51,43 +51,10 @@ extern DefaultSerial3 MSerial1; #define _MSERIAL(X) __MSERIAL(X) #define MSERIAL(X) _MSERIAL(INCREMENT(X)) -#if WITHIN(SERIAL_PORT, 0, 1) - #define MYSERIAL1 MSERIAL(SERIAL_PORT) -#elif SERIAL_PORT == -1 - #define MYSERIAL1 MSerialUSB -#else - #error "SERIAL_PORT must be -1 (Native USB only)." -#endif - -#ifdef SERIAL_PORT_2 - #if WITHIN(SERIAL_PORT_2, 0, 1) - #define MYSERIAL2 MSERIAL(SERIAL_PORT) - #elif SERIAL_PORT_2 == -1 - #define MYSERIAL2 MSerialUSB - #else - #error "SERIAL_PORT_2 must be -1 (Native USB only)." - #endif -#endif - -#ifdef MMU_SERIAL_PORT - #if WITHIN(MMU_SERIAL_PORT, 0, 1) - #define MMU_SERIAL MSERIAL(SERIAL_PORT) - #elif MMU_SERIAL_PORT == -1 - #define MMU_SERIAL MSerialUSB - #else - #error "MMU_SERIAL_PORT must be -1 (Native USB only)." - #endif -#endif - -#ifdef LCD_SERIAL_PORT - #if WITHIN(LCD_SERIAL_PORT, 0, 1) - #define LCD_SERIAL MSERIAL(SERIAL_PORT) - #elif LCD_SERIAL_PORT == -1 - #define LCD_SERIAL MSerialUSB - #else - #error "LCD_SERIAL_PORT must be -1 (Native USB only)." - #endif -#endif +#define SERIAL_INDEX_MIN 0 +#define SERIAL_INDEX_MAX 1 +#define USB_SERIAL_PORT(...) MSerialUSB +#include "../shared/serial_ports.h" typedef int8_t pin_t; @@ -177,7 +144,7 @@ public: static void delay_ms(const int ms) { delay(ms); } - // Tasks, called from idle() + // Tasks, called from marlin.idle() static void idletask() {} // Reset diff --git a/Marlin/src/HAL/SAMD21/QSPIFlash.cpp b/Marlin/src/HAL/SAMD21/eeprom/QSPIFlash.cpp similarity index 98% rename from Marlin/src/HAL/SAMD21/QSPIFlash.cpp rename to Marlin/src/HAL/SAMD21/eeprom/QSPIFlash.cpp index fa54c62071..2a93226a6f 100644 --- a/Marlin/src/HAL/SAMD21/QSPIFlash.cpp +++ b/Marlin/src/HAL/SAMD21/eeprom/QSPIFlash.cpp @@ -24,7 +24,7 @@ * SAMD21 HAL developed by Bart Meijer (brupje) * Based on SAMD51 HAL by Giuliano Zaro (AKA GMagician) */ -#include "../../inc/MarlinConfig.h" +#include "../../../inc/MarlinConfig.h" #if ENABLED(QSPI_EEPROM) diff --git a/Marlin/src/HAL/SAMD21/QSPIFlash.h b/Marlin/src/HAL/SAMD21/eeprom/QSPIFlash.h similarity index 100% rename from Marlin/src/HAL/SAMD21/QSPIFlash.h rename to Marlin/src/HAL/SAMD21/eeprom/QSPIFlash.h diff --git a/Marlin/src/HAL/SAMD21/eeprom_flash.cpp b/Marlin/src/HAL/SAMD21/eeprom/eeprom_flash.cpp similarity index 97% rename from Marlin/src/HAL/SAMD21/eeprom_flash.cpp rename to Marlin/src/HAL/SAMD21/eeprom/eeprom_flash.cpp index 66329bff19..0b5323cda4 100644 --- a/Marlin/src/HAL/SAMD21/eeprom_flash.cpp +++ b/Marlin/src/HAL/SAMD21/eeprom/eeprom_flash.cpp @@ -26,7 +26,7 @@ */ #ifdef __SAMD21__ -#include "../../inc/MarlinConfig.h" +#include "../../../inc/MarlinConfig.h" #if ENABLED(FLASH_EEPROM_EMULATION) @@ -35,7 +35,7 @@ /* reserve flash memory */ static const uint8_t flashdata[TOTAL_FLASH_SIZE] __attribute__((__aligned__(256))) { }; \ -#include "../shared/eeprom_api.h" +#include "../../shared/eeprom_api.h" size_t PersistentStore::capacity() { return MARLIN_EEPROM_SIZE - eeprom_exclude_size; } @@ -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) diff --git a/Marlin/src/HAL/SAMD21/eeprom_qspi.cpp b/Marlin/src/HAL/SAMD21/eeprom/eeprom_qspi.cpp similarity index 96% rename from Marlin/src/HAL/SAMD21/eeprom_qspi.cpp rename to Marlin/src/HAL/SAMD21/eeprom/eeprom_qspi.cpp index 12977a178c..8bd1bd3539 100644 --- a/Marlin/src/HAL/SAMD21/eeprom_qspi.cpp +++ b/Marlin/src/HAL/SAMD21/eeprom/eeprom_qspi.cpp @@ -26,13 +26,13 @@ */ #ifdef __SAMD21__ -#include "../../inc/MarlinConfig.h" +#include "../../../inc/MarlinConfig.h" #if ENABLED(QSPI_EEPROM) #error "QSPI_EEPROM emulation Not implemented on SAMD21" -#include "../shared/eeprom_api.h" +#include "../../shared/eeprom_api.h" #include "QSPIFlash.h" diff --git a/Marlin/src/HAL/SAMD21/eeprom_wired.cpp b/Marlin/src/HAL/SAMD21/eeprom/eeprom_wired.cpp similarity index 95% rename from Marlin/src/HAL/SAMD21/eeprom_wired.cpp rename to Marlin/src/HAL/SAMD21/eeprom/eeprom_wired.cpp index da0eb1b0c8..82c701ebb1 100644 --- a/Marlin/src/HAL/SAMD21/eeprom_wired.cpp +++ b/Marlin/src/HAL/SAMD21/eeprom/eeprom_wired.cpp @@ -26,7 +26,7 @@ */ #ifdef __SAMD21__ -#include "../../inc/MarlinConfig.h" +#include "../../../inc/MarlinConfig.h" #if USE_WIRED_EEPROM @@ -36,8 +36,8 @@ * with simple implementations supplied by Marlin. */ -#include "../shared/eeprom_if.h" -#include "../shared/eeprom_api.h" +#include "../../shared/eeprom_if.h" +#include "../../shared/eeprom_api.h" #ifndef MARLIN_EEPROM_SIZE #error "MARLIN_EEPROM_SIZE is required for I2C / SPI EEPROM." diff --git a/Marlin/src/HAL/SAMD21/spi_pins.h b/Marlin/src/HAL/SAMD21/spi_pins.h index 8c25b84dc1..1186c3de48 100644 --- a/Marlin/src/HAL/SAMD21/spi_pins.h +++ b/Marlin/src/HAL/SAMD21/spi_pins.h @@ -45,10 +45,3 @@ #ifndef SD_MOSI_PIN #define SD_MOSI_PIN 37 #endif -#ifndef SDSS - #define SDSS 18 -#endif - -#ifndef SD_SS_PIN - #define SD_SS_PIN SDSS -#endif diff --git a/Marlin/src/HAL/SAMD21/timers.cpp b/Marlin/src/HAL/SAMD21/timers.cpp index b5f1d4f7bd..21a1767fc0 100644 --- a/Marlin/src/HAL/SAMD21/timers.cpp +++ b/Marlin/src/HAL/SAMD21/timers.cpp @@ -165,7 +165,7 @@ void HAL_timer_start(const uint8_t timer_num, const uint32_t frequency) { tc->COUNT32.INTENCLR.reg = TC_INTENCLR_OVF; // disable overflow interrupt // TCn clock setup - GCLK->CLKCTRL.reg = (uint16_t) (GCLK_CLKCTRL_CLKEN | GCLK_CLKCTRL_GEN_GCLK0 | GCLK_CLKCTRL_ID(GCM_TC4_TC5)) ; + GCLK->CLKCTRL.reg = uint16_t(GCLK_CLKCTRL_CLKEN | GCLK_CLKCTRL_GEN_GCLK0 | GCLK_CLKCTRL_ID(GCM_TC4_TC5)); SYNC (GCLK->STATUS.bit.SYNCBUSY); tcReset(tc); // reset TC @@ -176,7 +176,7 @@ void HAL_timer_start(const uint8_t timer_num, const uint32_t frequency) { tc->COUNT32.CTRLA.reg |= TC_CTRLA_WAVEGEN_MFRQ; //set prescaler //the clock normally counts at the GCLK_TC frequency, but we can set it to divide that frequency to slow it down - //you can use different prescaler divisons here like TC_CTRLA_PRESCALER_DIV1 to get a different range + //you can use different prescaler divisions here like TC_CTRLA_PRESCALER_DIV1 to get a different range tc->COUNT32.CTRLA.reg |= TC_CTRLA_PRESCALER_DIV1 | TC_CTRLA_ENABLE; //it will divide GCLK_TC frequency by 1024 //set the compare-capture register. //The counter will count up to this value (it's a 16bit counter so we use uint16_t) diff --git a/Marlin/src/HAL/SAMD21/timers.h b/Marlin/src/HAL/SAMD21/timers.h index 303ccbdc50..dfae605595 100644 --- a/Marlin/src/HAL/SAMD21/timers.h +++ b/Marlin/src/HAL/SAMD21/timers.h @@ -33,7 +33,7 @@ // -------------------------------------------------------------------------- typedef uint32_t hal_timer_t; -#define HAL_TIMER_TYPE_MAX 0xFFFFFFFF +#define HAL_TIMER_TYPE_MAX hal_timer_t(UINT32_MAX) #define HAL_TIMER_RATE F_CPU // frequency of timers peripherals @@ -49,15 +49,14 @@ typedef uint32_t hal_timer_t; #define MF_TIMER_TEMP MF_TIMER_RTC // Timer Index for Temperature #endif -#define TEMP_TIMER_FREQUENCY 1000 // temperature interrupt frequency +#define TEMP_TIMER_FREQUENCY 1000 // (Hz) Temperature ISR 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_RATE HAL_TIMER_RATE // (Hz) Frequency of Stepper Timer ISR (HAL_TIMER_RATE / STEPPER_TIMER_PRESCALE) +#define STEPPER_TIMER_TICKS_PER_US (STEPPER_TIMER_RATE / 1000000) // (MHz) Stepper Timer ticks per µs #define STEPPER_TIMER_PRESCALE (CYCLES_PER_MICROSECOND / STEPPER_TIMER_TICKS_PER_US) -#define PULSE_TIMER_RATE STEPPER_TIMER_RATE -#define PULSE_TIMER_PRESCALE STEPPER_TIMER_PRESCALE -#define PULSE_TIMER_TICKS_PER_US STEPPER_TIMER_TICKS_PER_US +#define PULSE_TIMER_RATE STEPPER_TIMER_RATE // (Hz) Frequency of Pulse Timer +#define PULSE_TIMER_PRESCALE STEPPER_TIMER_PRESCALE #define ENABLE_STEPPER_DRIVER_INTERRUPT() HAL_timer_enable_interrupt(MF_TIMER_STEP) #define DISABLE_STEPPER_DRIVER_INTERRUPT() HAL_timer_disable_interrupt(MF_TIMER_STEP) @@ -143,9 +142,8 @@ FORCE_INLINE static void HAL_timer_isr_prologue(const uint8_t timer_num) { Rtc * const rtc = timer_config[timer_num].pRtc; // Clear interrupt flag rtc->MODE0.INTFLAG.reg = RTC_MODE0_INTFLAG_CMP0| RTC_MODE0_INTFLAG_OVF; - } - else if (timer_config[timer_num].type == TimerType::tcc){ + else if (timer_config[timer_num].type == TimerType::tcc) { Tcc * const tc = timer_config[timer_num].pTcc; // Clear interrupt flag tc->INTFLAG.reg = TCC_INTFLAG_OVF; @@ -157,4 +155,4 @@ FORCE_INLINE static void HAL_timer_isr_prologue(const uint8_t timer_num) { } } -#define HAL_timer_isr_epilogue(timer_num) +inline void HAL_timer_isr_epilogue(const uint8_t) {} diff --git a/Marlin/src/HAL/SAMD21/u8g/LCD_pin_routines.c b/Marlin/src/HAL/SAMD21/u8g/LCD_pin_routines.c index f9f77825f6..b2079fef9b 100644 --- a/Marlin/src/HAL/SAMD21/u8g/LCD_pin_routines.c +++ b/Marlin/src/HAL/SAMD21/u8g/LCD_pin_routines.c @@ -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__ diff --git a/Marlin/src/HAL/SAMD21/u8g/LCD_pin_routines.h b/Marlin/src/HAL/SAMD21/u8g/LCD_pin_routines.h index 92626552b0..a4bf2800fe 100644 --- a/Marlin/src/HAL/SAMD21/u8g/LCD_pin_routines.h +++ b/Marlin/src/HAL/SAMD21/u8g/LCD_pin_routines.h @@ -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); diff --git a/Marlin/src/HAL/SAMD51/HAL.cpp b/Marlin/src/HAL/SAMD51/HAL.cpp index a3c871ce51..aea908707b 100644 --- a/Marlin/src/HAL/SAMD51/HAL.cpp +++ b/Marlin/src/HAL/SAMD51/HAL.cpp @@ -61,7 +61,8 @@ #define GET_COOLER_ADC() TERN(HAS_TEMP_ADC_COOLER, PIN_TO_ADC(TEMP_COOLER_PIN), -1) #define GET_BOARD_ADC() TERN(HAS_TEMP_ADC_BOARD, PIN_TO_ADC(TEMP_BOARD_PIN), -1) #define GET_SOC_ADC() TERN(HAS_TEMP_ADC_BOARD, PIN_TO_ADC(TEMP_BOARD_PIN), -1) -#define GET_FILAMENT_WIDTH_ADC() TERN(FILAMENT_WIDTH_SENSOR, PIN_TO_ADC(FILWIDTH_PIN), -1) +#define GET_FILAMENT_WIDTH_ADC() TERN(HAS_FILWIDTH_ADC, PIN_TO_ADC(FILWIDTH_PIN), -1) +#define GET_FILAMENT2_WIDTH_ADC() TERN(HAS_FILWIDTH2_ADC, PIN_TO_ADC(FILWIDTH2_PIN), -1) #define GET_BUTTONS_ADC() TERN(HAS_ADC_BUTTONS, PIN_TO_ADC(ADC_KEYPAD_PIN), -1) #define GET_JOY_ADC_X() TERN(HAS_JOY_ADC_X, PIN_TO_ADC(JOY_X_PIN), -1) #define GET_JOY_ADC_Y() TERN(HAS_JOY_ADC_Y, PIN_TO_ADC(JOY_Y_PIN), -1) @@ -77,7 +78,7 @@ || GET_PROBE_ADC() == n \ || GET_COOLER_ADC() == n \ || GET_BOARD_ADC() == n || GET_SOC_ADC() == n \ - || GET_FILAMENT_WIDTH_ADC() == n \ + || GET_FILAMENT_WIDTH_ADC() == n || GET_FILAMENT2_WIDTH_ADC() == n \ || GET_BUTTONS_ADC() == n \ || GET_JOY_ADC_X() == n || GET_JOY_ADC_Y() == n || GET_JOY_ADC_Z() == n \ || GET_POWERMON_ADC_CURRENT() == n || GET_POWERMON_ADC_VOLTS() == n \ @@ -146,6 +147,9 @@ enum ADCIndex { #if GET_FILAMENT_WIDTH_ADC() == 0 FILWIDTH, #endif + #if GET_FILAMENT2_WIDTH_ADC() == 0 + FILWIDTH2, + #endif #if GET_BUTTONS_ADC() == 0 ADC_KEY, #endif @@ -212,6 +216,9 @@ enum ADCIndex { #if GET_FILAMENT_WIDTH_ADC() == 1 FILWIDTH, #endif + #if GET_FILAMENT2_WIDTH_ADC() == 1 + FILWIDTH2, + #endif #if GET_BUTTONS_ADC() == 1 ADC_KEY, #endif @@ -334,6 +341,9 @@ enum ADCIndex { #if GET_FILAMENT_WIDTH_ADC() == 0 FILWIDTH_PIN, #endif + #if GET_FILAMENT2_WIDTH_ADC() == 0 + FILWIDTH2_PIN, + #endif #if GET_BUTTONS_ADC() == 0 ADC_KEYPAD_PIN, #endif @@ -400,6 +410,9 @@ enum ADCIndex { #if GET_FILAMENT_WIDTH_ADC() == 1 FILWIDTH_PIN, #endif + #if GET_FILAMENT2_WIDTH_ADC() == 1 + FILWIDTH2_PIN, + #endif #if GET_BUTTONS_ADC() == 1 ADC_KEYPAD_PIN, #endif @@ -471,6 +484,9 @@ enum ADCIndex { #if GET_FILAMENT_WIDTH_ADC() == 0 { PIN_TO_INPUTCTRL(FILWIDTH_PIN) }, #endif + #if GET_FILAMENT2_WIDTH_ADC() == 0 + { PIN_TO_INPUTCTRL(FILWIDTH2_PIN) }, + #endif #if GET_BUTTONS_ADC() == 0 { PIN_TO_INPUTCTRL(ADC_KEYPAD_PIN) }, #endif @@ -543,6 +559,9 @@ enum ADCIndex { #if GET_FILAMENT_WIDTH_ADC() == 1 { PIN_TO_INPUTCTRL(FILWIDTH_PIN) }, #endif + #if GET_FILAMENT2_WIDTH_ADC() == 1 + { PIN_TO_INPUTCTRL(FILWIDTH2_PIN) }, + #endif #if GET_BUTTONS_ADC() == 1 { PIN_TO_INPUTCTRL(ADC_KEYPAD_PIN) }, #endif @@ -669,7 +688,7 @@ void MarlinHAL::init() { #if HAS_SD_DETECT && SD_CONNECTION_IS(ONBOARD) SET_INPUT_PULLUP(SD_DETECT_PIN); #endif - OUT_WRITE(SDSS, HIGH); // Try to set SDSS inactive before any other SPI users start up + OUT_WRITE(SD_SS_PIN, HIGH); // Try to set SDSS inactive before any other SPI users start up #endif } diff --git a/Marlin/src/HAL/SAMD51/HAL.h b/Marlin/src/HAL/SAMD51/HAL.h index 7655f82da1..65dcce966d 100644 --- a/Marlin/src/HAL/SAMD51/HAL.h +++ b/Marlin/src/HAL/SAMD51/HAL.h @@ -34,72 +34,7 @@ #ifdef ADAFRUIT_GRAND_CENTRAL_M4 #include "MarlinSerial_AGCM4.h" - - // Serial ports - typedef ForwardSerial1Class< decltype(Serial) > DefaultSerial1; - typedef ForwardSerial1Class< decltype(Serial1) > DefaultSerial2; - typedef ForwardSerial1Class< decltype(Serial2) > DefaultSerial3; - typedef ForwardSerial1Class< decltype(Serial3) > DefaultSerial4; - typedef ForwardSerial1Class< decltype(Serial4) > DefaultSerial5; - extern DefaultSerial1 MSerial0; - extern DefaultSerial2 MSerial1; - extern DefaultSerial3 MSerial2; - extern DefaultSerial4 MSerial3; - extern DefaultSerial5 MSerial4; - - #define __MSERIAL(X) MSerial##X - #define _MSERIAL(X) __MSERIAL(X) - #define MSERIAL(X) _MSERIAL(INCREMENT(X)) - - #if SERIAL_PORT == -1 - #define MYSERIAL1 MSerial0 - #elif WITHIN(SERIAL_PORT, 0, 3) - #define MYSERIAL1 MSERIAL(SERIAL_PORT) - #else - #error "SERIAL_PORT must be from 0 to 3. You can also use -1 if the board supports Native USB." - #endif - - #ifdef SERIAL_PORT_2 - #if SERIAL_PORT_2 == -1 - #define MYSERIAL2 MSerial0 - #elif WITHIN(SERIAL_PORT_2, 0, 3) - #define MYSERIAL2 MSERIAL(SERIAL_PORT_2) - #else - #error "SERIAL_PORT_2 must be from 0 to 3. You can also use -1 if the board supports Native USB." - #endif - #endif - - #ifdef SERIAL_PORT_3 - #if SERIAL_PORT_3 == -1 - #define MYSERIAL3 MSerial0 - #elif WITHIN(SERIAL_PORT_3, 0, 3) - #define MYSERIAL3 MSERIAL(SERIAL_PORT_3) - #else - #error "SERIAL_PORT_3 must be from 0 to 3. You can also use -1 if the board supports Native USB." - #endif - #endif - - #ifdef MMU_SERIAL_PORT - #if MMU_SERIAL_PORT == -1 - #define MMU_SERIAL MSerial0 - #elif WITHIN(MMU_SERIAL_PORT, 0, 3) - #define MMU_SERIAL MSERIAL(MMU_SERIAL_PORT) - #else - #error "MMU_SERIAL_PORT must be from 0 to 3. You can also use -1 if the board supports Native USB." - #endif - #endif - - #ifdef LCD_SERIAL_PORT - #if LCD_SERIAL_PORT == -1 - #define LCD_SERIAL MSerial0 - #elif WITHIN(LCD_SERIAL_PORT, 0, 3) - #define LCD_SERIAL MSERIAL(LCD_SERIAL_PORT) - #else - #error "LCD_SERIAL_PORT must be from 0 to 3. You can also use -1 if the board supports Native USB." - #endif - #endif - -#endif // ADAFRUIT_GRAND_CENTRAL_M4 +#endif typedef int8_t pin_t; @@ -186,7 +121,7 @@ public: static void delay_ms(const int ms) { delay(ms); } - // Tasks, called from idle() + // Tasks, called from marlin.idle() static void idletask() {} // Reset diff --git a/Marlin/src/HAL/SAMD51/MarlinSerial_AGCM4.h b/Marlin/src/HAL/SAMD51/MarlinSerial_AGCM4.h index 1044d9fcd0..7827c1f958 100644 --- a/Marlin/src/HAL/SAMD51/MarlinSerial_AGCM4.h +++ b/Marlin/src/HAL/SAMD51/MarlinSerial_AGCM4.h @@ -32,3 +32,24 @@ typedef Serial1Class UartT; extern UartT Serial2; extern UartT Serial3; extern UartT Serial4; + +typedef ForwardSerial1Class< decltype(Serial) > DefaultSerial1; +typedef ForwardSerial1Class< decltype(Serial1) > DefaultSerial2; +typedef ForwardSerial1Class< decltype(Serial2) > DefaultSerial3; +typedef ForwardSerial1Class< decltype(Serial3) > DefaultSerial4; +typedef ForwardSerial1Class< decltype(Serial4) > DefaultSerial5; + +extern DefaultSerial1 MSerial0; +extern DefaultSerial2 MSerial1; +extern DefaultSerial3 MSerial2; +extern DefaultSerial4 MSerial3; +extern DefaultSerial5 MSerial4; + +#define __MSERIAL(X) MSerial##X +#define _MSERIAL(X) __MSERIAL(X) +#define MSERIAL(X) _MSERIAL(INCREMENT(X)) + +#define SERIAL_INDEX_MIN 0 +#define SERIAL_INDEX_MAX 3 +#define USB_SERIAL_PORT(...) MSerial0 +#include "../shared/serial_ports.h" diff --git a/Marlin/src/HAL/SAMD51/QSPIFlash.cpp b/Marlin/src/HAL/SAMD51/eeprom/QSPIFlash.cpp similarity index 98% rename from Marlin/src/HAL/SAMD51/QSPIFlash.cpp rename to Marlin/src/HAL/SAMD51/eeprom/QSPIFlash.cpp index fc21a1ad8c..191da1f30c 100644 --- a/Marlin/src/HAL/SAMD51/QSPIFlash.cpp +++ b/Marlin/src/HAL/SAMD51/eeprom/QSPIFlash.cpp @@ -20,7 +20,7 @@ * */ -#include "../../inc/MarlinConfig.h" +#include "../../../inc/MarlinConfig.h" #if ENABLED(QSPI_EEPROM) diff --git a/Marlin/src/HAL/SAMD51/QSPIFlash.h b/Marlin/src/HAL/SAMD51/eeprom/QSPIFlash.h similarity index 100% rename from Marlin/src/HAL/SAMD51/QSPIFlash.h rename to Marlin/src/HAL/SAMD51/eeprom/QSPIFlash.h diff --git a/Marlin/src/HAL/SAMD51/eeprom_flash.cpp b/Marlin/src/HAL/SAMD51/eeprom/eeprom_flash.cpp similarity index 97% rename from Marlin/src/HAL/SAMD51/eeprom_flash.cpp rename to Marlin/src/HAL/SAMD51/eeprom/eeprom_flash.cpp index 7d5518956c..2387a0f99e 100644 --- a/Marlin/src/HAL/SAMD51/eeprom_flash.cpp +++ b/Marlin/src/HAL/SAMD51/eeprom/eeprom_flash.cpp @@ -25,11 +25,11 @@ */ #ifdef __SAMD51__ -#include "../../inc/MarlinConfig.h" +#include "../../../inc/MarlinConfig.h" #if ENABLED(FLASH_EEPROM_EMULATION) -#include "../shared/eeprom_api.h" +#include "../../shared/eeprom_api.h" #define NVMCTRL_CMD(c) do{ \ SYNC(!NVMCTRL->STATUS.bit.READY); \ diff --git a/Marlin/src/HAL/SAMD51/eeprom_qspi.cpp b/Marlin/src/HAL/SAMD51/eeprom/eeprom_qspi.cpp similarity index 96% rename from Marlin/src/HAL/SAMD51/eeprom_qspi.cpp rename to Marlin/src/HAL/SAMD51/eeprom/eeprom_qspi.cpp index a39e4c4fa3..e829c28e26 100644 --- a/Marlin/src/HAL/SAMD51/eeprom_qspi.cpp +++ b/Marlin/src/HAL/SAMD51/eeprom/eeprom_qspi.cpp @@ -25,11 +25,11 @@ */ #ifdef __SAMD51__ -#include "../../inc/MarlinConfig.h" +#include "../../../inc/MarlinConfig.h" #if ENABLED(QSPI_EEPROM) -#include "../shared/eeprom_api.h" +#include "../../shared/eeprom_api.h" #include "QSPIFlash.h" diff --git a/Marlin/src/HAL/SAMD51/eeprom_wired.cpp b/Marlin/src/HAL/SAMD51/eeprom/eeprom_wired.cpp similarity index 95% rename from Marlin/src/HAL/SAMD51/eeprom_wired.cpp rename to Marlin/src/HAL/SAMD51/eeprom/eeprom_wired.cpp index 00a739a587..fc1eb09a0c 100644 --- a/Marlin/src/HAL/SAMD51/eeprom_wired.cpp +++ b/Marlin/src/HAL/SAMD51/eeprom/eeprom_wired.cpp @@ -25,7 +25,7 @@ */ #ifdef __SAMD51__ -#include "../../inc/MarlinConfig.h" +#include "../../../inc/MarlinConfig.h" #if USE_WIRED_EEPROM @@ -34,8 +34,8 @@ * with simple implementations supplied by Marlin. */ -#include "../shared/eeprom_if.h" -#include "../shared/eeprom_api.h" +#include "../../shared/eeprom_if.h" +#include "../../shared/eeprom_api.h" #ifndef MARLIN_EEPROM_SIZE #error "MARLIN_EEPROM_SIZE is required for I2C / SPI EEPROM." diff --git a/Marlin/src/HAL/SAMD51/spi_pins.h b/Marlin/src/HAL/SAMD51/spi_pins.h index 2c7cbeb994..a2d5b72ec4 100644 --- a/Marlin/src/HAL/SAMD51/spi_pins.h +++ b/Marlin/src/HAL/SAMD51/spi_pins.h @@ -46,14 +46,9 @@ #ifndef SD_MOSI_PIN #define SD_MOSI_PIN 51 #endif - #ifndef SDSS - #define SDSS 53 - #endif #else #error "Unsupported board!" #endif - -#define SD_SS_PIN SDSS diff --git a/Marlin/src/HAL/SAMD51/timers.h b/Marlin/src/HAL/SAMD51/timers.h index 86c3241892..2682891cdc 100644 --- a/Marlin/src/HAL/SAMD51/timers.h +++ b/Marlin/src/HAL/SAMD51/timers.h @@ -32,7 +32,7 @@ // -------------------------------------------------------------------------- typedef uint32_t hal_timer_t; -#define HAL_TIMER_TYPE_MAX 0xFFFFFFFF +#define HAL_TIMER_TYPE_MAX hal_timer_t(UINT32_MAX) #define HAL_TIMER_RATE F_CPU // frequency of timers peripherals @@ -48,15 +48,14 @@ typedef uint32_t hal_timer_t; #define MF_TIMER_TEMP MF_TIMER_RTC // Timer Index for Temperature #endif -#define TEMP_TIMER_FREQUENCY 1000 // temperature interrupt frequency +#define TEMP_TIMER_FREQUENCY 1000 // (Hz) Temperature ISR 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_RATE HAL_TIMER_RATE // (Hz) Frequency of Stepper Timer ISR (HAL_TIMER_RATE / STEPPER_TIMER_PRESCALE) +#define STEPPER_TIMER_TICKS_PER_US (STEPPER_TIMER_RATE / 1000000) // (MHz) Stepper Timer ticks per µs #define STEPPER_TIMER_PRESCALE (CYCLES_PER_MICROSECOND / STEPPER_TIMER_TICKS_PER_US) -#define PULSE_TIMER_RATE STEPPER_TIMER_RATE -#define PULSE_TIMER_PRESCALE STEPPER_TIMER_PRESCALE -#define PULSE_TIMER_TICKS_PER_US STEPPER_TIMER_TICKS_PER_US +#define PULSE_TIMER_RATE STEPPER_TIMER_RATE // (Hz) Frequency of Pulse Timer +#define PULSE_TIMER_PRESCALE STEPPER_TIMER_PRESCALE #define ENABLE_STEPPER_DRIVER_INTERRUPT() HAL_timer_enable_interrupt(MF_TIMER_STEP) #define DISABLE_STEPPER_DRIVER_INTERRUPT() HAL_timer_disable_interrupt(MF_TIMER_STEP) @@ -145,4 +144,4 @@ FORCE_INLINE static void HAL_timer_isr_prologue(const uint8_t timer_num) { } } -#define HAL_timer_isr_epilogue(timer_num) +inline void HAL_timer_isr_epilogue(const uint8_t) {} diff --git a/Marlin/src/HAL/STM32/HAL.cpp b/Marlin/src/HAL/STM32/HAL.cpp index 610bd0b243..018fb48881 100644 --- a/Marlin/src/HAL/STM32/HAL.cpp +++ b/Marlin/src/HAL/STM32/HAL.cpp @@ -43,8 +43,8 @@ #endif #if HAS_SD_HOST_DRIVE - #include "msc_sd.h" - #include "usbd_cdc_if.h" + #include "sd/msc_sd.h" + #include #endif // ------------------------ @@ -66,11 +66,11 @@ 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) && (defined(SDSS) && SDSS != -1) - OUT_WRITE(SDSS, HIGH); // Try to set SDSS inactive before any other SPI users start up + #if HAS_MEDIA && DISABLED(ONBOARD_SDIO) && PIN_EXISTS(SD_SS) + OUT_WRITE(SD_SS_PIN, HIGH); // Try to set SDSS inactive before any other SPI users start up #endif #if PIN_EXISTS(LED) @@ -87,7 +87,7 @@ void MarlinHAL::init() { SetTimerInterruptPriorities(); - #if ENABLED(EMERGENCY_PARSER) && (USBD_USE_CDC || USBD_USE_CDC_MSC) + #if ENABLED(EMERGENCY_PARSER) && ANY(USBD_USE_CDC, USBD_USE_CDC_MSC) USB_Hook_init(); #endif @@ -97,7 +97,7 @@ void MarlinHAL::init() { #if PIN_EXISTS(USB_CONNECT) OUT_WRITE(USB_CONNECT_PIN, !USB_CONNECT_INVERTING); // USB clear connection - delay(1000); // Give OS time to notice + delay_ms(1000); // Give OS time to notice WRITE(USB_CONNECT_PIN, USB_CONNECT_INVERTING); #endif } @@ -114,7 +114,7 @@ void MarlinHAL::idletask() { void MarlinHAL::reboot() { NVIC_SystemReset(); } uint8_t MarlinHAL::get_reset_source() { - return + return ( #ifdef RCC_FLAG_IWDGRST // Some sources may not exist... RESET != __HAL_RCC_GET_FLAG(RCC_FLAG_IWDGRST) ? RST_WATCHDOG : #endif @@ -134,7 +134,7 @@ uint8_t MarlinHAL::get_reset_source() { RESET != __HAL_RCC_GET_FLAG(RCC_FLAG_PORRST) ? RST_POWER_ON : #endif 0 - ; + ); } void MarlinHAL::clear_reset_source() { __HAL_RCC_CLEAR_RESET_FLAGS(); } diff --git a/Marlin/src/HAL/STM32/HAL.h b/Marlin/src/HAL/STM32/HAL.h index eab31be265..24889c872a 100644 --- a/Marlin/src/HAL/STM32/HAL.h +++ b/Marlin/src/HAL/STM32/HAL.h @@ -23,18 +23,13 @@ #define CPU_32_BIT -#include "../../core/macros.h" -#include "../shared/Marduino.h" +#include "../../inc/MarlinConfigPre.h" + #include "../shared/math_32bit.h" #include "../shared/HAL_SPI.h" #include "temp_soc.h" #include "fastio.h" #include "Servo.h" -#include "MarlinSerial.h" - -#include "../../inc/MarlinConfigPre.h" - -#include // // Default graphical display delays @@ -43,87 +38,11 @@ #define CPU_ST7920_DELAY_2 40 #define CPU_ST7920_DELAY_3 340 -// ------------------------ -// Serial ports -// ------------------------ -#ifdef USBCON - #include - #include "../../core/serial_hook.h" - typedef ForwardSerial1Class< decltype(SerialUSB) > DefaultSerial1; - extern DefaultSerial1 MSerialUSB; -#endif +// +// Serial Ports +// -#define _MSERIAL(X) MSerial##X -#define MSERIAL(X) _MSERIAL(X) - -#if WITHIN(SERIAL_PORT, 1, 9) - #define MYSERIAL1 MSERIAL(SERIAL_PORT) -#elif !defined(USBCON) - #error "SERIAL_PORT must be from 1 to 9." -#elif SERIAL_PORT == -1 - #define MYSERIAL1 MSerialUSB -#else - #error "SERIAL_PORT must be from 1 to 9, or -1 for Native USB." -#endif - -#ifdef SERIAL_PORT_2 - #if WITHIN(SERIAL_PORT_2, 1, 9) - #define MYSERIAL2 MSERIAL(SERIAL_PORT_2) - #elif !defined(USBCON) - #error "SERIAL_PORT_2 must be from 1 to 9." - #elif SERIAL_PORT_2 == -1 - #define MYSERIAL2 MSerialUSB - #else - #error "SERIAL_PORT_2 must be from 1 to 9, or -1 for Native USB." - #endif -#endif - -#ifdef SERIAL_PORT_3 - #if WITHIN(SERIAL_PORT_3, 1, 9) - #define MYSERIAL3 MSERIAL(SERIAL_PORT_3) - #elif !defined(USBCON) - #error "SERIAL_PORT_3 must be from 1 to 9." - #elif SERIAL_PORT_3 == -1 - #define MYSERIAL3 MSerialUSB - #else - #error "SERIAL_PORT_3 must be from 1 to 9, or -1 for Native USB." - #endif -#endif - -#ifdef MMU_SERIAL_PORT - #if WITHIN(MMU_SERIAL_PORT, 1, 9) - #define MMU_SERIAL MSERIAL(MMU_SERIAL_PORT) - #elif !defined(USBCON) - #error "MMU_SERIAL_PORT must be from 1 to 9." - #elif MMU_SERIAL_PORT == -1 - #define MMU_SERIAL MSerialUSB - #else - #error "MMU_SERIAL_PORT must be from 1 to 9, or -1 for Native USB." - #endif -#endif - -#ifdef LCD_SERIAL_PORT - #if WITHIN(LCD_SERIAL_PORT, 1, 9) - #define LCD_SERIAL MSERIAL(LCD_SERIAL_PORT) - #elif !defined(USBCON) - #error "LCD_SERIAL_PORT must be from 1 to 9." - #elif LCD_SERIAL_PORT == -1 - #define LCD_SERIAL MSerialUSB - #else - #error "LCD_SERIAL_PORT must be from 1 to 9, or -1 for Native USB." - #endif - #if ANY(HAS_DGUS_LCD, EXTENSIBLE_UI) - #define LCD_SERIAL_TX_BUFFER_FREE() LCD_SERIAL.availableForWrite() - #endif -#endif - -#ifdef RS485_SERIAL_PORT - #if WITHIN(RS485_SERIAL_PORT, 1, 9) - #define RS485_SERIAL MSERIAL(RS485_SERIAL_PORT) - #else - #error "RS485_SERIAL_PORT must be from 1 to 9." - #endif -#endif +#include "MarlinSerial.h" /** * TODO: review this to return 1 for pins that are not analog input @@ -144,8 +63,6 @@ // Types // ------------------------ -typedef double isr_float_t; // FPU ops are used for single-precision, so use double for ISRs. - typedef int32_t pin_t; // Parity with platform/ststm32 class libServo; @@ -238,7 +155,7 @@ public: static void delay_ms(const int ms) { delay(ms); } - // Tasks, called from idle() + // Tasks, called from marlin.idle() static void idletask(); // Reset diff --git a/Marlin/src/HAL/STM32/HardwareSerial.cpp b/Marlin/src/HAL/STM32/HardwareSerial.cpp index 2a389447b7..58360cc31e 100644 --- a/Marlin/src/HAL/STM32/HardwareSerial.cpp +++ b/Marlin/src/HAL/STM32/HardwareSerial.cpp @@ -37,7 +37,17 @@ #include "HardwareSerial.h" #include "uart.h" -// USART/UART PIN MAPPING FOR STM32F0/F1/F2/F4/F7 +// Prevent selection of LPUART1 on STM32H7xx +#if defined(STM32H7xx) && (PIN_SERIAL1_TX == PA_9) + #undef PIN_SERIAL1_TX + #define PIN_SERIAL1_TX PA_9_ALT1 +#endif +#if defined(STM32H7xx) && (PIN_SERIAL1_RX == PA_10) + #undef PIN_SERIAL1_RX + #define PIN_SERIAL1_RX PA_10_ALT1 +#endif + +// USART/UART pin mapping for STM32F0/F1/F2/F4/F7/H7 #ifndef PIN_SERIAL1_TX #define PIN_SERIAL1_TX PA9 #endif @@ -75,46 +85,6 @@ #define PIN_SERIAL6_RX PC7 #endif -// TODO: Get from include file - -#if ANY(STM32F2xx, STM32F4xx, STM32F7xx) - - #define RCC_AHB1Periph_DMA1 ((uint32_t)0x00200000) - #define RCC_AHB1Periph_DMA2 ((uint32_t)0x00400000) - - void RCC_AHB1PeriphClockCmd(uint32_t RCC_AHB1Periph, FunctionalState NewState) { - // Check the parameters - assert_param(IS_RCC_AHB1_CLOCK_PERIPH(RCC_AHB1Periph)); - - assert_param(IS_FUNCTIONAL_STATE(NewState)); - if (NewState != DISABLE) - RCC->AHB1ENR |= RCC_AHB1Periph; - else - RCC->AHB1ENR &= ~RCC_AHB1Periph; - } - -#endif - -#if ANY(STM32F0xx, STM32F1xx) - - #define RCC_AHBPeriph_DMA1 ((uint32_t)0x00000001) - #define RCC_AHBPeriph_DMA2 ((uint32_t)0x00000002) - - void RCC_AHBPeriphClockCmd(uint32_t RCC_AHBPeriph, FunctionalState NewState) { - /* Check the parameters */ - assert_param(IS_RCC_AHB_PERIPH(RCC_AHBPeriph)); - assert_param(IS_FUNCTIONAL_STATE(NewState)); - - if (NewState != DISABLE) - RCC->AHBENR |= RCC_AHBPeriph; - else - RCC->AHBENR &= ~RCC_AHBPeriph; - } - -#endif - -// END OF TODO------------------------------------------------------ - // SerialEvent functions are weak, so when the user doesn't define them, // the linker just sets their address to 0 (which is checked below). #ifdef USING_HW_SERIAL1 @@ -161,11 +131,12 @@ HAL_HardwareSerial::HAL_HardwareSerial(void *peripheral) { setRx(PIN_SERIAL1_RX); setTx(PIN_SERIAL1_TX); _uart_index = 0; - #ifdef DMA2_Stream2 - RX_DMA = { USART1, RCC_AHB1Periph_DMA2, 4, DMA2_Stream2 }; + + #ifdef DMA2_Stream2 // F2 / F4 / F7 / H7 + RX_DMA = { USART1, 2, DMA2_Stream2 }; // USART, DMA controller no., DMA stream #endif - #ifdef DMA1_Channel5 - RX_DMA = { USART1, RCC_AHBPeriph_DMA1, DMA1, DMA1_Channel5 }; + #ifdef DMA1_Channel5 // F0 / F1 + RX_DMA = { USART1, 1, DMA1_Channel5 }; // USART, DMA controller no., DMA channel #endif } else if (peripheral == USART2) { @@ -173,10 +144,10 @@ HAL_HardwareSerial::HAL_HardwareSerial(void *peripheral) { setTx(PIN_SERIAL2_TX); _uart_index = 1; #ifdef DMA1_Stream5 - RX_DMA = { USART2, RCC_AHB1Periph_DMA1, 4, DMA1_Stream5 }; + RX_DMA = { USART2, 1, DMA1_Stream5 }; #endif #ifdef DMA1_Channel6 - RX_DMA = { USART2, RCC_AHBPeriph_DMA1, DMA1, DMA1_Channel6 }; + RX_DMA = { USART2, 1, DMA1_Channel6 }; #endif } else if (peripheral == USART3) { @@ -184,17 +155,17 @@ HAL_HardwareSerial::HAL_HardwareSerial(void *peripheral) { setTx(PIN_SERIAL3_TX); _uart_index = 2; #ifdef DMA1_Stream1 - RX_DMA = { USART3, RCC_AHB1Periph_DMA1, 4, DMA1_Stream1 }; + RX_DMA = { USART3, 1, DMA1_Stream1 }; #endif #ifdef DMA1_Channel3 // F0 has no support for UART3, requires system remapping - RX_DMA = { USART3, RCC_AHBPeriph_DMA1, DMA1, DMA1_Channel3 }; + RX_DMA = { USART3, 1, DMA1_Channel3 }; #endif } #ifdef USART4 // Only F2 / F4 / F7 else if (peripheral == USART4) { #ifdef DMA1_Stream2 - RX_DMA = { USART4, RCC_AHB1Periph_DMA1, 4, DMA1_Stream2 }; + RX_DMA = { USART4, 1, DMA1_Stream2 }; #endif setRx(PIN_SERIAL4_RX); setTx(PIN_SERIAL4_TX); @@ -205,10 +176,10 @@ HAL_HardwareSerial::HAL_HardwareSerial(void *peripheral) { #ifdef UART4 else if (peripheral == UART4) { #ifdef DMA1_Stream2 - RX_DMA = { UART4, RCC_AHB1Periph_DMA1, 4, DMA1_Stream2 }; + RX_DMA = { UART4, 1, DMA1_Stream2 }; #endif #ifdef DMA2_Channel3 // STM32F0xx has only 3 UARTs - RX_DMA = { UART4, RCC_AHBPeriph_DMA2, DMA2, DMA2_Channel3 }; + RX_DMA = { UART4, 2, DMA2_Channel3 }; #endif setRx(PIN_SERIAL4_RX); setTx(PIN_SERIAL4_TX); @@ -216,10 +187,10 @@ HAL_HardwareSerial::HAL_HardwareSerial(void *peripheral) { } #endif - #ifdef UART5 // Only F2 / F4 / F7 + #ifdef UART5 // Only F2 / F4 / F7 / H7 else if (peripheral == UART5) { #ifdef DMA1_Stream0 - RX_DMA = { UART5, RCC_AHB1Periph_DMA1, 4, DMA1_Stream0 }; + RX_DMA = { UART5, 1, DMA1_Stream0 }; #endif setRx(PIN_SERIAL5_RX); setTx(PIN_SERIAL5_TX); @@ -227,10 +198,10 @@ HAL_HardwareSerial::HAL_HardwareSerial(void *peripheral) { } #endif - #ifdef USART6 // Only F2 / F4 / F7 + #ifdef USART6 // Only F2 / F4 / F7 / H7 else if (peripheral == USART6) { #ifdef DMA2_Stream1 - RX_DMA = { USART6, RCC_AHB1Periph_DMA2, 4, DMA2_Stream1 }; + RX_DMA = { USART6, 2, DMA2_Stream1 }; #endif setRx(PIN_SERIAL6_RX); setTx(PIN_SERIAL6_TX); @@ -238,7 +209,7 @@ HAL_HardwareSerial::HAL_HardwareSerial(void *peripheral) { } #endif - else { // else get the pins of the first peripheral occurence in PinMap + else { // else get the pins of the first peripheral occurrence in PinMap _serial.pin_rx = pinmap_pin(peripheral, PinMap_UART_RX); _serial.pin_tx = pinmap_pin(peripheral, PinMap_UART_TX); } @@ -271,14 +242,34 @@ void HAL_HardwareSerial::init(PinName _rx, PinName _tx) { * @param obj : pointer to serial_t structure * @retval last character received */ -int HAL_HardwareSerial::_tx_complete_irq(serial_t *obj) { - // If interrupts are enabled, there must be more data in the output buffer. Send the next byte - obj->tx_tail = (obj->tx_tail + 1) % TX_BUFFER_SIZE; - if (obj->tx_head == obj->tx_tail) return -1; +#if DISABLED(STM32H7xx) - return 0; -} + int HAL_HardwareSerial::_tx_complete_irq(serial_t *obj) { + // If interrupts are enabled, there must be more data in the output buffer. Send the next byte + obj->tx_tail = (obj->tx_tail + 1) % TX_BUFFER_SIZE; + if (obj->tx_head == obj->tx_tail) + return -1; + + return 0; + } + +#else // STM32H7xx, has different uart_attach_tx_callback + + int HAL_HardwareSerial::_tx_complete_irq(serial_t *obj) { + // If interrupts are enabled, there must be more data in the output buffer. Send the next byte + obj->tx_tail = (obj->tx_tail + obj->tx_size) % TX_BUFFER_SIZE; + + if (obj->tx_head != obj->tx_tail) { + size_t remaining_data = (TX_BUFFER_SIZE + obj->tx_head - obj->tx_tail) % TX_BUFFER_SIZE; + obj->tx_size = min(remaining_data, (size_t)(TX_BUFFER_SIZE - obj->tx_tail)); + uart_attach_tx_callback(obj, _tx_complete_irq, obj->tx_size); + return -1; + } + return 0; + } + +#endif // Public Methods ////////////////////////////////////////////////////////////// @@ -340,7 +331,7 @@ void HAL_HardwareSerial::update_rx_head() { } #endif - #if ANY(STM32F2xx, STM32F4xx, STM32F7xx) + #if ANY(STM32F2xx, STM32F4xx, STM32F7xx, STM32H7xx) _serial.rx_head = RX_BUFFER_SIZE - RX_DMA.dma_streamRX->NDTR; #endif @@ -352,18 +343,22 @@ void HAL_HardwareSerial::update_rx_head() { int HAL_HardwareSerial::available() { update_rx_head(); + return ((unsigned int)(RX_BUFFER_SIZE + _serial.rx_head - _serial.rx_tail)) % RX_BUFFER_SIZE; } int HAL_HardwareSerial::peek() { update_rx_head(); - if (_serial.rx_head == _serial.rx_tail) return -1; + if (_serial.rx_head == _serial.rx_tail) + return -1; + return _serial.rx_buff[_serial.rx_tail]; } int HAL_HardwareSerial::read() { update_rx_head(); - if (_serial.rx_head == _serial.rx_tail) return -1; // No chars if the head isn't ahead of the tail + if (_serial.rx_head == _serial.rx_tail) + return -1; // No chars if the head isn't ahead of the tail unsigned char c = _serial.rx_buff[_serial.rx_tail]; _serial.rx_tail = (rx_buffer_index_t)(_serial.rx_tail + 1) % RX_BUFFER_SIZE; @@ -380,8 +375,18 @@ size_t HAL_HardwareSerial::write(uint8_t c) { // Interrupt based wri _serial.tx_buff[_serial.tx_head] = c; _serial.tx_head = i; - if (!serial_tx_active(&_serial)) - uart_attach_tx_callback(&_serial, _tx_complete_irq); // Write next byte, launch interrupt + #ifdef STM32H7xx // Support STM32H7xx with different uart_attach_tx_callback + if ((!serial_tx_active(&_serial)) && (_serial.tx_head != _serial.tx_tail)) { + size_t remaining_data = (TX_BUFFER_SIZE + _serial.tx_head -_serial.tx_tail) % TX_BUFFER_SIZE; + _serial.tx_size = min(remaining_data, (size_t)(TX_BUFFER_SIZE - _serial.tx_tail)); + uart_attach_tx_callback(&_serial, _tx_complete_irq, _serial.tx_size); + + return -1; + } + #else + if (!serial_tx_active(&_serial)) + uart_attach_tx_callback(&_serial, _tx_complete_irq); // Write next byte, launch interrupt + #endif return 1; } @@ -390,57 +395,132 @@ void HAL_HardwareSerial::flush() { while ((_serial.tx_head != _serial.tx_tail)) { /* nada */ } // nop, the interrupt handler will free up space for us } -#if ANY(STM32F2xx, STM32F4xx, STM32F7xx) +#if ANY(STM32F2xx, STM32F4xx, STM32F7xx, STM32H7xx) void HAL_HardwareSerial::Serial_DMA_Read_Enable() { - RCC_AHB1PeriphClockCmd(RX_DMA.dma_rcc, ENABLE); // Enable DMA clock - #ifdef STM32F7xx - RX_DMA.dma_streamRX->PAR = (uint32_t)(&RX_DMA.uart->RDR); // RX peripheral receive address (usart) F7 + if (RX_DMA.DMA_ID == 1) + __HAL_RCC_DMA1_CLK_ENABLE(); // Enable DMA1 clock + else + __HAL_RCC_DMA2_CLK_ENABLE(); // Enable DMA2 clock + + // Reset DMA, wait if needed to complete the running process + RX_DMA.dma_streamRX->CR = 0; // DMA stream clear/disable + while (RX_DMA.dma_streamRX->CR & DMA_SxCR_EN) { /* just wait for DMA to complete */ } + + // UART clear/disable + RX_DMA.uart->CR1 = 0; + + // Configure DMA + #if ANY(STM32F7xx, STM32H7xx) // F7 and H7 use RDR (Receive Data Register) + RX_DMA.dma_streamRX->PAR = (uint32_t)(&RX_DMA.uart->RDR); // DMA stream Peripheral Address Register = USART Data Register #else - RX_DMA.dma_streamRX->PAR = (uint32_t)(&RX_DMA.uart->DR); // RX peripheral address (usart) F2 / F4 + RX_DMA.dma_streamRX->PAR = (uint32_t)(&RX_DMA.uart->DR); // DMA stream Peripheral Address Register = USART Data Register #endif - RX_DMA.dma_streamRX->M0AR = (uint32_t)_serial.rx_buff; // RX destination address (memory) - RX_DMA.dma_streamRX->NDTR = RX_BUFFER_SIZE; // RX buffer size - RX_DMA.dma_streamRX->CR = (RX_DMA.dma_channel << 25); // RX channel selection, set to 0 all the other CR bits + RX_DMA.dma_streamRX->M0AR = (uint32_t)_serial.rx_buff; // DMA stream Memory 0 Adress Register = RX buffer address + RX_DMA.dma_streamRX->NDTR = RX_BUFFER_SIZE; // DMA stream Number of Data Transfer Register - RX_DMA.dma_streamRX->CR |= (3 << 16); // RX priority level: Very High + #if DISABLED(STM32H7xx) // Select channel via CR register - //RX_DMA.dma_streamRX->CR &= ~(3 << 13); // RX memory data size: 8 bit - //RX_DMA.dma_streamRX->CR &= ~(3 << 11); // RX peripheral data size: 8 bit - RX_DMA.dma_streamRX->CR |= (1 << 10); // RX memory increment mode - //RX_DMA.dma_streamRX->CR &= ~(1 << 9); // RX peripheral no increment mode - RX_DMA.dma_streamRX->CR |= (1 << 8); // RX circular mode enabled - //RX_DMA.dma_streamRX->CR &= ~(1 << 6); // RX data transfer direction: Peripheral-to-memory - RX_DMA.uart->CR3 |= (1 << 6); // Enable DMA receiver (DMAR) - RX_DMA.dma_streamRX->CR |= (1 << 0); // RX enable DMA + RX_DMA.dma_streamRX->CR = 4 << DMA_SxCR_CHSEL_Pos; // DMA stream Channel Selection, always use channel 4 + + #else // STM32H7xx, select channel with DMAMUX1, channel DMA1 is channel DMAMUX, channel DMA2 is channel DMAMUX + 8 + + if (RX_DMA.uart == USART1) DMAMUX1_Channel10->CCR |= DMA_REQUEST_USART1_RX; // DMA2, Stream 2 + if (RX_DMA.uart == USART2) DMAMUX1_Channel5->CCR |= DMA_REQUEST_USART2_RX; // DMA1, Stream 5 + if (RX_DMA.uart == USART3) DMAMUX1_Channel1->CCR |= DMA_REQUEST_USART3_RX; // DMA1, Stream 1 + #ifdef UART4 + if (RX_DMA.uart == UART4) DMAMUX1_Channel2->CCR |= DMA_REQUEST_UART4_RX; // DMA1, Stream 2 + #endif + #ifdef USART4 + if (RX_DMA.uart == USART4) DMAMUX1_Channel2->CCR |= DMA_REQUEST_USART4_RX; // DMA1, Stream 2 + #endif + #ifdef UART5 + if (RX_DMA.uart == UART5) DMAMUX1_Channel0->CCR |= DMA_REQUEST_UART5_RX; // DMA1, Stream 0 + #endif + #ifdef USART6 + if (RX_DMA.uart == USART6) DMAMUX1_Channel9->CCR |= DMA_REQUEST_USART6_RX; // DMA2, Stream 1 + #endif + + #endif // !STM32H7xx + + // Configure DMA + //RX_DMA.dma_streamRX->CR |= DMA_MBURST_SINGLE; // DMA stream Memory Burst transfer: single transfer = 0b00 + //RX_DMA.dma_streamRX->CR |= DMA_PBURST_SINGLE; // DMA stream Peripheral Burst transfer: single transfer = 0b00 + + #if ENABLED(STM32H7xx) + RX_DMA.dma_streamRX->CR |= DMA_SxCR_TRBUFF; // DMA stream Transfer handle bufferable (required for UART/USART) + #endif + + //RX_DMA.dma_streamRX->CR &= ~DMA_SxCR_CT; // DMA stream Current Target (only in double buffer mode) + //RX_DMA.dma_streamRX->CR &= ~DMA_SxCR_DBM; // DMA stream Double Buffer Mode + //RX_DMA.dma_streamRX->CR |= DMA_PRIORITY_LOW; // DMA stream Priority Level Low = 0b00 + //RX_DMA.dma_streamRX->CR &= ~DMA_SxCR_PINCOS; // DMA stream Peripheral Increment Offset Size + //RX_DMA.dma_streamRX->CR &= ~DMA_SxCR_MSIZE; // DMA stream Memory data Size: 8 bit = 0b00 + //RX_DMA.dma_streamRX->CR &= ~DMA_SxCR_PSIZE; // DMA stream Peripheral data Size: 8 bit = 0b00 + RX_DMA.dma_streamRX->CR |= DMA_SxCR_MINC; // DMA stream Memory Increment enable + //RX_DMA.dma_streamRX->CR &= ~DMA_SxCR_PINC; // DMA stream Peripheral increment + RX_DMA.dma_streamRX->CR |= DMA_SxCR_CIRC; // DMA stream Circular mode enable + //RX_DMA.dma_streamRX->CR |= DMA_PERIPH_TO_MEMORY; // DMA stream transfer Direction: Peripheral-to-memory = b00 + //RX_DMA.dma_streamRX->CR &= ~DMA_SxCR_PFCTRL; // DMA stream Peripheral Flow Controller: DMA = 0 + //RX_DMA.dma_streamRX->CR &= ~DMA_SxCR_TCIE; // DMA stream Transfer Complete Interrupt + //RX_DMA.dma_streamRX->CR &= ~DMA_SxCR_HTIE; // DMA stream Half Transfer Interrupt + //RX_DMA.dma_streamRX->CR &= ~DMA_SxCR_TEIE; // DMA stream Transfer Error Interrupt + //RX_DMA.dma_streamRX->CR &= ~DMA_SxCR_DMEIE; // DMA stream Direct Mode Error Interrupt + RX_DMA.dma_streamRX->CR |= DMA_SxCR_EN; // DMA stream Enable + + // Configure UART/USART + RX_DMA.uart->CR3 |= USART_CR3_DMAR; // UART DMA Receiver + RX_DMA.uart->CR1 |= USART_CR1_TE; // UART Transmitter Enable + RX_DMA.uart->CR1 |= USART_CR1_RE; // UART Receiver Enable + RX_DMA.uart->CR1 |= USART_CR1_UE; // UART Enable } -#endif // STM32F2xx || STM32F4xx || STM32F7xx +#endif // STM32F2xx || STM32F4xx || STM32F7xx || STM32H7xx #if ANY(STM32F0xx, STM32F1xx) void HAL_HardwareSerial::Serial_DMA_Read_Enable() { - RCC_AHBPeriphClockCmd(RX_DMA.dma_rcc, ENABLE); // enable DMA clock - RX_DMA.dma_channelRX->CPAR = (uint32_t)(&RX_DMA.uart->DR); // RX peripheral address (usart) - RX_DMA.dma_channelRX->CMAR = (uint32_t)_serial.rx_buff; // RX destination address (memory) - RX_DMA.dma_channelRX->CNDTR = RX_BUFFER_SIZE; // RX buffer size + if (RX_DMA.DMA_ID == 1) + __HAL_RCC_DMA1_CLK_ENABLE(); // enable DMA1 clock + else + __HAL_RCC_DMA2_CLK_ENABLE(); // enable DMA2 clock - RX_DMA.dma_channelRX->CCR = 0; // RX channel selection, set to 0 all the other CR bits + RX_DMA.dma_channelRX->CCR &= ~USART_CR1_UE; // DMA stream clear/disable + while (RX_DMA.dma_channelRX->CCR & DMA_CCR_EN) { /* just wait for DMA to complete */ } - RX_DMA.dma_channelRX->CCR |= (3<<12); // RX priority level: Very High + // Clear/disable UART and DMA + RX_DMA.uart->CR1 = 0; // UART clear CR1, disable DMA - //RX_DMA.dma_channelRX->CCR &= ~(1<<10); // RX memory data size: 8 bit - //RX_DMA.dma_channelRX->CCR &= ~(1<<8); // RX peripheral data size: 8 bit - RX_DMA.dma_channelRX->CCR |= (1<<7); // RX memory increment mode - //RX_DMA.dma_channelRX->CCR &= ~(1<<6); // RX peripheral no increment mode - RX_DMA.dma_channelRX->CCR |= (1<<5); // RX circular mode enabled - //RX_DMA.dma_channelRX->CCR &= ~(1<<4); // RX data transfer direction: Peripheral-to-memory + // Configure DMA - RX_DMA.uart->CR3 |= (1<<6); // enable DMA receiver (DMAR) - RX_DMA.dma_channelRX->CCR |= (1<<0); // RX enable DMA + #ifdef STM32F0xx + RX_DMA.dma_channelRX->CPAR = (uint32_t)(&RX_DMA.uart->RDR); // DMA channel Peripheral Address Register = USART Data Register + #else + RX_DMA.dma_channelRX->CPAR = (uint32_t)(&RX_DMA.uart->DR); // DMA channel Peripheral Address Register = USART Data Register + #endif + + RX_DMA.dma_channelRX->CMAR = (uint32_t)_serial.rx_buff; // DMA channel Memory Address Register + RX_DMA.dma_channelRX->CNDTR = RX_BUFFER_SIZE; // DMA channel Number of Data Transfer Register + //RX_DMA.dma_channelRX->CCR |= (0b00 << DMA_CCR_PL_Pos); // DMA channel Priority Level: Low = 0b00 + //RX_DMA.dma_channelRX->CCR &= ~DMA_CCR_MSIZE; // DMA channel Data Size: 8 bit = 0 + //RX_DMA.dma_channelRX->CCR &= ~DMA_CCR_PSIZE; // DMA channel Peripheral data size: 8 bit = 0 + RX_DMA.dma_channelRX->CCR |= DMA_CCR_MINC; // DMA channel Memory Increment enable + //RX_DMA.dma_channelRX->CCR &= ~DMA_CCR_PINC; // DMA channel Peripheral Increment disable + RX_DMA.dma_channelRX->CCR |= DMA_CCR_CIRC; // DMA channel Circular mode enable + //RX_DMA.dma_channelRX->CCR &= ~DMA_CCR_DIR; // DMA channel Data Transfer direction: 0=Read peripheral, 1=Read memory + //RX_DMA.dma_channelRX->CCR &= ~DMA_CCR_TEIE; // DMA channel Transfer Error Interrupt + //RX_DMA.dma_channelRX->CCR &= ~DMA_CCR_HTIE; // DMA channel Half Transfer Interrupt + //RX_DMA.dma_channelRX->CCR &= ~DMA_CCR_TCIE; // DMA channel Transfer Complete Interrupt + RX_DMA.dma_channelRX->CCR |= DMA_CCR_EN; // DMA channel enable + + // Configure UART/USART + RX_DMA.uart->CR3 |= USART_CR3_DMAR; // UART DMA Receiver enabled + RX_DMA.uart->CR1 |= USART_CR1_TE; // UART Transmitter Enable + RX_DMA.uart->CR1 |= USART_CR1_RE; // UART Receiver Enable + RX_DMA.uart->CR1 |= USART_CR1_UE; // UART Enable } #endif // STM32F0xx || STM32F1xx diff --git a/Marlin/src/HAL/STM32/HardwareSerial.h b/Marlin/src/HAL/STM32/HardwareSerial.h index cc564322b4..cf97637278 100644 --- a/Marlin/src/HAL/STM32/HardwareSerial.h +++ b/Marlin/src/HAL/STM32/HardwareSerial.h @@ -38,12 +38,10 @@ typedef struct { USART_TypeDef * uart; - uint32_t dma_rcc; + uint32_t DMA_ID; // DMA1=1; DM2=2; BDMA=3 #if ANY(STM32F0xx, STM32F1xx) // F0 / F1 - DMA_TypeDef * dma_controller; DMA_Channel_TypeDef * dma_channelRX; - #else // F2 / F4 / F7 - uint32_t dma_channel; + #else // F2 / F4 / F7 / H7 DMA_Stream_TypeDef * dma_streamRX; #endif } DMA_CFG; diff --git a/Marlin/src/HAL/STM32/MarlinSerial.h b/Marlin/src/HAL/STM32/MarlinSerial.h index d9311a98da..73ab77d8d4 100644 --- a/Marlin/src/HAL/STM32/MarlinSerial.h +++ b/Marlin/src/HAL/STM32/MarlinSerial.h @@ -33,6 +33,21 @@ #include "../../core/serial_hook.h" +#ifdef USBCON + #include + typedef ForwardSerial1Class< decltype(SerialUSB) > DefaultSerial1; + extern DefaultSerial1 MSerialUSB; + #define USB_SERIAL_PORT(...) MSerialUSB +#endif + +#define SERIAL_INDEX_MIN 1 +#define SERIAL_INDEX_MAX 9 +#include "../shared/serial_ports.h" + +#if defined(LCD_SERIAL_PORT) && ANY(HAS_DGUS_LCD, EXTENSIBLE_UI) + #define LCD_SERIAL_TX_BUFFER_FREE() LCD_SERIAL.availableForWrite() +#endif + #if ENABLED(SERIAL_DMA) struct MarlinSerial : public HAL_HardwareSerial { diff --git a/Marlin/src/HAL/STM32/README.md b/Marlin/src/HAL/STM32/README.md index 7680df6654..cf8aa50d50 100644 --- a/Marlin/src/HAL/STM32/README.md +++ b/Marlin/src/HAL/STM32/README.md @@ -3,9 +3,10 @@ This HAL is intended to act as the generic STM32 HAL for all STM32 chips (The whole F, H and L family). Currently it supports: - * STM32F0xx - * STM32F1xx - * STM32F4xx - * STM32F7xx + +- STM32F0xx +- STM32F1xx +- STM32F4xx +- STM32F7xx Targeting the official [Arduino STM32 Core](https://github.com/stm32duino/Arduino_Core_STM32). diff --git a/Marlin/src/HAL/STM32/Servo.cpp b/Marlin/src/HAL/STM32/Servo.cpp index 4f026ffc6d..eb535b1eb1 100644 --- a/Marlin/src/HAL/STM32/Servo.cpp +++ b/Marlin/src/HAL/STM32/Servo.cpp @@ -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); diff --git a/Marlin/src/HAL/STM32/eeprom_bl24cxx.cpp b/Marlin/src/HAL/STM32/eeprom/eeprom_bl24cxx.cpp similarity index 94% rename from Marlin/src/HAL/STM32/eeprom_bl24cxx.cpp rename to Marlin/src/HAL/STM32/eeprom/eeprom_bl24cxx.cpp index 3e0bb58dad..8240f15d3a 100644 --- a/Marlin/src/HAL/STM32/eeprom_bl24cxx.cpp +++ b/Marlin/src/HAL/STM32/eeprom/eeprom_bl24cxx.cpp @@ -20,7 +20,7 @@ * */ -#include "../platforms.h" +#include "../../platforms.h" #ifdef HAL_STM32 @@ -29,12 +29,12 @@ * with simple implementations supplied by Marlin. */ -#include "../../inc/MarlinConfig.h" +#include "../../../inc/MarlinConfig.h" #if ENABLED(IIC_BL24CXX_EEPROM) -#include "../shared/eeprom_if.h" -#include "../shared/eeprom_api.h" +#include "../../shared/eeprom_if.h" +#include "../../shared/eeprom_api.h" // // PersistentStore diff --git a/Marlin/src/HAL/STM32/eeprom_flash.cpp b/Marlin/src/HAL/STM32/eeprom/eeprom_flash.cpp similarity index 79% rename from Marlin/src/HAL/STM32/eeprom_flash.cpp rename to Marlin/src/HAL/STM32/eeprom/eeprom_flash.cpp index 37963ad501..5a9062e956 100644 --- a/Marlin/src/HAL/STM32/eeprom_flash.cpp +++ b/Marlin/src/HAL/STM32/eeprom/eeprom_flash.cpp @@ -19,15 +19,15 @@ * along with this program. If not, see . * */ -#include "../platforms.h" +#include "../../platforms.h" #ifdef HAL_STM32 -#include "../../inc/MarlinConfig.h" +#include "../../../inc/MarlinConfig.h" #if ENABLED(FLASH_EEPROM_EMULATION) -#include "../shared/eeprom_api.h" +#include "../../shared/eeprom_api.h" // Better: "utility/stm32_eeprom.h", but only after updating stm32duino to 2.0.0 // Use EEPROM.h for compatibility, for now. @@ -50,10 +50,10 @@ #if ENABLED(FLASH_EEPROM_LEVELING) - #include "stm32_def.h" + #include #define DEBUG_OUT ENABLED(EEPROM_CHITCHAT) - #include "../../core/debug_out.h" + #include "../../../core/debug_out.h" #ifndef MARLIN_EEPROM_SIZE #define MARLIN_EEPROM_SIZE 0x1000 // 4KB @@ -63,7 +63,7 @@ #define FLASH_SECTOR (FLASH_SECTOR_TOTAL - 1) #endif #ifndef FLASH_UNIT_SIZE - #define FLASH_UNIT_SIZE 0x20000 // 128kB + #define FLASH_UNIT_SIZE 0x20000 // 128K #endif #ifndef FLASH_ADDRESS_START @@ -74,13 +74,13 @@ #define EEPROM_SLOTS ((FLASH_UNIT_SIZE) / (MARLIN_EEPROM_SIZE)) #define SLOT_ADDRESS(slot) (FLASH_ADDRESS_START + (slot * (MARLIN_EEPROM_SIZE))) - #define UNLOCK_FLASH() if (!flash_unlocked) { \ - HAL_FLASH_Unlock(); \ - __HAL_FLASH_CLEAR_FLAG(FLASH_FLAG_EOP | FLASH_FLAG_OPERR | FLASH_FLAG_WRPERR | \ - FLASH_FLAG_PGAERR | FLASH_FLAG_PGPERR | FLASH_FLAG_PGSERR); \ - flash_unlocked = true; \ - } - #define LOCK_FLASH() if (flash_unlocked) { HAL_FLASH_Lock(); flash_unlocked = false; } + #ifdef STM32H7xx + #define FLASHWORD_SIZE 32U // STM32H7xx a FLASHWORD is 32 bytes (256 bits) + #define FLASH_FLAGS_TO_CLEAR (FLASH_FLAG_EOP | FLASH_FLAG_OPERR | FLASH_FLAG_WRPERR | FLASH_FLAG_PGSERR) + #else + #define FLASHWORD_SIZE 4U // STM32F4xx a FLASHWORD is 4 bytes sizeof(uint32_t) + #define FLASH_FLAGS_TO_CLEAR (FLASH_FLAG_EOP | FLASH_FLAG_OPERR | FLASH_FLAG_WRPERR | FLASH_FLAG_PGAERR | FLASH_FLAG_PGPERR | FLASH_FLAG_PGSERR) + #endif #define EMPTY_UINT32 ((uint32_t)-1) #define EMPTY_UINT8 ((uint8_t)-1) @@ -88,7 +88,7 @@ static uint8_t ram_eeprom[MARLIN_EEPROM_SIZE] __attribute__((aligned(4))) = {0}; static int current_slot = -1; - static_assert(0 == MARLIN_EEPROM_SIZE % 4, "MARLIN_EEPROM_SIZE must be a multiple of 4"); // Ensure copying as uint32_t is safe + static_assert(0 == MARLIN_EEPROM_SIZE % FLASHWORD_SIZE, "MARLIN_EEPROM_SIZE must be a multiple of the FLASHWORD size"); // Ensure copying as uint32_t is safe static_assert(0 == FLASH_UNIT_SIZE % MARLIN_EEPROM_SIZE, "MARLIN_EEPROM_SIZE must divide evenly into your FLASH_UNIT_SIZE"); static_assert(FLASH_UNIT_SIZE >= MARLIN_EEPROM_SIZE, "FLASH_UNIT_SIZE must be greater than or equal to your MARLIN_EEPROM_SIZE"); static_assert(IS_FLASH_SECTOR(FLASH_SECTOR), "FLASH_SECTOR is invalid"); @@ -125,13 +125,13 @@ bool PersistentStore::access_start() { } if (current_slot == -1) { // We didn't find anything, so we'll just initialize to empty - for (int i = 0; i < MARLIN_EEPROM_SIZE; i++) ram_eeprom[i] = EMPTY_UINT8; + for (int i = 0; i < long(MARLIN_EEPROM_SIZE); i++) ram_eeprom[i] = EMPTY_UINT8; current_slot = EEPROM_SLOTS; } else { // load current settings uint8_t *eeprom_data = (uint8_t *)SLOT_ADDRESS(current_slot); - for (int i = 0; i < MARLIN_EEPROM_SIZE; i++) ram_eeprom[i] = eeprom_data[i]; + for (int i = 0; i < long(MARLIN_EEPROM_SIZE); i++) ram_eeprom[i] = eeprom_data[i]; DEBUG_ECHOLNPGM("EEPROM loaded from slot ", current_slot, "."); } eeprom_data_written = false; @@ -147,11 +147,15 @@ bool PersistentStore::access_start() { bool PersistentStore::access_finish() { if (eeprom_data_written) { + #ifdef STM32F4xx // MCU may come up with flash error bits which prevent some flash operations. // Clear flags prior to flash operations to prevent errors. __HAL_FLASH_CLEAR_FLAG(FLASH_FLAG_OPERR | FLASH_FLAG_WRPERR | FLASH_FLAG_PGAERR | FLASH_FLAG_PGPERR | FLASH_FLAG_PGSERR); #endif + #ifdef STM32H7xx + __HAL_FLASH_CLEAR_FLAG(FLASH_FLAG_OPERR | FLASH_FLAG_WRPERR | FLASH_FLAG_PGSERR); + #endif #if ENABLED(FLASH_EEPROM_LEVELING) @@ -170,7 +174,12 @@ bool PersistentStore::access_finish() { EraseInitStruct.NbSectors = 1; current_slot = EEPROM_SLOTS - 1; - UNLOCK_FLASH(); + + if (!flash_unlocked) { + HAL_FLASH_Unlock(); + __HAL_FLASH_CLEAR_FLAG(FLASH_FLAGS_TO_CLEAR); + flash_unlocked = true; + } TERN_(HAS_PAUSE_SERVO_OUTPUT, PAUSE_SERVO_OUTPUT()); hal.isr_off(); @@ -181,26 +190,37 @@ bool PersistentStore::access_finish() { DEBUG_ECHOLNPGM("HAL_FLASHEx_Erase=", status); DEBUG_ECHOLNPGM("GetError=", HAL_FLASH_GetError()); DEBUG_ECHOLNPGM("SectorError=", SectorError); - LOCK_FLASH(); + if (flash_unlocked) { + HAL_FLASH_Lock(); + flash_unlocked = false; + } return false; } } - UNLOCK_FLASH(); + if (!flash_unlocked) { + HAL_FLASH_Unlock(); + __HAL_FLASH_CLEAR_FLAG(FLASH_FLAGS_TO_CLEAR); + flash_unlocked = true; + } uint32_t offset = 0, address = SLOT_ADDRESS(current_slot), - address_end = address + MARLIN_EEPROM_SIZE, - data = 0; + address_end = address + MARLIN_EEPROM_SIZE; bool success = true; while (address < address_end) { - memcpy(&data, ram_eeprom + offset, sizeof(data)); - status = HAL_FLASH_Program(FLASH_TYPEPROGRAM_WORD, address, data); + #ifdef STM32H7xx + status = HAL_FLASH_Program(FLASH_TYPEPROGRAM_FLASHWORD, address, uint32_t(ram_eeprom + offset)); + #else + //memcpy(&data, ram_eeprom + offset, sizeof(data)); // IRON, IMPROVED + //status = HAL_FLASH_Program(FLASH_TYPEPROGRAM_WORD, address, data); + status = HAL_FLASH_Program(FLASH_TYPEPROGRAM_WORD, address, *(uint32_t*)(ram_eeprom + offset)); // IRON, OPTIMIZED + #endif if (status == HAL_OK) { - address += sizeof(uint32_t); - offset += sizeof(uint32_t); + address += FLASHWORD_SIZE; + offset += FLASHWORD_SIZE; } else { DEBUG_ECHOLNPGM("HAL_FLASH_Program=", status); @@ -211,7 +231,10 @@ bool PersistentStore::access_finish() { } } - LOCK_FLASH(); + if (flash_unlocked) { + HAL_FLASH_Lock(); + flash_unlocked = false; + } if (success) { eeprom_data_written = false; diff --git a/Marlin/src/HAL/STM32/eeprom_if_iic.cpp b/Marlin/src/HAL/STM32/eeprom/eeprom_if_iic.cpp similarity index 88% rename from Marlin/src/HAL/STM32/eeprom_if_iic.cpp rename to Marlin/src/HAL/STM32/eeprom/eeprom_if_iic.cpp index ad8712c0c0..2733c8f283 100644 --- a/Marlin/src/HAL/STM32/eeprom_if_iic.cpp +++ b/Marlin/src/HAL/STM32/eeprom/eeprom_if_iic.cpp @@ -20,7 +20,7 @@ * */ -#include "../platforms.h" +#include "../../platforms.h" #ifdef HAL_STM32 @@ -29,12 +29,12 @@ * Enable USE_SHARED_EEPROM if not supplied by the framework. */ -#include "../../inc/MarlinConfig.h" +#include "../../../inc/MarlinConfig.h" #if ENABLED(IIC_BL24CXX_EEPROM) -#include "../../libs/BL24CXX.h" -#include "../shared/eeprom_if.h" +#include "../../../libs/BL24CXX.h" +#include "../../shared/eeprom_if.h" void eeprom_init() { BL24CXX::init(); } @@ -44,7 +44,7 @@ void eeprom_init() { BL24CXX::init(); } void eeprom_write_byte(uint8_t *pos, uint8_t value) { const unsigned eeprom_address = (unsigned)pos; - return BL24CXX::writeOneByte(eeprom_address, value); + BL24CXX::writeOneByte(eeprom_address, value); } uint8_t eeprom_read_byte(uint8_t *pos) { diff --git a/Marlin/src/HAL/STM32/eeprom_sdcard.cpp b/Marlin/src/HAL/STM32/eeprom/eeprom_sdcard.cpp similarity index 92% rename from Marlin/src/HAL/STM32/eeprom_sdcard.cpp rename to Marlin/src/HAL/STM32/eeprom/eeprom_sdcard.cpp index 071d0bac00..64da3745d1 100644 --- a/Marlin/src/HAL/STM32/eeprom_sdcard.cpp +++ b/Marlin/src/HAL/STM32/eeprom/eeprom_sdcard.cpp @@ -20,7 +20,7 @@ * */ -#include "../platforms.h" +#include "../../platforms.h" #ifdef HAL_STM32 @@ -28,12 +28,12 @@ * Implementation of EEPROM settings in SD Card */ -#include "../../inc/MarlinConfig.h" +#include "../../../inc/MarlinConfig.h" #if ENABLED(SDCARD_EEPROM_EMULATION) -#include "../shared/eeprom_api.h" -#include "../../sd/cardreader.h" +#include "../../shared/eeprom_api.h" +#include "../../../sd/cardreader.h" #define EEPROM_FILENAME "eeprom.dat" @@ -54,7 +54,7 @@ bool PersistentStore::access_start() { int bytes_read = file.read(HAL_eeprom_data, MARLIN_EEPROM_SIZE); if (bytes_read < 0) return false; - for (; bytes_read < MARLIN_EEPROM_SIZE; bytes_read++) + for (; bytes_read < long(MARLIN_EEPROM_SIZE); bytes_read++) HAL_eeprom_data[bytes_read] = 0xFF; file.close(); return true; diff --git a/Marlin/src/HAL/STM32/eeprom_sram.cpp b/Marlin/src/HAL/STM32/eeprom/eeprom_sram.cpp similarity index 93% rename from Marlin/src/HAL/STM32/eeprom_sram.cpp rename to Marlin/src/HAL/STM32/eeprom/eeprom_sram.cpp index 58a67f1759..a9d62ec29c 100644 --- a/Marlin/src/HAL/STM32/eeprom_sram.cpp +++ b/Marlin/src/HAL/STM32/eeprom/eeprom_sram.cpp @@ -19,16 +19,16 @@ * along with this program. If not, see . * */ -#include "../platforms.h" +#include "../../platforms.h" #ifdef HAL_STM32 -#include "../../inc/MarlinConfig.h" +#include "../../../inc/MarlinConfig.h" #if ENABLED(SRAM_EEPROM_EMULATION) -#include "../shared/eeprom_if.h" -#include "../shared/eeprom_api.h" +#include "../../shared/eeprom_if.h" +#include "../../shared/eeprom_api.h" #ifndef MARLIN_EEPROM_SIZE #define MARLIN_EEPROM_SIZE 0x1000 // 4KB diff --git a/Marlin/src/HAL/STM32/eeprom_wired.cpp b/Marlin/src/HAL/STM32/eeprom/eeprom_wired.cpp similarity index 94% rename from Marlin/src/HAL/STM32/eeprom_wired.cpp rename to Marlin/src/HAL/STM32/eeprom/eeprom_wired.cpp index 5440030bd4..fa45e6c40d 100644 --- a/Marlin/src/HAL/STM32/eeprom_wired.cpp +++ b/Marlin/src/HAL/STM32/eeprom/eeprom_wired.cpp @@ -19,11 +19,11 @@ * along with this program. If not, see . * */ -#include "../platforms.h" +#include "../../platforms.h" #ifdef HAL_STM32 -#include "../../inc/MarlinConfig.h" +#include "../../../inc/MarlinConfig.h" #if USE_WIRED_EEPROM @@ -32,8 +32,8 @@ * with simple implementations supplied by Marlin. */ -#include "../shared/eeprom_if.h" -#include "../shared/eeprom_api.h" +#include "../../shared/eeprom_if.h" +#include "../../shared/eeprom_api.h" #ifndef MARLIN_EEPROM_SIZE #define MARLIN_EEPROM_SIZE size_t(E2END + 1) diff --git a/Marlin/src/HAL/STM32/fastio.h b/Marlin/src/HAL/STM32/fastio.h index af2941c49c..a92bbc492e 100644 --- a/Marlin/src/HAL/STM32/fastio.h +++ b/Marlin/src/HAL/STM32/fastio.h @@ -77,6 +77,7 @@ void FastIO_init(); // Must be called before using fast io macros #define SET_INPUT_PULLUP(IO) _SET_MODE(IO, INPUT_PULLUP) //!< Input with Pull-up activation #define SET_INPUT_PULLDOWN(IO) _SET_MODE(IO, INPUT_PULLDOWN) //!< Input with Pull-down activation #define SET_OUTPUT(IO) OUT_WRITE(IO, LOW) +#define SET_OUTPUT_OD(IO) OUT_WRITE_OD(IO, LOW) #define SET_PWM(IO) _SET_MODE(IO, PWM) #define IS_INPUT(IO) diff --git a/Marlin/src/HAL/STM32/inc/Conditionals_post.h b/Marlin/src/HAL/STM32/inc/Conditionals_post.h index 6c97a635b3..8d72e720c1 100644 --- a/Marlin/src/HAL/STM32/inc/Conditionals_post.h +++ b/Marlin/src/HAL/STM32/inc/Conditionals_post.h @@ -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 diff --git a/Marlin/src/HAL/STM32/inc/SanityCheck.h b/Marlin/src/HAL/STM32/inc/SanityCheck.h index e35b4e59cf..616f96eba0 100644 --- a/Marlin/src/HAL/STM32/inc/SanityCheck.h +++ b/Marlin/src/HAL/STM32/inc/SanityCheck.h @@ -36,8 +36,8 @@ #error "SDCARD_EEPROM_EMULATION requires SDSUPPORT. Enable SDSUPPORT or choose another EEPROM emulation." #endif -#if !defined(STM32F4xx) && ENABLED(FLASH_EEPROM_LEVELING) - #error "FLASH_EEPROM_LEVELING is currently only supported on STM32F4 hardware." +#if NONE(STM32F4xx, STM32H7xx) && ENABLED(FLASH_EEPROM_LEVELING) + #error "FLASH_EEPROM_LEVELING is currently only supported on STM32F4/H7 hardware." // IRON #endif #if ENABLED(SERIAL_STATS_MAX_RX_QUEUED) @@ -58,7 +58,7 @@ * Check for common serial pin conflicts */ #define _CHECK_SERIAL_PIN(N) (( \ - BTN_EN1 == N || BTN_EN2 == N ||DOGLCD_CS == N || HEATER_BED_PIN == N || FAN0_PIN == N || \ + BTN_EN1 == N || BTN_EN2 == N || DOGLCD_CS == N || HEATER_BED_PIN == N || FAN0_PIN == N || \ SDIO_D2_PIN == N || SDIO_D3_PIN == N || SDIO_CK_PIN == N || SDIO_CMD_PIN == N || \ Y_STEP_PIN == N || Y_ENABLE_PIN == N || E0_ENABLE_PIN == N || POWER_LOSS_PIN == N \ )) diff --git a/Marlin/src/HAL/STM32/pinsDebug.h b/Marlin/src/HAL/STM32/pinsDebug.h index 21cd2de39f..89e2514af0 100644 --- a/Marlin/src/HAL/STM32/pinsDebug.h +++ b/Marlin/src/HAL/STM32/pinsDebug.h @@ -136,10 +136,8 @@ const XrefInfo pin_xref[] PROGMEM = { #define printPinNumber(Q) #define printPinAnalog(P) do{ sprintf_P(buffer, PSTR(" (A%2d) "), digitalPinToAnalogIndex(P)); SERIAL_ECHO(buffer); }while(0) #define digitalPinToAnalogIndex(P) -1 // will report analog pin number in the print port routine - -// x is a variable used to search pin_array -#define getPinIsDigitalByIndex(x) ((bool) pin_array[x].is_digital) -#define getPinByIndex(x) ((pin_t) pin_array[x].pin) +#define getPinIsDigitalByIndex(x) bool(pin_array[x].is_digital) +#define getPinByIndex(x) pin_t(pin_array[x].pin) #define printPinNameByIndex(x) do{ sprintf_P(buffer, PSTR("%-" STRINGIFY(MAX_NAME_LENGTH) "s"), pin_array[x].name); SERIAL_ECHO(buffer); }while(0) #define MULTI_NAME_PAD 33 // space needed to be pretty if not first name assigned to a pin @@ -150,7 +148,7 @@ const XrefInfo pin_xref[] PROGMEM = { #ifndef M43_NEVER_TOUCH #define _M43_NEVER_TOUCH(x) WITHIN(x, 9, 12) // SERIAL/USB pins: PA9(TX) PA10(RX) PA11(USB_DM) PA12(USB_DP) - #ifdef KILL_PIN + #if PIN_EXISTS(KILL) #define M43_NEVER_TOUCH(x) m43_never_touch(x) bool m43_never_touch(const pin_t index) { @@ -229,8 +227,7 @@ void printPinPort(const pin_t pin) { calc_p -= NUM_ANALOG_FIRST; if (calc_p > 7) calc_p += 8; } - SERIAL_ECHOPGM(" M42 P", calc_p); - SERIAL_CHAR(' '); + SERIAL_ECHO(F(" M42 P"), calc_p, C(' ')); if (calc_p < 100) { SERIAL_CHAR(' '); if (calc_p < 10) diff --git a/Marlin/src/HAL/STM32/msc_sd.cpp b/Marlin/src/HAL/STM32/sd/msc_sd.cpp similarity index 95% rename from Marlin/src/HAL/STM32/msc_sd.cpp rename to Marlin/src/HAL/STM32/sd/msc_sd.cpp index 5c8bee9c62..9bb65aab4a 100644 --- a/Marlin/src/HAL/STM32/msc_sd.cpp +++ b/Marlin/src/HAL/STM32/sd/msc_sd.cpp @@ -20,20 +20,19 @@ * along with this program. If not, see . * */ -#include "../platforms.h" +#include "../../platforms.h" #ifdef HAL_STM32 -#include "../../inc/MarlinConfigPre.h" +#include "../../../inc/MarlinConfigPre.h" #if HAS_SD_HOST_DRIVE -#include "../shared/Marduino.h" +#include "../../../sd/cardreader.h" + #include "msc_sd.h" -#include "usbd_core.h" - -#include "../../sd/cardreader.h" +#include #include #include @@ -49,7 +48,8 @@ class Sd2CardUSBMscHandler : public USBMscHandler { public: DiskIODriver* diskIODriver() { - #if ENABLED(MULTI_VOLUME) + // TODO: Explore a variable shared volume, or auto share the un-mounted volume(s) + #if HAS_MULTI_VOLUME #if SHARED_VOLUME_IS(SD_ONBOARD) return &card.media_driver_sdcard; #elif SHARED_VOLUME_IS(USB_FLASH_DRIVE) diff --git a/Marlin/src/HAL/STM32/msc_sd.h b/Marlin/src/HAL/STM32/sd/msc_sd.h similarity index 100% rename from Marlin/src/HAL/STM32/msc_sd.h rename to Marlin/src/HAL/STM32/sd/msc_sd.h diff --git a/Marlin/src/HAL/STM32/usb_host.cpp b/Marlin/src/HAL/STM32/sd/usb_host.cpp similarity index 96% rename from Marlin/src/HAL/STM32/usb_host.cpp rename to Marlin/src/HAL/STM32/sd/usb_host.cpp index afafe1d4f3..f411771c8a 100644 --- a/Marlin/src/HAL/STM32/usb_host.cpp +++ b/Marlin/src/HAL/STM32/sd/usb_host.cpp @@ -20,18 +20,17 @@ * */ -#include "../platforms.h" +#include "../../platforms.h" #ifdef HAL_STM32 -#include "../../inc/MarlinConfig.h" +#include "../../../inc/MarlinConfig.h" #if ALL(USE_OTG_USB_HOST, USBHOST) #include "usb_host.h" -#include "../shared/Marduino.h" -#include "usbh_core.h" -#include "usbh_msc.h" +#include +#include USBH_HandleTypeDef hUsbHost; USBHost usb; diff --git a/Marlin/src/HAL/STM32/usb_host.h b/Marlin/src/HAL/STM32/sd/usb_host.h similarity index 100% rename from Marlin/src/HAL/STM32/usb_host.h rename to Marlin/src/HAL/STM32/sd/usb_host.h diff --git a/Marlin/src/HAL/STM32/spi_pins.h b/Marlin/src/HAL/STM32/spi_pins.h index 7f341a8c25..da6fa0d160 100644 --- a/Marlin/src/HAL/STM32/spi_pins.h +++ b/Marlin/src/HAL/STM32/spi_pins.h @@ -33,6 +33,3 @@ #ifndef SD_MOSI_PIN #define SD_MOSI_PIN PIN_SPI_MOSI #endif -#ifndef SD_SS_PIN - #define SD_SS_PIN PIN_SPI_SS -#endif diff --git a/Marlin/src/HAL/STM32/temp_soc.h b/Marlin/src/HAL/STM32/temp_soc.h index 05fad695c3..cc165dd5e4 100644 --- a/Marlin/src/HAL/STM32/temp_soc.h +++ b/Marlin/src/HAL/STM32/temp_soc.h @@ -341,6 +341,6 @@ #elif defined(TS_TYPICAL_V) && defined(TS_TYPICAL_SLOPE) && defined(TS_TYPICAL_TEMP) - #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) + TS_TYPICAL_TEMP) + #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) #endif diff --git a/Marlin/src/HAL/STM32/tft/tft_fsmc.cpp b/Marlin/src/HAL/STM32/tft/tft_fsmc.cpp index bb011ec6f4..70caef6778 100644 --- a/Marlin/src/HAL/STM32/tft/tft_fsmc.cpp +++ b/Marlin/src/HAL/STM32/tft/tft_fsmc.cpp @@ -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); diff --git a/Marlin/src/HAL/STM32/tft/xpt2046.h b/Marlin/src/HAL/STM32/tft/xpt2046.h index 685c9441ae..f3d3e53291 100644 --- a/Marlin/src/HAL/STM32/tft/xpt2046.h +++ b/Marlin/src/HAL/STM32/tft/xpt2046.h @@ -49,7 +49,11 @@ #define TOUCH_INT_PIN -1 #endif -#define XPT2046_DFR_MODE 0x00 +#if PIN_EXISTS(TOUCH_INT) + #define XPT2046_DFR_MODE 0x00 +#else + #define XPT2046_DFR_MODE 0x01 +#endif #define XPT2046_SER_MODE 0x04 #define XPT2046_CONTROL 0x80 diff --git a/Marlin/src/HAL/STM32/timers.cpp b/Marlin/src/HAL/STM32/timers.cpp index 10e0dc43a4..5b58a915f0 100644 --- a/Marlin/src/HAL/STM32/timers.cpp +++ b/Marlin/src/HAL/STM32/timers.cpp @@ -81,10 +81,6 @@ #define MCU_TEMP_TIMER 14 // TIM7 is consumed by Software Serial if used. #endif -#ifndef HAL_TIMER_RATE - #define HAL_TIMER_RATE GetStepperTimerClkFreq() -#endif - #ifndef STEP_TIMER #define STEP_TIMER MCU_STEP_TIMER #endif @@ -141,7 +137,7 @@ void HAL_timer_start(const uint8_t timer_num, const uint32_t frequency) { */ timer_instance[timer_num]->setPrescaleFactor(STEPPER_TIMER_PRESCALE); //the -1 is done internally - timer_instance[timer_num]->setOverflow(_MIN(hal_timer_t(HAL_TIMER_TYPE_MAX), (HAL_TIMER_RATE) / (STEPPER_TIMER_PRESCALE) /* /frequency */), TICK_FORMAT); + timer_instance[timer_num]->setOverflow(_MIN(HAL_TIMER_TYPE_MAX, hal_timer_t((HAL_TIMER_RATE) / (STEPPER_TIMER_PRESCALE) /* / frequency */)), TICK_FORMAT); break; case MF_TIMER_TEMP: // TEMP TIMER - any available 16bit timer timer_instance[timer_num] = new HardwareTimer(TEMP_TIMER_DEV); diff --git a/Marlin/src/HAL/STM32/timers.h b/Marlin/src/HAL/STM32/timers.h index 180e240314..a6c9204a77 100644 --- a/Marlin/src/HAL/STM32/timers.h +++ b/Marlin/src/HAL/STM32/timers.h @@ -38,7 +38,7 @@ // of adding a run-time check and HAL_TIMER_TYPE_MAX is refactored to allow unique // values for each timer. #define hal_timer_t uint32_t -#define HAL_TIMER_TYPE_MAX UINT16_MAX +#define HAL_TIMER_TYPE_MAX hal_timer_t(UINT16_MAX) // Marlin timer_instance[] content (unrelated to timer selection) #define MF_TIMER_STEP 0 // Timer Index for Stepper @@ -48,23 +48,28 @@ #define TIMER_INDEX_(T) TIMER##T##_INDEX // TIMER#_INDEX enums (timer_index_t) depend on TIM#_BASE defines. #define TIMER_INDEX(T) TIMER_INDEX_(T) // Convert Timer ID to HardwareTimer_Handle index. -#define TEMP_TIMER_FREQUENCY 1000 // Temperature::isr() is expected to be called at around 1kHz +#ifndef HAL_TIMER_RATE + extern uint32_t GetStepperTimerClkFreq(); + #define HAL_TIMER_RATE GetStepperTimerClkFreq() +#endif -// TODO: get rid of manual rate/prescale/ticks/cycles taken for procedures in stepper.cpp -#define STEPPER_TIMER_RATE 2000000 // 2 Mhz -extern uint32_t GetStepperTimerClkFreq(); -#define STEPPER_TIMER_PRESCALE (GetStepperTimerClkFreq() / (STEPPER_TIMER_RATE)) -#define STEPPER_TIMER_TICKS_PER_US ((STEPPER_TIMER_RATE) / 1000000) // stepper timer ticks per µs +// Timer configuration constants +#define STEPPER_TIMER_RATE 2000000 +#define TEMP_TIMER_FREQUENCY 1000 // Temperature::isr() should run at ~1kHz -#define PULSE_TIMER_RATE STEPPER_TIMER_RATE -#define PULSE_TIMER_PRESCALE STEPPER_TIMER_PRESCALE -#define PULSE_TIMER_TICKS_PER_US STEPPER_TIMER_TICKS_PER_US +// Timer prescaler calculations +#define STEPPER_TIMER_PRESCALE ((HAL_TIMER_RATE) / (STEPPER_TIMER_RATE)) +#define STEPPER_TIMER_TICKS_PER_US ((STEPPER_TIMER_RATE) / 1000000UL) // (ticks/μs) Stepper Timer ticks per µs -#define ENABLE_STEPPER_DRIVER_INTERRUPT() HAL_timer_enable_interrupt(MF_TIMER_STEP) -#define DISABLE_STEPPER_DRIVER_INTERRUPT() HAL_timer_disable_interrupt(MF_TIMER_STEP) -#define STEPPER_ISR_ENABLED() HAL_timer_interrupt_enabled(MF_TIMER_STEP) +// Pulse Timer (counter) calculations +#define PULSE_TIMER_RATE STEPPER_TIMER_RATE // (Hz) Frequency of Pulse Timer +#define PULSE_TIMER_PRESCALE STEPPER_TIMER_PRESCALE -#define ENABLE_TEMPERATURE_INTERRUPT() HAL_timer_enable_interrupt(MF_TIMER_TEMP) +#define ENABLE_STEPPER_DRIVER_INTERRUPT() HAL_timer_enable_interrupt(MF_TIMER_STEP) +#define DISABLE_STEPPER_DRIVER_INTERRUPT() HAL_timer_disable_interrupt(MF_TIMER_STEP) +#define STEPPER_ISR_ENABLED() HAL_timer_interrupt_enabled(MF_TIMER_STEP) + +#define ENABLE_TEMPERATURE_INTERRUPT() HAL_timer_enable_interrupt(MF_TIMER_TEMP) #define DISABLE_TEMPERATURE_INTERRUPT() HAL_timer_disable_interrupt(MF_TIMER_TEMP) extern void Step_Handler(); @@ -116,5 +121,5 @@ FORCE_INLINE static void HAL_timer_set_compare(const uint8_t timer_num, const ha } } -#define HAL_timer_isr_prologue(T) NOOP -#define HAL_timer_isr_epilogue(T) NOOP +inline void HAL_timer_isr_prologue(const uint8_t) {} +inline void HAL_timer_isr_epilogue(const uint8_t) {} diff --git a/Marlin/src/HAL/STM32/u8g/LCD_defines.h b/Marlin/src/HAL/STM32/u8g/LCD_defines.h index 59b2b8839a..96f73002a5 100644 --- a/Marlin/src/HAL/STM32/u8g/LCD_defines.h +++ b/Marlin/src/HAL/STM32/u8g/LCD_defines.h @@ -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 diff --git a/Marlin/src/HAL/STM32/u8g/u8g_com_stm32duino_ssd_i2c.cpp b/Marlin/src/HAL/STM32/u8g/u8g_com_stm32duino_ssd_i2c.cpp new file mode 100644 index 0000000000..72abe1a656 --- /dev/null +++ b/Marlin/src/HAL/STM32/u8g/u8g_com_stm32duino_ssd_i2c.cpp @@ -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 . + * + */ + +/** + * 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 + +#if ENABLED(U8G_USES_HW_I2C) + #include + #ifndef MASTER_ADDRESS + #define MASTER_ADDRESS 0x01 + #endif +#endif + +#if ENABLED(U8G_USES_SW_I2C) + #include + #include +#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 diff --git a/Marlin/src/HAL/STM32/usb_serial.cpp b/Marlin/src/HAL/STM32/usb_serial.cpp index 0b2372f3a7..1ca8b19976 100644 --- a/Marlin/src/HAL/STM32/usb_serial.cpp +++ b/Marlin/src/HAL/STM32/usb_serial.cpp @@ -26,7 +26,7 @@ #include "../../inc/MarlinConfigPre.h" -#if ENABLED(EMERGENCY_PARSER) && (USBD_USE_CDC || USBD_USE_CDC_MSC) +#if ENABLED(EMERGENCY_PARSER) && ANY(USBD_USE_CDC, USBD_USE_CDC_MSC) #include "usb_serial.h" #include "../../feature/e_parser.h" @@ -56,5 +56,5 @@ void USB_Hook_init() { USBD_CDC_fops.Receive = USBD_CDC_Receive_hook; } -#endif // EMERGENCY_PARSER && USBD_USE_CDC +#endif // EMERGENCY_PARSER && (USBD_USE_CDC || USBD_USE_CDC_MSC) #endif // HAL_STM32 diff --git a/Marlin/src/HAL/STM32F1/HAL.cpp b/Marlin/src/HAL/STM32F1/HAL.cpp index e6cbb9fc06..fc1680cbf4 100644 --- a/Marlin/src/HAL/STM32F1/HAL.cpp +++ b/Marlin/src/HAL/STM32F1/HAL.cpp @@ -65,7 +65,8 @@ uint16_t adc_results[ADC_COUNT]; emergency_parser.update(MSerial0.emergency_state, buf[i + total - len]); } #endif -#endif + +#endif // SERIAL_USB && !HAS_SD_HOST_DRIVE // ------------------------ // Watchdog Timer @@ -130,30 +131,31 @@ uint16_t MarlinHAL::adc_result; #include -// Init the AD in continuous capture mode +// Init the ADC in continuous capture mode void MarlinHAL::adc_init() { static const uint8_t adc_pins[] = { - OPTITEM(HAS_TEMP_ADC_0, TEMP_0_PIN) - OPTITEM(HAS_TEMP_ADC_1, TEMP_1_PIN) - OPTITEM(HAS_TEMP_ADC_2, TEMP_2_PIN) - OPTITEM(HAS_TEMP_ADC_3, TEMP_3_PIN) - OPTITEM(HAS_TEMP_ADC_4, TEMP_4_PIN) - OPTITEM(HAS_TEMP_ADC_5, TEMP_5_PIN) - OPTITEM(HAS_TEMP_ADC_6, TEMP_6_PIN) - OPTITEM(HAS_TEMP_ADC_7, TEMP_7_PIN) - OPTITEM(HAS_HEATED_BED, TEMP_BED_PIN) - OPTITEM(HAS_TEMP_CHAMBER, TEMP_CHAMBER_PIN) - OPTITEM(HAS_TEMP_ADC_PROBE, TEMP_PROBE_PIN) - OPTITEM(HAS_TEMP_COOLER, TEMP_COOLER_PIN) - OPTITEM(HAS_TEMP_BOARD, TEMP_BOARD_PIN) - OPTITEM(HAS_TEMP_SOC, TEMP_SOC_PIN) - OPTITEM(FILAMENT_WIDTH_SENSOR, FILWIDTH_PIN) - OPTITEM(HAS_ADC_BUTTONS, ADC_KEYPAD_PIN) - OPTITEM(HAS_JOY_ADC_X, JOY_X_PIN) - OPTITEM(HAS_JOY_ADC_Y, JOY_Y_PIN) - OPTITEM(HAS_JOY_ADC_Z, JOY_Z_PIN) - OPTITEM(POWER_MONITOR_CURRENT, POWER_MONITOR_CURRENT_PIN) - OPTITEM(POWER_MONITOR_VOLTAGE, POWER_MONITOR_VOLTAGE_PIN) + OPTITEM(HAS_TEMP_ADC_0, TEMP_0_PIN ) + OPTITEM(HAS_TEMP_ADC_1, TEMP_1_PIN ) + OPTITEM(HAS_TEMP_ADC_2, TEMP_2_PIN ) + OPTITEM(HAS_TEMP_ADC_3, TEMP_3_PIN ) + OPTITEM(HAS_TEMP_ADC_4, TEMP_4_PIN ) + OPTITEM(HAS_TEMP_ADC_5, TEMP_5_PIN ) + OPTITEM(HAS_TEMP_ADC_6, TEMP_6_PIN ) + OPTITEM(HAS_TEMP_ADC_7, TEMP_7_PIN ) + OPTITEM(HAS_TEMP_ADC_BED, TEMP_BED_PIN ) + OPTITEM(HAS_TEMP_ADC_CHAMBER, TEMP_CHAMBER_PIN ) + OPTITEM(HAS_TEMP_ADC_PROBE, TEMP_PROBE_PIN ) + OPTITEM(HAS_TEMP_ADC_COOLER, TEMP_COOLER_PIN ) + OPTITEM(HAS_TEMP_ADC_BOARD, TEMP_BOARD_PIN ) + OPTITEM(HAS_TEMP_ADC_SOC, TEMP_SOC_PIN ) + OPTITEM(HAS_FILWIDTH_ADC, FILWIDTH_PIN ) + OPTITEM(HAS_FILWIDTH2_ADC, FILWIDTH2_PIN ) + OPTITEM(HAS_ADC_BUTTONS, ADC_KEYPAD_PIN ) + OPTITEM(HAS_JOY_ADC_X, JOY_X_PIN ) + OPTITEM(HAS_JOY_ADC_Y, JOY_Y_PIN ) + OPTITEM(HAS_JOY_ADC_Z, JOY_Z_PIN ) + OPTITEM(POWER_MONITOR_CURRENT, POWER_MONITOR_CURRENT_PIN) + OPTITEM(POWER_MONITOR_VOLTAGE, POWER_MONITOR_VOLTAGE_PIN) }; static STM32ADC adc(ADC1); // Configure the ADC @@ -174,27 +176,28 @@ void MarlinHAL::adc_start(const pin_t pin) { ADCIndex pin_index; switch (pin) { default: return; - _TCASE(HAS_TEMP_ADC_0, TEMP_0_PIN, TEMP_0) - _TCASE(HAS_TEMP_ADC_1, TEMP_1_PIN, TEMP_1) - _TCASE(HAS_TEMP_ADC_2, TEMP_2_PIN, TEMP_2) - _TCASE(HAS_TEMP_ADC_3, TEMP_3_PIN, TEMP_3) - _TCASE(HAS_TEMP_ADC_4, TEMP_4_PIN, TEMP_4) - _TCASE(HAS_TEMP_ADC_5, TEMP_5_PIN, TEMP_5) - _TCASE(HAS_TEMP_ADC_6, TEMP_6_PIN, TEMP_6) - _TCASE(HAS_TEMP_ADC_7, TEMP_7_PIN, TEMP_7) - _TCASE(HAS_HEATED_BED, TEMP_BED_PIN, TEMP_BED) - _TCASE(HAS_TEMP_CHAMBER, TEMP_CHAMBER_PIN, TEMP_CHAMBER) - _TCASE(HAS_TEMP_ADC_PROBE, TEMP_PROBE_PIN, TEMP_PROBE) - _TCASE(HAS_TEMP_COOLER, TEMP_COOLER_PIN, TEMP_COOLER) - _TCASE(HAS_TEMP_BOARD, TEMP_BOARD_PIN, TEMP_BOARD) - _TCASE(HAS_TEMP_SOC, TEMP_SOC_PIN, TEMP_SOC) - _TCASE(HAS_JOY_ADC_X, JOY_X_PIN, JOY_X) - _TCASE(HAS_JOY_ADC_Y, JOY_Y_PIN, JOY_Y) - _TCASE(HAS_JOY_ADC_Z, JOY_Z_PIN, JOY_Z) - _TCASE(FILAMENT_WIDTH_SENSOR, FILWIDTH_PIN, FILWIDTH) - _TCASE(HAS_ADC_BUTTONS, ADC_KEYPAD_PIN, ADC_KEY) - _TCASE(POWER_MONITOR_CURRENT, POWER_MONITOR_CURRENT_PIN, POWERMON_CURRENT) - _TCASE(POWER_MONITOR_VOLTAGE, POWER_MONITOR_VOLTAGE_PIN, POWERMON_VOLTAGE) + _TCASE(HAS_TEMP_ADC_0, TEMP_0_PIN, TEMP_0 ) + _TCASE(HAS_TEMP_ADC_1, TEMP_1_PIN, TEMP_1 ) + _TCASE(HAS_TEMP_ADC_2, TEMP_2_PIN, TEMP_2 ) + _TCASE(HAS_TEMP_ADC_3, TEMP_3_PIN, TEMP_3 ) + _TCASE(HAS_TEMP_ADC_4, TEMP_4_PIN, TEMP_4 ) + _TCASE(HAS_TEMP_ADC_5, TEMP_5_PIN, TEMP_5 ) + _TCASE(HAS_TEMP_ADC_6, TEMP_6_PIN, TEMP_6 ) + _TCASE(HAS_TEMP_ADC_7, TEMP_7_PIN, TEMP_7 ) + _TCASE(HAS_TEMP_ADC_BED, TEMP_BED_PIN, TEMP_BED ) + _TCASE(HAS_TEMP_ADC_CHAMBER, TEMP_CHAMBER_PIN, TEMP_CHAMBER ) + _TCASE(HAS_TEMP_ADC_PROBE, TEMP_PROBE_PIN, TEMP_PROBE ) + _TCASE(HAS_TEMP_ADC_COOLER, TEMP_COOLER_PIN, TEMP_COOLER ) + _TCASE(HAS_TEMP_ADC_BOARD, TEMP_BOARD_PIN, TEMP_BOARD ) + _TCASE(HAS_TEMP_ADC_SOC, TEMP_SOC_PIN, TEMP_SOC ) + _TCASE(HAS_FILWIDTH_ADC, FILWIDTH_PIN, FILWIDTH ) + _TCASE(HAS_FILWIDTH2_ADC, FILWIDTH2_PIN, FILWIDTH2 ) + _TCASE(HAS_ADC_BUTTONS, ADC_KEYPAD_PIN, ADC_KEY ) + _TCASE(HAS_JOY_ADC_X, JOY_X_PIN, JOY_X ) + _TCASE(HAS_JOY_ADC_Y, JOY_Y_PIN, JOY_Y ) + _TCASE(HAS_JOY_ADC_Z, JOY_Z_PIN, JOY_Z ) + _TCASE(POWER_MONITOR_CURRENT, POWER_MONITOR_CURRENT_PIN, POWERMON_CURRENT) + _TCASE(POWER_MONITOR_VOLTAGE, POWER_MONITOR_VOLTAGE_PIN, POWERMON_VOLTAGE) } adc_result = (adc_results[(int)pin_index] & 0xFFF) >> (12 - HAL_ADC_RESOLUTION); // shift out unused bits } @@ -252,7 +255,7 @@ void MarlinHAL::init() { #endif #if PIN_EXISTS(USB_CONNECT) OUT_WRITE(USB_CONNECT_PIN, !USB_CONNECT_INVERTING); // USB clear connection - delay(1000); // Give OS time to notice + delay_ms(1000); // Give OS time to notice WRITE(USB_CONNECT_PIN, USB_CONNECT_INVERTING); #endif TERN_(POSTMORTEM_DEBUGGING, install_min_serial()); // Install the minimal serial handler @@ -264,7 +267,7 @@ void MarlinHAL::idletask() { /** * When Marlin is using the SD card it should be locked to prevent it being * accessed from a PC over USB. - * Other HALs use (IS_SD_PRINTING() || IS_SD_FILE_OPEN()) to check for access + * Other HALs use (card.isStillPrinting() || card.isFileOpen()) to check for access * but this won't reliably detect other file operations. To be safe we just lock * the drive whenever Marlin has it mounted. LCDs should include an Unmount * command so drives can be released as needed. diff --git a/Marlin/src/HAL/STM32F1/HAL.h b/Marlin/src/HAL/STM32F1/HAL.h index e80ced866d..2c7321403f 100644 --- a/Marlin/src/HAL/STM32F1/HAL.h +++ b/Marlin/src/HAL/STM32F1/HAL.h @@ -40,11 +40,9 @@ #include "../../inc/MarlinConfigPre.h" #if HAS_SD_HOST_DRIVE - #include "msc_sd.h" + #include "sd/msc_sd.h" #endif -#include "MarlinSerial.h" - // ------------------------ // Defines // ------------------------ @@ -64,95 +62,11 @@ #endif #endif -// ------------------------ -// Serial ports -// ------------------------ +// +// Serial Ports +// -#ifdef SERIAL_USB - typedef ForwardSerial1Class< USBSerial > DefaultSerial1; - extern DefaultSerial1 MSerial0; - #if HAS_SD_HOST_DRIVE - #define UsbSerial MarlinCompositeSerial - #else - #define UsbSerial MSerial0 - #endif -#endif - -#define _MSERIAL(X) MSerial##X -#define MSERIAL(X) _MSERIAL(X) - -#if ANY(STM32_HIGH_DENSITY, STM32_XL_DENSITY) - #define NUM_UARTS 5 -#else - #define NUM_UARTS 3 -#endif - -#if SERIAL_PORT == -1 - #define MYSERIAL1 UsbSerial -#elif WITHIN(SERIAL_PORT, 1, NUM_UARTS) - #define MYSERIAL1 MSERIAL(SERIAL_PORT) -#else - #define MYSERIAL1 MSERIAL(1) // dummy port - static_assert(false, "SERIAL_PORT must be from 1 to " STRINGIFY(NUM_UARTS) ". You can also use -1 if the board supports Native USB.") -#endif - -#ifdef SERIAL_PORT_2 - #if SERIAL_PORT_2 == -1 - #define MYSERIAL2 UsbSerial - #elif WITHIN(SERIAL_PORT_2, 1, NUM_UARTS) - #define MYSERIAL2 MSERIAL(SERIAL_PORT_2) - #else - #define MYSERIAL2 MSERIAL(1) // dummy port - static_assert(false, "SERIAL_PORT_2 must be from 1 to " STRINGIFY(NUM_UARTS) ". You can also use -1 if the board supports Native USB.") - #endif -#endif - -#ifdef SERIAL_PORT_3 - #if SERIAL_PORT_3 == -1 - #define MYSERIAL3 UsbSerial - #elif WITHIN(SERIAL_PORT_3, 1, NUM_UARTS) - #define MYSERIAL3 MSERIAL(SERIAL_PORT_3) - #else - #define MYSERIAL3 MSERIAL(1) // dummy port - static_assert(false, "SERIAL_PORT_3 must be from 1 to " STRINGIFY(NUM_UARTS) ". You can also use -1 if the board supports Native USB.") - #endif -#endif - -#ifdef MMU_SERIAL_PORT - #if MMU_SERIAL_PORT == -1 - #define MMU_SERIAL UsbSerial - #elif WITHIN(MMU_SERIAL_PORT, 1, NUM_UARTS) - #define MMU_SERIAL MSERIAL(MMU_SERIAL_PORT) - #else - #define MMU_SERIAL MSERIAL(1) // dummy port - static_assert(false, "MMU_SERIAL_PORT must be from 1 to " STRINGIFY(NUM_UARTS) ". You can also use -1 if the board supports Native USB.") - #endif -#endif - -#ifdef LCD_SERIAL_PORT - #if LCD_SERIAL_PORT == -1 - #define LCD_SERIAL UsbSerial - #elif WITHIN(LCD_SERIAL_PORT, 1, NUM_UARTS) - #define LCD_SERIAL MSERIAL(LCD_SERIAL_PORT) - #else - #define LCD_SERIAL MSERIAL(1) // dummy port - static_assert(false, "LCD_SERIAL_PORT must be from 1 to " STRINGIFY(NUM_UARTS) ". You can also use -1 if the board supports Native USB.") - #endif - #if ANY(HAS_DGUS_LCD, EXTENSIBLE_UI) - #define LCD_SERIAL_TX_BUFFER_FREE() LCD_SERIAL.availableForWrite() - #endif -#endif - -#ifdef RS485_SERIAL_PORT - #if RS485_SERIAL_PORT == -1 - #define RS485_SERIAL UsbSerial - #elif WITHIN(RS485_SERIAL_PORT, 1, NUM_UARTS) - #define RS485_SERIAL MSERIAL(RS485_SERIAL_PORT) - #else - #define RS485_SERIAL MSERIAL(1) // dummy port - static_assert(false, "RS485_SERIAL_PORT must be from 1 to " STRINGIFY(NUM_UARTS) ".") - #endif -#endif +#include "MarlinSerial.h" /** * TODO: review this to return 1 for pins that are not analog input @@ -273,7 +187,7 @@ public: static void delay_ms(const int ms) { delay(ms); } - // Tasks, called from idle() + // Tasks, called from marlin.idle() static void idletask(); // Reset diff --git a/Marlin/src/HAL/STM32F1/HAL_N32.cpp b/Marlin/src/HAL/STM32F1/HAL_N32.cpp index 971a344f21..e45cbbbfff 100644 --- a/Marlin/src/HAL/STM32F1/HAL_N32.cpp +++ b/Marlin/src/HAL/STM32F1/HAL_N32.cpp @@ -612,7 +612,7 @@ void ADC_DMA_init() { * n32g452 - end ==============================================================================*/ -#define NS_PINRT(V...) do{ SERIAL_ECHO_START(); SERIAL_ECHOLNPAIR(V); }while(0) +#define NS_PINRT(V...) do{ SERIAL_ECHO_START(); SERIAL_ECHOLNPGM(V); }while(0) // Init the AD in continuous capture mode void MarlinHAL::adc_init() { @@ -622,7 +622,7 @@ void MarlinHAL::adc_init() { // GPIO settings reg_temp = ADC_RCC_APB2PCLKEN; - reg_temp |= 0x0f; // Make PORT mouth clock + reg_temp |= 0x0F; // Make PORT mouth clock ADC_RCC_APB2PCLKEN = reg_temp; //reg_temp = NS_GPIOC_PL_CFG; diff --git a/Marlin/src/HAL/STM32F1/HAL_N32.h b/Marlin/src/HAL/STM32F1/HAL_N32.h index 7162e2b971..719368f6f1 100644 --- a/Marlin/src/HAL/STM32F1/HAL_N32.h +++ b/Marlin/src/HAL/STM32F1/HAL_N32.h @@ -239,8 +239,8 @@ typedef struct { #define ADC_WORKMODE_SLOW_INTERL ((uint32_t)0x00080000) #define ADC_WORKMODE_ALTER_TRIG ((uint32_t)0x00090000) -#define ADC_EXT_TRIGCONV_T1_CC3 ((uint32_t)0x00040000) //!< For ADC1, ADC2 , ADC3 and ADC4 -#define ADC_EXT_TRIGCONV_NONE ((uint32_t)0x000E0000) //!< For ADC1, ADC2 , ADC3 and ADC4 +#define ADC_EXT_TRIGCONV_T1_CC3 ((uint32_t)0x00040000) //!< For ADC1, ADC2, ADC3, and ADC4 +#define ADC_EXT_TRIGCONV_NONE ((uint32_t)0x000E0000) //!< For ADC1, ADC2, ADC3, and ADC4 #define ADC_DAT_ALIGN_R ((uint32_t)0x00000000) #define ADC_DAT_ALIGN_L ((uint32_t)0x00000800) @@ -603,9 +603,9 @@ typedef struct { #define DMA_CHCFG7_PINC ((uint16_t)0x0040) //!< Peripheral increment mode #define DMA_CHCFG7_MINC ((uint16_t)0x0080) //!< Memory increment mode -#define DMA_CHCFG7_PSIZE , ((uint16_t)0x0300) //!< PSIZE[1:0] bits (Peripheral size) -#define DMA_CHCFG7_PSIZE_0 ((uint16_t)0x0100) //!< Bit 0 -#define DMA_CHCFG7_PSIZE_1 ((uint16_t)0x0200) //!< Bit 1 +#define DMA_CHCFG7_PSIZE ((uint16_t)0x0300) //!< PSIZE[1:0] bits (Peripheral size) +#define DMA_CHCFG7_PSIZE_0 ((uint16_t)0x0100) //!< Bit 0 +#define DMA_CHCFG7_PSIZE_1 ((uint16_t)0x0200) //!< Bit 1 #define DMA_CHCFG7_MSIZE ((uint16_t)0x0C00) //!< MSIZE[1:0] bits (Memory size) #define DMA_CHCFG7_MSIZE_0 ((uint16_t)0x0400) //!< Bit 0 @@ -627,9 +627,9 @@ typedef struct { #define DMA_CHCFG8_PINC ((uint16_t)0x0040) //!< Peripheral increment mode #define DMA_CHCFG8_MINC ((uint16_t)0x0080) //!< Memory increment mode -#define DMA_CHCFG8_PSIZE , ((uint16_t)0x0300) //!< PSIZE[1:0] bits (Peripheral size) -#define DMA_CHCFG8_PSIZE_0 ((uint16_t)0x0100) //!< Bit 0 -#define DMA_CHCFG8_PSIZE_1 ((uint16_t)0x0200) //!< Bit 1 +#define DMA_CHCFG8_PSIZE ((uint16_t)0x0300) //!< PSIZE[1:0] bits (Peripheral size) +#define DMA_CHCFG8_PSIZE_0 ((uint16_t)0x0100) //!< Bit 0 +#define DMA_CHCFG8_PSIZE_1 ((uint16_t)0x0200) //!< Bit 1 #define DMA_CHCFG8_MSIZE ((uint16_t)0x0C00) //!< MSIZE[1:0] bits (Memory size) #define DMA_CHCFG8_MSIZE_0 ((uint16_t)0x0400) //!< Bit 0 @@ -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); diff --git a/Marlin/src/HAL/STM32F1/MarlinSerial.h b/Marlin/src/HAL/STM32F1/MarlinSerial.h index 53bcd48476..c2dc5bd571 100644 --- a/Marlin/src/HAL/STM32F1/MarlinSerial.h +++ b/Marlin/src/HAL/STM32F1/MarlinSerial.h @@ -28,6 +28,29 @@ #include "../../inc/MarlinConfigPre.h" #include "../../core/serial_hook.h" +#ifdef SERIAL_USB + typedef ForwardSerial1Class< USBSerial > DefaultSerial1; + extern DefaultSerial1 MSerial0; + #if HAS_SD_HOST_DRIVE + #define UsbSerial MarlinCompositeSerial + #else + #define UsbSerial MSerial0 + #endif +#endif + +#define SERIAL_INDEX_MIN 1 +#if ANY(STM32_HIGH_DENSITY, STM32_XL_DENSITY) + #define SERIAL_INDEX_MAX 5 +#else + #define SERIAL_INDEX_MAX 3 +#endif +#define USB_SERIAL_PORT(...) UsbSerial +#include "../shared/serial_ports.h" + +#if defined(LCD_SERIAL_PORT) && ANY(HAS_DGUS_LCD, EXTENSIBLE_UI) + #define LCD_SERIAL_TX_BUFFER_FREE() LCD_SERIAL.availableForWrite() +#endif + // Increase priority of serial interrupts, to reduce overflow errors #define UART_IRQ_PRIO 1 diff --git a/Marlin/src/HAL/STM32F1/MinSerial.cpp b/Marlin/src/HAL/STM32F1/MinSerial.cpp index 8fb9133254..0d9a611d7e 100644 --- a/Marlin/src/HAL/STM32F1/MinSerial.cpp +++ b/Marlin/src/HAL/STM32F1/MinSerial.cpp @@ -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__ ( diff --git a/Marlin/src/HAL/STM32F1/README.md b/Marlin/src/HAL/STM32F1/README.md index b5bd5141fb..e289f35433 100644 --- a/Marlin/src/HAL/STM32F1/README.md +++ b/Marlin/src/HAL/STM32F1/README.md @@ -5,6 +5,7 @@ This HAL is for STM32F103 boards used with [Arduino STM32](https://github.com/ro Currently has been tested in Malyan M200 (103CBT6), SKRmini (103RCT6), Chitu 3d (103ZET6), and various 103VET6 boards. ### Main developers: + - Victorpv - xC000005 - thisiskeithb diff --git a/Marlin/src/HAL/STM32F1/SPI.h b/Marlin/src/HAL/STM32F1/SPI.h index 27bf684388..72063df699 100644 --- a/Marlin/src/HAL/STM32F1/SPI.h +++ b/Marlin/src/HAL/STM32F1/SPI.h @@ -33,12 +33,14 @@ #include #include +#include "../../core/macros.h" // for PIN_EXISTS + // Number of SPI ports -#ifdef BOARD_SPI3_SCK_PIN +#if PIN_EXISTS(BOARD_SPI3_SCK) #define BOARD_NR_SPI 3 -#elif defined(BOARD_SPI2_SCK_PIN) +#elif PIN_EXISTS(BOARD_SPI2_SCK) #define BOARD_NR_SPI 2 -#elif defined(BOARD_SPI1_SCK_PIN) +#elif PIN_EXISTS(BOARD_SPI1_SCK) #define BOARD_NR_SPI 1 #endif diff --git a/Marlin/src/HAL/STM32F1/Servo.cpp b/Marlin/src/HAL/STM32F1/Servo.cpp index 7aa8fe3d00..00caec287b 100644 --- a/Marlin/src/HAL/STM32F1/Servo.cpp +++ b/Marlin/src/HAL/STM32F1/Servo.cpp @@ -29,8 +29,6 @@ uint8_t ServoCount = 0; #include "Servo.h" -//#include "Servo.h" - #include #include #include diff --git a/Marlin/src/HAL/STM32F1/adc.h b/Marlin/src/HAL/STM32F1/adc.h index 25f4a7ce16..a2f5652de0 100644 --- a/Marlin/src/HAL/STM32F1/adc.h +++ b/Marlin/src/HAL/STM32F1/adc.h @@ -44,7 +44,8 @@ enum ADCIndex : uint8_t { OPTITEM(HAS_TEMP_ADC_COOLER, TEMP_COOLER ) OPTITEM(HAS_TEMP_ADC_BOARD, TEMP_BOARD ) OPTITEM(HAS_TEMP_ADC_SOC, TEMP_SOC ) - OPTITEM(FILAMENT_WIDTH_SENSOR, FILWIDTH ) + OPTITEM(HAS_FILWIDTH_ADC, FILWIDTH ) + OPTITEM(HAS_FILWIDTH2_ADC, FILWIDTH2 ) OPTITEM(HAS_ADC_BUTTONS, ADC_KEY ) OPTITEM(HAS_JOY_ADC_X, JOY_X ) OPTITEM(HAS_JOY_ADC_Y, JOY_Y ) diff --git a/Marlin/src/HAL/STM32F1/eeprom_bl24cxx.cpp b/Marlin/src/HAL/STM32F1/eeprom/eeprom_bl24cxx.cpp similarity index 95% rename from Marlin/src/HAL/STM32F1/eeprom_bl24cxx.cpp rename to Marlin/src/HAL/STM32F1/eeprom/eeprom_bl24cxx.cpp index 1252e77b0b..9e96a741bf 100644 --- a/Marlin/src/HAL/STM32F1/eeprom_bl24cxx.cpp +++ b/Marlin/src/HAL/STM32F1/eeprom/eeprom_bl24cxx.cpp @@ -26,12 +26,12 @@ * with simple implementations supplied by Marlin. */ -#include "../../inc/MarlinConfig.h" +#include "../../../inc/MarlinConfig.h" #if ENABLED(IIC_BL24CXX_EEPROM) -#include "../shared/eeprom_if.h" -#include "../shared/eeprom_api.h" +#include "../../shared/eeprom_if.h" +#include "../../shared/eeprom_api.h" // // PersistentStore diff --git a/Marlin/src/HAL/STM32F1/eeprom_flash.cpp b/Marlin/src/HAL/STM32F1/eeprom/eeprom_flash.cpp similarity index 85% rename from Marlin/src/HAL/STM32F1/eeprom_flash.cpp rename to Marlin/src/HAL/STM32F1/eeprom/eeprom_flash.cpp index afdfefd5f0..2292c02203 100644 --- a/Marlin/src/HAL/STM32F1/eeprom_flash.cpp +++ b/Marlin/src/HAL/STM32F1/eeprom/eeprom_flash.cpp @@ -28,18 +28,18 @@ #ifdef __STM32F1__ -#include "../../inc/MarlinConfig.h" +#include "../../../inc/MarlinConfig.h" #if ENABLED(FLASH_EEPROM_EMULATION) -#include "../shared/eeprom_api.h" +#include "../../shared/eeprom_api.h" #include #include // Store settings in the last two pages #ifndef MARLIN_EEPROM_SIZE - #define MARLIN_EEPROM_SIZE ((EEPROM_PAGE_SIZE) * 2) + #define MARLIN_EEPROM_SIZE ((EEPROM_PAGE_SIZE) * 2UL) #endif size_t PersistentStore::capacity() { return MARLIN_EEPROM_SIZE - eeprom_exclude_size; } @@ -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(EEPROM_PAGE0_BASE); - uint32_t *destination = reinterpret_cast(ram_eeprom); + const uint32_t *src = reinterpret_cast(EEPROM_PAGE0_BASE); + uint32_t *dst = reinterpret_cast(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(ram_eeprom); - for (size_t i = 0; i < MARLIN_EEPROM_SIZE; i += 2, ++source) { - if (FLASH_ProgramHalfWord(EEPROM_PAGE0_BASE + i, *source) != FLASH_COMPLETE) + const uint16_t *src = reinterpret_cast(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); } diff --git a/Marlin/src/HAL/STM32F1/eeprom_if_iic.cpp b/Marlin/src/HAL/STM32F1/eeprom/eeprom_if_iic.cpp similarity index 90% rename from Marlin/src/HAL/STM32F1/eeprom_if_iic.cpp rename to Marlin/src/HAL/STM32F1/eeprom/eeprom_if_iic.cpp index 78b7af0b04..e7e7fc1db1 100644 --- a/Marlin/src/HAL/STM32F1/eeprom_if_iic.cpp +++ b/Marlin/src/HAL/STM32F1/eeprom/eeprom_if_iic.cpp @@ -27,12 +27,12 @@ #ifdef __STM32F1__ -#include "../../inc/MarlinConfig.h" +#include "../../../inc/MarlinConfig.h" #if ENABLED(IIC_BL24CXX_EEPROM) -#include "../../libs/BL24CXX.h" -#include "../shared/eeprom_if.h" +#include "../../../libs/BL24CXX.h" +#include "../../shared/eeprom_if.h" void eeprom_init() { BL24CXX::init(); } @@ -42,7 +42,7 @@ void eeprom_init() { BL24CXX::init(); } void eeprom_write_byte(uint8_t *pos, uint8_t value) { const unsigned eeprom_address = (unsigned)pos; - return BL24CXX::writeOneByte(eeprom_address, value); + BL24CXX::writeOneByte(eeprom_address, value); } uint8_t eeprom_read_byte(uint8_t *pos) { diff --git a/Marlin/src/HAL/STM32F1/eeprom_sdcard.cpp b/Marlin/src/HAL/STM32F1/eeprom/eeprom_sdcard.cpp similarity index 93% rename from Marlin/src/HAL/STM32F1/eeprom_sdcard.cpp rename to Marlin/src/HAL/STM32F1/eeprom/eeprom_sdcard.cpp index 6b72193422..e41c6e0aa0 100644 --- a/Marlin/src/HAL/STM32F1/eeprom_sdcard.cpp +++ b/Marlin/src/HAL/STM32F1/eeprom/eeprom_sdcard.cpp @@ -27,12 +27,12 @@ #ifdef __STM32F1__ -#include "../../inc/MarlinConfig.h" +#include "../../../inc/MarlinConfig.h" #if ENABLED(SDCARD_EEPROM_EMULATION) -#include "../shared/eeprom_api.h" -#include "../../sd/cardreader.h" +#include "../../shared/eeprom_api.h" +#include "../../../sd/cardreader.h" #define EEPROM_FILENAME "eeprom.dat" @@ -53,7 +53,7 @@ bool PersistentStore::access_start() { int bytes_read = file.read(HAL_eeprom_data, MARLIN_EEPROM_SIZE); if (bytes_read < 0) return false; - for (; bytes_read < MARLIN_EEPROM_SIZE; bytes_read++) + for (; bytes_read < long(MARLIN_EEPROM_SIZE); bytes_read++) HAL_eeprom_data[bytes_read] = 0xFF; file.close(); return true; diff --git a/Marlin/src/HAL/STM32F1/eeprom_wired.cpp b/Marlin/src/HAL/STM32F1/eeprom/eeprom_wired.cpp similarity index 95% rename from Marlin/src/HAL/STM32F1/eeprom_wired.cpp rename to Marlin/src/HAL/STM32F1/eeprom/eeprom_wired.cpp index bfb7718094..a1464ab983 100644 --- a/Marlin/src/HAL/STM32F1/eeprom_wired.cpp +++ b/Marlin/src/HAL/STM32F1/eeprom/eeprom_wired.cpp @@ -26,12 +26,12 @@ #ifdef __STM32F1__ -#include "../../inc/MarlinConfig.h" +#include "../../../inc/MarlinConfig.h" #if USE_WIRED_EEPROM -#include "../shared/eeprom_if.h" -#include "../shared/eeprom_api.h" +#include "../../shared/eeprom_if.h" +#include "../../shared/eeprom_api.h" #ifndef MARLIN_EEPROM_SIZE #error "MARLIN_EEPROM_SIZE is required for I2C / SPI EEPROM." diff --git a/Marlin/src/HAL/STM32F1/fastio.h b/Marlin/src/HAL/STM32F1/fastio.h index 5b3ebaa52c..8bb986b466 100644 --- a/Marlin/src/HAL/STM32F1/fastio.h +++ b/Marlin/src/HAL/STM32F1/fastio.h @@ -44,6 +44,7 @@ #define SET_INPUT_PULLUP(IO) _SET_MODE(IO, GPIO_INPUT_PU) #define SET_INPUT_PULLDOWN(IO) _SET_MODE(IO, GPIO_INPUT_PD) #define SET_OUTPUT(IO) OUT_WRITE(IO, LOW) +#define SET_OUTPUT_OD(IO) OUT_WRITE_OD(IO, LOW) #define SET_PWM(IO) pinMode(IO, PWM) // do{ gpio_set_mode(PIN_MAP[pin].gpio_device, PIN_MAP[pin].gpio_bit, GPIO_AF_OUTPUT_PP); timer_set_mode(PIN_MAP[pin].timer_device, PIN_MAP[pin].timer_channel, TIMER_PWM); }while(0) #define SET_PWM_OD(IO) pinMode(IO, PWM_OPEN_DRAIN) diff --git a/Marlin/src/HAL/STM32F1/msc_sd.cpp b/Marlin/src/HAL/STM32F1/sd/msc_sd.cpp similarity index 96% rename from Marlin/src/HAL/STM32F1/msc_sd.cpp rename to Marlin/src/HAL/STM32F1/sd/msc_sd.cpp index 067b46eb8b..5f1ba30c8a 100644 --- a/Marlin/src/HAL/STM32F1/msc_sd.cpp +++ b/Marlin/src/HAL/STM32F1/sd/msc_sd.cpp @@ -22,20 +22,21 @@ */ #ifdef __STM32F1__ -#include "../../inc/MarlinConfigPre.h" +#include "../../../inc/MarlinConfigPre.h" #if HAS_SD_HOST_DRIVE #include "msc_sd.h" -#include "SPI.h" -#include "usb_reg_map.h" +#include "../SPI.h" + +#include #define PRODUCT_ID 0x29 USBMassStorage MarlinMSC; Serial1Class MarlinCompositeSerial(true); -#include "../../inc/MarlinConfig.h" +#include "../../../inc/MarlinConfig.h" #if SD_CONNECTION_IS(ONBOARD) diff --git a/Marlin/src/HAL/STM32F1/msc_sd.h b/Marlin/src/HAL/STM32F1/sd/msc_sd.h similarity index 93% rename from Marlin/src/HAL/STM32F1/msc_sd.h rename to Marlin/src/HAL/STM32F1/sd/msc_sd.h index 371211efc6..871d98eaf2 100644 --- a/Marlin/src/HAL/STM32F1/msc_sd.h +++ b/Marlin/src/HAL/STM32F1/sd/msc_sd.h @@ -24,8 +24,8 @@ #include -#include "../../inc/MarlinConfigPre.h" -#include "../../core/serial_hook.h" +#include "../../../inc/MarlinConfigPre.h" +#include "../../../core/serial_hook.h" extern USBMassStorage MarlinMSC; extern Serial1Class MarlinCompositeSerial; diff --git a/Marlin/src/HAL/STM32F1/onboard_sd.cpp b/Marlin/src/HAL/STM32F1/sd/onboard_sd.cpp similarity index 99% rename from Marlin/src/HAL/STM32F1/onboard_sd.cpp rename to Marlin/src/HAL/STM32F1/sd/onboard_sd.cpp index a3d8dcb2d5..ace1204b75 100644 --- a/Marlin/src/HAL/STM32F1/onboard_sd.cpp +++ b/Marlin/src/HAL/STM32F1/sd/onboard_sd.cpp @@ -13,13 +13,13 @@ #ifdef __STM32F1__ -#include "../../inc/MarlinConfig.h" +#include "../../../inc/MarlinConfig.h" #if SD_CONNECTION_IS(ONBOARD) #include "onboard_sd.h" -#include "SPI.h" -#include "fastio.h" +#include "../SPI.h" +#include "../fastio.h" #ifndef ONBOARD_SPI_DEVICE #define ONBOARD_SPI_DEVICE SPI_DEVICE diff --git a/Marlin/src/HAL/STM32F1/onboard_sd.h b/Marlin/src/HAL/STM32F1/sd/onboard_sd.h similarity index 100% rename from Marlin/src/HAL/STM32F1/onboard_sd.h rename to Marlin/src/HAL/STM32F1/sd/onboard_sd.h diff --git a/Marlin/src/HAL/STM32F1/sdio.cpp b/Marlin/src/HAL/STM32F1/sd/sdio.cpp similarity index 98% rename from Marlin/src/HAL/STM32F1/sdio.cpp rename to Marlin/src/HAL/STM32F1/sd/sdio.cpp index 23f984eff3..d657fd3b0e 100644 --- a/Marlin/src/HAL/STM32F1/sdio.cpp +++ b/Marlin/src/HAL/STM32F1/sd/sdio.cpp @@ -19,11 +19,11 @@ * along with this program. If not, see . * */ -#ifdef ARDUINO_ARCH_STM32F1 +#ifdef __STM32F1__ #include -#include "../../inc/MarlinConfig.h" // Allow pins/pins.h to set density +#include "../../../inc/MarlinConfig.h" // Allow pins/pins.h to set density #if ANY(STM32_HIGH_DENSITY, STM32_XL_DENSITY) @@ -145,7 +145,7 @@ bool SDIO_ReadBlock(uint32_t blockAddress, uint8_t *data) { return false; } -uint32_t millis(); +unsigned long millis(); bool SDIO_WriteBlock(uint32_t blockAddress, const uint8_t *data) { if (SDIO_GetCardState() != SDIO_CARD_TRANSFER) return false; @@ -219,7 +219,7 @@ bool SDIO_CmdAppSetBusWidth(uint32_t rsa, uint32_t argument) { bool SDIO_CmdAppOperCommand(uint32_t sdType) { if (!SDIO_CmdAppCommand(0)) return false; - SDIO_SendCommand(ACMD41_SD_APP_OP_COND , SDMMC_VOLTAGE_WINDOW_SD | sdType); + SDIO_SendCommand(ACMD41_SD_APP_OP_COND, SDMMC_VOLTAGE_WINDOW_SD | sdType); return SDIO_GetCmdResp3(); } @@ -308,4 +308,4 @@ bool SDIO_GetCmdResp7() { } #endif // STM32_HIGH_DENSITY || STM32_XL_DENSITY -#endif // ARDUINO_ARCH_STM32F1 +#endif // __STM32F1__ diff --git a/Marlin/src/HAL/STM32F1/sdio.h b/Marlin/src/HAL/STM32F1/sd/sdio.h similarity index 98% rename from Marlin/src/HAL/STM32F1/sdio.h rename to Marlin/src/HAL/STM32F1/sd/sdio.h index 08c884666d..ffcd354915 100644 --- a/Marlin/src/HAL/STM32F1/sdio.h +++ b/Marlin/src/HAL/STM32F1/sd/sdio.h @@ -21,7 +21,7 @@ */ #pragma once -#include "../../inc/MarlinConfig.h" // Allow pins/pins.h to override SDIO clock / retries +#include "../../../inc/MarlinConfig.h" // Allow pins/pins.h to override SDIO clock / retries #include #include diff --git a/Marlin/src/HAL/STM32F1/spi_pins.h b/Marlin/src/HAL/STM32F1/spi_pins.h index 3d3c8f8d2f..d9c5e1f8c6 100644 --- a/Marlin/src/HAL/STM32F1/spi_pins.h +++ b/Marlin/src/HAL/STM32F1/spi_pins.h @@ -46,11 +46,6 @@ #ifndef SD_MOSI_PIN #define SD_MOSI_PIN PA7 #endif -#ifndef SD_SS_PIN - #define SD_SS_PIN PA4 -#endif -#undef SDSS -#define SDSS SD_SS_PIN #ifndef SPI_DEVICE #define SPI_DEVICE 1 diff --git a/Marlin/src/HAL/STM32F1/tft/tft_fsmc.cpp b/Marlin/src/HAL/STM32F1/tft/tft_fsmc.cpp index 51f70b9365..73b0e7efb9 100644 --- a/Marlin/src/HAL/STM32F1/tft/tft_fsmc.cpp +++ b/Marlin/src/HAL/STM32F1/tft/tft_fsmc.cpp @@ -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; diff --git a/Marlin/src/HAL/STM32F1/timers.cpp b/Marlin/src/HAL/STM32F1/timers.cpp index 12477a4583..141dc80b80 100644 --- a/Marlin/src/HAL/STM32F1/timers.cpp +++ b/Marlin/src/HAL/STM32F1/timers.cpp @@ -84,7 +84,7 @@ void HAL_timer_start(const uint8_t timer_num, const uint32_t frequency) { timer_set_prescaler(STEP_TIMER_DEV, (uint16_t)(STEPPER_TIMER_PRESCALE - 1)); timer_set_reload(STEP_TIMER_DEV, 0xFFFF); timer_oc_set_mode(STEP_TIMER_DEV, STEP_TIMER_CHAN, TIMER_OC_MODE_FROZEN, TIMER_OC_NO_PRELOAD); // no output pin change - timer_set_compare(STEP_TIMER_DEV, STEP_TIMER_CHAN, _MIN(hal_timer_t(HAL_TIMER_TYPE_MAX), (STEPPER_TIMER_RATE) / frequency)); + timer_set_compare(STEP_TIMER_DEV, STEP_TIMER_CHAN, _MIN(HAL_TIMER_TYPE_MAX, hal_timer_t((STEPPER_TIMER_RATE) / frequency))); timer_no_ARR_preload_ARPE(STEP_TIMER_DEV); // Need to be sure no preload on ARR register timer_attach_interrupt(STEP_TIMER_DEV, STEP_TIMER_CHAN, stepTC_Handler); HAL_timer_set_interrupt_priority(MF_TIMER_STEP, STEP_TIMER_IRQ_PRIO); @@ -97,7 +97,7 @@ void HAL_timer_start(const uint8_t timer_num, const uint32_t frequency) { timer_set_count(TEMP_TIMER_DEV, 0); timer_set_prescaler(TEMP_TIMER_DEV, (uint16_t)(TEMP_TIMER_PRESCALE - 1)); timer_set_reload(TEMP_TIMER_DEV, 0xFFFF); - timer_set_compare(TEMP_TIMER_DEV, TEMP_TIMER_CHAN, _MIN(hal_timer_t(HAL_TIMER_TYPE_MAX), (F_CPU) / (TEMP_TIMER_PRESCALE) / frequency)); + timer_set_compare(TEMP_TIMER_DEV, TEMP_TIMER_CHAN, _MIN(HAL_TIMER_TYPE_MAX, hal_timer_t((F_CPU) / (TEMP_TIMER_PRESCALE) / frequency))); timer_attach_interrupt(TEMP_TIMER_DEV, TEMP_TIMER_CHAN, tempTC_Handler); HAL_timer_set_interrupt_priority(MF_TIMER_TEMP, TEMP_TIMER_IRQ_PRIO); timer_generate_update(TEMP_TIMER_DEV); diff --git a/Marlin/src/HAL/STM32F1/timers.h b/Marlin/src/HAL/STM32F1/timers.h index 89a609c2c3..3d6650a1a2 100644 --- a/Marlin/src/HAL/STM32F1/timers.h +++ b/Marlin/src/HAL/STM32F1/timers.h @@ -40,7 +40,7 @@ */ typedef uint16_t hal_timer_t; -#define HAL_TIMER_TYPE_MAX 0xFFFF +#define HAL_TIMER_TYPE_MAX hal_timer_t(UINT16_MAX) #define HAL_TIMER_RATE uint32_t(F_CPU) // frequency of timers peripherals @@ -95,27 +95,26 @@ typedef uint16_t hal_timer_t; #define TEMP_TIMER_IRQ_PRIO 3 #define SERVO0_TIMER_IRQ_PRIO 1 -#define TEMP_TIMER_PRESCALE 1000 // prescaler for setting Temp timer, 72Khz -#define TEMP_TIMER_FREQUENCY 1000 // temperature interrupt frequency +#define TEMP_TIMER_PRESCALE 1000 // Prescaler for setting Temp Timer, 72Khz +#define TEMP_TIMER_FREQUENCY 1000 // (Hz) Temperature ISR frequency -#define STEPPER_TIMER_PRESCALE 18 // prescaler for setting stepper timer, 4Mhz -#define STEPPER_TIMER_RATE (HAL_TIMER_RATE / STEPPER_TIMER_PRESCALE) // frequency of stepper timer -#define STEPPER_TIMER_TICKS_PER_US ((STEPPER_TIMER_RATE) / 1000000) // stepper timer ticks per µs +#define STEPPER_TIMER_PRESCALE 18 // Prescaler for setting stepper timer, 4Mhz +#define STEPPER_TIMER_RATE (HAL_TIMER_RATE / STEPPER_TIMER_PRESCALE) // (Hz) Frequency of Stepper Timer ISR +#define STEPPER_TIMER_TICKS_PER_US ((STEPPER_TIMER_RATE) / 1000000UL) // (MHz) Stepper Timer ticks per µs -#define PULSE_TIMER_RATE STEPPER_TIMER_RATE // frequency of pulse timer +#define PULSE_TIMER_RATE STEPPER_TIMER_RATE // (Hz) Frequency of Pulse Timer #define PULSE_TIMER_PRESCALE STEPPER_TIMER_PRESCALE -#define PULSE_TIMER_TICKS_PER_US STEPPER_TIMER_TICKS_PER_US timer_dev* HAL_get_timer_dev(int number); #define TIMER_DEV(num) HAL_get_timer_dev(num) #define STEP_TIMER_DEV TIMER_DEV(MF_TIMER_STEP) #define TEMP_TIMER_DEV TIMER_DEV(MF_TIMER_TEMP) -#define ENABLE_STEPPER_DRIVER_INTERRUPT() timer_enable_irq(STEP_TIMER_DEV, STEP_TIMER_CHAN) -#define DISABLE_STEPPER_DRIVER_INTERRUPT() timer_disable_irq(STEP_TIMER_DEV, STEP_TIMER_CHAN) -#define STEPPER_ISR_ENABLED() HAL_timer_interrupt_enabled(MF_TIMER_STEP) +#define ENABLE_STEPPER_DRIVER_INTERRUPT() timer_enable_irq(STEP_TIMER_DEV, STEP_TIMER_CHAN) +#define DISABLE_STEPPER_DRIVER_INTERRUPT() timer_disable_irq(STEP_TIMER_DEV, STEP_TIMER_CHAN) +#define STEPPER_ISR_ENABLED() HAL_timer_interrupt_enabled(MF_TIMER_STEP) -#define ENABLE_TEMPERATURE_INTERRUPT() timer_enable_irq(TEMP_TIMER_DEV, TEMP_TIMER_CHAN) +#define ENABLE_TEMPERATURE_INTERRUPT() timer_enable_irq(TEMP_TIMER_DEV, TEMP_TIMER_CHAN) #define DISABLE_TEMPERATURE_INTERRUPT() timer_disable_irq(TEMP_TIMER_DEV, TEMP_TIMER_CHAN) #define HAL_timer_get_count(timer_num) timer_get_count(TIMER_DEV(timer_num)) @@ -188,7 +187,7 @@ FORCE_INLINE static void HAL_timer_isr_prologue(const uint8_t timer_num) { } } -#define HAL_timer_isr_epilogue(T) NOOP +inline void HAL_timer_isr_epilogue(const uint8_t) {} // No command is available in framework to turn off ARPE bit, which is turned on by default in libmaple. // Needed here to reset ARPE=0 for stepper timer diff --git a/Marlin/src/HAL/STM32F1/dogm/u8g_com_stm32duino_swspi.cpp b/Marlin/src/HAL/STM32F1/u8g/u8g_com_stm32duino_swspi.cpp similarity index 100% rename from Marlin/src/HAL/STM32F1/dogm/u8g_com_stm32duino_swspi.cpp rename to Marlin/src/HAL/STM32F1/u8g/u8g_com_stm32duino_swspi.cpp diff --git a/Marlin/src/HAL/TEENSY31_32/HAL.cpp b/Marlin/src/HAL/TEENSY31_32/HAL.cpp index 2892368967..f54025991d 100644 --- a/Marlin/src/HAL/TEENSY31_32/HAL.cpp +++ b/Marlin/src/HAL/TEENSY31_32/HAL.cpp @@ -37,10 +37,20 @@ #define _IMPLEMENT_SERIAL(X) DefaultSerial##X MSerial##X(false, Serial##X) #define IMPLEMENT_SERIAL(X) _IMPLEMENT_SERIAL(X) -#if WITHIN(SERIAL_PORT, 0, 3) +#if WITHIN(SERIAL_PORT, SERIAL_INDEX_MIN, SERIAL_INDEX_MAX) IMPLEMENT_SERIAL(SERIAL_PORT); -#else - #error "SERIAL_PORT must be from 0 to 3." +#endif +#if defined(SERIAL_PORT_2) && WITHIN(SERIAL_PORT_2, SERIAL_INDEX_MIN, SERIAL_INDEX_MAX) + IMPLEMENT_SERIAL(SERIAL_PORT_2); +#endif +#if defined(SERIAL_PORT_3) && WITHIN(SERIAL_PORT_3, SERIAL_INDEX_MIN, SERIAL_INDEX_MAX) + IMPLEMENT_SERIAL(SERIAL_PORT_3); +#endif +#if defined(MMU_SERIAL_PORT) && WITHIN(MMU_SERIAL_PORT, SERIAL_INDEX_MIN, SERIAL_INDEX_MAX) + IMPLEMENT_SERIAL(MMU_SERIAL_PORT); +#endif +#if defined(LCD_SERIAL_PORT) && WITHIN(LCD_SERIAL_PORT, SERIAL_INDEX_MIN, SERIAL_INDEX_MAX) + IMPLEMENT_SERIAL(LCD_SERIAL_PORT); #endif USBSerialType USBSerial(false, SerialUSB); diff --git a/Marlin/src/HAL/TEENSY31_32/HAL.h b/Marlin/src/HAL/TEENSY31_32/HAL.h index 659fcb72e5..b98ee9eb39 100644 --- a/Marlin/src/HAL/TEENSY31_32/HAL.h +++ b/Marlin/src/HAL/TEENSY31_32/HAL.h @@ -64,17 +64,10 @@ typedef ForwardSerial1Class USBSerialType; extern USBSerialType USBSerial; -#define _MSERIAL(X) MSerial##X -#define MSERIAL(X) _MSERIAL(X) - -#if SERIAL_PORT == -1 - #define MYSERIAL1 USBSerial -#elif WITHIN(SERIAL_PORT, 0, 3) - DECLARE_SERIAL(SERIAL_PORT); - #define MYSERIAL1 MSERIAL(SERIAL_PORT) -#else - #error "The required SERIAL_PORT must be from 0 to 3, or -1 for Native USB." -#endif +#define SERIAL_INDEX_MIN 0 +#define SERIAL_INDEX_MAX 3 +#define USB_SERIAL_PORT(...) USBSerial +#include "../shared/serial_ports.h" // ------------------------ // Types @@ -149,7 +142,7 @@ public: static void delay_ms(const int ms) { delay(ms); } - // Tasks, called from idle() + // Tasks, called from marlin.idle() static void idletask() {} // Reset diff --git a/Marlin/src/HAL/TEENSY31_32/Servo.h b/Marlin/src/HAL/TEENSY31_32/Servo.h index 82b601d956..2da74fd25d 100644 --- a/Marlin/src/HAL/TEENSY31_32/Servo.h +++ b/Marlin/src/HAL/TEENSY31_32/Servo.h @@ -31,7 +31,5 @@ class libServo : public Servo { void move(const int value); private: typedef Servo super; - uint16_t min_ticks; - uint16_t max_ticks; uint8_t servoIndex; // index into the channel data for this servo }; diff --git a/Marlin/src/HAL/TEENSY31_32/fastio.h b/Marlin/src/HAL/TEENSY31_32/fastio.h index 622799ec8c..b582c7bfec 100644 --- a/Marlin/src/HAL/TEENSY31_32/fastio.h +++ b/Marlin/src/HAL/TEENSY31_32/fastio.h @@ -53,17 +53,17 @@ #define _SET_INPUT(P) do{ \ CORE_PIN ## P ## _CONFIG = PORT_PCR_MUX(1); \ - GPIO_BITBAND(CORE_PIN ## P ## _DDRREG , CORE_PIN ## P ## _BIT) = 0; \ + GPIO_BITBAND(CORE_PIN ## P ## _DDRREG, CORE_PIN ## P ## _BIT) = 0; \ }while(0) #define _SET_OUTPUT(P) do{ \ CORE_PIN ## P ## _CONFIG = PORT_PCR_MUX(1)|PORT_PCR_SRE|PORT_PCR_DSE; \ - GPIO_BITBAND(CORE_PIN ## P ## _DDRREG , CORE_PIN ## P ## _BIT) = 1; \ + GPIO_BITBAND(CORE_PIN ## P ## _DDRREG, CORE_PIN ## P ## _BIT) = 1; \ }while(0) #define _SET_INPUT_PULLUP(P) do{ \ CORE_PIN ## P ## _CONFIG = PORT_PCR_MUX(1) | PORT_PCR_PE | PORT_PCR_PS; \ - GPIO_BITBAND(CORE_PIN ## P ## _DDRREG , CORE_PIN ## P ## _BIT) = 0; \ + GPIO_BITBAND(CORE_PIN ## P ## _DDRREG, CORE_PIN ## P ## _BIT) = 0; \ }while(0) #define _IS_INPUT(P) ((CORE_PIN ## P ## _DDRREG & CORE_PIN ## P ## _BITMASK) == 0) diff --git a/Marlin/src/HAL/TEENSY31_32/spi_pins.h b/Marlin/src/HAL/TEENSY31_32/spi_pins.h index 6d0d05f85a..dbd0bb9174 100644 --- a/Marlin/src/HAL/TEENSY31_32/spi_pins.h +++ b/Marlin/src/HAL/TEENSY31_32/spi_pins.h @@ -24,4 +24,3 @@ #define SD_SCK_PIN 13 #define SD_MISO_PIN 12 #define SD_MOSI_PIN 11 -#define SD_SS_PIN 20 // SDSS // A.28, A.29, B.21, C.26, C.29 diff --git a/Marlin/src/HAL/TEENSY31_32/timers.h b/Marlin/src/HAL/TEENSY31_32/timers.h index 3bbc2421e0..cdca84ec1c 100644 --- a/Marlin/src/HAL/TEENSY31_32/timers.h +++ b/Marlin/src/HAL/TEENSY31_32/timers.h @@ -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 hal_timer_t(UINT32_MAX) #define FTM0_TIMER_PRESCALE 8 #define FTM1_TIMER_PRESCALE 4 @@ -58,26 +58,25 @@ typedef uint32_t hal_timer_t; #define TEMP_TIMER_FREQUENCY 1000 -#define STEPPER_TIMER_RATE HAL_TIMER_RATE -#define STEPPER_TIMER_TICKS_PER_US ((STEPPER_TIMER_RATE) / 1000000) -#define STEPPER_TIMER_PRESCALE (CYCLES_PER_MICROSECOND / STEPPER_TIMER_TICKS_PER_US) +#define STEPPER_TIMER_RATE HAL_TIMER_RATE +#define STEPPER_TIMER_TICKS_PER_US ((STEPPER_TIMER_RATE) / 1000000UL) // (MHz) 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 -#define PULSE_TIMER_PRESCALE STEPPER_TIMER_PRESCALE -#define PULSE_TIMER_TICKS_PER_US STEPPER_TIMER_TICKS_PER_US +#define PULSE_TIMER_RATE STEPPER_TIMER_RATE // (Hz) Frequency of Pulse Timer +#define PULSE_TIMER_PRESCALE STEPPER_TIMER_PRESCALE -#define ENABLE_STEPPER_DRIVER_INTERRUPT() HAL_timer_enable_interrupt(MF_TIMER_STEP) -#define DISABLE_STEPPER_DRIVER_INTERRUPT() HAL_timer_disable_interrupt(MF_TIMER_STEP) -#define STEPPER_ISR_ENABLED() HAL_timer_interrupt_enabled(MF_TIMER_STEP) +#define ENABLE_STEPPER_DRIVER_INTERRUPT() HAL_timer_enable_interrupt(MF_TIMER_STEP) +#define DISABLE_STEPPER_DRIVER_INTERRUPT() HAL_timer_disable_interrupt(MF_TIMER_STEP) +#define STEPPER_ISR_ENABLED() HAL_timer_interrupt_enabled(MF_TIMER_STEP) -#define ENABLE_TEMPERATURE_INTERRUPT() HAL_timer_enable_interrupt(MF_TIMER_TEMP) +#define ENABLE_TEMPERATURE_INTERRUPT() HAL_timer_enable_interrupt(MF_TIMER_TEMP) #define DISABLE_TEMPERATURE_INTERRUPT() HAL_timer_disable_interrupt(MF_TIMER_TEMP) #ifndef HAL_STEP_TIMER_ISR - #define HAL_STEP_TIMER_ISR() extern "C" void ftm0_isr() //void TC3_Handler() + #define HAL_STEP_TIMER_ISR() extern "C" void ftm0_isr() #endif #ifndef HAL_TEMP_TIMER_ISR - #define HAL_TEMP_TIMER_ISR() extern "C" void ftm1_isr() //void TC4_Handler() + #define HAL_TEMP_TIMER_ISR() extern "C" void ftm1_isr() #endif void HAL_timer_start(const uint8_t timer_num, const uint32_t frequency); @@ -110,4 +109,4 @@ void HAL_timer_disable_interrupt(const uint8_t timer_num); bool HAL_timer_interrupt_enabled(const uint8_t timer_num); void HAL_timer_isr_prologue(const uint8_t timer_num); -#define HAL_timer_isr_epilogue(T) NOOP +inline void HAL_timer_isr_epilogue(const uint8_t) {} diff --git a/Marlin/src/HAL/TEENSY35_36/HAL.cpp b/Marlin/src/HAL/TEENSY35_36/HAL.cpp index bc02ac1c45..f41582be30 100644 --- a/Marlin/src/HAL/TEENSY35_36/HAL.cpp +++ b/Marlin/src/HAL/TEENSY35_36/HAL.cpp @@ -37,10 +37,21 @@ #define _IMPLEMENT_SERIAL(X) DefaultSerial##X MSerial##X(false, Serial##X) #define IMPLEMENT_SERIAL(X) _IMPLEMENT_SERIAL(X) -#if WITHIN(SERIAL_PORT, 0, 3) +#if WITHIN(SERIAL_PORT, SERIAL_INDEX_MIN, SERIAL_INDEX_MAX) IMPLEMENT_SERIAL(SERIAL_PORT); #endif - +#if defined(SERIAL_PORT_2) && WITHIN(SERIAL_PORT_2, SERIAL_INDEX_MIN, SERIAL_INDEX_MAX) + IMPLEMENT_SERIAL(SERIAL_PORT_2); +#endif +#if defined(SERIAL_PORT_3) && WITHIN(SERIAL_PORT_3, SERIAL_INDEX_MIN, SERIAL_INDEX_MAX) + IMPLEMENT_SERIAL(SERIAL_PORT_3); +#endif +#if defined(MMU_SERIAL_PORT) && WITHIN(MMU_SERIAL_PORT, SERIAL_INDEX_MIN, SERIAL_INDEX_MAX) + IMPLEMENT_SERIAL(MMU_SERIAL_PORT); +#endif +#if defined(LCD_SERIAL_PORT) && WITHIN(LCD_SERIAL_PORT, SERIAL_INDEX_MIN, SERIAL_INDEX_MAX) + IMPLEMENT_SERIAL(LCD_SERIAL_PORT); +#endif USBSerialType USBSerial(false, SerialUSB); // ------------------------ diff --git a/Marlin/src/HAL/TEENSY35_36/HAL.h b/Marlin/src/HAL/TEENSY35_36/HAL.h index 44eafe5e6d..85d02cec8c 100644 --- a/Marlin/src/HAL/TEENSY35_36/HAL.h +++ b/Marlin/src/HAL/TEENSY35_36/HAL.h @@ -70,17 +70,10 @@ typedef ForwardSerial1Class USBSerialType; extern USBSerialType USBSerial; -#define _MSERIAL(X) MSerial##X -#define MSERIAL(X) _MSERIAL(X) - -#if SERIAL_PORT == -1 - #define MYSERIAL1 USBSerial -#elif WITHIN(SERIAL_PORT, 0, 3) - #define MYSERIAL1 MSERIAL(SERIAL_PORT) - DECLARE_SERIAL(SERIAL_PORT); -#else - #error "SERIAL_PORT must be from 0 to 3, or -1 for Native USB." -#endif +#define SERIAL_INDEX_MIN 0 +#define SERIAL_INDEX_MAX 3 +#define USB_SERIAL_PORT(...) USBSerial +#include "../shared/serial_ports.h" // ------------------------ // Types @@ -154,7 +147,7 @@ public: static void delay_ms(const int ms) { delay(ms); } - // Tasks, called from idle() + // Tasks, called from marlin.idle() static void idletask() {} // Reset diff --git a/Marlin/src/HAL/TEENSY35_36/Servo.h b/Marlin/src/HAL/TEENSY35_36/Servo.h index 719011f102..c37567a813 100644 --- a/Marlin/src/HAL/TEENSY35_36/Servo.h +++ b/Marlin/src/HAL/TEENSY35_36/Servo.h @@ -35,7 +35,5 @@ class libServo : public Servo { void move(const int value); private: typedef Servo super; - uint16_t min_ticks; - uint16_t max_ticks; uint8_t servoIndex; // Index into the channel data for this servo }; diff --git a/Marlin/src/HAL/TEENSY35_36/fastio.h b/Marlin/src/HAL/TEENSY35_36/fastio.h index 622799ec8c..b582c7bfec 100644 --- a/Marlin/src/HAL/TEENSY35_36/fastio.h +++ b/Marlin/src/HAL/TEENSY35_36/fastio.h @@ -53,17 +53,17 @@ #define _SET_INPUT(P) do{ \ CORE_PIN ## P ## _CONFIG = PORT_PCR_MUX(1); \ - GPIO_BITBAND(CORE_PIN ## P ## _DDRREG , CORE_PIN ## P ## _BIT) = 0; \ + GPIO_BITBAND(CORE_PIN ## P ## _DDRREG, CORE_PIN ## P ## _BIT) = 0; \ }while(0) #define _SET_OUTPUT(P) do{ \ CORE_PIN ## P ## _CONFIG = PORT_PCR_MUX(1)|PORT_PCR_SRE|PORT_PCR_DSE; \ - GPIO_BITBAND(CORE_PIN ## P ## _DDRREG , CORE_PIN ## P ## _BIT) = 1; \ + GPIO_BITBAND(CORE_PIN ## P ## _DDRREG, CORE_PIN ## P ## _BIT) = 1; \ }while(0) #define _SET_INPUT_PULLUP(P) do{ \ CORE_PIN ## P ## _CONFIG = PORT_PCR_MUX(1) | PORT_PCR_PE | PORT_PCR_PS; \ - GPIO_BITBAND(CORE_PIN ## P ## _DDRREG , CORE_PIN ## P ## _BIT) = 0; \ + GPIO_BITBAND(CORE_PIN ## P ## _DDRREG, CORE_PIN ## P ## _BIT) = 0; \ }while(0) #define _IS_INPUT(P) ((CORE_PIN ## P ## _DDRREG & CORE_PIN ## P ## _BITMASK) == 0) diff --git a/Marlin/src/HAL/TEENSY35_36/spi_pins.h b/Marlin/src/HAL/TEENSY35_36/spi_pins.h index cfffdc9325..d898a923f5 100644 --- a/Marlin/src/HAL/TEENSY35_36/spi_pins.h +++ b/Marlin/src/HAL/TEENSY35_36/spi_pins.h @@ -28,4 +28,3 @@ #define SD_SCK_PIN 13 #define SD_MISO_PIN 12 #define SD_MOSI_PIN 11 -#define SD_SS_PIN 20 // SDSS // A.28, A.29, B.21, C.26, C.29 diff --git a/Marlin/src/HAL/TEENSY35_36/timers.h b/Marlin/src/HAL/TEENSY35_36/timers.h index 3536b62265..1a5a8460c6 100644 --- a/Marlin/src/HAL/TEENSY35_36/timers.h +++ b/Marlin/src/HAL/TEENSY35_36/timers.h @@ -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 hal_timer_t(UINT32_MAX) #define FTM0_TIMER_PRESCALE 8 #define FTM1_TIMER_PRESCALE 4 @@ -58,19 +58,18 @@ typedef uint32_t hal_timer_t; #define TEMP_TIMER_FREQUENCY 1000 -#define STEPPER_TIMER_RATE HAL_TIMER_RATE -#define STEPPER_TIMER_TICKS_PER_US ((STEPPER_TIMER_RATE) / 1000000) -#define STEPPER_TIMER_PRESCALE (CYCLES_PER_MICROSECOND / STEPPER_TIMER_TICKS_PER_US) +#define STEPPER_TIMER_RATE HAL_TIMER_RATE +#define STEPPER_TIMER_TICKS_PER_US ((STEPPER_TIMER_RATE) / 1000000UL) // (MHz) 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 -#define PULSE_TIMER_PRESCALE STEPPER_TIMER_PRESCALE -#define PULSE_TIMER_TICKS_PER_US STEPPER_TIMER_TICKS_PER_US +#define PULSE_TIMER_RATE STEPPER_TIMER_RATE // (Hz) Frequency of Pulse Timer +#define PULSE_TIMER_PRESCALE STEPPER_TIMER_PRESCALE -#define ENABLE_STEPPER_DRIVER_INTERRUPT() HAL_timer_enable_interrupt(MF_TIMER_STEP) -#define DISABLE_STEPPER_DRIVER_INTERRUPT() HAL_timer_disable_interrupt(MF_TIMER_STEP) -#define STEPPER_ISR_ENABLED() HAL_timer_interrupt_enabled(MF_TIMER_STEP) +#define ENABLE_STEPPER_DRIVER_INTERRUPT() HAL_timer_enable_interrupt(MF_TIMER_STEP) +#define DISABLE_STEPPER_DRIVER_INTERRUPT() HAL_timer_disable_interrupt(MF_TIMER_STEP) +#define STEPPER_ISR_ENABLED() HAL_timer_interrupt_enabled(MF_TIMER_STEP) -#define ENABLE_TEMPERATURE_INTERRUPT() HAL_timer_enable_interrupt(MF_TIMER_TEMP) +#define ENABLE_TEMPERATURE_INTERRUPT() HAL_timer_enable_interrupt(MF_TIMER_TEMP) #define DISABLE_TEMPERATURE_INTERRUPT() HAL_timer_disable_interrupt(MF_TIMER_TEMP) #ifndef HAL_STEP_TIMER_ISR @@ -110,4 +109,4 @@ void HAL_timer_disable_interrupt(const uint8_t timer_num); bool HAL_timer_interrupt_enabled(const uint8_t timer_num); void HAL_timer_isr_prologue(const uint8_t timer_num); -#define HAL_timer_isr_epilogue(T) NOOP +inline void HAL_timer_isr_epilogue(const uint8_t) {} diff --git a/Marlin/src/HAL/TEENSY40_41/HAL.cpp b/Marlin/src/HAL/TEENSY40_41/HAL.cpp index 4dd5c3678d..3a1f06095b 100644 --- a/Marlin/src/HAL/TEENSY40_41/HAL.cpp +++ b/Marlin/src/HAL/TEENSY40_41/HAL.cpp @@ -39,18 +39,20 @@ #define _IMPLEMENT_SERIAL(X) DefaultSerial##X MSerial##X(false, Serial##X) #define IMPLEMENT_SERIAL(X) _IMPLEMENT_SERIAL(X) -#if WITHIN(SERIAL_PORT, 0, 8) +#if WITHIN(SERIAL_PORT, SERIAL_INDEX_MIN, SERIAL_INDEX_MAX) IMPLEMENT_SERIAL(SERIAL_PORT); #endif -#ifdef SERIAL_PORT_2 - #if WITHIN(SERIAL_PORT_2, 0, 8) - IMPLEMENT_SERIAL(SERIAL_PORT_2); - #endif +#if defined(SERIAL_PORT_2) && WITHIN(SERIAL_PORT_2, SERIAL_INDEX_MIN, SERIAL_INDEX_MAX) + IMPLEMENT_SERIAL(SERIAL_PORT_2); #endif -#ifdef SERIAL_PORT_3 - #if WITHIN(SERIAL_PORT_3, 0, 8) - IMPLEMENT_SERIAL(SERIAL_PORT_3); - #endif +#if defined(SERIAL_PORT_3) && WITHIN(SERIAL_PORT_3, SERIAL_INDEX_MIN, SERIAL_INDEX_MAX) + IMPLEMENT_SERIAL(SERIAL_PORT_3); +#endif +#if defined(MMU_SERIAL_PORT) && WITHIN(MMU_SERIAL_PORT, SERIAL_INDEX_MIN, SERIAL_INDEX_MAX) + IMPLEMENT_SERIAL(MMU_SERIAL_PORT); +#endif +#if defined(LCD_SERIAL_PORT) && WITHIN(LCD_SERIAL_PORT, SERIAL_INDEX_MIN, SERIAL_INDEX_MAX) + IMPLEMENT_SERIAL(LCD_SERIAL_PORT); #endif USBSerialType USBSerial(false, SerialUSB); @@ -96,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 @@ -202,18 +204,13 @@ uint16_t MarlinHAL::adc_value() { // Free Memory Accessor // ------------------------ -#define __bss_end _ebss - extern "C" { - extern char __bss_end; - extern char __heap_start; - extern void* __brkval; + // Reference for Teensy 4.x: https://forum.pjrc.com/index.php?threads/how-to-display-free-ram.33443/#post-275013 + extern unsigned long _heap_end; + extern char *__brkval; - // Doesn't work on Teensy 4.x uint32_t freeMemory() { - uint32_t free_memory; - free_memory = ((uint32_t)&free_memory) - (((uint32_t)__brkval) ?: ((uint32_t)&__bss_end)); - return free_memory; + return (char *)&_heap_end - __brkval; } } diff --git a/Marlin/src/HAL/TEENSY40_41/HAL.h b/Marlin/src/HAL/TEENSY40_41/HAL.h index 355d1d75ac..fc75539e9b 100644 --- a/Marlin/src/HAL/TEENSY40_41/HAL.h +++ b/Marlin/src/HAL/TEENSY40_41/HAL.h @@ -61,6 +61,8 @@ #undef PSTR #define PSTR(str) ({static const char *data = (str); &data[0];}) +#define HAL_CAN_SET_PWM_FREQ + // ------------------------ // Serial ports // ------------------------ @@ -76,41 +78,11 @@ typedef ForwardSerial1Class USBSerialType; extern USBSerialType USBSerial; -#define _MSERIAL(X) MSerial##X -#define MSERIAL(X) _MSERIAL(X) - -#if SERIAL_PORT == -1 - #define MYSERIAL1 USBSerial -#elif WITHIN(SERIAL_PORT, 0, 8) - DECLARE_SERIAL(SERIAL_PORT); - #define MYSERIAL1 MSERIAL(SERIAL_PORT) -#else - #error "The required SERIAL_PORT must be from 0 to 8, or -1 for Native USB." -#endif - -#ifdef SERIAL_PORT_2 - #if SERIAL_PORT_2 == -1 - #define MYSERIAL2 USBSerial - #elif SERIAL_PORT_2 == -2 - #define MYSERIAL2 ethernet.telnetClient - #elif WITHIN(SERIAL_PORT_2, 0, 8) - DECLARE_SERIAL(SERIAL_PORT_2); - #define MYSERIAL2 MSERIAL(SERIAL_PORT_2) - #else - #error "SERIAL_PORT_2 must be from 0 to 8, or -1 for Native USB, or -2 for Ethernet." - #endif -#endif - -#ifdef SERIAL_PORT_3 - #if SERIAL_PORT_3 == -1 - #define MYSERIAL3 USBSerial - #elif WITHIN(SERIAL_PORT_3, 0, 8) - DECLARE_SERIAL(SERIAL_PORT_3); - #define MYSERIAL3 MSERIAL(SERIAL_PORT_3) - #else - #error "SERIAL_PORT_3 must be from 0 to 8, or -1 for Native USB." - #endif -#endif +#define SERIAL_INDEX_MIN 0 +#define SERIAL_INDEX_MAX 8 +#define USB_SERIAL_PORT(...) USBSerial +#define ETH_SERIAL_PORT(...) ethernet.telnetClient +#include "../shared/serial_ports.h" // ------------------------ // Types @@ -188,7 +160,7 @@ public: static void delay_ms(const int ms) { delay(ms); } - // Tasks, called from idle() + // Tasks, called from marlin.idle() static void idletask() {} // Reset @@ -221,11 +193,15 @@ public: /** * Set the PWM duty cycle for the pin to the given value. - * No option to invert the duty cycle [default = false] - * No option to change the scale of the provided value to enable finer PWM duty control [default = 255] + * Optionally invert the duty cycle [default = false] + * Optionally change the scale of the provided value to enable finer PWM duty control [default = 255] */ - static void set_pwm_duty(const pin_t pin, const uint16_t v, const uint16_t=255, const bool=false) { - analogWrite(pin, v); - } + static void set_pwm_duty(const pin_t pin, const uint16_t v, const uint16_t v_size=255, const bool invert=false); + /** + * Set the PWM output frequency. This may affect multiple pins, though + * Teensy 4.x provides many timers affecting only a single pin. + * See: https://www.pjrc.com/teensy/td_pulse.html + */ + static void set_pwm_frequency(const pin_t pin, const uint16_t f_desired); }; diff --git a/Marlin/src/HAL/TEENSY40_41/Servo.h b/Marlin/src/HAL/TEENSY40_41/Servo.h index 699fd700c9..fceb9465ea 100644 --- a/Marlin/src/HAL/TEENSY40_41/Servo.h +++ b/Marlin/src/HAL/TEENSY40_41/Servo.h @@ -37,7 +37,5 @@ class libServo : public PWMServo { private: typedef PWMServo super; uint8_t servoPin; - uint16_t min_ticks; - uint16_t max_ticks; uint8_t servoIndex; // Index into the channel data for this servo }; diff --git a/Marlin/src/HAL/TEENSY40_41/fast_pwm.cpp b/Marlin/src/HAL/TEENSY40_41/fast_pwm.cpp new file mode 100644 index 0000000000..21531d115d --- /dev/null +++ b/Marlin/src/HAL/TEENSY40_41/fast_pwm.cpp @@ -0,0 +1,54 @@ +/** + * 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 . + * + */ + +#ifdef __IMXRT1062__ + +#include "../../inc/MarlinConfig.h" + +#include "HAL.h" + +void MarlinHAL::set_pwm_duty(const pin_t pin, const uint16_t v, const uint16_t v_size /*=255*/, const bool invert) { + + uint32_t bits = 1; + uint16_t value = _MIN(v, v_size); + + if (invert) value = v_size - value; + + // Choose scale as smallest power of 2 which holds v_size. + uint32_t scale = 1; + while (scale < v_size) { + bits++; + scale *= 2; + } + + uint32_t scaled_val = scale * value / v_size; + + uint32_t prior = analogWriteResolution(bits); + analogWrite(pin, scaled_val); + analogWriteResolution(prior); +} + +void MarlinHAL::set_pwm_frequency(const pin_t pin, const uint16_t f_desired) { + analogWriteFrequency(pin, f_desired); +} + +#endif // __IMXRT1062__ diff --git a/Marlin/src/HAL/TEENSY40_41/inc/SanityCheck.h b/Marlin/src/HAL/TEENSY40_41/inc/SanityCheck.h index 731658b4a3..7b1c466f23 100644 --- a/Marlin/src/HAL/TEENSY40_41/inc/SanityCheck.h +++ b/Marlin/src/HAL/TEENSY40_41/inc/SanityCheck.h @@ -33,10 +33,6 @@ #error "EMERGENCY_PARSER is not yet implemented for Teensy 4.0/4.1. Disable EMERGENCY_PARSER to continue." #endif -#if ENABLED(FAST_PWM_FAN) || SPINDLE_LASER_FREQUENCY - #error "Features requiring Hardware PWM (FAST_PWM_FAN, SPINDLE_LASER_FREQUENCY) are not yet supported for Teensy 4.0/4.1." -#endif - #if HAS_TMC_SW_SERIAL #error "TMC220x Software Serial is not supported for Teensy 4.0/4.1." #endif @@ -44,3 +40,19 @@ #if ENABLED(POSTMORTEM_DEBUGGING) #error "POSTMORTEM_DEBUGGING is not yet supported for Teensy 4.0/4.1." #endif + +#if ENABLED(SERIAL_STATS_MAX_RX_QUEUED) || ENABLED(SERIAL_STATS_DROPPED_RX) || ENABLED(SERIAL_STATS_RX_FRAMING_ERRORS) || ENABLED(SERIAL_STATS_RX_BUFFER_OVERRUNS) + #error "SERIAL_STATS_* features not supported on Teensy 4.0/4.1." +#endif + +#if ENABLED(BAUD_RATE_GCODE) && SERIAL_PORT_2 == -2 + #error "BAUD_RATE_GCODE cannot be enabled when using the Ethernet serial port." +#endif + +#if ENABLED(SPINDLE_LASER_USE_PWM) && !ENABLED(SILENCE_TEENSY_SPINDLE_LASER_WARNING) + #warning "SPINDLE_LASER_USE_PWM is untested on Teensy 4.0/4.1, see https://www.pjrc.com/teensy/td_pulse.html for details on frequencies, and resolution. #define SILENCE_TEENSY_SPINDLE_LASER_WARNING to silence warning." +#endif + +#if ENABLED(FAST_PWM_FAN) && FAST_PWM_FAN_FREQUENCY == 1000U + #warning "FAST_PWM_FAN_FREQUENCY has been left as default, see https://www.pjrc.com/teensy/td_pulse.html and consider raising it to reduce noise." +#endif diff --git a/Marlin/src/HAL/TEENSY40_41/spi_pins.h b/Marlin/src/HAL/TEENSY40_41/spi_pins.h index ba4a2c700a..fc1c2a7fed 100644 --- a/Marlin/src/HAL/TEENSY40_41/spi_pins.h +++ b/Marlin/src/HAL/TEENSY40_41/spi_pins.h @@ -28,4 +28,3 @@ #define SD_SCK_PIN 13 #define SD_MISO_PIN 12 #define SD_MOSI_PIN 11 -#define SD_SS_PIN 20 // SDSS // A.28, A.29, B.21, C.26, C.29 diff --git a/Marlin/src/HAL/TEENSY40_41/timers.cpp b/Marlin/src/HAL/TEENSY40_41/timers.cpp index ed99f65d6e..011f9fe31c 100644 --- a/Marlin/src/HAL/TEENSY40_41/timers.cpp +++ b/Marlin/src/HAL/TEENSY40_41/timers.cpp @@ -30,41 +30,82 @@ void HAL_timer_start(const uint8_t timer_num, const uint32_t frequency) { switch (timer_num) { + + // + // Step Timer – GPT1 - Compare Interrupt OCR1 - Reset Mode + // case MF_TIMER_STEP: - CCM_CSCMR1 &= ~CCM_CSCMR1_PERCLK_CLK_SEL; // turn off 24mhz mode + // 24MHz mode off – Use peripheral clock (150MHz) + CCM_CSCMR1 &= ~CCM_CSCMR1_PERCLK_CLK_SEL; + // Enable GPT1 clock gating CCM_CCGR1 |= CCM_CCGR1_GPT1_BUS(CCM_CCGR_ON); - GPT1_CR = 0; // disable timer - GPT1_SR = 0x3F; // clear all prior status - GPT1_PR = GPT1_TIMER_PRESCALE - 1; - GPT1_CR |= GPT_CR_CLKSRC(1); //clock selection #1 (peripheral clock = 150 MHz) - GPT1_CR |= GPT_CR_ENMOD; //reset count to zero before enabling - GPT1_CR |= GPT_CR_OM1(1); // toggle mode - GPT1_OCR1 = (GPT1_TIMER_RATE / frequency) -1; // Initial compare value - GPT1_IR = GPT_IR_OF1IE; // Compare3 value - GPT1_CR |= GPT_CR_EN; //enable GPT2 counting at 150 MHz + // Disable timer, clear all status bits + GPT1_CR = 0; // Disable timer + GPT1_SR = 0x3F; // Clear all prior status - OUT_WRITE(15, HIGH); + // Prescaler = 2 => 75MHz counting clock + GPT1_PR = GPT1_TIMER_PRESCALE - 1; + + GPT1_CR = GPT_CR_CLKSRC(1) // Clock selection #1 (peripheral clock = 150 MHz) + | GPT_CR_ENMOD // Reset count to zero before enabling + | GPT_CR_OM2(TERN(MARLIN_DEV_MODE, 1, 0)); // 0 = edge compare, 1 = toggle + + // Compare value – the number of clocks between edges + GPT1_OCR1 = (GPT1_TIMER_RATE / frequency) - 1; + + // Enable compare‑event interrupt + GPT1_IR = GPT_IR_OF1IE; // OF1 interrupt enabled + + // Pull Pin 15 HIGH (logic‑high is the “idle” state) + TERN_(MARLIN_DEV_MODE, OUT_WRITE(15, HIGH)); + + // Attach and enable Stepper IRQ + // Note: UART priority is 16 attachInterruptVector(IRQ_GPT1, &stepTC_Handler); - NVIC_SET_PRIORITY(IRQ_GPT1, 16); + NVIC_SET_PRIORITY(IRQ_GPT1, 16); // Priority 16 (higher than Temp Timer) + + // Start GPT1 counting at 150 MHz + GPT1_CR |= GPT_CR_EN; + break; + + // + // Temperature Timer – GPT2 - Compare Interrupt OCR1 - Reset Mode + // case MF_TIMER_TEMP: - CCM_CSCMR1 &= ~CCM_CSCMR1_PERCLK_CLK_SEL; // turn off 24mhz mode + // 24MHz mode off – Use peripheral clock (150MHz) + CCM_CSCMR1 &= ~CCM_CSCMR1_PERCLK_CLK_SEL; + // Enable GPT2 clock gating CCM_CCGR0 |= CCM_CCGR0_GPT2_BUS(CCM_CCGR_ON); - GPT2_CR = 0; // disable timer - GPT2_SR = 0x3F; // clear all prior status - GPT2_PR = GPT2_TIMER_PRESCALE - 1; - GPT2_CR |= GPT_CR_CLKSRC(1); //clock selection #1 (peripheral clock = 150 MHz) - GPT2_CR |= GPT_CR_ENMOD; //reset count to zero before enabling - GPT2_CR |= GPT_CR_OM1(1); // toggle mode - GPT2_OCR1 = (GPT2_TIMER_RATE / frequency) -1; // Initial compare value - GPT2_IR = GPT_IR_OF1IE; // Compare3 value - GPT2_CR |= GPT_CR_EN; //enable GPT2 counting at 150 MHz + // Disable timer, clear all status bits + GPT2_CR = 0; // Disable timer + GPT2_SR = 0x3F; // Clear all prior status - OUT_WRITE(14, HIGH); + // Prescaler = 10 => 15MHz counting clock + GPT2_PR = GPT2_TIMER_PRESCALE - 1; + + GPT2_CR = GPT_CR_CLKSRC(1) // Clock selection #1 (peripheral clock = 150 MHz) + | GPT_CR_ENMOD // and reset count to zero before enabling + | GPT_CR_OM2(TERN(MARLIN_DEV_MODE, 1, 0)); // 0 = edge compare, 1 = toggle + + // Compare value – the number of clocks between edges + GPT2_OCR1 = (GPT2_TIMER_RATE / frequency) - 1; + + // Enable compare‑event interrupt + GPT2_IR = GPT_IR_OF1IE; // OF1 interrupt enabled + + // Pull Pin 14 HIGH (logic‑high is the “idle” state) + TERN_(MARLIN_DEV_MODE, OUT_WRITE(14, HIGH)); + + // Attach Temperature ISR attachInterruptVector(IRQ_GPT2, &tempTC_Handler); - NVIC_SET_PRIORITY(IRQ_GPT2, 32); + NVIC_SET_PRIORITY(IRQ_GPT2, 32); // Priority 32 (lower than Step Timer) + + // Start GPT2 counting at 150 MHz + GPT2_CR |= GPT_CR_EN; + break; } } @@ -82,6 +123,7 @@ void HAL_timer_disable_interrupt(const uint8_t timer_num) { case MF_TIMER_TEMP: NVIC_DISABLE_IRQ(IRQ_GPT2); break; } + // Ensure the CPU actually stops servicing the IRQ // We NEED memory barriers to ensure Interrupts are actually disabled! // ( https://dzone.com/articles/nvic-disabling-interrupts-on-arm-cortex-m-and-the ) asm volatile("dsb"); @@ -97,8 +139,8 @@ bool HAL_timer_interrupt_enabled(const uint8_t timer_num) { void HAL_timer_isr_prologue(const uint8_t timer_num) { switch (timer_num) { - case MF_TIMER_STEP: GPT1_SR = GPT_IR_OF1IE; break; // clear OF3 bit - case MF_TIMER_TEMP: GPT2_SR = GPT_IR_OF1IE; break; // clear OF3 bit + case MF_TIMER_STEP: GPT1_SR = GPT_IR_OF1IE; break; // clear OF1 + case MF_TIMER_TEMP: GPT2_SR = GPT_IR_OF1IE; break; } asm volatile("dsb"); } diff --git a/Marlin/src/HAL/TEENSY40_41/timers.h b/Marlin/src/HAL/TEENSY40_41/timers.h index fc160ab8b8..66d00b1788 100644 --- a/Marlin/src/HAL/TEENSY40_41/timers.h +++ b/Marlin/src/HAL/TEENSY40_41/timers.h @@ -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 hal_timer_t(UINT32_MAX-1UL) #define GPT_TIMER_RATE (F_CPU / 4) // 150MHz (Can't use F_BUS_ACTUAL because it's extern volatile) @@ -57,20 +57,19 @@ typedef uint32_t hal_timer_t; #define TEMP_TIMER_RATE 1000000 #define TEMP_TIMER_FREQUENCY 1000 -#define HAL_TIMER_RATE GPT1_TIMER_RATE -#define STEPPER_TIMER_RATE HAL_TIMER_RATE -#define STEPPER_TIMER_TICKS_PER_US ((STEPPER_TIMER_RATE) / 1000000) -#define STEPPER_TIMER_PRESCALE ((GPT_TIMER_RATE / 1000000) / STEPPER_TIMER_TICKS_PER_US) +#define HAL_TIMER_RATE GPT1_TIMER_RATE +#define STEPPER_TIMER_RATE HAL_TIMER_RATE +#define STEPPER_TIMER_TICKS_PER_US ((STEPPER_TIMER_RATE) / 1000000UL) +#define STEPPER_TIMER_PRESCALE (GPT_TIMER_RATE / STEPPER_TIMER_RATE) -#define PULSE_TIMER_RATE STEPPER_TIMER_RATE // frequency of pulse timer -#define PULSE_TIMER_PRESCALE STEPPER_TIMER_PRESCALE -#define PULSE_TIMER_TICKS_PER_US STEPPER_TIMER_TICKS_PER_US +#define PULSE_TIMER_RATE STEPPER_TIMER_RATE // (Hz) Frequency of Pulse Timer +#define PULSE_TIMER_PRESCALE STEPPER_TIMER_PRESCALE -#define ENABLE_STEPPER_DRIVER_INTERRUPT() HAL_timer_enable_interrupt(MF_TIMER_STEP) -#define DISABLE_STEPPER_DRIVER_INTERRUPT() HAL_timer_disable_interrupt(MF_TIMER_STEP) -#define STEPPER_ISR_ENABLED() HAL_timer_interrupt_enabled(MF_TIMER_STEP) +#define ENABLE_STEPPER_DRIVER_INTERRUPT() HAL_timer_enable_interrupt(MF_TIMER_STEP) +#define DISABLE_STEPPER_DRIVER_INTERRUPT() HAL_timer_disable_interrupt(MF_TIMER_STEP) +#define STEPPER_ISR_ENABLED() HAL_timer_interrupt_enabled(MF_TIMER_STEP) -#define ENABLE_TEMPERATURE_INTERRUPT() HAL_timer_enable_interrupt(MF_TIMER_TEMP) +#define ENABLE_TEMPERATURE_INTERRUPT() HAL_timer_enable_interrupt(MF_TIMER_TEMP) #define DISABLE_TEMPERATURE_INTERRUPT() HAL_timer_disable_interrupt(MF_TIMER_TEMP) #ifndef HAL_STEP_TIMER_ISR @@ -89,8 +88,16 @@ void HAL_timer_start(const uint8_t timer_num, const uint32_t frequency); FORCE_INLINE static void HAL_timer_set_compare(const uint8_t timer_num, const hal_timer_t compare) { switch (timer_num) { - case MF_TIMER_STEP: GPT1_OCR1 = compare - 1; break; - case MF_TIMER_TEMP: GPT2_OCR1 = compare - 1; break; + case MF_TIMER_STEP: + GPT1_CR |= GPT_CR_FRR; // Free Run Mode (setting OCRx preserves CNT) + GPT1_OCR1 = compare - 1; + GPT1_CR &= ~GPT_CR_FRR; // Reset Mode (CNT resets on trigger) + break; + case MF_TIMER_TEMP: + GPT2_CR |= GPT_CR_FRR; // Free Run Mode (setting OCRx preserves CNT) + GPT2_OCR1 = compare - 1; + GPT2_CR &= ~GPT_CR_FRR; // Reset Mode (CNT resets on trigger) + break; } } @@ -115,5 +122,4 @@ void HAL_timer_disable_interrupt(const uint8_t timer_num); bool HAL_timer_interrupt_enabled(const uint8_t timer_num); void HAL_timer_isr_prologue(const uint8_t timer_num); -//void HAL_timer_isr_epilogue(const uint8_t timer_num) {} -#define HAL_timer_isr_epilogue(T) NOOP +inline void HAL_timer_isr_epilogue(const uint8_t) {} diff --git a/Marlin/src/HAL/platforms.h b/Marlin/src/HAL/platforms.h index 36fb792776..e7eea44308 100644 --- a/Marlin/src/HAL/platforms.h +++ b/Marlin/src/HAL/platforms.h @@ -37,6 +37,8 @@ #define HAL_PATH(PATH, NAME) XSTR(PATH/HAL/LPC1768/NAME) #elif defined(ARDUINO_ARCH_HC32) #define HAL_PATH(PATH, NAME) XSTR(PATH/HAL/HC32/NAME) +#elif defined(ARDUINO_ARCH_MFL) + #define HAL_PATH(PATH, NAME) XSTR(PATH/HAL/GD32_MFL/NAME) #elif defined(__STM32F1__) || defined(TARGET_STM32F1) #define HAL_PATH(PATH, NAME) XSTR(PATH/HAL/STM32F1/NAME) #elif defined(ARDUINO_ARCH_STM32) diff --git a/Marlin/src/HAL/shared/Delay.h b/Marlin/src/HAL/shared/Delay.h index a6795a78ea..eeaf4c59fc 100644 --- a/Marlin/src/HAL/shared/Delay.h +++ b/Marlin/src/HAL/shared/Delay.h @@ -100,7 +100,7 @@ void calibrate_delay_loop(); // For delay in microseconds, no smart delay selection is required, directly call the delay function // Teensy compiler is too old and does not accept smart delay compile-time / run-time selection correctly - #define DELAY_US(x) DelayCycleFnc((x) * ((F_CPU) / 1000000UL)) + #define DELAY_US(x) DelayCycleFnc((unsigned long)(x) * ((F_CPU) / 1000000UL)) #elif defined(__AVR__) FORCE_INLINE static void __delay_up_to_3c(uint8_t cycles) { @@ -164,7 +164,7 @@ void calibrate_delay_loop(); } // Delay in microseconds - #define DELAY_US(x) DELAY_CYCLES((x) * ((F_CPU) / 1000000UL)) + #define DELAY_US(x) DELAY_CYCLES((unsigned long)(x) * ((F_CPU) / 1000000UL)) #define DELAY_CYCLES_VAR DELAY_CYCLES @@ -173,7 +173,10 @@ void calibrate_delay_loop(); // DELAY_CYCLES specified inside platform // Delay in microseconds - #define DELAY_US(x) DELAY_CYCLES((x) * ((F_CPU) / 1000000UL)) + #define DELAY_US(x) DELAY_CYCLES((unsigned long)(x) * ((F_CPU) / 1000000UL)) + + #define DELAY_CYCLES_VAR DELAY_CYCLES + #else #error "Unsupported MCU architecture" diff --git a/Marlin/src/HAL/shared/backtrace/unwarm.h b/Marlin/src/HAL/shared/backtrace/unwarm.h index 72ea0b0627..8e432ebe77 100644 --- a/Marlin/src/HAL/shared/backtrace/unwarm.h +++ b/Marlin/src/HAL/shared/backtrace/unwarm.h @@ -15,7 +15,7 @@ #include "unwinder.h" -/** The maximum number of instructions to interpet in a function. +/** The maximum number of instructions to interpret in a function. * Unwinding will be unconditionally stopped and UNWIND_EXHAUSTED returned * if more than this number of instructions are interpreted in a single * function without unwinding a stack frame. This prevents infinite loops diff --git a/Marlin/src/HAL/shared/backtrace/unwarm_arm.cpp b/Marlin/src/HAL/shared/backtrace/unwarm_arm.cpp index decf74e6e9..e6064f65da 100644 --- a/Marlin/src/HAL/shared/backtrace/unwarm_arm.cpp +++ b/Marlin/src/HAL/shared/backtrace/unwarm_arm.cpp @@ -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 { diff --git a/Marlin/src/HAL/shared/math_32bit.h b/Marlin/src/HAL/shared/math_32bit.h index 1fb233e3e8..daf82e0650 100644 --- a/Marlin/src/HAL/shared/math_32bit.h +++ b/Marlin/src/HAL/shared/math_32bit.h @@ -22,6 +22,7 @@ #pragma once #include "../../core/macros.h" +#include /** * Math helper functions for 32 bit CPUs diff --git a/Marlin/src/HAL/shared/progmem.h b/Marlin/src/HAL/shared/progmem.h index 4cd7663df9..b3bd5c32fd 100644 --- a/Marlin/src/HAL/shared/progmem.h +++ b/Marlin/src/HAL/shared/progmem.h @@ -39,7 +39,7 @@ #endif #ifndef F class __FlashStringHelper; -#define F(str) (reinterpret_cast(PSTR(str))) +#define F(string_literal) (reinterpret_cast(PSTR(string_literal))) #endif #ifndef _SFR_BYTE #define _SFR_BYTE(n) (n) diff --git a/Marlin/src/HAL/shared/serial_ports.h b/Marlin/src/HAL/shared/serial_ports.h new file mode 100644 index 0000000000..2daeea34e3 --- /dev/null +++ b/Marlin/src/HAL/shared/serial_ports.h @@ -0,0 +1,178 @@ +/** + * 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 . + * + */ +#pragma once + +/** + * serial_ports.h - Define Marlin serial port macros and optionally declare ports + * + * This header defines one or more of the serial ports... + * - MYSERIAL1/2/3 ..... for host devices + * - MMU_SERIAL ........ for Multi-Material color changers + * - LCD_SERIAL ........ for serial LCDs + * - RS485_SERIAL ...... for CAN bus devices + * + * Before including this header define the following macros: + * - SERIAL_INDEX_MIN, SERIAL_INDEX_MAX to provide the valid range of serial port indexes. + * - _MSERIAL(X) and MSERIAL(X) to provide the instance name of Serial Port X. (Default: MSerial##X) + * - EP_SERIAL_PORT(X) to provide the instance name of Emergency Parser serial port X (if it is special). + * - USB_SERIAL_PORT(X) to provide the instance name of the USB serial port (if any). + * - ETH_SERIAL_PORT(X) to provide the instance name of the Ethernet serial port (if any). + * - DECLARE_SERIAL(X) to declare standard a serial port with the given index. + */ + +#ifndef _MSERIAL + #define _MSERIAL(X) MSerial##X +#endif +#ifndef MSERIAL + #define MSERIAL(X) _MSERIAL(X) +#endif + +#define INDEX_RANGE_MSG " must be from " STRINGIFY(SERIAL_INDEX_MIN) " to " STRINGIFY(SERIAL_INDEX_MAX) +#if defined(USB_SERIAL_PORT) && defined(ETH_SERIAL_PORT) + #define MORE_INDEXES_MSG ", -1 for Native USB, or -2 for Ethernet" +#elif defined(USB_SERIAL_PORT) + #define MORE_INDEXES_MSG ", or -1 for Native USB" +#elif defined(ETH_SERIAL_PORT) + #define MORE_INDEXES_MSG ", or -2 for Ethernet" +#else + #define MORE_INDEXES_MSG +#endif + +// +// SERIAL_PORT => MYSERIAL1 +// + +#if defined(EP_SERIAL_PORT) && ENABLED(EMERGENCY_PARSER) + #define MYSERIAL1 EP_SERIAL_PORT(1) +#elif WITHIN(SERIAL_PORT, SERIAL_INDEX_MIN, SERIAL_INDEX_MAX) + #define MYSERIAL1 MSERIAL(SERIAL_PORT) + #ifdef DECLARE_SERIAL + DECLARE_SERIAL(SERIAL_PORT); + #endif +#elif SERIAL_PORT == -1 && defined(USB_SERIAL_PORT) + #define MYSERIAL1 USB_SERIAL_PORT(1) +#elif SERIAL_PORT == -2 && defined(ETH_SERIAL_PORT) + #define MYSERIAL1 ETH_SERIAL_PORT(1) +#endif +#ifndef MYSERIAL1 + static_assert(false, "SERIAL_PORT" INDEX_RANGE_MSG MORE_INDEXES_MSG "."); + #define MYSERIAL1 _MSERIAL(1) // Dummy port +#endif + +// +// SERIAL_PORT_2 => MYSERIAL2 +// + +#ifdef SERIAL_PORT_2 + #if defined(EP_SERIAL_PORT) && ENABLED(EMERGENCY_PARSER) + #define MYSERIAL2 EP_SERIAL_PORT(2) + #elif WITHIN(SERIAL_PORT_2, SERIAL_INDEX_MIN, SERIAL_INDEX_MAX) + #define MYSERIAL2 MSERIAL(SERIAL_PORT_2) + #ifdef DECLARE_SERIAL + DECLARE_SERIAL(SERIAL_PORT_2); + #endif + #elif SERIAL_PORT_2 == -1 && defined(USB_SERIAL_PORT) + #define MYSERIAL2 USB_SERIAL_PORT(2) + #elif SERIAL_PORT_2 == -2 && defined(ETH_SERIAL_PORT) + #define MYSERIAL2 ETH_SERIAL_PORT(2) + #endif + #ifndef MYSERIAL2 + static_assert(false, "SERIAL_PORT_2" INDEX_RANGE_MSG MORE_INDEXES_MSG "."); + #define MYSERIAL2 _MSERIAL(1) // Dummy port + #endif +#endif + +// +// SERIAL_PORT_3 => MYSERIAL3 +// + +#ifdef SERIAL_PORT_3 + #if defined(EP_SERIAL_PORT) && ENABLED(EMERGENCY_PARSER) + #define MYSERIAL3 EP_SERIAL_PORT(3) + #elif WITHIN(SERIAL_PORT_3, SERIAL_INDEX_MIN, SERIAL_INDEX_MAX) + #define MYSERIAL3 MSERIAL(SERIAL_PORT_3) + #ifdef DECLARE_SERIAL + DECLARE_SERIAL(SERIAL_PORT_3); + #endif + #elif SERIAL_PORT_3 == -1 && defined(USB_SERIAL_PORT) + #define MYSERIAL3 USB_SERIAL_PORT(3) + #elif SERIAL_PORT_3 == -2 && defined(ETH_SERIAL_PORT) + #define MYSERIAL3 ETH_SERIAL_PORT(3) + #endif + #ifndef MYSERIAL3 + static_assert(false, "SERIAL_PORT_3" INDEX_RANGE_MSG MORE_INDEXES_MSG "."); + #define MYSERIAL3 _MSERIAL(1) // Dummy port + #endif +#endif + +// +// MMU_SERIAL_PORT => MMU_SERIAL +// + +#ifdef MMU_SERIAL_PORT + #if WITHIN(MMU_SERIAL_PORT, SERIAL_INDEX_MIN, SERIAL_INDEX_MAX) + #define MMU_SERIAL MSERIAL(MMU_SERIAL_PORT) + #ifdef DECLARE_SERIAL + DECLARE_SERIAL(MMU_SERIAL_PORT); + #endif + #else + static_assert(false, "MMU_SERIAL_PORT" INDEX_RANGE_MSG "."); + #define MMU_SERIAL _MSERIAL(1) // Dummy port + #endif +#endif + +// +// LCD_SERIAL_PORT => LCD_SERIAL +// + +#ifdef LCD_SERIAL_PORT + #if WITHIN(LCD_SERIAL_PORT, SERIAL_INDEX_MIN, SERIAL_INDEX_MAX) + #define LCD_SERIAL MSERIAL(LCD_SERIAL_PORT) + #ifdef DECLARE_SERIAL + DECLARE_SERIAL(LCD_SERIAL_PORT); + #endif + #else + static_assert(false, "LCD_SERIAL_PORT" INDEX_RANGE_MSG "."); + #define LCD_SERIAL _MSERIAL(1) // Dummy port + #endif +#endif + +// +// RS485_SERIAL_PORT => RS485_SERIAL +// + +#ifdef RS485_SERIAL_PORT + #if WITHIN(RS485_SERIAL_PORT, SERIAL_INDEX_MIN, SERIAL_INDEX_MAX) + #define RS485_SERIAL MSERIAL(RS485_SERIAL_PORT) + #ifdef DECLARE_SERIAL + DECLARE_SERIAL(RS485_SERIAL_PORT); + #endif + #else + static_assert(false, "RS485_SERIAL_PORT" INDEX_RANGE_MSG "."); + #define RS485_SERIAL _MSERIAL(1) // Dummy port + #endif +#endif + +#undef DECLARE_SERIAL +#undef SERIAL_INDEX_MIN +#undef SERIAL_INDEX_MAX +#undef INDEX_RANGE_MSG diff --git a/Marlin/src/HAL/shared/servo.h b/Marlin/src/HAL/shared/servo.h index fa75445ed7..85e645146c 100644 --- a/Marlin/src/HAL/shared/servo.h +++ b/Marlin/src/HAL/shared/servo.h @@ -59,7 +59,7 @@ * write() - Sets the servo angle in degrees. (invalid angle that is valid as pulse in microseconds is treated as microseconds) * writeMicroseconds() - Sets the servo pulse width in microseconds * read() - Gets the last written servo pulse width as an angle between 0 and 180. - * readMicroseconds() - Gets the last written servo pulse width in microseconds. (was read_us() in first release) + * readMicroseconds() - Gets the last written servo pulse width in microseconds. * attached() - Returns true if there is a servo attached. * detach() - Stops an attached servos from pulsing its i/o pin. * move(angle) - Sequence of attach(0), write(angle), @@ -76,6 +76,8 @@ #include "../LPC1768/Servo.h" #elif defined(ARDUINO_ARCH_HC32) #include "../HC32/Servo.h" +#elif defined(ARDUINO_ARCH_MFL) + #include "../GD32_MFL/Servo.h" #elif defined(__STM32F1__) || defined(TARGET_STM32F1) #include "../STM32F1/Servo.h" #elif defined(ARDUINO_ARCH_STM32) @@ -84,6 +86,8 @@ #include "../ESP32/Servo.h" #elif defined(__PLAT_RP2040__) #include "../RP2040/Servo.h" +#elif defined(__PLAT_NATIVE_SIM__) + #include "../NATIVE_SIM/Servo.h" #else #include @@ -98,22 +102,22 @@ class Servo { public: Servo(); - int8_t attach(const int pin); // attach the given pin to the next free channel, set pinMode, return channel number (-1 on fail) - int8_t attach(const int pin, const int min, const int max); // as above but also sets min and max values for writes. + int8_t attach(const int pin); // Attach the given pin to the next free channel, set pinMode, return channel number (-1 on fail) + int8_t attach(const int pin, const int min, const int max); // As above but also set min and max values for writes. void detach(); - void write(int value); // if value is < 200 it is treated as an angle, otherwise as pulse width in microseconds - void writeMicroseconds(int value); // write pulse width in microseconds - void move(const int value); // attach the servo, then move to value - // if value is < 200 it is treated as an angle, otherwise as pulse width in microseconds - // if DEACTIVATE_SERVOS_AFTER_MOVE wait SERVO_DELAY, then detach - int read(); // returns current pulse width as an angle between 0 and 180 degrees - int readMicroseconds(); // returns current pulse width in microseconds for this servo (was read_us() in first release) - bool attached(); // return true if this servo is attached, otherwise false + void write(int value); // If value is < 200 it is treated as an angle, otherwise as pulse width in microseconds + void writeMicroseconds(int value); // Write pulse width in microseconds + void move(const int value); // Attach the servo, then move to value + // If value is < 200 it is treated as an angle, otherwise as pulse width in microseconds + // If DEACTIVATE_SERVOS_AFTER_MOVE wait SERVO_DELAY, then detach + int read(); // Return current pulse width as an angle between 0 and 180 degrees + int readMicroseconds(); // Return current pulse width in microseconds for this servo + bool attached(); // Return true if this servo is attached, otherwise false private: - uint8_t servoIndex; // index into the channel data for this servo - int8_t min; // minimum is this value times 4 added to MIN_PULSE_WIDTH - int8_t max; // maximum is this value times 4 added to MAX_PULSE_WIDTH + uint8_t servoIndex; // Index into the channel data for this servo + int8_t min; // Minimum is this value times 4 added to MIN_PULSE_WIDTH + int8_t max; // Maximum is this value times 4 added to MAX_PULSE_WIDTH }; #endif diff --git a/Marlin/src/MarlinCore.cpp b/Marlin/src/MarlinCore.cpp index 2ed271d531..29a6b9e4ea 100644 --- a/Marlin/src/MarlinCore.cpp +++ b/Marlin/src/MarlinCore.cpp @@ -74,11 +74,11 @@ #endif #if HAS_DWIN_E3V2 - #include "lcd/e3v2/common/encoder.h" + #include "lcd/dwin/common/encoder.h" #if ENABLED(DWIN_CREALITY_LCD) - #include "lcd/e3v2/creality/dwin.h" + #include "lcd/dwin/creality/dwin.h" #elif ENABLED(DWIN_CREALITY_LCD_JYERSUI) - #include "lcd/e3v2/jyersui/dwin.h" + #include "lcd/dwin/jyersui/dwin.h" #elif ENABLED(SOVOL_SV06_RTS) #include "lcd/sovol_rts/sovol_rts.h" #endif @@ -152,23 +152,14 @@ #include "feature/encoder_i2c.h" #endif -#if (HAS_TRINAMIC_CONFIG || HAS_TMC_SPI) && DISABLED(PSU_DEFAULT_OFF) - #include "feature/tmc_util.h" +#if HAS_TRINAMIC_CONFIG + #include "module/stepper/trinamic.h" #endif #if HAS_CUTTER #include "feature/spindle_laser.h" #endif -#if HAS_MEDIA - CardReader card; -#endif - -#if ENABLED(G38_PROBE_TARGET) - uint8_t G38_move; // = 0 - bool G38_did_trigger; // = false -#endif - #if ENABLED(DELTA) #include "module/delta.h" #elif ENABLED(POLARGRAPH) @@ -269,25 +260,51 @@ #include "feature/rs485.h" #endif -PGMSTR(M112_KILL_STR, "M112 Shutdown"); +/** + * Spin in place here while keeping temperature processing alive + */ +void safe_delay(millis_t ms) { + while (ms > 50) { + ms -= 50; + delay(50); + thermalManager.task(); + } + delay(ms); + thermalManager.task(); // This keeps us safe if too many small safe_delay() calls are made +} -MarlinState marlin_state = MarlinState::MF_INITIALIZING; +// Singleton for Marlin global data and methods +Marlin marlin; + +// Marlin static data +#if ENABLED(CONFIGURABLE_MACHINE_NAME) + MString<64> Marlin::machine_name; +#endif + +// Global state of the firmware +MarlinState Marlin::state = MF_INITIALIZING; // For M109 and M190, this flag may be cleared (by M108) to exit the wait loop -bool wait_for_heatup = false; +bool Marlin::wait_for_heatup = false; + +#if !HAS_MEDIA + CardReader card; // Stub instance with "no media" methods +#endif + +PGMSTR(M112_KILL_STR, "M112 Shutdown"); // For M0/M1, this flag may be cleared (by M108) to exit the wait-for-user loop #if HAS_RESUME_CONTINUE - bool wait_for_user; // = false + bool Marlin::wait_for_user; // = false - void wait_for_user_response(millis_t ms/*=0*/, const bool no_sleep/*=false*/) { + void Marlin::wait_for_user_response(millis_t ms/*=0*/, const bool no_sleep/*=false*/) { UNUSED(no_sleep); KEEPALIVE_STATE(PAUSED_FOR_USER); - wait_for_user = true; + wait_start(); if (ms) ms += millis(); // expire time while (wait_for_user && !(ms && ELAPSED(millis(), ms))) idle(TERN_(ADVANCED_PAUSE_FEATURE, no_sleep)); - wait_for_user = false; + user_resume(); while (ui.button_pressed()) safe_delay(50); } @@ -317,7 +334,7 @@ bool wait_for_heatup = false; #pragma GCC diagnostic ignored "-Wnarrowing" #pragma GCC diagnostic ignored "-Wsign-compare" -bool pin_is_protected(const pin_t pin) { +bool Marlin::pin_is_protected(const pin_t pin) { #define pgm_read_pin(P) (sizeof(pin_t) == 2 ? (pin_t)pgm_read_word(P) : (pin_t)pgm_read_byte(P)) for (uint8_t i = 0; i < COUNT(sensitive_dio); ++i) if (pin == pgm_read_pin(&sensitive_dio[i])) return true; @@ -328,28 +345,28 @@ bool pin_is_protected(const pin_t pin) { #pragma GCC diagnostic pop -bool printer_busy() { +bool Marlin::printer_busy() { return planner.has_blocks_queued() || printingIsActive(); } /** * A Print Job exists when the timer is running or SD is printing */ -bool printJobOngoing() { return print_job_timer.isRunning() || IS_SD_PRINTING(); } +bool Marlin::printJobOngoing() { return print_job_timer.isRunning() || card.isStillPrinting(); } /** * Printing is active when a job is underway but not paused */ -bool printingIsActive() { return !did_pause_print && printJobOngoing(); } +bool Marlin::printingIsActive() { return !did_pause_print && printJobOngoing(); } /** * Printing is paused according to SD or host indicators */ -bool printingIsPaused() { - return did_pause_print || print_job_timer.isPaused() || IS_SD_PAUSED(); +bool Marlin::printingIsPaused() { + return did_pause_print || print_job_timer.isPaused() || card.isPaused(); } -void startOrResumeJob() { +void Marlin::startOrResumeJob() { if (!printingIsPaused()) { TERN_(GCODE_REPEAT_MARKERS, repeat.reset()); TERN_(CANCEL_OBJECTS, cancelable.reset()); @@ -375,7 +392,7 @@ void startOrResumeJob() { TERN(HAS_CUTTER, cutter.kill(), thermalManager.zero_fan_speeds()); // Full cutter shutdown including ISR control - wait_for_heatup = false; + marlin.heatup_done(); TERN_(POWER_LOSS_RECOVERY, recovery.purge()); @@ -387,8 +404,8 @@ void startOrResumeJob() { } inline void finishSDPrinting() { - if (queue.enqueue_one(F("M1001"))) { // Keep trying until it gets queued - marlin_state = MarlinState::MF_RUNNING; // Signal to stop trying + if (queue.enqueue_one(F("M1001"))) { // Keep trying until it gets queued + marlin.setState(MF_RUNNING); // Signal to stop trying TERN_(PASSWORD_AFTER_SD_PRINT_END, password.lock_machine()); TERN_(DGUS_LCD_UI_MKS, screen.sdPrintingFinished()); } @@ -409,7 +426,7 @@ void startOrResumeJob() { * - Check if an idle but hot extruder needs filament extruded (EXTRUDER_RUNOUT_PREVENT) * - Pulse FET_SAFETY_PIN if it exists */ -inline void manage_inactivity(const bool no_stepper_sleep=false) { +void Marlin::manage_inactivity(const bool no_stepper_sleep/*=false*/) { queue.get_available_commands(); @@ -424,8 +441,7 @@ inline void manage_inactivity(const bool no_stepper_sleep=false) { if (gcode.stepper_max_timed_out(ms)) { SERIAL_ERROR_START(); - SERIAL_ECHOPGM(STR_KILL_PRE); - SERIAL_ECHOLNPGM(STR_KILL_INACTIVE_TIME, parser.command_ptr); + SERIAL_ECHOLN(F(STR_KILL_PRE), F(STR_KILL_INACTIVE_TIME), parser.command_ptr); kill(); } @@ -476,7 +492,7 @@ inline void manage_inactivity(const bool no_stepper_sleep=false) { // Check if the kill button was pressed and wait to ensure the signal is not noise // typically caused by poor insulation and grounding on LCD cables. // Lower numbers here will increase response time and therefore safety rating. - // It is recommended to set this as low as possibe without false triggers. + // It is recommended to set this as low as possible without false triggers. // ------------------------------------------------------------------------------- #ifndef KILL_DELAY #define KILL_DELAY 250 @@ -493,8 +509,7 @@ inline void manage_inactivity(const bool no_stepper_sleep=false) { // ---------------------------------------------------------------- if (killCount >= KILL_DELAY) { SERIAL_ERROR_START(); - SERIAL_ECHOPGM(STR_KILL_PRE); - SERIAL_ECHOLNPGM(STR_KILL_BUTTON); + SERIAL_ECHOLN(F(STR_KILL_PRE), F(STR_KILL_BUTTON)); kill(); } #endif @@ -507,7 +522,7 @@ inline void manage_inactivity(const bool no_stepper_sleep=false) { // Handle a standalone HOME button constexpr millis_t HOME_DEBOUNCE_DELAY = 1000UL; static millis_t next_home_key_ms; // = 0 - if (!IS_SD_PRINTING() && !READ(HOME_PIN)) { // HOME_PIN goes LOW when pressed + if (!card.isStillPrinting() && !READ(HOME_PIN)) { // HOME_PIN goes LOW when pressed if (ELAPSED(ms, next_home_key_ms)) { next_home_key_ms = ms + HOME_DEBOUNCE_DELAY; LCD_MESSAGE(MSG_AUTO_HOME); @@ -525,11 +540,15 @@ inline void manage_inactivity(const bool no_stepper_sleep=false) { constexpr millis_t CUB_DEBOUNCE_DELAY_##N = 250UL; \ static millis_t next_cub_ms_##N; \ if (BUTTON##N##_HIT_STATE == READ(BUTTON##N##_PIN) \ - && (ENABLED(BUTTON##N##_WHEN_PRINTING) || printer_not_busy)) { \ + && (ENABLED(BUTTON##N##_WHEN_PRINTING) || printer_not_busy) \ + ) { \ if (ELAPSED(ms, next_cub_ms_##N)) { \ next_cub_ms_##N = ms + CUB_DEBOUNCE_DELAY_##N; \ CODE; \ - queue.inject(F(BUTTON##N##_GCODE)); \ + if (ENABLED(BUTTON##N##_IMMEDIATE)) \ + gcode.process_subcommands_now(F(BUTTON##N##_GCODE)); \ + else \ + queue.inject(F(BUTTON##N##_GCODE)); \ TERN_(HAS_MARLINUI_MENU, ui.quick_feedback()); \ } \ } \ @@ -674,14 +693,14 @@ inline void manage_inactivity(const bool no_stepper_sleep=false) { TERN_(HOTEND_IDLE_TIMEOUT, hotend_idle.check()); #if ANY(PSU_CONTROL, AUTO_POWER_CONTROL) && PIN_EXISTS(PS_ON_EDM) - if ( ELAPSED(ms, powerManager.last_state_change_ms + PS_EDM_RESPONSE) + if ( ELAPSED(ms, powerManager.last_state_change_ms, PS_EDM_RESPONSE) && (READ(PS_ON_PIN) != READ(PS_ON_EDM_PIN) || TERN0(PSU_OFF_REDUNDANT, extDigitalRead(PS_ON1_PIN) != extDigitalRead(PS_ON1_EDM_PIN))) ) kill(GET_TEXT_F(MSG_POWER_EDM_FAULT)); #endif #if ENABLED(EXTRUDER_RUNOUT_PREVENT) if (thermalManager.degHotend(active_extruder) > (EXTRUDER_RUNOUT_MINTEMP) - && ELAPSED(ms, gcode.previous_move_ms + SEC_TO_MS(EXTRUDER_RUNOUT_SECONDS)) + && ELAPSED(ms, gcode.previous_move_ms, SEC_TO_MS(EXTRUDER_RUNOUT_SECONDS)) && !planner.has_blocks_queued() ) { const int8_t e_stepper = TERN(HAS_SWITCHING_EXTRUDER, active_extruder >> 1, active_extruder); @@ -703,9 +722,9 @@ inline void manage_inactivity(const bool no_stepper_sleep=false) { #if ENABLED(DUAL_X_CARRIAGE) // handle delayed move timeout - if (delayed_move_time && ELAPSED(ms, delayed_move_time) && IsRunning()) { + if (delayed_move_time && ELAPSED(ms, delayed_move_time) && isRunning()) { // travel moves have been received so enact them - delayed_move_time = 0xFFFFFFFFUL; // force moves to be done + delayed_move_time = UINT32_MAX; // force moves to be done destination = current_position; prepare_line_to_destination(); planner.synchronize(); @@ -732,7 +751,8 @@ inline void manage_inactivity(const bool no_stepper_sleep=false) { WRITE(FET_SAFETY_PIN, FET_SAFETY_INVERTED); } #endif -} + +} // Marlin::manage_inactivity() #if ALL(EP_BABYSTEPPING, EMERGENCY_PARSER) #include "feature/babystep.h" @@ -760,14 +780,14 @@ inline void manage_inactivity(const bool no_stepper_sleep=false) { * - Update the Průša MMU2 * - Handle Joystick jogging */ -void idle(const bool no_stepper_sleep/*=false*/) { +void Marlin::idle(const bool no_stepper_sleep/*=false*/) { #ifdef MAX7219_DEBUG_PROFILE CodeProfiler idle_profiler; #endif #if ENABLED(MARLIN_DEV_MODE) static uint16_t idle_depth = 0; - if (++idle_depth > 5) SERIAL_ECHOLNPGM("idle() call depth: ", idle_depth); + if (++idle_depth > 5) SERIAL_ECHOLNPGM("Marlin::idle() call depth: ", idle_depth); #endif // Bed Distance Sensor task @@ -783,7 +803,7 @@ void idle(const bool no_stepper_sleep/*=false*/) { TERN_(MAX7219_DEBUG, max7219.idle_tasks()); // Return if setup() isn't completed - if (marlin_state == MarlinState::MF_INITIALIZING) goto IDLE_DONE; + if (is(MF_INITIALIZING)) goto IDLE_DONE; // TODO: Still causing errors TERN_(TOOL_SENSOR, (void)check_tool_sensor_stats(active_extruder, true)); @@ -802,7 +822,7 @@ void idle(const bool no_stepper_sleep/*=false*/) { // Handle Power-Loss Recovery #if ENABLED(POWER_LOSS_RECOVERY) && PIN_EXISTS(POWER_LOSS) - if (IS_SD_PRINTING()) recovery.outage(); + if (card.isStillPrinting()) recovery.outage(); #endif // Run StallGuard endstop checks @@ -814,9 +834,6 @@ void idle(const bool no_stepper_sleep/*=false*/) { // Handle SD Card insert / remove TERN_(HAS_MEDIA, card.manage_media()); - // Handle USB Flash Drive insert / remove - TERN_(USB_FLASH_DRIVE_SUPPORT, card.diskIODriver()->idle()); - // Announce Host Keepalive state (if any) TERN_(HOST_KEEPALIVE_FEATURE, gcode.host_keepalive()); @@ -886,13 +903,14 @@ void idle(const bool no_stepper_sleep/*=false*/) { TERN_(MARLIN_DEV_MODE, idle_depth--); return; -} + +} // Marlin::idle() /** * Kill all activity and lock the machine. * After this the machine will need to be reset. */ -void kill(FSTR_P const lcd_error/*=nullptr*/, FSTR_P const lcd_component/*=nullptr*/, const bool steppers_off/*=false*/) { +void Marlin::kill(FSTR_P const lcd_error/*=nullptr*/, FSTR_P const lcd_component/*=nullptr*/, const bool steppers_off/*=false*/) { thermalManager.disable_all_heaters(); TERN_(HAS_CUTTER, cutter.kill()); // Full cutter shutdown including ISR control @@ -918,7 +936,7 @@ void kill(FSTR_P const lcd_error/*=nullptr*/, FSTR_P const lcd_component/*=nullp minkill(steppers_off); } -void minkill(const bool steppers_off/*=false*/) { +void Marlin::minkill(const bool steppers_off/*=false*/) { // Wait a short time (allows messages to get out before shutting down. for (int i = 1000; i--;) DELAY_US(600); @@ -958,13 +976,14 @@ void minkill(const bool steppers_off/*=false*/) { for (;;) hal.watchdog_refresh(); // Wait for RESET button or power-cycle #endif -} + +} // Marlin::minkill /** * Turn off heaters and stop the print in progress * After a stop the machine may be resumed with M999 */ -void stop() { +void Marlin::stop() { thermalManager.disable_all_heaters(); // 'unpause' taken care of in here print_job_timer.stop(); @@ -973,13 +992,13 @@ void stop() { thermalManager.set_fans_paused(false); // Un-pause fans for safety #endif - if (!IsStopped()) { + if (!isStopped()) { SERIAL_ERROR_MSG(STR_ERR_STOPPED); LCD_MESSAGE(MSG_STOPPED); - safe_delay(350); // allow enough time for messages to get out before stopping - marlin_state = MarlinState::MF_STOPPED; + safe_delay(350); // Allow enough time for messages to get out before stopping + setState(MF_STOPPED); } -} +} // Marlin::stop() inline void tmc_standby_setup() { #if PIN_EXISTS(X_STDBY) @@ -1048,7 +1067,7 @@ inline void tmc_standby_setup() { #if PIN_EXISTS(E7_STDBY) SET_INPUT_PULLDOWN(E7_STDBY_PIN); #endif -} +} // tmc_standby_setup() /** * Marlin Firmware entry-point. Abandon Hope All Ye Who Enter Here. @@ -1346,8 +1365,11 @@ void setup() { #endif #endif - #if HAS_MEDIA && ANY(SDCARD_EEPROM_EMULATION, POWER_LOSS_RECOVERY) - SETUP_RUN(card.mount()); // Mount media with settings before first_load + #if HAS_MEDIA + SETUP_RUN(card.init()); // Prepare for media usage + #if ANY(SDCARD_EEPROM_EMULATION, POWER_LOSS_RECOVERY) + SETUP_RUN(card.mount()); // Mount media with settings before first_load + #endif #endif // Prepare some LCDs to display early @@ -1363,6 +1385,10 @@ void setup() { SETUP_RUN(settings.first_load()); // Load data from EEPROM if available (or use defaults) // This also updates variables in the planner, elsewhere + #if ENABLED(CONFIGURABLE_MACHINE_NAME) + SETUP_RUN(ui.reset_status(false)); // machine_name Initialized by settings.load() + #endif + #if ENABLED(PROBE_TARE) SETUP_RUN(probe.tare_init()); #endif @@ -1683,7 +1709,7 @@ void setup() { SETUP_RUN(ftMotion.init()); #endif - marlin_state = MarlinState::MF_RUNNING; + marlin.setState(MF_RUNNING); #ifdef STARTUP_TUNE // Play a short startup tune before continuing. @@ -1694,12 +1720,12 @@ void setup() { SETUP_LOG("setup() completed."); TERN_(MARLIN_TEST_BUILD, runStartupTests()); -} +} // setup() /** * The main Marlin program loop * - * - Call idle() to handle all tasks between G-code commands + * - Call marlin.idle() to handle all tasks between G-code commands * Note that no G-codes from the queue can be executed during idle() * but many G-codes can be called directly anytime like macros. * - Check whether SD card auto-start is needed now. @@ -1711,11 +1737,11 @@ void setup() { */ void loop() { do { - idle(); + marlin.idle(); #if HAS_MEDIA if (card.flag.abort_sd_printing) abortSDPrinting(); - if (marlin_state == MarlinState::MF_SD_COMPLETE) finishSDPrinting(); + if (marlin.is(MF_SD_COMPLETE)) finishSDPrinting(); #endif queue.advance(); diff --git a/Marlin/src/MarlinCore.h b/Marlin/src/MarlinCore.h index 9cf74de2c6..35482983ec 100644 --- a/Marlin/src/MarlinCore.h +++ b/Marlin/src/MarlinCore.h @@ -27,22 +27,8 @@ #include #include -void stop(); - -// Pass true to keep steppers from timing out -void idle(const bool no_stepper_sleep=false); -inline void idle_no_sleep() { idle(true); } - -#if ENABLED(G38_PROBE_TARGET) - extern uint8_t G38_move; // Flag to tell the ISR that G38 is in progress, and the type - extern bool G38_did_trigger; // Flag from the ISR to indicate the endstop changed -#endif - -void kill(FSTR_P const lcd_error=nullptr, FSTR_P const lcd_component=nullptr, const bool steppers_off=false); -void minkill(const bool steppers_off=false); - // Global State of the firmware -enum class MarlinState : uint8_t { +enum MarlinState : uint8_t { MF_INITIALIZING = 0, MF_STOPPED, MF_KILLED, @@ -52,35 +38,81 @@ enum class MarlinState : uint8_t { MF_WAITING, }; -extern MarlinState marlin_state; -inline bool IsRunning() { return marlin_state >= MarlinState::MF_RUNNING; } -inline bool IsStopped() { return marlin_state == MarlinState::MF_STOPPED; } +typedef bool (*testFunc_t)(); -bool printingIsActive(); -bool printJobOngoing(); -bool printingIsPaused(); -void startOrResumeJob(); +// Delay ensuring that temperatures are updated and the watchdog is kept alive +void safe_delay(millis_t ms); -bool printer_busy(); +// Singleton for Marlin global data and methods -extern bool wait_for_heatup; - -#if HAS_RESUME_CONTINUE - extern bool wait_for_user; - void wait_for_user_response(millis_t ms=0, const bool no_sleep=false); -#endif - -bool pin_is_protected(const pin_t pin); - -#if HAS_SUICIDE - inline void suicide() { OUT_WRITE(SUICIDE_PIN, SUICIDE_PIN_STATE); } -#endif - -#if HAS_KILL - #ifndef KILL_PIN_STATE - #define KILL_PIN_STATE LOW +class Marlin { +public: + #if ENABLED(CONFIGURABLE_MACHINE_NAME) + static MString<64> machine_name; #endif - inline bool kill_state() { return READ(KILL_PIN) == KILL_PIN_STATE; } -#endif + + static MarlinState state; + static void setState(const MarlinState s) { state = s; } + static bool is(const MarlinState s) { return state == s; } + static bool isStopped() { return is(MF_STOPPED); } + static bool isRunning() { return state >= MF_RUNNING; } + + static bool printingIsActive(); + static bool printJobOngoing(); + static bool printingIsPaused(); + static void startOrResumeJob(); + + static bool printer_busy(); + + static void stop(); + + // Maintain all important activities + static void manage_inactivity(const bool no_stepper_sleep=false); + + // Pass true to keep steppers from timing out + static void idle(const bool no_stepper_sleep=false); + static void idle_no_sleep() { idle(true); } + + static void kill(FSTR_P const lcd_error=nullptr, FSTR_P const lcd_component=nullptr, const bool steppers_off=false); + static void minkill(const bool steppers_off=false); + + #if HAS_RESUME_CONTINUE + // Global waiting for user response + static bool wait_for_user; + static void wait_start() { wait_for_user = true; } + static void user_resume() { wait_for_user = false; } + static void wait_for_user_response(millis_t ms=0, const bool no_sleep=false); + #endif + + // Global waiting for heatup state + static bool wait_for_heatup; + static bool is_heating() { return wait_for_heatup; } + static void heatup_start() { wait_for_heatup = true; } + static void heatup_done() { wait_for_heatup = false; } + static void end_waiting() { TERN_(HAS_RESUME_CONTINUE, wait_for_user =) wait_for_heatup = false; } + + // Shared function for M42 / M43 + static bool pin_is_protected(const pin_t pin); + + #if HAS_SUICIDE + static void suicide() { OUT_WRITE(SUICIDE_PIN, SUICIDE_PIN_STATE); } + #endif + + static bool kill_state() { + return ( + #if HAS_KILL + #ifndef KILL_PIN_STATE + #define KILL_PIN_STATE LOW + #endif + READ(KILL_PIN) == KILL_PIN_STATE + #else + false + #endif + ); + } + +}; + +extern Marlin marlin; extern const char M112_KILL_STR[]; diff --git a/Marlin/src/core/boards.h b/Marlin/src/core/boards.h index f08d69e3e5..6c51cb01a4 100644 --- a/Marlin/src/core/boards.h +++ b/Marlin/src/core/boards.h @@ -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 @@ -105,32 +106,34 @@ #define BOARD_TRIGORILLA_14_11 1138 // ... Rev 1.1 (new servo pin order) #define BOARD_RAMPS_ENDER_4 1139 // Creality: Ender-4, CR-8 #define BOARD_RAMPS_CREALITY 1140 // Creality: CR10S, CR20, CR-X -#define BOARD_DAGOMA_F5 1141 // Dagoma F5 -#define BOARD_DAGOMA_D6 1142 // Dagoma D6 (as found in the Dagoma DiscoUltimate V2 TMC) -#define BOARD_FYSETC_F6_13 1143 // FYSETC F6 1.3 -#define BOARD_FYSETC_F6_14 1144 // FYSETC F6 1.4 -#define BOARD_DUPLICATOR_I3_PLUS 1145 // Wanhao Duplicator i3 Plus -#define BOARD_VORON 1146 // VORON Design -#define BOARD_TRONXY_V3_1_0 1147 // Tronxy TRONXY-V3-1.0 -#define BOARD_Z_BOLT_X_SERIES 1148 // Z-Bolt X Series -#define BOARD_TT_OSCAR 1149 // TT OSCAR -#define BOARD_TANGO 1150 // BIQU Tango V1 -#define BOARD_MKS_GEN_L_V2 1151 // MKS GEN L V2 -#define BOARD_MKS_GEN_L_V21 1152 // MKS GEN L V2.1 -#define BOARD_COPYMASTER_3D 1153 // Copymaster 3D -#define BOARD_ORTUR_4 1154 // Ortur 4 -#define BOARD_TENLOG_D3_HERO 1155 // Tenlog D3 Hero IDEX printer -#define BOARD_TENLOG_MB1_V23 1156 // Tenlog D3, D5, D6 IDEX Printer -#define BOARD_RAMPS_S_12_EEFB 1157 // Ramps S 1.2 by Sakul.cz (Power outputs: Hotend0, Hotend1, Fan, Bed) -#define BOARD_RAMPS_S_12_EEEB 1158 // Ramps S 1.2 by Sakul.cz (Power outputs: Hotend0, Hotend1, Hotend2, Bed) -#define BOARD_RAMPS_S_12_EFFB 1159 // Ramps S 1.2 by Sakul.cz (Power outputs: Hotend, Fan0, Fan1, Bed) -#define BOARD_LONGER3D_LK1_PRO 1160 // Longer LK1 PRO / Alfawise U20 Pro (PRO version) -#define BOARD_LONGER3D_LKx_PRO 1161 // Longer LKx PRO / Alfawise Uxx Pro (PRO version) -#define BOARD_PXMALION_CORE_I3 1162 // Pxmalion Core I3 -#define BOARD_PANOWIN_CUTLASS 1163 // Panowin Cutlass (as found in the Panowin F1) -#define BOARD_KODAMA_BARDO 1164 // Kodama Bardo V1.x (as found in the Kodama Trinus) -#define BOARD_XTLW_MFF_V1 1165 // XTLW MFF V1.0 -#define BOARD_XTLW_MFF_V2 1166 // XTLW MFF V2.0 +#define BOARD_CREALITY_V252 1141 // Creality CR-10 V2, CR-10 V3 +#define BOARD_DAGOMA_F5 1142 // Dagoma F5 +#define BOARD_DAGOMA_D6 1143 // Dagoma D6 (as found in the Dagoma DiscoUltimate V2 TMC) +#define BOARD_FYSETC_F6_13 1144 // FYSETC F6 1.3 +#define BOARD_FYSETC_F6_14 1145 // FYSETC F6 1.4 +#define BOARD_DUPLICATOR_I3_PLUS 1146 // Wanhao Duplicator i3 Plus +#define BOARD_VORON 1147 // VORON Design +#define BOARD_TRONXY_V3_1_0 1148 // Tronxy TRONXY-V3-1.0 +#define BOARD_Z_BOLT_X_SERIES 1149 // Z-Bolt X Series +#define BOARD_TT_OSCAR 1150 // TT OSCAR +#define BOARD_TANGO 1151 // BIQU Tango V1 +#define BOARD_MKS_GEN_L_V2 1152 // MKS GEN L V2 +#define BOARD_MKS_GEN_L_V21 1153 // MKS GEN L V2.1 +#define BOARD_COPYMASTER_3D 1154 // Copymaster 3D +#define BOARD_ORTUR_4 1155 // Ortur 4 +#define BOARD_TENLOG_D3_HERO 1156 // Tenlog D3 Hero IDEX printer +#define BOARD_TENLOG_MB1_V23 1157 // Tenlog D3, D5, D6 IDEX Printer +#define BOARD_RAMPS_S_12_EEFB 1158 // Ramps S 1.2 by Sakul.cz (Power outputs: Hotend0, Hotend1, Fan, Bed) +#define BOARD_RAMPS_S_12_EEEB 1159 // Ramps S 1.2 by Sakul.cz (Power outputs: Hotend0, Hotend1, Hotend2, Bed) +#define BOARD_RAMPS_S_12_EFFB 1160 // Ramps S 1.2 by Sakul.cz (Power outputs: Hotend, Fan0, Fan1, Bed) +#define BOARD_LONGER3D_LK1_PRO 1161 // Longer LK1 PRO / Alfawise U20 Pro (PRO version) +#define BOARD_LONGER3D_LKx_PRO 1162 // Longer LKx PRO / Alfawise Uxx Pro (PRO version) +#define BOARD_PXMALION_CORE_I3 1163 // Pxmalion Core I3 +#define BOARD_PANOWIN_CUTLASS 1164 // Panowin Cutlass (as found in the Panowin F1) +#define BOARD_KODAMA_BARDO 1165 // Kodama Bardo V1.x (as found in the Kodama Trinus) +#define BOARD_XTLW_MFF_V1 1166 // XTLW MFF V1.0 +#define BOARD_XTLW_MFF_V2 1167 // XTLW MFF V2.0 +#define BOARD_RUMBA_E3D 1168 // E3D Rumba BigBox // // RAMBo and derivatives @@ -173,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 @@ -275,7 +279,7 @@ #define BOARD_MKS_SGEN_L_V2 2509 // MKS SGEN_L V2 #define BOARD_BTT_SKR_E3_TURBO 2510 // BigTreeTech SKR E3 Turbo #define BOARD_FLY_CDY 2511 // FLYmaker FLY CDY -#define BOARD_XTLW_CLIMBER_8TH_LPC 2512 // XTLW_CLIMBER_8TH_LPC +#define BOARD_XTLW_CLIMBER_8TH_LPC 2512 // XTLW Climber 8 // // SAM3X8E ARM Cortex-M3 @@ -283,7 +287,7 @@ #define BOARD_DUE3DOM 3000 // DUE3DOM for Arduino DUE #define BOARD_DUE3DOM_MINI 3001 // DUE3DOM MINI for Arduino DUE -#define BOARD_RADDS 3002 // RADDS +#define BOARD_RADDS 3002 // RADDS v1.5/v1.6 #define BOARD_RAMPS_FD_V1 3003 // RAMPS-FD v1 #define BOARD_RAMPS_FD_V2 3004 // RAMPS-FD v2 #define BOARD_RAMPS_SMART_EFB 3005 // RAMPS-SMART (Power outputs: Hotend, Fan, Bed) @@ -318,7 +322,7 @@ #define BOARD_ADSK 3101 // Arduino DUE Shield Kit (ADSK) // -// STM32 ARM Cortex-M0+ +// STM32 ARM Cortex-M0/+ // #define BOARD_BTT_EBB42_V1_1 4000 // BigTreeTech EBB42 V1.1 (STM32G0B1CB) @@ -330,83 +334,91 @@ #define BOARD_BTT_MANTA_M8P_V1_1 4006 // BigTreeTech Manta M8P V1.1 (STM32G0B1VE) #define BOARD_BTT_SKRAT_V1_0 4007 // BigTreeTech SKRat V1.0 (STM32G0B1VE) +// +// STM32 ARM Cortex-M0 +// + +#define BOARD_MALYAN_M200_V2 4100 // STM32F070CB controller +#define BOARD_MALYAN_M300 4101 // STM32F070-based delta +#define BOARD_FLY_D5 4102 // FLY_D5 (STM32F072RB) +#define BOARD_FLY_DP5 4103 // FLY_DP5 (STM32F072RB) +#define BOARD_FLY_D7 4104 // FLY_D7 (STM32F072RB) + // // STM32 ARM Cortex-M3 // -#define BOARD_MALYAN_M200_V2 5000 // STM32F070CB controller -#define BOARD_MALYAN_M300 5001 // STM32F070-based delta -#define BOARD_STM32F103RE 5002 // STM32F103RE Libmaple-based STM32F1 controller -#define BOARD_MALYAN_M200 5003 // STM32C8 Libmaple-based STM32F1 controller -#define BOARD_STM3R_MINI 5004 // STM32F103RE Libmaple-based STM32F1 controller -#define BOARD_GTM32_PRO_VB 5005 // STM32F103VE controller -#define BOARD_GTM32_PRO_VD 5006 // STM32F103VE controller -#define BOARD_GTM32_MINI 5007 // STM32F103VE controller -#define BOARD_GTM32_MINI_A30 5008 // STM32F103VE controller -#define BOARD_GTM32_REV_B 5009 // STM32F103VE controller -#define BOARD_MORPHEUS 5010 // STM32F103C8 / STM32F103CB Libmaple-based STM32F1 controller -#define BOARD_CHITU3D 5011 // Chitu3D (STM32F103RE) -#define BOARD_MKS_ROBIN 5012 // MKS Robin (STM32F103ZE) -#define BOARD_MKS_ROBIN_MINI 5013 // MKS Robin Mini (STM32F103VE) -#define BOARD_MKS_ROBIN_NANO 5014 // MKS Robin Nano (STM32F103VE) -#define BOARD_MKS_ROBIN_NANO_V2 5015 // MKS Robin Nano V2 (STM32F103VE) -#define BOARD_MKS_ROBIN_LITE 5016 // MKS Robin Lite/Lite2 (STM32F103RC) -#define BOARD_MKS_ROBIN_LITE3 5017 // MKS Robin Lite3 (STM32F103RC) -#define BOARD_MKS_ROBIN_PRO 5018 // MKS Robin Pro (STM32F103ZE) -#define BOARD_MKS_ROBIN_E3 5019 // MKS Robin E3 (STM32F103RC) -#define BOARD_MKS_ROBIN_E3_V1_1 5020 // MKS Robin E3 V1.1 (STM32F103RC) -#define BOARD_MKS_ROBIN_E3D 5021 // MKS Robin E3D (STM32F103RC) -#define BOARD_MKS_ROBIN_E3D_V1_1 5022 // MKS Robin E3D V1.1 (STM32F103RC) -#define BOARD_MKS_ROBIN_E3P 5023 // MKS Robin E3P (STM32F103VE) -#define BOARD_BTT_SKR_MINI_V1_1 5024 // BigTreeTech SKR Mini v1.1 (STM32F103RC) -#define BOARD_BTT_SKR_MINI_E3_V1_0 5025 // BigTreeTech SKR Mini E3 (STM32F103RC) -#define BOARD_BTT_SKR_MINI_E3_V1_2 5026 // BigTreeTech SKR Mini E3 V1.2 (STM32F103RC) -#define BOARD_BTT_SKR_MINI_E3_V2_0 5027 // BigTreeTech SKR Mini E3 V2.0 (STM32F103RC / STM32F103RE) -#define BOARD_BTT_SKR_MINI_MZ_V1_0 5028 // BigTreeTech SKR Mini MZ V1.0 (STM32F103RC) -#define BOARD_BTT_SKR_E3_DIP 5029 // BigTreeTech SKR E3 DIP V1.0 (STM32F103RC / STM32F103RE) -#define BOARD_BTT_SKR_CR6 5030 // BigTreeTech SKR CR6 v1.0 (STM32F103RE) -#define BOARD_JGAURORA_A5S_A1 5031 // JGAurora A5S A1 (STM32F103ZE) -#define BOARD_FYSETC_AIO_II 5032 // FYSETC AIO_II (STM32F103RC) -#define BOARD_FYSETC_CHEETAH 5033 // FYSETC Cheetah (STM32F103RC) -#define BOARD_FYSETC_CHEETAH_V12 5034 // FYSETC Cheetah V1.2 (STM32F103RC) -#define BOARD_LONGER3D_LK 5035 // Longer3D LK1/2 - Alfawise U20/U20+/U30 (STM32F103VE) -#define BOARD_CCROBOT_MEEB_3DP 5036 // ccrobot-online.com MEEB_3DP (STM32F103RC) -#define BOARD_CHITU3D_V5 5037 // Chitu3D TronXY X5SA V5 Board (STM32F103ZE) -#define BOARD_CHITU3D_V6 5038 // Chitu3D TronXY X5SA V6 Board (STM32F103ZE) -#define BOARD_CHITU3D_V9 5039 // Chitu3D TronXY X5SA V9 Board (STM32F103ZE) -#define BOARD_CREALITY_V4 5040 // Creality v4.x (STM32F103RC / STM32F103RE) -#define BOARD_CREALITY_V422 5041 // Creality v4.2.2 (STM32F103RC / STM32F103RE) -#define BOARD_CREALITY_V423 5042 // Creality v4.2.3 (STM32F103RC / STM32F103RE) -#define BOARD_CREALITY_V425 5043 // Creality v4.2.5 (STM32F103RC / STM32F103RE) -#define BOARD_CREALITY_V427 5044 // Creality v4.2.7 (STM32F103RC / STM32F103RE) -#define BOARD_CREALITY_V4210 5045 // Creality v4.2.10 (STM32F103RC / STM32F103RE) as found in the CR-30 -#define BOARD_CREALITY_V431 5046 // Creality v4.3.1 (STM32F103RC / STM32F103RE) -#define BOARD_CREALITY_V431_A 5047 // Creality v4.3.1a (STM32F103RC / STM32F103RE) -#define BOARD_CREALITY_V431_B 5048 // Creality v4.3.1b (STM32F103RC / STM32F103RE) -#define BOARD_CREALITY_V431_C 5049 // Creality v4.3.1c (STM32F103RC / STM32F103RE) -#define BOARD_CREALITY_V431_D 5050 // Creality v4.3.1d (STM32F103RC / STM32F103RE) -#define BOARD_CREALITY_V452 5051 // Creality v4.5.2 (STM32F103RC / STM32F103RE) -#define BOARD_CREALITY_V453 5052 // Creality v4.5.3 (STM32F103RC / STM32F103RE) -#define BOARD_CREALITY_V521 5053 // Creality v5.2.1 (STM32F103VE) as found in the SV04 -#define BOARD_CREALITY_V24S1 5054 // Creality v2.4.S1 (STM32F103RC / STM32F103RE) CR-FDM-v2.4.S1_v101 as found in the Ender-7 -#define BOARD_CREALITY_V24S1_301 5055 // Creality v2.4.S1_301 (STM32F103RC / STM32F103RE) CR-FDM-v24S1_301 as found in the Ender-3 S1 -#define BOARD_CREALITY_V25S1 5056 // Creality v2.5.S1 (STM32F103RE) CR-FDM-v2.5.S1_100 as found in the CR-10 Smart Pro -#define BOARD_TRIGORILLA_PRO 5057 // Trigorilla Pro (STM32F103ZE) -#define BOARD_FLY_MINI 5058 // FLYmaker FLY MINI (STM32F103RC) -#define BOARD_FLSUN_HISPEED 5059 // FLSUN HiSpeedV1 (STM32F103VE) -#define BOARD_BEAST 5060 // STM32F103RE Libmaple-based controller -#define BOARD_MINGDA_MPX_ARM_MINI 5061 // STM32F103ZE Mingda MD-16 -#define BOARD_ZONESTAR_ZM3E2 5062 // Zonestar ZM3E2 (STM32F103RC) -#define BOARD_ZONESTAR_ZM3E4 5063 // Zonestar ZM3E4 V1 (STM32F103VC) -#define BOARD_ZONESTAR_ZM3E4V2 5064 // Zonestar ZM3E4 V2 (STM32F103VC) -#define BOARD_ERYONE_ERY32_MINI 5065 // Eryone Ery32 mini (STM32F103VE) -#define BOARD_PANDA_PI_V29 5066 // Panda Pi V2.9 - Standalone (STM32F103RC) -#define BOARD_SOVOL_V131 5067 // Sovol V1.3.1 (GD32F103RE) -#define BOARD_TRIGORILLA_V006 5068 // Trigorilla V0.0.6 (GD32F103RE) -#define BOARD_KEDI_CONTROLLER_V1_2 5069 // EDUTRONICS Kedi Controller V1.2 (STM32F103RC) -#define BOARD_MD_D301 5070 // Mingda D2 DZ301 V1.0 (STM32F103ZE) -#define BOARD_VOXELAB_AQUILA 5071 // Voxelab Aquila V1.0.0/V1.0.1 (GD32F103RC / N32G455RE / STM32F103RE) -#define BOARD_SPRINGER_CONTROLLER 5072 // ORCA 3D SPRINGER Modular Controller (STM32F103VC) +#define BOARD_STM32F103RE 5000 // STM32F103RE Libmaple-based STM32F1 controller +#define BOARD_MALYAN_M200 5001 // STM32C8 Libmaple-based STM32F1 controller +#define BOARD_STM3R_MINI 5002 // STM32F103RE Libmaple-based STM32F1 controller +#define BOARD_GTM32_PRO_VB 5003 // STM32F103VE controller +#define BOARD_GTM32_PRO_VD 5004 // STM32F103VE controller +#define BOARD_GTM32_MINI 5005 // STM32F103VE controller +#define BOARD_GTM32_MINI_A30 5006 // STM32F103VE controller +#define BOARD_GTM32_REV_B 5007 // STM32F103VE controller +#define BOARD_MORPHEUS 5008 // STM32F103C8 / STM32F103CB Libmaple-based STM32F1 controller +#define BOARD_CHITU3D 5009 // Chitu3D (STM32F103RE) +#define BOARD_MKS_ROBIN 5010 // MKS Robin (STM32F103ZE) +#define BOARD_MKS_ROBIN_MINI 5011 // MKS Robin Mini (STM32F103VE) +#define BOARD_MKS_ROBIN_NANO 5012 // MKS Robin Nano (STM32F103VE) +#define BOARD_MKS_ROBIN_NANO_V2 5013 // MKS Robin Nano V2 (STM32F103VE) +#define BOARD_MKS_ROBIN_LITE 5014 // MKS Robin Lite/Lite2 (STM32F103RC) +#define BOARD_MKS_ROBIN_LITE3 5015 // MKS Robin Lite3 (STM32F103RC) +#define BOARD_MKS_ROBIN_PRO 5016 // MKS Robin Pro (STM32F103ZE) +#define BOARD_MKS_ROBIN_E3 5017 // MKS Robin E3 (STM32F103RC) +#define BOARD_MKS_ROBIN_E3_V1_1 5018 // MKS Robin E3 V1.1 (STM32F103RC) +#define BOARD_MKS_ROBIN_E3D 5019 // MKS Robin E3D (STM32F103RC) +#define BOARD_MKS_ROBIN_E3D_V1_1 5020 // MKS Robin E3D V1.1 (STM32F103RC) +#define BOARD_MKS_ROBIN_E3P 5021 // MKS Robin E3P (STM32F103VE) +#define BOARD_BTT_SKR_MINI_V1_1 5022 // BigTreeTech SKR Mini v1.1 (STM32F103RC) +#define BOARD_BTT_SKR_MINI_E3_V1_0 5023 // BigTreeTech SKR Mini E3 (STM32F103RC) +#define BOARD_BTT_SKR_MINI_E3_V1_2 5024 // BigTreeTech SKR Mini E3 V1.2 (STM32F103RC) +#define BOARD_BTT_SKR_MINI_E3_V2_0 5025 // BigTreeTech SKR Mini E3 V2.0 (STM32F103RC / STM32F103RE) +#define BOARD_BTT_SKR_MINI_MZ_V1_0 5026 // BigTreeTech SKR Mini MZ V1.0 (STM32F103RC) +#define BOARD_BTT_SKR_E3_DIP 5027 // BigTreeTech SKR E3 DIP V1.0 (STM32F103RC / STM32F103RE) +#define BOARD_BTT_SKR_CR6 5028 // BigTreeTech SKR CR6 v1.0 (STM32F103RE) +#define BOARD_JGAURORA_A5S_A1 5029 // JGAurora A5S A1 (STM32F103ZE) +#define BOARD_FYSETC_AIO_II 5030 // FYSETC AIO_II (STM32F103RC) +#define BOARD_FYSETC_CHEETAH 5031 // FYSETC Cheetah (STM32F103RC) +#define BOARD_FYSETC_CHEETAH_V12 5032 // FYSETC Cheetah V1.2 (STM32F103RC) +#define BOARD_LONGER3D_LK 5033 // Longer3D LK1/2 - Alfawise U20/U20+/U30 (STM32F103VE) +#define BOARD_CCROBOT_MEEB_3DP 5034 // ccrobot-online.com MEEB_3DP (STM32F103RC) +#define BOARD_CHITU3D_V5 5035 // Chitu3D TronXY X5SA V5 Board (STM32F103ZE) +#define BOARD_CHITU3D_V6 5036 // Chitu3D TronXY X5SA V6 Board (STM32F103ZE) +#define BOARD_CHITU3D_V9 5037 // Chitu3D TronXY X5SA V9 Board (STM32F103ZE) +#define BOARD_CREALITY_V4 5038 // Creality v4.x (STM32F103RC / STM32F103RE) +#define BOARD_CREALITY_V422 5039 // Creality v4.2.2 (STM32F103RC / STM32F103RE) ... GD32 Variant Below! +#define BOARD_CREALITY_V423 5040 // Creality v4.2.3 (STM32F103RC / STM32F103RE) +#define BOARD_CREALITY_V425 5041 // Creality v4.2.5 (STM32F103RC / STM32F103RE) +#define BOARD_CREALITY_V427 5042 // Creality v4.2.7 (STM32F103RC / STM32F103RE) ... GD32 Variant Below! +#define BOARD_CREALITY_V4210 5043 // Creality v4.2.10 (STM32F103RC / STM32F103RE) as found in the CR-30 +#define BOARD_CREALITY_V431 5044 // Creality v4.3.1 (STM32F103RC / STM32F103RE) +#define BOARD_CREALITY_V431_A 5045 // Creality v4.3.1a (STM32F103RC / STM32F103RE) +#define BOARD_CREALITY_V431_B 5046 // Creality v4.3.1b (STM32F103RC / STM32F103RE) +#define BOARD_CREALITY_V431_C 5047 // Creality v4.3.1c (STM32F103RC / STM32F103RE) +#define BOARD_CREALITY_V431_D 5048 // Creality v4.3.1d (STM32F103RC / STM32F103RE) +#define BOARD_CREALITY_V452 5049 // Creality v4.5.2 (STM32F103RC / STM32F103RE) +#define BOARD_CREALITY_V453 5050 // Creality v4.5.3 (STM32F103RC / STM32F103RE) +#define BOARD_CREALITY_V521 5051 // Creality v5.2.1 (STM32F103VE) as found in the SV04 +#define BOARD_CREALITY_V24S1 5052 // Creality v2.4.S1 (STM32F103RC / STM32F103RE) CR-FDM-v2.4.S1_v101 as found in the Ender-7 +#define BOARD_CREALITY_V24S1_301 5053 // Creality v2.4.S1_301 (STM32F103RC / STM32F103RE) CR-FDM-v24S1_301 as found in the Ender-3 S1 +#define BOARD_CREALITY_V25S1 5054 // Creality v2.5.S1 (STM32F103RE) CR-FDM-v2.5.S1_100 as found in the CR-10 Smart Pro +#define BOARD_TRIGORILLA_PRO 5055 // Trigorilla Pro (STM32F103ZE) +#define BOARD_FLY_MINI 5056 // FLYmaker FLY MINI (STM32F103RC) +#define BOARD_FLSUN_HISPEED 5057 // FLSUN HiSpeedV1 (STM32F103VE) +#define BOARD_BEAST 5058 // STM32F103RE Libmaple-based controller +#define BOARD_MINGDA_MPX_ARM_MINI 5059 // STM32F103ZE Mingda MD-16 +#define BOARD_ZONESTAR_ZM3E2 5060 // Zonestar ZM3E2 (STM32F103RC) +#define BOARD_ZONESTAR_ZM3E4 5061 // Zonestar ZM3E4 V1 (STM32F103VC) +#define BOARD_ZONESTAR_ZM3E4V2 5062 // Zonestar ZM3E4 V2 (STM32F103VC) +#define BOARD_ERYONE_ERY32_MINI 5063 // Eryone Ery32 mini (STM32F103VE) +#define BOARD_PANDA_PI_V29 5064 // Panda Pi V2.9 - Standalone (STM32F103RC) +#define BOARD_SOVOL_V131 5065 // Sovol V1.3.1 (GD32F103RE) +#define BOARD_TRIGORILLA_V006 5066 // Trigorilla V0.0.6 (GD32F103RE) +#define BOARD_KEDI_CONTROLLER_V1_2 5067 // EDUTRONICS Kedi Controller V1.2 (STM32F103RC) +#define BOARD_MD_D301 5068 // Mingda D2 DZ301 V1.0 (STM32F103ZE) +#define BOARD_VOXELAB_AQUILA 5069 // Voxelab Aquila V1.0.0/V1.0.1 (GD32F103RC / N32G455RE / STM32F103RE) +#define BOARD_SPRINGER_CONTROLLER 5070 // ORCA 3D SPRINGER Modular Controller (STM32F103VC) // // ARM Cortex-M4F @@ -419,60 +431,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_MKS_ROBIN_NANO_V1_3_F4 5238 // MKS Robin Nano V1.3 and MKS Robin Nano-S V1.3 (STM32F407VE) -#define BOARD_MKS_EAGLE 5239 // MKS Eagle (STM32F407VE) -#define BOARD_ARTILLERY_RUBY 5240 // Artillery Ruby (STM32F401RC) -#define BOARD_CREALITY_V24S1_301F4 5241 // Creality v2.4.S1_301F4 (STM32F401RC) as found in the Ender-3 S1 F4 -#define BOARD_CREALITY_CR4NTXXC10 5242 // Creality E3 Free-runs Silent Motherboard (STM32F401RET6) -#define BOARD_OPULO_LUMEN_REV4 5243 // Opulo Lumen PnP Controller REV4 (STM32F407VE / STM32F407VG) -#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_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 @@ -483,19 +503,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_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 @@ -532,15 +557,29 @@ // HC32 ARM Cortex-M4 // -#define BOARD_AQUILA_V101 7200 // Voxelab Aquila V1.0.0/V1.0.1/V1.0.2/V1.0.3 as found in the Voxelab Aquila X2 and C2 +#define BOARD_AQUILA_V101 7200 // Voxelab Aquila V1.0.0/1/2/3 (e.g., Aquila X2, C2). ... GD32 Variant Below! #define BOARD_CREALITY_ENDER2P_V24S4 7201 // Creality Ender 2 Pro v2.4.S4_170 (HC32f460kcta) +// +// GD32 ARM Cortex-M3 +// + +#define BOARD_AQUILA_V101_GD32_MFL 7300 // Voxelab Aquila V1.0.1 MFL (GD32F103RC) ... STM32/HC32 Variant Above! + +// +// GD32 ARM Cortex-M4 +// + +#define BOARD_CREALITY_V422_GD32_MFL 7400 // Creality V4.2.2 MFL (GD32F303RE) ... STM32 Variant Above! +#define BOARD_CREALITY_V427_GD32_MFL 7401 // Creality V4.2.7 MFL (GD32F303RE) ... STM32 Variant Above! + // // Raspberry Pi // -#define BOARD_RP2040 6200 // Generic RP2040 Test board -#define BOARD_BTT_SKR_PICO 6201 // BigTreeTech SKR Pico 1.x +#define BOARD_RP2040 6200 // Generic RP2040 Test board +#define BOARD_RASPBERRY_PI_PICO 6201 // Raspberry Pi Pico +#define BOARD_BTT_SKR_PICO 6202 // BigTreeTech SKR Pico 1.x // // Custom board diff --git a/Marlin/src/core/bug_on.h b/Marlin/src/core/bug_on.h index 7f1243ed40..8ff565ff73 100644 --- a/Marlin/src/core/bug_on.h +++ b/Marlin/src/core/bug_on.h @@ -27,12 +27,12 @@ // Useful macro for stopping the CPU on an unexpected condition // This is used like SERIAL_ECHOPGM, that is: a key-value call of the local variables you want // to dump to the serial port before stopping the CPU. - // \/ Don't replace by SERIAL_ECHOPGM since ONLY_FILENAME cannot be transformed to a PGM string on Arduino and it breaks building - #define BUG_ON(V...) do { SERIAL_ECHO(ONLY_FILENAME); SERIAL_ECHO(__LINE__); SERIAL_ECHOLNPGM(": "); SERIAL_ECHOLNPGM(V); SERIAL_FLUSHTX(); *(char*)0 = 42; } while(0) + // \/ Don't use SERIAL_ECHOPGM with ONLY_FILENAME. It can't be a PGM string, + #define BUG_ON(V...) do { SERIAL_ECHOLN(ONLY_FILENAME, __LINE__, F(": ")); SERIAL_ECHOLNPGM(V); SERIAL_FLUSHTX(); *(char*)0 = 42; } while(0) #elif ENABLED(MARLIN_DEV_MODE) // Don't stop the CPU here, but at least dump the bug on the serial port - // \/ Don't replace by SERIAL_ECHOPGM since ONLY_FILENAME cannot be transformed to a PGM string on Arduino and it breaks building - #define BUG_ON(V...) do { SERIAL_ECHO(ONLY_FILENAME); SERIAL_ECHO(__LINE__); SERIAL_ECHOLNPGM(": BUG!"); SERIAL_ECHOLNPGM(V); SERIAL_FLUSHTX(); } while(0) + // \/ Don't use SERIAL_ECHOPGM with ONLY_FILENAME. It can't be a PGM string, + #define BUG_ON(V...) do { SERIAL_ECHOLN(ONLY_FILENAME, __LINE__, F(": BUG!")); SERIAL_ECHOLNPGM(V); SERIAL_FLUSHTX(); } while(0) #else // Release mode, let's ignore the bug #define BUG_ON(V...) NOOP diff --git a/Marlin/src/core/drivers.h b/Marlin/src/core/drivers.h index c54e42c8fe..80980380a5 100644 --- a/Marlin/src/core/drivers.h +++ b/Marlin/src/core/drivers.h @@ -41,6 +41,7 @@ #define _TMC2208_STANDALONE 0x2208B #define _TMC2209 0x2209A #define _TMC2209_STANDALONE 0x2209B +#define _TMC2240 0x2240A #define _TMC2660 0x2660A #define _TMC2660_STANDALONE 0x2660B #define _TMC5130 0x5130A @@ -96,7 +97,7 @@ // Does not match standalone configurations #if ( HAS_DRIVER(TMC2130) || HAS_DRIVER(TMC2160) \ || HAS_DRIVER(TMC2208) || HAS_DRIVER(TMC2209) \ - || HAS_DRIVER(TMC2660) \ + || HAS_DRIVER(TMC2240) || HAS_DRIVER(TMC2660) \ || HAS_DRIVER(TMC5130) || HAS_DRIVER(TMC5160) ) #define HAS_TRINAMIC_CONFIG 1 #endif @@ -106,22 +107,33 @@ #if ( HAS_DRIVER(TMC2100) \ || HAS_DRIVER(TMC2130_STANDALONE) || HAS_DRIVER(TMC2160_STANDALONE) \ || HAS_DRIVER(TMC2208_STANDALONE) || HAS_DRIVER(TMC2209_STANDALONE) \ - || HAS_DRIVER(TMC2660_STANDALONE) || HAS_DRIVER(TMC5130_STANDALONE) \ - || HAS_DRIVER(TMC5160_STANDALONE) ) + || HAS_DRIVER(TMC2660_STANDALONE) \ + || HAS_DRIVER(TMC5130_STANDALONE) || HAS_DRIVER(TMC5160_STANDALONE) ) #define HAS_TRINAMIC_STANDALONE 1 #endif #if HAS_DRIVER(TMC2130) || HAS_DRIVER(TMC2160) || HAS_DRIVER(TMC5130) || HAS_DRIVER(TMC5160) #define HAS_TMCX1X0 1 #endif - +#if HAS_TMCX1X0 || HAS_DRIVER(TMC2240) + #define HAS_TMCX1X0_OR_2240 1 +#endif #if HAS_DRIVER(TMC2208) || HAS_DRIVER(TMC2209) #define HAS_TMC220x 1 #endif +//#if HAS_TMC_220x || HAS_DRIVER(TMC2240) +// #define HAS_TMC22xx 1 +//#endif +//#if HAS_TMCX1X0 || HAS_TMC220x +// #define HAS_TMC_CS_ACTUAL 1 +//#endif +//#if HAS_TMCX1X0 || HAS_DRIVER(TMC2209) +// #define HAS_TMC_SG_RESULT 1 +//#endif #define AXIS_IS_TMC(A) ( AXIS_DRIVER_TYPE(A,TMC2130) || AXIS_DRIVER_TYPE(A,TMC2160) \ || AXIS_DRIVER_TYPE(A,TMC2208) || AXIS_DRIVER_TYPE(A,TMC2209) \ - || AXIS_DRIVER_TYPE(A,TMC2660) \ + || AXIS_DRIVER_TYPE(A,TMC2240) || AXIS_DRIVER_TYPE(A,TMC2660) \ || AXIS_DRIVER_TYPE(A,TMC5130) || AXIS_DRIVER_TYPE(A,TMC5160) ) #define AXIS_IS_TMC_CONFIG AXIS_IS_TMC @@ -129,8 +141,8 @@ // Test for a driver that uses SPI - this allows checking whether a _CS_ pin // is considered sensitive #define AXIS_HAS_SPI(A) ( AXIS_DRIVER_TYPE(A,TMC2130) || AXIS_DRIVER_TYPE(A,TMC2160) \ - || AXIS_DRIVER_TYPE(A,TMC2660) || AXIS_DRIVER_TYPE(A,TMC5130) \ - || AXIS_DRIVER_TYPE(A,TMC5160) ) + || AXIS_DRIVER_TYPE(A,TMC2240) || AXIS_DRIVER_TYPE(A,TMC2660) \ + || AXIS_DRIVER_TYPE(A,TMC5130) || AXIS_DRIVER_TYPE(A,TMC5160) ) #define AXIS_HAS_UART(A) ( AXIS_DRIVER_TYPE(A,TMC2208) || AXIS_DRIVER_TYPE(A,TMC2209) ) @@ -140,19 +152,21 @@ #define AXIS_HAS_SW_SERIAL(A) ( AXIS_HAS_UART(A) && !defined(A##_HARDWARE_SERIAL) ) #define AXIS_HAS_STALLGUARD(A) ( AXIS_DRIVER_TYPE(A,TMC2130) || AXIS_DRIVER_TYPE(A,TMC2160) \ - || AXIS_DRIVER_TYPE(A,TMC2209) \ + || AXIS_DRIVER_TYPE(A,TMC2209) || AXIS_DRIVER_TYPE(A,TMC2240) \ || AXIS_DRIVER_TYPE(A,TMC2660) \ || AXIS_DRIVER_TYPE(A,TMC5130) || AXIS_DRIVER_TYPE(A,TMC5160) ) #define AXIS_HAS_STEALTHCHOP(A) ( AXIS_DRIVER_TYPE(A,TMC2130) || AXIS_DRIVER_TYPE(A,TMC2160) \ || AXIS_DRIVER_TYPE(A,TMC2208) || AXIS_DRIVER_TYPE(A,TMC2209) \ + || AXIS_DRIVER_TYPE(A,TMC2240) \ || AXIS_DRIVER_TYPE(A,TMC5130) || AXIS_DRIVER_TYPE(A,TMC5160) ) #define AXIS_HAS_SG_RESULT(A) ( AXIS_DRIVER_TYPE(A,TMC2130) || AXIS_DRIVER_TYPE(A,TMC2160) \ - || AXIS_DRIVER_TYPE(A,TMC2208) || AXIS_DRIVER_TYPE(A,TMC2209) ) + || AXIS_DRIVER_TYPE(A,TMC2208) || AXIS_DRIVER_TYPE(A,TMC2209) \ + || AXIS_DRIVER_TYPE(A,TMC2240) ) #define AXIS_HAS_COOLSTEP(A) ( AXIS_DRIVER_TYPE(A,TMC2130) \ - || AXIS_DRIVER_TYPE(A,TMC2209) \ + || AXIS_DRIVER_TYPE(A,TMC2209) || AXIS_DRIVER_TYPE(A,TMC2240) \ || AXIS_DRIVER_TYPE(A,TMC5130) || AXIS_DRIVER_TYPE(A,TMC5160) ) #define _OR_EAH(N,T) || AXIS_HAS_##T(E##N) @@ -195,6 +209,7 @@ #define THRS_TMC2160 255 #define THRS_TMC2208 255 #define THRS_TMC2209 255 +#define THRS_TMC2240 255 #define THRS_TMC2660 65535 #define THRS_TMC5130 65535 #define THRS_TMC5160 65535 diff --git a/Marlin/src/core/language.h b/Marlin/src/core/language.h index f64c7513df..837f3885b9 100644 --- a/Marlin/src/core/language.h +++ b/Marlin/src/core/language.h @@ -88,6 +88,7 @@ #undef MACHINE_NAME #define MACHINE_NAME DEFAULT_MACHINE_NAME #endif +#define MACHINE_NAME_SUBST TERN(CONFIGURABLE_MACHINE_NAME, "$", MACHINE_NAME) #define MARLIN_WEBSITE_URL "marlinfw.org" @@ -209,6 +210,8 @@ #define STR_KILL_BUTTON "KILL button/pin" // temperature.cpp strings +#define STR_WAIT_FOR_HOTEND "Wait for hotend heating..." +#define STR_WAIT_FOR_BED "Wait for bed heating..." #define STR_PID_AUTOTUNE "PID Autotune" #define STR_PID_AUTOTUNE_START " start" #define STR_PID_BAD_HEATER_ID " failed! Bad heater id" @@ -229,6 +232,8 @@ #define STR_PID_DEBUG_INPUT ": Input " #define STR_PID_DEBUG_OUTPUT " Output " #define STR_INVALID_EXTRUDER_NUM " - Invalid extruder number !" + +// MPCTEMP strings #define STR_MPC_AUTOTUNE_START "MPC Autotune start for " STR_E #define STR_MPC_AUTOTUNE_INTERRUPTED "MPC Autotune interrupted!" #define STR_MPC_AUTOTUNE_FINISHED "MPC Autotune finished! Put the constants below into Configuration.h" @@ -237,6 +242,7 @@ #define STR_MPC_MEASURING_AMBIENT "Measuring ambient heatloss at " #define STR_MPC_TEMPERATURE_ERROR "Temperature error" +// Temperature Sensors #define STR_HEATER_BED "bed" #define STR_HEATER_CHAMBER "chamber" #define STR_COOLER "cooler" @@ -246,6 +252,7 @@ #define STR_REDUNDANT "redundant " #define STR_LASER_TEMP "laser temperature" +// Misc. Errors, Thermal Runaway #define STR_STOPPED_HEATER ", system stopped! Heater_ID: " #define STR_DETECTED_TEMP_B " (temp: " #define STR_DETECTED_TEMP_E ")" @@ -268,6 +275,7 @@ #define STR_DEBUG_COMMUNICATION "COMMUNICATION" #define STR_DEBUG_DETAIL "DETAIL" +// Password Security #define STR_PRINTER_LOCKED "Printer locked! (Unlock with M511 or LCD)" #define STR_WRONG_PASSWORD "Incorrect Password" #define STR_PASSWORD_TOO_LONG "Password too long" @@ -295,6 +303,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" @@ -311,8 +320,9 @@ #define STR_FILAMENT_RUNOUT_SENSOR "Filament runout sensor" #define STR_DRIVER_STEPPING_MODE "Driver stepping mode" #define STR_STEPPER_DRIVER_CURRENT "Stepper driver current" +#define STR_HOMING_CURRENT "Homing Current (mA)" #define STR_HYBRID_THRESHOLD "Hybrid Threshold" -#define STR_STALLGUARD_THRESHOLD "StallGuard threshold" +#define STR_STALLGUARD_THRESHOLD "StallGuard Threshold" #define STR_HOME_OFFSET "Home offset" #define STR_SOFT_ENDSTOPS "Soft endstops" #define STR_MATERIAL_HEATUP "Material heatup parameters" @@ -356,6 +366,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 diff --git a/Marlin/src/core/macros.h b/Marlin/src/core/macros.h index e3fd9b6609..4f6b1df98b 100644 --- a/Marlin/src/core/macros.h +++ b/Marlin/src/core/macros.h @@ -25,12 +25,6 @@ #define __has_include(...) 1 #endif -#define ABCE 4 -#define XYZE 4 -#define ABC 3 -#define XYZ 3 -#define XY 2 - #define _AXIS(A) (A##_AXIS) #define _FORCE_INLINE_ __attribute__((__always_inline__)) __inline__ @@ -58,6 +52,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" @@ -80,6 +75,7 @@ #define CBI32(n,b) (n &= ~_BV32(b)) #define TBI32(N,B) (N ^= _BV32(B)) +// Macros for common maths operations #define cu(x) ({__typeof__(x) _x = (x); (_x)*(_x)*(_x);}) #define RADIANS(d) ((d)*float(M_PI)/180.0f) #define DEGREES(r) ((r)*180.0f/float(M_PI)) @@ -93,6 +89,8 @@ #define SIGN(a) ({__typeof__(a) _a = (a); (_a>0)-(_a<0);}) #define IS_POWER_OF_2(x) ((x) && !((x) & ((x) - 1))) +#define FLIP(X) (X = !(X)) + // Macros to constrain values #ifdef __cplusplus @@ -203,19 +201,26 @@ #define TERN(O,A,B) _TERN(_ENA_1(O),B,A) // OPTION ? 'A' : 'B' #define TERN0(O,A) _TERN(_ENA_1(O),0,A) // OPTION ? 'A' : '0' #define TERN1(O,A) _TERN(_ENA_1(O),1,A) // OPTION ? 'A' : '1' -#define TERN_(O,A) _TERN(_ENA_1(O),,A) // OPTION ? 'A' : '' #define _TERN(E,V...) __TERN(_CAT(T_,E),V) // Prepend 'T_' to get 'T_0' or 'T_1' #define __TERN(T,V...) ___TERN(_CAT(_NO,T),V) // Prepend '_NO' to get '_NOT_0' or '_NOT_1' #define ___TERN(P,V...) THIRD(P,V) // If first argument has a comma, A. Else B. #define IF_DISABLED(O,A) TERN(O,,A) +// "Ternary" that emits or omits the given content +#define EMIT(V...) V +#define OMIT(...) +#define TERN_(O,A) TERF(O,EMIT)(A) // OPTION ? 'A' : '' ; Usage: TERN_(OPTION, EMITTHIS) + +// Call G(...) or swallow with OMIT(...) +#define TERF(O,G) _TERN(_ENA_1(O),OMIT,G) // OPTION ? 'G' : 'OMIT' ; Usage: TERF(OPTION, CALLTHIS)(ARGS...) + // Macros to conditionally emit array items and function arguments #define _OPTITEM(A...) A, -#define OPTITEM(O,A...) TERN_(O,DEFER4(_OPTITEM)(A)) +#define OPTITEM(O,A...) TERN_(O,DEFER(_OPTITEM)(A)) #define _OPTARG(A...) , A -#define OPTARG(O,A...) TERN_(O,DEFER4(_OPTARG)(A)) +#define OPTARG(O,A...) TERN_(O,DEFER(_OPTARG)(A)) #define _OPTCODE(A) A; -#define OPTCODE(O,A) TERN_(O,DEFER4(_OPTCODE)(A)) +#define OPTCODE(O,A) TERN_(O,DEFER(_OPTCODE)(A)) // Macros to avoid operations that aren't always optimized away (e.g., 'f + 0.0' and 'f * 1.0'). // Compiler flags -fno-signed-zeros -ffinite-math-only also cover 'f * 1.0', 'f - f', etc. @@ -300,6 +305,12 @@ #define GANG_N_1(N,K) _GANG_N(N,K,K,K,K,K,K,K,K,K,K,K,K,K,K,K,K) // Expansion of some list items +#define LIST_32(A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z,AA,BB,CC,DD,EE,FF,...) A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z,AA,BB,CC,DD,EE,FF +#define LIST_31(A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z,AA,BB,CC,DD,EE,...) A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z,AA,BB,CC,DD,EE +#define LIST_30(A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z,AA,BB,CC,DD,...) A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z,AA,BB,CC,DD +#define LIST_29(A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z,AA,BB,CC,...) A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z,AA,BB,CC +#define LIST_28(A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z,AA,BB,...) A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,TU,V,W,X,Y,Z,AA,BB +#define LIST_27(A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z,AA,...) A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z,AA #define LIST_26(A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z,...) A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z #define LIST_25(A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,...) A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y #define LIST_24(A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,...) A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X @@ -540,6 +551,9 @@ #endif +// Limit an index to an array size +#define ALIM(I,ARR) _MIN(I, (signed)COUNT(ARR) - 1) + // Macros for adding #define INC_0 1 #define INC_1 2 @@ -562,6 +576,17 @@ #define INC_18 19 #define INC_19 20 #define INC_20 21 +#define INC_21 22 +#define INC_22 23 +#define INC_23 24 +#define INC_24 25 +#define INC_25 26 +#define INC_26 27 +#define INC_27 28 +#define INC_28 29 +#define INC_29 30 +#define INC_30 31 +#define INC_31 32 #define INCREMENT_(n) INC_##n #define INCREMENT(n) INCREMENT_(n) @@ -597,6 +622,23 @@ #define DEC_13 12 #define DEC_14 13 #define DEC_15 14 +#define DEC_16 15 +#define DEC_17 16 +#define DEC_18 17 +#define DEC_19 18 +#define DEC_20 19 +#define DEC_21 20 +#define DEC_22 21 +#define DEC_23 22 +#define DEC_24 23 +#define DEC_25 24 +#define DEC_26 25 +#define DEC_27 26 +#define DEC_28 27 +#define DEC_29 28 +#define DEC_30 29 +#define DEC_31 30 +#define DEC_32 31 #define DECREMENT_(n) DEC_##n #define DECREMENT(n) DECREMENT_(n) @@ -651,11 +693,8 @@ #define IF_ELSE(TF) _IF_ELSE(_BOOL(TF)) #define _IF_ELSE(TF) _CAT(_IF_, TF) -#define _IF_1(V...) V _IF_1_ELSE -#define _IF_0(...) _IF_0_ELSE - -#define _IF_1_ELSE(...) -#define _IF_0_ELSE(V...) V +#define _IF_1(V...) V OMIT +#define _IF_0(...) EMIT #define HAS_ARGS(V...) _BOOL(FIRST(_END_OF_ARGUMENTS_ V)()) #define _END_OF_ARGUMENTS_() 0 diff --git a/Marlin/src/core/millis_t.h b/Marlin/src/core/millis_t.h index e7032a2e55..1d3cc853b3 100644 --- a/Marlin/src/core/millis_t.h +++ b/Marlin/src/core/millis_t.h @@ -30,5 +30,7 @@ typedef uint32_t millis_t; #define MS_TO_SEC(N) millis_t((N)/1000UL) #define MS_TO_SEC_PRECISE(N) (float(N)/1000.0f) -#define PENDING(NOW,SOON) ((int32_t)(NOW-(SOON))<0) -#define ELAPSED(NOW,SOON) (!PENDING(NOW,SOON)) +constexpr bool _PENDING(const millis_t now, const millis_t when) { return int32_t(when - now) > 0; } +constexpr bool _PENDING(const millis_t now, const millis_t start, const millis_t interval) { return (now - start) < interval; } +#define PENDING(V...) _PENDING(V) +#define ELAPSED(V...) !_PENDING(V) diff --git a/Marlin/src/core/mstring.h b/Marlin/src/core/mstring.h index b405262d30..3ed21950de 100644 --- a/Marlin/src/core/mstring.h +++ b/Marlin/src/core/mstring.h @@ -158,16 +158,16 @@ public: MString& append_P(PGM_P const s) { int sz = length(); if (sz < SIZE) strlcpy_P(str + sz, s, SIZE - sz + 1); debug(F("pstring")); return *this; } MString& append(FSTR_P const f) { return append_P(FTOP(f)); } MString& append(const bool &b) { return append(b ? F("true") : F("false")); } - MString& append(const char c) { int sz = length(); if (sz < SIZE) { str[sz] = c; if (sz < SIZE - 1) str[sz + 1] = '\0'; } return *this; } + MString& append(const char c) { int sz = length(); if (sz < SIZE) { str[sz] = c; if (sz < SIZE - 1) str[sz + 1] = '\0'; } debug(F("char")); return *this; } #if ENABLED(FASTER_APPEND) - MString& append(const int8_t &i) { int sz = length(); SNPRINTF(&str[sz], SIZE - sz, "%d", i); return *this; } - MString& append(const short &i) { int sz = length(); SNPRINTF(&str[sz], SIZE - sz, "%d", i); return *this; } - MString& append(const int &i) { int sz = length(); SNPRINTF(&str[sz], SIZE - sz, "%d", i); return *this; } - MString& append(const long &l) { int sz = length(); SNPRINTF(&str[sz], SIZE - sz, "%ld", l); return *this; } - MString& append(const unsigned char &i) { int sz = length(); SNPRINTF(&str[sz], SIZE - sz, "%u", i); return *this; } - MString& append(const unsigned short &i) { int sz = length(); SNPRINTF(&str[sz], SIZE - sz, "%u", i); return *this; } - MString& append(const unsigned int &i) { int sz = length(); SNPRINTF(&str[sz], SIZE - sz, "%u", i); return *this; } - MString& append(const unsigned long &l) { int sz = length(); SNPRINTF(&str[sz], SIZE - sz, "%lu", l); return *this; } + MString& append(const int8_t &i) { int sz = length(); SNPRINTF(&str[sz], SIZE - sz, "%d", i); debug(F("int8_t")); return *this; } + MString& append(const short &i) { int sz = length(); SNPRINTF(&str[sz], SIZE - sz, "%d", i); debug(F("short")); return *this; } + MString& append(const int &i) { int sz = length(); SNPRINTF(&str[sz], SIZE - sz, "%d", i); debug(F("int")); return *this; } + MString& append(const long &l) { int sz = length(); SNPRINTF(&str[sz], SIZE - sz, "%ld", l); debug(F("long")); return *this; } + MString& append(const unsigned char &i) { int sz = length(); SNPRINTF(&str[sz], SIZE - sz, "%u", i); debug(F("uchar")); return *this; } + MString& append(const unsigned short &i) { int sz = length(); SNPRINTF(&str[sz], SIZE - sz, "%u", i); debug(F("ushort")); return *this; } + MString& append(const unsigned int &i) { int sz = length(); SNPRINTF(&str[sz], SIZE - sz, "%u", i); debug(F("uint")); return *this; } + MString& append(const unsigned long &l) { int sz = length(); SNPRINTF(&str[sz], SIZE - sz, "%lu", l); debug(F("ulong")); return *this; } #else MString& append(const int8_t &i) { char buf[ 5]; sprintf(buf, "%d", i); return append(buf); } MString& append(const short &i) { char buf[12]; sprintf(buf, "%d", i); return append(buf); } @@ -280,12 +280,11 @@ public: // Quick hash to detect change (e.g., to avoid expensive drawing) typedef IF::type hash_t; hash_t hash() const { + const int sz = length(); #if ENABLED(DJB2_HASH) hash_t hval = 5381; - char c; - while ((c = *str++)) hval += (hval << 5) + c; // = hval * 33 + c + for (int i = 0; i < sz; i++) hval += (hval << 5) + str[i]; // = hval * 33 + c #else - const int sz = length(); hash_t hval = hash_t(sz); for (int i = 0; i < sz; i++) hval = ((hval << 1) | (hval >> 15)) ^ str[i]; // ROL, XOR #endif @@ -298,6 +297,9 @@ public: MString& clear() { return set(); } MString& eol() { return append('\n'); } MString& trunc(const int &i) { if (i <= SIZE) str[i] = '\0'; debug(F("trunc")); return *this; } + MString& ltrim() { char *s = str; while (*s == ' ') ++s; if (s != str) strcpy(str, s); return *this; } + MString& rtrim() { int s = length(); while (s && str[s - 1] == ' ') --s; str[s] = '\0'; return *this; } + MString& trim() { return rtrim().ltrim(); } // Truncate on a Unicode boundary MString& utrunc(const int &n=SIZE) { diff --git a/Marlin/src/core/serial.cpp b/Marlin/src/core/serial.cpp index 8a8378330f..852cfc77f6 100644 --- a/Marlin/src/core/serial.cpp +++ b/Marlin/src/core/serial.cpp @@ -99,7 +99,7 @@ void SERIAL_WARN_START() { SERIAL_ECHO(F("Warning:")); } void SERIAL_ECHO_SP(uint8_t count) { count *= (PROPORTIONAL_FONT_RATIO); while (count--) SERIAL_CHAR(' '); } -void serial_offset(const_float_t v, const uint8_t sp/*=0*/) { +void serial_offset(const float v, const uint8_t sp/*=0*/) { if (v == 0 && sp == 1) SERIAL_CHAR(' '); else if (v > 0 || (v == 0 && sp == 2)) @@ -114,10 +114,6 @@ void serial_ternary(FSTR_P const pre, const bool onoff, FSTR_P const on, FSTR_P if (post) SERIAL_ECHO(post); } -void serialprint_onoff(const bool onoff) { SERIAL_ECHO(onoff ? F(STR_ON) : F(STR_OFF)); } -void serialprintln_onoff(const bool onoff) { serialprint_onoff(onoff); SERIAL_EOL(); } -void serialprint_truefalse(const bool tf) { SERIAL_ECHO(tf ? F("true") : F("false")); } - void print_bin(uint16_t val) { for (uint8_t i = 16; i--;) { SERIAL_CHAR('0' + TEST(val, i)); @@ -125,21 +121,23 @@ void print_bin(uint16_t val) { } } -void _print_xyz(NUM_AXIS_ARGS_(const_float_t) FSTR_P const prefix) { +void _print_xyz(NUM_AXIS_ARGS_(const float) FSTR_P const prefix) { if (prefix) SERIAL_ECHO(prefix); #if NUM_AXES - SERIAL_ECHOPGM_P( - LIST_N(DOUBLE(NUM_AXES), SP_X_STR, x, SP_Y_STR, y, SP_Z_STR, z, SP_I_STR, i, SP_J_STR, j, SP_K_STR, k, SP_U_STR, u, SP_V_STR, v, SP_W_STR, w) - ); + SERIAL_ECHOPGM_P(NUM_AXIS_PAIRED_LIST( + SP_X_STR, x, SP_Y_STR, y, SP_Z_STR, z, + SP_I_STR, i, SP_J_STR, j, SP_K_STR, k, + SP_U_STR, u, SP_V_STR, v, SP_W_STR, w + )); #endif } -void print_xyz(NUM_AXIS_ARGS_(const_float_t) FSTR_P const prefix/*=nullptr*/, FSTR_P const suffix/*=nullptr*/) { +void print_xyz(NUM_AXIS_ARGS_(const float) FSTR_P const prefix/*=nullptr*/, FSTR_P const suffix/*=nullptr*/) { _print_xyz(NUM_AXIS_LIST_(x, y, z, i, j, k, u, v, w) prefix); if (suffix) SERIAL_ECHO(suffix); else SERIAL_EOL(); } -void print_xyze(LOGICAL_AXIS_ARGS_(const_float_t) FSTR_P const prefix/*=nullptr*/, FSTR_P const suffix/*=nullptr*/) { +void print_xyze(LOGICAL_AXIS_ARGS_(const float) FSTR_P const prefix/*=nullptr*/, FSTR_P const suffix/*=nullptr*/) { _print_xyz(NUM_AXIS_LIST_(x, y, z, i, j, k, u, v, w) prefix); #if HAS_EXTRUDERS SERIAL_ECHOPGM_P(SP_E_STR, e); diff --git a/Marlin/src/core/serial.h b/Marlin/src/core/serial.h index 97f31dea35..6c73d72a22 100644 --- a/Marlin/src/core/serial.h +++ b/Marlin/src/core/serial.h @@ -185,7 +185,7 @@ void SERIAL_ECHOLN(T arg1, Args ... args) { SERIAL_ECHO(arg1); SERIAL_ECHO(args // all the odd loose string elements as PROGMEM strings. // -// Print up to 20 pairs of values. Odd elements must be literal strings. +// Print pairs of values. Odd elements must be literal strings. #define __SEP_N(N,V...) _SEP_##N(V) #define _SEP_N(N,V...) __SEP_N(N,V) #define _SEP_N_REF() _SEP_N @@ -194,7 +194,7 @@ void SERIAL_ECHOLN(T arg1, Args ... args) { SERIAL_ECHO(arg1); SERIAL_ECHO(args #define _SEP_3(s,v,V...) _SEP_2(s,v); DEFER2(_SEP_N_REF)()(TWO_ARGS(V),V); #define SERIAL_ECHOPGM(V...) do{ EVAL(_SEP_N(TWO_ARGS(V),V)); }while(0) -// Print up to 20 pairs of values followed by newline. Odd elements must be literal strings. +// Print pairs of values followed by newline. Odd elements must be literal strings. #define __SELP_N(N,V...) _SELP_##N(V) #define _SELP_N(N,V...) __SELP_N(N,V) #define _SELP_N_REF() _SELP_N @@ -203,7 +203,7 @@ void SERIAL_ECHOLN(T arg1, Args ... args) { SERIAL_ECHO(arg1); SERIAL_ECHO(args #define _SELP_3(s,v,V...) _SEP_2(s,v); DEFER2(_SELP_N_REF)()(TWO_ARGS(V),V); #define SERIAL_ECHOLNPGM(V...) do{ EVAL(_SELP_N(TWO_ARGS(V),V)); }while(0) -// Print up to 20 pairs of values. Odd elements must be PSTR pointers. +// Print pairs of values. Odd elements must be PSTR pointers. #define __SEP_N_P(N,V...) _SEP_##N##_P(V) #define _SEP_N_P(N,V...) __SEP_N_P(N,V) #define _SEP_N_P_REF() _SEP_N_P @@ -212,7 +212,7 @@ void SERIAL_ECHOLN(T arg1, Args ... args) { SERIAL_ECHO(arg1); SERIAL_ECHO(args #define _SEP_3_P(p,v,V...) _SEP_2_P(p,v); DEFER2(_SEP_N_P_REF)()(TWO_ARGS(V),V); #define SERIAL_ECHOPGM_P(V...) do{ EVAL(_SEP_N_P(TWO_ARGS(V),V)); }while(0) -// Print up to 20 pairs of values followed by newline. Odd elements must be PSTR pointers. +// Print pairs of values followed by newline. Odd elements must be PSTR pointers. #define __SELP_N_P(N,V...) _SELP_##N##_P(V) #define _SELP_N_P(N,V...) __SELP_N_P(N,V) #define _SELP_N_P_REF() _SELP_N_P @@ -233,19 +233,19 @@ void serial_ternary(FSTR_P const pre, const bool onoff, FSTR_P const on, FSTR_P // Print up to 255 spaces void SERIAL_ECHO_SP(uint8_t count); -void serialprint_onoff(const bool onoff); -void serialprintln_onoff(const bool onoff); -void serialprint_truefalse(const bool tf); -void serial_offset(const_float_t v, const uint8_t sp=0); // For v==0 draw space (sp==1) or plus (sp==2) +inline FSTR_P const ON_OFF(const bool onoff) { return onoff ? F("ON") : F("OFF"); } +inline FSTR_P const TRUE_FALSE(const bool tf) { return tf ? F("true") : F("false"); } + +void serial_offset(const float v, const uint8_t sp=0); // For v==0 draw space (sp==1) or plus (sp==2) void print_bin(const uint16_t val); -void print_xyz(NUM_AXIS_ARGS_(const_float_t) FSTR_P const prefix=nullptr, FSTR_P const suffix=nullptr); +void print_xyz(NUM_AXIS_ARGS_(const float) FSTR_P const prefix=nullptr, FSTR_P const suffix=nullptr); inline void print_xyz(const xyz_pos_t &xyz, FSTR_P const prefix=nullptr, FSTR_P const suffix=nullptr) { print_xyz(NUM_AXIS_ELEM_(xyz) prefix, suffix); } -void print_xyze(LOGICAL_AXIS_ARGS_(const_float_t) FSTR_P const prefix=nullptr, FSTR_P const suffix=nullptr); +void print_xyze(LOGICAL_AXIS_ARGS_(const float) FSTR_P const prefix=nullptr, FSTR_P const suffix=nullptr); inline void print_xyze(const xyze_pos_t &xyze, FSTR_P const prefix=nullptr, FSTR_P const suffix=nullptr) { print_xyze(LOGICAL_AXIS_ELEM_LC_(xyze) prefix, suffix); } diff --git a/Marlin/src/core/serial_base.h b/Marlin/src/core/serial_base.h index a2f49417b7..07bed55b35 100644 --- a/Marlin/src/core/serial_base.h +++ b/Marlin/src/core/serial_base.h @@ -220,7 +220,7 @@ struct SerialBase { // On non 2-complement CPU, there would be no possible representation for 2147483648. write('-'); } - printNumber_unsigned((uint_fixed_print_t)n , base); + printNumber_unsigned((uint_fixed_print_t)n, base); } // Print a decimal number @@ -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" diff --git a/Marlin/src/core/types.h b/Marlin/src/core/types.h index 74570ced76..b4d7705ffd 100644 --- a/Marlin/src/core/types.h +++ b/Marlin/src/core/types.h @@ -50,6 +50,7 @@ template struct IF { typedef L type; }; #define NUM_AXIS_DECL_LC(T,V) NUM_AXIS_LIST(T x=V, T y=V, T z=V, T i=V, T j=V, T k=V, T u=V, T v=V, T w=V) #define MAIN_AXIS_NAMES NUM_AXIS_LIST(X, Y, Z, I, J, K, U, V, W) #define MAIN_AXIS_NAMES_LC NUM_AXIS_LIST(x, y, z, i, j, k, u, v, w) +#define NUM_AXIS_CALL(G) do { NUM_AXIS_CODE(G(X_AXIS), G(Y_AXIS), G(Z_AXIS), G(I_AXIS), G(J_AXIS), G(K_AXIS), G(U_AXIS), G(V_AXIS), G(W_AXIS)); } while(0) #define STR_AXES_MAIN NUM_AXIS_GANG("X", "Y", "Z", STR_I, STR_J, STR_K, STR_U, STR_V, STR_W) #define LOGICAL_AXIS_GANG(N,V...) NUM_AXIS_GANG(V) GANG_ITEM_E(N) @@ -68,8 +69,12 @@ template struct IF { typedef L type; }; #define LOGICAL_AXIS_NAMES_LC LOGICAL_AXIS_LIST(e, x, y, z, i, j, k, u, v, w) #define LOGICAL_AXIS_MAP(F) MAP(F, LOGICAL_AXIS_NAMES) #define LOGICAL_AXIS_MAP_LC(F) MAP(F, LOGICAL_AXIS_NAMES_LC) +#define LOGICAL_AXIS_CALL(G) do { LOGICAL_AXIS_CODE(G(E_AXIS), G(X_AXIS), G(Y_AXIS), G(Z_AXIS), G(I_AXIS), G(J_AXIS), G(K_AXIS), G(U_AXIS), G(V_AXIS), G(W_AXIS)); } while(0) #define STR_AXES_LOGICAL LOGICAL_AXIS_GANG("E", "X", "Y", "Z", STR_I, STR_J, STR_K, STR_U, STR_V, STR_W) +#define NUM_AXIS_PAIRED_LIST(V...) LIST_N(DOUBLE(NUM_AXES), V) +#define LOGICAL_AXIS_PAIRED_LIST(EA,EB,V...) NUM_AXIS_PAIRED_LIST(V) LIST_ITEM_E(EA) LIST_ITEM_E(EB) + #if NUM_AXES #define NUM_AXES_SEP , #define MAIN_AXIS_MAP(F) MAP(F, MAIN_AXIS_NAMES) @@ -164,11 +169,27 @@ template struct IF { 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_AXIS_NAMES_LC 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 #define _RECIP(N) ((N) ? 1.0f / static_cast(N) : 0.0f) -#define _ABS(N) ((N) < 0 ? -(N) : (N)) +#define _ABS(N) ((N) < decltype(N)(0) ? -(N) : (N)) #define _LS(N) T(uint32_t(N) << p) #define _RS(N) T(uint32_t(N) >> p) #define _LSE(N) N = T(uint32_t(N) << p) @@ -180,6 +201,8 @@ template struct IF { typedef L type; }; #define uvalue_t(V) typename IF<((V)>65535), uint32_t, typename IF<((V)>255), uint16_t, uint8_t>::type>::type #define value_t(V) typename IF<((V)>32767), int32_t, typename IF<((V)>127), int16_t, int8_t>::type>::type +class BitProxy; + // Define a template for a bit field of N bits, using the smallest type that can hold N bits template 64)> struct Flags; @@ -218,6 +241,24 @@ struct Flags { 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& operator|=(Flags &p) const { b |= p.b; return *this; } + FI Flags& operator&=(Flags &p) const { b &= p.b; return *this; } + FI Flags& operator^=(Flags &p) const { b ^= p.b; return *this; } + + FI Flags& operator|=(const flagbits_t &p) { b |= flagbits_t(p); return *this; } + FI Flags& operator&=(const flagbits_t &p) { b &= flagbits_t(p); return *this; } + FI Flags& operator^=(const flagbits_t &p) { b ^= flagbits_t(p); return *this; } + + FI Flags operator|(Flags &p) const { return Flags(b | p.b); } + FI Flags operator&(Flags &p) const { return Flags(b & p.b); } + FI Flags operator^(Flags &p) const { return Flags(b ^ p.b); } + FI Flags operator~() const { return Flags(~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 @@ -352,23 +393,12 @@ typedef float feedRate_t; // // celsius_t is the native unit of temperature. Signed to handle a disconnected thermistor value (-14). -// For more resolition (e.g., for a chocolate printer) this may later be changed to Celsius x 100 +// For more resolution (e.g., for a chocolate printer) this may later be changed to Celsius x 100 // typedef uint16_t raw_adc_t; typedef int16_t celsius_t; typedef float celsius_float_t; -// -// On AVR pointers are only 2 bytes so use 'const float &' for 'const float' -// -#ifdef __AVR__ - typedef const float & const_float_t; -#else - typedef const float const_float_t; -#endif -typedef const_float_t const_feedRate_t; -typedef const_float_t const_celsius_float_t; - // Type large enough to count leveling grid points typedef IF 255)), uint16_t, uint8_t>::type grid_count_t; @@ -377,7 +407,7 @@ typedef IF 255)), uint16_t, uint8_t>::ty #define MMS_TO_MMM(MM_S) (static_cast(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 @@ -483,7 +513,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); @@ -514,9 +544,9 @@ struct XYval { #endif #if HAS_Y_AXIS FI void set(const T px, const T py) { x = px; y = py; } - FI void set(const T (&arr)[XY]) { x = arr[0]; y = arr[1]; } + FI void set(const T (&arr)[2]) { x = arr[0]; y = arr[1]; } #endif - #if NUM_AXES > XY + #if NUM_AXES > 2 FI void set(const T (&arr)[NUM_AXES]) { x = arr[0]; y = arr[1]; } #endif #if LOGICAL_AXES > NUM_AXES @@ -527,7 +557,7 @@ struct XYval { #endif // Length reduced to one dimension - FI constexpr T magnitude() const { return (T)sqrtf(x*x + y*y); } + FI constexpr T magnitude() const { return (T)SQRT(x*x + y*y); } // Pointer to the data as a simple array explicit FI operator T* () { return pos; } // If any element is true then it's true @@ -538,13 +568,18 @@ struct XYval { FI constexpr T large() const { return _MAX(x, y); } // Explicit copy and copies with conversion - FI constexpr XYval copy() const { return *this; } - FI constexpr XYval ABS() const { return { T(_ABS(x)), T(_ABS(y)) }; } - FI constexpr XYval asInt() const { return { int16_t(x), int16_t(y) }; } - FI constexpr XYval asLong() const { return { int32_t(x), int32_t(y) }; } - FI constexpr XYval ROUNDL() const { return { int32_t(LROUND(x)), int32_t(LROUND(y)) }; } - FI constexpr XYval asFloat() const { return { static_cast(x), static_cast(y) }; } - FI constexpr XYval reciprocal() const { return { _RECIP(x), _RECIP(y) }; } + FI constexpr XYval copy() const { return *this; } + FI constexpr XYval ABS() const { return { T(_ABS(x)), T(_ABS(y)) }; } + FI constexpr XYval ROUNDL() const { return { int32_t(LROUND(x)), int32_t(LROUND(y)) }; } + FI constexpr XYval reciprocal() const { return { _RECIP(x), _RECIP(y) }; } + + // Conversion to other types + FI constexpr XYval asInt16() const { return { int16_t(x), int16_t(y) }; } + FI constexpr XYval asInt32() const { return { int32_t(x), int32_t(y) }; } + FI constexpr XYval asUInt32() const { return { uint32_t(x), uint32_t(y) }; } + FI constexpr XYval asInt64() const { return { int64_t(x), int64_t(y) }; } + FI constexpr XYval asUInt64() const { return { uint64_t(x), uint64_t(y) }; } + FI constexpr XYval asFloat() const { return { static_cast(x), static_cast(y) }; } // Marlin workspace shifting is done with G92 and M206 FI XYval asLogical() const { XYval o = asFloat(); toLogical(o); return o; } @@ -564,11 +599,11 @@ struct XYval { FI XYval& operator= (const XYZEval &rs) { set(XY_LIST(rs.x, rs.y)); return *this; } // Override other operators to get intuitive behaviors - #define XY_OP(OP) { x TERN_(HAS_X_AXIS, OP rs.x), y TERN_(HAS_Y_AXIS, OP rs.y) } - FI constexpr XYval operator+ (const XYval &rs) const { return { x + rs.x, y + rs.y }; } - FI constexpr XYval operator- (const XYval &rs) const { return { x - rs.x, y - rs.y }; } - FI constexpr XYval operator* (const XYval &rs) const { return { x * rs.x, y * rs.y }; } - FI constexpr XYval operator/ (const XYval &rs) const { return { x / rs.x, y / rs.y }; } + #define XY_OP(OP) { T(x TERN_(HAS_X_AXIS, OP rs.x)), T(y TERN_(HAS_Y_AXIS, OP rs.y)) } + FI constexpr XYval operator+ (const XYval &rs) const { return { T(x + rs.x), T(y + rs.y) }; } + FI constexpr XYval operator- (const XYval &rs) const { return { T(x - rs.x), T(y - rs.y) }; } + FI constexpr XYval operator* (const XYval &rs) const { return { T(x * rs.x), T(y * rs.y) }; } + FI constexpr XYval operator/ (const XYval &rs) const { return { T(x / rs.x), T(y / rs.y) }; } FI constexpr XYval operator+ (const XYZval &rs) const { return { XY_OP(+) }; } FI constexpr XYval operator- (const XYZval &rs) const { return { XY_OP(-) }; } FI constexpr XYval operator* (const XYZval &rs) const { return { XY_OP(*) }; } @@ -616,6 +651,26 @@ struct XYval { FI bool operator!=(const XYval &rs) const { return !operator==(rs); } FI bool operator!=(const XYZval &rs) const { return !operator==(rs); } FI bool operator!=(const XYZEval &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 &rs) const { return x < rs.x && y < rs.y; } + FI bool operator<=(const XYval &rs) const { return x <= rs.x && y <= rs.y; } + FI bool operator> (const XYval &rs) const { return x > rs.x && y > rs.y; } + FI bool operator>=(const XYval &rs) const { return x >= rs.x && y >= rs.y; } + + FI bool operator< (const XYZval &rs) const { return true XY_GANG(&& x < rs.x, && y < rs.y); } + FI bool operator<=(const XYZval &rs) const { return true XY_GANG(&& x <= rs.x, && y <= rs.y); } + FI bool operator> (const XYZval &rs) const { return true XY_GANG(&& x > rs.x, && y > rs.y); } + FI bool operator>=(const XYZval &rs) const { return true XY_GANG(&& x >= rs.x, && y >= rs.y); } + + FI bool operator< (const XYZEval &rs) const { return true XY_GANG(&& x < rs.x, && y < rs.y); } + FI bool operator<=(const XYZEval &rs) const { return true XY_GANG(&& x <= rs.x, && y <= rs.y); } + FI bool operator> (const XYZEval &rs) const { return true XY_GANG(&& x > rs.x, && y > rs.y); } + FI bool operator>=(const XYZEval &rs) const { return true XY_GANG(&& x >= rs.x, && y >= rs.y); } + }; // @@ -638,8 +693,8 @@ struct XYZval { FI void reset() { NUM_AXIS_CODE(x = 0, y = 0, z = 0, i = 0, j = 0, k = 0, u = 0, v = 0, w = 0); } // Setters taking struct types and arrays - FI void set(const XYval pxy) { XY_CODE(x = pxy.x, y = pxy.y); } - FI void set(const XYval pxy, const T pz) { XYZ_CODE(x = pxy.x, y = pxy.y, z = pz); } + FI void set(const XYval &pxy) { XY_CODE(x = pxy.x, y = pxy.y); } + FI void set(const XYval &pxy, const T pz) { XYZ_CODE(x = pxy.x, y = pxy.y, z = pz); } FI void set(const T (&arr)[NUM_AXES]) { NUM_AXIS_CODE(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]); } #if LOGICAL_AXES > NUM_AXES FI void set(const T (&arr)[LOGICAL_AXES]) { NUM_AXIS_CODE(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]); } @@ -679,7 +734,7 @@ struct XYZval { #endif // Length reduced to one dimension - FI constexpr T magnitude() const { return (T)TERN(HAS_X_AXIS, sqrtf(NUM_AXIS_GANG(x*x, + y*y, + z*z, + i*i, + j*j, + k*k, + u*u, + v*v, + w*w)), 0); } + FI constexpr T magnitude() const { return (T)TERN(HAS_X_AXIS, SQRT(NUM_AXIS_GANG(x*x, + y*y, + z*z, + i*i, + j*j, + k*k, + u*u, + v*v, + w*w)), 0); } // Pointer to the data as a simple array explicit FI operator T* () { return pos; } // If any element is true then it's true @@ -692,12 +747,17 @@ struct XYZval { // Explicit copy and copies with conversion FI constexpr XYZval copy() const { XYZval o = *this; return o; } FI constexpr XYZval 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 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 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 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 asFloat() const { return NUM_AXIS_ARRAY(static_cast(x), static_cast(y), static_cast(z), static_cast(i), static_cast(j), static_cast(k), static_cast(u), static_cast(v), static_cast(w)); } FI constexpr XYZval 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 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 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 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 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 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 asFloat() const { return NUM_AXIS_ARRAY(static_cast(x), static_cast(y), static_cast(z), static_cast(i), static_cast(j), static_cast(k), static_cast(u), static_cast(v), static_cast(w)); } + // Marlin workspace shifting is done with G92 and M206 FI XYZval asLogical() const { XYZval o = asFloat(); toLogical(o); return o; } FI XYZval asNative() const { XYZval o = asFloat(); toNative(o); return o; } @@ -719,21 +779,21 @@ struct XYZval { FI XYZval& operator= (const XYZEval &rs) { set(NUM_AXIS_ELEM_LC(rs)); return *this; } // Override other operators to get intuitive behaviors - FI constexpr XYZval operator+ (const XYval &rs) const { return NUM_AXIS_ARRAY(x + rs.x, y + rs.y, z, i, j, k, u, v, w ); } - FI constexpr XYZval operator- (const XYval &rs) const { return NUM_AXIS_ARRAY(x - rs.x, y - rs.y, z, i, j, k, u, v, w ); } - FI constexpr XYZval operator* (const XYval &rs) const { return NUM_AXIS_ARRAY(x * rs.x, y * rs.y, z, i, j, k, u, v, w ); } - FI constexpr XYZval operator/ (const XYval &rs) const { return NUM_AXIS_ARRAY(x / rs.x, y / rs.y, z, i, j, k, u, v, w ); } - FI constexpr XYZval operator+ (const XYZval &rs) const { return NUM_AXIS_ARRAY(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 constexpr XYZval operator- (const XYZval &rs) const { return NUM_AXIS_ARRAY(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 constexpr XYZval operator* (const XYZval &rs) const { return NUM_AXIS_ARRAY(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 constexpr XYZval operator/ (const XYZval &rs) const { return NUM_AXIS_ARRAY(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 constexpr XYZval operator+ (const XYZEval &rs) const { return NUM_AXIS_ARRAY(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 constexpr XYZval operator- (const XYZEval &rs) const { return NUM_AXIS_ARRAY(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 constexpr XYZval operator* (const XYZEval &rs) const { return NUM_AXIS_ARRAY(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 constexpr XYZval operator/ (const XYZEval &rs) const { return NUM_AXIS_ARRAY(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 constexpr XYZval operator* (const float &p) const { return NUM_AXIS_ARRAY((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 XYZval operator+ (const XYval &rs) const { return NUM_AXIS_ARRAY(T(x + rs.x), T(y + rs.y), z, i, j, k, u, v, w ); } + FI constexpr XYZval operator- (const XYval &rs) const { return NUM_AXIS_ARRAY(T(x - rs.x), T(y - rs.y), z, i, j, k, u, v, w ); } + FI constexpr XYZval operator* (const XYval &rs) const { return NUM_AXIS_ARRAY(T(x * rs.x), T(y * rs.y), z, i, j, k, u, v, w ); } + FI constexpr XYZval operator/ (const XYval &rs) const { return NUM_AXIS_ARRAY(T(x / rs.x), T(y / rs.y), z, i, j, k, u, v, w ); } + FI constexpr XYZval operator+ (const XYZval &rs) const { return NUM_AXIS_ARRAY(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 XYZval operator- (const XYZval &rs) const { return NUM_AXIS_ARRAY(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 XYZval operator* (const XYZval &rs) const { return NUM_AXIS_ARRAY(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 XYZval operator/ (const XYZval &rs) const { return NUM_AXIS_ARRAY(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 XYZval operator+ (const XYZEval &rs) const { return NUM_AXIS_ARRAY(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 XYZval operator- (const XYZEval &rs) const { return NUM_AXIS_ARRAY(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 XYZval operator* (const XYZEval &rs) const { return NUM_AXIS_ARRAY(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 XYZval operator/ (const XYZEval &rs) const { return NUM_AXIS_ARRAY(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 XYZval operator* (const float &p) const { return NUM_AXIS_ARRAY(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 XYZval operator* (const int &p) const { return NUM_AXIS_ARRAY(x * p, y * p, z * p, i * p, j * p, k * p, u * p, v * p, w * p); } - FI constexpr XYZval operator/ (const float &p) const { return NUM_AXIS_ARRAY((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 XYZval operator/ (const float &p) const { return NUM_AXIS_ARRAY(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 XYZval operator/ (const int &p) const { return NUM_AXIS_ARRAY(x / p, y / p, z / p, i / p, j / p, k / p, u / p, v / p, w / p); } FI constexpr XYZval operator>>(const int &p) const { return NUM_AXIS_ARRAY(_RS(x), _RS(y), _RS(z), _RS(i), _RS(j), _RS(k), _RS(u), _RS(v), _RS(w)); } FI constexpr XYZval operator<<(const int &p) const { return NUM_AXIS_ARRAY(_LS(x), _LS(y), _LS(z), _LS(i), _LS(j), _LS(k), _LS(u), _LS(v), _LS(w)); } @@ -741,7 +801,7 @@ struct XYZval { // Absolute difference between two objects FI constexpr XYZval diff(const XYZEval &rs) const { return NUM_AXIS_ARRAY(T(_ABS(x - rs.x)), T(_ABS(y - rs.y)), T(_ABS(z - rs.z)), T(_ABS(i - rs.i)), T(_ABS(j - rs.j)), T(_ABS(k - rs.k)), T(_ABS(u - rs.u)), T(_ABS(v - rs.v)), T(_ABS(w - rs.w)) ); } - FI constexpr XYZval diff(const XYZval &rs) const { return NUM_AXIS_ARRAY(T(_ABS(x - rs.x)), T(_ABS(y - rs.y)), T(_ABS(z - rs.z)), T(_ABS(i - rs.i)), T(_ABS(j - rs.j)), T(_ABS(k - rs.k)), T(_ABS(u - rs.u)), T(_ABS(v - rs.v)), T(_ABS(w - rs.w)) ); } + FI constexpr XYZval diff(const XYZval &rs) const { return NUM_AXIS_ARRAY(T(_ABS(x - rs.x)), T(_ABS(y - rs.y)), T(_ABS(z - rs.z)), T(_ABS(i - rs.i)), T(_ABS(j - rs.j)), T(_ABS(k - rs.k)), T(_ABS(u - rs.u)), T(_ABS(v - rs.v)), T(_ABS(w - rs.w)) ); } FI constexpr XYZval diff(const XYval &rs) const { return NUM_AXIS_ARRAY(T(_ABS(x - rs.x)), T(_ABS(y - rs.y)), z, i, j, k, u, v, w ); } // Modifier operators @@ -759,12 +819,28 @@ struct XYZval { FI XYZval& operator/=(const XYZEval &rs) { NUM_AXIS_CODE(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); return *this; } FI XYZval& operator*=(const float &p) { NUM_AXIS_CODE(x *= p, y *= p, z *= p, i *= p, j *= p, k *= p, u *= p, v *= p, w *= p); return *this; } FI XYZval& operator*=(const int &p) { NUM_AXIS_CODE(x *= p, y *= p, z *= p, i *= p, j *= p, k *= p, u *= p, v *= p, w *= p); return *this; } + FI XYZval& operator/=(const float &p) { NUM_AXIS_CODE(x /= p, y /= p, z /= p, i /= p, j /= p, k /= p, u /= p, v /= p, w /= p); return *this; } FI XYZval& operator>>=(const int &p) { NUM_AXIS_CODE(_RSE(x), _RSE(y), _RSE(z), _RSE(i), _RSE(j), _RSE(k), _RSE(u), _RSE(v), _RSE(w)); return *this; } FI XYZval& 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 &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 &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 &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 &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 &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 &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 &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 &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 &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 &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 &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); } + }; // @@ -785,17 +861,17 @@ struct XYZEval { FI void reset() { LOGICAL_AXIS_GANG(e =, x =, y =, z =, i =, j =, k =, u =, v =, w =) 0; } // Setters taking struct types and arrays - FI void set(const XYval pxy) { XY_CODE(x = pxy.x, y = pxy.y); } - FI void set(const XYval pxy, const T pz) { XYZ_CODE(x = pxy.x, y = pxy.y, z = pz); } - FI void set(const XYZval pxyz) { set(NUM_AXIS_ELEM_LC(pxyz)); } - FI void set(const T (&arr)[NUM_AXES]) { NUM_AXIS_CODE(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 XYval &pxy) { XY_CODE(x = pxy.x, y = pxy.y); } + FI void set(const XYval &pxy, const T pz) { XYZ_CODE(x = pxy.x, y = pxy.y, z = pz); } + FI void set(const XYZval &pxyz) { set(NUM_AXIS_ELEM_LC(pxyz)); } + FI void set(const T (&arr)[NUM_AXES]) { NUM_AXIS_CODE(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]); } #if LOGICAL_AXES > NUM_AXES - FI void set(const T (&arr)[LOGICAL_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 XYval pxy, const T pz, const T pe) { set(pxy, pz); e = pe; } - FI void set(const XYZval 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); } + FI void set(const T (&arr)[LOGICAL_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 XYval &pxy, const T pz, const T pe) { set(pxy, pz); e = pe; } + FI void set(const XYZval &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 @@ -829,7 +905,7 @@ struct XYZEval { #endif // Length reduced to one dimension - FI constexpr T magnitude() const { return (T)sqrtf(LOGICAL_AXIS_GANG(+ e*e, + x*x, + y*y, + z*z, + i*i, + j*j, + k*k, + u*u, + v*v, + w*w)); } + FI constexpr T magnitude() const { return (T)SQRT(LOGICAL_AXIS_GANG(+ e*e, + x*x, + y*y, + z*z, + i*i, + j*j, + k*k, + u*u, + v*v, + w*w)); } // Pointer to the data as a simple array explicit FI operator T* () { return pos; } // If any element is true then it's true @@ -840,13 +916,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 copy() const { XYZEval v = *this; return v; } - FI constexpr XYZEval 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 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 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 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 asFloat() const { return LOGICAL_AXIS_ARRAY(static_cast(e), static_cast(x), static_cast(y), static_cast(z), static_cast(i), static_cast(j), static_cast(k), static_cast(u), static_cast(v), static_cast(w)); } - FI constexpr XYZEval 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 copy() const { XYZEval v = *this; return v; } + FI constexpr XYZEval 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 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 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 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 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 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 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 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 asFloat() const { return LOGICAL_AXIS_ARRAY(static_cast(e), static_cast(x), static_cast(y), static_cast(z), static_cast(i), static_cast(j), static_cast(k), static_cast(u), static_cast(v), static_cast(w)); } // Marlin workspace shifting is done with G92 and M206 FI XYZEval asLogical() const { XYZEval o = asFloat(); toLogical(o); return o; } @@ -868,21 +949,24 @@ struct XYZEval { FI XYZEval& operator= (const XYZval &rs) { set(NUM_AXIS_ELEM_LC(rs)); return *this; } // Override other operators to get intuitive behaviors - FI constexpr XYZEval operator+ (const XYval &rs) const { return LOGICAL_AXIS_ARRAY(e, x + rs.x, y + rs.y, z, i, j, k, u, v, w); } - FI constexpr XYZEval operator- (const XYval &rs) const { return LOGICAL_AXIS_ARRAY(e, x - rs.x, y - rs.y, z, i, j, k, u, v, w); } - FI constexpr XYZEval operator* (const XYval &rs) const { return LOGICAL_AXIS_ARRAY(e, x * rs.x, y * rs.y, z, i, j, k, u, v, w); } - FI constexpr XYZEval operator/ (const XYval &rs) const { return LOGICAL_AXIS_ARRAY(e, x / rs.x, y / rs.y, z, i, j, k, u, v, w); } - FI constexpr XYZEval operator+ (const XYZval &rs) const { return LOGICAL_AXIS_ARRAY(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 constexpr XYZEval operator- (const XYZval &rs) const { return LOGICAL_AXIS_ARRAY(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 constexpr XYZEval operator* (const XYZval &rs) const { return LOGICAL_AXIS_ARRAY(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 constexpr XYZEval operator/ (const XYZval &rs) const { return LOGICAL_AXIS_ARRAY(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 constexpr XYZEval operator+ (const XYZEval &rs) const { return LOGICAL_AXIS_ARRAY(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 constexpr XYZEval operator- (const XYZEval &rs) const { return LOGICAL_AXIS_ARRAY(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 constexpr XYZEval operator* (const XYZEval &rs) const { return LOGICAL_AXIS_ARRAY(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 constexpr XYZEval operator/ (const XYZEval &rs) const { return LOGICAL_AXIS_ARRAY(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 constexpr XYZEval 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 operator+ (const XYval &rs) const { return LOGICAL_AXIS_ARRAY(e, T(x + rs.x), T(y + rs.y), z, i, j, k, u, v, w); } + FI constexpr XYZEval operator- (const XYval &rs) const { return LOGICAL_AXIS_ARRAY(e, T(x - rs.x), T(y - rs.y), z, i, j, k, u, v, w); } + FI constexpr XYZEval operator* (const XYval &rs) const { return LOGICAL_AXIS_ARRAY(e, T(x * rs.x), T(y * rs.y), z, i, j, k, u, v, w); } + FI constexpr XYZEval operator/ (const XYval &rs) const { return LOGICAL_AXIS_ARRAY(e, T(x / rs.x), T(y / rs.y), z, i, j, k, u, v, w); } + FI constexpr XYZEval operator+ (const XYZval &rs) const { return LOGICAL_AXIS_ARRAY(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 operator- (const XYZval &rs) const { return LOGICAL_AXIS_ARRAY(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 operator* (const XYZval &rs) const { return LOGICAL_AXIS_ARRAY(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 operator/ (const XYZval &rs) const { return LOGICAL_AXIS_ARRAY(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 operator+ (const XYZEval &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 operator- (const XYZEval &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 operator* (const XYZEval &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 operator/ (const XYZEval &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 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 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 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 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 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 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 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 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 operator>>(const int &p) const { return LOGICAL_AXIS_ARRAY(_RS(e), _RS(x), _RS(y), _RS(z), _RS(i), _RS(j), _RS(k), _RS(u), _RS(v), _RS(w)); } FI constexpr XYZEval operator<<(const int &p) const { return LOGICAL_AXIS_ARRAY(_LS(e), _LS(x), _LS(y), _LS(z), _LS(i), _LS(j), _LS(k), _LS(u), _LS(v), _LS(w)); } @@ -890,8 +974,8 @@ struct XYZEval { // Absolute difference between two objects FI constexpr XYZEval diff(const XYZEval &rs) const { return LOGICAL_AXIS_ARRAY(T(_ABS(e - rs.e)), T(_ABS(x - rs.x)), T(_ABS(y - rs.y)), T(_ABS(z - rs.z)), T(_ABS(i - rs.i)), T(_ABS(j - rs.j)), T(_ABS(k - rs.k)), T(_ABS(u - rs.u)), T(_ABS(v - rs.v)), T(_ABS(w - rs.w)) ); } - FI constexpr XYZEval diff(const XYZval &rs) const { return LOGICAL_AXIS_ARRAY(0 , T(_ABS(x - rs.x)), T(_ABS(y - rs.y)), T(_ABS(z - rs.z)), T(_ABS(i - rs.i)), T(_ABS(j - rs.j)), T(_ABS(k - rs.k)), T(_ABS(u - rs.u)), T(_ABS(v - rs.v)), T(_ABS(w - rs.w)) ); } - FI constexpr XYZEval diff(const XYval &rs) const { return LOGICAL_AXIS_ARRAY(0 , T(_ABS(x - rs.x)), T(_ABS(y - rs.y)), z, i, j, k, u, v, w ); } + FI constexpr XYZEval diff(const XYZval &rs) const { return LOGICAL_AXIS_ARRAY(0, T(_ABS(x - rs.x)), T(_ABS(y - rs.y)), T(_ABS(z - rs.z)), T(_ABS(i - rs.i)), T(_ABS(j - rs.j)), T(_ABS(k - rs.k)), T(_ABS(u - rs.u)), T(_ABS(v - rs.v)), T(_ABS(w - rs.w)) ); } + FI constexpr XYZEval diff(const XYval &rs) const { return LOGICAL_AXIS_ARRAY(0, T(_ABS(x - rs.x)), T(_ABS(y - rs.y)), z, i, j, k, u, v, w ); } // Modifier operators FI XYZEval& operator+=(const XYval &rs) { XY_CODE(x += rs.x, y += rs.y); return *this; } @@ -906,19 +990,40 @@ struct XYZEval { FI XYZEval& operator-=(const XYZEval &rs) { LOGICAL_AXIS_CODE(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); return *this; } FI XYZEval& operator*=(const XYZEval &rs) { LOGICAL_AXIS_CODE(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); return *this; } FI XYZEval& operator/=(const XYZEval &rs) { LOGICAL_AXIS_CODE(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); return *this; } + FI XYZEval& operator+=(const T &p) { LOGICAL_AXIS_CODE(e += p, x += p, y += p, z += p, i += p, j += p, k += p, u += p, v += p, w += p); return *this; } + FI XYZEval& operator-=(const T &p) { LOGICAL_AXIS_CODE(e -= p, x -= p, y -= p, z -= p, i -= p, j -= p, k -= p, u -= p, v -= p, w -= p); return *this; } FI XYZEval& operator*=(const T &p) { LOGICAL_AXIS_CODE(e *= p, x *= p, y *= p, z *= p, i *= p, j *= p, k *= p, u *= p, v *= p, w *= p); return *this; } + FI XYZEval& operator/=(const T &p) { LOGICAL_AXIS_CODE(e /= p, x /= p, y /= p, z /= p, i /= p, j /= p, k /= p, u /= p, v /= p, w /= p); return *this; } FI XYZEval& operator>>=(const int &p) { LOGICAL_AXIS_CODE(_RSE(e), _RSE(x), _RSE(y), _RSE(z), _RSE(i), _RSE(j), _RSE(k), _RSE(u), _RSE(v), _RSE(w)); return *this; } FI XYZEval& 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 &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 &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 &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 &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 &rs) const { return !operator==(rs); } FI bool operator!=(const XYZEval &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 &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 &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 &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 &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 &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 &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 &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 &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 // for memset +// +// Axis indexed arrays of type T (x[SIZE], y[SIZE], etc.) +// template struct XYZarray { typedef T el[SIZE]; @@ -931,9 +1036,9 @@ struct XYZarray { }; FI void reset() { ZERO(data); } - FI void set(const int n, const XYval p) { NUM_AXIS_CODE(x[n]=p.x, y[n]=p.y,,,,,,,); } - FI void set(const int n, const XYZval p) { NUM_AXIS_CODE(x[n]=p.x, y[n]=p.y, z[n]=p.z, i[n]=p.i, j[n]=p.j, k[n]=p.k, u[n]=p.u, v[n]=p.v, w[n]=p.w ); } - FI void set(const int n, const XYZEval p) { NUM_AXIS_CODE(x[n]=p.x, y[n]=p.y, z[n]=p.z, i[n]=p.i, j[n]=p.j, k[n]=p.k, u[n]=p.u, v[n]=p.v, w[n]=p.w ); } + FI void set(const int n, const XYval &p) { NUM_AXIS_CODE(x[n]=p.x, y[n]=p.y,,,,,,,); } + FI void set(const int n, const XYZval &p) { NUM_AXIS_CODE(x[n]=p.x, y[n]=p.y, z[n]=p.z, i[n]=p.i, j[n]=p.j, k[n]=p.k, u[n]=p.u, v[n]=p.v, w[n]=p.w ); } + FI void set(const int n, const XYZEval &p) { NUM_AXIS_CODE(x[n]=p.x, y[n]=p.y, z[n]=p.z, i[n]=p.i, j[n]=p.j, k[n]=p.k, u[n]=p.u, v[n]=p.v, w[n]=p.w ); } // Setter for all individual args FI void set(const int n OPTARGS_NUM(const T)) { NUM_AXIS_CODE(a[n] = x, b[n] = y, c[n] = z, _i[n] = i, _j[n] = j, _k[n] = k, _u[n] = u, _v[n] = v, _w[n] = w); } @@ -979,9 +1084,9 @@ struct XYZEarray { }; FI void reset() { ZERO(data); } - FI void set(const int n, const XYval p) { NUM_AXIS_CODE(x[n]=p.x, y[n]=p.y,,,,,,,); } - FI void set(const int n, const XYZval p) { NUM_AXIS_CODE(x[n]=p.x, y[n]=p.y, z[n]=p.z, i[n]=p.i, j[n]=p.j, k[n]=p.k, u[n]=p.u, v[n]=p.v, w[n]=p.w ); } - FI void set(const int n, const XYZEval p) { LOGICAL_AXIS_CODE(e[n]=p.e, x[n]=p.x, y[n]=p.y, z[n]=p.z, i[n]=p.i, j[n]=p.j, k[n]=p.k, u[n]=p.u, v[n]=p.v, w[n]=p.w ); } + FI void set(const int n, const XYval &p) { NUM_AXIS_CODE(x[n]=p.x, y[n]=p.y,,,,,,,); } + FI void set(const int n, const XYZval &p) { NUM_AXIS_CODE(x[n]=p.x, y[n]=p.y, z[n]=p.z, i[n]=p.i, j[n]=p.j, k[n]=p.k, u[n]=p.u, v[n]=p.v, w[n]=p.w ); } + FI void set(const int n, const XYZEval &p) { LOGICAL_AXIS_CODE(e[n]=p.e, x[n]=p.x, y[n]=p.y, z[n]=p.z, i[n]=p.i, j[n]=p.j, k[n]=p.k, u[n]=p.u, v[n]=p.v, w[n]=p.w ); } // Setter for all individual args FI void set(const int n OPTARGS_NUM(const T)) { NUM_AXIS_CODE(a[n] = x, b[n] = y, c[n] = z, _i[n] = i, _j[n] = j, _k[n] = k, _u[n] = u, _v[n] = v, _w[n] = w); } @@ -1018,8 +1123,9 @@ struct XYZEarray { FI XYZEval operator[](const int n) const { return XYZval(LOGICAL_AXIS_ARRAY(e[n], x[n], y[n], z[n], i[n], j[n], k[n], u[n], v[n], w[n])); } }; -class AxisBits; - +// +// 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; @@ -1217,6 +1323,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); } @@ -1231,3 +1338,14 @@ public: #undef _LSE #undef _RSE #undef FI + +// Axis names for G-code parsing, reports, etc. +constexpr xyze_char_t axis_codes LOGICAL_AXIS_ARRAY('E', 'X', 'Y', 'Z', AXIS4_NAME, AXIS5_NAME, AXIS6_NAME, AXIS7_NAME, AXIS8_NAME, AXIS9_NAME); +#if NUM_AXES <= 3 && !HAS_EXTRUDERS + #define AXIS_CHAR(A) ((char)('X' + A)) + #define IAXIS_CHAR AXIS_CHAR +#else + constexpr xyze_char_t iaxis_codes LOGICAL_AXIS_ARRAY('E', 'X', 'Y', 'Z', 'I', 'J', 'K', 'U', 'V', 'W'); + #define AXIS_CHAR(A) axis_codes[A] + #define IAXIS_CHAR(A) iaxis_codes[A] +#endif diff --git a/Marlin/src/core/utility.cpp b/Marlin/src/core/utility.cpp index 6a8452bfaa..f6b8b304c0 100644 --- a/Marlin/src/core/utility.cpp +++ b/Marlin/src/core/utility.cpp @@ -22,26 +22,16 @@ #include "utility.h" -#include "../MarlinCore.h" #include "../module/temperature.h" #if ENABLED(MARLIN_DEV_MODE) MarlinError marlin_error_number; // Error Number - Marlin can beep X times periodically, display, and emit... #endif -void safe_delay(millis_t ms) { - while (ms > 50) { - ms -= 50; - delay(50); - thermalManager.task(); - } - delay(ms); - thermalManager.task(); // This keeps us safe if too many small safe_delay() calls are made -} - // A delay to provide brittle hosts time to receive bytes #if ENABLED(SERIAL_OVERRUN_PROTECTION) + #include "../MarlinCore.h" // for safe_delay #include "../gcode/gcode.h" // for set_autoreport_paused void serial_delay(const millis_t ms) { @@ -143,7 +133,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) @@ -154,10 +144,8 @@ void safe_delay(millis_t ms) { const float rz = bedlevel.get_z_correction(current_position); SERIAL_ECHO(ftostr43sign(rz, '+')); #if ENABLED(ENABLE_LEVELING_FADE_HEIGHT) - if (planner.z_fade_height) { - SERIAL_ECHOPGM(" (", ftostr43sign(rz * planner.fade_scaling_factor_for_z(current_position.z), '+')); - SERIAL_CHAR(')'); - } + if (planner.z_fade_height) + SERIAL_ECHO(F(" ("), ftostr43sign(rz * planner.fade_scaling_factor_for_z(current_position.z), '+'), C(')')); #endif #endif } @@ -176,10 +164,7 @@ void safe_delay(millis_t ms) { SERIAL_ECHOPGM("MBL Adjustment Z", ftostr43sign(z_offset + z_correction, '+')); #if ENABLED(ENABLE_LEVELING_FADE_HEIGHT) if (planner.z_fade_height) { - SERIAL_ECHOPGM(" (", ftostr43sign( - z_offset + z_correction * planner.fade_scaling_factor_for_z(current_position.z), '+' - )); - SERIAL_CHAR(')'); + SERIAL_ECHO(F(" ("), ftostr43sign(z_offset + z_correction * planner.fade_scaling_factor_for_z(current_position.z), '+'), C(')')); } #endif } diff --git a/Marlin/src/core/utility.h b/Marlin/src/core/utility.h index c3324443ba..b8b4de7f28 100644 --- a/Marlin/src/core/utility.h +++ b/Marlin/src/core/utility.h @@ -25,8 +25,6 @@ #include "../core/types.h" #include "../core/millis_t.h" -void safe_delay(millis_t ms); // Delay ensuring that temperatures are updated and the watchdog is kept alive. - #if ENABLED(SERIAL_OVERRUN_PROTECTION) void serial_delay(const millis_t ms); #else @@ -82,17 +80,6 @@ public: // in the range 0-100 while avoiding rounding artifacts constexpr uint8_t ui8_to_percent(const uint8_t i) { return (int(i) * 100 + 127) / 255; } -// Axis names for G-code parsing, reports, etc. -const xyze_char_t axis_codes LOGICAL_AXIS_ARRAY('E', 'X', 'Y', 'Z', AXIS4_NAME, AXIS5_NAME, AXIS6_NAME, AXIS7_NAME, AXIS8_NAME, AXIS9_NAME); -#if NUM_AXES <= XYZ && !HAS_EXTRUDERS - #define AXIS_CHAR(A) ((char)('X' + A)) - #define IAXIS_CHAR AXIS_CHAR -#else - const xyze_char_t iaxis_codes LOGICAL_AXIS_ARRAY('E', 'X', 'Y', 'Z', 'I', 'J', 'K', 'U', 'V', 'W'); - #define AXIS_CHAR(A) axis_codes[A] - #define IAXIS_CHAR(A) iaxis_codes[A] -#endif - #if ENABLED(MARLIN_DEV_MODE) enum MarlinError : uint8_t { ERR_NONE, diff --git a/Marlin/src/feature/babystep.cpp b/Marlin/src/feature/babystep.cpp index 014ccea1af..d61784517b 100644 --- a/Marlin/src/feature/babystep.cpp +++ b/Marlin/src/feature/babystep.cpp @@ -25,8 +25,7 @@ #if ENABLED(BABYSTEPPING) #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,17 +48,17 @@ 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)]++; } } -void Babystep::add_mm(const AxisEnum axis, const_float_t mm) { +void Babystep::add_mm(const AxisEnum axis, const float mm) { add_steps(axis, mm * planner.settings.axis_steps_per_mm[axis]); } #if ENABLED(BD_SENSOR) - void Babystep::set_mm(const AxisEnum axis, const_float_t mm) { + void Babystep::set_mm(const AxisEnum axis, const float mm) { //if (DISABLED(BABYSTEP_WITHOUT_HOMING) && axis_should_home(axis)) return; const int16_t distance = mm * planner.settings.axis_steps_per_mm[axis]; accum = distance; // Count up babysteps for the UI diff --git a/Marlin/src/feature/babystep.h b/Marlin/src/feature/babystep.h index 666a0ee8c5..da330672b2 100644 --- a/Marlin/src/feature/babystep.h +++ b/Marlin/src/feature/babystep.h @@ -61,7 +61,7 @@ public: static bool can_babystep(const AxisEnum axis); static void add_steps(const AxisEnum axis, const int16_t distance); - static void add_mm(const AxisEnum axis, const_float_t mm); + static void add_mm(const AxisEnum axis, const float mm); #if ENABLED(EP_BABYSTEPPING) // Step Z for M293 / M294 @@ -79,7 +79,7 @@ public: #endif // EP_BABYSTEPPING #if ENABLED(BD_SENSOR) - static void set_mm(const AxisEnum axis, const_float_t mm); + static void set_mm(const AxisEnum axis, const float mm); #endif static bool has_steps() { diff --git a/Marlin/src/feature/backlash.h b/Marlin/src/feature/backlash.h index 593e51b9d0..b4790cb161 100644 --- a/Marlin/src/feature/backlash.h +++ b/Marlin/src/feature/backlash.h @@ -81,10 +81,10 @@ public: static void set_correction(const float v) { set_correction_uint8(_MAX(0, _MIN(1.0, v)) * all_on + 0.5f); } static float get_correction() { return float(get_correction_uint8()) / all_on; } static void set_distance_mm(const AxisEnum axis, const float v); - static float get_distance_mm(const AxisEnum axis) {return distance_mm[axis];} + static float get_distance_mm(const AxisEnum axis) { return distance_mm[axis]; } #ifdef BACKLASH_SMOOTHING_MM static void set_smoothing_mm(const float v); - static float get_smoothing_mm() {return smoothing_mm;} + static float get_smoothing_mm() { return smoothing_mm; } #endif #endif diff --git a/Marlin/src/feature/bedlevel/abl/bbl.cpp b/Marlin/src/feature/bedlevel/abl/bbl.cpp index 14c4bd24bc..918b06d2b4 100644 --- a/Marlin/src/feature/bedlevel/abl/bbl.cpp +++ b/Marlin/src/feature/bedlevel/abl/bbl.cpp @@ -229,7 +229,7 @@ void LevelingBilinear::print_leveling_grid(const bed_mesh_t* _z_values/*=nullptr ) * 0.5f; } - float LevelingBilinear::virt_2cmr(const uint8_t x, const uint8_t y, const_float_t tx, const_float_t ty) { + float LevelingBilinear::virt_2cmr(const uint8_t x, const uint8_t y, const float tx, const float ty) { float row[4], column[4]; for (uint8_t i = 0; i < 4; ++i) { for (uint8_t j = 0; j < 4; ++j) { @@ -369,7 +369,7 @@ float LevelingBilinear::get_z_correction(const xy_pos_t &raw) { * Prepare a bilinear-leveled linear move on Cartesian, * splitting the move where it crosses grid borders. */ - void LevelingBilinear::line_to_destination(const_feedRate_t scaled_fr_mm_s, uint16_t x_splits, uint16_t y_splits) { + void LevelingBilinear::line_to_destination(const feedRate_t scaled_fr_mm_s, uint16_t x_splits, uint16_t y_splits) { // Get current and destination cells for this line xy_int_t c1 { CELL_INDEX(x, current_position.x), CELL_INDEX(y, current_position.y) }, c2 { CELL_INDEX(x, destination.x), CELL_INDEX(y, destination.y) }; diff --git a/Marlin/src/feature/bedlevel/abl/bbl.h b/Marlin/src/feature/bedlevel/abl/bbl.h index ca2e96593f..fb890333dc 100644 --- a/Marlin/src/feature/bedlevel/abl/bbl.h +++ b/Marlin/src/feature/bedlevel/abl/bbl.h @@ -45,7 +45,7 @@ private: static float virt_coord(const uint8_t x, const uint8_t y); static float virt_cmr(const float p[4], const uint8_t i, const float t); - static float virt_2cmr(const uint8_t x, const uint8_t y, const_float_t tx, const_float_t ty); + static float virt_2cmr(const uint8_t x, const uint8_t y, const float tx, const float ty); static void subdivide_mesh(); #endif @@ -63,7 +63,7 @@ public: static constexpr float get_z_offset() { return 0.0f; } #if IS_CARTESIAN && DISABLED(SEGMENT_LEVELED_MOVES) - static void line_to_destination(const_feedRate_t scaled_fr_mm_s, uint16_t x_splits=0xFFFF, uint16_t y_splits=0xFFFF); + static void line_to_destination(const feedRate_t scaled_fr_mm_s, uint16_t x_splits=0xFFFF, uint16_t y_splits=0xFFFF); #endif }; diff --git a/Marlin/src/feature/bedlevel/bdl/bdl.cpp b/Marlin/src/feature/bedlevel/bdl/bdl.cpp index 7e9d583cc1..45c7792d5c 100644 --- a/Marlin/src/feature/bedlevel/bdl/bdl.cpp +++ b/Marlin/src/feature/bedlevel/bdl/bdl.cpp @@ -24,7 +24,6 @@ #if ENABLED(BD_SENSOR) -#include "../../../MarlinCore.h" #include "../../../gcode/gcode.h" #include "../../../module/settings.h" #include "../../../module/motion.h" @@ -101,7 +100,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() { @@ -110,7 +109,7 @@ float BDS_Leveling::read() { } void BDS_Leveling::process() { - if (config_state == BDS_IDLE && printingIsActive()) return; + if (config_state == BDS_IDLE && marlin.printingIsActive()) return; static millis_t next_check_ms = 0; // starting at T=0 static float zpos = 0.0f; const millis_t ms = millis(); @@ -156,7 +155,7 @@ void BDS_Leveling::process() { } else if (config_state == BDS_HOMING_Z) { SERIAL_ECHOLNPGM("Read:", tmp); - kill(F("BDsensor connect Err!")); + marlin.kill(F("BDsensor connect Err!")); } DEBUG_ECHOLNPGM("BD:", tmp & 0x3FF, " Z:", cur_z, "|", current_position.z); diff --git a/Marlin/src/feature/bedlevel/bedlevel.cpp b/Marlin/src/feature/bedlevel/bedlevel.cpp index a76c6cdd26..e479e4c70a 100644 --- a/Marlin/src/feature/bedlevel/bedlevel.cpp +++ b/Marlin/src/feature/bedlevel/bedlevel.cpp @@ -77,7 +77,7 @@ void set_bed_leveling_enabled(const bool enable/*=true*/) { // Get the corrected leveled / unleveled position planner.apply_modifiers(current_position, true); // Physical position with all modifiers - planner.leveling_active ^= true; // Toggle leveling between apply and unapply + FLIP(planner.leveling_active); // Toggle leveling between apply and unapply planner.unapply_modifiers(current_position, true); // Logical position with modifiers removed sync_plan_position(); @@ -91,7 +91,7 @@ TemporaryBedLevelingState::TemporaryBedLevelingState(const bool enable) : saved( #if ENABLED(ENABLE_LEVELING_FADE_HEIGHT) - void set_z_fade_height(const_float_t zfh, const bool do_report/*=true*/) { + void set_z_fade_height(const float zfh, const bool do_report/*=true*/) { if (planner.z_fade_height == zfh) return; diff --git a/Marlin/src/feature/bedlevel/bedlevel.h b/Marlin/src/feature/bedlevel/bedlevel.h index ccb9543e72..5bfa2b7faf 100644 --- a/Marlin/src/feature/bedlevel/bedlevel.h +++ b/Marlin/src/feature/bedlevel/bedlevel.h @@ -38,7 +38,7 @@ void set_bed_leveling_enabled(const bool enable=true); void reset_bed_level(); #if ENABLED(ENABLE_LEVELING_FADE_HEIGHT) - void set_z_fade_height(const_float_t zfh, const bool do_report=true); + void set_z_fade_height(const float zfh, const bool do_report=true); #endif #if ANY(MESH_BED_LEVELING, PROBE_MANUALLY) diff --git a/Marlin/src/feature/bedlevel/mbl/mesh_bed_leveling.cpp b/Marlin/src/feature/bedlevel/mbl/mesh_bed_leveling.cpp index 14216ac424..155d34c4df 100644 --- a/Marlin/src/feature/bedlevel/mbl/mesh_bed_leveling.cpp +++ b/Marlin/src/feature/bedlevel/mbl/mesh_bed_leveling.cpp @@ -61,7 +61,7 @@ * Prepare a mesh-leveled linear move in a Cartesian setup, * splitting the move where it crosses mesh borders. */ - void mesh_bed_leveling::line_to_destination(const_feedRate_t scaled_fr_mm_s, uint8_t x_splits, uint8_t y_splits) { + void mesh_bed_leveling::line_to_destination(const feedRate_t scaled_fr_mm_s, uint8_t x_splits, uint8_t y_splits) { // Get current and destination cells for this line xy_uint8_t scel = cell_indexes(current_position), ecel = cell_indexes(destination); NOMORE(scel.x, GRID_MAX_CELLS_X - 1); diff --git a/Marlin/src/feature/bedlevel/mbl/mesh_bed_leveling.h b/Marlin/src/feature/bedlevel/mbl/mesh_bed_leveling.h index cb4f36cd59..43dabd3adb 100644 --- a/Marlin/src/feature/bedlevel/mbl/mesh_bed_leveling.h +++ b/Marlin/src/feature/bedlevel/mbl/mesh_bed_leveling.h @@ -55,7 +55,7 @@ public: static bool mesh_is_valid() { return has_mesh(); } - static void set_z(const int8_t px, const int8_t py, const_float_t z) { z_values[px][py] = z; } + static void set_z(const int8_t px, const int8_t py, const float z) { z_values[px][py] = z; } static void zigzag(const int8_t index, int8_t &px, int8_t &py) { px = index % (GRID_MAX_POINTS_X); @@ -63,7 +63,7 @@ public: if (py & 1) px = (GRID_MAX_POINTS_X) - 1 - px; // Zig zag } - static void set_zigzag_z(const int8_t index, const_float_t z) { + static void set_zigzag_z(const int8_t index, const float z) { int8_t px, py; zigzag(index, px, py); set_z(px, py, z); @@ -72,33 +72,33 @@ public: static float get_mesh_x(const uint8_t i) { return index_to_xpos[i]; } static float get_mesh_y(const uint8_t i) { return index_to_ypos[i]; } - static uint8_t cell_index_x(const_float_t x) { + static uint8_t cell_index_x(const float x) { int8_t cx = (x - (MESH_MIN_X)) * RECIPROCAL(MESH_X_DIST); return constrain(cx, 0, GRID_MAX_CELLS_X - 1); } - static uint8_t cell_index_y(const_float_t y) { + static uint8_t cell_index_y(const float y) { int8_t cy = (y - (MESH_MIN_Y)) * RECIPROCAL(MESH_Y_DIST); return constrain(cy, 0, GRID_MAX_CELLS_Y - 1); } - static xy_uint8_t cell_indexes(const_float_t x, const_float_t y) { + static xy_uint8_t cell_indexes(const float x, const float y) { return { cell_index_x(x), cell_index_y(y) }; } static xy_uint8_t cell_indexes(const xy_pos_t &xy) { return cell_indexes(xy.x, xy.y); } - static int8_t probe_index_x(const_float_t x) { + static int8_t probe_index_x(const float x) { int8_t px = (x - (MESH_MIN_X) + 0.5f * (MESH_X_DIST)) * RECIPROCAL(MESH_X_DIST); return WITHIN(px, 0, (GRID_MAX_POINTS_X) - 1) ? px : -1; } - static int8_t probe_index_y(const_float_t y) { + static int8_t probe_index_y(const float y) { int8_t py = (y - (MESH_MIN_Y) + 0.5f * (MESH_Y_DIST)) * RECIPROCAL(MESH_Y_DIST); return WITHIN(py, 0, (GRID_MAX_POINTS_Y) - 1) ? py : -1; } - static xy_int8_t probe_indexes(const_float_t x, const_float_t y) { + static xy_int8_t probe_indexes(const float x, const float y) { return { probe_index_x(x), probe_index_y(y) }; } static xy_int8_t probe_indexes(const xy_pos_t &xy) { return probe_indexes(xy.x, xy.y); } - static float calc_z0(const_float_t a0, const_float_t a1, const_float_t z1, const_float_t a2, const_float_t z2) { + static float calc_z0(const float a0, const float a1, const float z1, const float a2, const float z2) { const float delta_z = (z2 - z1) / (a2 - a1), delta_a = a0 - a1; return z1 + delta_a * delta_z; @@ -118,7 +118,7 @@ public: } #if IS_CARTESIAN && DISABLED(SEGMENT_LEVELED_MOVES) - static void line_to_destination(const_feedRate_t scaled_fr_mm_s, uint8_t x_splits=0xFF, uint8_t y_splits=0xFF); + static void line_to_destination(const feedRate_t scaled_fr_mm_s, uint8_t x_splits=0xFF, uint8_t y_splits=0xFF); #endif }; diff --git a/Marlin/src/feature/bedlevel/ubl/ubl.cpp b/Marlin/src/feature/bedlevel/ubl/ubl.cpp index 0228bd247e..2357437633 100644 --- a/Marlin/src/feature/bedlevel/ubl/ubl.cpp +++ b/Marlin/src/feature/bedlevel/ubl/ubl.cpp @@ -28,7 +28,6 @@ unified_bed_leveling bedlevel; -#include "../../../MarlinCore.h" #include "../../../gcode/gcode.h" #include "../../../module/settings.h" @@ -102,7 +101,7 @@ void unified_bed_leveling::invalidate() { set_all_mesh_points_to_value(NAN); } -void unified_bed_leveling::set_all_mesh_points_to_value(const_float_t value) { +void unified_bed_leveling::set_all_mesh_points_to_value(const float value) { GRID_LOOP(x, y) { z_values[x][y] = value; TERN_(EXTENSIBLE_UI, ExtUI::onMeshUpdate(x, y, value)); @@ -115,7 +114,7 @@ void unified_bed_leveling::set_all_mesh_points_to_value(const_float_t value) { constexpr int16_t Z_STEPS_NAN = INT16_MAX; void unified_bed_leveling::set_store_from_mesh(const bed_mesh_t &in_values, mesh_store_t &stored_values) { - auto z_to_store = [](const_float_t z) { + auto z_to_store = [](const float z) { if (isnan(z)) return Z_STEPS_NAN; const int32_t z_scaled = TRUNC(z * mesh_store_scaling); if (z_scaled == Z_STEPS_NAN || !WITHIN(z_scaled, INT16_MIN, INT16_MAX)) @@ -221,7 +220,7 @@ void unified_bed_leveling::display_map(const uint8_t map_type) { if (human) SERIAL_CHAR(is_current ? ']' : ' '); SERIAL_FLUSHTX(); - idle_no_sleep(); + marlin.idle_no_sleep(); } if (!lcd) SERIAL_EOL(); diff --git a/Marlin/src/feature/bedlevel/ubl/ubl.h b/Marlin/src/feature/bedlevel/ubl/ubl.h index b08cb812f8..f6e9ba0cd9 100644 --- a/Marlin/src/feature/bedlevel/ubl/ubl.h +++ b/Marlin/src/feature/bedlevel/ubl/ubl.h @@ -67,15 +67,15 @@ private: static G29_parameters_t param; #if IS_NEWPANEL - static void move_z_with_encoder(const_float_t multiplier); + static void move_z_with_encoder(const float multiplier); static float measure_point_with_encoder(); static float measure_business_card_thickness(); - static void manually_probe_remaining_mesh(const xy_pos_t&, const_float_t , const_float_t , const bool) __O0; + static void manually_probe_remaining_mesh(const xy_pos_t&, const float, const float, const bool) __O0; static void fine_tune_mesh(const xy_pos_t &pos, const bool do_ubl_mesh_map) __O0; #endif static bool G29_parse_parameters() __O0; - static void shift_mesh_height(); + static void shift_mesh_height(const float zoffs); static void probe_entire_mesh(const xy_pos_t &near, const bool do_ubl_mesh_map, const bool stow_probe, const bool do_furthest) __O0; static void tilt_mesh_based_on_probed_grid(const bool do_ubl_mesh_map); static bool smart_fill_one(const uint8_t x, const uint8_t y, const int8_t xdir, const int8_t ydir); @@ -101,13 +101,13 @@ public: static mesh_index_pair find_furthest_invalid_mesh_point() __O0; static void reset(); static void invalidate(); - static void set_all_mesh_points_to_value(const_float_t value); - static void adjust_mesh_to_mean(const bool cflag, const_float_t value); + static void set_all_mesh_points_to_value(const float value); + static void adjust_mesh_to_mean(const bool cflag, const float value); static bool sanity_check(); static void smart_fill_mesh(); static void G29() __O0; // O0 for no optimization - static void smart_fill_wlsf(const_float_t ) __O2; // O2 gives smaller code than Os on A2560 + static void smart_fill_wlsf(const float ) __O2; // O2 gives smaller code than Os on A2560 static int8_t storage_slot; @@ -130,42 +130,42 @@ public: unified_bed_leveling(); - FORCE_INLINE static void set_z(const int8_t px, const int8_t py, const_float_t z) { z_values[px][py] = z; } + FORCE_INLINE static void set_z(const int8_t px, const int8_t py, const float z) { z_values[px][py] = z; } - static int8_t cell_index_x_raw(const_float_t x) { + static int8_t cell_index_x_raw(const float x) { return FLOOR((x - (MESH_MIN_X)) * RECIPROCAL(MESH_X_DIST)); } - static int8_t cell_index_y_raw(const_float_t y) { + static int8_t cell_index_y_raw(const float y) { return FLOOR((y - (MESH_MIN_Y)) * RECIPROCAL(MESH_Y_DIST)); } - static bool cell_index_x_valid(const_float_t x) { + static bool cell_index_x_valid(const float x) { return WITHIN(cell_index_x_raw(x), 0, GRID_MAX_CELLS_X - 1); } - static bool cell_index_y_valid(const_float_t y) { + static bool cell_index_y_valid(const float y) { return WITHIN(cell_index_y_raw(y), 0, GRID_MAX_CELLS_Y - 1); } - static uint8_t cell_index_x(const_float_t x) { + static uint8_t cell_index_x(const float x) { return constrain(cell_index_x_raw(x), 0, GRID_MAX_CELLS_X - 1); } - static uint8_t cell_index_y(const_float_t y) { + static uint8_t cell_index_y(const float y) { return constrain(cell_index_y_raw(y), 0, GRID_MAX_CELLS_Y - 1); } - static xy_uint8_t cell_indexes(const_float_t x, const_float_t y) { + static xy_uint8_t cell_indexes(const float x, const float y) { return { cell_index_x(x), cell_index_y(y) }; } static xy_uint8_t cell_indexes(const xy_pos_t &xy) { return cell_indexes(xy.x, xy.y); } - static int8_t closest_x_index(const_float_t x) { + static int8_t closest_x_index(const float x) { const int8_t px = (x - (MESH_MIN_X) + (MESH_X_DIST) * 0.5) * RECIPROCAL(MESH_X_DIST); return WITHIN(px, 0, (GRID_MAX_POINTS_X) - 1) ? px : -1; } - static int8_t closest_y_index(const_float_t y) { + static int8_t closest_y_index(const float y) { const int8_t py = (y - (MESH_MIN_Y) + (MESH_Y_DIST) * 0.5) * RECIPROCAL(MESH_Y_DIST); return WITHIN(py, 0, (GRID_MAX_POINTS_Y) - 1) ? py : -1; } @@ -188,7 +188,7 @@ public: * It is fairly expensive with its 4 floating point additions and 2 floating point * multiplications. */ - FORCE_INLINE static float calc_z0(const_float_t a0, const_float_t a1, const_float_t z1, const_float_t a2, const_float_t z2) { + FORCE_INLINE static float calc_z0(const float a0, const float a1, const float z1, const float a2, const float z2) { return z1 + (z2 - z1) * (a0 - a1) / (a2 - a1); } @@ -202,7 +202,7 @@ public: * z_correction_for_x_on_horizontal_mesh_line is an optimization for * the case where the printer is making a vertical line that only crosses horizontal mesh lines. */ - static float z_correction_for_x_on_horizontal_mesh_line(const_float_t rx0, const int x1_i, const int yi) { + static float z_correction_for_x_on_horizontal_mesh_line(const float rx0, const int x1_i, const int yi) { if (!WITHIN(x1_i, 0, (GRID_MAX_POINTS_X) - 1) || !WITHIN(yi, 0, (GRID_MAX_POINTS_Y) - 1)) { if (DEBUGGING(LEVELING)) { @@ -225,7 +225,7 @@ public: // // See comments above for z_correction_for_x_on_horizontal_mesh_line // - static float z_correction_for_y_on_vertical_mesh_line(const_float_t ry0, const int xi, const int y1_i) { + static float z_correction_for_y_on_vertical_mesh_line(const float ry0, const int xi, const int y1_i) { if (!WITHIN(xi, 0, (GRID_MAX_POINTS_X) - 1) || !WITHIN(y1_i, 0, (GRID_MAX_POINTS_Y) - 1)) { if (DEBUGGING(LEVELING)) { @@ -251,7 +251,7 @@ public: * Z-Height at both ends. Then it does a linear interpolation of these heights based * on the Y position within the cell. */ - static float get_z_correction(const_float_t rx0, const_float_t ry0) { + static float get_z_correction(const float rx0, const float ry0) { const int8_t cx = cell_index_x(rx0), cy = cell_index_y(ry0); // return values are clamped /** @@ -295,9 +295,9 @@ public: } #if UBL_SEGMENTED - static bool line_to_destination_segmented(const_feedRate_t scaled_fr_mm_s); + static bool line_to_destination_segmented(const feedRate_t scaled_fr_mm_s); #else - static void line_to_destination_cartesian(const_feedRate_t scaled_fr_mm_s, const uint8_t e); + static void line_to_destination_cartesian(const feedRate_t scaled_fr_mm_s, const uint8_t e); #endif static bool mesh_is_valid() { diff --git a/Marlin/src/feature/bedlevel/ubl/ubl_G29.cpp b/Marlin/src/feature/bedlevel/ubl/ubl_G29.cpp index 4637bf87e8..6341933bfb 100644 --- a/Marlin/src/feature/bedlevel/ubl/ubl_G29.cpp +++ b/Marlin/src/feature/bedlevel/ubl/ubl_G29.cpp @@ -26,7 +26,6 @@ #include "../bedlevel.h" -#include "../../../MarlinCore.h" #include "../../../HAL/shared/eeprom_api.h" #include "../../../libs/hex_print.h" #include "../../../module/settings.h" @@ -48,6 +47,10 @@ #include "../hilbert_curve.h" #endif +#if ENABLED(FT_MOTION) + #include "../../../module/ft_motion.h" +#endif + #include #define UBL_G29_P31 @@ -297,12 +300,21 @@ G29_parameters_t unified_bed_leveling::param; void unified_bed_leveling::G29() { - bool probe_deployed = false; + #ifdef EVENT_GCODE_AFTER_G29 + bool probe_deployed = false; + #define SET_PROBE_DEPLOYED(N) probe_deployed = N + #else + #define SET_PROBE_DEPLOYED(N) + #endif + if (G29_parse_parameters()) return; // Abort on parameter error const uint8_t p_val = parser.byteval('P'); const bool may_move = p_val == 1 || p_val == 2 || p_val == 4 || parser.seen_test('J'); + // 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) { planner.synchronize(); @@ -316,6 +328,11 @@ void unified_bed_leveling::G29() { #endif probe.use_probing_tool(); + #ifdef EVENT_GCODE_BEFORE_G29 + if (DEBUGGING(LEVELING)) DEBUG_ECHOLNPGM("Before G29 G-code: ", EVENT_GCODE_BEFORE_G29); + gcode.process_subcommands_now(F(EVENT_GCODE_BEFORE_G29)); + #endif + // Position bed horizontally and Z probe vertically. #if HAS_SAFE_BED_LEVELING xyze_pos_t safe_position = current_position; @@ -357,7 +374,7 @@ void unified_bed_leveling::G29() { bool invalidate_all = count >= GRID_MAX_POINTS; if (!invalidate_all) { while (count--) { - if ((count & 0x0F) == 0x0F) idle(); + if ((count & 0x0F) == 0x0F) marlin.idle(); const mesh_index_pair closest = find_closest_mesh_point_of_type(REAL, param.XY_pos); // No more REAL mesh points to invalidate? Assume the user meant // to invalidate the ENTIRE mesh, which can't be done with @@ -379,7 +396,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"); @@ -430,7 +447,7 @@ void unified_bed_leveling::G29() { do_blocking_move_to_xy(0.5f * ((MESH_MIN_X) + (MESH_MAX_X)), 0.5f * ((MESH_MIN_Y) + (MESH_MAX_Y))); #endif report_current_position(); - probe_deployed = true; + SET_PROBE_DEPLOYED(true); } #endif // HAS_BED_PROBE @@ -465,7 +482,7 @@ void unified_bed_leveling::G29() { probe_entire_mesh(param.XY_pos, parser.seen_test('T'), parser.seen_test('E'), parser.seen_test('U')); report_current_position(); - probe_deployed = true; + SET_PROBE_DEPLOYED(true); } break; #endif // HAS_BED_PROBE @@ -503,7 +520,7 @@ void unified_bed_leveling::G29() { SERIAL_ECHOLNPGM("?Error in Business Card measurement."); return; } - probe_deployed = true; + SET_PROBE_DEPLOYED(true); } if (!position_is_reachable(param.XY_pos)) { @@ -593,7 +610,7 @@ void unified_bed_leveling::G29() { case 5: adjust_mesh_to_mean(param.C_seen, param.C_constant); break; - case 6: shift_mesh_height(); break; + case 6: shift_mesh_height(param.C_constant); break; } } @@ -630,7 +647,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; } @@ -658,7 +675,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; } @@ -681,13 +698,11 @@ void unified_bed_leveling::G29() { #endif #ifdef EVENT_GCODE_AFTER_G29 - if (DEBUGGING(LEVELING)) DEBUG_ECHOLNPGM("Z Probe End Script: ", EVENT_GCODE_AFTER_G29); + if (DEBUGGING(LEVELING)) DEBUG_ECHOLNPGM("After G29 G-code: ", EVENT_GCODE_AFTER_G29); if (probe_deployed) { planner.synchronize(); gcode.process_subcommands_now(F(EVENT_GCODE_AFTER_G29)); } - #else - UNUSED(probe_deployed); #endif probe.use_probing_tool(false); @@ -699,7 +714,7 @@ void unified_bed_leveling::G29() { * G29 P5 C : Adjust Mesh To Mean (and subtract the given offset). * Find the mean average and shift the mesh to center on that value. */ -void unified_bed_leveling::adjust_mesh_to_mean(const bool cflag, const_float_t offset) { +void unified_bed_leveling::adjust_mesh_to_mean(const bool cflag, const float offset) { float sum = 0; uint8_t n = 0; GRID_LOOP(x, y) @@ -735,10 +750,10 @@ void unified_bed_leveling::adjust_mesh_to_mean(const bool cflag, const_float_t o /** * G29 P6 C : Shift Mesh Height by a uniform constant. */ -void unified_bed_leveling::shift_mesh_height() { +void unified_bed_leveling::shift_mesh_height(const float zoffs) { GRID_LOOP(x, y) if (!isnan(z_values[x][y])) { - z_values[x][y] += param.C_constant; + z_values[x][y] += zoffs; TERN_(EXTENSIBLE_UI, ExtUI::onMeshUpdate(x, y, z_values[x][y])); } } @@ -765,7 +780,7 @@ void unified_bed_leveling::shift_mesh_height() { 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 @@ -840,7 +855,7 @@ void set_message_with_feedback(FSTR_P const fstr) { ui.quick_feedback(false); // Preserve button state for click-and-hold const millis_t nxt = millis() + 1500UL; while (ui.button_pressed()) { // Loop while the encoder is pressed. Uses hardware flag! - idle(); // idle, of course + marlin.idle(); // idle, of course if (ELAPSED(millis(), nxt)) { // After 1.5 seconds ui.quick_feedback(); if (func) (*func)(); @@ -853,10 +868,10 @@ void set_message_with_feedback(FSTR_P const fstr) { return false; } - void unified_bed_leveling::move_z_with_encoder(const_float_t multiplier) { + void unified_bed_leveling::move_z_with_encoder(const float multiplier) { ui.wait_for_release(); while (!ui.button_pressed()) { - idle(); + marlin.idle(); gcode.reset_stepper_timeout(); // Keep steppers powered if (encoder_diff) { do_blocking_move_to_z(current_position.z + float(encoder_diff) * multiplier); @@ -936,7 +951,7 @@ void set_message_with_feedback(FSTR_P const fstr) { * Move to INVALID points and * NOTE: Blocks the G-code queue and captures Marlin UI during use. */ - void unified_bed_leveling::manually_probe_remaining_mesh(const xy_pos_t &pos, const_float_t z_clearance, const_float_t thick, const bool do_ubl_mesh_map) { + void unified_bed_leveling::manually_probe_remaining_mesh(const xy_pos_t &pos, const float z_clearance, const float thick, const bool do_ubl_mesh_map) { ui.capture(); TERN_(EXTENSIBLE_UI, ExtUI::onLevelingStart()); @@ -1072,7 +1087,7 @@ void set_message_with_feedback(FSTR_P const fstr) { SET_SOFT_ENDSTOP_LOOSE(true); do { - idle_no_sleep(); + marlin.idle_no_sleep(); new_z = ui.ubl_mesh_value(); TERN_(UBL_MESH_EDIT_MOVES_Z, do_blocking_move_to_z(h_offset + new_z)); // Move the nozzle as the point is edited SERIAL_FLUSH(); // Prevent host M105 buffer overrun. @@ -1145,16 +1160,16 @@ bool unified_bed_leveling::G29_parse_parameters() { } if (parser.seen('P')) { - const uint8_t pv = parser.value_byte(); + const uint8_t pval = parser.value_byte(); #if !HAS_BED_PROBE - if (pv == 1) { + if (pval == 1) { SERIAL_ECHOLNPGM("G29 P1 requires a probe.\n"); err_flag = true; } else #endif { - param.P_phase = pv; + param.P_phase = pval; if (!WITHIN(param.P_phase, 0, 6)) { SERIAL_ECHOLNPGM("?(P)hase value invalid (0-6).\n"); err_flag = true; @@ -1166,7 +1181,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 @@ -1494,7 +1509,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; @@ -1550,7 +1565,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 @@ -1590,7 +1605,7 @@ void unified_bed_leveling::smart_fill_mesh() { } if (abort_flag) break; - zig_zag ^= true; + FLIP(zig_zag); } } probe.stow(); @@ -1644,10 +1659,10 @@ void unified_bed_leveling::smart_fill_mesh() { */ #if ENABLED(VALIDATE_MESH_TILT) auto d_from = []{ DEBUG_ECHOPGM("D from "); }; - auto normed = [&](const xy_pos_t &pos, const_float_t zadd) { + auto normed = [&](const xy_pos_t &pos, const float zadd) { return normal.x * pos.x + normal.y * pos.y + zadd; }; - auto debug_pt = [](const int num, const xy_pos_t &pos, const_float_t zadd) { + auto debug_pt = [](const int num, const xy_pos_t &pos, const float zadd) { d_from(); DEBUG_ECHOLN(F("Point "), num, C(':'), p_float_t(normed(pos, zadd), 6), F(" Z error = "), p_float_t(zadd - get_z_correction(pos), 6)); }; @@ -1668,7 +1683,7 @@ void unified_bed_leveling::smart_fill_mesh() { #endif // HAS_BED_PROBE #if ENABLED(UBL_G29_P31) - void unified_bed_leveling::smart_fill_wlsf(const_float_t weight_factor) { + void unified_bed_leveling::smart_fill_wlsf(const float weight_factor) { // For each undefined mesh point, compute a distance-weighted least squares fit // from all the originally populated mesh points, weighted toward the point @@ -1712,7 +1727,7 @@ void unified_bed_leveling::smart_fill_mesh() { const float ez = -lsf_results.D - lsf_results.A * ppos.x - lsf_results.B * ppos.y; z_values[ix][iy] = ez; TERN_(EXTENSIBLE_UI, ExtUI::onMeshUpdate(ix, iy, z_values[ix][iy])); - idle(); // housekeeping + marlin.idle(); // housekeeping } } } @@ -1769,7 +1784,7 @@ void unified_bed_leveling::smart_fill_mesh() { SERIAL_EOL(); #if HAS_KILL - SERIAL_ECHOLNPGM("Kill pin on :", KILL_PIN, " state:", kill_state()); + SERIAL_ECHOLNPGM("Kill pin on :", KILL_PIN, " state:", marlin.kill_state()); #endif SERIAL_EOL(); @@ -1778,14 +1793,14 @@ void unified_bed_leveling::smart_fill_mesh() { SERIAL_ECHOLNPGM("ubl_state_at_invocation :", ubl_state_at_invocation, "\nubl_state_recursion_chk :", ubl_state_recursion_chk); serial_delay(50); - SERIAL_ECHOLNPGM("Meshes go from ", hex_address((void*)settings.meshes_start_index()), " to ", hex_address((void*)settings.meshes_end_index())); + SERIAL_ECHOLNPGM("Meshes go from ", _hex_word(settings.meshes_start_index()), " to ", _hex_word(settings.meshes_end_index())); serial_delay(50); SERIAL_ECHOLNPGM("sizeof(unified_bed_leveling) : ", sizeof(unified_bed_leveling)); SERIAL_ECHOLNPGM("z_value[][] size: ", sizeof(z_values)); serial_delay(25); - SERIAL_ECHOLNPGM("EEPROM free for UBL: ", hex_address((void*)(settings.meshes_end_index() - settings.meshes_start_index()))); + SERIAL_ECHOLNPGM("EEPROM free for UBL: ", _hex_word(settings.meshes_end_index() - settings.meshes_start_index())); serial_delay(50); SERIAL_ECHOLNPGM("EEPROM can hold ", settings.calc_num_meshes(), " meshes.\n"); @@ -1807,7 +1822,7 @@ void unified_bed_leveling::smart_fill_mesh() { SERIAL_ECHO_MSG("EEPROM Dump:"); persistentStore.access_start(); for (uint16_t i = 0; i < persistentStore.capacity(); i += 16) { - if (!(i & 0x3)) idle(); + if (!(i & 0x3)) marlin.idle(); print_hex_word(i); SERIAL_ECHOPGM(": "); for (uint16_t j = 0; j < 16; j++) { @@ -1835,7 +1850,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; } diff --git a/Marlin/src/feature/bedlevel/ubl/ubl_motion.cpp b/Marlin/src/feature/bedlevel/ubl/ubl_motion.cpp index 053a68b77d..b6b9ec4368 100644 --- a/Marlin/src/feature/bedlevel/ubl/ubl_motion.cpp +++ b/Marlin/src/feature/bedlevel/ubl/ubl_motion.cpp @@ -32,7 +32,6 @@ #include "../../../module/delta.h" #endif -#include "../../../MarlinCore.h" #include //#define DEBUG_UBL_MOTION @@ -47,7 +46,7 @@ // corners of cells. To fix the issue, simply check if the start/end of the line // is very close to a cell boundary in advance and don't split the line there. - void unified_bed_leveling::line_to_destination_cartesian(const_feedRate_t scaled_fr_mm_s, const uint8_t extruder) { + void unified_bed_leveling::line_to_destination_cartesian(const feedRate_t scaled_fr_mm_s, const uint8_t extruder) { /** * Much of the nozzle movement will be within the same cell. So we will do as little computation * as possible to determine if this is the case. If this move is within the same cell, we will @@ -351,7 +350,7 @@ * Returns true if did NOT move, false if moved (requires current_position update). */ - bool __O2 unified_bed_leveling::line_to_destination_segmented(const_feedRate_t scaled_fr_mm_s) { + bool __O2 unified_bed_leveling::line_to_destination_segmented(const feedRate_t scaled_fr_mm_s) { if (!position_is_reachable(destination)) // fail if moving outside reachable boundary return true; // did not move, so current_position still accurate diff --git a/Marlin/src/feature/binary_stream.h b/Marlin/src/feature/binary_stream.h index b2d76c045a..304fdae300 100644 --- a/Marlin/src/feature/binary_stream.h +++ b/Marlin/src/feature/binary_stream.h @@ -134,19 +134,19 @@ private: public: static void idle() { - // If a transfer is interrupted and a file is left open, abort it after TIMEOUT ms + // If a transfer is interrupted and a file is left open, abort it after 'idle_period' ms const millis_t ms = millis(); if (transfer_active && ELAPSED(ms, idle_timeout)) { - idle_timeout = ms + IDLE_PERIOD; + idle_timeout = ms + idle_period; if (ELAPSED(ms, transfer_timeout)) transfer_abort(); } } static void process(uint8_t packet_type, char *buffer, const uint16_t length) { - transfer_timeout = millis() + TIMEOUT; + transfer_timeout = millis() + timeout; switch (static_cast(packet_type)) { case FileTransfer::QUERY: - SERIAL_ECHO(F("PFT:version:"), VERSION_MAJOR, C('.'), VERSION_MINOR, C('.'), VERSION_PATCH); + SERIAL_ECHO(F("PFT:version:"), version_major, C('.'), version_minor, C('.'), version_patch); #if ENABLED(BINARY_STREAM_COMPRESSION) SERIAL_ECHOLN(F(":compression:heatshrink,"), HEATSHRINK_STATIC_WINDOW_BITS, C(','), HEATSHRINK_STATIC_LOOKAHEAD_BITS); #else @@ -194,7 +194,7 @@ public: } } - static const uint16_t VERSION_MAJOR = 0, VERSION_MINOR = 1, VERSION_PATCH = 0, TIMEOUT = 10000, IDLE_PERIOD = 1000; + static const uint16_t version_major = 0, version_minor = 1, version_patch = 0, timeout = 10000, idle_period = 1000; }; class BinaryStream { @@ -209,7 +209,7 @@ public: struct Packet { // 10 byte protocol overhead, ascii with checksum and line number has a minimum of 7 increasing with line union Header { - static constexpr uint16_t HEADER_TOKEN = 0xB5AD; + static constexpr uint16_t header_token = 0xB5AD; struct [[gnu::packed]] { uint16_t token; // packet start token uint8_t sync; // stream sync, resend id and packet loss detection @@ -245,7 +245,7 @@ public: bytes_received = 0; checksum = 0; header_checksum = 0; - timeout = millis() + PACKET_MAX_WAIT; + timeout = millis() + packet_max_wait; buffer = nullptr; } } packet{}; @@ -272,14 +272,14 @@ public: } if (!bs_serial_data_available(card.transfer_port_index)) return false; data = bs_read_serial(card.transfer_port_index); - packet.timeout = millis() + PACKET_MAX_WAIT; + packet.timeout = millis() + packet_max_wait; return true; } template void receive(char (&buffer)[buffer_size]) { uint8_t data = 0; - millis_t transfer_window = millis() + RX_TIMESLICE; + millis_t transfer_window = millis() + rx_timeslice; #if HAS_MEDIA PORT_REDIRECT(SERIAL_PORTMASK(card.transfer_port_index)); @@ -299,7 +299,7 @@ public: case StreamState::PACKET_WAIT: if (!stream_read(data)) { idle(); return; } // no active packet so don't wait packet.header.data[1] = data; - if (packet.header.token == packet.header.HEADER_TOKEN) { + if (packet.header.token == packet.header.header_token) { packet.bytes_received = 2; stream_state = StreamState::PACKET_HEADER; } @@ -322,7 +322,7 @@ public: if (packet.header.checksum == packet.header_checksum) { // The SYNC control packet is a special case in that it doesn't require the stream sync to be correct if (static_cast(packet.header.protocol()) == Protocol::CONTROL && static_cast(packet.header.type()) == ProtocolControl::SYNC) { - SERIAL_ECHOLN(F("ss"), sync, C(','), buffer_size, C(','), VERSION_MAJOR, C('.'), VERSION_MINOR, C('.'), VERSION_PATCH); + SERIAL_ECHOLN(F("ss"), sync, C(','), buffer_size, C(','), version_major, C('.'), version_minor, C('.'), version_patch); stream_state = StreamState::PACKET_RESET; break; } @@ -398,7 +398,7 @@ public: stream_state = StreamState::PACKET_RESET; break; case StreamState::PACKET_RESEND: - if (packet_retries < MAX_RETRIES || MAX_RETRIES == 0) { + if (packet_retries < max_retries || max_retries == 0) { packet_retries++; stream_state = StreamState::PACKET_RESET; SERIAL_ECHO_MSG("Resend request ", packet_retries); @@ -446,7 +446,7 @@ public: SDFileTransferProtocol::idle(); } - static const uint16_t PACKET_MAX_WAIT = 500, RX_TIMESLICE = 20, MAX_RETRIES = 0, VERSION_MAJOR = 0, VERSION_MINOR = 1, VERSION_PATCH = 0; + static const uint16_t packet_max_wait = 500, rx_timeslice = 20, max_retries = 0, version_major = 0, version_minor = 1, version_patch = 0; uint8_t packet_retries, sync; uint16_t buffer_next_index; uint32_t bytes_received; diff --git a/Marlin/src/feature/bltouch.cpp b/Marlin/src/feature/bltouch.cpp index 2559547b85..85b69d66c4 100644 --- a/Marlin/src/feature/bltouch.cpp +++ b/Marlin/src/feature/bltouch.cpp @@ -48,7 +48,7 @@ bool BLTouch::command(const BLTCommand cmd, const millis_t &ms) { // The previous write should've already delayed to detect the alarm. if (cmd != current) { servo[Z_PROBE_SERVO_NR].move(cmd); - safe_delay(_MAX(ms, (uint32_t)BLTOUCH_DELAY)); // BLTOUCH_DELAY is also the *minimum* delay + safe_delay(_MAX(ms, uint32_t(BLTOUCH_DELAY))); // BLTOUCH_DELAY is also the *minimum* delay } return triggered(); } @@ -71,11 +71,9 @@ void BLTouch::init(const bool set_voltage/*=false*/) { #else - #ifdef DEBUG_OUT - if (DEBUGGING(LEVELING)) - DEBUG_ECHOLN( F("BLTouch Mode: "), bltouch.od_5v_mode ? F("5V") : F("OD"), - F(" (Default " TERN(BLTOUCH_SET_5V_MODE, "5V", "OD") ")")); - #endif + if (DEBUGGING(LEVELING)) + DEBUG_ECHOLN( F("BLTouch Mode: "), bltouch.od_5v_mode ? F("5V") : F("OD"), + F(" (Default " TERN(BLTOUCH_SET_5V_MODE, "5V", "OD") ")")); const bool should_set = od_5v_mode != ENABLED(BLTOUCH_SET_5V_MODE); diff --git a/Marlin/src/feature/bltouch.h b/Marlin/src/feature/bltouch.h index 0f9f2e68ba..1371ec9f46 100644 --- a/Marlin/src/feature/bltouch.h +++ b/Marlin/src/feature/bltouch.h @@ -26,6 +26,7 @@ // BLTouch commands are sent as servo angles typedef unsigned char BLTCommand; +#define DEPLOY_ALARM true #define STOW_ALARM true #define BLTOUCH_DEPLOY 10 #define BLTOUCH_STOW 90 @@ -104,7 +105,7 @@ public: static bool triggered(); private: - static bool _deploy_query_alarm() { return command(BLTOUCH_DEPLOY, BLTOUCH_DEPLOY_DELAY); } + static bool _deploy_query_alarm() { return command(BLTOUCH_DEPLOY, BLTOUCH_DEPLOY_DELAY) == DEPLOY_ALARM; } static bool _stow_query_alarm() { return command(BLTOUCH_STOW, BLTOUCH_STOW_DELAY) == STOW_ALARM; } static void clear(); diff --git a/Marlin/src/feature/cancel_object.cpp b/Marlin/src/feature/cancel_object.cpp index 818661b1f0..c17c9988e4 100644 --- a/Marlin/src/feature/cancel_object.cpp +++ b/Marlin/src/feature/cancel_object.cpp @@ -72,7 +72,7 @@ void CancelObject::report() { SERIAL_ECHO_START(); SERIAL_ECHOPGM("Canceled:"); for (int i = 0; i < state.object_count; i++) - if (TEST(state.canceled, i)) { SERIAL_CHAR(' '); SERIAL_ECHO(i); } + if (TEST(state.canceled, i)) SERIAL_ECHO(C(' '), i); SERIAL_EOL(); } diff --git a/Marlin/src/feature/caselight.cpp b/Marlin/src/feature/caselight.cpp index eb580a6d62..95221111b2 100644 --- a/Marlin/src/feature/caselight.cpp +++ b/Marlin/src/feature/caselight.cpp @@ -40,7 +40,7 @@ bool CaseLight::on = CASE_LIGHT_DEFAULT_ON; #if CASE_LIGHT_IS_COLOR_LED constexpr uint8_t init_case_light[] = CASE_LIGHT_DEFAULT_COLOR; - LEDColor CaseLight::color = { init_case_light[0], init_case_light[1], init_case_light[2] OPTARG(HAS_WHITE_LED, init_case_light[3]) }; + LED1Color_t CaseLight::color = { init_case_light[0], init_case_light[1], init_case_light[2] OPTARG(HAS_WHITE_LED, init_case_light[3]) }; #endif void CaseLight::update(const bool sflag) { @@ -67,13 +67,13 @@ void CaseLight::update(const bool sflag) { #if ENABLED(CASE_LIGHT_USE_NEOPIXEL) if (on) // Use current color of (NeoPixel) leds and new brightness level - leds.set_color(LEDColor(leds.color.r, leds.color.g, leds.color.b OPTARG(HAS_WHITE_LED, leds.color.w) OPTARG(NEOPIXEL_LED, n10ct))); + leds.set_color(LED1Color_t(leds.color.r, leds.color.g, leds.color.b OPTARG(HAS_WHITE_LED, leds.color.w) OPTARG(NEOPIXEL_LED, n10ct))); else // Switch off leds leds.set_off(); #else // Use CaseLight color (CASE_LIGHT_DEFAULT_COLOR) and new brightness level - leds.set_color(LEDColor(color.r, color.g, color.b OPTARG(HAS_WHITE_LED, color.w) OPTARG(NEOPIXEL_LED, n10ct))); + leds.set_color(LED1Color_t(color.r, color.g, color.b OPTARG(HAS_WHITE_LED, color.w) OPTARG(NEOPIXEL_LED, n10ct))); #endif #else // !CASE_LIGHT_IS_COLOR_LED diff --git a/Marlin/src/feature/caselight.h b/Marlin/src/feature/caselight.h index d88b3d67bf..28466cecaa 100644 --- a/Marlin/src/feature/caselight.h +++ b/Marlin/src/feature/caselight.h @@ -24,7 +24,7 @@ #include "../inc/MarlinConfig.h" #if CASE_LIGHT_IS_COLOR_LED - #include "leds/leds.h" // for LEDColor + #include "leds/leds.h" // for LED1Color_t #endif class CaseLight { @@ -50,7 +50,7 @@ public: #if ENABLED(CASE_LIGHT_IS_COLOR_LED) private: - static LEDColor color; + static LED1Color_t color; #endif }; diff --git a/Marlin/src/feature/controllerfan.cpp b/Marlin/src/feature/controllerfan.cpp index 323d988a2d..0636402136 100644 --- a/Marlin/src/feature/controllerfan.cpp +++ b/Marlin/src/feature/controllerfan.cpp @@ -44,9 +44,30 @@ uint8_t ControllerFan::speed; void ControllerFan::setup() { SET_OUTPUT(CONTROLLER_FAN_PIN); - #ifdef CONTROLLER_FAN2_PIN + #if PIN_EXISTS(CONTROLLER_FAN2) SET_OUTPUT(CONTROLLER_FAN2_PIN); #endif + #if PIN_EXISTS(CONTROLLER_FAN3) + SET_OUTPUT(CONTROLLER_FAN3_PIN); + #endif + #if PIN_EXISTS(CONTROLLER_FAN4) + SET_OUTPUT(CONTROLLER_FAN4_PIN); + #endif + #if PIN_EXISTS(CONTROLLER_FAN5) + SET_OUTPUT(CONTROLLER_FAN5_PIN); + #endif + #if PIN_EXISTS(CONTROLLER_FAN6) + SET_OUTPUT(CONTROLLER_FAN6_PIN); + #endif + #if PIN_EXISTS(CONTROLLER_FAN7) + SET_OUTPUT(CONTROLLER_FAN7_PIN); + #endif + #if PIN_EXISTS(CONTROLLER_FAN8) + SET_OUTPUT(CONTROLLER_FAN8_PIN); + #endif + #if PIN_EXISTS(CONTROLLER_FAN9) + SET_OUTPUT(CONTROLLER_FAN9_PIN); + #endif init(); } @@ -87,7 +108,7 @@ void ControllerFan::update() { * - If System is on idle and idle fan speed settings is activated. */ set_fan_speed( - settings.auto_mode && lastComponentOn && PENDING(ms, lastComponentOn + SEC_TO_MS(settings.duration)) + settings.auto_mode && lastComponentOn && PENDING(ms, lastComponentOn, SEC_TO_MS(settings.duration)) ? settings.active_speed : settings.idle_speed ); @@ -107,19 +128,38 @@ void ControllerFan::update() { fan_kick_end = 0; #endif - #if ENABLED(FAN_SOFT_PWM) - soft_pwm_speed = speed; - #else - if (PWM_PIN(CONTROLLER_FAN_PIN)) - hal.set_pwm_duty(pin_t(CONTROLLER_FAN_PIN), speed); - else - WRITE(CONTROLLER_FAN_PIN, speed > 0); + #define SET_CONTROLLER_FAN(N) do { \ + if (PWM_PIN(CONTROLLER_FAN##N##_PIN)) hal.set_pwm_duty(pin_t(CONTROLLER_FAN##N##_PIN), speed); \ + else WRITE(CONTROLLER_FAN##N##_PIN, speed > 0);\ + } while (0) - #ifdef CONTROLLER_FAN2_PIN - if (PWM_PIN(CONTROLLER_FAN2_PIN)) - hal.set_pwm_duty(pin_t(CONTROLLER_FAN2_PIN), speed); - else - WRITE(CONTROLLER_FAN2_PIN, speed > 0); + #if ENABLED(FAN_SOFT_PWM) + soft_pwm_speed = speed >> 1; // Controller Fan Soft PWM uses 0-127 as 0-100% so cut the 0-255 range in half. + #else + SET_CONTROLLER_FAN(); + #if PIN_EXISTS(CONTROLLER_FAN2) + SET_CONTROLLER_FAN(2); + #endif + #if PIN_EXISTS(CONTROLLER_FAN3) + SET_CONTROLLER_FAN(3); + #endif + #if PIN_EXISTS(CONTROLLER_FAN4) + SET_CONTROLLER_FAN(4); + #endif + #if PIN_EXISTS(CONTROLLER_FAN5) + SET_CONTROLLER_FAN(5); + #endif + #if PIN_EXISTS(CONTROLLER_FAN6) + SET_CONTROLLER_FAN(6); + #endif + #if PIN_EXISTS(CONTROLLER_FAN7) + SET_CONTROLLER_FAN(7); + #endif + #if PIN_EXISTS(CONTROLLER_FAN8) + SET_CONTROLLER_FAN(8); + #endif + #if PIN_EXISTS(CONTROLLER_FAN9) + SET_CONTROLLER_FAN(9); #endif #endif } diff --git a/Marlin/src/feature/cooler.h b/Marlin/src/feature/cooler.h index 9891514e23..ef3590c593 100644 --- a/Marlin/src/feature/cooler.h +++ b/Marlin/src/feature/cooler.h @@ -40,7 +40,7 @@ public: static bool enabled; static void enable() { enabled = true; } static void disable() { enabled = false; } - static void toggle() { enabled = !enabled; } + static void toggle() { FLIP(enabled); } static uint8_t mode; // 0 = CO2 Liquid cooling, 1 = Laser Diode TEC Heatsink Cooling static void set_mode(const uint8_t m) { mode = m; } @@ -96,7 +96,7 @@ public: #if ENABLED(FLOWMETER_SAFETY) static bool flowfault; // Flag that the cooler is in a fault state static bool flowsafety_enabled; // Flag to disable the cutter if flow rate is too low - static void flowsafety_toggle() { flowsafety_enabled = !flowsafety_enabled; } + static void flowsafety_toggle() { FLIP(flowsafety_enabled); } static bool check_flow_too_low() { const bool too_low = flowsafety_enabled && flowrate < (FLOWMETER_MIN_LITERS_PER_MINUTE); flowfault = too_low; diff --git a/Marlin/src/feature/dac/dac_dac084s085.cpp b/Marlin/src/feature/dac/dac_dac084s085.cpp index 772bb68de4..1338e5979d 100644 --- a/Marlin/src/feature/dac/dac_dac084s085.cpp +++ b/Marlin/src/feature/dac/dac_dac084s085.cpp @@ -10,7 +10,6 @@ #include "dac_dac084s085.h" -#include "../../MarlinCore.h" #include "../../HAL/shared/Delay.h" dac084s085::dac084s085() { } diff --git a/Marlin/src/feature/dac/stepper_dac.cpp b/Marlin/src/feature/dac/stepper_dac.cpp index f5664bc598..65423d3189 100644 --- a/Marlin/src/feature/dac/stepper_dac.cpp +++ b/Marlin/src/feature/dac/stepper_dac.cpp @@ -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(")")); diff --git a/Marlin/src/feature/direct_stepping.cpp b/Marlin/src/feature/direct_stepping.cpp index 13cf71e076..08cda561b1 100644 --- a/Marlin/src/feature/direct_stepping.cpp +++ b/Marlin/src/feature/direct_stepping.cpp @@ -175,7 +175,7 @@ namespace DirectStepping { template void SerialPageManager::write_responses() { if (fatal_error) { - kill(GET_TEXT_F(MSG_BAD_PAGE)); + marlin.kill(GET_TEXT_F(MSG_BAD_PAGE)); return; } diff --git a/Marlin/src/feature/e_parser.cpp b/Marlin/src/feature/e_parser.cpp index e249d81969..bda1232154 100644 --- a/Marlin/src/feature/e_parser.cpp +++ b/Marlin/src/feature/e_parser.cpp @@ -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 @@ -46,9 +49,6 @@ bool EmergencyParser::killed_by_M112, // = false // Global instance EmergencyParser emergency_parser; -// External references -extern bool wait_for_user, wait_for_heatup; - #if ENABLED(EP_BABYSTEPPING) #include "babystep.h" #endif @@ -147,9 +147,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; @@ -192,9 +205,12 @@ void EmergencyParser::update(EmergencyParser::State &state, const uint8_t c) { default: if (ISEOL(c)) { if (enabled) switch (state) { - case EP_M108: wait_for_user = wait_for_heatup = false; break; + case EP_M108: marlin.end_waiting(); 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; diff --git a/Marlin/src/feature/e_parser.h b/Marlin/src/feature/e_parser.h index 8dacb0581c..9f74a38116 100644 --- a/Marlin/src/feature/e_parser.h +++ b/Marlin/src/feature/e_parser.h @@ -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 @@ -79,6 +86,8 @@ public: static void update(State &state, const uint8_t c); + static bool isEnabled() { return enabled; } + private: static bool enabled; }; diff --git a/Marlin/src/feature/easythreed_ui.cpp b/Marlin/src/feature/easythreed_ui.cpp index 9617c62eb9..7180c4dbcd 100644 --- a/Marlin/src/feature/easythreed_ui.cpp +++ b/Marlin/src/feature/easythreed_ui.cpp @@ -78,9 +78,9 @@ void EasythreedUI::blinkLED() { prev_blink_interval_ms = blink_interval_ms; blink_start_ms = ms; } - if (PENDING(ms, blink_start_ms + blink_interval_ms)) + if (PENDING(ms, blink_start_ms, blink_interval_ms)) WRITE(EASYTHREED_LED_PIN, LOW); - else if (PENDING(ms, blink_start_ms + 2 * blink_interval_ms)) + else if (PENDING(ms, blink_start_ms, 2 * blink_interval_ms)) WRITE(EASYTHREED_LED_PIN, HIGH); else blink_start_ms = ms; @@ -91,7 +91,7 @@ void EasythreedUI::blinkLED() { // Load/Unload buttons are a 3 position switch with a common center ground. // void EasythreedUI::loadButton() { - if (printingIsActive()) return; + if (marlin.printingIsActive()) return; enum FilamentStatus : uint8_t { FS_IDLE, FS_PRESS, FS_CHECK, FS_PROCEED }; static uint8_t filament_status = FS_IDLE; @@ -107,7 +107,7 @@ void EasythreedUI::loadButton() { break; case FS_PRESS: - if (ELAPSED(millis(), filament_time + BTN_DEBOUNCE_MS)) { // After a short debounce delay... + if (ELAPSED(millis(), filament_time, BTN_DEBOUNCE_MS)) { // After a short debounce delay... if (!READ(BTN_RETRACT) || !READ(BTN_FEED)) { // ...if switch still toggled... thermalManager.setTargetHotend(EXTRUDE_MINTEMP + 10, 0); // Start heating up blink_interval_ms = LED_BLINK_7; // Set the LED to blink fast @@ -131,7 +131,7 @@ void EasythreedUI::loadButton() { break; case FS_PROCEED: { - // Feed or Retract just once. Hard abort all moves and return to idle on swicth release. + // Feed or Retract just once. Hard abort all moves and return to idle on switch release. static bool flag = false; if (READ(BTN_RETRACT) && READ(BTN_FEED)) { // Switch in center position (stop) flag = false; // Restore flag to false @@ -175,17 +175,17 @@ void EasythreedUI::printButton() { break; case KS_PRESS: - if (ELAPSED(ms, key_time + BTN_DEBOUNCE_MS)) // Wait for debounce interval to expire + if (ELAPSED(ms, key_time, BTN_DEBOUNCE_MS)) // Wait for debounce interval to expire key_status = READ(BTN_PRINT) ? KS_IDLE : KS_PROCEED; // Proceed if still pressed break; case KS_PROCEED: if (!READ(BTN_PRINT)) break; // Wait for the button to be released key_status = KS_IDLE; // Ready for the next press - if (PENDING(ms, key_time + 1200 - BTN_DEBOUNCE_MS)) { // Register a press < 1.2 seconds + if (PENDING(ms, key_time, 1200 - BTN_DEBOUNCE_MS)) { // Register a press < 1.2 seconds switch (print_key_flag) { case PF_START: { // The "Print" button starts an SD card print - if (printingIsActive()) break; // Already printing? (find another line that checks for 'is planner doing anything else right now?') + if (marlin.printingIsActive()) break; // Already printing? (find another line that checks for 'is planner doing anything else right now?') blink_interval_ms = LED_BLINK_2; // Blink the indicator LED at 1 second intervals print_key_flag = PF_PAUSE; // The "Print" button now pauses the print card.mount(); // Force SD card to mount - now! @@ -201,13 +201,13 @@ void EasythreedUI::printButton() { card.openAndPrintFile(card.filename); // Start printing it } break; case PF_PAUSE: { // Pause printing (not currently firing) - if (!printingIsActive()) break; + if (!marlin.printingIsActive()) break; blink_interval_ms = LED_ON; // Set indicator to steady ON queue.inject(F("M25")); // Queue Pause print_key_flag = PF_RESUME; // The "Print" button now resumes the print } break; case PF_RESUME: { // Resume printing - if (printingIsActive()) break; + if (marlin.printingIsActive()) break; blink_interval_ms = LED_BLINK_2; // Blink the indicator LED at 1 second intervals queue.inject(F("M24")); // Queue resume print_key_flag = PF_PAUSE; // The "Print" button now pauses the print @@ -215,7 +215,7 @@ void EasythreedUI::printButton() { } } else { // Register a longer press - if (print_key_flag == PF_START && !printingIsActive()) { // While not printing, this moves Z up 10mm + if (print_key_flag == PF_START && !marlin.printingIsActive()) { // While not printing, this moves Z up 10mm blink_interval_ms = LED_ON; queue.inject(F("G91\nG0 Z10 F600\nG90")); // Raise Z soon after returning to main loop } diff --git a/Marlin/src/feature/encoder_i2c.cpp b/Marlin/src/feature/encoder_i2c.cpp index 55bde4ca62..7c83053b89 100644 --- a/Marlin/src/feature/encoder_i2c.cpp +++ b/Marlin/src/feature/encoder_i2c.cpp @@ -149,7 +149,7 @@ void I2CPositionEncoder::update() { #ifdef I2CPE_ERR_THRESH_ABORT if (ABS(error) > I2CPE_ERR_THRESH_ABORT * planner.settings.axis_steps_per_mm[encoderAxis]) { - //kill(F("Significant Error")); + //marlin.kill(F("Significant Error")); SERIAL_ECHOLNPGM("Axis error over threshold, aborting!", error); safe_delay(5000); } @@ -168,8 +168,7 @@ void I2CPositionEncoder::update() { float sumP = 0; for (uint8_t i = 0; i < I2CPE_ERR_PRST_ARRAY_SIZE; ++i) sumP += errPrst[i]; const int32_t errorP = int32_t(sumP * RECIPROCAL(I2CPE_ERR_PRST_ARRAY_SIZE)); - SERIAL_CHAR(AXIS_CHAR(encoderAxis)); - SERIAL_ECHOLNPGM(" : CORRECT ERR ", errorP * planner.mm_per_step[encoderAxis], "mm"); + SERIAL_ECHOLN(C(AXIS_CHAR(encoderAxis)), F(" : CORRECT ERR "), errorP * planner.mm_per_step[encoderAxis], F("mm")); babystep.add_steps(encoderAxis, -LROUND(errorP)); errPrstIdx = 0; } @@ -188,8 +187,7 @@ void I2CPositionEncoder::update() { if (ABS(error) > I2CPE_ERR_CNT_THRESH * planner.settings.axis_steps_per_mm[encoderAxis]) { const millis_t ms = millis(); if (ELAPSED(ms, nextErrorCountTime)) { - SERIAL_CHAR(AXIS_CHAR(encoderAxis)); - SERIAL_ECHOLNPGM(" : LARGE ERR ", error, "; diffSum=", diffSum); + SERIAL_ECHOLN(C(AXIS_CHAR(encoderAxis)), F(" : LARGE ERR "), error, F("; diffSum="), diffSum); errorCount++; nextErrorCountTime = ms + I2CPE_ERR_CNT_DEBOUNCE_MS; } @@ -208,8 +206,7 @@ void I2CPositionEncoder::set_homed() { homed = trusted = true; #ifdef I2CPE_DEBUG - SERIAL_CHAR(AXIS_CHAR(encoderAxis)); - SERIAL_ECHOLNPGM(" axis encoder homed, offset of ", zeroOffset, " ticks."); + SERIAL_ECHO(C(AXIS_CHAR(encoderAxis)), F(" axis encoder homed, offset of "), zeroOffset, F(" ticks.\n")); #endif } } @@ -219,8 +216,7 @@ void I2CPositionEncoder::set_unhomed() { homed = trusted = false; #ifdef I2CPE_DEBUG - SERIAL_CHAR(AXIS_CHAR(encoderAxis)); - SERIAL_ECHOLNPGM(" axis encoder unhomed."); + SERIAL_ECHO(C(AXIS_CHAR(encoderAxis)), F(" axis encoder unhomed.\n")); #endif } @@ -247,10 +243,8 @@ float I2CPositionEncoder::get_axis_error_mm(const bool report) { diff = actual - target, error = ABS(diff) > 10000 ? 0 : diff; // Huge error is a bad reading - if (report) { - SERIAL_CHAR(AXIS_CHAR(encoderAxis)); - SERIAL_ECHOLNPGM(" axis target=", target, "mm; actual=", actual, "mm; err=", error, "mm"); - } + if (report) + SERIAL_ECHO(C(AXIS_CHAR(encoderAxis)), F(" axis target="), target, F("mm; actual="), actual, F("mm; err="), error, F("mm\n")); return error; } @@ -282,10 +276,8 @@ int32_t I2CPositionEncoder::get_axis_error_steps(const bool report) { errorPrev = error; - if (report) { - SERIAL_CHAR(AXIS_CHAR(encoderAxis)); - SERIAL_ECHOLNPGM(" axis target=", target, "; actual=", encoderCountInStepperTicksScaled, "; err=", error); - } + if (report) + SERIAL_ECHOLN(C(AXIS_CHAR(encoderAxis)), F(" axis target="), target, F("; actual="), encoderCountInStepperTicksScaled, F("; err="), error); if (suppressOutput) { if (report) SERIAL_ECHOLNPGM("!Discontinuity. Suppressing error."); @@ -647,23 +639,22 @@ void I2CPositionEncodersMgr::init() { void I2CPositionEncodersMgr::report_position(const int8_t idx, const bool units, const bool noOffset) { CHECK_IDX(); - if (units) + if (units) { SERIAL_ECHOLN(noOffset ? encoders[idx].mm_from_count(encoders[idx].get_raw_count()) : encoders[idx].get_position_mm()); - else { - if (noOffset) { - const int32_t raw_count = encoders[idx].get_raw_count(); - SERIAL_CHAR(AXIS_CHAR(encoders[idx).get_axis()], ' '); - - for (uint8_t j = 31; j > 0; j--) - SERIAL_ECHO((bool)(0x00000001 & (raw_count >> j))); - - SERIAL_ECHO((bool)(0x00000001 & raw_count)); - SERIAL_CHAR(' '); - SERIAL_ECHOLN(raw_count); - } - else - SERIAL_ECHOLN(encoders[idx].get_position()); + return; } + + if (noOffset) { + const int32_t raw_count = encoders[idx].get_raw_count(); + SERIAL_CHAR(AXIS_CHAR(encoders[idx].get_axis()), ' '); + + for (uint8_t j = 31; j >= 0; j--) + SERIAL_ECHO(TEST32(raw_count, j)); + + SERIAL_ECHOLN(C(' '), raw_count); + } + else + SERIAL_ECHOLN(encoders[idx].get_position()); } void I2CPositionEncodersMgr::change_module_address(const uint8_t oldaddr, const uint8_t newaddr) { @@ -707,7 +698,7 @@ void I2CPositionEncodersMgr::change_module_address(const uint8_t oldaddr, const // and enable it (it will likely have failed initialization on power-up, before the address change). const int8_t idx = idx_from_addr(newaddr); if (idx >= 0 && !encoders[idx].get_active()) { - SERIAL_CHAR(AXIS_CHAR(encoders[idx).get_axis()]); + SERIAL_CHAR(AXIS_CHAR(encoders[idx].get_axis())); SERIAL_ECHOLNPGM(" axis encoder was not detected on printer startup. Trying again."); encoders[idx].set_active(encoders[idx].passes_test(true)); } @@ -810,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); } } @@ -837,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); } } @@ -865,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); } } @@ -896,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); } } @@ -972,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()); } } @@ -1003,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); } } } @@ -1041,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); } } } @@ -1077,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()); @@ -1111,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); } } diff --git a/Marlin/src/feature/encoder_i2c.h b/Marlin/src/feature/encoder_i2c.h index 861a8e52d4..e8485a6b75 100644 --- a/Marlin/src/feature/encoder_i2c.h +++ b/Marlin/src/feature/encoder_i2c.h @@ -188,7 +188,7 @@ class I2CPositionEncoder { FORCE_INLINE void set_ec_method(const byte method) { ecMethod = method; } FORCE_INLINE float get_ec_threshold() { return ecThreshold; } - FORCE_INLINE void set_ec_threshold(const_float_t newThreshold) { ecThreshold = newThreshold; } + FORCE_INLINE void set_ec_threshold(const float newThreshold) { ecThreshold = newThreshold; } FORCE_INLINE int get_encoder_ticks_mm() { switch (type) { diff --git a/Marlin/src/feature/ethernet.cpp b/Marlin/src/feature/ethernet.cpp index 9b022b4e17..cdf176f832 100644 --- a/Marlin/src/feature/ethernet.cpp +++ b/Marlin/src/feature/ethernet.cpp @@ -172,4 +172,46 @@ void MarlinEthernet::check() { } } +void say_ethernet() { SERIAL_ECHOPGM(" Ethernet "); } + +void MarlinEthernet::ETH0_report(const bool forReplay/*=true*/) { + say_ethernet(); + SERIAL_ECHO_TERNARY(ethernet.hardware_enabled, "port ", "en", "dis", "abled.\n"); + if (ethernet.hardware_enabled) { + say_ethernet(); + SERIAL_ECHO_TERNARY(ethernet.have_telnet_client, "client ", "en", "dis", "abled.\n"); + } + else + SERIAL_ECHOLNPGM("Send 'M552 S1' to enable."); +} + +void MarlinEthernet::MAC_report(const bool forReplay/*=true*/) { + if (!forReplay) SERIAL_ECHO_START(); + SERIAL_ECHOPGM("MAC: "); + if (ethernet.hardware_enabled) { + uint8_t mac[6]; + Ethernet.MACAddress(mac); + for (uint8_t i = 0; i < 6; ++i) { + if (mac[i] < 0x10) SERIAL_CHAR('0'); + SERIAL_PRINT(mac[i], PrintBase::Hex); + if (i < 5) SERIAL_CHAR(':'); + } + } + else + SERIAL_ECHOPGM("Disabled"); + SERIAL_EOL(); +} + +// Display current values when the link is active, +// otherwise show the stored values +void MarlinEthernet::ip_report(const uint16_t cmd, FSTR_P const post, const IPAddress &ipo, const bool forReplay/*=true*/) { + if (!forReplay) SERIAL_ECHO_START(); + SERIAL_ECHO(F(" M"), cmd, C(' ')); + for (uint8_t i = 0; i < 4; ++i) { + SERIAL_ECHO(ipo[i]); + if (i < 3) SERIAL_CHAR('.'); + } + SERIAL_ECHOLN(F(" ; "), post); +} + #endif // HAS_ETHERNET diff --git a/Marlin/src/feature/ethernet.h b/Marlin/src/feature/ethernet.h index 70a58efce7..7aa364fc3c 100644 --- a/Marlin/src/feature/ethernet.h +++ b/Marlin/src/feature/ethernet.h @@ -25,6 +25,8 @@ #include #endif +#include "../HAL/shared/Marduino.h" + // Teensy 4.1 uses internal MAC Address class MarlinEthernet { @@ -34,6 +36,10 @@ class MarlinEthernet { static EthernetClient telnetClient; static void init(); static void check(); + + static void ETH0_report(const bool forReplay=true); + static void MAC_report(const bool forReplay=true); + static void ip_report(const uint16_t cmd, FSTR_P const post, const IPAddress &ipo, const bool forReplay=true); }; extern MarlinEthernet ethernet; diff --git a/Marlin/src/feature/fancheck.cpp b/Marlin/src/feature/fancheck.cpp index 844191e7e4..d0582ed97a 100644 --- a/Marlin/src/feature/fancheck.cpp +++ b/Marlin/src/feature/fancheck.cpp @@ -42,62 +42,18 @@ bool FanCheck::enabled; void FanCheck::init() { #define _TACHINIT(N) TERN(E##N##_FAN_TACHO_PULLUP, SET_INPUT_PULLUP, TERN(E##N##_FAN_TACHO_PULLDOWN, SET_INPUT_PULLDOWN, SET_INPUT))(E##N##_FAN_TACHO_PIN) - #if HAS_E0_FAN_TACHO - _TACHINIT(0); - #endif - #if HAS_E1_FAN_TACHO - _TACHINIT(1); - #endif - #if HAS_E2_FAN_TACHO - _TACHINIT(2); - #endif - #if HAS_E3_FAN_TACHO - _TACHINIT(3); - #endif - #if HAS_E4_FAN_TACHO - _TACHINIT(4); - #endif - #if HAS_E5_FAN_TACHO - _TACHINIT(5); - #endif - #if HAS_E6_FAN_TACHO - _TACHINIT(6); - #endif - #if HAS_E7_FAN_TACHO - _TACHINIT(7); - #endif + #define _EN_TACHINIT(N) TERF(HAS_E##N##_FAN_TACHO, _TACHINIT)(N); + REPEAT(8, _EN_TACHINIT); } void FanCheck::update_tachometers() { bool status; - #define _TACHO_CASE(N) case N: status = READ(E##N##_FAN_TACHO_PIN); break; + #define __TACHO_GET_STATUS(N) case N: status = READ(E##N##_FAN_TACHO_PIN); break; + #define _TACHO_GET_STATUS(N) TERF(HAS_E##N##_FAN_TACHO, __TACHO_GET_STATUS)(N) for (uint8_t f = 0; f < TACHO_COUNT; ++f) { switch (f) { - #if HAS_E0_FAN_TACHO - _TACHO_CASE(0) - #endif - #if HAS_E1_FAN_TACHO - _TACHO_CASE(1) - #endif - #if HAS_E2_FAN_TACHO - _TACHO_CASE(2) - #endif - #if HAS_E3_FAN_TACHO - _TACHO_CASE(3) - #endif - #if HAS_E4_FAN_TACHO - _TACHO_CASE(4) - #endif - #if HAS_E5_FAN_TACHO - _TACHO_CASE(5) - #endif - #if HAS_E6_FAN_TACHO - _TACHO_CASE(6) - #endif - #if HAS_E7_FAN_TACHO - _TACHO_CASE(7) - #endif + REPEAT(8, _TACHO_GET_STATUS) default: continue; } @@ -115,14 +71,8 @@ void FanCheck::compute_speed(uint16_t elapsedTime) { uint8_t fan_error_msk = 0; for (uint8_t f = 0; f < TACHO_COUNT; ++f) { switch (f) { - TERN_(HAS_E0_FAN_TACHO, case 0:) - TERN_(HAS_E1_FAN_TACHO, case 1:) - TERN_(HAS_E2_FAN_TACHO, case 2:) - TERN_(HAS_E3_FAN_TACHO, case 3:) - TERN_(HAS_E4_FAN_TACHO, case 4:) - TERN_(HAS_E5_FAN_TACHO, case 5:) - TERN_(HAS_E6_FAN_TACHO, case 6:) - TERN_(HAS_E7_FAN_TACHO, case 7:) + #define _EN_COMPUTE_FAN_CASE(N) TERN_(HAS_E##N##_FAN_TACHO, case N:) + REPEAT(8, _EN_COMPUTE_FAN_CASE) // Compute fan speed rps[f] = edge_counter[f] * float(250) / elapsedTime; edge_counter[f] = 0; @@ -143,7 +93,7 @@ void FanCheck::compute_speed(uint16_t elapsedTime) { // Drop the error when all fans are ok if (!fan_error_msk && error == TachoError::REPORTED) error = TachoError::FIXED; - if (error == TachoError::FIXED && !printJobOngoing() && !printingIsPaused()) { + if (error == TachoError::FIXED && !marlin.printJobOngoing() && !marlin.printingIsPaused()) { error = TachoError::NONE; // if the issue has been fixed while the printer is idle, reenable immediately ui.reset_alert_level(); } @@ -156,17 +106,17 @@ void FanCheck::compute_speed(uint16_t elapsedTime) { } void FanCheck::report_speed_error(uint8_t fan) { - if (printJobOngoing()) { + if (marlin.printJobOngoing()) { if (error == TachoError::NONE) { if (thermalManager.degTargetHotend(fan) != 0) { - kill(GET_TEXT_F(MSG_FAN_SPEED_FAULT)); + marlin.kill(GET_TEXT_F(MSG_FAN_SPEED_FAULT)); error = TachoError::REPORTED; } else error = TachoError::DETECTED; // Plans error for next processed command } } - else if (!printingIsPaused()) { + else if (!marlin.printingIsPaused()) { thermalManager.setTargetHotend(0, fan); // Always disable heating if (error == TachoError::NONE) error = TachoError::REPORTED; } @@ -179,14 +129,8 @@ void FanCheck::print_fan_states() { for (uint8_t s = 0; s < 2; ++s) { for (uint8_t f = 0; f < TACHO_COUNT; ++f) { switch (f) { - TERN_(HAS_E0_FAN_TACHO, case 0:) - TERN_(HAS_E1_FAN_TACHO, case 1:) - TERN_(HAS_E2_FAN_TACHO, case 2:) - TERN_(HAS_E3_FAN_TACHO, case 3:) - TERN_(HAS_E4_FAN_TACHO, case 4:) - TERN_(HAS_E5_FAN_TACHO, case 5:) - TERN_(HAS_E6_FAN_TACHO, case 6:) - TERN_(HAS_E7_FAN_TACHO, case 7:) + #define _EN_PRINT_FAN_CASE(N) TERN_(HAS_E##N##_FAN_TACHO, case N:) + REPEAT(8, _EN_PRINT_FAN_CASE) SERIAL_ECHOPGM("E", f); if (s == 0) SERIAL_ECHOPGM(":", 60 * rps[f], " RPM "); diff --git a/Marlin/src/feature/fancheck.h b/Marlin/src/feature/fancheck.h index b13a34fb19..fed6a798e1 100644 --- a/Marlin/src/feature/fancheck.h +++ b/Marlin/src/feature/fancheck.h @@ -25,7 +25,6 @@ #if HAS_FANCHECK -#include "../MarlinCore.h" #include "../lcd/marlinui.h" #if ENABLED(AUTO_REPORT_FANS) @@ -67,14 +66,18 @@ class FanCheck { static void compute_speed(uint16_t elapsedTime); static void print_fan_states(); #if HAS_PWMFANCHECK - static void toggle_measuring() { measuring = !measuring; } + static void toggle_measuring() { FLIP(measuring); } static bool is_measuring() { return measuring; } #endif static void check_deferred_error() { if (error == TachoError::DETECTED) { error = TachoError::REPORTED; - TERN(PARK_HEAD_ON_PAUSE, queue.inject(F("M125")), kill(GET_TEXT_F(MSG_FAN_SPEED_FAULT))); + #if ENABLED(PARK_HEAD_ON_PAUSE) + queue.inject(F("M125")); + #else + marlin.kill(GET_TEXT_F(MSG_FAN_SPEED_FAULT)); + #endif } } diff --git a/Marlin/src/feature/filwidth.h b/Marlin/src/feature/filwidth.h index ab50fe0af3..a16240936a 100644 --- a/Marlin/src/feature/filwidth.h +++ b/Marlin/src/feature/filwidth.h @@ -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 @@ -78,7 +78,7 @@ public: static void update_measured_mm() { measured_mm = raw_to_mm(); } // Update ring buffer used to delay filament measurements - static void advance_e(const_float_t e_move) { + static void advance_e(const float e_move) { // Increment counters with the E distance e_count += e_move; diff --git a/Marlin/src/feature/fwretract.cpp b/Marlin/src/feature/fwretract.cpp index fff2a1ed39..5ea20401ea 100644 --- a/Marlin/src/feature/fwretract.cpp +++ b/Marlin/src/feature/fwretract.cpp @@ -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 @@ -244,6 +243,7 @@ void FWRetract::M208_report() { " M208 S", LINEAR_UNIT(settings.retract_recover_extra) , " W", LINEAR_UNIT(settings.swap_retract_recover_extra) , " F", LINEAR_UNIT(MMS_TO_MMM(settings.retract_recover_feedrate_mm_s)) + , " R", LINEAR_UNIT(MMS_TO_MMM(settings.swap_retract_recover_feedrate_mm_s)) ); } diff --git a/Marlin/src/feature/host_actions.cpp b/Marlin/src/feature/host_actions.cpp index 538aa92e91..94bc4db011 100644 --- a/Marlin/src/feature/host_actions.cpp +++ b/Marlin/src/feature/host_actions.cpp @@ -87,10 +87,6 @@ void HostUI::action(FSTR_P const fstr, const bool eol) { PGMSTR(CONTINUE_STR, "Continue"); PGMSTR(DISMISS_STR, "Dismiss"); - #if HAS_RESUME_CONTINUE - extern bool wait_for_user; - #endif - void HostUI::notify(const char * const cstr) { PORT_REDIRECT(SerialMask::All); action(F("notification "), false); @@ -205,7 +201,7 @@ void HostUI::action(FSTR_P const fstr, const bool eol) { } break; case PROMPT_USER_CONTINUE: - TERN_(HAS_RESUME_CONTINUE, wait_for_user = false); + TERN_(HAS_RESUME_CONTINUE, marlin.user_resume()); break; case PROMPT_PAUSE_RESUME: #if ALL(ADVANCED_PAUSE_FEATURE, HAS_MEDIA) diff --git a/Marlin/src/feature/hotend_idle.cpp b/Marlin/src/feature/hotend_idle.cpp index eb16781fdd..a779efeaff 100644 --- a/Marlin/src/feature/hotend_idle.cpp +++ b/Marlin/src/feature/hotend_idle.cpp @@ -43,7 +43,7 @@ millis_t HotendIdleProtection::next_protect_ms = 0; hotend_idle_settings_t HotendIdleProtection::cfg; // Initialized by settings.load void HotendIdleProtection::check_hotends(const millis_t &ms) { - const bool busy = (TERN0(HAS_RESUME_CONTINUE, wait_for_user) || planner.has_blocks_queued()); + const bool busy = (TERN0(HAS_RESUME_CONTINUE, marlin.wait_for_user) || planner.has_blocks_queued()); bool do_prot = false; if (!busy && cfg.timeout != 0) { HOTEND_LOOP() { diff --git a/Marlin/src/feature/joystick.cpp b/Marlin/src/feature/joystick.cpp index 29addfcf1e..cbfab1fed8 100644 --- a/Marlin/src/feature/joystick.cpp +++ b/Marlin/src/feature/joystick.cpp @@ -67,18 +67,10 @@ Joystick joystick; #if ENABLED(JOYSTICK_DEBUG) void Joystick::report() { SERIAL_ECHOPGM("Joystick"); - #if HAS_JOY_ADC_X - SERIAL_ECHOPGM_P(SP_X_STR, JOY_X(x.getraw())); - #endif - #if HAS_JOY_ADC_Y - SERIAL_ECHOPGM_P(SP_Y_STR, JOY_Y(y.getraw())); - #endif - #if HAS_JOY_ADC_Z - SERIAL_ECHOPGM_P(SP_Z_STR, JOY_Z(z.getraw())); - #endif - #if HAS_JOY_ADC_EN - SERIAL_ECHO_TERNARY(READ(JOY_EN_PIN), " EN=", "HIGH (dis", "LOW (en", "abled)"); - #endif + TERF(HAS_JOY_ADC_X, SERIAL_ECHOPGM_P)(SP_X_STR, JOY_X(x.getraw())); + TERF(HAS_JOY_ADC_Y, SERIAL_ECHOPGM_P)(SP_Y_STR, JOY_Y(y.getraw())); + TERF(HAS_JOY_ADC_Z, SERIAL_ECHOPGM_P)(SP_Z_STR, JOY_Z(z.getraw())); + TERF(HAS_JOY_ADC_EN, SERIAL_ECHO_TERNARY)(READ(JOY_EN_PIN), " EN=", "HIGH (dis", "LOW (en", "abled)"); SERIAL_EOL(); } #endif diff --git a/Marlin/src/feature/leds/blinkm.cpp b/Marlin/src/feature/leds/blinkm.cpp index 868eb4b3d9..b040c8e76f 100644 --- a/Marlin/src/feature/leds/blinkm.cpp +++ b/Marlin/src/feature/leds/blinkm.cpp @@ -32,7 +32,7 @@ #include "leds.h" #include -void blinkm_set_led_color(const LEDColor &color) { +void blinkm_set_led_color(const LED1Color_t &color) { Wire.begin(); Wire.beginTransmission(I2C_ADDRESS(0x09)); Wire.write('o'); //to disable ongoing script, only needs to be used once diff --git a/Marlin/src/feature/leds/blinkm.h b/Marlin/src/feature/leds/blinkm.h index 29a9e78412..d3c528acbf 100644 --- a/Marlin/src/feature/leds/blinkm.h +++ b/Marlin/src/feature/leds/blinkm.h @@ -25,7 +25,6 @@ * blinkm.h - Control a BlinkM over i2c */ -struct LEDColor; -typedef LEDColor LEDColor; +struct LED1Color_t; -void blinkm_set_led_color(const LEDColor &color); +void blinkm_set_led_color(const LED1Color_t &color); diff --git a/Marlin/src/feature/leds/leds.cpp b/Marlin/src/feature/leds/leds.cpp index 0c70253dc8..55a10fcbbd 100644 --- a/Marlin/src/feature/leds/leds.cpp +++ b/Marlin/src/feature/leds/leds.cpp @@ -35,15 +35,15 @@ #endif #if ENABLED(LED_COLOR_PRESETS) - const LEDColor LEDLights::defaultLEDColor = LEDColor( + const LED1Color_t LEDLights::defaultLEDColor { LED_USER_PRESET_RED, LED_USER_PRESET_GREEN, LED_USER_PRESET_BLUE OPTARG(HAS_WHITE_LED, LED_USER_PRESET_WHITE) OPTARG(NEOPIXEL_LED, LED_USER_PRESET_BRIGHTNESS) - ); + }; #endif #if ANY(LED_CONTROL_MENU, PRINTER_EVENT_LEDS, CASE_LIGHT_IS_COLOR_LED) - LEDColor LEDLights::color; + LED1Color_t LEDLights::color; bool LEDLights::lights_on; #endif @@ -101,7 +101,7 @@ void LEDLights::setup() { constexpr int8_t led_pin_count = TERN(HAS_WHITE_LED, 4, 3); // Startup animation - LEDColor curColor = LEDColorOff(); + LED1Color_t curColor = LEDColorOff(); PCA9632_set_led_color(curColor); // blackout delay(200); @@ -156,15 +156,15 @@ void LEDLights::setup() { TERN_(LED_USER_PRESET_STARTUP, set_default()); } -void LEDLights::set_color(const LEDColor &incol +void LEDLights::set_color(const LED1Color_t &incol OPTARG(NEOPIXEL_IS_SEQUENTIAL, bool isSequence/*=false*/) ) { #if ENABLED(NEOPIXEL_LED) const uint32_t neocolor = LEDColorWhite() == incol - ? neo.Color(NEO_WHITE) - : neo.Color(incol.r, incol.g, incol.b OPTARG(HAS_WHITE_LED, incol.w)); + ? neo.White() + : neo.Color(incol.r, incol.g, incol.b OPTARG(HAS_WHITE_NEOPIXEL_1, incol.w)); #if ENABLED(NEOPIXEL_IS_SEQUENTIAL) static uint16_t nextLed = 0; @@ -258,7 +258,7 @@ void LEDLights::set_color(const LEDColor &incol #if ENABLED(NEOPIXEL2_SEPARATE) #if ENABLED(NEO2_COLOR_PRESETS) - const LEDColor LEDLights2::defaultLEDColor = LEDColor( + const LED2Color_t LEDLights2::defaultLEDColor2 = LED2Color_t( NEO2_USER_PRESET_RED, NEO2_USER_PRESET_GREEN, NEO2_USER_PRESET_BLUE OPTARG(HAS_WHITE_LED2, NEO2_USER_PRESET_WHITE) OPTARG(NEOPIXEL_LED, NEO2_USER_PRESET_BRIGHTNESS) @@ -266,7 +266,7 @@ void LEDLights::set_color(const LEDColor &incol #endif #if ENABLED(LED_CONTROL_MENU) - LEDColor LEDLights2::color; + LED2Color_t LEDLights2::color; bool LEDLights2::lights_on; #endif @@ -277,10 +277,10 @@ void LEDLights::set_color(const LEDColor &incol TERN_(NEO2_USER_PRESET_STARTUP, set_default()); } - void LEDLights2::set_color(const LEDColor &incol) { - const uint32_t neocolor = LEDColorWhite() == incol - ? neo2.Color(NEO2_WHITE) - : neo2.Color(incol.r, incol.g, incol.b OPTARG(HAS_WHITE_LED2, incol.w)); + void LEDLights2::set_color(const LED2Color_t &incol) { + const uint32_t neocolor = LEDColorWhite2() == incol + ? neo2.White() + : neo2.Color(incol.r, incol.g, incol.b OPTARG(HAS_WHITE_NEOPIXEL_2, incol.w)); neo2.set_brightness(incol.i); neo2.set_color(neocolor); diff --git a/Marlin/src/feature/leds/leds.h b/Marlin/src/feature/leds/leds.h index da8ba42fba..3ba3a31cdb 100644 --- a/Marlin/src/feature/leds/leds.h +++ b/Marlin/src/feature/leds/leds.h @@ -29,11 +29,6 @@ #include -// A white component can be passed -#if ANY(RGBW_LED, PCA9632_RGBW) - #define HAS_WHITE_LED 1 -#endif - #if ENABLED(NEOPIXEL_LED) #define _NEOPIXEL_INCLUDE_ #include "neopixel.h" @@ -52,75 +47,142 @@ #include "pca9632.h" #endif +#if ANY(RGBW_LED, PCA9632_RGBW, HAS_WHITE_NEOPIXEL_1) + #define HAS_WHITE_LED 1 +#endif +#if HAS_WHITE_NEOPIXEL_2 + #define HAS_WHITE_LED2 1 +#endif + /** * LEDcolor type for use with leds.set_color */ -typedef struct LEDColor { - uint8_t r, g, b - OPTARG(HAS_WHITE_LED, w) - OPTARG(NEOPIXEL_LED, i) - ; +struct LED1Color_t { + // Basic RGB color components + uint8_t r, g, b OPTARG(HAS_WHITE_LED, w) OPTARG(NEOPIXEL_LED, i); + // Default constructor - white color + LED1Color_t() : r(255), g(255), b(255) OPTARG(HAS_WHITE_LED, w(255)) OPTARG(NEOPIXEL_LED, i(NEOPIXEL_BRIGHTNESS)){} - LEDColor() : r(255), g(255), b(255) - OPTARG(HAS_WHITE_LED, w(255)) - OPTARG(NEOPIXEL_LED, i(NEOPIXEL_BRIGHTNESS)) - {} + // Copy constructor + LED1Color_t(const LED1Color_t&) = default; - LEDColor(const LEDColor&) = default; - - LEDColor(uint8_t r, uint8_t g, uint8_t b OPTARG(HAS_WHITE_LED, uint8_t w=0) OPTARG(NEOPIXEL_LED, uint8_t i=NEOPIXEL_BRIGHTNESS)) + // Constructor with individual components + LED1Color_t(uint8_t r, uint8_t g, uint8_t b OPTARG(HAS_WHITE_LED, uint8_t w=0) OPTARG(NEOPIXEL_LED, uint8_t i=NEOPIXEL_BRIGHTNESS)) : r(r), g(g), b(b) OPTARG(HAS_WHITE_LED, w(w)) OPTARG(NEOPIXEL_LED, i(i)) {} - LEDColor(const uint8_t (&rgbw)[4]) : r(rgbw[0]), g(rgbw[1]), b(rgbw[2]) - OPTARG(HAS_WHITE_LED, w(rgbw[3])) - OPTARG(NEOPIXEL_LED, i(NEOPIXEL_BRIGHTNESS)) - {} + // Constructor from array + LED1Color_t(const uint8_t (&rgbw)[4]) : r(rgbw[0]), g(rgbw[1]), b(rgbw[2]) + OPTARG(HAS_WHITE_LED, w(rgbw[3])) OPTARG(NEOPIXEL_LED, i(NEOPIXEL_BRIGHTNESS)){} - LEDColor& operator=(const uint8_t (&rgbw)[4]) { + // Array assignment operator + LED1Color_t& operator=(const uint8_t (&rgbw)[4]) { r = rgbw[0]; g = rgbw[1]; b = rgbw[2]; TERN_(HAS_WHITE_LED, w = rgbw[3]); return *this; } - bool operator==(const LEDColor &right) { - if (this == &right) return true; - return 0 == memcmp(this, &right, sizeof(LEDColor)); + // Comparison operators + bool operator==(const LED1Color_t &right) { + return (this == &right) || (0 == memcmp(this, &right, sizeof(LED1Color_t))); } - bool operator!=(const LEDColor &right) { return !operator==(right); } + bool operator!=(const LED1Color_t &right) { + return !operator==(right); + } + // Check if LED is effectively off bool is_off() const { return 3 > r + g + b + TERN0(HAS_WHITE_LED, w); } -} LEDColor; +}; + + +struct LED2Color_t { + // Basic RGB color components + uint8_t r, g, b OPTARG(HAS_WHITE_LED2, w) OPTARG(NEOPIXEL_LED, i); + // Default constructor - white color + LED2Color_t() : r(255), g(255), b(255) OPTARG(HAS_WHITE_LED2, w(255)) OPTARG(NEOPIXEL_LED, i(NEOPIXEL_BRIGHTNESS)){} + + // Copy constructor + LED2Color_t(const LED2Color_t&) = default; + + // Constructor with individual components + LED2Color_t(uint8_t r, uint8_t g, uint8_t b OPTARG(HAS_WHITE_LED2, uint8_t w=0) OPTARG(NEOPIXEL_LED, uint8_t i=NEOPIXEL_BRIGHTNESS)) + : r(r), g(g), b(b) OPTARG(HAS_WHITE_LED2, w(w)) OPTARG(NEOPIXEL_LED, i(i)) {} + + // Constructor from array + LED2Color_t(const uint8_t (&rgbw)[4]) : r(rgbw[0]), g(rgbw[1]), b(rgbw[2]) + OPTARG(HAS_WHITE_LED2, w(rgbw[3])) OPTARG(NEOPIXEL_LED, i(NEOPIXEL_BRIGHTNESS)){} + + // Array assignment operator + LED2Color_t& operator=(const uint8_t (&rgbw)[4]) { + r = rgbw[0]; g = rgbw[1]; b = rgbw[2]; + TERN_(HAS_WHITE_LED2, w = rgbw[3]); + return *this; + } + + // Comparison operators + bool operator==(const LED2Color_t &right) { + return (this == &right) || (0 == memcmp(this, &right, sizeof(LED1Color_t))); + } + + bool operator!=(const LED2Color_t &right) { + return !operator==(right); + } + + // Check if LED is effectively off + bool is_off() const { + return 3 > r + g + b + TERN0(HAS_WHITE_LED2, w); + } +}; /** * Color presets */ -#define LEDColorOff() LEDColor( 0, 0, 0) -#define LEDColorRed() LEDColor(255, 0, 0) +#define LEDColorOff() LED1Color_t( 0, 0, 0) +#define LEDColorRed() LED1Color_t(255, 0, 0) #if ENABLED(LED_COLORS_REDUCE_GREEN) - #define LEDColorOrange() LEDColor(255, 25, 0) - #define LEDColorYellow() LEDColor(255, 75, 0) + #define LEDColorOrange() LED1Color_t(255, 25, 0) + #define LEDColorYellow() LED1Color_t(255, 75, 0) #else - #define LEDColorOrange() LEDColor(255, 80, 0) - #define LEDColorYellow() LEDColor(255, 255, 0) + #define LEDColorOrange() LED1Color_t(255, 80, 0) + #define LEDColorYellow() LED1Color_t(255, 255, 0) #endif -#define LEDColorGreen() LEDColor( 0, 255, 0) -#define LEDColorBlue() LEDColor( 0, 0, 255) -#define LEDColorIndigo() LEDColor( 0, 255, 255) -#define LEDColorViolet() LEDColor(255, 0, 255) +#define LEDColorGreen() LED1Color_t( 0, 255, 0) +#define LEDColorBlue() LED1Color_t( 0, 0, 255) +#define LEDColorIndigo() LED1Color_t( 0, 255, 255) +#define LEDColorViolet() LED1Color_t(255, 0, 255) #if HAS_WHITE_LED && DISABLED(RGB_LED) - #define LEDColorWhite() LEDColor( 0, 0, 0, 255) + #define LEDColorWhite() LED1Color_t( 0, 0, 0, 255) #else - #define LEDColorWhite() LEDColor(255, 255, 255) + #define LEDColorWhite() LED1Color_t(255, 255, 255) #endif +#define LEDColorOff2() LED2Color_t( 0, 0, 0) +#define LEDColorRed2() LED2Color_t(255, 0, 0) +#if ENABLED(LED_COLORS_REDUCE_GREEN) + #define LEDColorOrange2() LED2Color_t(255, 25, 0) + #define LEDColorYellow2() LED2Color_t(255, 75, 0) +#else + #define LEDColorOrange2() LED2Color_t(255, 80, 0) + #define LEDColorYellow2() LED2Color_t(255, 255, 0) +#endif +#define LEDColorGreen2() LED2Color_t( 0, 255, 0) +#define LEDColorBlue2() LED2Color_t( 0, 0, 255) +#define LEDColorIndigo2() LED2Color_t( 0, 255, 255) +#define LEDColorViolet2() LED2Color_t(255, 0, 255) +#if HAS_WHITE_LED2 && DISABLED(RGB_LED) + #define LEDColorWhite2() LED2Color_t( 0, 0, 0, 255) +#else + #define LEDColorWhite2() LED2Color_t(255, 255, 255) +#endif + + class LEDLights { public: #if ANY(LED_CONTROL_MENU, PRINTER_EVENT_LEDS, CASE_LIGHT_IS_COLOR_LED) - static LEDColor color; // last non-off color + static LED1Color_t color; // last non-off color static bool lights_on; // the last set color was "on" #else static constexpr bool lights_on = true; @@ -130,7 +192,7 @@ public: static void setup(); // init() - static void set_color(const LEDColor &color + static void set_color(const LED1Color_t &color OPTARG(NEOPIXEL_IS_SEQUENTIAL, bool isSequence=false) ); @@ -139,7 +201,7 @@ public: OPTARG(NEOPIXEL_LED, uint8_t i=NEOPIXEL_BRIGHTNESS) OPTARG(NEOPIXEL_IS_SEQUENTIAL, bool isSequence=false) ) { - set_color(LEDColor(r, g, b OPTARG(HAS_WHITE_LED, w) OPTARG(NEOPIXEL_LED, i)) OPTARG(NEOPIXEL_IS_SEQUENTIAL, isSequence)); + set_color(LED1Color_t(r, g, b OPTARG(HAS_WHITE_LED, w) OPTARG(NEOPIXEL_LED, i)) OPTARG(NEOPIXEL_IS_SEQUENTIAL, isSequence)); } static void set_off() { set_color(LEDColorOff()); } @@ -147,7 +209,7 @@ public: static void set_white() { set_color(LEDColorWhite()); } #if ENABLED(LED_COLOR_PRESETS) - static const LEDColor defaultLEDColor; + static const LED1Color_t defaultLEDColor; static void set_default() { set_color(defaultLEDColor); } static void set_red() { set_color(LEDColorRed()); } static void set_orange() { set_color(LEDColorOrange()); } @@ -158,7 +220,7 @@ public: #endif #if ENABLED(PRINTER_EVENT_LEDS) - static LEDColor get_color() { return lights_on ? color : LEDColorOff(); } + static LED1Color_t get_color() { return lights_on ? color : LEDColorOff(); } #endif #if ENABLED(LED_CONTROL_MENU) @@ -190,35 +252,35 @@ extern LEDLights leds; static void setup(); // init() - static void set_color(const LEDColor &color); + static void set_color(const LED2Color_t &color); static void set_color(uint8_t r, uint8_t g, uint8_t b - OPTARG(HAS_WHITE_LED, uint8_t w=0) + OPTARG(HAS_WHITE_LED2, uint8_t w=0) OPTARG(NEOPIXEL_LED, uint8_t i=NEOPIXEL_BRIGHTNESS) ) { - set_color(LEDColor(r, g, b - OPTARG(HAS_WHITE_LED, w) + set_color(LED2Color_t(r, g, b + OPTARG(HAS_WHITE_LED2, w) OPTARG(NEOPIXEL_LED, i) )); } - static void set_off() { set_color(LEDColorOff()); } - static void set_green() { set_color(LEDColorGreen()); } - static void set_white() { set_color(LEDColorWhite()); } + static void set_off() { set_color(LEDColorOff2()); } + static void set_green() { set_color(LEDColorGreen2()); } + static void set_white() { set_color(LEDColorWhite2()); } #if ENABLED(NEO2_COLOR_PRESETS) - static const LEDColor defaultLEDColor; - static void set_default() { set_color(defaultLEDColor); } - static void set_red() { set_color(LEDColorRed()); } - static void set_orange() { set_color(LEDColorOrange()); } - static void set_yellow() { set_color(LEDColorYellow()); } - static void set_blue() { set_color(LEDColorBlue()); } - static void set_indigo() { set_color(LEDColorIndigo()); } - static void set_violet() { set_color(LEDColorViolet()); } + static const LED2Color_t defaultLEDColor2; + static void set_default() { set_color(defaultLEDColor2); } + static void set_red() { set_color(LEDColorRed2()); } + static void set_orange() { set_color(LEDColorOrange2()); } + static void set_yellow() { set_color(LEDColorYellow2()); } + static void set_blue() { set_color(LEDColorBlue2()); } + static void set_indigo() { set_color(LEDColorIndigo2()); } + static void set_violet() { set_color(LEDColorViolet2()); } #endif #if ENABLED(NEOPIXEL2_SEPARATE) - static LEDColor color; // last non-off color + static LED2Color_t color; // last non-off color static bool lights_on; // the last set color was "on" static void toggle(); // swap "off" with color static void update() { set_color(color); } diff --git a/Marlin/src/feature/leds/neopixel.cpp b/Marlin/src/feature/leds/neopixel.cpp index 1b0772c2f9..8165c7715c 100644 --- a/Marlin/src/feature/leds/neopixel.cpp +++ b/Marlin/src/feature/leds/neopixel.cpp @@ -103,7 +103,7 @@ void Marlin_NeoPixel::init() { safe_delay(500); set_color_startup(adaneo1.Color(0, 0, 255, 0)); // blue safe_delay(500); - #if HAS_WHITE_LED + #if HAS_WHITE_NEOPIXEL_1 set_color_startup(adaneo1.Color(0, 0, 0, 255)); // white safe_delay(500); #endif @@ -158,7 +158,7 @@ void Marlin_NeoPixel::init() { safe_delay(500); set_color_startup(adaneo.Color(0, 0, 255, 0)); // blue safe_delay(500); - #if HAS_WHITE_LED2 + #if HAS_WHITE_NEOPIXEL_2 set_color_startup(adaneo.Color(0, 0, 0, 255)); // white safe_delay(500); #endif diff --git a/Marlin/src/feature/leds/neopixel.h b/Marlin/src/feature/leds/neopixel.h index 26f7a07d58..f420a25b83 100644 --- a/Marlin/src/feature/leds/neopixel.h +++ b/Marlin/src/feature/leds/neopixel.h @@ -42,19 +42,17 @@ // Defines // ------------------------ -#define _NEO_IS_RGB(N) (N == NEO_RGB || N == NEO_RBG || N == NEO_GRB || N == NEO_GBR || N == NEO_BRG || N == NEO_BGR) +#define _NEO_IS_RGBW(N) ((N) & 0x30) != (((N) >> 2) & 0x30) -#if !_NEO_IS_RGB(NEOPIXEL_TYPE) - #define HAS_WHITE_LED 1 +#if _NEO_IS_RGBW(NEOPIXEL_TYPE) + #define HAS_WHITE_NEOPIXEL_1 1 #endif -#if HAS_WHITE_LED - #define NEO_WHITE 0, 0, 0, 255 -#else - #define NEO_WHITE 255, 255, 255 -#endif - -#if defined(NEOPIXEL2_TYPE) && NEOPIXEL2_TYPE != NEOPIXEL_TYPE && DISABLED(NEOPIXEL2_SEPARATE) +#if ENABLED(NEOPIXEL2_SEPARATE) + #if _NEO_IS_RGBW(NEOPIXEL2_TYPE) + #define HAS_WHITE_NEOPIXEL_2 1 + #endif +#elif defined(NEOPIXEL2_TYPE) && NEOPIXEL2_TYPE != NEOPIXEL_TYPE #define MULTIPLE_NEOPIXEL_TYPES 1 #endif @@ -62,6 +60,8 @@ #define CONJOINED_NEOPIXEL 1 #endif +#undef _NEO_IS_RGBW + // ------------------------ // Types // ------------------------ @@ -141,8 +141,17 @@ public: static uint8_t brightness() { return adaneo1.getBrightness(); } - static uint32_t Color(uint8_t r, uint8_t g, uint8_t b OPTARG(HAS_WHITE_LED, uint8_t w)) { - return adaneo1.Color(r, g, b OPTARG(HAS_WHITE_LED, w)); + static uint32_t Color(uint8_t r, uint8_t g, uint8_t b OPTARG(HAS_WHITE_NEOPIXEL_1, uint8_t w=0)) { + return adaneo1.Color(r, g, b OPTARG(HAS_WHITE_NEOPIXEL_1, w)); + } + static uint32_t White() { + return Color( + #if HAS_WHITE_NEOPIXEL_1 + 0, 0, 0, 255 + #else + 255, 255, 255 + #endif + ); } }; @@ -151,15 +160,6 @@ extern Marlin_NeoPixel neo; // Neo pixel channel 2 #if ENABLED(NEOPIXEL2_SEPARATE) - #if _NEO_IS_RGB(NEOPIXEL2_TYPE) - #define NEOPIXEL2_IS_RGB 1 - #define NEO2_WHITE 255, 255, 255 - #else - #define NEOPIXEL2_IS_RGBW 1 - #define HAS_WHITE_LED2 1 // A white component can be passed for NEOPIXEL2 - #define NEO2_WHITE 0, 0, 0, 255 - #endif - class Marlin_NeoPixel2 { private: static Adafruit_NeoPixel adaneo; @@ -184,13 +184,20 @@ extern Marlin_NeoPixel neo; static uint16_t pixels() { return adaneo.numPixels();} static uint32_t pixel_color(const uint16_t n) { return adaneo.getPixelColor(n); } static uint8_t brightness() { return adaneo.getBrightness(); } - static uint32_t Color(uint8_t r, uint8_t g, uint8_t b OPTARG(HAS_WHITE_LED2, uint8_t w)) { - return adaneo.Color(r, g, b OPTARG(HAS_WHITE_LED2, w)); + static uint32_t Color(uint8_t r, uint8_t g, uint8_t b OPTARG(HAS_WHITE_NEOPIXEL_2, uint8_t w=0)) { + return adaneo.Color(r, g, b OPTARG(HAS_WHITE_NEOPIXEL_2, w)); + } + static uint32_t White() { + return Color( + #if HAS_WHITE_NEOPIXEL_2 + 0, 0, 0, 255 + #else + 255, 255, 255 + #endif + ); } }; extern Marlin_NeoPixel2 neo2; #endif // NEOPIXEL2_SEPARATE - -#undef _NEO_IS_RGB diff --git a/Marlin/src/feature/leds/pca9632.cpp b/Marlin/src/feature/leds/pca9632.cpp index 40c16a9276..d8fba380a4 100644 --- a/Marlin/src/feature/leds/pca9632.cpp +++ b/Marlin/src/feature/leds/pca9632.cpp @@ -68,7 +68,7 @@ #ifndef PCA9632_BLU #define PCA9632_BLU 0x04 #endif -#if HAS_WHITE_LED && !defined(PCA9632_WHT) +#if ENABLED(PCA9632_RGBW) && !defined(PCA9632_WHT) #define PCA9632_WHT 0x06 #endif @@ -124,7 +124,7 @@ static void PCA9632_WriteAllRegisters(const byte addr, const byte regadd, const } #endif -void PCA9632_set_led_color(const LEDColor &color) { +void PCA9632_set_led_color(const LED1Color_t &color) { Wire.begin(); if (!PCA_init) { PCA_init = 1; @@ -135,10 +135,7 @@ void PCA9632_set_led_color(const LEDColor &color) { const byte LEDOUT = (color.r ? LED_PWM << PCA9632_RED : 0) | (color.g ? LED_PWM << PCA9632_GRN : 0) | (color.b ? LED_PWM << PCA9632_BLU : 0) - #if ENABLED(PCA9632_RGBW) - | (color.w ? LED_PWM << PCA9632_WHT : 0) - #endif - ; + | (TERN0(PCA9632_RGBW, color.w ? LED_PWM << PCA9632_WHT : 0)); PCA9632_WriteAllRegisters(PCA9632_ADDRESS,PCA9632_PWM0, color.r, color.g, color.b OPTARG(PCA9632_RGBW, color.w) diff --git a/Marlin/src/feature/leds/pca9632.h b/Marlin/src/feature/leds/pca9632.h index adef0200af..442166c245 100644 --- a/Marlin/src/feature/leds/pca9632.h +++ b/Marlin/src/feature/leds/pca9632.h @@ -26,10 +26,9 @@ * Written by Robert Mendon Feb 2017. */ -struct LEDColor; -typedef LEDColor LEDColor; +struct LED1Color_t; -void PCA9632_set_led_color(const LEDColor &color); +void PCA9632_set_led_color(const LED1Color_t &color); #if ENABLED(PCA9632_BUZZER) #include diff --git a/Marlin/src/feature/leds/printer_event_leds.cpp b/Marlin/src/feature/leds/printer_event_leds.cpp index e6407a6320..3cbce3da8c 100644 --- a/Marlin/src/feature/leds/printer_event_leds.cpp +++ b/Marlin/src/feature/leds/printer_event_leds.cpp @@ -47,7 +47,7 @@ PrinterEventLEDs printerEventLEDs; inline void pel_set_rgb(const uint8_t r, const uint8_t g, const uint8_t b OPTARG(HAS_WHITE_LED, const uint8_t w=0)) { leds.set_color( - LEDColor(r, g, b OPTARG(HAS_WHITE_LED, w) OPTARG(NEOPIXEL_LED, neo.brightness())) + LED1Color_t(r, g, b OPTARG(HAS_WHITE_LED, w) OPTARG(NEOPIXEL_LED, neo.brightness())) OPTARG(NEOPIXEL_IS_SEQUENTIAL, true) ); } diff --git a/Marlin/src/feature/leds/printer_event_leds.h b/Marlin/src/feature/leds/printer_event_leds.h index 856826b969..5fb08a547e 100644 --- a/Marlin/src/feature/leds/printer_event_leds.h +++ b/Marlin/src/feature/leds/printer_event_leds.h @@ -40,23 +40,23 @@ private: public: #if HAS_TEMP_HOTEND - static LEDColor onHotendHeatingStart() { old_intensity = 0; return leds.get_color(); } + static LED1Color_t onHotendHeatingStart() { old_intensity = 0; return leds.get_color(); } static void onHotendHeating(const celsius_t start, const celsius_t current, const celsius_t target); #endif #if HAS_HEATED_BED - static LEDColor onBedHeatingStart() { old_intensity = 127; return leds.get_color(); } + static LED1Color_t onBedHeatingStart() { old_intensity = 127; return leds.get_color(); } static void onBedHeating(const celsius_t start, const celsius_t current, const celsius_t target); #endif #if HAS_HEATED_CHAMBER - static LEDColor onChamberHeatingStart() { old_intensity = 127; return leds.get_color(); } + static LED1Color_t onChamberHeatingStart() { old_intensity = 127; return leds.get_color(); } static void onChamberHeating(const celsius_t start, const celsius_t current, const celsius_t target); #endif #if HAS_TEMP_HOTEND || HAS_HEATED_BED || HAS_HEATED_CHAMBER static void onHeatingDone() { leds.set_white(); } - static void onPIDTuningDone(LEDColor c) { leds.set_color(c); } + static void onPIDTuningDone(LED1Color_t c) { leds.set_color(c); } #endif #if HAS_MEDIA diff --git a/Marlin/src/feature/max7219.cpp b/Marlin/src/feature/max7219.cpp index a98248c53b..81f588008d 100644 --- a/Marlin/src/feature/max7219.cpp +++ b/Marlin/src/feature/max7219.cpp @@ -283,7 +283,7 @@ void Max7219::set(const uint8_t line, const uint8_t bits) { } // Draw a float with a decimal point and optional digits - void Max7219::print(const uint8_t start, const_float_t value, const uint8_t pre_size, const uint8_t post_size, const bool leadzero=false) { + void Max7219::print(const uint8_t start, const float value, const uint8_t pre_size, const uint8_t post_size, const bool leadzero=false) { if (pre_size) print(start, value, pre_size, leadzero, !!post_size); if (post_size) { const int16_t after = ABS(value) * (10 ^ post_size); @@ -480,32 +480,30 @@ void Max7219::register_setup() { #if MAX7219_INIT_TEST uint8_t test_mode = 0; - millis_t next_patt_ms; bool patt_on; #if MAX7219_INIT_TEST == 2 #define MAX7219_LEDS (MAX7219_X_LEDS * MAX7219_Y_LEDS) - constexpr millis_t pattern_delay = 4; - - int8_t spiralx, spiraly, spiral_dir; + xy_int8_t spiral; + int8_t spiral_dir; uvalue_t(MAX7219_LEDS) spiral_count; - void Max7219::test_pattern() { - constexpr int8_t way[][2] = { { 1, 0 }, { 0, 1 }, { -1, 0 }, { 0, -1 } }; - led_set(spiralx, spiraly, patt_on); - const int8_t x = spiralx + way[spiral_dir][0], y = spiraly + way[spiral_dir][1]; - if (!WITHIN(x, 0, MAX7219_X_LEDS - 1) || !WITHIN(y, 0, MAX7219_Y_LEDS - 1) || BIT_7219(x, y) == patt_on) + void Max7219::run_test_pattern() { + constexpr xy_int8_t way[] = { { 1, 0 }, { 0, 1 }, { -1, 0 }, { 0, -1 } }; + led_set(spiral.x, spiral.y, patt_on); + const xy_int8_t xy = spiral + way[spiral_dir]; + if (!WITHIN(xy.x, 0, MAX7219_X_LEDS - 1) || !WITHIN(xy.y, 0, MAX7219_Y_LEDS - 1) || BIT_7219(xy.x, xy.y) == patt_on) spiral_dir = (spiral_dir + 1) & 0x3; - spiralx += way[spiral_dir][0]; - spiraly += way[spiral_dir][1]; + spiral += way[spiral_dir]; if (!spiral_count--) { if (!patt_on) test_mode = 0; else { spiral_count = MAX7219_LEDS; - spiralx = spiraly = spiral_dir = 0; + spiral.reset(); + spiral_dir = 0; patt_on = false; } } @@ -516,7 +514,11 @@ void Max7219::register_setup() { constexpr millis_t pattern_delay = 20; int8_t sweep_count, sweepx, sweep_dir; - void Max7219::test_pattern() { + void Max7219::run_test_pattern() { + static millis_t next_pattern_ms = 0; + const millis_t ms = millis(); + if (PENDING(ms, next_pattern_ms)) return; + next_pattern_ms = ms + pattern_delay; set_column(sweepx, patt_on ? 0xFFFFFFFF : 0x00000000); sweepx += sweep_dir; if (!WITHIN(sweepx, 0, MAX7219_X_LEDS - 1)) { @@ -526,27 +528,21 @@ void Max7219::register_setup() { } else sweepx -= MAX7219_X_LEDS * sweep_dir; - patt_on ^= true; - next_patt_ms += 100; + FLIP(patt_on); + next_pattern_ms += 100; if (++test_mode > 4) test_mode = 0; } } #endif - void Max7219::run_test_pattern() { - const millis_t ms = millis(); - if (PENDING(ms, next_patt_ms)) return; - next_patt_ms = ms + pattern_delay; - test_pattern(); - } - void Max7219::start_test_pattern() { clear(); test_mode = 1; patt_on = true; #if MAX7219_INIT_TEST == 2 - spiralx = spiraly = spiral_dir = 0; + spiral.reset(); + spiral_dir = 0; spiral_count = MAX7219_LEDS; #else sweep_dir = 1; @@ -761,7 +757,7 @@ void Max7219::idle_tasks() { #ifdef MAX7219_DEBUG_MULTISTEPPING static uint8_t last_multistepping = 0; - const uint8_t multistepping = Stepper::steps_per_isr; + const uint8_t multistepping = stepper.steps_per_isr; if (multistepping != last_multistepping) { static uint8_t log2_old = 0; uint8_t log2_new = 0; @@ -774,7 +770,7 @@ void Max7219::idle_tasks() { #ifdef MAX7219_DEBUG_SLOWDOWN static uint8_t last_slowdown_count = 0; - const uint8_t slowdown_count = Planner::slowdown_count; + const uint8_t slowdown_count = planner.slowdown_count; if (slowdown_count != last_slowdown_count) { mark16(MAX7219_DEBUG_SLOWDOWN, last_slowdown_count, slowdown_count, &row_change_mask); last_slowdown_count = slowdown_count; diff --git a/Marlin/src/feature/max7219.h b/Marlin/src/feature/max7219.h index a6b110fdf4..9c39541a7c 100644 --- a/Marlin/src/feature/max7219.h +++ b/Marlin/src/feature/max7219.h @@ -74,14 +74,13 @@ #ifdef MAX7219_DEBUG_PROFILE // This class sums up the amount of time for which its instances exist. - // By default there is one instantiated for the duration of the idle() - // function. But an instance can be created in any code block to measure - // the time spent from the point of instantiation until the CPU leaves - // block. Be careful about having multiple instances of CodeProfiler as - // it does not guard against double counting. In general mixing ISR and - // non-ISR use will require critical sections but note that mode setting - // is atomic so the total or average times can safely be read if you set - // mode to FREEZE first. + // By default there is one instantiated for the duration of marlin.idle() + // but an instance can be created in any code block to measure time spent + // from instantiation until the CPU leaves the block. + // Be careful about having multiple instances of CodeProfiler as it does + // not guard against double counting. In general mixing ISR and non-ISR + // use will require critical sections but note that mode setting is atomic + // so the total or average times can safely be read if you set mode to FREEZE first. class CodeProfiler { public: enum Mode : uint8_t { ACCUMULATE_AVERAGE, ACCUMULATE_TOTAL, FREEZE }; @@ -110,7 +109,7 @@ if (mode == ACCUMULATE_TOTAL) return; // update time_fraction every hundred milliseconds - if (instance_count == 0 && ELAPSED(now, last_calc_time + 100000)) { + if (instance_count == 0 && now - last_calc_time > 100000) { time_fraction = total_time * 128 / (now - last_calc_time); last_calc_time = now; total_time = 0; @@ -166,7 +165,7 @@ public: // Draw an integer with optional leading zeros and optional decimal point void print(const uint8_t start, int16_t value, uint8_t size, const bool leadzero=false, bool dec=false); // Draw a float with a decimal point and optional digits - void print(const uint8_t start, const_float_t value, const uint8_t pre_size, const uint8_t post_size, const bool leadzero=false); + void print(const uint8_t start, const float value, const uint8_t pre_size, const uint8_t post_size, const bool leadzero=false); #endif // Set a single LED by XY coordinate diff --git a/Marlin/src/feature/meatpack.cpp b/Marlin/src/feature/meatpack.cpp index fe3dabe8da..3b762d4ded 100644 --- a/Marlin/src/feature/meatpack.cpp +++ b/Marlin/src/feature/meatpack.cpp @@ -169,9 +169,11 @@ void MeatPack::handle_command(const MeatPack_Command c) { void MeatPack::report_state() { // NOTE: if any configuration vars are added below, the outgoing sync text for host plugin // should not contain the "PV' substring, as this is used to indicate protocol version - SERIAL_ECHOPGM("[MP] " MeatPack_ProtocolVersion " "); - serialprint_onoff(TEST(state, MPConfig_Bit_Active)); - SERIAL_ECHO(TEST(state, MPConfig_Bit_NoSpaces) ? F(" NSP\n") : F(" ESP\n")); + SERIAL_ECHO( + F("[MP] " MeatPack_ProtocolVersion " "), + ON_OFF(TEST(state, MPConfig_Bit_Active)), + TEST(state, MPConfig_Bit_NoSpaces) ? F(" NSP\n") : F(" ESP\n") + ); } /** diff --git a/Marlin/src/feature/mixing.cpp b/Marlin/src/feature/mixing.cpp index f3fb2d07a3..bc98bf3b26 100644 --- a/Marlin/src/feature/mixing.cpp +++ b/Marlin/src/feature/mixing.cpp @@ -166,7 +166,7 @@ void Mixer::refresh_collector(const float proportion/*=1.0*/, const uint8_t t/*= float Mixer::prev_z; // = 0 - void Mixer::update_gradient_for_z(const_float_t z) { + void Mixer::update_gradient_for_z(const float z) { if (z == prev_z) return; prev_z = z; diff --git a/Marlin/src/feature/mixing.h b/Marlin/src/feature/mixing.h index c0f45e364a..bd7ffb560e 100644 --- a/Marlin/src/feature/mixing.h +++ b/Marlin/src/feature/mixing.h @@ -174,9 +174,9 @@ class Mixer { static float prev_z; // Update the current mix from the gradient for a given Z - static void update_gradient_for_z(const_float_t z); + static void update_gradient_for_z(const float z); static void update_gradient_for_planner_z(); - static void gradient_control(const_float_t z) { + static void gradient_control(const float z) { if (gradient.enabled) { if (z >= gradient.end_z) T(gradient.end_vtool); diff --git a/Marlin/src/feature/mmu/mmu.cpp b/Marlin/src/feature/mmu/mmu.cpp index 58c49ed224..b1e66cc425 100644 --- a/Marlin/src/feature/mmu/mmu.cpp +++ b/Marlin/src/feature/mmu/mmu.cpp @@ -24,7 +24,6 @@ #if HAS_PRUSA_MMU1 -#include "../../MarlinCore.h" #include "../../module/planner.h" #include "../../module/stepper.h" diff --git a/Marlin/src/feature/mmu/mmu2-serial-protocol.md b/Marlin/src/feature/mmu/mmu2-serial-protocol.md index 088d41b446..474fcd488b 100644 --- a/Marlin/src/feature/mmu/mmu2-serial-protocol.md +++ b/Marlin/src/feature/mmu/mmu2-serial-protocol.md @@ -1,5 +1,4 @@ -Startup sequence -================ +# Startup sequence When initialized, MMU sends @@ -8,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) @@ -20,26 +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 -========== +# 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' @@ -51,34 +49,30 @@ When done, the MMU sends We don't wait for a response here but immediately continue with the next G-code which should be one or more extruder moves to feed the filament into the hotend. -FINDA status -============ +# 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. +_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 -============= +# 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' -Unload filament -============= +# Unload filament - 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 -============== +# Eject filament -- MMU <= 'E*Filament index*\n' +- MMU <= 'E<_Filament index_>\n' - MMU => 'ok\n' diff --git a/Marlin/src/feature/mmu/mmu2.cpp b/Marlin/src/feature/mmu/mmu2.cpp index d5f115e74c..76e2b8505f 100644 --- a/Marlin/src/feature/mmu/mmu2.cpp +++ b/Marlin/src/feature/mmu/mmu2.cpp @@ -40,7 +40,6 @@ MMU2 mmu2; #include "../../module/temperature.h" #include "../../module/planner.h" #include "../../module/stepper.h" -#include "../../MarlinCore.h" #if ENABLED(HOST_PROMPT_SUPPORT) #include "../host_actions.h" @@ -96,7 +95,7 @@ struct E_Step { feedRate_t feedRate; //!< feed rate in mm/s }; -inline void unscaled_mmu2_e_move(const float &dist, const feedRate_t fr_mm_s, const bool sync=true) { +inline void unscaled_mmu2_e_move(const float dist, const feedRate_t fr_mm_s, const bool sync=true) { current_position.e += dist / planner.e_factor[active_extruder]; line_to_current_position(fr_mm_s); if (sync) planner.synchronize(); @@ -164,7 +163,7 @@ void MMU2::mmu_loop() { MMU2_SEND("S1"); // Read Version state = -2; } - else if (ELAPSED(millis(), prev_request + 30000)) { // 30sec after reset disable MMU + else if (ELAPSED(millis(), prev_request, 30000)) { // 30sec after reset disable MMU SERIAL_ECHOLNPGM("MMU not responding - DISABLED"); state = 0; } @@ -276,7 +275,7 @@ void MMU2::mmu_loop() { last_cmd = cmd; cmd = MMU_CMD_NONE; } - else if (ELAPSED(millis(), prev_P0_request + 300)) { + else if (ELAPSED(millis(), prev_P0_request, 300)) { MMU2_SEND("P0"); // Read FINDA state = 2; // wait for response } @@ -296,7 +295,7 @@ void MMU2::mmu_loop() { if (cmd == MMU_CMD_NONE) ready = true; state = 1; } - else if (ELAPSED(millis(), prev_request + MMU_P0_TIMEOUT)) // Resend request after timeout (3s) + else if (ELAPSED(millis(), prev_request, MMU_P0_TIMEOUT)) // Resend request after timeout (3s) state = 1; TERN_(HAS_PRUSA_MMU2S, check_filament()); @@ -335,7 +334,7 @@ void MMU2::mmu_loop() { last_cmd = MMU_CMD_NONE; } } - else if (ELAPSED(millis(), prev_request + MMU_CMD_TIMEOUT)) { + else if (ELAPSED(millis(), prev_request, MMU_CMD_TIMEOUT)) { // resend request after timeout if (last_cmd) { DEBUG_ECHOLNPGM("MMU retry"); @@ -446,7 +445,7 @@ bool MMU2::rx_ok() { void MMU2::check_version(const uint16_t buildnr) { if (buildnr < MMU_REQUIRED_FW_BUILDNR) { SERIAL_ERROR_MSG("Invalid MMU2 firmware. Version >= " STRINGIFY(MMU_REQUIRED_FW_BUILDNR) " required."); - kill(GET_TEXT_F(MSG_KILL_MMU2_FIRMWARE)); + marlin.kill(GET_TEXT_F(MSG_KILL_MMU2_FIRMWARE)); } } @@ -786,10 +785,10 @@ void MMU2::command(const uint8_t mmu_cmd) { * Wait for response from MMU */ bool MMU2::get_response() { - while (cmd != MMU_CMD_NONE) idle(); + while (cmd != MMU_CMD_NONE) marlin.idle(); while (!ready) { - idle(); + marlin.idle(); if (state != 3) break; } @@ -985,7 +984,7 @@ bool MMU2::eject_filament(const uint8_t index, const bool recover) { mmu2_attn_buzz(); TERN_(HOST_PROMPT_SUPPORT, hostui.continue_prompt(GET_TEXT_F(MSG_MMU2_EJECT_RECOVER))); TERN_(EXTENSIBLE_UI, ExtUI::onUserConfirmRequired(GET_TEXT_F(MSG_MMU2_EJECT_RECOVER))); - TERN_(HAS_RESUME_CONTINUE, wait_for_user_response()); + TERN_(HAS_RESUME_CONTINUE, marlin.wait_for_user_response()); mmu2_attn_buzz(); command(MMU_CMD_R0); diff --git a/Marlin/src/feature/mmu3/SpoolJoin.cpp b/Marlin/src/feature/mmu3/SpoolJoin.cpp index 48495a225c..f27d2bc7e9 100644 --- a/Marlin/src/feature/mmu3/SpoolJoin.cpp +++ b/Marlin/src/feature/mmu3/SpoolJoin.cpp @@ -47,7 +47,7 @@ void SpoolJoin::initStatus() { void SpoolJoin::toggle() { // Toggle enabled value. - enabled = !enabled; + FLIP(enabled); // Following Prusa's implementation let's save the value to the EEPROM // TODO: Move to settings.cpp diff --git a/Marlin/src/feature/mmu3/mmu3-serial-protocol.md b/Marlin/src/feature/mmu3/mmu3-serial-protocol.md index fd0f1fbcba..0d0f7ac6e0 100644 --- a/Marlin/src/feature/mmu3/mmu3-serial-protocol.md +++ b/Marlin/src/feature/mmu3/mmu3-serial-protocol.md @@ -28,6 +28,7 @@ This set of responses combines to indicate firmware version 3.0.2. ## Startup sequence When initialized the MMU waits for requests. Marlin repeatedly sends `S0` commands until it gets an answer: + ``` MMU3:>S0*c6\n MMU3:>S0*c6\n @@ -36,11 +37,13 @@ MMU3:>S0*c6\n ``` Once communication is established the MMU responds with: + ``` MMU3:S1*ad\n MMU3:M1*{CRC8}; MMU3:<---nothing--- @@ -61,10 +65,10 @@ MMU3:T0*{CRC8}\n @@ -96,6 +102,7 @@ MMU3:>C0*{CRC8}\n ``` The MMU will feed a few more millimeters of filament for the extruder gears to grab. When done, the MMU sends: + ``` MMU3:>Q0*{CRC8}\n MMU3: FinishingMoves @@ -103,18 +110,20 @@ MMU3: FinishingMoves After the `T0*P9` response we immediately continue with the next G-code which should be one or more extruder moves to feed the filament into the hotend. - ## FINDA status + ``` MMU3:>P0*{CRC8}\n ``` If the filament is loaded to the extruder, FINDA status is 1 and the MMU responds with: + ``` MMU3:L{Filament index}*{CRC8}\n MMU3:Q0*{CRC8}\n ``` The MMU will respond with status messages: + ``` MMU3:Q0*{CRC8}\n MMU3:steps[E_AXIS] != 0) e_active++; + if (block->steps.e != 0) e_active++; block_index = (block_index + 1) & (BLOCK_BUFFER_SIZE - 1); } } @@ -274,7 +273,7 @@ namespace MMU3 { */ void MMU3::checkFINDARunout() { if (!findaDetectsFilament() - //&& printJobOngoing() + //&& marlin.printJobOngoing() && parser.codenum != 600 && TERN1(HAS_LEVELING, planner.leveling_active) && xy_are_trusted() @@ -456,7 +455,7 @@ namespace MMU3 { if (slot != extruder) { if ( //findaDetectsFilament() - //!IS_SD_PRINTING() && !usb_timer.running() + //!card.isStillPrinting() && !usb_timer.running() !marlin_printingIsActive() ) { // If Tcodes are used manually through the serial @@ -760,10 +759,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 @@ -857,7 +856,7 @@ namespace MMU3 { for (;;) { // in our new implementation, we know the exact state of the MMU at any moment, we do not have to wait for a timeout // So in this case we should decide if the operation is: - // - still running -> wait normally in idle() + // - still running -> wait normally in marlin.idle() // - failed -> then do the safety moves on the printer like before // - finished ok -> proceed with reading other commands safe_delay_keep_alive(0); // calls logicStep() and remembers its return status @@ -867,7 +866,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); @@ -1162,7 +1161,7 @@ namespace MMU3 { // // Instead of doing a very long extrude as in PrusaFirmware, // Marlin's own MMU2s code has a better approach to this by spinning - // the extruder indefinitelly... + // the extruder indefinitely... // // this ensures that while the MMU is pushing the filament, // the extruder will keep rotating, preventing the filament to hit diff --git a/Marlin/src/feature/mmu3/mmu3.h b/Marlin/src/feature/mmu3/mmu3.h index 3c1088f3e5..968f76a912 100644 --- a/Marlin/src/feature/mmu3/mmu3.h +++ b/Marlin/src/feature/mmu3/mmu3.h @@ -115,12 +115,12 @@ void powerOn(); // Read from a MMU register (See gcode M707) - // @param address Address of register in hexidecimal + // @param address Address of register in hexadecimal // @return true upon success bool readRegister(uint8_t address); // Write from a MMU register (See gcode M708) - // @param address Address of register in hexidecimal + // @param address Address of register in hexadecimal // @param data Data to write to register // @return true upon success bool writeRegister(uint8_t address, uint16_t data); @@ -204,7 +204,7 @@ ErrorCode getLastErrorCode() const { return lastErrorCode; } // @return the version of the connected MMU FW. - // In the future we'll return the trully detected FW version + // In the future we'll return the truly detected FW version Version getMMUFWVersion() const { if (state() == xState::Active) { return { logic.mmuFwVersionMajor(), logic.mmuFwVersionMinor(), logic.mmuFwVersionRevision() }; diff --git a/Marlin/src/feature/mmu3/mmu3_error_converter.cpp b/Marlin/src/feature/mmu3/mmu3_error_converter.cpp index d5d124427e..7ed53c0229 100644 --- a/Marlin/src/feature/mmu3/mmu3_error_converter.cpp +++ b/Marlin/src/feature/mmu3/mmu3_error_converter.cpp @@ -60,7 +60,7 @@ namespace MMU3 { return (i != errorCodesEnd) ? (i - errorCodes) : (errorCodesSize - 1); } - // check that the searching algoritm works + // check that the searching algorithm works // static_assert( FindErrorIndex(ERR_MECHANICAL_FINDA_DIDNT_TRIGGER) == 0); // static_assert( FindErrorIndex(ERR_MECHANICAL_FINDA_FILAMENT_STUCK) == 1); // static_assert( FindErrorIndex(ERR_MECHANICAL_FSENSOR_DIDNT_TRIGGER) == 2); @@ -196,16 +196,16 @@ namespace MMU3 { return FindErrorIndex(ERR_OTHER_UNKNOWN_ERROR); } - uint16_t PrusaErrorCode(const uint8_t i) { return (uint16_t)pgm_read_word(&errorCodes[i]); } + uint16_t PrusaErrorCode(const uint8_t i) { return pgm_read_word(errorCodes + i); } - FSTR_P const PrusaErrorTitle(const uint8_t i) { return (FSTR_P const)pgm_read_ptr(&errorTitles[i]); } - FSTR_P const PrusaErrorDesc(const uint8_t i) { return (FSTR_P const)pgm_read_ptr(&errorDescs[i]); } + FSTR_P const PrusaErrorTitle(const uint8_t i) { return (FSTR_P const)pgm_read_ptr(errorTitles + i); } + FSTR_P const PrusaErrorDesc(const uint8_t i) { return (FSTR_P const)pgm_read_ptr(errorDescs + i); } uint8_t PrusaErrorButtons(const uint8_t i) { return pgm_read_byte(errorButtons + i); } FSTR_P const PrusaErrorButtonTitle(const uint8_t bi) { // -1 represents the hidden NoOperation button which is not drawn in any way - return (FSTR_P const)pgm_read_ptr(&btnOperation[bi - 1]); + return (FSTR_P const)pgm_read_ptr(btnOperation + bi - 1); } Buttons ButtonPressed(const ErrorCode ec) { diff --git a/Marlin/src/feature/mmu3/mmu3_fsensor.h b/Marlin/src/feature/mmu3/mmu3_fsensor.h index bda6bf2a70..0ef4864e9f 100644 --- a/Marlin/src/feature/mmu3/mmu3_fsensor.h +++ b/Marlin/src/feature/mmu3/mmu3_fsensor.h @@ -32,7 +32,7 @@ namespace MMU3 { - // Can be used to block printer's filament sensor handling - to avoid errorneous injecting of M600 + // Can be used to block printer's filament sensor handling - to avoid erroneous injecting of M600 // while doing a toolchange with the MMU // In case of "no filament sensor" these methods default to an empty implementation class FSensorBlockRunout { diff --git a/Marlin/src/feature/mmu3/mmu3_marlin.h b/Marlin/src/feature/mmu3/mmu3_marlin.h index 2754a2274b..499af0f285 100644 --- a/Marlin/src/feature/mmu3/mmu3_marlin.h +++ b/Marlin/src/feature/mmu3/mmu3_marlin.h @@ -33,10 +33,10 @@ namespace MMU3 { // - Unify implementation among MK3 and Buddy FW // - Enable unit testing of MMU top layer - void extruder_move(const_float_t distance, const_float_t feedRate_mm_s, const bool sync=true); - void extruder_schedule_turning(const_float_t feedRate_mm_s); + void extruder_move(const float distance, const float feedRate_mm_s, const bool sync=true); + void extruder_schedule_turning(const float feedRate_mm_s); - float move_raise_z(const_float_t delta); + float move_raise_z(const float delta); void planner_abort_queued_moves(); void planner_synchronize(); @@ -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(); diff --git a/Marlin/src/feature/mmu3/mmu3_marlin1.cpp b/Marlin/src/feature/mmu3/mmu3_marlin1.cpp index be54695c74..f12d83772a 100644 --- a/Marlin/src/feature/mmu3/mmu3_marlin1.cpp +++ b/Marlin/src/feature/mmu3/mmu3_marlin1.cpp @@ -49,13 +49,13 @@ namespace MMU3 { planner_synchronize(); } - void extruder_move(const_float_t delta, const_float_t feedRate_mm_s, const bool sync/*=true*/) { + void extruder_move(const float delta, const float feedRate_mm_s, const bool sync/*=true*/) { current_position.e += delta / planner.e_factor[active_extruder]; planner_line_to_current_position(feedRate_mm_s); if (sync) planner.synchronize(); } - float move_raise_z(const_float_t delta) { + float move_raise_z(const float delta) { //return raise_z(delta); xyze_pos_t current_position_before = current_position; do_z_clearance_by(delta); @@ -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); } @@ -123,15 +122,15 @@ namespace MMU3 { #endif } - bool marlin_printingIsActive() { return printingIsActive(); } + bool marlin_printingIsActive() { return marlin.printingIsActive(); } void marlin_manage_heater() { thermalManager.task(); } - void marlin_manage_inactivity(const bool b) { idle(b); } + void marlin_manage_inactivity(const bool b) { marlin.idle(b); } - void marlin_idle(bool b) { + void marlin_idle(const bool b) { thermalManager.task(); - idle(b); + marlin.idle(b); } void marlin_refresh_print_state_in_ram() { @@ -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); + marlin.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); diff --git a/Marlin/src/feature/mmu3/mmu3_power.cpp b/Marlin/src/feature/mmu3/mmu3_power.cpp index da905c6e29..1782cb49fc 100644 --- a/Marlin/src/feature/mmu3/mmu3_power.cpp +++ b/Marlin/src/feature/mmu3/mmu3_power.cpp @@ -39,26 +39,26 @@ namespace MMU3 { -// On MK3 we cannot do actual power cycle on HW. Instead trigger a hardware reset. -void power_on() { - #if PIN_EXISTS(MMU_RST) - OUT_WRITE(MMU_RST_PIN, HIGH); - #endif - power_reset(); -} + // On MK3 we cannot do actual power cycle on HW. Instead trigger a hardware reset. + void power_on() { + #if PIN_EXISTS(MMU_RST) + OUT_WRITE(MMU_RST_PIN, HIGH); + #endif + power_reset(); + } -void power_off() {} + void power_off() {} -void power_reset() { - #if PIN_EXISTS(MMU_RST) // HW - pulse reset pin - WRITE(MMU_RST_PIN, LOW); - safe_delay(100); - WRITE(MMU_RST_PIN, HIGH); - #else - mmu3.reset(MMU3::Software); // TODO: Needs redesign. This power implementation shouldn't know anything about the MMU itself - #endif - // otherwise HW reset is not available -} + void power_reset() { + #if PIN_EXISTS(MMU_RST) // HW - pulse reset pin + WRITE(MMU_RST_PIN, LOW); + safe_delay(100); + WRITE(MMU_RST_PIN, HIGH); + #else + mmu3.reset(MMU3::Software); // TODO: Needs redesign. This power implementation shouldn't know anything about the MMU itself + #endif + // otherwise HW reset is not available + } } // MMU3 diff --git a/Marlin/src/feature/mmu3/mmu3_power.h b/Marlin/src/feature/mmu3/mmu3_power.h index 4f6b94f01e..77259073a1 100644 --- a/Marlin/src/feature/mmu3/mmu3_power.h +++ b/Marlin/src/feature/mmu3/mmu3_power.h @@ -26,11 +26,7 @@ */ namespace MMU3 { - -void power_on(); - -void power_off(); - -void power_reset(); - -} // MMU3 + void power_on(); + void power_off(); + void power_reset(); +} diff --git a/Marlin/src/feature/mmu3/mmu3_protocol.h b/Marlin/src/feature/mmu3/mmu3_protocol.h index 7ec47fd524..f9553b58c8 100644 --- a/Marlin/src/feature/mmu3/mmu3_protocol.h +++ b/Marlin/src/feature/mmu3/mmu3_protocol.h @@ -115,7 +115,7 @@ namespace protocol { // A response message - responses are being sent from the MMU into the printer as a response to a request message. struct ResponseMsg { - RequestMsg request; //!< response is always preceeded by the request message + RequestMsg request; //!< response is always preceded by the request message ResponseMsgParamCodes paramCode; //!< code of the parameter uint16_t paramValue; //!< value of the parameter @@ -157,7 +157,7 @@ namespace protocol { // Protocol class is responsible for creating/decoding messages in Rx/Tx buffer // - // Beware - in the decoding more, it is meant to be a statefull instance which works through public methods + // Beware - in the decoding more, it is meant to be a stateful instance which works through public methods // processing one input byte per call. class Protocol { public: @@ -186,11 +186,11 @@ namespace protocol { static uint8_t EncodeWriteRequest(uint8_t address, uint16_t value, uint8_t *txbuff); // @return the maximum byte length necessary to encode a request message - // Beneficial in case of pre-allocating a buffer for enconding a RequestMsg. + // Beneficial in case of pre-allocating a buffer for encoding a RequestMsg. static constexpr uint8_t MaxRequestSize() { return 13; } // @return the maximum byte length necessary to encode a response message - // Beneficial in case of pre-allocating a buffer for enconding a ResponseMsg. + // Beneficial in case of pre-allocating a buffer for encoding a ResponseMsg. static constexpr uint8_t MaxResponseSize() { return 14; } // Encode generic response Command Accepted or Rejected diff --git a/Marlin/src/feature/mmu3/mmu3_protocol_logic.cpp b/Marlin/src/feature/mmu3/mmu3_protocol_logic.cpp index cf74e669b8..4323925b6b 100644 --- a/Marlin/src/feature/mmu3/mmu3_protocol_logic.cpp +++ b/Marlin/src/feature/mmu3/mmu3_protocol_logic.cpp @@ -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) { diff --git a/Marlin/src/feature/mmu3/mmu3_protocol_logic.h b/Marlin/src/feature/mmu3/mmu3_protocol_logic.h index 2fef77c276..30f9c5d0d5 100644 --- a/Marlin/src/feature/mmu3/mmu3_protocol_logic.h +++ b/Marlin/src/feature/mmu3/mmu3_protocol_logic.h @@ -36,24 +36,8 @@ #include "mmu_hw/buttons.h" #include "mmu_hw/registers.h" #include "mmu3_protocol.h" - - // #include std array is not available on AVR ... we need to "fake" it - namespace std { - template - 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 #include "mmu_hw/error_codes.h" #include "mmu_hw/progress_codes.h" @@ -351,8 +335,7 @@ namespace MMU3 { Protocol protocol; //!< protocol codec - std::array 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 diff --git a/Marlin/src/feature/mmu3/mmu3_reporting.cpp b/Marlin/src/feature/mmu3/mmu3_reporting.cpp index 4bf2088d27..c9b9dbe554 100644 --- a/Marlin/src/feature/mmu3/mmu3_reporting.cpp +++ b/Marlin/src/feature/mmu3/mmu3_reporting.cpp @@ -213,7 +213,7 @@ namespace MMU3 { void EndReport(CommandInProgress /*cip*/, ProgressCode /*ec*/) { // clear the status msg line - let the printed filename get visible again - if (!printJobOngoing()) ui.reset_status(); + if (!marlin.printJobOngoing()) ui.reset_status(); //custom_message_type = CustomMsg::Status; } @@ -353,17 +353,18 @@ namespace MMU3 { // Render the choices //if (two_choices) { // lcd_show_choices_prompt_P( - // LCD_LEFT_BUTTON_CHOICE, - // PrusaErrorButtonTitle(button_op_middle), - // GET_TEXT(MSG_BTN_MORE), - // 18, nullptr + // LCD_LEFT_BUTTON_CHOICE, + // PrusaErrorButtonTitle(button_op_middle), + // GET_TEXT(MSG_BTN_MORE), + // 18, nullptr // ); //} //else { - // lcd_show_choices_prompt_P(LCD_MIDDLE_BUTTON_CHOICE, - // PrusaErrorButtonTitle(button_op_middle), - // PrusaErrorButtonTitle(button_op_right), - // 9, GET_TEXT(MSG_BTN_MORE) + // lcd_show_choices_prompt_P( + // LCD_MIDDLE_BUTTON_CHOICE, + // PrusaErrorButtonTitle(button_op_middle), + // PrusaErrorButtonTitle(button_op_right), + // 9, GET_TEXT(MSG_BTN_MORE) // ); //} @@ -449,7 +450,7 @@ namespace MMU3 { const uint8_t ei = PrusaErrorCodeIndex((ErrorCode)ec); - // This should be the equivelent of the switch..case above... + // This should be the equivalent of the switch..case above... if ((uint8_t)ReportErrorHookState == (uint8_t)ReportErrorHookStates::RENDER_ERROR_SCREEN) { KEEPALIVE_STATE(PAUSED_FOR_USER); #if HAS_WIRED_LCD @@ -526,7 +527,7 @@ namespace MMU3 { #if HAS_WIRED_LCD // Set the cursor position each time in case some other // part of the firmware changes the cursor position - lcd_insert_char_into_status(col, sensorState ? LCD_STR_SOLID_BLOCK[0] : '-'); + lcd_replace_status_char(col, sensorState ? LCD_STR_SOLID_BLOCK[0] : '-'); if (ui.lcdDrawUpdate == LCDViewAction::LCDVIEW_NONE) ui.draw_status_message(false); #endif @@ -535,7 +536,7 @@ namespace MMU3 { void TryLoadUnloadReporter::Progress(bool sensorState) { // Always round up, you can only have 'whole' pixels. (floor is also an option) dpixel1 = ceil((stepper_get_machine_position_E_mm() - planner_get_current_position_E()) * pixel_per_mm); - if (dpixel1 - dpixel0) { + if (dpixel1 != dpixel0) { dpixel0 = dpixel1; if (lcd_cursor_col > (LCD_WIDTH - 1)) lcd_cursor_col = LCD_WIDTH - 1; Render(lcd_cursor_col++, sensorState); diff --git a/Marlin/src/feature/mmu3/mmu_hw/error_codes.h b/Marlin/src/feature/mmu3/mmu_hw/error_codes.h index cc583efbe6..b0bc36e206 100644 --- a/Marlin/src/feature/mmu3/mmu_hw/error_codes.h +++ b/Marlin/src/feature/mmu3/mmu_hw/error_codes.h @@ -33,7 +33,7 @@ * therefore the error codes have been extracted to one place. * * Please note the errors are intentionally coded as "negative" values (highest bit set), - * becase they are a complement to reporting the state of the high-level state machines - + * because they are a complement to reporting the state of the high-level state machines - * positive values are considered as normal progress, negative values are errors. * * Please note, that multiple TMC errors can occur at once, thus they are defined as a bitmask of the higher byte. diff --git a/Marlin/src/feature/mmu3/mmu_hw/errors_list.h b/Marlin/src/feature/mmu3/mmu_hw/errors_list.h index c4965791e6..9cfdba2283 100644 --- a/Marlin/src/feature/mmu3/mmu_hw/errors_list.h +++ b/Marlin/src/feature/mmu3/mmu_hw/errors_list.h @@ -37,7 +37,6 @@ #include #endif #include "buttons.h" -#include "../strlen_cx.h" #include "../ultralcd.h" namespace MMU3 { @@ -114,7 +113,7 @@ typedef enum : uint16_t { } err_num_t; // Avr gcc has serious trouble understanding static data structures in PROGMEM -// and inadvertedly falls back to copying the whole structure into RAM (which is obviously unwanted). +// and inadvertently falls back to copying the whole structure into RAM (which is obviously unwanted). // But since this file ought to be generated in the future from yaml prescription, // it really makes no difference if there are "nice" data structures or plain arrays. static const constexpr err_num_t errorCodes[] PROGMEM = { diff --git a/Marlin/src/feature/mmu3/ultralcd.cpp b/Marlin/src/feature/mmu3/ultralcd.cpp index 96e019740f..d3cd3d371e 100644 --- a/Marlin/src/feature/mmu3/ultralcd.cpp +++ b/Marlin/src/feature/mmu3/ultralcd.cpp @@ -37,181 +37,175 @@ #include "../../gcode/gcode.h" #include "../../lcd/marlinui.h" - //! @brief Show a two-choice prompt on the last line of the LCD - //! @param selected Show first choice as selected if true, the second otherwise - //! @param first_choice text caption of first possible choice - //! @param second_choice text caption of second possible choice - //! @param second_col column on LCD where second choice is rendered. - //! @param third_choice text caption of third, optional, choice. - void lcd_show_choices_prompt_P(uint8_t selected, const char *first_choice, const char *second_choice, uint8_t second_col, const char *third_choice) { - lcd_put_lchar(0, 3, selected == LCD_LEFT_BUTTON_CHOICE ? '>' : ' '); - lcd_put_u8str(first_choice); - lcd_put_lchar(second_col, 3, selected == LCD_MIDDLE_BUTTON_CHOICE ? '>' : ' '); - lcd_put_u8str(second_choice); - if (third_choice) { - lcd_put_lchar(18, 3, selected == LCD_RIGHT_BUTTON_CHOICE ? '>' : ' '); - lcd_put_u8str(third_choice); +//! @brief Show a two-choice prompt on the last line of the LCD +//! @param selected Show first choice as selected if true, the second otherwise +//! @param first_choice text caption of first possible choice +//! @param second_choice text caption of second possible choice +//! @param second_col column on LCD where second choice is rendered. +//! @param third_choice text caption of third, optional, choice. +void lcd_show_choices_prompt_P(uint8_t selected, const char *first_choice, const char *second_choice, uint8_t second_col, const char *third_choice) { + lcd_put_lchar(0, 3, selected == LCD_LEFT_BUTTON_CHOICE ? '>' : ' '); + lcd_put_u8str(first_choice); + lcd_put_lchar(second_col, 3, selected == LCD_MIDDLE_BUTTON_CHOICE ? '>' : ' '); + lcd_put_u8str(second_choice); + if (third_choice) { + lcd_put_lchar(18, 3, selected == LCD_RIGHT_BUTTON_CHOICE ? '>' : ' '); + lcd_put_u8str(third_choice); + } +} + +void lcd_space(uint8_t n) { + while (n--) lcd_put_lchar(' '); +} + +// Print extruder status (5 chars total) +// Scenario 1: "F?" +// There is no filament loaded and no tool change is in progress +// Scenario 2: "F[nr.]" +// [nr.] ranges from 1 to 5. +// Shows which filament is loaded. No tool change is in progress +// Scenario 3: "?>[nr.]" +// [nr.] ranges from 1 to 5. +// There is no filament currently loaded, but [nr.] is currently being loaded via tool change +// Scenario 4: "[nr.]>?" +// [nr.] ranges from 1 to 5. +// This scenario indicates a bug in the firmware if ? is on the right side +// Scenario 5: "[nr1.]>[nr2.]" +// [nr1.] ranges from 1 to 5. +// [nr2.] ranges from 1 to 5. +// Filament [nr1.] was loaded, but [nr2.] is currently being loaded via tool change +// Scenario 6: "?>?" +// This scenario should not be possible and indicates a bug in the firmware +uint8_t lcdui_print_extruder(void) { + uint8_t chars = 1; + lcd_space(1); + if (mmu3.get_current_tool() == mmu3.get_tool_change_tool()) { + lcd_put_lchar('F'); + lcd_put_lchar(mmu3.get_current_tool() == (uint8_t)MMU3::FILAMENT_UNKNOWN ? '?' : mmu3.get_current_tool() + '1'); + chars += 2; + } + else { + lcd_put_lchar(mmu3.get_current_tool() == (uint8_t)MMU3::FILAMENT_UNKNOWN ? '?' : mmu3.get_current_tool() + '1'); + lcd_put_lchar('>'); + lcd_put_lchar(mmu3.get_tool_change_tool() == (uint8_t)MMU3::FILAMENT_UNKNOWN ? '?' : mmu3.get_tool_change_tool() + '1'); + chars += 3; + } + return chars; +} + +bool is_whitespace_P(const char *c_addr) { + const char c = pgm_read_byte(c_addr); + return c == ' ' || c == '\t' || c == '\r' || c == '\n'; +} + +bool is_punctuation_P(const char *c_addr) { + const char c = pgm_read_byte(c_addr); + return c == '.' || c == ',' || c == ':' || c == ';' || c == '?' || c == '!' || c == '/'; +} + +/** + * @brief show full screen message + * + * This function is non-blocking + * @param msg message to be displayed from PROGMEM + * @return rest of the text (to be displayed on next page) + */ +static FSTR_P const lcd_display_message_fullscreen_async(FSTR_P const fmsg) { + PGM_P msg = FTOP(fmsg); + PGM_P msgend = msg; + //bool multi_screen = false; + for (uint8_t row = 0; row < LCD_HEIGHT; ++row) { + if (pgm_read_byte(msgend) == 0) break; + SETCURSOR(0, row); + + // Previous row ended with a complete word, so the first character in the + // next row is a whitespace. We can skip the whitespace on a new line. + if (is_whitespace_P(msg) && ++msg == nullptr) break; // End of the message. + + uint8_t linelen = (strlen_P(msg) > LCD_WIDTH) ? LCD_WIDTH : strlen_P(msg); + PGM_P const msgend2 = msg + linelen; + msgend = msgend2; + if (row == 3 && linelen == LCD_WIDTH) { + // Last line of the display, full line should be displayed. + // Find out, whether this message will be split into multiple screens. + //multi_screen = pgm_read_byte(msgend) != 0; + // We do not need this... + //if (multi_screen) msgend = (msgend2 -= 2); } - } - - void lcd_space(uint8_t n) { - while (n--) lcd_put_lchar(' '); - } - - // Print extruder status (5 chars total) - // Scenario 1: "F?" - // There is no filament loaded and no tool change is in progress - // Scenario 2: "F[nr.]" - // [nr.] ranges from 1 to 5. - // Shows which filament is loaded. No tool change is in progress - // Scenario 3: "?>[nr.]" - // [nr.] ranges from 1 to 5. - // There is no filament currently loaded, but [nr.] is currently being loaded via tool change - // Scenario 4: "[nr.]>?" - // [nr.] ranges from 1 to 5. - // This scenario indicates a bug in the firmware if ? is on the right side - // Scenario 5: "[nr1.]>[nr2.]" - // [nr1.] ranges from 1 to 5. - // [nr2.] ranges from 1 to 5. - // Filament [nr1.] was loaded, but [nr2.] is currently being loaded via tool change - // Scenario 6: "?>?" - // This scenario should not be possible and indicates a bug in the firmware - uint8_t lcdui_print_extruder(void) { - uint8_t chars = 1; - lcd_space(1); - if (mmu3.get_current_tool() == mmu3.get_tool_change_tool()) { - lcd_put_lchar('F'); - lcd_put_lchar(mmu3.get_current_tool() == (uint8_t)MMU3::FILAMENT_UNKNOWN ? '?' : mmu3.get_current_tool() + '1'); - chars += 2; + if (pgm_read_byte(msgend) != 0 && !is_whitespace_P(msgend) && !is_punctuation_P(msgend)) { + // Splitting a word. Find the start of the current word. + while (msgend > msg && !is_whitespace_P(msgend - 1)) --msgend; + if (msgend == msg) msgend = msgend2; // Found a single long word, which cannot be split. Just cut it. } - else { - lcd_put_lchar(mmu3.get_current_tool() == (uint8_t)MMU3::FILAMENT_UNKNOWN ? '?' : mmu3.get_current_tool() + '1'); - lcd_put_lchar('>'); - lcd_put_lchar(mmu3.get_tool_change_tool() == (uint8_t)MMU3::FILAMENT_UNKNOWN ? '?' : mmu3.get_tool_change_tool() + '1'); - chars += 3; - } - return chars; - } - - bool pgm_is_whitespace(const char *c_addr) { - const char c = pgm_read_byte(c_addr); - return c == ' ' || c == '\t' || c == '\r' || c == '\n'; - } - - bool pgm_is_interpunction(const char *c_addr) { - const char c = pgm_read_byte(c_addr); - return c == '.' || c == ',' || c == ':' || c == ';' || c == '?' || c == '!' || c == '/'; - } - - /** - * @brief show full screen message - * - * This function is non-blocking - * @param msg message to be displayed from PROGMEM - * @return rest of the text (to be displayed on next page) - */ - static FSTR_P const lcd_display_message_fullscreen_nonBlocking(FSTR_P const fmsg) { - PGM_P msg = FTOP(fmsg); - PGM_P msgend = msg; - //bool multi_screen = false; - for (uint8_t row = 0; row < LCD_HEIGHT; ++row) { - if (pgm_read_byte(msgend) == 0) break; - SETCURSOR(0, row); - - // Previous row ended with a complete word, so the first character in the - // next row is a whitespace. We can skip the whitespace on a new line. - if (pgm_is_whitespace(msg) && ++msg == nullptr) break; // End of the message. - - uint8_t linelen = (strlen_P(msg) > LCD_WIDTH) ? LCD_WIDTH : strlen_P(msg); - PGM_P const msgend2 = msg + linelen; - msgend = msgend2; - if (row == 3 && linelen == LCD_WIDTH) { - // Last line of the display, full line should be displayed. - // Find out, whether this message will be split into multiple screens. - //multi_screen = pgm_read_byte(msgend) != 0; - // We do not need this... - //if (multi_screen) msgend = (msgend2 -= 2); + for (; msg < msgend; ++msg) { + const char c = char(pgm_read_byte(msg)); + if (c == '\n') { + // Abort early if '\n' is encountered. + // This character is used to force the following words to be printed on the next line. + break; } - if (pgm_read_byte(msgend) != 0 && !pgm_is_whitespace(msgend) && !pgm_is_interpunction(msgend)) { - // Splitting a word. Find the start of the current word. - while (msgend > msg && !pgm_is_whitespace(msgend - 1)) --msgend; - if (msgend == msg) msgend = msgend2; // Found a single long word, which cannot be split. Just cut it. - } - for (; msg < msgend; ++msg) { - const char c = char(pgm_read_byte(msg)); - if (c == '\n') { - // Abort early if '\n' is encountered. - // This character is used to force the following words to be printed on the next line. - break; + lcd_put_lchar(c); + } + } + return FPSTR(msgend); +} + +FSTR_P const lcd_display_message_fullscreen(FSTR_P const fmsg) { + // Disable update of the screen by the usual lcd_update(0) routine. + #if HAS_WIRED_LCD + //ui.lcdDrawUpdate = LCDViewAction::LCDVIEW_NONE; + ui.clear_lcd(); + return lcd_display_message_fullscreen_async(fmsg); + #else + return fmsg + #endif +} + +/** + * @brief show full screen message and wait + * + * This function is blocking. + * @param msg message to be displayed from PROGMEM + */ +void lcd_show_fullscreen_message_and_wait(FSTR_P const fmsg) { + LcdUpdateDisabler lcdUpdateDisabler; + FSTR_P fmsg_next = lcd_display_message_fullscreen(fmsg); + const bool multi_screen = fmsg_next != nullptr; + ui.use_click(); + KEEPALIVE_STATE(PAUSED_FOR_USER); + // Until confirmed by a button click. + for (;;) { + if (fmsg_next == nullptr) { + // Display the confirm char. + //lcd_put_lchar(LCD_WIDTH - 2, LCD_HEIGHT - 2, LCD_STR_CONFIRM[0]); + } + // Wait for 5 seconds before displaying the next text. + for (uint8_t i = 0; i < 100; ++i) { + marlin.idle(true); + safe_delay(50); + if (ui.use_click()) { + if (fmsg_next == nullptr) { + KEEPALIVE_STATE(IN_HANDLER); + return ui.go_back(); } - lcd_put_lchar(c); + if (!multi_screen) break; + if (fmsg_next == nullptr) fmsg_next = fmsg; + fmsg_next = lcd_display_message_fullscreen(fmsg_next); } } - // We do not need this part... //if (multi_screen) { - // // Display the double down arrow. - // lcd_put_lchar(LCD_WIDTH - 2, LCD_HEIGHT - 2, LCD_STR_ARROW_2_DOWN[0]); + // if (fmsg_next == nullptr) fmsg_next = fmsg; + // fmsg_next = lcd_display_message_fullscreen(fmsg_next); //} - //return multi_screen ? msgend : nullptr; - return FPSTR(msgend); } +} - FSTR_P const lcd_display_message_fullscreen(FSTR_P const fmsg) { - // Disable update of the screen by the usual lcd_update(0) routine. - #if HAS_WIRED_LCD - //ui.lcdDrawUpdate = LCDViewAction::LCDVIEW_NONE; - ui.clear_lcd(); - return lcd_display_message_fullscreen_nonBlocking(fmsg); - #else - return fmsg - #endif - } - - /** - * @brief show full screen message and wait - * - * This function is blocking. - * @param msg message to be displayed from PROGMEM - */ - void lcd_show_fullscreen_message_and_wait(FSTR_P const fmsg) { - LcdUpdateDisabler lcdUpdateDisabler; - FSTR_P fmsg_next = lcd_display_message_fullscreen(fmsg); - const bool multi_screen = fmsg_next != nullptr; - ui.use_click(); - KEEPALIVE_STATE(PAUSED_FOR_USER); - // Until confirmed by a button click. - for (;;) { - if (fmsg_next == nullptr) { - // Display the confirm char. - //lcd_put_lchar(LCD_WIDTH - 2, LCD_HEIGHT - 2, LCD_STR_CONFIRM[0]); - } - // Wait for 5 seconds before displaying the next text. - for (uint8_t i = 0; i < 100; ++i) { - idle(true); - safe_delay(50); - if (ui.use_click()) { - if (fmsg_next == nullptr) { - KEEPALIVE_STATE(IN_HANDLER); - return ui.go_back(); - } - if (!multi_screen) break; - if (fmsg_next == nullptr) fmsg_next = fmsg; - fmsg_next = lcd_display_message_fullscreen(fmsg_next); - } - } - //if (multi_screen) { - // if (fmsg_next == nullptr) fmsg_next = fmsg; - // fmsg_next = lcd_display_message_fullscreen(fmsg_next); - //} - } - } - - void lcd_insert_char_into_status(uint8_t position, const char message) { - if (position >= LCD_WIDTH) return; - //int size = ui.status_message.length(); - char *str = ui.status_message.buffer(); - str[position] = message; - ui.refresh(LCDVIEW_REDRAW_NOW); // force redraw - } +void lcd_replace_status_char(const uint8_t position, const char message) { + if (position >= MAX_MESSAGE_SIZE) return; + //int size = ui.status_message.length(); + char *str = ui.status_message.buffer(); + str[position] = message; + ui.refresh(LCDVIEW_REDRAW_NOW); // force redraw +} #endif // HAS_PRUSA_MMU3 diff --git a/Marlin/src/feature/mmu3/ultralcd.h b/Marlin/src/feature/mmu3/ultralcd.h index 2f17b61d0a..e7f06dfb1f 100644 --- a/Marlin/src/feature/mmu3/ultralcd.h +++ b/Marlin/src/feature/mmu3/ultralcd.h @@ -48,11 +48,11 @@ class LcdUpdateDisabler { public: LcdUpdateDisabler() : m_updateEnabled(ui.lcdDrawUpdate) { - TERN_(HAS_WIRED_LCD, ui.lcdDrawUpdate = LCDViewAction::LCDVIEW_NONE); + TERN_(HAS_WIRED_LCD, ui.refresh(LCDViewAction::LCDVIEW_NONE)); } ~LcdUpdateDisabler() { #if HAS_WIRED_LCD - ui.lcdDrawUpdate = m_updateEnabled; + ui.refresh(m_updateEnabled); ui.clear_lcd(); ui.update(); #endif @@ -62,11 +62,11 @@ class LcdUpdateDisabler { LCDViewAction m_updateEnabled; }; -bool pgm_is_whitespace(const char *c_addr); -bool pgm_is_interpunction(const char *c_addr); +bool is_whitespace_P(const char *c_addr); +bool is_punctuation_P(const char *c_addr); FSTR_P const lcd_display_message_fullscreen(FSTR_P const pmsg); void lcd_show_choices_prompt_P(uint8_t selected, const char *first_choice, const char *second_choice, uint8_t second_col, const char *third_choice=nullptr); void lcd_show_fullscreen_message_and_wait(FSTR_P const fmsg); uint8_t lcdui_print_extruder(void); void lcd_space(uint8_t n); -void lcd_insert_char_into_status(uint8_t position, const char message); +void lcd_replace_status_char(uint8_t position, const char message); diff --git a/Marlin/src/feature/password/password.cpp b/Marlin/src/feature/password/password.cpp index 1d376cc586..d36b3edd09 100644 --- a/Marlin/src/feature/password/password.cpp +++ b/Marlin/src/feature/password/password.cpp @@ -36,7 +36,7 @@ uint32_t Password::value, Password::value_entry; // // Authenticate user with password. -// Called from Setup, after SD Prinitng Stops/Aborts, and M510 +// Called from Setup, after SD Printing Stops/Aborts, and M510 // void Password::lock_machine() { is_locked = true; diff --git a/Marlin/src/feature/password/password.h b/Marlin/src/feature/password/password.h index 208765b212..0f8bc28bd8 100644 --- a/Marlin/src/feature/password/password.h +++ b/Marlin/src/feature/password/password.h @@ -37,6 +37,8 @@ public: static void access_menu_password(); static void authentication_done(); static void media_gatekeeper(); + static void media_gatekeeper_sd(); + static void media_gatekeeper_usb(); private: static void authenticate_user(const screenFunc_t, const screenFunc_t); diff --git a/Marlin/src/feature/pause.cpp b/Marlin/src/feature/pause.cpp index 3589847761..025bcb8383 100644 --- a/Marlin/src/feature/pause.cpp +++ b/Marlin/src/feature/pause.cpp @@ -160,10 +160,10 @@ static bool ensure_safe_temperature(const bool wait=true, const PauseMode mode=P if (wait) return thermalManager.wait_for_hotend(active_extruder); // Allow interruption by Emergency Parser M108 - wait_for_heatup = TERN1(PREVENT_COLD_EXTRUSION, !thermalManager.allow_cold_extrude); - while (wait_for_heatup && ABS(thermalManager.wholeDegHotend(active_extruder) - thermalManager.degTargetHotend(active_extruder)) > (TEMP_WINDOW)) - idle(); - wait_for_heatup = false; + marlin.wait_for_heatup = TERN1(PREVENT_COLD_EXTRUSION, !thermalManager.allow_cold_extrude); + while (marlin.is_heating() && ABS(thermalManager.wholeDegHotend(active_extruder) - thermalManager.degTargetHotend(active_extruder)) > (TEMP_WINDOW)) + marlin.idle(); + marlin.heatup_done(); #if ENABLED(PREVENT_COLD_EXTRUSION) // A user can cancel wait-for-heating with M108 @@ -188,10 +188,8 @@ static bool ensure_safe_temperature(const bool wait=true, const PauseMode mode=P * * Returns 'true' if load was completed, 'false' for abort */ -bool load_filament(const_float_t slow_load_length/*=0*/, const_float_t fast_load_length/*=0*/, const_float_t purge_length/*=0*/, const int8_t max_beep_count/*=0*/, - const bool show_lcd/*=false*/, const bool pause_for_user/*=false*/, - const PauseMode mode/*=PAUSE_MODE_PAUSE_PRINT*/ - DXC_ARGS +bool load_filament(const float slow_load_length/*=0*/, const float fast_load_length/*=0*/, const float purge_length/*=0*/, const int8_t max_beep_count/*=0*/, + const bool show_lcd/*=false*/, const bool pause_for_user/*=false*/, const PauseMode mode/*=PAUSE_MODE_PAUSE_PRINT*/ DXC_ARGS ) { DEBUG_SECTION(lf, "load_filament", true); DEBUG_ECHOLNPGM("... slowlen:", slow_load_length, " fastlen:", fast_load_length, " purgelen:", purge_length, " maxbeep:", max_beep_count, " showlcd:", show_lcd, " pauseforuser:", pause_for_user, " pausemode:", mode DXC_SAY); @@ -208,7 +206,7 @@ bool load_filament(const_float_t slow_load_length/*=0*/, const_float_t fast_load first_impatient_beep(max_beep_count); KEEPALIVE_STATE(PAUSED_FOR_USER); - wait_for_user = true; // LCD click or M108 will clear this + marlin.wait_start(); // LCD click or M108 will clear this TERN_(EXTENSIBLE_UI, ExtUI::onUserConfirmRequired(GET_TEXT_F(MSG_FILAMENTLOAD))); @@ -217,19 +215,19 @@ bool load_filament(const_float_t slow_load_length/*=0*/, const_float_t fast_load hostui.prompt_do(PROMPT_USER_CONTINUE, F("Load Filament T"), tool, FPSTR(CONTINUE_STR)); #endif - while (wait_for_user) { + while (marlin.wait_for_user) { impatient_beep(max_beep_count); #if ALL(HAS_FILAMENT_SENSOR, FILAMENT_CHANGE_RESUME_ON_INSERT) #if MULTI_FILAMENT_SENSOR - #define _CASE_INSERTED(N) case N-1: if (READ(FIL_RUNOUT##N##_PIN) != FIL_RUNOUT##N##_STATE) wait_for_user = false; break; + #define _CASE_INSERTED(N) case N-1: if (!FILAMENT_IS_OUT(N)) marlin.user_resume(); break; switch (active_extruder) { REPEAT_1(NUM_RUNOUT_SENSORS, _CASE_INSERTED) } #else - if (!FILAMENT_IS_OUT()) wait_for_user = false; + if (!FILAMENT_IS_OUT()) marlin.user_resume(); #endif #endif - idle_no_sleep(); + marlin.idle_no_sleep(); } } @@ -272,10 +270,10 @@ bool load_filament(const_float_t slow_load_length/*=0*/, const_float_t fast_load TERN_(EXTENSIBLE_UI, ExtUI::onUserConfirmRequired(GET_TEXT_F(MSG_FILAMENT_CHANGE_PURGE))); TERN_(HOST_PROMPT_SUPPORT, hostui.continue_prompt(GET_TEXT_F(MSG_FILAMENT_CHANGE_PURGE))); - wait_for_user = true; // A click or M108 breaks the purge_length loop - for (float purge_count = purge_length; purge_count > 0 && wait_for_user; --purge_count) + marlin.wait_start(); // A click or M108 breaks the purge_length loop + for (float purge_count = purge_length; purge_count > 0 && marlin.wait_for_user; --purge_count) unscaled_e_move(1, ADVANCED_PAUSE_PURGE_FEEDRATE); - wait_for_user = false; + marlin.user_resume(); #else @@ -299,14 +297,14 @@ bool load_filament(const_float_t slow_load_length/*=0*/, const_float_t fast_load if (show_lcd) { // Show "Purge More" / "Resume" menu and wait for reply KEEPALIVE_STATE(PAUSED_FOR_USER); - wait_for_user = false; + marlin.user_resume(); + pause_menu_response = PAUSE_RESPONSE_WAIT_FOR; #if ANY(HAS_MARLINUI_MENU, EXTENSIBLE_UI) ui.pause_show_message(PAUSE_MESSAGE_OPTION); // MarlinUI and MKS UI also set PAUSE_RESPONSE_WAIT_FOR #else - pause_menu_response = PAUSE_RESPONSE_WAIT_FOR; TERN_(SOVOL_SV06_RTS, rts.gotoPage(ID_PurgeMore_L, ID_PurgeMore_D)); #endif - while (pause_menu_response == PAUSE_RESPONSE_WAIT_FOR) idle_no_sleep(); + while (pause_menu_response == PAUSE_RESPONSE_WAIT_FOR) marlin.idle_no_sleep(); } #endif @@ -344,10 +342,10 @@ inline void disable_active_extruder() { * * Returns 'true' if unload was completed, 'false' for abort */ -bool unload_filament(const_float_t unload_length, const bool show_lcd/*=false*/, +bool unload_filament(const float unload_length, const bool show_lcd/*=false*/, const PauseMode mode/*=PAUSE_MODE_PAUSE_PRINT*/ #if ALL(FILAMENT_UNLOAD_ALL_EXTRUDERS, MIXING_EXTRUDER) - , const_float_t mix_multiplier/*=1.0*/ + , const float mix_multiplier/*=1.0*/ #endif ) { DEBUG_SECTION(uf, "unload_filament", true); @@ -418,7 +416,7 @@ bool unload_filament(const_float_t unload_length, const bool show_lcd/*=false*/, */ uint8_t did_pause_print = 0; -bool pause_print(const_float_t retract, const xyz_pos_t &park_point, const bool show_lcd/*=false*/, const_float_t unload_length/*=0*/ DXC_ARGS) { +bool pause_print(const float retract, const xyz_pos_t &park_point, const bool show_lcd/*=false*/, const float unload_length/*=0*/ DXC_ARGS) { DEBUG_SECTION(pp, "pause_print", true); DEBUG_ECHOLNPGM("... park.x:", park_point.x, " y:", park_point.y, " z:", park_point.z, " unloadlen:", unload_length, " showlcd:", show_lcd DXC_SAY); @@ -439,7 +437,7 @@ bool pause_print(const_float_t retract, const xyz_pos_t &park_point, const bool // Pause the print job and timer #if HAS_MEDIA - const bool was_sd_printing = IS_SD_PRINTING(); + const bool was_sd_printing = card.isStillPrinting(); if (was_sd_printing) { card.pauseSDPrint(); ++did_pause_print; // Indicate SD pause also @@ -555,8 +553,8 @@ void wait_for_confirmation(const bool is_reload/*=false*/, const int8_t max_beep KEEPALIVE_STATE(PAUSED_FOR_USER); TERN_(HOST_PROMPT_SUPPORT, hostui.continue_prompt(GET_TEXT_F(MSG_NOZZLE_PARKED))); TERN_(EXTENSIBLE_UI, ExtUI::onUserConfirmRequired(GET_TEXT_F(MSG_NOZZLE_PARKED))); - wait_for_user = true; // LCD click or M108 will clear this - while (wait_for_user) { + marlin.wait_start(); // LCD click or M108 will clear this + while (marlin.wait_for_user) { impatient_beep(max_beep_count); // If the nozzle has timed out... @@ -581,7 +579,7 @@ void wait_for_confirmation(const bool is_reload/*=false*/, const int8_t max_beep ExtUI::onUserConfirmRequired(GET_TEXT_F(MSG_HEATER_TIMEOUT)); #endif - TERN_(HAS_RESUME_CONTINUE, wait_for_user_response(0, true)); // Wait for LCD click or M108 + TERN_(HAS_RESUME_CONTINUE, marlin.wait_for_user_response(0, true)); // Wait for LCD click or M108 TERN_(HOST_PROMPT_SUPPORT, hostui.prompt_do(PROMPT_INFO, GET_TEXT_F(MSG_REHEATING))); @@ -608,12 +606,12 @@ void wait_for_confirmation(const bool is_reload/*=false*/, const int8_t max_beep LCD_MESSAGE(MSG_REHEATDONE); #endif - IF_DISABLED(PAUSE_REHEAT_FAST_RESUME, wait_for_user = true); + IF_DISABLED(PAUSE_REHEAT_FAST_RESUME, marlin.wait_start()); nozzle_timed_out = false; first_impatient_beep(max_beep_count); } - idle_no_sleep(); + marlin.idle_no_sleep(); } TERN_(DUAL_X_CARRIAGE, set_duplication_enabled(saved_ext_dup_mode, saved_ext)); } @@ -639,9 +637,9 @@ void wait_for_confirmation(const bool is_reload/*=false*/, const int8_t max_beep * - Resume the current SD print job, if any */ void resume_print( - const_float_t slow_load_length/*=0*/, - const_float_t fast_load_length/*=0*/, - const_float_t purge_length/*=ADVANCED_PAUSE_PURGE_LENGTH*/, + const float slow_load_length/*=0*/, + const float fast_load_length/*=0*/, + const float purge_length/*=ADVANCED_PAUSE_PURGE_LENGTH*/, const int8_t max_beep_count/*=0*/, const celsius_t targetTemp/*=0*/, const bool show_lcd/*=true*/, diff --git a/Marlin/src/feature/pause.h b/Marlin/src/feature/pause.h index 5ee2e50ea7..4fbb108180 100644 --- a/Marlin/src/feature/pause.h +++ b/Marlin/src/feature/pause.h @@ -91,10 +91,10 @@ extern uint8_t did_pause_print; // Pause the print. If unload_length is set, do a Filament Unload bool pause_print( - const_float_t retract, // (mm) Retraction length + const float retract, // (mm) Retraction length const xyz_pos_t &park_point, // Parking XY Position and Z Raise const bool show_lcd=false, // Set LCD status messages? - const_float_t unload_length=0 // (mm) Filament Change Unload Length - 0 to skip + const float unload_length=0 // (mm) Filament Change Unload Length - 0 to skip DXC_PARAMS // Dual-X-Carriage extruder index ); @@ -105,9 +105,9 @@ void wait_for_confirmation( ); void resume_print( - const_float_t slow_load_length=0, // (mm) Slow Load Length for finishing move - const_float_t fast_load_length=0, // (mm) Fast Load Length for initial move - const_float_t purge_length=ADVANCED_PAUSE_PURGE_LENGTH, // (mm) Purge length + const float slow_load_length=0, // (mm) Slow Load Length for finishing move + const float fast_load_length=0, // (mm) Fast Load Length for initial move + const float purge_length=ADVANCED_PAUSE_PURGE_LENGTH, // (mm) Purge length const int8_t max_beep_count=0, // Beep alert for attention const celsius_t targetTemp=0, // (°C) A target temperature for the hotend const bool show_lcd=true, // Set LCD status messages? @@ -116,9 +116,9 @@ void resume_print( ); bool load_filament( - const_float_t slow_load_length=0, // (mm) Slow Load Length for finishing move - const_float_t fast_load_length=0, // (mm) Fast Load Length for initial move - const_float_t purge_length=0, // (mm) Purge length + const float slow_load_length=0, // (mm) Slow Load Length for finishing move + const float fast_load_length=0, // (mm) Fast Load Length for initial move + const float purge_length=0, // (mm) Purge length const int8_t max_beep_count=0, // Beep alert for attention const bool show_lcd=false, // Set LCD status messages? const bool pause_for_user=false, // Pause for user before returning? @@ -127,11 +127,11 @@ bool load_filament( ); bool unload_filament( - const_float_t unload_length, // (mm) Filament Unload Length - 0 to skip + const float unload_length, // (mm) Filament Unload Length - 0 to skip const bool show_lcd=false, // Set LCD status messages? const PauseMode mode=PAUSE_MODE_PAUSE_PRINT // Pause Mode to apply #if ALL(FILAMENT_UNLOAD_ALL_EXTRUDERS, MIXING_EXTRUDER) - , const_float_t mix_multiplier=1.0f // Extrusion multiplier (for a Mixing Extruder) + , const float mix_multiplier=1.0f // Extrusion multiplier (for a Mixing Extruder) #endif ); diff --git a/Marlin/src/feature/power.cpp b/Marlin/src/feature/power.cpp index c6dc562836..2068558fe9 100644 --- a/Marlin/src/feature/power.cpp +++ b/Marlin/src/feature/power.cpp @@ -119,7 +119,7 @@ void Power::power_on() { * Processes any PSU_POWEROFF_GCODE and makes a PS_OFF_SOUND if enabled. */ void Power::power_off() { - TERN_(HAS_SUICIDE, suicide()); + TERN_(HAS_SUICIDE, marlin.suicide()); if (!psu_on) return; @@ -208,7 +208,7 @@ void Power::power_off() { // If any of the stepper drivers are enabled... if (stepper.axis_enabled.bits) return true; - if (printJobOngoing() || printingIsPaused()) return true; + if (marlin.printJobOngoing() || marlin.printingIsPaused()) return true; #if ENABLED(AUTO_POWER_FANS) FANS_LOOP(i) if (thermalManager.fan_speed[i]) return true; @@ -261,7 +261,7 @@ void Power::power_off() { nextPowerCheck = now + 2500UL; if (is_power_needed()) power_on(); - else if (!lastPowerOn || (POWER_TIMEOUT > 0 && ELAPSED(now, lastPowerOn + SEC_TO_MS(POWER_TIMEOUT)))) + else if (!lastPowerOn || (POWER_TIMEOUT > 0 && ELAPSED(now, lastPowerOn, SEC_TO_MS(POWER_TIMEOUT)))) power_off(); } } diff --git a/Marlin/src/feature/powerloss.cpp b/Marlin/src/feature/powerloss.cpp index 3cd96e1155..0dd19808bc 100644 --- a/Marlin/src/feature/powerloss.cpp +++ b/Marlin/src/feature/powerloss.cpp @@ -99,7 +99,7 @@ PrintJobRecovery recovery; /** * Clear the recovery info */ -void PrintJobRecovery::init() { info = {}; } +void PrintJobRecovery::init() { info = { 0 }; } /** * Enable or disable then call changed() @@ -117,7 +117,7 @@ void PrintJobRecovery::enable(const bool onoff) { void PrintJobRecovery::changed() { if (!enabled) purge(); - else if (IS_SD_PRINTING()) + else if (card.isStillPrinting()) save(true); TERN_(EXTENSIBLE_UI, ExtUI::onSetPowerLoss(enabled)); } @@ -141,6 +141,14 @@ bool PrintJobRecovery::check() { return success; } +/** + * Cancel recovery + */ +void PrintJobRecovery::cancel() { + TERN_(PLR_HEAT_BED_ON_REBOOT, set_bed_temp(false)); + purge(); +} + /** * Delete the recovery file and clear the recovery data */ @@ -174,7 +182,7 @@ void PrintJobRecovery::prepare() { */ void PrintJobRecovery::save(const bool force/*=false*/, const float zraise/*=POWER_LOSS_ZRAISE*/, const bool raised/*=false*/) { - // We don't check IS_SD_PRINTING here so a save may occur during a pause + // We don't check isStillPrinting here so a save may occur during a pause #if SAVE_INFO_INTERVAL_MS > 0 static millis_t next_save_ms; // = 0 @@ -202,7 +210,7 @@ void PrintJobRecovery::save(const bool force/*=false*/, const float zraise/*=POW // Set Head and Foot to matching non-zero values if (!++info.valid_head) ++info.valid_head; // non-zero in sequence - //if (!IS_SD_PRINTING()) info.valid_head = 0; + //if (!card.isStillPrinting()) info.valid_head = 0; info.valid_foot = info.valid_head; // Machine state @@ -221,7 +229,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); @@ -270,7 +278,7 @@ void PrintJobRecovery::save(const bool force/*=false*/, const float zraise/*=POW #if ENABLED(BACKUP_POWER_SUPPLY) - void PrintJobRecovery::retract_and_lift(const_float_t zraise) { + void PrintJobRecovery::retract_and_lift(const float zraise) { #if POWER_LOSS_RETRACT_LEN || POWER_LOSS_ZRAISE gcode.set_relative_mode(true); // Use relative coordinates @@ -313,7 +321,7 @@ void PrintJobRecovery::save(const bool force/*=false*/, const float zraise/*=POW void PrintJobRecovery::_outage(TERN_(DEBUG_POWER_LOSS_RECOVERY, const bool simulated/*=false*/)) { #if ENABLED(BACKUP_POWER_SUPPLY) static bool lock = false; - if (lock) return; // No re-entrance from idle() during retract_and_lift() + if (lock) return; // No re-entrance from marlin.idle() during retract_and_lift() lock = true; #endif @@ -326,7 +334,7 @@ void PrintJobRecovery::save(const bool force/*=false*/, const float zraise/*=POW // Save the current position, distance that Z was (or should be) raised, // and a flag whether the raise was already done here. - if (IS_SD_PRINTING()) save(true, zraise, ENABLED(BACKUP_POWER_SUPPLY)); + if (card.isStillPrinting()) save(true, zraise, ENABLED(BACKUP_POWER_SUPPLY)); // Tell the LCD about the outage, even though it is about to die TERN_(EXTENSIBLE_UI, ExtUI::onPowerLoss()); @@ -347,7 +355,7 @@ void PrintJobRecovery::save(const bool force/*=false*/, const float zraise/*=POW sync_plan_position(); } else - kill(GET_TEXT_F(MSG_OUTAGE_RECOVERY)); + marlin.kill(GET_TEXT_F(MSG_OUTAGE_RECOVERY)); } #endif // POWER_LOSS_PIN || DEBUG_POWER_LOSS_RECOVERY @@ -366,6 +374,13 @@ void PrintJobRecovery::write() { if (!file.close()) DEBUG_ECHOLNPGM("Power-loss file close failed."); } +#if ENABLED(PLR_HEAT_BED_ON_REBOOT) + // Set bed temperature and wait. Called from M1000 to resume bed heating. + void PrintJobRecovery::set_bed_temp(const bool on) { + PROCESS_SUBCOMMANDS_NOW(TS(F("M190S"), on ? info.target_temperature_bed + PLR_HEAT_BED_EXTRA : 0)); + } +#endif + /** * Resume the saved print job */ @@ -420,8 +435,11 @@ void PrintJobRecovery::resume() { #endif // Interpret the saved Z according to flags - const float z_print = resume_pos.z, - z_raised = z_print + info.zraise; + const float z_print = resume_pos.z; + + #if ANY(Z_HOME_TO_MAX, POWER_LOSS_RECOVER_ZHOME) || DISABLED(BELTPRINTER) + const float z_raised = z_print + info.zraise; + #endif // // Home the axes that can safely be homed, and @@ -482,7 +500,7 @@ void PrintJobRecovery::resume() { #if !HOMING_Z_DOWN // The physical Z was adjusted at power-off so undo the M420S1 correction to Z with G92.9. - PROCESS_SUBCOMMANDS_NOW(TS(F("G92.9Z"), p_float_t(z_now, 1))); + PROCESS_SUBCOMMANDS_NOW(TS(F("G92.9Z"), p_float_t(z_now, 3))); #endif #endif @@ -493,7 +511,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))); @@ -529,7 +547,7 @@ void PrintJobRecovery::resume() { } #endif - // Restore retract and hop state from an active `G10` command + // Restore retract and hop state from an active 'G10' command #if ENABLED(FWRETRACT) EXTRUDER_LOOP() { if (info.retract[e] != 0.0) { @@ -656,7 +674,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(); @@ -722,7 +740,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 } diff --git a/Marlin/src/feature/powerloss.h b/Marlin/src/feature/powerloss.h index 8e1e299ac0..bfa5b4717f 100644 --- a/Marlin/src/feature/powerloss.h +++ b/Marlin/src/feature/powerloss.h @@ -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; @@ -201,10 +201,15 @@ class PrintJobRecovery { static void close() { file.close(); } static bool check(); + + #if ENABLED(PLR_HEAT_BED_ON_REBOOT) + static void set_bed_temp(const bool turn_on); + #endif + static void resume(); static void purge(); - static void cancel() { purge(); } + static void cancel(); static void load(); static void save(const bool force=ENABLED(SAVE_EACH_CMD_MODE), const float zraise=POWER_LOSS_ZRAISE, const bool raised=false); @@ -237,7 +242,7 @@ class PrintJobRecovery { static void write(); #if ENABLED(BACKUP_POWER_SUPPLY) - static void retract_and_lift(const_float_t zraise); + static void retract_and_lift(const float zraise); #endif #if PIN_EXISTS(POWER_LOSS) || ENABLED(DEBUG_POWER_LOSS_RECOVERY) diff --git a/Marlin/src/feature/probe_temp_comp.cpp b/Marlin/src/feature/probe_temp_comp.cpp index f640a9fd2f..7dfa28f4b9 100644 --- a/Marlin/src/feature/probe_temp_comp.cpp +++ b/Marlin/src/feature/probe_temp_comp.cpp @@ -104,12 +104,12 @@ void ProbeTempComp::print_offsets() { #endif } -void ProbeTempComp::prepare_new_calibration(const_float_t init_meas_z) { +void ProbeTempComp::prepare_new_calibration(const float init_meas_z) { calib_idx = 0; init_measurement = init_meas_z; } -void ProbeTempComp::push_back_new_measurement(const TempSensorID tsi, const_float_t meas_z) { +void ProbeTempComp::push_back_new_measurement(const TempSensorID tsi, const float meas_z) { if (calib_idx >= cali_info[tsi].measurements) return; sensor_z_offsets[tsi][calib_idx++] = static_cast((meas_z - init_measurement) * 1000.0f); } @@ -186,7 +186,7 @@ void ProbeTempComp::compensate_measurement(const TempSensorID tsi, const celsius }; // Interpolate Z based on a temperature being within a given range - auto linear_interp = [](const_float_t x, xy_float_t p1, xy_float_t p2) { + auto linear_interp = [](const float x, xy_float_t p1, xy_float_t p2) { // zoffs1 + zoffset_per_toffset * toffset return p1.y + (p2.y - p1.y) / (p2.x - p1.x) * (x - p1.x); }; @@ -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) { diff --git a/Marlin/src/feature/probe_temp_comp.h b/Marlin/src/feature/probe_temp_comp.h index 42348db684..e6509a20cf 100644 --- a/Marlin/src/feature/probe_temp_comp.h +++ b/Marlin/src/feature/probe_temp_comp.h @@ -84,8 +84,8 @@ class ProbeTempComp { } static bool set_offset(const TempSensorID tsi, const uint8_t idx, const int16_t offset); static void print_offsets(); - static void prepare_new_calibration(const_float_t init_meas_z); - static void push_back_new_measurement(const TempSensorID tsi, const_float_t meas_z); + static void prepare_new_calibration(const float init_meas_z); + static void push_back_new_measurement(const TempSensorID tsi, const float meas_z); static bool finish_calibration(const TempSensorID tsi); static void set_enabled(const bool ena) { enabled = ena; } diff --git a/Marlin/src/feature/runout.cpp b/Marlin/src/feature/runout.cpp index cb7c6279bc..f0b94d0de8 100644 --- a/Marlin/src/feature/runout.cpp +++ b/Marlin/src/feature/runout.cpp @@ -33,7 +33,7 @@ FilamentMonitor runout; bool FilamentMonitorBase::enabled = true, - FilamentMonitorBase::filament_ran_out; // = false + FilamentMonitorBase::filament_ran_out; // = false #if ENABLED(HOST_ACTION_COMMANDS) bool FilamentMonitorBase::host_handling; // = false @@ -51,6 +51,10 @@ bool FilamentMonitorBase::enabled = true, #if ENABLED(FILAMENT_MOTION_SENSOR) uint8_t FilamentSensorEncoder::motion_detected; #endif + #if ENABLED(FILAMENT_SWITCH_AND_MOTION) + bool RunoutResponseDelayed::ignore_motion = false; + float RunoutResponseDelayed::motion_distance_mm = FILAMENT_MOTION_DISTANCE_MM; + #endif #else int8_t RunoutResponseDebounced::runout_count[NUM_RUNOUT_SENSORS]; // = 0 #endif @@ -72,6 +76,8 @@ bool FilamentMonitorBase::enabled = true, void event_filament_runout(const uint8_t extruder) { + runout.init_for_restart(false); // Reset and disable + if (did_pause_print) return; // Action already in progress. Purge triggered repeated runout. #if ENABLED(TOOLCHANGE_MIGRATION_FEATURE) diff --git a/Marlin/src/feature/runout.h b/Marlin/src/feature/runout.h index 52a9020830..7881af4e38 100644 --- a/Marlin/src/feature/runout.h +++ b/Marlin/src/feature/runout.h @@ -31,7 +31,6 @@ #include "../module/stepper.h" // for block_t #include "../gcode/queue.h" #include "pause.h" // for did_pause_print -#include "../MarlinCore.h" // for printingIsActive() #include "../inc/MarlinConfig.h" @@ -46,12 +45,14 @@ #if ENABLED(FILAMENT_MOTION_SENSOR) #define HAS_FILAMENT_MOTION 1 -#endif -#if DISABLED(FILAMENT_MOTION_SENSOR) || ENABLED(FILAMENT_SWITCH_AND_MOTION) + #if ENABLED(FILAMENT_SWITCH_AND_MOTION) + #define HAS_FILAMENT_SWITCH 1 + #endif +#else #define HAS_FILAMENT_SWITCH 1 #endif -#define FILAMENT_IS_OUT() (READ(FIL_RUNOUT_PIN) == FIL_RUNOUT_STATE) +#define FILAMENT_IS_OUT(N...) (READ(FIL_RUNOUT##N##_PIN) == FIL_RUNOUT##N##_STATE) typedef Flags< #if NUM_MOTION_SENSORS > NUM_RUNOUT_SENSORS @@ -62,7 +63,7 @@ typedef Flags< > runout_flags_t; void event_filament_runout(const uint8_t extruder); -inline bool should_monitor_runout() { return did_pause_print || printingIsActive(); } +inline bool should_monitor_runout() { return did_pause_print || marlin.printingIsActive(); } template class TFilamentMonitor; @@ -120,15 +121,18 @@ class TFilamentMonitor : public FilamentMonitorBase { static void filament_motion_present(const uint8_t extruder) { response.filament_motion_present(extruder); } + static float& motion_distance() { return response.motion_distance_mm; } + static void set_motion_distance(const float mm) { response.motion_distance_mm = mm; } #endif #if HAS_FILAMENT_RUNOUT_DISTANCE static float& runout_distance() { return response.runout_distance_mm; } - static void set_runout_distance(const_float_t mm) { response.runout_distance_mm = mm; } + static void set_runout_distance(const float mm) { response.runout_distance_mm = mm; } #endif // Handle a block completion. RunoutResponseDelayed uses this to // add up the length of filament moved while the filament is out. + // Called from ISR context! static void block_completed(const block_t * const b) { if (enabled) { response.block_completed(b); @@ -138,39 +142,44 @@ class TFilamentMonitor : public FilamentMonitorBase { // Give the response a chance to update its counter. static void run() { - if (enabled && !filament_ran_out && should_monitor_runout()) { - TERN_(HAS_FILAMENT_RUNOUT_DISTANCE, cli()); // Prevent RunoutResponseDelayed::block_completed from accumulating here - response.run(); - sensor.run(); - const runout_flags_t runout_flags = response.has_run_out(); - TERN_(HAS_FILAMENT_RUNOUT_DISTANCE, sei()); - #if MULTI_FILAMENT_SENSOR - #if ENABLED(WATCH_ALL_RUNOUT_SENSORS) - const bool ran_out = bool(runout_flags); // any sensor triggers - uint8_t extruder = 0; - if (ran_out) while (!runout_flags.test(extruder)) extruder++; - #else - const bool ran_out = runout_flags[active_extruder]; // suppress non active extruders - uint8_t extruder = active_extruder; - #endif + if (!enabled || filament_ran_out || !should_monitor_runout()) return; + TERN_(HAS_FILAMENT_RUNOUT_DISTANCE, cli()); // Prevent RunoutResponseDelayed::block_completed from accumulating here + response.run(); + sensor.run(); + const runout_flags_t runout_flags = response.has_run_out(); + TERN_(HAS_FILAMENT_RUNOUT_DISTANCE, sei()); + #if MULTI_FILAMENT_SENSOR + #if ENABLED(WATCH_ALL_RUNOUT_SENSORS) + const bool ran_out = bool(runout_flags); // any sensor triggers + uint8_t extruder = 0; + if (ran_out) while (!runout_flags.test(extruder)) extruder++; #else - const bool ran_out = bool(runout_flags); + const bool ran_out = runout_flags[active_extruder]; // suppress non active extruders uint8_t extruder = active_extruder; #endif + #else + const bool ran_out = bool(runout_flags); + uint8_t extruder = active_extruder; + #endif - if (ran_out) { - #if ENABLED(FILAMENT_RUNOUT_SENSOR_DEBUG) - SERIAL_ECHOPGM("Runout Sensors: "); - for (uint8_t i = 0; i < 8; ++i) SERIAL_CHAR('0' + char(runout_flags[i])); - SERIAL_ECHOLNPGM(" -> ", extruder, " RUN OUT"); - #endif + if (!ran_out) return; - filament_ran_out = true; - event_filament_runout(extruder); - planner.synchronize(); - } - } + #if ENABLED(FILAMENT_RUNOUT_SENSOR_DEBUG) + SERIAL_ECHOPGM("Runout Sensors: "); + for (uint8_t i = 0; i < 8; ++i) SERIAL_CHAR('0' + char(runout_flags[i])); + SERIAL_ECHOLNPGM(" -> ", extruder, " RUN OUT"); + #endif + + filament_ran_out = true; + event_filament_runout(extruder); + planner.synchronize(); } + + // Reset after a filament runout or upon resuming a job + static void init_for_restart(const bool onoff=true) { + response.init_for_restart(onoff); + } + }; /*************************** FILAMENT PRESENCE SENSORS ***************************/ @@ -267,6 +276,7 @@ class FilamentSensorBase { } public: + // Called from ISR context to indicate a block was completed static void block_completed(const block_t * const b) { // If the sensor wheel has moved since the last call to // this method reset the runout counter for the extruder. @@ -303,6 +313,7 @@ class FilamentSensorBase { } public: + // Called from ISR context to indicate a block was completed static void block_completed(const block_t * const) {} static void run() { @@ -332,6 +343,7 @@ class FilamentSensorBase { TERN_(HAS_FILAMENT_SWITCH, static FilamentSensorSwitch switch_sensor); public: + // Called from ISR context to indicate a block was completed static void block_completed(const block_t * const b) { TERN_(HAS_FILAMENT_MOTION, encoder_sensor.block_completed(b)); TERN_(HAS_FILAMENT_SWITCH, switch_sensor.block_completed(b)); @@ -362,40 +374,67 @@ class FilamentSensorBase { class RunoutResponseDelayed { private: static countdown_t mm_countdown; + #if ENABLED(FILAMENT_SWITCH_AND_MOTION) + static bool ignore_motion; // Flag to ignore the encoder + #endif public: static float runout_distance_mm; + #if ENABLED(FILAMENT_SWITCH_AND_MOTION) + static float motion_distance_mm; + #endif + + static void set_ignore_motion(const bool ignore=true) { + UNUSED(ignore); + TERN_(FILAMENT_SWITCH_AND_MOTION, ignore_motion = ignore); + } + static void reset() { for (uint8_t i = 0; i < NUM_RUNOUT_SENSORS; ++i) filament_present(i); #if ENABLED(FILAMENT_SWITCH_AND_MOTION) for (uint8_t i = 0; i < NUM_MOTION_SENSORS; ++i) filament_motion_present(i); #endif + set_ignore_motion(false); } static void run() { #if ENABLED(FILAMENT_RUNOUT_SENSOR_DEBUG) static millis_t t = 0; const millis_t ms = millis(); - if (ELAPSED(ms, t)) { - t = millis() + 1000UL; - for (uint8_t i = 0; i < NUM_RUNOUT_SENSORS; ++i) - SERIAL_ECHO(i ? F(", ") : F("Runout remaining mm: "), mm_countdown.runout[i]); - #if ENABLED(FILAMENT_SWITCH_AND_MOTION) - for (uint8_t i = 0; i < NUM_MOTION_SENSORS; ++i) - SERIAL_ECHO(i ? F(", ") : F("Motion remaining mm: "), mm_countdown.motion[i]); - #endif - SERIAL_EOL(); - } + if (PENDING(ms, t)) return; + t = ms + 1000UL; + for (uint8_t i = 0; i < NUM_RUNOUT_SENSORS; ++i) + SERIAL_ECHO(i ? F(", ") : F("Runout remaining mm: "), mm_countdown.runout[i]); + #if ENABLED(FILAMENT_SWITCH_AND_MOTION) + for (uint8_t i = 0; i < NUM_MOTION_SENSORS; ++i) + SERIAL_ECHO(i ? F(", ") : F("Motion remaining mm: "), mm_countdown.motion[i]); + #endif + SERIAL_EOL(); #endif } + // Get runout status for all presence sensors and motion sensors static runout_flags_t has_run_out() { runout_flags_t runout_flags{0}; - for (uint8_t i = 0; i < NUM_RUNOUT_SENSORS; ++i) if (mm_countdown.runout[i] < 0) runout_flags.set(i); + #if ENABLED(FILAMENT_SWITCH_AND_MOTION) - for (uint8_t i = 0; i < NUM_MOTION_SENSORS; ++i) if (mm_countdown.motion[i] < 0) runout_flags.set(i); + // Runout based on filament motion + if (!ignore_motion) { + for (uint8_t i = 0; i < NUM_MOTION_SENSORS; ++i) { + if (mm_countdown.motion[i] < 0) { + runout_flags.set(i); + mm_countdown.runout[i] = -1; // For a filament jam don't wait for runout_distance_mm! + } + } + } #endif + + // Runout based on filament presence + for (uint8_t i = 0; i < NUM_RUNOUT_SENSORS; ++i) + if (mm_countdown.runout[i] < 0) + runout_flags.set(i); + return runout_flags; } @@ -419,8 +458,8 @@ class FilamentSensorBase { #if ENABLED(FILAMENT_SWITCH_AND_MOTION) static void filament_motion_present(const uint8_t extruder) { // Same logic as filament_present - if (mm_countdown.motion[extruder] < runout_distance_mm || did_pause_print) { - mm_countdown.motion[extruder] = runout_distance_mm; + if (mm_countdown.motion[extruder] < motion_distance_mm || did_pause_print) { + mm_countdown.motion[extruder] = motion_distance_mm; mm_countdown.motion_reset.clear(extruder); } else @@ -428,29 +467,42 @@ class FilamentSensorBase { } #endif + // Called from ISR context to indicate a block was completed static void block_completed(const block_t * const b) { - const int32_t esteps = b->steps.e; - if (!esteps) return; - // No calculation unless paused or printing if (!should_monitor_runout()) return; + // Only extrusion moves are examined + const int32_t esteps = b->steps.e; + if (!esteps) return; + // No need to ignore retract/unretract movement since they complement each other const uint8_t e = b->extruder; const float mm = (b->direction_bits.e ? esteps : -esteps) * planner.mm_per_step[E_AXIS_N(e)]; + // Apply E distance to runout countdown, reset if flagged if (e < NUM_RUNOUT_SENSORS) { mm_countdown.runout[e] -= mm; if (mm_countdown.runout_reset[e]) filament_present(e); // Reset pending. Try to reset. } #if ENABLED(FILAMENT_SWITCH_AND_MOTION) - if (e < NUM_MOTION_SENSORS) { + // Apply E distance to motion countdown, reset if flagged + if (!ignore_motion && e < NUM_MOTION_SENSORS) { mm_countdown.motion[e] -= mm; if (mm_countdown.motion_reset[e]) filament_motion_present(e); // Reset pending. Try to reset. } #endif } + + // Reset after a filament runout or upon resuming a job + static void init_for_restart(const bool onoff=true) { + UNUSED(onoff); + #if ENABLED(FILAMENT_SWITCH_AND_MOTION) + reset(); // also calls set_ignore_motion(false) + set_ignore_motion(!onoff); + #endif + } }; #else // !HAS_FILAMENT_RUNOUT_DISTANCE @@ -478,11 +530,15 @@ class FilamentSensorBase { return runout_flags; } + // Called from ISR context to indicate a block was completed static void block_completed(const block_t * const) { } static void filament_present(const uint8_t extruder) { runout_count[extruder] = runout_threshold; } + + // Reset after a filament runout or upon resuming a job + static void init_for_restart(const bool=true) { reset(); } }; #endif // !HAS_FILAMENT_RUNOUT_DISTANCE diff --git a/Marlin/src/feature/spindle_laser.cpp b/Marlin/src/feature/spindle_laser.cpp index b83c1c1797..dd8d859bde 100644 --- a/Marlin/src/feature/spindle_laser.cpp +++ b/Marlin/src/feature/spindle_laser.cpp @@ -43,6 +43,10 @@ bool SpindleLaser::enable_state; // Virtual uint8_t SpindleLaser::power, // Actual power output 0-255 ocr or "0 = off" > 0 = "on" SpindleLaser::last_power_applied; // = 0 // Basic power state tracking +#if HAS_SPINDLE_ACCELERATION + uint32_t SpindleLaser::acceleration_spindle_deg_per_s2; // (°/s/s) Spindle acceleration. Initialized by settings.load +#endif + #if ENABLED(LASER_FEATURE) cutter_test_pulse_t SpindleLaser::testPulse = 50; // (ms) Test fire pulse default duration uint8_t SpindleLaser::last_block_power; // = 0 // Track power changes for dynamic inline power @@ -100,7 +104,22 @@ void SpindleLaser::init() { #if ENABLED(HAL_CAN_SET_PWM_FREQ) && SPINDLE_LASER_FREQUENCY hal.set_pwm_frequency(pin_t(SPINDLE_LASER_PWM_PIN), frequency); #endif - hal.set_pwm_duty(pin_t(SPINDLE_LASER_PWM_PIN), ocr ^ SPINDLE_LASER_PWM_OFF); + #if HAS_SPINDLE_ACCELERATION + const int16_t diff = ocr - last_power_applied; + const uint8_t abs_diff = ABS(diff); + uint8_t current_ocr = last_power_applied; + // Duration between ocr increments. SPEED_POWER_MAX is in RPM. + const millis_t duration = (float(SPEED_POWER_MAX) * (60000.f / 2550.f) / float(acceleration_spindle_deg_per_s2)) * abs_diff; + millis_t next_ocr_change = millis() + duration; + while (current_ocr != ocr) { + while (PENDING(millis(), next_ocr_change)) marlin.idle(); + current_ocr += diff > 0 ? 1 : -1; + hal.set_pwm_duty(pin_t(SPINDLE_LASER_PWM_PIN), current_ocr ^ SPINDLE_LASER_PWM_OFF); + next_ocr_change += duration; + } + #else + hal.set_pwm_duty(pin_t(SPINDLE_LASER_PWM_PIN), ocr ^ SPINDLE_LASER_PWM_OFF); + #endif } void SpindleLaser::set_ocr(const uint8_t ocr) { @@ -111,10 +130,10 @@ void SpindleLaser::init() { } void SpindleLaser::ocr_off() { + _set_ocr(0); #if PIN_EXISTS(SPINDLE_LASER_ENA) WRITE(SPINDLE_LASER_ENA_PIN, !SPINDLE_LASER_ACTIVE_STATE); // Cutter OFF #endif - _set_ocr(0); } #endif // SPINDLE_LASER_USE_PWM @@ -127,9 +146,8 @@ void SpindleLaser::init() { */ void SpindleLaser::apply_power(const uint8_t opwr) { if (enabled() || opwr == 0) { // 0 check allows us to disable where no ENA pin exists - // Test and set the last power used to improve performance + // Test the last power used to improve performance if (opwr == last_power_applied) return; - last_power_applied = opwr; // Handle PWM driven or just simple on/off #if ENABLED(SPINDLE_LASER_USE_PWM) if (CUTTER_UNIT_IS(RPM) && unitPower == 0) @@ -146,6 +164,7 @@ void SpindleLaser::apply_power(const uint8_t opwr) { WRITE(SPINDLE_LASER_ENA_PIN, enabled() ? SPINDLE_LASER_ACTIVE_STATE : !SPINDLE_LASER_ACTIVE_STATE); isReadyForUI = true; #endif + last_power_applied = opwr; } else { #if PIN_EXISTS(SPINDLE_LASER_ENA) diff --git a/Marlin/src/feature/spindle_laser.h b/Marlin/src/feature/spindle_laser.h index a443d7df5e..8305c1fec4 100644 --- a/Marlin/src/feature/spindle_laser.h +++ b/Marlin/src/feature/spindle_laser.h @@ -54,13 +54,13 @@ class SpindleLaser { public: static CutterMode cutter_mode; - static constexpr uint8_t pct_to_ocr(const_float_t pct) { return uint8_t(PCT_TO_PWM(pct)); } + static constexpr uint8_t pct_to_ocr(const float pct) { return uint8_t(PCT_TO_PWM(pct)); } // cpower = configured values (e.g., SPEED_POWER_MAX) // 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 @@ -109,11 +109,14 @@ public: static uint8_t power, last_power_applied; // Basic power state tracking - static cutter_frequency_t frequency; // Set PWM frequency; range: 2K-50K + static cutter_frequency_t frequency; // (Hz) Laser/Spindle PWM frequency (2000..50000) - static cutter_power_t menuPower, // Power as set via LCD menu in PWM, Percentage or RPM - unitPower; // Power as displayed status in PWM, Percentage or RPM + static cutter_power_t menuPower, // Power as set via LCD menu in PWM, Percentage, or RPM + unitPower; // Power as displayed status in PWM, Percentage, or RPM + #if HAS_SPINDLE_ACCELERATION + static uint32_t acceleration_spindle_deg_per_s2; // (°/s/s) Spindle acceleration + #endif static void init(); #if ENABLED(HAL_CAN_SET_PWM_FREQ) && SPINDLE_LASER_FREQUENCY @@ -161,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; diff --git a/Marlin/src/feature/stepper_driver_safety.cpp b/Marlin/src/feature/stepper_driver_safety.cpp index 3ddc05ea1e..acdd695909 100644 --- a/Marlin/src/feature/stepper_driver_safety.cpp +++ b/Marlin/src/feature/stepper_driver_safety.cpp @@ -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() { diff --git a/Marlin/src/feature/tmc_util.cpp b/Marlin/src/feature/tmc_util.cpp index 6afbf4a0ce..a91d435355 100644 --- a/Marlin/src/feature/tmc_util.cpp +++ b/Marlin/src/feature/tmc_util.cpp @@ -24,8 +24,13 @@ #if HAS_TRINAMIC_CONFIG +/** + * feature/tmc_util.cpp - Functions for debugging Trinamic stepper drivers. + * The main entry point is `tmc_report_all` which is called by M122 to collect + * and report diagnostic information about each enabled TMC driver. + */ + #include "tmc_util.h" -#include "../MarlinCore.h" #include "../module/stepper/indirection.h" #include "../module/printcounter.h" @@ -43,6 +48,10 @@ #endif #endif +#if ENABLED(EDITABLE_HOMING_CURRENT) + homing_current_t homing_current_mA; +#endif + /** * Check for over temperature or short to ground error flags. * Report and log warning of overtemperature condition. @@ -68,7 +77,7 @@ #endif ; #if ENABLED(TMC_DEBUG) - #if HAS_TMCX1X0 || HAS_TMC220x + #if HAS_TMCX1X0_OR_2240 || HAS_TMC220x uint8_t cs_actual; #endif #if HAS_STALLGUARD @@ -138,6 +147,67 @@ #endif // HAS_TMCX1X0 + #if HAS_DRIVER(TMC2240) + + #if ENABLED(TMC_DEBUG) + static uint32_t get_pwm_scale(TMC2240Stepper &st) { return st.PWM_SCALE(); } + #endif + + static TMC_driver_data get_driver_data(TMC2240Stepper &st) { + constexpr uint8_t OT_bp = 25, OTPW_bp = 26; + constexpr uint32_t S2G_bm = 0x18000000; + #if ENABLED(TMC_DEBUG) + constexpr uint16_t SG_RESULT_bm = 0x3FF; // 0:9 + constexpr uint8_t STEALTH_bp = 14; + constexpr uint32_t CS_ACTUAL_bm = 0x1F0000; // 16:20 + constexpr uint8_t STALL_GUARD_bp = 24; + constexpr uint8_t STST_bp = 31; + #endif + TMC_driver_data data; + const auto ds = data.drv_status = st.DRV_STATUS(); + #ifdef __AVR__ + + // 8-bit optimization saves up to 70 bytes of PROGMEM per axis + uint8_t spart; + #if ENABLED(TMC_DEBUG) + data.sg_result = ds & SG_RESULT_bm; + spart = ds >> 8; + data.is_stealth = TEST(spart, STEALTH_bp - 8); + spart = ds >> 16; + data.cs_actual = spart & (CS_ACTUAL_bm >> 16); + #endif + spart = ds >> 24; + data.is_ot = TEST(spart, OT_bp - 24); + data.is_otpw = TEST(spart, OTPW_bp - 24); + data.is_s2g = !!(spart & (S2G_bm >> 24)); + #if ENABLED(TMC_DEBUG) + data.is_stall = TEST(spart, STALL_GUARD_bp - 24); + data.is_standstill = TEST(spart, STST_bp - 24); + data.sg_result_reasonable = !data.is_standstill; // sg_result has no reasonable meaning while standstill + #endif + + #else // !__AVR__ + + data.is_ot = TEST(ds, OT_bp); + data.is_otpw = TEST(ds, OTPW_bp); + data.is_s2g = !!(ds & S2G_bm); + #if ENABLED(TMC_DEBUG) + constexpr uint8_t CS_ACTUAL_sb = 16; + data.sg_result = ds & SG_RESULT_bm; + data.is_stealth = TEST(ds, STEALTH_bp); + data.cs_actual = (ds & CS_ACTUAL_bm) >> CS_ACTUAL_sb; + data.is_stall = TEST(ds, STALL_GUARD_bp); + data.is_standstill = TEST(ds, STST_bp); + data.sg_result_reasonable = !data.is_standstill; // sg_result has no reasonable meaning while standstill + #endif + + #endif // !__AVR__ + + return data; + } + + #endif // TMC2240 + #if HAS_TMC220x #if ENABLED(TMC_DEBUG) @@ -212,7 +282,7 @@ if (data.is_s2g) SERIAL_ECHOLNPGM("coil short circuit"); TERN_(TMC_DEBUG, tmc_report_all()); TERN_(SOVOL_SV06_RTS, rts.gotoPage(ID_DriverError_L, ID_DriverError_D)); - kill(F("Driver error")); + marlin.kill(F("Driver error")); } #endif @@ -227,13 +297,14 @@ SString<50>(F(" driver overtemperature warning! ("), st.getMilliamps(), F("mA)")).echoln(); } - template - void report_polled_driver_data(TMC &st, const TMC_driver_data &data) { - const uint32_t pwm_scale = get_pwm_scale(st); - st.printLabel(); - SString<60> report(':', pwm_scale); - #if ENABLED(TMC_DEBUG) - #if HAS_TMCX1X0 || HAS_TMC220x + #if ENABLED(TMC_DEBUG) + + template + void report_polled_driver_data(TMC &st, const TMC_driver_data &data) { + const uint32_t pwm_scale = get_pwm_scale(st); + st.printLabel(); + SString<60> report(':', pwm_scale); + #if HAS_TMCX1X0_OR_2240 || HAS_TMC220x report.append('/', data.cs_actual); #endif #if HAS_STALLGUARD @@ -243,22 +314,21 @@ else report += '-'; #endif - #endif - report += '|'; - if (st.error_count) report += 'E'; // Error - if (data.is_ot) report += 'O'; // Over-temperature - if (data.is_otpw) report += 'W'; // over-temperature pre-Warning - #if ENABLED(TMC_DEBUG) + report += '|'; + if (st.error_count) report += 'E'; // Error + if (data.is_ot) report += 'O'; // Over-temperature + if (data.is_otpw) report += 'W'; // over-temperature pre-Warning if (data.is_stall) report += 'G'; // stallGuard if (data.is_stealth) report += 'T'; // stealthChop if (data.is_standstill) report += 'I'; // standstIll - #endif - if (st.flag_otpw) report += 'F'; // otpw Flag - report += '|'; - if (st.otpw_count > 0) report += st.otpw_count; - report += '\t'; - report.echo(); - } + if (st.flag_otpw) report += 'F'; // otpw Flag + report += '|'; + if (st.otpw_count > 0) report += st.otpw_count; + report += '\t'; + report.echo(); + } + + #endif // TMC_DEBUG #if CURRENT_STEP_DOWN > 0 @@ -318,9 +388,9 @@ else if (st.otpw_count > 0) st.otpw_count = 0; } - #if ENABLED(TMC_DEBUG) - if (need_debug_reporting) report_polled_driver_data(st, data); - #endif + if (need_debug_reporting) { + TERN_(TMC_DEBUG, report_polled_driver_data(st, data)); + } return should_step_down; } @@ -344,127 +414,70 @@ if (need_update_error_counters || need_debug_reporting) { - #if AXIS_IS_TMC(X) || AXIS_IS_TMC(X2) - { - bool result = false; - #if AXIS_IS_TMC(X) - if (monitor_tmc_driver(stepperX, need_update_error_counters, need_debug_reporting)) result = true; - #endif - #if AXIS_IS_TMC(X2) - if (monitor_tmc_driver(stepperX2, need_update_error_counters, need_debug_reporting)) result = true; - #endif - if (result) { - #if AXIS_IS_TMC(X) - step_current_down(stepperX); - #endif - #if AXIS_IS_TMC(X2) - step_current_down(stepperX2); - #endif + #if X_IS_TRINAMIC || X2_IS_TRINAMIC + if ( TERN0(X_IS_TRINAMIC, monitor_tmc_driver(stepperX, need_update_error_counters, need_debug_reporting)) + || TERN0(X2_IS_TRINAMIC, monitor_tmc_driver(stepperX2, need_update_error_counters, need_debug_reporting)) + ) { + TERN_(X_IS_TRINAMIC, step_current_down(stepperX)); + TERN_(X2_IS_TRINAMIC, step_current_down(stepperX2)); } - } #endif - #if AXIS_IS_TMC(Y) || AXIS_IS_TMC(Y2) - { - bool result = false; - #if AXIS_IS_TMC(Y) - if (monitor_tmc_driver(stepperY, need_update_error_counters, need_debug_reporting)) result = true; - #endif - #if AXIS_IS_TMC(Y2) - if (monitor_tmc_driver(stepperY2, need_update_error_counters, need_debug_reporting)) result = true; - #endif - if (result) { - #if AXIS_IS_TMC(Y) - step_current_down(stepperY); - #endif - #if AXIS_IS_TMC(Y2) - step_current_down(stepperY2); - #endif + #if Y_IS_TRINAMIC || Y2_IS_TRINAMIC + if ( TERN0(Y_IS_TRINAMIC, monitor_tmc_driver(stepperY, need_update_error_counters, need_debug_reporting)) + || TERN0(Y2_IS_TRINAMIC, monitor_tmc_driver(stepperY2, need_update_error_counters, need_debug_reporting)) + ) { + TERN_(Y_IS_TRINAMIC, step_current_down(stepperY)); + TERN_(Y2_IS_TRINAMIC, step_current_down(stepperY2)); } - } #endif - #if AXIS_IS_TMC(Z) || AXIS_IS_TMC(Z2) || AXIS_IS_TMC(Z3) || AXIS_IS_TMC(Z4) - { - bool result = false; - #if AXIS_IS_TMC(Z) - if (monitor_tmc_driver(stepperZ, need_update_error_counters, need_debug_reporting)) result = true; - #endif - #if AXIS_IS_TMC(Z2) - if (monitor_tmc_driver(stepperZ2, need_update_error_counters, need_debug_reporting)) result = true; - #endif - #if AXIS_IS_TMC(Z3) - if (monitor_tmc_driver(stepperZ3, need_update_error_counters, need_debug_reporting)) result = true; - #endif - #if AXIS_IS_TMC(Z4) - if (monitor_tmc_driver(stepperZ4, need_update_error_counters, need_debug_reporting)) result = true; - #endif - if (result) { - #if AXIS_IS_TMC(Z) - step_current_down(stepperZ); - #endif - #if AXIS_IS_TMC(Z2) - step_current_down(stepperZ2); - #endif - #if AXIS_IS_TMC(Z3) - step_current_down(stepperZ3); - #endif - #if AXIS_IS_TMC(Z4) - step_current_down(stepperZ4); - #endif + #if ANY(Z_IS_TRINAMIC, Z2_IS_TRINAMIC, Z3_IS_TRINAMIC, Z4_IS_TRINAMIC) + if ( TERN0(Z_IS_TRINAMIC, monitor_tmc_driver(stepperZ, need_update_error_counters, need_debug_reporting)) + || TERN0(Z2_IS_TRINAMIC, monitor_tmc_driver(stepperZ2, need_update_error_counters, need_debug_reporting)) + || TERN0(Z3_IS_TRINAMIC, monitor_tmc_driver(stepperZ3, need_update_error_counters, need_debug_reporting)) + || TERN0(Z4_IS_TRINAMIC, monitor_tmc_driver(stepperZ4, need_update_error_counters, need_debug_reporting)) + ) { + TERN_(Z_IS_TRINAMIC, step_current_down(stepperZ)); + TERN_(Z2_IS_TRINAMIC, step_current_down(stepperZ2)); + TERN_(Z3_IS_TRINAMIC, step_current_down(stepperZ3)); + TERN_(Z4_IS_TRINAMIC, step_current_down(stepperZ4)); } - } #endif - #if AXIS_IS_TMC(I) + #if I_IS_TRINAMIC if (monitor_tmc_driver(stepperI, need_update_error_counters, need_debug_reporting)) step_current_down(stepperI); #endif - #if AXIS_IS_TMC(J) + #if J_IS_TRINAMIC if (monitor_tmc_driver(stepperJ, need_update_error_counters, need_debug_reporting)) step_current_down(stepperJ); #endif - #if AXIS_IS_TMC(K) + #if K_IS_TRINAMIC if (monitor_tmc_driver(stepperK, need_update_error_counters, need_debug_reporting)) step_current_down(stepperK); #endif - #if AXIS_IS_TMC(U) + #if U_IS_TRINAMIC if (monitor_tmc_driver(stepperU, need_update_error_counters, need_debug_reporting)) step_current_down(stepperU); #endif - #if AXIS_IS_TMC(V) + #if V_IS_TRINAMIC if (monitor_tmc_driver(stepperV, need_update_error_counters, need_debug_reporting)) step_current_down(stepperV); #endif - #if AXIS_IS_TMC(W) + #if W_IS_TRINAMIC if (monitor_tmc_driver(stepperW, need_update_error_counters, need_debug_reporting)) step_current_down(stepperW); #endif - #if AXIS_IS_TMC(E0) - (void)monitor_tmc_driver(stepperE0, need_update_error_counters, need_debug_reporting); - #endif - #if AXIS_IS_TMC(E1) - (void)monitor_tmc_driver(stepperE1, need_update_error_counters, need_debug_reporting); - #endif - #if AXIS_IS_TMC(E2) - (void)monitor_tmc_driver(stepperE2, need_update_error_counters, need_debug_reporting); - #endif - #if AXIS_IS_TMC(E3) - (void)monitor_tmc_driver(stepperE3, need_update_error_counters, need_debug_reporting); - #endif - #if AXIS_IS_TMC(E4) - (void)monitor_tmc_driver(stepperE4, need_update_error_counters, need_debug_reporting); - #endif - #if AXIS_IS_TMC(E5) - (void)monitor_tmc_driver(stepperE5, need_update_error_counters, need_debug_reporting); - #endif - #if AXIS_IS_TMC(E6) - (void)monitor_tmc_driver(stepperE6, need_update_error_counters, need_debug_reporting); - #endif - #if AXIS_IS_TMC(E7) - (void)monitor_tmc_driver(stepperE7, need_update_error_counters, need_debug_reporting); - #endif + TERN_(E0_IS_TRINAMIC, (void)monitor_tmc_driver(stepperE0, need_update_error_counters, need_debug_reporting)); + TERN_(E1_IS_TRINAMIC, (void)monitor_tmc_driver(stepperE1, need_update_error_counters, need_debug_reporting)); + TERN_(E2_IS_TRINAMIC, (void)monitor_tmc_driver(stepperE2, need_update_error_counters, need_debug_reporting)); + TERN_(E3_IS_TRINAMIC, (void)monitor_tmc_driver(stepperE3, need_update_error_counters, need_debug_reporting)); + TERN_(E4_IS_TRINAMIC, (void)monitor_tmc_driver(stepperE4, need_update_error_counters, need_debug_reporting)); + TERN_(E5_IS_TRINAMIC, (void)monitor_tmc_driver(stepperE5, need_update_error_counters, need_debug_reporting)); + TERN_(E6_IS_TRINAMIC, (void)monitor_tmc_driver(stepperE6, need_update_error_counters, need_debug_reporting)); + TERN_(E7_IS_TRINAMIC, (void)monitor_tmc_driver(stepperE7, need_update_error_counters, need_debug_reporting)); if (TERN0(TMC_DEBUG, need_debug_reporting)) SERIAL_EOL(); } @@ -510,7 +523,7 @@ TMC_TSTEP, TMC_TPWMTHRS, TMC_TPWMTHRS_MMS, - TMC_OTPW, + TMC_DEBUG_OTPW, TMC_OTPW_TRIGGERED, TMC_TOFF, TMC_TBL, @@ -518,7 +531,12 @@ TMC_HSTRT, TMC_SGT, TMC_MSCNT, - TMC_INTERPOLATE + TMC_INTERPOLATE, + TMC_VAIN, + TMC_VSUPPLY, + TMC_TEMP, + TMC_OVERTEMP, + TMC_OVERVOLT_THD }; enum TMC_drv_status_enum : char { TMC_DRV_CODES, @@ -562,24 +580,49 @@ TMC_GET_DRVCTRL, TMC_GET_DRVSTATUS, TMC_GET_SGCSCONF, - TMC_GET_SMARTEN + TMC_GET_SMARTEN, + TMC_GET_SG4_THRS, + TMC_GET_SG4_RESULT }; template static void print_vsense(TMC &st) { SERIAL_ECHO(st.vsense() ? F("1=.18") : F("0=.325")); } + #if HAS_DRIVER(TMC2160) + template + void print_vsense(TMCMarlin &) { } + #endif + #if HAS_DRIVER(TMC5160) + template + void print_vsense(TMCMarlin &) { } + #endif + #if HAS_DRIVER(TMC2240) + template + void print_vsense(TMCMarlin &) { } + #endif + + template + void print_cs_actual(TMC &st) { SERIAL_ECHO(st.cs_actual(), F("/31")); } + #if HAS_DRIVER(TMC2240) + template + void print_cs_actual(TMCMarlin &) { } + #endif + + static void print_true_or_false(const bool tf) { SERIAL_ECHO(TRUE_FALSE(tf)); } #if HAS_DRIVER(TMC2130) || HAS_DRIVER(TMC5130) + // Additional tmc_status fields for 2130/5130 and related drivers static void _tmc_status(TMC2130Stepper &st, const TMC_debug_enum i) { switch (i) { case TMC_PWM_SCALE: SERIAL_ECHO(st.PWM_SCALE()); break; case TMC_SGT: SERIAL_ECHO(st.sgt()); break; - case TMC_STEALTHCHOP: serialprint_truefalse(st.en_pwm_mode()); break; - case TMC_INTERPOLATE: serialprint_truefalse(st.intpol()); break; + case TMC_STEALTHCHOP: print_true_or_false(st.en_pwm_mode()); break; + case TMC_INTERPOLATE: print_true_or_false(st.intpol()); break; default: break; } } #endif #if HAS_TMCX1X0 + // Additional tmc_parse_drv_status fields for 2130 and related drivers static void _tmc_parse_drv_status(TMC2130Stepper &st, const TMC_drv_status_enum i) { switch (i) { case TMC_STALLGUARD: if (st.stallguard()) SERIAL_CHAR('*'); break; @@ -592,25 +635,18 @@ #endif #if HAS_DRIVER(TMC2160) || HAS_DRIVER(TMC5160) - template - void print_vsense(TMCMarlin &) { } - - template - void print_vsense(TMCMarlin &) { } - + // Additional tmc_status fields for 2160/5160 and related drivers static void _tmc_status(TMC2160Stepper &st, const TMC_debug_enum i) { switch (i) { case TMC_PWM_SCALE: SERIAL_ECHO(st.PWM_SCALE()); break; case TMC_SGT: SERIAL_ECHO(st.sgt()); break; - case TMC_STEALTHCHOP: serialprint_truefalse(st.en_pwm_mode()); break; - case TMC_GLOBAL_SCALER: - { - const uint16_t value = st.GLOBAL_SCALER(); - SERIAL_ECHO(value ?: 256); - SERIAL_ECHOPGM("/256"); - } - break; - case TMC_INTERPOLATE: serialprint_truefalse(st.intpol()); break; + case TMC_STEALTHCHOP: print_true_or_false(st.en_pwm_mode()); break; + case TMC_GLOBAL_SCALER: { + const uint16_t value = st.GLOBAL_SCALER(); + SERIAL_ECHO(value ?: 256); + SERIAL_ECHOPGM("/256"); + } break; + case TMC_INTERPOLATE: print_true_or_false(st.intpol()); break; default: break; } } @@ -618,32 +654,37 @@ #if HAS_TMC220x + // Additional tmc_status fields for 2208/2224/2209 drivers static void _tmc_status(TMC2208Stepper &st, const TMC_debug_enum i) { switch (i) { + // PWM_SCALE case TMC_PWM_SCALE_SUM: SERIAL_ECHO(st.pwm_scale_sum()); break; case TMC_PWM_SCALE_AUTO: SERIAL_ECHO(st.pwm_scale_auto()); break; + // PWM_AUTO case TMC_PWM_OFS_AUTO: SERIAL_ECHO(st.pwm_ofs_auto()); break; case TMC_PWM_GRAD_AUTO: SERIAL_ECHO(st.pwm_grad_auto()); break; - case TMC_STEALTHCHOP: serialprint_truefalse(st.stealth()); break; - case TMC_INTERPOLATE: serialprint_truefalse(st.intpol()); break; + // CHOPCONF + case TMC_STEALTHCHOP: print_true_or_false(st.stealth()); break; + case TMC_INTERPOLATE: print_true_or_false(st.intpol()); break; default: break; } } #if HAS_DRIVER(TMC2209) + // Additional tmc_status fields for 2209 drivers template static void _tmc_status(TMCMarlin &st, const TMC_debug_enum i) { switch (i) { case TMC_SGT: SERIAL_ECHO(st.SGTHRS()); break; case TMC_UART_ADDR: SERIAL_ECHO(st.get_address()); break; default: - TMC2208Stepper *parent = &st; - _tmc_status(*parent, i); + _tmc_status(static_cast(st), i); break; } } #endif + // Additional tmc_parse_drv_status fields for 2208/2224/2209 drivers static void _tmc_parse_drv_status(TMC2208Stepper &st, const TMC_drv_status_enum i) { switch (i) { case TMC_T157: if (st.t157()) SERIAL_CHAR('*'); break; @@ -658,53 +699,99 @@ } #if HAS_DRIVER(TMC2209) + // Additional tmc_parse_drv_status fields for 2209 drivers static void _tmc_parse_drv_status(TMC2209Stepper &st, const TMC_drv_status_enum i) { switch (i) { case TMC_SG_RESULT: SERIAL_ECHO(st.SG_RESULT()); break; - default: _tmc_parse_drv_status(static_cast(st), i); break; + default: + _tmc_parse_drv_status(static_cast(st), i); + break; } } #endif #endif // HAS_TMC220x + #if HAS_DRIVER(TMC2240) + + // Additional tmc_parse_drv_status fields for 2240 drivers + static void _tmc_parse_drv_status(TMC2240Stepper &st, const TMC_drv_status_enum i) { + switch (i) { + case TMC_S2VSA: if (st.s2vsa()) SERIAL_CHAR('*'); break; + case TMC_S2VSB: if (st.s2vsb()) SERIAL_CHAR('*'); break; + case TMC_STEALTHCHOP: print_true_or_false(st.stealth()); break; + case TMC_FSACTIVE: if (st.fsactive()) SERIAL_CHAR('*'); break; + case TMC_DRV_CS_ACTUAL: if (st.CS_ACTUAL()) SERIAL_CHAR('*'); break; + case TMC_STALLGUARD: if (st.stallguard()) SERIAL_CHAR('*'); break; + case TMC_OT: if (st.ot()) SERIAL_CHAR('*'); break; + case TMC_SG_RESULT: SERIAL_ECHO(st.SG_RESULT()); break; + default: break; // other... + } + } + + // Additional tmc_status fields for 2240 drivers + static void _tmc_status(TMC2240Stepper &st, const TMC_debug_enum i) { + switch (i) { + // PWM_SCALE + case TMC_PWM_SCALE_SUM: SERIAL_ECHO(st.pwm_scale_sum()); break; + case TMC_PWM_SCALE_AUTO: SERIAL_ECHO(st.pwm_scale_auto()); break; + // PWM_AUTO + case TMC_PWM_OFS_AUTO: SERIAL_ECHO(st.pwm_ofs_auto()); break; + case TMC_PWM_GRAD_AUTO: SERIAL_ECHO(st.pwm_grad_auto()); break; + // CHOPCONF + case TMC_STEALTHCHOP: print_true_or_false(st.stealth()); break; + case TMC_INTERPOLATE: print_true_or_false(st.intpol()); break; + case TMC_VAIN: SERIAL_ECHO(st.get_ain_voltage()); break; + case TMC_VSUPPLY: SERIAL_ECHO(st.get_vsupply_voltage()); break; + case TMC_TEMP: SERIAL_ECHO(st.get_chip_temperature()); break; + case TMC_OVERTEMP: SERIAL_ECHO(st.get_overtemp_prewarn_celsius()); break; + case TMC_OVERVOLT_THD: SERIAL_ECHO(st.get_overvoltage_threshold_voltage()); break; + default: break; + } + } + + #endif // TMC2240 + #if HAS_DRIVER(TMC2660) static void _tmc_parse_drv_status(TMC2660Stepper, const TMC_drv_status_enum) { } static void _tmc_status(TMC2660Stepper &st, const TMC_debug_enum i) { switch (i) { - case TMC_INTERPOLATE: serialprint_truefalse(st.intpol()); break; + case TMC_INTERPOLATE: print_true_or_false(st.intpol()); break; default: break; } } #endif + template + void print_tstep(TMC &st) { + const uint32_t tstep_value = st.TSTEP(); + if (tstep_value != 0xFFFFF) + SERIAL_ECHO(tstep_value); + else + SERIAL_ECHOPGM("max"); + } + void print_tstep(TMC2660Stepper &st) { } + + template + void print_blank_time(TMC &st) { SERIAL_ECHO(st.blank_time()); } + template + void print_blank_time(TMCMarlin &) { } + template static void tmc_status(TMC &st, const TMC_debug_enum i) { SERIAL_CHAR('\t'); switch (i) { case TMC_CODES: st.printLabel(); break; - case TMC_ENABLED: serialprint_truefalse(st.isEnabled()); break; + case TMC_ENABLED: print_true_or_false(st.isEnabled()); break; case TMC_CURRENT: SERIAL_ECHO(st.getMilliamps()); break; case TMC_RMS_CURRENT: SERIAL_ECHO(st.rms_current()); break; case TMC_MAX_CURRENT: SERIAL_ECHO(p_float_t(st.rms_current() * 1.41, 0)); break; - case TMC_IRUN: - SERIAL_ECHO(st.irun()); - SERIAL_ECHOPGM("/31"); - break; - case TMC_IHOLD: - SERIAL_ECHO(st.ihold()); - SERIAL_ECHOPGM("/31"); - break; - case TMC_CS_ACTUAL: - SERIAL_ECHO(st.cs_actual()); - SERIAL_ECHOPGM("/31"); - break; + case TMC_IRUN: SERIAL_ECHO(st.irun()); SERIAL_ECHOPGM("/31"); break; + case TMC_IHOLD: SERIAL_ECHO(st.ihold()); SERIAL_ECHOPGM("/31"); break; + case TMC_CS_ACTUAL: print_cs_actual(st); break; case TMC_VSENSE: print_vsense(st); break; case TMC_MICROSTEPS: SERIAL_ECHO(st.microsteps()); break; - case TMC_TSTEP: { - const uint32_t tstep_value = st.TSTEP(); - if (tstep_value != 0xFFFFF) SERIAL_ECHO(tstep_value); else SERIAL_ECHOPGM("max"); - } break; + case TMC_TSTEP: print_tstep(st); break; #if ENABLED(HYBRID_THRESHOLD) case TMC_TPWMTHRS: SERIAL_ECHO(uint32_t(st.TPWMTHRS())); break; case TMC_TPWMTHRS_MMS: { @@ -712,12 +799,12 @@ if (tpwmthrs_val) SERIAL_ECHO(tpwmthrs_val); else SERIAL_CHAR('-'); } break; #endif - case TMC_OTPW: serialprint_truefalse(st.otpw()); break; + case TMC_DEBUG_OTPW: print_true_or_false(st.otpw()); break; #if ENABLED(MONITOR_DRIVER_STATUS) - case TMC_OTPW_TRIGGERED: serialprint_truefalse(st.getOTPW()); break; + case TMC_OTPW_TRIGGERED: print_true_or_false(st.getOTPW()); break; #endif case TMC_TOFF: SERIAL_ECHO(st.toff()); break; - case TMC_TBL: SERIAL_ECHO(st.blank_time()); break; + case TMC_TBL: print_blank_time(st); break; case TMC_HEND: SERIAL_ECHO(st.hysteresis_end()); break; case TMC_HSTRT: SERIAL_ECHO(st.hysteresis_start()); break; case TMC_MSCNT: SERIAL_ECHO(st.get_microstep_counter()); break; @@ -731,132 +818,82 @@ SERIAL_CHAR('\t'); switch (i) { case TMC_CODES: st.printLabel(); break; - case TMC_ENABLED: serialprint_truefalse(st.isEnabled()); break; + case TMC_ENABLED: print_true_or_false(st.isEnabled()); break; case TMC_CURRENT: SERIAL_ECHO(st.getMilliamps()); break; case TMC_RMS_CURRENT: SERIAL_ECHO(st.rms_current()); break; case TMC_MAX_CURRENT: SERIAL_ECHO(p_float_t(st.rms_current() * 1.41, 0)); break; - case TMC_IRUN: - SERIAL_ECHO(st.cs()); - SERIAL_ECHOPGM("/31"); - break; + case TMC_IRUN: SERIAL_ECHO(st.cs()); SERIAL_ECHOPGM("/31"); break; case TMC_VSENSE: SERIAL_ECHO(st.vsense() ? F("1=.165") : F("0=.310")); break; case TMC_MICROSTEPS: SERIAL_ECHO(st.microsteps()); break; - //case TMC_OTPW: serialprint_truefalse(st.otpw()); break; - //case TMC_OTPW_TRIGGERED: serialprint_truefalse(st.getOTPW()); break; + //case TMC_DEBUG_OTPW: print_true_or_false(st.otpw()); break; + //case TMC_OTPW_TRIGGERED: print_true_or_false(st.getOTPW()); break; case TMC_SGT: SERIAL_ECHO(st.sgt()); break; case TMC_TOFF: SERIAL_ECHO(st.toff()); break; - case TMC_TBL: SERIAL_ECHO(st.blank_time()); break; + case TMC_TBL: print_blank_time(st); break; case TMC_HEND: SERIAL_ECHO(st.hysteresis_end()); break; case TMC_HSTRT: SERIAL_ECHO(st.hysteresis_start()); break; - default: break; + default: _tmc_status(st, i); break; } } - #endif + #endif // TMC2660 template static void tmc_parse_drv_status(TMC &st, const TMC_drv_status_enum i) { SERIAL_CHAR('\t'); switch (i) { - case TMC_DRV_CODES: st.printLabel(); break; - case TMC_STST: if (!st.stst()) SERIAL_CHAR('*'); break; - case TMC_OLB: if (st.olb()) SERIAL_CHAR('*'); break; - case TMC_OLA: if (st.ola()) SERIAL_CHAR('*'); break; - case TMC_S2GB: if (st.s2gb()) SERIAL_CHAR('*'); break; - case TMC_S2GA: if (st.s2ga()) SERIAL_CHAR('*'); break; - case TMC_DRV_OTPW: if (st.otpw()) SERIAL_CHAR('*'); break; - case TMC_OT: if (st.ot()) SERIAL_CHAR('*'); break; + case TMC_DRV_CODES: st.printLabel(); break; + case TMC_STST: if (!st.stst()) SERIAL_CHAR('*'); break; + case TMC_OLB: if (st.olb()) SERIAL_CHAR('*'); break; + case TMC_OLA: if (st.ola()) SERIAL_CHAR('*'); break; + case TMC_S2GB: if (st.s2gb()) SERIAL_CHAR('*'); break; + case TMC_S2GA: if (st.s2ga()) SERIAL_CHAR('*'); break; + case TMC_DRV_OTPW: if (st.otpw()) SERIAL_CHAR('*'); break; + case TMC_OT: if (st.ot()) SERIAL_CHAR('*'); break; case TMC_DRV_STATUS_HEX: { const uint32_t drv_status = st.DRV_STATUS(); - SERIAL_CHAR('\t'); - st.printLabel(); - SERIAL_CHAR('\t'); - print_hex_long(drv_status, ':', true); + SERIAL_CHAR('\t'); st.printLabel(); + SERIAL_CHAR('\t'); print_hex_long(drv_status, ':', true); if (drv_status == 0xFFFFFFFF || drv_status == 0) SERIAL_ECHOPGM("\t Bad response!"); SERIAL_EOL(); - break; - } + } break; default: _tmc_parse_drv_status(st, i); break; } } static void tmc_debug_loop(const TMC_debug_enum n OPTARGS_LOGICAL(const bool)) { if (TERN0(HAS_X_AXIS, x)) { - #if AXIS_IS_TMC(X) - tmc_status(stepperX, n); - #endif - #if AXIS_IS_TMC(X2) - tmc_status(stepperX2, n); - #endif + TERN_(X_IS_TRINAMIC, tmc_status(stepperX, n)); + TERN_(X2_IS_TRINAMIC, tmc_status(stepperX2, n)); } if (TERN0(HAS_Y_AXIS, y)) { - #if AXIS_IS_TMC(Y) - tmc_status(stepperY, n); - #endif - #if AXIS_IS_TMC(Y2) - tmc_status(stepperY2, n); - #endif + TERN_(Y_IS_TRINAMIC, tmc_status(stepperY, n)); + TERN_(Y2_IS_TRINAMIC, tmc_status(stepperY2, n)); } if (TERN0(HAS_Z_AXIS, z)) { - #if AXIS_IS_TMC(Z) - tmc_status(stepperZ, n); - #endif - #if AXIS_IS_TMC(Z2) - tmc_status(stepperZ2, n); - #endif - #if AXIS_IS_TMC(Z3) - tmc_status(stepperZ3, n); - #endif - #if AXIS_IS_TMC(Z4) - tmc_status(stepperZ4, n); - #endif + TERN_(Z_IS_TRINAMIC, tmc_status(stepperZ, n)); + TERN_(Z2_IS_TRINAMIC, tmc_status(stepperZ2, n)); + TERN_(Z3_IS_TRINAMIC, tmc_status(stepperZ3, n)); + TERN_(Z4_IS_TRINAMIC, tmc_status(stepperZ4, n)); } - #if AXIS_IS_TMC(I) - if (i) tmc_status(stepperI, n); - #endif - #if AXIS_IS_TMC(J) - if (j) tmc_status(stepperJ, n); - #endif - #if AXIS_IS_TMC(K) - if (k) tmc_status(stepperK, n); - #endif - #if AXIS_IS_TMC(U) - if (u) tmc_status(stepperU, n); - #endif - #if AXIS_IS_TMC(V) - if (v) tmc_status(stepperV, n); - #endif - #if AXIS_IS_TMC(W) - if (w) tmc_status(stepperW, n); - #endif + TERN_(I_IS_TRINAMIC, if (i) tmc_status(stepperI, n)); + TERN_(J_IS_TRINAMIC, if (j) tmc_status(stepperJ, n)); + TERN_(K_IS_TRINAMIC, if (k) tmc_status(stepperK, n)); + TERN_(U_IS_TRINAMIC, if (u) tmc_status(stepperU, n)); + TERN_(V_IS_TRINAMIC, if (v) tmc_status(stepperV, n)); + TERN_(W_IS_TRINAMIC, if (w) tmc_status(stepperW, n)); if (TERN0(HAS_EXTRUDERS, e)) { - #if AXIS_IS_TMC(E0) - tmc_status(stepperE0, n); - #endif - #if AXIS_IS_TMC(E1) - tmc_status(stepperE1, n); - #endif - #if AXIS_IS_TMC(E2) - tmc_status(stepperE2, n); - #endif - #if AXIS_IS_TMC(E3) - tmc_status(stepperE3, n); - #endif - #if AXIS_IS_TMC(E4) - tmc_status(stepperE4, n); - #endif - #if AXIS_IS_TMC(E5) - tmc_status(stepperE5, n); - #endif - #if AXIS_IS_TMC(E6) - tmc_status(stepperE6, n); - #endif - #if AXIS_IS_TMC(E7) - tmc_status(stepperE7, n); - #endif + TERN_(E0_IS_TRINAMIC, tmc_status(stepperE0, n)); + TERN_(E1_IS_TRINAMIC, tmc_status(stepperE1, n)); + TERN_(E2_IS_TRINAMIC, tmc_status(stepperE2, n)); + TERN_(E3_IS_TRINAMIC, tmc_status(stepperE3, n)); + TERN_(E4_IS_TRINAMIC, tmc_status(stepperE4, n)); + TERN_(E5_IS_TRINAMIC, tmc_status(stepperE5, n)); + TERN_(E6_IS_TRINAMIC, tmc_status(stepperE6, n)); + TERN_(E7_IS_TRINAMIC, tmc_status(stepperE7, n)); } SERIAL_EOL(); @@ -864,82 +901,38 @@ static void drv_status_loop(const TMC_drv_status_enum n OPTARGS_LOGICAL(const bool)) { if (TERN0(HAS_X_AXIS, x)) { - #if AXIS_IS_TMC(X) - tmc_parse_drv_status(stepperX, n); - #endif - #if AXIS_IS_TMC(X2) - tmc_parse_drv_status(stepperX2, n); - #endif + TERN_(X_IS_TRINAMIC, tmc_parse_drv_status(stepperX, n)); + TERN_(X2_IS_TRINAMIC, tmc_parse_drv_status(stepperX2, n)); } if (TERN0(HAS_Y_AXIS, y)) { - #if AXIS_IS_TMC(Y) - tmc_parse_drv_status(stepperY, n); - #endif - #if AXIS_IS_TMC(Y2) - tmc_parse_drv_status(stepperY2, n); - #endif + TERN_(Y_IS_TRINAMIC, tmc_parse_drv_status(stepperY, n)); + TERN_(Y2_IS_TRINAMIC, tmc_parse_drv_status(stepperY2, n)); } if (TERN0(HAS_Z_AXIS, z)) { - #if AXIS_IS_TMC(Z) - tmc_parse_drv_status(stepperZ, n); - #endif - #if AXIS_IS_TMC(Z2) - tmc_parse_drv_status(stepperZ2, n); - #endif - #if AXIS_IS_TMC(Z3) - tmc_parse_drv_status(stepperZ3, n); - #endif - #if AXIS_IS_TMC(Z4) - tmc_parse_drv_status(stepperZ4, n); - #endif + TERN_(Z_IS_TRINAMIC, tmc_parse_drv_status(stepperZ, n)); + TERN_(Z2_IS_TRINAMIC, tmc_parse_drv_status(stepperZ2, n)); + TERN_(Z3_IS_TRINAMIC, tmc_parse_drv_status(stepperZ3, n)); + TERN_(Z4_IS_TRINAMIC, tmc_parse_drv_status(stepperZ4, n)); } - #if AXIS_IS_TMC(I) - if (i) tmc_parse_drv_status(stepperI, n); - #endif - #if AXIS_IS_TMC(J) - if (j) tmc_parse_drv_status(stepperJ, n); - #endif - #if AXIS_IS_TMC(K) - if (k) tmc_parse_drv_status(stepperK, n); - #endif - #if AXIS_IS_TMC(U) - if (u) tmc_parse_drv_status(stepperU, n); - #endif - #if AXIS_IS_TMC(V) - if (v) tmc_parse_drv_status(stepperV, n); - #endif - #if AXIS_IS_TMC(W) - if (w) tmc_parse_drv_status(stepperW, n); - #endif + TERN_(I_IS_TRINAMIC, if (i) tmc_parse_drv_status(stepperI, n)); + TERN_(J_IS_TRINAMIC, if (j) tmc_parse_drv_status(stepperJ, n)); + TERN_(K_IS_TRINAMIC, if (k) tmc_parse_drv_status(stepperK, n)); + TERN_(U_IS_TRINAMIC, if (u) tmc_parse_drv_status(stepperU, n)); + TERN_(V_IS_TRINAMIC, if (v) tmc_parse_drv_status(stepperV, n)); + TERN_(W_IS_TRINAMIC, if (w) tmc_parse_drv_status(stepperW, n)); if (TERN0(HAS_EXTRUDERS, e)) { - #if AXIS_IS_TMC(E0) - tmc_parse_drv_status(stepperE0, n); - #endif - #if AXIS_IS_TMC(E1) - tmc_parse_drv_status(stepperE1, n); - #endif - #if AXIS_IS_TMC(E2) - tmc_parse_drv_status(stepperE2, n); - #endif - #if AXIS_IS_TMC(E3) - tmc_parse_drv_status(stepperE3, n); - #endif - #if AXIS_IS_TMC(E4) - tmc_parse_drv_status(stepperE4, n); - #endif - #if AXIS_IS_TMC(E5) - tmc_parse_drv_status(stepperE5, n); - #endif - #if AXIS_IS_TMC(E6) - tmc_parse_drv_status(stepperE6, n); - #endif - #if AXIS_IS_TMC(E7) - tmc_parse_drv_status(stepperE7, n); - #endif + TERN_(E0_IS_TRINAMIC, tmc_parse_drv_status(stepperE0, n)); + TERN_(E1_IS_TRINAMIC, tmc_parse_drv_status(stepperE1, n)); + TERN_(E2_IS_TRINAMIC, tmc_parse_drv_status(stepperE2, n)); + TERN_(E3_IS_TRINAMIC, tmc_parse_drv_status(stepperE3, n)); + TERN_(E4_IS_TRINAMIC, tmc_parse_drv_status(stepperE4, n)); + TERN_(E5_IS_TRINAMIC, tmc_parse_drv_status(stepperE5, n)); + TERN_(E6_IS_TRINAMIC, tmc_parse_drv_status(stepperE6, n)); + TERN_(E7_IS_TRINAMIC, tmc_parse_drv_status(stepperE7, n)); } SERIAL_EOL(); @@ -977,16 +970,16 @@ TMC_REPORT("tstep\t", TMC_TSTEP); TMC_REPORT("PWM thresh.", TMC_TPWMTHRS); TMC_REPORT("[mm/s]\t", TMC_TPWMTHRS_MMS); - TMC_REPORT("OT prewarn", TMC_OTPW); + 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); @@ -995,11 +988,12 @@ TMC_REPORT(" -start\t", TMC_HSTRT); TMC_REPORT("Stallguard thrs", TMC_SGT); TMC_REPORT("uStep count", TMC_MSCNT); + DRV_REPORT("DRVSTATUS", TMC_DRV_CODES); - #if HAS_TMCX1X0 || HAS_TMC220x + #if HAS_TMCX1X0_OR_2240 || HAS_TMC220x DRV_REPORT("sg_result", TMC_SG_RESULT); #endif - #if HAS_TMCX1X0 + #if HAS_TMCX1X0_OR_2240 DRV_REPORT("stallguard", TMC_STALLGUARD); DRV_REPORT("fsactive", TMC_FSACTIVE); #endif @@ -1015,30 +1009,40 @@ DRV_REPORT("150C\t", TMC_T150); DRV_REPORT("143C\t", TMC_T143); DRV_REPORT("120C\t", TMC_T120); + #endif + #if HAS_TMC220x || HAS_DRIVER(TMC2240) DRV_REPORT("s2vsa\t", TMC_S2VSA); DRV_REPORT("s2vsb\t", TMC_S2VSB); #endif - DRV_REPORT("Driver registers:\n",TMC_DRV_STATUS_HEX); + DRV_REPORT("Driver registers:\n", TMC_DRV_STATUS_HEX); + #if HAS_DRIVER(TMC2240) + TMC_REPORT("Analog in (v)", TMC_VAIN); + TMC_REPORT("Supply (v)", TMC_VSUPPLY); + TMC_REPORT("Temp (°C)", TMC_TEMP); + TMC_REPORT("OT pre warn (°C)", TMC_OVERTEMP); + TMC_REPORT("OV threshold (v)", TMC_OVERVOLT_THD); + #endif SERIAL_EOL(); } #define PRINT_TMC_REGISTER(REG_CASE) case TMC_GET_##REG_CASE: print_hex_long(st.REG_CASE(), ':'); break - #if HAS_TMCX1X0 - static void tmc_get_ic_registers(TMC2130Stepper &st, const TMC_get_registers_enum i) { - switch (i) { - PRINT_TMC_REGISTER(TCOOLTHRS); - PRINT_TMC_REGISTER(THIGH); - PRINT_TMC_REGISTER(COOLCONF); - default: SERIAL_CHAR('\t'); break; - } - } - #endif - #if HAS_TMC220x - static void tmc_get_ic_registers(TMC2208Stepper, const TMC_get_registers_enum) { SERIAL_CHAR('\t'); } - #endif - #if HAS_TRINAMIC_CONFIG + + template + static void tmc_get_ic_registers(TMC &, const TMC_get_registers_enum) { SERIAL_CHAR('\t'); } + + #if HAS_TMCX1X0 + static void tmc_get_ic_registers(TMC2130Stepper &st, const TMC_get_registers_enum i) { + switch (i) { + PRINT_TMC_REGISTER(TCOOLTHRS); + PRINT_TMC_REGISTER(THIGH); + PRINT_TMC_REGISTER(COOLCONF); + default: SERIAL_CHAR('\t'); break; + } + } + #endif + template static void tmc_get_registers(TMC &st, const TMC_get_registers_enum i) { switch (i) { @@ -1058,7 +1062,9 @@ } SERIAL_CHAR('\t'); } - #endif + + #endif // HAS_TRINAMIC_CONFIG + #if HAS_DRIVER(TMC2660) template static void tmc_get_registers(TMCMarlin &st, const TMC_get_registers_enum i) { @@ -1078,82 +1084,38 @@ static void tmc_get_registers(TMC_get_registers_enum n OPTARGS_LOGICAL(const bool)) { if (TERN0(HAS_X_AXIS, x)) { - #if AXIS_IS_TMC(X) - tmc_get_registers(stepperX, n); - #endif - #if AXIS_IS_TMC(X2) - tmc_get_registers(stepperX2, n); - #endif + TERN_(X_IS_TRINAMIC, tmc_get_registers(stepperX, n)); + TERN_(X2_IS_TRINAMIC, tmc_get_registers(stepperX2, n)); } if (TERN0(HAS_Y_AXIS, y)) { - #if AXIS_IS_TMC(Y) - tmc_get_registers(stepperY, n); - #endif - #if AXIS_IS_TMC(Y2) - tmc_get_registers(stepperY2, n); - #endif + TERN_(Y_IS_TRINAMIC, tmc_get_registers(stepperY, n)); + TERN_(Y2_IS_TRINAMIC, tmc_get_registers(stepperY2, n)); } if (TERN0(HAS_Z_AXIS, z)) { - #if AXIS_IS_TMC(Z) - tmc_get_registers(stepperZ, n); - #endif - #if AXIS_IS_TMC(Z2) - tmc_get_registers(stepperZ2, n); - #endif - #if AXIS_IS_TMC(Z3) - tmc_get_registers(stepperZ3, n); - #endif - #if AXIS_IS_TMC(Z4) - tmc_get_registers(stepperZ4, n); - #endif + TERN_(Z_IS_TRINAMIC, tmc_get_registers(stepperZ, n)); + TERN_(Z2_IS_TRINAMIC, tmc_get_registers(stepperZ2, n)); + TERN_(Z3_IS_TRINAMIC, tmc_get_registers(stepperZ3, n)); + TERN_(Z4_IS_TRINAMIC, tmc_get_registers(stepperZ4, n)); } - #if AXIS_IS_TMC(I) - if (i) tmc_get_registers(stepperI, n); - #endif - #if AXIS_IS_TMC(J) - if (j) tmc_get_registers(stepperJ, n); - #endif - #if AXIS_IS_TMC(K) - if (k) tmc_get_registers(stepperK, n); - #endif - #if AXIS_IS_TMC(U) - if (u) tmc_get_registers(stepperU, n); - #endif - #if AXIS_IS_TMC(V) - if (v) tmc_get_registers(stepperV, n); - #endif - #if AXIS_IS_TMC(W) - if (w) tmc_get_registers(stepperW, n); - #endif + TERN_(I_IS_TRINAMIC, if (i) tmc_get_registers(stepperI, n)); + TERN_(J_IS_TRINAMIC, if (j) tmc_get_registers(stepperJ, n)); + TERN_(K_IS_TRINAMIC, if (k) tmc_get_registers(stepperK, n)); + TERN_(U_IS_TRINAMIC, if (u) tmc_get_registers(stepperU, n)); + TERN_(V_IS_TRINAMIC, if (v) tmc_get_registers(stepperV, n)); + TERN_(W_IS_TRINAMIC, if (w) tmc_get_registers(stepperW, n)); if (TERN0(HAS_EXTRUDERS, e)) { - #if AXIS_IS_TMC(E0) - tmc_get_registers(stepperE0, n); - #endif - #if AXIS_IS_TMC(E1) - tmc_get_registers(stepperE1, n); - #endif - #if AXIS_IS_TMC(E2) - tmc_get_registers(stepperE2, n); - #endif - #if AXIS_IS_TMC(E3) - tmc_get_registers(stepperE3, n); - #endif - #if AXIS_IS_TMC(E4) - tmc_get_registers(stepperE4, n); - #endif - #if AXIS_IS_TMC(E5) - tmc_get_registers(stepperE5, n); - #endif - #if AXIS_IS_TMC(E6) - tmc_get_registers(stepperE6, n); - #endif - #if AXIS_IS_TMC(E7) - tmc_get_registers(stepperE7, n); - #endif + TERN_(E0_IS_TRINAMIC, tmc_get_registers(stepperE0, n)); + TERN_(E1_IS_TRINAMIC, tmc_get_registers(stepperE1, n)); + TERN_(E2_IS_TRINAMIC, tmc_get_registers(stepperE2, n)); + TERN_(E3_IS_TRINAMIC, tmc_get_registers(stepperE3, n)); + TERN_(E4_IS_TRINAMIC, tmc_get_registers(stepperE4, n)); + TERN_(E5_IS_TRINAMIC, tmc_get_registers(stepperE5, n)); + TERN_(E6_IS_TRINAMIC, tmc_get_registers(stepperE6, n)); + TERN_(E7_IS_TRINAMIC, tmc_get_registers(stepperE7, n)); } SERIAL_EOL(); @@ -1210,11 +1172,29 @@ st.TCOOLTHRS(0); } + bool tmc_enable_stallguard(TMC2240Stepper &st) { + const bool stealthchop_was_enabled = st.en_pwm_mode(); + + // TODO: Use StallGuard4 when stealthChop is enabled + // and leave stealthChop state unchanged. + + st.TCOOLTHRS(0xFFFFF); + st.en_pwm_mode(false); + st.diag0_stall(true); + + return stealthchop_was_enabled; + } + void tmc_disable_stallguard(TMC2240Stepper &st, const bool restore_stealth) { + st.TCOOLTHRS(0); + st.en_pwm_mode(restore_stealth); + st.diag0_stall(false); + } + bool tmc_enable_stallguard(TMC2660Stepper) { // TODO return false; } - void tmc_disable_stallguard(TMC2660Stepper, const bool) {}; + void tmc_disable_stallguard(TMC2660Stepper, const bool) { } #endif // USE_SENSORLESS @@ -1243,157 +1223,41 @@ void test_tmc_connection(LOGICAL_AXIS_ARGS_LC(const bool)) { uint8_t axis_connection = 0; if (TERN0(HAS_X_AXIS, x)) { - #if AXIS_IS_TMC(X) - axis_connection += test_connection(stepperX); - #endif - #if AXIS_IS_TMC(X2) - axis_connection += test_connection(stepperX2); - #endif + TERN_(X_IS_TRINAMIC, axis_connection += test_connection(stepperX)); + TERN_(X2_IS_TRINAMIC, axis_connection += test_connection(stepperX2)); } if (TERN0(HAS_Y_AXIS, y)) { - #if AXIS_IS_TMC(Y) - axis_connection += test_connection(stepperY); - #endif - #if AXIS_IS_TMC(Y2) - axis_connection += test_connection(stepperY2); - #endif + TERN_(Y_IS_TRINAMIC, axis_connection += test_connection(stepperY)); + TERN_(Y2_IS_TRINAMIC, axis_connection += test_connection(stepperY2)); } if (TERN0(HAS_Z_AXIS, z)) { - #if AXIS_IS_TMC(Z) - axis_connection += test_connection(stepperZ); - #endif - #if AXIS_IS_TMC(Z2) - axis_connection += test_connection(stepperZ2); - #endif - #if AXIS_IS_TMC(Z3) - axis_connection += test_connection(stepperZ3); - #endif - #if AXIS_IS_TMC(Z4) - axis_connection += test_connection(stepperZ4); - #endif + TERN_(Z_IS_TRINAMIC, axis_connection += test_connection(stepperZ)); + TERN_(Z2_IS_TRINAMIC, axis_connection += test_connection(stepperZ2)); + TERN_(Z3_IS_TRINAMIC, axis_connection += test_connection(stepperZ3)); + TERN_(Z4_IS_TRINAMIC, axis_connection += test_connection(stepperZ4)); } - #if AXIS_IS_TMC(I) - if (i) axis_connection += test_connection(stepperI); - #endif - #if AXIS_IS_TMC(J) - if (j) axis_connection += test_connection(stepperJ); - #endif - #if AXIS_IS_TMC(K) - if (k) axis_connection += test_connection(stepperK); - #endif - #if AXIS_IS_TMC(U) - if (u) axis_connection += test_connection(stepperU); - #endif - #if AXIS_IS_TMC(V) - if (v) axis_connection += test_connection(stepperV); - #endif - #if AXIS_IS_TMC(W) - if (w) axis_connection += test_connection(stepperW); - #endif + TERN_(I_IS_TRINAMIC, if (i) axis_connection += test_connection(stepperI)); + TERN_(J_IS_TRINAMIC, if (j) axis_connection += test_connection(stepperJ)); + TERN_(K_IS_TRINAMIC, if (k) axis_connection += test_connection(stepperK)); + TERN_(U_IS_TRINAMIC, if (u) axis_connection += test_connection(stepperU)); + TERN_(V_IS_TRINAMIC, if (v) axis_connection += test_connection(stepperV)); + TERN_(W_IS_TRINAMIC, if (w) axis_connection += test_connection(stepperW)); if (TERN0(HAS_EXTRUDERS, e)) { - #if AXIS_IS_TMC(E0) - axis_connection += test_connection(stepperE0); - #endif - #if AXIS_IS_TMC(E1) - axis_connection += test_connection(stepperE1); - #endif - #if AXIS_IS_TMC(E2) - axis_connection += test_connection(stepperE2); - #endif - #if AXIS_IS_TMC(E3) - axis_connection += test_connection(stepperE3); - #endif - #if AXIS_IS_TMC(E4) - axis_connection += test_connection(stepperE4); - #endif - #if AXIS_IS_TMC(E5) - axis_connection += test_connection(stepperE5); - #endif - #if AXIS_IS_TMC(E6) - axis_connection += test_connection(stepperE6); - #endif - #if AXIS_IS_TMC(E7) - axis_connection += test_connection(stepperE7); - #endif + TERN_(E0_IS_TRINAMIC, axis_connection += test_connection(stepperE0)); + TERN_(E1_IS_TRINAMIC, axis_connection += test_connection(stepperE1)); + TERN_(E2_IS_TRINAMIC, axis_connection += test_connection(stepperE2)); + TERN_(E3_IS_TRINAMIC, axis_connection += test_connection(stepperE3)); + TERN_(E4_IS_TRINAMIC, axis_connection += test_connection(stepperE4)); + TERN_(E5_IS_TRINAMIC, axis_connection += test_connection(stepperE5)); + TERN_(E6_IS_TRINAMIC, axis_connection += test_connection(stepperE6)); + TERN_(E7_IS_TRINAMIC, axis_connection += test_connection(stepperE7)); } if (axis_connection) LCD_MESSAGE(MSG_ERROR_TMC); } #endif // HAS_TRINAMIC_CONFIG - -#if HAS_TMC_SPI - #define SET_CS_PIN(st) OUT_WRITE(st##_CS_PIN, HIGH) - void tmc_init_cs_pins() { - #if AXIS_HAS_SPI(X) - SET_CS_PIN(X); - #endif - #if AXIS_HAS_SPI(Y) - SET_CS_PIN(Y); - #endif - #if AXIS_HAS_SPI(Z) - SET_CS_PIN(Z); - #endif - #if AXIS_HAS_SPI(X2) - SET_CS_PIN(X2); - #endif - #if AXIS_HAS_SPI(Y2) - SET_CS_PIN(Y2); - #endif - #if AXIS_HAS_SPI(Z2) - SET_CS_PIN(Z2); - #endif - #if AXIS_HAS_SPI(Z3) - SET_CS_PIN(Z3); - #endif - #if AXIS_HAS_SPI(Z4) - SET_CS_PIN(Z4); - #endif - #if AXIS_HAS_SPI(I) - SET_CS_PIN(I); - #endif - #if AXIS_HAS_SPI(J) - SET_CS_PIN(J); - #endif - #if AXIS_HAS_SPI(K) - SET_CS_PIN(K); - #endif - #if AXIS_HAS_SPI(U) - SET_CS_PIN(U); - #endif - #if AXIS_HAS_SPI(V) - SET_CS_PIN(V); - #endif - #if AXIS_HAS_SPI(W) - SET_CS_PIN(W); - #endif - #if AXIS_HAS_SPI(E0) - SET_CS_PIN(E0); - #endif - #if AXIS_HAS_SPI(E1) - SET_CS_PIN(E1); - #endif - #if AXIS_HAS_SPI(E2) - SET_CS_PIN(E2); - #endif - #if AXIS_HAS_SPI(E3) - SET_CS_PIN(E3); - #endif - #if AXIS_HAS_SPI(E4) - SET_CS_PIN(E4); - #endif - #if AXIS_HAS_SPI(E5) - SET_CS_PIN(E5); - #endif - #if AXIS_HAS_SPI(E6) - SET_CS_PIN(E6); - #endif - #if AXIS_HAS_SPI(E7) - SET_CS_PIN(E7); - #endif - } -#endif // HAS_TMC_SPI diff --git a/Marlin/src/feature/tmc_util.h b/Marlin/src/feature/tmc_util.h index 27aae23f89..556035f08c 100644 --- a/Marlin/src/feature/tmc_util.h +++ b/Marlin/src/feature/tmc_util.h @@ -95,7 +95,7 @@ class TMCMarlin : public TMC, public TMCStorage { TMC(CS, RS, pinMOSI, pinMISO, pinSCK) {} TMCMarlin(const uint16_t CS, const float RS, const uint16_t pinMOSI, const uint16_t pinMISO, const uint16_t pinSCK, const uint8_t axis_chain_index) : - TMC(CS, RS, pinMOSI, pinMISO, pinSCK, axis_chain_index) + TMC(CS, RS, pinMOSI, pinMISO, pinSCK, axis_chain_index) {} uint16_t rms_current() { return TMC::rms_current(); } void rms_current(uint16_t mA) { @@ -124,7 +124,7 @@ class TMCMarlin : public TMC, public TMCStorage { #if ENABLED(HYBRID_THRESHOLD) uint32_t get_pwm_thrs() { - return _tmc_thrs(this->microsteps(), this->TPWMTHRS(), planner.settings.axis_steps_per_mm[AXIS_ID]); + return _tmc_thrs(this->microsteps(), TMC::TPWMTHRS(), planner.settings.axis_steps_per_mm[AXIS_ID]); } void set_pwm_thrs(const uint32_t thrs) { TMC::TPWMTHRS(_tmc_thrs(this->microsteps(), thrs, planner.settings.axis_steps_per_mm[AXIS_ID])); @@ -197,7 +197,7 @@ class TMCMarlin : public TMC220 #if ENABLED(HYBRID_THRESHOLD) uint32_t get_pwm_thrs() { - return _tmc_thrs(this->microsteps(), this->TPWMTHRS(), planner.settings.axis_steps_per_mm[AXIS_ID]); + return _tmc_thrs(this->microsteps(), TMC2208Stepper::TPWMTHRS(), planner.settings.axis_steps_per_mm[AXIS_ID]); } void set_pwm_thrs(const uint32_t thrs) { TMC2208Stepper::TPWMTHRS(_tmc_thrs(this->microsteps(), thrs, planner.settings.axis_steps_per_mm[AXIS_ID])); @@ -249,13 +249,14 @@ class TMCMarlin : public TMC220 #if ENABLED(HYBRID_THRESHOLD) uint32_t get_pwm_thrs() { - return _tmc_thrs(this->microsteps(), this->TPWMTHRS(), planner.settings.axis_steps_per_mm[AXIS_ID]); + return _tmc_thrs(this->microsteps(), TMC2209Stepper::TPWMTHRS(), planner.settings.axis_steps_per_mm[AXIS_ID]); } void set_pwm_thrs(const uint32_t thrs) { TMC2209Stepper::TPWMTHRS(_tmc_thrs(this->microsteps(), thrs, planner.settings.axis_steps_per_mm[AXIS_ID])); TERN_(HAS_MARLINUI_MENU, this->stored.hybrid_thrs = thrs); } #endif + #if USE_SENSORLESS int16_t homing_threshold() { return TMC2209Stepper::SGTHRS(); } void homing_threshold(int16_t sgt_val) { @@ -278,6 +279,74 @@ class TMCMarlin : public TMC220 sgt_max = 255; }; +template +class TMCMarlin : public TMC2240Stepper, public TMCStorage { + public: + TMCMarlin(const uint16_t cs_pin, const uint8_t axis_chain_index) : + TMC2240Stepper(cs_pin, axis_chain_index) + {} + TMCMarlin(const uint16_t CS, const uint16_t pinMOSI, const uint16_t pinMISO, const uint16_t pinSCK, const uint8_t axis_chain_index) : + TMC2240Stepper(CS, pinMOSI, pinMISO, pinSCK, axis_chain_index ) + {} + + //uint8_t get_address() { return slave_address; } + uint16_t get_microstep_counter() { return microsteps(); } + + uint16_t rms_current() { return TMC2240Stepper::rms_current(); } + void rms_current(const uint16_t mA) { + this->val_mA = mA; + TMC2240Stepper::rms_current(mA); + } + void rms_current(const uint16_t mA, const float mult) { + this->val_mA = mA; + TMC2240Stepper::rms_current(mA, mult); + } + + #if HAS_STEALTHCHOP + bool get_stealthChop() { return this->en_pwm_mode(); } + bool get_stored_stealthChop() { return this->stored.stealthChop_enabled; } + void refresh_stepping_mode() { this->en_pwm_mode(this->stored.stealthChop_enabled); } + void set_stealthChop(const bool stch) { this->stored.stealthChop_enabled = stch; refresh_stepping_mode(); } + bool toggle_stepping_mode() { set_stealthChop(!this->stored.stealthChop_enabled); return get_stealthChop(); } + #endif + + void set_chopper_times(const chopper_timing_t &ct) { + TMC2240Stepper::toff(ct.toff); + TMC2240Stepper::hysteresis_end(ct.hend); + TMC2240Stepper::hysteresis_start(ct.hstrt); + } + + #if ENABLED(HYBRID_THRESHOLD) + uint32_t get_pwm_thrs() { + return _tmc_thrs(this->microsteps(), TMC2240Stepper::TPWMTHRS(), planner.settings.axis_steps_per_mm[AXIS_ID]); + } + void set_pwm_thrs(const uint32_t thrs) { + TMC2240Stepper::TPWMTHRS(_tmc_thrs(this->microsteps(), thrs, planner.settings.axis_steps_per_mm[AXIS_ID])); + TERN_(HAS_MARLINUI_MENU, this->stored.hybrid_thrs = thrs); + } + #endif + + #if USE_SENSORLESS + int16_t homing_threshold() { return TMC2240Stepper::sgt(); } + void homing_threshold(int16_t sgt_val) { + sgt_val = (int16_t)constrain(sgt_val, sgt_min, sgt_max); + TMC2240Stepper::sgt(sgt_val); + TERN_(HAS_MARLINUI_MENU, this->stored.homing_thrs = sgt_val); + } + #endif + + void refresh_stepper_current() { rms_current(this->val_mA); } + #if ENABLED(HYBRID_THRESHOLD) + void refresh_hybrid_thrs() { set_pwm_thrs(this->stored.hybrid_thrs); } + #endif + #if USE_SENSORLESS + void refresh_homing_thrs() { homing_threshold(this->stored.homing_thrs); } + #endif + + static constexpr int8_t sgt_min = -64, + sgt_max = 63; +}; + template class TMCMarlin : public TMC2660Stepper, public TMCStorage { public: @@ -353,6 +422,9 @@ void test_tmc_connection(LOGICAL_AXIS_DECL_LC(const bool, true)); bool tmc_enable_stallguard(TMC2209Stepper &st); void tmc_disable_stallguard(TMC2209Stepper &st, const bool restore_stealth); + bool tmc_enable_stallguard(TMC2240Stepper &st); + void tmc_disable_stallguard(TMC2240Stepper &st, const bool restore_stealth); + bool tmc_enable_stallguard(TMC2660Stepper); void tmc_disable_stallguard(TMC2660Stepper, const bool); @@ -362,7 +434,7 @@ void test_tmc_connection(LOGICAL_AXIS_DECL_LC(const bool, true)); bool TMCMarlin::test_stall_status() { this->switchCSpin(LOW); - // read stallGuard flag from TMC library, will handle HW and SW SPI + // Read stallGuard flag from TMC library, will handle HW and SW SPI TMC2130_n::DRV_STATUS_t drv_status{0}; drv_status.sr = this->DRV_STATUS(); @@ -375,8 +447,30 @@ void test_tmc_connection(LOGICAL_AXIS_DECL_LC(const bool, true)); #endif // USE_SENSORLESS -#endif // HAS_TRINAMIC_CONFIG +#if HAS_HOMING_CURRENT -#if HAS_TMC_SPI - void tmc_init_cs_pins(); -#endif + // Axes that have a distinct homing current + struct homing_current_t { + OPTCODE(X_HAS_HOME_CURRENT, uint16_t X) + OPTCODE(Y_HAS_HOME_CURRENT, uint16_t Y) + OPTCODE(Z_HAS_HOME_CURRENT, uint16_t Z) + OPTCODE(X2_HAS_HOME_CURRENT, uint16_t X2) + OPTCODE(Y2_HAS_HOME_CURRENT, uint16_t Y2) + OPTCODE(Z2_HAS_HOME_CURRENT, uint16_t Z2) + OPTCODE(Z3_HAS_HOME_CURRENT, uint16_t Z3) + OPTCODE(Z4_HAS_HOME_CURRENT, uint16_t Z4) + OPTCODE(I_HAS_HOME_CURRENT, uint16_t I) + OPTCODE(J_HAS_HOME_CURRENT, uint16_t J) + OPTCODE(K_HAS_HOME_CURRENT, uint16_t K) + OPTCODE(U_HAS_HOME_CURRENT, uint16_t U) + OPTCODE(V_HAS_HOME_CURRENT, uint16_t V) + OPTCODE(W_HAS_HOME_CURRENT, uint16_t W) + }; + + #if ENABLED(EDITABLE_HOMING_CURRENT) + extern homing_current_t homing_current_mA; + #endif + +#endif // HAS_HOMING_CURRENT + +#endif // HAS_TRINAMIC_CONFIG diff --git a/Marlin/src/feature/twibus.h b/Marlin/src/feature/twibus.h index de23abbed5..b438d10a33 100644 --- a/Marlin/src/feature/twibus.h +++ b/Marlin/src/feature/twibus.h @@ -64,7 +64,7 @@ class TWIBus { private: /** * @brief Number of bytes on buffer - * @description Number of bytes in the buffer waiting to be flushed to the bus + * @details Number of bytes in the buffer waiting to be flushed to the bus */ uint8_t buffer_s = 0; @@ -77,7 +77,7 @@ class TWIBus { public: /** * @brief Target device address - * @description The target device address. Persists until changed. + * @details The target device address. Persists until changed. */ uint8_t addr = 0; diff --git a/Marlin/src/feature/x_twist.cpp b/Marlin/src/feature/x_twist.cpp index 2b7924707e..6b155c49ab 100644 --- a/Marlin/src/feature/x_twist.cpp +++ b/Marlin/src/feature/x_twist.cpp @@ -53,7 +53,7 @@ void XATC::print_points() { SERIAL_EOL(); } -float lerp(const_float_t t, const_float_t a, const_float_t b) { return a + t * (b - a); } +float lerp(const float t, const float a, const float b) { return a + t * (b - a); } float XATC::compensation(const xy_pos_t &raw) { if (!enabled) return 0; diff --git a/Marlin/src/gcode/bedlevel/G26.cpp b/Marlin/src/gcode/bedlevel/G26.cpp index 8c26ca4e8f..899498faae 100644 --- a/Marlin/src/gcode/bedlevel/G26.cpp +++ b/Marlin/src/gcode/bedlevel/G26.cpp @@ -105,7 +105,6 @@ #include "../gcode.h" #include "../../feature/bedlevel/bedlevel.h" -#include "../../MarlinCore.h" #include "../../module/planner.h" #include "../../module/motion.h" #include "../../module/tool_change.h" @@ -170,7 +169,7 @@ float g26_random_deviation = 0.0; #endif -void move_to(const_float_t rx, const_float_t ry, const_float_t z, const_float_t e_delta) { +void move_to(const float rx, const float ry, const float z, const float e_delta) { static float last_z = -999.99; const xy_pos_t dest = { rx, ry }; @@ -196,7 +195,7 @@ void move_to(const_float_t rx, const_float_t ry, const_float_t z, const_float_t prepare_internal_move_to_destination(fr_mm_s); } -void move_to(const xyz_pos_t &where, const_float_t de) { move_to(where.x, where.y, where.z, de); } +void move_to(const xyz_pos_t &where, const float de) { move_to(where.x, where.y, where.z, de); } typedef struct { float extrusion_multiplier = EXTRUSION_MULTIPLIER, @@ -268,8 +267,10 @@ typedef struct { // If the end point of the line is closer to the nozzle, flip the direction, // moving from the end to the start. On very small lines the optimization isn't worth it. - if (dist_end < dist_start && (INTERSECTION_CIRCLE_RADIUS) < ABS(line_length)) - return print_line_from_here_to_there(e, s); + if (dist_end < dist_start && (INTERSECTION_CIRCLE_RADIUS) < ABS(line_length)) { + print_line_from_here_to_there(e, s); + return; + } // Decide whether to retract & lift if (dist_start > 2.0) retract_lift_move(s); @@ -661,7 +662,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(); @@ -854,7 +855,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 diff --git a/Marlin/src/gcode/bedlevel/G42.cpp b/Marlin/src/gcode/bedlevel/G42.cpp index 44f5ceada8..4b9b028419 100644 --- a/Marlin/src/gcode/bedlevel/G42.cpp +++ b/Marlin/src/gcode/bedlevel/G42.cpp @@ -25,7 +25,6 @@ #if HAS_MESH #include "../gcode.h" -#include "../../MarlinCore.h" // for IsRunning() #include "../../module/motion.h" #include "../../feature/bedlevel/bedlevel.h" diff --git a/Marlin/src/gcode/bedlevel/M420.cpp b/Marlin/src/gcode/bedlevel/M420.cpp index 8711bab9c8..05fa98e459 100644 --- a/Marlin/src/gcode/bedlevel/M420.cpp +++ b/Marlin/src/gcode/bedlevel/M420.cpp @@ -45,14 +45,14 @@ /** * M420: Enable/Disable Bed Leveling and/or set the Z fade height. * - * S[bool] Turns leveling on or off - * Z[height] Sets the Z fade height (0 or none to disable) - * V[bool] Verbose - Print the leveling grid + * S Turns leveling on or off + * Z Sets the Z fade height (0 or none to disable) + * V Verbose - Print the leveling grid * * With AUTO_BED_LEVELING_UBL only: * - * L[index] Load UBL mesh from index (0 is default) - * T[map] 0:Human-readable 1:CSV 2:"LCD" 4:Compact + * L Load UBL mesh from index (0 is default) + * T 0:Human-readable 1:CSV 2:"LCD" 4:Compact * * With mesh-based leveling only: * @@ -228,9 +228,7 @@ void GcodeSuite::M420() { if (to_enable && !planner.leveling_active) SERIAL_ERROR_MSG(STR_ERR_M420_FAILED); - SERIAL_ECHO_START(); - SERIAL_ECHOPGM("Bed Leveling "); - serialprintln_onoff(planner.leveling_active); + SERIAL_ECHO_MSG("Bed Leveling ", ON_OFF(planner.leveling_active)); #if ENABLED(ENABLE_LEVELING_FADE_HEIGHT) SERIAL_ECHO_START(); @@ -252,14 +250,13 @@ void GcodeSuite::M420_report(const bool forReplay/*=true*/) { report_heading_etc(forReplay, F( TERN(MESH_BED_LEVELING, "Mesh Bed Leveling", TERN(AUTO_BED_LEVELING_UBL, "Unified Bed Leveling", "Auto Bed Leveling")) )); - SERIAL_ECHO( + SERIAL_ECHOLN( F(" M420 S"), planner.leveling_active #if ENABLED(ENABLE_LEVELING_FADE_HEIGHT) , FPSTR(SP_Z_STR), LINEAR_UNIT(planner.z_fade_height) #endif - , F(" ; Leveling ") + , F(" ; Leveling "), ON_OFF(planner.leveling_active) ); - serialprintln_onoff(planner.leveling_active); } #endif // HAS_LEVELING diff --git a/Marlin/src/gcode/bedlevel/abl/G29.cpp b/Marlin/src/gcode/bedlevel/abl/G29.cpp index 3b922dd54f..800d51dac6 100644 --- a/Marlin/src/gcode/bedlevel/abl/G29.cpp +++ b/Marlin/src/gcode/bedlevel/abl/G29.cpp @@ -51,7 +51,7 @@ #if ENABLED(EXTENSIBLE_UI) #include "../../../lcd/extui/ui_api.h" #elif ENABLED(DWIN_CREALITY_LCD) - #include "../../../lcd/e3v2/creality/dwin.h" + #include "../../../lcd/dwin/creality/dwin.h" #elif ENABLED(SOVOL_SV06_RTS) #include "../../../lcd/sovol_rts/sovol_rts.h" #endif @@ -59,6 +59,10 @@ #define DEBUG_OUT ENABLED(DEBUG_LEVELING_FEATURE) #include "../../../core/debug_out.h" +#if DISABLED(PROBE_MANUALLY) && ENABLED(FT_MOTION) + #include "../../../module/ft_motion.h" +#endif + #if ABL_USES_GRID #if ENABLED(PROBE_Y_FIRST) #define PR_OUTER_VAR abl.meshCount.x @@ -152,81 +156,72 @@ public: #endif /** - * G29: Detailed Z probe, probes the bed at 3 or more points. - * Will fail if the printer has not been homed with G28. + * G29: Bed Leveling * - * Enhanced G29 Auto Bed Leveling Probe Routine + * Enhanced G29 Auto Bed Leveling Probe Routine. + * Probes the bed at 3 or more points. + * Will fail if the printer has not been homed with G28. * - * O Auto-level only if needed + * Parameters: + * O Auto-level only if needed (Optional) * - * D Dry-Run mode. Just evaluate the bed Topology - Don't apply - * or alter the bed level data. Useful to check the topology - * after a first run of G29. + * D Dry-Run mode. Just evaluate the bed Topology - + * Don't apply or alter the bed level data. + * Useful to check the topology after a first run of G29. * - * J Jettison current bed leveling data + * J Jettison current bed leveling data * - * V Set the verbose level (0-4). Example: "G29 V3" + * V<0-4> Set the verbose level (0-4) + * Example: G29 V3 * - * Parameters With LINEAR leveling only: + * With AUTO_BED_LEVELING_LINEAR: + * P Set the size of the grid that will be probed (P x P points) + * Example: G29 P4 * - * P Set the size of the grid that will be probed (P x P points). - * Example: "G29 P4" + * X Set the X size of the grid that will be probed (X x Y points) + * Example: G29 X7 Y5 * - * X Set the X size of the grid that will be probed (X x Y points). - * Example: "G29 X7 Y5" + * Y Set the Y size of the grid that will be probed (X x Y points) * - * Y Set the Y size of the grid that will be probed (X x Y points). + * T Generate a Bed Topology Report + * Example: G29 P5 T - for a detailed report. + * This is useful for manual bed leveling and finding flaws in the bed + * (to assist with part placement). + * Not supported by non-linear delta printer bed leveling. * - * T Generate a Bed Topology Report. Example: "G29 P5 T" for a detailed report. - * This is useful for manual bed leveling and finding flaws in the bed (to - * assist with part placement). - * Not supported by non-linear delta printer bed leveling. + * With AUTO_BED_LEVELING_LINEAR and AUTO_BED_LEVELING_BILINEAR: + * S Set the XY travel speed between probe points (in units/min) + * H Set bounds to a centered square H x H units in size + * -or- + * F Set the Front limit of the probing grid + * B Set the Back limit of the probing grid + * L Set the Left limit of the probing grid + * R Set the Right limit of the probing grid * - * Parameters With LINEAR and BILINEAR leveling only: + * With AUTO_BED_LEVELING_BILINEAR: + * Z Supply additional Z offset to all probe points. + * W Write a mesh point. (If G29 is idle.) + * I Index for mesh point + * J Index for mesh point + * X For mesh point, overrides I + * Y For mesh point, overrides J + * Z For mesh point. If omitted, uses current position's raw Z * - * S Set the XY travel speed between probe points (in units/min) + * With DEBUG_LEVELING_FEATURE: + * C Make a totally fake grid with no actual probing. + * For use in testing when no probing is possible. * - * H Set bounds to a centered square H x H units in size + * With PROBE_MANUALLY: + * To do manual probing simply repeat G29 until the procedure is complete. + * The first G29 accepts parameters. 'G29 Q' for status, 'G29 A' to abort. * - * -or- + * Q Query leveling and G29 state + * A Abort current leveling procedure * - * F Set the Front limit of the probing grid - * B Set the Back limit of the probing grid - * L Set the Left limit of the probing grid - * R Set the Right limit of the probing grid - * - * Parameters with DEBUG_LEVELING_FEATURE only: - * - * C Make a totally fake grid with no actual probing. - * For use in testing when no probing is possible. - * - * Parameters with BILINEAR leveling only: - * - * Z Supply an additional Z probe offset - * - * Extra parameters with PROBE_MANUALLY: - * - * To do manual probing simply repeat G29 until the procedure is complete. - * The first G29 accepts parameters. 'G29 Q' for status, 'G29 A' to abort. - * - * Q Query leveling and G29 state - * - * A Abort current leveling procedure - * - * Extra parameters with BILINEAR only: - * - * W Write a mesh point. (If G29 is idle.) - * I X index for mesh point - * J Y index for mesh point - * X X for mesh point, overrides I - * Y Y for mesh point, overrides J - * Z Z for mesh point. Otherwise, raw current Z. - * - * Without PROBE_MANUALLY: - * - * E By default G29 will engage the Z probe, test the bed, then disengage. - * Include "E" to engage/disengage the Z probe for each sample. - * There's no extra effect if you have a fixed Z probe. + * Without PROBE_MANUALLY: + * E By default G29 will engage the Z probe, test the bed, then disengage + * Include "E" to engage/disengage the Z probe for each sample. + * There's no extra effect if you have a fixed Z probe. */ G29_TYPE GcodeSuite::G29() { @@ -280,6 +275,11 @@ 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) + // Potentially disable Fixed-Time Motion for probing + TERN_(FT_MOTION, FTM_DISABLE_IN_SCOPE()); + #endif + /** * On the initial G29 fetch command parameters. */ @@ -287,6 +287,11 @@ G29_TYPE GcodeSuite::G29() { probe.use_probing_tool(); + #ifdef EVENT_GCODE_BEFORE_G29 + if (DEBUGGING(LEVELING)) DEBUG_ECHOLNPGM("Before G29 G-code: ", EVENT_GCODE_BEFORE_G29); + gcode.process_subcommands_now(F(EVENT_GCODE_BEFORE_G29)); + #endif + #if ANY(PROBE_MANUALLY, AUTO_BED_LEVELING_LINEAR) abl.abl_probe_index = -1; #endif @@ -687,7 +692,7 @@ G29_TYPE GcodeSuite::G29() { inInc = -1; // Zag left } - zig ^= true; // zag + FLIP(zig); // zag // An index to print current state grid_count_t pt_index = (PR_OUTER_VAR) * (PR_INNER_SIZE) + 1; @@ -704,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) { @@ -754,7 +759,7 @@ G29_TYPE GcodeSuite::G29() { for (;;) { pos = planner.get_axis_position_mm(axis); if (inInc > 0 ? (pos >= cmp) : (pos <= cmp)) break; - idle_no_sleep(); + marlin.idle_no_sleep(); } //if (DEBUGGING(LEVELING)) DEBUG_ECHOLNPGM_P(axis == Y_AXIS ? PSTR("Y=") : PSTR("X=", pos); @@ -798,7 +803,7 @@ G29_TYPE GcodeSuite::G29() { #endif abl.reenable = false; // Don't re-enable after modifying the mesh - idle_no_sleep(); + marlin.idle_no_sleep(); } // inner } // outer @@ -809,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]); @@ -842,15 +847,15 @@ G29_TYPE GcodeSuite::G29() { } #endif // !PROBE_MANUALLY - // - // G29 Finishing Code - // - // Unless this is a dry run, auto bed leveling will - // definitely be enabled after this point. - // - // If code above wants to continue leveling, it should - // return or loop before this point. - // + /** + * G29 Finishing Code + * + * Unless this is a dry run, auto bed leveling will + * definitely be enabled after this point. + * + * If code above wants to continue leveling, it should + * return or loop before this point. + */ if (DEBUGGING(LEVELING)) DEBUG_POS("> probing complete", current_position); @@ -879,12 +884,12 @@ G29_TYPE GcodeSuite::G29() { // For LINEAR leveling calculate matrix, print reports, correct the position /** - * solve the plane equation ax + by + d = z + * Solve the plane equation ax + by + d = z * A is the matrix with rows [x y 1] for all the probed points * B is the vector of the Z positions - * the normal vector to the plane is formed by the coefficients of the + * The normal vector to the plane is formed by the coefficients of the * plane equation in the standard form, which is Vx*x+Vy*y+Vz*z+d = 0 - * so Vx = -a Vy = -b Vz = 1 (we want the vector facing towards positive Z + * so Vx = -a Vy = -b Vz = 1 (we want the vector facing towards positive Z). */ struct { float a, b, d; } plane_equation_coefficients; @@ -1007,7 +1012,7 @@ G29_TYPE GcodeSuite::G29() { TERN_(HAS_BED_PROBE, probe.move_z_after_probing()); #ifdef EVENT_GCODE_AFTER_G29 - if (DEBUGGING(LEVELING)) DEBUG_ECHOLNPGM("Z Probe End Script: ", EVENT_GCODE_AFTER_G29); + if (DEBUGGING(LEVELING)) DEBUG_ECHOLNPGM("After G29 G-code: ", EVENT_GCODE_AFTER_G29); planner.synchronize(); process_subcommands_now(F(EVENT_GCODE_AFTER_G29)); #endif diff --git a/Marlin/src/gcode/bedlevel/mbl/G29.cpp b/Marlin/src/gcode/bedlevel/mbl/G29.cpp index 6d23de4f77..a08ecc327d 100644 --- a/Marlin/src/gcode/bedlevel/mbl/G29.cpp +++ b/Marlin/src/gcode/bedlevel/mbl/G29.cpp @@ -45,6 +45,10 @@ #define DEBUG_OUT ENABLED(DEBUG_LEVELING_FEATURE) #include "../../../core/debug_out.h" +#if ENABLED(FT_MOTION) + #include "../../../module/ft_motion.h" +#endif + // Save 130 bytes with non-duplication of PSTR inline void echo_not_entered(const char c) { SERIAL_CHAR(c); SERIAL_ECHOLNPGM(" not entered."); } @@ -63,6 +67,9 @@ inline void echo_not_entered(const char c) { SERIAL_CHAR(c); SERIAL_ECHOLNPGM(" */ void GcodeSuite::G29() { + // Potentially disable Fixed-Time Motion for probing + TERN_(FT_MOTION, FTM_DISABLE_IN_SCOPE()); + DEBUG_SECTION(log_G29, "G29", true); // G29 Q is also available if debugging @@ -91,7 +98,7 @@ void GcodeSuite::G29() { case MeshReport: SERIAL_ECHOPGM("Mesh Bed Leveling "); if (leveling_is_valid()) { - serialprintln_onoff(planner.leveling_active); + SERIAL_ECHOLN(ON_OFF(planner.leveling_active)); bedlevel.report_mesh(); } else @@ -218,7 +225,7 @@ void GcodeSuite::G29() { } } else - return echo_not_entered('J'); + return echo_not_entered('I'); if (parser.seenval('J')) { iy = parser.value_int(); @@ -253,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(); diff --git a/Marlin/src/gcode/calibrate/G28.cpp b/Marlin/src/gcode/calibrate/G28.cpp index ac90756ded..4a0ecffc4b 100644 --- a/Marlin/src/gcode/calibrate/G28.cpp +++ b/Marlin/src/gcode/calibrate/G28.cpp @@ -52,12 +52,16 @@ #include "../../feature/bltouch.h" #endif +#if ENABLED(FT_MOTION) + #include "../../module/ft_motion.h" +#endif + #include "../../lcd/marlinui.h" #if ENABLED(EXTENSIBLE_UI) #include "../../lcd/extui/ui_api.h" #elif ENABLED(DWIN_CREALITY_LCD) - #include "../../lcd/e3v2/creality/dwin.h" + #include "../../lcd/dwin/creality/dwin.h" #elif ENABLED(SOVOL_SV06_RTS) #include "../../lcd/sovol_rts/sovol_rts.h" #endif @@ -84,10 +88,8 @@ fr_mm_s = HYPOT(minfr, minfr); // Set homing current to X and Y axis if defined - #if HAS_CURRENT_HOME(X) - set_homing_current(X_AXIS); - #endif - #if HAS_CURRENT_HOME(Y) && NONE(CORE_IS_XY, MARKFORGED_XY, MARKFORGED_YX) + TERN_(X_HAS_HOME_CURRENT, set_homing_current(X_AXIS)); + #if Y_HAS_HOME_CURRENT && NONE(CORE_IS_XY, MARKFORGED_XY, MARKFORGED_YX) set_homing_current(Y_AXIS); #endif @@ -109,10 +111,8 @@ current_position.set(0.0, 0.0); - #if HAS_CURRENT_HOME(X) - restore_homing_current(X_AXIS); - #endif - #if HAS_CURRENT_HOME(Y) && NONE(CORE_IS_XY, MARKFORGED_XY, MARKFORGED_YX) + TERN_(X_HAS_HOME_CURRENT, restore_homing_current(X_AXIS)); + #if Y_HAS_HOME_CURRENT && NONE(CORE_IS_XY, MARKFORGED_XY, MARKFORGED_YX) restore_homing_current(Y_AXIS); #endif @@ -134,6 +134,9 @@ // Disallow Z homing if X or Y homing is needed if (homing_needed_error(_BV(X_AXIS) | _BV(Y_AXIS))) return; + // Potentially disable Fixed-Time Motion for homing + TERN_(FT_MOTION, FTM_DISABLE_IN_SCOPE()); + sync_plan_position(); /** @@ -195,11 +198,12 @@ #endif // IMPROVE_HOMING_RELIABILITY /** - * G28: Home all axes according to settings + * G28: Auto Home * - * Parameters + * Home all axes according to settings * - * None Home to all axes with no parameters. + * Parameters: + * None Home all axes * With QUICK_HOME enabled XY will home together, then Z. * * L Force leveling state ON (if possible) or OFF after homing (Requires RESTORE_LEVELING_AFTER_G28 or ENABLE_LEVELING_AFTER_G28) @@ -211,7 +215,7 @@ * fail with position unreachable due to probe/nozzle offset. This * can be used to avoid a model. * - * Cartesian/SCARA parameters + * Cartesian/SCARA parameters: * * X Home to the X endstop * Y Home to the Y endstop @@ -284,6 +288,9 @@ void GcodeSuite::G28() { motion_state_t saved_motion_state = begin_slow_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 #if DISABLED(DELTA) || ENABLED(DELTA_HOME_TO_SAFE_ZONE) @@ -291,7 +298,8 @@ void GcodeSuite::G28() { #endif // PARKING_EXTRUDER homing requires different handling of movement / solenoid activation, depending on the side of homing #if ENABLED(PARKING_EXTRUDER) - const bool pe_final_change_must_unpark = parking_extruder_unpark_after_homing(old_tool_index, X_HOME_DIR + 1 == old_tool_index * 2); + const bool homed_towards_tool = old_tool_index == TERN(X_HOME_TO_MIN, 0, 1), + pe_final_change_must_unpark = parking_extruder_unpark_after_homing(old_tool_index, homed_towards_tool); #endif tool_change(0, true); #endif diff --git a/Marlin/src/gcode/calibrate/G33.cpp b/Marlin/src/gcode/calibrate/G33.cpp index 80c4688a6e..0a8dd459ca 100644 --- a/Marlin/src/gcode/calibrate/G33.cpp +++ b/Marlin/src/gcode/calibrate/G33.cpp @@ -41,8 +41,8 @@ constexpr uint8_t _7P_STEP = 1, // 7-point step - to change number of calibration points _4P_STEP = _7P_STEP * 2, // 4-point step - NPP = _7P_STEP * 6; // number of calibration points on the radius -enum CalEnum : char { // the 7 main calibration points - add definitions if needed + NPP = _7P_STEP * 6; // Number of calibration points on the radius +enum CalEnum : char { // The 7 main calibration points - add definitions if needed CEN = 0, __A = 1, _AB = __A + _7P_STEP, @@ -87,7 +87,7 @@ void ac_cleanup() { TERN_(HAS_BED_PROBE, probe.use_probing_tool(false)); } -void print_signed_float(FSTR_P const prefix, const_float_t f) { +void print_signed_float(FSTR_P const prefix, const float f) { SERIAL_ECHO(F(" "), prefix, C(':')); serial_offset(f); } @@ -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; @@ -197,13 +197,13 @@ static bool probe_calibration_points(float z_pt[NPP + 1], const int8_t probe_poi if (!_0p_calibration) { - if (!_7p_no_intermediates && !_7p_4_intermediates && !_7p_11_intermediates) { // probe the center + if (!_7p_no_intermediates && !_7p_4_intermediates && !_7p_11_intermediates) { // Probe the center const xy_pos_t center{0}; z_pt[CEN] += calibration_probe(center, stow_after_each, probe_at_offset); if (isnan(z_pt[CEN])) return false; } - if (_7p_calibration) { // probe extra center points + if (_7p_calibration) { // Probe extra center points const float start = _7p_9_center ? float(_CA) + _7P_STEP / 3.0f : _7p_6_center ? float(_CA) : float(__C), steps = _7p_9_center ? _4P_STEP / 3.0f : _7p_6_center ? _7P_STEP : _4P_STEP; I_LOOP_CAL_PT(rad, start, steps) { @@ -216,7 +216,7 @@ static bool probe_calibration_points(float z_pt[NPP + 1], const int8_t probe_poi z_pt[CEN] /= float(_7p_2_intermediates ? 7 : probe_points); } - if (!_1p_calibration) { // probe the radius + if (!_1p_calibration) { // Probe the radius const CalEnum start = _4p_opposite_points ? _AB : __A; const float steps = _7p_14_intermediates ? _7P_STEP / 15.0f : // 15r * 6 + 10c = 100 _7p_11_intermediates ? _7P_STEP / 12.0f : // 12r * 6 + 9c = 81 @@ -241,7 +241,7 @@ static bool probe_calibration_points(float z_pt[NPP + 1], const int8_t probe_poi z_pt[uint8_t(LROUND(rad - interpol + NPP - 1)) % NPP + 1] += z_temp * sq(cos(RADIANS(interpol * 90))); z_pt[uint8_t(LROUND(rad - interpol)) % NPP + 1] += z_temp * sq(sin(RADIANS(interpol * 90))); } - zig_zag = !zig_zag; + FLIP(zig_zag); } if (_7p_intermed_points) LOOP_CAL_RAD(rad) @@ -254,10 +254,11 @@ static bool probe_calibration_points(float z_pt[NPP + 1], const int8_t probe_poi } /** - * kinematics routines and auto tune matrix scaling parameters: - * see https://github.com/LVD-AC/Marlin-AC/tree/1.1.x-AC/documentation for - * - formulae for approximative forward kinematics in the end-stop displacement matrix - * - definition of the matrix scaling parameters + * Kinematics routines and auto tune matrix scaling parameters + * + * NOTE: See https://github.com/LVD-AC/Marlin-AC/tree/1.1.x-AC/documentation for: + * - Formula for approximative forward kinematics in the end-stop displacement matrix + * - Definition of the matrix scaling parameters */ static void reverse_kinematics_probe_points(float z_pt[NPP + 1], abc_float_t mm_at_pt_axis[NPP + 1], const float dcr) { xyz_pos_t pos{0}; @@ -314,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) { @@ -346,43 +347,43 @@ static float auto_tune_a(const float dcr) { } /** - * G33 - Delta '1-4-7-point' Auto-Calibration - * Calibrate height, z_offset, endstops, delta radius, and tower angles. + * G33: Delta Auto Calibration + * + * Calibrate height, z_offset, endstops, delta radius, and tower angles. * * Parameters: + * P Number of probe points: + * P0 Normalizes end-stops and tower angle corrections only (no probing) + * P1 Probe center and set height only + * P2 Probe center and towers. Set height, endstops, and delta radius + * P3 Probe all positions - center, towers and opposite towers. Set all + * P4-P10 Probe all positions with intermediate locations, averaging them * - * Pn Number of probe points: - * P0 Normalizes calibration. - * P1 Calibrates height only with center probe. - * P2 Probe center and towers. Calibrate height, endstops and delta radius. - * P3 Probe all positions: center, towers and opposite towers. Calibrate all. - * P4-P10 Probe all positions at different intermediate locations and average them. + * R Temporarily reduce the size of the probe grid by the specified amount * - * Rn.nn Temporary reduce the probe grid by the specified amount (mm) + * T Disable tower angle corrections calibration (P3-P7) * - * T Don't calibrate tower angle corrections + * C Calibration precision; if omitted iterations stop at best achievable precision * - * Cn.nn Calibration precision; when omitted calibrates to maximum precision + * F<1-30> Run (“force”) this number of iterations and take the best result * - * Fn Force to run at least n iterations and take the best result + * V Verbose level: + * V0 Dry-run mode. Report settings and probe results. No calibration + * V1 Report start and end settings only + * V2 Report settings at each iteration + * V3 Report settings and probe results * - * Vn Verbose level: - * V0 Dry-run mode. Report settings and probe results. No calibration. - * V1 Report start and end settings only - * V2 Report settings at each iteration - * V3 Report settings and probe results + * E Engage the probe for each point * - * E Engage the probe for each point + * O Probe at probe-offset-relative positions instead of the required kinematic points * - * O Probe at offsetted probe positions (this is wrong but it seems to work) - * - * With SENSORLESS_PROBING: - * Use these flags to calibrate stall sensitivity: (e.g., `G33 P1 Y Z` to calibrate X only.) - * X Don't activate stallguard on X. - * Y Don't activate stallguard on Y. - * Z Don't activate stallguard on Z. - * - * S Save offset_sensorless_adj + * With HAS_DELTA_SENSORLESS_PROBING: + * Use these flags to calibrate stall sensitivity: + * Example: G33 P1 Y Z - to calibrate X only + * X Don't activate StallGuard on X + * Y Don't activate StallGuard on Y + * Z Don't activate StallGuard on Z + * S Save offset_sensorless_adj */ void GcodeSuite::G33() { @@ -481,15 +482,15 @@ void GcodeSuite::G33() { caltower({ false, true, false }); // B caltower({ false, false, true }); // C - probe.test_sensitivity = { true, true, true }; // reset to all + probe.test_sensitivity = { true, true, true }; // Reset to all } #endif - do { // start iterations + do { // Start iterations 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 @@ -505,11 +506,11 @@ void GcodeSuite::G33() { if ((zero_std_dev < test_precision || iterations <= force_iterations) && zero_std_dev > calibration_precision) { #if !HAS_BED_PROBE - test_precision = 0.0f; // forced end + test_precision = 0.0f; // Forced end #endif if (zero_std_dev < zero_std_dev_min) { - // set roll-back point + // Set roll-back point e_old = delta_endstop_adj; r_old = delta_radius; h_old = delta_height; @@ -520,19 +521,20 @@ void GcodeSuite::G33() { float r_delta = 0.0f; /** - * convergence matrices: - * see https://github.com/LVD-AC/Marlin-AC/tree/1.1.x-AC/documentation for - * - definition of the matrix scaling parameters - * - matrices for 4 and 7 point calibration + * Convergence matrices + * + * NOTE: See https://github.com/LVD-AC/Marlin-AC/tree/1.1.x-AC/documentation for: + * - 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) #define Z1(I) ZP(1, I) #define Z0(I) ZP(0, I) - // calculate factors + // Calculate factors if (_7p_9_center) dcr *= 0.9f; h_factor = auto_tune_h(dcr); r_factor = auto_tune_r(dcr); @@ -541,22 +543,22 @@ void GcodeSuite::G33() { switch (probe_points) { case 0: - test_precision = 0.0f; // forced end + test_precision = 0.0f; // Forced end break; case 1: - test_precision = 0.0f; // forced end + test_precision = 0.0f; // Forced end LOOP_NUM_AXES(axis) e_delta[axis] = +Z4(CEN); break; case 2: - if (towers_set) { // see 4 point calibration (towers) matrix + if (towers_set) { // See 4 point calibration (towers) matrix e_delta.set((+Z4(__A) -Z2(__B) -Z2(__C)) * h_factor +Z4(CEN), (-Z2(__A) +Z4(__B) -Z2(__C)) * h_factor +Z4(CEN), (-Z2(__A) -Z2(__B) +Z4(__C)) * h_factor +Z4(CEN)); r_delta = (+Z4(__A) +Z4(__B) +Z4(__C) -Z12(CEN)) * r_factor; } - else { // see 4 point calibration (opposites) matrix + else { // See 4 point calibration (opposites) matrix e_delta.set((-Z4(_BC) +Z2(_CA) +Z2(_AB)) * h_factor +Z4(CEN), (+Z2(_BC) -Z4(_CA) +Z2(_AB)) * h_factor +Z4(CEN), (+Z2(_BC) +Z2(_CA) -Z4(_AB)) * h_factor +Z4(CEN)); @@ -564,13 +566,13 @@ void GcodeSuite::G33() { } break; - default: // see 7 point calibration (towers & opposites) matrix + default: // See 7 point calibration (towers & opposites) matrix e_delta.set((+Z2(__A) -Z1(__B) -Z1(__C) -Z2(_BC) +Z1(_CA) +Z1(_AB)) * h_factor +Z4(CEN), (-Z1(__A) +Z2(__B) -Z1(__C) +Z1(_BC) -Z2(_CA) +Z1(_AB)) * h_factor +Z4(CEN), (-Z1(__A) -Z1(__B) +Z2(__C) +Z1(_BC) +Z1(_CA) -Z2(_AB)) * h_factor +Z4(CEN)); r_delta = (+Z2(__A) +Z2(__B) +Z2(__C) +Z2(_BC) +Z2(_CA) +Z2(_AB) -Z12(CEN)) * r_factor; - if (towers_set) { // see 7 point tower angle calibration (towers & opposites) matrix + if (towers_set) { // See 7 point tower angle calibration (towers & opposites) matrix t_delta.set((+Z0(__A) -Z4(__B) +Z4(__C) +Z0(_BC) -Z4(_CA) +Z4(_AB) +Z0(CEN)) * a_factor, (+Z4(__A) +Z0(__B) -Z4(__C) +Z4(_BC) +Z0(_CA) -Z4(_AB) +Z0(CEN)) * a_factor, (-Z4(__A) +Z4(__B) +Z0(__C) -Z4(_BC) +Z4(_CA) +Z0(_AB) +Z0(CEN)) * a_factor); @@ -582,14 +584,14 @@ void GcodeSuite::G33() { delta_tower_angle_trim += t_delta; } else if (zero_std_dev >= test_precision) { - // roll back + // Roll back delta_endstop_adj = e_old; delta_radius = r_old; delta_height = h_old; delta_tower_angle_trim = a_old; } - if (verbose_level != 0) { // !dry run + if (verbose_level != 0) { // !Dry-run // Normalize angles to least-squares if (_angle_results) { @@ -598,7 +600,7 @@ void GcodeSuite::G33() { LOOP_NUM_AXES(axis) delta_tower_angle_trim[axis] -= a_sum / 3.0f; } - // adjust delta_height and endstops by the max amount + // Adjust delta_height and endstops by the max amount const float z_temp = _MAX(delta_endstop_adj.a, delta_endstop_adj.b, delta_endstop_adj.c); delta_height -= z_temp; LOOP_NUM_AXES(axis) delta_endstop_adj[axis] -= z_temp; @@ -606,7 +608,7 @@ void GcodeSuite::G33() { recalc_delta_settings(); NOMORE(zero_std_dev_min, zero_std_dev); - // print report + // Print report if (verbose_level == 3 || verbose_level == 0) { print_calibration_results(z_at_pt, _tower_results, _opposite_results); @@ -620,7 +622,7 @@ void GcodeSuite::G33() { #endif } - if (verbose_level != 0) { // !dry run + if (verbose_level != 0) { // !Dry-run if ((zero_std_dev >= test_precision && iterations > force_iterations) || zero_std_dev <= calibration_precision) { // end iterations SERIAL_ECHOPGM("Calibration OK"); SERIAL_ECHO_SP(32); @@ -657,7 +659,7 @@ void GcodeSuite::G33() { print_calibration_settings(_endstop_results, _angle_results); } } - else { // dry run + else { // Dry-run FSTR_P const enddryrun = F("End DRY-RUN"); SERIAL_ECHO(enddryrun); SERIAL_ECHO_SP(35); diff --git a/Marlin/src/gcode/calibrate/G34.cpp b/Marlin/src/gcode/calibrate/G34.cpp index 9a0cb0054b..504dcd1c6f 100644 --- a/Marlin/src/gcode/calibrate/G34.cpp +++ b/Marlin/src/gcode/calibrate/G34.cpp @@ -40,7 +40,9 @@ #include "../../core/debug_out.h" /** - * G34 - Align the ends of the X gantry. See https://youtu.be/3jAFQdTk8iw + * G34: Mechanical Gantry Calibration + * + * Align the ends of the X gantry. See https://youtu.be/3jAFQdTk8iw * * - The carriage moves to GANTRY_CALIBRATION_SAFE_POSITION, also called the “pounce” position. * - If possible, the Z stepper current is reduced to the value specified by 'S' @@ -53,8 +55,8 @@ * - The machine is re-homed, according to GANTRY_CALIBRATION_COMMANDS_POST. * * Parameters: - * [S] - Current value to use for the raise move. (Default: GANTRY_CALIBRATION_CURRENT) - * [Z] - Extra distance past Z_MAX_POS to move the Z axis. (Default: GANTRY_CALIBRATION_EXTRA_HEIGHT) + * S Current value to use for the raise move. (Default: GANTRY_CALIBRATION_CURRENT) + * Z Extra distance past Z_MAX_POS to move the Z axis. (Default: GANTRY_CALIBRATION_EXTRA_HEIGHT) */ void GcodeSuite::G34() { @@ -95,37 +97,36 @@ void GcodeSuite::G34() { #if HAS_MOTOR_CURRENT_SPI const uint16_t target_current = parser.intval('S', GANTRY_CALIBRATION_CURRENT); - const uint32_t previous_current = stepper.motor_current_setting[Z_AXIS]; + const uint32_t previous_current_Z = stepper.motor_current_setting[Z_AXIS]; stepper.set_digipot_current(Z_AXIS, target_current); #elif HAS_MOTOR_CURRENT_PWM const uint16_t target_current = parser.intval('S', GANTRY_CALIBRATION_CURRENT); - const uint32_t previous_current = stepper.motor_current_setting[1]; // Z + const uint32_t previous_current_Z = stepper.motor_current_setting[1]; // Z stepper.set_digipot_current(1, target_current); #elif HAS_MOTOR_CURRENT_DAC const float target_current = parser.floatval('S', GANTRY_CALIBRATION_CURRENT); - const float previous_current = dac_amps(Z_AXIS, target_current); + const float previous_current_Z = dac_amps(Z_AXIS, target_current); stepper_dac.set_current_value(Z_AXIS, target_current); #elif HAS_MOTOR_CURRENT_I2C const uint16_t target_current = parser.intval('S', GANTRY_CALIBRATION_CURRENT); - previous_current = dac_amps(Z_AXIS); + const float previous_current_Z = dac_amps(Z_AXIS); digipot_i2c.set_current(Z_AXIS, target_current) #elif HAS_TRINAMIC_CONFIG const uint16_t target_current = parser.intval('S', GANTRY_CALIBRATION_CURRENT); - static uint16_t previous_current_arr[NUM_Z_STEPPERS]; - #if AXIS_IS_TMC(Z) - previous_current_arr[0] = stepperZ.getMilliamps(); + #if Z_IS_TRINAMIC + static uint16_t previous_current_Z = stepperZ.getMilliamps(); stepperZ.rms_current(target_current); #endif - #if AXIS_IS_TMC(Z2) - previous_current_arr[1] = stepperZ2.getMilliamps(); + #if Z2_IS_TRINAMIC + static uint16_t previous_current_Z2 = stepperZ2.getMilliamps(); stepperZ2.rms_current(target_current); #endif - #if AXIS_IS_TMC(Z3) - previous_current_arr[2] = stepperZ3.getMilliamps(); + #if Z3_IS_TRINAMIC + static uint16_t previous_current_Z3 = stepperZ3.getMilliamps(); stepperZ3.rms_current(target_current); #endif - #if AXIS_IS_TMC(Z4) - previous_current_arr[3] = stepperZ4.getMilliamps(); + #if Z4_IS_TRINAMIC + static uint16_t previous_current_Z4 = stepperZ4.getMilliamps(); stepperZ4.rms_current(target_current); #endif #endif @@ -140,26 +141,18 @@ void GcodeSuite::G34() { #endif #if HAS_MOTOR_CURRENT_SPI - stepper.set_digipot_current(Z_AXIS, previous_current); + stepper.set_digipot_current(Z_AXIS, previous_current_Z); #elif HAS_MOTOR_CURRENT_PWM - stepper.set_digipot_current(1, previous_current); + stepper.set_digipot_current(1, previous_current_Z); #elif HAS_MOTOR_CURRENT_DAC - stepper_dac.set_current_value(Z_AXIS, previous_current); + stepper_dac.set_current_value(Z_AXIS, previous_current_Z); #elif HAS_MOTOR_CURRENT_I2C - digipot_i2c.set_current(Z_AXIS, previous_current) + digipot_i2c.set_current(Z_AXIS, previous_current_Z) #elif HAS_TRINAMIC_CONFIG - #if AXIS_IS_TMC(Z) - stepperZ.rms_current(previous_current_arr[0]); - #endif - #if AXIS_IS_TMC(Z2) - stepperZ2.rms_current(previous_current_arr[1]); - #endif - #if AXIS_IS_TMC(Z3) - stepperZ3.rms_current(previous_current_arr[2]); - #endif - #if AXIS_IS_TMC(Z4) - stepperZ4.rms_current(previous_current_arr[3]); - #endif + TERN_(Z_IS_TRINAMIC, stepperZ.rms_current(previous_current_Z)); + TERN_(Z2_IS_TRINAMIC, stepperZ2.rms_current(previous_current_Z2)); + TERN_(Z3_IS_TRINAMIC, stepperZ3.rms_current(previous_current_Z3)); + TERN_(Z4_IS_TRINAMIC, stepperZ4.rms_current(previous_current_Z4)); #endif // Back off end plate, back to normal motion range diff --git a/Marlin/src/gcode/calibrate/G34_M422.cpp b/Marlin/src/gcode/calibrate/G34_M422.cpp index 17d576679f..6c367ad882 100644 --- a/Marlin/src/gcode/calibrate/G34_M422.cpp +++ b/Marlin/src/gcode/calibrate/G34_M422.cpp @@ -56,23 +56,24 @@ #endif /** - * G34: Z-Stepper automatic alignment + * G34: Z Steppers Auto-Alignment * - * Manual stepper lock controls (reset by G28): - * L Unlock all steppers - * Z<1-4> Z stepper to lock / unlock - * S 0=UNLOCKED 1=LOCKED. If omitted, assume LOCKED. + * Parameters: + * Manual stepper lock controls (reset by G28): + * L Unlock all steppers + * Z Target specific Z stepper to lock/unlock (1-4) + * S Lock state; 0=UNLOCKED 1=LOCKED. If omitted, assume LOCKED * - * Examples: - * G34 Z1 ; Lock Z1 - * G34 L Z2 ; Unlock all, then lock Z2 - * G34 Z2 S0 ; Unlock Z2 + * With Z_STEPPER_AUTO_ALIGN: + * I Number of test iterations. If omitted, Z_STEPPER_ALIGN_ITERATIONS. (1-30) + * T Target Accuracy factor. If omitted, Z_STEPPER_ALIGN_ACC. (0.01-1.0) + * A Provide an Amplification value. If omitted, Z_STEPPER_ALIGN_AMP. (0.5-2.0) + * R Recalculate points based on current probe offsets * - * With Z_STEPPER_AUTO_ALIGN: - * I Number of tests. If omitted, Z_STEPPER_ALIGN_ITERATIONS. - * T Target Accuracy factor. If omitted, Z_STEPPER_ALIGN_ACC. - * A Provide an Amplification value. If omitted, Z_STEPPER_ALIGN_AMP. - * R Flag to recalculate points based on current probe offsets + * Example: + * G34 Z1 ; Lock Z1 + * G34 L Z2 ; Unlock all, then lock Z2 + * G34 Z2 S0 ; Unlock Z2 */ void GcodeSuite::G34() { @@ -142,6 +143,11 @@ void GcodeSuite::G34() { probe.use_probing_tool(); + #ifdef EVENT_GCODE_BEFORE_G34 + if (DEBUGGING(LEVELING)) DEBUG_ECHOLNPGM("Before G34 G-code: ", F(EVENT_GCODE_BEFORE_G34)); + gcode.process_subcommands_now(F(EVENT_GCODE_BEFORE_G34)); + #endif + TERN_(HAS_DUPLICATION_MODE, set_duplication_enabled(false)); // Compute a worst-case clearance height to probe from. After the first @@ -213,26 +219,25 @@ void GcodeSuite::G34() { // Probing sanity check is disabled, as it would trigger even in normal cases because // current_position.z has been manually altered in the "dirty trick" above. - if (DEBUGGING(LEVELING)) - DEBUG_ECHOLNPGM( - "Z_PROBE_LOW_POINT: ", p_float_t(Z_PROBE_LOW_POINT, 2), - "z_probe: ", p_float_t(z_probe, 2), - "Probe Tgt: ", p_float_t((Z_PROBE_LOW_POINT) - z_probe * 0.5f, 2) - ); + const float minz = (Z_PROBE_LOW_POINT) - (z_probe * 0.5f); + + if (DEBUGGING(LEVELING)) { + DEBUG_ECHOPGM("Z_PROBE_LOW_POINT: " STRINGIFY(Z_PROBE_LOW_POINT)); + DEBUG_ECHOLNPGM(" z_probe: ", p_float_t(z_probe, 3), + " Probe Tgt: ", p_float_t(minz, 3)); + } const float z_probed_height = probe.probe_at_point( DIFF_TERN(HAS_HOME_OFFSET, ppos, xy_pos_t(home_offset)), // xy raise_after, // raise_after (DEBUGGING(LEVELING) || DEBUGGING(INFO)) ? 3 : 0, // verbose_level true, false, // probe_relative, sanity_check - (Z_PROBE_LOW_POINT) - (z_probe * 0.5f), // z_min_point + minz, // z_min_point 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); @@ -302,7 +307,7 @@ void GcodeSuite::G34() { SERIAL_EOL(); - SString<15 + TERN0(TRIPLE_Z, 30) + TERN0(QUAD_Z, 45)> msg(F("1:2="), p_float_t(ABS(z_measured[1] - z_measured[0]), 3)); + SString<15 + TERN0(TRIPLE_Z, 30) + TERN0(QUAD_Z, 45)> msg(F("2-1="), p_float_t(ABS(z_measured[1] - z_measured[0]), 3)); #if TRIPLE_Z msg.append(F(" 3-2="), p_float_t(ABS(z_measured[2] - z_measured[1]), 3)) .append(F(" 3-1="), p_float_t(ABS(z_measured[2] - z_measured[0]), 3)); @@ -316,7 +321,7 @@ void GcodeSuite::G34() { msg.echoln(); ui.set_status(msg); - auto decreasing_accuracy = [](const_float_t v1, const_float_t v2) { + auto decreasing_accuracy = [](const float v1, const float v2) { if (v1 < v2 * 0.7f) { SERIAL_ECHOLNPGM("Decreasing Accuracy Detected."); LCD_MESSAGE(MSG_DECREASING_ACCURACY); @@ -365,7 +370,7 @@ void GcodeSuite::G34() { if (decreasing_accuracy(last_z_align_move[zstepper], z_align_abs)) { if (DEBUGGING(LEVELING)) DEBUG_ECHOLNPGM("> Z", zstepper + 1, " last_z_align_move = ", last_z_align_move[zstepper]); if (DEBUGGING(LEVELING)) DEBUG_ECHOLNPGM("> Z", zstepper + 1, " z_align_abs = ", z_align_abs); - adjustment_reverse = !adjustment_reverse; + FLIP(adjustment_reverse); } // Remember the alignment for the next iteration, but only if steppers move, @@ -385,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 @@ -413,7 +418,7 @@ void GcodeSuite::G34() { SERIAL_ECHOLNPGM("G34 aborted."); else { SERIAL_ECHOLNPGM("Did ", iteration + (iteration != z_auto_align_iterations), " of ", z_auto_align_iterations); - SERIAL_ECHOLNPGM("Accuracy: ", p_float_t(z_maxdiff, 2)); + SERIAL_ECHOLNPGM("Accuracy: ", p_float_t(z_maxdiff, 3)); } // Stow the probe because the last call to probe.probe_at_point(...) @@ -429,9 +434,9 @@ void GcodeSuite::G34() { // Ideally, this would be equal to the 'z_probe * 0.5f' which was added earlier. if (DEBUGGING(LEVELING)) DEBUG_ECHOLNPGM( - "z_measured_min: ", p_float_t(z_measured_min, 2), - "Z_TWEEN_SAFE_CLEARANCE: ", p_float_t(Z_TWEEN_SAFE_CLEARANCE, 2), - "zoffs: ", p_float_t(zoffs, 2) + "z_measured_min: ", p_float_t(z_measured_min, 3), + "Z_TWEEN_SAFE_CLEARANCE: ", p_float_t(Z_TWEEN_SAFE_CLEARANCE, 3), + "zoffs: ", p_float_t(zoffs, 3) ); if (!err_break) @@ -439,6 +444,12 @@ void GcodeSuite::G34() { sync_plan_position(); #endif + #ifdef EVENT_GCODE_AFTER_G34 + if (DEBUGGING(LEVELING)) DEBUG_ECHOLNPGM("After G34 G-code: ", F(EVENT_GCODE_AFTER_G34)); + planner.synchronize(); + process_subcommands_now(F(EVENT_GCODE_AFTER_G34)); + #endif + probe.use_probing_tool(false); #if ALL(HAS_LEVELING, RESTORE_LEVELING_AFTER_G34) diff --git a/Marlin/src/gcode/calibrate/G425.cpp b/Marlin/src/gcode/calibrate/G425.cpp index 6338873ea7..883d7b4b6f 100644 --- a/Marlin/src/gcode/calibrate/G425.cpp +++ b/Marlin/src/gcode/calibrate/G425.cpp @@ -100,7 +100,9 @@ enum side_t : uint8_t { TOP, RIGHT, FRONT, LEFT, BACK, NUM_SIDES, - LIST_N(DOUBLE(SECONDARY_AXES), IMINIMUM, IMAXIMUM, JMINIMUM, JMAXIMUM, KMINIMUM, KMAXIMUM, UMINIMUM, UMAXIMUM, VMINIMUM, VMAXIMUM, WMINIMUM, WMAXIMUM) + LIST_N(DOUBLE(SECONDARY_AXES), + IMINIMUM, IMAXIMUM, JMINIMUM, JMAXIMUM, KMINIMUM, KMAXIMUM, + UMINIMUM, UMAXIMUM, VMINIMUM, VMAXIMUM, WMINIMUM, WMAXIMUM) }; static constexpr xyz_pos_t true_center CALIBRATION_OBJECT_CENTER; @@ -466,102 +468,54 @@ inline void probe_sides(measurements_t &m, const float uncertainty) { inline void report_measured_center(const measurements_t &m) { SERIAL_ECHOLNPGM("Center:"); - #if HAS_X_CENTER - SERIAL_ECHOLNPGM_P(SP_X_STR, m.obj_center.x); - #endif - #if HAS_Y_CENTER - SERIAL_ECHOLNPGM_P(SP_Y_STR, m.obj_center.y); - #endif + TERF(HAS_X_CENTER, SERIAL_ECHOLNPGM_P)(SP_X_STR, m.obj_center.x); + TERF(HAS_Y_CENTER, SERIAL_ECHOLNPGM_P)(SP_Y_STR, m.obj_center.y); SERIAL_ECHOLNPGM_P(SP_Z_STR, m.obj_center.z); - #if HAS_I_CENTER - SERIAL_ECHOLNPGM_P(SP_I_STR, m.obj_center.i); - #endif - #if HAS_J_CENTER - SERIAL_ECHOLNPGM_P(SP_J_STR, m.obj_center.j); - #endif - #if HAS_K_CENTER - SERIAL_ECHOLNPGM_P(SP_K_STR, m.obj_center.k); - #endif - #if HAS_U_CENTER - SERIAL_ECHOLNPGM_P(SP_U_STR, m.obj_center.u); - #endif - #if HAS_V_CENTER - SERIAL_ECHOLNPGM_P(SP_V_STR, m.obj_center.v); - #endif - #if HAS_W_CENTER - SERIAL_ECHOLNPGM_P(SP_W_STR, m.obj_center.w); - #endif + TERF(HAS_I_CENTER, SERIAL_ECHOLNPGM_P)(SP_I_STR, m.obj_center.i); + TERF(HAS_J_CENTER, SERIAL_ECHOLNPGM_P)(SP_J_STR, m.obj_center.j); + TERF(HAS_K_CENTER, SERIAL_ECHOLNPGM_P)(SP_K_STR, m.obj_center.k); + TERF(HAS_U_CENTER, SERIAL_ECHOLNPGM_P)(SP_U_STR, m.obj_center.u); + TERF(HAS_V_CENTER, SERIAL_ECHOLNPGM_P)(SP_V_STR, m.obj_center.v); + TERF(HAS_W_CENTER, SERIAL_ECHOLNPGM_P)(SP_W_STR, m.obj_center.w); SERIAL_EOL(); } inline void report_measured_backlash(const measurements_t &m) { SERIAL_ECHOLNPGM("Backlash:"); #if AXIS_CAN_CALIBRATE(X) - #if ENABLED(CALIBRATION_MEASURE_LEFT) - SERIAL_ECHOLNPGM(" Left: ", m.backlash[LEFT]); - #endif - #if ENABLED(CALIBRATION_MEASURE_RIGHT) - SERIAL_ECHOLNPGM(" Right: ", m.backlash[RIGHT]); - #endif + TERF(CALIBRATION_MEASURE_LEFT, SERIAL_ECHOLNPGM)(" Left: ", m.backlash[LEFT]); + TERF(CALIBRATION_MEASURE_RIGHT, SERIAL_ECHOLNPGM)(" Right: ", m.backlash[RIGHT]); #endif #if AXIS_CAN_CALIBRATE(Y) - #if ENABLED(CALIBRATION_MEASURE_FRONT) - SERIAL_ECHOLNPGM(" Front: ", m.backlash[FRONT]); - #endif - #if ENABLED(CALIBRATION_MEASURE_BACK) - SERIAL_ECHOLNPGM(" Back: ", m.backlash[BACK]); - #endif + TERF(CALIBRATION_MEASURE_FRONT, SERIAL_ECHOLNPGM)(" Front: ", m.backlash[FRONT]); + TERF(CALIBRATION_MEASURE_BACK, SERIAL_ECHOLNPGM)(" Back: ", m.backlash[BACK]); #endif #if AXIS_CAN_CALIBRATE(Z) SERIAL_ECHOLNPGM(" Top: ", m.backlash[TOP]); #endif #if AXIS_CAN_CALIBRATE(I) - #if ENABLED(CALIBRATION_MEASURE_IMIN) - SERIAL_ECHOLNPGM(" " STR_I_MIN ": ", m.backlash[IMINIMUM]); - #endif - #if ENABLED(CALIBRATION_MEASURE_IMAX) - SERIAL_ECHOLNPGM(" " STR_I_MAX ": ", m.backlash[IMAXIMUM]); - #endif + TERF(CALIBRATION_MEASURE_IMIN, SERIAL_ECHOLNPGM)(" " STR_I_MIN ": ", m.backlash[IMINIMUM]); + TERF(CALIBRATION_MEASURE_IMAX, SERIAL_ECHOLNPGM)(" " STR_I_MAX ": ", m.backlash[IMAXIMUM]); #endif #if AXIS_CAN_CALIBRATE(J) - #if ENABLED(CALIBRATION_MEASURE_JMIN) - SERIAL_ECHOLNPGM(" " STR_J_MIN ": ", m.backlash[JMINIMUM]); - #endif - #if ENABLED(CALIBRATION_MEASURE_JMAX) - SERIAL_ECHOLNPGM(" " STR_J_MAX ": ", m.backlash[JMAXIMUM]); - #endif + TERF(CALIBRATION_MEASURE_JMIN, SERIAL_ECHOLNPGM)(" " STR_J_MIN ": ", m.backlash[JMINIMUM]); + TERF(CALIBRATION_MEASURE_JMAX, SERIAL_ECHOLNPGM)(" " STR_J_MAX ": ", m.backlash[JMAXIMUM]); #endif #if AXIS_CAN_CALIBRATE(K) - #if ENABLED(CALIBRATION_MEASURE_KMIN) - SERIAL_ECHOLNPGM(" " STR_K_MIN ": ", m.backlash[KMINIMUM]); - #endif - #if ENABLED(CALIBRATION_MEASURE_KMAX) - SERIAL_ECHOLNPGM(" " STR_K_MAX ": ", m.backlash[KMAXIMUM]); - #endif + TERF(CALIBRATION_MEASURE_KMIN, SERIAL_ECHOLNPGM)(" " STR_K_MIN ": ", m.backlash[KMINIMUM]); + TERF(CALIBRATION_MEASURE_KMAX, SERIAL_ECHOLNPGM)(" " STR_K_MAX ": ", m.backlash[KMAXIMUM]); #endif #if AXIS_CAN_CALIBRATE(U) - #if ENABLED(CALIBRATION_MEASURE_UMIN) - SERIAL_ECHOLNPGM(" " STR_U_MIN ": ", m.backlash[UMINIMUM]); - #endif - #if ENABLED(CALIBRATION_MEASURE_UMAX) - SERIAL_ECHOLNPGM(" " STR_U_MAX ": ", m.backlash[UMAXIMUM]); - #endif + TERF(CALIBRATION_MEASURE_UMIN, SERIAL_ECHOLNPGM)(" " STR_U_MIN ": ", m.backlash[UMINIMUM]); + TERF(CALIBRATION_MEASURE_UMAX, SERIAL_ECHOLNPGM)(" " STR_U_MAX ": ", m.backlash[UMAXIMUM]); #endif #if AXIS_CAN_CALIBRATE(V) - #if ENABLED(CALIBRATION_MEASURE_VMIN) - SERIAL_ECHOLNPGM(" " STR_V_MIN ": ", m.backlash[VMINIMUM]); - #endif - #if ENABLED(CALIBRATION_MEASURE_VMAX) - SERIAL_ECHOLNPGM(" " STR_V_MAX ": ", m.backlash[VMAXIMUM]); - #endif + TERF(CALIBRATION_MEASURE_VMIN, SERIAL_ECHOLNPGM)(" " STR_V_MIN ": ", m.backlash[VMINIMUM]); + TERF(CALIBRATION_MEASURE_VMAX, SERIAL_ECHOLNPGM)(" " STR_V_MAX ": ", m.backlash[VMAXIMUM]); #endif #if AXIS_CAN_CALIBRATE(W) - #if ENABLED(CALIBRATION_MEASURE_WMIN) - SERIAL_ECHOLNPGM(" " STR_W_MIN ": ", m.backlash[WMINIMUM]); - #endif - #if ENABLED(CALIBRATION_MEASURE_WMAX) - SERIAL_ECHOLNPGM(" " STR_W_MAX ": ", m.backlash[WMAXIMUM]); - #endif + TERF(CALIBRATION_MEASURE_WMIN, SERIAL_ECHOLNPGM)(" " STR_W_MIN ": ", m.backlash[WMINIMUM]); + TERF(CALIBRATION_MEASURE_WMAX, SERIAL_ECHOLNPGM)(" " STR_W_MAX ": ", m.backlash[WMAXIMUM]); #endif SERIAL_EOL(); } @@ -602,12 +556,8 @@ inline void probe_sides(measurements_t &m, const float uncertainty) { inline void report_measured_nozzle_dimensions(const measurements_t &m) { SERIAL_ECHOLNPGM("Nozzle Tip Outer Dimensions:"); - #if HAS_X_CENTER - SERIAL_ECHOLNPGM_P(SP_X_STR, m.nozzle_outer_dimension.x); - #endif - #if HAS_Y_CENTER - SERIAL_ECHOLNPGM_P(SP_Y_STR, m.nozzle_outer_dimension.y); - #endif + TERF(HAS_X_CENTER, SERIAL_ECHOLNPGM_P)(SP_X_STR, m.nozzle_outer_dimension.x); + TERF(HAS_Y_CENTER, SERIAL_ECHOLNPGM_P)(SP_Y_STR, m.nozzle_outer_dimension.y); SERIAL_EOL(); UNUSED(m); } diff --git a/Marlin/src/gcode/calibrate/G76_M871.cpp b/Marlin/src/gcode/calibrate/G76_M871.cpp index bb69b75d50..35f7ac3174 100644 --- a/Marlin/src/gcode/calibrate/G76_M871.cpp +++ b/Marlin/src/gcode/calibrate/G76_M871.cpp @@ -38,47 +38,53 @@ #include "../../lcd/marlinui.h" /** - * G76: calibrate probe and/or bed temperature offsets - * Notes: - * - When calibrating probe, bed temperature is held constant. - * Compensation values are deltas to first probe measurement at probe temp. = 30°C. - * - When calibrating bed, probe temperature is held constant. - * Compensation values are deltas to first probe measurement at bed temp. = 60°C. - * - The hotend will not be heated at any time. - * - On my Průša MK3S clone I put a piece of paper between the probe and the hotend - * so the hotend fan would not cool my probe constantly. Alternatively you could just - * make sure the fan is not running while running the calibration process. + * G76: Probe Temperature Calibration * - * Probe calibration: - * - Moves probe to cooldown point. - * - Heats up bed to 100°C. - * - Moves probe to probing point (1mm above heatbed). - * - Waits until probe reaches target temperature (30°C). - * - Does a z-probing (=base value) and increases target temperature by 5°C. - * - Waits until probe reaches increased target temperature. - * - Does a z-probing (delta to base value will be a compensation value) and increases target temperature by 5°C. - * - Repeats last two steps until max. temperature reached or timeout (i.e. probe does not heat up any further). - * - Compensation values of higher temperatures will be extrapolated (using linear regression first). - * While this is not exact by any means it is still better than simply using the last compensation value. + * Calibrate probe and/or bed temperature offsets. * - * Bed calibration: - * - Moves probe to cooldown point. - * - Heats up bed to 60°C. - * - Moves probe to probing point (1mm above heatbed). - * - Waits until probe reaches target temperature (30°C). - * - Does a z-probing (=base value) and increases bed temperature by 5°C. - * - Moves probe to cooldown point. - * - Waits until probe is below 30°C and bed has reached target temperature. - * - Moves probe to probing point and waits until it reaches target temperature (30°C). - * - Does a z-probing (delta to base value will be a compensation value) and increases bed temperature by 5°C. - * - Repeats last four points until max. bed temperature reached (110°C) or timeout. - * - Compensation values of higher temperatures will be extrapolated (using linear regression first). - * While this is not exact by any means it is still better than simply using the last compensation value. + * Probe calibration: + * - Moves probe to cooldown point. + * - Heats up bed to 100°C. + * - Moves probe to probing point (1mm above heatbed). + * - Waits until probe reaches target temperature (30°C). + * - Does a z-probing (=base value) and increases target temperature by 5°C. + * - Waits until probe reaches increased target temperature. + * - Does a z-probing (delta to base value will be a compensation value) and increases target temperature by 5°C. + * - Repeats last two steps until max. temperature reached or timeout (i.e. probe does not heat up any further). + * - Compensation values of higher temperatures will be extrapolated (using linear regression first). + * While this is not exact by any means it is still better than simply using the last compensation value. * - * G76 [B | P] - * - no flag - Both calibration procedures will be run. - * - `B` - Run bed temperature calibration. - * - `P` - Run probe temperature calibration. + * Bed calibration: + * - Moves probe to cooldown point. + * - Heats up bed to 60°C. + * - Moves probe to probing point (1mm above heatbed). + * - Waits until probe reaches target temperature (30°C). + * - Does a z-probing (=base value) and increases bed temperature by 5°C. + * - Moves probe to cooldown point. + * - Waits until probe is below 30°C and bed has reached target temperature. + * - Moves probe to probing point and waits until it reaches target temperature (30°C). + * - Does a z-probing (delta to base value will be a compensation value) and increases bed temperature by 5°C. + * - Repeats last four points until max. bed temperature reached (110°C) or timeout. + * - Compensation values of higher temperatures will be extrapolated (using linear regression first). + * While this is not exact by any means it is still better than simply using the last compensation value. + * + * Usage: + * G76 [ B | P ] + * + * Parameters: + * None Run Both calibration procedures + * B Calibrate bed only + * P Calibrate probe only + * + * NOTES: + * - When calibrating probe, bed temperature is held constant. + * Compensation values are deltas to first probe measurement at probe temp. = 30°C. + * - When calibrating bed, probe temperature is held constant. + * Compensation values are deltas to first probe measurement at bed temp. = 60°C. + * - The hotend will not be heated at any time. + * - On my Průša MK3S clone I put a piece of paper between the probe and the hotend + * so the hotend fan would not cool my probe constantly. Alternatively you could just + * make sure the fan is not running while running the calibration process. */ #if ALL(PTC_PROBE, PTC_BED) @@ -90,7 +96,7 @@ void GcodeSuite::G76() { auto report_temps = [](millis_t &ntr, millis_t timeout=0) { - idle_no_sleep(); + marlin.idle_no_sleep(); const millis_t ms = millis(); if (ELAPSED(ms, ntr)) { ntr = ms + 1000; @@ -291,26 +297,30 @@ #endif // PTC_PROBE && PTC_BED /** - * M871: Report / reset temperature compensation offsets. - * Note: This does not affect values in EEPROM until M500. + * M871: Probe Temperature Config * + * Report / reset temperature compensation offsets. + * NOTE: This does not affect values in EEPROM until M500. + * + * Usage: * M871 [ R | B | P | E ] * - * No Parameters - Print current offset values. + * Parameters: + * None Print current offset values * - * Select only one of these flags: - * R - Reset all offsets to zero (i.e., disable compensation). - * B - Manually set offset for bed - * P - Manually set offset for probe - * E - Manually set offset for extruder + * Select only one of these flags: + * R Reset all offsets to zero (i.e., disable compensation) + * B Manually set offset for bed + * P Manually set offset for probe + * E Manually set offset for extruder * - * With B, P, or E: - * I[index] - Index in the array - * V[value] - Adjustment in µm + * With B, P, or E: + * I Index in the array + * V Adjustment in µm */ 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."); diff --git a/Marlin/src/gcode/calibrate/M100.cpp b/Marlin/src/gcode/calibrate/M100.cpp index c05fe12fc3..822ce969ec 100644 --- a/Marlin/src/gcode/calibrate/M100.cpp +++ b/Marlin/src/gcode/calibrate/M100.cpp @@ -28,39 +28,37 @@ #include "../queue.h" #include "../../libs/hex_print.h" -#include "../../MarlinCore.h" // for idle() - /** - * M100 Free Memory Watcher + * M100: Free Memory Watcher * * This code watches the free memory block between the bottom of the heap and the top of the stack. * This memory block is initialized and watched via the M100 command. * - * M100 I Initializes the free memory block and prints vitals statistics about the area + * Parameters: + * I Initializes the free memory block and prints vitals statistics about the area * - * M100 F Identifies how much of the free memory block remains free and unused. It also - * detects and reports any corruption within the free memory block that may have - * happened due to errant firmware. + * F Identifies how much of the free memory block remains free and unused. It also + * detects and reports any corruption within the free memory block that may have + * happened due to errant firmware. * - * M100 D Does a hex display of the free memory block along with a flag for any errant - * data that does not match the expected value. + * D Does a hex display of the free memory block along with a flag for any errant + * data that does not match the expected value. * - * M100 C x Corrupts x locations within the free memory block. This is useful to check the - * correctness of the M100 F and M100 D commands. + * C x Corrupts x locations within the free memory block. This is useful to check the + * correctness of the M100 F and M100 D commands. * * Also, there are two support functions that can be called from a developer's C code. - * - * uint16_t check_for_free_memory_corruption(PGM_P const free_memory_start); - * void M100_dump_routine(FSTR_P const title, const char * const start, const uintptr_t size); + * uint16_t check_for_free_memory_corruption(PGM_P const free_memory_start); + * void M100_dump_routine(FSTR_P const title, const char * const start, const uintptr_t size); * * Initial version by Roxy-3D */ -#define M100_FREE_MEMORY_DUMPER // Enable for the `M100 D` Dump sub-command -#define M100_FREE_MEMORY_CORRUPTOR // Enable for the `M100 C` Corrupt sub-command +#define M100_FREE_MEMORY_DUMPER // Enable for the 'M100 D' Dump sub-command +#define M100_FREE_MEMORY_CORRUPTOR // Enable for the 'M100 C' Corrupt sub-command #define TEST_BYTE ((char) 0xE5) -#if ANY(__AVR__, IS_32BIT_TEENSY) +#if ANY(__AVR__, IS_32BIT_TEENSY) && !IS_TEENSY_40_41 extern char __bss_end; char *end_bss = &__bss_end, @@ -178,7 +176,7 @@ inline int32_t count_test_bytes(const char * const start_free_memory) { SERIAL_EOL(); start_free_memory += 16; serial_delay(25); - idle(); + marlin.idle(); } } @@ -209,12 +207,12 @@ inline int check_for_free_memory_corruption(FSTR_P const title) { if (end_free_memory < start_free_memory) { SERIAL_ECHOPGM(" end_free_memory < Heap "); //SET_INPUT_PULLUP(63); // if the developer has a switch wired up to their controller board - //safe_delay(5); // this code can be enabled to pause the display as soon as the - //while ( READ(63)) // malfunction is detected. It is currently defaulting to a switch - // idle(); // being on pin-63 which is unassigend and available on most controller - //safe_delay(20); // boards. + //safe_delay(5); // this code can be enabled to pause the display as soon as the + //while ( READ(63)) // malfunction is detected. It is currently defaulting to a switch + // marlin.idle(); // being on pin-63 which is unassigend and available on most controller + //safe_delay(20); // boards. //while ( !READ(63)) - // idle(); + // marlin.idle(); serial_delay(20); #if ENABLED(M100_FREE_MEMORY_DUMPER) M100_dump_routine(F(" Memory corruption detected with end_free_memory(GET_TEXT_F(MSG_M48_DEVIATION), F(": "), w_float_t(sigma, 2, 6))); + if (MAX_MESSAGE_SIZE <= 20) { + // 12345678901234567890 + // Deviation: 0.123456 + ui.set_status_and_level(TS(GET_TEXT_F(MSG_M48_DEVIATION), F(": "), w_float_t(sigma, 2, 6))); + } else if (MAX_MESSAGE_SIZE <= 30) { + // 123456789012345678901234567890 + // Dev:0.12345, Max delta:0.12345 + ui.set_status_and_level(TS(GET_TEXT_F(MSG_M48_DEV), ':', w_float_t(sigma, 2, 5), F(", "), GET_TEXT(MSG_M48_MAX_DELTA), ':', w_float_t(_MAX(mean - min, max - mean), 2, 5))); + } else { + // 1234567890123456789012345678901234567890 + // Deviation: 1.23456, Max delta: 1.23456 + ui.set_status_and_level(TS(GET_TEXT_F(MSG_M48_DEVIATION), F(": "), w_float_t(sigma, 2, 6), F(", "), GET_TEXT(MSG_M48_MAX_DELTA), F(": "), w_float_t(_MAX(mean - min, max - mean), 2, 6))); + } #endif } diff --git a/Marlin/src/gcode/calibrate/M666.cpp b/Marlin/src/gcode/calibrate/M666.cpp index 4186290154..2584782cf3 100644 --- a/Marlin/src/gcode/calibrate/M666.cpp +++ b/Marlin/src/gcode/calibrate/M666.cpp @@ -39,7 +39,15 @@ #if ENABLED(DELTA) /** - * M666: Set delta endstop adjustment + * M666: Set Delta endstop adjustments + * + * Adjust the endstop offsets on a Delta printer. + * + * Parameters: + * None Report current offsets + * X Adjustment for the X actuator endstop + * Y Adjustment for the Y actuator endstop + * Z Adjustment for the Z actuator endstop */ void GcodeSuite::M666() { DEBUG_SECTION(log_M666, "M666", DEBUGGING(LEVELING)); @@ -74,14 +82,22 @@ #else /** - * M666: Set Dual Endstops offsets for X, Y, and/or Z. - * With no parameters report current offsets. + * M666: Set Dual Endstop Offsets * - * For Triple / Quad Z Endstops: - * Set Z2 Only: M666 S2 Z - * Set Z3 Only: M666 S3 Z - * Set Z4 Only: M666 S4 Z - * Set All: M666 Z + * Adjust the offsets for dual (or multiple) endstops. + * + * Parameters: + * None Report current offsets + * X Offset for the X axis endstops + * Y Offset for the Y axis endstops + * Z Offset for the Z axis endstops + * + * Example: + * For Triple / Quad Z Endstops: + * M666 S2 Z ; Set Z2 Only + * M666 S3 Z ; Set Z3 Only + * M666 S4 Z ; Set Z4 Only + * M666 Z ; Set All */ void GcodeSuite::M666() { if (!parser.seen_any()) return M666_report(); diff --git a/Marlin/src/gcode/calibrate/M852.cpp b/Marlin/src/gcode/calibrate/M852.cpp index 001160ae72..7cd9aaf718 100644 --- a/Marlin/src/gcode/calibrate/M852.cpp +++ b/Marlin/src/gcode/calibrate/M852.cpp @@ -28,12 +28,16 @@ #include "../../module/planner.h" /** - * M852: Get or set the machine skew factors. Reports current values with no arguments. + * M852: Bed Skew Compensation * - * S[xy_factor] - Alias for 'I' - * I[xy_factor] - New XY skew factor - * J[xz_factor] - New XZ skew factor - * K[yz_factor] - New YZ skew factor + * Get or set the machine skew factors; correct for misalignment + * + * Parameters: + * None Report current values + * S Alias for 'I' + * I New XY skew factor + * J New XZ skew factor + * K New YZ skew factor */ void GcodeSuite::M852() { if (!parser.seen("SIJK")) return M852_report(); diff --git a/Marlin/src/gcode/config/M200-M205.cpp b/Marlin/src/gcode/config/M200-M205.cpp index a0466fbeab..53d0b4b4a8 100644 --- a/Marlin/src/gcode/config/M200-M205.cpp +++ b/Marlin/src/gcode/config/M200-M205.cpp @@ -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 @@ -78,10 +78,10 @@ TERN_(MARLIN_SMALL_BUILD, return); if (!forReplay) { - report_heading(forReplay, F(STR_FILAMENT_SETTINGS), false); + report_heading(false, F(STR_FILAMENT_SETTINGS), false); if (!parser.volumetric_enabled) SERIAL_ECHOPGM(" (Disabled):"); SERIAL_EOL(); - report_echo_start(forReplay); + report_echo_start(false); } #if EXTRUDERS == 1 @@ -107,7 +107,7 @@ #endif } -#endif // !NO_VOLUMETRICS +#endif // HAS_VOLUMETRIC_EXTRUSION /** * M201: Set max acceleration in units/s^2 for print moves. @@ -124,8 +124,13 @@ * S : Speed factor percentage. */ void GcodeSuite::M201() { - if (!parser.seen("T" STR_AXES_LOGICAL TERN_(XY_FREQUENCY_LIMIT, "FS"))) + if (!parser.seen("T" STR_AXES_LOGICAL + #ifdef XY_FREQUENCY_LIMIT + "FS" + #endif + )) { return M201_report(); + } const int8_t target_extruder = get_target_extruder_from_command(); if (target_extruder < 0) return; @@ -147,30 +152,37 @@ void GcodeSuite::M201_report(const bool forReplay/*=true*/) { TERN_(MARLIN_SMALL_BUILD, return); report_heading_etc(forReplay, F(STR_MAX_ACCELERATION)); + + bool eol = false; + #if NUM_AXES - SERIAL_ECHOPGM_P( - LIST_N(DOUBLE(NUM_AXES), - PSTR(" M201 X"), LINEAR_UNIT(planner.settings.max_acceleration_mm_per_s2[X_AXIS]), - SP_Y_STR, LINEAR_UNIT(planner.settings.max_acceleration_mm_per_s2[Y_AXIS]), - SP_Z_STR, LINEAR_UNIT(planner.settings.max_acceleration_mm_per_s2[Z_AXIS]), - SP_I_STR, I_AXIS_UNIT(planner.settings.max_acceleration_mm_per_s2[I_AXIS]), - SP_J_STR, J_AXIS_UNIT(planner.settings.max_acceleration_mm_per_s2[J_AXIS]), - SP_K_STR, K_AXIS_UNIT(planner.settings.max_acceleration_mm_per_s2[K_AXIS]), - SP_U_STR, U_AXIS_UNIT(planner.settings.max_acceleration_mm_per_s2[U_AXIS]), - SP_V_STR, V_AXIS_UNIT(planner.settings.max_acceleration_mm_per_s2[V_AXIS]), - SP_W_STR, W_AXIS_UNIT(planner.settings.max_acceleration_mm_per_s2[W_AXIS]) - ) - ); + eol = true; + SERIAL_ECHOPGM_P(NUM_AXIS_PAIRED_LIST( + PSTR(" M201 X"), LINEAR_UNIT(planner.settings.max_acceleration_mm_per_s2[X_AXIS]), + SP_Y_STR, LINEAR_UNIT(planner.settings.max_acceleration_mm_per_s2[Y_AXIS]), + SP_Z_STR, LINEAR_UNIT(planner.settings.max_acceleration_mm_per_s2[Z_AXIS]), + SP_I_STR, I_AXIS_UNIT(planner.settings.max_acceleration_mm_per_s2[I_AXIS]), + SP_J_STR, J_AXIS_UNIT(planner.settings.max_acceleration_mm_per_s2[J_AXIS]), + SP_K_STR, K_AXIS_UNIT(planner.settings.max_acceleration_mm_per_s2[K_AXIS]), + SP_U_STR, U_AXIS_UNIT(planner.settings.max_acceleration_mm_per_s2[U_AXIS]), + SP_V_STR, V_AXIS_UNIT(planner.settings.max_acceleration_mm_per_s2[V_AXIS]), + SP_W_STR, W_AXIS_UNIT(planner.settings.max_acceleration_mm_per_s2[W_AXIS]) + )); #endif #if HAS_EXTRUDERS && DISABLED(DISTINCT_E_FACTORS) + eol = true; SERIAL_ECHOPGM_P(SP_E_STR, VOLUMETRIC_UNIT(planner.settings.max_acceleration_mm_per_s2[E_AXIS])); #endif - #if NUM_AXES || (HAS_EXTRUDERS && DISABLED(DISTINCT_E_FACTORS)) - SERIAL_EOL(); + #ifdef XY_FREQUENCY_LIMIT + eol = true; + SERIAL_ECHOPGM_P(PSTR(" F"), planner.xy_freq_limit_hz); + SERIAL_ECHOPGM_P(PSTR(" S"), (planner.xy_freq_min_speed_factor * 100)); #endif + if (eol) SERIAL_EOL(); + #if ENABLED(DISTINCT_E_FACTORS) for (uint8_t i = 0; i < E_STEPPERS; ++i) { report_echo_start(forReplay); @@ -205,33 +217,34 @@ void GcodeSuite::M203_report(const bool forReplay/*=true*/) { TERN_(MARLIN_SMALL_BUILD, return); report_heading_etc(forReplay, F(STR_MAX_FEEDRATES)); + + bool eol = false; + #if NUM_AXES - SERIAL_ECHOPGM_P( - LIST_N(DOUBLE(NUM_AXES), - PSTR(" M203 X"), LINEAR_UNIT(planner.settings.max_feedrate_mm_s[X_AXIS]), - SP_Y_STR, LINEAR_UNIT(planner.settings.max_feedrate_mm_s[Y_AXIS]), - SP_Z_STR, LINEAR_UNIT(planner.settings.max_feedrate_mm_s[Z_AXIS]), - SP_I_STR, LINEAR_UNIT(planner.settings.max_feedrate_mm_s[I_AXIS]), - SP_J_STR, LINEAR_UNIT(planner.settings.max_feedrate_mm_s[J_AXIS]), - SP_K_STR, LINEAR_UNIT(planner.settings.max_feedrate_mm_s[K_AXIS]), - SP_U_STR, LINEAR_UNIT(planner.settings.max_feedrate_mm_s[U_AXIS]), - SP_V_STR, LINEAR_UNIT(planner.settings.max_feedrate_mm_s[V_AXIS]), - SP_W_STR, LINEAR_UNIT(planner.settings.max_feedrate_mm_s[W_AXIS]) - ) - ); + eol = true; + SERIAL_ECHOPGM_P(NUM_AXIS_PAIRED_LIST( + PSTR(" M203 X"), LINEAR_UNIT(planner.settings.max_feedrate_mm_s[X_AXIS]), + SP_Y_STR, LINEAR_UNIT(planner.settings.max_feedrate_mm_s[Y_AXIS]), + SP_Z_STR, LINEAR_UNIT(planner.settings.max_feedrate_mm_s[Z_AXIS]), + SP_I_STR, LINEAR_UNIT(planner.settings.max_feedrate_mm_s[I_AXIS]), + SP_J_STR, LINEAR_UNIT(planner.settings.max_feedrate_mm_s[J_AXIS]), + SP_K_STR, LINEAR_UNIT(planner.settings.max_feedrate_mm_s[K_AXIS]), + SP_U_STR, LINEAR_UNIT(planner.settings.max_feedrate_mm_s[U_AXIS]), + SP_V_STR, LINEAR_UNIT(planner.settings.max_feedrate_mm_s[V_AXIS]), + SP_W_STR, LINEAR_UNIT(planner.settings.max_feedrate_mm_s[W_AXIS]) + )); #endif #if HAS_EXTRUDERS && DISABLED(DISTINCT_E_FACTORS) + eol = true; SERIAL_ECHOPGM_P(SP_E_STR, VOLUMETRIC_UNIT(planner.settings.max_feedrate_mm_s[E_AXIS])); #endif - #if NUM_AXES || (HAS_EXTRUDERS && DISABLED(DISTINCT_E_FACTORS)) - SERIAL_EOL(); - #endif + if (eol) SERIAL_EOL(); #if ENABLED(DISTINCT_E_FACTORS) for (uint8_t i = 0; i < E_STEPPERS; ++i) { - if (!forReplay) SERIAL_ECHO_START(); + report_echo_start(forReplay); SERIAL_ECHOLNPGM_P( PSTR(" M203 T"), i , SP_E_STR, VOLUMETRIC_UNIT(planner.settings.max_feedrate_mm_s[E_AXIS_N(i)]) @@ -360,7 +373,7 @@ void GcodeSuite::M205_report(const bool forReplay/*=true*/) { , PSTR(" J"), LINEAR_UNIT(planner.junction_deviation_mm) #endif #if ENABLED(CLASSIC_JERK) && NUM_AXES - , LIST_N(DOUBLE(NUM_AXES), + , NUM_AXIS_PAIRED_LIST( SP_X_STR, LINEAR_UNIT(planner.max_jerk.x), SP_Y_STR, LINEAR_UNIT(planner.max_jerk.y), SP_Z_STR, LINEAR_UNIT(planner.max_jerk.z), diff --git a/Marlin/src/gcode/config/M210.cpp b/Marlin/src/gcode/config/M210.cpp index 99c750bd25..41dbd73db4 100644 --- a/Marlin/src/gcode/config/M210.cpp +++ b/Marlin/src/gcode/config/M210.cpp @@ -47,33 +47,17 @@ void GcodeSuite::M210() { if (!parser.seen_any()) return M210_report(); - #if HAS_X_AXIS - if (parser.floatval('X') > 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); - #endif - #if HAS_Z_AXIS - if (parser.floatval('Z') > 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); - #endif - #if HAS_J_AXIS - if (parser.floatval(AXIS5_NAME) > 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); - #endif - #if HAS_U_AXIS - if (parser.floatval(AXIS7_NAME) > 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); - #endif - #if HAS_W_AXIS - if (parser.floatval(AXIS9_NAME) > 0) homing_feedrate_mm_m.w = parser.value_axis_units(W_AXIS); - #endif + NUM_AXIS_CODE( + if (parser.floatval(AXIS1_PARAM) > 0) homing_feedrate_mm_m.x = parser.value_axis_units(X_AXIS), + if (parser.floatval(AXIS2_PARAM) > 0) homing_feedrate_mm_m.y = parser.value_axis_units(Y_AXIS), + if (parser.floatval(AXIS3_PARAM) > 0) homing_feedrate_mm_m.z = parser.value_axis_units(Z_AXIS), + if (parser.floatval(AXIS4_PARAM) > 0) homing_feedrate_mm_m.i = parser.value_axis_units(I_AXIS), + if (parser.floatval(AXIS5_PARAM) > 0) homing_feedrate_mm_m.j = parser.value_axis_units(J_AXIS), + if (parser.floatval(AXIS6_PARAM) > 0) homing_feedrate_mm_m.k = parser.value_axis_units(K_AXIS), + if (parser.floatval(AXIS7_PARAM) > 0) homing_feedrate_mm_m.u = parser.value_axis_units(U_AXIS), + if (parser.floatval(AXIS8_PARAM) > 0) homing_feedrate_mm_m.v = parser.value_axis_units(V_AXIS), + if (parser.floatval(AXIS9_PARAM) > 0) homing_feedrate_mm_m.w = parser.value_axis_units(W_AXIS) + ); } void GcodeSuite::M210_report(const bool forReplay/*=true*/) { @@ -82,19 +66,17 @@ void GcodeSuite::M210_report(const bool forReplay/*=true*/) { report_heading_etc(forReplay, F(STR_HOMING_FEEDRATE)); SERIAL_ECHOPGM(" M210"); - SERIAL_ECHOLNPGM_P( - LIST_N(DOUBLE(NUM_AXES) - , SP_X_STR, X_AXIS_UNIT(homing_feedrate_mm_m.x) - , SP_Y_STR, Y_AXIS_UNIT(homing_feedrate_mm_m.y) - , SP_Z_STR, Z_AXIS_UNIT(homing_feedrate_mm_m.z) - , SP_I_STR, I_AXIS_UNIT(homing_feedrate_mm_m.i) - , SP_J_STR, J_AXIS_UNIT(homing_feedrate_mm_m.j) - , SP_K_STR, K_AXIS_UNIT(homing_feedrate_mm_m.k) - , SP_U_STR, U_AXIS_UNIT(homing_feedrate_mm_m.u) - , SP_V_STR, V_AXIS_UNIT(homing_feedrate_mm_m.v) - , SP_W_STR, W_AXIS_UNIT(homing_feedrate_mm_m.w) - ) - ); + SERIAL_ECHOLNPGM_P(NUM_AXIS_PAIRED_LIST( + SP_X_STR, X_AXIS_UNIT(homing_feedrate_mm_m.x), + SP_Y_STR, Y_AXIS_UNIT(homing_feedrate_mm_m.y), + SP_Z_STR, Z_AXIS_UNIT(homing_feedrate_mm_m.z), + SP_I_STR, I_AXIS_UNIT(homing_feedrate_mm_m.i), + SP_J_STR, J_AXIS_UNIT(homing_feedrate_mm_m.j), + SP_K_STR, K_AXIS_UNIT(homing_feedrate_mm_m.k), + SP_U_STR, U_AXIS_UNIT(homing_feedrate_mm_m.u), + SP_V_STR, V_AXIS_UNIT(homing_feedrate_mm_m.v), + SP_W_STR, W_AXIS_UNIT(homing_feedrate_mm_m.w) + )); } #endif // EDITABLE_HOMING_FEEDRATE diff --git a/Marlin/src/gcode/config/M218.cpp b/Marlin/src/gcode/config/M218.cpp index 006f9a1d2c..7d167e502d 100644 --- a/Marlin/src/gcode/config/M218.cpp +++ b/Marlin/src/gcode/config/M218.cpp @@ -65,7 +65,7 @@ void GcodeSuite::M218() { void GcodeSuite::M218_report(const bool forReplay/*=true*/) { TERN_(MARLIN_SMALL_BUILD, return); - report_heading_etc(forReplay, F(STR_HOTEND_OFFSETS)); + report_heading(forReplay, F(STR_HOTEND_OFFSETS)); for (uint8_t e = 1; e < HOTENDS; ++e) { report_echo_start(forReplay); SERIAL_ECHOLNPGM_P( diff --git a/Marlin/src/gcode/config/M220.cpp b/Marlin/src/gcode/config/M220.cpp index 6797df25d5..0d1e204800 100644 --- a/Marlin/src/gcode/config/M220.cpp +++ b/Marlin/src/gcode/config/M220.cpp @@ -24,16 +24,15 @@ #include "../../module/motion.h" /** - * M220: Set speed percentage factor, aka "Feed Rate" + * M220: Set Feedrate Percentage * - * Parameters - * S : Set the feed rate percentage factor + * Parameters: + * None Report the current speed percentage factor + * S Set the feed rate percentage factor * - * Report the current speed percentage factor if no parameter is specified - * - * For MMU2 and MMU2S devices... - * B : Flag to back up the current factor - * R : Flag to restore the last-saved factor + * For MMU2 and MMU2S devices: + * B Back up the current factor + * R Restore the last-saved factor */ void GcodeSuite::M220() { if (!parser.seen_any()) { diff --git a/Marlin/src/gcode/config/M301.cpp b/Marlin/src/gcode/config/M301.cpp index fe0eef772f..a47c03a8d4 100644 --- a/Marlin/src/gcode/config/M301.cpp +++ b/Marlin/src/gcode/config/M301.cpp @@ -28,22 +28,22 @@ #include "../../module/temperature.h" /** - * M301: Set PID parameters P I D (and optionally C, L) + * M301: Set Hotend PID * - * E[extruder] Default: 0 + * Set PID parameters P I D (and optionally C, L) * - * P[float] Kp term - * I[float] Ki term (unscaled) - * D[float] Kd term (unscaled) + * Parameters: + * E Default: 0 + * P Kp term + * I Ki term (unscaled) + * D Kd term (unscaled) * - * With PID_EXTRUSION_SCALING: + * With PID_EXTRUSION_SCALING: + * C Kc term + * L LPQ length * - * C[float] Kc term - * L[int] LPQ length - * - * With PID_FAN_SCALING: - * - * F[float] Kf term + * With PID_FAN_SCALING: + * F Kf term */ void GcodeSuite::M301() { // multi-extruder PID patch: M301 updates or prints a single extruder's PID values diff --git a/Marlin/src/gcode/config/M43.cpp b/Marlin/src/gcode/config/M43.cpp index 893607792a..9410fea136 100644 --- a/Marlin/src/gcode/config/M43.cpp +++ b/Marlin/src/gcode/config/M43.cpp @@ -25,7 +25,6 @@ #if ENABLED(PINS_DEBUGGING) #include "../gcode.h" -#include "../../MarlinCore.h" // for pin_is_protected, wait_for_user #include "../../pins/pinsDebug.h" #include "../../module/endstops.h" @@ -64,7 +63,7 @@ inline void toggle_pins() { for (uint8_t i = start; i <= end; ++i) { pin_t pin = GET_PIN_MAP_PIN_M43(i); if (!isValidPin(pin)) continue; - if (M43_NEVER_TOUCH(i) || (!ignore_protection && pin_is_protected(pin))) { + if (M43_NEVER_TOUCH(i) || (!ignore_protection && marlin.pin_is_protected(pin))) { printPinStateExt(pin, ignore_protection, true, F("Untouched ")); SERIAL_EOL(); } @@ -79,20 +78,20 @@ inline void toggle_pins() { #endif ); #if AVR_AT90USB1286_FAMILY // Teensy IDEs don't know about these pins so must use FASTIO - if (pin == TEENSY_E2) { - SET_OUTPUT(TEENSY_E2); + if (pin == PIN_E2) { + SET_OUTPUT(PIN_E2); for (int16_t j = 0; j < repeat; j++) { - WRITE(TEENSY_E2, LOW); safe_delay(wait); - WRITE(TEENSY_E2, HIGH); safe_delay(wait); - WRITE(TEENSY_E2, LOW); safe_delay(wait); + WRITE(PIN_E2, LOW); safe_delay(wait); + WRITE(PIN_E2, HIGH); safe_delay(wait); + WRITE(PIN_E2, LOW); safe_delay(wait); } } - else if (pin == TEENSY_E3) { - SET_OUTPUT(TEENSY_E3); + else if (pin == PIN_E3) { + SET_OUTPUT(PIN_E3); for (int16_t j = 0; j < repeat; j++) { - WRITE(TEENSY_E3, LOW); safe_delay(wait); - WRITE(TEENSY_E3, HIGH); safe_delay(wait); - WRITE(TEENSY_E3, LOW); safe_delay(wait); + WRITE(PIN_E3, LOW); safe_delay(wait); + WRITE(PIN_E3, HIGH); safe_delay(wait); + WRITE(PIN_E3, LOW); safe_delay(wait); } } else @@ -154,37 +153,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 @@ -329,7 +327,7 @@ void GcodeSuite::M43() { for (uint8_t i = first_pin; i <= last_pin; ++i) { pin_t pin = GET_PIN_MAP_PIN_M43(i); if (!isValidPin(pin)) continue; - if (M43_NEVER_TOUCH(i) || (!ignore_protection && pin_is_protected(pin))) continue; + if (M43_NEVER_TOUCH(i) || (!ignore_protection && marlin.pin_is_protected(pin))) continue; can_watch = true; pinMode(pin, INPUT_PULLUP); delay(1); @@ -359,7 +357,7 @@ void GcodeSuite::M43() { #if HAS_RESUME_CONTINUE KEEPALIVE_STATE(PAUSED_FOR_USER); - wait_for_user = true; + marlin.wait_start(); TERN_(HOST_PROMPT_SUPPORT, hostui.continue_prompt(F("M43 Waiting..."))); #if ENABLED(EXTENSIBLE_UI) ExtUI::onUserConfirmRequired(F("M43 Waiting...")); @@ -372,7 +370,7 @@ void GcodeSuite::M43() { for (uint8_t i = first_pin; i <= last_pin; ++i) { const pin_t pin = GET_PIN_MAP_PIN_M43(i); if (!isValidPin(pin)) continue; - if (M43_NEVER_TOUCH(i) || (!ignore_protection && pin_is_protected(pin))) continue; + if (M43_NEVER_TOUCH(i) || (!ignore_protection && marlin.pin_is_protected(pin))) continue; const byte val = /* isAnalogPin(pin) @@ -388,7 +386,7 @@ void GcodeSuite::M43() { #if HAS_RESUME_CONTINUE ui.update(); - if (!wait_for_user) break; + if (!marlin.wait_for_user) break; #endif safe_delay(200); diff --git a/Marlin/src/gcode/config/M550.cpp b/Marlin/src/gcode/config/M550.cpp new file mode 100644 index 0000000000..ed7dc49159 --- /dev/null +++ b/Marlin/src/gcode/config/M550.cpp @@ -0,0 +1,58 @@ +/** + * 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 . + * + */ + +#include "../../inc/MarlinConfig.h" + +#if ENABLED(CONFIGURABLE_MACHINE_NAME) + +#include "../gcode.h" +#include "../../lcd/marlinui.h" + +/** + * M550: Set machine name + * + * Parameters: + * P "" Set the name using the 'P' parameter (RepRapFirmware) + * "" Set the name using the "string" parameter + */ +void GcodeSuite::M550() { + bool did_set = true; + + if (parser.seenval('P')) + marlin.machine_name = parser.value_string(); + else if (TERN(GCODE_QUOTED_STRINGS, false, parser.seen('P'))) + marlin.machine_name = parser.string_arg[0] == 'P' ? &parser.string_arg[1] : parser.string_arg; + else if (parser.has_string()) + marlin.machine_name = parser.string_arg; + else + did_set = false; + + if (did_set) { + marlin.machine_name.trim(); + ui.reset_status(false); + } + else + SERIAL_ECHOLNPGM("RepRap name: ", &marlin.machine_name); + +} + +#endif // CONFIGURABLE_MACHINE_NAME diff --git a/Marlin/src/gcode/config/M575.cpp b/Marlin/src/gcode/config/M575.cpp index 2c12428d98..dd8f8addb5 100644 --- a/Marlin/src/gcode/config/M575.cpp +++ b/Marlin/src/gcode/config/M575.cpp @@ -51,25 +51,25 @@ void GcodeSuite::M575() { switch (baud) { case 2400: case 9600: case 19200: case 38400: case 57600: case 115200: case 250000: case 500000: case 1000000: { + SERIAL_FLUSH(); + const int8_t port = parser.intval('P', -99); const bool set1 = (port == -99 || port == 0); - if (set1) SERIAL_ECHO_MSG(" Serial ", AS_DIGIT(0), " baud rate set to ", baud); + if (set1) { MYSERIAL1.end(); MYSERIAL1.begin(baud); } #if HAS_MULTI_SERIAL const bool set2 = (port == -99 || port == 1); - if (set2) SERIAL_ECHO_MSG(" Serial ", AS_DIGIT(1), " baud rate set to ", baud); + if (set2) { MYSERIAL2.end(); MYSERIAL2.begin(baud); } #ifdef SERIAL_PORT_3 const bool set3 = (port == -99 || port == 2); - if (set3) SERIAL_ECHO_MSG(" Serial ", AS_DIGIT(2), " baud rate set to ", baud); + if (set3) { MYSERIAL3.end(); MYSERIAL3.begin(baud); } #endif #endif - SERIAL_FLUSH(); - - if (set1) { MYSERIAL1.end(); MYSERIAL1.begin(baud); } + if (set1) SERIAL_ECHO_MSG(" Serial ", AS_DIGIT(0), " baud rate set to ", baud); #if HAS_MULTI_SERIAL - if (set2) { MYSERIAL2.end(); MYSERIAL2.begin(baud); } + if (set2) SERIAL_ECHO_MSG(" Serial ", AS_DIGIT(1), " baud rate set to ", baud); #ifdef SERIAL_PORT_3 - if (set3) { MYSERIAL3.end(); MYSERIAL3.begin(baud); } + if (set3) SERIAL_ECHO_MSG(" Serial ", AS_DIGIT(2), " baud rate set to ", baud); #endif #endif diff --git a/Marlin/src/gcode/config/M92.cpp b/Marlin/src/gcode/config/M92.cpp index 2a5eb30f55..48c3c5f2f0 100644 --- a/Marlin/src/gcode/config/M92.cpp +++ b/Marlin/src/gcode/config/M92.cpp @@ -101,7 +101,7 @@ void GcodeSuite::M92_report(const bool forReplay/*=true*/, const int8_t e/*=-1*/ report_heading_etc(forReplay, F(STR_STEPS_PER_UNIT)); #if NUM_AXES #define PRINT_EOL - SERIAL_ECHOPGM_P(LIST_N(DOUBLE(NUM_AXES), + SERIAL_ECHOPGM_P(NUM_AXIS_PAIRED_LIST( PSTR(" M92 X"), LINEAR_UNIT(planner.settings.axis_steps_per_mm[X_AXIS]), SP_Y_STR, LINEAR_UNIT(planner.settings.axis_steps_per_mm[Y_AXIS]), SP_Z_STR, LINEAR_UNIT(planner.settings.axis_steps_per_mm[Z_AXIS]), diff --git a/Marlin/src/gcode/control/M108_M112_M410.cpp b/Marlin/src/gcode/control/M108_M112_M410.cpp index 39f9c04e19..e2ca9b2247 100644 --- a/Marlin/src/gcode/control/M108_M112_M410.cpp +++ b/Marlin/src/gcode/control/M108_M112_M410.cpp @@ -21,26 +21,21 @@ */ #include "../../inc/MarlinConfig.h" - -#if DISABLED(EMERGENCY_PARSER) - #include "../gcode.h" -#include "../../MarlinCore.h" // for wait_for_heatup, kill, M112_KILL_STR #include "../../module/motion.h" // for quickstop_stepper /** * M108: Stop the waiting for heaters in M109, M190, M303. Does not affect the target temperature. */ void GcodeSuite::M108() { - TERN_(HAS_RESUME_CONTINUE, wait_for_user = false); - wait_for_heatup = false; + marlin.end_waiting(); } /** * M112: Full Shutdown */ void GcodeSuite::M112() { - kill(FPSTR(M112_KILL_STR), nullptr, true); + marlin.kill(FPSTR(M112_KILL_STR), nullptr, true); } /** @@ -52,5 +47,3 @@ void GcodeSuite::M112() { void GcodeSuite::M410() { quickstop_stepper(); } - -#endif // !EMERGENCY_PARSER diff --git a/Marlin/src/gcode/control/M17_M18_M84.cpp b/Marlin/src/gcode/control/M17_M18_M84.cpp index 1742d288b3..90563889f3 100644 --- a/Marlin/src/gcode/control/M17_M18_M84.cpp +++ b/Marlin/src/gcode/control/M17_M18_M84.cpp @@ -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 } diff --git a/Marlin/src/gcode/control/M211.cpp b/Marlin/src/gcode/control/M211.cpp index 471ca6c448..e51a9d5297 100644 --- a/Marlin/src/gcode/control/M211.cpp +++ b/Marlin/src/gcode/control/M211.cpp @@ -43,8 +43,7 @@ void GcodeSuite::M211_report(const bool forReplay/*=true*/) { TERN_(MARLIN_SMALL_BUILD, return); report_heading_etc(forReplay, F(STR_SOFT_ENDSTOPS)); - SERIAL_ECHOPGM(" M211 S", AS_DIGIT(soft_endstop._enabled), " ; "); - serialprintln_onoff(soft_endstop._enabled); + SERIAL_ECHOLNPGM(" M211 S", AS_DIGIT(soft_endstop._enabled), " ; ", ON_OFF(soft_endstop._enabled)); report_echo_start(forReplay); const xyz_pos_t l_soft_min = soft_endstop.min.asLogical(), diff --git a/Marlin/src/gcode/control/M226.cpp b/Marlin/src/gcode/control/M226.cpp index 4eb3db4bc3..921ce0d4c2 100644 --- a/Marlin/src/gcode/control/M226.cpp +++ b/Marlin/src/gcode/control/M226.cpp @@ -25,7 +25,6 @@ #if ENABLED(DIRECT_PIN_CONTROL) #include "../gcode.h" -#include "../../MarlinCore.h" // for pin_is_protected and idle() #include "../../module/planner.h" void protected_pin_err(); @@ -40,7 +39,7 @@ void GcodeSuite::M226() { const pin_t pin = GET_PIN_MAP_PIN(pin_number); if (WITHIN(pin_state, -1, 1) && pin > -1) { - if (pin_is_protected(pin)) + if (marlin.pin_is_protected(pin)) protected_pin_err(); else { int target = LOW; @@ -51,7 +50,7 @@ void GcodeSuite::M226() { case 0: target = LOW; break; case -1: target = !extDigitalRead(pin); break; } - while (int(extDigitalRead(pin)) != target) idle(); + while (int(extDigitalRead(pin)) != target) marlin.idle(); } } // pin_state -1 0 1 && pin > -1 } // parser.seen('P') diff --git a/Marlin/src/gcode/control/M350_M351.cpp b/Marlin/src/gcode/control/M350_M351.cpp index 425abad529..76753b2ea9 100644 --- a/Marlin/src/gcode/control/M350_M351.cpp +++ b/Marlin/src/gcode/control/M350_M351.cpp @@ -27,7 +27,7 @@ #include "../gcode.h" #include "../../module/stepper.h" -#if NUM_AXES == XYZ && EXTRUDERS >= 1 +#if NUM_AXES == 3 && EXTRUDERS >= 1 #define HAS_M350_B_PARAM 1 // "5th axis" (after E0) for an original XYZEB setup. #endif diff --git a/Marlin/src/gcode/control/M42.cpp b/Marlin/src/gcode/control/M42.cpp index b995f208f5..717b0695a4 100644 --- a/Marlin/src/gcode/control/M42.cpp +++ b/Marlin/src/gcode/control/M42.cpp @@ -37,8 +37,6 @@ #define OUTPUT_OPEN_DRAIN OUTPUT_OPEN_DRAIN #endif -bool pin_is_protected(const pin_t pin); - void protected_pin_err() { SERIAL_ERROR_MSG(STR_ERR_PROTECTED_PIN); } @@ -46,15 +44,16 @@ void protected_pin_err() { /** * M42: Change pin status via G-Code * - * P Pin number (LED if omitted) - * For LPC1768 specify pin P1_02 as M42 P102, - * P1_20 as M42 P120, etc. + * Parameters: + * P Pin number (LED if omitted) + * For LPC1768 specify pin P1_02 as M42 P102, + * P1_20 as M42 P120, etc. * - * S Pin status from 0 - 255 - * I Flag to ignore Marlin's pin protection + * S Pin status from 0-255 + * I Flag to ignore Marlin's pin protection * - * T Pin mode: 0=INPUT 1=OUTPUT 2=INPUT_PULLUP 3=INPUT_PULLDOWN - * 4=INPUT_ANALOG 5=OUTPUT_OPEN_DRAIN + * T Pin mode: 0=INPUT | 1=OUTPUT | 2=INPUT_PULLUP | 3=INPUT_PULLDOWN + * 4=INPUT_ANALOG | 5=OUTPUT_OPEN_DRAIN */ void GcodeSuite::M42() { const int pin_index = PARSED_PIN_INDEX('P', GET_PIN_MAP_INDEX(LED_PIN)); @@ -62,7 +61,7 @@ void GcodeSuite::M42() { const pin_t pin = GET_PIN_MAP_PIN(pin_index); - if (!parser.boolval('I') && pin_is_protected(pin)) return protected_pin_err(); + if (!parser.boolval('I') && marlin.pin_is_protected(pin)) return protected_pin_err(); bool avoidWrite = false; if (parser.seenval('T')) { diff --git a/Marlin/src/gcode/control/M605.cpp b/Marlin/src/gcode/control/M605.cpp index 167cdae4a9..bf5549262d 100644 --- a/Marlin/src/gcode/control/M605.cpp +++ b/Marlin/src/gcode/control/M605.cpp @@ -115,7 +115,7 @@ else if (!parser.seen('W')) // if no S or W parameter, the DXC mode gets reset to the user's default dual_x_carriage_mode = DEFAULT_DUAL_X_CARRIAGE_MODE; - #ifdef DEBUG_DXC_MODE + #if ENABLED(DEBUG_DXC_MODE) if (parser.seen('W')) { DEBUG_ECHO_START(); @@ -155,13 +155,16 @@ #elif ENABLED(MULTI_NOZZLE_DUPLICATION) /** - * M605: Set multi-nozzle duplication mode + * M605: Multi Nozzle Mode * - * S2 - Enable duplication mode - * P[mask] - Bit-mask of nozzles to include in the duplication set. - * A value of 0 disables duplication. - * E[index] - Last nozzle index to include in the duplication set. - * A value of 0 disables duplication. + * Set multi-nozzle duplication mode. + * + * Parameters: + * S2 Enable duplication mode + * P Bit-mask of nozzles to include in the duplication set + * A value of 0 disables duplication + * E Last nozzle index to include in the duplication set + * A value of 0 disables duplication */ void GcodeSuite::M605() { bool ena = false; @@ -173,8 +176,7 @@ set_duplication_enabled(ena && (duplication_e_mask >= 3)); } SERIAL_ECHO_START(); - SERIAL_ECHOPGM(STR_DUPLICATION_MODE); - serialprint_onoff(extruder_duplication_enabled); + SERIAL_ECHOPGM(STR_DUPLICATION_MODE, ON_OFF(extruder_duplication_enabled)); if (ena) { SERIAL_ECHOPGM(" ( "); HOTEND_LOOP() if (TEST(duplication_e_mask, e)) { SERIAL_ECHO(e); SERIAL_CHAR(' '); } diff --git a/Marlin/src/gcode/control/M80_M81.cpp b/Marlin/src/gcode/control/M80_M81.cpp index 8a52d49d9a..a7653a4037 100644 --- a/Marlin/src/gcode/control/M80_M81.cpp +++ b/Marlin/src/gcode/control/M80_M81.cpp @@ -38,7 +38,7 @@ #include "../../feature/powerloss.h" #endif -#if HAS_SUICIDE +#if ANY(HAS_SUICIDE, CONFIGURABLE_MACHINE_NAME) #include "../../MarlinCore.h" #endif @@ -92,7 +92,11 @@ void GcodeSuite::M81() { safe_delay(1000); // Wait 1 second before switching off - LCD_MESSAGE_F(MACHINE_NAME " " STR_OFF "."); + #if ENABLED(CONFIGURABLE_MACHINE_NAME) + ui.set_status(&MString<30>(&marlin.machine_name, ' ', F(STR_OFF), '.')); + #else + LCD_MESSAGE_F(MACHINE_NAME " " STR_OFF "."); + #endif bool delayed_power_off = false; @@ -121,6 +125,6 @@ void GcodeSuite::M81() { #if ENABLED(PSU_CONTROL) powerManager.power_off_soon(); #elif HAS_SUICIDE - suicide(); + marlin.suicide(); #endif } diff --git a/Marlin/src/gcode/control/M993_M994.cpp b/Marlin/src/gcode/control/M993_M994.cpp index bc634ae13c..392c37234e 100644 --- a/Marlin/src/gcode/control/M993_M994.cpp +++ b/Marlin/src/gcode/control/M993_M994.cpp @@ -49,7 +49,8 @@ void GcodeSuite::M993() { W25QXX.SPI_FLASH_BufferRead(buf, addr, COUNT(buf)); addr += COUNT(buf); card.write(buf, COUNT(buf)); - if (addr % (COUNT(buf) * 10) == 0) SERIAL_CHAR('.'); + if (!(addr % (COUNT(buf) * 10))) SERIAL_CHAR('.'); + if (!(addr % (COUNT(buf) * 32))) hal.watchdog_refresh(); } SERIAL_ECHOLNPGM(" done"); @@ -78,7 +79,8 @@ void GcodeSuite::M994() { card.read(buf, COUNT(buf)); W25QXX.SPI_FLASH_BufferWrite(buf, addr, COUNT(buf)); addr += COUNT(buf); - if (addr % (COUNT(buf) * 10) == 0) SERIAL_CHAR('.'); + if (!(addr % (COUNT(buf) * 10))) SERIAL_CHAR('.'); + if (!(addr % (COUNT(buf) * 32))) hal.watchdog_refresh(); } SERIAL_ECHOLNPGM(" done"); diff --git a/Marlin/src/gcode/control/M999.cpp b/Marlin/src/gcode/control/M999.cpp index b4278fccad..863ab8eb90 100644 --- a/Marlin/src/gcode/control/M999.cpp +++ b/Marlin/src/gcode/control/M999.cpp @@ -23,7 +23,7 @@ #include "../gcode.h" #include "../../lcd/marlinui.h" // for ui.reset_alert_level -#include "../../MarlinCore.h" // for marlin_state +#include "../../MarlinCore.h" // for setState #include "../queue.h" // for flush_and_request_resend /** @@ -36,7 +36,7 @@ * existing command buffer. */ void GcodeSuite::M999() { - marlin_state = MarlinState::MF_RUNNING; + marlin.setState(MF_RUNNING); ui.reset_alert_level(); if (parser.boolval('S')) return; diff --git a/Marlin/src/gcode/control/T.cpp b/Marlin/src/gcode/control/T.cpp index 9f6fb2bb00..d5affa37e2 100644 --- a/Marlin/src/gcode/control/T.cpp +++ b/Marlin/src/gcode/control/T.cpp @@ -43,14 +43,15 @@ /** * T0-T: Switch tool, usually switching extruders * - * F[units/min] Set the movement feedrate - * S1 Don't move the tool in XY after change + * Parameters: + * F Set the movement feedrate + * S1 Don't move the tool in XY after change * - * For PRUSA_MMU2(S) and EXTENDABLE_EMU_MMU2(S) - * T[n] G-code to extrude at least 38.10 mm at feedrate 19.02 mm/s must follow immediately to load to extruder wheels. - * T? G-code to extrude shouldn't have to follow. Load to extruder wheels is done automatically. - * Tx Same as T?, but nozzle doesn't have to be preheated. Tc requires a preheated nozzle to finish filament load. - * Tc Load to nozzle after filament was prepared by Tc and nozzle is already heated. + * For PRUSA_MMU2(S) and EXTENDABLE_EMU_MMU2(S) + * T G-code to extrude at least 38.10 mm at feedrate 19.02 mm/s must follow immediately to load to extruder wheels. + * T? G-code to extrude shouldn't have to follow. Load to extruder wheels is done automatically. + * Tx Same as T?, but nozzle doesn't have to be preheated. Tc requires a preheated nozzle to finish filament load. + * Tc Load to nozzle after filament was prepared by Tc and nozzle is already heated. */ void GcodeSuite::T(const int8_t tool_index) { @@ -69,7 +70,7 @@ void GcodeSuite::T(const int8_t tool_index) { reset_stepper_timeout(); #if HAS_PRUSA_MMU3 - if (parser.string_arg) { + if (parser.has_string()) { mmu3.tool_change(parser.string_arg[0], uint8_t(tool_index)); // Special commands T?/Tx/Tc return; } diff --git a/Marlin/src/gcode/feature/advance/M900.cpp b/Marlin/src/gcode/feature/advance/M900.cpp index e8a16d952f..7631cd0e8c 100644 --- a/Marlin/src/gcode/feature/advance/M900.cpp +++ b/Marlin/src/gcode/feature/advance/M900.cpp @@ -22,22 +22,28 @@ #include "../../../inc/MarlinConfig.h" -#if ENABLED(LIN_ADVANCE) +#if HAS_LIN_ADVANCE_K #include "../../gcode.h" #include "../../../module/planner.h" +#include "../../../module/stepper.h" #if ENABLED(ADVANCE_K_EXTRA) - float other_extruder_advance_K[DISTINCT_E]; + float other_extruder_advance_K[EXTRUDERS]; uint8_t lin_adv_slot = 0; #endif /** * M900: Get or Set Linear Advance K-factor * T Which tool to address - * K Set current advance K factor (Slot 0). - * L Set secondary advance K factor (Slot 1). Requires ADVANCE_K_EXTRA. - * S<0/1> Activate slot 0 or 1. Requires ADVANCE_K_EXTRA. + * K Set current advance K factor (aka Slot 0). + * + * With ADVANCE_K_EXTRA: + * S<0/1> Activate slot 0 or 1. + * L Set secondary advance K factor (Slot 1). + * + * With SMOOTH_LIN_ADVANCE: + * U Set a tau value for LA smoothing */ void GcodeSuite::M900() { @@ -59,38 +65,43 @@ void GcodeSuite::M900() { } #endif - float &kref = planner.extruder_advance_K[E_INDEX_N(tool_index)], newK = kref; - const float oldK = newK; + const float oldK = planner.get_advance_k(tool_index); + float newK = oldK; + + #if ENABLED(SMOOTH_LIN_ADVANCE) + const float oldU = stepper.get_advance_tau(tool_index); + float newU = oldU; + #endif #if ENABLED(ADVANCE_K_EXTRA) - float &lref = other_extruder_advance_K[E_INDEX_N(tool_index)]; + float &lref = other_extruder_advance_K[tool_index]; - const bool old_slot = TEST(lin_adv_slot, tool_index), // The tool's current slot (0 or 1) - new_slot = parser.boolval('S', old_slot); // The passed slot (default = current) + const bool old_slot = TEST(lin_adv_slot, tool_index), // Each tool uses 1 bit to store its current slot (0 or 1) + new_slot = parser.boolval('S', old_slot); // The new slot (0 or 1) to set for the tool (default = no change) // If a new slot is being selected swap the current and // saved K values. Do here so K/L will apply correctly. if (new_slot != old_slot) { // Not the same slot? SET_BIT_TO(lin_adv_slot, tool_index, new_slot); // Update the slot for the tool - newK = lref; // Get new K value from backup - lref = oldK; // Save K to backup + newK = lref; // Get the backup K value (to apply below) + lref = oldK; // Back up the active K value } // Set the main K value. Apply if the main slot is active. if (parser.seenval('K')) { const float K = parser.value_float(); if (!WITHIN(K, 0, 10)) echo_value_oor('K'); - else if (new_slot) lref = K; // S1 Knn - else newK = K; // S0 Knn + else if (new_slot) lref = K; // S1 Knn (set main K in its backup slot) + else newK = K; // S0 Knn (use main K now) } // Set the extra K value. Apply if the extra slot is active. if (parser.seenval('L')) { const float L = parser.value_float(); if (!WITHIN(L, 0, 10)) echo_value_oor('L'); - else if (!new_slot) lref = L; // S0 Lnn - else newK = L; // S1 Lnn + else if (!new_slot) lref = L; // S0 Lnn (set extra K in its backup slot) + else newK = L; // S1 Lnn (use extra K now) } #else @@ -105,37 +116,59 @@ void GcodeSuite::M900() { #endif - if (newK != oldK) { + #if ENABLED(SMOOTH_LIN_ADVANCE) + if (parser.seenval('U')) { + const float tau = parser.value_float(); + if (WITHIN(tau, 0.0f, 0.5f)) + newU = tau; + else + echo_value_oor('U'); + } + #endif + + if (newK != oldK || TERN0(SMOOTH_LIN_ADVANCE, newU != oldU)) { planner.synchronize(); - kref = newK; + if (newK != oldK) planner.set_advance_k(newK, tool_index); + #if ENABLED(SMOOTH_LIN_ADVANCE) + if (newU != oldU) stepper.set_advance_tau(newU, tool_index); + #endif } if (!parser.seen_any()) { #if ENABLED(ADVANCE_K_EXTRA) - #if DISTINCT_E < 2 - SERIAL_ECHOLNPGM("Advance S", new_slot, " K", kref, "(S", !new_slot, " K", lref, ")"); + #if DISABLED(DISTINCT_E_FACTORS) + SERIAL_ECHOLNPGM("Advance S", new_slot, " K", newK, "(S", !new_slot, " K", lref, ")"); #else EXTRUDER_LOOP() { const bool slot = TEST(lin_adv_slot, e); - SERIAL_ECHOLNPGM("Advance T", e, " S", slot, " K", planner.extruder_advance_K[e], + SERIAL_ECHOLNPGM("Advance T", e, " S", slot, " K", planner.get_advance_k(e), "(S", !slot, " K", other_extruder_advance_K[e], ")"); } #endif - #else + #else // !ADVANCE_K_EXTRA SERIAL_ECHO_START(); - #if DISTINCT_E < 2 - SERIAL_ECHOLNPGM("Advance K=", planner.extruder_advance_K[0]); + #if DISABLED(DISTINCT_E_FACTORS) + SERIAL_ECHOPGM("Advance K=", planner.get_advance_k()); + #if ENABLED(SMOOTH_LIN_ADVANCE) + SERIAL_ECHOPGM(" TAU=", stepper.get_advance_tau()); + #endif + SERIAL_EOL(); #else SERIAL_ECHOPGM("Advance K"); - EXTRUDER_LOOP() SERIAL_ECHO(C(' '), C('0' + e), C(':'), planner.extruder_advance_K[e]); + EXTRUDER_LOOP() SERIAL_ECHO(C(' '), C('0' + e), C(':'), planner.get_advance_k(e)); SERIAL_EOL(); + #if ENABLED(SMOOTH_LIN_ADVANCE) + SERIAL_ECHOPGM("Advance TAU"); + EXTRUDER_LOOP() SERIAL_ECHO(C(' '), C('0' + e), C(':'), stepper.get_advance_tau(e)); + SERIAL_EOL(); + #endif #endif - #endif + #endif // !ADVANCE_K_EXTRA } } @@ -144,15 +177,21 @@ void GcodeSuite::M900_report(const bool forReplay/*=true*/) { TERN_(MARLIN_SMALL_BUILD, return); report_heading(forReplay, F(STR_LINEAR_ADVANCE)); - #if DISTINCT_E < 2 + DISTINCT_E_LOOP() { report_echo_start(forReplay); - SERIAL_ECHOLNPGM(" M900 K", planner.extruder_advance_K[0]); - #else - EXTRUDER_LOOP() { - report_echo_start(forReplay); - SERIAL_ECHOLNPGM(" M900 T", e, " K", planner.extruder_advance_K[e]); - } - #endif + SERIAL_ECHOPGM( + #if ENABLED(DISTINCT_E_FACTORS) + " M900 T", e, " K" + #else + " M900 K" + #endif + ); + SERIAL_ECHO(planner.get_advance_k(e)); + #if ENABLED(SMOOTH_LIN_ADVANCE) + SERIAL_ECHOPGM(" U", stepper.get_advance_tau(e)); + #endif + SERIAL_EOL(); + } } -#endif // LIN_ADVANCE +#endif // HAS_LIN_ADVANCE_K diff --git a/Marlin/src/gcode/feature/camera/M240.cpp b/Marlin/src/gcode/feature/camera/M240.cpp index bb1d3f9eee..8bf0f5d539 100644 --- a/Marlin/src/gcode/feature/camera/M240.cpp +++ b/Marlin/src/gcode/feature/camera/M240.cpp @@ -31,10 +31,6 @@ millis_t chdk_timeout; // = 0 #endif -#if defined(PHOTO_POSITION) && PHOTO_DELAY_MS > 0 - #include "../../../MarlinCore.h" // for idle() -#endif - #ifdef PHOTO_RETRACT_MM #define _PHOTO_RETRACT_MM (PHOTO_RETRACT_MM + 0) @@ -47,7 +43,7 @@ #endif #ifdef PHOTO_RETRACT_MM - inline void e_move_m240(const float length, const_feedRate_t fr_mm_s) { + inline void e_move_m240(const float length, const feedRate_t fr_mm_s) { if (length && thermalManager.hotEnoughToExtrude(active_extruder)) unscaled_e_move(length, fr_mm_s); } @@ -185,7 +181,7 @@ void GcodeSuite::M240() { #ifdef PHOTO_POSITION #if PHOTO_DELAY_MS > 0 const millis_t timeout = millis() + parser.intval('P', PHOTO_DELAY_MS); - while (PENDING(millis(), timeout)) idle(); + while (PENDING(millis(), timeout)) marlin.idle(); #endif do_blocking_move_to(old_pos, fr_mm_s); #ifdef PHOTO_RETRACT_MM diff --git a/Marlin/src/gcode/feature/cancel/M486.cpp b/Marlin/src/gcode/feature/cancel/M486.cpp index 37347e9d43..237654e433 100644 --- a/Marlin/src/gcode/feature/cancel/M486.cpp +++ b/Marlin/src/gcode/feature/cancel/M486.cpp @@ -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()); diff --git a/Marlin/src/gcode/feature/controllerfan/M710.cpp b/Marlin/src/gcode/feature/controllerfan/M710.cpp index c8b5efa8cb..6bdfcd9b32 100644 --- a/Marlin/src/gcode/feature/controllerfan/M710.cpp +++ b/Marlin/src/gcode/feature/controllerfan/M710.cpp @@ -46,24 +46,22 @@ * M710 I127 A1 S255 D160 ; Set controller fan idle speed 50%, AutoMode On, Fan speed 100%, duration to 160 Secs */ void GcodeSuite::M710() { + if (!parser.seen("ADIRS")) return M710_report(); - const bool seenR = parser.seen('R'); - if (seenR) controllerFan.reset(); + if (parser.seen_test('R')) + controllerFan.reset(); - const bool seenS = parser.seenval('S'); - if (seenS) controllerFan.settings.active_speed = parser.value_byte(); + if (parser.seenval('S')) + controllerFan.settings.active_speed = parser.value_byte(); - const bool seenI = parser.seenval('I'); - if (seenI) controllerFan.settings.idle_speed = parser.value_byte(); + if (parser.seenval('I')) + controllerFan.settings.idle_speed = parser.value_byte(); - const bool seenA = parser.seenval('A'); - if (seenA) controllerFan.settings.auto_mode = parser.value_bool(); + if (parser.seenval('A')) + controllerFan.settings.auto_mode = parser.value_bool(); - const bool seenD = parser.seenval('D'); - if (seenD) controllerFan.settings.duration = parser.value_ushort(); - - if (!(seenR || seenS || seenI || seenA || seenD)) - M710_report(); + if (parser.seenval('D')) + controllerFan.settings.duration = parser.value_ushort(); } void GcodeSuite::M710_report(const bool forReplay/*=true*/) { diff --git a/Marlin/src/gcode/feature/digipot/M907-M910.cpp b/Marlin/src/gcode/feature/digipot/M907-M910.cpp index ab1c316705..425d27a72d 100644 --- a/Marlin/src/gcode/feature/digipot/M907-M910.cpp +++ b/Marlin/src/gcode/feature/digipot/M907-M910.cpp @@ -46,15 +46,32 @@ * Set percentage of max current for all axes (Requires HAS_DIGIPOT_DAC) */ void GcodeSuite::M907() { + #if HAS_MOTOR_CURRENT_SPI if (!parser.seen("BS" STR_AXES_LOGICAL)) return M907_report(); - if (parser.seenval('S')) for (uint8_t i = 0; i < MOTOR_CURRENT_COUNT; ++i) stepper.set_digipot_current(i, parser.value_int()); - LOOP_LOGICAL_AXES(i) if (parser.seenval(IAXIS_CHAR(i))) stepper.set_digipot_current(i, parser.value_int()); // X Y Z (I J K U V W) E (map to drivers according to DIGIPOT_CHANNELS. Default with NUM_AXES 3: map X Y Z E to X Y Z E0) - // Additional extruders use B,C. - // TODO: Change these parameters because 'E' is used and D should be reserved for debugging. B? + // S - Set current in mA for all axes + if (parser.seenval('S')) + for (uint8_t i = 0; i < MOTOR_CURRENT_COUNT; ++i) + stepper.set_digipot_current(i, parser.value_int()); + + // X Y Z I J K U V W E + // Map to drivers according to pots addresses. + // Default with NUM_AXES 3: map X Y Z E to X Y Z E0. + LOOP_LOGICAL_AXES(i) + if (parser.seenval(IAXIS_CHAR(i))) + stepper.set_digipot_current(i, parser.value_int()); + + /** + * Additional extruders use B,C in this legacy protocol + * TODO: Update to allow for an index with X, Y, Z, E axis to isolate a single stepper + * and use configured axis names instead of IJKUVW. i.e., Match the behavior of + * other G-codes that set stepper-specific parameters. If necessary deprecate G-codes. + * Bonus Points: Standardize a method that all G-codes can use to refer to one or + * more steppers/drivers and apply to various G-codes. + */ #if E_STEPPERS >= 2 if (parser.seenval('B')) stepper.set_digipot_current(E_AXIS + 1, parser.value_int()); #if E_STEPPERS >= 3 @@ -68,58 +85,88 @@ void GcodeSuite::M907() { #define HAS_X_Y_XY_I_J_K_U_V_W 1 #endif - #if HAS_X_Y_XY_I_J_K_U_V_W || HAS_MOTOR_CURRENT_PWM_E || PIN_EXISTS(MOTOR_CURRENT_PWM_Z) + #if ANY(HAS_X_Y_XY_I_J_K_U_V_W, HAS_MOTOR_CURRENT_PWM_E, HAS_MOTOR_CURRENT_PWM_Z) if (!parser.seen("S" #if HAS_X_Y_XY_I_J_K_U_V_W - "XY" SECONDARY_AXIS_GANG("I", "J", "K", "U", "V", "W") - #endif - #if PIN_EXISTS(MOTOR_CURRENT_PWM_Z) - "Z" - #endif - #if HAS_MOTOR_CURRENT_PWM_E - "E" + NUM_AXIS_GANG("X", "Y",, "I", "J", "K", "U", "V", "W") #endif + TERN_(HAS_MOTOR_CURRENT_PWM_Z, "Z") + TERN_(HAS_MOTOR_CURRENT_PWM_E, "E") )) return M907_report(); - if (parser.seenval('S')) for (uint8_t a = 0; a < MOTOR_CURRENT_COUNT; ++a) stepper.set_digipot_current(a, parser.value_int()); + // S - Set all stepper current to the same value + if (parser.seenval('S')) { + const int16_t v = parser.value_int(); + for (uint8_t a = 0; a < MOTOR_CURRENT_COUNT; ++a) + stepper.set_digipot_current(a, v); + } - #if HAS_X_Y_XY_I_J_K_U_V_W - if (NUM_AXIS_GANG( - parser.seenval('X'), || parser.seenval('Y'), || false, - || parser.seenval('I'), || parser.seenval('J'), || parser.seenval('K'), - || parser.seenval('U'), || parser.seenval('V'), || parser.seenval('W') - )) stepper.set_digipot_current(0, parser.value_int()); - #endif - #if PIN_EXISTS(MOTOR_CURRENT_PWM_Z) - if (parser.seenval('Z')) stepper.set_digipot_current(1, parser.value_int()); - #endif - #if HAS_MOTOR_CURRENT_PWM_E - if (parser.seenval('E')) stepper.set_digipot_current(2, parser.value_int()); - #endif + // X Y I J K U V W - All aliases to set the current for "most axes." + // Only the value of the last given parameter is used. + if (ENABLED(HAS_X_Y_XY_I_J_K_U_V_W) && (NUM_AXIS_GANG( + parser.seenval('X'), || parser.seenval('Y'), || false, + || parser.seenval('I'), || parser.seenval('J'), || parser.seenval('K'), + || parser.seenval('U'), || parser.seenval('V'), || parser.seenval('W') + ))) + stepper.set_digipot_current(0, parser.value_int()); + + // Z - Set the current just for the Z axis + if (TERN0(HAS_MOTOR_CURRENT_PWM_Z, parser.seenval('Z'))) + stepper.set_digipot_current(1, parser.value_int()); + + // Z - Set the current just for the Extruder + if (TERN0(HAS_MOTOR_CURRENT_PWM_E, parser.seenval('E'))) + stepper.set_digipot_current(2, parser.value_int()); #endif #endif // HAS_MOTOR_CURRENT_PWM #if HAS_MOTOR_CURRENT_I2C - // this one uses actual amps in floating point - if (parser.seenval('S')) for (uint8_t q = 0; q < DIGIPOT_I2C_NUM_CHANNELS; ++q) digipot_i2c.set_current(q, parser.value_float()); - LOOP_LOGICAL_AXES(i) if (parser.seenval(IAXIS_CHAR(i))) digipot_i2c.set_current(i, parser.value_float()); // X Y Z (I J K U V W) E (map to drivers according to pots adresses. Default with NUM_AXES 3 X Y Z E: map to X Y Z E0) + // This current driver takes actual Amps in floating point + // rather than milli-amps or some scalar unit. + + // S - Set the same current in Amps on all channels + if (parser.seenval('S')) { + const float v = parser.value_float(); + for (uint8_t q = 0; q < DIGIPOT_I2C_NUM_CHANNELS; ++q) + digipot_i2c.set_current(q, v); + } + + // X Y Z I J K U V W E + // Map to drivers according to pots addresses. + // Default with NUM_AXES 3: map X Y Z E to X Y Z E0. + LOOP_LOGICAL_AXES(i) + if (parser.seenval(IAXIS_CHAR(i))) + digipot_i2c.set_current(i, parser.value_float()); + // Additional extruders use B,C,D. - // TODO: Change these parameters because 'E' is used and because 'D' should be reserved for debugging. B? + // TODO: Make parameters work like other axis-specific / stepper-specific. See above. #if E_STEPPERS >= 2 for (uint8_t i = E_AXIS + 1; i < _MAX(DIGIPOT_I2C_NUM_CHANNELS, (NUM_AXES + 3)); i++) - if (parser.seenval('B' + i - (E_AXIS + 1))) digipot_i2c.set_current(i, parser.value_float()); + if (parser.seenval('B' + i - (E_AXIS + 1))) + digipot_i2c.set_current(i, parser.value_float()); #endif - #endif + + #endif // HAS_MOTOR_CURRENT_I2C #if HAS_MOTOR_CURRENT_DAC + + // S - Set the same current percentage on all axes if (parser.seenval('S')) { const float dac_percent = parser.value_float(); - LOOP_LOGICAL_AXES(i) stepper_dac.set_current_percent(i, dac_percent); + LOOP_LOGICAL_AXES(i) + stepper_dac.set_current_percent(i, dac_percent); } - LOOP_LOGICAL_AXES(i) if (parser.seenval(IAXIS_CHAR(i))) stepper_dac.set_current_percent(i, parser.value_float()); // X Y Z (I J K U V W) E (map to drivers according to DAC_STEPPER_ORDER. Default with NUM_AXES 3: X Y Z E map to X Y Z E0) + + // X Y Z I J K U V W E + // Map to drivers according to pots addresses. + // Default with NUM_AXES 3: map X Y Z E to X Y Z E0. + LOOP_LOGICAL_AXES(i) + if (parser.seenval(IAXIS_CHAR(i))) + stepper_dac.set_current_percent(i, parser.value_float()); + #endif } @@ -131,8 +178,10 @@ void GcodeSuite::M907() { report_heading_etc(forReplay, F(STR_STEPPER_MOTOR_CURRENTS)); #if HAS_MOTOR_CURRENT_PWM SERIAL_ECHOLNPGM_P( // PWM-based has 3 values: - PSTR(" M907 X"), stepper.motor_current_setting[0] // X, Y, (I, J, K, U, V, W) - , SP_Z_STR, stepper.motor_current_setting[1] // Z + PSTR(" M907 X"), stepper.motor_current_setting[0] // X, Y, (I, J, K, U, V, W) + #if HAS_MOTOR_CURRENT_PWM_Z + , SP_Z_STR, stepper.motor_current_setting[1] // Z + #endif #if HAS_MOTOR_CURRENT_PWM_E , SP_E_STR, stepper.motor_current_setting[2] // E #endif diff --git a/Marlin/src/gcode/feature/filwidth/M404-M407.cpp b/Marlin/src/gcode/feature/filwidth/M404-M407.cpp index ff174ecf13..5b906760ed 100644 --- a/Marlin/src/gcode/feature/filwidth/M404-M407.cpp +++ b/Marlin/src/gcode/feature/filwidth/M404-M407.cpp @@ -26,7 +26,6 @@ #include "../../../feature/filwidth.h" #include "../../../module/planner.h" -#include "../../../MarlinCore.h" #include "../../gcode.h" /** diff --git a/Marlin/src/gcode/feature/ft_motion/M493.cpp b/Marlin/src/gcode/feature/ft_motion/M493.cpp index d5cfc82005..272c3d7ab3 100644 --- a/Marlin/src/gcode/feature/ft_motion/M493.cpp +++ b/Marlin/src/gcode/feature/ft_motion/M493.cpp @@ -27,63 +27,52 @@ #include "../../gcode.h" #include "../../../module/ft_motion.h" #include "../../../module/stepper.h" +#include "../../../lcd/marlinui.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; - case ftMotionShaper_ZVD: SERIAL_ECHOPGM("ZVD"); break; - case ftMotionShaper_ZVDD: SERIAL_ECHOPGM("ZVDD"); break; - case ftMotionShaper_ZVDDD: SERIAL_ECHOPGM("ZVDDD"); break; - case ftMotionShaper_EI: SERIAL_ECHOPGM("EI"); break; - case ftMotionShaper_2HEI: SERIAL_ECHOPGM("2 Hump EI"); break; - case ftMotionShaper_3HEI: SERIAL_ECHOPGM("3 Hump EI"); break; - case ftMotionShaper_MZV: SERIAL_ECHOPGM("MZV"); break; + TERN_(FTM_SHAPER_ZV, case ftMotionShaper_ZV: SERIAL_ECHOPGM("ZV"); break); + TERN_(FTM_SHAPER_ZVD, case ftMotionShaper_ZVD: SERIAL_ECHOPGM("ZVD"); break); + TERN_(FTM_SHAPER_ZVDD, case ftMotionShaper_ZVDD: SERIAL_ECHOPGM("ZVDD"); break); + TERN_(FTM_SHAPER_ZVDDD, case ftMotionShaper_ZVDDD: SERIAL_ECHOPGM("ZVDDD"); break); + TERN_(FTM_SHAPER_EI, case ftMotionShaper_EI: SERIAL_ECHOPGM("EI"); break); + TERN_(FTM_SHAPER_2HEI, case ftMotionShaper_2HEI: SERIAL_ECHOPGM("2 Hump EI"); break); + TERN_(FTM_SHAPER_3HEI, case ftMotionShaper_3HEI: SERIAL_ECHOPGM("3 Hump EI"); break); + TERN_(FTM_SHAPER_MZV, 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_HAS_SHAPER(X)) { - SERIAL_ECHOPGM(" with " AXIS_0_NAME); - say_shaper_type(X_AXIS); - } - #endif - #if HAS_Y_AXIS - if (AXIS_HAS_SHAPER(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_HAS_SHAPER(X) || AXIS_HAS_SHAPER(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 +86,45 @@ 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 ENABLED(FTM_SHAPER_E) + SERIAL_CHAR('E'); + SERIAL_ECHO_TERNARY(dynamic, " ", "base dynamic", "static", " shaper frequency: "); + SERIAL_ECHO(p_float_t(c.baseFreq.e, 2), F(" Hz")); + #if HAS_DYNAMIC_FREQ + if (dynamic) SERIAL_ECHO(F(" scaling: "), p_float_t(c.dynFreqK.e, 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,37 +132,62 @@ 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); + #if HAS_FTM_EI_SHAPING + #define Q_REPORT(A) , F(" Q"), c.vtol.A + #else + #define Q_REPORT(A) #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 \ + Q_REPORT(A) \ + ); + // Shaper type for each axis + SHAPED_MAP(_REPORT_M493_AXIS); } /** * M493: Set Fixed-time Motion Control parameters * - * S Set Fixed-Time motion mode on or off. + * S Set Fixed-Time motion mode on or off. Ignored with NO_STANDARD_MOTION. * 0: Fixed-Time Motion OFF (Standard Motion) * 1: Fixed-Time Motion ON * - * X/Y 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 Enable (1) or Disable (0) Axis Synchronization. + * + * Linear / Pressure Advance: + * + * P 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 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,253 +198,304 @@ void GcodeSuite::M493_report(const bool forReplay/*=true*/) { * 7: 3HEI : 3-Hump Extra-Intensive * 8: MZV : Mass-based Zero Vibration * - * P Enable (1) or Disable (0) Linear Advance pressure control + * A Set static/base frequency for the specified axes + * I Set damping ratio for the specified axes + * Q Set vibration tolerance (vtol) for the specified axes * - * K Set Linear Advance gain + * Dynamic Frequency Mode: * - * D Set Dynamic Frequency mode + * D 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 Set static/base frequency for the X axis - * F 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 Set frequency scaling for the specified axes * - * B Set static/base frequency for the Y axis - * H 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()) flag.report = true; - // Parse 'S' mode parameter. - if (parser.seen('S')) { - const bool active = parser.value_bool(); - if (active != ftMotion.cfg.active) { - stepper.ftMotion_syncPosition(); - ftMotion.cfg.active = active; - flag.report = true; - } - } + ft_config_t &c = ftMotion.cfg; - #if HAS_X_AXIS - auto set_shaper = [&](const AxisEnum axis, const char c) { - const ftMotionShaper_t newsh = (ftMotionShaper_t)parser.value_byte(); - 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; - } - } - return false; - }; - - if (parser.seenval('X') && set_shaper(X_AXIS, 'X')) return; // Parse 'X' mode parameter - - #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; - 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 (val >= 0.0f) { - ftMotion.cfg.linearAdvK = val; + #if HAS_STANDARD_MOTION + // Parse 'S' mode parameter. + if (parser.seen('S')) { + const bool active = parser.value_bool(); + if (active != c.active) { + ftMotion.toggle(); flag.report = true; } - else // Value out of range. - SERIAL_ECHOLNPGM("Linear Advance gain out of range."); + } + #endif + + #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 (c.setShaper(axis, newsh)) + flag.update = flag.report = true; + }; + if (seenC) { + #define _SET_SHAPER(A) set_shaper(_AXIS(A), shaperVal); + SHAPED_MAP(_SET_SHAPER); } - #endif // HAS_EXTRUDERS + #endif // NUM_AXES_SHAPED > 0 + + // Parse bool 'H' Axis Synchronization parameter. + if (parser.seen('H') && c.setAxisSync(parser.value_bool())) + flag.report = true; #if HAS_DYNAMIC_FREQ // Dynamic frequency mode parameter. if (parser.seenval('D')) { - if (AXIS_HAS_SHAPER(X) || AXIS_HAS_SHAPER(Y)) { - const dynFreqMode_t val = dynFreqMode_t(parser.value_byte()); - switch (val) { - #if HAS_DYNAMIC_FREQ_MM - case dynFreqMode_Z_BASED: - #endif - #if HAS_DYNAMIC_FREQ_G - case dynFreqMode_MASS_BASED: - #endif - case dynFreqMode_DISABLED: - ftMotion.cfg.dynFreqMode = val; - flag.report = true; - break; - default: - SERIAL_ECHOLNPGM("?Invalid Dynamic Frequency Mode [D] value."); - break; + if (AXIS_IS_SHAPING(X) || AXIS_IS_SHAPING(Y) || AXIS_IS_SHAPING(Z) || AXIS_IS_SHAPING(E)) { + switch (c.setDynFreqMode(parser.value_byte())) { + case 0: break; // Same value, no update + case 1: flag.report = true; break; // New value, updated + default: SERIAL_ECHOLN(F("?Invalid "), F("(D)ynamic Frequency Mode value.")); break; } } - else { - SERIAL_ECHOLNPGM("?Wrong shaper for [D] Dynamic Frequency mode."); - } + else + SERIAL_ECHOLNPGM("?Shaper required for (D)ynamic Frequency Mode ", c.dynFreqMode, "."); } - const bool modeUsesDynFreq = ( - TERN0(HAS_DYNAMIC_FREQ_MM, ftMotion.cfg.dynFreqMode == dynFreqMode_Z_BASED) - || TERN0(HAS_DYNAMIC_FREQ_G, ftMotion.cfg.dynFreqMode == dynFreqMode_MASS_BASED) - ); + const bool modeUsesDynFreq = c.modeUsesDynFreq(); #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 && c.goodBaseFreq(baseFreqVal); + 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 && c.goodZeta(zetaVal); + if (seenI && !goodZeta) + SERIAL_ECHOLN(F("?Invalid "), F("(I) Zeta value. (0.01-" STRINGIFY(FTM_MAX_DAMPENING) ")")); // Zeta out of range + + #if HAS_FTM_EI_SHAPING + // Vibration Tolerance parameter + const bool seenQ = parser.seenval('Q'); + const float vtolVal = seenQ ? parser.value_float() : 0.0f; + const bool goodVtol = seenQ && c.goodVtol(vtolVal); + if (seenQ && !goodVtol) + SERIAL_ECHOLN(F("?Invalid "), F("(Q) Vibration Tolerance value. (0.0-1.0)")); // VTol out of range + #endif + + const bool apply_xy = !parser.seen("XYZE"); + #if HAS_X_AXIS - // Parse frequency parameter (X axis). - if (parser.seenval('A')) { - if (AXIS_HAS_SHAPER(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 && c.setBaseFreq(X_AXIS, 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 && c.setDynFreqK(X_AXIS, 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_HAS_SHAPER(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 && c.setZeta(X_AXIS, 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), " (I) 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_HAS_EISHAPER(X)) { - if (WITHIN(val, 0.00f, 1.0f)) { - ftMotion.cfg.vtol[0] = val; - flag.update = true; + #if HAS_FTM_EI_SHAPING + // Parse X vtol parameter + if (seenQ) { + if (AXIS_IS_EISHAPING(X)) { + if (goodVtol && c.setVtol(X_AXIS, vtolVal)) + flag.update = true; + } + else + SERIAL_ECHOLNPGM("?Wrong mode for ", C(STEPPER_A_NAME), " (Q) vtol parameter."); } - else - SERIAL_ECHOLNPGM("Invalid X vtol [", C('Q'), "] value."); // VTol out of range. - } - else - SERIAL_ECHOLNPGM("Wrong mode for vtol parameter."); + #endif } #endif // HAS_X_AXIS #if HAS_Y_AXIS - // Parse frequency parameter (Y axis). - if (parser.seenval('B')) { - if (AXIS_HAS_SHAPER(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 && c.setBaseFreq(Y_AXIS, 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 && c.setDynFreqK(Y_AXIS, 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_HAS_SHAPER(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 && c.setZeta(Y_AXIS, 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), " (I) 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_HAS_EISHAPER(Y)) { - if (WITHIN(val, 0.00f, 1.0f)) { - ftMotion.cfg.vtol[1] = val; - flag.update = true; + #if HAS_FTM_EI_SHAPING + // Parse Y vtol parameter + if (seenQ) { + if (AXIS_IS_EISHAPING(Y)) { + if (goodVtol && c.setVtol(Y_AXIS, vtolVal)) + flag.update = true; + } + else + SERIAL_ECHOLNPGM("?Wrong mode for ", C(STEPPER_B_NAME), " (Q) vtol parameter."); } - else - SERIAL_ECHOLNPGM("Invalid Y vtol [", C('R'), "] value."); // VTol out of range. - } - else - SERIAL_ECHOLNPGM("Wrong mode for vtol parameter."); + #endif } #endif // HAS_Y_AXIS - if (flag.update) ftMotion.update_shaping_params(); + #if ENABLED(FTM_SHAPER_Z) + + if (parser.seen_test('Z')) { + + // Parse Z frequency parameter + if (seenA) { + if (AXIS_IS_SHAPING(Z)) { + if (goodBaseFreq && c.setBaseFreq(Z_AXIS, 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 && c.setDynFreqK(Z_AXIS, baseDynFreqVal)) + flag.report = true; + #endif + + // Parse Z zeta parameter + if (seenI) { + if (AXIS_IS_SHAPING(Z)) { + if (goodZeta && c.setZeta(Z_AXIS, zetaVal)) + flag.update = true; + } + else + SERIAL_ECHOLNPGM("?Wrong mode for ", C(STEPPER_C_NAME), " (I) zeta parameter."); + } + + #if HAS_FTM_EI_SHAPING + // Parse Z vtol parameter + if (seenQ) { + if (AXIS_IS_EISHAPING(Z)) { + if (goodVtol && c.setVtol(Z_AXIS, vtolVal)) + flag.update = true; + } + else + SERIAL_ECHOLNPGM("?Wrong mode for ", C(STEPPER_C_NAME), " (Q) vtol parameter."); + } + #endif + } + + #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 && c.setBaseFreq(E_AXIS, 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 && c.setDynFreqK(E_AXIS, baseDynFreqVal)) + flag.report = true; + #endif + + // Parse E zeta parameter + if (seenI) { + if (AXIS_IS_SHAPING(E)) { + if (goodZeta && c.setZeta(E_AXIS, zetaVal)) + flag.update = true; + } + else + SERIAL_ECHOLNPGM("?Wrong mode for ", C('E'), " (I) zeta parameter."); + } + + #if HAS_FTM_EI_SHAPING + // Parse E vtol parameter + if (seenQ) { + if (AXIS_IS_EISHAPING(E)) { + if (goodVtol && c.setVtol(E_AXIS, vtolVal)) + flag.update = true; + } + else + SERIAL_ECHOLNPGM("?Wrong mode for ", C('E'), " (Q) vtol parameter."); + } + #endif + } + + #endif // FTM_SHAPER_E + + if (flag.update || flag.report) + ui.refresh(); if (flag.report) say_shaping(); } diff --git a/Marlin/src/gcode/feature/ft_motion/M494.cpp b/Marlin/src/gcode/feature/ft_motion/M494.cpp new file mode 100644 index 0000000000..d6161a9574 --- /dev/null +++ b/Marlin/src/gcode/feature/ft_motion/M494.cpp @@ -0,0 +1,139 @@ +/** + * 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 . + * + */ +#include "../../../inc/MarlinConfigPre.h" + +#if ENABLED(FT_MOTION) + +#include "../../gcode.h" +#include "../../../module/ft_motion.h" +#include "../../../module/stepper.h" +#include "../../../module/planner.h" +#include "../../../lcd/marlinui.h" + +void say_ftm_settings() { + #if ANY(FTM_POLYS, FTM_SMOOTHING) + const ft_config_t &c = ftMotion.cfg; + #endif + + #if ENABLED(FTM_POLYS) + SERIAL_ECHOLN(F(" Trajectory: "), ftMotion.getTrajectoryName(), C('('), (uint8_t)ftMotion.getTrajectoryType(), C(')')); + if (ftMotion.getTrajectoryType() == TrajectoryType::POLY6) + SERIAL_ECHOLNPGM(" Poly6 Overshoot: ", p_float_t(c.poly6_acceleration_overshoot, 3)); + #endif + + #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); + + report_heading_etc(forReplay, F("FT Motion")); + SERIAL_ECHOPGM(" M494 T", (uint8_t)ftMotion.getTrajectoryType()); + + #if ANY(FTM_POLYS, FTM_SMOOTHING) + const ft_config_t &c = ftMotion.cfg; + #endif + + #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 ENABLED(FTM_POLYS) + if (ftMotion.getTrajectoryType() == TrajectoryType::POLY6) + SERIAL_ECHOPGM(" O", c.poly6_acceleration_overshoot); + #endif + + SERIAL_EOL(); +} + +/** + * M494: Set Fixed-time Motion Control parameters + * + * Parameters: + * T Set trajectory generator type (0=TRAPEZOIDAL, 1=POLY5, 2=POLY6) + * O Set acceleration overshoot for POLY6 (1.25-1.875) + * X