diff --git a/.github/code_of_conduct.md b/.github/code_of_conduct.md index 5fd9e0c8ee..f60db7ba39 100644 --- a/.github/code_of_conduct.md +++ b/.github/code_of_conduct.md @@ -8,19 +8,19 @@ In the interest of fostering an open and welcoming environment, we as contributo Examples of behavior that contributes to creating a positive environment include: -* Using welcoming and inclusive language -* Being respectful of differing viewpoints and experiences -* Gracefully accepting constructive criticism -* Focusing on what is best for the community -* Showing empathy towards other community members +- Using welcoming and inclusive language +- Being respectful of differing viewpoints and experiences +- Gracefully accepting constructive criticism +- Focusing on what is best for the community +- Showing empathy towards other community members Examples of unacceptable behavior by participants include: -* The use of sexualized language or imagery and unwelcome sexual attention or advances -* Trolling, insulting/derogatory comments, and personal or political attacks -* Public or private harassment -* Publishing others' private information, such as a physical or electronic address, without explicit permission -* Other conduct which could reasonably be considered inappropriate in a professional setting +- The use of sexualized language or imagery and unwelcome sexual attention or advances +- Trolling, insulting/derogatory comments, and personal or political attacks +- Public or private harassment +- Publishing others' private information, such as a physical or electronic address, without explicit permission +- Other conduct which could reasonably be considered inappropriate in a professional setting ## Our Responsibilities diff --git a/.github/contributing.md b/.github/contributing.md index bbf41ea1c8..0648b20135 100644 --- a/.github/contributing.md +++ b/.github/contributing.md @@ -11,18 +11,21 @@ The following is a set of guidelines for contributing to Marlin, hosted by the [ [I don't want to read this whole thing, I just have a question!!!](#i-dont-want-to-read-this-whole-thing-i-just-have-a-question) [How Can I Contribute?](#how-can-i-contribute) - * [Reporting Bugs](#reporting-bugs) - * [Suggesting Features or Changes](#suggesting-features-or-changes) - * [Your First Code Contribution](#your-first-code-contribution) - * [Pull Requests](#pull-requests) + +- [Reporting Bugs](#reporting-bugs) +- [Suggesting Features or Changes](#suggesting-features-or-changes) +- [Your First Code Contribution](#your-first-code-contribution) +- [Pull Requests](#pull-requests) [Styleguides](#styleguides) - * [Git Commit Messages](#git-commit-messages) - * [C++ Coding Standards](#c++-coding-standards) - * [Documentation Styleguide](#documentation) + +- [Git Commit Messages](#git-commit-messages) +- [C++ Coding Standards](#c++-coding-standards) +- [Documentation Styleguide](#documentation) [Additional Notes](#additional-notes) - * [Issue and Pull Request Labels](#issue-and-pull-request-labels) + +- [Issue and Pull Request Labels](#issue-and-pull-request-labels) ## Code of Conduct @@ -31,6 +34,7 @@ This project and everyone participating in it is governed by the [Marlin Code of ## I don't want to read this whole thing I just have a question!!! > [!NOTE] +> > Please don't file an issue to ask a question. You'll get faster results by using the resources below. We have a Message Board and a Facebook group where our knowledgable user community can provide helpful advice if you have questions. @@ -43,10 +47,10 @@ We have a Message Board and a Facebook group where our knowledgable user communi If chat is more your speed, you can join the MarlinFirmware Discord server: -* Use the link https://discord.com/servers/marlin-firmware-461605380783472640 to join up as a General User. -* Even though our Discord is pretty active, it may take a while for community members to respond — please be patient! -* Use the `#general` channel for general questions or discussion about Marlin. -* Other channels exist for certain topics or are limited to Patrons. Check the channel list. +- Use the link https://discord.com/servers/marlin-firmware-461605380783472640 to join up as a General User. +- Even though our Discord is pretty active, it may take a while for community members to respond — please be patient! +- Use the `#general` channel for general questions or discussion about Marlin. +- Other channels exist for certain topics or are limited to Patrons. Check the channel list. ## How Can I Contribute? @@ -57,6 +61,7 @@ This section guides you through submitting a Bug Report for Marlin. Following th Before creating a Bug Report, please test the "nightly" development branch, as you might find out that you don't need to create one. When you are creating a Bug Report, please [include as many details as possible](#how-do-i-submit-a-good-bug-report). Fill out [the required template](ISSUE_TEMPLATE/bug_report.yml), the information it asks for helps us resolve issues faster. > [!NOTE] +> > Regressions can happen. If you find a **Closed** issue that seems like your issue, go ahead and open a new issue and include a link to the original issue in the body of your new one. All you need to create a link is the issue number, preceded by #. For example, #8888. #### How Do I Submit A (Good) Bug Report? @@ -65,29 +70,29 @@ Bugs are tracked as [GitHub issues](https://guides.github.com/features/issues/). Explain the problem and include additional details to help maintainers reproduce the problem: -* **Use a clear and descriptive title** for the issue to identify the problem. -* **Describe the exact steps which reproduce the problem** in as many details as possible. For example, start by explaining how you started Marlin, e.g. which command exactly you used in the terminal, or how you started Marlin otherwise. When listing steps, **don't just say what you did, but explain how you did it**. For example, if you moved the cursor to the end of a line, explain if you used the mouse, or a keyboard shortcut or an Marlin command, and if so which one? -* **Provide specific examples to demonstrate the steps**. Include links to files or GitHub projects, or copy/pasteable snippets, which you use in those examples. If you're providing snippets or log output in the issue, use [Markdown code blocks](https://help.github.com/articles/markdown-basics/#multiple-lines). -* **Describe the behavior you observed after following the steps** and point out what exactly is the problem with that behavior. -* **Explain which behavior you expected to see instead and why.** -* **Include detailed log output** especially for probing and leveling. See below for usage of `DEBUG_LEVELING_FEATURE`. -* **Include screenshots, links to videos, etc.** which clearly demonstrate the problem. -* **Include G-code** (if relevant) that reliably causes the problem to show itself. -* **If the problem wasn't triggered by a specific action**, describe what you were doing before the problem happened and share more information using the guidelines below. +- **Use a clear and descriptive title** for the issue to identify the problem. +- **Describe the exact steps which reproduce the problem** in as many details as possible. For example, start by explaining how you started Marlin, e.g. which command exactly you used in the terminal, or how you started Marlin otherwise. When listing steps, **don't just say what you did, but explain how you did it**. For example, if you moved the cursor to the end of a line, explain if you used the mouse, or a keyboard shortcut or an Marlin command, and if so which one? +- **Provide specific examples to demonstrate the steps**. Include links to files or GitHub projects, or copy/pasteable snippets, which you use in those examples. If you're providing snippets or log output in the issue, use [Markdown code blocks](https://help.github.com/articles/markdown-basics/#multiple-lines). +- **Describe the behavior you observed after following the steps** and point out what exactly is the problem with that behavior. +- **Explain which behavior you expected to see instead and why.** +- **Include detailed log output** especially for probing and leveling. See below for usage of `DEBUG_LEVELING_FEATURE`. +- **Include screenshots, links to videos, etc.** which clearly demonstrate the problem. +- **Include G-code** (if relevant) that reliably causes the problem to show itself. +- **If the problem wasn't triggered by a specific action**, describe what you were doing before the problem happened and share more information using the guidelines below. Provide more context: -* **Can you reproduce the problem with a minimum of options enabled?** -* **Did the problem start happening recently** (e.g. after updating to a new version of Marlin) or was this always a problem? -* If the problem started happening recently, **can you reproduce the problem in an older version of Marlin?** What's the most recent version in which the problem doesn't happen? You can download older versions of Marlin from [the releases page](https://github.com/MarlinFirmware/Marlin/releases). -* **Can you reliably reproduce the issue?** If not, provide details about how often the problem happens and under which conditions it normally happens. +- **Can you reproduce the problem with a minimum of options enabled?** +- **Did the problem start happening recently** (e.g. after updating to a new version of Marlin) or was this always a problem? +- If the problem started happening recently, **can you reproduce the problem in an older version of Marlin?** What's the most recent version in which the problem doesn't happen? You can download older versions of Marlin from [the releases page](https://github.com/MarlinFirmware/Marlin/releases). +- **Can you reliably reproduce the issue?** If not, provide details about how often the problem happens and under which conditions it normally happens. Include details about your configuration and environment: -* **Which version of Marlin are you using?** Marlin's exact version and build date can be seen in the startup message when a host connects to Marlin, or in the LCD Info menu (if enabled). -* **What kind of 3D Printer and electronics are you using**? -* **What kind of add-ons (probe, filament sensor) do you have**? -* **Include your Configuration files.** Make a ZIP file containing `Configuration.h` and `Configuration_adv.h` and drop it on your reply. +- **Which version of Marlin are you using?** Marlin's exact version and build date can be seen in the startup message when a host connects to Marlin, or in the LCD Info menu (if enabled). +- **What kind of 3D Printer and electronics are you using**? +- **What kind of add-ons (probe, filament sensor) do you have**? +- **Include your Configuration files.** Make a ZIP file containing `Configuration.h` and `Configuration_adv.h` and drop it on your reply. ### Suggesting Features or Changes @@ -97,52 +102,52 @@ Before creating a suggestion, please check [this list](https://github.com/Marlin #### Before Submitting a Feature Request -* **Check the [Marlin website](https://marlinfw.org/)** for tips — you might discover that the feature is already included. Most importantly, check if you're using [the latest version of Marlin](https://github.com/MarlinFirmware/Marlin/releases) and if you can get the desired behavior by changing [Marlin's config settings](https://marlinfw.org/docs/configuration/configuration.html). -* **Perform a [cursory search](https://github.com/MarlinFirmware/Marlin/issues?q=is%3Aopen+is%3Aissue+label%3A%22T%3A+Feature+Request%22)** to see if the enhancement has already been suggested. If it has, add a comment to the existing issue instead of opening a new one. +- **Check the [Marlin website](https://marlinfw.org/)** for tips — you might discover that the feature is already included. Most importantly, check if you're using [the latest version of Marlin](https://github.com/MarlinFirmware/Marlin/releases) and if you can get the desired behavior by changing [Marlin's config settings](https://marlinfw.org/docs/configuration/configuration.html). +- **Perform a [cursory search](https://github.com/MarlinFirmware/Marlin/issues?q=is%3Aopen+is%3Aissue+label%3A%22T%3A+Feature+Request%22)** to see if the enhancement has already been suggested. If it has, add a comment to the existing issue instead of opening a new one. #### How Do I Submit A (Good) Feature Request? Feature Requests are tracked as [GitHub issues](https://guides.github.com/features/issues/). Please follow these guidelines in your request: -* **Use a clear and descriptive title** for the issue to identify the suggestion. -* **Provide a step-by-step description of the requested feature** in as much detail as possible. -* **Provide specific examples to demonstrate the steps**. -* **Describe the current behavior** and **explain which behavior you expected to see instead** and why. -* **Include screenshots and links to videos** which demonstrate the feature or point out the part of Marlin to which the request is related. -* **Explain why this feature would be useful** to most Marlin users. -* **Name other firmwares that have this feature, if any.** +- **Use a clear and descriptive title** for the issue to identify the suggestion. +- **Provide a step-by-step description of the requested feature** in as much detail as possible. +- **Provide specific examples to demonstrate the steps**. +- **Describe the current behavior** and **explain which behavior you expected to see instead** and why. +- **Include screenshots and links to videos** which demonstrate the feature or point out the part of Marlin to which the request is related. +- **Explain why this feature would be useful** to most Marlin users. +- **Name other firmwares that have this feature, if any.** ### Your First Code Contribution Unsure where to begin contributing to Marlin? You can start by looking through these `good-first-issue` and `help-wanted` issues: -* [Beginner issues][good-first-issue] - issues which should only require a few lines of code, and a test or two. -* [Help Wanted issues][help-wanted] - issues which should be a bit more involved than `beginner` issues. +- [Beginner issues][good-first-issue] - issues which should only require a few lines of code, and a test or two. +- [Help Wanted issues][help-wanted] - issues which should be a bit more involved than `beginner` issues. ### Pull Requests Pull Requests should always be targeted to working branches (e.g., `bugfix-2.1.x` and/or `bugfix-1.1.x`) and never to release branches (e.g., `2.0.x` and/or `1.1.x`). If this is your first Pull Request, please read our [Guide to Pull Requests](https://marlinfw.org/docs/development/getting_started_pull_requests.html) and GitHub's [Pull Request](https://help.github.com/articles/creating-a-pull-request/) documentation. -* Fill in [the required template](pull_request_template.md). -* Don't include issue numbers in the PR title. -* Include pictures, diagrams, and links to videos in your Pull Request to demonstrate your changes, if needed. -* Follow the [Coding Standards](https://marlinfw.org/docs/development/coding_standards.html) posted on our website. -* Document new code with clear and concise comments. -* End all files with a newline. +- Fill in [the required template](pull_request_template.md). +- Don't include issue numbers in the PR title. +- Include pictures, diagrams, and links to videos in your Pull Request to demonstrate your changes, if needed. +- Follow the [Coding Standards](https://marlinfw.org/docs/development/coding_standards.html) posted on our website. +- Document new code with clear and concise comments. +- End all files with a newline. ## Styleguides ### Git Commit Messages -* Use the present tense ("Add feature" not "Added feature"). -* Use the imperative mood ("Move cursor to..." not "Moves cursor to..."). -* Limit the first line to 72 characters or fewer. -* Reference issues and Pull Requests liberally after the first line. +- Use the present tense ("Add feature" not "Added feature"). +- Use the imperative mood ("Move cursor to..." not "Moves cursor to..."). +- Limit the first line to 72 characters or fewer. +- Reference issues and Pull Requests liberally after the first line. ### C++ Coding Standards -* Please read and follow the [Coding Standards](https://marlinfw.org/docs/development/coding_standards.html) posted on our website. Failure to follow these guidelines will delay evaluation and acceptance of Pull Requests. +- Please read and follow the [Coding Standards](https://marlinfw.org/docs/development/coding_standards.html) posted on our website. Failure to follow these guidelines will delay evaluation and acceptance of Pull Requests. ### Documentation -* Guidelines for documentation are still under development. In-general, be clear, concise, and to-the-point. +- Guidelines for documentation are still under development. In-general, be clear, concise, and to-the-point. diff --git a/Makefile b/Makefile index f8a9ae3c4e..a63b4dc683 100644 --- a/Makefile +++ b/Makefile @@ -161,7 +161,7 @@ format-lines: validate-lines: @echo "Validating text formatting" - @npx prettier --check . --editorconfig --object-wrap preserve + @npx prettier --check . --editorconfig --object-wrap preserve --prose-wrap never validate-urls: @echo "Checking URLs in source files" diff --git a/Marlin/Configuration_adv.h b/Marlin/Configuration_adv.h index e46a3af2de..84fbd6f8ed 100644 --- a/Marlin/Configuration_adv.h +++ b/Marlin/Configuration_adv.h @@ -1238,6 +1238,25 @@ #define FTM_FS 1000 // (Hz) Frequency for trajectory generation. #define FTM_MIN_SHAPE_FREQ 20 // (Hz) Minimum shaping frequency, lower consumes more RAM + /** + * TMC2208 / TMC2208_STANDALONE drivers require a brief pause after a DIR change + * to prevent a standstill shutdown when using StealthChop (the standalone default). + * These options cause FT Motion to delay for > 750µs after a DIR change on a given axis. + * Disable only if you are certain that this can never happen with your TMC2208s. + */ + #if AXIS_DRIVER_TYPE_X(TMC2208) || AXIS_DRIVER_TYPE_X(TMC2208_STANDALONE) + #define FTM_DIR_CHANGE_HOLD_X + #endif + #if AXIS_DRIVER_TYPE_Y(TMC2208) || AXIS_DRIVER_TYPE_Y(TMC2208_STANDALONE) + #define FTM_DIR_CHANGE_HOLD_Y + #endif + #if AXIS_DRIVER_TYPE_Z(TMC2208) || AXIS_DRIVER_TYPE_Z(TMC2208_STANDALONE) + #define FTM_DIR_CHANGE_HOLD_Z + #endif + #if HAS_E_DRIVER(TMC2208) || HAS_E_DRIVER(TMC2208_STANDALONE) + #define FTM_DIR_CHANGE_HOLD_E + #endif + #endif // FT_MOTION /** @@ -1782,6 +1801,12 @@ */ //#define SD_SPI_SPEED SPI_HALF_SPEED + /** + * Reinit the LCD after SD Card insert/remove or when entering the menu. + * Required for some LCDs that use shared SPI with an external SD Card reader. + */ + #define REINIT_NOISY_LCD + // The standard SD detect circuit reads LOW when media is inserted and HIGH when empty. // Enable this option and set to HIGH if your SD cards are incorrectly detected. //#define SD_DETECT_STATE HIGH @@ -2801,8 +2826,8 @@ * * Adds support for commands: * S000 : Report State and Position while moving. - * P000 : Instant Pause / Hold while moving. - * R000 : Resume from Pause / Hold. + * P000 : Instant Pause / Hold while moving. Enable SOFT_FEED_HOLD for soft deceleration. + * R000 : Resume from Pause / Hold. Enable SOFT_FEED_HOLD for soft acceleration. * * - During Hold all Emergency Parser commands are available, as usual. * - Enable NANODLP_Z_SYNC and NANODLP_ALL_AXIS for move command end-state reports. @@ -4432,15 +4457,38 @@ #endif /** - * Instant freeze / unfreeze functionality - * Potentially useful for rapid stop that allows being resumed. Halts stepper movement. - * Note this does NOT pause spindles, lasers, fans, heaters or any other auxiliary device. - * @section interface + * Freeze / Unfreeze + * + * Pause / Hold that keeps power available and does not stop the spindle can be initiated by + * the FREEZE_PIN. Halts instantly (default) or performs a soft feed hold that decelerates and + * halts movement at FREEZE_JERK (requires SOFT_FEED_HOLD). + * Motion can be resumed by using the FREEZE_PIN. + * + * NOTE: Controls Laser PWM but does NOT pause Spindle, Fans, Heaters or other devices. + * @section freeze */ //#define FREEZE_FEATURE #if ENABLED(FREEZE_FEATURE) - //#define FREEZE_PIN 41 // Override the default (KILL) pin here - #define FREEZE_STATE LOW // State of pin indicating freeze + //#define FREEZE_PIN -1 // Override the default (KILL) pin here + #define FREEZE_STATE LOW // State of pin indicating freeze +#endif + +#if ANY(FREEZE_FEATURE, REALTIME_REPORTING_COMMANDS) + /** + * Command P000 (REALTIME_REPORTING_COMMANDS and EMERGENCY_PARSER) or + * FREEZE_PIN (FREEZE_FEATURE) initiates a soft feed hold that keeps + * power available and does not stop the spindle. + * + * The soft feed hold decelerates and halts movement at FREEZE_JERK. + * Motion can be resumed with command R000 (requires REALTIME_REPORTING_COMMANDS) or + * by using the FREEZE_PIN (requires FREEZE_FEATURE). + * + * NOTE: Affects Laser PWM but DOES NOT pause Spindle, Fans, Heaters or other devices. + */ + //#define SOFT_FEED_HOLD + #if ENABLED(SOFT_FEED_HOLD) + #define FREEZE_JERK 2 // (mm/s) Completely halt when motion has decelerated below this value + #endif #endif /** diff --git a/Marlin/Version.h b/Marlin/Version.h index 3ebdc70bf4..17e522e0c8 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 "2025-12-25" +//#define STRING_DISTRIBUTION_DATE "2026-01-21" /** * The protocol for communication to the host. Protocol indicates communication diff --git a/Marlin/src/HAL/ESP32/HAL.cpp b/Marlin/src/HAL/ESP32/HAL.cpp index acfec29b2f..9adff634a0 100644 --- a/Marlin/src/HAL/ESP32/HAL.cpp +++ b/Marlin/src/HAL/ESP32/HAL.cpp @@ -271,7 +271,8 @@ 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 * 1023) * (1000.f / (ADC_REFERENCE_VOLTAGE)); + static constexpr uint32_t adc_divisor = uint32_t((ADC_REFERENCE_VOLTAGE) * 1000UL); + adc_result = (mv * 1023UL) / adc_divisor; // Change the attenuation level based on the new reading adc_atten_t atten; diff --git a/Marlin/src/HAL/HC32/README.md b/Marlin/src/HAL/HC32/README.md index 1161e881f6..c852edcf6c 100644 --- a/Marlin/src/HAL/HC32/README.md +++ b/Marlin/src/HAL/HC32/README.md @@ -6,7 +6,7 @@ This document provides notes on the HAL for the HC32F460 MCU. The HC32F460 HAL is designed to be generic enough for any HC32F460-based board. Adding support for a new HC32F460-based board will require the following steps: -1. Follow [the usual instructions](https://marlinfw.org/docs/development/boards.html#adding-a-new-board) to add a new board to Marlin. (i.e., Add a pins file, edit `boards.h` and `pins.h`, etc.) +1. Follow [the usual instructions](//marlinfw.org/docs/development/boards.html#adding-a-new-board) to add a new board to Marlin. (i.e., Add a pins file, edit `boards.h` and `pins.h`, etc.) 2. Determine the flash size your board uses: - Examine the board's main processor. (Refer the naming key in `hc32.ini`.) - Extend the `HC32F460C_common` base env for 256K, or `HC32F460E_common` for 512K. @@ -50,10 +50,12 @@ SCB->VTOR = ((uint32_t) APP_START_ADDRESS & SCB_VTOR_TBLOFF_Msk); Just searching for `SCB->VTOR` should yield some results. From there, you just need to look at the value that's assigned to it. The example uses `APP_START_ADDRESS`. > [!NOTE] +> > Some vendors publish incomplete source code. But they sometimes leave version control related files in the repo, which can contain previous version of files that were removed. Find these by including folders like `.git` or `.svn` in your search. > [!NOTE] -> The example is based on the [Voxelab-64/Aquila_X2](https://github.com/Voxelab-64/Aquila_X2/blob/main/firmware/Sources/.svn/pristine/ec/ec82bcb480b511906bc3e6658450e3a803ab9813.svn-base#L96) which actually includes deleted files in its repo. +> +> The example is based on the [Voxelab-64/Aquila_X2](//github.com/Voxelab-64/Aquila_X2/blob/main/firmware/Sources/.svn/pristine/ec/ec82bcb480b511906bc3e6658450e3a803ab9813.svn-base#L96) which actually includes deleted files in its repo. 2. Using a linker script @@ -72,7 +74,8 @@ MEMORY ``` > [!NOTE] -> This example is based on [Voxelab-64/Aquila_X2](https://github.com/Voxelab-64/Aquila_X2/blob/d1f23adf96920996b979bc31023d1dce236d05db/firmware/Sources/main/hdsc32core/hc32f46x_flash.ld#L55) +> +> This example is based on [Voxelab-64/Aquila_X2](//github.com/Voxelab-64/Aquila_X2/blob/d1f23adf96920996b979bc31023d1dce236d05db/firmware/Sources/main/hdsc32core/hc32f46x_flash.ld#L55) ## Documentation on the HC32F460 @@ -96,15 +99,15 @@ Contact me on Discord (@shadow578) if you need it. This HAL depends on the following projects: -- [shadow578/platform-hc32f46x](https://github.com/shadow578/platform-hc32f46x) (PlatformIO platform for HC32F46x) -- [shadow578/framework-arduino-hc32f46x](https://github.com/shadow578/framework-arduino-hc32f46x) (Arduino framework for HC32F46x) -- [shadow578/framework-hc32f46x-ddl](https://github.com/shadow578/framework-hc32f46x-ddl) (HC32F46x DDL framework) +- [shadow578/platform-hc32f46x](//github.com/shadow578/platform-hc32f46x) (PlatformIO platform for HC32F46x) +- [shadow578/framework-arduino-hc32f46x](//github.com/shadow578/framework-arduino-hc32f46x) (Arduino framework for HC32F46x) +- [shadow578/framework-hc32f46x-ddl](//github.com/shadow578/framework-hc32f46x-ddl) (HC32F46x DDL framework) ## Credits This HAL wouldn't be possible without the following projects: -- [Voxelab-64/Aquila_X2](https://github.com/Voxelab-64/Aquila_X2) (original implementation) -- [alexqzd/Marlin-H32](https://github.com/alexqzd/Marlin-H32) (misc. fixes to the original implementation) -- [kgoveas/Arduino-Core-Template](https://github.com/kgoveas/Arduino-Core-Template) (template for Arduino headers) -- [stm32duino/Arduino_Core_STM32](https://github.com/stm32duino/Arduino_Core_STM32) (misc. Arduino functions) +- [Voxelab-64/Aquila_X2](//github.com/Voxelab-64/Aquila_X2) (original implementation) +- [alexqzd/Marlin-H32](//github.com/alexqzd/Marlin-H32) (misc. fixes to the original implementation) +- [kgoveas/Arduino-Core-Template](//github.com/kgoveas/Arduino-Core-Template) (template for Arduino headers) +- [stm32duino/Arduino_Core_STM32](//github.com/stm32duino/Arduino_Core_STM32) (misc. Arduino functions) diff --git a/Marlin/src/HAL/SAMD21/endstop_interrupts.h b/Marlin/src/HAL/SAMD21/endstop_interrupts.h index 4ef075f8f9..8d8f9cd06f 100644 --- a/Marlin/src/HAL/SAMD21/endstop_interrupts.h +++ b/Marlin/src/HAL/SAMD21/endstop_interrupts.h @@ -32,7 +32,7 @@ * On SAMD21, all pins support external interrupt capability. * Any pin can be used for external interrupts, but there are some restrictions. * At most 16 different external interrupts can be used at one time. - * Further, you can’t just pick any 16 pins to use. This is because every pin on the SAMD21 + * Further, you can't just pick any 16 pins to use. This is because every pin on the SAMD21 * connects to what is called an EXTINT line, and only one pin per EXTINT line can be used for external * interrupts at a time */ diff --git a/Marlin/src/HAL/SAMD51/endstop_interrupts.h b/Marlin/src/HAL/SAMD51/endstop_interrupts.h index 34c238ba5c..4e342f754f 100644 --- a/Marlin/src/HAL/SAMD51/endstop_interrupts.h +++ b/Marlin/src/HAL/SAMD51/endstop_interrupts.h @@ -31,7 +31,7 @@ * On SAMD51, all pins support external interrupt capability. * Any pin can be used for external interrupts, but there are some restrictions. * At most 16 different external interrupts can be used at one time. - * Further, you can’t just pick any 16 pins to use. This is because every pin on the SAMD51 + * Further, you can't just pick any 16 pins to use. This is because every pin on the SAMD51 * connects to what is called an EXTINT line, and only one pin per EXTINT line can be used for external * interrupts at a time */ diff --git a/Marlin/src/HAL/STM32F1/endstop_interrupts.h b/Marlin/src/HAL/STM32F1/endstop_interrupts.h index 6724bf3456..f8f21a4c6d 100644 --- a/Marlin/src/HAL/STM32F1/endstop_interrupts.h +++ b/Marlin/src/HAL/STM32F1/endstop_interrupts.h @@ -27,7 +27,7 @@ * On STM32F, all pins support external interrupt capability. * Any pin can be used for external interrupts, but there are some restrictions. * At most 16 different external interrupts can be used at one time. - * Further, you can’t just pick any 16 pins to use. This is because every pin on the STM32 + * Further, you can't just pick any 16 pins to use. This is because every pin on the STM32 * connects to what is called an EXTI line, and only one pin per EXTI line can be used for external interrupts at a time * Check the Reference Manual of the MCU to confirm which line is used by each pin */ diff --git a/Marlin/src/MarlinCore.cpp b/Marlin/src/MarlinCore.cpp index 6d672e3b8c..94d0bce188 100644 --- a/Marlin/src/MarlinCore.cpp +++ b/Marlin/src/MarlinCore.cpp @@ -260,6 +260,10 @@ #include "feature/rs485.h" #endif +#if ENABLED(SOFT_FEED_HOLD) + #include "feature/e_parser.h" +#endif + /** * Spin in place here while keeping temperature processing alive */ @@ -514,8 +518,14 @@ void Marlin::manage_inactivity(const bool no_stepper_sleep/*=false*/) { } #endif - #if ENABLED(FREEZE_FEATURE) - stepper.frozen = READ(FREEZE_PIN) == FREEZE_STATE; + // Handle the FREEZE button + #if ANY(FREEZE_FEATURE, SOFT_FEED_HOLD) + stepper.set_frozen_triggered( + TERN0(FREEZE_FEATURE, READ(FREEZE_PIN) == FREEZE_STATE) + #if ALL(SOFT_FEED_HOLD, REALTIME_REPORTING_COMMANDS) + || realtime_ramping_pause_flag + #endif + ); #endif #if HAS_HOME @@ -1221,7 +1231,7 @@ void setup() { #endif #endif - #if ENABLED(FREEZE_FEATURE) + #if ENABLED(FREEZE_FEATURE) && DISABLED(NO_FREEZE_PIN) SETUP_LOG("FREEZE_PIN"); #if FREEZE_STATE SET_INPUT_PULLDOWN(FREEZE_PIN); diff --git a/Marlin/src/core/boards.h b/Marlin/src/core/boards.h index 6c51cb01a4..b99fcad89a 100644 --- a/Marlin/src/core/boards.h +++ b/Marlin/src/core/boards.h @@ -419,6 +419,7 @@ #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) +#define BOARD_ATOMSTACK_FB5_V2 5071 // Atomstack FB5 V2.0 (STM32F103RCT6) // // ARM Cortex-M4F diff --git a/Marlin/src/core/types.h b/Marlin/src/core/types.h index b4d7705ffd..159a2e265c 100644 --- a/Marlin/src/core/types.h +++ b/Marlin/src/core/types.h @@ -52,6 +52,11 @@ template struct IF { typedef L type; }; #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 NUM_AXIS_ANY(x, y, z, i, j, k, u, v, w) (false \ + NUM_AXIS_GANG(|| (x), || (y), || (z), || (i), || (j), || (k), || (u), || (v), || (w))) +#define NUM_AXIS_ALL(x, y, z, i, j, k, u, v, w) ((NUM_AXES > 0) \ + NUM_AXIS_GANG(&& (x), && (y), && (z), && (i), && (j), && (k), && (u), && (v), && (w))) +#define NUM_AXIS_NONE(V...) !NUM_AXIS_ANY(V) #define LOGICAL_AXIS_GANG(N,V...) NUM_AXIS_GANG(V) GANG_ITEM_E(N) #define LOGICAL_AXIS_CODE(N,V...) NUM_AXIS_CODE(V) CODE_ITEM_E(N) @@ -71,6 +76,11 @@ template struct IF { typedef L type; }; #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 LOGICAL_AXIS_ANY(e, x, y, z, i, j, k, u, v, w) (false \ + LOGICAL_AXIS_GANG(|| (e), || (x), || (y), || (z), || (i), || (j), || (k), || (u), || (v), || (w))) +#define LOGICAL_AXIS_ALL(e, x, y, z, i, j, k, u, v, w) ((LOGICAL_AXES > 0) \ + LOGICAL_AXIS_GANG(&& (e), && (x), && (y), && (z), && (i), && (j), && (k), && (u), && (v), && (w))) +#define LOGICAL_AXIS_NONE(V...) !LOGICAL_AXIS_ANY(V) #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) @@ -145,10 +155,14 @@ template struct IF { typedef L type; }; #define XY_ARRAY(V...) ARRAY_N(XY_COUNT, V) #define XY_CODE(V...) CODE_N(XY_COUNT, V) #define XY_GANG(V...) GANG_N(XY_COUNT, V) +#define XY_ANY(x,y) (false XY_GANG(|| (x), || (y))) +#define XY_ALL(x,y) ((NUM_AXES > 0) XY_GANG(&& (x), && (y))) #define XYZ_LIST(V...) LIST_N(XYZ_COUNT, V) #define XYZ_ARRAY(V...) ARRAY_N(XYZ_COUNT, V) #define XYZ_CODE(V...) CODE_N(XYZ_COUNT, V) #define XYZ_GANG(V...) GANG_N(XYZ_COUNT, V) +#define XYZ_ANY(x,y,z) (false XYZ_GANG(|| (x), || (y), || (z))) +#define XYZ_ALL(x,y,z) ((NUM_AXES > 0) XYZ_GANG(&& (x), && (y), && (z))) #if HAS_ROTATIONAL_AXES #define ROTATIONAL_AXIS_GANG(V...) GANG_N(ROTATIONAL_AXES, V) @@ -579,7 +593,7 @@ struct XYval { 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) }; } + FI constexpr XYval asFloat() const { return { float(x), float(y) }; } // Marlin workspace shifting is done with G92 and M206 FI XYval asLogical() const { XYval o = asFloat(); toLogical(o); return o; } @@ -646,8 +660,8 @@ struct XYval { // Exact comparisons. For floats a "NEAR" operation may be better. FI bool operator==(const XYval &rs) const { return x == rs.x && y == rs.y; } - FI bool operator==(const XYZval &rs) const { return ENABLED(HAS_X_AXIS) XY_GANG(&& x == rs.x, && y == rs.y); } - FI bool operator==(const XYZEval &rs) const { return ENABLED(HAS_X_AXIS) XY_GANG(&& x == rs.x, && y == rs.y); } + FI bool operator==(const XYZval &rs) const { return XY_ALL(x == rs.x, y == rs.y); } + FI bool operator==(const XYZEval &rs) const { return XY_ALL(x == rs.x, y == rs.y); } 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); } @@ -661,15 +675,15 @@ struct XYval { 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 XYZval &rs) const { return XY_ALL(x < rs.x, y < rs.y); } + FI bool operator<=(const XYZval &rs) const { return XY_ALL(x <= rs.x, y <= rs.y); } + FI bool operator> (const XYZval &rs) const { return XY_ALL(x > rs.x, y > rs.y); } + FI bool operator>=(const XYZval &rs) const { return XY_ALL(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); } + FI bool operator< (const XYZEval &rs) const { return XY_ALL(x < rs.x, y < rs.y); } + FI bool operator<=(const XYZEval &rs) const { return XY_ALL(x <= rs.x, y <= rs.y); } + FI bool operator> (const XYZEval &rs) const { return XY_ALL(x > rs.x, y > rs.y); } + FI bool operator>=(const XYZEval &rs) const { return XY_ALL(x >= rs.x, y >= rs.y); } }; @@ -738,7 +752,7 @@ struct XYZval { // Pointer to the data as a simple array explicit FI operator T* () { return pos; } // If any element is true then it's true - FI constexpr operator bool() const { return 0 NUM_AXIS_GANG(|| x, || y, || z, || i, || j, || k, || u, || v, || w); } + FI constexpr operator bool() const { return NUM_AXIS_ANY(x, y, z, i, j, k, u, v, w); } // Smallest element FI constexpr T small() const { return TERN0(HAS_X_AXIS, _MIN(NUM_AXIS_LIST(x, y, z, i, j, k, u, v, w))); } // Largest element @@ -756,13 +770,13 @@ struct XYZval { 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)); } + FI constexpr XYZval asFloat() const { return NUM_AXIS_ARRAY(float(x), float(y), float(z), float(i), float(j), float(k), float(u), float(v), float(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; } - // In-place cast to types having fewer fields + // In-place reinterpret-cast to types having fewer fields FI operator XYval&() { return *(XYval*)this; } FI operator const XYval&() const { return *(const XYval*)this; } @@ -824,22 +838,22 @@ struct XYZval { 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 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 NUM_AXIS_ALL(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 NUM_AXIS_ALL(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 XYZval &rs) const { return NUM_AXIS_ALL(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 NUM_AXIS_ALL(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 NUM_AXIS_ALL(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 NUM_AXIS_ALL(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); } + FI bool operator< (const XYZEval &rs) const { return NUM_AXIS_ALL(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 NUM_AXIS_ALL(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 NUM_AXIS_ALL(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 NUM_AXIS_ALL(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); } }; @@ -909,7 +923,7 @@ struct XYZEval { // Pointer to the data as a simple array explicit FI operator T* () { return pos; } // If any element is true then it's true - FI constexpr operator bool() const { return 0 LOGICAL_AXIS_GANG(|| e, || x, || y, || z, || i, || j, || k, || u, || v, || w); } + FI constexpr operator bool() const { return LOGICAL_AXIS_ANY(e, x, y, z, i, j, k, u, v, w); } // Smallest element FI constexpr T small() const { return _MIN(LOGICAL_AXIS_LIST(e, x, y, z, i, j, k, u, v, w)); } // Largest element @@ -927,13 +941,13 @@ struct XYZEval { 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)); } + FI constexpr XYZEval asFloat() const { return LOGICAL_AXIS_ARRAY(float(e), float(x), float(y), float(z), float(i), float(j), float(k), float(u), float(v), float(w)); } // Marlin workspace shifting is done with G92 and M206 FI XYZEval asLogical() const { XYZEval o = asFloat(); toLogical(o); return o; } FI XYZEval asNative() const { XYZEval o = asFloat(); toNative(o); return o; } - // In-place cast to types having fewer fields + // In-place reinterpret-cast to types having fewer fields FI operator XYval&() { return *(XYval*)this; } FI operator const XYval&() const { return *(const XYval*)this; } FI operator XYZval&() { return *(XYZval*)this; } @@ -998,24 +1012,24 @@ struct XYZEval { 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 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 NUM_AXIS_ALL(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 LOGICAL_AXIS_ALL(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 LOGICAL_AXIS_ALL(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 XYZEval &rs) const { return LOGICAL_AXIS_ALL(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 LOGICAL_AXIS_ALL(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 LOGICAL_AXIS_ALL(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 LOGICAL_AXIS_ALL(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); } + FI bool operator< (const XYZval &rs) const { return NUM_AXIS_ALL(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 NUM_AXIS_ALL(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 NUM_AXIS_ALL(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 NUM_AXIS_ALL(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); } }; diff --git a/Marlin/src/feature/e_parser.cpp b/Marlin/src/feature/e_parser.cpp index bda1232154..3744870164 100644 --- a/Marlin/src/feature/e_parser.cpp +++ b/Marlin/src/feature/e_parser.cpp @@ -60,6 +60,10 @@ EmergencyParser emergency_parser; void quickresume_stepper(); #endif +#if ENABLED(SOFT_FEED_HOLD) + bool realtime_ramping_pause_flag = false; +#endif + void EmergencyParser::update(EmergencyParser::State &state, const uint8_t c) { auto uppercase = [](char c) { return TERN0(GCODE_CASE_INSENSITIVE, WITHIN(c, 'a', 'z')) ? c + 'A' - 'a' : c; @@ -150,7 +154,7 @@ void EmergencyParser::update(EmergencyParser::State &state, const uint8_t c) { case EP_M4: switch (c) { case '1' :state = EP_M41; break; - #if ENABLED(FT_MOTION_RESONANCE_TEST) + #if ENABLED(FTM_RESONANCE_TEST) case '9': state = EP_M49; break; #endif default: state = EP_IGNORE; @@ -223,8 +227,8 @@ void EmergencyParser::update(EmergencyParser::State &state, const uint8_t c) { #endif #if ENABLED(REALTIME_REPORTING_COMMANDS) case EP_GRBL_STATUS: report_current_position_moving(); break; - case EP_GRBL_PAUSE: quickpause_stepper(); break; - case EP_GRBL_RESUME: quickresume_stepper(); break; + case EP_GRBL_PAUSE: TERN(SOFT_FEED_HOLD, realtime_ramping_pause_flag = true, quickpause_stepper()); break; + case EP_GRBL_RESUME: TERN(SOFT_FEED_HOLD, realtime_ramping_pause_flag = false, quickresume_stepper()); break; #endif #if ENABLED(SOFT_RESET_VIA_SERIAL) case EP_KILL: hal.reboot(); break; diff --git a/Marlin/src/feature/e_parser.h b/Marlin/src/feature/e_parser.h index 9f74a38116..a582ec6c3d 100644 --- a/Marlin/src/feature/e_parser.h +++ b/Marlin/src/feature/e_parser.h @@ -93,3 +93,7 @@ private: }; extern EmergencyParser emergency_parser; + +#if ENABLED(SOFT_FEED_HOLD) + extern bool realtime_ramping_pause_flag; +#endif diff --git a/Marlin/src/feature/mmu/mmu2-serial-protocol.md b/Marlin/src/feature/mmu/mmu2-serial-protocol.md index 474fcd488b..80480d15c7 100644 --- a/Marlin/src/feature/mmu/mmu2-serial-protocol.md +++ b/Marlin/src/feature/mmu/mmu2-serial-protocol.md @@ -41,12 +41,12 @@ as soon as the filament is fed down to the extruder. We follow with: - MMU <= 'C0\n' -MMU will feed a few more millimeters of filament for the extruder gears to grab. +MMU will feed a few more millimeters of filament for the extruder gears to grab.\ When done, the MMU sends - MMU => 'ok\n' -We don't wait for a response here but immediately continue with the next G-code which should +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 diff --git a/Marlin/src/gcode/calibrate/G28.cpp b/Marlin/src/gcode/calibrate/G28.cpp index 4a0ecffc4b..dabb53b47b 100644 --- a/Marlin/src/gcode/calibrate/G28.cpp +++ b/Marlin/src/gcode/calibrate/G28.cpp @@ -377,7 +377,7 @@ void GcodeSuite::G28() { float z_homing_height = seenR ? parser.value_linear_units() : Z_CLEARANCE_FOR_HOMING; // Check for any lateral motion that might require clearance - const bool may_skate = seenR NUM_AXIS_GANG(|| doX, || doY, || TERN0(Z_SAFE_HOMING, doZ), || doI, || doJ, || doK, || doU, || doV, || doW); + const bool may_skate = seenR && NUM_AXIS_ANY(doX, doY, TERN0(Z_SAFE_HOMING, doZ), doI, doJ, doK, doU, doV, doW); if (seenR && z_homing_height == 0) { if (DEBUGGING(LEVELING)) DEBUG_ECHOLNPGM("R0 = No Z raise"); diff --git a/Marlin/src/gcode/feature/ft_motion/M495_M496.cpp b/Marlin/src/gcode/feature/ft_motion/M495_M496.cpp index 15e1a1fe0f..18787ba32f 100644 --- a/Marlin/src/gcode/feature/ft_motion/M495_M496.cpp +++ b/Marlin/src/gcode/feature/ft_motion/M495_M496.cpp @@ -25,6 +25,7 @@ #if ENABLED(FTM_RESONANCE_TEST) #include "../../gcode.h" +#include "../../../lcd/marlinui.h" #include "../../../module/ft_motion.h" #include "../../../module/ft_motion/resonance_generator.h" @@ -173,6 +174,7 @@ void GcodeSuite::M496() { if (ftMotion.rtg.isActive()) { ftMotion.rtg.abort(); EmergencyParser::rt_stop_by_M496 = false; + ui.refresh(); #if DISABLED(MARLIN_SMALL_BUILD) SERIAL_ECHOLN(F("Resonance Test"), F(" aborted.")); #endif diff --git a/Marlin/src/inc/Conditionals-1-axes.h b/Marlin/src/inc/Conditionals-1-axes.h index d81aa2c746..fd917322f0 100644 --- a/Marlin/src/inc/Conditionals-1-axes.h +++ b/Marlin/src/inc/Conditionals-1-axes.h @@ -293,7 +293,7 @@ #if NUM_AXES >= 1 #define HAS_X_AXIS 1 #define HAS_A_AXIS 1 - #if NUM_AXES >= XY + #if NUM_AXES >= 2 #define HAS_Y_AXIS 1 #define HAS_B_AXIS 1 #if NUM_AXES >= 3 diff --git a/Marlin/src/inc/Conditionals-4-adv.h b/Marlin/src/inc/Conditionals-4-adv.h index 75c4efa743..5943b513e7 100644 --- a/Marlin/src/inc/Conditionals-4-adv.h +++ b/Marlin/src/inc/Conditionals-4-adv.h @@ -359,6 +359,10 @@ #if ANY(FTM_SHAPER_EI, FTM_SHAPER_2HEI, FTM_SHAPER_3HEI) #define HAS_FTM_EI_SHAPING 1 #endif + + #if ANY(FTM_DIR_CHANGE_HOLD_X, FTM_DIR_CHANGE_HOLD_Y, FTM_DIR_CHANGE_HOLD_Z, FTM_DIR_CHANGE_HOLD_E) + #define HAS_FTM_DIR_CHANGE_HOLD 1 + #endif #endif // Standard Motion diff --git a/Marlin/src/inc/Conditionals-5-post.h b/Marlin/src/inc/Conditionals-5-post.h index 024eb42f51..55cd16c8d7 100644 --- a/Marlin/src/inc/Conditionals-5-post.h +++ b/Marlin/src/inc/Conditionals-5-post.h @@ -605,11 +605,9 @@ #endif #endif - #if HAS_SD_DETECT && NONE(HAS_GRAPHICAL_TFT, LCD_USE_DMA_FSMC, HAS_FSMC_GRAPHICAL_TFT, HAS_SPI_GRAPHICAL_TFT, IS_DWIN_MARLINUI, EXTENSIBLE_UI, HAS_DWIN_E3V2, HAS_U8GLIB_I2C_OLED) - #define REINIT_NOISY_LCD 1 // Have the LCD re-init on SD insertion - #endif - -#endif // HAS_MEDIA +#else // !HAS_MEDIA + #undef REINIT_NOISY_LCD +#endif /** * Power Supply @@ -3049,9 +3047,10 @@ #endif // User Interface -#if ENABLED(FREEZE_FEATURE) && !PIN_EXISTS(FREEZE) && PIN_EXISTS(KILL) +#if ENABLED(FREEZE_FEATURE) && DISABLED(NO_FREEZE_PIN) && !PIN_EXISTS(FREEZE) && PIN_EXISTS(KILL) #define FREEZE_PIN KILL_PIN -#elif PIN_EXISTS(KILL) && TERN1(FREEZE_FEATURE, KILL_PIN != FREEZE_PIN) + #define FREEZE_STOLE_KILL_PIN_WARNING 1 +#elif PIN_EXISTS(KILL) && TERN1(HAS_FREEZE_PIN, KILL_PIN != FREEZE_PIN) #define HAS_KILL 1 #endif #if PIN_EXISTS(HOME) diff --git a/Marlin/src/inc/SanityCheck.h b/Marlin/src/inc/SanityCheck.h index 5856723c77..3155127c58 100644 --- a/Marlin/src/inc/SanityCheck.h +++ b/Marlin/src/inc/SanityCheck.h @@ -579,8 +579,12 @@ static_assert(COUNT(arm) == LOGICAL_AXES, "AXIS_RELATIVE_MODES must contain " _L /** * Instant Freeze */ -#if ENABLED(FREEZE_FEATURE) && !(PIN_EXISTS(FREEZE) && defined(FREEZE_STATE)) - #error "FREEZE_FEATURE requires both FREEZE_PIN and FREEZE_STATE." +#if ENABLED(SOFT_FEED_HOLD) && !defined(FREEZE_JERK) + #error "SOFT_FEED_HOLD requires FREEZE_JERK." +#elif ENABLED(FREEZE_FEATURE) && DISABLED(NO_FREEZE_PIN) && !(defined(FREEZE_PIN) && defined(FREEZE_STATE)) + #error "FREEZE_FEATURE requires FREEZE_PIN and FREEZE_STATE." +#elif ENABLED(NO_FREEZE_PIN) && !(defined(REALTIME_REPORTING_COMMANDS)) + #error "NO_FREEZE_PIN requires REALTIME_REPORTING_COMMANDS." #endif /** @@ -4501,8 +4505,8 @@ static_assert(_PLUS_TEST(3), "DEFAULT_MAX_ACCELERATION values must be positive." #error "SMOOTH_LIN_ADVANCE is not yet available in FT_MOTION. Disable NO_STANDARD_MOTION if you require it." #elif ENABLED(MIXING_EXTRUDER) #error "MIXING_EXTRUDER is not yet available in FT_MOTION. Disable NO_STANDARD_MOTION if you require it." - #elif ENABLED(FREEZE_FEATURE) - #error "FREEZE_FEATURE is not yet available in FT_MOTION. Disable NO_STANDARD_MOTION if you require it." + #elif ENABLED(SOFT_FEED_HOLD) + #error "SOFT_FEED_HOLD is not yet available in FT_MOTION. Disable NO_STANDARD_MOTION if you require it." #elif ENABLED(DIRECT_STEPPING) #error "DIRECT_STEPPING is not yet available in FT_MOTION. Disable NO_STANDARD_MOTION if you require it." #elif ENABLED(DIFFERENTIAL_EXTRUDER) diff --git a/Marlin/src/inc/Version.h b/Marlin/src/inc/Version.h index d73463086b..3264b06f06 100644 --- a/Marlin/src/inc/Version.h +++ b/Marlin/src/inc/Version.h @@ -42,7 +42,7 @@ * version was tagged. */ #ifndef STRING_DISTRIBUTION_DATE - #define STRING_DISTRIBUTION_DATE "2025-12-25" + #define STRING_DISTRIBUTION_DATE "2026-01-21" #endif /** diff --git a/Marlin/src/inc/Warnings.cpp b/Marlin/src/inc/Warnings.cpp index 9c4eabaf6e..6a097777b0 100644 --- a/Marlin/src/inc/Warnings.cpp +++ b/Marlin/src/inc/Warnings.cpp @@ -993,3 +993,22 @@ #if ALL(SMOOTH_LIN_ADVANCE, MIXING_EXTRUDER) #warning "SMOOTH_LIN_ADVANCE with MIXING_EXTRUDER is untested. Use with caution." #endif + +/** + * Some LCDs need re-init to deal with flaky SPI bus sharing + */ +#if HAS_SD_DETECT && NONE(HAS_GRAPHICAL_TFT, LCD_USE_DMA_FSMC, HAS_FSMC_GRAPHICAL_TFT, HAS_SPI_GRAPHICAL_TFT, IS_DWIN_MARLINUI, EXTENSIBLE_UI, HAS_DWIN_E3V2, HAS_U8GLIB_I2C_OLED) + #define RECOMMEND_REINIT_NOISY_LCD 1 +#endif +#if RECOMMEND_REINIT_NOISY_LCD && DISABLED(REINIT_NOISY_LCD) + #warning "It is recommended to enable REINIT_NOISY_LCD with your LCD controller model." +#elif !RECOMMEND_REINIT_NOISY_LCD && ENABLED(REINIT_NOISY_LCD) + #warning "REINIT_NOISY_LCD is probably not required with your LCD controller model." +#endif + +/** + * FREEZE_FEATURE may override the KILL_PIN + */ +#if FREEZE_STOLE_KILL_PIN_WARNING + #warning "FREEZE_FEATURE uses KILL_PIN replacing the KILL button. Define a separate FREEZE_PIN if you don't want this behavior." +#endif diff --git a/Marlin/src/lcd/extui/ftdi_eve_touch_ui/ftdi_eve_lib/README.md b/Marlin/src/lcd/extui/ftdi_eve_touch_ui/ftdi_eve_lib/README.md index 61e5f3a388..4a5fd4abc8 100644 --- a/Marlin/src/lcd/extui/ftdi_eve_touch_ui/ftdi_eve_lib/README.md +++ b/Marlin/src/lcd/extui/ftdi_eve_touch_ui/ftdi_eve_lib/README.md @@ -1,17 +1,17 @@ ## FTDI EVE Library -The FTDI EVE Library is a fully open-source library and UI framework for the FTDI +The FTDI EVE Library is a fully open-source library and UI framework for the FTDI\ FT800 and FT810 graphics processor. -Although the library has been developed within Lulzbot for providing a user interface +Although the library has been developed within Lulzbot for providing a user interface\ for Marlin, the library has been written so that it can be used in any Arduino sketch. -The library is split into two parts. The "basic" API provides a shallow interface to -the underlying FTDI hardware and command FIFO and provides low-level access to the +The library is split into two parts. The "basic" API provides a shallow interface to\ +the underlying FTDI hardware and command FIFO and provides low-level access to the\ hardware as closely as possible to the API described in the FTDI Programmer's Guide. -The "extended" API builds on top of the "basic" API to provide a GUI framework for -handling common challenges in building a usable GUI. The GUI framework provides the +The "extended" API builds on top of the "basic" API to provide a GUI framework for\ +handling common challenges in building a usable GUI. The GUI framework provides the\ following features: - Macros for a resolution-independent placement of widgets based on a grid. @@ -22,6 +22,6 @@ following features: - A sound player class for playing individual notes or complete sound sequences. - Display list caching, for storing static background elements of a screen in RAM_G. -See the "examples" folder for Arduino sketches. Modify the "src/config.h" file in -each to suit your particular setup. The "sample_configs" contain sample configuration -files for running the sketches on our 3D printer boards. +See the "examples" folder for Arduino sketches. Modify the "src/config.h" file in each\ +to suit your particular setup. The "sample_configs" contain sample configuration files\ +for running the sketches on our 3D printer boards. diff --git a/Marlin/src/lcd/language/language_en.h b/Marlin/src/lcd/language/language_en.h index 559b3e339d..ba5228a1f1 100644 --- a/Marlin/src/lcd/language/language_en.h +++ b/Marlin/src/lcd/language/language_en.h @@ -158,6 +158,7 @@ namespace LanguageNarrow_en { LSTR MSG_PREHEAT_1_END_E = _UxGT("Preheat ") PREHEAT_1_LABEL _UxGT(" End ~"); LSTR MSG_PREHEAT_1_ALL = _UxGT("Preheat ") PREHEAT_1_LABEL _UxGT(" All"); LSTR MSG_PREHEAT_1_BEDONLY = _UxGT("Preheat ") PREHEAT_1_LABEL _UxGT(" Bed"); + LSTR MSG_PREHEAT_1_CHAMBER = _UxGT("Preheat ") PREHEAT_1_LABEL _UxGT(" Chmb"); LSTR MSG_PREHEAT_1_SETTINGS = _UxGT("Preheat ") PREHEAT_1_LABEL _UxGT(" Conf"); LSTR MSG_PREHEAT_2 = _UxGT("Preheat ") PREHEAT_2_LABEL; @@ -1141,6 +1142,14 @@ namespace LanguageNarrow_en { namespace LanguageWide_en { using namespace LanguageNarrow_en; #if LCD_WIDTH >= 20 || HAS_DWIN_E3V2 + LSTR MSG_PREHEAT_1_END = _UxGT("Preheat ") PREHEAT_1_LABEL _UxGT(" Hotend"); + LSTR MSG_PREHEAT_1_END_E = _UxGT("Preheat ") PREHEAT_1_LABEL _UxGT(" Hotend ~"); + LSTR MSG_PREHEAT_1_CHAMBER = _UxGT("Preheat ") PREHEAT_1_LABEL _UxGT(" Chamber"); + LSTR MSG_PREHEAT_1_SETTINGS = _UxGT("Preheat ") PREHEAT_1_LABEL _UxGT(" Settings"); + LSTR MSG_PREHEAT_M_END = _UxGT("Preheat $ Hotend"); + LSTR MSG_PREHEAT_M_END_E = _UxGT("Preheat $ Hotend ~"); + LSTR MSG_PREHEAT_M_CHAMBER = _UxGT("Preheat $ Chamber"); + LSTR MSG_PREHEAT_M_SETTINGS = _UxGT("Preheat $ Settings"); LSTR MSG_HOST_START_PRINT = _UxGT("Start Host Print"); LSTR MSG_PRINTING_OBJECT = _UxGT("Printing Object"); LSTR MSG_CANCEL_OBJECT = _UxGT("Cancel Object"); @@ -1164,8 +1173,6 @@ namespace LanguageWide_en { LSTR MSG_HOMING_FEEDRATE_Y = _UxGT("Y Homing Feedrate"); LSTR MSG_HOMING_FEEDRATE_Z = _UxGT("Z Homing Feedrate"); LSTR MSG_EEPROM_INITIALIZED = _UxGT("Default Settings Restored"); - LSTR MSG_PREHEAT_M_CHAMBER = _UxGT("Preheat $ Chamber"); - LSTR MSG_PREHEAT_M_SETTINGS = _UxGT("Preheat $ Config"); LSTR MSG_FTM_RT_RUNNING = _UxGT("Resonance Test Running..."); LSTR MSG_FTM_RESONANCE_FREQ = _UxGT("Resonance frequency"); #endif diff --git a/Marlin/src/lcd/menu/menu_motion.cpp b/Marlin/src/lcd/menu/menu_motion.cpp index a9261dc922..59172a4787 100644 --- a/Marlin/src/lcd/menu/menu_motion.cpp +++ b/Marlin/src/lcd/menu/menu_motion.cpp @@ -424,12 +424,18 @@ void menu_move() { if (ftMotion.rtg.isActive() && !ftMotion.rtg.isDone()) { STATIC_ITEM(MSG_FTM_RT_RUNNING); - ACTION_ITEM(MSG_FTM_RT_STOP, []{ ftMotion.rtg.abort(); ui.refresh(); }); + GCODES_ITEM(MSG_FTM_RT_STOP, F("M496")); } else { - GCODES_ITEM_N(X_AXIS, MSG_FTM_RT_START_N, F("M495 X S")); - GCODES_ITEM_N(Y_AXIS, MSG_FTM_RT_START_N, F("M495 Y S")); - GCODES_ITEM_N(Z_AXIS, MSG_FTM_RT_START_N, F("M495 Z S")); + #if HAS_X_AXIS + GCODES_ITEM_N(X_AXIS, MSG_FTM_RT_START_N, F("M495 X S")); + #endif + #if HAS_Y_AXIS + GCODES_ITEM_N(Y_AXIS, MSG_FTM_RT_START_N, F("M495 Y S")); + #endif + #if HAS_Z_AXIS + GCODES_ITEM_N(Z_AXIS, MSG_FTM_RT_START_N, F("M495 Z S")); + #endif SUBMENU(MSG_FTM_RETRIEVE_FREQ, menu_ftm_resonance_freq); } diff --git a/Marlin/src/lcd/tft_io/st7735.h b/Marlin/src/lcd/tft_io/st7735.h index 1b0d23b6c4..f94c82be03 100644 --- a/Marlin/src/lcd/tft_io/st7735.h +++ b/Marlin/src/lcd/tft_io/st7735.h @@ -101,8 +101,8 @@ #define ST7735_NVFCTR1 0xD9 // EEPROM Control Status #define ST7735_NVFCTR2 0xDE // EEPROM Read Command #define ST7735_NVFCTR3 0xDF // EEPROM Write Command -#define ST7735_GMCTRP1 0xE0 // Gamma (‘+’polarity) Correction Characteristics Setting -#define ST7735_GMCTRN1 0xE1 // GMCTRN1 (E1h): Gamma ‘-’polarity Correction Characteristics Setting +#define ST7735_GMCTRP1 0xE0 // Gamma ('+'polarity) Correction Characteristics Setting +#define ST7735_GMCTRN1 0xE1 // GMCTRN1 (E1h): Gamma '-'polarity Correction Characteristics Setting #define ST7735_EXTCTRL 0xF0 // Extension Command Control #define ST7735_VCOM4L 0xFF // Vcom 4 Level Control diff --git a/Marlin/src/module/ft_motion.cpp b/Marlin/src/module/ft_motion.cpp index f6113c398e..93101a5a93 100644 --- a/Marlin/src/module/ft_motion.cpp +++ b/Marlin/src/module/ft_motion.cpp @@ -70,10 +70,15 @@ AxisBits FTMotion::moving_axis_flags, // These axes are moving in the // Block data variables. xyze_pos_t FTMotion::startPos, // (mm) Start position of block - FTMotion::endPos_prevBlock = { 0.0f }; // (mm) End position of previous block + FTMotion::endPos_prevBlock = { 0.0f }, // (mm) End position of previous block + FTMotion::last_target_traj = { 0.0f }; // (mm) Last target position after shaping and smoothing xyze_float_t FTMotion::ratio; // (ratio) Axis move ratio of block float FTMotion::tau = 0.0f; // (s) Time since start of block bool FTMotion::fastForwardUntilMotion = false; // Fast forward time if there is no motion +#if HAS_FTM_DIR_CHANGE_HOLD + xyze_uint_t FTMotion::hold_frames; // Briefly hold motion after direction changes to fix TMC2208 bug + AxisBits FTMotion::last_traj_dir; // Direction of the last trajectory point after shaping, smoothing, ... +#endif // Trajectory generators TrapezoidalTrajectoryGenerator FTMotion::trapezoidalGenerator; @@ -244,7 +249,11 @@ void FTMotion::reset() { TERN_(DISTINCT_E_FACTORS, block_extruder_axis = E_AXIS); moving_axis_flags.reset(); - + last_target_traj.reset(); + #if HAS_FTM_DIR_CHANGE_HOLD + last_traj_dir.reset(); + hold_frames.reset(); + #endif if (did_suspend) stepper.wake_up(); } @@ -371,7 +380,7 @@ bool FTMotion::plan_next_block() { if (current_block->is_sync_pos()) stepper._set_position(current_block->position); continue; } - ensure_float_precision(); + ensure_extruder_float_precision(); #if ENABLED(POWER_LOSS_RECOVERY) recovery.info.sdpos = current_block->sdpos; @@ -411,7 +420,7 @@ bool FTMotion::plan_next_block() { TERN_(FTM_HAS_LIN_ADVANCE, use_advance_lead = current_block->use_advance_lead); axis_move_dir = current_block->direction_bits; - #define _SET_MOVE_END(A) moving_axis_flags.A = moveDist.A ? true : false; + #define _SET_MOVE_END(A) moving_axis_flags.A = bool(moveDist.A); LOGICAL_AXIS_MAP(_SET_MOVE_END); @@ -432,7 +441,7 @@ bool FTMotion::plan_next_block() { * resolution = 2^(floor(log2(|x|)) - 23) * By resetting at ±1'000mm (1 meter), we get a minimum resolution of ~ 0.00006mm, enough for smoothing to work well. */ - void FTMotion::ensure_float_precision() { + void FTMotion::ensure_extruder_float_precision() { constexpr float FTM_POSITION_WRAP_THRESHOLD = 1000; // (mm) Reset when position exceeds this to prevent floating point precision loss if (ABS(endPos_prevBlock.E) < FTM_POSITION_WRAP_THRESHOLD) return; @@ -453,6 +462,9 @@ bool FTMotion::plan_next_block() { // Offset linear advance previous position prev_traj_e += offset; + // Make sure the difference is accounted-for in the past + last_target_traj.e += offset; + // Offset stepper current position const int64_t delta_steps_q48_16 = offset * planner.settings.axis_steps_per_mm[block_extruder_axis] * (1ULL << 16); stepping.curr_steps_q48_16.E += delta_steps_q48_16; @@ -524,13 +536,14 @@ xyze_float_t FTMotion::calc_traj_point(const float dist) { // Approximate Gaussian smoothing via chained EMAs auto _smoothen = [&](const AxisEnum axis, axis_smoothing_t &smoo) { - if (smoo.alpha <= 0.0f) return; - float smooth_val = traj_coords[axis]; - for (uint8_t _i = 0; _i < FTM_SMOOTHING_ORDER; ++_i) { - smoo.smoothing_pass[_i] += (smooth_val - smoo.smoothing_pass[_i]) * smoo.alpha; - smooth_val = smoo.smoothing_pass[_i]; + if (smoo.alpha != 1.0f) { + float smooth_val = traj_coords[axis]; + for (uint8_t _i = 0; _i < FTM_SMOOTHING_ORDER; ++_i) { + smoo.smoothing_pass[_i] += (smooth_val - smoo.smoothing_pass[_i]) * smoo.alpha; + smooth_val = smoo.smoothing_pass[_i]; + } + traj_coords[axis] = smooth_val; } - traj_coords[axis] = smooth_val; }; #define _SMOOTHEN(A) _smoothen(_AXIS(A), smoothing.A); @@ -584,7 +597,7 @@ void FTMotion::fill_stepper_plan_buffer() { float total_duration = currentGenerator->getTotalDuration(); // If the current plan is empty, it will have zero duration. while (tau + FTM_TS > total_duration) { /** - * We’ve reached the end of the current block. + * We've reached the end of the current block. * * `tau` is the time that has elapsed inside this block. After a block is finished, the next one may * start at any point between *just before* the last sampled time (one step earlier, i.e. `-FTM_TS`) @@ -593,7 +606,7 @@ void FTMotion::fill_stepper_plan_buffer() { * * To account for that uncertainty we simply subtract the duration of the finished block from `tau`. * This brings us back to a time value that is valid for the next block, while still allowing the next - * block’s start to be offset by up to one time step into the past. + * block's start to be offset by up to one time step into the past. */ tau -= total_duration; const bool plan_available = plan_next_block(); @@ -604,16 +617,48 @@ void FTMotion::fill_stepper_plan_buffer() { // Get distance from trajectory generator xyze_float_t traj_coords = calc_traj_point(currentGenerator->getDistanceAtTime(tau)); - if (fastForwardUntilMotion && traj_coords == startPos) { + if (fastForwardUntilMotion && traj_coords == last_target_traj) { // Axis synchronization delays all axes. When coming from a reset, there is a ramp up time filling all buffers. // If the slowest axis doesn't move and it isn't smoothened, this time can be skipped. // It eliminates idle time when changing smoothing time or shapers and speeds up homing and bed leveling. } else { + + #if HAS_FTM_DIR_CHANGE_HOLD + + // When a flip is detected (and the axis is in stealthChop or is standalone), + // hold that axis' trajectory coordinate constant for at least 750µs. + + #define DIR_FLIP_HOLD_S 0.000'750f + static constexpr uint32_t dir_flip_hold_frames = 1 + (DIR_FLIP_HOLD_S) / (FTM_TS); + + auto start_hold_if_dir_flip = [&](const AxisEnum a) { + const bool dir = traj_coords[a] > last_target_traj[a], + moved = traj_coords[a] != last_target_traj[a], + flipped = moved && (dir != last_traj_dir[a]), + hold = !moved || (flipped && hold_frames[a] > 0); + if (hold) { + if (hold_frames[a]) hold_frames[a]--; + traj_coords[a] = last_target_traj[a]; + } + else { + last_traj_dir[a] = dir; + hold_frames[a] = dir_flip_hold_frames; + } + }; + + #define START_HOLD_IF_DIR_FLIP(A) TERN_(FTM_DIR_CHANGE_HOLD_##A, start_hold_if_dir_flip(_AXIS(A))); + + LOGICAL_AXIS_MAP(START_HOLD_IF_DIR_FLIP); + + #endif // HAS_FTM_DIR_CHANGE_HOLD + fastForwardUntilMotion = false; + // Calculate and store stepper plan in buffer stepping_enqueue(traj_coords); } + last_target_traj = traj_coords; } } diff --git a/Marlin/src/module/ft_motion.h b/Marlin/src/module/ft_motion.h index 42dab9951d..15be0154ae 100644 --- a/Marlin/src/module/ft_motion.h +++ b/Marlin/src/module/ft_motion.h @@ -326,11 +326,17 @@ class FTMotion { private: // Block data variables. static xyze_pos_t startPos, // (mm) Start position of block - endPos_prevBlock; // (mm) End position of previous block + endPos_prevBlock, // (mm) End position of previous block + last_target_traj; // (mm) Last target position after shaping and smoothing static xyze_float_t ratio; // (ratio) Axis move ratio of block static float tau; // (s) Time since start of block static bool fastForwardUntilMotion; // Fast forward time if there is no motion + #if HAS_FTM_DIR_CHANGE_HOLD + static xyze_uint_t hold_frames; // Briefly hold motion after direction changes to fix TMC2208 bug + static AxisBits last_traj_dir; // Direction of the last trajectory point after shaping, smoothing, ... + #endif + // Trajectory generators static TrapezoidalTrajectoryGenerator trapezoidalGenerator; #if ENABLED(FTM_POLYS) @@ -375,8 +381,19 @@ class FTMotion { // Synchronize and reset motion prior to parameter changes friend void ft_config_t::prep_for_shaper_change(); static void prep_for_shaper_change() { + // planner.synchronize guarantees that motion reached a standstill with no echoes pending execution (including a runout block) planner.synchronize(); - reset(); + // Due to smoothing, the end position may not have been reached exactly. + // This is normally fine, but if smoothing time changes, and we assume it was reached, + // it may cause discontinuities. + // Therefore, set the next starting position to the exact reached position. + endPos_prevBlock = last_target_traj; + // We now know that we are not moving and there are no pending echoes, + // so set all shaping buffers to current position in case the new smoothing/shaping + // parameters force input shaping to look in a past position for echoes. + shaping.fill(endPos_prevBlock); + TERN_(FTM_SMOOTHING, smoothing.fill(endPos_prevBlock)); + fastForwardUntilMotion = true; } // Buffers @@ -386,7 +403,7 @@ class FTMotion { static void fill_stepper_plan_buffer(); static xyze_float_t calc_traj_point(const float dist); static bool plan_next_block(); - static void ensure_float_precision() IF_DISABLED(HAS_EXTRUDERS, {}); + static void ensure_extruder_float_precision() IF_DISABLED(HAS_EXTRUDERS, {}); }; // class FTMotion diff --git a/Marlin/src/module/ft_motion/resonance_generator.cpp b/Marlin/src/module/ft_motion/resonance_generator.cpp index 2c2297e312..1d2bd553fe 100644 --- a/Marlin/src/module/ft_motion/resonance_generator.cpp +++ b/Marlin/src/module/ft_motion/resonance_generator.cpp @@ -50,14 +50,38 @@ void ResonanceGenerator::reset() { done = false; } +// Fast sine approximation +float ResonanceGenerator::fast_sin(float x) { + static constexpr float INV_TAU = (1.0f / M_TAU); + + // Reduce the angle to [-π, π] + const float y = x * INV_TAU; // Multiples of 2π + int k = static_cast(y); // Truncates toward zero + + // Negative? The truncation is one too high. + if (y < 0.0f) --k; // Correct for negatives + + float r = x - k * M_TAU; // -π <= r <= π + if (r > M_PI) + r -= M_TAU; + else if (r < -M_PI) + r += M_TAU; + + // Cheap polynomial approximation of sin(r) + return r * (1.27323954f - 0.405284735f * ABS(r)); +} + void ResonanceGenerator::fill_stepper_plan_buffer() { - xyze_float_t traj_coords = {}; + xyze_float_t traj_coords = rt_params.start_pos; + + const float amplitude_precalc = (rt_params.amplitude_correction * rt_params.accel_per_hz * 0.25f) / sq(M_PI); + + float rt_factor = rt_time * M_TAU; while (!ftMotion.stepping.is_full()) { // Calculate current frequency - // Logarithmic approach with duration per octave - const float freq = rt_params.min_freq * powf(2.0f, rt_time / rt_params.octave_duration); - if (freq > rt_params.max_freq) { + current_freq *= freq_mul; + if (current_freq > rt_params.max_freq) { done = true; return; } @@ -65,22 +89,23 @@ void ResonanceGenerator::fill_stepper_plan_buffer() { // Amplitude based on a sinusoidal wave : A = accel / (4 * PI^2 * f^2) //const float accel_magnitude = rt_params.accel_per_hz * freq; //const float amplitude = rt_params.amplitude_correction * accel_magnitude / (4.0f * sq(M_PI) * sq(freq)); - const float amplitude = rt_params.amplitude_correction * rt_params.accel_per_hz * 0.25f / (sq(M_PI) * freq); + const float amplitude = amplitude_precalc / current_freq; // Phase in radians - const float phase = 2.0f * M_PI * freq * rt_time; + const float phase = current_freq * rt_factor; // Position Offset : between -A and +A - const float pos_offset = amplitude * sinf(phase); + const float pos_offset = amplitude * fast_sin(phase); - // Set base position and apply offset to the test axis in one step for all axes - #define _SET_TRAJ(A) traj_coords.A = rt_params.start_pos.A + (rt_params.axis == A##_AXIS ? pos_offset : 0.0f); - LOGICAL_AXIS_MAP(_SET_TRAJ); + // Resonate the axis being tested + traj_coords[rt_params.axis] = rt_params.start_pos[rt_params.axis] + pos_offset; + + // Increment for the next point (before calling out) + rt_time += FTM_TS; + rt_factor += FTM_TS * M_TAU; // Store in buffer ftMotion.stepping_enqueue(traj_coords); - // Increment time for the next point - rt_time += FTM_TS; } } diff --git a/Marlin/src/module/ft_motion/resonance_generator.h b/Marlin/src/module/ft_motion/resonance_generator.h index 16156693dd..06a34e4fd6 100644 --- a/Marlin/src/module/ft_motion/resonance_generator.h +++ b/Marlin/src/module/ft_motion/resonance_generator.h @@ -25,14 +25,18 @@ #include +#ifndef M_TAU + #define M_TAU (2.0f * M_PI) +#endif + typedef struct FTMResonanceTestParams { - AxisEnum axis = NO_AXIS_ENUM; // Axis to test - float min_freq = 5.0f; // Minimum frequency [Hz] - float max_freq = 100.0f; // Maximum frequency [Hz] - float octave_duration = 40.0f; // Octave duration for logarithmic progression - float accel_per_hz = 60.0f; // Acceleration per Hz [mm/sec/Hz] or [g/Hz] - int16_t amplitude_correction = 5; // Amplitude correction factor - xyze_pos_t start_pos; // Initial stepper position + AxisEnum axis = NO_AXIS_ENUM; // Axis to test + float min_freq = 5.0f; // Minimum frequency [Hz] + float max_freq = 100.0f; // Maximum frequency [Hz] + float octave_duration = 40.0f; // Octave duration for logarithmic progression + float accel_per_hz = 60.0f; // Acceleration per Hz [mm/sec/Hz] or [g/Hz] + int16_t amplitude_correction = 5; // Amplitude correction factor + xyze_pos_t start_pos; // Initial stepper position } ftm_resonance_test_params_t; class ResonanceGenerator { @@ -51,23 +55,33 @@ class ResonanceGenerator { rt_time = t; active = true; done = false; + // Precompute frequency multiplier + current_freq = rt_params.min_freq; + const float inv_octave_duration = 1.0f / rt_params.octave_duration; + freq_mul = exp2f(FTM_TS * inv_octave_duration); } + // Return frequency based on timeline float getFrequencyFromTimeline() { - return (rt_params.min_freq * powf(2.0f, timeline / rt_params.octave_duration)); // Return frequency based on timeline + // Logarithmic approach with duration per octave + return rt_params.min_freq * exp2f(timeline / rt_params.octave_duration); } void fill_stepper_plan_buffer(); // Fill stepper plan buffer with trajectory points + void setActive(const bool state) { active = state; } bool isActive() const { return active; } - bool isDone() const { return done; } - void setActive(bool state) { active = state; } - void setDone(bool state) { done = state; } - void abort(); // Abort resonance test + void setDone(const bool state) { done = state; } + bool isDone() const { return done; } + + void abort(); // Abort resonance test private: - static float rt_time; // Test timer - static bool active; // Resonance test active - static bool done; // Resonance test done + float fast_sin(float x); // Fast sine approximation + static float rt_time; // Test timer + float freq_mul; // Frequency multiplier for sine sweeping + float current_freq; // Current frequency being generated in sinusoidal motion + static bool active; // Resonance test active + static bool done; // Resonance test done }; diff --git a/Marlin/src/module/ft_motion/shaping.h b/Marlin/src/module/ft_motion/shaping.h index 0140a969ba..88b02fbdac 100644 --- a/Marlin/src/module/ft_motion/shaping.h +++ b/Marlin/src/module/ft_motion/shaping.h @@ -151,4 +151,9 @@ typedef struct Shaping { SHAPED_MAP(_RESET_ZI); zi_idx = 0; } + void fill(const xyze_float_t pos) { + #define _FILL_ZI(A) for (uint32_t i = 0; i < ftm_zmax; i++) A.d_zi[i] = pos.A; + SHAPED_MAP(_FILL_ZI); + #undef _FILL_ZI + } } shaping_t; diff --git a/Marlin/src/module/ft_motion/smoothing.cpp b/Marlin/src/module/ft_motion/smoothing.cpp index f40bd828aa..3708629271 100644 --- a/Marlin/src/module/ft_motion/smoothing.cpp +++ b/Marlin/src/module/ft_motion/smoothing.cpp @@ -28,12 +28,12 @@ // Set smoothing time and recalculate alpha and delay. void AxisSmoothing::set_time(const float s_time) { - if (s_time > 0.001f) { - alpha = 1.0f - expf(-(FTM_TS) * (FTM_SMOOTHING_ORDER) / s_time ); + if (s_time >= 0.0001f) { + alpha = 1.0f - expf(-(FTM_TS) * (FTM_SMOOTHING_ORDER) / s_time); delay_samples = s_time * FTM_FS; } else { - alpha = 0.0f; + alpha = 1.0f; delay_samples = 0; } } diff --git a/Marlin/src/module/ft_motion/smoothing.h b/Marlin/src/module/ft_motion/smoothing.h index e3f9962a09..00be0f8892 100644 --- a/Marlin/src/module/ft_motion/smoothing.h +++ b/Marlin/src/module/ft_motion/smoothing.h @@ -55,4 +55,9 @@ typedef struct Smoothing { LOGICAL_AXIS_MAP(_CLEAR); #undef _CLEAR } + void fill(const xyze_float_t pos) { + #define _FILL_SMO(A) for (uint32_t i = 0; i < FTM_SMOOTHING_ORDER; i++) A.smoothing_pass[i] = pos.A; + LOGICAL_AXIS_MAP(_FILL_SMO); + #undef _FILL_SMO + } } smoothing_t; diff --git a/Marlin/src/module/ft_motion/stepping.h b/Marlin/src/module/ft_motion/stepping.h index b7cbe8391b..636945ac06 100644 --- a/Marlin/src/module/ft_motion/stepping.h +++ b/Marlin/src/module/ft_motion/stepping.h @@ -35,18 +35,11 @@ FORCE_INLINE constexpr uint32_t a_times_b_shift_16(const uint32_t a, const uint3 constexpr int CLZ32(const uint32_t v, const int c=0) { return v ? (TEST32(v, 31)) ? c : CLZ32(v << 1, c + 1) : 32; } -#define FTM_NEVER uint32_t(UINT16_MAX) // Reserved number to indicate "no ticks in this frame" (FRAME_TICKS_FP+1 would work too) constexpr uint32_t FRAME_TICKS = STEPPER_TIMER_RATE / FTM_FS; // Timer ticks per frame constexpr uint32_t FTM_Q_INT = 32u - CLZ32(FRAME_TICKS + 1U); // Bits to represent the integer part of the max value (duration of a frame, +1 one for FTM_NEVER). constexpr uint32_t FTM_Q = 16u - FTM_Q_INT; // uint16 interval fractional bits. // Intervals buffer has fixed point numbers with the point on this position -static_assert(FRAME_TICKS < FTM_NEVER, "(STEPPER_TIMER_RATE / FTM_FS) (" STRINGIFY(STEPPER_TIMER_RATE) " / " STRINGIFY(FTM_FS) ") must be < " STRINGIFY(FTM_NEVER) " to fit 16-bit fixed-point numbers."); - -// Sanity check -static_assert(POW(2, 16 - FTM_Q) > FRAME_TICKS, "FRAME_TICKS in Q format should fit in a uint16"); -static_assert(POW(2, 16 - FTM_Q - 1) <= FRAME_TICKS, "A smaller FTM_Q would still alow a FRAME_TICKS in Q format to fit in a uint16"); - // The _FP and _fp suffixes mean the number is in fixed point format with the point at the FTM_Q position. // See: https://en.wikipedia.org/wiki/Fixed-point_arithmetic // e.g., number_fp = number << FTM_Q @@ -54,6 +47,12 @@ static_assert(POW(2, 16 - FTM_Q - 1) <= FRAME_TICKS, "A smaller FTM_Q would stil constexpr uint32_t ONE_FP = 1UL << FTM_Q; // Number 1 in fixed point format constexpr uint32_t FP_FLOOR_MASK = ~(ONE_FP - 1); // Bit mask to do FLOOR in fixed point constexpr uint32_t FRAME_TICKS_FP = FRAME_TICKS << FTM_Q; // Ticks in a frame in fixed point +constexpr uint32_t FTM_NEVER = FRAME_TICKS_FP + 1; // Reserved number to indicate "no ticks in this frame", also max isr wait on empty stepper buffer + +// Sanity check +static_assert(FRAME_TICKS < FTM_NEVER, "(STEPPER_TIMER_RATE / FTM_FS) (" STRINGIFY(STEPPER_TIMER_RATE) " / " STRINGIFY(FTM_FS) ") must be < " STRINGIFY(FTM_NEVER) " to fit 16-bit fixed-point numbers."); +static_assert(POW(2, 16 - FTM_Q) > FRAME_TICKS, "FRAME_TICKS in Q format should fit in a uint16"); +static_assert(POW(2, 16 - FTM_Q - 1) <= FRAME_TICKS, "A smaller FTM_Q would still alow a FRAME_TICKS in Q format to fit in a uint16"); typedef struct stepper_plan { AxisBits dir_bits; diff --git a/Marlin/src/module/motion.cpp b/Marlin/src/module/motion.cpp index 1012cc4150..8a92482d82 100644 --- a/Marlin/src/module/motion.cpp +++ b/Marlin/src/module/motion.cpp @@ -1438,7 +1438,7 @@ FORCE_INLINE void segment_idle(millis_t &next_idle_ms) { float get_move_distance(const xyze_pos_t &diff OPTARG(HAS_ROTATIONAL_AXES, bool &is_cartesian_move)) { #if NUM_AXES - if (!(NUM_AXIS_GANG(diff.x, || diff.y, /* skip z */, || diff.i, || diff.j, || diff.k, || diff.u, || diff.v, || diff.w))) + if (NUM_AXIS_NONE(diff.x, diff.y, 0, diff.i, diff.j, diff.k, diff.u, diff.v, diff.w)) return TERN0(HAS_Z_AXIS, ABS(diff.z)); #if ENABLED(ARTICULATED_ROBOT_ARM) diff --git a/Marlin/src/module/planner.cpp b/Marlin/src/module/planner.cpp index b11740b00a..6da11fd8c4 100644 --- a/Marlin/src/module/planner.cpp +++ b/Marlin/src/module/planner.cpp @@ -786,7 +786,7 @@ block_t* Planner::get_future_block(const uint8_t offset) { * Calculate trapezoid (or or update FTM) motion parameters for a block. * * `entry_speed` is an optional override in mm/s. - * A value of `0` is a sentinel meaning “do not override the block’s + * A value of `0` is a sentinel meaning “do not override the block's * existing entry speed / initial_rate.” * * This is relied upon by recalculate_trapezoids(), which intentionally @@ -1372,7 +1372,7 @@ void Planner::check_axes_activity() { float high = 0.0f; for (uint8_t b = block_buffer_tail; b != block_buffer_head; b = next_block_index(b)) { const block_t * const block = &block_buffer[b]; - if (NUM_AXIS_GANG(block->steps.x, || block->steps.y, || block->steps.z, || block->steps.i, || block->steps.j, || block->steps.k, || block->steps.u, || block->steps.v, || block->steps.w)) { + if (XYZ_HAS_STEPS(block)) { const float se = float(block->steps.e) / block->step_event_count * block->nominal_speed; // mm/sec NOLESS(high, se); } @@ -2023,12 +2023,7 @@ bool Planner::_populate_block( bool cartesian_move = hints.cartesian_move; #endif - if (true NUM_AXIS_GANG( - && block->steps.a < MIN_STEPS_PER_SEGMENT, && block->steps.b < MIN_STEPS_PER_SEGMENT, && block->steps.c < MIN_STEPS_PER_SEGMENT, - && block->steps.i < MIN_STEPS_PER_SEGMENT, && block->steps.j < MIN_STEPS_PER_SEGMENT, && block->steps.k < MIN_STEPS_PER_SEGMENT, - && block->steps.u < MIN_STEPS_PER_SEGMENT, && block->steps.v < MIN_STEPS_PER_SEGMENT, && block->steps.w < MIN_STEPS_PER_SEGMENT - ) - ) { + if (!XYZ_HAS_ENOUGH_STEPS(block)) { block->millimeters = TERN0(HAS_EXTRUDERS, ABS(dist_mm.e)); } else { @@ -2098,11 +2093,7 @@ bool Planner::_populate_block( E_TERN_(block->extruder = extruder); #if ENABLED(AUTO_POWER_CONTROL) - if (NUM_AXIS_GANG( - block->steps.x, || block->steps.y, || block->steps.z, - || block->steps.i, || block->steps.j, || block->steps.k, - || block->steps.u, || block->steps.v, || block->steps.w - )) powerManager.power_on(); + if (XYZ_HAS_STEPS(block)) powerManager.power_on(); #endif // Enable active axes @@ -2352,7 +2343,7 @@ bool Planner::_populate_block( #if ANY(LIN_ADVANCE, FTM_HAS_LIN_ADVANCE) bool use_adv_lead = false; #endif - if (!ANY_AXIS_MOVES(block)) { // Is this a retract / recover move? + if (!XYZ_HAS_STEPS(block)) { // Is this a retract / recover move? accel = CEIL(settings.retract_acceleration * steps_per_mm); // Convert to: acceleration steps/sec^2 } else { @@ -2437,6 +2428,9 @@ bool Planner::_populate_block( block->acceleration_steps_per_s2 = accel; #if DISABLED(S_CURVE_ACCELERATION) block->acceleration_rate = uint32_t(accel * (float(_BV32(24)) / (STEPPER_TIMER_RATE))); + #elif ENABLED(SOFT_FEED_HOLD) + // No need to waste time calculating the linear acceleration rate until the freeze_pin is triggered, leave this 0 + block->acceleration_rate = 0; #endif #endif block->acceleration = accel / steps_per_mm; diff --git a/Marlin/src/module/planner.h b/Marlin/src/module/planner.h index 2838fb90c3..36b94da77d 100644 --- a/Marlin/src/module/planner.h +++ b/Marlin/src/module/planner.h @@ -254,7 +254,8 @@ typedef struct PlannerBlock { #if ENABLED(S_CURVE_ACCELERATION) uint32_t acceleration_time_inverse, // Inverse of acceleration and deceleration periods, expressed as integer. Scale depends on CPU being used deceleration_time_inverse; - #elif HAS_STANDARD_MOTION + #endif + #if ENABLED(HAS_STANDARD_MOTION) && (DISABLED(S_CURVE_ACCELERATION) || ENABLED(FREEZE_FEATURE)) uint32_t acceleration_rate; // Acceleration rate in (2^24 steps)/timer_ticks*s #endif @@ -1188,10 +1189,18 @@ class Planner { #define PLANNER_XY_FEEDRATE_MM_S 60.0f #endif -#define ANY_AXIS_MOVES(BLOCK) \ - (false NUM_AXIS_GANG( \ - || BLOCK->steps.a, || BLOCK->steps.b, || BLOCK->steps.c, \ - || BLOCK->steps.i, || BLOCK->steps.j, || BLOCK->steps.k, \ - || BLOCK->steps.u, || BLOCK->steps.v, || BLOCK->steps.w)) +#define XYZ_HAS_STEPS(B) NUM_AXIS_ANY( \ + B->steps.a, B->steps.b, B->steps.c, \ + B->steps.i, B->steps.j, B->steps.k, \ + B->steps.u, B->steps.v, B->steps.w) + +#if MIN_STEPS_PER_SEGMENT <= 1 + #define XYZ_HAS_ENOUGH_STEPS XYZ_HAS_STEPS +#else + #define XYZ_HAS_ENOUGH_STEPS(B) NUM_AXIS_ANY( \ + B->steps.a >= MIN_STEPS_PER_SEGMENT, B->steps.b >= MIN_STEPS_PER_SEGMENT, B->steps.c >= MIN_STEPS_PER_SEGMENT, \ + B->steps.i >= MIN_STEPS_PER_SEGMENT, B->steps.j >= MIN_STEPS_PER_SEGMENT, B->steps.k >= MIN_STEPS_PER_SEGMENT, \ + B->steps.u >= MIN_STEPS_PER_SEGMENT, B->steps.v >= MIN_STEPS_PER_SEGMENT, B->steps.w >= MIN_STEPS_PER_SEGMENT) +#endif extern Planner planner; diff --git a/Marlin/src/module/settings.cpp b/Marlin/src/module/settings.cpp index e48b215b77..f0ade99082 100644 --- a/Marlin/src/module/settings.cpp +++ b/Marlin/src/module/settings.cpp @@ -1876,8 +1876,13 @@ void MarlinSettings::postprocess() { TERN_(EXTENSIBLE_UI, ExtUI::onSettingsStored(success)); + // Remember the error condition so One-Click Printing can be skipped + #if ENABLED(ONE_CLICK_PRINT) && NONE(EEPROM_AUTO_INIT, EEPROM_INIT_NOW) + working_crc = uint16_t(eeprom_error); + #endif + return success; - } + } // save EEPROM_Error MarlinSettings::check_version() { if (!EEPROM_START(EEPROM_OFFSET)) return ERR_EEPROM_NOPROM; @@ -3077,8 +3082,13 @@ void MarlinSettings::postprocess() { if (!validating && TERN1(EEPROM_BOOT_SILENT, marlin.isRunning())) report(); #endif + // Remember the error condition so One-Click Printing can be skipped + #if ENABLED(ONE_CLICK_PRINT) && NONE(EEPROM_AUTO_INIT, EEPROM_INIT_NOW) + working_crc = uint16_t(eeprom_error); + #endif + return eeprom_error; - } + } // _load #ifdef ARCHIM2_SPI_FLASH_EEPROM_BACKUP_SIZE extern bool restoreEEPROM(); @@ -3146,7 +3156,7 @@ void MarlinSettings::postprocess() { #if ENABLED(AUTO_BED_LEVELING_UBL) - inline void ubl_invalid_slot(const int s) { + static void ubl_invalid_slot(const int s) { DEBUG_ECHOLN(F("?Invalid "), F("slot.\n"), s, F(" mesh slots available.")); UNUSED(s); } diff --git a/Marlin/src/module/settings.h b/Marlin/src/module/settings.h index f181e4014d..a6f3c2850f 100644 --- a/Marlin/src/module/settings.h +++ b/Marlin/src/module/settings.h @@ -67,6 +67,10 @@ class MarlinSettings { static bool load(); // Return 'true' if data was loaded ok static bool validate(); // Return 'true' if EEPROM data is ok + #if ENABLED(ONE_CLICK_PRINT) && NONE(EEPROM_AUTO_INIT, EEPROM_INIT_NOW) + static EEPROM_Error eeprom_status() { return (EEPROM_Error)working_crc; } + #endif + static EEPROM_Error check_version(); static void first_load() { @@ -100,10 +104,8 @@ class MarlinSettings { #else // !EEPROM_SETTINGS - FORCE_INLINE - static bool load() { reset(); report(); return true; } - FORCE_INLINE - static void first_load() { (void)load(); } + FORCE_INLINE static bool load() { reset(); report(); return true; } + FORCE_INLINE static void first_load() { (void)load(); } #endif // !EEPROM_SETTINGS @@ -114,8 +116,7 @@ class MarlinSettings { #if DISABLED(DISABLE_M503) static void report(const bool forReplay=false); #else - FORCE_INLINE - static void report(const bool=false) {} + FORCE_INLINE static void report(const bool=false) {} #endif private: diff --git a/Marlin/src/module/stepper.cpp b/Marlin/src/module/stepper.cpp index 2a10c83800..cfb2617024 100644 --- a/Marlin/src/module/stepper.cpp +++ b/Marlin/src/module/stepper.cpp @@ -199,8 +199,14 @@ uint32_t Stepper::acceleration_time, Stepper::deceleration_time; constexpr uint8_t Stepper::oversampling_factor; // = 0 #endif -#if ENABLED(FREEZE_FEATURE) - bool Stepper::frozen; // = false +#if ANY(SOFT_FEED_HOLD, FREEZE_FEATURE) + frozen_state_t Stepper::frozen_state; // Frozen flags +#endif +#if ENABLED(SOFT_FEED_HOLD) + uint32_t Stepper::frozen_time; // How much time has passed since frozen_state was triggered? + #if ENABLED(LASER_FEATURE) + uint8_t frozen_last_laser_power; // Saved laser power prior to halting motion + #endif #endif // Delta error variables for the Bresenham line tracer @@ -1846,7 +1852,11 @@ void Stepper::isr() { if (!current_block || step_events_completed >= step_event_count) return; // Skipping step processing causes motion to freeze - if (TERN0(FREEZE_FEATURE, frozen)) return; + #if ENABLED(SOFT_FEED_HOLD) + if (frozen_state.triggered && frozen_state.solid) return; + #elif ENABLED(FREEZE_FEATURE) + if (frozen_state.state == 0) return; + #endif // Count of pending loops and events for this iteration const uint32_t pending_events = step_event_count - step_events_completed; @@ -2418,6 +2428,10 @@ void Stepper::isr() { // If no queued movements, just wait 1ms for the next block hal_timer_t interval = (STEPPER_TIMER_RATE) / 1000UL; + // Frozen solid?? Exit and do not fetch blocks. + if (TERN0(SOFT_FEED_HOLD, frozen_state.triggered && frozen_state.solid)) + return interval; + // If there is a current block if (current_block) { // If current block is finished, reset pointer and finalize state @@ -2460,11 +2474,16 @@ void Stepper::isr() { // acc_step_rate is in steps/second + // Modify acc_step_rate if the machine is freezing + TERN_(SOFT_FEED_HOLD, check_frozen_time(acc_step_rate)); + // step_rate to timer interval and steps per stepper isr interval = calc_multistep_timer_interval(acc_step_rate << oversampling_factor); acceleration_time += interval; deceleration_time = 0; // Reset since we're doing acceleration first. + TERN_(SOFT_FEED_HOLD, check_frozen_state(FREEZE_ACCELERATION, interval)); + // Apply Nonlinear Extrusion, if enabled calc_nonlinear_e(acc_step_rate << oversampling_factor); @@ -2526,10 +2545,14 @@ void Stepper::isr() { #endif + TERN_(SOFT_FEED_HOLD, check_frozen_time(step_rate)); + // step_rate to timer interval and steps per stepper isr interval = calc_multistep_timer_interval(step_rate << oversampling_factor); deceleration_time += interval; + TERN_(SOFT_FEED_HOLD, check_frozen_state(FREEZE_DECELERATION, interval)); + // Apply Nonlinear Extrusion, if enabled calc_nonlinear_e(step_rate << oversampling_factor); @@ -2576,21 +2599,25 @@ void Stepper::isr() { else { // Must be in cruise phase otherwise // Calculate the ticks_nominal for this nominal speed, if not done yet - if (ticks_nominal == 0) { + if (ticks_nominal == 0 || TERN0(SOFT_FEED_HOLD, frozen_time)) { + uint32_t step_rate = current_block->nominal_rate; + + TERN_(SOFT_FEED_HOLD, check_frozen_time(step_rate)); + // step_rate to timer interval and loops for the nominal speed - ticks_nominal = calc_multistep_timer_interval(current_block->nominal_rate << oversampling_factor); + ticks_nominal = calc_multistep_timer_interval(step_rate << oversampling_factor); deceleration_time = ticks_nominal / 2; // Prepare for deceleration - IF_DISABLED(S_CURVE_ACCELERATION, acc_step_rate = current_block->nominal_rate); + IF_DISABLED(S_CURVE_ACCELERATION, acc_step_rate = step_rate); TERN_(SMOOTH_LIN_ADVANCE, curr_step_rate = current_block->nominal_rate); // Apply Nonlinear Extrusion, if enabled - calc_nonlinear_e(current_block->nominal_rate << oversampling_factor); + calc_nonlinear_e(step_rate << oversampling_factor); #if HAS_ROUGH_LIN_ADVANCE if (la_active) - la_interval = calc_timer_interval(current_block->nominal_rate >> current_block->la_scaling); + la_interval = calc_timer_interval(step_rate >> current_block->la_scaling); #endif // Adjust Laser Power - Cruise @@ -2610,6 +2637,8 @@ void Stepper::isr() { // The timer interval is just the nominal value for the nominal speed interval = ticks_nominal; + + TERN_(SOFT_FEED_HOLD, check_frozen_state(FREEZE_CRUISE, interval)); } } @@ -2631,9 +2660,12 @@ void Stepper::isr() { #endif } else { // !current_block + TERN_(SOFT_FEED_HOLD, check_frozen_state(FREEZE_STATIONARY, interval)); + #if ENABLED(LASER_FEATURE) + // If no movement in dynamic mode turn Laser off if (cutter.cutter_mode == CUTTER_MODE_DYNAMIC) - cutter.apply_power(0); // No movement in dynamic mode so turn Laser off + cutter.apply_power(0); #endif } @@ -2905,7 +2937,7 @@ void Stepper::isr() { ne.edividend = advance_dividend.e; const float scale = (float(ne.edividend) / advance_divisor) * planner.mm_per_step[E_AXIS_N(current_block->extruder)]; ne.scale_q24 = _BV32(24) * scale; - if (ne.settings.enabled && current_block->direction_bits.e && ANY_AXIS_MOVES(current_block)) { + if (ne.settings.enabled && current_block->direction_bits.e && XYZ_HAS_STEPS(current_block)) { ne.q24.A = _BV32(24) * ne.settings.coeff.A; ne.q24.B = _BV32(24) * ne.settings.coeff.B; ne.q24.C = _BV32(24) * ne.settings.coeff.C; @@ -2916,13 +2948,22 @@ void Stepper::isr() { } #endif + uint32_t initial_rate = current_block->initial_rate; + + #if ENABLED(SOFT_FEED_HOLD) + if (frozen_time) check_frozen_time(initial_rate); + #endif + // Calculate the initial timer interval - interval = calc_multistep_timer_interval(current_block->initial_rate << oversampling_factor); + interval = calc_multistep_timer_interval(initial_rate << oversampling_factor); + + TERN_(SOFT_FEED_HOLD, check_frozen_state(FREEZE_ACCELERATION, interval)); + // Initialize ac/deceleration time as if half the time passed. acceleration_time = deceleration_time = interval / 2; // Apply Nonlinear Extrusion, if enabled - calc_nonlinear_e(current_block->initial_rate << oversampling_factor); + calc_nonlinear_e(initial_rate << oversampling_factor); #if ENABLED(LIN_ADVANCE) #if ENABLED(SMOOTH_LIN_ADVANCE) @@ -2930,7 +2971,7 @@ void Stepper::isr() { #else if (la_active) { const uint32_t la_step_rate = la_advance_steps < current_block->max_adv_steps ? current_block->la_advance_rate : 0; - la_interval = calc_timer_interval((current_block->initial_rate + la_step_rate) >> current_block->la_scaling); + la_interval = calc_timer_interval((initial_rate + la_step_rate) >> current_block->la_scaling); } #endif #endif @@ -2959,7 +3000,7 @@ void Stepper::isr() { const bool forward_e = step_rate > 0; #if ENABLED(NONLINEAR_EXTRUSION) - if (ne.settings.enabled && forward_e && ANY_AXIS_MOVES(current_block)) { + if (ne.settings.enabled && forward_e && XYZ_HAS_STEPS(current_block)) { // Maximum polynomial value is just above 1, like 1.05..1.2, less than 2 anyway, so we can use 30 bits for fractional part int32_t vd_q30 = ne.q30.A * sq(step_rate) + ne.q30.B * step_rate; NOLESS(vd_q30, 0); @@ -3376,6 +3417,10 @@ void Stepper::init() { #endif // HAS_ZV_SHAPING +/** + * Position + */ + /** * Set the stepper positions directly in steps * @@ -3502,20 +3547,11 @@ void Stepper::set_axis_position(const AxisEnum a, const int32_t &v) { AVR_ATOMIC_SECTION_END(); } -#endif // HAS_EXTRUDERS +#endif -#if ENABLED(FT_MOTION) - - void Stepper::ftMotion_syncPosition() { - planner.synchronize(); - - // Update stepper positions from the planner - AVR_ATOMIC_SECTION_START(); - count_position = planner.position; - AVR_ATOMIC_SECTION_END(); - } - -#endif // FT_MOTION +/** + * Endstops + */ /** * Record stepper positions and discard the rest of the current block @@ -3561,6 +3597,10 @@ int32_t Stepper::triggered_position(const AxisEnum axis) { return v; } +/** + * Reporting + */ + #if ANY(CORE_IS_XY, CORE_IS_XZ, MARKFORGED_XY, MARKFORGED_YX, IS_SCARA, DELTA) #define SAYS_A 1 #endif @@ -3592,6 +3632,15 @@ void Stepper::report_positions() { #if ENABLED(FT_MOTION) + void Stepper::ftMotion_syncPosition() { + planner.synchronize(); + + // Update stepper positions from the planner + AVR_ATOMIC_SECTION_START(); + count_position = planner.position; + AVR_ATOMIC_SECTION_END(); + } + /** * Run stepping for FT Motion from the Stepper ISR at regular short intervals. * @@ -3668,11 +3717,11 @@ void Stepper::report_positions() { #endif // Only wait for axes without edge stepping - const bool any_wait = false LOGICAL_AXIS_GANG( - || (!e_axis_has_dedge && step_bits.E), - || (!AXIS_HAS_DEDGE(X) && step_bits.X), || (!AXIS_HAS_DEDGE(Y) && step_bits.Y), || (!AXIS_HAS_DEDGE(Z) && step_bits.Z), - || (!AXIS_HAS_DEDGE(I) && step_bits.I), || (!AXIS_HAS_DEDGE(J) && step_bits.J), || (!AXIS_HAS_DEDGE(K) && step_bits.K), - || (!AXIS_HAS_DEDGE(U) && step_bits.U), || (!AXIS_HAS_DEDGE(V) && step_bits.V), || (!AXIS_HAS_DEDGE(W) && step_bits.W) + const bool any_wait = LOGICAL_AXIS_ANY( + !e_axis_has_dedge && step_bits.E, + !AXIS_HAS_DEDGE(X) && step_bits.X, !AXIS_HAS_DEDGE(Y) && step_bits.Y, !AXIS_HAS_DEDGE(Z) && step_bits.Z, + !AXIS_HAS_DEDGE(I) && step_bits.I, !AXIS_HAS_DEDGE(J) && step_bits.J, !AXIS_HAS_DEDGE(K) && step_bits.K, + !AXIS_HAS_DEDGE(U) && step_bits.U, !AXIS_HAS_DEDGE(V) && step_bits.V, !AXIS_HAS_DEDGE(W) && step_bits.W ); // Allow pulses to be registered by stepper drivers @@ -3686,6 +3735,10 @@ void Stepper::report_positions() { #endif // FT_MOTION +/** + * Babystepping + */ + #if ENABLED(BABYSTEPPING) #define _ENABLE_AXIS(A) enable_axis(_AXIS(A)) @@ -3864,3 +3917,105 @@ void Stepper::report_positions() { } #endif // BABYSTEPPING + +#if ENABLED(SOFT_FEED_HOLD) + + void Stepper::set_frozen_solid(const bool state) { + if (state == frozen_state.solid) return; + + frozen_state.solid = true; + + #if ENABLED(LASER_FEATURE) + if (state) { + frozen_last_laser_power = cutter.last_power_applied; + cutter.apply_power(0); // No movement in dynamic mode so turn Laser off + } + else + cutter.apply_power(frozen_last_laser_power); // Restore frozen laser power + #endif + + #if ENABLED(REALTIME_REPORTING_COMMANDS) + set_and_report_grblstate(state ? M_HOLD : M_RUNNING); + #endif + } + + void Stepper::check_frozen_time(uint32_t &step_rate) { + // If frozen_time is 0 there is no need to modify the current step_rate + if (!frozen_time) return; + + #if ENABLED(S_CURVE_ACCELERATION) + // If the machine is configured to use S_CURVE_ACCELERATION standard ramp acceleration + // rate will not have been calculated at this point + if (!current_block->acceleration_rate) + current_block->acceleration_rate = uint32_t(current_block->acceleration_steps_per_s2 * (float(1UL << 24) / (STEPPER_TIMER_RATE))); + #endif + + const uint32_t freeze_rate = STEP_MULTIPLY(frozen_time, current_block->acceleration_rate); + const uint32_t min_step_rate = current_block->steps_per_mm * (FREEZE_JERK); + + if (step_rate > freeze_rate) + step_rate -= freeze_rate; + else + step_rate = 0; + + if (step_rate <= min_step_rate) { + set_frozen_solid(true); + step_rate = min_step_rate; + } + } + + void Stepper::check_frozen_state(const FreezePhase phase, const uint32_t interval) { + switch (phase) { + case FREEZE_STATIONARY: + // If triggered while stationary immediately set solid flag + if (frozen_state.triggered) { + frozen_time = 0; + set_frozen_solid(true); + } + else + set_frozen_solid(false); + break; + + case FREEZE_ACCELERATION: + // If frozen state is activated during the acceleration phase of a block we need to double our decceleration efforts + if (frozen_state.triggered) { + if (!frozen_state.solid) frozen_time += interval * 2; + } + else + set_frozen_solid(false); + break; + + case FREEZE_DECELERATION: + // If frozen state is deactivated during the deceleration phase we need to double our acceleration efforts + if (!frozen_state.triggered) { + if (frozen_time) { + if (frozen_time > interval * 2) + frozen_time -= interval * 2; + else + frozen_time = 0; + } + set_frozen_solid(false); + } + break; + + case FREEZE_CRUISE: + // During cruise stage acceleration/deceleration take place at regular rate + if (frozen_state.triggered) { + if (!frozen_state.solid) frozen_time += interval; + } + else { + if (frozen_time) { + if (frozen_time > interval) + frozen_time -= interval; + else { + frozen_time = 0; + ticks_nominal = 0; // Reset ticks_nominal to allow for recalculation of interval at nominal_rate + } + } + set_frozen_solid(false); + } + break; + } + } + +#endif // SOFT_FEED_HOLD diff --git a/Marlin/src/module/stepper.h b/Marlin/src/module/stepper.h index 6e6761f842..ec567245f0 100644 --- a/Marlin/src/module/stepper.h +++ b/Marlin/src/module/stepper.h @@ -318,6 +318,26 @@ constexpr ena_mask_t enable_overlap[] = { #endif // NONLINEAR_EXTRUSION +#if ANY(FREEZE_FEATURE, SOFT_FEED_HOLD) + + typedef union { + uint8_t state; + struct { bool triggered:1, solid:1; }; + } frozen_state_t; + + enum FrozenState { FROZEN_TRIGGERED, FROZEN_SOLID }; + + #if ENABLED(SOFT_FEED_HOLD) + enum FreezePhase : uint8_t { + FREEZE_STATIONARY, + FREEZE_ACCELERATION, + FREEZE_DECELERATION, + FREEZE_CRUISE + }; + #endif + +#endif + // // Stepper class definition // @@ -367,8 +387,12 @@ class Stepper { static constexpr uint8_t last_moved_extruder = 0; #endif - #if ENABLED(FREEZE_FEATURE) - static bool frozen; // Set this flag to instantly freeze motion + #if ANY(FREEZE_FEATURE, SOFT_FEED_HOLD) + static frozen_state_t frozen_state; // Frozen flags + static void set_frozen_triggered(const bool state) { frozen_state.triggered = state; } + #if ENABLED(SOFT_FEED_HOLD) + static bool is_frozen_triggered() { return frozen_state.triggered; } + #endif #endif #if ENABLED(NONLINEAR_EXTRUSION) @@ -800,6 +824,15 @@ class Stepper { static void ftMotion_stepper(); #endif + #if ENABLED(SOFT_FEED_HOLD) + static uint32_t frozen_time; // How much time passed since frozen_state was triggered? + #if ENABLED(LASER_FEATURE) + static uint8_t frozen_last_laser_power; // Saved laser power prior to halting motion + #endif + static void check_frozen_state(const FreezePhase type, const uint32_t interval); + static void check_frozen_time(uint32_t &step_rate); + static void set_frozen_solid(const bool state); + #endif }; extern Stepper stepper; diff --git a/Marlin/src/pins/pins.h b/Marlin/src/pins/pins.h index a89f1e1d52..4672c92e01 100644 --- a/Marlin/src/pins/pins.h +++ b/Marlin/src/pins/pins.h @@ -555,7 +555,7 @@ #elif MB(STM32F103RE) #include "stm32f1/pins_STM32F1R.h" // STM32F1 env:STM32F103RE env:STM32F103RE_maple #elif MB(MALYAN_M200) - #include "stm32f1/pins_MALYAN_M200.h" // STM32F1 env:STM32F103CB_malyan env:STM32F103CB_malyan_maple + #include "stm32f1/pins_MALYAN_M200.h" // STM32F1 env:STM32F103CB_malyan #elif MB(STM3R_MINI) #include "stm32f1/pins_STM3R_MINI.h" // STM32F1 env:STM32F103VE env:STM32F103RE_maple #elif MB(GTM32_PRO_VB) @@ -686,6 +686,8 @@ #include "gd32f1/pins_VOXELAB_AQUILA.h" // GD32F1, N32G4, STM32F1 env:GD32F103RC_voxelab_maple env:N32G455RE_voxelab_maple env:STM32F103RE_creality_maple env:STM32F103RE_creality #elif MB(SPRINGER_CONTROLLER) #include "stm32f1/pins_ORCA_3D_SPRINGER.h" // STM32F1 env:STM32F103VC_orca3d +#elif MB(ATOMSTACK_FB5_V2) + #include "stm32f1/pins_ATOMSTACK_FB5_V2.h" // STM32F1 env:STM32F103RC_atomstack // // ARM Cortex-M4F diff --git a/Marlin/src/pins/stm32f1/pins_ATOMSTACK_FB5_V2.h b/Marlin/src/pins/stm32f1/pins_ATOMSTACK_FB5_V2.h new file mode 100644 index 0000000000..220fa116e9 --- /dev/null +++ b/Marlin/src/pins/stm32f1/pins_ATOMSTACK_FB5_V2.h @@ -0,0 +1,198 @@ +/** + * Marlin 3D Printer Firmware + * Copyright (c) 2026 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 + +/** + * AtomStack FB5 V2.0 (STM32F103RCT6) common board pin assignments + */ + +#include "env_validate.h" + +#ifndef BOARD_INFO_NAME + #define BOARD_INFO_NAME "AtomStack FB5 V2.0" +#endif +#ifndef DEFAULT_MACHINE_NAME + #define DEFAULT_MACHINE_NAME "ATOMSTACK Cambrian" +#endif + +// +// EEPROM +// +#if ANY(NO_EEPROM_SELECTED, FLASH_EEPROM_EMULATION) + #define FLASH_EEPROM_EMULATION + #define EEPROM_PAGE_SIZE (0x800U) // 2K + #define EEPROM_START_ADDRESS (0x8000000UL + (STM32_FLASH_SIZE) * 1024UL - (EEPROM_PAGE_SIZE) * 2UL) + #define MARLIN_EEPROM_SIZE EEPROM_PAGE_SIZE // 2K +#endif + +// +// Servos +// +#define SERVO0_PIN PA3 + +// +// Limit Switches +// +#define X_STOP_PIN PA4 +#define Y_STOP_PIN PA5 +#define Z_STOP_PIN PC6 + +// +// Z Probe +// +#ifndef Z_MIN_PROBE_PIN + #define Z_MIN_PROBE_PIN PB1 +#endif + +// +// Probe enable +// +#if ENABLED(PROBE_ENABLE_DISABLE) && !defined(PROBE_ENABLE_PIN) + #define PROBE_ENABLE_PIN SERVO0_PIN +#endif + +// +// Steppers +// +#define X_STEP_PIN PC0 +#define X_DIR_PIN PB2 +#define X_ENABLE_PIN PC13 + +#define Y_STEP_PIN PC2 +#define Y_DIR_PIN PB9 +#define Y_ENABLE_PIN PB12 + +#ifndef Z_STEP_PIN + #define Z_STEP_PIN PB7 +#endif +#ifndef Z_DIR_PIN + #define Z_DIR_PIN PB6 +#endif +#define Z_ENABLE_PIN PB8 + +#define E0_STEP_PIN PB4 +#define E0_DIR_PIN PB3 +#define E0_ENABLE_PIN PB5 + +#if HAS_TMC_UART + /** + * TMC2208/TMC2209 stepper drivers + * + * Hardware serial communication ports. + * If undefined software serial is used according to the pins below + */ + //#define X_HARDWARE_SERIAL MSerial1 + //#define Y_HARDWARE_SERIAL MSerial1 + //#define Z_HARDWARE_SERIAL MSerial1 + //#define E0_HARDWARE_SERIAL MSerial1 + + #define X_SERIAL_TX_PIN PC7 + #define Y_SERIAL_TX_PIN PD2 + #define Z_SERIAL_TX_PIN PC12 + #define E0_SERIAL_TX_PIN PC11 + + // Reduce baud rate to improve software serial reliability + #ifndef TMC_BAUD_RATE + #define TMC_BAUD_RATE 19200 + #endif + +#endif // HAS_TMC_UART + +// +// Heaters / Fans +// +#define HEATER_0_PIN PC9 +#define HEATER_BED_PIN PC8 + +#define FAN0_PIN PA8 + +// +// Temperature Sensors +// +#define TEMP_0_PIN PA0 // TH1 +#define TEMP_BED_PIN PA1 // TB + +// +// Filament Runout Sensor +// +//#define FIL_RUNOUT_PIN PB10 // MT_DET (Mechanical Limit Detector) +#define FIL_RUNOUT_PIN PC15 // E0-STOP + +// +// Power-loss Detection +// +#ifndef POWER_LOSS_PIN + //#define POWER_LOSS_PIN PC12 // Power Loss Detection: PWR-DET +#endif + +// +// USB connect control +// +#ifndef USB_CONNECT_PIN + #define USB_CONNECT_PIN PB11 + #define USB_CONNECT_INVERTING false +#endif + +/** + * AtomStack FB5 V2.0 + * ------ + * 5V | 1 2 | 5V + * GND | 3 4 | GND + * NC | 5 6 | PA9 (TX1) + * NC | 7 8 | PA10 (RX1) + * ------ + * AUX1 + */ + +/** + * DWG80480C043_02WTCZ12 4.3 Inch Smart LCD [800x480] pinout + * --- + * 5V | 1 | + * NC | 2 | + * (TX1) PA9 | 3 | + * (RX1)PA10 | 4 | + * NC | 5 | + * GND | 6 | + * --- + * DWIN (plug) + */ + +// LED driving pin +#ifndef BOARD_NEOPIXEL_PIN + #define BOARD_NEOPIXEL_PIN PA2 +#endif + +// +// SD Card +// +#define SDCARD_CONNECTION ONBOARD +#define ONBOARD_SPI_DEVICE 2 // Maple +#define ONBOARD_SD_CS_PIN SD_SS_PIN +#define SD_DETECT_PIN PC10 +#define NO_SD_HOST_DRIVE + +// TODO: This is the only way to set SPI for SD on STM32 (for now) +#define ENABLE_SPI2 +#define SD_SCK_PIN PB13 +#define SD_MISO_PIN PB14 +#define SD_MOSI_PIN PB15 +#define SD_SS_PIN PA15 diff --git a/Marlin/src/pins/stm32f1/pins_CREALITY_V425.h b/Marlin/src/pins/stm32f1/pins_CREALITY_V425.h index a225fe11be..42875713f1 100644 --- a/Marlin/src/pins/stm32f1/pins_CREALITY_V425.h +++ b/Marlin/src/pins/stm32f1/pins_CREALITY_V425.h @@ -68,6 +68,13 @@ // #define HEATER_0_PIN PA0 // HEATER1 #define HEATER_BED_PIN PA1 // HOT BED -#define FAN0_PIN PA2 // FAN +#define FAN0_PIN PA2 // FAN0 +#define FAN1_PIN PC1 // FAN1 +#define FAN2_PIN PC0 // FAN2 + +// +// Misc. Functions +// +#define LED_PIN PC14 #include "pins_CREALITY_V4.h" diff --git a/Marlin/src/sd/cardreader.cpp b/Marlin/src/sd/cardreader.cpp index b6a0c73c09..426437d9d1 100644 --- a/Marlin/src/sd/cardreader.cpp +++ b/Marlin/src/sd/cardreader.cpp @@ -95,13 +95,13 @@ int16_t CardReader::nrItems = -1; #if ENABLED(SDCARD_SORT_ALPHA) - int16_t CardReader::sort_count; #if ENABLED(SDSORT_GCODE) SortFlag CardReader::sort_alpha; int8_t CardReader::sort_folders; //bool CardReader::sort_reverse; #endif + int16_t CardReader::sort_count; uint8_t *CardReader::sort_order; #if ENABLED(SDSORT_USES_RAM) @@ -159,13 +159,15 @@ CardReader::CardReader() { static uint8_t sort_order_static[SDSORT_LIMIT]; sort_order = sort_order_static; #endif - #if ENABLED(SDSORT_CACHE_NAMES) && DISABLED(SDSORT_DYNAMIC_RAM) - static char sortshort_static[SDSORT_LIMIT][FILENAME_LENGTH]; - sortshort = sortshort_static; - #endif - #if ENABLED(SDSORT_CACHE_NAMES) && !ALL(SDSORT_DYNAMIC_RAM, SDSORT_USES_STACK) - static char sortnames_static[SDSORT_LIMIT][SORTED_LONGNAME_STORAGE]; - sortnames = sortnames_static; + #if ENABLED(SDSORT_CACHE_NAMES) + #if DISABLED(SDSORT_DYNAMIC_RAM) + static char sortshort_static[SDSORT_LIMIT][FILENAME_LENGTH]; + sortshort = sortshort_static; + #endif + #if !ALL(SDSORT_DYNAMIC_RAM, SDSORT_USES_STACK) + static char sortnames_static[SDSORT_LIMIT][SORTED_LONGNAME_STORAGE]; + sortnames = sortnames_static; + #endif #endif sort_count = 0; @@ -1030,11 +1032,16 @@ void CardReader::write_command(char * const buf) { * Select the newest file and ask the user if they want to print it. */ bool CardReader::one_click_check() { + // Don't proceed if an EEPROM error needs a response + #if ENABLED(EEPROM_SETTINGS) && NONE(EEPROM_AUTO_INIT, EEPROM_INIT_NOW) + if (settings.eeprom_status() != ERR_EEPROM_NOERR) return false; + #endif + const bool found = selectNewestFile(); // Changes the current workDir if found if (found) { //SERIAL_ECHO_MSG(" OCP File: ", longest_filename(), "\n"); //ui.init(); - one_click_print(); // Restores workkDir to root (eventually) + one_click_print(); // Restores workDir to root (eventually) } return found; } @@ -1339,7 +1346,7 @@ void CardReader::cdroot() { #define SET_SORTSHORT(I) NOOP #endif #endif - #endif + #endif // SDSORT_USES_RAM /** * Read all the files and produce a sort key @@ -1595,7 +1602,7 @@ void CardReader::cdroot() { } else { sort_order[0] = uint8_t(0); - #if ALL(SDSORT_USES_RAM, SDSORT_CACHE_NAMES) + #if ENABLED(SDSORT_CACHE_NAMES) #if ENABLED(SDSORT_DYNAMIC_RAM) sortnames = new char[1][SORTED_LONGNAME_STORAGE]; sortshort = new char[1][SORTED_SHORTNAME_STORAGE]; diff --git a/Marlin/src/sd/cardreader.h b/Marlin/src/sd/cardreader.h index 5956ffd091..fd514a5340 100644 --- a/Marlin/src/sd/cardreader.h +++ b/Marlin/src/sd/cardreader.h @@ -353,17 +353,17 @@ private: // Alphabetical file and folder sorting // #if ENABLED(SDCARD_SORT_ALPHA) - static int16_t sort_count; // Count of sorted items in the current directory + #if ENABLED(SDSORT_GCODE) static SortFlag sort_alpha; // Sorting: REV, OFF, FWD static int8_t sort_folders; // Folder sorting before/none/after //static bool sort_reverse; // Flag to enable / disable reverse sorting #endif - // Pointer to the static or dynamic sort index - static uint8_t *sort_order; + static int16_t sort_count; // Count of sorted items in the current directory + static uint8_t *sort_order; // Pointer to the static or dynamic sort index - #if ALL(SDSORT_USES_RAM, SDSORT_CACHE_NAMES) && DISABLED(SDSORT_DYNAMIC_RAM) + #if ENABLED(SDSORT_CACHE_NAMES) && DISABLED(SDSORT_DYNAMIC_RAM) #define SORTED_LONGNAME_MAXLEN (SDSORT_CACHE_VFATS) * (FILENAME_LENGTH) #define SORTED_LONGNAME_STORAGE (SORTED_LONGNAME_MAXLEN + 1) #else diff --git a/README.md b/README.md index d68fd0297e..93e16d33f0 100644 --- a/README.md +++ b/README.md @@ -110,49 +110,59 @@ Did you know that Marlin includes a Simulator that can run on Windows, macOS, an ### Supported Platforms -| Platform | MCU | Example Boards | -| ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ------------------------------- | ---------------------------------------------------------- | -| [Arduino AVR](//www.arduino.cc/) | ATmega | RAMPS, Melzi, RAMBo | -| [Teensy++ 2.0](//www.microchip.com/en-us/product/AT90USB1286) | AT90USB1286 | Printrboard | -| [Arduino Due](//www.arduino.cc/en/Guide/ArduinoDue) | SAM3X8E | RAMPS-FD, RADDS, RAMPS4DUE | -| [ESP32](//github.com/espressif/arduino-esp32) | ESP32 | FYSETC E4, E4d@BOX, MRR | -| [GD32](//www.gigadevice.com/) | GD32 ARM Cortex-M4 | Creality MFL GD32 V4.2.2 | -| [HC32](//www.huazhoucn.com/) | HC32 | Ender-2 Pro, Voxelab Aquila | -| [LPC1768](//www.nxp.com/products/processors-and-microcontrollers/arm-microcontrollers/general-purpose-mcus/lpc1700-cortex-m3/512-kb-flash-64-kb-sram-ethernet-usb-lqfp100-package:LPC1768FBD100) | ARM® Cortex-M3 | MKS SBASE, Re-ARM, Selena Compact | -| [LPC1769](//www.nxp.com/products/processors-and-microcontrollers/arm-microcontrollers/general-purpose-mcus/lpc1700-cortex-m3/512-kb-flash-64-kb-sram-ethernet-usb-lqfp100-package:LPC1769FBD100) | ARM® Cortex-M3 | Smoothieboard, Azteeg X5 mini, TH3D EZBoard | -| [Pico RP2040](//www.raspberrypi.com/documentation/microcontrollers/pico-series.html) | Dual Cortex M0+ | BigTreeTech SKR Pico | -| [STM32F103](//www.st.com/en/microcontrollers-microprocessors/stm32f103.html) | ARM® Cortex-M3 | Malyan M200, GTM32 Pro, MKS Robin, BTT SKR Mini | -| [STM32F401](//www.st.com/en/microcontrollers-microprocessors/stm32f401.html) | ARM® Cortex-M4 | ARMED, Rumba32, SKR Pro, Lerdge, FYSETC S6, Artillery Ruby | -| [STM32F7x6](//www.st.com/en/microcontrollers-microprocessors/stm32f7x6.html) | ARM® Cortex-M7 | The Borg, RemRam V1 | -| [STM32G0B1RET6](//www.st.com/en/microcontrollers-microprocessors/stm32g0x1.html) | ARM® Cortex-M0+ | BigTreeTech SKR mini E3 V3.0 | -| [STM32H743xIT6](//www.st.com/en/microcontrollers-microprocessors/stm32h743-753.html) | ARM® Cortex-M7 | BigTreeTech SKR V3.0, SKR EZ V3.0, SKR SE BX V2.0/V3.0 | -| [SAMD21P20A](//www.adafruit.com/product/4064) | ARM® Cortex-M0+ | Adafruit Grand Central M4 | -| [SAMD51P20A](//www.adafruit.com/product/4064) | ARM® Cortex-M4 | Adafruit Grand Central M4 | -| [Teensy 3.2/3.1](//www.pjrc.com/teensy/teensy31.html) | MK20DX256VLH7 ARM® Cortex-M4 | -| [Teensy 3.5](//www.pjrc.com/store/teensy35.html) | MK64FX512-VMD12 ARM® Cortex-M4 | -| [Teensy 3.6](//www.pjrc.com/store/teensy36.html) | MK66FX1MB-VMD18 ARM® Cortex-M4 | -| [Teensy 4.0](//www.pjrc.com/store/teensy40.html) | MIMXRT1062-DVL6B ARM® Cortex-M7 | -| [Teensy 4.1](//www.pjrc.com/store/teensy41.html) | MIMXRT1062-DVJ6B ARM® Cortex-M7 | -| Linux Native | x86 / ARM / RISC-V | Raspberry Pi GPIO | -| Simulator | Windows, macOS, Linux | Desktop OS | -| [All supported boards](//marlinfw.org/docs/hardware/boards.html#boards-list) | All platforms | All boards | +| Platform | MCU | Example Boards | +| --- | --- | --- | +| [Arduino AVR](//www.arduino.cc/) | ATmega | RAMPS, Melzi, RAMBo | +| [Teensy++ 2.0](//www.microchip.com/en-us/product/AT90USB1286) | AT90USB1286 | Printrboard | +| [Arduino Due](//www.arduino.cc/en/Guide/ArduinoDue) | SAM3X8E | RAMPS-FD, RADDS, RAMPS4DUE | +| [ESP32](//github.com/espressif/arduino-esp32) | ESP32 | FYSETC E4, E4d@BOX, MRR | +| [GD32](//www.gigadevice.com/) | GD32 ARM Cortex-M4 | Creality MFL GD32 V4.2.2 | +| [HC32](//www.huazhoucn.com/) | HC32 | Ender-2 Pro, Voxelab Aquila | +| [LPC1768](//www.nxp.com/products/processors-and-microcontrollers/arm-microcontrollers/general-purpose-mcus/lpc1700-cortex-m3/512-kb-flash-64-kb-sram-ethernet-usb-lqfp100-package:LPC1768FBD100) | ARM® Cortex-M3 | MKS SBASE, Re-ARM, Selena Compact | +| [LPC1769](//www.nxp.com/products/processors-and-microcontrollers/arm-microcontrollers/general-purpose-mcus/lpc1700-cortex-m3/512-kb-flash-64-kb-sram-ethernet-usb-lqfp100-package:LPC1769FBD100) | ARM® Cortex-M3 | Smoothieboard, Azteeg X5 mini, TH3D EZBoard | +| [Pico RP2040](//www.raspberrypi.com/documentation/microcontrollers/pico-series.html) | Dual Cortex M0+ | BigTreeTech SKR Pico | +| [STM32F103](//www.st.com/en/microcontrollers-microprocessors/stm32f103.html) | ARM® Cortex-M3 | Malyan M200, GTM32 Pro, MKS Robin, BTT SKR Mini | +| [STM32F401](//www.st.com/en/microcontrollers-microprocessors/stm32f401.html) | ARM® Cortex-M4 | ARMED, Rumba32, SKR Pro, Lerdge, FYSETC S6, Artillery Ruby | +| [STM32F7x6](//www.st.com/en/microcontrollers-microprocessors/stm32f7x6.html) | ARM® Cortex-M7 | The Borg, RemRam V1 | +| [STM32G0B1RET6](//www.st.com/en/microcontrollers-microprocessors/stm32g0x1.html) | ARM® Cortex-M0+ | BigTreeTech SKR mini E3 V3.0 | +| [STM32H743xIT6](//www.st.com/en/microcontrollers-microprocessors/stm32h743-753.html) | ARM® Cortex-M7 | BigTreeTech SKR V3.0, SKR EZ V3.0, SKR SE BX V2.0/V3.0 | +| [SAMD21P20A](//www.adafruit.com/product/4064) | ARM® Cortex-M0+ | Adafruit Grand Central M4 | +| [SAMD51P20A](//www.adafruit.com/product/4064) | ARM® Cortex-M4 | Adafruit Grand Central M4 | +| [Teensy 3.2/3.1](//www.pjrc.com/teensy/teensy31.html) | MK20DX256VLH7 ARM® Cortex-M4 | +| [Teensy 3.5](//www.pjrc.com/store/teensy35.html) | MK64FX512-VMD12 ARM® Cortex-M4 | +| [Teensy 3.6](//www.pjrc.com/store/teensy36.html) | MK66FX1MB-VMD18 ARM® Cortex-M4 | +| [Teensy 4.0](//www.pjrc.com/store/teensy40.html) | MIMXRT1062-DVL6B ARM® Cortex-M7 | +| [Teensy 4.1](//www.pjrc.com/store/teensy41.html) | MIMXRT1062-DVJ6B ARM® Cortex-M7 | +| Linux Native | x86 / ARM / RISC-V | Raspberry Pi GPIO | +| Simulator | Windows, macOS, Linux | Desktop OS | +| [All supported boards](//marlinfw.org/docs/hardware/boards.html#boards-list) | All platforms | All boards | -## Marlin Support +## Marlin Discord + +The [Marlin Firmware Discord](//discord.gg/marlin-firmware-461605380783472640) is a great place to discuss issues with Marlin users and developers, get interactive help with troubleshooting, and build on your best ideas to improve to Marlin in tandem with the most active members of the development team. + +

+ + + +

+ +## Other Marlin Support The Issue Queue is reserved for Bug Reports and Feature Requests. Please use the following resources for help with configuration and troubleshooting: - [Marlin Documentation](//marlinfw.org) - Official Marlin documentation -- [Marlin Discord](//discord.com/servers/marlin-firmware-461605380783472640) - Discuss issues with Marlin users and developers -- Facebook Group ["Marlin Firmware"](//www.facebook.com/groups/1049718498464482/) -- RepRap.org [Marlin Forum](//forums.reprap.org/list.php?415) -- Facebook Group ["Marlin Firmware for 3D Printers"](//www.facebook.com/groups/3Dtechtalk/) -- [Marlin Configuration](//www.youtube.com/results?search_query=marlin+configuration) on YouTube +- ["Marlin Firmware"](//www.facebook.com/groups/1049718498464482/) Facebook Group +- [Marlin Forum](//forums.reprap.org/list.php?415) at RepRap.org +- ["Marlin Firmware for 3D Printers"](//www.facebook.com/groups/3Dtechtalk/) Facebook Group +- [Marlin Configuration](//www.youtube.com/results?search_query=marlin+configuration) playlist on YouTube ## Contributing Patches -You can contribute patches by submitting a Pull Request to the ([bugfix-2.1.x](//github.com/MarlinFirmware/Marlin/tree/bugfix-2.1.x)) branch. +Contribute your patches to Marlin by submitting a Pull Request to the ([bugfix-2.1.x](//github.com/MarlinFirmware/Marlin/tree/bugfix-2.1.x)) branch. -- We use branches named with a "bugfix" or "dev" prefix to fix bugs and integrate new features. +- We use the `bugfix-2.1.x` branch to fix bugs and integrate new features into the latest firmware. Use with caution! +- We maintain `lts-x.x.x` branches, mainly for vendors, so that older versions of Marlin can be patched as-needed to stay functional and fix bugs. - Follow the [Coding Standards](//marlinfw.org/docs/development/coding_standards.html) to gain points with the maintainers. - Please submit Feature Requests and Bug Reports to the [Issue Queue](//github.com/MarlinFirmware/Marlin/issues/new/choose). See above for user support. - Whenever you add new features, be sure to add one or more build tests to `buildroot/tests`. Any tests added to a PR will be run within that PR on GitHub servers as soon as they are pushed. To minimize iteration be sure to run your new tests locally, if possible. @@ -165,11 +175,11 @@ You can contribute patches by submitting a Pull Request to the ([bugfix-2.1.x](/ - To run all unit test suites: - Using PIO: `platformio run -t test-marlin` - Using Make: `make unit-test-all-local` - - Using Docker + make: `maker unit-test-all-local-docker` + - Using Docker + make: `make unit-test-all-local-docker` - To run a single unit test suite: - Using PIO: `platformio run -t marlin_` - Using make: `make unit-test-single-local TEST_TARGET=` - - Using Docker + make: `maker unit-test-single-local-docker TEST_TARGET=` + - Using Docker + make: `make unit-test-single-local-docker TEST_TARGET=` - If your feature can be unit tested, add one or more unit tests. For more information see our documentation on [Unit Tests](test). ## Contributors @@ -180,17 +190,17 @@ Marlin Firmware original logo design by Ahmet Cem TURAN [@ahmetcemturan](//githu ## Project Leadership -| Name | Role | Link | Donate | -| -------------------- | ------------ | -------------------------------------------- | --------------------------------------------------------------------- | -| 🇺🇸 Scott Lahteine | Project Lead | [[@thinkyhead](//github.com/thinkyhead)] | [💸 Donate](//marlinfw.org/docs/development/contributing.html#donate) | -| 🇺🇸 Roxanne Neufeld | Admin | [[@Roxy-3D](//github.com/Roxy-3D)] | -| 🇺🇸 Keith Bennett | Admin | [[@thisiskeithb](//github.com/thisiskeithb)] | [💸 Donate](//github.com/sponsors/thisiskeithb) | -| 🇺🇸 Jason Smith | Admin | [[@sjasonsmith](//github.com/sjasonsmith)] | -| 🇧🇷 Victor Oliveira | Admin | [[@rhapsodyv](//github.com/rhapsodyv)] | -| 🇬🇧 Chris Pepper | Admin | [[@p3p](//github.com/p3p)] | -| 🇳🇿 Peter Ellens | Admin | [[@ellensp](//github.com/ellensp)] | [💸 Donate](//ko-fi.com/ellensp) | -| 🇺🇸 Bob Kuhn | Admin | [[@Bob-the-Kuhn](//github.com/Bob-the-Kuhn)] | -| 🇳🇱 Erik van der Zalm | Founder | [[@ErikZalm](//github.com/ErikZalm)] | +| Name | Role | Link | Donate | +| --- | --- | --- | --- | +| 🇺🇸 Scott Lahteine | Project Lead | [[@thinkyhead](//github.com/thinkyhead)] | [❤️ Donate](//marlinfw.org/docs/development/contributing.html#donate) | +| 🇳🇿 Peter Ellens | Admin | [[@ellensp](//github.com/ellensp)] | [❤️ Donate](//ko-fi.com/ellensp) | +| 🇬🇧 Chris Pepper | Admin | [[@p3p](//github.com/p3p)] | +| 🇺🇸 Keith Bennett | Admin | [[@thisiskeithb](//github.com/thisiskeithb)] | [❤️ Donate](//github.com/sponsors/thisiskeithb) | +| 🇺🇸 Roxanne Neufeld | Admin | [[@Roxy-3D](//github.com/Roxy-3D)] | +| 🇺🇸 Jason Smith | Admin | [[@sjasonsmith](//github.com/sjasonsmith)] | +| 🇧🇷 Victor Oliveira | Admin | [[@rhapsodyv](//github.com/rhapsodyv)] | +| 🇺🇸 Bob Kuhn | Admin | [[@Bob-the-Kuhn](//github.com/Bob-the-Kuhn)] | +| 🇳🇱 Erik van der Zalm | Founder | [[@ErikZalm](//github.com/ErikZalm)] | ## Star History diff --git a/buildroot/bin/use_example_configs b/buildroot/bin/use_example_configs index 72930d8c45..b017205bdd 100755 --- a/buildroot/bin/use_example_configs +++ b/buildroot/bin/use_example_configs @@ -61,9 +61,9 @@ def copy_config_files(branch, config_path, dest_dir): else: debug_print(f"{fname} not found in {src_dir}") -def fetch_config_files(branch, config_path, dest_dir): +def fetch_config_files(cref, config_path, dest_dir): config_path_url = config_path.replace(' ', '%20') - base_url = f"https://raw.githubusercontent.com/MarlinFirmware/Configurations/{branch}/config/{config_path_url}" + base_url = f"https://raw.githubusercontent.com/MarlinFirmware/Configurations/{cref}/config/{config_path_url}" for file in CONFIG_FILES: url = f"{base_url}/{file}" @@ -80,8 +80,8 @@ def fetch_config_files(branch, config_path, dest_dir): else: raise -def fetch_configs(branch, config_path): - print(f"Fetching {config_path} configurations from {branch}...") +def fetch_configs(cref, config_path): + print(f"Fetching {config_path} configurations from {cref}...") marlin_dir = Path("Marlin") if not marlin_dir.exists(): @@ -89,37 +89,37 @@ def fetch_configs(branch, config_path): sys.exit(1) if os.environ.get('GITHUB_ACTIONS'): # Running on GitHub ? - copy_config_files(branch, config_path, marlin_dir) + copy_config_files(cref, config_path, marlin_dir) else: - fetch_config_files(branch, config_path, marlin_dir) + fetch_config_files(cref, config_path, marlin_dir) def main(): - branch = get_current_branch() - if not branch: + mbranch = get_current_branch() + if not mbranch: print("Not a git repository or no branch found.") sys.exit(1) - if branch.startswith("bugfix-2."): - branch = branch - elif branch.endswith("bugfix-2.1.x"): - branch = "bugfix-2.1.x" - elif branch.endswith("-2.1.x") or branch == "2.1.x": - branch = "latest-2.1.x" - elif branch.endswith("-2.0.x") or branch == "2.0.x": - branch = "latest-2.0.x" - elif branch.endswith("-1.1.x") or branch == "1.1.x": - branch = "latest-1.1.x" - elif branch.endswith("-1.0.x") or branch == "1.0.x": - branch = "latest-1.0.x" + if mbranch.startswith("bugfix-"): + cref = mbranch + elif mbranch.startswith("lts-"): + cref = mbranch.replace("lts-", "latest-") + elif mbranch.endswith("-2.1.x") or mbranch == "2.1.x": + cref = "latest-2.1.x" + elif mbranch.endswith("-2.0.x") or mbranch == "2.0.x": + cref = "latest-2.0.x" + elif mbranch.endswith("-1.1.x") or mbranch == "1.1.x": + cref = "latest-1.1.x" + elif mbranch == "1.0.x": + cref = "latest-1.0.x" else: - branch = "bugfix-2.1.x" + cref = "bugfix-2.1.x" if len(sys.argv) > 1: arg = sys.argv[1] if ':' in arg: part1, part2 = arg.split(':', 1) config_path = part2 - branch = part1 + cref = part1 else: config_path = arg config_path = 'examples/'+config_path @@ -134,7 +134,7 @@ def main(): except FileNotFoundError: print("restore_configs not found, skipping.") - fetch_configs(branch, config_path) + fetch_configs(cref, config_path) if __name__ == "__main__": main() diff --git a/buildroot/share/PlatformIO/boards/marlin_malyanM200.json b/buildroot/share/PlatformIO/boards/marlin_malyanM200.json deleted file mode 100644 index 4dbf760774..0000000000 --- a/buildroot/share/PlatformIO/boards/marlin_malyanM200.json +++ /dev/null @@ -1,35 +0,0 @@ -{ - "build": { - "core": "maple", - "cpu": "cortex-m3", - "extra_flags": "-DARDUINO_GENERIC_STM32F103C -DMCU_STM32F103CB", - "f_cpu": "72000000L", - "hwids": [ - ["0x1EAF", "0x0003"], - ["0x1EAF", "0x0004"] - ], - "ldscript": "jtagOffset.ld", - "mcu": "stm32f103cb", - "variant": "malyanM200", - "vec_tab_addr": "0x8002000" - }, - "debug": { - "jlink_device": "STM32F103CB", - "openocd_target": "stm32f1x", - "svd_path": "STM32F103xx.svd" - }, - "platform": "ststm32", - "frameworks": ["arduino"], - "name": "Malyan STM32F103CB (20k RAM. 128k Flash)", - "upload": { - "disable_flushing": false, - "maximum_ram_size": 20480, - "maximum_size": 131072, - "protocol": "serial", - "require_upload_port": true, - "use_1200bps_touch": false, - "wait_for_upload_port": false - }, - "url": "https://www.st.com/content/st_com/en/products/microcontrollers/stm32-32-bit-arm-cortex-mcus/stm32f1-series/stm32f103/stm32f103cb.html", - "vendor": "Generic" -} diff --git a/buildroot/share/PlatformIO/scripts/preprocessor.py b/buildroot/share/PlatformIO/scripts/preprocessor.py index efc3a6261e..3cd279fa57 100644 --- a/buildroot/share/PlatformIO/scripts/preprocessor.py +++ b/buildroot/share/PlatformIO/scripts/preprocessor.py @@ -37,15 +37,20 @@ def run_preprocessor(env, fn=None): else: cmd += ['-D' + s] - cmd += ['-D__MARLIN_DEPS__ -w -dM -E -x c++'] - depcmd = cmd + [ filename ] - cmd = ' '.join(depcmd) + cmd += ['-D__MARLIN_DEPS__ -w -dM -E -x c++', filename] + + cmd = ' '.join(cmd) blab(cmd) + try: - define_list = subprocess.check_output(cmd, shell=True).splitlines() + define_list_text = subprocess.check_output(cmd, shell=True) except: - define_list = {} + raise RuntimeError(f"Command `{cmd}` failed during build pre-processing.") + + define_list = define_list_text.splitlines() if define_list_text else [] + preprocessor_cache[filename] = define_list + return define_list diff --git a/buildroot/share/fonts/README.md b/buildroot/share/fonts/README.md index 57b4d1f57e..22c2d36651 100644 --- a/buildroot/share/fonts/README.md +++ b/buildroot/share/fonts/README.md @@ -4,7 +4,7 @@ The original author of the following font files is [A. Hardtung](https://github.com/AnHardt). -Any copyright is dedicated to the Public Domain. +Any copyright is dedicated to the Public Domain.\ https://creativecommons.org/publicdomain/zero/1.0/ - HD44780_C.fon ([fe2bd23](https://github.com/MarlinFirmware/Marlin/commit/fe2bd237d556439499dfdee852c1550c7a16430a)) diff --git a/buildroot/share/git/README.md b/buildroot/share/git/README.md index ae321303fc..3a22603ea9 100644 --- a/buildroot/share/git/README.md +++ b/buildroot/share/git/README.md @@ -16,26 +16,26 @@ The following scripts can be used on any system with a GNU environment to speed #### Remotes -| File | Description | -| ----------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| mfadd [user] | Add and Fetch Remote - Add and fetch another user's Marlin fork. Optionally, check out one of their branches. | -| mfinit | Init Working Copy - Create a remote named '`upstream`' (for use by the other scripts) pointing to the '`MarlinFirmware`' fork. This only needs to be used once. Newer versions of GitHub Desktop may create `upstream` on your behalf. | +| File | Description | +| --- | --- | +| mfadd [user] | Add and Fetch Remote - Add and fetch another user's Marlin fork. Optionally, check out one of their branches. | +| mfinit | Init Working Copy - Create a remote named '`upstream`' (for use by the other scripts) pointing to the '`MarlinFirmware`' fork. This only needs to be used once. Newer versions of GitHub Desktop may create `upstream` on your behalf. | #### Branches -| File | Description | -| ------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------ | -| mfnew [branch] | New Branch - Creates a new branch based on `upstream/[PR-target]`. All new work should start with this command. | -| mffp | Fast Push - Push the HEAD or a commit ID to `upstream` immediately. Requires privileged access to the MarlinFirmware repo. | -| firstpush | Push the current branch to 'origin' -your fork on GitHub- and set it to track '`origin`'. The branch needs to reside on GitHub before you can use it to make a PR. | +| File | Description | +| --- | --- | +| mfnew [branch] | New Branch - Creates a new branch based on `upstream/[PR-target]`. All new work should start with this command. | +| mffp | Fast Push - Push the HEAD or a commit ID to `upstream` immediately. Requires privileged access to the MarlinFirmware repo. | +| firstpush | Push the current branch to 'origin' -your fork on GitHub- and set it to track '`origin`'. The branch needs to reside on GitHub before you can use it to make a PR. | #### Making / Amending PRs -| File | Description | -| ---- | -------------------------------------------------------------------------------------------------------------------------------- | -| mfpr | Pull Request - Open the Compare / Pull Request page on GitHub for the current branch. | +| File | Description | +| --- | --- | +| mfpr | Pull Request - Open the Compare / Pull Request page on GitHub for the current branch. | | mfrb | Do a `git rebase` then `git rebase -i` of the current branch onto `upstream/[PR-target]`. Use this to edit your commits anytime. | -| mfqp | Quick Patch - Commit all current changes as "patch", then do `mfrb`, followed by `git push -f` if no conflicts need resolution. | +| mfqp | Quick Patch - Commit all current changes as "patch", then do `mfrb`, followed by `git push -f` if no conflicts need resolution. | #### Documentation @@ -46,12 +46,12 @@ The following scripts can be used on any system with a GNU environment to speed #### Utilities -| File | Description | -| ------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| ghtp -[h/s] | Set the protocol to use for all remotes. -h for HTTPS, -s for SSL. | -| ghpc [-f] | Push current branch to 'origin' or to the remote indicated by the error. | -| mfinfo | This utility script is used by the other scripts to get:
- The upstream project ('`MarlinFirmware`')
- the '`origin`' project (i.e., your GitHub username),
- the repository name ('`Marlin`'),
- the PR target branch ('`bugfix-1.1.x`'), and
- the current branch (or the first command-line argument).

By itself, `mfinfo` simply prints these values to the console. | -| mfclean      | Prune your merged and remotely-deleted branches. | +| File | Description | +| --- | --- | +| ghtp -[h/s] | Set the protocol to use for all remotes. -h for HTTPS, -s for SSL. | +| ghpc [-f] | Push current branch to 'origin' or to the remote indicated by the error. | +| mfinfo | This utility script is used by the other scripts to get:
- The upstream project ('`MarlinFirmware`')
- the '`origin`' project (i.e., your GitHub username),
- the repository name ('`Marlin`'),
- the PR target branch ('`bugfix-1.1.x`'), and
- the current branch (or the first command-line argument).

By itself, `mfinfo` simply prints these values to the console. | +| mfclean      | Prune your merged and remotely-deleted branches. | --- diff --git a/buildroot/share/scripts/linesformat.py b/buildroot/share/scripts/linesformat.py index 8978de0ec9..7fd80c1b55 100755 --- a/buildroot/share/scripts/linesformat.py +++ b/buildroot/share/scripts/linesformat.py @@ -69,6 +69,3 @@ def format_text(argv): # Python standard startup for command line with arguments if __name__ == '__main__': format_text(sys.argv[1:]) - -# Usage -apply_editorconfig_rules('/path/to/your/folder') diff --git a/buildroot/tests/DUE b/buildroot/tests/DUE index d5fcf2e4cb..9b8be3fbf9 100755 --- a/buildroot/tests/DUE +++ b/buildroot/tests/DUE @@ -14,8 +14,9 @@ opt_set MOTHERBOARD BOARD_RAMPS4DUE_EFB \ E0_AUTO_FAN_PIN 8 FANMUX0_PIN 53 EXTRUDER_AUTO_FAN_SPEED 100 \ TEMP_SENSOR_CHAMBER 3 TEMP_CHAMBER_PIN 6 HEATER_CHAMBER_PIN 45 \ BACKLASH_MEASUREMENT_FEEDRATE 600 \ - TRAMMING_POINT_XY '{{20,20},{20,20},{20,20},{20,20},{20,20}}' TRAMMING_POINT_NAME_5 '"Point 5"' -opt_enable S_CURVE_ACCELERATION EEPROM_SETTINGS GCODE_MACROS GCODE_MACROS_IN_EEPROM \ + TRAMMING_POINT_XY '{{20,20},{20,20},{20,20},{20,20},{20,20}}' TRAMMING_POINT_NAME_5 '"Point 5"' \ + FREEZE_PIN 17 +opt_enable S_CURVE_ACCELERATION FREEZE_FEATURE SOFT_FEED_HOLD EEPROM_SETTINGS GCODE_MACROS GCODE_MACROS_IN_EEPROM \ FIX_MOUNTED_PROBE Z_SAFE_HOMING CODEPENDENT_XY_HOMING \ ASSISTED_TRAMMING REPORT_TRAMMING_MM ASSISTED_TRAMMING_WAIT_POSITION \ EEPROM_SETTINGS SDSUPPORT BINARY_FILE_TRANSFER \ diff --git a/buildroot/tests/STM32F103RC_btt b/buildroot/tests/STM32F103RC_btt index 7a03dd64fa..9e6019bb91 100755 --- a/buildroot/tests/STM32F103RC_btt +++ b/buildroot/tests/STM32F103RC_btt @@ -11,11 +11,13 @@ set -e # restore_configs opt_set MOTHERBOARD BOARD_BTT_SKR_MINI_E3_V1_0 SERIAL_PORT 1 SERIAL_PORT_2 -1 \ - X_DRIVER_TYPE TMC2209 Y_DRIVER_TYPE TMC2209 Z_DRIVER_TYPE TMC2209 E0_DRIVER_TYPE TMC2209 \ + X_DRIVER_TYPE TMC2208 Y_DRIVER_TYPE TMC2208 Z_DRIVER_TYPE TMC2208 E0_DRIVER_TYPE TMC2208 \ X_CURRENT_HOME X_CURRENT/2 Y_CURRENT_HOME Y_CURRENT/2 Z_CURRENT_HOME Y_CURRENT/2 -opt_enable CR10_STOCKDISPLAY PINS_DEBUGGING Z_IDLE_HEIGHT EDITABLE_HOMING_CURRENT \ - INPUT_SHAPING_X INPUT_SHAPING_Y FT_MOTION FT_MOTION_MENU FTM_RESONANCE_TEST EMERGENCY_PARSER \ +opt_enable CR10_STOCKDISPLAY EMERGENCY_PARSER Z_IDLE_HEIGHT EDITABLE_HOMING_CURRENT \ + INPUT_SHAPING_X INPUT_SHAPING_Y \ + FT_MOTION FT_MOTION_MENU FTM_RESONANCE_TEST \ BIQU_MICROPROBE_V1 PROBE_ENABLE_DISABLE Z_SAFE_HOMING AUTO_BED_LEVELING_BILINEAR \ - ADAPTIVE_STEP_SMOOTHING LIN_ADVANCE SMOOTH_LIN_ADVANCE NONLINEAR_EXTRUSION + ADAPTIVE_STEP_SMOOTHING LIN_ADVANCE SMOOTH_LIN_ADVANCE NONLINEAR_EXTRUSION \ + PINS_DEBUGGING opt_disable FTM_POLYS -exec_test $1 $2 "BigTreeTech SKR Mini E3 1.0 - TMC2209 HW Serial, FT_MOTION w/out FTM_POLYS" "$3" +exec_test $1 $2 "BigTreeTech SKR Mini E3 1.0 - TMC2208 HW Serial, FT_MOTION w/out FTM_POLYS" "$3" diff --git a/docs/BinaryFileTransferProtocol.md b/docs/BinaryFileTransferProtocol.md index ebb1194aac..cd8eaae46f 100644 --- a/docs/BinaryFileTransferProtocol.md +++ b/docs/BinaryFileTransferProtocol.md @@ -38,14 +38,14 @@ ADB5 00 0 1 0000 0103 +-------------------------------+-------------------------------+ ``` -| Field | Width | Description | -| --------------- | ------- | ------------------------------------------------------------------------------------------------- | -| Start Token | 16 bits | Each packet must start with the 16-bit value `0xB5AD`. | -| Sync Number | 8 bits | Synchronization value, each packet after sync should increment this value by 1. | -| Protocol ID | 4 bits | Protocol ID. `0` for Connection Control, `1` for Transfer. See Below. | -| Packet Type | 4 bits | Packet Type ID. Depends on the Protocol ID, see below. | -| Payload Length | 16 bits | Length of payload data. If this value is greater than 0, a packet payload will follow the header. | -| Header Checksum | 16 bits | 16-bit Fletchers checksum of the header data excluding the Start Token | +| Field | Width | Description | +| --- | --- | --- | +| Start Token | 16 bits | Each packet must start with the 16-bit value `0xB5AD`. | +| Sync Number | 8 bits | Synchronization value, each packet after sync should increment this value by 1. | +| Protocol ID | 4 bits | Protocol ID. `0` for Connection Control, `1` for Transfer. See Below. | +| Packet Type | 4 bits | Packet Type ID. Depends on the Protocol ID, see below. | +| Payload Length | 16 bits | Length of payload data. If this value is greater than 0, a packet payload will follow the header. | +| Header Checksum | 16 bits | 16-bit Fletchers checksum of the header data excluding the Start Token | ## Packet Payload @@ -61,10 +61,10 @@ If the Payload Length field of the header is non-zero, payload data is expected +-------------------------------+-------------------------------+ ``` -| Field | Width | Description | -| --------------- | -------------------- | ------------------------------------------------------------------------------------------------------------------ | -| Payload Data | Payload Length bytes | Payload data. This should be no longer than the buffer length reported by the Connection SYNC operation. | -| Packet Checksum | 16 bits | 16-bit Fletchers checksum of the header and payload, including the Header Checksum, but excluding the Start Token. | +| Field | Width | Description | +| --- | --- | --- | +| Payload Data | Payload Length bytes | Payload data. This should be no longer than the buffer length reported by the Connection SYNC operation. | +| Packet Checksum | 16 bits | 16-bit Fletchers checksum of the header and payload, including the Header Checksum, but excluding the Start Token. | ## Fletchers Checksum @@ -125,13 +125,13 @@ Returns a sync response: ss,,.. ``` -| Value | Description | -| ------------- | --------------------------------------------------------------------------------------------------------------------- | -| SYNC | The current Sync Number, this should be used in the next packet sent and incremented by 1 for each packet sent after. | -| BUFFER_SIZE | The client buffer size. Packet Payload Length must not exceed this value. | -| VERSION_MAJOR | The major version number of the client Marlin BFT protocol, e.g., `0`. | -| VERSION_MINOR | The minor version number of the client Marlin BFT protocol, e.g., `1`. | -| VERSION_PATCH | The patch version number of the client Marlin BFT protocol, e.g., `0`. | +| Value | Description | +| --- | --- | +| SYNC | The current Sync Number, this should be used in the next packet sent and incremented by 1 for each packet sent after. | +| BUFFER_SIZE | The client buffer size. Packet Payload Length must not exceed this value. | +| VERSION_MAJOR | The major version number of the client Marlin BFT protocol, e.g., `0`. | +| VERSION_MINOR | The minor version number of the client Marlin BFT protocol, e.g., `1`. | +| VERSION_PATCH | The patch version number of the client Marlin BFT protocol, e.g., `0`. | Example response: @@ -147,13 +147,13 @@ A CLOSE packet should be the last packet sent by a host. On success, the client `Protocol ID` 1 packets control the file transfers performed over the connection: -| Packet Type | Name | Description | -| ----------- | ----- | ------------------------------------------------------------- | -| 0 | QUERY | Query the client protocol details and compression parameters. | -| 1 | OPEN | Open a file for writing and begin accepting data to transfer. | -| 2 | CLOSE | Finish writing and close the current file. | -| 3 | WRITE | Write data to an open file. | -| 4 | ABORT | Abort file transfer. | +| Packet Type | Name | Description | +| --- | --- | --- | +| 0 | QUERY | Query the client protocol details and compression parameters. | +| 1 | OPEN | Open a file for writing and begin accepting data to transfer. | +| 2 | CLOSE | Finish writing and close the current file. | +| 3 | WRITE | Write data to an open file. | +| 4 | ABORT | Abort file transfer. | ### QUERY Packet @@ -165,12 +165,12 @@ Returns a query response: PFT:version:..:compression:(,) ``` -| Value | Description | -| ------------------ | --------------------------------------------------------------------------------------------------------------------------------------------- | -| VERSION_MAJOR | The major version number of the client Marlin BFT protocol, e.g., `0`. | -| VERSION_MINOR | The minor version number of the client Marlin BFT protocol, e.g., `1`. | -| VERSION_PATCH | The patch version number of the client Marlin BFT protocol, e.g., `0`. | -| COMPRESSION_ALGO | Compression algorithm. Currently either `heatshrink` or `none` | +| Value | Description | +| --- | --- | +| VERSION_MAJOR | The major version number of the client Marlin BFT protocol, e.g., `0`. | +| VERSION_MINOR | The minor version number of the client Marlin BFT protocol, e.g., `1`. | +| VERSION_PATCH | The patch version number of the client Marlin BFT protocol, e.g., `0`. | +| COMPRESSION_ALGO | Compression algorithm. Currently either `heatshrink` or `none` | | COMPRESSION_PARAMS | Compression parameters, separated by commas. Currently, if `COMPRESSION_AGLO` is heatshrink, this will be the window size and lookahead size. | Example response: @@ -197,12 +197,12 @@ Payload: +-------------------------------+-------------------------------+ ``` -| Field | Width | Description | -| --------------- | ------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| Dummy | 8 bits | A boolean value indicating if this file transfer should be actually carried out or not. If `1`, the client will respond as if the file is opened and accept data transfer, but no data will be written. | -| Compression | 8 bits | A boolean value indicating if the data to be transferred will be compressed using the algorithm and parameters returned in the QUERY Packet. | -| Filename | ... | A filename including a null terminator byte. | -| Packet Checksum | 16 bits | 16-bit Fletchers checksum of the header and payload, including the Header Checksum, but excluding the Start Token. | +| Field | Width | Description | +| --- | --- | --- | +| Dummy | 8 bits | A boolean value indicating if this file transfer should be actually carried out or not. If `1`, the client will respond as if the file is opened and accept data transfer, but no data will be written. | +| Compression | 8 bits | A boolean value indicating if the data to be transferred will be compressed using the algorithm and parameters returned in the QUERY Packet. | +| Filename | ... | A filename including a null terminator byte. | +| Packet Checksum | 16 bits | 16-bit Fletchers checksum of the header and payload, including the Header Checksum, but excluding the Start Token. | Responses: @@ -228,7 +228,7 @@ Responses: Writes payload data to the currently open file. If the file was opened with Compression set to 1, the data will be decompressed first. Payload Length must not exceed the buffer size returned by the SYNC Packet. -Responses: +Responses:\ On success, an `ok` response will be sent. On error, an `ok` response will be followed by an error response: | Response | Description | diff --git a/docs/Bresenham.md b/docs/Bresenham.md index 6916e35f48..f447ac0056 100644 --- a/docs/Bresenham.md +++ b/docs/Bresenham.md @@ -1,4 +1,4 @@ -On the Bresenham algorithm as implemented by Marlin: +On the Bresenham algorithm as implemented by Marlin:\ (Taken from (https://www.cs.helsinki.fi/group/goa/mallinnus/lines/bresenh.html) The basic Bresenham algorithm: diff --git a/docs/ConfigEmbedding.md b/docs/ConfigEmbedding.md index a9770fb42b..ac032ab1ed 100644 --- a/docs/ConfigEmbedding.md +++ b/docs/ConfigEmbedding.md @@ -8,7 +8,7 @@ At the start of the PlatformIO build process, we create an embedded configuratio ## Extracting configurations from a Marlin binary -To get the configuration out of a binary firmware, you'll need a non-write-protected SD card inserted into the printer while running the firmware. +To get the configuration out of a binary firmware, you'll need a non-write-protected SD card inserted into the printer while running the firmware.\ Send the command `M503 C` to write the file `mc.zip` to the SD card. Copy the file to your computer, ideally in the same folder as the Marlin repository. Run the following commands to extract and apply the configuration: diff --git a/docs/Cutter.md b/docs/Cutter.md index ace957210a..51ed260b08 100644 --- a/docs/Cutter.md +++ b/docs/Cutter.md @@ -91,7 +91,7 @@ Once the entry and exit power values are determined, the values are divided into trap step power incr_decr = ( cruize power - entry_exit ) / accel_decel_steps -The trap steps are incremented or decremented during each accel or decel step until the block is complete. +The trap steps are incremented or decremented during each accel or decel step until the block is complete.\ Step power is either cumulatively added or subtracted during trapezoid ramp progressions. #### Planner Code: diff --git a/docs/Serial.md b/docs/Serial.md index 9ef9a781fa..6806199ae9 100644 --- a/docs/Serial.md +++ b/docs/Serial.md @@ -1,6 +1,6 @@ # Serial port architecture in Marlin -Marlin is targeting a plethora of different CPU architectures and platforms. Each of these platforms has its own serial interface. +Marlin is targeting a plethora of different CPU architectures and platforms. Each of these platforms has its own serial interface.\ While many provide a Arduino-like Serial class, it's not all of them, and the differences in the existing API create a very complex brain teaser for writing code that works more or less on each platform. Moreover, many platform have intrinsic needs about serial port (like forwarding the output on multiple serial port, providing a _serial-like_ telnet server, mixing USB-based serial port with SD card emulation) that are difficult to handle cleanly in the other platform serial logic. @@ -9,18 +9,17 @@ Starting with version 2.0.8, Marlin provides a common interface for its serial n ## Common interface -This interface is declared in `Marlin/src/core/serial_base.h` +This interface is declared in `Marlin/src/core/serial_base.h`.\ Any implementation will need to follow this interface for being used transparently in Marlin's codebase. -The implementation was written to prioritize performance over abstraction, so the base interface is not using virtual inheritance to avoid the cost of virtual dispatching while calling methods. +The implementation was written to prioritize performance over abstraction, so the base interface is not using virtual inheritance to avoid the cost of virtual dispatching while calling methods.\ Instead, the Curiously Recurring Template Pattern (**CRTP**) is used so that, upon compilation, the interface abstraction does not incur a performance cost. Because some platform do not follow the same interface, the missing method in the actual low-level implementation are detected via SFINAE and a wrapper is generated when such method are missing. See the `CALL_IF_EXISTS` macro in `Marlin/src/core/macros.h` for documentation of this technique. ## Composing the desired feature -The different specificities for each architecture are provided by composing the serial type based on desired functionality. -In the `Marlin/src/core/serial_hook.h` file, the different serial feature are declared and defined in each templated type: +The different specificities for each architecture are provided by composing the serial type based on desired functionality. In the `Marlin/src/core/serial_hook.h` file, the different serial feature are declared and defined in each templated type: 1. `BaseSerial` is a simple 1:1 wrapper to the underlying, Arduino compatible, `Serial`'s class. It derives from it. You'll use this if the platform does not do anything specific for the `Serial` object (for example, if an interrupt callback calls directly the serial **instance** in the platform's framework code, this is not the right class to use). This wrapper is completely inlined so that it does not generate any code upon compilation. `BaseSerial` constructor forwards any parameter to the platform's `Serial`'s constructor. 2. `ForwardSerial` is a composing wrapper. It references an actual Arduino compatible `Serial` instance. You'll use this if the instance is declared in the platform's framework and is being referred directly in the framework. This is not as efficient as the `BaseSerial` implementation since static dereferencing is done for each method call (it'll still be faster than virtual dispatching) @@ -30,7 +29,7 @@ In the `Marlin/src/core/serial_hook.h` file, the different serial feature are de ## Plumbing -Since all the types above are using CRTP, it's possible to combine them to get the appropriate functionality. +Since all the types above are using CRTP, it's possible to combine them to get the appropriate functionality.\ This is easily done via type definition of the feature. For example, to create a single serial interface with 2 serial outputs (one enabled at runtime and the other switchable): @@ -51,8 +50,8 @@ The magical numbers here are the step and offset for computing the serial port. MS< A = MS, B=MS, offset=0, step=2> ``` -This means that the underlying multiserial A (with output to `a,b`) is available from offset = 0 to offset + step = 1 (default value). -The multiserial B (with output to `c,d`) is available from offset = 2 (the next step from the root multiserial) to offset + step = 3. +This means that the underlying multiserial A (with output to `a,b`) is available from offset = 0 to offset + step = 1 (default value).\ +The multiserial B (with output to `c,d`) is available from offset = 2 (the next step from the root multiserial) to offset + step = 3.\ In practice, the root multiserial will redirect any index/mask `offset` to `offset + step - 1` to its first leaf, and any index/mask `offset + step` to `offset + 2*step - 1` to its second leaf. ## Emergency parser @@ -63,19 +62,19 @@ By default, the serial base interface provide an emergency parser that's only en The following macros are defined (in `serial.h`) to output data to the serial ports: -| MACRO | Parameters | Usage | Example | Expected output | -| -------------------- | ----------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------- | ----------------------------------------------------------------------- | ----------------- | -| `SERIAL_ECHO` | Any basic type is supported (`char`, `uint8_t`, `int16_t`, `int32_t`, `float`, `long`, `const char*`, ...). | For a numeric type it prints the number in decimal. A string is output as a string. | `uint8_t a = 123; SERIAL_ECHO(a); SERIAL_CHAR(' '); SERIAL_ECHO(' '); ` | `123 32` | -| `SERIAL_ECHOLN` | Same as `SERIAL_ECHO` | Do `SERIAL_ECHO`, adding a newline | `int a = 456; SERIAL_ECHOLN(a);` | `456\n` | -| `SERIAL_ECHOPGM` | String / Value pairs | Print a series of string literals and values alternately | `SERIAL_ECHOPGM("Bob", 34);` | `Bob34` | -| `SERIAL_ECHOLNPGM` | Same as `SERIAL_ECHOPGM` | Do `SERIAL_ECHOPGM`, adding a newline | `SERIAL_ECHOPGM("Alice", 56);` | `alice56` | -| `SERIAL_ECHOPGM_P` | Like `SERIAL_ECHOPGM` but takes PGM strings | Print a series of PGM strings and values alternately | `SERIAL_ECHOPGM_P(GET_TEXT(MSG_HELLO), 123);` | `Hello123` | -| `SERIAL_ECHOLNPGM_P` | Same as `SERIAL_ECHOPGM_P` | Do `SERIAL_ECHOPGM_P`, adding a newline | `SERIAL_ECHOLNPGM_P(PSTR("Alice"), 78);` | `alice78\n` | -| `SERIAL_ECHO_START` | None | Prefix an echo line | `SERIAL_ECHO_START();` | `echo:` | -| `SERIAL_ECHO_MSG` | Same as `SERIAL_ECHOLNPGM` | Print a full echo line | `SERIAL_ECHO_MSG("Count is ", count);` | `echo:Count is 3` | -| `SERIAL_ERROR_START` | None | Prefix an error line | `SERIAL_ERROR_START();` | `Error:` | -| `SERIAL_ERROR_MSG` | Same as `SERIAL_ECHOLNPGM` | Print a full error line | `SERIAL_ERROR_MSG("Not found");` | `Error:Not found` | -| `SERIAL_ECHO_SP` | Number of spaces | Print one or more spaces | `SERIAL_ECHO_SP(3)` | ` ` | -| `SERIAL_EOL` | None | Print an end of line | `SERIAL_EOL();` | `\n` | +| MACRO | Parameters | Usage | Example | Expected output | +| --- | --- | --- | --- | --- | +| `SERIAL_ECHO` | Any basic type is supported (`char`, `uint8_t`, `int16_t`, `int32_t`, `float`, `long`, `const char*`, ...). | For a numeric type it prints the number in decimal. A string is output as a string. | `uint8_t a = 123; SERIAL_ECHO(a); SERIAL_CHAR(' '); SERIAL_ECHO(' '); ` | `123 32` | +| `SERIAL_ECHOLN` | Same as `SERIAL_ECHO` | Do `SERIAL_ECHO`, adding a newline | `int a = 456; SERIAL_ECHOLN(a);` | `456\n` | +| `SERIAL_ECHOPGM` | String / Value pairs | Print a series of string literals and values alternately | `SERIAL_ECHOPGM("Bob", 34);` | `Bob34` | +| `SERIAL_ECHOLNPGM` | Same as `SERIAL_ECHOPGM` | Do `SERIAL_ECHOPGM`, adding a newline | `SERIAL_ECHOPGM("Alice", 56);` | `alice56` | +| `SERIAL_ECHOPGM_P` | Like `SERIAL_ECHOPGM` but takes PGM strings | Print a series of PGM strings and values alternately | `SERIAL_ECHOPGM_P(GET_TEXT(MSG_HELLO), 123);` | `Hello123` | +| `SERIAL_ECHOLNPGM_P` | Same as `SERIAL_ECHOPGM_P` | Do `SERIAL_ECHOPGM_P`, adding a newline | `SERIAL_ECHOLNPGM_P(PSTR("Alice"), 78);` | `alice78\n` | +| `SERIAL_ECHO_START` | None | Prefix an echo line | `SERIAL_ECHO_START();` | `echo:` | +| `SERIAL_ECHO_MSG` | Same as `SERIAL_ECHOLNPGM` | Print a full echo line | `SERIAL_ECHO_MSG("Count is ", count);` | `echo:Count is 3` | +| `SERIAL_ERROR_START` | None | Prefix an error line | `SERIAL_ERROR_START();` | `Error:` | +| `SERIAL_ERROR_MSG` | Same as `SERIAL_ECHOLNPGM` | Print a full error line | `SERIAL_ERROR_MSG("Not found");` | `Error:Not found` | +| `SERIAL_ECHO_SP` | Number of spaces | Print one or more spaces | `SERIAL_ECHO_SP(3)` | ` ` | +| `SERIAL_EOL` | None | Print an end of line | `SERIAL_EOL();` | `\n` | _This document was written by [X-Ryl669](https://blog.cyril.by) and is under [CC-SA license](https://creativecommons.org/licenses/by-sa)_ diff --git a/ini/stm32f1-maple.ini b/ini/stm32f1-maple.ini index f6c8b8da56..36f651b976 100644 --- a/ini/stm32f1-maple.ini +++ b/ini/stm32f1-maple.ini @@ -326,30 +326,19 @@ extra_scripts = ${STM32F1_maple.extra_scripts} buildroot/share/PlatformIO/scripts/jgaurora_a5s_a1_with_bootloader.py build_flags = ${STM32F1_maple.build_flags} -DSTM32F1xx -DSTM32_XL_DENSITY -# -# Malyan M200 (STM32F103CB) -# -[env:STM32F103CB_malyan_maple] -extends = STM32F1_maple -board = marlin_malyanM200 -build_flags = ${STM32F1_maple.build_flags} - -DMCU_STM32F103CB -D__STM32F1__=1 -std=c++1y -DSERIAL_USB -ffunction-sections -fdata-sections - -Wl,--gc-sections -DDEBUG_LEVEL=0 -lib_ignore = ${STM32F1_maple.lib_ignore} - SoftwareSerialM - # # Chitu boards like Tronxy X5s (STM32F103ZET6) # [env:chitu_f103_maple] -extends = STM32F1_maple -board = marlin_maple_CHITU_F103 -extra_scripts = ${STM32F1_maple.extra_scripts} - pre:buildroot/share/PlatformIO/scripts/STM32F1_create_variant.py - buildroot/share/PlatformIO/scripts/chitu_crypt.py -build_flags = ${STM32F1_maple.build_flags} -DSTM32F1xx -DSTM32_XL_DENSITY -DSTM32_FLASH_SIZE=512 -build_unflags = ${STM32F1_maple.build_unflags} - -DCONFIG_MAPLE_MINI_NO_DISABLE_DEBUG= -DERROR_LED_PORT=GPIOE -DERROR_LED_PIN=6 +extends = STM32F1_maple +board = marlin_maple_CHITU_F103 +extra_scripts = ${STM32F1_maple.extra_scripts} + pre:buildroot/share/PlatformIO/scripts/STM32F1_create_variant.py + buildroot/share/PlatformIO/scripts/chitu_crypt.py +build_flags = ${STM32F1_maple.build_flags} -DSTM32F1xx -DSTM32_XL_DENSITY -DSTM32_FLASH_SIZE=512 +build_unflags = ${STM32F1_maple.build_unflags} + -DCONFIG_MAPLE_MINI_NO_DISABLE_DEBUG= -DERROR_LED_PORT=GPIOE -DERROR_LED_PIN=6 +board_build.crypt_chitu = update.cbd # # Some Chitu V5 boards have a problem with GPIO init. diff --git a/ini/stm32f1.ini b/ini/stm32f1.ini index 58b33afaaf..3e9cd3b058 100644 --- a/ini/stm32f1.ini +++ b/ini/stm32f1.ini @@ -115,6 +115,22 @@ build_unflags = ${common_STM32F103RC_variant.build_unflags} -DUSBCON -DUSBD_USE_CDC debug_tool = stlink +# +# AtomStack FB5 V2.0 (STM32F103RCT6 ARM Cortex-M3) +# +[env:STM32F103RC_atomstack] +extends = common_STM32F103RC_variant +board_build.encrypt_mks = Robin_e3.bin +board_build.offset = 0x5000 +board_upload.offset_address = 0x08005000 +build_flags = ${common_STM32F103RC_variant.build_flags} + -DTIMER_SERVO=TIM5 + -DUSE_USB_FS + -DUSBD_IRQ_PRIO=5 + -DUSBD_IRQ_SUBPRIO=6 + -DUSBD_USE_CDC_MSC +;upload_protocol = stlink + # # Creality (STM32F103Rx) #