diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile new file mode 100644 index 0000000000..4f29a10053 --- /dev/null +++ b/.devcontainer/Dockerfile @@ -0,0 +1,29 @@ +# See here for image contents: https://github.com/microsoft/vscode-dev-containers/tree/v0.187.0/containers/python-3/.devcontainer/base.Dockerfile + +# [Choice] Python version: 3, 3.9, 3.8, 3.7, 3.6 +ARG VARIANT="3.9.0-buster" +FROM python:${VARIANT} + +# [Option] Install Node.js +ARG INSTALL_NODE="true" +ARG NODE_VERSION="lts/*" +RUN if [ "${INSTALL_NODE}" = "true" ]; then su vscode -c "umask 0002 && . /usr/local/share/nvm/nvm.sh && nvm install ${NODE_VERSION} 2>&1"; fi + +# [Optional] If your pip requirements rarely change, uncomment this section to add them to the image. +# COPY requirements.txt /tmp/pip-tmp/ +# RUN pip3 --disable-pip-version-check --no-cache-dir install -r /tmp/pip-tmp/requirements.txt \ +# && rm -rf /tmp/pip-tmp + +# [Optional] Uncomment this section to install additional OS packages. +# RUN apt-get update && export DEBIAN_FRONTEND=noninteractive \ +# && apt-get -y install --no-install-recommends + +# [Optional] Uncomment this line to install global node packages. +# RUN su vscode -c "source /usr/local/share/nvm/nvm.sh && npm install -g " 2>&1 + + +RUN pip install -U https://github.com/platformio/platformio-core/archive/develop.zip +RUN platformio update +# To get the test platforms +RUN pip install PyYaml +#ENV PATH /code/buildroot/bin/:/code/buildroot/tests/:${PATH} diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json new file mode 100644 index 0000000000..54627d462b --- /dev/null +++ b/.devcontainer/devcontainer.json @@ -0,0 +1,51 @@ +// For format details, see https://aka.ms/devcontainer.json. For config options, see the README at: +// https://github.com/microsoft/vscode-dev-containers/tree/v0.187.0/containers/python-3 +{ + "name": "Python 3", + "build": { + "dockerfile": "Dockerfile", + "context": "..", + "args": { + // Update 'VARIANT' to pick a Python version: 3, 3.6, 3.7, 3.8, 3.9 + "VARIANT": "3.9.0-buster", + // Options + "INSTALL_NODE": "false", + "NODE_VERSION": "lts/*" + } + }, + + // Set *default* container specific settings.json values on container create. + "settings": { + "python.pythonPath": "/usr/local/bin/python", + "python.languageServer": "Pylance", + "python.linting.enabled": true, + "python.linting.pylintEnabled": true, + "python.formatting.autopep8Path": "/usr/local/py-utils/bin/autopep8", + "python.formatting.blackPath": "/usr/local/py-utils/bin/black", + "python.formatting.yapfPath": "/usr/local/py-utils/bin/yapf", + "python.linting.banditPath": "/usr/local/py-utils/bin/bandit", + "python.linting.flake8Path": "/usr/local/py-utils/bin/flake8", + "python.linting.mypyPath": "/usr/local/py-utils/bin/mypy", + "python.linting.pycodestylePath": "/usr/local/py-utils/bin/pycodestyle", + "python.linting.pydocstylePath": "/usr/local/py-utils/bin/pydocstyle", + "python.linting.pylintPath": "/usr/local/py-utils/bin/pylint" + }, + + // Add the IDs of extensions you want installed when the container is created. + "extensions": [ + "ms-python.python", + "ms-python.vscode-pylance", + "platformio.platformio-ide", + "marlinfirmware.auto-build", + "editorconfig.editorconfig" + ], + + // Use 'forwardPorts' to make a list of ports inside the container available locally. + // "forwardPorts": [], + + // Use 'postCreateCommand' to run commands after the container is created. + // "postCreateCommand": "pip3 install --user -r requirements.txt", + + // Comment out connect as root instead. More info: https://aka.ms/vscode-remote/containers/non-root. + // "remoteUser": "vscode" +} diff --git a/.editorconfig b/.editorconfig index 57a5b2fb5e..1037e74ef3 100644 --- a/.editorconfig +++ b/.editorconfig @@ -1,19 +1,29 @@ # editorconfig.org root = true +[*] +trim_trailing_whitespace = true +insert_final_newline = true + [{*.patch,syntax_test_*}] trim_trailing_whitespace = false +[{*.c,*.cpp,*.h,*.ino,*.py,Makefile}] +end_of_line = lf + [{*.c,*.cpp,*.h,*.ino}] charset = utf-8 - -[{*.c,*.cpp,*.h,*.ino,Makefile}] -trim_trailing_whitespace = true -insert_final_newline = true -end_of_line = lf indent_style = space indent_size = 2 +[{Makefile}] +indent_style = tab +indent_size = 2 + +[*.md] +# Two spaces at the end of the line means newline in Markdown +trim_trailing_whitespace = false + [{*.py}] indent_style = space indent_size = 4 diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml index efc5972325..e0ee13af07 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.yml +++ b/.github/ISSUE_TEMPLATE/bug_report.yml @@ -1,6 +1,7 @@ name: 🪲 Report a bug description: Create a bug report to help improve Marlin Firmware title: "[BUG] (bug summary)" +labels: ["Bug: Potential ?"] body: - type: markdown attributes: @@ -100,7 +101,7 @@ body: - type: input attributes: label: Printer model - description: Creality Ender 3, Prusa mini, or Kossel Delta? + description: Creality Ender-3, Prusa mini, or Kossel Delta? - type: input attributes: @@ -109,8 +110,13 @@ body: - type: input attributes: - label: Add-ons - description: Please list any hardware add-ons that could be involved. + label: LCD/Controller + description: Some Marlin behaviors are determined by the controller. Describe your LCD/Controller model and version. + + - type: input + attributes: + label: Other add-ons + description: Please list any other hardware add-ons that could be involved. - type: dropdown attributes: diff --git a/.github/ISSUE_TEMPLATE/feature_request.yml b/.github/ISSUE_TEMPLATE/feature_request.yml index b64383cd48..2e8607142c 100644 --- a/.github/ISSUE_TEMPLATE/feature_request.yml +++ b/.github/ISSUE_TEMPLATE/feature_request.yml @@ -1,7 +1,7 @@ name: ✨ Request a feature description: Request a new Marlin Firmware feature title: "[FR] (feature summary)" -labels: 'T: Feature Request' +labels: ["T: Feature Request"] body: - type: markdown attributes: diff --git a/.github/code_of_conduct.md b/.github/code_of_conduct.md index 854fed4ec4..5fd9e0c8ee 100644 --- a/.github/code_of_conduct.md +++ b/.github/code_of_conduct.md @@ -28,15 +28,9 @@ Project maintainers are responsible for clarifying the standards of acceptable b Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful. -## Scope - -This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers. - ## Enforcement -Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at [marlinfirmware@github.com](mailto:marlinfirmware@github.com). All complaints will be reviewed and investigated and will result in a response that is deemed necessary and appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately. - -Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership. +Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by following GitHub's [reporting abuse or spam article](https://docs.github.com/en/communities/maintaining-your-safety-on-github/reporting-abuse-or-spam). All complaints will be reviewed and investigated and will result in a response that is deemed necessary and appropriate to the circumstances. ## Attribution diff --git a/.github/contributing.md b/.github/contributing.md index ef1726366a..c9b31998e9 100644 --- a/.github/contributing.md +++ b/.github/contributing.md @@ -26,11 +26,12 @@ The following is a set of guidelines for contributing to Marlin, hosted by the [ ## Code of Conduct -This project and everyone participating in it is governed by the [Marlin Code of Conduct](code_of_conduct.md). By participating, you are expected to uphold this code. Please report unacceptable behavior to [marlinfirmware@github.com](mailto:marlinfirmware@github.com). +This project and everyone participating in it is governed by the [Marlin Code of Conduct](code_of_conduct.md). By participating, you are expected to uphold this code. Please report unacceptable behavior by following GitHub's [reporting abuse or spam article](https://docs.github.com/en/communities/maintaining-your-safety-on-github/reporting-abuse-or-spam). ## 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. +> [!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. @@ -55,7 +56,8 @@ 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. +> [!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? diff --git a/.github/workflows/auto-label.yml b/.github/workflows/auto-label.yml new file mode 100644 index 0000000000..c69e6c4fad --- /dev/null +++ b/.github/workflows/auto-label.yml @@ -0,0 +1,41 @@ +# +# auto-label.yml +# - Find all open issues without a label and a title containing "[BUG]". +# - Apply the label "Bug: Potential ?" to these issues. +# + +name: Label Old Bugs + +on: + schedule: + - cron: "30 8 * * *" + +jobs: + autolabel: + name: Auto Label + if: github.repository == 'MarlinFirmware/Marlin' + runs-on: ubuntu-latest + steps: + - name: Auto Label for [BUG] + uses: actions/github-script@v7 + with: + script: | + // Get all open issues in this repository + const issueList = await github.rest.issues.listForRepo({ + owner: context.repo.owner, + repo: context.repo.repo, + state: 'open' + }); + // Filter issues without labels that have a title containing '[BUG]'. + const matchingIssues = issueList.data.filter( + issue => issue.title.includes('[BUG]') && issue.labels.length === 0 + ); + // Process the first 50 + for (const issue of matchingIssues.slice(0, 50)) { + await github.rest.issues.addLabels({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: issue.number, + labels: ['Bug: Potential ?'] + }); + } diff --git a/.github/workflows/bump-date.yml b/.github/workflows/bump-date.yml index 51b58ad493..a08eeea561 100644 --- a/.github/workflows/bump-date.yml +++ b/.github/workflows/bump-date.yml @@ -18,10 +18,10 @@ jobs: steps: - - name: Check out bugfix-2.1.x - uses: actions/checkout@v2 + - name: Check out bugfix-2.0.x + uses: actions/checkout@v3 with: - ref: bugfix-2.1.x + ref: bugfix-2.0.x - name: Bump Date (bugfix-2.0.x) run: | @@ -39,7 +39,7 @@ jobs: exit 0 - name: Check out bugfix-2.1.x - uses: actions/checkout@v2 + uses: actions/checkout@v3 with: ref: bugfix-2.1.x diff --git a/.github/workflows/check-pr.yml b/.github/workflows/check-pr.yml index f631f69dea..2b15067f51 100644 --- a/.github/workflows/check-pr.yml +++ b/.github/workflows/check-pr.yml @@ -12,7 +12,6 @@ on: - 1.0.x - 1.1.x - 2.0.x - - 2.1.x jobs: bad_target: @@ -29,6 +28,6 @@ jobs: Please redo this PR starting with the `bugfix-2.1.x` branch and be careful to target `bugfix-2.1.x` when resubmitting the PR. Patches may also target `bugfix-2.0.x` if they are specifically for 2.0.9.x. - It may help to set your fork's default branch to `bugfix-2.0.x`. + It may help to set your fork's default branch to `bugfix-2.1.x`. See [this page](https://marlinfw.org/docs/development/getting_started_pull_requests.html) for full instructions. diff --git a/.github/workflows/clean-closed.yml b/.github/workflows/clean-closed.yml index befec4498f..318d083dfa 100644 --- a/.github/workflows/clean-closed.yml +++ b/.github/workflows/clean-closed.yml @@ -23,6 +23,7 @@ jobs: - "S: Please Merge" - "S: Please Test" - "help wanted" + - "Bug: Potential ?" - "Needs: Discussion" - "Needs: Documentation" - "Needs: More Data" @@ -31,7 +32,7 @@ jobs: - "Needs: Work" steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - name: Remove Labels uses: actions-ecosystem/action-remove-labels@v1 with: diff --git a/.github/workflows/close-stale.yml b/.github/workflows/close-stale.yml index 88fea1996d..397f9b5ea6 100644 --- a/.github/workflows/close-stale.yml +++ b/.github/workflows/close-stale.yml @@ -17,12 +17,24 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/stale@v3 + - uses: actions/stale@v8 with: repo-token: ${{ secrets.GITHUB_TOKEN }} - stale-issue-message: 'This issue has had no activity in the last 60 days. Please add a reply if you want to keep this issue active, otherwise it will be automatically closed within 10 days.' - days-before-stale: 60 - days-before-close: 10 + stale-issue-message: | + Greetings from the Marlin AutoBot! + This issue has had no activity for the last 90 days. + Do you still see this issue with the latest `bugfix-2.1.x` code? + Please add a reply within 14 days or this issue will be automatically closed. + To keep a confirmed issue open we can also add a "Bug: Confirmed" tag. + + Disclaimer: This is an open community project with lots of activity and limited + resources. The main project contributors will do a bug sweep ahead of the next + release, but any skilled member of the community may jump in at any time to fix + this issue. That can take a while depending on our busy lives so please be patient, + and take advantage of other resources such as the MarlinFirmware Discord to help + solve the issue. + days-before-stale: 90 + days-before-close: 14 stale-issue-label: 'stale-closing-soon' exempt-all-assignees: true exempt-issue-labels: 'Bug: Confirmed !,T: Feature Request,Needs: More Data,Needs: Discussion,Needs: Documentation,Needs: Patch,Needs: Work,Needs: Testing,help wanted,no-locking' diff --git a/.github/workflows/test-builds.yml b/.github/workflows/test-builds.yml index 5a18a2e8bf..7c62b5af6c 100644 --- a/.github/workflows/test-builds.yml +++ b/.github/workflows/test-builds.yml @@ -9,6 +9,7 @@ on: pull_request: branches: - bugfix-2.1.x + - 2.1.x paths-ignore: - config/** - data/** @@ -17,6 +18,7 @@ on: push: branches: - bugfix-2.1.x + - 2.1.x paths-ignore: - config/** - data/** @@ -33,93 +35,121 @@ jobs: strategy: matrix: test-platform: - # Base Environments - - DUE - - DUE_archim - - esp32 + # Native - linux_native + + # AVR - mega2560 - - at90usb1286_dfu - - teensy31 - - teensy35 - - teensy41 - - SAMD51_grandcentral_m4 - - PANDA_PI_V29 - - # Extended AVR Environments - - - FYSETC_F6 - mega1280 + - at90usb1286_dfu + + # AVR Extended + - FYSETC_F6 + - melzi_optiboot - rambo - sanguino1284p - sanguino644p - # STM32F1 (Maple) Environments + # SAM3X8E + - DUE + - DUE_archim - #- STM32F103RC_btt_maple - - STM32F103RC_btt_USB_maple - - STM32F103RC_fysetc_maple - - STM32F103RC_meeb_maple - - jgaurora_a5s_a1_maple - - STM32F103VE_longer_maple - #- mks_robin_maple - - mks_robin_lite_maple - - mks_robin_pro_maple - #- mks_robin_nano_v1v2_maple - #- STM32F103RE_creality_maple - - STM32F103VE_ZM3E4V2_USB_maple + # SAMD21 + - SAMD51_grandcentral_m4 + - SAMD21_minitronics20 - # STM32 (ST) Environments + # ESP32 + - esp32 + - mks_tinybee + # Teensy 2 + #- at90usb1286_cdc + + # Teensy MK20DX256 + - teensy31 + + # Teensy MK64FX512, MK66FX1M0 + - teensy35 + + # Teensy IMXRT1062DVx6A + - teensy41 + + # STM32F0 + - malyan_M300 + - STM32F070CB_malyan + - STM32F070RB_malyan + + # STM32F1 + - chitu_f103 + - mks_robin + - mks_robin_nano_v1v2 + - PANDA_PI_V29 - STM32F103RC_btt - #- STM32F103RC_btt_USB + - STM32F103RC_fysetc - STM32F103RE_btt - STM32F103RE_btt_USB - STM32F103RE_creality - - STM32F401RC_creality - STM32F103VE_longer - - STM32F407VE_black - - BIGTREE_BTT002 - - BIGTREE_SKR_PRO - - BIGTREE_GTR_V1_0 - - mks_robin - - ARMED - - FYSETC_S6 - - STM32F070CB_malyan - - STM32F070RB_malyan - - malyan_M300 - - FLYF407ZG - - rumba32 - - LERDGEX - - LERDGEK - - mks_robin_nano_v1v2 - #- mks_robin_nano_v1v2_usbmod + #- mks_robin_mini #- mks_robin_nano_v1_3_f4_usbmod + #- mks_robin_nano_v1v2_usbmod + #- STM32F103CB_malyan + #- STM32F103RC_btt_USB + #- STM32F103RE + + # STM32F4 + - ARMED + - BIGTREE_BTT002 + - BIGTREE_GTR_V1_0 + - BIGTREE_SKR_PRO + - FLYF407ZG + - FYSETC_S6 + - LERDGEK + - LERDGEX + - mks_robin_pro2 + - Opulo_Lumen_REV3 + - rumba32 + - STM32F401RC_creality + - STM32F407VE_black + - I3DBEEZ9_V1 + + # STM32F7 - NUCLEO_F767ZI - REMRAM_V1 + + # STM32H7 - BTT_SKR_SE_BX - - chitu_f103 - - Opulo_Lumen_REV3 + - STM32H743VI_btt - # ESP32 environments - - mks_tinybee + # STM32F1 (Maple) + - jgaurora_a5s_a1_maple + - mks_robin_lite_maple + - mks_robin_pro_maple + - STM32F103RC_btt_USB_maple + - STM32F103RC_fysetc_maple + - STM32F103RC_meeb_maple + - STM32F103VE_longer_maple + - STM32F103VE_ZM3E4V2_USB_maple + #- mks_robin_maple + #- mks_robin_nano_v1v2_maple + #- STM32F103RC_btt_maple + #- STM32F103RE_creality_maple - # Put lengthy tests last + # STM32G0 + - STM32G0B1RE_btt + # HC32 + - HC32F460C_aquila_101 + + # LPC176x - Lengthy tests - LPC1768 - LPC1769 - # Non-working environment tests - #- at90usb1286_cdc - #- STM32F103CB_malyan - #- STM32F103RE - #- mks_robin_mini - steps: - name: Check out the PR - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Cache pip uses: actions/cache@v3 @@ -135,11 +165,11 @@ jobs: path: ~/.platformio key: ${{ runner.os }}-${{ hashFiles('**/lockfiles') }} - - name: Select Python 3.7 - uses: actions/setup-python@v3 + - name: Select Python 3.9 + uses: actions/setup-python@v4 with: - python-version: '3.7' # Version range or exact version of a Python version to use, using semvers version range syntax. - architecture: 'x64' # optional x64 or x86. Defaults to x64 if not specified + python-version: '3.9' + architecture: 'x64' - name: Install PlatformIO run: | diff --git a/.gitignore b/.gitignore index 09db344257..c7d47c607f 100755 --- a/.gitignore +++ b/.gitignore @@ -21,35 +21,21 @@ # Generated files _Version.h -bdf2u8g +bdf2u8g.exe +genpages.exe marlin_config.json mczip.h +language*.csv +out-csv/ +out-language/ *.gen *.sublime-workspace -# # OS -# applet/ .DS_Store -# -# Misc -# -*~ -*.orig -*.rej -*.bak -*.idea -*.i -*.ii -*.swp -tags - -# -# C++ -# -# Compiled Object files +# Compiled C++ Object files *.slo *.lo *.o @@ -80,10 +66,7 @@ tags *.out *.app -# -# C -# -# Object files +# Compiled C Object files *.o *.ko *.obj @@ -143,14 +126,16 @@ vc-fileutils.settings .vscode/* !.vscode/extensions.json -#Simulation +# Simulation files imgui.ini eeprom.dat spi_flash.bin fs.img -#cmake +# CMake +buildroot/share/cmake/* CMakeLists.txt +!buildroot/share/cmake/CMakeLists.txt src/CMakeLists.txt CMakeListsPrivate.txt build/ @@ -170,3 +155,16 @@ __pycache__ # IOLogger logs *_log.csv + +# Misc. +*~ +*.orig +*.rej +*.bak +*.idea +*.i +*.ii +*.swp +tags +*.logs +*.bak diff --git a/.vscode/extensions.json b/.vscode/extensions.json index f495d14f53..52fe2a0bdb 100644 --- a/.vscode/extensions.json +++ b/.vscode/extensions.json @@ -6,6 +6,7 @@ "platformio.platformio-ide" ], "unwantedRecommendations": [ + "ms-vscode-remote.remote-containers", "ms-vscode.cpptools-extension-pack" ] } diff --git a/Makefile b/Makefile index d0495dc7d8..11e908ef83 100644 --- a/Makefile +++ b/Makefile @@ -1,11 +1,17 @@ +SCRIPTS_DIR := buildroot/share/scripts +CONTAINER_RT_BIN := docker +CONTAINER_RT_OPTS := --rm -v $(PWD):/code -v platformio-cache:/root/.platformio +CONTAINER_IMAGE := marlin-dev + help: @echo "Tasks for local development:" + @echo "* format-pins: Reformat all pins files" @echo "* tests-single-ci: Run a single test from inside the CI" @echo "* tests-single-local: Run a single test locally" - @echo "* tests-single-local-docker: Run a single test locally, using docker-compose" + @echo "* tests-single-local-docker: Run a single test locally, using docker" @echo "* tests-all-local: Run all tests locally" - @echo "* tests-all-local-docker: Run all tests locally, using docker-compose" - @echo "* setup-local-docker: Setup local docker-compose" + @echo "* tests-all-local-docker: Run all tests locally, using docker" + @echo "* setup-local-docker: Build the local docker image" @echo "" @echo "Options for testing:" @echo " TEST_TARGET Set when running tests-single-*, to select the" @@ -22,7 +28,7 @@ help: tests-single-ci: export GIT_RESET_HARD=true - $(MAKE) tests-single-local TEST_TARGET=$(TEST_TARGET) + $(MAKE) tests-single-local TEST_TARGET=$(TEST_TARGET) PLATFORMIO_BUILD_FLAGS=-DGITHUB_ACTION .PHONY: tests-single-ci tests-single-local: @@ -34,19 +40,30 @@ tests-single-local: tests-single-local-docker: @if ! test -n "$(TEST_TARGET)" ; then echo "***ERROR*** Set TEST_TARGET= or use make tests-all-local-docker" ; return 1; fi - docker-compose run --rm marlin $(MAKE) tests-single-local TEST_TARGET=$(TEST_TARGET) VERBOSE_PLATFORMIO=$(VERBOSE_PLATFORMIO) GIT_RESET_HARD=$(GIT_RESET_HARD) ONLY_TEST="$(ONLY_TEST)" + @if ! $(CONTAINER_RT_BIN) images -q $(CONTAINER_IMAGE) > /dev/null ; then $(MAKE) setup-local-docker ; fi + $(CONTAINER_RT_BIN) run $(CONTAINER_RT_OPTS) $(CONTAINER_IMAGE) $(MAKE) tests-single-local TEST_TARGET=$(TEST_TARGET) VERBOSE_PLATFORMIO=$(VERBOSE_PLATFORMIO) GIT_RESET_HARD=$(GIT_RESET_HARD) ONLY_TEST="$(ONLY_TEST)" .PHONY: tests-single-local-docker tests-all-local: export PATH="./buildroot/bin/:./buildroot/tests/:${PATH}" \ && export VERBOSE_PLATFORMIO=$(VERBOSE_PLATFORMIO) \ - && for TEST_TARGET in $$(./get_test_targets.py) ; do echo "Running tests for $$TEST_TARGET" ; run_tests . $$TEST_TARGET ; done + && for TEST_TARGET in $$($(SCRIPTS_DIR)/get_test_targets.py) ; do echo "Running tests for $$TEST_TARGET" ; run_tests . $$TEST_TARGET ; done .PHONY: tests-all-local tests-all-local-docker: - docker-compose run --rm marlin $(MAKE) tests-all-local VERBOSE_PLATFORMIO=$(VERBOSE_PLATFORMIO) GIT_RESET_HARD=$(GIT_RESET_HARD) + @if ! $(CONTAINER_RT_BIN) images -q $(CONTAINER_IMAGE) > /dev/null ; then $(MAKE) setup-local-docker ; fi + $(CONTAINER_RT_BIN) run $(CONTAINER_RT_OPTS) $(CONTAINER_IMAGE) $(MAKE) tests-all-local VERBOSE_PLATFORMIO=$(VERBOSE_PLATFORMIO) GIT_RESET_HARD=$(GIT_RESET_HARD) .PHONY: tests-all-local-docker setup-local-docker: - docker-compose build + $(CONTAINER_RT_BIN) build -t $(CONTAINER_IMAGE) -f docker/Dockerfile . .PHONY: setup-local-docker + +PINS := $(shell find Marlin/src/pins -mindepth 2 -name '*.h') + +.PHONY: $(PINS) + +$(PINS): %: + @echo "Formatting $@" && node buildroot/share/scripts/pinsformat.js $@ + +format-pins: $(PINS) diff --git a/Marlin/Configuration.h b/Marlin/Configuration.h index 1f7f1a94f7..d1216812a5 100644 --- a/Marlin/Configuration.h +++ b/Marlin/Configuration.h @@ -48,7 +48,7 @@ * Advanced settings can be found in Configuration_adv.h * */ -#define CONFIGURATION_H_VERSION 02010200 +#define CONFIGURATION_H_VERSION 02010300 //=========================================================================== //============================= Getting Started ============================= @@ -59,12 +59,13 @@ * * Example Configs: https://github.com/MarlinFirmware/Configurations/branches/all * - * Průša Calculator: https://blog.prusaprinters.org/calculator_3416/ + * Průša Calculator: https://blog.prusa3d.com/calculator_3416/ * * Calibration Guides: https://reprap.org/wiki/Calibration * https://reprap.org/wiki/Triffid_Hunter%27s_Calibration_Guide - * https://sites.google.com/site/repraplogphase/calibration-of-your-reprap + * https://web.archive.org/web/20220907014303/https://sites.google.com/site/repraplogphase/calibration-of-your-reprap * https://youtu.be/wAL9d7FgInk + * https://teachingtechyt.github.io/calibration.html * * Calibration Objects: https://www.thingiverse.com/thing:5573 * https://www.thingiverse.com/thing:1278865 @@ -76,26 +77,6 @@ #define STRING_CONFIG_H_AUTHOR "Lulzbot" // Who made the changes. #define CUSTOM_VERSION_FILE Version.h // Path from the root directory (no quotes) -/** - * *** VENDORS PLEASE READ *** - * - * Marlin allows you to add a custom boot image for Graphical LCDs. - * With this option Marlin will first show your custom screen followed - * by the standard Marlin logo with version number and web URL. - * - * We encourage you to take advantage of this new feature and we also - * respectfully request that you retain the unmodified Marlin boot screen. - */ - -// Show the Marlin bootscreen on startup. ** ENABLE FOR PRODUCTION ** -#define SHOW_BOOTSCREEN - -// Show the bitmap in Marlin/_Bootscreen.h on startup. -#define SHOW_CUSTOM_BOOTSCREEN - -// Show the bitmap in Marlin/_Statusscreen.h on the status screen. -//#define CUSTOM_STATUS_SCREEN_IMAGE - // @section machine // Choose the name from boards.h that matches your setup @@ -308,24 +289,6 @@ //#define SINGLENOZZLE_STANDBY_FAN #endif -// @section multi-material - -/** - * Multi-Material Unit - * Set to one of these predefined models: - * - * PRUSA_MMU1 : Průša MMU1 (The "multiplexer" version) - * PRUSA_MMU2 : Průša MMU2 - * PRUSA_MMU2S : Průša MMU2S (Requires MK3S extruder with motion sensor, EXTRUDERS = 5) - * EXTENDABLE_EMU_MMU2 : MMU with configurable number of filaments (ERCF, SMuFF or similar with Průša MMU2 compatible firmware) - * EXTENDABLE_EMU_MMU2S : MMUS with configurable number of filaments (ERCF, SMuFF or similar with Průša MMU2 compatible firmware) - * - * Requires NOZZLE_PARK_FEATURE to park print head in case MMU unit fails. - * See additional options in Configuration_adv.h. - * :["PRUSA_MMU1", "PRUSA_MMU2", "PRUSA_MMU2S", "EXTENDABLE_EMU_MMU2", "EXTENDABLE_EMU_MMU2S"] - */ -//#define MMU_MODEL PRUSA_MMU2 - // A dual extruder that uses a single stepper motor //#define SWITCHING_EXTRUDER #if ENABLED(SWITCHING_EXTRUDER) @@ -336,17 +299,27 @@ #endif #endif -// A dual-nozzle that uses a servomotor to raise/lower one (or both) of the nozzles +// Switch extruders by bumping the toolhead. Requires EVENT_GCODE_TOOLCHANGE_#. +//#define MECHANICAL_SWITCHING_EXTRUDER + +/** + * A dual-nozzle that uses a servomotor to raise/lower one (or both) of the nozzles. + * Can be combined with SWITCHING_EXTRUDER. + */ #if ENABLED(TazPro) #define SWITCHING_NOZZLE #endif #if ENABLED(SWITCHING_NOZZLE) #define SWITCHING_NOZZLE_SERVO_NR 0 #define SWITCHING_NOZZLE_E1_SERVO_NR 1 // If two servos are used, the index of the second - #define SWITCHING_NOZZLE_SERVO_ANGLES { 55, 120 } // Angles for E0, E1 (single servo) or lowered/raised (dual servo) + #define SWITCHING_NOZZLE_SERVO_ANGLES { 55, 120 } // A pair of angles for { E0, E1 }. + // For Dual Servo use two pairs: { { lower, raise }, { lower, raise } } #define SWITCHING_NOZZLE_SERVO_DWELL 2500 // Dwell time to wait for servo to make physical move #endif +// Switch nozzles by bumping the toolhead. Requires EVENT_GCODE_TOOLCHANGE_#. +//#define MECHANICAL_SWITCHING_NOZZLE + /** * Two separate X-carriages with extruders that connect to a moving part * via a solenoid docking mechanism. Requires SOL1_PIN and SOL2_PIN. @@ -363,7 +336,7 @@ */ //#define MAGNETIC_PARKING_EXTRUDER -#if EITHER(PARKING_EXTRUDER, MAGNETIC_PARKING_EXTRUDER) +#if ANY(PARKING_EXTRUDER, MAGNETIC_PARKING_EXTRUDER) #define PARKING_EXTRUDER_PARKING_X { -78, 184 } // X positions for parking the extruders #define PARKING_EXTRUDER_GRAB_DISTANCE 1 // (mm) Distance to move beyond the parking point to grab the extruder @@ -461,6 +434,24 @@ #define HOTEND_OFFSET_Y {0.0, 0.095} // <-- changed: (mm) relative Y-offset for each nozzle #define HOTEND_OFFSET_Z {0.0, 0.005} // <-- changed: (mm) relative Z-offset for each nozzle +// @section multi-material + +/** + * Multi-Material Unit + * Set to one of these predefined models: + * + * PRUSA_MMU1 : Průša MMU1 (The "multiplexer" version) + * PRUSA_MMU2 : Průša MMU2 + * PRUSA_MMU2S : Průša MMU2S (Requires MK3S extruder with motion sensor, EXTRUDERS = 5) + * EXTENDABLE_EMU_MMU2 : MMU with configurable number of filaments (ERCF, SMuFF or similar with Průša MMU2 compatible firmware) + * EXTENDABLE_EMU_MMU2S : MMUS with configurable number of filaments (ERCF, SMuFF or similar with Průša MMU2 compatible firmware) + * + * Requires NOZZLE_PARK_FEATURE to park print head in case MMU unit fails. + * See additional options in Configuration_adv.h. + * :["PRUSA_MMU1", "PRUSA_MMU2", "PRUSA_MMU2S", "EXTENDABLE_EMU_MMU2", "EXTENDABLE_EMU_MMU2S"] + */ +//#define MMU_MODEL PRUSA_MMU2 + // @section psu control /** @@ -490,15 +481,16 @@ //#define AUTO_POWER_CONTROL // Enable automatic control of the PS_ON pin #if ENABLED(AUTO_POWER_CONTROL) - #define AUTO_POWER_FANS // Turn on PSU if fans need power - #define AUTO_POWER_E_FANS - #define AUTO_POWER_CONTROLLERFAN - #define AUTO_POWER_CHAMBER_FAN - #define AUTO_POWER_COOLER_FAN + #define AUTO_POWER_FANS // Turn on PSU for fans + #define AUTO_POWER_E_FANS // Turn on PSU for E Fans + #define AUTO_POWER_CONTROLLERFAN // Turn on PSU for Controller Fan + #define AUTO_POWER_CHAMBER_FAN // Turn on PSU for Chamber Fan + #define AUTO_POWER_COOLER_FAN // Turn on PSU for Cooler Fan + #define AUTO_POWER_SPINDLE_LASER // Turn on PSU for Spindle/Laser #define POWER_TIMEOUT 30 // (s) Turn off power if the machine is idle for this duration //#define POWER_OFF_DELAY 60 // (s) Delay of poweroff after M81 command. Useful to let fans run for extra time. #endif - #if EITHER(AUTO_POWER_CONTROL, POWER_OFF_WAIT_FOR_COOLDOWN) + #if ANY(AUTO_POWER_CONTROL, POWER_OFF_WAIT_FOR_COOLDOWN) //#define AUTO_POWER_E_TEMP 50 // (°C) PSU on if any extruder is over this temperature //#define AUTO_POWER_CHAMBER_TEMP 30 // (°C) PSU on if the chamber is over this temperature //#define AUTO_POWER_COOLER_TEMP 26 // (°C) PSU on if the cooler is over this temperature @@ -511,78 +503,70 @@ // @section temperature /** - * --NORMAL IS 4.7kΩ PULLUP!-- 1kΩ pullup can be used on hotend sensor, using correct resistor and table + * Temperature Sensors: * - * Temperature sensors available: - * - * SPI RTD/Thermocouple Boards - IMPORTANT: Read the NOTE below! - * ------- - * -5 : MAX31865 with Pt100/Pt1000, 2, 3, or 4-wire (only for sensors 0-1) - * NOTE: You must uncomment/set the MAX31865_*_OHMS_n defines below. - * -3 : MAX31855 with Thermocouple, -200°C to +700°C (only for sensors 0-1) - * -2 : MAX6675 with Thermocouple, 0°C to +700°C (only for sensors 0-1) - * - * NOTE: Ensure TEMP_n_CS_PIN is set in your pins file for each TEMP_SENSOR_n using an SPI Thermocouple. By default, - * Hardware SPI on the default serial bus is used. If you have also set TEMP_n_SCK_PIN and TEMP_n_MISO_PIN, - * Software SPI will be used on those ports instead. You can force Hardware SPI on the default bus in the - * Configuration_adv.h file. At this time, separate Hardware SPI buses for sensors are not supported. - * - * Analog Themocouple Boards - * ------- - * -4 : AD8495 with Thermocouple - * -1 : AD595 with Thermocouple + * NORMAL IS 4.7kΩ PULLUP! Hotend sensors can use 1kΩ pullup with correct resistor and table. * + * ================================================================ * Analog Thermistors - 4.7kΩ pullup - Normal - * ------- - * 1 : 100kΩ EPCOS - Best choice for EPCOS thermistors - * 331 : 100kΩ Same as #1, but 3.3V scaled for MEGA - * 332 : 100kΩ Same as #1, but 3.3V scaled for DUE - * 2 : 200kΩ ATC Semitec 204GT-2 - * 202 : 200kΩ Copymaster 3D - * 3 : ???Ω Mendel-parts thermistor - * 4 : 10kΩ Generic Thermistor !! DO NOT use for a hotend - it gives bad resolution at high temp. !! - * 5 : 100kΩ ATC Semitec 104GT-2/104NT-4-R025H42G - Used in ParCan, J-Head, and E3D, SliceEngineering 300°C - * 501 : 100kΩ Zonestar - Tronxy X3A - * 502 : 100kΩ Zonestar - used by hot bed in Zonestar Průša P802M - * 503 : 100kΩ Zonestar (Z8XM2) Heated Bed thermistor - * 504 : 100kΩ Zonestar P802QR2 (Part# QWG-104F-B3950) Hotend Thermistor - * 505 : 100kΩ Zonestar P802QR2 (Part# QWG-104F-3950) Bed Thermistor - * 512 : 100kΩ RPW-Ultra hotend - * 6 : 100kΩ EPCOS - Not as accurate as table #1 (created using a fluke thermocouple) - * 7 : 100kΩ Honeywell 135-104LAG-J01 - * 71 : 100kΩ Honeywell 135-104LAF-J01 - * 8 : 100kΩ Vishay 0603 SMD NTCS0603E3104FXT - * 9 : 100kΩ GE Sensing AL03006-58.2K-97-G1 - * 10 : 100kΩ RS PRO 198-961 - * 11 : 100kΩ Keenovo AC silicone mats, most Wanhao i3 machines - beta 3950, 1% - * 12 : 100kΩ Vishay 0603 SMD NTCS0603E3104FXT (#8) - calibrated for Makibox hot bed - * 13 : 100kΩ Hisens up to 300°C - for "Simple ONE" & "All In ONE" hotend - beta 3950, 1% - * 15 : 100kΩ Calibrated for JGAurora A5 hotend - * 18 : 200kΩ ATC Semitec 204GT-2 Dagoma.Fr - MKS_Base_DKU001327 - * 22 : 100kΩ GTM32 Pro vB - hotend - 4.7kΩ pullup to 3.3V and 220Ω to analog input - * 23 : 100kΩ GTM32 Pro vB - bed - 4.7kΩ pullup to 3.3v and 220Ω to analog input - * 30 : 100kΩ Kis3d Silicone heating mat 200W/300W with 6mm precision cast plate (EN AW 5083) NTC100K - beta 3950 - * 60 : 100kΩ Maker's Tool Works Kapton Bed Thermistor - beta 3950 - * 61 : 100kΩ Formbot/Vivedino 350°C Thermistor - beta 3950 - * 66 : 4.7MΩ Dyze Design / Trianglelab T-D500 500°C High Temperature Thermistor - * 67 : 500kΩ SliceEngineering 450°C Thermistor - * 68 : PT100 amplifier board from Dyze Design - * 70 : 100kΩ bq Hephestos 2 - * 75 : 100kΩ Generic Silicon Heat Pad with NTC100K MGB18-104F39050L32 - * 2000 : 100kΩ Ultimachine Rambo TDK NTCG104LH104KT1 NTC100K motherboard Thermistor + * ================================================================ + * 1 : 100kΩ EPCOS - Best choice for EPCOS thermistors + * 331 : 100kΩ Same as #1, but 3.3V scaled for MEGA + * 332 : 100kΩ Same as #1, but 3.3V scaled for DUE + * 2 : 200kΩ ATC Semitec 204GT-2 + * 202 : 200kΩ Copymaster 3D + * 3 : ???Ω Mendel-parts thermistor + * 4 : 10kΩ Generic Thermistor !! DO NOT use for a hotend - it gives bad resolution at high temp. !! + * 5 : 100kΩ ATC Semitec 104GT-2/104NT-4-R025H42G - Used in ParCan, J-Head, and E3D, SliceEngineering 300°C + * 501 : 100kΩ Zonestar - Tronxy X3A + * 502 : 100kΩ Zonestar - used by hot bed in Zonestar Průša P802M + * 503 : 100kΩ Zonestar (Z8XM2) Heated Bed thermistor + * 504 : 100kΩ Zonestar P802QR2 (Part# QWG-104F-B3950) Hotend Thermistor + * 505 : 100kΩ Zonestar P802QR2 (Part# QWG-104F-3950) Bed Thermistor + * 512 : 100kΩ RPW-Ultra hotend + * 6 : 100kΩ EPCOS - Not as accurate as table #1 (created using a fluke thermocouple) + * 7 : 100kΩ Honeywell 135-104LAG-J01 + * 71 : 100kΩ Honeywell 135-104LAF-J01 + * 8 : 100kΩ Vishay 0603 SMD NTCS0603E3104FXT + * 9 : 100kΩ GE Sensing AL03006-58.2K-97-G1 + * 10 : 100kΩ RS PRO 198-961 + * 11 : 100kΩ Keenovo AC silicone mats, most Wanhao i3 machines - beta 3950, 1% + * 12 : 100kΩ Vishay 0603 SMD NTCS0603E3104FXT (#8) - calibrated for Makibox hot bed + * 13 : 100kΩ Hisens up to 300°C - for "Simple ONE" & "All In ONE" hotend - beta 3950, 1% + * 14 : 100kΩ (R25), 4092K (beta25), 4.7kΩ pull-up, bed thermistor as used in Ender-5 S1 + * 15 : 100kΩ Calibrated for JGAurora A5 hotend + * 17 : 100kΩ Dagoma NTC white thermistor + * 18 : 200kΩ ATC Semitec 204GT-2 Dagoma.Fr - MKS_Base_DKU001327 + * 22 : 100kΩ GTM32 Pro vB - hotend - 4.7kΩ pullup to 3.3V and 220Ω to analog input + * 23 : 100kΩ GTM32 Pro vB - bed - 4.7kΩ pullup to 3.3v and 220Ω to analog input + * 30 : 100kΩ Kis3d Silicone heating mat 200W/300W with 6mm precision cast plate (EN AW 5083) NTC100K - beta 3950 + * 60 : 100kΩ Maker's Tool Works Kapton Bed Thermistor - beta 3950 + * 61 : 100kΩ Formbot/Vivedino 350°C Thermistor - beta 3950 + * 66 : 4.7MΩ Dyze Design / Trianglelab T-D500 500°C High Temperature Thermistor + * 67 : 500kΩ SliceEngineering 450°C Thermistor + * 68 : PT100 Smplifier board from Dyze Design + * 70 : 100kΩ bq Hephestos 2 + * 75 : 100kΩ Generic Silicon Heat Pad with NTC100K MGB18-104F39050L32 + * 666 : 200kΩ Einstart S custom thermistor with 10k pullup. + * 2000 : 100kΩ Ultimachine Rambo TDK NTCG104LH104KT1 NTC100K motherboard Thermistor * - * Analog Thermistors - 1kΩ pullup - Atypical, and requires changing out the 4.7kΩ pullup for 1kΩ. - * ------- (but gives greater accuracy and more stable PID) - * 51 : 100kΩ EPCOS (1kΩ pullup) - * 52 : 200kΩ ATC Semitec 204GT-2 (1kΩ pullup) - * 55 : 100kΩ ATC Semitec 104GT-2 - Used in ParCan & J-Head (1kΩ pullup) + * ================================================================ + * Analog Thermistors - 1kΩ pullup + * Atypical, and requires changing out the 4.7kΩ pullup for 1kΩ. + * (but gives greater accuracy and more stable PID) + * ================================================================ + * 51 : 100kΩ EPCOS (1kΩ pullup) + * 52 : 200kΩ ATC Semitec 204GT-2 (1kΩ pullup) + * 55 : 100kΩ ATC Semitec 104GT-2 - Used in ParCan & J-Head (1kΩ pullup) * + * ================================================================ * Analog Thermistors - 10kΩ pullup - Atypical - * ------- - * 99 : 100kΩ Found on some Wanhao i3 machines with a 10kΩ pull-up resistor + * ================================================================ + * 99 : 100kΩ Found on some Wanhao i3 machines with a 10kΩ pull-up resistor * + * ================================================================ * Analog RTDs (Pt100/Pt1000) - * ------- + * ================================================================ * 110 : Pt100 with 1kΩ pullup (atypical) * 147 : Pt100 with 4.7kΩ pullup * 1010 : Pt1000 with 1kΩ pullup (atypical) @@ -594,15 +578,39 @@ * NOTE: ADC pins are not 5V tolerant. Not recommended because it's possible to damage the CPU by going over 500°C. * 201 : Pt100 with circuit in Overlord, similar to Ultimainboard V2.x * + * ================================================================ + * SPI RTD/Thermocouple Boards + * ================================================================ + * -5 : MAX31865 with Pt100/Pt1000, 2, 3, or 4-wire (only for sensors 0-2 and bed) + * NOTE: You must uncomment/set the MAX31865_*_OHMS_n defines below. + * -3 : MAX31855 with Thermocouple, -200°C to +700°C (only for sensors 0-2 and bed) + * -2 : MAX6675 with Thermocouple, 0°C to +700°C (only for sensors 0-2 and bed) + * + * NOTE: Ensure TEMP_n_CS_PIN is set in your pins file for each TEMP_SENSOR_n using an SPI Thermocouple. By default, + * Hardware SPI on the default serial bus is used. If you have also set TEMP_n_SCK_PIN and TEMP_n_MISO_PIN, + * Software SPI will be used on those ports instead. You can force Hardware SPI on the default bus in the + * Configuration_adv.h file. At this time, separate Hardware SPI buses for sensors are not supported. + * + * ================================================================ + * Analog Thermocouple Boards + * ================================================================ + * -4 : AD8495 with Thermocouple + * -1 : AD595 with Thermocouple + * + * ================================================================ + * SoC internal sensor + * ================================================================ + * 100 : SoC internal sensor + * + * ================================================================ * Custom/Dummy/Other Thermal Sensors - * ------ + * ================================================================ * 0 : not used * 1000 : Custom - Specify parameters in Configuration_adv.h * * !!! Use these for Testing or Development purposes. NEVER for production machine. !!! * 998 : Dummy Table that ALWAYS reads 25°C or the temperature defined below. * 999 : Dummy Table that ALWAYS reads 100°C or the temperature defined below. - * */ #define TEMP_SENSOR_0 5 #if ENABLED(TazPro) @@ -619,6 +627,7 @@ #define TEMP_SENSOR_CHAMBER 0 #define TEMP_SENSOR_COOLER 0 #define TEMP_SENSOR_BOARD 0 +#define TEMP_SENSOR_SOC 0 #define TEMP_SENSOR_REDUNDANT 0 // Dummy thermistor constant temperature readings, for use with 998 and 999 @@ -716,14 +725,18 @@ // @section hotend temp -// Enable PIDTEMP for PID control or MPCTEMP for Predictive Model. -// temperature control. Disable both for bang-bang heating. -#define PIDTEMP // See the PID Tuning Guide at https://reprap.org/wiki/PID_Tuning -//#define MPCTEMP // ** EXPERIMENTAL ** +/** + * Temperature Control + * + * (NONE) : Bang-bang heating + * PIDTEMP : PID temperature control (~4.1K) + * MPCTEMP : Predictive Model temperature control. (~1.8K without auto-tune) + */ +#define PIDTEMP // See the PID Tuning Guide at https://reprap.org/wiki/PID_Tuning +//#define MPCTEMP // ** EXPERIMENTAL ** See https://marlinfw.org/docs/features/model_predictive_control.html -#define BANG_MAX 255 // Limits current to nozzle while in bang-bang mode; 255=full current -#define PID_MAX BANG_MAX // Limits current to nozzle while PID is active (see PID_FUNCTIONAL_RANGE below); 255=full current -#define PID_K1 0.95 // Smoothing factor within any PID loop +#define PID_MAX 255 // Limit hotend current while PID is active (see PID_FUNCTIONAL_RANGE below); 255=full current +#define PID_K1 0.95 // Smoothing factor within any PID loop #if ENABLED(PIDTEMP) //#define PID_DEBUG // Print PID debug data to the serial port. Use 'M303 D' to toggle activation. @@ -747,21 +760,24 @@ #define DEFAULT_Kd 61.93 #endif #endif +#else + #define BANG_MAX 255 // Limit hotend current while in bang-bang mode; 255=full current #endif /** * Model Predictive Control for hotend * - * Use a physical model of the hotend to control temperature. When configured correctly - * this gives better responsiveness and stability than PID and it also removes the need - * for PID_EXTRUSION_SCALING and PID_FAN_SCALING. Use M306 T to autotune the model. + * Use a physical model of the hotend to control temperature. When configured correctly this gives + * better responsiveness and stability than PID and removes the need for PID_EXTRUSION_SCALING + * and PID_FAN_SCALING. Enable MPC_AUTOTUNE and use M306 T to autotune the model. * @section mpctemp */ #if ENABLED(MPCTEMP) - //#define MPC_EDIT_MENU // Add MPC editing to the "Advanced Settings" menu. (~1300 bytes of flash) + #define MPC_AUTOTUNE // Include a method to do MPC auto-tuning (~6.3K bytes of flash) + //#define MPC_EDIT_MENU // Add MPC editing to the "Advanced Settings" menu. (~1.3K bytes of flash) //#define MPC_AUTOTUNE_MENU // Add MPC auto-tuning to the "Advanced Settings" menu. (~350 bytes of flash) - #define MPC_MAX BANG_MAX // (0..255) Current to nozzle while MPC is active. + #define MPC_MAX 255 // (0..255) Current to nozzle while MPC is active. #define MPC_HEATER_POWER { 40.0f } // (W) Heat cartridge powers. #define MPC_INCLUDE_FAN // Model the fan speed? @@ -780,8 +796,12 @@ //#define MPC_FAN_0_ACTIVE_HOTEND #endif + // Filament Heat Capacity (joules/kelvin/mm) + // Set at runtime with M306 H #define FILAMENT_HEAT_CAPACITY_PERMM { 5.6e-3f } // 0.0056 J/K/mm for 1.75mm PLA (0.0149 J/K/mm for 2.85mm PLA). - //#define FILAMENT_HEAT_CAPACITY_PERMM { 3.6e-3f } // 0.0036 J/K/mm for 1.75mm PETG (0.0094 J/K/mm for 2.85mm PETG). + // 0.0036 J/K/mm for 1.75mm PETG (0.0094 J/K/mm for 2.85mm PETG). + // 0.00515 J/K/mm for 1.75mm ABS (0.0137 J/K/mm for 2.85mm ABS). + // 0.00522 J/K/mm for 1.75mm Nylon (0.0138 J/K/mm for 2.85mm Nylon). // Advanced options #define MPC_SMOOTHING_FACTOR 0.5f // (0.0...1.0) Noisy temperature sensors may need a lower value for stabilization. @@ -796,23 +816,7 @@ //====================== PID > Bed Temperature Control ====================== //=========================================================================== -/** - * PID Bed Heating - * - * If this option is enabled set PID constants below. - * If this option is disabled, bang-bang will be used and BED_LIMIT_SWITCHING will enable hysteresis. - * - * The PID frequency will be the same as the extruder PWM. - * If PID_dT is the default, and correct for the hardware/configuration, that means 7.689Hz, - * which is fine for driving a square wave into a resistive load and does not significantly - * impact FET heating. This also works fine on a Fotek SSR-10DA Solid State Relay into a 250W - * heater. If your configuration is significantly different than this and you don't understand - * the issues involved, don't use bed PID until someone else verifies that your hardware works. - * @section bed temp - */ -#define PIDTEMPBED - -//#define BED_LIMIT_SWITCHING +// @section bed temp /** * Max Bed Power @@ -826,6 +830,20 @@ #define MAX_BED_POWER 255 // limits duty cycle to bed; 255=full current #endif +/** + * PID Bed Heating + * + * The PID frequency will be the same as the extruder PWM. + * If PID_dT is the default, and correct for the hardware/configuration, that means 7.689Hz, + * which is fine for driving a square wave into a resistive load and does not significantly + * impact FET heating. This also works fine on a Fotek SSR-10DA Solid State Relay into a 250W + * heater. If your configuration is significantly different than this and you don't understand + * the issues involved, don't use bed PID until someone else verifies that your hardware works. + * + * With this option disabled, bang-bang will be used. BED_LIMIT_SWITCHING enables hysteresis. + */ +#define PIDTEMPBED + #if ENABLED(PIDTEMPBED) //#define MIN_BED_POWER 0 //#define PID_BED_DEBUG // Print Bed PID debug data to the serial port. @@ -861,7 +879,12 @@ //#define DEFAULT_bedKd 1675.16 // FIND YOUR OWN: "M303 E-1 C8 S90" to run autotune on the bed at 90 degreesC for 8 cycles. -#endif // PIDTEMPBED +#else + //#define BED_LIMIT_SWITCHING // Keep the bed temperature within BED_HYSTERESIS of the target +#endif + +// Add 'M190 R T' for more gradual M190 R bed cooling. +//#define BED_ANNEALING_GCODE //=========================================================================== //==================== PID > Chamber Temperature Control ==================== @@ -973,8 +996,16 @@ //#define COREYX //#define COREZX //#define COREZY -//#define MARKFORGED_XY // MarkForged. See https://reprap.org/forum/read.php?152,504042 + +// +// MarkForged Kinematics +// See https://reprap.org/forum/read.php?152,504042 +// +//#define MARKFORGED_XY //#define MARKFORGED_YX +#if ANY(MARKFORGED_XY, MARKFORGED_YX) + //#define MARKFORGED_INVERSE // Enable for an inverted Markforged kinematics belt path +#endif // Enable for a belt style printer with endless "Z" motion //#define BELTPRINTER @@ -982,8 +1013,9 @@ // Enable for Polargraph Kinematics //#define POLARGRAPH #if ENABLED(POLARGRAPH) - #define POLARGRAPH_MAX_BELT_LEN 1035.0 - #define DEFAULT_SEGMENTS_PER_SECOND 5 + #define POLARGRAPH_MAX_BELT_LEN 1035.0 // (mm) Belt length at full extension. Override with M665 H. + #define DEFAULT_SEGMENTS_PER_SECOND 5 // Move segmentation based on duration + #define PEN_UP_DOWN_MENU // Add "Pen Up" and "Pen Down" to the MarlinUI menu #endif // @section delta @@ -1013,15 +1045,13 @@ #define DELTA_CALIBRATION_DEFAULT_POINTS 4 #endif - // NOTE: All values for DELTA_* values MUST be floating point, so always have a decimal point in them - - #if EITHER(DELTA_AUTO_CALIBRATION, DELTA_CALIBRATION_MENU) + #if ANY(DELTA_AUTO_CALIBRATION, DELTA_CALIBRATION_MENU) // Step size for paper-test probing #define PROBE_MANUALLY_STEP 0.05 // (mm) #endif // Print surface diameter/2 minus unreachable space (avoid collisions with vertical towers). - #define DELTA_PRINTABLE_RADIUS 140.0 // (mm) + #define PRINTABLE_RADIUS 140.0 // (mm) // Maximum reachable area #define DELTA_MAX_RADIUS 140.0 // (mm) @@ -1032,7 +1062,7 @@ // Distance between bed and nozzle Z home position #define DELTA_HEIGHT 250.00 // (mm) Get this value from G33 auto calibrate - #define DELTA_ENDSTOP_ADJ { 0.0, 0.0, 0.0 } // Get these values from G33 auto calibrate + #define DELTA_ENDSTOP_ADJ { 0.0, 0.0, 0.0 } // (mm) Get these values from G33 auto calibrate // Horizontal distance bridged by diagonal push rods when effector is centered. #define DELTA_RADIUS 124.0 // (mm) Get this value from G33 auto calibrate @@ -1040,11 +1070,11 @@ // Trim adjustments for individual towers // tower angle corrections for X and Y tower / rotate XYZ so Z tower angle = 0 // measured in degrees anticlockwise looking from above the printer - #define DELTA_TOWER_ANGLE_TRIM { 0.0, 0.0, 0.0 } // Get these values from G33 auto calibrate + #define DELTA_TOWER_ANGLE_TRIM { 0.0, 0.0, 0.0 } // (mm) Get these values from G33 auto calibrate - // Delta radius and diagonal rod adjustments (mm) - //#define DELTA_RADIUS_TRIM_TOWER { 0.0, 0.0, 0.0 } - //#define DELTA_DIAGONAL_ROD_TRIM_TOWER { 0.0, 0.0, 0.0 } + // Delta radius and diagonal rod adjustments + //#define DELTA_RADIUS_TRIM_TOWER { 0.0, 0.0, 0.0 } // (mm) + //#define DELTA_DIAGONAL_ROD_TRIM_TOWER { 0.0, 0.0, 0.0 } // (mm) #endif // @section scara @@ -1059,7 +1089,7 @@ */ //#define MORGAN_SCARA //#define MP_SCARA -#if EITHER(MORGAN_SCARA, MP_SCARA) +#if ANY(MORGAN_SCARA, MP_SCARA) // If movement is choppy try lowering this value #define DEFAULT_SEGMENTS_PER_SECOND 200 @@ -1075,13 +1105,13 @@ #if ENABLED(MORGAN_SCARA) //#define DEBUG_SCARA_KINEMATICS - #define SCARA_FEEDRATE_SCALING // Convert XY feedrate from mm/s to degrees/s on the fly + #define FEEDRATE_SCALING // Convert XY feedrate from mm/s to degrees/s on the fly // Radius around the center where the arm cannot reach #define MIDDLE_DEAD_ZONE_R 0 // (mm) - #define THETA_HOMING_OFFSET 0 // Calculated from Calibration Guide and M360 / M114. See http://reprap.harleystudio.co.za/?page_id=1073 - #define PSI_HOMING_OFFSET 0 // Calculated from Calibration Guide and M364 / M114. See http://reprap.harleystudio.co.za/?page_id=1073 + #define THETA_HOMING_OFFSET 0 // Calculated from Calibration Guide and M360 / M114. See https://www.morgan3dp.com/morgan-calibration-guide/ + #define PSI_HOMING_OFFSET 0 // Calculated from Calibration Guide and M364 / M114. See https://www.morgan3dp.com/morgan-calibration-guide/ #elif ENABLED(MP_SCARA) @@ -1110,16 +1140,69 @@ #define TPARA_OFFSET_Y 0 // (mm) #define TPARA_OFFSET_Z 0 // (mm) - #define SCARA_FEEDRATE_SCALING // Convert XY feedrate from mm/s to degrees/s on the fly + #define FEEDRATE_SCALING // Convert XY feedrate from mm/s to degrees/s on the fly // Radius around the center where the arm cannot reach #define MIDDLE_DEAD_ZONE_R 0 // (mm) - // Calculated from Calibration Guide and M360 / M114. See http://reprap.harleystudio.co.za/?page_id=1073 + // Calculated from Calibration Guide and M360 / M114. See https://www.morgan3dp.com/morgan-calibration-guide/ #define THETA_HOMING_OFFSET 0 #define PSI_HOMING_OFFSET 0 #endif +// @section polar + +/** + * POLAR Kinematics + * developed by Kadir ilkimen for PolarBear CNC and babyBear + * https://github.com/kadirilkimen/Polar-Bear-Cnc-Machine + * https://github.com/kadirilkimen/babyBear-3D-printer + * + * A polar machine can have different configurations. + * This kinematics is only compatible with the following configuration: + * X : Independent linear + * Y or B : Polar + * Z : Independent linear + * + * For example, PolarBear has CoreXZ plus Polar Y or B. + * + * Motion problem for Polar axis near center / origin: + * + * 3D printing: + * Movements very close to the center of the polar axis take more time than others. + * This brief delay results in more material deposition due to the pressure in the nozzle. + * + * Current Kinematics and feedrate scaling deals with this by making the movement as fast + * as possible. It works for slow movements but doesn't work well with fast ones. A more + * complicated extrusion compensation must be implemented. + * + * Ideally, it should estimate that a long rotation near the center is ahead and will cause + * unwanted deposition. Therefore it can compensate the extrusion beforehand. + * + * Laser cutting: + * Same thing would be a problem for laser engraving too. As it spends time rotating at the + * center point, more likely it will burn more material than it should. Therefore similar + * compensation would be implemented for laser-cutting operations. + * + * Milling: + * This shouldn't be a problem for cutting/milling operations. + */ +//#define POLAR +#if ENABLED(POLAR) + #define DEFAULT_SEGMENTS_PER_SECOND 180 // If movement is choppy try lowering this value + #define PRINTABLE_RADIUS 82.0f // (mm) Maximum travel of X axis + + // Movements fall inside POLAR_FAST_RADIUS are assigned the highest possible feedrate + // to compensate unwanted deposition related to the near-origin motion problem. + #define POLAR_FAST_RADIUS 3.0f // (mm) + + // Radius which is unreachable by the tool. + // Needed if the tool is not perfectly aligned to the center of the polar axis. + #define POLAR_CENTER_OFFSET 0.0f // (mm) + + #define FEEDRATE_SCALING // Convert XY feedrate from mm/s to degrees/s on the fly +#endif + // @section machine // Articulated robot (arm). Joints are directly mapped to axes with no kinematics. @@ -1135,30 +1218,6 @@ // @section endstops -// Specify here all the endstop connectors that are connected to any endstop or probe. -// Almost all printers will be using one per axis. Probes will use one or more of the -// extra connectors. Leave undefined any used for non-endstop and non-probe purposes. -#define USE_XMIN_PLUG -#if DISABLED(MiniV2, TazPro) - #define USE_YMIN_PLUG -#endif -#define USE_ZMIN_PLUG -//#define USE_IMIN_PLUG -//#define USE_JMIN_PLUG -//#define USE_KMIN_PLUG -//#define USE_UMIN_PLUG -//#define USE_VMIN_PLUG -//#define USE_WMIN_PLUG -//#define USE_XMAX_PLUG -#define USE_YMAX_PLUG -#define USE_ZMAX_PLUG -//#define USE_IMAX_PLUG -//#define USE_JMAX_PLUG -//#define USE_KMAX_PLUG -//#define USE_UMAX_PLUG -//#define USE_VMAX_PLUG -//#define USE_WMAX_PLUG - // Enable pullup for all endstops to prevent a floating state #define ENDSTOPPULLUPS #if DISABLED(ENDSTOPPULLUPS) @@ -1209,43 +1268,45 @@ //#define ENDSTOPPULLDOWN_ZMIN_PROBE #endif -// Mechanical endstop with COM to ground and NC to Signal uses "false" here (most common setup). +/** + * Endstop "Hit" State + * Set to the state (HIGH or LOW) that applies to each endstop. + */ #if ANY(Mini, MiniV2, TazPro) - #define X_MIN_ENDSTOP_INVERTING true // Set to true to invert the logic of the endstop. + #define X_MIN_ENDSTOP_HIT_STATE LOW #else - #define X_MIN_ENDSTOP_INVERTING false // Set to true to invert the logic of the endstop. + #define X_MIN_ENDSTOP_HIT_STATE HIGH #endif +#define X_MAX_ENDSTOP_HIT_STATE HIGH #if ENABLED(Mini) - #define Y_MIN_ENDSTOP_INVERTING true // Set to true to invert the logic of the endstop. + #define Y_MIN_ENDSTOP_HIT_STATE LOW #else - #define Y_MIN_ENDSTOP_INVERTING false // Set to true to invert the logic of the endstop. + #define Y_MIN_ENDSTOP_HIT_STATE HIGH #endif -#define Z_MIN_ENDSTOP_INVERTING true // Set to true to invert the logic of the endstop. - -#define I_MIN_ENDSTOP_INVERTING false // Set to true to invert the logic of the endstop. -#define J_MIN_ENDSTOP_INVERTING false // Set to true to invert the logic of the endstop. -#define K_MIN_ENDSTOP_INVERTING false // Set to true to invert the logic of the endstop. -#define U_MIN_ENDSTOP_INVERTING false // Set to true to invert the logic of the endstop. -#define V_MIN_ENDSTOP_INVERTING false // Set to true to invert the logic of the endstop. -#define W_MIN_ENDSTOP_INVERTING false // Set to true to invert the logic of the endstop. -#define X_MAX_ENDSTOP_INVERTING false // Set to true to invert the logic of the endstop. #if ANY(Mini, MiniV2, TazPro) - #define Y_MAX_ENDSTOP_INVERTING true // Set to true to invert the logic of the endstop. + #define Y_MAX_ENDSTOP_HIT_STATE LOW #else - #define Y_MAX_ENDSTOP_INVERTING false // Set to true to invert the logic of the endstop. + #define Y_MAX_ENDSTOP_HIT_STATE HIGH #endif +#define Z_MIN_ENDSTOP_HIT_STATE LOW #if ENABLED(Mini) - #define Z_MAX_ENDSTOP_INVERTING true // Set to true to invert the logic of the endstop. + #define Z_MAX_ENDSTOP_HIT_STATE LOW #else - #define Z_MAX_ENDSTOP_INVERTING false // Set to true to invert the logic of the endstop. + #define Z_MAX_ENDSTOP_HIT_STATE HIGH #endif -#define I_MAX_ENDSTOP_INVERTING false // Set to true to invert the logic of the endstop. -#define J_MAX_ENDSTOP_INVERTING false // Set to true to invert the logic of the endstop. -#define K_MAX_ENDSTOP_INVERTING false // Set to true to invert the logic of the endstop. -#define U_MAX_ENDSTOP_INVERTING false // Set to true to invert the logic of the endstop. -#define V_MAX_ENDSTOP_INVERTING false // Set to true to invert the logic of the endstop. -#define W_MAX_ENDSTOP_INVERTING false // Set to true to invert the logic of the endstop. -#define Z_MIN_PROBE_ENDSTOP_INVERTING true // Set to true to invert the logic of the probe. +#define I_MIN_ENDSTOP_HIT_STATE HIGH +#define I_MAX_ENDSTOP_HIT_STATE HIGH +#define J_MIN_ENDSTOP_HIT_STATE HIGH +#define J_MAX_ENDSTOP_HIT_STATE HIGH +#define K_MIN_ENDSTOP_HIT_STATE HIGH +#define K_MAX_ENDSTOP_HIT_STATE HIGH +#define U_MIN_ENDSTOP_HIT_STATE HIGH +#define U_MAX_ENDSTOP_HIT_STATE HIGH +#define V_MIN_ENDSTOP_HIT_STATE HIGH +#define V_MAX_ENDSTOP_HIT_STATE HIGH +#define W_MIN_ENDSTOP_HIT_STATE HIGH +#define W_MAX_ENDSTOP_HIT_STATE HIGH +#define Z_MIN_PROBE_ENDSTOP_HIT_STATE LOW // Enable this feature if all enabled endstop pins are interrupt-capable. // This will remove the need to poll the interrupt pins, saving many CPU cycles. @@ -1443,18 +1504,15 @@ /** * Z_MIN_PROBE_PIN * - * Define this pin if the probe is not connected to Z_MIN_PIN. - * If not defined the default pin for the selected MOTHERBOARD - * will be used. Most of the time the default is what you want. + * Override this pin only if the probe cannot be connected to + * the default Z_MIN_PROBE_PIN for the selected MOTHERBOARD. * * - The simplest option is to use a free endstop connector. * - Use 5V for powered (usually inductive) sensors. * - * - RAMPS 1.3/1.4 boards may use the 5V, GND, and Aux4->D32 pin: - * - For simple switches connect... - * - normally-closed switches to GND and D32. - * - normally-open switches to 5V and D32. - * + * - For simple switches... + * - Normally-closed (NC) also connect to GND. + * - Normally-open (NO) also connect to 5V. */ #if ENABLED(Taz6) #define Z_MIN_PROBE_PIN SERVO0_PIN // Pin 32 is the RAMPS default @@ -1489,8 +1547,13 @@ /** * Z Servo Probe, such as an endstop switch on a rotating arm. */ -//#define Z_PROBE_SERVO_NR 0 // Defaults to SERVO 0 connector. -//#define Z_SERVO_ANGLES { 70, 0 } // Z Servo Deploy and Stow angles +//#define Z_PROBE_SERVO_NR 0 +#ifdef Z_PROBE_SERVO_NR + //#define Z_SERVO_ANGLES { 70, 0 } // Z Servo Deploy and Stow angles + //#define Z_SERVO_MEASURE_ANGLE 45 // Use if the servo must move to a "free" position for measuring after deploy + //#define Z_SERVO_INTERMEDIATE_STOW // Stow the probe between points + //#define Z_SERVO_DEACTIVATE_AFTER_STOW // Deactivate the servo when probe is stowed +#endif /** * The BLTouch probe uses a Hall effect sensor and emulates a servo. @@ -1516,7 +1579,7 @@ * on the right, enable and set TOUCH_MI_DEPLOY_XPOS to the deploy position. * * Also requires: BABYSTEPPING, BABYSTEP_ZPROBE_OFFSET, Z_SAFE_HOMING, - * and a minimum Z_HOMING_HEIGHT of 10. + * and a minimum Z_CLEARANCE_FOR_HOMING of 10. */ //#define TOUCH_MI_PROBE #if ENABLED(TOUCH_MI_PROBE) @@ -1525,6 +1588,18 @@ //#define TOUCH_MI_MANUAL_DEPLOY // For manual deploy (LCD menu) #endif +/** + * Bed Distance Sensor + * + * Measures the distance from bed to nozzle with accuracy of 0.01mm. + * For information about this sensor https://github.com/markniu/Bed_Distance_sensor + * Uses I2C port, so it requires I2C library markyue/Panda_SoftMasterI2C. + */ +//#define BD_SENSOR +#if ENABLED(BD_SENSOR) + //#define BD_SENSOR_PROBE_NO_STOP // Probe bed without stopping at each probe point +#endif + // A probe that is deployed and stowed with a solenoid pin (SOL1_PIN) //#define SOLENOID_PROBE @@ -1560,7 +1635,7 @@ #define MAG_MOUNTED_STOW_5 { PROBE_STOW_FEEDRATE, { 0, 0, 0 } } // Extra move if needed #endif -// Duet Smart Effector (for delta printers) - https://bit.ly/2ul5U7J +// Duet Smart Effector (for delta printers) - https://docs.duet3d.com/en/Duet3D_hardware/Accessories/Smart_Effector // When the pin is defined you can use M672 to set/reset the probe sensitivity. //#define DUET_SMART_EFFECTOR #if ENABLED(DUET_SMART_EFFECTOR) @@ -1576,7 +1651,7 @@ //#define SENSORLESS_PROBING /** - * Allen key retractable z-probe as seen on many Kossel delta printers - https://reprap.org/wiki/Kossel#Automatic_bed_leveling_probe + * Allen key retractable z-probe as seen on many Kossel delta printers - https://reprap.org/wiki/Kossel#Autolevel_probe * Deploys by touching z-axis belt. Retracts by pushing the probe down. */ //#define Z_PROBE_ALLEN_KEY @@ -1584,13 +1659,13 @@ // 2 or 3 sets of coordinates for deploying and retracting the spring loaded touch probe on G29, // if servo actuated touch probe is not defined. Uncomment as appropriate for your printer/probe. - #define Z_PROBE_ALLEN_KEY_DEPLOY_1 { 30.0, DELTA_PRINTABLE_RADIUS, 100.0 } + #define Z_PROBE_ALLEN_KEY_DEPLOY_1 { 30.0, PRINTABLE_RADIUS, 100.0 } #define Z_PROBE_ALLEN_KEY_DEPLOY_1_FEEDRATE XY_PROBE_FEEDRATE - #define Z_PROBE_ALLEN_KEY_DEPLOY_2 { 0.0, DELTA_PRINTABLE_RADIUS, 100.0 } + #define Z_PROBE_ALLEN_KEY_DEPLOY_2 { 0.0, PRINTABLE_RADIUS, 100.0 } #define Z_PROBE_ALLEN_KEY_DEPLOY_2_FEEDRATE (XY_PROBE_FEEDRATE)/10 - #define Z_PROBE_ALLEN_KEY_DEPLOY_3 { 0.0, (DELTA_PRINTABLE_RADIUS) * 0.75, 100.0 } + #define Z_PROBE_ALLEN_KEY_DEPLOY_3 { 0.0, (PRINTABLE_RADIUS) * 0.75, 100.0 } #define Z_PROBE_ALLEN_KEY_DEPLOY_3_FEEDRATE XY_PROBE_FEEDRATE #define Z_PROBE_ALLEN_KEY_STOW_1 { -64.0, 56.0, 23.0 } // Move the probe into position @@ -1623,7 +1698,7 @@ * * Tune and Adjust * - Probe Offsets can be tuned at runtime with 'M851', LCD menus, babystepping, etc. - * - PROBE_OFFSET_WIZARD (configuration_adv.h) can be used for setting the Z offset. + * - PROBE_OFFSET_WIZARD (Configuration_adv.h) can be used for setting the Z offset. * * Assuming the typical work area orientation: * - Probe to RIGHT of the Nozzle has a Positive X offset @@ -1658,6 +1733,12 @@ #endif +// Enable and set to use a specific tool for probing. Disable to allow any tool. +#define PROBING_TOOL 0 +#ifdef PROBING_TOOL + //#define PROBE_TOOLCHANGE_NO_MOVE // Suppress motion on probe tool-change +#endif + // Most probes should stay away from the edges of the bed, but // with NOZZLE_AS_PROBE this can be negative for a wider probing area. #define PROBING_MARGIN 0 @@ -1733,16 +1814,21 @@ * Example: `M851 Z-5` with a CLEARANCE of 4 => 9mm from bed to nozzle. * But: `M851 Z+1` with a CLEARANCE of 2 => 2mm from bed to nozzle. */ -#define Z_CLEARANCE_DEPLOY_PROBE 5 // Z Clearance for Deploy/Stow -#define Z_CLEARANCE_BETWEEN_PROBES 5 // Z Clearance between probe points -#define Z_CLEARANCE_MULTI_PROBE 5 // Z Clearance between multiple probes -//#define Z_AFTER_PROBING 5 // Z position after probing is done +#define Z_CLEARANCE_DEPLOY_PROBE 5 // (mm) Z Clearance for Deploy/Stow +#define Z_CLEARANCE_BETWEEN_PROBES 5 // (mm) Z Clearance between probe points +#define Z_CLEARANCE_MULTI_PROBE 5 // (mm) Z Clearance between multiple probes +#define Z_PROBE_ERROR_TOLERANCE 3 // (mm) Tolerance for early trigger (<= -probe.offset.z + ZPET) +//#define Z_AFTER_PROBING 5 // (mm) Z position after probing is done -#define Z_PROBE_LOW_POINT -4 // Farthest distance below the trigger-point to go before stopping +#define Z_PROBE_LOW_POINT -4 // (mm) Farthest distance below the trigger-point to go before stopping -// For M851 give a range for adjusting the Z probe offset -#define Z_PROBE_OFFSET_RANGE_MIN -3 -#define Z_PROBE_OFFSET_RANGE_MAX 5 +// For M851 provide ranges for adjusting the X, Y, and Z probe offsets +//#define PROBE_OFFSET_XMIN -50 // (mm) +//#define PROBE_OFFSET_XMAX 50 // (mm) +//#define PROBE_OFFSET_YMIN -50 // (mm) +//#define PROBE_OFFSET_YMAX 50 // (mm) +//#define PROBE_OFFSET_ZMIN -20 // (mm) +//#define PROBE_OFFSET_ZMAX 20 // (mm) // Enable the M48 repeatability test to test probe accuracy //#define Z_MIN_PROBE_REPEATABILITY_TEST @@ -1792,23 +1878,23 @@ // Disable axis steppers immediately when they're not being stepped. // WARNING: When motors turn off there is a chance of losing position accuracy! -#define DISABLE_X false -#define DISABLE_Y false -#define DISABLE_Z false -//#define DISABLE_I false -//#define DISABLE_J false -//#define DISABLE_K false -//#define DISABLE_U false -//#define DISABLE_V false -//#define DISABLE_W false +//#define DISABLE_X +//#define DISABLE_Y +//#define DISABLE_Z +//#define DISABLE_I +//#define DISABLE_J +//#define DISABLE_K +//#define DISABLE_U +//#define DISABLE_V +//#define DISABLE_W // Turn off the display blinking that warns about possible accuracy reduction //#define DISABLE_REDUCED_ACCURACY_WARNING // @section extruder -#define DISABLE_E false // Disable the extruder when not stepping -#define DISABLE_INACTIVE_EXTRUDER // Keep only the active extruder enabled +//#define DISABLE_E // Disable the extruder when not stepping +#define DISABLE_OTHER_EXTRUDERS // Keep only the active extruder enabled // @section motion @@ -1851,10 +1937,13 @@ */ //#define Z_IDLE_HEIGHT Z_HOME_POS -#define Z_HOMING_HEIGHT 5 // (mm) Minimal Z height before homing (G28) for Z clearance above the bed, clamps, ... - // Be sure to have this much clearance over your Z_MAX_POS to prevent grinding. +#define Z_CLEARANCE_FOR_HOMING 5 // (mm) Minimal Z height before homing (G28) for Z clearance above the bed, clamps, ... + // You'll need this much clearance above Z_MAX_POS to avoid grinding. -//#define Z_AFTER_HOMING 10 // (mm) Height to move to after homing Z +//#define Z_AFTER_HOMING 10 // (mm) Height to move to after homing (if Z was homed) +//#define XY_AFTER_HOMING { 10, 10 } // (mm) Move to an XY position after homing (and raising Z) + +//#define EVENT_GCODE_AFTER_HOMING "M300 P440 S200" // Commands to run after G28 (and move to XY_AFTER_HOMING) // Direction of endstops when homing; 1=MAX, -1=MIN // :[-1,1] @@ -1876,6 +1965,21 @@ //#define V_HOME_DIR -1 //#define W_HOME_DIR -1 +/** + * Safety Stops + * If an axis has endstops on both ends the one specified above is used for + * homing, while the other can be used for things like SD_ABORT_ON_ENDSTOP_HIT. + */ +//#define X_SAFETY_STOP +//#define Y_SAFETY_STOP +//#define Z_SAFETY_STOP +//#define I_SAFETY_STOP +//#define J_SAFETY_STOP +//#define K_SAFETY_STOP +//#define U_SAFETY_STOP +//#define V_SAFETY_STOP +//#define W_SAFETY_STOP + // @section geometry // The size of the print bed @@ -1987,7 +2091,7 @@ #define MAX_SOFTWARE_ENDSTOP_W #endif -#if EITHER(MIN_SOFTWARE_ENDSTOPS, MAX_SOFTWARE_ENDSTOPS) +#if ANY(MIN_SOFTWARE_ENDSTOPS, MAX_SOFTWARE_ENDSTOPS) //#define SOFT_ENDSTOPS_MENU_ITEM // Enable/Disable software endstops from the LCD #endif @@ -2063,7 +2167,48 @@ // Enable this option to use an encoder disc that toggles the runout pin // as the filament moves. (Be sure to set FILAMENT_RUNOUT_DISTANCE_MM // large enough to avoid false positives.) - #define FILAMENT_MOTION_SENSOR + //#define FILAMENT_MOTION_SENSOR + + #if ENABLED(FILAMENT_MOTION_SENSOR) + //#define FILAMENT_SWITCH_AND_MOTION + #if ENABLED(FILAMENT_SWITCH_AND_MOTION) + #define NUM_MOTION_SENSORS 1 // Number of sensors, up to one per extruder. Define a FIL_MOTION#_PIN for each. + //#define FIL_MOTION1_PIN -1 + + // Override individually if the motion sensors vary + //#define FIL_MOTION1_STATE LOW + //#define FIL_MOTION1_PULLUP + //#define FIL_MOTION1_PULLDOWN + + //#define FIL_MOTION2_STATE LOW + //#define FIL_MOTION2_PULLUP + //#define FIL_MOTION2_PULLDOWN + + //#define FIL_MOTION3_STATE LOW + //#define FIL_MOTION3_PULLUP + //#define FIL_MOTION3_PULLDOWN + + //#define FIL_MOTION4_STATE LOW + //#define FIL_MOTION4_PULLUP + //#define FIL_MOTION4_PULLDOWN + + //#define FIL_MOTION5_STATE LOW + //#define FIL_MOTION5_PULLUP + //#define FIL_MOTION5_PULLDOWN + + //#define FIL_MOTION6_STATE LOW + //#define FIL_MOTION6_PULLUP + //#define FIL_MOTION6_PULLDOWN + + //#define FIL_MOTION7_STATE LOW + //#define FIL_MOTION7_PULLUP + //#define FIL_MOTION7_PULLDOWN + + //#define FIL_MOTION8_STATE LOW + //#define FIL_MOTION8_PULLUP + //#define FIL_MOTION8_PULLDOWN + #endif + #endif #endif #endif @@ -2111,6 +2256,12 @@ //#define AUTO_BED_LEVELING_UBL //#define MESH_BED_LEVELING +/** + * Commands to execute at the end of G29 probing. + * Useful to retract or move the Z probe out of the way. + */ +//#define Z_PROBE_END_SCRIPT "G1 Z10 F12000\nG1 X15 Y330\nG1 Z0.5\nG1 Z10" + /** * Normally G28 leaves leveling disabled on completion. Enable one of * these options to restore the prior leveling state or to always enable @@ -2128,15 +2279,6 @@ #define LEVELING_BED_TEMP 50 #endif -/** - * Bed Distance Sensor - * - * Measures the distance from bed to nozzle with accuracy of 0.01mm. - * For information about this sensor https://github.com/markniu/Bed_Distance_sensor - * Uses I2C port, so it requires I2C library markyue/Panda_SoftMasterI2C. - */ -//#define BD_SENSOR - /** * Enable detailed logging of G28, G29, M48, etc. * Turn on with the command 'M111 S32'. @@ -2150,17 +2292,21 @@ #endif #if ANY(MESH_BED_LEVELING, AUTO_BED_LEVELING_BILINEAR, AUTO_BED_LEVELING_UBL) - // Gradually reduce leveling correction until a set height is reached, - // at which point movement will be level to the machine's XY plane. - // The height can be set with M420 Z + /** + * Gradually reduce leveling correction until a set height is reached, + * at which point movement will be level to the machine's XY plane. + * The height can be set with M420 Z + */ #define ENABLE_LEVELING_FADE_HEIGHT #if ENABLED(ENABLE_LEVELING_FADE_HEIGHT) #define DEFAULT_LEVELING_FADE_HEIGHT 0.0 // (mm) Default fade height. #endif - // For Cartesian machines, instead of dividing moves on mesh boundaries, - // split up moves into short segments like a Delta. This follows the - // contours of the bed more closely than edge-to-edge straight moves. + /** + * For Cartesian machines, instead of dividing moves on mesh boundaries, + * split up moves into short segments like a Delta. This follows the + * contours of the bed more closely than edge-to-edge straight moves. + */ #define SEGMENT_LEVELED_MOVES #define LEVELED_SEGMENT_LENGTH 5.0 // (mm) Length of all segments (except the last one) @@ -2180,7 +2326,7 @@ #endif -#if EITHER(AUTO_BED_LEVELING_LINEAR, AUTO_BED_LEVELING_BILINEAR) +#if ANY(AUTO_BED_LEVELING_LINEAR, AUTO_BED_LEVELING_BILINEAR) // Set the number of grid points per dimension. #define GRID_MAX_POINTS_X 2 @@ -2197,7 +2343,7 @@ //#define EXTRAPOLATE_BEYOND_GRID // - // Experimental Subdivision of the grid by Catmull-Rom method. + // Subdivision of the grid by Catmull-Rom method. // Synthesizes intermediate points to produce a more detailed mesh. // //#define ABL_BILINEAR_SUBDIVISION @@ -2222,6 +2368,9 @@ //#define UBL_HILBERT_CURVE // Use Hilbert distribution for less travel when probing multiple points + //#define UBL_TILT_ON_MESH_POINTS // Use nearest mesh points with G29 J for better Z reference + //#define UBL_TILT_ON_MESH_POINTS_3POINT // Use nearest mesh points with G29 J0 (3-point) + #define UBL_MESH_EDIT_MOVES_Z // Sophisticated users prefer no movement of nozzle #define UBL_SAVE_ACTIVE_ON_M500 // Save the currently active mesh in the current slot on M500 @@ -2230,6 +2379,25 @@ //#define UBL_MESH_WIZARD // Run several commands in a row to get a complete mesh + /** + * Probing not allowed within the position of an obstacle. + */ + //#define AVOID_OBSTACLES + #if ENABLED(AVOID_OBSTACLES) + #define CLIP_W 23 // Bed clip width, should be padded a few mm over its physical size + #define CLIP_H 14 // Bed clip height, should be padded a few mm over its physical size + + // Obstacle Rectangles defined as { X1, Y1, X2, Y2 } + #define OBSTACLE1 { (X_BED_SIZE) / 4 - (CLIP_W) / 2, 0, (X_BED_SIZE) / 4 + (CLIP_W) / 2, CLIP_H } + #define OBSTACLE2 { (X_BED_SIZE) * 3 / 4 - (CLIP_W) / 2, 0, (X_BED_SIZE) * 3 / 4 + (CLIP_W) / 2, CLIP_H } + #define OBSTACLE3 { (X_BED_SIZE) / 4 - (CLIP_W) / 2, (Y_BED_SIZE) - (CLIP_H), (X_BED_SIZE) / 4 + (CLIP_W) / 2, Y_BED_SIZE } + #define OBSTACLE4 { (X_BED_SIZE) * 3 / 4 - (CLIP_W) / 2, (Y_BED_SIZE) - (CLIP_H), (X_BED_SIZE) * 3 / 4 + (CLIP_W) / 2, Y_BED_SIZE } + + // The probed grid must be inset for G29 J. This is okay, since it is + // only used to compute a linear transformation for the mesh itself. + #define G29J_MESH_TILT_MARGIN ((CLIP_H) + 1) + #endif + #elif ENABLED(MESH_BED_LEVELING) //=========================================================================== @@ -2261,8 +2429,8 @@ #if ENABLED(LCD_BED_TRAMMING) #define BED_TRAMMING_INSET_LFRB { 30, 30, 30, 30 } // (mm) Left, Front, Right, Back insets - #define BED_TRAMMING_HEIGHT 0.0 // (mm) Z height of nozzle at leveling points - #define BED_TRAMMING_Z_HOP 4.0 // (mm) Z height of nozzle between leveling points + #define BED_TRAMMING_HEIGHT 0.0 // (mm) Z height of nozzle at tramming points + #define BED_TRAMMING_Z_HOP 4.0 // (mm) Z height of nozzle between tramming points //#define BED_TRAMMING_INCLUDE_CENTER // Move to the center after the last corner //#define BED_TRAMMING_USE_PROBE #if ENABLED(BED_TRAMMING_USE_PROBE) @@ -2291,12 +2459,6 @@ #define BED_TRAMMING_LEVELING_ORDER { LF, RF, RB, LB } #endif -/** - * Commands to execute at the end of G29 probing. - * Useful to retract or move the Z probe out of the way. - */ -//#define Z_PROBE_END_SCRIPT "G1 Z10 F12000\nG1 X15 Y330\nG1 Z0.5\nG1 Z10" - // @section homing // The center of the bed is at (X=0, Y=0) @@ -2324,10 +2486,10 @@ #if ENABLED(Taz6) #define Z_SAFE_HOMING #endif - #if ENABLED(Z_SAFE_HOMING) - #define Z_SAFE_HOMING_X_POINT -19 // X point for Z homing - #define Z_SAFE_HOMING_Y_POINT 262 // Y point for Z homing + #define Z_SAFE_HOMING_X_POINT -19 // (mm) X point for Z homing + #define Z_SAFE_HOMING_Y_POINT 262 // (mm) Y point for Z homing + //#define Z_SAFE_HOMING_POINT_ABSOLUTE // Ignore home offsets (M206) for Z homing position #endif // Homing speeds (mm/m) @@ -2491,7 +2653,7 @@ #endif /** - * Clean Nozzle Feature -- EXPERIMENTAL + * Clean Nozzle Feature * * Adds the G12 command to perform a nozzle cleaning process. * @@ -2525,19 +2687,22 @@ * Before starting, the nozzle moves to NOZZLE_CLEAN_START_POINT. * * Caveats: The ending Z should be the same as starting Z. - * Attention: EXPERIMENTAL. G-code arguments may change. - * */ #define NOZZLE_CLEAN_FEATURE #if ENABLED(NOZZLE_CLEAN_FEATURE) - #define CLEAN_SCRIPT "M117 Hot end heating...\nM104 S170\nG28 O1\nM117 Wiping nozzle\nT0\nG1 X-17 Y25 Z10 F4000\nM109 R170\nG1 Z1\nM114\nG1 X-17 Y25\nG1 X-17 Y95\nG1 X-17 Y25\nG1 X-17 Y95\nG1 X-17 Y25\nG1 X-17 Y95\nG1 X-17 Y25\nG1 X-17 Y95\nG1 X-17 Y25\nG1 X-17 Y95\nG1 X-17 Y25\nG1 X-17 Y95\nG1 Z15\nM400\nM106 S255\nG0 X-10.0 Y-9.0M109 R160\nM107" + #define NOZZLE_CLEAN_PATTERN_LINE // Provide 'G12 P0' - a simple linear cleaning pattern + #define NOZZLE_CLEAN_PATTERN_ZIGZAG // Provide 'G12 P1' - a zigzag cleaning pattern + #define NOZZLE_CLEAN_PATTERN_CIRCLE // Provide 'G12 P2' - a circular cleaning pattern - // Default number of pattern repetitions - #define NOZZLE_CLEAN_STROKES 12 + // Default pattern to use when 'P' is not provided to G12. One of the enabled options above. + #define NOZZLE_CLEAN_DEFAULT_PATTERN 0 - // Default number of triangles - #define NOZZLE_CLEAN_TRIANGLES 3 + #define NOZZLE_CLEAN_STROKES 12 // Default number of pattern repetitions + + #if ENABLED(NOZZLE_CLEAN_PATTERN_ZIGZAG) + #define NOZZLE_CLEAN_TRIANGLES 3 // Default number of triangles + #endif // Specify positions for each tool as { { X, Y, Z }, { X, Y, Z } } // Dual hotend system may use { { -20, (Y_BED_SIZE / 2), (Z_MIN_POS + 1) }, { 420, (Y_BED_SIZE / 2), (Z_MIN_POS + 1) }} @@ -2552,12 +2717,11 @@ #define NOZZLE_CLEAN_END_POINT { -17, 25, 1 } #endif - // Circular pattern radius - #define NOZZLE_CLEAN_CIRCLE_RADIUS 6.5 - // Circular pattern circle fragments number - #define NOZZLE_CLEAN_CIRCLE_FN 10 - // Middle point of circle - #define NOZZLE_CLEAN_CIRCLE_MIDDLE NOZZLE_CLEAN_START_POINT + #if ENABLED(NOZZLE_CLEAN_PATTERN_CIRCLE) + #define NOZZLE_CLEAN_CIRCLE_RADIUS 6.5 // (mm) Circular pattern radius + #define NOZZLE_CLEAN_CIRCLE_FN 10 // Circular pattern circle number of segments + #define NOZZLE_CLEAN_CIRCLE_MIDDLE NOZZLE_CLEAN_START_POINT // Middle point of circle + #endif // Move the nozzle to the initial position after cleaning //#define NOZZLE_CLEAN_GOBACK @@ -2660,8 +2824,8 @@ #define PASSWORD_LENGTH 4 // (#) Number of digits (1-9). 3 or 4 is recommended #define PASSWORD_ON_STARTUP #define PASSWORD_UNLOCK_GCODE // Unlock with the M511 P command. Disable to prevent brute-force attack. - #define PASSWORD_CHANGE_GCODE // Change the password with M512 P N. - //#define PASSWORD_ON_SD_PRINT_MENU // This does not prevent gcodes from running + #define PASSWORD_CHANGE_GCODE // Change the password with M512 P S. + //#define PASSWORD_ON_SD_PRINT_MENU // This does not prevent G-codes from running //#define PASSWORD_AFTER_SD_PRINT_END //#define PASSWORD_AFTER_SD_PRINT_ABORT //#include "Configuration_Secure.h" // External file with PASSWORD_DEFAULT_VALUE @@ -2827,6 +2991,18 @@ //#define LCD_FEEDBACK_FREQUENCY_DURATION_MS 2 //#define LCD_FEEDBACK_FREQUENCY_HZ 5000 +// +// Tone queue size, used to keep beeps from blocking execution. +// Default is 4, or override here. Costs 4 bytes of SRAM per entry. +// +//#define TONE_QUEUE_LENGTH 4 + +// +// A sequence of tones to play at startup, in pairs of tone (Hz), duration (ms). +// Silence in-between tones. +// +//#define STARTUP_TUNE { 698, 300, 0, 50, 523, 50, 0, 25, 494, 50, 0, 25, 523, 100, 0, 50, 554, 300, 0, 100, 523, 300 } + //============================================================================= //======================== LCD / Controller Selection ========================= //======================== (Character-based LCDs) ========================= @@ -2851,7 +3027,7 @@ // // Original RADDS LCD Display+Encoder+SDCardReader -// http://doku.radds.org/dokumentation/lcd-display/ +// https://web.archive.org/web/20200719145306/http://doku.radds.org/dokumentation/lcd-display/ // //#define RADDS_DISPLAY @@ -2881,7 +3057,6 @@ // // RigidBot Panel V1.0 -// http://www.inventapart.com/ // //#define RIGIDBOT_PANEL @@ -2918,15 +3093,16 @@ // // Elefu RA Board Control Panel -// http://www.elefu.com/index.php?route=product/product&product_id=53 +// https://web.archive.org/web/20140823033947/http://www.elefu.com/index.php?route=product/product&product_id=53 // //#define RA_CONTROL_PANEL // // Sainsmart (YwRobot) LCD Displays // -// These require F.Malpartida's LiquidCrystal_I2C library -// https://bitbucket.org/fmalpartida/new-liquidcrystal/wiki/Home +// These require LiquidCrystal_I2C library: +// https://github.com/MarlinFirmware/New-LiquidCrystal +// https://github.com/fmalpartida/New-LiquidCrystal/wiki // //#define LCD_SAINSMART_I2C_1602 //#define LCD_SAINSMART_I2C_2004 @@ -2959,7 +3135,7 @@ // // -// 2-wire Non-latching LCD SR from https://goo.gl/aJJ4sH +// 2-wire Non-latching LCD SR from https://github.com/fmalpartida/New-LiquidCrystal/wiki/schematics#user-content-ShiftRegister_connection // LCD configuration: https://reprap.org/wiki/SAV_3D_LCD // //#define SAV_3DLCD @@ -3000,7 +3176,7 @@ // // ReprapWorld Graphical LCD -// https://reprapworld.com/?products_details&products_id/1218 +// https://reprapworld.com/electronics/3d-printer-modules/autonomous-printing/graphical-lcd-screen-v1-0/ // //#define REPRAPWORLD_GRAPHICAL_LCD @@ -3025,7 +3201,7 @@ // // MaKr3d Makr-Panel with graphic controller and SD support. -// https://reprap.org/wiki/MaKr3d_MaKrPanel +// https://reprap.org/wiki/MaKrPanel // //#define MAKRPANEL @@ -3043,7 +3219,7 @@ // // Cartesio UI -// http://mauk.cc/webshop/cartesio-shop/electronics/user-interface +// https://web.archive.org/web/20180605050442/http://mauk.cc/webshop/cartesio-shop/electronics/user-interface // //#define CARTESIO_UI @@ -3087,16 +3263,16 @@ //#define FYSETC_GENERIC_12864_1_1 // Larger display with basic ON/OFF backlight. // -// BigTreeTech Mini 12864 V1.0 is an alias for FYSETC_MINI_12864_2_1. Type A/B. NeoPixel RGB Backlight. +// BigTreeTech Mini 12864 V1.0 / V2.0 is an alias for FYSETC_MINI_12864_2_1. Type A/B. NeoPixel RGB Backlight. +// https://github.com/bigtreetech/MINI-12864 // -//#define BTT_MINI_12864_V1 +//#define BTT_MINI_12864 // -// Factory display for Creality CR-10 +// Factory display for Creality CR-10 / CR-7 / Ender-3 // https://www.aliexpress.com/item/32833148327.html // -// This is RAMPS-compatible using a single 10-pin connector. -// (For CR-10 owners who want to replace the Melzi Creality board but retain the display) +// Connect to EXP1 on RAMPS and compatible boards. // //#define CR10_STOCKDISPLAY @@ -3106,14 +3282,14 @@ //#define ENDER2_STOCKDISPLAY // -// ANET and Tronxy Graphical Controller -// -// Anet 128x64 full graphics lcd with rotary encoder as used on Anet A6 -// A clone of the RepRapDiscount full graphics display but with -// different pins/wiring (see pins_ANET_10.h). Enable one of these. +// ANET and Tronxy 128×64 Full Graphics Controller as used on Anet A6 // //#define ANET_FULL_GRAPHICS_LCD -//#define ANET_FULL_GRAPHICS_LCD_ALT_WIRING + +// +// GUCOCO CTC 128×64 Full Graphics Controller as used on GUCOCO CTC A10S +// +//#define CTC_A10S_A13 // // AZSMZ 12864 LCD with SD @@ -3198,23 +3374,16 @@ /** * DGUS Touch Display with DWIN OS. (Choose one.) - * ORIGIN : https://www.aliexpress.com/item/32993409517.html - * FYSETC : https://www.aliexpress.com/item/32961471929.html - * MKS : https://www.aliexpress.com/item/1005002008179262.html - * - * Flash display with DGUS Displays for Marlin: - * - Format the SD card to FAT32 with an allocation size of 4kb. - * - Download files as specified for your type of display. - * - Plug the microSD card into the back of the display. - * - Boot the display and wait for the update to complete. * * ORIGIN (Marlin DWIN_SET) * - Download https://github.com/coldtobi/Marlin_DGUS_Resources * - Copy the downloaded DWIN_SET folder to the SD card. + * - Product: https://www.aliexpress.com/item/32993409517.html * * FYSETC (Supplier default) * - Download https://github.com/FYSETC/FYSTLCD-2.0 * - Copy the downloaded SCREEN folder to the SD card. + * - Product: https://www.aliexpress.com/item/32961471929.html * * HIPRECY (Supplier default) * - Download https://github.com/HiPrecy/Touch-Lcd-LEO @@ -3223,18 +3392,34 @@ * MKS (MKS-H43) (Supplier default) * - Download https://github.com/makerbase-mks/MKS-H43 * - Copy the downloaded DWIN_SET folder to the SD card. + * - Product: https://www.aliexpress.com/item/1005002008179262.html * * RELOADED (T5UID1) - * - Download https://github.com/Desuuuu/DGUS-reloaded/releases + * - Download https://github.com/Neo2003/DGUS-reloaded/releases * - Copy the downloaded DWIN_SET folder to the SD card. + * + * IA_CREALITY (T5UID1) + * - Download https://github.com/InsanityAutomation/Marlin/raw/CrealityDwin_2.0/TM3D_Combined480272_Landscape_V7.7z + * - Copy the downloaded DWIN_SET folder to the SD card. + * + * E3S1PRO (T5L) + * - Download https://github.com/CrealityOfficial/Ender-3S1/archive/3S1_Plus_Screen.zip + * - Copy the downloaded DWIN_SET folder to the SD card. + * + * Flash display with DGUS Displays for Marlin: + * - Format the SD card to FAT32 with an allocation size of 4kb. + * - Download files as specified for your type of display. + * - Plug the microSD card into the back of the display. + * - Boot the display and wait for the update to complete. + * + * :[ 'ORIGIN', 'FYSETC', 'HYPRECY', 'MKS', 'RELOADED', 'IA_CREALITY', 'E3S1PRO' ] */ -//#define DGUS_LCD_UI_ORIGIN -//#define DGUS_LCD_UI_FYSETC -//#define DGUS_LCD_UI_HIPRECY -//#define DGUS_LCD_UI_MKS -//#define DGUS_LCD_UI_RELOADED -#if ENABLED(DGUS_LCD_UI_MKS) +//#define DGUS_LCD_UI ORIGIN +#if DGUS_UI_IS(MKS) #define USE_MKS_GREEN_UI +#elif DGUS_UI_IS(IA_CREALITY) + //#define LCD_SCREEN_ROTATE 90 // Portrait Mode or 800x480 displays + //#define IA_CREALITY_BOOT_DELAY 1500 // (ms) #endif // @@ -3251,15 +3436,23 @@ #endif // -// Touch-screen LCD for Anycubic printers +// Touch-screen LCD for Anycubic Chiron +// +//#define ANYCUBIC_LCD_CHIRON + +// +// Touch-screen LCD for Anycubic i3 Mega // //#define ANYCUBIC_LCD_I3MEGA -//#define ANYCUBIC_LCD_CHIRON -#if EITHER(ANYCUBIC_LCD_I3MEGA, ANYCUBIC_LCD_CHIRON) - //#define ANYCUBIC_LCD_DEBUG +#if ENABLED(ANYCUBIC_LCD_I3MEGA) //#define ANYCUBIC_LCD_GCODE_EXT // Add ".gcode" to menu entries for DGUS clone compatibility #endif +// +// Touch-screen LCD for Anycubic Vyper +// +//#define ANYCUBIC_LCD_VYPER + // // 320x240 Nextion 2.8" serial TFT Resistive Touch Screen NX3224T028 // @@ -3287,6 +3480,7 @@ // // 480x320, 3.5", SPI Display with Rotary Encoder from MKS // Usually paired with MKS Robin Nano V2 & V3 +// https://github.com/makerbase-mks/MKS-TFT-Hardware/tree/master/MKS%20TS35 // //#define MKS_TS35_V2_0 @@ -3351,12 +3545,14 @@ //#define ANET_ET5_TFT35 // -// 1024x600, 7", RGB Stock Display with Rotary Encoder from BIQU-BX +// 1024x600, 7", RGB Stock Display with Rotary Encoder from BIQU BX +// https://github.com/bigtreetech/BIQU-BX/tree/master/Hardware // //#define BIQU_BX_TFT70 // // 480x320, 3.5", SPI Stock Display with Rotary Encoder from BIQU B1 SE Series +// https://github.com/bigtreetech/TFT35-SPI/tree/master/v1 // //#define BTT_TFT35_SPI_V1_0 @@ -3393,8 +3589,32 @@ //#define TFT_COLOR_UI //#define TFT_LVGL_UI +#if ENABLED(TFT_COLOR_UI) + /** + * TFT Font for Color_UI. Choose one of the following: + * + * NOTOSANS - Default font with anti-aliasing. Supports Latin Extended and non-Latin characters. + * UNIFONT - Lightweight font, no anti-aliasing. Supports Latin Extended and non-Latin characters. + * HELVETICA - Lightweight font, no anti-aliasing. Supports Basic Latin (0x0020-0x007F) and Latin-1 Supplement (0x0080-0x00FF) characters only. + */ + #define TFT_FONT NOTOSANS + + /** + * TFT Theme for Color_UI. Choose one of the following or add a new one to 'Marlin/src/lcd/tft/themes' directory + * + * BLUE_MARLIN - Default theme with 'midnight blue' background + * BLACK_MARLIN - Theme with 'black' background + * ANET_BLACK - Theme used for Anet ET4/5 + */ + #define TFT_THEME BLACK_MARLIN + + //#define TFT_SHARED_IO // I/O is shared between TFT display and other devices. Disable async data transfer. + + #define COMPACT_MARLIN_BOOT_LOGO // Use compressed data to save Flash space +#endif + #if ENABLED(TFT_LVGL_UI) - //#define MKS_WIFI_MODULE // MKS WiFi module + //#define MKS_WIFI_MODULE // MKS WiFi module #endif /** @@ -3439,7 +3659,7 @@ //#define TOUCH_OFFSET_Y 257 //#define TOUCH_ORIENTATION TOUCH_LANDSCAPE - #if BOTH(TOUCH_SCREEN_CALIBRATION, EEPROM_SETTINGS) + #if ALL(TOUCH_SCREEN_CALIBRATION, EEPROM_SETTINGS) #define TOUCH_CALIBRATION_AUTO_SAVE // Auto save successful calibration values to EEPROM #endif @@ -3538,11 +3758,14 @@ //#define RGB_LED //#define RGBW_LED -#if EITHER(RGB_LED, RGBW_LED) +#if ANY(RGB_LED, RGBW_LED) //#define RGB_LED_R_PIN 34 //#define RGB_LED_G_PIN 43 //#define RGB_LED_B_PIN 35 //#define RGB_LED_W_PIN -1 +#endif + +#if ANY(RGB_LED, RGBW_LED, PCA9632) //#define RGB_STARTUP_TEST // For PWM pins, fade between all colors #if ENABLED(RGB_STARTUP_TEST) #define RGB_STARTUP_TEST_INNER_MS 10 // (ms) Reduce or increase fading speed @@ -3568,6 +3791,7 @@ #define NEOPIXEL2_PIXELS 15 // Number of LEDs in the second strip #define NEOPIXEL2_BRIGHTNESS 127 // Initial brightness (0-255) #define NEOPIXEL2_STARTUP_TEST // Cycle through colors at startup + #define NEOPIXEL_M150_DEFAULT -1 // Default strip for M150 without 'S'. Use -1 to set all by default. #else //#define NEOPIXEL2_INSERIES // Default behavior is NeoPixel 2 in parallel #endif @@ -3575,7 +3799,8 @@ // Use some of the NeoPixel LEDs for static (background) lighting //#define NEOPIXEL_BKGD_INDEX_FIRST 0 // Index of the first background LED //#define NEOPIXEL_BKGD_INDEX_LAST 5 // Index of the last background LED - //#define NEOPIXEL_BKGD_COLOR { 255, 255, 255, 0 } // R, G, B, W + //#define NEOPIXEL_BKGD_COLOR { 255, 255, 255, 0 } // R, G, B, W + //#define NEOPIXEL_BKGD_TIMEOUT_COLOR { 25, 25, 25, 0 } // R, G, B, W //#define NEOPIXEL_BKGD_ALWAYS_ON // Keep the backlight on when other NeoPixels are off #endif diff --git a/Marlin/Configuration_adv.h b/Marlin/Configuration_adv.h index 3240c91002..54e5504dd2 100644 --- a/Marlin/Configuration_adv.h +++ b/Marlin/Configuration_adv.h @@ -31,7 +31,7 @@ * Basic settings can be found in Configuration.h * */ -#define CONFIGURATION_ADV_H_VERSION 02010200 +#define CONFIGURATION_ADV_H_VERSION 02010300 // @section develop @@ -192,12 +192,10 @@ /** * Hephestos 2 24V heated bed upgrade kit. - * https://store.bq.com/en/heated-bed-kit-hephestos2 + * https://www.en3dstudios.com/product/bq-hephestos-2-heated-bed-kit/ */ //#define HEPHESTOS2_HEATED_BED_KIT #if ENABLED(HEPHESTOS2_HEATED_BED_KIT) - #undef TEMP_SENSOR_BED - #define TEMP_SENSOR_BED 70 #define HEATER_BED_INVERTING true #endif @@ -280,9 +278,15 @@ #define THERMAL_PROTECTION_BOARD // Halt the printer if the board sensor leaves the temp range below. #define BOARD_MINTEMP 8 // (°C) #define BOARD_MAXTEMP 70 // (°C) - #ifndef TEMP_BOARD_PIN - //#define TEMP_BOARD_PIN -1 // Board temp sensor pin, if not set in pins file. - #endif + //#define TEMP_BOARD_PIN -1 // Board temp sensor pin override. +#endif + +// +// SoC Sensor options +// +#if TEMP_SENSOR_SOC + #define THERMAL_PROTECTION_SOC // Halt the printer if the SoC sensor leaves the temp range below. + #define SOC_MAXTEMP 85 // (°C) #endif /** @@ -302,12 +306,15 @@ * THERMAL_PROTECTION_HYSTERESIS and/or THERMAL_PROTECTION_PERIOD */ #if ENABLED(THERMAL_PROTECTION_HOTENDS) - #define THERMAL_PROTECTION_PERIOD 15 // Seconds - #define THERMAL_PROTECTION_HYSTERESIS 30 // Degrees Celsius + #define THERMAL_PROTECTION_PERIOD 40 // (seconds) + #define THERMAL_PROTECTION_HYSTERESIS 10 // (°C) - #define ADAPTIVE_FAN_SLOWING // Slow part cooling fan if temperature drops - #if BOTH(ADAPTIVE_FAN_SLOWING, PIDTEMP) - #define NO_FAN_SLOWING_IN_PID_TUNING // Don't slow fan speed during M303 + #define ADAPTIVE_FAN_SLOWING // Slow down the part-cooling fan if the temperature drops + #if ENABLED(ADAPTIVE_FAN_SLOWING) + //#define REPORT_ADAPTIVE_FAN_SLOWING // Report fan slowing activity to the console + #if ANY(MPCTEMP, PIDTEMP) + #define TEMP_TUNING_MAINTAIN_FAN // Don't slow down the fan speed during M303 or M306 T + #endif #endif /** @@ -322,62 +329,87 @@ * and/or decrease WATCH_TEMP_INCREASE. WATCH_TEMP_INCREASE should not be set * below 2. */ - #define WATCH_TEMP_PERIOD 50 // Seconds - #define WATCH_TEMP_INCREASE 5 // Degrees Celsius + #define WATCH_TEMP_PERIOD 50 // (seconds) + #define WATCH_TEMP_INCREASE 5 // (°C) #endif /** * Thermal Protection parameters for the bed are just as above for hotends. */ #if ENABLED(THERMAL_PROTECTION_BED) - #define THERMAL_PROTECTION_BED_PERIOD 15 // Seconds - #define THERMAL_PROTECTION_BED_HYSTERESIS 10 // Degrees Celsius + #define THERMAL_PROTECTION_BED_PERIOD 15 // (seconds) + #define THERMAL_PROTECTION_BED_HYSTERESIS 10 // (°C) /** * As described above, except for the bed (M140/M190/M303). */ - #define WATCH_BED_TEMP_PERIOD 60 // Seconds - #define WATCH_BED_TEMP_INCREASE 2 // Degrees Celsius + #define WATCH_BED_TEMP_PERIOD 60 // (seconds) + #define WATCH_BED_TEMP_INCREASE 2 // (°C) #endif /** * Thermal Protection parameters for the heated chamber. */ #if ENABLED(THERMAL_PROTECTION_CHAMBER) - #define THERMAL_PROTECTION_CHAMBER_PERIOD 20 // Seconds - #define THERMAL_PROTECTION_CHAMBER_HYSTERESIS 2 // Degrees Celsius + #define THERMAL_PROTECTION_CHAMBER_PERIOD 20 // (seconds) + #define THERMAL_PROTECTION_CHAMBER_HYSTERESIS 2 // (°C) /** * Heated chamber watch settings (M141/M191). */ - #define WATCH_CHAMBER_TEMP_PERIOD 60 // Seconds - #define WATCH_CHAMBER_TEMP_INCREASE 2 // Degrees Celsius + #define WATCH_CHAMBER_TEMP_PERIOD 60 // (seconds) + #define WATCH_CHAMBER_TEMP_INCREASE 2 // (°C) #endif /** * Thermal Protection parameters for the laser cooler. */ #if ENABLED(THERMAL_PROTECTION_COOLER) - #define THERMAL_PROTECTION_COOLER_PERIOD 10 // Seconds - #define THERMAL_PROTECTION_COOLER_HYSTERESIS 3 // Degrees Celsius + #define THERMAL_PROTECTION_COOLER_PERIOD 10 // (seconds) + #define THERMAL_PROTECTION_COOLER_HYSTERESIS 3 // (°C) /** * Laser cooling watch settings (M143/M193). */ - #define WATCH_COOLER_TEMP_PERIOD 60 // Seconds - #define WATCH_COOLER_TEMP_INCREASE 3 // Degrees Celsius + #define WATCH_COOLER_TEMP_PERIOD 60 // (seconds) + #define WATCH_COOLER_TEMP_INCREASE 3 // (°C) #endif #if ANY(THERMAL_PROTECTION_HOTENDS, THERMAL_PROTECTION_BED, THERMAL_PROTECTION_CHAMBER, THERMAL_PROTECTION_COOLER) /** - * Thermal Protection Variance Monitor - EXPERIMENTAL. - * Kill the machine on a stuck temperature sensor. Disable if you get false positives. + * Thermal Protection Variance Monitor - EXPERIMENTAL + * Kill the machine on a stuck temperature sensor. + * + * This feature may cause some thermally-stable systems to halt. Be sure to test it thoroughly under + * a variety of conditions. Disable if you get false positives. + * + * This feature ensures that temperature sensors are updating regularly. If sensors die or get "stuck", + * or if Marlin stops reading them, temperatures will remain constant while heaters may still be powered! + * This feature only monitors temperature changes so it should catch any issue, hardware or software. + * + * By default it uses the THERMAL_PROTECTION_*_PERIOD constants (above) for the time window, within which + * at least one temperature change must occur, to indicate that sensor polling is working. If any monitored + * heater's temperature remains totally constant (without even a fractional change) during this period, a + * thermal malfunction error occurs and the printer is halted. + * + * A very stable heater might produce a false positive and halt the printer. In this case, try increasing + * the corresponding THERMAL_PROTECTION_*_PERIOD constant a bit. Keep in mind that uncontrolled heating + * shouldn't be allowed to persist for more than a minute or two. + * + * Be careful to distinguish false positives from real sensor issues before disabling this feature. If the + * heater's temperature appears even slightly higher than expected after restarting, you may have a real + * thermal malfunction. Check the temperature graph in your host for any unusual bumps. */ - //#define THERMAL_PROTECTION_VARIANCE_MONITOR // Detect a sensor malfunction preventing temperature updates + //#define THERMAL_PROTECTION_VARIANCE_MONITOR + #if ENABLED(THERMAL_PROTECTION_VARIANCE_MONITOR) + // Variance detection window to override the THERMAL_PROTECTION...PERIOD settings above. + // Keep in mind that some heaters heat up faster than others. + //#define THERMAL_PROTECTION_VARIANCE_MONITOR_PERIOD 30 // (s) Override all watch periods + #endif #endif #if ENABLED(PIDTEMP) - // Add an experimental additional term to the heater power, proportional to the extrusion speed. + // Add an additional term to the heater power, proportional to the extrusion speed. // A well-chosen Kc value should add just enough power to melt the increased material volume. //#define PID_EXTRUSION_SCALING #if ENABLED(PID_EXTRUSION_SCALING) @@ -386,12 +418,12 @@ #endif /** - * Add an experimental additional term to the heater power, proportional to the fan speed. + * Add an additional term to the heater power, proportional to the fan speed. * A well-chosen Kf value should add just enough power to compensate for power-loss from the cooling fan. * You can either just add a constant compensation with the DEFAULT_Kf value * or follow the instruction below to get speed-dependent compensation. * - * Constant compensation (use only with fanspeeds of 0% and 100%) + * Constant compensation (use only with fan speeds of 0% and 100%) * --------------------------------------------------------------------- * A good starting point for the Kf-value comes from the calculation: * kf = (power_fan * eff_fan) / power_heater * 255 @@ -418,7 +450,7 @@ //#define PID_FAN_SCALING_ALTERNATIVE_DEFINITION #if ENABLED(PID_FAN_SCALING_ALTERNATIVE_DEFINITION) // The alternative definition is used for an easier configuration. - // Just figure out Kf at fullspeed (255) and PID_FAN_SCALING_MIN_SPEED. + // Just figure out Kf at full speed (255) and PID_FAN_SCALING_MIN_SPEED. // DEFAULT_Kf and PID_FAN_SCALING_LIN_FACTOR are calculated accordingly. #define PID_FAN_SCALING_AT_FULL_SPEED 13.0 //=PID_FAN_SCALING_LIN_FACTOR*255+DEFAULT_Kf @@ -452,6 +484,9 @@ #define AUTOTEMP #if ENABLED(AUTOTEMP) #define AUTOTEMP_OLDWEIGHT 0.98 // Factor used to weight previous readings (0.0 < value < 1.0) + #define AUTOTEMP_MIN 210 + #define AUTOTEMP_MAX 250 + #define AUTOTEMP_FACTOR 0.1f // Turn on AUTOTEMP on M104/M109 by default using proportions set here //#define AUTOTEMP_PROPORTIONAL #if ENABLED(AUTOTEMP_PROPORTIONAL) @@ -471,10 +506,10 @@ * Thermistors able to support high temperature tend to have a hard time getting * good readings at room and lower temperatures. This means TEMP_SENSOR_X_RAW_LO_TEMP * will probably be caught when the heating element first turns on during the - * preheating process, which will trigger a min_temp_error as a safety measure + * preheating process, which will trigger a MINTEMP error as a safety measure * and force stop everything. * To circumvent this limitation, we allow for a preheat time (during which, - * min_temp_error won't be triggered) and add a min_temp buffer to handle + * MINTEMP error won't be triggered) and add a min_temp buffer to handle * aberrant readings. * * If you want to enable this feature for your hotend thermistor(s) @@ -482,7 +517,7 @@ */ // The number of consecutive low temperature errors that can occur -// before a min_temp_error is triggered. (Shouldn't be more than 10.) +// before a MINTEMP error is triggered. (Shouldn't be more than 10.) //#define MAX_CONSECUTIVE_LOW_TEMPERATURE_ERROR_ALLOWED 0 /** @@ -492,7 +527,8 @@ * the minimum temperature your thermistor can read. The lower the better/safer. * This shouldn't need to be more than 30 seconds (30000) */ -//#define MILLISECONDS_PREHEAT_TIME 0 +//#define PREHEAT_TIME_HOTEND_MS 0 +//#define PREHEAT_TIME_BED_MS 0 // @section extruder @@ -530,6 +566,8 @@ #define TEMP_SENSOR_AD8495_OFFSET 0.0 #define TEMP_SENSOR_AD8495_GAIN 1.0 +// @section fans + /** * Controller Fan * To cool down the stepper drivers and MOSFETs. @@ -540,23 +578,27 @@ #define USE_CONTROLLER_FAN #if ENABLED(USE_CONTROLLER_FAN) #if ANY(Mini, MiniV2, TazPro) - #define CONTROLLER_FAN_PIN FAN1_PIN // Set a custom pin for the controller fan + #define CONTROLLER_FAN_PIN FAN1_PIN // Set a custom pin for the controller fan #else - #define CONTROLLER_FAN_PIN FAN2_PIN // Set a custom pin for the controller fan + #define CONTROLLER_FAN_PIN FAN2_PIN // Set a custom pin for the controller fan #endif - //#define CONTROLLER_FAN_USE_Z_ONLY // With this option only the Z axis is considered + //#define CONTROLLER_FAN2_PIN -1 // Set a custom pin for second controller fan + //#define CONTROLLER_FAN_USE_Z_ONLY // With this option only the Z axis is considered #if ENABLED(MiniV2) - #define CONTROLLER_FAN_IGNORE_Z // Ignore Z stepper. Useful when stepper timeout is disabled. + #define CONTROLLER_FAN_IGNORE_Z // Ignore Z stepper. Useful when stepper timeout is disabled. #endif - #define CONTROLLERFAN_SPEED_MIN 0 // (0-255) Minimum speed. (If set below this value the fan is turned off.) - #define CONTROLLERFAN_SPEED_ACTIVE 255 // (0-255) Active speed, used when any motor is enabled - #define CONTROLLERFAN_SPEED_IDLE 120 // (0-255) Idle speed, used when motors are disabled - #define CONTROLLERFAN_IDLE_TIME 60 // (seconds) Extra time to keep the fan running after disabling motors + #define CONTROLLERFAN_SPEED_MIN 0 // (0-255) Minimum speed. (If set below this value the fan is turned off.) + #define CONTROLLERFAN_SPEED_ACTIVE 255 // (0-255) Active speed, used when any motor is enabled + #define CONTROLLERFAN_SPEED_IDLE 0 // (0-255) Idle speed, used when motors are disabled + #define CONTROLLERFAN_IDLE_TIME 60 // (seconds) Extra time to keep the fan running after disabling motors // Use TEMP_SENSOR_BOARD as a trigger for enabling the controller fan //#define CONTROLLER_FAN_MIN_BOARD_TEMP 40 // (°C) Turn on the fan if the board reaches this temperature - #define CONTROLLER_FAN_EDITABLE // Enable M710 configurable settings + // Use TEMP_SENSOR_SOC as a trigger for enabling the controller fan + //#define CONTROLLER_FAN_MIN_SOC_TEMP 40 // (°C) Turn on the fan if the SoC reaches this temperature + + #define CONTROLLER_FAN_EDITABLE // Enable M710 configurable settings #if ENABLED(CONTROLLER_FAN_EDITABLE) #define CONTROLLER_FAN_MENU // Enable the Controller Fan submenu #endif @@ -598,7 +640,7 @@ * FAST_PWM_FAN_FREQUENCY * Set this to your desired frequency. * For AVR, if left undefined this defaults to F = F_CPU/(2*255*1) - * i.e., F = 31.4kHz on 16MHz microcontrollers or F = 39.2kHz on 20MHz microcontrollers. + * i.e., F = 31.4kHz on 16MHz micro-controllers or F = 39.2kHz on 20MHz micro-controllers. * For non AVR, if left undefined this defaults to F = 1Khz. * This F value is only to protect the hardware from an absence of configuration * and not to complete it when users are not aware that the frequency must be specifically set to support the target board. @@ -631,11 +673,12 @@ #endif /** - * Use one of the PWM fans as a redundant part-cooling fan + * Assign more PWM fans for part cooling, synchronized with Fan 0 */ -//#define REDUNDANT_PART_COOLING_FAN 2 // Index of the fan to sync with FAN 0. - -// @section extruder +//#define REDUNDANT_PART_COOLING_FAN 1 // Index of the first fan to synchronize with Fan 0 +#ifdef REDUNDANT_PART_COOLING_FAN + //#define NUM_REDUNDANT_FANS 1 // Number of sequential fans to synchronize with Fan 0 +#endif /** * Extruder cooling fans @@ -713,6 +756,7 @@ #define FANMUX2_PIN -1 /** + * @section caselight * M355 Case Light on-off / brightness */ //#define CASE_LIGHT_ENABLE @@ -727,15 +771,15 @@ #if ENABLED(NEOPIXEL_LED) //#define CASE_LIGHT_USE_NEOPIXEL // Use NeoPixel LED as case light #endif - #if EITHER(RGB_LED, RGBW_LED) + #if ANY(RGB_LED, RGBW_LED) //#define CASE_LIGHT_USE_RGB_LED // Use RGB / RGBW LED as case light #endif - #if EITHER(CASE_LIGHT_USE_NEOPIXEL, CASE_LIGHT_USE_RGB_LED) + #if ANY(CASE_LIGHT_USE_NEOPIXEL, CASE_LIGHT_USE_RGB_LED) #define CASE_LIGHT_DEFAULT_COLOR { 255, 255, 255, 255 } // { Red, Green, Blue, White } #endif #endif -// @section homing +// @section endstops // If you want endstops to stay on (by default) even when not homing // enable this option. Override at any time with M120, M121. @@ -752,6 +796,8 @@ //#define CLOSED_LOOP_MOVE_COMPLETE_PIN -1 #endif +// @section idex + /** * Dual X Carriage * @@ -786,7 +832,6 @@ #define X1_MAX_POS X_BED_SIZE // A max coordinate so the X1 carriage can't hit the parked X2 carriage #define X2_MIN_POS 80 // A min coordinate so the X2 carriage can't hit the parked X1 carriage #define X2_MAX_POS 353 // The max position of the X2 carriage, typically also the home position - #define X2_HOME_DIR 1 // Set to 1. The X2 carriage always homes to the max endstop position #define X2_HOME_POS X2_MAX_POS // Default X2 home position. Set to X2_MAX_POS. // NOTE: For Dual X Carriage use M218 T1 Xn to override the X2_HOME_POS. // This allows recalibration of endstops distance without a rebuild. @@ -802,6 +847,8 @@ //#define EVENT_GCODE_IDEX_AFTER_MODECHANGE "G28X" #endif +// @section multi stepper + /** * Multi-Stepper / Multi-Endstop * @@ -820,22 +867,22 @@ * Get the offset by homing X and measuring the error. * Also set with 'M666 X' and stored to EEPROM with 'M500'. * - * - Use X2_USE_ENDSTOP to set the endstop plug by name. (_XMIN_, _XMAX_, _YMIN_, _YMAX_, _ZMIN_, _ZMAX_) + * - Define the extra endstop pins here to override defaults. No auto-assignment. */ #if HAS_X2_STEPPER && DISABLED(DUAL_X_CARRIAGE) //#define INVERT_X2_VS_X_DIR // X2 direction signal is the opposite of X //#define X_DUAL_ENDSTOPS // X2 has its own endstop #if ENABLED(X_DUAL_ENDSTOPS) - #define X2_USE_ENDSTOP _XMAX_ // X2 endstop board plug. Don't forget to enable USE_*_PLUG. + //#define X2_STOP_PIN X_MAX_PIN // X2 endstop pin override #define X2_ENDSTOP_ADJUSTMENT 0 // X2 offset relative to X endstop #endif #endif -#if HAS_DUAL_Y_STEPPERS +#if HAS_Y2_STEPPER //#define INVERT_Y2_VS_Y_DIR // Y2 direction signal is the opposite of Y //#define Y_DUAL_ENDSTOPS // Y2 has its own endstop #if ENABLED(Y_DUAL_ENDSTOPS) - #define Y2_USE_ENDSTOP _YMAX_ // Y2 endstop board plug. Don't forget to enable USE_*_PLUG. + //#define Y2_STOP_PIN Y_MAX_PIN // Y2 endstop pin override #define Y2_ENDSTOP_ADJUSTMENT 0 // Y2 offset relative to Y endstop #endif #endif @@ -848,21 +895,21 @@ //#define Z_MULTI_ENDSTOPS // Other Z axes have their own endstops #if ENABLED(Z_MULTI_ENDSTOPS) - #define Z2_USE_ENDSTOP _XMAX_ // Z2 endstop board plug. Don't forget to enable USE_*_PLUG. - #define Z2_ENDSTOP_ADJUSTMENT 0 // Z2 offset relative to Y endstop + //#define Z2_STOP_PIN X_MAX_PIN // Z2 endstop pin override + #define Z2_ENDSTOP_ADJUSTMENT 0 // Z2 offset relative to Z endstop #endif #ifdef Z3_DRIVER_TYPE //#define INVERT_Z3_VS_Z_DIR // Z3 direction signal is the opposite of Z #if ENABLED(Z_MULTI_ENDSTOPS) - #define Z3_USE_ENDSTOP _YMAX_ // Z3 endstop board plug. Don't forget to enable USE_*_PLUG. - #define Z3_ENDSTOP_ADJUSTMENT 0 // Z3 offset relative to Y endstop + //#define Z3_STOP_PIN Y_MAX_PIN // Z3 endstop pin override + #define Z3_ENDSTOP_ADJUSTMENT 0 // Z3 offset relative to Z endstop #endif #endif #ifdef Z4_DRIVER_TYPE //#define INVERT_Z4_VS_Z_DIR // Z4 direction signal is the opposite of Z #if ENABLED(Z_MULTI_ENDSTOPS) - #define Z4_USE_ENDSTOP _ZMAX_ // Z4 endstop board plug. Don't forget to enable USE_*_PLUG. - #define Z4_ENDSTOP_ADJUSTMENT 0 // Z4 offset relative to Y endstop + //#define Z4_STOP_PIN Z_MAX_PIN // Z4 endstop pin override + #define Z4_ENDSTOP_ADJUSTMENT 0 // Z4 offset relative to Z endstop #endif #endif #endif @@ -873,6 +920,8 @@ //#define INVERT_E1_VS_E0_DIR // E direction signals are opposites #endif +// @section extruder + // Activate a solenoid on the active extruder with M380. Disable all with M381. // Define SOL0_PIN, SOL1_PIN, etc., for each extruder that has a solenoid. //#define EXT_SOLENOID @@ -900,7 +949,7 @@ #define QUICK_HOME // If G28 contains XY do a diagonal move first //#define HOME_Y_BEFORE_X // If G28 contains XY home Y before X -//#define HOME_Z_FIRST // Home Z first. Requires a Z-MIN endstop (not a probe). +//#define HOME_Z_FIRST // Home Z first. Requires a real endstop (not a probe). //#define CODEPENDENT_XY_HOMING // If X/Y can't home without homing Y/X first // @section bltouch @@ -945,12 +994,15 @@ * Danger: Don't activate 5V mode unless attached to a 5V-tolerant controller! * V3.0 or 3.1: Set default mode to 5V mode at Marlin startup. * If disabled, OD mode is the hard-coded default on 3.0 - * On startup, Marlin will compare its eeprom to this value. If the selected mode - * differs, a mode set eeprom write will be completed at initialization. - * Use the option below to force an eeprom write to a V3.1 probe regardless. + * On startup, Marlin will compare its EEPROM to this value. If the selected mode + * differs, a mode set EEPROM write will be completed at initialization. + * Use the option below to force an EEPROM write to a V3.1 probe regardless. */ //#define BLTOUCH_SET_5V_MODE + // Safety: Enable voltage mode settings in the LCD menu. + //#define BLTOUCH_LCD_VOLTAGE_MENU + /** * Safety: Activate if connecting a probe with an unknown voltage mode. * V3.0: Set a probe into mode selected above at Marlin startup. Required for 5V mode on 3.0 @@ -969,12 +1021,16 @@ */ //#define BLTOUCH_HS_MODE true - // Safety: Enable voltage mode settings in the LCD menu. - //#define BLTOUCH_LCD_VOLTAGE_MENU + #ifdef BLTOUCH_HS_MODE + // The probe Z offset (M851 Z) is the height at which the probe triggers. + // This must be large enough to keep the probe pin off the bed and prevent + // it from snagging on the bed clips. + #define BLTOUCH_HS_EXTRA_CLEARANCE 7 // Extra Z Clearance + #endif #endif // BLTOUCH -// @section extras +// @section calibration /** * Z Steppers Auto-Alignment @@ -1048,7 +1104,7 @@ //#define ASSISTED_TRAMMING #if ENABLED(ASSISTED_TRAMMING) - // Define positions for probe points. + // Define from 3 to 9 points to probe. #define TRAMMING_POINT_XY { { 20, 20 }, { 180, 20 }, { 180, 180 }, { 20, 180 } } // Define position names for probe points. @@ -1074,21 +1130,86 @@ #endif -// @section motion +// @section motion control + +/** + * Fixed-time-based Motion Control -- EXPERIMENTAL + * Enable/disable and set parameters with G-code M493. + */ +//#define FT_MOTION +#if ENABLED(FT_MOTION) + #define FTM_DEFAULT_MODE ftMotionMode_DISABLED // Default mode of fixed time control. (Enums in ft_types.h) + #define FTM_DEFAULT_DYNFREQ_MODE dynFreqMode_DISABLED // Default mode of dynamic frequency calculation. (Enums in ft_types.h) + #define FTM_SHAPING_DEFAULT_X_FREQ 37.0f // (Hz) Default peak frequency used by input shapers + #define FTM_SHAPING_DEFAULT_Y_FREQ 37.0f // (Hz) Default peak frequency used by input shapers + #define FTM_LINEAR_ADV_DEFAULT_ENA false // Default linear advance enable (true) or disable (false) + #define FTM_LINEAR_ADV_DEFAULT_K 0.0f // Default linear advance gain + #define FTM_SHAPING_ZETA_X 0.1f // Zeta used by input shapers for X axis + #define FTM_SHAPING_ZETA_Y 0.1f // Zeta used by input shapers for Y axis + + #define FTM_SHAPING_V_TOL_X 0.05f // Vibration tolerance used by EI input shapers for X axis + #define FTM_SHAPING_V_TOL_Y 0.05f // Vibration tolerance used by EI input shapers for Y axis + + //#define FT_MOTION_MENU // Provide a MarlinUI menu to set M493 parameters + + /** + * Advanced configuration + */ + #define FTM_UNIFIED_BWS // DON'T DISABLE unless you use Ulendo FBS (not implemented) + #if ENABLED(FTM_UNIFIED_BWS) + #define FTM_BW_SIZE 100 // Unified Window and Batch size with a ratio of 2 + #else + #define FTM_WINDOW_SIZE 200 // Custom Window size for trajectory generation needed by Ulendo FBS + #define FTM_BATCH_SIZE 100 // Custom Batch size for trajectory generation needed by Ulendo FBS + #endif + + #define FTM_FS 1000 // (Hz) Frequency for trajectory generation. (Reciprocal of FTM_TS) + #define FTM_TS 0.001f // (s) Time step for trajectory generation. (Reciprocal of FTM_FS) + + // These values may be configured to adjust the duration of loop(). + #define FTM_STEPS_PER_LOOP 60 // Number of stepper commands to generate each loop() + #define FTM_POINTS_PER_LOOP 100 // Number of trajectory points to generate each loop() + + #if DISABLED(COREXY) + #define FTM_STEPPER_FS 20000 // (Hz) Frequency for stepper I/O update + + // Use this to adjust the time required to consume the command buffer. + // Try increasing this value if stepper motion is choppy. + #define FTM_STEPPERCMD_BUFF_SIZE 3000 // Size of the stepper command buffers + // (FTM_STEPS_PER_LOOP * FTM_POINTS_PER_LOOP) is a good start + // If you run out of memory, fall back to 3000 and increase progressively + #else + // CoreXY motion needs a larger buffer size. These values are based on our testing. + #define FTM_STEPPER_FS 30000 + #define FTM_STEPPERCMD_BUFF_SIZE 6000 + #endif + + #define FTM_STEPS_PER_UNIT_TIME (FTM_STEPPER_FS / FTM_FS) // Interpolated stepper commands per unit time + #define FTM_CTS_COMPARE_VAL (FTM_STEPS_PER_UNIT_TIME / 2) // Comparison value used in interpolation algorithm + #define FTM_MIN_TICKS ((STEPPER_TIMER_RATE) / (FTM_STEPPER_FS)) // Minimum stepper ticks between steps + + #define FTM_MIN_SHAPE_FREQ 10 // Minimum shaping frequency + #define FTM_RATIO (FTM_FS / FTM_MIN_SHAPE_FREQ) // Factor for use in FTM_ZMAX. DON'T CHANGE. + #define FTM_ZMAX (FTM_RATIO * 2) // Maximum delays for shaping functions (even numbers only!) + // Calculate as: + // ZV : FTM_RATIO / 2 + // ZVD, MZV : FTM_RATIO + // 2HEI : FTM_RATIO * 3 / 2 + // 3HEI : FTM_RATIO * 2 +#endif /** * Input Shaping -- EXPERIMENTAL * * Zero Vibration (ZV) Input Shaping for X and/or Y movements. * - * This option uses a lot of SRAM for the step buffer, which is related to the - * largest step rate possible for the shaped axes. If the build fails due to - * low SRAM the buffer size may be reduced by setting smaller values for - * DEFAULT_AXIS_STEPS_PER_UNIT and/or DEFAULT_MAX_FEEDRATE. Disabling - * ADAPTIVE_STEP_SMOOTHING and reducing the step rate for non-shaped axes may - * also reduce the buffer sizes. Runtime editing of max feedrate (M203) or - * resonant frequency (M593) may result in input shaping losing effectiveness - * during high speed movements to prevent buffer overruns. + * This option uses a lot of SRAM for the step buffer. The buffer size is + * calculated automatically from SHAPING_FREQ_[XY], DEFAULT_AXIS_STEPS_PER_UNIT, + * DEFAULT_MAX_FEEDRATE and ADAPTIVE_STEP_SMOOTHING. The default calculation can + * be overridden by setting SHAPING_MIN_FREQ and/or SHAPING_MAX_FEEDRATE. + * The higher the frequency and the lower the feedrate, the smaller the buffer. + * If the buffer is too small at runtime, input shaping will have reduced + * effectiveness during high speed movements. * * Tune with M593 D F: * @@ -1100,53 +1221,55 @@ */ //#define INPUT_SHAPING_X //#define INPUT_SHAPING_Y -#if EITHER(INPUT_SHAPING_X, INPUT_SHAPING_Y) +#if ANY(INPUT_SHAPING_X, INPUT_SHAPING_Y) #if ENABLED(INPUT_SHAPING_X) - #define SHAPING_FREQ_X 40 // (Hz) The default dominant resonant frequency on the X axis. - #define SHAPING_ZETA_X 0.15f // Damping ratio of the X axis (range: 0.0 = no damping to 1.0 = critical damping). + #define SHAPING_FREQ_X 40 // (Hz) The default dominant resonant frequency on the X axis. + #define SHAPING_ZETA_X 0.15f // Damping ratio of the X axis (range: 0.0 = no damping to 1.0 = critical damping). #endif #if ENABLED(INPUT_SHAPING_Y) - #define SHAPING_FREQ_Y 40 // (Hz) The default dominant resonant frequency on the Y axis. - #define SHAPING_ZETA_Y 0.15f // Damping ratio of the Y axis (range: 0.0 = no damping to 1.0 = critical damping). + #define SHAPING_FREQ_Y 40 // (Hz) The default dominant resonant frequency on the Y axis. + #define SHAPING_ZETA_Y 0.15f // Damping ratio of the Y axis (range: 0.0 = no damping to 1.0 = critical damping). #endif - //#define SHAPING_MENU // Add a menu to the LCD to set shaping parameters. + //#define SHAPING_MIN_FREQ 20 // By default the minimum of the shaping frequencies. Override to affect SRAM usage. + //#define SHAPING_MAX_STEPRATE 10000 // By default the maximum total step rate of the shaped axes. Override to affect SRAM usage. + //#define SHAPING_MENU // Add a menu to the LCD to set shaping parameters. #endif +// @section motion + #define AXIS_RELATIVE_MODES { false, false, false, false } // Add a Duplicate option for well-separated conjoined nozzles //#define MULTI_NOZZLE_DUPLICATION -// By default pololu step drivers require an active high signal. However, some high power drivers require an active low signal as step. -#define INVERT_X_STEP_PIN false -#define INVERT_Y_STEP_PIN false -#define INVERT_Z_STEP_PIN false -#define INVERT_I_STEP_PIN false -#define INVERT_J_STEP_PIN false -#define INVERT_K_STEP_PIN false -#define INVERT_U_STEP_PIN false -#define INVERT_V_STEP_PIN false -#define INVERT_W_STEP_PIN false -#define INVERT_E_STEP_PIN false +// By default stepper drivers require an active-HIGH signal but some high-power drivers require an active-LOW signal to step. +#define STEP_STATE_X HIGH +#define STEP_STATE_Y HIGH +#define STEP_STATE_Z HIGH +#define STEP_STATE_I HIGH +#define STEP_STATE_J HIGH +#define STEP_STATE_K HIGH +#define STEP_STATE_U HIGH +#define STEP_STATE_V HIGH +#define STEP_STATE_W HIGH +#define STEP_STATE_E HIGH /** * Idle Stepper Shutdown - * Set DISABLE_INACTIVE_? 'true' to shut down axis steppers after an idle period. - * The Deactive Time can be overridden with M18 and M84. Set to 0 for No Timeout. + * Enable DISABLE_IDLE_* to shut down axis steppers after an idle period. + * The default timeout duration can be overridden with M18 and M84. Set to 0 for No Timeout. */ -#define DEFAULT_STEPPER_DEACTIVE_TIME 240 -#define DISABLE_INACTIVE_X true -#define DISABLE_INACTIVE_Y true -#if ANY(TazPro, MiniV2) - #define DISABLE_INACTIVE_Z true // Set to false if the nozzle will fall down on your printed part when print has finished. -#endif -#define DISABLE_INACTIVE_I true -#define DISABLE_INACTIVE_J true -#define DISABLE_INACTIVE_K true -#define DISABLE_INACTIVE_U true -#define DISABLE_INACTIVE_V true -#define DISABLE_INACTIVE_W true -#define DISABLE_INACTIVE_E true +#define DEFAULT_STEPPER_TIMEOUT_SEC 120 +#define DISABLE_IDLE_X +#define DISABLE_IDLE_Y +#define DISABLE_IDLE_Z // Disable if the nozzle could fall onto your printed part! +//#define DISABLE_IDLE_I +//#define DISABLE_IDLE_J +//#define DISABLE_IDLE_K +//#define DISABLE_IDLE_U +//#define DISABLE_IDLE_V +//#define DISABLE_IDLE_W +#define DISABLE_IDLE_E // Shut down all idle extruders // If the Nozzle or Bed falls when the Z stepper is disabled, set its resting position here. //#define Z_AFTER_DEACTIVATE Z_HOME_POS @@ -1181,14 +1304,9 @@ */ //#define XY_FREQUENCY_LIMIT 10 // (Hz) Maximum frequency of small zigzag infill moves. Set with M201 F. #ifdef XY_FREQUENCY_LIMIT - #define XY_FREQUENCY_MIN_PERCENT 5 // (percent) Minimum FR percentage to apply. Set with M201 G. + #define XY_FREQUENCY_MIN_PERCENT 5 // (%) Minimum FR percentage to apply. Set with M201 G. #endif -// Minimum planner junction speed. Sets the default minimum speed the planner plans for at the end -// of the buffer and all stops. This should not be much greater than zero and should only be changed -// if unwanted behavior is observed on a user's machine when running at very slow speeds. -#define MINIMUM_PLANNER_SPEED 0.05 // (mm/s) - // // Backlash Compensation // Adds extra movement to axes on direction-changes to account for backlash. @@ -1326,7 +1444,7 @@ //#define CALIBRATION_MEASURE_WMAX // Probing at the exact top center only works if the center is flat. If - // probing on a screwhead or hollow washer, probe near the edges. + // probing on a screw head or hollow washer, probe near the edges. //#define CALIBRATION_MEASURE_AT_TOP_EDGES // Define the pin to read during calibration @@ -1338,6 +1456,12 @@ #endif #endif +/** + * Multi-stepping sends steps in bursts to reduce MCU usage for high step-rates. + * This allows higher feedrates than the MCU could otherwise support. + */ +#define MULTISTEPPING_LIMIT 16 //: [1, 2, 4, 8, 16, 32, 64, 128] + /** * Adaptive Step Smoothing increases the resolution of multi-axis moves, particularly at step frequencies * below 1kHz (for AVR) or 10kHz (for ARM), where aliasing between axes in multi-axis moves causes audible @@ -1394,7 +1518,7 @@ */ //#define DIGIPOT_MCP4018 // Requires https://github.com/felias-fogg/SlowSoftI2CMaster //#define DIGIPOT_MCP4451 -#if EITHER(DIGIPOT_MCP4018, DIGIPOT_MCP4451) +#if ANY(DIGIPOT_MCP4018, DIGIPOT_MCP4451) #define DIGIPOT_I2C_NUM_CHANNELS 8 // 5DPRINT:4 AZTEEG_X3_PRO:8 MKS_SBASE:5 MIGHTYBOARD_REVE:5 // Actual motor currents in Amps. The number of entries must match DIGIPOT_I2C_NUM_CHANNELS. @@ -1446,12 +1570,7 @@ #define FEEDRATE_CHANGE_BEEP_FREQUENCY 440 #endif -// -// LCD Backlight Timeout -// -//#define LCD_BACKLIGHT_TIMEOUT_MINS 1 // (minutes) Timeout before turning off the backlight - -#if HAS_BED_PROBE && EITHER(HAS_MARLINUI_MENU, HAS_TFT_LVGL_UI) +#if HAS_BED_PROBE && ANY(HAS_MARLINUI_MENU, HAS_TFT_LVGL_UI) //#define PROBE_OFFSET_WIZARD // Add a Probe Z Offset calibration option to the LCD menu #if ENABLED(PROBE_OFFSET_WIZARD) /** @@ -1493,31 +1612,74 @@ #define LCD_PRINTER_INFO_IS_BOOTSCREEN // Show bootscreen(s) instead of Printer Info pages #endif + /** + * MarlinUI "Move Axis" menu distances. Comma-separated list. + * Values are displayed as-defined, so always use plain numbers here. + * Axis moves <= 1/2 the axis length and Extruder moves <= EXTRUDE_MAXLENGTH + * will be shown in the move submenus. + */ + #define MANUAL_MOVE_DISTANCE_MM 10, 1.0, 0.1 // (mm) + //#define MANUAL_MOVE_DISTANCE_MM 100, 50, 10, 1.0, 0.1 // (mm) + //#define MANUAL_MOVE_DISTANCE_MM 500, 100, 50, 10, 1.0, 0.1 // (mm) + + // Manual move distances for INCH_MODE_SUPPORT + #define MANUAL_MOVE_DISTANCE_IN 0.100, 0.010, 0.001 // (in) + //#define MANUAL_MOVE_DISTANCE_IN 1.000, 0.500, 0.100, 0.010, 0.001 // (in) + //#define MANUAL_MOVE_DISTANCE_IN 5.000, 1.000, 0.500, 0.100, 0.010, 0.001 // (in) + + // Manual move distances for rotational axes + #define MANUAL_MOVE_DISTANCE_DEG 90, 45, 22.5, 5, 1 // (°) + // BACK menu items keep the highlight at the top #define TURBO_BACK_MENU_ITEM // Insert a menu for preheating at the top level to allow for quick access //#define PREHEAT_SHORTCUT_MENU_ITEM + // Add Configuration > Debug Menu > Endstop Test for endstop/probe/runout testing + //#define LCD_ENDSTOP_TEST + #endif // HAS_MARLINUI_MENU -#if ANY(HAS_DISPLAY, DWIN_LCD_PROUI, DWIN_CREALITY_LCD_JYERSUI) - //#define SOUND_MENU_ITEM // Add a mute option to the LCD menu - #define SOUND_ON_DEFAULT // Buzzer/speaker default enabled state -#endif - - #define LCD_TIMEOUT_TO_STATUS 15000 // (ms) -#if EITHER(HAS_DISPLAY, DWIN_LCD_PROUI) - // The timeout to return to the status screen from sub-menus - #define LCD_TIMEOUT_TO_STATUS 15000 // (ms) - +#if HAS_DISPLAY + /** + * *** VENDORS PLEASE READ *** + * + * Marlin allows you to add a custom boot image for Graphical LCDs. + * With this option Marlin will first show your custom screen followed + * by the standard Marlin logo with version number and web URL. + * + * We encourage you to take advantage of this new feature and we also + * respectfully request that you retain the unmodified Marlin boot screen. + */ + #define SHOW_BOOTSCREEN // Show the Marlin bootscreen on startup. ** ENABLE FOR PRODUCTION ** #if ENABLED(SHOW_BOOTSCREEN) - #define BOOTSCREEN_TIMEOUT 4000 // (ms) Total Duration to display the boot screen(s) - #if EITHER(HAS_MARLINUI_U8GLIB, TFT_COLOR_UI) + #define BOOTSCREEN_TIMEOUT 3000 // (ms) Total Duration to display the boot screen(s) + #if ANY(HAS_MARLINUI_U8GLIB, TFT_COLOR_UI) #define BOOT_MARLIN_LOGO_SMALL // Show a smaller Marlin logo on the Boot Screen (saving lots of flash) #endif + #if HAS_MARLINUI_U8GLIB + //#define BOOT_MARLIN_LOGO_ANIMATED // Animated Marlin logo. Costs ~3260 (or ~940) bytes of flash. + #endif + #if ANY(HAS_MARLINUI_U8GLIB, TOUCH_UI_FTDI_EVE) + //#define SHOW_CUSTOM_BOOTSCREEN // Show the bitmap in Marlin/_Bootscreen.h on startup. + #endif #endif + #if HAS_MARLINUI_U8GLIB + //#define CUSTOM_STATUS_SCREEN_IMAGE // Show the bitmap in Marlin/_Statusscreen.h on the status screen. + #endif + + //#define SOUND_MENU_ITEM // Add a mute option to the LCD menu + #define SOUND_ON_DEFAULT // Buzzer/speaker default enabled state + + #if HAS_WIRED_LCD + //#define DOUBLE_LCD_FRAMERATE // Not recommended for slow boards. + #endif + + // The timeout to return to the status screen from sub-menus + #define LCD_TIMEOUT_TO_STATUS 15000 // (ms) + // Scroll a longer status message into view #define STATUS_MESSAGE_SCROLLING @@ -1530,6 +1692,9 @@ // Show the E position (filament used) during printing //#define LCD_SHOW_E_TOTAL + // Display a negative temperature instead of "err" + //#define SHOW_TEMPERATURE_BELOW_ZERO + /** * LED Control Menu * Add LED Control to the LCD menu @@ -1555,29 +1720,40 @@ #endif #endif -#endif // HAS_DISPLAY || DWIN_LCD_PROUI +#endif // HAS_DISPLAY -// Add the G-code 'M73' to set / report the current job progress +#if HAS_FEEDRATE_EDIT + #define SPEED_EDIT_MIN 10 // (%) Feedrate percentage edit range minimum + #define SPEED_EDIT_MAX 999 // (%) Feedrate percentage edit range maximum +#endif +#if HAS_FLOW_EDIT + #define FLOW_EDIT_MIN 10 // (%) Flow percentage edit range minimum + #define FLOW_EDIT_MAX 999 // (%) Flow percentage edit range maximum +#endif + +// Add 'M73' to set print job progress, overrides Marlin's built-in estimate #define SET_PROGRESS_MANUALLY #if ENABLED(SET_PROGRESS_MANUALLY) - #define SET_PROGRESS_PERCENT // Add 'P' parameter to set percentage done, otherwise use Marlin's estimate - #define SET_REMAINING_TIME // Add 'R' parameter to set remaining time, otherwise use Marlin's estimate + #define SET_PROGRESS_PERCENT // Add 'P' parameter to set percentage done + #define SET_REMAINING_TIME // Add 'R' parameter to set remaining time //#define SET_INTERACTION_TIME // Add 'C' parameter to set time until next filament change or other user interaction + //#define M73_REPORT // Report M73 values to host + #if ALL(M73_REPORT, HAS_MEDIA) + #define M73_REPORT_SD_ONLY // Report only when printing from SD + #endif +#endif + +// LCD Print Progress options. Multiple times may be displayed in turn. +#if HAS_DISPLAY && ANY(HAS_MEDIA, SET_PROGRESS_MANUALLY) + #define SHOW_PROGRESS_PERCENT // Show print progress percentage (doesn't affect progress bar) + #define SHOW_ELAPSED_TIME // Display elapsed printing time (prefix 'E') + //#define SHOW_REMAINING_TIME // Display estimated time to completion (prefix 'R') #if ENABLED(SET_INTERACTION_TIME) #define SHOW_INTERACTION_TIME // Display time until next user interaction ('C' = filament change) #endif - //#define M73_REPORT // Report progress to host with 'M73' -#endif - -// LCD Print Progress options, multiple can be rotated depending on screen layout -#if HAS_DISPLAY && EITHER(SDSUPPORT, SET_PROGRESS_MANUALLY) - #define SHOW_PROGRESS_PERCENT // Show print progress percentage (doesn't affect progress bar) - #define SHOW_ELAPSED_TIME // Display elapsed printing time (prefix 'E') - #define SHOW_REMAINING_TIME // Display estimated time to completion (prefix 'R') - //#define PRINT_PROGRESS_SHOW_DECIMALS // Show/report progress with decimal digits, not all UIs support this - #if EITHER(HAS_MARLINUI_HD44780, IS_TFTGLCD_PANEL) + #if ANY(HAS_MARLINUI_HD44780, IS_TFTGLCD_PANEL) //#define LCD_PROGRESS_BAR // Show a progress bar on HD44780 LCDs for SD printing #if ENABLED(LCD_PROGRESS_BAR) #define PROGRESS_BAR_BAR_TIME 2000 // (ms) Amount of time to show the bar @@ -1589,7 +1765,7 @@ #endif #endif -#if ENABLED(SDSUPPORT) +#if HAS_MEDIA /** * SD Card SPI Speed * May be required to resolve "volume init" errors. @@ -1626,6 +1802,7 @@ //#define NO_SD_AUTOSTART // Remove auto#.g file support completely to save some Flash, SRAM //#define MENU_ADDAUTOSTART // Add a menu option to run auto#.g files + //#define ONE_CLICK_PRINT // Prompt to print the newest file on inserted media //#define BROWSE_MEDIA_ON_INSERT // Open the file browser when media is inserted //#define MEDIA_MENU_AT_TOP // Force the media menu to be listed on the top of the main menu @@ -1694,9 +1871,10 @@ // SD Card Sorting options #if ENABLED(SDCARD_SORT_ALPHA) + #define SDSORT_REVERSE false // Default to sorting file names in reverse order. #define SDSORT_LIMIT 40 // Maximum number of sorted items (10-256). Costs 27 bytes each. - #define FOLDER_SORTING -1 // -1=above 0=none 1=below - #define SDSORT_GCODE false // Allow turning sorting on/off with LCD and M34 G-code. + #define SDSORT_FOLDERS -1 // -1=above 0=none 1=below + #define SDSORT_GCODE false // Enable G-code M34 to set sorting behaviors: M34 S<-1|0|1> F<-1|0|1> #define SDSORT_USES_RAM false // Pre-allocate a static array for faster pre-sorting. #define SDSORT_USES_STACK false // Prefer the stack for pre-sorting to give back some SRAM. (Negated by next 2 options.) #define SDSORT_CACHE_NAMES false // Keep sorted items in RAM longer for speedy performance. Most expensive option. @@ -1833,7 +2011,7 @@ #define DEFAULT_SHARED_VOLUME SV_USB_FLASH_DRIVE #endif -#endif // SDSUPPORT +#endif // HAS_MEDIA /** * By default an onboard SD card reader may be shared as a USB mass- @@ -1901,7 +2079,7 @@ #endif /** - * Status (Info) Screen customizations + * Status (Info) Screen customization * These options may affect code size and screen render time. * Custom status screens can forcibly override these settings. */ @@ -1917,8 +2095,10 @@ //#define STATUS_ALT_BED_BITMAP // Use the alternative bed bitmap //#define STATUS_ALT_FAN_BITMAP // Use the alternative fan bitmap //#define STATUS_FAN_FRAMES 3 // :[0,1,2,3,4] Number of fan animation frames + + // Only one STATUS_HEAT_* option can be enabled //#define STATUS_HEAT_PERCENT // Show heating in a progress bar - //#define BOOT_MARLIN_LOGO_ANIMATED // Animated Marlin logo. Costs ~3260 (or ~940) bytes of flash. + //#define STATUS_HEAT_POWER // Show heater output power as a vertical bar // Frivolous Game Options //#define MARLIN_BRICKOUT @@ -1946,11 +2126,11 @@ #define DGUS_UPDATE_INTERVAL_MS 500 // (ms) Interval between automatic screen updates - #if ANY(DGUS_LCD_UI_FYSETC, DGUS_LCD_UI_MKS, DGUS_LCD_UI_HIPRECY) + #if DGUS_UI_IS(FYSETC, MKS, HIPRECY) #define DGUS_PRINT_FILENAME // Display the filename during printing #define DGUS_PREHEAT_UI // Display a preheat screen during heatup - #if EITHER(DGUS_LCD_UI_FYSETC, DGUS_LCD_UI_MKS) + #if DGUS_UI_IS(FYSETC, MKS) //#define DGUS_UI_MOVE_DIS_OPTION // Disabled by default for FYSETC and MKS #else #define DGUS_UI_MOVE_DIS_OPTION // Enabled by default for UI_HIPRECY @@ -1967,6 +2147,22 @@ #define DGUS_UI_WAITING_STATUS 10 #define DGUS_UI_WAITING_STATUS_PERIOD 8 // Increase to slower waiting status looping #endif + + #elif DGUS_UI_IS(E3S1PRO) + /** + * The stock Ender-3 S1 Pro/Plus display firmware has rather poor SD file handling. + * + * The autoscroll is mainly useful for status messages, filenames, and the "About" page. + * + * NOTE: The Advanced SD Card option is affected by the stock touchscreen firmware, so + * pages 5 and up will display "4/4". This may get fixed in a screen firmware update. + */ + #define DGUS_SOFTWARE_AUTOSCROLL // Enable long text software auto-scroll + #define DGUS_AUTOSCROLL_START_CYCLES 1 // Refresh cycles without scrolling at the beginning of text strings + #define DGUS_AUTOSCROLL_END_CYCLES 1 // ... at the end of text strings + + #define DGUS_ADVANCED_SDCARD // Allow more than 20 files and navigating directories + #define DGUS_USERCONFIRM // Reuse the SD Card page to show various messages #endif #endif // HAS_DGUS_LCD @@ -1998,7 +2194,7 @@ // // Specify additional languages for the UI. Default specified by LCD_LANGUAGE. // -#if ANY(DOGLCD, TFT_COLOR_UI, TOUCH_UI_FTDI_EVE, IS_DWIN_MARLINUI) +#if ANY(DOGLCD, TFT_COLOR_UI, TOUCH_UI_FTDI_EVE, IS_DWIN_MARLINUI, ANYCUBIC_LCD_VYPER) //#define LCD_LANGUAGE_2 fr //#define LCD_LANGUAGE_3 de //#define LCD_LANGUAGE_4 es @@ -2109,6 +2305,15 @@ //#define TFT_BTOKMENU_COLOR 0x145F // 00010 100010 11111 Cyan #endif +// +// LCD Backlight Timeout +// Requires a display with a controllable backlight +// +//#define LCD_BACKLIGHT_TIMEOUT_MINS 1 // (minutes) Timeout before turning off the backlight +#if defined(DISPLAY_SLEEP_MINUTES) || defined(LCD_BACKLIGHT_TIMEOUT_MINS) + #define EDITABLE_DISPLAY_TIMEOUT // Edit timeout with M255 S and a menu item +#endif + // // ADC Button Debounce // @@ -2143,10 +2348,11 @@ */ #define BABYSTEPPING #if ENABLED(BABYSTEPPING) - #define INTEGRATED_BABYSTEPPING // EXPERIMENTAL integration of babystepping into the Stepper ISR + //#define EP_BABYSTEPPING // M293/M294 babystepping with EMERGENCY_PARSER support //#define BABYSTEP_WITHOUT_HOMING + #define BABYSTEP_ALWAYS_AVAILABLE // Allow babystepping at all times (not just during movement) //#define BABYSTEP_XY // Also enable X/Y Babystepping. Not supported on DELTA! - #define BABYSTEP_INVERT_Z false // Change if Z babysteps should go the other way + //#define BABYSTEP_INVERT_Z // Enable if Z babysteps should go the other way //#define BABYSTEP_MILLIMETER_UNITS // Specify BABYSTEP_MULTIPLICATOR_(XY|Z) in mm instead of micro-steps #define BABYSTEP_MULTIPLICATOR_Z 10 // (steps or mm) Steps or millimeter distance for each Z babystep #define BABYSTEP_MULTIPLICATOR_XY 1 // (steps or mm) Steps or millimeter distance for each XY babystep @@ -2155,8 +2361,7 @@ #if ENABLED(DOUBLECLICK_FOR_Z_BABYSTEPPING) #define DOUBLECLICK_MAX_INTERVAL 1250 // Maximum interval between clicks, in milliseconds. // Note: Extra time may be added to mitigate controller latency. - #define BABYSTEP_ALWAYS_AVAILABLE // Allow babystepping at all times (not just during movement). - //#define MOVE_Z_WHEN_IDLE // Jump to the move Z menu on doubleclick when printer is idle. + //#define MOVE_Z_WHEN_IDLE // Jump to the move Z menu on double-click when printer is idle. #if ENABLED(MOVE_Z_WHEN_IDLE) #define MOVE_Z_IDLE_MULTIPLICATOR 1 // Multiply 1mm by this factor for the move step size. #endif @@ -2168,7 +2373,7 @@ #if ENABLED(BABYSTEP_ZPROBE_OFFSET) //#define BABYSTEP_HOTEND_Z_OFFSET // For multiple hotends, babystep relative Z offsets #if DISABLED(TazPro) - #define BABYSTEP_ZPROBE_GFX_OVERLAY // Enable graphical overlay on Z-offset editor + #define BABYSTEP_GFX_OVERLAY // Enable graphical overlay on Z-offset editor #endif #endif #endif @@ -2199,11 +2404,18 @@ #endif //#define ADVANCE_K_EXTRA // Add a second linear advance constant, configurable with M900 L. //#define LA_DEBUG // Print debug information to serial during operation. Disable for production use. - //#define EXPERIMENTAL_SCURVE // Allow S-Curve Acceleration to be used with LA. //#define ALLOW_LOW_EJERK // Allow a DEFAULT_EJERK value of <10. Recommended for direct drive hotends. //#define EXPERIMENTAL_I2S_LA // Allow I2S_STEPPER_STREAM to be used with LA. Performance degrades as the LA step rate reaches ~20kHz. #endif +/** + * Nonlinear Extrusion Control + * + * Control extrusion rate based on instantaneous extruder velocity. Can be used to correct for + * underextrusion at high extruder speeds that are otherwise well-behaved (i.e., not skipping). + */ +//#define NONLINEAR_EXTRUSION + // @section leveling /** @@ -2225,13 +2437,10 @@ * Points to probe for all 3-point Leveling procedures. * Override if the automatically selected points are inadequate. */ -#if EITHER(AUTO_BED_LEVELING_3POINT, AUTO_BED_LEVELING_UBL) - //#define PROBE_PT_1_X 15 - //#define PROBE_PT_1_Y 180 - //#define PROBE_PT_2_X 15 - //#define PROBE_PT_2_Y 20 - //#define PROBE_PT_3_X 170 - //#define PROBE_PT_3_Y 20 +#if NEEDS_THREE_PROBE_POINTS + //#define PROBE_PT_1 { 15, 180 } // (mm) { x, y } + //#define PROBE_PT_2 { 15, 20 } + //#define PROBE_PT_3 { 170, 20 } #endif /** @@ -2277,7 +2486,7 @@ #endif #endif -#if EITHER(MESH_BED_LEVELING, AUTO_BED_LEVELING_UBL) +#if ANY(MESH_BED_LEVELING, AUTO_BED_LEVELING_UBL) // Override the mesh area if the automatic (max) area is too large //#define MESH_MIN_X MESH_INSET //#define MESH_MIN_Y MESH_INSET @@ -2285,7 +2494,7 @@ //#define MESH_MAX_Y Y_BED_SIZE - (MESH_INSET) #endif -#if BOTH(AUTO_BED_LEVELING_UBL, EEPROM_SETTINGS) +#if ALL(AUTO_BED_LEVELING_UBL, EEPROM_SETTINGS) //#define OPTIMIZED_MESH_STORAGE // Store mesh with less precision to save EEPROM space #endif @@ -2318,6 +2527,8 @@ #endif +// @section probes + /** * Thermal Probe Compensation * @@ -2366,7 +2577,7 @@ #endif // G76 options - #if BOTH(PTC_PROBE, PTC_BED) + #if ALL(PTC_PROBE, PTC_BED) // Park position to wait for probe cooldown #define PTC_PARK_POS { 0, 0, 100 } @@ -2380,7 +2591,7 @@ // Height above Z=0.0 to raise the nozzle. Lowering this can help the probe to heat faster. // Note: The Z=0.0 offset is determined by the probe Z offset (e.g., as set with M851 Z). - #define PTC_PROBE_HEATING_OFFSET 0.5 + #define PTC_PROBE_HEATING_OFFSET 0.5 // (mm) #endif #endif // PTC_PROBE || PTC_BED || PTC_HOTEND @@ -2408,7 +2619,7 @@ // G5 Bézier Curve Support with XYZE destination and IJPQ offsets //#define BEZIER_CURVE_SUPPORT // Requires ~2666 bytes -#if EITHER(ARC_SUPPORT, BEZIER_CURVE_SUPPORT) +#if ANY(ARC_SUPPORT, BEZIER_CURVE_SUPPORT) //#define CNC_WORKSPACE_PLANES // Allow G2/G3/G5 to operate in XY, ZX, or YZ planes #endif @@ -2435,6 +2646,8 @@ #define G38_MINIMUM_MOVE 0.0275 // (mm) Minimum distance that will produce a move. #endif +// @section motion + // Moves (or segments) with fewer steps than this will be joined with the next move #define MIN_STEPS_PER_SEGMENT 6 @@ -2490,13 +2703,12 @@ //================================= Buffers ================================= //=========================================================================== -// @section motion +// @section gcode // The number of linear moves that can be in the planner at once. -// The value of BLOCK_BUFFER_SIZE must be a power of 2 (e.g., 8, 16, 32) -#if BOTH(SDSUPPORT, DIRECT_STEPPING) +#if ALL(HAS_MEDIA, DIRECT_STEPPING) #define BLOCK_BUFFER_SIZE 8 -#elif ENABLED(SDSUPPORT) +#elif HAS_MEDIA #define BLOCK_BUFFER_SIZE 16 #else #define BLOCK_BUFFER_SIZE 16 @@ -2529,7 +2741,7 @@ //#define SERIAL_XON_XOFF #endif -#if ENABLED(SDSUPPORT) +#if HAS_MEDIA // Enable this option to collect and display the maximum // RX queue usage after transferring a file to SD. //#define SERIAL_STATS_MAX_RX_QUEUED @@ -2575,11 +2787,13 @@ //#define FULL_REPORT_TO_HOST_FEATURE // Auto-report the machine status like Grbl CNC #endif -// Bad Serial-connections can miss a received command by sending an 'ok' -// Therefore some clients abort after 30 seconds in a timeout. -// Some other clients start sending commands while receiving a 'wait'. -// This "wait" is only sent when the buffer is empty. 1 second is a good value here. -//#define NO_TIMEOUTS 1000 // Milliseconds +/** + * Bad Serial-connections can miss a received command by sending an 'ok' + * Therefore some clients abort after 30 seconds in a timeout. + * Some other clients start sending commands while receiving a 'wait'. + * This "wait" is only sent when the buffer is empty. 1 second is a good value here. + */ +//#define NO_TIMEOUTS 1000 // (ms) // Some clients will have this feature soon. This could make the NO_TIMEOUTS unnecessary. #define ADVANCED_OK @@ -2591,6 +2805,15 @@ // For serial echo, the number of digits after the decimal point //#define SERIAL_FLOAT_PRECISION 4 +/** + * This feature is EXPERIMENTAL so use with caution and test thoroughly. + * Enable this option to receive data on the serial ports via the onboard DMA + * controller for more stable and reliable high-speed serial communication. + * Only some STM32 MCUs are currently supported. + * Note: This has no effect on emulated USB serial ports. + */ +//#define SERIAL_DMA + /** * Set the number of proportional font spaces required to fill up a typical character space. * This can help to better align the output of commands like `G29 O` Mesh Output. @@ -2611,6 +2834,8 @@ */ //#define EXTRA_FAN_SPEED +// @section gcode + /** * Firmware-based and LCD-controlled retract * @@ -2646,6 +2871,8 @@ #endif #endif +// @section tool change + /** * Universal tool change settings. * Applies to all types of extruders except where explicitly noted. @@ -2663,9 +2890,17 @@ * Extra G-code to run while executing tool-change commands. Can be used to use an additional * stepper motor (e.g., I axis in Configuration.h) to drive the tool-changer. */ - //#define EVENT_GCODE_TOOLCHANGE_T0 "G28 A\nG1 A0" // Extra G-code to run while executing tool-change command T0 - //#define EVENT_GCODE_TOOLCHANGE_T1 "G1 A10" // Extra G-code to run while executing tool-change command T1 - //#define EVENT_GCODE_TOOLCHANGE_ALWAYS_RUN // Always execute above G-code sequences. Use with caution! + //#define EVENT_GCODE_TOOLCHANGE_T0 "G28 A\nG1 A0" // Extra G-code to run while executing tool-change command T0 + //#define EVENT_GCODE_TOOLCHANGE_T1 "G1 A10" // Extra G-code to run while executing tool-change command T1 + //#define EVENT_GCODE_TOOLCHANGE_ALWAYS_RUN // Always execute above G-code sequences. Use with caution! + + /** + * Consider coordinates for EVENT_GCODE_TOOLCHANGE_Tx as relative to T0 + * so that moves in the specified axes are the same for all tools. + */ + //#define TC_GCODE_USE_GLOBAL_X // Use X position relative to Tool 0 + //#define TC_GCODE_USE_GLOBAL_Y // Use Y position relative to Tool 0 + //#define TC_GCODE_USE_GLOBAL_Z // Use Z position relative to Tool 0 /** * Tool Sensors detect when tools have been picked up or dropped. @@ -2718,7 +2953,21 @@ * - Switch to a different nozzle on an extruder jam */ #define TOOLCHANGE_MIGRATION_FEATURE + #if ENABLED(TOOLCHANGE_MIGRATION_FEATURE) + // Override toolchange settings + // By default tool migration uses regular toolchange settings. + // With a prime tower, tool-change swapping/priming occur inside the bed. + // When migrating to a new unprimed tool you can set override values below. + //#define MIGRATION_ZRAISE 0 // (mm) + // Longer prime to clean out + //#define MIGRATION_FS_EXTRA_PRIME 0 // (mm) Extra priming length + //#define MIGRATION_FS_WIPE_RETRACT 0 // (mm) Retract before cooling for less stringing, better wipe, etc. + + // Cool after prime to reduce stringing + //#define MIGRATION_FS_FAN_SPEED 255 // 0-255 + //#define MIGRATION_FS_FAN_TIME 0 // (seconds) + #endif #endif /** @@ -2731,6 +2980,9 @@ #define TOOLCHANGE_PARK_XY_FEEDRATE 6000 // (mm/m) //#define TOOLCHANGE_PARK_X_ONLY // X axis only move //#define TOOLCHANGE_PARK_Y_ONLY // Y axis only move + #if ENABLED(TOOLCHANGE_MIGRATION_FEATURE) + //#define TOOLCHANGE_MIGRATION_DO_PARK // Force park (or no-park) on migration + #endif #endif #endif // EXTRUDERS > 1 @@ -2841,10 +3093,10 @@ #endif #if AXIS_IS_TMC_CONFIG(X2) - #define X2_CURRENT 800 - #define X2_CURRENT_HOME X2_CURRENT - #define X2_MICROSTEPS X_MICROSTEPS - #define X2_RSENSE 0.11 + #define X2_CURRENT X_CURRENT + #define X2_CURRENT_HOME X_CURRENT_HOME + #define X2_MICROSTEPS X_MICROSTEPS + #define X2_RSENSE X_RSENSE #define X2_CHAIN_POS -1 //#define X2_INTERPOLATE true //#define X2_HOLD_MULTIPLIER 0.5 @@ -2861,10 +3113,10 @@ #endif #if AXIS_IS_TMC_CONFIG(Y2) - #define Y2_CURRENT 800 - #define Y2_CURRENT_HOME Y2_CURRENT - #define Y2_MICROSTEPS Y_MICROSTEPS - #define Y2_RSENSE 0.11 + #define Y2_CURRENT Y_CURRENT + #define Y2_CURRENT_HOME Y_CURRENT_HOME + #define Y2_MICROSTEPS Y_MICROSTEPS + #define Y2_RSENSE Y_RSENSE #define Y2_CHAIN_POS -1 //#define Y2_INTERPOLATE true //#define Y2_HOLD_MULTIPLIER 0.5 @@ -2885,30 +3137,30 @@ #endif #if AXIS_IS_TMC_CONFIG(Z2) - #define Z2_CURRENT 800 - #define Z2_CURRENT_HOME Z2_CURRENT - #define Z2_MICROSTEPS Z_MICROSTEPS - #define Z2_RSENSE 0.11 + #define Z2_CURRENT Z_CURRENT + #define Z2_CURRENT_HOME Z_CURRENT_HOME + #define Z2_MICROSTEPS Z_MICROSTEPS + #define Z2_RSENSE Z_RSENSE #define Z2_CHAIN_POS -1 //#define Z2_INTERPOLATE true //#define Z2_HOLD_MULTIPLIER 0.5 #endif #if AXIS_IS_TMC_CONFIG(Z3) - #define Z3_CURRENT 800 - #define Z3_CURRENT_HOME Z3_CURRENT - #define Z3_MICROSTEPS Z_MICROSTEPS - #define Z3_RSENSE 0.11 + #define Z3_CURRENT Z_CURRENT + #define Z3_CURRENT_HOME Z_CURRENT_HOME + #define Z3_MICROSTEPS Z_MICROSTEPS + #define Z3_RSENSE Z_RSENSE #define Z3_CHAIN_POS -1 //#define Z3_INTERPOLATE true //#define Z3_HOLD_MULTIPLIER 0.5 #endif #if AXIS_IS_TMC_CONFIG(Z4) - #define Z4_CURRENT 800 - #define Z4_CURRENT_HOME Z4_CURRENT - #define Z4_MICROSTEPS Z_MICROSTEPS - #define Z4_RSENSE 0.11 + #define Z4_CURRENT Z_CURRENT + #define Z4_CURRENT_HOME Z_CURRENT_HOME + #define Z4_MICROSTEPS Z_MICROSTEPS + #define Z4_RSENSE Z_RSENSE #define Z4_CHAIN_POS -1 //#define Z4_INTERPOLATE true //#define Z4_HOLD_MULTIPLIER 0.5 @@ -2984,63 +3236,63 @@ #endif #if AXIS_IS_TMC_CONFIG(E1) - #define E1_CURRENT 960 + #define E1_CURRENT E0_CURRENT #define E1_MICROSTEPS E0_MICROSTEPS - #define E1_RSENSE 0.12 + #define E1_RSENSE E0_RSENSE #define E1_CHAIN_POS -1 //#define E1_INTERPOLATE true //#define E1_HOLD_MULTIPLIER 0.5 #endif #if AXIS_IS_TMC_CONFIG(E2) - #define E2_CURRENT 800 + #define E2_CURRENT E0_CURRENT #define E2_MICROSTEPS E0_MICROSTEPS - #define E2_RSENSE 0.11 + #define E2_RSENSE E0_RSENSE #define E2_CHAIN_POS -1 //#define E2_INTERPOLATE true //#define E2_HOLD_MULTIPLIER 0.5 #endif #if AXIS_IS_TMC_CONFIG(E3) - #define E3_CURRENT 800 + #define E3_CURRENT E0_CURRENT #define E3_MICROSTEPS E0_MICROSTEPS - #define E3_RSENSE 0.11 + #define E3_RSENSE E0_RSENSE #define E3_CHAIN_POS -1 //#define E3_INTERPOLATE true //#define E3_HOLD_MULTIPLIER 0.5 #endif #if AXIS_IS_TMC_CONFIG(E4) - #define E4_CURRENT 800 + #define E4_CURRENT E0_CURRENT #define E4_MICROSTEPS E0_MICROSTEPS - #define E4_RSENSE 0.11 + #define E4_RSENSE E0_RSENSE #define E4_CHAIN_POS -1 //#define E4_INTERPOLATE true //#define E4_HOLD_MULTIPLIER 0.5 #endif #if AXIS_IS_TMC_CONFIG(E5) - #define E5_CURRENT 800 + #define E5_CURRENT E0_CURRENT #define E5_MICROSTEPS E0_MICROSTEPS - #define E5_RSENSE 0.11 + #define E5_RSENSE E0_RSENSE #define E5_CHAIN_POS -1 //#define E5_INTERPOLATE true //#define E5_HOLD_MULTIPLIER 0.5 #endif #if AXIS_IS_TMC_CONFIG(E6) - #define E6_CURRENT 800 + #define E6_CURRENT E0_CURRENT #define E6_MICROSTEPS E0_MICROSTEPS - #define E6_RSENSE 0.11 + #define E6_RSENSE E0_RSENSE #define E6_CHAIN_POS -1 //#define E6_INTERPOLATE true //#define E6_HOLD_MULTIPLIER 0.5 #endif #if AXIS_IS_TMC_CONFIG(E7) - #define E7_CURRENT 800 + #define E7_CURRENT E0_CURRENT #define E7_MICROSTEPS E0_MICROSTEPS - #define E7_RSENSE 0.11 + #define E7_RSENSE E0_RSENSE #define E7_CHAIN_POS -1 //#define E7_INTERPOLATE true //#define E7_HOLD_MULTIPLIER 0.5 @@ -3052,28 +3304,28 @@ * Override default SPI pins for TMC2130, TMC2160, TMC2660, TMC5130 and TMC5160 drivers here. * The default pins can be found in your board's pins file. */ - //#define X_CS_PIN -1 - //#define Y_CS_PIN -1 - //#define Z_CS_PIN -1 - //#define X2_CS_PIN -1 - //#define Y2_CS_PIN -1 - //#define Z2_CS_PIN -1 - //#define Z3_CS_PIN -1 - //#define Z4_CS_PIN -1 - //#define I_CS_PIN -1 - //#define J_CS_PIN -1 - //#define K_CS_PIN -1 - //#define U_CS_PIN -1 - //#define V_CS_PIN -1 - //#define W_CS_PIN -1 - //#define E0_CS_PIN -1 - //#define E1_CS_PIN -1 - //#define E2_CS_PIN -1 - //#define E3_CS_PIN -1 - //#define E4_CS_PIN -1 - //#define E5_CS_PIN -1 - //#define E6_CS_PIN -1 - //#define E7_CS_PIN -1 + //#define X_CS_PIN -1 + //#define Y_CS_PIN -1 + //#define Z_CS_PIN -1 + //#define X2_CS_PIN -1 + //#define Y2_CS_PIN -1 + //#define Z2_CS_PIN -1 + //#define Z3_CS_PIN -1 + //#define Z4_CS_PIN -1 + //#define I_CS_PIN -1 + //#define J_CS_PIN -1 + //#define K_CS_PIN -1 + //#define U_CS_PIN -1 + //#define V_CS_PIN -1 + //#define W_CS_PIN -1 + //#define E0_CS_PIN -1 + //#define E1_CS_PIN -1 + //#define E2_CS_PIN -1 + //#define E3_CS_PIN -1 + //#define E4_CS_PIN -1 + //#define E5_CS_PIN -1 + //#define E6_CS_PIN -1 + //#define E7_CS_PIN -1 /** * Software option for SPI driven drivers (TMC2130, TMC2160, TMC2660, TMC5130 and TMC5160). @@ -3263,7 +3515,7 @@ * * It is recommended to set HOMING_BUMP_MM to { 0, 0, 0 }. * - * SPI_ENDSTOPS *** Beta feature! *** TMC2130/TMC5160 Only *** + * SPI_ENDSTOPS *** TMC2130/TMC5160 Only *** * Poll the driver through SPI to determine load when homing. * Removes the need for a wire from DIAG1 to an endstop pin. * @@ -3275,7 +3527,7 @@ */ #define SENSORLESS_HOMING // StallGuard capable drivers only - #if EITHER(SENSORLESS_HOMING, SENSORLESS_PROBING) + #if ANY(SENSORLESS_HOMING, SENSORLESS_PROBING) // TMC2209: 0...255. TMC2130: -64...63 #if ENABLED(TazPro) #define X_STALL_SENSITIVITY 6 @@ -3298,7 +3550,7 @@ //#define U_STALL_SENSITIVITY 8 //#define V_STALL_SENSITIVITY 8 //#define W_STALL_SENSITIVITY 8 - //#define SPI_ENDSTOPS // TMC2130 only + //#define SPI_ENDSTOPS // TMC2130/TMC5160 only //#define IMPROVE_HOMING_RELIABILITY #endif @@ -3317,10 +3569,9 @@ //#define TMC_HOME_PHASE { 896, 896, 896 } /** - * Beta feature! - * Create a 50/50 square wave step pulse optimal for stepper drivers. + * Step on both rising and falling edge signals (as with a square wave). */ - //#define SQUARE_WAVE_STEPPING + //#define EDGE_STEPPING /** * Enable M122 debugging command for TMC stepper drivers. @@ -3359,9 +3610,8 @@ /** * TWI/I2C BUS * - * This feature is an EXPERIMENTAL feature so it shall not be used on production - * machines. Enabling this will allow you to send and receive I2C data from slave - * devices on the bus. + * This feature is EXPERIMENTAL but may be useful for custom I2C peripherals. + * Enable this to send and receive I2C data from slave devices on the bus. * * ; Example #1 * ; This macro send the string "Marlin" to the slave device with address 0x63 (99) @@ -3408,7 +3658,7 @@ //#define PHOTOGRAPH_PIN 23 // Canon Hack Development Kit - // https://captain-slow.dk/2014/03/09/3d-printing-timelapses/ + // https://web.archive.org/web/20200920094805/https://captain-slow.dk/2014/03/09/3d-printing-timelapses/ //#define CHDK_PIN 4 // Optional second move with delay to trigger the camera shutter @@ -3451,7 +3701,7 @@ */ //#define SPINDLE_FEATURE //#define LASER_FEATURE -#if EITHER(SPINDLE_FEATURE, LASER_FEATURE) +#if ANY(SPINDLE_FEATURE, LASER_FEATURE) #define SPINDLE_LASER_ACTIVE_STATE LOW // Set to "HIGH" if SPINDLE_LASER_ENA_PIN is active HIGH #define SPINDLE_LASER_USE_PWM // Enable if your controller supports setting the speed/power @@ -3562,7 +3812,7 @@ * Feed rates are set by the F parameter of a move command e.g. G1 X0 Y10 F6000 * Laser power would be calculated by bit shifting off 8 LSB's. In binary this is div 256. * The calculation gives us ocr values from 0 to 255, values over F65535 will be set as 255 . - * More refined power control such as compesation for accell/decell will be addressed in future releases. + * More refined power control such as compensation for accel/decel will be addressed in future releases. * * M5 I clears inline mode and set power to 0, M5 sets the power output to 0 but leaves inline mode on. */ @@ -3570,8 +3820,8 @@ /** * Enable M3 commands for laser mode inline power planner syncing. * This feature enables any M3 S-value to be injected into the block buffers while in - * CUTTER_MODE_CONTINUOUS. The option allows M3 laser power to be commited without waiting - * for a planner syncronization + * CUTTER_MODE_CONTINUOUS. The option allows M3 laser power to be committed without waiting + * for a planner synchronization */ //#define LASER_POWER_SYNC @@ -3738,6 +3988,9 @@ * Auto-report position with M154 S */ //#define AUTO_REPORT_POSITION +#if ENABLED(AUTO_REPORT_POSITION) + //#define AUTO_REPORT_REAL_POSITION // Auto-report the real position +#endif /** * Include capabilities in M115 output @@ -3782,7 +4035,8 @@ * Use 'M200 [T] L' to override and 'M502' to reset. * A non-zero value activates Volume-based Extrusion Limiting. */ - #define DEFAULT_VOLUMETRIC_EXTRUDER_LIMIT 0.00 // (mm^3/sec) + #define DEFAULT_VOLUMETRIC_EXTRUDER_LIMIT 0.00 // (mm^3/sec) + #define VOLUMETRIC_EXTRUDER_LIMIT_MAX 20 // (mm^3/sec) #endif #endif @@ -3815,14 +4069,17 @@ //#define REPETIER_GCODE_M360 // Add commands originally from Repetier FW /** - * Enable this option for a leaner build of Marlin that removes all - * workspace offsets, simplifying coordinate transformations, leveling, etc. - * - * - M206 and M428 are disabled. - * - G92 will revert to its behavior from Marlin 1.0. + * Enable this option for a leaner build of Marlin that removes + * workspace offsets to slightly optimize performance. + * G92 will revert to its behavior from Marlin 1.0. */ //#define NO_WORKSPACE_OFFSETS +/** + * Disable M206 and M428 if you don't need home offsets. + */ +//#define NO_HOME_OFFSETS + /** * CNC G-code options * Support CNC-style G-code dialects used by laser cutters, drawing machine cams, etc. @@ -4035,7 +4292,7 @@ * Wiki: https://wiki.aus3d.com.au/Magnetic_Encoder * Github: https://github.com/Aus3D/MagneticEncoder * - * Supplier: https://aus3d.com.au/magnetic-encoder-module + * Supplier: https://aus3d.com.au/products/magnetic-encoder-module * Alternative Supplier: https://reliabuild3d.com/ * * Reliabuild encoders have been modified to improve reliability. @@ -4202,16 +4459,18 @@ * Sample debug features * If you add more debug displays, be careful to avoid conflicts! */ - #define MAX7219_DEBUG_PRINTER_ALIVE // Blink corner LED of 8x8 matrix to show that the firmware is functioning - #define MAX7219_DEBUG_PLANNER_HEAD 2 // Show the planner queue head position on this and the next LED matrix row - #define MAX7219_DEBUG_PLANNER_TAIL 4 // Show the planner queue tail position on this and the next LED matrix row + #define MAX7219_DEBUG_PRINTER_ALIVE // Blink corner LED of 8x8 matrix to show that the firmware is functioning + #define MAX7219_DEBUG_PLANNER_HEAD 2 // Show the planner queue head position on this and the next LED matrix row + #define MAX7219_DEBUG_PLANNER_TAIL 4 // Show the planner queue tail position on this and the next LED matrix row - #define MAX7219_DEBUG_PLANNER_QUEUE 0 // Show the current planner queue depth on this and the next LED matrix row - // If you experience stuttering, reboots, etc. this option can reveal how - // tweaks made to the configuration are affecting the printer in real-time. - #define MAX7219_DEBUG_PROFILE 6 // Display the fraction of CPU time spent in profiled code on this LED matrix - // row. By default idle() is profiled so this shows how "idle" the processor is. - // See class CodeProfiler. + #define MAX7219_DEBUG_PLANNER_QUEUE 0 // Show the current planner queue depth on this and the next LED matrix row + // If you experience stuttering, reboots, etc. this option can reveal how + // tweaks made to the configuration are affecting the printer in real-time. + #define MAX7219_DEBUG_PROFILE 6 // Display the fraction of CPU time spent in profiled code on this LED matrix + // row. By default idle() is profiled so this shows how "idle" the processor is. + // See class CodeProfiler. + //#define MAX7219_DEBUG_MULTISTEPPING 6 // Show multi-stepping 1 to 128 on this LED matrix row. + //#define MAX7219_DEBUG_SLOWDOWN 6 // Count (mod 16) how many times SLOWDOWN has reduced print speed. #endif /** @@ -4236,13 +4495,17 @@ #endif /** - * WiFi Support (Espressif ESP32 WiFi) + * Native ESP32 board with WiFi or add-on ESP32 WiFi-101 module */ -//#define WIFISUPPORT // Marlin embedded WiFi management +//#define WIFISUPPORT // Marlin embedded WiFi management. Not needed for simple WiFi serial port. //#define ESP3D_WIFISUPPORT // ESP3D Library WiFi management (https://github.com/luc-github/ESP3DLib) -#if EITHER(WIFISUPPORT, ESP3D_WIFISUPPORT) - //#define WEBSUPPORT // Start a webserver (which may include auto-discovery) +/** + * Extras for an ESP32-based motherboard with WIFISUPPORT + * These options don't apply to add-on WiFi modules based on ESP32 WiFi101. + */ +#if ENABLED(WIFISUPPORT) + //#define WEBSUPPORT // Start a webserver (which may include auto-discovery) using SPIFFS //#define OTASUPPORT // Support over-the-air firmware updates //#define WIFI_CUSTOM_COMMAND // Accept feature config commands (e.g., WiFi ESP3D) from the host @@ -4292,35 +4555,34 @@ // Add an LCD menu for MMU2 //#define MMU2_MENUS - #if EITHER(MMU2_MENUS, HAS_PRUSA_MMU2S) - // Settings for filament load / unload from the LCD menu. - // This is for Prusa MK3-style extruders. Customize for your hardware. - #define MMU2_FILAMENTCHANGE_EJECT_FEED 80.0 - #define MMU2_LOAD_TO_NOZZLE_SEQUENCE \ - { 7.2, 1145 }, \ - { 14.4, 871 }, \ - { 36.0, 1393 }, \ - { 14.4, 871 }, \ - { 50.0, 198 } - #define MMU2_RAMMING_SEQUENCE \ - { 1.0, 1000 }, \ - { 1.0, 1500 }, \ - { 2.0, 2000 }, \ - { 1.5, 3000 }, \ - { 2.5, 4000 }, \ - { -15.0, 5000 }, \ - { -14.0, 1200 }, \ - { -6.0, 600 }, \ - { 10.0, 700 }, \ - { -10.0, 400 }, \ - { -50.0, 2000 } - #endif + // Settings for filament load / unload from the LCD menu. + // This is for Průša MK3-style extruders. Customize for your hardware. + #define MMU2_FILAMENTCHANGE_EJECT_FEED 80.0 + #define MMU2_LOAD_TO_NOZZLE_SEQUENCE \ + { 7.2, 1145 }, \ + { 14.4, 871 }, \ + { 36.0, 1393 }, \ + { 14.4, 871 }, \ + { 50.0, 198 } + + #define MMU2_RAMMING_SEQUENCE \ + { 1.0, 1000 }, \ + { 1.0, 1500 }, \ + { 2.0, 2000 }, \ + { 1.5, 3000 }, \ + { 2.5, 4000 }, \ + { -15.0, 5000 }, \ + { -14.0, 1200 }, \ + { -6.0, 600 }, \ + { 10.0, 700 }, \ + { -10.0, 400 }, \ + { -50.0, 2000 } /** * Using a sensor like the MMU2S * This mode requires a MK3S extruder with a sensor at the extruder idler, like the MMU2S. - * See https://help.prusa3d.com/en/guide/3b-mk3s-mk2-5s-extruder-upgrade_41560, step 11 + * See https://help.prusa3d.com/guide/3b-mk3s-mk2-5s-extruder-upgrade_41560#42048, step 11 */ #if HAS_PRUSA_MMU2S #define MMU2_C0_RETRY 5 // Number of retries (total time = timeout*retries) @@ -4338,6 +4600,8 @@ #define MMU2_CAN_LOAD_INCREMENT_SEQUENCE \ { -MMU2_CAN_LOAD_INCREMENT, MMU2_CAN_LOAD_FEEDRATE } + // Continue unloading if sensor detects filament after the initial unload move + //#define MMU_IR_UNLOAD_MOVE #else /** diff --git a/Marlin/Makefile b/Marlin/Makefile index ca7cacaa6a..e5ba9cb341 100644 --- a/Marlin/Makefile +++ b/Marlin/Makefile @@ -63,8 +63,8 @@ HARDWARE_MOTHERBOARD ?= 1020 ifeq ($(OS),Windows_NT) # Windows - ARDUINO_INSTALL_DIR ?= ${HOME}/Arduino - ARDUINO_USER_DIR ?= ${HOME}/Arduino + ARDUINO_INSTALL_DIR ?= ${HOME}/AppData/Local/Arduino + ARDUINO_USER_DIR ?= ${HOME}/Documents/Arduino else UNAME_S := $(shell uname -s) ifeq ($(UNAME_S),Linux) @@ -82,11 +82,11 @@ endif # Arduino source install directory, and version number # On most linuxes this will be /usr/share/arduino -ARDUINO_INSTALL_DIR ?= ${HOME}/Arduino -ARDUINO_VERSION ?= 106 +ARDUINO_INSTALL_DIR ?= ${HOME}/AppData/Local/Arduino # C:/Users/${USERNAME}/AppData/Local/Arduino +ARDUINO_VERSION ?= 10819 # The installed Libraries are in the User folder -ARDUINO_USER_DIR ?= ${HOME}/Arduino +ARDUINO_USER_DIR ?= ${HOME}/Documents/Arduino # You can optionally set a path to the avr-gcc tools. # Requires a trailing slash. For example, /usr/local/avr-gcc/bin/ @@ -656,18 +656,18 @@ ifeq ($(HARDWARE_VARIANT), $(filter $(HARDWARE_VARIANT),arduino Teensy Sanguino) # Old libraries (avr-core 1.6.21 < / Arduino < 1.6.8) VPATH += $(ARDUINO_INSTALL_DIR)/hardware/arduino/avr/libraries/SPI # New libraries (avr-core >= 1.6.21 / Arduino >= 1.6.8) - VPATH += $(ARDUINO_INSTALL_DIR)/hardware/arduino/avr/libraries/SPI/src + VPATH += $(ARDUINO_INSTALL_DIR)/packages/arduino/hardware/arduino/avr/1.8.6/libraries/SPI/src endif ifeq ($(IS_MCU),1) - VPATH += $(ARDUINO_INSTALL_DIR)/hardware/arduino/avr/cores/arduino + VPATH += $(ARDUINO_INSTALL_DIR)/packages/arduino/hardware/arduino/avr/1.8.6/cores/arduino # Old libraries (avr-core 1.6.21 < / Arduino < 1.6.8) VPATH += $(ARDUINO_INSTALL_DIR)/hardware/arduino/avr/libraries/SPI VPATH += $(ARDUINO_INSTALL_DIR)/hardware/arduino/avr/libraries/SoftwareSerial # New libraries (avr-core >= 1.6.21 / Arduino >= 1.6.8) - VPATH += $(ARDUINO_INSTALL_DIR)/hardware/arduino/avr/libraries/SPI/src - VPATH += $(ARDUINO_INSTALL_DIR)/hardware/arduino/avr/libraries/SoftwareSerial/src + VPATH += $(ARDUINO_INSTALL_DIR)/packages/arduino/hardware/arduino/avr/1.8.6/libraries/SPI/src + VPATH += $(ARDUINO_INSTALL_DIR)/packages/arduino/hardware/arduino/avr/1.8.6/libraries/SoftwareSerial/src endif VPATH += $(ARDUINO_INSTALL_DIR)/libraries/LiquidCrystal/src @@ -681,17 +681,17 @@ ifeq ($(WIRE), 1) VPATH += $(ARDUINO_INSTALL_DIR)/hardware/arduino/avr/libraries/Wire VPATH += $(ARDUINO_INSTALL_DIR)/hardware/arduino/avr/libraries/Wire/utility # New libraries (avr-core >= 1.6.21 / Arduino >= 1.6.8) - VPATH += $(ARDUINO_INSTALL_DIR)/hardware/arduino/avr/libraries/Wire/src - VPATH += $(ARDUINO_INSTALL_DIR)/hardware/arduino/avr/libraries/Wire/src/utility + VPATH += $(ARDUINO_INSTALL_DIR)/packages/arduino/hardware/avr/1.8.6/libraries/Wire/src + VPATH += $(ARDUINO_INSTALL_DIR)/packages/arduino/hardware/avr/1.8.6/libraries/Wire/src/utility endif ifeq ($(NEOPIXEL), 1) VPATH += $(ARDUINO_INSTALL_DIR)/libraries/Adafruit_NeoPixel endif ifeq ($(U8GLIB), 1) -VPATH += $(ARDUINO_INSTALL_DIR)/libraries/U8glib -VPATH += $(ARDUINO_INSTALL_DIR)/libraries/U8glib/csrc -VPATH += $(ARDUINO_INSTALL_DIR)/libraries/U8glib/cppsrc -VPATH += $(ARDUINO_INSTALL_DIR)/libraries/U8glib/fntsrc +VPATH += $(ARDUINO_INSTALL_DIR)/libraries/U8glib-HAL +VPATH += $(ARDUINO_INSTALL_DIR)/libraries/U8glib-HAL/src +# VPATH += $(ARDUINO_INSTALL_DIR)/libraries/U8glib +# VPATH += $(ARDUINO_INSTALL_DIR)/libraries/U8glib/src endif ifeq ($(TMC), 1) VPATH += $(ARDUINO_INSTALL_DIR)/libraries/TMCStepper/src @@ -700,9 +700,9 @@ endif ifeq ($(HARDWARE_VARIANT), arduino) HARDWARE_SUB_VARIANT ?= mega - VPATH += $(ARDUINO_INSTALL_DIR)/hardware/arduino/avr/variants/$(HARDWARE_SUB_VARIANT) + VPATH += $(ARDUINO_INSTALL_DIR)/packages/arduino/hardware/avr/1.8.6/variants/$(HARDWARE_SUB_VARIANT) else ifeq ($(HARDWARE_VARIANT), Sanguino) - VPATH += $(ARDUINO_INSTALL_DIR)/hardware/marlin/avr/variants/sanguino + VPATH += $(ARDUINO_INSTALL_DIR)/packages/arduino/hardware/avr/1.8.6/variants/sanguino else ifeq ($(HARDWARE_VARIANT), archim) VPATH += $(ARDUINO_INSTALL_DIR)/packages/ultimachine/hardware/sam/1.6.9-b/system/libsam VPATH += $(ARDUINO_INSTALL_DIR)/packages/ultimachine/hardware/sam/1.6.9-b/system/CMSIS/CMSIS/Include/ @@ -718,7 +718,7 @@ else ifeq ($(HARDWARE_VARIANT), archim) LDLIBS = $(ARDUINO_INSTALL_DIR)/packages/ultimachine/hardware/sam/1.6.9-b/variants/archim/libsam_sam3x8e_gcc_rel.a else HARDWARE_SUB_VARIANT ?= standard - VPATH += $(ARDUINO_INSTALL_DIR)/hardware/$(HARDWARE_VARIANT)/variants/$(HARDWARE_SUB_VARIANT) + VPATH += $(ARDUINO_INSTALL_DIR)/packages/arduino/hardware/avr/1.8.6/variants/$(HARDWARE_SUB_VARIANT) endif LIB_SRC = wiring.c \ @@ -733,7 +733,7 @@ endif ifeq ($(HARDWARE_VARIANT), Teensy) LIB_SRC = wiring.c - VPATH += $(ARDUINO_INSTALL_DIR)/hardware/teensy/cores/teensy + VPATH += $(ARDUINO_INSTALL_DIR)/packages/arduino/hardware/teensy/cores/teensy endif LIB_CXXSRC = WMath.cpp WString.cpp Print.cpp SPI.cpp @@ -880,7 +880,7 @@ AVRDUDE_WRITE_FLASH = -Uflash:w:$(BUILD_DIR)/$(TARGET).hex:i ifeq ($(shell uname -s), Linux) AVRDUDE_CONF = /etc/avrdude/avrdude.conf else - AVRDUDE_CONF = $(ARDUINO_INSTALL_DIR)/hardware/tools/avr/etc/avrdude.conf + AVRDUDE_CONF = $(ARDUINO_INSTALL_DIR)/packages/arduino/tools/avrdude/6.3.0-arduino17/etc/avrdude.conf endif AVRDUDE_FLAGS = -D -C$(AVRDUDE_CONF) \ -p$(PROG_MCU) -P$(AVRDUDE_PORT) -c$(AVRDUDE_PROGRAMMER) \ diff --git a/Marlin/Marlin.ino b/Marlin/Marlin.ino index 57c825445f..81652000a8 100644 --- a/Marlin/Marlin.ino +++ b/Marlin/Marlin.ino @@ -2,7 +2,7 @@ Marlin Firmware - (c) 2011-2020 MarlinFirmware + (c) 2011-2023 MarlinFirmware Portions of Marlin are (c) by their respective authors. All code complies with GPLv2 and/or GPLv3 @@ -27,7 +27,7 @@ Configuration - https://github.com/MarlinFirmware/Configurations Example configurations for several printer models. - - https://www.youtube.com/watch?v=3gwWVFtdg-4 + - https://youtu.be/3gwWVFtdg-4 A good 20-minute overview of Marlin configuration by Tom Sanladerer. (Applies to Marlin 1.0.x, so Jerk and Acceleration should be halved.) Also... https://www.google.com/search?tbs=vid%3A1&q=configure+marlin diff --git a/Marlin/Version.h b/Marlin/Version.h index 43874f6ea1..2044279143 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 "2022-11-29" +//#define STRING_DISTRIBUTION_DATE "2024-01-01" /** * Defines a generic printer name to be output to the LCD after booting Marlin. diff --git a/Marlin/config.ini b/Marlin/config.ini index 0fb9fb0c93..fed2a5c68c 100644 --- a/Marlin/config.ini +++ b/Marlin/config.ini @@ -3,10 +3,50 @@ # config.ini - Options to apply before the build # [config:base] +# +# ini_use_config - A comma-separated list of actions to apply to the Configuration files. +# The actions will be applied in the listed order. +# - none +# Ignore this file and don't apply any configuration options +# +# - base +# Just apply the options in config:base to the configuration +# +# - minimal +# Just apply the options in config:minimal to the configuration +# +# - all +# Apply all 'config:*' sections in this file to the configuration +# +# - another.ini +# Load another INI file with a path relative to this config.ini file (i.e., within Marlin/) +# +# - https://me.myserver.com/path/to/configs +# Fetch configurations from any URL. +# +# - example/Creality/Ender-5 Plus @ bugfix-2.1.x +# Fetch example configuration files from the MarlinFirmware/Configurations repository +# https://raw.githubusercontent.com/MarlinFirmware/Configurations/bugfix-2.1.x/config/examples/Creality/Ender-5%20Plus/ +# +# - example/default @ release-2.0.9.7 +# Fetch default configuration files from the MarlinFirmware/Configurations repository +# https://raw.githubusercontent.com/MarlinFirmware/Configurations/release-2.0.9.7/config/default/ +# +# - [disable] +# Comment out all #defines in both Configuration.h and Configuration_adv.h. This is useful +# to start with a clean slate before applying any config: options, so only the options explicitly +# set in config.ini will be enabled in the configuration. +# +# - [flatten] (Not yet implemented) +# Produce a flattened set of Configuration.h and Configuration_adv.h files with only the enabled +# #defines and no comments. A clean look, but context-free. +# ini_use_config = none # Load all config: sections in this file ;ini_use_config = all +# Disable everything and apply subsequent config:base options +;ini_use_config = [disable], base # Load config file relative to Marlin/ ;ini_use_config = another.ini # Download configurations from GitHub @@ -42,7 +82,7 @@ preheat_1_temp_hotend = 180 bang_max = 255 pidtemp = on pid_k1 = 0.95 -pid_max = BANG_MAX +pid_max = 255 pid_functional_range = 10 default_kp = 22.20 @@ -69,13 +109,9 @@ x_home_dir = -1 y_home_dir = -1 z_home_dir = -1 -use_xmin_plug = on -use_ymin_plug = on -use_zmin_plug = on - -x_min_endstop_inverting = false -y_min_endstop_inverting = false -z_min_endstop_inverting = false +x_min_endstop_hit_state = HIGH +y_min_endstop_hit_state = HIGH +z_min_endstop_hit_state = HIGH default_axis_steps_per_unit = { 80, 80, 400, 500 } axis_relative_modes = { false, false, false, false } @@ -95,15 +131,15 @@ invert_y_dir = true invert_z_dir = false invert_e0_dir = false -invert_e_step_pin = false -invert_x_step_pin = false -invert_y_step_pin = false -invert_z_step_pin = false +step_state_e = HIGH +step_state_x = HIGH +step_state_y = HIGH +step_state_z = HIGH -disable_x = false -disable_y = false -disable_z = false -disable_e = false +disable_x = off +disable_y = off +disable_z = off +disable_e = off proportional_font_ratio = 1.0 default_nominal_filament_dia = 1.75 @@ -127,7 +163,7 @@ busy_while_heating = on default_ejerk = 5.0 default_keepalive_interval = 2 default_leveling_fade_height = 0.0 -disable_inactive_extruder = on +disable_other_extruders = on display_charset_hd44780 = JAPANESE eeprom_boot_silent = on eeprom_chitchat = on @@ -176,12 +212,12 @@ auto_report_temperatures = on autotemp = on autotemp_oldweight = 0.98 bed_check_interval = 5000 -default_stepper_deactive_time = 120 +default_stepper_timeout_sec = 120 default_volumetric_extruder_limit = 0.00 -disable_inactive_e = true -disable_inactive_x = true -disable_inactive_y = true -disable_inactive_z = true +disable_idle_x = on +disable_idle_y = on +disable_idle_z = on +disable_idle_e = on e0_auto_fan_pin = -1 encoder_100x_steps_per_sec = 80 encoder_10x_steps_per_sec = 30 diff --git a/Marlin/src/HAL/AVR/HAL.cpp b/Marlin/src/HAL/AVR/HAL.cpp index 5382eb36a2..407a570cde 100644 --- a/Marlin/src/HAL/AVR/HAL.cpp +++ b/Marlin/src/HAL/AVR/HAL.cpp @@ -61,23 +61,40 @@ void save_reset_reason() { wdt_disable(); } +#include "registers.h" + +MarlinHAL::MarlinHAL() { + TERN_(HAL_AVR_DIRTY_INIT, _ATmega_resetperipherals()); // Clean-wipe the device state. +} + void MarlinHAL::init() { // Init Servo Pins - #define INIT_SERVO(N) OUT_WRITE(SERVO##N##_PIN, LOW) #if HAS_SERVO_0 - INIT_SERVO(0); + OUT_WRITE(SERVO0_PIN, LOW); #endif #if HAS_SERVO_1 - INIT_SERVO(1); + OUT_WRITE(SERVO1_PIN, LOW); #endif #if HAS_SERVO_2 - INIT_SERVO(2); + OUT_WRITE(SERVO2_PIN, LOW); #endif #if HAS_SERVO_3 - INIT_SERVO(3); + OUT_WRITE(SERVO3_PIN, LOW); #endif init_pwm_timers(); // Init user timers to default frequency - 1000HZ + + #if PIN_EXISTS(BEEPER) && ENABLED(HAL_AVR_DIRTY_INIT) && DISABLED(ATMEGA_NO_BEEPFIX) + // Make sure no alternative is locked onto the BEEPER. + // This fixes the issue where the ATmega is constantly beeping. + // Might disable other peripherals using the pin; to circumvent that please undefine one of the above things! + // The true culprit is the AVR ArduinoCore that enables peripherals redundantly. + // (USART1 on the GeeeTech GT2560) + // https://www.youtube.com/watch?v=jMgCvRXkexk + _ATmega_savePinAlternate(BEEPER_PIN); + + OUT_WRITE(BEEPER_PIN, LOW); + #endif } void MarlinHAL::reboot() { @@ -145,12 +162,12 @@ void MarlinHAL::reboot() { // Free Memory Accessor // ------------------------ -#if ENABLED(SDSUPPORT) +#if HAS_MEDIA #include "../../sd/SdFatUtil.h" int freeMemory() { return SdFatUtil::FreeRam(); } -#else // !SDSUPPORT +#else // !HAS_MEDIA extern "C" { extern char __bss_end; @@ -167,6 +184,6 @@ void MarlinHAL::reboot() { } } -#endif // !SDSUPPORT +#endif // !HAS_MEDIA #endif // __AVR__ diff --git a/Marlin/src/HAL/AVR/HAL.h b/Marlin/src/HAL/AVR/HAL.h index d458790979..3c883b645c 100644 --- a/Marlin/src/HAL/AVR/HAL.h +++ b/Marlin/src/HAL/AVR/HAL.h @@ -1,7 +1,9 @@ /** * Marlin 3D Printer Firmware * Copyright (c) 2020 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] - * Copyright (c) 2016 Bob Cousins bobcousins42@googlemail.com + * + * 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 @@ -140,15 +142,15 @@ typedef Servo hal_servo_t; #endif #define LCD_SERIAL lcdSerial #if HAS_DGUS_LCD - #define SERIAL_GET_TX_BUFFER_FREE() LCD_SERIAL.get_tx_buffer_free() + #define LCD_SERIAL_TX_BUFFER_FREE() LCD_SERIAL.get_tx_buffer_free() #endif #endif // // ADC // -#define HAL_ADC_VREF 5.0 -#define HAL_ADC_RESOLUTION 10 +#define HAL_ADC_VREF_MV 5000 +#define HAL_ADC_RESOLUTION 10 // // Pin Mapping for M42, M43, M226 @@ -187,7 +189,7 @@ class MarlinHAL { public: // Earliest possible init, before setup() - MarlinHAL() {} + MarlinHAL(); // Watchdog static void watchdog_init() IF_DISABLED(USE_WATCHDOG, {}); diff --git a/Marlin/src/HAL/AVR/HAL_SPI.cpp b/Marlin/src/HAL/AVR/HAL_SPI.cpp index dc98f2f79e..32c0361d03 100644 --- a/Marlin/src/HAL/AVR/HAL_SPI.cpp +++ b/Marlin/src/HAL/AVR/HAL_SPI.cpp @@ -198,7 +198,7 @@ void spiBegin() { // output pin high - like sending 0xFF WRITE(SD_MOSI_PIN, HIGH); - LOOP_L_N(i, 8) { + for (uint8_t i = 0; i < 8; ++i) { WRITE(SD_SCK_PIN, HIGH); nop; // adjust so SCK is nice @@ -225,7 +225,7 @@ void spiBegin() { void spiSend(uint8_t data) { // no interrupts during byte send - about 8µs cli(); - LOOP_L_N(i, 8) { + for (uint8_t i = 0; i < 8; ++i) { WRITE(SD_SCK_PIN, LOW); WRITE(SD_MOSI_PIN, data & 0x80); data <<= 1; diff --git a/Marlin/src/HAL/AVR/MarlinSerial.h b/Marlin/src/HAL/AVR/MarlinSerial.h index 7eb76000d6..a40730e0a8 100644 --- a/Marlin/src/HAL/AVR/MarlinSerial.h +++ b/Marlin/src/HAL/AVR/MarlinSerial.h @@ -34,12 +34,9 @@ #include #include "../../inc/MarlinConfigPre.h" +#include "../../core/types.h" #include "../../core/serial_hook.h" -#ifndef SERIAL_PORT - #define SERIAL_PORT 0 -#endif - #ifndef USBCON // The presence of the UBRRH register is used to detect a UART. @@ -138,10 +135,6 @@ #define BYTE 0 - // Templated type selector - template struct TypeSelector { typedef T type;} ; - template struct TypeSelector { typedef F type; }; - template class MarlinSerial { protected: @@ -164,7 +157,7 @@ static constexpr B_U2Xx B_U2X = 0; // Base size of type on buffer size - typedef typename TypeSelector<(Cfg::RX_SIZE>256), uint16_t, uint8_t>::type ring_buffer_pos_t; + typedef uvalue_t(Cfg::RX_SIZE - 1) ring_buffer_pos_t; struct ring_buffer_r { volatile ring_buffer_pos_t head, tail; @@ -283,7 +276,7 @@ static constexpr bool DROPPED_RX = false; static constexpr bool RX_FRAMING_ERRORS = false; static constexpr bool MAX_RX_QUEUED = false; - static constexpr bool RX_OVERRUNS = BOTH(HAS_DGUS_LCD, SERIAL_STATS_RX_BUFFER_OVERRUNS); + static constexpr bool RX_OVERRUNS = ALL(HAS_DGUS_LCD, SERIAL_STATS_RX_BUFFER_OVERRUNS); }; typedef Serial1Class< MarlinSerial< LCDSerialCfg > > MSerialLCD; diff --git a/Marlin/src/HAL/AVR/eeprom.cpp b/Marlin/src/HAL/AVR/eeprom.cpp index 8d084dec7f..6465e47025 100644 --- a/Marlin/src/HAL/AVR/eeprom.cpp +++ b/Marlin/src/HAL/AVR/eeprom.cpp @@ -23,7 +23,7 @@ #include "../../inc/MarlinConfig.h" -#if EITHER(EEPROM_SETTINGS, SD_FIRMWARE_UPDATE) +#if ANY(EEPROM_SETTINGS, SD_FIRMWARE_UPDATE) /** * PersistentStore for Arduino-style EEPROM interface diff --git a/Marlin/src/HAL/AVR/endstop_interrupts.h b/Marlin/src/HAL/AVR/endstop_interrupts.h index 5511aa406f..2532624d39 100644 --- a/Marlin/src/HAL/AVR/endstop_interrupts.h +++ b/Marlin/src/HAL/AVR/endstop_interrupts.h @@ -120,7 +120,7 @@ void pciSetup(const int8_t pin) { void setup_endstop_interrupts() { #define _ATTACH(P) attachInterrupt(digitalPinToInterrupt(P), endstop_ISR, CHANGE) - #if HAS_X_MAX + #if USE_X_MAX #if (digitalPinToInterrupt(X_MAX_PIN) != NOT_AN_INTERRUPT) _ATTACH(X_MAX_PIN); #else @@ -128,7 +128,7 @@ void setup_endstop_interrupts() { pciSetup(X_MAX_PIN); #endif #endif - #if HAS_X_MIN + #if USE_X_MIN #if (digitalPinToInterrupt(X_MIN_PIN) != NOT_AN_INTERRUPT) _ATTACH(X_MIN_PIN); #else @@ -136,7 +136,7 @@ void setup_endstop_interrupts() { pciSetup(X_MIN_PIN); #endif #endif - #if HAS_Y_MAX + #if USE_Y_MAX #if (digitalPinToInterrupt(Y_MAX_PIN) != NOT_AN_INTERRUPT) _ATTACH(Y_MAX_PIN); #else @@ -144,7 +144,7 @@ void setup_endstop_interrupts() { pciSetup(Y_MAX_PIN); #endif #endif - #if HAS_Y_MIN + #if USE_Y_MIN #if (digitalPinToInterrupt(Y_MIN_PIN) != NOT_AN_INTERRUPT) _ATTACH(Y_MIN_PIN); #else @@ -152,7 +152,7 @@ void setup_endstop_interrupts() { pciSetup(Y_MIN_PIN); #endif #endif - #if HAS_Z_MAX + #if USE_Z_MAX #if (digitalPinToInterrupt(Z_MAX_PIN) != NOT_AN_INTERRUPT) _ATTACH(Z_MAX_PIN); #else @@ -160,7 +160,7 @@ void setup_endstop_interrupts() { pciSetup(Z_MAX_PIN); #endif #endif - #if HAS_Z_MIN + #if USE_Z_MIN #if (digitalPinToInterrupt(Z_MIN_PIN) != NOT_AN_INTERRUPT) _ATTACH(Z_MIN_PIN); #else @@ -168,97 +168,97 @@ void setup_endstop_interrupts() { pciSetup(Z_MIN_PIN); #endif #endif - #if HAS_I_MAX + #if USE_I_MAX #if (digitalPinToInterrupt(I_MAX_PIN) != NOT_AN_INTERRUPT) _ATTACH(I_MAX_PIN); #else - static_assert(digitalPinHasPCICR(I_MAX_PIN), "I_MAX_PIN is not interrupt-capable"); + static_assert(digitalPinHasPCICR(I_MAX_PIN), "I_MAX_PIN is not interrupt-capable. Disable ENDSTOP_INTERRUPTS_FEATURE to continue."); pciSetup(I_MAX_PIN); #endif - #elif HAS_I_MIN + #elif USE_I_MIN #if (digitalPinToInterrupt(I_MIN_PIN) != NOT_AN_INTERRUPT) _ATTACH(I_MIN_PIN); #else - static_assert(digitalPinHasPCICR(I_MIN_PIN), "I_MIN_PIN is not interrupt-capable"); + static_assert(digitalPinHasPCICR(I_MIN_PIN), "I_MIN_PIN is not interrupt-capable. Disable ENDSTOP_INTERRUPTS_FEATURE to continue."); pciSetup(I_MIN_PIN); #endif #endif - #if HAS_J_MAX + #if USE_J_MAX #if (digitalPinToInterrupt(J_MAX_PIN) != NOT_AN_INTERRUPT) _ATTACH(J_MAX_PIN); #else - static_assert(digitalPinHasPCICR(J_MAX_PIN), "J_MAX_PIN is not interrupt-capable"); + static_assert(digitalPinHasPCICR(J_MAX_PIN), "J_MAX_PIN is not interrupt-capable. Disable ENDSTOP_INTERRUPTS_FEATURE to continue."); pciSetup(J_MAX_PIN); #endif - #elif HAS_J_MIN + #elif USE_J_MIN #if (digitalPinToInterrupt(J_MIN_PIN) != NOT_AN_INTERRUPT) _ATTACH(J_MIN_PIN); #else - static_assert(digitalPinHasPCICR(J_MIN_PIN), "J_MIN_PIN is not interrupt-capable"); + static_assert(digitalPinHasPCICR(J_MIN_PIN), "J_MIN_PIN is not interrupt-capable. Disable ENDSTOP_INTERRUPTS_FEATURE to continue."); pciSetup(J_MIN_PIN); #endif #endif - #if HAS_K_MAX + #if USE_K_MAX #if (digitalPinToInterrupt(K_MAX_PIN) != NOT_AN_INTERRUPT) _ATTACH(K_MAX_PIN); #else - static_assert(digitalPinHasPCICR(K_MAX_PIN), "K_MAX_PIN is not interrupt-capable"); + static_assert(digitalPinHasPCICR(K_MAX_PIN), "K_MAX_PIN is not interrupt-capable. Disable ENDSTOP_INTERRUPTS_FEATURE to continue."); pciSetup(K_MAX_PIN); #endif - #elif HAS_K_MIN + #elif USE_K_MIN #if (digitalPinToInterrupt(K_MIN_PIN) != NOT_AN_INTERRUPT) _ATTACH(K_MIN_PIN); #else - static_assert(digitalPinHasPCICR(K_MIN_PIN), "K_MIN_PIN is not interrupt-capable"); + static_assert(digitalPinHasPCICR(K_MIN_PIN), "K_MIN_PIN is not interrupt-capable. Disable ENDSTOP_INTERRUPTS_FEATURE to continue."); pciSetup(K_MIN_PIN); #endif #endif - #if HAS_U_MAX + #if USE_U_MAX #if (digitalPinToInterrupt(U_MAX_PIN) != NOT_AN_INTERRUPT) _ATTACH(U_MAX_PIN); #else - static_assert(digitalPinHasPCICR(U_MAX_PIN), "U_MAX_PIN is not interrupt-capable"); + static_assert(digitalPinHasPCICR(U_MAX_PIN), "U_MAX_PIN is not interrupt-capable. Disable ENDSTOP_INTERRUPTS_FEATURE to continue."); pciSetup(U_MAX_PIN); #endif - #elif HAS_U_MIN + #elif USE_U_MIN #if (digitalPinToInterrupt(U_MIN_PIN) != NOT_AN_INTERRUPT) _ATTACH(U_MIN_PIN); #else - static_assert(digitalPinHasPCICR(U_MIN_PIN), "U_MIN_PIN is not interrupt-capable"); + static_assert(digitalPinHasPCICR(U_MIN_PIN), "U_MIN_PIN is not interrupt-capable. Disable ENDSTOP_INTERRUPTS_FEATURE to continue."); pciSetup(U_MIN_PIN); #endif #endif - #if HAS_V_MAX + #if USE_V_MAX #if (digitalPinToInterrupt(V_MAX_PIN) != NOT_AN_INTERRUPT) _ATTACH(V_MAX_PIN); #else - static_assert(digitalPinHasPCICR(V_MAX_PIN), "V_MAX_PIN is not interrupt-capable"); + static_assert(digitalPinHasPCICR(V_MAX_PIN), "V_MAX_PIN is not interrupt-capable. Disable ENDSTOP_INTERRUPTS_FEATURE to continue."); pciSetup(V_MAX_PIN); #endif - #elif HAS_V_MIN + #elif USE_V_MIN #if (digitalPinToInterrupt(V_MIN_PIN) != NOT_AN_INTERRUPT) _ATTACH(V_MIN_PIN); #else - static_assert(digitalPinHasPCICR(V_MIN_PIN), "V_MIN_PIN is not interrupt-capable"); + static_assert(digitalPinHasPCICR(V_MIN_PIN), "V_MIN_PIN is not interrupt-capable. Disable ENDSTOP_INTERRUPTS_FEATURE to continue."); pciSetup(V_MIN_PIN); #endif #endif - #if HAS_W_MAX + #if USE_W_MAX #if (digitalPinToInterrupt(W_MAX_PIN) != NOT_AN_INTERRUPT) _ATTACH(W_MAX_PIN); #else - static_assert(digitalPinHasPCICR(W_MAX_PIN), "W_MAX_PIN is not interrupt-capable"); + static_assert(digitalPinHasPCICR(W_MAX_PIN), "W_MAX_PIN is not interrupt-capable. Disable ENDSTOP_INTERRUPTS_FEATURE to continue."); pciSetup(W_MAX_PIN); #endif - #elif HAS_W_MIN + #elif USE_W_MIN #if (digitalPinToInterrupt(W_MIN_PIN) != NOT_AN_INTERRUPT) _ATTACH(W_MIN_PIN); #else - static_assert(digitalPinHasPCICR(W_MIN_PIN), "W_MIN_PIN is not interrupt-capable"); + static_assert(digitalPinHasPCICR(W_MIN_PIN), "W_MIN_PIN is not interrupt-capable. Disable ENDSTOP_INTERRUPTS_FEATURE to continue."); pciSetup(W_MIN_PIN); #endif #endif - #if HAS_X2_MAX + #if USE_X2_MAX #if (digitalPinToInterrupt(X2_MAX_PIN) != NOT_AN_INTERRUPT) _ATTACH(X2_MAX_PIN); #else @@ -266,7 +266,7 @@ void setup_endstop_interrupts() { pciSetup(X2_MAX_PIN); #endif #endif - #if HAS_X2_MIN + #if USE_X2_MIN #if (digitalPinToInterrupt(X2_MIN_PIN) != NOT_AN_INTERRUPT) _ATTACH(X2_MIN_PIN); #else @@ -274,7 +274,7 @@ void setup_endstop_interrupts() { pciSetup(X2_MIN_PIN); #endif #endif - #if HAS_Y2_MAX + #if USE_Y2_MAX #if (digitalPinToInterrupt(Y2_MAX_PIN) != NOT_AN_INTERRUPT) _ATTACH(Y2_MAX_PIN); #else @@ -282,7 +282,7 @@ void setup_endstop_interrupts() { pciSetup(Y2_MAX_PIN); #endif #endif - #if HAS_Y2_MIN + #if USE_Y2_MIN #if (digitalPinToInterrupt(Y2_MIN_PIN) != NOT_AN_INTERRUPT) _ATTACH(Y2_MIN_PIN); #else @@ -290,7 +290,7 @@ void setup_endstop_interrupts() { pciSetup(Y2_MIN_PIN); #endif #endif - #if HAS_Z2_MAX + #if USE_Z2_MAX #if (digitalPinToInterrupt(Z2_MAX_PIN) != NOT_AN_INTERRUPT) _ATTACH(Z2_MAX_PIN); #else @@ -298,7 +298,7 @@ void setup_endstop_interrupts() { pciSetup(Z2_MAX_PIN); #endif #endif - #if HAS_Z2_MIN + #if USE_Z2_MIN #if (digitalPinToInterrupt(Z2_MIN_PIN) != NOT_AN_INTERRUPT) _ATTACH(Z2_MIN_PIN); #else @@ -306,7 +306,7 @@ void setup_endstop_interrupts() { pciSetup(Z2_MIN_PIN); #endif #endif - #if HAS_Z3_MAX + #if USE_Z3_MAX #if (digitalPinToInterrupt(Z3_MAX_PIN) != NOT_AN_INTERRUPT) _ATTACH(Z3_MAX_PIN); #else @@ -314,7 +314,7 @@ void setup_endstop_interrupts() { pciSetup(Z3_MAX_PIN); #endif #endif - #if HAS_Z3_MIN + #if USE_Z3_MIN #if (digitalPinToInterrupt(Z3_MIN_PIN) != NOT_AN_INTERRUPT) _ATTACH(Z3_MIN_PIN); #else @@ -322,7 +322,7 @@ void setup_endstop_interrupts() { pciSetup(Z3_MIN_PIN); #endif #endif - #if HAS_Z4_MAX + #if USE_Z4_MAX #if (digitalPinToInterrupt(Z4_MAX_PIN) != NOT_AN_INTERRUPT) _ATTACH(Z4_MAX_PIN); #else @@ -330,7 +330,7 @@ void setup_endstop_interrupts() { pciSetup(Z4_MAX_PIN); #endif #endif - #if HAS_Z4_MIN + #if USE_Z4_MIN #if (digitalPinToInterrupt(Z4_MIN_PIN) != NOT_AN_INTERRUPT) _ATTACH(Z4_MIN_PIN); #else @@ -338,7 +338,7 @@ void setup_endstop_interrupts() { pciSetup(Z4_MIN_PIN); #endif #endif - #if HAS_Z_MIN_PROBE_PIN + #if USE_Z_MIN_PROBE #if (digitalPinToInterrupt(Z_MIN_PROBE_PIN) != NOT_AN_INTERRUPT) _ATTACH(Z_MIN_PROBE_PIN); #else diff --git a/Marlin/src/HAL/AVR/fast_pwm.cpp b/Marlin/src/HAL/AVR/fast_pwm.cpp index e440315e00..6da68e6245 100644 --- a/Marlin/src/HAL/AVR/fast_pwm.cpp +++ b/Marlin/src/HAL/AVR/fast_pwm.cpp @@ -23,6 +23,10 @@ #include "../../inc/MarlinConfig.h" +//#define DEBUG_AVR_FAST_PWM +#define DEBUG_OUT ENABLED(DEBUG_AVR_FAST_PWM) +#include "../../core/debug_out.h" + struct Timer { volatile uint8_t* TCCRnQ[3]; // max 3 TCCR registers per timer volatile uint16_t* OCRnQ[3]; // max 3 OCR registers per timer @@ -108,12 +112,15 @@ const Timer get_pwm_timer(const pin_t pin) { } void MarlinHAL::set_pwm_frequency(const pin_t pin, const uint16_t f_desired) { + DEBUG_ECHOLNPGM("set_pwm_frequency(pin=", pin, ", freq=", f_desired, ")"); const Timer timer = get_pwm_timer(pin); if (timer.isProtected || !timer.isPWM) return; // Don't proceed if protected timer or not recognized const bool is_timer2 = timer.n == 2; const uint16_t maxtop = is_timer2 ? 0xFF : 0xFFFF; + DEBUG_ECHOLNPGM("maxtop=", maxtop); + uint16_t res = 0xFF; // resolution (TOP value) uint8_t j = CS_NONE; // prescaler index uint8_t wgm = WGM_PWM_PC_8; // waveform generation mode @@ -121,23 +128,29 @@ void MarlinHAL::set_pwm_frequency(const pin_t pin, const uint16_t f_desired) { // Calculating the prescaler and resolution to use to achieve closest frequency if (f_desired != 0) { constexpr uint16_t prescaler[] = { 1, 8, (32), 64, (128), 256, 1024 }; // (*) are Timer 2 only - uint16_t f = (F_CPU) / (2 * 1024 * maxtop) + 1; // Start with the lowest non-zero frequency achievable (1 or 31) + uint16_t f = (F_CPU) / (uint32_t(maxtop) << 11) + 1; // Start with the lowest non-zero frequency achievable (for 16MHz, 1 or 31) - LOOP_L_N(i, COUNT(prescaler)) { // Loop through all prescaler values - const uint16_t p = prescaler[i]; + DEBUG_ECHOLNPGM("f=", f); + DEBUG_ECHOLNPGM("(prescaler loop)"); + for (uint8_t i = 0; i < COUNT(prescaler); ++i) { // Loop through all prescaler values + const uint32_t p = prescaler[i]; // Extend to 32 bits for calculations + DEBUG_ECHOLNPGM("prescaler[", i, "]=", p); uint16_t res_fast_temp, res_pc_temp; if (is_timer2) { #if ENABLED(USE_OCR2A_AS_TOP) // No resolution calculation for TIMER2 unless enabled USE_OCR2A_AS_TOP const uint16_t rft = (F_CPU) / (p * f_desired); res_fast_temp = rft - 1; res_pc_temp = rft / 2; + DEBUG_ECHOLNPGM("(Timer2) res_fast_temp=", res_fast_temp, " res_pc_temp=", res_pc_temp); #else res_fast_temp = res_pc_temp = maxtop; + DEBUG_ECHOLNPGM("(Timer2) res_fast_temp=", maxtop, " res_pc_temp=", maxtop); #endif } else { if (p == 32 || p == 128) continue; // Skip TIMER2 specific prescalers when not TIMER2 const uint16_t rft = (F_CPU) / (p * f_desired); + DEBUG_ECHOLNPGM("(Not Timer 2) F_CPU=" STRINGIFY(F_CPU), " prescaler=", p, " f_desired=", f_desired); res_fast_temp = rft - 1; res_pc_temp = rft / 2; } @@ -146,24 +159,28 @@ void MarlinHAL::set_pwm_frequency(const pin_t pin, const uint16_t f_desired) { LIMIT(res_pc_temp, 1U, maxtop); // Calculate frequencies of test prescaler and resolution values - const int f_diff = ABS(f - int(f_desired)), - f_fast_temp = (F_CPU) / (p * (1 + res_fast_temp)), - f_fast_diff = ABS(f_fast_temp - int(f_desired)), - f_pc_temp = (F_CPU) / (2 * p * res_pc_temp), - f_pc_diff = ABS(f_pc_temp - int(f_desired)); + const uint16_t f_fast_temp = (F_CPU) / (p * (1 + res_fast_temp)), + f_pc_temp = (F_CPU) / ((p * res_pc_temp) << 1), + f_diff = _MAX(f, f_desired) - _MIN(f, f_desired), + f_fast_diff = _MAX(f_fast_temp, f_desired) - _MIN(f_fast_temp, f_desired), + f_pc_diff = _MAX(f_pc_temp, f_desired) - _MIN(f_pc_temp, f_desired); + + DEBUG_ECHOLNPGM("f_fast_temp=", f_fast_temp, " f_pc_temp=", f_pc_temp, " f_diff=", f_diff, " f_fast_diff=", f_fast_diff, " f_pc_diff=", f_pc_diff); if (f_fast_diff < f_diff && f_fast_diff <= f_pc_diff) { // FAST values are closest to desired f // Set the Wave Generation Mode to FAST PWM wgm = is_timer2 ? uint8_t(TERN(USE_OCR2A_AS_TOP, WGM2_FAST_PWM_OCR2A, WGM2_FAST_PWM)) : uint8_t(WGM_FAST_PWM_ICRn); // Remember this combination f = f_fast_temp; res = res_fast_temp; j = i + 1; + DEBUG_ECHOLNPGM("(FAST) updated f=", f); } else if (f_pc_diff < f_diff) { // PHASE CORRECT values are closes to desired f // Set the Wave Generation Mode to PWM PHASE CORRECT wgm = is_timer2 ? uint8_t(TERN(USE_OCR2A_AS_TOP, WGM2_PWM_PC_OCR2A, WGM2_PWM_PC)) : uint8_t(WGM_PWM_PC_ICRn); f = f_pc_temp; res = res_pc_temp; j = i + 1; + DEBUG_ECHOLNPGM("(PHASE) updated f=", f); } - } + } // prescaler loop } _SET_WGMnQ(timer, wgm); @@ -215,7 +232,7 @@ void MarlinHAL::init_pwm_timers() { #endif }; - LOOP_L_N(i, COUNT(pwm_pin)) + for (uint8_t i = 0; i < COUNT(pwm_pin); ++i) set_pwm_frequency(pwm_pin[i], 1000); } diff --git a/Marlin/src/HAL/AVR/fastio.h b/Marlin/src/HAL/AVR/fastio.h index 612ab902e3..4516d9cd54 100644 --- a/Marlin/src/HAL/AVR/fastio.h +++ b/Marlin/src/HAL/AVR/fastio.h @@ -255,84 +255,6 @@ enum ClockSource2 : uint8_t { #define SET_FOCB(T,V) SET_FOC(T,B,V) #define SET_FOCC(T,V) SET_FOC(T,C,V) -#if 0 - -/** - * PWM availability macros - */ - -// Determine which hardware PWMs are already in use -#define _PWM_CHK_FAN_B(P) (P == E0_AUTO_FAN_PIN || P == E1_AUTO_FAN_PIN || P == E2_AUTO_FAN_PIN || P == E3_AUTO_FAN_PIN || P == E4_AUTO_FAN_PIN || P == E5_AUTO_FAN_PIN || P == E6_AUTO_FAN_PIN || P == E7_AUTO_FAN_PIN || P == CHAMBER_AUTO_FAN_PIN || P == COOLER_AUTO_FAN_PIN) -#if PIN_EXISTS(CONTROLLER_FAN) - #define PWM_CHK_FAN_B(P) (_PWM_CHK_FAN_B(P) || P == CONTROLLER_FAN_PIN) -#else - #define PWM_CHK_FAN_B(P) _PWM_CHK_FAN_B(P) -#endif - -#if ANY_PIN(FAN, FAN1, FAN2, FAN3, FAN4, FAN5, FAN6, FAN7) - #if PIN_EXISTS(FAN7) - #define PWM_CHK_FAN_A(P) (P == FAN0_PIN || P == FAN1_PIN || P == FAN2_PIN || P == FAN3_PIN || P == FAN4_PIN || P == FAN5_PIN || P == FAN6_PIN || P == FAN7_PIN) - #elif PIN_EXISTS(FAN6) - #define PWM_CHK_FAN_A(P) (P == FAN0_PIN || P == FAN1_PIN || P == FAN2_PIN || P == FAN3_PIN || P == FAN4_PIN || P == FAN5_PIN || P == FAN6_PIN) - #elif PIN_EXISTS(FAN5) - #define PWM_CHK_FAN_A(P) (P == FAN0_PIN || P == FAN1_PIN || P == FAN2_PIN || P == FAN3_PIN || P == FAN4_PIN || P == FAN5_PIN) - #elif PIN_EXISTS(FAN4) - #define PWM_CHK_FAN_A(P) (P == FAN0_PIN || P == FAN1_PIN || P == FAN2_PIN || P == FAN3_PIN || P == FAN4_PIN) - #elif PIN_EXISTS(FAN3) - #define PWM_CHK_FAN_A(P) (P == FAN0_PIN || P == FAN1_PIN || P == FAN2_PIN || P == FAN3_PIN) - #elif PIN_EXISTS(FAN2) - #define PWM_CHK_FAN_A(P) (P == FAN0_PIN || P == FAN1_PIN || P == FAN2_PIN) - #elif PIN_EXISTS(FAN1) - #define PWM_CHK_FAN_A(P) (P == FAN0_PIN || P == FAN1_PIN) - #else - #define PWM_CHK_FAN_A(P) (P == FAN0_PIN) - #endif -#else - #define PWM_CHK_FAN_A(P) false -#endif - -#if HAS_MOTOR_CURRENT_PWM - #if PIN_EXISTS(MOTOR_CURRENT_PWM_XY) - #define PWM_CHK_MOTOR_CURRENT(P) (P == MOTOR_CURRENT_PWM_E || P == MOTOR_CURRENT_PWM_E0 || P == MOTOR_CURRENT_PWM_E1 || P == MOTOR_CURRENT_PWM_Z || P == MOTOR_CURRENT_PWM_XY) - #elif PIN_EXISTS(MOTOR_CURRENT_PWM_Z) - #define PWM_CHK_MOTOR_CURRENT(P) (P == MOTOR_CURRENT_PWM_E || P == MOTOR_CURRENT_PWM_E0 || P == MOTOR_CURRENT_PWM_E1 || P == MOTOR_CURRENT_PWM_Z) - #else - #define PWM_CHK_MOTOR_CURRENT(P) (P == MOTOR_CURRENT_PWM_E || P == MOTOR_CURRENT_PWM_E0 || P == MOTOR_CURRENT_PWM_E1) - #endif -#else - #define PWM_CHK_MOTOR_CURRENT(P) false -#endif - -#ifdef NUM_SERVOS - #if AVR_ATmega2560_FAMILY - #define PWM_CHK_SERVO(P) (P == 5 || (NUM_SERVOS > 12 && P == 6) || (NUM_SERVOS > 24 && P == 46)) // PWMS 3A, 4A & 5A - #elif AVR_ATmega2561_FAMILY - #define PWM_CHK_SERVO(P) (P == 5) // PWM3A - #elif AVR_ATmega1284_FAMILY - #define PWM_CHK_SERVO(P) false - #elif AVR_AT90USB1286_FAMILY - #define PWM_CHK_SERVO(P) (P == 16) // PWM3A - #elif AVR_ATmega328_FAMILY - #define PWM_CHK_SERVO(P) false - #endif -#else - #define PWM_CHK_SERVO(P) false -#endif - -#if ENABLED(BARICUDA) - #if HAS_HEATER_1 && HAS_HEATER_2 - #define PWM_CHK_HEATER(P) (P == HEATER_1_PIN || P == HEATER_2_PIN) - #elif HAS_HEATER_1 - #define PWM_CHK_HEATER(P) (P == HEATER_1_PIN) - #endif -#else - #define PWM_CHK_HEATER(P) false -#endif - -#define PWM_CHK(P) (PWM_CHK_HEATER(P) || PWM_CHK_SERVO(P) || PWM_CHK_MOTOR_CURRENT(P) || PWM_CHK_FAN_A(P) || PWM_CHK_FAN_B(P)) - -#endif // PWM_CHK is not used in Marlin - // define which hardware PWMs are available for the current CPU // all timer 1 PWMS deleted from this list because they are never available #if AVR_ATmega2560_FAMILY diff --git a/Marlin/src/HAL/AVR/fastio/fastio_1280.h b/Marlin/src/HAL/AVR/fastio/fastio_1280.h index f482f823e8..633774dda9 100644 --- a/Marlin/src/HAL/AVR/fastio/fastio_1280.h +++ b/Marlin/src/HAL/AVR/fastio/fastio_1280.h @@ -27,43 +27,44 @@ * Hardware Pin : 02 03 06 07 01 05 15 16 17 18 23 24 25 26 64 63 13 12 46 45 44 43 78 77 76 75 74 73 72 71 60 59 58 57 56 55 54 53 50 70 52 51 42 41 40 39 38 37 36 35 22 21 20 19 97 96 95 94 93 92 91 90 89 88 87 86 85 84 83 82 | 04 08 09 10 11 14 27 28 29 30 31 32 33 34 47 48 49 61 62 65 66 67 68 69 79 80 81 98 99 100 * Port : E0 E1 E4 E5 G5 E3 H3 H4 H5 H6 B4 B5 B6 B7 J1 J0 H1 H0 D3 D2 D1 D0 A0 A1 A2 A3 A4 A5 A6 A7 C7 C6 C5 C4 C3 C2 C1 C0 D7 G2 G1 G0 L7 L6 L5 L4 L3 L2 L1 L0 B3 B2 B1 B0 F0 F1 F2 F3 F4 F5 F6 F7 K0 K1 K2 K3 K4 K5 K6 K7 | E2 E6 E7 xx xx H2 H7 G3 G4 xx xx xx xx xx D4 D5 D6 xx xx J2 J3 J4 J5 J6 J7 xx xx xx xx xx * Logical Pin : 00 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 | 78 79 80 xx xx 84 85 71 70 xx xx xx xx xx 81 82 83 xx xx 72 73 75 76 77 74 xx xx xx xx xx + * Analog Input : 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 + * + * Arduino Pin Layout video: https://youtu.be/rIqeVCX09FA + * AVR alternate pin function overview video: https://youtu.be/1yd8wuI5Plg */ #include "../fastio.h" -// change for your board -#define DEBUG_LED DIO21 - // UART -#define RXD DIO0 -#define TXD DIO1 +#define RXD 0 +#define TXD 1 // SPI -#define SCK DIO52 -#define MISO DIO50 -#define MOSI DIO51 -#define SS DIO53 +#define MISO 50 +#define MOSI 51 +#define SCK 52 +#define SS 53 // TWI (I2C) -#define SCL DIO21 -#define SDA DIO20 +#define SCL 21 +#define SDA 20 // Timers and PWM -#define OC0A DIO13 -#define OC0B DIO4 -#define OC1A DIO11 -#define OC1B DIO12 -#define OC2A DIO10 -#define OC2B DIO9 -#define OC3A DIO5 -#define OC3B DIO2 -#define OC3C DIO3 -#define OC4A DIO6 -#define OC4B DIO7 -#define OC4C DIO8 -#define OC5A DIO46 -#define OC5B DIO45 -#define OC5C DIO44 +#define OC0A 13 +#define OC0B 4 +#define OC1A 11 +#define OC1B 12 +#define OC2A 10 +#define OC2B 9 +#define OC3A 5 +#define OC3B 2 +#define OC3C 3 +#define OC4A 6 +#define OC4B 7 +#define OC4C 8 +#define OC5A 46 +#define OC5B 45 +#define OC5C 44 // Digital I/O diff --git a/Marlin/src/HAL/AVR/fastio/fastio_1281.h b/Marlin/src/HAL/AVR/fastio/fastio_1281.h index e0bc5e2995..6067248978 100644 --- a/Marlin/src/HAL/AVR/fastio/fastio_1281.h +++ b/Marlin/src/HAL/AVR/fastio/fastio_1281.h @@ -26,36 +26,36 @@ * * Logical Pin: 38 39 40 41 42 43 44 45 16 10 11 12 06 07 08 09 30 31 32 33 34 35 36 37 17 18 19 20 21 22 23 24 00 01 13 05 02 03 14 15 46 47 48 49 50 51 52 53 25 26 27 28 29 04 * Port: A0 A1 A2 A3 A4 A5 A6 A7 B0 B1 B2 B3 B4 B5 B6 B7 C0 C1 C2 C3 C4 C5 C6 C7 D0 D1 D2 D3 D4 D5 D6 D7 E0 E1 E2 E3 E4 E5 E6 E7 F0 F1 F2 F3 F4 F5 F6 F7 G0 G1 G2 G3 G4 G5 + * + * Arduino Pin Layout video: https://youtu.be/rIqeVCX09FA + * AVR alternate pin function overview video: https://youtu.be/1yd8wuI5Plg */ #include "../fastio.h" -// change for your board -#define DEBUG_LED DIO46 - // UART -#define RXD DIO0 -#define TXD DIO1 +#define RXD 0 +#define TXD 1 // SPI -#define SCK DIO10 -#define MISO DIO12 -#define MOSI DIO11 -#define SS DIO16 +#define SCK 10 +#define MISO 12 +#define MOSI 11 +#define SS 16 // TWI (I2C) -#define SCL DIO17 -#define SDA DIO18 +#define SCL 17 +#define SDA 18 // Timers and PWM -#define OC0A DIO9 -#define OC0B DIO4 -#define OC1A DIO7 -#define OC1B DIO8 -#define OC2A DIO6 -#define OC3A DIO5 -#define OC3B DIO2 -#define OC3C DIO3 +#define OC0A 9 +#define OC0B 4 +#define OC1A 7 +#define OC1B 8 +#define OC2A 6 +#define OC3A 5 +#define OC3B 2 +#define OC3C 3 // Digital I/O diff --git a/Marlin/src/HAL/AVR/fastio/fastio_168.h b/Marlin/src/HAL/AVR/fastio/fastio_168.h index 8cfdd1e8f8..cc55979740 100644 --- a/Marlin/src/HAL/AVR/fastio/fastio_168.h +++ b/Marlin/src/HAL/AVR/fastio/fastio_168.h @@ -26,33 +26,34 @@ * * Logical Pin: 08 09 10 11 12 13 14 15 16 17 18 19 20 21 00 01 02 03 04 05 06 07 * Port: B0 B1 B2 B3 B4 B5 C0 C1 C2 C3 C4 C5 C6 C7 D0 D1 D2 D3 D4 D5 D6 D7 + * + * Arduino Pin Layout video: https://youtu.be/rIqeVCX09FA + * AVR alternate pin function overview video: https://youtu.be/1yd8wuI5Plg */ #include "../fastio.h" -#define DEBUG_LED AIO5 - // UART -#define RXD DIO0 -#define TXD DIO1 +#define RXD 0 +#define TXD 1 // SPI -#define SCK DIO13 -#define MISO DIO12 -#define MOSI DIO11 -#define SS DIO10 +#define SS 10 +#define MOSI 11 +#define MISO 12 +#define SCK 13 // TWI (I2C) #define SCL AIO5 #define SDA AIO4 // Timers and PWM -#define OC0A DIO6 -#define OC0B DIO5 -#define OC1A DIO9 -#define OC1B DIO10 -#define OC2A DIO11 -#define OC2B DIO3 +#define OC0A 6 +#define OC0B 5 +#define OC1A 9 +#define OC1B 10 +#define OC2A 11 +#define OC2B 3 // Digital I/O diff --git a/Marlin/src/HAL/AVR/fastio/fastio_644.h b/Marlin/src/HAL/AVR/fastio/fastio_644.h index f4a9427e0a..94b322a819 100644 --- a/Marlin/src/HAL/AVR/fastio/fastio_644.h +++ b/Marlin/src/HAL/AVR/fastio/fastio_644.h @@ -26,6 +26,9 @@ * * Logical Pin: 00 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 * Port: B0 B1 B2 B3 B4 B5 B6 B7 D0 D1 D2 D3 D4 D5 D6 D7 C0 C1 C2 C3 C4 C5 C6 C7 A7 A6 A5 A4 A3 A2 A1 A0 + * + * Arduino Pin Layout video: https://youtu.be/rIqeVCX09FA + * AVR alternate pin function overview video: https://youtu.be/1yd8wuI5Plg */ /** ATMega644 @@ -56,34 +59,32 @@ #include "../fastio.h" -#define DEBUG_LED DIO0 - // UART -#define RXD DIO8 -#define TXD DIO9 -#define RXD0 DIO8 -#define TXD0 DIO9 +#define RXD 8 +#define TXD 9 +#define RXD0 8 +#define TXD0 9 -#define RXD1 DIO10 -#define TXD1 DIO11 +#define RXD1 10 +#define TXD1 11 // SPI -#define SCK DIO7 -#define MISO DIO6 -#define MOSI DIO5 -#define SS DIO4 +#define SS 4 +#define MOSI 5 +#define MISO 6 +#define SCK 7 // TWI (I2C) -#define SCL DIO16 -#define SDA DIO17 +#define SCL 16 +#define SDA 17 // Timers and PWM -#define OC0A DIO3 -#define OC0B DIO4 -#define OC1A DIO13 -#define OC1B DIO12 -#define OC2A DIO15 -#define OC2B DIO14 +#define OC0A 3 +#define OC0B 4 +#define OC1A 13 +#define OC1B 12 +#define OC2A 15 +#define OC2B 14 // Digital I/O diff --git a/Marlin/src/HAL/AVR/fastio/fastio_AT90USB.h b/Marlin/src/HAL/AVR/fastio/fastio_AT90USB.h index 51d400b705..0c434b157c 100644 --- a/Marlin/src/HAL/AVR/fastio/fastio_AT90USB.h +++ b/Marlin/src/HAL/AVR/fastio/fastio_AT90USB.h @@ -27,18 +27,18 @@ * Logical Pin: 28 29 30 31 32 33 34 35 20 21 22 23 24 25 26 27 10 11 12 13 14 15 16 17 00 01 02 03 04 05 06 07 08 09(46*47)36 37 18 19 38 39 40 41 42 43 44 45 * Port: A0 A1 A2 A3 A4 A5 A6 A7 B0 B1 B2 B3 B4 B5 B6 B7 C0 C1 C2 C3 C4 C5 C6 C7 D0 D1 D2 D3 D4 D5 D6 D7 E0 E1 E2 E3 E4 E5 E6 E7 F0 F1 F2 F3 F4 F5 F6 F7 * The logical pins 46 and 47 are not supported by Teensyduino, but are supported below as E2 and E3 + * + * Arduino Pin Layout video: https://youtu.be/rIqeVCX09FA + * AVR alternate pin function overview video: https://youtu.be/1yd8wuI5Plg */ #include "../fastio.h" -// change for your board -#define DEBUG_LED DIO31 /* led D5 red */ - // SPI -#define SCK DIO21 // 9 -#define MISO DIO23 // 11 -#define MOSI DIO22 // 10 -#define SS DIO20 // 8 +#define SS 20 // 8 +#define SCK 21 // 9 +#define MOSI 22 // 10 +#define MISO 23 // 11 // Digital I/O diff --git a/Marlin/src/HAL/AVR/inc/Conditionals_LCD.h b/Marlin/src/HAL/AVR/inc/Conditionals_LCD.h index a611ccd7c4..65b019b261 100644 --- a/Marlin/src/HAL/AVR/inc/Conditionals_LCD.h +++ b/Marlin/src/HAL/AVR/inc/Conditionals_LCD.h @@ -21,6 +21,6 @@ */ #pragma once -#if HAS_SPI_TFT || HAS_FSMC_TFT - #error "Sorry! TFT displays are not available for HAL/AVR." +#ifndef SERIAL_PORT + #define SERIAL_PORT 0 #endif diff --git a/Marlin/src/HAL/AVR/inc/SanityCheck.h b/Marlin/src/HAL/AVR/inc/SanityCheck.h index ff1610f741..85ee683685 100644 --- a/Marlin/src/HAL/AVR/inc/SanityCheck.h +++ b/Marlin/src/HAL/AVR/inc/SanityCheck.h @@ -25,17 +25,21 @@ * Test AVR-specific configuration values for errors at compile-time. */ +#if HAS_SPI_TFT || HAS_FSMC_TFT + #error "Sorry! TFT displays are not available for HAL/AVR." +#endif + /** * Check for common serial pin conflicts */ #define CHECK_SERIAL_PIN(N) ( \ - X_STOP_PIN == N || Y_STOP_PIN == N || Z_STOP_PIN == N \ - || X_MIN_PIN == N || Y_MIN_PIN == N || Z_MIN_PIN == N \ - || X_MAX_PIN == N || Y_MAX_PIN == N || Z_MAX_PIN == N \ - || X_STEP_PIN == N || Y_STEP_PIN == N || Z_STEP_PIN == N \ - || X_DIR_PIN == N || Y_DIR_PIN == N || Z_DIR_PIN == N \ - || X_ENA_PIN == N || Y_ENA_PIN == N || Z_ENA_PIN == N \ - || BTN_EN1 == N || BTN_EN2 == N \ + X_STOP_PIN == N || Y_STOP_PIN == N || Z_STOP_PIN == N \ + || X_MIN_PIN == N || Y_MIN_PIN == N || Z_MIN_PIN == N \ + || X_MAX_PIN == N || Y_MAX_PIN == N || Z_MAX_PIN == N \ + || X_STEP_PIN == N || Y_STEP_PIN == N || Z_STEP_PIN == N \ + || X_DIR_PIN == N || Y_DIR_PIN == N || Z_DIR_PIN == N \ + || X_ENA_PIN == N || Y_ENA_PIN == N || Z_ENA_PIN == N \ + || BTN_EN1 == N || BTN_EN2 == N || LCD_PINS_EN == N \ ) #if SERIAL_IN_USE(0) // D0-D1. No known conflicts. @@ -69,8 +73,8 @@ /** * Checks for SOFT PWM */ -#if HAS_FAN0 && FAN_PIN == 9 && DISABLED(FAN_SOFT_PWM) && ENABLED(SPEAKER) - #error "FAN_PIN 9 Hardware PWM uses Timer 2 which conflicts with Arduino AVR Tone Timer (for SPEAKER)." +#if HAS_FAN0 && FAN0_PIN == 9 && DISABLED(FAN_SOFT_PWM) && ENABLED(SPEAKER) + #error "FAN0_PIN 9 Hardware PWM uses Timer 2 which conflicts with Arduino AVR Tone Timer (for SPEAKER)." #error "Disable SPEAKER or enable FAN_SOFT_PWM." #endif @@ -91,11 +95,11 @@ /** * The Trinamic library includes SoftwareSerial.h, leading to a compile error. */ -#if BOTH(HAS_TRINAMIC_CONFIG, ENDSTOP_INTERRUPTS_FEATURE) +#if ALL(HAS_TRINAMIC_CONFIG, ENDSTOP_INTERRUPTS_FEATURE) #error "TMCStepper includes SoftwareSerial.h which is incompatible with ENDSTOP_INTERRUPTS_FEATURE. Disable ENDSTOP_INTERRUPTS_FEATURE to continue." #endif -#if BOTH(HAS_TMC_SW_SERIAL, MONITOR_DRIVER_STATUS) +#if ALL(HAS_TMC_SW_SERIAL, MONITOR_DRIVER_STATUS) #error "MONITOR_DRIVER_STATUS causes performance issues when used with SoftwareSerial-connected drivers. Disable MONITOR_DRIVER_STATUS or use hardware serial to continue." #endif diff --git a/Marlin/src/HAL/AVR/math.h b/Marlin/src/HAL/AVR/math.h index 7dd1018ff1..16848524fa 100644 --- a/Marlin/src/HAL/AVR/math.h +++ b/Marlin/src/HAL/AVR/math.h @@ -27,13 +27,14 @@ // intRes = longIn1 * longIn2 >> 24 // uses: -// A[tmp] to store 0 -// B[tmp] to store bits 16-23 of the 48bit result. The top bit is used to round the two byte result. -// note that the lower two bytes and the upper byte of the 48bit result are not calculated. -// this can cause the result to be out by one as the lower bytes may cause carries into the upper ones. -// B A are bits 24-39 and are the returned value -// C B A is longIn1 -// D C B A is longIn2 +// r1, r0 for the result of mul. +// [tmp1] to store 0. +// [tmp2] to store bits 16-23 of the 56 bit result. The top bit of [tmp2] is used for rounding. +// Note that the lower two bytes and the upper two bytes of the 56 bit result are not calculated. +// This can cause the result to be out by one as the lower bytes may cause carries into the upper ones. +// [intRes] (A B) is bits 24-39 and is the returned value. +// [longIn1] (C B A) is a 24 bit parameter. +// [longIn2] (D C B A) is a 32 bit parameter. // FORCE_INLINE static uint16_t MultiU24X32toH16(uint32_t longIn1, uint32_t longIn2) { uint8_t tmp1; @@ -66,11 +67,9 @@ FORCE_INLINE static uint16_t MultiU24X32toH16(uint32_t longIn1, uint32_t longIn2 A("add %[tmp2], r1") A("adc %A[intRes], %[tmp1]") A("adc %B[intRes], %[tmp1]") - A("lsr %[tmp2]") - A("adc %A[intRes], %[tmp1]") - A("adc %B[intRes], %[tmp1]") A("mul %D[longIn2], %A[longIn1]") - A("add %A[intRes], r0") + A("lsl %[tmp2]") + A("adc %A[intRes], r0") A("adc %B[intRes], r1") A("mul %D[longIn2], %B[longIn1]") A("add %B[intRes], r0") @@ -85,29 +84,26 @@ FORCE_INLINE static uint16_t MultiU24X32toH16(uint32_t longIn1, uint32_t longIn2 return intRes; } -// intRes = intIn1 * intIn2 >> 16 +// charRes = charIn1 * charIn2 >> 8 // uses: -// r26 to store 0 -// r27 to store the byte 1 of the 24 bit result -FORCE_INLINE static uint16_t MultiU16X8toH16(uint8_t charIn1, uint16_t intIn2) { - uint8_t tmp; - uint16_t intRes; +// r1, r0 for the result of mul. After the mul, r0 holds bits 0-7 of the 16 bit result, +// and the top bit of r0 is used for rounding. +// [charRes] is bits 8-15 and is the returned value. +// [charIn1] is an 8 bit parameter. +// [charIn2] is an 8 bit parameter. +// +FORCE_INLINE static uint8_t MultiU8X8toH8(uint8_t charIn1, uint8_t charIn2) { + uint8_t charRes; __asm__ __volatile__ ( - A("clr %[tmp]") - A("mul %[charIn1], %B[intIn2]") - A("movw %A[intRes], r0") - A("mul %[charIn1], %A[intIn2]") - A("add %A[intRes], r1") - A("adc %B[intRes], %[tmp]") - A("lsr r0") - A("adc %A[intRes], %[tmp]") - A("adc %B[intRes], %[tmp]") + A("mul %[charIn1], %[charIn2]") + A("mov %[charRes], r1") A("clr r1") - : [intRes] "=&r" (intRes), - [tmp] "=&r" (tmp) + A("lsl r0") + A("adc %[charRes], r1") + : [charRes] "=&r" (charRes) : [charIn1] "d" (charIn1), - [intIn2] "d" (intIn2) + [charIn2] "d" (charIn2) : "cc" ); - return intRes; + return charRes; } diff --git a/Marlin/src/HAL/AVR/pinsDebug.h b/Marlin/src/HAL/AVR/pinsDebug.h index dab4e44715..fc51f41ef8 100644 --- a/Marlin/src/HAL/AVR/pinsDebug.h +++ b/Marlin/src/HAL/AVR/pinsDebug.h @@ -64,23 +64,25 @@ #define VALID_PIN(pin) (pin >= 0 && pin < NUM_DIGITAL_PINS ? 1 : 0) #if AVR_ATmega1284_FAMILY - #define DIGITAL_PIN_TO_ANALOG_PIN(P) int(analogInputToDigitalPin(0) - (P)) - #define IS_ANALOG(P) ((P) >= analogInputToDigitalPin(7) && (P) <= analogInputToDigitalPin(0)) + #define IS_ANALOG(P) WITHIN(P, analogInputToDigitalPin(7), analogInputToDigitalPin(0)) + #define DIGITAL_PIN_TO_ANALOG_PIN(P) int(IS_ANALOG(P) ? (P) - analogInputToDigitalPin(7) : -1) #else - #define DIGITAL_PIN_TO_ANALOG_PIN(P) int((P) - analogInputToDigitalPin(0)) - #define IS_ANALOG(P) ((P) >= analogInputToDigitalPin(0) && ((P) <= analogInputToDigitalPin(15) || (P) <= analogInputToDigitalPin(7))) + #define _ANALOG1(P) WITHIN(P, analogInputToDigitalPin(0), analogInputToDigitalPin(7)) + #define _ANALOG2(P) WITHIN(P, analogInputToDigitalPin(8), analogInputToDigitalPin(15)) + #define IS_ANALOG(P) (_ANALOG1(P) || _ANALOG2(P)) + #define DIGITAL_PIN_TO_ANALOG_PIN(P) int(_ANALOG1(P) ? (P) - analogInputToDigitalPin(0) : _ANALOG2(P) ? (P) - analogInputToDigitalPin(8) + 8 : -1) #endif #define GET_ARRAY_PIN(p) pgm_read_byte(&pin_array[p].pin) #define MULTI_NAME_PAD 26 // space needed to be pretty if not first name assigned to a pin void PRINT_ARRAY_NAME(uint8_t x) { PGM_P const name_mem_pointer = (PGM_P)pgm_read_ptr(&pin_array[x].name); - LOOP_L_N(y, MAX_NAME_LENGTH) { + for (uint8_t y = 0; y < MAX_NAME_LENGTH; ++y) { char temp_char = pgm_read_byte(name_mem_pointer + y); if (temp_char != 0) SERIAL_CHAR(temp_char); else { - LOOP_L_N(i, MAX_NAME_LENGTH - y) SERIAL_CHAR(' '); + for (uint8_t i = 0; i < MAX_NAME_LENGTH - y; ++i) SERIAL_CHAR(' '); break; } } @@ -88,7 +90,6 @@ void PRINT_ARRAY_NAME(uint8_t x) { #define GET_ARRAY_IS_DIGITAL(x) pgm_read_byte(&pin_array[x].is_digital) - #if defined(__AVR_ATmega1284P__) // 1284 IDE extensions set this to the number of #undef NUM_DIGITAL_PINS // digital only pins while all other CPUs have it #define NUM_DIGITAL_PINS 32 // set to digital only + digital/analog @@ -108,7 +109,7 @@ void PRINT_ARRAY_NAME(uint8_t x) { * Print a pin's PWM status. * Return true if it's currently a PWM pin. */ -static bool pwm_status(uint8_t pin) { +bool pwm_status(uint8_t pin) { char buffer[20]; // for the sprintf statements switch (digitalPinToTimer_DEBUG(pin)) { @@ -231,12 +232,12 @@ const volatile uint8_t* const PWM_OCR[][3] PROGMEM = { #define OCR_VAL(T, L) pgm_read_word(&PWM_OCR[T][L]) -static void err_is_counter() { SERIAL_ECHOPGM(" non-standard PWM mode"); } -static void err_is_interrupt() { SERIAL_ECHOPGM(" compare interrupt enabled"); } -static void err_prob_interrupt() { SERIAL_ECHOPGM(" overflow interrupt enabled"); } -static void print_is_also_tied() { SERIAL_ECHOPGM(" is also tied to this pin"); SERIAL_ECHO_SP(14); } +void err_is_counter() { SERIAL_ECHOPGM(" non-standard PWM mode"); } +void err_is_interrupt() { SERIAL_ECHOPGM(" compare interrupt enabled"); } +void err_prob_interrupt() { SERIAL_ECHOPGM(" overflow interrupt enabled"); } +void print_is_also_tied() { SERIAL_ECHOPGM(" is also tied to this pin"); SERIAL_ECHO_SP(14); } -inline void com_print(const uint8_t N, const uint8_t Z) { +void com_print(const uint8_t N, const uint8_t Z) { const uint8_t *TCCRA = (uint8_t*)TCCR_A(N); SERIAL_ECHOPGM(" COM", AS_DIGIT(N)); SERIAL_CHAR(Z); @@ -278,7 +279,7 @@ void timer_prefix(uint8_t T, char L, uint8_t N) { // T - timer L - pwm N - if (TEST(*TMSK, TOIE)) err_prob_interrupt(); } -static void pwm_details(uint8_t pin) { +void pwm_details(uint8_t pin) { switch (digitalPinToTimer_DEBUG(pin)) { #if ABTEST(0) @@ -352,47 +353,41 @@ static void pwm_details(uint8_t pin) { } // pwm_details #ifndef digitalRead_mod // Use Teensyduino's version of digitalRead - it doesn't disable the PWMs - int digitalRead_mod(const int8_t pin) { // same as digitalRead except the PWM stop section has been removed + int digitalRead_mod(const pin_t pin) { // same as digitalRead except the PWM stop section has been removed const uint8_t port = digitalPinToPort_DEBUG(pin); return (port != NOT_A_PIN) && (*portInputRegister(port) & digitalPinToBitMask_DEBUG(pin)) ? HIGH : LOW; } #endif -#ifndef PRINT_PORT +void print_port(const pin_t pin) { // print port number + #ifdef digitalPinToPort_DEBUG + uint8_t x; + SERIAL_ECHOPGM(" Port: "); + #if AVR_AT90USB1286_FAMILY + x = (pin == 46 || pin == 47) ? 'E' : digitalPinToPort_DEBUG(pin) + 64; + #else + x = digitalPinToPort_DEBUG(pin) + 64; + #endif + SERIAL_CHAR(x); - void print_port(int8_t pin) { // print port number - #ifdef digitalPinToPort_DEBUG - uint8_t x; - SERIAL_ECHOPGM(" Port: "); - #if AVR_AT90USB1286_FAMILY - x = (pin == 46 || pin == 47) ? 'E' : digitalPinToPort_DEBUG(pin) + 64; - #else - x = digitalPinToPort_DEBUG(pin) + 64; - #endif - SERIAL_CHAR(x); - - #if AVR_AT90USB1286_FAMILY - if (pin == 46) - x = '2'; - else if (pin == 47) - x = '3'; - else { - uint8_t temp = digitalPinToBitMask_DEBUG(pin); - for (x = '0'; x < '9' && temp != 1; x++) temp >>= 1; - } - #else + #if AVR_AT90USB1286_FAMILY + if (pin == 46) + x = '2'; + else if (pin == 47) + x = '3'; + else { uint8_t temp = digitalPinToBitMask_DEBUG(pin); for (x = '0'; x < '9' && temp != 1; x++) temp >>= 1; - #endif - SERIAL_CHAR(x); + } #else - SERIAL_ECHO_SP(10); + uint8_t temp = digitalPinToBitMask_DEBUG(pin); + for (x = '0'; x < '9' && temp != 1; x++) temp >>= 1; #endif - } - - #define PRINT_PORT(p) print_port(p) - -#endif + SERIAL_CHAR(x); + #else + SERIAL_ECHO_SP(10); + #endif +} #define PRINT_PIN(p) do{ sprintf_P(buffer, PSTR("%3d "), p); SERIAL_ECHO(buffer); }while(0) #define PRINT_PIN_ANALOG(p) do{ sprintf_P(buffer, PSTR(" (A%2d) "), DIGITAL_PIN_TO_ANALOG_PIN(pin)); SERIAL_ECHO(buffer); }while(0) diff --git a/Marlin/src/HAL/AVR/pinsDebug_Teensyduino.h b/Marlin/src/HAL/AVR/pinsDebug_Teensyduino.h index 582ae79ba7..c812d4fb11 100644 --- a/Marlin/src/HAL/AVR/pinsDebug_Teensyduino.h +++ b/Marlin/src/HAL/AVR/pinsDebug_Teensyduino.h @@ -22,11 +22,10 @@ #pragma once // -// some of the pin mapping functions of the Teensduino extension to the Arduino IDE -// do not function the same as the other Arduino extensions +// Some of the pin mapping functions of the Arduino IDE Teensduino extension +// function differently from other Arduino extensions. // - #define TEENSYDUINO_IDE //digitalPinToTimer(pin) function works like Arduino but Timers are not defined @@ -48,8 +47,6 @@ #define PE 5 #define PF 6 -#undef digitalPinToPort - const uint8_t PROGMEM digital_pin_to_port_PGM[] = { PD, // 0 - PD0 - INT0 - PWM PD, // 1 - PD1 - INT1 - PWM @@ -101,7 +98,7 @@ const uint8_t PROGMEM digital_pin_to_port_PGM[] = { PE, // 47 - PE3 (not defined in teensyduino) }; -#define digitalPinToPort(P) ( pgm_read_byte( digital_pin_to_port_PGM + (P) ) ) +#define digitalPinToPort(P) pgm_read_byte(digital_pin_to_port_PGM[P]) // digitalPinToBitMask(pin) is OK diff --git a/Marlin/src/HAL/AVR/pinsDebug_plus_70.h b/Marlin/src/HAL/AVR/pinsDebug_plus_70.h index d9aa44c3cb..fa479cfe8f 100644 --- a/Marlin/src/HAL/AVR/pinsDebug_plus_70.h +++ b/Marlin/src/HAL/AVR/pinsDebug_plus_70.h @@ -231,7 +231,6 @@ const uint8_t PROGMEM digital_pin_to_bit_mask_PGM_plus_70[] = { #define digitalPinToBitMask_plus_70(P) ( pgm_read_byte( digital_pin_to_bit_mask_PGM_plus_70 + (P) ) ) - const uint8_t PROGMEM digital_pin_to_timer_PGM_plus_70[] = { // TIMERS // ------------------------ diff --git a/Marlin/src/HAL/AVR/registers.cpp b/Marlin/src/HAL/AVR/registers.cpp new file mode 100644 index 0000000000..08a74c952a --- /dev/null +++ b/Marlin/src/HAL/AVR/registers.cpp @@ -0,0 +1,979 @@ +/** + * Marlin 3D Printer Firmware + * Copyright (c) 2023 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] + * + * Based on Sprinter and grbl. + * Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +#ifdef __AVR__ + +#include "../../inc/MarlinConfigPre.h" + +#if ENABLED(HAL_AVR_DIRTY_INIT) + +#include "registers.h" + +// Since the compiler could be creating multiple copies of function code-graphs for each header inline-inclusion, +// we want to off-load the function definitions that define static memory into this solitary compilation unit. +// This way the ROM is NOT bloated (who knows if the compiler is optimizing same-content constant objects into one?) + +ATmegaPinFunctions _ATmega_getPinFunctions(int pin) { + if (pin < 0) return {}; + + ATmegaPinInfo info = _ATmega_getPinInfo((unsigned int)pin); + + #ifdef __AVR_TRM01__ + if (info.port == eATmegaPort::PORT_A) { + if (info.pinidx == 7) { + static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::EXTMEM_AD7 }; + return { funcs, countof(funcs) }; + } + else if (info.pinidx == 6) { + static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::EXTMEM_AD6 }; + return { funcs, countof(funcs) }; + } + else if (info.pinidx == 5) { + static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::EXTMEM_AD5 }; + return { funcs, countof(funcs) }; + } + else if (info.pinidx == 4) { + static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::EXTMEM_AD4 }; + return { funcs, countof(funcs) }; + } + else if (info.pinidx == 3) { + static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::EXTMEM_AD3 }; + return { funcs, countof(funcs) }; + } + else if (info.pinidx == 2) { + static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::EXTMEM_AD2 }; + return { funcs, countof(funcs) }; + } + else if (info.pinidx == 1) { + static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::EXTMEM_AD1 }; + return { funcs, countof(funcs) }; + } + else if (info.pinidx == 0) { + static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::EXTMEM_AD0 }; + return { funcs, countof(funcs) }; + } + } + else if (info.port == eATmegaPort::PORT_B) { + if (info.pinidx == 7) { + static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::TOC0A, eATmegaPinFunc::TOC1C, eATmegaPinFunc::PCI7 }; + return { funcs, countof(funcs) }; + } + else if (info.pinidx == 6) { + static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::TOC1B, eATmegaPinFunc::PCI6 }; + return { funcs, countof(funcs) }; + } + else if (info.pinidx == 5) { + static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::TOC1A, eATmegaPinFunc::PCI5 }; + return { funcs, countof(funcs) }; + } + else if (info.pinidx == 4) { + static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::TOC2A, eATmegaPinFunc::PCI4 }; + return { funcs, countof(funcs) }; + } + else if (info.pinidx == 3) { + static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::SPI_MISO, eATmegaPinFunc::PCI3 }; + return { funcs, countof(funcs) }; + } + else if (info.pinidx == 2) { + static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::SPI_MOSI, eATmegaPinFunc::PCI2 }; + return { funcs, countof(funcs) }; + } + else if (info.pinidx == 1) { + static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::SPI_SCK, eATmegaPinFunc::PCI1 }; + return { funcs, countof(funcs) }; + } + else if (info.pinidx == 0) { + static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::SPI_CS, eATmegaPinFunc::PCI0 }; + return { funcs, countof(funcs) }; + } + } + else if (info.port == eATmegaPort::PORT_C) { + if (info.pinidx == 7) { + static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::EXTMEM_AD15 }; + return { funcs, countof(funcs) }; + } + else if (info.pinidx == 6) { + static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::EXTMEM_AD14 }; + return { funcs, countof(funcs) }; + } + else if (info.pinidx == 5) { + static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::EXTMEM_AD13 }; + return { funcs, countof(funcs) }; + } + else if (info.pinidx == 4) { + static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::EXTMEM_AD12 }; + return { funcs, countof(funcs) }; + } + else if (info.pinidx == 3) { + static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::EXTMEM_AD11 }; + return { funcs, countof(funcs) }; + } + else if (info.pinidx == 2) { + static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::EXTMEM_AD10 }; + return { funcs, countof(funcs) }; + } + else if (info.pinidx == 1) { + static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::EXTMEM_AD9 }; + return { funcs, countof(funcs) }; + } + else if (info.pinidx == 0) { + static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::EXTMEM_AD8 }; + return { funcs, countof(funcs) }; + } + } + else if (info.port == eATmegaPort::PORT_D) { + if (info.pinidx == 7) { + static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::TIMER0_CLKI }; + return { funcs, countof(funcs) }; + } + else if (info.pinidx == 6) { + static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::TIMER1_CLKI }; + return { funcs, countof(funcs) }; + } + else if (info.pinidx == 5) { + static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::USART1_CLK }; + return { funcs, countof(funcs) }; + } + else if (info.pinidx == 4) { + static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::TIMER1_ICP }; + return { funcs, countof(funcs) }; + } + else if (info.pinidx == 3) { + static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::EINT3, eATmegaPinFunc::USART1_TXD }; + return { funcs, countof(funcs) }; + } + else if (info.pinidx == 2) { + static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::EINT2, eATmegaPinFunc::USART1_RXD }; + return { funcs, countof(funcs) }; + } + else if (info.pinidx == 1) { + static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::EINT1, eATmegaPinFunc::TWI_SDA }; + return { funcs, countof(funcs) }; + } + else if (info.pinidx == 0) { + static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::EINT0, eATmegaPinFunc::TWI_CLK }; + return { funcs, countof(funcs) }; + } + } + else if (info.port == eATmegaPort::PORT_E) { + if (info.pinidx == 7) { + static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::EINT7, eATmegaPinFunc::TIMER3_ICP, eATmegaPinFunc::CLKO }; + return { funcs, countof(funcs) }; + } + else if (info.pinidx == 6) { + static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::EINT6, eATmegaPinFunc::TIMER3_CLKI }; + return { funcs, countof(funcs) }; + } + else if (info.pinidx == 5) { + static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::EINT5, eATmegaPinFunc::TOC3C }; + return { funcs, countof(funcs) }; + } + else if (info.pinidx == 4) { + static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::EINT4, eATmegaPinFunc::TOC3B }; + return { funcs, countof(funcs) }; + } + else if (info.pinidx == 3) { + static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::AIN1, eATmegaPinFunc::TOC3A }; + return { funcs, countof(funcs) }; + } + else if (info.pinidx == 2) { + static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::AIN0, eATmegaPinFunc::USART0_CLK }; + return { funcs, countof(funcs) }; + } + else if (info.pinidx == 1) { + static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::PDO, eATmegaPinFunc::USART0_TXD }; + return { funcs, countof(funcs) }; + } + else if (info.pinidx == 0) { + static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::PDI, eATmegaPinFunc::USART0_RXD, eATmegaPinFunc::PCI8 }; + return { funcs, countof(funcs) }; + } + } + else if (info.port == eATmegaPort::PORT_F) { + if (info.pinidx == 7) { + static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::ADC7 }; + return { funcs, countof(funcs) }; + } + else if (info.pinidx == 6) { + static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::ADC6 }; + return { funcs, countof(funcs) }; + } + else if (info.pinidx == 5) { + static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::ADC5 }; + return { funcs, countof(funcs) }; + } + else if (info.pinidx == 4) { + static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::ADC4 }; + return { funcs, countof(funcs) }; + } + else if (info.pinidx == 3) { + static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::ADC3 }; + return { funcs, countof(funcs) }; + } + else if (info.pinidx == 2) { + static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::ADC2 }; + return { funcs, countof(funcs) }; + } + else if (info.pinidx == 1) { + static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::ADC1 }; + return { funcs, countof(funcs) }; + } + else if (info.pinidx == 0) { + static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::ADC0 }; + return { funcs, countof(funcs) }; + } + } + else if (info.port == eATmegaPort::PORT_G) { + if (info.pinidx == 5) { + static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::TOC0B }; + return { funcs, countof(funcs) }; + } + else if (info.pinidx == 4) { + static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::TOSC1 }; + return { funcs, countof(funcs) }; + } + else if (info.pinidx == 3 ) { + static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::TOSC2 }; + return { funcs, countof(funcs) }; + } + else if (info.pinidx == 2) { + static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::EXTMEM_ALE }; + return { funcs, countof(funcs) }; + } + else if (info.pinidx == 1) { + static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::EXTMEM_RD }; + return { funcs, countof(funcs) }; + } + else if (info.pinidx == 0) { + static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::EXTMEM_WR }; + return { funcs, countof(funcs) }; + } + } + else if (info.port == eATmegaPort::PORT_H) { + if (info.pinidx == 7) { + static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::TIMER4_CLKI }; + return { funcs, countof(funcs) }; + } + else if (info.pinidx == 6) { + static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::TOC2B }; + return { funcs, countof(funcs) }; + } + else if (info.pinidx == 5) { + static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::TOC4C }; + return { funcs, countof(funcs) }; + } + else if (info.pinidx == 4) { + static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::TOC4B }; + return { funcs, countof(funcs) }; + } + else if (info.pinidx == 3) { + static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::TOC4A }; + return { funcs, countof(funcs) }; + } + else if (info.pinidx == 2) { + static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::USART2_CLK }; + return { funcs, countof(funcs) }; + } + else if (info.pinidx == 1) { + static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::USART2_TXD }; + return { funcs, countof(funcs) }; + } + else if (info.pinidx == 0) { + static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::USART2_RXD }; + return { funcs, countof(funcs) }; + } + } + else if (info.port == eATmegaPort::PORT_J) { + if (info.pinidx == 6) { + static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::PCI15 }; + return { funcs, countof(funcs) }; + } + else if (info.pinidx == 5) { + static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::PCI14 }; + return { funcs, countof(funcs) }; + } + else if (info.pinidx == 4) { + static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::PCI13 }; + return { funcs, countof(funcs) }; + } + else if (info.pinidx == 3) { + static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::PCI12 }; + return { funcs, countof(funcs) }; + } + else if (info.pinidx == 2) { + static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::USART3_CLK, eATmegaPinFunc::PCI11 }; + return { funcs, countof(funcs) }; + } + else if (info.pinidx == 1) { + static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::USART3_TXD, eATmegaPinFunc::PCI10 }; + return { funcs, countof(funcs) }; + } + else if (info.pinidx == 0) { + static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::USART3_RXD, eATmegaPinFunc::PCI9 }; + return { funcs, countof(funcs) }; + } + } + else if (info.port == eATmegaPort::PORT_K) { + if (info.pinidx == 7) { + static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::ADC15, eATmegaPinFunc::PCI23 }; + return { funcs, countof(funcs) }; + } + else if (info.pinidx == 6) { + static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::ADC14, eATmegaPinFunc::PCI22 }; + return { funcs, countof(funcs) }; + } + else if (info.pinidx == 5) { + static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::ADC13, eATmegaPinFunc::PCI21 }; + return { funcs, countof(funcs) }; + } + else if (info.pinidx == 4) { + static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::ADC12, eATmegaPinFunc::PCI20 }; + return { funcs, countof(funcs) }; + } + else if (info.pinidx == 3) { + static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::ADC11, eATmegaPinFunc::PCI19 }; + return { funcs, countof(funcs) }; + } + else if (info.pinidx == 2) { + static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::ADC10, eATmegaPinFunc::PCI18 }; + return { funcs, countof(funcs) }; + } + else if (info.pinidx == 1) { + static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::ADC9, eATmegaPinFunc::PCI17 }; + return { funcs, countof(funcs) }; + } + else if (info.pinidx == 0) { + static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::ADC8, eATmegaPinFunc::PCI16 }; + return { funcs, countof(funcs) }; + } + } + else if (info.port == eATmegaPort::PORT_L) { + if (info.pinidx == 5) { + static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::TOC5C }; + return { funcs, countof(funcs) }; + } + else if (info.pinidx == 4) { + static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::TOC5B }; + return { funcs, countof(funcs) }; + } + else if (info.pinidx == 3) { + static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::TOC5A }; + return { funcs, countof(funcs) }; + } + else if (info.pinidx == 2) { + static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::TIMER5_CLKI }; + return { funcs, countof(funcs) }; + } + else if (info.pinidx == 1) { + static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::TIMER5_ICP }; + return { funcs, countof(funcs) }; + } + else if (info.pinidx == 0) { + static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::TIMER4_ICP }; + return { funcs, countof(funcs) }; + } + } + #elif defined(__AVR_TRM02__) + if (info.port == eATmegaPort::PORT_A) { + if (info.pinidx == 7) { + static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::PCI7, eATmegaPinFunc::ADC7 }; + return { funcs, countof(funcs) }; + } + else if (info.pinidx == 6) { + static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::PCI6, eATmegaPinFunc::ADC6 }; + return { funcs, countof(funcs) }; + } + else if (info.pinidx == 5) { + static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::PCI5, eATmegaPinFunc::ADC5 }; + return { funcs, countof(funcs) }; + } + else if (info.pinidx == 4) { + static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::PCI4, eATmegaPinFunc::ADC4 }; + return { funcs, countof(funcs) }; + } + else if (info.pinidx == 3) { + static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::PCI3, eATmegaPinFunc::ADC3 }; + return { funcs, countof(funcs) }; + } + else if (info.pinidx == 2) { + static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::PCI2, eATmegaPinFunc::ADC2 }; + return { funcs, countof(funcs) }; + } + else if (info.pinidx == 1) { + static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::PCI1, eATmegaPinFunc::ADC1 }; + return { funcs, countof(funcs) }; + } + else if (info.pinidx == 0) { + static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::PCI0, eATmegaPinFunc::ADC0 }; + return { funcs, countof(funcs) }; + } + } + else if (info.port == eATmegaPort::PORT_B) { + if (info.pinidx == 7) { + static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::SPI_SCK, eATmegaPinFunc::TOC3B, eATmegaPinFunc::PCI15 }; + return { funcs, countof(funcs) }; + } + else if (info.pinidx == 6) { + static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::SPI_MISO, eATmegaPinFunc::TOC3A, eATmegaPinFunc::PCI14 }; + return { funcs, countof(funcs) }; + } + else if (info.pinidx == 5) { + static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::SPI_MOSI, eATmegaPinFunc::TIMER3_ICP, eATmegaPinFunc::PCI13 }; + return { funcs, countof(funcs) }; + } + else if (info.pinidx == 4) { + static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::SPI_CS, eATmegaPinFunc::TOC0B, eATmegaPinFunc::PCI12 }; + return { funcs, countof(funcs) }; + } + else if (info.pinidx == 3) { + static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::AIN1, eATmegaPinFunc::TOC0A, eATmegaPinFunc::PCI11 }; + return { funcs, countof(funcs) }; + } + else if (info.pinidx == 2) { + static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::AIN0, eATmegaPinFunc::EINT2, eATmegaPinFunc::PCI10 }; + return { funcs, countof(funcs) }; + } + else if (info.pinidx == 1) { + static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::TIMER1_ECI, eATmegaPinFunc::CLKO, eATmegaPinFunc::PCI9 }; + return { funcs, countof(funcs) }; + } + else if (info.pinidx == 0) { + static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::TIMER0_ECI, eATmegaPinFunc::USART0_CLK, eATmegaPinFunc::PCI8 }; + return { funcs, countof(funcs) }; + } + } + else if (info.port == eATmegaPort::PORT_C) { + if (info.pinidx == 7) { + static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::TOSC2, eATmegaPinFunc::PCI23 }; + return { funcs, countof(funcs) }; + } + else if (info.pinidx == 6) { + static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::TOSC1, eATmegaPinFunc::PCI22 }; + return { funcs, countof(funcs) }; + } + else if (info.pinidx == 5) { + static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::PCI21 }; + return { funcs, countof(funcs) }; + } + else if (info.pinidx == 4) { + static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::PCI20 }; + return { funcs, countof(funcs) }; + } + else if (info.pinidx == 3) { + static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::PCI19 }; + return { funcs, countof(funcs) }; + } + else if (info.pinidx == 2) { + static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::PCI18 }; + return { funcs, countof(funcs) }; + } + else if (info.pinidx == 1) { + static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::PCI17, eATmegaPinFunc::TWI_SDA }; + return { funcs, countof(funcs) }; + } + else if (info.pinidx == 0) { + static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::TWI_CLK, eATmegaPinFunc::PCI16 }; + return { funcs, countof(funcs) }; + } + } + else if (info.port == eATmegaPort::PORT_D) { + if (info.pinidx == 7) { + static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::TOC2A, eATmegaPinFunc::PCI31 }; + return { funcs, countof(funcs) }; + } + else if (info.pinidx == 6) { + static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::TIMER1_ICP, eATmegaPinFunc::TOC2B, eATmegaPinFunc::PCI30 }; + return { funcs, countof(funcs) }; + } + else if (info.pinidx == 5) { + static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::TOC1A, eATmegaPinFunc::PCI29 }; + return { funcs, countof(funcs) }; + } + else if (info.pinidx == 4) { + static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::TOC1B, eATmegaPinFunc::USART1_CLK, eATmegaPinFunc::PCI28 }; + return { funcs, countof(funcs) }; + } + else if (info.pinidx == 3) { + static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::EINT1, eATmegaPinFunc::USART1_TXD, eATmegaPinFunc::PCI27 }; + return { funcs, countof(funcs) }; + } + else if (info.pinidx == 2) { + static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::EINT0, eATmegaPinFunc::USART1_RXD, eATmegaPinFunc::PCI26 }; + return { funcs, countof(funcs) }; + } + else if (info.pinidx == 1) { + static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::USART0_TXD, eATmegaPinFunc::PCI25 }; + return { funcs, countof(funcs) }; + } + else if (info.pinidx == 0) { + static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::USART0_TXD, eATmegaPinFunc::PCI24, eATmegaPinFunc::TIMER3_ECI }; + return { funcs, countof(funcs) }; + } + } + #elif defined(__AVR_TRM03__) + if (info.port == eATmegaPort::PORT_B) { + if (info.pinidx == 7) { + static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::XTAL2, eATmegaPinFunc::TOSC2, eATmegaPinFunc::PCI7 }; + return { funcs, countof(funcs) }; + } + else if (info.pinidx == 6) { + static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::XTAL1, eATmegaPinFunc::TOSC1, eATmegaPinFunc::PCI6 }; + return { funcs, countof(funcs) }; + } + else if (info.pinidx == 5) { + static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::SPI_SCK, eATmegaPinFunc::PCI5 }; + return { funcs, countof(funcs) }; + } + else if (info.pinidx == 4) { + static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::SPI_MISO, eATmegaPinFunc::PCI4 }; + return { funcs, countof(funcs) }; + } + else if (info.pinidx == 3) { + static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::SPI_MOSI, eATmegaPinFunc::TOC2A, eATmegaPinFunc::PCI3 }; + return { funcs, countof(funcs) }; + } + else if (info.pinidx == 2) { + static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::SPI_CS, eATmegaPinFunc::TOC1B, eATmegaPinFunc::PCI2 }; + return { funcs, countof(funcs) }; + } + else if (info.pinidx == 1) { + static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::TOC1A, eATmegaPinFunc::PCI1 }; + return { funcs, countof(funcs) }; + } + else if (info.pinidx == 0) { + static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::TIMER1_ICP, eATmegaPinFunc::CLKO, eATmegaPinFunc::PCI0 }; + return { funcs, countof(funcs) }; + } + } + else if (info.port == eATmegaPort::PORT_C) { + if (info.pinidx == 6) { + static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::PCI14 }; + return { funcs, countof(funcs) }; + } + else if (info.pinidx == 5) { + static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::ADC5, eATmegaPinFunc::TWI_CLK, eATmegaPinFunc::PCI13 }; + return { funcs, countof(funcs) }; + } + else if (info.pinidx == 4) { + static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::ADC4, eATmegaPinFunc::TWI_SDA, eATmegaPinFunc::PCI12 }; + return { funcs, countof(funcs) }; + } + else if (info.pinidx == 3) { + static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::ADC3, eATmegaPinFunc::PCI11 }; + return { funcs, countof(funcs) }; + } + else if (info.pinidx == 2) { + static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::ADC2, eATmegaPinFunc::PCI10 }; + return { funcs, countof(funcs) }; + } + else if (info.pinidx == 1) { + static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::ADC1, eATmegaPinFunc::PCI9 }; + return { funcs, countof(funcs) }; + } + else if (info.pinidx == 0) { + static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::ADC0, eATmegaPinFunc::PCI8 }; + return { funcs, countof(funcs) }; + } + } + else if (info.port == eATmegaPort::PORT_D) { + if (info.pinidx == 7) { + static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::AIN1, eATmegaPinFunc::PCI23 }; + return { funcs, countof(funcs) }; + } + else if (info.pinidx == 6) { + static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::AIN0, eATmegaPinFunc::TOC0A, eATmegaPinFunc::PCI22 }; + return { funcs, countof(funcs) }; + } + else if (info.pinidx == 5) { + static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::TIMER1_ECI, eATmegaPinFunc::TOC0B, eATmegaPinFunc::PCI21 }; + return { funcs, countof(funcs) }; + } + else if (info.pinidx == 4) { + static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::USART_CLK, eATmegaPinFunc::TIMER0_ECI, eATmegaPinFunc::PCI20 }; + return { funcs, countof(funcs) }; + } + else if (info.pinidx == 3) { + static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::EINT1, eATmegaPinFunc::TOC2B, eATmegaPinFunc::PCI19 }; + return { funcs, countof(funcs) }; + } + else if (info.pinidx == 2) { + static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::EINT0, eATmegaPinFunc::PCI18 }; + return { funcs, countof(funcs) }; + } + else if (info.pinidx == 1) { + static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::USART_TXD, eATmegaPinFunc::PCI17 }; + return { funcs, countof(funcs) }; + } + else if (info.pinidx == 0) { + static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::USART_RXD, eATmegaPinFunc::PCI16 }; + return { funcs, countof(funcs) }; + } + } + #elif defined(__AVR_TRM04__) + if (info.port == eATmegaPort::PORT_A) { + if (info.pinidx == 7) { + static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::EXTMEM_AD7 }; + return { funcs, countof(funcs) }; + } + else if (info.pinidx == 6) { + static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::EXTMEM_AD6 }; + return { funcs, countof(funcs) }; + } + else if (info.pinidx == 5) { + static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::EXTMEM_AD5 }; + return { funcs, countof(funcs) }; + } + else if (info.pinidx == 4) { + static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::EXTMEM_AD4 }; + return { funcs, countof(funcs) }; + } + else if (info.pinidx == 3) { + static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::EXTMEM_AD3 }; + return { funcs, countof(funcs) }; + } + else if (info.pinidx == 2) { + static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::EXTMEM_AD2 }; + return { funcs, countof(funcs) }; + } + else if (info.pinidx == 1) { + static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::EXTMEM_AD1 }; + return { funcs, countof(funcs) }; + } + else if (info.pinidx == 0) { + static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::EXTMEM_AD0 }; + return { funcs, countof(funcs) }; + } + } + else if (info.port == eATmegaPort::PORT_B) { + if (info.pinidx == 7) { + static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::TOC0A, eATmegaPinFunc::TOC1C, eATmegaPinFunc::PCI7 }; + return { funcs, countof(funcs) }; + } + else if (info.pinidx == 6) { + static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::TOC1B, eATmegaPinFunc::PCI6 }; + return { funcs, countof(funcs) }; + } + else if (info.pinidx == 5) { + static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::TOC1A, eATmegaPinFunc::PCI5 }; + return { funcs, countof(funcs) }; + } + else if (info.pinidx == 4) { + static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::TOC2A, eATmegaPinFunc::PCI4 }; + return { funcs, countof(funcs) }; + } + else if (info.pinidx == 3) { + static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::PDO, eATmegaPinFunc::SPI_MISO, eATmegaPinFunc::PCI3 }; + return { funcs, countof(funcs) }; + } + else if (info.pinidx == 2) { + static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::PDI, eATmegaPinFunc::SPI_MOSI, eATmegaPinFunc::PCI2 }; + return { funcs, countof(funcs) }; + } + else if (info.pinidx == 1) { + static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::SPI_SCK, eATmegaPinFunc::PCI1 }; + return { funcs, countof(funcs) }; + } + else if (info.pinidx == 0) { + static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::SPI_CS, eATmegaPinFunc::PCI0 }; + return { funcs, countof(funcs) }; + } + } + else if (info.port == eATmegaPort::PORT_C) { + if (info.pinidx == 7) { + static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::EXTMEM_AD15, eATmegaPinFunc::TIMER3_ICP, eATmegaPinFunc::CLKO }; + return { funcs, countof(funcs) }; + } + else if (info.pinidx == 6) { + static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::EXTMEM_AD14, eATmegaPinFunc::TOC3A }; + return { funcs, countof(funcs) }; + } + else if (info.pinidx == 5) { + static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::EXTMEM_AD13, eATmegaPinFunc::TOC3B }; + return { funcs, countof(funcs) }; + } + else if (info.pinidx == 4) { + static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::EXTMEM_AD12, eATmegaPinFunc::TOC3C }; + return { funcs, countof(funcs) }; + } + else if (info.pinidx == 3) { + static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::EXTMEM_AD11, eATmegaPinFunc::TIMER3_CLKI }; + return { funcs, countof(funcs) }; + } + else if (info.pinidx == 2) { + static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::EXTMEM_AD10 }; + return { funcs, countof(funcs) }; + } + else if (info.pinidx == 1) { + static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::EXTMEM_AD9 }; + return { funcs, countof(funcs) }; + } + else if (info.pinidx == 0) { + static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::EXTMEM_AD8 }; + return { funcs, countof(funcs) }; + } + } + else if (info.port == eATmegaPort::PORT_D) { + if (info.pinidx == 7) { + static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::TIMER0_CLKI }; + return { funcs, countof(funcs) }; + } + else if (info.pinidx == 6) { + static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::TIMER1_CLKI }; + return { funcs, countof(funcs) }; + } + else if (info.pinidx == 5) { + static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::USART1_CLK }; + return { funcs, countof(funcs) }; + } + else if (info.pinidx == 4) { + static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::TIMER1_ICP }; + return { funcs, countof(funcs) }; + } + else if (info.pinidx == 3) { + static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::EINT3, eATmegaPinFunc::USART1_TXD }; + return { funcs, countof(funcs) }; + } + else if (info.pinidx == 2) { + static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::EINT2, eATmegaPinFunc::USART1_RXD }; + return { funcs, countof(funcs) }; + } + else if (info.pinidx == 1) { + static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::EINT1, eATmegaPinFunc::TWI_SDA, eATmegaPinFunc::TOC2B }; + return { funcs, countof(funcs) }; + } + else if (info.pinidx == 0) { + static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::EINT0, eATmegaPinFunc::TWI_CLK, eATmegaPinFunc::TOC0B }; + return { funcs, countof(funcs) }; + } + } + else if (info.port == eATmegaPort::PORT_E) { + if (info.pinidx == 7) { + static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::EINT7, eATmegaPinFunc::AIN1, eATmegaPinFunc::UVCON }; + return { funcs, countof(funcs) }; + } + else if (info.pinidx == 6) { + static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::EINT6, eATmegaPinFunc::AIN0 }; + return { funcs, countof(funcs) }; + } + else if (info.pinidx == 5) { + static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::EINT5, eATmegaPinFunc::TOSC2 }; + return { funcs, countof(funcs) }; + } + else if (info.pinidx == 4) { + static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::EINT4, eATmegaPinFunc::TOSC2 }; + return { funcs, countof(funcs) }; + } + else if (info.pinidx == 3) { + static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::UID }; + return { funcs, countof(funcs) }; + } + else if (info.pinidx == 2) { + static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::EXTMEM_ALE }; + return { funcs, countof(funcs) }; + } + else if (info.pinidx == 1) { + static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::EXTMEM_RD }; + return { funcs, countof(funcs) }; + } + else if (info.pinidx == 0) { + static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::EXTMEM_WR }; + return { funcs, countof(funcs) }; + } + } + else if (info.port == eATmegaPort::PORT_F) { + if (info.pinidx == 7) { + static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::ADC7 }; + return { funcs, countof(funcs) }; + } + else if (info.pinidx == 6) { + static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::ADC6 }; + return { funcs, countof(funcs) }; + } + else if (info.pinidx == 5) { + static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::ADC5 }; + return { funcs, countof(funcs) }; + } + else if (info.pinidx == 4) { + static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::ADC4 }; + return { funcs, countof(funcs) }; + } + else if (info.pinidx == 3) { + static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::ADC3 }; + return { funcs, countof(funcs) }; + } + else if (info.pinidx == 2) { + static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::ADC2 }; + return { funcs, countof(funcs) }; + } + else if (info.pinidx == 1) { + static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::ADC1 }; + return { funcs, countof(funcs) }; + } + else if (info.pinidx == 0) { + static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::ADC0 }; + return { funcs, countof(funcs) }; + } + } + #elif defined(__AVR_TRM05__) + if (info.port == eATmegaPort::PORT_A) { + if (info.pinidx == 7) { + static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::ADC7, eATmegaPinFunc::PCI7 }; + return { funcs, countof(funcs) }; + } + else if (info.pinidx == 6) { + static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::ADC6, eATmegaPinFunc::PCI6 }; + return { funcs, countof(funcs) }; + } + else if (info.pinidx == 5) { + static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::ADC5, eATmegaPinFunc::PCI5 }; + return { funcs, countof(funcs) }; + } + else if (info.pinidx == 4) { + static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::ADC4, eATmegaPinFunc::PCI4 }; + return { funcs, countof(funcs) }; + } + else if (info.pinidx == 3) { + static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::ADC3, eATmegaPinFunc::PCI3 }; + return { funcs, countof(funcs) }; + } + else if (info.pinidx == 2) { + static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::ADC2, eATmegaPinFunc::PCI2 }; + return { funcs, countof(funcs) }; + } + else if (info.pinidx == 1) { + static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::ADC1, eATmegaPinFunc::PCI1 }; + return { funcs, countof(funcs) }; + } + else if (info.pinidx == 0) { + static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::ADC0, eATmegaPinFunc::PCI0 }; + return { funcs, countof(funcs) }; + } + } + else if (info.port == eATmegaPort::PORT_B) { + if (info.pinidx == 7) { + static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::SPI_SCK, eATmegaPinFunc::PCI15 }; + return { funcs, countof(funcs) }; + } + else if (info.pinidx == 6) { + static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::SPI_MISO, eATmegaPinFunc::PCI14 }; + return { funcs, countof(funcs) }; + } + else if (info.pinidx == 5) { + static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::SPI_MOSI, eATmegaPinFunc::PCI13 }; + return { funcs, countof(funcs) }; + } + else if (info.pinidx == 4) { + static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::SPI_CS, eATmegaPinFunc::TOC0B, eATmegaPinFunc::PCI12 }; + return { funcs, countof(funcs) }; + } + else if (info.pinidx == 3) { + static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::AIN1, eATmegaPinFunc::TOC0A, eATmegaPinFunc::PCI11 }; + return { funcs, countof(funcs) }; + } + else if (info.pinidx == 2) { + static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::AIN0, eATmegaPinFunc::EINT2, eATmegaPinFunc::PCI10 }; + return { funcs, countof(funcs) }; + } + else if (info.pinidx == 1) { + static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::TIMER1_ECI, eATmegaPinFunc::CLKO, eATmegaPinFunc::PCI9 }; + return { funcs, countof(funcs) }; + } + else if (info.pinidx == 0) { + static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::TIMER0_ECI, eATmegaPinFunc::USART0_CLK, eATmegaPinFunc::PCI8 }; + return { funcs, countof(funcs) }; + } + } + else if (info.port == eATmegaPort::PORT_C) { + if (info.pinidx == 7) { + static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::TOSC2, eATmegaPinFunc::PCI23 }; + return { funcs, countof(funcs) }; + } + else if (info.pinidx == 6) { + static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::TOSC1, eATmegaPinFunc::PCI22 }; + return { funcs, countof(funcs) }; + } + else if (info.pinidx == 5) { + static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::PCI21 }; + return { funcs, countof(funcs) }; + } + else if (info.pinidx == 4) { + static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::PCI20 }; + return { funcs, countof(funcs) }; + } + else if (info.pinidx == 3) { + static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::PCI19 }; + return { funcs, countof(funcs) }; + } + else if (info.pinidx == 2) { + static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::PCI18 }; + return { funcs, countof(funcs) }; + } + else if (info.pinidx == 1) { + static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::TWI_SDA, eATmegaPinFunc::PCI17 }; + return { funcs, countof(funcs) }; + } + else if (info.pinidx == 0) { + static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::TWI_CLK, eATmegaPinFunc::PCI16 }; + return { funcs, countof(funcs) }; + } + } + else if (info.port == eATmegaPort::PORT_D) { + if (info.pinidx == 7) { + static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::TOC2A, eATmegaPinFunc::PCI31 }; + return { funcs, countof(funcs) }; + } + if (info.pinidx == 6) { + static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::TIMER1_ICP, eATmegaPinFunc::TOC2B, eATmegaPinFunc::PCI30 }; + return { funcs, countof(funcs) }; + } + if (info.pinidx == 5) { + static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::TOC1A, eATmegaPinFunc::PCI29 }; + return { funcs, countof(funcs) }; + } + if (info.pinidx == 4) { + static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::TOC1B, eATmegaPinFunc::USART1_CLK, eATmegaPinFunc::PCI28 }; + return { funcs, countof(funcs) }; + } + if (info.pinidx == 3) { + static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::EINT1, eATmegaPinFunc::USART1_TXD, eATmegaPinFunc::PCI27 }; + return { funcs, countof(funcs) }; + } + if (info.pinidx == 2) { + static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::EINT0, eATmegaPinFunc::USART1_RXD, eATmegaPinFunc::PCI26 }; + return { funcs, countof(funcs) }; + } + if (info.pinidx == 1) { + static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::USART0_TXD, eATmegaPinFunc::PCI25 }; + return { funcs, countof(funcs) }; + } + if (info.pinidx == 0) { + static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::USART0_RXD, eATmegaPinFunc::PCI24 }; + return { funcs, countof(funcs) }; + } + } + #endif + + return ATmegaPinFunctions(); // default and empty. +} + +#endif // HAL_AVR_DIRTY_INIT +#endif // __AVR__ diff --git a/Marlin/src/HAL/AVR/registers.h b/Marlin/src/HAL/AVR/registers.h new file mode 100644 index 0000000000..64c0955c3e --- /dev/null +++ b/Marlin/src/HAL/AVR/registers.h @@ -0,0 +1,5080 @@ +/** + * Marlin 3D Printer Firmware + * Copyright (c) 2023 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] + * + * Based on Sprinter and grbl. + * Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ +#pragma once + +#include + +// This volatile-nonsense has to be done due to the C++ platform language specialization that specifies, for it's own compiler ideology, +// that memory writes and reads can be optimized across easily-reachable code spaces. This is in contrast to MSVC which specifies that +// memory writes and reads are holy. + +// OVERVIEW OF PREPROCESSOR DEFINITIONS: +// __AVR_ATmega2560__ +// __AVR_ATmega1284P__ +// __AVR_ATmega1280__ +// __AVR_ATmega644__ +// __AVR_ATmega644P__ +// __AVR_ATmega2561__ + +// Contributed by Martin Turski, company owner of EirDev, on the 29th of November, 2022 +// Contact E-Mail: turningtides@outlook.de +// Created specifically for the Marlin FW for AVR backwards-compatibility. +// Please expand this file with details of every supported AVR implementation. +// 1) download the latest technical reference manual +// 2) add the new technical reference manual below using a set of __AVR_*__ preprocessor definitions and a new __AVR_TRM*__ incrementing define +// 3) check which of the existing AVR registers exist on the new implementation and enable them +// 4) add any new register definitions +// 5) add the register memory layout below the definitions +// 6) extend the _ATmega_resetperipherals functions +// 7) extend the _ATmega_savePinAlternate function +// 8) copy the extension idea to _ATmega_restorePinAlternate and finish implementing it +// You need to adjust the eATmegaPort enumeration aswell. + +#if defined(__AVR_TRM01__) || defined(__AVR_TRM02__) || defined(__AVR_TRM03__) || defined(__AVR_TRM04__) || defined(__AVR_TRM05__) + #error "Fatal error: __AVR_TRMn__ already defined! (n: 01|02|03|04|05)" +#endif + +#if defined(__AVR_ATmega2560__) || defined(__AVR_ATmega2561__) || defined(__AVR_ATmega1280__) || defined(__AVR_ATmega1281__) || defined(__AVR_ATmega640__) + // ATmega2560 technical reference manual date: 28th of November, 2022 + // ATmega640-1280-1281-2560-2561-Datasheet-DS40002211A.pdf + #define __AVR_TRM01__ +#elif defined(__AVR_ATmega164A__) || defined(__AVR_ATmega164PA__) || defined(__AVR_ATmega324A__) || defined(__AVR_ATmega324PA__) || defined(__AVR_ATmega644A__) || defined(__AVR_ATmega644PA__) || defined(__AVR_ATmega1284__) || defined(__AVR_ATmega1284P__) + // ATmega1284 technical reference manual date: 29th of November, 2022 + // ATmega164A_PA-324A_PA-644A_PA-1284_P_Data-Sheet-40002070B.pdf + #define __AVR_TRM02__ +#elif defined(__AVR_ATmega48A__) || defined(__AVR_ATmega48PA__) || defined(__AVR_ATmega88A__) || defined(__AVR_ATmega88PA__) || defined(__AVR_ATmega168A__) || defined(__AVR_ATmega168PA__) || defined(__AVR_ATmega328__) || defined(__AVR_ATmega328P__) + // ATmega328 technical reference manual date: 29th of November, 2022 + // ATmega48A-PA-88A-PA-168A-PA-328-P-DS-DS40002061B.pdf + #define __AVR_TRM03__ +#elif defined(__AVR_AT90USB1287__) || defined(__AVR_AT90USB1286__) || defined(__AVR_AT90USB1286P__) || defined(__AVR_AT90USB646__) || defined(__AVR_AT90USB646P__) || defined(__AVR_AT90USB647__) + // AT90USB1287 technical reference manual ID: 7593D–AVR–07/06 + // Preliminary. + #define __AVR_TRM04__ +#elif defined(__AVR_ATmega164P__) || defined(__AVR_ATmega164V__) || defined(__AVR_ATmega324P__) || defined(__AVR_ATmega324V__) || defined(__AVR_ATmega644P__) || defined(__AVR_ATmega644V__) + // ATmega644P technical reference manual date: 14th of February, 2023 + // ATmega164P-324P-644P-Data-Sheet-40002071A.pdf + #define __AVR_TRM05__ +#endif + +/** + * HELPER FUNCTIONS + */ +namespace AVRHelpers { + + template + struct no_volatile { + typedef T type; + }; + + template + struct no_volatile : public no_volatile {}; + + template + struct voltype { + typedef T type; + }; + template + struct voltype { + typedef uint8_t type; + }; + template + struct voltype { + typedef uint16_t type; + }; + template + struct voltype { + typedef uint32_t type; + }; + + template + inline void dwrite(volatile T& v, const T& V) noexcept { + (volatile typename voltype ::type&)v = (const typename voltype ::type&)V; + } + +} // namespace AVRHelpers + +// As old as the ATmega series of CPU is, the worse the actual libraries making +// use of the MCU likely are. + +// These registers as references do not take program space since they are purely references. + +// It would be great if the old AVR definitions could be wasted in favor of these +// and code be rewritten to use the following more robust definitions. + +struct _bit_reg_t { + uint8_t val; + + bool getValue(uint8_t idx) const volatile { + return ( val & (1 << idx) ); + } + void setValue(uint8_t idx, bool value) volatile { + if (value) + val |= (1 << idx); + else + val &= ~(1 << idx); + } +}; + +#if defined(__AVR_TRM01__) || defined(__AVR_TRM02__) || defined(__AVR_TRM03__) || defined(__AVR_TRM04__) || defined(__AVR_TRM05__) + + typedef _bit_reg_t PIN_reg_t; + typedef _bit_reg_t DDR_reg_t; + typedef _bit_reg_t PORT_reg_t; + + struct PORT_dev_t { + PIN_reg_t _PIN; + DDR_reg_t _DDR; + PORT_reg_t _PORT; + + inline void operator = ( const PORT_dev_t& r ) volatile { + using namespace AVRHelpers; + dwrite(this->_PIN, r._PIN); + dwrite(this->_DDR, r._DDR); + dwrite(this->_PORT, r._PORT); + } + }; + static_assert(sizeof(PORT_dev_t) == 3, "invalid size of ATmega2560 GPIO_dev_t"); + +#endif // __AVR_TRM01__ || __AVR_TRM02__ || __AVR_TRM03__ || __AVR_TRM04__ || __AVR_TRM05__ + +#ifdef __AVR_TRM01__ + + struct _bitG_reg_t { + uint8_t val : 6; + uint8_t reserved1 : 2; + + bool getValue(uint8_t idx) const volatile { + return val & (1 << idx); + } + void setValue(uint8_t idx, bool value) volatile { + if (value) + val |= (1 << idx); + else + val &= ~(1 << idx); + } + }; + typedef _bitG_reg_t PING_reg_t; + typedef _bitG_reg_t DDRG_reg_t; + typedef _bitG_reg_t PORTG_reg_t; + + struct PORTG_dev_t { + PING_reg_t _PIN; + DDRG_reg_t _DDR; + PORTG_reg_t _PORT; + + inline void operator = ( const PORTG_dev_t& r ) volatile { + using namespace AVRHelpers; + dwrite(this->_PIN, r._PIN); + dwrite(this->_DDR, r._DDR); + dwrite(this->_PORT, r._PORT); + } + }; + +#endif + +#ifdef __AVR_TRM03__ + + struct _bitC_reg_t { + uint8_t val : 7; + uint8_t reserved1 : 1; + + bool getValue(uint8_t idx) const volatile { + return ( val & (1 << idx) ); + } + void setValue(uint8_t idx, bool value) volatile { + if (value) + val |= (1 << idx); + else + val &= ~(1 << idx); + } + }; + typedef _bitC_reg_t PINC_reg_t; + typedef _bitC_reg_t DDRC_reg_t; + typedef _bitC_reg_t PORTC_reg_t; + + struct PORTC_dev_t { + PINC_reg_t _PIN; + DDRC_reg_t _DDR; + PORTC_reg_t _PORT; + + inline void operator = ( const PORTC_dev_t& r ) volatile { + this->_PIN = r._PIN; + this->_DDR = r._DDR; + this->_PORT = r._PORT; + } + }; + +#endif + +#if defined(__AVR_TRM01__) || defined(__AVR_TRM02__) || defined(__AVR_TRM03__) || defined(__AVR_TRM04__) || defined(__AVR_TRM05__) + + struct TIFR0_reg_t { + uint8_t _TOV0 : 1; + uint8_t _OCF0A : 1; + uint8_t _OCF0B : 1; + uint8_t reserved1 : 5; + }; + static_assert(sizeof(TIFR0_reg_t) == 1, "invalid size of ATmega2560 TIFR0_reg_t"); + + struct TIFR1_reg_t { + #if defined(__AVR_TRM01__) || defined(__AVR_TRM04__) + uint8_t _TOV1 : 1; + uint8_t _OCF1A : 1; + uint8_t _OCF1B : 1; + uint8_t _OCF1C : 1; + uint8_t reserved1 : 1; + uint8_t _ICF1 : 1; + uint8_t reserved2 : 2; + #elif defined(__AVR_TRM02__) || defined(__AVR_TRM03__) || defined(__AVR_TRM05__) + uint8_t _TOV1 : 1; + uint8_t _OCF1A : 1; + uint8_t _OCF1B : 1; + uint8_t reserved1 : 2; + uint8_t _ICF1 : 1; + uint8_t reserved2 : 2; + #endif + }; + static_assert(sizeof(TIFR1_reg_t) == 1, "invalid size of ATmega2560 TIFR1_reg_t"); + + struct TIFR2_reg_t { + uint8_t _TOV2 : 1; + uint8_t _OCF2A : 1; + uint8_t _OCF2B : 1; + uint8_t reserved1 : 5; + }; + static_assert(sizeof(TIFR2_reg_t) == 1, "invalid size of ATmega2560 TIFR2_reg_t"); + +#endif // __AVR_TRM01__ || __AVR_TRM02__ || __AVR_TRM03__ || __AVR_TRM04__ || __AVR_TRM05__ + +#if defined(__AVR_TRM01__) || defined(__AVR_TRM02__) || defined(__AVR_TRM04__) + + struct TIFR3_reg_t { + #if defined(__AVR_TRM01__) || defined(__AVR_TRM04__) + uint8_t _TOV3 : 1; + uint8_t _OCF3A : 1; + uint8_t _OCF3B : 1; + uint8_t _OCF3C : 1; + uint8_t reserved1 : 1; + uint8_t _ICF3 : 1; + uint8_t reserved2 : 2; + #elif defined(__AVR_TRM02__) + uint8_t _TOV3 : 1; + uint8_t _OCF3A : 1; + uint8_t _OCF3B : 1; + uint8_t reserved1 : 2; + uint8_t _ICF3 : 1; + uint8_t reserved2 : 2; + #endif + }; + static_assert(sizeof(TIFR3_reg_t) == 1, "invalid size of ATmega2560 TIFR3_reg_t"); + +#endif // __AVR_TRM01__ || __AVR_TRM02__ || __AVR_TRM04__ + +#ifdef __AVR_TRM01__ + + struct TIFR4_reg_t { + uint8_t _TOV4 : 1; + uint8_t _OCF4A : 1; + uint8_t _OCF4B : 1; + uint8_t _OCF4C : 1; + uint8_t reserved1 : 1; + uint8_t _ICF4 : 1; + uint8_t reserved2 : 2; + }; + static_assert(sizeof(TIFR4_reg_t) == 1, "invalid size of ATmega2560 TIFR4_reg_t"); + + struct TIFR5_reg_t { + uint8_t _TOV5 : 1; + uint8_t _OCF5A : 1; + uint8_t _OCF5B : 1; + uint8_t _OCF5C : 1; + uint8_t reserved1 : 1; + uint8_t _ICF5 : 1; + uint8_t reserved2 : 2; + }; + static_assert(sizeof(TIFR5_reg_t) == 1, "invalid size of ATmega2560 TIFR5_reg_t"); + +#endif // __AVR_TRM01__ + +#if defined(__AVR_TRM01__) || defined(__AVR_TRM02__) || defined(__AVR_TRM03__) || defined(__AVR_TRM04__) || defined(__AVR_TRM05__) + + struct PCIFR_reg_t { + #if defined(__AVR_TRM01__) || defined(__AVR_TRM03__) + uint8_t _PCIF0 : 1; + uint8_t _PCIF1 : 1; + uint8_t _PCIF2 : 1; + uint8_t reserved1 : 5; + #elif defined(__AVR_TRM02__) || defined(__AVR_TRM05__) + uint8_t _PCIF0 : 1; + uint8_t _PCIF1 : 1; + uint8_t _PCIF2 : 1; + uint8_t _PCIF3 : 1; + uint8_t reserved1 : 4; + #elif defined(__AVR_TRM04__) + uint8_t _PCIF0 : 1; + uint8_t reserved1 : 7; + #endif + }; + static_assert(sizeof(PCIFR_reg_t) == 1, "invalid size of ATmega2560 PCIFR_reg_t"); + + struct EIFR_reg_t { + #if defined(__AVR_TRM01__) || defined(__AVR_TRM04__) + uint8_t _INTF0 : 1; + uint8_t _INTF1 : 1; + uint8_t _INTF2 : 1; + uint8_t _INTF3 : 1; + uint8_t _INTF4 : 1; + uint8_t _INTF5 : 1; + uint8_t _INTF6 : 1; + uint8_t _INTF7 : 1; + #elif defined(__AVR_TRM02__) || defined(__AVR_TRM05__) + uint8_t _INTF0 : 1; + uint8_t _INTF1 : 1; + uint8_t _INTF2 : 1; + uint8_t reserved1 : 5; + #elif defined(__AVR_TRM03__) + uint8_t _INTF0 : 1; + uint8_t _INTF1 : 1; + uint8_t reserved1 : 6; + #endif + }; + static_assert(sizeof(EIFR_reg_t) == 1, "invalid size of ATmega2560 EIFR_reg_t"); + + struct EIMSK_reg_t { + #if defined(__AVR_TRM01__) || defined(__AVR_TRM04__) + uint8_t _INT0 : 1; + uint8_t _INT1 : 1; + uint8_t _INT2 : 1; + uint8_t _INT3 : 1; + uint8_t _INT4 : 1; + uint8_t _INT5 : 1; + uint8_t _INT6 : 1; + uint8_t _INT7 : 1; + #elif defined(__AVR_TRM02__) || defined(__AVR_TRM05__) + uint8_t _INT0 : 1; + uint8_t _INT1 : 1; + uint8_t _INT2 : 1; + uint8_t reserved1 : 5; + #elif defined(__AVR_TRM03__) + uint8_t _INT0 : 1; + uint8_t _INT1 : 1; + uint8_t reserved1 : 6; + #endif + }; + static_assert(sizeof(EIMSK_reg_t) == 1, "invalid size of ATmega2560 EIMSK_reg_t"); + + struct EECR_reg_t { + uint8_t _EERE : 1; + uint8_t _EEPE : 1; + uint8_t _EEMPE : 1; + uint8_t _EERIE : 1; + uint8_t _EEPM0 : 1; + uint8_t _EEPM1 : 1; + uint8_t reserved1 : 2; + }; + static_assert(sizeof(EECR_reg_t) == 1, "invalid size of ATmega2560 EECR_reg_t"); + + struct EEAR_reg_t { + #if defined(__AVR_TRM01__) || defined(__AVR_TRM02__) || defined(__AVR_TRM04__) || defined(__AVR_TRM05__) + uint16_t _EEAR : 12; + uint16_t reserved1 : 4; + #elif defined(__AVR_TRM03__) + #if defined(__AVR_ATmega88A__) || defined(__AVR_ATmega88PA__) || defined(__AVR_ATmega168A__) || defined(__AVR_ATmega168PA__) || defined(__AVR_ATmega328P__) + uint16_t _EEAR : 16; + #else + uint8_t _EEAR : 8; + uint8_t reserved1 : 8; + #endif + #endif + }; + static_assert(sizeof(EEAR_reg_t) == 2, "invalid size of ATmega2560 EEAR_reg_t"); + + struct GTCCR_reg_t { + uint8_t _PSRSYNC : 1; + uint8_t _PSRASY : 1; + uint8_t reserved1 : 5; + uint8_t _TSM : 1; + }; + static_assert(sizeof(GTCCR_reg_t) == 1, "invalid size of ATmega2560 GTCCR_reg_t"); + + struct SPCR_reg_t { + uint8_t _SPR : 2; + uint8_t _CPHA : 1; + uint8_t _CPOL : 1; + uint8_t _MSTR : 1; + uint8_t _DORD : 1; + uint8_t _SPE : 1; + uint8_t _SPIE : 1; + }; + static_assert(sizeof(SPCR_reg_t) == 1, "invalid size of ATmega2560 SPCR_reg_t"); + + struct SPSR_reg_t { + uint8_t _SPI2X : 1; + uint8_t reserved1 : 5; + uint8_t _WCOL : 1; + uint8_t _SPIF : 1; + }; + static_assert(sizeof(SPSR_reg_t) == 1, "invalid size of ATmega2560 SPSR_reg_t"); + + struct ACSR_reg_t { + uint8_t _ACIS : 2; + uint8_t _ACIC : 1; + uint8_t _ACIE : 1; + uint8_t _ACI : 1; + uint8_t _ACO : 1; + uint8_t _ACBG : 1; + uint8_t _ACD : 1; + }; + static_assert(sizeof(ACSR_reg_t) == 1, "invalid size of ATmega2560 ACSR_reg_t"); + + struct SMCR_reg_t { + uint8_t _SE : 1; + uint8_t _SM : 3; + uint8_t reserved1 : 4; + }; + static_assert(sizeof(SMCR_reg_t) == 1, "invalid size of ATmega2560 SMCR_reg_t"); + + struct MCUSR_reg_t { + #if defined(__AVR_TRM01__) || defined(__AVR_TRM02__) || defined(__AVR_TRM04__) || defined(__AVR_TRM05__) + uint8_t _PORF : 1; + uint8_t _EXTRF : 1; + uint8_t _BORF : 1; + uint8_t _WDRF : 1; + uint8_t _JTRF : 1; + uint8_t reserved1 : 3; + #elif defined(__AVR_TRM03__) + uint8_t _PORF : 1; + uint8_t _EXTRF : 1; + uint8_t _BORF : 1; + uint8_t _WDRF : 1; + uint8_t reserved1 : 4; + #endif + }; + static_assert(sizeof(MCUSR_reg_t) == 1, "invalid size of ATmega2560 MCUSR_reg_t"); + + struct MCUCR_reg_t { + #if defined(__AVR_TRM01__) || defined(__AVR_TRM04__) + uint8_t _IVCE : 1; + uint8_t _IVSEL : 1; + uint8_t reserved1 : 2; + uint8_t _PUD : 1; + uint8_t reserved2 : 2; + uint8_t _JTD : 1; + #elif defined(__AVR_TRM02__) || defined(__AVR_TRM05__) + uint8_t _IVCE : 1; + uint8_t _IVSEL : 1; + uint8_t reserved1 : 2; + uint8_t _PUD : 1; + uint8_t _BODSE : 1; + uint8_t _BODS : 1; + uint8_t _JTD : 1; + #elif defined(__AVR_TRM03__) + uint8_t _IVCE : 1; + uint8_t _IVSEL : 1; + uint8_t reserved1 : 2; + uint8_t _PUD : 1; + uint8_t _BODSE : 1; + uint8_t _BODS : 1; + uint8_t reserved2 : 1; + #endif + }; + static_assert(sizeof(MCUCR_reg_t) == 1, "invalid size of ATmega2560 MCUCR_reg_t"); + + struct SPMCSR_reg_t { + #if defined(__AVR_TRM01__) || defined(__AVR_TRM02__) || defined(__AVR_TRM04__) || defined(__AVR_TRM05__) + uint8_t _SPMEN : 1; + uint8_t _PGERS : 1; + uint8_t _PGWRT : 1; + uint8_t _BLBSET : 1; + uint8_t _RWWSRE : 1; + uint8_t _SIGRD : 1; + uint8_t _RWWSB : 1; + uint8_t _SPMIE : 1; + #elif defined(__AVR_TRM03__) + #if defined(__AVR_ATmega88A__) || defined(__AVR_ATmega88PA__) || defined(__AVR_ATmega168A__) || defined(__AVR_ATmega168PA__) || defined(__AVR_ATmega328P__) + uint8_t _SPMEN : 1; + uint8_t _PGERS : 1; + uint8_t _PGWRT : 1; + uint8_t _BLBSET : 1; + uint8_t _RWWSRE : 1; + uint8_t _SIGRD : 1; + uint8_t _RWWSB : 1; + uint8_t _SPMIE : 1; + #else + uint8_t _SPMEN : 1; + uint8_t _PGERS : 1; + uint8_t _PGWRT : 1; + uint8_t _BLBSET : 1; + uint8_t reserved1 : 1; + uint8_t _SIGRD : 1; + uint8_t reserved2 : 1; + uint8_t _SPMIE : 1; + #endif + #endif + }; + static_assert(sizeof(SPMCSR_reg_t) == 1, "invalid size of ATmega2560 SPMCSR_reg_t"); + +#endif // __AVR_TRM01__ || __AVR_TRM02__ || __AVR_TRM03__ || __AVR_TRM04__ + +#if defined(__AVR_TRM01__) || defined(__AVR_TRM02__) || defined(__AVR_TRM04__) || defined(__AVR_TRM05__) + + struct RAMPZ_reg_t { + #if defined(__AVR_TRM01__) || defined(__AVR_TRM02__) || defined(__AVR_TRM04__) + uint8_t _RAMPZ : 2; + uint8_t reserved1 : 6; + #elif defined(__AVR_TRM05__) + uint8_t _RAMPZ : 1; + uint8_t reserved1 : 7; + #endif + }; + static_assert(sizeof(RAMPZ_reg_t) == 1, "invalid size of ATmega2560 RAMPZ_reg_t"); + +#endif // __AVR_TRM01__ || __AVR_TRM02__ || __AVR_TRM04__ || __AVR_TRM05__ + +#ifdef __AVR_TRM01__ + + struct EIND_reg_t { + uint8_t _EIND0 : 1; + uint8_t reserved1 : 7; + }; + static_assert(sizeof(EIND_reg_t) == 1, "invalid size of ATmega2560 EIND_reg_t"); + +#endif // __AVR_TRM01__ + +#if defined(__AVR_TRM01__) || defined(__AVR_TRM02__) || defined(__AVR_TRM03__) || defined(__AVR_TRM04__) || defined(__AVR_TRM05__) + + struct SP_reg_t { + #if defined(__AVR_TRM01__) || defined(__AVR_TRM02__) || defined(__AVR_TRM04__) || defined(__AVR_TRM05__) + uint16_t _SP; + #elif defined(__AVR_TRM03__) + #if defined(__AVR_ATmega88A__) || defined(__AVR_ATmega88PA__) || defined(__AVR_ATmega168A__) || defined(__AVR_ATmega168PA__) || defined(__AVR_ATmega328P__) + uint16_t _SP : 11; + uint16_t reserved1 : 5; + #else + uint16_t _SP : 10; + uint16_t reserved1 : 6; + #endif + #endif + }; + static_assert(sizeof(SP_reg_t) == 2, "invalid size of ATmega2560 SP_reg_t"); + + struct SREG_reg_t { + uint8_t _C : 1; + uint8_t _Z : 1; + uint8_t _N : 1; + uint8_t _V : 1; + uint8_t _S : 1; + uint8_t _H : 1; + uint8_t _T : 1; + uint8_t _I : 1; + }; + static_assert(sizeof(SREG_reg_t) == 1, "invalid size of ATmega2560 SREG_reg_t"); + + struct WDTCSR_reg_t { + uint8_t _WDP0 : 1; + uint8_t _WDP1 : 1; + uint8_t _WDP2 : 1; + uint8_t _WDE : 1; + uint8_t _WDCE : 1; + uint8_t _WDP3 : 1; + uint8_t _WDIE : 1; + uint8_t _WDIF : 1; + }; + static_assert(sizeof(WDTCSR_reg_t) == 1, "invalid size of ATmega2560 WDTCSR_reg_t"); + + struct CLKPR_reg_t { + uint8_t _CLKPS : 4; + uint8_t reserved1 : 3; + uint8_t _CLKPCE : 1; + }; + static_assert(sizeof(CLKPR_reg_t) == 1, "invalid size of ATmega2560 CLKPR_reg_t"); + + struct PRR0_reg_t { + #ifdef __AVR_TRM01__ + uint8_t _PRADC : 1; + uint8_t _PRUSART0 : 1; + uint8_t _PRSPI : 1; + uint8_t _PRTIM1 : 1; + uint8_t reserved1 : 1; + uint8_t _PRTIM0 : 1; + uint8_t _PRTIM2 : 1; + uint8_t _PRTWI : 1; + #elif defined(__AVR_TRM02__) || defined(__AVR_TRM05__) + uint8_t _PRADC : 1; + uint8_t _PRUSART0 : 1; + uint8_t _PRSPI : 1; + uint8_t _PRTIM1 : 1; + uint8_t _PRUSART1 : 1; + uint8_t _PRTIM0 : 1; + uint8_t _PRTIM2 : 1; + uint8_t _PRTWI : 1; + #elif defined(__AVR_TRM03__) + uint8_t _PRADC : 1; + uint8_t _PRUSART0 : 1; + uint8_t _PRSPI : 1; + uint8_t _PRTIM1 : 1; + uint8_t reserved1 : 1; + uint8_t _PRTIM0 : 1; + uint8_t _PRTIM2 : 1; + uint8_t _PRTWI : 1; + #elif defined(__AVR_TRM04__) + uint8_t _PRADC : 1; + uint8_t reserved1 : 1; + uint8_t _PRSPI : 1; + uint8_t _PRTIM1 : 1; + uint8_t reserved2 : 1; + uint8_t _PRTIM0 : 1; + uint8_t _PRTIM2 : 1; + uint8_t _PRTWI : 1; + #endif + }; + static_assert(sizeof(PRR0_reg_t) == 1, "invalid size of ATmega2560 PRR0_reg_t"); + +#endif // __AVR_TRM01__ || __AVR_TRM02__ || __AVR_TRM03__ || __AVR_TRM04__ || __AVR_TRM05__ + +#if defined(__AVR_TRM01__) || defined(__AVR_TRM02__) || defined(__AVR_TRM04__) + + struct PRR1_reg_t { + #ifdef __AVR_TRM01__ + uint8_t _PRUSART1 : 1; + uint8_t _PRUSART2 : 1; + uint8_t _PRUSART3 : 1; + uint8_t _PRTIM3 : 1; + uint8_t _PRTIM4 : 1; + uint8_t _PRTIM5 : 1; + uint8_t reserved1 : 2; + #elif defined(__AVR_TRM02__) + uint8_t _PRTIM3 : 1; + uint8_t reserved1 : 7; + #elif defined(__AVR_TRM04__) + uint8_t _PRUSART1 : 1; + uint8_t reserved1 : 2; + uint8_t _PRTIM3 : 1; + uint8_t reserved2 : 3; + uint8_t _PRUSB : 1; + #endif + }; + static_assert(sizeof(PRR1_reg_t) == 1, "invalid size of ATmega2560 PRR1_reg_t"); + +#endif // __AVR_TRM01__ || __AVR_TRM02__ || __AVR_TRM04__ + +#if defined(__AVR_TRM01__) || defined(__AVR_TRM02__) || defined(__AVR_TRM03__) || defined(__AVR_TRM04__) || defined(__AVR_TRM05__) + + struct PCICR_reg_t { + #if defined(__AVR_TRM01__) || defined(__AVR_TRM03__) + uint8_t _PCIE0 : 1; + uint8_t _PCIE1 : 1; + uint8_t _PCIE2 : 1; + uint8_t reserved1 : 5; + #elif defined(__AVR_TRM02__) || defined(__AVR_TRM05__) + uint8_t _PCIE0 : 1; + uint8_t _PCIE1 : 1; + uint8_t _PCIE2 : 1; + uint8_t _PCIE3 : 1; + uint8_t reserved1 : 4; + #elif defined(__AVR_TRM04__) + uint8_t _PCIE0 : 1; + uint8_t reserved1 : 7; + #endif + }; + static_assert(sizeof(PCICR_reg_t) == 1, "invalid size of ATmega2560 PCICR_reg_t"); + + struct EICRA_reg_t { + #if defined(__AVR_TRM01__) || defined(__AVR_TRM04__) + uint8_t _ISC0 : 2; + uint8_t _ISC1 : 2; + uint8_t _ISC2 : 2; + uint8_t _ISC3 : 2; + #elif defined(__AVR_TRM02__) || defined(__AVR_TRM05__) + uint8_t _ISC0 : 2; + uint8_t _ISC1 : 2; + uint8_t _ISC2 : 2; + uint8_t reserved1 : 2; + #elif defined(__AVR_TRM03__) + uint8_t _ISC0 : 2; + uint8_t _ISC1 : 2; + uint8_t reserved1 : 4; + #endif + }; + static_assert(sizeof(EICRA_reg_t) == 1, "invalid size of ATmega2560 EICRA_reg_t"); + +#endif // __AVR_TRM01__ || __AVR_TRM02__ || __AVR_TRM03__ || __AVR_TRM04__ || __AVR_TRM05__ + +#if defined(__AVR_TRM01__) || defined(__AVR_TRM04__) + + struct EICRB_reg_t { + uint8_t _ISC4 : 2; + uint8_t _ISC5 : 2; + uint8_t _ISC6 : 2; + uint8_t _ISC7 : 2; + }; + static_assert(sizeof(EICRB_reg_t) == 1, "invalid size of ATmega2560 EICRB_reg_t"); + +#endif // __AVR_TRM01__ || __AVR_TRM04__ + +#if defined(__AVR_TRM03__) + + struct _bitPCMSK1_reg_t { + uint8_t val : 7; + uint8_t reserved1 : 1; + + bool getValue(uint8_t idx) { return val & (1 << idx); } + void setValue(uint8_t idx, bool value) { + if (value) + val |= (1 << idx); + else + val &= ~(1 << idx); + } + }; + +#endif // __AVR_TRM03__ + +#if defined(__AVR_TRM01__) || defined(__AVR_TRM02__) || defined(__AVR_TRM03__) || defined(__AVR_TRM04__) || defined(__AVR_TRM05__) + + struct TIMSK0_reg_t { + #ifdef __AVR_TRM01__ + uint8_t _TOIE0 : 1; + uint8_t _OCIE0A : 1; + uint8_t _OCIE0B : 1; + uint8_t _OCIE0C : 1; + uint8_t reserved1 : 1; + uint8_t _ICIE0 : 1; + uint8_t reserved2 : 2; + #elif defined(__AVR_TRM02__) || defined(__AVR_TRM03__) || defined(__AVR_TRM04__) || defined(__AVR_TRM05__) + uint8_t _TOIE0 : 1; + uint8_t _OCIE0A : 1; + uint8_t _OCIE0B : 1; + uint8_t reserved1 : 5; + #endif + }; + static_assert(sizeof(TIMSK0_reg_t) == 1, "invalid size of ATmega2560 TIMSK0_reg_t"); + + struct TIMSK1_reg_t { + #if defined(__AVR_TRM01__) || defined(__AVR_TRM04__) + uint8_t _TOIE1 : 1; + uint8_t _OCIE1A : 1; + uint8_t _OCIE1B : 1; + uint8_t _OCIE1C : 1; + uint8_t reserved1 : 1; + uint8_t _ICIE1: 1; + uint8_t reserved2 : 2; + #elif defined(__AVR_TRM02__) || defined(__AVR_TRM03__) || defined(__AVR_TRM05__) + uint8_t _TOIE1 : 1; + uint8_t _OCIE1A : 1; + uint8_t _OCIE1B : 1; + uint8_t reserved1 : 2; + uint8_t _ICIE1: 1; + uint8_t reserved2 : 2; + #endif + }; + static_assert(sizeof(TIMSK1_reg_t) == 1, "invalid size of ATmega2560 TIMSK1_reg_t"); + + struct TIMSK2_reg_t { + uint8_t _TOIE2 : 1; + uint8_t _OCIE2A : 1; + uint8_t _OCIE2B : 1; + uint8_t reserved1 : 5; + }; + static_assert(sizeof(TIMSK2_reg_t) == 1, "invalid size of ATmega2560 TIMSK2_reg_t"); + +#endif // __AVR_TRM01__ || __AVR_TRM02__ || __AVR_TRM03__ || __AVR_TRM04__ || __AVR_TRM05__ + +#if defined(__AVR_TRM01__) || defined(__AVR_TRM02__) || defined(__AVR_TRM04__) + + struct TIMSK3_reg_t { + #if defined(__AVR_TRM01__) || defined(__AVR_TRM04__) + uint8_t _TOIE3 : 1; + uint8_t _OCIE3A : 1; + uint8_t _OCIE3B : 1; + uint8_t _OCIE3C : 1; + uint8_t reserved1 : 1; + uint8_t _ICIE3 : 1; + uint8_t reserved2 : 2; + #elif defined(__AVR_TRM02__) + uint8_t _TOIE3 : 1; + uint8_t _OCIE3A : 1; + uint8_t _OCIE3B : 1; + uint8_t reserved1 : 2; + uint8_t _ICIE3 : 1; + uint8_t reserved2 : 2; + #endif + }; + static_assert(sizeof(TIMSK3_reg_t) == 1, "invalid size of ATmega2560 TIMSK3_reg_t"); + +#endif // __AVR_TRM01__ || __AVR_TRM02__ || __AVR_TRM04__ + +#ifdef __AVR_TRM01__ + + struct TIMSK4_reg_t { + uint8_t _TOIE4 : 1; + uint8_t _OCIE4A : 1; + uint8_t _OCIE4B : 1; + uint8_t _OCIE4C : 1; + uint8_t reserved1 : 1; + uint8_t _ICIE4 : 1; + uint8_t reserved2 : 2; + }; + static_assert(sizeof(TIMSK4_reg_t) == 1, "invalid size of ATmega2560 TIMSK4_reg_t"); + + struct TIMSK5_reg_t { + uint8_t _TOIE5 : 1; + uint8_t _OCIE5A : 1; + uint8_t _OCIE5B : 1; + uint8_t _OCIE5C : 1; + uint8_t reserved1 : 1; + uint8_t _ICIE5 : 1; + uint8_t reserved2 : 2; + }; + static_assert(sizeof(TIMSK5_reg_t) == 1, "invalid size of ATmega2560 TIMSK5_reg_t"); + +#endif // __AVR_TRM01__ + +#if defined(__AVR_TRM01__) || defined(__AVR_TRM04__) + + struct XMCRA_reg_t { + uint8_t _SRW0 : 2; + uint8_t _SRW1 : 2; + uint8_t _SRL : 3; + uint8_t _SRE : 1; + }; + static_assert(sizeof(XMCRA_reg_t) == 1, "invalid size of ATmega2560 XMCRA_reg_t"); + + struct XMCRB_reg_t { + uint8_t _XMM : 3; + uint8_t reserved1 : 4; + uint8_t _XMBK : 1; + }; + static_assert(sizeof(XMCRB_reg_t) == 1, "invalid size of ATmega2560 XMCRB_reg_t"); + +#endif // __AVR_TRM01__ || __AVR_TRM04__ + +#if defined(__AVR_TRM01__) || defined(__AVR_TRM02__) || defined(__AVR_TRM03__) || defined(__AVR_TRM04__) || defined(__AVR_TRM05__) + + struct ADCSRA_reg_t { + uint8_t _ADPS : 3; + uint8_t _ADIE : 1; + uint8_t _ADIF : 1; + uint8_t _ADATE : 1; + uint8_t _ADSC : 1; + uint8_t _ADEN : 1; + }; + static_assert(sizeof(ADCSRA_reg_t) == 1, "invalid size of ATmega2560 ADCSRA_reg_t"); + + struct ADCSRB_reg_t { + #if defined(__AVR_TRM01__) || defined(__AVR_TRM04__) + uint8_t _ADTS : 3; + uint8_t _MUX5 : 1; + uint8_t reserved1 : 2; + uint8_t _ACME : 1; + uint8_t reserved2 : 1; + #elif defined(__AVR_TRM02__) || defined(__AVR_TRM03__) || defined(__AVR_TRM05__) + uint8_t _ADTS : 3; + uint8_t reserved1 : 3; + uint8_t _ACME : 1; + uint8_t reserved2 : 1; + #endif + }; + static_assert(sizeof(ADCSRB_reg_t) == 1, "invalid size of ATmega2560 ADCSRB_reg_t"); + + struct ADMUX_reg_t { + #if defined(__AVR_TRM01__) || defined(__AVR_TRM02__) || defined(__AVR_TRM04__) || defined(__AVR_TRM05__) + uint8_t _MUX0 : 1; + uint8_t _MUX1 : 1; + uint8_t _MUX2 : 1; + uint8_t _MUX3 : 1; + uint8_t _MUX4 : 1; + uint8_t _ADLAR : 1; + uint8_t _REFS0 : 1; + uint8_t _REFS1 : 1; + #elif defined(__AVR_TRM03__) + uint8_t _MUX0 : 1; + uint8_t _MUX1 : 1; + uint8_t _MUX2 : 1; + uint8_t _MUX3 : 1; + uint8_t reserved1 : 1; + uint8_t _ADLAR : 1; + uint8_t _REFS0 : 1; + uint8_t _REFS1 : 1; + #endif + }; + static_assert(sizeof(ADMUX_reg_t) == 1, "invalid size of ATmega2560 ADMUX_reg_t"); + +#endif // __AVR_TRM01__ || __AVR_TRM02__ || __AVR_TRM03__ || __AVR_TRM04__ + +#ifdef __AVR_TRM01__ + + struct DIDR2_reg_t { + uint8_t _ADC8D : 1; + uint8_t _ADC9D : 1; + uint8_t _ADC10D : 1; + uint8_t _ADC11D : 1; + uint8_t _ADC12D : 1; + uint8_t _ADC13D : 1; + uint8_t _ADC14D : 1; + uint8_t _ADC15D : 1; + }; + static_assert(sizeof(DIDR2_reg_t) == 1, "invalid size of ATmega2560 DIDR2_reg_t"); + +#endif // __AVR_TRM01__ + +#if defined(__AVR_TRM01__) || defined(__AVR_TRM02__) || defined(__AVR_TRM03__) || defined(__AVR_TRM04__) || defined(__AVR_TRM05__) + + struct DIDR0_reg_t { + #if defined(__AVR_TRM01__) || defined(__AVR_TRM02__) || defined(__AVR_TRM04__) || defined(__AVR_TRM05__) + uint8_t _ADC0D : 1; + uint8_t _ADC1D : 1; + uint8_t _ADC2D : 1; + uint8_t _ADC3D : 1; + uint8_t _ADC4D : 1; + uint8_t _ADC5D : 1; + uint8_t _ADC6D : 1; + uint8_t _ADC7D : 1; + #elif defined(__AVR_TRM03__) + uint8_t _ADC0D : 1; + uint8_t _ADC1D : 1; + uint8_t _ADC2D : 1; + uint8_t _ADC3D : 1; + uint8_t _ADC4D : 1; + uint8_t _ADC5D : 1; + uint8_t reserved1 : 2; + #endif + }; + static_assert(sizeof(DIDR0_reg_t) == 1, "invalid size of ATmega2560 DIDR0_reg_t"); + + struct DIDR1_reg_t { + uint8_t _AIN0D : 1; + uint8_t _AIN1D : 1; + uint8_t reserved1 : 6; + }; + static_assert(sizeof(DIDR1_reg_t) == 1, "invalid size of ATmega2560 DIDR1_reg_t"); + + struct TCCRnA_reg_t { + #if defined(__AVR_TRM01__) || defined(__AVR_TRM04__) + uint8_t _WGMn0 : 1; + uint8_t _WGMn1 : 1; + uint8_t _COMnC : 2; + uint8_t _COMnB : 2; + uint8_t _COMnA : 2; + #elif defined(__AVR_TRM02__) || defined(__AVR_TRM03__) || defined(__AVR_TRM05__) + uint8_t _WGMn0 : 1; + uint8_t _WGMn1 : 1; + uint8_t reserved1 : 2; + uint8_t _COMnB : 2; + uint8_t _COMnA : 2; + #endif + }; + static_assert(sizeof(TCCRnA_reg_t) == 1, "invalid size of ATmega2560 TCCRnA_reg_t"); + + struct TCCRnB_reg_t { + uint8_t _CSn : 3; + uint8_t _WGMn2 : 1; + uint8_t _WGMn3 : 1; + uint8_t reserved1 : 1; + uint8_t _ICESn : 1; + uint8_t _ICNCn : 1; + }; + static_assert(sizeof(TCCRnB_reg_t) == 1, "invalid size of ATmega2560 TCCRnB_reg_t"); + + struct TCCRnC_reg_t { + #if defined(__AVR_TRM01__) || defined(__AVR_TRM04__) + uint8_t reserved1 : 5; + uint8_t _FOCnC : 1; + uint8_t _FOCnB : 1; + uint8_t _FOCnA : 1; + #elif defined(__AVR_TRM02__) || defined(__AVR_TRM03__) || defined(__AVR_TRM05__) + uint8_t reserved1 : 6; + uint8_t _FOCnB : 1; + uint8_t _FOCnA : 1; + #endif + }; + static_assert(sizeof(TCCRnC_reg_t) == 1, "invalid size of ATmega2560 TCCRnC_reg_t"); + + struct TIMER_dev_t { + TCCRnA_reg_t _TCCRnA; + TCCRnB_reg_t _TCCRnB; + TCCRnC_reg_t _TCCRnC; + uint8_t reserved1; + uint16_t _TCNTn; + uint16_t _ICRn; + uint16_t _OCRnA; + uint16_t _OCRnB; + #if defined(__AVR_TRM01__) || defined(__AVR_TRM04__) + uint16_t _OCRnC; + #endif + + inline void operator = ( const TIMER_dev_t& r ) volatile { + using namespace AVRHelpers; + dwrite(this->_TCCRnA, r._TCCRnA); + dwrite(this->_TCCRnB, r._TCCRnB); + dwrite(this->_TCCRnC, r._TCCRnC); + this->reserved1 = r.reserved1; + this->_TCNTn = r._TCNTn; + this->_ICRn = r._ICRn; + this->_OCRnA = r._OCRnA; + this->_OCRnB = r._OCRnB; + #if defined(__AVR_TRM01__) || defined(__AVR_TRM04__) + this->_OCRnC = r._OCRnC; + #endif + } + }; + #if defined(__AVR_TRM01__) || defined(__AVR_TRM04__) + static_assert(sizeof(TIMER_dev_t) == 14, "invalid size of ATmega2560 TIMER_dev_t"); + #elif defined(__AVR_TRM02__) || defined(__AVR_TRM03__) || defined(__AVR_TRM05__) + static_assert(sizeof(TIMER_dev_t) == 12, "invalid size of ATmega1284 TIMER_dev_t"); + #endif + + struct TCCRnA_8bit_reg_t { + uint8_t _WGMn0 : 1; + uint8_t _WGMn1 : 1; + uint8_t reserved1 : 2; + uint8_t _COMnB : 2; + uint8_t _COMnA : 2; + }; + static_assert(sizeof(TCCRnA_8bit_reg_t) == 1, "invalid size of ATmega2560 TCCRnA_8bit_reg_t"); + + struct TCCRnB_8bit_reg_t { + uint8_t _CSn : 3; + uint8_t _WGMn2 : 1; + uint8_t reserved1 : 2; + uint8_t _FOCnB : 1; + uint8_t _FOCnA : 1; + }; + static_assert(sizeof(TCCRnB_8bit_reg_t) == 1, "invalid size of ATmega2560 TCCRnB_8bit_reg_t"); + + struct TIMER_8bit_dev_t { + TCCRnA_8bit_reg_t _TCCRnA; + TCCRnB_8bit_reg_t _TCCRnB; + uint8_t _TCNTn; + uint8_t _OCRnA; + uint8_t _OCRnB; + + inline void operator = ( const TIMER_8bit_dev_t& r ) volatile { + using namespace AVRHelpers; + dwrite(this->_TCCRnA, r._TCCRnA); + dwrite(this->_TCCRnB, r._TCCRnB); + this->_TCNTn = r._TCNTn; + this->_OCRnA = r._OCRnA; + this->_OCRnB = r._OCRnB; + } + }; + static_assert(sizeof(TIMER_8bit_dev_t) == 5, "invalid size of ATmega2560 TIMER_8bit_dev_t"); + + struct ASSR_reg_t { + uint8_t _TCR2BUB : 1; + uint8_t _TCR2AUB : 1; + uint8_t _OCR2BUB : 1; + uint8_t _OCR2AUB : 1; + uint8_t _TCN2UB : 1; + uint8_t _AS2 : 1; + uint8_t _EXCLK : 1; + uint8_t reserved1 : 1; + }; + static_assert(sizeof(ASSR_reg_t) == 1, "invalid size of ATmega2560 ASSR_reg_t"); + + struct TWSR_reg_t { + uint8_t _TWPS0 : 1; + uint8_t _TWPS1 : 1; + uint8_t reserved1 : 1; + uint8_t _TWS3 : 1; + uint8_t _TWS4 : 1; + uint8_t _TWS5 : 1; + uint8_t _TWS6 : 1; + uint8_t _TWS7 : 1; + }; + static_assert(sizeof(TWSR_reg_t) == 1, "invalid size of ATmega2560 TWSR_reg_t"); + + struct TWAR_reg_t { + uint8_t _TWGCE : 1; + uint8_t _TWA : 7; + }; + static_assert(sizeof(TWAR_reg_t) == 1, "invalid size of ATmega2560 TWAR_reg_t"); + + struct TWCR_reg_t { + uint8_t _TWIE : 1; + uint8_t reserved1 : 1; + uint8_t _TWEN : 1; + uint8_t _TWWC : 1; + uint8_t _TWSTO : 1; + uint8_t _TWSTA : 1; + uint8_t _TWEA : 1; + uint8_t _TWINT : 1; + }; + static_assert(sizeof(TWCR_reg_t) == 1, "invalid size of ATmega2560 TWCR_reg_t"); + + struct TWAMR_reg_t { + uint8_t reserved1 : 1; + uint8_t _TWAM : 7; + }; + static_assert(sizeof(TWAMR_reg_t) == 1, "invalid size of ATmega2560 TWAMR_reg_t"); + + struct UBRRn_reg_t { + uint16_t _UBRR : 12; + uint16_t reserved1 : 4; + }; + static_assert(sizeof(UBRRn_reg_t) == 2, "invalid size of ATmega2560 UBRRn_reg_t)"); + + struct UCSRnC_reg_t { + #if defined(__AVR_TRM01__) || defined(__AVR_TRM02__) || defined(__AVR_TRM03__) || defined(__AVR_TRM04__) + uint8_t _UCPOL : 1; + uint8_t _UCSZn0 : 1; + uint8_t _UCSZn1 : 1; + uint8_t _USBS : 1; + uint8_t _UPM : 2; + uint8_t _UMSEL : 2; + #elif defined(__AVR_TRM05__) + uint8_t _UCPOL : 1; + uint8_t _UCPHA : 1; + uint8_t _UDORD : 1; + uint8_t reserved1 : 3; + uint8_t _UMSEL : 2; + #endif + }; + static_assert(sizeof(UCSRnC_reg_t) == 1, "invalid size of ATmega2560 UCSRnC_reg_t"); + + struct UCSRnB_reg_t { + uint8_t _TXB8 : 1; + uint8_t _RXB8 : 1; + uint8_t _UCSZn2 : 1; + uint8_t _TXEN : 1; + uint8_t _RXEN : 1; + uint8_t _UDRIE : 1; + uint8_t _TXCIE : 1; + uint8_t _RXCIE : 1; + }; + static_assert(sizeof(UCSRnB_reg_t) == 1, "invalid size of ATmega2560 UCSRnB_reg_t"); + + struct UCSRnA_reg_t { + uint8_t _MPCM : 1; + uint8_t _U2X : 1; + uint8_t _UPE : 1; + uint8_t _DOR : 1; + uint8_t _FE : 1; + uint8_t _UDRE : 1; + uint8_t _TXC : 1; + uint8_t _RXC : 1; + }; + static_assert(sizeof(UCSRnA_reg_t) == 1, "invalid size of ATmega2560 UCSRnA_reg_t"); + + struct USART_dev_t { + UCSRnA_reg_t _UCSRnA; + UCSRnB_reg_t _UCSRnB; + UCSRnC_reg_t _UCSRnC; + uint8_t reserved1; + UBRRn_reg_t _UBRRn; + uint8_t _UDRn; + + inline void operator = ( const USART_dev_t& r ) volatile { + using namespace AVRHelpers; + dwrite(this->_UCSRnA, r._UCSRnA); + dwrite(this->_UCSRnB, r._UCSRnB); + dwrite(this->_UCSRnC, r._UCSRnC); + dwrite(this->reserved1, r.reserved1); + dwrite(this->_UBRRn, r._UBRRn); + dwrite(this->_UDRn, r._UDRn); + } + }; + static_assert(sizeof(USART_dev_t) == 7, "invalid size of ATmega2560 USART_dev_t"); + +#endif // __AVR_TRM01__ || __AVR_TRM02__ || __AVR_TRM03__ || __AVR_TRM04__ + +#ifdef __AVR_TRM04__ + + struct UHCON_reg_t { + uint8_t _SOFEN : 1; + uint8_t _RESET : 1; + uint8_t _RESUME : 1; + uint8_t reserved1 : 5; + }; + static_assert(sizeof(UHCON_reg_t) == 1, "invalid size of ATUSB90 UHCON_reg_t"); + + struct UHINT_reg_t { + uint8_t _DCONNI : 1; + uint8_t _DDISCI : 1; + uint8_t _RSTI : 1; + uint8_t _RSMEDI : 1; + uint8_t _RXRSMI : 1; + uint8_t _HSOFI : 1; + uint8_t _HWUPI : 1; + uint8_t reserved1 : 1; + }; + static_assert(sizeof(UHINT_reg_t) == 1, "invalid size of ATUSB90 UHINT_reg_t"); + + struct UHIEN_reg_t { + uint8_t _SUSPE : 1; + uint8_t _MSOFE : 1; + uint8_t _SOFE : 1; + uint8_t _EORSTE : 1; + uint8_t _WAKEUPE : 1; + uint8_t _EORSME : 1; + uint8_t _UPRSME : 1; + uint8_t reserved1 : 1; + }; + static_assert(sizeof(UHIEN_reg_t) == 1, "invalid size of ATUSB90 UHIEN_reg_t"); + + struct UHADDR_reg_t { + uint8_t _HADD : 7; + uint8_t reserved1 : 1; + }; + static_assert(sizeof(UHADDR_reg_t) == 1, "invalid size of ATUSB90 UHADDR_reg_t"); + + struct UHFNUM_reg_t { + uint16_t _FNUM : 11; + uint16_t reserved1 : 5; + }; + static_assert(sizeof(UHFNUM_reg_t) == 2, "invalid size of ATUSB90 UHFNUM_reg_t"); + + struct UPINTX_reg_t { + uint8_t _RXINI : 1; + uint8_t _RXSTALLI : 1; + uint8_t _TXOUTI : 1; + uint8_t _TXSTPI : 1; + uint8_t _PERRI : 1; + uint8_t _RWAL : 1; + uint8_t _NAKEDI : 1; + uint8_t _FIFOCON : 1; + }; + static_assert(sizeof(UPINTX_reg_t) == 1, "invalid size of ATUSB90 UPINTX_reg_t"); + + struct UPNUM_reg_t { + uint8_t _PNUM : 3; + uint8_t reserved1 : 5; + }; + static_assert(sizeof(UPNUM_reg_t) == 1, "invalid size of ATUSB90 UPNUM_reg_t"); + + struct UPRST_reg_t { + uint8_t _PRST : 7; + uint8_t reserved1 : 1; + }; + static_assert(sizeof(UPRST_reg_t) == 1, "invalid size of ATUSB90 UPRST_reg_t"); + + struct UPCONX_reg_t { + uint8_t _PEN : 1; + uint8_t reserved1 : 2; + uint8_t _RSTDT : 1; + uint8_t _AUTOSW : 1; + uint8_t _INMODE : 1; + uint8_t _PFREEZE : 1; + uint8_t reserved2 : 1; + }; + static_assert(sizeof(UPCONX_reg_t) == 1, "invalid size of ATUSB90 UPCONX_reg_t"); + + struct UPCFG0X_reg_t { + uint8_t _PEPNUM : 4; + uint8_t _PTOKEN : 2; + uint8_t _PTYPE : 2; + }; + static_assert(sizeof(UPCFG0X_reg_t) == 1, "invalid size of ATUSB90 UPCFG0_reg_t"); + + struct UPCFG1X_reg_t { + uint8_t reserved1 : 1; + uint8_t _ALLOC : 1; + uint8_t _PBK : 2; + uint8_t _PSIZE : 3; + uint8_t reserved2 : 1; + }; + static_assert(sizeof(UPCFG1X_reg_t) == 1, "invalid size of ATUSB90 UPCFG1X_reg_t"); + + struct UPSTAX_reg_t { + uint8_t _NBUSYBK : 2; + uint8_t _DTSEQ : 2; + uint8_t reserved1 : 1; + uint8_t _UNDERFI : 1; + uint8_t _OVERFI : 1; + uint8_t _CFGOK : 1; + }; + static_assert(sizeof(UPSTAX_reg_t) == 1, "invalid size of ATUSB90 UPSTAX_reg_t"); + + struct UPIENX_reg_t { + uint8_t _RXINE : 1; + uint8_t _RXSTALLE : 1; + uint8_t _TXOUTE : 1; + uint8_t _TXSTPE : 1; + uint8_t _PERRE : 1; + uint8_t reserved1 : 1; + uint8_t _NAKEDE : 1; + uint8_t _FLERRE : 1; + }; + static_assert(sizeof(UPIENX_reg_t) == 1, "invalid size of ATUSB90 UPIENX_reg_t"); + + struct UHWCON_reg_t { + uint8_t _UVREGE : 1; + uint8_t reserved1 : 3; + uint8_t _UVCONE : 1; + uint8_t reserved2 : 1; + uint8_t _UIDE : 1; + uint8_t _UIMOD : 1; + }; + static_assert(sizeof(UHWCON_reg_t) == 1, "invalid size of ATUSB90 UHWCON_reg_t"); + + struct USBCON_reg_t { + uint8_t _VBUSTE : 1; + uint8_t _IDTE : 1; + uint8_t reserved1 : 2; + uint8_t _OTGPADE : 1; + uint8_t _FRZCLK : 1; + uint8_t _HOST : 1; + uint8_t _USBE : 1; + }; + static_assert(sizeof(USBCON_reg_t) == 1, "invalid size of ATUSB90 USBCON_reg_t"); + + struct USBSTA_reg_t { + uint8_t _VBUS : 1; + uint8_t _ID : 1; + uint8_t reserved1 : 1; + uint8_t _SPEED : 1; + uint8_t reserved2 : 4; + }; + static_assert(sizeof(USBSTA_reg_t) == 1, "invalid size of ATUSB90 USBSTA_reg_t"); + + struct USBINT_reg_t { + uint8_t _VBUSTI : 1; + uint8_t _IDTI : 1; + uint8_t reserved1 : 6; + }; + static_assert(sizeof(USBINT_reg_t) == 1, "invalid size of ATUSB90 USBINT_reg_t"); + + struct UDPADD_reg_t { + uint16_t _DPADD : 11; + uint16_t reserved1 : 4; + uint16_t _DPACC : 1; + }; + static_assert(sizeof(UDPADD_reg_t) == 2, "invalid size of ATUSB90 UDPADD_reg_t"); + + struct OTGCON_reg_t { + uint8_t _VBUSRQC : 1; + uint8_t _VBUSREQ : 1; + uint8_t _VBUSHWC : 1; + uint8_t _SRPSEL : 1; + uint8_t _SRPREQ : 1; + uint8_t _HNPREQ : 1; + uint8_t reserved1 : 1; + uint8_t _zero : 1; + }; + static_assert(sizeof(OTGCON_reg_t) == 1, "invalid size of ATUSB90 OTGCON_reg_t"); + + struct OTGIEN_reg_t { + uint8_t _SRPE : 1; + uint8_t _VBERRE : 1; + uint8_t _BCERRE : 1; + uint8_t _ROLEEXE : 1; + uint8_t _HNPERRE : 1; + uint8_t _STOE : 1; + uint8_t reserved1 : 2; + }; + static_assert(sizeof(OTGIEN_reg_t) == 1, "invalid size of ATUSB90 OTGIEN_reg_t"); + + struct OTGINT_reg_t { + uint8_t _SRPI : 1; + uint8_t _VBERRI : 1; + uint8_t _BCERRI : 1; + uint8_t _ROLEEXI : 1; + uint8_t _HNPERRI : 1; + uint8_t _STOI : 1; + uint8_t reserved1 : 2; + }; + static_assert(sizeof(OTGINT_reg_t) == 1, "invalid size of ATUSB90 OTGINT_reg_t"); + + struct UDCON_reg_t { + uint8_t _DETACH : 1; + uint8_t _RMWKUP : 1; + uint8_t _LSM : 1; + uint8_t reserved1 : 5; + }; + static_assert(sizeof(UDCON_reg_t) == 1, "invalid size of ATUSB90 UDCON_reg_t"); + + struct UDINT_reg_t { + uint8_t _SUSPI : 1; + uint8_t _MSOFI : 1; + uint8_t _SOFI : 1; + uint8_t _EORSTI : 1; + uint8_t _WAKEUPI : 1; + uint8_t _EORSMI : 1; + uint8_t _UPRSMI : 1; + uint8_t reserved1 : 1; + }; + static_assert(sizeof(UDINT_reg_t) == 1, "invalid size of ATUSB90 UDINT_reg_t"); + + struct UDIEN_reg_t { + uint8_t _SUSPE : 1; + uint8_t _MSOFE : 1; + uint8_t _SOFE : 1; + uint8_t _EORSTE : 1; + uint8_t _WAKEUPE : 1; + uint8_t _EORSME : 1; + uint8_t _UPRSME : 1; + uint8_t reserved1 : 1; + }; + static_assert(sizeof(UDIEN_reg_t) == 1, "invalid size of ATUSB90 UDIEN_reg_t"); + + struct UDADDR_reg_t { + uint8_t _UADD : 7; + uint8_t _ADDEN : 1; + }; + static_assert(sizeof(UDADDR_reg_t) == 1, "invalid size of ATUSB90 UADDR_reg_t"); + + struct UDFNUM_reg_t { + uint16_t _FNUM : 11; + uint16_t reserved1 : 5; + }; + static_assert(sizeof(UDFNUM_reg_t) == 2, "invalid size of ATUSB90 UDFNUM_reg_t"); + + struct UDMFN_reg_t { + uint8_t reserved1 : 4; + uint8_t _FNCERR : 1; + uint8_t reserved2 : 3; + }; + static_assert(sizeof(UDMFN_reg_t) == 1, "invalid size of ATUSB90 UDMFN_reg_t"); + + struct UDTST_reg_t { + uint8_t reserved1 : 2; + uint8_t _TSTJ : 1; + uint8_t _TSTK : 1; + uint8_t _TSTPCKT : 1; + uint8_t _OPMODE2 : 1; + uint8_t reserved2 : 2; + }; + static_assert(sizeof(UDTST_reg_t) == 1, "invalid size of ATUSB90 UDTST_reg_t"); + + struct UEINTX_reg_t { + uint8_t _TXINI : 1; + uint8_t _STALLEDI : 1; + uint8_t _RXOUTI : 1; + uint8_t _RXSTPI : 1; + uint8_t _NAKOUTI : 1; + uint8_t _RWAL : 1; + uint8_t _NAKINI : 1; + uint8_t _FIFOCON : 1; + }; + static_assert(sizeof(UEINTX_reg_t) == 1, "invalid size of ATUSB90 UEINTX_reg_t"); + + struct UENUM_reg_t { + uint8_t _EPNUM : 3; + uint8_t reserved1 : 5; + }; + static_assert(sizeof(UENUM_reg_t) == 1, "invalid size of ATUSB90 UENUM_reg_t"); + + struct UERST_reg_t { + uint8_t _EPRST : 7; + uint8_t reserved1 : 1; + }; + static_assert(sizeof(UERST_reg_t) == 1, "invalid size of ATUSB90 UERST_reg_t"); + + struct UECONX_reg_t { + uint8_t _EPEN : 1; + uint8_t reserved1 : 2; + uint8_t _RSTDT : 1; + uint8_t _STALLRQC : 1; + uint8_t _STALLRQ : 1; + uint8_t reserved2 : 2; + }; + static_assert(sizeof(UECONX_reg_t) == 1, "invalid size of ATUSB90 UECONX_reg_t"); + + struct UECFG0X_reg_t { + uint8_t _EPDIR : 1; + uint8_t _NYETSDIS : 1; + uint8_t _AUTOSW : 1; + uint8_t _ISOSW : 1; + uint8_t reserved1 : 2; + uint8_t _EPTYPE : 2; + }; + static_assert(sizeof(UECFG0X_reg_t) == 1, "invalid size of ATUSB90 UECFG0X_reg_t"); + + struct UECFG1X_reg_t { + uint8_t reserved1 : 1; + uint8_t _ALLOC : 1; + uint8_t _EPBK : 2; + uint8_t _EPSIZE : 3; + uint8_t reserved2 : 1; + }; + static_assert(sizeof(UECFG1X_reg_t) == 1, "invalid size of ATUSB90 UECFG1X_reg_t"); + + struct UESTA0X_reg_t { + uint8_t _NBUSYBK : 2; + uint8_t _DTSEQ : 2; + uint8_t _ZLPSEEN : 1; + uint8_t _UNDERFI : 1; + uint8_t _OVERFI : 1; + uint8_t _CFGOK : 1; + }; + static_assert(sizeof(UESTA0X_reg_t) == 1, "invalid size of ATUSB90 UESTA0X_reg_t"); + + struct UESTA1X_reg_t { + uint8_t _CURRBK : 2; + uint8_t _CTRLDIR : 1; + uint8_t reserved1 : 5; + }; + static_assert(sizeof(UESTA1X_reg_t) == 1, "invalid size of ATUSB90 UESTA1X_reg_t"); + + struct UEIENX_reg_t { + uint8_t _TXINE : 1; + uint8_t _STALLEDE : 1; + uint8_t _RXOUTE : 1; + uint8_t _RXSTPE : 1; + uint8_t _NAKOUTE : 1; + uint8_t reserved1 : 1; + uint8_t _NAKINE : 1; + uint8_t _FLERRE : 1; + }; + static_assert(sizeof(UEIENX_reg_t) == 1, "invalid size of ATUSB90 UEIENX_reg_t"); + + struct UEBCX_reg_t { + uint16_t _BYCT : 11; + uint16_t reserved1 : 5; + }; + static_assert(sizeof(UEBCX_reg_t) == 2, "invalid size of ATUSB90 UEBCX_reg_t"); + + struct UEINT_reg_t { + uint8_t _EPINT : 7; + uint8_t reserved1 : 1; + }; + static_assert(sizeof(UEINT_reg_t) == 1, "invalid size of ATUSB90 UEINT_reg_t"); + + struct UPERRX_reg_t { + uint8_t _DATATGL : 1; + uint8_t _DATAPID : 1; + uint8_t _PID : 1; + uint8_t _TIMEOUT : 1; + uint8_t _CRC16 : 1; + uint8_t _COUNTER : 2; + uint8_t reserved1 : 1; + }; + static_assert(sizeof(UPERRX_reg_t) == 1, "invalid size of ATUSB90 UPERRX_reg_t"); + + struct UPBCX_reg_t { + uint16_t _PBYCT : 11; + uint16_t reserved1 : 5; + }; + static_assert(sizeof(UPBCX_reg_t) == 2, "invalid size of ATUSB90 UPBCX_reg_t"); + + struct OTGTCON_reg_t { + uint8_t _VALUE : 2; + uint8_t reserved1 : 3; + uint8_t _PAGE : 2; + uint8_t _one : 1; + }; + static_assert(sizeof(OTGTCON_reg_t) == 1, "invalid size of ATUSB90 OTGTCON_reg_t"); + + struct PLLCSR_reg_t { + uint8_t _PLOCK : 1; + uint8_t _PLLE : 1; + uint8_t _PLLP : 3; + uint8_t reserved1 : 3; + }; + static_assert(sizeof(PLLCSR_reg_t) == 1, "invalid size of ATUSB90 PLLCSR_reg_t"); + +#endif // __AVR_TRM04__ + +/** + * REGISTER MEMORY MAP + */ + +#define __AVR_DEFREG(tn,n,a) static volatile tn& n = *(tn*)a +#define _AVR_DEFREG(n,a) __AVR_DEFREG(n##_reg_t, _##n, a) + +#ifdef __AVR_TRM01__ + // page 399ff of ATmega640-1280-1281-2560-2561-Datasheet-DS40002211A.pdf + + __AVR_DEFREG(PORT_dev_t, _PORTA, 0x20); + __AVR_DEFREG(PORT_dev_t, _PORTB, 0x23); + __AVR_DEFREG(PORT_dev_t, _PORTC, 0x26); + __AVR_DEFREG(PORT_dev_t, _PORTD, 0x29); + __AVR_DEFREG(PORT_dev_t, _PORTE, 0x2C); + __AVR_DEFREG(PORT_dev_t, _PORTF, 0x2F); + __AVR_DEFREG(PORTG_dev_t, _PORTG, 0x32); + __AVR_DEFREG(PORT_dev_t, _PORTH, 0x100); + __AVR_DEFREG(PORT_dev_t, _PORTJ, 0x103); + __AVR_DEFREG(PORT_dev_t, _PORTK, 0x106); + __AVR_DEFREG(PORT_dev_t, _PORTL, 0x109); + __AVR_DEFREG(TIFR0_reg_t, _TIFR0, 0x35); + __AVR_DEFREG(TIFR1_reg_t, _TIFR1, 0x36); + __AVR_DEFREG(TIFR2_reg_t, _TIFR2, 0x37); + __AVR_DEFREG(TIFR3_reg_t, _TIFR3, 0x38); + __AVR_DEFREG(TIFR4_reg_t, _TIFR4, 0x39); + __AVR_DEFREG(TIFR5_reg_t, _TIFR5, 0x3A); + __AVR_DEFREG(PCIFR_reg_t, _PCIFR, 0x3B); + __AVR_DEFREG(EIFR_reg_t, _EIFR, 0x3C); + __AVR_DEFREG(EIMSK_reg_t, _EIMSK, 0x3D); + __AVR_DEFREG(_bit_reg_t, _GPIOR0, 0x3E); + __AVR_DEFREG(EECR_reg_t, _EECR, 0x3F); + __AVR_DEFREG(uint8_t, _EEDR, 0x40); + __AVR_DEFREG(EEAR_reg_t, _EEAR, 0x41); + __AVR_DEFREG(GTCCR_reg_t, _GTCCR, 0x43); + __AVR_DEFREG(TIMER_8bit_dev_t, TIMER0, 0x44); + __AVR_DEFREG(_bit_reg_t, _GPIOR1, 0x4A); + __AVR_DEFREG(_bit_reg_t, _GPIOR2, 0x4B); + __AVR_DEFREG(SPCR_reg_t, _SPCR, 0x4C); + __AVR_DEFREG(SPSR_reg_t, _SPSR, 0x4D); + __AVR_DEFREG(uint8_t, _SPDR, 0x4E); + __AVR_DEFREG(ACSR_reg_t, _ACSR, 0x50); + __AVR_DEFREG(_bit_reg_t, _OCDR, 0x51); + __AVR_DEFREG(SMCR_reg_t, _SMCR, 0x53); + __AVR_DEFREG(MCUSR_reg_t, _MCUSR, 0x54); + __AVR_DEFREG(MCUCR_reg_t, _MCUCR, 0x55); + __AVR_DEFREG(SPMCSR_reg_t, _SPMCSR, 0x57); + __AVR_DEFREG(RAMPZ_reg_t, _RAMPZ, 0x5B); + __AVR_DEFREG(EIND_reg_t, _EIND, 0x5C); + __AVR_DEFREG(SP_reg_t, _SP, 0x5D); + __AVR_DEFREG(SREG_reg_t, _SREG, 0x5F); + __AVR_DEFREG(WDTCSR_reg_t, _WDTCSR, 0x60); + __AVR_DEFREG(CLKPR_reg_t, _CLKPR, 0x61); + __AVR_DEFREG(PRR0_reg_t, _PRR0, 0x64); + __AVR_DEFREG(PRR1_reg_t, _PRR1, 0x65); + __AVR_DEFREG(uint8_t, _OSCCAL, 0x66); + __AVR_DEFREG(PCICR_reg_t, _PCICR, 0x68); + __AVR_DEFREG(EICRA_reg_t, _EICRA, 0x69); + __AVR_DEFREG(EICRB_reg_t, _EICRB, 0x6A); + __AVR_DEFREG(_bit_reg_t, _PCMSK0, 0x6B); + __AVR_DEFREG(_bit_reg_t, _PCMSK1, 0x6C); + __AVR_DEFREG(_bit_reg_t, _PCMSK2, 0x6D); + __AVR_DEFREG(TIMSK0_reg_t, _TIMSK0, 0x6E); + __AVR_DEFREG(TIMSK1_reg_t, _TIMSK1, 0x6F); + __AVR_DEFREG(TIMSK2_reg_t, _TIMSK2, 0x70); + __AVR_DEFREG(TIMSK3_reg_t, _TIMSK3, 0x71); + __AVR_DEFREG(TIMSK4_reg_t, _TIMSK4, 0x72); + __AVR_DEFREG(TIMSK5_reg_t, _TIMSK5, 0x73); + __AVR_DEFREG(XMCRA_reg_t, _XMCRA, 0x74); + __AVR_DEFREG(XMCRB_reg_t, _XMCRB, 0x75); + __AVR_DEFREG(uint16_t, _ADC, 0x78); + __AVR_DEFREG(ADCSRA_reg_t, _ADCSRA, 0x7A); + __AVR_DEFREG(ADCSRB_reg_t, _ADCSRB, 0x7B); + __AVR_DEFREG(ADMUX_reg_t, _ADMUX, 0x7C); + __AVR_DEFREG(DIDR2_reg_t, _DIDR2, 0x7D); + __AVR_DEFREG(DIDR0_reg_t, _DIDR0, 0x7E); + __AVR_DEFREG(DIDR1_reg_t, _DIDR1, 0x7F); + __AVR_DEFREG(TIMER_dev_t, TIMER1, 0x80); + __AVR_DEFREG(TIMER_dev_t, TIMER3, 0x90); + __AVR_DEFREG(TIMER_dev_t, TIMER4, 0xA0); + __AVR_DEFREG(TIMER_dev_t, TIMER5, 0x120); + __AVR_DEFREG(TIMER_8bit_dev_t, _TIMER2, 0xB0); + __AVR_DEFREG(ASSR_reg_t, _ASSR, 0xB6); + __AVR_DEFREG(uint8_t, _TWBR, 0xB8); + __AVR_DEFREG(TWSR_reg_t, _TWSR, 0xB9); + __AVR_DEFREG(TWAR_reg_t, _TWAR, 0xBA); + __AVR_DEFREG(uint8_t, _TWDR, 0xBB); + __AVR_DEFREG(TWCR_reg_t, _TWCR, 0xBC); + __AVR_DEFREG(TWAMR_reg_t, _TWAMR, 0xBD); + __AVR_DEFREG(USART_dev_t, USART0, 0xC0); + __AVR_DEFREG(USART_dev_t, USART1, 0xC8); + __AVR_DEFREG(USART_dev_t, USART2, 0xD0); + __AVR_DEFREG(USART_dev_t, USART3, 0x130); + +#elif defined(__AVR_TRM02__) + // page 637ff of ATmega164A_PA-324A_PA-644A_PA-1284_P_Data-Sheet-40002070B.pdf + __AVR_DEFREG(PORT_dev_t, _PORTA, 0x20); + __AVR_DEFREG(PORT_dev_t, _PORTB, 0x23); + __AVR_DEFREG(PORT_dev_t, _PORTC, 0x26); + __AVR_DEFREG(PORT_dev_t, _PORTD, 0x29); + __AVR_DEFREG(TIFR0_reg_t, _TIFR0, 0x35); + __AVR_DEFREG(TIFR1_reg_t, _TIFR1, 0x36); + __AVR_DEFREG(TIFR2_reg_t, _TIFR2, 0x37); + __AVR_DEFREG(TIFR3_reg_t, _TIFR3, 0x38); + __AVR_DEFREG(PCIFR_reg_t, _PCIFR, 0x3B); + __AVR_DEFREG(EIFR_reg_t, _EIFR, 0x3C); + __AVR_DEFREG(EIMSK_reg_t, _EIMSK, 0x3D); + __AVR_DEFREG(_bit_reg_t, _GPIOR0, 0x3E); + __AVR_DEFREG(EECR_reg_t, _EECR, 0x3F); + __AVR_DEFREG(uint8_t, _EEDR, 0x40); + __AVR_DEFREG(EEAR_reg_t, _EEAR, 0x41); + __AVR_DEFREG(GTCCR_reg_t, _GTCCR, 0x43); + __AVR_DEFREG(TIMER_8bit_dev_t, TIMER0, 0x44); + __AVR_DEFREG(_bit_reg_t, _GPIOR1, 0x4A); + __AVR_DEFREG(_bit_reg_t, _GPIOR2, 0x4B); + __AVR_DEFREG(SPCR_reg_t, _SPCR, 0x4C); + __AVR_DEFREG(SPSR_reg_t, _SPSR, 0x4D); + __AVR_DEFREG(uint8_t, _SPDR, 0x4E); + __AVR_DEFREG(ACSR_reg_t, _ACSR, 0x50); + __AVR_DEFREG(SMCR_reg_t, _SMCR, 0x53); + __AVR_DEFREG(MCUSR_reg_t, _MSUSR, 0x54); + __AVR_DEFREG(MCUCR_reg_t, _MCUCR, 0x55); + __AVR_DEFREG(SPMCSR_reg_t, _SPMCSR, 0x57); + __AVR_DEFREG(SP_reg_t, _SP, 0x5D); + __AVR_DEFREG(SREG_reg_t, _SREG, 0x5F); + __AVR_DEFREG(WDTCSR_reg_t, _WDTCSR, 0x60); + __AVR_DEFREG(CLKPR_reg_t, _CLKPR, 0x61); + __AVR_DEFREG(PRR0_reg_t, _PRR0, 0x64); + __AVR_DEFREG(PRR1_reg_t, _PRR1, 0x65); + __AVR_DEFREG(uint8_t, _OSCCAL, 0x66); + __AVR_DEFREG(PCICR_reg_t, _PCICR, 0x68); + __AVR_DEFREG(EICRA_reg_t, _EICRA, 0x69); + __AVR_DEFREG(_bit_reg_t, _PCMSK0, 0x6B); + __AVR_DEFREG(_bit_reg_t, _PCMSK1, 0x6C); + __AVR_DEFREG(_bit_reg_t, _PCMSK2, 0x6D); + __AVR_DEFREG(TIMSK0_reg_t, _TIMSK0, 0x6E); + __AVR_DEFREG(TIMSK1_reg_t, _TIMSK1, 0x6F); + __AVR_DEFREG(TIMSK2_reg_t, _TIMSK2, 0x70); + __AVR_DEFREG(TIMSK3_reg_t, _TIMSK3, 0x71); + __AVR_DEFREG(_bit_reg_t, _PCMSK3, 0x73); + __AVR_DEFREG(uint16_t, _ADC, 0x78); + __AVR_DEFREG(ADCSRA_reg_t, _ADCSRA, 0x7A); + __AVR_DEFREG(ADCSRB_reg_t, _ADCSRB, 0x7B); + __AVR_DEFREG(ADMUX_reg_t, _ADMUX, 0x7C); + __AVR_DEFREG(DIDR0_reg_t, _DIDR0, 0x7E); + __AVR_DEFREG(DIDR1_reg_t, _DIDR1, 0x7F); + __AVR_DEFREG(TIMER_dev_t, TIMER1, 0x80); + __AVR_DEFREG(TIMER_dev_t, TIMER3, 0x90); + __AVR_DEFREG(TIMER_8bit_dev_t, _TIMER2, 0xB0); + __AVR_DEFREG(ASSR_reg_t, _ASSR, 0xB6); + __AVR_DEFREG(uint8_t, _TWBR, 0xB8); + __AVR_DEFREG(TWSR_reg_t, _TWSR, 0xB9); + __AVR_DEFREG(TWAR_reg_t, _TWAR, 0xBA); + __AVR_DEFREG(uint8_t, _TWDR, 0xBB); + __AVR_DEFREG(TWCR_reg_t, _TWCR, 0xBC); + __AVR_DEFREG(TWAMR_reg_t, _TWAMR, 0xBD); + __AVR_DEFREG(USART_dev_t, USART0, 0xC0); + __AVR_DEFREG(USART_dev_t, USART1, 0xC8); + +#elif defined(__AVR_TRM03__) + // page 621ff of ATmega48A-PA-88A-PA-168A-PA-328-P-DS-DS40002061B.pdf + __AVR_DEFREG(PORT_dev_t, _PORTB, 0x23); + __AVR_DEFREG(PORTC_dev_t, _PORTC, 0x26); + __AVR_DEFREG(PORT_dev_t, _PORTD, 0x29); + __AVR_DEFREG(TIFR0_reg_t, _TIFR0, 0x35); + __AVR_DEFREG(TIFR1_reg_t, _TIFR1, 0x36); + __AVR_DEFREG(TIFR2_reg_t, _TIFR2, 0x37); + __AVR_DEFREG(PCIFR_reg_t, _PCIFR, 0x3B); + __AVR_DEFREG(EIFR_reg_t, _EIFR, 0x3C); + __AVR_DEFREG(EIMSK_reg_t, _EIMSK, 0x3D); + __AVR_DEFREG(_bit_reg_t, _GPIOR0, 0x3E); + __AVR_DEFREG(EECR_reg_t, _EECR, 0x3F); + __AVR_DEFREG(uint8_t, _EEDR, 0x40); + __AVR_DEFREG(EEAR_reg_t, _EEAR, 0x41); + __AVR_DEFREG(GTCCR_reg_t, _GTCCR, 0x43); + __AVR_DEFREG(TIMER_8bit_dev_t, TIMER0, 0x44); + __AVR_DEFREG(_bit_reg_t, _GPIOR1, 0x4A); + __AVR_DEFREG(_bit_reg_t, _GPIOR2, 0x4B); + __AVR_DEFREG(SPCR_reg_t, _SPCR, 0x4C); + __AVR_DEFREG(SPSR_reg_t, _SPSR, 0x4D); + __AVR_DEFREG(uint8_t, _SPDR, 0x4E); + __AVR_DEFREG(ACSR_reg_t, _ACSR, 0x50); + __AVR_DEFREG(SMCR_reg_t, _SMCR, 0x53); + __AVR_DEFREG(MCUSR_reg_t, _MSUCR, 0x54); + __AVR_DEFREG(MCUCR_reg_t, _MCUCR, 0x55); + __AVR_DEFREG(SPMCSR_reg_t, _SPMCSR, 0x57); + __AVR_DEFREG(SP_reg_t, _SP, 0x5D); + __AVR_DEFREG(SREG_reg_t, _SREG, 0x5F); + __AVR_DEFREG(WDTCSR_reg_t, _WDTCSR, 0x60); + __AVR_DEFREG(CLKPR_reg_t, _CLKPR, 0x61); + __AVR_DEFREG(PRR0_reg_t, _PRR0, 0x64); + __AVR_DEFREG(uint8_t, _OSCCAL, 0x66); + __AVR_DEFREG(PCICR_reg_t, _PCICR, 0x68); + __AVR_DEFREG(EICRA_reg_t, _EICRA, 0x69); + __AVR_DEFREG(_bit_reg_t, _PCMSK0, 0x6B); + __AVR_DEFREG(_bitPCMSK1_reg_t, _PCMSK1, 0x6C); + __AVR_DEFREG(_bit_reg_t, _PCMSK2, 0x6D); + __AVR_DEFREG(TIMSK0_reg_t, _TIMSK0, 0x6E); + __AVR_DEFREG(TIMSK1_reg_t, _TIMSK1, 0x6F); + __AVR_DEFREG(TIMSK2_reg_t, _TIMSK2, 0x70); + __AVR_DEFREG(uint16_t, _ADC, 0x78); + __AVR_DEFREG(ADCSRA_reg_t, _ADCSRA, 0x7A); + __AVR_DEFREG(ADCSRB_reg_t, _ADCSRB, 0x7B); + __AVR_DEFREG(ADMUX_reg_t, _ADMUX, 0x7C); + __AVR_DEFREG(DIDR0_reg_t, _DIDR0, 0x7E); + __AVR_DEFREG(DIDR1_reg_t, _DIDR1, 0x7F); + __AVR_DEFREG(TIMER_dev_t, TIMER1, 0x80); + __AVR_DEFREG(TIMER_8bit_dev_t, _TIMER2, 0xB0); + __AVR_DEFREG(ASSR_reg_t, _ASSR, 0xB6); + __AVR_DEFREG(uint8_t, _TWBR, 0xB8); + __AVR_DEFREG(TWSR_reg_t, _TWSR, 0xB9); + __AVR_DEFREG(TWAR_reg_t, _TWAR, 0xBA); + __AVR_DEFREG(uint8_t, _TWDR, 0xBB); + __AVR_DEFREG(TWCR_reg_t, _TWCR, 0xBC); + __AVR_DEFREG(TWAMR_reg_t, _TWAMR, 0xBD); + __AVR_DEFREG(USART_dev_t, USART0, 0xC0); + +#elif defined(__AVR_TRM04__) + __AVR_DEFREG(PORT_dev_t, _PORTA, 0x20); + __AVR_DEFREG(PORT_dev_t, _PORTB, 0x23); + __AVR_DEFREG(PORT_dev_t, _PORTC, 0x26); + __AVR_DEFREG(PORT_dev_t, _PORTD, 0x29); + __AVR_DEFREG(PORT_dev_t, _PORTE, 0x2C); + __AVR_DEFREG(PORT_dev_t, _PORTF, 0x2F); + __AVR_DEFREG(TIFR0_reg_t, _TIFR0, 0x35); + __AVR_DEFREG(TIFR1_reg_t, _TIFR1, 0x36); + __AVR_DEFREG(TIFR2_reg_t, _TIFR2, 0x37); + __AVR_DEFREG(TIFR3_reg_t, _TIFR3, 0x38); + __AVR_DEFREG(PCIFR_reg_t, _PCIFR, 0x3B); + __AVR_DEFREG(EIFR_reg_t, _EIFR, 0x3C); + __AVR_DEFREG(EIMSK_reg_t, _EIMSK, 0x3D); + __AVR_DEFREG(_bit_reg_t, _GPIOR0, 0x3E); + __AVR_DEFREG(EECR_reg_t, _EECR, 0x3F); + __AVR_DEFREG(uint8_t, _EEDR, 0x40); + __AVR_DEFREG(EEAR_reg_t, _EEAR, 0x41); + __AVR_DEFREG(GTCCR_reg_t, _GTCCR, 0x43); + __AVR_DEFREG(TIMER_8bit_dev_t, TIMER0, 0x44); + __AVR_DEFREG(PLLCSR_reg_t, _PLLCSR, 0x49); + __AVR_DEFREG(_bit_reg_t, _GPIOR1, 0x4A); + __AVR_DEFREG(_bit_reg_t, _GPIOR2, 0x4B); + __AVR_DEFREG(SPCR_reg_t, _SPCR, 0x4C); + __AVR_DEFREG(SPSR_reg_t, _SPSR, 0x4D); + __AVR_DEFREG(uint8_t, _SPDR, 0x4E); + __AVR_DEFREG(ACSR_reg_t, _ACSR, 0x50); + __AVR_DEFREG(uint8_t, _OCDR, 0x51); + __AVR_DEFREG(SMCR_reg_t, _SMCR, 0x53); + __AVR_DEFREG(MCUSR_reg_t, _MCUSR, 0x54); + __AVR_DEFREG(MCUCR_reg_t, _MCUCR, 0x55); + __AVR_DEFREG(SPMCSR_reg_t, _SPMCSR, 0x57); + __AVR_DEFREG(RAMPZ_reg_t, _RAMPZ, 0x5B); + __AVR_DEFREG(SP_reg_t, _SP, 0x5D); + __AVR_DEFREG(SREG_reg_t, _SREG, 0x5F); + __AVR_DEFREG(WDTCSR_reg_t, _WDTCSR, 0x60); + __AVR_DEFREG(CLKPR_reg_t, _CLKPR, 0x61); + __AVR_DEFREG(PRR0_reg_t, _PRR0, 0x64); + __AVR_DEFREG(PRR1_reg_t, _PRR1, 0x65); + __AVR_DEFREG(uint8_t, _OSCCAL, 0x66); + __AVR_DEFREG(PCICR_reg_t, _PCICR, 0x68); + __AVR_DEFREG(EICRA_reg_t, _EICRA, 0x69); + __AVR_DEFREG(EICRB_reg_t, _EICRB, 0x6A); + __AVR_DEFREG(_bit_reg_t, _PCMSK0, 0x6B); + __AVR_DEFREG(TIMSK0_reg_t, _TIMSK0, 0x6E); + __AVR_DEFREG(TIMSK1_reg_t, _TIMSK1, 0x6F); + __AVR_DEFREG(TIMSK2_reg_t, _TIMSK2, 0x70); + __AVR_DEFREG(TIMSK3_reg_t, _TIMSK3, 0x71); + __AVR_DEFREG(XMCRA_reg_t, _XMCRA, 0x74); + __AVR_DEFREG(XMCRB_reg_t, _XMCRB, 0x75); + __AVR_DEFREG(uint16_t, _ADC, 0x78); + __AVR_DEFREG(ADCSRA_reg_t, _ADCSRA, 0x7A); + __AVR_DEFREG(ADCSRB_reg_t, _ADCSRB, 0x7B); + __AVR_DEFREG(ADMUX_reg_t, _ADMUX, 0x7C); + __AVR_DEFREG(DIDR0_reg_t, _DIDR0, 0x7E); + __AVR_DEFREG(DIDR1_reg_t, _DIDR1, 0x7F); + __AVR_DEFREG(TIMER_dev_t, TIMER1, 0x80); + __AVR_DEFREG(TIMER_dev_t, TIMER3, 0x90); + __AVR_DEFREG(UHCON_reg_t, _UHCON, 0x9E); + __AVR_DEFREG(UHINT_reg_t, _UHINT, 0x9F); + __AVR_DEFREG(UHIEN_reg_t, _UHIEN, 0xA0); + __AVR_DEFREG(UHADDR_reg_t, _UHADDR, 0xA1); + __AVR_DEFREG(UHFNUM_reg_t, _UHFNUM, 0xA2); + __AVR_DEFREG(uint8_t, _UHFLEN, 0xA4); + __AVR_DEFREG(uint8_t, _UPINRQX, 0xA5); + __AVR_DEFREG(UPINTX_reg_t, _UPINTX, 0xA6); + __AVR_DEFREG(UPNUM_reg_t, _UPNUM, 0xA7); + __AVR_DEFREG(UPRST_reg_t, _UPRST, 0xA8); + __AVR_DEFREG(UPCONX_reg_t, _UPCONX, 0xA9); + _AVR_DEFREG(UPCFG0X, 0xAA); + _AVR_DEFREG(UPCFG1X, 0xAB); + _AVR_DEFREG(UPSTAX, 0xAC); + __AVR_DEFREG(uint8_t, _UPCFG2X, 0xAD); + _AVR_DEFREG(UPIENX, 0xAE); + __AVR_DEFREG(uint8_t, _UPDATX, 0xAF); + __AVR_DEFREG(TIMER_8bit_dev_t, _TIMER2, 0xB0); + __AVR_DEFREG(ASSR_reg_t, _ASSR, 0xB6); + __AVR_DEFREG(uint8_t, _TWBR, 0xB8); + __AVR_DEFREG(TWSR_reg_t, _TWSR, 0xB9); + __AVR_DEFREG(TWAR_reg_t, _TWAR, 0xBA); + __AVR_DEFREG(uint8_t, _TWDR, 0xBB); + __AVR_DEFREG(TWCR_reg_t, _TWCR, 0xBC); + __AVR_DEFREG(TWAMR_reg_t, _TWAMR, 0xBD); + __AVR_DEFREG(USART_dev_t, USART1, 0xC8); + _AVR_DEFREG(UHWCON, 0xD7); + _AVR_DEFREG(USBCON, 0xD8); + _AVR_DEFREG(USBSTA, 0xD9); + _AVR_DEFREG(USBINT, 0xDA); + _AVR_DEFREG(UDPADD, 0xDB); + _AVR_DEFREG(OTGCON, 0xDD); + _AVR_DEFREG(OTGIEN, 0xDE); + _AVR_DEFREG(OTGINT, 0xDF); + _AVR_DEFREG(UDCON, 0xE0); + _AVR_DEFREG(UDINT, 0xE1); + _AVR_DEFREG(UDIEN, 0xE2); + _AVR_DEFREG(UDADDR, 0xE3); + _AVR_DEFREG(UDFNUM, 0xE4); + _AVR_DEFREG(UDMFN, 0xE6); + _AVR_DEFREG(UDTST, 0xE7); + _AVR_DEFREG(UEINTX, 0xE8); + _AVR_DEFREG(UENUM, 0xE9); + _AVR_DEFREG(UERST, 0xEA); + _AVR_DEFREG(UECONX, 0xEB); + _AVR_DEFREG(UECFG0X, 0xEC); + _AVR_DEFREG(UECFG1X, 0xED); + _AVR_DEFREG(UESTA0X, 0xEE); + _AVR_DEFREG(UESTA1X, 0xEF); + _AVR_DEFREG(UEIENX, 0xF0); + __AVR_DEFREG(uint8_t, _UEDATx, 0xF1); + _AVR_DEFREG(UEBCX, 0xF2); + _AVR_DEFREG(UEINT, 0xF4); + _AVR_DEFREG(UPERRX, 0xF5); + _AVR_DEFREG(UPBCX, 0xF6); + __AVR_DEFREG(uint8_t, _UPINT, 0xF8); + _AVR_DEFREG(OTGTCON, 0xF9); +#elif defined(__AVR_TRM05__) + // page 476ff. of ATmega164P-324P-644P-Data-Sheet-40002071A.pdf + __AVR_DEFREG(PORT_dev_t, _PORTA, 0x20); + __AVR_DEFREG(PORT_dev_t, _PORTB, 0x23); + __AVR_DEFREG(PORT_dev_t, _PORTC, 0x26); + __AVR_DEFREG(PORT_dev_t, _PORTD, 0x29); + __AVR_DEFREG(TIFR0_reg_t, _TIFR0, 0x35); + __AVR_DEFREG(TIFR1_reg_t, _TIFR1, 0x36); + __AVR_DEFREG(TIFR2_reg_t, _TIFR2, 0x37); + __AVR_DEFREG(PCIFR_reg_t, _PCIFR, 0x3B); + __AVR_DEFREG(EIFR_reg_t, _EIFR, 0x3C); + __AVR_DEFREG(EIMSK_reg_t, _EIMSK, 0x3D); + __AVR_DEFREG(_bit_reg_t, _GPIOR0, 0x3E); + __AVR_DEFREG(EECR_reg_t, _EECR, 0x3F); + __AVR_DEFREG(uint8_t, _EEDR, 0x40); + __AVR_DEFREG(EEAR_reg_t, _EEAR, 0x41); + __AVR_DEFREG(GTCCR_reg_t, _GTCCR, 0x43); + __AVR_DEFREG(TIMER_8bit_dev_t, TIMER0, 0x44); + __AVR_DEFREG(_bit_reg_t, _GPIOR1, 0x4A); + __AVR_DEFREG(_bit_reg_t, _GPIOR2, 0x4B); + __AVR_DEFREG(SPCR_reg_t, _SPCR, 0x4C); + __AVR_DEFREG(SPSR_reg_t, _SPSR, 0x4D); + __AVR_DEFREG(uint8_t, _SPDR, 0x4E); + __AVR_DEFREG(ACSR_reg_t, _ACSR, 0x50); + __AVR_DEFREG(uint8_t, _OCDR, 0x51); + __AVR_DEFREG(SMCR_reg_t, _SMCR, 0x53); + __AVR_DEFREG(MCUSR_reg_t, _MCUSR, 0x54); + __AVR_DEFREG(MCUCR_reg_t, _MCUCR, 0x55); + __AVR_DEFREG(SPMCSR_reg_t, _SPMCSR, 0x57); + __AVR_DEFREG(RAMPZ_reg_t, _RAMPZ, 0x5B); + __AVR_DEFREG(SP_reg_t, _SP, 0x5D); + __AVR_DEFREG(SREG_reg_t, _SREG, 0x5F); + __AVR_DEFREG(WDTCSR_reg_t, _WDTCSR, 0x60); + __AVR_DEFREG(CLKPR_reg_t, _CLKPR, 0x61); + __AVR_DEFREG(PRR0_reg_t, _PRR0, 0x64); + __AVR_DEFREG(uint8_t, _OSCCAL, 0x66); + __AVR_DEFREG(PCICR_reg_t, _PCICR, 0x68); + __AVR_DEFREG(EICRA_reg_t, _EICRA, 0x69); + __AVR_DEFREG(_bit_reg_t, _PCMSK0, 0x6B); + __AVR_DEFREG(_bit_reg_t, _PCMSK1, 0x6C); + __AVR_DEFREG(_bit_reg_t, _PCMSK2, 0x6D); + __AVR_DEFREG(TIMSK0_reg_t, _TIMSK0, 0x6E); + __AVR_DEFREG(TIMSK1_reg_t, _TIMSK1, 0x6F); + __AVR_DEFREG(TIMSK2_reg_t, _TIMSK2, 0x70); + __AVR_DEFREG(_bit_reg_t, _PCMKS3, 0x73); + __AVR_DEFREG(uint16_t, _ADC, 0x78); + __AVR_DEFREG(ADCSRA_reg_t, _ADCSRA, 0x7A); + __AVR_DEFREG(ADCSRB_reg_t, _ADCSRB, 0x7B); + __AVR_DEFREG(ADMUX_reg_t, _ADMUX, 0x7C); + __AVR_DEFREG(DIDR0_reg_t, _DIDR0, 0x7E); + __AVR_DEFREG(DIDR1_reg_t, _DIDR1, 0x7F); + __AVR_DEFREG(TIMER_dev_t, TIMER1, 0x80); + __AVR_DEFREG(TIMER_8bit_dev_t, _TIMER2, 0xB0); + __AVR_DEFREG(ASSR_reg_t, _ASSR, 0xB6); + __AVR_DEFREG(uint8_t, _TWBR, 0xB8); + __AVR_DEFREG(TWSR_reg_t, _TWSR, 0xB8); + __AVR_DEFREG(TWAR_reg_t, _TWAR, 0xBA); + __AVR_DEFREG(uint8_t, _TWDR, 0xBB); + __AVR_DEFREG(TWCR_reg_t, _TWCR, 0xBC); + __AVR_DEFREG(TWAMR_reg_t, _TWAMR, 0xBD); + __AVR_DEFREG(USART_dev_t, USART0, 0xC0); + __AVR_DEFREG(USART_dev_t, USART1, 0xC8); +#endif + +inline void _ATmega_resetperipherals() { + using namespace AVRHelpers; + + // Due to BOOTLOADER or other board inconsistencies we could get launched into Marlin FW + // with configuration that does not match the reset state in the documentation. That is why + // we should clean-reset the entire device. + #if defined(__AVR_TRM01__) || defined(__AVR_TRM02__) || defined(__AVR_TRM03__) || defined(__AVR_TRM04__) || defined(__AVR_TRM05__) + SREG_reg_t __SREG; + __SREG._C = false; + __SREG._Z = false; + __SREG._N = false; + __SREG._V = false; + __SREG._S = false; + __SREG._H = false; + __SREG._T = false; + __SREG._I = false; + dwrite(_SREG, __SREG); + #endif + + #if defined(__AVR_TRM01__) || defined(__AVR_TRM04__) || defined(__AVR_TRM05__) + _RAMPZ._RAMPZ = 0; + #endif + #ifdef __AVR_TRM01__ + _EIND._EIND0 = false; + #endif + + #if defined(__AVR_TRM01__) || defined(__AVR_TRM02__) || defined(__AVR_TRM03__) || defined(__AVR_TRM05__) + _EEAR._EEAR = 0; + dwrite(_EEDR, (uint8_t)0u); + #endif + + #if defined(__AVR_TRM01__) || defined(__AVR_TRM02__) || defined(__AVR_TRM03__) || defined(__AVR_TRM04__) || defined(__AVR_TRM05__) + EECR_reg_t __EECR; + __EECR._EERE = false; + __EECR._EEPE = false; + __EECR._EEMPE = false; + __EECR._EERIE = false; + __EECR._EEPM0 = 0; + __EECR._EEPM1 = 0; + __EECR.reserved1 = 0; + dwrite(_EECR, __EECR); + #endif + + #if defined(__AVR_TRM01__) || defined(__AVR_TRM02__) || defined(__AVR_TRM03__) || defined(__AVR_TRM04__) || defined(__AVR_TRM05__) + _GPIOR2.val = 0; + _GPIOR1.val = 0; + _GPIOR0.val = 0; + #endif + + #if defined(__AVR_TRM01__) || defined(__AVR_TRM04__) + XMCRA_reg_t __XMCRA; + __XMCRA._SRW0 = 0; + __XMCRA._SRW1 = 0; + __XMCRA._SRL = 0; + __XMCRA._SRE = 0; + dwrite(_XMCRA, __XMCRA); + + XMCRB_reg_t __XMCRB; + __XMCRB._XMM = 0; + __XMCRB.reserved1 = 0; + __XMCRB._XMBK = false; + dwrite(_XMCRB, __XMCRB); + #endif + + #if defined(__AVR_TRM01__) || defined(__AVR_TRM02__) || defined(__AVR_TRM03__) || defined(__AVR_TRM04__) || defined(__AVR_TRM05__) + SMCR_reg_t __SMCR; + __SMCR._SE = false; + __SMCR._SM = 0; + __SMCR.reserved1 = 0; + dwrite(_SMCR, __SMCR); + #endif + + #if defined(__AVR_TRM01__) || defined(__AVR_TRM02__) || defined(__AVR_TRM03__) || defined(__AVR_TRM04__) || defined(__AVR_TRM05__) + PRR0_reg_t __PRR0; + #if defined(__AVR_TRM01__) || defined(__AVR_TRM03__) + __PRR0._PRADC = false; + __PRR0._PRUSART0 = false; + __PRR0._PRSPI = false; + __PRR0._PRTIM1 = false; + __PRR0.reserved1 = false; + __PRR0._PRTIM0 = false; + __PRR0._PRTIM2 = false; + __PRR0._PRTWI = false; + #elif defined(__AVR_TRM02__) + __PRR0._PRADC = false; + __PRR0._PRUSART0 = false; + __PRR0._PRSPI = false; + __PRR0._PRTIM1 = false; + __PRR0._PRUSART1 = false; + __PRR0._PRTIM0 = false; + __PRR0._PRTIM2 = false; + __PRR0._PRTWI = false; + #elif defined(__AVR_TRM04__) + __PRR0._PRADC = false; + __PRR0.reserved1 = false; + __PRR0._PRSPI = false; + __PRR0._PRTIM1 = false; + __PRR0.reserved2 = false; + __PRR0._PRTIM0 = false; + __PRR0._PRTIM2 = false; + __PRR0._PRTWI = false; + #endif + dwrite(_PRR0, __PRR0); + #endif + + #if defined(__AVR_TRM01__) || defined(__AVR_TRM02__) || defined(__AVR_TRM04__) + PRR1_reg_t __PRR1; + #ifdef __AVR_TRM01__ + __PRR1._PRUSART1 = false; + __PRR1._PRUSART2 = false; + __PRR1._PRUSART3 = false; + __PRR1._PRTIM3 = false; + __PRR1._PRTIM4 = false; + __PRR1._PRTIM5 = false; + __PRR1.reserved1 = 0; + #elif defined(__AVR_TRM02__) + __PRR1._PRTIM3 = false; + __PRR1.reserved1 = 0; + #elif defined(__AVR_TRM04__) + __PRR1._PRUSART1 = false; + __PRR1.reserved1 = 0; + #endif + dwrite(_PRR1, __PRR1); + #endif + + #if defined(__AVR_TRM01__) || defined(__AVR_TRM02__) || defined(__AVR_TRM03__) || defined(__AVR_TRM04__) || defined(__AVR_TRM05__) + WDTCSR_reg_t __WDTCSR; + __WDTCSR._WDP0 = 0; + __WDTCSR._WDP1 = 0; + __WDTCSR._WDP2 = 0; + __WDTCSR._WDE = false; + __WDTCSR._WDCE = false; + __WDTCSR._WDP3 = 0; + __WDTCSR._WDIE = false; + __WDTCSR._WDIF = false; + dwrite(_WDTCSR, __WDTCSR); + #endif + + #if defined(__AVR_TRM01__) || defined(__AVR_TRM02__) || defined(__AVR_TRM03__) || defined(__AVR_TRM04__) || defined(__AVR_TRM05__) + _MCUCR._PUD = false; + #endif + + #if defined(__AVR_TRM01__) || defined(__AVR_TRM02__) || defined(__AVR_TRM03__) || defined(__AVR_TRM04__) || defined(__AVR_TRM05__) + PORT_dev_t __PORT; + __PORT._PIN.val = 0; + __PORT._DDR.val = 0; + __PORT._PORT.val = 0; + #endif + + #if defined(__AVR_TRM01__) || defined(__AVR_TRM02__) || defined(__AVR_TRM04__) || defined(__AVR_TRM05__) + dwrite(_PORTA, __PORT); + dwrite(_PORTC, __PORT); + #endif + #if defined(__AVR_TRM01__) || defined(__AVR_TRM02__) || defined(__AVR_TRM03__) || defined(__AVR_TRM04__) || defined(__AVR_TRM05__) + dwrite(_PORTB, __PORT); + dwrite(_PORTD, __PORT); + #endif + #if defined(__AVR_TRM01__) || defined(__AVR_TRM04__) + dwrite(_PORTE, __PORT); + dwrite(_PORTF, __PORT); + #endif + + #ifdef __AVR_TRM01__ + PORTG_dev_t __PORTG; + __PORTG._PIN.val = 0; + __PORTG._PIN.reserved1 = 0; + __PORTG._DDR.val = 0; + __PORTG._DDR.reserved1 = 0; + __PORTG._PORT.val = 0; + __PORTG._PORT.reserved1 = 0; + dwrite(_PORTG, __PORTG); + #endif + + #ifdef __AVR_TRM03__ + PORTC_dev_t __PORTC; + __PORTC._PIN.val = 0; + __PORTC._PIN.reserved1 = 0; + __PORTC._DDR.val = 0; + __PORTC._DDR.reserved1 = 0; + __PORTC._PORT.val = 0; + __PORTC._PORT.reserved1 = 0; + dwrite(_PORTC, __PORTC); + #endif + + #ifdef __AVR_TRM01__ + dwrite(_PORTH, __PORT); + dwrite(_PORTJ, __PORT); + dwrite(_PORTK, __PORT); + dwrite(_PORTL, __PORT); + #endif + + #if defined(__AVR_TRM01__) || defined(__AVR_TRM02__) || defined(__AVR_TRM03__) || defined(__AVR_TRM04__) || defined(__AVR_TRM05__) + EICRA_reg_t __EICRA; + #if defined(__AVR_TRM01__) || defined(__AVR_TRM04__) + __EICRA._ISC0 = 0; + __EICRA._ISC1 = 0; + __EICRA._ISC2 = 0; + __EICRA._ISC3 = 0; + #elif defined(__AVR_TRM02__) || defined(__AVR_TRM05__) + __EICRA._ISC0 = 0; + __EICRA._ISC1 = 0; + __EICRA._ISC2 = 0; + __EICRA.reserved1 = 0; + #elif defined(__AVR_TRM03__) + __EICRA._ISC0 = 0; + __EICRA._ISC1 = 0; + __EICRA.reserved1 = 0; + #endif + dwrite(_EICRA, __EICRA); + #endif + + #if defined(__AVR_TRM01__) || defined(__AVR_TRM04__) + EICRB_reg_t __EICRB; + __EICRB._ISC4 = 0; + __EICRB._ISC5 = 0; + __EICRB._ISC6 = 0; + __EICRB._ISC7 = 0; + dwrite(_EICRB, __EICRB); + #endif + + #if defined(__AVR_TRM01__) || defined(__AVR_TRM02__) || defined(__AVR_TRM03__) || defined(__AVR_TRM04__) || defined(__AVR_TRM05__) + EIMSK_reg_t __EIMSK; + #if defined(__AVR_TRM01__) || defined(__AVR_TRM04__) + __EIMSK._INT0 = false; + __EIMSK._INT1 = false; + __EIMSK._INT2 = false; + __EIMSK._INT3 = false; + __EIMSK._INT4 = false; + __EIMSK._INT5 = false; + __EIMSK._INT6 = false; + __EIMSK._INT7 = false; + #elif defined(__AVR_TRM02__) || defined(__AVR_TRM05__) + __EIMSK._INT0 = false; + __EIMSK._INT1 = false; + __EIMSK._INT2 = false; + __EIMSK.reserved1 = 0; + #elif defined(__AVR_TRM03__) + __EIMSK._INT0 = false; + __EIMSK._INT1 = false; + __EIMSK.reserved1 = 0; + #endif + dwrite(_EIMSK, __EIMSK); + #endif + + #if defined(__AVR_TRM01__) || defined(__AVR_TRM02__) || defined(__AVR_TRM03__) || defined(__AVR_TRM04__) || defined(__AVR_TRM05__) + EIFR_reg_t __EIFR; + #if defined(__AVR_TRM01__) || defined(__AVR_TRM04__) + __EIFR._INTF0 = false; + __EIFR._INTF1 = false; + __EIFR._INTF2 = false; + __EIFR._INTF3 = false; + __EIFR._INTF4 = false; + __EIFR._INTF5 = false; + __EIFR._INTF6 = false; + __EIFR._INTF7 = false; + #elif defined(__AVR_TRM02__) || defined(__AVR_TRM05__) + __EIFR._INTF0 = false; + __EIFR._INTF1 = false; + __EIFR._INTF2 = false; + __EIFR.reserved1 = 0; + #elif defined(__AVR_TRM03__) + __EIFR._INTF0 = false; + __EIFR._INTF1 = false; + __EIFR.reserved1 = 0; + #endif + dwrite(_EIFR, __EIFR); + #endif + + #if defined(__AVR_TRM01__) || defined(__AVR_TRM02__) || defined(__AVR_TRM03__) || defined(__AVR_TRM04__) || defined(__AVR_TRM05__) + PCICR_reg_t __PCICR; + #if defined(__AVR_TRM01__) || defined(__AVR_TRM03__) + __PCICR._PCIE0 = false; + __PCICR._PCIE1 = false; + __PCICR._PCIE2 = false; + __PCICR.reserved1 = 0; + #elif defined(__AVR_TRM02__) || defined(__AVR_TRM05__) + __PCICR._PCIE0 = false; + __PCICR._PCIE1 = false; + __PCICR._PCIE2 = false; + __PCICR._PCIE3 = false; + __PCICR.reserved1 = 0; + #elif defined(__AVR_TRM04__) + __PCICR._PCIE0 = false; + __PCICR.reserved1 = 0; + #endif + dwrite(_PCICR, __PCICR); + #endif + + #if defined(__AVR_TRM01__) || defined(__AVR_TRM02__) || defined(__AVR_TRM03__) || defined(__AVR_TRM04__) || defined(__AVR_TRM05__) + PCIFR_reg_t __PCIFR; + #if defined(__AVR_TRM01__) || defined(__AVR_TRM03__) + __PCIFR._PCIF0 = false; + __PCIFR._PCIF1 = false; + __PCIFR._PCIF2 = false; + __PCIFR.reserved1 = 0; + #elif defined(__AVR_TRM02__) || defined(__AVR_TRM05__) + __PCIFR._PCIF0 = false; + __PCIFR._PCIF1 = false; + __PCIFR._PCIF2 = false; + __PCIFR._PCIF3 = false; + __PCIFR.reserved1 = 0; + #elif defined(__AVR_TRM04__) + __PCIFR._PCIF0 = false; + __PCIFR.reserved1 = 0; + #endif + dwrite(_PCIFR, __PCIFR); + #endif + + #if defined(__AVR_TRM01__) || defined(__AVR_TRM02__) || defined(__AVR_TRM03__) || defined(__AVR_TRM04__) || defined(__AVR_TRM05__) + _PCMSK0.val = 0; + #endif + #if defined(__AVR_TRM01__) || defined(__AVR_TRM02__) || defined(__AVR_TRM03__) || defined(__AVR_TRM05__) + _PCMSK1.val = 0; + _PCMSK2.val = 0; + #endif + #if defined(__AVR_TRM03__) + _PCMSK1.reserved1 = 0; + #endif + #if defined(__AVR_TRM02__) + _PCMSK3.val = 0; + #endif + + #if defined(__AVR_TRM01__) || defined(__AVR_TRM02__) || defined(__AVR_TRM03__) || defined(__AVR_TRM04__) || defined(__AVR_TRM05__) + TIMER_8bit_dev_t __TIMER_8bit; + __TIMER_8bit._TCCRnA._WGMn0 = 0; + __TIMER_8bit._TCCRnA._WGMn1 = 0; + __TIMER_8bit._TCCRnA.reserved1 = 0; + __TIMER_8bit._TCCRnA._COMnB = 0; + __TIMER_8bit._TCCRnA._COMnA = 0; + __TIMER_8bit._TCCRnB._CSn = 0; + __TIMER_8bit._TCCRnB._WGMn2 = 0; + __TIMER_8bit._TCCRnB.reserved1 = 0; + __TIMER_8bit._TCCRnB._FOCnB = false; + __TIMER_8bit._TCCRnB._FOCnA = false, + __TIMER_8bit._TCNTn = 0; + __TIMER_8bit._OCRnA = 0; + __TIMER_8bit._OCRnB = 0; + dwrite(TIMER0, __TIMER_8bit); + #endif + + #if defined(__AVR_TRM01__) || defined(__AVR_TRM02__) || defined(__AVR_TRM03__) || defined(__AVR_TRM04__) || defined(__AVR_TRM05__) + TIMSK0_reg_t __TIMSK0; + __TIMSK0._TOIE0 = false; + __TIMSK0._OCIE0A = false; + __TIMSK0._OCIE0B = false; + __TIMSK0.reserved1 = 0; + dwrite(_TIMSK0, __TIMSK0); + + TIFR0_reg_t __TIFR0; + __TIFR0._TOV0 = false; + __TIFR0._OCF0A = false; + __TIFR0._OCF0B = false; + __TIFR0.reserved1 = 0; + dwrite(_TIFR0, __TIFR0); + #endif + + #if defined(__AVR_TRM01__) || defined(__AVR_TRM02__) || defined(__AVR_TRM03__) || defined(__AVR_TRM04__) || defined(__AVR_TRM05__) + TIMER_dev_t TIMER; + TIMER._TCCRnA._WGMn0 = 0; + TIMER._TCCRnA._WGMn1 = 0; + #if defined(__AVR_TRM01__) || defined(__AVR_TRM04__) + TIMER._TCCRnA._COMnC = 0; + #endif + TIMER._TCCRnA._COMnB = 0; + TIMER._TCCRnA._COMnA = 0; + TIMER._TCCRnB._CSn = 0; + TIMER._TCCRnB._WGMn2 = 0; + TIMER._TCCRnB.reserved1 = 0; + TIMER._TCCRnB._ICESn = 0; + TIMER._TCCRnB._ICNCn = 0; + TIMER._TCCRnC.reserved1 = 0; + #if defined(__AVR_TRM01__) || defined(__AVR_TRM04__) + TIMER._TCCRnC._FOCnC = false; + #endif + TIMER._TCCRnC._FOCnB = false; + TIMER._TCCRnC._FOCnA = false; + TIMER._TCNTn = 0; + TIMER._OCRnA = 0; + TIMER._OCRnB = 0; + #if defined(__AVR_TRM01__) || defined(__AVR_TRM04__) + TIMER._OCRnC = 0; + #endif + TIMER._ICRn = 0; + dwrite(TIMER1, TIMER); + #endif + #if defined(__AVR_TRM01__) || defined(__AVR_TRM02__) || defined(__AVR_TRM04__) + dwrite(TIMER3, TIMER); + #endif + #ifdef __AVR_TRM01__ + dwrite(TIMER4, TIMER); + dwrite(TIMER5, TIMER); + #endif + + #if defined(__AVR_TRM01__) || defined(__AVR_TRM02__) || defined(__AVR_TRM03__) || defined(__AVR_TRM04__) || defined(__AVR_TRM05__) + TIMSK1_reg_t __TIMSK1; + __TIMSK1._TOIE1 = false; + __TIMSK1._OCIE1A = false; + __TIMSK1._OCIE1B = false; + #if defined(__AVR_TRM01__) || defined(__AVR_TRM04__) + __TIMSK1._OCIE1C = false; + #endif + __TIMSK1.reserved1 = 0; + __TIMSK1._ICIE1 = false; + __TIMSK1.reserved2 = 0; + dwrite(_TIMSK1, __TIMSK1); + #endif + + #if defined(__AVR_TRM01__) || defined(__AVR_TRM02__) || defined(__AVR_TRM04__) + TIMSK3_reg_t __TIMSK3; + __TIMSK3._TOIE3 = false; + __TIMSK3._OCIE3A = false; + __TIMSK3._OCIE3B = false; + #if defined(__AVR_TRM01__) || defined(__AVR_TRM04__) + __TIMSK3._OCIE3C = false; + #endif + __TIMSK3.reserved1 = 0; + __TIMSK3._ICIE3 = false; + __TIMSK3.reserved2 = 0; + dwrite(_TIMSK3, __TIMSK3); + #endif + + #ifdef __AVR_TRM01__ + TIMSK4_reg_t __TIMSK4; + __TIMSK4._TOIE4 = false; + __TIMSK4._OCIE4A = false; + __TIMSK4._OCIE4B = false; + __TIMSK4._OCIE4C = false; + __TIMSK4.reserved1 = false; + __TIMSK4._ICIE4 = false; + __TIMSK4.reserved2 = false; + dwrite(_TIMSK4, __TIMSK4); + + TIMSK5_reg_t __TIMSK5; + __TIMSK5._TOIE5 = false; + __TIMSK5._OCIE5A = false; + __TIMSK5._OCIE5B = false; + __TIMSK5._OCIE5C = false; + __TIMSK5.reserved1 = 0; + __TIMSK5._ICIE5 = false; + __TIMSK5.reserved2 = 0; + dwrite(_TIMSK5, __TIMSK5); + #endif + + #if defined(__AVR_TRM01__) || defined(__AVR_TRM02__) || defined(__AVR_TRM03__) || defined(__AVR_TRM04__) || defined(__AVR_TRM05__) + TIFR1_reg_t __TIFR1; + __TIFR1._TOV1 = false; + __TIFR1._OCF1A = false; + __TIFR1._OCF1B = false; + #if defined(__AVR_TRM01__) || defined(__AVR_TRM04__) + __TIFR1._OCF1C = false; + #endif + __TIFR1.reserved1 = 0; + __TIFR1._ICF1 = false; + __TIFR1.reserved2 = 0; + dwrite(_TIFR1, __TIFR1); + #endif + + #if defined(__AVR_TRM01__) || defined(__AVR_TRM02__) || defined(__AVR_TRM04__) + TIFR3_reg_t __TIFR3; + __TIFR3._TOV3 = false; + __TIFR3._OCF3A = false; + __TIFR3._OCF3B = false; + #if defined(__AVR_TRM01__) || defined(__AVR_TRM04__) + __TIFR3._OCF3C = false; + #endif + __TIFR3.reserved1 = 0; + __TIFR3._ICF3 = false; + __TIFR3.reserved2 = 0; + dwrite(_TIFR3, __TIFR3); + #endif + + #ifdef __AVR_TRM01__ + TIFR4_reg_t __TIFR4; + __TIFR4._TOV4 = false; + __TIFR4._OCF4A = false; + __TIFR4._OCF4B = false; + __TIFR4._OCF4C = false; + __TIFR4.reserved1 = 0; + __TIFR4._ICF4 = false; + __TIFR4.reserved2 = 0; + dwrite(_TIFR4, __TIFR4); + + TIFR5_reg_t __TIFR5; + __TIFR5._TOV5 = false; + __TIFR5._OCF5A = false; + __TIFR5._OCF5B = false; + __TIFR5._OCF5C = false; + __TIFR5.reserved1 = 0; + __TIFR5._ICF5 = false; + __TIFR5.reserved2 = 0; + dwrite(_TIFR5, __TIFR5); + #endif + + #if defined(__AVR_TRM01__) || defined(__AVR_TRM02__) || defined(__AVR_TRM03__) || defined(__AVR_TRM04__) || defined(__AVR_TRM05__) + dwrite(_TIMER2, __TIMER_8bit); + #endif + + #if defined(__AV_TRM01__) || defined(__AVR_TRM02__) || defined(__AVR_TRM03__) || defined(__AVR_TRM04__) || defined(__AVR_TRM05__) + ASSR_reg_t __ASSR; + __ASSR._TCR2BUB = false; + __ASSR._TCR2AUB = false; + __ASSR._OCR2BUB = false; + __ASSR._OCR2AUB = false; + __ASSR._TCN2UB = false; + __ASSR._AS2 = false; + __ASSR._EXCLK = false; + __ASSR.reserved1 = 0; + dwrite(_ASSR, __ASSR); + #endif + + #if defined(__AVR_TRM01__) || defined(__AVR_TRM02__) || defined(__AVR_TRM03__) || defined(__AVR_TRM04__) || defined(__AVR_TRM05__) + TIMSK2_reg_t __TIMSK2; + __TIMSK2._TOIE2 = false; + __TIMSK2._OCIE2A = false; + __TIMSK2._OCIE2B = false; + __TIMSK2.reserved1 = 0; + dwrite(_TIMSK2, __TIMSK2); + + TIFR2_reg_t __TIFR2; + __TIFR2._TOV2 = false; + __TIFR2._OCF2A = false; + __TIFR2._OCF2B = false; + __TIFR2.reserved1 = 0; + dwrite(_TIFR2, __TIFR2); + #endif + + #if defined(__AVR_TRM01__) || defined(__AVR_TRM02__) || defined(__AVR_TRM03__) || defined(__AVR_TRM04__) || defined(__AVR_TRM05__) + SPCR_reg_t __SPCR; + __SPCR._SPR = 0; + __SPCR._CPHA = 0; + __SPCR._CPOL = 0; + __SPCR._MSTR = 0; + __SPCR._DORD = 0; + __SPCR._SPE = false; + __SPCR._SPIE = false; + dwrite(_SPCR, __SPCR); + + SPSR_reg_t __SPSR; + __SPSR._SPI2X = false; + __SPSR.reserved1 = 0; + __SPSR._WCOL = false; + __SPSR._SPIF = false; + dwrite(_SPSR, __SPSR); + #endif + + #if defined(__AVR_TRM01__) || defined(__AVR_TRM02__) || defined(__AVR_TRM03__) || defined(__AVR_TRM04__) || defined(__AVR_TRM05__) + USART_dev_t USART; + USART._UDRn = 0; + USART._UCSRnA._MPCM = false; + USART._UCSRnA._U2X = false; + USART._UCSRnA._UPE = false; + USART._UCSRnA._DOR = false; + USART._UCSRnA._FE = false; + USART._UCSRnA._UDRE = true; + USART._UCSRnA._TXC = false; + USART._UCSRnA._RXC = false; + USART._UCSRnB._TXB8 = false; + USART._UCSRnB._RXB8 = false; + USART._UCSRnB._UCSZn2 = false; + USART._UCSRnB._TXEN = false; + USART._UCSRnB._RXEN = false; + USART._UCSRnB._UDRIE = false; + USART._UCSRnB._TXCIE = false; + USART._UCSRnB._RXCIE = false; + USART._UCSRnC._UCPOL = false; + #if defined(__AVR_TRM01__) || defined(__AVR_TRM02__) || defined(__AVR_TRM03__) || defined(__AVR_TRM04__) + USART._UCSRnC._UCSZn0 = 1; + USART._UCSRnC._UCSZn1 = 1; + USART._UCSRnC._USBS = false; + USART._UCSRnC._UPM = 0; + USART._UCSRnC._UPM = 0; + USART._UCSRnC._UMSEL = 0; + #elif defined(__AVR_TRM05__) + USART._UCSRnC._UCPOL = 0; + USART._UCSRnC._UCPHA = 0; + USART._UCSRnC._UDORD = 0; + USART._UCSRnC.reserved1 = 0; + USART._UCSRnC._UMSEL = 0; + #endif + USART._UBRRn._UBRR = 0; + USART._UBRRn.reserved1 = 0; + #endif + #if defined(__AVR_TRM01__) || defined(__AVR_TRM02__) || defined(__AVR_TRM03__) || defined(__AVR_TRM05__) + dwrite(USART0, USART); + #endif + #if defined(__AVR_TRM01__) || defined(__AVR_TRM02__) || defined(__AVR_TRM04__) || defined(__AVR_TRM05__) + dwrite(USART1, USART); + #endif + #ifdef __AVR_TRM01__ + dwrite(USART2, USART); + dwrite(USART3, USART); + #endif + + #if defined(__AVR_TRM01__) || defined(__AVR_TRM02__) || defined(__AVR_TRM03__) || defined(__AVR_TRM04__) || defined(__AVR_TRM05__) + dwrite(_TWBR, (uint8_t)0); + + TWCR_reg_t __TWCR; + __TWCR._TWIE = false; + __TWCR.reserved1 = 0; + __TWCR._TWEN = false; + __TWCR._TWWC = false; + __TWCR._TWSTO = false; + __TWCR._TWSTA = false; + __TWCR._TWEA = false; + __TWCR._TWINT = false; + dwrite(_TWCR, __TWCR); + + TWSR_reg_t __TWSR; + __TWSR._TWPS0 = false; + __TWSR._TWPS1 = false; + __TWSR.reserved1 = 0; + __TWSR._TWS3 = 1; + __TWSR._TWS4 = 1; + __TWSR._TWS5 = 1; + __TWSR._TWS6 = 1; + __TWSR._TWS7 = 1; + dwrite(_TWSR, __TWSR); + + dwrite(_TWDR, (uint8_t)0xFF); + + TWAR_reg_t __TWAR; + __TWAR._TWGCE = false; + __TWAR._TWA = 0x7F; + dwrite(_TWAR, __TWAR); + + TWAMR_reg_t __TWAMR; + __TWAMR.reserved1 = false; + __TWAMR._TWAM = 0; + dwrite(_TWAMR, __TWAMR); + #endif + + #if defined(__AVR_TRM01__) || defined(__AVR_TRM02__) || defined(__AVR_TRM03__) || defined(__AVR_TRM04__) || defined(__AVR_TRM05__) + ADCSRB_reg_t __ADCSRB; + __ADCSRB._ADTS = 0; + #ifdef __AVR_TRM01__ + __ADCSRB._MUX5 = 0; + #endif + __ADCSRB.reserved1 = 0; + __ADCSRB._ACME = false; + __ADCSRB.reserved2 = 0; + dwrite(_ADCSRB, __ADCSRB); + + ACSR_reg_t __ACSR; + __ACSR._ACIS = 0; + __ACSR._ACIC = false; + __ACSR._ACIE = false; + __ACSR._ACI = false; + __ACSR._ACO = false; + __ACSR._ACBG = false; + __ACSR._ACD = false; + dwrite(_ACSR, __ACSR); + #endif + + #if defined(__AVR_TRM01__) || defined(__AVR_TRM02__) || defined(__AVR_TRM03__) || defined(__AVR_TRM04__) || defined(__AVR_TRM05__) + DIDR1_reg_t __DIDR1; + __DIDR1._AIN0D = false; + __DIDR1._AIN1D = false; + __DIDR1.reserved1 = false; + dwrite(_DIDR1, __DIDR1); + #endif + + #if defined(__AVR_TRM01__) || defined(__AVR_TRM02__) || defined(__AVR_TRM03__) || defined(__AVR_TRM04__) || defined(__AVR_TRM05__) + ADMUX_reg_t __ADMUX; + __ADMUX._MUX0 = 0; + __ADMUX._MUX1 = 0; + __ADMUX._MUX2 = 0; + __ADMUX._MUX3 = 0; + #if defined(__AVR_TRM01__) || defined(__AVR_TRM02__) || defined(__AVR_TRM04__) || defined(__AVR_TRM05__) + __ADMUX._MUX4 = 0; + #elif defined(__AVR_TRM03__) + __ADMUX.reserved1 = 0; + #endif + __ADMUX._ADLAR = 0; + __ADMUX._REFS0 = 0; + __ADMUX._REFS1 = 0; + dwrite(_ADMUX, __ADMUX); + + ADCSRA_reg_t __ADCSRA; + __ADCSRA._ADPS = 0; + __ADCSRA._ADIE = false; + __ADCSRA._ADIF = false; + __ADCSRA._ADATE = false; + __ADCSRA._ADSC = false; + __ADCSRA._ADEN = false; + dwrite(_ADCSRA, __ADCSRA); + + dwrite(_ADC, (uint16_t)0); + #endif + + #if defined(__AVR_TRM01__) || defined(__AVR_TRM02__) || defined(__AVR_TRM03__) || defined(__AVR_TRM04__) || defined(__AVR_TRM05__) + SPMCSR_reg_t __SPMCSR; + #if defined(__AVR_TRM01__) || defined(__AVR_TRM02__) || defined(__AVR_TRM04__) || defined(__AVR_TRM05__) + __SPMCSR._SPMEN = false; + __SPMCSR._PGERS = false; + __SPMCSR._PGWRT = false; + __SPMCSR._BLBSET = false; + __SPMCSR._RWWSRE = false; + __SPMCSR._SIGRD = false; + __SPMCSR._RWWSB = false; + __SPMCSR._SPMIE = false; + #elif defined(__AVR_TRM03__) + #if defined(__AVR_ATmega88A__) || defined(__AVR_ATmega88PA__) || defined(__AVR_ATmega168A__) || defined(__AVR_ATmega168PA__) || defined(__AVR_ATmega328P__) + __SPMCSR._SPMEN = false; + __SPMCSR._PGERS = false; + __SPMCSR._PGWRT = false; + __SPMCSR._BLBSET = false; + __SPMCSR._RWWSRE = false; + __SPMCSR._SIGRD = false; + __SPMCSR._RWWSB = false; + __SPMCSR._SPMIE = false; + #else + __SPMCSR._SPMEN = false; + __SPMCSR._PGERS = false; + __SPMCSR._PGWRT = false; + __SPMCSR._BLBSET = false; + __SPMCSR.reserved1 = false; + __SPMCSR._SIGRD = false; + __SPMCSR.reserved2 = false; + __SPMCSR._SPMIE = false; + #endif + #endif + dwrite(_SPMCSR, __SPMCSR); + #endif + + // TODO: add the __AVR_TRM04__ initializations, if required (mostly USB related) +} + +struct pin_dev_state_t { + #ifdef __AVR_TRM01__ + uint8_t _SRE : 1; // port A + uint8_t _COM0B : 2; + uint8_t _COM1A : 2; + uint8_t _COM1B : 2; + uint8_t _COM1C : 2; + uint8_t _COM2A : 2; + uint8_t _COM2B : 2; + uint8_t _COM3A : 2; + uint8_t _COM3B : 2; + uint8_t _COM3C : 2; + uint8_t _COM4A : 2; + uint8_t _COM4B : 2; + uint8_t _COM4C : 2; + uint8_t _COM5A : 2; + uint8_t _COM5B : 2; + uint8_t _COM5C : 2; + uint8_t _PCIE0 : 1; + uint8_t _PCIE1 : 1; // INTn + uint8_t _PCIE2 : 1; + uint8_t _SPE : 1; + uint8_t _USART0_RXEN : 1; + uint8_t _USART0_TXEN : 1; + uint8_t _USART1_RXEN : 1; + uint8_t _USART1_TXEN : 1; + uint8_t _USART2_RXEN : 1; + uint8_t _USART2_TXEN : 1; + uint8_t _USART3_RXEN : 1; + uint8_t _USART3_TXEN : 1; + //uint8_t _JTAGEN : 1; + uint8_t _AS2 : 1; + #elif defined(__AVR_TRM02__) + uint8_t _PCIE0 : 1; + uint8_t _PCIE1 : 1; + uint8_t _PCIE2 : 1; + uint8_t _PCIE3 : 1; + uint8_t _ADC7D : 1; + uint8_t _ADC6D : 1; + uint8_t _ADC5D : 1; + uint8_t _ADC4D : 1; + uint8_t _ADC3D : 1; + uint8_t _ADC2D : 1; + uint8_t _ADC1D : 1; + uint8_t _ADC0D : 1; + uint8_t _SPE : 1; + uint8_t _COM0A : 2; + uint8_t _COM0B : 2; + uint8_t _COM2A : 2; + uint8_t _COM2B : 2; + uint8_t _COM1A : 2; + uint8_t _COM1B : 2; + //uint8_t _JTAGEN : 1; + uint8_t _AS2 : 1; + uint8_t _TWEN : 1; + uint8_t _USART1_TXEN : 1; + uint8_t _USART1_RXEN : 1; + uint8_t _USART0_TXEN : 1; + uint8_t _USART0_RXEN : 1; + #elif defined(__AVR_TRM03__) + uint8_t _AS2 : 1; + uint8_t _PCIE0 : 1; + uint8_t _PCIE1 : 1; + uint8_t _PCIE2 : 1; + uint8_t _SPE : 1; + uint8_t _COM2B : 2; + uint8_t _COM2A : 2; + uint8_t _COM1B : 2; + uint8_t _COM1A : 2; + uint8_t _COM0A : 2; + uint8_t _COM0B : 2; + uint8_t _TWEN : 1; + uint8_t _ADC7D : 1; + uint8_t _ADC6D : 1; + uint8_t _ADC5D : 1; + uint8_t _ADC4D : 1; + uint8_t _ADC3D : 1; + uint8_t _ADC2D : 1; + uint8_t _ADC1D : 1; + uint8_t _ADC0D : 1; + uint8_t _UMSEL : 2; + uint8_t _USART0_TXEN : 1; + uint8_t _USART0_RXEN : 1; + #elif defined(__AVR_TRM04__) + uint8_t _SRE : 1; + uint8_t _SPE : 1; + uint8_t _COM0B : 2; + uint8_t _COM1C : 2; + uint8_t _COM1B : 2; + uint8_t _COM1A : 2; + uint8_t _COM2A : 2; + uint8_t _COM2B : 2; + uint8_t _PCIE0 : 1; + uint8_t _USART1_RXEN : 1; + uint8_t _USART1_TXEN : 1; + uint8_t _TWEN : 1; + uint8_t _INT7 : 1; + uint8_t _INT6 : 1; + uint8_t _INT5 : 1; + uint8_t _INT4 : 1; + uint8_t _INT3 : 1; + uint8_t _INT2 : 1; + uint8_t _INT1 : 1; + uint8_t _INT0; + uint8_t _UVCONE : 1; + uint8_t _UIDE : 1; + //uint8_t _JTAGEN : 1; + #elif defined(__AVR_TRM05__) + uint8_t _ADC7D : 1; + uint8_t _ADC6D : 1; + uint8_t _ADC5D : 1; + uint8_t _ADC4D : 1; + uint8_t _ADC3D : 1; + uint8_t _ADC2D : 1; + uint8_t _ADC1D : 1; + uint8_t _ADC0D : 1; + uint8_t _PCIE0 : 1; + uint8_t _PCIE1 : 1; + uint8_t _PCIE2 : 1; + uint8_t _PCIE3 : 1; + uint8_t _SPE : 1; + uint8_t _COM0A : 2; + uint8_t _COM0B : 2; + uint8_t _COM2A : 2; + uint8_t _COM2B : 2; + uint8_t _COM1A : 2; + uint8_t _COM1B : 2; + uint8_t _AS2 : 1; + uint8_t _TWEN : 1; + uint8_t _TXEN1 : 1; + uint8_t _RXEN1 : 1; + uint8_t _TXEN0 : 1; + uint8_t _RXEN0 : 1; + uint8_t _INT2 : 1; + uint8_t _INT1 : 1; + uint8_t _INT0 : 1; + //uint8_t _JTAGEN : 1; + #endif +}; + +// AVR ArduinoCore is written like a hack-job (random peripherals enabled all-the-time). + +enum class eATmegaPort { + #ifdef __AVR_TRM01__ + PORT_A, PORT_B, PORT_C, PORT_D, PORT_E, PORT_F, PORT_G, PORT_H, PORT_J, PORT_K, PORT_L + #elif defined(__AVR_TRM02__) || defined(__AVR_TRM05__) + PORT_A, PORT_B, PORT_C, PORT_D + #elif defined(__AVR_TRM03__) + PORT_B, PORT_C, PORT_D + #elif defined(__AVR_TRM04__) + PORT_A, PORT_B, PORT_C, PORT_D, PORT_E, PORT_F + #endif +}; + +struct ATmegaPinInfo { + eATmegaPort port; + uint8_t pinidx; +}; + +#if defined(__AVR_TRM01__) || defined(__AVR_TRM02__) || defined(__AVR_TRM04__) || defined(__AVR_TRM05__) + #define _SPA_DIO_DDRA (eATmegaPort::PORT_A) +#endif +#if defined(__AVR_TRM01__) || defined(__AVR_TRM02__) || defined(__AVR_TRM03__) || defined(__AVR_TRM04__) || defined(__AVR_TRM05__) + #define _SPA_DIO_DDRB (eATmegaPort::PORT_B) + #define _SPA_DIO_DDRC (eATmegaPort::PORT_C) + #define _SPA_DIO_DDRD (eATmegaPort::PORT_D) +#endif +#if defined(__AVR_TRM01__) || defined(__AVR_TRM04__) + #define _SPA_DIO_DDRE (eATmegaPort::PORT_E) + #define _SPA_DIO_DDRF (eATmegaPort::PORT_F) +#endif +#ifdef __AVR_TRM01__ + #define _SPA_DIO_DDRG (eATmegaPort::PORT_G) + #define _SPA_DIO_DDRH (eATmegaPort::PORT_H) + #define _SPA_DIO_DDRJ (eATmegaPort::PORT_J) + #define _SPA_DIO_DDRK (eATmegaPort::PORT_K) + #define _SPA_DIO_DDRL (eATmegaPort::PORT_L) +#endif + +#define __SPA_IFPORT_STMT(dr) if (ddrp == &D##dr) port = _SPA_DIO_D##dr; + +#ifdef _SPA_DIO_DDRA + #define _SPA_IFPORT_PORTA __SPA_IFPORT_STMT(DRA) +#else + #define _SPA_IFPORT_PORTA +#endif +#ifdef _SPA_DIO_DDRB + #define _SPA_IFPORT_PORTB __SPA_IFPORT_STMT(DRB) +#else + #define _SPA_IFPORT_PORTB +#endif +#ifdef _SPA_DIO_DDRC + #define _SPA_IFPORT_PORTC __SPA_IFPORT_STMT(DRC) +#else + #define _SPA_IFPORT_PORTC +#endif +#ifdef _SPA_DIO_DDRD + #define _SPA_IFPORT_PORTD __SPA_IFPORT_STMT(DRD) +#else + #define _SPA_IFPORT_PORTD +#endif +#ifdef _SPA_DIO_DDRE + #define _SPA_IFPORT_PORTE __SPA_IFPORT_STMT(DRE) +#else + #define _SPA_IFPORT_PORTE +#endif +#ifdef _SPA_DIO_DDRF + #define _SPA_IFPORT_PORTF __SPA_IFPORT_STMT(DRF) +#else + #define _SPA_IFPORT_PORTF +#endif +#ifdef _SPA_DIO_DDRG + #define _SPA_IFPORT_PORTG __SPA_IFPORT_STMT(DRG) +#else + #define _SPA_IFPORT_PORTG +#endif +#ifdef _SPA_DIO_DDRH + #define _SPA_IFPORT_PORTH __SPA_IFPORT_STMT(DRH) +#else + #define _SPA_IFPORT_PORTH +#endif +#ifdef _SPA_DIO_DDRJ + #define _SPA_IFPORT_PORTJ __SPA_IFPORT_STMT(DRJ) +#else + #define _SPA_IFPORT_PORTJ +#endif +#ifdef _SPA_DIO_DDRK + #define _SPA_IFPORT_PORTK __SPA_IFPORT_STMT(DRK) +#else + #define _SPA_IFPORT_PORTK +#endif +#ifdef _SPA_DIO_DDRL + #define _SPA_IFPORT_PORTL __SPA_IFPORT_STMT(DRL) +#else + #define _SPA_IFPORT_PORTL +#endif + +#define _SPA_RESOLVE_DIO(ddr) _SPA_DIO_##ddr +#define _SPA_DIOn_PORTRET(val, n) if (val == n) { \ + auto *ddrp = &DIO##n##_DDR; \ + eATmegaPort port; \ + _SPA_IFPORT_PORTA \ + _SPA_IFPORT_PORTB \ + _SPA_IFPORT_PORTC \ + _SPA_IFPORT_PORTD \ + _SPA_IFPORT_PORTE \ + _SPA_IFPORT_PORTF \ + _SPA_IFPORT_PORTG \ + _SPA_IFPORT_PORTH \ + _SPA_IFPORT_PORTJ \ + _SPA_IFPORT_PORTK \ + _SPA_IFPORT_PORTL \ + return { port, DIO##n##_PIN }; \ + } + +inline ATmegaPinInfo _ATmega_getPinInfo(uint8_t pin) { + #if DIO_NUM > 0 + _SPA_DIOn_PORTRET(pin, 0) + #endif + #if DIO_NUM > 1 + _SPA_DIOn_PORTRET(pin, 1) + #endif + #if DIO_NUM > 2 + _SPA_DIOn_PORTRET(pin, 2) + #endif + #if DIO_NUM > 3 + _SPA_DIOn_PORTRET(pin, 3) + #endif + #if DIO_NUM > 4 + _SPA_DIOn_PORTRET(pin, 4) + #endif + #if DIO_NUM > 5 + _SPA_DIOn_PORTRET(pin, 5) + #endif + #if DIO_NUM > 6 + _SPA_DIOn_PORTRET(pin, 6) + #endif + #if DIO_NUM > 7 + _SPA_DIOn_PORTRET(pin, 7) + #endif + #if DIO_NUM > 8 + _SPA_DIOn_PORTRET(pin, 8) + #endif + #if DIO_NUM > 9 + _SPA_DIOn_PORTRET(pin, 9) + #endif + + #if DIO_NUM > 10 + _SPA_DIOn_PORTRET(pin, 10) + #endif + #if DIO_NUM > 11 + _SPA_DIOn_PORTRET(pin, 11) + #endif + #if DIO_NUM > 12 + _SPA_DIOn_PORTRET(pin, 12) + #endif + #if DIO_NUM > 13 + _SPA_DIOn_PORTRET(pin, 13) + #endif + #if DIO_NUM > 14 + _SPA_DIOn_PORTRET(pin, 14) + #endif + #if DIO_NUM > 15 + _SPA_DIOn_PORTRET(pin, 15) + #endif + #if DIO_NUM > 16 + _SPA_DIOn_PORTRET(pin, 16) + #endif + #if DIO_NUM > 17 + _SPA_DIOn_PORTRET(pin, 17) + #endif + #if DIO_NUM > 18 + _SPA_DIOn_PORTRET(pin, 18) + #endif + #if DIO_NUM > 19 + _SPA_DIOn_PORTRET(pin, 19) + #endif + + #if DIO_NUM > 20 + _SPA_DIOn_PORTRET(pin, 20) + #endif + #if DIO_NUM > 21 + _SPA_DIOn_PORTRET(pin, 21) + #endif + #if DIO_NUM > 22 + _SPA_DIOn_PORTRET(pin, 22) + #endif + #if DIO_NUM > 23 + _SPA_DIOn_PORTRET(pin, 23) + #endif + #if DIO_NUM > 24 + _SPA_DIOn_PORTRET(pin, 24) + #endif + #if DIO_NUM > 25 + _SPA_DIOn_PORTRET(pin, 25) + #endif + #if DIO_NUM > 26 + _SPA_DIOn_PORTRET(pin, 26) + #endif + #if DIO_NUM > 27 + _SPA_DIOn_PORTRET(pin, 27) + #endif + #if DIO_NUM > 28 + _SPA_DIOn_PORTRET(pin, 28) + #endif + #if DIO_NUM > 29 + _SPA_DIOn_PORTRET(pin, 29) + #endif + + #if DIO_NUM > 30 + _SPA_DIOn_PORTRET(pin, 30) + #endif + #if DIO_NUM > 31 + _SPA_DIOn_PORTRET(pin, 31) + #endif + #if DIO_NUM > 32 + _SPA_DIOn_PORTRET(pin, 32) + #endif + #if DIO_NUM > 33 + _SPA_DIOn_PORTRET(pin, 33) + #endif + #if DIO_NUM > 34 + _SPA_DIOn_PORTRET(pin, 34) + #endif + #if DIO_NUM > 35 + _SPA_DIOn_PORTRET(pin, 35) + #endif + #if DIO_NUM > 36 + _SPA_DIOn_PORTRET(pin, 36) + #endif + #if DIO_NUM > 37 + _SPA_DIOn_PORTRET(pin, 37) + #endif + #if DIO_NUM > 38 + _SPA_DIOn_PORTRET(pin, 38) + #endif + #if DIO_NUM > 39 + _SPA_DIOn_PORTRET(pin, 39) + #endif + + #if DIO_NUM > 40 + _SPA_DIOn_PORTRET(pin, 40) + #endif + #if DIO_NUM > 41 + _SPA_DIOn_PORTRET(pin, 41) + #endif + #if DIO_NUM > 42 + _SPA_DIOn_PORTRET(pin, 42) + #endif + #if DIO_NUM > 43 + _SPA_DIOn_PORTRET(pin, 43) + #endif + #if DIO_NUM > 44 + _SPA_DIOn_PORTRET(pin, 44) + #endif + #if DIO_NUM > 45 + _SPA_DIOn_PORTRET(pin, 45) + #endif + #if DIO_NUM > 46 + _SPA_DIOn_PORTRET(pin, 46) + #endif + #if DIO_NUM > 47 + _SPA_DIOn_PORTRET(pin, 47) + #endif + #if DIO_NUM > 48 + _SPA_DIOn_PORTRET(pin, 48) + #endif + #if DIO_NUM > 49 + _SPA_DIOn_PORTRET(pin, 49) + #endif + + #if DIO_NUM > 50 + _SPA_DIOn_PORTRET(pin, 50) + #endif + #if DIO_NUM > 51 + _SPA_DIOn_PORTRET(pin, 51) + #endif + #if DIO_NUM > 52 + _SPA_DIOn_PORTRET(pin, 52) + #endif + #if DIO_NUM > 53 + _SPA_DIOn_PORTRET(pin, 53) + #endif + #if DIO_NUM > 54 + _SPA_DIOn_PORTRET(pin, 54) + #endif + #if DIO_NUM > 55 + _SPA_DIOn_PORTRET(pin, 55) + #endif + #if DIO_NUM > 56 + _SPA_DIOn_PORTRET(pin, 56) + #endif + #if DIO_NUM > 57 + _SPA_DIOn_PORTRET(pin, 57) + #endif + #if DIO_NUM > 58 + _SPA_DIOn_PORTRET(pin, 58) + #endif + #if DIO_NUM > 59 + _SPA_DIOn_PORTRET(pin, 59) + #endif + + #if DIO_NUM > 60 + _SPA_DIOn_PORTRET(pin, 60) + #endif + #if DIO_NUM > 61 + _SPA_DIOn_PORTRET(pin, 61) + #endif + #if DIO_NUM > 62 + _SPA_DIOn_PORTRET(pin, 62) + #endif + #if DIO_NUM > 63 + _SPA_DIOn_PORTRET(pin, 63) + #endif + #if DIO_NUM > 64 + _SPA_DIOn_PORTRET(pin, 64) + #endif + #if DIO_NUM > 65 + _SPA_DIOn_PORTRET(pin, 65) + #endif + #if DIO_NUM > 66 + _SPA_DIOn_PORTRET(pin, 66) + #endif + #if DIO_NUM > 67 + _SPA_DIOn_PORTRET(pin, 67) + #endif + #if DIO_NUM > 68 + _SPA_DIOn_PORTRET(pin, 68) + #endif + #if DIO_NUM > 69 + _SPA_DIOn_PORTRET(pin, 69) + #endif + + #if DIO_NUM > 70 + _SPA_DIOn_PORTRET(pin, 70) + #endif + #if DIO_NUM > 71 + _SPA_DIOn_PORTRET(pin, 71) + #endif + #if DIO_NUM > 72 + _SPA_DIOn_PORTRET(pin, 72) + #endif + #if DIO_NUM > 73 + _SPA_DIOn_PORTRET(pin, 73) + #endif + #if DIO_NUM > 74 + _SPA_DIOn_PORTRET(pin, 74) + #endif + #if DIO_NUM > 75 + _SPA_DIOn_PORTRET(pin, 75) + #endif + #if DIO_NUM > 76 + _SPA_DIOn_PORTRET(pin, 76) + #endif + #if DIO_NUM > 77 + _SPA_DIOn_PORTRET(pin, 77) + #endif + #if DIO_NUM > 78 + _SPA_DIOn_PORTRET(pin, 78) + #endif + #if DIO_NUM > 79 + _SPA_DIOn_PORTRET(pin, 79) + #endif + + #if DIO_NUM > 80 + _SPA_DIOn_PORTRET(pin, 80) + #endif + #if DIO_NUM > 81 + _SPA_DIOn_PORTRET(pin, 81) + #endif + #if DIO_NUM > 82 + _SPA_DIOn_PORTRET(pin, 82) + #endif + #if DIO_NUM > 83 + _SPA_DIOn_PORTRET(pin, 83) + #endif + #if DIO_NUM > 84 + _SPA_DIOn_PORTRET(pin, 84) + #endif + #if DIO_NUM > 85 + _SPA_DIOn_PORTRET(pin, 85) + #endif + #if DIO_NUM > 86 + _SPA_DIOn_PORTRET(pin, 86) + #endif + #if DIO_NUM > 87 + _SPA_DIOn_PORTRET(pin, 87) + #endif + #if DIO_NUM > 88 + _SPA_DIOn_PORTRET(pin, 88) + #endif + #if DIO_NUM > 89 + _SPA_DIOn_PORTRET(pin, 89) + #endif + + // Default. + #if defined(__AVR_TRM01__) || defined(__AVR_TRM02__) || defined(__AVR_TRM04__) || defined(__AVR_TRM05__) + return { eATmegaPort::PORT_A, 0 }; + #elif defined(__AVR_TRM03__) + return { eATmegaPort::PORT_B, 0 }; + #endif +} + +enum class eATmegaPeripheral { + UNDEFINED, + #ifdef __AVR_TRM01__ + PADC, PUSART0, PSPI, PTIM1, PTIM0, PTIM2, PTWI, PUSART1, PUSART2, PUSART3, PTIM3, PTIM4, PTIM5 + #elif defined(__AVR_TRM02__) + PADC, PUSART0, PSPI, PTIM1, PUSART1, PTIM0, PTIM2, PTWI, PTIM3 + #elif defined(__AVR_TRM03__) + PADC, PUSART0, PSPI, PTIM1, PTIM0, PTIM2, PTWI + #elif defined(__AVR_TRM04__) + PADC, PSPI, PTIM1, PTIM0, PTIM2, PTWI, PUSART1, PTIM3, PUSB + #elif defined(__AVR_TRM05__) + PADC, PUSART0, PSPI, PTIM1, PUSART1, PTIM0, PTIM2, PTWI + #endif + , NUM_PERIPHERALS +}; + +enum class eATmegaPinFunc : uint8_t { + #ifdef __AVR_TRM01__ + EXTMEM_AD15, EXTMEM_AD14, EXTMEM_AD13, EXTMEM_AD12, EXTMEM_AD11, EXTMEM_AD10, EXTMEM_AD9, EXTMEM_AD8, + EXTMEM_AD7, EXTMEM_AD6, EXTMEM_AD5, EXTMEM_AD4, EXTMEM_AD3, EXTMEM_AD2, EXTMEM_AD1, EXTMEM_AD0, + EXTMEM_ALE, EXTMEM_RD, EXTMEM_WR, + TOC0A, TOC0B, TOC1A, TOC1B, TOC1C, TOC2A, TOC2B, TOC3C, TOC3B, TOC3A, TOC4C, TOC4B, TOC4A, TOC5C, TOC5B, TOC5A, + EINT7, EINT6, EINT5, EINT4, EINT3, EINT2, EINT1, EINT0, + PCI0, PCI1, PCI2, PCI3, PCI4, PCI5, PCI6, PCI7, + PCI8, PCI9, PCI10, PCI11, PCI12, PCI13, PCI14, PCI15, + PCI16, PCI17, PCI18, PCI19, PCI20, PCI21, PCI22, PCI23, + SPI_MISO, SPI_MOSI, SPI_SCK, SPI_CS, + TOSC1, TOSC2, + TIMER0_CLKI, TIMER1_CLKI, TIMER3_CLKI, TIMER4_CLKI, TIMER5_CLKI, + TIMER1_ICP, TIMER3_ICP, TIMER5_ICP, TIMER4_ICP, + USART0_CLK, USART1_CLK, USART2_CLK, USART3_CLK, + USART0_TXD, USART0_RXD, USART1_TXD, USART1_RXD, USART2_TXD, USART2_RXD, USART3_TXD, USART3_RXD, + TWI_SDA, TWI_CLK, + CLKO, PDO, PDI, + AIN0, AIN1, + ADC15, ADC14, ADC13, ADC12, ADC11, ADC10, ADC9, ADC8, + ADC7, ADC6, ADC5, ADC4, ADC3, ADC2, ADC1, ADC0 + #elif defined(__AVR_TRM02__) + ADC7, ADC6, ADC5, ADC4, ADC3, ADC2, ADC1, ADC0, + SPI_SCK, SPI_MISO, SPI_MOSI, SPI_CS, + PCI31, PCI30, PCI29, PCI28, PCI27, PCI26, PCI25, PCI24, + PCI23, PCI22, PCI21, PCI20, PCI19, PCI18, PCI17, PCI16, + PCI15, PCI14, PCI13, PCI12, PCI11, PCI10, PCI9, PCI8, + PCI7, PCI6, PCI5, PCI4, PCI3, PCI2, PCI1, PCI0, + EINT2, EINT1, EINT0, + TIMER3_ICP, + TIMER3_ECI, TIMER1_ECI, TIMER0_ECI, + TIMER1_ICP, + TOC3B, TOC3A, TOC2A, TOC2B, TOC1A, TOC1B, TOC0B, TOC0A, + AIN1, AIN0, + USART0_CLK, USART1_CLK, + USART0_TXD, USART0_RXD, USART1_TXD, USART1_RXD, + CLKO, + TOSC2, TOSC1, + TWI_SDA, TWI_CLK + #elif defined(__AVR_TRM03__) + ADC5, ADC4, ADC3, ADC2, ADC1, ADC0, + XTAL2, XTAL1, + TOSC2, TOSC1, + SPI_SCK, SPI_MISO, SPI_MOSI, SPI_CS, + TOC2B, TOC2A, TOC1B, TOC1A, TOC0A, TOC0B, + TIMER1_ICP, + TIMER1_ECI, TIMER0_ECI, + TWI_CLK, TWI_SDA, + PCI23, PCI22, PCI21, PCI20, PCI19, PCI18, PCI17, PCI16, + PCI14, PCI13, PCI12, PCI11, PCI10, PCI9, PCI8, + PCI7, PCI6, PCI5, PCI4, PCI3, PCI2, PCI1, PCI0, + CLKO, + AIN1, AIN0, + USART_CLK, + USART_TXD, USART_RXD, + EINT1, EINT0 + #elif defined(__AVR_TRM04__) + EXTMEM_AD15, EXTMEM_AD14, EXTMEM_AD13, EXTMEM_AD12, EXTMEM_AD11, EXTMEM_AD10, EXTMEM_AD9, EXTMEM_AD8, + EXTMEM_AD7, EXTMEM_AD6, EXTMEM_AD5, EXTMEM_AD4, EXTMEM_AD3, EXTMEM_AD2, EXTMEM_AD1, EXTMEM_AD0, + EXTMEM_ALE, EXTMEM_RD, EXTMEM_WR, + TOC0B, TOC0A, TOC1C, TOC1B, TOC1A, TOC2B, TOC2A, TOC3A, TOC3B, TOC3C, + CLKO, PDO, PDI, + SPI_MISO, SPI_MOSI, SPI_SCK, SPI_CS, + TIMER3_ICP, TIMER1_ICP, + TIMER3_CLKI, TIMER0_CLKI, TIMER1_CLKI, + USART1_CLK, USART1_TXD, USART1_RXD, + EINT7, EINT6, EINT5, EINT4, EINT3, EINT2, EINT1, EINT0, + PCI7, PCI6, PCI5, PCI4, PCI3, PCI2, PCI1, PCI0, + TWI_SDA, TWI_CLK, + AIN1, AIN0, + TOSC2, + UID, UVCON, + ADC7, ADC6, ADC5, ADC4, ADC3, ADC2, ADC1, ADC0 + #elif defined(__AVR_TRM05__) + ADC7, ADC6, ADC5, ADC4, ADC3, ADC2, ADC1, ADC0, + PCI31, PCI30, PCI29, PCI28, PCI27, PCI26, PCI25, PCI24, + PCI23, PCI22, PCI21, PCI20, PCI19, PCI18, PCI17, PCI16, + PCI15, PCI14, PCI13, PCI12, PCI11, PCI10, PCI9, PCI8, + PCI7, PCI6, PCI5, PCI4, PCI3, PCI2, PCI1, PCI0, + SPI_SCK, SPI_MISO, SPI_MOSI, SPI_CS, + AIN1, AIN0, + TIMER1_ICP, TIMER0_ICP, + TIMER1_ECI, TIMER0_ECI, + TOC0B, TOC0A, TOC2A, TOC2B, TOC1A, TOC1B, + TOSC2, TOSC1, + //JTAG_TDI, JTAG_TDO, JTAG_TMS, JTAG_TCK, + TWI_CLK, TWI_SDA, + EINT2, EINT1, EINT0, + CLKO, + USART0_CLK, USART0_TXD, USART0_RXD, + USART1_CLK, USART1_TXD, USART1_RXD + #endif + , NUM_FUNCS +}; + +#ifndef countof + #define countof(x) (sizeof(x) / sizeof(*x)) +#endif + +struct ATmegaPinFunctions { + inline ATmegaPinFunctions(const eATmegaPinFunc *funcs, uint8_t cnt) noexcept : funcs(funcs), cnt(cnt) {} + inline ATmegaPinFunctions() = default; + inline ATmegaPinFunctions(const ATmegaPinFunctions&) = default; + + const eATmegaPinFunc *funcs = nullptr; + uint8_t cnt = 0; + + inline bool hasFunc(eATmegaPinFunc query) const { + for (uint8_t n = 0; n < this->cnt; n++) { + eATmegaPinFunc func = this->funcs[n]; + if (func == query) return true; + } + return false; + } + template + inline bool hasFunc(eATmegaPinFunc func, otherItemType&&... items) const { + return hasFunc(func) || hasFunc(((otherItemType&&)items)...); + } + + template + inline void iterate(callbackType&& cb) const { + for (uint8_t n = 0; n < this->cnt; n++) { + eATmegaPinFunc func = this->funcs[n]; + cb(func); + } + } +}; + +ATmegaPinFunctions _ATmega_getPinFunctions(int pin); + +struct ATmegaPinFuncSet { + inline ATmegaPinFuncSet() noexcept { + for (bool& f : this->funcs) f = false; + } + template + inline ATmegaPinFuncSet(eATmegaPinFunc func, funcItemType&&... items) noexcept : ATmegaPinFuncSet() { + add(func, ((funcItemType&&)items)...); + } + template + inline ATmegaPinFuncSet(int pin, funcItemType&&... items) noexcept : ATmegaPinFuncSet() { + addFromPin(pin, ((funcItemType&&)items)...); + } + inline ATmegaPinFuncSet(const ATmegaPinFuncSet&) = default; + + inline void add(eATmegaPinFunc value) noexcept { + this->funcs[(uint8_t)value] = true; + } + template + inline void add(eATmegaPinFunc value, funcItemType&&... items) { + add(value); + add(((eATmegaPinFunc&&)items)...); + } + + inline void addFromPin(int pin) noexcept { + ATmegaPinFunctions funcs = _ATmega_getPinFunctions(pin); + funcs.iterate( + [this]( eATmegaPinFunc func ) noexcept { this->add(func); } + ); + } + template + inline void addFromPin(int pin, itemType&&... items) noexcept { + addFromPin(pin); + addFromPin(((itemType&&)items)...); + } + + inline bool hasFunc(eATmegaPinFunc value) const noexcept { + return this->funcs[(uint8_t)value]; + } + + inline bool hasAnyFunc() const noexcept { return false; } + template + inline bool hasAnyFunc(funcItem&& item, otherFuncItem&&... funcs) const noexcept { + return hasFunc(item) || hasAnyFunc(((otherFuncItem&&)funcs)...); + } + + template + inline void iterate(callbackType&& cb) const { + for (uint8_t n = 1; n < countof(this->funcs); n++) { + const bool& f = this->funcs[n]; + if (f) cb((eATmegaPinFunc)n); + } + } + +private: + bool funcs[(uint8_t)eATmegaPinFunc::NUM_FUNCS]; +}; + +inline void _ATmega_setPeripheralPower(eATmegaPeripheral peri, bool fullPower) { + bool reducePower = (fullPower == false); + switch(peri) { + #ifdef __AVR_TRM01__ + case eATmegaPeripheral::PADC: _PRR0._PRADC = reducePower; break; + case eATmegaPeripheral::PUSART0: _PRR0._PRUSART0 = reducePower; break; + case eATmegaPeripheral::PSPI: _PRR0._PRSPI = reducePower; break; + case eATmegaPeripheral::PTIM1: _PRR0._PRTIM1 = reducePower; break; + case eATmegaPeripheral::PTIM0: _PRR0._PRTIM0 = reducePower; break; + case eATmegaPeripheral::PTIM2: _PRR0._PRTIM2 = reducePower; break; + case eATmegaPeripheral::PTWI: _PRR0._PRTWI = reducePower; break; + case eATmegaPeripheral::PUSART1: _PRR1._PRUSART1 = reducePower; break; + case eATmegaPeripheral::PUSART2: _PRR1._PRUSART2 = reducePower; break; + case eATmegaPeripheral::PUSART3: _PRR1._PRUSART3 = reducePower; break; + case eATmegaPeripheral::PTIM3: _PRR1._PRTIM3 = reducePower; break; + case eATmegaPeripheral::PTIM4: _PRR1._PRTIM4 = reducePower; break; + case eATmegaPeripheral::PTIM5: _PRR1._PRTIM5 = reducePower; break; + #elif defined(__AVR_TRM02__) + case eATmegaPeripheral::PADC: _PRR0._PRADC = reducePower; break; + case eATmegaPeripheral::PUSART0: _PRR0._PRUSART0 = reducePower; break; + case eATmegaPeripheral::PSPI: _PRR0._PRSPI = reducePower; break; + case eATmegaPeripheral::PTIM1: _PRR0._PRTIM1 = reducePower; break; + case eATmegaPeripheral::PUSART1: _PRR0._PRUSART1 = reducePower; break; + case eATmegaPeripheral::PTIM0: _PRR0._PRTIM0 = reducePower; break; + case eATmegaPeripheral::PTIM2: _PRR0._PRTIM2 = reducePower; break; + case eATmegaPeripheral::PTWI: _PRR0._PRTWI = reducePower; break; + case eATmegaPeripheral::PTIM3: _PRR1._PRTIM3 = reducePower; break; + #elif defined(__AVR_TRM03__) + case eATmegaPeripheral::PADC: _PRR0._PRADC = reducePower; break; + case eATmegaPeripheral::PUSART0: _PRR0._PRUSART0 = reducePower; break; + case eATmegaPeripheral::PSPI: _PRR0._PRSPI = reducePower; break; + case eATmegaPeripheral::PTIM1: _PRR0._PRTIM1 = reducePower; break; + case eATmegaPeripheral::PTIM0: _PRR0._PRTIM0 = reducePower; break; + case eATmegaPeripheral::PTIM2: _PRR0._PRTIM2 = reducePower; break; + case eATmegaPeripheral::PTWI: _PRR0._PRTWI = reducePower; break; + #elif defined(__AVR_TRM04__) + case eATmegaPeripheral::PADC: _PRR0._PRADC = reducePower; break; + case eATmegaPeripheral::PSPI: _PRR0._PRSPI = reducePower; break; + case eATmegaPeripheral::PTIM1: _PRR0._PRTIM1 = reducePower; break; + case eATmegaPeripheral::PTIM0: _PRR0._PRTIM0 = reducePower; break; + case eATmegaPeripheral::PTIM2: _PRR0._PRTIM2 = reducePower; break; + case eATmegaPeripheral::PTWI: _PRR0._PRTWI = reducePower; break; + case eATmegaPeripheral::PUSART1: _PRR1._PRUSART1 = reducePower; break; + case eATmegaPeripheral::PTIM3: _PRR1._PRTIM3 = reducePower; break; + case eATmegaPeripheral::PUSB: _PRR1._PRUSB = reducePower; break; + #elif defined(__AVR_TRM05__) + case eATmegaPeripheral::PADC: _PRR0._PRADC = reducePower; break; + case eATmegaPeripheral::PUSART0: _PRR0._PRUSART0 = reducePower; break; + case eATmegaPeripheral::PSPI: _PRR0._PRSPI = reducePower; break; + case eATmegaPeripheral::PTIM1: _PRR0._PRTIM1 = reducePower; break; + case eATmegaPeripheral::PUSART1: _PRR0._PRUSART1 = reducePower; break; + case eATmegaPeripheral::PTIM0: _PRR0._PRTIM0 = reducePower; break; + case eATmegaPeripheral::PTIM2: _PRR0._PRTIM2 = reducePower; break; + case eATmegaPeripheral::PTWI: _PRR0._PRTWI = reducePower; break; + #endif + case eATmegaPeripheral::UNDEFINED: case eATmegaPeripheral::NUM_PERIPHERALS: break; + } +} + +inline bool _ATmega_getPeripheralPower(eATmegaPeripheral peri) { + switch(peri) { + #ifdef __AVR_TRM01__ + case eATmegaPeripheral::PADC: return _PRR0._PRADC == false; + case eATmegaPeripheral::PUSART0: return _PRR0._PRUSART0 == false; + case eATmegaPeripheral::PSPI: return _PRR0._PRSPI == false; + case eATmegaPeripheral::PTIM1: return _PRR0._PRTIM1 == false; + case eATmegaPeripheral::PTIM0: return _PRR0._PRTIM0 == false; + case eATmegaPeripheral::PTIM2: return _PRR0._PRTIM2 == false; + case eATmegaPeripheral::PTWI: return _PRR0._PRTWI == false; + case eATmegaPeripheral::PUSART1: return _PRR1._PRUSART1 == false; + case eATmegaPeripheral::PUSART2: return _PRR1._PRUSART2 == false; + case eATmegaPeripheral::PUSART3: return _PRR1._PRUSART3 == false; + case eATmegaPeripheral::PTIM3: return _PRR1._PRTIM3 == false; + case eATmegaPeripheral::PTIM4: return _PRR1._PRTIM4 == false; + case eATmegaPeripheral::PTIM5: return _PRR1._PRTIM5 == false; + #elif defined(__AVR_TRM02__) + case eATmegaPeripheral::PADC: return _PRR0._PRADC == false; + case eATmegaPeripheral::PUSART0: return _PRR0._PRUSART0 == false; + case eATmegaPeripheral::PSPI: return _PRR0._PRSPI == false; + case eATmegaPeripheral::PTIM1: return _PRR0._PRTIM1 == false; + case eATmegaPeripheral::PUSART1: return _PRR0._PRUSART1 == false; + case eATmegaPeripheral::PTIM0: return _PRR0._PRTIM0 == false; + case eATmegaPeripheral::PTIM2: return _PRR0._PRTIM2 == false; + case eATmegaPeripheral::PTWI: return _PRR0._PRTWI == false; + case eATmegaPeripheral::PTIM3: return _PRR1._PRTIM3 == false; + #elif defined(__AVR_TRM03__) + case eATmegaPeripheral::PADC: return _PRR0._PRADC == false; + case eATmegaPeripheral::PUSART0: return _PRR0._PRUSART0 == false; + case eATmegaPeripheral::PSPI: return _PRR0._PRSPI == false; + case eATmegaPeripheral::PTIM1: return _PRR0._PRTIM1 == false; + case eATmegaPeripheral::PTIM0: return _PRR0._PRTIM0 == false; + case eATmegaPeripheral::PTIM2: return _PRR0._PRTIM2 == false; + case eATmegaPeripheral::PTWI: return _PRR0._PRTWI == false; + #elif defined(__AVR_TRM04__) + case eATmegaPeripheral::PADC: return _PRR0._PRADC == false; + case eATmegaPeripheral::PSPI: return _PRR0._PRSPI == false; + case eATmegaPeripheral::PTIM1: return _PRR0._PRTIM1 == false; + case eATmegaPeripheral::PTIM0: return _PRR0._PRTIM0 == false; + case eATmegaPeripheral::PTIM2: return _PRR0._PRTIM2 == false; + case eATmegaPeripheral::PTWI: return _PRR0._PRTWI == false; + case eATmegaPeripheral::PUSART1: return _PRR1._PRUSART1 == false; + case eATmegaPeripheral::PTIM3: return _PRR1._PRTIM3 == false; + case eATmegaPeripheral::PUSB: return _PRR1._PRUSB == false; + #elif defined(__AVR_TRM05__) + case eATmegaPeripheral::PADC: return _PRR0._PRADC == false; + case eATmegaPeripheral::PUSART0: return _PRR0._PRUSART0 == false; + case eATmegaPeripheral::PSPI: return _PRR0._PRSPI == false; + case eATmegaPeripheral::PTIM1: return _PRR0._PRTIM1 == false; + case eATmegaPeripheral::PUSART1: return _PRR0._PRUSART1 == false; + case eATmegaPeripheral::PTIM0: return _PRR0._PRTIM0 == false; + case eATmegaPeripheral::PTIM2: return _PRR0._PRTIM2 == false; + case eATmegaPeripheral::PTWI: return _PRR0._PRTWI == false; + #endif + case eATmegaPeripheral::UNDEFINED: case eATmegaPeripheral::NUM_PERIPHERALS: break; + } + return false; +} + +inline eATmegaPeripheral _ATmega_getPeripheralForFunc( eATmegaPinFunc func ) { + // In C++20 there is the "using-enum" statement. I wish we had C++20 over here... + //using enum eATmegaPinFunc; + switch(func) { + #ifdef __AVR_TRM01__ + case eATmegaPinFunc::TOC0A: case eATmegaPinFunc::TOC0B: return eATmegaPeripheral::PTIM0; + case eATmegaPinFunc::TOC1A: case eATmegaPinFunc::TOC1B: case eATmegaPinFunc::TOC1C: return eATmegaPeripheral::PTIM1; + case eATmegaPinFunc::TOC2A: case eATmegaPinFunc::TOC2B: return eATmegaPeripheral::PTIM2; + case eATmegaPinFunc::TOC3A: case eATmegaPinFunc::TOC3B: case eATmegaPinFunc::TOC3C: return eATmegaPeripheral::PTIM3; + case eATmegaPinFunc::TOC4A: case eATmegaPinFunc::TOC4B: case eATmegaPinFunc::TOC4C: return eATmegaPeripheral::PTIM4; + case eATmegaPinFunc::TOC5A: case eATmegaPinFunc::TOC5B: case eATmegaPinFunc::TOC5C: return eATmegaPeripheral::PTIM5; + case eATmegaPinFunc::SPI_MISO: case eATmegaPinFunc::SPI_MOSI: case eATmegaPinFunc::SPI_SCK: case eATmegaPinFunc::SPI_CS: return eATmegaPeripheral::PSPI; + case eATmegaPinFunc::TIMER0_CLKI: return eATmegaPeripheral::PTIM0; + case eATmegaPinFunc::TIMER1_CLKI: case eATmegaPinFunc::TIMER1_ICP: return eATmegaPeripheral::PTIM1; + case eATmegaPinFunc::TIMER3_CLKI: case eATmegaPinFunc::TIMER3_ICP: return eATmegaPeripheral::PTIM3; + case eATmegaPinFunc::TIMER4_CLKI: case eATmegaPinFunc::TIMER4_ICP: return eATmegaPeripheral::PTIM4; + case eATmegaPinFunc::TIMER5_CLKI: case eATmegaPinFunc::TIMER5_ICP: return eATmegaPeripheral::PTIM5; + case eATmegaPinFunc::USART0_CLK: case eATmegaPinFunc::USART0_TXD: case eATmegaPinFunc::USART0_RXD: return eATmegaPeripheral::PUSART0; + case eATmegaPinFunc::USART1_CLK: case eATmegaPinFunc::USART1_TXD: case eATmegaPinFunc::USART1_RXD: return eATmegaPeripheral::PUSART1; + case eATmegaPinFunc::USART2_CLK: case eATmegaPinFunc::USART2_TXD: case eATmegaPinFunc::USART2_RXD: return eATmegaPeripheral::PUSART2; + case eATmegaPinFunc::USART3_CLK: case eATmegaPinFunc::USART3_TXD: case eATmegaPinFunc::USART3_RXD: return eATmegaPeripheral::PUSART3; + case eATmegaPinFunc::TWI_SDA: case eATmegaPinFunc::TWI_CLK: return eATmegaPeripheral::PTWI; + case eATmegaPinFunc::ADC15: case eATmegaPinFunc::ADC14: case eATmegaPinFunc::ADC13: case eATmegaPinFunc::ADC12: case eATmegaPinFunc::ADC11: case eATmegaPinFunc::ADC10: case eATmegaPinFunc::ADC9: case eATmegaPinFunc::ADC8: + case eATmegaPinFunc::ADC7: case eATmegaPinFunc::ADC6: case eATmegaPinFunc::ADC5: case eATmegaPinFunc::ADC4: case eATmegaPinFunc::ADC3: case eATmegaPinFunc::ADC2: case eATmegaPinFunc::ADC1: case eATmegaPinFunc::ADC0: + return eATmegaPeripheral::PADC; + #elif defined(__AVR_TRM02__) + case eATmegaPinFunc::ADC7: case eATmegaPinFunc::ADC6: case eATmegaPinFunc::ADC5: case eATmegaPinFunc::ADC4: case eATmegaPinFunc::ADC3: case eATmegaPinFunc::ADC2: case eATmegaPinFunc::ADC1: case eATmegaPinFunc::ADC0: + return eATmegaPeripheral::PADC; + case eATmegaPinFunc::SPI_SCK: case eATmegaPinFunc::SPI_MISO: case eATmegaPinFunc::SPI_MOSI: case eATmegaPinFunc::SPI_CS: return eATmegaPeripheral::PSPI; + case eATmegaPinFunc::TIMER3_ICP: case eATmegaPinFunc::TIMER3_ECI: return eATmegaPeripheral::PTIM3; + case eATmegaPinFunc::TIMER1_ECI: case eATmegaPinFunc::TIMER1_ICP: return eATmegaPeripheral::PTIM1; + case eATmegaPinFunc::TIMER0_ECI: return eATmegaPeripheral::PTIM0; + case eATmegaPinFunc::TOC3B: case eATmegaPinFunc::TOC3A: return eATmegaPeripheral::PTIM3; + case eATmegaPinFunc::TOC2A: case eATmegaPinFunc::TOC2B: return eATmegaPeripheral::PTIM2; + case eATmegaPinFunc::TOC1A: case eATmegaPinFunc::TOC1B: return eATmegaPeripheral::PTIM1; + case eATmegaPinFunc::TOC0B: case eATmegaPinFunc::TOC0A: return eATmegaPeripheral::PTIM0; + case eATmegaPinFunc::USART0_CLK: case eATmegaPinFunc::USART0_TXD: case eATmegaPinFunc::USART0_RXD: return eATmegaPeripheral::PUSART0; + case eATmegaPinFunc::USART1_CLK: case eATmegaPinFunc::USART1_TXD: case eATmegaPinFunc::USART1_RXD: return eATmegaPeripheral::PUSART1; + case eATmegaPinFunc::TWI_SDA: case eATmegaPinFunc::TWI_CLK: return eATmegaPeripheral::PTWI; + #elif defined(__AVR_TRM03__) + case eATmegaPinFunc::ADC5: case eATmegaPinFunc::ADC4: case eATmegaPinFunc::ADC3: case eATmegaPinFunc::ADC2: case eATmegaPinFunc::ADC1: case eATmegaPinFunc::ADC0: + return eATmegaPeripheral::PADC; + case eATmegaPinFunc::SPI_SCK: case eATmegaPinFunc::SPI_MISO: case eATmegaPinFunc::SPI_MOSI: case eATmegaPinFunc::SPI_CS: return eATmegaPeripheral::PSPI; + case eATmegaPinFunc::TOC2B: case eATmegaPinFunc::TOC2A: return eATmegaPeripheral::PTIM2; + case eATmegaPinFunc::TOC1B: case eATmegaPinFunc::TOC1A: return eATmegaPeripheral::PTIM1; + case eATmegaPinFunc::TOC0A: case eATmegaPinFunc::TOC0B: return eATmegaPeripheral::PTIM0; + case eATmegaPinFunc::TIMER1_ICP: case eATmegaPinFunc::TIMER1_ECI: return eATmegaPeripheral::PTIM1; + case eATmegaPinFunc::TIMER0_ECI: return eATmegaPeripheral::PTIM0; + case eATmegaPinFunc::TWI_CLK: case eATmegaPinFunc::TWI_SDA: return eATmegaPeripheral::PTWI; + case eATmegaPinFunc::USART_CLK: case eATmegaPinFunc::USART_TXD: case eATmegaPinFunc::USART_RXD: return eATmegaPeripheral::PUSART0; + #elif defined(__AVR_TRM04__) + case eATmegaPinFunc::TOC0B: case eATmegaPinFunc::TOC0A: return eATmegaPeripheral::PTIM0; + case eATmegaPinFunc::TOC1C: case eATmegaPinFunc::TOC1B: case eATmegaPinFunc::TOC1A: return eATmegaPeripheral::PTIM1; + case eATmegaPinFunc::TOC2B: case eATmegaPinFunc::TOC2A: return eATmegaPeripheral::PTIM2; + case eATmegaPinFunc::TOC3A: case eATmegaPinFunc::TOC3B: case eATmegaPinFunc::TOC3C: return eATmegaPeripheral::PTIM3; + case eATmegaPinFunc::SPI_MISO: case eATmegaPinFunc::SPI_MOSI: case eATmegaPinFunc::SPI_SCK: case eATmegaPinFunc::SPI_CS: return eATmegaPeripheral::PSPI; + case eATmegaPinFunc::TIMER3_ICP: case eATmegaPinFunc::TIMER3_CLKI: return eATmegaPeripheral::PTIM3; + case eATmegaPinFunc::TIMER1_ICP: case eATmegaPinFunc::TIMER1_CLKI: return eATmegaPeripheral::PTIM1; + case eATmegaPinFunc::TIMER0_CLKI: return eATmegaPeripheral::PTIM0; + case eATmegaPinFunc::USART1_CLK: case eATmegaPinFunc::USART1_TXD: case eATmegaPinFunc::USART1_RXD: return eATmegaPeripheral::PUSART1; + case eATmegaPinFunc::TWI_SDA: case eATmegaPinFunc::TWI_CLK: return eATmegaPeripheral::PTWI; + case eATmegaPinFunc::UID: case eATmegaPinFunc::UVCON: return eATmegaPeripheral::PUSB; + case eATmegaPinFunc::ADC7: case eATmegaPinFunc::ADC6: case eATmegaPinFunc::ADC5: case eATmegaPinFunc::ADC4: case eATmegaPinFunc::ADC3: case eATmegaPinFunc::ADC2: case eATmegaPinFunc::ADC1: case eATmegaPinFunc::ADC0: + return eATmegaPeripheral::PADC; + #elif defined(__AVR_TRM05__) + case eATmegaPinFunc::ADC7: case eATmegaPinFunc::ADC6: case eATmegaPinFunc::ADC5: case eATmegaPinFunc::ADC4: case eATmegaPinFunc::ADC3: case eATmegaPinFunc::ADC2: case eATmegaPinFunc::ADC1: case eATmegaPinFunc::ADC0: + return eATmegaPeripheral::PADC; + case eATmegaPinFunc::SPI_MISO: case eATmegaPinFunc::SPI_MOSI: case eATmegaPinFunc::SPI_SCK: case eATmegaPinFunc::SPI_CS: return eATmegaPeripheral::PSPI; + case eATmegaPinFunc::TIMER1_ICP: case eATmegaPinFunc::TIMER1_ECI: return eATmegaPeripheral::PTIM1; + case eATmegaPinFunc::TIMER0_ICP: case eATmegaPinFunc::TIMER0_ECI: return eATmegaPeripheral::PTIM0; + case eATmegaPinFunc::TOC0B: case eATmegaPinFunc::TOC0A: return eATmegaPeripheral::PTIM0; + case eATmegaPinFunc::TOC1A: case eATmegaPinFunc::TOC1B: return eATmegaPeripheral::PTIM1; + case eATmegaPinFunc::TOC2A: case eATmegaPinFunc::TOC2B: return eATmegaPeripheral::PTIM2; + case eATmegaPinFunc::TWI_CLK: case eATmegaPinFunc::TWI_SDA: return eATmegaPeripheral::PTWI; + case eATmegaPinFunc::USART0_CLK: case eATmegaPinFunc::USART0_TXD: case eATmegaPinFunc::USART0_RXD: return eATmegaPeripheral::PUSART0; + case eATmegaPinFunc::USART1_CLK: case eATmegaPinFunc::USART1_TXD: case eATmegaPinFunc::USART1_RXD: return eATmegaPeripheral::PUSART1; + #endif + // There are quite some pin functions that have no peripheral assignment, and that is OK! + default: break; + } + return eATmegaPeripheral::UNDEFINED; +} + +struct ATmegaPeripheralSet { + inline ATmegaPeripheralSet() noexcept { + for (bool& f : this->funcs) f = false; + } + template + inline ATmegaPeripheralSet(funcItemType&&... items) noexcept : ATmegaPinFuncSet() { + add(((eATmegaPinFunc&&)items)...); + } + inline ATmegaPeripheralSet(const ATmegaPeripheralSet&) = default; + + inline void add(eATmegaPeripheral value) noexcept { + this->funcs[(uint8_t)value] = true; + } + template + inline void add(eATmegaPeripheral value, funcItemType&&... items) noexcept { + add(value); + add(((funcItemType&&)items)...); + } + + inline bool hasItem(eATmegaPeripheral value) const noexcept { + return this->funcs[(uint8_t)value]; + } + template + inline bool hasItem(eATmegaPeripheral&& item, otherFuncItem&&... funcs) const noexcept { + return hasItem(item) || hasItem(((otherFuncItem&&)funcs)...); + } + + template + inline void iterate(callbackType&& cb) const { + for (uint8_t n = 1; n < countof(funcs); n++) { + const bool& f = this->funcs[n]; + if (f) cb( (eATmegaPeripheral)n ); + } + } + + inline void fromPinFuncs(const ATmegaPinFuncSet& funcSet) { + funcSet.iterate( + [this]( eATmegaPinFunc func ) noexcept { + this->add( _ATmega_getPeripheralForFunc(func) ); + } + ); + } + +private: + bool funcs[(uint8_t)eATmegaPeripheral::NUM_PERIPHERALS]; +}; + +struct ATmegaPeripheralPowerGate { + inline ATmegaPeripheralPowerGate(ATmegaPeripheralSet& periSet) noexcept : periSet(periSet) { + periSet.iterate( + [this]( eATmegaPeripheral peri ) noexcept { + this->states[(uint8_t)peri] = _ATmega_getPeripheralPower(peri); + _ATmega_setPeripheralPower(peri, true); + } + ); + } + inline ATmegaPeripheralPowerGate(const ATmegaPeripheralPowerGate&) = delete; + + inline ~ATmegaPeripheralPowerGate() { + periSet.iterate( + [this]( eATmegaPeripheral peri ) noexcept { + _ATmega_setPeripheralPower(peri, this->states[(uint8_t)peri]); + } + ); + } + + inline ATmegaPeripheralPowerGate& operator = (const ATmegaPeripheralPowerGate&) = delete; + +private: + ATmegaPeripheralSet& periSet; + bool states[(uint8_t)eATmegaPeripheral::NUM_PERIPHERALS]; +}; + +inline pin_dev_state_t _ATmega_savePinAlternates(const ATmegaPinFuncSet& funcSet) { + // TODO: the manual states that registers of power-reduced peripherals cannot be read or written, and that + // the resources (GPIO pins) remain occupied during power-reduction. This is a serious problem and we should + // add power-reduction awareness to this logic! + + pin_dev_state_t state; + + ATmegaPeripheralSet periSet; + periSet.fromPinFuncs(funcSet); + + ATmegaPeripheralPowerGate pgate(periSet); + + #ifdef __AVR_TRM01__ + // See page 75ff of ATmega2560 technical reference manual. + if (funcSet.hasAnyFunc( + eATmegaPinFunc::EXTMEM_AD15, eATmegaPinFunc::EXTMEM_AD14, eATmegaPinFunc::EXTMEM_AD13, eATmegaPinFunc::EXTMEM_AD12, eATmegaPinFunc::EXTMEM_AD11, eATmegaPinFunc::EXTMEM_AD10, eATmegaPinFunc::EXTMEM_AD9, eATmegaPinFunc::EXTMEM_AD8, + eATmegaPinFunc::EXTMEM_AD7, eATmegaPinFunc::EXTMEM_AD6, eATmegaPinFunc::EXTMEM_AD5, eATmegaPinFunc::EXTMEM_AD4, eATmegaPinFunc::EXTMEM_AD3, eATmegaPinFunc::EXTMEM_AD2, eATmegaPinFunc::EXTMEM_AD1, eATmegaPinFunc::EXTMEM_AD0, + eATmegaPinFunc::EXTMEM_ALE, eATmegaPinFunc::EXTMEM_RD, eATmegaPinFunc::EXTMEM_WR + )) { + state._SRE = _XMCRA._SRE; + _XMCRA._SRE = false; + } + if (funcSet.hasAnyFunc( + eATmegaPinFunc::PCI0, eATmegaPinFunc::PCI1, eATmegaPinFunc::PCI2, eATmegaPinFunc::PCI3, eATmegaPinFunc::PCI4, eATmegaPinFunc::PCI5, eATmegaPinFunc::PCI6, eATmegaPinFunc::PCI7 + )) { + state._PCIE0 = _PCICR._PCIE0; + _PCICR._PCIE0 = false; + } + if (funcSet.hasFunc(eATmegaPinFunc::TOC1C)) { + state._COM1C = TIMER1._TCCRnA._COMnC; + TIMER1._TCCRnA._COMnC = 0; + } + if (funcSet.hasFunc(eATmegaPinFunc::TOC1B)) { + state._COM1B = TIMER1._TCCRnA._COMnB; + TIMER1._TCCRnA._COMnB = 0; + } + if (funcSet.hasFunc(eATmegaPinFunc::TOC1A)) { + state._COM1A = TIMER1._TCCRnA._COMnA; + TIMER1._TCCRnA._COMnA = 0; + } + if (funcSet.hasFunc(eATmegaPinFunc::TOC2A)) { + state._COM2A = _TIMER2._TCCRnA._COMnA; + _TIMER2._TCCRnA._COMnA = 0; + } + if (funcSet.hasAnyFunc(eATmegaPinFunc::USART1_TXD, eATmegaPinFunc::USART1_CLK)) { + state._USART1_TXEN = USART1._UCSRnB._TXEN; + USART1._UCSRnB._TXEN = false; + } + if (funcSet.hasAnyFunc(eATmegaPinFunc::USART1_RXD, eATmegaPinFunc::USART1_CLK)) { + state._USART1_RXEN = USART1._UCSRnB._RXEN; + USART1._UCSRnB._RXEN = false; + } + if (funcSet.hasFunc(eATmegaPinFunc::TOC3C)) { + state._COM3C = TIMER3._TCCRnA._COMnC; + TIMER3._TCCRnA._COMnC = 0; + } + // There is an error in the technical reference manual signal mapping table + // of ATmega2560 where is says that pin 3 is mapped to OC3B, but the list + // says OC3A. + if (funcSet.hasFunc(eATmegaPinFunc::TOC3B)) { + state._COM3B = TIMER3._TCCRnA._COMnB; + TIMER3._TCCRnA._COMnB = 0; + } + if (funcSet.hasFunc(eATmegaPinFunc::TOC3A)) { + state._COM3A = TIMER3._TCCRnA._COMnA; + TIMER3._TCCRnA._COMnA = 0; + } + if (funcSet.hasAnyFunc(eATmegaPinFunc::USART0_RXD, eATmegaPinFunc::USART0_CLK)) { + state._USART0_RXEN = USART0._UCSRnB._RXEN; + USART0._UCSRnB._RXEN = false; + } + if (funcSet.hasAnyFunc(eATmegaPinFunc::USART0_TXD, eATmegaPinFunc::USART0_CLK)) { + state._USART0_TXEN = USART0._UCSRnB._TXEN; + USART0._UCSRnB._TXEN = false; + } + if (funcSet.hasAnyFunc(eATmegaPinFunc::PCI15, eATmegaPinFunc::PCI14, eATmegaPinFunc::PCI13, eATmegaPinFunc::PCI12, eATmegaPinFunc::PCI11, eATmegaPinFunc::PCI10, eATmegaPinFunc::PCI9, eATmegaPinFunc::PCI8)) { + state._PCIE1 = _PCICR._PCIE1; + _PCICR._PCIE1 = false; + } + if (funcSet.hasAnyFunc(eATmegaPinFunc::TOC0B)) { + state._COM0B = TIMER0._TCCRnA._COMnB; + TIMER0._TCCRnA._COMnB = 0; + } + if (funcSet.hasAnyFunc(eATmegaPinFunc::TOSC1, eATmegaPinFunc::TOSC2)) { + state._AS2 = _ASSR._AS2; + _ASSR._AS2 = false; + } + if (funcSet.hasFunc(eATmegaPinFunc::TOC2B)) { + state._COM2B = _TIMER2._TCCRnA._COMnB; + _TIMER2._TCCRnA._COMnB = 0; + } + if (funcSet.hasFunc(eATmegaPinFunc::TOC4C)) { + state._COM4C = TIMER4._TCCRnA._COMnC; + TIMER4._TCCRnA._COMnC = 0; + } + if (funcSet.hasFunc(eATmegaPinFunc::TOC4B)) { + state._COM4B = TIMER4._TCCRnA._COMnB; + TIMER4._TCCRnA._COMnB = 0; + } + if (funcSet.hasFunc(eATmegaPinFunc::TOC4A)) { + state._COM4A = TIMER4._TCCRnA._COMnA; + TIMER4._TCCRnA._COMnA = 0; + } + if (funcSet.hasAnyFunc(eATmegaPinFunc::USART2_RXD, eATmegaPinFunc::USART2_CLK)) { + state._USART2_RXEN = USART2._UCSRnB._RXEN; + USART2._UCSRnB._RXEN = false; + } + if (funcSet.hasAnyFunc(eATmegaPinFunc::USART2_TXD, eATmegaPinFunc::USART2_CLK)) { + state._USART2_TXEN = USART2._UCSRnB._TXEN; + USART2._UCSRnB._TXEN = false; + } + if (funcSet.hasAnyFunc(eATmegaPinFunc::USART3_TXD, eATmegaPinFunc::USART3_CLK)) { + state._USART3_RXEN = USART3._UCSRnB._RXEN; + USART3._UCSRnB._RXEN = false; + } + if (funcSet.hasAnyFunc(eATmegaPinFunc::USART3_TXD, eATmegaPinFunc::USART3_CLK)) { + state._USART3_TXEN = USART3._UCSRnB._TXEN; + USART3._UCSRnB._TXEN = false; + } + if (funcSet.hasAnyFunc( + eATmegaPinFunc::PCI23, eATmegaPinFunc::PCI22, eATmegaPinFunc::PCI21, eATmegaPinFunc::PCI20, eATmegaPinFunc::PCI19, eATmegaPinFunc::PCI18, eATmegaPinFunc::PCI17, eATmegaPinFunc::PCI16 + )) { + state._PCIE2 = _PCICR._PCIE2; + _PCICR._PCIE2 = false; + } + if (funcSet.hasFunc(eATmegaPinFunc::TOC5C)) { + state._COM5C = TIMER5._TCCRnA._COMnC; + TIMER5._TCCRnA._COMnC = 0; + } + if (funcSet.hasFunc(eATmegaPinFunc::TOC5B)) { + state._COM5B = TIMER5._TCCRnA._COMnB; + TIMER5._TCCRnA._COMnB = 0; + } + if (funcSet.hasFunc(eATmegaPinFunc::TOC5A)) { + state._COM5A = TIMER5._TCCRnA._COMnA; + TIMER5._TCCRnA._COMnA = 0; + } + #elif defined(__AVR_TRM02__) + if (funcSet.hasAnyFunc(eATmegaPinFunc::PCI7, eATmegaPinFunc::PCI6, eATmegaPinFunc::PCI5, eATmegaPinFunc::PCI4, eATmegaPinFunc::PCI3, eATmegaPinFunc::PCI2, eATmegaPinFunc::PCI1, eATmegaPinFunc::PCI0)) { + state._PCIE0 = _PCICR._PCIE0; + _PCICR._PCIE0 = false; + } + if (funcSet.hasFunc(eATmegaPinFunc::ADC7)) { + state._ADC7D = _DIDR0._ADC7D; + _DIDR0._ADC7D = false; + } + if (funcSet.hasFunc(eATmegaPinFunc::ADC6)) { + state._ADC6D = _DIDR0._ADC6D; + _DIDR0._ADC6D = false; + } + if (funcSet.hasFunc(eATmegaPinFunc::ADC5)) { + state._ADC5D = _DIDR0._ADC5D; + _DIDR0._ADC5D = false; + } + if (funcSet.hasFunc(eATmegaPinFunc::ADC4)) { + state._ADC4D = _DIDR0._ADC4D; + _DIDR0._ADC4D = false; + } + if (funcSet.hasFunc(eATmegaPinFunc::ADC3)) { + state._ADC3D = _DIDR0._ADC3D; + _DIDR0._ADC3D = false; + } + if (funcSet.hasFunc(eATmegaPinFunc::ADC2)) { + state._ADC2D = _DIDR0._ADC2D; + _DIDR0._ADC2D = false; + } + if (funcSet.hasFunc(eATmegaPinFunc::ADC1)) { + state._ADC1D = _DIDR0._ADC1D; + _DIDR0._ADC1D = false; + } + if (funcSet.hasFunc(eATmegaPinFunc::ADC0)) { + state._ADC0D = _DIDR0._ADC0D; + _DIDR0._ADC0D = false; + } + if (funcSet.hasAnyFunc(eATmegaPinFunc::PCI15, eATmegaPinFunc::PCI14, eATmegaPinFunc::PCI13, eATmegaPinFunc::PCI12, eATmegaPinFunc::PCI11, eATmegaPinFunc::PCI10, eATmegaPinFunc::PCI9, eATmegaPinFunc::PCI8)) { + state._PCIE1 = _PCICR._PCIE1; + _PCICR._PCIE1 = false; + } + if (funcSet.hasAnyFunc(eATmegaPinFunc::SPI_SCK, eATmegaPinFunc::SPI_MISO, eATmegaPinFunc::SPI_MOSI, eATmegaPinFunc::SPI_CS)) { + state._SPE = _SPCR._SPE; + _SPCR._SPE = false; + } + if (funcSet.hasFunc(eATmegaPinFunc::TOC0A)) { + state._COM0A = TIMER0._TCCRnA._COMnA; + TIMER0._TCCRnA._COMnA = 0; + } + if (funcSet.hasFunc(eATmegaPinFunc::TOC0B)) { + state._COM0B = TIMER0._TCCRnA._COMnB; + TIMER0._TCCRnA._COMnB = 0; + } + if (funcSet.hasAnyFunc(eATmegaPinFunc::TOSC1, eATmegaPinFunc::TOSC2)) { + state._AS2 = _ASSR._AS2; + _ASSR._AS2 = false; + } + if (funcSet.hasAnyFunc(eATmegaPinFunc::PCI23, eATmegaPinFunc::PCI22, eATmegaPinFunc::PCI21, eATmegaPinFunc::PCI20, eATmegaPinFunc::PCI19, eATmegaPinFunc::PCI18, eATmegaPinFunc::PCI17, eATmegaPinFunc::PCI16)) { + state._PCIE2 = _PCICR._PCIE2; + _PCICR._PCIE2 = false; + } + if (funcSet.hasAnyFunc(eATmegaPinFunc::PCI31, eATmegaPinFunc::PCI30, eATmegaPinFunc::PCI29, eATmegaPinFunc::PCI28, eATmegaPinFunc::PCI27, eATmegaPinFunc::PCI26, eATmegaPinFunc::PCI25, eATmegaPinFunc::PCI24)) { + state._PCIE3 = _PCICR._PCIE3; + _PCICR._PCIE3 = false; + } + if (funcSet.hasFunc(eATmegaPinFunc::TOC2A)) { + state._COM2A = _TIMER2._TCCRnA._COMnA; + _TIMER2._TCCRnA._COMnA = 0; + } + if (funcSet.hasFunc(eATmegaPinFunc::TOC2B)) { + state._COM2B = _TIMER2._TCCRnA._COMnB; + _TIMER2._TCCRnA._COMnB = 0; + } + if (funcSet.hasFunc(eATmegaPinFunc::TOC1A)) { + state._COM1A = TIMER1._TCCRnA._COMnA; + TIMER1._TCCRnA._COMnA = 0; + } + if (funcSet.hasFunc(eATmegaPinFunc::TOC1B)) { + state._COM1B = TIMER1._TCCRnA._COMnB; + TIMER1._TCCRnA._COMnB = 0; + } + if (funcSet.hasFunc(eATmegaPinFunc::USART1_TXD)) { + state._USART1_TXEN = USART1._UCSRnB._TXEN; + USART1._UCSRnB._TXEN = false; + } + if (funcSet.hasFunc(eATmegaPinFunc::USART1_RXD)) { + state._USART1_RXEN = USART1._UCSRnB._RXEN; + USART1._UCSRnB._RXEN = false; + } + if (funcSet.hasFunc(eATmegaPinFunc::USART0_TXD)) { + state._USART0_TXEN = USART0._UCSRnB._TXEN; + USART0._UCSRnB._TXEN = false; + } + // There is a bug in the ATmega164A technical reference manual where + // it says that pin 0 is mapped to USART1 RXD in the signal mapping table + // but the associated list says USART0 RXD. + if (funcSet.hasFunc(eATmegaPinFunc::USART0_RXD)) { + state._USART0_RXEN = USART0._UCSRnB._RXEN; + USART0._UCSRnB._RXEN = false; + } + #elif defined(__AVR_TRM03__) + if (funcSet.hasAnyFunc(eATmegaPinFunc::PCI7, eATmegaPinFunc::PCI6, eATmegaPinFunc::PCI5, eATmegaPinFunc::PCI4, eATmegaPinFunc::PCI3, eATmegaPinFunc::PCI2, eATmegaPinFunc::PCI1, eATmegaPinFunc::PCI0)) { + state._PCIE0 = _PCICR._PCIE0; + _PCICR._PCIE0 = false; + } + if (funcSet.hasAnyFunc(eATmegaPinFunc::TOSC1, eATmegaPinFunc::TOSC2)) { + state._AS2 = _ASSR._AS2; + _ASSR._AS2 = false; + } + if (funcSet.hasAnyFunc(eATmegaPinFunc::SPI_SCK, eATmegaPinFunc::SPI_MISO, eATmegaPinFunc::SPI_MOSI, eATmegaPinFunc::SPI_CS)) { + state._SPE = _SPCR._SPE; + _SPCR._SPE = false; + } + if (funcSet.hasFunc(eATmegaPinFunc::TOC2A)) { + state._COM2A = _TIMER2._TCCRnA._COMnA; + _TIMER2._TCCRnA._COMnA = 0; + } + if (funcSet.hasFunc(eATmegaPinFunc::TOC1B)) { + state._COM1B = TIMER1._TCCRnA._COMnB; + TIMER1._TCCRnA._COMnB = 0; + } + if (funcSet.hasFunc(eATmegaPinFunc::TOC1A)) { + state._COM1A = TIMER1._TCCRnA._COMnA; + TIMER1._TCCRnA._COMnA = 0; + } + if (funcSet.hasAnyFunc(eATmegaPinFunc::PCI14, eATmegaPinFunc::PCI13, eATmegaPinFunc::PCI12, eATmegaPinFunc::PCI11, eATmegaPinFunc::PCI10, eATmegaPinFunc::PCI9, eATmegaPinFunc::PCI8)) { + state._PCIE1 = _PCICR._PCIE1; + _PCICR._PCIE1 = false; + } + if (funcSet.hasAnyFunc(eATmegaPinFunc::TWI_CLK, eATmegaPinFunc::TWI_SDA)) { + state._TWEN = _TWCR._TWEN; + _TWCR._TWEN = false; + } + if (funcSet.hasFunc(eATmegaPinFunc::ADC5)) { + state._ADC5D = _DIDR0._ADC5D; + _DIDR0._ADC5D = false; + } + if (funcSet.hasFunc(eATmegaPinFunc::ADC4)) { + state._ADC4D = _DIDR0._ADC4D; + _DIDR0._ADC4D = false; + } + if (funcSet.hasFunc(eATmegaPinFunc::ADC3)) { + state._ADC3D = _DIDR0._ADC3D; + _DIDR0._ADC3D = false; + } + if (funcSet.hasFunc(eATmegaPinFunc::ADC2)) { + state._ADC2D = _DIDR0._ADC2D; + _DIDR0._ADC2D = false; + } + if (funcSet.hasFunc(eATmegaPinFunc::ADC1)) { + state._ADC1D = _DIDR0._ADC1D; + _DIDR0._ADC1D = false; + } + if (funcSet.hasFunc(eATmegaPinFunc::ADC0)) { + state._ADC0D = _DIDR0._ADC0D; + _DIDR0._ADC0D = false; + } + // There is a bug in the ATmega48A technical reference manual where pin 2 + // is said to be mapped to PCIE1 but logically it should be PCIE2 instead. + // The real mapping can be read in the documentation of the PCICR register. + if (funcSet.hasAnyFunc(eATmegaPinFunc::PCI23, eATmegaPinFunc::PCI22, eATmegaPinFunc::PCI21, eATmegaPinFunc::PCI20, eATmegaPinFunc::PCI19, eATmegaPinFunc::PCI18, eATmegaPinFunc::PCI17, eATmegaPinFunc::PCI16)) { + state._PCIE2 = _PCICR._PCIE2; + _PCICR._PCIE2 = false; + } + if (funcSet.hasFunc(eATmegaPinFunc::TOC0A)) { + state._COM0A = TIMER0._TCCRnA._COMnA; + TIMER0._TCCRnA._COMnA = 0; + } + if (funcSet.hasFunc(eATmegaPinFunc::TOC0B)) { + state._COM0B = TIMER0._TCCRnA._COMnB; + TIMER0._TCCRnA._COMnB = 0; + } + if (funcSet.hasFunc(eATmegaPinFunc::USART_CLK)) { + state._UMSEL = USART0._UCSRnC._UMSEL; + USART0._UCSRnC._UMSEL = 0; + } + if (funcSet.hasFunc(eATmegaPinFunc::TOC2B)) { + state._COM2B = _TIMER2._TCCRnA._COMnB; + _TIMER2._TCCRnA._COMnB = 0; + } + if (funcSet.hasFunc(eATmegaPinFunc::USART_TXD)) { + state._USART0_TXEN = USART0._UCSRnB._TXEN; + USART0._UCSRnB._TXEN = false; + } + if (funcSet.hasFunc(eATmegaPinFunc::USART_RXD)) { + state._USART0_RXEN = USART0._UCSRnB._RXEN; + USART0._UCSRnB._RXEN = false; + } + #elif defined(__AVR_TRM04__) + if (funcSet.hasAnyFunc( + eATmegaPinFunc::EXTMEM_AD15, eATmegaPinFunc::EXTMEM_AD14, eATmegaPinFunc::EXTMEM_AD13, eATmegaPinFunc::EXTMEM_AD12, eATmegaPinFunc::EXTMEM_AD11, eATmegaPinFunc::EXTMEM_AD10, eATmegaPinFunc::EXTMEM_AD9, eATmegaPinFunc::EXTMEM_AD8, + eATmegaPinFunc::EXTMEM_AD7, eATmegaPinFunc::EXTMEM_AD6, eATmegaPinFunc::EXTMEM_AD5, eATmegaPinFunc::EXTMEM_AD4, eATmegaPinFunc::EXTMEM_AD3, eATmegaPinFunc::EXTMEM_AD2, eATmegaPinFunc::EXTMEM_AD1, eATmegaPinFunc::EXTMEM_AD0, + eATmegaPinFunc::EXTMEM_ALE, eATmegaPinFunc::EXTMEM_RD, eATmegaPinFunc::EXTMEM_WR + )) { + state._SRE = _XMCRA._SRE; + _XMCRA._SRE = false; + } + if (funcSet.hasFunc(eATmegaPinFunc::TOC1C)) { + state._COM1C = TIMER1._TCCRnA._COMnC; + TIMER1._TCCRnA._COMnC = 0; + } + if (funcSet.hasFunc(eATmegaPinFunc::TOC1B)) { + state._COM1B = TIMER1._TCCRnA._COMnB; + TIMER1._TCCRnA._COMnB = 0; + } + if (funcSet.hasFunc(eATmegaPinFunc::TOC1A)) { + state._COM1A = TIMER1._TCCRnA._COMnA; + TIMER1._TCCRnA._COMnA = 0; + } + if (funcSet.hasFunc(eATmegaPinFunc::TOC2A)) { + state._COM2A = _TIMER2._TCCRnA._COMnA; + _TIMER2._TCCRnA._COMnA = 0; + } + if (funcSet.hasAnyFunc(eATmegaPinFunc::SPI_MISO, eATmegaPinFunc::SPI_MOSI, eATmegaPinFunc::SPI_SCK, eATmegaPinFunc::SPI_CS)) { + state._SPE = _SPCR._SPE; + _SPCR._SPE = false; + } + if (funcSet.hasAnyFunc(eATmegaPinFunc::PCI7, eATmegaPinFunc::PCI6, eATmegaPinFunc::PCI5, eATmegaPinFunc::PCI4, eATmegaPinFunc::PCI3, eATmegaPinFunc::PCI2, eATmegaPinFunc::PCI1, eATmegaPinFunc::PCI0)) { + state._PCIE0 = _PCICR._PCIE0; + _PCICR._PCIE0 = false; + } + if (funcSet.hasAnyFunc(eATmegaPinFunc::USART1_CLK, eATmegaPinFunc::USART1_TXD)) { + state._USART1_TXEN = USART1._UCSRnB._TXEN; + USART1._UCSRnB._TXEN = false; + } + if (funcSet.hasAnyFunc(eATmegaPinFunc::USART1_CLK, eATmegaPinFunc::USART1_RXD)) { + state._USART1_RXEN = USART1._UCSRnB._RXEN; + USART1._UCSRnB._RXEN = false; + } + if (funcSet.hasAnyFunc(eATmegaPinFunc::TWI_SDA, eATmegaPinFunc::TWI_CLK)) { + state._TWEN = _TWCR._TWEN; + _TWCR._TWEN = false; + } + if (funcSet.hasFunc(eATmegaPinFunc::TOC2B)) { + state._COM2B = _TIMER2._TCCRnA._COMnB; + _TIMER2._TCCRnA._COMnB = 0; + } + if (funcSet.hasFunc(eATmegaPinFunc::TOC0B)) { + state._COM0B = TIMER0._TCCRnA._COMnB; + TIMER0._TCCRnA._COMnB = 0; + } + if (funcSet.hasFunc(eATmegaPinFunc::EINT3)) { + state._INT3 = _EIMSK._INT3; + _EIMSK._INT3 = false; + } + if (funcSet.hasFunc(eATmegaPinFunc::EINT2)) { + state._INT2 = _EIMSK._INT2; + _EIMSK._INT2 = false; + } + if (funcSet.hasFunc(eATmegaPinFunc::EINT1)) { + state._INT1 = _EIMSK._INT1; + _EIMSK._INT1 = false; + } + if (funcSet.hasFunc(eATmegaPinFunc::EINT0)) { + state._INT0 = _EIMSK._INT0; + _EIMSK._INT0 = false; + } + if (funcSet.hasFunc(eATmegaPinFunc::UVCON)) { + state._UVCONE = _UHWCON._UVCONE; + _UHWCON._UVCONE = false; + } + if (funcSet.hasFunc(eATmegaPinFunc::UID)) { + state._UIDE = _UHWCON._UIDE; + _UHWCON._UIDE = false; + } + if (funcSet.hasFunc(eATmegaPinFunc::EINT7)) { + state._INT7 = _EIMSK._INT7; + _EIMSK._INT7 = false; + } + if (funcSet.hasFunc(eATmegaPinFunc::EINT6)) { + state._INT6 = _EIMSK._INT6; + _EIMSK._INT6 = false; + } + if (funcSet.hasFunc(eATmegaPinFunc::EINT5)) { + state._INT5 = _EIMSK._INT5; + _EIMSK._INT5 = false; + } + if (funcSet.hasFunc(eATmegaPinFunc::EINT4)) { + state._INT4 = _EIMSK._INT4; + _EIMSK._INT4 = false; + } + #elif defined(__AVR_TRM05__) + if (funcSet.hasAnyFunc(eATmegaPinFunc::PCI7, eATmegaPinFunc::PCI6, eATmegaPinFunc::PCI5, eATmegaPinFunc::PCI4, eATmegaPinFunc::PCI3, eATmegaPinFunc::PCI2, eATmegaPinFunc::PCI1, eATmegaPinFunc::PCI0)) { + state._PCIE0 = _PCICR._PCIE0; + _PCICR._PCIE0 = false; + } + if (funcSet.hasAnyFunc(eATmegaPinFunc::PCI15, eATmegaPinFunc::PCI14, eATmegaPinFunc::PCI13, eATmegaPinFunc::PCI12, eATmegaPinFunc::PCI11, eATmegaPinFunc::PCI10, eATmegaPinFunc::PCI9, eATmegaPinFunc::PCI8)) { + state._PCIE1 = _PCICR._PCIE1; + _PCICR._PCIE1 = false; + } + if (funcSet.hasAnyFunc(eATmegaPinFunc::PCI23, eATmegaPinFunc::PCI22, eATmegaPinFunc::PCI21, eATmegaPinFunc::PCI20, eATmegaPinFunc::PCI19, eATmegaPinFunc::PCI18, eATmegaPinFunc::PCI17, eATmegaPinFunc::PCI16)) { + state._PCIE2 = _PCICR._PCIE2; + _PCICR._PCIE2 = false; + } + if (funcSet.hasAnyFunc(eATmegaPinFunc::PCI31, eATmegaPinFunc::PCI30, eATmegaPinFunc::PCI29, eATmegaPinFunc::PCI28, eATmegaPinFunc::PCI27, eATmegaPinFunc::PCI26, eATmegaPinFunc::PCI25, eATmegaPinFunc::PCI24)) { + state._PCIE3 = _PCICR._PCIE3; + _PCICR._PCIE3 = false; + } + if (funcSet.hasAnyFunc(eATmegaPinFunc::SPI_SCK, eATmegaPinFunc::SPI_MISO, eATmegaPinFunc::SPI_MOSI, eATmegaPinFunc::SPI_CS)) { + state._SPE = _SPCR._SPE; + _SPCR._SPE = false; + } + if (funcSet.hasFunc(eATmegaPinFunc::TOC0B)) { + state._COM0B = TIMER0._TCCRnA._COMnB; + TIMER0._TCCRnA._COMnB = 0; + } + if (funcSet.hasFunc(eATmegaPinFunc::TOC0A)) { + state._COM0A = TIMER0._TCCRnA._COMnA; + TIMER0._TCCRnA._COMnA = 0; + } + if (funcSet.hasFunc(eATmegaPinFunc::TOC2A)) { + state._COM2A = _TIMER2._TCCRnA._COMnA; + _TIMER2._TCCRnA._COMnA = 0; + } + if (funcSet.hasFunc(eATmegaPinFunc::TOC2B)) { + state._COM2B = _TIMER2._TCCRnA._COMnB; + _TIMER2._TCCRnA._COMnB = 0; + } + if (funcSet.hasFunc(eATmegaPinFunc::TOC1A)) { + state._COM1A = TIMER1._TCCRnA._COMnA; + TIMER1._TCCRnA._COMnA = 0; + } + if (funcSet.hasFunc(eATmegaPinFunc::TOC1B)) { + state._COM1B = TIMER1._TCCRnA._COMnB; + TIMER1._TCCRnA._COMnB = 0; + } + if (funcSet.hasAnyFunc(eATmegaPinFunc::TWI_CLK, eATmegaPinFunc::TWI_SDA)) { + state._TWEN = _TWCR._TWEN; + _TWCR._TWEN = false; + } + if (funcSet.hasFunc(eATmegaPinFunc::EINT2)) { + state._INT2 = _EIMSK._INT2; + _EIMSK._INT2 = false; + } + if (funcSet.hasFunc(eATmegaPinFunc::EINT1)) { + state._INT1 = _EIMSK._INT1; + _EIMSK._INT1 = false; + } + if (funcSet.hasFunc(eATmegaPinFunc::EINT0)) { + state._INT0 = _EIMSK._INT0; + _EIMSK._INT0 = false; + } + if (funcSet.hasAnyFunc(eATmegaPinFunc::USART0_CLK, eATmegaPinFunc::USART0_TXD)) { + state._TXEN0 = USART0._UCSRnB._TXEN; + USART0._UCSRnB._TXEN = false; + } + if (funcSet.hasAnyFunc(eATmegaPinFunc::USART0_CLK, eATmegaPinFunc::USART0_RXD)) { + state._RXEN0 = USART0._UCSRnB._RXEN; + USART0._UCSRnB._RXEN = false; + } + if (funcSet.hasAnyFunc(eATmegaPinFunc::USART1_CLK, eATmegaPinFunc::USART1_TXD)) { + state._TXEN1 = USART1._UCSRnB._TXEN; + USART1._UCSRnB._TXEN = false; + } + if (funcSet.hasAnyFunc(eATmegaPinFunc::USART1_CLK, eATmegaPinFunc::USART1_RXD)) { + state._RXEN1 = USART1._UCSRnB._RXEN; + USART1._UCSRnB._RXEN = false; + } + #endif + + return state; +} + +inline void _ATmega_restorePinAlternates(const ATmegaPinFuncSet& funcSet, const pin_dev_state_t& state) { + ATmegaPeripheralSet periSet; + periSet.fromPinFuncs(funcSet); + + ATmegaPeripheralPowerGate pgate(periSet); + + #ifdef __AVR_TRM01__ + // See page 75ff of ATmega2560 technical reference manual. + if (funcSet.hasAnyFunc( + eATmegaPinFunc::EXTMEM_AD15, eATmegaPinFunc::EXTMEM_AD14, eATmegaPinFunc::EXTMEM_AD13, eATmegaPinFunc::EXTMEM_AD12, eATmegaPinFunc::EXTMEM_AD11, eATmegaPinFunc::EXTMEM_AD10, eATmegaPinFunc::EXTMEM_AD9, eATmegaPinFunc::EXTMEM_AD8, + eATmegaPinFunc::EXTMEM_AD7, eATmegaPinFunc::EXTMEM_AD6, eATmegaPinFunc::EXTMEM_AD5, eATmegaPinFunc::EXTMEM_AD4, eATmegaPinFunc::EXTMEM_AD3, eATmegaPinFunc::EXTMEM_AD2, eATmegaPinFunc::EXTMEM_AD1, eATmegaPinFunc::EXTMEM_AD0, + eATmegaPinFunc::EXTMEM_ALE, eATmegaPinFunc::EXTMEM_RD, eATmegaPinFunc::EXTMEM_WR + )) { + _XMCRA._SRE = state._SRE; + } + if (funcSet.hasAnyFunc( + eATmegaPinFunc::PCI0, eATmegaPinFunc::PCI1, eATmegaPinFunc::PCI2, eATmegaPinFunc::PCI3, eATmegaPinFunc::PCI4, eATmegaPinFunc::PCI5, eATmegaPinFunc::PCI6, eATmegaPinFunc::PCI7 + )) { + _PCICR._PCIE0 = state._PCIE0; + } + if (funcSet.hasFunc(eATmegaPinFunc::TOC1C)) { + TIMER1._TCCRnA._COMnC = state._COM1C; + } + if (funcSet.hasFunc(eATmegaPinFunc::TOC1B)) { + TIMER1._TCCRnA._COMnB = state._COM1B; + } + if (funcSet.hasFunc(eATmegaPinFunc::TOC1A)) { + TIMER1._TCCRnA._COMnA = state._COM1A; + } + if (funcSet.hasFunc(eATmegaPinFunc::TOC2A)) { + _TIMER2._TCCRnA._COMnA = state._COM2A; + } + if (funcSet.hasAnyFunc(eATmegaPinFunc::USART1_TXD, eATmegaPinFunc::USART1_CLK)) { + USART1._UCSRnB._TXEN = state._USART1_TXEN; + } + if (funcSet.hasAnyFunc(eATmegaPinFunc::USART1_RXD, eATmegaPinFunc::USART1_CLK)) { + USART1._UCSRnB._RXEN = state._USART1_RXEN; + } + if (funcSet.hasFunc(eATmegaPinFunc::TOC3C)) { + TIMER3._TCCRnA._COMnC = state._COM3C; + } + // There is an error in the technical reference manual signal mapping table + // of ATmega2560 where is says that pin 3 is mapped to OC3B, but the list + // says OC3A. + if (funcSet.hasFunc(eATmegaPinFunc::TOC3B)) { + TIMER3._TCCRnA._COMnB = state._COM3B; + } + if (funcSet.hasFunc(eATmegaPinFunc::TOC3A)) { + TIMER3._TCCRnA._COMnA = state._COM3A; + } + if (funcSet.hasAnyFunc(eATmegaPinFunc::USART0_RXD, eATmegaPinFunc::USART0_CLK)) { + USART0._UCSRnB._RXEN = state._USART0_RXEN; + } + if (funcSet.hasAnyFunc(eATmegaPinFunc::USART0_TXD, eATmegaPinFunc::USART0_CLK)) { + USART0._UCSRnB._TXEN = state._USART0_TXEN; + } + if (funcSet.hasAnyFunc(eATmegaPinFunc::PCI15, eATmegaPinFunc::PCI14, eATmegaPinFunc::PCI13, eATmegaPinFunc::PCI12, eATmegaPinFunc::PCI11, eATmegaPinFunc::PCI10, eATmegaPinFunc::PCI9, eATmegaPinFunc::PCI8)) { + _PCICR._PCIE1 = state._PCIE1; + } + if (funcSet.hasAnyFunc(eATmegaPinFunc::TOC0B)) { + TIMER0._TCCRnA._COMnB = state._COM0B; + } + if (funcSet.hasAnyFunc(eATmegaPinFunc::TOSC1, eATmegaPinFunc::TOSC2)) { + _ASSR._AS2 = state._AS2; + } + if (funcSet.hasFunc(eATmegaPinFunc::TOC2B)) { + _TIMER2._TCCRnA._COMnB = state._COM2B; + } + if (funcSet.hasFunc(eATmegaPinFunc::TOC4C)) { + TIMER4._TCCRnA._COMnC = state._COM4C; + } + if (funcSet.hasFunc(eATmegaPinFunc::TOC4B)) { + TIMER4._TCCRnA._COMnB = state._COM4B; + } + if (funcSet.hasFunc(eATmegaPinFunc::TOC4A)) { + TIMER4._TCCRnA._COMnA = state._COM4A; + } + if (funcSet.hasAnyFunc(eATmegaPinFunc::USART2_RXD, eATmegaPinFunc::USART2_CLK)) { + USART2._UCSRnB._RXEN = state._USART2_RXEN; + } + if (funcSet.hasAnyFunc(eATmegaPinFunc::USART2_TXD, eATmegaPinFunc::USART2_CLK)) { + USART2._UCSRnB._TXEN = state._USART2_TXEN; + } + if (funcSet.hasAnyFunc(eATmegaPinFunc::USART3_TXD, eATmegaPinFunc::USART3_CLK)) { + USART3._UCSRnB._RXEN = state._USART3_RXEN; + } + if (funcSet.hasAnyFunc(eATmegaPinFunc::USART3_TXD, eATmegaPinFunc::USART3_CLK)) { + USART3._UCSRnB._TXEN = state._USART3_TXEN; + } + if (funcSet.hasAnyFunc( + eATmegaPinFunc::PCI23, eATmegaPinFunc::PCI22, eATmegaPinFunc::PCI21, eATmegaPinFunc::PCI20, eATmegaPinFunc::PCI19, eATmegaPinFunc::PCI18, eATmegaPinFunc::PCI17, eATmegaPinFunc::PCI16 + )) { + _PCICR._PCIE2 = state._PCIE2; + } + if (funcSet.hasFunc(eATmegaPinFunc::TOC5C)) { + TIMER5._TCCRnA._COMnC = state._COM5C; + } + if (funcSet.hasFunc(eATmegaPinFunc::TOC5B)) { + TIMER5._TCCRnA._COMnB = state._COM5B; + } + if (funcSet.hasFunc(eATmegaPinFunc::TOC5A)) { + TIMER5._TCCRnA._COMnA = state._COM5A; + } + #elif defined(__AVR_TRM02__) + if (funcSet.hasAnyFunc(eATmegaPinFunc::PCI7, eATmegaPinFunc::PCI6, eATmegaPinFunc::PCI5, eATmegaPinFunc::PCI4, eATmegaPinFunc::PCI3, eATmegaPinFunc::PCI2, eATmegaPinFunc::PCI1, eATmegaPinFunc::PCI0)) { + _PCICR._PCIE0 = state._PCIE0; + } + if (funcSet.hasFunc(eATmegaPinFunc::ADC7)) { + _DIDR0._ADC7D = state._ADC7D; + } + if (funcSet.hasFunc(eATmegaPinFunc::ADC6)) { + _DIDR0._ADC6D = state._ADC6D; + } + if (funcSet.hasFunc(eATmegaPinFunc::ADC5)) { + _DIDR0._ADC5D = state._ADC5D; + } + if (funcSet.hasFunc(eATmegaPinFunc::ADC4)) { + _DIDR0._ADC4D = state._ADC4D; + } + if (funcSet.hasFunc(eATmegaPinFunc::ADC3)) { + _DIDR0._ADC3D = state._ADC3D; + } + if (funcSet.hasFunc(eATmegaPinFunc::ADC2)) { + _DIDR0._ADC2D = state._ADC2D; + } + if (funcSet.hasFunc(eATmegaPinFunc::ADC1)) { + _DIDR0._ADC1D = state._ADC1D; + } + if (funcSet.hasFunc(eATmegaPinFunc::ADC0)) { + _DIDR0._ADC0D = state._ADC0D; + } + if (funcSet.hasAnyFunc(eATmegaPinFunc::PCI15, eATmegaPinFunc::PCI14, eATmegaPinFunc::PCI13, eATmegaPinFunc::PCI12, eATmegaPinFunc::PCI11, eATmegaPinFunc::PCI10, eATmegaPinFunc::PCI9, eATmegaPinFunc::PCI8)) { + _PCICR._PCIE1 = state._PCIE1; + } + if (funcSet.hasAnyFunc(eATmegaPinFunc::SPI_SCK, eATmegaPinFunc::SPI_MISO, eATmegaPinFunc::SPI_MOSI, eATmegaPinFunc::SPI_CS)) { + _SPCR._SPE = state._SPE; + } + if (funcSet.hasFunc(eATmegaPinFunc::TOC0A)) { + TIMER0._TCCRnA._COMnA = state._COM0A; + } + if (funcSet.hasFunc(eATmegaPinFunc::TOC0B)) { + TIMER0._TCCRnA._COMnB = state._COM0B; + } + if (funcSet.hasAnyFunc(eATmegaPinFunc::TOSC1, eATmegaPinFunc::TOSC2)) { + _ASSR._AS2 = state._AS2; + } + if (funcSet.hasAnyFunc(eATmegaPinFunc::PCI23, eATmegaPinFunc::PCI22, eATmegaPinFunc::PCI21, eATmegaPinFunc::PCI20, eATmegaPinFunc::PCI19, eATmegaPinFunc::PCI18, eATmegaPinFunc::PCI17, eATmegaPinFunc::PCI16)) { + _PCICR._PCIE2 = state._PCIE2; + } + if (funcSet.hasAnyFunc(eATmegaPinFunc::PCI31, eATmegaPinFunc::PCI30, eATmegaPinFunc::PCI29, eATmegaPinFunc::PCI28, eATmegaPinFunc::PCI27, eATmegaPinFunc::PCI26, eATmegaPinFunc::PCI25, eATmegaPinFunc::PCI24)) { + _PCICR._PCIE3 = state._PCIE3; + } + if (funcSet.hasFunc(eATmegaPinFunc::TOC2A)) { + _TIMER2._TCCRnA._COMnA = state._COM2A; + } + if (funcSet.hasFunc(eATmegaPinFunc::TOC2B)) { + _TIMER2._TCCRnA._COMnB = state._COM2B; + } + if (funcSet.hasFunc(eATmegaPinFunc::TOC1A)) { + TIMER1._TCCRnA._COMnA = state._COM1A; + } + if (funcSet.hasFunc(eATmegaPinFunc::TOC1B)) { + TIMER1._TCCRnA._COMnB = state._COM1B; + } + if (funcSet.hasFunc(eATmegaPinFunc::USART1_TXD)) { + USART1._UCSRnB._TXEN = state._USART1_TXEN; + } + if (funcSet.hasFunc(eATmegaPinFunc::USART1_RXD)) { + USART1._UCSRnB._RXEN = state._USART1_RXEN; + } + if (funcSet.hasFunc(eATmegaPinFunc::USART0_TXD)) { + USART0._UCSRnB._TXEN = state._USART0_TXEN; + } + // There is a bug in the ATmega164A technical reference manual where + // it says that pin 0 is mapped to USART1 RXD in the signal mapping table + // but the associated list says USART0 RXD. + if (funcSet.hasFunc(eATmegaPinFunc::USART0_RXD)) { + USART0._UCSRnB._RXEN = state._USART0_RXEN; + } + #elif defined(__AVR_TRM03__) + if (funcSet.hasAnyFunc(eATmegaPinFunc::PCI7, eATmegaPinFunc::PCI6, eATmegaPinFunc::PCI5, eATmegaPinFunc::PCI4, eATmegaPinFunc::PCI3, eATmegaPinFunc::PCI2, eATmegaPinFunc::PCI1, eATmegaPinFunc::PCI0)) { + _PCICR._PCIE0 = state._PCIE0; + } + if (funcSet.hasAnyFunc(eATmegaPinFunc::TOSC1, eATmegaPinFunc::TOSC2)) { + _ASSR._AS2 = state._AS2; + } + if (funcSet.hasAnyFunc(eATmegaPinFunc::SPI_SCK, eATmegaPinFunc::SPI_MISO, eATmegaPinFunc::SPI_MOSI, eATmegaPinFunc::SPI_CS)) { + _SPCR._SPE = state._SPE; + } + if (funcSet.hasFunc(eATmegaPinFunc::TOC2A)) { + _TIMER2._TCCRnA._COMnA = state._COM2A; + } + if (funcSet.hasFunc(eATmegaPinFunc::TOC1B)) { + TIMER1._TCCRnA._COMnB = state._COM1B; + } + if (funcSet.hasFunc(eATmegaPinFunc::TOC1A)) { + TIMER1._TCCRnA._COMnA = state._COM1A; + } + if (funcSet.hasAnyFunc(eATmegaPinFunc::PCI14, eATmegaPinFunc::PCI13, eATmegaPinFunc::PCI12, eATmegaPinFunc::PCI11, eATmegaPinFunc::PCI10, eATmegaPinFunc::PCI9, eATmegaPinFunc::PCI8)) { + _PCICR._PCIE1 = state._PCIE1; + } + if (funcSet.hasAnyFunc(eATmegaPinFunc::TWI_CLK, eATmegaPinFunc::TWI_SDA)) { + _TWCR._TWEN = state._TWEN; + } + if (funcSet.hasFunc(eATmegaPinFunc::ADC5)) { + _DIDR0._ADC5D = state._ADC5D; + } + if (funcSet.hasFunc(eATmegaPinFunc::ADC4)) { + _DIDR0._ADC4D = state._ADC4D; + } + if (funcSet.hasFunc(eATmegaPinFunc::ADC3)) { + _DIDR0._ADC3D = state._ADC3D; + } + if (funcSet.hasFunc(eATmegaPinFunc::ADC2)) { + _DIDR0._ADC2D = state._ADC2D; + } + if (funcSet.hasFunc(eATmegaPinFunc::ADC1)) { + _DIDR0._ADC1D = state._ADC1D; + } + if (funcSet.hasFunc(eATmegaPinFunc::ADC0)) { + _DIDR0._ADC0D = state._ADC0D; + } + // There is a bug in the ATmega48A technical reference manual where pin 2 + // is said to be mapped to PCIE1 but logically it should be PCIE2 instead. + // The real mapping can be read in the documentation of the PCICR register. + if (funcSet.hasAnyFunc(eATmegaPinFunc::PCI23, eATmegaPinFunc::PCI22, eATmegaPinFunc::PCI21, eATmegaPinFunc::PCI20, eATmegaPinFunc::PCI19, eATmegaPinFunc::PCI18, eATmegaPinFunc::PCI17, eATmegaPinFunc::PCI16)) { + _PCICR._PCIE2 = state._PCIE2; + } + if (funcSet.hasFunc(eATmegaPinFunc::TOC0A)) { + TIMER0._TCCRnA._COMnA = state._COM0A; + } + if (funcSet.hasFunc(eATmegaPinFunc::TOC0B)) { + TIMER0._TCCRnA._COMnB = state._COM0B; + } + if (funcSet.hasFunc(eATmegaPinFunc::USART_CLK)) { + USART0._UCSRnC._UMSEL = state._UMSEL; + } + if (funcSet.hasFunc(eATmegaPinFunc::TOC2B)) { + _TIMER2._TCCRnA._COMnB = state._COM2B; + } + if (funcSet.hasFunc(eATmegaPinFunc::USART_TXD)) { + USART0._UCSRnB._TXEN = state._USART0_TXEN; + } + if (funcSet.hasFunc(eATmegaPinFunc::USART_RXD)) { + USART0._UCSRnB._RXEN = state._USART0_RXEN; + } + #elif defined(__AVR_TRM04__) + if (funcSet.hasAnyFunc( + eATmegaPinFunc::EXTMEM_AD15, eATmegaPinFunc::EXTMEM_AD14, eATmegaPinFunc::EXTMEM_AD13, eATmegaPinFunc::EXTMEM_AD12, eATmegaPinFunc::EXTMEM_AD11, eATmegaPinFunc::EXTMEM_AD10, eATmegaPinFunc::EXTMEM_AD9, eATmegaPinFunc::EXTMEM_AD8, + eATmegaPinFunc::EXTMEM_AD7, eATmegaPinFunc::EXTMEM_AD6, eATmegaPinFunc::EXTMEM_AD5, eATmegaPinFunc::EXTMEM_AD4, eATmegaPinFunc::EXTMEM_AD3, eATmegaPinFunc::EXTMEM_AD2, eATmegaPinFunc::EXTMEM_AD1, eATmegaPinFunc::EXTMEM_AD0, + eATmegaPinFunc::EXTMEM_ALE, eATmegaPinFunc::EXTMEM_RD, eATmegaPinFunc::EXTMEM_WR + )) { + _XMCRA._SRE = state._SRE; + } + if (funcSet.hasFunc(eATmegaPinFunc::TOC1C)) { + TIMER1._TCCRnA._COMnC = state._COM1C; + } + if (funcSet.hasFunc(eATmegaPinFunc::TOC1B)) { + TIMER1._TCCRnA._COMnB = state._COM1B; + } + if (funcSet.hasFunc(eATmegaPinFunc::TOC1A)) { + TIMER1._TCCRnA._COMnA = state._COM1A; + } + if (funcSet.hasFunc(eATmegaPinFunc::TOC2A)) { + _TIMER2._TCCRnA._COMnA = state._COM2A; + } + if (funcSet.hasAnyFunc(eATmegaPinFunc::SPI_MISO, eATmegaPinFunc::SPI_MOSI, eATmegaPinFunc::SPI_SCK, eATmegaPinFunc::SPI_CS)) { + _SPCR._SPE = state._SPE; + } + if (funcSet.hasAnyFunc(eATmegaPinFunc::PCI7, eATmegaPinFunc::PCI6, eATmegaPinFunc::PCI5, eATmegaPinFunc::PCI4, eATmegaPinFunc::PCI3, eATmegaPinFunc::PCI2, eATmegaPinFunc::PCI1, eATmegaPinFunc::PCI0)) { + _PCICR._PCIE0 = state._PCIE0; + } + if (funcSet.hasAnyFunc(eATmegaPinFunc::USART1_CLK, eATmegaPinFunc::USART1_TXD)) { + USART1._UCSRnB._TXEN = state._USART1_TXEN; + } + if (funcSet.hasAnyFunc(eATmegaPinFunc::USART1_CLK, eATmegaPinFunc::USART1_RXD)) { + USART1._UCSRnB._RXEN = state._USART1_RXEN; + } + if (funcSet.hasAnyFunc(eATmegaPinFunc::TWI_SDA, eATmegaPinFunc::TWI_CLK)) { + _TWCR._TWEN = state._TWEN; + } + if (funcSet.hasFunc(eATmegaPinFunc::TOC2B)) { + _TIMER2._TCCRnA._COMnB = state._COM2B; + } + if (funcSet.hasFunc(eATmegaPinFunc::TOC0B)) { + TIMER0._TCCRnA._COMnB = state._COM0B; + } + if (funcSet.hasFunc(eATmegaPinFunc::EINT3)) { + _EIMSK._INT3 = state._INT3; + } + if (funcSet.hasFunc(eATmegaPinFunc::EINT2)) { + _EIMSK._INT2 = state._INT2; + } + if (funcSet.hasFunc(eATmegaPinFunc::EINT1)) { + _EIMSK._INT1 = state._INT1; + } + if (funcSet.hasFunc(eATmegaPinFunc::EINT0)) { + _EIMSK._INT0 = state._INT0; + } + if (funcSet.hasFunc(eATmegaPinFunc::UVCON)) { + _UHWCON._UVCONE = state._UVCONE; + } + if (funcSet.hasFunc(eATmegaPinFunc::UID)) { + _UHWCON._UIDE = state._UIDE; + } + if (funcSet.hasFunc(eATmegaPinFunc::EINT7)) { + _EIMSK._INT7 = state._INT7; + } + if (funcSet.hasFunc(eATmegaPinFunc::EINT6)) { + _EIMSK._INT6 = state._INT6; + } + if (funcSet.hasFunc(eATmegaPinFunc::EINT5)) { + _EIMSK._INT5 = state._INT5; + } + if (funcSet.hasFunc(eATmegaPinFunc::EINT4)) { + _EIMSK._INT4 = state._INT4; + } + #elif defined(__AVR_TRM05__) + if (funcSet.hasAnyFunc(eATmegaPinFunc::PCI7, eATmegaPinFunc::PCI6, eATmegaPinFunc::PCI5, eATmegaPinFunc::PCI4, eATmegaPinFunc::PCI3, eATmegaPinFunc::PCI2, eATmegaPinFunc::PCI1, eATmegaPinFunc::PCI0)) { + _PCICR._PCIE0 = state._PCIE0; + } + if (funcSet.hasAnyFunc(eATmegaPinFunc::PCI15, eATmegaPinFunc::PCI14, eATmegaPinFunc::PCI13, eATmegaPinFunc::PCI12, eATmegaPinFunc::PCI11, eATmegaPinFunc::PCI10, eATmegaPinFunc::PCI9, eATmegaPinFunc::PCI8)) { + _PCICR._PCIE1 = state._PCIE1; + } + if (funcSet.hasAnyFunc(eATmegaPinFunc::PCI23, eATmegaPinFunc::PCI22, eATmegaPinFunc::PCI21, eATmegaPinFunc::PCI20, eATmegaPinFunc::PCI19, eATmegaPinFunc::PCI18, eATmegaPinFunc::PCI17, eATmegaPinFunc::PCI16)) { + _PCICR._PCIE2 = state._PCIE2; + } + if (funcSet.hasAnyFunc(eATmegaPinFunc::PCI31, eATmegaPinFunc::PCI30, eATmegaPinFunc::PCI29, eATmegaPinFunc::PCI28, eATmegaPinFunc::PCI27, eATmegaPinFunc::PCI26, eATmegaPinFunc::PCI25, eATmegaPinFunc::PCI24)) { + _PCICR._PCIE3 = state._PCIE3; + } + if (funcSet.hasAnyFunc(eATmegaPinFunc::SPI_SCK, eATmegaPinFunc::SPI_MISO, eATmegaPinFunc::SPI_MOSI, eATmegaPinFunc::SPI_CS)) { + _SPCR._SPE = state._SPE; + } + if (funcSet.hasFunc(eATmegaPinFunc::TOC0B)) { + TIMER0._TCCRnA._COMnB = state._COM0B; + } + if (funcSet.hasFunc(eATmegaPinFunc::TOC0A)) { + TIMER0._TCCRnA._COMnA = state._COM0A; + } + if (funcSet.hasFunc(eATmegaPinFunc::TOC2A)) { + _TIMER2._TCCRnA._COMnA = state._COM2A; + } + if (funcSet.hasFunc(eATmegaPinFunc::TOC2B)) { + _TIMER2._TCCRnA._COMnB = state._COM2B; + } + if (funcSet.hasFunc(eATmegaPinFunc::TOC1A)) { + TIMER1._TCCRnA._COMnA = state._COM1A; + } + if (funcSet.hasFunc(eATmegaPinFunc::TOC1B)) { + TIMER1._TCCRnA._COMnB = state._COM1B; + } + if (funcSet.hasAnyFunc(eATmegaPinFunc::TWI_CLK, eATmegaPinFunc::TWI_SDA)) { + _TWCR._TWEN = state._TWEN; + } + if (funcSet.hasFunc(eATmegaPinFunc::EINT2)) { + _EIMSK._INT2 = state._INT2; + } + if (funcSet.hasFunc(eATmegaPinFunc::EINT1)) { + _EIMSK._INT1 = state._INT1; + } + if (funcSet.hasFunc(eATmegaPinFunc::EINT0)) { + _EIMSK._INT0 = state._INT0; + } + if (funcSet.hasAnyFunc(eATmegaPinFunc::USART0_CLK, eATmegaPinFunc::USART0_TXD)) { + USART0._UCSRnB._TXEN = state._TXEN0; + } + if (funcSet.hasAnyFunc(eATmegaPinFunc::USART0_CLK, eATmegaPinFunc::USART0_RXD)) { + USART0._UCSRnB._RXEN = state._RXEN0; + } + if (funcSet.hasAnyFunc(eATmegaPinFunc::USART1_CLK, eATmegaPinFunc::USART1_TXD)) { + USART1._UCSRnB._TXEN = state._TXEN1; + } + if (funcSet.hasAnyFunc(eATmegaPinFunc::USART1_CLK, eATmegaPinFunc::USART1_RXD)) { + USART1._UCSRnB._RXEN = state._RXEN1; + } + #endif +} + +inline pin_dev_state_t _ATmega_savePinAlternate(uint8_t pin) { + return _ATmega_savePinAlternates({pin}); +} + +inline void _ATmega_restorePinAlternate(uint8_t pin, const pin_dev_state_t& state) { + _ATmega_restorePinAlternate({pin}, state); +} + +#ifndef LOW + #define LOW 0 +#endif +#ifndef HIGH + #define HIGH 1 +#endif + +inline void _ATmega_digitalWrite(int pin, int state) { + if (pin < 0) return; + + ATmegaPinInfo info = _ATmega_getPinInfo((unsigned int)pin); + + #ifdef __AVR_TRM01__ + if (info.port == eATmegaPort::PORT_A) { + _PORTA._PORT.setValue(info.pinidx, state == HIGH); + } + else if (info.port == eATmegaPort::PORT_B) { + _PORTB._PORT.setValue(info.pinidx, state == HIGH); + } + else if (info.port == eATmegaPort::PORT_C) { + _PORTC._PORT.setValue(info.pinidx, state == HIGH); + } + else if (info.port == eATmegaPort::PORT_D) { + _PORTD._PORT.setValue(info.pinidx, state == HIGH); + } + else if (info.port == eATmegaPort::PORT_E) { + _PORTE._PORT.setValue(info.pinidx, state == HIGH); + } + else if (info.port == eATmegaPort::PORT_F) { + _PORTF._PORT.setValue(info.pinidx, state == HIGH); + } + else if (info.port == eATmegaPort::PORT_G) { + _PORTG._PORT.setValue(info.pinidx, state == HIGH); + } + else if (info.port == eATmegaPort::PORT_H) { + _PORTH._PORT.setValue(info.pinidx, state == HIGH); + } + else if (info.port == eATmegaPort::PORT_J) { + _PORTJ._PORT.setValue(info.pinidx, state == HIGH); + } + else if (info.port == eATmegaPort::PORT_K) { + _PORTK._PORT.setValue(info.pinidx, state == HIGH); + } + else if (info.port == eATmegaPort::PORT_L) { + _PORTL._PORT.setValue(info.pinidx, state == HIGH); + } + #elif defined(__AVR_TRM02__) || defined(__AVR_TRM05__) + if (info.port == eATmegaPort::PORT_A) { + _PORTA._PORT.setValue(info.pinidx, state == HIGH); + } + else if (info.port == eATmegaPort::PORT_B) { + _PORTB._PORT.setValue(info.pinidx, state == HIGH); + } + else if (info.port == eATmegaPort::PORT_C) { + _PORTC._PORT.setValue(info.pinidx, state == HIGH); + } + else if (info.port == eATmegaPort::PORT_D) { + _PORTD._PORT.setValue(info.pinidx, state == HIGH); + } + #elif defined(__AVR_TRM03__) + if (info.port == eATmegaPort::PORT_B) { + _PORTB._PORT.setValue(info.pinidx, state == HIGH); + } + else if (info.port == eATmegaPort::PORT_C) { + _PORTC._PORT.setValue(info.pinidx, state == HIGH); + } + else if (info.port == eATmegaPort::PORT_D) { + _PORTD._PORT.setValue(info.pinidx, state == HIGH); + } + #elif defined(__AVR_TRM04__) + if (info.port == eATmegaPort::PORT_A) { + _PORTA._PORT.setValue(info.pinidx, state == HIGH); + } + else if (info.port == eATmegaPort::PORT_B) { + _PORTB._PORT.setValue(info.pinidx, state == HIGH); + } + else if (info.port == eATmegaPort::PORT_C) { + _PORTC._PORT.setValue(info.pinidx, state == HIGH); + } + else if (info.port == eATmegaPort::PORT_D) { + _PORTD._PORT.setValue(info.pinidx, state == HIGH); + } + else if (info.port == eATmegaPort::PORT_E) { + _PORTE._PORT.setValue(info.pinidx, state == HIGH); + } + else if (info.port == eATmegaPort::PORT_F) { + _PORTF._PORT.setValue(info.pinidx, state == HIGH); + } + #endif +} + +inline int _ATmega_digitalRead(int pin) { + int value = LOW; + + if (pin < 0) return value; + + ATmegaPinInfo info = _ATmega_getPinInfo((unsigned int)pin); + + #ifdef __AVR_TRM01__ + if (info.port == eATmegaPort::PORT_A) { + value = _PORTA._PIN.getValue(info.pinidx); + } + else if (info.port == eATmegaPort::PORT_B) { + value = _PORTB._PIN.getValue(info.pinidx); + } + else if (info.port == eATmegaPort::PORT_C) { + value = _PORTC._PIN.getValue(info.pinidx); + } + else if (info.port == eATmegaPort::PORT_D) { + value = _PORTD._PIN.getValue(info.pinidx); + } + else if (info.port == eATmegaPort::PORT_E) { + value = _PORTE._PIN.getValue(info.pinidx); + } + else if (info.port == eATmegaPort::PORT_F) { + value = _PORTF._PIN.getValue(info.pinidx); + } + else if (info.port == eATmegaPort::PORT_G) { + value = _PORTG._PIN.getValue(info.pinidx); + } + else if (info.port == eATmegaPort::PORT_H) { + value = _PORTH._PIN.getValue(info.pinidx); + } + else if (info.port == eATmegaPort::PORT_J) { + value = _PORTJ._PIN.getValue(info.pinidx); + } + else if (info.port == eATmegaPort::PORT_K) { + value = _PORTK._PIN.getValue(info.pinidx); + } + else if (info.port == eATmegaPort::PORT_L) { + value = _PORTL._PIN.getValue(info.pinidx); + } + #elif defined(__AVR_TRM02__) || defined(__AVR_TRM05__) + if (info.port == eATmegaPort::PORT_A) { + value = _PORTA._PIN.getValue(info.pinidx); + } + else if (info.port == eATmegaPort::PORT_B) { + value = _PORTB._PIN.getValue(info.pinidx); + } + else if (info.port == eATmegaPort::PORT_C) { + value = _PORTC._PIN.getValue(info.pinidx); + } + else if (info.port == eATmegaPort::PORT_D) { + value = _PORTD._PIN.getValue(info.pinidx); + } + #elif defined(__AVR_TRM03__) + if (info.port == eATmegaPort::PORT_B) { + value = _PORTB._PIN.getValue(info.pinidx); + } + else if (info.port == eATmegaPort::PORT_C) { + value = _PORTC._PIN.getValue(info.pinidx); + } + else if (info.port == eATmegaPort::PORT_D) { + value = _PORTD._PIN.getValue(info.pinidx); + } + #elif defined(__AVR_TRM04__) + if (info.port == eATmegaPort::PORT_A) { + value = _PORTA._PIN.getValue(info.pinidx); + } + else if (info.port == eATmegaPort::PORT_B) { + value = _PORTB._PIN.getValue(info.pinidx); + } + else if (info.port == eATmegaPort::PORT_C) { + value = _PORTC._PIN.getValue(info.pinidx); + } + else if (info.port == eATmegaPort::PORT_D) { + value = _PORTD._PIN.getValue(info.pinidx); + } + else if (info.port == eATmegaPort::PORT_E) { + value = _PORTE._PIN.getValue(info.pinidx); + } + else if (info.port == eATmegaPort::PORT_F) { + value = _PORTF._PIN.getValue(info.pinidx); + } + #endif + + return value; +} + +#ifndef OUTPUT + #define OUTPUT 1 +#endif +#ifndef INPUT + #define INPUT 0 +#endif + +inline void _ATmega_pinMode(int pin, int mode) { + if (pin < 0) return; + + ATmegaPinInfo info = _ATmega_getPinInfo((unsigned int)pin); + + #ifdef __AVR_TRM01__ + if (info.port == eATmegaPort::PORT_A) { + _PORTA._DDR.setValue(info.pinidx, mode == OUTPUT); + } + else if (info.port == eATmegaPort::PORT_B) { + _PORTB._DDR.setValue(info.pinidx, mode == OUTPUT); + } + else if (info.port == eATmegaPort::PORT_C) { + _PORTC._DDR.setValue(info.pinidx, mode == OUTPUT); + } + else if (info.port == eATmegaPort::PORT_D) { + _PORTD._DDR.setValue(info.pinidx, mode == OUTPUT); + } + else if (info.port == eATmegaPort::PORT_E) { + _PORTE._DDR.setValue(info.pinidx, mode == OUTPUT); + } + else if (info.port == eATmegaPort::PORT_F) { + _PORTF._DDR.setValue(info.pinidx, mode == OUTPUT); + } + else if (info.port == eATmegaPort::PORT_G) { + _PORTG._DDR.setValue(info.pinidx, mode == OUTPUT); + } + else if (info.port == eATmegaPort::PORT_H) { + _PORTH._DDR.setValue(info.pinidx, mode == OUTPUT); + } + else if (info.port == eATmegaPort::PORT_J) { + _PORTJ._DDR.setValue(info.pinidx, mode == OUTPUT); + } + else if (info.port == eATmegaPort::PORT_K) { + _PORTK._DDR.setValue(info.pinidx, mode == OUTPUT); + } + else if (info.port == eATmegaPort::PORT_L) { + _PORTL._DDR.setValue(info.pinidx, mode == OUTPUT); + } + #elif defined(__AVR_TRM02__) || defined(__AVR_TRM05__) + if (info.port == eATmegaPort::PORT_A) { + _PORTA._DDR.setValue(info.pinidx, mode == OUTPUT); + } + else if (info.port == eATmegaPort::PORT_B) { + _PORTB._DDR.setValue(info.pinidx, mode == OUTPUT); + } + else if (info.port == eATmegaPort::PORT_C) { + _PORTC._DDR.setValue(info.pinidx, mode == OUTPUT); + } + else if (info.port == eATmegaPort::PORT_D) { + _PORTD._DDR.setValue(info.pinidx, mode == OUTPUT); + } + #elif defined(__AVR_TRM03__) + if (info.port == eATmegaPort::PORT_B) { + _PORTB._DDR.setValue(info.pinidx, mode == OUTPUT); + } + else if (info.port == eATmegaPort::PORT_C) { + _PORTC._DDR.setValue(info.pinidx, mode == OUTPUT); + } + else if (info.port == eATmegaPort::PORT_D) { + _PORTD._DDR.setValue(info.pinidx, mode == OUTPUT); + } + #elif defined(__AVR_TRM04__) + if (info.port == eATmegaPort::PORT_A) { + _PORTA._DDR.setValue(info.pinidx, mode == OUTPUT); + } + else if (info.port == eATmegaPort::PORT_B) { + _PORTB._DDR.setValue(info.pinidx, mode == OUTPUT); + } + else if (info.port == eATmegaPort::PORT_C) { + _PORTC._DDR.setValue(info.pinidx, mode == OUTPUT); + } + else if (info.port == eATmegaPort::PORT_D) { + _PORTD._DDR.setValue(info.pinidx, mode == OUTPUT); + } + else if (info.port == eATmegaPort::PORT_E) { + _PORTE._DDR.setValue(info.pinidx, mode == OUTPUT); + } + else if (info.port == eATmegaPort::PORT_F) { + _PORTF._DDR.setValue(info.pinidx, mode == OUTPUT); + } + #endif +} + +#if defined(__AVR_TRM01__) || defined(__AVR_TRM02__) + struct _ATmega_efuse { + uint8_t _BODLEVEL : 3; + uint8_t reserved1 : 5; + }; + + struct _ATmega_hfuse { + uint8_t _BOOTRST : 1; + uint8_t _BOOTSZ : 2; + uint8_t _EESAVE : 1; + uint8_t _WDTON : 1; + uint8_t _SPIEN : 1; + uint8_t _JTAGEN : 1; + uint8_t _OCDEN : 1; + }; + + struct _ATmega_lfuse { + uint8_t _CKSEL : 4; + uint8_t _SUT0 : 1; + uint8_t _SUT1 : 1; + uint8_t _CKOUT : 1; + uint8_t _CKDIV8 : 1; + }; + + #ifndef AVR_DEFAULT_LFUSE_VALUE + #define AVR_DEFAULT_LFUSE_VALUE 0xFF + #endif + #ifndef AVR_DEFAULT_HFUSE_VALUE + #define AVR_DEFAULT_HFUSE_VALUE 0x99 + #endif + #ifndef AVR_DEFAULT_LFUSE_VALUE + #define AVR_DEFAULT_LFUSE_VALUE 0x62 + #endif + +#elif defined(__AVR_TRM03__) + #if defined(__AVR_ATmega48A__) || defined(__AVR_ATmega48PA__) + struct _ATmega_efuse { + uint8_t _SELFPRGEN : 1; + uint8_t reserved1 : 7; + }; + + #ifndef AVR_DEFAULT_EFUSE_VALUE + #define AVR_DEFAULT_EFUSE_VALUE 0xFF + #endif + + #elif defined(__AVR_ATmega88A__) || defined(__AVR_ATmega88PA__) || defined(__AVR_ATmega168A__) || defined(__AVR_ATmega168PA__) + struct _ATmega_efuse { + uint8_t _BOOTRST : 1; + uint8_t _BOOTSZ : 2; + uint8_t reserved1 : 5; + }; + + #ifndef AVR_DEFAULT_EFUSE_VALUE + #define AVR_DEFAULT_EFUSE_VALUE 0xF9 + #endif + + #else // defined(__AVR_ATmega328__) || defined(__AVR_ATmega328P__) + struct _ATmega_efuse { + uint8_t _BODLEVEL : 3; + uint8_t reserved1 : 5; + }; + + #ifndef AVR_DEFAULT_EFUSE_VALUE + #define AVR_DEFAULT_EFUSE_VALUE 0xFF + #endif + + #endif + + #if defined(__AVR_ATmega48A__) || defined(__AVR_ATmega48PA__) || defined(__AVR_ATmega88A__) || defined(__AVR_ATmega88PA__) || defined(__AVR_ATmega168A__) || defined(__AVR_ATmega168PA__) + struct _ATmega_hfuse { + uint8_t _BODLEVEL : 3; + uint8_t _EESAVE : 1; + uint8_t _WDTON : 1; + uint8_t _SPIEN : 1; + uint8_t _DWEN : 1; + uint8_t _RSTDISBL : 1; + }; + + #ifndef AVR_DEFAULT_HFUSE_VALUE + #define AVR_DEFAULT_HFUSE_VALUE 0xCF + #endif + + #else // defined(__AVR_ATmega328__) || defined(__AVR_ATmega328P__) + struct _ATmega_hfuse { + uint8_t _BOOTRST : 1; + uint8_t _BOOTSZ : 2; + uint8_t _EESAVE : 1; + uint8_t _WDTON : 1; + uint8_t _SPIEN : 1; + uint8_t _DWEN : 1; + uint8_t _RSTDISBL : 1; + }; + + #ifndef AVR_DEFAULT_HFUSE_VALUE + #define AVR_DEFAULT_HFUSE_VALUE 0xC9 + #endif + + #endif + + struct _ATmega_lfuse { + uint8_t _CKSEL : 4; + uint8_t _SUT0 : 1; + uint8_t _SUT1 : 1; + uint8_t _CKOUT : 1; + uint8_t _CKDIV8 : 1; + }; + + #ifndef AVR_DEFAULT_LFUSE_VALUE + #define AVR_DEFAULT_LFUSE_VALUE 0xC9 + #endif + +#elif defined(__AVR_TRM04__) + struct _ATmega_efuse { + uint8_t _BODLEVEL : 3; + uint8_t _HWBE : 1; + uint8_t reserved1 : 4; + }; + + struct _ATmega_hfuse { + uint8_t _BOOTRST : 1; + uint8_t _BOOTSZ : 2; + uint8_t _EESAVE : 1; + uint8_t _WDTON : 1; + uint8_t _SPIEN : 1; + uint8_t _JTAGEN : 1; + uint8_t _OCDEN : 1; + }; + + struct _ATmega_lfuse { + uint8_t _CKSEL : 4; + uint8_t _SUT0 : 1; + uint8_t _SUT1 : 1; + uint8_t _CKOUT : 1; + uint8_t _CKDIV8 : 1; + }; + + // Default values if not already defined. + #ifndef AVR_DEFAULT_EFUSE_VALUE + #define AVR_DEFAULT_EFUSE_VALUE 0xF3 + #endif + #ifndef AVR_DEFAULT_HFUSE_VALUE + #define AVR_DEFAULT_HFUSE_VALUE 0x99 + #endif + #ifndef AVR_DEFAULT_LFUSE_VALUE + #define AVR_DEFAULT_LFUSE_VALUE 0x62 + #endif + +#elif defined(__AVR_TRM05__) + struct _ATmega_efuse { + uint8_t _BODLEVEL0 : 1; + uint8_t _BODLEVEL1 : 1; + uint8_t _BODLEVEL2 : 1; + uint8_t reserved1 : 5; + }; + + struct _ATmega_hfuse { + uint8_t _BOOTRST : 1; + uint8_t _BOOTSZ : 2; + uint8_t _EESAVE : 1; + uint8_t _WDTON : 1; + uint8_t _SPIEN : 1; + uint8_t _JTAGEN : 1; + uint8_t _OCDEN : 1; + }; + + struct _ATmega_lfuse { + uint8_t _CKSEL : 4; + uint8_t _SUT0 : 1; + uint8_t _SUT1 : 1; + uint8_t _CKOUT : 1; + uint8_t _CKDIV8 : 1; + }; + + #ifndef AVR_DEFAULT_EFUSE_VALUE + #define AVR_DEFAULT_EFUSE_VALUE 0xFF + #endif + #ifndef AVR_DEFAULT_HFUSE_VALUE + #define AVR_DEFAULT_HFUSE_VALUE 0x88 + #endif + #ifndef AVR_DEFAULT_LFUSE_VALUE + #define AVR_DEFAULT_LFUSE_VALUE 0x62 + #endif +#endif + +struct ATmega_efuse : public _ATmega_efuse { + inline ATmega_efuse(uint8_t val = 0) { *(uint8_t*)this = val; } + inline ATmega_efuse(const ATmega_efuse&) = default; +}; +struct ATmega_hfuse : public _ATmega_hfuse { + inline ATmega_hfuse(uint8_t val = 0) { *(uint8_t*)this = val; } + inline ATmega_hfuse(const ATmega_hfuse&) = default; +}; +struct ATmega_lfuse : public _ATmega_lfuse { + inline ATmega_lfuse(uint8_t val = 0) { *(uint8_t*)this = val; } + inline ATmega_lfuse(const ATmega_lfuse&) = default; +}; diff --git a/Marlin/src/HAL/AVR/timers.h b/Marlin/src/HAL/AVR/timers.h index 33c3880b6b..94b17f3102 100644 --- a/Marlin/src/HAL/AVR/timers.h +++ b/Marlin/src/HAL/AVR/timers.h @@ -1,7 +1,9 @@ /** * Marlin 3D Printer Firmware * Copyright (c) 2020 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] - * Copyright (c) 2016 Bob Cousins bobcousins42@googlemail.com + * + * 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 @@ -44,14 +46,14 @@ typedef uint16_t hal_timer_t; #define MF_TIMER_TEMP 0 #endif -#define TEMP_TIMER_FREQUENCY ((F_CPU) / 64.0 / 256.0) +#define TEMP_TIMER_FREQUENCY (((F_CPU) + 0x2000) / 0x4000) #define STEPPER_TIMER_RATE HAL_TIMER_RATE #define STEPPER_TIMER_PRESCALE 8 -#define STEPPER_TIMER_TICKS_PER_US ((STEPPER_TIMER_RATE) / 1000000) // Cannot be of type double +#define STEPPER_TIMER_TICKS_PER_US ((STEPPER_TIMER_RATE) / 1000000) -#define PULSE_TIMER_RATE STEPPER_TIMER_RATE // frequency of pulse timer -#define PULSE_TIMER_PRESCALE STEPPER_TIMER_PRESCALE +#define PULSE_TIMER_RATE STEPPER_TIMER_RATE +#define PULSE_TIMER_PRESCALE STEPPER_TIMER_PRESCALE #define PULSE_TIMER_TICKS_PER_US STEPPER_TIMER_TICKS_PER_US #define ENABLE_STEPPER_DRIVER_INTERRUPT() SBI(TIMSK1, OCIE1A) diff --git a/Marlin/src/HAL/AVR/u8g/LCD_defines.h b/Marlin/src/HAL/AVR/u8g/LCD_defines.h new file mode 100644 index 0000000000..91858c0dbf --- /dev/null +++ b/Marlin/src/HAL/AVR/u8g/LCD_defines.h @@ -0,0 +1,29 @@ +/** + * Marlin 3D Printer Firmware + * Copyright (c) 2023 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] + * + * Based on Sprinter and grbl. + * Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (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 + +/** + * AVR LCD-specific defines + */ + +uint8_t u8g_com_HAL_AVR_sw_sp_fn(u8g_t *u8g, uint8_t msg, uint8_t arg_val, void *arg_ptr); +#define U8G_COM_HAL_SW_SPI_FN u8g_com_HAL_AVR_sw_sp_fn diff --git a/Marlin/src/HAL/AVR/u8g_com_HAL_AVR_sw_spi.cpp b/Marlin/src/HAL/AVR/u8g_com_HAL_AVR_sw_spi.cpp index 45b54379db..79bafe2939 100644 --- a/Marlin/src/HAL/AVR/u8g_com_HAL_AVR_sw_spi.cpp +++ b/Marlin/src/HAL/AVR/u8g_com_HAL_AVR_sw_spi.cpp @@ -88,7 +88,7 @@ void u8g_spiSend_sw_AVR_mode_0(uint8_t val) { volatile uint8_t *outData = u8g_outData, *outClock = u8g_outClock; U8G_ATOMIC_START(); - LOOP_L_N(i, 8) { + for (uint8_t i = 0; i < 8; ++i) { if (val & 0x80) *outData |= bitData; else @@ -108,7 +108,7 @@ void u8g_spiSend_sw_AVR_mode_3(uint8_t val) { volatile uint8_t *outData = u8g_outData, *outClock = u8g_outClock; U8G_ATOMIC_START(); - LOOP_L_N(i, 8) { + for (uint8_t i = 0; i < 8; ++i) { *outClock &= bitNotClock; if (val & 0x80) *outData |= bitData; diff --git a/Marlin/src/HAL/DUE/HAL.cpp b/Marlin/src/HAL/DUE/HAL.cpp index 4353f16497..763091cb00 100644 --- a/Marlin/src/HAL/DUE/HAL.cpp +++ b/Marlin/src/HAL/DUE/HAL.cpp @@ -1,7 +1,9 @@ /** * Marlin 3D Printer Firmware * Copyright (c) 2020 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] - * Copyright (c) 2016 Bob Cousins bobcousins42@googlemail.com + * + * 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 @@ -45,7 +47,7 @@ uint16_t MarlinHAL::adc_result; #endif void MarlinHAL::init() { - #if ENABLED(SDSUPPORT) + #if HAS_MEDIA OUT_WRITE(SDSS, HIGH); // Try to set SDSS inactive before any other SPI users start up #endif usb_task_init(); // Initialize the USB stack diff --git a/Marlin/src/HAL/DUE/HAL.h b/Marlin/src/HAL/DUE/HAL.h index 585b893841..49a8be3fe7 100644 --- a/Marlin/src/HAL/DUE/HAL.h +++ b/Marlin/src/HAL/DUE/HAL.h @@ -1,9 +1,9 @@ /** * Marlin 3D Printer Firmware - * * Copyright (c) 2020 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] - * Copyright (c) 2016 Bob Cousins bobcousins42@googlemail.com - * Copyright (c) 2015-2016 Nico Tonnhofer wurstnase.reprap@gmail.com + * + * 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 @@ -123,7 +123,7 @@ typedef Servo hal_servo_t; // // ADC // -#define HAL_ADC_VREF 3.3 +#define HAL_ADC_VREF_MV 3300 #define HAL_ADC_RESOLUTION 10 #ifndef analogInputToDigitalPin diff --git a/Marlin/src/HAL/DUE/HAL_SPI.cpp b/Marlin/src/HAL/DUE/HAL_SPI.cpp index f5bcaacee5..63ebf164f2 100644 --- a/Marlin/src/HAL/DUE/HAL_SPI.cpp +++ b/Marlin/src/HAL/DUE/HAL_SPI.cpp @@ -42,7 +42,7 @@ // Public functions // ------------------------ -#if EITHER(DUE_SOFTWARE_SPI, FORCE_SOFT_SPI) +#if ANY(DUE_SOFTWARE_SPI, FORCE_SOFT_SPI) // ------------------------ // Software SPI diff --git a/Marlin/src/HAL/DUE/MarlinSerial.h b/Marlin/src/HAL/DUE/MarlinSerial.h index 5a61bffee0..b80ae21823 100644 --- a/Marlin/src/HAL/DUE/MarlinSerial.h +++ b/Marlin/src/HAL/DUE/MarlinSerial.h @@ -30,6 +30,7 @@ #include #include "../../inc/MarlinConfigPre.h" +#include "../../core/types.h" #include "../../core/serial_hook.h" // Define constants and variables for buffering incoming serial data. We're @@ -52,10 +53,6 @@ // #error "TX_BUFFER_SIZE must be 0, a power of 2 greater than 1, and no greater than 256." //#endif -// Templated type selector -template struct TypeSelector { typedef T type;} ; -template struct TypeSelector { typedef F type; }; - // Templated structure wrapper template struct StructWrapper { constexpr StructWrapper(int) {} @@ -76,7 +73,7 @@ protected: static constexpr int HWUART_IRQ_ID = IRQ_IDS[Cfg::PORT]; // Base size of type on buffer size - typedef typename TypeSelector<(Cfg::RX_SIZE>256), uint16_t, uint8_t>::type ring_buffer_pos_t; + typedef uvalue_t(Cfg::RX_SIZE - 1) ring_buffer_pos_t; struct ring_buffer_r { volatile ring_buffer_pos_t head, tail; diff --git a/Marlin/src/HAL/DUE/MinSerial.cpp b/Marlin/src/HAL/DUE/MinSerial.cpp index e5b3dbfe6f..505a712aa9 100644 --- a/Marlin/src/HAL/DUE/MinSerial.cpp +++ b/Marlin/src/HAL/DUE/MinSerial.cpp @@ -73,18 +73,18 @@ void install_min_serial() { } #if DISABLED(DYNAMIC_VECTORTABLE) -extern "C" { - __attribute__((naked)) void JumpHandler_ASM() { - __asm__ __volatile__ ( - "b CommonHandler_ASM\n" - ); + extern "C" { + __attribute__((naked)) void JumpHandler_ASM() { + __asm__ __volatile__ ( + "b CommonHandler_ASM\n" + ); + } + void __attribute__((naked, alias("JumpHandler_ASM"))) HardFault_Handler(); + void __attribute__((naked, alias("JumpHandler_ASM"))) BusFault_Handler(); + void __attribute__((naked, alias("JumpHandler_ASM"))) UsageFault_Handler(); + void __attribute__((naked, alias("JumpHandler_ASM"))) MemManage_Handler(); + void __attribute__((naked, alias("JumpHandler_ASM"))) NMI_Handler(); } - void __attribute__((naked, alias("JumpHandler_ASM"))) HardFault_Handler(); - void __attribute__((naked, alias("JumpHandler_ASM"))) BusFault_Handler(); - void __attribute__((naked, alias("JumpHandler_ASM"))) UsageFault_Handler(); - void __attribute__((naked, alias("JumpHandler_ASM"))) MemManage_Handler(); - void __attribute__((naked, alias("JumpHandler_ASM"))) NMI_Handler(); -} #endif #endif // POSTMORTEM_DEBUGGING diff --git a/Marlin/src/HAL/DUE/eeprom_flash.cpp b/Marlin/src/HAL/DUE/eeprom_flash.cpp index 607764155b..a0ed6cc843 100644 --- a/Marlin/src/HAL/DUE/eeprom_flash.cpp +++ b/Marlin/src/HAL/DUE/eeprom_flash.cpp @@ -1,10 +1,9 @@ /** * Marlin 3D Printer Firmware - * * Copyright (c) 2020 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] - * Copyright (c) 2016 Bob Cousins bobcousins42@googlemail.com - * Copyright (c) 2015-2016 Nico Tonnhofer wurstnase.reprap@gmail.com - * Copyright (c) 2016 Victor Perez victor_pv@hotmail.com + * + * 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 diff --git a/Marlin/src/HAL/DUE/eeprom_wired.cpp b/Marlin/src/HAL/DUE/eeprom_wired.cpp index 557a2f2cff..24f8c06d2e 100644 --- a/Marlin/src/HAL/DUE/eeprom_wired.cpp +++ b/Marlin/src/HAL/DUE/eeprom_wired.cpp @@ -1,10 +1,9 @@ /** * Marlin 3D Printer Firmware - * * Copyright (c) 2020 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] - * Copyright (c) 2016 Bob Cousins bobcousins42@googlemail.com - * Copyright (c) 2015-2016 Nico Tonnhofer wurstnase.reprap@gmail.com - * Copyright (c) 2016 Victor Perez victor_pv@hotmail.com + * + * 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 diff --git a/Marlin/src/HAL/DUE/endstop_interrupts.h b/Marlin/src/HAL/DUE/endstop_interrupts.h index c1bbcb121b..954eb625a5 100644 --- a/Marlin/src/HAL/DUE/endstop_interrupts.h +++ b/Marlin/src/HAL/DUE/endstop_interrupts.h @@ -47,33 +47,33 @@ void endstop_ISR() { endstops.update(); } void setup_endstop_interrupts() { #define _ATTACH(P) attachInterrupt(digitalPinToInterrupt(P), endstop_ISR, CHANGE) - TERN_(HAS_X_MAX, _ATTACH(X_MAX_PIN)); - TERN_(HAS_X_MIN, _ATTACH(X_MIN_PIN)); - TERN_(HAS_Y_MAX, _ATTACH(Y_MAX_PIN)); - TERN_(HAS_Y_MIN, _ATTACH(Y_MIN_PIN)); - TERN_(HAS_Z_MAX, _ATTACH(Z_MAX_PIN)); - TERN_(HAS_Z_MIN, _ATTACH(Z_MIN_PIN)); - TERN_(HAS_X2_MAX, _ATTACH(X2_MAX_PIN)); - TERN_(HAS_X2_MIN, _ATTACH(X2_MIN_PIN)); - TERN_(HAS_Y2_MAX, _ATTACH(Y2_MAX_PIN)); - TERN_(HAS_Y2_MIN, _ATTACH(Y2_MIN_PIN)); - TERN_(HAS_Z2_MAX, _ATTACH(Z2_MAX_PIN)); - TERN_(HAS_Z2_MIN, _ATTACH(Z2_MIN_PIN)); - TERN_(HAS_Z3_MAX, _ATTACH(Z3_MAX_PIN)); - TERN_(HAS_Z3_MIN, _ATTACH(Z3_MIN_PIN)); - TERN_(HAS_Z4_MAX, _ATTACH(Z4_MAX_PIN)); - TERN_(HAS_Z4_MIN, _ATTACH(Z4_MIN_PIN)); - TERN_(HAS_Z_MIN_PROBE_PIN, _ATTACH(Z_MIN_PROBE_PIN)); - TERN_(HAS_I_MAX, _ATTACH(I_MAX_PIN)); - TERN_(HAS_I_MIN, _ATTACH(I_MIN_PIN)); - TERN_(HAS_J_MAX, _ATTACH(J_MAX_PIN)); - TERN_(HAS_J_MIN, _ATTACH(J_MIN_PIN)); - TERN_(HAS_K_MAX, _ATTACH(K_MAX_PIN)); - TERN_(HAS_K_MIN, _ATTACH(K_MIN_PIN)); - TERN_(HAS_U_MAX, _ATTACH(U_MAX_PIN)); - TERN_(HAS_U_MIN, _ATTACH(U_MIN_PIN)); - TERN_(HAS_V_MAX, _ATTACH(V_MAX_PIN)); - TERN_(HAS_V_MIN, _ATTACH(V_MIN_PIN)); - TERN_(HAS_W_MAX, _ATTACH(W_MAX_PIN)); - TERN_(HAS_W_MIN, _ATTACH(W_MIN_PIN)); + TERN_(USE_X_MAX, _ATTACH(X_MAX_PIN)); + TERN_(USE_X_MIN, _ATTACH(X_MIN_PIN)); + TERN_(USE_Y_MAX, _ATTACH(Y_MAX_PIN)); + TERN_(USE_Y_MIN, _ATTACH(Y_MIN_PIN)); + TERN_(USE_Z_MAX, _ATTACH(Z_MAX_PIN)); + TERN_(USE_Z_MIN, _ATTACH(Z_MIN_PIN)); + TERN_(USE_X2_MAX, _ATTACH(X2_MAX_PIN)); + TERN_(USE_X2_MIN, _ATTACH(X2_MIN_PIN)); + TERN_(USE_Y2_MAX, _ATTACH(Y2_MAX_PIN)); + TERN_(USE_Y2_MIN, _ATTACH(Y2_MIN_PIN)); + TERN_(USE_Z2_MAX, _ATTACH(Z2_MAX_PIN)); + TERN_(USE_Z2_MIN, _ATTACH(Z2_MIN_PIN)); + TERN_(USE_Z3_MAX, _ATTACH(Z3_MAX_PIN)); + TERN_(USE_Z3_MIN, _ATTACH(Z3_MIN_PIN)); + TERN_(USE_Z4_MAX, _ATTACH(Z4_MAX_PIN)); + TERN_(USE_Z4_MIN, _ATTACH(Z4_MIN_PIN)); + TERN_(USE_Z_MIN_PROBE, _ATTACH(Z_MIN_PROBE_PIN)); + TERN_(USE_I_MAX, _ATTACH(I_MAX_PIN)); + TERN_(USE_I_MIN, _ATTACH(I_MIN_PIN)); + TERN_(USE_J_MAX, _ATTACH(J_MAX_PIN)); + TERN_(USE_J_MIN, _ATTACH(J_MIN_PIN)); + TERN_(USE_K_MAX, _ATTACH(K_MAX_PIN)); + TERN_(USE_K_MIN, _ATTACH(K_MIN_PIN)); + TERN_(USE_U_MAX, _ATTACH(U_MAX_PIN)); + TERN_(USE_U_MIN, _ATTACH(U_MIN_PIN)); + TERN_(USE_V_MAX, _ATTACH(V_MAX_PIN)); + TERN_(USE_V_MIN, _ATTACH(V_MIN_PIN)); + TERN_(USE_W_MAX, _ATTACH(W_MAX_PIN)); + TERN_(USE_W_MIN, _ATTACH(W_MIN_PIN)); } diff --git a/Marlin/src/HAL/DUE/fastio.h b/Marlin/src/HAL/DUE/fastio.h index a609210d81..77bc1911d8 100644 --- a/Marlin/src/HAL/DUE/fastio.h +++ b/Marlin/src/HAL/DUE/fastio.h @@ -189,12 +189,12 @@ */ // UART -#define RXD DIO0 -#define TXD DIO1 +#define RXD 0 +#define TXD 1 // TWI (I2C) -#define SCL DIO21 -#define SDA DIO20 +#define SCL 21 +#define SDA 20 /** * pins diff --git a/Marlin/src/HAL/DUE/fastio/G2_PWM.h b/Marlin/src/HAL/DUE/fastio/G2_PWM.h index dc4edffff8..2afe246cea 100644 --- a/Marlin/src/HAL/DUE/fastio/G2_PWM.h +++ b/Marlin/src/HAL/DUE/fastio/G2_PWM.h @@ -63,7 +63,7 @@ extern PWM_map ISR_table[NUM_PWMS]; extern uint32_t motor_current_setting[3]; #define IR_BIT(p) (WITHIN(p, 0, 3) ? (p) : (p) + 4) -#define COPY_ACTIVE_TABLE() do{ LOOP_L_N(i, 6) work_table[i] = active_table[i]; }while(0) +#define COPY_ACTIVE_TABLE() do{ for (uint8_t i = 0; i < 6; ++i) work_table[i] = active_table[i]; }while(0) #define PWM_MR0 19999 // base repetition rate minus one count - 20mS #define PWM_PR 24 // prescaler value - prescaler divide by 24 + 1 - 1 MHz output diff --git a/Marlin/src/HAL/DUE/inc/Conditionals_LCD.h b/Marlin/src/HAL/DUE/inc/Conditionals_LCD.h index 5867414447..5f1c4b1601 100644 --- a/Marlin/src/HAL/DUE/inc/Conditionals_LCD.h +++ b/Marlin/src/HAL/DUE/inc/Conditionals_LCD.h @@ -20,7 +20,3 @@ * */ #pragma once - -#if HAS_SPI_TFT || HAS_FSMC_TFT - #error "Sorry! TFT displays are not available for HAL/DUE." -#endif diff --git a/Marlin/src/HAL/DUE/inc/Conditionals_post.h b/Marlin/src/HAL/DUE/inc/Conditionals_post.h index ce6d3fdde2..295596b78b 100644 --- a/Marlin/src/HAL/DUE/inc/Conditionals_post.h +++ b/Marlin/src/HAL/DUE/inc/Conditionals_post.h @@ -23,6 +23,6 @@ #if USE_FALLBACK_EEPROM #define FLASH_EEPROM_EMULATION -#elif EITHER(I2C_EEPROM, SPI_EEPROM) +#elif ANY(I2C_EEPROM, SPI_EEPROM) #define USE_SHARED_EEPROM 1 #endif diff --git a/Marlin/src/HAL/DUE/inc/SanityCheck.h b/Marlin/src/HAL/DUE/inc/SanityCheck.h index 1f5acc360c..a8f5de8298 100644 --- a/Marlin/src/HAL/DUE/inc/SanityCheck.h +++ b/Marlin/src/HAL/DUE/inc/SanityCheck.h @@ -25,6 +25,10 @@ * Test Arduino Due specific configuration values for errors at compile-time. */ +#if HAS_SPI_TFT || HAS_FSMC_TFT + #error "Sorry! TFT displays are not available for HAL/DUE." +#endif + /** * Check for common serial pin conflicts */ @@ -64,9 +68,9 @@ * Usually the hardware SPI pins are only available to the LCD. This makes the DUE hard SPI used at the same time * as the TMC2130 soft SPI the most common setup. */ -#define _IS_HW_SPI(P) (defined(TMC_SW_##P) && (TMC_SW_##P == SD_MOSI_PIN || TMC_SW_##P == SD_MISO_PIN || TMC_SW_##P == SD_SCK_PIN)) +#define _IS_HW_SPI(P) (defined(TMC_SPI_##P) && (TMC_SPI_##P == SD_MOSI_PIN || TMC_SPI_##P == SD_MISO_PIN || TMC_SPI_##P == SD_SCK_PIN)) -#if ENABLED(SDSUPPORT) && HAS_DRIVER(TMC2130) +#if HAS_MEDIA && HAS_DRIVER(TMC2130) #if ENABLED(TMC_USE_SW_SPI) #if DISABLED(DUE_SOFTWARE_SPI) && (_IS_HW_SPI(MOSI) || _IS_HW_SPI(MISO) || _IS_HW_SPI(SCK)) #error "DUE hardware SPI is required but is incompatible with TMC2130 software SPI. Either disable TMC_USE_SW_SPI or use separate pins for the two SPIs." @@ -77,7 +81,7 @@ #endif #if ENABLED(FAST_PWM_FAN) || SPINDLE_LASER_FREQUENCY - #error "Features requiring Hardware PWM (FAST_PWM_FAN, SPINDLE_LASER_FREQUENCY) are not yet supported on DUE." + #error "Features requiring Hardware PWM (FAST_PWM_FAN, SPINDLE_LASER_FREQUENCY) are not yet supported for HAL/DUE." #endif #if HAS_TMC_SW_SERIAL diff --git a/Marlin/src/HAL/DUE/pinsDebug.h b/Marlin/src/HAL/DUE/pinsDebug.h index 2aafe9be0c..1544853553 100644 --- a/Marlin/src/HAL/DUE/pinsDebug.h +++ b/Marlin/src/HAL/DUE/pinsDebug.h @@ -64,7 +64,6 @@ #define NUMBER_PINS_TOTAL PINS_COUNT #define digitalRead_mod(p) extDigitalRead(p) // AVR digitalRead disabled PWM before it read the pin -#define PRINT_PORT(p) #define PRINT_ARRAY_NAME(x) do{ sprintf_P(buffer, PSTR("%-" STRINGIFY(MAX_NAME_LENGTH) "s"), pin_array[x].name); SERIAL_ECHO(buffer); }while(0) #define PRINT_PIN(p) do{ sprintf_P(buffer, PSTR("%02d"), p); SERIAL_ECHO(buffer); }while(0) #define PRINT_PIN_ANALOG(p) do{ sprintf_P(buffer, PSTR(" (A%2d) "), DIGITAL_PIN_TO_ANALOG_PIN(pin)); SERIAL_ECHO(buffer); }while(0) @@ -93,6 +92,8 @@ void pwm_details(int32_t pin) { } } +void print_port(const pin_t) {} + /** * DUE Board pin | PORT | Label * ----------------+--------+------- diff --git a/Marlin/src/HAL/DUE/timers.cpp b/Marlin/src/HAL/DUE/timers.cpp index e5647817b6..e388255c08 100644 --- a/Marlin/src/HAL/DUE/timers.cpp +++ b/Marlin/src/HAL/DUE/timers.cpp @@ -1,9 +1,9 @@ /** * Marlin 3D Printer Firmware - * * Copyright (c) 2020 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] - * Copyright (c) 2016 Bob Cousins bobcousins42@googlemail.com - * Copyright (c) 2015-2016 Nico Tonnhofer wurstnase.reprap@gmail.com + * + * 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 diff --git a/Marlin/src/HAL/DUE/timers.h b/Marlin/src/HAL/DUE/timers.h index dc35c77e63..db5d83a06f 100644 --- a/Marlin/src/HAL/DUE/timers.h +++ b/Marlin/src/HAL/DUE/timers.h @@ -1,8 +1,9 @@ /** * Marlin 3D Printer Firmware - * * Copyright (c) 2020 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] - * Copyright (c) 2016 Bob Cousins bobcousins42@googlemail.com + * + * 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 diff --git a/Marlin/src/HAL/DUE/u8g/LCD_defines.h b/Marlin/src/HAL/DUE/u8g/LCD_defines.h new file mode 100644 index 0000000000..e85f13514f --- /dev/null +++ b/Marlin/src/HAL/DUE/u8g/LCD_defines.h @@ -0,0 +1,34 @@ +/** + * Marlin 3D Printer Firmware + * Copyright (c) 2023 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] + * + * Based on Sprinter and grbl. + * Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (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 + +/** + * DUE (SAM3X8E) LCD-specific defines + */ + +uint8_t u8g_com_HAL_DUE_sw_spi_fn(u8g_t *u8g, uint8_t msg, uint8_t arg_val, void *arg_ptr); +uint8_t u8g_com_HAL_DUE_shared_hw_spi_fn(u8g_t *u8g, uint8_t msg, uint8_t arg_val, void *arg_ptr); +uint8_t u8g_com_HAL_DUE_ST7920_sw_spi_fn(u8g_t *u8g, uint8_t msg, uint8_t arg_val, void *arg_ptr); + +#define U8G_COM_HAL_SW_SPI_FN u8g_com_HAL_DUE_sw_spi_fn +#define U8G_COM_HAL_HW_SPI_FN u8g_com_HAL_DUE_shared_hw_spi_fn +#define U8G_COM_ST7920_HAL_SW_SPI u8g_com_HAL_DUE_ST7920_sw_spi_fn diff --git a/Marlin/src/HAL/DUE/dogm/u8g_com_HAL_DUE_shared_hw_spi.cpp b/Marlin/src/HAL/DUE/u8g/u8g_com_HAL_DUE_shared_hw_spi.cpp similarity index 100% rename from Marlin/src/HAL/DUE/dogm/u8g_com_HAL_DUE_shared_hw_spi.cpp rename to Marlin/src/HAL/DUE/u8g/u8g_com_HAL_DUE_shared_hw_spi.cpp diff --git a/Marlin/src/HAL/DUE/dogm/u8g_com_HAL_DUE_st7920_sw_spi.cpp b/Marlin/src/HAL/DUE/u8g/u8g_com_HAL_DUE_st7920_sw_spi.cpp similarity index 100% rename from Marlin/src/HAL/DUE/dogm/u8g_com_HAL_DUE_st7920_sw_spi.cpp rename to Marlin/src/HAL/DUE/u8g/u8g_com_HAL_DUE_st7920_sw_spi.cpp diff --git a/Marlin/src/HAL/DUE/dogm/u8g_com_HAL_DUE_sw_spi.cpp b/Marlin/src/HAL/DUE/u8g/u8g_com_HAL_DUE_sw_spi.cpp similarity index 100% rename from Marlin/src/HAL/DUE/dogm/u8g_com_HAL_DUE_sw_spi.cpp rename to Marlin/src/HAL/DUE/u8g/u8g_com_HAL_DUE_sw_spi.cpp diff --git a/Marlin/src/HAL/DUE/dogm/u8g_com_HAL_DUE_sw_spi_shared.cpp b/Marlin/src/HAL/DUE/u8g/u8g_com_HAL_DUE_sw_spi_shared.cpp similarity index 98% rename from Marlin/src/HAL/DUE/dogm/u8g_com_HAL_DUE_sw_spi_shared.cpp rename to Marlin/src/HAL/DUE/u8g/u8g_com_HAL_DUE_sw_spi_shared.cpp index 904924793b..86c8a48470 100644 --- a/Marlin/src/HAL/DUE/dogm/u8g_com_HAL_DUE_sw_spi_shared.cpp +++ b/Marlin/src/HAL/DUE/u8g/u8g_com_HAL_DUE_sw_spi_shared.cpp @@ -81,7 +81,7 @@ Pio *SCK_pPio, *MOSI_pPio; uint32_t SCK_dwMask, MOSI_dwMask; void u8g_spiSend_sw_DUE_mode_0(uint8_t val) { // 3MHz - LOOP_L_N(i, 8) { + for (uint8_t i = 0; i < 8; ++i) { if (val & 0x80) MOSI_pPio->PIO_SODR = MOSI_dwMask; else @@ -95,7 +95,7 @@ void u8g_spiSend_sw_DUE_mode_0(uint8_t val) { // 3MHz } void u8g_spiSend_sw_DUE_mode_3(uint8_t val) { // 3.5MHz - LOOP_L_N(i, 8) { + for (uint8_t i = 0; i < 8; ++i) { SCK_pPio->PIO_CODR = SCK_dwMask; DELAY_NS(50); if (val & 0x80) diff --git a/Marlin/src/HAL/DUE/dogm/u8g_com_HAL_DUE_sw_spi_shared.h b/Marlin/src/HAL/DUE/u8g/u8g_com_HAL_DUE_sw_spi_shared.h similarity index 100% rename from Marlin/src/HAL/DUE/dogm/u8g_com_HAL_DUE_sw_spi_shared.h rename to Marlin/src/HAL/DUE/u8g/u8g_com_HAL_DUE_sw_spi_shared.h diff --git a/Marlin/src/HAL/DUE/usb/conf_usb.h b/Marlin/src/HAL/DUE/usb/conf_usb.h index 4de9e347e2..f66194c6e6 100644 --- a/Marlin/src/HAL/DUE/usb/conf_usb.h +++ b/Marlin/src/HAL/DUE/usb/conf_usb.h @@ -101,7 +101,7 @@ #define USB_DEVICE_SPECIFIC_REQUEST() usb_task_other_requests() //@} -#if ENABLED(SDSUPPORT) +#if HAS_MEDIA /** * USB Device low level configuration * When only one interface is used, these configurations are defined by the class module. @@ -185,7 +185,7 @@ //! Enable id string of interface to add an extra USB string #define UDI_CDC_IAD_STRING_ID 4 -#if ENABLED(SDSUPPORT) +#if HAS_MEDIA /** * USB CDC low level configuration * In standalone these configurations are defined by the CDC module. diff --git a/Marlin/src/HAL/DUE/usb/genclk.h b/Marlin/src/HAL/DUE/usb/genclk.h index cde03bc0d1..45eba5873f 100644 --- a/Marlin/src/HAL/DUE/usb/genclk.h +++ b/Marlin/src/HAL/DUE/usb/genclk.h @@ -74,17 +74,17 @@ extern "C" { //@{ enum genclk_source { - GENCLK_PCK_SRC_SLCK_RC = 0, //!< Internal 32kHz RC oscillator as PCK source clock - GENCLK_PCK_SRC_SLCK_XTAL = 1, //!< External 32kHz crystal oscillator as PCK source clock - GENCLK_PCK_SRC_SLCK_BYPASS = 2, //!< External 32kHz bypass oscillator as PCK source clock - GENCLK_PCK_SRC_MAINCK_4M_RC = 3, //!< Internal 4MHz RC oscillator as PCK source clock - GENCLK_PCK_SRC_MAINCK_8M_RC = 4, //!< Internal 8MHz RC oscillator as PCK source clock - GENCLK_PCK_SRC_MAINCK_12M_RC = 5, //!< Internal 12MHz RC oscillator as PCK source clock - GENCLK_PCK_SRC_MAINCK_XTAL = 6, //!< External crystal oscillator as PCK source clock - GENCLK_PCK_SRC_MAINCK_BYPASS = 7, //!< External bypass oscillator as PCK source clock - GENCLK_PCK_SRC_PLLACK = 8, //!< Use PLLACK as PCK source clock - GENCLK_PCK_SRC_PLLBCK = 9, //!< Use PLLBCK as PCK source clock - GENCLK_PCK_SRC_MCK = 10, //!< Use Master Clk as PCK source clock + GENCLK_PCK_SRC_SLCK_RC = 0, //!< Internal 32kHz RC oscillator as PCK source clock + GENCLK_PCK_SRC_SLCK_XTAL = 1, //!< External 32kHz crystal oscillator as PCK source clock + GENCLK_PCK_SRC_SLCK_BYPASS = 2, //!< External 32kHz bypass oscillator as PCK source clock + GENCLK_PCK_SRC_MAINCK_4M_RC = 3, //!< Internal 4MHz RC oscillator as PCK source clock + GENCLK_PCK_SRC_MAINCK_8M_RC = 4, //!< Internal 8MHz RC oscillator as PCK source clock + GENCLK_PCK_SRC_MAINCK_12M_RC = 5, //!< Internal 12MHz RC oscillator as PCK source clock + GENCLK_PCK_SRC_MAINCK_XTAL = 6, //!< External crystal oscillator as PCK source clock + GENCLK_PCK_SRC_MAINCK_BYPASS = 7, //!< External bypass oscillator as PCK source clock + GENCLK_PCK_SRC_PLLACK = 8, //!< Use PLLACK as PCK source clock + GENCLK_PCK_SRC_PLLBCK = 9, //!< Use PLLBCK as PCK source clock + GENCLK_PCK_SRC_MCK = 10, //!< Use Master Clk as PCK source clock }; //@} @@ -93,176 +93,162 @@ enum genclk_source { //@{ enum genclk_divider { - GENCLK_PCK_PRES_1 = PMC_PCK_PRES_CLK_1, //!< Set PCK clock prescaler to 1 - GENCLK_PCK_PRES_2 = PMC_PCK_PRES_CLK_2, //!< Set PCK clock prescaler to 2 - GENCLK_PCK_PRES_4 = PMC_PCK_PRES_CLK_4, //!< Set PCK clock prescaler to 4 - GENCLK_PCK_PRES_8 = PMC_PCK_PRES_CLK_8, //!< Set PCK clock prescaler to 8 - GENCLK_PCK_PRES_16 = PMC_PCK_PRES_CLK_16, //!< Set PCK clock prescaler to 16 - GENCLK_PCK_PRES_32 = PMC_PCK_PRES_CLK_32, //!< Set PCK clock prescaler to 32 - GENCLK_PCK_PRES_64 = PMC_PCK_PRES_CLK_64, //!< Set PCK clock prescaler to 64 + GENCLK_PCK_PRES_1 = PMC_PCK_PRES_CLK_1, //!< Set PCK clock prescaler to 1 + GENCLK_PCK_PRES_2 = PMC_PCK_PRES_CLK_2, //!< Set PCK clock prescaler to 2 + GENCLK_PCK_PRES_4 = PMC_PCK_PRES_CLK_4, //!< Set PCK clock prescaler to 4 + GENCLK_PCK_PRES_8 = PMC_PCK_PRES_CLK_8, //!< Set PCK clock prescaler to 8 + GENCLK_PCK_PRES_16 = PMC_PCK_PRES_CLK_16, //!< Set PCK clock prescaler to 16 + GENCLK_PCK_PRES_32 = PMC_PCK_PRES_CLK_32, //!< Set PCK clock prescaler to 32 + GENCLK_PCK_PRES_64 = PMC_PCK_PRES_CLK_64, //!< Set PCK clock prescaler to 64 }; //@} struct genclk_config { - uint32_t ctrl; + uint32_t ctrl; }; -static inline void genclk_config_defaults(struct genclk_config *p_cfg, - uint32_t ul_id) -{ - ul_id = ul_id; - p_cfg->ctrl = 0; +static inline void genclk_config_defaults(struct genclk_config *p_cfg, uint32_t ul_id) { + ul_id = ul_id; + p_cfg->ctrl = 0; } -static inline void genclk_config_read(struct genclk_config *p_cfg, - uint32_t ul_id) -{ - p_cfg->ctrl = PMC->PMC_PCK[ul_id]; +static inline void genclk_config_read(struct genclk_config *p_cfg, uint32_t ul_id) { + p_cfg->ctrl = PMC->PMC_PCK[ul_id]; } -static inline void genclk_config_write(const struct genclk_config *p_cfg, - uint32_t ul_id) -{ - PMC->PMC_PCK[ul_id] = p_cfg->ctrl; +static inline void genclk_config_write(const struct genclk_config *p_cfg, uint32_t ul_id) { + PMC->PMC_PCK[ul_id] = p_cfg->ctrl; } //! \name Programmable Clock Source and Prescaler configuration //@{ -static inline void genclk_config_set_source(struct genclk_config *p_cfg, - enum genclk_source e_src) -{ - p_cfg->ctrl &= (~PMC_PCK_CSS_Msk); +static inline void genclk_config_set_source(struct genclk_config *p_cfg, enum genclk_source e_src) { + p_cfg->ctrl &= (~PMC_PCK_CSS_Msk); - switch (e_src) { - case GENCLK_PCK_SRC_SLCK_RC: - case GENCLK_PCK_SRC_SLCK_XTAL: - case GENCLK_PCK_SRC_SLCK_BYPASS: - p_cfg->ctrl |= (PMC_PCK_CSS_SLOW_CLK); - break; + switch (e_src) { + case GENCLK_PCK_SRC_SLCK_RC: + case GENCLK_PCK_SRC_SLCK_XTAL: + case GENCLK_PCK_SRC_SLCK_BYPASS: + p_cfg->ctrl |= (PMC_PCK_CSS_SLOW_CLK); + break; - case GENCLK_PCK_SRC_MAINCK_4M_RC: - case GENCLK_PCK_SRC_MAINCK_8M_RC: - case GENCLK_PCK_SRC_MAINCK_12M_RC: - case GENCLK_PCK_SRC_MAINCK_XTAL: - case GENCLK_PCK_SRC_MAINCK_BYPASS: - p_cfg->ctrl |= (PMC_PCK_CSS_MAIN_CLK); - break; + case GENCLK_PCK_SRC_MAINCK_4M_RC: + case GENCLK_PCK_SRC_MAINCK_8M_RC: + case GENCLK_PCK_SRC_MAINCK_12M_RC: + case GENCLK_PCK_SRC_MAINCK_XTAL: + case GENCLK_PCK_SRC_MAINCK_BYPASS: + p_cfg->ctrl |= (PMC_PCK_CSS_MAIN_CLK); + break; - case GENCLK_PCK_SRC_PLLACK: - p_cfg->ctrl |= (PMC_PCK_CSS_PLLA_CLK); - break; + case GENCLK_PCK_SRC_PLLACK: + p_cfg->ctrl |= (PMC_PCK_CSS_PLLA_CLK); + break; - case GENCLK_PCK_SRC_PLLBCK: - p_cfg->ctrl |= (PMC_PCK_CSS_UPLL_CLK); - break; + case GENCLK_PCK_SRC_PLLBCK: + p_cfg->ctrl |= (PMC_PCK_CSS_UPLL_CLK); + break; - case GENCLK_PCK_SRC_MCK: - p_cfg->ctrl |= (PMC_PCK_CSS_MCK); - break; - } + case GENCLK_PCK_SRC_MCK: + p_cfg->ctrl |= (PMC_PCK_CSS_MCK); + break; + } } -static inline void genclk_config_set_divider(struct genclk_config *p_cfg, - uint32_t e_divider) -{ - p_cfg->ctrl &= ~PMC_PCK_PRES_Msk; - p_cfg->ctrl |= e_divider; +static inline void genclk_config_set_divider(struct genclk_config *p_cfg, uint32_t e_divider) { + p_cfg->ctrl &= ~PMC_PCK_PRES_Msk; + p_cfg->ctrl |= e_divider; } //@} -static inline void genclk_enable(const struct genclk_config *p_cfg, - uint32_t ul_id) -{ - PMC->PMC_PCK[ul_id] = p_cfg->ctrl; - pmc_enable_pck(ul_id); +static inline void genclk_enable(const struct genclk_config *p_cfg, uint32_t ul_id) { + PMC->PMC_PCK[ul_id] = p_cfg->ctrl; + pmc_enable_pck(ul_id); } -static inline void genclk_disable(uint32_t ul_id) -{ - pmc_disable_pck(ul_id); +static inline void genclk_disable(uint32_t ul_id) { + pmc_disable_pck(ul_id); } -static inline void genclk_enable_source(enum genclk_source e_src) -{ - switch (e_src) { - case GENCLK_PCK_SRC_SLCK_RC: - if (!osc_is_ready(OSC_SLCK_32K_RC)) { - osc_enable(OSC_SLCK_32K_RC); - osc_wait_ready(OSC_SLCK_32K_RC); - } - break; +static inline void genclk_enable_source(enum genclk_source e_src) { + switch (e_src) { + case GENCLK_PCK_SRC_SLCK_RC: + if (!osc_is_ready(OSC_SLCK_32K_RC)) { + osc_enable(OSC_SLCK_32K_RC); + osc_wait_ready(OSC_SLCK_32K_RC); + } + break; - case GENCLK_PCK_SRC_SLCK_XTAL: - if (!osc_is_ready(OSC_SLCK_32K_XTAL)) { - osc_enable(OSC_SLCK_32K_XTAL); - osc_wait_ready(OSC_SLCK_32K_XTAL); - } - break; + case GENCLK_PCK_SRC_SLCK_XTAL: + if (!osc_is_ready(OSC_SLCK_32K_XTAL)) { + osc_enable(OSC_SLCK_32K_XTAL); + osc_wait_ready(OSC_SLCK_32K_XTAL); + } + break; - case GENCLK_PCK_SRC_SLCK_BYPASS: - if (!osc_is_ready(OSC_SLCK_32K_BYPASS)) { - osc_enable(OSC_SLCK_32K_BYPASS); - osc_wait_ready(OSC_SLCK_32K_BYPASS); - } - break; + case GENCLK_PCK_SRC_SLCK_BYPASS: + if (!osc_is_ready(OSC_SLCK_32K_BYPASS)) { + osc_enable(OSC_SLCK_32K_BYPASS); + osc_wait_ready(OSC_SLCK_32K_BYPASS); + } + break; - case GENCLK_PCK_SRC_MAINCK_4M_RC: - if (!osc_is_ready(OSC_MAINCK_4M_RC)) { - osc_enable(OSC_MAINCK_4M_RC); - osc_wait_ready(OSC_MAINCK_4M_RC); - } - break; + case GENCLK_PCK_SRC_MAINCK_4M_RC: + if (!osc_is_ready(OSC_MAINCK_4M_RC)) { + osc_enable(OSC_MAINCK_4M_RC); + osc_wait_ready(OSC_MAINCK_4M_RC); + } + break; - case GENCLK_PCK_SRC_MAINCK_8M_RC: - if (!osc_is_ready(OSC_MAINCK_8M_RC)) { - osc_enable(OSC_MAINCK_8M_RC); - osc_wait_ready(OSC_MAINCK_8M_RC); - } - break; + case GENCLK_PCK_SRC_MAINCK_8M_RC: + if (!osc_is_ready(OSC_MAINCK_8M_RC)) { + osc_enable(OSC_MAINCK_8M_RC); + osc_wait_ready(OSC_MAINCK_8M_RC); + } + break; - case GENCLK_PCK_SRC_MAINCK_12M_RC: - if (!osc_is_ready(OSC_MAINCK_12M_RC)) { - osc_enable(OSC_MAINCK_12M_RC); - osc_wait_ready(OSC_MAINCK_12M_RC); - } - break; + case GENCLK_PCK_SRC_MAINCK_12M_RC: + if (!osc_is_ready(OSC_MAINCK_12M_RC)) { + osc_enable(OSC_MAINCK_12M_RC); + osc_wait_ready(OSC_MAINCK_12M_RC); + } + break; - case GENCLK_PCK_SRC_MAINCK_XTAL: - if (!osc_is_ready(OSC_MAINCK_XTAL)) { - osc_enable(OSC_MAINCK_XTAL); - osc_wait_ready(OSC_MAINCK_XTAL); - } - break; + case GENCLK_PCK_SRC_MAINCK_XTAL: + if (!osc_is_ready(OSC_MAINCK_XTAL)) { + osc_enable(OSC_MAINCK_XTAL); + osc_wait_ready(OSC_MAINCK_XTAL); + } + break; - case GENCLK_PCK_SRC_MAINCK_BYPASS: - if (!osc_is_ready(OSC_MAINCK_BYPASS)) { - osc_enable(OSC_MAINCK_BYPASS); - osc_wait_ready(OSC_MAINCK_BYPASS); - } - break; + case GENCLK_PCK_SRC_MAINCK_BYPASS: + if (!osc_is_ready(OSC_MAINCK_BYPASS)) { + osc_enable(OSC_MAINCK_BYPASS); + osc_wait_ready(OSC_MAINCK_BYPASS); + } + break; -#ifdef CONFIG_PLL0_SOURCE - case GENCLK_PCK_SRC_PLLACK: - pll_enable_config_defaults(0); - break; -#endif + #ifdef CONFIG_PLL0_SOURCE + case GENCLK_PCK_SRC_PLLACK: + pll_enable_config_defaults(0); + break; + #endif -#ifdef CONFIG_PLL1_SOURCE - case GENCLK_PCK_SRC_PLLBCK: - pll_enable_config_defaults(1); - break; -#endif + #ifdef CONFIG_PLL1_SOURCE + case GENCLK_PCK_SRC_PLLBCK: + pll_enable_config_defaults(1); + break; + #endif - case GENCLK_PCK_SRC_MCK: - break; + case GENCLK_PCK_SRC_MCK: + break; - default: - Assert(false); - break; - } + default: + Assert(false); + break; + } } //! @} diff --git a/Marlin/src/HAL/DUE/usb/osc.h b/Marlin/src/HAL/DUE/usb/osc.h index 953bcbbed1..c0ae24381a 100644 --- a/Marlin/src/HAL/DUE/usb/osc.h +++ b/Marlin/src/HAL/DUE/usb/osc.h @@ -62,28 +62,28 @@ extern "C" { * should be defined by the board code, otherwise default value are used. */ #ifndef BOARD_FREQ_SLCK_XTAL -# warning The board slow clock xtal frequency has not been defined. -# define BOARD_FREQ_SLCK_XTAL (32768UL) + #warning The board slow clock xtal frequency has not been defined. + #define BOARD_FREQ_SLCK_XTAL (32768UL) #endif #ifndef BOARD_FREQ_SLCK_BYPASS -# warning The board slow clock bypass frequency has not been defined. -# define BOARD_FREQ_SLCK_BYPASS (32768UL) + #warning The board slow clock bypass frequency has not been defined. + #define BOARD_FREQ_SLCK_BYPASS (32768UL) #endif #ifndef BOARD_FREQ_MAINCK_XTAL -# warning The board main clock xtal frequency has not been defined. -# define BOARD_FREQ_MAINCK_XTAL (12000000UL) + #warning The board main clock xtal frequency has not been defined. + #define BOARD_FREQ_MAINCK_XTAL (12000000UL) #endif #ifndef BOARD_FREQ_MAINCK_BYPASS -# warning The board main clock bypass frequency has not been defined. -# define BOARD_FREQ_MAINCK_BYPASS (12000000UL) + #warning The board main clock bypass frequency has not been defined. + #define BOARD_FREQ_MAINCK_BYPASS (12000000UL) #endif #ifndef BOARD_OSC_STARTUP_US -# warning The board main clock xtal startup time has not been defined. -# define BOARD_OSC_STARTUP_US (15625UL) + #warning The board main clock xtal startup time has not been defined. + #define BOARD_OSC_STARTUP_US (15625UL) #endif /** @@ -115,122 +115,118 @@ extern "C" { #define OSC_MAINCK_BYPASS_HZ BOARD_FREQ_MAINCK_BYPASS //!< External bypass oscillator. //@} -static inline void osc_enable(uint32_t ul_id) -{ - switch (ul_id) { - case OSC_SLCK_32K_RC: - break; +static inline void osc_enable(uint32_t ul_id) { + switch (ul_id) { + case OSC_SLCK_32K_RC: + break; - case OSC_SLCK_32K_XTAL: - pmc_switch_sclk_to_32kxtal(PMC_OSC_XTAL); - break; + case OSC_SLCK_32K_XTAL: + pmc_switch_sclk_to_32kxtal(PMC_OSC_XTAL); + break; - case OSC_SLCK_32K_BYPASS: - pmc_switch_sclk_to_32kxtal(PMC_OSC_BYPASS); - break; + case OSC_SLCK_32K_BYPASS: + pmc_switch_sclk_to_32kxtal(PMC_OSC_BYPASS); + break; - case OSC_MAINCK_4M_RC: - pmc_switch_mainck_to_fastrc(CKGR_MOR_MOSCRCF_4_MHz); - break; + case OSC_MAINCK_4M_RC: + pmc_switch_mainck_to_fastrc(CKGR_MOR_MOSCRCF_4_MHz); + break; - case OSC_MAINCK_8M_RC: - pmc_switch_mainck_to_fastrc(CKGR_MOR_MOSCRCF_8_MHz); - break; + case OSC_MAINCK_8M_RC: + pmc_switch_mainck_to_fastrc(CKGR_MOR_MOSCRCF_8_MHz); + break; - case OSC_MAINCK_12M_RC: - pmc_switch_mainck_to_fastrc(CKGR_MOR_MOSCRCF_12_MHz); - break; + case OSC_MAINCK_12M_RC: + pmc_switch_mainck_to_fastrc(CKGR_MOR_MOSCRCF_12_MHz); + break; - case OSC_MAINCK_XTAL: - pmc_switch_mainck_to_xtal(PMC_OSC_XTAL/*, - pmc_us_to_moscxtst(BOARD_OSC_STARTUP_US, - OSC_SLCK_32K_RC_HZ)*/); - break; + case OSC_MAINCK_XTAL: + pmc_switch_mainck_to_xtal(PMC_OSC_XTAL/*, + pmc_us_to_moscxtst(BOARD_OSC_STARTUP_US, + OSC_SLCK_32K_RC_HZ)*/); + break; - case OSC_MAINCK_BYPASS: - pmc_switch_mainck_to_xtal(PMC_OSC_BYPASS/*, - pmc_us_to_moscxtst(BOARD_OSC_STARTUP_US, - OSC_SLCK_32K_RC_HZ)*/); - break; - } + case OSC_MAINCK_BYPASS: + pmc_switch_mainck_to_xtal(PMC_OSC_BYPASS/*, + pmc_us_to_moscxtst(BOARD_OSC_STARTUP_US, + OSC_SLCK_32K_RC_HZ)*/); + break; + } } -static inline void osc_disable(uint32_t ul_id) -{ - switch (ul_id) { - case OSC_SLCK_32K_RC: - case OSC_SLCK_32K_XTAL: - case OSC_SLCK_32K_BYPASS: - break; +static inline void osc_disable(uint32_t ul_id) { + switch (ul_id) { + case OSC_SLCK_32K_RC: + case OSC_SLCK_32K_XTAL: + case OSC_SLCK_32K_BYPASS: + break; - case OSC_MAINCK_4M_RC: - case OSC_MAINCK_8M_RC: - case OSC_MAINCK_12M_RC: - pmc_osc_disable_fastrc(); - break; + case OSC_MAINCK_4M_RC: + case OSC_MAINCK_8M_RC: + case OSC_MAINCK_12M_RC: + pmc_osc_disable_fastrc(); + break; - case OSC_MAINCK_XTAL: - pmc_osc_disable_xtal(PMC_OSC_XTAL); - break; + case OSC_MAINCK_XTAL: + pmc_osc_disable_xtal(PMC_OSC_XTAL); + break; - case OSC_MAINCK_BYPASS: - pmc_osc_disable_xtal(PMC_OSC_BYPASS); - break; - } + case OSC_MAINCK_BYPASS: + pmc_osc_disable_xtal(PMC_OSC_BYPASS); + break; + } } -static inline bool osc_is_ready(uint32_t ul_id) -{ - switch (ul_id) { - case OSC_SLCK_32K_RC: - return 1; +static inline bool osc_is_ready(uint32_t ul_id) { + switch (ul_id) { + case OSC_SLCK_32K_RC: + return 1; - case OSC_SLCK_32K_XTAL: - case OSC_SLCK_32K_BYPASS: - return pmc_osc_is_ready_32kxtal(); + case OSC_SLCK_32K_XTAL: + case OSC_SLCK_32K_BYPASS: + return pmc_osc_is_ready_32kxtal(); - case OSC_MAINCK_4M_RC: - case OSC_MAINCK_8M_RC: - case OSC_MAINCK_12M_RC: - case OSC_MAINCK_XTAL: - case OSC_MAINCK_BYPASS: - return pmc_osc_is_ready_mainck(); - } + case OSC_MAINCK_4M_RC: + case OSC_MAINCK_8M_RC: + case OSC_MAINCK_12M_RC: + case OSC_MAINCK_XTAL: + case OSC_MAINCK_BYPASS: + return pmc_osc_is_ready_mainck(); + } - return 0; + return 0; } -static inline uint32_t osc_get_rate(uint32_t ul_id) -{ - switch (ul_id) { - case OSC_SLCK_32K_RC: - return OSC_SLCK_32K_RC_HZ; +static inline uint32_t osc_get_rate(uint32_t ul_id) { + switch (ul_id) { + case OSC_SLCK_32K_RC: + return OSC_SLCK_32K_RC_HZ; - case OSC_SLCK_32K_XTAL: - return BOARD_FREQ_SLCK_XTAL; + case OSC_SLCK_32K_XTAL: + return BOARD_FREQ_SLCK_XTAL; - case OSC_SLCK_32K_BYPASS: - return BOARD_FREQ_SLCK_BYPASS; + case OSC_SLCK_32K_BYPASS: + return BOARD_FREQ_SLCK_BYPASS; - case OSC_MAINCK_4M_RC: - return OSC_MAINCK_4M_RC_HZ; + case OSC_MAINCK_4M_RC: + return OSC_MAINCK_4M_RC_HZ; - case OSC_MAINCK_8M_RC: - return OSC_MAINCK_8M_RC_HZ; + case OSC_MAINCK_8M_RC: + return OSC_MAINCK_8M_RC_HZ; - case OSC_MAINCK_12M_RC: - return OSC_MAINCK_12M_RC_HZ; + case OSC_MAINCK_12M_RC: + return OSC_MAINCK_12M_RC_HZ; - case OSC_MAINCK_XTAL: - return BOARD_FREQ_MAINCK_XTAL; + case OSC_MAINCK_XTAL: + return BOARD_FREQ_MAINCK_XTAL; - case OSC_MAINCK_BYPASS: - return BOARD_FREQ_MAINCK_BYPASS; - } + case OSC_MAINCK_BYPASS: + return BOARD_FREQ_MAINCK_BYPASS; + } - return 0; + return 0; } /** @@ -241,11 +237,10 @@ static inline uint32_t osc_get_rate(uint32_t ul_id) * * \param id A number identifying the oscillator to wait for. */ -static inline void osc_wait_ready(uint8_t id) -{ - while (!osc_is_ready(id)) { - /* Do nothing */ - } +static inline void osc_wait_ready(uint8_t id) { + while (!osc_is_ready(id)) { + /* Do nothing */ + } } //! @} diff --git a/Marlin/src/HAL/DUE/usb/pll.h b/Marlin/src/HAL/DUE/usb/pll.h index 8eaf27672b..d25a1f65d0 100644 --- a/Marlin/src/HAL/DUE/usb/pll.h +++ b/Marlin/src/HAL/DUE/usb/pll.h @@ -77,22 +77,22 @@ extern "C" { #define PLL_COUNT 0x3FU enum pll_source { - PLL_SRC_MAINCK_4M_RC = OSC_MAINCK_4M_RC, //!< Internal 4MHz RC oscillator. - PLL_SRC_MAINCK_8M_RC = OSC_MAINCK_8M_RC, //!< Internal 8MHz RC oscillator. - PLL_SRC_MAINCK_12M_RC = OSC_MAINCK_12M_RC, //!< Internal 12MHz RC oscillator. - PLL_SRC_MAINCK_XTAL = OSC_MAINCK_XTAL, //!< External crystal oscillator. - PLL_SRC_MAINCK_BYPASS = OSC_MAINCK_BYPASS, //!< External bypass oscillator. - PLL_NR_SOURCES, //!< Number of PLL sources. + PLL_SRC_MAINCK_4M_RC = OSC_MAINCK_4M_RC, //!< Internal 4MHz RC oscillator. + PLL_SRC_MAINCK_8M_RC = OSC_MAINCK_8M_RC, //!< Internal 8MHz RC oscillator. + PLL_SRC_MAINCK_12M_RC = OSC_MAINCK_12M_RC, //!< Internal 12MHz RC oscillator. + PLL_SRC_MAINCK_XTAL = OSC_MAINCK_XTAL, //!< External crystal oscillator. + PLL_SRC_MAINCK_BYPASS = OSC_MAINCK_BYPASS, //!< External bypass oscillator. + PLL_NR_SOURCES, //!< Number of PLL sources. }; struct pll_config { - uint32_t ctrl; + uint32_t ctrl; }; #define pll_get_default_rate(pll_id) \ - ((osc_get_rate(CONFIG_PLL##pll_id##_SOURCE) \ - * CONFIG_PLL##pll_id##_MUL) \ - / CONFIG_PLL##pll_id##_DIV) + ((osc_get_rate(CONFIG_PLL##pll_id##_SOURCE) \ + * CONFIG_PLL##pll_id##_MUL) \ + / CONFIG_PLL##pll_id##_DIV) /* Force UTMI PLL parameters (Hardware defined) */ #ifdef CONFIG_PLL1_SOURCE @@ -113,145 +113,130 @@ struct pll_config { * is hidden in this implementation. Use mul as mul effective value. */ static inline void pll_config_init(struct pll_config *p_cfg, - enum pll_source e_src, uint32_t ul_div, uint32_t ul_mul) -{ - uint32_t vco_hz; + enum pll_source e_src, uint32_t ul_div, uint32_t ul_mul) { + uint32_t vco_hz; - Assert(e_src < PLL_NR_SOURCES); + Assert(e_src < PLL_NR_SOURCES); - if (ul_div == 0 && ul_mul == 0) { /* Must only be true for UTMI PLL */ - p_cfg->ctrl = CKGR_UCKR_UPLLCOUNT(PLL_COUNT); - } else { /* PLLA */ - /* Calculate internal VCO frequency */ - vco_hz = osc_get_rate(e_src) / ul_div; - Assert(vco_hz >= PLL_INPUT_MIN_HZ); - Assert(vco_hz <= PLL_INPUT_MAX_HZ); + if (ul_div == 0 && ul_mul == 0) { /* Must only be true for UTMI PLL */ + p_cfg->ctrl = CKGR_UCKR_UPLLCOUNT(PLL_COUNT); + } + else { /* PLLA */ + /* Calculate internal VCO frequency */ + vco_hz = osc_get_rate(e_src) / ul_div; + Assert(vco_hz >= PLL_INPUT_MIN_HZ); + Assert(vco_hz <= PLL_INPUT_MAX_HZ); - vco_hz *= ul_mul; - Assert(vco_hz >= PLL_OUTPUT_MIN_HZ); - Assert(vco_hz <= PLL_OUTPUT_MAX_HZ); + vco_hz *= ul_mul; + Assert(vco_hz >= PLL_OUTPUT_MIN_HZ); + Assert(vco_hz <= PLL_OUTPUT_MAX_HZ); - /* PMC hardware will automatically make it mul+1 */ - p_cfg->ctrl = CKGR_PLLAR_MULA(ul_mul - 1) | CKGR_PLLAR_DIVA(ul_div) | CKGR_PLLAR_PLLACOUNT(PLL_COUNT); - } + /* PMC hardware will automatically make it mul+1 */ + p_cfg->ctrl = CKGR_PLLAR_MULA(ul_mul - 1) | CKGR_PLLAR_DIVA(ul_div) | CKGR_PLLAR_PLLACOUNT(PLL_COUNT); + } } -#define pll_config_defaults(cfg, pll_id) \ - pll_config_init(cfg, \ - CONFIG_PLL##pll_id##_SOURCE, \ - CONFIG_PLL##pll_id##_DIV, \ - CONFIG_PLL##pll_id##_MUL) +#define pll_config_defaults(cfg, pll_id) \ + pll_config_init(cfg, \ + CONFIG_PLL##pll_id##_SOURCE, \ + CONFIG_PLL##pll_id##_DIV, \ + CONFIG_PLL##pll_id##_MUL) -static inline void pll_config_read(struct pll_config *p_cfg, uint32_t ul_pll_id) -{ - Assert(ul_pll_id < NR_PLLS); - - if (ul_pll_id == PLLA_ID) { - p_cfg->ctrl = PMC->CKGR_PLLAR; - } else { - p_cfg->ctrl = PMC->CKGR_UCKR; - } +static inline void pll_config_read(struct pll_config *p_cfg, uint32_t ul_pll_id) { + Assert(ul_pll_id < NR_PLLS); + p_cfg->ctrl = ul_pll_id == PLLA_ID ? PMC->CKGR_PLLAR : PMC->CKGR_UCKR; } -static inline void pll_config_write(const struct pll_config *p_cfg, uint32_t ul_pll_id) -{ - Assert(ul_pll_id < NR_PLLS); +static inline void pll_config_write(const struct pll_config *p_cfg, uint32_t ul_pll_id) { + Assert(ul_pll_id < NR_PLLS); - if (ul_pll_id == PLLA_ID) { - pmc_disable_pllack(); // Always stop PLL first! - PMC->CKGR_PLLAR = CKGR_PLLAR_ONE | p_cfg->ctrl; - } else { - PMC->CKGR_UCKR = p_cfg->ctrl; - } + if (ul_pll_id == PLLA_ID) { + pmc_disable_pllack(); // Always stop PLL first! + PMC->CKGR_PLLAR = CKGR_PLLAR_ONE | p_cfg->ctrl; + } + else + PMC->CKGR_UCKR = p_cfg->ctrl; } -static inline void pll_enable(const struct pll_config *p_cfg, uint32_t ul_pll_id) -{ - Assert(ul_pll_id < NR_PLLS); +static inline void pll_enable(const struct pll_config *p_cfg, uint32_t ul_pll_id) { + Assert(ul_pll_id < NR_PLLS); - if (ul_pll_id == PLLA_ID) { - pmc_disable_pllack(); // Always stop PLL first! - PMC->CKGR_PLLAR = CKGR_PLLAR_ONE | p_cfg->ctrl; - } else { - PMC->CKGR_UCKR = p_cfg->ctrl | CKGR_UCKR_UPLLEN; - } + if (ul_pll_id == PLLA_ID) { + pmc_disable_pllack(); // Always stop PLL first! + PMC->CKGR_PLLAR = CKGR_PLLAR_ONE | p_cfg->ctrl; + } + else + PMC->CKGR_UCKR = p_cfg->ctrl | CKGR_UCKR_UPLLEN; } /** * \note This will only disable the selected PLL, not the underlying oscillator (mainck). */ -static inline void pll_disable(uint32_t ul_pll_id) -{ - Assert(ul_pll_id < NR_PLLS); +static inline void pll_disable(uint32_t ul_pll_id) { + Assert(ul_pll_id < NR_PLLS); - if (ul_pll_id == PLLA_ID) { - pmc_disable_pllack(); - } else { - PMC->CKGR_UCKR &= ~CKGR_UCKR_UPLLEN; - } + if (ul_pll_id == PLLA_ID) + pmc_disable_pllack(); + else + PMC->CKGR_UCKR &= ~CKGR_UCKR_UPLLEN; } -static inline uint32_t pll_is_locked(uint32_t ul_pll_id) -{ - Assert(ul_pll_id < NR_PLLS); +static inline uint32_t pll_is_locked(uint32_t ul_pll_id) { + Assert(ul_pll_id < NR_PLLS); - if (ul_pll_id == PLLA_ID) { - return pmc_is_locked_pllack(); - } else { - return pmc_is_locked_upll(); - } + if (ul_pll_id == PLLA_ID) + return pmc_is_locked_pllack(); + else + return pmc_is_locked_upll(); } -static inline void pll_enable_source(enum pll_source e_src) -{ - switch (e_src) { - case PLL_SRC_MAINCK_4M_RC: - case PLL_SRC_MAINCK_8M_RC: - case PLL_SRC_MAINCK_12M_RC: - case PLL_SRC_MAINCK_XTAL: - case PLL_SRC_MAINCK_BYPASS: - osc_enable(e_src); - osc_wait_ready(e_src); - break; +static inline void pll_enable_source(enum pll_source e_src) { + switch (e_src) { + case PLL_SRC_MAINCK_4M_RC: + case PLL_SRC_MAINCK_8M_RC: + case PLL_SRC_MAINCK_12M_RC: + case PLL_SRC_MAINCK_XTAL: + case PLL_SRC_MAINCK_BYPASS: + osc_enable(e_src); + osc_wait_ready(e_src); + break; - default: - Assert(false); - break; - } + default: + Assert(false); + break; + } } -static inline void pll_enable_config_defaults(unsigned int ul_pll_id) -{ - struct pll_config pllcfg; +static inline void pll_enable_config_defaults(unsigned int ul_pll_id) { + struct pll_config pllcfg; - if (pll_is_locked(ul_pll_id)) { - return; // Pll already running - } - switch (ul_pll_id) { -#ifdef CONFIG_PLL0_SOURCE - case 0: - pll_enable_source(CONFIG_PLL0_SOURCE); - pll_config_init(&pllcfg, - CONFIG_PLL0_SOURCE, - CONFIG_PLL0_DIV, - CONFIG_PLL0_MUL); - break; -#endif -#ifdef CONFIG_PLL1_SOURCE - case 1: - pll_enable_source(CONFIG_PLL1_SOURCE); - pll_config_init(&pllcfg, - CONFIG_PLL1_SOURCE, - CONFIG_PLL1_DIV, - CONFIG_PLL1_MUL); - break; -#endif - default: - Assert(false); - break; - } - pll_enable(&pllcfg, ul_pll_id); - while (!pll_is_locked(ul_pll_id)); + if (pll_is_locked(ul_pll_id)) return; // Pll already running + + switch (ul_pll_id) { + #ifdef CONFIG_PLL0_SOURCE + case 0: + pll_enable_source(CONFIG_PLL0_SOURCE); + pll_config_init(&pllcfg, + CONFIG_PLL0_SOURCE, + CONFIG_PLL0_DIV, + CONFIG_PLL0_MUL); + break; + #endif + #ifdef CONFIG_PLL1_SOURCE + case 1: + pll_enable_source(CONFIG_PLL1_SOURCE); + pll_config_init(&pllcfg, + CONFIG_PLL1_SOURCE, + CONFIG_PLL1_DIV, + CONFIG_PLL1_MUL); + break; + #endif + default: + Assert(false); + break; + } + pll_enable(&pllcfg, ul_pll_id); + while (!pll_is_locked(ul_pll_id)); } /** @@ -264,15 +249,12 @@ static inline void pll_enable_config_defaults(unsigned int ul_pll_id) * \retval STATUS_OK The PLL is now locked. * \retval ERR_TIMEOUT Timed out waiting for PLL to become locked. */ -static inline int pll_wait_for_lock(unsigned int pll_id) -{ - Assert(pll_id < NR_PLLS); +static inline int pll_wait_for_lock(unsigned int pll_id) { + Assert(pll_id < NR_PLLS); - while (!pll_is_locked(pll_id)) { - /* Do nothing */ - } + while (!pll_is_locked(pll_id)) { /* Do nothing */ } - return 0; + return 0; } //! @} diff --git a/Marlin/src/HAL/DUE/usb/sbc_protocol.h b/Marlin/src/HAL/DUE/usb/sbc_protocol.h index ab845739fd..983ec7adca 100644 --- a/Marlin/src/HAL/DUE/usb/sbc_protocol.h +++ b/Marlin/src/HAL/DUE/usb/sbc_protocol.h @@ -57,7 +57,6 @@ #ifndef _SBC_PROTOCOL_H_ #define _SBC_PROTOCOL_H_ - /** * \ingroup usb_msc_protocol * \defgroup usb_sbc_protocol SCSI Block Commands protocol definitions @@ -81,82 +80,82 @@ //@{ enum scsi_sbc_mode { - SCSI_MS_MODE_RW_ERR_RECOV = 0x01, //!< Read-Write Error Recovery mode page - SCSI_MS_MODE_FORMAT_DEVICE = 0x03, //!< Format Device mode page - SCSI_MS_MODE_FLEXIBLE_DISK = 0x05, //!< Flexible Disk mode page - SCSI_MS_MODE_CACHING = 0x08, //!< Caching mode page + SCSI_MS_MODE_RW_ERR_RECOV = 0x01, //!< Read-Write Error Recovery mode page + SCSI_MS_MODE_FORMAT_DEVICE = 0x03, //!< Format Device mode page + SCSI_MS_MODE_FLEXIBLE_DISK = 0x05, //!< Flexible Disk mode page + SCSI_MS_MODE_CACHING = 0x08, //!< Caching mode page }; //! \name SBC-2 Device-Specific Parameter //@{ -#define SCSI_MS_SBC_WP 0x80 //!< Write Protected -#define SCSI_MS_SBC_DPOFUA 0x10 //!< DPO and FUA supported +#define SCSI_MS_SBC_WP 0x80 //!< Write Protected +#define SCSI_MS_SBC_DPOFUA 0x10 //!< DPO and FUA supported //@} /** * \brief SBC-2 Short LBA mode parameter block descriptor */ struct sbc_slba_block_desc { - be32_t nr_blocks; //!< Number of Blocks - be32_t block_len; //!< Block Length -#define SBC_SLBA_BLOCK_LEN_MASK 0x00FFFFFFU //!< Mask reserved bits + be32_t nr_blocks; //!< Number of Blocks + be32_t block_len; //!< Block Length +#define SBC_SLBA_BLOCK_LEN_MASK 0x00FFFFFFU //!< Mask reserved bits }; /** * \brief SBC-2 Caching mode page */ struct sbc_caching_mode_page { - uint8_t page_code; - uint8_t page_length; - uint8_t flags2; -#define SBC_MP_CACHE_IC (1 << 7) //!< Initiator Control -#define SBC_MP_CACHE_ABPF (1 << 6) //!< Abort Pre-Fetch -#define SBC_MP_CACHE_CAP (1 << 5) //!< Catching Analysis Permitted -#define SBC_MP_CACHE_DISC (1 << 4) //!< Discontinuity -#define SBC_MP_CACHE_SIZE (1 << 3) //!< Size enable -#define SBC_MP_CACHE_WCE (1 << 2) //!< Write back Cache Enable -#define SBC_MP_CACHE_MF (1 << 1) //!< Multiplication Factor -#define SBC_MP_CACHE_RCD (1 << 0) //!< Read Cache Disable - uint8_t retention; - be16_t dis_pf_transfer_len; - be16_t min_prefetch; - be16_t max_prefetch; - be16_t max_prefetch_ceil; - uint8_t flags12; -#define SBC_MP_CACHE_FSW (1 << 7) //!< Force Sequential Write -#define SBC_MP_CACHE_LBCSS (1 << 6) //!< Logical Blk Cache Seg Sz -#define SBC_MP_CACHE_DRA (1 << 5) //!< Disable Read-Ahead -#define SBC_MP_CACHE_NV_DIS (1 << 0) //!< Non-Volatile Cache Disable - uint8_t nr_cache_segments; - be16_t cache_segment_size; - uint8_t reserved[4]; + uint8_t page_code; + uint8_t page_length; + uint8_t flags2; +#define SBC_MP_CACHE_IC (1 << 7) //!< Initiator Control +#define SBC_MP_CACHE_ABPF (1 << 6) //!< Abort Pre-Fetch +#define SBC_MP_CACHE_CAP (1 << 5) //!< Catching Analysis Permitted +#define SBC_MP_CACHE_DISC (1 << 4) //!< Discontinuity +#define SBC_MP_CACHE_SIZE (1 << 3) //!< Size enable +#define SBC_MP_CACHE_WCE (1 << 2) //!< Write back Cache Enable +#define SBC_MP_CACHE_MF (1 << 1) //!< Multiplication Factor +#define SBC_MP_CACHE_RCD (1 << 0) //!< Read Cache Disable + uint8_t retention; + be16_t dis_pf_transfer_len; + be16_t min_prefetch; + be16_t max_prefetch; + be16_t max_prefetch_ceil; + uint8_t flags12; +#define SBC_MP_CACHE_FSW (1 << 7) //!< Force Sequential Write +#define SBC_MP_CACHE_LBCSS (1 << 6) //!< Logical Blk Cache Seg Sz +#define SBC_MP_CACHE_DRA (1 << 5) //!< Disable Read-Ahead +#define SBC_MP_CACHE_NV_DIS (1 << 0) //!< Non-Volatile Cache Disable + uint8_t nr_cache_segments; + be16_t cache_segment_size; + uint8_t reserved[4]; }; /** * \brief SBC-2 Read-Write Error Recovery mode page */ struct sbc_rdwr_error_recovery_mode_page { - uint8_t page_code; - uint8_t page_length; -#define SPC_MP_RW_ERR_RECOV_PAGE_LENGTH 0x0A - uint8_t flags1; -#define SBC_MP_RW_ERR_RECOV_AWRE (1 << 7) -#define SBC_MP_RW_ERR_RECOV_ARRE (1 << 6) -#define SBC_MP_RW_ERR_RECOV_TB (1 << 5) -#define SBC_MP_RW_ERR_RECOV_RC (1 << 4) -#define SBC_MP_RW_ERR_RECOV_ERR (1 << 3) -#define SBC_MP_RW_ERR_RECOV_PER (1 << 2) -#define SBC_MP_RW_ERR_RECOV_DTE (1 << 1) -#define SBC_MP_RW_ERR_RECOV_DCR (1 << 0) - uint8_t read_retry_count; - uint8_t correction_span; - uint8_t head_offset_count; - uint8_t data_strobe_offset_count; - uint8_t flags2; - uint8_t write_retry_count; - uint8_t flags3; - be16_t recovery_time_limit; + uint8_t page_code; + uint8_t page_length; + #define SPC_MP_RW_ERR_RECOV_PAGE_LENGTH 0x0A + uint8_t flags1; + #define SBC_MP_RW_ERR_RECOV_AWRE (1 << 7) + #define SBC_MP_RW_ERR_RECOV_ARRE (1 << 6) + #define SBC_MP_RW_ERR_RECOV_TB (1 << 5) + #define SBC_MP_RW_ERR_RECOV_RC (1 << 4) + #define SBC_MP_RW_ERR_RECOV_ERR (1 << 3) + #define SBC_MP_RW_ERR_RECOV_PER (1 << 2) + #define SBC_MP_RW_ERR_RECOV_DTE (1 << 1) + #define SBC_MP_RW_ERR_RECOV_DCR (1 << 0) + uint8_t read_retry_count; + uint8_t correction_span; + uint8_t head_offset_count; + uint8_t data_strobe_offset_count; + uint8_t flags2; + uint8_t write_retry_count; + uint8_t flags3; + be16_t recovery_time_limit; }; //@} @@ -164,8 +163,8 @@ struct sbc_rdwr_error_recovery_mode_page { * \brief SBC-2 READ CAPACITY (10) parameter data */ struct sbc_read_capacity10_data { - be32_t max_lba; //!< LBA of last logical block - be32_t block_len; //!< Number of bytes in the last logical block + be32_t max_lba; //!< LBA of last logical block + be32_t block_len; //!< Number of bytes in the last logical block }; //@} diff --git a/Marlin/src/HAL/DUE/usb/sd_mmc_spi_mem.cpp b/Marlin/src/HAL/DUE/usb/sd_mmc_spi_mem.cpp index 34cc256b30..65a926ff36 100644 --- a/Marlin/src/HAL/DUE/usb/sd_mmc_spi_mem.cpp +++ b/Marlin/src/HAL/DUE/usb/sd_mmc_spi_mem.cpp @@ -6,7 +6,7 @@ #include "../../../inc/MarlinConfig.h" -#if ENABLED(SDSUPPORT) +#if HAS_MEDIA #include "../../../sd/cardreader.h" extern "C" { @@ -138,5 +138,5 @@ Ctrl_status sd_mmc_spi_usb_write_10(uint32_t addr, uint16_t nb_sector) { #endif // ACCESS_USB == true -#endif // SDSUPPORT +#endif // HAS_MEDIA #endif // ARDUINO_ARCH_SAM diff --git a/Marlin/src/HAL/DUE/usb/spc_protocol.h b/Marlin/src/HAL/DUE/usb/spc_protocol.h index d67cc5c788..808c388f4f 100644 --- a/Marlin/src/HAL/DUE/usb/spc_protocol.h +++ b/Marlin/src/HAL/DUE/usb/spc_protocol.h @@ -59,23 +59,23 @@ //! \name SCSI commands defined by SPC-2 //@{ -#define SPC_TEST_UNIT_READY 0x00 -#define SPC_REQUEST_SENSE 0x03 -#define SPC_INQUIRY 0x12 -#define SPC_MODE_SELECT6 0x15 -#define SPC_MODE_SENSE6 0x1A -#define SPC_SEND_DIAGNOSTIC 0x1D -#define SPC_PREVENT_ALLOW_MEDIUM_REMOVAL 0x1E -#define SPC_MODE_SENSE10 0x5A -#define SPC_REPORT_LUNS 0xA0 +#define SPC_TEST_UNIT_READY 0x00 +#define SPC_REQUEST_SENSE 0x03 +#define SPC_INQUIRY 0x12 +#define SPC_MODE_SELECT6 0x15 +#define SPC_MODE_SENSE6 0x1A +#define SPC_SEND_DIAGNOSTIC 0x1D +#define SPC_PREVENT_ALLOW_MEDIUM_REMOVAL 0x1E +#define SPC_MODE_SENSE10 0x5A +#define SPC_REPORT_LUNS 0xA0 //@} //! \brief May be set in byte 0 of the INQUIRY CDB //@{ //! Enable Vital Product Data -#define SCSI_INQ_REQ_EVPD 0x01 +#define SCSI_INQ_REQ_EVPD 0x01 //! Command Support Data specified by the PAGE OR OPERATION CODE field -#define SCSI_INQ_REQ_CMDT 0x02 +#define SCSI_INQ_REQ_CMDT 0x02 //@} COMPILER_PACK_SET(1) @@ -84,110 +84,110 @@ COMPILER_PACK_SET(1) * \brief SCSI Standard Inquiry data structure */ struct scsi_inquiry_data { - uint8_t pq_pdt; //!< Peripheral Qual / Peripheral Dev Type -#define SCSI_INQ_PQ_CONNECTED 0x00 //!< Peripheral connected -#define SCSI_INQ_PQ_NOT_CONN 0x20 //!< Peripheral not connected -#define SCSI_INQ_PQ_NOT_SUPP 0x60 //!< Peripheral not supported -#define SCSI_INQ_DT_DIR_ACCESS 0x00 //!< Direct Access (SBC) -#define SCSI_INQ_DT_SEQ_ACCESS 0x01 //!< Sequential Access -#define SCSI_INQ_DT_PRINTER 0x02 //!< Printer -#define SCSI_INQ_DT_PROCESSOR 0x03 //!< Processor device -#define SCSI_INQ_DT_WRITE_ONCE 0x04 //!< Write-once device -#define SCSI_INQ_DT_CD_DVD 0x05 //!< CD/DVD device -#define SCSI_INQ_DT_OPTICAL 0x07 //!< Optical Memory -#define SCSI_INQ_DT_MC 0x08 //!< Medium Changer -#define SCSI_INQ_DT_ARRAY 0x0C //!< Storage Array Controller -#define SCSI_INQ_DT_ENCLOSURE 0x0D //!< Enclosure Services -#define SCSI_INQ_DT_RBC 0x0E //!< Simplified Direct Access -#define SCSI_INQ_DT_OCRW 0x0F //!< Optical card reader/writer -#define SCSI_INQ_DT_BCC 0x10 //!< Bridge Controller Commands -#define SCSI_INQ_DT_OSD 0x11 //!< Object-based Storage -#define SCSI_INQ_DT_NONE 0x1F //!< No Peripheral - uint8_t flags1; //!< Flags (byte 1) -#define SCSI_INQ_RMB 0x80 //!< Removable Medium - uint8_t version; //!< Version -#define SCSI_INQ_VER_NONE 0x00 //!< No standards conformance -#define SCSI_INQ_VER_SPC 0x03 //!< SCSI Primary Commands (link to SBC) -#define SCSI_INQ_VER_SPC2 0x04 //!< SCSI Primary Commands - 2 (link to SBC-2) -#define SCSI_INQ_VER_SPC3 0x05 //!< SCSI Primary Commands - 3 (link to SBC-2) -#define SCSI_INQ_VER_SPC4 0x06 //!< SCSI Primary Commands - 4 (link to SBC-3) - uint8_t flags3; //!< Flags (byte 3) -#define SCSI_INQ_NORMACA 0x20 //!< Normal ACA Supported -#define SCSI_INQ_HISUP 0x10 //!< Hierarchal LUN addressing -#define SCSI_INQ_RSP_SPC2 0x02 //!< SPC-2 / SPC-3 response format - uint8_t addl_len; //!< Additional Length (n-4) -#define SCSI_INQ_ADDL_LEN(tot) ((tot)-5) //!< Total length is \a tot - uint8_t flags5; //!< Flags (byte 5) -#define SCSI_INQ_SCCS 0x80 - uint8_t flags6; //!< Flags (byte 6) -#define SCSI_INQ_BQUE 0x80 -#define SCSI_INQ_ENCSERV 0x40 -#define SCSI_INQ_MULTIP 0x10 -#define SCSI_INQ_MCHGR 0x08 -#define SCSI_INQ_ADDR16 0x01 - uint8_t flags7; //!< Flags (byte 7) -#define SCSI_INQ_WBUS16 0x20 -#define SCSI_INQ_SYNC 0x10 -#define SCSI_INQ_LINKED 0x08 -#define SCSI_INQ_CMDQUE 0x02 - uint8_t vendor_id[8]; //!< T10 Vendor Identification - uint8_t product_id[16]; //!< Product Identification - uint8_t product_rev[4]; //!< Product Revision Level + uint8_t pq_pdt; //!< Peripheral Qual / Peripheral Dev Type + #define SCSI_INQ_PQ_CONNECTED 0x00 //!< Peripheral connected + #define SCSI_INQ_PQ_NOT_CONN 0x20 //!< Peripheral not connected + #define SCSI_INQ_PQ_NOT_SUPP 0x60 //!< Peripheral not supported + #define SCSI_INQ_DT_DIR_ACCESS 0x00 //!< Direct Access (SBC) + #define SCSI_INQ_DT_SEQ_ACCESS 0x01 //!< Sequential Access + #define SCSI_INQ_DT_PRINTER 0x02 //!< Printer + #define SCSI_INQ_DT_PROCESSOR 0x03 //!< Processor device + #define SCSI_INQ_DT_WRITE_ONCE 0x04 //!< Write-once device + #define SCSI_INQ_DT_CD_DVD 0x05 //!< CD/DVD device + #define SCSI_INQ_DT_OPTICAL 0x07 //!< Optical Memory + #define SCSI_INQ_DT_MC 0x08 //!< Medium Changer + #define SCSI_INQ_DT_ARRAY 0x0C //!< Storage Array Controller + #define SCSI_INQ_DT_ENCLOSURE 0x0D //!< Enclosure Services + #define SCSI_INQ_DT_RBC 0x0E //!< Simplified Direct Access + #define SCSI_INQ_DT_OCRW 0x0F //!< Optical card reader/writer + #define SCSI_INQ_DT_BCC 0x10 //!< Bridge Controller Commands + #define SCSI_INQ_DT_OSD 0x11 //!< Object-based Storage + #define SCSI_INQ_DT_NONE 0x1F //!< No Peripheral + uint8_t flags1; //!< Flags (byte 1) + #define SCSI_INQ_RMB 0x80 //!< Removable Medium + uint8_t version; //!< Version + #define SCSI_INQ_VER_NONE 0x00 //!< No standards conformance + #define SCSI_INQ_VER_SPC 0x03 //!< SCSI Primary Commands (link to SBC) + #define SCSI_INQ_VER_SPC2 0x04 //!< SCSI Primary Commands - 2 (link to SBC-2) + #define SCSI_INQ_VER_SPC3 0x05 //!< SCSI Primary Commands - 3 (link to SBC-2) + #define SCSI_INQ_VER_SPC4 0x06 //!< SCSI Primary Commands - 4 (link to SBC-3) + uint8_t flags3; //!< Flags (byte 3) + #define SCSI_INQ_NORMACA 0x20 //!< Normal ACA Supported + #define SCSI_INQ_HISUP 0x10 //!< Hierarchal LUN addressing + #define SCSI_INQ_RSP_SPC2 0x02 //!< SPC-2 / SPC-3 response format + uint8_t addl_len; //!< Additional Length (n-4) + #define SCSI_INQ_ADDL_LEN(tot) ((tot)-5) //!< Total length is \a tot + uint8_t flags5; //!< Flags (byte 5) + #define SCSI_INQ_SCCS 0x80 + uint8_t flags6; //!< Flags (byte 6) + #define SCSI_INQ_BQUE 0x80 + #define SCSI_INQ_ENCSERV 0x40 + #define SCSI_INQ_MULTIP 0x10 + #define SCSI_INQ_MCHGR 0x08 + #define SCSI_INQ_ADDR16 0x01 + uint8_t flags7; //!< Flags (byte 7) + #define SCSI_INQ_WBUS16 0x20 + #define SCSI_INQ_SYNC 0x10 + #define SCSI_INQ_LINKED 0x08 + #define SCSI_INQ_CMDQUE 0x02 + uint8_t vendor_id[8]; //!< T10 Vendor Identification + uint8_t product_id[16]; //!< Product Identification + uint8_t product_rev[4]; //!< Product Revision Level }; /** * \brief SCSI Standard Request sense data structure */ struct scsi_request_sense_data { - /* 1st byte: REQUEST SENSE response flags*/ - uint8_t valid_reponse_code; -#define SCSI_SENSE_VALID 0x80 //!< Indicates the INFORMATION field contains valid information -#define SCSI_SENSE_RESPONSE_CODE_MASK 0x7F -#define SCSI_SENSE_CURRENT 0x70 //!< Response code 70h (current errors) -#define SCSI_SENSE_DEFERRED 0x71 + /* 1st byte: REQUEST SENSE response flags*/ + uint8_t valid_reponse_code; + #define SCSI_SENSE_VALID 0x80 //!< Indicates the INFORMATION field contains valid information + #define SCSI_SENSE_RESPONSE_CODE_MASK 0x7F + #define SCSI_SENSE_CURRENT 0x70 //!< Response code 70h (current errors) + #define SCSI_SENSE_DEFERRED 0x71 - /* 2nd byte */ - uint8_t obsolete; + /* 2nd byte */ + uint8_t obsolete; - /* 3rd byte */ - uint8_t sense_flag_key; -#define SCSI_SENSE_FILEMARK 0x80 //!< Indicates that the current command has read a filemark or setmark. -#define SCSI_SENSE_EOM 0x40 //!< Indicates that an end-of-medium condition exists. -#define SCSI_SENSE_ILI 0x20 //!< Indicates that the requested logical block length did not match the logical block length of the data on the medium. -#define SCSI_SENSE_RESERVED 0x10 //!< Reserved -#define SCSI_SENSE_KEY(x) (x&0x0F) //!< Sense Key + /* 3rd byte */ + uint8_t sense_flag_key; + #define SCSI_SENSE_FILEMARK 0x80 //!< Indicates that the current command has read a filemark or setmark. + #define SCSI_SENSE_EOM 0x40 //!< Indicates that an end-of-medium condition exists. + #define SCSI_SENSE_ILI 0x20 //!< Indicates that the requested logical block length did not match the logical block length of the data on the medium. + #define SCSI_SENSE_RESERVED 0x10 //!< Reserved + #define SCSI_SENSE_KEY(x) (x&0x0F) //!< Sense Key - /* 4th to 7th bytes - INFORMATION field */ - uint8_t information[4]; + /* 4th to 7th bytes - INFORMATION field */ + uint8_t information[4]; - /* 8th byte - ADDITIONAL SENSE LENGTH field */ - uint8_t AddSenseLen; -#define SCSI_SENSE_ADDL_LEN(total_len) ((total_len) - 8) + /* 8th byte - ADDITIONAL SENSE LENGTH field */ + uint8_t AddSenseLen; + #define SCSI_SENSE_ADDL_LEN(total_len) ((total_len) - 8) - /* 9th to 12th byte - COMMAND-SPECIFIC INFORMATION field */ - uint8_t CmdSpecINFO[4]; + /* 9th to 12th byte - COMMAND-SPECIFIC INFORMATION field */ + uint8_t CmdSpecINFO[4]; - /* 13th byte - ADDITIONAL SENSE CODE field */ - uint8_t AddSenseCode; + /* 13th byte - ADDITIONAL SENSE CODE field */ + uint8_t AddSenseCode; - /* 14th byte - ADDITIONAL SENSE CODE QUALIFIER field */ - uint8_t AddSnsCodeQlfr; + /* 14th byte - ADDITIONAL SENSE CODE QUALIFIER field */ + uint8_t AddSnsCodeQlfr; - /* 15th byte - FIELD REPLACEABLE UNIT CODE field */ - uint8_t FldReplUnitCode; + /* 15th byte - FIELD REPLACEABLE UNIT CODE field */ + uint8_t FldReplUnitCode; - /* 16th byte */ - uint8_t SenseKeySpec[3]; -#define SCSI_SENSE_SKSV 0x80 //!< Indicates the SENSE-KEY SPECIFIC field contains valid information + /* 16th byte */ + uint8_t SenseKeySpec[3]; + #define SCSI_SENSE_SKSV 0x80 //!< Indicates the SENSE-KEY SPECIFIC field contains valid information }; COMPILER_PACK_RESET() /* Vital Product Data page codes */ enum scsi_vpd_page_code { - SCSI_VPD_SUPPORTED_PAGES = 0x00, - SCSI_VPD_UNIT_SERIAL_NUMBER = 0x80, - SCSI_VPD_DEVICE_IDENTIFICATION = 0x83, + SCSI_VPD_SUPPORTED_PAGES = 0x00, + SCSI_VPD_UNIT_SERIAL_NUMBER = 0x80, + SCSI_VPD_DEVICE_IDENTIFICATION = 0x83, }; #define SCSI_VPD_HEADER_SIZE 4 @@ -200,37 +200,36 @@ enum scsi_vpd_page_code { #define SCSI_VPD_ID_TYPE_T10 1 - /* Sense keys */ enum scsi_sense_key { - SCSI_SK_NO_SENSE = 0x0, - SCSI_SK_RECOVERED_ERROR = 0x1, - SCSI_SK_NOT_READY = 0x2, - SCSI_SK_MEDIUM_ERROR = 0x3, - SCSI_SK_HARDWARE_ERROR = 0x4, - SCSI_SK_ILLEGAL_REQUEST = 0x5, - SCSI_SK_UNIT_ATTENTION = 0x6, - SCSI_SK_DATA_PROTECT = 0x7, - SCSI_SK_BLANK_CHECK = 0x8, - SCSI_SK_VENDOR_SPECIFIC = 0x9, - SCSI_SK_COPY_ABORTED = 0xA, - SCSI_SK_ABORTED_COMMAND = 0xB, - SCSI_SK_VOLUME_OVERFLOW = 0xD, - SCSI_SK_MISCOMPARE = 0xE, + SCSI_SK_NO_SENSE = 0x0, + SCSI_SK_RECOVERED_ERROR = 0x1, + SCSI_SK_NOT_READY = 0x2, + SCSI_SK_MEDIUM_ERROR = 0x3, + SCSI_SK_HARDWARE_ERROR = 0x4, + SCSI_SK_ILLEGAL_REQUEST = 0x5, + SCSI_SK_UNIT_ATTENTION = 0x6, + SCSI_SK_DATA_PROTECT = 0x7, + SCSI_SK_BLANK_CHECK = 0x8, + SCSI_SK_VENDOR_SPECIFIC = 0x9, + SCSI_SK_COPY_ABORTED = 0xA, + SCSI_SK_ABORTED_COMMAND = 0xB, + SCSI_SK_VOLUME_OVERFLOW = 0xD, + SCSI_SK_MISCOMPARE = 0xE, }; /* Additional Sense Code / Additional Sense Code Qualifier pairs */ enum scsi_asc_ascq { - SCSI_ASC_NO_ADDITIONAL_SENSE_INFO = 0x0000, - SCSI_ASC_LU_NOT_READY_REBUILD_IN_PROGRESS = 0x0405, - SCSI_ASC_WRITE_ERROR = 0x0C00, - SCSI_ASC_UNRECOVERED_READ_ERROR = 0x1100, - SCSI_ASC_INVALID_COMMAND_OPERATION_CODE = 0x2000, - SCSI_ASC_INVALID_FIELD_IN_CDB = 0x2400, - SCSI_ASC_WRITE_PROTECTED = 0x2700, - SCSI_ASC_NOT_READY_TO_READY_CHANGE = 0x2800, - SCSI_ASC_MEDIUM_NOT_PRESENT = 0x3A00, - SCSI_ASC_INTERNAL_TARGET_FAILURE = 0x4400, + SCSI_ASC_NO_ADDITIONAL_SENSE_INFO = 0x0000, + SCSI_ASC_LU_NOT_READY_REBUILD_IN_PROGRESS = 0x0405, + SCSI_ASC_WRITE_ERROR = 0x0C00, + SCSI_ASC_UNRECOVERED_READ_ERROR = 0x1100, + SCSI_ASC_INVALID_COMMAND_OPERATION_CODE = 0x2000, + SCSI_ASC_INVALID_FIELD_IN_CDB = 0x2400, + SCSI_ASC_WRITE_PROTECTED = 0x2700, + SCSI_ASC_NOT_READY_TO_READY_CHANGE = 0x2800, + SCSI_ASC_MEDIUM_NOT_PRESENT = 0x3A00, + SCSI_ASC_INTERNAL_TARGET_FAILURE = 0x4400, }; /** @@ -240,9 +239,9 @@ enum scsi_asc_ascq { * that are applicable to all SCSI devices. */ enum scsi_spc_mode { - SCSI_MS_MODE_VENDOR_SPEC = 0x00, - SCSI_MS_MODE_INFEXP = 0x1C, // Informational exceptions control page - SCSI_MS_MODE_ALL = 0x3F, + SCSI_MS_MODE_VENDOR_SPEC = 0x00, + SCSI_MS_MODE_INFEXP = 0x1C, // Informational exceptions control page + SCSI_MS_MODE_ALL = 0x3F, }; /** @@ -250,51 +249,45 @@ enum scsi_spc_mode { * See chapter 8.3.8 */ struct spc_control_page_info_execpt { - uint8_t page_code; - uint8_t page_length; -#define SPC_MP_INFEXP_PAGE_LENGTH 0x0A - uint8_t flags1; -#define SPC_MP_INFEXP_PERF (1<<7) //!< Initiator Control -#define SPC_MP_INFEXP_EBF (1<<5) //!< Caching Analysis Permitted -#define SPC_MP_INFEXP_EWASC (1<<4) //!< Discontinuity -#define SPC_MP_INFEXP_DEXCPT (1<<3) //!< Size enable -#define SPC_MP_INFEXP_TEST (1<<2) //!< Writeback Cache Enable -#define SPC_MP_INFEXP_LOGERR (1<<0) //!< Log errors bit - uint8_t mrie; -#define SPC_MP_INFEXP_MRIE_NO_REPORT 0x00 -#define SPC_MP_INFEXP_MRIE_ASYNC_EVENT 0x01 -#define SPC_MP_INFEXP_MRIE_GEN_UNIT 0x02 -#define SPC_MP_INFEXP_MRIE_COND_RECOV_ERROR 0x03 -#define SPC_MP_INFEXP_MRIE_UNCOND_RECOV_ERROR 0x04 -#define SPC_MP_INFEXP_MRIE_NO_SENSE 0x05 -#define SPC_MP_INFEXP_MRIE_ONLY_REPORT 0x06 - be32_t interval_timer; - be32_t report_count; + uint8_t page_code; + uint8_t page_length; + #define SPC_MP_INFEXP_PAGE_LENGTH 0x0A + uint8_t flags1; + #define SPC_MP_INFEXP_PERF (1<<7) //!< Initiator Control + #define SPC_MP_INFEXP_EBF (1<<5) //!< Caching Analysis Permitted + #define SPC_MP_INFEXP_EWASC (1<<4) //!< Discontinuity + #define SPC_MP_INFEXP_DEXCPT (1<<3) //!< Size enable + #define SPC_MP_INFEXP_TEST (1<<2) //!< Writeback Cache Enable + #define SPC_MP_INFEXP_LOGERR (1<<0) //!< Log errors bit + uint8_t mrie; + #define SPC_MP_INFEXP_MRIE_NO_REPORT 0x00 + #define SPC_MP_INFEXP_MRIE_ASYNC_EVENT 0x01 + #define SPC_MP_INFEXP_MRIE_GEN_UNIT 0x02 + #define SPC_MP_INFEXP_MRIE_COND_RECOV_ERROR 0x03 + #define SPC_MP_INFEXP_MRIE_UNCOND_RECOV_ERROR 0x04 + #define SPC_MP_INFEXP_MRIE_NO_SENSE 0x05 + #define SPC_MP_INFEXP_MRIE_ONLY_REPORT 0x06 + be32_t interval_timer; + be32_t report_count; }; - enum scsi_spc_mode_sense_pc { - SCSI_MS_SENSE_PC_CURRENT = 0, - SCSI_MS_SENSE_PC_CHANGEABLE = 1, - SCSI_MS_SENSE_PC_DEFAULT = 2, - SCSI_MS_SENSE_PC_SAVED = 3, + SCSI_MS_SENSE_PC_CURRENT = 0, + SCSI_MS_SENSE_PC_CHANGEABLE = 1, + SCSI_MS_SENSE_PC_DEFAULT = 2, + SCSI_MS_SENSE_PC_SAVED = 3, }; - - -static inline bool scsi_mode_sense_dbd_is_set(const uint8_t * cdb) -{ - return (cdb[1] >> 3) & 1; +static inline bool scsi_mode_sense_dbd_is_set(const uint8_t * cdb) { + return (cdb[1] >> 3) & 1; } -static inline uint8_t scsi_mode_sense_get_page_code(const uint8_t * cdb) -{ - return cdb[2] & 0x3F; +static inline uint8_t scsi_mode_sense_get_page_code(const uint8_t * cdb) { + return cdb[2] & 0x3F; } -static inline uint8_t scsi_mode_sense_get_pc(const uint8_t * cdb) -{ - return cdb[2] >> 6; +static inline uint8_t scsi_mode_sense_get_pc(const uint8_t * cdb) { + return cdb[2] >> 6; } /** @@ -302,10 +295,10 @@ static inline uint8_t scsi_mode_sense_get_pc(const uint8_t * cdb) * SENSE(6) */ struct scsi_mode_param_header6 { - uint8_t mode_data_length; //!< Number of bytes after this - uint8_t medium_type; //!< Medium Type - uint8_t device_specific_parameter; //!< Defined by command set - uint8_t block_descriptor_length; //!< Length of block descriptors + uint8_t mode_data_length; //!< Number of bytes after this + uint8_t medium_type; //!< Medium Type + uint8_t device_specific_parameter; //!< Defined by command set + uint8_t block_descriptor_length; //!< Length of block descriptors }; /** @@ -313,23 +306,23 @@ struct scsi_mode_param_header6 { * SENSE(10) */ struct scsi_mode_param_header10 { - be16_t mode_data_length; //!< Number of bytes after this - uint8_t medium_type; //!< Medium Type - uint8_t device_specific_parameter; //!< Defined by command set - uint8_t flags4; //!< LONGLBA in bit 0 - uint8_t reserved; - be16_t block_descriptor_length; //!< Length of block descriptors + be16_t mode_data_length; //!< Number of bytes after this + uint8_t medium_type; //!< Medium Type + uint8_t device_specific_parameter; //!< Defined by command set + uint8_t flags4; //!< LONGLBA in bit 0 + uint8_t reserved; + be16_t block_descriptor_length; //!< Length of block descriptors }; /** * \brief SCSI Page_0 Mode Page header (SPF not set) */ struct scsi_mode_page_0_header { - uint8_t page_code; -#define SCSI_PAGE_CODE_PS (1 << 7) //!< Parameters Saveable -#define SCSI_PAGE_CODE_SPF (1 << 6) //!< SubPage Format - uint8_t page_length; //!< Number of bytes after this -#define SCSI_MS_PAGE_LEN(total) ((total) - 2) + uint8_t page_code; +#define SCSI_PAGE_CODE_PS (1 << 7) //!< Parameters Saveable +#define SCSI_PAGE_CODE_SPF (1 << 6) //!< SubPage Format + uint8_t page_length; //!< Number of bytes after this +#define SCSI_MS_PAGE_LEN(total) ((total) - 2) }; //@} diff --git a/Marlin/src/HAL/DUE/usb/sysclk.h b/Marlin/src/HAL/DUE/usb/sysclk.h index 16db8c86d3..0623378615 100644 --- a/Marlin/src/HAL/DUE/usb/sysclk.h +++ b/Marlin/src/HAL/DUE/usb/sysclk.h @@ -71,7 +71,7 @@ * \subsection sysclk_quickstart_use_case_1_setup_steps Initialization code * Add to the application initialization code: * \code - sysclk_init(); + sysclk_init(); \endcode * * \subsection sysclk_quickstart_use_case_1_setup_steps_workflow Workflow @@ -82,15 +82,15 @@ * Add or uncomment the following in your conf_clock.h header file, commenting out all other * definitions of the same symbol(s): * \code - #define CONFIG_SYSCLK_SOURCE SYSCLK_SRC_PLLACK + #define CONFIG_SYSCLK_SOURCE SYSCLK_SRC_PLLACK - // Fpll0 = (Fclk * PLL_mul) / PLL_div - #define CONFIG_PLL0_SOURCE PLL_SRC_MAINCK_XTAL - #define CONFIG_PLL0_MUL (84000000UL / BOARD_FREQ_MAINCK_XTAL) - #define CONFIG_PLL0_DIV 1 + // Fpll0 = (Fclk * PLL_mul) / PLL_div + #define CONFIG_PLL0_SOURCE PLL_SRC_MAINCK_XTAL + #define CONFIG_PLL0_MUL (84000000UL / BOARD_FREQ_MAINCK_XTAL) + #define CONFIG_PLL0_DIV 1 - // Fbus = Fsys / BUS_div - #define CONFIG_SYSCLK_PRES SYSCLK_PRES_1 + // Fbus = Fsys / BUS_div + #define CONFIG_SYSCLK_PRES SYSCLK_PRES_1 \endcode * * \subsection sysclk_quickstart_use_case_1_example_workflow Workflow @@ -100,14 +100,14 @@ * \code #define CONFIG_PLL0_SOURCE PLL_SRC_MAINCK_XTAL \endcode * -# Configure the PLL module to multiply the external fast crystal oscillator frequency up to 84MHz: * \code - #define CONFIG_PLL0_MUL (84000000UL / BOARD_FREQ_MAINCK_XTAL) - #define CONFIG_PLL0_DIV 1 + #define CONFIG_PLL0_MUL (84000000UL / BOARD_FREQ_MAINCK_XTAL) + #define CONFIG_PLL0_DIV 1 \endcode * \note For user boards, \c BOARD_FREQ_MAINCK_XTAL should be defined in the board \c conf_board.h configuration * file as the frequency of the fast crystal attached to the microcontroller. * -# Configure the main clock to run at the full 84MHz, disable scaling of the main system clock speed: * \code - #define CONFIG_SYSCLK_PRES SYSCLK_PRES_1 + #define CONFIG_SYSCLK_PRES SYSCLK_PRES_1 \endcode * \note Some dividers are powers of two, while others are integer division factors. Refer to the * formulas in the conf_clock.h template commented above each division define. @@ -136,7 +136,7 @@ extern "C" { * initialization. */ #ifndef CONFIG_SYSCLK_SOURCE -# define CONFIG_SYSCLK_SOURCE SYSCLK_SRC_MAINCK_4M_RC + #define CONFIG_SYSCLK_SOURCE SYSCLK_SRC_MAINCK_4M_RC #endif /** * \def CONFIG_SYSCLK_PRES @@ -149,7 +149,7 @@ extern "C" { * after initialization. */ #ifndef CONFIG_SYSCLK_PRES -# define CONFIG_SYSCLK_PRES 0 + #define CONFIG_SYSCLK_PRES 0 #endif //@} @@ -197,7 +197,7 @@ extern "C" { * USB is not required. */ #ifdef __DOXYGEN__ -# define CONFIG_USBCLK_SOURCE + #define CONFIG_USBCLK_SOURCE #endif /** @@ -209,7 +209,7 @@ extern "C" { * defined. */ #ifdef __DOXYGEN__ -# define CONFIG_USBCLK_DIV + #define CONFIG_USBCLK_DIV #endif diff --git a/Marlin/src/HAL/DUE/usb/udc.h b/Marlin/src/HAL/DUE/usb/udc.h index 8d92eb5c03..6230a81b35 100644 --- a/Marlin/src/HAL/DUE/usb/udc.h +++ b/Marlin/src/HAL/DUE/usb/udc.h @@ -144,15 +144,15 @@ extern "C" { * \code #define USB_DEVICE_ATTACH_AUTO_DISABLE \endcode * User C file contains: * \code - // Authorize VBUS monitoring - if (!udc_include_vbus_monitoring()) { - // Implement custom VBUS monitoring via GPIO or other - } - Event_VBUS_present() // VBUS interrupt or GPIO interrupt or other - { - // Attach USB Device - udc_attach(); - } + // Authorize VBUS monitoring + if (!udc_include_vbus_monitoring()) { + // Implement custom VBUS monitoring via GPIO or other + } + Event_VBUS_present() // VBUS interrupt or GPIO interrupt or other + { + // Attach USB Device + udc_attach(); + } \endcode * * - Case of battery charging. conf_usb.h file contains define @@ -160,21 +160,20 @@ extern "C" { * \code #define USB_DEVICE_ATTACH_AUTO_DISABLE \endcode * User C file contains: * \code - Event VBUS present() // VBUS interrupt or GPIO interrupt or .. - { - // Authorize battery charging, but wait key press to start USB. - } - Event Key press() - { - // Stop batteries charging - // Start USB - udc_attach(); - } + Event VBUS present() // VBUS interrupt or GPIO interrupt or .. + { + // Authorize battery charging, but wait key press to start USB. + } + Event Key press() + { + // Stop batteries charging + // Start USB + udc_attach(); + } \endcode */ -static inline bool udc_include_vbus_monitoring(void) -{ - return udd_include_vbus_monitoring(); +static inline bool udc_include_vbus_monitoring(void) { + return udd_include_vbus_monitoring(); } /*! \brief Start the USB Device stack @@ -192,32 +191,26 @@ void udc_stop(void); * then it will attach device when an acceptable Vbus * level from the host is detected. */ -static inline void udc_attach(void) -{ - udd_attach(); +static inline void udc_attach(void) { + udd_attach(); } - /** * \brief Detaches the device from the bus * * The driver must remove pull-up on USB line D- or D+. */ -static inline void udc_detach(void) -{ - udd_detach(); +static inline void udc_detach(void) { + udd_detach(); } - /*! \brief The USB driver sends a resume signal called \e "Upstream Resume" * This is authorized only when the remote wakeup feature is enabled by host. */ -static inline void udc_remotewakeup(void) -{ - udd_send_remotewakeup(); +static inline void udc_remotewakeup(void) { + udd_send_remotewakeup(); } - /** * \brief Returns a pointer on the current interface descriptor * @@ -296,23 +289,23 @@ usb_iface_desc_t UDC_DESC_STORAGE *udc_get_interface_desc(void); * * for AVR and SAM3/4 devices, add to the initialization code: * \code - sysclk_init(); - irq_initialize_vectors(); - cpu_irq_enable(); - board_init(); - sleepmgr_init(); // Optional + sysclk_init(); + irq_initialize_vectors(); + cpu_irq_enable(); + board_init(); + sleepmgr_init(); // Optional \endcode * * For SAMD devices, add to the initialization code: * \code - system_init(); - irq_initialize_vectors(); - cpu_irq_enable(); - sleepmgr_init(); // Optional + system_init(); + irq_initialize_vectors(); + cpu_irq_enable(); + sleepmgr_init(); // Optional \endcode * Add to the main IDLE loop: * \code - sleepmgr_enter_sleep(); // Optional + sleepmgr_enter_sleep(); // Optional \endcode * */ @@ -324,20 +317,20 @@ usb_iface_desc_t UDC_DESC_STORAGE *udc_get_interface_desc(void); * * Content of conf_usb.h: * \code - #define USB_DEVICE_VENDOR_ID 0x03EB - #define USB_DEVICE_PRODUCT_ID 0xXXXX - #define USB_DEVICE_MAJOR_VERSION 1 - #define USB_DEVICE_MINOR_VERSION 0 - #define USB_DEVICE_POWER 100 - #define USB_DEVICE_ATTR USB_CONFIG_ATTR_BUS_POWERED + #define USB_DEVICE_VENDOR_ID 0x03EB + #define USB_DEVICE_PRODUCT_ID 0xXXXX + #define USB_DEVICE_MAJOR_VERSION 1 + #define USB_DEVICE_MINOR_VERSION 0 + #define USB_DEVICE_POWER 100 + #define USB_DEVICE_ATTR USB_CONFIG_ATTR_BUS_POWERED \endcode * * Add to application C-file: * \code - void usb_init(void) - { - udc_start(); - } + void usb_init(void) + { + udc_start(); + } \endcode */ @@ -349,17 +342,17 @@ usb_iface_desc_t UDC_DESC_STORAGE *udc_get_interface_desc(void); * -# Ensure that conf_usb.h is available and contains the following configuration * which is the main USB device configuration: * - \code // Vendor ID provided by USB org (ATMEL 0x03EB) - #define USB_DEVICE_VENDOR_ID 0x03EB // Type Word - // Product ID (Atmel PID referenced in usb_atmel.h) - #define USB_DEVICE_PRODUCT_ID 0xXXXX // Type Word - // Major version of the device - #define USB_DEVICE_MAJOR_VERSION 1 // Type Byte - // Minor version of the device - #define USB_DEVICE_MINOR_VERSION 0 // Type Byte - // Maximum device power (mA) - #define USB_DEVICE_POWER 100 // Type 9-bits - // USB attributes to enable features - #define USB_DEVICE_ATTR USB_CONFIG_ATTR_BUS_POWERED // Flags \endcode + #define USB_DEVICE_VENDOR_ID 0x03EB // Type Word + // Product ID (Atmel PID referenced in usb_atmel.h) + #define USB_DEVICE_PRODUCT_ID 0xXXXX // Type Word + // Major version of the device + #define USB_DEVICE_MAJOR_VERSION 1 // Type Byte + // Minor version of the device + #define USB_DEVICE_MINOR_VERSION 0 // Type Byte + // Maximum device power (mA) + #define USB_DEVICE_POWER 100 // Type 9-bits + // USB attributes to enable features + #define USB_DEVICE_ATTR USB_CONFIG_ATTR_BUS_POWERED // Flags \endcode * -# Call the USB device stack start function to enable stack and start USB: * - \code udc_start(); \endcode * \note In case of USB dual roles (Device and Host) managed through USB OTG connector @@ -372,90 +365,90 @@ usb_iface_desc_t UDC_DESC_STORAGE *udc_get_interface_desc(void); * * Content of XMEGA conf_clock.h: * \code - // Configuration based on internal RC: - // USB clock need of 48Mhz - #define CONFIG_USBCLK_SOURCE USBCLK_SRC_RCOSC - #define CONFIG_OSC_RC32_CAL 48000000UL - #define CONFIG_OSC_AUTOCAL_RC32MHZ_REF_OSC OSC_ID_USBSOF - // CPU clock need of clock > 12MHz to run with USB (Here 24MHz) - #define CONFIG_SYSCLK_SOURCE SYSCLK_SRC_RC32MHZ - #define CONFIG_SYSCLK_PSADIV SYSCLK_PSADIV_2 - #define CONFIG_SYSCLK_PSBCDIV SYSCLK_PSBCDIV_1_1 + // Configuration based on internal RC: + // USB clock need of 48Mhz + #define CONFIG_USBCLK_SOURCE USBCLK_SRC_RCOSC + #define CONFIG_OSC_RC32_CAL 48000000UL + #define CONFIG_OSC_AUTOCAL_RC32MHZ_REF_OSC OSC_ID_USBSOF + // CPU clock need of clock > 12MHz to run with USB (Here 24MHz) + #define CONFIG_SYSCLK_SOURCE SYSCLK_SRC_RC32MHZ + #define CONFIG_SYSCLK_PSADIV SYSCLK_PSADIV_2 + #define CONFIG_SYSCLK_PSBCDIV SYSCLK_PSBCDIV_1_1 \endcode * * Content of conf_clock.h for AT32UC3A0, AT32UC3A1, AT32UC3B devices (USBB): * \code - // Configuration based on 12MHz external OSC: - #define CONFIG_PLL1_SOURCE PLL_SRC_OSC0 - #define CONFIG_PLL1_MUL 8 - #define CONFIG_PLL1_DIV 2 - #define CONFIG_USBCLK_SOURCE USBCLK_SRC_PLL1 - #define CONFIG_USBCLK_DIV 1 // Fusb = Fsys/(2 ^ USB_div) + // Configuration based on 12MHz external OSC: + #define CONFIG_PLL1_SOURCE PLL_SRC_OSC0 + #define CONFIG_PLL1_MUL 8 + #define CONFIG_PLL1_DIV 2 + #define CONFIG_USBCLK_SOURCE USBCLK_SRC_PLL1 + #define CONFIG_USBCLK_DIV 1 // Fusb = Fsys/(2 ^ USB_div) \endcode * * Content of conf_clock.h for AT32UC3A3, AT32UC3A4 devices (USBB with high speed support): * \code - // Configuration based on 12MHz external OSC: - #define CONFIG_USBCLK_SOURCE USBCLK_SRC_OSC0 - #define CONFIG_USBCLK_DIV 1 // Fusb = Fsys/(2 ^ USB_div) + // Configuration based on 12MHz external OSC: + #define CONFIG_USBCLK_SOURCE USBCLK_SRC_OSC0 + #define CONFIG_USBCLK_DIV 1 // Fusb = Fsys/(2 ^ USB_div) \endcode * * Content of conf_clock.h for AT32UC3C, ATUCXXD, ATUCXXL3U, ATUCXXL4U devices (USBC): * \code - // Configuration based on 12MHz external OSC: - #define CONFIG_PLL1_SOURCE PLL_SRC_OSC0 - #define CONFIG_PLL1_MUL 8 - #define CONFIG_PLL1_DIV 2 - #define CONFIG_USBCLK_SOURCE USBCLK_SRC_PLL1 - #define CONFIG_USBCLK_DIV 1 // Fusb = Fsys/(2 ^ USB_div) - // CPU clock need of clock > 25MHz to run with USBC - #define CONFIG_SYSCLK_SOURCE SYSCLK_SRC_PLL1 + // Configuration based on 12MHz external OSC: + #define CONFIG_PLL1_SOURCE PLL_SRC_OSC0 + #define CONFIG_PLL1_MUL 8 + #define CONFIG_PLL1_DIV 2 + #define CONFIG_USBCLK_SOURCE USBCLK_SRC_PLL1 + #define CONFIG_USBCLK_DIV 1 // Fusb = Fsys/(2 ^ USB_div) + // CPU clock need of clock > 25MHz to run with USBC + #define CONFIG_SYSCLK_SOURCE SYSCLK_SRC_PLL1 \endcode * * Content of conf_clock.h for SAM3S, SAM3SD, SAM4S devices (UPD: USB Peripheral Device): * \code - // PLL1 (B) Options (Fpll = (Fclk * PLL_mul) / PLL_div) - #define CONFIG_PLL1_SOURCE PLL_SRC_MAINCK_XTAL - #define CONFIG_PLL1_MUL 16 - #define CONFIG_PLL1_DIV 2 - // USB Clock Source Options (Fusb = FpllX / USB_div) - #define CONFIG_USBCLK_SOURCE USBCLK_SRC_PLL1 - #define CONFIG_USBCLK_DIV 2 + // PLL1 (B) Options (Fpll = (Fclk * PLL_mul) / PLL_div) + #define CONFIG_PLL1_SOURCE PLL_SRC_MAINCK_XTAL + #define CONFIG_PLL1_MUL 16 + #define CONFIG_PLL1_DIV 2 + // USB Clock Source Options (Fusb = FpllX / USB_div) + #define CONFIG_USBCLK_SOURCE USBCLK_SRC_PLL1 + #define CONFIG_USBCLK_DIV 2 \endcode * * Content of conf_clock.h for SAM3U device (UPDHS: USB Peripheral Device High Speed): * \code - // USB Clock Source fixed at UPLL. + // USB Clock Source fixed at UPLL. \endcode * * Content of conf_clock.h for SAM3X, SAM3A devices (UOTGHS: USB OTG High Speed): * \code - // USB Clock Source fixed at UPLL. - #define CONFIG_USBCLK_SOURCE USBCLK_SRC_UPLL - #define CONFIG_USBCLK_DIV 1 + // USB Clock Source fixed at UPLL. + #define CONFIG_USBCLK_SOURCE USBCLK_SRC_UPLL + #define CONFIG_USBCLK_DIV 1 \endcode * * Content of conf_clocks.h for SAMD devices (USB): * \code - // System clock bus configuration - # define CONF_CLOCK_FLASH_WAIT_STATES 2 + // System clock bus configuration + # define CONF_CLOCK_FLASH_WAIT_STATES 2 - // USB Clock Source fixed at DFLL. - // SYSTEM_CLOCK_SOURCE_DFLL configuration - Digital Frequency Locked Loop - # define CONF_CLOCK_DFLL_ENABLE true - # define CONF_CLOCK_DFLL_LOOP_MODE SYSTEM_CLOCK_DFLL_LOOP_MODE_USB_RECOVERY - # define CONF_CLOCK_DFLL_ON_DEMAND true + // USB Clock Source fixed at DFLL. + // SYSTEM_CLOCK_SOURCE_DFLL configuration - Digital Frequency Locked Loop + # define CONF_CLOCK_DFLL_ENABLE true + # define CONF_CLOCK_DFLL_LOOP_MODE SYSTEM_CLOCK_DFLL_LOOP_MODE_USB_RECOVERY + # define CONF_CLOCK_DFLL_ON_DEMAND true - // Set this to true to configure the GCLK when running clocks_init. - // If set to false, none of the GCLK generators will be configured in clocks_init(). - # define CONF_CLOCK_CONFIGURE_GCLK true + // Set this to true to configure the GCLK when running clocks_init. + // If set to false, none of the GCLK generators will be configured in clocks_init(). + # define CONF_CLOCK_CONFIGURE_GCLK true - // Configure GCLK generator 0 (Main Clock) - # define CONF_CLOCK_GCLK_0_ENABLE true - # define CONF_CLOCK_GCLK_0_RUN_IN_STANDBY true - # define CONF_CLOCK_GCLK_0_CLOCK_SOURCE SYSTEM_CLOCK_SOURCE_DFLL - # define CONF_CLOCK_GCLK_0_PRESCALER 1 - # define CONF_CLOCK_GCLK_0_OUTPUT_ENABLE false + // Configure GCLK generator 0 (Main Clock) + # define CONF_CLOCK_GCLK_0_ENABLE true + # define CONF_CLOCK_GCLK_0_RUN_IN_STANDBY true + # define CONF_CLOCK_GCLK_0_CLOCK_SOURCE SYSTEM_CLOCK_SOURCE_DFLL + # define CONF_CLOCK_GCLK_0_PRESCALER 1 + # define CONF_CLOCK_GCLK_0_OUTPUT_ENABLE false \endcode */ @@ -474,34 +467,34 @@ usb_iface_desc_t UDC_DESC_STORAGE *udc_get_interface_desc(void); * \subsection udc_use_case_1_usage_code Example code * Content of conf_usb.h: * \code - #if // Low speed - #define USB_DEVICE_LOW_SPEED - // #define USB_DEVICE_HS_SUPPORT + #if // Low speed + #define USB_DEVICE_LOW_SPEED + // #define USB_DEVICE_HS_SUPPORT - #elif // Full speed - // #define USB_DEVICE_LOW_SPEED - // #define USB_DEVICE_HS_SUPPORT + #elif // Full speed + // #define USB_DEVICE_LOW_SPEED + // #define USB_DEVICE_HS_SUPPORT - #elif // High speed - // #define USB_DEVICE_LOW_SPEED - #define USB_DEVICE_HS_SUPPORT + #elif // High speed + // #define USB_DEVICE_LOW_SPEED + #define USB_DEVICE_HS_SUPPORT - #endif + #endif \endcode * * \subsection udc_use_case_1_usage_flow Workflow * -# Ensure that conf_usb.h is available and contains the following parameters * required for a USB device low speed (1.5Mbit/s): * - \code #define USB_DEVICE_LOW_SPEED - //#define USB_DEVICE_HS_SUPPORT \endcode + //#define USB_DEVICE_HS_SUPPORT \endcode * -# Ensure that conf_usb.h contains the following parameters * required for a USB device full speed (12Mbit/s): * - \code //#define USB_DEVICE_LOW_SPEED - //#define USB_DEVICE_HS_SUPPORT \endcode + //#define USB_DEVICE_HS_SUPPORT \endcode * -# Ensure that conf_usb.h contains the following parameters * required for a USB device high speed (480Mbit/s): * - \code //#define USB_DEVICE_LOW_SPEED - #define USB_DEVICE_HS_SUPPORT \endcode + #define USB_DEVICE_HS_SUPPORT \endcode */ /** @@ -518,20 +511,20 @@ usb_iface_desc_t UDC_DESC_STORAGE *udc_get_interface_desc(void); * \subsection udc_use_case_2_usage_code Example code * Content of conf_usb.h: * \code - #define USB_DEVICE_MANUFACTURE_NAME "Manufacture name" - #define USB_DEVICE_PRODUCT_NAME "Product name" - #define USB_DEVICE_SERIAL_NAME "12...EF" + #define USB_DEVICE_MANUFACTURE_NAME "Manufacture name" + #define USB_DEVICE_PRODUCT_NAME "Product name" + #define USB_DEVICE_SERIAL_NAME "12...EF" \endcode * * \subsection udc_use_case_2_usage_flow Workflow * -# Ensure that conf_usb.h is available and contains the following parameters * required to enable different USB strings: * - \code // Static ASCII name for the manufacture - #define USB_DEVICE_MANUFACTURE_NAME "Manufacture name" \endcode + #define USB_DEVICE_MANUFACTURE_NAME "Manufacture name" \endcode * - \code // Static ASCII name for the product - #define USB_DEVICE_PRODUCT_NAME "Product name" \endcode + #define USB_DEVICE_PRODUCT_NAME "Product name" \endcode * - \code // Static ASCII name to enable and set a serial number - #define USB_DEVICE_SERIAL_NAME "12...EF" \endcode + #define USB_DEVICE_SERIAL_NAME "12...EF" \endcode */ /** @@ -548,42 +541,42 @@ usb_iface_desc_t UDC_DESC_STORAGE *udc_get_interface_desc(void); * \subsection udc_use_case_3_usage_code Example code * Content of conf_usb.h: * \code - #define USB_DEVICE_ATTR \ - (USB_CONFIG_ATTR_REMOTE_WAKEUP | USB_CONFIG_ATTR_..._POWERED) - #define UDC_REMOTEWAKEUP_ENABLE() my_callback_remotewakeup_enable() - extern void my_callback_remotewakeup_enable(void); - #define UDC_REMOTEWAKEUP_DISABLE() my_callback_remotewakeup_disable() - extern void my_callback_remotewakeup_disable(void); + #define USB_DEVICE_ATTR \ + (USB_CONFIG_ATTR_REMOTE_WAKEUP | USB_CONFIG_ATTR_..._POWERED) + #define UDC_REMOTEWAKEUP_ENABLE() my_callback_remotewakeup_enable() + extern void my_callback_remotewakeup_enable(void); + #define UDC_REMOTEWAKEUP_DISABLE() my_callback_remotewakeup_disable() + extern void my_callback_remotewakeup_disable(void); \endcode * * Add to application C-file: * \code - void my_callback_remotewakeup_enable(void) - { - // Enable application wakeup events (e.g. enable GPIO interrupt) - } - void my_callback_remotewakeup_disable(void) - { - // Disable application wakeup events (e.g. disable GPIO interrupt) - } + void my_callback_remotewakeup_enable(void) + { + // Enable application wakeup events (e.g. enable GPIO interrupt) + } + void my_callback_remotewakeup_disable(void) + { + // Disable application wakeup events (e.g. disable GPIO interrupt) + } - void my_interrupt_event(void) - { - udc_remotewakeup(); - } + void my_interrupt_event(void) + { + udc_remotewakeup(); + } \endcode * * \subsection udc_use_case_3_usage_flow Workflow * -# Ensure that conf_usb.h is available and contains the following parameters * required to enable remote wakeup feature: * - \code // Authorizes the remote wakeup feature - #define USB_DEVICE_ATTR (USB_CONFIG_ATTR_REMOTE_WAKEUP | USB_CONFIG_ATTR_..._POWERED) \endcode + #define USB_DEVICE_ATTR (USB_CONFIG_ATTR_REMOTE_WAKEUP | USB_CONFIG_ATTR_..._POWERED) \endcode * - \code // Define callback called when the host enables the remotewakeup feature - #define UDC_REMOTEWAKEUP_ENABLE() my_callback_remotewakeup_enable() - extern void my_callback_remotewakeup_enable(void); \endcode + #define UDC_REMOTEWAKEUP_ENABLE() my_callback_remotewakeup_enable() + extern void my_callback_remotewakeup_enable(void); \endcode * - \code // Define callback called when the host disables the remotewakeup feature - #define UDC_REMOTEWAKEUP_DISABLE() my_callback_remotewakeup_disable() - extern void my_callback_remotewakeup_disable(void); \endcode + #define UDC_REMOTEWAKEUP_DISABLE() my_callback_remotewakeup_disable() + extern void my_callback_remotewakeup_disable(void); \endcode * -# Send a remote wakeup (USB upstream): * - \code udc_remotewakeup(); \endcode */ @@ -603,40 +596,40 @@ usb_iface_desc_t UDC_DESC_STORAGE *udc_get_interface_desc(void); * \subsection udc_use_case_5_usage_code Example code * Content of conf_usb.h: * \code - #define USB_DEVICE_ATTR (USB_CONFIG_ATTR_BUS_POWERED) - #define UDC_SUSPEND_EVENT() user_callback_suspend_action() - extern void user_callback_suspend_action(void) - #define UDC_RESUME_EVENT() user_callback_resume_action() - extern void user_callback_resume_action(void) + #define USB_DEVICE_ATTR (USB_CONFIG_ATTR_BUS_POWERED) + #define UDC_SUSPEND_EVENT() user_callback_suspend_action() + extern void user_callback_suspend_action(void) + #define UDC_RESUME_EVENT() user_callback_resume_action() + extern void user_callback_resume_action(void) \endcode * * Add to application C-file: * \code - void user_callback_suspend_action(void) - { - // Disable hardware component to reduce power consumption - } - void user_callback_resume_action(void) - { - // Re-enable hardware component - } + void user_callback_suspend_action(void) + { + // Disable hardware component to reduce power consumption + } + void user_callback_resume_action(void) + { + // Re-enable hardware component + } \endcode * * \subsection udc_use_case_5_usage_flow Workflow * -# Ensure that conf_usb.h is available and contains the following parameters: * - \code // Authorizes the BUS power feature - #define USB_DEVICE_ATTR (USB_CONFIG_ATTR_BUS_POWERED) \endcode + #define USB_DEVICE_ATTR (USB_CONFIG_ATTR_BUS_POWERED) \endcode * - \code // Define callback called when the host suspend the USB line - #define UDC_SUSPEND_EVENT() user_callback_suspend_action() - extern void user_callback_suspend_action(void); \endcode + #define UDC_SUSPEND_EVENT() user_callback_suspend_action() + extern void user_callback_suspend_action(void); \endcode * - \code // Define callback called when the host or device resume the USB line - #define UDC_RESUME_EVENT() user_callback_resume_action() - extern void user_callback_resume_action(void); \endcode + #define UDC_RESUME_EVENT() user_callback_resume_action() + extern void user_callback_resume_action(void); \endcode * -# Reduce power consumption in suspend mode (max. 2.5mA on Vbus): * - \code void user_callback_suspend_action(void) - { - turn_off_components(); - } \endcode + { + turn_off_components(); + } \endcode */ /** @@ -654,42 +647,42 @@ usb_iface_desc_t UDC_DESC_STORAGE *udc_get_interface_desc(void); * \subsection udc_use_case_6_usage_code Example code * Content of conf_usb.h: * \code - #define USB_DEVICE_SERIAL_NAME - #define USB_DEVICE_GET_SERIAL_NAME_POINTER serial_number - #define USB_DEVICE_GET_SERIAL_NAME_LENGTH 12 - extern uint8_t serial_number[]; + #define USB_DEVICE_SERIAL_NAME + #define USB_DEVICE_GET_SERIAL_NAME_POINTER serial_number + #define USB_DEVICE_GET_SERIAL_NAME_LENGTH 12 + extern uint8_t serial_number[]; \endcode * * Add to application C-file: * \code - uint8_t serial_number[USB_DEVICE_GET_SERIAL_NAME_LENGTH]; + uint8_t serial_number[USB_DEVICE_GET_SERIAL_NAME_LENGTH]; - void init_build_usb_serial_number(void) - { - serial_number[0] = 'A'; - serial_number[1] = 'B'; - ... - serial_number[USB_DEVICE_GET_SERIAL_NAME_LENGTH-1] = 'C'; - } \endcode + void init_build_usb_serial_number(void) + { + serial_number[0] = 'A'; + serial_number[1] = 'B'; + ... + serial_number[USB_DEVICE_GET_SERIAL_NAME_LENGTH-1] = 'C'; + } \endcode * * \subsection udc_use_case_6_usage_flow Workflow * -# Ensure that conf_usb.h is available and contains the following parameters * required to enable a USB serial number strings dynamically: * - \code #define USB_DEVICE_SERIAL_NAME // Define this empty - #define USB_DEVICE_GET_SERIAL_NAME_POINTER serial_number // Give serial array pointer - #define USB_DEVICE_GET_SERIAL_NAME_LENGTH 12 // Give size of serial array - extern uint8_t serial_number[]; // Declare external serial array \endcode + #define USB_DEVICE_GET_SERIAL_NAME_POINTER serial_number // Give serial array pointer + #define USB_DEVICE_GET_SERIAL_NAME_LENGTH 12 // Give size of serial array + extern uint8_t serial_number[]; // Declare external serial array \endcode * -# Before start USB stack, initialize the serial array * - \code - uint8_t serial_number[USB_DEVICE_GET_SERIAL_NAME_LENGTH]; + uint8_t serial_number[USB_DEVICE_GET_SERIAL_NAME_LENGTH]; - void init_build_usb_serial_number(void) - { - serial_number[0] = 'A'; - serial_number[1] = 'B'; - ... - serial_number[USB_DEVICE_GET_SERIAL_NAME_LENGTH-1] = 'C'; - } \endcode + void init_build_usb_serial_number(void) + { + serial_number[0] = 'A'; + serial_number[1] = 'B'; + ... + serial_number[USB_DEVICE_GET_SERIAL_NAME_LENGTH-1] = 'C'; + } \endcode */ diff --git a/Marlin/src/HAL/DUE/usb/udc_desc.h b/Marlin/src/HAL/DUE/usb/udc_desc.h index 052ca08eca..f1f328d035 100644 --- a/Marlin/src/HAL/DUE/usb/udc_desc.h +++ b/Marlin/src/HAL/DUE/usb/udc_desc.h @@ -78,50 +78,47 @@ extern "C" { * For Mega application used "code". */ #define UDC_DESC_STORAGE - // Descriptor storage in internal RAM + // Descriptor storage in internal RAM #if (defined UDC_DATA_USE_HRAM_SUPPORT) -# if defined(__GNUC__) -# define UDC_DATA(x) COMPILER_WORD_ALIGNED __attribute__((__section__(".data_hram0"))) -# define UDC_BSS(x) COMPILER_ALIGNED(x) __attribute__((__section__(".bss_hram0"))) -# elif defined(__ICCAVR32__) -# define UDC_DATA(x) COMPILER_ALIGNED(x) __data32 -# define UDC_BSS(x) COMPILER_ALIGNED(x) __data32 -# endif -#else -# define UDC_DATA(x) COMPILER_ALIGNED(x) -# define UDC_BSS(x) COMPILER_ALIGNED(x) + #if defined(__GNUC__) + #define UDC_DATA(x) COMPILER_WORD_ALIGNED __attribute__((__section__(".data_hram0"))) + #define UDC_BSS(x) COMPILER_ALIGNED(x) __attribute__((__section__(".bss_hram0"))) +#elif defined(__ICCAVR32__) + #define UDC_DATA(x) COMPILER_ALIGNED(x) __data32 + #define UDC_BSS(x) COMPILER_ALIGNED(x) __data32 +#endif +#else + #define UDC_DATA(x) COMPILER_ALIGNED(x) + #define UDC_BSS(x) COMPILER_ALIGNED(x) #endif - - /** * \brief Configuration descriptor and UDI link for one USB speed */ typedef struct { - //! USB configuration descriptor - usb_conf_desc_t UDC_DESC_STORAGE *desc; - //! Array of UDI API pointer - udi_api_t UDC_DESC_STORAGE *UDC_DESC_STORAGE * udi_apis; + //! USB configuration descriptor + usb_conf_desc_t UDC_DESC_STORAGE *desc; + //! Array of UDI API pointer + udi_api_t UDC_DESC_STORAGE *UDC_DESC_STORAGE * udi_apis; } udc_config_speed_t; - /** * \brief All information about the USB Device */ typedef struct { - //! USB device descriptor for low or full speed - usb_dev_desc_t UDC_DESC_STORAGE *confdev_lsfs; - //! USB configuration descriptor and UDI API pointers for low or full speed - udc_config_speed_t UDC_DESC_STORAGE *conf_lsfs; -#ifdef USB_DEVICE_HS_SUPPORT - //! USB device descriptor for high speed - usb_dev_desc_t UDC_DESC_STORAGE *confdev_hs; - //! USB device qualifier, only use in high speed mode - usb_dev_qual_desc_t UDC_DESC_STORAGE *qualifier; - //! USB configuration descriptor and UDI API pointers for high speed - udc_config_speed_t UDC_DESC_STORAGE *conf_hs; -#endif - usb_dev_bos_desc_t UDC_DESC_STORAGE *conf_bos; + //! USB device descriptor for low or full speed + usb_dev_desc_t UDC_DESC_STORAGE *confdev_lsfs; + //! USB configuration descriptor and UDI API pointers for low or full speed + udc_config_speed_t UDC_DESC_STORAGE *conf_lsfs; + #ifdef USB_DEVICE_HS_SUPPORT + //! USB device descriptor for high speed + usb_dev_desc_t UDC_DESC_STORAGE *confdev_hs; + //! USB device qualifier, only use in high speed mode + usb_dev_qual_desc_t UDC_DESC_STORAGE *qualifier; + //! USB configuration descriptor and UDI API pointers for high speed + udc_config_speed_t UDC_DESC_STORAGE *conf_hs; + #endif + usb_dev_bos_desc_t UDC_DESC_STORAGE *conf_bos; } udc_config_t; //! Global variables of USB Device Descriptor and UDI links diff --git a/Marlin/src/HAL/DUE/usb/udd.h b/Marlin/src/HAL/DUE/usb/udd.h index 319d8842f7..6eda465e54 100644 --- a/Marlin/src/HAL/DUE/usb/udd.h +++ b/Marlin/src/HAL/DUE/usb/udd.h @@ -71,8 +71,8 @@ typedef uint8_t udd_ep_id_t; //! \brief Endpoint transfer status //! Returned in parameters of callback register via udd_ep_run routine. typedef enum { - UDD_EP_TRANSFER_OK = 0, - UDD_EP_TRANSFER_ABORT = 1, + UDD_EP_TRANSFER_OK = 0, + UDD_EP_TRANSFER_ABORT = 1, } udd_ep_status_t; /** @@ -82,41 +82,37 @@ typedef enum { * It can be updated by udc_process_setup() from UDC or *setup() from UDIs. */ typedef struct { - //! Data received in USB SETUP packet - //! Note: The swap of "req.wValues" from uin16_t to le16_t is done by UDD. - usb_setup_req_t req; + //! Data received in USB SETUP packet + //! Note: The swap of "req.wValues" from uin16_t to le16_t is done by UDD. + usb_setup_req_t req; - //! Point to buffer to send or fill with data following SETUP packet - //! This buffer must be word align for DATA IN phase (use prefix COMPILER_WORD_ALIGNED for buffer) - uint8_t *payload; + //! Point to buffer to send or fill with data following SETUP packet + //! This buffer must be word align for DATA IN phase (use prefix COMPILER_WORD_ALIGNED for buffer) + uint8_t *payload; - //! Size of buffer to send or fill, and content the number of byte transferred - uint16_t payload_size; + //! Size of buffer to send or fill, and content the number of byte transferred + uint16_t payload_size; - //! Callback called after reception of ZLP from setup request - void (*callback)(void); + //! Callback called after reception of ZLP from setup request + void (*callback)(void); - //! Callback called when the buffer given (.payload) is full or empty. - //! This one return false to abort data transfer, or true with a new buffer in .payload. - bool (*over_under_run)(void); + //! Callback called when the buffer given (.payload) is full or empty. + //! This one return false to abort data transfer, or true with a new buffer in .payload. + bool (*over_under_run)(void); } udd_ctrl_request_t; extern udd_ctrl_request_t udd_g_ctrlreq; //! Return true if the setup request \a udd_g_ctrlreq indicates IN data transfer -#define Udd_setup_is_in() \ - (USB_REQ_DIR_IN == (udd_g_ctrlreq.req.bmRequestType & USB_REQ_DIR_MASK)) +#define Udd_setup_is_in() (USB_REQ_DIR_IN == (udd_g_ctrlreq.req.bmRequestType & USB_REQ_DIR_MASK)) //! Return true if the setup request \a udd_g_ctrlreq indicates OUT data transfer -#define Udd_setup_is_out() \ - (USB_REQ_DIR_OUT == (udd_g_ctrlreq.req.bmRequestType & USB_REQ_DIR_MASK)) +#define Udd_setup_is_out() (USB_REQ_DIR_OUT == (udd_g_ctrlreq.req.bmRequestType & USB_REQ_DIR_MASK)) //! Return the type of the SETUP request \a udd_g_ctrlreq. \see usb_reqtype. -#define Udd_setup_type() \ - (udd_g_ctrlreq.req.bmRequestType & USB_REQ_TYPE_MASK) +#define Udd_setup_type() (udd_g_ctrlreq.req.bmRequestType & USB_REQ_TYPE_MASK) //! Return the recipient of the SETUP request \a udd_g_ctrlreq. \see usb_recipient -#define Udd_setup_recipient() \ - (udd_g_ctrlreq.req.bmRequestType & USB_REQ_RECIP_MASK) +#define Udd_setup_recipient() (udd_g_ctrlreq.req.bmRequestType & USB_REQ_RECIP_MASK) /** * \brief End of halt callback function type. @@ -134,8 +130,7 @@ typedef void (*udd_callback_halt_cleared_t)(void); * \param status UDD_EP_TRANSFER_ABORT, if transfer is aborted * \param n number of data transferred */ -typedef void (*udd_callback_trans_t) (udd_ep_status_t status, - iram_size_t nb_transferred, udd_ep_id_t ep); +typedef void (*udd_callback_trans_t) (udd_ep_status_t status, iram_size_t nb_transferred, udd_ep_id_t ep); /** * \brief Authorizes the VBUS event @@ -239,8 +234,7 @@ void udd_set_setup_payload( uint8_t *payload, uint16_t payload_size ); * * \return \c 1 if the endpoint is enabled, otherwise \c 0. */ -bool udd_ep_alloc(udd_ep_id_t ep, uint8_t bmAttributes, - uint16_t MaxEndpointSize); +bool udd_ep_alloc(udd_ep_id_t ep, uint8_t bmAttributes, uint16_t MaxEndpointSize); /** * \brief Disables an endpoint @@ -294,8 +288,7 @@ bool udd_ep_clear_halt(udd_ep_id_t ep); * * \return \c 1 if the register is accepted, otherwise \c 0. */ -bool udd_ep_wait_stall_clear(udd_ep_id_t ep, - udd_callback_halt_cleared_t callback); +bool udd_ep_wait_stall_clear(udd_ep_id_t ep, udd_callback_halt_cleared_t callback); /** * \brief Allows to receive or send data on an endpoint @@ -321,9 +314,8 @@ bool udd_ep_wait_stall_clear(udd_ep_id_t ep, * * \return \c 1 if function was successfully done, otherwise \c 0. */ -bool udd_ep_run(udd_ep_id_t ep, bool b_shortpacket, - uint8_t * buf, iram_size_t buf_size, - udd_callback_trans_t callback); +bool udd_ep_run(udd_ep_id_t ep, bool b_shortpacket, uint8_t * buf, iram_size_t buf_size, udd_callback_trans_t callback); + /** * \brief Aborts transfer on going on endpoint * @@ -339,7 +331,6 @@ void udd_ep_abort(udd_ep_id_t ep); //@} - /** * \name High speed test mode management * @@ -352,7 +343,6 @@ void udd_test_mode_se0_nak(void); void udd_test_mode_packet(void); //@} - /** * \name UDC callbacks to provide for UDD * diff --git a/Marlin/src/HAL/DUE/usb/udi.h b/Marlin/src/HAL/DUE/usb/udi.h index febf03b718..bc5de086f3 100644 --- a/Marlin/src/HAL/DUE/usb/udi.h +++ b/Marlin/src/HAL/DUE/usb/udi.h @@ -72,57 +72,57 @@ extern "C" { * selected by UDC. */ typedef struct { - /** - * \brief Enable the interface. - * - * This function is called when the host selects a configuration - * to which this interface belongs through a Set Configuration - * request, and when the host selects an alternate setting of - * this interface through a Set Interface request. - * - * \return \c 1 if function was successfully done, otherwise \c 0. - */ - bool (*enable)(void); + /** + * \brief Enable the interface. + * + * This function is called when the host selects a configuration + * to which this interface belongs through a Set Configuration + * request, and when the host selects an alternate setting of + * this interface through a Set Interface request. + * + * \return \c 1 if function was successfully done, otherwise \c 0. + */ + bool (*enable)(void); - /** - * \brief Disable the interface. - * - * This function is called when this interface is currently - * active, and - * - the host selects any configuration through a Set - * Configuration request, or - * - the host issues a USB reset, or - * - the device is detached from the host (i.e. Vbus is no - * longer present) - */ - void (*disable)(void); + /** + * \brief Disable the interface. + * + * This function is called when this interface is currently + * active, and + * - the host selects any configuration through a Set + * Configuration request, or + * - the host issues a USB reset, or + * - the device is detached from the host (i.e. Vbus is no + * longer present) + */ + void (*disable)(void); - /** - * \brief Handle a control request directed at an interface. - * - * This function is called when this interface is currently - * active and the host sends a SETUP request - * with this interface as the recipient. - * - * Use udd_g_ctrlreq to decode and response to SETUP request. - * - * \return \c 1 if this interface supports the SETUP request, otherwise \c 0. - */ - bool (*setup)(void); + /** + * \brief Handle a control request directed at an interface. + * + * This function is called when this interface is currently + * active and the host sends a SETUP request + * with this interface as the recipient. + * + * Use udd_g_ctrlreq to decode and response to SETUP request. + * + * \return \c 1 if this interface supports the SETUP request, otherwise \c 0. + */ + bool (*setup)(void); - /** - * \brief Returns the current setting of the selected interface. - * - * This function is called when UDC when know alternate setting of selected interface. - * - * \return alternate setting of selected interface - */ - uint8_t (*getsetting)(void); + /** + * \brief Returns the current setting of the selected interface. + * + * This function is called when UDC when know alternate setting of selected interface. + * + * \return alternate setting of selected interface + */ + uint8_t (*getsetting)(void); - /** - * \brief To signal that a SOF is occurred - */ - void (*sof_notify)(void); + /** + * \brief To signal that a SOF is occurred + */ + void (*sof_notify)(void); } udi_api_t; //@} diff --git a/Marlin/src/HAL/DUE/usb/udi_cdc.h b/Marlin/src/HAL/DUE/usb/udi_cdc.h index b61845011a..2bc5fff187 100644 --- a/Marlin/src/HAL/DUE/usb/udi_cdc.h +++ b/Marlin/src/HAL/DUE/usb/udi_cdc.h @@ -92,18 +92,18 @@ extern UDC_DESC_STORAGE udi_api_t udi_api_cdc_data; * descriptors for the CDC Communication Class interface. */ typedef struct { - //! Standard interface descriptor - usb_iface_desc_t iface; - //! CDC Header functional descriptor - usb_cdc_hdr_desc_t header; - //! CDC Abstract Control Model functional descriptor - usb_cdc_acm_desc_t acm; - //! CDC Union functional descriptor - usb_cdc_union_desc_t union_desc; - //! CDC Call Management functional descriptor - usb_cdc_call_mgmt_desc_t call_mgmt; - //! Notification endpoint descriptor - usb_ep_desc_t ep_notify; + //! Standard interface descriptor + usb_iface_desc_t iface; + //! CDC Header functional descriptor + usb_cdc_hdr_desc_t header; + //! CDC Abstract Control Model functional descriptor + usb_cdc_acm_desc_t acm; + //! CDC Union functional descriptor + usb_cdc_union_desc_t union_desc; + //! CDC Call Management functional descriptor + usb_cdc_call_mgmt_desc_t call_mgmt; + //! Notification endpoint descriptor + usb_ep_desc_t ep_notify; } udi_cdc_comm_desc_t; @@ -114,11 +114,11 @@ typedef struct { * CDC Data Class interface. */ typedef struct { - //! Standard interface descriptor - usb_iface_desc_t iface; - //! Data IN/OUT endpoint descriptors - usb_ep_desc_t ep_in; - usb_ep_desc_t ep_out; + //! Standard interface descriptor + usb_iface_desc_t iface; + //! Data IN/OUT endpoint descriptors + usb_ep_desc_t ep_in; + usb_ep_desc_t ep_out; } udi_cdc_data_desc_t; @@ -136,13 +136,13 @@ typedef struct { //@{ //! By default no string associated to these interfaces #ifndef UDI_CDC_IAD_STRING_ID_0 -#define UDI_CDC_IAD_STRING_ID_0 0 + #define UDI_CDC_IAD_STRING_ID_0 0 #endif #ifndef UDI_CDC_COMM_STRING_ID_0 -#define UDI_CDC_COMM_STRING_ID_0 0 + #define UDI_CDC_COMM_STRING_ID_0 0 #endif #ifndef UDI_CDC_DATA_STRING_ID_0 -#define UDI_CDC_DATA_STRING_ID_0 0 + #define UDI_CDC_DATA_STRING_ID_0 0 #endif #define UDI_CDC_IAD_DESC_0 UDI_CDC_IAD_DESC(0) #define UDI_CDC_COMM_DESC_0 UDI_CDC_COMM_DESC(0) @@ -151,13 +151,13 @@ typedef struct { //! By default no string associated to these interfaces #ifndef UDI_CDC_IAD_STRING_ID_1 -#define UDI_CDC_IAD_STRING_ID_1 0 + #define UDI_CDC_IAD_STRING_ID_1 0 #endif #ifndef UDI_CDC_COMM_STRING_ID_1 -#define UDI_CDC_COMM_STRING_ID_1 0 + #define UDI_CDC_COMM_STRING_ID_1 0 #endif #ifndef UDI_CDC_DATA_STRING_ID_1 -#define UDI_CDC_DATA_STRING_ID_1 0 + #define UDI_CDC_DATA_STRING_ID_1 0 #endif #define UDI_CDC_IAD_DESC_1 UDI_CDC_IAD_DESC(1) #define UDI_CDC_COMM_DESC_1 UDI_CDC_COMM_DESC(1) @@ -166,13 +166,13 @@ typedef struct { //! By default no string associated to these interfaces #ifndef UDI_CDC_IAD_STRING_ID_2 -#define UDI_CDC_IAD_STRING_ID_2 0 + #define UDI_CDC_IAD_STRING_ID_2 0 #endif #ifndef UDI_CDC_COMM_STRING_ID_2 -#define UDI_CDC_COMM_STRING_ID_2 0 + #define UDI_CDC_COMM_STRING_ID_2 0 #endif #ifndef UDI_CDC_DATA_STRING_ID_2 -#define UDI_CDC_DATA_STRING_ID_2 0 + #define UDI_CDC_DATA_STRING_ID_2 0 #endif #define UDI_CDC_IAD_DESC_2 UDI_CDC_IAD_DESC(2) #define UDI_CDC_COMM_DESC_2 UDI_CDC_COMM_DESC(2) @@ -181,13 +181,13 @@ typedef struct { //! By default no string associated to these interfaces #ifndef UDI_CDC_IAD_STRING_ID_3 -#define UDI_CDC_IAD_STRING_ID_3 0 + #define UDI_CDC_IAD_STRING_ID_3 0 #endif #ifndef UDI_CDC_COMM_STRING_ID_3 -#define UDI_CDC_COMM_STRING_ID_3 0 + #define UDI_CDC_COMM_STRING_ID_3 0 #endif #ifndef UDI_CDC_DATA_STRING_ID_3 -#define UDI_CDC_DATA_STRING_ID_3 0 + #define UDI_CDC_DATA_STRING_ID_3 0 #endif #define UDI_CDC_IAD_DESC_3 UDI_CDC_IAD_DESC(3) #define UDI_CDC_COMM_DESC_3 UDI_CDC_COMM_DESC(3) @@ -196,13 +196,13 @@ typedef struct { //! By default no string associated to these interfaces #ifndef UDI_CDC_IAD_STRING_ID_4 -#define UDI_CDC_IAD_STRING_ID_4 0 + #define UDI_CDC_IAD_STRING_ID_4 0 #endif #ifndef UDI_CDC_COMM_STRING_ID_4 -#define UDI_CDC_COMM_STRING_ID_4 0 + #define UDI_CDC_COMM_STRING_ID_4 0 #endif #ifndef UDI_CDC_DATA_STRING_ID_4 -#define UDI_CDC_DATA_STRING_ID_4 0 + #define UDI_CDC_DATA_STRING_ID_4 0 #endif #define UDI_CDC_IAD_DESC_4 UDI_CDC_IAD_DESC(4) #define UDI_CDC_COMM_DESC_4 UDI_CDC_COMM_DESC(4) @@ -211,13 +211,13 @@ typedef struct { //! By default no string associated to these interfaces #ifndef UDI_CDC_IAD_STRING_ID_5 -#define UDI_CDC_IAD_STRING_ID_5 0 + #define UDI_CDC_IAD_STRING_ID_5 0 #endif #ifndef UDI_CDC_COMM_STRING_ID_5 -#define UDI_CDC_COMM_STRING_ID_5 0 + #define UDI_CDC_COMM_STRING_ID_5 0 #endif #ifndef UDI_CDC_DATA_STRING_ID_5 -#define UDI_CDC_DATA_STRING_ID_5 0 + #define UDI_CDC_DATA_STRING_ID_5 0 #endif #define UDI_CDC_IAD_DESC_5 UDI_CDC_IAD_DESC(5) #define UDI_CDC_COMM_DESC_5 UDI_CDC_COMM_DESC(5) @@ -226,13 +226,13 @@ typedef struct { //! By default no string associated to these interfaces #ifndef UDI_CDC_IAD_STRING_ID_6 -#define UDI_CDC_IAD_STRING_ID_6 0 + #define UDI_CDC_IAD_STRING_ID_6 0 #endif #ifndef UDI_CDC_COMM_STRING_ID_6 -#define UDI_CDC_COMM_STRING_ID_6 0 + #define UDI_CDC_COMM_STRING_ID_6 0 #endif #ifndef UDI_CDC_DATA_STRING_ID_6 -#define UDI_CDC_DATA_STRING_ID_6 0 + #define UDI_CDC_DATA_STRING_ID_6 0 #endif #define UDI_CDC_IAD_DESC_6 UDI_CDC_IAD_DESC(6) #define UDI_CDC_COMM_DESC_6 UDI_CDC_COMM_DESC(6) @@ -240,7 +240,6 @@ typedef struct { #define UDI_CDC_DATA_DESC_6_HS UDI_CDC_DATA_DESC_HS(6) //@} - //! Content of CDC IAD interface descriptor for all speeds #define UDI_CDC_IAD_DESC(port) { \ .bLength = sizeof(usb_iad_desc_t),\ @@ -270,7 +269,7 @@ typedef struct { .call_mgmt.bDescriptorType = CDC_CS_INTERFACE,\ .call_mgmt.bDescriptorSubtype = CDC_SCS_CALL_MGMT,\ .call_mgmt.bmCapabilities = \ - CDC_CALL_MGMT_SUPPORTED | CDC_CALL_MGMT_OVER_DCI,\ + CDC_CALL_MGMT_SUPPORTED | CDC_CALL_MGMT_OVER_DCI,\ .acm.bFunctionLength = sizeof(usb_cdc_acm_desc_t),\ .acm.bDescriptorType = CDC_CS_INTERFACE,\ .acm.bDescriptorSubtype = CDC_SCS_ACM,\ @@ -610,40 +609,37 @@ iram_size_t udi_cdc_multi_write_buf(uint8_t port, const void* buf, iram_size_t s * \subsection udi_cdc_basic_use_case_usage_code Example code * Content of conf_usb.h: * \code - #define UDI_CDC_ENABLE_EXT(port) my_callback_cdc_enable() - extern bool my_callback_cdc_enable(void); - #define UDI_CDC_DISABLE_EXT(port) my_callback_cdc_disable() - extern void my_callback_cdc_disable(void); - #define UDI_CDC_LOW_RATE + #define UDI_CDC_ENABLE_EXT(port) my_callback_cdc_enable() + extern bool my_callback_cdc_enable(void); + #define UDI_CDC_DISABLE_EXT(port) my_callback_cdc_disable() + extern void my_callback_cdc_disable(void); + #define UDI_CDC_LOW_RATE - #define UDI_CDC_DEFAULT_RATE 115200 - #define UDI_CDC_DEFAULT_STOPBITS CDC_STOP_BITS_1 - #define UDI_CDC_DEFAULT_PARITY CDC_PAR_NONE - #define UDI_CDC_DEFAULT_DATABITS 8 + #define UDI_CDC_DEFAULT_RATE 115200 + #define UDI_CDC_DEFAULT_STOPBITS CDC_STOP_BITS_1 + #define UDI_CDC_DEFAULT_PARITY CDC_PAR_NONE + #define UDI_CDC_DEFAULT_DATABITS 8 - #include "udi_cdc_conf.h" // At the end of conf_usb.h file + #include "udi_cdc_conf.h" // At the end of conf_usb.h file \endcode * * Add to application C-file: * \code - static bool my_flag_autorize_cdc_transfert = false; - bool my_callback_cdc_enable(void) - { - my_flag_autorize_cdc_transfert = true; - return true; - } - void my_callback_cdc_disable(void) - { - my_flag_autorize_cdc_transfert = false; - } + static bool my_flag_autorize_cdc_transfert = false; + bool my_callback_cdc_enable(void) { + my_flag_autorize_cdc_transfert = true; + return true; + } + void my_callback_cdc_disable(void) { + my_flag_autorize_cdc_transfert = false; + } - void task(void) - { - if (my_flag_autorize_cdc_transfert) { - udi_cdc_putc('A'); - udi_cdc_getc(); - } - } + void task(void) { + if (my_flag_autorize_cdc_transfert) { + udi_cdc_putc('A'); + udi_cdc_getc(); + } + } \endcode * * \subsection udi_cdc_basic_use_case_setup_flow Workflow @@ -652,14 +648,14 @@ iram_size_t udi_cdc_multi_write_buf(uint8_t port, const void* buf, iram_size_t s * - \code #define USB_DEVICE_SERIAL_NAME "12...EF" // Disk SN for CDC \endcode * \note The USB serial number is mandatory when a CDC interface is used. * - \code #define UDI_CDC_ENABLE_EXT(port) my_callback_cdc_enable() - extern bool my_callback_cdc_enable(void); \endcode + extern bool my_callback_cdc_enable(void); \endcode * \note After the device enumeration (detecting and identifying USB devices), * the USB host starts the device configuration. When the USB CDC interface * from the device is accepted by the host, the USB host enables this interface and the * UDI_CDC_ENABLE_EXT() callback function is called and return true. * Thus, when this event is received, the data transfer on CDC interface are authorized. * - \code #define UDI_CDC_DISABLE_EXT(port) my_callback_cdc_disable() - extern void my_callback_cdc_disable(void); \endcode + extern void my_callback_cdc_disable(void); \endcode * \note When the USB device is unplugged or is reset by the USB host, the USB * interface is disabled and the UDI_CDC_DISABLE_EXT() callback function * is called. Thus, the data transfer must be stopped on CDC interface. @@ -667,19 +663,19 @@ iram_size_t udi_cdc_multi_write_buf(uint8_t port, const void* buf, iram_size_t s * \note Define it when the transfer CDC Device to Host is a low rate * (<512000 bauds) to reduce CDC buffers size. * - \code #define UDI_CDC_DEFAULT_RATE 115200 - #define UDI_CDC_DEFAULT_STOPBITS CDC_STOP_BITS_1 - #define UDI_CDC_DEFAULT_PARITY CDC_PAR_NONE - #define UDI_CDC_DEFAULT_DATABITS 8 \endcode + #define UDI_CDC_DEFAULT_STOPBITS CDC_STOP_BITS_1 + #define UDI_CDC_DEFAULT_PARITY CDC_PAR_NONE + #define UDI_CDC_DEFAULT_DATABITS 8 \endcode * \note Default configuration of communication port at startup. * -# Send or wait data on CDC line: * - \code // Waits and gets a value on CDC line - int udi_cdc_getc(void); - // Reads a RAM buffer on CDC line - iram_size_t udi_cdc_read_buf(int *buf, iram_size_t size); - // Puts a byte on CDC line - int udi_cdc_putc(int value); - // Writes a RAM buffer on CDC line - iram_size_t udi_cdc_write_buf(const int *buf, iram_size_t size); \endcode + int udi_cdc_getc(void); + // Reads a RAM buffer on CDC line + iram_size_t udi_cdc_read_buf(int *buf, iram_size_t size); + // Puts a byte on CDC line + int udi_cdc_putc(int value); + // Writes a RAM buffer on CDC line + iram_size_t udi_cdc_write_buf(const int *buf, iram_size_t size); \endcode * * \section udi_cdc_use_cases Advanced use cases * For more advanced use of the UDI CDC module, see the following use cases: @@ -713,90 +709,90 @@ iram_size_t udi_cdc_multi_write_buf(uint8_t port, const void* buf, iram_size_t s * \subsection udi_cdc_use_case_composite_usage_code Example code * Content of conf_usb.h: * \code - #define USB_DEVICE_EP_CTRL_SIZE 64 - #define USB_DEVICE_NB_INTERFACE (X+2) - #define USB_DEVICE_MAX_EP (X+3) + #define USB_DEVICE_EP_CTRL_SIZE 64 + #define USB_DEVICE_NB_INTERFACE (X+2) + #define USB_DEVICE_MAX_EP (X+3) - #define UDI_CDC_DATA_EP_IN_0 (1 | USB_EP_DIR_IN) // TX - #define UDI_CDC_DATA_EP_OUT_0 (2 | USB_EP_DIR_OUT) // RX - #define UDI_CDC_COMM_EP_0 (3 | USB_EP_DIR_IN) // Notify endpoint - #define UDI_CDC_COMM_IFACE_NUMBER_0 X+0 - #define UDI_CDC_DATA_IFACE_NUMBER_0 X+1 + #define UDI_CDC_DATA_EP_IN_0 (1 | USB_EP_DIR_IN) // TX + #define UDI_CDC_DATA_EP_OUT_0 (2 | USB_EP_DIR_OUT) // RX + #define UDI_CDC_COMM_EP_0 (3 | USB_EP_DIR_IN) // Notify endpoint + #define UDI_CDC_COMM_IFACE_NUMBER_0 X+0 + #define UDI_CDC_DATA_IFACE_NUMBER_0 X+1 - #define UDI_COMPOSITE_DESC_T \ - usb_iad_desc_t udi_cdc_iad; \ - udi_cdc_comm_desc_t udi_cdc_comm; \ - udi_cdc_data_desc_t udi_cdc_data; \ - ... - #define UDI_COMPOSITE_DESC_FS \ - .udi_cdc_iad = UDI_CDC_IAD_DESC_0, \ - .udi_cdc_comm = UDI_CDC_COMM_DESC_0, \ - .udi_cdc_data = UDI_CDC_DATA_DESC_0_FS, \ - ... - #define UDI_COMPOSITE_DESC_HS \ - .udi_cdc_iad = UDI_CDC_IAD_DESC_0, \ - .udi_cdc_comm = UDI_CDC_COMM_DESC_0, \ - .udi_cdc_data = UDI_CDC_DATA_DESC_0_HS, \ - ... - #define UDI_COMPOSITE_API \ - &udi_api_cdc_comm, \ - &udi_api_cdc_data, \ - ... + #define UDI_COMPOSITE_DESC_T \ + usb_iad_desc_t udi_cdc_iad; \ + udi_cdc_comm_desc_t udi_cdc_comm; \ + udi_cdc_data_desc_t udi_cdc_data; \ + ... + #define UDI_COMPOSITE_DESC_FS \ + .udi_cdc_iad = UDI_CDC_IAD_DESC_0, \ + .udi_cdc_comm = UDI_CDC_COMM_DESC_0, \ + .udi_cdc_data = UDI_CDC_DATA_DESC_0_FS, \ + ... + #define UDI_COMPOSITE_DESC_HS \ + .udi_cdc_iad = UDI_CDC_IAD_DESC_0, \ + .udi_cdc_comm = UDI_CDC_COMM_DESC_0, \ + .udi_cdc_data = UDI_CDC_DATA_DESC_0_HS, \ + ... + #define UDI_COMPOSITE_API \ + &udi_api_cdc_comm, \ + &udi_api_cdc_data, \ + ... \endcode * * \subsection udi_cdc_use_case_composite_usage_flow Workflow * -# Ensure that conf_usb.h is available and contains the following parameters * required for a USB composite device configuration: * - \code // Endpoint control size, This must be: - // - 8, 16, 32 or 64 for full speed device (8 is recommended to save RAM) - // - 64 for a high speed device - #define USB_DEVICE_EP_CTRL_SIZE 64 - // Total Number of interfaces on this USB device. - // Add 2 for CDC. - #define USB_DEVICE_NB_INTERFACE (X+2) - // Total number of endpoints on this USB device. - // This must include each endpoint for each interface. - // Add 3 for CDC. - #define USB_DEVICE_MAX_EP (X+3) \endcode + // - 8, 16, 32 or 64 for full speed device (8 is recommended to save RAM) + // - 64 for a high speed device + #define USB_DEVICE_EP_CTRL_SIZE 64 + // Total Number of interfaces on this USB device. + // Add 2 for CDC. + #define USB_DEVICE_NB_INTERFACE (X+2) + // Total number of endpoints on this USB device. + // This must include each endpoint for each interface. + // Add 3 for CDC. + #define USB_DEVICE_MAX_EP (X+3) \endcode * -# Ensure that conf_usb.h contains the description of * composite device: * - \code // The endpoint numbers chosen by you for the CDC. - // The endpoint numbers starting from 1. - #define UDI_CDC_DATA_EP_IN_0 (1 | USB_EP_DIR_IN) // TX - #define UDI_CDC_DATA_EP_OUT_0 (2 | USB_EP_DIR_OUT) // RX - #define UDI_CDC_COMM_EP_0 (3 | USB_EP_DIR_IN) // Notify endpoint - // The interface index of an interface starting from 0 - #define UDI_CDC_COMM_IFACE_NUMBER_0 X+0 - #define UDI_CDC_DATA_IFACE_NUMBER_0 X+1 \endcode + // The endpoint numbers starting from 1. + #define UDI_CDC_DATA_EP_IN_0 (1 | USB_EP_DIR_IN) // TX + #define UDI_CDC_DATA_EP_OUT_0 (2 | USB_EP_DIR_OUT) // RX + #define UDI_CDC_COMM_EP_0 (3 | USB_EP_DIR_IN) // Notify endpoint + // The interface index of an interface starting from 0 + #define UDI_CDC_COMM_IFACE_NUMBER_0 X+0 + #define UDI_CDC_DATA_IFACE_NUMBER_0 X+1 \endcode * -# Ensure that conf_usb.h contains the following parameters * required for a USB composite device configuration: * - \code // USB Interfaces descriptor structure - #define UDI_COMPOSITE_DESC_T \ - ... - usb_iad_desc_t udi_cdc_iad; \ - udi_cdc_comm_desc_t udi_cdc_comm; \ - udi_cdc_data_desc_t udi_cdc_data; \ - ... - // USB Interfaces descriptor value for Full Speed - #define UDI_COMPOSITE_DESC_FS \ - ... - .udi_cdc_iad = UDI_CDC_IAD_DESC_0, \ - .udi_cdc_comm = UDI_CDC_COMM_DESC_0, \ - .udi_cdc_data = UDI_CDC_DATA_DESC_0_FS, \ - ... - // USB Interfaces descriptor value for High Speed - #define UDI_COMPOSITE_DESC_HS \ - ... - .udi_cdc_iad = UDI_CDC_IAD_DESC_0, \ - .udi_cdc_comm = UDI_CDC_COMM_DESC_0, \ - .udi_cdc_data = UDI_CDC_DATA_DESC_0_HS, \ - ... - // USB Interface APIs - #define UDI_COMPOSITE_API \ - ... - &udi_api_cdc_comm, \ - &udi_api_cdc_data, \ - ... \endcode + #define UDI_COMPOSITE_DESC_T \ + ... + usb_iad_desc_t udi_cdc_iad; \ + udi_cdc_comm_desc_t udi_cdc_comm; \ + udi_cdc_data_desc_t udi_cdc_data; \ + ... + // USB Interfaces descriptor value for Full Speed + #define UDI_COMPOSITE_DESC_FS \ + ... + .udi_cdc_iad = UDI_CDC_IAD_DESC_0, \ + .udi_cdc_comm = UDI_CDC_COMM_DESC_0, \ + .udi_cdc_data = UDI_CDC_DATA_DESC_0_FS, \ + ... + // USB Interfaces descriptor value for High Speed + #define UDI_COMPOSITE_DESC_HS \ + ... + .udi_cdc_iad = UDI_CDC_IAD_DESC_0, \ + .udi_cdc_comm = UDI_CDC_COMM_DESC_0, \ + .udi_cdc_data = UDI_CDC_DATA_DESC_0_HS, \ + ... + // USB Interface APIs + #define UDI_COMPOSITE_API \ + ... + &udi_api_cdc_comm, \ + &udi_api_cdc_data, \ + ... \endcode * - \note The descriptors order given in the four lists above must be the * same as the order defined by all interface indexes. The interface index * orders are defined through UDI_X_IFACE_NUMBER defines.\n diff --git a/Marlin/src/HAL/DUE/usb/udi_cdc_desc.c b/Marlin/src/HAL/DUE/usb/udi_cdc_desc.c index 97c334e2a8..4c79e8df13 100644 --- a/Marlin/src/HAL/DUE/usb/udi_cdc_desc.c +++ b/Marlin/src/HAL/DUE/usb/udi_cdc_desc.c @@ -51,7 +51,7 @@ #include "udc_desc.h" #include "udi_cdc.h" -#if DISABLED(SDSUPPORT) +#if !HAS_MEDIA /** * \defgroup udi_cdc_group_single_desc USB device descriptors for a single interface @@ -256,6 +256,6 @@ UDC_DESC_STORAGE udc_config_t udc_config = { //@} //@} -#endif // SDSUPPORT +#endif // HAS_MEDIA #endif // ARDUINO_ARCH_SAM diff --git a/Marlin/src/HAL/DUE/usb/udi_composite_desc.c b/Marlin/src/HAL/DUE/usb/udi_composite_desc.c index da74fbe60d..b10d043b9f 100644 --- a/Marlin/src/HAL/DUE/usb/udi_composite_desc.c +++ b/Marlin/src/HAL/DUE/usb/udi_composite_desc.c @@ -50,7 +50,7 @@ #include "udd.h" #include "udc_desc.h" -#if ENABLED(SDSUPPORT) +#if HAS_MEDIA /** * \defgroup udi_group_desc Descriptors for a USB Device @@ -189,4 +189,4 @@ UDC_DESC_STORAGE udc_config_t udc_config = { #endif // ARDUINO_ARCH_SAM -#endif // SDSUPPORT +#endif // HAS_MEDIA diff --git a/Marlin/src/HAL/DUE/usb/udi_msc.c b/Marlin/src/HAL/DUE/usb/udi_msc.c index dd34048772..3f70a8fb18 100644 --- a/Marlin/src/HAL/DUE/usb/udi_msc.c +++ b/Marlin/src/HAL/DUE/usb/udi_msc.c @@ -57,7 +57,7 @@ #include "ctrl_access.h" #include -#if ENABLED(SDSUPPORT) +#if HAS_MEDIA #ifndef UDI_MSC_NOTIFY_TRANS_EXT # define UDI_MSC_NOTIFY_TRANS_EXT() @@ -372,9 +372,7 @@ static void udi_msc_sbc_trans(bool b_read); //@} - -bool udi_msc_enable(void) -{ +bool udi_msc_enable(void) { uint8_t lun; udi_msc_b_trans_req = false; udi_msc_b_cbw_invalid = false; @@ -397,18 +395,14 @@ bool udi_msc_enable(void) return true; } - -void udi_msc_disable(void) -{ +void udi_msc_disable(void) { udi_msc_b_trans_req = false; udi_msc_b_ack_trans = true; udi_msc_b_reset_trans = true; UDI_MSC_DISABLE_EXT(); } - -bool udi_msc_setup(void) -{ +bool udi_msc_setup(void) { if (Udd_setup_is_in()) { // Requests Interface GET if (Udd_setup_type() == USB_REQ_TYPE_CLASS) { @@ -451,17 +445,14 @@ bool udi_msc_setup(void) return false; // Not supported request } -uint8_t udi_msc_getsetting(void) -{ +uint8_t udi_msc_getsetting(void) { return 0; // MSC don't have multiple alternate setting } - // ------------------------ //------- Routines to process CBW packet -static void udi_msc_cbw_invalid(void) -{ +static void udi_msc_cbw_invalid(void) { if (!udi_msc_b_cbw_invalid) return; // Don't re-stall endpoint if error reset by setup udd_ep_set_halt(UDI_MSC_EP_OUT); @@ -469,8 +460,7 @@ static void udi_msc_cbw_invalid(void) udd_ep_wait_stall_clear(UDI_MSC_EP_OUT, udi_msc_cbw_invalid); } -static void udi_msc_csw_invalid(void) -{ +static void udi_msc_csw_invalid(void) { if (!udi_msc_b_cbw_invalid) return; // Don't re-stall endpoint if error reset by setup udd_ep_set_halt(UDI_MSC_EP_IN); @@ -478,8 +468,7 @@ static void udi_msc_csw_invalid(void) udd_ep_wait_stall_clear(UDI_MSC_EP_IN, udi_msc_csw_invalid); } -static void udi_msc_cbw_wait(void) -{ +static void udi_msc_cbw_wait(void) { // Register buffer and callback on OUT endpoint if (!udd_ep_run(UDI_MSC_EP_OUT, true, (uint8_t *) & udi_msc_cbw, @@ -490,10 +479,8 @@ static void udi_msc_cbw_wait(void) } } - static void udi_msc_cbw_received(udd_ep_status_t status, - iram_size_t nb_received, udd_ep_id_t ep) -{ + iram_size_t nb_received, udd_ep_id_t ep) { UNUSED(ep); // Check status of transfer if (UDD_EP_TRANSFER_OK != status) { @@ -582,9 +569,7 @@ static void udi_msc_cbw_received(udd_ep_status_t status, } } - -static bool udi_msc_cbw_validate(uint32_t alloc_len, uint8_t dir_flag) -{ +static bool udi_msc_cbw_validate(uint32_t alloc_len, uint8_t dir_flag) { /* * The following cases should result in a phase error: * - Case 2: Hn < Di @@ -612,12 +597,10 @@ static bool udi_msc_cbw_validate(uint32_t alloc_len, uint8_t dir_flag) return true; } - // ------------------------ //------- Routines to process small data packet -static void udi_msc_data_send(uint8_t * buffer, uint8_t buf_size) -{ +static void udi_msc_data_send(uint8_t * buffer, uint8_t buf_size) { // Sends data on IN endpoint if (!udd_ep_run(UDI_MSC_EP_IN, true, buffer, buf_size, udi_msc_data_sent)) { @@ -627,10 +610,8 @@ static void udi_msc_data_send(uint8_t * buffer, uint8_t buf_size) } } - static void udi_msc_data_sent(udd_ep_status_t status, iram_size_t nb_sent, - udd_ep_id_t ep) -{ + udd_ep_id_t ep) { UNUSED(ep); if (UDD_EP_TRANSFER_OK != status) { // Error protocol @@ -644,12 +625,10 @@ static void udi_msc_data_sent(udd_ep_status_t status, iram_size_t nb_sent, udi_msc_csw_process(); } - // ------------------------ //------- Routines to process CSW packet -static void udi_msc_csw_process(void) -{ +static void udi_msc_csw_process(void) { if (0 != udi_msc_csw.dCSWDataResidue) { // Residue not NULL // then STALL next request from USB host on corresponding endpoint @@ -664,9 +643,7 @@ static void udi_msc_csw_process(void) udi_msc_csw_send(); } - -void udi_msc_csw_send(void) -{ +void udi_msc_csw_send(void) { // Sends CSW on IN endpoint if (!udd_ep_run(UDI_MSC_EP_IN, false, (uint8_t *) & udi_msc_csw, @@ -678,10 +655,8 @@ void udi_msc_csw_send(void) } } - static void udi_msc_csw_sent(udd_ep_status_t status, iram_size_t nb_sent, - udd_ep_id_t ep) -{ + udd_ep_id_t ep) { UNUSED(ep); UNUSED(status); UNUSED(nb_sent); @@ -690,20 +665,17 @@ static void udi_msc_csw_sent(udd_ep_status_t status, iram_size_t nb_sent, udi_msc_cbw_wait(); } - // ------------------------ //------- Routines manage sense data -static void udi_msc_clear_sense(void) -{ +static void udi_msc_clear_sense(void) { memset((uint8_t*)&udi_msc_sense, 0, sizeof(struct scsi_request_sense_data)); udi_msc_sense.valid_reponse_code = SCSI_SENSE_VALID | SCSI_SENSE_CURRENT; udi_msc_sense.AddSenseLen = SCSI_SENSE_ADDL_LEN(sizeof(udi_msc_sense)); } static void udi_msc_sense_fail(uint8_t sense_key, uint16_t add_sense, - uint32_t lba) -{ + uint32_t lba) { udi_msc_clear_sense(); udi_msc_csw.bCSWStatus = USB_CSW_STATUS_FAIL; udi_msc_sense.sense_flag_key = sense_key; @@ -715,53 +687,39 @@ static void udi_msc_sense_fail(uint8_t sense_key, uint16_t add_sense, udi_msc_sense.AddSnsCodeQlfr = add_sense; } -static void udi_msc_sense_pass(void) -{ +static void udi_msc_sense_pass(void) { udi_msc_clear_sense(); udi_msc_csw.bCSWStatus = USB_CSW_STATUS_PASS; } - -static void udi_msc_sense_fail_not_present(void) -{ +static void udi_msc_sense_fail_not_present(void) { udi_msc_sense_fail(SCSI_SK_NOT_READY, SCSI_ASC_MEDIUM_NOT_PRESENT, 0); } -static void udi_msc_sense_fail_busy_or_change(void) -{ - udi_msc_sense_fail(SCSI_SK_UNIT_ATTENTION, - SCSI_ASC_NOT_READY_TO_READY_CHANGE, 0); +static void udi_msc_sense_fail_busy_or_change(void) { + udi_msc_sense_fail(SCSI_SK_UNIT_ATTENTION, SCSI_ASC_NOT_READY_TO_READY_CHANGE, 0); } -static void udi_msc_sense_fail_hardware(void) -{ - udi_msc_sense_fail(SCSI_SK_HARDWARE_ERROR, - SCSI_ASC_NO_ADDITIONAL_SENSE_INFO, 0); +static void udi_msc_sense_fail_hardware(void) { + udi_msc_sense_fail(SCSI_SK_HARDWARE_ERROR, SCSI_ASC_NO_ADDITIONAL_SENSE_INFO, 0); } -static void udi_msc_sense_fail_protected(void) -{ +static void udi_msc_sense_fail_protected(void) { udi_msc_sense_fail(SCSI_SK_DATA_PROTECT, SCSI_ASC_WRITE_PROTECTED, 0); } -static void udi_msc_sense_fail_cdb_invalid(void) -{ - udi_msc_sense_fail(SCSI_SK_ILLEGAL_REQUEST, - SCSI_ASC_INVALID_FIELD_IN_CDB, 0); +static void udi_msc_sense_fail_cdb_invalid(void) { + udi_msc_sense_fail(SCSI_SK_ILLEGAL_REQUEST, SCSI_ASC_INVALID_FIELD_IN_CDB, 0); } -static void udi_msc_sense_command_invalid(void) -{ - udi_msc_sense_fail(SCSI_SK_ILLEGAL_REQUEST, - SCSI_ASC_INVALID_COMMAND_OPERATION_CODE, 0); +static void udi_msc_sense_command_invalid(void) { + udi_msc_sense_fail(SCSI_SK_ILLEGAL_REQUEST, SCSI_ASC_INVALID_COMMAND_OPERATION_CODE, 0); } - // ------------------------ //------- Routines manage SCSI Commands -static void udi_msc_spc_requestsense(void) -{ +static void udi_msc_spc_requestsense(void) { uint8_t length = udi_msc_cbw.CDB[4]; // Can't send more than sense data length @@ -774,9 +732,7 @@ static void udi_msc_spc_requestsense(void) udi_msc_data_send((uint8_t*)&udi_msc_sense, length); } - -static void udi_msc_spc_inquiry(void) -{ +static void udi_msc_spc_inquiry(void) { uint8_t length, i; UDC_DATA(4) // Constant inquiry data for all LUNs @@ -835,9 +791,7 @@ static void udi_msc_spc_inquiry(void) udi_msc_data_send((uint8_t *) & udi_msc_inquiry_data, length); } - -static bool udi_msc_spc_testunitready_global(void) -{ +static bool udi_msc_spc_testunitready_global(void) { switch (mem_test_unit_ready(udi_msc_cbw.bCBWLUN)) { case CTRL_GOOD: return true; // Don't change sense data @@ -855,9 +809,7 @@ static bool udi_msc_spc_testunitready_global(void) return false; } - -static void udi_msc_spc_testunitready(void) -{ +static void udi_msc_spc_testunitready(void) { if (udi_msc_spc_testunitready_global()) { // LUN ready, then update sense data with status pass udi_msc_sense_pass(); @@ -866,9 +818,7 @@ static void udi_msc_spc_testunitready(void) udi_msc_csw_process(); } - -static void udi_msc_spc_mode_sense(bool b_sense10) -{ +static void udi_msc_spc_mode_sense(bool b_sense10) { // Union of all mode sense structures union sense_6_10 { struct { @@ -943,9 +893,7 @@ static void udi_msc_spc_mode_sense(bool b_sense10) udi_msc_data_send((uint8_t *) & sense, request_lgt); } - -static void udi_msc_spc_prevent_allow_medium_removal(void) -{ +static void udi_msc_spc_prevent_allow_medium_removal(void) { uint8_t prevent = udi_msc_cbw.CDB[4]; if (0 == prevent) { udi_msc_sense_pass(); @@ -955,9 +903,7 @@ static void udi_msc_spc_prevent_allow_medium_removal(void) udi_msc_csw_process(); } - -static void udi_msc_sbc_start_stop(void) -{ +static void udi_msc_sbc_start_stop(void) { bool start = 0x1 & udi_msc_cbw.CDB[4]; bool loej = 0x2 & udi_msc_cbw.CDB[4]; if (loej) { @@ -967,9 +913,7 @@ static void udi_msc_sbc_start_stop(void) udi_msc_csw_process(); } - -static void udi_msc_sbc_read_capacity(void) -{ +static void udi_msc_sbc_read_capacity(void) { UDC_BSS(4) static struct sbc_read_capacity10_data udi_msc_capacity; if (!udi_msc_cbw_validate(sizeof(udi_msc_capacity), @@ -1003,9 +947,7 @@ static void udi_msc_sbc_read_capacity(void) sizeof(udi_msc_capacity)); } - -static void udi_msc_sbc_trans(bool b_read) -{ +static void udi_msc_sbc_trans(bool b_read) { uint32_t trans_size; if (!b_read) { @@ -1038,9 +980,7 @@ static void udi_msc_sbc_trans(bool b_read) UDI_MSC_NOTIFY_TRANS_EXT(); } - -bool udi_msc_process_trans(void) -{ +bool udi_msc_process_trans(void) { Ctrl_status status; if (!udi_msc_b_trans_req) @@ -1084,10 +1024,8 @@ bool udi_msc_process_trans(void) return true; } - static void udi_msc_trans_ack(udd_ep_status_t status, iram_size_t n, - udd_ep_id_t ep) -{ + udd_ep_id_t ep) { UNUSED(ep); UNUSED(n); // Update variable to signal the end of transfer @@ -1095,10 +1033,8 @@ static void udi_msc_trans_ack(udd_ep_status_t status, iram_size_t n, udi_msc_b_ack_trans = true; } - bool udi_msc_trans_block(bool b_read, uint8_t * block, iram_size_t block_size, - void (*callback) (udd_ep_status_t status, iram_size_t n, udd_ep_id_t ep)) -{ + void (*callback) (udd_ep_status_t status, iram_size_t n, udd_ep_id_t ep)) { if (!udi_msc_b_ack_trans) return false; // No possible, transfer on going @@ -1127,6 +1063,6 @@ bool udi_msc_trans_block(bool b_read, uint8_t * block, iram_size_t block_size, //@} -#endif // SDSUPPORT +#endif // HAS_MEDIA #endif // ARDUINO_ARCH_SAM diff --git a/Marlin/src/HAL/DUE/usb/udi_msc.h b/Marlin/src/HAL/DUE/usb/udi_msc.h index 730dbc8eec..0ede4d6a83 100644 --- a/Marlin/src/HAL/DUE/usb/udi_msc.h +++ b/Marlin/src/HAL/DUE/usb/udi_msc.h @@ -77,9 +77,9 @@ extern UDC_DESC_STORAGE udi_api_t udi_api_msc; //! Interface descriptor structure for MSC typedef struct { - usb_iface_desc_t iface; - usb_ep_desc_t ep_in; - usb_ep_desc_t ep_out; + usb_iface_desc_t iface; + usb_ep_desc_t ep_in; + usb_ep_desc_t ep_out; } udi_msc_desc_t; //! By default no string associated to this interface @@ -94,32 +94,32 @@ typedef struct { //! Content of MSC interface descriptor for all speeds #define UDI_MSC_DESC \ - .iface.bLength = sizeof(usb_iface_desc_t),\ - .iface.bDescriptorType = USB_DT_INTERFACE,\ - .iface.bInterfaceNumber = UDI_MSC_IFACE_NUMBER,\ - .iface.bAlternateSetting = 0,\ - .iface.bNumEndpoints = 2,\ - .iface.bInterfaceClass = MSC_CLASS,\ - .iface.bInterfaceSubClass = MSC_SUBCLASS_TRANSPARENT,\ - .iface.bInterfaceProtocol = MSC_PROTOCOL_BULK,\ - .iface.iInterface = UDI_MSC_STRING_ID,\ - .ep_in.bLength = sizeof(usb_ep_desc_t),\ - .ep_in.bDescriptorType = USB_DT_ENDPOINT,\ - .ep_in.bEndpointAddress = UDI_MSC_EP_IN,\ - .ep_in.bmAttributes = USB_EP_TYPE_BULK,\ - .ep_in.bInterval = 0,\ - .ep_out.bLength = sizeof(usb_ep_desc_t),\ - .ep_out.bDescriptorType = USB_DT_ENDPOINT,\ - .ep_out.bEndpointAddress = UDI_MSC_EP_OUT,\ - .ep_out.bmAttributes = USB_EP_TYPE_BULK,\ - .ep_out.bInterval = 0, + .iface.bLength = sizeof(usb_iface_desc_t),\ + .iface.bDescriptorType = USB_DT_INTERFACE,\ + .iface.bInterfaceNumber = UDI_MSC_IFACE_NUMBER,\ + .iface.bAlternateSetting = 0,\ + .iface.bNumEndpoints = 2,\ + .iface.bInterfaceClass = MSC_CLASS,\ + .iface.bInterfaceSubClass = MSC_SUBCLASS_TRANSPARENT,\ + .iface.bInterfaceProtocol = MSC_PROTOCOL_BULK,\ + .iface.iInterface = UDI_MSC_STRING_ID,\ + .ep_in.bLength = sizeof(usb_ep_desc_t),\ + .ep_in.bDescriptorType = USB_DT_ENDPOINT,\ + .ep_in.bEndpointAddress = UDI_MSC_EP_IN,\ + .ep_in.bmAttributes = USB_EP_TYPE_BULK,\ + .ep_in.bInterval = 0,\ + .ep_out.bLength = sizeof(usb_ep_desc_t),\ + .ep_out.bDescriptorType = USB_DT_ENDPOINT,\ + .ep_out.bEndpointAddress = UDI_MSC_EP_OUT,\ + .ep_out.bmAttributes = USB_EP_TYPE_BULK,\ + .ep_out.bInterval = 0, //! Content of MSC interface descriptor for full speed only #define UDI_MSC_DESC_FS {\ - UDI_MSC_DESC \ - .ep_in.wMaxPacketSize = LE16(UDI_MSC_EPS_SIZE_FS),\ - .ep_out.wMaxPacketSize = LE16(UDI_MSC_EPS_SIZE_FS),\ - } + UDI_MSC_DESC \ + .ep_in.wMaxPacketSize = LE16(UDI_MSC_EPS_SIZE_FS),\ + .ep_out.wMaxPacketSize = LE16(UDI_MSC_EPS_SIZE_FS),\ + } //! Content of MSC interface descriptor for high speed only #define UDI_MSC_DESC_HS {\ @@ -129,7 +129,6 @@ typedef struct { } //@} - /** * \ingroup udi_group * \defgroup udi_msc_group USB Device Interface (UDI) for Mass Storage Class (MSC) @@ -163,14 +162,13 @@ bool udi_msc_process_trans(void); * \return \c 1 if function was successfully done, otherwise \c 0. */ bool udi_msc_trans_block(bool b_read, uint8_t * block, iram_size_t block_size, - void (*callback) (udd_ep_status_t status, iram_size_t n, udd_ep_id_t ep)); + void (*callback) (udd_ep_status_t status, iram_size_t n, udd_ep_id_t ep)); //@} #ifdef __cplusplus } #endif - /** * \page udi_msc_quickstart Quick start guide for USB device Mass Storage module (UDI MSC) * @@ -200,35 +198,32 @@ bool udi_msc_trans_block(bool b_read, uint8_t * block, iram_size_t block_size, * \subsection udi_msc_basic_use_case_usage_code Example code * Content of conf_usb.h: * \code - #define USB_DEVICE_SERIAL_NAME "12...EF" // Disk SN for MSC - #define UDI_MSC_GLOBAL_VENDOR_ID \ - 'A', 'T', 'M', 'E', 'L', ' ', ' ', ' ' - #define UDI_MSC_GLOBAL_PRODUCT_VERSION \ - '1', '.', '0', '0' - #define UDI_MSC_ENABLE_EXT() my_callback_msc_enable() - extern bool my_callback_msc_enable(void); - #define UDI_MSC_DISABLE_EXT() my_callback_msc_disable() - extern void my_callback_msc_disable(void); - #include "udi_msc_conf.h" // At the end of conf_usb.h file + #define USB_DEVICE_SERIAL_NAME "12...EF" // Disk SN for MSC + #define UDI_MSC_GLOBAL_VENDOR_ID \ + 'A', 'T', 'M', 'E', 'L', ' ', ' ', ' ' + #define UDI_MSC_GLOBAL_PRODUCT_VERSION \ + '1', '.', '0', '0' + #define UDI_MSC_ENABLE_EXT() my_callback_msc_enable() + extern bool my_callback_msc_enable(void); + #define UDI_MSC_DISABLE_EXT() my_callback_msc_disable() + extern void my_callback_msc_disable(void); + #include "udi_msc_conf.h" // At the end of conf_usb.h file \endcode * * Add to application C-file: * \code - static bool my_flag_autorize_msc_transfert = false; - bool my_callback_msc_enable(void) - { - my_flag_autorize_msc_transfert = true; - return true; - } - void my_callback_msc_disable(void) - { - my_flag_autorize_msc_transfert = false; - } + static bool my_flag_autorize_msc_transfert = false; + bool my_callback_msc_enable(void) { + my_flag_autorize_msc_transfert = true; + return true; + } + void my_callback_msc_disable(void) { + my_flag_autorize_msc_transfert = false; + } - void task(void) - { - udi_msc_process_trans(); - } + void task(void) { + udi_msc_process_trans(); + } \endcode * * \subsection udi_msc_basic_use_case_setup_flow Workflow @@ -237,14 +232,14 @@ bool udi_msc_trans_block(bool b_read, uint8_t * block, iram_size_t block_size, * - \code #define USB_DEVICE_SERIAL_NAME "12...EF" // Disk SN for MSC \endcode * \note The USB serial number is mandatory when a MSC interface is used. * - \code //! Vendor name and Product version of MSC interface - #define UDI_MSC_GLOBAL_VENDOR_ID \ - 'A', 'T', 'M', 'E', 'L', ' ', ' ', ' ' - #define UDI_MSC_GLOBAL_PRODUCT_VERSION \ - '1', '.', '0', '0' \endcode + #define UDI_MSC_GLOBAL_VENDOR_ID \ + 'A', 'T', 'M', 'E', 'L', ' ', ' ', ' ' + #define UDI_MSC_GLOBAL_PRODUCT_VERSION \ + '1', '.', '0', '0' \endcode * \note The USB MSC interface requires a vendor ID (8 ASCII characters) * and a product version (4 ASCII characters). * - \code #define UDI_MSC_ENABLE_EXT() my_callback_msc_enable() - extern bool my_callback_msc_enable(void); \endcode + extern bool my_callback_msc_enable(void); \endcode * \note After the device enumeration (detecting and identifying USB devices), * the USB host starts the device configuration. When the USB MSC interface * from the device is accepted by the host, the USB host enables this interface and the @@ -252,7 +247,7 @@ bool udi_msc_trans_block(bool b_read, uint8_t * block, iram_size_t block_size, * Thus, when this event is received, the tasks which call * udi_msc_process_trans() must be enabled. * - \code #define UDI_MSC_DISABLE_EXT() my_callback_msc_disable() - extern void my_callback_msc_disable(void); \endcode + extern void my_callback_msc_disable(void); \endcode * \note When the USB device is unplugged or is reset by the USB host, the USB * interface is disabled and the UDI_MSC_DISABLE_EXT() callback function * is called. Thus, it is recommended to disable the task which is called udi_msc_process_trans(). @@ -261,15 +256,15 @@ bool udi_msc_trans_block(bool b_read, uint8_t * block, iram_size_t block_size, * must be done outside USB interrupt routine. This is done in the MSC process * ("udi_msc_process_trans()") called by main loop: * - \code * void task(void) { - udi_msc_process_trans(); - } \endcode + udi_msc_process_trans(); + } \endcode * -# The MSC speed depends on task periodicity. To get the best speed * the notification callback "UDI_MSC_NOTIFY_TRANS_EXT" can be used to wakeup * this task (Example, through a mutex): * - \code #define UDI_MSC_NOTIFY_TRANS_EXT() msc_notify_trans() - void msc_notify_trans(void) { - wakeup_my_task(); - } \endcode + void msc_notify_trans(void) { + wakeup_my_task(); + } \endcode * * \section udi_msc_use_cases Advanced use cases * For more advanced use of the UDI MSC module, see the following use cases: @@ -302,72 +297,72 @@ bool udi_msc_trans_block(bool b_read, uint8_t * block, iram_size_t block_size, * \subsection udi_msc_use_case_composite_usage_code Example code * Content of conf_usb.h: * \code - #define USB_DEVICE_EP_CTRL_SIZE 64 - #define USB_DEVICE_NB_INTERFACE (X+1) - #define USB_DEVICE_MAX_EP (X+2) + #define USB_DEVICE_EP_CTRL_SIZE 64 + #define USB_DEVICE_NB_INTERFACE (X+1) + #define USB_DEVICE_MAX_EP (X+2) - #define UDI_MSC_EP_IN (X | USB_EP_DIR_IN) - #define UDI_MSC_EP_OUT (Y | USB_EP_DIR_OUT) - #define UDI_MSC_IFACE_NUMBER X + #define UDI_MSC_EP_IN (X | USB_EP_DIR_IN) + #define UDI_MSC_EP_OUT (Y | USB_EP_DIR_OUT) + #define UDI_MSC_IFACE_NUMBER X - #define UDI_COMPOSITE_DESC_T \ - udi_msc_desc_t udi_msc; \ - ... - #define UDI_COMPOSITE_DESC_FS \ - .udi_msc = UDI_MSC_DESC, \ - ... - #define UDI_COMPOSITE_DESC_HS \ - .udi_msc = UDI_MSC_DESC, \ - ... - #define UDI_COMPOSITE_API \ - &udi_api_msc, \ - ... + #define UDI_COMPOSITE_DESC_T \ + udi_msc_desc_t udi_msc; \ + ... + #define UDI_COMPOSITE_DESC_FS \ + .udi_msc = UDI_MSC_DESC, \ + ... + #define UDI_COMPOSITE_DESC_HS \ + .udi_msc = UDI_MSC_DESC, \ + ... + #define UDI_COMPOSITE_API \ + &udi_api_msc, \ + ... \endcode * * \subsection udi_msc_use_case_composite_usage_flow Workflow * -# Ensure that conf_usb.h is available and contains the following parameters * required for a USB composite device configuration: * - \code // Endpoint control size, This must be: - // - 8, 16, 32 or 64 for full speed device (8 is recommended to save RAM) - // - 64 for a high speed device - #define USB_DEVICE_EP_CTRL_SIZE 64 - // Total Number of interfaces on this USB device. - // Add 1 for MSC. - #define USB_DEVICE_NB_INTERFACE (X+1) - // Total number of endpoints on this USB device. - // This must include each endpoint for each interface. - // Add 2 for MSC. - #define USB_DEVICE_MAX_EP (X+2) \endcode + // - 8, 16, 32 or 64 for full speed device (8 is recommended to save RAM) + // - 64 for a high speed device + #define USB_DEVICE_EP_CTRL_SIZE 64 + // Total Number of interfaces on this USB device. + // Add 1 for MSC. + #define USB_DEVICE_NB_INTERFACE (X+1) + // Total number of endpoints on this USB device. + // This must include each endpoint for each interface. + // Add 2 for MSC. + #define USB_DEVICE_MAX_EP (X+2) \endcode * -# Ensure that conf_usb.h contains the description of * composite device: * - \code // The endpoint numbers chosen by you for the MSC. - // The endpoint numbers starting from 1. - #define UDI_MSC_EP_IN (X | USB_EP_DIR_IN) - #define UDI_MSC_EP_OUT (Y | USB_EP_DIR_OUT) - // The interface index of an interface starting from 0 - #define UDI_MSC_IFACE_NUMBER X \endcode + // The endpoint numbers starting from 1. + #define UDI_MSC_EP_IN (X | USB_EP_DIR_IN) + #define UDI_MSC_EP_OUT (Y | USB_EP_DIR_OUT) + // The interface index of an interface starting from 0 + #define UDI_MSC_IFACE_NUMBER X \endcode * -# Ensure that conf_usb.h contains the following parameters * required for a USB composite device configuration: * - \code // USB Interfaces descriptor structure - #define UDI_COMPOSITE_DESC_T \ - ... - udi_msc_desc_t udi_msc; \ - ... - // USB Interfaces descriptor value for Full Speed - #define UDI_COMPOSITE_DESC_FS \ - ... - .udi_msc = UDI_MSC_DESC_FS, \ - ... - // USB Interfaces descriptor value for High Speed - #define UDI_COMPOSITE_DESC_HS \ - ... - .udi_msc = UDI_MSC_DESC_HS, \ - ... - // USB Interface APIs - #define UDI_COMPOSITE_API \ - ... - &udi_api_msc, \ - ... \endcode + #define UDI_COMPOSITE_DESC_T \ + ... + udi_msc_desc_t udi_msc; \ + ... + // USB Interfaces descriptor value for Full Speed + #define UDI_COMPOSITE_DESC_FS \ + ... + .udi_msc = UDI_MSC_DESC_FS, \ + ... + // USB Interfaces descriptor value for High Speed + #define UDI_COMPOSITE_DESC_HS \ + ... + .udi_msc = UDI_MSC_DESC_HS, \ + ... + // USB Interface APIs + #define UDI_COMPOSITE_API \ + ... + &udi_api_msc, \ + ... \endcode * - \note The descriptors order given in the four lists above must be the * same as the order defined by all interface indexes. The interface index * orders are defined through UDI_X_IFACE_NUMBER defines. diff --git a/Marlin/src/HAL/DUE/usb/uotghs_otg.h b/Marlin/src/HAL/DUE/usb/uotghs_otg.h index eca5e938bb..f0e55c896f 100644 --- a/Marlin/src/HAL/DUE/usb/uotghs_otg.h +++ b/Marlin/src/HAL/DUE/usb/uotghs_otg.h @@ -127,13 +127,13 @@ void otg_dual_disable(void); //! These macros allows to enable/disable pad and UOTGHS hardware //! @{ //! Reset USB macro -#define otg_reset() \ - do { \ - UOTGHS->UOTGHS_CTRL = 0; \ - while( UOTGHS->UOTGHS_SR & 0x3FFF) {\ - UOTGHS->UOTGHS_SCR = 0xFFFFFFFF;\ - } \ - } while (0) +#define otg_reset() \ + do { \ + UOTGHS->UOTGHS_CTRL = 0; \ + while( UOTGHS->UOTGHS_SR & 0x3FFF) { \ + UOTGHS->UOTGHS_SCR = 0xFFFFFFFF; \ + } \ + } while (0) //! Enable USB macro #define otg_enable() (Set_bits(UOTGHS->UOTGHS_CTRL, UOTGHS_CTRL_USBE)) //! Disable USB macro @@ -157,15 +157,14 @@ void otg_dual_disable(void); //! Configure time-out of specified OTG timer #define otg_configure_timeout(timer, timeout) (Set_bits(UOTGHS->UOTGHS_CTRL, UOTGHS_CTRL_UNLOCK),\ - Wr_bitfield(UOTGHS->UOTGHS_CTRL, UOTGHS_CTRL_TIMPAGE_Msk, timer),\ - Wr_bitfield(UOTGHS->UOTGHS_CTRL, UOTGHS_CTRL_TIMVALUE_Msk, timeout),\ - Clr_bits(UOTGHS->UOTGHS_CTRL, UOTGHS_CTRL_UNLOCK)) + Wr_bitfield(UOTGHS->UOTGHS_CTRL, UOTGHS_CTRL_TIMPAGE_Msk, timer),\ + Wr_bitfield(UOTGHS->UOTGHS_CTRL, UOTGHS_CTRL_TIMVALUE_Msk, timeout),\ + Clr_bits(UOTGHS->UOTGHS_CTRL, UOTGHS_CTRL_UNLOCK)) //! Get configured time-out of specified OTG timer #define otg_get_timeout(timer) (Set_bits(UOTGHS->UOTGHS_CTRL, UOTGHS_CTRL_UNLOCK),\ - Wr_bitfield(UOTGHS->UOTGHS_CTRL, UOTGHS_CTRL_TIMPAGE_Msk, timer),\ - Clr_bits(UOTGHS->UOTGHS_CTRL, UOTGHS_CTRL_UNLOCK),\ - Rd_bitfield(UOTGHS->UOTGHS_CTRL, UOTGHS_CTRL_TIMVALUE_Msk)) - + Wr_bitfield(UOTGHS->UOTGHS_CTRL, UOTGHS_CTRL_TIMPAGE_Msk, timer),\ + Clr_bits(UOTGHS->UOTGHS_CTRL, UOTGHS_CTRL_UNLOCK),\ + Rd_bitfield(UOTGHS->UOTGHS_CTRL, UOTGHS_CTRL_TIMVALUE_Msk)) //! Get the dual-role device state of the internal USB finite state machine of the UOTGHS controller #define otg_get_fsm_drd_state() (Rd_bitfield(UOTGHS->UOTGHS_FSM, UOTGHS_FSM_DRDSTATE_Msk)) diff --git a/Marlin/src/HAL/DUE/usb/usb_protocol.h b/Marlin/src/HAL/DUE/usb/usb_protocol.h index ea51a86896..4540247df8 100644 --- a/Marlin/src/HAL/DUE/usb/usb_protocol.h +++ b/Marlin/src/HAL/DUE/usb/usb_protocol.h @@ -108,17 +108,17 @@ * \brief Standard USB requests (bRequest) */ enum usb_reqid { - USB_REQ_GET_STATUS = 0, - USB_REQ_CLEAR_FEATURE = 1, - USB_REQ_SET_FEATURE = 3, - USB_REQ_SET_ADDRESS = 5, - USB_REQ_GET_DESCRIPTOR = 6, - USB_REQ_SET_DESCRIPTOR = 7, - USB_REQ_GET_CONFIGURATION = 8, - USB_REQ_SET_CONFIGURATION = 9, - USB_REQ_GET_INTERFACE = 10, - USB_REQ_SET_INTERFACE = 11, - USB_REQ_SYNCH_FRAME = 12, + USB_REQ_GET_STATUS = 0, + USB_REQ_CLEAR_FEATURE = 1, + USB_REQ_SET_FEATURE = 3, + USB_REQ_SET_ADDRESS = 5, + USB_REQ_GET_DESCRIPTOR = 6, + USB_REQ_SET_DESCRIPTOR = 7, + USB_REQ_GET_CONFIGURATION = 8, + USB_REQ_SET_CONFIGURATION = 9, + USB_REQ_GET_INTERFACE = 10, + USB_REQ_SET_INTERFACE = 11, + USB_REQ_SYNCH_FRAME = 12, }; /** @@ -126,9 +126,9 @@ enum usb_reqid { * */ enum usb_device_status { - USB_DEV_STATUS_BUS_POWERED = 0, - USB_DEV_STATUS_SELF_POWERED = 1, - USB_DEV_STATUS_REMOTEWAKEUP = 2 + USB_DEV_STATUS_BUS_POWERED = 0, + USB_DEV_STATUS_SELF_POWERED = 1, + USB_DEV_STATUS_REMOTEWAKEUP = 2 }; /** @@ -136,7 +136,7 @@ enum usb_device_status { * */ enum usb_interface_status { - USB_IFACE_STATUS_RESERVED = 0 + USB_IFACE_STATUS_RESERVED = 0 }; /** @@ -144,7 +144,7 @@ enum usb_interface_status { * */ enum usb_endpoint_status { - USB_EP_STATUS_HALTED = 1, + USB_EP_STATUS_HALTED = 1, }; /** @@ -153,11 +153,11 @@ enum usb_endpoint_status { * \note valid for SetFeature request. */ enum usb_device_feature { - USB_DEV_FEATURE_REMOTE_WAKEUP = 1, //!< Remote wakeup enabled - USB_DEV_FEATURE_TEST_MODE = 2, //!< USB test mode - USB_DEV_FEATURE_OTG_B_HNP_ENABLE = 3, - USB_DEV_FEATURE_OTG_A_HNP_SUPPORT = 4, - USB_DEV_FEATURE_OTG_A_ALT_HNP_SUPPORT = 5 + USB_DEV_FEATURE_REMOTE_WAKEUP = 1, //!< Remote wakeup enabled + USB_DEV_FEATURE_TEST_MODE = 2, //!< USB test mode + USB_DEV_FEATURE_OTG_B_HNP_ENABLE = 3, + USB_DEV_FEATURE_OTG_A_HNP_SUPPORT = 4, + USB_DEV_FEATURE_OTG_A_ALT_HNP_SUPPORT = 5 }; /** @@ -166,54 +166,54 @@ enum usb_device_feature { * \note valid for USB_DEV_FEATURE_TEST_MODE request. */ enum usb_device_hs_test_mode { - USB_DEV_TEST_MODE_J = 1, - USB_DEV_TEST_MODE_K = 2, - USB_DEV_TEST_MODE_SE0_NAK = 3, - USB_DEV_TEST_MODE_PACKET = 4, - USB_DEV_TEST_MODE_FORCE_ENABLE = 5, + USB_DEV_TEST_MODE_J = 1, + USB_DEV_TEST_MODE_K = 2, + USB_DEV_TEST_MODE_SE0_NAK = 3, + USB_DEV_TEST_MODE_PACKET = 4, + USB_DEV_TEST_MODE_FORCE_ENABLE = 5, }; /** * \brief Standard USB endpoint feature/status flags */ enum usb_endpoint_feature { - USB_EP_FEATURE_HALT = 0, + USB_EP_FEATURE_HALT = 0, }; /** * \brief Standard USB Test Mode Selectors */ enum usb_test_mode_selector { - USB_TEST_J = 0x01, - USB_TEST_K = 0x02, - USB_TEST_SE0_NAK = 0x03, - USB_TEST_PACKET = 0x04, - USB_TEST_FORCE_ENABLE = 0x05, + USB_TEST_J = 0x01, + USB_TEST_K = 0x02, + USB_TEST_SE0_NAK = 0x03, + USB_TEST_PACKET = 0x04, + USB_TEST_FORCE_ENABLE = 0x05, }; /** * \brief Standard USB descriptor types */ enum usb_descriptor_type { - USB_DT_DEVICE = 1, - USB_DT_CONFIGURATION = 2, - USB_DT_STRING = 3, - USB_DT_INTERFACE = 4, - USB_DT_ENDPOINT = 5, - USB_DT_DEVICE_QUALIFIER = 6, - USB_DT_OTHER_SPEED_CONFIGURATION = 7, - USB_DT_INTERFACE_POWER = 8, - USB_DT_OTG = 9, - USB_DT_IAD = 0x0B, - USB_DT_BOS = 0x0F, - USB_DT_DEVICE_CAPABILITY = 0x10, + USB_DT_DEVICE = 1, + USB_DT_CONFIGURATION = 2, + USB_DT_STRING = 3, + USB_DT_INTERFACE = 4, + USB_DT_ENDPOINT = 5, + USB_DT_DEVICE_QUALIFIER = 6, + USB_DT_OTHER_SPEED_CONFIGURATION = 7, + USB_DT_INTERFACE_POWER = 8, + USB_DT_OTG = 9, + USB_DT_IAD = 0x0B, + USB_DT_BOS = 0x0F, + USB_DT_DEVICE_CAPABILITY = 0x10, }; /** * \brief USB Device Capability types */ enum usb_capability_type { - USB_DC_USB20_EXTENSION = 0x02, + USB_DC_USB20_EXTENSION = 0x02, }; /** @@ -221,7 +221,7 @@ enum usb_capability_type { * To fill bmAttributes field of usb_capa_ext_desc_t structure. */ enum usb_capability_extension_attr { - USB_DC_EXT_LPM = 0x00000002, + USB_DC_EXT_LPM = 0x00000002, }; #define HIRD_50_US 0 @@ -254,18 +254,18 @@ enum usb_capability_extension_attr { * \brief Standard USB endpoint transfer types */ enum usb_ep_type { - USB_EP_TYPE_CONTROL = 0x00, - USB_EP_TYPE_ISOCHRONOUS = 0x01, - USB_EP_TYPE_BULK = 0x02, - USB_EP_TYPE_INTERRUPT = 0x03, - USB_EP_TYPE_MASK = 0x03, + USB_EP_TYPE_CONTROL = 0x00, + USB_EP_TYPE_ISOCHRONOUS = 0x01, + USB_EP_TYPE_BULK = 0x02, + USB_EP_TYPE_INTERRUPT = 0x03, + USB_EP_TYPE_MASK = 0x03, }; /** * \brief Standard USB language IDs for string descriptors */ enum usb_langid { - USB_LANGID_EN_US = 0x0409, //!< English (United States) + USB_LANGID_EN_US = 0x0409, //!< English (United States) }; /** @@ -308,31 +308,31 @@ COMPILER_PACK_SET(1) * The data payload of SETUP packets always follows this structure. */ typedef struct { - uint8_t bmRequestType; - uint8_t bRequest; - le16_t wValue; - le16_t wIndex; - le16_t wLength; + uint8_t bmRequestType; + uint8_t bRequest; + le16_t wValue; + le16_t wIndex; + le16_t wLength; } usb_setup_req_t; /** * \brief Standard USB device descriptor structure */ typedef struct { - uint8_t bLength; - uint8_t bDescriptorType; - le16_t bcdUSB; - uint8_t bDeviceClass; - uint8_t bDeviceSubClass; - uint8_t bDeviceProtocol; - uint8_t bMaxPacketSize0; - le16_t idVendor; - le16_t idProduct; - le16_t bcdDevice; - uint8_t iManufacturer; - uint8_t iProduct; - uint8_t iSerialNumber; - uint8_t bNumConfigurations; + uint8_t bLength; + uint8_t bDescriptorType; + le16_t bcdUSB; + uint8_t bDeviceClass; + uint8_t bDeviceSubClass; + uint8_t bDeviceProtocol; + uint8_t bMaxPacketSize0; + le16_t idVendor; + le16_t idProduct; + le16_t bcdDevice; + uint8_t iManufacturer; + uint8_t iProduct; + uint8_t iSerialNumber; + uint8_t bNumConfigurations; } usb_dev_desc_t; /** @@ -344,15 +344,15 @@ typedef struct { * the device was operating at full speed.) */ typedef struct { - uint8_t bLength; - uint8_t bDescriptorType; - le16_t bcdUSB; - uint8_t bDeviceClass; - uint8_t bDeviceSubClass; - uint8_t bDeviceProtocol; - uint8_t bMaxPacketSize0; - uint8_t bNumConfigurations; - uint8_t bReserved; + uint8_t bLength; + uint8_t bDescriptorType; + le16_t bcdUSB; + uint8_t bDeviceClass; + uint8_t bDeviceSubClass; + uint8_t bDeviceProtocol; + uint8_t bMaxPacketSize0; + uint8_t bNumConfigurations; + uint8_t bReserved; } usb_dev_qual_desc_t; /** @@ -368,10 +368,10 @@ typedef struct { * The descriptor type in the GetDescriptor() request is set to BOS. */ typedef struct { - uint8_t bLength; - uint8_t bDescriptorType; - le16_t wTotalLength; - uint8_t bNumDeviceCaps; + uint8_t bLength; + uint8_t bDescriptorType; + le16_t wTotalLength; + uint8_t bNumDeviceCaps; } usb_dev_bos_desc_t; @@ -381,10 +381,10 @@ typedef struct { * Defines the set of USB 1.1-specific device level capabilities. */ typedef struct { - uint8_t bLength; - uint8_t bDescriptorType; - uint8_t bDevCapabilityType; - le32_t bmAttributes; + uint8_t bLength; + uint8_t bDescriptorType; + uint8_t bDevCapabilityType; + le32_t bmAttributes; } usb_dev_capa_ext_desc_t; /** @@ -393,22 +393,22 @@ typedef struct { * The BOS descriptor and capabilities descriptors for LPM. */ typedef struct { - usb_dev_bos_desc_t bos; - usb_dev_capa_ext_desc_t capa_ext; + usb_dev_bos_desc_t bos; + usb_dev_capa_ext_desc_t capa_ext; } usb_dev_lpm_desc_t; /** * \brief Standard USB Interface Association Descriptor structure */ typedef struct { - uint8_t bLength; //!< size of this descriptor in bytes - uint8_t bDescriptorType; //!< INTERFACE descriptor type - uint8_t bFirstInterface; //!< Number of interface - uint8_t bInterfaceCount; //!< value to select alternate setting - uint8_t bFunctionClass; //!< Class code assigned by the USB - uint8_t bFunctionSubClass;//!< Sub-class code assigned by the USB - uint8_t bFunctionProtocol;//!< Protocol code assigned by the USB - uint8_t iFunction; //!< Index of string descriptor + uint8_t bLength; //!< size of this descriptor in bytes + uint8_t bDescriptorType; //!< INTERFACE descriptor type + uint8_t bFirstInterface; //!< Number of interface + uint8_t bInterfaceCount; //!< value to select alternate setting + uint8_t bFunctionClass; //!< Class code assigned by the USB + uint8_t bFunctionSubClass;//!< Sub-class code assigned by the USB + uint8_t bFunctionProtocol;//!< Protocol code assigned by the USB + uint8_t iFunction; //!< Index of string descriptor } usb_association_desc_t; @@ -416,14 +416,14 @@ typedef struct { * \brief Standard USB configuration descriptor structure */ typedef struct { - uint8_t bLength; - uint8_t bDescriptorType; - le16_t wTotalLength; - uint8_t bNumInterfaces; - uint8_t bConfigurationValue; - uint8_t iConfiguration; - uint8_t bmAttributes; - uint8_t bMaxPower; + uint8_t bLength; + uint8_t bDescriptorType; + le16_t wTotalLength; + uint8_t bNumInterfaces; + uint8_t bConfigurationValue; + uint8_t iConfiguration; + uint8_t bmAttributes; + uint8_t bMaxPower; } usb_conf_desc_t; @@ -438,41 +438,41 @@ typedef struct { * \brief Standard USB association descriptor structure */ typedef struct { - uint8_t bLength; //!< Size of this descriptor in bytes - uint8_t bDescriptorType; //!< Interface descriptor type - uint8_t bFirstInterface; //!< Number of interface - uint8_t bInterfaceCount; //!< value to select alternate setting - uint8_t bFunctionClass; //!< Class code assigned by the USB - uint8_t bFunctionSubClass; //!< Sub-class code assigned by the USB - uint8_t bFunctionProtocol; //!< Protocol code assigned by the USB - uint8_t iFunction; //!< Index of string descriptor + uint8_t bLength; //!< Size of this descriptor in bytes + uint8_t bDescriptorType; //!< Interface descriptor type + uint8_t bFirstInterface; //!< Number of interface + uint8_t bInterfaceCount; //!< value to select alternate setting + uint8_t bFunctionClass; //!< Class code assigned by the USB + uint8_t bFunctionSubClass; //!< Sub-class code assigned by the USB + uint8_t bFunctionProtocol; //!< Protocol code assigned by the USB + uint8_t iFunction; //!< Index of string descriptor } usb_iad_desc_t; /** * \brief Standard USB interface descriptor structure */ typedef struct { - uint8_t bLength; - uint8_t bDescriptorType; - uint8_t bInterfaceNumber; - uint8_t bAlternateSetting; - uint8_t bNumEndpoints; - uint8_t bInterfaceClass; - uint8_t bInterfaceSubClass; - uint8_t bInterfaceProtocol; - uint8_t iInterface; + uint8_t bLength; + uint8_t bDescriptorType; + uint8_t bInterfaceNumber; + uint8_t bAlternateSetting; + uint8_t bNumEndpoints; + uint8_t bInterfaceClass; + uint8_t bInterfaceSubClass; + uint8_t bInterfaceProtocol; + uint8_t iInterface; } usb_iface_desc_t; /** * \brief Standard USB endpoint descriptor structure */ typedef struct { - uint8_t bLength; - uint8_t bDescriptorType; - uint8_t bEndpointAddress; - uint8_t bmAttributes; - le16_t wMaxPacketSize; - uint8_t bInterval; + uint8_t bLength; + uint8_t bDescriptorType; + uint8_t bEndpointAddress; + uint8_t bmAttributes; + le16_t wMaxPacketSize; + uint8_t bInterval; } usb_ep_desc_t; @@ -480,13 +480,13 @@ typedef struct { * \brief A standard USB string descriptor structure */ typedef struct { - uint8_t bLength; - uint8_t bDescriptorType; + uint8_t bLength; + uint8_t bDescriptorType; } usb_str_desc_t; typedef struct { - usb_str_desc_t desc; - le16_t string[1]; + usb_str_desc_t desc; + le16_t string[1]; } usb_str_lgid_desc_t; COMPILER_PACK_RESET() diff --git a/Marlin/src/HAL/DUE/usb/usb_protocol_cdc.h b/Marlin/src/HAL/DUE/usb/usb_protocol_cdc.h index d594db52e3..9b82afc624 100644 --- a/Marlin/src/HAL/DUE/usb/usb_protocol_cdc.h +++ b/Marlin/src/HAL/DUE/usb/usb_protocol_cdc.h @@ -58,42 +58,42 @@ * \name Possible values of class */ //@{ -#define CDC_CLASS_DEVICE 0x02 //!< USB Communication Device Class -#define CDC_CLASS_COMM 0x02 //!< CDC Communication Class Interface -#define CDC_CLASS_DATA 0x0A //!< CDC Data Class Interface +#define CDC_CLASS_DEVICE 0x02 //!< USB Communication Device Class +#define CDC_CLASS_COMM 0x02 //!< CDC Communication Class Interface +#define CDC_CLASS_DATA 0x0A //!< CDC Data Class Interface #define CDC_CLASS_MULTI 0xEF //!< CDC Multi-interface Function //@} //! \name USB CDC Subclass IDs //@{ -#define CDC_SUBCLASS_DLCM 0x01 //!< Direct Line Control Model -#define CDC_SUBCLASS_ACM 0x02 //!< Abstract Control Model -#define CDC_SUBCLASS_TCM 0x03 //!< Telephone Control Model -#define CDC_SUBCLASS_MCCM 0x04 //!< Multi-Channel Control Model -#define CDC_SUBCLASS_CCM 0x05 //!< CAPI Control Model -#define CDC_SUBCLASS_ETH 0x06 //!< Ethernet Networking Control Model -#define CDC_SUBCLASS_ATM 0x07 //!< ATM Networking Control Model +#define CDC_SUBCLASS_DLCM 0x01 //!< Direct Line Control Model +#define CDC_SUBCLASS_ACM 0x02 //!< Abstract Control Model +#define CDC_SUBCLASS_TCM 0x03 //!< Telephone Control Model +#define CDC_SUBCLASS_MCCM 0x04 //!< Multi-Channel Control Model +#define CDC_SUBCLASS_CCM 0x05 //!< CAPI Control Model +#define CDC_SUBCLASS_ETH 0x06 //!< Ethernet Networking Control Model +#define CDC_SUBCLASS_ATM 0x07 //!< ATM Networking Control Model //@} //! \name USB CDC Communication Interface Protocol IDs //@{ -#define CDC_PROTOCOL_V25TER 0x01 //!< Common AT commands +#define CDC_PROTOCOL_V25TER 0x01 //!< Common AT commands //@} //! \name USB CDC Data Interface Protocol IDs //@{ -#define CDC_PROTOCOL_I430 0x30 //!< ISDN BRI -#define CDC_PROTOCOL_HDLC 0x31 //!< HDLC -#define CDC_PROTOCOL_TRANS 0x32 //!< Transparent -#define CDC_PROTOCOL_Q921M 0x50 //!< Q.921 management protocol -#define CDC_PROTOCOL_Q921 0x51 //!< Q.931 [sic] Data link protocol -#define CDC_PROTOCOL_Q921TM 0x52 //!< Q.921 TEI-multiplexor -#define CDC_PROTOCOL_V42BIS 0x90 //!< Data compression procedures -#define CDC_PROTOCOL_Q931 0x91 //!< Euro-ISDN protocol control -#define CDC_PROTOCOL_V120 0x92 //!< V.24 rate adaption to ISDN -#define CDC_PROTOCOL_CAPI20 0x93 //!< CAPI Commands -#define CDC_PROTOCOL_HOST 0xFD //!< Host based driver +#define CDC_PROTOCOL_I430 0x30 //!< ISDN BRI +#define CDC_PROTOCOL_HDLC 0x31 //!< HDLC +#define CDC_PROTOCOL_TRANS 0x32 //!< Transparent +#define CDC_PROTOCOL_Q921M 0x50 //!< Q.921 management protocol +#define CDC_PROTOCOL_Q921 0x51 //!< Q.931 [sic] Data link protocol +#define CDC_PROTOCOL_Q921TM 0x52 //!< Q.921 TEI-multiplexor +#define CDC_PROTOCOL_V42BIS 0x90 //!< Data compression procedures +#define CDC_PROTOCOL_Q931 0x91 //!< Euro-ISDN protocol control +#define CDC_PROTOCOL_V120 0x92 //!< V.24 rate adaption to ISDN +#define CDC_PROTOCOL_CAPI20 0x93 //!< CAPI Commands +#define CDC_PROTOCOL_HOST 0xFD //!< Host based driver /** * \brief Describes the Protocol Unit Functional Descriptors [sic] * on Communication Class Interface @@ -103,16 +103,16 @@ //! \name USB CDC Functional Descriptor Types //@{ -#define CDC_CS_INTERFACE 0x24 //!< Interface Functional Descriptor -#define CDC_CS_ENDPOINT 0x25 //!< Endpoint Functional Descriptor +#define CDC_CS_INTERFACE 0x24 //!< Interface Functional Descriptor +#define CDC_CS_ENDPOINT 0x25 //!< Endpoint Functional Descriptor //@} //! \name USB CDC Functional Descriptor Subtypes //@{ -#define CDC_SCS_HEADER 0x00 //!< Header Functional Descriptor -#define CDC_SCS_CALL_MGMT 0x01 //!< Call Management -#define CDC_SCS_ACM 0x02 //!< Abstract Control Management -#define CDC_SCS_UNION 0x06 //!< Union Functional Descriptor +#define CDC_SCS_HEADER 0x00 //!< Header Functional Descriptor +#define CDC_SCS_CALL_MGMT 0x01 //!< Call Management +#define CDC_SCS_ACM 0x02 //!< Abstract Control Management +#define CDC_SCS_UNION 0x06 //!< Union Functional Descriptor //@} //! \name USB CDC Request IDs @@ -171,36 +171,36 @@ COMPILER_PACK_SET(1) //! CDC Header Functional Descriptor typedef struct { - uint8_t bFunctionLength; - uint8_t bDescriptorType; - uint8_t bDescriptorSubtype; - le16_t bcdCDC; + uint8_t bFunctionLength; + uint8_t bDescriptorType; + uint8_t bDescriptorSubtype; + le16_t bcdCDC; } usb_cdc_hdr_desc_t; //! CDC Call Management Functional Descriptor typedef struct { - uint8_t bFunctionLength; - uint8_t bDescriptorType; - uint8_t bDescriptorSubtype; - uint8_t bmCapabilities; - uint8_t bDataInterface; + uint8_t bFunctionLength; + uint8_t bDescriptorType; + uint8_t bDescriptorSubtype; + uint8_t bmCapabilities; + uint8_t bDataInterface; } usb_cdc_call_mgmt_desc_t; //! CDC ACM Functional Descriptor typedef struct { - uint8_t bFunctionLength; - uint8_t bDescriptorType; - uint8_t bDescriptorSubtype; - uint8_t bmCapabilities; + uint8_t bFunctionLength; + uint8_t bDescriptorType; + uint8_t bDescriptorSubtype; + uint8_t bmCapabilities; } usb_cdc_acm_desc_t; //! CDC Union Functional Descriptor typedef struct { - uint8_t bFunctionLength; - uint8_t bDescriptorType; - uint8_t bDescriptorSubtype; - uint8_t bMasterInterface; - uint8_t bSlaveInterface0; + uint8_t bFunctionLength; + uint8_t bDescriptorType; + uint8_t bDescriptorSubtype; + uint8_t bMasterInterface; + uint8_t bSlaveInterface0; } usb_cdc_union_desc_t; @@ -235,24 +235,24 @@ typedef struct { //@{ //! Line Coding structure typedef struct { - le32_t dwDTERate; - uint8_t bCharFormat; - uint8_t bParityType; - uint8_t bDataBits; + le32_t dwDTERate; + uint8_t bCharFormat; + uint8_t bParityType; + uint8_t bDataBits; } usb_cdc_line_coding_t; //! Possible values of bCharFormat enum cdc_char_format { - CDC_STOP_BITS_1 = 0, //!< 1 stop bit - CDC_STOP_BITS_1_5 = 1, //!< 1.5 stop bits - CDC_STOP_BITS_2 = 2, //!< 2 stop bits + CDC_STOP_BITS_1 = 0, //!< 1 stop bit + CDC_STOP_BITS_1_5 = 1, //!< 1.5 stop bits + CDC_STOP_BITS_2 = 2, //!< 2 stop bits }; //! Possible values of bParityType enum cdc_parity { - CDC_PAR_NONE = 0, //!< No parity - CDC_PAR_ODD = 1, //!< Odd parity - CDC_PAR_EVEN = 2, //!< Even parity - CDC_PAR_MARK = 3, //!< Parity forced to 0 (space) - CDC_PAR_SPACE = 4, //!< Parity forced to 1 (mark) + CDC_PAR_NONE = 0, //!< No parity + CDC_PAR_ODD = 1, //!< Odd parity + CDC_PAR_EVEN = 2, //!< Even parity + CDC_PAR_MARK = 3, //!< Parity forced to 0 (space) + CDC_PAR_SPACE = 4, //!< Parity forced to 1 (mark) }; //@} @@ -262,7 +262,7 @@ enum cdc_parity { //! Control signal structure typedef struct { - uint16_t value; + uint16_t value; } usb_cdc_control_signal_t; //! \name Possible values in usb_cdc_control_signal_t @@ -283,11 +283,11 @@ typedef struct { //@{ typedef struct { - uint8_t bmRequestType; - uint8_t bNotification; - le16_t wValue; - le16_t wIndex; - le16_t wLength; + uint8_t bmRequestType; + uint8_t bNotification; + le16_t wValue; + le16_t wIndex; + le16_t wLength; } usb_cdc_notify_msg_t; //! \name USB CDC serial state @@ -295,8 +295,8 @@ typedef struct { //! Hardware handshake support (cdc spec 1.1 chapter 6.3.5) typedef struct { - usb_cdc_notify_msg_t header; - le16_t value; + usb_cdc_notify_msg_t header; + le16_t value; } usb_cdc_notify_serial_state_t; //! \name Possible values in usb_cdc_notify_serial_state_t diff --git a/Marlin/src/HAL/DUE/usb/usb_protocol_msc.h b/Marlin/src/HAL/DUE/usb/usb_protocol_msc.h index e1e59237d8..cc30a94e4f 100644 --- a/Marlin/src/HAL/DUE/usb/usb_protocol_msc.h +++ b/Marlin/src/HAL/DUE/usb/usb_protocol_msc.h @@ -59,7 +59,7 @@ * \name Possible Class value */ //@{ -#define MSC_CLASS 0x08 +#define MSC_CLASS 0x08 //@} /** @@ -71,12 +71,12 @@ * operating systems like Windows XP. */ //@{ -#define MSC_SUBCLASS_RBC 0x01 //!< Reduced Block Commands -#define MSC_SUBCLASS_ATAPI 0x02 //!< CD/DVD devices -#define MSC_SUBCLASS_QIC_157 0x03 //!< Tape devices -#define MSC_SUBCLASS_UFI 0x04 //!< Floppy disk drives -#define MSC_SUBCLASS_SFF_8070I 0x05 //!< Floppy disk drives -#define MSC_SUBCLASS_TRANSPARENT 0x06 //!< Determined by INQUIRY +#define MSC_SUBCLASS_RBC 0x01 //!< Reduced Block Commands +#define MSC_SUBCLASS_ATAPI 0x02 //!< CD/DVD devices +#define MSC_SUBCLASS_QIC_157 0x03 //!< Tape devices +#define MSC_SUBCLASS_UFI 0x04 //!< Floppy disk drives +#define MSC_SUBCLASS_SFF_8070I 0x05 //!< Floppy disk drives +#define MSC_SUBCLASS_TRANSPARENT 0x06 //!< Determined by INQUIRY //@} /** @@ -84,9 +84,9 @@ * \note Only the BULK protocol should be used in new designs. */ //@{ -#define MSC_PROTOCOL_CBI 0x00 //!< Command/Bulk/Interrupt -#define MSC_PROTOCOL_CBI_ALT 0x01 //!< W/o command completion -#define MSC_PROTOCOL_BULK 0x50 //!< Bulk-only +#define MSC_PROTOCOL_CBI 0x00 //!< Command/Bulk/Interrupt +#define MSC_PROTOCOL_CBI_ALT 0x01 //!< W/o command completion +#define MSC_PROTOCOL_BULK 0x50 //!< Bulk-only //@} @@ -94,8 +94,8 @@ * \brief MSC USB requests (bRequest) */ enum usb_reqid_msc { - USB_REQ_MSC_BULK_RESET = 0xFF, //!< Mass Storage Reset - USB_REQ_MSC_GET_MAX_LUN = 0xFE //!< Get Max LUN + USB_REQ_MSC_BULK_RESET = 0xFF, //!< Mass Storage Reset + USB_REQ_MSC_GET_MAX_LUN = 0xFE //!< Get Max LUN }; @@ -106,20 +106,20 @@ COMPILER_PACK_SET(1) */ //@{ struct usb_msc_cbw { - le32_t dCBWSignature; //!< Must contain 'USBC' - le32_t dCBWTag; //!< Unique command ID - le32_t dCBWDataTransferLength; //!< Number of bytes to transfer - uint8_t bmCBWFlags; //!< Direction in bit 7 - uint8_t bCBWLUN; //!< Logical Unit Number - uint8_t bCBWCBLength; //!< Number of valid CDB bytes - uint8_t CDB[16]; //!< SCSI Command Descriptor Block + le32_t dCBWSignature; //!< Must contain 'USBC' + le32_t dCBWTag; //!< Unique command ID + le32_t dCBWDataTransferLength; //!< Number of bytes to transfer + uint8_t bmCBWFlags; //!< Direction in bit 7 + uint8_t bCBWLUN; //!< Logical Unit Number + uint8_t bCBWCBLength; //!< Number of valid CDB bytes + uint8_t CDB[16]; //!< SCSI Command Descriptor Block }; -#define USB_CBW_SIGNATURE 0x55534243 //!< dCBWSignature value -#define USB_CBW_DIRECTION_IN (1<<7) //!< Data from device to host -#define USB_CBW_DIRECTION_OUT (0<<7) //!< Data from host to device -#define USB_CBW_LUN_MASK 0x0F //!< Valid bits in bCBWLUN -#define USB_CBW_LEN_MASK 0x1F //!< Valid bits in bCBWCBLength +#define USB_CBW_SIGNATURE 0x55534243 //!< dCBWSignature value +#define USB_CBW_DIRECTION_IN (1<<7) //!< Data from device to host +#define USB_CBW_DIRECTION_OUT (0<<7) //!< Data from host to device +#define USB_CBW_LUN_MASK 0x0F //!< Valid bits in bCBWLUN +#define USB_CBW_LEN_MASK 0x1F //!< Valid bits in bCBWCBLength //@} @@ -128,16 +128,16 @@ struct usb_msc_cbw { */ //@{ struct usb_msc_csw { - le32_t dCSWSignature; //!< Must contain 'USBS' - le32_t dCSWTag; //!< Same as dCBWTag - le32_t dCSWDataResidue; //!< Number of bytes not transferred - uint8_t bCSWStatus; //!< Status code + le32_t dCSWSignature; //!< Must contain 'USBS' + le32_t dCSWTag; //!< Same as dCBWTag + le32_t dCSWDataResidue; //!< Number of bytes not transferred + uint8_t bCSWStatus; //!< Status code }; -#define USB_CSW_SIGNATURE 0x55534253 //!< dCSWSignature value -#define USB_CSW_STATUS_PASS 0x00 //!< Command Passed -#define USB_CSW_STATUS_FAIL 0x01 //!< Command Failed -#define USB_CSW_STATUS_PE 0x02 //!< Phase Error +#define USB_CSW_SIGNATURE 0x55534253 //!< dCSWSignature value +#define USB_CSW_STATUS_PASS 0x00 //!< Command Passed +#define USB_CSW_STATUS_FAIL 0x01 //!< Command Failed +#define USB_CSW_STATUS_PE 0x02 //!< Phase Error //@} COMPILER_PACK_RESET() diff --git a/Marlin/src/HAL/DUE/usb/usb_task.c b/Marlin/src/HAL/DUE/usb/usb_task.c index 86ab27217a..6f027f83a1 100644 --- a/Marlin/src/HAL/DUE/usb/usb_task.c +++ b/Marlin/src/HAL/DUE/usb/usb_task.c @@ -51,14 +51,14 @@ #include "conf_usb.h" #include "udc.h" -#if ENABLED(SDSUPPORT) +#if HAS_MEDIA static volatile bool main_b_msc_enable = false; #endif static volatile bool main_b_cdc_enable = false; static volatile bool main_b_dtr_active = false; void usb_task_idle(void) { - #if ENABLED(SDSUPPORT) + #if HAS_MEDIA // Attend SD card access from the USB MSD -- Prioritize access to improve speed int delay = 2; while (main_b_msc_enable && --delay > 0) { @@ -70,7 +70,7 @@ void usb_task_idle(void) { #endif } -#if ENABLED(SDSUPPORT) +#if HAS_MEDIA bool usb_task_msc_enable(void) { return ((main_b_msc_enable = true)); } void usb_task_msc_disable(void) { main_b_msc_enable = false; } bool usb_task_msc_isenabled(void) { return main_b_msc_enable; } @@ -206,13 +206,13 @@ static USB_MicrosoftExtendedPropertiesDescriptor microsoft_extended_properties_d bool usb_task_extra_string(void) { static uint8_t udi_msft_magic[] = "MSFT100\xEE"; static uint8_t udi_cdc_name[] = "CDC interface"; - #if ENABLED(SDSUPPORT) + #if HAS_MEDIA static uint8_t udi_msc_name[] = "MSC interface"; #endif struct extra_strings_desc_t { usb_str_desc_t header; - #if ENABLED(SDSUPPORT) + #if HAS_MEDIA le16_t string[Max(Max(sizeof(udi_cdc_name) - 1, sizeof(udi_msc_name) - 1), sizeof(udi_msft_magic) - 1)]; #else le16_t string[Max(sizeof(udi_cdc_name) - 1, sizeof(udi_msft_magic) - 1)]; @@ -231,7 +231,7 @@ bool usb_task_extra_string(void) { str_lgt = sizeof(udi_cdc_name) - 1; str = udi_cdc_name; break; - #if ENABLED(SDSUPPORT) + #if HAS_MEDIA case UDI_MSC_STRING_ID: str_lgt = sizeof(udi_msc_name) - 1; str = udi_msc_name; diff --git a/Marlin/src/HAL/ESP32/HAL.cpp b/Marlin/src/HAL/ESP32/HAL.cpp index 29f3be3c02..4890972b01 100644 --- a/Marlin/src/HAL/ESP32/HAL.cpp +++ b/Marlin/src/HAL/ESP32/HAL.cpp @@ -165,7 +165,7 @@ void MarlinHAL::init_board() { } void MarlinHAL::idletask() { - #if BOTH(WIFISUPPORT, OTASUPPORT) + #if ALL(WIFISUPPORT, OTASUPPORT) OTA_handle(); #endif TERN_(ESP3D_WIFISUPPORT, esp3dlib.idletask()); @@ -175,7 +175,7 @@ uint8_t MarlinHAL::get_reset_source() { return rtc_get_reset_reason(1); } void MarlinHAL::reboot() { ESP.restart(); } -void _delay_ms(int delay_ms) { delay(delay_ms); } +void _delay_ms(const int ms) { delay(ms); } // return free memory between end of heap (or end bss) and whatever is current int MarlinHAL::freeMemory() { return ESP.getFreeHeap(); } @@ -342,16 +342,16 @@ void MarlinHAL::set_pwm_duty(const pin_t pin, const uint16_t v, const uint16_t v } else pindata.pwm_duty_ticks = duty; // PWM duty count = # of 4µs ticks per full PWM cycle + + return; } - else #endif - { - const int8_t cid = get_pwm_channel(pin, PWM_FREQUENCY, PWM_RESOLUTION); - if (cid >= 0) { - const uint32_t duty = map(invert ? v_size - v : v, 0, v_size, 0, _BV(PWM_RESOLUTION)-1); - ledcWrite(cid, duty); - } - } + + const int8_t cid = get_pwm_channel(pin, PWM_FREQUENCY, PWM_RESOLUTION); + if (cid >= 0) { + const uint32_t duty = map(invert ? v_size - v : v, 0, v_size, 0, _BV(PWM_RESOLUTION)-1); + ledcWrite(cid, duty); + } } int8_t MarlinHAL::set_pwm_frequency(const pin_t pin, const uint32_t f_desired) { @@ -360,17 +360,15 @@ int8_t MarlinHAL::set_pwm_frequency(const pin_t pin, const uint32_t f_desired) { pwm_pin_data[pin & 0x7F].pwm_cycle_ticks = 1000000UL / f_desired / 4; // # of 4µs ticks per full PWM cycle return 0; } - else #endif - { - const int8_t cid = channel_for_pin(pin); - if (cid >= 0) { - if (f_desired == ledcReadFreq(cid)) return cid; // no freq change - ledcDetachPin(chan_pin[cid]); - chan_pin[cid] = 0; // remove old freq channel - } - return get_pwm_channel(pin, f_desired, PWM_RESOLUTION); // try for new one - } + + const int8_t cid = channel_for_pin(pin); + if (cid >= 0) { + if (f_desired == ledcReadFreq(cid)) return cid; // no freq change + ledcDetachPin(chan_pin[cid]); + chan_pin[cid] = 0; // remove old freq channel + } + return get_pwm_channel(pin, f_desired, PWM_RESOLUTION); // try for new one } // use hardware PWM if avail, if not then ISR diff --git a/Marlin/src/HAL/ESP32/HAL.h b/Marlin/src/HAL/ESP32/HAL.h index ddfedf92ee..0acb3676a2 100644 --- a/Marlin/src/HAL/ESP32/HAL.h +++ b/Marlin/src/HAL/ESP32/HAL.h @@ -1,7 +1,9 @@ /** * Marlin 3D Printer Firmware * Copyright (c) 2020 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] - * Copyright (c) 2016 Bob Cousins bobcousins42@googlemail.com + * + * 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 @@ -50,14 +52,12 @@ #define MYSERIAL1 flushableSerial -#if EITHER(WIFISUPPORT, ESP3D_WIFISUPPORT) - #if ENABLED(ESP3D_WIFISUPPORT) - typedef ForwardSerial1Class< decltype(Serial2Socket) > DefaultSerial1; - extern DefaultSerial1 MSerial0; - #define MYSERIAL2 MSerial0 - #else - #define MYSERIAL2 webSocketSerial - #endif +#if ENABLED(ESP3D_WIFISUPPORT) + typedef ForwardSerial1Class< decltype(Serial2Socket) > DefaultSerial1; + extern DefaultSerial1 MSerial0; + #define MYSERIAL2 MSerial0 +#elif ENABLED(WIFISUPPORT) + #define MYSERIAL2 webSocketSerial #endif #define CRITICAL_SECTION_START() portENTER_CRITICAL(&hal.spinlock) @@ -171,7 +171,7 @@ void _delay_ms(const int ms); // MarlinHAL Class // ------------------------ -#define HAL_ADC_VREF 3.3 +#define HAL_ADC_VREF_MV 3300 #define HAL_ADC_RESOLUTION 10 class MarlinHAL { diff --git a/Marlin/src/HAL/ESP32/HAL_SPI.cpp b/Marlin/src/HAL/ESP32/HAL_SPI.cpp index 868ab1b671..e5302bb905 100644 --- a/Marlin/src/HAL/ESP32/HAL_SPI.cpp +++ b/Marlin/src/HAL/ESP32/HAL_SPI.cpp @@ -4,7 +4,6 @@ * * Based on Sprinter and grbl. * Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm - * Copyright (c) 2017 Victor Perez * * 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 @@ -53,7 +52,7 @@ static SPISettings spiConfig; // ------------------------ void spiBegin() { - #if ENABLED(SDSUPPORT) && PIN_EXISTS(SD_SS) + #if HAS_MEDIA && PIN_EXISTS(SD_SS) OUT_WRITE(SD_SS_PIN, HIGH); #endif } diff --git a/Marlin/src/HAL/ESP32/endstop_interrupts.h b/Marlin/src/HAL/ESP32/endstop_interrupts.h index 0536864610..1377345992 100644 --- a/Marlin/src/HAL/ESP32/endstop_interrupts.h +++ b/Marlin/src/HAL/ESP32/endstop_interrupts.h @@ -42,33 +42,33 @@ void ICACHE_RAM_ATTR endstop_ISR() { endstops.update(); } void setup_endstop_interrupts() { #define _ATTACH(P) attachInterrupt(digitalPinToInterrupt(P), endstop_ISR, CHANGE) - TERN_(HAS_X_MAX, _ATTACH(X_MAX_PIN)); - TERN_(HAS_X_MIN, _ATTACH(X_MIN_PIN)); - TERN_(HAS_Y_MAX, _ATTACH(Y_MAX_PIN)); - TERN_(HAS_Y_MIN, _ATTACH(Y_MIN_PIN)); - TERN_(HAS_Z_MAX, _ATTACH(Z_MAX_PIN)); - TERN_(HAS_Z_MIN, _ATTACH(Z_MIN_PIN)); - TERN_(HAS_X2_MAX, _ATTACH(X2_MAX_PIN)); - TERN_(HAS_X2_MIN, _ATTACH(X2_MIN_PIN)); - TERN_(HAS_Y2_MAX, _ATTACH(Y2_MAX_PIN)); - TERN_(HAS_Y2_MIN, _ATTACH(Y2_MIN_PIN)); - TERN_(HAS_Z2_MAX, _ATTACH(Z2_MAX_PIN)); - TERN_(HAS_Z2_MIN, _ATTACH(Z2_MIN_PIN)); - TERN_(HAS_Z3_MAX, _ATTACH(Z3_MAX_PIN)); - TERN_(HAS_Z3_MIN, _ATTACH(Z3_MIN_PIN)); - TERN_(HAS_Z4_MAX, _ATTACH(Z4_MAX_PIN)); - TERN_(HAS_Z4_MIN, _ATTACH(Z4_MIN_PIN)); - TERN_(HAS_Z_MIN_PROBE_PIN, _ATTACH(Z_MIN_PROBE_PIN)); - TERN_(HAS_I_MAX, _ATTACH(I_MAX_PIN)); - TERN_(HAS_I_MIN, _ATTACH(I_MIN_PIN)); - TERN_(HAS_J_MAX, _ATTACH(J_MAX_PIN)); - TERN_(HAS_J_MIN, _ATTACH(J_MIN_PIN)); - TERN_(HAS_K_MAX, _ATTACH(K_MAX_PIN)); - TERN_(HAS_K_MIN, _ATTACH(K_MIN_PIN)); - TERN_(HAS_U_MAX, _ATTACH(U_MAX_PIN)); - TERN_(HAS_U_MIN, _ATTACH(U_MIN_PIN)); - TERN_(HAS_V_MAX, _ATTACH(V_MAX_PIN)); - TERN_(HAS_V_MIN, _ATTACH(V_MIN_PIN)); - TERN_(HAS_W_MAX, _ATTACH(W_MAX_PIN)); - TERN_(HAS_W_MIN, _ATTACH(W_MIN_PIN)); + TERN_(USE_X_MAX, _ATTACH(X_MAX_PIN)); + TERN_(USE_X_MIN, _ATTACH(X_MIN_PIN)); + TERN_(USE_Y_MAX, _ATTACH(Y_MAX_PIN)); + TERN_(USE_Y_MIN, _ATTACH(Y_MIN_PIN)); + TERN_(USE_Z_MAX, _ATTACH(Z_MAX_PIN)); + TERN_(USE_Z_MIN, _ATTACH(Z_MIN_PIN)); + TERN_(USE_X2_MAX, _ATTACH(X2_MAX_PIN)); + TERN_(USE_X2_MIN, _ATTACH(X2_MIN_PIN)); + TERN_(USE_Y2_MAX, _ATTACH(Y2_MAX_PIN)); + TERN_(USE_Y2_MIN, _ATTACH(Y2_MIN_PIN)); + TERN_(USE_Z2_MAX, _ATTACH(Z2_MAX_PIN)); + TERN_(USE_Z2_MIN, _ATTACH(Z2_MIN_PIN)); + TERN_(USE_Z3_MAX, _ATTACH(Z3_MAX_PIN)); + TERN_(USE_Z3_MIN, _ATTACH(Z3_MIN_PIN)); + TERN_(USE_Z4_MAX, _ATTACH(Z4_MAX_PIN)); + TERN_(USE_Z4_MIN, _ATTACH(Z4_MIN_PIN)); + TERN_(USE_Z_MIN_PROBE, _ATTACH(Z_MIN_PROBE_PIN)); + TERN_(USE_I_MAX, _ATTACH(I_MAX_PIN)); + TERN_(USE_I_MIN, _ATTACH(I_MIN_PIN)); + TERN_(USE_J_MAX, _ATTACH(J_MAX_PIN)); + TERN_(USE_J_MIN, _ATTACH(J_MIN_PIN)); + TERN_(USE_K_MAX, _ATTACH(K_MAX_PIN)); + TERN_(USE_K_MIN, _ATTACH(K_MIN_PIN)); + TERN_(USE_U_MAX, _ATTACH(U_MAX_PIN)); + TERN_(USE_U_MIN, _ATTACH(U_MIN_PIN)); + TERN_(USE_V_MAX, _ATTACH(V_MAX_PIN)); + TERN_(USE_V_MIN, _ATTACH(V_MIN_PIN)); + TERN_(USE_W_MAX, _ATTACH(W_MAX_PIN)); + TERN_(USE_W_MIN, _ATTACH(W_MIN_PIN)); } diff --git a/Marlin/src/HAL/ESP32/i2s.cpp b/Marlin/src/HAL/ESP32/i2s.cpp index d9bad4ec2d..69f8ca9845 100644 --- a/Marlin/src/HAL/ESP32/i2s.cpp +++ b/Marlin/src/HAL/ESP32/i2s.cpp @@ -149,30 +149,28 @@ void stepperTask(void *parameter) { dma.rw_pos = 0; while (dma.rw_pos < DMA_SAMPLE_COUNT) { - // Fill with the port data post pulse_phase until the next step - if (nextMainISR && TERN1(LIN_ADVANCE, nextAdvanceISR)) - i2s_push_sample(); - - // i2s_push_sample() is also called from Stepper::pulse_phase_isr() and Stepper::advance_isr() - // in a rare case where both are called, we need to double decrement the counters - const uint8_t push_count = 1 + (!nextMainISR && TERN0(LIN_ADVANCE, !nextAdvanceISR)); - - #if ENABLED(LIN_ADVANCE) - if (!nextAdvanceISR) { - Stepper::advance_isr(); - nextAdvanceISR = Stepper::la_interval; - } - else if (nextAdvanceISR == Stepper::LA_ADV_NEVER) - nextAdvanceISR = Stepper::la_interval; - #endif - if (!nextMainISR) { Stepper::pulse_phase_isr(); nextMainISR = Stepper::block_phase_isr(); } + #if ENABLED(LIN_ADVANCE) + else if (!nextAdvanceISR) { + Stepper::advance_isr(); + nextAdvanceISR = Stepper::la_interval; + } + #endif + else + i2s_push_sample(); - nextMainISR -= push_count; - TERN_(LIN_ADVANCE, nextAdvanceISR -= push_count); + nextMainISR--; + + #if ENABLED(LIN_ADVANCE) + if (nextAdvanceISR == Stepper::LA_ADV_NEVER) + nextAdvanceISR = Stepper::la_interval; + + if (nextAdvanceISR && nextAdvanceISR != Stepper::LA_ADV_NEVER) + nextAdvanceISR--; + #endif } } } @@ -358,7 +356,7 @@ void i2s_push_sample() { // Every 4µs (when space in DMA buffer) toggle each expander PWM output using // the current duty cycle/frequency so they sync with any steps (once // through the DMA/FIFO buffers). PWM signal inversion handled by other functions - LOOP_L_N(p, MAX_EXPANDER_BITS) { + for (uint8_t p = 0; p < MAX_EXPANDER_BITS; ++p) { if (hal.pwm_pin_data[p].pwm_duty_ticks > 0) { // pin has active pwm? if (hal.pwm_pin_data[p].pwm_tick_count == 0) { if (TEST32(i2s_port_data, p)) { // hi->lo diff --git a/Marlin/src/HAL/ESP32/inc/Conditionals_LCD.h b/Marlin/src/HAL/ESP32/inc/Conditionals_LCD.h index 4da600179d..07d2efe0bd 100644 --- a/Marlin/src/HAL/ESP32/inc/Conditionals_LCD.h +++ b/Marlin/src/HAL/ESP32/inc/Conditionals_LCD.h @@ -21,6 +21,6 @@ */ #pragma once -#if HAS_SPI_TFT || HAS_FSMC_TFT - #error "Sorry! TFT displays are not available for HAL/ESP32." +#if ANY(MKS_MINI_12864, FYSETC_MINI_12864_2_1) + #define U8G_HW_SPI_ESP32 1 #endif diff --git a/Marlin/src/HAL/ESP32/inc/SanityCheck.h b/Marlin/src/HAL/ESP32/inc/SanityCheck.h index 8c5621f10c..dd199c390d 100644 --- a/Marlin/src/HAL/ESP32/inc/SanityCheck.h +++ b/Marlin/src/HAL/ESP32/inc/SanityCheck.h @@ -21,19 +21,26 @@ */ #pragma once +#if HAS_SPI_TFT || HAS_FSMC_TFT + #error "Sorry! TFT displays are not available for HAL/ESP32." +#endif + #if ENABLED(EMERGENCY_PARSER) #error "EMERGENCY_PARSER is not yet implemented for ESP32. Disable EMERGENCY_PARSER to continue." #endif -#if (ENABLED(SPINDLE_LASER_USE_PWM) && SPINDLE_LASER_FREQUENCY > 78125) || (ENABLED(FAST_PWM_FAN_FREQUENCY) && FAST_PWM_FAN_FREQUENCY > 78125) - #error "SPINDLE_LASER_FREQUENCY and FAST_PWM_FREQUENCY maximum value is 78125Hz for ESP32." +#if ENABLED(SPINDLE_LASER_USE_PWM) && SPINDLE_LASER_FREQUENCY > 78125 + #error "SPINDLE_LASER_FREQUENCY maximum value is 78125Hz for ESP32." +#endif +#if ENABLED(FAST_PWM_FAN) && FAST_PWM_FAN_FREQUENCY > 78125 + #error "FAST_PWM_FREQUENCY maximum value is 78125Hz for ESP32." #endif #if HAS_TMC_SW_SERIAL #error "TMC220x Software Serial is not supported on ESP32." #endif -#if BOTH(WIFISUPPORT, ESP3D_WIFISUPPORT) +#if ALL(WIFISUPPORT, ESP3D_WIFISUPPORT) #error "Only enable one WiFi option, either WIFISUPPORT or ESP3D_WIFISUPPORT." #endif @@ -45,14 +52,14 @@ #error "FAST_PWM_FAN is not available on TinyBee." #endif -#if BOTH(I2S_STEPPER_STREAM, BABYSTEPPING) && DISABLED(INTEGRATED_BABYSTEPPING) - #error "BABYSTEPPING on I2S stream requires INTEGRATED_BABYSTEPPING." -#endif - #if USING_PULLDOWNS #error "PULLDOWN pin mode is not available on ESP32 boards." #endif -#if BOTH(I2S_STEPPER_STREAM, LIN_ADVANCE) && DISABLED(EXPERIMENTAL_I2S_LA) +#if ALL(I2S_STEPPER_STREAM, LIN_ADVANCE) && DISABLED(EXPERIMENTAL_I2S_LA) #error "I2S stream is currently incompatible with LIN_ADVANCE." #endif + +#if ALL(I2S_STEPPER_STREAM, PRINTCOUNTER) && PRINTCOUNTER_SAVE_INTERVAL > 0 && DISABLED(PRINTCOUNTER_SYNC) + #error "PRINTCOUNTER_SAVE_INTERVAL may cause issues on ESP32 with an I2S expander. Define PRINTCOUNTER_SYNC in Configuration.h for an imperfect solution." +#endif diff --git a/Marlin/src/HAL/ESP32/ota.cpp b/Marlin/src/HAL/ESP32/ota.cpp index 69a3e25e56..01f5924871 100644 --- a/Marlin/src/HAL/ESP32/ota.cpp +++ b/Marlin/src/HAL/ESP32/ota.cpp @@ -1,7 +1,9 @@ /** * Marlin 3D Printer Firmware * Copyright (c) 2020 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] - * Copyright (c) 2016 Bob Cousins bobcousins42@googlemail.com + * + * 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 @@ -22,7 +24,7 @@ #include "../../inc/MarlinConfigPre.h" -#if BOTH(WIFISUPPORT, OTASUPPORT) +#if ALL(WIFISUPPORT, OTASUPPORT) #include #include @@ -50,7 +52,7 @@ void OTA_init() { }) .onError([](ota_error_t error) { Serial.printf("Error[%u]: ", error); - char *str; + const char *str = "unknown"; switch (error) { case OTA_AUTH_ERROR: str = "Auth Failed"; break; case OTA_BEGIN_ERROR: str = "Begin Failed"; break; diff --git a/Marlin/src/HAL/ESP32/ota.h b/Marlin/src/HAL/ESP32/ota.h index 546ace82db..a91d04dbb7 100644 --- a/Marlin/src/HAL/ESP32/ota.h +++ b/Marlin/src/HAL/ESP32/ota.h @@ -1,7 +1,9 @@ /** * Marlin 3D Printer Firmware * Copyright (c) 2020 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] - * Copyright (c) 2016 Bob Cousins bobcousins42@googlemail.com + * + * 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 diff --git a/Marlin/src/HAL/ESP32/spiffs.cpp b/Marlin/src/HAL/ESP32/spiffs.cpp index a0e713bff0..043ad7849a 100644 --- a/Marlin/src/HAL/ESP32/spiffs.cpp +++ b/Marlin/src/HAL/ESP32/spiffs.cpp @@ -23,7 +23,7 @@ #include "../../inc/MarlinConfigPre.h" -#if BOTH(WIFISUPPORT, WEBSUPPORT) +#if ALL(WIFISUPPORT, WEBSUPPORT) #include "../../core/serial.h" diff --git a/Marlin/src/HAL/ESP32/timers.cpp b/Marlin/src/HAL/ESP32/timers.cpp index c37ad2430c..a6893150b6 100644 --- a/Marlin/src/HAL/ESP32/timers.cpp +++ b/Marlin/src/HAL/ESP32/timers.cpp @@ -111,12 +111,12 @@ void HAL_timer_start(const uint8_t timer_num, const uint32_t frequency) { /** * Set the upper value of the timer, when the timer reaches this upper value the * interrupt should be triggered and the counter reset - * @param timer_num timer number to set the count to - * @param count threshold at which the interrupt is triggered + * @param timer_num timer number to set the compare value to + * @param compare threshold at which the interrupt is triggered */ -void HAL_timer_set_compare(const uint8_t timer_num, hal_timer_t count) { +void HAL_timer_set_compare(const uint8_t timer_num, const hal_timer_t compare) { const tTimerConfig timer = timer_config[timer_num]; - timer_set_alarm_value(timer.group, timer.idx, count); + timer_set_alarm_value(timer.group, timer.idx, compare); } /** diff --git a/Marlin/src/HAL/ESP32/u8g/LCD_defines.h b/Marlin/src/HAL/ESP32/u8g/LCD_defines.h new file mode 100644 index 0000000000..3696d60d7c --- /dev/null +++ b/Marlin/src/HAL/ESP32/u8g/LCD_defines.h @@ -0,0 +1,29 @@ +/** + * Marlin 3D Printer Firmware + * Copyright (c) 2023 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] + * + * Based on Sprinter and grbl. + * Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (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 + +/** + * ESP32 LCD-specific defines + */ + +uint8_t u8g_esp32_hw_spi_fn(u8g_t *u8g, uint8_t msg, uint8_t arg_val, void *arg_ptr); +#define U8G_COM_HAL_HW_SPI_FN u8g_esp32_hw_spi_fn diff --git a/Marlin/src/HAL/ESP32/u8g_esp32_spi.cpp b/Marlin/src/HAL/ESP32/u8g_esp32_spi.cpp index bd7ecdc9f2..a4c1980adc 100644 --- a/Marlin/src/HAL/ESP32/u8g_esp32_spi.cpp +++ b/Marlin/src/HAL/ESP32/u8g_esp32_spi.cpp @@ -25,14 +25,14 @@ #include "../../inc/MarlinConfig.h" -#if EITHER(MKS_MINI_12864, FYSETC_MINI_12864_2_1) +#if U8G_HW_SPI_ESP32 #include #include "../shared/HAL_SPI.h" #include "HAL.h" #include "SPI.h" -#if ENABLED(SDSUPPORT) +#if HAS_MEDIA #include "../../sd/cardreader.h" #if ENABLED(ESP3D_WIFISUPPORT) #include "sd_ESP32.h" @@ -41,7 +41,6 @@ static SPISettings spiConfig; - #ifndef LCD_SPI_SPEED #ifdef SD_SPI_SPEED #define LCD_SPI_SPEED SD_SPI_SPEED // Assume SPI speed shared with SD @@ -50,7 +49,7 @@ static SPISettings spiConfig; #endif #endif -uint8_t u8g_eps_hw_spi_fn(u8g_t *u8g, uint8_t msg, uint8_t arg_val, void *arg_ptr) { +uint8_t u8g_esp32_hw_spi_fn(u8g_t *u8g, uint8_t msg, uint8_t arg_val, void *arg_ptr) { static uint8_t msgInitCount = 2; // Ignore all messages until 2nd U8G_COM_MSG_INIT #if ENABLED(PAUSE_LCD_FOR_BUSY_SD) @@ -101,6 +100,5 @@ uint8_t u8g_eps_hw_spi_fn(u8g_t *u8g, uint8_t msg, uint8_t arg_val, void *arg_pt return 1; } -#endif // EITHER(MKS_MINI_12864, FYSETC_MINI_12864_2_1) - +#endif // U8G_HW_SPI_ESP32 #endif // ARDUINO_ARCH_ESP32 diff --git a/Marlin/src/HAL/ESP32/web.cpp b/Marlin/src/HAL/ESP32/web.cpp index 7a27707a3e..63a101595f 100644 --- a/Marlin/src/HAL/ESP32/web.cpp +++ b/Marlin/src/HAL/ESP32/web.cpp @@ -23,7 +23,7 @@ #include "../../inc/MarlinConfigPre.h" -#if BOTH(WIFISUPPORT, WEBSUPPORT) +#if ALL(WIFISUPPORT, WEBSUPPORT) #include "../../inc/MarlinConfig.h" diff --git a/Marlin/src/HAL/HAL.h b/Marlin/src/HAL/HAL.h index 5186578019..f3e16cfdf1 100644 --- a/Marlin/src/HAL/HAL.h +++ b/Marlin/src/HAL/HAL.h @@ -27,7 +27,7 @@ #define GCC_VERSION (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__) #endif -#include HAL_PATH(.,HAL.h) +#include HAL_PATH(..,HAL.h) extern MarlinHAL hal; #define HAL_ADC_RANGE _BV(HAL_ADC_RESOLUTION) diff --git a/Marlin/src/HAL/HC32/HAL.cpp b/Marlin/src/HAL/HC32/HAL.cpp new file mode 100644 index 0000000000..a74d21e6fd --- /dev/null +++ b/Marlin/src/HAL/HC32/HAL.cpp @@ -0,0 +1,56 @@ +/** + * Marlin 3D Printer Firmware + * Copyright (c) 2023 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] + * + * Based on Sprinter and grbl. + * Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +#ifdef ARDUINO_ARCH_HC32 + +#include "HAL.h" +#include +#include + +// +// Emergency Parser +// +#if ENABLED(EMERGENCY_PARSER) + +extern "C" void core_hook_usart_rx_irq(uint8_t ch, uint8_t usart) { + // Only handle receive on host serial ports + if (false + #ifdef SERIAL_PORT + || usart != SERIAL_PORT + #endif + #ifdef SERIAL_PORT_2 + || usart != SERIAL_PORT_2 + #endif + #ifdef SERIAL_PORT_3 + || usart != SERIAL_PORT_3 + #endif + ) { + return; + } + + // Submit character to emergency parser + if (MYSERIAL1.emergency_parser_enabled()) + emergency_parser.update(MYSERIAL1.emergency_state, ch); +} + +#endif // EMERGENCY_PARSER +#endif // ARDUINO_ARCH_HC32 diff --git a/Marlin/src/HAL/HC32/HAL.h b/Marlin/src/HAL/HC32/HAL.h new file mode 100644 index 0000000000..dd02183dd0 --- /dev/null +++ b/Marlin/src/HAL/HC32/HAL.h @@ -0,0 +1,154 @@ +/** + * Marlin 3D Printer Firmware + * Copyright (c) 2023 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] + * + * Based on Sprinter and grbl. + * Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (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 . + * + */ + +/** + * HAL for HC32F460 based boards + * + * Note: MarlinHAL class is in MarlinHAL.h/cpp + */ + +#define CPU_32_BIT + +#include "../../inc/MarlinConfig.h" + +#include "../../core/macros.h" +#include "../shared/Marduino.h" +#include "../shared/math_32bit.h" +#include "../shared/HAL_SPI.h" + +#include "fastio.h" +#include "timers.h" +#include "MarlinSerial.h" + +#include + +// +// Serial Ports +// +#define _MSERIAL(X) MSerial##X +#define MSERIAL(X) _MSERIAL(X) +#define NUM_UARTS 4 + +#if SERIAL_PORT == -1 + #error "USB Serial is not supported on HC32F460" +#elif WITHIN(SERIAL_PORT, 1, NUM_UARTS) + #define MYSERIAL1 MSERIAL(SERIAL_PORT) +#else + #define MYSERIAL1 MSERIAL(1) // Dummy port + static_assert(false, "SERIAL_PORT must be from 1 to " STRINGIFY(NUM_UARTS) ".") +#endif + +#ifdef SERIAL_PORT_2 + #if SERIAL_PORT_2 == -1 + #error "USB Serial is not supported on HC32F460" + #elif WITHIN(SERIAL_PORT_2, 1, NUM_UARTS) + #define MYSERIAL2 MSERIAL(SERIAL_PORT_2) + #else + #define MYSERIAL2 MSERIAL(1) // Dummy port + static_assert(false, "SERIAL_PORT_2 must be from 1 to " STRINGIFY(NUM_UARTS) ".") + #endif +#endif + +#ifdef SERIAL_PORT_3 + #if SERIAL_PORT_3 == -1 + #error "USB Serial is not supported on HC32F460" + #elif WITHIN(SERIAL_PORT_3, 1, NUM_UARTS) + #define MYSERIAL3 MSERIAL(SERIAL_PORT_3) + #else + #define MYSERIAL3 MSERIAL(1) // Dummy port + static_assert(false, "SERIAL_PORT_3 must be from 1 to " STRINGIFY(NUM_UARTS) ".") + #endif +#endif + +#ifdef LCD_SERIAL_PORT + #if LCD_SERIAL_PORT == -1 + #error "USB Serial is not supported on HC32F460" + #elif WITHIN(LCD_SERIAL_PORT, 1, NUM_UARTS) + #define LCD_SERIAL MSERIAL(LCD_SERIAL_PORT) + #else + #define LCD_SERIAL MSERIAL(1) // Dummy port + static_assert(false, "LCD_SERIAL_PORT must be from 1 to " STRINGIFY(NUM_UARTS) ".") + #endif + + #if HAS_DGUS_LCD + #define LCD_SERIAL_TX_BUFFER_FREE() LCD_SERIAL.availableForWrite() + #endif +#endif + +// +// Emergency Parser +// +#if ENABLED(EMERGENCY_PARSER) + extern "C" void usart_rx_irq_hook(uint8_t ch, uint8_t usart); +#endif + +// +// Misc. Defines +// +#define square(x) ((x) * (x)) + +#ifndef strncpy_P + #define strncpy_P(dest, src, num) strncpy((dest), (src), (num)) +#endif + +// +// Misc. Functions +// +#ifndef analogInputToDigitalPin +#define analogInputToDigitalPin(p) (p) +#endif + +#define CRITICAL_SECTION_START \ + uint32_t primask = __get_PRIMASK(); \ + (void)__iCliRetVal() + +#define CRITICAL_SECTION_END \ + if (!primask) \ + (void)__iSeiRetVal() + +// Disable interrupts +#define cli() noInterrupts() + +// Enable interrupts +#define sei() interrupts() + +// bss_end alias +#define __bss_end __bss_end__ + +// Fix bug in pgm_read_ptr +#undef pgm_read_ptr +#define pgm_read_ptr(addr) (*(addr)) + +// +// ADC +// +#define HAL_ADC_VREF_MV 3300 +#define HAL_ADC_RESOLUTION 10 + +#define GET_PIN_MAP_PIN(index) index +#define GET_PIN_MAP_INDEX(pin) pin +#define PARSED_PIN_INDEX(code, dval) parser.intval(code, dval) + +// +// MarlinHAL implementation +// +#include "MarlinHAL.h" diff --git a/Marlin/src/HAL/HC32/MarlinHAL.cpp b/Marlin/src/HAL/HC32/MarlinHAL.cpp new file mode 100644 index 0000000000..1ab374fbf1 --- /dev/null +++ b/Marlin/src/HAL/HC32/MarlinHAL.cpp @@ -0,0 +1,278 @@ +/** + * Marlin 3D Printer Firmware + * Copyright (c) 2023 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] + * + * Based on Sprinter and grbl. + * Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (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 . + * + */ + +/** + * HAL for HC32F460, based heavily on the legacy implementation and STM32F1 + */ +#ifdef ARDUINO_ARCH_HC32 + +#include "../../inc/MarlinConfig.h" + +#include "HAL.h" // Includes MarlinHAL.h +#include +#include + +#if TEMP_SENSOR_SOC + #include +#endif + +extern "C" char *_sbrk(int incr); + +#if ENABLED(POSTMORTEM_DEBUGGING) + // From MinSerial.cpp + extern void install_min_serial(); +#endif + +#if ENABLED(MARLIN_DEV_MODE) + inline void HAL_clock_frequencies_dump() { + // 1. dump all clock frequencies + update_system_clock_frequencies(); + SERIAL_ECHOPGM( + "-- clocks dump -- \nSYS=", SYSTEM_CLOCK_FREQUENCIES.system, + "\nHCLK=", SYSTEM_CLOCK_FREQUENCIES.hclk, + "\nPCLK0=", SYSTEM_CLOCK_FREQUENCIES.pclk0, + "\nPCLK1=", SYSTEM_CLOCK_FREQUENCIES.pclk1, + "\nPCLK2=", SYSTEM_CLOCK_FREQUENCIES.pclk2, + "\nPCLK3=", SYSTEM_CLOCK_FREQUENCIES.pclk3, + "\nPCLK4=", SYSTEM_CLOCK_FREQUENCIES.pclk4, + "\nEXCLK=", SYSTEM_CLOCK_FREQUENCIES.exclk, + "\nF_CPU=", F_CPU + ); + + // 2. dump current system clock source + en_clk_sys_source_t clkSrc = CLK_GetSysClkSource(); + SERIAL_ECHOPGM("\nSYSCLK="); + switch (clkSrc) { + case ClkSysSrcHRC: SERIAL_ECHOPGM("HRC"); break; + case ClkSysSrcMRC: SERIAL_ECHOPGM("MRC"); break; + case ClkSysSrcLRC: SERIAL_ECHOPGM("LRC"); break; + case ClkSysSrcXTAL: SERIAL_ECHOPGM("XTAL"); break; + case ClkSysSrcXTAL32: SERIAL_ECHOPGM("XTAL32"); break; + case CLKSysSrcMPLL: SERIAL_ECHOPGM("MPLL"); + + // 3. if MPLL is used, dump MPLL settings: + // (derived from CLK_SetPllSource and CLK_MpllConfig) + // source + switch (M4_SYSREG->CMU_PLLCFGR_f.PLLSRC) { + case ClkPllSrcXTAL: SERIAL_ECHOPGM(",XTAL"); break; + case ClkPllSrcHRC: SERIAL_ECHOPGM(",HRC"); break; + default: break; + } + + // PLL multipliers and dividers + SERIAL_ECHOPGM( + "\nP=", M4_SYSREG->CMU_PLLCFGR_f.MPLLP + 1UL, + "\nQ=", M4_SYSREG->CMU_PLLCFGR_f.MPLLQ + 1UL, + "\nR=", M4_SYSREG->CMU_PLLCFGR_f.MPLLR + 1UL, + "\nN=", M4_SYSREG->CMU_PLLCFGR_f.MPLLN + 1UL, + "\nM=", M4_SYSREG->CMU_PLLCFGR_f.MPLLM + 1UL + ); + break; + default: break; + } + + // Done + SERIAL_ECHOPGM("\n--\n"); + } +#endif // MARLIN_DEV_MODE + +// +// MarlinHAL class implementation +// + +pin_t MarlinHAL::last_adc_pin; + +#if TEMP_SENSOR_SOC + float MarlinHAL::soc_temp = 0; +#endif + +MarlinHAL::MarlinHAL() {} + +void MarlinHAL::watchdog_init() { + TERN_(USE_WATCHDOG, WDT.begin(5000)); // Reset on 5 second timeout +} + +void MarlinHAL::watchdog_refresh() { + TERN_(USE_WATCHDOG, WDT.reload()); +} + +void MarlinHAL::init() { + NVIC_SetPriorityGrouping(0x3); + + // Print clock frequencies to host serial + TERN_(MARLIN_DEV_MODE, HAL_clock_frequencies_dump()); + + // Register min serial + TERN_(POSTMORTEM_DEBUGGING, install_min_serial()); +} + +void MarlinHAL::init_board() {} + +void MarlinHAL::reboot() { + NVIC_SystemReset(); +} + +bool MarlinHAL::isr_state() { + return !__get_PRIMASK(); +} + +void MarlinHAL::isr_on() { + __enable_irq(); +} + +void MarlinHAL::isr_off() { + __disable_irq(); +} + +void MarlinHAL::delay_ms(const int ms) { + delay(ms); +} + +void MarlinHAL::idletask() {} + +uint8_t MarlinHAL::get_reset_source() { + // Query reset cause from RMU + stc_rmu_rstcause_t rstCause; + RMU_GetResetCause(&rstCause); + + // Map reset cause code to those expected by Marlin + // - Reset causes are flags, so multiple can be set + TERN_(MARLIN_DEV_MODE, printf("-- Reset Cause -- \n")); + uint8_t cause = 0; + #define MAP_CAUSE(from, to) \ + if (rstCause.from == Set) { \ + TERN_(MARLIN_DEV_MODE, printf(" - " STRINGIFY(from) "\n")); \ + cause |= to; \ + } + + // Power on + MAP_CAUSE(enPowerOn, RST_POWER_ON) // Power on reset + + // External + MAP_CAUSE(enRstPin, RST_EXTERNAL) // Reset pin + MAP_CAUSE(enPvd1, RST_EXTERNAL) // Program voltage detection reset + MAP_CAUSE(enPvd2, RST_EXTERNAL) // " + + // Brown out + MAP_CAUSE(enBrownOut, RST_BROWN_OUT) // Brown out reset + + // Wdt + MAP_CAUSE(enWdt, RST_WATCHDOG) // Watchdog reset + MAP_CAUSE(enSwdt, RST_WATCHDOG) // Special WDT reset + + // Software + MAP_CAUSE(enPowerDown, RST_SOFTWARE) // MCU power down (?) + MAP_CAUSE(enSoftware, RST_SOFTWARE) // Software reset (e.g. NVIC_SystemReset()) + + // Misc. + MAP_CAUSE(enMpuErr, RST_BACKUP) // MPU error + MAP_CAUSE(enRamParityErr, RST_BACKUP) // RAM parity error + MAP_CAUSE(enRamEcc, RST_BACKUP) // RAM ecc error + MAP_CAUSE(enClkFreqErr, RST_BACKUP) // Clock frequency failure + MAP_CAUSE(enXtalErr, RST_BACKUP) // XTAL failure + + #undef MAP_CAUSE + return cause; +} + +void MarlinHAL::clear_reset_source() { + RMU_ClrResetFlag(); +} + +int MarlinHAL::freeMemory() { + volatile char top; + return &top - _sbrk(0); +} + +void MarlinHAL::adc_init() {} + +void MarlinHAL::adc_enable(const pin_t pin) { + #if TEMP_SENSOR_SOC + if (pin == TEMP_SOC_PIN) { + // Start OTS, min. 1s between reads + ChipTemperature.begin(); + ChipTemperature.setMinimumReadDeltaMillis(1000); + return; + } + #endif + + // Just set pin mode to analog + pinMode(pin, INPUT_ANALOG); +} + +void MarlinHAL::adc_start(const pin_t pin) { + MarlinHAL::last_adc_pin = pin; + + #if TEMP_SENSOR_SOC + if (pin == TEMP_SOC_PIN) { + // Read OTS + float temp; + if (ChipTemperature.read(temp)) + MarlinHAL::soc_temp = temp; + return; + } + #endif + + CORE_ASSERT(IS_GPIO_PIN(pin), "adc_start: invalid pin") + + analogReadAsync(pin); +} + +bool MarlinHAL::adc_ready() { + #if TEMP_SENSOR_SOC + if (MarlinHAL::last_adc_pin == TEMP_SOC_PIN) return true; + #endif + + CORE_ASSERT(IS_GPIO_PIN(MarlinHAL::last_adc_pin), "adc_ready: invalid pin") + + return getAnalogReadComplete(MarlinHAL::last_adc_pin); +} + +uint16_t MarlinHAL::adc_value() { + #if TEMP_SENSOR_SOC + if (MarlinHAL::last_adc_pin == TEMP_SOC_PIN) + return OTS_FLOAT_TO_ADC_READING(MarlinHAL::soc_temp); + #endif + + // Read conversion result + CORE_ASSERT(IS_GPIO_PIN(MarlinHAL::last_adc_pin), "adc_value: invalid pin") + + return getAnalogReadValue(MarlinHAL::last_adc_pin); +} + +void MarlinHAL::set_pwm_duty(const pin_t pin, const uint16_t value, const uint16_t scale, const bool invert) { + // Invert value if requested + const uint16_t val = invert ? scale - value : value; + + // AnalogWrite the value, core handles the rest + // Pin mode should be set by Marlin by calling SET_PWM() before calling this function + analogWriteScaled(pin, val, scale); +} + +void MarlinHAL::set_pwm_frequency(const pin_t pin, const uint16_t f_desired) { + // TODO set_pwm_frequency is not implemented yet + panic("set_pwm_frequency is not implemented yet\n"); +} + +void flashFirmware(const int16_t) { MarlinHAL::reboot(); } + +#endif // ARDUINO_ARCH_HC32 diff --git a/Marlin/src/HAL/HC32/MarlinHAL.h b/Marlin/src/HAL/HC32/MarlinHAL.h new file mode 100644 index 0000000000..86dc3c7e53 --- /dev/null +++ b/Marlin/src/HAL/HC32/MarlinHAL.h @@ -0,0 +1,133 @@ +/** + * Marlin 3D Printer Firmware + * Copyright (c) 2023 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] + * + * Based on Sprinter and grbl. + * Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ +#pragma once + +#include +#include + +typedef gpio_pin_t pin_t; + +#if TEMP_SENSOR_SOC + /** + * Convert ots measurement float to uint16_t for adc_value() + * + * @note returns float as integer in degrees C * 10, if T > 0 + */ + #define OTS_FLOAT_TO_ADC_READING(T) ((T) > 0 ? ((uint16_t)((T) * 10.0f)) : 0) + + /** + * Convert adc_value() uint16_t to ots measurement float + * + * @note see OTS_FLOAT_TO_ADC_READING for inverse + * + * @note RAW is oversampled by OVERSAMPLENR, so we need to divide first + */ + #define TEMP_SOC_SENSOR(RAW) ((float)(((RAW) / OVERSAMPLENR) / 10)) +#endif + +/** + * HAL class for Marlin on HC32F460 + */ +class MarlinHAL { +public: + // Earliest possible init, before setup() + MarlinHAL(); + + // Watchdog + static void watchdog_init(); + static void watchdog_refresh(); + + static void init(); // Called early in setup() + static void init_board(); // Called less early in setup() + static void reboot(); // Restart the firmware from 0x0 + + // Interrupts + static bool isr_state(); + static void isr_on(); + static void isr_off(); + + static void delay_ms(const int ms); + + // Tasks, called from idle() + static void idletask(); + + // Reset + static uint8_t get_reset_source(); + static void clear_reset_source(); + + // Free SRAM + static int freeMemory(); + + // + // ADC Methods + // + + // Called by Temperature::init once at startup + static void adc_init(); + + // Called by Temperature::init for each sensor at startup + static void adc_enable(const pin_t pin); + + // Begin ADC sampling on the given pin. Called from Temperature::isr! + static void adc_start(const pin_t pin); + + // Is the ADC ready for reading? + static bool adc_ready(); + + // The current value of the ADC register + static uint16_t adc_value(); + + /** + * Set the PWM duty cycle for the pin to the given value. + * Optionally invert the duty cycle [default = false] + * Optionally change the maximum size of the provided value to enable finer PWM duty control [default = 255] + * The timer must be pre-configured with set_pwm_frequency() if the default frequency is not desired. + */ + static void set_pwm_duty(const pin_t pin, const uint16_t value, const uint16_t scale = 255, const bool invert = false); + + /** + * Set the frequency of the timer for the given pin. + * All Timer PWM pins run at the same frequency. + */ + static void set_pwm_frequency(const pin_t pin, const uint16_t f_desired); + +private: + /** + * Pin number of the last pin that was used with adc_start() + */ + static pin_t last_adc_pin; + + #if TEMP_SENSOR_SOC + /** + * On-chip temperature sensor value + */ + static float soc_temp; + #endif +}; + +// M997: Trigger a firmware update from SD card (after upload). +// On HC32F460, a reboot is enough to do this. +#ifndef PLATFORM_M997_SUPPORT + #define PLATFORM_M997_SUPPORT +#endif + +void flashFirmware(const int16_t); diff --git a/Marlin/src/HAL/HC32/MarlinSerial.cpp b/Marlin/src/HAL/HC32/MarlinSerial.cpp new file mode 100644 index 0000000000..168533f664 --- /dev/null +++ b/Marlin/src/HAL/HC32/MarlinSerial.cpp @@ -0,0 +1,142 @@ +/** + * Marlin 3D Printer Firmware + * Copyright (c) 2023 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] + * + * Based on Sprinter and grbl. + * Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ +#ifdef ARDUINO_ARCH_HC32 + +#include "../../inc/MarlinConfig.h" +#include "MarlinSerial.h" +#include + +/** + * Not every MarlinSerial instance should handle emergency parsing, as + * it would not make sense to parse GCode from TMC responses + */ +constexpr bool serial_handles_emergency(int port) { + return false + #ifdef SERIAL_PORT + || (SERIAL_PORT) == port + #endif + #ifdef SERIAL_PORT_2 + || (SERIAL_PORT_2) == port + #endif + #ifdef LCD_SERIAL_PORT + || (LCD_SERIAL_PORT) == port + #endif + ; +} + +// +// Define serial ports +// +#define DEFINE_HWSERIAL_MARLIN(name, n) \ + MSerialT name(serial_handles_emergency(n), \ + &USART##n##_config, \ + BOARD_USART##n##_TX_PIN, \ + BOARD_USART##n##_RX_PIN); + +DEFINE_HWSERIAL_MARLIN(MSerial1, 1); +DEFINE_HWSERIAL_MARLIN(MSerial2, 2); + +// +// Serial port assertions +// + +// Check the type of each serial port by passing it to a template function. +// HardwareSerial is known to sometimes hang the controller when an error occurs, +// so this case will fail the static assert. All other classes are assumed to be ok. +template +constexpr bool IsSerialClassAllowed(const T &) { return true; } +constexpr bool IsSerialClassAllowed(const HardwareSerial &) { return false; } +constexpr bool IsSerialClassAllowed(const Usart &) { return false; } + +// If you encounter this error, replace SerialX with MSerialX, for example MSerial3. +#define CHECK_CFG_SERIAL(A) static_assert(IsSerialClassAllowed(A), STRINGIFY(A) " is defined incorrectly"); +#define CHECK_AXIS_SERIAL(A) static_assert(IsSerialClassAllowed(A##_HARDWARE_SERIAL), STRINGIFY(A) "_HARDWARE_SERIAL must be defined in the form MSerial1, rather than Serial1"); + +// Non-TMC ports were already validated in HAL.h, so do not require verbose error messages. +#ifdef MYSERIAL1 + CHECK_CFG_SERIAL(MYSERIAL1); +#endif +#ifdef MYSERIAL2 + CHECK_CFG_SERIAL(MYSERIAL2); +#endif +#ifdef LCD_SERIAL + CHECK_CFG_SERIAL(LCD_SERIAL); +#endif +#if AXIS_HAS_HW_SERIAL(X) + CHECK_AXIS_SERIAL(X); +#endif +#if AXIS_HAS_HW_SERIAL(X2) + CHECK_AXIS_SERIAL(X2); +#endif +#if AXIS_HAS_HW_SERIAL(Y) + CHECK_AXIS_SERIAL(Y); +#endif +#if AXIS_HAS_HW_SERIAL(Y2) + CHECK_AXIS_SERIAL(Y2); +#endif +#if AXIS_HAS_HW_SERIAL(Z) + CHECK_AXIS_SERIAL(Z); +#endif +#if AXIS_HAS_HW_SERIAL(Z2) + CHECK_AXIS_SERIAL(Z2); +#endif +#if AXIS_HAS_HW_SERIAL(Z3) + CHECK_AXIS_SERIAL(Z3); +#endif +#if AXIS_HAS_HW_SERIAL(Z4) + CHECK_AXIS_SERIAL(Z4); +#endif +#if AXIS_HAS_HW_SERIAL(I) + CHECK_AXIS_SERIAL(I); +#endif +#if AXIS_HAS_HW_SERIAL(J) + CHECK_AXIS_SERIAL(J); +#endif +#if AXIS_HAS_HW_SERIAL(K) + CHECK_AXIS_SERIAL(K); +#endif +#if AXIS_HAS_HW_SERIAL(E0) + CHECK_AXIS_SERIAL(E0); +#endif +#if AXIS_HAS_HW_SERIAL(E1) + CHECK_AXIS_SERIAL(E1); +#endif +#if AXIS_HAS_HW_SERIAL(E2) + CHECK_AXIS_SERIAL(E2); +#endif +#if AXIS_HAS_HW_SERIAL(E3) + CHECK_AXIS_SERIAL(E3); +#endif +#if AXIS_HAS_HW_SERIAL(E4) + CHECK_AXIS_SERIAL(E4); +#endif +#if AXIS_HAS_HW_SERIAL(E5) + CHECK_AXIS_SERIAL(E5); +#endif +#if AXIS_HAS_HW_SERIAL(E6) + CHECK_AXIS_SERIAL(E6); +#endif +#if AXIS_HAS_HW_SERIAL(E7) + CHECK_AXIS_SERIAL(E7); +#endif + +#endif // ARDUINO_ARCH_HC32 diff --git a/Marlin/src/HAL/HC32/MarlinSerial.h b/Marlin/src/HAL/HC32/MarlinSerial.h new file mode 100644 index 0000000000..08eeef4395 --- /dev/null +++ b/Marlin/src/HAL/HC32/MarlinSerial.h @@ -0,0 +1,56 @@ +/** + * Marlin 3D Printer Firmware + * Copyright (c) 2023 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] + * + * Based on Sprinter and grbl. + * Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ +#pragma once + +#include "../../core/serial_hook.h" +#include + +// Optionally set uart IRQ priority to reduce overflow errors +// #define UART_IRQ_PRIO 1 + +struct MarlinSerial : public Usart { + MarlinSerial(struct usart_config_t *usart_device, gpio_pin_t tx_pin, gpio_pin_t rx_pin) : Usart(usart_device, tx_pin, rx_pin) {} + + #ifdef UART_IRQ_PRIO + void setPriority() { + NVIC_SetPriority(c_dev()->interrupts.rx_data_available.interrupt_number, UART_IRQ_PRIO); + NVIC_SetPriority(c_dev()->interrupts.rx_error.interrupt_number, UART_IRQ_PRIO); + NVIC_SetPriority(c_dev()->interrupts.tx_buffer_empty.interrupt_number, UART_IRQ_PRIO); + NVIC_SetPriority(c_dev()->interrupts.tx_complete.interrupt_number, UART_IRQ_PRIO); + } + + void begin(uint32_t baud) { + Usart::begin(baud); + setPriority(); + } + + void begin(uint32_t baud, uint8_t config) { + Usart::begin(baud, config); + setPriority(); + } + #endif +}; + +typedef Serial1Class MSerialT; + +extern MSerialT MSerial1; +extern MSerialT MSerial2; diff --git a/Marlin/src/HAL/HC32/MinSerial.cpp b/Marlin/src/HAL/HC32/MinSerial.cpp new file mode 100644 index 0000000000..93017ee0df --- /dev/null +++ b/Marlin/src/HAL/HC32/MinSerial.cpp @@ -0,0 +1,151 @@ +/** + * Marlin 3D Printer Firmware + * Copyright (c) 2023 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] + * + * Based on Sprinter and grbl. + * Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +#ifdef ARDUINO_ARCH_HC32 + +#include "../../inc/MarlinConfig.h" +#include + +#if ANY(POSTMORTEM_DEBUGGING, PANIC_ENABLE) + +#include + +// +// Shared by both panic and PostMortem debugging +// +static void minserial_begin() { + #if !WITHIN(SERIAL_PORT, 1, 3) + #warning "MinSerial requires a physical UART port for output." + #warning "Disabling MinSerial because the used serial port is not a HW port." + #else + + // Prepare usart_sync configuration + const stc_usart_uart_init_t usart_config = { + .enClkMode = UsartIntClkCkNoOutput, + .enClkDiv = UsartClkDiv_1, + .enDataLength = UsartDataBits8, + .enDirection = UsartDataLsbFirst, + .enStopBit = UsartOneStopBit, + .enParity = UsartParityNone, + .enSampleMode = UsartSampleBit8, + .enDetectMode = UsartStartBitFallEdge, + .enHwFlow = UsartRtsEnable, + }; + + // Initializes usart_sync driver + #define __USART_SYNC_INIT(port_no, baud, config) \ + usart_sync_init(M4_USART##port_no, \ + BOARD_USART##port_no##_TX_PIN, \ + baud, \ + config); + #define USART_SYNC_INIT(port_no, baud, config) __USART_SYNC_INIT(port_no, baud, config) + + // This will reset the baudrate to what is defined in Configuration.h, + // ignoring any changes made with e.g. M575. + // keeping the dynamic baudrate would require re-calculating the baudrate + // using the register values, which is a pain... + + // TODO: retain dynamic baudrate in MinSerial init + // -> see USART_SetBaudrate(), needs to be inverted + USART_SYNC_INIT(SERIAL_PORT, BAUDRATE, &usart_config); + + #undef USART_SYNC_INIT + #undef __USART_SYNC_INIT + #endif +} + +static void minserial_putc(char c) { + #if WITHIN(SERIAL_PORT, 1, 3) + #define __USART_SYNC_PUTC(port_no, ch) usart_sync_putc(M4_USART##port_no, ch); + #define USART_SYNC_PUTC(port_no, ch) __USART_SYNC_PUTC(port_no, ch) + + USART_SYNC_PUTC(SERIAL_PORT, c); + + #undef USART_SYNC_PUTC + #undef __USART_SYNC_PUTC + #endif +} + +// +// Panic only +// +#ifdef PANIC_ENABLE + +void panic_begin() { + minserial_begin(); + panic_puts("\n\nPANIC:\n"); +} + +void panic_puts(const char *str) { + while (*str) minserial_putc(*str++); +} + +#endif // PANIC_ENABLE + +// +// PostMortem debugging only +// +#if ENABLED(POSTMORTEM_DEBUGGING) + +#include "../shared/MinSerial.h" +#include + +void fault_handlers_init() { + // Enable cpu traps: + // - Divide by zero + // - Unaligned access + SCB->CCR |= SCB_CCR_DIV_0_TRP_Msk; //| SCB_CCR_UNALIGN_TRP_Msk; +} + +void install_min_serial() { + HAL_min_serial_init = &minserial_begin; + HAL_min_serial_out = &minserial_putc; +} + +extern "C" { + __attribute__((naked)) void JumpHandler_ASM() { + __asm__ __volatile__( + "b CommonHandler_ASM\n"); + } + void __attribute__((naked, alias("JumpHandler_ASM"), nothrow)) HardFault_Handler(); + void __attribute__((naked, alias("JumpHandler_ASM"), nothrow)) BusFault_Handler(); + void __attribute__((naked, alias("JumpHandler_ASM"), nothrow)) UsageFault_Handler(); + void __attribute__((naked, alias("JumpHandler_ASM"), nothrow)) MemManage_Handler(); + void __attribute__((naked, alias("JumpHandler_ASM"), nothrow)) NMI_Handler(); +} + +#endif // POSTMORTEM_DEBUGGING +#endif // POSTMORTEM_DEBUGGING || PANIC_ENABLE + +// +// Panic_end is always required to print the '!!' to the host +// +void panic_end() { + // Print '!!' to signal error to host + // Do it 10x so it's not missed + for (uint_fast8_t i = 10; i--;) panic_printf("\n!!\n"); + + // Then, reset the board + NVIC_SystemReset(); +} + +#endif // ARDUINO_ARCH_HC32 diff --git a/Marlin/src/HAL/HC32/README.md b/Marlin/src/HAL/HC32/README.md new file mode 100644 index 0000000000..c9ae8a9a20 --- /dev/null +++ b/Marlin/src/HAL/HC32/README.md @@ -0,0 +1,110 @@ +# HC32F460 HAL + +This document provides notes on the HAL for the HC32F460 MCU. + +## Adding support for a new board + +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.) +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. +3. Determine your board's application start address (see [below](#finding-the-application-start-address)) +4. Set `board_build.ld_args.flash_start` to the app start address once you've found it. If your board doesn't use a bootloader, you may be able to use the "ICSP" header or DFU. This document will be updated once we have more information about flashing without a bootloader. + +### Finding the application start address + +If the board contains a bootloader you'll need to find the application address. This is the address the bootloader jumps to after it's done. You can find this address in a few different ways: + +#### 1. Using log messages + +If you're lucky, the bootloader may print the app start address on the serial output during boot. To check for this, use your favorite serial monitor to observe the serial output when you power on the board. Look for a message like "Jumping to 0xC000" or "GotoApp->addr=0xC000". This line would be printed before Marlin's "start" message. + +Example: + +``` +[...] +version 1.2 +sdio init success! +Disk init +Tips ------ None Firmware file +GotoApp->addr=0xC000 + +start +[...] +``` + +#### 2. Using published source code + +If the vendor has published Marlin source code that includes the bootloader, you can search the bootloader source code for the address. Begin your search with the following steps: + +1. Find the code that sets the vector table offset + +The vector table offset is usually set using a line like this: + +```c +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/d1f23adf96920996b979bc31023d1dce236d05db/firmware/Sources/.svn/pristine/ec/ec82bcb480b511906bc3e6658450e3a803ab9813.svn-base#L96) which actually includes deleted files in its repo. + +2. Using a linker script + +If the repository contains a linker script, look at the memory regions, specifically a region named `FLASH` or similar. The `ORIGIN` of that region will be the application start address. + +**Example:** + +```ld +MEMORY +{ + FLASH (rx): ORIGIN = 0x0000C000, LENGTH = 512K + OTP (rx): ORIGIN = 0x03000C00, LENGTH = 1020 + RAM (rwx): ORIGIN = 0x1FFF8000, LENGTH = 188K + RET_RAM (rwx): ORIGIN = 0x200F0000, LENGTH = 4K +} +``` + +> [!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) + +## Documentation on the HC32F460 + +Due to uncertain licensing (w/r/t STMicro), documentation for the HC32F460 is only available upon request. Documentation includes the following: + +- Datasheet, user manual, reference manual +- Application notes for the DDL +- DDL source code +- IDE support packages (Keil, IAR, ...) including .svd files +- Programming software +- Emulator / debugger drivers +- Development board documentation and schematics +- Errata documents +- (Limited) sales information +- Full Voxelab firmware source code +- Documents in Chinese or English (machine translated) + +Contact me on Discord (@shadow578) if you need it. + +## Dependencies + +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) + +## 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) diff --git a/Marlin/src/HAL/HC32/Servo.cpp b/Marlin/src/HAL/HC32/Servo.cpp new file mode 100644 index 0000000000..ce78572ef5 --- /dev/null +++ b/Marlin/src/HAL/HC32/Servo.cpp @@ -0,0 +1,84 @@ +/** + * Marlin 3D Printer Firmware + * Copyright (c) 2023 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] + * + * Based on Sprinter and grbl. + * Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +#ifdef ARDUINO_ARCH_HC32 + +#include "../../inc/MarlinConfig.h" + +#if HAS_SERVOS + +#include "Servo.h" + +static uint8_t servoCount = 0; +static MarlinServo *servos[NUM_SERVOS] = {0}; + +constexpr uint32_t servoDelays[] = SERVO_DELAY; +static_assert(COUNT(servoDelays) == NUM_SERVOS, "SERVO_DELAY must be an array NUM_SERVOS long."); + +// +// MarlinServo impl +// +MarlinServo::MarlinServo() { + this->channel = servoCount++; + servos[this->channel] = this; +} + +int8_t MarlinServo::attach(const pin_t apin) { + // Use last pin if pin not given + if (apin >= 0) this->pin = apin; + + // If attached, do nothing but no fail + if (this->servo.attached()) return 0; + + // Attach + const uint8_t rc = this->servo.attach(this->pin); + return rc == INVALID_SERVO ? -1 : rc; +} + +void MarlinServo::detach() { + this->servo.detach(); +} + +bool MarlinServo::attached() { + return this->servo.attached(); +} + +void MarlinServo::write(servo_angle_t angle) { + this->angle = angle; + this->servo.write(angle); +} + +void MarlinServo::move(servo_angle_t angle) { + // Attach with pin=-1 to use last pin attach() was called with + if (attach(-1) < 0) return; // Attach failed + + write(angle); + safe_delay(servoDelays[this->channel]); + TERN_(DEACTIVATE_SERVOS_AFTER_MOVE, detach()); +} + +servo_angle_t MarlinServo::read() { + return TERN(OPTIMISTIC_SERVO_READ, this->angle, this->servo.read()); +} + +#endif // HAS_SERVOS +#endif // ARDUINO_ARCH_HC32 diff --git a/Marlin/src/HAL/HC32/Servo.h b/Marlin/src/HAL/HC32/Servo.h new file mode 100644 index 0000000000..db2f60d190 --- /dev/null +++ b/Marlin/src/HAL/HC32/Servo.h @@ -0,0 +1,97 @@ +/** + * Marlin 3D Printer Firmware + * Copyright (c) 2023 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] + * + * Based on Sprinter and grbl. + * Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +#include "../../inc/MarlinConfigPre.h" + +#include + +/** + * return last written value in servo.read instead of calculated value + */ +#define OPTIMISTIC_SERVO_READ + +/** + * @brief servo lib wrapper for marlin + */ +class MarlinServo { +public: + MarlinServo(); + + /** + * @brief attach the pin to the servo, set pin mode, return channel number + * @param pin pin to attach to + * @return channel number, -1 if failed + */ + int8_t attach(const pin_t apin); + + /** + * @brief detach servo + */ + void detach(); + + /** + * @brief is servo attached? + */ + bool attached(); + + /** + * @brief set servo angle + * @param angle new angle + */ + void write(servo_angle_t angle); + + /** + * @brief attach servo, move to angle, delay then detach + * @param angle angle to move to + */ + void move(servo_angle_t angle); + + /** + * @brief read current angle + * @return current angle betwwne 0 and 180 degrees + */ + servo_angle_t read(); + +private: + /** + * @brief internal servo object, provided by arduino core + */ + Servo servo; + + /** + * @brief virtual servo channel + */ + uint8_t channel; + + /** + * @brief pin the servo attached to last + */ + pin_t pin; + + /** + * @brief last known servo angle + */ + servo_angle_t angle; +}; + +// Alias for marlin HAL +typedef MarlinServo hal_servo_t; diff --git a/Marlin/src/HAL/HC32/eeprom_bl24cxx.cpp b/Marlin/src/HAL/HC32/eeprom_bl24cxx.cpp new file mode 100644 index 0000000000..fe4a91384a --- /dev/null +++ b/Marlin/src/HAL/HC32/eeprom_bl24cxx.cpp @@ -0,0 +1,92 @@ +/** + * Marlin 3D Printer Firmware + * Copyright (c) 2023 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] + * + * Based on Sprinter and grbl. + * Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +/** + * PersistentStore for Arduino-style EEPROM interface + * with simple implementations supplied by Marlin. + */ +#ifdef ARDUINO_ARCH_HC32 + +#include "../../inc/MarlinConfig.h" + +#if ENABLED(IIC_BL24CXX_EEPROM) + +#include "../shared/eeprom_api.h" +#include "../shared/eeprom_if.h" + +#ifndef MARLIN_EEPROM_SIZE + #error "MARLIN_EEPROM_SIZE is required for IIC_BL24CXX_EEPROM." +#endif + +size_t PersistentStore::capacity() { return MARLIN_EEPROM_SIZE; } + +bool PersistentStore::access_start() { + eeprom_init(); + return true; +} + +bool PersistentStore::access_finish() { return true; } + +bool PersistentStore::write_data(int &pos, const uint8_t *value, size_t size, uint16_t *crc) { + while (size--) { + uint8_t v = *value; + uint8_t *const p = (uint8_t *const)pos; + + // EEPROM has only ~100,000 write cycles, + // so only write bytes that have changed! + if (v != eeprom_read_byte(p)) { + eeprom_write_byte(p, v); + delay(2); + if (eeprom_read_byte(p) != v) { + SERIAL_ECHO_MSG(STR_ERR_EEPROM_WRITE); + return true; + } + } + + crc16(crc, &v, 1); + pos++; + value++; + } + + return false; +} + +bool PersistentStore::read_data(int &pos, uint8_t *value, size_t size, + uint16_t *crc, const bool writing /*=true*/) { + do { + uint8_t *const p = (uint8_t *const)pos; + uint8_t c = eeprom_read_byte(p); + if (writing) + { + *value = c; + } + + crc16(crc, &c, 1); + pos++; + value++; + } while (--size); + + return false; +} + +#endif // IIC_BL24CXX_EEPROM +#endif // ARDUINO_ARCH_HC32 diff --git a/Marlin/src/HAL/HC32/eeprom_if_iic.cpp b/Marlin/src/HAL/HC32/eeprom_if_iic.cpp new file mode 100644 index 0000000000..02b1d3fd54 --- /dev/null +++ b/Marlin/src/HAL/HC32/eeprom_if_iic.cpp @@ -0,0 +1,51 @@ +/** + * Marlin 3D Printer Firmware + * Copyright (c) 2023 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] + * + * Based on Sprinter and grbl. + * Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +/** + * Platform-independent Arduino functions for I2C EEPROM. + * Enable USE_SHARED_EEPROM if not supplied by the framework. + */ +#ifdef ARDUINO_ARCH_HC32 + +#include "../../inc/MarlinConfig.h" + +#if ENABLED(IIC_BL24CXX_EEPROM) + +#include "../../libs/BL24CXX.h" +#include "../shared/eeprom_if.h" + +void eeprom_init() { + BL24CXX::init(); +} + +void eeprom_write_byte(uint8_t *pos, unsigned char value) { + const unsigned eeprom_address = (unsigned)pos; + return BL24CXX::writeOneByte(eeprom_address, value); +} + +uint8_t eeprom_read_byte(uint8_t *pos) { + const unsigned eeprom_address = (unsigned)pos; + return BL24CXX::readOneByte(eeprom_address); +} + +#endif // IIC_BL24CXX_EEPROM +#endif // ARDUINO_ARCH_HC32 diff --git a/Marlin/src/HAL/HC32/eeprom_sdcard.cpp b/Marlin/src/HAL/HC32/eeprom_sdcard.cpp new file mode 100644 index 0000000000..ec77c441a0 --- /dev/null +++ b/Marlin/src/HAL/HC32/eeprom_sdcard.cpp @@ -0,0 +1,98 @@ +/** + * Marlin 3D Printer Firmware + * Copyright (c) 2023 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] + * + * Based on Sprinter and grbl. + * Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (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 . + * + */ + +/** + * Implementation of EEPROM settings in SD Card + */ +#ifdef ARDUINO_ARCH_HC32 + +#include "../../inc/MarlinConfig.h" + +#if ENABLED(SDCARD_EEPROM_EMULATION) + +#include "../shared/eeprom_api.h" +#include "../../sd/cardreader.h" + +#define EEPROM_FILENAME "eeprom.dat" + +#ifndef MARLIN_EEPROM_SIZE + #define MARLIN_EEPROM_SIZE 0x1000 // 4KB +#endif + +size_t PersistentStore::capacity() { + return MARLIN_EEPROM_SIZE; +} + +#define _ALIGN(x) __attribute__((aligned(x))) +static char _ALIGN(4) HAL_eeprom_data[MARLIN_EEPROM_SIZE]; + +bool PersistentStore::access_start() { + if (!card.isMounted()) return false; + + MediaFile file, root = card.getroot(); + if (!file.open(&root, EEPROM_FILENAME, O_RDONLY)) + return true; // False aborts the save + + int bytes_read = file.read(HAL_eeprom_data, MARLIN_EEPROM_SIZE); + if (bytes_read < 0) return false; + + for (; bytes_read < MARLIN_EEPROM_SIZE; bytes_read++) + HAL_eeprom_data[bytes_read] = 0xFF; + + file.close(); + return true; +} + +bool PersistentStore::access_finish() { + if (!card.isMounted()) return false; + + MediaFile file, root = card.getroot(); + int bytes_written = 0; + if (file.open(&root, EEPROM_FILENAME, O_CREAT | O_WRITE | O_TRUNC)) { + bytes_written = file.write(HAL_eeprom_data, MARLIN_EEPROM_SIZE); + file.close(); + } + + return (bytes_written == MARLIN_EEPROM_SIZE); +} + +bool PersistentStore::write_data(int &pos, const uint8_t *value, size_t size, uint16_t *crc) { + for (size_t i = 0; i < size; i++) HAL_eeprom_data[pos + i] = value[i]; + + crc16(crc, value, size); + pos += size; + return false; +} + +bool PersistentStore::read_data(int &pos, uint8_t *value, const size_t size, uint16_t *crc, const bool writing /*=true*/) { + for (size_t i = 0; i < size; i++) { + uint8_t c = HAL_eeprom_data[pos + i]; + if (writing) value[i] = c; + crc16(crc, &c, 1); + } + + pos += size; + return false; +} + +#endif // SDCARD_EEPROM_EMULATION +#endif // ARDUINO_ARCH_HC32 diff --git a/Marlin/src/HAL/HC32/eeprom_wired.cpp b/Marlin/src/HAL/HC32/eeprom_wired.cpp new file mode 100644 index 0000000000..42c2563588 --- /dev/null +++ b/Marlin/src/HAL/HC32/eeprom_wired.cpp @@ -0,0 +1,94 @@ +/** + * Marlin 3D Printer Firmware + * Copyright (c) 2023 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ +#ifdef ARDUINO_ARCH_HC32 + +#include "../../inc/MarlinConfig.h" + +#if USE_WIRED_EEPROM + +#warning "SPI / I2C EEPROM has not been tested on HC32F460." + +/** + * PersistentStore for Arduino-style EEPROM interface + * with simple implementations supplied by Marlin. + */ + +#include "../shared/eeprom_if.h" +#include "../shared/eeprom_api.h" + +#ifndef MARLIN_EEPROM_SIZE + #error "MARLIN_EEPROM_SIZE is required for I2C / SPI EEPROM." +#endif +size_t PersistentStore::capacity() { return MARLIN_EEPROM_SIZE; } + +bool PersistentStore::access_finish() { return true; } + +bool PersistentStore::access_start() { + eeprom_init(); + #if ENABLED(SPI_EEPROM) + #if SPI_CHAN_EEPROM1 == 1 + SET_OUTPUT(BOARD_SPI1_SCK_PIN); + SET_OUTPUT(BOARD_SPI1_MOSI_PIN); + SET_INPUT(BOARD_SPI1_MISO_PIN); + SET_OUTPUT(SPI_EEPROM1_CS); + #endif + + spiInit(0); + #endif + return true; +} + +bool PersistentStore::write_data(int &pos, const uint8_t *value, size_t size, uint16_t *crc) { + while (size--) { + uint8_t *const p = (uint8_t *const)pos; + uint8_t v = *value; + // EEPROM has only ~100,000 write cycles, + // so only write bytes that have changed! + if (v != eeprom_read_byte(p)) { + eeprom_write_byte(p, v); + if (eeprom_read_byte(p) != v) { + SERIAL_ECHO_MSG(STR_ERR_EEPROM_WRITE); + return true; + } + } + crc16(crc, &v, 1); + pos++; + value++; + } + + return false; +} + +bool PersistentStore::read_data(int &pos, uint8_t *value, size_t size, uint16_t *crc, const bool writing /*=true*/) { + do { + uint8_t c = eeprom_read_byte((uint8_t *)pos); + if (writing && value) { + *value = c; + } + + crc16(crc, &c, 1); + pos++; + value++; + } while (--size); + + return false; +} + +#endif // USE_WIRED_EEPROM +#endif // ARDUINO_ARCH_HC32 diff --git a/Marlin/src/HAL/HC32/endstop_interrupts.cpp b/Marlin/src/HAL/HC32/endstop_interrupts.cpp new file mode 100644 index 0000000000..a976fa1d3c --- /dev/null +++ b/Marlin/src/HAL/HC32/endstop_interrupts.cpp @@ -0,0 +1,98 @@ +/** + * Marlin 3D Printer Firmware + * Copyright (c) 2023 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] + * + * Based on Sprinter and grbl. + * Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +#ifdef ARDUINO_ARCH_HC32 + +#include "endstop_interrupts.h" +#include "../../module/endstops.h" +#include + +#define ENDSTOP_IRQ_PRIORITY DDL_IRQ_PRIORITY_06 + +// +// IRQ handler +// +void endstopIRQHandler() { + bool flag = false; + + // Check all irq flags + #define CHECK(name) TERN_(USE_##name, flag |= checkIRQFlag(name##_PIN, /*clear*/ true)) + + CHECK(X_MAX); + CHECK(X_MIN); + + CHECK(Y_MAX); + CHECK(Y_MIN); + + CHECK(Z_MAX); + CHECK(Z_MIN); + + CHECK(Z2_MAX); + CHECK(Z2_MIN); + + CHECK(Z3_MAX); + CHECK(Z3_MIN); + + CHECK(Z_MIN_PROBE); + + // Update endstops + if (flag) endstops.update(); + + #undef CHECK +} + +// +// HAL functions +// +void setup_endstop_interrupts() { + #define SETUP(name) TERN_(USE_##name, attachInterrupt(name##_PIN, endstopIRQHandler, CHANGE); setInterruptPriority(name##_PIN, ENDSTOP_IRQ_PRIORITY)) + + SETUP(X_MAX); + SETUP(X_MIN); + + SETUP(Y_MAX); + SETUP(Y_MIN); + + SETUP(Z_MAX); + SETUP(Z_MIN); + + SETUP(Z2_MAX); + SETUP(Z2_MIN); + + SETUP(Z3_MAX); + SETUP(Z3_MIN); + + SETUP(Z_MIN_PROBE); + + #undef SETUP +} + +// Ensure 1 - 10 IRQs are registered +// Disable some endstops if you encounter this error +#define ENDSTOPS_INTERRUPTS_COUNT COUNT_ENABLED(USE_X_MAX, USE_X_MIN, USE_Y_MAX, USE_Y_MIN, USE_Z_MAX, USE_Z_MIN, USE_Z2_MAX, USE_Z2_MIN, USE_Z3_MAX, USE_Z3_MIN, USE_Z_MIN_PROBE) +#if ENDSTOPS_INTERRUPTS_COUNT > 10 + #error "Too many endstop interrupts! HC32F460 only supports 10 endstop interrupts." +#elif ENDSTOPS_INTERRUPTS_COUNT == 0 + #error "No endstop interrupts are enabled! Comment out this line to continue." +#endif + +#endif // ARDUINO_ARCH_HC32 diff --git a/Marlin/src/HAL/HC32/endstop_interrupts.h b/Marlin/src/HAL/HC32/endstop_interrupts.h new file mode 100644 index 0000000000..124f6f1a1b --- /dev/null +++ b/Marlin/src/HAL/HC32/endstop_interrupts.h @@ -0,0 +1,48 @@ +/** + * Marlin 3D Printer Firmware + * Copyright (c) 2023 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] + * + * Based on Sprinter and grbl. + * Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (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 + +/** + * Endstop interrupts for HC32F460 based targets. + * + * On HC32F460, all pins support external interrupt capability, with some restrictions. + * See the documentation of WInterrupts#attachInterrupt() for details. + * + * TL;DR + * any 16 pins can be used, but only one pin per EXTI line (so PA0 and PB0 are no-good). + */ + +/** + * Endstop Interrupts + * + * Without endstop interrupts the endstop pins must be polled continually in + * the temperature-ISR via endstops.update(), most of the time finding no change. + * With this feature endstops.update() is called only when we know that at + * least one endstop has changed state, saving valuable CPU cycles. + * + * This feature only works when all used endstop pins can generate an 'external interrupt'. + * + * Test whether pins issue interrupts on your board by flashing 'pin_interrupt_test.ino'. + * (Located in Marlin/buildroot/share/pin_interrupt_test/pin_interrupt_test.ino) + */ + +void setup_endstop_interrupts(); diff --git a/Marlin/src/HAL/HC32/fastio.h b/Marlin/src/HAL/HC32/fastio.h new file mode 100644 index 0000000000..af46866172 --- /dev/null +++ b/Marlin/src/HAL/HC32/fastio.h @@ -0,0 +1,69 @@ +/** + * Marlin 3D Printer Firmware + * Copyright (c) 2023 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] + * + * Based on Sprinter and grbl. + * Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ +#pragma once + +/** + * Fast I/O interfaces for HC32F460 + * These use GPIO functions instead of Direct Port Manipulation. + */ +#include +#include +#include + +#define READ(IO) (GPIO_GetBit(IO) ? HIGH : LOW) +#define WRITE(IO, V) (((V) > 0) ? GPIO_SetBits(IO) : GPIO_ResetBits(IO)) +#define TOGGLE(IO) (GPIO_Toggle(IO)) + +#define _GET_MODE(IO) getPinMode(IO) +#define _SET_MODE(IO, M) pinMode(IO, M) +#define _SET_OUTPUT(IO) _SET_MODE(IO, OUTPUT) + +#define OUT_WRITE(IO, V) \ + do { \ + _SET_OUTPUT(IO); \ + WRITE(IO, V); \ + } while (0) + +#define SET_INPUT(IO) _SET_MODE(IO, INPUT_FLOATING) +#define SET_INPUT_PULLUP(IO) _SET_MODE(IO, INPUT_PULLUP) +#define SET_INPUT_PULLDOWN(IO) _SET_MODE(IO, INPUT_PULLDOWN) +#define SET_OUTPUT(IO) OUT_WRITE(IO, LOW) +#define SET_PWM(IO) _SET_MODE(IO, OUTPUT_PWM) + +#define IS_INPUT(IO) ( \ + _GET_MODE(IO) == INPUT || \ + _GET_MODE(IO) == INPUT_FLOATING || \ + _GET_MODE(IO) == INPUT_ANALOG || \ + _GET_MODE(IO) == INPUT_PULLUP || \ + _GET_MODE(IO) == INPUT_PULLDOWN) + +#define IS_OUTPUT(IO) ( \ + _GET_MODE(IO) == OUTPUT || \ + _GET_MODE(IO) == OUTPUT_PWM || \ + _GET_MODE(IO) == OUTPUT_OPEN_DRAIN) + +#define PWM_PIN(IO) isAnalogWritePin(IO) + +#define extDigitalRead(IO) digitalRead(IO) +#define extDigitalWrite(IO, V) digitalWrite(IO, V) + +#define NO_COMPILE_TIME_PWM // Can't check for PWM at compile time diff --git a/Marlin/src/HAL/HC32/inc/Conditionals_LCD.h b/Marlin/src/HAL/HC32/inc/Conditionals_LCD.h new file mode 100644 index 0000000000..8266da4b2a --- /dev/null +++ b/Marlin/src/HAL/HC32/inc/Conditionals_LCD.h @@ -0,0 +1,26 @@ +/** + * Marlin 3D Printer Firmware + * Copyright (c) 2023 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] + * + * Based on Sprinter and grbl. + * Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ +#pragma once + +#if ALL(HAS_MARLINUI_U8GLIB, FORCE_SOFT_SPI) + #define U8G_SW_SPI_HC32 1 +#endif diff --git a/Marlin/src/HAL/HC32/inc/Conditionals_adv.h b/Marlin/src/HAL/HC32/inc/Conditionals_adv.h new file mode 100644 index 0000000000..06f15e5105 --- /dev/null +++ b/Marlin/src/HAL/HC32/inc/Conditionals_adv.h @@ -0,0 +1,26 @@ +/** + * Marlin 3D Printer Firmware + * Copyright (c) 2023 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] + * + * Based on Sprinter and grbl. + * Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (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 + +#ifndef TEMP_SOC_PIN + #define TEMP_SOC_PIN 0xFF // Dummy that is not a valid GPIO, HAL checks for this +#endif diff --git a/Marlin/src/HAL/HC32/inc/Conditionals_post.h b/Marlin/src/HAL/HC32/inc/Conditionals_post.h new file mode 100644 index 0000000000..bcffd5a8d5 --- /dev/null +++ b/Marlin/src/HAL/HC32/inc/Conditionals_post.h @@ -0,0 +1,34 @@ +/** + * Marlin 3D Printer Firmware + * Copyright (c) 2023 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] + * + * Based on Sprinter and grbl. + * Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ +#pragma once + +// If no real EEPROM, Flash emulation, or SRAM emulation is available fall back to SD emulation +#if USE_FALLBACK_EEPROM + #define SDCARD_EEPROM_EMULATION +#elif ANY(I2C_EEPROM, SPI_EEPROM) + #define USE_SHARED_EEPROM 1 +#endif + +// Allow SD support to be disabled +#if !HAS_MEDIA + #undef ONBOARD_SDIO +#endif diff --git a/Marlin/src/HAL/HC32/inc/SanityCheck.h b/Marlin/src/HAL/HC32/inc/SanityCheck.h new file mode 100644 index 0000000000..d7c6894039 --- /dev/null +++ b/Marlin/src/HAL/HC32/inc/SanityCheck.h @@ -0,0 +1,78 @@ +/** + * Marlin 3D Printer Firmware + * Copyright (c) 2023 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] + * + * Based on Sprinter and grbl. + * Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (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 + +#ifndef BOARD_XTAL_FREQUENCY + #error "BOARD_XTAL_FREQUENCY is required for HC32F460." +#endif + +#if ENABLED(FAST_PWM_FAN) + #error "FAST_PWM_FAN is not yet implemented for this platform." +#endif + +#if !defined(HAVE_SW_SERIAL) && HAS_TMC_SW_SERIAL + #error "Missing SoftwareSerial implementation." +#endif + +#if ENABLED(SDCARD_EEPROM_EMULATION) && !HAS_MEDIA + #undef SDCARD_EEPROM_EMULATION // Avoid additional error noise + #if USE_FALLBACK_EEPROM + #warning "EEPROM type not specified. Fallback is SDCARD_EEPROM_EMULATION." + #endif + + #error "SDCARD_EEPROM_EMULATION requires SDSUPPORT. Enable SDSUPPORT or choose another EEPROM emulation." +#endif + +#if ENABLED(SERIAL_STATS_MAX_RX_QUEUED) + #error "SERIAL_STATS_MAX_RX_QUEUED is not supported on this platform." +#elif ENABLED(SERIAL_STATS_DROPPED_RX) + #error "SERIAL_STATS_DROPPED_RX is not supported on this platform." +#endif + +#if ENABLED(NEOPIXEL_LED) && DISABLED(MKS_MINI_12864_V3) + #error "NEOPIXEL_LED (Adafruit NeoPixel) is not supported for HC32F460. Comment out this line to proceed at your own risk!" +#endif + +// Emergency Parser needs at least one serial with HardwareSerial. +#if ENABLED(EMERGENCY_PARSER) && ((SERIAL_PORT == -1 && !defined(SERIAL_PORT_2)) || (SERIAL_PORT_2 == -1 && !defined(SERIAL_PORT))) + #error "EMERGENCY_PARSER is only supported by HardwareSerial on HC32F460." +#endif + +#if TEMP_SENSOR_SOC + #if !defined(TEMP_SOC_PIN) + #error "TEMP_SOC_PIN must be defined to use TEMP_SENSOR_SOC." + #endif + + #if defined(TEMP_SOC_PIN) && IS_GPIO_PIN(TEMP_SOC_PIN) + #error "TEMP_SOC_PIN must not be a valid GPIO pin to avoid conflicts." + #endif +#endif + +#if ENABLED(POSTMORTEM_DEBUGGING) && !defined(CORE_DISABLE_FAULT_HANDLER) + #error "POSTMORTEM_DEBUGGING requires CORE_DISABLE_FAULT_HANDLER to be set." +#endif + +#if defined(PANIC_ENABLE) + #if defined(PANIC_USART1_TX_PIN) || defined(PANIC_USART2_TX_PIN) || defined(PANIC_USART3_TX_PIN) || defined(PANIC_USART3_TX_PIN) + #error "HC32 HAL uses a custom panic handler. Do not define PANIC_USARTx_TX_PIN." + #endif +#endif diff --git a/Marlin/src/HAL/HC32/pinsDebug.h b/Marlin/src/HAL/HC32/pinsDebug.h new file mode 100644 index 0000000000..1bee6ceb3e --- /dev/null +++ b/Marlin/src/HAL/HC32/pinsDebug.h @@ -0,0 +1,174 @@ +/** + * Marlin 3D Printer Firmware + * Copyright (c) 2023 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ +#pragma once + +#include "../../inc/MarlinConfig.h" +#include "fastio.h" +#include + +// +// Translation of routines & variables used by pinsDebug.h +// +#ifndef BOARD_NR_GPIO_PINS + #error "Expected BOARD_NR_GPIO_PINS not found." +#endif + +#define NUM_DIGITAL_PINS BOARD_NR_GPIO_PINS +#define NUMBER_PINS_TOTAL BOARD_NR_GPIO_PINS +#define VALID_PIN(pin) IS_GPIO_PIN(pin) + +// Note: pin_array is defined in `Marlin/src/pins/pinsDebug.h`, and since this file is included +// after it, it is available in this file as well. +#define GET_ARRAY_PIN(p) pin_t(pin_array[p].pin) +#define digitalRead_mod(p) extDigitalRead(p) +#define PRINT_PIN(p) \ + do { \ + sprintf_P(buffer, PSTR("%3hd "), int16_t(p)); \ + SERIAL_ECHO(buffer); \ + } while (0) +#define PRINT_PIN_ANALOG(p) \ + do { \ + sprintf_P(buffer, PSTR(" (A%2d) "), DIGITAL_PIN_TO_ANALOG_PIN(pin)); \ + SERIAL_ECHO(buffer); \ + } while (0) +#define PRINT_PORT(p) print_port(p) +#define PRINT_ARRAY_NAME(x) \ + do { \ + sprintf_P(buffer, PSTR("%-" STRINGIFY(MAX_NAME_LENGTH) "s"), pin_array[x].name); \ + SERIAL_ECHO(buffer); \ + } while (0) + +#define MULTI_NAME_PAD 21 // Space needed to be pretty if not first name assigned to a pin + +// +// Pins that will cause a hang / reset / disconnect in M43 Toggle and Watch utils +// +#ifndef M43_NEVER_TOUCH + // Don't touch any of the following pins: + // - Host serial pins, and + // - Pins that could be connected to oscillators (see datasheet, Table 2.1): + // - XTAL = PH0, PH1 + // - XTAL32 = PC14, PC15 + #define IS_HOST_USART_PIN(Q) (Q == BOARD_USART2_TX_PIN || Q == BOARD_USART2_RX_PIN) + #define IS_OSC_PIN(Q) (Q == PH0 || Q == PH1 || Q == PC14 || Q == PC15) + + #define M43_NEVER_TOUCH(Q) (IS_HOST_USART_PIN(Q) || IS_OSC_PIN(Q)) +#endif + +static pin_t DIGITAL_PIN_TO_ANALOG_PIN(pin_t pin) { + if (!VALID_PIN(pin)) return -1; + const int8_t adc_channel = int8_t(PIN_MAP[pin].adc_info.channel); + return pin_t(adc_channel); +} + +static bool IS_ANALOG(pin_t pin) { + if (!VALID_PIN(pin)) return false; + + if (PIN_MAP[pin].adc_info.channel != ADC_PIN_INVALID) + return _GET_MODE(pin) == INPUT_ANALOG && !M43_NEVER_TOUCH(pin); + + return false; +} + +static bool GET_PINMODE(const pin_t pin) { + return VALID_PIN(pin) && !IS_INPUT(pin); +} + +static bool GET_ARRAY_IS_DIGITAL(const int16_t array_pin) { + const pin_t pin = GET_ARRAY_PIN(array_pin); + return (!IS_ANALOG(pin)); +} + +/** + * @brief print pin PWM status + * @return true if pin is currently a PWM pin, false otherwise + */ +bool pwm_status(const pin_t pin) { + // Get timer assignment for pin + timera_config_t *unit; + en_timera_channel_t channel; + en_port_func_t port_function; + if (!timera_get_assignment(pin, unit, channel, port_function) || unit == nullptr) { + // No pwm pin or no unit assigned + return false; + } + + // A pin that is PWM output is: + // - Assigned to a timerA unit (tested above) + // - Unit is initialized + // - Channel is active + // - PinMode is OUTPUT_PWM + return timera_is_unit_initialized(unit) && timera_is_channel_active(unit, channel) && getPinMode(pin) == OUTPUT_PWM; +} + +void pwm_details(const pin_t pin) { + // Get timer assignment for pin + timera_config_t *unit; + en_timera_channel_t channel; + en_port_func_t port_function; + if (!timera_get_assignment(pin, unit, channel, port_function) || unit == nullptr) + return; // No pwm pin or no unit assigned + + // Print timer assignment of pin, eg. "TimerA1Ch2 Func4" + SERIAL_ECHOPGM("TimerA", TIMERA_REG_TO_X(unit->peripheral.register_base), + "Ch", TIMERA_CHANNEL_TO_X(channel), + " Func", int(port_function)); + SERIAL_ECHO_SP(3); // 3 spaces + + // Print timer unit state, eg. "1/16 PERAR=1234" OR "N/A" + if (timera_is_unit_initialized(unit)) { + // Unit initialized, print + // - Timer clock divider + // - Timer period value (PERAR) + const uint8_t clock_divider = timera_clk_div_to_n(unit->state.base_init->enClkDiv); + const uint16_t period = TIMERA_GetPeriodValue(unit->peripheral.register_base); + SERIAL_ECHOPGM("1/", clock_divider, " PERAR=", period); + } + else { + // Unit not initialized + SERIAL_ECHOPGM("N/A"); + return; + } + + SERIAL_ECHO_SP(3); // 3 spaces + + // Print timer channel state, e.g. "CMPAR=1234" OR "N/A" + if (timera_is_channel_active(unit, channel)) { + // Channel active, print + // - Channel compare value + const uint16_t compare = TIMERA_GetCompareValue(unit->peripheral.register_base, channel); + SERIAL_ECHOPGM("CMPAR=", compare); + } + else { + // Channel inactive + SERIAL_ECHOPGM("N/A"); + } +} + +void print_port(pin_t pin) { + const char port = 'A' + char(pin >> 4); // Pin div 16 + const int16_t gbit = PIN_MAP[pin].bit_pos; + char buffer[8]; + sprintf_P(buffer, PSTR("P%c%hd "), port, gbit); + if (gbit < 10) { + SERIAL_CHAR(' '); + } + + SERIAL_ECHO(buffer); +} diff --git a/Marlin/src/HAL/HC32/printf_retarget.cpp b/Marlin/src/HAL/HC32/printf_retarget.cpp new file mode 100644 index 0000000000..2c98415dff --- /dev/null +++ b/Marlin/src/HAL/HC32/printf_retarget.cpp @@ -0,0 +1,55 @@ +/** + * Marlin 3D Printer Firmware + * Copyright (c) 2023 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] + * + * Based on Sprinter and grbl. + * Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +#ifdef ARDUINO_ARCH_HC32 +#ifdef REDIRECT_PRINTF_TO_SERIAL + +#if !defined(__GNUC__) + #error "only GCC is supported" +#endif + +#include "../../inc/MarlinConfig.h" + +/** + * @brief implementation of _write that redirects everything to the host serial(s) + * @param file file descriptor. don't care + * @param ptr pointer to the data to write + * @param len length of the data to write + * @return number of bytes written + */ +extern "C" int _write(int file, char *ptr, int len) { + //SERIAL_ECHO_START(); // echo: + for (int i = 0; i < len; i++) SERIAL_CHAR(ptr[i]); + return len; +} + +/** + * @brief implementation of _isatty that always returns 1 + * @param file file descriptor. don't care + * @return everything is a tty. there are no files to be had + */ +extern "C" int _isatty(int file) { + return 1; +} + +#endif // REDIRECT_PRINTF_TO_SERIAL +#endif // ARDUINO_ARCH_HC32 diff --git a/Marlin/src/HAL/HC32/sdio.cpp b/Marlin/src/HAL/HC32/sdio.cpp new file mode 100644 index 0000000000..4360d715ff --- /dev/null +++ b/Marlin/src/HAL/HC32/sdio.cpp @@ -0,0 +1,137 @@ +/** + * Marlin 3D Printer Firmware + * Copyright (c) 2023 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] + * + * Based on Sprinter and grbl. + * Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +#ifdef ARDUINO_ARCH_HC32 + +#include "sdio.h" +#include +#include + +// +// SDIO configuration +// + +#define SDIO_PERIPHERAL M4_SDIOC1 + +// Use DMA2 channel 0 +#define SDIO_DMA_PERIPHERAL M4_DMA2 +#define SDIO_DMA_CHANNEL DmaCh0 + +// SDIO read/write operation retries and timeouts +#define SDIO_READ_RETRIES 3 +#define SDIO_READ_TIMEOUT 100 // ms + +#define SDIO_WRITE_RETRIES 1 +#define SDIO_WRITE_TIMEOUT 100 // ms + +// +// HAL functions +// + +#define WITH_RETRY(retries, fn) \ + for (int retry = 0; retry < (retries); retry++) { \ + MarlinHAL::watchdog_refresh(); \ + yield(); \ + fn \ + } + +stc_sd_handle_t *handle; + +bool SDIO_Init() { + // Configure SDIO pins + GPIO_SetFunc(BOARD_SDIO_D0, Func_Sdio); + GPIO_SetFunc(BOARD_SDIO_D1, Func_Sdio); + GPIO_SetFunc(BOARD_SDIO_D2, Func_Sdio); + GPIO_SetFunc(BOARD_SDIO_D3, Func_Sdio); + GPIO_SetFunc(BOARD_SDIO_CLK, Func_Sdio); + GPIO_SetFunc(BOARD_SDIO_CMD, Func_Sdio); + GPIO_SetFunc(BOARD_SDIO_DET, Func_Sdio); + + // Create DMA configuration + stc_sdcard_dma_init_t *dmaConf = new stc_sdcard_dma_init_t; + dmaConf->DMAx = SDIO_DMA_PERIPHERAL; + dmaConf->enDmaCh = SDIO_DMA_CHANNEL; + + // Create handle in DMA mode + handle = new stc_sd_handle_t; + handle->SDIOCx = SDIO_PERIPHERAL; + handle->enDevMode = SdCardDmaMode; + handle->pstcDmaInitCfg = dmaConf; + + // Create card configuration + // This should be a fairly safe configuration for most cards + stc_sdcard_init_t cardConf = { + .enBusWidth = SdiocBusWidth4Bit, + .enClkFreq = SdiocClk400K, + .enSpeedMode = SdiocNormalSpeedMode, + //.pstcInitCfg = NULL, + }; + + // Initialize sd card + en_result_t rc = SDCARD_Init(handle, &cardConf); + if (rc != Ok) printf("SDIO_Init() error (rc=%u)\n", rc); + + return rc == Ok; +} + +bool SDIO_ReadBlock(uint32_t block, uint8_t *dst) { + CORE_ASSERT(handle != NULL, "SDIO not initialized"); + CORE_ASSERT(dst != NULL, "SDIO_ReadBlock dst is NULL"); + + WITH_RETRY(SDIO_READ_RETRIES, { + en_result_t rc = SDCARD_ReadBlocks(handle, block, 1, dst, SDIO_READ_TIMEOUT); + if (rc == Ok) return true; + printf("SDIO_ReadBlock error (rc=%u; ErrorCode=%lu)\n", rc, handle->u32ErrorCode); + }) + + return false; +} + +bool SDIO_WriteBlock(uint32_t block, const uint8_t *src) { + CORE_ASSERT(handle != NULL, "SDIO not initialized"); + CORE_ASSERT(src != NULL, "SDIO_WriteBlock src is NULL"); + + WITH_RETRY(SDIO_WRITE_RETRIES, { + en_result_t rc = SDCARD_WriteBlocks(handle, block, 1, (uint8_t *)src, SDIO_WRITE_TIMEOUT); + if (rc == Ok) return true; + printf("SDIO_WriteBlock error (rc=%u; ErrorCode=%lu)\n", rc, handle->u32ErrorCode); + }) + + return false; +} + +bool SDIO_IsReady() { + CORE_ASSERT(handle != NULL, "SDIO not initialized"); + return bool(handle->stcCardStatus.READY_FOR_DATA); +} + +uint32_t SDIO_GetCardSize() { + CORE_ASSERT(handle != NULL, "SDIO not initialized"); + + // Multiply number of blocks with block size to get size in bytes + const uint64_t cardSizeBytes = uint64_t(handle->stcSdCardInfo.u32LogBlockNbr) * uint64_t(handle->stcSdCardInfo.u32LogBlockSize); + + // If the card is bigger than ~4Gb (maximum a 32bit integer can hold), clamp to the maximum value of a 32 bit integer + return _MAX(cardSizeBytes, UINT32_MAX); +} + +#endif // ARDUINO_ARCH_HC32 diff --git a/Marlin/src/HAL/HC32/sdio.h b/Marlin/src/HAL/HC32/sdio.h new file mode 100644 index 0000000000..89d4b061b1 --- /dev/null +++ b/Marlin/src/HAL/HC32/sdio.h @@ -0,0 +1,28 @@ +/** + * Marlin 3D Printer Firmware + * Copyright (c) 2023 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] + * Copyright (c) 2016 Bob Cousins bobcousins42@googlemail.com + * Copyright (c) 2017 Victor Perez + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ +#pragma once +#include "../../inc/MarlinConfig.h" + +bool SDIO_Init(); +bool SDIO_ReadBlock(uint32_t block, uint8_t *dst); +bool SDIO_WriteBlock(uint32_t block, const uint8_t *src); +bool SDIO_IsReady(); +uint32_t SDIO_GetCardSize(); diff --git a/Marlin/src/HAL/HC32/spi_pins.h b/Marlin/src/HAL/HC32/spi_pins.h new file mode 100644 index 0000000000..8a8e054b9b --- /dev/null +++ b/Marlin/src/HAL/HC32/spi_pins.h @@ -0,0 +1,19 @@ +/** + * Marlin 3D Printer Firmware + * Copyright (c) 2023 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ +#pragma once diff --git a/Marlin/src/HAL/HC32/sysclock.cpp b/Marlin/src/HAL/HC32/sysclock.cpp new file mode 100644 index 0000000000..d205d725cc --- /dev/null +++ b/Marlin/src/HAL/HC32/sysclock.cpp @@ -0,0 +1,124 @@ +/** + * Marlin 3D Printer Firmware + * Copyright (c) 2023 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] + * + * Based on Sprinter and grbl. + * Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (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 . + * + */ + +/** + * HC32f460 system clock configuration + */ + +#ifdef ARDUINO_ARCH_HC32 + +// Get BOARD_XTAL_FREQUENCY from configuration / pins +#include "../../inc/MarlinConfig.h" + +#include +#include + +void core_hook_sysclock_init() { + // Set wait cycles, as we are about to switch to 200 MHz HCLK + sysclock_configure_flash_wait_cycles(); + sysclock_configure_sram_wait_cycles(); + + // Configure MPLLp to 200 MHz output, with different settings depending on XTAL availability + #if BOARD_XTAL_FREQUENCY == 8000000 // 8 MHz XTAL + // - M = 1 => 8 MHz / 1 = 8 MHz + // - N = 50 => 8 MHz * 50 = 400 MHz + // - P = 2 => 400 MHz / 2 = 200 MHz (sysclk) + // - Q,R = 4 => 400 MHz / 4 = 100 MHz (dont care) + stc_clk_mpll_cfg_t pllConf = { + .PllpDiv = 2u, // P + .PllqDiv = 4u, // Q + .PllrDiv = 4u, // R + .plln = 50u, // N + .pllmDiv = 1u, // M + }; + sysclock_configure_xtal(); + sysclock_configure_mpll(ClkPllSrcXTAL, &pllConf); + + #elif BOARD_XTAL_FREQUENCY == 16000000 // 16 MHz XTAL + // - M = 1 => 16 MHz / 1 = 16 MHz + // - N = 50 => 16 MHz * 25 = 400 MHz + // - P = 2 => 400 MHz / 2 = 200 MHz (sysclk) + // - Q,R = 4 => 400 MHz / 4 = 100 MHz (dont care) + stc_clk_mpll_cfg_t pllConf = { + .PllpDiv = 2u, // P + .PllqDiv = 4u, // Q + .PllrDiv = 4u, // R + .plln = 50u, // N + .pllmDiv = 1u, // M + }; + sysclock_configure_xtal(); + sysclock_configure_mpll(ClkPllSrcXTAL, &pllConf); + + #warning "HC32F460 with 16 MHz XTAL has not been tested." + + #else // HRC (16 MHz) + // - M = 1 => 16 MHz / 1 = 16 MHz + // - N = 25 => 16 MHz * 25 = 400 MHz + // - P = 2 => 400 MHz / 2 = 200 MHz (sysclk) + // - Q,R = 4 => 400 MHz / 4 = 100 MHz (dont care) + stc_clk_mpll_cfg_t pllConf = { + .PllpDiv = 2u, // P + .PllqDiv = 4u, // Q + .PllrDiv = 4u, // R + .plln = 25u, // N + .pllmDiv = 1u, // M + }; + sysclock_configure_hrc(); + sysclock_configure_mpll(ClkPllSrcHRC, &pllConf); + + // HRC could have been configured by ICG to 20 MHz + // TODO: handle gracefully if HRC is not 16 MHz + if (1UL != (HRC_FREQ_MON() & 1UL)) { + panic("HRC is not 16 MHz"); + } + + #ifdef BOARD_XTAL_FREQUENCY + #warning "No valid XTAL frequency defined, falling back to HRC." + #endif + #endif + + // Setup clock divisors for sysclk = 200 MHz: + // Note: PCLK1 is used for step+temp timers, and need to be kept at 50 MHz (until there is a better solution) + stc_clk_sysclk_cfg_t sysClkConf = { + .enHclkDiv = ClkSysclkDiv1, // HCLK = 200 MHz (CPU) + .enExclkDiv = ClkSysclkDiv2, // EXCLK = 100 MHz (SDIO) + .enPclk0Div = ClkSysclkDiv1, // PCLK0 = 200 MHz (Timer6 (not used)) + .enPclk1Div = ClkSysclkDiv4, // PCLK1 = 50 MHz (USART, SPI, I2S, Timer0 (step+temp), TimerA (Servo)) + .enPclk2Div = ClkSysclkDiv4, // PCLK2 = 50 MHz (ADC) + .enPclk3Div = ClkSysclkDiv4, // PCLK3 = 50 MHz (I2C, WDT) + .enPclk4Div = ClkSysclkDiv2, // PCLK4 = 100 MHz (ADC ctl) + }; + sysclock_set_clock_dividers(&sysClkConf); + + // Set power mode + #define POWER_MODE_SYSTEM_CLOCK 200000000 // 200 MHz + power_mode_update_pre(POWER_MODE_SYSTEM_CLOCK); + + // Switch to MPLL as sysclk source + CLK_SetSysClkSource(CLKSysSrcMPLL); + + // Set power mode + power_mode_update_post(POWER_MODE_SYSTEM_CLOCK); + #undef POWER_MODE_SYSTEM_CLOCK +} + +#endif // ARDUINO_ARCH_HC32 diff --git a/Marlin/src/HAL/HC32/timers.cpp b/Marlin/src/HAL/HC32/timers.cpp new file mode 100644 index 0000000000..5f7d499622 --- /dev/null +++ b/Marlin/src/HAL/HC32/timers.cpp @@ -0,0 +1,54 @@ +/** + * Marlin 3D Printer Firmware + * Copyright (c) 2023 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] + * + * Based on Sprinter and grbl. + * Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +#ifdef ARDUINO_ARCH_HC32 + +#include "timers.h" +#include + +/** + * Timer0 Unit 2 Channel A is used for Temperature interrupts + */ +Timer0 temp_timer(&TIMER02A_config, &Temp_Handler); + +/** + * Timer0 Unit 2 Channel B is used for Step interrupts + */ +Timer0 step_timer(&TIMER02B_config, &Step_Handler); + +void HAL_timer_start(const timer_channel_t timer_num, const uint32_t frequency) { + if (timer_num == TEMP_TIMER_NUM) { + CORE_DEBUG_PRINTF("HAL_timer_start: temp timer, f=%ld\n", long(frequency)); + timer_num->start(frequency, TEMP_TIMER_PRESCALE); + timer_num->setCallbackPriority(TEMP_TIMER_PRIORITY); + } + else if (timer_num == STEP_TIMER_NUM) { + CORE_DEBUG_PRINTF("HAL_timer_start: step timer, f=%ld\n", long(frequency)); + timer_num->start(frequency, STEPPER_TIMER_PRESCALE); + timer_num->setCallbackPriority(STEP_TIMER_PRIORITY); + } + else { + CORE_ASSERT_FAIL("HAL_timer_start: invalid timer_num") + } +} + +#endif // ARDUINO_ARCH_HC32 diff --git a/Marlin/src/HAL/HC32/timers.h b/Marlin/src/HAL/HC32/timers.h new file mode 100644 index 0000000000..17d8967982 --- /dev/null +++ b/Marlin/src/HAL/HC32/timers.h @@ -0,0 +1,135 @@ +/** + * Marlin 3D Printer Firmware + * Copyright (c) 2023 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] + * Copyright (c) 2016 Bob Cousins bobcousins42@googlemail.com + * Copyright (c) 2017 Victor Perez + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#pragma once +#include +#include + +// +// Timer Types +// +typedef Timer0 *timer_channel_t; +typedef uint16_t hal_timer_t; +#define HAL_TIMER_TYPE_MAX 0xFFFF + +// +// Timer instances +// +extern Timer0 temp_timer; +extern Timer0 step_timer; + +// +// Timer Configurations +// + +// TODO: some calculations (step irq min_step_rate) require the timer rate to be known at compile time +// this is not possible with the HC32F460, as the timer rate depends on PCLK1 +// as a workaround, PCLK1 = 50MHz is assumed (check with clock dump in MarlinHAL::init()) +#define HAL_TIMER_RATE 50000000 // 50MHz +// #define HAL_TIMER_RATE TIMER0_BASE_FREQUENCY + +// TODO: CYCLES_PER_MICROSECOND seems to be used by Marlin to calculate the number of cycles per microsecond in the timer ISRs +// by default, it uses F_CPU, but since that is not known at compile time for HC32, we overwrite it here +#undef CYCLES_PER_MICROSECOND +#define CYCLES_PER_MICROSECOND (HAL_TIMER_RATE / 1000000UL) + +// Temperature timer +#define TEMP_TIMER_NUM (&temp_timer) +#define TEMP_TIMER_PRIORITY DDL_IRQ_PRIORITY_02 +#define TEMP_TIMER_PRESCALE 16ul +#define TEMP_TIMER_RATE 1000 // 1kHz +#define TEMP_TIMER_FREQUENCY TEMP_TIMER_RATE // Alias for Marlin + +// Stepper timer +#define STEP_TIMER_NUM (&step_timer) +#define STEP_TIMER_PRIORITY DDL_IRQ_PRIORITY_01 +#define STEPPER_TIMER_PRESCALE 16ul + +// TODO: STEPPER_TIMER_RATE seems to work fine like this, but requires further testing... +#define STEPPER_TIMER_RATE (HAL_TIMER_RATE / STEPPER_TIMER_PRESCALE) // 50MHz / 16 = 3.125MHz +#define STEPPER_TIMER_TICKS_PER_US (STEPPER_TIMER_RATE / 1000000) + +// Pulse timer (== stepper timer) +#define PULSE_TIMER_NUM STEP_TIMER_NUM +#define PULSE_TIMER_PRESCALE STEPPER_TIMER_PRESCALE +#define PULSE_TIMER_TICKS_PER_US STEPPER_TIMER_TICKS_PER_US + +// +// Channel aliases +// +#define MF_TIMER_TEMP TEMP_TIMER_NUM +#define MF_TIMER_STEP STEP_TIMER_NUM +#define MF_TIMER_PULSE PULSE_TIMER_NUM + +// +// HAL functions +// +void HAL_timer_start(const timer_channel_t timer_num, const uint32_t frequency); + +// Inlined since they are somewhat critical +#define MARLIN_HAL_TIMER_INLINE_ATTR __attribute__((always_inline)) inline + +MARLIN_HAL_TIMER_INLINE_ATTR void HAL_timer_enable_interrupt(const timer_channel_t timer_num) { + timer_num->resume(); +} + +MARLIN_HAL_TIMER_INLINE_ATTR void HAL_timer_disable_interrupt(const timer_channel_t timer_num) { + timer_num->pause(); +} + +MARLIN_HAL_TIMER_INLINE_ATTR bool HAL_timer_interrupt_enabled(const timer_channel_t timer_num) { + return timer_num->isPaused(); +} + +MARLIN_HAL_TIMER_INLINE_ATTR void HAL_timer_set_compare(const timer_channel_t timer_num, const hal_timer_t compare) { + timer_num->setCompareValue(compare); +} + +MARLIN_HAL_TIMER_INLINE_ATTR hal_timer_t HAL_timer_get_count(const timer_channel_t timer_num) { + return timer_num->getCount(); +} + +MARLIN_HAL_TIMER_INLINE_ATTR void HAL_timer_isr_prologue(const timer_channel_t timer_num) { + timer_num->clearInterruptFlag(); +} + +MARLIN_HAL_TIMER_INLINE_ATTR void HAL_timer_isr_epilogue(const timer_channel_t timer_num) {} + +// +// HAL function aliases +// +#define ENABLE_STEPPER_DRIVER_INTERRUPT() HAL_timer_enable_interrupt(STEP_TIMER_NUM) +#define DISABLE_STEPPER_DRIVER_INTERRUPT() HAL_timer_disable_interrupt(STEP_TIMER_NUM) +#define STEPPER_ISR_ENABLED() HAL_timer_interrupt_enabled(STEP_TIMER_NUM) + +#define ENABLE_TEMPERATURE_INTERRUPT() HAL_timer_enable_interrupt(TEMP_TIMER_NUM) +#define DISABLE_TEMPERATURE_INTERRUPT() HAL_timer_disable_interrupt(TEMP_TIMER_NUM); + +// +// HAL ISR callbacks +// +void Step_Handler(); +void Temp_Handler(); + +#ifndef HAL_STEP_TIMER_ISR +#define HAL_STEP_TIMER_ISR() void Step_Handler() +#endif +#ifndef HAL_TEMP_TIMER_ISR +#define HAL_TEMP_TIMER_ISR() void Temp_Handler() +#endif diff --git a/Marlin/src/HAL/HC32/u8g/LCD_defines.h b/Marlin/src/HAL/HC32/u8g/LCD_defines.h new file mode 100644 index 0000000000..cb5a6812ef --- /dev/null +++ b/Marlin/src/HAL/HC32/u8g/LCD_defines.h @@ -0,0 +1,29 @@ +/** + * Marlin 3D Printer Firmware + * Copyright (c) 2023 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] + * + * Based on Sprinter and grbl. + * Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (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 + +/** + * HC32 LCD-specific defines + */ + +uint8_t u8g_com_HAL_HC32_sw_spi_fn(u8g_t *u8g, uint8_t msg, uint8_t arg_val, void *arg_ptr); +#define U8G_COM_HAL_SW_SPI_FN u8g_com_HAL_HC32_sw_spi_fn diff --git a/Marlin/src/HAL/HC32/u8g/u8g_com_HAL_HC32_sw_spi.cpp b/Marlin/src/HAL/HC32/u8g/u8g_com_HAL_HC32_sw_spi.cpp new file mode 100644 index 0000000000..9f36096194 --- /dev/null +++ b/Marlin/src/HAL/HC32/u8g/u8g_com_HAL_HC32_sw_spi.cpp @@ -0,0 +1,163 @@ +/** + * Marlin 3D Printer Firmware + * Copyright (c) 2023 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] + * + * Based on Sprinter and grbl. + * Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +#ifdef ARDUINO_ARCH_HC32 + +#include "../../../inc/MarlinConfig.h" + +#if U8G_SW_SPI_HC32 + +#warning "Software SPI for U8Glib is experimental on HC32F460. Please share your experiences at https://github.com/shadow578/Marlin-H32/issues/35" + +#include +#include "../../shared/HAL_SPI.h" + +#ifndef LCD_SPI_SPEED + #define LCD_SPI_SPEED SPI_FULL_SPEED // Fastest + //#define LCD_SPI_SPEED SPI_QUARTER_SPEED // Slower +#endif + +static uint8_t SPI_speed = LCD_SPI_SPEED; + +static inline uint8_t swSpiTransfer_mode_0(uint8_t b, const uint8_t spi_speed, const pin_t miso_pin=-1) { + for (i = 0; i < 8; ++i) { + if (spi_speed == 0) { + WRITE(DOGLCD_MOSI, !!(b & 0x80)); + WRITE(DOGLCD_SCK, HIGH); + b <<= 1; + if (miso_pin >= 0 && READ(miso_pin)) b |= 1; + WRITE(DOGLCD_SCK, LOW); + } + else { + const uint8_t state = (b & 0x80) ? HIGH : LOW; + for (j = 0; j < spi_speed; ++j) WRITE(DOGLCD_MOSI, state); + for (j = 0; j < spi_speed + (miso_pin >= 0 ? 0 : 1; ++j)) WRITE(DOGLCD_SCK, HIGH); + + b <<= 1; + if (miso_pin >= 0 && READ(miso_pin)) b |= 1; + + for (j = 0; j < spi_speed; ++j) WRITE(DOGLCD_SCK, LOW); + } + } + return b; +} + +static inline uint8_t swSpiTransfer_mode_3(uint8_t b, const uint8_t spi_speed, const pin_t miso_pin=-1) { + for (i = 0; i < 8; ++i) { + const uint8_t state = (b & 0x80) ? HIGH : LOW; + if (spi_speed == 0) { + WRITE(DOGLCD_SCK, LOW); + WRITE(DOGLCD_MOSI, state); + WRITE(DOGLCD_MOSI, state); // need some setup time + WRITE(DOGLCD_SCK, HIGH); + } + else { + for (j = 0; j < spi_speed + (miso_pin >= 0 ? 0 : 1); ++j) WRITE(DOGLCD_SCK, LOW); + for (j = 0; j < spi_speed; ++j) WRITE(DOGLCD_MOSI, state); + for (j = 0; j < spi_speed; ++j) WRITE(DOGLCD_SCK, HIGH); + } + b <<= 1; + if (miso_pin >= 0 && READ(miso_pin)) b |= 1; + } + return b; +} + +static void u8g_sw_spi_shift_out(uint8_t val) { + #if ANY(FYSETC_MINI_12864, MKS_MINI_12864) + swSpiTransfer_mode_3(val, SPI_speed); + #else + swSpiTransfer_mode_0(val, SPI_speed); + #endif +} + +static uint8_t swSpiInit(const uint8_t spi_speed) { + #if PIN_EXISTS(LCD_RESET) + SET_OUTPUT(LCD_RESET_PIN); + #endif + SET_OUTPUT(DOGLCD_A0); + OUT_WRITE(DOGLCD_SCK, LOW); + OUT_WRITE(DOGLCD_MOSI, LOW); + OUT_WRITE(DOGLCD_CS, HIGH); + return spi_speed; +} + +uint8_t u8g_com_HAL_HC32_sw_spi_fn(u8g_t *u8g, uint8_t msg, uint8_t arg_val, void *arg_ptr) { + switch (msg) { + case U8G_COM_MSG_INIT: + SPI_speed = swSpiInit(LCD_SPI_SPEED); + break; + + case U8G_COM_MSG_STOP: + break; + + case U8G_COM_MSG_RESET: + #if PIN_EXISTS(LCD_RESET) + WRITE(LCD_RESET_PIN, arg_val); + #endif + break; + + case U8G_COM_MSG_CHIP_SELECT: + #if ANY(FYSETC_MINI_12864, MKS_MINI_12864) // This LCD SPI is running mode 3 while SD card is running mode 0 + if (arg_val) { // SCK idle state needs to be set to the proper idle state before + // the next chip select goes active + WRITE(DOGLCD_SCK, HIGH); // Set SCK to mode 3 idle state before CS goes active + WRITE(DOGLCD_CS, LOW); + } + else { + WRITE(DOGLCD_CS, HIGH); + WRITE(DOGLCD_SCK, LOW); // Set SCK to mode 0 idle state after CS goes inactive + } + #else + WRITE(DOGLCD_CS, !arg_val); + #endif + break; + + case U8G_COM_MSG_WRITE_BYTE: + u8g_sw_spi_shift_out(arg_val); + break; + + case U8G_COM_MSG_WRITE_SEQ: { + uint8_t *ptr = (uint8_t *)arg_ptr; + while (arg_val > 0) { + u8g_sw_spi_shift_out(*ptr++); + arg_val--; + } + } break; + + case U8G_COM_MSG_WRITE_SEQ_P: { + uint8_t *ptr = (uint8_t *)arg_ptr; + while (arg_val > 0) { + u8g_sw_spi_shift_out(u8g_pgm_read(ptr)); + ptr++; + arg_val--; + } + } break; + + case U8G_COM_MSG_ADDRESS: /* define cmd (arg_val = 0) or data mode (arg_val = 1) */ + WRITE(DOGLCD_A0, arg_val); + break; + } + return 1; +} + +#endif // U8G_SW_SPI_HC32 +#endif // ARDUINO_ARCH_HC32 diff --git a/Marlin/src/HAL/LINUX/HAL.cpp b/Marlin/src/HAL/LINUX/HAL.cpp index db43f42eaa..6a767c76e7 100644 --- a/Marlin/src/HAL/LINUX/HAL.cpp +++ b/Marlin/src/HAL/LINUX/HAL.cpp @@ -52,8 +52,7 @@ uint8_t MarlinHAL::active_ch = 0; uint16_t MarlinHAL::adc_value() { const pin_t pin = analogInputToDigitalPin(active_ch); if (!VALID_PIN(pin)) return 0; - const uint16_t data = ((Gpio::get(pin) >> 2) & 0x3FF); - return data; // return 10bit value as Marlin expects + return uint16_t((Gpio::get(pin) >> 2) & 0x3FF); // return 10bit value as Marlin expects } void MarlinHAL::reboot() { /* Reset the application state and GPIO */ } diff --git a/Marlin/src/HAL/LINUX/HAL.h b/Marlin/src/HAL/LINUX/HAL.h index 22c3e521f0..e84516d4dc 100644 --- a/Marlin/src/HAL/LINUX/HAL.h +++ b/Marlin/src/HAL/LINUX/HAL.h @@ -1,9 +1,9 @@ /** * Marlin 3D Printer Firmware - * * Copyright (c) 2020 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] - * Copyright (c) 2016 Bob Cousins bobcousins42@googlemail.com - * Copyright (c) 2015-2016 Nico Tonnhofer wurstnase.reprap@gmail.com + * + * 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 @@ -80,8 +80,8 @@ extern MSerialT usb_serial; #define CRITICAL_SECTION_END() // ADC -#define HAL_ADC_VREF 5.0 -#define HAL_ADC_RESOLUTION 10 +#define HAL_ADC_VREF_MV 5000 +#define HAL_ADC_RESOLUTION 10 // ------------------------ // Class Utilities diff --git a/Marlin/src/HAL/LINUX/inc/Conditionals_LCD.h b/Marlin/src/HAL/LINUX/inc/Conditionals_LCD.h index 99a6fc2753..5f1c4b1601 100644 --- a/Marlin/src/HAL/LINUX/inc/Conditionals_LCD.h +++ b/Marlin/src/HAL/LINUX/inc/Conditionals_LCD.h @@ -20,7 +20,3 @@ * */ #pragma once - -#if HAS_SPI_TFT || HAS_FSMC_TFT - #error "Sorry! TFT displays are not available for HAL/LINUX." -#endif diff --git a/Marlin/src/HAL/LINUX/inc/SanityCheck.h b/Marlin/src/HAL/LINUX/inc/SanityCheck.h index 36d3190a3e..861bade10f 100644 --- a/Marlin/src/HAL/LINUX/inc/SanityCheck.h +++ b/Marlin/src/HAL/LINUX/inc/SanityCheck.h @@ -31,13 +31,17 @@ #endif #if ENABLED(FAST_PWM_FAN) || SPINDLE_LASER_FREQUENCY - #error "Features requiring Hardware PWM (FAST_PWM_FAN, SPINDLE_LASER_FREQUENCY) are not yet supported on LINUX." + #error "Features requiring Hardware PWM (FAST_PWM_FAN, SPINDLE_LASER_FREQUENCY) are not yet supported for HAL/LINUX." +#endif + +#if HAS_SPI_TFT || HAS_FSMC_TFT + #error "Sorry! TFT displays are not available for HAL/LINUX." #endif #if HAS_TMC_SW_SERIAL - #error "TMC220x Software Serial is not supported on LINUX." + #error "TMC220x Software Serial is not supported for HAL/LINUX." #endif #if ENABLED(POSTMORTEM_DEBUGGING) - #error "POSTMORTEM_DEBUGGING is not yet supported on LINUX." + #error "POSTMORTEM_DEBUGGING is not yet supported for HAL/LINUX." #endif diff --git a/Marlin/src/HAL/LINUX/include/Arduino.h b/Marlin/src/HAL/LINUX/include/Arduino.h index f05aaed880..6e9c80ee07 100644 --- a/Marlin/src/HAL/LINUX/include/Arduino.h +++ b/Marlin/src/HAL/LINUX/include/Arduino.h @@ -28,6 +28,9 @@ #include +#define strlcpy(A, B, C) strncpy(A, B, (C) - 1) +#define strlcpy_P(A, B, C) strncpy_P(A, B, (C) - 1) + #define HIGH 0x01 #define LOW 0x00 diff --git a/Marlin/src/HAL/LINUX/pinsDebug.h b/Marlin/src/HAL/LINUX/pinsDebug.h index 7bfd97d024..e4ee27e8dd 100644 --- a/Marlin/src/HAL/LINUX/pinsDebug.h +++ b/Marlin/src/HAL/LINUX/pinsDebug.h @@ -28,36 +28,33 @@ * Translation of routines & variables used by pinsDebug.h */ -#define NUMBER_PINS_TOTAL NUM_DIGITAL_PINS -#define pwm_details(pin) NOOP // (do nothing) -#define pwm_status(pin) false // Print a pin's PWM status. Return true if it's currently a PWM pin. +#define NUMBER_PINS_TOTAL NUM_DIGITAL_PINS #define IS_ANALOG(P) (DIGITAL_PIN_TO_ANALOG_PIN(P) >= 0 ? 1 : 0) #define digitalRead_mod(p) digitalRead(p) -#define PRINT_PORT(p) #define GET_ARRAY_PIN(p) pin_array[p].pin #define PRINT_ARRAY_NAME(x) do{ sprintf_P(buffer, PSTR("%-" STRINGIFY(MAX_NAME_LENGTH) "s"), pin_array[x].name); SERIAL_ECHO(buffer); }while(0) #define PRINT_PIN(p) do{ sprintf_P(buffer, PSTR("%3d "), p); SERIAL_ECHO(buffer); }while(0) #define PRINT_PIN_ANALOG(p) do{ sprintf_P(buffer, PSTR(" (A%2d) "), DIGITAL_PIN_TO_ANALOG_PIN(pin)); SERIAL_ECHO(buffer); }while(0) -#define MULTI_NAME_PAD 16 // space needed to be pretty if not first name assigned to a pin +#define MULTI_NAME_PAD 16 // space needed to be pretty if not first name assigned to a pin // active ADC function/mode/code values for PINSEL registers -constexpr int8_t ADC_pin_mode(pin_t pin) { - return (-1); -} +constexpr int8_t ADC_pin_mode(pin_t pin) { return -1; } -int8_t get_pin_mode(pin_t pin) { - if (!VALID_PIN(pin)) return -1; - return 0; -} +int8_t get_pin_mode(const pin_t pin) { return VALID_PIN(pin) ? 0 : -1; } -bool GET_PINMODE(pin_t pin) { - int8_t pin_mode = get_pin_mode(pin); - if (pin_mode == -1 || pin_mode == ADC_pin_mode(pin)) // found an invalid pin or active analog pin +bool GET_PINMODE(const pin_t pin) { + const int8_t pin_mode = get_pin_mode(pin); + if (pin_mode == -1 || pin_mode == ADC_pin_mode(pin)) // Invalid pin or active analog pin return false; - return (Gpio::getMode(pin) != 0); //input/output state + return (Gpio::getMode(pin) != 0); // Input/output state } -bool GET_ARRAY_IS_DIGITAL(pin_t pin) { +bool GET_ARRAY_IS_DIGITAL(const pin_t pin) { return (!IS_ANALOG(pin) || get_pin_mode(pin) != ADC_pin_mode(pin)); } + +void pwm_details(const pin_t pin) {} +bool pwm_status(const pin_t) { return false; } + +void print_port(const pin_t) {} diff --git a/Marlin/src/HAL/LINUX/spi_pins.h b/Marlin/src/HAL/LINUX/spi_pins.h index 33136ac9dd..7bd2498be7 100644 --- a/Marlin/src/HAL/LINUX/spi_pins.h +++ b/Marlin/src/HAL/LINUX/spi_pins.h @@ -24,11 +24,11 @@ #include "../../core/macros.h" #include "../../inc/MarlinConfigPre.h" -#if BOTH(HAS_MARLINUI_U8GLIB, SDSUPPORT) && (LCD_PINS_D4 == SD_SCK_PIN || LCD_PINS_ENABLE == SD_MOSI_PIN || DOGLCD_SCK == SD_SCK_PIN || DOGLCD_MOSI == SD_MOSI_PIN) - #define LPC_SOFTWARE_SPI // If the SD card and LCD adapter share the same SPI pins, then software SPI is currently - // needed due to the speed and mode required for communicating with each device being different. - // This requirement can be removed if the SPI access to these devices is updated to use - // spiBeginTransaction. +#if ALL(HAS_MARLINUI_U8GLIB, HAS_MEDIA) && (LCD_PINS_D4 == SD_SCK_PIN || LCD_PINS_EN == SD_MOSI_PIN || DOGLCD_SCK == SD_SCK_PIN || DOGLCD_MOSI == SD_MOSI_PIN) + #define SOFTWARE_SPI // If the SD card and LCD adapter share the same SPI pins, then software SPI is currently + // needed due to the speed and mode required for communicating with each device being different. + // This requirement can be removed if the SPI access to these devices is updated to use + // spiBeginTransaction. #endif // Onboard SD diff --git a/Marlin/src/HAL/LINUX/timers.cpp b/Marlin/src/HAL/LINUX/timers.cpp index 66d80f2518..a8ab403197 100644 --- a/Marlin/src/HAL/LINUX/timers.cpp +++ b/Marlin/src/HAL/LINUX/timers.cpp @@ -1,9 +1,9 @@ /** * Marlin 3D Printer Firmware - * * Copyright (c) 2020 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] - * Copyright (c) 2016 Bob Cousins bobcousins42@googlemail.com - * Copyright (c) 2015-2016 Nico Tonnhofer wurstnase.reprap@gmail.com + * + * 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 diff --git a/Marlin/src/HAL/LINUX/timers.h b/Marlin/src/HAL/LINUX/timers.h index 2d2a95774c..2b29edce0b 100644 --- a/Marlin/src/HAL/LINUX/timers.h +++ b/Marlin/src/HAL/LINUX/timers.h @@ -1,8 +1,9 @@ /** * Marlin 3D Printer Firmware - * * Copyright (c) 2020 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] - * Copyright (c) 2016 Bob Cousins bobcousins42@googlemail.com + * + * 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 diff --git a/Marlin/src/HAL/LINUX/u8g/LCD_defines.h b/Marlin/src/HAL/LINUX/u8g/LCD_defines.h new file mode 100644 index 0000000000..6caa0240ca --- /dev/null +++ b/Marlin/src/HAL/LINUX/u8g/LCD_defines.h @@ -0,0 +1,26 @@ +/** + * Marlin 3D Printer Firmware + * Copyright (c) 2023 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] + * + * Based on Sprinter and grbl. + * Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (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 + +/** + * Linux LCD-specific defines + */ diff --git a/Marlin/src/HAL/LPC1768/HAL.cpp b/Marlin/src/HAL/LPC1768/HAL.cpp index 9ff3a6ba59..6fada12486 100644 --- a/Marlin/src/HAL/LPC1768/HAL.cpp +++ b/Marlin/src/HAL/LPC1768/HAL.cpp @@ -23,11 +23,22 @@ #include "../../inc/MarlinConfig.h" #include "../shared/Delay.h" -#include "../../../gcode/parser.h" +#include "../../core/millis_t.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include DefaultSerial1 USBSerial(false, UsbSerial); uint32_t MarlinHAL::adc_result = 0; +pin_t MarlinHAL::adc_pin = 0; // U8glib required functions extern "C" { @@ -48,6 +59,132 @@ int freeMemory() { return result; } +extern "C" { + #include + int isLPC1769(); + void disk_timerproc(); +} + +extern uint32_t MSC_SD_Init(uint8_t pdrv); + +void SysTick_Callback() { disk_timerproc(); } + +TERN_(POSTMORTEM_DEBUGGING, extern void install_min_serial()); + +void MarlinHAL::init() { + + // Init LEDs + #if PIN_EXISTS(LED) + SET_DIR_OUTPUT(LED_PIN); + WRITE_PIN_CLR(LED_PIN); + #if PIN_EXISTS(LED2) + SET_DIR_OUTPUT(LED2_PIN); + WRITE_PIN_CLR(LED2_PIN); + #if PIN_EXISTS(LED3) + SET_DIR_OUTPUT(LED3_PIN); + WRITE_PIN_CLR(LED3_PIN); + #if PIN_EXISTS(LED4) + SET_DIR_OUTPUT(LED4_PIN); + WRITE_PIN_CLR(LED4_PIN); + #endif + #endif + #endif + + // Flash status LED 3 times to indicate Marlin has started booting + for (uint8_t i = 0; i < 6; ++i) { + TOGGLE(LED_PIN); + delay(100); + } + #endif + + // Init Servo Pins + #define INIT_SERVO(N) OUT_WRITE(SERVO##N##_PIN, LOW) + #if HAS_SERVO_0 + INIT_SERVO(0); + #endif + #if HAS_SERVO_1 + INIT_SERVO(1); + #endif + #if HAS_SERVO_2 + INIT_SERVO(2); + #endif + #if HAS_SERVO_3 + INIT_SERVO(3); + #endif + + //debug_frmwrk_init(); + //_DBG("\n\nDebug running\n"); + // Initialize the SD card chip select pins as soon as possible + #if PIN_EXISTS(SD_SS) + OUT_WRITE(SD_SS_PIN, HIGH); + #endif + + #if PIN_EXISTS(ONBOARD_SD_CS) && ONBOARD_SD_CS_PIN != SD_SS_PIN + OUT_WRITE(ONBOARD_SD_CS_PIN, HIGH); + #endif + + #ifdef LPC1768_ENABLE_CLKOUT_12M + /** + * CLKOUTCFG register + * bit 8 (CLKOUT_EN) = enables CLKOUT signal. Disabled for now to prevent glitch when enabling GPIO. + * bits 7:4 (CLKOUTDIV) = set to 0 for divider setting of /1 + * bits 3:0 (CLKOUTSEL) = set to 1 to select main crystal oscillator as CLKOUT source + */ + LPC_SC->CLKOUTCFG = (0<<8)|(0<<4)|(1<<0); + // set P1.27 pin to function 01 (CLKOUT) + PINSEL_CFG_Type PinCfg; + PinCfg.Portnum = 1; + PinCfg.Pinnum = 27; + PinCfg.Funcnum = 1; // function 01 (CLKOUT) + PinCfg.OpenDrain = 0; // not open drain + PinCfg.Pinmode = 2; // no pull-up/pull-down + PINSEL_ConfigPin(&PinCfg); + // now set CLKOUT_EN bit + SBI(LPC_SC->CLKOUTCFG, 8); + #endif + + USB_Init(); // USB Initialization + USB_Connect(false); // USB clear connection + delay(1000); // Give OS time to notice + USB_Connect(true); + + TERN_(HAS_SD_HOST_DRIVE, MSC_SD_Init(0)); // Enable USB SD card access + + const millis_t usb_timeout = millis() + 2000; + while (!USB_Configuration && PENDING(millis(), usb_timeout)) { + delay(50); + idletask(); + #if PIN_EXISTS(LED) + TOGGLE(LED_PIN); // Flash quickly during USB initialization + #endif + } + + HAL_timer_init(); + + TERN_(POSTMORTEM_DEBUGGING, install_min_serial()); // Install the min serial handler +} + +#include "../../sd/cardreader.h" + +// HAL idle task +void MarlinHAL::idletask() { + #if HAS_SHARED_MEDIA + // If Marlin is using the SD card we need to lock it to prevent access from + // a PC via USB. + // Other HALs use IS_SD_PRINTING() and IS_SD_FILE_OPEN() to check for access but + // this will not reliably detect delete operations. To be safe we will lock + // the disk if Marlin has it mounted. Unfortunately there is currently no way + // to unmount the disk from the LCD menu. + // if (IS_SD_PRINTING() || IS_SD_FILE_OPEN()) + if (card.isMounted()) + MSC_Aquire_Lock(); + else + MSC_Release_Lock(); + #endif + // Perform USB stack housekeeping + MSC_RunDeferredCommands(); +} + void MarlinHAL::reboot() { NVIC_SystemReset(); } uint8_t MarlinHAL::get_reset_source() { @@ -112,6 +249,8 @@ void flashFirmware(const int16_t) { #endif // USE_WATCHDOG +#include "../../../gcode/parser.h" + // For M42/M43, scan command line for pin code // return index into pin map array if found and the pin is valid. // return dval if not found or not a valid pin. diff --git a/Marlin/src/HAL/LPC1768/HAL.h b/Marlin/src/HAL/LPC1768/HAL.h index b0eeb983b4..ab28e06eb8 100644 --- a/Marlin/src/HAL/LPC1768/HAL.h +++ b/Marlin/src/HAL/LPC1768/HAL.h @@ -1,9 +1,9 @@ /** * Marlin 3D Printer Firmware - * * Copyright (c) 2020 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] - * Copyright (c) 2016 Bob Cousins bobcousins42@googlemail.com - * Copyright (c) 2015-2016 Nico Tonnhofer wurstnase.reprap@gmail.com + * + * 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 @@ -101,7 +101,7 @@ extern DefaultSerial1 USBSerial; #error "LCD_SERIAL_PORT must be from 0 to 3. You can also use -1 if the board supports Native USB." #endif #if HAS_DGUS_LCD - #define SERIAL_GET_TX_BUFFER_FREE() LCD_SERIAL.available() + #define LCD_SERIAL_TX_BUFFER_FREE() LCD_SERIAL.available() #endif #endif @@ -127,7 +127,7 @@ extern DefaultSerial1 USBSerial; // K = 6, 565 samples, 500Hz sample rate, 1.13s convergence on full range step // Memory usage per ADC channel (bytes): 4 (32 Bytes for 8 channels) -#define HAL_ADC_VREF 3.3 // ADC voltage reference +#define HAL_ADC_VREF_MV 3300 // ADC voltage reference #define HAL_ADC_RESOLUTION 12 // 15 bit maximum, raw temperature is stored as int16_t #define HAL_ADC_FILTERED // Disable oversampling done in Marlin as ADC values already filtered in HAL @@ -165,7 +165,9 @@ int16_t PARSED_PIN_INDEX(const char code, const int16_t dval); // Defines // ------------------------ -#define PLATFORM_M997_SUPPORT +#ifndef PLATFORM_M997_SUPPORT + #define PLATFORM_M997_SUPPORT +#endif void flashFirmware(const int16_t); #define HAL_CAN_SET_PWM_FREQ // This HAL supports PWM Frequency adjustment @@ -241,15 +243,18 @@ public: // Begin ADC sampling on the given pin. Called from Temperature::isr! static uint32_t adc_result; - static void adc_start(const pin_t pin) { - adc_result = FilteredADC::read(pin) >> (16 - HAL_ADC_RESOLUTION); // returns 16bit value, reduce to required bits - } + static pin_t adc_pin; + + static void adc_start(const pin_t pin) { adc_pin = pin; } // Is the ADC ready for reading? - static bool adc_ready() { return true; } + static bool adc_ready() { return LPC176x::adc_hardware.done(LPC176x::pin_get_adc_channel(adc_pin)); } // The current value of the ADC register - static uint16_t adc_value() { return uint16_t(adc_result); } + static uint16_t adc_value() { + adc_result = FilteredADC::read(adc_pin) >> (16 - HAL_ADC_RESOLUTION); // returns 16bit value, reduce to required bits + return uint16_t(adc_result); + } /** * Set the PWM duty cycle for the pin to the given value. diff --git a/Marlin/src/HAL/LPC1768/HAL_SPI.cpp b/Marlin/src/HAL/LPC1768/HAL_SPI.cpp index 29f9b43afe..6ce7f75552 100644 --- a/Marlin/src/HAL/LPC1768/HAL_SPI.cpp +++ b/Marlin/src/HAL/LPC1768/HAL_SPI.cpp @@ -60,7 +60,7 @@ // ------------------------ // Public functions // ------------------------ -#if ENABLED(LPC_SOFTWARE_SPI) +#if ENABLED(SOFTWARE_SPI) // Software SPI @@ -161,7 +161,7 @@ // TODO: Implement this method } -#endif // LPC_SOFTWARE_SPI +#endif // SOFTWARE_SPI /** * @brief Wait until TXE (tx empty) flag is set and BSY (busy) flag unset. @@ -318,8 +318,16 @@ void SPIClass::dmaSend(void *buf, uint16_t length, bool minc) { // Enable DMA GPDMA_ChannelCmd(0, ENABLE); + /** + * Observed behaviour on normal data transfer completion (SKR 1.3 board / LPC1768 MCU) + * GPDMA_STAT_INTTC flag is SET + * GPDMA_STAT_INTERR flag is NOT SET + * GPDMA_STAT_RAWINTTC flag is NOT SET + * GPDMA_STAT_RAWINTERR flag is SET + */ + // Wait for data transfer - while (!GPDMA_IntGetStatus(GPDMA_STAT_RAWINTTC, 0) && !GPDMA_IntGetStatus(GPDMA_STAT_RAWINTERR, 0)) { } + while (!GPDMA_IntGetStatus(GPDMA_STAT_INTTC, 0) && !GPDMA_IntGetStatus(GPDMA_STAT_INTERR, 0)) {} // Clear err and int GPDMA_ClearIntPending (GPDMA_STATCLR_INTTC, 0); @@ -333,6 +341,43 @@ void SPIClass::dmaSend(void *buf, uint16_t length, bool minc) { SSP_DMACmd(_currentSetting->spi_d, SSP_DMA_TX, DISABLE); } +void SPIClass::dmaSendAsync(void *buf, uint16_t length, bool minc) { + //TODO: LPC dma can only write 0xFFF bytes at once. + GPDMA_Channel_CFG_Type GPDMACfg; + + /* Configure GPDMA channel 0 -------------------------------------------------------------*/ + /* DMA Channel 0 */ + GPDMACfg.ChannelNum = 0; + // Source memory + GPDMACfg.SrcMemAddr = (uint32_t)buf; + // Destination memory - Not used + GPDMACfg.DstMemAddr = 0; + // Transfer size + GPDMACfg.TransferSize = length; + // Transfer width + GPDMACfg.TransferWidth = (_currentSetting->dataSize == DATA_SIZE_16BIT) ? GPDMA_WIDTH_HALFWORD : GPDMA_WIDTH_BYTE; + // Transfer type + GPDMACfg.TransferType = GPDMA_TRANSFERTYPE_M2P; + // Source connection - unused + GPDMACfg.SrcConn = 0; + // Destination connection + GPDMACfg.DstConn = (_currentSetting->spi_d == LPC_SSP0) ? GPDMA_CONN_SSP0_Tx : GPDMA_CONN_SSP1_Tx; + + GPDMACfg.DMALLI = 0; + + // Enable dma on SPI + SSP_DMACmd(_currentSetting->spi_d, SSP_DMA_TX, ENABLE); + + // Only increase memory if minc is true + GPDMACfg.MemoryIncrease = (minc ? GPDMA_DMACCxControl_SI : 0); + + // Setup channel with given parameter + GPDMA_Setup(&GPDMACfg); + + // Enable DMA + GPDMA_ChannelCmd(0, ENABLE); +} + uint16_t SPIClass::read() { return SSP_ReceiveData(_currentSetting->spi_d); } diff --git a/Marlin/src/HAL/LPC1768/MarlinSerial.h b/Marlin/src/HAL/LPC1768/MarlinSerial.h index 3e6848a1e3..2fadd8209b 100644 --- a/Marlin/src/HAL/LPC1768/MarlinSerial.h +++ b/Marlin/src/HAL/LPC1768/MarlinSerial.h @@ -30,16 +30,6 @@ #endif #include "../../core/serial_hook.h" -#ifndef SERIAL_PORT - #define SERIAL_PORT 0 -#endif -#ifndef RX_BUFFER_SIZE - #define RX_BUFFER_SIZE 128 -#endif -#ifndef TX_BUFFER_SIZE - #define TX_BUFFER_SIZE 32 -#endif - class MarlinSerial : public HardwareSerial { public: MarlinSerial(LPC_UART_TypeDef *UARTx) : HardwareSerial(UARTx) { } diff --git a/Marlin/src/HAL/LPC1768/MinSerial.cpp b/Marlin/src/HAL/LPC1768/MinSerial.cpp index 7a1c038c0b..368bcb5259 100644 --- a/Marlin/src/HAL/LPC1768/MinSerial.cpp +++ b/Marlin/src/HAL/LPC1768/MinSerial.cpp @@ -33,18 +33,18 @@ static void TX(char c) { _DBC(c); } void install_min_serial() { HAL_min_serial_out = &TX; } #if DISABLED(DYNAMIC_VECTORTABLE) -extern "C" { - __attribute__((naked)) void JumpHandler_ASM() { - __asm__ __volatile__ ( - "b CommonHandler_ASM\n" - ); + extern "C" { + __attribute__((naked)) void JumpHandler_ASM() { + __asm__ __volatile__ ( + "b CommonHandler_ASM\n" + ); + } + void __attribute__((naked, alias("JumpHandler_ASM"))) HardFault_Handler(); + void __attribute__((naked, alias("JumpHandler_ASM"))) BusFault_Handler(); + void __attribute__((naked, alias("JumpHandler_ASM"))) UsageFault_Handler(); + void __attribute__((naked, alias("JumpHandler_ASM"))) MemManage_Handler(); + void __attribute__((naked, alias("JumpHandler_ASM"))) NMI_Handler(); } - void __attribute__((naked, alias("JumpHandler_ASM"))) HardFault_Handler(); - void __attribute__((naked, alias("JumpHandler_ASM"))) BusFault_Handler(); - void __attribute__((naked, alias("JumpHandler_ASM"))) UsageFault_Handler(); - void __attribute__((naked, alias("JumpHandler_ASM"))) MemManage_Handler(); - void __attribute__((naked, alias("JumpHandler_ASM"))) NMI_Handler(); -} #endif #endif // POSTMORTEM_DEBUGGING diff --git a/Marlin/src/HAL/LPC1768/Servo.h b/Marlin/src/HAL/LPC1768/Servo.h index f02f503a67..221001c948 100644 --- a/Marlin/src/HAL/LPC1768/Servo.h +++ b/Marlin/src/HAL/LPC1768/Servo.h @@ -39,7 +39,6 @@ * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ -#pragma once /** * Based on "servo.h - Interrupt driven Servo library for Arduino using 16 bit timers - diff --git a/Marlin/src/HAL/LPC1768/eeprom_sdcard.cpp b/Marlin/src/HAL/LPC1768/eeprom_sdcard.cpp index 1991d79719..4f1797dc6a 100644 --- a/Marlin/src/HAL/LPC1768/eeprom_sdcard.cpp +++ b/Marlin/src/HAL/LPC1768/eeprom_sdcard.cpp @@ -91,15 +91,9 @@ bool PersistentStore::access_finish() { static void debug_rw(const bool write, int &pos, const uint8_t *value, const size_t size, const FRESULT s, const size_t total=0) { #if ENABLED(DEBUG_SD_EEPROM_EMULATION) FSTR_P const rw_str = write ? F("write") : F("read"); - SERIAL_CHAR(' '); - SERIAL_ECHOF(rw_str); - SERIAL_ECHOLNPGM("_data(", pos, ",", *value, ",", size, ", ...)"); - if (total) { - SERIAL_ECHOPGM(" f_"); - SERIAL_ECHOF(rw_str); - SERIAL_ECHOPGM("()=", s, "\n size=", size, "\n bytes_"); - SERIAL_ECHOLNF(write ? F("written=") : F("read="), total); - } + SERIAL_ECHOLN(C(' '), rw_str, F("_data("), pos, C(','), *value, C(','), size, F(", ...)")); + if (total) + SERIAL_ECHOLN(F(" f_"), rw_str, F("()="), s, F("\n size="), size, F("\n bytes_"), write ? F("written=") : F("read="), total); else SERIAL_ECHOLNPGM(" f_lseek()=", s); #endif diff --git a/Marlin/src/HAL/LPC1768/endstop_interrupts.h b/Marlin/src/HAL/LPC1768/endstop_interrupts.h index e4ac17f608..7a67b958b4 100644 --- a/Marlin/src/HAL/LPC1768/endstop_interrupts.h +++ b/Marlin/src/HAL/LPC1768/endstop_interrupts.h @@ -44,147 +44,171 @@ void setup_endstop_interrupts() { #define _ATTACH(P) attachInterrupt(digitalPinToInterrupt(P), endstop_ISR, CHANGE) #define LPC1768_PIN_INTERRUPT_M(pin) ((pin >> 0x5 & 0x7) == 0 || (pin >> 0x5 & 0x7) == 2) - #if HAS_X_MAX + #if USE_X_MAX #if !LPC1768_PIN_INTERRUPT_M(X_MAX_PIN) #error "X_MAX_PIN is not INTERRUPT-capable. Disable ENDSTOP_INTERRUPTS_FEATURE to continue." #endif _ATTACH(X_MAX_PIN); #endif - #if HAS_X_MIN + #if USE_X_MIN #if !LPC1768_PIN_INTERRUPT_M(X_MIN_PIN) #error "X_MIN_PIN is not INTERRUPT-capable. Disable ENDSTOP_INTERRUPTS_FEATURE to continue." #endif _ATTACH(X_MIN_PIN); #endif - #if HAS_Y_MAX + #if USE_Y_MAX #if !LPC1768_PIN_INTERRUPT_M(Y_MAX_PIN) #error "Y_MAX_PIN is not INTERRUPT-capable. Disable ENDSTOP_INTERRUPTS_FEATURE to continue." #endif _ATTACH(Y_MAX_PIN); #endif - #if HAS_Y_MIN + #if USE_Y_MIN #if !LPC1768_PIN_INTERRUPT_M(Y_MIN_PIN) #error "Y_MIN_PIN is not INTERRUPT-capable. Disable ENDSTOP_INTERRUPTS_FEATURE to continue." #endif _ATTACH(Y_MIN_PIN); #endif - #if HAS_Z_MAX + #if USE_Z_MAX #if !LPC1768_PIN_INTERRUPT_M(Z_MAX_PIN) #error "Z_MAX_PIN is not INTERRUPT-capable. Disable ENDSTOP_INTERRUPTS_FEATURE to continue." #endif _ATTACH(Z_MAX_PIN); #endif - #if HAS_Z_MIN + #if USE_Z_MIN #if !LPC1768_PIN_INTERRUPT_M(Z_MIN_PIN) #error "Z_MIN_PIN is not INTERRUPT-capable. Disable ENDSTOP_INTERRUPTS_FEATURE to continue." #endif _ATTACH(Z_MIN_PIN); #endif - #if HAS_Z2_MAX + #if USE_X2_MAX + #if !LPC1768_PIN_INTERRUPT_M(X2_MAX_PIN) + #error "X2_MAX_PIN is not INTERRUPT-capable. Disable ENDSTOP_INTERRUPTS_FEATURE to continue." + #endif + _ATTACH(X2_MAX_PIN); + #endif + #if USE_X2_MIN + #if !LPC1768_PIN_INTERRUPT_M(X2_MIN_PIN) + #error "X2_MIN_PIN is not INTERRUPT-capable. Disable ENDSTOP_INTERRUPTS_FEATURE to continue." + #endif + _ATTACH(X2_MIN_PIN); + #endif + #if USE_Y2_MAX + #if !LPC1768_PIN_INTERRUPT_M(Y2_MAX_PIN) + #error "Y2_MAX_PIN is not INTERRUPT-capable. Disable ENDSTOP_INTERRUPTS_FEATURE to continue." + #endif + _ATTACH(Y2_MAX_PIN); + #endif + #if USE_Y2_MIN + #if !LPC1768_PIN_INTERRUPT_M(Y2_MIN_PIN) + #error "Y2_MIN_PIN is not INTERRUPT-capable. Disable ENDSTOP_INTERRUPTS_FEATURE to continue." + #endif + _ATTACH(Y2_MIN_PIN); + #endif + #if USE_Z2_MAX #if !LPC1768_PIN_INTERRUPT_M(Z2_MAX_PIN) #error "Z2_MAX_PIN is not INTERRUPT-capable. Disable ENDSTOP_INTERRUPTS_FEATURE to continue." #endif _ATTACH(Z2_MAX_PIN); #endif - #if HAS_Z2_MIN + #if USE_Z2_MIN #if !LPC1768_PIN_INTERRUPT_M(Z2_MIN_PIN) #error "Z2_MIN_PIN is not INTERRUPT-capable. Disable ENDSTOP_INTERRUPTS_FEATURE to continue." #endif _ATTACH(Z2_MIN_PIN); #endif - #if HAS_Z3_MAX + #if USE_Z3_MAX #if !LPC1768_PIN_INTERRUPT_M(Z3_MAX_PIN) #error "Z3_MIN_PIN is not INTERRUPT-capable. Disable ENDSTOP_INTERRUPTS_FEATURE to continue." #endif _ATTACH(Z3_MAX_PIN); #endif - #if HAS_Z3_MIN + #if USE_Z3_MIN #if !LPC1768_PIN_INTERRUPT_M(Z3_MIN_PIN) #error "Z3_MIN_PIN is not INTERRUPT-capable. Disable ENDSTOP_INTERRUPTS_FEATURE to continue." #endif _ATTACH(Z3_MIN_PIN); #endif - #if HAS_Z4_MAX + #if USE_Z4_MAX #if !LPC1768_PIN_INTERRUPT_M(Z4_MAX_PIN) #error "Z4_MIN_PIN is not INTERRUPT-capable. Disable ENDSTOP_INTERRUPTS_FEATURE to continue." #endif _ATTACH(Z4_MAX_PIN); #endif - #if HAS_Z4_MIN + #if USE_Z4_MIN #if !LPC1768_PIN_INTERRUPT_M(Z4_MIN_PIN) #error "Z4_MIN_PIN is not INTERRUPT-capable. Disable ENDSTOP_INTERRUPTS_FEATURE to continue." #endif _ATTACH(Z4_MIN_PIN); #endif - #if HAS_Z_MIN_PROBE_PIN + #if USE_Z_MIN_PROBE #if !LPC1768_PIN_INTERRUPT_M(Z_MIN_PROBE_PIN) #error "Z_MIN_PROBE_PIN is not INTERRUPT-capable. Disable ENDSTOP_INTERRUPTS_FEATURE to continue." #endif _ATTACH(Z_MIN_PROBE_PIN); #endif - #if HAS_I_MAX + #if USE_I_MAX #if !LPC1768_PIN_INTERRUPT_M(I_MAX_PIN) - #error "I_MAX_PIN is not INTERRUPT-capable." + #error "I_MAX_PIN is not INTERRUPT-capable. Disable ENDSTOP_INTERRUPTS_FEATURE to continue." #endif _ATTACH(I_MAX_PIN); - #elif HAS_I_MIN + #elif USE_I_MIN #if !LPC1768_PIN_INTERRUPT_M(I_MIN_PIN) - #error "I_MIN_PIN is not INTERRUPT-capable." + #error "I_MIN_PIN is not INTERRUPT-capable. Disable ENDSTOP_INTERRUPTS_FEATURE to continue." #endif _ATTACH(I_MIN_PIN); #endif - #if HAS_J_MAX + #if USE_J_MAX #if !LPC1768_PIN_INTERRUPT_M(J_MAX_PIN) - #error "J_MAX_PIN is not INTERRUPT-capable." + #error "J_MAX_PIN is not INTERRUPT-capable. Disable ENDSTOP_INTERRUPTS_FEATURE to continue." #endif _ATTACH(J_MAX_PIN); - #elif HAS_J_MIN + #elif USE_J_MIN #if !LPC1768_PIN_INTERRUPT_M(J_MIN_PIN) - #error "J_MIN_PIN is not INTERRUPT-capable." + #error "J_MIN_PIN is not INTERRUPT-capable. Disable ENDSTOP_INTERRUPTS_FEATURE to continue." #endif _ATTACH(J_MIN_PIN); #endif - #if HAS_K_MAX + #if USE_K_MAX #if !LPC1768_PIN_INTERRUPT_M(K_MAX_PIN) - #error "K_MAX_PIN is not INTERRUPT-capable." + #error "K_MAX_PIN is not INTERRUPT-capable. Disable ENDSTOP_INTERRUPTS_FEATURE to continue." #endif _ATTACH(K_MAX_PIN); - #elif HAS_K_MIN + #elif USE_K_MIN #if !LPC1768_PIN_INTERRUPT_M(K_MIN_PIN) - #error "K_MIN_PIN is not INTERRUPT-capable." + #error "K_MIN_PIN is not INTERRUPT-capable. Disable ENDSTOP_INTERRUPTS_FEATURE to continue." #endif _ATTACH(K_MIN_PIN); #endif - #if HAS_U_MAX + #if USE_U_MAX #if !LPC1768_PIN_INTERRUPT_M(U_MAX_PIN) - #error "U_MAX_PIN is not INTERRUPT-capable." + #error "U_MAX_PIN is not INTERRUPT-capable. Disable ENDSTOP_INTERRUPTS_FEATURE to continue." #endif _ATTACH(U_MAX_PIN); - #elif HAS_U_MIN + #elif USE_U_MIN #if !LPC1768_PIN_INTERRUPT_M(U_MIN_PIN) - #error "U_MIN_PIN is not INTERRUPT-capable." + #error "U_MIN_PIN is not INTERRUPT-capable. Disable ENDSTOP_INTERRUPTS_FEATURE to continue." #endif _ATTACH(U_MIN_PIN); #endif - #if HAS_V_MAX + #if USE_V_MAX #if !LPC1768_PIN_INTERRUPT_M(V_MAX_PIN) - #error "V_MAX_PIN is not INTERRUPT-capable." + #error "V_MAX_PIN is not INTERRUPT-capable. Disable ENDSTOP_INTERRUPTS_FEATURE to continue." #endif _ATTACH(V_MAX_PIN); - #elif HAS_V_MIN + #elif USE_V_MIN #if !LPC1768_PIN_INTERRUPT_M(V_MIN_PIN) - #error "V_MIN_PIN is not INTERRUPT-capable." + #error "V_MIN_PIN is not INTERRUPT-capable. Disable ENDSTOP_INTERRUPTS_FEATURE to continue." #endif _ATTACH(V_MIN_PIN); #endif - #if HAS_W_MAX + #if USE_W_MAX #if !LPC1768_PIN_INTERRUPT_M(W_MAX_PIN) - #error "W_MAX_PIN is not INTERRUPT-capable." + #error "W_MAX_PIN is not INTERRUPT-capable. Disable ENDSTOP_INTERRUPTS_FEATURE to continue." #endif _ATTACH(W_MAX_PIN); - #elif HAS_W_MIN + #elif USE_W_MIN #if !LPC1768_PIN_INTERRUPT_M(W_MIN_PIN) - #error "W_MIN_PIN is not INTERRUPT-capable." + #error "W_MIN_PIN is not INTERRUPT-capable. Disable ENDSTOP_INTERRUPTS_FEATURE to continue." #endif _ATTACH(W_MIN_PIN); #endif diff --git a/Marlin/src/HAL/LPC1768/inc/Conditionals_LCD.h b/Marlin/src/HAL/LPC1768/inc/Conditionals_LCD.h index 32ef908d63..65b019b261 100644 --- a/Marlin/src/HAL/LPC1768/inc/Conditionals_LCD.h +++ b/Marlin/src/HAL/LPC1768/inc/Conditionals_LCD.h @@ -21,6 +21,6 @@ */ #pragma once -#if HAS_FSMC_TFT - #error "Sorry! FSMC TFT displays are not current available for HAL/LPC1768." +#ifndef SERIAL_PORT + #define SERIAL_PORT 0 #endif diff --git a/Marlin/src/HAL/LPC1768/inc/Conditionals_adv.h b/Marlin/src/HAL/LPC1768/inc/Conditionals_adv.h index 8e7cab185f..9d04c4f787 100644 --- a/Marlin/src/HAL/LPC1768/inc/Conditionals_adv.h +++ b/Marlin/src/HAL/LPC1768/inc/Conditionals_adv.h @@ -24,3 +24,10 @@ #if DISABLED(NO_SD_HOST_DRIVE) #define HAS_SD_HOST_DRIVE 1 #endif + +#ifndef RX_BUFFER_SIZE + #define RX_BUFFER_SIZE 128 +#endif +#ifndef TX_BUFFER_SIZE + #define TX_BUFFER_SIZE 32 +#endif diff --git a/Marlin/src/HAL/LPC1768/inc/Conditionals_post.h b/Marlin/src/HAL/LPC1768/inc/Conditionals_post.h index 3549950008..0b03cb2aea 100644 --- a/Marlin/src/HAL/LPC1768/inc/Conditionals_post.h +++ b/Marlin/src/HAL/LPC1768/inc/Conditionals_post.h @@ -23,12 +23,12 @@ #if USE_FALLBACK_EEPROM #define FLASH_EEPROM_EMULATION -#elif EITHER(I2C_EEPROM, SPI_EEPROM) +#elif ANY(I2C_EEPROM, SPI_EEPROM) #define USE_SHARED_EEPROM 1 #endif // LPC1768 boards seem to lose steps when saving to EEPROM during print (issue #20785) // TODO: Which other boards are incompatible? #if defined(MCU_LPC1768) && ENABLED(FLASH_EEPROM_EMULATION) && PRINTCOUNTER_SAVE_INTERVAL > 0 - #define PRINTCOUNTER_SYNC 1 + #define PRINTCOUNTER_SYNC #endif diff --git a/Marlin/src/HAL/LPC1768/inc/SanityCheck.h b/Marlin/src/HAL/LPC1768/inc/SanityCheck.h index 8265d58a6e..2782f225b0 100644 --- a/Marlin/src/HAL/LPC1768/inc/SanityCheck.h +++ b/Marlin/src/HAL/LPC1768/inc/SanityCheck.h @@ -77,6 +77,10 @@ static_assert(!(NUM_SERVOS && ENABLED(FAST_PWM_FAN)), "BLTOUCH and Servos are in #endif #endif +#if HAS_FSMC_TFT + #error "Sorry! FSMC TFT displays are not current available for HAL/LPC1768." +#endif + static_assert(DISABLED(BAUD_RATE_GCODE), "BAUD_RATE_GCODE is not yet supported on LPC176x."); /** @@ -95,7 +99,7 @@ static_assert(DISABLED(BAUD_RATE_GCODE), "BAUD_RATE_GCODE is not yet supported o #if USING_HW_SERIAL0 #define IS_TX0(P) (P == P0_02) #define IS_RX0(P) (P == P0_03) - #if IS_TX0(TMC_SW_MISO) || IS_RX0(TMC_SW_MOSI) + #if IS_TX0(TMC_SPI_MISO) || IS_RX0(TMC_SPI_MOSI) #error "Serial port pins (0) conflict with Trinamic SPI pins!" #elif HAS_PRUSA_MMU1 && (IS_TX0(E_MUX1_PIN) || IS_RX0(E_MUX0_PIN)) #error "Serial port pins (0) conflict with Multi-Material-Unit multiplexer pins!" @@ -111,7 +115,7 @@ static_assert(DISABLED(BAUD_RATE_GCODE), "BAUD_RATE_GCODE is not yet supported o #define IS_RX1(P) (P == P0_16) #define _IS_TX1_1 IS_TX1 #define _IS_RX1_1 IS_RX1 - #if IS_TX1(TMC_SW_SCK) + #if IS_TX1(TMC_SPI_SCK) #error "Serial port pins (1) conflict with other pins!" #elif HAS_ROTARY_ENCODER #if IS_TX1(BTN_EN2) || IS_RX1(BTN_EN1) @@ -146,7 +150,7 @@ static_assert(DISABLED(BAUD_RATE_GCODE), "BAUD_RATE_GCODE is not yet supported o #error "Serial port pins (2) conflict with other pins!" #elif Y_HOME_TO_MIN && IS_TX2(Y_STOP_PIN) #error "Serial port pins (2) conflict with Y endstop pin!" - #elif USES_Z_MIN_PROBE_PIN && IS_TX2(Z_MIN_PROBE_PIN) + #elif USE_Z_MIN_PROBE && IS_TX2(Z_MIN_PROBE_PIN) #error "Serial port pins (2) conflict with probe pin!" #elif ANY_TX(2, X_ENABLE_PIN, Y_ENABLE_PIN) || ANY_RX(2, X_DIR_PIN, Y_DIR_PIN) #error "Serial port pins (2) conflict with X/Y stepper pins!" @@ -197,7 +201,7 @@ static_assert(DISABLED(BAUD_RATE_GCODE), "BAUD_RATE_GCODE is not yet supported o #if USEDI2CDEV_M == 0 // P0_27 [D57] (AUX-1) .......... P0_28 [D58] (AUX-1) #define PIN_IS_SDA0(P) (P##_PIN == P0_27) #define IS_SCL0(P) (P == P0_28) - #if ENABLED(SDSUPPORT) && PIN_IS_SDA0(SD_DETECT) + #if HAS_MEDIA && PIN_IS_SDA0(SD_DETECT) #error "SDA0 overlaps with SD_DETECT_PIN!" #elif PIN_IS_SDA0(E0_AUTO_FAN) #error "SDA0 overlaps with E0_AUTO_FAN_PIN!" @@ -237,7 +241,7 @@ static_assert(DISABLED(BAUD_RATE_GCODE), "BAUD_RATE_GCODE is not yet supported o #define PIN_IS_SCL2(P) (P##_PIN == P0_11) #if PIN_IS_SDA2(Y_STOP) #error "i2c SDA2 overlaps with Y endstop pin!" - #elif USES_Z_MIN_PROBE_PIN && PIN_IS_SDA2(Z_MIN_PROBE) + #elif USE_Z_MIN_PROBE && PIN_IS_SDA2(Z_MIN_PROBE) #error "i2c SDA2 overlaps with Z probe pin!" #elif PIN_IS_SDA2(X_ENABLE) || PIN_IS_SDA2(Y_ENABLE) #error "i2c SDA2 overlaps with X/Y ENABLE pin!" diff --git a/Marlin/src/HAL/LPC1768/include/SPI.h b/Marlin/src/HAL/LPC1768/include/SPI.h index 24f4759315..03d34becd8 100644 --- a/Marlin/src/HAL/LPC1768/include/SPI.h +++ b/Marlin/src/HAL/LPC1768/include/SPI.h @@ -155,6 +155,7 @@ public: void read(uint8_t *buf, uint32_t len); void dmaSend(void *buf, uint16_t length, bool minc); + void dmaSendAsync(void *buf, uint16_t length, bool minc); /** * @brief Sets the number of the SPI peripheral to be used by diff --git a/Marlin/src/HAL/LPC1768/main.cpp b/Marlin/src/HAL/LPC1768/main.cpp deleted file mode 100644 index 419c99793f..0000000000 --- a/Marlin/src/HAL/LPC1768/main.cpp +++ /dev/null @@ -1,163 +0,0 @@ -/** - * Marlin 3D Printer Firmware - * Copyright (c) 2020 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] - * - * Based on Sprinter and grbl. - * Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - */ -#ifdef TARGET_LPC1768 - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "../../inc/MarlinConfig.h" -#include "../../core/millis_t.h" - -#include "../../sd/cardreader.h" - -extern uint32_t MSC_SD_Init(uint8_t pdrv); - -extern "C" { - #include - extern "C" int isLPC1769(); - extern "C" void disk_timerproc(); -} - -void SysTick_Callback() { disk_timerproc(); } - -TERN_(POSTMORTEM_DEBUGGING, extern void install_min_serial()); - -void MarlinHAL::init() { - - // Init LEDs - #if PIN_EXISTS(LED) - SET_DIR_OUTPUT(LED_PIN); - WRITE_PIN_CLR(LED_PIN); - #if PIN_EXISTS(LED2) - SET_DIR_OUTPUT(LED2_PIN); - WRITE_PIN_CLR(LED2_PIN); - #if PIN_EXISTS(LED3) - SET_DIR_OUTPUT(LED3_PIN); - WRITE_PIN_CLR(LED3_PIN); - #if PIN_EXISTS(LED4) - SET_DIR_OUTPUT(LED4_PIN); - WRITE_PIN_CLR(LED4_PIN); - #endif - #endif - #endif - - // Flash status LED 3 times to indicate Marlin has started booting - LOOP_L_N(i, 6) { - TOGGLE(LED_PIN); - delay(100); - } - #endif - - // Init Servo Pins - #define INIT_SERVO(N) OUT_WRITE(SERVO##N##_PIN, LOW) - #if HAS_SERVO_0 - INIT_SERVO(0); - #endif - #if HAS_SERVO_1 - INIT_SERVO(1); - #endif - #if HAS_SERVO_2 - INIT_SERVO(2); - #endif - #if HAS_SERVO_3 - INIT_SERVO(3); - #endif - - //debug_frmwrk_init(); - //_DBG("\n\nDebug running\n"); - // Initialize the SD card chip select pins as soon as possible - #if PIN_EXISTS(SD_SS) - OUT_WRITE(SD_SS_PIN, HIGH); - #endif - - #if PIN_EXISTS(ONBOARD_SD_CS) && ONBOARD_SD_CS_PIN != SD_SS_PIN - OUT_WRITE(ONBOARD_SD_CS_PIN, HIGH); - #endif - - #ifdef LPC1768_ENABLE_CLKOUT_12M - /** - * CLKOUTCFG register - * bit 8 (CLKOUT_EN) = enables CLKOUT signal. Disabled for now to prevent glitch when enabling GPIO. - * bits 7:4 (CLKOUTDIV) = set to 0 for divider setting of /1 - * bits 3:0 (CLKOUTSEL) = set to 1 to select main crystal oscillator as CLKOUT source - */ - LPC_SC->CLKOUTCFG = (0<<8)|(0<<4)|(1<<0); - // set P1.27 pin to function 01 (CLKOUT) - PINSEL_CFG_Type PinCfg; - PinCfg.Portnum = 1; - PinCfg.Pinnum = 27; - PinCfg.Funcnum = 1; // function 01 (CLKOUT) - PinCfg.OpenDrain = 0; // not open drain - PinCfg.Pinmode = 2; // no pull-up/pull-down - PINSEL_ConfigPin(&PinCfg); - // now set CLKOUT_EN bit - SBI(LPC_SC->CLKOUTCFG, 8); - #endif - - USB_Init(); // USB Initialization - USB_Connect(false); // USB clear connection - delay(1000); // Give OS time to notice - USB_Connect(true); - - TERN_(HAS_SD_HOST_DRIVE, MSC_SD_Init(0)); // Enable USB SD card access - - const millis_t usb_timeout = millis() + 2000; - while (!USB_Configuration && PENDING(millis(), usb_timeout)) { - delay(50); - idletask(); - #if PIN_EXISTS(LED) - TOGGLE(LED_PIN); // Flash quickly during USB initialization - #endif - } - - HAL_timer_init(); - - TERN_(POSTMORTEM_DEBUGGING, install_min_serial()); // Install the min serial handler -} - -// HAL idle task -void MarlinHAL::idletask() { - #if HAS_SHARED_MEDIA - // If Marlin is using the SD card we need to lock it to prevent access from - // a PC via USB. - // Other HALs use IS_SD_PRINTING() and IS_SD_FILE_OPEN() to check for access but - // this will not reliably detect delete operations. To be safe we will lock - // the disk if Marlin has it mounted. Unfortunately there is currently no way - // to unmount the disk from the LCD menu. - // if (IS_SD_PRINTING() || IS_SD_FILE_OPEN()) - if (card.isMounted()) - MSC_Aquire_Lock(); - else - MSC_Release_Lock(); - #endif - // Perform USB stack housekeeping - MSC_RunDeferredCommands(); -} - -#endif // TARGET_LPC1768 diff --git a/Marlin/src/HAL/LPC1768/pinsDebug.h b/Marlin/src/HAL/LPC1768/pinsDebug.h index a2f5c123a2..975511be9a 100644 --- a/Marlin/src/HAL/LPC1768/pinsDebug.h +++ b/Marlin/src/HAL/LPC1768/pinsDebug.h @@ -29,11 +29,8 @@ */ #define NUMBER_PINS_TOTAL NUM_DIGITAL_PINS -#define pwm_details(pin) pin = pin // do nothing // print PWM details -#define pwm_status(pin) false //Print a pin's PWM status. Return true if it's currently a PWM pin. #define IS_ANALOG(P) (DIGITAL_PIN_TO_ANALOG_PIN(P) >= 0 ? 1 : 0) #define digitalRead_mod(p) extDigitalRead(p) -#define PRINT_PORT(p) #define GET_ARRAY_PIN(p) pin_array[p].pin #define PRINT_ARRAY_NAME(x) do{ sprintf_P(buffer, PSTR("%-" STRINGIFY(MAX_NAME_LENGTH) "s"), pin_array[x].name); SERIAL_ECHO(buffer); }while(0) #define PRINT_PIN(p) do{ sprintf_P(buffer, PSTR("P%d_%02d"), LPC176x::pin_port(p), LPC176x::pin_bit(p)); SERIAL_ECHO(buffer); }while(0) @@ -46,10 +43,14 @@ #endif bool GET_PINMODE(const pin_t pin) { - if (!LPC176x::pin_is_valid(pin) || LPC176x::pin_adc_enabled(pin)) // found an invalid pin or active analog pin + if (!LPC176x::pin_is_valid(pin) || LPC176x::pin_adc_enabled(pin)) // Invalid pin or active analog pin return false; return LPC176x::gpio_direction(pin); } #define GET_ARRAY_IS_DIGITAL(x) ((bool) pin_array[x].is_digital) + +void print_port(const pin_t) {} +void pwm_details(const pin_t) {} +bool pwm_status(const pin_t) { return false; } diff --git a/Marlin/src/HAL/LPC1768/spi_pins.h b/Marlin/src/HAL/LPC1768/spi_pins.h index e7d774742f..babe8a11d7 100644 --- a/Marlin/src/HAL/LPC1768/spi_pins.h +++ b/Marlin/src/HAL/LPC1768/spi_pins.h @@ -23,11 +23,11 @@ #include "../../core/macros.h" -#if BOTH(SDSUPPORT, HAS_MARLINUI_U8GLIB) && (LCD_PINS_D4 == SD_SCK_PIN || LCD_PINS_ENABLE == SD_MOSI_PIN || DOGLCD_SCK == SD_SCK_PIN || DOGLCD_MOSI == SD_MOSI_PIN) - #define LPC_SOFTWARE_SPI // If the SD card and LCD adapter share the same SPI pins, then software SPI is currently - // needed due to the speed and mode required for communicating with each device being different. - // This requirement can be removed if the SPI access to these devices is updated to use - // spiBeginTransaction. +#if ALL(HAS_MEDIA, HAS_MARLINUI_U8GLIB) && (LCD_PINS_D4 == SD_SCK_PIN || LCD_PINS_EN == SD_MOSI_PIN || DOGLCD_SCK == SD_SCK_PIN || DOGLCD_MOSI == SD_MOSI_PIN) + #define SOFTWARE_SPI // If the SD card and LCD adapter share the same SPI pins, then software SPI is currently + // needed due to the speed and mode required for communicating with each device being different. + // This requirement can be removed if the SPI access to these devices is updated to use + // spiBeginTransaction. #endif /** onboard SD card */ diff --git a/Marlin/src/HAL/LPC1768/tft/tft_spi.cpp b/Marlin/src/HAL/LPC1768/tft/tft_spi.cpp index a9847b2d2f..beaadaf519 100644 --- a/Marlin/src/HAL/LPC1768/tft/tft_spi.cpp +++ b/Marlin/src/HAL/LPC1768/tft/tft_spi.cpp @@ -20,15 +20,17 @@ * */ +#ifdef TARGET_LPC1768 + #include "../../../inc/MarlinConfig.h" #if HAS_SPI_TFT #include "tft_spi.h" -SPIClass TFT_SPI::SPIx(1); +SPIClass TFT_SPI::SPIx(TFT_SPI_DEVICE); -void TFT_SPI::Init() { +void TFT_SPI::init() { #if PIN_EXISTS(TFT_RESET) OUT_WRITE(TFT_RESET_PIN, HIGH); delay(100); @@ -38,60 +40,38 @@ void TFT_SPI::Init() { OUT_WRITE(TFT_BACKLIGHT_PIN, HIGH); #endif - SET_OUTPUT(TFT_DC_PIN); - SET_OUTPUT(TFT_CS_PIN); - WRITE(TFT_DC_PIN, HIGH); - WRITE(TFT_CS_PIN, HIGH); + OUT_WRITE(TFT_DC_PIN, HIGH); + OUT_WRITE(TFT_CS_PIN, HIGH); - /** - * STM32F1 APB2 = 72MHz, APB1 = 36MHz, max SPI speed of this MCU if 18Mhz - * STM32F1 has 3 SPI ports, SPI1 in APB2, SPI2/SPI3 in APB1 - * so the minimum prescale of SPI1 is DIV4, SPI2/SPI3 is DIV2 - */ - #if 0 - #if SPI_DEVICE == 1 - #define SPI_CLOCK_MAX SPI_CLOCK_DIV4 - #else - #define SPI_CLOCK_MAX SPI_CLOCK_DIV2 - #endif - uint8_t clock; - uint8_t spiRate = SPI_FULL_SPEED; - switch (spiRate) { - case SPI_FULL_SPEED: clock = SPI_CLOCK_MAX ; break; - case SPI_HALF_SPEED: clock = SPI_CLOCK_DIV4 ; break; - case SPI_QUARTER_SPEED: clock = SPI_CLOCK_DIV8 ; break; - case SPI_EIGHTH_SPEED: clock = SPI_CLOCK_DIV16; break; - case SPI_SPEED_5: clock = SPI_CLOCK_DIV32; break; - case SPI_SPEED_6: clock = SPI_CLOCK_DIV64; break; - default: clock = SPI_CLOCK_DIV2; // Default from the SPI library - } - #endif - - #if TFT_MISO_PIN == BOARD_SPI1_MISO_PIN - SPIx.setModule(1); - #elif TFT_MISO_PIN == BOARD_SPI2_MISO_PIN - SPIx.setModule(2); - #endif + SPIx.setModule(TFT_SPI_DEVICE); SPIx.setClock(SPI_CLOCK_MAX_TFT); SPIx.setBitOrder(MSBFIRST); SPIx.setDataMode(SPI_MODE0); } -void TFT_SPI::DataTransferBegin(uint16_t DataSize) { - SPIx.setDataSize(DataSize); +void TFT_SPI::dataTransferBegin(uint16_t dataSize) { + SPIx.setDataSize(dataSize); SPIx.begin(); WRITE(TFT_CS_PIN, LOW); } -uint32_t TFT_SPI::GetID() { +#ifdef TFT_DEFAULT_DRIVER + #include "../../../lcd/tft_io/tft_ids.h" +#endif + +uint32_t TFT_SPI::getID() { uint32_t id; - id = ReadID(LCD_READ_ID); + id = readID(LCD_READ_ID); if ((id & 0xFFFF) == 0 || (id & 0xFFFF) == 0xFFFF) - id = ReadID(LCD_READ_ID4); + id = readID(LCD_READ_ID4); + #ifdef TFT_DEFAULT_DRIVER + if ((id & 0xFFFF) == 0 || (id & 0xFFFF) == 0xFFFF) + id = TFT_DEFAULT_DRIVER; + #endif return id; } -uint32_t TFT_SPI::ReadID(uint16_t Reg) { +uint32_t TFT_SPI::readID(const uint16_t inReg) { uint32_t data = 0; #if PIN_EXISTS(TFT_MISO) @@ -100,31 +80,77 @@ uint32_t TFT_SPI::ReadID(uint16_t Reg) { SPIx.setClock(SPI_CLOCK_DIV64); SPIx.begin(); WRITE(TFT_CS_PIN, LOW); - WriteReg(Reg); + writeReg(inReg); - LOOP_L_N(i, 4) { + for (uint8_t i = 0; i < 4; ++i) { SPIx.read((uint8_t*)&d, 1); data = (data << 8) | d; } - DataTransferEnd(); + dataTransferEnd(); SPIx.setClock(SPI_CLOCK_MAX_TFT); #endif return data >> 7; } -bool TFT_SPI::isBusy() { return false; } +bool TFT_SPI::isBusy() { + #define __IS_DMA_CONFIGURED(__HANDLE__) ((__HANDLE__)->DMACCSrcAddr != 0) -void TFT_SPI::Abort() { DataTransferEnd(); } + // DMA Channel 0 is hardcoded in dmaSendAsync() and dmaSend() + if (!__IS_DMA_CONFIGURED(LPC_GPDMACH0)) return false; -void TFT_SPI::Transmit(uint16_t Data) { SPIx.transfer(Data); } + if (GPDMA_IntGetStatus(GPDMA_STAT_INTERR, 0)) { + // You should not be here - DMA transfer error flag is set + // Abort DMA transfer and release SPI + } + else { + // Check if DMA transfer completed flag is set + if (!GPDMA_IntGetStatus(GPDMA_STAT_INTTC, 0)) return true; + // Check if SPI TX butter is empty and SPI is idle + if ((SSP_GetStatus(LPC_SSPx, SSP_STAT_TXFIFO_EMPTY) == RESET) || (SSP_GetStatus(LPC_SSPx, SSP_STAT_BUSY) == SET)) return true; + } -void TFT_SPI::TransmitDMA(uint32_t MemoryIncrease, uint16_t *Data, uint16_t Count) { - DataTransferBegin(DATASIZE_16BIT); - WRITE(TFT_DC_PIN, HIGH); - SPIx.dmaSend(Data, Count, MemoryIncrease); - DataTransferEnd(); + abort(); + return false; +} + +void TFT_SPI::abort() { + // DMA Channel 0 is hardcoded in dmaSendAsync() and dmaSend() + + // Disable DMA + GPDMA_ChannelCmd(0, DISABLE); + + // Clear ERR and TC + GPDMA_ClearIntPending(GPDMA_STATCLR_INTTC, 0); + GPDMA_ClearIntPending(GPDMA_STATCLR_INTERR, 0); + + // Disable DMA on SPI + SSP_DMACmd(LPC_SSPx, SSP_DMA_TX, DISABLE); + + // Deconfigure DMA Channel 0 + LPC_GPDMACH0->DMACCControl = 0U; + LPC_GPDMACH0->DMACCConfig = 0U; + LPC_GPDMACH0->DMACCSrcAddr = 0U; + LPC_GPDMACH0->DMACCDestAddr = 0U; + + dataTransferEnd(); +} + +void TFT_SPI::transmit(uint16_t data) { SPIx.transfer(data); } + +void TFT_SPI::transmit(uint32_t memoryIncrease, uint16_t *data, uint16_t count) { + dataTransferBegin(DATASIZE_16BIT); + SPIx.dmaSend(data, count, memoryIncrease); + abort(); +} + +void TFT_SPI::transmitDMA(uint32_t memoryIncrease, uint16_t *data, uint16_t count) { + dataTransferBegin(DATASIZE_16BIT); + SPIx.dmaSendAsync(data, count, memoryIncrease); + + TERN_(TFT_SHARED_IO, while (isBusy())); } #endif // HAS_SPI_TFT +#endif // TARGET_LPC1768 diff --git a/Marlin/src/HAL/LPC1768/tft/tft_spi.h b/Marlin/src/HAL/LPC1768/tft/tft_spi.h index 4753fdbae9..6d5829fc73 100644 --- a/Marlin/src/HAL/LPC1768/tft/tft_spi.h +++ b/Marlin/src/HAL/LPC1768/tft/tft_spi.h @@ -27,6 +27,18 @@ #include // #include +#define IS_SPI(N) (BOARD_NR_SPI >= N && (TFT_SCK_PIN == BOARD_SPI##N##_SCK_PIN) && (TFT_MOSI_PIN == BOARD_SPI##N##_MOSI_PIN) && (TFT_MISO_PIN == BOARD_SPI##N##_MISO_PIN)) +#if IS_SPI(1) + #define TFT_SPI_DEVICE 1 + #define LPC_SSPx LPC_SSP0 +#elif IS_SPI(2) + #define TFT_SPI_DEVICE 2 + #define LPC_SSPx LPC_SSP1 +#else + #error "Invalid TFT SPI configuration." +#endif +#undef IS_SPI + #ifndef LCD_READ_ID #define LCD_READ_ID 0x04 // Read display identification information (0xD3 on ILI9341) #endif @@ -34,44 +46,44 @@ #define LCD_READ_ID4 0xD3 // Read display identification information (0xD3 on ILI9341) #endif -#define DATASIZE_8BIT SSP_DATABIT_8 -#define DATASIZE_16BIT SSP_DATABIT_16 -#define TFT_IO_DRIVER TFT_SPI +#define DATASIZE_8BIT SSP_DATABIT_8 +#define DATASIZE_16BIT SSP_DATABIT_16 +#define TFT_IO_DRIVER TFT_SPI +#define DMA_MAX_WORDS 0xFFF -#define DMA_MINC_ENABLE 1 -#define DMA_MINC_DISABLE 0 +#define DMA_MINC_ENABLE 1 +#define DMA_MINC_DISABLE 0 class TFT_SPI { private: - static uint32_t ReadID(uint16_t Reg); - static void Transmit(uint16_t Data); - static void TransmitDMA(uint32_t MemoryIncrease, uint16_t *Data, uint16_t Count); + static uint32_t readID(const uint16_t inReg); + static void transmit(uint16_t data); + static void transmit(uint32_t memoryIncrease, uint16_t *data, uint16_t count); + static void transmitDMA(uint32_t memoryIncrease, uint16_t *data, uint16_t count); public: static SPIClass SPIx; - static void Init(); - static uint32_t GetID(); + static void init(); + static uint32_t getID(); static bool isBusy(); - static void Abort(); + static void abort(); - static void DataTransferBegin(uint16_t DataWidth = DATASIZE_16BIT); - static void DataTransferEnd() { OUT_WRITE(TFT_CS_PIN, HIGH); SPIx.end(); }; - static void DataTransferAbort(); + static void dataTransferBegin(uint16_t dataWidth=DATASIZE_16BIT); + static void dataTransferEnd() { WRITE(TFT_CS_PIN, HIGH); SSP_Cmd(LPC_SSPx, DISABLE); }; + static void dataTransferAbort(); - static void WriteData(uint16_t Data) { Transmit(Data); } - static void WriteReg(uint16_t Reg) { OUT_WRITE(TFT_A0_PIN, LOW); Transmit(Reg); OUT_WRITE(TFT_A0_PIN, HIGH); } + static void writeData(uint16_t data) { transmit(data); } + static void writeReg(const uint16_t inReg) { WRITE(TFT_DC_PIN, LOW); transmit(inReg); WRITE(TFT_DC_PIN, HIGH); } - static void WriteSequence(uint16_t *Data, uint16_t Count) { TransmitDMA(DMA_MINC_ENABLE, Data, Count); } - // static void WriteMultiple(uint16_t Color, uint16_t Count) { static uint16_t Data; Data = Color; TransmitDMA(DMA_MINC_DISABLE, &Data, Count); } - static void WriteMultiple(uint16_t Color, uint32_t Count) { - static uint16_t Data; Data = Color; - //LPC dma can only write 0xFFF bytes at once. - #define MAX_DMA_SIZE (0xFFF - 1) - while (Count > 0) { - TransmitDMA(DMA_MINC_DISABLE, &Data, Count > MAX_DMA_SIZE ? MAX_DMA_SIZE : Count); - Count = Count > MAX_DMA_SIZE ? Count - MAX_DMA_SIZE : 0; + static void writeSequence_DMA(uint16_t *data, uint16_t count) { transmitDMA(DMA_MINC_ENABLE, data, count); } + static void writeMultiple_DMA(uint16_t color, uint16_t count) { static uint16_t data; data = color; transmitDMA(DMA_MINC_DISABLE, &data, count); } + + static void writeSequence(uint16_t *data, uint16_t count) { transmit(DMA_MINC_ENABLE, data, count); } + static void writeMultiple(uint16_t color, uint32_t count) { + while (count > 0) { + transmit(DMA_MINC_DISABLE, &color, count > DMA_MAX_WORDS ? DMA_MAX_WORDS : count); + count = count > DMA_MAX_WORDS ? count - DMA_MAX_WORDS : 0; } - #undef MAX_DMA_SIZE } }; diff --git a/Marlin/src/HAL/LPC1768/tft/xpt2046.cpp b/Marlin/src/HAL/LPC1768/tft/xpt2046.cpp index 9c1e158981..a737266c68 100644 --- a/Marlin/src/HAL/LPC1768/tft/xpt2046.cpp +++ b/Marlin/src/HAL/LPC1768/tft/xpt2046.cpp @@ -20,6 +20,8 @@ * */ +#ifdef TARGET_LPC1768 + #include "../../../inc/MarlinConfig.h" #if HAS_TFT_XPT2046 || HAS_RES_TOUCH_BUTTONS @@ -43,10 +45,12 @@ uint16_t delta(uint16_t a, uint16_t b) { return a > b ? a - b : b - a; } } #endif -void XPT2046::Init() { - SET_INPUT(TOUCH_MISO_PIN); - SET_OUTPUT(TOUCH_MOSI_PIN); - SET_OUTPUT(TOUCH_SCK_PIN); +void XPT2046::init() { + #if DISABLED(TOUCH_BUTTONS_HW_SPI) + SET_INPUT(TOUCH_MISO_PIN); + SET_OUTPUT(TOUCH_MOSI_PIN); + SET_OUTPUT(TOUCH_SCK_PIN); + #endif OUT_WRITE(TOUCH_CS_PIN, HIGH); #if PIN_EXISTS(TOUCH_INT) @@ -70,9 +74,8 @@ bool XPT2046::isTouched() { ); } -bool XPT2046::getRawPoint(int16_t *x, int16_t *y) { - if (isBusy()) return false; - if (!isTouched()) return false; +bool XPT2046::getRawPoint(int16_t * const x, int16_t * const y) { + if (isBusy() || !isTouched()) return false; *x = getRawData(XPT2046_X); *y = getRawData(XPT2046_Y); return isTouched(); @@ -81,7 +84,7 @@ bool XPT2046::getRawPoint(int16_t *x, int16_t *y) { uint16_t XPT2046::getRawData(const XPTCoordinate coordinate) { uint16_t data[3]; - DataTransferBegin(); + dataTransferBegin(); TERN_(TOUCH_BUTTONS_HW_SPI, SPIx.begin()); for (uint16_t i = 0; i < 3 ; i++) { @@ -90,7 +93,7 @@ uint16_t XPT2046::getRawData(const XPTCoordinate coordinate) { } TERN_(TOUCH_BUTTONS_HW_SPI, SPIx.end()); - DataTransferEnd(); + dataTransferEnd(); uint16_t delta01 = delta(data[0], data[1]), delta02 = delta(data[0], data[2]), @@ -103,18 +106,18 @@ uint16_t XPT2046::getRawData(const XPTCoordinate coordinate) { } uint16_t XPT2046::IO(uint16_t data) { - return TERN(TOUCH_BUTTONS_HW_SPI, HardwareIO, SoftwareIO)(data); + return TERN(TOUCH_BUTTONS_HW_SPI, hardwareIO, softwareIO)(data); } extern uint8_t spiTransfer(uint8_t b); #if ENABLED(TOUCH_BUTTONS_HW_SPI) - uint16_t XPT2046::HardwareIO(uint16_t data) { + uint16_t XPT2046::hardwareIO(uint16_t data) { return SPIx.transfer(data & 0xFF); } #endif -uint16_t XPT2046::SoftwareIO(uint16_t data) { +uint16_t XPT2046::softwareIO(uint16_t data) { uint16_t result = 0; for (uint8_t j = 0x80; j; j >>= 1) { @@ -128,4 +131,5 @@ uint16_t XPT2046::SoftwareIO(uint16_t data) { return result; } -#endif // HAS_TFT_XPT2046 +#endif // HAS_TFT_XPT2046 || HAS_RES_TOUCH_BUTTONS +#endif // TARGET_LPC1768 diff --git a/Marlin/src/HAL/LPC1768/tft/xpt2046.h b/Marlin/src/HAL/LPC1768/tft/xpt2046.h index 7c456cf00e..9a19e3c98d 100644 --- a/Marlin/src/HAL/LPC1768/tft/xpt2046.h +++ b/Marlin/src/HAL/LPC1768/tft/xpt2046.h @@ -65,12 +65,12 @@ private: static uint16_t getRawData(const XPTCoordinate coordinate); static bool isTouched(); - static void DataTransferBegin() { WRITE(TOUCH_CS_PIN, LOW); }; - static void DataTransferEnd() { WRITE(TOUCH_CS_PIN, HIGH); }; + static void dataTransferBegin() { WRITE(TOUCH_CS_PIN, LOW); }; + static void dataTransferEnd() { WRITE(TOUCH_CS_PIN, HIGH); }; #if ENABLED(TOUCH_BUTTONS_HW_SPI) - static uint16_t HardwareIO(uint16_t data); + static uint16_t hardwareIO(uint16_t data); #endif - static uint16_t SoftwareIO(uint16_t data); + static uint16_t softwareIO(uint16_t data); static uint16_t IO(uint16_t data = 0); public: @@ -78,6 +78,6 @@ public: static SPIClass SPIx; #endif - static void Init(); - static bool getRawPoint(int16_t *x, int16_t *y); + static void init(); + static bool getRawPoint(int16_t * const x, int16_t * const y); }; diff --git a/Marlin/src/HAL/LPC1768/timers.cpp b/Marlin/src/HAL/LPC1768/timers.cpp index bbb13f81da..b541ab6e6a 100644 --- a/Marlin/src/HAL/LPC1768/timers.cpp +++ b/Marlin/src/HAL/LPC1768/timers.cpp @@ -1,9 +1,9 @@ /** * Marlin 3D Printer Firmware - * * Copyright (c) 2020 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] - * Copyright (c) 2016 Bob Cousins bobcousins42@googlemail.com - * Copyright (c) 2015-2016 Nico Tonnhofer wurstnase.reprap@gmail.com + * + * 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 diff --git a/Marlin/src/HAL/LPC1768/timers.h b/Marlin/src/HAL/LPC1768/timers.h index c6d7bc632e..bae01703ed 100644 --- a/Marlin/src/HAL/LPC1768/timers.h +++ b/Marlin/src/HAL/LPC1768/timers.h @@ -1,8 +1,9 @@ /** * Marlin 3D Printer Firmware - * * Copyright (c) 2020 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] - * Copyright (c) 2016 Bob Cousins bobcousins42@googlemail.com + * + * 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 diff --git a/Marlin/src/HAL/LPC1768/u8g/LCD_defines.h b/Marlin/src/HAL/LPC1768/u8g/LCD_defines.h index d2260037b6..5b58f1223a 100644 --- a/Marlin/src/HAL/LPC1768/u8g/LCD_defines.h +++ b/Marlin/src/HAL/LPC1768/u8g/LCD_defines.h @@ -25,25 +25,22 @@ * LPC1768 LCD-specific defines */ -// The following are optional depending on the platform. +#ifndef U8G_HAL_LINKS -// definitions of HAL specific com and device drivers. -uint8_t u8g_com_HAL_LPC1768_hw_spi_fn(u8g_t *u8g, uint8_t msg, uint8_t arg_val, void *arg_ptr); -uint8_t u8g_com_HAL_LPC1768_sw_spi_fn(u8g_t *u8g, uint8_t msg, uint8_t arg_val, void *arg_ptr); -uint8_t u8g_com_HAL_LPC1768_ST7920_hw_spi_fn(u8g_t *u8g, uint8_t msg, uint8_t arg_val, void *arg_ptr); -uint8_t u8g_com_HAL_LPC1768_ST7920_sw_spi_fn(u8g_t *u8g, uint8_t msg, uint8_t arg_val, void *arg_ptr); -uint8_t u8g_com_HAL_LPC1768_ssd_hw_i2c_fn(u8g_t *u8g, uint8_t msg, uint8_t arg_val, void *arg_ptr); + #define U8G_COM_SSD_I2C_HAL u8g_com_arduino_ssd_i2c_fn // See U8glib-HAL +#else -// connect U8g com generic com names to the desired driver -#define U8G_COM_HW_SPI u8g_com_HAL_LPC1768_hw_spi_fn // use LPC1768 specific hardware SPI routine -#define U8G_COM_SW_SPI u8g_com_HAL_LPC1768_sw_spi_fn // use LPC1768 specific software SPI routine -#define U8G_COM_ST7920_HW_SPI u8g_com_HAL_LPC1768_ST7920_hw_spi_fn -#define U8G_COM_ST7920_SW_SPI u8g_com_HAL_LPC1768_ST7920_sw_spi_fn -#define U8G_COM_SSD_I2C u8g_com_HAL_LPC1768_ssd_hw_i2c_fn + uint8_t u8g_com_HAL_LPC1768_hw_spi_fn(u8g_t *u8g, uint8_t msg, uint8_t arg_val, void *arg_ptr); + uint8_t u8g_com_HAL_LPC1768_sw_spi_fn(u8g_t *u8g, uint8_t msg, uint8_t arg_val, void *arg_ptr); + uint8_t u8g_com_HAL_LPC1768_ST7920_hw_spi_fn(u8g_t *u8g, uint8_t msg, uint8_t arg_val, void *arg_ptr); + uint8_t u8g_com_HAL_LPC1768_ST7920_sw_spi_fn(u8g_t *u8g, uint8_t msg, uint8_t arg_val, void *arg_ptr); + uint8_t u8g_com_HAL_LPC1768_ssd_hw_i2c_fn(u8g_t *u8g, uint8_t msg, uint8_t arg_val, void *arg_ptr); -// let these default for now -#define U8G_COM_PARALLEL u8g_com_null_fn -#define U8G_COM_T6963 u8g_com_null_fn -#define U8G_COM_FAST_PARALLEL u8g_com_null_fn -#define U8G_COM_UC_I2C u8g_com_null_fn + #define U8G_COM_HAL_SW_SPI_FN u8g_com_HAL_LPC1768_sw_spi_fn + #define U8G_COM_HAL_HW_SPI_FN u8g_com_HAL_LPC1768_hw_spi_fn + #define U8G_COM_ST7920_HAL_SW_SPI u8g_com_HAL_LPC1768_ST7920_sw_spi_fn + #define U8G_COM_ST7920_HAL_HW_SPI u8g_com_HAL_LPC1768_ST7920_hw_spi_fn + #define U8G_COM_SSD_I2C_HAL u8g_com_HAL_LPC1768_ssd_hw_i2c_fn + +#endif diff --git a/Marlin/src/HAL/LPC1768/u8g/u8g_com_HAL_LPC1768_hw_spi.cpp b/Marlin/src/HAL/LPC1768/u8g/u8g_com_HAL_LPC1768_hw_spi.cpp index 0118f92847..406fc4840c 100644 --- a/Marlin/src/HAL/LPC1768/u8g/u8g_com_HAL_LPC1768_hw_spi.cpp +++ b/Marlin/src/HAL/LPC1768/u8g/u8g_com_HAL_LPC1768_hw_spi.cpp @@ -125,5 +125,4 @@ uint8_t u8g_com_HAL_LPC1768_hw_spi_fn(u8g_t *u8g, uint8_t msg, uint8_t arg_val, } #endif // HAS_MARLINUI_U8GLIB - #endif // TARGET_LPC1768 diff --git a/Marlin/src/HAL/LPC1768/u8g/u8g_com_HAL_LPC1768_ssd_hw_i2c.cpp b/Marlin/src/HAL/LPC1768/u8g/u8g_com_HAL_LPC1768_ssd_hw_i2c.cpp index bf76eaf0f4..3dea365ac7 100644 --- a/Marlin/src/HAL/LPC1768/u8g/u8g_com_HAL_LPC1768_ssd_hw_i2c.cpp +++ b/Marlin/src/HAL/LPC1768/u8g/u8g_com_HAL_LPC1768_ssd_hw_i2c.cpp @@ -194,5 +194,4 @@ uint8_t u8g_com_HAL_LPC1768_ssd_hw_i2c_fn(u8g_t *u8g, uint8_t msg, uint8_t arg_v } #endif // HAS_MARLINUI_U8GLIB - #endif // TARGET_LPC1768 diff --git a/Marlin/src/HAL/LPC1768/u8g/u8g_com_HAL_LPC1768_st7920_hw_spi.cpp b/Marlin/src/HAL/LPC1768/u8g/u8g_com_HAL_LPC1768_st7920_hw_spi.cpp index ce7b338019..c029dc0680 100644 --- a/Marlin/src/HAL/LPC1768/u8g/u8g_com_HAL_LPC1768_st7920_hw_spi.cpp +++ b/Marlin/src/HAL/LPC1768/u8g/u8g_com_HAL_LPC1768_st7920_hw_spi.cpp @@ -134,5 +134,4 @@ uint8_t u8g_com_HAL_LPC1768_ST7920_hw_spi_fn(u8g_t *u8g, uint8_t msg, uint8_t ar } #endif // HAS_MARLINUI_U8GLIB - #endif // TARGET_LPC1768 diff --git a/Marlin/src/HAL/LPC1768/u8g/u8g_com_HAL_LPC1768_sw_spi.cpp b/Marlin/src/HAL/LPC1768/u8g/u8g_com_HAL_LPC1768_sw_spi.cpp index f116a9b80a..4edd0d3886 100644 --- a/Marlin/src/HAL/LPC1768/u8g/u8g_com_HAL_LPC1768_sw_spi.cpp +++ b/Marlin/src/HAL/LPC1768/u8g/u8g_com_HAL_LPC1768_sw_spi.cpp @@ -75,7 +75,7 @@ uint8_t swSpiTransfer_mode_0(uint8_t b, const uint8_t spi_speed, const pin_t sck_pin, const pin_t miso_pin, const pin_t mosi_pin ) { - LOOP_L_N(i, 8) { + for (uint8_t i = 0; i < 8; ++i) { if (spi_speed == 0) { LPC176x::gpio_set(mosi_pin, !!(b & 0x80)); LPC176x::gpio_set(sck_pin, HIGH); @@ -85,16 +85,16 @@ uint8_t swSpiTransfer_mode_0(uint8_t b, const uint8_t spi_speed, const pin_t sck } else { const uint8_t state = (b & 0x80) ? HIGH : LOW; - LOOP_L_N(j, spi_speed) + for (uint8_t j = 0; j < spi_speed; ++j) LPC176x::gpio_set(mosi_pin, state); - LOOP_L_N(j, spi_speed + (miso_pin >= 0 ? 0 : 1)) + for (uint8_t j = 0; j < spi_speed + (miso_pin >= 0 ? 0 : 1); ++j) LPC176x::gpio_set(sck_pin, HIGH); b <<= 1; if (miso_pin >= 0 && LPC176x::gpio_get(miso_pin)) b |= 1; - LOOP_L_N(j, spi_speed) + for (uint8_t j = 0; j < spi_speed; ++j) LPC176x::gpio_set(sck_pin, LOW); } } @@ -104,7 +104,7 @@ uint8_t swSpiTransfer_mode_0(uint8_t b, const uint8_t spi_speed, const pin_t sck uint8_t swSpiTransfer_mode_3(uint8_t b, const uint8_t spi_speed, const pin_t sck_pin, const pin_t miso_pin, const pin_t mosi_pin ) { - LOOP_L_N(i, 8) { + for (uint8_t i = 0; i < 8; ++i) { const uint8_t state = (b & 0x80) ? HIGH : LOW; if (spi_speed == 0) { LPC176x::gpio_set(sck_pin, LOW); @@ -113,13 +113,13 @@ uint8_t swSpiTransfer_mode_3(uint8_t b, const uint8_t spi_speed, const pin_t sck LPC176x::gpio_set(sck_pin, HIGH); } else { - LOOP_L_N(j, spi_speed + (miso_pin >= 0 ? 0 : 1)) + for (uint8_t j = 0; j < spi_speed + (miso_pin >= 0 ? 0 : 1); ++j) LPC176x::gpio_set(sck_pin, LOW); - LOOP_L_N(j, spi_speed) + for (uint8_t j = 0; j < spi_speed; ++j) LPC176x::gpio_set(mosi_pin, state); - LOOP_L_N(j, spi_speed) + for (uint8_t j = 0; j < spi_speed; ++j) LPC176x::gpio_set(sck_pin, HIGH); } b <<= 1; @@ -131,8 +131,8 @@ uint8_t swSpiTransfer_mode_3(uint8_t b, const uint8_t spi_speed, const pin_t sck static uint8_t SPI_speed = 0; -static void u8g_sw_spi_HAL_LPC1768_shift_out(uint8_t dataPin, uint8_t clockPin, uint8_t val) { - #if EITHER(FYSETC_MINI_12864, MKS_MINI_12864) +static void u8g_sw_spi_shift_out(uint8_t dataPin, uint8_t clockPin, uint8_t val) { + #if ANY(FYSETC_MINI_12864, MKS_MINI_12864) swSpiTransfer_mode_3(val, SPI_speed, clockPin, -1, dataPin); #else swSpiTransfer_mode_0(val, SPI_speed, clockPin, -1, dataPin); @@ -160,10 +160,10 @@ uint8_t u8g_com_HAL_LPC1768_sw_spi_fn(u8g_t *u8g, uint8_t msg, uint8_t arg_val, break; case U8G_COM_MSG_CHIP_SELECT: - #if EITHER(FYSETC_MINI_12864, MKS_MINI_12864) // LCD SPI is running mode 3 while SD card is running mode 0 - if (arg_val) { // SCK idle state needs to be set to the proper idle state before - // the next chip select goes active - u8g_SetPILevel(u8g, U8G_PI_SCK, 1); // Set SCK to mode 3 idle state before CS goes active + #if ANY(FYSETC_MINI_12864, MKS_MINI_12864) // LCD SPI is running mode 3 while SD card is running mode 0 + if (arg_val) { // SCK idle state needs to be set to the proper idle state before + // the next chip select goes active + u8g_SetPILevel(u8g, U8G_PI_SCK, 1); // Set SCK to mode 3 idle state before CS goes active u8g_SetPILevel(u8g, U8G_PI_CS, LOW); } else { @@ -176,13 +176,13 @@ uint8_t u8g_com_HAL_LPC1768_sw_spi_fn(u8g_t *u8g, uint8_t msg, uint8_t arg_val, break; case U8G_COM_MSG_WRITE_BYTE: - u8g_sw_spi_HAL_LPC1768_shift_out(u8g->pin_list[U8G_PI_MOSI], u8g->pin_list[U8G_PI_SCK], arg_val); + u8g_sw_spi_shift_out(u8g->pin_list[U8G_PI_MOSI], u8g->pin_list[U8G_PI_SCK], arg_val); break; case U8G_COM_MSG_WRITE_SEQ: { uint8_t *ptr = (uint8_t *)arg_ptr; while (arg_val > 0) { - u8g_sw_spi_HAL_LPC1768_shift_out(u8g->pin_list[U8G_PI_MOSI], u8g->pin_list[U8G_PI_SCK], *ptr++); + u8g_sw_spi_shift_out(u8g->pin_list[U8G_PI_MOSI], u8g->pin_list[U8G_PI_SCK], *ptr++); arg_val--; } } @@ -191,7 +191,7 @@ uint8_t u8g_com_HAL_LPC1768_sw_spi_fn(u8g_t *u8g, uint8_t msg, uint8_t arg_val, case U8G_COM_MSG_WRITE_SEQ_P: { uint8_t *ptr = (uint8_t *)arg_ptr; while (arg_val > 0) { - u8g_sw_spi_HAL_LPC1768_shift_out(u8g->pin_list[U8G_PI_MOSI], u8g->pin_list[U8G_PI_SCK], u8g_pgm_read(ptr)); + u8g_sw_spi_shift_out(u8g->pin_list[U8G_PI_MOSI], u8g->pin_list[U8G_PI_SCK], u8g_pgm_read(ptr)); ptr++; arg_val--; } diff --git a/Marlin/src/HAL/NATIVE_SIM/HAL.h b/Marlin/src/HAL/NATIVE_SIM/HAL.h index 6620361144..8e88e50230 100644 --- a/Marlin/src/HAL/NATIVE_SIM/HAL.h +++ b/Marlin/src/HAL/NATIVE_SIM/HAL.h @@ -1,9 +1,9 @@ /** * Marlin 3D Printer Firmware - * * Copyright (c) 2021 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] - * Copyright (c) 2016 Bob Cousins bobcousins42@googlemail.com - * Copyright (c) 2015-2016 Nico Tonnhofer wurstnase.reprap@gmail.com + * + * 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 @@ -114,8 +114,8 @@ extern MSerialT serial_stream_3; // ADC // ------------------------ -#define HAL_ADC_VREF 5.0 -#define HAL_ADC_RESOLUTION 10 +#define HAL_ADC_VREF_MV 5000 +#define HAL_ADC_RESOLUTION 10 /* ---------------- Delay in cycles */ @@ -208,8 +208,8 @@ public: MarlinHAL() {} // Watchdog - static void watchdog_init() IF_DISABLED(USE_WATCHDOG, {}); - static void watchdog_refresh() IF_DISABLED(USE_WATCHDOG, {}); + static void watchdog_init(); + static void watchdog_refresh(); static void init() {} // Called early in setup() static void init_board() {} // Called less early in setup() diff --git a/Marlin/src/HAL/NATIVE_SIM/MarlinSPI.h b/Marlin/src/HAL/NATIVE_SIM/MarlinSPI.h index b5cc6f02a4..0c447ba4cb 100644 --- a/Marlin/src/HAL/NATIVE_SIM/MarlinSPI.h +++ b/Marlin/src/HAL/NATIVE_SIM/MarlinSPI.h @@ -1,9 +1,9 @@ /** * Marlin 3D Printer Firmware - * * Copyright (c) 2021 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] - * Copyright (c) 2016 Bob Cousins bobcousins42@googlemail.com - * Copyright (c) 2015-2016 Nico Tonnhofer wurstnase.reprap@gmail.com + * + * 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 diff --git a/Marlin/src/HAL/NATIVE_SIM/inc/SanityCheck.h b/Marlin/src/HAL/NATIVE_SIM/inc/SanityCheck.h index 2d7bef23a3..615e5254c9 100644 --- a/Marlin/src/HAL/NATIVE_SIM/inc/SanityCheck.h +++ b/Marlin/src/HAL/NATIVE_SIM/inc/SanityCheck.h @@ -31,7 +31,7 @@ #endif #if ENABLED(FAST_PWM_FAN) || SPINDLE_LASER_FREQUENCY - #error "Features requiring Hardware PWM (FAST_PWM_FAN, SPINDLE_LASER_FREQUENCY) are not yet supported on LINUX." + #error "Features requiring Hardware PWM (FAST_PWM_FAN, SPINDLE_LASER_FREQUENCY) are not yet supported for HAL/LINUX." #endif #if HAS_TMC_SW_SERIAL diff --git a/Marlin/src/HAL/NATIVE_SIM/pinsDebug.cpp b/Marlin/src/HAL/NATIVE_SIM/pinsDebug.cpp new file mode 100644 index 0000000000..c4d56c6c21 --- /dev/null +++ b/Marlin/src/HAL/NATIVE_SIM/pinsDebug.cpp @@ -0,0 +1,48 @@ +/** + * Marlin 3D Printer Firmware + * Copyright (c) 2021 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] + * + * Based on Sprinter and grbl. + * Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +#ifdef __PLAT_NATIVE_SIM__ + +#include "../../inc/MarlinConfig.h" +#include "pinsDebug.h" + +int8_t ADC_pin_mode(pin_t pin) { return -1; } + +int8_t get_pin_mode(const pin_t pin) { return VALID_PIN(pin) ? 0 : -1; } + +bool GET_PINMODE(const pin_t pin) { + const int8_t pin_mode = get_pin_mode(pin); + if (pin_mode == -1 || pin_mode == ADC_pin_mode(pin)) // Invalid pin or active analog pin + return false; + + return (Gpio::getMode(pin) != 0); // Input/output state +} + +bool GET_ARRAY_IS_DIGITAL(const pin_t pin) { + return !IS_ANALOG(pin) || get_pin_mode(pin) != ADC_pin_mode(pin); +} + +void print_port(const pin_t) {} +void pwm_details(const pin_t) {} +bool pwm_status(const pin_t) { return false; } + +#endif diff --git a/Marlin/src/HAL/NATIVE_SIM/pinsDebug.h b/Marlin/src/HAL/NATIVE_SIM/pinsDebug.h index aa90eb39a3..3321d1484d 100644 --- a/Marlin/src/HAL/NATIVE_SIM/pinsDebug.h +++ b/Marlin/src/HAL/NATIVE_SIM/pinsDebug.h @@ -2,6 +2,9 @@ * Marlin 3D Printer Firmware * Copyright (c) 2021 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] * + * Based on Sprinter and grbl. + * Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm + * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or @@ -27,35 +30,19 @@ */ #define NUMBER_PINS_TOTAL NUM_DIGITAL_PINS -#define pwm_details(pin) pin = pin // do nothing // print PWM details -#define pwm_status(pin) false //Print a pin's PWM status. Return true if it's currently a PWM pin. #define IS_ANALOG(P) (DIGITAL_PIN_TO_ANALOG_PIN(P) >= 0 ? 1 : 0) #define digitalRead_mod(p) digitalRead(p) -#define PRINT_PORT(p) #define GET_ARRAY_PIN(p) pin_array[p].pin #define PRINT_ARRAY_NAME(x) do{ sprintf_P(buffer, PSTR("%-" STRINGIFY(MAX_NAME_LENGTH) "s"), pin_array[x].name); SERIAL_ECHO(buffer); }while(0) #define PRINT_PIN(p) do{ sprintf_P(buffer, PSTR("%3d "), p); SERIAL_ECHO(buffer); }while(0) #define PRINT_PIN_ANALOG(p) do{ sprintf_P(buffer, PSTR(" (A%2d) "), DIGITAL_PIN_TO_ANALOG_PIN(pin)); SERIAL_ECHO(buffer); }while(0) #define MULTI_NAME_PAD 16 // space needed to be pretty if not first name assigned to a pin -// active ADC function/mode/code values for PINSEL registers -inline constexpr int8_t ADC_pin_mode(pin_t pin) { - return (-1); -} - -inline int8_t get_pin_mode(pin_t pin) { - if (!VALID_PIN(pin)) return -1; - return 0; -} - -inline bool GET_PINMODE(pin_t pin) { - int8_t pin_mode = get_pin_mode(pin); - if (pin_mode == -1 || pin_mode == ADC_pin_mode(pin)) // found an invalid pin or active analog pin - return false; - - return (Gpio::getMode(pin) != 0); //input/output state -} - -inline bool GET_ARRAY_IS_DIGITAL(pin_t pin) { - return (!IS_ANALOG(pin) || get_pin_mode(pin) != ADC_pin_mode(pin)); -} +// Active ADC function/mode/code values for PINSEL registers +int8_t ADC_pin_mode(pin_t pin); +int8_t get_pin_mode(const pin_t pin); +bool GET_PINMODE(const pin_t pin); +bool GET_ARRAY_IS_DIGITAL(const pin_t pin); +void print_port(const pin_t); +void pwm_details(const pin_t); +bool pwm_status(const pin_t); diff --git a/Marlin/src/HAL/NATIVE_SIM/spi_pins.h b/Marlin/src/HAL/NATIVE_SIM/spi_pins.h index a5138e0ccb..9b1bae9a58 100644 --- a/Marlin/src/HAL/NATIVE_SIM/spi_pins.h +++ b/Marlin/src/HAL/NATIVE_SIM/spi_pins.h @@ -24,8 +24,8 @@ #include "../../core/macros.h" #include "../../inc/MarlinConfigPre.h" -#if BOTH(HAS_MARLINUI_U8GLIB, SDSUPPORT) && (LCD_PINS_D4 == SD_SCK_PIN || LCD_PINS_ENABLE == SD_MOSI_PIN || DOGLCD_SCK == SD_SCK_PIN || DOGLCD_MOSI == SD_MOSI_PIN) - #define LPC_SOFTWARE_SPI // If the SD card and LCD adapter share the same SPI pins, then software SPI is currently +#if ALL(HAS_MARLINUI_U8GLIB, HAS_MEDIA) && (LCD_PINS_D4 == SD_SCK_PIN || LCD_PINS_EN == SD_MOSI_PIN || DOGLCD_SCK == SD_SCK_PIN || DOGLCD_MOSI == SD_MOSI_PIN) + #define SOFTWARE_SPI // If the SD card and LCD adapter share the same SPI pins, then software SPI is currently // needed due to the speed and mode required for communicating with each device being different. // This requirement can be removed if the SPI access to these devices is updated to use // spiBeginTransaction. diff --git a/Marlin/src/HAL/NATIVE_SIM/tft/tft_spi.h b/Marlin/src/HAL/NATIVE_SIM/tft/tft_spi.h index b3e622f19a..944b8267f6 100644 --- a/Marlin/src/HAL/NATIVE_SIM/tft/tft_spi.h +++ b/Marlin/src/HAL/NATIVE_SIM/tft/tft_spi.h @@ -31,34 +31,37 @@ #endif #define DATASIZE_8BIT 8 -#define DATASIZE_16BIT 16 -#define TFT_IO_DRIVER TFT_SPI +#define DATASIZE_16BIT 16 +#define TFT_IO_DRIVER TFT_SPI +#define DMA_MAX_WORDS 0xFFFF -#define DMA_MINC_ENABLE 1 +#define DMA_MINC_ENABLE 1 #define DMA_MINC_DISABLE 0 class TFT_SPI { private: - static uint32_t ReadID(uint16_t Reg); - static void Transmit(uint16_t Data); - static void TransmitDMA(uint32_t MemoryIncrease, uint16_t *Data, uint16_t Count); + static uint32_t readID(const uint16_t inReg); + static void transmit(uint16_t data); + static void transmitDMA(uint32_t memoryIncrease, uint16_t *data, uint16_t count); public: // static SPIClass SPIx; - static void Init(); - static uint32_t GetID(); + static void init(); + static uint32_t getID(); static bool isBusy(); - static void Abort(); + static void abort(); - static void DataTransferBegin(uint16_t DataWidth = DATASIZE_16BIT); - static void DataTransferEnd(); - static void DataTransferAbort(); + static void dataTransferBegin(uint16_t dataWidth=DATASIZE_16BIT); + static void dataTransferEnd(); + static void dataTransferAbort(); - static void WriteData(uint16_t Data); - static void WriteReg(uint16_t Reg); + static void writeData(uint16_t data); + static void writeReg(const uint16_t inReg); - static void WriteSequence(uint16_t *Data, uint16_t Count); - // static void WriteMultiple(uint16_t Color, uint16_t Count); - static void WriteMultiple(uint16_t Color, uint32_t Count); + static void writeSequence_DMA(uint16_t *data, uint16_t count) { writeSequence(data, count); } + static void writeMultiple_DMA(uint16_t color, uint16_t count) { writeMultiple(color, count); } + + static void writeSequence(uint16_t *data, uint16_t count); + static void writeMultiple(uint16_t color, uint32_t count); }; diff --git a/Marlin/src/HAL/NATIVE_SIM/tft/xpt2046.h b/Marlin/src/HAL/NATIVE_SIM/tft/xpt2046.h index 4e999f88ff..d37f74c774 100644 --- a/Marlin/src/HAL/NATIVE_SIM/tft/xpt2046.h +++ b/Marlin/src/HAL/NATIVE_SIM/tft/xpt2046.h @@ -2,6 +2,9 @@ * Marlin 3D Printer Firmware * Copyright (c) 2021 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] * + * Based on Sprinter and grbl. + * Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm + * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or @@ -62,12 +65,12 @@ private: static uint16_t getRawData(const XPTCoordinate coordinate); static bool isTouched(); - static void DataTransferBegin(); - static void DataTransferEnd(); + static void dataTransferBegin(); + static void dataTransferEnd(); #if ENABLED(TOUCH_BUTTONS_HW_SPI) - static uint16_t HardwareIO(uint16_t data); + static uint16_t hardwareIO(uint16_t data); #endif - static uint16_t SoftwareIO(uint16_t data); + static uint16_t softwareIO(uint16_t data); static uint16_t IO(uint16_t data = 0); public: @@ -75,6 +78,6 @@ public: static SPIClass SPIx; #endif - static void Init(); - static bool getRawPoint(int16_t *x, int16_t *y); + static void init(); + static bool getRawPoint(int16_t * const x, int16_t * const y); }; diff --git a/Marlin/src/HAL/NATIVE_SIM/timers.h b/Marlin/src/HAL/NATIVE_SIM/timers.h index be38d583b6..d46e8e7b94 100644 --- a/Marlin/src/HAL/NATIVE_SIM/timers.h +++ b/Marlin/src/HAL/NATIVE_SIM/timers.h @@ -1,8 +1,9 @@ /** * Marlin 3D Printer Firmware - * * Copyright (c) 2021 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] - * Copyright (c) 2016 Bob Cousins bobcousins42@googlemail.com + * + * 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 diff --git a/Marlin/src/HAL/NATIVE_SIM/u8g/LCD_I2C_routines.h b/Marlin/src/HAL/NATIVE_SIM/u8g/LCD_I2C_routines.h index 6d5f91d3ba..ec263b6dd3 100644 --- a/Marlin/src/HAL/NATIVE_SIM/u8g/LCD_I2C_routines.h +++ b/Marlin/src/HAL/NATIVE_SIM/u8g/LCD_I2C_routines.h @@ -34,4 +34,3 @@ void u8g_i2c_stop(); #ifdef __cplusplus } #endif - diff --git a/Marlin/src/HAL/NATIVE_SIM/u8g/LCD_defines.h b/Marlin/src/HAL/NATIVE_SIM/u8g/LCD_defines.h index 44ffbfeb90..63701ca334 100644 --- a/Marlin/src/HAL/NATIVE_SIM/u8g/LCD_defines.h +++ b/Marlin/src/HAL/NATIVE_SIM/u8g/LCD_defines.h @@ -21,24 +21,14 @@ */ #pragma once -void usleep(uint64_t microsec); -// The following are optional depending on the platform. +/** + * Native/Simulator LCD-specific defines + */ + +void usleep(uint64_t microsec); -// definitions of HAL specific com and device drivers. uint8_t u8g_com_sw_spi_fn(u8g_t *u8g, uint8_t msg, uint8_t arg_val, void *arg_ptr); uint8_t u8g_com_ST7920_sw_spi_fn(u8g_t *u8g, uint8_t msg, uint8_t arg_val, void *arg_ptr); -// connect U8g com generic com names to the desired driver -#define U8G_COM_SW_SPI u8g_com_sw_spi_fn -#define U8G_COM_ST7920_SW_SPI u8g_com_ST7920_sw_spi_fn - -// let these default for now -#define U8G_COM_HW_SPI u8g_com_null_fn -#define U8G_COM_ST7920_HW_SPI u8g_com_null_fn -#define U8G_COM_SSD_I2C u8g_com_null_fn -#define U8G_COM_PARALLEL u8g_com_null_fn -#define U8G_COM_T6963 u8g_com_null_fn -#define U8G_COM_FAST_PARALLEL u8g_com_null_fn -#define U8G_COM_UC_I2C u8g_com_null_fn - - +#define U8G_COM_HAL_SW_SPI_FN u8g_com_sw_spi_fn +#define U8G_COM_ST7920_HAL_SW_SPI u8g_com_ST7920_sw_spi_fn diff --git a/Marlin/src/HAL/NATIVE_SIM/u8g/LCD_pin_routines.cpp b/Marlin/src/HAL/NATIVE_SIM/u8g/LCD_pin_routines.cpp index 91b7e0f67f..3566528079 100644 --- a/Marlin/src/HAL/NATIVE_SIM/u8g/LCD_pin_routines.cpp +++ b/Marlin/src/HAL/NATIVE_SIM/u8g/LCD_pin_routines.cpp @@ -43,7 +43,6 @@ void u8g_SetPinOutput(uint8_t internal_pin_number) { SET_DIR_OUTPUT(internal_pin void u8g_SetPinInput(uint8_t internal_pin_number) { SET_DIR_INPUT(internal_pin_number); } void u8g_SetPinLevel(uint8_t pin, uint8_t pin_status) { WRITE_PIN(pin, pin_status); } uint8_t u8g_GetPinLevel(uint8_t pin) { return READ_PIN(pin); } -void usleep(uint64_t microsec) { assert(false); /* why we here? */ } #ifdef __cplusplus } diff --git a/Marlin/src/HAL/NATIVE_SIM/u8g/u8g_com_st7920_sw_spi.cpp b/Marlin/src/HAL/NATIVE_SIM/u8g/u8g_com_st7920_sw_spi.cpp index c384cdd751..46f2798afa 100644 --- a/Marlin/src/HAL/NATIVE_SIM/u8g/u8g_com_st7920_sw_spi.cpp +++ b/Marlin/src/HAL/NATIVE_SIM/u8g/u8g_com_st7920_sw_spi.cpp @@ -100,6 +100,7 @@ static void u8g_com_st7920_write_byte_sw_spi(uint8_t rs, uint8_t val) { swSpiTransfer(val & 0x0F0, SPI_speed, SCK_pin_ST7920_HAL, -1, MOSI_pin_ST7920_HAL_HAL); swSpiTransfer(val << 4, SPI_speed, SCK_pin_ST7920_HAL, -1, MOSI_pin_ST7920_HAL_HAL); } + #ifdef __cplusplus extern "C" { #endif @@ -128,7 +129,7 @@ uint8_t u8g_com_ST7920_sw_spi_fn(u8g_t *u8g, uint8_t msg, uint8_t arg_val, void break; case U8G_COM_MSG_RESET: - if (U8G_PIN_NONE != u8g->pin_list[U8G_PI_RESET]) u8g_SetPILevel(u8g, U8G_PI_RESET, arg_val); + if (U8G_PIN_NONE != u8g->pin_list[U8G_PI_RESET]) u8g_SetPILevel(u8g, U8G_PI_RESET, arg_val); break; case U8G_COM_MSG_ADDRESS: /* define cmd (arg_val = 0) or data mode (arg_val = 1) */ @@ -163,9 +164,10 @@ uint8_t u8g_com_ST7920_sw_spi_fn(u8g_t *u8g, uint8_t msg, uint8_t arg_val, void } return 1; } + #ifdef __cplusplus } #endif #endif // IS_U8GLIB_ST7920 -#endif // TARGET_LPC1768 +#endif // __PLAT_NATIVE_SIM__ diff --git a/Marlin/src/HAL/NATIVE_SIM/u8g/u8g_com_sw_spi.cpp b/Marlin/src/HAL/NATIVE_SIM/u8g/u8g_com_sw_spi.cpp index 7be84580b1..9184e2f618 100644 --- a/Marlin/src/HAL/NATIVE_SIM/u8g/u8g_com_sw_spi.cpp +++ b/Marlin/src/HAL/NATIVE_SIM/u8g/u8g_com_sw_spi.cpp @@ -70,7 +70,7 @@ #endif uint8_t swSpiTransfer_mode_0(uint8_t b, const uint8_t spi_speed, const pin_t sck_pin, const pin_t miso_pin, const pin_t mosi_pin ) { - LOOP_L_N(i, 8) { + for (uint8_t i = 0; i < 8; ++i) { if (spi_speed == 0) { WRITE_PIN(mosi_pin, !!(b & 0x80)); WRITE_PIN(sck_pin, HIGH); @@ -80,16 +80,16 @@ uint8_t swSpiTransfer_mode_0(uint8_t b, const uint8_t spi_speed, const pin_t sck } else { const uint8_t state = (b & 0x80) ? HIGH : LOW; - LOOP_L_N(j, spi_speed) + for (uint8_t j = 0; j < spi_speed; ++j) WRITE_PIN(mosi_pin, state); - LOOP_L_N(j, spi_speed + (miso_pin >= 0 ? 0 : 1)) + for (uint8_t j = 0; j < spi_speed + (miso_pin >= 0 ? 0 : 1); ++j) WRITE_PIN(sck_pin, HIGH); b <<= 1; if (miso_pin >= 0 && READ_PIN(miso_pin)) b |= 1; - LOOP_L_N(j, spi_speed) + for (uint8_t j = 0; j < spi_speed; ++j) WRITE_PIN(sck_pin, LOW); } } @@ -99,7 +99,7 @@ uint8_t swSpiTransfer_mode_0(uint8_t b, const uint8_t spi_speed, const pin_t sck uint8_t swSpiTransfer_mode_3(uint8_t b, const uint8_t spi_speed, const pin_t sck_pin, const pin_t miso_pin, const pin_t mosi_pin ) { - LOOP_L_N(i, 8) { + for (uint8_t i = 0; i < 8; ++i) { const uint8_t state = (b & 0x80) ? HIGH : LOW; if (spi_speed == 0) { WRITE_PIN(sck_pin, LOW); @@ -108,13 +108,13 @@ uint8_t swSpiTransfer_mode_3(uint8_t b, const uint8_t spi_speed, const pin_t sck WRITE_PIN(sck_pin, HIGH); } else { - LOOP_L_N(j, spi_speed + (miso_pin >= 0 ? 0 : 1)) + for (uint8_t j = 0; j < spi_speed + (miso_pin >= 0 ? 0 : 1); ++j) WRITE_PIN(sck_pin, LOW); - LOOP_L_N(j, spi_speed) + for (uint8_t j = 0; j < spi_speed; ++j) WRITE_PIN(mosi_pin, state); - LOOP_L_N(j, spi_speed) + for (uint8_t j = 0; j < spi_speed; ++j) WRITE_PIN(sck_pin, HIGH); } b <<= 1; @@ -131,7 +131,7 @@ static uint8_t swSpiInit(const uint8_t spi_speed, const uint8_t clk_pin, const u } static void u8g_sw_spi_shift_out(uint8_t dataPin, uint8_t clockPin, uint8_t val) { - #if EITHER(FYSETC_MINI_12864, MKS_MINI_12864) + #if ANY(FYSETC_MINI_12864, MKS_MINI_12864) swSpiTransfer_mode_3(val, SPI_speed, clockPin, -1, dataPin); #else swSpiTransfer_mode_0(val, SPI_speed, clockPin, -1, dataPin); @@ -159,10 +159,10 @@ uint8_t u8g_com_sw_spi_fn(u8g_t *u8g, uint8_t msg, uint8_t arg_val, void *arg_pt break; case U8G_COM_MSG_CHIP_SELECT: - #if EITHER(FYSETC_MINI_12864, MKS_MINI_12864) // LCD SPI is running mode 3 while SD card is running mode 0 - if (arg_val) { // SCK idle state needs to be set to the proper idle state before - // the next chip select goes active - u8g_SetPILevel(u8g, U8G_PI_SCK, 1); // Set SCK to mode 3 idle state before CS goes active + #if ANY(FYSETC_MINI_12864, MKS_MINI_12864) // LCD SPI is running mode 3 while SD card is running mode 0 + if (arg_val) { // SCK idle state needs to be set to the proper idle state before + // the next chip select goes active + u8g_SetPILevel(u8g, U8G_PI_SCK, 1); // Set SCK to mode 3 idle state before CS goes active u8g_SetPILevel(u8g, U8G_PI_CS, LOW); } else { diff --git a/Marlin/src/HAL/SAMD21/HAL.cpp b/Marlin/src/HAL/SAMD21/HAL.cpp new file mode 100644 index 0000000000..1bc0406ab3 --- /dev/null +++ b/Marlin/src/HAL/SAMD21/HAL.cpp @@ -0,0 +1,212 @@ +/** + * Marlin 3D Printer Firmware + * Copyright (c) 2022 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 . + * + */ + +/** + * SAMD21 HAL developed by Bart Meijer (brupje) + * Based on SAMD51 HAL by Giuliano Zaro (AKA GMagician) + */ +#ifdef __SAMD21__ + +#include "../../inc/MarlinConfig.h" + +#include + +#if USING_HW_SERIALUSB + DefaultSerial1 MSerialUSB(false, SerialUSB); +#endif +#if USING_HW_SERIAL0 + DefaultSerial2 MSerial1(false, Serial1); +#endif +#if USING_HW_SERIAL1 + DefaultSerial3 MSerial2(false, Serial2); +#endif + + + +#define WDT_CONFIG_PER_7_Val 0x9u +#define WDT_CONFIG_PER_Pos 0 +#define WDT_CONFIG_PER_7 (WDT_CONFIG_PER_7_Val << WDT_CONFIG_PER_Pos) + +#if ENABLED(USE_WATCHDOG) + + #define WDT_TIMEOUT_REG TERN(WATCHDOG_DURATION_8S, WDT_CONFIG_PER_CYC8192, WDT_CONFIG_PER_CYC4096) // 4 or 8 second timeout + + void MarlinHAL::watchdog_init() { + // Set up the generic clock (GCLK2) used to clock the watchdog timer at 1.024kHz + GCLK->GENDIV.reg = GCLK_GENDIV_DIV(4) | // Divide the 32.768kHz clock source by divisor 32, where 2^(4 + 1): 32.768kHz/32=1.024kHz + GCLK_GENDIV_ID(2); // Select Generic Clock (GCLK) 2 + while (GCLK->STATUS.bit.SYNCBUSY); // Wait for synchronization + + REG_GCLK_GENCTRL = GCLK_GENCTRL_DIVSEL | // Set to divide by 2^(GCLK_GENDIV_DIV(4) + 1) + GCLK_GENCTRL_IDC | // Set the duty cycle to 50/50 HIGH/LOW + GCLK_GENCTRL_GENEN | // Enable GCLK2 + GCLK_GENCTRL_SRC_OSCULP32K | // Set the clock source to the ultra low power oscillator (OSCULP32K) + GCLK_GENCTRL_ID(2); // Select GCLK2 + while (GCLK->STATUS.bit.SYNCBUSY); // Wait for synchronization + + // Feed GCLK2 to WDT (Watchdog Timer) + REG_GCLK_CLKCTRL = GCLK_CLKCTRL_CLKEN | // Enable GCLK2 to the WDT + GCLK_CLKCTRL_GEN_GCLK2 | // Select GCLK2 + GCLK_CLKCTRL_ID_WDT; // Feed the GCLK2 to the WDT + while (GCLK->STATUS.bit.SYNCBUSY); // Wait for synchronization + + WDT->CONFIG.bit.PER = WDT_CONFIG_PER_7; // Set the WDT reset timeout to 4 seconds + while (WDT->STATUS.bit.SYNCBUSY); // Wait for synchronization + REG_WDT_CTRL = WDT_CTRL_ENABLE; // Enable the WDT in normal mode + while (WDT->STATUS.bit.SYNCBUSY); // Wait for synchronization + } + + // Reset watchdog. MUST be called at least every 4 seconds after the + // first watchdog_init or SAMD will go into emergency procedures. + void MarlinHAL::watchdog_refresh() { + WDT->CLEAR.reg = WDT_CLEAR_CLEAR_KEY; + while (WDT->STATUS.bit.SYNCBUSY); + } + +#endif + +// ------------------------ +// Types +// ------------------------ + +// ------------------------ +// Private Variables +// ------------------------ + +// ------------------------ +// Private functions +// ------------------------ + +void MarlinHAL::dma_init() {} + +// ------------------------ +// Public functions +// ------------------------ + +// HAL initialization task +void MarlinHAL::init() { + TERN_(DMA_IS_REQUIRED, dma_init()); + #if HAS_MEDIA + #if HAS_SD_DETECT && SD_CONNECTION_IS(ONBOARD) + SET_INPUT_PULLUP(SD_DETECT_PIN); + #endif + OUT_WRITE(SDSS, HIGH); // Try to set SDSS inactive before any other SPI users start up + #endif +} + +#pragma push_macro("WDT") +#undef WDT // Required to be able to use '.bit.WDT'. Compiler wrongly replace struct field with WDT define +uint8_t MarlinHAL::get_reset_source() { + + return 0; +} +#pragma pop_macro("WDT") + +void MarlinHAL::reboot() { NVIC_SystemReset(); } + +extern "C" { + void * _sbrk(int incr); + extern unsigned int __bss_end__; // end of bss section +} + +// Return free memory between end of heap (or end bss) and whatever is current +int freeMemory() { + int free_memory, heap_end = (int)_sbrk(0); + return (int)&free_memory - (heap_end ?: (int)&__bss_end__); +} + +// ------------------------ +// ADC +// ------------------------ + +uint16_t MarlinHAL::adc_result; + +void MarlinHAL::adc_init() { + /* thanks to https://www.eevblog.com/forum/microcontrollers/samd21g18-adc-with-resrdy-interrupts-only-reads-once-or-twice/ */ + + ADC->CTRLA.bit.ENABLE = false; + while(ADC->STATUS.bit.SYNCBUSY); + + // load chip corrections + uint32_t bias = (*((uint32_t *) ADC_FUSES_BIASCAL_ADDR) & ADC_FUSES_BIASCAL_Msk) >> ADC_FUSES_BIASCAL_Pos; + uint32_t linearity = (*((uint32_t *) ADC_FUSES_LINEARITY_0_ADDR) & ADC_FUSES_LINEARITY_0_Msk) >> ADC_FUSES_LINEARITY_0_Pos; + linearity |= ((*((uint32_t *) ADC_FUSES_LINEARITY_1_ADDR) & ADC_FUSES_LINEARITY_1_Msk) >> ADC_FUSES_LINEARITY_1_Pos) << 5; + + /* Wait for bus synchronization. */ + while (ADC->STATUS.bit.SYNCBUSY) {}; + + ADC->CALIB.reg = ADC_CALIB_BIAS_CAL(bias) | ADC_CALIB_LINEARITY_CAL(linearity); + + /* Wait for bus synchronization. */ + while (ADC->STATUS.bit.SYNCBUSY) {}; + + ADC->CTRLA.bit.SWRST = true; + while(ADC->STATUS.bit.SYNCBUSY); + + ADC->REFCTRL.reg = ADC_REFCTRL_REFSEL_INTVCC1; + ADC->AVGCTRL.reg = ADC_AVGCTRL_SAMPLENUM_32| ADC_AVGCTRL_ADJRES(4);; + + + ADC->CTRLB.reg = ADC_CTRLB_PRESCALER_DIV128 | + ADC_CTRLB_RESSEL_16BIT | + ADC_CTRLB_FREERUN; + while(ADC->STATUS.bit.SYNCBUSY); + + ADC->SAMPCTRL.bit.SAMPLEN = 0x00; + while(ADC->STATUS.bit.SYNCBUSY); + + ADC->INPUTCTRL.reg = ADC_INPUTCTRL_INPUTSCAN(HAL_ADC_AIN_LEN) // scan (INPUTSCAN + NUM_EXTUDERS - 1) pins + | ADC_INPUTCTRL_GAIN_DIV2 |ADC_INPUTCTRL_MUXNEG_GND| HAL_ADC_AIN_START ; /* set to first AIN */ + + while(ADC->STATUS.bit.SYNCBUSY); + + ADC->INTENSET.reg |= ADC_INTENSET_RESRDY; // enable Result Ready ADC interrupts + while (ADC->STATUS.bit.SYNCBUSY); + + NVIC_EnableIRQ(ADC_IRQn); // enable ADC interrupts + + NVIC_SetPriority(ADC_IRQn, 3); + + ADC->CTRLA.bit.ENABLE = true; +} + +volatile uint32_t adc_results[HAL_ADC_AIN_NUM_SENSORS]; + +void ADC_Handler() { + while(ADC->STATUS.bit.SYNCBUSY == 1); + int pos = ADC->INPUTCTRL.bit.INPUTOFFSET; + + adc_results[pos] = ADC->RESULT.reg; /* Read the value. */ + ADC->INTFLAG.reg = ADC_INTENSET_RESRDY; /* Clear the data ready flag. */ +} + +void MarlinHAL::adc_start(const pin_t pin) { + /* due to the way INPUTOFFSET works, the last sensor is the first position in the array + and we want the ADC_handler interrupt to be as simple possible, so we do the calculation here. + */ + unsigned int pos = PIN_TO_INPUTCTRL(pin) - HAL_ADC_AIN_START + 1; + if (pos == HAL_ADC_AIN_NUM_SENSORS) pos = 0; + adc_result = adc_results[pos]; // 16-bit resolution + //adc_result = 0xFFFF; +} + +#endif // __SAMD21__ diff --git a/Marlin/src/HAL/SAMD21/HAL.h b/Marlin/src/HAL/SAMD21/HAL.h new file mode 100644 index 0000000000..fe72859549 --- /dev/null +++ b/Marlin/src/HAL/SAMD21/HAL.h @@ -0,0 +1,223 @@ +/** + * Marlin 3D Printer Firmware + * Copyright (c) 2022 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 + +/** + * SAMD21 HAL developed by Bart Meijer (brupje) + * Based on SAMD51 HAL by Giuliano Zaro (AKA GMagician) + */ + +#define CPU_32_BIT + +#include "../shared/Marduino.h" +#include "../shared/math_32bit.h" +#include "../shared/HAL_SPI.h" +#include "fastio.h" + +// ------------------------ +// Serial ports +// ------------------------ +#include "../../core/serial_hook.h" +typedef ForwardSerial1Class< decltype(SerialUSB) > DefaultSerial1; +extern DefaultSerial1 MSerialUSB; + +// Serial ports +typedef ForwardSerial1Class< decltype(Serial1) > DefaultSerial2; +typedef ForwardSerial1Class< decltype(Serial2) > DefaultSerial3; + +extern DefaultSerial2 MSerial0; +extern DefaultSerial3 MSerial1; + + +#define __MSERIAL(X) MSerial##X +#define _MSERIAL(X) __MSERIAL(X) +#define MSERIAL(X) _MSERIAL(INCREMENT(X)) + +#if WITHIN(SERIAL_PORT, 0, 1) + #define MYSERIAL1 MSERIAL(SERIAL_PORT) +#elif SERIAL_PORT == -1 + #define MYSERIAL1 MSerialUSB +#else + #error "SERIAL_PORT must be -1 (Native USB only)." +#endif + +#ifdef SERIAL_PORT_2 + #if WITHIN(SERIAL_PORT_2, 0, 1) + #define MYSERIAL2 MSERIAL(SERIAL_PORT) + #elif SERIAL_PORT_2 == -1 + #define MYSERIAL2 MSerialUSB + #else + #error "SERIAL_PORT_2 must be -1 (Native USB only)." + #endif +#endif + +#ifdef MMU2_SERIAL_PORT + #if WITHIN(MMU2_SERIAL_PORT, 0, 1) + #define MMU2_SERIAL MSERIAL(SERIAL_PORT) + #elif MMU2_SERIAL_PORT == -1 + #define MMU2_SERIAL MSerialUSB + #else + #error "MMU2_SERIAL_PORT must be -1 (Native USB only)." + #endif +#endif + +#ifdef LCD_SERIAL_PORT + #if WITHIN(LCD_SERIAL_PORT, 0, 1) + #define LCD_SERIAL MSERIAL(SERIAL_PORT) + #elif LCD_SERIAL_PORT == -1 + #define LCD_SERIAL MSerialUSB + #else + #error "LCD_SERIAL_PORT must be -1 (Native USB only)." + #endif +#endif + +typedef int8_t pin_t; + +#define SHARED_SERVOS HAS_SERVOS // Use shared/servos.cpp + +class Servo; +typedef Servo hal_servo_t; + +// +// Interrupts +// +#define CRITICAL_SECTION_START() const bool irqon = !__get_PRIMASK(); __disable_irq() +#define CRITICAL_SECTION_END() if (irqon) __enable_irq() + +#define cli() __disable_irq() // Disable interrupts +#define sei() __enable_irq() // Enable interrupts + +// +// ADC +// + +#define HAL_ADC_FILTERED 1 // Disable Marlin's oversampling. The HAL filters ADC values. +#define HAL_ADC_VREF_MV 3300 +#define HAL_ADC_RESOLUTION 12 +#define HAL_ADC_AIN_START ADC_INPUTCTRL_MUXPOS_PIN3 +#define HAL_ADC_AIN_NUM_SENSORS 3 +#define HAL_ADC_AIN_LEN HAL_ADC_AIN_NUM_SENSORS-1 + +// +// Pin Mapping for M42, M43, M226 +// +#define GET_PIN_MAP_PIN(index) index +#define GET_PIN_MAP_INDEX(pin) pin +#define PARSED_PIN_INDEX(code, dval) parser.intval(code, dval) + +// +// Tone +// +void tone(const pin_t _pin, const unsigned int frequency, const unsigned long duration=0); +void noTone(const pin_t _pin); + +// ------------------------ +// Class Utilities +// ------------------------ + +#pragma GCC diagnostic push +#if GCC_VERSION <= 50000 + #pragma GCC diagnostic ignored "-Wunused-function" +#endif + +#ifdef __cplusplus + extern "C" { +#endif + +char *dtostrf(double __val, signed char __width, unsigned char __prec, char *__s); + +extern "C" int freeMemory(); + +#ifdef __cplusplus + } +#endif + +#pragma GCC diagnostic pop + +// ------------------------ +// MarlinHAL Class +// ------------------------ + +class MarlinHAL { +public: + + // Earliest possible init, before setup() + MarlinHAL() {} + + // Watchdog + static void watchdog_init() IF_DISABLED(USE_WATCHDOG, {}); + static void watchdog_refresh() IF_DISABLED(USE_WATCHDOG, {}); + + static void init(); // Called early in setup() + static void init_board() {} // Called less early in setup() + static void reboot(); // Restart the firmware from 0x0 + + // Interrupts + static bool isr_state() { return !__get_PRIMASK(); } + static void isr_on() { sei(); } + static void isr_off() { cli(); } + + static void delay_ms(const int ms) { delay(ms); } + + // Tasks, called from idle() + static void idletask() {} + + // Reset + static uint8_t get_reset_source(); + static void clear_reset_source() {} + + // Free SRAM + static int freeMemory() { return ::freeMemory(); } + + // + // ADC Methods + // + + static uint16_t adc_result; + + // Called by Temperature::init once at startup + static void adc_init(); + + // Called by Temperature::init for each sensor at startup + static void adc_enable(const uint8_t ch) {} + + // Begin ADC sampling on the given pin. Called from Temperature::isr! + static void adc_start(const pin_t pin); + + // Is the ADC ready for reading? + static bool adc_ready() { return true; } + + // The current value of the ADC register + static uint16_t adc_value() { return adc_result; } + + /** + * Set the PWM duty cycle for the pin to the given value. + * No option to invert the duty cycle [default = false] + * No option to change the scale of the provided value to enable finer PWM duty control [default = 255] + */ + static void set_pwm_duty(const pin_t pin, const uint16_t v, const uint16_t=255, const bool=false) { + analogWrite(pin, v); + } + +private: + static void dma_init(); +}; diff --git a/Marlin/src/HAL/SAMD21/HAL_SPI.cpp b/Marlin/src/HAL/SAMD21/HAL_SPI.cpp new file mode 100644 index 0000000000..e01f540cf8 --- /dev/null +++ b/Marlin/src/HAL/SAMD21/HAL_SPI.cpp @@ -0,0 +1,148 @@ +/** + * Marlin 3D Printer Firmware + * Copyright (c) 2022 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 . + * + */ + +/** + * SAMD21 HAL developed by Bart Meijer (brupje) + * Based on SAMD51 HAL by Giuliano Zaro (AKA GMagician) + */ + +/** + * Hardware and software SPI implementations are included in this file. + * + * Control of the slave select pin(s) is handled by the calling routines and + * SAMD21 let hardware SPI handling to remove SS from its logic. + */ + +#ifdef __SAMD21__ + +// -------------------------------------------------------------------------- +// Includes +// -------------------------------------------------------------------------- + +#include "../../inc/MarlinConfig.h" +#include + +// -------------------------------------------------------------------------- +// Public functions +// -------------------------------------------------------------------------- + +#if ANY(SOFTWARE_SPI, FORCE_SOFT_SPI) + + // ------------------------ + // Software SPI + // ------------------------ + #error "Software SPI not supported for SAMD21. Use Hardware SPI." + +#else // !SOFTWARE_SPI + + static SPISettings spiConfig; + + // ------------------------ + // Hardware SPI + // ------------------------ + void spiBegin() { + spiInit(SPI_HALF_SPEED); + } + + void spiInit(uint8_t spiRate) { + // Use Marlin datarates + uint32_t clock; + switch (spiRate) { + case SPI_FULL_SPEED: clock = 8000000; break; + case SPI_HALF_SPEED: clock = 4000000; break; + case SPI_QUARTER_SPEED: clock = 2000000; break; + case SPI_EIGHTH_SPEED: clock = 1000000; break; + case SPI_SIXTEENTH_SPEED: clock = 500000; break; + case SPI_SPEED_5: clock = 250000; break; + case SPI_SPEED_6: clock = 125000; break; + default: clock = 4000000; break; // Default from the SPI library + } + spiConfig = SPISettings(clock, MSBFIRST, SPI_MODE0); + SPI.begin(); + } + + /** + * @brief Receives a single byte from the SPI port. + * + * @return Byte received + * + * @details + */ + uint8_t spiRec() { + SPI.beginTransaction(spiConfig); + uint8_t returnByte = SPI.transfer(0xFF); + SPI.endTransaction(); + return returnByte; + } + + /** + * @brief Receives a number of bytes from the SPI port to a buffer + * + * @param buf Pointer to starting address of buffer to write to. + * @param nbyte Number of bytes to receive. + * @return Nothing + */ + void spiRead(uint8_t *buf, uint16_t nbyte) { + if (nbyte == 0) return; + memset(buf, 0xFF, nbyte); + + SPI.beginTransaction(spiConfig); + SPI.transfer(buf, nbyte); + SPI.endTransaction(); + + } + + /** + * @brief Sends a single byte on SPI port + * + * @param b Byte to send + * + * @details + */ + void spiSend(uint8_t b) { + SPI.beginTransaction(spiConfig); + SPI.transfer(b); + SPI.endTransaction(); + } + + /** + * @brief Write token and then write from 512 byte buffer to SPI (for SD card) + * + * @param buf Pointer with buffer start address + * @return Nothing + * + * @details Uses DMA + */ + void spiSendBlock(uint8_t token, const uint8_t *buf) { + SPI.beginTransaction(spiConfig); + SPI.transfer(token); + SPI.transfer((uint8_t*)buf, 512); + SPI.endTransaction(); + } + + void spiBeginTransaction(uint32_t spiClock, uint8_t bitOrder, uint8_t dataMode) { + spiConfig = SPISettings(spiClock, (BitOrder)bitOrder, dataMode); + SPI.beginTransaction(spiConfig); + } +#endif // !SOFTWARE_SPI + +#endif // __SAMD21__ diff --git a/Marlin/src/HAL/SAMD21/MarlinSPI.h b/Marlin/src/HAL/SAMD21/MarlinSPI.h new file mode 100644 index 0000000000..7b5392793e --- /dev/null +++ b/Marlin/src/HAL/SAMD21/MarlinSPI.h @@ -0,0 +1,31 @@ +/** + * Marlin 3D Printer Firmware + * Copyright (c) 2022 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 . + * + */ + +/** + * SAMD21 HAL developed by Bart Meijer (brupje) + * Based on SAMD51 HAL by Giuliano Zaro (AKA GMagician) + */ +#pragma once + +#include + +using MarlinSPI = SPIClass; diff --git a/Marlin/src/HAL/SAMD21/QSPIFlash.cpp b/Marlin/src/HAL/SAMD21/QSPIFlash.cpp new file mode 100644 index 0000000000..fa54c62071 --- /dev/null +++ b/Marlin/src/HAL/SAMD21/QSPIFlash.cpp @@ -0,0 +1,82 @@ +/** + * Marlin 3D Printer Firmware + * Copyright (c) 2022 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 . + * + */ + +/** + * SAMD21 HAL developed by Bart Meijer (brupje) + * Based on SAMD51 HAL by Giuliano Zaro (AKA GMagician) + */ +#include "../../inc/MarlinConfig.h" + +#if ENABLED(QSPI_EEPROM) + +#include "QSPIFlash.h" + +#define INVALID_ADDR 0xFFFFFFFF +#define SECTOR_OF(a) (a & ~(SFLASH_SECTOR_SIZE - 1)) +#define OFFSET_OF(a) (a & (SFLASH_SECTOR_SIZE - 1)) + +Adafruit_SPIFlashBase * QSPIFlash::_flashBase = nullptr; +uint8_t QSPIFlash::_buf[SFLASH_SECTOR_SIZE]; +uint32_t QSPIFlash::_addr = INVALID_ADDR; + +void QSPIFlash::begin() { + if (_flashBase) return; + + _flashBase = new Adafruit_SPIFlashBase(new Adafruit_FlashTransport_QSPI()); + _flashBase->begin(nullptr); +} + +size_t QSPIFlash::size() { + return _flashBase->size(); +} + +uint8_t QSPIFlash::readByte(const uint32_t address) { + if (SECTOR_OF(address) == _addr) return _buf[OFFSET_OF(address)]; + + return _flashBase->read8(address); +} + +void QSPIFlash::writeByte(const uint32_t address, const uint8_t value) { + uint32_t const sector_addr = SECTOR_OF(address); + + // Page changes, flush old and update new cache + if (sector_addr != _addr) { + flush(); + _addr = sector_addr; + + // read a whole page from flash + _flashBase->readBuffer(sector_addr, _buf, SFLASH_SECTOR_SIZE); + } + + _buf[OFFSET_OF(address)] = value; +} + +void QSPIFlash::flush() { + if (_addr == INVALID_ADDR) return; + + _flashBase->eraseSector(_addr / SFLASH_SECTOR_SIZE); + _flashBase->writeBuffer(_addr, _buf, SFLASH_SECTOR_SIZE); + + _addr = INVALID_ADDR; +} + +#endif // QSPI_EEPROM diff --git a/Marlin/src/HAL/SAMD21/QSPIFlash.h b/Marlin/src/HAL/SAMD21/QSPIFlash.h new file mode 100644 index 0000000000..58822fe05f --- /dev/null +++ b/Marlin/src/HAL/SAMD21/QSPIFlash.h @@ -0,0 +1,49 @@ +/** + * @file QSPIFlash.h + * + * The MIT License (MIT) + * + * Copyright (c) 2019 Ha Thach and Dean Miller for Adafruit Industries LLC + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * Derived from Adafruit_SPIFlash class with no SdFat references + */ +#pragma once + +#include + +// This class extends Adafruit_SPIFlashBase by adding caching support. +// +// This class will use 4096 Bytes of RAM as a block cache. +class QSPIFlash { + public: + static void begin(); + static size_t size(); + static uint8_t readByte(const uint32_t address); + static void writeByte(const uint32_t address, const uint8_t v); + static void flush(); + + private: + static Adafruit_SPIFlashBase * _flashBase; + static uint8_t _buf[SFLASH_SECTOR_SIZE]; + static uint32_t _addr; +}; + +extern QSPIFlash qspi; diff --git a/Marlin/src/HAL/SAMD21/SAMD21.h b/Marlin/src/HAL/SAMD21/SAMD21.h new file mode 100644 index 0000000000..8e9d17fc50 --- /dev/null +++ b/Marlin/src/HAL/SAMD21/SAMD21.h @@ -0,0 +1,66 @@ +/** + * Marlin 3D Printer Firmware + * Copyright (c) 2022 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 + +/** + * SAMD21 HAL developed by Bart Meijer (brupje) + * Based on SAMD51 HAL by Giuliano Zaro (AKA GMagician) + */ + +#define SYNC(sc) while (sc) { \ + asm(""); \ + } + +// Get SAMD port/pin from specified arduino pin +#define GET_SAMD_PORT(P) _GET_SAMD_PORT(PIN_TO_SAMD_PIN(P)) +#define GET_SAMD_PIN(P) _GET_SAMD_PIN(PIN_TO_SAMD_PIN(P)) + +// Get external interrupt line associated to specified arduino pin +#define PIN_TO_EILINE(P) _SAMDPORTPIN_TO_EILINE(GET_SAMD_PORT(P), GET_SAMD_PIN(P)) + +// Get adc/ain associated to specified arduino pin +#define PIN_TO_ADC(P) (ANAPIN_TO_ADCAIN(P) >> 8) + +// Private defines +#define PIN_TO_SAMD_PIN(P) DIO##P##_PIN + +#define _GET_SAMD_PORT(P) ((P) >> 5) +#define _GET_SAMD_PIN(P) ((P) & 0x1F) + +// Get external interrupt line +#define _SAMDPORTPIN_TO_EILINE(P,B) ((P == 0 && WITHIN(B, 0, 31) && B != 26 && B != 28 && B != 29) ? (B) & 0xF \ + : (P == 1 && (WITHIN(B, 0, 25) || WITHIN(B, 30, 31))) ? (B) & 0xF \ + : (P == 1 && WITHIN(B, 26, 29)) ? 12 + (B) - 26 \ + : (P == 2 && (WITHIN(B, 0, 6) || WITHIN(B, 10, 31)) && B != 29) ? (B) & 0xF \ + : (P == 2 && B == 7) ? 9 \ + : (P == 3 && WITHIN(B, 0, 1)) ? (B) \ + : (P == 3 && WITHIN(B, 8, 12)) ? 3 + (B) - 8 \ + : (P == 3 && WITHIN(B, 20, 21)) ? 10 + (B) - 20 \ + : -1) + + + +#define A2_AIN 3 +#define A3_AIN 4 +#define A4_AIN 5 +#define PIN_TO_AIN(P) A##P##_AIN +#define AIN_TO_RESULT(P) ( (P - HAL_ADC_AIN_START == HAL_ADC_AIN_NUM_SENSORS-1) ? 0 : (P - HAL_ADC_AIN_START + 1) ) diff --git a/Marlin/src/HAL/SAMD21/Servo.cpp b/Marlin/src/HAL/SAMD21/Servo.cpp new file mode 100644 index 0000000000..38b995fc9a --- /dev/null +++ b/Marlin/src/HAL/SAMD21/Servo.cpp @@ -0,0 +1,220 @@ +/** + * Marlin 3D Printer Firmware + * Copyright (c) 2022 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 . + * + */ + +/** + * SAMD21 HAL developed by Bart Meijer (brupje) + * Based on SAMD51 HAL by Giuliano Zaro (AKA GMagician) + */ + +/** + * This comes from Arduino library which at the moment is buggy and uncompilable + */ + +#ifdef __SAMD21__ + +#include "../../inc/MarlinConfig.h" + +#if HAS_SERVOS + +#include "../shared/servo.h" +#include "../shared/servo_private.h" +#include "SAMD21.h" + +#define __TC_GCLK_ID(t) TC##t##_GCLK_ID +#define _TC_GCLK_ID(t) __TC_GCLK_ID(t) +#define TC_GCLK_ID _TC_GCLK_ID(SERVO_TC) + +#define _TC_PRESCALER(d) TC_CTRLA_PRESCALER_DIV##d##_Val +#define TC_PRESCALER(d) _TC_PRESCALER(d) + +#define __SERVO_IRQn(t) TC##t##_IRQn +#define _SERVO_IRQn(t) __SERVO_IRQn(t) +#define SERVO_IRQn _SERVO_IRQn(SERVO_TC) + +#define HAL_SERVO_TIMER_ISR() TC_HANDLER(SERVO_TC) + +#define TIMER_TCCHANNEL(t) ((t) & 1) +#define TC_COUNTER_START_VAL 0xFFFF + + +static volatile int8_t currentServoIndex[_Nbr_16timers]; // index for the servo being pulsed for each timer (or -1 if refresh interval) + +FORCE_INLINE static uint16_t getTimerCount() { + Tcc * const tc = timer_config[SERVO_TC].pTcc; + + tc->CTRLBSET.reg = TCC_CTRLBCLR_CMD_READSYNC; + SYNC(tc->STATUS.reg & TC_STATUS_SYNCBUSY); + + return tc->COUNT.bit.COUNT; +} + +// ---------------------------- +// Interrupt handler for the TC +// ---------------------------- +HAL_SERVO_TIMER_ISR() { + Tcc * const tc = timer_config[SERVO_TC].pTcc; + const timer16_Sequence_t timer = + #ifndef _useTimer1 + _timer2 + #elif !defined(_useTimer2) + _timer1 + #else + (tc->INTFLAG.reg & tc->INTENSET.reg & TC_INTFLAG_MC0) ? _timer1 : _timer2 + #endif + ; + const uint8_t tcChannel = TIMER_TCCHANNEL(timer); + + int8_t cho = currentServoIndex[timer]; // Handle the prior servo first + if (cho < 0) { // Servo -1 indicates the refresh interval completed... + #if defined(_useTimer1) && defined(_useTimer2) + if (currentServoIndex[timer ^ 1] >= 0) { + // Wait for both channels + // Clear the interrupt + tc->INTFLAG.reg = (tcChannel == 0) ? TC_INTFLAG_MC0 : TC_INTFLAG_MC1; + return; + } + #endif + tc->COUNT.reg = TC_COUNTER_START_VAL; // ...so reset the timer + SYNC(tc->STATUS.reg & TC_STATUS_SYNCBUSY); + } + else if (SERVO_INDEX(timer, cho) < ServoCount) // prior channel handled? + digitalWrite(SERVO(timer, cho).Pin.nbr, LOW); // pulse the prior channel LOW + + currentServoIndex[timer] = ++cho; // go to the next channel (or 0) + if (cho < SERVOS_PER_TIMER && SERVO_INDEX(timer, cho) < ServoCount) { + if (SERVO(timer, cho).Pin.isActive) // activated? + digitalWrite(SERVO(timer, cho).Pin.nbr, HIGH); // yes: pulse HIGH + + tc->CC[tcChannel].reg = getTimerCount() - (uint16_t)SERVO(timer, cho).ticks; + } + else { + // finished all channels so wait for the refresh period to expire before starting over + currentServoIndex[timer] = -1; // reset the timer COUNT.reg on the next call + const uint16_t cval = getTimerCount() - 256 / (SERVO_TIMER_PRESCALER), // allow 256 cycles to ensure the next CV not missed + ival = (TC_COUNTER_START_VAL) - (uint16_t)usToTicks(REFRESH_INTERVAL); // at least REFRESH_INTERVAL has elapsed + tc->CC[tcChannel].reg = min(cval, ival); + } + if (tcChannel == 0) { + SYNC(tc->SYNCBUSY.bit.CC0); + tc->INTFLAG.reg = TC_INTFLAG_MC0; // Clear the interrupt + } + else { + SYNC(tc->SYNCBUSY.bit.CC1); + tc->INTFLAG.reg = TC_INTFLAG_MC1; // Clear the interrupt + } +} + +void initISR(const timer16_Sequence_t timer) { + Tcc * const tc = timer_config[SERVO_TC].pTcc; + const uint8_t tcChannel = TIMER_TCCHANNEL(timer); + + static bool initialized = false; // Servo TC has been initialized + if (!initialized) { + NVIC_DisableIRQ(SERVO_IRQn); + + // Disable the timer + tc->CTRLA.bit.ENABLE = false; + SYNC(tc->STATUS.reg & TC_STATUS_SYNCBUSY); + + // Select GCLK0 as timer/counter input clock source + GCLK->CLKCTRL.reg =(GCLK_CLKCTRL_CLKEN | GCLK_CLKCTRL_GEN_GCLK0 | GCLK_CLKCTRL_ID(TCC0_GCLK_ID)); + SYNC (GCLK->STATUS.bit.SYNCBUSY); + + // Reset the timer + tc->CTRLA.bit.SWRST = true; + SYNC(tc->CTRLA.bit.SWRST); + + // Set timer counter mode to 16 bits + tc->CTRLA.reg = TC_CTRLA_MODE_COUNT16; + + // Set timer counter mode as normal PWM + tc->WAVE.bit.WAVEGEN = TCC_WAVE_WAVEGEN_NPWM_Val; + + // Set the prescaler factor + tc->CTRLA.bit.PRESCALER = TC_PRESCALER(SERVO_TIMER_PRESCALER); + + // Count down + tc->CTRLBSET.reg = TCC_CTRLBCLR_DIR; + SYNC(tc->SYNCBUSY.bit.CTRLB); + + // Reset all servo indexes + memset((void *)currentServoIndex, 0xFF, sizeof(currentServoIndex)); + + // Configure interrupt request + NVIC_ClearPendingIRQ(SERVO_IRQn); + NVIC_SetPriority(SERVO_IRQn, 5); + NVIC_EnableIRQ(SERVO_IRQn); + + initialized = true; + } + + if (!tc->CTRLA.bit.ENABLE) { + // Reset the timer counter + tc->COUNT.reg = TC_COUNTER_START_VAL; + SYNC(tc->STATUS.reg & TC_STATUS_SYNCBUSY); + + // Enable the timer and start it + tc->CTRLA.bit.ENABLE = true; + SYNC(tc->STATUS.reg & TC_STATUS_SYNCBUSY); + } + // First interrupt request after 1 ms + tc->CC[tcChannel].reg = getTimerCount() - (uint16_t)usToTicks(1000UL); + + if (tcChannel == 0 ) { + SYNC(tc->SYNCBUSY.bit.CC0); + + // Clear pending match interrupt + tc->INTFLAG.reg = TC_INTENSET_MC0; + // Enable the match channel interrupt request + tc->INTENSET.reg = TC_INTENSET_MC0; + } + else { + SYNC(tc->SYNCBUSY.bit.CC1); + + // Clear pending match interrupt + tc->INTFLAG.reg = TC_INTENSET_MC1; + // Enable the match channel interrupt request + tc->INTENSET.reg = TC_INTENSET_MC1; + } +} + +void finISR(const timer16_Sequence_t timer_index) { + Tcc * const tc = timer_config[SERVO_TC].pTcc; + const uint8_t tcChannel = TIMER_TCCHANNEL(timer_index); + + // Disable the match channel interrupt request + tc->INTENCLR.reg = (tcChannel == 0) ? TC_INTENCLR_MC0 : TC_INTENCLR_MC1; + + if (true + #if defined(_useTimer1) && defined(_useTimer2) + && (tc->INTENCLR.reg & (TC_INTENCLR_MC0|TC_INTENCLR_MC1)) == 0 + #endif + ) { + // Disable the timer if not used + tc->CTRLA.bit.ENABLE = false; + SYNC(tc->STATUS.reg & TC_STATUS_SYNCBUSY); + } +} + +#endif // HAS_SERVOS + +#endif // __SAMD21__ diff --git a/Marlin/src/HAL/SAMD21/ServoTimers.h b/Marlin/src/HAL/SAMD21/ServoTimers.h new file mode 100644 index 0000000000..8980547683 --- /dev/null +++ b/Marlin/src/HAL/SAMD21/ServoTimers.h @@ -0,0 +1,45 @@ +/** + * Marlin 3D Printer Firmware + * Copyright (c) 2022 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 + +/** + * SAMD21 HAL developed by Bart Meijer (brupje) + * Based on SAMD51 HAL by Giuliano Zaro (AKA GMagician) + */ + +#define _useTimer1 +#define _useTimer2 + +#define TRIM_DURATION 5 // compensation ticks to trim adjust for digitalWrite delays +#define SERVO_TIMER_PRESCALER 64 // timer prescaler factor to 64 (avoid overflowing 16-bit clock counter, at 120MHz this is 1831 ticks per millisecond + +#define SERVO_TC 3 + +typedef enum { + #ifdef _useTimer1 + _timer1, + #endif + #ifdef _useTimer2 + _timer2, + #endif + _Nbr_16timers +} timer16_Sequence_t; diff --git a/Marlin/src/HAL/SAMD21/eeprom_flash.cpp b/Marlin/src/HAL/SAMD21/eeprom_flash.cpp new file mode 100644 index 0000000000..4a4e328d1a --- /dev/null +++ b/Marlin/src/HAL/SAMD21/eeprom_flash.cpp @@ -0,0 +1,141 @@ +/** + * Marlin 3D Printer Firmware + * Copyright (c) 2022 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 . + * + */ + +/** + * SAMD21 HAL developed by Bart Meijer (brupje) + * Based on SAMD51 HAL by Giuliano Zaro (AKA GMagician) + */ +#ifdef __SAMD21__ + +#include "../../inc/MarlinConfig.h" + +#if ENABLED(FLASH_EEPROM_EMULATION) + +#define TOTAL_FLASH_SIZE (MARLIN_EEPROM_SIZE+255)/256*256 + +/* reserve flash memory */ +static const uint8_t flashdata[TOTAL_FLASH_SIZE] __attribute__((__aligned__(256))) { }; \ + +#include "../shared/eeprom_api.h" + +size_t PersistentStore::capacity() { + return MARLIN_EEPROM_SIZE; + /* const uint8_t psz = NVMCTRL->SEESTAT.bit.PSZ, + sblk = NVMCTRL->SEESTAT.bit.SBLK; + + return (!psz && !sblk) ? 0 + : (psz <= 2) ? (0x200 << psz) + : (sblk == 1 || psz == 3) ? 4096 + : (sblk == 2 || psz == 4) ? 8192 + : (sblk <= 4 || psz == 5) ? 16384 + : (sblk >= 9 && psz == 7) ? 65536 + : 32768;*/ +} + +uint32_t PAGE_SIZE; +uint32_t ROW_SIZE; +bool hasWritten = false; +uint8_t * buffer; + +void _erase(const volatile void *flash_ptr) { + NVMCTRL->ADDR.reg = ((uint32_t)flash_ptr) / 2; + NVMCTRL->CTRLA.reg = NVMCTRL_CTRLA_CMDEX_KEY | NVMCTRL_CTRLA_CMD_ER; + while (!NVMCTRL->INTFLAG.bit.READY) { } + +} + +void erase(const volatile void *flash_ptr, uint32_t size) { + const uint8_t *ptr = (const uint8_t *)flash_ptr; + while (size > ROW_SIZE) { + _erase(ptr); + ptr += ROW_SIZE; + size -= ROW_SIZE; + } + _erase(ptr); +} + +bool PersistentStore::access_start() { + /* clear page buffer*/ + NVMCTRL->CTRLA.reg = NVMCTRL_CTRLA_CMDEX_KEY | NVMCTRL_CTRLA_CMD_PBC; + while (NVMCTRL->INTFLAG.bit.READY == 0) { } + + PAGE_SIZE = pow(2,3 + NVMCTRL->PARAM.bit.PSZ); + ROW_SIZE= PAGE_SIZE * 4; + /*NVMCTRL->SEECFG.reg = NVMCTRL_SEECFG_WMODE_BUFFERED; // Buffered mode and segment reallocation active + if (NVMCTRL->SEESTAT.bit.RLOCK) + NVMCTRL_CMD(NVMCTRL_CTRLB_CMD_USEE); */ // Unlock E2P data write access + // erase(&flashdata[0], TOTAL_FLASH_SIZE); + return true; +} + +bool PersistentStore::access_finish() { + if (hasWritten) { + erase(&flashdata[0], TOTAL_FLASH_SIZE); + + NVMCTRL->CTRLA.reg = NVMCTRL_CTRLA_CMDEX_KEY | NVMCTRL_CTRLA_CMD_PBC; + while (NVMCTRL->INTFLAG.bit.READY == 0) { } + + NVMCTRL->CTRLB.bit.MANW = 0; + + volatile uint32_t *dst_addr = (volatile uint32_t *) &flashdata; + + uint32_t *pointer = (uint32_t *) buffer; + for (uint32_t i = 0; i < TOTAL_FLASH_SIZE; i+=4) { + + *dst_addr = (uint32_t) *pointer; + pointer++; + dst_addr ++; + } + + // Execute "WP" Write Page + NVMCTRL->CTRLA.reg = NVMCTRL_CTRLA_CMDEX_KEY | NVMCTRL_CTRLA_CMD_WP; + while (NVMCTRL->INTFLAG.bit.READY == 0) { } + + free(buffer); + hasWritten = false; + } + return true; +} + +bool PersistentStore::write_data(int &pos, const uint8_t *value, size_t size, uint16_t *crc) { + if (!hasWritten) { + // init temp buffer + buffer = (uint8_t *) malloc(MARLIN_EEPROM_SIZE); + hasWritten=true; + } + + memcpy(buffer+pos,value,size); + pos += size; + return false; +} + +bool PersistentStore::read_data(int &pos, uint8_t *value, size_t size, uint16_t *crc, const bool writing/*=true*/) { + volatile uint8_t *dst_addr = (volatile uint8_t *) &flashdata; + dst_addr += pos; + + memcpy(value,(const void *) dst_addr,size); + pos += size; + return false; +} + +#endif // FLASH_EEPROM_EMULATION +#endif // __SAMD21__ diff --git a/Marlin/src/HAL/SAMD21/eeprom_qspi.cpp b/Marlin/src/HAL/SAMD21/eeprom_qspi.cpp new file mode 100644 index 0000000000..587dcb0b14 --- /dev/null +++ b/Marlin/src/HAL/SAMD21/eeprom_qspi.cpp @@ -0,0 +1,79 @@ +/** + * Marlin 3D Printer Firmware + * Copyright (c) 2022 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 . + * + */ + +/** + * SAMD21 HAL developed by Bart Meijer (brupje) + * Based on SAMD51 HAL by Giuliano Zaro (AKA GMagician) + */ +#ifdef __SAMD21__ + +#include "../../inc/MarlinConfig.h" + +#if ENABLED(QSPI_EEPROM) + +#error "QSPI_EEPROM emulation Not implemented on SAMD21" + +#include "../shared/eeprom_api.h" + +#include "QSPIFlash.h" + +static bool initialized; + +size_t PersistentStore::capacity() { return qspi.size(); } + +bool PersistentStore::access_start() { + if (!initialized) { + qspi.begin(); + initialized = true; + } + return true; +} + +bool PersistentStore::access_finish() { + qspi.flush(); + return true; +} + +bool PersistentStore::write_data(int &pos, const uint8_t *value, size_t size, uint16_t *crc) { + while (size--) { + const uint8_t v = *value; + qspi.writeByte(pos, v); + crc16(crc, &v, 1); + pos++; + value++; + } + return false; +} + +bool PersistentStore::read_data(int &pos, uint8_t *value, size_t size, uint16_t *crc, const bool writing/*=true*/) { + while (size--) { + uint8_t c = qspi.readByte(pos); + if (writing) *value = c; + crc16(crc, &c, 1); + pos++; + value++; + } + return false; +} + +#endif // QSPI_EEPROM +#endif // __SAMD21__ diff --git a/Marlin/src/HAL/SAMD21/eeprom_wired.cpp b/Marlin/src/HAL/SAMD21/eeprom_wired.cpp new file mode 100644 index 0000000000..ab71e616fc --- /dev/null +++ b/Marlin/src/HAL/SAMD21/eeprom_wired.cpp @@ -0,0 +1,82 @@ +/** + * Marlin 3D Printer Firmware + * Copyright (c) 2022 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 . + * + */ + +/** + * SAMD21 HAL developed by Bart Meijer (brupje) + * Based on SAMD51 HAL by Giuliano Zaro (AKA GMagician) + */ +#ifdef __SAMD21__ + +#include "../../inc/MarlinConfig.h" + +#if USE_WIRED_EEPROM + +#error "USE_WIRED_EEPROM emulation Not implemented on SAMD21" +/** + * PersistentStore for Arduino-style EEPROM interface + * with simple implementations supplied by Marlin. + */ + +#include "../shared/eeprom_if.h" +#include "../shared/eeprom_api.h" + +#ifndef MARLIN_EEPROM_SIZE + #error "MARLIN_EEPROM_SIZE is required for I2C / SPI EEPROM." +#endif +size_t PersistentStore::capacity() { return MARLIN_EEPROM_SIZE; } + +bool PersistentStore::access_start() { eeprom_init(); return true; } +bool PersistentStore::access_finish() { return true; } + +bool PersistentStore::write_data(int &pos, const uint8_t *value, size_t size, uint16_t *crc) { + uint16_t written = 0; + while (size--) { + const uint8_t v = *value; + uint8_t * const p = (uint8_t * const)pos; + if (v != eeprom_read_byte(p)) { // EEPROM has only ~100,000 write cycles, so only write bytes that have changed! + eeprom_write_byte(p, v); + if (++written & 0x7F) delay(2); else safe_delay(2); // Avoid triggering watchdog during long EEPROM writes + if (eeprom_read_byte(p) != v) { + SERIAL_ECHO_MSG(STR_ERR_EEPROM_WRITE); + return true; + } + } + crc16(crc, &v, 1); + pos++; + value++; + } + return false; +} + +bool PersistentStore::read_data(int &pos, uint8_t *value, size_t size, uint16_t *crc, const bool writing/*=true*/) { + while (size--) { + uint8_t c = eeprom_read_byte((uint8_t*)pos); + if (writing) *value = c; + crc16(crc, &c, 1); + pos++; + value++; + } + return false; +} + +#endif // USE_WIRED_EEPROM +#endif // __SAMD21__ diff --git a/Marlin/src/HAL/SAMD21/endstop_interrupts.h b/Marlin/src/HAL/SAMD21/endstop_interrupts.h new file mode 100644 index 0000000000..37fdb7504b --- /dev/null +++ b/Marlin/src/HAL/SAMD21/endstop_interrupts.h @@ -0,0 +1,283 @@ +/** + * Marlin 3D Printer Firmware + * Copyright (c) 2022 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 + +/** + * SAMD21 HAL developed by Bart Meijer (brupje) + * Based on SAMD51 HAL by Giuliano Zaro (AKA GMagician) + */ + +/** + * Endstop interrupts for ATMEL SAMD21 based targets. + * + * 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 + * connects to what is called an EXTINT line, and only one pin per EXTINT line can be used for external + * interrupts at a time + */ + +/** + * Endstop Interrupts + * + * Without endstop interrupts the endstop pins must be polled continually in + * the temperature-ISR via endstops.update(), most of the time finding no change. + * With this feature endstops.update() is called only when we know that at + * least one endstop has changed state, saving valuable CPU cycles. + * + * This feature only works when all used endstop pins can generate an 'external interrupt'. + * + * Test whether pins issue interrupts on your board by flashing 'pin_interrupt_test.ino'. + * (Located in Marlin/buildroot/share/pin_interrupt_test/pin_interrupt_test.ino) + */ + +#include "../../module/endstops.h" + +#define MATCH_EILINE(P1,P2) (P1 != P2 && PIN_TO_EILINE(P1) == PIN_TO_EILINE(P2)) +#define MATCH_X_MAX_EILINE(P) TERN0(USE_X_MAX, DEFER4(MATCH_EILINE)(P, X_MAX_PIN)) +#define MATCH_X_MIN_EILINE(P) TERN0(USE_X_MIN, DEFER4(MATCH_EILINE)(P, X_MIN_PIN)) +#define MATCH_Y_MAX_EILINE(P) TERN0(USE_Y_MAX, DEFER4(MATCH_EILINE)(P, Y_MAX_PIN)) +#define MATCH_Y_MIN_EILINE(P) TERN0(USE_Y_MIN, DEFER4(MATCH_EILINE)(P, Y_MIN_PIN)) +#define MATCH_Z_MAX_EILINE(P) TERN0(USE_Z_MAX, DEFER4(MATCH_EILINE)(P, Z_MAX_PIN)) +#define MATCH_Z_MIN_EILINE(P) TERN0(USE_Z_MIN, DEFER4(MATCH_EILINE)(P, Z_MIN_PIN)) +#define MATCH_I_MAX_EILINE(P) TERN0(USE_I_MAX, DEFER4(MATCH_EILINE)(P, I_MAX_PIN)) +#define MATCH_I_MIN_EILINE(P) TERN0(USE_I_MIN, DEFER4(MATCH_EILINE)(P, I_MIN_PIN)) +#define MATCH_J_MAX_EILINE(P) TERN0(USE_J_MAX, DEFER4(MATCH_EILINE)(P, J_MAX_PIN)) +#define MATCH_J_MIN_EILINE(P) TERN0(USE_J_MIN, DEFER4(MATCH_EILINE)(P, J_MIN_PIN)) +#define MATCH_K_MAX_EILINE(P) TERN0(USE_K_MAX, DEFER4(MATCH_EILINE)(P, K_MAX_PIN)) +#define MATCH_K_MIN_EILINE(P) TERN0(USE_K_MIN, DEFER4(MATCH_EILINE)(P, K_MIN_PIN)) +#define MATCH_U_MAX_EILINE(P) TERN0(USE_U_MAX, DEFER4(MATCH_EILINE)(P, U_MAX_PIN)) +#define MATCH_U_MIN_EILINE(P) TERN0(USE_U_MIN, DEFER4(MATCH_EILINE)(P, U_MIN_PIN)) +#define MATCH_V_MAX_EILINE(P) TERN0(USE_V_MAX, DEFER4(MATCH_EILINE)(P, V_MAX_PIN)) +#define MATCH_V_MIN_EILINE(P) TERN0(USE_V_MIN, DEFER4(MATCH_EILINE)(P, V_MIN_PIN)) +#define MATCH_W_MAX_EILINE(P) TERN0(USE_W_MAX, DEFER4(MATCH_EILINE)(P, W_MAX_PIN)) +#define MATCH_W_MIN_EILINE(P) TERN0(USE_W_MIN, DEFER4(MATCH_EILINE)(P, W_MIN_PIN)) +#define MATCH_X2_MAX_EILINE(P) TERN0(USE_X2_MAX, DEFER4(MATCH_EILINE)(P, X2_MAX_PIN)) +#define MATCH_X2_MIN_EILINE(P) TERN0(USE_X2_MIN, DEFER4(MATCH_EILINE)(P, X2_MIN_PIN)) +#define MATCH_Y2_MAX_EILINE(P) TERN0(USE_Y2_MAX, DEFER4(MATCH_EILINE)(P, Y2_MAX_PIN)) +#define MATCH_Y2_MIN_EILINE(P) TERN0(USE_Y2_MIN, DEFER4(MATCH_EILINE)(P, Y2_MIN_PIN)) +#define MATCH_Z2_MAX_EILINE(P) TERN0(USE_Z2_MAX, DEFER4(MATCH_EILINE)(P, Z2_MAX_PIN)) +#define MATCH_Z2_MIN_EILINE(P) TERN0(USE_Z2_MIN, DEFER4(MATCH_EILINE)(P, Z2_MIN_PIN)) +#define MATCH_Z3_MAX_EILINE(P) TERN0(USE_Z3_MAX, DEFER4(MATCH_EILINE)(P, Z3_MAX_PIN)) +#define MATCH_Z3_MIN_EILINE(P) TERN0(USE_Z3_MIN, DEFER4(MATCH_EILINE)(P, Z3_MIN_PIN)) +#define MATCH_Z4_MAX_EILINE(P) TERN0(USE_Z4_MAX, DEFER4(MATCH_EILINE)(P, Z4_MAX_PIN)) +#define MATCH_Z4_MIN_EILINE(P) TERN0(USE_Z4_MIN, DEFER4(MATCH_EILINE)(P, Z4_MIN_PIN)) +#define MATCH_Z_MIN_PROBE_EILINE(P) TERN0(USE_Z_MIN_PROBE, DEFER4(MATCH_EILINE)(P, Z_MIN_PROBE_PIN)) + +#define AVAILABLE_EILINE(P) ( PIN_TO_EILINE(P) != -1 \ + && !MATCH_X_MAX_EILINE(P) && !MATCH_X_MIN_EILINE(P) \ + && !MATCH_Y_MAX_EILINE(P) && !MATCH_Y_MIN_EILINE(P) \ + && !MATCH_Z_MAX_EILINE(P) && !MATCH_Z_MIN_EILINE(P) \ + && !MATCH_I_MAX_EILINE(P) && !MATCH_I_MIN_EILINE(P) \ + && !MATCH_J_MAX_EILINE(P) && !MATCH_J_MIN_EILINE(P) \ + && !MATCH_K_MAX_EILINE(P) && !MATCH_K_MIN_EILINE(P) \ + && !MATCH_U_MAX_EILINE(P) && !MATCH_U_MIN_EILINE(P) \ + && !MATCH_V_MAX_EILINE(P) && !MATCH_V_MIN_EILINE(P) \ + && !MATCH_W_MAX_EILINE(P) && !MATCH_W_MIN_EILINE(P) \ + && !MATCH_X2_MAX_EILINE(P) && !MATCH_X2_MIN_EILINE(P) \ + && !MATCH_Y2_MAX_EILINE(P) && !MATCH_Y2_MIN_EILINE(P) \ + && !MATCH_Z2_MAX_EILINE(P) && !MATCH_Z2_MIN_EILINE(P) \ + && !MATCH_Z3_MAX_EILINE(P) && !MATCH_Z3_MIN_EILINE(P) \ + && !MATCH_Z4_MAX_EILINE(P) && !MATCH_Z4_MIN_EILINE(P) \ + && !MATCH_Z_MIN_PROBE_EILINE(P) ) + +// One ISR for all EXT-Interrupts +void endstop_ISR() { endstops.update(); } + +void setup_endstop_interrupts() { + #define _ATTACH(P) attachInterrupt(P, endstop_ISR, CHANGE) + #if USE_X_MAX + #if !AVAILABLE_EILINE(X_MAX_PIN) + #error "X_MAX_PIN has no EXTINT line available. Disable ENDSTOP_INTERRUPTS_FEATURE to continue." + #endif + _ATTACH(X_MAX_PIN); + #endif + #if USE_X_MIN + #if !AVAILABLE_EILINE(X_MIN_PIN) + #error "X_MIN_PIN has no EXTINT line available. Disable ENDSTOP_INTERRUPTS_FEATURE to continue." + #endif + _ATTACH(X_MIN_PIN); + #endif + #if USE_Y_MAX + #if !AVAILABLE_EILINE(Y_MAX_PIN) + #error "Y_MAX_PIN has no EXTINT line available. Disable ENDSTOP_INTERRUPTS_FEATURE to continue." + #endif + _ATTACH(Y_MAX_PIN); + #endif + #if USE_Y_MIN + #if !AVAILABLE_EILINE(Y_MIN_PIN) + #error "Y_MIN_PIN has no EXTINT line available. Disable ENDSTOP_INTERRUPTS_FEATURE to continue." + #endif + _ATTACH(Y_MIN_PIN); + #endif + #if USE_Z_MAX + #if !AVAILABLE_EILINE(Z_MAX_PIN) + #error "Z_MAX_PIN has no EXTINT line available. Disable ENDSTOP_INTERRUPTS_FEATURE to continue." + #endif + _ATTACH(Z_MAX_PIN); + #endif + #if USE_Z_MIN + #if !AVAILABLE_EILINE(Z_MIN_PIN) + #error "Z_MIN_PIN has no EXTINT line available. Disable ENDSTOP_INTERRUPTS_FEATURE to continue." + #endif + _ATTACH(Z_MIN_PIN); + #endif + #if USE_X2_MAX + #if !AVAILABLE_EILINE(X2_MAX_PIN) + #error "X2_MAX_PIN has no EXTINT line available. Disable ENDSTOP_INTERRUPTS_FEATURE to continue." + #endif + _ATTACH(X2_MAX_PIN); + #endif + #if USE_X2_MIN + #if !AVAILABLE_EILINE(X2_MIN_PIN) + #error "X2_MIN_PIN has no EXTINT line available. Disable ENDSTOP_INTERRUPTS_FEATURE to continue." + #endif + _ATTACH(X2_MIN_PIN); + #endif + #if USE_Y2_MAX + #if !AVAILABLE_EILINE(Y2_MAX_PIN) + #error "Y2_MAX_PIN has no EXTINT line available. Disable ENDSTOP_INTERRUPTS_FEATURE to continue." + #endif + _ATTACH(Y2_MAX_PIN); + #endif + #if USE_Y2_MIN + #if !AVAILABLE_EILINE(Y2_MIN_PIN) + #error "Y2_MIN_PIN has no EXTINT line available. Disable ENDSTOP_INTERRUPTS_FEATURE to continue." + #endif + _ATTACH(Y2_MIN_PIN); + #endif + #if USE_Z2_MAX + #if !AVAILABLE_EILINE(Z2_MAX_PIN) + #error "Z2_MAX_PIN has no EXTINT line available. Disable ENDSTOP_INTERRUPTS_FEATURE to continue." + #endif + _ATTACH(Z2_MAX_PIN); + #endif + #if USE_Z2_MIN + #if !AVAILABLE_EILINE(Z2_MIN_PIN) + #error "Z2_MIN_PIN has no EXTINT line available. Disable ENDSTOP_INTERRUPTS_FEATURE to continue." + #endif + _ATTACH(Z2_MIN_PIN); + #endif + #if USE_Z3_MAX + #if !AVAILABLE_EILINE(Z3_MAX_PIN) + #error "Z3_MAX_PIN has no EXTINT line available. Disable ENDSTOP_INTERRUPTS_FEATURE to continue." + #endif + _ATTACH(Z3_MAX_PIN); + #endif + #if USE_Z3_MIN + #if !AVAILABLE_EILINE(Z3_MIN_PIN) + #error "Z3_MIN_PIN has no EXTINT line available. Disable ENDSTOP_INTERRUPTS_FEATURE to continue." + #endif + _ATTACH(Z3_MIN_PIN); + #endif + #if USE_Z4_MAX + #if !AVAILABLE_EILINE(Z4_MAX_PIN) + #error "Z4_MAX_PIN has no EXTINT line available. Disable ENDSTOP_INTERRUPTS_FEATURE to continue." + #endif + _ATTACH(Z4_MAX_PIN); + #endif + #if USE_Z4_MIN + #if !AVAILABLE_EILINE(Z4_MIN_PIN) + #error "Z4_MIN_PIN has no EXTINT line available. Disable ENDSTOP_INTERRUPTS_FEATURE to continue." + #endif + _ATTACH(Z4_MIN_PIN); + #endif + #if USE_Z_MIN_PROBE + #if !AVAILABLE_EILINE(Z_MIN_PROBE_PIN) + #error "Z_MIN_PROBE_PIN has no EXTINT line available. Disable ENDSTOP_INTERRUPTS_FEATURE to continue." + #endif + _ATTACH(Z_MIN_PROBE_PIN); + #endif + #if USE_I_MAX + #if !AVAILABLE_EILINE(I_MAX_PIN) + #error "I_MAX_PIN has no EXTINT line available. Disable ENDSTOP_INTERRUPTS_FEATURE to continue." + #endif + attachInterrupt(I_MAX_PIN, endstop_ISR, CHANGE); + #endif + #if USE_I_MIN + #if !AVAILABLE_EILINE(I_MIN_PIN) + #error "I_MIN_PIN has no EXTINT line available. Disable ENDSTOP_INTERRUPTS_FEATURE to continue." + #endif + attachInterrupt(I_MIN_PIN, endstop_ISR, CHANGE); + #endif + #if USE_J_MAX + #if !AVAILABLE_EILINE(J_MAX_PIN) + #error "J_MAX_PIN has no EXTINT line available. Disable ENDSTOP_INTERRUPTS_FEATURE to continue." + #endif + attachInterrupt(J_MAX_PIN, endstop_ISR, CHANGE); + #endif + #if USE_J_MIN + #if !AVAILABLE_EILINE(J_MIN_PIN) + #error "J_MIN_PIN has no EXTINT line available. Disable ENDSTOP_INTERRUPTS_FEATURE to continue." + #endif + attachInterrupt(J_MIN_PIN, endstop_ISR, CHANGE); + #endif + #if USE_K_MAX + #if !AVAILABLE_EILINE(K_MAX_PIN) + #error "K_MAX_PIN has no EXTINT line available. Disable ENDSTOP_INTERRUPTS_FEATURE to continue." + #endif + attachInterrupt(K_MAX_PIN, endstop_ISR, CHANGE); + #endif + #if USE_K_MIN + #if !AVAILABLE_EILINE(K_MIN_PIN) + #error "K_MIN_PIN has no EXTINT line available. Disable ENDSTOP_INTERRUPTS_FEATURE to continue." + #endif + attachInterrupt(K_MIN_PIN, endstop_ISR, CHANGE); + #endif + #if USE_U_MAX + #if !AVAILABLE_EILINE(U_MAX_PIN) + #error "U_MAX_PIN has no EXTINT line available. Disable ENDSTOP_INTERRUPTS_FEATURE to continue." + #endif + attachInterrupt(U_MAX_PIN, endstop_ISR, CHANGE); + #endif + #if USE_U_MIN + #if !AVAILABLE_EILINE(U_MIN_PIN) + #error "U_MIN_PIN has no EXTINT line available. Disable ENDSTOP_INTERRUPTS_FEATURE to continue." + #endif + attachInterrupt(U_MIN_PIN, endstop_ISR, CHANGE); + #endif + #if USE_V_MAX + #if !AVAILABLE_EILINE(V_MAX_PIN) + #error "V_MAX_PIN has no EXTINT line available. Disable ENDSTOP_INTERRUPTS_FEATURE to continue." + #endif + attachInterrupt(V_MAX_PIN, endstop_ISR, CHANGE); + #endif + #if USE_V_MIN + #if !AVAILABLE_EILINE(V_MIN_PIN) + #error "V_MIN_PIN has no EXTINT line available. Disable ENDSTOP_INTERRUPTS_FEATURE to continue." + #endif + attachInterrupt(V_MIN_PIN, endstop_ISR, CHANGE); + #endif + #if USE_W_MAX + #if !AVAILABLE_EILINE(W_MAX_PIN) + #error "W_MAX_PIN has no EXTINT line available. Disable ENDSTOP_INTERRUPTS_FEATURE to continue." + #endif + attachInterrupt(W_MAX_PIN, endstop_ISR, CHANGE); + #endif + #if USE_W_MIN + #if !AVAILABLE_EILINE(W_MIN_PIN) + #error "W_MIN_PIN has no EXTINT line available. Disable ENDSTOP_INTERRUPTS_FEATURE to continue." + #endif + attachInterrupt(W_MIN_PIN, endstop_ISR, CHANGE); + #endif +} diff --git a/Marlin/src/HAL/SAMD21/fastio.h b/Marlin/src/HAL/SAMD21/fastio.h new file mode 100644 index 0000000000..471e8b62ab --- /dev/null +++ b/Marlin/src/HAL/SAMD21/fastio.h @@ -0,0 +1,215 @@ +/** + * Marlin 3D Printer Firmware + * Copyright (c) 2022 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 + +/** + * SAMD21 HAL developed by Bart Meijer (brupje) + * Based on SAMD51 HAL by Giuliano Zaro (AKA GMagician) + */ + +/** + * Fast IO functions for SAMD21 + */ + +#include "SAMD21.h" + +/** + * Utility functions + */ + +#ifndef MASK + #define MASK(PIN) _BV(PIN) +#endif + +/** + * Magic I/O routines + * + * Now you can simply SET_OUTPUT(IO); WRITE(IO, HIGH); WRITE(IO, LOW); + */ + +// Read a pin +#define READ(IO) ((PORT->Group[(EPortType)GET_SAMD_PORT(IO)].IN.reg & MASK(GET_SAMD_PIN(IO))) != 0) + +// Write to a pin +#define WRITE(IO,V) do{ \ + const EPortType port = (EPortType)GET_SAMD_PORT(IO); \ + const uint32_t mask = MASK(GET_SAMD_PIN(IO)); \ + \ + if (V) PORT->Group[port].OUTSET.reg = mask; \ + else PORT->Group[port].OUTCLR.reg = mask; \ + }while(0) + +// Toggle a pin +#define TOGGLE(IO) PORT->Group[(EPortType)GET_SAMD_PORT(IO)].OUTTGL.reg = MASK(GET_SAMD_PIN(IO)); + +// Set pin as input +#define SET_INPUT(IO) do{ \ + const EPortType port = (EPortType)GET_SAMD_PORT(IO); \ + const uint32_t pin = GET_SAMD_PIN(IO); \ + \ + PORT->Group[port].PINCFG[pin].reg = (uint8_t)(PORT_PINCFG_INEN); \ + PORT->Group[port].DIRCLR.reg = MASK(pin); \ + }while(0) +// Set pin as input with pullup +#define SET_INPUT_PULLUP(IO) do{ \ + const EPortType port = (EPortType)GET_SAMD_PORT(IO); \ + const uint32_t pin = GET_SAMD_PIN(IO); \ + const uint32_t mask = MASK(pin); \ + \ + PORT->Group[port].PINCFG[pin].reg = (uint8_t)(PORT_PINCFG_INEN | PORT_PINCFG_PULLEN); \ + PORT->Group[port].DIRCLR.reg = mask; \ + PORT->Group[port].OUTSET.reg = mask; \ + }while(0) +// Set pin as input with pulldown +#define SET_INPUT_PULLDOWN(IO) do{ \ + const EPortType port = (EPortType)GET_SAMD_PORT(IO); \ + const uint32_t pin = GET_SAMD_PIN(IO); \ + const uint32_t mask = MASK(pin); \ + \ + PORT->Group[port].PINCFG[pin].reg = (uint8_t)(PORT_PINCFG_INEN | PORT_PINCFG_PULLEN); \ + PORT->Group[port].DIRCLR.reg = mask; \ + PORT->Group[port].OUTCLR.reg = mask; \ + }while(0) +// Set pin as output (push pull) +#define SET_OUTPUT(IO) do{ \ + const EPortType port = (EPortType)GET_SAMD_PORT(IO); \ + const uint32_t pin = GET_SAMD_PIN(IO); \ + \ + PORT->Group[port].DIRSET.reg = MASK(pin); \ + PORT->Group[port].PINCFG[pin].reg = 0; \ + }while(0) +// Set pin as output (open drain) +#define SET_OUTPUT_OD(IO) do{ \ + const EPortType port = (EPortType)GET_SAMD_PORT(IO); \ + const uint32_t pin = GET_SAMD_PIN(IO); \ + \ + PORT->Group[port].PINCFG[pin].reg = (uint8_t)(PORT_PINCFG_PULLEN); \ + PORT->Group[port].DIRCLR.reg = MASK(pin); \ + }while(0) +// Set pin as PWM (push pull) +#define SET_PWM SET_OUTPUT +// Set pin as PWM (open drain) +#define SET_PWM_OD SET_OUTPUT_OD + +// check if pin is an output +#define IS_OUTPUT(IO) ((PORT->Group[(EPortType)GET_SAMD_PORT(IO)].DIR.reg & MASK(GET_SAMD_PIN(IO))) \ + || (PORT->Group[(EPortType)GET_SAMD_PORT(IO)].PINCFG[GET_SAMD_PIN(IO)].reg & (PORT_PINCFG_INEN | PORT_PINCFG_PULLEN)) == PORT_PINCFG_PULLEN) +// check if pin is an input +#define IS_INPUT(IO) !IS_OUTPUT(IO) + +// Shorthand +#define OUT_WRITE(IO,V) do{ SET_OUTPUT(IO); WRITE(IO,V); }while(0) +#define OUT_WRITE_OD(IO,V) do{ SET_OUTPUT_OD(IO); WRITE(IO,V); }while(0) + +// digitalRead/Write wrappers +#define extDigitalRead(IO) digitalRead(IO) +#define extDigitalWrite(IO,V) digitalWrite(IO,V) + +/** + * Ports and functions + * Added as necessary or if I feel like it- not a comprehensive list! + */ + +/** + * Some of these share the same source and so can't be used in the same time + */ +#define PWM_PIN(P) (WITHIN(P, 2, 13) || WITHIN(P, 22, 23) || WITHIN(P, 44, 45) || P == 48) + +// Return fulfilled ADCx->INPUTCTRL.reg +#define PIN_TO_INPUTCTRL(P) ( (P == 0) ? ADC_INPUTCTRL_MUXPOS_PIN0 \ + : ((P) == 1) ? ADC_INPUTCTRL_MUXPOS_PIN1 \ + : ((P) == 2) ? ADC_INPUTCTRL_MUXPOS_PIN3 \ + : ((P) == 3) ? ADC_INPUTCTRL_MUXPOS_PIN4 \ + : ((P) == 4) ? ADC_INPUTCTRL_MUXPOS_PIN5 \ + : ((P) == 5) ? ADC_INPUTCTRL_MUXPOS_PIN5 \ + : ((P) == 6) ? ADC_INPUTCTRL_MUXPOS_PIN6 \ + : ((P) == 7) ? ADC_INPUTCTRL_MUXPOS_PIN7 \ + : ((P) == 8) ? ADC_INPUTCTRL_MUXPOS_PIN8 \ + : ((P) == 9) ? ADC_INPUTCTRL_MUXPOS_PIN9 \ + : ((P) == 10) ? ADC_INPUTCTRL_MUXPOS_PIN10 \ + : ((P) == 11) ? ADC_INPUTCTRL_MUXPOS_PIN11 \ + : ((P) == 12) ? ADC_INPUTCTRL_MUXPOS_PIN12 \ + : ((P) == 13) ? ADC_INPUTCTRL_MUXPOS_PIN13 \ + : ((P) == 14) ? ADC_INPUTCTRL_MUXPOS_PIN14 \ + : ADC_INPUTCTRL_MUXPOS_PIN15) + +#define digitalPinToAnalogInput(P) (WITHIN(P, 67, 74) ? (P) - 67 : WITHIN(P, 54, 61) ? 8 + (P) - 54 : WITHIN(P, 12, 13) ? 16 + (P) - 12 : P == 9 ? 18 : -1) + +/** + * pins + */ + +// PORTA +#define DIO28_PIN PIN_PA02 // A0 +#define DIO56_PIN PIN_PA03 // A13 +#define DIO31_PIN PIN_PA04 // A13 +#define DIO32_PIN PIN_PA05 // A1 +#define DIO8_PIN PIN_PA06 // A14 +#define DIO9_PIN PIN_PA07 // A15 +#define DIO4_PIN PIN_PA08 // A15 +#define DIO3_PIN PIN_PA09 // A15 +#define DIO1_PIN PIN_PA10 +#define DIO0_PIN PIN_PA11 +#define DIO18_PIN PIN_PA12 +#define DIO52_PIN PIN_PA13 +#define DIO2_PIN PIN_PA14 +#define DIO5_PIN PIN_PA15 +#define DIO11_PIN PIN_PA16 +#define DIO13_PIN PIN_PA17 +#define DIO10_PIN PIN_PA18 +#define DIO12_PIN PIN_PA19 +#define DIO6_PIN PIN_PA20 +#define DIO07_PIN PIN_PA21 +#define DIO34_PIN PIN_PA22 +#define DIO35_PIN PIN_PA23 +#define DIO42_PIN PIN_PA24 +#define DIO43_PIN PIN_PA25 + +#define DIO40_PIN PIN_PA27 + +#define DIO26_PIN PIN_PB00 +#define DIO27_PIN PIN_PB01 // A0 +#define DIO33_PIN PIN_PB02 +#define DIO39_PIN PIN_PB03 +#define DIO14_PIN PIN_PB04 +#define DIO15_PIN PIN_PB05 +#define DIO16_PIN PIN_PB06 +#define DIO17_PIN PIN_PB07 +#define DIO29_PIN PIN_PB08 +#define DIO30_PIN PIN_PB09 +#define DIO37_PIN PIN_PB10 +#define DIO38_PIN PIN_PB11 +#define DIO36_PIN PIN_PB12 +#define DIO19_PIN PIN_PB13 +#define DIO20_PIN PIN_PB14 +#define DIO21_PIN PIN_PB15 +#define DIO22_PIN PIN_PB16 +#define DIO23_PIN PIN_PB17 + +#define DIO44_PIN PIN_PB22 +#define DIO45_PIN PIN_PB23 +#define DIO24_PIN PIN_PB30 +#define DIO25_PIN PIN_PB31 + +#define DIO53_PIN PIN_PA21 +#define DIO54_PIN PIN_PA06 +#define DIO55_PIN PIN_PA07 diff --git a/Marlin/src/HAL/SAMD21/inc/Conditionals_LCD.h b/Marlin/src/HAL/SAMD21/inc/Conditionals_LCD.h new file mode 100644 index 0000000000..570baf7e95 --- /dev/null +++ b/Marlin/src/HAL/SAMD21/inc/Conditionals_LCD.h @@ -0,0 +1,22 @@ +/** + * Marlin 3D Printer Firmware + * Copyright (c) 2022 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] + * + * Based on Sprinter and grbl. + * Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ +#pragma once diff --git a/Marlin/src/HAL/SAMD21/inc/Conditionals_adv.h b/Marlin/src/HAL/SAMD21/inc/Conditionals_adv.h new file mode 100644 index 0000000000..d6a3c4fe0b --- /dev/null +++ b/Marlin/src/HAL/SAMD21/inc/Conditionals_adv.h @@ -0,0 +1,27 @@ +/** + * Marlin 3D Printer Firmware + * Copyright (c) 2022 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 . + * + */ + +/** + * SAMD21 HAL developed by Bart Meijer (brupje) + * Based on SAMD51 HAL by Giuliano Zaro (AKA GMagician) + */ +#pragma once diff --git a/Marlin/src/HAL/SAMD21/inc/Conditionals_post.h b/Marlin/src/HAL/SAMD21/inc/Conditionals_post.h new file mode 100644 index 0000000000..87d3350c94 --- /dev/null +++ b/Marlin/src/HAL/SAMD21/inc/Conditionals_post.h @@ -0,0 +1,33 @@ +/** + * Marlin 3D Printer Firmware + * Copyright (c) 2022 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 . + * + */ + +/** + * SAMD21 HAL developed by Bart Meijer (brupje) + * Based on SAMD51 HAL by Giuliano Zaro (AKA GMagician) + */ +#pragma once + +#if USE_FALLBACK_EEPROM + #define FLASH_EEPROM_EMULATION +#elif ANY(I2C_EEPROM, SPI_EEPROM) + #define USE_SHARED_EEPROM 1 +#endif diff --git a/Marlin/src/HAL/SAMD21/inc/SanityCheck.h b/Marlin/src/HAL/SAMD21/inc/SanityCheck.h new file mode 100644 index 0000000000..83fafc9689 --- /dev/null +++ b/Marlin/src/HAL/SAMD21/inc/SanityCheck.h @@ -0,0 +1,54 @@ +/** + * Marlin 3D Printer Firmware + * Copyright (c) 2022 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 . + * + */ + +/** + * SAMD21 HAL developed by Bart Meijer (brupje) + * Based on SAMD51 HAL by Giuliano Zaro (AKA GMagician) + */ + +/** + * Test SAMD21 specific configuration values for errors at compile-time. + */ + +#if HAS_SPI_TFT || HAS_FSMC_TFT + #error "Sorry! TFT displays are not available for HAL/SAMD21." +#endif + +#if SERVO_TC == MF_TIMER_RTC + #error "Servos can't use RTC timer" +#endif + +#if ENABLED(EMERGENCY_PARSER) + #error "EMERGENCY_PARSER is not yet implemented for SAMD21. Disable EMERGENCY_PARSER to continue." +#endif + +#if ENABLED(ONBOARD_SDIO) + #error "ONBOARD_SDIO is not supported on SAMD21." +#endif + +#if ENABLED(FAST_PWM_FAN) + #error "Features requiring Hardware PWM (FAST_PWM_FAN) are not yet supported for HAL/SAMD21." +#endif + +#if ENABLED(POSTMORTEM_DEBUGGING) + #error "POSTMORTEM_DEBUGGING is not yet supported on SAMD21." +#endif diff --git a/Marlin/src/HAL/SAMD21/pinsDebug.h b/Marlin/src/HAL/SAMD21/pinsDebug.h new file mode 100644 index 0000000000..f94315cdf5 --- /dev/null +++ b/Marlin/src/HAL/SAMD21/pinsDebug.h @@ -0,0 +1,160 @@ +/** + * Marlin 3D Printer Firmware + * Copyright (c) 2022 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 + +/** + * SAMD21 HAL developed by Bart Meijer (brupje) + * Based on SAMD51 HAL by Giuliano Zaro (AKA GMagician) + */ + +#define NUMBER_PINS_TOTAL PINS_COUNT + +#define digitalRead_mod(p) extDigitalRead(p) +#define PRINT_PORT(p) do{ SERIAL_ECHOPGM(" Port: "); sprintf_P(buffer, PSTR("%c%02ld"), 'A' + g_APinDescription[p].ulPort, g_APinDescription[p].ulPin); SERIAL_ECHO(buffer); }while (0) +#define PRINT_ARRAY_NAME(x) do{ sprintf_P(buffer, PSTR("%-" STRINGIFY(MAX_NAME_LENGTH) "s"), pin_array[x].name); SERIAL_ECHO(buffer); }while(0) +#define PRINT_PIN(p) do{ sprintf_P(buffer, PSTR("%3d "), p); SERIAL_ECHO(buffer); }while(0) +#define PRINT_PIN_ANALOG(p) do{ sprintf_P(buffer, PSTR(" (A%2d) "), DIGITAL_PIN_TO_ANALOG_PIN(pin)); SERIAL_ECHO(buffer); }while(0) +#define GET_ARRAY_PIN(p) pin_array[p].pin +#define GET_ARRAY_IS_DIGITAL(p) pin_array[p].is_digital +#define VALID_PIN(pin) (pin >= 0 && pin < (int8_t)NUMBER_PINS_TOTAL) +#define DIGITAL_PIN_TO_ANALOG_PIN(p) digitalPinToAnalogInput(p) +#define IS_ANALOG(P) (DIGITAL_PIN_TO_ANALOG_PIN(P)!=-1) +#define pwm_status(pin) digitalPinHasPWM(pin) +#define MULTI_NAME_PAD 27 // space needed to be pretty if not first name assigned to a pin + +// pins that will cause hang/reset/disconnect in M43 Toggle and Watch utilities +// uses pin index +#define M43_NEVER_TOUCH(Q) ((Q) >= 75) + +bool GET_PINMODE(int8_t pin) { // 1: output, 0: input + const EPortType samdport = g_APinDescription[pin].ulPort; + const uint32_t samdpin = g_APinDescription[pin].ulPin; + return PORT->Group[samdport].DIR.reg & MASK(samdpin) || (PORT->Group[samdport].PINCFG[samdpin].reg & (PORT_PINCFG_INEN | PORT_PINCFG_PULLEN)) == PORT_PINCFG_PULLEN; +} + +void pwm_details(int32_t pin) { + if (pwm_status(pin)) { + //uint32_t chan = g_APinDescription[pin].ulPWMChannel TODO when fast pwm is operative; + //SERIAL_ECHOPGM("PWM = ", duty); + } +} + +/** + * SAMD21 Board pin| PORT | Label + * ----------------+--------+------- + * 0 | PB25 | "RX0" + * 1 | PB24 | "TX0" + * 2 | PC18 | + * 3 | PC19 | + * 4 | PC20 | + * 5 | PC21 | + * 6 | PD20 | + * 7 | PD21 | + * 8 | PB18 | + * 9 | PB2 | + * 10 | PB22 | + * 11 | PB23 | + * 12 | PB0 | "A16" + * 13 | PB1 | LED AMBER "L" / "A17" + * 14 | PB16 | "TX3" + * 15 | PB17 | "RX3" + * 16 | PC22 | "TX2" + * 17 | PC23 | "RX2" + * 18 | PB12 | "TX1" / "A18" + * 19 | PB13 | "RX1" + * 20 | PB20 | "SDA" + * 21 | PB21 | "SCL" + * 22 | PD12 | + * 23 | PA15 | + * 24 | PC17 | + * 25 | PC16 | + * 26 | PA12 | + * 27 | PA13 | + * 28 | PA14 | + * 29 | PB19 | + * 30 | PA23 | + * 31 | PA22 | + * 32 | PA21 | + * 33 | PA20 | + * 34 | PA19 | + * 35 | PA18 | + * 36 | PA17 | + * 37 | PA16 | + * 38 | PB15 | + * 39 | PB14 | + * 40 | PC13 | + * 41 | PC12 | + * 42 | PC15 | + * 43 | PC14 | + * 44 | PC11 | + * 45 | PC10 | + * 46 | PC6 | + * 47 | PC7 | + * 48 | PC4 | + * 49 | PC5 | + * 50 | PD11 | + * 51 | PD8 | + * 52 | PD9 | + * 53 | PD10 | + * 54 | PB5 | "A8" + * 55 | PB6 | "A9" + * 56 | PB7 | "A10" + * 57 | PB8 | "A11" + * 58 | PB9 | "A12" + * 69 | PA4 | "A13" + * 60 | PA6 | "A14" + * 61 | PA7 | "A15" + * 62 | PB17 | + * 63 | PB20 | + * 64 | PD11 | + * 65 | PD8 | + * 66 | PD9 | + * 67 | PA2 | "A0" / "DAC0" + * 68 | PA5 | "A1" / "DAC1" + * 69 | PB3 | "A2" + * 70 | PC0 | "A3" + * 71 | PC1 | "A4" + * 72 | PC2 | "A5" + * 73 | PC3 | "A6" + * 74 | PB4 | "A7" + * 75 | PC31 | LED GREEN "RX" + * 76 | PC30 | LED GREEN "TX" + * 77 | PA27 | USB: Host enable + * 78 | PA24 | USB: D- + * 79 | PA25 | USB: D+ + * 80 | PB29 | SD: MISO + * 81 | PB27 | SD: SCK + * 82 | PB26 | SD: MOSI + * 83 | PB28 | SD: CS + * 84 | PA3 | AREF + * 85 | PA2 | DAC0 (Duplicate) + * 86 | PA5 | DAC1 (Duplicate) + * 87 | PB1 | LED AMBER "L" (Duplicate) + * 88 | PC24 | NeoPixel + * 89 | PB10 | QSPI: SCK + * 90 | PB11 | QSPI: CS + * 91 | PA8 | QSPI: IO0 + * 92 | PA9 | QSPI: IO1 + * 93 | PA10 | QSPI: IO2 + * 94 | PA11 | QSPI: IO3 + * 95 | PB31 | SD: DETECT + */ diff --git a/Marlin/src/HAL/SAMD21/spi_pins.h b/Marlin/src/HAL/SAMD21/spi_pins.h new file mode 100644 index 0000000000..8c25b84dc1 --- /dev/null +++ b/Marlin/src/HAL/SAMD21/spi_pins.h @@ -0,0 +1,54 @@ +/** + * Marlin 3D Printer Firmware + * Copyright (c) 2022 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 + +/** + * SAMD21 HAL developed by Bart Meijer (brupje) + * Based on SAMD51 HAL by Giuliano Zaro (AKA GMagician) + */ + +/** + * SAMD21 Default SPI Pins + * + * SS SCK MISO MOSI + * +-------------------------+ + * SPI | 53 52 50 51 | + * SPI1 | 83 81 80 82 | + * +-------------------------+ + * Any pin can be used for Chip Select (SD_SS_PIN) + */ +#ifndef SD_SCK_PIN + #define SD_SCK_PIN 38 +#endif +#ifndef SD_MISO_PIN + #define SD_MISO_PIN 36 +#endif +#ifndef SD_MOSI_PIN + #define SD_MOSI_PIN 37 +#endif +#ifndef SDSS + #define SDSS 18 +#endif + +#ifndef SD_SS_PIN + #define SD_SS_PIN SDSS +#endif diff --git a/Marlin/src/HAL/SAMD21/timers.cpp b/Marlin/src/HAL/SAMD21/timers.cpp new file mode 100644 index 0000000000..b5f1d4f7bd --- /dev/null +++ b/Marlin/src/HAL/SAMD21/timers.cpp @@ -0,0 +1,217 @@ +/** + * Marlin 3D Printer Firmware + * Copyright (c) 2022 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 . + * + */ + +/** + * SAMD21 HAL developed by Bart Meijer (brupje) + * Based on SAMD51 HAL by Giuliano Zaro (AKA GMagician) + */ +#ifdef __SAMD21__ + +// -------------------------------------------------------------------------- +// Includes +// -------------------------------------------------------------------------- + +#include "../../inc/MarlinConfig.h" +#include "ServoTimers.h" // for SERVO_TC + +// -------------------------------------------------------------------------- +// Local defines +// -------------------------------------------------------------------------- + +#define NUM_HARDWARE_TIMERS 9 + +// -------------------------------------------------------------------------- +// Private Variables +// -------------------------------------------------------------------------- + +const tTimerConfig timer_config[NUM_HARDWARE_TIMERS] = { + { {.pTcc=TCC0}, TimerType::tcc, TCC0_IRQn, TC_PRIORITY(0) }, // 0 - stepper (assigned priority 2) + { {.pTcc=TCC1}, TimerType::tcc, TCC1_IRQn, TC_PRIORITY(1) }, // 1 - stepper (needed by 32 bit timers) + { {.pTcc=TCC2}, TimerType::tcc, TCC2_IRQn, 5 }, // 2 - tone (reserved by framework and fixed assigned priority 5) + { {.pTc=TC3}, TimerType::tc, TC3_IRQn, TC_PRIORITY(3) }, // 3 - servo (assigned priority 1) + { {.pTc=TC4}, TimerType::tc, TC4_IRQn, TC_PRIORITY(4) }, // 4 - software serial (no interrupts used) + { {.pTc=TC5}, TimerType::tc, TC5_IRQn, TC_PRIORITY(5) }, + { {.pTc=TC6}, TimerType::tc, TC6_IRQn, TC_PRIORITY(6) }, + { {.pTc=TC7}, TimerType::tc, TC7_IRQn, TC_PRIORITY(7) }, + { {.pRtc=RTC}, TimerType::rtc, RTC_IRQn, TC_PRIORITY(8) } // 8 - temperature (assigned priority 6) +}; + +// -------------------------------------------------------------------------- +// Private functions +// -------------------------------------------------------------------------- + +FORCE_INLINE void Disable_Irq(IRQn_Type irq) { + NVIC_DisableIRQ(irq); + + // We NEED memory barriers to ensure Interrupts are actually disabled! + // ( https://dzone.com/articles/nvic-disabling-interrupts-on-arm-cortex-m-and-the ) + __DSB(); + __ISB(); +} + +static bool tcIsSyncing(Tc * tc) { + return tc->COUNT32.STATUS.reg & TC_STATUS_SYNCBUSY; +} + +static void tcReset( Tc * tc) { + tc->COUNT32.CTRLA.reg = TC_CTRLA_SWRST; + while (tcIsSyncing(tc)) {} + while (tc->COUNT32.CTRLA.bit.SWRST) {} +} + +// -------------------------------------------------------------------------- +// Public functions +// -------------------------------------------------------------------------- + +void HAL_timer_start(const uint8_t timer_num, const uint32_t frequency) { + IRQn_Type irq = timer_config[timer_num].IRQ_Id; + + // Disable interrupt, just in case it was already enabled + NVIC_DisableIRQ(irq); + NVIC_ClearPendingIRQ(irq); + + if (timer_num == MF_TIMER_RTC) { + + // https://github.com/arduino-libraries/RTCZero + Rtc * const rtc = timer_config[timer_num].pRtc; + PM->APBAMASK.reg |= PM_APBAMASK_RTC; + + GCLK->CLKCTRL.reg = (uint32_t)((GCLK_CLKCTRL_CLKEN | GCLK_CLKCTRL_GEN_GCLK4 | (RTC_GCLK_ID << GCLK_CLKCTRL_ID_Pos))); + while (GCLK->STATUS.bit.SYNCBUSY) {} + + GCLK->GENCTRL.reg = (GCLK_GENCTRL_GENEN | GCLK_GENCTRL_SRC_OSCULP32K | GCLK_GENCTRL_ID(4) | GCLK_GENCTRL_DIVSEL ); + while (GCLK->STATUS.reg & GCLK_STATUS_SYNCBUSY) {} + + GCLK->GENDIV.reg = GCLK_GENDIV_ID(4); + GCLK->GENDIV.bit.DIV=4; + while (GCLK->STATUS.reg & GCLK_STATUS_SYNCBUSY) {} + + // Disable timer interrupt + rtc->MODE0.INTENCLR.reg = RTC_MODE0_INTENCLR_CMP0; + SYNC(rtc->MODE0.STATUS.bit.SYNCBUSY); + + while(rtc->MODE0.STATUS.bit.SYNCBUSY) {} + + // Stop timer, just in case, to be able to reconfigure it + rtc->MODE0.CTRL.reg = + RTC_MODE0_CTRL_MODE_COUNT32 | // Mode 0 = 32-bits counter + RTC_MODE0_CTRL_PRESCALER_DIV1024; // Divisor = 1024 + + while(rtc->MODE0.STATUS.bit.SYNCBUSY) {} + + // Mode, reset counter on match + rtc->MODE0.CTRL.reg = RTC_MODE0_CTRL_MODE_COUNT32 | RTC_MODE0_CTRL_MATCHCLR; + + // Set compare value + rtc->MODE0.COMP[0].reg = (32768 + frequency / 2) / frequency; + SYNC(rtc->MODE0.STATUS.bit.SYNCBUSY); + + // Enable interrupt on compare + rtc->MODE0.INTFLAG.reg = RTC_MODE0_INTFLAG_CMP0; // reset pending interrupt + rtc->MODE0.INTENSET.reg = RTC_MODE0_INTENSET_CMP0; // enable compare 0 interrupt + + // And start timer + rtc->MODE0.CTRL.bit.ENABLE = true; + SYNC(rtc->MODE0.STATUS.bit.SYNCBUSY); + + } + else if (timer_config[timer_num].type==TimerType::tcc) { + + Tcc * const tc = timer_config[timer_num].pTcc; + + PM->APBCMASK.reg |= PM_APBCMASK_TCC0; + GCLK->CLKCTRL.reg =(GCLK_CLKCTRL_CLKEN | GCLK_CLKCTRL_GEN_GCLK0 | GCLK_CLKCTRL_ID(TCC0_GCLK_ID)); + SYNC (GCLK->STATUS.bit.SYNCBUSY); + + tc->CTRLA.reg = TCC_CTRLA_SWRST; + SYNC (tc->SYNCBUSY.reg & TCC_SYNCBUSY_SWRST) {} + + SYNC (tc->CTRLA.bit.SWRST); + + tc->CTRLA.reg &= ~(TCC_CTRLA_ENABLE); // disable TC module + + tc->CTRLA.reg |= TCC_WAVE_WAVEGEN_MFRQ; + tc->CTRLA.reg |= TCC_CTRLA_PRESCALER_DIV2; + tc->CC[0].reg = (HAL_TIMER_RATE) / frequency; + tc->INTENSET.reg = TCC_INTFLAG_MC0; + tc->CTRLA.reg |= TCC_CTRLA_ENABLE; + tc->INTFLAG.reg = 0xFF; + SYNC ( tc->STATUS.reg & TC_STATUS_SYNCBUSY); + + } + else { + Tc * const tc = timer_config[timer_num].pTc; + + // Disable timer interrupt + tc->COUNT32.INTENCLR.reg = TC_INTENCLR_OVF; // disable overflow interrupt + + // TCn clock setup + GCLK->CLKCTRL.reg = (uint16_t) (GCLK_CLKCTRL_CLKEN | GCLK_CLKCTRL_GEN_GCLK0 | GCLK_CLKCTRL_ID(GCM_TC4_TC5)) ; + SYNC (GCLK->STATUS.bit.SYNCBUSY); + + tcReset(tc); // reset TC + + // Set Timer counter 5 Mode to 16 bits, it will become a 16bit counter ('mode1' in the datasheet) + tc->COUNT32.CTRLA.reg |= TC_CTRLA_MODE_COUNT32; + // Set TC waveform generation mode to 'match frequency' + tc->COUNT32.CTRLA.reg |= TC_CTRLA_WAVEGEN_MFRQ; + //set prescaler + //the clock normally counts at the GCLK_TC frequency, but we can set it to divide that frequency to slow it down + //you can use different prescaler divisons here like TC_CTRLA_PRESCALER_DIV1 to get a different range + tc->COUNT32.CTRLA.reg |= TC_CTRLA_PRESCALER_DIV1 | TC_CTRLA_ENABLE; //it will divide GCLK_TC frequency by 1024 + //set the compare-capture register. + //The counter will count up to this value (it's a 16bit counter so we use uint16_t) + //this is how we fine-tune the frequency, make it count to a lower or higher value + //system clock should be 1MHz (8MHz/8) at Reset by default + tc->COUNT32.CC[0].reg = (uint16_t) (HAL_TIMER_RATE / frequency); + while (tcIsSyncing(tc)) {} + + // Enable the TC interrupt request + tc->COUNT32.INTENSET.bit.MC0 = 1; + while (tcIsSyncing(tc)) {} + } + + NVIC_SetPriority(irq, timer_config[timer_num].priority); + NVIC_EnableIRQ(irq); +} + +void HAL_timer_enable_interrupt(const uint8_t timer_num) { + const IRQn_Type irq = timer_config[timer_num].IRQ_Id; + NVIC_EnableIRQ(irq); +} + +void HAL_timer_disable_interrupt(const uint8_t timer_num) { + const IRQn_Type irq = timer_config[timer_num].IRQ_Id; + Disable_Irq(irq); +} + +// missing from CMSIS: Check if interrupt is enabled or not +static bool NVIC_GetEnabledIRQ(IRQn_Type IRQn) { + return TEST(NVIC->ISER[uint32_t(IRQn) >> 5], uint32_t(IRQn) & 0x1F); +} + +bool HAL_timer_interrupt_enabled(const uint8_t timer_num) { + const IRQn_Type irq = timer_config[timer_num].IRQ_Id; + return NVIC_GetEnabledIRQ(irq); +} + +#endif // __SAMD21__ diff --git a/Marlin/src/HAL/SAMD21/timers.h b/Marlin/src/HAL/SAMD21/timers.h new file mode 100644 index 0000000000..303ccbdc50 --- /dev/null +++ b/Marlin/src/HAL/SAMD21/timers.h @@ -0,0 +1,160 @@ +/** + * Marlin 3D Printer Firmware + * Copyright (c) 2022 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 + +/** + * SAMD21 HAL developed by Bart Meijer (brupje) + * Based on SAMD51 HAL by Giuliano Zaro (AKA GMagician) + */ + +#include + +// -------------------------------------------------------------------------- +// Defines +// -------------------------------------------------------------------------- + +typedef uint32_t hal_timer_t; +#define HAL_TIMER_TYPE_MAX 0xFFFFFFFF + +#define HAL_TIMER_RATE F_CPU // frequency of timers peripherals + +#define MF_TIMER_RTC 8 // This is not a TC but a RTC + +#ifndef MF_TIMER_STEP + #define MF_TIMER_STEP 4 // Timer Index for Stepper +#endif +#ifndef MF_TIMER_PULSE + #define MF_TIMER_PULSE MF_TIMER_STEP +#endif +#ifndef MF_TIMER_TEMP + #define MF_TIMER_TEMP MF_TIMER_RTC // Timer Index for Temperature +#endif + +#define TEMP_TIMER_FREQUENCY 1000 // temperature interrupt frequency + +#define STEPPER_TIMER_RATE HAL_TIMER_RATE // frequency of stepper timer (HAL_TIMER_RATE / STEPPER_TIMER_PRESCALE) +#define STEPPER_TIMER_TICKS_PER_US (STEPPER_TIMER_RATE / 1000000) // stepper timer ticks per µs +#define STEPPER_TIMER_PRESCALE (CYCLES_PER_MICROSECOND / STEPPER_TIMER_TICKS_PER_US) + +#define PULSE_TIMER_RATE STEPPER_TIMER_RATE +#define PULSE_TIMER_PRESCALE STEPPER_TIMER_PRESCALE +#define PULSE_TIMER_TICKS_PER_US STEPPER_TIMER_TICKS_PER_US + +#define ENABLE_STEPPER_DRIVER_INTERRUPT() HAL_timer_enable_interrupt(MF_TIMER_STEP) +#define DISABLE_STEPPER_DRIVER_INTERRUPT() HAL_timer_disable_interrupt(MF_TIMER_STEP) +#define STEPPER_ISR_ENABLED() HAL_timer_interrupt_enabled(MF_TIMER_STEP) + +#define ENABLE_TEMPERATURE_INTERRUPT() HAL_timer_enable_interrupt(MF_TIMER_TEMP) +#define DISABLE_TEMPERATURE_INTERRUPT() HAL_timer_disable_interrupt(MF_TIMER_TEMP) + +#define TC_PRIORITY(t) ( t == SERVO_TC ? 1 \ + : (t == MF_TIMER_STEP || t == MF_TIMER_PULSE) ? 2 \ + : (t == MF_TIMER_TEMP) ? 6 : 7 ) + +#define _TC_HANDLER(t) void TC##t##_Handler() +#define TC_HANDLER(t) _TC_HANDLER(t) +#ifndef HAL_STEP_TIMER_ISR + #define HAL_STEP_TIMER_ISR() TC_HANDLER(MF_TIMER_STEP) +#endif +#if MF_TIMER_STEP != MF_TIMER_PULSE + #define HAL_PULSE_TIMER_ISR() TC_HANDLER(MF_TIMER_PULSE) +#endif +#if MF_TIMER_TEMP == MF_TIMER_RTC + #define HAL_TEMP_TIMER_ISR() void RTC_Handler() +#else + #define HAL_TEMP_TIMER_ISR() TC_HANDLER(MF_TIMER_TEMP) +#endif + +// -------------------------------------------------------------------------- +// Types +// -------------------------------------------------------------------------- +typedef enum { tcc, tc, rtc } TimerType; + +typedef struct { + union { + Tc *pTc; + Tcc *pTcc; + Rtc *pRtc; + }; + TimerType type; + IRQn_Type IRQ_Id; + uint8_t priority; +} tTimerConfig; + +// -------------------------------------------------------------------------- +// Public Variables +// -------------------------------------------------------------------------- + +extern const tTimerConfig timer_config[]; + +// -------------------------------------------------------------------------- +// Public functions +// -------------------------------------------------------------------------- + +void HAL_timer_start(const uint8_t timer_num, const uint32_t frequency); + +FORCE_INLINE static void HAL_timer_set_compare(const uint8_t timer_num, const hal_timer_t compare) { + // Should never be called with timer MF_TIMER_RTC + Tc * const tc = timer_config[timer_num].pTc; + tc->COUNT32.CC[0].reg = compare; +} + +FORCE_INLINE static hal_timer_t HAL_timer_get_compare(const uint8_t timer_num) { + // Should never be called with timer MF_TIMER_RTC + Tc * const tc = timer_config[timer_num].pTc; + return (hal_timer_t)tc->COUNT32.CC[0].reg; +} + +FORCE_INLINE static hal_timer_t HAL_timer_get_count(const uint8_t timer_num) { + // Should never be called with timer MF_TIMER_RTC + Tc * const tc = timer_config[timer_num].pTc; + tc->COUNT32.READREQ.reg = TC_READREQ_RREQ; + // Request a read synchronization + SYNC (tc->COUNT32.STATUS.bit.SYNCBUSY); + //SYNC(tc->COUNT32.STATUS.bit.SYNCBUSY ); + return tc->COUNT32.COUNT.reg; +} + +void HAL_timer_enable_interrupt(const uint8_t timer_num); +void HAL_timer_disable_interrupt(const uint8_t timer_num); +bool HAL_timer_interrupt_enabled(const uint8_t timer_num); + +FORCE_INLINE static void HAL_timer_isr_prologue(const uint8_t timer_num) { + if (timer_num == MF_TIMER_RTC) { + Rtc * const rtc = timer_config[timer_num].pRtc; + // Clear interrupt flag + rtc->MODE0.INTFLAG.reg = RTC_MODE0_INTFLAG_CMP0| RTC_MODE0_INTFLAG_OVF; + + } + else if (timer_config[timer_num].type == TimerType::tcc){ + Tcc * const tc = timer_config[timer_num].pTcc; + // Clear interrupt flag + tc->INTFLAG.reg = TCC_INTFLAG_OVF; + } + else { + Tc * const tc = timer_config[timer_num].pTc; + // Clear interrupt flag + tc->COUNT32.INTFLAG.bit.MC0 = 1; + } +} + +#define HAL_timer_isr_epilogue(timer_num) diff --git a/Marlin/src/HAL/SAMD21/u8g/LCD_I2C_routines.cpp b/Marlin/src/HAL/SAMD21/u8g/LCD_I2C_routines.cpp new file mode 100644 index 0000000000..41da7c10fc --- /dev/null +++ b/Marlin/src/HAL/SAMD21/u8g/LCD_I2C_routines.cpp @@ -0,0 +1,32 @@ +/** + * Marlin 3D Printer Firmware + * Copyright (c) 2022 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 . + * + */ + +/** + * SAMD21 HAL developed by Bart Meijer (brupje) + * Based on SAMD51 HAL by Giuliano Zaro (AKA GMagician) + */ +// adapted from I2C/master/master.c example +// https://www-users.cs.york.ac.uk/~pcc/MCP/HAPR-Course-web/CMSIS/examples/html/master_8c_source.html + +#ifdef __SAMD21__ + +#endif // __SAMD21__ diff --git a/Marlin/src/HAL/SAMD21/u8g/LCD_I2C_routines.h b/Marlin/src/HAL/SAMD21/u8g/LCD_I2C_routines.h new file mode 100644 index 0000000000..d6a3c4fe0b --- /dev/null +++ b/Marlin/src/HAL/SAMD21/u8g/LCD_I2C_routines.h @@ -0,0 +1,27 @@ +/** + * Marlin 3D Printer Firmware + * Copyright (c) 2022 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 . + * + */ + +/** + * SAMD21 HAL developed by Bart Meijer (brupje) + * Based on SAMD51 HAL by Giuliano Zaro (AKA GMagician) + */ +#pragma once diff --git a/Marlin/src/HAL/SAMD21/u8g/LCD_defines.h b/Marlin/src/HAL/SAMD21/u8g/LCD_defines.h new file mode 100644 index 0000000000..d6fe93117b --- /dev/null +++ b/Marlin/src/HAL/SAMD21/u8g/LCD_defines.h @@ -0,0 +1,29 @@ +/** + * Marlin 3D Printer Firmware + * Copyright (c) 2022 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 + +/** + * SAMD21 LCD-specific defines + */ + +uint8_t u8g_com_samd21_st7920_hw_spi_fn(u8g_t *u8g, uint8_t msg, uint8_t arg_val, void *arg_ptr); +#define U8G_COM_ST7920_HAL_HW_SPI u8g_com_samd21_st7920_hw_spi_fn diff --git a/Marlin/src/HAL/SAMD21/u8g/LCD_pin_routines.c b/Marlin/src/HAL/SAMD21/u8g/LCD_pin_routines.c new file mode 100644 index 0000000000..f9f77825f6 --- /dev/null +++ b/Marlin/src/HAL/SAMD21/u8g/LCD_pin_routines.c @@ -0,0 +1,42 @@ +/** + * Marlin 3D Printer Firmware + * Copyright (c) 2022 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 . + * + */ + +/** + * SAMD21 HAL developed by Bart Meijer (brupje) + * Based on SAMD51 HAL by Giuliano Zaro (AKA GMagician) + */ + +/** + * Low level pin manipulation routines - used by all the drivers. + * + * These are based on the SAMD51 pinMode, digitalRead & digitalWrite routines. + * + * Couldn't just call exact copies because the overhead killed the LCD update speed + * With an intermediate level the softspi was running in the 10-20kHz range which + * resulted in using about about 25% of the CPU's time. + */ + +#ifdef __SAMD21__ + +#include + +#endif // __SAMD21__ diff --git a/Marlin/src/HAL/SAMD21/u8g/LCD_pin_routines.h b/Marlin/src/HAL/SAMD21/u8g/LCD_pin_routines.h new file mode 100644 index 0000000000..92626552b0 --- /dev/null +++ b/Marlin/src/HAL/SAMD21/u8g/LCD_pin_routines.h @@ -0,0 +1,42 @@ +/** + * Marlin 3D Printer Firmware + * Copyright (c) 2022 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 . + * + */ + +/** + * SAMD21 HAL developed by Bart Meijer (brupje) + * Based on SAMD51 HAL by Giuliano Zaro (AKA GMagician) + */ +#pragma once + +/** + * Low level pin manipulation routines - used by all the drivers. + * + * These are based on the SAMD51 pinMode, digitalRead & digitalWrite routines. + * + * Couldn't just call exact copies because the overhead killed the LCD update speed + * With an intermediate level the softspi was running in the 10-20kHz range which + * resulted in using about about 25% of the CPU's time. + */ + +void u8g_SetPinOutput(uint8_t internal_pin_number); +void u8g_SetPinInput(uint8_t internal_pin_number); +void u8g_SetPinLevel(uint8_t pin, uint8_t pin_status); +uint8_t u8g_GetPinLevel(uint8_t pin); diff --git a/Marlin/src/HAL/SAMD21/u8g/u8g_com_HAL_samd21_shared_hw_spi.cpp b/Marlin/src/HAL/SAMD21/u8g/u8g_com_HAL_samd21_shared_hw_spi.cpp new file mode 100644 index 0000000000..42630a6ce5 --- /dev/null +++ b/Marlin/src/HAL/SAMD21/u8g/u8g_com_HAL_samd21_shared_hw_spi.cpp @@ -0,0 +1,158 @@ +/** + * Marlin 3D Printer Firmware + * Copyright (c) 2022 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 . + * + */ + +/** + * SAMD21 HAL developed by Bart Meijer (brupje) + * Based on SAMD51 HAL by Giuliano Zaro (AKA GMagician) + */ + +/** + * Based on u8g_com_msp430_hw_spi.c + * + * Universal 8bit Graphics Library + * + * Copyright (c) 2012, olikraus@gmail.com + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, this list + * of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright notice, this + * list of conditions and the following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifdef __SAMD21__ + +#include "../../../inc/MarlinConfigPre.h" + +#if HAS_MARLINUI_U8GLIB + +#include +#include "SPI.h" + +#include "../../shared/HAL_SPI.h" + +#ifndef LCD_SPI_SPEED + #define LCD_SPI_SPEED SPI_HALF_SPEED +#endif + +void u8g_SetPIOutput(u8g_t *u8g, uint8_t pin_index) { + if (u8g->pin_list[pin_index]!= U8G_PIN_NONE) + pinMode(u8g->pin_list[pin_index],OUTPUT); +} + +void u8g_SetPILevel(u8g_t *u8g, uint8_t pin_index, uint8_t level) { + if (u8g->pin_list[pin_index]!= U8G_PIN_NONE) + digitalWrite(u8g->pin_list[pin_index],level); +} + +uint8_t u8g_com_samd21_st7920_hw_spi_fn(u8g_t *u8g, uint8_t msg, uint8_t arg_val, void *arg_ptr) { + + + switch (msg) { + case U8G_COM_MSG_STOP: + break; + + case U8G_COM_MSG_INIT: + u8g_SetPIOutput(u8g, U8G_PI_CS); + u8g_SetPIOutput(u8g, U8G_PI_A0); + u8g_SetPIOutput(u8g, U8G_PI_RESET); + + u8g_SetPILevel(u8g, U8G_PI_CS, LOW); + + spiBegin(); + u8g->pin_list[U8G_PI_A0_STATE] = 0; + break; + + case U8G_COM_MSG_ADDRESS: // define cmd (arg_val = 0) or data mode (arg_val = 1) + u8g_SetPILevel(u8g, U8G_PI_A0, arg_val); + u8g->pin_list[U8G_PI_A0_STATE] = arg_val; + break; + + case U8G_COM_MSG_CHIP_SELECT: // arg_val == 1 means chip selected, but ST7920 is active high, so needs inverting + u8g_SetPILevel(u8g, U8G_PI_CS, arg_val ? HIGH : LOW); + break; + + case U8G_COM_MSG_RESET: + u8g_SetPILevel(u8g, U8G_PI_RESET, arg_val); + break; + + case U8G_COM_MSG_WRITE_BYTE: + spiBeginTransaction(LCD_SPI_SPEED, MSBFIRST, SPI_MODE0); + + if (u8g->pin_list[U8G_PI_A0_STATE] == 0) { // command + SPI.transfer(0x0f8); u8g->pin_list[U8G_PI_A0_STATE] = 2; + } + else if (u8g->pin_list[U8G_PI_A0_STATE] == 1) { // data + SPI.transfer(0x0fa); u8g->pin_list[U8G_PI_A0_STATE] = 2; + } + + SPI.transfer(arg_val & 0x0f0); + SPI.transfer(arg_val << 4); + SPI.endTransaction(); + break; + + case U8G_COM_MSG_WRITE_SEQ: + spiBeginTransaction(LCD_SPI_SPEED, MSBFIRST, SPI_MODE0); + + if (u8g->pin_list[U8G_PI_A0_STATE] == 0 ) { // command + SPI.transfer(0x0f8); u8g->pin_list[U8G_PI_A0_STATE] = 2; + } + else if (u8g->pin_list[U8G_PI_A0_STATE] == 1) { // data + SPI.transfer(0x0fa); u8g->pin_list[U8G_PI_A0_STATE] = 2; + } + + uint8_t *ptr = (uint8_t*)arg_ptr; + while (arg_val > 0) { + SPI.transfer((*ptr) & 0x0f0); + SPI.transfer((*ptr) << 4); + ptr++; + arg_val--; + } + + SPI.endTransaction(); + break; + } + return 1; +} + +#endif // HAS_MARLINUI_U8GLIB + +#endif // __SAMD21__ diff --git a/Marlin/src/HAL/SAMD51/HAL.cpp b/Marlin/src/HAL/SAMD51/HAL.cpp index 8c102b643d..a3c871ce51 100644 --- a/Marlin/src/HAL/SAMD51/HAL.cpp +++ b/Marlin/src/HAL/SAMD51/HAL.cpp @@ -47,24 +47,27 @@ #endif #endif -#define GET_TEMP_0_ADC() TERN(HAS_TEMP_ADC_0, PIN_TO_ADC(TEMP_0_PIN), -1) -#define GET_TEMP_1_ADC() TERN(HAS_TEMP_ADC_1, PIN_TO_ADC(TEMP_1_PIN), -1) -#define GET_TEMP_2_ADC() TERN(HAS_TEMP_ADC_2, PIN_TO_ADC(TEMP_2_PIN), -1) -#define GET_TEMP_3_ADC() TERN(HAS_TEMP_ADC_3, PIN_TO_ADC(TEMP_3_PIN), -1) -#define GET_TEMP_4_ADC() TERN(HAS_TEMP_ADC_4, PIN_TO_ADC(TEMP_4_PIN), -1) -#define GET_TEMP_5_ADC() TERN(HAS_TEMP_ADC_5, PIN_TO_ADC(TEMP_5_PIN), -1) -#define GET_TEMP_6_ADC() TERN(HAS_TEMP_ADC_6, PIN_TO_ADC(TEMP_6_PIN), -1) -#define GET_TEMP_7_ADC() TERN(HAS_TEMP_ADC_7, PIN_TO_ADC(TEMP_7_PIN), -1) -#define GET_BED_ADC() TERN(HAS_TEMP_ADC_BED, PIN_TO_ADC(TEMP_BED_PIN), -1) -#define GET_CHAMBER_ADC() TERN(HAS_TEMP_ADC_CHAMBER, PIN_TO_ADC(TEMP_CHAMBER_PIN), -1) -#define GET_PROBE_ADC() TERN(HAS_TEMP_ADC_PROBE, PIN_TO_ADC(TEMP_PROBE_PIN), -1) -#define GET_COOLER_ADC() TERN(HAS_TEMP_ADC_COOLER, PIN_TO_ADC(TEMP_COOLER_PIN), -1) -#define GET_BOARD_ADC() TERN(HAS_TEMP_ADC_BOARD, PIN_TO_ADC(TEMP_BOARD_PIN), -1) -#define GET_FILAMENT_WIDTH_ADC() TERN(FILAMENT_WIDTH_SENSOR, PIN_TO_ADC(FILWIDTH_PIN), -1) -#define GET_BUTTONS_ADC() TERN(HAS_ADC_BUTTONS, PIN_TO_ADC(ADC_KEYPAD_PIN), -1) -#define GET_JOY_ADC_X() TERN(HAS_JOY_ADC_X, PIN_TO_ADC(JOY_X_PIN), -1) -#define GET_JOY_ADC_Y() TERN(HAS_JOY_ADC_Y, PIN_TO_ADC(JOY_Y_PIN), -1) -#define GET_JOY_ADC_Z() TERN(HAS_JOY_ADC_Z, PIN_TO_ADC(JOY_Z_PIN), -1) +#define GET_TEMP_0_ADC() TERN(HAS_TEMP_ADC_0, PIN_TO_ADC(TEMP_0_PIN), -1) +#define GET_TEMP_1_ADC() TERN(HAS_TEMP_ADC_1, PIN_TO_ADC(TEMP_1_PIN), -1) +#define GET_TEMP_2_ADC() TERN(HAS_TEMP_ADC_2, PIN_TO_ADC(TEMP_2_PIN), -1) +#define GET_TEMP_3_ADC() TERN(HAS_TEMP_ADC_3, PIN_TO_ADC(TEMP_3_PIN), -1) +#define GET_TEMP_4_ADC() TERN(HAS_TEMP_ADC_4, PIN_TO_ADC(TEMP_4_PIN), -1) +#define GET_TEMP_5_ADC() TERN(HAS_TEMP_ADC_5, PIN_TO_ADC(TEMP_5_PIN), -1) +#define GET_TEMP_6_ADC() TERN(HAS_TEMP_ADC_6, PIN_TO_ADC(TEMP_6_PIN), -1) +#define GET_TEMP_7_ADC() TERN(HAS_TEMP_ADC_7, PIN_TO_ADC(TEMP_7_PIN), -1) +#define GET_BED_ADC() TERN(HAS_TEMP_ADC_BED, PIN_TO_ADC(TEMP_BED_PIN), -1) +#define GET_CHAMBER_ADC() TERN(HAS_TEMP_ADC_CHAMBER, PIN_TO_ADC(TEMP_CHAMBER_PIN), -1) +#define GET_PROBE_ADC() TERN(HAS_TEMP_ADC_PROBE, PIN_TO_ADC(TEMP_PROBE_PIN), -1) +#define GET_COOLER_ADC() TERN(HAS_TEMP_ADC_COOLER, PIN_TO_ADC(TEMP_COOLER_PIN), -1) +#define GET_BOARD_ADC() TERN(HAS_TEMP_ADC_BOARD, PIN_TO_ADC(TEMP_BOARD_PIN), -1) +#define GET_SOC_ADC() TERN(HAS_TEMP_ADC_BOARD, PIN_TO_ADC(TEMP_BOARD_PIN), -1) +#define GET_FILAMENT_WIDTH_ADC() TERN(FILAMENT_WIDTH_SENSOR, PIN_TO_ADC(FILWIDTH_PIN), -1) +#define GET_BUTTONS_ADC() TERN(HAS_ADC_BUTTONS, PIN_TO_ADC(ADC_KEYPAD_PIN), -1) +#define GET_JOY_ADC_X() TERN(HAS_JOY_ADC_X, PIN_TO_ADC(JOY_X_PIN), -1) +#define GET_JOY_ADC_Y() TERN(HAS_JOY_ADC_Y, PIN_TO_ADC(JOY_Y_PIN), -1) +#define GET_JOY_ADC_Z() TERN(HAS_JOY_ADC_Z, PIN_TO_ADC(JOY_Z_PIN), -1) +#define GET_POWERMON_ADC_CURRENT() TERN(POWER_MONITOR_CURRENT, PIN_TO_ADC(POWER_MONITOR_CURRENT_PIN), -1) +#define GET_POWERMON_ADC_VOLTS() TERN(POWER_MONITOR_VOLTAGE, PIN_TO_ADC(POWER_MONITOR_VOLTAGE_PIN), -1) #define IS_ADC_REQUIRED(n) ( \ GET_TEMP_0_ADC() == n || GET_TEMP_1_ADC() == n || GET_TEMP_2_ADC() == n || GET_TEMP_3_ADC() == n \ @@ -73,10 +76,11 @@ || GET_CHAMBER_ADC() == n \ || GET_PROBE_ADC() == n \ || GET_COOLER_ADC() == n \ - || GET_BOARD_ADC() == n \ + || GET_BOARD_ADC() == n || GET_SOC_ADC() == n \ || GET_FILAMENT_WIDTH_ADC() == n \ || GET_BUTTONS_ADC() == n \ || GET_JOY_ADC_X() == n || GET_JOY_ADC_Y() == n || GET_JOY_ADC_Z() == n \ + || GET_POWERMON_ADC_CURRENT() == n || GET_POWERMON_ADC_VOLTS() == n \ ) #if IS_ADC_REQUIRED(0) @@ -136,6 +140,9 @@ enum ADCIndex { #if GET_BOARD_ADC() == 0 TEMP_BOARD, #endif + #if GET_SOC_ADC() == 0 + TEMP_SOC, + #endif #if GET_FILAMENT_WIDTH_ADC() == 0 FILWIDTH, #endif @@ -151,6 +158,15 @@ enum ADCIndex { #if GET_JOY_ADC_Z() == 0 JOY_Z, #endif + #if GET_POWERMON_ADC_CURRENT() == 0 + POWERMON_CURRENT, + #endif + #if GET_POWERMON_ADC_VOLTS() == 0 + POWERMON_VOLTAGE, + #endif + + // Indexes for ADC1 after those for ADC0 + #if GET_TEMP_0_ADC() == 1 TEMP_0, #endif @@ -190,6 +206,9 @@ enum ADCIndex { #if GET_BOARD_ADC() == 1 TEMP_BOARD, #endif + #if GET_SOC_ADC() == 1 + TEMP_SOC, + #endif #if GET_FILAMENT_WIDTH_ADC() == 1 FILWIDTH, #endif @@ -205,6 +224,12 @@ enum ADCIndex { #if GET_JOY_ADC_Z() == 1 JOY_Z, #endif + #if GET_POWERMON_ADC_CURRENT() == 1 + POWERMON_CURRENT, + #endif + #if GET_POWERMON_ADC_VOLTS() == 1 + POWERMON_VOLTAGE, + #endif ADC_COUNT }; @@ -303,6 +328,9 @@ enum ADCIndex { #if GET_BOARD_ADC() == 0 TEMP_BOARD_PIN, #endif + #if GET_SOC_ADC() == 0 + TEMP_SOC_PIN, + #endif #if GET_FILAMENT_WIDTH_ADC() == 0 FILWIDTH_PIN, #endif @@ -318,7 +346,15 @@ enum ADCIndex { #if GET_JOY_ADC_Z() == 0 JOY_Z_PIN, #endif - // ADC1 pins + #if GET_POWERMON_ADC_CURRENT() == 0 + POWER_MONITOR_CURRENT_PIN, + #endif + #if GET_POWERMON_ADC_VOLTS() == 0 + POWER_MONITOR_VOLTAGE_PIN, + #endif + + // Pins for ADC1 after ADC0 + #if GET_TEMP_0_ADC() == 1 TEMP_0_PIN, #endif @@ -358,6 +394,9 @@ enum ADCIndex { #if GET_BOARD_ADC() == 1 TEMP_BOARD_PIN, #endif + #if GET_SOC_ADC() == 1 + TEMP_SOC_PIN, + #endif #if GET_FILAMENT_WIDTH_ADC() == 1 FILWIDTH_PIN, #endif @@ -373,6 +412,12 @@ enum ADCIndex { #if GET_JOY_ADC_Z() == 1 JOY_Z_PIN, #endif + #if GET_POWERMON_ADC_CURRENT() == 1 + POWER_MONITOR_CURRENT_PIN, + #endif + #if GET_POWERMON_ADC_VOLTS() == 1 + POWER_MONITOR_VOLTAGE_PIN, + #endif }; static uint16_t adc_results[ADC_COUNT]; @@ -420,6 +465,9 @@ enum ADCIndex { #if GET_BOARD_ADC() == 0 { PIN_TO_INPUTCTRL(TEMP_BOARD_PIN) }, #endif + #if GET_SOC_ADC() == 0 + { PIN_TO_INPUTCTRL(TEMP_SOC_PIN) }, + #endif #if GET_FILAMENT_WIDTH_ADC() == 0 { PIN_TO_INPUTCTRL(FILWIDTH_PIN) }, #endif @@ -435,6 +483,12 @@ enum ADCIndex { #if GET_JOY_ADC_Z() == 0 { PIN_TO_INPUTCTRL(JOY_Z_PIN) }, #endif + #if GET_POWERMON_ADC_CURRENT() == 0 + { PIN_TO_INPUTCTRL(POWER_MONITOR_CURRENT_PIN) }, + #endif + #if GET_POWERMON_ADC_VOLTS() == 0 + { PIN_TO_INPUTCTRL(POWER_MONITOR_VOLTAGE_PIN) }, + #endif }; #define ADC0_AINCOUNT COUNT(adc0_dma_regs_list) @@ -483,6 +537,9 @@ enum ADCIndex { #if GET_BOARD_ADC() == 1 { PIN_TO_INPUTCTRL(TEMP_BOARD_PIN) }, #endif + #if GET_SOC_ADC() == 1 + { PIN_TO_INPUTCTRL(TEMP_SOC_PIN) }, + #endif #if GET_FILAMENT_WIDTH_ADC() == 1 { PIN_TO_INPUTCTRL(FILWIDTH_PIN) }, #endif @@ -498,6 +555,12 @@ enum ADCIndex { #if GET_JOY_ADC_Z() == 1 { PIN_TO_INPUTCTRL(JOY_Z_PIN) }, #endif + #if GET_POWERMON_ADC_CURRENT() == 1 + { PIN_TO_INPUTCTRL(POWER_MONITOR_CURRENT_PIN) }, + #endif + #if GET_POWERMON_ADC_VOLTS() == 1 + { PIN_TO_INPUTCTRL(POWER_MONITOR_VOLTAGE_PIN) }, + #endif }; #define ADC1_AINCOUNT COUNT(adc1_dma_regs_list) @@ -602,7 +665,7 @@ void MarlinHAL::dma_init() { // HAL initialization task void MarlinHAL::init() { TERN_(DMA_IS_REQUIRED, dma_init()); - #if ENABLED(SDSUPPORT) + #if HAS_MEDIA #if HAS_SD_DETECT && SD_CONNECTION_IS(ONBOARD) SET_INPUT_PULLUP(SD_DETECT_PIN); #endif @@ -650,10 +713,10 @@ void MarlinHAL::adc_init() { #if ADC_IS_REQUIRED memset(adc_results, 0xFF, sizeof(adc_results)); // Fill result with invalid values - LOOP_L_N(pi, COUNT(adc_pins)) + for (uint8_t pi = 0; pi < COUNT(adc_pins); ++pi) pinPeripheral(adc_pins[pi], PIO_ANALOG); - LOOP_S_LE_N(ai, FIRST_ADC, LAST_ADC) { + for (uint8_t ai = FIRST_ADC; ai <= LAST_ADC; ++ai) { Adc* adc = ((Adc*[])ADC_INSTS)[ai]; // ADC clock setup @@ -685,7 +748,7 @@ void MarlinHAL::adc_init() { void MarlinHAL::adc_start(const pin_t pin) { #if ADC_IS_REQUIRED - LOOP_L_N(pi, COUNT(adc_pins)) + for (uint8_t pi = 0; pi < COUNT(adc_pins); ++pi) if (pin == adc_pins[pi]) { adc_result = adc_results[pi]; return; } #endif diff --git a/Marlin/src/HAL/SAMD51/HAL.h b/Marlin/src/HAL/SAMD51/HAL.h index fe29d6c7f4..c96401fd97 100644 --- a/Marlin/src/HAL/SAMD51/HAL.h +++ b/Marlin/src/HAL/SAMD51/HAL.h @@ -112,7 +112,7 @@ typedef Servo hal_servo_t; // //#define HAL_ADC_FILTERED // Disable Marlin's oversampling. The HAL filters ADC values. -#define HAL_ADC_VREF 3.3 +#define HAL_ADC_VREF_MV 3300 #define HAL_ADC_RESOLUTION 10 // ... 12 // diff --git a/Marlin/src/HAL/SAMD51/HAL_SPI.cpp b/Marlin/src/HAL/SAMD51/HAL_SPI.cpp index 58fdfe9499..63d3971965 100644 --- a/Marlin/src/HAL/SAMD51/HAL_SPI.cpp +++ b/Marlin/src/HAL/SAMD51/HAL_SPI.cpp @@ -44,7 +44,7 @@ // Public functions // -------------------------------------------------------------------------- -#if EITHER(SOFTWARE_SPI, FORCE_SOFT_SPI) +#if ANY(SOFTWARE_SPI, FORCE_SOFT_SPI) // ------------------------ // Software SPI diff --git a/Marlin/src/HAL/SAMD51/endstop_interrupts.h b/Marlin/src/HAL/SAMD51/endstop_interrupts.h index e0e811c3a0..84b6c46da9 100644 --- a/Marlin/src/HAL/SAMD51/endstop_interrupts.h +++ b/Marlin/src/HAL/SAMD51/endstop_interrupts.h @@ -53,31 +53,35 @@ #include "../../module/endstops.h" #define MATCH_EILINE(P1,P2) (P1 != P2 && PIN_TO_EILINE(P1) == PIN_TO_EILINE(P2)) -#define MATCH_X_MAX_EILINE(P) TERN0(HAS_X_MAX, DEFER4(MATCH_EILINE)(P, X_MAX_PIN)) -#define MATCH_X_MIN_EILINE(P) TERN0(HAS_X_MIN, DEFER4(MATCH_EILINE)(P, X_MIN_PIN)) -#define MATCH_Y_MAX_EILINE(P) TERN0(HAS_Y_MAX, DEFER4(MATCH_EILINE)(P, Y_MAX_PIN)) -#define MATCH_Y_MIN_EILINE(P) TERN0(HAS_Y_MIN, DEFER4(MATCH_EILINE)(P, Y_MIN_PIN)) -#define MATCH_Z_MAX_EILINE(P) TERN0(HAS_Z_MAX, DEFER4(MATCH_EILINE)(P, Z_MAX_PIN)) -#define MATCH_Z_MIN_EILINE(P) TERN0(HAS_Z_MIN, DEFER4(MATCH_EILINE)(P, Z_MIN_PIN)) -#define MATCH_I_MAX_EILINE(P) TERN0(HAS_I_MAX, DEFER4(MATCH_EILINE)(P, I_MAX_PIN)) -#define MATCH_I_MIN_EILINE(P) TERN0(HAS_I_MIN, DEFER4(MATCH_EILINE)(P, I_MIN_PIN)) -#define MATCH_J_MAX_EILINE(P) TERN0(HAS_J_MAX, DEFER4(MATCH_EILINE)(P, J_MAX_PIN)) -#define MATCH_J_MIN_EILINE(P) TERN0(HAS_J_MIN, DEFER4(MATCH_EILINE)(P, J_MIN_PIN)) -#define MATCH_K_MAX_EILINE(P) TERN0(HAS_K_MAX, DEFER4(MATCH_EILINE)(P, K_MAX_PIN)) -#define MATCH_K_MIN_EILINE(P) TERN0(HAS_K_MIN, DEFER4(MATCH_EILINE)(P, K_MIN_PIN)) -#define MATCH_U_MAX_EILINE(P) TERN0(HAS_U_MAX, DEFER4(MATCH_EILINE)(P, U_MAX_PIN)) -#define MATCH_U_MIN_EILINE(P) TERN0(HAS_U_MIN, DEFER4(MATCH_EILINE)(P, U_MIN_PIN)) -#define MATCH_V_MAX_EILINE(P) TERN0(HAS_V_MAX, DEFER4(MATCH_EILINE)(P, V_MAX_PIN)) -#define MATCH_V_MIN_EILINE(P) TERN0(HAS_V_MIN, DEFER4(MATCH_EILINE)(P, V_MIN_PIN)) -#define MATCH_W_MAX_EILINE(P) TERN0(HAS_W_MAX, DEFER4(MATCH_EILINE)(P, W_MAX_PIN)) -#define MATCH_W_MIN_EILINE(P) TERN0(HAS_W_MIN, DEFER4(MATCH_EILINE)(P, W_MIN_PIN)) -#define MATCH_Z2_MAX_EILINE(P) TERN0(HAS_Z2_MAX, DEFER4(MATCH_EILINE)(P, Z2_MAX_PIN)) -#define MATCH_Z2_MIN_EILINE(P) TERN0(HAS_Z2_MIN, DEFER4(MATCH_EILINE)(P, Z2_MIN_PIN)) -#define MATCH_Z3_MAX_EILINE(P) TERN0(HAS_Z3_MAX, DEFER4(MATCH_EILINE)(P, Z3_MAX_PIN)) -#define MATCH_Z3_MIN_EILINE(P) TERN0(HAS_Z3_MIN, DEFER4(MATCH_EILINE)(P, Z3_MIN_PIN)) -#define MATCH_Z4_MAX_EILINE(P) TERN0(HAS_Z4_MAX, DEFER4(MATCH_EILINE)(P, Z4_MAX_PIN)) -#define MATCH_Z4_MIN_EILINE(P) TERN0(HAS_Z4_MIN, DEFER4(MATCH_EILINE)(P, Z4_MIN_PIN)) -#define MATCH_Z_MIN_PROBE_EILINE(P) TERN0(HAS_Z_MIN_PROBE_PIN, DEFER4(MATCH_EILINE)(P, Z_MIN_PROBE_PIN)) +#define MATCH_X_MAX_EILINE(P) TERN0(USE_X_MAX, DEFER4(MATCH_EILINE)(P, X_MAX_PIN)) +#define MATCH_X_MIN_EILINE(P) TERN0(USE_X_MIN, DEFER4(MATCH_EILINE)(P, X_MIN_PIN)) +#define MATCH_Y_MAX_EILINE(P) TERN0(USE_Y_MAX, DEFER4(MATCH_EILINE)(P, Y_MAX_PIN)) +#define MATCH_Y_MIN_EILINE(P) TERN0(USE_Y_MIN, DEFER4(MATCH_EILINE)(P, Y_MIN_PIN)) +#define MATCH_Z_MAX_EILINE(P) TERN0(USE_Z_MAX, DEFER4(MATCH_EILINE)(P, Z_MAX_PIN)) +#define MATCH_Z_MIN_EILINE(P) TERN0(USE_Z_MIN, DEFER4(MATCH_EILINE)(P, Z_MIN_PIN)) +#define MATCH_I_MAX_EILINE(P) TERN0(USE_I_MAX, DEFER4(MATCH_EILINE)(P, I_MAX_PIN)) +#define MATCH_I_MIN_EILINE(P) TERN0(USE_I_MIN, DEFER4(MATCH_EILINE)(P, I_MIN_PIN)) +#define MATCH_J_MAX_EILINE(P) TERN0(USE_J_MAX, DEFER4(MATCH_EILINE)(P, J_MAX_PIN)) +#define MATCH_J_MIN_EILINE(P) TERN0(USE_J_MIN, DEFER4(MATCH_EILINE)(P, J_MIN_PIN)) +#define MATCH_K_MAX_EILINE(P) TERN0(USE_K_MAX, DEFER4(MATCH_EILINE)(P, K_MAX_PIN)) +#define MATCH_K_MIN_EILINE(P) TERN0(USE_K_MIN, DEFER4(MATCH_EILINE)(P, K_MIN_PIN)) +#define MATCH_U_MAX_EILINE(P) TERN0(USE_U_MAX, DEFER4(MATCH_EILINE)(P, U_MAX_PIN)) +#define MATCH_U_MIN_EILINE(P) TERN0(USE_U_MIN, DEFER4(MATCH_EILINE)(P, U_MIN_PIN)) +#define MATCH_V_MAX_EILINE(P) TERN0(USE_V_MAX, DEFER4(MATCH_EILINE)(P, V_MAX_PIN)) +#define MATCH_V_MIN_EILINE(P) TERN0(USE_V_MIN, DEFER4(MATCH_EILINE)(P, V_MIN_PIN)) +#define MATCH_W_MAX_EILINE(P) TERN0(USE_W_MAX, DEFER4(MATCH_EILINE)(P, W_MAX_PIN)) +#define MATCH_W_MIN_EILINE(P) TERN0(USE_W_MIN, DEFER4(MATCH_EILINE)(P, W_MIN_PIN)) +#define MATCH_X2_MAX_EILINE(P) TERN0(USE_X2_MAX, DEFER4(MATCH_EILINE)(P, X2_MAX_PIN)) +#define MATCH_X2_MIN_EILINE(P) TERN0(USE_X2_MIN, DEFER4(MATCH_EILINE)(P, X2_MIN_PIN)) +#define MATCH_Y2_MAX_EILINE(P) TERN0(USE_Y2_MAX, DEFER4(MATCH_EILINE)(P, Y2_MAX_PIN)) +#define MATCH_Y2_MIN_EILINE(P) TERN0(USE_Y2_MIN, DEFER4(MATCH_EILINE)(P, Y2_MIN_PIN)) +#define MATCH_Z2_MAX_EILINE(P) TERN0(USE_Z2_MAX, DEFER4(MATCH_EILINE)(P, Z2_MAX_PIN)) +#define MATCH_Z2_MIN_EILINE(P) TERN0(USE_Z2_MIN, DEFER4(MATCH_EILINE)(P, Z2_MIN_PIN)) +#define MATCH_Z3_MAX_EILINE(P) TERN0(USE_Z3_MAX, DEFER4(MATCH_EILINE)(P, Z3_MAX_PIN)) +#define MATCH_Z3_MIN_EILINE(P) TERN0(USE_Z3_MIN, DEFER4(MATCH_EILINE)(P, Z3_MIN_PIN)) +#define MATCH_Z4_MAX_EILINE(P) TERN0(USE_Z4_MAX, DEFER4(MATCH_EILINE)(P, Z4_MAX_PIN)) +#define MATCH_Z4_MIN_EILINE(P) TERN0(USE_Z4_MIN, DEFER4(MATCH_EILINE)(P, Z4_MIN_PIN)) +#define MATCH_Z_MIN_PROBE_EILINE(P) TERN0(USE_Z_MIN_PROBE, DEFER4(MATCH_EILINE)(P, Z_MIN_PROBE_PIN)) #define AVAILABLE_EILINE(P) ( PIN_TO_EILINE(P) != -1 \ && !MATCH_X_MAX_EILINE(P) && !MATCH_X_MIN_EILINE(P) \ @@ -89,6 +93,8 @@ && !MATCH_U_MAX_EILINE(P) && !MATCH_U_MIN_EILINE(P) \ && !MATCH_V_MAX_EILINE(P) && !MATCH_V_MIN_EILINE(P) \ && !MATCH_W_MAX_EILINE(P) && !MATCH_W_MIN_EILINE(P) \ + && !MATCH_X2_MAX_EILINE(P) && !MATCH_X2_MIN_EILINE(P) \ + && !MATCH_Y2_MAX_EILINE(P) && !MATCH_Y2_MIN_EILINE(P) \ && !MATCH_Z2_MAX_EILINE(P) && !MATCH_Z2_MIN_EILINE(P) \ && !MATCH_Z3_MAX_EILINE(P) && !MATCH_Z3_MIN_EILINE(P) \ && !MATCH_Z4_MAX_EILINE(P) && !MATCH_Z4_MIN_EILINE(P) \ @@ -99,153 +105,153 @@ void endstop_ISR() { endstops.update(); } void setup_endstop_interrupts() { #define _ATTACH(P) attachInterrupt(P, endstop_ISR, CHANGE) - #if HAS_X_MAX + #if USE_X_MAX #if !AVAILABLE_EILINE(X_MAX_PIN) - #error "X_MAX_PIN has no EXTINT line available." + #error "X_MAX_PIN has no EXTINT line available. Disable ENDSTOP_INTERRUPTS_FEATURE to continue." #endif _ATTACH(X_MAX_PIN); #endif - #if HAS_X_MIN + #if USE_X_MIN #if !AVAILABLE_EILINE(X_MIN_PIN) - #error "X_MIN_PIN has no EXTINT line available." + #error "X_MIN_PIN has no EXTINT line available. Disable ENDSTOP_INTERRUPTS_FEATURE to continue." #endif _ATTACH(X_MIN_PIN); #endif - #if HAS_Y_MAX + #if USE_Y_MAX #if !AVAILABLE_EILINE(Y_MAX_PIN) - #error "Y_MAX_PIN has no EXTINT line available." + #error "Y_MAX_PIN has no EXTINT line available. Disable ENDSTOP_INTERRUPTS_FEATURE to continue." #endif _ATTACH(Y_MAX_PIN); #endif - #if HAS_Y_MIN + #if USE_Y_MIN #if !AVAILABLE_EILINE(Y_MIN_PIN) - #error "Y_MIN_PIN has no EXTINT line available." + #error "Y_MIN_PIN has no EXTINT line available. Disable ENDSTOP_INTERRUPTS_FEATURE to continue." #endif _ATTACH(Y_MIN_PIN); #endif - #if HAS_Z_MAX + #if USE_Z_MAX #if !AVAILABLE_EILINE(Z_MAX_PIN) - #error "Z_MAX_PIN has no EXTINT line available." + #error "Z_MAX_PIN has no EXTINT line available. Disable ENDSTOP_INTERRUPTS_FEATURE to continue." #endif _ATTACH(Z_MAX_PIN); #endif - #if HAS_Z_MIN + #if USE_Z_MIN #if !AVAILABLE_EILINE(Z_MIN_PIN) - #error "Z_MIN_PIN has no EXTINT line available." + #error "Z_MIN_PIN has no EXTINT line available. Disable ENDSTOP_INTERRUPTS_FEATURE to continue." #endif _ATTACH(Z_MIN_PIN); #endif - #if HAS_Z2_MAX + #if USE_Z2_MAX #if !AVAILABLE_EILINE(Z2_MAX_PIN) - #error "Z2_MAX_PIN has no EXTINT line available." + #error "Z2_MAX_PIN has no EXTINT line available. Disable ENDSTOP_INTERRUPTS_FEATURE to continue." #endif _ATTACH(Z2_MAX_PIN); #endif - #if HAS_Z2_MIN + #if USE_Z2_MIN #if !AVAILABLE_EILINE(Z2_MIN_PIN) - #error "Z2_MIN_PIN has no EXTINT line available." + #error "Z2_MIN_PIN has no EXTINT line available. Disable ENDSTOP_INTERRUPTS_FEATURE to continue." #endif _ATTACH(Z2_MIN_PIN); #endif - #if HAS_Z3_MAX + #if USE_Z3_MAX #if !AVAILABLE_EILINE(Z3_MAX_PIN) - #error "Z3_MAX_PIN has no EXTINT line available." + #error "Z3_MAX_PIN has no EXTINT line available. Disable ENDSTOP_INTERRUPTS_FEATURE to continue." #endif _ATTACH(Z3_MAX_PIN); #endif - #if HAS_Z3_MIN + #if USE_Z3_MIN #if !AVAILABLE_EILINE(Z3_MIN_PIN) - #error "Z3_MIN_PIN has no EXTINT line available." + #error "Z3_MIN_PIN has no EXTINT line available. Disable ENDSTOP_INTERRUPTS_FEATURE to continue." #endif _ATTACH(Z3_MIN_PIN); #endif - #if HAS_Z4_MAX + #if USE_Z4_MAX #if !AVAILABLE_EILINE(Z4_MAX_PIN) - #error "Z4_MAX_PIN has no EXTINT line available." + #error "Z4_MAX_PIN has no EXTINT line available. Disable ENDSTOP_INTERRUPTS_FEATURE to continue." #endif _ATTACH(Z4_MAX_PIN); #endif - #if HAS_Z4_MIN + #if USE_Z4_MIN #if !AVAILABLE_EILINE(Z4_MIN_PIN) - #error "Z4_MIN_PIN has no EXTINT line available." + #error "Z4_MIN_PIN has no EXTINT line available. Disable ENDSTOP_INTERRUPTS_FEATURE to continue." #endif _ATTACH(Z4_MIN_PIN); #endif - #if HAS_Z_MIN_PROBE_PIN + #if USE_Z_MIN_PROBE #if !AVAILABLE_EILINE(Z_MIN_PROBE_PIN) - #error "Z_MIN_PROBE_PIN has no EXTINT line available." + #error "Z_MIN_PROBE_PIN has no EXTINT line available. Disable ENDSTOP_INTERRUPTS_FEATURE to continue." #endif _ATTACH(Z_MIN_PROBE_PIN); #endif - #if HAS_I_MAX + #if USE_I_MAX #if !AVAILABLE_EILINE(I_MAX_PIN) - #error "I_MAX_PIN has no EXTINT line available." + #error "I_MAX_PIN has no EXTINT line available. Disable ENDSTOP_INTERRUPTS_FEATURE to continue." #endif attachInterrupt(I_MAX_PIN, endstop_ISR, CHANGE); #endif - #if HAS_I_MIN + #if USE_I_MIN #if !AVAILABLE_EILINE(I_MIN_PIN) - #error "I_MIN_PIN has no EXTINT line available." + #error "I_MIN_PIN has no EXTINT line available. Disable ENDSTOP_INTERRUPTS_FEATURE to continue." #endif attachInterrupt(I_MIN_PIN, endstop_ISR, CHANGE); #endif - #if HAS_J_MAX + #if USE_J_MAX #if !AVAILABLE_EILINE(J_MAX_PIN) - #error "J_MAX_PIN has no EXTINT line available." + #error "J_MAX_PIN has no EXTINT line available. Disable ENDSTOP_INTERRUPTS_FEATURE to continue." #endif attachInterrupt(J_MAX_PIN, endstop_ISR, CHANGE); #endif - #if HAS_J_MIN + #if USE_J_MIN #if !AVAILABLE_EILINE(J_MIN_PIN) - #error "J_MIN_PIN has no EXTINT line available." + #error "J_MIN_PIN has no EXTINT line available. Disable ENDSTOP_INTERRUPTS_FEATURE to continue." #endif attachInterrupt(J_MIN_PIN, endstop_ISR, CHANGE); #endif - #if HAS_K_MAX + #if USE_K_MAX #if !AVAILABLE_EILINE(K_MAX_PIN) - #error "K_MAX_PIN has no EXTINT line available." + #error "K_MAX_PIN has no EXTINT line available. Disable ENDSTOP_INTERRUPTS_FEATURE to continue." #endif attachInterrupt(K_MAX_PIN, endstop_ISR, CHANGE); #endif - #if HAS_K_MIN + #if USE_K_MIN #if !AVAILABLE_EILINE(K_MIN_PIN) - #error "K_MIN_PIN has no EXTINT line available." + #error "K_MIN_PIN has no EXTINT line available. Disable ENDSTOP_INTERRUPTS_FEATURE to continue." #endif attachInterrupt(K_MIN_PIN, endstop_ISR, CHANGE); #endif - #if HAS_U_MAX + #if USE_U_MAX #if !AVAILABLE_EILINE(U_MAX_PIN) - #error "U_MAX_PIN has no EXTINT line available." + #error "U_MAX_PIN has no EXTINT line available. Disable ENDSTOP_INTERRUPTS_FEATURE to continue." #endif attachInterrupt(U_MAX_PIN, endstop_ISR, CHANGE); #endif - #if HAS_U_MIN + #if USE_U_MIN #if !AVAILABLE_EILINE(U_MIN_PIN) - #error "U_MIN_PIN has no EXTINT line available." + #error "U_MIN_PIN has no EXTINT line available. Disable ENDSTOP_INTERRUPTS_FEATURE to continue." #endif attachInterrupt(U_MIN_PIN, endstop_ISR, CHANGE); #endif - #if HAS_V_MAX + #if USE_V_MAX #if !AVAILABLE_EILINE(V_MAX_PIN) - #error "V_MAX_PIN has no EXTINT line available." + #error "V_MAX_PIN has no EXTINT line available. Disable ENDSTOP_INTERRUPTS_FEATURE to continue." #endif attachInterrupt(V_MAX_PIN, endstop_ISR, CHANGE); #endif - #if HAS_V_MIN + #if USE_V_MIN #if !AVAILABLE_EILINE(V_MIN_PIN) - #error "V_MIN_PIN has no EXTINT line available." + #error "V_MIN_PIN has no EXTINT line available. Disable ENDSTOP_INTERRUPTS_FEATURE to continue." #endif attachInterrupt(V_MIN_PIN, endstop_ISR, CHANGE); #endif - #if HAS_W_MAX + #if USE_W_MAX #if !AVAILABLE_EILINE(W_MAX_PIN) - #error "W_MAX_PIN has no EXTINT line available." + #error "W_MAX_PIN has no EXTINT line available. Disable ENDSTOP_INTERRUPTS_FEATURE to continue." #endif attachInterrupt(W_MAX_PIN, endstop_ISR, CHANGE); #endif - #if HAS_W_MIN + #if USE_W_MIN #if !AVAILABLE_EILINE(W_MIN_PIN) - #error "W_MIN_PIN has no EXTINT line available." + #error "W_MIN_PIN has no EXTINT line available. Disable ENDSTOP_INTERRUPTS_FEATURE to continue." #endif attachInterrupt(W_MIN_PIN, endstop_ISR, CHANGE); #endif diff --git a/Marlin/src/HAL/SAMD51/fastio.h b/Marlin/src/HAL/SAMD51/fastio.h index 0acf481317..3d43bdb24d 100644 --- a/Marlin/src/HAL/SAMD51/fastio.h +++ b/Marlin/src/HAL/SAMD51/fastio.h @@ -130,7 +130,7 @@ #ifdef ADAFRUIT_GRAND_CENTRAL_M4 - /* + /** * Adafruit Grand Central M4 has a lot of PWMs the availables are listed here. * Some of these share the same source and so can't be used in the same time */ @@ -176,7 +176,7 @@ #define digitalPinToAnalogInput(P) (WITHIN(P, 67, 74) ? (P) - 67 : WITHIN(P, 54, 61) ? 8 + (P) - 54 : WITHIN(P, 12, 13) ? 16 + (P) - 12 : P == 9 ? 18 : -1) - /* + /** * pins */ diff --git a/Marlin/src/HAL/SAMD51/inc/Conditionals_LCD.h b/Marlin/src/HAL/SAMD51/inc/Conditionals_LCD.h index 932348c52f..5f1c4b1601 100644 --- a/Marlin/src/HAL/SAMD51/inc/Conditionals_LCD.h +++ b/Marlin/src/HAL/SAMD51/inc/Conditionals_LCD.h @@ -20,7 +20,3 @@ * */ #pragma once - -#if HAS_SPI_TFT || HAS_FSMC_TFT - #error "Sorry! TFT displays are not available for HAL/SAMD51." -#endif diff --git a/Marlin/src/HAL/SAMD51/inc/Conditionals_post.h b/Marlin/src/HAL/SAMD51/inc/Conditionals_post.h index ce6d3fdde2..295596b78b 100644 --- a/Marlin/src/HAL/SAMD51/inc/Conditionals_post.h +++ b/Marlin/src/HAL/SAMD51/inc/Conditionals_post.h @@ -23,6 +23,6 @@ #if USE_FALLBACK_EEPROM #define FLASH_EEPROM_EMULATION -#elif EITHER(I2C_EEPROM, SPI_EEPROM) +#elif ANY(I2C_EEPROM, SPI_EEPROM) #define USE_SHARED_EEPROM 1 #endif diff --git a/Marlin/src/HAL/SAMD51/inc/SanityCheck.h b/Marlin/src/HAL/SAMD51/inc/SanityCheck.h index ae1bc2f3ef..4719ac6eb8 100644 --- a/Marlin/src/HAL/SAMD51/inc/SanityCheck.h +++ b/Marlin/src/HAL/SAMD51/inc/SanityCheck.h @@ -29,6 +29,10 @@ * Test SAMD51 specific configuration values for errors at compile-time. */ +#if HAS_SPI_TFT || HAS_FSMC_TFT + #error "Sorry! TFT displays are not available for HAL/SAMD51." +#endif + #if ENABLED(FLASH_EEPROM_EMULATION) #warning "Did you activate the SmartEEPROM? See https://github.com/GMagician/SAMD51-SmartEEprom-Manager/releases" #endif @@ -50,12 +54,12 @@ #error "EMERGENCY_PARSER is not yet implemented for SAMD51. Disable EMERGENCY_PARSER to continue." #endif -#if ENABLED(SDIO_SUPPORT) - #error "SDIO_SUPPORT is not supported on SAMD51." +#if ENABLED(ONBOARD_SDIO) + #error "ONBOARD_SDIO is not supported on SAMD51." #endif #if ENABLED(FAST_PWM_FAN) || SPINDLE_LASER_FREQUENCY - #error "Features requiring Hardware PWM (FAST_PWM_FAN, SPINDLE_LASER_FREQUENCY) are not yet supported on SAMD51." + #error "Features requiring Hardware PWM (FAST_PWM_FAN, SPINDLE_LASER_FREQUENCY) are not yet supported for HAL/SAMD51." #endif #if ENABLED(POSTMORTEM_DEBUGGING) diff --git a/Marlin/src/HAL/SAMD51/spi_pins.h b/Marlin/src/HAL/SAMD51/spi_pins.h index f1e4fd4302..2c7cbeb994 100644 --- a/Marlin/src/HAL/SAMD51/spi_pins.h +++ b/Marlin/src/HAL/SAMD51/spi_pins.h @@ -27,7 +27,7 @@ #ifdef ADAFRUIT_GRAND_CENTRAL_M4 - /* + /** * AGCM4 Default SPI Pins * * SS SCK MISO MOSI diff --git a/Marlin/src/HAL/SAMD51/u8g/LCD_defines.h b/Marlin/src/HAL/SAMD51/u8g/LCD_defines.h new file mode 100644 index 0000000000..658a2c0fc1 --- /dev/null +++ b/Marlin/src/HAL/SAMD51/u8g/LCD_defines.h @@ -0,0 +1,29 @@ +/** + * Marlin 3D Printer Firmware + * Copyright (c) 2023 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] + * + * Based on Sprinter and grbl. + * Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (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 + +/** + * SAMD51 LCD-specific defines + */ + +#define U8G_COM_HAL_HW_SPI_FN u8g_com_samd51_hw_spi_fn // See U8glib-HAL +#define U8G_COM_ST7920_HAL_HW_SPI u8g_com_samd51_st7920_hw_spi_fn // See U8glib-HAL diff --git a/Marlin/src/HAL/STM32/HAL.cpp b/Marlin/src/HAL/STM32/HAL.cpp index aff52f597f..610bd0b243 100644 --- a/Marlin/src/HAL/STM32/HAL.cpp +++ b/Marlin/src/HAL/STM32/HAL.cpp @@ -1,10 +1,9 @@ /** * Marlin 3D Printer Firmware - * * Copyright (c) 2020 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] - * Copyright (c) 2016 Bob Cousins bobcousins42@googlemail.com - * Copyright (c) 2015-2016 Nico Tonnhofer wurstnase.reprap@gmail.com - * Copyright (c) 2017 Victor Perez + * + * 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 @@ -70,7 +69,7 @@ void MarlinHAL::init() { constexpr int cpuFreq = F_CPU; UNUSED(cpuFreq); - #if ENABLED(SDSUPPORT) && DISABLED(SDIO_SUPPORT) && (defined(SDSS) && SDSS != -1) + #if HAS_MEDIA && DISABLED(ONBOARD_SDIO) && (defined(SDSS) && SDSS != -1) OUT_WRITE(SDSS, HIGH); // Try to set SDSS inactive before any other SPI users start up #endif diff --git a/Marlin/src/HAL/STM32/HAL.h b/Marlin/src/HAL/STM32/HAL.h index 3e85aca293..276f031685 100644 --- a/Marlin/src/HAL/STM32/HAL.h +++ b/Marlin/src/HAL/STM32/HAL.h @@ -1,10 +1,9 @@ /** * Marlin 3D Printer Firmware - * * Copyright (c) 2020 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] - * Copyright (c) 2016 Bob Cousins bobcousins42@googlemail.com - * Copyright (c) 2015-2016 Nico Tonnhofer wurstnase.reprap@gmail.com - * Copyright (c) 2017 Victor Perez + * + * 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 @@ -28,6 +27,7 @@ #include "../shared/Marduino.h" #include "../shared/math_32bit.h" #include "../shared/HAL_SPI.h" +#include "temp_soc.h" #include "fastio.h" #include "Servo.h" #include "MarlinSerial.h" @@ -56,64 +56,64 @@ #define _MSERIAL(X) MSerial##X #define MSERIAL(X) _MSERIAL(X) -#if WITHIN(SERIAL_PORT, 1, 6) +#if WITHIN(SERIAL_PORT, 1, 9) #define MYSERIAL1 MSERIAL(SERIAL_PORT) #elif !defined(USBCON) - #error "SERIAL_PORT must be from 1 to 6." + #error "SERIAL_PORT must be from 1 to 9." #elif SERIAL_PORT == -1 #define MYSERIAL1 MSerialUSB #else - #error "SERIAL_PORT must be from 1 to 6, or -1 for Native USB." + #error "SERIAL_PORT must be from 1 to 9, or -1 for Native USB." #endif #ifdef SERIAL_PORT_2 - #if WITHIN(SERIAL_PORT_2, 1, 6) + #if WITHIN(SERIAL_PORT_2, 1, 9) #define MYSERIAL2 MSERIAL(SERIAL_PORT_2) #elif !defined(USBCON) - #error "SERIAL_PORT must be from 1 to 6." + #error "SERIAL_PORT_2 must be from 1 to 9." #elif SERIAL_PORT_2 == -1 #define MYSERIAL2 MSerialUSB #else - #error "SERIAL_PORT_2 must be from 1 to 6, or -1 for Native USB." + #error "SERIAL_PORT_2 must be from 1 to 9, or -1 for Native USB." #endif #endif #ifdef SERIAL_PORT_3 - #if WITHIN(SERIAL_PORT_3, 1, 6) + #if WITHIN(SERIAL_PORT_3, 1, 9) #define MYSERIAL3 MSERIAL(SERIAL_PORT_3) #elif !defined(USBCON) - #error "SERIAL_PORT must be from 1 to 6." + #error "SERIAL_PORT_3 must be from 1 to 9." #elif SERIAL_PORT_3 == -1 #define MYSERIAL3 MSerialUSB #else - #error "SERIAL_PORT_3 must be from 1 to 6, or -1 for Native USB." + #error "SERIAL_PORT_3 must be from 1 to 9, or -1 for Native USB." #endif #endif #ifdef MMU2_SERIAL_PORT - #if WITHIN(MMU2_SERIAL_PORT, 1, 6) + #if WITHIN(MMU2_SERIAL_PORT, 1, 9) #define MMU2_SERIAL MSERIAL(MMU2_SERIAL_PORT) #elif !defined(USBCON) - #error "SERIAL_PORT must be from 1 to 6." + #error "MMU2_SERIAL_PORT must be from 1 to 9." #elif MMU2_SERIAL_PORT == -1 #define MMU2_SERIAL MSerialUSB #else - #error "MMU2_SERIAL_PORT must be from 1 to 6, or -1 for Native USB." + #error "MMU2_SERIAL_PORT must be from 1 to 9, or -1 for Native USB." #endif #endif #ifdef LCD_SERIAL_PORT - #if WITHIN(LCD_SERIAL_PORT, 1, 6) + #if WITHIN(LCD_SERIAL_PORT, 1, 9) #define LCD_SERIAL MSERIAL(LCD_SERIAL_PORT) #elif !defined(USBCON) - #error "SERIAL_PORT must be from 1 to 6." + #error "LCD_SERIAL_PORT must be from 1 to 9." #elif LCD_SERIAL_PORT == -1 #define LCD_SERIAL MSerialUSB #else - #error "LCD_SERIAL_PORT must be from 1 to 6, or -1 for Native USB." + #error "LCD_SERIAL_PORT must be from 1 to 9, or -1 for Native USB." #endif #if HAS_DGUS_LCD - #define SERIAL_GET_TX_BUFFER_FREE() LCD_SERIAL.availableForWrite() + #define LCD_SERIAL_TX_BUFFER_FREE() LCD_SERIAL.availableForWrite() #endif #endif @@ -138,11 +138,7 @@ typedef double isr_float_t; // FPU ops are used for single-precision, so use double for ISRs. -#ifdef STM32G0B1xx - typedef int32_t pin_t; -#else - typedef int16_t pin_t; -#endif +typedef int32_t pin_t; // Parity with platform/ststm32 class libServo; typedef libServo hal_servo_t; @@ -159,7 +155,7 @@ typedef libServo hal_servo_t; #define HAL_ADC_RESOLUTION 12 #endif -#define HAL_ADC_VREF 3.3 +#define HAL_ADC_VREF_MV 3300 // // Pin Mapping for M42, M43, M226 @@ -174,7 +170,9 @@ typedef libServo hal_servo_t; #define JTAGSWD_RESET() AFIO_DBGAFR_CONFIG(AFIO_MAPR_SWJ_CFG_RESET); // Reset: FULL SWD+JTAG #endif -#define PLATFORM_M997_SUPPORT +#ifndef PLATFORM_M997_SUPPORT + #define PLATFORM_M997_SUPPORT +#endif void flashFirmware(const int16_t); // Maple Compatibility diff --git a/Marlin/src/HAL/STM32/HAL_SPI.cpp b/Marlin/src/HAL/STM32/HAL_SPI.cpp index 40d320d5e8..cc035ecffa 100644 --- a/Marlin/src/HAL/STM32/HAL_SPI.cpp +++ b/Marlin/src/HAL/STM32/HAL_SPI.cpp @@ -4,7 +4,6 @@ * * Based on Sprinter and grbl. * Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm - * Copyright (c) 2017 Victor Perez * * 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 @@ -78,7 +77,6 @@ static SPISettings spiConfig; case SPI_SPEED_6: delaySPIFunc = &delaySPI_2000; break; // desired: 250,000 actual: ~210K default: delaySPIFunc = &delaySPI_4000; break; // desired: 125,000 actual: ~123K } - SPI.begin(); } // Begin SPI transaction, set clock, bit order, data mode diff --git a/Marlin/src/HAL/STM32/HardwareSerial.cpp b/Marlin/src/HAL/STM32/HardwareSerial.cpp new file mode 100644 index 0000000000..a6f97f356e --- /dev/null +++ b/Marlin/src/HAL/STM32/HardwareSerial.cpp @@ -0,0 +1,449 @@ +/** + * Marlin 3D Printer Firmware + * Copyright (c) 2023 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] + * + * Based on Sprinter and grbl. + * Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm + * Copyright (c) 2017 Victor Perez + * + * 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 . + * + */ + +// +// HAL_HardwareSerial Class. Adapted from Arduino HardwareSerial. +// + +#include "../platforms.h" + +#ifdef HAL_STM32 + +#include "../../inc/MarlinConfig.h" + +#if ENABLED(SERIAL_DMA) && defined(HAL_UART_MODULE_ENABLED) && !defined(HAL_UART_MODULE_ONLY) + +#include +#include "HardwareSerial.h" +#include "uart.h" + +// USART/UART PIN MAPPING FOR STM32F0/F1/F2/F4/F7 +#ifndef PIN_SERIAL1_TX + #define PIN_SERIAL1_TX PA9 +#endif +#ifndef PIN_SERIAL1_RX + #define PIN_SERIAL1_RX PA10 +#endif +#ifndef PIN_SERIAL2_TX + #define PIN_SERIAL2_TX PA2 +#endif +#ifndef PIN_SERIAL2_RX + #define PIN_SERIAL2_RX PA3 +#endif +#ifndef PIN_SERIAL3_TX + #define PIN_SERIAL3_TX PB10 +#endif +#ifndef PIN_SERIAL3_RX + #define PIN_SERIAL3_RX PB11 +#endif +#ifndef PIN_SERIAL4_TX + #define PIN_SERIAL4_TX PC10 +#endif +#ifndef PIN_SERIAL4_RX + #define PIN_SERIAL4_RX PC11 +#endif +#ifndef PIN_SERIAL5_TX + #define PIN_SERIAL5_TX PC12 +#endif +#ifndef PIN_SERIAL5_RX + #define PIN_SERIAL5_RX PD2 +#endif +#ifndef PIN_SERIAL6_TX + #define PIN_SERIAL6_TX PC6 +#endif +#ifndef PIN_SERIAL6_RX + #define PIN_SERIAL6_RX PC7 +#endif + +// TODO: Get from include file + +#if ANY(STM32F2xx, STM32F4xx, STM32F7xx) + + #define RCC_AHB1Periph_DMA1 ((uint32_t)0x00200000) + #define RCC_AHB1Periph_DMA2 ((uint32_t)0x00400000) + + void RCC_AHB1PeriphClockCmd(uint32_t RCC_AHB1Periph, FunctionalState NewState) { + // Check the parameters + assert_param(IS_RCC_AHB1_CLOCK_PERIPH(RCC_AHB1Periph)); + + assert_param(IS_FUNCTIONAL_STATE(NewState)); + if (NewState != DISABLE) + RCC->AHB1ENR |= RCC_AHB1Periph; + else + RCC->AHB1ENR &= ~RCC_AHB1Periph; + } + +#endif + +#if ANY(STM32F0xx, STM32F1xx) + + #define RCC_AHBPeriph_DMA1 ((uint32_t)0x00000001) + #define RCC_AHBPeriph_DMA2 ((uint32_t)0x00000002) + + void RCC_AHBPeriphClockCmd(uint32_t RCC_AHBPeriph, FunctionalState NewState) { + /* Check the parameters */ + assert_param(IS_RCC_AHB_PERIPH(RCC_AHBPeriph)); + assert_param(IS_FUNCTIONAL_STATE(NewState)); + + if (NewState != DISABLE) + RCC->AHBENR |= RCC_AHBPeriph; + else + RCC->AHBENR &= ~RCC_AHBPeriph; + } + +#endif + +// END OF TODO------------------------------------------------------ + +// SerialEvent functions are weak, so when the user doesn't define them, +// the linker just sets their address to 0 (which is checked below). +#ifdef USING_HW_SERIAL1 + HAL_HardwareSerial HSerial1(USART1); + void serialEvent1() __attribute__((weak)); +#endif +#ifdef USING_HW_SERIAL2 + HAL_HardwareSerial HSerial2(USART2); + void serialEvent2() __attribute__((weak)); +#endif +#ifdef USING_HW_SERIAL3 + HAL_HardwareSerial Serial3(USART3); + void serialEvent3() __attribute__((weak)); +#endif +#ifdef USING_HW_SERIAL4 + #ifdef USART4 + HAL_HardwareSerial HSerial4(USART4); + #else + HAL_HardwareSerial HSerial4(UART4); + #endif + void serialEvent4() __attribute__((weak)); +#endif +#ifdef USING_HW_SERIAL5 + #ifdef USART5 + HAL_HardwareSerial HSerial5(USART5); + #else + HAL_HardwareSerial HSerial5(UART5); + #endif + void serialEvent5() __attribute__((weak)); +#endif +#ifdef USING_HW_SERIAL6 + #ifdef USART6 + HAL_HardwareSerial HSerial5(USART6); + #else + HAL_HardwareSerial HSerial5(UART6); + #endif + void serialEvent5() __attribute__((weak)); +#endif + +// Constructors //////////////////////////////////////////////////////////////// + +HAL_HardwareSerial::HAL_HardwareSerial(void *peripheral) { + if (peripheral == USART1) { + setRx(PIN_SERIAL1_RX); + setTx(PIN_SERIAL1_TX); + _uart_index = 0; + #ifdef DMA2_Stream2 + RX_DMA = { USART1, RCC_AHB1Periph_DMA2, 4, DMA2_Stream2 }; + #endif + #ifdef DMA1_Channel5 + RX_DMA = { USART1, RCC_AHBPeriph_DMA1, DMA1, DMA1_Channel5 }; + #endif + } + else if (peripheral == USART2) { + setRx(PIN_SERIAL2_RX); + setTx(PIN_SERIAL2_TX); + _uart_index = 1; + #ifdef DMA1_Stream5 + RX_DMA = { USART2, RCC_AHB1Periph_DMA1, 4, DMA1_Stream5 }; + #endif + #ifdef DMA1_Channel6 + RX_DMA = { USART2, RCC_AHBPeriph_DMA1, DMA1, DMA1_Channel6 }; + #endif + } + else if (peripheral == USART3) { + setRx(PIN_SERIAL3_RX); + setTx(PIN_SERIAL3_TX); + _uart_index = 2; + #ifdef DMA1_Stream1 + RX_DMA = { USART3, RCC_AHB1Periph_DMA1, 4, DMA1_Stream1 }; + #endif + #ifdef DMA1_Channel3 // F0 has no support for UART3, requires system remapping + RX_DMA = { USART3, RCC_AHBPeriph_DMA1, DMA1, DMA1_Channel3 }; + #endif + } + + #ifdef USART4 // Only F2 / F4 / F7 + else if (peripheral == USART4) { + #ifdef DMA1_Stream2 + RX_DMA = { USART4, RCC_AHB1Periph_DMA1, 4, DMA1_Stream2 }; + #endif + setRx(PIN_SERIAL4_RX); + setTx(PIN_SERIAL4_TX); + _uart_index = 3; + } + #endif + + #ifdef UART4 + else if (peripheral == UART4) { + #ifdef DMA1_Stream2 + RX_DMA = { UART4, RCC_AHB1Periph_DMA1, 4, DMA1_Stream2 }; + #endif + #ifdef DMA2_Channel3 // STM32F0xx has only 3 UARTs + RX_DMA = { UART4, RCC_AHBPeriph_DMA2, DMA2, DMA2_Channel3 }; + #endif + setRx(PIN_SERIAL4_RX); + setTx(PIN_SERIAL4_TX); + _uart_index = 3; + } + #endif + + #ifdef UART5 // Only F2 / F4 / F7 + else if (peripheral == UART5) { + #ifdef DMA1_Stream0 + RX_DMA = { UART5, RCC_AHB1Periph_DMA1, 4, DMA1_Stream0 }; + #endif + setRx(PIN_SERIAL5_RX); + setTx(PIN_SERIAL5_TX); + _uart_index = 4; + } + #endif + + #ifdef USART6 // Only F2 / F4 / F7 + else if (peripheral == USART6) { + #ifdef DMA2_Stream1 + RX_DMA = { USART6, RCC_AHB1Periph_DMA2, 4, DMA2_Stream1 }; + #endif + setRx(PIN_SERIAL6_RX); + setTx(PIN_SERIAL6_TX); + _uart_index = 5; + } + #endif + + else { // else get the pins of the first peripheral occurence in PinMap + _serial.pin_rx = pinmap_pin(peripheral, PinMap_UART_RX); + _serial.pin_tx = pinmap_pin(peripheral, PinMap_UART_TX); + } + + init(_serial.pin_rx, _serial.pin_tx); +} + +void HAL_HardwareSerial::setRx(uint32_t _rx) { + _serial.pin_rx = digitalPinToPinName(_rx); +} + +void HAL_HardwareSerial::setTx(uint32_t _tx) { + _serial.pin_tx = digitalPinToPinName(_tx); +} + +void HAL_HardwareSerial::init(PinName _rx, PinName _tx) { + _serial.pin_rx = _rx; + _serial.rx_buff = _rx_buffer; + _serial.rx_head = _serial.rx_tail = 0; + + _serial.pin_tx = _tx; + _serial.tx_buff = _tx_buffer; + _serial.tx_head = _serial.tx_tail = 0; +} + +// Actual interrupt handlers ////////////////////////////////////////////////////////////// + +/** + * @brief Read receive byte from uart + * @param obj : pointer to serial_t structure + * @retval last character received + */ +int HAL_HardwareSerial::_tx_complete_irq(serial_t *obj) { + // If interrupts are enabled, there must be more data in the output buffer. Send the next byte + obj->tx_tail = (obj->tx_tail + 1) % TX_BUFFER_SIZE; + + if (obj->tx_head == obj->tx_tail) return -1; + + return 0; +} + +// Public Methods ////////////////////////////////////////////////////////////// + +void HAL_HardwareSerial::begin(unsigned long baud, uint8_t config) { + uint32_t databits = 0, stopbits = 0, parity = 0; + + _baud = baud; + _config = config; + + // Manage databits + switch (config & 0x07) { + case 0x02: databits = 6; break; + case 0x04: databits = 7; break; + case 0x06: databits = 8; break; + default: databits = 0; break; + } + + if ((config & 0x30) == 0x30) { + parity = UART_PARITY_ODD; + databits++; + } + else if ((config & 0x20) == 0x20) { + parity = UART_PARITY_EVEN; + databits++; + } + else + parity = UART_PARITY_NONE; + + stopbits = (config & 0x08) == 0x08 ? UART_STOPBITS_2 : UART_STOPBITS_1; + + switch (databits) { + #ifdef UART_WORDLENGTH_7B + case 7: databits = UART_WORDLENGTH_7B; break; + #endif + case 8: databits = UART_WORDLENGTH_8B; break; + case 9: databits = UART_WORDLENGTH_9B; break; + default: + case 0: Error_Handler(); break; + } + + uart_init(&_serial, (uint32_t)baud, databits, parity, stopbits); + Serial_DMA_Read_Enable(); // Start the circular DMA serial reading process, no callback needed +} + +void HAL_HardwareSerial::end() { + flush(); // Wait for transmission of outgoing data + uart_deinit(&_serial); + _serial.rx_head = _serial.rx_tail; // Clear any received data +} + +// Update buffer head for DMA progress +void HAL_HardwareSerial::update_rx_head() { + + #if ENABLED(EMERGENCY_PARSER) + static uint32_t flag = 0; + while (flag != _serial.rx_head) { // send all available data to emergency parser immediately + emergency_parser.update(static_cast(this)->emergency_state, _serial.rx_buff[flag]); + flag = (flag + 1) % RX_BUFFER_SIZE; + } + #endif + + #if ANY(STM32F2xx, STM32F4xx, STM32F7xx) + _serial.rx_head = RX_BUFFER_SIZE - RX_DMA.dma_streamRX->NDTR; + #endif + + #if ANY(STM32F0xx, STM32F1xx) + _serial.rx_head = RX_BUFFER_SIZE - RX_DMA.dma_channelRX->CNDTR; + #endif + +} + +int HAL_HardwareSerial::available() { + update_rx_head(); + return ((unsigned int)(RX_BUFFER_SIZE + _serial.rx_head - _serial.rx_tail)) % RX_BUFFER_SIZE; +} + +int HAL_HardwareSerial::peek() { + update_rx_head(); + if (_serial.rx_head == _serial.rx_tail) return -1; + return _serial.rx_buff[_serial.rx_tail]; +} + +int HAL_HardwareSerial::read() { + update_rx_head(); + if (_serial.rx_head == _serial.rx_tail) return -1; // No chars if the head isn't ahead of the tail + + unsigned char c = _serial.rx_buff[_serial.rx_tail]; + _serial.rx_tail = (rx_buffer_index_t)(_serial.rx_tail + 1) % RX_BUFFER_SIZE; + return c; +} + +size_t HAL_HardwareSerial::write(uint8_t c) { // Interrupt based writing + tx_buffer_index_t i = (_serial.tx_head + 1) % TX_BUFFER_SIZE; + + // If the output buffer is full, there's nothing for it other than to + // wait for the interrupt handler to empty it a bit + while (i == _serial.tx_tail) { /* nada */ } // NOP, let the interrupt free up space for us + + _serial.tx_buff[_serial.tx_head] = c; + _serial.tx_head = i; + + if (!serial_tx_active(&_serial)) + uart_attach_tx_callback(&_serial, _tx_complete_irq); // Write next byte, launch interrupt + + return 1; +} + +void HAL_HardwareSerial::flush() { + while ((_serial.tx_head != _serial.tx_tail)) { /* nada */ } // nop, the interrupt handler will free up space for us +} + +#if ANY(STM32F2xx, STM32F4xx, STM32F7xx) + + void HAL_HardwareSerial::Serial_DMA_Read_Enable() { + RCC_AHB1PeriphClockCmd(RX_DMA.dma_rcc, ENABLE); // Enable DMA clock + + #ifdef STM32F7xx + RX_DMA.dma_streamRX->PAR = (uint32_t)(&RX_DMA.uart->RDR); // RX peripheral receive address (usart) F7 + #else + RX_DMA.dma_streamRX->PAR = (uint32_t)(&RX_DMA.uart->DR); // RX peripheral address (usart) F2 / F4 + #endif + RX_DMA.dma_streamRX->M0AR = (uint32_t)_serial.rx_buff; // RX destination address (memory) + RX_DMA.dma_streamRX->NDTR = RX_BUFFER_SIZE; // RX buffer size + + RX_DMA.dma_streamRX->CR = (RX_DMA.dma_channel << 25); // RX channel selection, set to 0 all the other CR bits + + RX_DMA.dma_streamRX->CR |= (3 << 16); // RX priority level: Very High + + //RX_DMA.dma_streamRX->CR &= ~(3 << 13); // RX memory data size: 8 bit + //RX_DMA.dma_streamRX->CR &= ~(3 << 11); // RX peripheral data size: 8 bit + RX_DMA.dma_streamRX->CR |= (1 << 10); // RX memory increment mode + //RX_DMA.dma_streamRX->CR &= ~(1 << 9); // RX peripheral no increment mode + RX_DMA.dma_streamRX->CR |= (1 << 8); // RX circular mode enabled + //RX_DMA.dma_streamRX->CR &= ~(1 << 6); // RX data transfer direction: Peripheral-to-memory + RX_DMA.uart->CR3 |= (1 << 6); // Enable DMA receiver (DMAR) + RX_DMA.dma_streamRX->CR |= (1 << 0); // RX enable DMA + } + +#endif // STM32F2xx || STM32F4xx || STM32F7xx + +#if ANY(STM32F0xx, STM32F1xx) + + void HAL_HardwareSerial::Serial_DMA_Read_Enable() { + RCC_AHBPeriphClockCmd(RX_DMA.dma_rcc, ENABLE); // enable DMA clock + + RX_DMA.dma_channelRX->CPAR = (uint32_t)(&RX_DMA.uart->DR); // RX peripheral address (usart) + RX_DMA.dma_channelRX->CMAR = (uint32_t)_serial.rx_buff; // RX destination address (memory) + RX_DMA.dma_channelRX->CNDTR = RX_BUFFER_SIZE; // RX buffer size + + RX_DMA.dma_channelRX->CCR = 0; // RX channel selection, set to 0 all the other CR bits + + RX_DMA.dma_channelRX->CCR |= (3<<12); // RX priority level: Very High + + //RX_DMA.dma_channelRX->CCR &= ~(1<<10); // RX memory data size: 8 bit + //RX_DMA.dma_channelRX->CCR &= ~(1<<8); // RX peripheral data size: 8 bit + RX_DMA.dma_channelRX->CCR |= (1<<7); // RX memory increment mode + //RX_DMA.dma_channelRX->CCR &= ~(1<<6); // RX peripheral no increment mode + RX_DMA.dma_channelRX->CCR |= (1<<5); // RX circular mode enabled + //RX_DMA.dma_channelRX->CCR &= ~(1<<4); // RX data transfer direction: Peripheral-to-memory + + RX_DMA.uart->CR3 |= (1<<6); // enable DMA receiver (DMAR) + RX_DMA.dma_channelRX->CCR |= (1<<0); // RX enable DMA + } + +#endif // STM32F0xx || STM32F1xx + +#endif // SERIAL_DMA && HAL_UART_MODULE_ENABLED && !HAL_UART_MODULE_ONLY +#endif // HAL_STM32 diff --git a/Marlin/src/HAL/STM32/HardwareSerial.h b/Marlin/src/HAL/STM32/HardwareSerial.h new file mode 100644 index 0000000000..cc564322b4 --- /dev/null +++ b/Marlin/src/HAL/STM32/HardwareSerial.h @@ -0,0 +1,85 @@ +/** + * Marlin 3D Printer Firmware + * Copyright (c) 2023 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] + * + * Based on Sprinter and grbl. + * Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm + * Copyright (c) 2017 Victor Perez + * + * 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 + +// +// HAL_HardwareSerial Class. Adapted from Arduino HardwareSerial. +// + +#if RX_BUFFER_SIZE == 0 + #undef RX_BUFFER_SIZE + #define RX_BUFFER_SIZE 128 +#endif + +#if TX_BUFFER_SIZE == 0 + #undef TX_BUFFER_SIZE + #define TX_BUFFER_SIZE 64 +#endif + +typedef struct { + USART_TypeDef * uart; + uint32_t dma_rcc; + #if ANY(STM32F0xx, STM32F1xx) // F0 / F1 + DMA_TypeDef * dma_controller; + DMA_Channel_TypeDef * dma_channelRX; + #else // F2 / F4 / F7 + uint32_t dma_channel; + DMA_Stream_TypeDef * dma_streamRX; + #endif +} DMA_CFG; + +class HAL_HardwareSerial : public Stream { + protected: + // Don't put any members after these buffers, since only the first + // 32 bytes of this struct can be accessed quickly using the ldd instruction. + unsigned char _rx_buffer[RX_BUFFER_SIZE]; + unsigned char _tx_buffer[TX_BUFFER_SIZE]; + + serial_t _serial; + + public: + HAL_HardwareSerial(void *peripheral); + void begin(unsigned long, uint8_t); + void end(); + virtual int available(); + virtual int read(); + virtual int peek(); + virtual size_t write(uint8_t); + virtual void flush(); + operator bool() { return true; } + + void setRx(uint32_t _rx); + void setTx(uint32_t _tx); + + static int _tx_complete_irq(serial_t *obj); // Interrupt handler + + private: + uint8_t _uart_index; + bool _rx_enabled; + uint8_t _config; + unsigned long _baud; + void init(PinName _rx, PinName _tx); + void update_rx_head(); + DMA_CFG RX_DMA; + void Serial_DMA_Read_Enable(); +}; diff --git a/Marlin/src/HAL/STM32/MarlinSerial.cpp b/Marlin/src/HAL/STM32/MarlinSerial.cpp index 37a8f40fd0..c4bc629949 100644 --- a/Marlin/src/HAL/STM32/MarlinSerial.cpp +++ b/Marlin/src/HAL/STM32/MarlinSerial.cpp @@ -37,11 +37,25 @@ #ifndef USART5 #define USART5 UART5 #endif +#ifndef USART7 + #define USART7 UART7 +#endif +#ifndef USART8 + #define USART8 UART8 +#endif +#ifndef USART9 + #define USART9 UART9 +#endif -#define DECLARE_SERIAL_PORT(ser_num) \ - void _rx_complete_irq_ ## ser_num (serial_t * obj); \ - MSerialT MSerial ## ser_num (true, USART ## ser_num, &_rx_complete_irq_ ## ser_num); \ - void _rx_complete_irq_ ## ser_num (serial_t * obj) { MSerial ## ser_num ._rx_complete_irq(obj); } +#if ENABLED(SERIAL_DMA) + #define DECLARE_SERIAL_PORT(ser_num) \ + MSerialT MSerial ## ser_num (true, USART ## ser_num); +#else + #define DECLARE_SERIAL_PORT(ser_num) \ + void _rx_complete_irq_ ## ser_num (serial_t * obj); \ + MSerialT MSerial ## ser_num (true, USART ## ser_num, &_rx_complete_irq_ ## ser_num); \ + void _rx_complete_irq_ ## ser_num (serial_t * obj) { MSerial ## ser_num ._rx_complete_irq(obj); } +#endif #if USING_HW_SERIAL1 DECLARE_SERIAL_PORT(1) @@ -78,33 +92,38 @@ #endif void MarlinSerial::begin(unsigned long baud, uint8_t config) { - HardwareSerial::begin(baud, config); - // Replace the IRQ callback with the one we have defined - TERN_(EMERGENCY_PARSER, _serial.rx_callback = _rx_callback); + #if ENABLED(SERIAL_DMA) + HAL_HardwareSerial::begin(baud, config); + #else + HardwareSerial::begin(baud, config); + // Replace the IRQ callback with the one we have defined + TERN_(EMERGENCY_PARSER, _serial.rx_callback = _rx_callback); + #endif } -// This function is Copyright (c) 2006 Nicholas Zambetti. -void MarlinSerial::_rx_complete_irq(serial_t *obj) { - // No Parity error, read byte and store it in the buffer if there is room - unsigned char c; +#if DISABLED(SERIAL_DMA) - if (uart_getc(obj, &c) == 0) { + // This function Copyright (c) 2006 Nicholas Zambetti. + void MarlinSerial::_rx_complete_irq(serial_t *obj) { + // No Parity error, read byte and store it in the buffer if there is room + unsigned char c; + if (uart_getc(obj, &c) == 0) { - rx_buffer_index_t i = (unsigned int)(obj->rx_head + 1) % SERIAL_RX_BUFFER_SIZE; + rx_buffer_index_t i = (unsigned int)(obj->rx_head + 1) % SERIAL_RX_BUFFER_SIZE; - // if we should be storing the received character into the location - // just before the tail (meaning that the head would advance to the - // current location of the tail), we're about to overflow the buffer - // and so we don't write the character or advance the head. - if (i != obj->rx_tail) { - obj->rx_buff[obj->rx_head] = c; - obj->rx_head = i; + // If tail overlaps head the buffer is overflowed + // so don't write the character or advance the head. + if (i != obj->rx_tail) { + obj->rx_buff[obj->rx_head] = c; + obj->rx_head = i; + } + + #if ENABLED(EMERGENCY_PARSER) + emergency_parser.update(static_cast(this)->emergency_state, c); + #endif } - - #if ENABLED(EMERGENCY_PARSER) - emergency_parser.update(static_cast(this)->emergency_state, c); - #endif } -} + +#endif // !SERIAL_DMA #endif // HAL_STM32 diff --git a/Marlin/src/HAL/STM32/MarlinSerial.h b/Marlin/src/HAL/STM32/MarlinSerial.h index bf861fb8a7..4ab1e4e75a 100644 --- a/Marlin/src/HAL/STM32/MarlinSerial.h +++ b/Marlin/src/HAL/STM32/MarlinSerial.h @@ -27,23 +27,38 @@ #include "../../feature/e_parser.h" #endif +#if ENABLED(SERIAL_DMA) + #include "HardwareSerial.h" +#endif + #include "../../core/serial_hook.h" -typedef void (*usart_rx_callback_t)(serial_t * obj); +#if ENABLED(SERIAL_DMA) -struct MarlinSerial : public HardwareSerial { - MarlinSerial(void *peripheral, usart_rx_callback_t rx_callback) : - HardwareSerial(peripheral), _rx_callback(rx_callback) - { } + struct MarlinSerial : public HAL_HardwareSerial { + MarlinSerial(void *peripheral) : HAL_HardwareSerial(peripheral) { } + void begin(unsigned long baud, uint8_t config); + inline void begin(unsigned long baud) { begin(baud, SERIAL_8N1); } + }; - void begin(unsigned long baud, uint8_t config); - inline void begin(unsigned long baud) { begin(baud, SERIAL_8N1); } +#else // Arduino non-DMA - void _rx_complete_irq(serial_t *obj); + typedef void (*usart_rx_callback_t)(serial_t * obj); -protected: - usart_rx_callback_t _rx_callback; -}; + struct MarlinSerial : public HardwareSerial { + MarlinSerial(void *peripheral, usart_rx_callback_t rx_callback) + : HardwareSerial(peripheral), _rx_callback(rx_callback) { } + + void begin(unsigned long baud, uint8_t config); + inline void begin(unsigned long baud) { begin(baud, SERIAL_8N1); } + + void _rx_complete_irq(serial_t *obj); + + protected: + usart_rx_callback_t _rx_callback; + }; + +#endif typedef Serial1Class MSerialT; extern MSerialT MSerial1; diff --git a/Marlin/src/HAL/STM32/MinSerial.cpp b/Marlin/src/HAL/STM32/MinSerial.cpp index b0fcff20c1..a27bc35a14 100644 --- a/Marlin/src/HAL/STM32/MinSerial.cpp +++ b/Marlin/src/HAL/STM32/MinSerial.cpp @@ -4,7 +4,6 @@ * * Based on Sprinter and grbl. * Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm - * Copyright (c) 2017 Victor Perez * * 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 @@ -45,7 +44,7 @@ struct USARTMin { volatile uint32_t CR2; }; -#if WITHIN(SERIAL_PORT, 1, 6) +#if WITHIN(SERIAL_PORT, 1, 9) // Depending on the CPU, the serial port is different for USART1 static const uintptr_t regsAddr[] = { TERN(STM32F1xx, 0x40013800, 0x40011000), // USART1 @@ -53,7 +52,10 @@ struct USARTMin { 0x40004800, // USART3 0x40004C00, // UART4_BASE 0x40005000, // UART5_BASE - 0x40011400 // USART6 + 0x40011400, // USART6 + 0x40007800, // UART7_BASE + 0x40007C00, // UART8_BASE + 0x40011800 // UART9_BASE }; static USARTMin * regs = (USARTMin*)regsAddr[SERIAL_PORT - 1]; #endif @@ -116,7 +118,7 @@ static void TXBegin() { // A SW memory barrier, to ensure GCC does not overoptimize loops #define sw_barrier() __asm__ volatile("": : :"memory"); static void TX(char c) { - #if WITHIN(SERIAL_PORT, 1, 6) + #if WITHIN(SERIAL_PORT, 1, 9) constexpr uint32_t usart_sr_txe = _BV(7); while (!(regs->SR & usart_sr_txe)) { hal.watchdog_refresh(); @@ -135,18 +137,18 @@ void install_min_serial() { } #if NONE(DYNAMIC_VECTORTABLE, STM32F0xx, STM32G0xx) // Cortex M0 can't jump to a symbol that's too far from the current function, so we work around this in exception_arm.cpp -extern "C" { - __attribute__((naked)) void JumpHandler_ASM() { - __asm__ __volatile__ ( - "b CommonHandler_ASM\n" - ); + extern "C" { + __attribute__((naked)) void JumpHandler_ASM() { + __asm__ __volatile__ ( + "b CommonHandler_ASM\n" + ); + } + void __attribute__((naked, alias("JumpHandler_ASM"), nothrow)) HardFault_Handler(); + void __attribute__((naked, alias("JumpHandler_ASM"), nothrow)) BusFault_Handler(); + void __attribute__((naked, alias("JumpHandler_ASM"), nothrow)) UsageFault_Handler(); + void __attribute__((naked, alias("JumpHandler_ASM"), nothrow)) MemManage_Handler(); + void __attribute__((naked, alias("JumpHandler_ASM"), nothrow)) NMI_Handler(); } - void __attribute__((naked, alias("JumpHandler_ASM"), nothrow)) HardFault_Handler(); - void __attribute__((naked, alias("JumpHandler_ASM"), nothrow)) BusFault_Handler(); - void __attribute__((naked, alias("JumpHandler_ASM"), nothrow)) UsageFault_Handler(); - void __attribute__((naked, alias("JumpHandler_ASM"), nothrow)) MemManage_Handler(); - void __attribute__((naked, alias("JumpHandler_ASM"), nothrow)) NMI_Handler(); -} #endif #endif // POSTMORTEM_DEBUGGING diff --git a/Marlin/src/HAL/STM32/Servo.cpp b/Marlin/src/HAL/STM32/Servo.cpp index a00186e0e7..4f026ffc6d 100644 --- a/Marlin/src/HAL/STM32/Servo.cpp +++ b/Marlin/src/HAL/STM32/Servo.cpp @@ -4,7 +4,6 @@ * * Based on Sprinter and grbl. * Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm - * Copyright (c) 2017 Victor Perez * * 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 diff --git a/Marlin/src/HAL/STM32/Servo.h b/Marlin/src/HAL/STM32/Servo.h index 1527e753b6..95ecb5d977 100644 --- a/Marlin/src/HAL/STM32/Servo.h +++ b/Marlin/src/HAL/STM32/Servo.h @@ -4,7 +4,6 @@ * * Based on Sprinter and grbl. * Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm - * Copyright (c) 2017 Victor Perez * * 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 diff --git a/Marlin/src/HAL/STM32/eeprom_flash.cpp b/Marlin/src/HAL/STM32/eeprom_flash.cpp index 6bd519877d..69511c6de4 100644 --- a/Marlin/src/HAL/STM32/eeprom_flash.cpp +++ b/Marlin/src/HAL/STM32/eeprom_flash.cpp @@ -1,10 +1,9 @@ /** * Marlin 3D Printer Firmware - * * Copyright (c) 2020 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] - * Copyright (c) 2016 Bob Cousins bobcousins42@googlemail.com - * Copyright (c) 2015-2016 Nico Tonnhofer wurstnase.reprap@gmail.com - * Copyright (c) 2016 Victor Perez victor_pv@hotmail.com + * + * 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 diff --git a/Marlin/src/HAL/STM32/eeprom_sdcard.cpp b/Marlin/src/HAL/STM32/eeprom_sdcard.cpp index 473b656f9a..1b5c0ae5b2 100644 --- a/Marlin/src/HAL/STM32/eeprom_sdcard.cpp +++ b/Marlin/src/HAL/STM32/eeprom_sdcard.cpp @@ -48,7 +48,7 @@ static char _ALIGN(4) HAL_eeprom_data[MARLIN_EEPROM_SIZE]; bool PersistentStore::access_start() { if (!card.isMounted()) return false; - SdFile file, root = card.getroot(); + MediaFile file, root = card.getroot(); if (!file.open(&root, EEPROM_FILENAME, O_RDONLY)) return true; @@ -63,7 +63,7 @@ bool PersistentStore::access_start() { bool PersistentStore::access_finish() { if (!card.isMounted()) return false; - SdFile file, root = card.getroot(); + MediaFile file, root = card.getroot(); int bytes_written = 0; if (file.open(&root, EEPROM_FILENAME, O_CREAT | O_WRITE | O_TRUNC)) { bytes_written = file.write(HAL_eeprom_data, MARLIN_EEPROM_SIZE); diff --git a/Marlin/src/HAL/STM32/eeprom_sram.cpp b/Marlin/src/HAL/STM32/eeprom_sram.cpp index 687e7f55c2..9bd84ff4fe 100644 --- a/Marlin/src/HAL/STM32/eeprom_sram.cpp +++ b/Marlin/src/HAL/STM32/eeprom_sram.cpp @@ -1,10 +1,9 @@ /** * Marlin 3D Printer Firmware - * * Copyright (c) 2020 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] - * Copyright (c) 2016 Bob Cousins bobcousins42@googlemail.com - * Copyright (c) 2015-2016 Nico Tonnhofer wurstnase.reprap@gmail.com - * Copyright (c) 2016 Victor Perez victor_pv@hotmail.com + * + * 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 diff --git a/Marlin/src/HAL/STM32/eeprom_wired.cpp b/Marlin/src/HAL/STM32/eeprom_wired.cpp index cf0468151e..6fb9d9b51b 100644 --- a/Marlin/src/HAL/STM32/eeprom_wired.cpp +++ b/Marlin/src/HAL/STM32/eeprom_wired.cpp @@ -1,10 +1,9 @@ /** * Marlin 3D Printer Firmware - * * Copyright (c) 2020 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] - * Copyright (c) 2016 Bob Cousins bobcousins42@googlemail.com - * Copyright (c) 2015-2016 Nico Tonnhofer wurstnase.reprap@gmail.com - * Copyright (c) 2016 Victor Perez victor_pv@hotmail.com + * + * 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 diff --git a/Marlin/src/HAL/STM32/endstop_interrupts.h b/Marlin/src/HAL/STM32/endstop_interrupts.h index d2f20ba1c7..ab86bf29c2 100644 --- a/Marlin/src/HAL/STM32/endstop_interrupts.h +++ b/Marlin/src/HAL/STM32/endstop_interrupts.h @@ -4,7 +4,6 @@ * * Based on Sprinter and grbl. * Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm - * Copyright (c) 2017 Victor Perez * * 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 @@ -29,33 +28,33 @@ void endstop_ISR() { endstops.update(); } void setup_endstop_interrupts() { #define _ATTACH(P) attachInterrupt(P, endstop_ISR, CHANGE) - TERN_(HAS_X_MAX, _ATTACH(X_MAX_PIN)); - TERN_(HAS_X_MIN, _ATTACH(X_MIN_PIN)); - TERN_(HAS_Y_MAX, _ATTACH(Y_MAX_PIN)); - TERN_(HAS_Y_MIN, _ATTACH(Y_MIN_PIN)); - TERN_(HAS_Z_MAX, _ATTACH(Z_MAX_PIN)); - TERN_(HAS_Z_MIN, _ATTACH(Z_MIN_PIN)); - TERN_(HAS_X2_MAX, _ATTACH(X2_MAX_PIN)); - TERN_(HAS_X2_MIN, _ATTACH(X2_MIN_PIN)); - TERN_(HAS_Y2_MAX, _ATTACH(Y2_MAX_PIN)); - TERN_(HAS_Y2_MIN, _ATTACH(Y2_MIN_PIN)); - TERN_(HAS_Z2_MAX, _ATTACH(Z2_MAX_PIN)); - TERN_(HAS_Z2_MIN, _ATTACH(Z2_MIN_PIN)); - TERN_(HAS_Z3_MAX, _ATTACH(Z3_MAX_PIN)); - TERN_(HAS_Z3_MIN, _ATTACH(Z3_MIN_PIN)); - TERN_(HAS_Z4_MAX, _ATTACH(Z4_MAX_PIN)); - TERN_(HAS_Z4_MIN, _ATTACH(Z4_MIN_PIN)); - TERN_(HAS_Z_MIN_PROBE_PIN, _ATTACH(Z_MIN_PROBE_PIN)); - TERN_(HAS_I_MAX, _ATTACH(I_MAX_PIN)); - TERN_(HAS_I_MIN, _ATTACH(I_MIN_PIN)); - TERN_(HAS_J_MAX, _ATTACH(J_MAX_PIN)); - TERN_(HAS_J_MIN, _ATTACH(J_MIN_PIN)); - TERN_(HAS_K_MAX, _ATTACH(K_MAX_PIN)); - TERN_(HAS_K_MIN, _ATTACH(K_MIN_PIN)); - TERN_(HAS_U_MAX, _ATTACH(U_MAX_PIN)); - TERN_(HAS_U_MIN, _ATTACH(U_MIN_PIN)); - TERN_(HAS_V_MAX, _ATTACH(V_MAX_PIN)); - TERN_(HAS_V_MIN, _ATTACH(V_MIN_PIN)); - TERN_(HAS_W_MAX, _ATTACH(W_MAX_PIN)); - TERN_(HAS_W_MIN, _ATTACH(W_MIN_PIN)); + TERN_(USE_X_MAX, _ATTACH(X_MAX_PIN)); + TERN_(USE_X_MIN, _ATTACH(X_MIN_PIN)); + TERN_(USE_Y_MAX, _ATTACH(Y_MAX_PIN)); + TERN_(USE_Y_MIN, _ATTACH(Y_MIN_PIN)); + TERN_(USE_Z_MAX, _ATTACH(Z_MAX_PIN)); + TERN_(USE_Z_MIN, _ATTACH(Z_MIN_PIN)); + TERN_(USE_X2_MAX, _ATTACH(X2_MAX_PIN)); + TERN_(USE_X2_MIN, _ATTACH(X2_MIN_PIN)); + TERN_(USE_Y2_MAX, _ATTACH(Y2_MAX_PIN)); + TERN_(USE_Y2_MIN, _ATTACH(Y2_MIN_PIN)); + TERN_(USE_Z2_MAX, _ATTACH(Z2_MAX_PIN)); + TERN_(USE_Z2_MIN, _ATTACH(Z2_MIN_PIN)); + TERN_(USE_Z3_MAX, _ATTACH(Z3_MAX_PIN)); + TERN_(USE_Z3_MIN, _ATTACH(Z3_MIN_PIN)); + TERN_(USE_Z4_MAX, _ATTACH(Z4_MAX_PIN)); + TERN_(USE_Z4_MIN, _ATTACH(Z4_MIN_PIN)); + TERN_(USE_Z_MIN_PROBE, _ATTACH(Z_MIN_PROBE_PIN)); + TERN_(USE_I_MAX, _ATTACH(I_MAX_PIN)); + TERN_(USE_I_MIN, _ATTACH(I_MIN_PIN)); + TERN_(USE_J_MAX, _ATTACH(J_MAX_PIN)); + TERN_(USE_J_MIN, _ATTACH(J_MIN_PIN)); + TERN_(USE_K_MAX, _ATTACH(K_MAX_PIN)); + TERN_(USE_K_MIN, _ATTACH(K_MIN_PIN)); + TERN_(USE_U_MAX, _ATTACH(U_MAX_PIN)); + TERN_(USE_U_MIN, _ATTACH(U_MIN_PIN)); + TERN_(USE_V_MAX, _ATTACH(V_MAX_PIN)); + TERN_(USE_V_MIN, _ATTACH(V_MIN_PIN)); + TERN_(USE_W_MAX, _ATTACH(W_MAX_PIN)); + TERN_(USE_W_MIN, _ATTACH(W_MIN_PIN)); } diff --git a/Marlin/src/HAL/STM32/fastio.cpp b/Marlin/src/HAL/STM32/fastio.cpp index b34555b8c8..f8501545a0 100644 --- a/Marlin/src/HAL/STM32/fastio.cpp +++ b/Marlin/src/HAL/STM32/fastio.cpp @@ -4,7 +4,6 @@ * * Based on Sprinter and grbl. * Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm - * Copyright (c) 2017 Victor Perez * * 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 @@ -29,7 +28,7 @@ GPIO_TypeDef* FastIOPortMap[LastPort + 1] = { 0 }; void FastIO_init() { - LOOP_L_N(i, NUM_DIGITAL_PINS) + for (uint8_t i = 0; i < NUM_DIGITAL_PINS; ++i) FastIOPortMap[STM_PORT(digitalPin[i])] = get_GPIO_Port(STM_PORT(digitalPin[i])); } diff --git a/Marlin/src/HAL/STM32/fastio.h b/Marlin/src/HAL/STM32/fastio.h index 4a48954471..af2941c49c 100644 --- a/Marlin/src/HAL/STM32/fastio.h +++ b/Marlin/src/HAL/STM32/fastio.h @@ -4,7 +4,6 @@ * * Based on Sprinter and grbl. * Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm - * Copyright (c) 2017 Victor Perez * * 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 diff --git a/Marlin/src/HAL/STM32/inc/Conditionals_adv.h b/Marlin/src/HAL/STM32/inc/Conditionals_adv.h index 451c94f25d..032716a294 100644 --- a/Marlin/src/HAL/STM32/inc/Conditionals_adv.h +++ b/Marlin/src/HAL/STM32/inc/Conditionals_adv.h @@ -21,7 +21,7 @@ */ #pragma once -#if BOTH(SDSUPPORT, USBD_USE_CDC_MSC) && DISABLED(NO_SD_HOST_DRIVE) +#if ALL(HAS_MEDIA, USBD_USE_CDC_MSC) && DISABLED(NO_SD_HOST_DRIVE) #define HAS_SD_HOST_DRIVE 1 #endif diff --git a/Marlin/src/HAL/STM32/inc/Conditionals_post.h b/Marlin/src/HAL/STM32/inc/Conditionals_post.h index c5ce66a26f..6c97a635b3 100644 --- a/Marlin/src/HAL/STM32/inc/Conditionals_post.h +++ b/Marlin/src/HAL/STM32/inc/Conditionals_post.h @@ -24,11 +24,11 @@ // If no real or emulated EEPROM selected, fall back to SD emulation #if USE_FALLBACK_EEPROM #define SDCARD_EEPROM_EMULATION -#elif EITHER(I2C_EEPROM, SPI_EEPROM) +#elif ANY(I2C_EEPROM, SPI_EEPROM) #define USE_SHARED_EEPROM 1 #endif // Some STM32F4 boards may lose steps when saving to EEPROM during print (PR #17946) #if defined(STM32F4xx) && ENABLED(FLASH_EEPROM_EMULATION) && PRINTCOUNTER_SAVE_INTERVAL > 0 - #define PRINTCOUNTER_SYNC 1 + #define PRINTCOUNTER_SYNC #endif diff --git a/Marlin/src/HAL/STM32/inc/SanityCheck.h b/Marlin/src/HAL/STM32/inc/SanityCheck.h index e8ddfa1720..80d0314dbb 100644 --- a/Marlin/src/HAL/STM32/inc/SanityCheck.h +++ b/Marlin/src/HAL/STM32/inc/SanityCheck.h @@ -29,7 +29,7 @@ //#endif -#if ENABLED(SDCARD_EEPROM_EMULATION) && DISABLED(SDSUPPORT) +#if ENABLED(SDCARD_EEPROM_EMULATION) && !HAS_MEDIA #undef SDCARD_EEPROM_EMULATION // Avoid additional error noise #if USE_FALLBACK_EEPROM #warning "EEPROM type not specified. Fallback is SDCARD_EEPROM_EMULATION." @@ -51,11 +51,15 @@ #error "TFT_COLOR_UI, TFT_LVGL_UI and TFT_CLASSIC_UI are currently only supported on STM32H7, STM32F4 and STM32F1 hardware." #endif +#if TEMP_SENSOR_SOC && defined(ATEMP) && TEMP_SOC_PIN != ATEMP + #error "TEMP_SENSOR_SOC requires 'TEMP_SOC_PIN ATEMP' on STM32." +#endif + /** * Check for common serial pin conflicts */ #define _CHECK_SERIAL_PIN(N) (( \ - BTN_EN1 == N || DOGLCD_CS == N || HEATER_BED_PIN == N || FAN_PIN == N || \ + BTN_EN1 == N || DOGLCD_CS == N || HEATER_BED_PIN == N || FAN0_PIN == N || \ SDIO_D2_PIN == N || SDIO_D3_PIN == N || SDIO_CK_PIN == N || SDIO_CMD_PIN == N \ )) #define CHECK_SERIAL_PIN(T,N) defined(UART##N##_##T##_PIN) && _CHECK_SERIAL_PIN(UART##N##_##T##_PIN) diff --git a/Marlin/src/HAL/STM32/msc_sd.cpp b/Marlin/src/HAL/STM32/msc_sd.cpp index a40bec9d64..5c8bee9c62 100644 --- a/Marlin/src/HAL/STM32/msc_sd.cpp +++ b/Marlin/src/HAL/STM32/msc_sd.cpp @@ -1,14 +1,21 @@ /** * Marlin 3D Printer Firmware - * * Copyright (c) 2021 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] * Copyright (c) 2019 BigTreeTech [https://github.com/bigtreetech] * + * 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 . * @@ -33,6 +40,12 @@ #define BLOCK_SIZE 512 #define PRODUCT_ID 0x29 +#ifndef SD_MULTIBLOCK_RETRY_CNT + #define SD_MULTIBLOCK_RETRY_CNT 1 +#elif SD_MULTIBLOCK_RETRY_CNT < 1 + #error "SD_MULTIBLOCK_RETRY_CNT must be greater than or equal to 1." +#endif + class Sd2CardUSBMscHandler : public USBMscHandler { public: DiskIODriver* diskIODriver() { @@ -58,19 +71,29 @@ public: // single block if (blkLen == 1) { hal.watchdog_refresh(); - sd2card->writeBlock(blkAddr, pBuf); - return true; + return sd2card->writeBlock(blkAddr, pBuf); } // multi block optimization - sd2card->writeStart(blkAddr, blkLen); - while (blkLen--) { - hal.watchdog_refresh(); - sd2card->writeData(pBuf); - pBuf += BLOCK_SIZE; + bool done = false; + for (uint16_t rcount = SD_MULTIBLOCK_RETRY_CNT; !done && rcount--;) { + uint8_t *cBuf = pBuf; + sd2card->writeStart(blkAddr, blkLen); + bool okay = true; // Assume success + for (uint32_t i = blkLen; i--;) { + hal.watchdog_refresh(); + if (!sd2card->writeData(cBuf)) { // Write. Did it fail? + sd2card->writeStop(); // writeStop for new writeStart + okay = false; // Failed, so retry + break; // Go to while... below + } + cBuf += BLOCK_SIZE; + } + done = okay; // Done if no error occurred } - sd2card->writeStop(); - return true; + + if (done) sd2card->writeStop(); + return done; } bool Read(uint8_t *pBuf, uint32_t blkAddr, uint16_t blkLen) { @@ -78,24 +101,32 @@ public: // single block if (blkLen == 1) { hal.watchdog_refresh(); - sd2card->readBlock(blkAddr, pBuf); - return true; + return sd2card->readBlock(blkAddr, pBuf); } // multi block optimization - sd2card->readStart(blkAddr); - while (blkLen--) { - hal.watchdog_refresh(); - sd2card->readData(pBuf); - pBuf += BLOCK_SIZE; + bool done = false; + for (uint16_t rcount = SD_MULTIBLOCK_RETRY_CNT; !done && rcount--;) { + uint8_t *cBuf = pBuf; + sd2card->readStart(blkAddr); + bool okay = true; // Assume success + for (uint32_t i = blkLen; i--;) { + hal.watchdog_refresh(); + if (!sd2card->readData(cBuf)) { // Read. Did it fail? + sd2card->readStop(); // readStop for new readStart + okay = false; // Failed, so retry + break; // Go to while... below + } + cBuf += BLOCK_SIZE; + } + done = okay; // Done if no error occurred } - sd2card->readStop(); - return true; + + if (done) sd2card->readStop(); + return done; } - bool IsReady() { - return diskIODriver()->isReady(); - } + bool IsReady() { return diskIODriver()->isReady(); } }; Sd2CardUSBMscHandler usbMscHandler; diff --git a/Marlin/src/HAL/STM32/msc_sd.h b/Marlin/src/HAL/STM32/msc_sd.h index a8e5349f7c..20e738223c 100644 --- a/Marlin/src/HAL/STM32/msc_sd.h +++ b/Marlin/src/HAL/STM32/msc_sd.h @@ -1,14 +1,21 @@ /** * Marlin 3D Printer Firmware - * * Copyright (c) 2021 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] * Copyright (c) 2019 BigTreeTech [https://github.com/bigtreetech] * + * 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 . * diff --git a/Marlin/src/HAL/STM32/pinsDebug.h b/Marlin/src/HAL/STM32/pinsDebug.h index 29a4e003f9..13990a69f5 100644 --- a/Marlin/src/HAL/STM32/pinsDebug.h +++ b/Marlin/src/HAL/STM32/pinsDebug.h @@ -111,13 +111,14 @@ const XrefInfo pin_xref[] PROGMEM = { #if NUM_ANALOG_FIRST >= NUM_DIGITAL_PINS #define HAS_HIGH_ANALOG_PINS 1 #endif -#define NUM_ANALOG_LAST ((NUM_ANALOG_FIRST) + (NUM_ANALOG_INPUTS) - 1) +#ifndef NUM_ANALOG_LAST + #define NUM_ANALOG_LAST ((NUM_ANALOG_FIRST) + (NUM_ANALOG_INPUTS) - 1) +#endif #define NUMBER_PINS_TOTAL ((NUM_DIGITAL_PINS) + TERN0(HAS_HIGH_ANALOG_PINS, NUM_ANALOG_INPUTS)) #define VALID_PIN(P) (WITHIN(P, 0, (NUM_DIGITAL_PINS) - 1) || TERN0(HAS_HIGH_ANALOG_PINS, WITHIN(P, NUM_ANALOG_FIRST, NUM_ANALOG_LAST))) #define digitalRead_mod(Ard_num) extDigitalRead(Ard_num) // must use Arduino pin numbers when doing reads #define PRINT_PIN(Q) #define PRINT_PIN_ANALOG(p) do{ sprintf_P(buffer, PSTR(" (A%2d) "), DIGITAL_PIN_TO_ANALOG_PIN(pin)); SERIAL_ECHO(buffer); }while(0) -#define PRINT_PORT(ANUM) port_print(ANUM) #define DIGITAL_PIN_TO_ANALOG_PIN(ANUM) -1 // will report analog pin number in the print port routine // x is a variable used to search pin_array @@ -185,7 +186,7 @@ bool is_digital(const pin_t Ard_num) { return pin_mode == MODE_PIN_INPUT || pin_mode == MODE_PIN_OUTPUT; } -void port_print(const pin_t Ard_num) { +void print_port(const pin_t Ard_num) { char buffer[16]; pin_t Index; for (Index = 0; Index < NUMBER_PINS_TOTAL; Index++) diff --git a/Marlin/src/HAL/STM32/sdio.cpp b/Marlin/src/HAL/STM32/sdio.cpp index 41fe90b825..de388b8e14 100644 --- a/Marlin/src/HAL/STM32/sdio.cpp +++ b/Marlin/src/HAL/STM32/sdio.cpp @@ -26,7 +26,7 @@ #include "../../inc/MarlinConfig.h" -#if ENABLED(SDIO_SUPPORT) +#if ENABLED(ONBOARD_SDIO) #include "sdio.h" @@ -286,6 +286,9 @@ void HAL_SD_MspInit(SD_HandleTypeDef *hsd) { go_to_transfer_speed(); + hsd.Init.ClockPowerSave = SDIO_CLOCK_POWER_SAVE_ENABLE; + hsd.Init.ClockDiv = 8; + #if PINS_EXIST(SDIO_D1, SDIO_D2, SDIO_D3) // go to 4 bit wide mode if pins are defined retry_Cnt = retryCnt; for (;;) { @@ -433,7 +436,10 @@ bool SDIO_WriteBlock(uint32_t block, const uint8_t *src) { #else uint8_t retries = SDIO_READ_RETRIES; - while (retries--) if (SDIO_ReadWriteBlock_DMA(block, src, nullptr)) return true; + while (retries--) { + if (SDIO_ReadWriteBlock_DMA(block, src, nullptr)) return true; + delay(10); + } return false; #endif @@ -447,5 +453,5 @@ uint32_t SDIO_GetCardSize() { return (uint32_t)(hsd.SdCard.BlockNbr) * (hsd.SdCard.BlockSize); } -#endif // SDIO_SUPPORT +#endif // ONBOARD_SDIO #endif // HAL_STM32 diff --git a/Marlin/src/HAL/STM32/temp_soc.h b/Marlin/src/HAL/STM32/temp_soc.h new file mode 100644 index 0000000000..05fad695c3 --- /dev/null +++ b/Marlin/src/HAL/STM32/temp_soc.h @@ -0,0 +1,346 @@ +/** + * Marlin 3D Printer Firmware + * Copyright (c) 2023 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] + * + * Based on Sprinter and grbl. + * Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (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 + +#ifdef STM32F0xx + /* + STM32F030x4 STM32F030x6 STM32F030x8 STM32F030xC https://www.st.com/resource/en/datasheet/stm32f030f4.pdf + --> TS_CAL2 not defined in datasheet + STM32F031x4 STM32F031x6 https://www.st.com/resource/en/datasheet/stm32f031c4.pdf + STM32F038x6 https://www.st.com/resource/en/datasheet/stm32f038c6.pdf + STM32F042x4 STM32F042x6 https://www.st.com/resource/en/datasheet/stm32f042c4.pdf + STM32F048C6 STM32F048G6 STM32F048T6 https://www.st.com/resource/en/datasheet/stm32f048c6.pdf + STM32F051x4 STM32F051x6 STM32F051x8 https://www.st.com/resource/en/datasheet/dm00039193.pdf + STM32F058C8 STM32F058R8 STM32F058T8 https://www.st.com/resource/en/datasheet/stm32f058c8.pdf + STM32F070CB STM32F070RB STM32F070C6 STM32F070F6 https://www.st.com/resource/en/datasheet/stm32f070c6.pdf + --> TS_CAL2 not defined in datasheet + STM32F071x8 STM32F071xB https://www.st.com/resource/en/datasheet/stm32f071cb.pdf + STM32F072x8 STM32F072xB https://www.st.com/resource/en/datasheet/stm32f072c8.pdf + STM32F078CB STM32F078RB STM32F078VB https://www.st.com/resource/en/datasheet/stm32f078cb.pdf + STM32F091xB STM32F091xC https://www.st.com/resource/en/datasheet/stm32f091cc.pdf + STM32F098CC STM32F098RC STM32F098VC https://www.st.com/resource/en/datasheet/stm32f098cc.pdf + */ + #define TS_CAL1_TEMP 30 // Calibration temperature of TS_CAL1 (see specific SoC datasheet) + #define TS_CAL1_REGOFFSET 0x1FFFF7B8 // Memory address of TS_CAL1 for STM32F030x4/x6/x8/xC (see specific SoC datasheet) + #define TS_CAL2_TEMP 110 // Calibration temperature of TS_CAL2 (see specific SoC datasheet) + #define TS_CAL2_REGOFFSET 0x1FFFF7C2 // Memory address of TS_CAL2 for STM32F030x4/x6/x8/xC (see specific SoC datasheet) + +#elif defined(STM32F1xx) + /* + STM32F100xC STM32F100xD STM32F100xE https://www.st.com/resource/en/datasheet/stm32f100rc.pdf + --> V=1.41 + STM32F100x4 STM32F100x6 STM32F100x8 STM32F100xB https://www.st.com/resource/en/datasheet/stm32f100cb.pdf + --> V=1.41 + STM32F101x8 STM32F101xB https://www.st.com/resource/en/datasheet/stm32f101r8.pdf + STM32F101xC STM32F101xD STM32F101xE https://www.st.com/resource/en/datasheet/stm32f101rc.pdf + STM32F101x4 STM32F101x6 https://www.st.com/resource/en/datasheet/stm32f101c4.pdf + STM32F101xF STM32F101xG https://www.st.com/resource/en/datasheet/stm32f101vf.pdf + STM32F102x8 STM32F102xB https://www.st.com/resource/en/datasheet/stm32f102c8.pdf + --> V=1.42 / Slope=4.35 + STM32F102x4 STM32F102x6 https://www.st.com/resource/en/datasheet/stm32f102c4.pdf + --> V=1.42 / Slope=4.35 + STM32F103x8 STM32F103xB https://www.st.com/resource/en/datasheet/stm32f103c8.pdf + STM32F103xC STM32F103xD STM32F103xE https://www.st.com/resource/en/datasheet/stm32f103rc.pdf + STM32F103x4 STM32F103x6 https://www.st.com/resource/en/datasheet/stm32f103c4.pdf + STM32F103xF STM32F103xG https://www.st.com/resource/en/datasheet/stm32f103rg.pdf + STM32F105xx STM32F107xx https://www.st.com/resource/en/datasheet/stm32f105r8.pdf + */ + #define TS_TYPICAL_V 1.43 + #define TS_TYPICAL_TEMP 25 + #define TS_TYPICAL_SLOPE 4.3 + +#elif defined(STM32F2xx) + /* + STM32F205xx STM32F207xx https://www.st.com/resource/en/datasheet/stm32f205rb.pdf + STM32F215xx STM32F217xx https://www.st.com/resource/en/datasheet/stm32f215re.pdf + */ + #define TS_TYPICAL_V 0.76 + #define TS_TYPICAL_TEMP 25 + #define TS_TYPICAL_SLOPE 2.5 + +#elif defined(STM32F3xx) + /* + STM32F301x6 STM32F301x8 https://www.st.com/resource/en/datasheet/stm32f301c6.pdf + STM32F302xD STM32F302xE https://www.st.com/resource/en/datasheet/stm32f302re.pdf + STM32F302x6 STM32F302x8 https://www.st.com/resource/en/datasheet/stm32f302r6.pdf + STM32F302xB STM32F302xC https://www.st.com/resource/en/datasheet/stm32f302cb.pdf + STM32F303xD STM32F303xE https://www.st.com/resource/en/datasheet/stm32f303re.pdf + STM32F303xB STM32F303xC https://www.st.com/resource/en/datasheet/stm32f303cb.pdf + STM32F303x6/x8 https://www.st.com/resource/en/datasheet/stm32f303c6.pdf + STM32F334x4 STM32F334x6 STM32F334x8 https://www.st.com/resource/en/datasheet/stm32f334k4.pdf + STM32F373xx https://www.st.com/resource/en/datasheet/stm32f373cc.pdf + STM32F358xC https://www.st.com/resource/en/datasheet/stm32f358cc.pdf + STM32F378xx https://www.st.com/resource/en/datasheet/stm32f378cc.pdf + STM32F318C8 STM32F318K8 https://www.st.com/resource/en/datasheet/stm32f318c8.pdf + STM32F328C8 https://www.st.com/resource/en/datasheet/stm32f328c8.pdf + STM32F398VE https://www.st.com/resource/en/datasheet/stm32f398ve.pdf + */ + #define TS_CAL1_TEMP 30 + #define TS_CAL1_REGOFFSET 0x1FFFF7B8 + #define TS_CAL2_TEMP 110 + #define TS_CAL2_REGOFFSET 0x1FFFF7C2 + +#elif defined(STM32F4xx) + /* + STM32F401xD STM32F401xE https://www.st.com/resource/en/datasheet/stm32f401re.pdf + STM32F411xC STM32F411xE https://www.st.com/resource/en/datasheet/stm32f411ce.pdf + STM32F446xC/E https://www.st.com/resource/en/datasheet/stm32f446mc.pdf + STM32F479xx https://www.st.com/resource/en/datasheet/stm32f479ai.pdf + STM32F412xE STM32F412xG https://www.st.com/resource/en/datasheet/stm32f412ce.pdf + STM32F410x8 STM32F410xB https://www.st.com/resource/en/datasheet/stm32f410cb.pdf + STM32F469xx https://www.st.com/resource/en/datasheet/stm32f469ae.pdf + STM32F423xH https://www.st.com/resource/en/datasheet/stm32f423ch.pdf + STM32F413xG STM32F413xH https://www.st.com/resource/en/datasheet/stm32f413cg.pdf + STM32F415xx STM32F417xx https://www.st.com/resource/en/datasheet/stm32f415rg.pdf + STM32F405xx STM32F407xx https://www.st.com/resource/en/datasheet/stm32f405rg.pdf + STM32F427xx STM32F429xx https://www.st.com/resource/en/datasheet/stm32f427vg.pdf + STM32F437xx STM32F439xx https://www.st.com/resource/en/datasheet/stm32f437vg.pdf + STM32F401xB STM32F401xC https://www.st.com/resource/en/datasheet/stm32f401cb.pdf + */ + #define TS_CAL1_TEMP 30 + #define TS_CAL1_REGOFFSET 0x1FFF7A2C + #define TS_CAL2_TEMP 110 + #define TS_CAL2_REGOFFSET 0x1FFF7A2E + +#elif defined(STM32F7xx) + /* + STM32F756xx https://www.st.com/resource/en/datasheet/stm32f756bg.pdf + STM32F745xx STM32F746xx https://www.st.com/resource/en/datasheet/stm32f745ie.pdf + STM32F777xx STM32F778Ax STM32F779xx https://www.st.com/resource/en/datasheet/stm32f777bi.pdf + STM32F765xx STM32F767xx STM32F768Ax STM32F769xx https://www.st.com/resource/en/datasheet/stm32f765bi.pdf + STM32F722xx STM32F723xx https://www.st.com/resource/en/datasheet/stm32f722ic.pdf + --> TS_CAL1/2 = 0x1FF07A2C / 0x1FF07A2E + STM32F732xx STM32F733xx https://www.st.com/resource/en/datasheet/stm32f732ie.pdf + --> TS_CAL1/2 = 0x1FF07A2C / 0x1FF07A2E + STM32F750x8 https://www.st.com/resource/en/datasheet/stm32f750n8.pdf + STM32F730x8 https://www.st.com/resource/en/datasheet/stm32f730i8.pdf + --> TS_CAL1/2 = 0x1FF07A2C / 0x1FF07A2E + */ + #define TS_CAL1_TEMP 30 + #define TS_CAL1_REGOFFSET 0x1FF0F44C + #define TS_CAL2_TEMP 110 + #define TS_CAL2_REGOFFSET 0x1FF0F44E + +#elif defined(STM32G0xx) + /* + STM32G030x6/x8 https://www.st.com/resource/en/datasheet/stm32g030c6.pdf + --> TS_CAL2 not defined in datasheet + STM32G050x6/x8 https://www.st.com/resource/en/datasheet/stm32g050c6.pdf + STM32G0B0KE/CE/RE/VE https://www.st.com/resource/en/datasheet/stm32g0b0ce.pdf + --> TS_CAL2 not defined in datasheet + STM32G081xB https://www.st.com/resource/en/datasheet/stm32g081cb.pdf + STM32G071x8/xB https://www.st.com/resource/en/datasheet/stm32g071c8.pdf + STM32G031x4/x6/x8 https://www.st.com/resource/en/datasheet/stm32g031c6.pdf + STM32G041x6/x8 https://www.st.com/resource/en/datasheet/stm32g041c8.pdf + STM32G051x6/x8 https://www.st.com/resource/en/datasheet/stm32g051c6.pdf + STM32G061x6/x8 https://www.st.com/resource/en/datasheet/stm32g061c6.pdf + STM32G0B1xB/xC/xE https://www.st.com/resource/en/datasheet/stm32g0b1cc.pdf + STM32G0C1xC/xE https://www.st.com/resource/en/datasheet/stm32g0c1cc.pdf + */ + #define TS_CAL1_TEMP 30 + #define TS_CAL1_REGOFFSET 0x1FFF75A8 + #define TS_CAL2_TEMP 130 + #define TS_CAL2_REGOFFSET 0x1FFF75CA + +#elif defined(STM32G4xx) + /* + STM32G431x6 STM32G431x8 STM32G431xB https://www.st.com/resource/en/datasheet/stm32g431c6.pdf + STM32G441xB https://www.st.com/resource/en/datasheet/stm32g441cb.pdf + STM32G491xC STM32G491xE https://www.st.com/resource/en/datasheet/stm32g491cc.pdf + STM32G4A1xE https://www.st.com/resource/en/datasheet/stm32g4a1ce.pdf + STM32G473xB STM32G473xC STM32G473xE https://www.st.com/resource/en/datasheet/stm32g473cb.pdf + STM32G483xE https://www.st.com/resource/en/datasheet/stm32g483ce.pdf + --> TS_CAL1/TS_CAL2 not defined in datasheet + STM32G474xB STM32G474xC STM32G474xE https://www.st.com/resource/en/datasheet/stm32g474cb.pdf + STM32G484xE https://www.st.com/resource/en/datasheet/stm32g484ce.pdf + */ + #define TS_CAL1_TEMP 30 + #define TS_CAL1_REGOFFSET 0x1FFF75A8 + #define TS_CAL2_TEMP 130 + #define TS_CAL2_REGOFFSET 0x1FFF75CA + +#elif defined(STM32H7xx) + /* + STM32H7A3xI/G + --> TS_CAL1/2 = 0x08FFF814 / 0x08FFF818 + STM32H7B0xB + --> TS_CAL1/2 = 0x08FFF814 / 0x08FFF818 + STM32H7B3xI + --> TS_CAL1/2 = 0x08FFF814 / 0x08FFF818 + STM32H725xE/G + STM32H735xG + STM32H723VE STM32H723VG STM32H723ZE STM32H723ZG + STM32H730AB STM32H730IB STM32H730VB STM32H730ZB + STM32H733VG STM32H733ZG + STM32H742xI/G STM32H743xI/G + --> CAL2_TEMP = 110 + STM32H745xI/G + STM32H747xI/G + STM32H753xI + STM32H755xI + STM32H757xI + STM32H750VB STM32H750ZB STM32H750IB STM32H750XB + --> CAL2_TEMP = 110 + */ + #define TS_CAL1_TEMP 30 + #define TS_CAL1_REGOFFSET 0x1FF1E820 + #define TS_CAL2_TEMP 130 + #define TS_CAL2_REGOFFSET 0x1FF1E840 + +#elif defined(STM32L0xx) + /* + STM32L010RB + --> TS_CAL1/TS_CAL2 not defined in datasheet + STM32L010F4 STM32L010K4 + --> TS_CAL1/TS_CAL2 not defined in datasheet + STM32L010C6 + --> TS_CAL1/TS_CAL2 not defined in datasheet + STM32L010K8 STM32L010R8 + --> TS_CAL1/TS_CAL2 not defined in datasheet + STM32L011x3 STM32L011x4 + --> TS_CAL1 not defined in datasheet + STM32L021D4 STM32L021F4 STM32L021G4 STM32L021K4 + --> TS_CAL1 not defined in datasheet + STM32L031x4 STM32L031x6 + STM32L041x6 + STM32L051x6 STM32L051x8 + STM32L071x8 STM32L071xB STM32L071xZ + STM32L081CB STM32L081CZ STM32L081KZ + STM32L052x6 STM32L052x8 + STM32L062K8 STM32L062T8 STM32L062C8 + STM32L072x8 STM32L072xB STM32L072xZ + STM32L082KB STM32L082KZ STM32L082CZ + STM32L053C6 STM32L053C8 STM32L053R6 STM32L053R8 + STM32L063C8 STM32L063R8 + STM32L073x8 STM32L073xB STM32L073xZ + STM32L083x8 STM32L083xB STM32L083xZ + */ + #define TS_CAL1_TEMP 30 + #define TS_CAL1_REGOFFSET 0x1FF8007A + #define TS_CAL2_TEMP 130 + #define TS_CAL2_REGOFFSET 0x1FF8007E + +#elif defined(STM32L1xx) + /* + STM32L100x6/8/B-A + --> TS_CAL1/TS_CAL2 not defined in datasheet + STM32L100RC + --> TS_CAL1/TS_CAL2 not defined in datasheet + STM32L100C6 STM32L100R8/RB + --> TS_CAL1/TS_CAL2 not defined in datasheet + STM32L151x6/8/B-A STM32L152x6/8/B-A + --> TS_CAL1/2 = 0x08FFF814 / 0x08FFF818 + STM32L151xD STM32L152xD + STM32L151VD-X STM32L152VD-X + STM32L15xCC STM32L15xRC STM32L15xUC STM32L15xVC + STM32L15xQC STM32L15xRC-A STM32L15xVC-A STM32L15xZC + STM32L162xE + STM32L162VD STM32L162ZD STM32L162QD STM32L162RD + STM32L162VC STM32L162RC + STM32L162VD-X + STM32L162QC STM32L162VC-A STM32L162ZC STM32L162RC-A + */ + #define TS_CAL1_TEMP 30 + #define TS_CAL1_REGOFFSET 0x1FF800FA + #define TS_CAL2_TEMP 110 + #define TS_CAL2_REGOFFSET 0x1FF800FE + +#elif defined(STM32L4xx) + /* + STM32L431xx + STM32L451xx + STM32L471xx + --> CAL2_TEMP = 110 + STM32L412xx + STM32L422xx + STM32L432KB STM32L432KC + STM32L442KC + STM32L452xx + STM32L462CE STM32L462RE STM32L462VE + STM32L433xx + STM32L443CC STM32L443RC STM32L443VC + STM32L475xx + --> CAL2_TEMP = 110 + STM32L476xx + --> CAL2_TEMP = 110 + STM32L486xx : + --> CAL2_TEMP = 110 + STM32L496xx + STM32L4A6xG + */ + #define TS_CAL1_TEMP 30 + #define TS_CAL1_REGOFFSET 0x1FFF75A8 + #define TS_CAL2_TEMP 130 + #define TS_CAL2_REGOFFSET 0x1FFF75CA + +#elif defined(STM32MP1xx) + /* + STM32MP131A STM32MP131D + STM32MP131C STM32MP131F + STM32MP133A STM32MP133D + STM32MP133C STM32MP133F + STM32MP135A STM32MP135D + STM32MP135C STM32MP135F + STM32MP151A/D + STM32MP151C/F + STM32MP153A/D + STM32MP153C/F + STM32MP157A/D + STM32MP157C/F + */ + // BSEC -> RCC + //#define TS_CAL1_TEMP 30 + //#define TS_CAL1_REGOFFSET 0x5C00 525C[15:0] + //#define TS_CAL2_TEMP 130 + //#define TS_CAL2_REGOFFSET 0x5C00 525C[31:16] + +#elif defined(STM32WBxx) + /* + STM32WB10CC + STM32WB50CG STM32WB30CE + STM32WB15CC + STM32WB55xx STM32WB35xx + */ + #define TS_CAL1_TEMP 30 + #define TS_CAL1_REGOFFSET 0x1FFF75A8 + #define TS_CAL2_TEMP 130 + #define TS_CAL2_REGOFFSET 0x1FFF75CA +#endif + +// TODO implement voltage scaling (calibrated Vrefint) and ADC resolution scaling (when applicable) + +/** + * When provided in datasheet, the use of calibrated values (TS_CAL1, TS_CAL2) should always be preferred over typical values. + * Typical values may result in important variation from the actual temperature. + * + * If calibrated values are not provided in datasheet, it is encouraged to calibrate your specific chip yourself. + */ +#if defined(TS_CAL1_TEMP) && defined(TS_CAL1_REGOFFSET) && defined(TS_CAL2_TEMP) && defined(TS_CAL2_REGOFFSET) + + #define READMEMORY(ADDR) (*((uint16_t const *)(ADDR))) + #define TEMP_SOC_SENSOR(RAW) (float((TS_CAL2_TEMP) - (TS_CAL1_TEMP)) / (READMEMORY(TS_CAL2_REGOFFSET) - READMEMORY(TS_CAL1_REGOFFSET)) * ((RAW) / float(OVERSAMPLENR) - READMEMORY(TS_CAL1_REGOFFSET)) + (TS_CAL1_TEMP)) + +#elif defined(TS_TYPICAL_V) && defined(TS_TYPICAL_SLOPE) && defined(TS_TYPICAL_TEMP) + + #define TEMP_SOC_SENSOR(RAW) ((TS_TYPICAL_V - (RAW) / float(OVERSAMPLENR) / float(HAL_ADC_RANGE) * (float(ADC_VREF_MV) / 1000.0f)) / ((TS_TYPICAL_SLOPE) / 1000) + TS_TYPICAL_TEMP) + +#endif diff --git a/Marlin/src/HAL/STM32/tft/gt911.cpp b/Marlin/src/HAL/STM32/tft/gt911.cpp index 180abc68b0..e57bccfef3 100644 --- a/Marlin/src/HAL/STM32/tft/gt911.cpp +++ b/Marlin/src/HAL/STM32/tft/gt911.cpp @@ -90,7 +90,7 @@ bool SW_IIC::read_ack() { } void SW_IIC::send_byte(uint8_t txd) { - LOOP_L_N(i, 8) { + for (uint8_t i = 0; i < 8; ++i) { write_sda(txd & 0x80); // write data bit txd <<= 1; iic_delay(1); @@ -107,7 +107,7 @@ uint8_t SW_IIC::read_byte(bool ack) { uint8_t data = 0; set_sda_in(); - LOOP_L_N(i, 8) { + for (uint8_t i = 0; i < 8; ++i) { write_scl(HIGH); // SCL = 1 iic_delay(1); data <<= 1; @@ -128,12 +128,12 @@ SW_IIC GT911::sw_iic = SW_IIC(GT911_SW_I2C_SDA_PIN, GT911_SW_I2C_SCL_PIN); void GT911::write_reg(uint16_t reg, uint8_t reg_len, uint8_t* w_data, uint8_t w_len) { sw_iic.start(); sw_iic.send_byte(gt911_slave_address); // Set IIC Slave address - LOOP_L_N(i, reg_len) { // Set reg address + for (uint8_t i = 0; i < reg_len; ++i) { // Set reg address uint8_t r = (reg >> (8 * (reg_len - 1 - i))) & 0xFF; sw_iic.send_byte(r); } - LOOP_L_N(i, w_len) { // Write data to reg + for (uint8_t i = 0; i < w_len; ++i) { // Write data to reg sw_iic.send_byte(w_data[i]); } sw_iic.stop(); @@ -142,7 +142,7 @@ void GT911::write_reg(uint16_t reg, uint8_t reg_len, uint8_t* w_data, uint8_t w_ void GT911::read_reg(uint16_t reg, uint8_t reg_len, uint8_t* r_data, uint8_t r_len) { sw_iic.start(); sw_iic.send_byte(gt911_slave_address); // Set IIC Slave address - LOOP_L_N(i, reg_len) { // Set reg address + for (uint8_t i = 0; i < reg_len; ++i) { // Set reg address uint8_t r = (reg >> (8 * (reg_len - 1 - i))) & 0xFF; sw_iic.send_byte(r); } @@ -150,13 +150,13 @@ void GT911::read_reg(uint16_t reg, uint8_t reg_len, uint8_t* r_data, uint8_t r_l sw_iic.start(); sw_iic.send_byte(gt911_slave_address + 1); // Set read mode - LOOP_L_N(i, r_len) { + for (uint8_t i = 0; i < r_len; ++i) r_data[i] = sw_iic.read_byte(1); // Read data from reg - } + sw_iic.stop(); } -void GT911::Init() { +void GT911::init() { OUT_WRITE(GT911_RST_PIN, LOW); OUT_WRITE(GT911_INT_PIN, LOW); delay(11); @@ -189,8 +189,8 @@ bool GT911::getFirstTouchPoint(int16_t *x, int16_t *y) { return false; } -bool GT911::getPoint(int16_t *x, int16_t *y) { - static bool touched = 0; +bool GT911::getRawPoint(int16_t * const x, int16_t * const y) { + static bool touched = false; static int16_t read_x = 0, read_y = 0; static millis_t next_time = 0; diff --git a/Marlin/src/HAL/STM32/tft/gt911.h b/Marlin/src/HAL/STM32/tft/gt911.h index 6ecfe8b82e..989517c183 100644 --- a/Marlin/src/HAL/STM32/tft/gt911.h +++ b/Marlin/src/HAL/STM32/tft/gt911.h @@ -39,42 +39,18 @@ class SW_IIC { private: uint16_t scl_pin; uint16_t sda_pin; - void write_scl(bool level) - { - WRITE(scl_pin, level); - } - void write_sda(bool level) - { - WRITE(sda_pin, level); - } - bool read_sda() - { - return READ(sda_pin); - } - void set_sda_out() - { - SET_OUTPUT(sda_pin); - } - void set_sda_in() - { - SET_INPUT_PULLUP(sda_pin); - } - static void iic_delay(uint8_t t) - { - delayMicroseconds(t); - } + void write_scl(bool level) { WRITE(scl_pin, level); } + void write_sda(bool level) { WRITE(sda_pin, level); } + bool read_sda() { return READ(sda_pin); } + void set_sda_out() { SET_OUTPUT(sda_pin); } + void set_sda_in() { SET_INPUT_PULLUP(sda_pin); } + static void iic_delay(uint8_t t) { delayMicroseconds(t); } public: SW_IIC(uint16_t sda, uint16_t scl); // setSCL/SDA have to be called before begin() - void setSCL(uint16_t scl) - { - scl_pin = scl; - }; - void setSDA(uint16_t sda) - { - sda_pin = sda; - }; + void setSCL(uint16_t scl) { scl_pin = scl; } + void setSDA(uint16_t sda) { sda_pin = sda; } void init(); // Initialize the IO port of IIC void start(); // Send IIC start signal void stop(); // Send IIC stop signal @@ -114,7 +90,7 @@ class GT911 { static void read_reg(uint16_t reg, uint8_t reg_len, uint8_t* r_data, uint8_t r_len); public: - static void Init(); + static void init(); static bool getFirstTouchPoint(int16_t *x, int16_t *y); - static bool getPoint(int16_t *x, int16_t *y); + static bool getRawPoint(int16_t * const x, int16_t * const y); }; diff --git a/Marlin/src/HAL/STM32/tft/tft_fsmc.cpp b/Marlin/src/HAL/STM32/tft/tft_fsmc.cpp index 3df982e48b..8e4f97d0a3 100644 --- a/Marlin/src/HAL/STM32/tft/tft_fsmc.cpp +++ b/Marlin/src/HAL/STM32/tft/tft_fsmc.cpp @@ -35,17 +35,17 @@ SRAM_HandleTypeDef TFT_FSMC::SRAMx; DMA_HandleTypeDef TFT_FSMC::DMAtx; LCD_CONTROLLER_TypeDef *TFT_FSMC::LCD; -void TFT_FSMC::Init() { +void TFT_FSMC::init() { uint32_t controllerAddress; - FSMC_NORSRAM_TimingTypeDef Timing, ExtTiming; + FSMC_NORSRAM_TimingTypeDef timing, extTiming; - uint32_t NSBank = (uint32_t)pinmap_peripheral(digitalPinToPinName(TFT_CS_PIN), PinMap_FSMC_CS); + uint32_t nsBank = (uint32_t)pinmap_peripheral(digitalPinToPinName(TFT_CS_PIN), pinMap_FSMC_CS); // Perform the SRAM1 memory initialization sequence SRAMx.Instance = FSMC_NORSRAM_DEVICE; SRAMx.Extended = FSMC_NORSRAM_EXTENDED_DEVICE; // SRAMx.Init - SRAMx.Init.NSBank = NSBank; + SRAMx.Init.NSBank = nsBank; SRAMx.Init.DataAddressMux = FSMC_DATA_ADDRESS_MUX_DISABLE; SRAMx.Init.MemoryType = FSMC_MEMORY_TYPE_SRAM; SRAMx.Init.MemoryDataWidth = TERN(TFT_INTERFACE_FSMC_8BIT, FSMC_NORSRAM_MEM_BUS_WIDTH_8, FSMC_NORSRAM_MEM_BUS_WIDTH_16); @@ -63,48 +63,48 @@ void TFT_FSMC::Init() { #endif // Read Timing - relatively slow to ensure ID information is correctly read from TFT controller // Can be decreases from 15-15-24 to 4-4-8 with risk of stability loss - Timing.AddressSetupTime = 15; - Timing.AddressHoldTime = 15; - Timing.DataSetupTime = 24; - Timing.BusTurnAroundDuration = 0; - Timing.CLKDivision = 16; - Timing.DataLatency = 17; - Timing.AccessMode = FSMC_ACCESS_MODE_A; + timing.AddressSetupTime = 15; + timing.AddressHoldTime = 15; + timing.DataSetupTime = 24; + timing.BusTurnAroundDuration = 0; + timing.CLKDivision = 16; + timing.DataLatency = 17; + timing.AccessMode = FSMC_ACCESS_MODE_A; // Write Timing - // Can be decreases from 8-15-8 to 0-0-1 with risk of stability loss - ExtTiming.AddressSetupTime = 8; - ExtTiming.AddressHoldTime = 15; - ExtTiming.DataSetupTime = 8; - ExtTiming.BusTurnAroundDuration = 0; - ExtTiming.CLKDivision = 16; - ExtTiming.DataLatency = 17; - ExtTiming.AccessMode = FSMC_ACCESS_MODE_A; + // Can be decreased from 8-15-8 to 0-0-1 with risk of stability loss + extTiming.AddressSetupTime = 8; + extTiming.AddressHoldTime = 15; + extTiming.DataSetupTime = 8; + extTiming.BusTurnAroundDuration = 0; + extTiming.CLKDivision = 16; + extTiming.DataLatency = 17; + extTiming.AccessMode = FSMC_ACCESS_MODE_A; __HAL_RCC_FSMC_CLK_ENABLE(); - for (uint16_t i = 0; PinMap_FSMC[i].pin != NC; i++) - pinmap_pinout(PinMap_FSMC[i].pin, PinMap_FSMC); - pinmap_pinout(digitalPinToPinName(TFT_CS_PIN), PinMap_FSMC_CS); - pinmap_pinout(digitalPinToPinName(TFT_RS_PIN), PinMap_FSMC_RS); + for (uint16_t i = 0; pinMap_FSMC[i].pin != NC; i++) + pinmap_pinout(pinMap_FSMC[i].pin, pinMap_FSMC); + pinmap_pinout(digitalPinToPinName(TFT_CS_PIN), pinMap_FSMC_CS); + pinmap_pinout(digitalPinToPinName(TFT_RS_PIN), pinMap_FSMC_RS); controllerAddress = FSMC_BANK1_1; #ifdef PF0 - switch (NSBank) { + switch (nsBank) { case FSMC_NORSRAM_BANK2: controllerAddress = FSMC_BANK1_2 ; break; case FSMC_NORSRAM_BANK3: controllerAddress = FSMC_BANK1_3 ; break; case FSMC_NORSRAM_BANK4: controllerAddress = FSMC_BANK1_4 ; break; } #endif - controllerAddress |= (uint32_t)pinmap_peripheral(digitalPinToPinName(TFT_RS_PIN), PinMap_FSMC_RS); + controllerAddress |= (uint32_t)pinmap_peripheral(digitalPinToPinName(TFT_RS_PIN), pinMap_FSMC_RS); - HAL_SRAM_Init(&SRAMx, &Timing, &ExtTiming); - - __HAL_RCC_DMA2_CLK_ENABLE(); + HAL_SRAM_Init(&SRAMx, &timing, &extTiming); #ifdef STM32F1xx - DMAtx.Instance = DMA2_Channel1; + __HAL_RCC_DMA1_CLK_ENABLE(); + DMAtx.Instance = DMA1_Channel1; #elif defined(STM32F4xx) + __HAL_RCC_DMA2_CLK_ENABLE(); DMAtx.Instance = DMA2_Stream0; DMAtx.Init.Channel = DMA_CHANNEL_0; DMAtx.Init.FIFOMode = DMA_FIFOMODE_ENABLE; @@ -123,23 +123,23 @@ void TFT_FSMC::Init() { LCD = (LCD_CONTROLLER_TypeDef *)controllerAddress; } -uint32_t TFT_FSMC::GetID() { +uint32_t TFT_FSMC::getID() { uint32_t id; - WriteReg(0); + writeReg(0); id = LCD->RAM; if (id == 0) - id = ReadID(LCD_READ_ID); + id = readID(LCD_READ_ID); if ((id & 0xFFFF) == 0 || (id & 0xFFFF) == 0xFFFF) - id = ReadID(LCD_READ_ID4); + id = readID(LCD_READ_ID4); return id; } -uint32_t TFT_FSMC::ReadID(tft_data_t Reg) { +uint32_t TFT_FSMC::readID(const tft_data_t inReg) { uint32_t id; - WriteReg(Reg); + writeReg(inReg); id = LCD->RAM; // dummy read - id = Reg << 24; + id = inReg << 24; id |= (LCD->RAM & 0x00FF) << 16; id |= (LCD->RAM & 0x00FF) << 8; id |= LCD->RAM & 0x00FF; @@ -148,26 +148,43 @@ uint32_t TFT_FSMC::ReadID(tft_data_t Reg) { bool TFT_FSMC::isBusy() { #ifdef STM32F1xx - volatile bool dmaEnabled = (DMAtx.Instance->CCR & DMA_CCR_EN) != RESET; + #define __IS_DMA_ENABLED(__HANDLE__) ((__HANDLE__)->Instance->CCR & DMA_CCR_EN) + #define __IS_DMA_CONFIGURED(__HANDLE__) ((__HANDLE__)->Instance->CPAR != 0) #elif defined(STM32F4xx) - volatile bool dmaEnabled = DMAtx.Instance->CR & DMA_SxCR_EN; + #define __IS_DMA_ENABLED(__HANDLE__) ((__HANDLE__)->Instance->CR & DMA_SxCR_EN) + #define __IS_DMA_CONFIGURED(__HANDLE__) ((__HANDLE__)->Instance->PAR != 0) #endif - if (dmaEnabled) { - if (__HAL_DMA_GET_FLAG(&DMAtx, __HAL_DMA_GET_TC_FLAG_INDEX(&DMAtx)) != 0 || __HAL_DMA_GET_FLAG(&DMAtx, __HAL_DMA_GET_TE_FLAG_INDEX(&DMAtx)) != 0) - Abort(); - } - else - Abort(); - return dmaEnabled; + + if (!__IS_DMA_CONFIGURED(&DMAtx)) return false; + + // Check if DMA transfer error or transfer complete flags are set + if ((__HAL_DMA_GET_FLAG(&DMAtx, __HAL_DMA_GET_TE_FLAG_INDEX(&DMAtx)) == 0) && (__HAL_DMA_GET_FLAG(&DMAtx, __HAL_DMA_GET_TC_FLAG_INDEX(&DMAtx)) == 0)) return true; + + __DSB(); + abort(); + return false; } -void TFT_FSMC::TransmitDMA(uint32_t MemoryIncrease, uint16_t *Data, uint16_t Count) { - DMAtx.Init.PeriphInc = MemoryIncrease; +void TFT_FSMC::abort() { + HAL_DMA_Abort(&DMAtx); // Abort DMA transfer if any + HAL_DMA_DeInit(&DMAtx); // Deconfigure DMA +} + +void TFT_FSMC::transmitDMA(uint32_t memoryIncrease, uint16_t *data, uint16_t count) { + DMAtx.Init.PeriphInc = memoryIncrease; HAL_DMA_Init(&DMAtx); - DataTransferBegin(); - HAL_DMA_Start(&DMAtx, (uint32_t)Data, (uint32_t)&(LCD->RAM), Count); + HAL_DMA_Start(&DMAtx, (uint32_t)data, (uint32_t)&(LCD->RAM), count); + + TERN_(TFT_SHARED_IO, while (isBusy())); +} + +void TFT_FSMC::transmit(uint32_t memoryIncrease, uint16_t *data, uint16_t count) { + DMAtx.Init.PeriphInc = memoryIncrease; + HAL_DMA_Init(&DMAtx); + dataTransferBegin(); + HAL_DMA_Start(&DMAtx, (uint32_t)data, (uint32_t)&(LCD->RAM), count); HAL_DMA_PollForTransfer(&DMAtx, HAL_DMA_FULL_TRANSFER, HAL_MAX_DELAY); - Abort(); + abort(); } #endif // HAS_FSMC_TFT diff --git a/Marlin/src/HAL/STM32/tft/tft_fsmc.h b/Marlin/src/HAL/STM32/tft/tft_fsmc.h index 2200abaa10..1776cbdb0f 100644 --- a/Marlin/src/HAL/STM32/tft/tft_fsmc.h +++ b/Marlin/src/HAL/STM32/tft/tft_fsmc.h @@ -31,6 +31,10 @@ #error "FSMC TFT is currently only supported on STM32F1 and STM32F4 hardware." #endif +#ifndef HAL_SRAM_MODULE_ENABLED + #error "SRAM module disabled for the STM32 framework (HAL_SRAM_MODULE_ENABLED)! Please consult the development team." +#endif + #ifndef LCD_READ_ID #define LCD_READ_ID 0x04 // Read display identification information (0xD3 on ILI9341) #endif @@ -41,6 +45,7 @@ #define DATASIZE_8BIT SPI_DATASIZE_8BIT #define DATASIZE_16BIT SPI_DATASIZE_16BIT #define TFT_IO_DRIVER TFT_FSMC +#define DMA_MAX_WORDS 0xFFFF #define TFT_DATASIZE TERN(TFT_INTERFACE_FSMC_8BIT, DATASIZE_8BIT, DATASIZE_16BIT) typedef TERN(TFT_INTERFACE_FSMC_8BIT, uint8_t, uint16_t) tft_data_t; @@ -57,29 +62,31 @@ class TFT_FSMC { static LCD_CONTROLLER_TypeDef *LCD; - static uint32_t ReadID(tft_data_t Reg); - static void Transmit(tft_data_t Data) { LCD->RAM = Data; __DSB(); } - static void TransmitDMA(uint32_t MemoryIncrease, uint16_t *Data, uint16_t Count); + static uint32_t readID(const tft_data_t reg); + static void transmit(tft_data_t data) { LCD->RAM = data; __DSB(); } + static void transmit(uint32_t memoryIncrease, uint16_t *data, uint16_t count); + static void transmitDMA(uint32_t memoryIncrease, uint16_t *data, uint16_t count); public: - static void Init(); - static uint32_t GetID(); + static void init(); + static uint32_t getID(); static bool isBusy(); - static void Abort() { __HAL_DMA_DISABLE(&DMAtx); } + static void abort(); - static void DataTransferBegin(uint16_t DataWidth = TFT_DATASIZE) {} - static void DataTransferEnd() {}; + static void dataTransferBegin(uint16_t dataWidth=TFT_DATASIZE) {} + static void dataTransferEnd() {} - static void WriteData(uint16_t Data) { Transmit(tft_data_t(Data)); } - static void WriteReg(uint16_t Reg) { LCD->REG = tft_data_t(Reg); __DSB(); } + static void writeData(uint16_t data) { transmit(tft_data_t(data)); } + static void writeReg(const uint16_t inReg) { LCD->REG = tft_data_t(inReg); __DSB(); } - static void WriteSequence(uint16_t *Data, uint16_t Count) { TransmitDMA(DMA_PINC_ENABLE, Data, Count); } - static void WriteMultiple(uint16_t Color, uint16_t Count) { static uint16_t Data; Data = Color; TransmitDMA(DMA_PINC_DISABLE, &Data, Count); } - static void WriteMultiple(uint16_t Color, uint32_t Count) { - static uint16_t Data; Data = Color; - while (Count > 0) { - TransmitDMA(DMA_MINC_DISABLE, &Data, Count > 0xFFFF ? 0xFFFF : Count); - Count = Count > 0xFFFF ? Count - 0xFFFF : 0; + static void writeSequence_DMA(uint16_t *data, uint16_t count) { transmitDMA(DMA_PINC_ENABLE, data, count); } + static void writeMultiple_DMA(uint16_t color, uint16_t count) { static uint16_t data; data = color; transmitDMA(DMA_PINC_DISABLE, &data, count); } + + static void writeSequence(uint16_t *data, uint16_t count) { transmit(DMA_PINC_ENABLE, data, count); } + static void writeMultiple(uint16_t color, uint32_t count) { + while (count > 0) { + transmit(DMA_MINC_DISABLE, &color, count > DMA_MAX_WORDS ? DMA_MAX_WORDS : count); + count = count > DMA_MAX_WORDS ? count - DMA_MAX_WORDS : 0; } } }; @@ -96,7 +103,7 @@ class TFT_FSMC { #error No configuration for this MCU #endif -const PinMap PinMap_FSMC[] = { +const PinMap pinMap_FSMC[] = { {PD_14, FSMC_NORSRAM_DEVICE, FSMC_PIN_DATA}, // FSMC_D00 {PD_15, FSMC_NORSRAM_DEVICE, FSMC_PIN_DATA}, // FSMC_D01 {PD_0, FSMC_NORSRAM_DEVICE, FSMC_PIN_DATA}, // FSMC_D02 @@ -120,7 +127,7 @@ const PinMap PinMap_FSMC[] = { {NC, NP, 0} }; -const PinMap PinMap_FSMC_CS[] = { +const PinMap pinMap_FSMC_CS[] = { {PD_7, (void *)FSMC_NORSRAM_BANK1, FSMC_PIN_DATA}, // FSMC_NE1 #ifdef PF0 {PG_9, (void *)FSMC_NORSRAM_BANK2, FSMC_PIN_DATA}, // FSMC_NE2 @@ -136,7 +143,7 @@ const PinMap PinMap_FSMC_CS[] = { #define FSMC_RS(A) (void *)((2 << A) - 2) #endif -const PinMap PinMap_FSMC_RS[] = { +const PinMap pinMap_FSMC_RS[] = { #ifdef PF0 {PF_0, FSMC_RS( 0), FSMC_PIN_DATA}, // FSMC_A0 {PF_1, FSMC_RS( 1), FSMC_PIN_DATA}, // FSMC_A1 diff --git a/Marlin/src/HAL/STM32/tft/tft_ltdc.cpp b/Marlin/src/HAL/STM32/tft/tft_ltdc.cpp index 95871bf41f..3bbc39f20a 100644 --- a/Marlin/src/HAL/STM32/tft/tft_ltdc.cpp +++ b/Marlin/src/HAL/STM32/tft/tft_ltdc.cpp @@ -246,28 +246,28 @@ uint16_t TFT_LTDC::y_cur = 0; uint8_t TFT_LTDC::reg = 0; volatile uint16_t* TFT_LTDC::framebuffer = (volatile uint16_t* )FRAME_BUFFER_ADDRESS; -void TFT_LTDC::Init() { +void TFT_LTDC::init() { // SDRAM pins init - for (uint16_t i = 0; PinMap_SDRAM[i].pin != NC; i++) - pinmap_pinout(PinMap_SDRAM[i].pin, PinMap_SDRAM); + for (uint16_t i = 0; pinMap_SDRAM[i].pin != NC; i++) + pinmap_pinout(pinMap_SDRAM[i].pin, pinMap_SDRAM); // SDRAM peripheral config SDRAM_Config(); // LTDC pins init - for (uint16_t i = 0; PinMap_LTDC[i].pin != NC; i++) - pinmap_pinout(PinMap_LTDC[i].pin, PinMap_LTDC); + for (uint16_t i = 0; pinMap_LTDC[i].pin != NC; i++) + pinmap_pinout(pinMap_LTDC[i].pin, pinMap_LTDC); // LTDC peripheral config LTDC_Config(); } -uint32_t TFT_LTDC::GetID() { +uint32_t TFT_LTDC::getID() { return 0xABAB; } -uint32_t TFT_LTDC::ReadID(tft_data_t Reg) { +uint32_t TFT_LTDC::readID(const tft_data_t inReg) { return 0xABAB; } @@ -275,15 +275,15 @@ bool TFT_LTDC::isBusy() { return false; } -uint16_t TFT_LTDC::ReadPoint(uint16_t x, uint16_t y) { +uint16_t TFT_LTDC::readPoint(uint16_t x, uint16_t y) { return framebuffer[(TFT_WIDTH * y) + x]; } -void TFT_LTDC::DrawPoint(uint16_t x, uint16_t y, uint16_t color) { +void TFT_LTDC::drawPoint(uint16_t x, uint16_t y, uint16_t color) { framebuffer[(TFT_WIDTH * y) + x] = color; } -void TFT_LTDC::DrawRect(uint16_t sx, uint16_t sy, uint16_t ex, uint16_t ey, uint16_t color) { +void TFT_LTDC::drawRect(uint16_t sx, uint16_t sy, uint16_t ex, uint16_t ey, uint16_t color) { if (sx == ex || sy == ey) return; @@ -307,7 +307,7 @@ void TFT_LTDC::DrawRect(uint16_t sx, uint16_t sy, uint16_t ex, uint16_t ey, uint SBI(DMA2D->IFCR, 1); } -void TFT_LTDC::DrawImage(uint16_t sx, uint16_t sy, uint16_t ex, uint16_t ey, uint16_t *colors) { +void TFT_LTDC::drawImage(uint16_t sx, uint16_t sy, uint16_t ex, uint16_t ey, uint16_t *colors) { if (sx == ex || sy == ey) return; @@ -332,18 +332,18 @@ void TFT_LTDC::DrawImage(uint16_t sx, uint16_t sy, uint16_t ex, uint16_t ey, uin SBI(DMA2D->IFCR, 1); } -void TFT_LTDC::WriteData(uint16_t data) { +void TFT_LTDC::writeData(uint16_t data) { switch (reg) { case 0x01: x_cur = x_min = data; return; case 0x02: x_max = data; return; case 0x03: y_cur = y_min = data; return; case 0x04: y_max = data; return; } - Transmit(data); + transmit(data); } -void TFT_LTDC::Transmit(tft_data_t Data) { - DrawPoint(x_cur, y_cur, Data); +void TFT_LTDC::transmit(tft_data_t data) { + drawPoint(x_cur, y_cur, data); x_cur++; if (x_cur > x_max) { x_cur = x_min; @@ -352,35 +352,31 @@ void TFT_LTDC::Transmit(tft_data_t Data) { } } -void TFT_LTDC::WriteReg(uint16_t Reg) { - reg = Reg; -} +void TFT_LTDC::transmit(uint32_t memoryIncrease, uint16_t *data, uint16_t count) { -void TFT_LTDC::TransmitDMA(uint32_t MemoryIncrease, uint16_t *Data, uint16_t Count) { - - while (x_cur != x_min && Count) { - Transmit(*Data); - if (MemoryIncrease == DMA_PINC_ENABLE) Data++; - Count--; + while (x_cur != x_min && count) { + transmit(*data); + if (memoryIncrease == DMA_PINC_ENABLE) data++; + count--; } uint16_t width = x_max - x_min + 1; - uint16_t height = Count / width; - uint16_t x_end_cnt = Count - (width * height); + uint16_t height = count / width; + uint16_t x_end_cnt = count - (width * height); if (height) { - if (MemoryIncrease == DMA_PINC_ENABLE) { - DrawImage(x_min, y_cur, x_min + width, y_cur + height, Data); - Data += width * height; + if (memoryIncrease == DMA_PINC_ENABLE) { + drawImage(x_min, y_cur, x_min + width, y_cur + height, data); + data += width * height; } else - DrawRect(x_min, y_cur, x_min + width, y_cur + height, *Data); + drawRect(x_min, y_cur, x_min + width, y_cur + height, *data); y_cur += height; } while (x_end_cnt) { - Transmit(*Data); - if (MemoryIncrease == DMA_PINC_ENABLE) Data++; + transmit(*data); + if (memoryIncrease == DMA_PINC_ENABLE) data++; x_end_cnt--; } } diff --git a/Marlin/src/HAL/STM32/tft/tft_ltdc.h b/Marlin/src/HAL/STM32/tft/tft_ltdc.h index 7b63d6929b..90cc58d8a5 100644 --- a/Marlin/src/HAL/STM32/tft/tft_ltdc.h +++ b/Marlin/src/HAL/STM32/tft/tft_ltdc.h @@ -32,6 +32,7 @@ #define DATASIZE_8BIT SPI_DATASIZE_8BIT #define DATASIZE_16BIT SPI_DATASIZE_16BIT #define TFT_IO_DRIVER TFT_LTDC +#define DMA_MAX_WORDS 0xFFFF #define TFT_DATASIZE DATASIZE_16BIT typedef uint16_t tft_data_t; @@ -42,39 +43,41 @@ class TFT_LTDC { static uint16_t x_min, x_max, y_min, y_max, x_cur, y_cur; static uint8_t reg; - static uint32_t ReadID(tft_data_t Reg); + static uint32_t readID(const tft_data_t inReg); - static uint16_t ReadPoint(uint16_t x, uint16_t y); - static void DrawPoint(uint16_t x, uint16_t y, uint16_t color); - static void DrawRect(uint16_t sx, uint16_t sy, uint16_t ex, uint16_t ey, uint16_t color); - static void DrawImage(uint16_t sx, uint16_t sy, uint16_t ex, uint16_t ey, uint16_t *colors); - static void Transmit(tft_data_t Data); - static void TransmitDMA(uint32_t MemoryIncrease, uint16_t *Data, uint16_t Count); + static uint16_t readPoint(uint16_t x, uint16_t y); + static void drawPoint(uint16_t x, uint16_t y, uint16_t color); + static void drawRect(uint16_t sx, uint16_t sy, uint16_t ex, uint16_t ey, uint16_t color); + static void drawImage(uint16_t sx, uint16_t sy, uint16_t ex, uint16_t ey, uint16_t *colors); + static void transmit(tft_data_t data); + static void transmit(uint32_t memoryIncrease, uint16_t *data, uint16_t count); public: - static void Init(); - static uint32_t GetID(); + static void init(); + static uint32_t getID(); static bool isBusy(); - static void Abort() { /*__HAL_DMA_DISABLE(&DMAtx);*/ } + static void abort() { /*__HAL_DMA_DISABLE(&DMAtx);*/ } - static void DataTransferBegin(uint16_t DataWidth = TFT_DATASIZE) {} - static void DataTransferEnd() {}; + static void dataTransferBegin(uint16_t dataWidth=TFT_DATASIZE) {} + static void dataTransferEnd() {}; - static void WriteData(uint16_t Data); - static void WriteReg(uint16_t Reg); + static void writeData(uint16_t data); + static void writeReg(const uint16_t inReg) { reg = inReg; } - static void WriteSequence(uint16_t *Data, uint16_t Count) { TransmitDMA(DMA_PINC_ENABLE, Data, Count); } - static void WriteMultiple(uint16_t Color, uint16_t Count) { static uint16_t Data; Data = Color; TransmitDMA(DMA_PINC_DISABLE, &Data, Count); } - static void WriteMultiple(uint16_t Color, uint32_t Count) { - static uint16_t Data; Data = Color; - while (Count > 0) { - TransmitDMA(DMA_MINC_DISABLE, &Data, Count > 0xFFFF ? 0xFFFF : Count); - Count = Count > 0xFFFF ? Count - 0xFFFF : 0; + // Non-blocking DMA data transfer is not implemented for LTDC interface + inline static void writeSequence_DMA(uint16_t *data, uint16_t count) { writeSequence(data, count); } + inline static void writeMultiple_DMA(uint16_t color, uint16_t count) { writeMultiple(color, count); } + + static void writeSequence(uint16_t *data, uint16_t count) { transmit(DMA_PINC_ENABLE, data, count); } + static void writeMultiple(uint16_t color, uint32_t count) { + while (count > 0) { + transmit(DMA_PINC_DISABLE, &color, count > DMA_MAX_WORDS ? DMA_MAX_WORDS : count); + count = count > DMA_MAX_WORDS ? count - DMA_MAX_WORDS : 0; } } }; -const PinMap PinMap_LTDC[] = { +const PinMap pinMap_LTDC[] = { {PF_10, LTDC, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF14_LTDC)}, // LCD_DE {PG_7, LTDC, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF14_LTDC)}, // LCD_CLK {PI_9, LTDC, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF14_LTDC)}, // LCD_VSYNC @@ -101,7 +104,7 @@ const PinMap PinMap_LTDC[] = { {NC, NP, 0} }; -const PinMap PinMap_SDRAM[] = { +const PinMap pinMap_SDRAM[] = { {PC_0, FMC_Bank1_R, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF12_FMC)}, // FMC_SDNWE {PC_2, FMC_Bank1_R, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF12_FMC)}, // FMC_SDNE0 {PC_3, FMC_Bank1_R, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF12_FMC)}, // FMC_SDCKE0 diff --git a/Marlin/src/HAL/STM32/tft/tft_spi.cpp b/Marlin/src/HAL/STM32/tft/tft_spi.cpp index e455164c77..cca247e20d 100644 --- a/Marlin/src/HAL/STM32/tft/tft_spi.cpp +++ b/Marlin/src/HAL/STM32/tft/tft_spi.cpp @@ -34,7 +34,7 @@ SPI_HandleTypeDef TFT_SPI::SPIx; DMA_HandleTypeDef TFT_SPI::DMAtx; -void TFT_SPI::Init() { +void TFT_SPI::init() { SPI_TypeDef *spiInstance; OUT_WRITE(TFT_A0_PIN, HIGH); @@ -52,7 +52,6 @@ void TFT_SPI::Init() { SPIx.Init.NSS = SPI_NSS_SOFT; SPIx.Init.Mode = SPI_MODE_MASTER; SPIx.Init.Direction = (TFT_MISO_PIN == TFT_MOSI_PIN) ? SPI_DIRECTION_1LINE : SPI_DIRECTION_2LINES; - SPIx.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_2; SPIx.Init.CLKPhase = SPI_PHASE_1EDGE; SPIx.Init.CLKPolarity = SPI_POLARITY_LOW; SPIx.Init.DataSize = SPI_DATASIZE_8BIT; @@ -61,12 +60,25 @@ void TFT_SPI::Init() { SPIx.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE; SPIx.Init.CRCPolynomial = 10; + #ifndef STM32H7xx + SPIx.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_2; // 18 MBit/s for F103, 21 MBit/s for F407, 25 MBit/s for F411 + #else + SPIx.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_4; // 20 MBit/s for H743 + SPIx.Init.NSSPMode = SPI_NSS_PULSE_ENABLE; + SPIx.Init.NSSPolarity = SPI_NSS_POLARITY_LOW; + SPIx.Init.FifoThreshold = SPI_FIFO_THRESHOLD_01DATA; + SPIx.Init.MasterSSIdleness = SPI_MASTER_SS_IDLENESS_00CYCLE; + SPIx.Init.MasterInterDataIdleness = SPI_MASTER_INTERDATA_IDLENESS_00CYCLE; + SPIx.Init.MasterReceiverAutoSusp = SPI_MASTER_RX_AUTOSUSP_DISABLE; + SPIx.Init.MasterKeepIOState = SPI_MASTER_KEEP_IO_STATE_ENABLE; + SPIx.Init.IOSwap = SPI_IO_SWAP_DISABLE; + #endif + pinmap_pinout(digitalPinToPinName(TFT_SCK_PIN), PinMap_SPI_SCLK); pinmap_pinout(digitalPinToPinName(TFT_MOSI_PIN), PinMap_SPI_MOSI); #if PIN_EXISTS(TFT_MISO) && TFT_MISO_PIN != TFT_MOSI_PIN pinmap_pinout(digitalPinToPinName(TFT_MISO_PIN), PinMap_SPI_MISO); #endif - pin_PullConfig(get_GPIO_Port(STM_PORT(digitalPinToPinName(TFT_SCK_PIN))), STM_LL_GPIO_PIN(digitalPinToPinName(TFT_SCK_PIN)), GPIO_PULLDOWN); #ifdef SPI1_BASE if (SPIx.Instance == SPI1) { @@ -74,12 +86,17 @@ void TFT_SPI::Init() { #ifdef STM32F1xx __HAL_RCC_DMA1_CLK_ENABLE(); DMAtx.Instance = DMA1_Channel3; + SPIx.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_4; // SPI1 clock on F1 and F4 is two times faster than SPI2 and SPI3 clock #elif defined(STM32F4xx) __HAL_RCC_DMA2_CLK_ENABLE(); DMAtx.Instance = DMA2_Stream3; DMAtx.Init.Channel = DMA_CHANNEL_3; + SPIx.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_4; // SPI1 clock on F1 and F4 is two times faster than SPI2 and SPI3 clock + #elif defined(STM32H7xx) + __HAL_RCC_DMA1_CLK_ENABLE(); + DMAtx.Instance = DMA1_Stream4; + DMAtx.Init.Request = DMA_REQUEST_SPI1_TX; #endif - SPIx.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_4; } #endif #ifdef SPI2_BASE @@ -92,6 +109,10 @@ void TFT_SPI::Init() { __HAL_RCC_DMA1_CLK_ENABLE(); DMAtx.Instance = DMA1_Stream4; DMAtx.Init.Channel = DMA_CHANNEL_0; + #elif defined(STM32H7xx) + __HAL_RCC_DMA1_CLK_ENABLE(); + DMAtx.Instance = DMA1_Stream4; + DMAtx.Init.Request = DMA_REQUEST_SPI2_TX; #endif } #endif @@ -105,25 +126,27 @@ void TFT_SPI::Init() { __HAL_RCC_DMA1_CLK_ENABLE(); DMAtx.Instance = DMA1_Stream5; DMAtx.Init.Channel = DMA_CHANNEL_0; + #elif defined(STM32H7xx) + __HAL_RCC_DMA1_CLK_ENABLE(); + DMAtx.Instance = DMA1_Stream4; + DMAtx.Init.Request = DMA_REQUEST_SPI3_TX; #endif } #endif - HAL_SPI_Init(&SPIx); - DMAtx.Init.Direction = DMA_MEMORY_TO_PERIPH; DMAtx.Init.PeriphInc = DMA_PINC_DISABLE; DMAtx.Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD; DMAtx.Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD; DMAtx.Init.Mode = DMA_NORMAL; DMAtx.Init.Priority = DMA_PRIORITY_LOW; - #ifdef STM32F4xx + #if ANY(STM32F4xx, STM32H7xx) DMAtx.Init.FIFOMode = DMA_FIFOMODE_DISABLE; #endif } -void TFT_SPI::DataTransferBegin(uint16_t DataSize) { - SPIx.Init.DataSize = DataSize == DATASIZE_8BIT ? SPI_DATASIZE_8BIT : SPI_DATASIZE_16BIT; +void TFT_SPI::dataTransferBegin(uint16_t dataSize) { + SPIx.Init.DataSize = dataSize; HAL_SPI_Init(&SPIx); WRITE(TFT_CS_PIN, LOW); } @@ -132,11 +155,11 @@ void TFT_SPI::DataTransferBegin(uint16_t DataSize) { #include "../../../lcd/tft_io/tft_ids.h" #endif -uint32_t TFT_SPI::GetID() { +uint32_t TFT_SPI::getID() { uint32_t id; - id = ReadID(LCD_READ_ID); + id = readID(LCD_READ_ID); if ((id & 0xFFFF) == 0 || (id & 0xFFFF) == 0xFFFF) { - id = ReadID(LCD_READ_ID4); + id = readID(LCD_READ_ID4); #ifdef TFT_DEFAULT_DRIVER if ((id & 0xFFFF) == 0 || (id & 0xFFFF) == 0xFFFF) id = TFT_DEFAULT_DRIVER; @@ -145,125 +168,189 @@ uint32_t TFT_SPI::GetID() { return id; } -uint32_t TFT_SPI::ReadID(uint16_t Reg) { - uint32_t Data = 0; +uint32_t TFT_SPI::readID(const uint16_t inReg) { + uint32_t data = 0; #if PIN_EXISTS(TFT_MISO) - uint32_t BaudRatePrescaler = SPIx.Init.BaudRatePrescaler; - uint32_t i; + const uint32_t oldPrescaler = SPIx.Init.BaudRatePrescaler; - SPIx.Init.BaudRatePrescaler = SPIx.Instance == SPI1 ? SPI_BAUDRATEPRESCALER_8 : SPI_BAUDRATEPRESCALER_4; - DataTransferBegin(DATASIZE_8BIT); - WriteReg(Reg); + SPIx.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_64; + dataTransferBegin(DATASIZE_8BIT); + writeReg(inReg); if (SPIx.Init.Direction == SPI_DIRECTION_1LINE) SPI_1LINE_RX(&SPIx); - __HAL_SPI_ENABLE(&SPIx); - for (i = 0; i < 4; i++) { - #if TFT_MISO_PIN != TFT_MOSI_PIN - //if (hspi->Init.Direction == SPI_DIRECTION_2LINES) { + #ifdef STM32H7xx + for (uint32_t i = 0; i < 4; i++) { + MODIFY_REG(SPIx.Instance->CR2, SPI_CR2_TSIZE, 1); + __HAL_SPI_ENABLE(&SPIx); + SET_BIT(SPIx.Instance->CR1, SPI_CR1_CSTART); + + #if TFT_MISO_PIN != TFT_MOSI_PIN + SPIx.Instance->TXDR = 0; + #endif + while (!__HAL_SPI_GET_FLAG(&SPIx, SPI_FLAG_EOT)) {} + data = (data << 8) | SPIx.Instance->RXDR; + __HAL_SPI_DISABLE(&SPIx); + __HAL_SPI_CLEAR_EOTFLAG(&SPIx); + __HAL_SPI_CLEAR_TXTFFLAG(&SPIx); + } + #else + __HAL_SPI_ENABLE(&SPIx); + for (uint32_t i = 0; i < 4; i++) { + #if TFT_MISO_PIN != TFT_MOSI_PIN while (!__HAL_SPI_GET_FLAG(&SPIx, SPI_FLAG_TXE)) {} SPIx.Instance->DR = 0; - //} - #endif - while (!__HAL_SPI_GET_FLAG(&SPIx, SPI_FLAG_RXNE)) {} - Data = (Data << 8) | SPIx.Instance->DR; - } + #endif + while (!__HAL_SPI_GET_FLAG(&SPIx, SPI_FLAG_RXNE)) {} + data = (data << 8) | SPIx.Instance->DR; + } + #endif - __HAL_SPI_DISABLE(&SPIx); - DataTransferEnd(); - - SPIx.Init.BaudRatePrescaler = BaudRatePrescaler; + dataTransferEnd(); + SPIx.Init.BaudRatePrescaler = oldPrescaler; #endif - return Data >> 7; + return data >> 7; } bool TFT_SPI::isBusy() { #ifdef STM32F1xx - volatile bool dmaEnabled = (DMAtx.Instance->CCR & DMA_CCR_EN) != RESET; + #define __IS_DMA_ENABLED(__HANDLE__) ((__HANDLE__)->Instance->CCR & DMA_CCR_EN) + #define __IS_DMA_CONFIGURED(__HANDLE__) ((__HANDLE__)->Instance->CPAR != 0) #elif defined(STM32F4xx) - volatile bool dmaEnabled = DMAtx.Instance->CR & DMA_SxCR_EN; + #define __IS_DMA_ENABLED(__HANDLE__) ((__HANDLE__)->Instance->CR & DMA_SxCR_EN) + #define __IS_DMA_CONFIGURED(__HANDLE__) ((__HANDLE__)->Instance->PAR != 0) + #elif defined(STM32H7xx) + #define __IS_DMA_ENABLED(__HANDLE__) (((DMA_Stream_TypeDef *)((__HANDLE__)->Instance))->CR & DMA_SxCR_EN) + #define __IS_DMA_CONFIGURED(__HANDLE__) (((DMA_Stream_TypeDef *)((__HANDLE__)->Instance))->PAR != 0) #endif - if (dmaEnabled) { - if (__HAL_DMA_GET_FLAG(&DMAtx, __HAL_DMA_GET_TC_FLAG_INDEX(&DMAtx)) != 0 || __HAL_DMA_GET_FLAG(&DMAtx, __HAL_DMA_GET_TE_FLAG_INDEX(&DMAtx)) != 0) - Abort(); + + if (!__IS_DMA_CONFIGURED(&DMAtx)) return false; + + if (__HAL_DMA_GET_FLAG(&DMAtx, __HAL_DMA_GET_TE_FLAG_INDEX(&DMAtx))) { + // You should not be here - DMA transfer error flag is set + // Abort DMA transfer and release SPI } - else - Abort(); - return dmaEnabled; + else { + // Check if DMA transfer completed flag is set + if (__HAL_DMA_GET_FLAG(&DMAtx, __HAL_DMA_GET_TC_FLAG_INDEX(&DMAtx)) == 0) return true; + #ifdef STM32H7xx + // Check if SPI data transfer is completed + if (!__HAL_SPI_GET_FLAG(&SPIx, SPI_FLAG_EOT)) return true; + #else + // Check if SPI is idle + if (__HAL_SPI_GET_FLAG(&SPIx, SPI_FLAG_BSY)) return true; + #endif + } + + abort(); + return false; } -void TFT_SPI::Abort() { - // Wait for any running spi - while (!__HAL_SPI_GET_FLAG(&SPIx, SPI_FLAG_TXE)) {} - while ( __HAL_SPI_GET_FLAG(&SPIx, SPI_FLAG_BSY)) {} - // First, abort any running dma - HAL_DMA_Abort(&DMAtx); - // DeInit objects +void TFT_SPI::abort() { + HAL_DMA_Abort(&DMAtx); // Abort DMA transfer if any HAL_DMA_DeInit(&DMAtx); - HAL_SPI_DeInit(&SPIx); - // Deselect CS - DataTransferEnd(); + + #ifdef STM32H7xx + CLEAR_BIT(SPIx.Instance->CFG1, SPI_CFG1_TXDMAEN); + __HAL_SPI_CLEAR_EOTFLAG(&SPIx); + __HAL_SPI_CLEAR_TXTFFLAG(&SPIx); + #else + CLEAR_BIT(SPIx.Instance->CR2, SPI_CR2_TXDMAEN); + #endif + + dataTransferEnd(); // Stop SPI and deselect CS } -void TFT_SPI::Transmit(uint16_t Data) { - if (TFT_MISO_PIN == TFT_MOSI_PIN) +void TFT_SPI::transmit(uint16_t data) { + #if TFT_MISO_PIN == TFT_MOSI_PIN SPI_1LINE_TX(&SPIx); + #endif - __HAL_SPI_ENABLE(&SPIx); + #ifdef STM32H7xx + MODIFY_REG(SPIx.Instance->CR2, SPI_CR2_TSIZE, 1); + __HAL_SPI_ENABLE(&SPIx); + SET_BIT(SPIx.Instance->CR1, SPI_CR1_CSTART); - SPIx.Instance->DR = Data; + SPIx.Instance->TXDR = data; - while (!__HAL_SPI_GET_FLAG(&SPIx, SPI_FLAG_TXE)) {} - while ( __HAL_SPI_GET_FLAG(&SPIx, SPI_FLAG_BSY)) {} + while (!__HAL_SPI_GET_FLAG(&SPIx, SPI_SR_EOT)) {} - if (TFT_MISO_PIN != TFT_MOSI_PIN) - __HAL_SPI_CLEAR_OVRFLAG(&SPIx); // Clear overrun flag in 2 Lines communication mode because received is not read + __HAL_SPI_CLEAR_EOTFLAG(&SPIx); + __HAL_SPI_CLEAR_TXTFFLAG(&SPIx); + #else + __HAL_SPI_ENABLE(&SPIx); + SPIx.Instance->DR = data; + while (__HAL_SPI_GET_FLAG(&SPIx, SPI_FLAG_BSY)) {} + #endif + + __HAL_SPI_DISABLE(&SPIx); + + #if TFT_MISO_PIN != TFT_MOSI_PIN + __HAL_SPI_CLEAR_OVRFLAG(&SPIx); // Clear overrun flag in 2 Lines communication mode because received data is not read + #endif } -void TFT_SPI::TransmitDMA(uint32_t MemoryIncrease, uint16_t *Data, uint16_t Count) { - // Wait last dma finish, to start another - while (isBusy()) { /* nada */ } - - DMAtx.Init.MemInc = MemoryIncrease; +void TFT_SPI::transmitDMA(uint32_t memoryIncrease, uint16_t *data, uint16_t count) { + DMAtx.Init.MemInc = memoryIncrease; HAL_DMA_Init(&DMAtx); - if (TFT_MISO_PIN == TFT_MOSI_PIN) + #if TFT_MISO_PIN == TFT_MOSI_PIN SPI_1LINE_TX(&SPIx); + #endif - DataTransferBegin(); + dataTransferBegin(); - HAL_DMA_Start(&DMAtx, (uint32_t)Data, (uint32_t)&(SPIx.Instance->DR), Count); - __HAL_SPI_ENABLE(&SPIx); + #ifdef STM32H7xx + HAL_DMA_Start(&DMAtx, (uint32_t)data, (uint32_t)&(SPIx.Instance->TXDR), count); - SET_BIT(SPIx.Instance->CR2, SPI_CR2_TXDMAEN); // Enable Tx DMA Request + CLEAR_BIT(SPIx.Instance->CFG1, SPI_CFG1_TXDMAEN); + MODIFY_REG(SPIx.Instance->CR2, SPI_CR2_TSIZE, count); + SET_BIT(SPIx.Instance->CFG1, SPI_CFG1_TXDMAEN); // Enable Tx DMA Request + __HAL_SPI_ENABLE(&SPIx); + SET_BIT(SPIx.Instance->CR1, SPI_CR1_CSTART); + #else + HAL_DMA_Start(&DMAtx, (uint32_t)data, (uint32_t)&(SPIx.Instance->DR), count); + + __HAL_SPI_ENABLE(&SPIx); + SET_BIT(SPIx.Instance->CR2, SPI_CR2_TXDMAEN); // Enable Tx DMA Request + #endif + + TERN_(TFT_SHARED_IO, while (isBusy())); +} + +void TFT_SPI::transmit(uint32_t memoryIncrease, uint16_t *data, uint16_t count) { + transmitDMA(memoryIncrease, data, count); HAL_DMA_PollForTransfer(&DMAtx, HAL_DMA_FULL_TRANSFER, HAL_MAX_DELAY); - Abort(); + #ifdef STM32H7xx + while (!__HAL_SPI_GET_FLAG(&SPIx, SPI_SR_EOT)) {} + #else + while (__HAL_SPI_GET_FLAG(&SPIx, SPI_FLAG_BSY)) {} + #endif + abort(); } #if ENABLED(USE_SPI_DMA_TC) + void TFT_SPI::transmitDMA_IT(uint32_t memoryIncrease, uint16_t *data, uint16_t count) { - void TFT_SPI::TransmitDMA_IT(uint32_t MemoryIncrease, uint16_t *Data, uint16_t Count) { - - DMAtx.Init.MemInc = MemoryIncrease; + DMAtx.Init.MemInc = memoryIncrease; HAL_DMA_Init(&DMAtx); if (TFT_MISO_PIN == TFT_MOSI_PIN) SPI_1LINE_TX(&SPIx); - DataTransferBegin(); + dataTransferBegin(); HAL_NVIC_SetPriority(DMA2_Stream3_IRQn, 5, 0); HAL_NVIC_EnableIRQ(DMA2_Stream3_IRQn); - HAL_DMA_Start_IT(&DMAtx, (uint32_t)Data, (uint32_t)&(SPIx.Instance->DR), Count); + HAL_DMA_Start_IT(&DMAtx, (uint32_t)data, (uint32_t)&(SPIx.Instance->DR), count); __HAL_SPI_ENABLE(&SPIx); SET_BIT(SPIx.Instance->CR2, SPI_CR2_TXDMAEN); // Enable Tx DMA Request } - extern "C" void DMA2_Stream3_IRQHandler(void) { HAL_DMA_IRQHandler(&TFT_SPI::DMAtx); } - + extern "C" void DMA2_Stream3_IRQHandler(void) { TFT_SPI::DMA_IRQHandler(); } #endif #endif // HAS_SPI_TFT diff --git a/Marlin/src/HAL/STM32/tft/tft_spi.h b/Marlin/src/HAL/STM32/tft/tft_spi.h index de051e2294..6345c91f6c 100644 --- a/Marlin/src/HAL/STM32/tft/tft_spi.h +++ b/Marlin/src/HAL/STM32/tft/tft_spi.h @@ -25,8 +25,10 @@ #include "stm32f1xx_hal.h" #elif defined(STM32F4xx) #include "stm32f4xx_hal.h" +#elif defined(STM32H7xx) + #include "stm32h7xx_hal.h" #else - #error SPI TFT is currently only supported on STM32F1 and STM32F4 hardware. + #error SPI TFT is currently only supported on STM32F1, STM32F4 and STM32H7 hardware. #endif #ifndef LCD_READ_ID @@ -38,47 +40,49 @@ #define DATASIZE_8BIT SPI_DATASIZE_8BIT #define DATASIZE_16BIT SPI_DATASIZE_16BIT +#define DATASIZE_32BIT SPI_DATASIZE_32BIT #define TFT_IO_DRIVER TFT_SPI +#define DMA_MAX_WORDS 0xFFFF class TFT_SPI { private: static SPI_HandleTypeDef SPIx; + static DMA_HandleTypeDef DMAtx; - - static uint32_t ReadID(uint16_t Reg); - static void Transmit(uint16_t Data); - static void TransmitDMA(uint32_t MemoryIncrease, uint16_t *Data, uint16_t Count); + static uint32_t readID(const uint16_t inReg); + static void transmit(uint16_t data); + static void transmit(uint32_t memoryIncrease, uint16_t *data, uint16_t count); + static void transmitDMA(uint32_t memoryIncrease, uint16_t *data, uint16_t count); #if ENABLED(USE_SPI_DMA_TC) - static void TransmitDMA_IT(uint32_t MemoryIncrease, uint16_t *Data, uint16_t Count); + static void transmitDMA_IT(uint32_t memoryIncrease, uint16_t *data, uint16_t count); #endif public: - static DMA_HandleTypeDef DMAtx; - - static void Init(); - static uint32_t GetID(); + static void init(); + static uint32_t getID(); static bool isBusy(); - static void Abort(); + static void abort(); - static void DataTransferBegin(uint16_t DataWidth = DATASIZE_16BIT); - static void DataTransferEnd() { WRITE(TFT_CS_PIN, HIGH); }; - static void DataTransferAbort(); + static void dataTransferBegin(uint16_t dataWidth=DATASIZE_16BIT); + static void dataTransferEnd() { WRITE(TFT_CS_PIN, HIGH); __HAL_SPI_DISABLE(&SPIx); }; + static void dataTransferAbort(); - static void WriteData(uint16_t Data) { Transmit(Data); } - static void WriteReg(uint16_t Reg) { WRITE(TFT_A0_PIN, LOW); Transmit(Reg); WRITE(TFT_A0_PIN, HIGH); } + static void writeData(uint16_t data) { transmit(data); } + static void writeReg(const uint16_t inReg) { WRITE(TFT_A0_PIN, LOW); transmit(inReg); WRITE(TFT_A0_PIN, HIGH); } - static void WriteSequence(uint16_t *Data, uint16_t Count) { TransmitDMA(DMA_MINC_ENABLE, Data, Count); } + static void writeSequence_DMA(uint16_t *data, uint16_t count) { transmitDMA(DMA_MINC_ENABLE, data, count); } + static void writeMultiple_DMA(uint16_t color, uint16_t count) { static uint16_t data; data = color; transmitDMA(DMA_MINC_DISABLE, &data, count); } #if ENABLED(USE_SPI_DMA_TC) - static void WriteSequenceIT(uint16_t *Data, uint16_t Count) { TransmitDMA_IT(DMA_MINC_ENABLE, Data, Count); } + static void writeSequenceIT(uint16_t *data, uint16_t count) { transmitDMA_IT(DMA_MINC_ENABLE, data, count); } + inline static void DMA_IRQHandler() { HAL_DMA_IRQHandler(&TFT_SPI::DMAtx); } #endif - static void WriteMultiple(uint16_t Color, uint16_t Count) { static uint16_t Data; Data = Color; TransmitDMA(DMA_MINC_DISABLE, &Data, Count); } - static void WriteMultiple(uint16_t Color, uint32_t Count) { - static uint16_t Data; Data = Color; - while (Count > 0) { - TransmitDMA(DMA_MINC_DISABLE, &Data, Count > 0xFFFF ? 0xFFFF : Count); - Count = Count > 0xFFFF ? Count - 0xFFFF : 0; + static void writeSequence(uint16_t *data, uint16_t count) { transmit(DMA_MINC_ENABLE, data, count); } + static void writeMultiple(uint16_t color, uint32_t count) { + while (count > 0) { + transmit(DMA_MINC_DISABLE, &color, count > DMA_MAX_WORDS ? DMA_MAX_WORDS : count); + count = count > DMA_MAX_WORDS ? count - DMA_MAX_WORDS : 0; } } }; diff --git a/Marlin/src/HAL/STM32/tft/xpt2046.cpp b/Marlin/src/HAL/STM32/tft/xpt2046.cpp index cf4a8f18e9..c5645ad79c 100644 --- a/Marlin/src/HAL/STM32/tft/xpt2046.cpp +++ b/Marlin/src/HAL/STM32/tft/xpt2046.cpp @@ -35,7 +35,7 @@ uint16_t delta(uint16_t a, uint16_t b) { return a > b ? a - b : b - a; } SPI_HandleTypeDef XPT2046::SPIx; -void XPT2046::Init() { +void XPT2046::init() { SPI_TypeDef *spiInstance; OUT_WRITE(TOUCH_CS_PIN, HIGH); @@ -56,7 +56,6 @@ void XPT2046::Init() { SPIx.Init.NSS = SPI_NSS_SOFT; SPIx.Init.Mode = SPI_MODE_MASTER; SPIx.Init.Direction = SPI_DIRECTION_2LINES; - SPIx.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_8; SPIx.Init.CLKPhase = SPI_PHASE_2EDGE; SPIx.Init.CLKPolarity = SPI_POLARITY_HIGH; SPIx.Init.DataSize = SPI_DATASIZE_8BIT; @@ -65,6 +64,20 @@ void XPT2046::Init() { SPIx.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE; SPIx.Init.CRCPolynomial = 10; + #ifndef STM32H7xx + SPIx.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_8; // 4.5 MBit/s for F103 and 5.25 MBit/s for F407 + #else + SPIx.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_16; // 5 MBit/s for H743 + SPIx.Init.NSSPMode = SPI_NSS_PULSE_ENABLE; + SPIx.Init.NSSPolarity = SPI_NSS_POLARITY_LOW; + SPIx.Init.FifoThreshold = SPI_FIFO_THRESHOLD_01DATA; + SPIx.Init.MasterSSIdleness = SPI_MASTER_SS_IDLENESS_00CYCLE; + SPIx.Init.MasterInterDataIdleness = SPI_MASTER_INTERDATA_IDLENESS_00CYCLE; + SPIx.Init.MasterReceiverAutoSusp = SPI_MASTER_RX_AUTOSUSP_DISABLE; + SPIx.Init.MasterKeepIOState = SPI_MASTER_KEEP_IO_STATE_ENABLE; + SPIx.Init.IOSwap = SPI_IO_SWAP_DISABLE; + #endif + pinmap_pinout(digitalPinToPinName(TOUCH_SCK_PIN), PinMap_SPI_SCLK); pinmap_pinout(digitalPinToPinName(TOUCH_MOSI_PIN), PinMap_SPI_MOSI); pinmap_pinout(digitalPinToPinName(TOUCH_MISO_PIN), PinMap_SPI_MISO); @@ -106,9 +119,8 @@ bool XPT2046::isTouched() { ); } -bool XPT2046::getRawPoint(int16_t *x, int16_t *y) { - if (isBusy()) return false; - if (!isTouched()) return false; +bool XPT2046::getRawPoint(int16_t * const x, int16_t * const y) { + if (isBusy() || !isTouched()) return false; *x = getRawData(XPT2046_X); *y = getRawData(XPT2046_Y); return isTouched(); @@ -117,14 +129,14 @@ bool XPT2046::getRawPoint(int16_t *x, int16_t *y) { uint16_t XPT2046::getRawData(const XPTCoordinate coordinate) { uint16_t data[3]; - DataTransferBegin(); + dataTransferBegin(); for (uint16_t i = 0; i < 3 ; i++) { IO(coordinate); data[i] = (IO() << 4) | (IO() >> 4); } - DataTransferEnd(); + dataTransferEnd(); uint16_t delta01 = delta(data[0], data[1]); uint16_t delta02 = delta(data[0], data[2]); @@ -140,17 +152,34 @@ uint16_t XPT2046::getRawData(const XPTCoordinate coordinate) { return (data[0] + data[1]) >> 1; } -uint16_t XPT2046::HardwareIO(uint16_t data) { - __HAL_SPI_ENABLE(&SPIx); - while ((SPIx.Instance->SR & SPI_FLAG_TXE) != SPI_FLAG_TXE) {} - SPIx.Instance->DR = data; - while ((SPIx.Instance->SR & SPI_FLAG_RXNE) != SPI_FLAG_RXNE) {} - __HAL_SPI_DISABLE(&SPIx); +uint16_t XPT2046::hardwareIO(uint16_t data) { + #ifdef STM32H7xx + MODIFY_REG(SPIx.Instance->CR2, SPI_CR2_TSIZE, 1); + __HAL_SPI_ENABLE(&SPIx); + SET_BIT(SPIx.Instance->CR1, SPI_CR1_CSTART); - return SPIx.Instance->DR; + SPIx.Instance->TXDR = data; + + while (!__HAL_SPI_GET_FLAG(&SPIx, SPI_SR_EOT)) {} + data = SPIx.Instance->RXDR; + + __HAL_SPI_DISABLE(&SPIx); + __HAL_SPI_CLEAR_EOTFLAG(&SPIx); + __HAL_SPI_CLEAR_TXTFFLAG(&SPIx); + + return data; + #else + __HAL_SPI_ENABLE(&SPIx); + while ((SPIx.Instance->SR & SPI_FLAG_TXE) != SPI_FLAG_TXE) {} + SPIx.Instance->DR = data; + while ((SPIx.Instance->SR & SPI_FLAG_RXNE) != SPI_FLAG_RXNE) {} + __HAL_SPI_DISABLE(&SPIx); + + return SPIx.Instance->DR; + #endif } -uint16_t XPT2046::SoftwareIO(uint16_t data) { +uint16_t XPT2046::softwareIO(uint16_t data) { uint16_t result = 0; for (uint8_t j = 0x80; j > 0; j >>= 1) { diff --git a/Marlin/src/HAL/STM32/tft/xpt2046.h b/Marlin/src/HAL/STM32/tft/xpt2046.h index 71de6b0025..685c9441ae 100644 --- a/Marlin/src/HAL/STM32/tft/xpt2046.h +++ b/Marlin/src/HAL/STM32/tft/xpt2046.h @@ -22,9 +22,13 @@ #pragma once #ifdef STM32F1xx - #include + #include "stm32f1xx_hal.h" #elif defined(STM32F4xx) - #include + #include "stm32f4xx_hal.h" +#elif defined(STM32H7xx) + #include "stm32h7xx_hal.h" +#else + #error SPI Touch Screen is currently only supported on STM32F1, STM32F4 and STM32H7 hardware. #endif #include "../../../inc/MarlinConfig.h" @@ -69,13 +73,13 @@ private: static uint16_t getRawData(const XPTCoordinate coordinate); static bool isTouched(); - static void DataTransferBegin() { if (SPIx.Instance) { HAL_SPI_Init(&SPIx); } WRITE(TOUCH_CS_PIN, LOW); }; - static void DataTransferEnd() { WRITE(TOUCH_CS_PIN, HIGH); }; - static uint16_t HardwareIO(uint16_t data); - static uint16_t SoftwareIO(uint16_t data); - static uint16_t IO(uint16_t data = 0) { return SPIx.Instance ? HardwareIO(data) : SoftwareIO(data); } + static void dataTransferBegin() { if (SPIx.Instance) { HAL_SPI_Init(&SPIx); } WRITE(TOUCH_CS_PIN, LOW); }; + static void dataTransferEnd() { WRITE(TOUCH_CS_PIN, HIGH); }; + static uint16_t hardwareIO(uint16_t data); + static uint16_t softwareIO(uint16_t data); + static uint16_t IO(uint16_t data = 0) { return SPIx.Instance ? hardwareIO(data) : softwareIO(data); } public: - static void Init(); - static bool getRawPoint(int16_t *x, int16_t *y); + static void init(); + static bool getRawPoint(int16_t * const x, int16_t * const y); }; diff --git a/Marlin/src/HAL/STM32/timers.cpp b/Marlin/src/HAL/STM32/timers.cpp index e68b59c46f..10e0dc43a4 100644 --- a/Marlin/src/HAL/STM32/timers.cpp +++ b/Marlin/src/HAL/STM32/timers.cpp @@ -1,9 +1,9 @@ /** * Marlin 3D Printer Firmware - * * Copyright (c) 2020 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] - * Copyright (c) 2016 Bob Cousins bobcousins42@googlemail.com - * Copyright (c) 2015-2016 Nico Tonnhofer wurstnase.reprap@gmail.com + * + * 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 @@ -292,9 +292,9 @@ static constexpr int get_timer_num_from_base_address(uintptr_t base_address) { // constexpr doesn't like using the base address pointers that timers evaluate to. // We can get away with casting them to uintptr_t, if we do so inside an array. // GCC will not currently do it directly to a uintptr_t. -IF_ENABLED(HAS_TMC_SW_SERIAL, static constexpr uintptr_t timer_serial[] = {uintptr_t(TIMER_SERIAL)}); -IF_ENABLED(SPEAKER, static constexpr uintptr_t timer_tone[] = {uintptr_t(TIMER_TONE)}); -IF_ENABLED(HAS_SERVOS, static constexpr uintptr_t timer_servo[] = {uintptr_t(TIMER_SERVO)}); +TERN_(HAS_TMC_SW_SERIAL, static constexpr uintptr_t timer_serial[] = {uintptr_t(TIMER_SERIAL)}); +TERN_(SPEAKER, static constexpr uintptr_t timer_tone[] = {uintptr_t(TIMER_TONE)}); +TERN_(HAS_SERVOS, static constexpr uintptr_t timer_servo[] = {uintptr_t(TIMER_SERVO)}); enum TimerPurpose { TP_SERIAL, TP_TONE, TP_SERVO, TP_STEP, TP_TEMP }; @@ -316,8 +316,8 @@ static constexpr struct { TimerPurpose p; int t; } timers_in_use[] = { }; static constexpr bool verify_no_timer_conflicts() { - LOOP_L_N(i, COUNT(timers_in_use)) - LOOP_S_L_N(j, i + 1, COUNT(timers_in_use)) + for (uint8_t i = 0; i < COUNT(timers_in_use); ++i) + for (uint8_t j = i + 1; j < COUNT(timers_in_use); ++j) if (timers_in_use[i].t == timers_in_use[j].t) return false; return true; } diff --git a/Marlin/src/HAL/STM32/timers.h b/Marlin/src/HAL/STM32/timers.h index 6828998198..180e240314 100644 --- a/Marlin/src/HAL/STM32/timers.h +++ b/Marlin/src/HAL/STM32/timers.h @@ -1,9 +1,9 @@ /** * Marlin 3D Printer Firmware - * * Copyright (c) 2020 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] - * Copyright (c) 2016 Bob Cousins bobcousins42@googlemail.com - * Copyright (c) 2017 Victor Perez + * + * 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 diff --git a/Marlin/src/HAL/STM32/u8g/LCD_defines.h b/Marlin/src/HAL/STM32/u8g/LCD_defines.h new file mode 100644 index 0000000000..35f1674d69 --- /dev/null +++ b/Marlin/src/HAL/STM32/u8g/LCD_defines.h @@ -0,0 +1,32 @@ +/** + * Marlin 3D Printer Firmware + * Copyright (c) 2023 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] + * + * Based on Sprinter and grbl. + * Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (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 + +/** + * STM32 LCD-specific defines + */ + +uint8_t u8g_com_std_sw_spi_fn(u8g_t *u8g, uint8_t msg, uint8_t arg_val, void *arg_ptr); // See U8glib-HAL +uint8_t u8g_com_stm32duino_hw_spi_fn(u8g_t *u8g, uint8_t msg, uint8_t arg_val, void *arg_ptr); // See U8glib-HAL + +#define U8G_COM_HAL_SW_SPI_FN u8g_com_std_sw_spi_fn +#define U8G_COM_HAL_HW_SPI_FN u8g_com_stm32duino_hw_spi_fn diff --git a/Marlin/src/HAL/STM32/usb_host.cpp b/Marlin/src/HAL/STM32/usb_host.cpp index d77f0b28e9..afafe1d4f3 100644 --- a/Marlin/src/HAL/STM32/usb_host.cpp +++ b/Marlin/src/HAL/STM32/usb_host.cpp @@ -26,7 +26,7 @@ #include "../../inc/MarlinConfig.h" -#if BOTH(USE_OTG_USB_HOST, USBHOST) +#if ALL(USE_OTG_USB_HOST, USBHOST) #include "usb_host.h" #include "../shared/Marduino.h" @@ -44,7 +44,7 @@ static void USBH_UserProcess(USBH_HandleTypeDef *phost, uint8_t id) { break; case HOST_USER_DISCONNECTION: //SERIAL_ECHOLNPGM("APPLICATION_DISCONNECT"); - //usb.setUsbTaskState(USB_STATE_RUNNING); + usb.setUsbTaskState(USB_STATE_INIT); break; case HOST_USER_CLASS_ACTIVE: //SERIAL_ECHOLNPGM("APPLICATION_READY"); diff --git a/Marlin/src/HAL/STM32F1/HAL.cpp b/Marlin/src/HAL/STM32F1/HAL.cpp index 4d3140001e..e6cbb9fc06 100644 --- a/Marlin/src/HAL/STM32F1/HAL.cpp +++ b/Marlin/src/HAL/STM32F1/HAL.cpp @@ -1,10 +1,9 @@ /** * Marlin 3D Printer Firmware - * * Copyright (c) 2020 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] - * Copyright (c) 2016 Bob Cousins bobcousins42@googlemail.com - * Copyright (c) 2015-2016 Nico Tonnhofer wurstnase.reprap@gmail.com - * Copyright (c) 2017 Victor Perez + * + * 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 @@ -30,53 +29,8 @@ #include "../../inc/MarlinConfig.h" #include "HAL.h" -#include - -// ------------------------ -// Types -// ------------------------ - -#define __I -#define __IO volatile - typedef struct { - __I uint32_t CPUID; /*!< Offset: 0x000 (R/ ) CPUID Base Register */ - __IO uint32_t ICSR; /*!< Offset: 0x004 (R/W) Interrupt Control and State Register */ - __IO uint32_t VTOR; /*!< Offset: 0x008 (R/W) Vector Table Offset Register */ - __IO uint32_t AIRCR; /*!< Offset: 0x00C (R/W) Application Interrupt and Reset Control Register */ - __IO uint32_t SCR; /*!< Offset: 0x010 (R/W) System Control Register */ - __IO uint32_t CCR; /*!< Offset: 0x014 (R/W) Configuration Control Register */ - __IO uint8_t SHP[12]; /*!< Offset: 0x018 (R/W) System Handlers Priority Registers (4-7, 8-11, 12-15) */ - __IO uint32_t SHCSR; /*!< Offset: 0x024 (R/W) System Handler Control and State Register */ - __IO uint32_t CFSR; /*!< Offset: 0x028 (R/W) Configurable Fault Status Register */ - __IO uint32_t HFSR; /*!< Offset: 0x02C (R/W) HardFault Status Register */ - __IO uint32_t DFSR; /*!< Offset: 0x030 (R/W) Debug Fault Status Register */ - __IO uint32_t MMFAR; /*!< Offset: 0x034 (R/W) MemManage Fault Address Register */ - __IO uint32_t BFAR; /*!< Offset: 0x038 (R/W) BusFault Address Register */ - __IO uint32_t AFSR; /*!< Offset: 0x03C (R/W) Auxiliary Fault Status Register */ - __I uint32_t PFR[2]; /*!< Offset: 0x040 (R/ ) Processor Feature Register */ - __I uint32_t DFR; /*!< Offset: 0x048 (R/ ) Debug Feature Register */ - __I uint32_t ADR; /*!< Offset: 0x04C (R/ ) Auxiliary Feature Register */ - __I uint32_t MMFR[4]; /*!< Offset: 0x050 (R/ ) Memory Model Feature Register */ - __I uint32_t ISAR[5]; /*!< Offset: 0x060 (R/ ) Instruction Set Attributes Register */ - uint32_t RESERVED0[5]; - __IO uint32_t CPACR; /*!< Offset: 0x088 (R/W) Coprocessor Access Control Register */ - } SCB_Type; - -// ------------------------ -// Local defines -// ------------------------ - -#define SCS_BASE (0xE000E000UL) /*!< System Control Space Base Address */ -#define SCB_BASE (SCS_BASE + 0x0D00UL) /*!< System Control Block Base Address */ - -#define SCB ((SCB_Type *) SCB_BASE ) /*!< SCB configuration struct */ - -/* SCB Application Interrupt and Reset Control Register Definitions */ -#define SCB_AIRCR_VECTKEY_Pos 16 /*!< SCB AIRCR: VECTKEY Position */ -#define SCB_AIRCR_VECTKEY_Msk (0xFFFFUL << SCB_AIRCR_VECTKEY_Pos) /*!< SCB AIRCR: VECTKEY Mask */ - -#define SCB_AIRCR_PRIGROUP_Pos 8 /*!< SCB AIRCR: PRIGROUP Position */ -#define SCB_AIRCR_PRIGROUP_Msk (7UL << SCB_AIRCR_PRIGROUP_Pos) /*!< SCB AIRCR: PRIGROUP Mask */ +#include "adc.h" +uint16_t adc_results[ADC_COUNT]; // ------------------------ // Serial ports @@ -172,11 +126,84 @@ void analogWrite(const pin_t pin, int pwm_val8) { uint16_t MarlinHAL::adc_result; +#ifndef VOXELAB_N32 + +#include + +// Init the AD in continuous capture mode +void MarlinHAL::adc_init() { + static const uint8_t adc_pins[] = { + OPTITEM(HAS_TEMP_ADC_0, TEMP_0_PIN) + OPTITEM(HAS_TEMP_ADC_1, TEMP_1_PIN) + OPTITEM(HAS_TEMP_ADC_2, TEMP_2_PIN) + OPTITEM(HAS_TEMP_ADC_3, TEMP_3_PIN) + OPTITEM(HAS_TEMP_ADC_4, TEMP_4_PIN) + OPTITEM(HAS_TEMP_ADC_5, TEMP_5_PIN) + OPTITEM(HAS_TEMP_ADC_6, TEMP_6_PIN) + OPTITEM(HAS_TEMP_ADC_7, TEMP_7_PIN) + OPTITEM(HAS_HEATED_BED, TEMP_BED_PIN) + OPTITEM(HAS_TEMP_CHAMBER, TEMP_CHAMBER_PIN) + OPTITEM(HAS_TEMP_ADC_PROBE, TEMP_PROBE_PIN) + OPTITEM(HAS_TEMP_COOLER, TEMP_COOLER_PIN) + OPTITEM(HAS_TEMP_BOARD, TEMP_BOARD_PIN) + OPTITEM(HAS_TEMP_SOC, TEMP_SOC_PIN) + OPTITEM(FILAMENT_WIDTH_SENSOR, FILWIDTH_PIN) + OPTITEM(HAS_ADC_BUTTONS, ADC_KEYPAD_PIN) + OPTITEM(HAS_JOY_ADC_X, JOY_X_PIN) + OPTITEM(HAS_JOY_ADC_Y, JOY_Y_PIN) + OPTITEM(HAS_JOY_ADC_Z, JOY_Z_PIN) + OPTITEM(POWER_MONITOR_CURRENT, POWER_MONITOR_CURRENT_PIN) + OPTITEM(POWER_MONITOR_VOLTAGE, POWER_MONITOR_VOLTAGE_PIN) + }; + static STM32ADC adc(ADC1); + // Configure the ADC + adc.calibrate(); + adc.setSampleRate((F_CPU > 72000000) ? ADC_SMPR_71_5 : ADC_SMPR_41_5); // 71.5 or 41.5 ADC cycles + adc.setPins((uint8_t *)adc_pins, ADC_COUNT); + adc.setDMA(adc_results, uint16_t(ADC_COUNT), uint32_t(DMA_MINC_MODE | DMA_CIRC_MODE), nullptr); + adc.setScanMode(); + adc.setContinuous(); + adc.startConversion(); +} + +#endif // !VOXELAB_N32 + +void MarlinHAL::adc_start(const pin_t pin) { + #define __TCASE(N,I) case N: pin_index = I; break; + #define _TCASE(C,N,I) TERN_(C, __TCASE(N, I)) + ADCIndex pin_index; + switch (pin) { + default: return; + _TCASE(HAS_TEMP_ADC_0, TEMP_0_PIN, TEMP_0) + _TCASE(HAS_TEMP_ADC_1, TEMP_1_PIN, TEMP_1) + _TCASE(HAS_TEMP_ADC_2, TEMP_2_PIN, TEMP_2) + _TCASE(HAS_TEMP_ADC_3, TEMP_3_PIN, TEMP_3) + _TCASE(HAS_TEMP_ADC_4, TEMP_4_PIN, TEMP_4) + _TCASE(HAS_TEMP_ADC_5, TEMP_5_PIN, TEMP_5) + _TCASE(HAS_TEMP_ADC_6, TEMP_6_PIN, TEMP_6) + _TCASE(HAS_TEMP_ADC_7, TEMP_7_PIN, TEMP_7) + _TCASE(HAS_HEATED_BED, TEMP_BED_PIN, TEMP_BED) + _TCASE(HAS_TEMP_CHAMBER, TEMP_CHAMBER_PIN, TEMP_CHAMBER) + _TCASE(HAS_TEMP_ADC_PROBE, TEMP_PROBE_PIN, TEMP_PROBE) + _TCASE(HAS_TEMP_COOLER, TEMP_COOLER_PIN, TEMP_COOLER) + _TCASE(HAS_TEMP_BOARD, TEMP_BOARD_PIN, TEMP_BOARD) + _TCASE(HAS_TEMP_SOC, TEMP_SOC_PIN, TEMP_SOC) + _TCASE(HAS_JOY_ADC_X, JOY_X_PIN, JOY_X) + _TCASE(HAS_JOY_ADC_Y, JOY_Y_PIN, JOY_Y) + _TCASE(HAS_JOY_ADC_Z, JOY_Z_PIN, JOY_Z) + _TCASE(FILAMENT_WIDTH_SENSOR, FILWIDTH_PIN, FILWIDTH) + _TCASE(HAS_ADC_BUTTONS, ADC_KEYPAD_PIN, ADC_KEY) + _TCASE(POWER_MONITOR_CURRENT, POWER_MONITOR_CURRENT_PIN, POWERMON_CURRENT) + _TCASE(POWER_MONITOR_VOLTAGE, POWER_MONITOR_VOLTAGE_PIN, POWERMON_VOLTAGE) + } + adc_result = (adc_results[(int)pin_index] & 0xFFF) >> (12 - HAL_ADC_RESOLUTION); // shift out unused bits +} + // ------------------------ -// Private functions +// Public functions // ------------------------ -static void NVIC_SetPriorityGrouping(uint32_t PriorityGroup) { +void NVIC_SetPriorityGrouping(uint32_t PriorityGroup) { uint32_t reg_value; uint32_t PriorityGroupTmp = (PriorityGroup & (uint32_t)0x07); // only values 0..7 are used @@ -188,10 +215,6 @@ static void NVIC_SetPriorityGrouping(uint32_t PriorityGroup) { SCB->AIRCR = reg_value; } -// ------------------------ -// Public functions -// ------------------------ - void flashFirmware(const int16_t) { hal.reboot(); } // @@ -224,7 +247,7 @@ void MarlinHAL::init() { #endif #if HAS_SD_HOST_DRIVE MSC_SD_init(); - #elif BOTH(SERIAL_USB, EMERGENCY_PARSER) + #elif ALL(SERIAL_USB, EMERGENCY_PARSER) usb_cdcacm_set_hooks(USB_CDCACM_HOOK_RX, my_rx_callback); #endif #if PIN_EXISTS(USB_CONNECT) @@ -238,150 +261,20 @@ void MarlinHAL::init() { // HAL idle task void MarlinHAL::idletask() { #if HAS_SHARED_MEDIA - // If Marlin is using the SD card we need to lock it to prevent access from - // a PC via USB. - // Other HALs use IS_SD_PRINTING() and IS_SD_FILE_OPEN() to check for access but - // this will not reliably detect delete operations. To be safe we will lock - // the disk if Marlin has it mounted. Unfortunately there is currently no way - // to unmount the disk from the LCD menu. - // if (IS_SD_PRINTING() || IS_SD_FILE_OPEN()) - /* copy from lpc1768 framework, should be fixed later for process HAS_SD_HOST_DRIVE*/ - // process USB mass storage device class loop - MarlinMSC.loop(); + /** + * When Marlin is using the SD card it should be locked to prevent it being + * accessed from a PC over USB. + * Other HALs use (IS_SD_PRINTING() || IS_SD_FILE_OPEN()) to check for access + * but this won't reliably detect other file operations. To be safe we just lock + * the drive whenever Marlin has it mounted. LCDs should include an Unmount + * command so drives can be released as needed. + */ + /* Copied from LPC1768 framework. Should be fixed later to process HAS_SD_HOST_DRIVE */ + //if (!drive_locked()) // TODO + MarlinMSC.loop(); // Process USB mass storage device class loop #endif } void MarlinHAL::reboot() { nvic_sys_reset(); } -// ------------------------ -// Free Memory Accessor -// ------------------------ - -extern "C" { - extern unsigned int _ebss; // end of bss section -} - -/** - * TODO: Change this to correct it for libmaple - */ - -// return free memory between end of heap (or end bss) and whatever is current - -/* -#include -//extern caddr_t _sbrk(int incr); -#ifndef CONFIG_HEAP_END -extern char _lm_heap_end; -#define CONFIG_HEAP_END ((caddr_t)&_lm_heap_end) -#endif - -extern "C" { - static int freeMemory() { - char top = 't'; - return &top - reinterpret_cast(sbrk(0)); - } - int freeMemory() { - int free_memory; - int heap_end = (int)_sbrk(0); - free_memory = ((int)&free_memory) - ((int)heap_end); - return free_memory; - } -} -*/ - -// ------------------------ -// ADC -// ------------------------ - -enum ADCIndex : uint8_t { - OPTITEM(HAS_TEMP_ADC_0, TEMP_0) - OPTITEM(HAS_TEMP_ADC_1, TEMP_1) - OPTITEM(HAS_TEMP_ADC_2, TEMP_2) - OPTITEM(HAS_TEMP_ADC_3, TEMP_3) - OPTITEM(HAS_TEMP_ADC_4, TEMP_4) - OPTITEM(HAS_TEMP_ADC_5, TEMP_5) - OPTITEM(HAS_TEMP_ADC_6, TEMP_6) - OPTITEM(HAS_TEMP_ADC_7, TEMP_7) - OPTITEM(HAS_HEATED_BED, TEMP_BED) - OPTITEM(HAS_TEMP_CHAMBER, TEMP_CHAMBER) - OPTITEM(HAS_TEMP_ADC_PROBE, TEMP_PROBE) - OPTITEM(HAS_TEMP_COOLER, TEMP_COOLER) - OPTITEM(HAS_TEMP_BOARD, TEMP_BOARD) - OPTITEM(FILAMENT_WIDTH_SENSOR, FILWIDTH) - OPTITEM(HAS_ADC_BUTTONS, ADC_KEY) - OPTITEM(HAS_JOY_ADC_X, JOY_X) - OPTITEM(HAS_JOY_ADC_Y, JOY_Y) - OPTITEM(HAS_JOY_ADC_Z, JOY_Z) - OPTITEM(POWER_MONITOR_CURRENT, POWERMON_CURRENT) - OPTITEM(POWER_MONITOR_VOLTAGE, POWERMON_VOLTS) - ADC_COUNT -}; - -static uint16_t adc_results[ADC_COUNT]; - -// Init the AD in continuous capture mode -void MarlinHAL::adc_init() { - static const uint8_t adc_pins[] = { - OPTITEM(HAS_TEMP_ADC_0, TEMP_0_PIN) - OPTITEM(HAS_TEMP_ADC_1, TEMP_1_PIN) - OPTITEM(HAS_TEMP_ADC_2, TEMP_2_PIN) - OPTITEM(HAS_TEMP_ADC_3, TEMP_3_PIN) - OPTITEM(HAS_TEMP_ADC_4, TEMP_4_PIN) - OPTITEM(HAS_TEMP_ADC_5, TEMP_5_PIN) - OPTITEM(HAS_TEMP_ADC_6, TEMP_6_PIN) - OPTITEM(HAS_TEMP_ADC_7, TEMP_7_PIN) - OPTITEM(HAS_HEATED_BED, TEMP_BED_PIN) - OPTITEM(HAS_TEMP_CHAMBER, TEMP_CHAMBER_PIN) - OPTITEM(HAS_TEMP_ADC_PROBE, TEMP_PROBE_PIN) - OPTITEM(HAS_TEMP_COOLER, TEMP_COOLER_PIN) - OPTITEM(HAS_TEMP_BOARD, TEMP_BOARD_PIN) - OPTITEM(FILAMENT_WIDTH_SENSOR, FILWIDTH_PIN) - OPTITEM(HAS_ADC_BUTTONS, ADC_KEYPAD_PIN) - OPTITEM(HAS_JOY_ADC_X, JOY_X_PIN) - OPTITEM(HAS_JOY_ADC_Y, JOY_Y_PIN) - OPTITEM(HAS_JOY_ADC_Z, JOY_Z_PIN) - OPTITEM(POWER_MONITOR_CURRENT, POWER_MONITOR_CURRENT_PIN) - OPTITEM(POWER_MONITOR_VOLTAGE, POWER_MONITOR_VOLTAGE_PIN) - }; - static STM32ADC adc(ADC1); - // configure the ADC - adc.calibrate(); - adc.setSampleRate((F_CPU > 72000000) ? ADC_SMPR_71_5 : ADC_SMPR_41_5); // 71.5 or 41.5 ADC cycles - adc.setPins((uint8_t *)adc_pins, ADC_COUNT); - adc.setDMA(adc_results, uint16_t(ADC_COUNT), uint32_t(DMA_MINC_MODE | DMA_CIRC_MODE), nullptr); - adc.setScanMode(); - adc.setContinuous(); - adc.startConversion(); -} - -void MarlinHAL::adc_start(const pin_t pin) { - #define __TCASE(N,I) case N: pin_index = I; break; - #define _TCASE(C,N,I) TERN_(C, __TCASE(N, I)) - ADCIndex pin_index; - switch (pin) { - default: return; - _TCASE(HAS_TEMP_ADC_0, TEMP_0_PIN, TEMP_0) - _TCASE(HAS_TEMP_ADC_1, TEMP_1_PIN, TEMP_1) - _TCASE(HAS_TEMP_ADC_2, TEMP_2_PIN, TEMP_2) - _TCASE(HAS_TEMP_ADC_3, TEMP_3_PIN, TEMP_3) - _TCASE(HAS_TEMP_ADC_4, TEMP_4_PIN, TEMP_4) - _TCASE(HAS_TEMP_ADC_5, TEMP_5_PIN, TEMP_5) - _TCASE(HAS_TEMP_ADC_6, TEMP_6_PIN, TEMP_6) - _TCASE(HAS_TEMP_ADC_7, TEMP_7_PIN, TEMP_7) - _TCASE(HAS_HEATED_BED, TEMP_BED_PIN, TEMP_BED) - _TCASE(HAS_TEMP_CHAMBER, TEMP_CHAMBER_PIN, TEMP_CHAMBER) - _TCASE(HAS_TEMP_ADC_PROBE, TEMP_PROBE_PIN, TEMP_PROBE) - _TCASE(HAS_TEMP_COOLER, TEMP_COOLER_PIN, TEMP_COOLER) - _TCASE(HAS_TEMP_BOARD, TEMP_BOARD_PIN, TEMP_BOARD) - _TCASE(HAS_JOY_ADC_X, JOY_X_PIN, JOY_X) - _TCASE(HAS_JOY_ADC_Y, JOY_Y_PIN, JOY_Y) - _TCASE(HAS_JOY_ADC_Z, JOY_Z_PIN, JOY_Z) - _TCASE(FILAMENT_WIDTH_SENSOR, FILWIDTH_PIN, FILWIDTH) - _TCASE(HAS_ADC_BUTTONS, ADC_KEYPAD_PIN, ADC_KEY) - _TCASE(POWER_MONITOR_CURRENT, POWER_MONITOR_CURRENT_PIN, POWERMON_CURRENT) - _TCASE(POWER_MONITOR_VOLTAGE, POWER_MONITOR_VOLTAGE_PIN, POWERMON_VOLTS) - } - adc_result = (adc_results[(int)pin_index] & 0xFFF) >> (12 - HAL_ADC_RESOLUTION); // shift out unused bits -} - #endif // __STM32F1__ diff --git a/Marlin/src/HAL/STM32F1/HAL.h b/Marlin/src/HAL/STM32F1/HAL.h index b14b5f7e79..41c91e200f 100644 --- a/Marlin/src/HAL/STM32F1/HAL.h +++ b/Marlin/src/HAL/STM32F1/HAL.h @@ -1,10 +1,9 @@ /** * Marlin 3D Printer Firmware - * * Copyright (c) 2020 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] - * Copyright (c) 2016 Bob Cousins bobcousins42@googlemail.com - * Copyright (c) 2015-2016 Nico Tonnhofer wurstnase.reprap@gmail.com - * Copyright (c) 2017 Victor Perez + * + * 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 @@ -82,7 +81,7 @@ #define _MSERIAL(X) MSerial##X #define MSERIAL(X) _MSERIAL(X) -#if EITHER(STM32_HIGH_DENSITY, STM32_XL_DENSITY) +#if ANY(STM32_HIGH_DENSITY, STM32_XL_DENSITY) #define NUM_UARTS 5 #else #define NUM_UARTS 3 @@ -140,7 +139,7 @@ static_assert(false, "LCD_SERIAL_PORT must be from 1 to " STRINGIFY(NUM_UARTS) ". You can also use -1 if the board supports Native USB.") #endif #if HAS_DGUS_LCD - #define SERIAL_GET_TX_BUFFER_FREE() LCD_SERIAL.availableForWrite() + #define LCD_SERIAL_TX_BUFFER_FREE() LCD_SERIAL.availableForWrite() #endif #endif @@ -190,7 +189,7 @@ typedef int8_t pin_t; #define HAL_ADC_RESOLUTION 12 #endif -#define HAL_ADC_VREF 3.3 +#define HAL_ADC_VREF_MV 3300 uint16_t analogRead(const pin_t pin); // need hal.adc_enable() first void analogWrite(const pin_t pin, int pwm_val8); // PWM only! mul by 257 in maple!? @@ -205,7 +204,9 @@ void analogWrite(const pin_t pin, int pwm_val8); // PWM only! mul by 257 in mapl #define JTAG_DISABLE() afio_cfg_debug_ports(AFIO_DEBUG_SW_ONLY) #define JTAGSWD_DISABLE() afio_cfg_debug_ports(AFIO_DEBUG_NONE) -#define PLATFORM_M997_SUPPORT +#ifndef PLATFORM_M997_SUPPORT + #define PLATFORM_M997_SUPPORT +#endif void flashFirmware(const int16_t); #define HAL_CAN_SET_PWM_FREQ // This HAL supports PWM Frequency adjustment @@ -220,10 +221,10 @@ void flashFirmware(const int16_t); // Memory related #define __bss_end __bss_end__ -void _delay_ms(const int ms); - extern "C" char* _sbrk(int incr); +void NVIC_SetPriorityGrouping(uint32_t PriorityGroup); + #pragma GCC diagnostic push #if GCC_VERSION <= 50000 #pragma GCC diagnostic ignored "-Wunused-function" @@ -307,3 +308,49 @@ public: static void set_pwm_frequency(const pin_t pin, const uint16_t f_desired); }; + +// ------------------------ +// Types +// ------------------------ + +#define __I +#define __IO volatile + typedef struct { + __I uint32_t CPUID; /*!< Offset: 0x000 (R/ ) CPUID Base Register */ + __IO uint32_t ICSR; /*!< Offset: 0x004 (R/W) Interrupt Control and State Register */ + __IO uint32_t VTOR; /*!< Offset: 0x008 (R/W) Vector Table Offset Register */ + __IO uint32_t AIRCR; /*!< Offset: 0x00C (R/W) Application Interrupt and Reset Control Register */ + __IO uint32_t SCR; /*!< Offset: 0x010 (R/W) System Control Register */ + __IO uint32_t CCR; /*!< Offset: 0x014 (R/W) Configuration Control Register */ + __IO uint8_t SHP[12]; /*!< Offset: 0x018 (R/W) System Handlers Priority Registers (4-7, 8-11, 12-15) */ + __IO uint32_t SHCSR; /*!< Offset: 0x024 (R/W) System Handler Control and State Register */ + __IO uint32_t CFSR; /*!< Offset: 0x028 (R/W) Configurable Fault Status Register */ + __IO uint32_t HFSR; /*!< Offset: 0x02C (R/W) HardFault Status Register */ + __IO uint32_t DFSR; /*!< Offset: 0x030 (R/W) Debug Fault Status Register */ + __IO uint32_t MMFAR; /*!< Offset: 0x034 (R/W) MemManage Fault Address Register */ + __IO uint32_t BFAR; /*!< Offset: 0x038 (R/W) BusFault Address Register */ + __IO uint32_t AFSR; /*!< Offset: 0x03C (R/W) Auxiliary Fault Status Register */ + __I uint32_t PFR[2]; /*!< Offset: 0x040 (R/ ) Processor Feature Register */ + __I uint32_t DFR; /*!< Offset: 0x048 (R/ ) Debug Feature Register */ + __I uint32_t ADR; /*!< Offset: 0x04C (R/ ) Auxiliary Feature Register */ + __I uint32_t MMFR[4]; /*!< Offset: 0x050 (R/ ) Memory Model Feature Register */ + __I uint32_t ISAR[5]; /*!< Offset: 0x060 (R/ ) Instruction Set Attributes Register */ + uint32_t RESERVED0[5]; + __IO uint32_t CPACR; /*!< Offset: 0x088 (R/W) Coprocessor Access Control Register */ + } SCB_Type; + +// ------------------------ +// System Control Space +// ------------------------ + +#define SCS_BASE (0xE000E000UL) /*!< System Control Space Base Address */ +#define SCB_BASE (SCS_BASE + 0x0D00UL) /*!< System Control Block Base Address */ + +#define SCB ((SCB_Type *) SCB_BASE ) /*!< SCB configuration struct */ + +/* SCB Application Interrupt and Reset Control Register Definitions */ +#define SCB_AIRCR_VECTKEY_Pos 16 /*!< SCB AIRCR: VECTKEY Position */ +#define SCB_AIRCR_VECTKEY_Msk (0xFFFFUL << SCB_AIRCR_VECTKEY_Pos) /*!< SCB AIRCR: VECTKEY Mask */ + +#define SCB_AIRCR_PRIGROUP_Pos 8 /*!< SCB AIRCR: PRIGROUP Position */ +#define SCB_AIRCR_PRIGROUP_Msk (7UL << SCB_AIRCR_PRIGROUP_Pos) /*!< SCB AIRCR: PRIGROUP Mask */ diff --git a/Marlin/src/HAL/STM32F1/HAL_N32.cpp b/Marlin/src/HAL/STM32F1/HAL_N32.cpp new file mode 100644 index 0000000000..971a344f21 --- /dev/null +++ b/Marlin/src/HAL/STM32F1/HAL_N32.cpp @@ -0,0 +1,641 @@ +/** + * Marlin 3D Printer Firmware + * Copyright (c) 2023 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] + * + * Based on Sprinter and grbl. + * Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (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 . + * + */ + +/** + * HAL for stm32duino.com based on Libmaple and compatible (STM32F1) + * Specifically for VOXELAB_N32. TODO: Rework for generic N32 MCU. + */ + +#if defined(__STM32F1__) && defined(VOXELAB_N32) + +#include "../../inc/MarlinConfig.h" +#include "HAL_N32.h" +#include "HAL.h" + +#include "adc.h" + +void ADC_Init(ADC_Module* NS_ADCx, ADC_InitType* ADC_InitStruct) { + uint32_t tmpreg1 = 0; + uint8_t tmpreg2 = 0; + + /*---------------------------- ADCx CTRL1 Configuration -----------------*/ + /* Get the ADCx CTRL1 value */ + tmpreg1 = NS_ADCx->CTRL1; + /* Clear DUALMOD and SCAN bits */ + tmpreg1 &= CTRL1_CLR_MASK; + /* Configure ADCx: Dual mode and scan conversion mode */ + /* Set DUALMOD bits according to WorkMode value */ + /* Set SCAN bit according to MultiChEn value */ + tmpreg1 |= (uint32_t)(ADC_InitStruct->WorkMode | ((uint32_t)ADC_InitStruct->MultiChEn << 8)); + /* Write to ADCx CTRL1 */ + NS_ADCx->CTRL1 = tmpreg1; + + /*---------------------------- ADCx CTRL2 Configuration -----------------*/ + /* Get the ADCx CTRL2 value */ + tmpreg1 = NS_ADCx->CTRL2; + /* Clear CONT, ALIGN and EXTSEL bits */ + tmpreg1 &= CTRL2_CLR_MASK; + /* Configure ADCx: external trigger event and continuous conversion mode */ + /* Set ALIGN bit according to DatAlign value */ + /* Set EXTSEL bits according to ExtTrigSelect value */ + /* Set CONT bit according to ContinueConvEn value */ + tmpreg1 |= (uint32_t)(ADC_InitStruct->DatAlign | ADC_InitStruct->ExtTrigSelect + | ((uint32_t)ADC_InitStruct->ContinueConvEn << 1)); + /* Write to ADCx CTRL2 */ + NS_ADCx->CTRL2 = tmpreg1; + + /*---------------------------- ADCx RSEQ1 Configuration -----------------*/ + /* Get the ADCx RSEQ1 value */ + tmpreg1 = NS_ADCx->RSEQ1; + /* Clear L bits */ + tmpreg1 &= RSEQ1_CLR_MASK; + /* Configure ADCx: regular channel sequence length */ + /* Set L bits according to ChsNumber value */ + tmpreg2 |= (uint8_t)(ADC_InitStruct->ChsNumber - (uint8_t)1); + tmpreg1 |= (uint32_t)tmpreg2 << 20; + /* Write to ADCx RSEQ1 */ + NS_ADCx->RSEQ1 = tmpreg1; +} + +/**================================================================ + * ADC reset + ================================================================*/ +void ADC_DeInit(ADC_Module* NS_ADCx) { + uint32_t reg_temp; + + if (NS_ADCx == NS_ADC1) { + /* Enable ADC1 reset state */ + reg_temp = ADC_RCC_AHBPRST; + reg_temp |= RCC_AHB_PERIPH_ADC1; + ADC_RCC_AHBPRST = reg_temp; // ADC module reunion position + ADC_RCC_AHBPRST = 0x00000000; // ADC module reset and clear + } + else if (NS_ADCx == NS_ADC2) { + /* Enable ADC2 reset state */ + reg_temp = ADC_RCC_AHBPRST; + reg_temp |= RCC_AHB_PERIPH_ADC2; + ADC_RCC_AHBPRST = reg_temp; // ADC module reunion position + ADC_RCC_AHBPRST = 0x00000000; // ADC module reset and clear + } + else if (NS_ADCx == NS_ADC3) { + /* Enable ADC2 reset state */ + reg_temp = ADC_RCC_AHBPRST; + reg_temp |= RCC_AHB_PERIPH_ADC3; + ADC_RCC_AHBPRST = reg_temp; // ADC module reunion position + ADC_RCC_AHBPRST = 0x00000000; // ADC module reset and clear + } + else if (NS_ADCx == NS_ADC4) { + /* Enable ADC3 reset state */ + reg_temp = ADC_RCC_AHBPRST; + reg_temp |= RCC_AHB_PERIPH_ADC4; + ADC_RCC_AHBPRST = reg_temp; // ADC module reunion position + ADC_RCC_AHBPRST = 0x00000000; // ADC module reset and clear + } +} + +/**================================================================ + * ADC module enable + ================================================================*/ +void ADC_Enable(ADC_Module* NS_ADCx, uint32_t Cmd) { + if (Cmd) + /* Set the AD_ON bit to wake up the ADC from power down mode */ + NS_ADCx->CTRL2 |= CTRL2_AD_ON_SET; + else + /* Disable the selected ADC peripheral */ + NS_ADCx->CTRL2 &= CTRL2_AD_ON_RESET; +} + +/**================================================================ + * Get the ADC status logo bit + ================================================================*/ +uint32_t ADC_GetFlagStatusNew(ADC_Module* NS_ADCx, uint8_t ADC_FLAG_NEW) { + uint32_t bitstatus = 0; + + /* Check the status of the specified ADC flag */ + if ((NS_ADCx->CTRL3 & ADC_FLAG_NEW) != (uint8_t)0) + /* ADC_FLAG_NEW is set */ + bitstatus = 1; + else + /* ADC_FLAG_NEW is reset */ + bitstatus = 0; + /* Return the ADC_FLAG_NEW status */ + return bitstatus; +} + +/**================================================================ + * Open ADC calibration + ================================================================*/ +void ADC_StartCalibration(ADC_Module* NS_ADCx) { + /* Enable the selected ADC calibration process */ + if (NS_ADCx->CALFACT == 0) + NS_ADCx->CTRL2 |= CTRL2_CAL_SET; +} + +/**================================================================ + * Enable ADC DMA + ================================================================*/ +void ADC_EnableDMA(ADC_Module* NS_ADCx, uint32_t Cmd) { + if (Cmd != 0) + /* Enable the selected ADC DMA request */ + NS_ADCx->CTRL2 |= CTRL2_DMA_SET; + else + /* Disable the selected ADC DMA request */ + NS_ADCx->CTRL2 &= CTRL2_DMA_RESET; +} + +/**================================================================ + * Configure ADC interrupt enable enable + ================================================================*/ +void ADC_ConfigInt(ADC_Module* NS_ADCx, uint16_t ADC_IT, uint32_t Cmd) { + uint8_t itmask = 0; + + /* Get the ADC IT index */ + itmask = (uint8_t)ADC_IT; + if (Cmd != 0) + /* Enable the selected ADC interrupts */ + NS_ADCx->CTRL1 |= itmask; + else + /* Disable the selected ADC interrupts */ + NS_ADCx->CTRL1 &= (~(uint32_t)itmask); +} + +/**================================================================ + * Get ADC calibration status + ================================================================*/ +uint32_t ADC_GetCalibrationStatus(ADC_Module* NS_ADCx) { + uint32_t bitstatus = 0; + + /* Check the status of CAL bit */ + if ((NS_ADCx->CTRL2 & CTRL2_CAL_SET) != (uint32_t)0) + /* CAL bit is set: calibration on going */ + bitstatus = 1; + else + /* CAL bit is reset: end of calibration */ + bitstatus = 0; + + if (NS_ADCx->CALFACT != 0) + bitstatus = 0; + /* Return the CAL bit status */ + return bitstatus; +} + +/**================================================================ + * Configure the ADC channel + ================================================================*/ +void ADC_ConfigRegularChannel(ADC_Module* NS_ADCx, uint8_t ADC_Channel, uint8_t Rank, uint8_t ADC_SampleTime) { + uint32_t tmpreg1 = 0, tmpreg2 = 0; + + if (ADC_Channel == ADC_CH_18) { + tmpreg1 = NS_ADCx->SAMPT3; + tmpreg1 &= (~0x00000007); + tmpreg1 |= ADC_SampleTime; + NS_ADCx->SAMPT3 = tmpreg1; + } + else if (ADC_Channel > ADC_CH_9) { /* if ADC_CH_10 ... ADC_CH_17 is selected */ + /* Get the old register value */ + tmpreg1 = NS_ADCx->SAMPT1; + /* Calculate the mask to clear */ + tmpreg2 = SAMPT1_SMP_SET << (3 * (ADC_Channel - 10)); + /* Clear the old channel sample time */ + tmpreg1 &= ~tmpreg2; + /* Calculate the mask to set */ + tmpreg2 = (uint32_t)ADC_SampleTime << (3 * (ADC_Channel - 10)); + /* Set the new channel sample time */ + tmpreg1 |= tmpreg2; + /* Store the new register value */ + NS_ADCx->SAMPT1 = tmpreg1; + } + else { /* ADC_Channel include in ADC_Channel_[0..9] */ + /* Get the old register value */ + tmpreg1 = NS_ADCx->SAMPT2; + /* Calculate the mask to clear */ + tmpreg2 = SAMPT2_SMP_SET << (3 * ADC_Channel); + /* Clear the old channel sample time */ + tmpreg1 &= ~tmpreg2; + /* Calculate the mask to set */ + tmpreg2 = (uint32_t)ADC_SampleTime << (3 * ADC_Channel); + /* Set the new channel sample time */ + tmpreg1 |= tmpreg2; + /* Store the new register value */ + NS_ADCx->SAMPT2 = tmpreg1; + } + /* For Rank 1 to 6 */ + if (Rank < 7) { + /* Get the old register value */ + tmpreg1 = NS_ADCx->RSEQ3; + /* Calculate the mask to clear */ + tmpreg2 = SQR3_SEQ_SET << (5 * (Rank - 1)); + /* Clear the old SQx bits for the selected rank */ + tmpreg1 &= ~tmpreg2; + /* Calculate the mask to set */ + tmpreg2 = (uint32_t)ADC_Channel << (5 * (Rank - 1)); + /* Set the SQx bits for the selected rank */ + tmpreg1 |= tmpreg2; + /* Store the new register value */ + NS_ADCx->RSEQ3 = tmpreg1; + } + /* For Rank 7 to 12 */ + else if (Rank < 13) { + /* Get the old register value */ + tmpreg1 = NS_ADCx->RSEQ2; + /* Calculate the mask to clear */ + tmpreg2 = SQR2_SEQ_SET << (5 * (Rank - 7)); + /* Clear the old SQx bits for the selected rank */ + tmpreg1 &= ~tmpreg2; + /* Calculate the mask to set */ + tmpreg2 = (uint32_t)ADC_Channel << (5 * (Rank - 7)); + /* Set the SQx bits for the selected rank */ + tmpreg1 |= tmpreg2; + /* Store the new register value */ + NS_ADCx->RSEQ2 = tmpreg1; + } + /* For Rank 13 to 16 */ + else { + /* Get the old register value */ + tmpreg1 = NS_ADCx->RSEQ1; + /* Calculate the mask to clear */ + tmpreg2 = SQR1_SEQ_SET << (5 * (Rank - 13)); + /* Clear the old SQx bits for the selected rank */ + tmpreg1 &= ~tmpreg2; + /* Calculate the mask to set */ + tmpreg2 = (uint32_t)ADC_Channel << (5 * (Rank - 13)); + /* Set the SQx bits for the selected rank */ + tmpreg1 |= tmpreg2; + /* Store the new register value */ + NS_ADCx->RSEQ1 = tmpreg1; + } +} + +/**================================================================ + * Start ADC conversion + ================================================================*/ +void ADC_EnableSoftwareStartConv(ADC_Module* NS_ADCx, uint32_t Cmd) { + if (Cmd != 0) + /* Enable the selected ADC conversion on external event and start the selected + ADC conversion */ + NS_ADCx->CTRL2 |= CTRL2_EXT_TRIG_SWSTART_SET; + else + /* Disable the selected ADC conversion on external event and stop the selected + ADC conversion */ + NS_ADCx->CTRL2 &= CTRL2_EXT_TRIG_SWSTART_RESET; +} + +/**================================================================ + * Get the ADC status logo bit + ================================================================*/ +uint32_t ADC_GetFlagStatus(ADC_Module* NS_ADCx, uint8_t ADC_FLAG) { + uint32_t bitstatus = 0; + + /* Check the status of the specified ADC flag */ + if ((NS_ADCx->STS & ADC_FLAG) != (uint8_t)0) + /* ADC_FLAG is set */ + bitstatus = 1; + else + /* ADC_FLAG is reset */ + bitstatus = 0; + /* Return the ADC_FLAG status */ + return bitstatus; +} + +/**================================================================ + * Clear status logo bit + ================================================================*/ +void ADC_ClearFlag(ADC_Module* NS_ADCx, uint8_t ADC_FLAG) { + /* Clear the selected ADC flags */ + NS_ADCx->STS &= ~(uint32_t)ADC_FLAG; +} + +/**================================================================ + * Get ADC sampling value + ================================================================*/ +uint16_t ADC_GetDat(ADC_Module* NS_ADCx) { + /* Return the selected ADC conversion value */ + return (uint16_t)NS_ADCx->DAT; +} + +/**================================================================ + * Initialize ADC clock + ================================================================*/ + +void enable_adc_clk(uint8_t cmd) { + uint32_t reg_temp; + if (cmd) { + /** Make PWR clock */ + reg_temp = ADC_RCC_APB1PCLKEN; + reg_temp |= RCC_APB1Periph_PWR; + ADC_RCC_APB1PCLKEN = reg_temp; + + /** Enable expansion mode */ + reg_temp = NS_PWR_CR3; + reg_temp |= 0x00000001; + NS_PWR_CR3 = reg_temp; + + /** Make ADC clock */ + reg_temp = ADC_RCC_AHBPCLKEN; + reg_temp |= ( RCC_AHB_PERIPH_ADC1 | + RCC_AHB_PERIPH_ADC2 | + RCC_AHB_PERIPH_ADC3 | + RCC_AHB_PERIPH_ADC4 ); + ADC_RCC_AHBPCLKEN = reg_temp; + + /** Reset */ + reg_temp = ADC_RCC_AHBPRST; + reg_temp |= ( RCC_AHB_PERIPH_ADC1 | + RCC_AHB_PERIPH_ADC2 | + RCC_AHB_PERIPH_ADC3 | + RCC_AHB_PERIPH_ADC4 ); + ADC_RCC_AHBPRST = reg_temp; // ADC module reunion position + ADC_RCC_AHBPRST &= ~reg_temp; // ADC module reset and clear + + /** Set ADC 1M clock */ + reg_temp = ADC_RCC_CFG2; + reg_temp &= CFG2_ADC1MSEL_RESET_MASK; // HSI as an ADC 1M clock + reg_temp &= CFG2_ADC1MPRES_RESET_MASK; + reg_temp |= 7 << 11; // Adc1m 8m / 8 = 1m + + /** Set the ADC PLL frequency split coefficient */ + reg_temp &= CFG2_ADCPLLPRES_RESET_MASK; + reg_temp |= RCC_ADCPLLCLK_DIV4; // ADC PLL frequency split coefficient + + /** Set the ADC HCLK frequency frequency coefficient */ + reg_temp &= CFG2_ADCHPRES_RESET_MASK; + reg_temp |= RCC_ADCHCLK_DIV4; // ADC HCLK frequency split coefficient + ADC_RCC_CFG2 = reg_temp; // Write to register + } + else { + /** Turn off the ADC clock */ + reg_temp = ADC_RCC_AHBPCLKEN; + reg_temp &= ~( RCC_AHB_PERIPH_ADC1 | + RCC_AHB_PERIPH_ADC2 | + RCC_AHB_PERIPH_ADC3 | + RCC_AHB_PERIPH_ADC4 ); + ADC_RCC_AHBPCLKEN = reg_temp; + } + +} + +/**================================================================ + * Initialize ADC peripheral parameters + ================================================================*/ +void ADC_Initial(ADC_Module* NS_ADCx) { + ADC_InitType ADC_InitStructure; + + /* ADC configuration ------------------------------------------------------*/ + ADC_InitStructure.WorkMode = ADC_WORKMODE_INDEPENDENT; // Independent mode + ADC_InitStructure.MultiChEn = 1; // Multi-channel enable + ADC_InitStructure.ContinueConvEn = 1; // Continuous enable + ADC_InitStructure.ExtTrigSelect = ADC_EXT_TRIGCONV_NONE; // Non-trigger + ADC_InitStructure.DatAlign = ADC_DAT_ALIGN_R; // Right alignment + ADC_InitStructure.ChsNumber = 2; // Scan channel number + ADC_Init(NS_ADCx, &ADC_InitStructure); + + /* ADC regular channel14 configuration */ + ADC_ConfigRegularChannel(NS_ADCx, ADC2_Channel_05_PC4, 2, ADC_SAMP_TIME_55CYCLES5); + ADC_ConfigRegularChannel(NS_ADCx, ADC2_Channel_12_PC5, 1, ADC_SAMP_TIME_55CYCLES5); + + /** 使能ADC DMA */ + ADC_EnableDMA(NS_ADCx, 1); + + /* Enable ADC */ + ADC_Enable(NS_ADCx, 1); + while(ADC_GetFlagStatusNew(NS_ADCx, ADC_FLAG_RDY) == 0); + + /* Start ADC calibration */ + ADC_StartCalibration(NS_ADCx); + while (ADC_GetCalibrationStatus(NS_ADCx)); + + /* Start ADC Software Conversion */ + ADC_EnableSoftwareStartConv(NS_ADCx, 1); +} + +/**================================================================ + * Single independent sampling + ================================================================*/ +uint16_t ADC_GetData(ADC_Module* NS_ADCx, uint8_t ADC_Channel) { + uint16_t dat; + + /** Set channel parameters */ + ADC_ConfigRegularChannel(NS_ADCx, ADC_Channel, 1, ADC_SAMP_TIME_239CYCLES5); + + /* Start ADC Software Conversion */ + ADC_EnableSoftwareStartConv(NS_ADCx, 1); + while(ADC_GetFlagStatus(NS_ADCx, ADC_FLAG_ENDC) == 0); + + ADC_ClearFlag(NS_ADCx, ADC_FLAG_ENDC); + ADC_ClearFlag(NS_ADCx, ADC_FLAG_STR); + dat = ADC_GetDat(NS_ADCx); + return dat; +} + +void DMA_DeInit(DMA_ChannelType* DMAyChx) { + + /* Disable the selected DMAy Channelx */ + DMAyChx->CHCFG &= (uint16_t)(~DMA_CHCFG1_CHEN); + + /* Reset DMAy Channelx control register */ + DMAyChx->CHCFG = 0; + + /* Reset DMAy Channelx remaining bytes register */ + DMAyChx->TXNUM = 0; + + /* Reset DMAy Channelx peripheral address register */ + DMAyChx->PADDR = 0; + + /* Reset DMAy Channelx memory address register */ + DMAyChx->MADDR = 0; + + if (DMAyChx == DMA1_CH1) { + /* Reset interrupt pending bits for DMA1 Channel1 */ + DMA1->INTCLR |= DMA1_CH1_INT_MASK; + } + else if (DMAyChx == DMA1_CH2) { + /* Reset interrupt pending bits for DMA1 Channel2 */ + DMA1->INTCLR |= DMA1_CH2_INT_MASK; + } + else if (DMAyChx == DMA1_CH3) { + /* Reset interrupt pending bits for DMA1 Channel3 */ + DMA1->INTCLR |= DMA1_CH3_INT_MASK; + } + else if (DMAyChx == DMA1_CH4) { + /* Reset interrupt pending bits for DMA1 Channel4 */ + DMA1->INTCLR |= DMA1_CH4_INT_MASK; + } + else if (DMAyChx == DMA1_CH5) { + /* Reset interrupt pending bits for DMA1 Channel5 */ + DMA1->INTCLR |= DMA1_CH5_INT_MASK; + } + else if (DMAyChx == DMA1_CH6) { + /* Reset interrupt pending bits for DMA1 Channel6 */ + DMA1->INTCLR |= DMA1_CH6_INT_MASK; + } + else if (DMAyChx == DMA1_CH7) { + /* Reset interrupt pending bits for DMA1 Channel7 */ + DMA1->INTCLR |= DMA1_CH7_INT_MASK; + } + else if (DMAyChx == DMA1_CH8) { + /* Reset interrupt pending bits for DMA1 Channel8 */ + DMA1->INTCLR |= DMA1_CH8_INT_MASK; + } + else if (DMAyChx == DMA2_CH1) { + /* Reset interrupt pending bits for DMA2 Channel1 */ + DMA2->INTCLR |= DMA2_CH1_INT_MASK; + } + else if (DMAyChx == DMA2_CH2) { + /* Reset interrupt pending bits for DMA2 Channel2 */ + DMA2->INTCLR |= DMA2_CH2_INT_MASK; + } + else if (DMAyChx == DMA2_CH3) { + /* Reset interrupt pending bits for DMA2 Channel3 */ + DMA2->INTCLR |= DMA2_CH3_INT_MASK; + } + else if (DMAyChx == DMA2_CH4) { + /* Reset interrupt pending bits for DMA2 Channel4 */ + DMA2->INTCLR |= DMA2_CH4_INT_MASK; + } + else if (DMAyChx == DMA2_CH5) { + /* Reset interrupt pending bits for DMA2 Channel5 */ + DMA2->INTCLR |= DMA2_CH5_INT_MASK; + } + else if (DMAyChx == DMA2_CH6) { + /* Reset interrupt pending bits for DMA2 Channel6 */ + DMA2->INTCLR |= DMA2_CH6_INT_MASK; + } + else if (DMAyChx == DMA2_CH7) { + /* Reset interrupt pending bits for DMA2 Channel7 */ + DMA2->INTCLR |= DMA2_CH7_INT_MASK; + } + else if (DMAyChx == DMA2_CH8) + /* Reset interrupt pending bits for DMA2 Channel8 */ + DMA2->INTCLR |= DMA2_CH8_INT_MASK; +} + +void DMA_Init(DMA_ChannelType* DMAyChx, DMA_InitType* DMA_InitParam) { + uint32_t tmpregister = 0; + + /*--------------------------- DMAy Channelx CHCFG Configuration --------------*/ + /* Get the DMAyChx CHCFG value */ + tmpregister = DMAyChx->CHCFG; + /* Clear MEM2MEM, PL, MSIZE, PSIZE, MINC, PINC, CIRC and DIR bits */ + tmpregister &= CCR_CLEAR_Mask; + /* Configure DMAy Channelx: data transfer, data size, priority level and mode */ + /* Set DIR bit according to Direction value */ + /* Set CIRC bit according to CircularMode value */ + /* Set PINC bit according to PeriphInc value */ + /* Set MINC bit according to DMA_MemoryInc value */ + /* Set PSIZE bits according to PeriphDataSize value */ + /* Set MSIZE bits according to MemDataSize value */ + /* Set PL bits according to Priority value */ + /* Set the MEM2MEM bit according to Mem2Mem value */ + tmpregister |= DMA_InitParam->Direction | DMA_InitParam->CircularMode | DMA_InitParam->PeriphInc + | DMA_InitParam->DMA_MemoryInc | DMA_InitParam->PeriphDataSize | DMA_InitParam->MemDataSize + | DMA_InitParam->Priority | DMA_InitParam->Mem2Mem; + + /* Write to DMAy Channelx CHCFG */ + DMAyChx->CHCFG = tmpregister; + + /*--------------------------- DMAy Channelx TXNUM Configuration --------------*/ + /* Write to DMAy Channelx TXNUM */ + DMAyChx->TXNUM = DMA_InitParam->BufSize; + + /*--------------------------- DMAy Channelx PADDR Configuration --------------*/ + /* Write to DMAy Channelx PADDR */ + DMAyChx->PADDR = DMA_InitParam->PeriphAddr; + + /*--------------------------- DMAy Channelx MADDR Configuration --------------*/ + /* Write to DMAy Channelx MADDR */ + DMAyChx->MADDR = DMA_InitParam->MemAddr; +} + +void DMA_EnableChannel(DMA_ChannelType* DMAyChx, uint32_t Cmd) { + if (Cmd != 0) { + /* Enable the selected DMAy Channelx */ + DMAyChx->CHCFG |= DMA_CHCFG1_CHEN; + } + else { + /* Disable the selected DMAy Channelx */ + DMAyChx->CHCFG &= (uint16_t)(~DMA_CHCFG1_CHEN); + } +} + +/**================================================================ + * Initialize the DMA of ADC + ================================================================*/ +void ADC_DMA_init() { + DMA_InitType DMA_InitStructure; + uint32_t reg_temp; + + /** Make DMA clock */ + reg_temp = ADC_RCC_AHBPCLKEN; + reg_temp |= ( RCC_AHB_PERIPH_DMA1 | + RCC_AHB_PERIPH_DMA2 ); + ADC_RCC_AHBPCLKEN = reg_temp; + + /* DMA channel configuration*/ + DMA_DeInit(USE_DMA_CH); + DMA_InitStructure.PeriphAddr = (uint32_t)&USE_ADC->DAT; + DMA_InitStructure.MemAddr = (uint32_t)adc_results; + DMA_InitStructure.Direction = DMA_DIR_PERIPH_SRC; // Peripheral-> memory + DMA_InitStructure.BufSize = 2; + DMA_InitStructure.PeriphInc = DMA_PERIPH_INC_DISABLE; + DMA_InitStructure.DMA_MemoryInc = DMA_MEM_INC_ENABLE; // Memory ++ + DMA_InitStructure.PeriphDataSize = DMA_PERIPH_DATA_SIZE_HALFWORD; + DMA_InitStructure.MemDataSize = DMA_MemoryDataSize_HalfWord; + DMA_InitStructure.CircularMode = DMA_MODE_CIRCULAR; + DMA_InitStructure.Priority = DMA_PRIORITY_HIGH; + DMA_InitStructure.Mem2Mem = DMA_M2M_DISABLE; + DMA_Init(USE_DMA_CH, &DMA_InitStructure); + + /* Enable DMA channel1 */ + DMA_EnableChannel(USE_DMA_CH, 1); +} + +/**============================================================================= + * n32g452 - end + ==============================================================================*/ + +#define NS_PINRT(V...) do{ SERIAL_ECHO_START(); SERIAL_ECHOLNPAIR(V); }while(0) + +// Init the AD in continuous capture mode +void MarlinHAL::adc_init() { + uint32_t reg_temp; + + //SERIAL_ECHO_MSG("\r\n n32g45x HAL_adc_init\r\n"); + + // GPIO settings + reg_temp = ADC_RCC_APB2PCLKEN; + reg_temp |= 0x0f; // Make PORT mouth clock + ADC_RCC_APB2PCLKEN = reg_temp; + + //reg_temp = NS_GPIOC_PL_CFG; + //reg_temp &= 0XFF00FFFF; + //NS_GPIOC_PL_CFG = reg_temp; // PC4/5 analog input + + enable_adc_clk(1); // Make ADC clock + ADC_DMA_init(); // DMA initialization + ADC_Initial(NS_ADC2); // ADC initialization + + delay(2); + //NS_PINRT("get adc1 = ", adc_results[0], "\r\n"); + //NS_PINRT("get adc2 = ", adc_results[1], "\r\n"); +} + +#endif // __STM32F1__ && VOXELAB_N32 diff --git a/Marlin/src/HAL/STM32F1/HAL_N32.h b/Marlin/src/HAL/STM32F1/HAL_N32.h new file mode 100644 index 0000000000..46ec7ba6db --- /dev/null +++ b/Marlin/src/HAL/STM32F1/HAL_N32.h @@ -0,0 +1,892 @@ +/** + * Marlin 3D Printer Firmware + * Copyright (c) 2023 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] + * + * Based on Sprinter and grbl. + * Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (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 . + * + */ + +/** + * HAL for stm32duino.com based on Libmaple and compatible (STM32F1) + * Specifically for VOXELAB_N32 (N32G452). TODO: Rework for generic N32 MCU. + */ + +#include + +typedef struct { + uint32_t WorkMode; + uint32_t MultiChEn; + uint32_t ContinueConvEn; + uint32_t ExtTrigSelect; + uint32_t DatAlign; + uint8_t ChsNumber; +} ADC_InitType; + +typedef struct { + __IO uint32_t STS; + __IO uint32_t CTRL1; + __IO uint32_t CTRL2; + __IO uint32_t SAMPT1; + __IO uint32_t SAMPT2; + __IO uint32_t JOFFSET1; + __IO uint32_t JOFFSET2; + __IO uint32_t JOFFSET3; + __IO uint32_t JOFFSET4; + __IO uint32_t WDGHIGH; + __IO uint32_t WDGLOW; + __IO uint32_t RSEQ1; + __IO uint32_t RSEQ2; + __IO uint32_t RSEQ3; + __IO uint32_t JSEQ; + __IO uint32_t JDAT1; + __IO uint32_t JDAT2; + __IO uint32_t JDAT3; + __IO uint32_t JDAT4; + __IO uint32_t DAT; + __IO uint32_t DIFSEL; + __IO uint32_t CALFACT; + __IO uint32_t CTRL3; + __IO uint32_t SAMPT3; +} ADC_Module; + +#define NS_ADC1_BASE ((uint32_t)0x40020800) +#define NS_ADC2_BASE ((uint32_t)0x40020c00) +#define NS_ADC3_BASE ((uint32_t)0x40021800) +#define NS_ADC4_BASE ((uint32_t)0x40021c00) + +#define NS_ADC1 ((ADC_Module*)NS_ADC1_BASE) +#define NS_ADC2 ((ADC_Module*)NS_ADC2_BASE) +#define NS_ADC3 ((ADC_Module*)NS_ADC3_BASE) +#define NS_ADC4 ((ADC_Module*)NS_ADC4_BASE) + +#define ADC1_Channel_01_PA0 ((uint8_t)0x01) +#define ADC1_Channel_02_PA1 ((uint8_t)0x02) +#define ADC1_Channel_03_PA6 ((uint8_t)0x03) +#define ADC1_Channel_04_PA3 ((uint8_t)0x04) +#define ADC1_Channel_05_PF4 ((uint8_t)0x05) +#define ADC1_Channel_06_PC0 ((uint8_t)0x06) +#define ADC1_Channel_07_PC1 ((uint8_t)0x07) +#define ADC1_Channel_08_PC2 ((uint8_t)0x08) +#define ADC1_Channel_09_PC3 ((uint8_t)0x09) +#define ADC1_Channel_10_PF2 ((uint8_t)0x0A) +#define ADC1_Channel_11_PA2 ((uint8_t)0x0B) + +#define ADC2_Channel_01_PA4 ((uint8_t)0x01) +#define ADC2_Channel_02_PA5 ((uint8_t)0x02) +#define ADC2_Channel_03_PB1 ((uint8_t)0x03) +#define ADC2_Channel_04_PA7 ((uint8_t)0x04) +#define ADC2_Channel_05_PC4 ((uint8_t)0x05) +#define ADC2_Channel_06_PC0 ((uint8_t)0x06) +#define ADC2_Channel_07_PC1 ((uint8_t)0x07) +#define ADC2_Channel_08_PC2 ((uint8_t)0x08) +#define ADC2_Channel_09_PC3 ((uint8_t)0x09) +#define ADC2_Channel_10_PF2 ((uint8_t)0x0A) +#define ADC2_Channel_11_PA2 ((uint8_t)0x0B) +#define ADC2_Channel_12_PC5 ((uint8_t)0x0C) +#define ADC2_Channel_13_PB2 ((uint8_t)0x0D) + +#define ADC3_Channel_01_PB11 ((uint8_t)0x01) +#define ADC3_Channel_02_PE9 ((uint8_t)0x02) +#define ADC3_Channel_03_PE13 ((uint8_t)0x03) +#define ADC3_Channel_04_PE12 ((uint8_t)0x04) +#define ADC3_Channel_05_PB13 ((uint8_t)0x05) +#define ADC3_Channel_06_PE8 ((uint8_t)0x06) +#define ADC3_Channel_07_PD10 ((uint8_t)0x07) +#define ADC3_Channel_08_PD11 ((uint8_t)0x08) +#define ADC3_Channel_09_PD12 ((uint8_t)0x09) +#define ADC3_Channel_10_PD13 ((uint8_t)0x0A) +#define ADC3_Channel_11_PD14 ((uint8_t)0x0B) +#define ADC3_Channel_12_PB0 ((uint8_t)0x0C) +#define ADC3_Channel_13_PE7 ((uint8_t)0x0D) +#define ADC3_Channel_14_PE10 ((uint8_t)0x0E) +#define ADC3_Channel_15_PE11 ((uint8_t)0x0F) + +#define ADC4_Channel_01_PE14 ((uint8_t)0x01) +#define ADC4_Channel_02_PE15 ((uint8_t)0x02) +#define ADC4_Channel_03_PB12 ((uint8_t)0x03) +#define ADC4_Channel_04_PB14 ((uint8_t)0x04) +#define ADC4_Channel_05_PB15 ((uint8_t)0x05) +#define ADC4_Channel_06_PE8 ((uint8_t)0x06) +#define ADC4_Channel_07_PD10 ((uint8_t)0x07) +#define ADC4_Channel_08_PD11 ((uint8_t)0x08) +#define ADC4_Channel_09_PD12 ((uint8_t)0x09) +#define ADC4_Channel_10_PD13 ((uint8_t)0x0A) +#define ADC4_Channel_11_PD14 ((uint8_t)0x0B) +#define ADC4_Channel_12_PD8 ((uint8_t)0x0C) +#define ADC4_Channel_13_PD9 ((uint8_t)0x0D) + +#define ADC_RCC_BASE ((uint32_t)0x40021000) +#define ADC_RCC_CTRL *((uint32_t*)(ADC_RCC_BASE + 0x00)) +#define ADC_RCC_CFG *((uint32_t*)(ADC_RCC_BASE + 0x04)) +#define ADC_RCC_CLKINT *((uint32_t*)(ADC_RCC_BASE + 0x08)) +#define ADC_RCC_APB2PRST *((uint32_t*)(ADC_RCC_BASE + 0x0c)) +#define ADC_RCC_APB1PRST *((uint32_t*)(ADC_RCC_BASE + 0x10)) +#define ADC_RCC_AHBPCLKEN *((uint32_t*)(ADC_RCC_BASE + 0x14)) +#define ADC_RCC_APB2PCLKEN *((uint32_t*)(ADC_RCC_BASE + 0x18)) +#define ADC_RCC_APB1PCLKEN *((uint32_t*)(ADC_RCC_BASE + 0x1c)) +#define ADC_RCC_BDCTRL *((uint32_t*)(ADC_RCC_BASE + 0x20)) +#define ADC_RCC_CTRLSTS *((uint32_t*)(ADC_RCC_BASE + 0x24)) +#define ADC_RCC_AHBPRST *((uint32_t*)(ADC_RCC_BASE + 0x28)) +#define ADC_RCC_CFG2 *((uint32_t*)(ADC_RCC_BASE + 0x2c)) +#define ADC_RCC_CFG3 *((uint32_t*)(ADC_RCC_BASE + 0x30)) + +#define NS_PWR_CR3 *((uint32_t*)(0x40007000 + 0x0C)) +#define RCC_APB1Periph_PWR ((uint32_t)0x10000000) + +/////////////////////////////// +#define NS_GPIOA_BASE ((uint32_t)0x40010800) +#define NS_GPIOA_PL_CFG *((uint32_t*)(NS_GPIOA_BASE + 0x00)) +#define NS_GPIOA_PH_CFG *((uint32_t*)(NS_GPIOA_BASE + 0x04)) + +#define NS_GPIOC_BASE ((uint32_t)0x40011000) +#define NS_GPIOC_PL_CFG *((uint32_t*)(NS_GPIOC_BASE + 0x00)) +#define NS_GPIOC_PH_CFG *((uint32_t*)(NS_GPIOC_BASE + 0x04)) + +/* CFG2 register bit mask */ +#define CFG2_TIM18CLKSEL_SET_MASK ((uint32_t)0x20000000) +#define CFG2_TIM18CLKSEL_RESET_MASK ((uint32_t)0xDFFFFFFF) +#define CFG2_RNGCPRES_SET_MASK ((uint32_t)0x1F000000) +#define CFG2_RNGCPRES_RESET_MASK ((uint32_t)0xE0FFFFFF) +#define CFG2_ADC1MSEL_SET_MASK ((uint32_t)0x00000400) +#define CFG2_ADC1MSEL_RESET_MASK ((uint32_t)0xFFFFFBFF) +#define CFG2_ADC1MPRES_SET_MASK ((uint32_t)0x0000F800) +#define CFG2_ADC1MPRES_RESET_MASK ((uint32_t)0xFFFF07FF) +#define CFG2_ADCPLLPRES_SET_MASK ((uint32_t)0x000001F0) +#define CFG2_ADCPLLPRES_RESET_MASK ((uint32_t)0xFFFFFE0F) +#define CFG2_ADCHPRES_SET_MASK ((uint32_t)0x0000000F) +#define CFG2_ADCHPRES_RESET_MASK ((uint32_t)0xFFFFFFF0) + +#define RCC_ADCPLLCLK_DISABLE ((uint32_t)0xFFFFFEFF) +#define RCC_ADCPLLCLK_DIV1 ((uint32_t)0x00000100) +#define RCC_ADCPLLCLK_DIV2 ((uint32_t)0x00000110) +#define RCC_ADCPLLCLK_DIV4 ((uint32_t)0x00000120) +#define RCC_ADCPLLCLK_DIV6 ((uint32_t)0x00000130) +#define RCC_ADCPLLCLK_DIV8 ((uint32_t)0x00000140) +#define RCC_ADCPLLCLK_DIV10 ((uint32_t)0x00000150) +#define RCC_ADCPLLCLK_DIV12 ((uint32_t)0x00000160) +#define RCC_ADCPLLCLK_DIV16 ((uint32_t)0x00000170) +#define RCC_ADCPLLCLK_DIV32 ((uint32_t)0x00000180) +#define RCC_ADCPLLCLK_DIV64 ((uint32_t)0x00000190) +#define RCC_ADCPLLCLK_DIV128 ((uint32_t)0x000001A0) +#define RCC_ADCPLLCLK_DIV256 ((uint32_t)0x000001B0) +#define RCC_ADCPLLCLK_DIV_OTHERS ((uint32_t)0x000001C0) + +#define RCC_ADCHCLK_DIV1 ((uint32_t)0x00000000) +#define RCC_ADCHCLK_DIV2 ((uint32_t)0x00000001) +#define RCC_ADCHCLK_DIV4 ((uint32_t)0x00000002) +#define RCC_ADCHCLK_DIV6 ((uint32_t)0x00000003) +#define RCC_ADCHCLK_DIV8 ((uint32_t)0x00000004) +#define RCC_ADCHCLK_DIV10 ((uint32_t)0x00000005) +#define RCC_ADCHCLK_DIV12 ((uint32_t)0x00000006) +#define RCC_ADCHCLK_DIV16 ((uint32_t)0x00000007) +#define RCC_ADCHCLK_DIV32 ((uint32_t)0x00000008) +#define RCC_ADCHCLK_DIV_OTHERS ((uint32_t)0x00000008) + +#define SAMPT1_SMP_SET ((uint32_t)0x00000007) +#define SAMPT2_SMP_SET ((uint32_t)0x00000007) + +#define SQR4_SEQ_SET ((uint32_t)0x0000001F) +#define SQR3_SEQ_SET ((uint32_t)0x0000001F) +#define SQR2_SEQ_SET ((uint32_t)0x0000001F) +#define SQR1_SEQ_SET ((uint32_t)0x0000001F) + +#define CTRL1_CLR_MASK ((uint32_t)0xFFF0FEFF) +#define RSEQ1_CLR_MASK ((uint32_t)0xFF0FFFFF) +#define CTRL2_CLR_MASK ((uint32_t)0xFFF1F7FD) + +#define ADC_CH_0 ((uint8_t)0x00) +#define ADC_CH_1 ((uint8_t)0x01) +#define ADC_CH_2 ((uint8_t)0x02) +#define ADC_CH_3 ((uint8_t)0x03) +#define ADC_CH_4 ((uint8_t)0x04) +#define ADC_CH_5 ((uint8_t)0x05) +#define ADC_CH_6 ((uint8_t)0x06) +#define ADC_CH_7 ((uint8_t)0x07) +#define ADC_CH_8 ((uint8_t)0x08) +#define ADC_CH_9 ((uint8_t)0x09) +#define ADC_CH_10 ((uint8_t)0x0A) +#define ADC_CH_11 ((uint8_t)0x0B) +#define ADC_CH_12 ((uint8_t)0x0C) +#define ADC_CH_13 ((uint8_t)0x0D) +#define ADC_CH_14 ((uint8_t)0x0E) +#define ADC_CH_15 ((uint8_t)0x0F) +#define ADC_CH_16 ((uint8_t)0x10) +#define ADC_CH_17 ((uint8_t)0x11) +#define ADC_CH_18 ((uint8_t)0x12) + +#define ADC_WORKMODE_INDEPENDENT ((uint32_t)0x00000000) +#define ADC_WORKMODE_REG_INJECT_SIMULT ((uint32_t)0x00010000) +#define ADC_WORKMODE_REG_SIMULT_ALTER_TRIG ((uint32_t)0x00020000) +#define ADC_WORKMODE_INJ_SIMULT_FAST_INTERL ((uint32_t)0x00030000) +#define ADC_WORKMODE_INJ_SIMULT_SLOW_INTERL ((uint32_t)0x00040000) +#define ADC_WORKMODE_INJ_SIMULT ((uint32_t)0x00050000) +#define ADC_WORKMODE_REG_SIMULT ((uint32_t)0x00060000) +#define ADC_WORKMODE_FAST_INTERL ((uint32_t)0x00070000) +#define ADC_WORKMODE_SLOW_INTERL ((uint32_t)0x00080000) +#define ADC_WORKMODE_ALTER_TRIG ((uint32_t)0x00090000) + +#define ADC_EXT_TRIGCONV_T1_CC3 ((uint32_t)0x00040000) //!< For ADC1, ADC2 , ADC3 and ADC4 +#define ADC_EXT_TRIGCONV_NONE ((uint32_t)0x000E0000) //!< For ADC1, ADC2 , ADC3 and ADC4 + +#define ADC_DAT_ALIGN_R ((uint32_t)0x00000000) +#define ADC_DAT_ALIGN_L ((uint32_t)0x00000800) + +#define ADC_FLAG_RDY ((uint8_t)0x20) +#define ADC_FLAG_PD_RDY ((uint8_t)0x40) + +#define CTRL2_AD_ON_SET ((uint32_t)0x00000001) +#define CTRL2_AD_ON_RESET ((uint32_t)0xFFFFFFFE) + +#define CTRL2_CAL_SET ((uint32_t)0x00000004) + +/* ADC Software start mask */ +#define CTRL2_EXT_TRIG_SWSTART_SET ((uint32_t)0x00500000) +#define CTRL2_EXT_TRIG_SWSTART_RESET ((uint32_t)0xFFAFFFFF) + +#define ADC_SAMP_TIME_1CYCLES5 ((uint8_t)0x00) +#define ADC_SAMP_TIME_7CYCLES5 ((uint8_t)0x01) +#define ADC_SAMP_TIME_13CYCLES5 ((uint8_t)0x02) +#define ADC_SAMP_TIME_28CYCLES5 ((uint8_t)0x03) +#define ADC_SAMP_TIME_41CYCLES5 ((uint8_t)0x04) +#define ADC_SAMP_TIME_55CYCLES5 ((uint8_t)0x05) +#define ADC_SAMP_TIME_71CYCLES5 ((uint8_t)0x06) +#define ADC_SAMP_TIME_239CYCLES5 ((uint8_t)0x07) + +#define ADC_FLAG_AWDG ((uint8_t)0x01) +#define ADC_FLAG_ENDC ((uint8_t)0x02) +#define ADC_FLAG_JENDC ((uint8_t)0x04) +#define ADC_FLAG_JSTR ((uint8_t)0x08) +#define ADC_FLAG_STR ((uint8_t)0x10) +#define ADC_FLAG_EOC_ANY ((uint8_t)0x20) +#define ADC_FLAG_JEOC_ANY ((uint8_t)0x40) + +/* ADC DMA mask */ +#define CTRL2_DMA_SET ((uint32_t)0x00000100) +#define CTRL2_DMA_RESET ((uint32_t)0xFFFFFEFF) + +typedef struct { + uint32_t PeriphAddr; + uint32_t MemAddr; + uint32_t Direction; + uint32_t BufSize; + uint32_t PeriphInc; + uint32_t DMA_MemoryInc; + uint32_t PeriphDataSize; + uint32_t MemDataSize; + uint32_t CircularMode; + uint32_t Priority; + uint32_t Mem2Mem; +} DMA_InitType; + +typedef struct { + __IO uint32_t CHCFG; + __IO uint32_t TXNUM; + __IO uint32_t PADDR; + __IO uint32_t MADDR; + __IO uint32_t CHSEL; +} DMA_ChannelType; + +#define DMA_DIR_PERIPH_DST ((uint32_t)0x00000010) +#define DMA_DIR_PERIPH_SRC ((uint32_t)0x00000000) + +#define DMA_PERIPH_INC_ENABLE ((uint32_t)0x00000040) +#define DMA_PERIPH_INC_DISABLE ((uint32_t)0x00000000) + +#define DMA_MEM_INC_ENABLE ((uint32_t)0x00000080) +#define DMA_MEM_INC_DISABLE ((uint32_t)0x00000000) + +#define DMA_PERIPH_DATA_SIZE_BYTE ((uint32_t)0x00000000) +#define DMA_PERIPH_DATA_SIZE_HALFWORD ((uint32_t)0x00000100) +#define DMA_PERIPH_DATA_SIZE_WORD ((uint32_t)0x00000200) + +#define DMA_MemoryDataSize_Byte ((uint32_t)0x00000000) +#define DMA_MemoryDataSize_HalfWord ((uint32_t)0x00000400) +#define DMA_MemoryDataSize_Word ((uint32_t)0x00000800) + +#define DMA_MODE_CIRCULAR ((uint32_t)0x00000020) +#define DMA_MODE_NORMAL ((uint32_t)0x00000000) + +#define DMA_M2M_ENABLE ((uint32_t)0x00004000) +#define DMA_M2M_DISABLE ((uint32_t)0x00000000) + +#define RCC_AHB_PERIPH_DMA1 ((uint32_t)0x00000001) +#define RCC_AHB_PERIPH_DMA2 ((uint32_t)0x00000002) + +/******************* Bit definition for DMA_CHCFG1 register *******************/ +#define DMA_CHCFG1_CHEN ((uint16_t)0x0001) //!< Channel enable +#define DMA_CHCFG1_TXCIE ((uint16_t)0x0002) //!< Transfer complete interrupt enable +#define DMA_CHCFG1_HTXIE ((uint16_t)0x0004) //!< Half Transfer interrupt enable +#define DMA_CHCFG1_ERRIE ((uint16_t)0x0008) //!< Transfer error interrupt enable +#define DMA_CHCFG1_DIR ((uint16_t)0x0010) //!< Data transfer direction +#define DMA_CHCFG1_CIRC ((uint16_t)0x0020) //!< Circular mode +#define DMA_CHCFG1_PINC ((uint16_t)0x0040) //!< Peripheral increment mode +#define DMA_CHCFG1_MINC ((uint16_t)0x0080) //!< Memory increment mode + +#define NS_DMA1_BASE (0x40020000) +#define DMA1_CH1_BASE (NS_DMA1_BASE + 0x0008) +#define DMA1_CH2_BASE (NS_DMA1_BASE + 0x001C) +#define DMA1_CH3_BASE (NS_DMA1_BASE + 0x0030) +#define DMA1_CH4_BASE (NS_DMA1_BASE + 0x0044) +#define DMA1_CH5_BASE (NS_DMA1_BASE + 0x0058) +#define DMA1_CH6_BASE (NS_DMA1_BASE + 0x006C) +#define DMA1_CH7_BASE (NS_DMA1_BASE + 0x0080) +#define DMA1_CH8_BASE (NS_DMA1_BASE + 0x0094) + +#define NS_DMA2_BASE (0x40020400) +#define DMA2_CH1_BASE (NS_DMA2_BASE + 0x008) +#define DMA2_CH2_BASE (NS_DMA2_BASE + 0x01C) +#define DMA2_CH3_BASE (NS_DMA2_BASE + 0x0030) +#define DMA2_CH4_BASE (NS_DMA2_BASE + 0x0044) +#define DMA2_CH5_BASE (NS_DMA2_BASE + 0x0058) +#define DMA2_CH6_BASE (NS_DMA2_BASE + 0x006C) +#define DMA2_CH7_BASE (NS_DMA2_BASE + 0x0080) +#define DMA2_CH8_BASE (NS_DMA2_BASE + 0x0094) + +#define DMA1 ((DMA_Module*)NS_DMA1_BASE) +#define DMA2 ((DMA_Module*)NS_DMA2_BASE) +#define DMA1_CH1 ((DMA_ChannelType*)DMA1_CH1_BASE) +#define DMA1_CH2 ((DMA_ChannelType*)DMA1_CH2_BASE) +#define DMA1_CH3 ((DMA_ChannelType*)DMA1_CH3_BASE) +#define DMA1_CH4 ((DMA_ChannelType*)DMA1_CH4_BASE) +#define DMA1_CH5 ((DMA_ChannelType*)DMA1_CH5_BASE) +#define DMA1_CH6 ((DMA_ChannelType*)DMA1_CH6_BASE) +#define DMA1_CH7 ((DMA_ChannelType*)DMA1_CH7_BASE) +#define DMA1_CH8 ((DMA_ChannelType*)DMA1_CH8_BASE) +#define DMA2_CH1 ((DMA_ChannelType*)DMA2_CH1_BASE) +#define DMA2_CH2 ((DMA_ChannelType*)DMA2_CH2_BASE) +#define DMA2_CH3 ((DMA_ChannelType*)DMA2_CH3_BASE) +#define DMA2_CH4 ((DMA_ChannelType*)DMA2_CH4_BASE) +#define DMA2_CH5 ((DMA_ChannelType*)DMA2_CH5_BASE) +#define DMA2_CH6 ((DMA_ChannelType*)DMA2_CH6_BASE) +#define DMA2_CH7 ((DMA_ChannelType*)DMA2_CH7_BASE) +#define DMA2_CH8 ((DMA_ChannelType*)DMA2_CH8_BASE) + +/******************************************************************************/ +/* */ +/* DMA Controller */ +/* */ +/******************************************************************************/ + +/******************* Bit definition for DMA_INTSTS register ********************/ +#define DMA_INTSTS_GLBF1 ((uint32_t)0x00000001) //!< Channel 1 Global interrupt flag +#define DMA_INTSTS_TXCF1 ((uint32_t)0x00000002) //!< Channel 1 Transfer Complete flag +#define DMA_INTSTS_HTXF1 ((uint32_t)0x00000004) //!< Channel 1 Half Transfer flag +#define DMA_INTSTS_ERRF1 ((uint32_t)0x00000008) //!< Channel 1 Transfer Error flag +#define DMA_INTSTS_GLBF2 ((uint32_t)0x00000010) //!< Channel 2 Global interrupt flag +#define DMA_INTSTS_TXCF2 ((uint32_t)0x00000020) //!< Channel 2 Transfer Complete flag +#define DMA_INTSTS_HTXF2 ((uint32_t)0x00000040) //!< Channel 2 Half Transfer flag +#define DMA_INTSTS_ERRF2 ((uint32_t)0x00000080) //!< Channel 2 Transfer Error flag +#define DMA_INTSTS_GLBF3 ((uint32_t)0x00000100) //!< Channel 3 Global interrupt flag +#define DMA_INTSTS_TXCF3 ((uint32_t)0x00000200) //!< Channel 3 Transfer Complete flag +#define DMA_INTSTS_HTXF3 ((uint32_t)0x00000400) //!< Channel 3 Half Transfer flag +#define DMA_INTSTS_ERRF3 ((uint32_t)0x00000800) //!< Channel 3 Transfer Error flag +#define DMA_INTSTS_GLBF4 ((uint32_t)0x00001000) //!< Channel 4 Global interrupt flag +#define DMA_INTSTS_TXCF4 ((uint32_t)0x00002000) //!< Channel 4 Transfer Complete flag +#define DMA_INTSTS_HTXF4 ((uint32_t)0x00004000) //!< Channel 4 Half Transfer flag +#define DMA_INTSTS_ERRF4 ((uint32_t)0x00008000) //!< Channel 4 Transfer Error flag +#define DMA_INTSTS_GLBF5 ((uint32_t)0x00010000) //!< Channel 5 Global interrupt flag +#define DMA_INTSTS_TXCF5 ((uint32_t)0x00020000) //!< Channel 5 Transfer Complete flag +#define DMA_INTSTS_HTXF5 ((uint32_t)0x00040000) //!< Channel 5 Half Transfer flag +#define DMA_INTSTS_ERRF5 ((uint32_t)0x00080000) //!< Channel 5 Transfer Error flag +#define DMA_INTSTS_GLBF6 ((uint32_t)0x00100000) //!< Channel 6 Global interrupt flag +#define DMA_INTSTS_TXCF6 ((uint32_t)0x00200000) //!< Channel 6 Transfer Complete flag +#define DMA_INTSTS_HTXF6 ((uint32_t)0x00400000) //!< Channel 6 Half Transfer flag +#define DMA_INTSTS_ERRF6 ((uint32_t)0x00800000) //!< Channel 6 Transfer Error flag +#define DMA_INTSTS_GLBF7 ((uint32_t)0x01000000) //!< Channel 7 Global interrupt flag +#define DMA_INTSTS_TXCF7 ((uint32_t)0x02000000) //!< Channel 7 Transfer Complete flag +#define DMA_INTSTS_HTXF7 ((uint32_t)0x04000000) //!< Channel 7 Half Transfer flag +#define DMA_INTSTS_ERRF7 ((uint32_t)0x08000000) //!< Channel 7 Transfer Error flag +#define DMA_INTSTS_GLBF8 ((uint32_t)0x10000000) //!< Channel 7 Global interrupt flag +#define DMA_INTSTS_TXCF8 ((uint32_t)0x20000000) //!< Channel 7 Transfer Complete flag +#define DMA_INTSTS_HTXF8 ((uint32_t)0x40000000) //!< Channel 7 Half Transfer flag +#define DMA_INTSTS_ERRF8 ((uint32_t)0x80000000) //!< Channel 7 Transfer Error flag + +/******************* Bit definition for DMA_INTCLR register *******************/ +#define DMA_INTCLR_CGLBF1 ((uint32_t)0x00000001) //!< Channel 1 Global interrupt clear +#define DMA_INTCLR_CTXCF1 ((uint32_t)0x00000002) //!< Channel 1 Transfer Complete clear +#define DMA_INTCLR_CHTXF1 ((uint32_t)0x00000004) //!< Channel 1 Half Transfer clear +#define DMA_INTCLR_CERRF1 ((uint32_t)0x00000008) //!< Channel 1 Transfer Error clear +#define DMA_INTCLR_CGLBF2 ((uint32_t)0x00000010) //!< Channel 2 Global interrupt clear +#define DMA_INTCLR_CTXCF2 ((uint32_t)0x00000020) //!< Channel 2 Transfer Complete clear +#define DMA_INTCLR_CHTXF2 ((uint32_t)0x00000040) //!< Channel 2 Half Transfer clear +#define DMA_INTCLR_CERRF2 ((uint32_t)0x00000080) //!< Channel 2 Transfer Error clear +#define DMA_INTCLR_CGLBF3 ((uint32_t)0x00000100) //!< Channel 3 Global interrupt clear +#define DMA_INTCLR_CTXCF3 ((uint32_t)0x00000200) //!< Channel 3 Transfer Complete clear +#define DMA_INTCLR_CHTXF3 ((uint32_t)0x00000400) //!< Channel 3 Half Transfer clear +#define DMA_INTCLR_CERRF3 ((uint32_t)0x00000800) //!< Channel 3 Transfer Error clear +#define DMA_INTCLR_CGLBF4 ((uint32_t)0x00001000) //!< Channel 4 Global interrupt clear +#define DMA_INTCLR_CTXCF4 ((uint32_t)0x00002000) //!< Channel 4 Transfer Complete clear +#define DMA_INTCLR_CHTXF4 ((uint32_t)0x00004000) //!< Channel 4 Half Transfer clear +#define DMA_INTCLR_CERRF4 ((uint32_t)0x00008000) //!< Channel 4 Transfer Error clear +#define DMA_INTCLR_CGLBF5 ((uint32_t)0x00010000) //!< Channel 5 Global interrupt clear +#define DMA_INTCLR_CTXCF5 ((uint32_t)0x00020000) //!< Channel 5 Transfer Complete clear +#define DMA_INTCLR_CHTXF5 ((uint32_t)0x00040000) //!< Channel 5 Half Transfer clear +#define DMA_INTCLR_CERRF5 ((uint32_t)0x00080000) //!< Channel 5 Transfer Error clear +#define DMA_INTCLR_CGLBF6 ((uint32_t)0x00100000) //!< Channel 6 Global interrupt clear +#define DMA_INTCLR_CTXCF6 ((uint32_t)0x00200000) //!< Channel 6 Transfer Complete clear +#define DMA_INTCLR_CHTXF6 ((uint32_t)0x00400000) //!< Channel 6 Half Transfer clear +#define DMA_INTCLR_CERRF6 ((uint32_t)0x00800000) //!< Channel 6 Transfer Error clear +#define DMA_INTCLR_CGLBF7 ((uint32_t)0x01000000) //!< Channel 7 Global interrupt clear +#define DMA_INTCLR_CTXCF7 ((uint32_t)0x02000000) //!< Channel 7 Transfer Complete clear +#define DMA_INTCLR_CHTXF7 ((uint32_t)0x04000000) //!< Channel 7 Half Transfer clear +#define DMA_INTCLR_CERRF7 ((uint32_t)0x08000000) //!< Channel 7 Transfer Error clear +#define DMA_INTCLR_CGLBF8 ((uint32_t)0x10000000) //!< Channel 7 Global interrupt clear +#define DMA_INTCLR_CTXCF8 ((uint32_t)0x20000000) //!< Channel 7 Transfer Complete clear +#define DMA_INTCLR_CHTXF8 ((uint32_t)0x40000000) //!< Channel 7 Half Transfer clear +#define DMA_INTCLR_CERRF8 ((uint32_t)0x80000000) //!< Channel 7 Transfer Error clear + +/******************* Bit definition for DMA_CHCFG1 register *******************/ +#define DMA_CHCFG1_CHEN ((uint16_t)0x0001) //!< Channel enable +#define DMA_CHCFG1_TXCIE ((uint16_t)0x0002) //!< Transfer complete interrupt enable +#define DMA_CHCFG1_HTXIE ((uint16_t)0x0004) //!< Half Transfer interrupt enable +#define DMA_CHCFG1_ERRIE ((uint16_t)0x0008) //!< Transfer error interrupt enable +#define DMA_CHCFG1_DIR ((uint16_t)0x0010) //!< Data transfer direction +#define DMA_CHCFG1_CIRC ((uint16_t)0x0020) //!< Circular mode +#define DMA_CHCFG1_PINC ((uint16_t)0x0040) //!< Peripheral increment mode +#define DMA_CHCFG1_MINC ((uint16_t)0x0080) //!< Memory increment mode + +#define DMA_CHCFG1_PSIZE ((uint16_t)0x0300) //!< PSIZE[1:0] bits (Peripheral size) +#define DMA_CHCFG1_PSIZE_0 ((uint16_t)0x0100) //!< Bit 0 +#define DMA_CHCFG1_PSIZE_1 ((uint16_t)0x0200) //!< Bit 1 + +#define DMA_CHCFG1_MSIZE ((uint16_t)0x0C00) //!< MSIZE[1:0] bits (Memory size) +#define DMA_CHCFG1_MSIZE_0 ((uint16_t)0x0400) //!< Bit 0 +#define DMA_CHCFG1_MSIZE_1 ((uint16_t)0x0800) //!< Bit 1 + +#define DMA_CHCFG1_PRIOLVL ((uint16_t)0x3000) //!< PL[1:0] bits(Channel Priority level) +#define DMA_CHCFG1_PRIOLVL_0 ((uint16_t)0x1000) //!< Bit 0 +#define DMA_CHCFG1_PRIOLVL_1 ((uint16_t)0x2000) //!< Bit 1 + +#define DMA_CHCFG1_MEM2MEM ((uint16_t)0x4000) //!< Memory to memory mode + +/******************* Bit definition for DMA_CHCFG2 register *******************/ +#define DMA_CHCFG2_CHEN ((uint16_t)0x0001) //!< Channel enable +#define DMA_CHCFG2_TXCIE ((uint16_t)0x0002) //!< Transfer complete interrupt enable +#define DMA_CHCFG2_HTXIE ((uint16_t)0x0004) //!< Half Transfer interrupt enable +#define DMA_CHCFG2_ERRIE ((uint16_t)0x0008) //!< Transfer error interrupt enable +#define DMA_CHCFG2_DIR ((uint16_t)0x0010) //!< Data transfer direction +#define DMA_CHCFG2_CIRC ((uint16_t)0x0020) //!< Circular mode +#define DMA_CHCFG2_PINC ((uint16_t)0x0040) //!< Peripheral increment mode +#define DMA_CHCFG2_MINC ((uint16_t)0x0080) //!< Memory increment mode + +#define DMA_CHCFG2_PSIZE ((uint16_t)0x0300) //!< PSIZE[1:0] bits (Peripheral size) +#define DMA_CHCFG2_PSIZE_0 ((uint16_t)0x0100) //!< Bit 0 +#define DMA_CHCFG2_PSIZE_1 ((uint16_t)0x0200) //!< Bit 1 + +#define DMA_CHCFG2_MSIZE ((uint16_t)0x0C00) //!< MSIZE[1:0] bits (Memory size) +#define DMA_CHCFG2_MSIZE_0 ((uint16_t)0x0400) //!< Bit 0 +#define DMA_CHCFG2_MSIZE_1 ((uint16_t)0x0800) //!< Bit 1 + +#define DMA_CHCFG2_PRIOLVL ((uint16_t)0x3000) //!< PL[1:0] bits (Channel Priority level) +#define DMA_CHCFG2_PRIOLVL_0 ((uint16_t)0x1000) //!< Bit 0 +#define DMA_CHCFG2_PRIOLVL_1 ((uint16_t)0x2000) //!< Bit 1 + +#define DMA_CHCFG2_MEM2MEM ((uint16_t)0x4000) //!< Memory to memory mode + +/******************* Bit definition for DMA_CHCFG3 register *******************/ +#define DMA_CHCFG3_CHEN ((uint16_t)0x0001) //!< Channel enable +#define DMA_CHCFG3_TXCIE ((uint16_t)0x0002) //!< Transfer complete interrupt enable +#define DMA_CHCFG3_HTXIE ((uint16_t)0x0004) //!< Half Transfer interrupt enable +#define DMA_CHCFG3_ERRIE ((uint16_t)0x0008) //!< Transfer error interrupt enable +#define DMA_CHCFG3_DIR ((uint16_t)0x0010) //!< Data transfer direction +#define DMA_CHCFG3_CIRC ((uint16_t)0x0020) //!< Circular mode +#define DMA_CHCFG3_PINC ((uint16_t)0x0040) //!< Peripheral increment mode +#define DMA_CHCFG3_MINC ((uint16_t)0x0080) //!< Memory increment mode + +#define DMA_CHCFG3_PSIZE ((uint16_t)0x0300) //!< PSIZE[1:0] bits (Peripheral size) +#define DMA_CHCFG3_PSIZE_0 ((uint16_t)0x0100) //!< Bit 0 +#define DMA_CHCFG3_PSIZE_1 ((uint16_t)0x0200) //!< Bit 1 + +#define DMA_CHCFG3_MSIZE ((uint16_t)0x0C00) //!< MSIZE[1:0] bits (Memory size) +#define DMA_CHCFG3_MSIZE_0 ((uint16_t)0x0400) //!< Bit 0 +#define DMA_CHCFG3_MSIZE_1 ((uint16_t)0x0800) //!< Bit 1 + +#define DMA_CHCFG3_PRIOLVL ((uint16_t)0x3000) //!< PL[1:0] bits (Channel Priority level) +#define DMA_CHCFG3_PRIOLVL_0 ((uint16_t)0x1000) //!< Bit 0 +#define DMA_CHCFG3_PRIOLVL_1 ((uint16_t)0x2000) //!< Bit 1 + +#define DMA_CHCFG3_MEM2MEM ((uint16_t)0x4000) //!< Memory to memory mode + +/*!<****************** Bit definition for DMA_CHCFG4 register *******************/ +#define DMA_CHCFG4_CHEN ((uint16_t)0x0001) //!< Channel enable +#define DMA_CHCFG4_TXCIE ((uint16_t)0x0002) //!< Transfer complete interrupt enable +#define DMA_CHCFG4_HTXIE ((uint16_t)0x0004) //!< Half Transfer interrupt enable +#define DMA_CHCFG4_ERRIE ((uint16_t)0x0008) //!< Transfer error interrupt enable +#define DMA_CHCFG4_DIR ((uint16_t)0x0010) //!< Data transfer direction +#define DMA_CHCFG4_CIRC ((uint16_t)0x0020) //!< Circular mode +#define DMA_CHCFG4_PINC ((uint16_t)0x0040) //!< Peripheral increment mode +#define DMA_CHCFG4_MINC ((uint16_t)0x0080) //!< Memory increment mode + +#define DMA_CHCFG4_PSIZE ((uint16_t)0x0300) //!< PSIZE[1:0] bits (Peripheral size) +#define DMA_CHCFG4_PSIZE_0 ((uint16_t)0x0100) //!< Bit 0 +#define DMA_CHCFG4_PSIZE_1 ((uint16_t)0x0200) //!< Bit 1 + +#define DMA_CHCFG4_MSIZE ((uint16_t)0x0C00) //!< MSIZE[1:0] bits (Memory size) +#define DMA_CHCFG4_MSIZE_0 ((uint16_t)0x0400) //!< Bit 0 +#define DMA_CHCFG4_MSIZE_1 ((uint16_t)0x0800) //!< Bit 1 + +#define DMA_CHCFG4_PRIOLVL ((uint16_t)0x3000) //!< PL[1:0] bits (Channel Priority level) +#define DMA_CHCFG4_PRIOLVL_0 ((uint16_t)0x1000) //!< Bit 0 +#define DMA_CHCFG4_PRIOLVL_1 ((uint16_t)0x2000) //!< Bit 1 + +#define DMA_CHCFG4_MEM2MEM ((uint16_t)0x4000) //!< Memory to memory mode + +/****************** Bit definition for DMA_CHCFG5 register *******************/ +#define DMA_CHCFG5_CHEN ((uint16_t)0x0001) //!< Channel enable +#define DMA_CHCFG5_TXCIE ((uint16_t)0x0002) //!< Transfer complete interrupt enable +#define DMA_CHCFG5_HTXIE ((uint16_t)0x0004) //!< Half Transfer interrupt enable +#define DMA_CHCFG5_ERRIE ((uint16_t)0x0008) //!< Transfer error interrupt enable +#define DMA_CHCFG5_DIR ((uint16_t)0x0010) //!< Data transfer direction +#define DMA_CHCFG5_CIRC ((uint16_t)0x0020) //!< Circular mode +#define DMA_CHCFG5_PINC ((uint16_t)0x0040) //!< Peripheral increment mode +#define DMA_CHCFG5_MINC ((uint16_t)0x0080) //!< Memory increment mode + +#define DMA_CHCFG5_PSIZE ((uint16_t)0x0300) //!< PSIZE[1:0] bits (Peripheral size) +#define DMA_CHCFG5_PSIZE_0 ((uint16_t)0x0100) //!< Bit 0 +#define DMA_CHCFG5_PSIZE_1 ((uint16_t)0x0200) //!< Bit 1 + +#define DMA_CHCFG5_MSIZE ((uint16_t)0x0C00) //!< MSIZE[1:0] bits (Memory size) +#define DMA_CHCFG5_MSIZE_0 ((uint16_t)0x0400) //!< Bit 0 +#define DMA_CHCFG5_MSIZE_1 ((uint16_t)0x0800) //!< Bit 1 + +#define DMA_CHCFG5_PRIOLVL ((uint16_t)0x3000) //!< PL[1:0] bits (Channel Priority level) +#define DMA_CHCFG5_PRIOLVL_0 ((uint16_t)0x1000) //!< Bit 0 +#define DMA_CHCFG5_PRIOLVL_1 ((uint16_t)0x2000) //!< Bit 1 + +#define DMA_CHCFG5_MEM2MEM ((uint16_t)0x4000) //!< Memory to memory mode enable + +/******************* Bit definition for DMA_CHCFG6 register *******************/ +#define DMA_CHCFG6_CHEN ((uint16_t)0x0001) //!< Channel enable +#define DMA_CHCFG6_TXCIE ((uint16_t)0x0002) //!< Transfer complete interrupt enable +#define DMA_CHCFG6_HTXIE ((uint16_t)0x0004) //!< Half Transfer interrupt enable +#define DMA_CHCFG6_ERRIE ((uint16_t)0x0008) //!< Transfer error interrupt enable +#define DMA_CHCFG6_DIR ((uint16_t)0x0010) //!< Data transfer direction +#define DMA_CHCFG6_CIRC ((uint16_t)0x0020) //!< Circular mode +#define DMA_CHCFG6_PINC ((uint16_t)0x0040) //!< Peripheral increment mode +#define DMA_CHCFG6_MINC ((uint16_t)0x0080) //!< Memory increment mode + +#define DMA_CHCFG6_PSIZE ((uint16_t)0x0300) //!< PSIZE[1:0] bits (Peripheral size) +#define DMA_CHCFG6_PSIZE_0 ((uint16_t)0x0100) //!< Bit 0 +#define DMA_CHCFG6_PSIZE_1 ((uint16_t)0x0200) //!< Bit 1 + +#define DMA_CHCFG6_MSIZE ((uint16_t)0x0C00) //!< MSIZE[1:0] bits (Memory size) +#define DMA_CHCFG6_MSIZE_0 ((uint16_t)0x0400) //!< Bit 0 +#define DMA_CHCFG6_MSIZE_1 ((uint16_t)0x0800) //!< Bit 1 + +#define DMA_CHCFG6_PRIOLVL ((uint16_t)0x3000) //!< PL[1:0] bits (Channel Priority level) +#define DMA_CHCFG6_PRIOLVL_0 ((uint16_t)0x1000) //!< Bit 0 +#define DMA_CHCFG6_PRIOLVL_1 ((uint16_t)0x2000) //!< Bit 1 + +#define DMA_CHCFG6_MEM2MEM ((uint16_t)0x4000) //!< Memory to memory mode + +/******************* Bit definition for DMA_CHCFG7 register *******************/ +#define DMA_CHCFG7_CHEN ((uint16_t)0x0001) //!< Channel enable +#define DMA_CHCFG7_TXCIE ((uint16_t)0x0002) //!< Transfer complete interrupt enable +#define DMA_CHCFG7_HTXIE ((uint16_t)0x0004) //!< Half Transfer interrupt enable +#define DMA_CHCFG7_ERRIE ((uint16_t)0x0008) //!< Transfer error interrupt enable +#define DMA_CHCFG7_DIR ((uint16_t)0x0010) //!< Data transfer direction +#define DMA_CHCFG7_CIRC ((uint16_t)0x0020) //!< Circular mode +#define DMA_CHCFG7_PINC ((uint16_t)0x0040) //!< Peripheral increment mode +#define DMA_CHCFG7_MINC ((uint16_t)0x0080) //!< Memory increment mode + +#define DMA_CHCFG7_PSIZE , ((uint16_t)0x0300) //!< PSIZE[1:0] bits (Peripheral size) +#define DMA_CHCFG7_PSIZE_0 ((uint16_t)0x0100) //!< Bit 0 +#define DMA_CHCFG7_PSIZE_1 ((uint16_t)0x0200) //!< Bit 1 + +#define DMA_CHCFG7_MSIZE ((uint16_t)0x0C00) //!< MSIZE[1:0] bits (Memory size) +#define DMA_CHCFG7_MSIZE_0 ((uint16_t)0x0400) //!< Bit 0 +#define DMA_CHCFG7_MSIZE_1 ((uint16_t)0x0800) //!< Bit 1 + +#define DMA_CHCFG7_PRIOLVL ((uint16_t)0x3000) //!< PL[1:0] bits (Channel Priority level) +#define DMA_CHCFG7_PRIOLVL_0 ((uint16_t)0x1000) //!< Bit 0 +#define DMA_CHCFG7_PRIOLVL_1 ((uint16_t)0x2000) //!< Bit 1 + +#define DMA_CHCFG7_MEM2MEM ((uint16_t)0x4000) //!< Memory to memory mode enable + +/******************* Bit definition for DMA_CHCFG8 register *******************/ +#define DMA_CHCFG8_CHEN ((uint16_t)0x0001) //!< Channel enable +#define DMA_CHCFG8_TXCIE ((uint16_t)0x0002) //!< Transfer complete interrupt enable +#define DMA_CHCFG8_HTXIE ((uint16_t)0x0004) //!< Half Transfer interrupt enable +#define DMA_CHCFG8_ERRIE ((uint16_t)0x0008) //!< Transfer error interrupt enable +#define DMA_CHCFG8_DIR ((uint16_t)0x0010) //!< Data transfer direction +#define DMA_CHCFG8_CIRC ((uint16_t)0x0020) //!< Circular mode +#define DMA_CHCFG8_PINC ((uint16_t)0x0040) //!< Peripheral increment mode +#define DMA_CHCFG8_MINC ((uint16_t)0x0080) //!< Memory increment mode + +#define DMA_CHCFG8_PSIZE , ((uint16_t)0x0300) //!< PSIZE[1:0] bits (Peripheral size) +#define DMA_CHCFG8_PSIZE_0 ((uint16_t)0x0100) //!< Bit 0 +#define DMA_CHCFG8_PSIZE_1 ((uint16_t)0x0200) //!< Bit 1 + +#define DMA_CHCFG8_MSIZE ((uint16_t)0x0C00) //!< MSIZE[1:0] bits (Memory size) +#define DMA_CHCFG8_MSIZE_0 ((uint16_t)0x0400) //!< Bit 0 +#define DMA_CHCFG8_MSIZE_1 ((uint16_t)0x0800) //!< Bit 1 + +#define DMA_CHCFG8_PRIOLVL ((uint16_t)0x3000) //!< PL[1:0] bits (Channel Priority level) +#define DMA_CHCFG8_PRIOLVL_0 ((uint16_t)0x1000) //!< Bit 0 +#define DMA_CHCFG8_PRIOLVL_1 ((uint16_t)0x2000) //!< Bit 1 + +#define DMA_CHCFG8_MEM2MEM ((uint16_t)0x4000) //!< Memory to memory mode enable + +/****************** Bit definition for DMA_TXNUM1 register ******************/ +#define DMA_TXNUM1_NDTX ((uint16_t)0xFFFF) //!< Number of data to Transfer + +/****************** Bit definition for DMA_TXNUM2 register ******************/ +#define DMA_TXNUM2_NDTX ((uint16_t)0xFFFF) //!< Number of data to Transfer + +/****************** Bit definition for DMA_TXNUM3 register ******************/ +#define DMA_TXNUM3_NDTX ((uint16_t)0xFFFF) //!< Number of data to Transfer + +/****************** Bit definition for DMA_TXNUM4 register ******************/ +#define DMA_TXNUM4_NDTX ((uint16_t)0xFFFF) //!< Number of data to Transfer + +/****************** Bit definition for DMA_TXNUM5 register ******************/ +#define DMA_TXNUM5_NDTX ((uint16_t)0xFFFF) //!< Number of data to Transfer + +/****************** Bit definition for DMA_TXNUM6 register ******************/ +#define DMA_TXNUM6_NDTX ((uint16_t)0xFFFF) //!< Number of data to Transfer + +/****************** Bit definition for DMA_TXNUM7 register ******************/ +#define DMA_TXNUM7_NDTX ((uint16_t)0xFFFF) //!< Number of data to Transfer + +/****************** Bit definition for DMA_TXNUM8 register ******************/ +#define DMA_TXNUM8_NDTX ((uint16_t)0xFFFF) //!< Number of data to Transfer + +/****************** Bit definition for DMA_PADDR1 register *******************/ +#define DMA_PADDR1_ADDR ((uint32_t)0xFFFFFFFF) //!< Peripheral Address + +/****************** Bit definition for DMA_PADDR2 register *******************/ +#define DMA_PADDR2_ADDR ((uint32_t)0xFFFFFFFF) //!< Peripheral Address + +/****************** Bit definition for DMA_PADDR3 register *******************/ +#define DMA_PADDR3_ADDR ((uint32_t)0xFFFFFFFF) //!< Peripheral Address + +/****************** Bit definition for DMA_PADDR4 register *******************/ +#define DMA_PADDR4_ADDR ((uint32_t)0xFFFFFFFF) //!< Peripheral Address + +/****************** Bit definition for DMA_PADDR5 register *******************/ +#define DMA_PADDR5_ADDR ((uint32_t)0xFFFFFFFF) //!< Peripheral Address + +/****************** Bit definition for DMA_PADDR6 register *******************/ +#define DMA_PADDR6_ADDR ((uint32_t)0xFFFFFFFF) //!< Peripheral Address + +/****************** Bit definition for DMA_PADDR7 register *******************/ +#define DMA_PADDR7_ADDR ((uint32_t)0xFFFFFFFF) //!< Peripheral Address + +/****************** Bit definition for DMA_PADDR8 register *******************/ +#define DMA_PADDR8_ADDR ((uint32_t)0xFFFFFFFF) //!< Peripheral Address + +/****************** Bit definition for DMA_MADDR1 register *******************/ +#define DMA_MADDR1_ADDR ((uint32_t)0xFFFFFFFF) //!< Memory Address + +/****************** Bit definition for DMA_MADDR2 register *******************/ +#define DMA_MADDR2_ADDR ((uint32_t)0xFFFFFFFF) //!< Memory Address + +/****************** Bit definition for DMA_MADDR3 register *******************/ +#define DMA_MADDR3_ADDR ((uint32_t)0xFFFFFFFF) //!< Memory Address + +/****************** Bit definition for DMA_MADDR4 register *******************/ +#define DMA_MADDR4_ADDR ((uint32_t)0xFFFFFFFF) //!< Memory Address + +/****************** Bit definition for DMA_MADDR5 register *******************/ +#define DMA_MADDR5_ADDR ((uint32_t)0xFFFFFFFF) //!< Memory Address + +/****************** Bit definition for DMA_MADDR6 register *******************/ +#define DMA_MADDR6_ADDR ((uint32_t)0xFFFFFFFF) //!< Memory Address + +/****************** Bit definition for DMA_MADDR7 register *******************/ +#define DMA_MADDR7_ADDR ((uint32_t)0xFFFFFFFF) //!< Memory Address + +/****************** Bit definition for DMA_MADDR8 register *******************/ +#define DMA_MADDR8_ADDR ((uint32_t)0xFFFFFFFF) //!< Memory Address + +/****************** Bit definition for DMA_CHSEL1 register *******************/ +#define DMA_CHSEL1_CH_SEL ((uint32_t)0x0000003F) //!< Channel Select + +/****************** Bit definition for DMA_CHSEL2 register *******************/ +#define DMA_CHSEL2_CH_SEL ((uint32_t)0x0000003F) //!< Channel Select + +/****************** Bit definition for DMA_CHSEL3 register *******************/ +#define DMA_CHSEL3_CH_SEL ((uint32_t)0x0000003F) //!< Channel Select + +/****************** Bit definition for DMA_CHSEL4 register *******************/ +#define DMA_CHSEL4_CH_SEL ((uint32_t)0x0000003F) //!< Channel Select + +/****************** Bit definition for DMA_CHSEL5 register *******************/ +#define DMA_CHSEL5_CH_SEL ((uint32_t)0x0000003F) //!< Channel Select + +/****************** Bit definition for DMA_CHSEL6 register *******************/ +#define DMA_CHSEL6_CH_SEL ((uint32_t)0x0000003F) //!< Channel Select + +/****************** Bit definition for DMA_CHSEL7 register *******************/ +#define DMA_CHSEL7_CH_SEL ((uint32_t)0x0000003F) //!< Channel Select + +/****************** Bit definition for DMA_CHSEL8 register *******************/ +#define DMA_CHSEL8_CH_SEL ((uint32_t)0x0000003F) //!< Channel Select + +/****************** Bit definition for DMA_CHMAPEN register *******************/ +#define DMA_CHMAPEN_MAP_EN ((uint32_t)0x00000001) //!< Channel Map Enable + +/* DMA1 Channelx interrupt pending bit masks */ +#define DMA1_CH1_INT_MASK ((uint32_t)(DMA_INTSTS_GLBF1 | DMA_INTSTS_TXCF1 | DMA_INTSTS_HTXF1 | DMA_INTSTS_ERRF1)) +#define DMA1_CH2_INT_MASK ((uint32_t)(DMA_INTSTS_GLBF2 | DMA_INTSTS_TXCF2 | DMA_INTSTS_HTXF2 | DMA_INTSTS_ERRF2)) +#define DMA1_CH3_INT_MASK ((uint32_t)(DMA_INTSTS_GLBF3 | DMA_INTSTS_TXCF3 | DMA_INTSTS_HTXF3 | DMA_INTSTS_ERRF3)) +#define DMA1_CH4_INT_MASK ((uint32_t)(DMA_INTSTS_GLBF4 | DMA_INTSTS_TXCF4 | DMA_INTSTS_HTXF4 | DMA_INTSTS_ERRF4)) +#define DMA1_CH5_INT_MASK ((uint32_t)(DMA_INTSTS_GLBF5 | DMA_INTSTS_TXCF5 | DMA_INTSTS_HTXF5 | DMA_INTSTS_ERRF5)) +#define DMA1_CH6_INT_MASK ((uint32_t)(DMA_INTSTS_GLBF6 | DMA_INTSTS_TXCF6 | DMA_INTSTS_HTXF6 | DMA_INTSTS_ERRF6)) +#define DMA1_CH7_INT_MASK ((uint32_t)(DMA_INTSTS_GLBF7 | DMA_INTSTS_TXCF7 | DMA_INTSTS_HTXF7 | DMA_INTSTS_ERRF7)) +#define DMA1_CH8_INT_MASK ((uint32_t)(DMA_INTSTS_GLBF8 | DMA_INTSTS_TXCF8 | DMA_INTSTS_HTXF8 | DMA_INTSTS_ERRF8)) + +/* DMA2 Channelx interrupt pending bit masks */ +#define DMA2_CH1_INT_MASK ((uint32_t)(DMA_INTSTS_GLBF1 | DMA_INTSTS_TXCF1 | DMA_INTSTS_HTXF1 | DMA_INTSTS_ERRF1)) +#define DMA2_CH2_INT_MASK ((uint32_t)(DMA_INTSTS_GLBF2 | DMA_INTSTS_TXCF2 | DMA_INTSTS_HTXF2 | DMA_INTSTS_ERRF2)) +#define DMA2_CH3_INT_MASK ((uint32_t)(DMA_INTSTS_GLBF3 | DMA_INTSTS_TXCF3 | DMA_INTSTS_HTXF3 | DMA_INTSTS_ERRF3)) +#define DMA2_CH4_INT_MASK ((uint32_t)(DMA_INTSTS_GLBF4 | DMA_INTSTS_TXCF4 | DMA_INTSTS_HTXF4 | DMA_INTSTS_ERRF4)) +#define DMA2_CH5_INT_MASK ((uint32_t)(DMA_INTSTS_GLBF5 | DMA_INTSTS_TXCF5 | DMA_INTSTS_HTXF5 | DMA_INTSTS_ERRF5)) +#define DMA2_CH6_INT_MASK ((uint32_t)(DMA_INTSTS_GLBF6 | DMA_INTSTS_TXCF6 | DMA_INTSTS_HTXF6 | DMA_INTSTS_ERRF6)) +#define DMA2_CH7_INT_MASK ((uint32_t)(DMA_INTSTS_GLBF7 | DMA_INTSTS_TXCF7 | DMA_INTSTS_HTXF7 | DMA_INTSTS_ERRF7)) +#define DMA2_CH8_INT_MASK ((uint32_t)(DMA_INTSTS_GLBF8 | DMA_INTSTS_TXCF8 | DMA_INTSTS_HTXF8 | DMA_INTSTS_ERRF8)) + +typedef struct { + __IO uint32_t INTSTS; + __IO uint32_t INTCLR; + __IO DMA_ChannelType DMA_Channel[8]; + __IO uint32_t CHMAPEN; +} DMA_Module; + +#define RCC_AHB_PERIPH_ADC1 ((uint32_t)0x00001000) +#define RCC_AHB_PERIPH_ADC2 ((uint32_t)0x00002000) +#define RCC_AHB_PERIPH_ADC3 ((uint32_t)0x00004000) +#define RCC_AHB_PERIPH_ADC4 ((uint32_t)0x00008000) + +void ADC_Init(ADC_Module* NS_ADCx, ADC_InitType* ADC_InitStruct); + +/**================================================================ + * ADC reset + ================================================================*/ +void ADC_DeInit(ADC_Module* NS_ADCx); + +/**================================================================ + * ADC module enable + ================================================================*/ +void ADC_Enable(ADC_Module* NS_ADCx, uint32_t Cmd); + +/**================================================================ + * Get the ADC status logo bit + ================================================================*/ +uint32_t ADC_GetFlagStatusNew(ADC_Module* NS_ADCx, uint8_t ADC_FLAG_NEW); + +/**================================================================ + * Open ADC calibration + ================================================================*/ +void ADC_StartCalibration(ADC_Module* NS_ADCx); + +/**================================================================ + * Enable ADC DMA + ================================================================*/ +void ADC_EnableDMA(ADC_Module* NS_ADCx, uint32_t Cmd); + +/**================================================================ + * Configure ADC interrupt enable enable + ================================================================*/ +void ADC_ConfigInt(ADC_Module* NS_ADCx, uint16_t ADC_IT, uint32_t Cmd); + +/**================================================================ + * Get ADC calibration status + ================================================================*/ +uint32_t ADC_GetCalibrationStatus(ADC_Module* NS_ADCx); + +/**================================================================ + * Configure the ADC channel + ================================================================*/ +void ADC_ConfigRegularChannel(ADC_Module* NS_ADCx, uint8_t ADC_Channel, uint8_t Rank, uint8_t ADC_SampleTime); + +/**================================================================ + * Start ADC conversion + ================================================================*/ +void ADC_EnableSoftwareStartConv(ADC_Module* NS_ADCx, uint32_t Cmd); + +/**================================================================ + * Get the ADC status logo bit + ================================================================*/ +uint32_t ADC_GetFlagStatus(ADC_Module* NS_ADCx, uint8_t ADC_FLAG); + +/**================================================================ + * Clear status logo bit + ================================================================*/ +void ADC_ClearFlag(ADC_Module* NS_ADCx, uint8_t ADC_FLAG); + +/**================================================================ + * Get ADC sampling value + ================================================================*/ +uint16_t ADC_GetDat(ADC_Module* NS_ADCx); + +//////////////////////////////////////////////////////////////////////////////// + +typedef struct { + __IO uint32_t CR; /* Completely compatible */ + __IO uint32_t CFGR; /* Not compatible: ADC frequency is not set here */ + __IO uint32_t CIR; /* Completely compatible */ + + __IO uint32_t APB2RSTR; /* Completely compatible */ + __IO uint32_t APB1RSTR; /* Completely compatible */ + + __IO uint32_t AHBENR; /* Not compatible: ADC clock enables settings here */ + __IO uint32_t APB2ENR; /* Not compatible: ADC clock enables to be here */ + __IO uint32_t APB1ENR; /* compatible */ + __IO uint32_t BDCR; /* compatible */ + __IO uint32_t CSR; /* compatible */ + + + __IO uint32_t AHBRSTR; /* Not compatible, ADC reset here settings */ + __IO uint32_t CFGR2; /* Not compatible, ADC clock settings here */ + __IO uint32_t CFGR3; /* Not compatible, add a new register */ + +} RCC_TypeDef; + +#define RCC ((RCC_TypeDef *) ADC_RCC_BASE) + +/**================================================================ + * Initialize ADC clock + ================================================================*/ + +void enable_adc_clk(uint8_t cmd); + +/**================================================================ + * Initialize ADC peripheral parameters + ================================================================*/ +void ADC_Initial(ADC_Module* NS_ADCx); + +/**================================================================ + * Single independent sampling + ================================================================*/ +uint16_t ADC_GetData(ADC_Module* NS_ADCx, uint8_t ADC_Channel); + +void DMA_DeInit(DMA_ChannelType* DMAyChx); + +#define CCR_CLEAR_Mask ((uint32_t)0xFFFF800F) + +void DMA_Init(DMA_ChannelType* DMAyChx, DMA_InitType* DMA_InitParam); + +void DMA_EnableChannel(DMA_ChannelType* DMAyChx, uint32_t Cmd); + +#define USE_ADC NS_ADC2 +#define USE_DMA_CH DMA1_CH8 + +/**================================================================ + * Initialize the DMA of ADC + ================================================================*/ +void ADC_DMA_init(); diff --git a/Marlin/src/HAL/STM32F1/HAL_SPI.cpp b/Marlin/src/HAL/STM32F1/HAL_SPI.cpp index abb348d743..b5b57536f3 100644 --- a/Marlin/src/HAL/STM32F1/HAL_SPI.cpp +++ b/Marlin/src/HAL/STM32F1/HAL_SPI.cpp @@ -4,7 +4,6 @@ * * Based on Sprinter and grbl. * Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm - * Copyright (c) 2017 Victor Perez * * 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 diff --git a/Marlin/src/HAL/STM32F1/MarlinSerial.cpp b/Marlin/src/HAL/STM32F1/MarlinSerial.cpp index 6dabcde51e..3b26b630df 100644 --- a/Marlin/src/HAL/STM32F1/MarlinSerial.cpp +++ b/Marlin/src/HAL/STM32F1/MarlinSerial.cpp @@ -28,7 +28,7 @@ // Copied from ~/.platformio/packages/framework-arduinoststm32-maple/STM32F1/system/libmaple/usart_private.h // Changed to handle Emergency Parser -static inline __always_inline void my_usart_irq(ring_buffer *rb, ring_buffer *wb, usart_reg_map *regs, MSerialT &serial) { +FORCE_INLINE void my_usart_irq(ring_buffer *rb, ring_buffer *wb, usart_reg_map *regs, MSerialT &serial) { /* Handle RXNEIE and TXEIE interrupts. * RXNE signifies availability of a byte in DR. * @@ -75,9 +75,9 @@ static inline __always_inline void my_usart_irq(ring_buffer *rb, ring_buffer *wb } // Not every MarlinSerial port should handle emergency parsing. -// It would not make sense to parse GCode from TMC responses, for example. +// It would not make sense to parse G-Code from TMC responses, for example. constexpr bool serial_handles_emergency(int port) { - return false + return (false #ifdef SERIAL_PORT || (SERIAL_PORT) == port #endif @@ -87,7 +87,7 @@ constexpr bool serial_handles_emergency(int port) { #ifdef LCD_SERIAL_PORT || (LCD_SERIAL_PORT) == port #endif - ; + ); } #define DEFINE_HWSERIAL_MARLIN(name, n) \ @@ -116,7 +116,7 @@ constexpr bool serial_handles_emergency(int port) { #endif DEFINE_HWSERIAL_MARLIN(MSerial2, 2); DEFINE_HWSERIAL_MARLIN(MSerial3, 3); -#if EITHER(STM32_HIGH_DENSITY, STM32_XL_DENSITY) +#if ANY(STM32_HIGH_DENSITY, STM32_XL_DENSITY) DEFINE_HWSERIAL_UART_MARLIN(MSerial4, 4); DEFINE_HWSERIAL_UART_MARLIN(MSerial5, 5); #endif diff --git a/Marlin/src/HAL/STM32F1/MarlinSerial.h b/Marlin/src/HAL/STM32F1/MarlinSerial.h index dda32fe7a2..53bcd48476 100644 --- a/Marlin/src/HAL/STM32F1/MarlinSerial.h +++ b/Marlin/src/HAL/STM32F1/MarlinSerial.h @@ -52,7 +52,7 @@ typedef Serial1Class MSerialT; extern MSerialT MSerial1; extern MSerialT MSerial2; extern MSerialT MSerial3; -#if EITHER(STM32_HIGH_DENSITY, STM32_XL_DENSITY) +#if ANY(STM32_HIGH_DENSITY, STM32_XL_DENSITY) extern MSerialT MSerial4; extern MSerialT MSerial5; #endif diff --git a/Marlin/src/HAL/STM32F1/MinSerial.cpp b/Marlin/src/HAL/STM32F1/MinSerial.cpp index 6cf68d8d8f..8fb9133254 100644 --- a/Marlin/src/HAL/STM32F1/MinSerial.cpp +++ b/Marlin/src/HAL/STM32F1/MinSerial.cpp @@ -4,7 +4,6 @@ * * Based on Sprinter and grbl. * Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm - * Copyright (c) 2017 Victor Perez * * 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 diff --git a/Marlin/src/HAL/STM32F1/SPI.cpp b/Marlin/src/HAL/STM32F1/SPI.cpp index 1ce2c7d3fd..a180684757 100644 --- a/Marlin/src/HAL/STM32F1/SPI.cpp +++ b/Marlin/src/HAL/STM32F1/SPI.cpp @@ -526,23 +526,22 @@ void SPIClass::onReceive(void(*callback)()) { _currentSetting->receiveCallback = callback; if (callback) { switch (_currentSetting->spi_d->clk_id) { - #if BOARD_NR_SPI >= 1 - case RCC_SPI1: - dma_attach_interrupt(_currentSetting->spiDmaDev, _currentSetting->spiRxDmaChannel, &SPIClass::_spi1EventCallback); - break; - #endif - #if BOARD_NR_SPI >= 2 - case RCC_SPI2: - dma_attach_interrupt(_currentSetting->spiDmaDev, _currentSetting->spiRxDmaChannel, &SPIClass::_spi2EventCallback); - break; - #endif - #if BOARD_NR_SPI >= 3 - case RCC_SPI3: - dma_attach_interrupt(_currentSetting->spiDmaDev, _currentSetting->spiRxDmaChannel, &SPIClass::_spi3EventCallback); - break; - #endif - default: - ASSERT(0); + #if BOARD_NR_SPI >= 1 + case RCC_SPI1: + dma_attach_interrupt(_currentSetting->spiDmaDev, _currentSetting->spiRxDmaChannel, &SPIClass::_spi1EventCallback); + break; + #endif + #if BOARD_NR_SPI >= 2 + case RCC_SPI2: + dma_attach_interrupt(_currentSetting->spiDmaDev, _currentSetting->spiRxDmaChannel, &SPIClass::_spi2EventCallback); + break; + #endif + #if BOARD_NR_SPI >= 3 + case RCC_SPI3: + dma_attach_interrupt(_currentSetting->spiDmaDev, _currentSetting->spiRxDmaChannel, &SPIClass::_spi3EventCallback); + break; + #endif + default: ASSERT(0); } } else { @@ -554,23 +553,22 @@ void SPIClass::onTransmit(void(*callback)()) { _currentSetting->transmitCallback = callback; if (callback) { switch (_currentSetting->spi_d->clk_id) { - #if BOARD_NR_SPI >= 1 - case RCC_SPI1: - dma_attach_interrupt(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel, &SPIClass::_spi1EventCallback); - break; - #endif - #if BOARD_NR_SPI >= 2 - case RCC_SPI2: - dma_attach_interrupt(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel, &SPIClass::_spi2EventCallback); - break; - #endif - #if BOARD_NR_SPI >= 3 - case RCC_SPI3: - dma_attach_interrupt(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel, &SPIClass::_spi3EventCallback); - break; - #endif - default: - ASSERT(0); + #if BOARD_NR_SPI >= 1 + case RCC_SPI1: + dma_attach_interrupt(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel, &SPIClass::_spi1EventCallback); + break; + #endif + #if BOARD_NR_SPI >= 2 + case RCC_SPI2: + dma_attach_interrupt(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel, &SPIClass::_spi2EventCallback); + break; + #endif + #if BOARD_NR_SPI >= 3 + case RCC_SPI3: + dma_attach_interrupt(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel, &SPIClass::_spi3EventCallback); + break; + #endif + default: ASSERT(0); } } else { diff --git a/Marlin/src/HAL/STM32F1/SPI.h b/Marlin/src/HAL/STM32F1/SPI.h index 13f4d5ed6c..27bf684388 100644 --- a/Marlin/src/HAL/STM32F1/SPI.h +++ b/Marlin/src/HAL/STM32F1/SPI.h @@ -33,6 +33,15 @@ #include #include +// Number of SPI ports +#ifdef BOARD_SPI3_SCK_PIN + #define BOARD_NR_SPI 3 +#elif defined(BOARD_SPI2_SCK_PIN) + #define BOARD_NR_SPI 2 +#elif defined(BOARD_SPI1_SCK_PIN) + #define BOARD_NR_SPI 1 +#endif + // SPI_HAS_TRANSACTION means SPI has // - beginTransaction() // - endTransaction() @@ -49,7 +58,7 @@ #define SPI_CLOCK_DIV128 SPI_BAUD_PCLK_DIV_128 #define SPI_CLOCK_DIV256 SPI_BAUD_PCLK_DIV_256 -/* +/** * Roger Clark. 20150106 * Commented out redundant AVR defined * @@ -144,7 +153,7 @@ private: friend class SPIClass; }; -/* +/** * Kept for compat. */ static const uint8_t ff = 0xFF; @@ -224,7 +233,7 @@ public: void onReceive(void(*)()); void onTransmit(void(*)()); - /* + /** * I/O */ @@ -305,7 +314,7 @@ public: uint8_t dmaSendRepeat(uint16_t length); uint8_t dmaSendAsync(const void * transmitBuf, uint16_t length, bool minc = 1); - /* + /** * Pin accessors */ @@ -389,7 +398,7 @@ private: void updateSettings(); - /* + /** * Functions added for DMA transfers with Callback. * Experimental. */ diff --git a/Marlin/src/HAL/STM32F1/Servo.cpp b/Marlin/src/HAL/STM32F1/Servo.cpp index 47ffb631cf..7aa8fe3d00 100644 --- a/Marlin/src/HAL/STM32F1/Servo.cpp +++ b/Marlin/src/HAL/STM32F1/Servo.cpp @@ -4,7 +4,6 @@ * * Based on Sprinter and grbl. * Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm - * Copyright (c) 2017 Victor Perez * * 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 diff --git a/Marlin/src/HAL/STM32F1/Servo.h b/Marlin/src/HAL/STM32F1/Servo.h index 745a1c93f0..ffafc23833 100644 --- a/Marlin/src/HAL/STM32F1/Servo.h +++ b/Marlin/src/HAL/STM32F1/Servo.h @@ -4,7 +4,6 @@ * * Based on Sprinter and grbl. * Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm - * Copyright (c) 2017 Victor Perez * * 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 diff --git a/Marlin/src/HAL/STM32F1/adc.h b/Marlin/src/HAL/STM32F1/adc.h new file mode 100644 index 0000000000..25f4a7ce16 --- /dev/null +++ b/Marlin/src/HAL/STM32F1/adc.h @@ -0,0 +1,57 @@ +/** + * Marlin 3D Printer Firmware + * Copyright (c) 2023 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] + * + * Based on Sprinter and grbl. + * Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (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 + +/** + * HAL for stm32duino.com based on Libmaple and compatible (STM32F1) + * + * adc.h - Define enumerated indices for enabled ADC Features + */ + +#include "../../inc/MarlinConfig.h" + +enum ADCIndex : uint8_t { + OPTITEM(HAS_TEMP_ADC_0, TEMP_0 ) + OPTITEM(HAS_TEMP_ADC_1, TEMP_1 ) + OPTITEM(HAS_TEMP_ADC_2, TEMP_2 ) + OPTITEM(HAS_TEMP_ADC_3, TEMP_3 ) + OPTITEM(HAS_TEMP_ADC_4, TEMP_4 ) + OPTITEM(HAS_TEMP_ADC_5, TEMP_5 ) + OPTITEM(HAS_TEMP_ADC_6, TEMP_6 ) + OPTITEM(HAS_TEMP_ADC_7, TEMP_7 ) + OPTITEM(HAS_TEMP_ADC_BED, TEMP_BED ) + OPTITEM(HAS_TEMP_ADC_CHAMBER, TEMP_CHAMBER ) + OPTITEM(HAS_TEMP_ADC_PROBE, TEMP_PROBE ) + OPTITEM(HAS_TEMP_ADC_COOLER, TEMP_COOLER ) + OPTITEM(HAS_TEMP_ADC_BOARD, TEMP_BOARD ) + OPTITEM(HAS_TEMP_ADC_SOC, TEMP_SOC ) + OPTITEM(FILAMENT_WIDTH_SENSOR, FILWIDTH ) + OPTITEM(HAS_ADC_BUTTONS, ADC_KEY ) + OPTITEM(HAS_JOY_ADC_X, JOY_X ) + OPTITEM(HAS_JOY_ADC_Y, JOY_Y ) + OPTITEM(HAS_JOY_ADC_Z, JOY_Z ) + OPTITEM(POWER_MONITOR_CURRENT, POWERMON_CURRENT ) + OPTITEM(POWER_MONITOR_VOLTAGE, POWERMON_VOLTAGE ) + ADC_COUNT +}; + +extern uint16_t adc_results[ADC_COUNT]; diff --git a/Marlin/src/HAL/STM32F1/dogm/u8g_com_stm32duino_swspi.cpp b/Marlin/src/HAL/STM32F1/dogm/u8g_com_stm32duino_swspi.cpp index 26ea1ea19a..fc421897c4 100644 --- a/Marlin/src/HAL/STM32F1/dogm/u8g_com_stm32duino_swspi.cpp +++ b/Marlin/src/HAL/STM32F1/dogm/u8g_com_stm32duino_swspi.cpp @@ -24,7 +24,7 @@ #include "../../../inc/MarlinConfig.h" -#if BOTH(HAS_MARLINUI_U8GLIB, FORCE_SOFT_SPI) +#if ALL(HAS_MARLINUI_U8GLIB, FORCE_SOFT_SPI) #include #include "../../shared/HAL_SPI.h" @@ -37,7 +37,7 @@ static uint8_t SPI_speed = LCD_SPI_SPEED; static inline uint8_t swSpiTransfer_mode_0(uint8_t b, const uint8_t spi_speed, const pin_t miso_pin=-1) { - LOOP_L_N(i, 8) { + for (uint8_t i = 0; i < 8; ++i) { if (spi_speed == 0) { WRITE(DOGLCD_MOSI, !!(b & 0x80)); WRITE(DOGLCD_SCK, HIGH); @@ -47,16 +47,16 @@ static inline uint8_t swSpiTransfer_mode_0(uint8_t b, const uint8_t spi_speed, c } else { const uint8_t state = (b & 0x80) ? HIGH : LOW; - LOOP_L_N(j, spi_speed) + for (uint8_t j = 0; j < spi_speed; ++j) WRITE(DOGLCD_MOSI, state); - LOOP_L_N(j, spi_speed + (miso_pin >= 0 ? 0 : 1)) + for (uint8_t j = 0; j < spi_speed + (miso_pin >= 0 ? 0 : 1); ++j) WRITE(DOGLCD_SCK, HIGH); b <<= 1; if (miso_pin >= 0 && READ(miso_pin)) b |= 1; - LOOP_L_N(j, spi_speed) + for (uint8_t j = 0; j < spi_speed; ++j) WRITE(DOGLCD_SCK, LOW); } } @@ -64,7 +64,7 @@ static inline uint8_t swSpiTransfer_mode_0(uint8_t b, const uint8_t spi_speed, c } static inline uint8_t swSpiTransfer_mode_3(uint8_t b, const uint8_t spi_speed, const pin_t miso_pin=-1) { - LOOP_L_N(i, 8) { + for (uint8_t i = 0; i < 8; ++i) { const uint8_t state = (b & 0x80) ? HIGH : LOW; if (spi_speed == 0) { WRITE(DOGLCD_SCK, LOW); @@ -73,13 +73,13 @@ static inline uint8_t swSpiTransfer_mode_3(uint8_t b, const uint8_t spi_speed, c WRITE(DOGLCD_SCK, HIGH); } else { - LOOP_L_N(j, spi_speed + (miso_pin >= 0 ? 0 : 1)) + for (uint8_t j = 0; j < spi_speed + (miso_pin >= 0 ? 0 : 1); ++j) WRITE(DOGLCD_SCK, LOW); - LOOP_L_N(j, spi_speed) + for (uint8_t j = 0; j < spi_speed; ++j) WRITE(DOGLCD_MOSI, state); - LOOP_L_N(j, spi_speed) + for (uint8_t j = 0; j < spi_speed; ++j) WRITE(DOGLCD_SCK, HIGH); } b <<= 1; @@ -88,7 +88,7 @@ static inline uint8_t swSpiTransfer_mode_3(uint8_t b, const uint8_t spi_speed, c return b; } -static void u8g_sw_spi_HAL_STM32F1_shift_out(uint8_t val) { +static void u8g_sw_spi_shift_out(uint8_t val) { #if ENABLED(FYSETC_MINI_12864) swSpiTransfer_mode_3(val, SPI_speed); #else @@ -139,13 +139,13 @@ uint8_t u8g_com_HAL_STM32F1_sw_spi_fn(u8g_t *u8g, uint8_t msg, uint8_t arg_val, break; case U8G_COM_MSG_WRITE_BYTE: - u8g_sw_spi_HAL_STM32F1_shift_out(arg_val); + u8g_sw_spi_shift_out(arg_val); break; case U8G_COM_MSG_WRITE_SEQ: { uint8_t *ptr = (uint8_t *)arg_ptr; while (arg_val > 0) { - u8g_sw_spi_HAL_STM32F1_shift_out(*ptr++); + u8g_sw_spi_shift_out(*ptr++); arg_val--; } } break; @@ -153,7 +153,7 @@ uint8_t u8g_com_HAL_STM32F1_sw_spi_fn(u8g_t *u8g, uint8_t msg, uint8_t arg_val, case U8G_COM_MSG_WRITE_SEQ_P: { uint8_t *ptr = (uint8_t *)arg_ptr; while (arg_val > 0) { - u8g_sw_spi_HAL_STM32F1_shift_out(u8g_pgm_read(ptr)); + u8g_sw_spi_shift_out(u8g_pgm_read(ptr)); ptr++; arg_val--; } diff --git a/Marlin/src/HAL/STM32F1/eeprom_flash.cpp b/Marlin/src/HAL/STM32F1/eeprom_flash.cpp index e7d9dd29e2..48fb2d286c 100644 --- a/Marlin/src/HAL/STM32F1/eeprom_flash.cpp +++ b/Marlin/src/HAL/STM32F1/eeprom_flash.cpp @@ -1,10 +1,9 @@ /** * Marlin 3D Printer Firmware - * * Copyright (c) 2020 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] - * Copyright (c) 2016 Bob Cousins bobcousins42@googlemail.com - * Copyright (c) 2015-2016 Nico Tonnhofer wurstnase.reprap@gmail.com - * Copyright (c) 2016 Victor Perez victor_pv@hotmail.com + * + * 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 diff --git a/Marlin/src/HAL/STM32F1/eeprom_sdcard.cpp b/Marlin/src/HAL/STM32F1/eeprom_sdcard.cpp index d608ccee14..9cfa97c1ab 100644 --- a/Marlin/src/HAL/STM32F1/eeprom_sdcard.cpp +++ b/Marlin/src/HAL/STM32F1/eeprom_sdcard.cpp @@ -47,7 +47,7 @@ static char _ALIGN(4) HAL_eeprom_data[MARLIN_EEPROM_SIZE]; bool PersistentStore::access_start() { if (!card.isMounted()) return false; - SdFile file, root = card.getroot(); + MediaFile file, root = card.getroot(); if (!file.open(&root, EEPROM_FILENAME, O_RDONLY)) return true; // false aborts the save @@ -62,7 +62,7 @@ bool PersistentStore::access_start() { bool PersistentStore::access_finish() { if (!card.isMounted()) return false; - SdFile file, root = card.getroot(); + MediaFile file, root = card.getroot(); int bytes_written = 0; if (file.open(&root, EEPROM_FILENAME, O_CREAT | O_WRITE | O_TRUNC)) { bytes_written = file.write(HAL_eeprom_data, MARLIN_EEPROM_SIZE); diff --git a/Marlin/src/HAL/STM32F1/endstop_interrupts.h b/Marlin/src/HAL/STM32F1/endstop_interrupts.h index a1ef8a8c3a..d11b3bf505 100644 --- a/Marlin/src/HAL/STM32F1/endstop_interrupts.h +++ b/Marlin/src/HAL/STM32F1/endstop_interrupts.h @@ -4,7 +4,6 @@ * * Based on Sprinter and grbl. * Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm - * Copyright (c) 2017 Victor Perez * * 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 @@ -54,33 +53,33 @@ void endstop_ISR() { endstops.update(); } void setup_endstop_interrupts() { #define _ATTACH(P) attachInterrupt(P, endstop_ISR, CHANGE) - TERN_(HAS_X_MAX, _ATTACH(X_MAX_PIN)); - TERN_(HAS_X_MIN, _ATTACH(X_MIN_PIN)); - TERN_(HAS_Y_MAX, _ATTACH(Y_MAX_PIN)); - TERN_(HAS_Y_MIN, _ATTACH(Y_MIN_PIN)); - TERN_(HAS_Z_MAX, _ATTACH(Z_MAX_PIN)); - TERN_(HAS_Z_MIN, _ATTACH(Z_MIN_PIN)); - TERN_(HAS_X2_MAX, _ATTACH(X2_MAX_PIN)); - TERN_(HAS_X2_MIN, _ATTACH(X2_MIN_PIN)); - TERN_(HAS_Y2_MAX, _ATTACH(Y2_MAX_PIN)); - TERN_(HAS_Y2_MIN, _ATTACH(Y2_MIN_PIN)); - TERN_(HAS_Z2_MAX, _ATTACH(Z2_MAX_PIN)); - TERN_(HAS_Z2_MIN, _ATTACH(Z2_MIN_PIN)); - TERN_(HAS_Z3_MAX, _ATTACH(Z3_MAX_PIN)); - TERN_(HAS_Z3_MIN, _ATTACH(Z3_MIN_PIN)); - TERN_(HAS_Z4_MAX, _ATTACH(Z4_MAX_PIN)); - TERN_(HAS_Z4_MIN, _ATTACH(Z4_MIN_PIN)); - TERN_(HAS_Z_MIN_PROBE_PIN, _ATTACH(Z_MIN_PROBE_PIN)); - TERN_(HAS_I_MAX, _ATTACH(I_MAX_PIN)); - TERN_(HAS_I_MIN, _ATTACH(I_MIN_PIN)); - TERN_(HAS_J_MAX, _ATTACH(J_MAX_PIN)); - TERN_(HAS_J_MIN, _ATTACH(J_MIN_PIN)); - TERN_(HAS_K_MAX, _ATTACH(K_MAX_PIN)); - TERN_(HAS_K_MIN, _ATTACH(K_MIN_PIN)); - TERN_(HAS_U_MAX, _ATTACH(U_MAX_PIN)); - TERN_(HAS_U_MIN, _ATTACH(U_MIN_PIN)); - TERN_(HAS_V_MAX, _ATTACH(V_MAX_PIN)); - TERN_(HAS_V_MIN, _ATTACH(V_MIN_PIN)); - TERN_(HAS_W_MAX, _ATTACH(W_MAX_PIN)); - TERN_(HAS_W_MIN, _ATTACH(W_MIN_PIN)); + TERN_(USE_X_MAX, _ATTACH(X_MAX_PIN)); + TERN_(USE_X_MIN, _ATTACH(X_MIN_PIN)); + TERN_(USE_Y_MAX, _ATTACH(Y_MAX_PIN)); + TERN_(USE_Y_MIN, _ATTACH(Y_MIN_PIN)); + TERN_(USE_Z_MAX, _ATTACH(Z_MAX_PIN)); + TERN_(USE_Z_MIN, _ATTACH(Z_MIN_PIN)); + TERN_(USE_X2_MAX, _ATTACH(X2_MAX_PIN)); + TERN_(USE_X2_MIN, _ATTACH(X2_MIN_PIN)); + TERN_(USE_Y2_MAX, _ATTACH(Y2_MAX_PIN)); + TERN_(USE_Y2_MIN, _ATTACH(Y2_MIN_PIN)); + TERN_(USE_Z2_MAX, _ATTACH(Z2_MAX_PIN)); + TERN_(USE_Z2_MIN, _ATTACH(Z2_MIN_PIN)); + TERN_(USE_Z3_MAX, _ATTACH(Z3_MAX_PIN)); + TERN_(USE_Z3_MIN, _ATTACH(Z3_MIN_PIN)); + TERN_(USE_Z4_MAX, _ATTACH(Z4_MAX_PIN)); + TERN_(USE_Z4_MIN, _ATTACH(Z4_MIN_PIN)); + TERN_(USE_Z_MIN_PROBE, _ATTACH(Z_MIN_PROBE_PIN)); + TERN_(USE_I_MAX, _ATTACH(I_MAX_PIN)); + TERN_(USE_I_MIN, _ATTACH(I_MIN_PIN)); + TERN_(USE_J_MAX, _ATTACH(J_MAX_PIN)); + TERN_(USE_J_MIN, _ATTACH(J_MIN_PIN)); + TERN_(USE_K_MAX, _ATTACH(K_MAX_PIN)); + TERN_(USE_K_MIN, _ATTACH(K_MIN_PIN)); + TERN_(USE_U_MAX, _ATTACH(U_MAX_PIN)); + TERN_(USE_U_MIN, _ATTACH(U_MIN_PIN)); + TERN_(USE_V_MAX, _ATTACH(V_MAX_PIN)); + TERN_(USE_V_MIN, _ATTACH(V_MIN_PIN)); + TERN_(USE_W_MAX, _ATTACH(W_MAX_PIN)); + TERN_(USE_W_MIN, _ATTACH(W_MIN_PIN)); } diff --git a/Marlin/src/HAL/STM32F1/fast_pwm.cpp b/Marlin/src/HAL/STM32F1/fast_pwm.cpp index 297804a3ac..c3f96f0f92 100644 --- a/Marlin/src/HAL/STM32F1/fast_pwm.cpp +++ b/Marlin/src/HAL/STM32F1/fast_pwm.cpp @@ -39,7 +39,7 @@ inline uint8_t timer_and_index_for_pin(const pin_t pin, timer_dev **timer_ptr) { void MarlinHAL::set_pwm_duty(const pin_t pin, const uint16_t v, const uint16_t v_size/*=255*/, const bool invert/*=false*/) { const uint16_t duty = invert ? v_size - v : v; if (PWM_PIN(pin)) { - timer_dev *timer; UNUSED(timer); + timer_dev *timer; if (timer_freq[timer_and_index_for_pin(pin, &timer)] == 0) set_pwm_frequency(pin, PWM_FREQUENCY); const uint8_t channel = PIN_MAP[pin].timer_channel; @@ -55,7 +55,7 @@ void MarlinHAL::set_pwm_duty(const pin_t pin, const uint16_t v, const uint16_t v void MarlinHAL::set_pwm_frequency(const pin_t pin, const uint16_t f_desired) { if (!PWM_PIN(pin)) return; // Don't proceed if no hardware timer - timer_dev *timer; UNUSED(timer); + timer_dev *timer; timer_freq[timer_and_index_for_pin(pin, &timer)] = f_desired; // Protect used timers diff --git a/Marlin/src/HAL/STM32F1/fastio.h b/Marlin/src/HAL/STM32F1/fastio.h index e75254d692..5b3ebaa52c 100644 --- a/Marlin/src/HAL/STM32F1/fastio.h +++ b/Marlin/src/HAL/STM32F1/fastio.h @@ -4,7 +4,6 @@ * * Based on Sprinter and grbl. * Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm - * Copyright (c) 2017 Victor Perez * * 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 diff --git a/Marlin/src/HAL/STM32F1/inc/Conditionals_post.h b/Marlin/src/HAL/STM32F1/inc/Conditionals_post.h index 656fbe1ce2..f130f5cad8 100644 --- a/Marlin/src/HAL/STM32F1/inc/Conditionals_post.h +++ b/Marlin/src/HAL/STM32F1/inc/Conditionals_post.h @@ -24,11 +24,11 @@ // If no real EEPROM, Flash emulation, or SRAM emulation is available fall back to SD emulation #if USE_FALLBACK_EEPROM #define SDCARD_EEPROM_EMULATION -#elif EITHER(I2C_EEPROM, SPI_EEPROM) +#elif ANY(I2C_EEPROM, SPI_EEPROM) #define USE_SHARED_EEPROM 1 #endif -// Allow SDSUPPORT to be disabled -#if DISABLED(SDSUPPORT) - #undef SDIO_SUPPORT +// Allow for no media drives +#if !HAS_MEDIA + #undef ONBOARD_SDIO #endif diff --git a/Marlin/src/HAL/STM32F1/inc/SanityCheck.h b/Marlin/src/HAL/STM32F1/inc/SanityCheck.h index fe8f6e0ec2..1da42dcc8f 100644 --- a/Marlin/src/HAL/STM32F1/inc/SanityCheck.h +++ b/Marlin/src/HAL/STM32F1/inc/SanityCheck.h @@ -25,7 +25,7 @@ * Test STM32F1-specific configuration values for errors at compile-time. */ -#if ENABLED(SDCARD_EEPROM_EMULATION) && DISABLED(SDSUPPORT) +#if ENABLED(SDCARD_EEPROM_EMULATION) && !HAS_MEDIA #undef SDCARD_EEPROM_EMULATION // Avoid additional error noise #if USE_FALLBACK_EEPROM #warning "EEPROM type not specified. Fallback is SDCARD_EEPROM_EMULATION." diff --git a/Marlin/src/HAL/STM32F1/msc_sd.cpp b/Marlin/src/HAL/STM32F1/msc_sd.cpp index f490c83ed8..067b46eb8b 100644 --- a/Marlin/src/HAL/STM32F1/msc_sd.cpp +++ b/Marlin/src/HAL/STM32F1/msc_sd.cpp @@ -1,14 +1,21 @@ /** * Marlin 3D Printer Firmware - * * Copyright (c) 2020 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] * Copyright (c) 2019 BigTreeTech [https://github.com/bigtreetech] * + * 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 . * diff --git a/Marlin/src/HAL/STM32F1/msc_sd.h b/Marlin/src/HAL/STM32F1/msc_sd.h index f4636bdff7..371211efc6 100644 --- a/Marlin/src/HAL/STM32F1/msc_sd.h +++ b/Marlin/src/HAL/STM32F1/msc_sd.h @@ -1,14 +1,21 @@ /** * Marlin 3D Printer Firmware - * * Copyright (c) 2020 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] * Copyright (c) 2019 BigTreeTech [https://github.com/bigtreetech] * + * 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 . * diff --git a/Marlin/src/HAL/STM32F1/onboard_sd.h b/Marlin/src/HAL/STM32F1/onboard_sd.h index f228d068c9..f8846e95bc 100644 --- a/Marlin/src/HAL/STM32F1/onboard_sd.h +++ b/Marlin/src/HAL/STM32F1/onboard_sd.h @@ -1,11 +1,31 @@ -/*----------------------------------------------------------------------- -/ * Copyright (c) 2020 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] -/ * Copyright (c) 2019 BigTreeTech [https://github.com/bigtreetech] -/ * Low level disk interface module include file (C)ChaN, 2015 -/-----------------------------------------------------------------------*/ - +/** + * Marlin 3D Printer Firmware + * Copyright (c) 2020 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] + * + * Based on Sprinter and grbl. + * Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ #pragma once +/*----------------------------------------------------------------------- +/ * Copyright (c) 2019 BigTreeTech [https://github.com/bigtreetech] +/ * Low level disk interface module include file (c) ChaN, 2015 +/-----------------------------------------------------------------------*/ + #define _DISKIO_WRITE 1 /* 1: Enable disk_write function */ #define _DISKIO_IOCTL 1 /* 1: Enable disk_ioctl function */ #define _DISKIO_ISDIO 0 /* 1: Enable iSDIO control function */ diff --git a/Marlin/src/HAL/STM32F1/pinsDebug.h b/Marlin/src/HAL/STM32F1/pinsDebug.h index 7828479658..6f8e48f455 100644 --- a/Marlin/src/HAL/STM32F1/pinsDebug.h +++ b/Marlin/src/HAL/STM32F1/pinsDebug.h @@ -41,11 +41,9 @@ extern const stm32_pin_info PIN_MAP[BOARD_NR_GPIO_PINS]; #define NUMBER_PINS_TOTAL BOARD_NR_GPIO_PINS #define VALID_PIN(pin) (pin >= 0 && pin < BOARD_NR_GPIO_PINS) #define GET_ARRAY_PIN(p) pin_t(pin_array[p].pin) -#define pwm_status(pin) PWM_PIN(pin) #define digitalRead_mod(p) extDigitalRead(p) #define PRINT_PIN(p) do{ sprintf_P(buffer, PSTR("%3hd "), int16_t(p)); SERIAL_ECHO(buffer); }while(0) #define PRINT_PIN_ANALOG(p) do{ sprintf_P(buffer, PSTR(" (A%2d) "), DIGITAL_PIN_TO_ANALOG_PIN(pin)); SERIAL_ECHO(buffer); }while(0) -#define PRINT_PORT(p) print_port(p) #define PRINT_ARRAY_NAME(x) do{ sprintf_P(buffer, PSTR("%-" STRINGIFY(MAX_NAME_LENGTH) "s"), pin_array[x].name); SERIAL_ECHO(buffer); }while(0) #define MULTI_NAME_PAD 21 // space needed to be pretty if not first name assigned to a pin @@ -54,20 +52,18 @@ extern const stm32_pin_info PIN_MAP[BOARD_NR_GPIO_PINS]; #define M43_NEVER_TOUCH(Q) (Q >= 9 && Q <= 12) // SERIAL/USB pins PA9(TX) PA10(RX) #endif -static int8_t get_pin_mode(pin_t pin) { - return VALID_PIN(pin) ? _GET_MODE(pin) : -1; -} +int8_t get_pin_mode(const pin_t pin) { return VALID_PIN(pin) ? _GET_MODE(pin) : -1; } -static pin_t DIGITAL_PIN_TO_ANALOG_PIN(pin_t pin) { +pin_t DIGITAL_PIN_TO_ANALOG_PIN(const pin_t pin) { if (!VALID_PIN(pin)) return -1; - int8_t adc_channel = int8_t(PIN_MAP[pin].adc_channel); + pin_t adc_channel = pin_t(PIN_MAP[pin].adc_channel); #ifdef NUM_ANALOG_INPUTS - if (adc_channel >= NUM_ANALOG_INPUTS) adc_channel = ADCx; + if (adc_channel >= NUM_ANALOG_INPUTS) adc_channel = (pin_t)ADCx; #endif - return pin_t(adc_channel); + return adc_channel; } -static bool IS_ANALOG(pin_t pin) { +bool IS_ANALOG(const pin_t pin) { if (!VALID_PIN(pin)) return false; if (PIN_MAP[pin].adc_channel != ADCx) { #ifdef NUM_ANALOG_INPUTS @@ -78,11 +74,11 @@ static bool IS_ANALOG(pin_t pin) { return false; } -static bool GET_PINMODE(const pin_t pin) { +bool GET_PINMODE(const pin_t pin) { return VALID_PIN(pin) && !IS_INPUT(pin); } -static bool GET_ARRAY_IS_DIGITAL(const int16_t array_pin) { +bool GET_ARRAY_IS_DIGITAL(const int16_t array_pin) { const pin_t pin = GET_ARRAY_PIN(array_pin); return (!IS_ANALOG(pin) #ifdef NUM_ANALOG_INPUTS @@ -93,12 +89,12 @@ static bool GET_ARRAY_IS_DIGITAL(const int16_t array_pin) { #include "../../inc/MarlinConfig.h" // Allow pins/pins.h to set density -static void pwm_details(const pin_t pin) { +void pwm_details(const pin_t pin) { if (PWM_PIN(pin)) { timer_dev * const tdev = PIN_MAP[pin].timer_device; const uint8_t channel = PIN_MAP[pin].timer_channel; const char num = ( - #if EITHER(STM32_HIGH_DENSITY, STM32_XL_DENSITY) + #if ANY(STM32_HIGH_DENSITY, STM32_XL_DENSITY) tdev == &timer8 ? '8' : tdev == &timer5 ? '5' : #endif @@ -113,7 +109,9 @@ static void pwm_details(const pin_t pin) { } } -static void print_port(pin_t pin) { +bool pwm_status(const pin_t pin) { return PWM_PIN(pin); } + +void print_port(const pin_t pin) { const char port = 'A' + char(pin >> 4); // pin div 16 const int16_t gbit = PIN_MAP[pin].gpio_bit; char buffer[8]; diff --git a/Marlin/src/HAL/STM32F1/sdio.cpp b/Marlin/src/HAL/STM32F1/sdio.cpp index 6e41d2cbf1..23f984eff3 100644 --- a/Marlin/src/HAL/STM32F1/sdio.cpp +++ b/Marlin/src/HAL/STM32F1/sdio.cpp @@ -4,7 +4,6 @@ * * Based on Sprinter and grbl. * Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm - * Copyright (c) 2017 Victor Perez * * 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 @@ -26,7 +25,7 @@ #include "../../inc/MarlinConfig.h" // Allow pins/pins.h to set density -#if EITHER(STM32_HIGH_DENSITY, STM32_XL_DENSITY) +#if ANY(STM32_HIGH_DENSITY, STM32_XL_DENSITY) #include "sdio.h" @@ -136,8 +135,13 @@ bool SDIO_ReadBlock_DMA(uint32_t blockAddress, uint8_t *data) { } bool SDIO_ReadBlock(uint32_t blockAddress, uint8_t *data) { - uint32_t retries = SDIO_READ_RETRIES; - while (retries--) if (SDIO_ReadBlock_DMA(blockAddress, data)) return true; + uint8_t retries = SDIO_READ_RETRIES; + while (retries--) { + if (SDIO_ReadBlock_DMA(blockAddress, data)) return true; + #if SD_RETRY_DELAY_MS + delay(SD_RETRY_DELAY_MS); + #endif + } return false; } diff --git a/Marlin/src/HAL/STM32F1/sdio.h b/Marlin/src/HAL/STM32F1/sdio.h index 8777299f01..2371601e99 100644 --- a/Marlin/src/HAL/STM32F1/sdio.h +++ b/Marlin/src/HAL/STM32F1/sdio.h @@ -1,9 +1,9 @@ /** * Marlin 3D Printer Firmware - * * Copyright (c) 2020 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] - * Copyright (c) 2016 Bob Cousins bobcousins42@googlemail.com - * Copyright (c) 2017 Victor Perez + * + * 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 diff --git a/Marlin/src/HAL/STM32F1/tft/tft_fsmc.cpp b/Marlin/src/HAL/STM32F1/tft/tft_fsmc.cpp index 5b52fb416f..51f70b9365 100644 --- a/Marlin/src/HAL/STM32F1/tft/tft_fsmc.cpp +++ b/Marlin/src/HAL/STM32F1/tft/tft_fsmc.cpp @@ -20,6 +20,8 @@ * */ +#ifdef __STM32F1__ + #include "../../../inc/MarlinConfig.h" #if HAS_FSMC_TFT @@ -85,7 +87,7 @@ __attribute__((always_inline)) __STATIC_INLINE void __DSB() { #define FSMC_DATA_SETUP_TIME 15 // DataSetupTime static uint8_t fsmcInit = 0; -void TFT_FSMC::Init() { +void TFT_FSMC::init() { uint8_t cs = FSMC_CS_PIN, rs = FSMC_RS_PIN; uint32_t controllerAddress; @@ -179,35 +181,35 @@ void TFT_FSMC::Init() { LCD = (LCD_CONTROLLER_TypeDef*)controllerAddress; } -void TFT_FSMC::Transmit(uint16_t Data) { - LCD->RAM = Data; +void TFT_FSMC::transmit(uint16_t data) { + LCD->RAM = data; __DSB(); } -void TFT_FSMC::WriteReg(uint16_t Reg) { - LCD->REG = Reg; +void TFT_FSMC::writeReg(const uint16_t inReg) { + LCD->REG = inReg; __DSB(); } -uint32_t TFT_FSMC::GetID() { +uint32_t TFT_FSMC::getID() { uint32_t id; - WriteReg(0x0000); + writeReg(0x0000); id = LCD->RAM; if (id == 0) - id = ReadID(LCD_READ_ID); + id = readID(LCD_READ_ID); if ((id & 0xFFFF) == 0 || (id & 0xFFFF) == 0xFFFF) - id = ReadID(LCD_READ_ID4); + id = readID(LCD_READ_ID4); if ((id & 0xFF00) == 0 && (id & 0xFF) != 0) - id = ReadID(LCD_READ_ID4); + id = readID(LCD_READ_ID4); return id; } - uint32_t TFT_FSMC::ReadID(uint16_t Reg) { + uint32_t TFT_FSMC::readID(const uint16_t inReg) { uint32_t id; - WriteReg(Reg); + writeReg(inReg); id = LCD->RAM; // dummy read - id = Reg << 24; + id = inReg << 24; id |= (LCD->RAM & 0x00FF) << 16; id |= (LCD->RAM & 0x00FF) << 8; id |= LCD->RAM & 0x00FF; @@ -215,23 +217,52 @@ uint32_t TFT_FSMC::GetID() { } bool TFT_FSMC::isBusy() { + #define __IS_DMA_CONFIGURED(__DMAx__, __CHx__) (dma_channel_regs(__DMAx__, __CHx__)->CPAR != 0) + + if (!__IS_DMA_CONFIGURED(FSMC_DMA_DEV, FSMC_DMA_CHANNEL)) return false; + + // Check if DMA transfer error or transfer complete flags are set + if ((dma_get_isr_bits(FSMC_DMA_DEV, FSMC_DMA_CHANNEL) & (DMA_ISR_TCIF | DMA_ISR_TEIF)) == 0) return true; + + __DSB(); + abort(); return false; } -void TFT_FSMC::Abort() { +void TFT_FSMC::abort() { + dma_channel_reg_map *channel_regs = dma_channel_regs(FSMC_DMA_DEV, FSMC_DMA_CHANNEL); + dma_disable(FSMC_DMA_DEV, FSMC_DMA_CHANNEL); // Abort DMA transfer if any + + // Deconfigure DMA + channel_regs->CCR = 0U; + channel_regs->CNDTR = 0U; + channel_regs->CMAR = 0U; + channel_regs->CPAR = 0U; } -void TFT_FSMC::TransmitDMA(uint32_t MemoryIncrease, uint16_t *Data, uint16_t Count) { +void TFT_FSMC::transmitDMA(uint32_t memoryIncrease, uint16_t *data, uint16_t count) { + // TODO: HAL STM32 uses DMA2_Channel1 for FSMC on STM32F1 + dma_setup_transfer(FSMC_DMA_DEV, FSMC_DMA_CHANNEL, data, DMA_SIZE_16BITS, &LCD->RAM, DMA_SIZE_16BITS, DMA_MEM_2_MEM | memoryIncrease); + dma_set_num_transfers(FSMC_DMA_DEV, FSMC_DMA_CHANNEL, count); + dma_clear_isr_bits(FSMC_DMA_DEV, FSMC_DMA_CHANNEL); + dma_enable(FSMC_DMA_DEV, FSMC_DMA_CHANNEL); + + TERN_(TFT_SHARED_IO, while (isBusy())); +} + +void TFT_FSMC::transmit(uint32_t memoryIncrease, uint16_t *data, uint16_t count) { #if defined(FSMC_DMA_DEV) && defined(FSMC_DMA_CHANNEL) - dma_setup_transfer(FSMC_DMA_DEV, FSMC_DMA_CHANNEL, Data, DMA_SIZE_16BITS, &LCD->RAM, DMA_SIZE_16BITS, DMA_MEM_2_MEM | MemoryIncrease); - dma_set_num_transfers(FSMC_DMA_DEV, FSMC_DMA_CHANNEL, Count); + dma_setup_transfer(FSMC_DMA_DEV, FSMC_DMA_CHANNEL, data, DMA_SIZE_16BITS, &LCD->RAM, DMA_SIZE_16BITS, DMA_MEM_2_MEM | memoryIncrease); + dma_set_num_transfers(FSMC_DMA_DEV, FSMC_DMA_CHANNEL, count); dma_clear_isr_bits(FSMC_DMA_DEV, FSMC_DMA_CHANNEL); dma_enable(FSMC_DMA_DEV, FSMC_DMA_CHANNEL); - while ((dma_get_isr_bits(FSMC_DMA_DEV, FSMC_DMA_CHANNEL) & 0x0A) == 0) {}; - dma_disable(FSMC_DMA_DEV, FSMC_DMA_CHANNEL); + while ((dma_get_isr_bits(FSMC_DMA_DEV, FSMC_DMA_CHANNEL) & (DMA_CCR_TEIE | DMA_CCR_TCIE)) == 0) {} + abort(); #endif } #endif // HAS_FSMC_TFT + +#endif // __STM32F1__ diff --git a/Marlin/src/HAL/STM32F1/tft/tft_fsmc.h b/Marlin/src/HAL/STM32F1/tft/tft_fsmc.h index d9ee1f4c77..214acf127e 100644 --- a/Marlin/src/HAL/STM32F1/tft/tft_fsmc.h +++ b/Marlin/src/HAL/STM32F1/tft/tft_fsmc.h @@ -30,9 +30,20 @@ #include +#ifndef FSMC_DMA_DEV + #define FSMC_DMA_DEV DMA2 +#endif +#ifndef FSMC_DMA_CHANNEL + #define FSMC_DMA_CHANNEL DMA_CH5 +#endif + #define DATASIZE_8BIT DMA_SIZE_8BITS #define DATASIZE_16BIT DMA_SIZE_16BITS #define TFT_IO_DRIVER TFT_FSMC +#define DMA_MAX_WORDS 0xFFFF + +#define DMA_PINC_ENABLE DMA_PINC_MODE +#define DMA_PINC_DISABLE 0 typedef struct { __IO uint16_t REG; @@ -43,29 +54,31 @@ class TFT_FSMC { private: static LCD_CONTROLLER_TypeDef *LCD; - static uint32_t ReadID(uint16_t Reg); - static void Transmit(uint16_t Data); - static void TransmitDMA(uint32_t MemoryIncrease, uint16_t *Data, uint16_t Count); + static uint32_t readID(const uint16_t inReg); + static void transmit(uint16_t data); + static void transmit(uint32_t memoryIncrease, uint16_t *data, uint16_t count); + static void transmitDMA(uint32_t memoryIncrease, uint16_t *data, uint16_t count); public: - static void Init(); - static uint32_t GetID(); + static void init(); + static uint32_t getID(); static bool isBusy(); - static void Abort(); + static void abort(); - static void DataTransferBegin(uint16_t DataWidth = DATASIZE_16BIT) {}; - static void DataTransferEnd() {}; + static void dataTransferBegin(uint16_t dataWidth=DATASIZE_16BIT) {}; + static void dataTransferEnd() {}; - static void WriteData(uint16_t Data) { Transmit(Data); } - static void WriteReg(uint16_t Reg); + static void writeData(uint16_t data) { transmit(data); } + static void writeReg(const uint16_t inReg); - static void WriteSequence(uint16_t *Data, uint16_t Count) { TransmitDMA(DMA_PINC_MODE, Data, Count); } - static void WriteMultiple(uint16_t Color, uint16_t Count) { static uint16_t Data; Data = Color; TransmitDMA(DMA_CIRC_MODE, &Data, Count); } - static void WriteMultiple(uint16_t Color, uint32_t Count) { - static uint16_t Data; Data = Color; - while (Count > 0) { - TransmitDMA(DMA_CIRC_MODE, &Data, Count > 0xFFFF ? 0xFFFF : Count); - Count = Count > 0xFFFF ? Count - 0xFFFF : 0; + static void writeSequence_DMA(uint16_t *data, uint16_t count) { transmitDMA(DMA_PINC_ENABLE, data, count); } + static void writeMultiple_DMA(uint16_t color, uint16_t count) { static uint16_t data; data = color; transmitDMA(DMA_PINC_DISABLE, &data, count); } + + static void writeSequence(uint16_t *data, uint16_t count) { transmit(DMA_PINC_ENABLE, data, count); } + static void writeMultiple(uint16_t color, uint32_t count) { + while (count > 0) { + transmit(DMA_PINC_DISABLE, &color, count > DMA_MAX_WORDS ? DMA_MAX_WORDS : count); + count = count > DMA_MAX_WORDS ? count - DMA_MAX_WORDS : 0; } } }; diff --git a/Marlin/src/HAL/STM32F1/tft/tft_spi.cpp b/Marlin/src/HAL/STM32F1/tft/tft_spi.cpp index f447cec811..f26103b25d 100644 --- a/Marlin/src/HAL/STM32F1/tft/tft_spi.cpp +++ b/Marlin/src/HAL/STM32F1/tft/tft_spi.cpp @@ -20,15 +20,17 @@ * */ +#ifdef __STM32F1__ + #include "../../../inc/MarlinConfig.h" #if HAS_SPI_TFT #include "tft_spi.h" -SPIClass TFT_SPI::SPIx(1); +SPIClass TFT_SPI::SPIx(TFT_SPI_DEVICE); -void TFT_SPI::Init() { +void TFT_SPI::init() { #if PIN_EXISTS(TFT_RESET) OUT_WRITE(TFT_RESET_PIN, HIGH); delay(100); @@ -46,7 +48,7 @@ void TFT_SPI::Init() { * STM32F1 has 3 SPI ports, SPI1 in APB2, SPI2/SPI3 in APB1 * so the minimum prescale of SPI1 is DIV4, SPI2/SPI3 is DIV2 */ - #if SPI_DEVICE == 1 + #if TFT_SPI_DEVICE == 1 #define SPI_CLOCK_MAX SPI_CLOCK_DIV4 #else #define SPI_CLOCK_MAX SPI_CLOCK_DIV2 @@ -62,27 +64,27 @@ void TFT_SPI::Init() { case SPI_SPEED_6: clock = SPI_CLOCK_DIV64; break; default: clock = SPI_CLOCK_DIV2; // Default from the SPI library } - SPIx.setModule(1); + SPIx.setModule(TFT_SPI_DEVICE); SPIx.setClockDivider(clock); SPIx.setBitOrder(MSBFIRST); SPIx.setDataMode(SPI_MODE0); } -void TFT_SPI::DataTransferBegin(uint16_t DataSize) { - SPIx.setDataSize(DataSize); +void TFT_SPI::dataTransferBegin(uint16_t dataSize) { + SPIx.setDataSize(dataSize); SPIx.begin(); - OUT_WRITE(TFT_CS_PIN, LOW); + WRITE(TFT_CS_PIN, LOW); } #ifdef TFT_DEFAULT_DRIVER #include "../../../lcd/tft_io/tft_ids.h" #endif -uint32_t TFT_SPI::GetID() { +uint32_t TFT_SPI::getID() { uint32_t id; - id = ReadID(LCD_READ_ID); + id = readID(LCD_READ_ID); if ((id & 0xFFFF) == 0 || (id & 0xFFFF) == 0xFFFF) { - id = ReadID(LCD_READ_ID4); + id = readID(LCD_READ_ID4); #ifdef TFT_DEFAULT_DRIVER if ((id & 0xFFFF) == 0 || (id & 0xFFFF) == 0xFFFF) id = TFT_DEFAULT_DRIVER; @@ -91,39 +93,78 @@ uint32_t TFT_SPI::GetID() { return id; } -uint32_t TFT_SPI::ReadID(uint16_t Reg) { - #if !PIN_EXISTS(TFT_MISO) - return 0; - #else - uint8_t d = 0; - uint32_t data = 0; - SPIx.setClockDivider(SPI_CLOCK_DIV16); - DataTransferBegin(DATASIZE_8BIT); - WriteReg(Reg); +uint32_t TFT_SPI::readID(const uint16_t inReg) { + uint32_t data = 0; - LOOP_L_N(i, 4) { - SPIx.read((uint8_t*)&d, 1); + #if PIN_EXISTS(TFT_MISO) + SPIx.setClockDivider(SPI_CLOCK_DIV16); + dataTransferBegin(DATASIZE_8BIT); + writeReg(inReg); + + for (uint8_t i = 0; i < 4; ++i) { + uint8_t d; + SPIx.read(&d, 1); data = (data << 8) | d; } - DataTransferEnd(); + dataTransferEnd(); SPIx.setClockDivider(SPI_CLOCK_MAX); - - return data >> 7; #endif + + return data >> 7; } -bool TFT_SPI::isBusy() { return false; } +bool TFT_SPI::isBusy() { + #define __IS_DMA_CONFIGURED(__DMAx__, __CHx__) (dma_channel_regs(__DMAx__, __CHx__)->CPAR != 0) -void TFT_SPI::Abort() { DataTransferEnd(); } + if (!__IS_DMA_CONFIGURED(DMAx, DMA_CHx)) return false; -void TFT_SPI::Transmit(uint16_t Data) { SPIx.send(Data); } + if (dma_get_isr_bits(DMAx, DMA_CHx) & DMA_ISR_TEIF) { + // You should not be here - DMA transfer error flag is set + // Abort DMA transfer and release SPI + } + else { + // Check if DMA transfer completed flag is set + if (!(dma_get_isr_bits(DMAx, DMA_CHx) & DMA_ISR_TCIF)) return true; + // Check if SPI TX butter is empty and SPI is idle + if (!(SPIdev->regs->SR & SPI_SR_TXE) || (SPIdev->regs->SR & SPI_SR_BSY)) return true; + } -void TFT_SPI::TransmitDMA(uint32_t MemoryIncrease, uint16_t *Data, uint16_t Count) { - DataTransferBegin(); - OUT_WRITE(TFT_DC_PIN, HIGH); - SPIx.dmaSend(Data, Count, MemoryIncrease == DMA_MINC_ENABLE); - DataTransferEnd(); + abort(); + return false; +} + +void TFT_SPI::abort() { + dma_channel_reg_map *channel_regs = dma_channel_regs(DMAx, DMA_CHx); + + dma_disable(DMAx, DMA_CHx); // Abort DMA transfer if any + spi_tx_dma_disable(SPIdev); + + // Deconfigure DMA + channel_regs->CCR = 0U; + channel_regs->CNDTR = 0U; + channel_regs->CMAR = 0U; + channel_regs->CPAR = 0U; + + dataTransferEnd(); +} + +void TFT_SPI::transmit(uint16_t data) { SPIx.send(data); } + +void TFT_SPI::transmitDMA(uint32_t memoryIncrease, uint16_t *data, uint16_t count) { + dataTransferBegin(); + SPIx.dmaSendAsync(data, count, memoryIncrease == DMA_MINC_ENABLE); + + TERN_(TFT_SHARED_IO, while (isBusy())); +} + +void TFT_SPI::transmit(uint32_t memoryIncrease, uint16_t *data, uint16_t count) { + WRITE(TFT_DC_PIN, HIGH); + dataTransferBegin(); + SPIx.dmaSend(data, count, memoryIncrease == DMA_MINC_ENABLE); + dataTransferEnd(); } #endif // HAS_SPI_TFT + +#endif // __STM32F1__ diff --git a/Marlin/src/HAL/STM32F1/tft/tft_spi.h b/Marlin/src/HAL/STM32F1/tft/tft_spi.h index da9a8e0c22..af53f352be 100644 --- a/Marlin/src/HAL/STM32F1/tft/tft_spi.h +++ b/Marlin/src/HAL/STM32F1/tft/tft_spi.h @@ -25,6 +25,27 @@ #include +#define IS_SPI(N) (BOARD_NR_SPI >= N && (TFT_SCK_PIN == BOARD_SPI##N##_SCK_PIN) && (TFT_MOSI_PIN == BOARD_SPI##N##_MOSI_PIN) && (TFT_MISO_PIN == BOARD_SPI##N##_MISO_PIN)) +#if IS_SPI(1) + #define TFT_SPI_DEVICE 1 + #define SPIdev SPI1 + #define DMAx DMA1 + #define DMA_CHx DMA_CH3 +#elif IS_SPI(2) + #define TFT_SPI_DEVICE 2 + #define SPIdev SPI2 + #define DMAx DMA1 + #define DMA_CHx DMA_CH5 +#elif IS_SPI(3) + #define TFT_SPI_DEVICE 3 + #define SPIdev SPI3 + #define DMAx DMA2 + #define DMA_CHx DMA_CH2 +#else + #error "Invalid TFT SPI configuration." +#endif +#undef IS_SPI + #ifndef LCD_READ_ID #define LCD_READ_ID 0x04 // Read display identification information (0xD3 on ILI9341) #endif @@ -32,41 +53,44 @@ #define LCD_READ_ID4 0xD3 // Read display identification information (0xD3 on ILI9341) #endif -#define DATASIZE_8BIT DATA_SIZE_8BIT -#define DATASIZE_16BIT DATA_SIZE_16BIT -#define TFT_IO_DRIVER TFT_SPI +#define DATASIZE_8BIT DATA_SIZE_8BIT +#define DATASIZE_16BIT DATA_SIZE_16BIT +#define TFT_IO_DRIVER TFT_SPI +#define DMA_MAX_WORDS 0xFFFF -#define DMA_MINC_ENABLE 1 -#define DMA_MINC_DISABLE 0 +#define DMA_MINC_ENABLE DMA_MINC_MODE +#define DMA_MINC_DISABLE 0 class TFT_SPI { private: - static uint32_t ReadID(uint16_t Reg); - static void Transmit(uint16_t Data); - static void TransmitDMA(uint32_t MemoryIncrease, uint16_t *Data, uint16_t Count); + static uint32_t readID(const uint16_t inReg); + static void transmit(uint16_t data); + static void transmit(uint32_t memoryIncrease, uint16_t *data, uint16_t count); + static void transmitDMA(uint32_t memoryIncrease, uint16_t *data, uint16_t count); public: static SPIClass SPIx; - static void Init(); - static uint32_t GetID(); + static void init(); + static uint32_t getID(); static bool isBusy(); - static void Abort(); + static void abort(); - static void DataTransferBegin(uint16_t DataWidth = DATA_SIZE_16BIT); - static void DataTransferEnd() { WRITE(TFT_CS_PIN, HIGH); SPIx.end(); }; - static void DataTransferAbort(); + static void dataTransferBegin(uint16_t dataWidth=DATA_SIZE_16BIT); + static void dataTransferEnd() { WRITE(TFT_CS_PIN, HIGH); SPIx.end(); }; + static void dataTransferAbort(); - static void WriteData(uint16_t Data) { Transmit(Data); } - static void WriteReg(uint16_t Reg) { WRITE(TFT_A0_PIN, LOW); Transmit(Reg); WRITE(TFT_A0_PIN, HIGH); } + static void writeData(uint16_t data) { transmit(data); } + static void writeReg(const uint16_t inReg) { WRITE(TFT_DC_PIN, LOW); transmit(inReg); WRITE(TFT_DC_PIN, HIGH); } - static void WriteSequence(uint16_t *Data, uint16_t Count) { TransmitDMA(DMA_MINC_ENABLE, Data, Count); } - static void WriteMultiple(uint16_t Color, uint16_t Count) { static uint16_t Data; Data = Color; TransmitDMA(DMA_MINC_DISABLE, &Data, Count); } - static void WriteMultiple(uint16_t Color, uint32_t Count) { - static uint16_t Data; Data = Color; - while (Count > 0) { - TransmitDMA(DMA_MINC_DISABLE, &Data, Count > 0xFFFF ? 0xFFFF : Count); - Count = Count > 0xFFFF ? Count - 0xFFFF : 0; + static void writeSequence_DMA(uint16_t *data, uint16_t count) { transmitDMA(DMA_MINC_ENABLE, data, count); } + static void writeMultiple_DMA(uint16_t color, uint16_t count) { static uint16_t data; data = color; transmitDMA(DMA_MINC_DISABLE, &data, count); } + + static void writeSequence(uint16_t *data, uint16_t count) { transmit(DMA_MINC_ENABLE, data, count); } + static void writeMultiple(uint16_t color, uint32_t count) { + while (count > 0) { + transmit(DMA_MINC_DISABLE, &color, count > DMA_MAX_WORDS ? DMA_MAX_WORDS : count); + count = count > DMA_MAX_WORDS ? count - DMA_MAX_WORDS : 0; } } }; diff --git a/Marlin/src/HAL/STM32F1/tft/xpt2046.cpp b/Marlin/src/HAL/STM32F1/tft/xpt2046.cpp index ac9ad072aa..475290de45 100644 --- a/Marlin/src/HAL/STM32F1/tft/xpt2046.cpp +++ b/Marlin/src/HAL/STM32F1/tft/xpt2046.cpp @@ -20,6 +20,8 @@ * */ +#ifdef __STM32F1__ + #include "../../../inc/MarlinConfig.h" #if HAS_TFT_XPT2046 || HAS_RES_TOUCH_BUTTONS @@ -57,7 +59,7 @@ uint16_t delta(uint16_t a, uint16_t b) { return a > b ? a - b : b - a; } } #endif // TOUCH_BUTTONS_HW_SPI -void XPT2046::Init() { +void XPT2046::init() { SET_INPUT(TOUCH_MISO_PIN); SET_OUTPUT(TOUCH_MOSI_PIN); SET_OUTPUT(TOUCH_SCK_PIN); @@ -84,9 +86,8 @@ bool XPT2046::isTouched() { ); } -bool XPT2046::getRawPoint(int16_t *x, int16_t *y) { - if (isBusy()) return false; - if (!isTouched()) return false; +bool XPT2046::getRawPoint(int16_t * const x, int16_t * const y) { + if (isBusy() || !isTouched()) return false; *x = getRawData(XPT2046_X); *y = getRawData(XPT2046_Y); return isTouched(); @@ -95,7 +96,7 @@ bool XPT2046::getRawPoint(int16_t *x, int16_t *y) { uint16_t XPT2046::getRawData(const XPTCoordinate coordinate) { uint16_t data[3]; - DataTransferBegin(); + dataTransferBegin(); TERN_(TOUCH_BUTTONS_HW_SPI, SPIx.begin()); for (uint16_t i = 0; i < 3 ; i++) { @@ -104,7 +105,7 @@ uint16_t XPT2046::getRawData(const XPTCoordinate coordinate) { } TERN_(TOUCH_BUTTONS_HW_SPI, SPIx.end()); - DataTransferEnd(); + dataTransferEnd(); uint16_t delta01 = delta(data[0], data[1]), delta02 = delta(data[0], data[2]), @@ -117,17 +118,17 @@ uint16_t XPT2046::getRawData(const XPTCoordinate coordinate) { } uint16_t XPT2046::IO(uint16_t data) { - return TERN(TOUCH_BUTTONS_HW_SPI, HardwareIO, SoftwareIO)(data); + return TERN(TOUCH_BUTTONS_HW_SPI, hardwareIO, softwareIO)(data); } #if ENABLED(TOUCH_BUTTONS_HW_SPI) - uint16_t XPT2046::HardwareIO(uint16_t data) { + uint16_t XPT2046::hardwareIO(uint16_t data) { uint16_t result = SPIx.transfer(data); return result; } #endif -uint16_t XPT2046::SoftwareIO(uint16_t data) { +uint16_t XPT2046::softwareIO(uint16_t data) { uint16_t result = 0; for (uint8_t j = 0x80; j; j >>= 1) { @@ -141,4 +142,6 @@ uint16_t XPT2046::SoftwareIO(uint16_t data) { return result; } -#endif // HAS_TFT_XPT2046 +#endif // HAS_TFT_XPT2046 || HAS_RES_TOUCH_BUTTONS + +#endif // __STM32F1__ diff --git a/Marlin/src/HAL/STM32F1/tft/xpt2046.h b/Marlin/src/HAL/STM32F1/tft/xpt2046.h index 7c456cf00e..9a19e3c98d 100644 --- a/Marlin/src/HAL/STM32F1/tft/xpt2046.h +++ b/Marlin/src/HAL/STM32F1/tft/xpt2046.h @@ -65,12 +65,12 @@ private: static uint16_t getRawData(const XPTCoordinate coordinate); static bool isTouched(); - static void DataTransferBegin() { WRITE(TOUCH_CS_PIN, LOW); }; - static void DataTransferEnd() { WRITE(TOUCH_CS_PIN, HIGH); }; + static void dataTransferBegin() { WRITE(TOUCH_CS_PIN, LOW); }; + static void dataTransferEnd() { WRITE(TOUCH_CS_PIN, HIGH); }; #if ENABLED(TOUCH_BUTTONS_HW_SPI) - static uint16_t HardwareIO(uint16_t data); + static uint16_t hardwareIO(uint16_t data); #endif - static uint16_t SoftwareIO(uint16_t data); + static uint16_t softwareIO(uint16_t data); static uint16_t IO(uint16_t data = 0); public: @@ -78,6 +78,6 @@ public: static SPIClass SPIx; #endif - static void Init(); - static bool getRawPoint(int16_t *x, int16_t *y); + static void init(); + static bool getRawPoint(int16_t * const x, int16_t * const y); }; diff --git a/Marlin/src/HAL/STM32F1/timers.cpp b/Marlin/src/HAL/STM32F1/timers.cpp index 112c730b9a..12477a4583 100644 --- a/Marlin/src/HAL/STM32F1/timers.cpp +++ b/Marlin/src/HAL/STM32F1/timers.cpp @@ -1,9 +1,9 @@ /** * Marlin 3D Printer Firmware - * * Copyright (c) 2020 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] - * Copyright (c) 2016 Bob Cousins bobcousins42@googlemail.com - * Copyright (c) 2015-2016 Nico Tonnhofer wurstnase.reprap@gmail.com + * + * 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 diff --git a/Marlin/src/HAL/STM32F1/timers.h b/Marlin/src/HAL/STM32F1/timers.h index 0cd807fc84..89a609c2c3 100644 --- a/Marlin/src/HAL/STM32F1/timers.h +++ b/Marlin/src/HAL/STM32F1/timers.h @@ -1,9 +1,9 @@ /** * Marlin 3D Printer Firmware - * * Copyright (c) 2020 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] - * Copyright (c) 2016 Bob Cousins bobcousins42@googlemail.com - * Copyright (c) 2017 Victor Perez + * + * 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 @@ -80,8 +80,8 @@ typedef uint16_t hal_timer_t; //#define MF_TIMER_TEMP 4 // 2->4, Timer 2 for Stepper Current PWM #endif -#if MB(BTT_SKR_MINI_E3_V1_0, BTT_SKR_E3_DIP, BTT_SKR_MINI_E3_V1_2, MKS_ROBIN_LITE, MKS_ROBIN_E3D, MKS_ROBIN_E3) - // SKR Mini E3 boards use PA8 as FAN_PIN, so TIMER 1 is used for Fan PWM. +#if MB(BTT_SKR_MINI_E3_V1_0, BTT_SKR_E3_DIP, BTT_SKR_MINI_E3_V1_2, MKS_ROBIN_LITE, MKS_ROBIN_E3D, MKS_ROBIN_E3, VOXELAB_AQUILA) + // SKR Mini E3 boards use PA8 as FAN0_PIN, so TIMER 1 is used for Fan PWM. #ifdef STM32_HIGH_DENSITY #define MF_TIMER_SERVO0 8 // tone.cpp uses Timer 4 #else diff --git a/Marlin/src/HAL/STM32F1/u8g/LCD_defines.h b/Marlin/src/HAL/STM32F1/u8g/LCD_defines.h new file mode 100644 index 0000000000..4bd461cb39 --- /dev/null +++ b/Marlin/src/HAL/STM32F1/u8g/LCD_defines.h @@ -0,0 +1,34 @@ +/** + * Marlin 3D Printer Firmware + * Copyright (c) 2023 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] + * + * Based on Sprinter and grbl. + * Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (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 + +/** + * STM32F1 (Maple) LCD-specific defines + */ + +uint8_t u8g_com_HAL_STM32F1_sw_spi_fn(u8g_t *u8g, uint8_t msg, uint8_t arg_val, void *arg_ptr); +uint8_t u8g_com_stm32duino_hw_spi_fn(u8g_t *u8g, uint8_t msg, uint8_t arg_val, void *arg_ptr); // See U8glib-HAL + +#define U8G_COM_HAL_SW_SPI_FN u8g_com_HAL_STM32F1_sw_spi_fn +#define U8G_COM_HAL_HW_SPI_FN u8g_com_stm32duino_hw_spi_fn // See U8glib-HAL +#define U8G_COM_ST7920_HAL_SW_SPI u8g_com_std_sw_spi_fn // See U8glib-HAL +#define U8G_COM_ST7920_HAL_HW_SPI u8g_com_stm32duino_hw_spi_fn // See U8glib-HAL diff --git a/Marlin/src/HAL/TEENSY31_32/HAL.h b/Marlin/src/HAL/TEENSY31_32/HAL.h index a7aa9f0da2..16594c16a8 100644 --- a/Marlin/src/HAL/TEENSY31_32/HAL.h +++ b/Marlin/src/HAL/TEENSY31_32/HAL.h @@ -1,9 +1,9 @@ /** * Marlin 3D Printer Firmware - * * Copyright (c) 2020 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] - * Copyright (c) 2016 Bob Cousins bobcousins42@googlemail.com - * Copyright (c) 2015-2016 Nico Tonnhofer wurstnase.reprap@gmail.com + * + * 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 @@ -101,7 +101,7 @@ uint32_t __get_PRIMASK(void); // CMSIS #define analogInputToDigitalPin(p) ((p < 12U) ? (p) + 54U : -1) #endif -#define HAL_ADC_VREF 3.3 +#define HAL_ADC_VREF_MV 3300 #define HAL_ADC_RESOLUTION 10 // diff --git a/Marlin/src/HAL/TEENSY31_32/endstop_interrupts.h b/Marlin/src/HAL/TEENSY31_32/endstop_interrupts.h index c1bbcb121b..954eb625a5 100644 --- a/Marlin/src/HAL/TEENSY31_32/endstop_interrupts.h +++ b/Marlin/src/HAL/TEENSY31_32/endstop_interrupts.h @@ -47,33 +47,33 @@ void endstop_ISR() { endstops.update(); } void setup_endstop_interrupts() { #define _ATTACH(P) attachInterrupt(digitalPinToInterrupt(P), endstop_ISR, CHANGE) - TERN_(HAS_X_MAX, _ATTACH(X_MAX_PIN)); - TERN_(HAS_X_MIN, _ATTACH(X_MIN_PIN)); - TERN_(HAS_Y_MAX, _ATTACH(Y_MAX_PIN)); - TERN_(HAS_Y_MIN, _ATTACH(Y_MIN_PIN)); - TERN_(HAS_Z_MAX, _ATTACH(Z_MAX_PIN)); - TERN_(HAS_Z_MIN, _ATTACH(Z_MIN_PIN)); - TERN_(HAS_X2_MAX, _ATTACH(X2_MAX_PIN)); - TERN_(HAS_X2_MIN, _ATTACH(X2_MIN_PIN)); - TERN_(HAS_Y2_MAX, _ATTACH(Y2_MAX_PIN)); - TERN_(HAS_Y2_MIN, _ATTACH(Y2_MIN_PIN)); - TERN_(HAS_Z2_MAX, _ATTACH(Z2_MAX_PIN)); - TERN_(HAS_Z2_MIN, _ATTACH(Z2_MIN_PIN)); - TERN_(HAS_Z3_MAX, _ATTACH(Z3_MAX_PIN)); - TERN_(HAS_Z3_MIN, _ATTACH(Z3_MIN_PIN)); - TERN_(HAS_Z4_MAX, _ATTACH(Z4_MAX_PIN)); - TERN_(HAS_Z4_MIN, _ATTACH(Z4_MIN_PIN)); - TERN_(HAS_Z_MIN_PROBE_PIN, _ATTACH(Z_MIN_PROBE_PIN)); - TERN_(HAS_I_MAX, _ATTACH(I_MAX_PIN)); - TERN_(HAS_I_MIN, _ATTACH(I_MIN_PIN)); - TERN_(HAS_J_MAX, _ATTACH(J_MAX_PIN)); - TERN_(HAS_J_MIN, _ATTACH(J_MIN_PIN)); - TERN_(HAS_K_MAX, _ATTACH(K_MAX_PIN)); - TERN_(HAS_K_MIN, _ATTACH(K_MIN_PIN)); - TERN_(HAS_U_MAX, _ATTACH(U_MAX_PIN)); - TERN_(HAS_U_MIN, _ATTACH(U_MIN_PIN)); - TERN_(HAS_V_MAX, _ATTACH(V_MAX_PIN)); - TERN_(HAS_V_MIN, _ATTACH(V_MIN_PIN)); - TERN_(HAS_W_MAX, _ATTACH(W_MAX_PIN)); - TERN_(HAS_W_MIN, _ATTACH(W_MIN_PIN)); + TERN_(USE_X_MAX, _ATTACH(X_MAX_PIN)); + TERN_(USE_X_MIN, _ATTACH(X_MIN_PIN)); + TERN_(USE_Y_MAX, _ATTACH(Y_MAX_PIN)); + TERN_(USE_Y_MIN, _ATTACH(Y_MIN_PIN)); + TERN_(USE_Z_MAX, _ATTACH(Z_MAX_PIN)); + TERN_(USE_Z_MIN, _ATTACH(Z_MIN_PIN)); + TERN_(USE_X2_MAX, _ATTACH(X2_MAX_PIN)); + TERN_(USE_X2_MIN, _ATTACH(X2_MIN_PIN)); + TERN_(USE_Y2_MAX, _ATTACH(Y2_MAX_PIN)); + TERN_(USE_Y2_MIN, _ATTACH(Y2_MIN_PIN)); + TERN_(USE_Z2_MAX, _ATTACH(Z2_MAX_PIN)); + TERN_(USE_Z2_MIN, _ATTACH(Z2_MIN_PIN)); + TERN_(USE_Z3_MAX, _ATTACH(Z3_MAX_PIN)); + TERN_(USE_Z3_MIN, _ATTACH(Z3_MIN_PIN)); + TERN_(USE_Z4_MAX, _ATTACH(Z4_MAX_PIN)); + TERN_(USE_Z4_MIN, _ATTACH(Z4_MIN_PIN)); + TERN_(USE_Z_MIN_PROBE, _ATTACH(Z_MIN_PROBE_PIN)); + TERN_(USE_I_MAX, _ATTACH(I_MAX_PIN)); + TERN_(USE_I_MIN, _ATTACH(I_MIN_PIN)); + TERN_(USE_J_MAX, _ATTACH(J_MAX_PIN)); + TERN_(USE_J_MIN, _ATTACH(J_MIN_PIN)); + TERN_(USE_K_MAX, _ATTACH(K_MAX_PIN)); + TERN_(USE_K_MIN, _ATTACH(K_MIN_PIN)); + TERN_(USE_U_MAX, _ATTACH(U_MAX_PIN)); + TERN_(USE_U_MIN, _ATTACH(U_MIN_PIN)); + TERN_(USE_V_MAX, _ATTACH(V_MAX_PIN)); + TERN_(USE_V_MIN, _ATTACH(V_MIN_PIN)); + TERN_(USE_W_MAX, _ATTACH(W_MAX_PIN)); + TERN_(USE_W_MIN, _ATTACH(W_MIN_PIN)); } diff --git a/Marlin/src/HAL/TEENSY31_32/inc/Conditionals_LCD.h b/Marlin/src/HAL/TEENSY31_32/inc/Conditionals_LCD.h index 54ec166643..5f1c4b1601 100644 --- a/Marlin/src/HAL/TEENSY31_32/inc/Conditionals_LCD.h +++ b/Marlin/src/HAL/TEENSY31_32/inc/Conditionals_LCD.h @@ -20,7 +20,3 @@ * */ #pragma once - -#if HAS_SPI_TFT || HAS_FSMC_TFT - #error "Sorry! TFT displays are not available for HAL/TEENSY31_32." -#endif diff --git a/Marlin/src/HAL/TEENSY31_32/inc/SanityCheck.h b/Marlin/src/HAL/TEENSY31_32/inc/SanityCheck.h index dbce187673..c5b25f2cb5 100644 --- a/Marlin/src/HAL/TEENSY31_32/inc/SanityCheck.h +++ b/Marlin/src/HAL/TEENSY31_32/inc/SanityCheck.h @@ -25,22 +25,26 @@ * Test TEENSY35_36 specific configuration values for errors at compile-time. */ +#if HAS_SPI_TFT || HAS_FSMC_TFT + #error "Sorry! TFT displays are not available for Teensy 3.1/3.2." +#endif + #if ENABLED(EMERGENCY_PARSER) #error "EMERGENCY_PARSER is not yet implemented for Teensy 3.1/3.2. Disable EMERGENCY_PARSER to continue." #endif #if ENABLED(FAST_PWM_FAN) || SPINDLE_LASER_FREQUENCY - #error "Features requiring Hardware PWM (FAST_PWM_FAN, SPINDLE_LASER_FREQUENCY) are not yet supported on Teensy 3.1/3.2." + #error "Features requiring Hardware PWM (FAST_PWM_FAN, SPINDLE_LASER_FREQUENCY) are not yet supported for Teensy 3.1/3.2." #endif #if HAS_TMC_SW_SERIAL - #error "TMC220x Software Serial is not supported on Teensy 3.1/3.2." + #error "TMC220x Software Serial is not supported for Teensy 3.1/3.2." #endif #if ENABLED(POSTMORTEM_DEBUGGING) - #error "POSTMORTEM_DEBUGGING is not yet supported on Teensy 3.1/3.2." + #error "POSTMORTEM_DEBUGGING is not yet supported for Teensy 3.1/3.2." #endif #if USING_PULLDOWNS - #error "PULLDOWN pin mode is not available on Teensy 3.1/3.2 boards." + #error "PULLDOWN pin mode is not available for Teensy 3.1/3.2." #endif diff --git a/Marlin/src/HAL/TEENSY31_32/u8g/LCD_defines.h b/Marlin/src/HAL/TEENSY31_32/u8g/LCD_defines.h new file mode 100644 index 0000000000..a13e7e837f --- /dev/null +++ b/Marlin/src/HAL/TEENSY31_32/u8g/LCD_defines.h @@ -0,0 +1,26 @@ +/** + * Marlin 3D Printer Firmware + * Copyright (c) 2023 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] + * + * Based on Sprinter and grbl. + * Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (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 + +/** + * Teensy 3.1/3.2 LCD-specific defines + */ diff --git a/Marlin/src/HAL/TEENSY35_36/HAL.h b/Marlin/src/HAL/TEENSY35_36/HAL.h index 2a192e4718..6921334003 100644 --- a/Marlin/src/HAL/TEENSY35_36/HAL.h +++ b/Marlin/src/HAL/TEENSY35_36/HAL.h @@ -1,9 +1,9 @@ /** * Marlin 3D Printer Firmware - * * Copyright (c) 2020 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] - * Copyright (c) 2016 Bob Cousins bobcousins42@googlemail.com - * Copyright (c) 2015-2016 Nico Tonnhofer wurstnase.reprap@gmail.com + * + * 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 @@ -106,7 +106,7 @@ typedef int8_t pin_t; #define analogInputToDigitalPin(p) ((p < 12U) ? (p) + 54U : -1) #endif -#define HAL_ADC_VREF 3.3 +#define HAL_ADC_VREF_MV 3300 #define HAL_ADC_RESOLUTION 10 // diff --git a/Marlin/src/HAL/TEENSY35_36/eeprom.cpp b/Marlin/src/HAL/TEENSY35_36/eeprom.cpp index b80e93b536..a2afa45343 100644 --- a/Marlin/src/HAL/TEENSY35_36/eeprom.cpp +++ b/Marlin/src/HAL/TEENSY35_36/eeprom.cpp @@ -1,10 +1,9 @@ /** * Marlin 3D Printer Firmware - * * Copyright (c) 2020 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] - * Copyright (c) 2016 Bob Cousins bobcousins42@googlemail.com - * Copyright (c) 2015-2016 Nico Tonnhofer wurstnase.reprap@gmail.com - * Copyright (c) 2016 Victor Perez victor_pv@hotmail.com + * + * 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 diff --git a/Marlin/src/HAL/TEENSY35_36/endstop_interrupts.h b/Marlin/src/HAL/TEENSY35_36/endstop_interrupts.h index 48d3bbbfa1..bc8e177fb7 100644 --- a/Marlin/src/HAL/TEENSY35_36/endstop_interrupts.h +++ b/Marlin/src/HAL/TEENSY35_36/endstop_interrupts.h @@ -46,33 +46,33 @@ void endstop_ISR() { endstops.update(); } */ void setup_endstop_interrupts() { #define _ATTACH(P) attachInterrupt(digitalPinToInterrupt(P), endstop_ISR, CHANGE) - TERN_(HAS_X_MAX, _ATTACH(X_MAX_PIN)); - TERN_(HAS_X_MIN, _ATTACH(X_MIN_PIN)); - TERN_(HAS_Y_MAX, _ATTACH(Y_MAX_PIN)); - TERN_(HAS_Y_MIN, _ATTACH(Y_MIN_PIN)); - TERN_(HAS_Z_MAX, _ATTACH(Z_MAX_PIN)); - TERN_(HAS_Z_MIN, _ATTACH(Z_MIN_PIN)); - TERN_(HAS_X2_MAX, _ATTACH(X2_MAX_PIN)); - TERN_(HAS_X2_MIN, _ATTACH(X2_MIN_PIN)); - TERN_(HAS_Y2_MAX, _ATTACH(Y2_MAX_PIN)); - TERN_(HAS_Y2_MIN, _ATTACH(Y2_MIN_PIN)); - TERN_(HAS_Z2_MAX, _ATTACH(Z2_MAX_PIN)); - TERN_(HAS_Z2_MIN, _ATTACH(Z2_MIN_PIN)); - TERN_(HAS_Z3_MAX, _ATTACH(Z3_MAX_PIN)); - TERN_(HAS_Z3_MIN, _ATTACH(Z3_MIN_PIN)); - TERN_(HAS_Z4_MAX, _ATTACH(Z4_MAX_PIN)); - TERN_(HAS_Z4_MIN, _ATTACH(Z4_MIN_PIN)); - TERN_(HAS_Z_MIN_PROBE_PIN, _ATTACH(Z_MIN_PROBE_PIN)); - TERN_(HAS_I_MAX, _ATTACH(I_MAX_PIN)); - TERN_(HAS_I_MIN, _ATTACH(I_MIN_PIN)); - TERN_(HAS_J_MAX, _ATTACH(J_MAX_PIN)); - TERN_(HAS_J_MIN, _ATTACH(J_MIN_PIN)); - TERN_(HAS_K_MAX, _ATTACH(K_MAX_PIN)); - TERN_(HAS_K_MIN, _ATTACH(K_MIN_PIN)); - TERN_(HAS_U_MAX, _ATTACH(U_MAX_PIN)); - TERN_(HAS_U_MIN, _ATTACH(U_MIN_PIN)); - TERN_(HAS_V_MAX, _ATTACH(V_MAX_PIN)); - TERN_(HAS_V_MIN, _ATTACH(V_MIN_PIN)); - TERN_(HAS_W_MAX, _ATTACH(W_MAX_PIN)); - TERN_(HAS_W_MIN, _ATTACH(W_MIN_PIN)); + TERN_(USE_X_MAX, _ATTACH(X_MAX_PIN)); + TERN_(USE_X_MIN, _ATTACH(X_MIN_PIN)); + TERN_(USE_Y_MAX, _ATTACH(Y_MAX_PIN)); + TERN_(USE_Y_MIN, _ATTACH(Y_MIN_PIN)); + TERN_(USE_Z_MAX, _ATTACH(Z_MAX_PIN)); + TERN_(USE_Z_MIN, _ATTACH(Z_MIN_PIN)); + TERN_(USE_X2_MAX, _ATTACH(X2_MAX_PIN)); + TERN_(USE_X2_MIN, _ATTACH(X2_MIN_PIN)); + TERN_(USE_Y2_MAX, _ATTACH(Y2_MAX_PIN)); + TERN_(USE_Y2_MIN, _ATTACH(Y2_MIN_PIN)); + TERN_(USE_Z2_MAX, _ATTACH(Z2_MAX_PIN)); + TERN_(USE_Z2_MIN, _ATTACH(Z2_MIN_PIN)); + TERN_(USE_Z3_MAX, _ATTACH(Z3_MAX_PIN)); + TERN_(USE_Z3_MIN, _ATTACH(Z3_MIN_PIN)); + TERN_(USE_Z4_MAX, _ATTACH(Z4_MAX_PIN)); + TERN_(USE_Z4_MIN, _ATTACH(Z4_MIN_PIN)); + TERN_(USE_Z_MIN_PROBE, _ATTACH(Z_MIN_PROBE_PIN)); + TERN_(USE_I_MAX, _ATTACH(I_MAX_PIN)); + TERN_(USE_I_MIN, _ATTACH(I_MIN_PIN)); + TERN_(USE_J_MAX, _ATTACH(J_MAX_PIN)); + TERN_(USE_J_MIN, _ATTACH(J_MIN_PIN)); + TERN_(USE_K_MAX, _ATTACH(K_MAX_PIN)); + TERN_(USE_K_MIN, _ATTACH(K_MIN_PIN)); + TERN_(USE_U_MAX, _ATTACH(U_MAX_PIN)); + TERN_(USE_U_MIN, _ATTACH(U_MIN_PIN)); + TERN_(USE_V_MAX, _ATTACH(V_MAX_PIN)); + TERN_(USE_V_MIN, _ATTACH(V_MIN_PIN)); + TERN_(USE_W_MAX, _ATTACH(W_MAX_PIN)); + TERN_(USE_W_MIN, _ATTACH(W_MIN_PIN)); } diff --git a/Marlin/src/HAL/TEENSY35_36/inc/Conditionals_LCD.h b/Marlin/src/HAL/TEENSY35_36/inc/Conditionals_LCD.h index 632ee533ac..5f1c4b1601 100644 --- a/Marlin/src/HAL/TEENSY35_36/inc/Conditionals_LCD.h +++ b/Marlin/src/HAL/TEENSY35_36/inc/Conditionals_LCD.h @@ -20,7 +20,3 @@ * */ #pragma once - -#if HAS_SPI_TFT || HAS_FSMC_TFT - #error "Sorry! TFT displays are not available for HAL/TEENSY35_36." -#endif diff --git a/Marlin/src/HAL/TEENSY35_36/inc/SanityCheck.h b/Marlin/src/HAL/TEENSY35_36/inc/SanityCheck.h index 3308707371..843905a851 100644 --- a/Marlin/src/HAL/TEENSY35_36/inc/SanityCheck.h +++ b/Marlin/src/HAL/TEENSY35_36/inc/SanityCheck.h @@ -25,22 +25,26 @@ * Test TEENSY35_36 specific configuration values for errors at compile-time. */ +#if HAS_SPI_TFT || HAS_FSMC_TFT + #error "Sorry! TFT displays are not available for Teensy 3.5/3.6." +#endif + #if ENABLED(EMERGENCY_PARSER) #error "EMERGENCY_PARSER is not yet implemented for Teensy 3.5/3.6. Disable EMERGENCY_PARSER to continue." #endif #if ENABLED(FAST_PWM_FAN) || SPINDLE_LASER_FREQUENCY - #error "Features requiring Hardware PWM (FAST_PWM_FAN, SPINDLE_LASER_FREQUENCY) are not yet supported on Teensy 3.5/3.6." + #error "Features requiring Hardware PWM (FAST_PWM_FAN, SPINDLE_LASER_FREQUENCY) are not yet supported for Teensy 3.5/3.6." #endif #if HAS_TMC_SW_SERIAL - #error "TMC220x Software Serial is not supported on Teensy 3.5/3.6." + #error "TMC220x Software Serial is not supported for Teensy 3.5/3.6." #endif #if ENABLED(POSTMORTEM_DEBUGGING) - #error "POSTMORTEM_DEBUGGING is not yet supported on Teensy 3.5/3.6." + #error "POSTMORTEM_DEBUGGING is not yet supported for Teensy 3.5/3.6." #endif #if USING_PULLDOWNS - #error "PULLDOWN pin mode is not available on Teensy 3.5/3.6 boards." + #error "PULLDOWN pin mode is not available for Teensy 3.5/3.6." #endif diff --git a/Marlin/src/HAL/TEENSY35_36/pinsDebug.h b/Marlin/src/HAL/TEENSY35_36/pinsDebug.h index 7a2e1d6e59..8526febf10 100644 --- a/Marlin/src/HAL/TEENSY35_36/pinsDebug.h +++ b/Marlin/src/HAL/TEENSY35_36/pinsDebug.h @@ -55,12 +55,12 @@ #define IS_ANALOG(P) ((P) >= analogInputToDigitalPin(0) && (P) <= analogInputToDigitalPin(9)) || ((P) >= analogInputToDigitalPin(12) && (P) <= analogInputToDigitalPin(20)) -void HAL_print_analog_pin(char buffer[], int8_t pin) { +void print_analog_pin(char buffer[], int8_t pin) { if (pin <= 23) sprintf_P(buffer, PSTR("(A%2d) "), int(pin - 14)); else if (pin <= 39) sprintf_P(buffer, PSTR("(A%2d) "), int(pin - 19)); } -void HAL_analog_pin_state(char buffer[], int8_t pin) { +void analog_pin_state(char buffer[], int8_t pin) { if (pin <= 23) sprintf_P(buffer, PSTR("Analog in =% 5d"), analogRead(pin - 14)); else if (pin <= 39) sprintf_P(buffer, PSTR("Analog in =% 5d"), analogRead(pin - 19)); } @@ -77,7 +77,7 @@ void HAL_analog_pin_state(char buffer[], int8_t pin) { * Print a pin's PWM status. * Return true if it's currently a PWM pin. */ -bool HAL_pwm_status(int8_t pin) { +bool pwm_status(int8_t pin) { char buffer[20]; // for the sprintf statements switch (pin) { FTM_CASE(0,0); @@ -108,4 +108,4 @@ bool HAL_pwm_status(int8_t pin) { SERIAL_ECHOPGM(" "); } -static void HAL_pwm_details(uint8_t pin) { /* TODO */ } +void pwm_details(uint8_t pin) { /* TODO */ } diff --git a/Marlin/src/HAL/TEENSY35_36/timers.h b/Marlin/src/HAL/TEENSY35_36/timers.h index 8af79d7392..3536b62265 100644 --- a/Marlin/src/HAL/TEENSY35_36/timers.h +++ b/Marlin/src/HAL/TEENSY35_36/timers.h @@ -1,8 +1,9 @@ /** * Marlin 3D Printer Firmware * Copyright (c) 2020 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] - * Copyright (c) 2016 Bob Cousins bobcousins42@googlemail.com - * Copyright (c) 2015-2016 Nico Tonnhofer wurstnase.reprap@gmail.com + * + * 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 diff --git a/Marlin/src/HAL/TEENSY35_36/u8g/LCD_defines.h b/Marlin/src/HAL/TEENSY35_36/u8g/LCD_defines.h new file mode 100644 index 0000000000..511085781c --- /dev/null +++ b/Marlin/src/HAL/TEENSY35_36/u8g/LCD_defines.h @@ -0,0 +1,26 @@ +/** + * Marlin 3D Printer Firmware + * Copyright (c) 2023 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] + * + * Based on Sprinter and grbl. + * Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (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 + +/** + * Teensy 3.5/3.6 LCD-specific defines + */ diff --git a/Marlin/src/HAL/TEENSY40_41/HAL.cpp b/Marlin/src/HAL/TEENSY40_41/HAL.cpp index 1d02ab8575..4dd5c3678d 100644 --- a/Marlin/src/HAL/TEENSY40_41/HAL.cpp +++ b/Marlin/src/HAL/TEENSY40_41/HAL.cpp @@ -39,9 +39,19 @@ #define _IMPLEMENT_SERIAL(X) DefaultSerial##X MSerial##X(false, Serial##X) #define IMPLEMENT_SERIAL(X) _IMPLEMENT_SERIAL(X) -#if WITHIN(SERIAL_PORT, 0, 3) +#if WITHIN(SERIAL_PORT, 0, 8) IMPLEMENT_SERIAL(SERIAL_PORT); #endif +#ifdef SERIAL_PORT_2 + #if WITHIN(SERIAL_PORT_2, 0, 8) + IMPLEMENT_SERIAL(SERIAL_PORT_2); + #endif +#endif +#ifdef SERIAL_PORT_3 + #if WITHIN(SERIAL_PORT_3, 0, 8) + IMPLEMENT_SERIAL(SERIAL_PORT_3); + #endif +#endif USBSerialType USBSerial(false, SerialUSB); // ------------------------ diff --git a/Marlin/src/HAL/TEENSY40_41/HAL.h b/Marlin/src/HAL/TEENSY40_41/HAL.h index c54a2e8a0b..fa5971a681 100644 --- a/Marlin/src/HAL/TEENSY40_41/HAL.h +++ b/Marlin/src/HAL/TEENSY40_41/HAL.h @@ -1,9 +1,9 @@ /** * Marlin 3D Printer Firmware - * * Copyright (c) 2020 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] - * Copyright (c) 2016 Bob Cousins bobcousins42@googlemail.com - * Copyright (c) 2015-2016 Nico Tonnhofer wurstnase.reprap@gmail.com + * + * 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 @@ -80,7 +80,7 @@ extern USBSerialType USBSerial; #define MSERIAL(X) _MSERIAL(X) #if SERIAL_PORT == -1 - #define MYSERIAL1 SerialUSB + #define MYSERIAL1 USBSerial #elif WITHIN(SERIAL_PORT, 0, 8) DECLARE_SERIAL(SERIAL_PORT); #define MYSERIAL1 MSERIAL(SERIAL_PORT) @@ -90,16 +90,28 @@ extern USBSerialType USBSerial; #ifdef SERIAL_PORT_2 #if SERIAL_PORT_2 == -1 - #define MYSERIAL2 usbSerial + #define MYSERIAL2 USBSerial #elif SERIAL_PORT_2 == -2 #define MYSERIAL2 ethernet.telnetClient #elif WITHIN(SERIAL_PORT_2, 0, 8) + DECLARE_SERIAL(SERIAL_PORT_2); #define MYSERIAL2 MSERIAL(SERIAL_PORT_2) #else #error "SERIAL_PORT_2 must be from 0 to 8, or -1 for Native USB, or -2 for Ethernet." #endif #endif +#ifdef SERIAL_PORT_3 + #if SERIAL_PORT_3 == -1 + #define MYSERIAL3 USBSerial + #elif WITHIN(SERIAL_PORT_3, 0, 8) + DECLARE_SERIAL(SERIAL_PORT_3); + #define MYSERIAL3 MSERIAL(SERIAL_PORT_3) + #else + #error "SERIAL_PORT_3 must be from 0 to 8, or -1 for Native USB." + #endif +#endif + // ------------------------ // Types // ------------------------ @@ -124,7 +136,7 @@ typedef int8_t pin_t; #define analogInputToDigitalPin(p) ((p < 12U) ? (p) + 54U : -1) #endif -#define HAL_ADC_VREF 3.3 +#define HAL_ADC_VREF_MV 3300 #define HAL_ADC_RESOLUTION 10 #define HAL_ADC_FILTERED // turn off ADC oversampling diff --git a/Marlin/src/HAL/TEENSY40_41/eeprom.cpp b/Marlin/src/HAL/TEENSY40_41/eeprom.cpp index 3cd376edce..87f7dd3cfc 100644 --- a/Marlin/src/HAL/TEENSY40_41/eeprom.cpp +++ b/Marlin/src/HAL/TEENSY40_41/eeprom.cpp @@ -1,10 +1,9 @@ /** * Marlin 3D Printer Firmware - * * Copyright (c) 2020 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] - * Copyright (c) 2016 Bob Cousins bobcousins42@googlemail.com - * Copyright (c) 2015-2016 Nico Tonnhofer wurstnase.reprap@gmail.com - * Copyright (c) 2016 Victor Perez victor_pv@hotmail.com + * + * 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 diff --git a/Marlin/src/HAL/TEENSY40_41/endstop_interrupts.h b/Marlin/src/HAL/TEENSY40_41/endstop_interrupts.h index 4c3ddec9f1..722912c890 100644 --- a/Marlin/src/HAL/TEENSY40_41/endstop_interrupts.h +++ b/Marlin/src/HAL/TEENSY40_41/endstop_interrupts.h @@ -46,27 +46,33 @@ void endstop_ISR() { endstops.update(); } */ void setup_endstop_interrupts() { #define _ATTACH(P) attachInterrupt(digitalPinToInterrupt(P), endstop_ISR, CHANGE) - TERN_(HAS_X_MAX, _ATTACH(X_MAX_PIN)); - TERN_(HAS_X_MIN, _ATTACH(X_MIN_PIN)); - TERN_(HAS_Y_MAX, _ATTACH(Y_MAX_PIN)); - TERN_(HAS_Y_MIN, _ATTACH(Y_MIN_PIN)); - TERN_(HAS_Z_MAX, _ATTACH(Z_MAX_PIN)); - TERN_(HAS_Z_MIN, _ATTACH(Z_MIN_PIN)); - TERN_(HAS_X2_MAX, _ATTACH(X2_MAX_PIN)); - TERN_(HAS_X2_MIN, _ATTACH(X2_MIN_PIN)); - TERN_(HAS_Y2_MAX, _ATTACH(Y2_MAX_PIN)); - TERN_(HAS_Y2_MIN, _ATTACH(Y2_MIN_PIN)); - TERN_(HAS_Z2_MAX, _ATTACH(Z2_MAX_PIN)); - TERN_(HAS_Z2_MIN, _ATTACH(Z2_MIN_PIN)); - TERN_(HAS_Z3_MAX, _ATTACH(Z3_MAX_PIN)); - TERN_(HAS_Z3_MIN, _ATTACH(Z3_MIN_PIN)); - TERN_(HAS_Z4_MAX, _ATTACH(Z4_MAX_PIN)); - TERN_(HAS_Z4_MIN, _ATTACH(Z4_MIN_PIN)); - TERN_(HAS_Z_MIN_PROBE_PIN, _ATTACH(Z_MIN_PROBE_PIN)); - TERN_(HAS_I_MAX, _ATTACH(I_MAX_PIN)); - TERN_(HAS_I_MIN, _ATTACH(I_MIN_PIN)); - TERN_(HAS_J_MAX, _ATTACH(J_MAX_PIN)); - TERN_(HAS_J_MIN, _ATTACH(J_MIN_PIN)); - TERN_(HAS_K_MAX, _ATTACH(K_MAX_PIN)); - TERN_(HAS_K_MIN, _ATTACH(K_MIN_PIN)); + TERN_(USE_X_MAX, _ATTACH(X_MAX_PIN)); + TERN_(USE_X_MIN, _ATTACH(X_MIN_PIN)); + TERN_(USE_Y_MAX, _ATTACH(Y_MAX_PIN)); + TERN_(USE_Y_MIN, _ATTACH(Y_MIN_PIN)); + TERN_(USE_Z_MAX, _ATTACH(Z_MAX_PIN)); + TERN_(USE_Z_MIN, _ATTACH(Z_MIN_PIN)); + TERN_(USE_X2_MAX, _ATTACH(X2_MAX_PIN)); + TERN_(USE_X2_MIN, _ATTACH(X2_MIN_PIN)); + TERN_(USE_Y2_MAX, _ATTACH(Y2_MAX_PIN)); + TERN_(USE_Y2_MIN, _ATTACH(Y2_MIN_PIN)); + TERN_(USE_Z2_MAX, _ATTACH(Z2_MAX_PIN)); + TERN_(USE_Z2_MIN, _ATTACH(Z2_MIN_PIN)); + TERN_(USE_Z3_MAX, _ATTACH(Z3_MAX_PIN)); + TERN_(USE_Z3_MIN, _ATTACH(Z3_MIN_PIN)); + TERN_(USE_Z4_MAX, _ATTACH(Z4_MAX_PIN)); + TERN_(USE_Z4_MIN, _ATTACH(Z4_MIN_PIN)); + TERN_(USE_Z_MIN_PROBE, _ATTACH(Z_MIN_PROBE_PIN)); + TERN_(USE_I_MAX, _ATTACH(I_MAX_PIN)); + TERN_(USE_I_MIN, _ATTACH(I_MIN_PIN)); + TERN_(USE_J_MAX, _ATTACH(J_MAX_PIN)); + TERN_(USE_J_MIN, _ATTACH(J_MIN_PIN)); + TERN_(USE_K_MAX, _ATTACH(K_MAX_PIN)); + TERN_(USE_K_MIN, _ATTACH(K_MIN_PIN)); + TERN_(USE_U_MAX, _ATTACH(U_MAX_PIN)); + TERN_(USE_U_MIN, _ATTACH(U_MIN_PIN)); + TERN_(USE_V_MAX, _ATTACH(V_MAX_PIN)); + TERN_(USE_V_MIN, _ATTACH(V_MIN_PIN)); + TERN_(USE_W_MAX, _ATTACH(W_MAX_PIN)); + TERN_(USE_W_MIN, _ATTACH(W_MIN_PIN)); } diff --git a/Marlin/src/HAL/TEENSY40_41/fastio.h b/Marlin/src/HAL/TEENSY40_41/fastio.h index 52f991dfb8..179f044c9b 100644 --- a/Marlin/src/HAL/TEENSY40_41/fastio.h +++ b/Marlin/src/HAL/TEENSY40_41/fastio.h @@ -4,7 +4,6 @@ * * Based on Sprinter and grbl. * Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm - * Copyright (c) 2017 Victor Perez * * 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 diff --git a/Marlin/src/HAL/TEENSY40_41/inc/Conditionals_LCD.h b/Marlin/src/HAL/TEENSY40_41/inc/Conditionals_LCD.h index 6a8540927b..5f1c4b1601 100644 --- a/Marlin/src/HAL/TEENSY40_41/inc/Conditionals_LCD.h +++ b/Marlin/src/HAL/TEENSY40_41/inc/Conditionals_LCD.h @@ -20,7 +20,3 @@ * */ #pragma once - -#if HAS_SPI_TFT || HAS_FSMC_TFT - #error "Sorry! TFT displays are not available for HAL/TEENSY40_41." -#endif diff --git a/Marlin/src/HAL/TEENSY40_41/inc/SanityCheck.h b/Marlin/src/HAL/TEENSY40_41/inc/SanityCheck.h index 3d2668d749..731658b4a3 100644 --- a/Marlin/src/HAL/TEENSY40_41/inc/SanityCheck.h +++ b/Marlin/src/HAL/TEENSY40_41/inc/SanityCheck.h @@ -25,18 +25,22 @@ * Test TEENSY41 specific configuration values for errors at compile-time. */ +#if HAS_SPI_TFT || HAS_FSMC_TFT + #error "Sorry! TFT displays are not available for Teensy 4.0/4.1." +#endif + #if ENABLED(EMERGENCY_PARSER) #error "EMERGENCY_PARSER is not yet implemented for Teensy 4.0/4.1. Disable EMERGENCY_PARSER to continue." #endif #if ENABLED(FAST_PWM_FAN) || SPINDLE_LASER_FREQUENCY - #error "Features requiring Hardware PWM (FAST_PWM_FAN, SPINDLE_LASER_FREQUENCY) are not yet supported on Teensy 4.0/4.1." + #error "Features requiring Hardware PWM (FAST_PWM_FAN, SPINDLE_LASER_FREQUENCY) are not yet supported for Teensy 4.0/4.1." #endif #if HAS_TMC_SW_SERIAL - #error "TMC220x Software Serial is not supported on Teensy 4.0/4.1." + #error "TMC220x Software Serial is not supported for Teensy 4.0/4.1." #endif #if ENABLED(POSTMORTEM_DEBUGGING) - #error "POSTMORTEM_DEBUGGING is not yet supported on Teensy 4.0/4.1." + #error "POSTMORTEM_DEBUGGING is not yet supported for Teensy 4.0/4.1." #endif diff --git a/Marlin/src/HAL/TEENSY40_41/pinsDebug.h b/Marlin/src/HAL/TEENSY40_41/pinsDebug.h index fc90f671cf..54f3cb5885 100644 --- a/Marlin/src/HAL/TEENSY40_41/pinsDebug.h +++ b/Marlin/src/HAL/TEENSY40_41/pinsDebug.h @@ -30,7 +30,6 @@ #define NUMBER_PINS_TOTAL NUM_DIGITAL_PINS #define digitalRead_mod(p) extDigitalRead(p) // AVR digitalRead disabled PWM before it read the pin -#define PRINT_PORT(p) #define PRINT_ARRAY_NAME(x) do{ sprintf_P(buffer, PSTR("%-" STRINGIFY(MAX_NAME_LENGTH) "s"), pin_array[x].name); SERIAL_ECHO(buffer); }while(0) #define PRINT_PIN(p) do{ sprintf_P(buffer, PSTR("%02d"), p); SERIAL_ECHO(buffer); }while(0) #define PRINT_PIN_ANALOG(p) do{ sprintf_P(buffer, PSTR(" (A%2d) "), DIGITAL_PIN_TO_ANALOG_PIN(pin)); SERIAL_ECHO(buffer); }while(0) @@ -39,7 +38,6 @@ #define VALID_PIN(pin) (pin >= 0 && pin < int8_t(NUMBER_PINS_TOTAL)) #define DIGITAL_PIN_TO_ANALOG_PIN(p) int(p - analogInputToDigitalPin(0)) #define IS_ANALOG(P) ((P) >= analogInputToDigitalPin(0) && (P) <= analogInputToDigitalPin(13)) || ((P) >= analogInputToDigitalPin(14) && (P) <= analogInputToDigitalPin(17)) -#define pwm_status(pin) HAL_pwm_status(pin) #define GET_PINMODE(PIN) (VALID_PIN(pin) && IS_OUTPUT(pin)) #define MULTI_NAME_PAD 16 // space needed to be pretty if not first name assigned to a pin @@ -120,12 +118,12 @@ const struct pwm_pin_info_struct pwm_pin_info[] = { #endif }; -void HAL_print_analog_pin(char buffer[], int8_t pin) { +void print_analog_pin(char buffer[], const pin_t pin) { if (pin <= 23) sprintf_P(buffer, PSTR("(A%2d) "), int(pin - 14)); else if (pin <= 41) sprintf_P(buffer, PSTR("(A%2d) "), int(pin - 24)); } -void HAL_analog_pin_state(char buffer[], int8_t pin) { +void analog_pin_state(char buffer[], const pin_t pin) { if (pin <= 23) sprintf_P(buffer, PSTR("Analog in =% 5d"), analogRead(pin - 14)); else if (pin <= 41) sprintf_P(buffer, PSTR("Analog in =% 5d"), analogRead(pin - 24)); } @@ -136,14 +134,14 @@ void HAL_analog_pin_state(char buffer[], int8_t pin) { * Print a pin's PWM status. * Return true if it's currently a PWM pin. */ -bool HAL_pwm_status(int8_t pin) { +bool pwm_status(const pin_t pin) { char buffer[20]; // for the sprintf statements const struct pwm_pin_info_struct *info; - if (pin >= CORE_NUM_DIGITAL) return 0; - info = pwm_pin_info + pin; + if (pin >= CORE_NUM_DIGITAL) return false; - if (info->type == 0) return 0; + info = pwm_pin_info + pin; + if (info->type == 0) return false; /* TODO decode pwm value from timers */ // for now just indicate if output is set as pwm @@ -151,4 +149,6 @@ bool HAL_pwm_status(int8_t pin) { return (*(portConfigRegister(pin)) == info->muxval); } -static void pwm_details(uint8_t pin) { /* TODO */ } +void pwm_details(const pin_t) { /* TODO */ } + +void print_port(const pin_t) {} diff --git a/Marlin/src/HAL/TEENSY40_41/timers.h b/Marlin/src/HAL/TEENSY40_41/timers.h index 77fe0953d3..3c7cda0b4e 100644 --- a/Marlin/src/HAL/TEENSY40_41/timers.h +++ b/Marlin/src/HAL/TEENSY40_41/timers.h @@ -1,8 +1,9 @@ /** * Marlin 3D Printer Firmware * Copyright (c) 2020 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] - * Copyright (c) 2016 Bob Cousins bobcousins42@googlemail.com - * Copyright (c) 2015-2016 Nico Tonnhofer wurstnase.reprap@gmail.com + * + * 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 diff --git a/Marlin/src/HAL/TEENSY40_41/u8g/LCD_defines.h b/Marlin/src/HAL/TEENSY40_41/u8g/LCD_defines.h new file mode 100644 index 0000000000..349f8c0399 --- /dev/null +++ b/Marlin/src/HAL/TEENSY40_41/u8g/LCD_defines.h @@ -0,0 +1,26 @@ +/** + * Marlin 3D Printer Firmware + * Copyright (c) 2023 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] + * + * Based on Sprinter and grbl. + * Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (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 + +/** + * Teensy 4.0/4.1 LCD-specific defines + */ diff --git a/Marlin/src/HAL/platforms.h b/Marlin/src/HAL/platforms.h index 28fe28e109..9eaf7cea98 100644 --- a/Marlin/src/HAL/platforms.h +++ b/Marlin/src/HAL/platforms.h @@ -24,32 +24,36 @@ #define XSTR(V...) #V #ifdef __AVR__ - #define HAL_PATH(PATH, NAME) XSTR(PATH/AVR/NAME) + #define HAL_PATH(PATH, NAME) XSTR(PATH/HAL/AVR/NAME) #elif defined(ARDUINO_ARCH_SAM) - #define HAL_PATH(PATH, NAME) XSTR(PATH/DUE/NAME) + #define HAL_PATH(PATH, NAME) XSTR(PATH/HAL/DUE/NAME) #elif defined(__MK20DX256__) - #define HAL_PATH(PATH, NAME) XSTR(PATH/TEENSY31_32/NAME) + #define HAL_PATH(PATH, NAME) XSTR(PATH/HAL/TEENSY31_32/NAME) #elif defined(__MK64FX512__) || defined(__MK66FX1M0__) - #define HAL_PATH(PATH, NAME) XSTR(PATH/TEENSY35_36/NAME) + #define HAL_PATH(PATH, NAME) XSTR(PATH/HAL/TEENSY35_36/NAME) #elif defined(__IMXRT1062__) - #define HAL_PATH(PATH, NAME) XSTR(PATH/TEENSY40_41/NAME) + #define HAL_PATH(PATH, NAME) XSTR(PATH/HAL/TEENSY40_41/NAME) #elif defined(TARGET_LPC1768) - #define HAL_PATH(PATH, NAME) XSTR(PATH/LPC1768/NAME) + #define HAL_PATH(PATH, NAME) XSTR(PATH/HAL/LPC1768/NAME) +#elif defined(ARDUINO_ARCH_HC32) + #define HAL_PATH(PATH, NAME) XSTR(PATH/HAL/HC32/NAME) #elif defined(__STM32F1__) || defined(TARGET_STM32F1) - #define HAL_PATH(PATH, NAME) XSTR(PATH/STM32F1/NAME) + #define HAL_PATH(PATH, NAME) XSTR(PATH/HAL/STM32F1/NAME) #elif defined(ARDUINO_ARCH_STM32) #ifndef HAL_STM32 #define HAL_STM32 #endif - #define HAL_PATH(PATH, NAME) XSTR(PATH/STM32/NAME) + #define HAL_PATH(PATH, NAME) XSTR(PATH/HAL/STM32/NAME) #elif defined(ARDUINO_ARCH_ESP32) - #define HAL_PATH(PATH, NAME) XSTR(PATH/ESP32/NAME) + #define HAL_PATH(PATH, NAME) XSTR(PATH/HAL/ESP32/NAME) #elif defined(__PLAT_LINUX__) - #define HAL_PATH(PATH, NAME) XSTR(PATH/LINUX/NAME) + #define HAL_PATH(PATH, NAME) XSTR(PATH/HAL/LINUX/NAME) #elif defined(__PLAT_NATIVE_SIM__) - #define HAL_PATH(PATH, NAME) XSTR(PATH/NATIVE_SIM/NAME) + #define HAL_PATH(PATH, NAME) XSTR(PATH/HAL/NATIVE_SIM/NAME) #elif defined(__SAMD51__) - #define HAL_PATH(PATH, NAME) XSTR(PATH/SAMD51/NAME) + #define HAL_PATH(PATH, NAME) XSTR(PATH/HAL/SAMD51/NAME) +#elif defined(__SAMD21__) + #define HAL_PATH(PATH, NAME) XSTR(PATH/HAL/SAMD21/NAME) #else #error "Unsupported Platform!" #endif diff --git a/Marlin/src/HAL/shared/Delay.cpp b/Marlin/src/HAL/shared/Delay.cpp index c64376d25d..fd52eb2c6a 100644 --- a/Marlin/src/HAL/shared/Delay.cpp +++ b/Marlin/src/HAL/shared/Delay.cpp @@ -109,13 +109,7 @@ #if ENABLED(MARLIN_DEV_MODE) void dump_delay_accuracy_check() { auto report_call_time = [](FSTR_P const name, FSTR_P const unit, const uint32_t cycles, const uint32_t total, const bool do_flush=true) { - SERIAL_ECHOPGM("Calling "); - SERIAL_ECHOF(name); - SERIAL_ECHOLNPGM(" for ", cycles); - SERIAL_ECHOF(unit); - SERIAL_ECHOLNPGM(" took: ", total); - SERIAL_CHAR(' '); - SERIAL_ECHOF(unit); + SERIAL_ECHOLN(F("Calling "), name, F(" for "), cycles, C(' '), unit, F(" took: "), total, C(' '), unit); if (do_flush) SERIAL_FLUSHTX(); }; diff --git a/Marlin/src/HAL/shared/HAL_ST7920.h b/Marlin/src/HAL/shared/HAL_ST7920.h index 4e362f96ba..305736c3a5 100644 --- a/Marlin/src/HAL/shared/HAL_ST7920.h +++ b/Marlin/src/HAL/shared/HAL_ST7920.h @@ -27,7 +27,7 @@ * (bypassing U8G), it will allow the LIGHTWEIGHT_UI to operate. */ -#if BOTH(HAS_MARLINUI_U8GLIB, LIGHTWEIGHT_UI) +#if ALL(HAS_MARLINUI_U8GLIB, LIGHTWEIGHT_UI) void ST7920_cs(); void ST7920_ncs(); void ST7920_set_cmd(); diff --git a/Marlin/src/HAL/shared/backtrace/unwarmbytab.cpp b/Marlin/src/HAL/shared/backtrace/unwarmbytab.cpp index 148927a19f..bd87b6731c 100644 --- a/Marlin/src/HAL/shared/backtrace/unwarmbytab.cpp +++ b/Marlin/src/HAL/shared/backtrace/unwarmbytab.cpp @@ -55,7 +55,12 @@ static const char *UnwTabGetFunctionName(const UnwindCallbacks *cb, uint32_t add return nullptr; if ((flag_word & 0xFF000000) == 0xFF000000) { - return (const char *)(address - 4 - (flag_word & 0x00FFFFFF)); + const uint32_t fn_name_addr = address - 4 - (flag_word & 0x00FFFFFF); + + // Ensure the address is readable to avoid returning a bogus pointer + uint8_t dummy = 0; + if (cb->readB(fn_name_addr, &dummy)) + return (const char *)fn_name_addr; } return nullptr; } diff --git a/Marlin/src/HAL/shared/backtrace/unwmemaccess.cpp b/Marlin/src/HAL/shared/backtrace/unwmemaccess.cpp index a4151b38c2..da1cff4fcc 100644 --- a/Marlin/src/HAL/shared/backtrace/unwmemaccess.cpp +++ b/Marlin/src/HAL/shared/backtrace/unwmemaccess.cpp @@ -135,7 +135,7 @@ // Generic ARM code, that's testing if an access to the given address would cause a fault or not // It can't guarantee an address is in RAM or Flash only, but we usually don't care - #define NVIC_FAULT_STAT 0xE000ED28 // Configurable Fault Status Reg. + #define NVIC_FAULT_STAT 0xE000ED28 // Configurable Fault Status reg. #define NVIC_CFG_CTRL 0xE000ED14 // Configuration Control Register #define NVIC_FAULT_STAT_BFARV 0x00008000 // BFAR is valid #define NVIC_CFG_CTRL_BFHFNMIGN 0x00000100 // Ignore bus fault in NMI/fault diff --git a/Marlin/src/HAL/shared/cpu_exception/exception_arm.cpp b/Marlin/src/HAL/shared/cpu_exception/exception_arm.cpp index e54661c770..d478255678 100644 --- a/Marlin/src/HAL/shared/cpu_exception/exception_arm.cpp +++ b/Marlin/src/HAL/shared/cpu_exception/exception_arm.cpp @@ -4,7 +4,6 @@ * * Based on Sprinter and grbl. * Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm - * Copyright (c) 2020 Cyril Russo * * 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 @@ -279,8 +278,6 @@ void CommonHandler_C(ContextStateFrame * frame, unsigned long lr, unsigned long if (!faulted_from_exception) { // Not sure about the non_usage_fault, we want to try anyway, don't we ? && !non_usage_fault_occurred) // Try to resume to our handler here CFSR |= CFSR; // The ARM programmer manual says you must write to 1 all fault bits to clear them so this instruction is correct - // The frame will not be valid when returning anymore, let's clean it - savedFrame.CFSR = 0; frame->pc = (uint32_t)resume_from_fault; // Patch where to return to frame->lr = 0xDEADBEEF; // If our handler returns (it shouldn't), let's make it trigger an exception immediately diff --git a/Marlin/src/HAL/shared/eeprom_api.cpp b/Marlin/src/HAL/shared/eeprom_api.cpp index 47cfa5a2db..62a8f2afbc 100644 --- a/Marlin/src/HAL/shared/eeprom_api.cpp +++ b/Marlin/src/HAL/shared/eeprom_api.cpp @@ -1,10 +1,9 @@ /** * Marlin 3D Printer Firmware - * * Copyright (c) 2020 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] - * Copyright (c) 2016 Bob Cousins bobcousins42@googlemail.com - * Copyright (c) 2015-2016 Nico Tonnhofer wurstnase.reprap@gmail.com - * Copyright (c) 2016 Victor Perez victor_pv@hotmail.com + * + * 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 @@ -22,7 +21,7 @@ */ #include "../../inc/MarlinConfigPre.h" -#if EITHER(EEPROM_SETTINGS, SD_FIRMWARE_UPDATE) +#if ANY(EEPROM_SETTINGS, SD_FIRMWARE_UPDATE) #include "eeprom_api.h" PersistentStore persistentStore; diff --git a/Marlin/src/HAL/shared/eeprom_api.h b/Marlin/src/HAL/shared/eeprom_api.h index cd744f82dc..7be1e72f7a 100644 --- a/Marlin/src/HAL/shared/eeprom_api.h +++ b/Marlin/src/HAL/shared/eeprom_api.h @@ -1,10 +1,9 @@ /** * Marlin 3D Printer Firmware - * * Copyright (c) 2020 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] - * Copyright (c) 2016 Bob Cousins bobcousins42@googlemail.com - * Copyright (c) 2015-2016 Nico Tonnhofer wurstnase.reprap@gmail.com - * Copyright (c) 2016 Victor Perez victor_pv@hotmail.com + * + * 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 diff --git a/Marlin/src/HAL/shared/eeprom_if.h b/Marlin/src/HAL/shared/eeprom_if.h index e496de2a03..8b9791e1f8 100644 --- a/Marlin/src/HAL/shared/eeprom_if.h +++ b/Marlin/src/HAL/shared/eeprom_if.h @@ -1,9 +1,9 @@ /** * Marlin 3D Printer Firmware - * * Copyright (c) 2020 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] - * Copyright (c) 2016 Bob Cousins bobcousins42@googlemail.com - * Copyright (c) 2015-2016 Nico Tonnhofer wurstnase.reprap@gmail.com + * + * 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 diff --git a/Marlin/src/HAL/shared/eeprom_if_i2c.cpp b/Marlin/src/HAL/shared/eeprom_if_i2c.cpp index 6b559e234b..bba9c626a4 100644 --- a/Marlin/src/HAL/shared/eeprom_if_i2c.cpp +++ b/Marlin/src/HAL/shared/eeprom_if_i2c.cpp @@ -33,13 +33,14 @@ #if ENABLED(SOFT_I2C_EEPROM) #include - SlowSoftWire Wire = SlowSoftWire(I2C_SDA_PIN, I2C_SCL_PIN, true); + SlowSoftWire eWire = SlowSoftWire(I2C_SDA_PIN, I2C_SCL_PIN, true); #else #include + #define eWire Wire #endif void eeprom_init() { - Wire.begin( + eWire.begin( #if PINS_EXIST(I2C_SCL, I2C_SDA) && DISABLED(SOFT_I2C_EEPROM) uint8_t(I2C_SDA_PIN), uint8_t(I2C_SCL_PIN) #endif @@ -75,16 +76,16 @@ static uint8_t _eeprom_calc_device_address(uint8_t * const pos) { static void _eeprom_begin(uint8_t * const pos) { const unsigned eeprom_address = (unsigned)pos; - Wire.beginTransmission(_eeprom_calc_device_address(pos)); + eWire.beginTransmission(_eeprom_calc_device_address(pos)); if (!SMALL_EEPROM) - Wire.write(uint8_t((eeprom_address >> 8) & 0xFF)); // Address High, if needed - Wire.write(uint8_t(eeprom_address & 0xFF)); // Address Low + eWire.write(uint8_t((eeprom_address >> 8) & 0xFF)); // Address High, if needed + eWire.write(uint8_t(eeprom_address & 0xFF)); // Address Low } void eeprom_write_byte(uint8_t *pos, uint8_t value) { _eeprom_begin(pos); - Wire.write(value); - Wire.endTransmission(); + eWire.write(value); + eWire.endTransmission(); // wait for write cycle to complete // this could be done more efficiently with "acknowledge polling" @@ -93,9 +94,9 @@ void eeprom_write_byte(uint8_t *pos, uint8_t value) { uint8_t eeprom_read_byte(uint8_t *pos) { _eeprom_begin(pos); - Wire.endTransmission(); - Wire.requestFrom(_eeprom_calc_device_address(pos), (byte)1); - return Wire.available() ? Wire.read() : 0xFF; + eWire.endTransmission(); + eWire.requestFrom(_eeprom_calc_device_address(pos), (byte)1); + return eWire.available() ? eWire.read() : 0xFF; } #endif // USE_SHARED_EEPROM diff --git a/Marlin/src/HAL/shared/esp_wifi.cpp b/Marlin/src/HAL/shared/esp_wifi.cpp index a55f5ca39f..8a6ac2dfa9 100644 --- a/Marlin/src/HAL/shared/esp_wifi.cpp +++ b/Marlin/src/HAL/shared/esp_wifi.cpp @@ -21,6 +21,9 @@ */ #include "../../inc/MarlinConfig.h" + +#if ENABLED(WIFISUPPORT) + #include "Delay.h" void esp_wifi_init(void) { // init ESP01 WIFI module pins @@ -41,3 +44,5 @@ void esp_wifi_init(void) { // init ESP01 WIFI module pi OUT_WRITE(ESP_WIFI_MODULE_ENABLE_PIN, HIGH); #endif } + +#endif // WIFISUPPORT diff --git a/Marlin/src/HAL/shared/fauxpins.h b/Marlin/src/HAL/shared/fauxpins.h new file mode 100644 index 0000000000..924bfba02a --- /dev/null +++ b/Marlin/src/HAL/shared/fauxpins.h @@ -0,0 +1,367 @@ +/** + * Marlin 3D Printer Firmware + * Copyright (c) 2023 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] + * + * Based on Sprinter and grbl. + * Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (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 + +// +// Faux pins for Dependency Check +// + +// +// STM32 Pin Names +// +#define PA0 0x10 +#define PA1 0x11 +#define PA2 0x12 +#define PA3 0x13 +#define PA4 0x14 +#define PA5 0x15 +#define PA6 0x16 +#define PA7 0x17 +#define PA8 0x18 +#define PA9 0x19 +#define PA10 0x1A +#define PA11 0x1B +#define PA12 0x1C +#define PA13 0x1D +#define PA14 0x1E +#define PA15 0x1F + +#define PB0 0x20 +#define PB1 0x21 +#define PB2 0x22 +#define PB3 0x23 +#define PB4 0x24 +#define PB5 0x25 +#define PB6 0x26 +#define PB7 0x27 +#define PB8 0x28 +#define PB9 0x29 +#define PB10 0x2A +#define PB11 0x2B +#define PB12 0x2C +#define PB13 0x2D +#define PB14 0x2E +#define PB15 0x2F + +#define PC0 0x30 +#define PC1 0x31 +#define PC2 0x32 +#define PC3 0x33 +#define PC4 0x34 +#define PC5 0x35 +#define PC6 0x36 +#define PC7 0x37 +#define PC8 0x38 +#define PC9 0x39 +#define PC10 0x3A +#define PC11 0x3B +#define PC12 0x3C +#define PC13 0x3D +#define PC14 0x3E +#define PC15 0x3F + +#define PD0 0x40 +#define PD1 0x41 +#define PD2 0x42 +#define PD3 0x43 +#define PD4 0x44 +#define PD5 0x45 +#define PD6 0x46 +#define PD7 0x47 +#define PD8 0x48 +#define PD9 0x49 +#define PD10 0x4A +#define PD11 0x4B +#define PD12 0x4C +#define PD13 0x4D +#define PD14 0x4E +#define PD15 0x4F + +#define PE0 0x50 +#define PE1 0x51 +#define PE2 0x52 +#define PE3 0x53 +#define PE4 0x54 +#define PE5 0x55 +#define PE6 0x56 +#define PE7 0x57 +#define PE8 0x58 +#define PE9 0x59 +#define PE10 0x5A +#define PE11 0x5B +#define PE12 0x5C +#define PE13 0x5D +#define PE14 0x5E +#define PE15 0x5F + +#define PF0 0x60 +#define PF1 0x61 +#define PF2 0x62 +#define PF3 0x63 +#define PF4 0x64 +#define PF5 0x65 +#define PF6 0x66 +#define PF7 0x67 +#define PF8 0x68 +#define PF9 0x69 +#define PF10 0x6A +#define PF11 0x6B +#define PF12 0x6C +#define PF13 0x6D +#define PF14 0x6E +#define PF15 0x6F + +#define PG0 0x70 +#define PG1 0x71 +#define PG2 0x72 +#define PG3 0x73 +#define PG4 0x74 +#define PG5 0x75 +#define PG6 0x76 +#define PG7 0x77 +#define PG8 0x78 +#define PG9 0x79 +#define PG10 0x7A +#define PG11 0x7B +#define PG12 0x7C +#define PG13 0x7D +#define PG14 0x7E +#define PG15 0x7F + +#define PH0 0x80 +#define PH1 0x81 +#define PH2 0x82 +#define PH3 0x83 +#define PH4 0x84 +#define PH5 0x85 +#define PH6 0x86 +#define PH7 0x87 +#define PH8 0x88 +#define PH9 0x89 +#define PH10 0x8A +#define PH11 0x8B +#define PH12 0x8C +#define PH13 0x8D +#define PH14 0x8E +#define PH15 0x8F + +#define PI0 0x90 +#define PI1 0x91 +#define PI2 0x92 +#define PI3 0x93 +#define PI4 0x94 +#define PI5 0x95 +#define PI6 0x96 +#define PI7 0x97 +#define PI8 0x98 +#define PI9 0x99 +#define PI10 0x9A +#define PI11 0x9B +#define PI12 0x9C +#define PI13 0x9D +#define PI14 0x9E +#define PI15 0x9F + +#define PJ0 0xA0 +#define PJ1 0xA1 +#define PJ2 0xA2 +#define PJ3 0xA3 +#define PJ4 0xA4 +#define PJ5 0xA5 +#define PJ6 0xA6 +#define PJ7 0xA7 +#define PJ8 0xA8 +#define PJ9 0xA9 +#define PJ10 0xAA +#define PJ11 0xAB +#define PJ12 0xAC +#define PJ13 0xAD +#define PJ14 0xAE +#define PJ15 0xAF + +// +// LPC Pin Names +// +#define P0_00 100 +#define P0_01 101 +#define P0_02 102 +#define P0_03 103 +#define P0_04 104 +#define P0_05 105 +#define P0_06 106 +#define P0_07 107 +#define P0_08 108 +#define P0_09 109 +#define P0_10 110 +#define P0_11 111 +#define P0_12 112 +#define P0_13 113 +#define P0_14 114 +#define P0_15 115 +#define P0_16 116 +#define P0_17 117 +#define P0_18 118 +#define P0_19 119 +#define P0_20 120 +#define P0_21 121 +#define P0_22 122 +#define P0_23 123 +#define P0_24 124 +#define P0_25 125 +#define P0_26 126 +#define P0_27 127 +#define P0_28 128 +#define P0_29 129 +#define P0_30 130 +#define P0_31 131 + +#define P1_00 200 +#define P1_01 201 +#define P1_02 202 +#define P1_03 203 +#define P1_04 204 +#define P1_05 205 +#define P1_06 206 +#define P1_07 207 +#define P1_08 208 +#define P1_09 209 +#define P1_10 210 +#define P1_11 211 +#define P1_12 212 +#define P1_13 213 +#define P1_14 214 +#define P1_15 215 +#define P1_16 216 +#define P1_17 217 +#define P1_18 218 +#define P1_19 219 +#define P1_20 220 +#define P1_21 221 +#define P1_22 222 +#define P1_23 223 +#define P1_24 224 +#define P1_25 225 +#define P1_26 226 +#define P1_27 227 +#define P1_28 228 +#define P1_29 229 +#define P1_30 230 +#define P1_31 231 + +#define P2_00 300 +#define P2_01 301 +#define P2_02 302 +#define P2_03 303 +#define P2_04 304 +#define P2_05 305 +#define P2_06 306 +#define P2_07 307 +#define P2_08 308 +#define P2_09 309 +#define P2_10 310 +#define P2_11 311 +#define P2_12 312 +#define P2_13 313 +#define P2_14 314 +#define P2_15 315 +#define P2_16 316 +#define P2_17 317 +#define P2_18 318 +#define P2_19 319 +#define P2_20 320 +#define P2_21 321 +#define P2_22 322 +#define P2_23 323 +#define P2_24 324 +#define P2_25 325 +#define P2_26 326 +#define P2_27 327 +#define P2_28 328 +#define P2_29 329 +#define P2_30 330 +#define P2_31 331 + +#define P3_00 400 +#define P3_01 401 +#define P3_02 402 +#define P3_03 403 +#define P3_04 404 +#define P3_05 405 +#define P3_06 406 +#define P3_07 407 +#define P3_08 408 +#define P3_09 409 +#define P3_10 410 +#define P3_11 411 +#define P3_12 412 +#define P3_13 413 +#define P3_14 414 +#define P3_15 415 +#define P3_16 416 +#define P3_17 417 +#define P3_18 418 +#define P3_19 419 +#define P3_20 420 +#define P3_21 421 +#define P3_22 422 +#define P3_23 423 +#define P3_24 424 +#define P3_25 425 +#define P3_26 426 +#define P3_27 427 +#define P3_28 428 +#define P3_29 429 +#define P3_30 430 +#define P3_31 431 + +#define P4_00 500 +#define P4_01 501 +#define P4_02 502 +#define P4_03 503 +#define P4_04 504 +#define P4_05 505 +#define P4_06 506 +#define P4_07 507 +#define P4_08 508 +#define P4_09 509 +#define P4_10 510 +#define P4_11 511 +#define P4_12 512 +#define P4_13 513 +#define P4_14 514 +#define P4_15 515 +#define P4_16 516 +#define P4_17 517 +#define P4_18 518 +#define P4_19 519 +#define P4_20 520 +#define P4_21 521 +#define P4_22 522 +#define P4_23 523 +#define P4_24 524 +#define P4_25 525 +#define P4_26 526 +#define P4_27 527 +#define P4_28 528 +#define P4_29 529 +#define P4_30 530 +#define P4_31 531 diff --git a/Marlin/src/HAL/shared/servo.cpp b/Marlin/src/HAL/shared/servo.cpp index b838800de6..bb9d618018 100644 --- a/Marlin/src/HAL/shared/servo.cpp +++ b/Marlin/src/HAL/shared/servo.cpp @@ -67,7 +67,7 @@ uint8_t ServoCount = 0; // the total number of attached static bool anyTimerChannelActive(const timer16_Sequence_t timer) { // returns true if any servo is active on this timer - LOOP_L_N(channel, SERVOS_PER_TIMER) { + for (uint8_t channel = 0; channel < SERVOS_PER_TIMER; ++channel) { if (SERVO(timer, channel).Pin.isActive) return true; } diff --git a/Marlin/src/HAL/shared/servo.h b/Marlin/src/HAL/shared/servo.h index c2560a8538..786c1e6a72 100644 --- a/Marlin/src/HAL/shared/servo.h +++ b/Marlin/src/HAL/shared/servo.h @@ -74,6 +74,8 @@ #include "../TEENSY40_41/Servo.h" #elif defined(TARGET_LPC1768) #include "../LPC1768/Servo.h" +#elif defined(ARDUINO_ARCH_HC32) + #include "../HC32/Servo.h" #elif defined(__STM32F1__) || defined(TARGET_STM32F1) #include "../STM32F1/Servo.h" #elif defined(ARDUINO_ARCH_STM32) @@ -83,10 +85,10 @@ #else #include - #if defined(__AVR__) || defined(ARDUINO_ARCH_SAM) || defined(__SAMD51__) + #if defined(__AVR__) || defined(ARDUINO_ARCH_SAM) || defined(__SAMD51__) || defined(__SAMD21__) // we're good to go #else - #error "This library only supports boards with an AVR, SAM3X or SAMD51 processor." + #error "This library only supports boards with an AVR, SAM3X, SAMD21 or SAMD51 processor." #endif #define Servo_VERSION 2 // software version of this library diff --git a/Marlin/src/HAL/shared/servo_private.h b/Marlin/src/HAL/shared/servo_private.h index 10cc5a1988..8fd5ab2d88 100644 --- a/Marlin/src/HAL/shared/servo_private.h +++ b/Marlin/src/HAL/shared/servo_private.h @@ -49,8 +49,10 @@ #include "../DUE/ServoTimers.h" #elif defined(__SAMD51__) #include "../SAMD51/ServoTimers.h" +#elif defined(__SAMD21__) + #include "../SAMD21/ServoTimers.h" #else - #error "This library only supports boards with an AVR, SAM3X or SAMD51 processor." + #error "This library only supports boards with an AVR, SAM3X, SAMD21 or SAMD51 processor." #endif // Macros diff --git a/Marlin/src/MarlinCore.cpp b/Marlin/src/MarlinCore.cpp index 0fe7d47855..6f413e705d 100644 --- a/Marlin/src/MarlinCore.cpp +++ b/Marlin/src/MarlinCore.cpp @@ -34,6 +34,10 @@ #include "HAL/shared/esp_wifi.h" #include "HAL/shared/cpu_exception/exception_hook.h" +#if ENABLED(WIFISUPPORT) + #include "HAL/shared/esp_wifi.h" +#endif + #ifdef ARDUINO #include #endif @@ -46,6 +50,9 @@ #include "module/settings.h" #include "module/stepper.h" #include "module/temperature.h" +#if ENABLED(FT_MOTION) + #include "module/ft_motion.h" +#endif #include "gcode/gcode.h" #include "gcode/parser.h" @@ -153,7 +160,7 @@ #include "feature/spindle_laser.h" #endif -#if ENABLED(SDSUPPORT) +#if HAS_MEDIA CardReader card; #endif @@ -168,6 +175,8 @@ #include "module/polargraph.h" #elif IS_SCARA #include "module/scara.h" +#elif ENABLED(POLAR) + #include "module/polar.h" #endif #if HAS_LEVELING @@ -190,7 +199,7 @@ #include "feature/runout.h" #endif -#if EITHER(PROBE_TARE, HAS_Z_SERVO_PROBE) +#if ANY(PROBE_TARE, HAS_Z_SERVO_PROBE) #include "module/probe.h" #endif @@ -232,7 +241,7 @@ #include "feature/password/password.h" #endif -#if ENABLED(DGUS_LCD_UI_MKS) +#if DGUS_LCD_UI_MKS #include "lcd/extui/dgus/DGUSScreenHandler.h" #endif @@ -312,7 +321,7 @@ bool pin_is_protected(const pin_t pin) { static constexpr size_t pincount = OnlyPins::size; static const pin_t (&sensitive_pins)[pincount] PROGMEM = OnlyPins::table; #endif - LOOP_L_N(i, pincount) { + for (uint8_t i = 0; i < pincount; ++i) { const pin_t * const pptr = &sensitive_pins[i]; if (pin == (sizeof(pin_t) == 2 ? (pin_t)pgm_read_word(pptr) : (pin_t)pgm_read_byte(pptr))) return true; } @@ -347,14 +356,12 @@ void startOrResumeJob() { TERN_(GCODE_REPEAT_MARKERS, repeat.reset()); TERN_(CANCEL_OBJECTS, cancelable.reset()); TERN_(LCD_SHOW_E_TOTAL, e_move_accumulator = 0); - #if ENABLED(SET_REMAINING_TIME) - ui.reset_remaining_time(); - #endif + TERN_(SET_REMAINING_TIME, ui.reset_remaining_time()); } print_job_timer.start(); } -#if ENABLED(SDSUPPORT) +#if HAS_MEDIA inline void abortSDPrinting() { IF_DISABLED(NO_SD_AUTOSTART, card.autofile_cancel()); @@ -384,11 +391,11 @@ void startOrResumeJob() { if (queue.enqueue_one(F("M1001"))) { // Keep trying until it gets queued marlin_state = MF_RUNNING; // Signal to stop trying TERN_(PASSWORD_AFTER_SD_PRINT_END, password.lock_machine()); - TERN_(DGUS_LCD_UI_MKS, ScreenHandler.SDPrintingFinished()); + TERN_(DGUS_LCD_UI_MKS, screen.sdPrintingFinished()); } } -#endif // SDSUPPORT +#endif // HAS_MEDIA /** * Minimal management of Marlin's core activities: @@ -427,7 +434,7 @@ inline void manage_inactivity(const bool no_stepper_sleep=false) { if (has_blocks) gcode.reset_stepper_timeout(ms); // Reset timeout for M18/M84, M85 max 'kill', and laser. // M18 / M84 : Handle steppers inactive time timeout - #if HAS_DISABLE_INACTIVE_AXIS + #if HAS_DISABLE_IDLE_AXES if (gcode.stepper_inactive_time) { static bool already_shutdown_steppers; // = false @@ -437,16 +444,16 @@ inline void manage_inactivity(const bool no_stepper_sleep=false) { already_shutdown_steppers = true; // Individual axes will be disabled if configured - TERN_(DISABLE_INACTIVE_X, stepper.disable_axis(X_AXIS)); - TERN_(DISABLE_INACTIVE_Y, stepper.disable_axis(Y_AXIS)); - TERN_(DISABLE_INACTIVE_Z, stepper.disable_axis(Z_AXIS)); - TERN_(DISABLE_INACTIVE_I, stepper.disable_axis(I_AXIS)); - TERN_(DISABLE_INACTIVE_J, stepper.disable_axis(J_AXIS)); - TERN_(DISABLE_INACTIVE_K, stepper.disable_axis(K_AXIS)); - TERN_(DISABLE_INACTIVE_U, stepper.disable_axis(U_AXIS)); - TERN_(DISABLE_INACTIVE_V, stepper.disable_axis(V_AXIS)); - TERN_(DISABLE_INACTIVE_W, stepper.disable_axis(W_AXIS)); - TERN_(DISABLE_INACTIVE_E, stepper.disable_e_steppers()); + TERN_(DISABLE_IDLE_X, stepper.disable_axis(X_AXIS)); + TERN_(DISABLE_IDLE_Y, stepper.disable_axis(Y_AXIS)); + TERN_(DISABLE_IDLE_Z, stepper.disable_axis(Z_AXIS)); + TERN_(DISABLE_IDLE_I, stepper.disable_axis(I_AXIS)); + TERN_(DISABLE_IDLE_J, stepper.disable_axis(J_AXIS)); + TERN_(DISABLE_IDLE_K, stepper.disable_axis(K_AXIS)); + TERN_(DISABLE_IDLE_U, stepper.disable_axis(U_AXIS)); + TERN_(DISABLE_IDLE_V, stepper.disable_axis(V_AXIS)); + TERN_(DISABLE_IDLE_W, stepper.disable_axis(W_AXIS)); + TERN_(DISABLE_IDLE_E, stepper.disable_e_steppers()); TERN_(AUTO_BED_LEVELING_UBL, bedlevel.steppers_were_disabled()); } @@ -518,8 +525,8 @@ inline void manage_inactivity(const bool no_stepper_sleep=false) { if (ELAPSED(ms, next_cub_ms_##N)) { \ next_cub_ms_##N = ms + CUB_DEBOUNCE_DELAY_##N; \ CODE; \ - queue.inject(F(BUTTON##N##_GCODE)); \ - TERN_(HAS_MARLINUI_MENU, ui.quick_feedback()); \ + queue.inject(F(BUTTON##N##_GCODE)); \ + TERN_(HAS_MARLINUI_MENU, ui.quick_feedback()); \ } \ } \ }while(0) @@ -667,28 +674,9 @@ inline void manage_inactivity(const bool no_stepper_sleep=false) { && ELAPSED(ms, gcode.previous_move_ms + SEC_TO_MS(EXTRUDER_RUNOUT_SECONDS)) && !planner.has_blocks_queued() ) { - #if ENABLED(SWITCHING_EXTRUDER) - bool oldstatus; - switch (active_extruder) { - default: oldstatus = stepper.AXIS_IS_ENABLED(E_AXIS, 0); stepper.ENABLE_EXTRUDER(0); break; - #if E_STEPPERS > 1 - case 2: case 3: oldstatus = stepper.AXIS_IS_ENABLED(E_AXIS, 1); stepper.ENABLE_EXTRUDER(1); break; - #if E_STEPPERS > 2 - case 4: case 5: oldstatus = stepper.AXIS_IS_ENABLED(E_AXIS, 2); stepper.ENABLE_EXTRUDER(2); break; - #if E_STEPPERS > 3 - case 6: case 7: oldstatus = stepper.AXIS_IS_ENABLED(E_AXIS, 3); stepper.ENABLE_EXTRUDER(3); break; - #endif // E_STEPPERS > 3 - #endif // E_STEPPERS > 2 - #endif // E_STEPPERS > 1 - } - #else // !SWITCHING_EXTRUDER - bool oldstatus; - switch (active_extruder) { - default: - #define _CASE_EN(N) case N: oldstatus = stepper.AXIS_IS_ENABLED(E_AXIS, N); stepper.ENABLE_EXTRUDER(N); break; - REPEAT(E_STEPPERS, _CASE_EN); - } - #endif + const int8_t e_stepper = TERN(HAS_SWITCHING_EXTRUDER, active_extruder >> 1, active_extruder); + const bool e_off = !stepper.AXIS_IS_ENABLED(E_AXIS, e_stepper); + if (e_off) stepper.ENABLE_EXTRUDER(e_stepper); const float olde = current_position.e; current_position.e += EXTRUDER_RUNOUT_EXTRUDE; @@ -697,22 +685,7 @@ inline void manage_inactivity(const bool no_stepper_sleep=false) { planner.set_e_position_mm(olde); planner.synchronize(); - #if ENABLED(SWITCHING_EXTRUDER) - switch (active_extruder) { - default: if (oldstatus) stepper.ENABLE_EXTRUDER(0); else stepper.DISABLE_EXTRUDER(0); break; - #if E_STEPPERS > 1 - case 2: case 3: if (oldstatus) stepper.ENABLE_EXTRUDER(1); else stepper.DISABLE_EXTRUDER(1); break; - #if E_STEPPERS > 2 - case 4: case 5: if (oldstatus) stepper.ENABLE_EXTRUDER(2); else stepper.DISABLE_EXTRUDER(2); break; - #endif // E_STEPPERS > 2 - #endif // E_STEPPERS > 1 - } - #else // !SWITCHING_EXTRUDER - switch (active_extruder) { - #define _CASE_RESTORE(N) case N: if (oldstatus) stepper.ENABLE_EXTRUDER(N); else stepper.DISABLE_EXTRUDER(N); break; - REPEAT(E_STEPPERS, _CASE_RESTORE); - } - #endif // !SWITCHING_EXTRUDER + if (e_off) stepper.DISABLE_EXTRUDER(e_stepper); gcode.reset_stepper_timeout(ms); } @@ -751,6 +724,10 @@ inline void manage_inactivity(const bool no_stepper_sleep=false) { #endif } +#if ALL(EP_BABYSTEPPING, EMERGENCY_PARSER) + #include "feature/babystep.h" +#endif + /** * Standard idle routine keeps the machine alive: * - Core Marlin activities @@ -773,7 +750,7 @@ inline void manage_inactivity(const bool no_stepper_sleep=false) { * - Update the Průša MMU2 * - Handle Joystick jogging */ -void idle(bool no_stepper_sleep/*=false*/) { +void idle(const bool no_stepper_sleep/*=false*/) { #ifdef MAX7219_DEBUG_PROFILE CodeProfiler idle_profiler; #endif @@ -821,11 +798,11 @@ void idle(bool no_stepper_sleep/*=false*/) { // Run StallGuard endstop checks #if ENABLED(SPI_ENDSTOPS) if (endstops.tmc_spi_homing.any && TERN1(IMPROVE_HOMING_RELIABILITY, ELAPSED(millis(), sg_guard_period))) - LOOP_L_N(i, 4) if (endstops.tmc_spi_homing_check()) break; // Read SGT 4 times per idle loop + for (uint8_t i = 0; i < 4; ++i) if (endstops.tmc_spi_homing_check()) break; // Read SGT 4 times per idle loop #endif // Handle SD Card insert / remove - TERN_(SDSUPPORT, card.manage_media()); + TERN_(HAS_MEDIA, card.manage_media()); // Handle USB Flash Drive insert / remove TERN_(USB_FLASH_DRIVE_SUPPORT, card.diskIODriver()->idle()); @@ -840,7 +817,7 @@ void idle(bool no_stepper_sleep/*=false*/) { TERN_(HAS_BEEPER, buzzer.tick()); // Handle UI input / draw events - TERN(DWIN_CREALITY_LCD, DWIN_Update(), ui.update()); + TERN(DWIN_CREALITY_LCD, dwinUpdate(), ui.update()); // Run i2c Position Encoders #if ENABLED(I2C_POSITION_ENCODERS) @@ -873,14 +850,23 @@ void idle(bool no_stepper_sleep/*=false*/) { // Handle Joystick jogging TERN_(POLL_JOG, joystick.inject_jog_moves()); + // Async Babystepping via the Emergency Parser + #if ALL(EP_BABYSTEPPING, EMERGENCY_PARSER) + babystep.do_ep_steps(); + #endif + // Direct Stepping TERN_(DIRECT_STEPPING, page_manager.write_responses()); // Update the LVGL interface TERN_(HAS_TFT_LVGL_UI, LV_TASK_HANDLER()); + // Manage Fixed-time Motion Control + TERN_(FT_MOTION, ftMotion.loop()); + IDLE_DONE: TERN_(MARLIN_DEV_MODE, idle_depth--); + return; } @@ -894,7 +880,7 @@ void kill(FSTR_P const lcd_error/*=nullptr*/, FSTR_P const lcd_component/*=nullp TERN_(HAS_CUTTER, cutter.kill()); // Full cutter shutdown including ISR control // Echo the LCD message to serial for extra context - if (lcd_error) { SERIAL_ECHO_START(); SERIAL_ECHOLNF(lcd_error); } + if (lcd_error) { SERIAL_ECHO_START(); SERIAL_ECHOLN(lcd_error); } #if HAS_DISPLAY ui.kill_screen(lcd_error ?: GET_TEXT_F(MSG_KILLED), lcd_component ?: FPSTR(NUL_STR)); @@ -936,7 +922,7 @@ void minkill(const bool steppers_off/*=false*/) { TERN_(HAS_SUICIDE, suicide()); - #if EITHER(HAS_KILL, SOFT_RESET_ON_KILL) + #if ANY(HAS_KILL, SOFT_RESET_ON_KILL) // Wait for both KILL and ENC to be released while (TERN0(HAS_KILL, kill_state()) || TERN0(SOFT_RESET_ON_KILL, ui.button_pressed())) @@ -965,7 +951,7 @@ void stop() { print_job_timer.stop(); - #if EITHER(PROBING_FANS_OFF, ADVANCED_PAUSE_FANS_PAUSE) + #if ANY(PROBING_FANS_OFF, ADVANCED_PAUSE_FANS_PAUSE) thermalManager.set_fans_paused(false); // Un-pause fans for safety #endif @@ -1151,7 +1137,7 @@ void setup() { #if ENABLED(MARLIN_DEV_MODE) auto log_current_ms = [&](PGM_P const msg) { SERIAL_ECHO_START(); - SERIAL_CHAR('['); SERIAL_ECHO(millis()); SERIAL_ECHOPGM("] "); + TSS('[', millis(), F("] ")).echo(); SERIAL_ECHOLNPGM_P(msg); }; #define SETUP_LOG(M) log_current_ms(PSTR(M)) @@ -1233,6 +1219,12 @@ void setup() { #if TEMP_SENSOR_IS_MAX_TC(1) || (TEMP_SENSOR_IS_MAX_TC(REDUNDANT) && REDUNDANT_TEMP_MATCH(SOURCE, E1)) OUT_WRITE(TEMP_1_CS_PIN, HIGH); #endif + #if TEMP_SENSOR_IS_MAX_TC(2) || (TEMP_SENSOR_IS_MAX_TC(REDUNDANT) && REDUNDANT_TEMP_MATCH(SOURCE, E2)) + OUT_WRITE(TEMP_2_CS_PIN, HIGH); + #endif + #if TEMP_SENSOR_IS_MAX_TC(BED) + OUT_WRITE(TEMP_BED_CS_PIN, HIGH); + #endif #if ENABLED(DUET_SMART_EFFECTOR) && PIN_EXISTS(SMART_EFFECTOR_MOD) OUT_WRITE(SMART_EFFECTOR_MOD_PIN, LOW); // Put Smart Effector into NORMAL mode @@ -1268,7 +1260,9 @@ void setup() { SETUP_RUN(hal.init_board()); - SETUP_RUN(esp_wifi_init()); + #if ENABLED(WIFISUPPORT) + SETUP_RUN(esp_wifi_init()); + #endif // Report Reset Reason if (mcu & RST_POWER_ON) SERIAL_ECHOLNPGM(STR_POWERUP); @@ -1325,14 +1319,14 @@ void setup() { #endif #endif - #if BOTH(SDSUPPORT, SDCARD_EEPROM_EMULATION) + #if ALL(HAS_MEDIA, SDCARD_EEPROM_EMULATION) SETUP_RUN(card.mount()); // Mount media with settings before first_load #endif SETUP_RUN(settings.first_load()); // Load data from EEPROM if available (or use defaults) // This also updates variables in the planner, elsewhere - #if BOTH(HAS_WIRED_LCD, SHOW_BOOTSCREEN) + #if ALL(HAS_WIRED_LCD, SHOW_BOOTSCREEN) SETUP_RUN(ui.show_bootscreen()); const millis_t bootscreen_ms = millis(); #endif @@ -1349,7 +1343,7 @@ void setup() { SETUP_RUN(touchBt.init()); #endif - TERN_(HAS_M206_COMMAND, current_position += home_offset); // Init current position based on home_offset + TERN_(HAS_HOME_OFFSET, current_position += home_offset); // Init current position based on home_offset sync_plan_position(); // Vital to init stepper/planner equivalent for current_position @@ -1407,7 +1401,7 @@ void setup() { SETUP_RUN(stepper_dac.init()); #endif - #if EITHER(Z_PROBE_SLED, SOLENOID_PROBE) && HAS_SOLENOID_1 + #if ANY(Z_PROBE_SLED, SOLENOID_PROBE) && HAS_SOLENOID_1 OUT_WRITE(SOL1_PIN, LOW); // OFF #endif @@ -1597,7 +1591,7 @@ void setup() { #endif #if HAS_DWIN_E3V2_BASIC - SETUP_RUN(DWIN_InitScreen()); + SETUP_RUN(dwinInitScreen()); #endif #if HAS_SERVICE_INTERVALS && !HAS_DWIN_E3V2_BASIC @@ -1613,13 +1607,13 @@ void setup() { #endif #if HAS_TFT_LVGL_UI - #if ENABLED(SDSUPPORT) + #if HAS_MEDIA if (!card.isMounted()) SETUP_RUN(card.mount()); // Mount SD to load graphics and fonts #endif SETUP_RUN(tft_lvgl_init()); #endif - #if BOTH(HAS_WIRED_LCD, SHOW_BOOTSCREEN) + #if ALL(HAS_WIRED_LCD, SHOW_BOOTSCREEN) const millis_t elapsed = millis() - bootscreen_ms; #if ENABLED(MARLIN_DEV_MODE) SERIAL_ECHOLNPGM("elapsed=", elapsed); @@ -1631,7 +1625,7 @@ void setup() { SETUP_RUN(password.lock_machine()); // Will not proceed until correct password provided #endif - #if BOTH(HAS_MARLINUI_MENU, TOUCH_SCREEN_CALIBRATION) && EITHER(TFT_CLASSIC_UI, TFT_COLOR_UI) + #if ALL(HAS_MARLINUI_MENU, TOUCH_SCREEN_CALIBRATION) && ANY(TFT_CLASSIC_UI, TFT_COLOR_UI) SETUP_RUN(ui.check_touch_calibration()); #endif @@ -1647,8 +1641,18 @@ void setup() { SETUP_RUN(bdl.init(I2C_BD_SDA_PIN, I2C_BD_SCL_PIN, I2C_BD_DELAY)); #endif + #if ENABLED(FT_MOTION) + SETUP_RUN(ftMotion.init()); + #endif + marlin_state = MF_RUNNING; + #ifdef STARTUP_TUNE + // Play a short startup tune before continuing. + constexpr uint16_t tune[] = STARTUP_TUNE; + for (uint8_t i = 0; i < COUNT(tune) - 1; i += 2) BUZZ(tune[i + 1], tune[i]); + #endif + SETUP_LOG("setup() completed."); TERN_(MARLIN_TEST_BUILD, runStartupTests()); @@ -1671,14 +1675,14 @@ void loop() { do { idle(); - #if ENABLED(SDSUPPORT) + #if HAS_MEDIA if (card.flag.abort_sd_printing) abortSDPrinting(); if (marlin_state == MF_SD_COMPLETE) finishSDPrinting(); #endif queue.advance(); - #if EITHER(POWER_OFF_TIMER, POWER_OFF_WAIT_FOR_COOLDOWN) + #if ANY(POWER_OFF_TIMER, POWER_OFF_WAIT_FOR_COOLDOWN) powerManager.checkAutoPowerOff(); #endif diff --git a/Marlin/src/MarlinCore.h b/Marlin/src/MarlinCore.h index f80405a302..e9c63bb31f 100644 --- a/Marlin/src/MarlinCore.h +++ b/Marlin/src/MarlinCore.h @@ -30,7 +30,7 @@ void stop(); // Pass true to keep steppers from timing out -void idle(bool no_stepper_sleep=false); +void idle(const bool no_stepper_sleep=false); inline void idle_no_sleep() { idle(true); } #if ENABLED(G38_PROBE_TARGET) diff --git a/Marlin/src/core/boards.h b/Marlin/src/core/boards.h index b5f5b037f9..91141b23f9 100644 --- a/Marlin/src/core/boards.h +++ b/Marlin/src/core/boards.h @@ -21,6 +21,11 @@ */ #pragma once +/** + * Whenever changes are made to this file, please update Marlin/Makefile + * and _data/boards.yml in the MarlinDocumentation repo. + */ + #include "macros.h" #define BOARD_UNKNOWN -1 @@ -49,6 +54,12 @@ #define BOARD_RAMPS_PLUS_EEF 1033 // RAMPS Plus 3DYMY (Power outputs: Hotend0, Hotend1, Fan) #define BOARD_RAMPS_PLUS_SF 1034 // RAMPS Plus 3DYMY (Power outputs: Spindle, Controller Fan) +#define BOARD_RAMPS_BTT_16_PLUS_EFB 1035 // RAMPS 1.6+ (Power outputs: Hotend, Fan, Bed) +#define BOARD_RAMPS_BTT_16_PLUS_EEB 1036 // RAMPS 1.6+ (Power outputs: Hotend0, Hotend1, Bed) +#define BOARD_RAMPS_BTT_16_PLUS_EFF 1037 // RAMPS 1.6+ (Power outputs: Hotend, Fan0, Fan1) +#define BOARD_RAMPS_BTT_16_PLUS_EEF 1038 // RAMPS 1.6+ (Power outputs: Hotend0, Hotend1, Fan) +#define BOARD_RAMPS_BTT_16_PLUS_SF 1039 // RAMPS 1.6+ (Power outputs: Spindle, Controller Fan) + // // RAMPS Derivatives - ATmega1280, ATmega2560 // @@ -118,6 +129,8 @@ #define BOARD_LONGER3D_LKx_PRO 1162 // Longer LKx PRO / Alfawise Uxx Pro (PRO version) #define BOARD_ZRIB_V53 1163 // Zonestar zrib V5.3 (Chinese RAMPS replica) #define BOARD_PXMALION_CORE_I3 1164 // Pxmalion Core I3 +#define BOARD_PANOWIN_CUTLASS 1165 // Panowin Cutlass (as found in the Panowin F1) +#define BOARD_KODAMA_BARDO 1166 // Kodama Bardo V1.x (as found in the Kodama Trinus) // // RAMBo and derivatives @@ -166,6 +179,7 @@ #define BOARD_GT2560_V4_A20 1328 // Geeetech GT2560 Rev B for A20(M/T/D) #define BOARD_PROTONEER_CNC_SHIELD_V3 1329 // Mega controller & Protoneer CNC Shield V3.00 #define BOARD_WEEDO_62A 1330 // WEEDO 62A board (TINA2, Monoprice Cadet, etc.) +#define BOARD_GT2560_V41B 1331 // Geeetech GT2560 V4.1B for A10(M/T/D) // // ATmega1281, ATmega2561 @@ -184,12 +198,13 @@ #define BOARD_MELZI_V2 1503 // Melzi V2 #define BOARD_MELZI_MAKR3D 1504 // Melzi with ATmega1284 (MaKr3d version) #define BOARD_MELZI_CREALITY 1505 // Melzi Creality3D (for CR-10 etc) -#define BOARD_MELZI_MALYAN 1506 // Melzi Malyan M150 -#define BOARD_MELZI_TRONXY 1507 // Tronxy X5S -#define BOARD_STB_11 1508 // STB V1.1 -#define BOARD_AZTEEG_X1 1509 // Azteeg X1 -#define BOARD_ANET_10 1510 // Anet 1.0 (Melzi clone) -#define BOARD_ZMIB_V2 1511 // ZoneStar ZMIB V2 +#define BOARD_MELZI_CREALITY_ENDER2 1506 // Melzi Creality3D (for Ender-2) +#define BOARD_MELZI_MALYAN 1507 // Melzi Malyan M150 +#define BOARD_MELZI_TRONXY 1508 // Tronxy X5S +#define BOARD_STB_11 1509 // STB V1.1 +#define BOARD_AZTEEG_X1 1510 // Azteeg X1 +#define BOARD_ANET_10 1511 // Anet 1.0 (Melzi clone) +#define BOARD_ZMIB_V2 1512 // ZoneStar ZMIB V2 // // Other ATmega644P, ATmega644, ATmega1284P @@ -221,7 +236,7 @@ #define BOARD_5DPRINT 1707 // 5DPrint D8 Driver Board // -// LPC1768 ARM Cortex M3 +// LPC1768 ARM Cortex-M3 // #define BOARD_RAMPS_14_RE_ARM_EFB 2000 // Re-ARM with RAMPS 1.4 (Power outputs: Hotend, Fan, Bed) @@ -242,7 +257,7 @@ #define BOARD_EMOTRONIC 2015 // eMotion-Tech eMotronic // -// LPC1769 ARM Cortex M3 +// LPC1769 ARM Cortex-M3 // #define BOARD_MKS_SGEN 2500 // MKS-SGen @@ -259,7 +274,7 @@ #define BOARD_FLY_CDY 2511 // FLYmaker FLY CDY // -// SAM3X8E ARM Cortex M3 +// SAM3X8E ARM Cortex-M3 // #define BOARD_DUE3DOM 3000 // DUE3DOM for Arduino DUE @@ -292,178 +307,219 @@ #define BOARD_KRATOS32 3027 // K.3D Kratos32 (Arduino Due Shield) // -// SAM3X8C ARM Cortex M3 +// SAM3X8C ARM Cortex-M3 // #define BOARD_PRINTRBOARD_G2 3100 // Printrboard G2 #define BOARD_ADSK 3101 // Arduino DUE Shield Kit (ADSK) +// +// STM32 ARM Cortex-M0+ +// + +#define BOARD_BTT_EBB42_V1_1 4000 // BigTreeTech EBB42 V1.1 (STM32G0B1CB) +#define BOARD_BTT_SKR_MINI_E3_V3_0 4001 // BigTreeTech SKR Mini E3 V3.0 (STM32G0B0RE / STM32G0B1RE) +#define BOARD_BTT_MANTA_E3_EZ_V1_0 4002 // BigTreeTech Manta E3 EZ V1.0 (STM32G0B1RE) +#define BOARD_BTT_MANTA_M4P_V2_1 4003 // BigTreeTech Manta M4P V2.1 (STM32G0B0RE) +#define BOARD_BTT_MANTA_M5P_V1_0 4004 // BigTreeTech Manta M5P V1.0 (STM32G0B1RE) +#define BOARD_BTT_MANTA_M8P_V1_0 4005 // BigTreeTech Manta M8P V1.0 (STM32G0B1VE) +#define BOARD_BTT_MANTA_M8P_V1_1 4006 // BigTreeTech Manta M8P V1.1 (STM32G0B1VE) + // // STM32 ARM Cortex-M3 // -#define BOARD_MALYAN_M200_V2 4000 // STM32F070CB controller -#define BOARD_MALYAN_M300 4001 // STM32F070-based delta -#define BOARD_STM32F103RE 4002 // STM32F103RE Libmaple-based STM32F1 controller -#define BOARD_MALYAN_M200 4003 // STM32C8 Libmaple-based STM32F1 controller -#define BOARD_STM3R_MINI 4004 // STM32F103RE Libmaple-based STM32F1 controller -#define BOARD_GTM32_PRO_VB 4005 // STM32F103VE controller -#define BOARD_GTM32_MINI 4006 // STM32F103VE controller -#define BOARD_GTM32_MINI_A30 4007 // STM32F103VE controller -#define BOARD_GTM32_REV_B 4008 // STM32F103VE controller -#define BOARD_MORPHEUS 4009 // STM32F103C8 / STM32F103CB Libmaple-based STM32F1 controller -#define BOARD_CHITU3D 4010 // Chitu3D (STM32F103RE) -#define BOARD_MKS_ROBIN 4011 // MKS Robin (STM32F103ZE) -#define BOARD_MKS_ROBIN_MINI 4012 // MKS Robin Mini (STM32F103VE) -#define BOARD_MKS_ROBIN_NANO 4013 // MKS Robin Nano (STM32F103VE) -#define BOARD_MKS_ROBIN_NANO_V2 4014 // MKS Robin Nano V2 (STM32F103VE) -#define BOARD_MKS_ROBIN_LITE 4015 // MKS Robin Lite/Lite2 (STM32F103RC) -#define BOARD_MKS_ROBIN_LITE3 4016 // MKS Robin Lite3 (STM32F103RC) -#define BOARD_MKS_ROBIN_PRO 4017 // MKS Robin Pro (STM32F103ZE) -#define BOARD_MKS_ROBIN_E3 4018 // MKS Robin E3 (STM32F103RC) -#define BOARD_MKS_ROBIN_E3_V1_1 4019 // MKS Robin E3 V1.1 (STM32F103RC) -#define BOARD_MKS_ROBIN_E3D 4020 // MKS Robin E3D (STM32F103RC) -#define BOARD_MKS_ROBIN_E3D_V1_1 4021 // MKS Robin E3D V1.1 (STM32F103RC) -#define BOARD_MKS_ROBIN_E3P 4022 // MKS Robin E3p (STM32F103VE) -#define BOARD_BTT_SKR_MINI_V1_1 4023 // BigTreeTech SKR Mini v1.1 (STM32F103RC) -#define BOARD_BTT_SKR_MINI_E3_V1_0 4024 // BigTreeTech SKR Mini E3 (STM32F103RC) -#define BOARD_BTT_SKR_MINI_E3_V1_2 4025 // BigTreeTech SKR Mini E3 V1.2 (STM32F103RC) -#define BOARD_BTT_SKR_MINI_E3_V2_0 4026 // BigTreeTech SKR Mini E3 V2.0 (STM32F103RC / STM32F103RE) -#define BOARD_BTT_SKR_MINI_E3_V3_0 4027 // BigTreeTech SKR Mini E3 V3.0 (STM32G0B1RE) -#define BOARD_BTT_SKR_MINI_E3_V3_0_1 4028 // BigTreeTech SKR Mini E3 V3.0.1 (STM32F401RC) -#define BOARD_BTT_SKR_MINI_MZ_V1_0 4029 // BigTreeTech SKR Mini MZ V1.0 (STM32F103RC) -#define BOARD_BTT_SKR_E3_DIP 4030 // BigTreeTech SKR E3 DIP V1.0 (STM32F103RC / STM32F103RE) -#define BOARD_BTT_SKR_CR6 4031 // BigTreeTech SKR CR6 v1.0 (STM32F103RE) -#define BOARD_JGAURORA_A5S_A1 4032 // JGAurora A5S A1 (STM32F103ZE) -#define BOARD_FYSETC_AIO_II 4033 // FYSETC AIO_II (STM32F103RC) -#define BOARD_FYSETC_CHEETAH 4034 // FYSETC Cheetah (STM32F103RC) -#define BOARD_FYSETC_CHEETAH_V12 4035 // FYSETC Cheetah V1.2 (STM32F103RC) -#define BOARD_LONGER3D_LK 4036 // Longer3D LK1/2 - Alfawise U20/U20+/U30 (STM32F103VE) -#define BOARD_CCROBOT_MEEB_3DP 4037 // ccrobot-online.com MEEB_3DP (STM32F103RC) -#define BOARD_CHITU3D_V5 4038 // Chitu3D TronXY X5SA V5 Board (STM32F103ZE) -#define BOARD_CHITU3D_V6 4039 // Chitu3D TronXY X5SA V6 Board (STM32F103ZE) -#define BOARD_CHITU3D_V9 4040 // Chitu3D TronXY X5SA V9 Board (STM32F103ZE) -#define BOARD_CREALITY_V4 4041 // Creality v4.x (STM32F103RC / STM32F103RE) -#define BOARD_CREALITY_V422 4042 // Creality v4.2.2 (STM32F103RC / STM32F103RE) -#define BOARD_CREALITY_V423 4043 // Creality v4.2.3 (STM32F103RC / STM32F103RE) -#define BOARD_CREALITY_V425 4044 // Creality v4.2.5 (STM32F103RC / STM32F103RE) -#define BOARD_CREALITY_V427 4045 // Creality v4.2.7 (STM32F103RC / STM32F103RE) -#define BOARD_CREALITY_V4210 4046 // Creality v4.2.10 (STM32F103RC / STM32F103RE) as found in the CR-30 -#define BOARD_CREALITY_V431 4047 // Creality v4.3.1 (STM32F103RC / STM32F103RE) -#define BOARD_CREALITY_V431_A 4048 // Creality v4.3.1a (STM32F103RC / STM32F103RE) -#define BOARD_CREALITY_V431_B 4049 // Creality v4.3.1b (STM32F103RC / STM32F103RE) -#define BOARD_CREALITY_V431_C 4050 // Creality v4.3.1c (STM32F103RC / STM32F103RE) -#define BOARD_CREALITY_V431_D 4051 // Creality v4.3.1d (STM32F103RC / STM32F103RE) -#define BOARD_CREALITY_V452 4052 // Creality v4.5.2 (STM32F103RC / STM32F103RE) -#define BOARD_CREALITY_V453 4053 // Creality v4.5.3 (STM32F103RC / STM32F103RE) -#define BOARD_CREALITY_V521 4054 // Creality v5.2.1 (STM32F103VE) as found in the SV04 -#define BOARD_CREALITY_V24S1 4055 // Creality v2.4.S1 (STM32F103RC / STM32F103RE) v101 as found in the Ender-7 -#define BOARD_CREALITY_V24S1_301 4056 // Creality v2.4.S1_301 (STM32F103RC / STM32F103RE) v301 as found in the Ender-3 S1 -#define BOARD_CREALITY_V25S1 4057 // Creality v2.5.S1 (STM32F103RE) as found in the CR-10 Smart Pro -#define BOARD_TRIGORILLA_PRO 4058 // Trigorilla Pro (STM32F103ZE) -#define BOARD_FLY_MINI 4059 // FLYmaker FLY MINI (STM32F103RC) -#define BOARD_FLSUN_HISPEED 4060 // FLSUN HiSpeedV1 (STM32F103VE) -#define BOARD_BEAST 4061 // STM32F103RE Libmaple-based controller -#define BOARD_MINGDA_MPX_ARM_MINI 4062 // STM32F103ZE Mingda MD-16 -#define BOARD_GTM32_PRO_VD 4063 // STM32F103VE controller -#define BOARD_ZONESTAR_ZM3E2 4064 // Zonestar ZM3E2 (STM32F103RC) -#define BOARD_ZONESTAR_ZM3E4 4065 // Zonestar ZM3E4 V1 (STM32F103VC) -#define BOARD_ZONESTAR_ZM3E4V2 4066 // Zonestar ZM3E4 V2 (STM32F103VC) -#define BOARD_ERYONE_ERY32_MINI 4067 // Eryone Ery32 mini (STM32F103VE) -#define BOARD_PANDA_PI_V29 4068 // Panda Pi V2.9 - Standalone (STM32F103RC) +#define BOARD_MALYAN_M200_V2 5000 // STM32F070CB controller +#define BOARD_MALYAN_M300 5001 // STM32F070-based delta +#define BOARD_STM32F103RE 5002 // STM32F103RE Libmaple-based STM32F1 controller +#define BOARD_MALYAN_M200 5003 // STM32C8 Libmaple-based STM32F1 controller +#define BOARD_STM3R_MINI 5004 // STM32F103RE Libmaple-based STM32F1 controller +#define BOARD_GTM32_PRO_VB 5005 // STM32F103VE controller +#define BOARD_GTM32_MINI 5006 // STM32F103VE controller +#define BOARD_GTM32_MINI_A30 5007 // STM32F103VE controller +#define BOARD_GTM32_REV_B 5008 // STM32F103VE controller +#define BOARD_MORPHEUS 5009 // STM32F103C8 / STM32F103CB Libmaple-based STM32F1 controller +#define BOARD_CHITU3D 5010 // Chitu3D (STM32F103RE) +#define BOARD_MKS_ROBIN 5011 // MKS Robin (STM32F103ZE) +#define BOARD_MKS_ROBIN_MINI 5012 // MKS Robin Mini (STM32F103VE) +#define BOARD_MKS_ROBIN_NANO 5013 // MKS Robin Nano (STM32F103VE) +#define BOARD_MKS_ROBIN_NANO_V2 5014 // MKS Robin Nano V2 (STM32F103VE) +#define BOARD_MKS_ROBIN_LITE 5015 // MKS Robin Lite/Lite2 (STM32F103RC) +#define BOARD_MKS_ROBIN_LITE3 5016 // MKS Robin Lite3 (STM32F103RC) +#define BOARD_MKS_ROBIN_PRO 5017 // MKS Robin Pro (STM32F103ZE) +#define BOARD_MKS_ROBIN_E3 5018 // MKS Robin E3 (STM32F103RC) +#define BOARD_MKS_ROBIN_E3_V1_1 5019 // MKS Robin E3 V1.1 (STM32F103RC) +#define BOARD_MKS_ROBIN_E3D 5020 // MKS Robin E3D (STM32F103RC) +#define BOARD_MKS_ROBIN_E3D_V1_1 5021 // MKS Robin E3D V1.1 (STM32F103RC) +#define BOARD_MKS_ROBIN_E3P 5022 // MKS Robin E3P (STM32F103VE) +#define BOARD_BTT_SKR_MINI_V1_1 5023 // BigTreeTech SKR Mini v1.1 (STM32F103RC) +#define BOARD_BTT_SKR_MINI_E3_V1_0 5024 // BigTreeTech SKR Mini E3 (STM32F103RC) +#define BOARD_BTT_SKR_MINI_E3_V1_2 5025 // BigTreeTech SKR Mini E3 V1.2 (STM32F103RC) +#define BOARD_BTT_SKR_MINI_E3_V2_0 5026 // BigTreeTech SKR Mini E3 V2.0 (STM32F103RC / STM32F103RE) +#define BOARD_BTT_SKR_MINI_MZ_V1_0 5027 // BigTreeTech SKR Mini MZ V1.0 (STM32F103RC) +#define BOARD_BTT_SKR_E3_DIP 5028 // BigTreeTech SKR E3 DIP V1.0 (STM32F103RC / STM32F103RE) +#define BOARD_BTT_SKR_CR6 5029 // BigTreeTech SKR CR6 v1.0 (STM32F103RE) +#define BOARD_JGAURORA_A5S_A1 5030 // JGAurora A5S A1 (STM32F103ZE) +#define BOARD_FYSETC_AIO_II 5031 // FYSETC AIO_II (STM32F103RC) +#define BOARD_FYSETC_CHEETAH 5032 // FYSETC Cheetah (STM32F103RC) +#define BOARD_FYSETC_CHEETAH_V12 5033 // FYSETC Cheetah V1.2 (STM32F103RC) +#define BOARD_LONGER3D_LK 5034 // Longer3D LK1/2 - Alfawise U20/U20+/U30 (STM32F103VE) +#define BOARD_CCROBOT_MEEB_3DP 5035 // ccrobot-online.com MEEB_3DP (STM32F103RC) +#define BOARD_CHITU3D_V5 5036 // Chitu3D TronXY X5SA V5 Board (STM32F103ZE) +#define BOARD_CHITU3D_V6 5037 // Chitu3D TronXY X5SA V6 Board (STM32F103ZE) +#define BOARD_CHITU3D_V9 5038 // Chitu3D TronXY X5SA V9 Board (STM32F103ZE) +#define BOARD_CREALITY_V4 5039 // Creality v4.x (STM32F103RC / STM32F103RE) +#define BOARD_CREALITY_V422 5040 // Creality v4.2.2 (STM32F103RC / STM32F103RE) +#define BOARD_CREALITY_V423 5041 // Creality v4.2.3 (STM32F103RC / STM32F103RE) +#define BOARD_CREALITY_V425 5042 // Creality v4.2.5 (STM32F103RC / STM32F103RE) +#define BOARD_CREALITY_V427 5043 // Creality v4.2.7 (STM32F103RC / STM32F103RE) +#define BOARD_CREALITY_V4210 5044 // Creality v4.2.10 (STM32F103RC / STM32F103RE) as found in the CR-30 +#define BOARD_CREALITY_V431 5045 // Creality v4.3.1 (STM32F103RC / STM32F103RE) +#define BOARD_CREALITY_V431_A 5046 // Creality v4.3.1a (STM32F103RC / STM32F103RE) +#define BOARD_CREALITY_V431_B 5047 // Creality v4.3.1b (STM32F103RC / STM32F103RE) +#define BOARD_CREALITY_V431_C 5048 // Creality v4.3.1c (STM32F103RC / STM32F103RE) +#define BOARD_CREALITY_V431_D 5049 // Creality v4.3.1d (STM32F103RC / STM32F103RE) +#define BOARD_CREALITY_V452 5050 // Creality v4.5.2 (STM32F103RC / STM32F103RE) +#define BOARD_CREALITY_V453 5051 // Creality v4.5.3 (STM32F103RC / STM32F103RE) +#define BOARD_CREALITY_V521 5052 // Creality v5.2.1 (STM32F103VE) as found in the SV04 +#define BOARD_CREALITY_V24S1 5053 // Creality v2.4.S1 (STM32F103RC / STM32F103RE) v101 as found in the Ender-7 +#define BOARD_CREALITY_V24S1_301 5054 // Creality v2.4.S1_301 (STM32F103RC / STM32F103RE) v301 as found in the Ender-3 S1 +#define BOARD_CREALITY_V25S1 5055 // Creality v2.5.S1 (STM32F103RE) as found in the CR-10 Smart Pro +#define BOARD_TRIGORILLA_PRO 5056 // Trigorilla Pro (STM32F103ZE) +#define BOARD_FLY_MINI 5057 // FLYmaker FLY MINI (STM32F103RC) +#define BOARD_FLSUN_HISPEED 5058 // FLSUN HiSpeedV1 (STM32F103VE) +#define BOARD_BEAST 5059 // STM32F103RE Libmaple-based controller +#define BOARD_MINGDA_MPX_ARM_MINI 5060 // STM32F103ZE Mingda MD-16 +#define BOARD_GTM32_PRO_VD 5061 // STM32F103VE controller +#define BOARD_ZONESTAR_ZM3E2 5062 // Zonestar ZM3E2 (STM32F103RC) +#define BOARD_ZONESTAR_ZM3E4 5063 // Zonestar ZM3E4 V1 (STM32F103VC) +#define BOARD_ZONESTAR_ZM3E4V2 5064 // Zonestar ZM3E4 V2 (STM32F103VC) +#define BOARD_ERYONE_ERY32_MINI 5065 // Eryone Ery32 mini (STM32F103VE) +#define BOARD_PANDA_PI_V29 5066 // Panda Pi V2.9 - Standalone (STM32F103RC) +#define BOARD_SOVOL_V131 5067 // Sovol V1.3.1 (GD32F103RE) +#define BOARD_TRIGORILLA_V006 5068 // Trigorilla V0.0.6 (GD32F103RE) +#define BOARD_KEDI_CONTROLLER_V1_2 5069 // EDUTRONICS Kedi Controller V1.2 (STM32F103RC) +#define BOARD_MD_D301 5070 // Mingda D2 DZ301 V1.0 (STM32F103ZE) +#define BOARD_VOXELAB_AQUILA 5071 // Voxelab Aquila V1.0.0/V1.0.1 (GD32F103RC / N32G455RE / STM32F103RE) +#define BOARD_SPRINGER_CONTROLLER 5072 // ORCA 3D SPRINGER Modular Controller (STM32F103VC) // // ARM Cortex-M4F // -#define BOARD_TEENSY31_32 4100 // Teensy3.1 and Teensy3.2 -#define BOARD_TEENSY35_36 4101 // Teensy3.5 and Teensy3.6 +#define BOARD_TEENSY31_32 5100 // Teensy3.1 and Teensy3.2 +#define BOARD_TEENSY35_36 5101 // Teensy3.5 and Teensy3.6 // // STM32 ARM Cortex-M4F // -#define BOARD_ARMED 4200 // Arm'ed STM32F4-based controller -#define BOARD_RUMBA32_V1_0 4201 // RUMBA32 STM32F446VE based controller from Aus3D -#define BOARD_RUMBA32_V1_1 4202 // RUMBA32 STM32F446VE based controller from Aus3D -#define BOARD_RUMBA32_MKS 4203 // RUMBA32 STM32F446VE based controller from Makerbase -#define BOARD_RUMBA32_BTT 4204 // RUMBA32 STM32F446VE based controller from BIGTREETECH -#define BOARD_BLACK_STM32F407VE 4205 // BLACK_STM32F407VE -#define BOARD_BLACK_STM32F407ZE 4206 // BLACK_STM32F407ZE -#define BOARD_BTT_SKR_PRO_V1_1 4207 // BigTreeTech SKR Pro v1.1 (STM32F407ZG) -#define BOARD_BTT_SKR_PRO_V1_2 4208 // BigTreeTech SKR Pro v1.2 (STM32F407ZG) -#define BOARD_BTT_BTT002_V1_0 4209 // BigTreeTech BTT002 v1.0 (STM32F407VG) -#define BOARD_BTT_E3_RRF 4210 // BigTreeTech E3 RRF (STM32F407VG) -#define BOARD_BTT_SKR_V2_0_REV_A 4211 // BigTreeTech SKR v2.0 Rev A (STM32F407VG) -#define BOARD_BTT_SKR_V2_0_REV_B 4212 // BigTreeTech SKR v2.0 Rev B (STM32F407VG/STM32F429VG) -#define BOARD_BTT_GTR_V1_0 4213 // BigTreeTech GTR v1.0 (STM32F407IGT) -#define BOARD_BTT_OCTOPUS_V1_0 4214 // BigTreeTech Octopus v1.0 (STM32F446ZE) -#define BOARD_BTT_OCTOPUS_V1_1 4215 // BigTreeTech Octopus v1.1 (STM32F446ZE) -#define BOARD_BTT_OCTOPUS_PRO_V1_0 4216 // BigTreeTech Octopus Pro v1.0 (STM32F446ZE / STM32F429ZG) -#define BOARD_LERDGE_K 4217 // Lerdge K (STM32F407ZG) -#define BOARD_LERDGE_S 4218 // Lerdge S (STM32F407VE) -#define BOARD_LERDGE_X 4219 // Lerdge X (STM32F407VE) -#define BOARD_VAKE403D 4220 // VAkE 403D (STM32F446VE) -#define BOARD_FYSETC_S6 4221 // FYSETC S6 (STM32F446VE) -#define BOARD_FYSETC_S6_V2_0 4222 // FYSETC S6 v2.0 (STM32F446VE) -#define BOARD_FYSETC_SPIDER 4223 // FYSETC Spider (STM32F446VE) -#define BOARD_FLYF407ZG 4224 // FLYmaker FLYF407ZG (STM32F407ZG) -#define BOARD_MKS_ROBIN2 4225 // MKS_ROBIN2 (STM32F407ZE) -#define BOARD_MKS_ROBIN_PRO_V2 4226 // MKS Robin Pro V2 (STM32F407VE) -#define BOARD_MKS_ROBIN_NANO_V3 4227 // MKS Robin Nano V3 (STM32F407VG) -#define BOARD_MKS_ROBIN_NANO_V3_1 4228 // MKS Robin Nano V3.1 (STM32F407VE) -#define BOARD_MKS_MONSTER8_V1 4229 // MKS Monster8 V1 (STM32F407VE) -#define BOARD_MKS_MONSTER8_V2 4230 // MKS Monster8 V2 (STM32F407VE) -#define BOARD_ANET_ET4 4231 // ANET ET4 V1.x (STM32F407VG) -#define BOARD_ANET_ET4P 4232 // ANET ET4P V1.x (STM32F407VG) -#define BOARD_FYSETC_CHEETAH_V20 4233 // FYSETC Cheetah V2.0 (STM32F401RC) -#define BOARD_TH3D_EZBOARD_V2 4234 // TH3D EZBoard v2.0 (STM32F405RG) -#define BOARD_OPULO_LUMEN_REV3 4235 // Opulo Lumen PnP Controller REV3 (STM32F407VE / STM32F407VG) -#define BOARD_MKS_ROBIN_NANO_V1_3_F4 4236 // MKS Robin Nano V1.3 and MKS Robin Nano-S V1.3 (STM32F407VE) -#define BOARD_MKS_EAGLE 4237 // MKS Eagle (STM32F407VE) -#define BOARD_ARTILLERY_RUBY 4238 // Artillery Ruby (STM32F401RC) -#define BOARD_FYSETC_SPIDER_V2_2 4239 // FYSETC Spider V2.2 (STM32F446VE) -#define BOARD_CREALITY_V24S1_301F4 4240 // Creality v2.4.S1_301F4 (STM32F401RC) as found in the Ender-3 S1 F4 -#define BOARD_OPULO_LUMEN_REV4 4241 // Opulo Lumen PnP Controller REV4 (STM32F407VE / STM32F407VG) -#define BOARD_FYSETC_SPIDER_KING407 4242 // FYSETC Spider King407 (STM32F407ZG) -#define BOARD_MKS_SKIPR_V1 4243 // MKS SKIPR v1.0 all-in-one board (STM32F407VE) -#define BOARD_TRONXY_V10 4244 // TRONXY V10 (STM32F446ZE) +#define BOARD_ARMED 5200 // Arm'ed STM32F4-based controller +#define BOARD_RUMBA32_V1_0 5201 // RUMBA32 STM32F446VE based controller from Aus3D +#define BOARD_RUMBA32_V1_1 5202 // RUMBA32 STM32F446VE based controller from Aus3D +#define BOARD_RUMBA32_MKS 5203 // RUMBA32 STM32F446VE based controller from Makerbase +#define BOARD_RUMBA32_BTT 5204 // RUMBA32 STM32F446VE based controller from BIGTREETECH +#define BOARD_BLACK_STM32F407VE 5205 // BLACK_STM32F407VE +#define BOARD_BLACK_STM32F407ZE 5206 // BLACK_STM32F407ZE +#define BOARD_BTT_SKR_MINI_E3_V3_0_1 5207 // BigTreeTech SKR Mini E3 V3.0.1 (STM32F401RC) +#define BOARD_BTT_SKR_PRO_V1_1 5208 // BigTreeTech SKR Pro v1.1 (STM32F407ZG) +#define BOARD_BTT_SKR_PRO_V1_2 5209 // BigTreeTech SKR Pro v1.2 (STM32F407ZG) +#define BOARD_BTT_BTT002_V1_0 5210 // BigTreeTech BTT002 v1.0 (STM32F407VG) +#define BOARD_BTT_E3_RRF 5211 // BigTreeTech E3 RRF (STM32F407VG) +#define BOARD_BTT_SKR_V2_0_REV_A 5212 // BigTreeTech SKR v2.0 Rev A (STM32F407VG) +#define BOARD_BTT_SKR_V2_0_REV_B 5213 // BigTreeTech SKR v2.0 Rev B (STM32F407VG/STM32F429VG) +#define BOARD_BTT_GTR_V1_0 5214 // BigTreeTech GTR v1.0 (STM32F407IGT) +#define BOARD_BTT_OCTOPUS_V1_0 5215 // BigTreeTech Octopus v1.0 (STM32F446ZE) +#define BOARD_BTT_OCTOPUS_V1_1 5216 // BigTreeTech Octopus v1.1 (STM32F446ZE) +#define BOARD_BTT_OCTOPUS_PRO_V1_0 5217 // BigTreeTech Octopus Pro v1.0 (STM32F446ZE / STM32F429ZG) +#define BOARD_LERDGE_K 5218 // Lerdge K (STM32F407ZG) +#define BOARD_LERDGE_S 5219 // Lerdge S (STM32F407VE) +#define BOARD_LERDGE_X 5220 // Lerdge X (STM32F407VE) +#define BOARD_FYSETC_S6 5221 // FYSETC S6 (STM32F446VE) +#define BOARD_FYSETC_S6_V2_0 5222 // FYSETC S6 v2.0 (STM32F446VE) +#define BOARD_FYSETC_SPIDER 5223 // FYSETC Spider (STM32F446VE) +#define BOARD_FLYF407ZG 5224 // FLYmaker FLYF407ZG (STM32F407ZG) +#define BOARD_MKS_ROBIN2 5225 // MKS Robin2 V1.0 (STM32F407ZE) +#define BOARD_MKS_ROBIN_PRO_V2 5226 // MKS Robin Pro V2 (STM32F407VE) +#define BOARD_MKS_ROBIN_NANO_V3 5227 // MKS Robin Nano V3 (STM32F407VG) +#define BOARD_MKS_ROBIN_NANO_V3_1 5228 // MKS Robin Nano V3.1 (STM32F407VE) +#define BOARD_MKS_MONSTER8_V1 5229 // MKS Monster8 V1 (STM32F407VE) +#define BOARD_MKS_MONSTER8_V2 5230 // MKS Monster8 V2 (STM32F407VE) +#define BOARD_ANET_ET4 5231 // ANET ET4 V1.x (STM32F407VG) +#define BOARD_ANET_ET4P 5232 // ANET ET4P V1.x (STM32F407VG) +#define BOARD_FYSETC_CHEETAH_V20 5233 // FYSETC Cheetah V2.0 (STM32F401RC) +#define BOARD_TH3D_EZBOARD_V2 5234 // TH3D EZBoard v2.0 (STM32F405RG) +#define BOARD_OPULO_LUMEN_REV3 5235 // Opulo Lumen PnP Controller REV3 (STM32F407VE / STM32F407VG) +#define BOARD_MKS_ROBIN_NANO_V1_3_F4 5236 // MKS Robin Nano V1.3 and MKS Robin Nano-S V1.3 (STM32F407VE) +#define BOARD_MKS_EAGLE 5237 // MKS Eagle (STM32F407VE) +#define BOARD_ARTILLERY_RUBY 5238 // Artillery Ruby (STM32F401RC) +#define BOARD_FYSETC_SPIDER_V2_2 5239 // FYSETC Spider V2.2 (STM32F446VE) +#define BOARD_CREALITY_V24S1_301F4 5240 // Creality v2.4.S1_301F4 (STM32F401RC) as found in the Ender-3 S1 F4 +#define BOARD_CREALITY_CR4NTXXC10 5241 // Creality E3 Free-runs Silent Motherboard (STM32F401RET6) +#define BOARD_OPULO_LUMEN_REV4 5242 // Opulo Lumen PnP Controller REV4 (STM32F407VE / STM32F407VG) +#define BOARD_FYSETC_SPIDER_KING407 5243 // FYSETC Spider King407 (STM32F407ZG) +#define BOARD_MKS_SKIPR_V1 5244 // MKS SKIPR v1.0 all-in-one board (STM32F407VE) +#define BOARD_TRONXY_V10 5245 // TRONXY V10 (STM32F446ZE) +#define BOARD_CREALITY_F401RE 5246 // Creality CR4NS200141C13 (STM32F401RE) as found in the Ender-5 S1 +#define BOARD_BLACKPILL_CUSTOM 5247 // Custom board based on STM32F401CDU6. +#define BOARD_I3DBEEZ9_V1 5248 // I3DBEEZ9 V1 (STM32F407ZG) +#define BOARD_MELLOW_FLY_E3_V2 5249 // Mellow Fly E3 V2 (STM32F407VG) +#define BOARD_FYSETC_CHEETAH_V30 5250 // FYSETC Cheetah V3.0 (STM32F446RC) +#define BOARD_BLACKBEEZMINI_V1 5251 // BlackBeezMini V1 (STM32F401CCU6) // -// ARM Cortex M7 +// ARM Cortex-M7 // -#define BOARD_REMRAM_V1 5000 // RemRam v1 -#define BOARD_TEENSY41 5001 // Teensy 4.1 -#define BOARD_T41U5XBB 5002 // T41U5XBB Teensy 4.1 breakout board -#define BOARD_NUCLEO_F767ZI 5003 // ST NUCLEO-F767ZI Dev Board -#define BOARD_BTT_SKR_SE_BX_V2 5004 // BigTreeTech SKR SE BX V2.0 (STM32H743II) -#define BOARD_BTT_SKR_SE_BX_V3 5005 // BigTreeTech SKR SE BX V3.0 (STM32H743II) -#define BOARD_BTT_SKR_V3_0 5006 // BigTreeTech SKR V3.0 (STM32H743VG) -#define BOARD_BTT_SKR_V3_0_EZ 5007 // BigTreeTech SKR V3.0 EZ (STM32H743VG) +#define BOARD_REMRAM_V1 6000 // RemRam v1 +#define BOARD_TEENSY41 6001 // Teensy 4.1 +#define BOARD_T41U5XBB 6002 // T41U5XBB Teensy 4.1 breakout board +#define BOARD_NUCLEO_F767ZI 6003 // ST NUCLEO-F767ZI Dev Board +#define BOARD_BTT_SKR_SE_BX_V2 6004 // BigTreeTech SKR SE BX V2.0 (STM32H743II) +#define BOARD_BTT_SKR_SE_BX_V3 6005 // BigTreeTech SKR SE BX V3.0 (STM32H743II) +#define BOARD_BTT_SKR_V3_0 6006 // BigTreeTech SKR V3.0 (STM32H743VI / STM32H723VG) +#define BOARD_BTT_SKR_V3_0_EZ 6007 // BigTreeTech SKR V3.0 EZ (STM32H743VI / STM32H723VG) +#define BOARD_BTT_OCTOPUS_MAX_EZ_V1_0 6008 // BigTreeTech Octopus Max EZ V1.0 (STM32H723ZE) +#define BOARD_BTT_OCTOPUS_PRO_V1_0_1 6009 // BigTreeTech Octopus Pro v1.0.1 (STM32H723ZE) +#define BOARD_BTT_OCTOPUS_PRO_V1_1 6010 // BigTreeTech Octopus Pro v1.1 (STM32H723ZE) +#define BOARD_BTT_MANTA_M8P_V2_0 6011 // BigTreeTech Manta M8P V2.0 (STM32H723ZE) +#define BOARD_BTT_KRAKEN_V1_0 6012 // BigTreeTech Kraken v1.0 (STM32H723ZG) // // Espressif ESP32 WiFi // -#define BOARD_ESPRESSIF_ESP32 6000 // Generic ESP32 -#define BOARD_MRR_ESPA 6001 // MRR ESPA based on ESP32 (native pins only) -#define BOARD_MRR_ESPE 6002 // MRR ESPE based on ESP32 (with I2S stepper stream) -#define BOARD_E4D_BOX 6003 // E4d@BOX -#define BOARD_RESP32_CUSTOM 6004 // Rutilea ESP32 custom board -#define BOARD_FYSETC_E4 6005 // FYSETC E4 -#define BOARD_PANDA_ZHU 6006 // Panda_ZHU -#define BOARD_PANDA_M4 6007 // Panda_M4 -#define BOARD_MKS_TINYBEE 6008 // MKS TinyBee based on ESP32 (with I2S stepper stream) -#define BOARD_ENWI_ESPNP 6009 // enwi ESPNP based on ESP32 (with I2S stepper stream) +#define BOARD_ESPRESSIF_ESP32 7000 // Generic ESP32 +#define BOARD_MRR_ESPA 7001 // MRR ESPA based on ESP32 (native pins only) +#define BOARD_MRR_ESPE 7002 // MRR ESPE based on ESP32 (with I2S stepper stream) +#define BOARD_E4D_BOX 7003 // E4d@BOX +#define BOARD_RESP32_CUSTOM 7004 // Rutilea ESP32 custom board +#define BOARD_FYSETC_E4 7005 // FYSETC E4 +#define BOARD_PANDA_ZHU 7006 // Panda_ZHU +#define BOARD_PANDA_M4 7007 // Panda_M4 +#define BOARD_MKS_TINYBEE 7008 // MKS TinyBee based on ESP32 (with I2S stepper stream) +#define BOARD_ENWI_ESPNP 7009 // enwi ESPNP based on ESP32 (with I2S stepper stream) +#define BOARD_GODI_CONTROLLER_V1_0 7010 // Godi Controller based on ESP32 32-Bit V1.0 +#define BOARD_MM_JOKER 7011 // MagicMaker JOKER based on ESP32 (with I2S stepper stream) // -// SAMD51 ARM Cortex M4 +// SAMD51 ARM Cortex-M4 // -#define BOARD_AGCM4_RAMPS_144 6100 // RAMPS 1.4.4 -#define BOARD_BRICOLEMON_V1_0 6101 // Bricolemon -#define BOARD_BRICOLEMON_LITE_V1_0 6102 // Bricolemon Lite +#define BOARD_AGCM4_RAMPS_144 7100 // RAMPS 1.4.4 +#define BOARD_BRICOLEMON_V1_0 7101 // Bricolemon +#define BOARD_BRICOLEMON_LITE_V1_0 7102 // Bricolemon Lite + +// +// SAMD21 ARM Cortex-M4 +// + +#define BOARD_MINITRONICS20 7103 // Minitronics v2.0 + +// +// HC32 ARM Cortex-M4 +// +#define BOARD_AQUILA_V101 7200 // Voxelab Aquila V1.0.0/V1.0.1/V1.0.2/V1.0.3 as found in the Voxelab Aquila X2 and C2 // // Custom board @@ -475,7 +531,7 @@ // Simulations // -#define BOARD_LINUX_RAMPS 9999 +#define BOARD_SIMULATED 9999 #define _MB_1(B) (defined(BOARD_##B) && MOTHERBOARD==BOARD_##B) #define MB(V...) DO(MB,||,V) diff --git a/Marlin/src/core/debug_out.h b/Marlin/src/core/debug_out.h index eb1c91e507..8f14f05c79 100644 --- a/Marlin/src/core/debug_out.h +++ b/Marlin/src/core/debug_out.h @@ -29,23 +29,18 @@ #undef DEBUG_SECTION #undef DEBUG_ECHO_START #undef DEBUG_ERROR_START +#undef DEBUG_WARN_START #undef DEBUG_CHAR #undef DEBUG_ECHO -#undef DEBUG_DECIMAL -#undef DEBUG_ECHO_F #undef DEBUG_ECHOLN #undef DEBUG_ECHOPGM #undef DEBUG_ECHOLNPGM -#undef DEBUG_ECHOF -#undef DEBUG_ECHOLNF #undef DEBUG_ECHOPGM_P #undef DEBUG_ECHOLNPGM_P -#undef DEBUG_ECHOPAIR_F -#undef DEBUG_ECHOPAIR_F_P -#undef DEBUG_ECHOLNPAIR_F -#undef DEBUG_ECHOLNPAIR_F_P #undef DEBUG_ECHO_MSG #undef DEBUG_ERROR_MSG +#undef DEBUG_WARN_MSG +#undef DEBUG_ECHO_TERNARY #undef DEBUG_EOL #undef DEBUG_FLUSH #undef DEBUG_POS @@ -60,25 +55,20 @@ #define DEBUG_ECHO_START SERIAL_ECHO_START #define DEBUG_ERROR_START SERIAL_ERROR_START + #define DEBUG_WARN_START SERIAL_WARN_START #define DEBUG_CHAR SERIAL_CHAR #define DEBUG_ECHO SERIAL_ECHO - #define DEBUG_DECIMAL SERIAL_DECIMAL - #define DEBUG_ECHO_F SERIAL_ECHO_F #define DEBUG_ECHOLN SERIAL_ECHOLN #define DEBUG_ECHOPGM SERIAL_ECHOPGM #define DEBUG_ECHOLNPGM SERIAL_ECHOLNPGM - #define DEBUG_ECHOF SERIAL_ECHOF - #define DEBUG_ECHOLNF SERIAL_ECHOLNF #define DEBUG_ECHOPGM SERIAL_ECHOPGM #define DEBUG_ECHOPGM_P SERIAL_ECHOPGM_P - #define DEBUG_ECHOPAIR_F SERIAL_ECHOPAIR_F - #define DEBUG_ECHOPAIR_F_P SERIAL_ECHOPAIR_F_P #define DEBUG_ECHOLNPGM SERIAL_ECHOLNPGM #define DEBUG_ECHOLNPGM_P SERIAL_ECHOLNPGM_P - #define DEBUG_ECHOLNPAIR_F SERIAL_ECHOLNPAIR_F - #define DEBUG_ECHOLNPAIR_F_P SERIAL_ECHOLNPAIR_F_P #define DEBUG_ECHO_MSG SERIAL_ECHO_MSG #define DEBUG_ERROR_MSG SERIAL_ERROR_MSG + #define DEBUG_WARN_MSG SERIAL_WARN_MSG + #define DEBUG_ECHO_TERNARY SERIAL_ECHO_TERNARY #define DEBUG_EOL SERIAL_EOL #define DEBUG_FLUSH SERIAL_FLUSH #define DEBUG_POS SERIAL_POS @@ -91,23 +81,18 @@ #define DEBUG_SECTION(...) NOOP #define DEBUG_ECHO_START() NOOP #define DEBUG_ERROR_START() NOOP + #define DEBUG_WARN_START() NOOP #define DEBUG_CHAR(...) NOOP #define DEBUG_ECHO(...) NOOP - #define DEBUG_DECIMAL(...) NOOP - #define DEBUG_ECHO_F(...) NOOP #define DEBUG_ECHOLN(...) NOOP #define DEBUG_ECHOPGM(...) NOOP #define DEBUG_ECHOLNPGM(...) NOOP - #define DEBUG_ECHOF(...) NOOP - #define DEBUG_ECHOLNF(...) NOOP #define DEBUG_ECHOPGM_P(...) NOOP #define DEBUG_ECHOLNPGM_P(...) NOOP - #define DEBUG_ECHOPAIR_F(...) NOOP - #define DEBUG_ECHOPAIR_F_P(...) NOOP - #define DEBUG_ECHOLNPAIR_F(...) NOOP - #define DEBUG_ECHOLNPAIR_F_P(...) NOOP #define DEBUG_ECHO_MSG(...) NOOP #define DEBUG_ERROR_MSG(...) NOOP + #define DEBUG_WARN_MSG(...) NOOP + #define DEBUG_ECHO_TERNARY(...) NOOP #define DEBUG_EOL() NOOP #define DEBUG_FLUSH() NOOP #define DEBUG_POS(...) NOOP diff --git a/Marlin/src/core/debug_section.h b/Marlin/src/core/debug_section.h index 6e23d9e4ed..6319515b71 100644 --- a/Marlin/src/core/debug_section.h +++ b/Marlin/src/core/debug_section.h @@ -38,12 +38,9 @@ private: bool debug; void echo_msg(FSTR_P const fpre) { - SERIAL_ECHOF(fpre); - if (the_msg) { - SERIAL_CHAR(' '); - SERIAL_ECHOF(the_msg); - } + SERIAL_ECHO(fpre); + if (the_msg) SERIAL_ECHO(C(' '), the_msg); SERIAL_CHAR(' '); - print_pos(current_position); + print_xyz(xyz_pos_t(current_position)); } }; diff --git a/Marlin/src/core/drivers.h b/Marlin/src/core/drivers.h index 72a7d1f4b7..fce8a5a9b2 100644 --- a/Marlin/src/core/drivers.h +++ b/Marlin/src/core/drivers.h @@ -64,7 +64,7 @@ #define AXIS_DRIVER_TYPE_W(T) _AXIS_DRIVER_TYPE(W,T) #define AXIS_DRIVER_TYPE_X2(T) (HAS_X2_STEPPER && _AXIS_DRIVER_TYPE(X2,T)) -#define AXIS_DRIVER_TYPE_Y2(T) (HAS_DUAL_Y_STEPPERS && _AXIS_DRIVER_TYPE(Y2,T)) +#define AXIS_DRIVER_TYPE_Y2(T) (HAS_Y2_STEPPER && _AXIS_DRIVER_TYPE(Y2,T)) #define AXIS_DRIVER_TYPE_Z2(T) (NUM_Z_STEPPERS >= 2 && _AXIS_DRIVER_TYPE(Z2,T)) #define AXIS_DRIVER_TYPE_Z3(T) (NUM_Z_STEPPERS >= 3 && _AXIS_DRIVER_TYPE(Z3,T)) #define AXIS_DRIVER_TYPE_Z4(T) (NUM_Z_STEPPERS >= 4 && _AXIS_DRIVER_TYPE(Z4,T)) diff --git a/Marlin/src/core/endianness.h b/Marlin/src/core/endianness.h new file mode 100644 index 0000000000..8fa8e40078 --- /dev/null +++ b/Marlin/src/core/endianness.h @@ -0,0 +1,76 @@ +/** + * Marlin 3D Printer Firmware + * Copyright (c) 2023 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] + * + * Based on Sprinter and grbl. + * Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ +#pragma once + +#include "../core/types.h" +#include "../core/macros.h" + +#ifdef __cplusplus + +namespace Endianness { + static constexpr uint32_t _dword = 0x01020304; + static constexpr uint8_t _lsb = (const uint8_t&)_dword; + + static constexpr bool cpuIsLittleEndian = _lsb == 0x04; + static constexpr bool cpuIsBigEndian = _lsb == 0x01; + static_assert(cpuIsLittleEndian ^ cpuIsBigEndian, "Unknown CPU endianness"); + + // constexpr byte swapping for integral types + template static constexpr typename Private::enable_if::value, T>::type swap(T V, T swappedV=(T)0, size_t byteIndex=0) { + return byteIndex == sizeof(T) + ? swappedV + : swap((T)(V >> 8), (swappedV << 8) | (V & (T)0xFF), byteIndex + 1); + } + + // constexpr byte swapping for types derived from integral types (e.g. enums) + template static constexpr typename Private::enable_if< + Private::is_same::type>::value, T>::type swap(T V) { return (T)swap((uint16_t)V); } + template static constexpr typename Private::enable_if< + Private::is_same::type>::value, T>::type swap(T V) { return (T)swap((uint32_t)V); } + template static constexpr typename Private::enable_if< + Private::is_same::type>::value, T>::type swap(T V) { return (T)swap((uint64_t)V); } + + // Generic byte swapping + // CANNOT be used to initialize constexpr declarations + template static constexpr typename Private::enable_if::value && !Private::is_enum::value, T>::type swap(T V) { + union { + T val; + char byte[sizeof(T)]; + } src{}, dst{}; + + src.val = V; + for (uint8_t i = 0; i < sizeof(T); ++i) dst.byte[i] = src.byte[sizeof(T) - i - 1]; + return dst.val; + } + + // Convert to / from known endianness, depending on the host endianness + template static constexpr T toBE(T V) { return cpuIsLittleEndian ? swap(V) : V; } + template static constexpr T toLE(T V) { return cpuIsLittleEndian ? V : swap(V); } + template static constexpr T fromBE(T V) { return cpuIsLittleEndian ? swap(V) : V; } + template static constexpr T fromLE(T V) { return cpuIsLittleEndian ? V : swap(V); } + + // Reads a big/little endian from a pointer and converts it to the host endianness + template static constexpr T fromBE_P(void* V) { return fromBE(*(T*)V); } + template static constexpr T fromLE_P(void* V) { return fromLE(*(T*)V); } +}; + +#endif // __cplusplus diff --git a/Marlin/src/core/language.h b/Marlin/src/core/language.h index 545f9df641..645725237b 100644 --- a/Marlin/src/core/language.h +++ b/Marlin/src/core/language.h @@ -55,6 +55,7 @@ // eu Basque-Euskera // fi Finnish // fr French +// fr_na French without accents (DWIN T5UID1 touchscreen) // gl Galician // hr Croatian // hu Hungarian @@ -153,7 +154,7 @@ #define STR_ERR_ARC_ARGS "G2/G3 bad parameters" #define STR_ERR_PROTECTED_PIN "Protected Pin" #define STR_ERR_M420_FAILED "Failed to enable Bed Leveling" -#define STR_ERR_M428_TOO_FAR "Too far from reference point" +#define STR_ERR_M428_TOO_FAR "Too far from MIN/MAX" #define STR_ERR_M303_DISABLED "PIDTEMP disabled" #define STR_M119_REPORT "Reporting endstop status" #define STR_ON "ON" @@ -192,6 +193,7 @@ #define STR_ERR_LONG_EXTRUDE_STOP " too long extrusion prevented" #define STR_ERR_HOTEND_TOO_COLD "Hotend too cold" #define STR_ERR_EEPROM_WRITE "Error writing to EEPROM!" +#define STR_ERR_EEPROM_CORRUPT "EEPROM Corrupt" #define STR_FILAMENT_CHANGE_HEAT_LCD "Press button to heat nozzle" #define STR_FILAMENT_CHANGE_INSERT_LCD "Insert filament and press button" @@ -229,10 +231,9 @@ #define STR_PID_DEBUG_INPUT ": Input " #define STR_PID_DEBUG_OUTPUT " Output " #define STR_INVALID_EXTRUDER_NUM " - Invalid extruder number !" -#define STR_MPC_AUTOTUNE "MPC Autotune" -#define STR_MPC_AUTOTUNE_START " start for " STR_E -#define STR_MPC_AUTOTUNE_INTERRUPTED " interrupted!" -#define STR_MPC_AUTOTUNE_FINISHED " finished! Put the constants below into Configuration.h" +#define STR_MPC_AUTOTUNE_START "MPC Autotune start for " STR_E +#define STR_MPC_AUTOTUNE_INTERRUPTED "MPC Autotune interrupted!" +#define STR_MPC_AUTOTUNE_FINISHED "MPC Autotune finished! Put the constants below into Configuration.h" #define STR_MPC_COOLING_TO_AMBIENT "Cooling to ambient" #define STR_MPC_HEATING_PAST_200 "Heating to over 200C" #define STR_MPC_MEASURING_AMBIENT "Measuring ambient heatloss at " @@ -242,15 +243,18 @@ #define STR_HEATER_CHAMBER "chamber" #define STR_COOLER "cooler" #define STR_MOTHERBOARD "motherboard" +#define STR_SOC "soc" #define STR_PROBE "probe" #define STR_REDUNDANT "redundant " #define STR_LASER_TEMP "laser temperature" #define STR_STOPPED_HEATER ", system stopped! Heater_ID: " +#define STR_DETECTED_TEMP_B " (temp: " +#define STR_DETECTED_TEMP_E ")" #define STR_REDUNDANCY "Heater switched off. Temperature difference between temp sensors is too high !" #define STR_T_HEATING_FAILED "Heating failed" #define STR_T_THERMAL_RUNAWAY "Thermal Runaway" -#define STR_T_MALFUNCTION "Thermal Malfunction" +#define STR_T_THERMAL_MALFUNCTION "Thermal Malfunction" #define STR_T_MAXTEMP "MAXTEMP triggered" #define STR_T_MINTEMP "MINTEMP triggered" #define STR_ERR_PROBING_FAILED "Probing Failed" @@ -276,9 +280,11 @@ // Settings Report Strings #define STR_Z_AUTO_ALIGN "Z Auto-Align" #define STR_BACKLASH_COMPENSATION "Backlash compensation" +#define STR_FT_MOTION "Fixed-Time Motion" #define STR_S_SEG_PER_SEC "S" #define STR_DELTA_SETTINGS "Delta (L R H S XYZ ABC)" #define STR_SCARA_SETTINGS "SCARA" +#define STR_POLAR_SETTINGS "Polar" #define STR_POLARGRAPH_SETTINGS "Polargraph" #define STR_SCARA_P_T_Z "P T Z" #define STR_ENDSTOP_ADJUSTMENT "Endstop adjustment" @@ -295,6 +301,7 @@ #define STR_CHAMBER_PID "Chamber PID" #define STR_STEPS_PER_UNIT "Steps per unit" #define STR_LINEAR_ADVANCE "Linear Advance" +#define STR_NONLINEAR_EXTRUSION "Nonlinear Extrusion" #define STR_CONTROLLER_FAN "Controller Fan" #define STR_STEPPER_MOTOR_CURRENTS "Stepper motor currents" #define STR_RETRACT_S_F_Z "Retract (S F Z)" @@ -322,10 +329,12 @@ // // Endstop Names used by Endstops::report_states // -#define STR_X_MIN "x_min" -#define STR_X_MAX "x_max" -#define STR_X2_MIN "x2_min" -#define STR_X2_MAX "x2_max" +#if HAS_X_AXIS + #define STR_X_MIN "x_min" + #define STR_X_MAX "x_max" + #define STR_X2_MIN "x2_min" + #define STR_X2_MAX "x2_max" +#endif #if HAS_Y_AXIS #define STR_Y_MIN "y_min" @@ -502,7 +511,7 @@ #define STR_W "" #endif -#if EITHER(HAS_MARLINUI_HD44780, IS_TFTGLCD_PANEL) +#if ANY(HAS_MARLINUI_HD44780, IS_TFTGLCD_PANEL) // Custom characters defined in the first 8 characters of the LCD #define LCD_STR_BEDTEMP "\x00" // Print only as a char. This will have 'unexpected' results when used in a string! diff --git a/Marlin/src/core/macros.h b/Marlin/src/core/macros.h index 3029009c06..784002c769 100644 --- a/Marlin/src/core/macros.h +++ b/Marlin/src/core/macros.h @@ -33,60 +33,16 @@ #define _AXIS(A) (A##_AXIS) -#define _XSTOP_ 0x01 -#define _YSTOP_ 0x02 -#define _ZSTOP_ 0x03 -#define _ISTOP_ 0x04 -#define _JSTOP_ 0x05 -#define _KSTOP_ 0x06 -#define _USTOP_ 0x07 -#define _VSTOP_ 0x08 -#define _WSTOP_ 0x09 -#define _XMIN_ 0x11 -#define _YMIN_ 0x12 -#define _ZMIN_ 0x13 -#define _IMIN_ 0x14 -#define _JMIN_ 0x15 -#define _KMIN_ 0x16 -#define _UMIN_ 0x17 -#define _VMIN_ 0x18 -#define _WMIN_ 0x19 -#define _XMAX_ 0x21 -#define _YMAX_ 0x22 -#define _ZMAX_ 0x23 -#define _IMAX_ 0x24 -#define _JMAX_ 0x25 -#define _KMAX_ 0x26 -#define _UMAX_ 0x27 -#define _VMAX_ 0x28 -#define _WMAX_ 0x29 -#define _XDIAG_ 0x31 -#define _YDIAG_ 0x32 -#define _ZDIAG_ 0x33 -#define _IDIAG_ 0x34 -#define _JDIAG_ 0x35 -#define _KDIAG_ 0x36 -#define _UDIAG_ 0x37 -#define _VDIAG_ 0x38 -#define _WDIAG_ 0x39 -#define _E0DIAG_ 0xE0 -#define _E1DIAG_ 0xE1 -#define _E2DIAG_ 0xE2 -#define _E3DIAG_ 0xE3 -#define _E4DIAG_ 0xE4 -#define _E5DIAG_ 0xE5 -#define _E6DIAG_ 0xE6 -#define _E7DIAG_ 0xE7 - #define _FORCE_INLINE_ __attribute__((__always_inline__)) __inline__ #define FORCE_INLINE __attribute__((always_inline)) inline #define NO_INLINE __attribute__((noinline)) #define _UNUSED __attribute__((unused)) -#define __O0 __attribute__((optimize("O0"))) -#define __Os __attribute__((optimize("Os"))) -#define __O1 __attribute__((optimize("O1"))) -#define __O2 __attribute__((optimize("O2"))) -#define __O3 __attribute__((optimize("O3"))) +#define __O0 __attribute__((optimize("O0"))) // No optimization and less debug info +#define __Og __attribute__((optimize("Og"))) // Optimize the debugging experience +#define __Os __attribute__((optimize("Os"))) // Optimize for size +#define __O1 __attribute__((optimize("O1"))) // Try to reduce size and cycles; nothing that takes a lot of time to compile +#define __O2 __attribute__((optimize("O2"))) // Optimize even more +#define __O3 __attribute__((optimize("O3"))) // Optimize yet more #define IS_CONSTEXPR(...) __builtin_constant_p(__VA_ARGS__) // Only valid solution with C++14. Should use std::is_constant_evaluated() in C++20 instead @@ -223,22 +179,29 @@ #define _DO_N(W,C,N,V...) __DO_N(W,C,N,V) #define DO(W,C,V...) (_DO_N(W,C,NUM_ARGS(V),V)) -// Macros to support option testing +// Concatenate symbol names, without or with pre-expansion #define _CAT(a,V...) a##V #define CAT(a,V...) _CAT(a,V) +// Recognize "true" values: blank, 1, 0x1, true #define _ISENA_ ~,1 #define _ISENA_1 ~,1 #define _ISENA_0x1 ~,1 #define _ISENA_true ~,1 #define _ISENA(V...) IS_PROBE(V) +// Macros to evaluate simple option switches #define _ENA_1(O) _ISENA(CAT(_IS,CAT(ENA_, O))) #define _DIS_1(O) NOT(_ENA_1(O)) #define ENABLED(V...) DO(ENA,&&,V) #define DISABLED(V...) DO(DIS,&&,V) +#define ANY(V...) !DISABLED(V) +#define ALL ENABLED +#define NONE DISABLED #define COUNT_ENABLED(V...) DO(ENA,+,V) +#define MANY(V...) (COUNT_ENABLED(V) > 1) +// Ternary pre-compiler macros conceal non-emitted content from the compiler #define TERN(O,A,B) _TERN(_ENA_1(O),B,A) // OPTION ? 'A' : 'B' #define TERN0(O,A) _TERN(_ENA_1(O),0,A) // OPTION ? 'A' : '0' #define TERN1(O,A) _TERN(_ENA_1(O),1,A) // OPTION ? 'A' : '1' @@ -246,7 +209,9 @@ #define _TERN(E,V...) __TERN(_CAT(T_,E),V) // Prepend 'T_' to get 'T_0' or 'T_1' #define __TERN(T,V...) ___TERN(_CAT(_NO,T),V) // Prepend '_NO' to get '_NOT_0' or '_NOT_1' #define ___TERN(P,V...) THIRD(P,V) // If first argument has a comma, A. Else B. +#define IF_DISABLED(O,A) TERN(O,,A) +// Macros to conditionally emit array items and function arguments #define _OPTITEM(A...) A, #define OPTITEM(O,A...) TERN_(O,DEFER4(_OPTITEM)(A)) #define _OPTARG(A...) , A @@ -254,22 +219,16 @@ #define _OPTCODE(A) A; #define OPTCODE(O,A) TERN_(O,DEFER4(_OPTCODE)(A)) -// Macros to avoid 'f + 0.0' which is not always optimized away. Minus included for symmetry. +// Macros to avoid operations that aren't always optimized away (e.g., 'f + 0.0' and 'f * 1.0'). // Compiler flags -fno-signed-zeros -ffinite-math-only also cover 'f * 1.0', 'f - f', etc. #define PLUS_TERN0(O,A) _TERN(_ENA_1(O),,+ (A)) // OPTION ? '+ (A)' : '' #define MINUS_TERN0(O,A) _TERN(_ENA_1(O),,- (A)) // OPTION ? '- (A)' : '' +#define MUL_TERN1(O,A) _TERN(_ENA_1(O),,* (A)) // OPTION ? '* (A)' : '' +#define DIV_TERN1(O,A) _TERN(_ENA_1(O),,/ (A)) // OPTION ? '/ (A)' : '' #define SUM_TERN(O,B,A) ((B) PLUS_TERN0(O,A)) // ((B) (OPTION ? '+ (A)' : '')) #define DIFF_TERN(O,B,A) ((B) MINUS_TERN0(O,A)) // ((B) (OPTION ? '- (A)' : '')) - -#define IF_ENABLED TERN_ -#define IF_DISABLED(O,A) TERN(O,,A) - -#define ANY(V...) !DISABLED(V) -#define NONE(V...) DISABLED(V) -#define ALL(V...) ENABLED(V) -#define BOTH(V1,V2) ALL(V1,V2) -#define EITHER(V1,V2) ANY(V1,V2) -#define MANY(V...) (COUNT_ENABLED(V) > 1) +#define MUL_TERN(O,B,A) ((B) MUL_TERN1(O,A)) // ((B) (OPTION ? '* (A)' : '')) +#define DIV_TERN(O,B,A) ((B) DIV_TERN1(O,A)) // ((B) (OPTION ? '/ (A)' : '')) // Macros to support pins/buttons exist testing #define PIN_EXISTS(PN) (defined(PN##_PIN) && PN##_PIN >= 0) @@ -282,6 +241,7 @@ #define BUTTONS_EXIST(V...) DO(BTNEX,&&,V) #define ANY_BUTTON(V...) DO(BTNEX,||,V) +// Value helper macros #define WITHIN(N,L,H) ((N) >= (L) && (N) <= (H)) #define ISEOL(C) ((C) == '\n' || (C) == '\r') #define NUMERIC(a) WITHIN(a, '0', '9') @@ -289,6 +249,8 @@ #define HEXCHR(a) (NUMERIC(a) ? (a) - '0' : WITHIN(a, 'a', 'f') ? ((a) - 'a' + 10) : WITHIN(a, 'A', 'F') ? ((a) - 'A' + 10) : -1) #define NUMERIC_SIGNED(a) (NUMERIC(a) || (a) == '-' || (a) == '+') #define DECIMAL_SIGNED(a) (DECIMAL(a) || (a) == '-' || (a) == '+') + +// Array shorthand #define COUNT(a) (sizeof(a)/sizeof(*a)) #define ZERO(a) memset((void*)a,0,sizeof(a)) #define COPY(a,b) do{ \ @@ -296,6 +258,7 @@ memcpy(&a[0],&b[0],_MIN(sizeof(a),sizeof(b))); \ }while(0) +// Expansion of some code #define CODE_16( A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,...) A; B; C; D; E; F; G; H; I; J; K; L; M; N; O; P #define CODE_15( A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,...) A; B; C; D; E; F; G; H; I; J; K; L; M; N; O #define CODE_14( A,B,C,D,E,F,G,H,I,J,K,L,M,N,...) A; B; C; D; E; F; G; H; I; J; K; L; M; N @@ -316,6 +279,7 @@ #define _CODE_N(N,V...) CODE_##N(V) #define CODE_N(N,V...) _CODE_N(N,V) +// Expansion of some non-delimited content #define GANG_16(A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,...) A B C D E F G H I J K L M N O P #define GANG_15(A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,...) A B C D E F G H I J K L M N O #define GANG_14(A,B,C,D,E,F,G,H,I,J,K,L,M,N,...) A B C D E F G H I J K L M N @@ -337,7 +301,7 @@ #define GANG_N(N,V...) _GANG_N(N,V) #define GANG_N_1(N,K) _GANG_N(N,K,K,K,K,K,K,K,K,K,K,K,K,K,K,K,K) -// Macros for initializing arrays +// Expansion of some list items #define LIST_26(A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z,...) A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z #define LIST_25(A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,...) A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y #define LIST_24(A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,...) A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X @@ -375,11 +339,6 @@ #define _JOIN_1(O) (O) #define JOIN_N(N,C,V...) (DO(JOIN,C,LIST_N(N,V))) -#define LOOP_S_LE_N(VAR, S, N) for (uint8_t VAR=(S); VAR<=(N); VAR++) -#define LOOP_S_L_N(VAR, S, N) for (uint8_t VAR=(S); VAR<(N); VAR++) -#define LOOP_LE_N(VAR, N) LOOP_S_LE_N(VAR, 0, N) -#define LOOP_L_N(VAR, N) LOOP_S_L_N(VAR, 0, N) - #define NOOP (void(0)) #define CEILING(x,y) (((x) + (y) - 1) / (y)) @@ -429,6 +388,8 @@ extern "C++" { // C++11 solution that is standards compliant. Return type is deduced automatically + template static constexpr N _MIN(const N val) { return val; } + template static constexpr N _MAX(const N val) { return val; } template static constexpr auto _MIN(const L lhs, const R rhs) -> decltype(lhs + rhs) { return lhs < rhs ? lhs : rhs; } @@ -448,9 +409,9 @@ FORCE_INLINE constexpr T operator|(T x, T y) { return static_cast(static_cast(x) | static_cast(y)); } \ FORCE_INLINE constexpr T operator^(T x, T y) { return static_cast(static_cast(x) ^ static_cast(y)); } \ FORCE_INLINE constexpr T operator~(T x) { return static_cast(~static_cast(x)); } \ - FORCE_INLINE T & operator&=(T &x, T y) { return x &= y; } \ - FORCE_INLINE T & operator|=(T &x, T y) { return x |= y; } \ - FORCE_INLINE T & operator^=(T &x, T y) { return x ^= y; } + FORCE_INLINE T & operator&=(T &x, T y) { x = x & y; return x; } \ + FORCE_INLINE T & operator|=(T &x, T y) { x = x | y; return x; } \ + FORCE_INLINE T & operator^=(T &x, T y) { x = x ^ y; return x; } // C++11 solution that is standard compliant. is not available on all platform namespace Private { @@ -462,7 +423,41 @@ template struct first_type_of { typedef T type; }; template struct first_type_of { typedef T type; }; + + // remove const/volatile type qualifiers + template struct remove_const { typedef T type; }; + template struct remove_const { typedef T type; }; + + template struct remove_volatile { typedef T type; }; + template struct remove_volatile { typedef T type; }; + + template struct remove_cv { typedef typename remove_const::type>::type type; }; + + // test if type is integral + template struct _is_integral { enum { value = false }; }; + template<> struct _is_integral { enum { value = true }; }; + template<> struct _is_integral { enum { value = true }; }; + template<> struct _is_integral { enum { value = true }; }; + template<> struct _is_integral { enum { value = true }; }; + template<> struct _is_integral { enum { value = true }; }; + template<> struct _is_integral { enum { value = true }; }; + template<> struct _is_integral { enum { value = true }; }; + template<> struct _is_integral { enum { value = true }; }; + template<> struct _is_integral { enum { value = true }; }; + template<> struct _is_integral { enum { value = true }; }; + template struct is_integral : public _is_integral::type> {}; } + + // enum type check and regression to its underlying integral. + namespace Private { + template struct is_enum { enum { value = __is_enum(T) }; }; + + template::value> struct _underlying_type { using type = __underlying_type(T); }; + template struct _underlying_type { }; + + template struct underlying_type : public _underlying_type { }; + } + // C++11 solution using SFINAE to detect the existence of a member in a class at compile time. // It creates a HasMember structure containing 'value' set to true if the member exists #define HAS_MEMBER_IMPL(Member) \ @@ -634,7 +629,9 @@ #define DEFER4(M) M EMPTY EMPTY EMPTY EMPTY()()()() // Force define expansion -#define EVAL(V...) EVAL16(V) +#define EVAL EVAL16 +#define EVAL4096(V...) EVAL2048(EVAL2048(V)) +#define EVAL2048(V...) EVAL1024(EVAL1024(V)) #define EVAL1024(V...) EVAL512(EVAL512(V)) #define EVAL512(V...) EVAL256(EVAL256(V)) #define EVAL256(V...) EVAL128(EVAL128(V)) @@ -712,10 +709,24 @@ ( DEFER2(__RREPEAT2)()(ADD1(_RPT_I),SUB1(_RPT_N),_RPT_OP,V) ) \ ( /* Do nothing */ ) #define __RREPEAT2() _RREPEAT2 -#define RREPEAT_S(S,N,OP) EVAL1024(_RREPEAT(S,SUB##S(N),OP)) -#define RREPEAT(N,OP) RREPEAT_S(0,N,OP) -#define RREPEAT2_S(S,N,OP,V...) EVAL1024(_RREPEAT2(S,SUB##S(N),OP,V)) -#define RREPEAT2(N,OP,V...) RREPEAT2_S(0,N,OP,V) +#define RREPEAT_S(S,N,OP) EVAL1024(_RREPEAT(S,SUB##S(N),OP)) +#define RREPEAT(N,OP) RREPEAT_S(0,N,OP) +#define RREPEAT_1(N,OP) RREPEAT_S(1,INCREMENT(N),OP) +#define RREPEAT2_S(S,N,OP,V...) EVAL1024(_RREPEAT2(S,SUB##S(N),OP,V)) +#define RREPEAT2(N,OP,V...) RREPEAT2_S(0,N,OP,V) + +// Emit a list of N OP(I) items with ascending counter. +#define _REPLIST(_RPT_I,_RPT_N,_RPT_OP) \ + _RPT_OP(_RPT_I) \ + IF_ELSE(SUB1(_RPT_N)) \ + ( , DEFER2(__REPLIST)()(ADD1(_RPT_I),SUB1(_RPT_N),_RPT_OP) ) \ + ( /* Do nothing */ ) +#define __REPLIST() _REPLIST + +// Repeat a macro, comma-separated, passing S...N-1. +#define REPLIST_S(S,N,OP) EVAL(_REPLIST(S,SUB##S(N),OP)) +#define REPLIST(N,OP) REPLIST_S(0,N,OP) +#define REPLIST_1(N,OP) REPLIST_S(1,INCREMENT(N),OP) // Call OP(A) with each item as an argument #define _MAP(_MAP_OP,A,V...) \ @@ -742,3 +753,14 @@ #define _HAS_E_TEMP(N) || TEMP_SENSOR(N) #define HAS_E_TEMP_SENSOR (0 REPEAT(EXTRUDERS, _HAS_E_TEMP)) #define TEMP_SENSOR_IS_MAX_TC(T) (TEMP_SENSOR(T) == -5 || TEMP_SENSOR(T) == -3 || TEMP_SENSOR(T) == -2) + +#define _UI_NONE 0 +#define _UI_ORIGIN 101 +#define _UI_FYSETC 102 +#define _UI_HIPRECY 103 +#define _UI_MKS 104 +#define _UI_RELOADED 105 +#define _UI_IA_CREALITY 106 +#define _UI_E3S1PRO 107 +#define _DGUS_UI_IS(N) || (CAT(_UI_, DGUS_LCD_UI) == CAT(_UI_, N)) +#define DGUS_UI_IS(V...) (0 MAP(_DGUS_UI_IS, V)) diff --git a/Marlin/src/core/millis_t.h b/Marlin/src/core/millis_t.h index 95bc40e1ec..e7032a2e55 100644 --- a/Marlin/src/core/millis_t.h +++ b/Marlin/src/core/millis_t.h @@ -28,6 +28,7 @@ typedef uint32_t millis_t; #define SEC_TO_MS(N) millis_t((N)*1000UL) #define MIN_TO_MS(N) SEC_TO_MS((N)*60UL) #define MS_TO_SEC(N) millis_t((N)/1000UL) +#define MS_TO_SEC_PRECISE(N) (float(N)/1000.0f) #define PENDING(NOW,SOON) ((int32_t)(NOW-(SOON))<0) #define ELAPSED(NOW,SOON) (!PENDING(NOW,SOON)) diff --git a/Marlin/src/core/mstring.h b/Marlin/src/core/mstring.h new file mode 100644 index 0000000000..31e8c8c6e6 --- /dev/null +++ b/Marlin/src/core/mstring.h @@ -0,0 +1,320 @@ +/** + * Marlin 3D Printer Firmware + * Copyright (c) 2022 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 + +/** + * Lightweight string class template providing operators for all common tasks + * and conversion from F() and PSTR() strings into SRAM strings that reside + * on the stack or persistently, with overflow prevention. + * + * Examples: + * + * MString<50> mystr(F("Hello "), intvar, " World"); // "Hello 3 World" + * + * mystr.append(" (", p_float_t(123.4, 2), ')'); // "Hello 3 World (123.40)" + * + * mystr.clear(); + * + * mystr.append(spaces_t(10), repchr_t('-', 5)); // Repeats are sometimes cheaper than strings + * + * mystr.appendf(F(" ... %i/%i"), count, total); // Works like printf, requires F string + * + */ + +#include "types.h" +#include "utility.h" // AXIS_CHAR +#include "../lcd/utf8.h" + +#ifndef DEFAULT_MSTRING_SIZE + #define DEFAULT_MSTRING_SIZE 20 +#endif + +//#define UNSAFE_MSTRING // Don't initialize the string to "" or set a terminating nul +//#define USE_SPRINTF // Use sprintf instead of snprintf +//#define DJB2_HASH // 32-bit hash with Djb2 algorithm +//#define MSTRING_DEBUG // Debug string operations to diagnose memory leaks +//#define FASTER_APPEND // Append without using an intermediate buffer + +// Declare externs for serial debug output +template extern void SERIAL_ECHO(T x); +template extern void SERIAL_ECHOLN(T x); +extern void SERIAL_ECHO(serial_char_t x); +extern void SERIAL_CHAR(char c); + +#define START_OF_UTF8_CHAR(C) (((C) & 0xC0u) != 0x80U) + +#if ENABLED(USE_SPRINTF) + #define SNPRINTF(A, S, V...) sprintf(A, V) + #define SNPRINTF_P(A, S, V...) sprintf_P(A, V) +#else + #define SNPRINTF(V...) snprintf(V) + #define SNPRINTF_P(V...) snprintf_P(V) +#endif + +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wdeprecated-declarations" + +#if DISABLED(UNSAFE_MSTRING) && GCC_VERSION >= 80000 + #pragma GCC diagnostic ignored "-Wstringop-truncation" +#endif + +/** + * @brief MString class template + * @details A class template providing convenient string operators, + * very similar to the Arduino String class, as it turns out. + * + * @tparam SIZE The pre-allocated storage for the string buffer + */ +template +class MString { +protected: + char str[SIZE+1]; +public: + MString() { safety(0); safety(SIZE); } + + template + MString(const T v) { set(v); safety(SIZE); } + + static_assert(SIZE > 0, "Bad SIZE for MString!"); + + void debug(FSTR_P const f) { + #if ENABLED(MSTRING_DEBUG) + SERIAL_ECHOLN(f, C(':'), uintptr_t(str), C(' '), length(), C(' '), str); + #endif + } + + void safety(const int n) { if (SAFE && n <= SIZE) str[n] = '\0'; } + + // Chainable String Setters + MString& set() { str[0] = '\0'; debug(F("clear")); return *this; } + MString& set(char *s) { strlcpy(str, s, SIZE + 1); debug(F("string")); return *this; } + MString& set(const char *s) { return set(const_cast(s)); } + MString& set_P(PGM_P const s) { strlcpy_P(str, s, SIZE + 1); debug(F("pstring")); return *this; } + MString& set(FSTR_P const f) { return set_P(FTOP(f)); } + MString& set(const bool &b) { return set(b ? F("true") : F("false")); } + MString& set(const char c) { str[0] = c; str[1] = '\0'; debug(F("char")); return *this; } + MString& set(const int8_t &i) { SNPRINTF_P(str, SIZE, PSTR("%d"), i); debug(F("int8_t")); return *this; } + MString& set(const short &i) { SNPRINTF_P(str, SIZE, PSTR("%d"), i); debug(F("short")); return *this; } + MString& set(const int &i) { SNPRINTF_P(str, SIZE, PSTR("%d"), i); debug(F("int")); return *this; } + MString& set(const long &l) { SNPRINTF_P(str, SIZE, PSTR("%ld"), l); debug(F("long")); return *this; } + MString& set(const unsigned char &i) { SNPRINTF_P(str, SIZE, PSTR("%u"), i); debug(F("uchar")); return *this; } + MString& set(const unsigned short &i) { SNPRINTF_P(str, SIZE, PSTR("%u"), i); debug(F("ushort")); return *this; } + MString& set(const unsigned int &i) { SNPRINTF_P(str, SIZE, PSTR("%u"), i); debug(F("uint")); return *this; } + MString& set(const unsigned long &l) { SNPRINTF_P(str, SIZE, PSTR("%lu"), l); debug(F("ulong")); return *this; } + MString& set(const float &f) { return set(p_float_t(f, SERIAL_FLOAT_PRECISION)); } + MString& set(const p_float_t &pf) { return set(w_float_t(pf.value, 1, pf.prec)); } + MString& set(const w_float_t &wf) { char f1[20]; return set(dtostrf(wf.value, wf.width, wf.prec, f1)); } + MString& set(const serial_char_t &v) { return set(char(v.c)); } + MString& set(const xyz_pos_t &v) { set(); return append(v); } + MString& set(const xyze_pos_t &v) { set(); return append(v); } + + template + MString& set(const MString &m) { strlcpy(str, &m, SIZE + 1); debug(F("MString")); return *this; } + + MString& setn(char *s, int len) { int c = _MIN(len, SIZE); strlcpy(str, s, c + 1); debug(F("string")); return *this; } + MString& setn(const char *s, int len) { return setn(const_cast(s), len); } + MString& setn_P(PGM_P const s, int len) { int c = _MIN(len, SIZE); strlcpy_P(str, s, c + 1); debug(F("pstring")); return *this; } + MString& setn(FSTR_P const f, int len) { return setn_P(FTOP(f), len); } + + // set(repchr_t('-', 10)) + MString& set(const repchr_t &s) { int c = _MIN(s.count, SIZE); if (c >= 0) { if (c > 0) memset(str, s.asc, c); str[c] = '\0'; } debug(F("repchr_t")); return *this; } + + // set(spaces_t(10)) + MString& set(const spaces_t &s) { repchr_t r(' ', s.count); return set(r); } + + // Set with format string and arguments, like printf + template + MString& setf_P(PGM_P const fmt, Args... more) { SNPRINTF_P(str, SIZE, fmt, more...); debug(F("setf_P")); return *this; } + + template + MString& setf(const char *fmt, Args... more) { SNPRINTF(str, SIZE, fmt, more...); debug(F("setf")); return *this; } + + template + MString& setf(FSTR_P const fmt, Args... more) { return setf_P(FTOP(fmt), more...); } + + // Chainable String appenders + MString& append() { debug(F("nil")); return *this; } // for macros that might emit no output + MString& append(char *s) { int sz = length(); if (sz < SIZE) strlcpy(str + sz, s, SIZE - sz + 1); debug(F("string")); return *this; } + MString& append(const char *s) { return append(const_cast(s)); } + MString& append_P(PGM_P const s) { int sz = length(); if (sz < SIZE) strlcpy_P(str + sz, s, SIZE - sz + 1); debug(F("pstring")); return *this; } + MString& append(FSTR_P const f) { return append_P(FTOP(f)); } + MString& append(const bool &b) { return append(b ? F("true") : F("false")); } + MString& append(const char c) { int sz = length(); if (sz < SIZE) { str[sz] = c; if (sz < SIZE - 1) str[sz + 1] = '\0'; } return *this; } + #if ENABLED(FASTER_APPEND) + MString& append(const int8_t &i) { int sz = length(); SNPRINTF(&str[sz], SIZE - sz, "%d", i); return *this; } + MString& append(const short &i) { int sz = length(); SNPRINTF(&str[sz], SIZE - sz, "%d", i); return *this; } + MString& append(const int &i) { int sz = length(); SNPRINTF(&str[sz], SIZE - sz, "%d", i); return *this; } + MString& append(const long &l) { int sz = length(); SNPRINTF(&str[sz], SIZE - sz, "%ld", l); return *this; } + MString& append(const unsigned char &i) { int sz = length(); SNPRINTF(&str[sz], SIZE - sz, "%u", i); return *this; } + MString& append(const unsigned short &i) { int sz = length(); SNPRINTF(&str[sz], SIZE - sz, "%u", i); return *this; } + MString& append(const unsigned int &i) { int sz = length(); SNPRINTF(&str[sz], SIZE - sz, "%u", i); return *this; } + MString& append(const unsigned long &l) { int sz = length(); SNPRINTF(&str[sz], SIZE - sz, "%lu", l); return *this; } + #else + MString& append(const int8_t &i) { char buf[ 5]; sprintf(buf, "%d", i); return append(buf); } + MString& append(const short &i) { char buf[12]; sprintf(buf, "%d", i); return append(buf); } + MString& append(const int &i) { char buf[12]; sprintf(buf, "%d", i); return append(buf); } + MString& append(const long &l) { char buf[12]; sprintf(buf, "%ld", l); return append(buf); } + MString& append(const unsigned char &i) { char buf[ 5]; sprintf(buf, "%u", i); return append(buf); } + MString& append(const unsigned short &i) { char buf[11]; sprintf(buf, "%u", i); return append(buf); } + MString& append(const unsigned int &i) { char buf[11]; sprintf(buf, "%u", i); return append(buf); } + MString& append(const unsigned long &l) { char buf[11]; sprintf(buf, "%lu", l); return append(buf); } + #endif + MString& append(const float &f) { return append(p_float_t(f, SERIAL_FLOAT_PRECISION)); } + MString& append(const p_float_t &pf) { return append(w_float_t(pf.value, 1, pf.prec)); } + MString& append(const w_float_t &wf) { char f1[20]; return append(dtostrf(wf.value, wf.width, wf.prec, f1)); } + MString& append(const serial_char_t &v) { return append(char(v.c)); } + MString& append(const xyz_pos_t &v) { LOOP_NUM_AXES(i) { if (i) append(' '); append(AXIS_CHAR(i), v[i]); } debug(F("xyz")); return *this; } + MString& append(const xyze_pos_t &v) { LOOP_LOGICAL_AXES(i) { if (i) append(' '); append(AXIS_CHAR(i), v[i]); } debug(F("xyze")); return *this; } + + template + MString& append(const MString &m) { return append(&m); } + + // Append only if the given space is available + MString& appendn(char *s, int len) { int sz = length(), c = _MIN(len, SIZE - sz); if (c > 0) { strlcpy(str + sz, s, c + 1); } debug(F("string")); return *this; } + MString& appendn(const char *s, int len) { return appendn(const_cast(s), len); } + MString& appendn_P(PGM_P const s, int len) { int sz = length(), c = _MIN(len, SIZE - sz); if (c > 0) { strlcpy_P(str + sz, s, c + 1); } debug(F("pstring")); return *this; } + MString& appendn(FSTR_P const f, int len) { return appendn_P(FTOP(f), len); } + + // append(repchr_t('-', 10)) + MString& append(const repchr_t &s) { + const int sz = length(), c = _MIN(s.count, SIZE - sz); + if (c > 0) { memset(str + sz, s.asc, c); str[sz + c] = '\0'; } + debug(F("repchr")); + return *this; + } + + // append(spaces_t(10)) + MString& append(const spaces_t &s) { return append(repchr_t(' ', s.count)); } + + template + MString& appendf_P(PGM_P const fmt, Args... more) { + int sz = length(); + if (sz < SIZE) SNPRINTF_P(str + sz, SIZE - sz, fmt, more...); + debug(F("appendf_P")); + return *this; + } + + template + MString& appendf(const char *fmt, Args... more) { + const int sz = length(); + if (sz < SIZE) SNPRINTF(str + sz, SIZE - sz, fmt, more...); + debug(F("appendf")); + return *this; + } + + template + MString& appendf(FSTR_P const fmt, Args... more) { return appendf_P(FTOP(fmt), more...); } + + // Instantiate with a list of things + template + MString(T arg1, Args... more) { set(arg1); append(more...); } + + // Catch unhandled types to prevent infinite recursion + template MString& append(T) { return append(TERN(MSTRING_DEBUG, typeid(T).name(), '?')); } + + // Take a list of any number of arguments and append them to the string + template + MString& append(T arg1, Args... more) { return append(arg1).append(more...); } + + // Take a list of any number of arguments and set them in the string + template + MString& set(T arg1, Args... more) { return set(arg1).append(more...); } + + // Operator = as shorthand for set() + template + MString& operator=(const T &v) { return set(v); } + + // Operator += as shorthand for append() + template + MString& operator+=(const T &v) { return append(v); } + + // Operator + as shorthand for append-to-copy + template + MString operator+(const T &v) { return MString(str, v); } + + #ifndef __AVR__ + MString(const double d) { set(d); } + MString& set(const double &f) { return set(p_double_t(f, SERIAL_FLOAT_PRECISION)); } + MString& set(const p_double_t &pf) { return set(w_double_t(pf.value, 1, pf.prec)); } + MString& set(const w_double_t &wf) { char d1[20]; return set(dtostrf(wf.value, wf.width, wf.prec, d1)); } + MString& append(const double &f) { return append(p_double_t(f, SERIAL_FLOAT_PRECISION)); } + MString& append(const p_double_t &pf) { return append(w_double_t(pf.value, 1, pf.prec)); } + MString& append(const w_double_t &wf) { char d1[20]; return append(dtostrf(wf.value, wf.width, wf.prec, d1)); } + #endif + + // Get the character at a given index + char operator[](const int i) const { return str[i]; } + + // Cast to char* (explicit?) + operator char* () { return str; } + + // Use &mystring as shorthand for mystring.str + char* operator&() { return str; } + + // Return the buffer address (same as &) + char* buffer() { return str; } + + int length() const { return strlen(str); } + int glyphs() { return utf8_strlen(str); } + bool empty() { return !str[0]; } + + // Quick hash to detect change (e.g., to avoid expensive drawing) + typedef IF::type hash_t; + hash_t hash() const { + #if ENABLED(DJB2_HASH) + hash_t hval = 5381; + char c; + while ((c = *str++)) hval += (hval << 5) + c; // = hval * 33 + c + #else + const int sz = length(); + hash_t hval = hash_t(sz); + for (int i = 0; i < sz; i++) hval = ((hval << 1) | (hval >> 15)) ^ str[i]; // ROL, XOR + #endif + return hval; + } + + void copyto(char * const dst) const { strcpy(dst, str); } + void copyto(char * const dst, int len) const { strlcpy(dst, str, len + 1); } + + MString& clear() { return set(); } + MString& eol() { return append('\n'); } + MString& trunc(const int &i) { if (i <= SIZE) str[i] = '\0'; debug(F("trunc")); return *this; } + + // Truncate on a Unicode boundary + MString& utrunc(const int &n=SIZE) { + const int sz = length(); + if (sz && n <= sz) + for (int i = n; i >= 0; i--) if (START_OF_UTF8_CHAR(str[i])) { str[i] = '\0'; break; } + debug(F("utrunc")); + return *this; + } + +}; + +#pragma GCC diagnostic pop + +// Temporary inline string typically used to compose a G-code command +#ifndef TS_SIZE + #define TS_SIZE 63 +#endif +typedef MString TString; +#define TS(V...) TString(V) diff --git a/Marlin/src/core/multi_language.h b/Marlin/src/core/multi_language.h index 05a713e435..2c0eb7aa72 100644 --- a/Marlin/src/core/multi_language.h +++ b/Marlin/src/core/multi_language.h @@ -64,6 +64,9 @@ typedef const char Language_Str[]; #if NUM_LANGUAGES > 1 #define HAS_MULTI_LANGUAGE 1 + #if HAS_MARLINUI_MENU + #define HAS_MENU_MULTI_LANGUAGE 1 + #endif #define GET_TEXT(MSG) ( \ ui.language == 4 ? GET_LANG(LCD_LANGUAGE_5)::MSG : \ ui.language == 3 ? GET_LANG(LCD_LANGUAGE_4)::MSG : \ diff --git a/Marlin/src/core/serial.cpp b/Marlin/src/core/serial.cpp index 727b191d04..d6c4b55459 100644 --- a/Marlin/src/core/serial.cpp +++ b/Marlin/src/core/serial.cpp @@ -27,7 +27,8 @@ #include "../feature/ethernet.h" #endif -uint8_t marlin_debug_flags = MARLIN_DEBUG_NONE; +// Echo commands to the terminal by default in dev mode +uint8_t marlin_debug_flags = TERN(MARLIN_DEV_MODE, MARLIN_DEBUG_ECHO, MARLIN_DEBUG_NONE); // Commonly-used strings in serial output PGMSTR(SP_A_STR, " A"); PGMSTR(SP_B_STR, " B"); PGMSTR(SP_C_STR, " C"); @@ -68,31 +69,52 @@ MAP(_N_LBL, LOGICAL_AXIS_NAMES); MAP(_SP_N_LBL, LOGICAL_AXIS_NAMES); #endif -void serial_print_P(PGM_P str) { - while (const char c = pgm_read_byte(str++)) SERIAL_CHAR(c); +// Specializations for float, p_float_t, w_float_t +template <> void SERIAL_ECHO(const float f) { SERIAL_IMPL.print(f, SERIAL_FLOAT_PRECISION); } +template <> void SERIAL_ECHO(const p_float_t pf) { SERIAL_IMPL.print(pf.value, pf.prec); } +template <> void SERIAL_ECHO(const w_float_t wf) { char f1[20]; SERIAL_IMPL.print(dtostrf(wf.value, wf.width, wf.prec, f1)); } + +// Specializations for F-string +template <> void SERIAL_ECHO(const FSTR_P fstr) { SERIAL_ECHO_P(FTOP(fstr)); } +template <> void SERIAL_ECHOLN(const FSTR_P fstr) { SERIAL_ECHOLN_P(FTOP(fstr)); } + +void SERIAL_CHAR(char a) { SERIAL_IMPL.write(a); } +void SERIAL_EOL() { SERIAL_CHAR('\n'); } + +void SERIAL_ECHO(serial_char_t x) { SERIAL_IMPL.write(x.c); } + +void SERIAL_FLUSH() { SERIAL_IMPL.flush(); } +void SERIAL_FLUSHTX() { SERIAL_IMPL.flushTX(); } + +void SERIAL_ECHO_P(PGM_P pstr) { + while (const char c = pgm_read_byte(pstr++)) SERIAL_CHAR(c); } +void SERIAL_ECHOLN_P(PGM_P pstr) { SERIAL_ECHO_P(pstr); SERIAL_EOL(); } -void serial_echo_start() { serial_print(F("echo:")); } -void serial_error_start() { serial_print(F("Error:")); } +void SERIAL_ECHO_START() { SERIAL_ECHO(F("echo:")); } +void SERIAL_ERROR_START() { SERIAL_ECHO(F("Error:")); } +void SERIAL_WARN_START() { SERIAL_ECHO(F("Warning:")); } -void serial_spaces(uint8_t count) { count *= (PROPORTIONAL_FONT_RATIO); while (count--) SERIAL_CHAR(' '); } +void SERIAL_ECHO_SP(uint8_t count) { count *= (PROPORTIONAL_FONT_RATIO); while (count--) SERIAL_CHAR(' '); } void serial_offset(const_float_t v, const uint8_t sp/*=0*/) { if (v == 0 && sp == 1) SERIAL_CHAR(' '); else if (v > 0 || (v == 0 && sp == 2)) SERIAL_CHAR('+'); - SERIAL_DECIMAL(v); + SERIAL_ECHO(v); } -void serial_ternary(const bool onoff, FSTR_P const pre, FSTR_P const on, FSTR_P const off, FSTR_P const post/*=nullptr*/) { - if (pre) serial_print(pre); - serial_print(onoff ? on : off); - if (post) serial_print(post); +void serial_ternary(FSTR_P const pre, const bool onoff, FSTR_P const on, FSTR_P const off, FSTR_P const post/*=nullptr*/) { + if (pre) SERIAL_ECHO(pre); + if (onoff && on) SERIAL_ECHO(on); + if (!onoff && off) SERIAL_ECHO(off); + if (post) SERIAL_ECHO(post); } -void serialprint_onoff(const bool onoff) { serial_print(onoff ? F(STR_ON) : F(STR_OFF)); } + +void serialprint_onoff(const bool onoff) { SERIAL_ECHO(onoff ? F(STR_ON) : F(STR_OFF)); } void serialprintln_onoff(const bool onoff) { serialprint_onoff(onoff); SERIAL_EOL(); } -void serialprint_truefalse(const bool tf) { serial_print(tf ? F("true") : F("false")); } +void serialprint_truefalse(const bool tf) { SERIAL_ECHO(tf ? F("true") : F("false")); } void print_bin(uint16_t val) { for (uint8_t i = 16; i--;) { @@ -101,10 +123,24 @@ void print_bin(uint16_t val) { } } -void print_pos(NUM_AXIS_ARGS(const_float_t), FSTR_P const prefix/*=nullptr*/, FSTR_P const suffix/*=nullptr*/) { - if (prefix) serial_print(prefix); - SERIAL_ECHOPGM_P( - LIST_N(DOUBLE(NUM_AXES), SP_X_STR, x, SP_Y_STR, y, SP_Z_STR, z, SP_I_STR, i, SP_J_STR, j, SP_K_STR, k, SP_U_STR, u, SP_V_STR, v, SP_W_STR, w) - ); - if (suffix) serial_print(suffix); else SERIAL_EOL(); +void _print_xyz(NUM_AXIS_ARGS_(const_float_t) FSTR_P const prefix) { + if (prefix) SERIAL_ECHO(prefix); + #if NUM_AXES + SERIAL_ECHOPGM_P( + LIST_N(DOUBLE(NUM_AXES), SP_X_STR, x, SP_Y_STR, y, SP_Z_STR, z, SP_I_STR, i, SP_J_STR, j, SP_K_STR, k, SP_U_STR, u, SP_V_STR, v, SP_W_STR, w) + ); + #endif +} + +void print_xyz(NUM_AXIS_ARGS_(const_float_t) FSTR_P const prefix/*=nullptr*/, FSTR_P const suffix/*=nullptr*/) { + _print_xyz(NUM_AXIS_LIST_(x, y, z, i, j, k, u, v, w) prefix); + if (suffix) SERIAL_ECHO(suffix); else SERIAL_EOL(); +} + +void print_xyze(LOGICAL_AXIS_ARGS_(const_float_t) FSTR_P const prefix/*=nullptr*/, FSTR_P const suffix/*=nullptr*/) { + _print_xyz(NUM_AXIS_LIST_(x, y, z, i, j, k, u, v, w) prefix); + #if HAS_EXTRUDERS + SERIAL_ECHOPGM_P(SP_E_STR, e); + #endif + if (suffix) SERIAL_ECHO(suffix); else SERIAL_EOL(); } diff --git a/Marlin/src/core/serial.h b/Marlin/src/core/serial.h index c19bc08783..ff02ebedc2 100644 --- a/Marlin/src/core/serial.h +++ b/Marlin/src/core/serial.h @@ -125,8 +125,6 @@ extern uint8_t marlin_debug_flags; #define SERIAL_IMPL SERIAL_LEAF_1 #endif -#define SERIAL_OUT(WHAT, V...) (void)SERIAL_IMPL.WHAT(V) - #define PORT_REDIRECT(p) _PORT_REDIRECT(1,p) #define PORT_RESTORE() _PORT_RESTORE(1) #define SERIAL_PORTMASK(P) SerialMask::from(P) @@ -134,65 +132,70 @@ extern uint8_t marlin_debug_flags; // // SERIAL_CHAR - Print one or more individual chars // -inline void SERIAL_CHAR(char a) { SERIAL_IMPL.write(a); } +void SERIAL_CHAR(char a); template void SERIAL_CHAR(char a, Args ... args) { SERIAL_IMPL.write(a); SERIAL_CHAR(args ...); } /** - * SERIAL_ECHO - Print a single string or value. + * SERIAL_ECHO / SERIAL_ECHOLN - Print a single string or value. * Any numeric parameter (including char) is printed as a base-10 number. * A string pointer or literal will be output as a string. * * NOTE: Use SERIAL_CHAR to print char as a single character. */ -template -void SERIAL_ECHO(T x) { SERIAL_IMPL.print(x); } +template void SERIAL_ECHO(T x) { SERIAL_IMPL.print(x); } +template void SERIAL_ECHOLN(T x) { SERIAL_IMPL.println(x); } // Wrapper for ECHO commands to interpret a char -typedef struct SerialChar { char c; SerialChar(char n) : c(n) { } } serial_char_t; -inline void SERIAL_ECHO(serial_char_t x) { SERIAL_IMPL.write(x.c); } -#define AS_CHAR(C) serial_char_t(C) -#define AS_DIGIT(C) AS_CHAR('0' + (C)) +void SERIAL_ECHO(serial_char_t x); +#define AS_DIGIT(n) C('0' + (n)) -template -void SERIAL_ECHOLN(T x) { SERIAL_IMPL.println(x); } - -// SERIAL_PRINT works like SERIAL_ECHO but also takes the numeric base -template -void SERIAL_PRINT(T x, U y) { SERIAL_IMPL.print(x, y); } - -template -void SERIAL_PRINTLN(T x, PrintBase y) { SERIAL_IMPL.println(x, y); } +// Print an integer with a numeric base such as PrintBase::Hex +template void SERIAL_PRINT(T x, PrintBase y) { SERIAL_IMPL.print(x, y); } +template void SERIAL_PRINTLN(T x, PrintBase y) { SERIAL_IMPL.println(x, y); } // Flush the serial port -inline void SERIAL_FLUSH() { SERIAL_IMPL.flush(); } -inline void SERIAL_FLUSHTX() { SERIAL_IMPL.flushTX(); } +void SERIAL_FLUSH(); +void SERIAL_FLUSHTX(); -// Serial echo and error prefixes -#define SERIAL_ECHO_START() serial_echo_start() -#define SERIAL_ERROR_START() serial_error_start() +// Start an echo: or error: output +void SERIAL_ECHO_START(); +void SERIAL_ERROR_START(); +void SERIAL_WARN_START(); // Serial end-of-line -#define SERIAL_EOL() SERIAL_CHAR('\n') +void SERIAL_EOL(); // Print a single PROGMEM, PGM_P, or PSTR() string. -void serial_print_P(PGM_P str); -inline void serial_println_P(PGM_P str) { serial_print_P(str); SERIAL_EOL(); } +void SERIAL_ECHO_P(PGM_P pstr); +void SERIAL_ECHOLN_P(PGM_P pstr); -// Print a single FSTR_P, F(), or FPSTR() string. -inline void serial_print(FSTR_P const fstr) { serial_print_P(FTOP(fstr)); } -inline void serial_println(FSTR_P const fstr) { serial_println_P(FTOP(fstr)); } +// Specializations for float, p_float_t, and w_float_t +template<> void SERIAL_ECHO(const float f); +template<> void SERIAL_ECHO(const p_float_t pf); +template<> void SERIAL_ECHO(const w_float_t wf); + +// Specializations for F-string +template<> void SERIAL_ECHO(const FSTR_P fstr); +template<> void SERIAL_ECHOLN(const FSTR_P fstr); + +// Print any number of items with arbitrary types (except loose PROGMEM strings) +template +void SERIAL_ECHO(T arg1, Args ... args) { SERIAL_ECHO(arg1); SERIAL_ECHO(args ...); } +template +void SERIAL_ECHOLN(T arg1, Args ... args) { SERIAL_ECHO(arg1); SERIAL_ECHO(args ...); SERIAL_EOL(); } // -// SERIAL_ECHOPGM... macros are used to output string-value pairs. +// SERIAL_ECHOPGM... macros are used to output string-value pairs, wrapping +// all the odd loose string elements as PROGMEM strings. // // Print up to 20 pairs of values. Odd elements must be literal strings. #define __SEP_N(N,V...) _SEP_##N(V) #define _SEP_N(N,V...) __SEP_N(N,V) #define _SEP_N_REF() _SEP_N -#define _SEP_1(s) serial_print(F(s)); -#define _SEP_2(s,v) serial_echopair(F(s),v); +#define _SEP_1(s) SERIAL_ECHO(F(s)); +#define _SEP_2(s,v) SERIAL_ECHO(F(s),v); #define _SEP_3(s,v,V...) _SEP_2(s,v); DEFER2(_SEP_N_REF)()(TWO_ARGS(V),V); #define SERIAL_ECHOPGM(V...) do{ EVAL(_SEP_N(TWO_ARGS(V),V)); }while(0) @@ -200,8 +203,8 @@ inline void serial_println(FSTR_P const fstr) { serial_println_P(FTOP(fstr)); } #define __SELP_N(N,V...) _SELP_##N(V) #define _SELP_N(N,V...) __SELP_N(N,V) #define _SELP_N_REF() _SELP_N -#define _SELP_1(s) serial_print(F(s "\n")); -#define _SELP_2(s,v) serial_echolnpair(F(s),v); +#define _SELP_1(s) SERIAL_ECHO(F(s "\n")); +#define _SELP_2(s,v) SERIAL_ECHOLN(F(s),v); #define _SELP_3(s,v,V...) _SEP_2(s,v); DEFER2(_SELP_N_REF)()(TWO_ARGS(V),V); #define SERIAL_ECHOLNPGM(V...) do{ EVAL(_SELP_N(TWO_ARGS(V),V)); }while(0) @@ -209,8 +212,8 @@ inline void serial_println(FSTR_P const fstr) { serial_println_P(FTOP(fstr)); } #define __SEP_N_P(N,V...) _SEP_##N##_P(V) #define _SEP_N_P(N,V...) __SEP_N_P(N,V) #define _SEP_N_P_REF() _SEP_N_P -#define _SEP_1_P(p) serial_print_P(p); -#define _SEP_2_P(p,v) serial_echopair_P(p,v); +#define _SEP_1_P(p) SERIAL_ECHO(FPSTR(p)); +#define _SEP_2_P(p,v) SERIAL_ECHO(FPSTR(p),v); #define _SEP_3_P(p,v,V...) _SEP_2_P(p,v); DEFER2(_SEP_N_P_REF)()(TWO_ARGS(V),V); #define SERIAL_ECHOPGM_P(V...) do{ EVAL(_SEP_N_P(TWO_ARGS(V),V)); }while(0) @@ -218,131 +221,91 @@ inline void serial_println(FSTR_P const fstr) { serial_println_P(FTOP(fstr)); } #define __SELP_N_P(N,V...) _SELP_##N##_P(V) #define _SELP_N_P(N,V...) __SELP_N_P(N,V) #define _SELP_N_P_REF() _SELP_N_P -#define _SELP_1_P(p) serial_println_P(p) -#define _SELP_2_P(p,v) serial_echolnpair_P(p,v) +#define _SELP_1_P(p) SERIAL_ECHOLN(FPSTR(p)); +#define _SELP_2_P(p,v) SERIAL_ECHOLN(FPSTR(p),v); #define _SELP_3_P(p,v,V...) { _SEP_2_P(p,v); DEFER2(_SELP_N_P_REF)()(TWO_ARGS(V),V); } #define SERIAL_ECHOLNPGM_P(V...) do{ EVAL(_SELP_N_P(TWO_ARGS(V),V)); }while(0) -// Print up to 20 pairs of values. Odd elements must be FSTR_P, F(), or FPSTR(). -#define __SEP_N_F(N,V...) _SEP_##N##_F(V) -#define _SEP_N_F(N,V...) __SEP_N_F(N,V) -#define _SEP_N_F_REF() _SEP_N_F -#define _SEP_1_F(p) serial_print(p); -#define _SEP_2_F(p,v) serial_echopair(p,v); -#define _SEP_3_F(p,v,V...) _SEP_2_F(p,v); DEFER2(_SEP_N_F_REF)()(TWO_ARGS(V),V); -#define SERIAL_ECHOF(V...) do{ EVAL(_SEP_N_F(TWO_ARGS(V),V)); }while(0) +#define SERIAL_ECHO_MSG(V...) do{ SERIAL_ECHO_START(); SERIAL_ECHOLNPGM(V); }while(0) +#define SERIAL_ERROR_MSG(V...) do{ SERIAL_ERROR_START(); SERIAL_ECHOLNPGM(V); }while(0) +#define SERIAL_WARN_MSG(V...) do{ SERIAL_WARN_START(); SERIAL_ECHOLNPGM(V); }while(0) -// Print up to 20 pairs of values followed by newline. Odd elements must be FSTR_P, F(), or FPSTR(). -#define __SELP_N_F(N,V...) _SELP_##N##_F(V) -#define _SELP_N_F(N,V...) __SELP_N_F(N,V) -#define _SELP_N_F_REF() _SELP_N_F -#define _SELP_1_F(p) serial_println(p) -#define _SELP_2_F(p,v) serial_echolnpair(p,v) -#define _SELP_3_F(p,v,V...) { _SEP_2_F(p,v); DEFER2(_SELP_N_F_REF)()(TWO_ARGS(V),V); } -#define SERIAL_ECHOLNF(V...) do{ EVAL(_SELP_N_F(TWO_ARGS(V),V)); }while(0) +// Print a prefix, conditional string, and suffix +void serial_ternary(FSTR_P const pre, const bool onoff, FSTR_P const on, FSTR_P const off, FSTR_P const post=nullptr); +// Shorthand to put loose strings in PROGMEM +#define SERIAL_ECHO_TERNARY(TF, PRE, ON, OFF, POST) serial_ternary(F(PRE), TF, F(ON), F(OFF), F(POST)) -#ifdef AllowDifferentTypeInList +// Print up to 255 spaces +void SERIAL_ECHO_SP(uint8_t count); - inline void SERIAL_ECHOLIST_IMPL() {} - template - void SERIAL_ECHOLIST_IMPL(T && t) { SERIAL_IMPL.print(t); } - - template - void SERIAL_ECHOLIST_IMPL(T && t, Args && ... args) { - SERIAL_IMPL.print(t); - serial_print(F(", ")); - SERIAL_ECHOLIST_IMPL(args...); - } - - template - void SERIAL_ECHOLIST(FSTR_P const str, Args && ... args) { - SERIAL_IMPL.print(FTOP(str)); - SERIAL_ECHOLIST_IMPL(args...); - } - -#else // Optimization if the listed type are all the same (seems to be the case in the codebase so use that instead) - - template - void SERIAL_ECHOLIST(FSTR_P const fstr, Args && ... args) { - serial_print(fstr); - typename Private::first_type_of::type values[] = { args... }; - constexpr size_t argsSize = sizeof...(args); - for (size_t i = 0; i < argsSize; i++) { - if (i) serial_print(F(", ")); - SERIAL_IMPL.print(values[i]); - } - } - -#endif - -// SERIAL_ECHO_F prints a floating point value with optional precision -inline void SERIAL_ECHO_F(EnsureDouble x, int digit=2) { SERIAL_IMPL.print(x, digit); } - -#define SERIAL_ECHOPAIR_F_P(P,V...) do{ serial_print_P(P); SERIAL_ECHO_F(V); }while(0) -#define SERIAL_ECHOLNPAIR_F_P(P,V...) do{ SERIAL_ECHOPAIR_F_P(P,V); SERIAL_EOL(); }while(0) - -#define SERIAL_ECHOPAIR_F_F(S,V...) do{ serial_print(S); SERIAL_ECHO_F(V); }while(0) -#define SERIAL_ECHOLNPAIR_F_F(S,V...) do{ SERIAL_ECHOPAIR_F_F(S,V); SERIAL_EOL(); }while(0) - -#define SERIAL_ECHOPAIR_F(S,V...) SERIAL_ECHOPAIR_F_F(F(S),V) -#define SERIAL_ECHOLNPAIR_F(V...) do{ SERIAL_ECHOPAIR_F(V); SERIAL_EOL(); }while(0) - -#define SERIAL_ECHO_MSG(V...) do{ SERIAL_ECHO_START(); SERIAL_ECHOLNPGM(V); }while(0) -#define SERIAL_ERROR_MSG(V...) do{ SERIAL_ERROR_START(); SERIAL_ECHOLNPGM(V); }while(0) - -#define SERIAL_ECHO_SP(C) serial_spaces(C) - -#define SERIAL_ECHO_TERNARY(TF, PRE, ON, OFF, POST) serial_ternary(TF, F(PRE), F(ON), F(OFF), F(POST)) - -#if SERIAL_FLOAT_PRECISION - #define SERIAL_DECIMAL(V) SERIAL_PRINT(V, SERIAL_FLOAT_PRECISION) -#else - #define SERIAL_DECIMAL(V) SERIAL_ECHO(V) -#endif - -// -// Functions for serial printing from PROGMEM. (Saves loads of SRAM.) -// -inline void serial_echopair_P(PGM_P const pstr, serial_char_t v) { serial_print_P(pstr); SERIAL_CHAR(v.c); } -inline void serial_echopair_P(PGM_P const pstr, float v) { serial_print_P(pstr); SERIAL_DECIMAL(v); } -inline void serial_echopair_P(PGM_P const pstr, double v) { serial_print_P(pstr); SERIAL_DECIMAL(v); } -//inline void serial_echopair_P(PGM_P const pstr, const char *v) { serial_print_P(pstr); SERIAL_ECHO(v); } -inline void serial_echopair_P(PGM_P const pstr, FSTR_P v) { serial_print_P(pstr); SERIAL_ECHOF(v); } - -// Default implementation for types without a specialization. Handles integers. -template -inline void serial_echopair_P(PGM_P const pstr, T v) { serial_print_P(pstr); SERIAL_ECHO(v); } - -// Add a newline. -template -inline void serial_echolnpair_P(PGM_P const pstr, T v) { serial_echopair_P(pstr, v); SERIAL_EOL(); } - -// Catch-all for __FlashStringHelper * -template -inline void serial_echopair(FSTR_P const fstr, T v) { serial_echopair_P(FTOP(fstr), v); } - -// Add a newline to the serial output -template -inline void serial_echolnpair(FSTR_P const fstr, T v) { serial_echolnpair_P(FTOP(fstr), v); } - -void serial_echo_start(); -void serial_error_start(); -void serial_ternary(const bool onoff, FSTR_P const pre, FSTR_P const on, FSTR_P const off, FSTR_P const post=nullptr); void serialprint_onoff(const bool onoff); void serialprintln_onoff(const bool onoff); void serialprint_truefalse(const bool tf); -void serial_spaces(uint8_t count); void serial_offset(const_float_t v, const uint8_t sp=0); // For v==0 draw space (sp==1) or plus (sp==2) void print_bin(const uint16_t val); -void print_pos(NUM_AXIS_ARGS(const_float_t), FSTR_P const prefix=nullptr, FSTR_P const suffix=nullptr); -inline void print_pos(const xyz_pos_t &xyz, FSTR_P const prefix=nullptr, FSTR_P const suffix=nullptr) { - print_pos(NUM_AXIS_ELEM(xyz), prefix, suffix); +void print_xyz(NUM_AXIS_ARGS_(const_float_t) FSTR_P const prefix=nullptr, FSTR_P const suffix=nullptr); +inline void print_xyz(const xyz_pos_t &xyz, FSTR_P const prefix=nullptr, FSTR_P const suffix=nullptr) { + print_xyz(NUM_AXIS_ELEM_(xyz) prefix, suffix); } -#define SERIAL_POS(SUFFIX,VAR) do { print_pos(VAR, F(" " STRINGIFY(VAR) "="), F(" : " SUFFIX "\n")); }while(0) -#define SERIAL_XYZ(PREFIX,V...) do { print_pos(V, F(PREFIX)); }while(0) +void print_xyze(LOGICAL_AXIS_ARGS_(const_float_t) FSTR_P const prefix=nullptr, FSTR_P const suffix=nullptr); +inline void print_xyze(const xyze_pos_t &xyze, FSTR_P const prefix=nullptr, FSTR_P const suffix=nullptr) { + print_xyze(LOGICAL_AXIS_ELEM_(xyze) prefix, suffix); +} + +#define SERIAL_POS(SUFFIX,VAR) do { print_xyz(VAR, F(" " STRINGIFY(VAR) "="), F(" : " SUFFIX "\n")); }while(0) +#define SERIAL_XYZ(PREFIX,V...) do { print_xyz(V, F(PREFIX)); }while(0) + +/** + * Extended string that can echo itself to serial + */ +template +class SString : public MString { +public: + typedef MString super; + using super::str; + using super::debug; + + SString() : super() {} + + template + SString(T arg1, Args... more) : super(arg1, more...) {} + + SString& set() { super::set(); return *this; } + + template + SString& setf_P(PGM_P const fmt, Args... more) { super::setf_P(fmt, more...); return *this; } + + template + SString& setf(const char *fmt, Args... more) { super::setf(fmt, more...); return *this; } + + template + SString& setf(FSTR_P const fmt, Args... more) { super::setf(fmt, more...); return *this; } + + template + SString& set(const T &v) { super::set(v); return *this; } + + template + SString& append(const T &v) { super::append(v); return *this; } + + template + SString& set(T arg1, Args... more) { set(arg1).append(more...); return *this; } + + template + SString& append(T arg1, Args... more) { append(arg1).append(more...); return *this; } + + SString& clear() { set(); return *this; } + SString& eol() { append('\n'); return *this; } + SString& trunc(const int &i) { super::trunc(i); return *this; } + + // Extended with methods to print to serial + SString& echo() { SERIAL_ECHO(str); return *this; } + SString& echoln() { SERIAL_ECHOLN(str); return *this; } +}; + +#define TSS(V...) SString<>(V) // // Commonly-used strings in serial output diff --git a/Marlin/src/core/serial_base.h b/Marlin/src/core/serial_base.h index a5abd67d87..a2f49417b7 100644 --- a/Marlin/src/core/serial_base.h +++ b/Marlin/src/core/serial_base.h @@ -23,6 +23,8 @@ #include "../inc/MarlinConfigPre.h" +#include // for size_t + #if ENABLED(EMERGENCY_PARSER) #include "../feature/e_parser.h" #endif @@ -77,7 +79,7 @@ struct EnsureDouble { operator double() { return a; } // If the compiler breaks on ambiguity here, it's likely because print(X, base) is called with X not a double/float, and // a base that's not a PrintBase value. This code is made to detect the error. You MUST set a base explicitly like this: - // SERIAL_PRINT(v, PrintBase::Hex) + //SERIAL_PRINT(v, PrintBase::Hex) EnsureDouble(double a) : a(a) {} EnsureDouble(float a) : a(a) {} }; @@ -167,7 +169,6 @@ struct SerialBase { FORCE_INLINE void print(unsigned int c, PrintBase base) { printNumber_unsigned(c, base); } FORCE_INLINE void print(unsigned long c, PrintBase base) { printNumber_unsigned(c, base); } - void print(EnsureDouble c, int digits) { printFloat(c, digits); } // Forward the call to the former's method @@ -178,7 +179,7 @@ struct SerialBase { void print(T c) { print(c, PrintBase::Dec); } void print(float c) { print(c, 2); } - void print(double c) { print(c, 2); } + void print(double c) { print(c, 2); } void println(char *s) { print(s); println(); } void println(const char *s) { print(s); println(); } @@ -232,7 +233,7 @@ struct SerialBase { // Round correctly so that print(1.999, 2) prints as "2.00" double rounding = 0.5; - LOOP_L_N(i, digits) rounding *= 0.1; + for (uint8_t i = 0; i < digits; ++i) rounding *= 0.1; number += rounding; // Extract the integer part of the number and print it diff --git a/Marlin/src/core/serial_hook.h b/Marlin/src/core/serial_hook.h index 65c553c702..06efce1dc5 100644 --- a/Marlin/src/core/serial_hook.h +++ b/Marlin/src/core/serial_hook.h @@ -179,7 +179,7 @@ struct RuntimeSerial : public SerialBase< RuntimeSerial >, public Seria // Append Hookable for this class SerialFeature features(serial_index_t index) const { return SerialFeature::Hookable | CALL_IF_EXISTS(SerialFeature, static_cast(this), features, index); } - void setHook(WriteHook writeHook = 0, EndOfMessageHook eofHook = 0, void * userPointer = 0) { + void setHook(WriteHook writeHook=0, EndOfMessageHook eofHook=0, void * userPointer=0) { // Order is important here as serial code can be called inside interrupts // When setting a hook, the user pointer must be set first so if writeHook is called as soon as it's set, it'll be valid if (userPointer) this->userPointer = userPointer; @@ -292,7 +292,7 @@ struct MultiSerial : public SerialBase< MultiSerial< REPEAT(NUM_SERIAL, _S_NAME) #define _S_REFS(N) Serial##N##T & serial##N, #define _S_INIT(N) ,serial##N (serial##N) - MultiSerial(REPEAT(NUM_SERIAL, _S_REFS) const SerialMask mask = ALL, const bool e = false) + MultiSerial(REPEAT(NUM_SERIAL, _S_REFS) const SerialMask mask=ALL, const bool e=false) : BaseClassT(e), portMask(mask) REPEAT(NUM_SERIAL, _S_INIT) {} }; diff --git a/Marlin/src/core/types.h b/Marlin/src/core/types.h index 0281dea08c..3d12503461 100644 --- a/Marlin/src/core/types.h +++ b/Marlin/src/core/types.h @@ -31,52 +31,108 @@ // // typename IF<(MYOPT==12), int, float>::type myvar; // -template -struct IF { typedef R type; }; -template -struct IF { typedef L type; }; +template struct IF { typedef R type; }; +template struct IF { typedef L type; }; #define ALL_AXIS_NAMES X, X2, Y, Y2, Z, Z2, Z3, Z4, I, J, K, U, V, W, E0, E1, E2, E3, E4, E5, E6, E7 -#define NUM_AXIS_GANG(V...) GANG_N(NUM_AXES, V) -#define NUM_AXIS_CODE(V...) CODE_N(NUM_AXES, V) -#define NUM_AXIS_LIST(V...) LIST_N(NUM_AXES, V) -#define NUM_AXIS_LIST_1(V) LIST_N_1(NUM_AXES, V) -#define NUM_AXIS_ARRAY(V...) { NUM_AXIS_LIST(V) } -#define NUM_AXIS_ARRAY_1(V) { NUM_AXIS_LIST_1(V) } -#define NUM_AXIS_ARGS(T...) NUM_AXIS_LIST(T x, T y, T z, T i, T j, T k, T u, T v, T w) -#define NUM_AXIS_ELEM(O) NUM_AXIS_LIST(O.x, O.y, O.z, O.i, O.j, O.k, O.u, O.v, O.w) -#define NUM_AXIS_DEFS(T,V) NUM_AXIS_LIST(T x=V, T y=V, T z=V, T i=V, T j=V, T k=V, T u=V, T v=V, T w=V) -#define MAIN_AXIS_NAMES NUM_AXIS_LIST(X, Y, Z, I, J, K, U, V, W) -#define MAIN_AXIS_MAP(F) MAP(F, MAIN_AXIS_NAMES) -#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_GANG(V...) GANG_N(NUM_AXES, V) +#define NUM_AXIS_CODE(V...) CODE_N(NUM_AXES, V) +#define NUM_AXIS_LIST(V...) LIST_N(NUM_AXES, V) +#define NUM_AXIS_LIST_1(V) LIST_N_1(NUM_AXES, V) +#define NUM_AXIS_ARRAY(V...) { NUM_AXIS_LIST(V) } +#define NUM_AXIS_ARRAY_1(V) { NUM_AXIS_LIST_1(V) } +#define NUM_AXIS_ARGS(T) NUM_AXIS_LIST(T x, T y, T z, T i, T j, T k, T u, T v, T w) +#define NUM_AXIS_ELEM(O) NUM_AXIS_LIST(O.x, O.y, O.z, O.i, O.j, O.k, O.u, O.v, O.w) +#define NUM_AXIS_DECL(T,V) NUM_AXIS_LIST(T x=V, T y=V, T z=V, T i=V, T j=V, T k=V, T u=V, T v=V, T w=V) +#define MAIN_AXIS_NAMES NUM_AXIS_LIST(X, Y, Z, I, J, K, U, V, W) +#define STR_AXES_MAIN NUM_AXIS_GANG("X", "Y", "Z", STR_I, STR_J, STR_K, STR_U, STR_V, STR_W) -#define LOGICAL_AXIS_GANG(E,V...) NUM_AXIS_GANG(V) GANG_ITEM_E(E) -#define LOGICAL_AXIS_CODE(E,V...) NUM_AXIS_CODE(V) CODE_ITEM_E(E) -#define LOGICAL_AXIS_LIST(E,V...) NUM_AXIS_LIST(V) LIST_ITEM_E(E) -#define LOGICAL_AXIS_LIST_1(V) NUM_AXIS_LIST_1(V) LIST_ITEM_E(V) +#define LOGICAL_AXIS_GANG(E,V...) NUM_AXIS_GANG(V) GANG_ITEM_E(E) +#define LOGICAL_AXIS_CODE(E,V...) NUM_AXIS_CODE(V) CODE_ITEM_E(E) +#define LOGICAL_AXIS_LIST(E,V...) NUM_AXIS_LIST(V) LIST_ITEM_E(E) +#define LOGICAL_AXIS_LIST_1(V) NUM_AXIS_LIST_1(V) LIST_ITEM_E(V) #define LOGICAL_AXIS_ARRAY(E,V...) { LOGICAL_AXIS_LIST(E,V) } #define LOGICAL_AXIS_ARRAY_1(V) { LOGICAL_AXIS_LIST_1(V) } -#define LOGICAL_AXIS_ARGS(T...) LOGICAL_AXIS_LIST(T e, T x, T y, T z, T i, T j, T k, T u, T v, T w) -#define LOGICAL_AXIS_ELEM(O) LOGICAL_AXIS_LIST(O.e, O.x, O.y, O.z, O.i, O.j, O.k, O.u, O.v, O.w) -#define LOGICAL_AXIS_DECL(T,V) LOGICAL_AXIS_LIST(T e=V, T x=V, T y=V, T z=V, T i=V, T j=V, T k=V, T u=V, T v=V, T w=V) -#define LOGICAL_AXIS_NAMES LOGICAL_AXIS_LIST(E, X, Y, Z, I, J, K, U, V, W) -#define LOGICAL_AXIS_MAP(F) MAP(F, LOGICAL_AXIS_NAMES) -#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_ARGS(T) LOGICAL_AXIS_LIST(T e, T x, T y, T z, T i, T j, T k, T u, T v, T w) +#define LOGICAL_AXIS_ELEM(O) LOGICAL_AXIS_LIST(O.e, O.x, O.y, O.z, O.i, O.j, O.k, O.u, O.v, O.w) +#define LOGICAL_AXIS_DECL(T,V) LOGICAL_AXIS_LIST(T e=V, T x=V, T y=V, T z=V, T i=V, T j=V, T k=V, T u=V, T v=V, T w=V) +#define LOGICAL_AXIS_NAMES LOGICAL_AXIS_LIST(E, X, Y, Z, I, J, K, U, V, W) +#define LOGICAL_AXIS_MAP(F) MAP(F, LOGICAL_AXIS_NAMES) +#define STR_AXES_LOGICAL LOGICAL_AXIS_GANG("E", "X", "Y", "Z", STR_I, STR_J, STR_K, STR_U, STR_V, STR_W) -#define XYZ_GANG(V...) GANG_N(PRIMARY_LINEAR_AXES, V) -#define XYZ_CODE(V...) CODE_N(PRIMARY_LINEAR_AXES, V) +#if NUM_AXES + #define NUM_AXES_SEP , + #define MAIN_AXIS_MAP(F) MAP(F, MAIN_AXIS_NAMES) + #define OPTARGS_NUM(T) , NUM_AXIS_ARGS(T) + #define OPTARGS_LOGICAL(T) , LOGICAL_AXIS_ARGS(T) +#else + #define NUM_AXES_SEP + #define MAIN_AXIS_MAP(F) + #define OPTARGS_NUM(T) + #define OPTARGS_LOGICAL(T) +#endif + +#define NUM_AXIS_GANG_(V...) NUM_AXIS_GANG(V) NUM_AXES_SEP +#define NUM_AXIS_LIST_(V...) NUM_AXIS_LIST(V) NUM_AXES_SEP +#define NUM_AXIS_LIST_1_(V...) NUM_AXIS_LIST_1(V) NUM_AXES_SEP +#define NUM_AXIS_ARGS_(T) NUM_AXIS_ARGS(T) NUM_AXES_SEP +#define NUM_AXIS_ELEM_(T) NUM_AXIS_ELEM(T) NUM_AXES_SEP +#define MAIN_AXIS_NAMES_ MAIN_AXIS_NAMES NUM_AXES_SEP + +#if LOGICAL_AXES + #define LOGICAL_AXES_SEP , +#else + #define LOGICAL_AXES_SEP +#endif + +#define LOGICAL_AXIS_GANG_(V...) LOGICAL_AXIS_GANG(V) LOGICAL_AXES_SEP +#define LOGICAL_AXIS_LIST_(V...) LOGICAL_AXIS_LIST(V) LOGICAL_AXES_SEP +#define LOGICAL_AXIS_LIST_1_(V...) LOGICAL_AXIS_LIST_1(V) LOGICAL_AXES_SEP +#define LOGICAL_AXIS_ARGS_(T) LOGICAL_AXIS_ARGS(T) LOGICAL_AXES_SEP +#define LOGICAL_AXIS_ELEM_(T) LOGICAL_AXIS_ELEM(T) LOGICAL_AXES_SEP +#define LOGICAL_AXIS_NAMES_ LOGICAL_AXIS_NAMES LOGICAL_AXES_SEP #define SECONDARY_AXIS_GANG(V...) GANG_N(SECONDARY_AXES, V) #define SECONDARY_AXIS_CODE(V...) CODE_N(SECONDARY_AXES, V) +#define SECONDARY_AXIS_LIST(V...) LIST_N(SECONDARY_AXES, V) +#define SECONDARY_AXIS_ARGS(T) SECONDARY_AXIS_LIST(T i, T j, T k, T u, T v, T w) + +// Just the XY or XYZ elements +#if HAS_Z_AXIS + #define XYZ_COUNT 3 + #define XY_COUNT 2 +#elif HAS_Y_AXIS + #define XY_COUNT 2 +#elif HAS_X_AXIS + #define XY_COUNT 1 +#else + #define XY_COUNT 0 +#endif +#ifndef XYZ_COUNT + #define XYZ_COUNT XY_COUNT +#endif +#define XY_LIST(V...) LIST_N(XY_COUNT, V) +#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 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) #if HAS_ROTATIONAL_AXES #define ROTATIONAL_AXIS_GANG(V...) GANG_N(ROTATIONAL_AXES, V) #endif #if HAS_EXTRUDERS - #define LIST_ITEM_E(N) , N - #define CODE_ITEM_E(N) ; N + #if NUM_AXES + #define LIST_ITEM_E(N) , N + #define CODE_ITEM_E(N) ; N + #else + #define LIST_ITEM_E(N) N + #define CODE_ITEM_E(N) N + #endif #define GANG_ITEM_E(N) N #else #define LIST_ITEM_E(N) @@ -86,58 +142,77 @@ struct IF { typedef L type; }; #define AXIS_COLLISION(L) (AXIS4_NAME == L || AXIS5_NAME == L || AXIS6_NAME == L || AXIS7_NAME == L || AXIS8_NAME == L || AXIS9_NAME == L) +// Helpers +#define _RECIP(N) ((N) ? 1.0f / static_cast(N) : 0.0f) +#define _ABS(N) ((N) < 0 ? -(N) : (N)) +#define _LS(N) T(uint32_t(N) << p) +#define _RS(N) T(uint32_t(N) >> p) +#define _LSE(N) N = T(uint32_t(N) << p) +#define _RSE(N) N = T(uint32_t(N) >> p) +#define FI FORCE_INLINE + +// Define types based on largest bit width stored value required +#define bits_t(W) typename IF<((W)> 16), uint32_t, typename IF<((W)> 8), uint16_t, uint8_t>::type>::type +#define uvalue_t(V) typename IF<((V)>65535), uint32_t, typename IF<((V)>255), uint16_t, uint8_t>::type>::type +#define value_t(V) typename IF<((V)>32767), int32_t, typename IF<((V)>127), int16_t, int8_t>::type>::type + // General Flags for some number of states template struct Flags { - typedef typename IF<(N>8), uint16_t, uint8_t>::type bits_t; + typedef uvalue_t(N) flagbits_t; typedef struct { bool b0:1, b1:1, b2:1, b3:1, b4:1, b5:1, b6:1, b7:1; } N8; typedef struct { bool b0:1, b1:1, b2:1, b3:1, b4:1, b5:1, b6:1, b7:1, b8:1, b9:1, b10:1, b11:1, b12:1, b13:1, b14:1, b15:1; } N16; + typedef struct { bool b0:1, b1:1, b2:1, b3:1, b4:1, b5:1, b6:1, b7:1, b8:1, b9:1, b10:1, b11:1, b12:1, b13:1, b14:1, b15:1, + b16:1, b17:1, b18:1, b19:1, b20:1, b21:1, b22:1, b23:1, b24:1, b25:1, b26:1, b27:1, b28:1, b29:1, b30:1, b31:1; } N32; union { - bits_t b; - typename IF<(N>8), N16, N8>::type flag; + flagbits_t b; + typename IF<(N>16), N32, typename IF<(N>8), N16, N8>::type>::type flag; }; - void reset() { b = 0; } - void set(const int n, const bool onoff) { onoff ? set(n) : clear(n); } - void set(const int n) { b |= (bits_t)_BV(n); } - void clear(const int n) { b &= ~(bits_t)_BV(n); } - bool test(const int n) const { return TEST(b, n); } - bool operator[](const int n) { return test(n); } - bool operator[](const int n) const { return test(n); } - int size() const { return sizeof(b); } + FI void reset() { b = 0; } + FI void set(const int n, const bool onoff) { onoff ? set(n) : clear(n); } + FI void set(const int n) { b |= (flagbits_t)_BV(n); } + FI void clear(const int n) { b &= ~(flagbits_t)_BV(n); } + FI bool test(const int n) const { return TEST(b, n); } + FI bool operator[](const int n) { return test(n); } + FI bool operator[](const int n) const { return test(n); } + FI int size() const { return sizeof(b); } + FI operator bool() const { return b; } }; // Specialization for a single bool flag template<> struct Flags<1> { bool b; - void reset() { b = false; } - void set(const int n, const bool onoff) { onoff ? set(n) : clear(n); } - void set(const int) { b = true; } - void clear(const int) { b = false; } - bool test(const int) const { return b; } - bool& operator[](const int) { return b; } - bool operator[](const int) const { return b; } - int size() const { return sizeof(b); } + FI void reset() { b = false; } + FI void set(const int n, const bool onoff) { onoff ? set(n) : clear(n); } + FI void set(const int) { b = true; } + FI void clear(const int) { b = false; } + FI bool test(const int) const { return b; } + FI bool& operator[](const int) { return b; } + FI bool operator[](const int) const { return b; } + FI int size() const { return sizeof(b); } + FI operator bool() const { return b; } }; typedef Flags<8> flags_8_t; typedef Flags<16> flags_16_t; // Flags for some axis states, with per-axis aliases xyzijkuvwe -typedef struct AxisFlags { +typedef struct { union { struct Flags flags; struct { bool LOGICAL_AXIS_LIST(e:1, x:1, y:1, z:1, i:1, j:1, k:1, u:1, v:1, w:1); }; }; - void reset() { flags.reset(); } - void set(const int n) { flags.set(n); } - void set(const int n, const bool onoff) { flags.set(n, onoff); } - void clear(const int n) { flags.clear(n); } - bool test(const int n) const { return flags.test(n); } - bool operator[](const int n) { return flags[n]; } - bool operator[](const int n) const { return flags[n]; } - int size() const { return sizeof(flags); } -} axis_flags_t; + FI void reset() { flags.reset(); } + FI void set(const int n) { flags.set(n); } + FI void set(const int n, const bool onoff) { flags.set(n, onoff); } + FI void clear(const int n) { flags.clear(n); } + FI bool test(const int n) const { return flags.test(n); } + FI bool operator[](const int n) { return flags[n]; } + FI bool operator[](const int n) const { return flags[n]; } + FI int size() const { return sizeof(flags); } + FI operator bool() const { return flags; } +} AxisFlags; // // Enumerated axis indices @@ -149,49 +224,48 @@ typedef struct AxisFlags { enum AxisEnum : uint8_t { // Linear axes may be controlled directly or indirectly - NUM_AXIS_LIST(X_AXIS, Y_AXIS, Z_AXIS, I_AXIS, J_AXIS, K_AXIS, U_AXIS, V_AXIS, W_AXIS) + NUM_AXIS_LIST_(X_AXIS, Y_AXIS, Z_AXIS, I_AXIS, J_AXIS, K_AXIS, U_AXIS, V_AXIS, W_AXIS) - // Extruder axes may be considered distinctly - #define _EN_ITEM(N) , E##N##_AXIS + #define _EN_ITEM(N) E##N##_AXIS, REPEAT(EXTRUDERS, _EN_ITEM) #undef _EN_ITEM // Core also keeps toolhead directions #if ANY(IS_CORE, MARKFORGED_XY, MARKFORGED_YX) - , X_HEAD, Y_HEAD, Z_HEAD + X_HEAD, Y_HEAD, Z_HEAD, #endif // Distinct axes, including all E and Core - , NUM_AXIS_ENUMS + NUM_AXIS_ENUMS, // Most of the time we refer only to the single E_AXIS #if HAS_EXTRUDERS - , E_AXIS = E0_AXIS + E_AXIS = E0_AXIS, #endif // A, B, and C are for DELTA, SCARA, etc. - , A_AXIS = X_AXIS + #if HAS_X_AXIS + A_AXIS = X_AXIS, + #endif #if HAS_Y_AXIS - , B_AXIS = Y_AXIS + B_AXIS = Y_AXIS, #endif #if HAS_Z_AXIS - , C_AXIS = Z_AXIS + C_AXIS = Z_AXIS, #endif // To refer to all or none - , ALL_AXES_ENUM = 0xFE, NO_AXIS_ENUM = 0xFF + ALL_AXES_ENUM = 0xFE, NO_AXIS_ENUM = 0xFF }; -typedef IF<(NUM_AXIS_ENUMS > 8), uint16_t, uint8_t>::type axis_bits_t; - // // Loop over axes // -#define LOOP_ABC(VAR) LOOP_S_LE_N(VAR, A_AXIS, C_AXIS) -#define LOOP_NUM_AXES(VAR) LOOP_S_L_N(VAR, X_AXIS, NUM_AXES) -#define LOOP_LOGICAL_AXES(VAR) LOOP_S_L_N(VAR, X_AXIS, LOGICAL_AXES) -#define LOOP_DISTINCT_AXES(VAR) LOOP_S_L_N(VAR, X_AXIS, DISTINCT_AXES) -#define LOOP_DISTINCT_E(VAR) LOOP_L_N(VAR, DISTINCT_E) +#define LOOP_ABC(VAR) for (uint8_t VAR = A_AXIS; VAR <= C_AXIS; ++VAR) +#define LOOP_NUM_AXES(VAR) for (uint8_t VAR = 0; VAR < NUM_AXES; ++VAR) +#define LOOP_LOGICAL_AXES(VAR) for (uint8_t VAR = 0; VAR < LOGICAL_AXES; ++VAR) +#define LOOP_DISTINCT_AXES(VAR) for (uint8_t VAR = 0; VAR < DISTINCT_AXES; ++VAR) +#define LOOP_DISTINCT_E(VAR) for (uint8_t VAR = 0; VAR < DISTINCT_E; ++VAR) // // feedRate_t is just a humble float @@ -217,21 +291,47 @@ typedef float celsius_float_t; typedef const_float_t const_feedRate_t; typedef const_float_t const_celsius_float_t; +// Type large enough to count leveling grid points +typedef IF 255)), uint16_t, uint8_t>::type grid_count_t; + // Conversion macros #define MMM_TO_MMS(MM_M) feedRate_t(static_cast(MM_M) / 60.0f) #define MMS_TO_MMM(MM_S) (static_cast(MM_S) * 60.0f) +// Packaged character for C macro and other usage +typedef struct SerialChar { char c; SerialChar(char n) : c(n) { } } serial_char_t; +#define C(c) serial_char_t(c) + +// Packaged types: float with precision and/or width; a repeated space/character +typedef struct WFloat { float value; char width; char prec; + WFloat(float v, char w, char p) : value(v), width(w), prec(p) {} + } w_float_t; +typedef struct PFloat { float value; char prec; + PFloat(float v, char p) : value(v), prec(p) {} + } p_float_t; +typedef struct RepChr { char asc; int8_t count; + RepChr(char a, uint8_t c) : asc(a), count(c) {} + } repchr_t; +typedef struct Spaces { int8_t count; + Spaces(uint8_t c) : count(c) {} + } spaces_t; + +#ifdef __AVR__ + typedef w_float_t w_double_t; + typedef p_float_t p_double_t; +#else + typedef struct WDouble { double value; char width; char prec; + WDouble(double v, char w, char p) : value(v), width(w), prec(p) {} + } w_double_t; + typedef struct PDouble { double value; char prec; + PDouble(double v, char p) : value(v), prec(p) {} + } p_double_t; +#endif + // // Coordinates structures for XY, XYZ, XYZE... // -// Helpers -#define _RECIP(N) ((N) ? 1.0f / static_cast(N) : 0.0f) -#define _ABS(N) ((N) < 0 ? -(N) : (N)) -#define _LS(N) (N = (T)(uint32_t(N) << p)) -#define _RS(N) (N = (T)(uint32_t(N) >> p)) -#define FI FORCE_INLINE - // Forward declarations template struct XYval; template struct XYZval; @@ -309,12 +409,13 @@ typedef abce_float_t abce_pos_t; void toLogical(xy_pos_t &raw); void toLogical(xyz_pos_t &raw); void toLogical(xyze_pos_t &raw); -void toNative(xy_pos_t &raw); -void toNative(xyz_pos_t &raw); -void toNative(xyze_pos_t &raw); +void toNative(xy_pos_t &lpos); +void toNative(xyz_pos_t &lpos); +void toNative(xyze_pos_t &lpos); // // Paired XY coordinates, counters, flags, etc. +// Always has XY elements regardless of the number of configured axes. // template struct XYval { @@ -325,162 +426,157 @@ struct XYval { }; // Set all to 0 - FI void reset() { x = y = 0; } + FI void reset() { x = y = 0; } // Setters taking struct types and arrays - FI void set(const T px) { x = px; } + #if HAS_X_AXIS + FI void set(const T px) { x = px; } + #endif #if HAS_Y_AXIS - FI void set(const T px, const T py) { x = px; y = py; } - FI void set(const T (&arr)[XY]) { x = arr[0]; y = arr[1]; } + FI void set(const T px, const T py) { x = px; y = py; } + FI void set(const T (&arr)[XY]) { x = arr[0]; y = arr[1]; } #endif #if NUM_AXES > XY - FI void set(const T (&arr)[NUM_AXES]) { x = arr[0]; y = arr[1]; } + FI void set(const T (&arr)[NUM_AXES]) { x = arr[0]; y = arr[1]; } #endif #if LOGICAL_AXES > NUM_AXES - FI void set(const T (&arr)[LOGICAL_AXES]) { x = arr[0]; y = arr[1]; } + FI void set(const T (&arr)[LOGICAL_AXES]) { x = arr[0]; y = arr[1]; } #if DISTINCT_AXES > LOGICAL_AXES - FI void set(const T (&arr)[DISTINCT_AXES]) { x = arr[0]; y = arr[1]; } + FI void set(const T (&arr)[DISTINCT_AXES]) { x = arr[0]; y = arr[1]; } #endif #endif // Length reduced to one dimension - FI T magnitude() const { return (T)sqrtf(x*x + y*y); } + FI constexpr T magnitude() const { return (T)sqrtf(x*x + y*y); } // Pointer to the data as a simple array - FI operator T* () { return pos; } + FI operator T* () { return pos; } // If any element is true then it's true - FI operator bool() { return x || y; } + FI constexpr operator bool() const { return x || y; } // Smallest element - FI T small() const { return _MIN(x, y); } + FI constexpr T small() const { return _MIN(x, y); } // Largest element - FI T large() const { return _MAX(x, y); } + FI constexpr T large() const { return _MAX(x, y); } // Explicit copy and copies with conversion - FI XYval copy() const { return *this; } - FI XYval ABS() const { return { T(_ABS(x)), T(_ABS(y)) }; } - FI XYval asInt() { return { int16_t(x), int16_t(y) }; } - FI XYval asInt() const { return { int16_t(x), int16_t(y) }; } - FI XYval asLong() { return { int32_t(x), int32_t(y) }; } - FI XYval asLong() const { return { int32_t(x), int32_t(y) }; } - FI XYval ROUNDL() { return { int32_t(LROUND(x)), int32_t(LROUND(y)) }; } - FI XYval ROUNDL() const { return { int32_t(LROUND(x)), int32_t(LROUND(y)) }; } - FI XYval asFloat() { return { static_cast(x), static_cast(y) }; } - FI XYval asFloat() const { return { static_cast(x), static_cast(y) }; } - FI XYval reciprocal() const { return { _RECIP(x), _RECIP(y) }; } + FI constexpr XYval copy() const { return *this; } + FI constexpr XYval ABS() const { return { T(_ABS(x)), T(_ABS(y)) }; } + FI constexpr XYval asInt() const { return { int16_t(x), int16_t(y) }; } + FI constexpr XYval asLong() const { return { int32_t(x), int32_t(y) }; } + FI constexpr XYval ROUNDL() const { return { int32_t(LROUND(x)), int32_t(LROUND(y)) }; } + FI constexpr XYval asFloat() const { return { static_cast(x), static_cast(y) }; } + FI constexpr XYval reciprocal() const { return { _RECIP(x), _RECIP(y) }; } // Marlin workspace shifting is done with G92 and M206 - FI XYval asLogical() const { XYval o = asFloat(); toLogical(o); return o; } - FI XYval asNative() const { XYval o = asFloat(); toNative(o); return o; } + FI XYval asLogical() const { XYval o = asFloat(); toLogical(o); return o; } + FI XYval asNative() const { XYval o = asFloat(); toNative(o); return o; } // Cast to a type with more fields by making a new object - FI operator XYZval() { return { x, y }; } - FI operator XYZval() const { return { x, y }; } - FI operator XYZEval() { return { x, y }; } - FI operator XYZEval() const { return { x, y }; } + FI constexpr operator XYZval() const { return { x, y }; } + FI constexpr operator XYZEval() const { return { x, y }; } // Accessor via an AxisEnum (or any integer) [index] - FI T& operator[](const int n) { return pos[n]; } - FI const T& operator[](const int n) const { return pos[n]; } + FI T& operator[](const int n) { return pos[n]; } + FI const T& operator[](const int n) const { return pos[n]; } // Assignment operator overrides do the expected thing - FI XYval& operator= (const T v) { set(v, v ); return *this; } - FI XYval& operator= (const XYZval &rs) { set(rs.x, rs.y); return *this; } - FI XYval& operator= (const XYZEval &rs) { set(rs.x, rs.y); return *this; } + FI XYval& operator= (const T v) { set(v, v); return *this; } + FI XYval& operator= (const XYZval &rs) { set(XY_LIST(rs.x, rs.y)); return *this; } + FI XYval& operator= (const XYZEval &rs) { set(XY_LIST(rs.x, rs.y)); return *this; } // Override other operators to get intuitive behaviors - FI XYval operator+ (const XYval &rs) const { XYval ls = *this; ls.x += rs.x; ls.y += rs.y; return ls; } - FI XYval operator+ (const XYval &rs) { XYval ls = *this; ls.x += rs.x; ls.y += rs.y; return ls; } - FI XYval operator- (const XYval &rs) const { XYval ls = *this; ls.x -= rs.x; ls.y -= rs.y; return ls; } - FI XYval operator- (const XYval &rs) { XYval ls = *this; ls.x -= rs.x; ls.y -= rs.y; return ls; } - FI XYval operator* (const XYval &rs) const { XYval ls = *this; ls.x *= rs.x; ls.y *= rs.y; return ls; } - FI XYval operator* (const XYval &rs) { XYval ls = *this; ls.x *= rs.x; ls.y *= rs.y; return ls; } - FI XYval operator/ (const XYval &rs) const { XYval ls = *this; ls.x /= rs.x; ls.y /= rs.y; return ls; } - FI XYval operator/ (const XYval &rs) { XYval ls = *this; ls.x /= rs.x; ls.y /= rs.y; return ls; } - FI XYval operator+ (const XYZval &rs) const { XYval ls = *this; ls.x += rs.x; ls.y += rs.y; return ls; } - FI XYval operator+ (const XYZval &rs) { XYval ls = *this; ls.x += rs.x; ls.y += rs.y; return ls; } - FI XYval operator- (const XYZval &rs) const { XYval ls = *this; ls.x -= rs.x; ls.y -= rs.y; return ls; } - FI XYval operator- (const XYZval &rs) { XYval ls = *this; ls.x -= rs.x; ls.y -= rs.y; return ls; } - FI XYval operator* (const XYZval &rs) const { XYval ls = *this; ls.x *= rs.x; ls.y *= rs.y; return ls; } - FI XYval operator* (const XYZval &rs) { XYval ls = *this; ls.x *= rs.x; ls.y *= rs.y; return ls; } - FI XYval operator/ (const XYZval &rs) const { XYval ls = *this; ls.x /= rs.x; ls.y /= rs.y; return ls; } - FI XYval operator/ (const XYZval &rs) { XYval ls = *this; ls.x /= rs.x; ls.y /= rs.y; return ls; } - FI XYval operator+ (const XYZEval &rs) const { XYval ls = *this; ls.x += rs.x; ls.y += rs.y; return ls; } - FI XYval operator+ (const XYZEval &rs) { XYval ls = *this; ls.x += rs.x; ls.y += rs.y; return ls; } - FI XYval operator- (const XYZEval &rs) const { XYval ls = *this; ls.x -= rs.x; ls.y -= rs.y; return ls; } - FI XYval operator- (const XYZEval &rs) { XYval ls = *this; ls.x -= rs.x; ls.y -= rs.y; return ls; } - FI XYval operator* (const XYZEval &rs) const { XYval ls = *this; ls.x *= rs.x; ls.y *= rs.y; return ls; } - FI XYval operator* (const XYZEval &rs) { XYval ls = *this; ls.x *= rs.x; ls.y *= rs.y; return ls; } - FI XYval operator/ (const XYZEval &rs) const { XYval ls = *this; ls.x /= rs.x; ls.y /= rs.y; return ls; } - FI XYval operator/ (const XYZEval &rs) { XYval ls = *this; ls.x /= rs.x; ls.y /= rs.y; return ls; } - FI XYval operator* (const float &p) const { XYval ls = *this; ls.x *= p; ls.y *= p; return ls; } - FI XYval operator* (const float &p) { XYval ls = *this; ls.x *= p; ls.y *= p; return ls; } - FI XYval operator* (const int &p) const { XYval ls = *this; ls.x *= p; ls.y *= p; return ls; } - FI XYval operator* (const int &p) { XYval ls = *this; ls.x *= p; ls.y *= p; return ls; } - FI XYval operator/ (const float &p) const { XYval ls = *this; ls.x /= p; ls.y /= p; return ls; } - FI XYval operator/ (const float &p) { XYval ls = *this; ls.x /= p; ls.y /= p; return ls; } - FI XYval operator/ (const int &p) const { XYval ls = *this; ls.x /= p; ls.y /= p; return ls; } - FI XYval operator/ (const int &p) { XYval ls = *this; ls.x /= p; ls.y /= p; return ls; } - FI XYval operator>>(const int &p) const { XYval ls = *this; _RS(ls.x); _RS(ls.y); return ls; } - FI XYval operator>>(const int &p) { XYval ls = *this; _RS(ls.x); _RS(ls.y); return ls; } - FI XYval operator<<(const int &p) const { XYval ls = *this; _LS(ls.x); _LS(ls.y); return ls; } - FI XYval operator<<(const int &p) { XYval ls = *this; _LS(ls.x); _LS(ls.y); return ls; } - FI const XYval operator-() const { XYval o = *this; o.x = -x; o.y = -y; return o; } - FI XYval operator-() { XYval o = *this; o.x = -x; o.y = -y; return o; } + #define XY_OP(OP) { x TERN_(HAS_X_AXIS, OP rs.x), y TERN_(HAS_Y_AXIS, OP rs.y) } + FI constexpr XYval operator+ (const XYval &rs) const { return { x + rs.x, y + rs.y }; } + FI constexpr XYval operator- (const XYval &rs) const { return { x - rs.x, y - rs.y }; } + FI constexpr XYval operator* (const XYval &rs) const { return { x * rs.x, y * rs.y }; } + FI constexpr XYval operator/ (const XYval &rs) const { return { x / rs.x, y / rs.y }; } + FI constexpr XYval operator+ (const XYZval &rs) const { return { XY_OP(+) }; } + FI constexpr XYval operator- (const XYZval &rs) const { return { XY_OP(-) }; } + FI constexpr XYval operator* (const XYZval &rs) const { return { XY_OP(*) }; } + FI constexpr XYval operator/ (const XYZval &rs) const { return { XY_OP(/) }; } + FI constexpr XYval operator+ (const XYZEval &rs) const { return { XY_OP(+) }; } + FI constexpr XYval operator- (const XYZEval &rs) const { return { XY_OP(-) }; } + FI constexpr XYval operator* (const XYZEval &rs) const { return { XY_OP(*) }; } + FI constexpr XYval operator/ (const XYZEval &rs) const { return { XY_OP(/) }; } + FI constexpr XYval operator* (const float &p) const { return { (T)(x * p), (T)(y * p) }; } + FI constexpr XYval operator* (const int &p) const { return { x * p, y * p }; } + FI constexpr XYval operator/ (const float &p) const { return { (T)(x / p), (T)(y / p) }; } + FI constexpr XYval operator/ (const int &p) const { return { x / p, y / p }; } + FI constexpr XYval operator>>(const int &p) const { return { _RS(x), _RS(y) }; } + FI constexpr XYval operator<<(const int &p) const { return { _LS(x), _LS(y) }; } + FI constexpr XYval operator-() const { return { -x, -y }; } + #undef XY_OP // Modifier operators - FI XYval& operator+=(const XYval &rs) { x += rs.x; y += rs.y; return *this; } - FI XYval& operator-=(const XYval &rs) { x -= rs.x; y -= rs.y; return *this; } - FI XYval& operator*=(const XYval &rs) { x *= rs.x; y *= rs.y; return *this; } - FI XYval& operator+=(const XYZval &rs) { x += rs.x; y += rs.y; return *this; } - FI XYval& operator-=(const XYZval &rs) { x -= rs.x; y -= rs.y; return *this; } - FI XYval& operator*=(const XYZval &rs) { x *= rs.x; y *= rs.y; return *this; } - FI XYval& operator+=(const XYZEval &rs) { x += rs.x; y += rs.y; return *this; } - FI XYval& operator-=(const XYZEval &rs) { x -= rs.x; y -= rs.y; return *this; } - FI XYval& operator*=(const XYZEval &rs) { x *= rs.x; y *= rs.y; return *this; } - FI XYval& operator*=(const float &p) { x *= p; y *= p; return *this; } - FI XYval& operator*=(const int &p) { x *= p; y *= p; return *this; } - FI XYval& operator>>=(const int &p) { _RS(x); _RS(y); return *this; } - FI XYval& operator<<=(const int &p) { _LS(x); _LS(y); return *this; } + FI XYval& operator+=(const XYval &rs) { x += rs.x; y += rs.y; return *this; } + FI XYval& operator-=(const XYval &rs) { x -= rs.x; y -= rs.y; return *this; } + FI XYval& operator*=(const XYval &rs) { x *= rs.x; y *= rs.y; return *this; } + FI XYval& operator/=(const XYval &rs) { x /= rs.x; y /= rs.y; return *this; } + FI XYval& operator+=(const XYZval &rs) { XY_CODE(x += rs.x, y += rs.y); return *this; } + FI XYval& operator-=(const XYZval &rs) { XY_CODE(x -= rs.x, y -= rs.y); return *this; } + FI XYval& operator*=(const XYZval &rs) { XY_CODE(x *= rs.x, y *= rs.y); return *this; } + FI XYval& operator/=(const XYZval &rs) { XY_CODE(x /= rs.x, y /= rs.y); return *this; } + FI XYval& operator+=(const XYZEval &rs) { XY_CODE(x += rs.x, y += rs.y); return *this; } + FI XYval& operator-=(const XYZEval &rs) { XY_CODE(x -= rs.x, y -= rs.y); return *this; } + FI XYval& operator*=(const XYZEval &rs) { XY_CODE(x *= rs.x, y *= rs.y); return *this; } + FI XYval& operator/=(const XYZEval &rs) { XY_CODE(x /= rs.x, y /= rs.y); return *this; } + FI XYval& operator*=(const float &p) { x *= p; y *= p; return *this; } + FI XYval& operator*=(const int &p) { x *= p; y *= p; return *this; } + FI XYval& operator>>=(const int &p) { _RSE(x); _RSE(y); return *this; } + FI XYval& operator<<=(const int &p) { _LSE(x); _LSE(y); return *this; } + + // Absolute difference between two objects + FI constexpr XYval diff(const XYZEval &rs) const { return { TERN(HAS_X_AXIS, T(_ABS(x - rs.x)), x), TERN(HAS_Y_AXIS, T(_ABS(y - rs.y)), y) }; } + FI constexpr XYval diff(const XYZval &rs) const { return { TERN(HAS_X_AXIS, T(_ABS(x - rs.x)), x), TERN(HAS_Y_AXIS, T(_ABS(y - rs.y)), y) }; } + FI constexpr XYval diff(const XYval &rs) const { return { T(_ABS(x - rs.x)), T(_ABS(y - rs.y)) }; } // 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 x == rs.x && y == rs.y; } - FI bool operator==(const XYZEval &rs) const { return 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); } + 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 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); } }; // // Linear Axes coordinates, counters, flags, etc. +// May have any number of axes according to configuration, including zero axes. // template struct XYZval { union { - struct { T NUM_AXIS_ARGS(); }; - struct { T NUM_AXIS_LIST(a, b, c, _i, _j, _k, _u, _v, _w); }; + #if NUM_AXES + struct { NUM_AXIS_CODE(T x, T y, T z, T i, T j, T k, T u, T v, T w); }; + struct { NUM_AXIS_CODE(T a, T b, T c, T _i, T _j, T _k, T _u, T _v, T _w); }; + #endif T pos[NUM_AXES]; }; // Set all to 0 - FI void reset() { NUM_AXIS_GANG(x =, y =, z =, i =, j =, k =, u =, v =, w =) 0; } + FI void reset() { NUM_AXIS_CODE(x = 0, y = 0, z = 0, i = 0, j = 0, k = 0, u = 0, v = 0, w = 0); } // Setters taking struct types and arrays - FI void set(const T px) { x = px; } - FI void set(const T px, const T py) { x = px; y = py; } - FI void set(const XYval pxy) { x = pxy.x; y = pxy.y; } - FI void set(const XYval pxy, const T pz) { NUM_AXIS_CODE(x = pxy.x, y = pxy.y, z = pz, NOOP, NOOP, NOOP, NOOP, NOOP, NOOP); } - FI void set(const T (&arr)[XY]) { x = arr[0]; y = arr[1]; } - #if HAS_Z_AXIS - FI void set(const T (&arr)[NUM_AXES]) { NUM_AXIS_CODE(x = arr[0], y = arr[1], z = arr[2], i = arr[3], j = arr[4], k = arr[5], u = arr[6], v = arr[7], w = arr[8]); } - FI void set(NUM_AXIS_ARGS(const T)) { NUM_AXIS_CODE(a = x, b = y, c = z, _i = i, _j = j, _k = k, _u = u, _v = v, _w = w ); } - #endif + FI void set(const XYval pxy) { XY_CODE(x = pxy.x, y = pxy.y); } + FI void set(const XYval pxy, const T pz) { XYZ_CODE(x = pxy.x, y = pxy.y, z = pz); } + FI void set(const T (&arr)[NUM_AXES]) { NUM_AXIS_CODE(x = arr[0], y = arr[1], z = arr[2], i = arr[3], j = arr[4], k = arr[5], u = arr[6], v = arr[7], w = arr[8]); } #if LOGICAL_AXES > NUM_AXES - FI void set(const T (&arr)[LOGICAL_AXES]) { NUM_AXIS_CODE(x = arr[0], y = arr[1], z = arr[2], i = arr[3], j = arr[4], k = arr[5], u = arr[6], v = arr[7], w = arr[8]); } - FI void set(LOGICAL_AXIS_ARGS(const T)) { NUM_AXIS_CODE(a = x, b = y, c = z, _i = i, _j = j, _k = k, _u = u, _v = v, _w = w ); } + FI void set(const T (&arr)[LOGICAL_AXES]) { NUM_AXIS_CODE(x = arr[0], y = arr[1], z = arr[2], i = arr[3], j = arr[4], k = arr[5], u = arr[6], v = arr[7], w = arr[8]); } + FI void set(LOGICAL_AXIS_ARGS(const T)) { NUM_AXIS_CODE(a = x, b = y, c = z, _i = i, _j = j, _k = k, _u = u, _v = v, _w = w); } #if DISTINCT_AXES > LOGICAL_AXES - FI void set(const T (&arr)[DISTINCT_AXES]) { NUM_AXIS_CODE(x = arr[0], y = arr[1], z = arr[2], i = arr[3], j = arr[4], k = arr[5], u = arr[6], v = arr[7], w = arr[8]); } + FI void set(const T (&arr)[DISTINCT_AXES]) { NUM_AXIS_CODE(x = arr[0], y = arr[1], z = arr[2], i = arr[3], j = arr[4], k = arr[5], u = arr[6], v = arr[7], w = arr[8]); } #endif #endif + + // Setter for all individual args + FI void set(NUM_AXIS_ARGS(const T)) { NUM_AXIS_CODE(a = x, b = y, c = z, _i = i, _j = j, _k = k, _u = u, _v = v, _w = w); } + + // Setters with fewer elements leave the rest untouched + #if HAS_Y_AXIS + FI void set(const T px) { x = px; } + #endif + #if HAS_Z_AXIS + FI void set(const T px, const T py) { x = px; y = py; } + #endif #if HAS_I_AXIS FI void set(const T px, const T py, const T pz) { x = px; y = py; z = pz; } #endif @@ -501,114 +597,98 @@ struct XYZval { #endif // Length reduced to one dimension - FI T magnitude() const { return (T)sqrtf(NUM_AXIS_GANG(x*x, + y*y, + z*z, + i*i, + j*j, + k*k, + u*u, + v*v, + w*w)); } + FI constexpr T magnitude() const { return (T)TERN(HAS_X_AXIS, sqrtf(NUM_AXIS_GANG(x*x, + y*y, + z*z, + i*i, + j*j, + k*k, + u*u, + v*v, + w*w)), 0); } // Pointer to the data as a simple array - FI operator T* () { return pos; } + FI operator T* () { return pos; } // If any element is true then it's true - FI operator bool() { return NUM_AXIS_GANG(x, || y, || z, || i, || j, || k, || u, || v, || w); } + FI constexpr operator bool() const { return 0 NUM_AXIS_GANG(|| x, || y, || z, || i, || j, || k, || u, || v, || w); } // Smallest element - FI T small() const { return _MIN(NUM_AXIS_LIST(x, y, z, i, j, k, u, v, w)); } + FI constexpr T small() const { return TERN(HAS_X_AXIS, _MIN(NUM_AXIS_LIST(x, y, z, i, j, k, u, v, w)), 0); } // Largest element - FI T large() const { return _MAX(NUM_AXIS_LIST(x, y, z, i, j, k, u, v, w)); } + FI constexpr T large() const { return TERN(HAS_X_AXIS, _MAX(NUM_AXIS_LIST(x, y, z, i, j, k, u, v, w)), 0); } // Explicit copy and copies with conversion - FI XYZval copy() const { XYZval o = *this; return o; } - FI XYZval ABS() const { return NUM_AXIS_ARRAY(T(_ABS(x)), T(_ABS(y)), T(_ABS(z)), T(_ABS(i)), T(_ABS(j)), T(_ABS(k)), T(_ABS(u)), T(_ABS(v)), T(_ABS(w))); } - FI XYZval asInt() { return NUM_AXIS_ARRAY(int16_t(x), int16_t(y), int16_t(z), int16_t(i), int16_t(j), int16_t(k), int16_t(u), int16_t(v), int16_t(w)); } - FI XYZval asInt() const { return NUM_AXIS_ARRAY(int16_t(x), int16_t(y), int16_t(z), int16_t(i), int16_t(j), int16_t(k), int16_t(u), int16_t(v), int16_t(w)); } - FI XYZval asLong() { return NUM_AXIS_ARRAY(int32_t(x), int32_t(y), int32_t(z), int32_t(i), int32_t(j), int32_t(k), int32_t(u), int32_t(v), int32_t(w)); } - FI XYZval asLong() const { return NUM_AXIS_ARRAY(int32_t(x), int32_t(y), int32_t(z), int32_t(i), int32_t(j), int32_t(k), int32_t(u), int32_t(v), int32_t(w)); } - FI XYZval ROUNDL() { return NUM_AXIS_ARRAY(int32_t(LROUND(x)), int32_t(LROUND(y)), int32_t(LROUND(z)), int32_t(LROUND(i)), int32_t(LROUND(j)), int32_t(LROUND(k)), int32_t(LROUND(u)), int32_t(LROUND(v)), int32_t(LROUND(w))); } - FI XYZval ROUNDL() const { return NUM_AXIS_ARRAY(int32_t(LROUND(x)), int32_t(LROUND(y)), int32_t(LROUND(z)), int32_t(LROUND(i)), int32_t(LROUND(j)), int32_t(LROUND(k)), int32_t(LROUND(u)), int32_t(LROUND(v)), int32_t(LROUND(w))); } - FI XYZval asFloat() { 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 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 XYZval reciprocal() const { return NUM_AXIS_ARRAY(_RECIP(x), _RECIP(y), _RECIP(z), _RECIP(i), _RECIP(j), _RECIP(k), _RECIP(u), _RECIP(v), _RECIP(w)); } + FI constexpr XYZval copy() const { XYZval o = *this; return o; } + FI constexpr XYZval ABS() const { return NUM_AXIS_ARRAY(T(_ABS(x)), T(_ABS(y)), T(_ABS(z)), T(_ABS(i)), T(_ABS(j)), T(_ABS(k)), T(_ABS(u)), T(_ABS(v)), T(_ABS(w))); } + FI constexpr XYZval asInt() const { return NUM_AXIS_ARRAY(int16_t(x), int16_t(y), int16_t(z), int16_t(i), int16_t(j), int16_t(k), int16_t(u), int16_t(v), int16_t(w)); } + FI constexpr XYZval asLong() const { return NUM_AXIS_ARRAY(int32_t(x), int32_t(y), int32_t(z), int32_t(i), int32_t(j), int32_t(k), int32_t(u), int32_t(v), int32_t(w)); } + FI constexpr XYZval ROUNDL() const { return NUM_AXIS_ARRAY(int32_t(LROUND(x)), int32_t(LROUND(y)), int32_t(LROUND(z)), int32_t(LROUND(i)), int32_t(LROUND(j)), int32_t(LROUND(k)), int32_t(LROUND(u)), int32_t(LROUND(v)), int32_t(LROUND(w))); } + FI constexpr XYZval asFloat() const { return NUM_AXIS_ARRAY(static_cast(x), static_cast(y), static_cast(z), static_cast(i), static_cast(j), static_cast(k), static_cast(u), static_cast(v), static_cast(w)); } + FI constexpr XYZval reciprocal() const { return NUM_AXIS_ARRAY(_RECIP(x), _RECIP(y), _RECIP(z), _RECIP(i), _RECIP(j), _RECIP(k), _RECIP(u), _RECIP(v), _RECIP(w)); } // 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; } + 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 - FI operator XYval&() { return *(XYval*)this; } - FI operator const XYval&() const { return *(const XYval*)this; } + FI operator XYval&() { return *(XYval*)this; } + FI operator const XYval&() const { return *(const XYval*)this; } // Cast to a type with more fields by making a new object - FI operator XYZEval() const { return NUM_AXIS_ARRAY(x, y, z, i, j, k, u, v, w); } + FI constexpr operator XYZEval() const { return NUM_AXIS_ARRAY(x, y, z, i, j, k, u, v, w); } // Accessor via an AxisEnum (or any integer) [index] - FI T& operator[](const int n) { return pos[n]; } - FI const T& operator[](const int n) const { return pos[n]; } + FI T& operator[](const int n) { return pos[n]; } + FI const T& operator[](const int n) const { return pos[n]; } // Assignment operator overrides do the expected thing - FI XYZval& operator= (const T v) { set(ARRAY_N_1(NUM_AXES, v)); return *this; } - FI XYZval& operator= (const XYval &rs) { set(rs.x, rs.y ); return *this; } - FI XYZval& operator= (const XYZEval &rs) { set(NUM_AXIS_ELEM(rs)); return *this; } + FI XYZval& operator= (const T v) { set(ARRAY_N_1(NUM_AXES, v)); return *this; } + FI XYZval& operator= (const XYval &rs) { set(rs.x, rs.y); return *this; } + FI XYZval& operator= (const XYZEval &rs) { set(NUM_AXIS_ELEM(rs)); return *this; } // Override other operators to get intuitive behaviors - FI XYZval operator+ (const XYval &rs) const { XYZval ls = *this; NUM_AXIS_CODE(ls.x += rs.x, ls.y += rs.y, NOOP , NOOP , NOOP , NOOP , NOOP , NOOP , NOOP ); return ls; } - FI XYZval operator+ (const XYval &rs) { XYZval ls = *this; NUM_AXIS_CODE(ls.x += rs.x, ls.y += rs.y, NOOP , NOOP , NOOP , NOOP , NOOP , NOOP , NOOP ); return ls; } - FI XYZval operator- (const XYval &rs) const { XYZval ls = *this; NUM_AXIS_CODE(ls.x -= rs.x, ls.y -= rs.y, NOOP , NOOP , NOOP , NOOP , NOOP , NOOP , NOOP ); return ls; } - FI XYZval operator- (const XYval &rs) { XYZval ls = *this; NUM_AXIS_CODE(ls.x -= rs.x, ls.y -= rs.y, NOOP , NOOP , NOOP , NOOP , NOOP , NOOP , NOOP ); return ls; } - FI XYZval operator* (const XYval &rs) const { XYZval ls = *this; NUM_AXIS_CODE(ls.x *= rs.x, ls.y *= rs.y, NOOP , NOOP , NOOP , NOOP , NOOP , NOOP , NOOP ); return ls; } - FI XYZval operator* (const XYval &rs) { XYZval ls = *this; NUM_AXIS_CODE(ls.x *= rs.x, ls.y *= rs.y, NOOP , NOOP , NOOP , NOOP , NOOP , NOOP , NOOP ); return ls; } - FI XYZval operator/ (const XYval &rs) const { XYZval ls = *this; NUM_AXIS_CODE(ls.x /= rs.x, ls.y /= rs.y, NOOP , NOOP , NOOP , NOOP , NOOP , NOOP , NOOP ); return ls; } - FI XYZval operator/ (const XYval &rs) { XYZval ls = *this; NUM_AXIS_CODE(ls.x /= rs.x, ls.y /= rs.y, NOOP , NOOP , NOOP , NOOP , NOOP , NOOP , NOOP ); return ls; } - FI XYZval operator+ (const XYZval &rs) const { XYZval ls = *this; NUM_AXIS_CODE(ls.x += rs.x, ls.y += rs.y, ls.z += rs.z, ls.i += rs.i, ls.j += rs.j, ls.k += rs.k, ls.u += rs.u, ls.v += rs.v, ls.w += rs.w); return ls; } - FI XYZval operator+ (const XYZval &rs) { XYZval ls = *this; NUM_AXIS_CODE(ls.x += rs.x, ls.y += rs.y, ls.z += rs.z, ls.i += rs.i, ls.j += rs.j, ls.k += rs.k, ls.u += rs.u, ls.v += rs.v, ls.w += rs.w); return ls; } - FI XYZval operator- (const XYZval &rs) const { XYZval ls = *this; NUM_AXIS_CODE(ls.x -= rs.x, ls.y -= rs.y, ls.z -= rs.z, ls.i -= rs.i, ls.j -= rs.j, ls.k -= rs.k, ls.u -= rs.u, ls.v -= rs.v, ls.w -= rs.w); return ls; } - FI XYZval operator- (const XYZval &rs) { XYZval ls = *this; NUM_AXIS_CODE(ls.x -= rs.x, ls.y -= rs.y, ls.z -= rs.z, ls.i -= rs.i, ls.j -= rs.j, ls.k -= rs.k, ls.u -= rs.u, ls.v -= rs.v, ls.w -= rs.w); return ls; } - FI XYZval operator* (const XYZval &rs) const { XYZval ls = *this; NUM_AXIS_CODE(ls.x *= rs.x, ls.y *= rs.y, ls.z *= rs.z, ls.i *= rs.i, ls.j *= rs.j, ls.k *= rs.k, ls.u *= rs.u, ls.v *= rs.v, ls.w *= rs.w); return ls; } - FI XYZval operator* (const XYZval &rs) { XYZval ls = *this; NUM_AXIS_CODE(ls.x *= rs.x, ls.y *= rs.y, ls.z *= rs.z, ls.i *= rs.i, ls.j *= rs.j, ls.k *= rs.k, ls.u *= rs.u, ls.v *= rs.v, ls.w *= rs.w); return ls; } - FI XYZval operator/ (const XYZval &rs) const { XYZval ls = *this; NUM_AXIS_CODE(ls.x /= rs.x, ls.y /= rs.y, ls.z /= rs.z, ls.i /= rs.i, ls.j /= rs.j, ls.k /= rs.k, ls.u /= rs.u, ls.v /= rs.v, ls.w /= rs.w); return ls; } - FI XYZval operator/ (const XYZval &rs) { XYZval ls = *this; NUM_AXIS_CODE(ls.x /= rs.x, ls.y /= rs.y, ls.z /= rs.z, ls.i /= rs.i, ls.j /= rs.j, ls.k /= rs.k, ls.u /= rs.u, ls.v /= rs.v, ls.w /= rs.w); return ls; } - FI XYZval operator+ (const XYZEval &rs) const { XYZval ls = *this; NUM_AXIS_CODE(ls.x += rs.x, ls.y += rs.y, ls.z += rs.z, ls.i += rs.i, ls.j += rs.j, ls.k += rs.k, ls.u += rs.u, ls.v += rs.v, ls.w += rs.w); return ls; } - FI XYZval operator+ (const XYZEval &rs) { XYZval ls = *this; NUM_AXIS_CODE(ls.x += rs.x, ls.y += rs.y, ls.z += rs.z, ls.i += rs.i, ls.j += rs.j, ls.k += rs.k, ls.u += rs.u, ls.v += rs.v, ls.w += rs.w); return ls; } - FI XYZval operator- (const XYZEval &rs) const { XYZval ls = *this; NUM_AXIS_CODE(ls.x -= rs.x, ls.y -= rs.y, ls.z -= rs.z, ls.i -= rs.i, ls.j -= rs.j, ls.k -= rs.k, ls.u -= rs.u, ls.v -= rs.v, ls.w -= rs.w); return ls; } - FI XYZval operator- (const XYZEval &rs) { XYZval ls = *this; NUM_AXIS_CODE(ls.x -= rs.x, ls.y -= rs.y, ls.z -= rs.z, ls.i -= rs.i, ls.j -= rs.j, ls.k -= rs.k, ls.u -= rs.u, ls.v -= rs.v, ls.w -= rs.w); return ls; } - FI XYZval operator* (const XYZEval &rs) const { XYZval ls = *this; NUM_AXIS_CODE(ls.x *= rs.x, ls.y *= rs.y, ls.z *= rs.z, ls.i *= rs.i, ls.j *= rs.j, ls.k *= rs.k, ls.u *= rs.u, ls.v *= rs.v, ls.w *= rs.w); return ls; } - FI XYZval operator* (const XYZEval &rs) { XYZval ls = *this; NUM_AXIS_CODE(ls.x *= rs.x, ls.y *= rs.y, ls.z *= rs.z, ls.i *= rs.i, ls.j *= rs.j, ls.k *= rs.k, ls.u *= rs.u, ls.v *= rs.v, ls.w *= rs.w); return ls; } - FI XYZval operator/ (const XYZEval &rs) const { XYZval ls = *this; NUM_AXIS_CODE(ls.x /= rs.x, ls.y /= rs.y, ls.z /= rs.z, ls.i /= rs.i, ls.j /= rs.j, ls.k /= rs.k, ls.u /= rs.u, ls.v /= rs.v, ls.w /= rs.w); return ls; } - FI XYZval operator/ (const XYZEval &rs) { XYZval ls = *this; NUM_AXIS_CODE(ls.x /= rs.x, ls.y /= rs.y, ls.z /= rs.z, ls.i /= rs.i, ls.j /= rs.j, ls.k /= rs.k, ls.u /= rs.u, ls.v /= rs.v, ls.w /= rs.w); return ls; } - FI XYZval operator* (const float &p) const { XYZval ls = *this; NUM_AXIS_CODE(ls.x *= p, ls.y *= p, ls.z *= p, ls.i *= p, ls.j *= p, ls.k *= p, ls.u *= p, ls.v *= p, ls.w *= p ); return ls; } - FI XYZval operator* (const float &p) { XYZval ls = *this; NUM_AXIS_CODE(ls.x *= p, ls.y *= p, ls.z *= p, ls.i *= p, ls.j *= p, ls.k *= p, ls.u *= p, ls.v *= p, ls.w *= p ); return ls; } - FI XYZval operator* (const int &p) const { XYZval ls = *this; NUM_AXIS_CODE(ls.x *= p, ls.y *= p, ls.z *= p, ls.i *= p, ls.j *= p, ls.k *= p, ls.u *= p, ls.v *= p, ls.w *= p ); return ls; } - FI XYZval operator* (const int &p) { XYZval ls = *this; NUM_AXIS_CODE(ls.x *= p, ls.y *= p, ls.z *= p, ls.i *= p, ls.j *= p, ls.k *= p, ls.u *= p, ls.v *= p, ls.w *= p ); return ls; } - FI XYZval operator/ (const float &p) const { XYZval ls = *this; NUM_AXIS_CODE(ls.x /= p, ls.y /= p, ls.z /= p, ls.i /= p, ls.j /= p, ls.k /= p, ls.u /= p, ls.v /= p, ls.w /= p ); return ls; } - FI XYZval operator/ (const float &p) { XYZval ls = *this; NUM_AXIS_CODE(ls.x /= p, ls.y /= p, ls.z /= p, ls.i /= p, ls.j /= p, ls.k /= p, ls.u /= p, ls.v /= p, ls.w /= p ); return ls; } - FI XYZval operator/ (const int &p) const { XYZval ls = *this; NUM_AXIS_CODE(ls.x /= p, ls.y /= p, ls.z /= p, ls.i /= p, ls.j /= p, ls.k /= p, ls.u /= p, ls.v /= p, ls.w /= p ); return ls; } - FI XYZval operator/ (const int &p) { XYZval ls = *this; NUM_AXIS_CODE(ls.x /= p, ls.y /= p, ls.z /= p, ls.i /= p, ls.j /= p, ls.k /= p, ls.u /= p, ls.v /= p, ls.w /= p ); return ls; } - FI XYZval operator>>(const int &p) const { XYZval ls = *this; NUM_AXIS_CODE(_RS(ls.x), _RS(ls.y), _RS(ls.z), _RS(ls.i), _RS(ls.j), _RS(ls.k), _RS(ls.u), _RS(ls.v), _RS(ls.w) ); return ls; } - FI XYZval operator>>(const int &p) { XYZval ls = *this; NUM_AXIS_CODE(_RS(ls.x), _RS(ls.y), _RS(ls.z), _RS(ls.i), _RS(ls.j), _RS(ls.k), _RS(ls.u), _RS(ls.v), _RS(ls.w) ); return ls; } - FI XYZval operator<<(const int &p) const { XYZval ls = *this; NUM_AXIS_CODE(_LS(ls.x), _LS(ls.y), _LS(ls.z), _LS(ls.i), _LS(ls.j), _LS(ls.k), _LS(ls.u), _LS(ls.v), _LS(ls.w) ); return ls; } - FI XYZval operator<<(const int &p) { XYZval ls = *this; NUM_AXIS_CODE(_LS(ls.x), _LS(ls.y), _LS(ls.z), _LS(ls.i), _LS(ls.j), _LS(ls.k), _LS(ls.u), _LS(ls.v), _LS(ls.w) ); return ls; } - FI const XYZval operator-() const { XYZval o = *this; NUM_AXIS_CODE(o.x = -x, o.y = -y, o.z = -z, o.i = -i, o.j = -j, o.k = -k, o.u = -u, o.v = -v, o.w = -w); return o; } - FI XYZval operator-() { XYZval o = *this; NUM_AXIS_CODE(o.x = -x, o.y = -y, o.z = -z, o.i = -i, o.j = -j, o.k = -k, o.u = -u, o.v = -v, o.w = -w); return o; } + FI constexpr XYZval operator+ (const XYval &rs) const { return NUM_AXIS_ARRAY(x + rs.x, y + rs.y, z, i, j, k, u, v, w ); } + FI constexpr XYZval operator- (const XYval &rs) const { return NUM_AXIS_ARRAY(x - rs.x, y - rs.y, z, i, j, k, u, v, w ); } + FI constexpr XYZval operator* (const XYval &rs) const { return NUM_AXIS_ARRAY(x * rs.x, y * rs.y, z, i, j, k, u, v, w ); } + FI constexpr XYZval operator/ (const XYval &rs) const { return NUM_AXIS_ARRAY(x / rs.x, y / rs.y, z, i, j, k, u, v, w ); } + FI constexpr XYZval operator+ (const XYZval &rs) const { return NUM_AXIS_ARRAY(x + rs.x, y + rs.y, z + rs.z, i + rs.i, j + rs.j, k + rs.k, u + rs.u, v + rs.v, w + rs.w ); } + FI constexpr XYZval operator- (const XYZval &rs) const { return NUM_AXIS_ARRAY(x - rs.x, y - rs.y, z - rs.z, i - rs.i, j - rs.j, k - rs.k, u - rs.u, v - rs.v, w - rs.w ); } + FI constexpr XYZval operator* (const XYZval &rs) const { return NUM_AXIS_ARRAY(x * rs.x, y * rs.y, z * rs.z, i * rs.i, j * rs.j, k * rs.k, u * rs.u, v * rs.v, w * rs.w ); } + FI constexpr XYZval operator/ (const XYZval &rs) const { return NUM_AXIS_ARRAY(x / rs.x, y / rs.y, z / rs.z, i / rs.i, j / rs.j, k / rs.k, u / rs.u, v / rs.v, w / rs.w ); } + FI constexpr XYZval operator+ (const XYZEval &rs) const { return NUM_AXIS_ARRAY(x + rs.x, y + rs.y, z + rs.z, i + rs.i, j + rs.j, k + rs.k, u + rs.u, v + rs.v, w + rs.w ); } + FI constexpr XYZval operator- (const XYZEval &rs) const { return NUM_AXIS_ARRAY(x - rs.x, y - rs.y, z - rs.z, i - rs.i, j - rs.j, k - rs.k, u - rs.u, v - rs.v, w - rs.w ); } + FI constexpr XYZval operator* (const XYZEval &rs) const { return NUM_AXIS_ARRAY(x * rs.x, y * rs.y, z * rs.z, i * rs.i, j * rs.j, k * rs.k, u * rs.u, v * rs.v, w * rs.w ); } + FI constexpr XYZval operator/ (const XYZEval &rs) const { return NUM_AXIS_ARRAY(x / rs.x, y / rs.y, z / rs.z, i / rs.i, j / rs.j, k / rs.k, u / rs.u, v / rs.v, w / rs.w ); } + FI constexpr XYZval operator* (const float &p) const { return NUM_AXIS_ARRAY((T)(x * p), (T)(y * p), (T)(z * p), (T)(i * p), (T)(j * p), (T)(k * p), (T)(u * p), (T)(v * p), (T)(w * p)); } + FI constexpr XYZval operator* (const int &p) const { return NUM_AXIS_ARRAY(x * p, y * p, z * p, i * p, j * p, k * p, u * p, v * p, w * p); } + FI constexpr XYZval operator/ (const float &p) const { return NUM_AXIS_ARRAY((T)(x / p), (T)(y / p), (T)(z / p), (T)(i / p), (T)(j / p), (T)(k / p), (T)(u / p), (T)(v / p), (T)(w / p)); } + FI constexpr XYZval operator/ (const int &p) const { return NUM_AXIS_ARRAY(x / p, y / p, z / p, i / p, j / p, k / p, u / p, v / p, w / p); } + FI constexpr XYZval operator>>(const int &p) const { return NUM_AXIS_ARRAY(_RS(x), _RS(y), _RS(z), _RS(i), _RS(j), _RS(k), _RS(u), _RS(v), _RS(w)); } + FI constexpr XYZval operator<<(const int &p) const { return NUM_AXIS_ARRAY(_LS(x), _LS(y), _LS(z), _LS(i), _LS(j), _LS(k), _LS(u), _LS(v), _LS(w)); } + FI constexpr XYZval operator-() const { return NUM_AXIS_ARRAY(-x, -y, -z, -i, -j, -k, -u, -v, -w); } + + // Absolute difference between two objects + FI constexpr XYZval diff(const XYZEval &rs) const { return NUM_AXIS_ARRAY(T(_ABS(x - rs.x)), T(_ABS(y - rs.y)), T(_ABS(z - rs.z)), T(_ABS(i - rs.i)), T(_ABS(j - rs.j)), T(_ABS(k - rs.k)), T(_ABS(u - rs.u)), T(_ABS(v - rs.v)), T(_ABS(w - rs.w)) ); } + FI constexpr XYZval diff(const XYZval &rs) const { return NUM_AXIS_ARRAY(T(_ABS(x - rs.x)), T(_ABS(y - rs.y)), T(_ABS(z - rs.z)), T(_ABS(i - rs.i)), T(_ABS(j - rs.j)), T(_ABS(k - rs.k)), T(_ABS(u - rs.u)), T(_ABS(v - rs.v)), T(_ABS(w - rs.w)) ); } + FI constexpr XYZval diff(const XYval &rs) const { return NUM_AXIS_ARRAY(T(_ABS(x - rs.x)), T(_ABS(y - rs.y)), z, i, j, k, u, v, w ); } // Modifier operators - FI XYZval& operator+=(const XYval &rs) { NUM_AXIS_CODE(x += rs.x, y += rs.y, NOOP, NOOP, NOOP, NOOP, NOOP, NOOP, NOOP ); return *this; } - FI XYZval& operator-=(const XYval &rs) { NUM_AXIS_CODE(x -= rs.x, y -= rs.y, NOOP, NOOP, NOOP, NOOP, NOOP, NOOP, NOOP ); return *this; } - FI XYZval& operator*=(const XYval &rs) { NUM_AXIS_CODE(x *= rs.x, y *= rs.y, NOOP, NOOP, NOOP, NOOP, NOOP, NOOP, NOOP ); return *this; } - FI XYZval& operator/=(const XYval &rs) { NUM_AXIS_CODE(x /= rs.x, y /= rs.y, NOOP, NOOP, NOOP, NOOP, NOOP, NOOP, NOOP ); return *this; } - FI XYZval& operator+=(const XYZval &rs) { NUM_AXIS_CODE(x += rs.x, y += rs.y, z += rs.z, i += rs.i, j += rs.j, k += rs.k, u += rs.u, v += rs.v, w += rs.w); return *this; } - FI XYZval& operator-=(const XYZval &rs) { NUM_AXIS_CODE(x -= rs.x, y -= rs.y, z -= rs.z, i -= rs.i, j -= rs.j, k -= rs.k, u -= rs.u, v -= rs.v, w -= rs.w); return *this; } - FI XYZval& operator*=(const XYZval &rs) { NUM_AXIS_CODE(x *= rs.x, y *= rs.y, z *= rs.z, i *= rs.i, j *= rs.j, k *= rs.k, u *= rs.u, v *= rs.v, w *= rs.w); return *this; } - FI XYZval& operator/=(const XYZval &rs) { NUM_AXIS_CODE(x /= rs.x, y /= rs.y, z /= rs.z, i /= rs.i, j /= rs.j, k /= rs.k, u /= rs.u, v /= rs.v, w /= rs.w); return *this; } - FI XYZval& operator+=(const XYZEval &rs) { NUM_AXIS_CODE(x += rs.x, y += rs.y, z += rs.z, i += rs.i, j += rs.j, k += rs.k, u += rs.u, v += rs.v, w += rs.w); return *this; } - FI XYZval& operator-=(const XYZEval &rs) { NUM_AXIS_CODE(x -= rs.x, y -= rs.y, z -= rs.z, i -= rs.i, j -= rs.j, k -= rs.k, u -= rs.u, v -= rs.v, w -= rs.w); return *this; } - FI XYZval& operator*=(const XYZEval &rs) { NUM_AXIS_CODE(x *= rs.x, y *= rs.y, z *= rs.z, i *= rs.i, j *= rs.j, k *= rs.k, u *= rs.u, v *= rs.v, w *= rs.w); return *this; } - FI XYZval& operator/=(const XYZEval &rs) { NUM_AXIS_CODE(x /= rs.x, y /= rs.y, z /= rs.z, i /= rs.i, j /= rs.j, k /= rs.k, u /= rs.u, v /= rs.v, w /= rs.w); return *this; } - FI XYZval& operator*=(const float &p) { NUM_AXIS_CODE(x *= p, y *= p, z *= p, i *= p, j *= p, k *= p, u *= p, v *= p, w *= p); return *this; } - FI XYZval& operator*=(const int &p) { NUM_AXIS_CODE(x *= p, y *= p, z *= p, i *= p, j *= p, k *= p, u *= p, v *= p, w *= p); return *this; } - FI XYZval& operator>>=(const int &p) { NUM_AXIS_CODE(_RS(x), _RS(y), _RS(z), _RS(i), _RS(j), _RS(k), _RS(u), _RS(v), _RS(w)); return *this; } - FI XYZval& operator<<=(const int &p) { NUM_AXIS_CODE(_LS(x), _LS(y), _LS(z), _LS(i), _LS(j), _LS(k), _LS(u), _LS(v), _LS(w)); return *this; } + FI XYZval& operator+=(const XYval &rs) { XY_CODE(x += rs.x, y += rs.y); return *this; } + FI XYZval& operator-=(const XYval &rs) { XY_CODE(x -= rs.x, y -= rs.y); return *this; } + FI XYZval& operator*=(const XYval &rs) { XY_CODE(x *= rs.x, y *= rs.y); return *this; } + FI XYZval& operator/=(const XYval &rs) { XY_CODE(x /= rs.x, y /= rs.y); return *this; } + FI XYZval& operator+=(const XYZval &rs) { NUM_AXIS_CODE(x += rs.x, y += rs.y, z += rs.z, i += rs.i, j += rs.j, k += rs.k, u += rs.u, v += rs.v, w += rs.w); return *this; } + FI XYZval& operator-=(const XYZval &rs) { NUM_AXIS_CODE(x -= rs.x, y -= rs.y, z -= rs.z, i -= rs.i, j -= rs.j, k -= rs.k, u -= rs.u, v -= rs.v, w -= rs.w); return *this; } + FI XYZval& operator*=(const XYZval &rs) { NUM_AXIS_CODE(x *= rs.x, y *= rs.y, z *= rs.z, i *= rs.i, j *= rs.j, k *= rs.k, u *= rs.u, v *= rs.v, w *= rs.w); return *this; } + FI XYZval& operator/=(const XYZval &rs) { NUM_AXIS_CODE(x /= rs.x, y /= rs.y, z /= rs.z, i /= rs.i, j /= rs.j, k /= rs.k, u /= rs.u, v /= rs.v, w /= rs.w); return *this; } + FI XYZval& operator+=(const XYZEval &rs) { NUM_AXIS_CODE(x += rs.x, y += rs.y, z += rs.z, i += rs.i, j += rs.j, k += rs.k, u += rs.u, v += rs.v, w += rs.w); return *this; } + FI XYZval& operator-=(const XYZEval &rs) { NUM_AXIS_CODE(x -= rs.x, y -= rs.y, z -= rs.z, i -= rs.i, j -= rs.j, k -= rs.k, u -= rs.u, v -= rs.v, w -= rs.w); return *this; } + FI XYZval& operator*=(const XYZEval &rs) { NUM_AXIS_CODE(x *= rs.x, y *= rs.y, z *= rs.z, i *= rs.i, j *= rs.j, k *= rs.k, u *= rs.u, v *= rs.v, w *= rs.w); return *this; } + FI XYZval& operator/=(const XYZEval &rs) { NUM_AXIS_CODE(x /= rs.x, y /= rs.y, z /= rs.z, i /= rs.i, j /= rs.j, k /= rs.k, u /= rs.u, v /= rs.v, w /= rs.w); return *this; } + FI XYZval& operator*=(const float &p) { NUM_AXIS_CODE(x *= p, y *= p, z *= p, i *= p, j *= p, k *= p, u *= p, v *= p, w *= p); return *this; } + FI XYZval& operator*=(const int &p) { NUM_AXIS_CODE(x *= p, y *= p, z *= p, i *= p, j *= p, k *= p, u *= p, v *= p, w *= p); return *this; } + FI XYZval& operator>>=(const int &p) { NUM_AXIS_CODE(_RSE(x), _RSE(y), _RSE(z), _RSE(i), _RSE(j), _RSE(k), _RSE(u), _RSE(v), _RSE(w)); return *this; } + FI XYZval& operator<<=(const int &p) { NUM_AXIS_CODE(_LSE(x), _LSE(y), _LSE(z), _LSE(i), _LSE(j), _LSE(k), _LSE(u), _LSE(v), _LSE(w)); return *this; } // Exact comparisons. For floats a "NEAR" operation may be better. - FI bool operator==(const XYZEval &rs) const { return true NUM_AXIS_GANG(&& x == rs.x, && y == rs.y, && z == rs.z, && i == rs.i, && j == rs.j, && k == rs.k, && u == rs.u, && v == rs.v, && w == rs.w); } - FI bool operator!=(const XYZEval &rs) const { return !operator==(rs); } + 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 !operator==(rs); } }; // // Logical Axes coordinates, counters, etc. +// May have any number of axes according to configuration, including zero axes. +// When there is no extruder, essentially identical to XYZval. // template struct XYZEval { @@ -618,11 +698,33 @@ struct XYZEval { T pos[LOGICAL_AXES]; }; // Reset all to 0 - FI void reset() { LOGICAL_AXIS_GANG(e =, x =, y =, z =, i =, j =, k =, u =, v =, w =) 0; } + FI void reset() { LOGICAL_AXIS_GANG(e =, x =, y =, z =, i =, j =, k =, u =, v =, w =) 0; } - // Setters for some number of linear axes, not all - FI void set(const T px) { x = px; } - FI void set(const T px, const T py) { x = px; y = py; } + // Setters taking struct types and arrays + FI void set(const XYval pxy) { XY_CODE(x = pxy.x, y = pxy.y); } + FI void set(const XYval pxy, const T pz) { XYZ_CODE(x = pxy.x, y = pxy.y, z = pz); } + FI void set(const XYZval pxyz) { set(NUM_AXIS_ELEM(pxyz)); } + FI void set(const T (&arr)[NUM_AXES]) { NUM_AXIS_CODE(x = arr[0], y = arr[1], z = arr[2], i = arr[3], j = arr[4], k = arr[5], u = arr[6], v = arr[7], w = arr[8]); } + #if LOGICAL_AXES > NUM_AXES + FI void set(const T (&arr)[LOGICAL_AXES]) { LOGICAL_AXIS_CODE(e = arr[LOGICAL_AXES-1], x = arr[0], y = arr[1], z = arr[2], i = arr[3], j = arr[4], k = arr[5], u = arr[6], v = arr[7], w = arr[8]); } + FI void set(const XYval pxy, const T pz, const T pe) { set(pxy, pz); e = pe; } + FI void set(const XYZval pxyz, const T pe) { set(pxyz); e = pe; } + FI void set(LOGICAL_AXIS_ARGS(const T)) { LOGICAL_AXIS_CODE(_e = e, a = x, b = y, c = z, _i = i, _j = j, _k = k, _u = u, _v = v, _w = w); } + #if DISTINCT_AXES > LOGICAL_AXES + FI void set(const T (&arr)[DISTINCT_AXES]) { LOGICAL_AXIS_CODE(e = arr[LOGICAL_AXES-1], x = arr[0], y = arr[1], z = arr[2], i = arr[3], j = arr[4], k = arr[5], u = arr[6], v = arr[7], w = arr[8]); } + #endif + #endif + + // Setter for all individual args + FI void set(NUM_AXIS_ARGS(const T)) { NUM_AXIS_CODE(a = x, b = y, c = z, _i = i, _j = j, _k = k, _u = u, _v = v, _w = w); } + + // Setters with fewer elements leave the rest untouched + #if HAS_Y_AXIS + FI void set(const T px) { x = px; } + #endif + #if HAS_Z_AXIS + FI void set(const T px, const T py) { x = px; y = py; } + #endif #if HAS_I_AXIS FI void set(const T px, const T py, const T pz) { x = px; y = py; z = pz; } #endif @@ -642,46 +744,29 @@ struct XYZEval { FI void set(const T px, const T py, const T pz, const T pi, const T pj, const T pk, const T pu, const T pv) { x = px; y = py; z = pz; i = pi; j = pj; k = pk; u = pu; v = pv; } #endif - // Setters taking struct types and arrays - FI void set(const XYval pxy) { x = pxy.x; y = pxy.y; } - FI void set(const XYZval pxyz) { set(NUM_AXIS_ELEM(pxyz)); } - #if HAS_Z_AXIS - FI void set(NUM_AXIS_ARGS(const T)) { NUM_AXIS_CODE(a = x, b = y, c = z, _i = i, _j = j, _k = k, _u = u, _v = v, _w = w); } - #endif - FI void set(const XYval pxy, const T pz) { set(pxy); TERN_(HAS_Z_AXIS, z = pz); } - #if LOGICAL_AXES > NUM_AXES - FI void set(const XYval pxy, const T pz, const T pe) { set(pxy, pz); e = pe; } - FI void set(const XYZval pxyz, const T pe) { set(pxyz); e = pe; } - FI void set(LOGICAL_AXIS_ARGS(const T)) { LOGICAL_AXIS_CODE(_e = e, a = x, b = y, c = z, _i = i, _j = j, _k = k, _u = u, _v = v, _w = w); } - #endif - // Length reduced to one dimension - FI T magnitude() const { return (T)sqrtf(LOGICAL_AXIS_GANG(+ e*e, + x*x, + y*y, + z*z, + i*i, + j*j, + k*k, + u*u, + v*v, + w*w)); } + FI constexpr T magnitude() const { return (T)sqrtf(LOGICAL_AXIS_GANG(+ e*e, + x*x, + y*y, + z*z, + i*i, + j*j, + k*k, + u*u, + v*v, + w*w)); } // Pointer to the data as a simple array - FI operator T* () { return pos; } + FI operator T* () { return pos; } // If any element is true then it's true - FI operator bool() { return 0 LOGICAL_AXIS_GANG(|| e, || x, || y, || z, || i, || j, || k, || u, || v, || w); } + FI constexpr operator bool() const { return 0 LOGICAL_AXIS_GANG(|| e, || x, || y, || z, || i, || j, || k, || u, || v, || w); } // Smallest element - FI T small() const { return _MIN(LOGICAL_AXIS_LIST(e, x, y, z, i, j, k, u, v, w)); } + FI constexpr T small() const { return _MIN(LOGICAL_AXIS_LIST(e, x, y, z, i, j, k, u, v, w)); } // Largest element - FI T large() const { return _MAX(LOGICAL_AXIS_LIST(e, x, y, z, i, j, k, u, v, w)); } + FI constexpr T large() const { return _MAX(LOGICAL_AXIS_LIST(e, x, y, z, i, j, k, u, v, w)); } // Explicit copy and copies with conversion - FI XYZEval copy() const { XYZEval v = *this; return v; } - FI XYZEval ABS() const { return LOGICAL_AXIS_ARRAY(T(_ABS(e)), T(_ABS(x)), T(_ABS(y)), T(_ABS(z)), T(_ABS(i)), T(_ABS(j)), T(_ABS(k)), T(_ABS(u)), T(_ABS(v)), T(_ABS(w))); } - FI XYZEval asInt() { return LOGICAL_AXIS_ARRAY(int16_t(e), int16_t(x), int16_t(y), int16_t(z), int16_t(i), int16_t(j), int16_t(k), int16_t(u), int16_t(v), int16_t(w)); } - FI XYZEval asInt() const { return LOGICAL_AXIS_ARRAY(int16_t(e), int16_t(x), int16_t(y), int16_t(z), int16_t(i), int16_t(j), int16_t(k), int16_t(u), int16_t(v), int16_t(w)); } - FI XYZEval asLong() { return LOGICAL_AXIS_ARRAY(int32_t(e), int32_t(x), int32_t(y), int32_t(z), int32_t(i), int32_t(j), int32_t(k), int32_t(u), int32_t(v), int32_t(w)); } - FI XYZEval asLong() const { return LOGICAL_AXIS_ARRAY(int32_t(e), int32_t(x), int32_t(y), int32_t(z), int32_t(i), int32_t(j), int32_t(k), int32_t(u), int32_t(v), int32_t(w)); } - FI XYZEval ROUNDL() { return LOGICAL_AXIS_ARRAY(int32_t(LROUND(e)), int32_t(LROUND(x)), int32_t(LROUND(y)), int32_t(LROUND(z)), int32_t(LROUND(i)), int32_t(LROUND(j)), int32_t(LROUND(k)), int32_t(LROUND(u)), int32_t(LROUND(v)), int32_t(LROUND(w))); } - FI XYZEval ROUNDL() const { return LOGICAL_AXIS_ARRAY(int32_t(LROUND(e)), int32_t(LROUND(x)), int32_t(LROUND(y)), int32_t(LROUND(z)), int32_t(LROUND(i)), int32_t(LROUND(j)), int32_t(LROUND(k)), int32_t(LROUND(u)), int32_t(LROUND(v)), int32_t(LROUND(w))); } - FI XYZEval asFloat() { 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 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 XYZEval reciprocal() const { return LOGICAL_AXIS_ARRAY(_RECIP(e), _RECIP(x), _RECIP(y), _RECIP(z), _RECIP(i), _RECIP(j), _RECIP(k), _RECIP(u), _RECIP(v), _RECIP(w)); } + FI constexpr XYZEval copy() const { XYZEval v = *this; return v; } + FI constexpr XYZEval ABS() const { return LOGICAL_AXIS_ARRAY(T(_ABS(e)), T(_ABS(x)), T(_ABS(y)), T(_ABS(z)), T(_ABS(i)), T(_ABS(j)), T(_ABS(k)), T(_ABS(u)), T(_ABS(v)), T(_ABS(w))); } + FI constexpr XYZEval asInt() const { return LOGICAL_AXIS_ARRAY(int16_t(e), int16_t(x), int16_t(y), int16_t(z), int16_t(i), int16_t(j), int16_t(k), int16_t(u), int16_t(v), int16_t(w)); } + FI constexpr XYZEval asLong() const { return LOGICAL_AXIS_ARRAY(int32_t(e), int32_t(x), int32_t(y), int32_t(z), int32_t(i), int32_t(j), int32_t(k), int32_t(u), int32_t(v), int32_t(w)); } + FI constexpr XYZEval ROUNDL() const { return LOGICAL_AXIS_ARRAY(int32_t(LROUND(e)), int32_t(LROUND(x)), int32_t(LROUND(y)), int32_t(LROUND(z)), int32_t(LROUND(i)), int32_t(LROUND(j)), int32_t(LROUND(k)), int32_t(LROUND(u)), int32_t(LROUND(v)), int32_t(LROUND(w))); } + FI constexpr XYZEval asFloat() const { return LOGICAL_AXIS_ARRAY(static_cast(e), static_cast(x), static_cast(y), static_cast(z), static_cast(i), static_cast(j), static_cast(k), static_cast(u), static_cast(v), static_cast(w)); } + FI constexpr XYZEval reciprocal() const { return LOGICAL_AXIS_ARRAY(_RECIP(e), _RECIP(x), _RECIP(y), _RECIP(z), _RECIP(i), _RECIP(j), _RECIP(k), _RECIP(u), _RECIP(v), _RECIP(w)); } // 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; } + 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 FI operator XYval&() { return *(XYval*)this; } @@ -690,80 +775,349 @@ struct XYZEval { FI operator const XYZval&() const { return *(const XYZval*)this; } // Accessor via an AxisEnum (or any integer) [index] - FI T& operator[](const int n) { return pos[n]; } - FI const T& operator[](const int n) const { return pos[n]; } + FI T& operator[](const int n) { return pos[n]; } + FI const T& operator[](const int n) const { return pos[n]; } // Assignment operator overrides do the expected thing - FI XYZEval& operator= (const T v) { set(LOGICAL_AXIS_LIST_1(v)); return *this; } - FI XYZEval& operator= (const XYval &rs) { set(rs.x, rs.y); return *this; } - FI XYZEval& operator= (const XYZval &rs) { set(NUM_AXIS_ELEM(rs)); return *this; } + FI XYZEval& operator= (const T v) { set(LOGICAL_AXIS_LIST_1(v)); return *this; } + FI XYZEval& operator= (const XYval &rs) { set(rs.x, rs.y); return *this; } + FI XYZEval& operator= (const XYZval &rs) { set(NUM_AXIS_ELEM(rs)); return *this; } // Override other operators to get intuitive behaviors - FI XYZEval operator+ (const XYval &rs) const { XYZEval ls = *this; ls.x += rs.x; ls.y += rs.y; return ls; } - FI XYZEval operator+ (const XYval &rs) { XYZEval ls = *this; ls.x += rs.x; ls.y += rs.y; return ls; } - FI XYZEval operator- (const XYval &rs) const { XYZEval ls = *this; ls.x -= rs.x; ls.y -= rs.y; return ls; } - FI XYZEval operator- (const XYval &rs) { XYZEval ls = *this; ls.x -= rs.x; ls.y -= rs.y; return ls; } - FI XYZEval operator* (const XYval &rs) const { XYZEval ls = *this; ls.x *= rs.x; ls.y *= rs.y; return ls; } - FI XYZEval operator* (const XYval &rs) { XYZEval ls = *this; ls.x *= rs.x; ls.y *= rs.y; return ls; } - FI XYZEval operator/ (const XYval &rs) const { XYZEval ls = *this; ls.x /= rs.x; ls.y /= rs.y; return ls; } - FI XYZEval operator/ (const XYval &rs) { XYZEval ls = *this; ls.x /= rs.x; ls.y /= rs.y; return ls; } - FI XYZEval operator+ (const XYZval &rs) const { XYZval ls = *this; NUM_AXIS_CODE(ls.x += rs.x, ls.y += rs.y, ls.z += rs.z, ls.i += rs.i, ls.j += rs.j, ls.k += rs.k, ls.u += rs.u, ls.v += rs.v, ls.w += rs.w); return ls; } - FI XYZEval operator+ (const XYZval &rs) { XYZval ls = *this; NUM_AXIS_CODE(ls.x += rs.x, ls.y += rs.y, ls.z += rs.z, ls.i += rs.i, ls.j += rs.j, ls.k += rs.k, ls.u += rs.u, ls.v += rs.v, ls.w += rs.w); return ls; } - FI XYZEval operator- (const XYZval &rs) const { XYZval ls = *this; NUM_AXIS_CODE(ls.x -= rs.x, ls.y -= rs.y, ls.z -= rs.z, ls.i -= rs.i, ls.j -= rs.j, ls.k -= rs.k, ls.u -= rs.u, ls.v -= rs.v, ls.w -= rs.w); return ls; } - FI XYZEval operator- (const XYZval &rs) { XYZval ls = *this; NUM_AXIS_CODE(ls.x -= rs.x, ls.y -= rs.y, ls.z -= rs.z, ls.i -= rs.i, ls.j -= rs.j, ls.k -= rs.k, ls.u -= rs.u, ls.v -= rs.v, ls.w -= rs.w); return ls; } - FI XYZEval operator* (const XYZval &rs) const { XYZval ls = *this; NUM_AXIS_CODE(ls.x *= rs.x, ls.y *= rs.y, ls.z *= rs.z, ls.i *= rs.i, ls.j *= rs.j, ls.k *= rs.k, ls.u *= rs.u, ls.v *= rs.v, ls.w *= rs.w); return ls; } - FI XYZEval operator* (const XYZval &rs) { XYZval ls = *this; NUM_AXIS_CODE(ls.x *= rs.x, ls.y *= rs.y, ls.z *= rs.z, ls.i *= rs.i, ls.j *= rs.j, ls.k *= rs.k, ls.u *= rs.u, ls.v *= rs.v, ls.w *= rs.w); return ls; } - FI XYZEval operator/ (const XYZval &rs) const { XYZval ls = *this; NUM_AXIS_CODE(ls.x /= rs.x, ls.y /= rs.y, ls.z /= rs.z, ls.i /= rs.i, ls.j /= rs.j, ls.k /= rs.k, ls.u /= rs.u, ls.v /= rs.v, ls.w /= rs.w); return ls; } - FI XYZEval operator/ (const XYZval &rs) { XYZval ls = *this; NUM_AXIS_CODE(ls.x /= rs.x, ls.y /= rs.y, ls.z /= rs.z, ls.i /= rs.i, ls.j /= rs.j, ls.k /= rs.k, ls.u /= rs.u, ls.v /= rs.v, ls.w /= rs.w); return ls; } - FI XYZEval operator+ (const XYZEval &rs) const { XYZEval ls = *this; LOGICAL_AXIS_CODE(ls.e += rs.e, ls.x += rs.x, ls.y += rs.y, ls.z += rs.z, ls.i += rs.i, ls.j += rs.j, ls.k += rs.k, ls.u += rs.u, ls.v += rs.v, ls.w += rs.w); return ls; } - FI XYZEval operator+ (const XYZEval &rs) { XYZEval ls = *this; LOGICAL_AXIS_CODE(ls.e += rs.e, ls.x += rs.x, ls.y += rs.y, ls.z += rs.z, ls.i += rs.i, ls.j += rs.j, ls.k += rs.k, ls.u += rs.u, ls.v += rs.v, ls.w += rs.w); return ls; } - FI XYZEval operator- (const XYZEval &rs) const { XYZEval ls = *this; LOGICAL_AXIS_CODE(ls.e -= rs.e, ls.x -= rs.x, ls.y -= rs.y, ls.z -= rs.z, ls.i -= rs.i, ls.j -= rs.j, ls.k -= rs.k, ls.u -= rs.u, ls.v -= rs.v, ls.w -= rs.w); return ls; } - FI XYZEval operator- (const XYZEval &rs) { XYZEval ls = *this; LOGICAL_AXIS_CODE(ls.e -= rs.e, ls.x -= rs.x, ls.y -= rs.y, ls.z -= rs.z, ls.i -= rs.i, ls.j -= rs.j, ls.k -= rs.k, ls.u -= rs.u, ls.v -= rs.v, ls.w -= rs.w); return ls; } - FI XYZEval operator* (const XYZEval &rs) const { XYZEval ls = *this; LOGICAL_AXIS_CODE(ls.e *= rs.e, ls.x *= rs.x, ls.y *= rs.y, ls.z *= rs.z, ls.i *= rs.i, ls.j *= rs.j, ls.k *= rs.k, ls.u *= rs.u, ls.v *= rs.v, ls.w *= rs.w); return ls; } - FI XYZEval operator* (const XYZEval &rs) { XYZEval ls = *this; LOGICAL_AXIS_CODE(ls.e *= rs.e, ls.x *= rs.x, ls.y *= rs.y, ls.z *= rs.z, ls.i *= rs.i, ls.j *= rs.j, ls.k *= rs.k, ls.u *= rs.u, ls.v *= rs.v, ls.w *= rs.w); return ls; } - FI XYZEval operator/ (const XYZEval &rs) const { XYZEval ls = *this; LOGICAL_AXIS_CODE(ls.e /= rs.e, ls.x /= rs.x, ls.y /= rs.y, ls.z /= rs.z, ls.i /= rs.i, ls.j /= rs.j, ls.k /= rs.k, ls.u /= rs.u, ls.v /= rs.v, ls.w /= rs.w); return ls; } - FI XYZEval operator/ (const XYZEval &rs) { XYZEval ls = *this; LOGICAL_AXIS_CODE(ls.e /= rs.e, ls.x /= rs.x, ls.y /= rs.y, ls.z /= rs.z, ls.i /= rs.i, ls.j /= rs.j, ls.k /= rs.k, ls.u /= rs.u, ls.v /= rs.v, ls.w /= rs.w); return ls; } - FI XYZEval operator* (const float &p) const { XYZEval ls = *this; LOGICAL_AXIS_CODE(ls.e *= p, ls.x *= p, ls.y *= p, ls.z *= p, ls.i *= p, ls.j *= p, ls.k *= p, ls.u *= p, ls.v *= p, ls.w *= p ); return ls; } - FI XYZEval operator* (const float &p) { XYZEval ls = *this; LOGICAL_AXIS_CODE(ls.e *= p, ls.x *= p, ls.y *= p, ls.z *= p, ls.i *= p, ls.j *= p, ls.k *= p, ls.u *= p, ls.v *= p, ls.w *= p ); return ls; } - FI XYZEval operator* (const int &p) const { XYZEval ls = *this; LOGICAL_AXIS_CODE(ls.e *= p, ls.x *= p, ls.y *= p, ls.z *= p, ls.i *= p, ls.j *= p, ls.k *= p, ls.u *= p, ls.v *= p, ls.w *= p ); return ls; } - FI XYZEval operator* (const int &p) { XYZEval ls = *this; LOGICAL_AXIS_CODE(ls.e *= p, ls.x *= p, ls.y *= p, ls.z *= p, ls.i *= p, ls.j *= p, ls.k *= p, ls.u *= p, ls.v *= p, ls.w *= p ); return ls; } - FI XYZEval operator/ (const float &p) const { XYZEval ls = *this; LOGICAL_AXIS_CODE(ls.e /= p, ls.x /= p, ls.y /= p, ls.z /= p, ls.i /= p, ls.j /= p, ls.k /= p, ls.u /= p, ls.v /= p, ls.w /= p ); return ls; } - FI XYZEval operator/ (const float &p) { XYZEval ls = *this; LOGICAL_AXIS_CODE(ls.e /= p, ls.x /= p, ls.y /= p, ls.z /= p, ls.i /= p, ls.j /= p, ls.k /= p, ls.u /= p, ls.v /= p, ls.w /= p ); return ls; } - FI XYZEval operator/ (const int &p) const { XYZEval ls = *this; LOGICAL_AXIS_CODE(ls.e /= p, ls.x /= p, ls.y /= p, ls.z /= p, ls.i /= p, ls.j /= p, ls.k /= p, ls.u /= p, ls.v /= p, ls.w /= p ); return ls; } - FI XYZEval operator/ (const int &p) { XYZEval ls = *this; LOGICAL_AXIS_CODE(ls.e /= p, ls.x /= p, ls.y /= p, ls.z /= p, ls.i /= p, ls.j /= p, ls.k /= p, ls.u /= p, ls.v /= p, ls.w /= p ); return ls; } - FI XYZEval operator>>(const int &p) const { XYZEval ls = *this; LOGICAL_AXIS_CODE(_RS(ls.e), _RS(ls.x), _RS(ls.y), _RS(ls.z), _RS(ls.i), _RS(ls.j), _RS(ls.k), _RS(ls.u), _RS(ls.v), _RS(ls.w) ); return ls; } - FI XYZEval operator>>(const int &p) { XYZEval ls = *this; LOGICAL_AXIS_CODE(_RS(ls.e), _RS(ls.x), _RS(ls.y), _RS(ls.z), _RS(ls.i), _RS(ls.j), _RS(ls.k), _RS(ls.u), _RS(ls.v), _RS(ls.w) ); return ls; } - FI XYZEval operator<<(const int &p) const { XYZEval ls = *this; LOGICAL_AXIS_CODE(_LS(ls.e), _LS(ls.x), _LS(ls.y), _LS(ls.z), _LS(ls.i), _LS(ls.j), _LS(ls.k), _LS(ls.u), _LS(ls.v), _LS(ls.w) ); return ls; } - FI XYZEval operator<<(const int &p) { XYZEval ls = *this; LOGICAL_AXIS_CODE(_LS(ls.e), _LS(ls.x), _LS(ls.y), _LS(ls.z), _LS(ls.i), _LS(ls.j), _LS(ls.k), _LS(ls.u), _LS(ls.v), _LS(ls.w) ); return ls; } - FI const XYZEval operator-() const { return LOGICAL_AXIS_ARRAY(-e, -x, -y, -z, -i, -j, -k, -u, -v, -w); } - FI XYZEval operator-() { return LOGICAL_AXIS_ARRAY(-e, -x, -y, -z, -i, -j, -k, -u, -v, -w); } + FI constexpr XYZEval operator+ (const XYval &rs) const { return LOGICAL_AXIS_ARRAY(e, x + rs.x, y + rs.y, z, i, j, k, u, v, w); } + FI constexpr XYZEval operator- (const XYval &rs) const { return LOGICAL_AXIS_ARRAY(e, x - rs.x, y - rs.y, z, i, j, k, u, v, w); } + FI constexpr XYZEval operator* (const XYval &rs) const { return LOGICAL_AXIS_ARRAY(e, x * rs.x, y * rs.y, z, i, j, k, u, v, w); } + FI constexpr XYZEval operator/ (const XYval &rs) const { return LOGICAL_AXIS_ARRAY(e, x / rs.x, y / rs.y, z, i, j, k, u, v, w); } + FI constexpr XYZEval operator+ (const XYZval &rs) const { return LOGICAL_AXIS_ARRAY(e, x + rs.x, y + rs.y, z + rs.z, i + rs.i, j + rs.j, k + rs.k, u + rs.u, v + rs.v, w + rs.w); } + FI constexpr XYZEval operator- (const XYZval &rs) const { return LOGICAL_AXIS_ARRAY(e, x - rs.x, y - rs.y, z - rs.z, i - rs.i, j - rs.j, k - rs.k, u - rs.u, v - rs.v, w - rs.w); } + FI constexpr XYZEval operator* (const XYZval &rs) const { return LOGICAL_AXIS_ARRAY(e, x * rs.x, y * rs.y, z * rs.z, i * rs.i, j * rs.j, k * rs.k, u * rs.u, v * rs.v, w * rs.w); } + FI constexpr XYZEval operator/ (const XYZval &rs) const { return LOGICAL_AXIS_ARRAY(e, x / rs.x, y / rs.y, z / rs.z, i / rs.i, j / rs.j, k / rs.k, u / rs.u, v / rs.v, w / rs.w); } + FI constexpr XYZEval operator+ (const XYZEval &rs) const { return LOGICAL_AXIS_ARRAY(e + rs.e, x + rs.x, y + rs.y, z + rs.z, i + rs.i, j + rs.j, k + rs.k, u + rs.u, v + rs.v, w + rs.w); } + FI constexpr XYZEval operator- (const XYZEval &rs) const { return LOGICAL_AXIS_ARRAY(e - rs.e, x - rs.x, y - rs.y, z - rs.z, i - rs.i, j - rs.j, k - rs.k, u - rs.u, v - rs.v, w - rs.w); } + FI constexpr XYZEval operator* (const XYZEval &rs) const { return LOGICAL_AXIS_ARRAY(e * rs.e, x * rs.x, y * rs.y, z * rs.z, i * rs.i, j * rs.j, k * rs.k, u * rs.u, v * rs.v, w * rs.w); } + FI constexpr XYZEval operator/ (const XYZEval &rs) const { return LOGICAL_AXIS_ARRAY(e / rs.e, x / rs.x, y / rs.y, z / rs.z, i / rs.i, j / rs.j, k / rs.k, u / rs.u, v / rs.v, w / rs.w); } + FI constexpr XYZEval operator* (const float &p) const { return LOGICAL_AXIS_ARRAY((T)(e * p), (T)(x * p), (T)(y * p), (T)(z * p), (T)(i * p), (T)(j * p), (T)(k * p), (T)(u * p), (T)(v * p), (T)(w * p)); } + FI constexpr XYZEval operator* (const int &p) const { return LOGICAL_AXIS_ARRAY(e * p, x * p, y * p, z * p, i * p, j * p, k * p, u * p, v * p, w * p); } + FI constexpr XYZEval operator/ (const float &p) const { return LOGICAL_AXIS_ARRAY((T)(e / p), (T)(x / p), (T)(y / p), (T)(z / p), (T)(i / p), (T)(j / p), (T)(k / p), (T)(u / p), (T)(v / p), (T)(w / p)); } + FI constexpr XYZEval operator/ (const int &p) const { return LOGICAL_AXIS_ARRAY(e / p, x / p, y / p, z / p, i / p, j / p, k / p, u / p, v / p, w / p); } + FI constexpr XYZEval operator>>(const int &p) const { return LOGICAL_AXIS_ARRAY(_RS(e), _RS(x), _RS(y), _RS(z), _RS(i), _RS(j), _RS(k), _RS(u), _RS(v), _RS(w)); } + FI constexpr XYZEval operator<<(const int &p) const { return LOGICAL_AXIS_ARRAY(_LS(e), _LS(x), _LS(y), _LS(z), _LS(i), _LS(j), _LS(k), _LS(u), _LS(v), _LS(w)); } + FI constexpr XYZEval operator-() const { return LOGICAL_AXIS_ARRAY(-e, -x, -y, -z, -i, -j, -k, -u, -v, -w); } + + // Absolute difference between two objects + FI constexpr XYZEval diff(const XYZEval &rs) const { return LOGICAL_AXIS_ARRAY(T(_ABS(e - rs.e)), T(_ABS(x - rs.x)), T(_ABS(y - rs.y)), T(_ABS(z - rs.z)), T(_ABS(i - rs.i)), T(_ABS(j - rs.j)), T(_ABS(k - rs.k)), T(_ABS(u - rs.u)), T(_ABS(v - rs.v)), T(_ABS(w - rs.w)) ); } + FI constexpr XYZEval diff(const XYZval &rs) const { return LOGICAL_AXIS_ARRAY(0 , T(_ABS(x - rs.x)), T(_ABS(y - rs.y)), T(_ABS(z - rs.z)), T(_ABS(i - rs.i)), T(_ABS(j - rs.j)), T(_ABS(k - rs.k)), T(_ABS(u - rs.u)), T(_ABS(v - rs.v)), T(_ABS(w - rs.w)) ); } + FI constexpr XYZEval diff(const XYval &rs) const { return LOGICAL_AXIS_ARRAY(0 , T(_ABS(x - rs.x)), T(_ABS(y - rs.y)), z, i, j, k, u, v, w ); } // Modifier operators - FI XYZEval& operator+=(const XYval &rs) { x += rs.x; y += rs.y; return *this; } - FI XYZEval& operator-=(const XYval &rs) { x -= rs.x; y -= rs.y; return *this; } - FI XYZEval& operator*=(const XYval &rs) { x *= rs.x; y *= rs.y; return *this; } - FI XYZEval& operator/=(const XYval &rs) { x /= rs.x; y /= rs.y; return *this; } - FI XYZEval& operator+=(const XYZval &rs) { NUM_AXIS_CODE(x += rs.x, y += rs.y, z += rs.z, i += rs.i, j += rs.j, k += rs.k, u += rs.u, v += rs.v, w += rs.w); return *this; } - FI XYZEval& operator-=(const XYZval &rs) { NUM_AXIS_CODE(x -= rs.x, y -= rs.y, z -= rs.z, i -= rs.i, j -= rs.j, k -= rs.k, u -= rs.u, v -= rs.v, w -= rs.w); return *this; } - FI XYZEval& operator*=(const XYZval &rs) { NUM_AXIS_CODE(x *= rs.x, y *= rs.y, z *= rs.z, i *= rs.i, j *= rs.j, k *= rs.k, u *= rs.u, v *= rs.v, w *= rs.w); return *this; } - FI XYZEval& operator/=(const XYZval &rs) { NUM_AXIS_CODE(x /= rs.x, y /= rs.y, z /= rs.z, i /= rs.i, j /= rs.j, k /= rs.k, u /= rs.u, v /= rs.v, w /= rs.w); return *this; } - FI XYZEval& operator+=(const XYZEval &rs) { LOGICAL_AXIS_CODE(e += rs.e, x += rs.x, y += rs.y, z += rs.z, i += rs.i, j += rs.j, k += rs.k, u += rs.u, v += rs.v, w += rs.w); return *this; } - FI XYZEval& operator-=(const XYZEval &rs) { LOGICAL_AXIS_CODE(e -= rs.e, x -= rs.x, y -= rs.y, z -= rs.z, i -= rs.i, j -= rs.j, k -= rs.k, u -= rs.u, v -= rs.v, w -= rs.w); return *this; } - FI XYZEval& operator*=(const XYZEval &rs) { LOGICAL_AXIS_CODE(e *= rs.e, x *= rs.x, y *= rs.y, z *= rs.z, i *= rs.i, j *= rs.j, k *= rs.k, u *= rs.u, v *= rs.v, w *= rs.w); return *this; } - FI XYZEval& operator/=(const XYZEval &rs) { LOGICAL_AXIS_CODE(e /= rs.e, x /= rs.x, y /= rs.y, z /= rs.z, i /= rs.i, j /= rs.j, k /= rs.k, u /= rs.u, v /= rs.v, w /= rs.w); return *this; } - FI XYZEval& operator*=(const T &p) { LOGICAL_AXIS_CODE(e *= p, x *= p, y *= p, z *= p, i *= p, j *= p, k *= p, u *= p, v *= p, w *= p); return *this; } - FI XYZEval& operator>>=(const int &p) { LOGICAL_AXIS_CODE(_RS(e), _RS(x), _RS(y), _RS(z), _RS(i), _RS(j), _RS(k), _RS(u), _RS(v), _RS(w)); return *this; } - FI XYZEval& operator<<=(const int &p) { LOGICAL_AXIS_CODE(_LS(e), _LS(x), _LS(y), _LS(z), _LS(i), _LS(j), _LS(k), _LS(u), _LS(v), _LS(w)); return *this; } + FI XYZEval& operator+=(const XYval &rs) { XY_CODE(x += rs.x, y += rs.y); return *this; } + FI XYZEval& operator-=(const XYval &rs) { XY_CODE(x -= rs.x, y -= rs.y); return *this; } + FI XYZEval& operator*=(const XYval &rs) { XY_CODE(x *= rs.x, y *= rs.y); return *this; } + FI XYZEval& operator/=(const XYval &rs) { XY_CODE(x /= rs.x, y /= rs.y); return *this; } + FI XYZEval& operator+=(const XYZval &rs) { NUM_AXIS_CODE(x += rs.x, y += rs.y, z += rs.z, i += rs.i, j += rs.j, k += rs.k, u += rs.u, v += rs.v, w += rs.w); return *this; } + FI XYZEval& operator-=(const XYZval &rs) { NUM_AXIS_CODE(x -= rs.x, y -= rs.y, z -= rs.z, i -= rs.i, j -= rs.j, k -= rs.k, u -= rs.u, v -= rs.v, w -= rs.w); return *this; } + FI XYZEval& operator*=(const XYZval &rs) { NUM_AXIS_CODE(x *= rs.x, y *= rs.y, z *= rs.z, i *= rs.i, j *= rs.j, k *= rs.k, u *= rs.u, v *= rs.v, w *= rs.w); return *this; } + FI XYZEval& operator/=(const XYZval &rs) { NUM_AXIS_CODE(x /= rs.x, y /= rs.y, z /= rs.z, i /= rs.i, j /= rs.j, k /= rs.k, u /= rs.u, v /= rs.v, w /= rs.w); return *this; } + FI XYZEval& operator+=(const XYZEval &rs) { LOGICAL_AXIS_CODE(e += rs.e, x += rs.x, y += rs.y, z += rs.z, i += rs.i, j += rs.j, k += rs.k, u += rs.u, v += rs.v, w += rs.w); return *this; } + FI XYZEval& operator-=(const XYZEval &rs) { LOGICAL_AXIS_CODE(e -= rs.e, x -= rs.x, y -= rs.y, z -= rs.z, i -= rs.i, j -= rs.j, k -= rs.k, u -= rs.u, v -= rs.v, w -= rs.w); return *this; } + FI XYZEval& operator*=(const XYZEval &rs) { LOGICAL_AXIS_CODE(e *= rs.e, x *= rs.x, y *= rs.y, z *= rs.z, i *= rs.i, j *= rs.j, k *= rs.k, u *= rs.u, v *= rs.v, w *= rs.w); return *this; } + FI XYZEval& operator/=(const XYZEval &rs) { LOGICAL_AXIS_CODE(e /= rs.e, x /= rs.x, y /= rs.y, z /= rs.z, i /= rs.i, j /= rs.j, k /= rs.k, u /= rs.u, v /= rs.v, w /= rs.w); return *this; } + FI XYZEval& operator*=(const T &p) { LOGICAL_AXIS_CODE(e *= p, x *= p, y *= p, z *= p, i *= p, j *= p, k *= p, u *= p, v *= p, w *= p); return *this; } + FI XYZEval& operator>>=(const int &p) { LOGICAL_AXIS_CODE(_RSE(e), _RSE(x), _RSE(y), _RSE(z), _RSE(i), _RSE(j), _RSE(k), _RSE(u), _RSE(v), _RSE(w)); return *this; } + FI XYZEval& operator<<=(const int &p) { LOGICAL_AXIS_CODE(_LSE(e), _LSE(x), _LSE(y), _LSE(z), _LSE(i), _LSE(j), _LSE(k), _LSE(u), _LSE(v), _LSE(w)); return *this; } // Exact comparisons. For floats a "NEAR" operation may be better. - FI bool operator==(const XYZval &rs) const { return true NUM_AXIS_GANG(&& x == rs.x, && y == rs.y, && z == rs.z, && i == rs.i, && j == rs.j, && k == rs.k, && u == rs.u, && v == rs.v, && w == rs.w); } - FI bool operator==(const XYZEval &rs) const { return true LOGICAL_AXIS_GANG(&& e == rs.e, && x == rs.x, && y == rs.y, && z == rs.z, && i == rs.i, && j == rs.j, && k == rs.k, && u == rs.u, && v == rs.v, && w == rs.w); } - FI bool operator!=(const XYZval &rs) const { return !operator==(rs); } - FI bool operator!=(const XYZEval &rs) const { return !operator==(rs); } + FI bool operator==(const XYZval &rs) const { return true NUM_AXIS_GANG(&& x == rs.x, && y == rs.y, && z == rs.z, && i == rs.i, && j == rs.j, && k == rs.k, && u == rs.u, && v == rs.v, && w == rs.w); } + FI bool operator==(const XYZEval &rs) const { return true LOGICAL_AXIS_GANG(&& e == rs.e, && x == rs.x, && y == rs.y, && z == rs.z, && i == rs.i, && j == rs.j, && k == rs.k, && u == rs.u, && v == rs.v, && w == rs.w); } + FI bool operator!=(const XYZval &rs) const { return !operator==(rs); } + FI bool operator!=(const XYZEval &rs) const { return !operator==(rs); } +}; + +#include // for memset + +template +struct XYZarray { + typedef T el[SIZE]; + union { + el data[LOGICAL_AXES]; + struct { NUM_AXIS_CODE(T x, T y, T z, T i, T j, T k, T u, T v, T w); }; + struct { NUM_AXIS_CODE(T a, T b, T c, T _i, T _j, T _k, T _u, T _v, T _w); }; + }; + FI void reset() { ZERO(data); } + + FI void set(const int n, const XYval p) { NUM_AXIS_CODE(x[n]=p.x, y[n]=p.y,,,,,,,); } + FI void set(const int n, const XYZval p) { NUM_AXIS_CODE(x[n]=p.x, y[n]=p.y, z[n]=p.z, i[n]=p.i, j[n]=p.j, k[n]=p.k, u[n]=p.u, v[n]=p.v, w[n]=p.w ); } + FI void set(const int n, const XYZEval p) { NUM_AXIS_CODE(x[n]=p.x, y[n]=p.y, z[n]=p.z, i[n]=p.i, j[n]=p.j, k[n]=p.k, u[n]=p.u, v[n]=p.v, w[n]=p.w ); } + + // Setter for all individual args + FI void set(const int n OPTARGS_NUM(const T)) { NUM_AXIS_CODE(a[n] = x, b[n] = y, c[n] = z, _i[n] = i, _j[n] = j, _k[n] = k, _u[n] = u, _v[n] = v, _w[n] = w); } + + // Setters with fewer elements leave the rest untouched + #if HAS_Y_AXIS + FI void set(const int n, const T px) { x[n] = px; } + #endif + #if HAS_Z_AXIS + FI void set(const int n, const T px, const T py) { x[n] = px; y[n] = py; } + #endif + #if HAS_I_AXIS + FI void set(const int n, const T px, const T py, const T pz) { x[n] = px; y[n] = py; z[n] = pz; } + #endif + #if HAS_J_AXIS + FI void set(const int n, const T px, const T py, const T pz, const T pi) { x[n] = px; y[n] = py; z[n] = pz; i[n] = pi; } + #endif + #if HAS_K_AXIS + FI void set(const int n, const T px, const T py, const T pz, const T pi, const T pj) { x[n] = px; y[n] = py; z[n] = pz; i[n] = pi; j[n] = pj; } + #endif + #if HAS_U_AXIS + FI void set(const int n, const T px, const T py, const T pz, const T pi, const T pj, const T pk) { x[n] = px; y[n] = py; z[n] = pz; i[n] = pi; j[n] = pj; k[n] = pk; } + #endif + #if HAS_V_AXIS + FI void set(const int n, const T px, const T py, const T pz, const T pi, const T pj, const T pk, const T pu) { x[n] = px; y[n] = py; z[n] = pz; i[n] = pi; j[n] = pj; k[n] = pk; u[n] = pu; } + #endif + #if HAS_W_AXIS + FI void set(const int n, const T px, const T py, const T pz, const T pi, const T pj, const T pk, const T pu, const T pv) { x[n] = px; y[n] = py; z[n] = pz; i[n] = pi; j[n] = pj; k[n] = pk; u[n] = pu; v[n] = pv; } + #endif + + FI XYZval operator[](const int n) const { return XYZval(NUM_AXIS_ARRAY(x[n], y[n], z[n], i[n], j[n], k[n], u[n], v[n], w[n])); } +}; + +template +struct XYZEarray { + typedef T el[SIZE]; + union { + el data[LOGICAL_AXES]; + struct { el LOGICAL_AXIS_ARGS(); }; + struct { el LOGICAL_AXIS_LIST(_e, a, b, c, _i, _j, _k, _u, _v, _w); }; + }; + FI void reset() { ZERO(data); } + + FI void set(const int n, const XYval p) { NUM_AXIS_CODE(x[n]=p.x, y[n]=p.y,,,,,,,); } + FI void set(const int n, const XYZval p) { NUM_AXIS_CODE(x[n]=p.x, y[n]=p.y, z[n]=p.z, i[n]=p.i, j[n]=p.j, k[n]=p.k, u[n]=p.u, v[n]=p.v, w[n]=p.w ); } + FI void set(const int n, const XYZEval p) { LOGICAL_AXIS_CODE(e[n]=p.e, x[n]=p.x, y[n]=p.y, z[n]=p.z, i[n]=p.i, j[n]=p.j, k[n]=p.k, u[n]=p.u, v[n]=p.v, w[n]=p.w ); } + + // Setter for all individual args + FI void set(const int n OPTARGS_NUM(const T)) { NUM_AXIS_CODE(a[n] = x, b[n] = y, c[n] = z, _i[n] = i, _j[n] = j, _k[n] = k, _u[n] = u, _v[n] = v, _w[n] = w); } + #if LOGICAL_AXES > NUM_AXES + FI void set(const int n, LOGICAL_AXIS_ARGS(const T)) { LOGICAL_AXIS_CODE(_e[n] = e, a[n] = x, b[n] = y, c[n] = z, _i[n] = i, _j[n] = j, _k[n] = k, _u[n] = u, _v[n] = v, _w[n] = w); } + #endif + + // Setters with fewer elements leave the rest untouched + #if HAS_Y_AXIS + FI void set(const int n, const T px) { x[n] = px; } + #endif + #if HAS_Z_AXIS + FI void set(const int n, const T px, const T py) { x[n] = px; y[n] = py; } + #endif + #if HAS_I_AXIS + FI void set(const int n, const T px, const T py, const T pz) { x[n] = px; y[n] = py; z[n] = pz; } + #endif + #if HAS_J_AXIS + FI void set(const int n, const T px, const T py, const T pz, const T pi) { x[n] = px; y[n] = py; z[n] = pz; i[n] = pi; } + #endif + #if HAS_K_AXIS + FI void set(const int n, const T px, const T py, const T pz, const T pi, const T pj) { x[n] = px; y[n] = py; z[n] = pz; i[n] = pi; j[n] = pj; } + #endif + #if HAS_U_AXIS + FI void set(const int n, const T px, const T py, const T pz, const T pi, const T pj, const T pk) { x[n] = px; y[n] = py; z[n] = pz; i[n] = pi; j[n] = pj; k[n] = pk; } + #endif + #if HAS_V_AXIS + FI void set(const int n, const T px, const T py, const T pz, const T pi, const T pj, const T pk, const T pu) { x[n] = px; y[n] = py; z[n] = pz; i[n] = pi; j[n] = pj; k[n] = pk; u[n] = pu; } + #endif + #if HAS_W_AXIS + FI void set(const int n, const T px, const T py, const T pz, const T pi, const T pj, const T pk, const T pu, const T pv) { x[n] = px; y[n] = py; z[n] = pz; i[n] = pi; j[n] = pj; k[n] = pk; u[n] = pu; v[n] = pv; } + #endif + + FI XYZEval operator[](const int n) const { return XYZval(LOGICAL_AXIS_ARRAY(e[n], x[n], y[n], z[n], i[n], j[n], k[n], u[n], v[n], w[n])); } +}; + +class AxisBits; + +class AxisBits { +public: + typedef bits_t(NUM_AXIS_ENUMS) el; + union { + el bits; + // x, y, z ... e0, e1, e2 ... hx, hy, hz + struct { + #if NUM_AXES + bool NUM_AXIS_LIST(x:1, y:1, z:1, i:1, j:1, k:1, u:1, v:1, w:1); + #endif + #define _EN_ITEM(N) bool e##N:1; + REPEAT(EXTRUDERS,_EN_ITEM) + #undef _EN_ITEM + #if ANY(IS_CORE, MARKFORGED_XY, MARKFORGED_YX) + bool hx:1, hy:1, hz:1; + #endif + }; + // X, Y, Z ... E0, E1, E2 ... HX, HY, HZ + struct { + #if NUM_AXES + bool NUM_AXIS_LIST(X:1, Y:1, Z:1, I:1, J:1, K:1, U:1, V:1, W:1); + #endif + #define _EN_ITEM(N) bool E##N:1; + REPEAT(EXTRUDERS,_EN_ITEM) + #undef _EN_ITEM + #if ANY(IS_CORE, MARKFORGED_XY, MARKFORGED_YX) + bool HX:1, HY:1, HZ:1; + #endif + }; + // a, b, c, e ... ha, hb, hc + struct { + bool LOGICAL_AXIS_LIST(e:1, a:1, b:1, c:1, _i:1, _j:1, _k:1, _u:1, _v:1, _w:1); + #if EXTRUDERS > 1 + #define _EN_ITEM(N) bool _e##N:1; + REPEAT_S(1,EXTRUDERS,_EN_ITEM) + #undef _EN_ITEM + #endif + #if ANY(IS_CORE, MARKFORGED_XY, MARKFORGED_YX) + bool ha:1, hb:1, hc:1; + #endif + }; + // A, B, C, E ... HA, HB, HC + struct { + bool LOGICAL_AXIS_LIST(E:1, A:1, B:1, C:1, _I:1, _J:1, _K:1, _U:1, _V:1, _W:1); + #if EXTRUDERS > 1 + #define _EN_ITEM(N) bool _E##N:1; + REPEAT_S(1,EXTRUDERS,_EN_ITEM) + #undef _EN_ITEM + #endif + #if ANY(IS_CORE, MARKFORGED_XY, MARKFORGED_YX) + bool HA:1, HB:1, HC:1; + #endif + }; + }; + + AxisBits() { reset(); } + + // Constructor, setter, and operator= for bit mask + AxisBits(const el p) { set(p); } + FI void set(const el p) { bits = el(p); } + FI AxisBits& operator=(const el p) { set(p); return *this; } + + FI void reset() { set(0); } + FI void fill() { set(_BV(NUM_AXIS_ENUMS) - 1); } + + #define MSET(pE,pX,pY,pZ,pI,pJ,pK,pU,pV,pW) LOGICAL_AXIS_CODE(e=pE, x=pX, y=pY, z=pZ, i=pI, j=pJ, k=pK, u=pU, v=pV, w=pW) + + // Constructor, setter, and operator= for XYZE type + AxisBits(const xyze_bool_t &p) { set(p); } + FI void set(const xyze_bool_t &p) { + MSET(p.e, p.x, p.y, p.z, p.i, p.j, p.k, p.u, p.v, p.w); + } + FI AxisBits& operator=(const xyze_bool_t &p) { set(p); return *this; } + + // Constructor, setter, and operator= for bool array + AxisBits(const bool (&p)[LOGICAL_AXES]) { set(p); } + FI void set(const bool (&p)[LOGICAL_AXES]) { + MSET(p[E_AXIS], p[X_AXIS], p[Y_AXIS], p[Z_AXIS], + p[I_AXIS], p[J_AXIS], p[K_AXIS], + p[U_AXIS], p[V_AXIS], p[W_AXIS]); + } + FI AxisBits& operator=(const bool (&p)[LOGICAL_AXES]) { set(p); return *this; } + + // Constructor, setter, and operator= for undersized bool arrays + #if LOGICAL_AXES > 1 + AxisBits(const bool (&p)[1]) { set(p); } + FI void set(const bool (&p)[1]) { + MSET(0, p[X_AXIS], 0, 0, 0, 0, 0, 0, 0, 0); + } + FI AxisBits& operator=(const bool (&p)[1]) { set(p); return *this; } + #endif + #if LOGICAL_AXES > 2 + AxisBits(const bool (&p)[2]) { set(p); } + FI void set(const bool (&p)[2]) { + MSET(0, p[X_AXIS], p[Y_AXIS], 0, 0, 0, 0, 0, 0, 0); + } + FI AxisBits& operator=(const bool (&p)[2]) { set(p); return *this; } + #endif + #if LOGICAL_AXES > 3 + AxisBits(const bool (&p)[3]) { set(p); } + FI void set(const bool (&p)[3]) { + MSET(0, p[X_AXIS], p[Y_AXIS], p[Z_AXIS], 0, 0, 0, 0, 0, 0); + } + FI AxisBits& operator=(const bool (&p)[3]) { set(p); return *this; } + #endif + #if LOGICAL_AXES > 4 + AxisBits(const bool (&p)[4]) { set(p); } + FI void set(const bool (&p)[4]) { + MSET(0, p[X_AXIS], p[Y_AXIS], p[Z_AXIS], p[I_AXIS], 0, 0, 0, 0, 0); + } + FI AxisBits& operator=(const bool (&p)[4]) { set(p); return *this; } + #endif + #if LOGICAL_AXES > 5 + AxisBits(const bool (&p)[5]) { set(p); } + FI void set(const bool (&p)[5]) { + MSET(0, p[X_AXIS], p[Y_AXIS], p[Z_AXIS], p[I_AXIS], p[J_AXIS], 0, 0, 0, 0); + } + FI AxisBits& operator=(const bool (&p)[5]) { set(p); return *this; } + #endif + #if LOGICAL_AXES > 6 + AxisBits(const bool (&p)[6]) { set(p); } + FI void set(const bool (&p)[6]) { + MSET(0, p[X_AXIS], p[Y_AXIS], p[Z_AXIS], p[I_AXIS], p[J_AXIS], p[K_AXIS], 0, 0, 0); + } + FI AxisBits& operator=(const bool (&p)[6]) { set(p); return *this; } + #endif + #if LOGICAL_AXES > 7 + AxisBits(const bool (&p)[7]) { set(p); } + FI void set(const bool (&p)[7]) { + MSET(0, p[X_AXIS], p[Y_AXIS], p[Z_AXIS], p[I_AXIS], p[J_AXIS], p[K_AXIS], p[U_AXIS], 0, 0); + } + FI AxisBits& operator=(const bool (&p)[7]) { set(p); return *this; } + #endif + #if LOGICAL_AXES > 8 + AxisBits(const bool (&p)[8]) { set(p); } + FI void set(const bool (&p)[8]) { + MSET(0, p[X_AXIS], p[Y_AXIS], p[Z_AXIS], p[I_AXIS], p[J_AXIS], p[K_AXIS], p[U_AXIS], p[V_AXIS], 0); + } + FI AxisBits& operator=(const bool (&p)[8]) { set(p); return *this; } + #endif + #if LOGICAL_AXES > 9 + AxisBits(const bool (&p)[9]) { set(p); } + FI void set(const bool (&p)[9]) { + MSET(0, p[X_AXIS], p[Y_AXIS], p[Z_AXIS], p[I_AXIS], p[J_AXIS], p[K_AXIS], p[U_AXIS], p[V_AXIS], p[W_AXIS]); + } + FI AxisBits& operator=(const bool (&p)[9]) { set(p); return *this; } + #endif + #undef MSET + + FI bool toggle(const AxisEnum n) { TBI(bits, n); return TEST(bits, n); } + FI void bset(const AxisEnum n) { SBI(bits, n); } + FI void bclr(const AxisEnum n) { CBI(bits, n); } + + // Accessor via an AxisEnum (or any integer) [index] + FI bool operator[](const int n) const { return TEST(bits, n); } + FI bool operator[](const AxisEnum n) const { return TEST(bits, n); } + + FI AxisBits& operator|=(const el &p) { bits |= el(p); return *this; } + FI AxisBits& operator&=(const el &p) { bits &= el(p); return *this; } + FI AxisBits& operator^=(const el &p) { bits ^= el(p); return *this; } + + FI AxisBits& operator|=(const AxisBits &p) { bits |= p.bits; return *this; } + FI AxisBits& operator&=(const AxisBits &p) { bits &= p.bits; return *this; } + FI AxisBits& operator^=(const AxisBits &p) { bits ^= p.bits; return *this; } + + FI bool operator==(const AxisBits &p) const { return p.bits == bits; } + FI bool operator!=(const AxisBits &p) const { return p.bits != bits; } + + FI el operator|(const el &p) const { return bits | el(p); } + FI el operator&(const el &p) const { return bits & el(p); } + FI el operator^(const el &p) const { return bits ^ el(p); } + + FI AxisBits operator|(const AxisBits &p) const { return AxisBits(bits | p.bits); } + FI AxisBits operator&(const AxisBits &p) const { return AxisBits(bits & p.bits); } + FI AxisBits operator^(const AxisBits &p) const { return AxisBits(bits ^ p.bits); } + + FI operator bool() const { return !!bits; } + FI operator uint16_t() const { return uint16_t(bits & 0xFFFF); } + FI operator uint32_t() const { return uint32_t(bits); } + }; #undef _RECIP #undef _ABS #undef _LS #undef _RS +#undef _LSE +#undef _RSE #undef FI diff --git a/Marlin/src/core/utility.cpp b/Marlin/src/core/utility.cpp index 64f083e197..8476591d4b 100644 --- a/Marlin/src/core/utility.cpp +++ b/Marlin/src/core/utility.cpp @@ -25,6 +25,10 @@ #include "../MarlinCore.h" #include "../module/temperature.h" +#if ENABLED(MARLIN_DEV_MODE) + MarlinError marlin_error_number; // Error Number - Marlin can beep X times periodically, display, and emit... +#endif + void safe_delay(millis_t ms) { while (ms > 50) { ms -= 50; @@ -95,9 +99,9 @@ void safe_delay(millis_t ms) { SERIAL_ECHOPGM(" (Aligned With"); if (probe.offset_xy.y > 0) - SERIAL_ECHOF(F(TERN(IS_SCARA, "-Distal", "-Back"))); + SERIAL_ECHO(F(TERN(IS_SCARA, "-Distal", "-Back"))); else if (probe.offset_xy.y < 0) - SERIAL_ECHOF(F(TERN(IS_SCARA, "-Proximal", "-Front"))); + SERIAL_ECHO(F(TERN(IS_SCARA, "-Proximal", "-Front"))); else if (probe.offset_xy.x != 0) SERIAL_ECHOPGM("-Center"); @@ -105,7 +109,7 @@ void safe_delay(millis_t ms) { #endif - SERIAL_ECHOF(probe.offset.z < 0 ? F("Below") : probe.offset.z > 0 ? F("Above") : F("Same Z as")); + SERIAL_ECHO(probe.offset.z < 0 ? F("Below") : probe.offset.z > 0 ? F("Above") : F("Same Z as")); SERIAL_ECHOLNPGM(" Nozzle)"); #endif diff --git a/Marlin/src/core/utility.h b/Marlin/src/core/utility.h index 2731e62b67..c3324443ba 100644 --- a/Marlin/src/core/utility.h +++ b/Marlin/src/core/utility.h @@ -33,17 +33,17 @@ void safe_delay(millis_t ms); // Delay ensuring that temperatures are inline void serial_delay(const millis_t) {} #endif -#if (GRID_MAX_POINTS_X) && (GRID_MAX_POINTS_Y) +#if GRID_MAX_POINTS // 16x16 bit arrays template struct FlagBits { - typename IF<(W>8), uint16_t, uint8_t>::type bits[H]; - void fill() { memset(bits, 0xFF, sizeof(bits)); } - void reset() { memset(bits, 0x00, sizeof(bits)); } - void unmark(const uint8_t x, const uint8_t y) { CBI(bits[y], x); } - void mark(const uint8_t x, const uint8_t y) { SBI(bits[y], x); } - bool marked(const uint8_t x, const uint8_t y) { return TEST(bits[y], x); } + bits_t(W) flags[H]; + void fill() { memset(flags, 0xFF, sizeof(flags)); } + void reset() { memset(flags, 0x00, sizeof(flags)); } + void unmark(const uint8_t x, const uint8_t y) { CBI(flags[y], x); } + void mark(const uint8_t x, const uint8_t y) { SBI(flags[y], x); } + bool marked(const uint8_t x, const uint8_t y) { return TEST(flags[y], x); } inline void unmark(const xy_int8_t &xy) { unmark(xy.x, xy.y); } inline void mark(const xy_int8_t &xy) { mark(xy.x, xy.y); } inline bool marked(const xy_int8_t &xy) { return marked(xy.x, xy.y); } @@ -92,3 +92,22 @@ const xyze_char_t axis_codes LOGICAL_AXIS_ARRAY('E', 'X', 'Y', 'Z', AXIS4_NAME, #define AXIS_CHAR(A) axis_codes[A] #define IAXIS_CHAR(A) iaxis_codes[A] #endif + +#if ENABLED(MARLIN_DEV_MODE) + enum MarlinError : uint8_t { + ERR_NONE, + ERR_STRING_RANGE, // A string buffer was too small to set the whole blob + ERR_ASSERTION, // An assertion was triggered + ERR_MALFUNCTION, + ERR_MEMORY_LEAK, + ERR_COMMS_SERIAL, + ERR_COMMS_SPI, + ERR_PLANNER_STARVED, + ERR_TMC_SHUTDOWN, + ERR_PROCEDURE_FAILED, + ERR_TOO_WACK, + ERR_PLAID_IN_SUMMER + }; + extern MarlinError marlin_error_number; // Error Number - Marlin can beep, display, and emit... + inline void error(const MarlinError err) { marlin_error_number = err; } +#endif diff --git a/Marlin/src/feature/babystep.cpp b/Marlin/src/feature/babystep.cpp index 2e3d6a9fd2..c6717268a6 100644 --- a/Marlin/src/feature/babystep.cpp +++ b/Marlin/src/feature/babystep.cpp @@ -26,7 +26,7 @@ #include "babystep.h" #include "../MarlinCore.h" -#include "../module/motion.h" // for axes_should_home() +#include "../module/motion.h" // for axes_should_home(), BABYSTEP_ALLOWED #include "../module/planner.h" // for axis_steps_per_mm[] #include "../module/stepper.h" @@ -42,6 +42,10 @@ volatile int16_t Babystep::steps[BS_AXIS_IND(Z_AXIS) + 1]; #endif int16_t Babystep::accum; +#if ALL(EP_BABYSTEPPING, EMERGENCY_PARSER) + int16_t Babystep::ep_babysteps; +#endif + void Babystep::step_axis(const AxisEnum axis) { const int16_t curTodo = steps[BS_AXIS_IND(axis)]; // get rid of volatile for performance if (curTodo) { @@ -62,7 +66,7 @@ void Babystep::add_mm(const AxisEnum axis, const_float_t mm) { steps[BS_AXIS_IND(axis)] = distance; TERN_(BABYSTEP_DISPLAY_TOTAL, axis_total[BS_TOTAL_IND(axis)] = distance); TERN_(BABYSTEP_ALWAYS_AVAILABLE, gcode.reset_stepper_timeout()); - TERN_(INTEGRATED_BABYSTEPPING, if (has_steps()) stepper.initiateBabystepping()); + TERN_(BABYSTEPPING, if (has_steps()) stepper.initiateBabystepping()); } #endif @@ -73,7 +77,13 @@ void Babystep::add_steps(const AxisEnum axis, const int16_t distance) { steps[BS_AXIS_IND(axis)] += distance; TERN_(BABYSTEP_DISPLAY_TOTAL, axis_total[BS_TOTAL_IND(axis)] += distance); TERN_(BABYSTEP_ALWAYS_AVAILABLE, gcode.reset_stepper_timeout()); - TERN_(INTEGRATED_BABYSTEPPING, if (has_steps()) stepper.initiateBabystepping()); + TERN_(BABYSTEPPING, if (has_steps()) stepper.initiateBabystepping()); } +#if ENABLED(EP_BABYSTEPPING) + // Step Z for M293 / M294 + void Babystep::z_up() { if (BABYSTEP_ALLOWED()) add_steps(Z_AXIS, +BABYSTEP_SIZE_Z); } + void Babystep::z_down() { if (BABYSTEP_ALLOWED()) add_steps(Z_AXIS, -BABYSTEP_SIZE_Z); } +#endif + #endif // BABYSTEPPING diff --git a/Marlin/src/feature/babystep.h b/Marlin/src/feature/babystep.h index bbf0c5a260..38a19a3b14 100644 --- a/Marlin/src/feature/babystep.h +++ b/Marlin/src/feature/babystep.h @@ -23,15 +23,10 @@ #include "../inc/MarlinConfigPre.h" -#if ENABLED(INTEGRATED_BABYSTEPPING) - #define BABYSTEPS_PER_SEC 1000UL - #define BABYSTEP_TICKS ((STEPPER_TIMER_RATE) / (BABYSTEPS_PER_SEC)) -#else - #define BABYSTEPS_PER_SEC 976UL - #define BABYSTEP_TICKS ((TEMP_TIMER_RATE) / (BABYSTEPS_PER_SEC)) -#endif +#define BABYSTEPS_PER_SEC 1000UL +#define BABYSTEP_TICKS ((STEPPER_TIMER_RATE) / (BABYSTEPS_PER_SEC)) -#if IS_CORE || EITHER(BABYSTEP_XY, I2C_POSITION_ENCODERS) +#if ANY(IS_CORE, BABYSTEP_XY, I2C_POSITION_ENCODERS) #define BS_AXIS_IND(A) A #define BS_AXIS(I) AxisEnum(I) #else @@ -52,6 +47,10 @@ public: static volatile int16_t steps[BS_AXIS_IND(Z_AXIS) + 1]; static int16_t accum; // Total babysteps in current edit + #if ALL(EP_BABYSTEPPING, EMERGENCY_PARSER) + static int16_t ep_babysteps; + #endif + #if ENABLED(BABYSTEP_DISPLAY_TOTAL) static int16_t axis_total[BS_TOTAL_IND(Z_AXIS) + 1]; // Total babysteps since G28 static void reset_total(const AxisEnum axis) { @@ -63,6 +62,21 @@ public: static void add_steps(const AxisEnum axis, const int16_t distance); static void add_mm(const AxisEnum axis, const_float_t mm); + #if ENABLED(EP_BABYSTEPPING) + // Step Z for M293 / M294 + static void z_up(); + static void z_down(); + #if ENABLED(EMERGENCY_PARSER) + // Step Z according to steps accumulated by the EP + FORCE_INLINE static void do_ep_steps() { + if (ep_babysteps) { + if (ep_babysteps > 0) { z_up(); ep_babysteps--; } + else { z_down(); ep_babysteps++; } + } + } + #endif + #endif // EP_BABYSTEPPING + #if ENABLED(BD_SENSOR) static void set_mm(const AxisEnum axis, const_float_t mm); #endif @@ -76,7 +90,7 @@ public: // apply accumulated babysteps to the axes. // static void task() { - LOOP_LE_N(i, BS_AXIS_IND(Z_AXIS)) step_axis(BS_AXIS(i)); + for (uint8_t i = 0; i <= BS_AXIS_IND(Z_AXIS); ++i) step_axis(BS_AXIS(i)); } private: diff --git a/Marlin/src/feature/backlash.cpp b/Marlin/src/feature/backlash.cpp index 13e2cd99ec..07fa7725a0 100644 --- a/Marlin/src/feature/backlash.cpp +++ b/Marlin/src/feature/backlash.cpp @@ -29,7 +29,7 @@ #include "../module/motion.h" #include "../module/planner.h" -axis_bits_t Backlash::last_direction_bits; +AxisBits Backlash::last_direction_bits; xyz_long_t Backlash::residual_error{0}; #ifdef BACKLASH_DISTANCE_MM @@ -63,25 +63,25 @@ Backlash backlash; * spread over multiple segments, smoothing out artifacts even more. */ -void Backlash::add_correction_steps(const int32_t &da, const int32_t &db, const int32_t &dc, const axis_bits_t dm, block_t * const block) { - axis_bits_t changed_dir = last_direction_bits ^ dm; +void Backlash::add_correction_steps(const xyze_long_t &dist, const AxisBits dm, block_t * const block) { + AxisBits changed_dir = last_direction_bits ^ dm; // Ignore direction change unless steps are taken in that direction - #if DISABLED(CORE_BACKLASH) || EITHER(MARKFORGED_XY, MARKFORGED_YX) - if (!da) CBI(changed_dir, X_AXIS); - if (!db) CBI(changed_dir, Y_AXIS); - if (!dc) CBI(changed_dir, Z_AXIS); + #if DISABLED(CORE_BACKLASH) || ANY(MARKFORGED_XY, MARKFORGED_YX) + if (!dist.a) changed_dir.x = false; + if (!dist.b) changed_dir.y = false; + if (!dist.c) changed_dir.z = false; #elif CORE_IS_XY - if (!(da + db)) CBI(changed_dir, X_AXIS); - if (!(da - db)) CBI(changed_dir, Y_AXIS); - if (!dc) CBI(changed_dir, Z_AXIS); + if (!(dist.a + dist.b)) changed_dir.x = false; + if (!(dist.a - dist.b)) changed_dir.y = false; + if (!dist.c) changed_dir.z = false; #elif CORE_IS_XZ - if (!(da + dc)) CBI(changed_dir, X_AXIS); - if (!(da - dc)) CBI(changed_dir, Z_AXIS); - if (!db) CBI(changed_dir, Y_AXIS); + if (!(dist.a + dist.c)) changed_dir.x = false; + if (!(dist.a - dist.c)) changed_dir.z = false; + if (!dist.b) changed_dir.y = false; #elif CORE_IS_YZ - if (!(db + dc)) CBI(changed_dir, Y_AXIS); - if (!(db - dc)) CBI(changed_dir, Z_AXIS); - if (!da) CBI(changed_dir, X_AXIS); + if (!(dist.b + dist.c)) changed_dir.y = false; + if (!(dist.b - dist.c)) changed_dir.z = false; + if (!dist.a) changed_dir.x = false; #endif last_direction_bits ^= changed_dir; @@ -97,18 +97,24 @@ void Backlash::add_correction_steps(const int32_t &da, const int32_t &db, const const float f_corr = float(correction) / all_on; + bool changed = false; + float millimeters_delta = 0.0f; + #if IS_KINEMATIC + float sqr_stepper_space_mm = 0.0f; + #endif + LOOP_NUM_AXES(axis) { + TERN_(IS_KINEMATIC, sqr_stepper_space_mm += sq(dist[axis] * planner.mm_per_step[axis])); + if (distance_mm[axis]) { - const bool reverse = TEST(dm, axis); + const bool forward = dm[axis]; // When an axis changes direction, add axis backlash to the residual error - if (TEST(changed_dir, axis)) - residual_error[axis] += (reverse ? -f_corr : f_corr) * distance_mm[axis] * planner.settings.axis_steps_per_mm[axis]; + if (changed_dir[axis]) + residual_error[axis] += (forward ? f_corr : -f_corr) * distance_mm[axis] * planner.settings.axis_steps_per_mm[axis]; // Decide how much of the residual error to correct in this segment int32_t error_correction = residual_error[axis]; - if (reverse != (error_correction < 0)) - error_correction = 0; // Don't take up any backlash in this segment, as it would subtract steps #ifdef BACKLASH_SMOOTHING_MM if (error_correction && smoothing_mm != 0) { @@ -118,9 +124,18 @@ void Backlash::add_correction_steps(const int32_t &da, const int32_t &db, const } #endif + // Don't correct backlash in the opposite direction to movement on this axis and for accuracy in + // updating block->millimeters, don't add too many steps to the movement on this axis + if (forward) + LIMIT(error_correction, 0, dist[axis]); + else + LIMIT(error_correction, dist[axis], 0); + // This correction reduces the residual error and adds block steps if (error_correction) { + changed = true; block->steps[axis] += ABS(error_correction); + millimeters_delta += dist[axis] * error_correction * sq(planner.mm_per_step[axis]); #if ENABLED(CORE_BACKLASH) switch (axis) { case CORE_AXIS_1: @@ -142,19 +157,24 @@ void Backlash::add_correction_steps(const int32_t &da, const int32_t &db, const } } } + + // If backlash correction steps were added modify block->millimeters with a linear approximation + // See https://github.com/MarlinFirmware/Marlin/pull/26392 + if (changed) + block->millimeters += TERN(IS_KINEMATIC, millimeters_delta * block->millimeters / sqr_stepper_space_mm, millimeters_delta / block->millimeters); } int32_t Backlash::get_applied_steps(const AxisEnum axis) { if (axis >= NUM_AXES) return 0; - const bool reverse = TEST(last_direction_bits, axis); + const bool forward = last_direction_bits[axis]; const int32_t residual_error_axis = residual_error[axis]; - // At startup it is assumed the last move was forwards. So the applied - // steps will always be a non-positive number. + // At startup it is assumed the last move was forward. + // So the applied steps will always be negative. - if (!reverse) return -residual_error_axis; + if (forward) return -residual_error_axis; const float f_corr = float(correction) / all_on; const int32_t full_error_axis = -f_corr * distance_mm[axis] * planner.settings.axis_steps_per_mm[axis]; diff --git a/Marlin/src/feature/backlash.h b/Marlin/src/feature/backlash.h index 0bace526e5..593e51b9d0 100644 --- a/Marlin/src/feature/backlash.h +++ b/Marlin/src/feature/backlash.h @@ -29,7 +29,7 @@ public: static constexpr uint8_t all_on = 0xFF, all_off = 0x00; private: - static axis_bits_t last_direction_bits; + static AxisBits last_direction_bits; static xyz_long_t residual_error; #if ENABLED(BACKLASH_GCODE) @@ -72,7 +72,7 @@ public: return has_measurement(X_AXIS) || has_measurement(Y_AXIS) || has_measurement(Z_AXIS); } - static void add_correction_steps(const int32_t &da, const int32_t &db, const int32_t &dc, const axis_bits_t dm, block_t * const block); + static void add_correction_steps(const xyze_long_t &dist, const AxisBits dm, block_t * const block); static int32_t get_applied_steps(const AxisEnum axis); #if ENABLED(BACKLASH_GCODE) diff --git a/Marlin/src/feature/bedlevel/abl/bbl.cpp b/Marlin/src/feature/bedlevel/abl/bbl.cpp index be0e862cc1..14c4bd24bc 100644 --- a/Marlin/src/feature/bedlevel/abl/bbl.cpp +++ b/Marlin/src/feature/bedlevel/abl/bbl.cpp @@ -133,8 +133,8 @@ void LevelingBilinear::extrapolate_unprobed_bed_level() { yend = ctry1; #endif - LOOP_LE_N(xo, xend) - LOOP_LE_N(yo, yend) { + for (uint8_t xo = 0; xo <= xend; ++xo) + for (uint8_t yo = 0; yo <= yend; ++yo) { uint8_t x2 = ctrx2 + xo, y2 = ctry2 + yo; #ifndef HALF_IN_X const uint8_t x1 = ctrx1 - xo; @@ -153,7 +153,7 @@ void LevelingBilinear::extrapolate_unprobed_bed_level() { } } -void LevelingBilinear::print_leveling_grid(const bed_mesh_t* _z_values /*= NULL*/) { +void LevelingBilinear::print_leveling_grid(const bed_mesh_t* _z_values/*=nullptr*/) { // print internal grid(s) or just the one passed as a parameter SERIAL_ECHOLNPGM("Bilinear Leveling Grid:"); print_2d_array(GRID_MAX_POINTS_X, GRID_MAX_POINTS_Y, 3, _z_values ? *_z_values[0] : z_values[0]); @@ -175,13 +175,13 @@ void LevelingBilinear::print_leveling_grid(const bed_mesh_t* _z_values /*= NULL* xy_float_t LevelingBilinear::grid_factor_virt; #define LINEAR_EXTRAPOLATION(E, I) ((E) * 2 - (I)) - float LevelingBilinear::bed_level_virt_coord(const uint8_t x, const uint8_t y) { + float LevelingBilinear::virt_coord(const uint8_t x, const uint8_t y) { uint8_t ep = 0, ip = 1; if (x > (GRID_MAX_POINTS_X) + 1 || y > (GRID_MAX_POINTS_Y) + 1) { // The requested point requires extrapolating two points beyond the mesh. // These values are only requested for the edges of the mesh, which are always an actual mesh point, // and do not require interpolation. When interpolation is not needed, this "Mesh + 2" point is - // cancelled out in bed_level_virt_cmr and does not impact the result. Return 0.0 rather than + // cancelled out in virt_cmr and does not impact the result. Return 0.0 rather than // making this function more complex by extrapolating two points. return 0.0; } @@ -197,8 +197,8 @@ void LevelingBilinear::print_leveling_grid(const bed_mesh_t* _z_values /*= NULL* ); else return LINEAR_EXTRAPOLATION( - bed_level_virt_coord(ep + 1, y), - bed_level_virt_coord(ip + 1, y) + virt_coord(ep + 1, y), + virt_coord(ip + 1, y) ); } if (!y || y == ABL_TEMP_POINTS_Y - 1) { @@ -213,14 +213,14 @@ void LevelingBilinear::print_leveling_grid(const bed_mesh_t* _z_values /*= NULL* ); else return LINEAR_EXTRAPOLATION( - bed_level_virt_coord(x, ep + 1), - bed_level_virt_coord(x, ip + 1) + virt_coord(x, ep + 1), + virt_coord(x, ip + 1) ); } return z_values[x - 1][y - 1]; } - float LevelingBilinear::bed_level_virt_cmr(const float p[4], const uint8_t i, const float t) { + float LevelingBilinear::virt_cmr(const float p[4], const uint8_t i, const float t) { return ( p[i-1] * -t * sq(1 - t) + p[i] * (2 - 5 * sq(t) + 3 * t * sq(t)) @@ -229,33 +229,28 @@ void LevelingBilinear::print_leveling_grid(const bed_mesh_t* _z_values /*= NULL* ) * 0.5f; } - float LevelingBilinear::bed_level_virt_2cmr(const uint8_t x, const uint8_t y, const_float_t tx, const_float_t ty) { + float LevelingBilinear::virt_2cmr(const uint8_t x, const uint8_t y, const_float_t tx, const_float_t ty) { float row[4], column[4]; - LOOP_L_N(i, 4) { - LOOP_L_N(j, 4) { - column[j] = bed_level_virt_coord(i + x - 1, j + y - 1); + for (uint8_t i = 0; i < 4; ++i) { + for (uint8_t j = 0; j < 4; ++j) { + column[j] = virt_coord(i + x - 1, j + y - 1); } - row[i] = bed_level_virt_cmr(column, 1, ty); + row[i] = virt_cmr(column, 1, ty); } - return bed_level_virt_cmr(row, 1, tx); + return virt_cmr(row, 1, tx); } - void LevelingBilinear::bed_level_virt_interpolate() { + void LevelingBilinear::subdivide_mesh() { grid_spacing_virt = grid_spacing / (BILINEAR_SUBDIVISIONS); grid_factor_virt = grid_spacing_virt.reciprocal(); - LOOP_L_N(y, GRID_MAX_POINTS_Y) - LOOP_L_N(x, GRID_MAX_POINTS_X) - LOOP_L_N(ty, BILINEAR_SUBDIVISIONS) - LOOP_L_N(tx, BILINEAR_SUBDIVISIONS) { + for (uint8_t y = 0; y < GRID_MAX_POINTS_Y; ++y) + for (uint8_t x = 0; x < GRID_MAX_POINTS_X; ++x) + for (uint8_t ty = 0; ty < BILINEAR_SUBDIVISIONS; ++ty) + for (uint8_t tx = 0; tx < BILINEAR_SUBDIVISIONS; ++tx) { if ((ty && y == (GRID_MAX_POINTS_Y) - 1) || (tx && x == (GRID_MAX_POINTS_X) - 1)) continue; z_values_virt[x * (BILINEAR_SUBDIVISIONS) + tx][y * (BILINEAR_SUBDIVISIONS) + ty] = - bed_level_virt_2cmr( - x + 1, - y + 1, - (float)tx / (BILINEAR_SUBDIVISIONS), - (float)ty / (BILINEAR_SUBDIVISIONS) - ); + virt_2cmr(x + 1, y + 1, (float)tx / (BILINEAR_SUBDIVISIONS), (float)ty / (BILINEAR_SUBDIVISIONS)); } } @@ -263,7 +258,7 @@ void LevelingBilinear::print_leveling_grid(const bed_mesh_t* _z_values /*= NULL* // Refresh after other values have been updated void LevelingBilinear::refresh_bed_level() { - TERN_(ABL_BILINEAR_SUBDIVISION, bed_level_virt_interpolate()); + TERN_(ABL_BILINEAR_SUBDIVISION, subdivide_mesh()); cached_rel.x = cached_rel.y = -999.999; cached_g.x = cached_g.y = -99; } diff --git a/Marlin/src/feature/bedlevel/abl/bbl.h b/Marlin/src/feature/bedlevel/abl/bbl.h index c2be4fee82..ca2e96593f 100644 --- a/Marlin/src/feature/bedlevel/abl/bbl.h +++ b/Marlin/src/feature/bedlevel/abl/bbl.h @@ -43,17 +43,17 @@ private: static xy_pos_t grid_spacing_virt; static xy_float_t grid_factor_virt; - static float bed_level_virt_coord(const uint8_t x, const uint8_t y); - static float bed_level_virt_cmr(const float p[4], const uint8_t i, const float t); - static float bed_level_virt_2cmr(const uint8_t x, const uint8_t y, const_float_t tx, const_float_t ty); - static void bed_level_virt_interpolate(); + static float virt_coord(const uint8_t x, const uint8_t y); + static float virt_cmr(const float p[4], const uint8_t i, const float t); + static float virt_2cmr(const uint8_t x, const uint8_t y, const_float_t tx, const_float_t ty); + static void subdivide_mesh(); #endif public: static void reset(); static void set_grid(const xy_pos_t& _grid_spacing, const xy_pos_t& _grid_start); static void extrapolate_unprobed_bed_level(); - static void print_leveling_grid(const bed_mesh_t* _z_values = NULL); + static void print_leveling_grid(const bed_mesh_t *_z_values=nullptr); static void refresh_bed_level(); static bool has_mesh() { return !!grid_spacing.x; } static bool mesh_is_valid() { return has_mesh(); } diff --git a/Marlin/src/feature/bedlevel/bdl/bdl.cpp b/Marlin/src/feature/bedlevel/bdl/bdl.cpp index 1a27011a4b..d469bb0c06 100644 --- a/Marlin/src/feature/bedlevel/bdl/bdl.cpp +++ b/Marlin/src/feature/bedlevel/bdl/bdl.cpp @@ -34,6 +34,7 @@ #include "../../../module/temperature.h" #include "../../../module/endstops.h" #include "../../babystep.h" +#include "../../../lcd/marlinui.h" // I2C software Master library for segment bed heating and bed distance sensor #include @@ -42,6 +43,8 @@ BDS_Leveling bdl; //#define DEBUG_OUT_BD +#define DEBUG_OUT ENABLED(DEBUG_OUT_BD) +#include "../../../core/debug_out.h" // M102 S-5 Read raw Calibrate data // M102 S-6 Start Calibrate @@ -49,144 +52,199 @@ BDS_Leveling bdl; // M102 S-1 Read sensor information #define MAX_BD_HEIGHT 4.0f +#define CMD_READ_VERSION 1016 #define CMD_START_READ_CALIBRATE_DATA 1017 #define CMD_END_READ_CALIBRATE_DATA 1018 #define CMD_START_CALIBRATE 1019 #define CMD_END_CALIBRATE 1021 -#define CMD_READ_VERSION 1016 - -I2C_SegmentBED BD_I2C_SENSOR; - #define BD_SENSOR_I2C_ADDR 0x3C +I2C_SegmentBED BD_I2C_SENSOR; +float BDS_Leveling::pos_zero_offset; int8_t BDS_Leveling::config_state; -uint8_t BDS_Leveling::homing; - -void BDS_Leveling::echo_name() { SERIAL_ECHOPGM("Bed Distance Leveling"); } void BDS_Leveling::init(uint8_t _sda, uint8_t _scl, uint16_t delay_s) { - int ret = BD_I2C_SENSOR.i2c_init(_sda, _scl, BD_SENSOR_I2C_ADDR, delay_s); - if (ret != 1) SERIAL_ECHOLNPGM("BD_I2C_SENSOR Init Fail return code:", ret); - config_state = 0; + config_state = BDS_IDLE; + const int ret = BD_I2C_SENSOR.i2c_init(_sda, _scl, BD_SENSOR_I2C_ADDR, delay_s); + if (ret != 1) SERIAL_ECHOLNPGM("BD Sensor Init Fail (", ret, ")"); + sync_plan_position(); + pos_zero_offset = planner.get_axis_position_mm(Z_AXIS) - current_position.z; + SERIAL_ECHOLNPGM("BD Sensor Zero Offset:", pos_zero_offset); +} + +bool BDS_Leveling::check(const uint16_t data, const bool raw_data/*=false*/, const bool hicheck/*=false*/) { + if (BD_I2C_SENSOR.BD_Check_OddEven(data) == 0) { + SERIAL_ECHOLNPGM("Read Error."); + return true; // error + } + if (raw_data == true) { + if (hicheck && (data & 0x3FF) > 400) + SERIAL_ECHOLNPGM("Bad BD Sensor height! Recommended distance 0.5-2.0mm"); + else if (!good_data(data)) + SERIAL_ECHOLNPGM("Invalid data, please calibrate."); + else + return false; + } + else { + if ((data & 0x3FF) >= (MAX_BD_HEIGHT) * 100 - 10) + SERIAL_ECHOLNPGM("Out of Range."); + else + return false; + } + return true; // error +} + +float BDS_Leveling::interpret(const uint16_t data) { + return (data & 0x3FF) / 100.0f; } float BDS_Leveling::read() { - const uint16_t tmp = BD_I2C_SENSOR.BD_i2c_read(); - float BD_z = NAN; - if (BD_I2C_SENSOR.BD_Check_OddEven(tmp) && (tmp & 0x3FF) < 1020) - BD_z = (tmp & 0x3FF) / 100.0f; - return BD_z; + const uint16_t data = BD_I2C_SENSOR.BD_i2c_read(); + return check(data) ? NAN : interpret(data); } void BDS_Leveling::process() { - //if (config_state == 0) return; - static millis_t next_check_ms = 0; // starting at T=0 - static float z_pose = 0.0f; - const millis_t ms = millis(); - if (ELAPSED(ms, next_check_ms)) { // timed out (or first run) - next_check_ms = ms + (config_state < 0 ? 1000 : 100); // check at 1Hz or 10Hz - - unsigned short tmp = 0; - const float cur_z = planner.get_axis_position_mm(Z_AXIS); //current_position.z - static float old_cur_z = cur_z, - old_buf_z = current_position.z; + if (config_state == BDS_IDLE && printingIsActive()) return; + static millis_t next_check_ms = 0; // starting at T=0 + static float zpos = 0.0f; + const millis_t ms = millis(); + if (ELAPSED(ms, next_check_ms)) { // timed out (or first run) + // Check at 1KHz, 5Hz, or 20Hz + next_check_ms = ms + (config_state == BDS_HOMING_Z ? 1 : (config_state < BDS_IDLE ? 200 : 50)); + uint16_t tmp = 0; + const float cur_z = planner.get_axis_position_mm(Z_AXIS) - pos_zero_offset; + static float old_cur_z = cur_z, old_buf_z = current_position.z; tmp = BD_I2C_SENSOR.BD_i2c_read(); - if (BD_I2C_SENSOR.BD_Check_OddEven(tmp) && (tmp & 0x3FF) < 1020) { - const float z_sensor = (tmp & 0x3FF) / 100.0f; - if (cur_z < 0) config_state = 0; - //float abs_z = current_position.z > cur_z ? (current_position.z - cur_z) : (cur_z - current_position.z); + if (BD_I2C_SENSOR.BD_Check_OddEven(tmp) && good_data(tmp)) { + const float z_sensor = interpret(tmp); #if ENABLED(BABYSTEPPING) - if (cur_z < config_state * 0.1f - && config_state > 0 - && old_cur_z == cur_z - && old_buf_z == current_position.z - && z_sensor < (MAX_BD_HEIGHT) - ) { - babystep.set_mm(Z_AXIS, cur_z - z_sensor); - #if ENABLED(DEBUG_OUT_BD) - SERIAL_ECHOLNPGM("BD:", z_sensor, ", Z:", cur_z, "|", current_position.z); - #endif - } - else { - babystep.set_mm(Z_AXIS, 0); //if (old_cur_z <= cur_z) Z_DIR_WRITE(!INVERT_Z_DIR); - stepper.set_directions(); + if (config_state > 0) { + if (cur_z < config_state * 0.1f + && old_cur_z == cur_z + && old_buf_z == current_position.z + && z_sensor < (MAX_BD_HEIGHT) - 0.1f + ) { + babystep.set_mm(Z_AXIS, cur_z - z_sensor); + DEBUG_ECHOLNPGM("BD:", z_sensor, ", Z:", cur_z, "|", current_position.z); + } + else + babystep.set_mm(Z_AXIS, 0); } #endif + old_cur_z = cur_z; old_buf_z = current_position.z; - endstops.bdp_state_update(z_sensor <= 0.01f); - //endstops.update(); + endstops.bdp_state_update(z_sensor <= BD_SENSOR_HOME_Z_POSITION); + + #if HAS_STATUS_MESSAGE + static float old_z_sensor = 0; + if (old_z_sensor != z_sensor) { + old_z_sensor = z_sensor; + char tmp_1[32]; + sprintf_P(tmp_1, PSTR("BD:%d.%02dmm"), int(z_sensor), int(z_sensor * 100) % 100); + //SERIAL_ECHOLNPGM("Bed Dis:", z_sensor, "mm"); + ui.set_status(tmp_1, true); + } + #endif + } + else if (config_state == BDS_HOMING_Z) { + SERIAL_ECHOLNPGM("Read:", tmp); + kill(F("BDsensor connect Err!")); } - else - stepper.set_directions(); - #if ENABLED(DEBUG_OUT_BD) - SERIAL_ECHOLNPGM("BD:", tmp & 0x3FF, ", Z:", cur_z, "|", current_position.z); - if (BD_I2C_SENSOR.BD_Check_OddEven(tmp) == 0) SERIAL_ECHOLNPGM("errorCRC"); - #endif + DEBUG_ECHOLNPGM("BD:", tmp & 0x3FF, " Z:", cur_z, "|", current_position.z); + if (TERN0(DEBUG_OUT_BD, BD_I2C_SENSOR.BD_Check_OddEven(tmp) == 0)) DEBUG_ECHOLNPGM("CRC error"); - if ((tmp & 0x3FF) > 1020) { + if (!good_data(tmp)) { BD_I2C_SENSOR.BD_i2c_stop(); safe_delay(10); } + // Read version. Usually used as a connection check + if (config_state == BDS_VERSION) { + config_state = BDS_IDLE; + BD_I2C_SENSOR.BD_i2c_write(CMD_READ_VERSION); + safe_delay(100); + char tmp_1[21]; + for (int i = 0; i < 19; i++) { + tmp_1[i] = BD_I2C_SENSOR.BD_i2c_read() & 0xFF; + safe_delay(50); + } + BD_I2C_SENSOR.BD_i2c_write(CMD_END_READ_CALIBRATE_DATA); + SERIAL_ECHOLNPGM("BD Sensor version:", tmp_1); + if (tmp_1[0] != 'V') SERIAL_ECHOLNPGM("Read Error. Check connection and delay."); + safe_delay(50); + } // read raw calibrate data - if (config_state == -5) { + else if (config_state == BDS_READ_RAW) { BD_I2C_SENSOR.BD_i2c_write(CMD_START_READ_CALIBRATE_DATA); - safe_delay(1000); + safe_delay(100); for (int i = 0; i < MAX_BD_HEIGHT * 10; i++) { tmp = BD_I2C_SENSOR.BD_i2c_read(); - SERIAL_ECHOLNPGM("Calibrate data:", i, ",", tmp & 0x3FF, ", check:", BD_I2C_SENSOR.BD_Check_OddEven(tmp)); - safe_delay(500); + SERIAL_ECHOLNPGM("Calibrate data:", i, ",", tmp & 0x3FF); + (void)check(tmp, true, i == 0); + safe_delay(50); } - config_state = 0; BD_I2C_SENSOR.BD_i2c_write(CMD_END_READ_CALIBRATE_DATA); - safe_delay(500); + safe_delay(50); + config_state = BDS_IDLE; } - else if (config_state <= -6) { // Start Calibrate - safe_delay(100); - if (config_state == -6) { - //BD_I2C_SENSOR.BD_i2c_write(1019); // begin calibrate - //delay(1000); - gcode.stepper_inactive_time = SEC_TO_MS(60 * 5); - gcode.process_subcommands_now(F("M17 Z")); - gcode.process_subcommands_now(F("G1 Z0.0")); - z_pose = 0; - safe_delay(1000); + else if (config_state <= BDS_CALIBRATE_START) { // Start Calibrate + safe_delay(10); + if (config_state == BDS_CALIBRATE_START) { + config_state = BDS_CALIBRATING; + REMEMBER(gsit, gcode.stepper_inactive_time, MIN_TO_MS(5)); + SERIAL_ECHOLNPGM("c_z0:", planner.get_axis_position_mm(Z_AXIS), "-", pos_zero_offset); + + // Move the z axis instead of enabling the Z axis with M17 + // TODO: Use do_blocking_move_to_z for synchronized move. + current_position.z = 0; + sync_plan_position(); + gcode.process_subcommands_now(F("G1Z0.05")); + safe_delay(300); + gcode.process_subcommands_now(F("G1Z0.00")); + safe_delay(300); + current_position.z = 0; + sync_plan_position(); + //safe_delay(1000); + + while ((planner.get_axis_position_mm(Z_AXIS) - pos_zero_offset) > 0.00001f) { + safe_delay(200); + SERIAL_ECHOLNPGM("waiting cur_z:", planner.get_axis_position_mm(Z_AXIS)); + } + zpos = 0.00001f; + safe_delay(100); BD_I2C_SENSOR.BD_i2c_write(CMD_START_CALIBRATE); // Begin calibrate - SERIAL_ECHOLNPGM("Begin calibrate"); - safe_delay(2000); - config_state = -7; + SERIAL_ECHOLNPGM("BD Sensor Calibrating..."); + safe_delay(200); } - else if (planner.get_axis_position_mm(Z_AXIS) < 10.0f) { - if (z_pose >= MAX_BD_HEIGHT) { + else if ((planner.get_axis_position_mm(Z_AXIS) - pos_zero_offset) < 10.0f) { + if (zpos >= MAX_BD_HEIGHT) { + config_state = BDS_IDLE; BD_I2C_SENSOR.BD_i2c_write(CMD_END_CALIBRATE); // End calibrate - SERIAL_ECHOLNPGM("End calibrate data"); - z_pose = 7; - config_state = 0; - safe_delay(1000); + SERIAL_ECHOLNPGM("BD Sensor calibrated."); + zpos = 7.0f; + safe_delay(500); } else { - float tmp_k = 0; - char tmp_1[30]; - sprintf_P(tmp_1, PSTR("G1 Z%d.%d"), int(z_pose), int(int(z_pose * 10) % 10)); + char tmp_1[32]; + // TODO: Use prepare_internal_move_to_destination to guarantee machine space + sprintf_P(tmp_1, PSTR("G1Z%d.%d"), int(zpos), int(zpos * 10) % 10); gcode.process_subcommands_now(tmp_1); - - SERIAL_ECHO(tmp_1); - SERIAL_ECHOLNPGM(" ,Z:", current_position.z); - - while (tmp_k < (z_pose - 0.1f)) { - tmp_k = planner.get_axis_position_mm(Z_AXIS); - safe_delay(1); + SERIAL_ECHO(tmp_1); SERIAL_ECHOLNPGM(", Z:", current_position.z); + uint16_t failcount = 300; + for (float tmp_k = 0; abs(zpos - tmp_k) > 0.006f && failcount--;) { + tmp_k = planner.get_axis_position_mm(Z_AXIS) - pos_zero_offset; + safe_delay(10); + if (!failcount--) break; } - safe_delay(800); - tmp = (z_pose + 0.0001f) * 10; + safe_delay(600); + tmp = uint16_t((zpos + 0.00001f) * 10); BD_I2C_SENSOR.BD_i2c_write(tmp); - SERIAL_ECHOLNPGM("w:", tmp, ",Zpose:", z_pose); - z_pose += 0.1001f; - //queue.enqueue_now_P(PSTR("G90")); + SERIAL_ECHOLNPGM("w:", tmp, ", Z:", zpos); + zpos += 0.1001f; } } } diff --git a/Marlin/src/feature/bedlevel/bdl/bdl.h b/Marlin/src/feature/bedlevel/bdl/bdl.h index 6307b1ab28..ed91d7081b 100644 --- a/Marlin/src/feature/bedlevel/bdl/bdl.h +++ b/Marlin/src/feature/bedlevel/bdl/bdl.h @@ -23,14 +23,30 @@ #include +#ifndef BD_SENSOR_HOME_Z_POSITION + #define BD_SENSOR_HOME_Z_POSITION 0.5 +#endif + +enum BDS_State : int8_t { + BDS_IDLE, + BDS_VERSION = -1, + BDS_READ_MM = -2, + BDS_HOMING_Z = -3, + BDS_READ_RAW = -5, + BDS_CALIBRATE_START = -6, + BDS_CALIBRATING = -7 +}; + class BDS_Leveling { public: static int8_t config_state; - static uint8_t homing; - static void echo_name(); + static float pos_zero_offset; static void init(uint8_t _sda, uint8_t _scl, uint16_t delay_s); static void process(); static float read(); + static float interpret(const uint16_t data); + static float good_data(const uint16_t data) { return (data & 0x3FF) < 1016; } + static bool check(const uint16_t data, const bool raw_data=false, const bool hicheck=false); }; extern BDS_Leveling bdl; diff --git a/Marlin/src/feature/bedlevel/bedlevel.cpp b/Marlin/src/feature/bedlevel/bedlevel.cpp index 03b67745ec..a76c6cdd26 100644 --- a/Marlin/src/feature/bedlevel/bedlevel.cpp +++ b/Marlin/src/feature/bedlevel/bedlevel.cpp @@ -27,7 +27,7 @@ #include "bedlevel.h" #include "../../module/planner.h" -#if EITHER(MESH_BED_LEVELING, PROBE_MANUALLY) +#if ANY(MESH_BED_LEVELING, PROBE_MANUALLY) #include "../../module/motion.h" #endif @@ -120,7 +120,7 @@ void reset_bed_level() { TERN_(ABL_PLANAR, planner.bed_level_matrix.set_to_identity()); } -#if EITHER(AUTO_BED_LEVELING_BILINEAR, MESH_BED_LEVELING) +#if ANY(AUTO_BED_LEVELING_BILINEAR, MESH_BED_LEVELING) /** * Enable to produce output in JSON format suitable @@ -137,8 +137,8 @@ void reset_bed_level() { */ void print_2d_array(const uint8_t sx, const uint8_t sy, const uint8_t precision, const float *values) { #ifndef SCAD_MESH_OUTPUT - LOOP_L_N(x, sx) { - serial_spaces(precision + (x < 10 ? 3 : 2)); + for (uint8_t x = 0; x < sx; ++x) { + SERIAL_ECHO_SP(precision + (x < 10 ? 3 : 2)); SERIAL_ECHO(x); } SERIAL_EOL(); @@ -146,19 +146,19 @@ void reset_bed_level() { #ifdef SCAD_MESH_OUTPUT SERIAL_ECHOLNPGM("measured_z = ["); // open 2D array #endif - LOOP_L_N(y, sy) { + for (uint8_t y = 0; y < sy; ++y) { #ifdef SCAD_MESH_OUTPUT SERIAL_ECHOPGM(" ["); // open sub-array #else if (y < 10) SERIAL_CHAR(' '); SERIAL_ECHO(y); #endif - LOOP_L_N(x, sx) { + for (uint8_t x = 0; x < sx; ++x) { SERIAL_CHAR(' '); const float offset = values[x * sy + y]; if (!isnan(offset)) { if (offset >= 0) SERIAL_CHAR('+'); - SERIAL_ECHO_F(offset, int(precision)); + SERIAL_ECHO(p_float_t(offset, precision)); } else { #ifdef SCAD_MESH_OUTPUT @@ -166,7 +166,7 @@ void reset_bed_level() { SERIAL_CHAR(' '); SERIAL_ECHOPGM("NAN"); #else - LOOP_L_N(i, precision + 3) + for (uint8_t i = 0; i < precision + 3; ++i) SERIAL_CHAR(i ? '=' : ' '); #endif } @@ -188,7 +188,7 @@ void reset_bed_level() { #endif // AUTO_BED_LEVELING_BILINEAR || MESH_BED_LEVELING -#if EITHER(MESH_BED_LEVELING, PROBE_MANUALLY) +#if ANY(MESH_BED_LEVELING, PROBE_MANUALLY) void _manual_goto_xy(const xy_pos_t &pos) { diff --git a/Marlin/src/feature/bedlevel/bedlevel.h b/Marlin/src/feature/bedlevel/bedlevel.h index aeafec10d6..ccb9543e72 100644 --- a/Marlin/src/feature/bedlevel/bedlevel.h +++ b/Marlin/src/feature/bedlevel/bedlevel.h @@ -23,7 +23,7 @@ #include "../../inc/MarlinConfigPre.h" -#if EITHER(RESTORE_LEVELING_AFTER_G28, ENABLE_LEVELING_AFTER_G28) +#if ANY(RESTORE_LEVELING_AFTER_G28, ENABLE_LEVELING_AFTER_G28) #define CAN_SET_LEVELING_AFTER_G28 1 #endif @@ -41,7 +41,7 @@ void reset_bed_level(); void set_z_fade_height(const_float_t zfh, const bool do_report=true); #endif -#if EITHER(MESH_BED_LEVELING, PROBE_MANUALLY) +#if ANY(MESH_BED_LEVELING, PROBE_MANUALLY) void _manual_goto_xy(const xy_pos_t &pos); #endif @@ -69,7 +69,7 @@ class TemporaryBedLevelingState { #include "mbl/mesh_bed_leveling.h" #endif - #if EITHER(AUTO_BED_LEVELING_BILINEAR, MESH_BED_LEVELING) + #if ANY(AUTO_BED_LEVELING_BILINEAR, MESH_BED_LEVELING) #include diff --git a/Marlin/src/feature/bedlevel/hilbert_curve.cpp b/Marlin/src/feature/bedlevel/hilbert_curve.cpp index 7474123e3f..57cbdfb34d 100644 --- a/Marlin/src/feature/bedlevel/hilbert_curve.cpp +++ b/Marlin/src/feature/bedlevel/hilbert_curve.cpp @@ -28,8 +28,8 @@ constexpr int8_t to_fix(int8_t v) { return v * 2; } constexpr int8_t to_int(int8_t v) { return v / 2; } -constexpr uint8_t log2(uint8_t n) { return (n > 1) ? 1 + log2(n >> 1) : 0; } -constexpr uint8_t order(uint8_t n) { return uint8_t(log2(n - 1)) + 1; } +constexpr uint8_t log2(uint8_t n) { return (n > 1) ? 1 + log2(uint8_t(n >> 1)) : 0; } +constexpr uint8_t order(uint8_t n) { return uint8_t(log2(uint8_t(n - 1))) + 1; } constexpr uint8_t ord = order(_MAX(GRID_MAX_POINTS_X, GRID_MAX_POINTS_Y)); constexpr uint8_t dim = _BV(ord); diff --git a/Marlin/src/feature/bedlevel/mbl/mesh_bed_leveling.cpp b/Marlin/src/feature/bedlevel/mbl/mesh_bed_leveling.cpp index 193cbbf765..f40cbccadd 100644 --- a/Marlin/src/feature/bedlevel/mbl/mesh_bed_leveling.cpp +++ b/Marlin/src/feature/bedlevel/mbl/mesh_bed_leveling.cpp @@ -40,9 +40,9 @@ mesh_bed_leveling::index_to_ypos[GRID_MAX_POINTS_Y]; mesh_bed_leveling::mesh_bed_leveling() { - LOOP_L_N(i, GRID_MAX_POINTS_X) + for (uint8_t i = 0; i < GRID_MAX_POINTS_X; ++i) index_to_xpos[i] = MESH_MIN_X + i * (MESH_X_DIST); - LOOP_L_N(i, GRID_MAX_POINTS_Y) + for (uint8_t i = 0; i < GRID_MAX_POINTS_Y; ++i) index_to_ypos[i] = MESH_MIN_Y + i * (MESH_Y_DIST); reset(); } @@ -123,8 +123,7 @@ #endif // IS_CARTESIAN && !SEGMENT_LEVELED_MOVES void mesh_bed_leveling::report_mesh() { - SERIAL_ECHOPAIR_F(STRINGIFY(GRID_MAX_POINTS_X) "x" STRINGIFY(GRID_MAX_POINTS_Y) " mesh. Z offset: ", z_offset, 5); - SERIAL_ECHOLNPGM("\nMeasured points:"); + SERIAL_ECHOLN(F(STRINGIFY(GRID_MAX_POINTS_X) "x" STRINGIFY(GRID_MAX_POINTS_Y) " mesh. Z offset: "), p_float_t(z_offset, 5), F("\nMeasured points:")); print_2d_array(GRID_MAX_POINTS_X, GRID_MAX_POINTS_Y, 5, z_values[0]); } diff --git a/Marlin/src/feature/bedlevel/mbl/mesh_bed_leveling.h b/Marlin/src/feature/bedlevel/mbl/mesh_bed_leveling.h index 1a8e693e81..cb4f36cd59 100644 --- a/Marlin/src/feature/bedlevel/mbl/mesh_bed_leveling.h +++ b/Marlin/src/feature/bedlevel/mbl/mesh_bed_leveling.h @@ -32,8 +32,8 @@ enum MeshLevelingState : char { MeshReset // G29 S5 }; -#define MESH_X_DIST (float(MESH_MAX_X - (MESH_MIN_X)) / (GRID_MAX_CELLS_X)) -#define MESH_Y_DIST (float(MESH_MAX_Y - (MESH_MIN_Y)) / (GRID_MAX_CELLS_Y)) +#define MESH_X_DIST (float((MESH_MAX_X) - (MESH_MIN_X)) / (GRID_MAX_CELLS_X)) +#define MESH_Y_DIST (float((MESH_MAX_Y) - (MESH_MIN_Y)) / (GRID_MAX_CELLS_Y)) class mesh_bed_leveling { public: @@ -72,18 +72,18 @@ public: static float get_mesh_x(const uint8_t i) { return index_to_xpos[i]; } static float get_mesh_y(const uint8_t i) { return index_to_ypos[i]; } - static int8_t cell_index_x(const_float_t x) { + static uint8_t cell_index_x(const_float_t x) { int8_t cx = (x - (MESH_MIN_X)) * RECIPROCAL(MESH_X_DIST); return constrain(cx, 0, GRID_MAX_CELLS_X - 1); } - static int8_t cell_index_y(const_float_t y) { + static uint8_t cell_index_y(const_float_t y) { int8_t cy = (y - (MESH_MIN_Y)) * RECIPROCAL(MESH_Y_DIST); return constrain(cy, 0, GRID_MAX_CELLS_Y - 1); } - static xy_int8_t cell_indexes(const_float_t x, const_float_t y) { + static xy_uint8_t cell_indexes(const_float_t x, const_float_t y) { return { cell_index_x(x), cell_index_y(y) }; } - static xy_int8_t cell_indexes(const xy_pos_t &xy) { return cell_indexes(xy.x, xy.y); } + static xy_uint8_t cell_indexes(const xy_pos_t &xy) { return cell_indexes(xy.x, xy.y); } static int8_t probe_index_x(const_float_t x) { int8_t px = (x - (MESH_MIN_X) + 0.5f * (MESH_X_DIST)) * RECIPROCAL(MESH_X_DIST); @@ -107,9 +107,9 @@ public: static float get_z_offset() { return z_offset; } static float get_z_correction(const xy_pos_t &pos) { - const xy_int8_t ind = cell_indexes(pos); + const xy_uint8_t ind = cell_indexes(pos); const float x1 = index_to_xpos[ind.x], x2 = index_to_xpos[ind.x+1], - y1 = index_to_xpos[ind.y], y2 = index_to_xpos[ind.y+1], + y1 = index_to_ypos[ind.y], y2 = index_to_ypos[ind.y+1], z1 = calc_z0(pos.x, x1, z_values[ind.x][ind.y ], x2, z_values[ind.x+1][ind.y ]), z2 = calc_z0(pos.x, x1, z_values[ind.x][ind.y+1], x2, z_values[ind.x+1][ind.y+1]), zf = calc_z0(pos.y, y1, z1, y2, z2); diff --git a/Marlin/src/feature/bedlevel/ubl/ubl.cpp b/Marlin/src/feature/bedlevel/ubl/ubl.cpp index f2af1445b1..0228bd247e 100644 --- a/Marlin/src/feature/bedlevel/ubl/ubl.cpp +++ b/Marlin/src/feature/bedlevel/ubl/ubl.cpp @@ -51,15 +51,14 @@ void unified_bed_leveling::report_current_mesh() { GRID_LOOP(x, y) if (!isnan(z_values[x][y])) { SERIAL_ECHO_START(); - SERIAL_ECHOPGM(" M421 I", x, " J", y); - SERIAL_ECHOLNPAIR_F_P(SP_Z_STR, z_values[x][y], 4); + SERIAL_ECHOLN(F(" M421 I"), x, F(" J"), y, FPSTR(SP_Z_STR), p_float_t(z_values[x][y], 4)); serial_delay(75); // Prevent Printrun from exploding } } void unified_bed_leveling::report_state() { echo_name(); - SERIAL_ECHO_TERNARY(planner.leveling_active, " System v" UBL_VERSION " ", "", "in", "active\n"); + serial_ternary(F(" System v" UBL_VERSION " "), planner.leveling_active, nullptr, F("in"), F("active\n")); serial_delay(50); } @@ -149,7 +148,7 @@ static void serial_echo_xy(const uint8_t sp, const int16_t x, const int16_t y) { static void serial_echo_column_labels(const uint8_t sp) { SERIAL_ECHO_SP(7); - LOOP_L_N(i, GRID_MAX_POINTS_X) { + for (uint8_t i = 0; i < GRID_MAX_POINTS_X; ++i) { if (i < 10) SERIAL_CHAR(' '); SERIAL_ECHO(i); SERIAL_ECHO_SP(sp); @@ -199,7 +198,7 @@ void unified_bed_leveling::display_map(const uint8_t map_type) { } // Row Values (I indexes) - LOOP_L_N(i, GRID_MAX_POINTS_X) { + for (uint8_t i = 0; i < GRID_MAX_POINTS_X; ++i) { // Opening Brace or Space const bool is_current = i == curr.x && j == curr.y; @@ -211,10 +210,10 @@ void unified_bed_leveling::display_map(const uint8_t map_type) { // TODO: Display on Graphical LCD } else if (isnan(f)) - SERIAL_ECHOF(human ? F(" . ") : F("NAN")); + SERIAL_ECHO(human ? F(" . ") : F("NAN")); else if (human || csv) { if (human && f >= 0) SERIAL_CHAR(f > 0 ? '+' : ' '); // Display sign also for positive numbers (' ' for 0) - SERIAL_DECIMAL(f); // Positive: 5 digits, Negative: 6 digits + SERIAL_ECHO(p_float_t(f, 3)); // Positive: 5 digits, Negative: 6 digits } if (csv && i < (GRID_MAX_POINTS_X) - 1) SERIAL_CHAR('\t'); diff --git a/Marlin/src/feature/bedlevel/ubl/ubl.h b/Marlin/src/feature/bedlevel/ubl/ubl.h index a7103d6e18..7377f7dfc0 100644 --- a/Marlin/src/feature/bedlevel/ubl/ubl.h +++ b/Marlin/src/feature/bedlevel/ubl/ubl.h @@ -38,8 +38,8 @@ enum MeshPointType : char { INVALID, REAL, SET_IN_BITMAP, CLOSEST }; struct mesh_index_pair; -#define MESH_X_DIST (float(MESH_MAX_X - (MESH_MIN_X)) / (GRID_MAX_CELLS_X)) -#define MESH_Y_DIST (float(MESH_MAX_Y - (MESH_MIN_Y)) / (GRID_MAX_CELLS_Y)) +#define MESH_X_DIST (float((MESH_MAX_X) - (MESH_MIN_X)) / (GRID_MAX_CELLS_X)) +#define MESH_Y_DIST (float((MESH_MAX_Y) - (MESH_MIN_Y)) / (GRID_MAX_CELLS_Y)) #if ENABLED(OPTIMIZED_MESH_STORAGE) typedef int16_t mesh_store_t[GRID_MAX_POINTS_X][GRID_MAX_POINTS_Y]; @@ -48,8 +48,8 @@ struct mesh_index_pair; typedef struct { bool C_seen; int8_t KLS_storage_slot; - uint8_t R_repetition, - V_verbosity, + grid_count_t R_repetition; + uint8_t V_verbosity, P_phase, T_map_type; float B_shim_thickness, @@ -77,7 +77,6 @@ private: static bool G29_parse_parameters() __O0; static void shift_mesh_height(); static void probe_entire_mesh(const xy_pos_t &near, const bool do_ubl_mesh_map, const bool stow_probe, const bool do_furthest) __O0; - static void tilt_mesh_based_on_3pts(const_float_t z1, const_float_t z2, const_float_t z3); static void tilt_mesh_based_on_probed_grid(const bool do_ubl_mesh_map); static bool smart_fill_one(const uint8_t x, const uint8_t y, const int8_t xdir, const int8_t ydir); static bool smart_fill_one(const xy_uint8_t &pos, const xy_uint8_t &dir) { @@ -141,26 +140,26 @@ public: return FLOOR((y - (MESH_MIN_Y)) * RECIPROCAL(MESH_Y_DIST)); } - static int8_t cell_index_x_valid(const_float_t x) { + static bool cell_index_x_valid(const_float_t x) { return WITHIN(cell_index_x_raw(x), 0, GRID_MAX_CELLS_X - 1); } - static int8_t cell_index_y_valid(const_float_t y) { + static bool cell_index_y_valid(const_float_t y) { return WITHIN(cell_index_y_raw(y), 0, GRID_MAX_CELLS_Y - 1); } - static int8_t cell_index_x(const_float_t x) { + static uint8_t cell_index_x(const_float_t x) { return constrain(cell_index_x_raw(x), 0, GRID_MAX_CELLS_X - 1); } - static int8_t cell_index_y(const_float_t y) { + static uint8_t cell_index_y(const_float_t y) { return constrain(cell_index_y_raw(y), 0, GRID_MAX_CELLS_Y - 1); } - static xy_int8_t cell_indexes(const_float_t x, const_float_t y) { + static xy_uint8_t cell_indexes(const_float_t x, const_float_t y) { return { cell_index_x(x), cell_index_y(y) }; } - static xy_int8_t cell_indexes(const xy_pos_t &xy) { return cell_indexes(xy.x, xy.y); } + static xy_uint8_t cell_indexes(const xy_pos_t &xy) { return cell_indexes(xy.x, xy.y); } static int8_t closest_x_index(const_float_t x) { const int8_t px = (x - (MESH_MIN_X) + (MESH_X_DIST) * 0.5) * RECIPROCAL(MESH_X_DIST); @@ -264,9 +263,9 @@ public: return UBL_Z_RAISE_WHEN_OFF_MESH; #endif - const uint8_t mx = _MIN(cx, (GRID_MAX_POINTS_X) - 2) + 1, my = _MIN(cy, (GRID_MAX_POINTS_Y) - 2) + 1, - x0 = get_mesh_x(cx), x1 = get_mesh_x(cx + 1); - const float z1 = calc_z0(rx0, x0, z_values[cx][cy], x1, z_values[mx][cy]), + const uint8_t mx = _MIN(cx, (GRID_MAX_POINTS_X) - 2) + 1, my = _MIN(cy, (GRID_MAX_POINTS_Y) - 2) + 1; + const float x0 = get_mesh_x(cx), x1 = get_mesh_x(cx + 1), + z1 = calc_z0(rx0, x0, z_values[cx][cy], x1, z_values[mx][cy]), z2 = calc_z0(rx0, x0, z_values[cx][my], x1, z_values[mx][my]); float z0 = calc_z0(ry0, get_mesh_y(cy), z1, get_mesh_y(cy + 1), z2); @@ -279,10 +278,8 @@ public: if (DEBUGGING(MESH_ADJUST)) DEBUG_ECHOLNPGM("??? Yikes! NAN in "); } - if (DEBUGGING(MESH_ADJUST)) { - DEBUG_ECHOPGM("get_z_correction(", rx0, ", ", ry0); - DEBUG_ECHOLNPAIR_F(") => ", z0, 6); - } + if (DEBUGGING(MESH_ADJUST)) + DEBUG_ECHOLN(F("get_z_correction("), rx0, F(", "), ry0, F(") => "), p_float_t(z0, 6)); return z0; } diff --git a/Marlin/src/feature/bedlevel/ubl/ubl_G29.cpp b/Marlin/src/feature/bedlevel/ubl/ubl_G29.cpp index d6cb0b762f..c61a84894a 100644 --- a/Marlin/src/feature/bedlevel/ubl/ubl_G29.cpp +++ b/Marlin/src/feature/bedlevel/ubl/ubl_G29.cpp @@ -112,7 +112,7 @@ * If omitted, the nozzle will raise by Z_CLEARANCE_BETWEEN_PROBES. * * H # Offset With P4, 'H' specifies the Offset above the mesh height to place the nozzle. - * If omitted, Z_CLEARANCE_BETWEEN_PROBES will be used. + * If omitted, Z_TWEEN_SAFE_CLEARANCE will be used. * * I # Invalidate Invalidate the specified number of Mesh Points near the given 'X' 'Y'. If X or Y are omitted, * the nozzle location is used. If no 'I' value is given, only the point nearest to the location @@ -306,21 +306,22 @@ void unified_bed_leveling::G29() { const uint8_t p_val = parser.byteval('P'); const bool may_move = p_val == 1 || p_val == 2 || p_val == 4 || parser.seen_test('J'); - #if HAS_MULTI_HOTEND - const uint8_t old_tool_index = active_extruder; - #endif // Check for commands that require the printer to be homed if (may_move) { planner.synchronize(); - // Send 'N' to force homing before G29 (internal only) - if (axes_should_home() || parser.seen_test('N')) gcode.home_all_axes(); - TERN_(HAS_MULTI_HOTEND, if (active_extruder != 0) tool_change(0, true)); + #if ALL(DWIN_LCD_PROUI, ZHOME_BEFORE_LEVELING) + save_ubl_active_state_and_disable(); + gcode.process_subcommands_now(F("G28Z")); + restore_ubl_active_state_and_leave(); + #else + // Send 'N' to force homing before G29 (internal only) + if (axes_should_home() || parser.seen_test('N')) gcode.home_all_axes(); + #endif + probe.use_probing_tool(); // Position bed horizontally and Z probe vertically. - #if defined(SAFE_BED_LEVELING_START_X) || defined(SAFE_BED_LEVELING_START_Y) || defined(SAFE_BED_LEVELING_START_Z) \ - || defined(SAFE_BED_LEVELING_START_I) || defined(SAFE_BED_LEVELING_START_J) || defined(SAFE_BED_LEVELING_START_K) \ - || defined(SAFE_BED_LEVELING_START_U) || defined(SAFE_BED_LEVELING_START_V) || defined(SAFE_BED_LEVELING_START_W) + #if HAS_SAFE_BED_LEVELING xyze_pos_t safe_position = current_position; #ifdef SAFE_BED_LEVELING_START_X safe_position.x = SAFE_BED_LEVELING_START_X; @@ -351,12 +352,12 @@ void unified_bed_leveling::G29() { #endif do_blocking_move_to(safe_position); - #endif + #endif // HAS_SAFE_BED_LEVELING } // Invalidate one or more nearby mesh points, possibly all. if (parser.seen('I')) { - uint8_t count = parser.has_value() ? parser.value_byte() : 1; + grid_count_t count = parser.has_value() ? parser.value_ushort() : 1; bool invalidate_all = count >= GRID_MAX_POINTS; if (!invalidate_all) { while (count--) { @@ -401,7 +402,7 @@ void unified_bed_leveling::G29() { break; case 1: - LOOP_L_N(x, GRID_MAX_POINTS_X) { // Create a diagonal line several Mesh cells thick that is raised + for (uint8_t x = 0; x < GRID_MAX_POINTS_X; ++x) { // Create a diagonal line several Mesh cells thick that is raised const uint8_t x2 = x + (x < (GRID_MAX_POINTS_Y) - 1 ? 1 : -1); z_values[x][x] += 9.999f; z_values[x][x2] += 9.999f; // We want the altered line several mesh points thick @@ -463,12 +464,8 @@ void unified_bed_leveling::G29() { invalidate(); SERIAL_ECHOLNPGM("Mesh invalidated. Probing mesh."); } - if (param.V_verbosity > 1) { - SERIAL_ECHOPGM("Probing around (", param.XY_pos.x); - SERIAL_CHAR(','); - SERIAL_DECIMAL(param.XY_pos.y); - SERIAL_ECHOLNPGM(").\n"); - } + if (param.V_verbosity > 1) + SERIAL_ECHOLN(F("Probing around ("), param.XY_pos.x, C(','), param.XY_pos.y, F(").\n")); probe_entire_mesh(param.XY_pos, parser.seen_test('T'), parser.seen_test('E'), parser.seen_test('U')); report_current_position(); @@ -698,7 +695,7 @@ void unified_bed_leveling::G29() { UNUSED(probe_deployed); #endif - TERN_(HAS_MULTI_HOTEND, if (old_tool_index != 0) tool_change(old_tool_index)); + probe.use_probing_tool(false); return; } @@ -727,10 +724,10 @@ void unified_bed_leveling::adjust_mesh_to_mean(const bool cflag, const_float_t o sum_of_diff_squared += sq(z_values[x][y] - mean); SERIAL_ECHOLNPGM("# of samples: ", n); - SERIAL_ECHOLNPAIR_F("Mean Mesh Height: ", mean, 6); + SERIAL_ECHOLNPGM("Mean Mesh Height: ", p_float_t(mean, 6)); const float sigma = SQRT(sum_of_diff_squared / (n + 1)); - SERIAL_ECHOLNPAIR_F("Standard Deviation: ", sigma, 6); + SERIAL_ECHOLNPGM("Standard Deviation: ", p_float_t(sigma, 6)); if (cflag) GRID_LOOP(x, y) @@ -762,19 +759,21 @@ void unified_bed_leveling::shift_mesh_height() { TERN_(HAS_MARLINUI_MENU, ui.capture()); TERN_(EXTENSIBLE_UI, ExtUI::onLevelingStart()); - TERN_(DWIN_LCD_PROUI, DWIN_LevelingStart()); + TERN_(DWIN_LCD_PROUI, dwinLevelingStart()); save_ubl_active_state_and_disable(); // No bed level correction so only raw data is obtained - uint8_t count = GRID_MAX_POINTS; + grid_count_t count = GRID_MAX_POINTS; mesh_index_pair best; TERN_(EXTENSIBLE_UI, ExtUI::onMeshUpdate(best.pos, ExtUI::G29_START)); do { if (do_ubl_mesh_map) display_map(param.T_map_type); - const uint8_t point_num = (GRID_MAX_POINTS - count) + 1; + const grid_count_t point_num = (GRID_MAX_POINTS - count) + 1; SERIAL_ECHOLNPGM("Probing mesh point ", point_num, "/", GRID_MAX_POINTS, "."); TERN_(HAS_STATUS_MESSAGE, ui.status_printf(0, F(S_FMT " %i/%i"), GET_TEXT(MSG_PROBING_POINT), point_num, int(GRID_MAX_POINTS))); + TERN_(HAS_BACKLIGHT_TIMEOUT, ui.refresh_backlight_timeout()); + TERN_(DWIN_LCD_PROUI, dwinRedrawScreen()); #if HAS_MARLINUI_MENU if (ui.button_pressed()) { @@ -789,17 +788,18 @@ void unified_bed_leveling::shift_mesh_height() { } #endif - best = do_furthest + #ifndef HUGE_VALF + #define HUGE_VALF __FLT_MAX__ + #endif + + best = do_furthest // Points with valid data or HUGE_VALF are skipped ? find_furthest_invalid_mesh_point() : find_closest_mesh_point_of_type(INVALID, nearby, true); if (best.pos.x >= 0) { // mesh point found and is reachable by probe TERN_(EXTENSIBLE_UI, ExtUI::onMeshUpdate(best.pos, ExtUI::G29_POINT_START)); - const float measured_z = probe.probe_at_point( - best.meshpos(), - stow_probe ? PROBE_PT_STOW : PROBE_PT_RAISE, param.V_verbosity - ); - z_values[best.pos.x][best.pos.y] = measured_z; + const float measured_z = probe.probe_at_point(best.meshpos(), stow_probe ? PROBE_PT_STOW : PROBE_PT_RAISE, param.V_verbosity); + z_values[best.pos.x][best.pos.y] = isnan(measured_z) ? HUGE_VALF : measured_z; // Mark invalid point already probed with HUGE_VALF to omit it in the next loop #if ENABLED(EXTENSIBLE_UI) ExtUI::onMeshUpdate(best.pos, ExtUI::G29_POINT_FINISH); ExtUI::onMeshUpdate(best.pos, measured_z); @@ -809,6 +809,8 @@ void unified_bed_leveling::shift_mesh_height() { } while (best.pos.x >= 0 && --count); + GRID_LOOP(x, y) if (z_values[x][y] == HUGE_VALF) z_values[x][y] = NAN; // Restore NAN for HUGE_VALF marks + TERN_(EXTENSIBLE_UI, ExtUI::onMeshUpdate(best.pos, ExtUI::G29_FINISH)); // Release UI during stow to allow for PAUSE_BEFORE_DEPLOY_STOW @@ -826,7 +828,7 @@ void unified_bed_leveling::shift_mesh_height() { ); TERN_(EXTENSIBLE_UI, ExtUI::onLevelingDone()); - TERN_(DWIN_LCD_PROUI, DWIN_LevelingDone()); + TERN_(DWIN_LCD_PROUI, dwinLevelingDone()); } #endif // HAS_BED_PROBE @@ -887,8 +889,32 @@ void set_message_with_feedback(FSTR_P const fstr) { ui.capture(); save_ubl_active_state_and_disable(); // Disable bed level correction for probing - do_blocking_move_to(0.5f * (MESH_MAX_X - (MESH_MIN_X)), 0.5f * (MESH_MAX_Y - (MESH_MIN_Y)), MANUAL_PROBE_START_Z); - //, _MIN(planner.settings.max_feedrate_mm_s[X_AXIS], planner.settings.max_feedrate_mm_s[Y_AXIS]) * 0.5f); + do_blocking_move_to( + xyz_pos_t({ + 0.5f * ((MESH_MAX_X) - (MESH_MIN_X)), + 0.5f * ((MESH_MAX_Y) - (MESH_MIN_Y)), + MANUAL_PROBE_START_Z + #ifdef SAFE_BED_LEVELING_START_I + , SAFE_BED_LEVELING_START_I + #endif + #ifdef SAFE_BED_LEVELING_START_J + , SAFE_BED_LEVELING_START_J + #endif + #ifdef SAFE_BED_LEVELING_START_K + , SAFE_BED_LEVELING_START_K + #endif + #ifdef SAFE_BED_LEVELING_START_U + , SAFE_BED_LEVELING_START_U + #endif + #ifdef SAFE_BED_LEVELING_START_V + , SAFE_BED_LEVELING_START_V + #endif + #ifdef SAFE_BED_LEVELING_START_W + , SAFE_BED_LEVELING_START_W + #endif + }) + //, _MIN(planner.settings.max_feedrate_mm_s[X_AXIS], planner.settings.max_feedrate_mm_s[Y_AXIS]) * 0.5f + ); planner.synchronize(); SERIAL_ECHOPGM("Place shim under nozzle"); @@ -897,22 +923,19 @@ void set_message_with_feedback(FSTR_P const fstr) { echo_and_take_a_measurement(); const float z1 = measure_point_with_encoder(); - do_blocking_move_to_z(current_position.z + SIZE_OF_LITTLE_RAISE); - planner.synchronize(); + do_z_clearance_by(SIZE_OF_LITTLE_RAISE); SERIAL_ECHOPGM("Remove shim"); LCD_MESSAGE(MSG_UBL_BC_REMOVE); echo_and_take_a_measurement(); const float z2 = measure_point_with_encoder(); - do_blocking_move_to_z(current_position.z + Z_CLEARANCE_BETWEEN_PROBES); + do_z_clearance_by(Z_CLEARANCE_BETWEEN_PROBES); const float thickness = ABS(z1 - z2); - if (param.V_verbosity > 1) { - SERIAL_ECHOPAIR_F("Business Card is ", thickness, 4); - SERIAL_ECHOLNPGM("mm thick."); - } + if (param.V_verbosity > 1) + SERIAL_ECHOLNPGM("Business Card is ", p_float_t(thickness, 4), "mm thick."); restore_ubl_active_state_and_leave(); @@ -978,7 +1001,7 @@ void set_message_with_feedback(FSTR_P const fstr) { TERN_(EXTENSIBLE_UI, ExtUI::onMeshUpdate(location, z_values[lpos.x][lpos.y])); if (param.V_verbosity > 2) - SERIAL_ECHOLNPAIR_F("Mesh Point Measured at: ", z_values[lpos.x][lpos.y], 6); + SERIAL_ECHOLNPGM("Mesh Point Measured at: ", p_float_t(z_values[lpos.x][lpos.y], 6)); SERIAL_FLUSH(); // Prevent host M105 buffer overrun. } while (location.valid()); @@ -1016,9 +1039,9 @@ void set_message_with_feedback(FSTR_P const fstr) { save_ubl_active_state_and_disable(); LCD_MESSAGE(MSG_UBL_FINE_TUNE_MESH); - ui.capture(); // Take over control of the LCD encoder + ui.capture(); // Take over control of the LCD encoder - do_blocking_move_to_xy_z(pos, Z_CLEARANCE_BETWEEN_PROBES); // Move to the given XY with probe clearance + do_blocking_move_to_xy_z(pos, Z_TWEEN_SAFE_CLEARANCE); // Move to the given XY with probe clearance MeshFlags done_flags{0}; const xy_int8_t &lpos = location.pos; @@ -1035,7 +1058,7 @@ void set_message_with_feedback(FSTR_P const fstr) { done_flags.mark(lpos); // Mark this location as 'adjusted' so a new // location is used on the next loop - const xyz_pos_t raw = { get_mesh_x(lpos.x), get_mesh_y(lpos.y), Z_CLEARANCE_BETWEEN_PROBES }; + const xyz_pos_t raw = { get_mesh_x(lpos.x), get_mesh_y(lpos.y), Z_TWEEN_SAFE_CLEARANCE }; if (!position_is_reachable(raw)) break; // SHOULD NOT OCCUR (find_closest_mesh_point_of_type only returns reachable) @@ -1045,7 +1068,7 @@ void set_message_with_feedback(FSTR_P const fstr) { KEEPALIVE_STATE(PAUSED_FOR_USER); - if (do_ubl_mesh_map) display_map(param.T_map_type); // Display the current point + if (do_ubl_mesh_map) display_map(param.T_map_type); // Display the current point #if IS_TFTGLCD_PANEL ui.ubl_plot(lpos.x, lpos.y); // update plot screen @@ -1075,7 +1098,7 @@ void set_message_with_feedback(FSTR_P const fstr) { // Button held down? Abort editing if (_click_and_hold([]{ ui.return_to_status(); - do_z_clearance(Z_CLEARANCE_BETWEEN_PROBES); + do_z_clearance(Z_TWEEN_SAFE_CLEARANCE); set_message_with_feedback(GET_TEXT_F(MSG_EDITING_STOPPED)); })) break; @@ -1095,7 +1118,7 @@ void set_message_with_feedback(FSTR_P const fstr) { if (do_ubl_mesh_map) display_map(param.T_map_type); restore_ubl_active_state_and_leave(); - do_blocking_move_to_xy_z(pos, Z_CLEARANCE_BETWEEN_PROBES); + do_blocking_move_to_xy_z(pos, Z_TWEEN_SAFE_CLEARANCE); LCD_MESSAGE(MSG_UBL_DONE_EDITING_MESH); SERIAL_ECHOLNPGM("Done Editing Mesh"); @@ -1120,7 +1143,7 @@ bool unified_bed_leveling::G29_parse_parameters() { param.R_repetition = 0; if (parser.seen('R')) { - param.R_repetition = parser.has_value() ? parser.value_byte() : GRID_MAX_POINTS; + param.R_repetition = parser.has_value() ? parser.value_ushort() : GRID_MAX_POINTS; NOMORE(param.R_repetition, GRID_MAX_POINTS); if (param.R_repetition < 1) { SERIAL_ECHOLNPGM("?(R)epetition count invalid (1+).\n"); @@ -1430,7 +1453,7 @@ void unified_bed_leveling::smart_fill_mesh() { info3 PROGMEM = { (GRID_MAX_POINTS_X) - 1, 0, 0, GRID_MAX_POINTS_Y, true }; // Right side of the mesh looking left static const smart_fill_info * const info[] PROGMEM = { &info0, &info1, &info2, &info3 }; - LOOP_L_N(i, COUNT(info)) { + for (uint8_t i = 0; i < COUNT(info); ++i) { const smart_fill_info *f = (smart_fill_info*)pgm_read_ptr(&info[i]); const int8_t sx = pgm_read_byte(&f->sx), sy = pgm_read_byte(&f->sy), ex = pgm_read_byte(&f->ex), ey = pgm_read_byte(&f->ey); @@ -1456,81 +1479,42 @@ void unified_bed_leveling::smart_fill_mesh() { #include "../../../libs/vector_3.h" void unified_bed_leveling::tilt_mesh_based_on_probed_grid(const bool do_3_pt_leveling) { - const float x_min = probe.min_x(), x_max = probe.max_x(), - y_min = probe.min_y(), y_max = probe.max_y(), - dx = (x_max - x_min) / (param.J_grid_size - 1), - dy = (y_max - y_min) / (param.J_grid_size - 1); - - xy_float_t points[3]; - probe.get_three_points(points); float measured_z; bool abort_flag = false; - #ifdef VALIDATE_MESH_TILT - float z1, z2, z3; // Needed for algorithm validation below - #endif - struct linear_fit_data lsf_results; incremental_LSF_reset(&lsf_results); if (do_3_pt_leveling) { - SERIAL_ECHOLNPGM("Tilting mesh (1/3)"); - TERN_(HAS_STATUS_MESSAGE, ui.status_printf(0, F(S_FMT " 1/3"), GET_TEXT(MSG_LCD_TILTING_MESH))); + xy_float_t points[3]; + probe.get_three_points(points); - measured_z = probe.probe_at_point(points[0], PROBE_PT_RAISE, param.V_verbosity); - if (isnan(measured_z)) - abort_flag = true; - else { - measured_z -= get_z_correction(points[0]); - #ifdef VALIDATE_MESH_TILT - z1 = measured_z; - #endif - if (param.V_verbosity > 3) { - serial_spaces(16); - SERIAL_ECHOLNPGM("Corrected_Z=", measured_z); + #if ENABLED(UBL_TILT_ON_MESH_POINTS_3POINT) + mesh_index_pair cpos[3]; + for (uint8_t ix = 0; ix < 3; ++ix) { // Convert points to coordinates of mesh points + cpos[ix] = find_closest_mesh_point_of_type(REAL, points[ix], true); + points[ix] = cpos[ix].meshpos(); } - incremental_LSF(&lsf_results, points[0], measured_z); - } + #endif - if (!abort_flag) { - SERIAL_ECHOLNPGM("Tilting mesh (2/3)"); - TERN_(HAS_STATUS_MESSAGE, ui.status_printf(0, F(S_FMT " 2/3"), GET_TEXT(MSG_LCD_TILTING_MESH))); + #if ENABLED(VALIDATE_MESH_TILT) + float gotz[3]; // Used for algorithm validation below + #endif - measured_z = probe.probe_at_point(points[1], PROBE_PT_RAISE, param.V_verbosity); - #ifdef VALIDATE_MESH_TILT - z2 = measured_z; - #endif - if (isnan(measured_z)) - abort_flag = true; - else { - measured_z -= get_z_correction(points[1]); - if (param.V_verbosity > 3) { - serial_spaces(16); - SERIAL_ECHOLNPGM("Corrected_Z=", measured_z); - } - incremental_LSF(&lsf_results, points[1], measured_z); - } - } + for (uint8_t i = 0; i < 3; ++i) { + SERIAL_ECHOLNPGM("Tilting mesh (", i + 1, "/3)"); + TERN_(HAS_STATUS_MESSAGE, ui.status_printf(0, F(S_FMT " %i/3"), GET_TEXT(MSG_LCD_TILTING_MESH), i + 1)); - if (!abort_flag) { - SERIAL_ECHOLNPGM("Tilting mesh (3/3)"); - TERN_(HAS_STATUS_MESSAGE, ui.status_printf(0, F(S_FMT " 3/3"), GET_TEXT(MSG_LCD_TILTING_MESH))); + measured_z = probe.probe_at_point(points[i], i < 2 ? PROBE_PT_RAISE : PROBE_PT_LAST_STOW, param.V_verbosity); + if ((abort_flag = isnan(measured_z))) break; - measured_z = probe.probe_at_point(points[2], PROBE_PT_LAST_STOW, param.V_verbosity); - #ifdef VALIDATE_MESH_TILT - z3 = measured_z; - #endif - if (isnan(measured_z)) - abort_flag = true; - else { - measured_z -= get_z_correction(points[2]); - if (param.V_verbosity > 3) { - serial_spaces(16); - SERIAL_ECHOLNPGM("Corrected_Z=", measured_z); - } - incremental_LSF(&lsf_results, points[2], measured_z); - } + measured_z -= TERN(UBL_TILT_ON_MESH_POINTS_3POINT, z_values[cpos[i].pos.x][cpos[i].pos.y], get_z_correction(points[i])); + TERN_(VALIDATE_MESH_TILT, gotz[i] = measured_z); + + if (param.V_verbosity > 3) { SERIAL_ECHO_SP(16); SERIAL_ECHOLNPGM("Corrected_Z=", measured_z); } + + incremental_LSF(&lsf_results, points[i], measured_z); } probe.stow(); @@ -1543,54 +1527,79 @@ void unified_bed_leveling::smart_fill_mesh() { } else { // !do_3_pt_leveling + #ifndef G29J_MESH_TILT_MARGIN + #define G29J_MESH_TILT_MARGIN 0 + #endif + const float x_min = _MAX((X_MIN_POS) + (G29J_MESH_TILT_MARGIN), MESH_MIN_X, probe.min_x()), + x_max = _MIN((X_MAX_POS) - (G29J_MESH_TILT_MARGIN), MESH_MAX_X, probe.max_x()), + y_min = _MAX((Y_MIN_POS) + (G29J_MESH_TILT_MARGIN), MESH_MIN_Y, probe.min_y()), + y_max = _MIN((Y_MAX_POS) - (G29J_MESH_TILT_MARGIN), MESH_MAX_Y, probe.max_y()), + dx = (x_max - x_min) / (param.J_grid_size - 1), + dy = (y_max - y_min) / (param.J_grid_size - 1); + bool zig_zag = false; const uint16_t total_points = sq(param.J_grid_size); uint16_t point_num = 1; - xy_pos_t rpos; - LOOP_L_N(ix, param.J_grid_size) { + for (uint8_t ix = 0; ix < param.J_grid_size; ++ix) { + xy_pos_t rpos; rpos.x = x_min + ix * dx; - LOOP_L_N(iy, param.J_grid_size) { + for (uint8_t iy = 0; iy < param.J_grid_size; ++iy) { rpos.y = y_min + dy * (zig_zag ? param.J_grid_size - 1 - iy : iy); - if (!abort_flag) { - SERIAL_ECHOLNPGM("Tilting mesh point ", point_num, "/", total_points, "\n"); - TERN_(HAS_STATUS_MESSAGE, ui.status_printf(0, F(S_FMT " %i/%i"), GET_TEXT(MSG_LCD_TILTING_MESH), point_num, total_points)); - - measured_z = probe.probe_at_point(rpos, parser.seen_test('E') ? PROBE_PT_STOW : PROBE_PT_RAISE, param.V_verbosity); // TODO: Needs error handling - - abort_flag = isnan(measured_z); - + #if ENABLED(UBL_TILT_ON_MESH_POINTS) #if ENABLED(DEBUG_LEVELING_FEATURE) - if (DEBUGGING(LEVELING)) { - const xy_pos_t lpos = rpos.asLogical(); - DEBUG_CHAR('('); - DEBUG_ECHO_F(rpos.x, 7); - DEBUG_CHAR(','); - DEBUG_ECHO_F(rpos.y, 7); - DEBUG_ECHOPAIR_F(") logical: (", lpos.x, 7); - DEBUG_CHAR(','); - DEBUG_ECHO_F(lpos.y, 7); - DEBUG_ECHOPAIR_F(") measured: ", measured_z, 7); - DEBUG_ECHOPAIR_F(" correction: ", get_z_correction(rpos), 7); - } + xy_pos_t oldRpos; + if (DEBUGGING(LEVELING)) oldRpos = rpos; #endif + mesh_index_pair cpos; + rpos -= probe.offset; + cpos = find_closest_mesh_point_of_type(REAL, rpos, true); + rpos = cpos.meshpos(); + #endif - measured_z -= get_z_correction(rpos) /* + probe.offset.z */ ; + SERIAL_ECHOLNPGM("Tilting mesh point ", point_num, "/", total_points, "\n"); + TERN_(HAS_STATUS_MESSAGE, ui.status_printf(0, F(S_FMT " %i/%i"), GET_TEXT(MSG_LCD_TILTING_MESH), point_num, total_points)); - if (DEBUGGING(LEVELING)) DEBUG_ECHOLNPAIR_F(" final >>>---> ", measured_z, 7); + measured_z = probe.probe_at_point(rpos, parser.seen_test('E') ? PROBE_PT_STOW : PROBE_PT_RAISE, param.V_verbosity); // TODO: Needs error handling - if (param.V_verbosity > 3) { - serial_spaces(16); - SERIAL_ECHOLNPGM("Corrected_Z=", measured_z); + if ((abort_flag = isnan(measured_z))) break; + + const float zcorr = TERN(UBL_TILT_ON_MESH_POINTS, z_values[cpos.pos.x][cpos.pos.y], get_z_correction(rpos)); + + #if ENABLED(DEBUG_LEVELING_FEATURE) + if (DEBUGGING(LEVELING)) { + #if ENABLED(UBL_TILT_ON_MESH_POINTS) + const xy_pos_t oldLpos = oldRpos.asLogical(); + DEBUG_ECHO(F("Calculated point: ("), p_float_t(oldRpos.x, 7), C(','), p_float_t(oldRpos.y, 7), + F(") logical: ("), p_float_t(oldLpos.x, 7), C(','), p_float_t(oldLpos.y, 7), + F(")\nSelected mesh point: ") + ); + #endif + const xy_pos_t lpos = rpos.asLogical(); + DEBUG_ECHO( C('('), p_float_t(rpos.x, 7), C(','), p_float_t(rpos.y, 7), + F(") logical: ("), p_float_t(lpos.x, 7), C(','), p_float_t(lpos.y, 7), + F(") measured: "), p_float_t(measured_z, 7), + F(" correction: "), p_float_t(zcorr, 7) + ); } - incremental_LSF(&lsf_results, rpos, measured_z); + #endif + + measured_z -= zcorr; + + if (DEBUGGING(LEVELING)) DEBUG_ECHOLNPGM(" final >>>---> ", p_float_t(measured_z, 7)); + + if (param.V_verbosity > 3) { + SERIAL_ECHO_SP(16); + SERIAL_ECHOLNPGM("Corrected_Z=", measured_z); } + incremental_LSF(&lsf_results, rpos, measured_z); point_num++; } + if (abort_flag) break; zig_zag ^= true; } } @@ -1598,20 +1607,14 @@ void unified_bed_leveling::smart_fill_mesh() { probe.move_z_after_probing(); if (abort_flag || finish_incremental_LSF(&lsf_results)) { - SERIAL_ECHOPGM("Could not complete LSF!"); + SERIAL_ECHOLNPGM("Could not complete LSF!"); return; } vector_3 normal = vector_3(lsf_results.A, lsf_results.B, 1).get_normal(); - if (param.V_verbosity > 2) { - SERIAL_ECHOPAIR_F("bed plane normal = [", normal.x, 7); - SERIAL_CHAR(','); - SERIAL_ECHO_F(normal.y, 7); - SERIAL_CHAR(','); - SERIAL_ECHO_F(normal.z, 7); - SERIAL_ECHOLNPGM("]"); - } + if (param.V_verbosity > 2) + SERIAL_ECHOLN(F("bed plane normal = ["), p_float_t(normal.x, 7), C(','), p_float_t(normal.y, 7), C(','), p_float_t(normal.z, 7), C(']')); matrix_3x3 rotation = matrix_3x3::create_look_at(vector_3(lsf_results.A, lsf_results.B, 1)); @@ -1619,24 +1622,14 @@ void unified_bed_leveling::smart_fill_mesh() { float mx = get_mesh_x(i), my = get_mesh_y(j), mz = z_values[i][j]; if (DEBUGGING(LEVELING)) { - DEBUG_ECHOPAIR_F("before rotation = [", mx, 7); - DEBUG_CHAR(','); - DEBUG_ECHO_F(my, 7); - DEBUG_CHAR(','); - DEBUG_ECHO_F(mz, 7); - DEBUG_ECHOPGM("] ---> "); + DEBUG_ECHOLN(F("before rotation = ["), p_float_t(mx, 7), C(','), p_float_t(my, 7), C(','), p_float_t(mz, 7), F("] ---> ")); DEBUG_DELAY(20); } rotation.apply_rotation_xyz(mx, my, mz); if (DEBUGGING(LEVELING)) { - DEBUG_ECHOPAIR_F("after rotation = [", mx, 7); - DEBUG_CHAR(','); - DEBUG_ECHO_F(my, 7); - DEBUG_CHAR(','); - DEBUG_ECHO_F(mz, 7); - DEBUG_ECHOLNPGM("]"); + DEBUG_ECHOLN(F("after rotation = ["), p_float_t(mx, 7), C(','), p_float_t(my, 7), C(','), p_float_t(mz, 7), F("] ---> ")); DEBUG_DELAY(20); } @@ -1646,17 +1639,9 @@ void unified_bed_leveling::smart_fill_mesh() { if (DEBUGGING(LEVELING)) { rotation.debug(F("rotation matrix:\n")); - DEBUG_ECHOPAIR_F("LSF Results A=", lsf_results.A, 7); - DEBUG_ECHOPAIR_F(" B=", lsf_results.B, 7); - DEBUG_ECHOLNPAIR_F(" D=", lsf_results.D, 7); + DEBUG_ECHOLN(F("LSF Results A="), p_float_t(lsf_results.A, 7), F(" B="), p_float_t(lsf_results.B, 7), F(" D="), p_float_t(lsf_results.D, 7)); DEBUG_DELAY(55); - - DEBUG_ECHOPAIR_F("bed plane normal = [", normal.x, 7); - DEBUG_CHAR(','); - DEBUG_ECHO_F(normal.y, 7); - DEBUG_CHAR(','); - DEBUG_ECHO_F(normal.z, 7); - DEBUG_ECHOLNPGM("]"); + DEBUG_ECHOLN(F("bed plane normal = ["), p_float_t(normal.x, 7), C(','), p_float_t(normal.y, 7), C(','), p_float_t(normal.z, 7), C(']')); DEBUG_EOL(); /** @@ -1667,25 +1652,24 @@ void unified_bed_leveling::smart_fill_mesh() { * The Z error between the probed point locations and the get_z_correction() * numbers for those locations should be 0. */ - #ifdef VALIDATE_MESH_TILT + #if ENABLED(VALIDATE_MESH_TILT) auto d_from = []{ DEBUG_ECHOPGM("D from "); }; auto normed = [&](const xy_pos_t &pos, const_float_t zadd) { return normal.x * pos.x + normal.y * pos.y + zadd; }; - auto debug_pt = [](FSTR_P const pre, const xy_pos_t &pos, const_float_t zadd) { - d_from(); SERIAL_ECHOF(pre); - DEBUG_ECHO_F(normed(pos, zadd), 6); - DEBUG_ECHOLNPAIR_F(" Z error = ", zadd - get_z_correction(pos), 6); + auto debug_pt = [](const int num, const xy_pos_t &pos, const_float_t zadd) { + d_from(); + DEBUG_ECHOLN(F("Point "), num, C(':'), p_float_t(normed(pos, zadd), 6), F(" Z error = "), p_float_t(zadd - get_z_correction(pos), 6)); }; - debug_pt(F("1st point: "), probe_pt[0], normal.z * z1); - debug_pt(F("2nd point: "), probe_pt[1], normal.z * z2); - debug_pt(F("3rd point: "), probe_pt[2], normal.z * z3); - d_from(); DEBUG_ECHOPGM("safe home with Z="); - DEBUG_ECHOLNPAIR_F("0 : ", normed(safe_homing_xy, 0), 6); - d_from(); DEBUG_ECHOPGM("safe home with Z="); - DEBUG_ECHOLNPAIR_F("mesh value ", normed(safe_homing_xy, get_z_correction(safe_homing_xy)), 6); - DEBUG_ECHOPGM(" Z error = (", Z_SAFE_HOMING_X_POINT, ",", Z_SAFE_HOMING_Y_POINT); - DEBUG_ECHOLNPAIR_F(") = ", get_z_correction(safe_homing_xy), 6); + debug_pt(1, probe_pt[0], normal.z * gotz[0]); + debug_pt(2, probe_pt[1], normal.z * gotz[1]); + debug_pt(3, probe_pt[2], normal.z * gotz[2]); + #if ENABLED(Z_SAFE_HOMING) + constexpr xy_float_t safe_xy = { Z_SAFE_HOMING_X_POINT, Z_SAFE_HOMING_Y_POINT }; + d_from(); DEBUG_ECHOLN(F("safe home with Z="), F("0 : "), p_float_t(normed(safe_xy, 0), 6)); + d_from(); DEBUG_ECHOLN(F("safe home with Z="), F("mesh value "), p_float_t(normed(safe_xy, get_z_correction(safe_xy)), 6)); + DEBUG_ECHO(F(" Z error = ("), Z_SAFE_HOMING_X_POINT, C(','), Z_SAFE_HOMING_Y_POINT, F(") = "), p_float_t(get_z_correction(safe_xy), 6)); + #endif #endif } // DEBUGGING(LEVELING) @@ -1712,17 +1696,17 @@ void unified_bed_leveling::smart_fill_mesh() { GRID_LOOP(jx, jy) if (!isnan(z_values[jx][jy])) SBI(bitmap[jx], jy); xy_pos_t ppos; - LOOP_L_N(ix, GRID_MAX_POINTS_X) { + for (uint8_t ix = 0; ix < GRID_MAX_POINTS_X; ++ix) { ppos.x = get_mesh_x(ix); - LOOP_L_N(iy, GRID_MAX_POINTS_Y) { + for (uint8_t iy = 0; iy < GRID_MAX_POINTS_Y; ++iy) { ppos.y = get_mesh_y(iy); if (isnan(z_values[ix][iy])) { // undefined mesh point at (ppos.x,ppos.y), compute weighted LSF from original valid mesh points. incremental_LSF_reset(&lsf_results); xy_pos_t rpos; - LOOP_L_N(jx, GRID_MAX_POINTS_X) { + for (uint8_t jx = 0; jx < GRID_MAX_POINTS_X; ++jx) { rpos.x = get_mesh_x(jx); - LOOP_L_N(jy, GRID_MAX_POINTS_Y) { + for (uint8_t jy = 0; jy < GRID_MAX_POINTS_Y; ++jy) { if (TEST(bitmap[jx], jy)) { rpos.y = get_mesh_y(jy); const float rz = z_values[jx][jy], @@ -1732,7 +1716,7 @@ void unified_bed_leveling::smart_fill_mesh() { } } if (finish_incremental_LSF(&lsf_results)) { - SERIAL_ECHOLNPGM("Insufficient data"); + SERIAL_ECHOLNPGM(" Insufficient data"); return; } const float ez = -lsf_results.D - lsf_results.A * ppos.x - lsf_results.B * ppos.y; @@ -1743,7 +1727,7 @@ void unified_bed_leveling::smart_fill_mesh() { } } - SERIAL_ECHOLNPGM("done"); + SERIAL_ECHOLNPGM(" done."); } #endif // UBL_G29_P31 @@ -1756,20 +1740,19 @@ void unified_bed_leveling::smart_fill_mesh() { report_state(); if (storage_slot == -1) - SERIAL_ECHOPGM("No Mesh Loaded."); + SERIAL_ECHOLNPGM("No Mesh Loaded."); else - SERIAL_ECHOPGM("Mesh ", storage_slot, " Loaded."); - SERIAL_EOL(); + SERIAL_ECHOLNPGM("Mesh ", storage_slot, " Loaded."); serial_delay(50); #if ENABLED(ENABLE_LEVELING_FADE_HEIGHT) - SERIAL_ECHOLNPAIR_F("Fade Height M420 Z", planner.z_fade_height, 4); + SERIAL_ECHOLN(F("Fade Height M420 Z"), p_float_t(planner.z_fade_height, 4)); #endif adjust_mesh_to_mean(param.C_seen, param.C_constant); #if HAS_BED_PROBE - SERIAL_ECHOLNPAIR_F("Probe Offset M851 Z", probe.offset.z, 7); + SERIAL_ECHOLNPGM("Probe Offset M851 Z", p_float_t(probe.offset.z, 7)); #endif SERIAL_ECHOLNPGM("MESH_MIN_X " STRINGIFY(MESH_MIN_X) "=", MESH_MIN_X); serial_delay(50); @@ -1782,17 +1765,15 @@ void unified_bed_leveling::smart_fill_mesh() { SERIAL_ECHOLNPGM("MESH_Y_DIST ", MESH_Y_DIST); serial_delay(50); SERIAL_ECHOPGM("X-Axis Mesh Points at: "); - LOOP_L_N(i, GRID_MAX_POINTS_X) { - SERIAL_ECHO_F(LOGICAL_X_POSITION(get_mesh_x(i)), 3); - SERIAL_ECHOPGM(" "); + for (uint8_t i = 0; i < GRID_MAX_POINTS_X; ++i) { + SERIAL_ECHO(p_float_t(LOGICAL_X_POSITION(get_mesh_x(i)), 3), F(" ")); serial_delay(25); } SERIAL_EOL(); SERIAL_ECHOPGM("Y-Axis Mesh Points at: "); - LOOP_L_N(i, GRID_MAX_POINTS_Y) { - SERIAL_ECHO_F(LOGICAL_Y_POSITION(get_mesh_y(i)), 3); - SERIAL_ECHOPGM(" "); + for (uint8_t i = 0; i < GRID_MAX_POINTS_Y; ++i) { + SERIAL_ECHO(p_float_t(LOGICAL_Y_POSITION(get_mesh_y(i)), 3), F(" ")); serial_delay(25); } SERIAL_EOL(); @@ -1804,23 +1785,21 @@ void unified_bed_leveling::smart_fill_mesh() { SERIAL_EOL(); serial_delay(50); - #if ENABLED(UBL_DEVEL_DEBUGGING) - SERIAL_ECHOLNPGM("ubl_state_at_invocation :", ubl_state_at_invocation, "\nubl_state_recursion_chk :", ubl_state_recursion_chk); - serial_delay(50); + SERIAL_ECHOLNPGM("ubl_state_at_invocation :", ubl_state_at_invocation, "\nubl_state_recursion_chk :", ubl_state_recursion_chk); + serial_delay(50); - SERIAL_ECHOLNPGM("Meshes go from ", hex_address((void*)settings.meshes_start_index()), " to ", hex_address((void*)settings.meshes_end_index())); - serial_delay(50); + SERIAL_ECHOLNPGM("Meshes go from ", hex_address((void*)settings.meshes_start_index()), " to ", hex_address((void*)settings.meshes_end_index())); + serial_delay(50); - SERIAL_ECHOLNPGM("sizeof(ubl) : ", sizeof(ubl)); SERIAL_EOL(); - SERIAL_ECHOLNPGM("z_value[][] size: ", sizeof(z_values)); SERIAL_EOL(); - serial_delay(25); + SERIAL_ECHOLNPGM("sizeof(unified_bed_leveling) : ", sizeof(unified_bed_leveling)); + SERIAL_ECHOLNPGM("z_value[][] size: ", sizeof(z_values)); + serial_delay(25); - SERIAL_ECHOLNPGM("EEPROM free for UBL: ", hex_address((void*)(settings.meshes_end_index() - settings.meshes_start_index()))); - serial_delay(50); + SERIAL_ECHOLNPGM("EEPROM free for UBL: ", hex_address((void*)(settings.meshes_end_index() - settings.meshes_start_index()))); + serial_delay(50); - SERIAL_ECHOLNPGM("EEPROM can hold ", settings.calc_num_meshes(), " meshes.\n"); - serial_delay(25); - #endif // UBL_DEVEL_DEBUGGING + SERIAL_ECHOLNPGM("EEPROM can hold ", settings.calc_num_meshes(), " meshes.\n"); + serial_delay(25); if (!sanity_check()) { echo_name(); diff --git a/Marlin/src/feature/bedlevel/ubl/ubl_motion.cpp b/Marlin/src/feature/bedlevel/ubl/ubl_motion.cpp index 96c30a0efd..053a68b77d 100644 --- a/Marlin/src/feature/bedlevel/ubl/ubl_motion.cpp +++ b/Marlin/src/feature/bedlevel/ubl/ubl_motion.cpp @@ -61,7 +61,7 @@ const xyze_pos_t &start = current_position, &end = destination; #endif - const xy_int8_t istart = cell_indexes(start), iend = cell_indexes(end); + const xy_uint8_t istart = cell_indexes(start), iend = cell_indexes(end); // A move within the same cell needs no splitting if (istart == iend) { @@ -108,7 +108,7 @@ const xy_float_t dist = end - start; const xy_bool_t neg { dist.x < 0, dist.y < 0 }; - const xy_int8_t ineg { int8_t(neg.x), int8_t(neg.y) }; + const xy_uint8_t ineg { uint8_t(neg.x), uint8_t(neg.y) }; const xy_float_t sign { neg.x ? -1.0f : 1.0f, neg.y ? -1.0f : 1.0f }; const xy_int8_t iadd { int8_t(iend.x == istart.x ? 0 : sign.x), int8_t(iend.y == istart.y ? 0 : sign.y) }; @@ -131,7 +131,7 @@ const bool inf_normalized_flag = isinf(e_normalized_dist); #endif - xy_int8_t icell = istart; + xy_uint8_t icell = istart; const float ratio = dist.y / dist.x, // Allow divide by zero c = start.y - ratio * start.x; @@ -252,7 +252,7 @@ * Generic case of a line crossing both X and Y Mesh lines. */ - xy_int8_t cnt = (istart - iend).ABS(); + xy_uint8_t cnt = istart.diff(iend); icell += ineg; @@ -334,16 +334,14 @@ #else // UBL_SEGMENTED #if IS_SCARA - #define DELTA_SEGMENT_MIN_LENGTH 0.25 // SCARA minimum segment size is 0.25mm - #elif ENABLED(DELTA) - #define DELTA_SEGMENT_MIN_LENGTH 0.10 // mm (still subject to DEFAULT_SEGMENTS_PER_SECOND) - #elif ENABLED(POLARGRAPH) - #define DELTA_SEGMENT_MIN_LENGTH 0.10 // mm (still subject to DEFAULT_SEGMENTS_PER_SECOND) + #define SEGMENT_MIN_LENGTH 0.25 // SCARA minimum segment size is 0.25mm + #elif IS_KINEMATIC + #define SEGMENT_MIN_LENGTH 0.10 // (mm) Still subject to DEFAULT_SEGMENTS_PER_SECOND #else // CARTESIAN #ifdef LEVELED_SEGMENT_LENGTH - #define DELTA_SEGMENT_MIN_LENGTH LEVELED_SEGMENT_LENGTH + #define SEGMENT_MIN_LENGTH LEVELED_SEGMENT_LENGTH #else - #define DELTA_SEGMENT_MIN_LENGTH 1.00 // mm (similar to G2/G3 arc segmentation) + #define SEGMENT_MIN_LENGTH 1.00 // (mm) Similar to G2/G3 arc segmentation #endif #endif @@ -361,23 +359,23 @@ const xyze_pos_t total = destination - current_position; const float cart_xy_mm_2 = HYPOT2(total.x, total.y), - cart_xy_mm = SQRT(cart_xy_mm_2); // Total XY distance + cart_xy_mm = SQRT(cart_xy_mm_2); // Total XY distance #if IS_KINEMATIC - const float seconds = cart_xy_mm / scaled_fr_mm_s; // Duration of XY move at requested rate - uint16_t segments = LROUND(segments_per_second * seconds), // Preferred number of segments for distance @ feedrate - seglimit = LROUND(cart_xy_mm * RECIPROCAL(DELTA_SEGMENT_MIN_LENGTH)); // Number of segments at minimum segment length - NOMORE(segments, seglimit); // Limit to minimum segment length (fewer segments) + const float seconds = cart_xy_mm / scaled_fr_mm_s; // Duration of XY move at requested rate + uint16_t segments = LROUND(segments_per_second * seconds), // Preferred number of segments for distance @ feedrate + seglimit = LROUND(cart_xy_mm * RECIPROCAL(SEGMENT_MIN_LENGTH)); // Number of segments at minimum segment length + NOMORE(segments, seglimit); // Limit to minimum segment length (fewer segments) #else - uint16_t segments = LROUND(cart_xy_mm * RECIPROCAL(DELTA_SEGMENT_MIN_LENGTH)); // Cartesian fixed segment length + uint16_t segments = LROUND(cart_xy_mm * RECIPROCAL(SEGMENT_MIN_LENGTH)); // Cartesian fixed segment length #endif - NOLESS(segments, 1U); // Must have at least one segment - const float inv_segments = 1.0f / segments; // Reciprocal to save calculation + NOLESS(segments, 1U); // Must have at least one segment + const float inv_segments = 1.0f / segments; // Reciprocal to save calculation // Add hints to help optimize the move - PlannerHints hints(SQRT(cart_xy_mm_2 + sq(total.z)) * inv_segments); // Length of each segment - #if ENABLED(SCARA_FEEDRATE_SCALING) + PlannerHints hints(SQRT(cart_xy_mm_2 + sq(total.z)) * inv_segments); // Length of each segment + #if ENABLED(FEEDRATE_SCALING) hints.inv_duration = scaled_fr_mm_s / hints.millimeters; #endif diff --git a/Marlin/src/feature/binary_stream.h b/Marlin/src/feature/binary_stream.h index 417e39c745..a9cd12b85e 100644 --- a/Marlin/src/feature/binary_stream.h +++ b/Marlin/src/feature/binary_stream.h @@ -281,7 +281,7 @@ public: uint8_t data = 0; millis_t transfer_window = millis() + RX_TIMESLICE; - #if ENABLED(SDSUPPORT) + #if HAS_MEDIA PORT_REDIRECT(SERIAL_PORTMASK(card.transfer_port_index)); #endif diff --git a/Marlin/src/feature/bltouch.cpp b/Marlin/src/feature/bltouch.cpp index 10d3131aed..02f76c1392 100644 --- a/Marlin/src/feature/bltouch.cpp +++ b/Marlin/src/feature/bltouch.cpp @@ -29,7 +29,7 @@ BLTouch bltouch; bool BLTouch::od_5v_mode; // Initialized by settings.load, 0 = Open Drain; 1 = 5V Drain -#ifdef BLTOUCH_HS_MODE +#if HAS_BLTOUCH_HS_MODE bool BLTouch::high_speed_mode; // Initialized by settings.load, 0 = Low Speed; 1 = High Speed #else constexpr bool BLTouch::high_speed_mode; @@ -38,15 +38,18 @@ bool BLTouch::od_5v_mode; // Initialized by settings.load, 0 = Open Drai #include "../module/servo.h" #include "../module/probe.h" -void stop(); - #define DEBUG_OUT ENABLED(DEBUG_LEVELING_FEATURE) #include "../core/debug_out.h" bool BLTouch::command(const BLTCommand cmd, const millis_t &ms) { - if (DEBUGGING(LEVELING)) SERIAL_ECHOLNPGM("BLTouch Command :", cmd); - servo[Z_PROBE_SERVO_NR].move(cmd); - safe_delay(_MAX(ms, (uint32_t)BLTOUCH_DELAY)); // BLTOUCH_DELAY is also the *minimum* delay + const BLTCommand current = servo[Z_PROBE_SERVO_NR].read(); + if (DEBUGGING(LEVELING)) SERIAL_ECHOLNPGM("BLTouch from ", current, " to ", cmd); + // If the new command is the same, skip it (and the delay). + // The previous write should've already delayed to detect the alarm. + if (cmd != current) { + servo[Z_PROBE_SERVO_NR].move(cmd); + safe_delay(_MAX(ms, (uint32_t)BLTOUCH_DELAY)); // BLTOUCH_DELAY is also the *minimum* delay + } return triggered(); } diff --git a/Marlin/src/feature/bltouch.h b/Marlin/src/feature/bltouch.h index fa857bb96a..0f9f2e68ba 100644 --- a/Marlin/src/feature/bltouch.h +++ b/Marlin/src/feature/bltouch.h @@ -70,13 +70,13 @@ public: static void init(const bool set_voltage=false); static bool od_5v_mode; // Initialized by settings.load, 0 = Open Drain; 1 = 5V Drain - #ifdef BLTOUCH_HS_MODE + #if HAS_BLTOUCH_HS_MODE static bool high_speed_mode; // Initialized by settings.load, 0 = Low Speed; 1 = High Speed #else static constexpr bool high_speed_mode = false; #endif - static float z_extra_clearance() { return high_speed_mode ? 7 : 0; } + static float z_extra_clearance() { return TERN0(HAS_BLTOUCH_HS_MODE, high_speed_mode ? BLTOUCH_HS_EXTRA_CLEARANCE : 0); } // DEPLOY and STOW are wrapped for error handling - these are used by homing and by probing static bool deploy() { return deploy_proc(); } diff --git a/Marlin/src/feature/cancel_object.cpp b/Marlin/src/feature/cancel_object.cpp index bffd2bb720..0040f6ed9d 100644 --- a/Marlin/src/feature/cancel_object.cpp +++ b/Marlin/src/feature/cancel_object.cpp @@ -44,9 +44,9 @@ void CancelObject::set_active_object(const int8_t obj) { else skipping = false; - #if BOTH(HAS_STATUS_MESSAGE, CANCEL_OBJECTS_REPORTING) + #if ALL(HAS_STATUS_MESSAGE, CANCEL_OBJECTS_REPORTING) if (active_object >= 0) - ui.status_printf(0, F(S_FMT " %i"), GET_TEXT(MSG_PRINTING_OBJECT), int(active_object)); + ui.set_status(MString<30>(GET_TEXT_F(MSG_PRINTING_OBJECT), ' ', active_object)); else ui.reset_status(); #endif diff --git a/Marlin/src/feature/caselight.h b/Marlin/src/feature/caselight.h index 17e1222acb..d88b3d67bf 100644 --- a/Marlin/src/feature/caselight.h +++ b/Marlin/src/feature/caselight.h @@ -30,7 +30,7 @@ class CaseLight { public: static bool on; - #if ENABLED(CASELIGHT_USES_BRIGHTNESS) + #if CASELIGHT_USES_BRIGHTNESS static uint8_t brightness; #endif diff --git a/Marlin/src/feature/controllerfan.cpp b/Marlin/src/feature/controllerfan.cpp index 2f25832cdc..816ffb23b7 100644 --- a/Marlin/src/feature/controllerfan.cpp +++ b/Marlin/src/feature/controllerfan.cpp @@ -38,8 +38,15 @@ uint8_t ControllerFan::speed; const controllerFan_settings_t &ControllerFan::settings = controllerFan_defaults; #endif +#if ENABLED(FAN_SOFT_PWM) + uint8_t ControllerFan::soft_pwm_speed; +#endif + void ControllerFan::setup() { SET_OUTPUT(CONTROLLER_FAN_PIN); + #ifdef CONTROLLER_FAN2_PIN + SET_OUTPUT(CONTROLLER_FAN2_PIN); + #endif init(); } @@ -58,10 +65,16 @@ void ControllerFan::update() { // - At least one stepper driver is enabled // - The heated bed is enabled // - TEMP_SENSOR_BOARD is reporting >= CONTROLLER_FAN_MIN_BOARD_TEMP + // - TEMP_SENSOR_SOC is reporting >= CONTROLLER_FAN_MIN_SOC_TEMP const ena_mask_t axis_mask = TERN(CONTROLLER_FAN_USE_Z_ONLY, _BV(Z_AXIS), (ena_mask_t)~TERN0(CONTROLLER_FAN_IGNORE_Z, _BV(Z_AXIS))); if ( (stepper.axis_enabled.bits & axis_mask) || TERN0(HAS_HEATED_BED, thermalManager.temp_bed.soft_pwm_amount > 0) - || TERN0(HAS_CONTROLLER_FAN_MIN_BOARD_TEMP, thermalManager.wholeDegBoard() >= CONTROLLER_FAN_MIN_BOARD_TEMP) + #ifdef CONTROLLER_FAN_MIN_BOARD_TEMP + || thermalManager.wholeDegBoard() >= CONTROLLER_FAN_MIN_BOARD_TEMP + #endif + #ifdef CONTROLLER_FAN_MIN_SOC_TEMP + || thermalManager.wholeDegSoc() >= CONTROLLER_FAN_MIN_SOC_TEMP + #endif ) lastMotorOn = ms; //... set time to NOW so the fan will turn on // Fan Settings. Set fan > 0: @@ -89,12 +102,19 @@ void ControllerFan::update() { #endif #if ENABLED(FAN_SOFT_PWM) - thermalManager.soft_pwm_controller_speed = speed; + soft_pwm_speed = speed; #else if (PWM_PIN(CONTROLLER_FAN_PIN)) hal.set_pwm_duty(pin_t(CONTROLLER_FAN_PIN), speed); else WRITE(CONTROLLER_FAN_PIN, speed > 0); + + #ifdef CONTROLLER_FAN2_PIN + if (PWM_PIN(CONTROLLER_FAN2_PIN)) + hal.set_pwm_duty(pin_t(CONTROLLER_FAN2_PIN), speed); + else + WRITE(CONTROLLER_FAN2_PIN, speed > 0); + #endif #endif } } diff --git a/Marlin/src/feature/controllerfan.h b/Marlin/src/feature/controllerfan.h index 55eb2359b0..68502afa66 100644 --- a/Marlin/src/feature/controllerfan.h +++ b/Marlin/src/feature/controllerfan.h @@ -60,6 +60,9 @@ class ControllerFan { #else static const controllerFan_settings_t &settings; #endif + #if ENABLED(FAN_SOFT_PWM) + static uint8_t soft_pwm_speed; + #endif static bool state() { return speed > 0; } static void init() { reset(); } static void reset() { TERN_(CONTROLLER_FAN_EDITABLE, settings = controllerFan_defaults); } diff --git a/Marlin/src/feature/cooler.cpp b/Marlin/src/feature/cooler.cpp index e0f99777d1..6c45e99226 100644 --- a/Marlin/src/feature/cooler.cpp +++ b/Marlin/src/feature/cooler.cpp @@ -22,7 +22,7 @@ #include "../inc/MarlinConfig.h" -#if EITHER(HAS_COOLER, LASER_COOLANT_FLOW_METER) +#if ANY(HAS_COOLER, LASER_COOLANT_FLOW_METER) #include "cooler.h" Cooler cooler; diff --git a/Marlin/src/feature/digipot/digipot_mcp4018.cpp b/Marlin/src/feature/digipot/digipot_mcp4018.cpp index 3f2ecbfcdc..f776c5a339 100644 --- a/Marlin/src/feature/digipot/digipot_mcp4018.cpp +++ b/Marlin/src/feature/digipot/digipot_mcp4018.cpp @@ -89,7 +89,7 @@ void DigipotI2C::set_current(const uint8_t channel, const float current) { } void DigipotI2C::init() { - LOOP_L_N(i, DIGIPOT_I2C_NUM_CHANNELS) pots[i].i2c_init(); + for (uint8_t i = 0; i < DIGIPOT_I2C_NUM_CHANNELS; ++i) pots[i].i2c_init(); // Init currents according to Configuration_adv.h static const float digipot_motor_current[] PROGMEM = @@ -99,7 +99,7 @@ void DigipotI2C::init() { DIGIPOT_I2C_MOTOR_CURRENTS #endif ; - LOOP_L_N(i, COUNT(digipot_motor_current)) + for (uint8_t i = 0; i < COUNT(digipot_motor_current); ++i) set_current(i, pgm_read_float(&digipot_motor_current[i])); } diff --git a/Marlin/src/feature/digipot/digipot_mcp4451.cpp b/Marlin/src/feature/digipot/digipot_mcp4451.cpp index ba5ecdad05..7416fe9f8d 100644 --- a/Marlin/src/feature/digipot/digipot_mcp4451.cpp +++ b/Marlin/src/feature/digipot/digipot_mcp4451.cpp @@ -94,7 +94,7 @@ void DigipotI2C::init() { DIGIPOT_I2C_MOTOR_CURRENTS #endif ; - LOOP_L_N(i, COUNT(digipot_motor_current)) + for (uint8_t i = 0; i < COUNT(digipot_motor_current); ++i) set_current(i, pgm_read_float(&digipot_motor_current[i])); } diff --git a/Marlin/src/feature/direct_stepping.h b/Marlin/src/feature/direct_stepping.h index 962310281e..b8a803f811 100644 --- a/Marlin/src/feature/direct_stepping.h +++ b/Marlin/src/feature/direct_stepping.h @@ -80,9 +80,6 @@ namespace DirectStepping { static void set_page_state(const page_idx_t page_idx, const PageState page_state); }; - template struct TypeSelector { typedef T type;} ; - template struct TypeSelector { typedef F type; }; - template struct config_t { static constexpr char CONTROL_CHAR = '!'; @@ -98,8 +95,8 @@ namespace DirectStepping { static constexpr int TOTAL_STEPS = SEGMENT_STEPS * SEGMENTS; static constexpr int PAGE_SIZE = (AXIS_COUNT * BITS_SEGMENT * SEGMENTS) / 8; - typedef typename TypeSelector<(PAGE_SIZE>256), uint16_t, uint8_t>::type write_byte_idx_t; - typedef typename TypeSelector<(PAGE_COUNT>256), uint16_t, uint8_t>::type page_idx_t; + typedef uvalue_t(PAGE_SIZE - 1) write_byte_idx_t; + typedef uvalue_t(PAGE_COUNT - 1) page_idx_t; }; template diff --git a/Marlin/src/feature/e_parser.cpp b/Marlin/src/feature/e_parser.cpp index cfe0956aa7..da193ed30a 100644 --- a/Marlin/src/feature/e_parser.cpp +++ b/Marlin/src/feature/e_parser.cpp @@ -24,7 +24,7 @@ * e_parser.cpp - Intercept special commands directly in the serial stream */ -#include "../inc/MarlinConfigPre.h" +#include "../inc/MarlinConfig.h" #if ENABLED(EMERGENCY_PARSER) @@ -33,16 +33,199 @@ // Static data members bool EmergencyParser::killed_by_M112, // = false EmergencyParser::quickstop_by_M410, - #if ENABLED(SDSUPPORT) + #if HAS_MEDIA EmergencyParser::sd_abort_by_M524, #endif EmergencyParser::enabled; #if ENABLED(HOST_PROMPT_SUPPORT) + #include "host_actions.h" uint8_t EmergencyParser::M876_reason; // = 0 #endif // Global instance EmergencyParser emergency_parser; +// External references +extern bool wait_for_user, wait_for_heatup; + +#if ENABLED(EP_BABYSTEPPING) + #include "babystep.h" +#endif + +#if ENABLED(REALTIME_REPORTING_COMMANDS) + // From motion.h, which cannot be included here + void report_current_position_moving(); + void quickpause_stepper(); + void quickresume_stepper(); +#endif + +void EmergencyParser::update(EmergencyParser::State &state, const uint8_t c) { + switch (state) { + case EP_RESET: + switch (c) { + case ' ': case '\n': case '\r': break; + case 'N': state = EP_N; break; + case 'M': state = EP_M; break; + #if ENABLED(REALTIME_REPORTING_COMMANDS) + case 'S': state = EP_S; break; + case 'P': state = EP_P; break; + case 'R': state = EP_R; break; + #endif + #if ENABLED(SOFT_RESET_VIA_SERIAL) + case '^': state = EP_ctrl; break; + case 'K': state = EP_K; break; + #endif + default: state = EP_IGNORE; + } + break; + + case EP_N: + switch (c) { + case '0' ... '9': + case '-': case ' ': break; + case 'M': state = EP_M; break; + #if ENABLED(REALTIME_REPORTING_COMMANDS) + case 'S': state = EP_S; break; + case 'P': state = EP_P; break; + case 'R': state = EP_R; break; + #endif + default: state = EP_IGNORE; + } + break; + + #if ENABLED(REALTIME_REPORTING_COMMANDS) + case EP_S: state = (c == '0') ? EP_S0 : EP_IGNORE; break; + case EP_S0: state = (c == '0') ? EP_S00 : EP_IGNORE; break; + case EP_S00: state = (c == '0') ? EP_GRBL_STATUS : EP_IGNORE; break; + + case EP_R: state = (c == '0') ? EP_R0 : EP_IGNORE; break; + case EP_R0: state = (c == '0') ? EP_R00 : EP_IGNORE; break; + case EP_R00: state = (c == '0') ? EP_GRBL_RESUME : EP_IGNORE; break; + + case EP_P: state = (c == '0') ? EP_P0 : EP_IGNORE; break; + case EP_P0: state = (c == '0') ? EP_P00 : EP_IGNORE; break; + case EP_P00: state = (c == '0') ? EP_GRBL_PAUSE : EP_IGNORE; break; + #endif + + #if ENABLED(SOFT_RESET_VIA_SERIAL) + case EP_ctrl: state = (c == 'X') ? EP_KILL : EP_IGNORE; break; + case EP_K: state = (c == 'I') ? EP_KI : EP_IGNORE; break; + case EP_KI: state = (c == 'L') ? EP_KIL : EP_IGNORE; break; + case EP_KIL: state = (c == 'L') ? EP_KILL : EP_IGNORE; break; + #endif + + case EP_M: + switch (c) { + case ' ': break; + case '1': state = EP_M1; break; + #if ENABLED(EP_BABYSTEPPING) + case '2': state = EP_M2; break; + #endif + case '4': state = EP_M4; break; + #if HAS_MEDIA + case '5': state = EP_M5; break; + #endif + #if ENABLED(HOST_PROMPT_SUPPORT) + case '8': state = EP_M8; break; + #endif + default: state = EP_IGNORE; + } + break; + + case EP_M1: + switch (c) { + case '0': state = EP_M10; break; + case '1': state = EP_M11; break; + default: state = EP_IGNORE; + } + break; + + case EP_M10: state = (c == '8') ? EP_M108 : EP_IGNORE; break; + case EP_M11: state = (c == '2') ? EP_M112 : EP_IGNORE; break; + case EP_M4: state = (c == '1') ? EP_M41 : EP_IGNORE; break; + case EP_M41: state = (c == '0') ? EP_M410 : EP_IGNORE; break; + + #if HAS_MEDIA + case EP_M5: state = (c == '2') ? EP_M52 : EP_IGNORE; break; + case EP_M52: state = (c == '4') ? EP_M524 : EP_IGNORE; break; + #endif + + #if ENABLED(EP_BABYSTEPPING) + case EP_M2: + switch (c) { + case '9': state = EP_M29; break; + default: state = EP_IGNORE; + } + break; + + case EP_M29: + switch (c) { + case '3': state = EP_M293; break; + case '4': state = EP_M294; break; + default: state = EP_IGNORE; + } + break; + #endif + + #if ENABLED(HOST_PROMPT_SUPPORT) + + case EP_M8: state = (c == '7') ? EP_M87 : EP_IGNORE; break; + case EP_M87: state = (c == '6') ? EP_M876 : EP_IGNORE; break; + + case EP_M876: + switch (c) { + case ' ': break; + case 'S': state = EP_M876S; break; + default: state = EP_IGNORE; break; + } + break; + + case EP_M876S: + switch (c) { + case ' ': break; + case '0' ... '9': + state = EP_M876SN; + M876_reason = uint8_t(c - '0'); + break; + } + break; + + #endif + + case EP_IGNORE: + if (ISEOL(c)) state = EP_RESET; + break; + + default: + if (ISEOL(c)) { + if (enabled) switch (state) { + case EP_M108: wait_for_user = wait_for_heatup = false; break; + case EP_M112: killed_by_M112 = true; break; + case EP_M410: quickstop_by_M410 = true; break; + #if ENABLED(EP_BABYSTEPPING) + case EP_M293: babystep.ep_babysteps++; break; + case EP_M294: babystep.ep_babysteps--; break; + #endif + #if HAS_MEDIA + case EP_M524: sd_abort_by_M524 = true; break; + #endif + #if ENABLED(HOST_PROMPT_SUPPORT) + case EP_M876SN: hostui.handle_response(M876_reason); break; + #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; + #endif + #if ENABLED(SOFT_RESET_VIA_SERIAL) + case EP_KILL: hal.reboot(); break; + #endif + default: break; + } + state = EP_RESET; + } + } +} + #endif // EMERGENCY_PARSER diff --git a/Marlin/src/feature/e_parser.h b/Marlin/src/feature/e_parser.h index 3a15a7ffa0..8dacb0581c 100644 --- a/Marlin/src/feature/e_parser.h +++ b/Marlin/src/feature/e_parser.h @@ -27,24 +27,6 @@ #include "../inc/MarlinConfigPre.h" -#if ENABLED(HOST_PROMPT_SUPPORT) - #include "host_actions.h" -#endif - -// External references -extern bool wait_for_user, wait_for_heatup; - -#if ENABLED(REALTIME_REPORTING_COMMANDS) - // From motion.h, which cannot be included here - void report_current_position_moving(); - void quickpause_stepper(); - void quickresume_stepper(); -#endif - -#if ENABLED(SOFT_RESET_VIA_SERIAL) - void HAL_reboot(); -#endif - class EmergencyParser { public: @@ -58,9 +40,12 @@ public: EP_M10, EP_M108, EP_M11, EP_M112, EP_M4, EP_M41, EP_M410, - #if ENABLED(SDSUPPORT) + #if HAS_MEDIA EP_M5, EP_M52, EP_M524, #endif + #if ENABLED(EP_BABYSTEPPING) + EP_M2, EP_M29, EP_M293, EP_M294, + #endif #if ENABLED(HOST_PROMPT_SUPPORT) EP_M8, EP_M87, EP_M876, EP_M876S, EP_M876SN, #endif @@ -79,7 +64,7 @@ public: static bool killed_by_M112; static bool quickstop_by_M410; - #if ENABLED(SDSUPPORT) + #if HAS_MEDIA static bool sd_abort_by_M524; #endif @@ -92,149 +77,7 @@ public: FORCE_INLINE static void enable() { enabled = true; } FORCE_INLINE static void disable() { enabled = false; } - FORCE_INLINE static void update(State &state, const uint8_t c) { - switch (state) { - case EP_RESET: - switch (c) { - case ' ': case '\n': case '\r': break; - case 'N': state = EP_N; break; - case 'M': state = EP_M; break; - #if ENABLED(REALTIME_REPORTING_COMMANDS) - case 'S': state = EP_S; break; - case 'P': state = EP_P; break; - case 'R': state = EP_R; break; - #endif - #if ENABLED(SOFT_RESET_VIA_SERIAL) - case '^': state = EP_ctrl; break; - case 'K': state = EP_K; break; - #endif - default: state = EP_IGNORE; - } - break; - - case EP_N: - switch (c) { - case '0' ... '9': - case '-': case ' ': break; - case 'M': state = EP_M; break; - #if ENABLED(REALTIME_REPORTING_COMMANDS) - case 'S': state = EP_S; break; - case 'P': state = EP_P; break; - case 'R': state = EP_R; break; - #endif - default: state = EP_IGNORE; - } - break; - - #if ENABLED(REALTIME_REPORTING_COMMANDS) - case EP_S: state = (c == '0') ? EP_S0 : EP_IGNORE; break; - case EP_S0: state = (c == '0') ? EP_S00 : EP_IGNORE; break; - case EP_S00: state = (c == '0') ? EP_GRBL_STATUS : EP_IGNORE; break; - - case EP_R: state = (c == '0') ? EP_R0 : EP_IGNORE; break; - case EP_R0: state = (c == '0') ? EP_R00 : EP_IGNORE; break; - case EP_R00: state = (c == '0') ? EP_GRBL_RESUME : EP_IGNORE; break; - - case EP_P: state = (c == '0') ? EP_P0 : EP_IGNORE; break; - case EP_P0: state = (c == '0') ? EP_P00 : EP_IGNORE; break; - case EP_P00: state = (c == '0') ? EP_GRBL_PAUSE : EP_IGNORE; break; - #endif - - #if ENABLED(SOFT_RESET_VIA_SERIAL) - case EP_ctrl: state = (c == 'X') ? EP_KILL : EP_IGNORE; break; - case EP_K: state = (c == 'I') ? EP_KI : EP_IGNORE; break; - case EP_KI: state = (c == 'L') ? EP_KIL : EP_IGNORE; break; - case EP_KIL: state = (c == 'L') ? EP_KILL : EP_IGNORE; break; - #endif - - case EP_M: - switch (c) { - case ' ': break; - case '1': state = EP_M1; break; - case '4': state = EP_M4; break; - #if ENABLED(SDSUPPORT) - case '5': state = EP_M5; break; - #endif - #if ENABLED(HOST_PROMPT_SUPPORT) - case '8': state = EP_M8; break; - #endif - default: state = EP_IGNORE; - } - break; - - case EP_M1: - switch (c) { - case '0': state = EP_M10; break; - case '1': state = EP_M11; break; - default: state = EP_IGNORE; - } - break; - - case EP_M10: state = (c == '8') ? EP_M108 : EP_IGNORE; break; - case EP_M11: state = (c == '2') ? EP_M112 : EP_IGNORE; break; - case EP_M4: state = (c == '1') ? EP_M41 : EP_IGNORE; break; - case EP_M41: state = (c == '0') ? EP_M410 : EP_IGNORE; break; - - #if ENABLED(SDSUPPORT) - case EP_M5: state = (c == '2') ? EP_M52 : EP_IGNORE; break; - case EP_M52: state = (c == '4') ? EP_M524 : EP_IGNORE; break; - #endif - - #if ENABLED(HOST_PROMPT_SUPPORT) - - case EP_M8: state = (c == '7') ? EP_M87 : EP_IGNORE; break; - case EP_M87: state = (c == '6') ? EP_M876 : EP_IGNORE; break; - - case EP_M876: - switch (c) { - case ' ': break; - case 'S': state = EP_M876S; break; - default: state = EP_IGNORE; break; - } - break; - - case EP_M876S: - switch (c) { - case ' ': break; - case '0' ... '9': - state = EP_M876SN; - M876_reason = uint8_t(c - '0'); - break; - } - break; - - #endif - - case EP_IGNORE: - if (ISEOL(c)) state = EP_RESET; - break; - - default: - if (ISEOL(c)) { - if (enabled) switch (state) { - case EP_M108: wait_for_user = wait_for_heatup = false; break; - case EP_M112: killed_by_M112 = true; break; - case EP_M410: quickstop_by_M410 = true; break; - #if ENABLED(SDSUPPORT) - case EP_M524: sd_abort_by_M524 = true; break; - #endif - #if ENABLED(HOST_PROMPT_SUPPORT) - case EP_M876SN: hostui.handle_response(M876_reason); break; - #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; - #endif - #if ENABLED(SOFT_RESET_VIA_SERIAL) - case EP_KILL: HAL_reboot(); break; - #endif - default: break; - } - state = EP_RESET; - } - } - } + static void update(State &state, const uint8_t c); private: static bool enabled; diff --git a/Marlin/src/feature/easythreed_ui.cpp b/Marlin/src/feature/easythreed_ui.cpp index b15daffc09..39248bfc7d 100644 --- a/Marlin/src/feature/easythreed_ui.cpp +++ b/Marlin/src/feature/easythreed_ui.cpp @@ -190,31 +190,28 @@ void EasythreedUI::printButton() { print_key_flag = PF_PAUSE; // The "Print" button now pauses the print card.mount(); // Force SD card to mount - now! if (!card.isMounted) { // Failed to mount? - blink_interval_ms = LED_OFF; // Turn off LED - print_key_flag = PF_START; - return; // Bail out + blink_interval_ms = LED_OFF; // Turn off LED + print_key_flag = PF_START; + return; // Bail out } card.ls(); // List all files to serial output - const uint16_t filecnt = card.countFilesInWorkDir(); // Count printable files in cwd + const int16_t filecnt = card.get_num_items(); // Count printable files in cwd if (filecnt == 0) return; // None are printable? card.selectFileByIndex(filecnt); // Select the last file according to current sort options card.openAndPrintFile(card.filename); // Start printing it - break; - } + } break; case PF_PAUSE: { // Pause printing (not currently firing) if (!printingIsActive()) break; blink_interval_ms = LED_ON; // Set indicator to steady ON queue.inject(F("M25")); // Queue Pause print_key_flag = PF_RESUME; // The "Print" button now resumes the print - break; - } + } break; case PF_RESUME: { // Resume printing if (printingIsActive()) break; blink_interval_ms = LED_BLINK_2; // Blink the indicator LED at 1 second intervals queue.inject(F("M24")); // Queue resume print_key_flag = PF_PAUSE; // The "Print" button now pauses the print - break; - } + } break; } } else { // Register a longer press diff --git a/Marlin/src/feature/encoder_i2c.cpp b/Marlin/src/feature/encoder_i2c.cpp index 092ce0f8b8..5a0564ee71 100644 --- a/Marlin/src/feature/encoder_i2c.cpp +++ b/Marlin/src/feature/encoder_i2c.cpp @@ -49,7 +49,7 @@ void I2CPositionEncoder::init(const uint8_t address, const AxisEnum axis) { initialized = true; - SERIAL_ECHOLNPGM("Setting up encoder on ", AS_CHAR(AXIS_CHAR(encoderAxis)), " axis, addr = ", address); + SERIAL_ECHOLNPGM("Setting up encoder on ", C(AXIS_CHAR(encoderAxis)), " axis, addr = ", address); position = get_position(); } @@ -67,7 +67,7 @@ void I2CPositionEncoder::update() { /* if (trusted) { //commented out as part of the note below trusted = false; - SERIAL_ECHOLNPGM("Fault detected on ", AS_CHAR(AXIS_CHAR(encoderAxis)), " axis encoder. Disengaging error correction until module is trusted again."); + SERIAL_ECHOLNPGM("Fault detected on ", C(AXIS_CHAR(encoderAxis)), " axis encoder. Disengaging error correction until module is trusted again."); } */ return; @@ -92,7 +92,7 @@ void I2CPositionEncoder::update() { if (millis() - lastErrorTime > I2CPE_TIME_TRUSTED) { trusted = true; - SERIAL_ECHOLNPGM("Untrusted encoder module on ", AS_CHAR(AXIS_CHAR(encoderAxis)), " axis has been fault-free for set duration, reinstating error correction."); + SERIAL_ECHOLNPGM("Untrusted encoder module on ", C(AXIS_CHAR(encoderAxis)), " axis has been fault-free for set duration, reinstating error correction."); //the encoder likely lost its place when the error occurred, so we'll reset and use the printer's //idea of where it the axis is to re-initialize @@ -106,10 +106,7 @@ void I2CPositionEncoder::update() { SERIAL_ECHOLNPGM("Current position is ", pos); SERIAL_ECHOLNPGM("Position in encoder ticks is ", positionInTicks); SERIAL_ECHOLNPGM("New zero-offset of ", zeroOffset); - SERIAL_ECHOPGM("New position reads as ", get_position()); - SERIAL_CHAR('('); - SERIAL_DECIMAL(mm_from_count(get_position())); - SERIAL_ECHOLNPGM(")"); + SERIAL_ECHOLN(F("New position reads as "), get_position(), C('('), mm_from_count(get_position()), C(')')); #endif } #endif @@ -138,7 +135,7 @@ void I2CPositionEncoder::update() { errIdx = (errIdx >= I2CPE_ERR_ARRAY_SIZE - 1) ? 0 : errIdx + 1; err[errIdx] = get_axis_error_steps(false); - LOOP_L_N(i, I2CPE_ERR_ARRAY_SIZE) { + for (uint8_t i = 0; i < I2CPE_ERR_ARRAY_SIZE; ++i) { sum += err[i]; if (i) diffSum += ABS(err[i-1] - err[i]); } @@ -170,7 +167,7 @@ void I2CPositionEncoder::update() { errPrst[errPrstIdx++] = error; // Error must persist for I2CPE_ERR_PRST_ARRAY_SIZE error cycles. This also serves to improve the average accuracy if (errPrstIdx >= I2CPE_ERR_PRST_ARRAY_SIZE) { float sumP = 0; - LOOP_L_N(i, I2CPE_ERR_PRST_ARRAY_SIZE) sumP += errPrst[i]; + for (uint8_t i = 0; i < I2CPE_ERR_PRST_ARRAY_SIZE; ++i) sumP += errPrst[i]; const int32_t errorP = int32_t(sumP * RECIPROCAL(I2CPE_ERR_PRST_ARRAY_SIZE)); SERIAL_CHAR(AXIS_CHAR(encoderAxis)); SERIAL_ECHOLNPGM(" : CORRECT ERR ", errorP * planner.mm_per_step[encoderAxis], "mm"); @@ -232,7 +229,7 @@ bool I2CPositionEncoder::passes_test(const bool report) { if (report) { if (H != I2CPE_MAG_SIG_GOOD) SERIAL_ECHOPGM("Warning. "); SERIAL_CHAR(AXIS_CHAR(encoderAxis)); - serial_ternary(H == I2CPE_MAG_SIG_BAD, F(" axis "), F("magnetic strip "), F("encoder ")); + serial_ternary(F(" axis "), H == I2CPE_MAG_SIG_BAD, F("magnetic strip "), F("encoder ")); switch (H) { case I2CPE_MAG_SIG_GOOD: case I2CPE_MAG_SIG_MID: @@ -404,7 +401,7 @@ void I2CPositionEncoder::calibrate_steps_mm(const uint8_t iter) { planner.synchronize(); - LOOP_L_N(i, iter) { + for (uint8_t i = 0; i < iter; ++i) { TERN_(HAS_EXTRUDERS, startCoord.e = planner.get_axis_position_mm(E_AXIS)); planner.buffer_line(startCoord, fr_mm_s, 0); planner.synchronize(); diff --git a/Marlin/src/feature/encoder_i2c.h b/Marlin/src/feature/encoder_i2c.h index f25fe2ea6b..861a8e52d4 100644 --- a/Marlin/src/feature/encoder_i2c.h +++ b/Marlin/src/feature/encoder_i2c.h @@ -90,7 +90,7 @@ #define I2CPE_PARSE_ERR 1 #define I2CPE_PARSE_OK 0 -#define LOOP_PE(VAR) LOOP_L_N(VAR, I2CPE_ENCODER_CNT) +#define LOOP_PE(VAR) for (uint8_t VAR = 0; VAR < I2CPE_ENCODER_CNT; ++VAR) #define CHECK_IDX() do{ if (!WITHIN(idx, 0, I2CPE_ENCODER_CNT - 1)) return; }while(0) typedef union { @@ -261,32 +261,32 @@ class I2CPositionEncodersMgr { static void report_error_count(const int8_t idx, const AxisEnum axis) { CHECK_IDX(); - SERIAL_ECHOLNPGM("Error count on ", AS_CHAR(AXIS_CHAR(axis)), " axis is ", encoders[idx].get_error_count()); + SERIAL_ECHOLNPGM("Error count on ", C(AXIS_CHAR(axis)), " axis is ", encoders[idx].get_error_count()); } static void reset_error_count(const int8_t idx, const AxisEnum axis) { CHECK_IDX(); encoders[idx].set_error_count(0); - SERIAL_ECHOLNPGM("Error count on ", AS_CHAR(AXIS_CHAR(axis)), " axis has been reset."); + SERIAL_ECHOLNPGM("Error count on ", C(AXIS_CHAR(axis)), " axis has been reset."); } static void enable_ec(const int8_t idx, const bool enabled, const AxisEnum axis) { CHECK_IDX(); encoders[idx].set_ec_enabled(enabled); - SERIAL_ECHOPGM("Error correction on ", AS_CHAR(AXIS_CHAR(axis))); + SERIAL_ECHOPGM("Error correction on ", C(AXIS_CHAR(axis))); SERIAL_ECHO_TERNARY(encoders[idx].get_ec_enabled(), " axis is ", "en", "dis", "abled.\n"); } static void set_ec_threshold(const int8_t idx, const float newThreshold, const AxisEnum axis) { CHECK_IDX(); encoders[idx].set_ec_threshold(newThreshold); - SERIAL_ECHOLNPGM("Error correct threshold for ", AS_CHAR(AXIS_CHAR(axis)), " axis set to ", newThreshold, "mm."); + SERIAL_ECHOLNPGM("Error correct threshold for ", C(AXIS_CHAR(axis)), " axis set to ", newThreshold, "mm."); } static void get_ec_threshold(const int8_t idx, const AxisEnum axis) { CHECK_IDX(); const float threshold = encoders[idx].get_ec_threshold(); - SERIAL_ECHOLNPGM("Error correct threshold for ", AS_CHAR(AXIS_CHAR(axis)), " axis is ", threshold, "mm."); + SERIAL_ECHOLNPGM("Error correct threshold for ", C(AXIS_CHAR(axis)), " axis is ", threshold, "mm."); } static int8_t idx_from_axis(const AxisEnum axis) { diff --git a/Marlin/src/feature/fancheck.cpp b/Marlin/src/feature/fancheck.cpp index 126b79b0a4..844191e7e4 100644 --- a/Marlin/src/feature/fancheck.cpp +++ b/Marlin/src/feature/fancheck.cpp @@ -72,7 +72,7 @@ void FanCheck::update_tachometers() { bool status; #define _TACHO_CASE(N) case N: status = READ(E##N##_FAN_TACHO_PIN); break; - LOOP_L_N(f, TACHO_COUNT) { + for (uint8_t f = 0; f < TACHO_COUNT; ++f) { switch (f) { #if HAS_E0_FAN_TACHO _TACHO_CASE(0) @@ -113,7 +113,7 @@ void FanCheck::compute_speed(uint16_t elapsedTime) { static uint8_t fan_reported_errors_msk = 0; uint8_t fan_error_msk = 0; - LOOP_L_N(f, TACHO_COUNT) { + for (uint8_t f = 0; f < TACHO_COUNT; ++f) { switch (f) { TERN_(HAS_E0_FAN_TACHO, case 0:) TERN_(HAS_E1_FAN_TACHO, case 1:) @@ -150,7 +150,7 @@ void FanCheck::compute_speed(uint16_t elapsedTime) { if (fan_error_msk & ~fan_reported_errors_msk) { // Handle new faults only - LOOP_L_N(f, TACHO_COUNT) if (TEST(fan_error_msk, f)) report_speed_error(f); + for (uint8_t f = 0; f < TACHO_COUNT; ++f) if (TEST(fan_error_msk, f)) report_speed_error(f); } fan_reported_errors_msk = fan_error_msk; } @@ -176,8 +176,8 @@ void FanCheck::report_speed_error(uint8_t fan) { } void FanCheck::print_fan_states() { - LOOP_L_N(s, 2) { - LOOP_L_N(f, TACHO_COUNT) { + for (uint8_t s = 0; s < 2; ++s) { + for (uint8_t f = 0; f < TACHO_COUNT; ++f) { switch (f) { TERN_(HAS_E0_FAN_TACHO, case 0:) TERN_(HAS_E1_FAN_TACHO, case 1:) diff --git a/Marlin/src/feature/filwidth.cpp b/Marlin/src/feature/filwidth.cpp index 2bd9c78980..3befd7752a 100644 --- a/Marlin/src/feature/filwidth.cpp +++ b/Marlin/src/feature/filwidth.cpp @@ -42,7 +42,7 @@ int8_t FilamentWidthSensor::ratios[MAX_MEASUREMENT_DELAY + 1], // Ring void FilamentWidthSensor::init() { const int8_t ratio = sample_to_size_ratio(); - LOOP_L_N(i, COUNT(ratios)) ratios[i] = ratio; + for (uint8_t i = 0; i < COUNT(ratios); ++i) ratios[i] = ratio; index_r = index_w = 0; } diff --git a/Marlin/src/feature/filwidth.h b/Marlin/src/feature/filwidth.h index 9eb1e77762..ab50fe0af3 100644 --- a/Marlin/src/feature/filwidth.h +++ b/Marlin/src/feature/filwidth.h @@ -67,7 +67,7 @@ public: } // Convert raw measurement to mm - static float raw_to_mm(const uint16_t v) { return v * float(ADC_VREF) * RECIPROCAL(float(MAX_RAW_THERMISTOR_VALUE)); } + static float raw_to_mm(const uint16_t v) { return v * (float(ADC_VREF_MV) / 1000.0f) * RECIPROCAL(float(MAX_RAW_THERMISTOR_VALUE)); } static float raw_to_mm() { return raw_to_mm(raw); } // A scaled reading is ready diff --git a/Marlin/src/feature/fwretract.cpp b/Marlin/src/feature/fwretract.cpp index 28355640d2..b4ef18a9b9 100644 --- a/Marlin/src/feature/fwretract.cpp +++ b/Marlin/src/feature/fwretract.cpp @@ -195,8 +195,6 @@ void FWRetract::retract(const bool retracting E_OPTARG(bool swapping/*=false*/)) //*/ } -//extern const char SP_Z_STR[]; - /** * M207: Set firmware retraction values * diff --git a/Marlin/src/feature/host_actions.cpp b/Marlin/src/feature/host_actions.cpp index 773b6ebc61..cc5face259 100644 --- a/Marlin/src/feature/host_actions.cpp +++ b/Marlin/src/feature/host_actions.cpp @@ -41,8 +41,7 @@ HostUI hostui; void HostUI::action(FSTR_P const fstr, const bool eol) { PORT_REDIRECT(SerialMask::All); - SERIAL_ECHOPGM("//action:"); - SERIAL_ECHOF(fstr); + SERIAL_ECHOPGM("//action:", fstr); if (eol) SERIAL_EOL(); } @@ -107,7 +106,7 @@ void HostUI::action(FSTR_P const fstr, const bool eol) { void HostUI::prompt(FSTR_P const ptype, const bool eol/*=true*/) { PORT_REDIRECT(SerialMask::All); action(F("prompt_"), false); - SERIAL_ECHOF(ptype); + SERIAL_ECHO(ptype); if (eol) SERIAL_EOL(); } @@ -187,13 +186,13 @@ void HostUI::action(FSTR_P const fstr, const bool eol) { switch (response) { case 0: // "Purge More" button - #if BOTH(M600_PURGE_MORE_RESUMABLE, ADVANCED_PAUSE_FEATURE) + #if ALL(M600_PURGE_MORE_RESUMABLE, ADVANCED_PAUSE_FEATURE) pause_menu_response = PAUSE_RESPONSE_EXTRUDE_MORE; // Simulate menu selection (menu exits, doesn't extrude more) #endif break; case 1: // "Continue" / "Disable Runout" button - #if BOTH(M600_PURGE_MORE_RESUMABLE, ADVANCED_PAUSE_FEATURE) + #if ALL(M600_PURGE_MORE_RESUMABLE, ADVANCED_PAUSE_FEATURE) pause_menu_response = PAUSE_RESPONSE_RESUME_PRINT; // Simulate menu selection #endif #if HAS_FILAMENT_SENSOR @@ -209,7 +208,7 @@ void HostUI::action(FSTR_P const fstr, const bool eol) { TERN_(HAS_RESUME_CONTINUE, wait_for_user = false); break; case PROMPT_PAUSE_RESUME: - #if BOTH(ADVANCED_PAUSE_FEATURE, SDSUPPORT) + #if ALL(ADVANCED_PAUSE_FEATURE, HAS_MEDIA) extern const char M24_STR[]; queue.inject_P(M24_STR); #endif diff --git a/Marlin/src/feature/host_actions.h b/Marlin/src/feature/host_actions.h index 3f75562398..c030ebad01 100644 --- a/Marlin/src/feature/host_actions.h +++ b/Marlin/src/feature/host_actions.h @@ -35,6 +35,8 @@ PROMPT_INFO }; + extern const char CONTINUE_STR[], DISMISS_STR[]; + #endif class HostUI { @@ -111,6 +113,9 @@ class HostUI { static void prompt_do(const PromptReason reason, FSTR_P const pstr, const char extra_char, FSTR_P const btn1=nullptr, FSTR_P const btn2=nullptr); static void prompt_do(const PromptReason reason, const char * const cstr, const char extra_char, FSTR_P const btn1=nullptr, FSTR_P const btn2=nullptr); + static void continue_prompt(FSTR_P const fstr) { prompt_do(PROMPT_USER_CONTINUE, fstr, FPSTR(CONTINUE_STR)); } + static void continue_prompt(const char * const cstr) { prompt_do(PROMPT_USER_CONTINUE, cstr, FPSTR(CONTINUE_STR)); } + static void prompt_open(const PromptReason reason, FSTR_P const pstr, FSTR_P const btn1=nullptr, FSTR_P const btn2=nullptr) { if (host_prompt_reason == PROMPT_NOT_DEFINED) prompt_do(reason, pstr, btn1, btn2); } @@ -124,5 +129,3 @@ class HostUI { }; extern HostUI hostui; - -extern const char CONTINUE_STR[], DISMISS_STR[]; diff --git a/Marlin/src/feature/hotend_idle.cpp b/Marlin/src/feature/hotend_idle.cpp index 4b137f42da..050898e3b5 100644 --- a/Marlin/src/feature/hotend_idle.cpp +++ b/Marlin/src/feature/hotend_idle.cpp @@ -37,28 +37,33 @@ #include "../module/planner.h" #include "../lcd/marlinui.h" -extern HotendIdleProtection hotend_idle; +HotendIdleProtection hotend_idle; millis_t HotendIdleProtection::next_protect_ms = 0; +hotend_idle_settings_t HotendIdleProtection::cfg; // Initialized by settings.load() void HotendIdleProtection::check_hotends(const millis_t &ms) { + const bool busy = (TERN0(HAS_RESUME_CONTINUE, wait_for_user) || planner.has_blocks_queued()); bool do_prot = false; - HOTEND_LOOP() { - const bool busy = (TERN0(HAS_RESUME_CONTINUE, wait_for_user) || planner.has_blocks_queued()); - if (thermalManager.degHotend(e) >= (HOTEND_IDLE_MIN_TRIGGER) && !busy) { - do_prot = true; break; + if (!busy && cfg.timeout != 0) { + HOTEND_LOOP() { + if (thermalManager.degHotend(e) >= cfg.trigger) { + do_prot = true; break; + } } } - if (bool(next_protect_ms) != do_prot) - next_protect_ms = do_prot ? ms + hp_interval : 0; + if (!do_prot) + next_protect_ms = 0; // No hotends are hot so cancel timeout + else if (!next_protect_ms) // Timeout is possible? + next_protect_ms = ms + 1000UL * cfg.timeout; // Start timeout if not already set } void HotendIdleProtection::check_e_motion(const millis_t &ms) { static float old_e_position = 0; if (old_e_position != current_position.e) { - old_e_position = current_position.e; // Track filament motion - if (next_protect_ms) // If some heater is on then... - next_protect_ms = ms + hp_interval; // ...delay the timeout till later + old_e_position = current_position.e; // Track filament motion + if (next_protect_ms) // If some heater is on then... + next_protect_ms = ms + 1000UL * cfg.timeout; // ...delay the timeout till later } } @@ -79,12 +84,12 @@ void HotendIdleProtection::timed_out() { SERIAL_ECHOLNPGM("Hotend Idle Timeout"); LCD_MESSAGE(MSG_HOTEND_IDLE_TIMEOUT); HOTEND_LOOP() { - if ((HOTEND_IDLE_NOZZLE_TARGET) < thermalManager.degTargetHotend(e)) - thermalManager.setTargetHotend(HOTEND_IDLE_NOZZLE_TARGET, e); + if (cfg.nozzle_target < thermalManager.degTargetHotend(e)) + thermalManager.setTargetHotend(cfg.nozzle_target, e); } #if HAS_HEATED_BED - if ((HOTEND_IDLE_BED_TARGET) < thermalManager.degTargetBed()) - thermalManager.setTargetBed(HOTEND_IDLE_BED_TARGET); + if (cfg.bed_target < thermalManager.degTargetBed()) + thermalManager.setTargetBed(cfg.bed_target); #endif } diff --git a/Marlin/src/feature/hotend_idle.h b/Marlin/src/feature/hotend_idle.h index 40f557d5ed..a4229153c9 100644 --- a/Marlin/src/feature/hotend_idle.h +++ b/Marlin/src/feature/hotend_idle.h @@ -21,13 +21,26 @@ */ #pragma once -#include "../core/millis_t.h" +#include "../inc/MarlinConfig.h" + +typedef struct { + int16_t timeout, trigger, nozzle_target; + #if HAS_HEATED_BED + int16_t bed_target; + #endif + void set_defaults() { + timeout = HOTEND_IDLE_TIMEOUT_SEC; + trigger = HOTEND_IDLE_MIN_TRIGGER; + nozzle_target = HOTEND_IDLE_NOZZLE_TARGET; + bed_target = HOTEND_IDLE_BED_TARGET; + } +} hotend_idle_settings_t; class HotendIdleProtection { public: static void check(); + static hotend_idle_settings_t cfg; private: - static constexpr millis_t hp_interval = SEC_TO_MS(HOTEND_IDLE_TIMEOUT_SEC); static millis_t next_protect_ms; static void check_hotends(const millis_t &ms); static void check_e_motion(const millis_t &ms); diff --git a/Marlin/src/feature/leds/leds.cpp b/Marlin/src/feature/leds/leds.cpp index 3753235ab5..ac7f181516 100644 --- a/Marlin/src/feature/leds/leds.cpp +++ b/Marlin/src/feature/leds/leds.cpp @@ -30,7 +30,7 @@ #include "leds.h" -#if EITHER(CASE_LIGHT_USE_RGB_LED, CASE_LIGHT_USE_NEOPIXEL) +#if ANY(CASE_LIGHT_USE_RGB_LED, CASE_LIGHT_USE_NEOPIXEL) #include "../../feature/caselight.h" #endif @@ -50,7 +50,7 @@ LEDLights leds; void LEDLights::setup() { - #if EITHER(RGB_LED, RGBW_LED) + #if ANY(RGB_LED, RGBW_LED) if (PWM_PIN(RGB_LED_R_PIN)) SET_PWM(RGB_LED_R_PIN); else SET_OUTPUT(RGB_LED_R_PIN); if (PWM_PIN(RGB_LED_G_PIN)) SET_PWM(RGB_LED_G_PIN); else SET_OUTPUT(RGB_LED_G_PIN); if (PWM_PIN(RGB_LED_B_PIN)) SET_PWM(RGB_LED_B_PIN); else SET_OUTPUT(RGB_LED_B_PIN); @@ -76,8 +76,8 @@ void LEDLights::setup() { #endif delay(200); - LOOP_L_N(i, led_pin_count) { - LOOP_LE_N(b, 200) { + for (uint8_t i = 0; i < led_pin_count; ++i) { + for (uint8_t b = 0; b <= 200; ++b) { const uint16_t led_pwm = b <= 100 ? b : 200 - b; if (i == 0 && PWM_PIN(RGB_LED_R_PIN)) hal.set_pwm_duty(pin_t(RGB_LED_R_PIN), led_pwm); else WRITE(RGB_LED_R_PIN, b < 100 ? HIGH : LOW); if (i == 1 && PWM_PIN(RGB_LED_G_PIN)) hal.set_pwm_duty(pin_t(RGB_LED_G_PIN), led_pwm); else WRITE(RGB_LED_G_PIN, b < 100 ? HIGH : LOW); @@ -95,7 +95,62 @@ void LEDLights::setup() { delay(500); } #endif // RGB_STARTUP_TEST - #endif + + #elif ALL(PCA9632, RGB_STARTUP_TEST) // PCA9632 RGB_STARTUP_TEST + + constexpr int8_t led_pin_count = TERN(HAS_WHITE_LED, 4, 3); + + // Startup animation + LEDColor curColor = LEDColorOff(); + PCA9632_set_led_color(curColor); // blackout + delay(200); + + /** + * LED Pin Counter steps -> events + * | 0-100 | 100-200 | 200-300 | 300-400 | + * fade in steady | fade out + * start next pin fade in + */ + + uint16_t led_pin_counters[led_pin_count] = { 1, 0, 0 }; + + bool canEnd = false; + while (led_pin_counters[0] != 99 || !canEnd) { + if (led_pin_counters[0] == 99) // End loop next time pin0 counter is 99 + canEnd = true; + for (uint8_t i = 0; i < led_pin_count; ++i) { + if (led_pin_counters[i] > 0) { + if (++led_pin_counters[i] == 400) // turn off current pin counter in led_pin_counters + led_pin_counters[i] = 0; + else if (led_pin_counters[i] == 201) { // start next pin pwm + led_pin_counters[i + 1 == led_pin_count ? 0 : i + 1] = 1; + i++; // skip next pin in this loop so it doesn't increment twice + } + } + } + uint16_t r, g, b; + r = led_pin_counters[0]; curColor.r = r <= 100 ? r : r <= 300 ? 100 : 400 - r; + g = led_pin_counters[1]; curColor.g = g <= 100 ? g : g <= 300 ? 100 : 400 - g; + b = led_pin_counters[2]; curColor.b = b <= 100 ? b : b <= 300 ? 100 : 400 - b; + #if HAS_WHITE_LED + const uint16_t w = led_pin_counters[3]; curColor.w = w <= 100 ? w : w <= 300 ? 100 : 400 - w; + #endif + PCA9632_set_led_color(curColor); + delay(RGB_STARTUP_TEST_INNER_MS); + } + + // Fade to white + for (uint8_t led_pwm = 0; led_pwm <= 100; ++led_pwm) { + NOLESS(curColor.r, led_pwm); + NOLESS(curColor.g, led_pwm); + NOLESS(curColor.b, led_pwm); + TERN_(HAS_WHITE_LED, NOLESS(curColor.w, led_pwm)); + PCA9632_set_led_color(curColor); + delay(RGB_STARTUP_TEST_INNER_MS); + } + + #endif // PCA9632 && RGB_STARTUP_TEST + TERN_(NEOPIXEL_LED, neo.init()); TERN_(PCA9533, PCA9533_init()); TERN_(LED_USER_PRESET_STARTUP, set_default()); @@ -121,7 +176,7 @@ void LEDLights::set_color(const LEDColor &incol #endif #endif - #if BOTH(CASE_LIGHT_MENU, CASE_LIGHT_USE_NEOPIXEL) + #if ALL(CASE_LIGHT_MENU, CASE_LIGHT_USE_NEOPIXEL) // Update brightness only if caselight is ON or switching leds off if (caselight.on || incol.is_off()) #endif @@ -136,7 +191,7 @@ void LEDLights::set_color(const LEDColor &incol } #endif - #if BOTH(CASE_LIGHT_MENU, CASE_LIGHT_USE_NEOPIXEL) + #if ALL(CASE_LIGHT_MENU, CASE_LIGHT_USE_NEOPIXEL) // Update color only if caselight is ON or switching leds off if (caselight.on || incol.is_off()) #endif @@ -151,7 +206,7 @@ void LEDLights::set_color(const LEDColor &incol #endif - #if EITHER(RGB_LED, RGBW_LED) + #if ANY(RGB_LED, RGBW_LED) // This variant uses 3-4 separate pins for the RGB(W) components. // If the pins can do PWM then their intensity will be set. @@ -173,7 +228,7 @@ void LEDLights::set_color(const LEDColor &incol TERN_(PCA9632, PCA9632_set_led_color(incol)); TERN_(PCA9533, PCA9533_set_rgb(incol.r, incol.g, incol.b)); - #if EITHER(LED_CONTROL_MENU, PRINTER_EVENT_LEDS) + #if ANY(LED_CONTROL_MENU, PRINTER_EVENT_LEDS) // Don't update the color when OFF lights_on = !incol.is_off(); if (lights_on) color = incol; diff --git a/Marlin/src/feature/leds/leds.h b/Marlin/src/feature/leds/leds.h index c6137b45c3..7a31ca685d 100644 --- a/Marlin/src/feature/leds/leds.h +++ b/Marlin/src/feature/leds/leds.h @@ -30,7 +30,7 @@ #include // A white component can be passed -#if EITHER(RGBW_LED, PCA9632_RGBW) +#if ANY(RGBW_LED, PCA9632_RGBW) #define HAS_WHITE_LED 1 #endif @@ -164,7 +164,7 @@ public: #if ENABLED(LED_CONTROL_MENU) static void toggle(); // swap "off" with color #endif - #if EITHER(LED_CONTROL_MENU, CASE_LIGHT_USE_RGB_LED) || LED_POWEROFF_TIMEOUT > 0 + #if ANY(LED_CONTROL_MENU, CASE_LIGHT_USE_RGB_LED) || LED_POWEROFF_TIMEOUT > 0 static void update() { set_color(color); } #endif diff --git a/Marlin/src/feature/leds/neopixel.cpp b/Marlin/src/feature/leds/neopixel.cpp index 4f104234f1..1b0772c2f9 100644 --- a/Marlin/src/feature/leds/neopixel.cpp +++ b/Marlin/src/feature/leds/neopixel.cpp @@ -30,7 +30,7 @@ #include "leds.h" -#if EITHER(NEOPIXEL_STARTUP_TEST, NEOPIXEL2_STARTUP_TEST) +#if ANY(NEOPIXEL_STARTUP_TEST, NEOPIXEL2_STARTUP_TEST) #include "../../core/utility.h" #endif @@ -54,7 +54,15 @@ Adafruit_NeoPixel Marlin_NeoPixel::adaneo1(NEOPIXEL_PIXELS, NEOPIXEL_PIN, NEOPIX set_background_color(background_color); } -#endif + void Marlin_NeoPixel::set_background_off() { + #ifndef NEOPIXEL_BKGD_TIMEOUT_COLOR + #define NEOPIXEL_BKGD_TIMEOUT_COLOR { 0, 0, 0, 0 } + #endif + constexpr uint8_t background_color_off[4] = NEOPIXEL_BKGD_TIMEOUT_COLOR; + set_background_color(background_color_off); + } + +#endif // NEOPIXEL_BKGD_INDEX_FIRST void Marlin_NeoPixel::set_color(const uint32_t color) { if (neoindex >= 0) { @@ -108,7 +116,7 @@ void Marlin_NeoPixel::init() { set_color(adaneo1.Color TERN(LED_USER_PRESET_STARTUP, (LED_USER_PRESET_RED, LED_USER_PRESET_GREEN, LED_USER_PRESET_BLUE, LED_USER_PRESET_WHITE), - (255, 255, 255, 255)) + (0, 0, 0, 0)) ); } diff --git a/Marlin/src/feature/leds/neopixel.h b/Marlin/src/feature/leds/neopixel.h index 2048e2c2ee..6cc8b6157e 100644 --- a/Marlin/src/feature/leds/neopixel.h +++ b/Marlin/src/feature/leds/neopixel.h @@ -58,7 +58,7 @@ #define MULTIPLE_NEOPIXEL_TYPES 1 #endif -#if EITHER(MULTIPLE_NEOPIXEL_TYPES, NEOPIXEL2_INSERIES) +#if ANY(MULTIPLE_NEOPIXEL_TYPES, NEOPIXEL2_INSERIES) #define CONJOINED_NEOPIXEL 1 #endif @@ -66,7 +66,7 @@ // Types // ------------------------ -typedef IF<(TERN0(NEOPIXEL_LED, NEOPIXEL_PIXELS > 127)), int16_t, int8_t>::type pixel_index_t; +typedef value_t(TERN0(NEOPIXEL_LED, NEOPIXEL_PIXELS)) pixel_index_t; // ------------------------ // Classes @@ -91,6 +91,7 @@ public: static void set_background_color(const uint8_t r, const uint8_t g, const uint8_t b, const uint8_t w); static void set_background_color(const uint8_t (&rgbw)[4]) { set_background_color(rgbw[0], rgbw[1], rgbw[2], rgbw[3]); } static void reset_background_color(); + static void set_background_off(); #endif static void begin() { diff --git a/Marlin/src/feature/leds/pca9533.cpp b/Marlin/src/feature/leds/pca9533.cpp index 914db21ba3..d71760e2cb 100644 --- a/Marlin/src/feature/leds/pca9533.cpp +++ b/Marlin/src/feature/leds/pca9533.cpp @@ -1,4 +1,4 @@ -/* +/** * Marlin 3D Printer Firmware * Copyright (c) 2020 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] * diff --git a/Marlin/src/feature/leds/pca9533.h b/Marlin/src/feature/leds/pca9533.h index 431058c491..3a18e96b24 100644 --- a/Marlin/src/feature/leds/pca9533.h +++ b/Marlin/src/feature/leds/pca9533.h @@ -1,4 +1,4 @@ -/* +/** * Marlin 3D Printer Firmware * Copyright (c) 2020 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] * @@ -21,7 +21,7 @@ */ #pragma once -/* +/** * Driver for the PCA9533 LED controller found on the MightyBoard * used by FlashForge Creator Pro, MakerBot, etc. * Written 2020 APR 01 by grauerfuchs diff --git a/Marlin/src/feature/leds/pca9632.cpp b/Marlin/src/feature/leds/pca9632.cpp index abea988004..07c379a815 100644 --- a/Marlin/src/feature/leds/pca9632.cpp +++ b/Marlin/src/feature/leds/pca9632.cpp @@ -148,7 +148,7 @@ void PCA9632_set_led_color(const LEDColor &color) { #if ENABLED(PCA9632_BUZZER) - void PCA9632_buzz(const long, const uint16_t) { + void PCA9632_buzz(const long, const uint16_t=0) { uint8_t data[] = PCA9632_BUZZER_DATA; Wire.beginTransmission(I2C_ADDRESS(PCA9632_ADDRESS)); Wire.write(data, sizeof(data)); diff --git a/Marlin/src/feature/leds/pca9632.h b/Marlin/src/feature/leds/pca9632.h index fb59a8c184..adef0200af 100644 --- a/Marlin/src/feature/leds/pca9632.h +++ b/Marlin/src/feature/leds/pca9632.h @@ -33,5 +33,5 @@ void PCA9632_set_led_color(const LEDColor &color); #if ENABLED(PCA9632_BUZZER) #include - void PCA9632_buzz(const long, const uint16_t); + void PCA9632_buzz(const long, const uint16_t=0); #endif diff --git a/Marlin/src/feature/leds/printer_event_leds.h b/Marlin/src/feature/leds/printer_event_leds.h index 2a4342e8f5..3a037eba96 100644 --- a/Marlin/src/feature/leds/printer_event_leds.h +++ b/Marlin/src/feature/leds/printer_event_leds.h @@ -59,7 +59,7 @@ public: static void onPidTuningDone(LEDColor c) { leds.set_color(c); } #endif - #if ENABLED(SDSUPPORT) + #if HAS_MEDIA static void onPrintCompleted() { leds.set_green(); @@ -80,7 +80,7 @@ public: #endif } - #endif // SDSUPPORT + #endif // HAS_MEDIA }; extern PrinterEventLEDs printerEventLEDs; diff --git a/Marlin/src/feature/max7219.cpp b/Marlin/src/feature/max7219.cpp index 2fdfcba32d..12e4a539d3 100644 --- a/Marlin/src/feature/max7219.cpp +++ b/Marlin/src/feature/max7219.cpp @@ -44,6 +44,7 @@ #include "max7219.h" #include "../module/planner.h" +#include "../module/stepper.h" #include "../MarlinCore.h" #include "../HAL/shared/Delay.h" @@ -135,9 +136,7 @@ uint8_t Max7219::suspended; // = 0; void Max7219::error(FSTR_P const func, const int32_t v1, const int32_t v2/*=-1*/) { #if ENABLED(MAX7219_ERRORS) - SERIAL_ECHOPGM("??? Max7219::"); - SERIAL_ECHOF(func, AS_CHAR('(')); - SERIAL_ECHO(v1); + SERIAL_ECHO(F("??? Max7219::"), func, C('('), v1); if (v2 > 0) SERIAL_ECHOPGM(", ", v2); SERIAL_CHAR(')'); SERIAL_EOL(); @@ -155,7 +154,7 @@ void Max7219::error(FSTR_P const func, const int32_t v1, const int32_t v2/*=-1*/ */ inline uint32_t flipped(const uint32_t bits, const uint8_t n_bytes) { uint32_t mask = 1, outbits = 0; - LOOP_L_N(b, n_bytes * 8) { + for (uint8_t b = 0; b < n_bytes * 8; ++b) { outbits <<= 1; if (bits & mask) outbits |= 1; mask <<= 1; @@ -338,13 +337,13 @@ void Max7219::fill() { void Max7219::clear_row(const uint8_t row) { if (row >= MAX7219_Y_LEDS) return error(F("clear_row"), row); - LOOP_L_N(x, MAX7219_X_LEDS) CLR_7219(x, row); + for (uint8_t x = 0; x < MAX7219_X_LEDS; ++x) CLR_7219(x, row); send_row(row); } void Max7219::clear_column(const uint8_t col) { if (col >= MAX7219_X_LEDS) return error(F("set_column"), col); - LOOP_L_N(y, MAX7219_Y_LEDS) CLR_7219(col, y); + for (uint8_t y = 0; y < MAX7219_Y_LEDS; ++y) CLR_7219(col, y); send_column(col); } @@ -356,7 +355,7 @@ void Max7219::clear_column(const uint8_t col) { void Max7219::set_row(const uint8_t row, const uint32_t val) { if (row >= MAX7219_Y_LEDS) return error(F("set_row"), row); uint32_t mask = _BV32(MAX7219_X_LEDS - 1); - LOOP_L_N(x, MAX7219_X_LEDS) { + for (uint8_t x = 0; x < MAX7219_X_LEDS; ++x) { if (val & mask) SET_7219(x, row); else CLR_7219(x, row); mask >>= 1; } @@ -371,7 +370,7 @@ void Max7219::set_row(const uint8_t row, const uint32_t val) { void Max7219::set_column(const uint8_t col, const uint32_t val) { if (col >= MAX7219_X_LEDS) return error(F("set_column"), col); uint32_t mask = _BV32(MAX7219_Y_LEDS - 1); - LOOP_L_N(y, MAX7219_Y_LEDS) { + for (uint8_t y = 0; y < MAX7219_Y_LEDS; ++y) { if (val & mask) SET_7219(col, y); else CLR_7219(col, y); mask >>= 1; } @@ -436,23 +435,23 @@ void Max7219::set_columns_32bits(const uint8_t x, uint32_t val) { // Initialize the Max7219 void Max7219::register_setup() { - LOOP_L_N(i, MAX7219_NUMBER_UNITS) + for (uint8_t i = 0; i < MAX7219_NUMBER_UNITS; ++i) send(max7219_reg_scanLimit, 0x07); pulse_load(); // Tell the chips to load the clocked out data - LOOP_L_N(i, MAX7219_NUMBER_UNITS) + for (uint8_t i = 0; i < MAX7219_NUMBER_UNITS; ++i) send(max7219_reg_decodeMode, 0x00); // Using an led matrix (not digits) pulse_load(); // Tell the chips to load the clocked out data - LOOP_L_N(i, MAX7219_NUMBER_UNITS) + for (uint8_t i = 0; i < MAX7219_NUMBER_UNITS; ++i) send(max7219_reg_shutdown, 0x01); // Not in shutdown mode pulse_load(); // Tell the chips to load the clocked out data - LOOP_L_N(i, MAX7219_NUMBER_UNITS) + for (uint8_t i = 0; i < MAX7219_NUMBER_UNITS; ++i) send(max7219_reg_displayTest, 0x00); // No display test pulse_load(); // Tell the chips to load the clocked out data - LOOP_L_N(i, MAX7219_NUMBER_UNITS) + for (uint8_t i = 0; i < MAX7219_NUMBER_UNITS; ++i) send(max7219_reg_intensity, 0x01 & 0x0F); // The first 0x0F is the value you can set // Range: 0x00 to 0x0F pulse_load(); // Tell the chips to load the clocked out data @@ -471,7 +470,7 @@ void Max7219::register_setup() { constexpr millis_t pattern_delay = 4; int8_t spiralx, spiraly, spiral_dir; - IF<(MAX7219_LEDS > 255), uint16_t, uint8_t>::type spiral_count; + uvalue_t(MAX7219_LEDS) spiral_count; void Max7219::test_pattern() { constexpr int8_t way[][2] = { { 1, 0 }, { 0, 1 }, { -1, 0 }, { 0, -1 } }; @@ -707,7 +706,7 @@ void Max7219::idle_tasks() { #ifdef MAX7219_DEBUG_PLANNER_QUEUE static int16_t last_depth = 0; - const int16_t current_depth = (head - tail + BLOCK_BUFFER_SIZE) & (BLOCK_BUFFER_SIZE - 1) & 0xF; + const int16_t current_depth = BLOCK_MOD(head - tail + (BLOCK_BUFFER_SIZE)) & 0xF; if (current_depth != last_depth) { quantity16(MAX7219_DEBUG_PLANNER_QUEUE, last_depth, current_depth, &row_change_mask); last_depth = current_depth; @@ -723,10 +722,32 @@ void Max7219::idle_tasks() { } #endif + #ifdef MAX7219_DEBUG_MULTISTEPPING + static uint8_t last_multistepping = 0; + const uint8_t multistepping = Stepper::steps_per_isr; + if (multistepping != last_multistepping) { + static uint8_t log2_old = 0; + uint8_t log2_new = 0; + for (uint8_t val = multistepping; val > 1; val >>= 1) log2_new++; + mark16(MAX7219_DEBUG_MULTISTEPPING, log2_old, log2_new, &row_change_mask); + last_multistepping = multistepping; + log2_old = log2_new; + } + #endif + + #ifdef MAX7219_DEBUG_SLOWDOWN + static uint8_t last_slowdown_count = 0; + const uint8_t slowdown_count = Planner::slowdown_count; + if (slowdown_count != last_slowdown_count) { + mark16(MAX7219_DEBUG_SLOWDOWN, last_slowdown_count, slowdown_count, &row_change_mask); + last_slowdown_count = slowdown_count; + } + #endif + // batch line updates suspended--; if (!suspended) - LOOP_L_N(i, 8) if (row_change_mask & _BV(i)) + for (uint8_t i = 0; i < 8; ++i) if (row_change_mask & _BV(i)) refresh_line(i); // After resume() automatically do a refresh() diff --git a/Marlin/src/feature/meatpack.cpp b/Marlin/src/feature/meatpack.cpp index 07ff41e5be..fe3dabe8da 100644 --- a/Marlin/src/feature/meatpack.cpp +++ b/Marlin/src/feature/meatpack.cpp @@ -140,7 +140,7 @@ void MeatPack::handle_output_char(const uint8_t c) { #if ENABLED(MP_DEBUG) if (chars_decoded < 1024) { ++chars_decoded; - DEBUG_ECHOLNPGM("RB: ", AS_CHAR(c)); + DEBUG_ECHOLNPGM("RB: ", C(c)); } #endif } @@ -171,7 +171,7 @@ void MeatPack::report_state() { // should not contain the "PV' substring, as this is used to indicate protocol version SERIAL_ECHOPGM("[MP] " MeatPack_ProtocolVersion " "); serialprint_onoff(TEST(state, MPConfig_Bit_Active)); - SERIAL_ECHOF(TEST(state, MPConfig_Bit_NoSpaces) ? F(" NSP\n") : F(" ESP\n")); + SERIAL_ECHO(TEST(state, MPConfig_Bit_NoSpaces) ? F(" NSP\n") : F(" ESP\n")); } /** diff --git a/Marlin/src/feature/meatpack.h b/Marlin/src/feature/meatpack.h index 98a535e592..37039c3056 100644 --- a/Marlin/src/feature/meatpack.h +++ b/Marlin/src/feature/meatpack.h @@ -20,7 +20,7 @@ * */ -/* +/** * MeatPack G-code Compression * * Algorithm & Implementation: Scott Mudge - mail@scottmudge.com diff --git a/Marlin/src/feature/mixing.cpp b/Marlin/src/feature/mixing.cpp index b1a069e320..4021393f18 100644 --- a/Marlin/src/feature/mixing.cpp +++ b/Marlin/src/feature/mixing.cpp @@ -24,8 +24,6 @@ #if ENABLED(MIXING_EXTRUDER) -//#define MIXER_NORMALIZER_DEBUG - #include "mixing.h" Mixer mixer; @@ -44,7 +42,7 @@ int_fast8_t Mixer::runner = 0; mixer_comp_t Mixer::s_color[MIXING_STEPPERS]; mixer_accu_t Mixer::accu[MIXING_STEPPERS] = { 0 }; -#if EITHER(HAS_DUAL_MIXING, GRADIENT_MIX) +#if ANY(HAS_DUAL_MIXING, GRADIENT_MIX) mixer_perc_t Mixer::mix[MIXING_STEPPERS]; #endif @@ -62,10 +60,7 @@ void Mixer::normalize(const uint8_t tool_index) { } #ifdef MIXER_NORMALIZER_DEBUG SERIAL_ECHOPGM("Mixer: Old relation : [ "); - MIXER_STEPPER_LOOP(i) { - SERIAL_DECIMAL(collector[i] / csum); - SERIAL_CHAR(' '); - } + MIXER_STEPPER_LOOP(i) SERIAL_ECHO(collector[i] / csum, C(' ')); SERIAL_ECHOLNPGM("]"); #endif @@ -77,16 +72,12 @@ void Mixer::normalize(const uint8_t tool_index) { csum = 0; SERIAL_ECHOPGM("Mixer: Normalize to : [ "); MIXER_STEPPER_LOOP(i) { - SERIAL_ECHO(uint16_t(color[tool_index][i])); - SERIAL_CHAR(' '); + SERIAL_ECHO(uint16_t(color[tool_index][i]), C(' ')); csum += color[tool_index][i]; } SERIAL_ECHOLNPGM("]"); SERIAL_ECHOPGM("Mixer: New relation : [ "); - MIXER_STEPPER_LOOP(i) { - SERIAL_ECHO_F(uint16_t(color[tool_index][i]) / csum, 3); - SERIAL_CHAR(' '); - } + MIXER_STEPPER_LOOP(i) SERIAL_ECHO(p_float_t(uint16_t(color[tool_index][i]) / csum, 3), C(' ')); SERIAL_ECHOLNPGM("]"); #endif @@ -96,13 +87,13 @@ void Mixer::normalize(const uint8_t tool_index) { void Mixer::reset_vtools() { // Virtual Tools 0, 1, 2, 3 = Filament 1, 2, 3, 4, etc. // Every virtual tool gets a pure filament - LOOP_L_N(t, _MIN(MIXING_VIRTUAL_TOOLS, MIXING_STEPPERS)) + for (uint8_t t = 0; t < _MIN(MIXING_VIRTUAL_TOOLS, MIXING_STEPPERS); ++t) MIXER_STEPPER_LOOP(i) color[t][i] = (t == i) ? COLOR_A_MASK : 0; // Remaining virtual tools are 100% filament 1 #if MIXING_VIRTUAL_TOOLS > MIXING_STEPPERS - LOOP_S_L_N(t, MIXING_STEPPERS, MIXING_VIRTUAL_TOOLS) + for (uint8_t t = MIXING_STEPPERS; t < MIXING_VIRTUAL_TOOLS; ++t) MIXER_STEPPER_LOOP(i) color[t][i] = (i == 0) ? COLOR_A_MASK : 0; #endif @@ -140,7 +131,7 @@ void Mixer::init() { color[MIXER_AUTORETRACT_TOOL][i] = COLOR_A_MASK; #endif - #if EITHER(HAS_DUAL_MIXING, GRADIENT_MIX) + #if ANY(HAS_DUAL_MIXING, GRADIENT_MIX) update_mix_from_vtool(); #endif diff --git a/Marlin/src/feature/mixing.h b/Marlin/src/feature/mixing.h index 85d52d69c8..4340a510a5 100644 --- a/Marlin/src/feature/mixing.h +++ b/Marlin/src/feature/mixing.h @@ -108,7 +108,7 @@ class Mixer { } // Used when dealing with blocks - FORCE_INLINE static void populate_block(mixer_comp_t b_color[MIXING_STEPPERS]) { + FORCE_INLINE static void populate_block(mixer_comp_t (&b_color)[MIXING_STEPPERS]) { #if ENABLED(GRADIENT_MIX) if (gradient.enabled) { MIXER_STEPPER_LOOP(i) b_color[i] = gradient.color[i]; @@ -118,11 +118,11 @@ class Mixer { MIXER_STEPPER_LOOP(i) b_color[i] = color[selected_vtool][i]; } - FORCE_INLINE static void stepper_setup(mixer_comp_t b_color[MIXING_STEPPERS]) { + FORCE_INLINE static void stepper_setup(mixer_comp_t (&b_color)[MIXING_STEPPERS]) { MIXER_STEPPER_LOOP(i) s_color[i] = b_color[i]; } - #if EITHER(HAS_DUAL_MIXING, GRADIENT_MIX) + #if ANY(HAS_DUAL_MIXING, GRADIENT_MIX) static mixer_perc_t mix[MIXING_STEPPERS]; // Scratch array for the Mix in proportion to 100 @@ -137,26 +137,24 @@ class Mixer { MIXER_STEPPER_LOOP(i) tcolor[i] = mix[i] * scale; #ifdef MIXER_NORMALIZER_DEBUG - SERIAL_ECHOPGM("Mix [ "); - SERIAL_ECHOLIST_N(MIXING_STEPPERS, mix[0], mix[1], mix[2], mix[3], mix[4], mix[5]); - SERIAL_ECHOPGM(" ] to Color [ "); - SERIAL_ECHOLIST_N(MIXING_STEPPERS, tcolor[0], tcolor[1], tcolor[2], tcolor[3], tcolor[4], tcolor[5]); - SERIAL_ECHOLNPGM(" ]"); + SERIAL_ECHOLN( + F("Mix [ "), LIST_N(MIXING_STEPPERS, mix[0], mix[1], mix[2], mix[3], mix[4], mix[5]), + F(" ] to Color [ "), LIST_N(MIXING_STEPPERS, tcolor[0], tcolor[1], tcolor[2], tcolor[3], tcolor[4], tcolor[5]), + F(" ]") + ); #endif } static void update_mix_from_vtool(const uint8_t j=selected_vtool) { float ctot = 0; MIXER_STEPPER_LOOP(i) ctot += color[j][i]; - //MIXER_STEPPER_LOOP(i) mix[i] = 100.0f * color[j][i] / ctot; - MIXER_STEPPER_LOOP(i) mix[i] = mixer_perc_t(100.0f * color[j][i] / ctot); + MIXER_STEPPER_LOOP(i) mix[i] = mixer_perc_t(100.0f * color[j][i] / ctot + 0.5f); #ifdef MIXER_NORMALIZER_DEBUG - SERIAL_ECHOPGM("V-tool ", j, " [ "); - SERIAL_ECHOLIST_N(MIXING_STEPPERS, color[j][0], color[j][1], color[j][2], color[j][3], color[j][4], color[j][5]); - SERIAL_ECHOPGM(" ] to Mix [ "); - SERIAL_ECHOLIST_N(MIXING_STEPPERS, mix[0], mix[1], mix[2], mix[3], mix[4], mix[5]); - SERIAL_ECHOLNPGM(" ]"); + SERIAL_ECHOLN(F("V-tool "), j, + F(" [ "), LIST_N(MIXING_STEPPERS, color[j][0], color[j][1], color[j][2], color[j][3], color[j][4], color[j][5]), + F(" ] to Mix [ "), LIST_N(MIXING_STEPPERS, mix[0], mix[1], mix[2], mix[3], mix[4], mix[5]), F(" ]") + ); #endif } @@ -197,11 +195,10 @@ class Mixer { MIXER_STEPPER_LOOP(i) mix[i] = (mixer_perc_t)CEIL(100.0f * gradient.color[i] / ctot); #ifdef MIXER_NORMALIZER_DEBUG - SERIAL_ECHOPGM("Gradient [ "); - SERIAL_ECHOLIST_N(MIXING_STEPPERS, gradient.color[0], gradient.color[1], gradient.color[2], gradient.color[3], gradient.color[4], gradient.color[5]); - SERIAL_ECHOPGM(" ] to Mix [ "); - SERIAL_ECHOLIST_N(MIXING_STEPPERS, mix[0], mix[1], mix[2], mix[3], mix[4], mix[5]); - SERIAL_ECHOLNPGM(" ]"); + SERIAL_ECHOLN( + F("Gradient [ "), LIST_N(MIXING_STEPPERS, gradient.color[0], gradient.color[1], gradient.color[2], gradient.color[3], gradient.color[4], gradient.color[5]), + F(" ] to Mix [ "), LIST_N(MIXING_STEPPERS, mix[0], mix[1], mix[2], mix[3], mix[4], mix[5]), F(" ]") + ); #endif } @@ -234,13 +231,7 @@ class Mixer { for (;;) { if (--runner < 0) runner = MIXING_STEPPERS - 1; accu[runner] += s_color[runner]; - if ( - #ifdef MIXER_ACCU_SIGNED - accu[runner] < 0 - #else - accu[runner] & COLOR_A_MASK - #endif - ) { + if (TERN(MIXER_ACCU_SIGNED, accu[runner] < 0, accu[runner] & COLOR_A_MASK)) { accu[runner] &= COLOR_MASK; return runner; } diff --git a/Marlin/src/feature/mmu/mmu2-serial-protocol.md b/Marlin/src/feature/mmu/mmu2-serial-protocol.md index 93135e406f..42f30e418d 100644 --- a/Marlin/src/feature/mmu/mmu2-serial-protocol.md +++ b/Marlin/src/feature/mmu/mmu2-serial-protocol.md @@ -91,4 +91,3 @@ Eject filament - MMU <= 'E*Filament index*\n' - MMU => 'ok\n' - diff --git a/Marlin/src/feature/mmu/mmu2.cpp b/Marlin/src/feature/mmu/mmu2.cpp index 4f86578a60..5ef56c7eac 100644 --- a/Marlin/src/feature/mmu/mmu2.cpp +++ b/Marlin/src/feature/mmu/mmu2.cpp @@ -76,7 +76,7 @@ MMU2 mmu2; #define MMU2_NO_TOOL 99 #define MMU_BAUD 115200 -bool MMU2::_enabled, MMU2::ready, MMU2::mmu_print_saved; +bool MMU2::_enabled, MMU2::ready; #if HAS_PRUSA_MMU2S bool MMU2::mmu2s_triggered; #endif @@ -84,7 +84,6 @@ uint8_t MMU2::cmd, MMU2::cmd_arg, MMU2::last_cmd, MMU2::extruder; int8_t MMU2::state = 0; volatile int8_t MMU2::finda = 1; volatile bool MMU2::finda_runout_valid; -int16_t MMU2::version = -1, MMU2::buildnr = -1; millis_t MMU2::prev_request, MMU2::prev_P0_request; char MMU2::rx_buffer[MMU_RX_SIZE], MMU2::tx_buffer[MMU_TX_SIZE]; @@ -93,14 +92,11 @@ struct E_Step { feedRate_t feedRate; //!< feed rate in mm/s }; -static constexpr E_Step - ramming_sequence[] PROGMEM = { MMU2_RAMMING_SEQUENCE } - , load_to_nozzle_sequence[] PROGMEM = { MMU2_LOAD_TO_NOZZLE_SEQUENCE } - #if HAS_PRUSA_MMU2S - , can_load_sequence[] PROGMEM = { MMU2_CAN_LOAD_SEQUENCE } - , can_load_increment_sequence[] PROGMEM = { MMU2_CAN_LOAD_INCREMENT_SEQUENCE } - #endif -; +inline void unscaled_mmu2_e_move(const float &dist, const feedRate_t fr_mm_s, const bool sync=true) { + current_position.e += dist / planner.e_factor[active_extruder]; + line_to_current_position(fr_mm_s); + if (sync) planner.synchronize(); +} MMU2::MMU2() { rx_buffer[0] = '\0'; @@ -136,12 +132,12 @@ void MMU2::reset() { #endif } -uint8_t MMU2::get_current_tool() { - return extruder == MMU2_NO_TOOL ? -1 : extruder; -} +int8_t MMU2::get_current_tool() { return extruder == MMU2_NO_TOOL ? -1 : extruder; } -#if EITHER(HAS_PRUSA_MMU2S, MMU_EXTRUDER_SENSOR) +#if ANY(HAS_PRUSA_MMU2S, MMU_EXTRUDER_SENSOR) #define FILAMENT_PRESENT() (READ(FIL_RUNOUT1_PIN) != FIL_RUNOUT1_STATE) +#else + #define FILAMENT_PRESENT() true #endif void mmu2_attn_buzz(const bool two=false) { @@ -149,6 +145,7 @@ void mmu2_attn_buzz(const bool two=false) { if (two) { BUZZ(10, 0); BUZZ(200, 404); } } +// Avoiding sscanf significantly reduces build size void MMU2::mmu_loop() { switch (state) { @@ -163,7 +160,7 @@ void MMU2::mmu_loop() { MMU2_SEND("S1"); // Read Version state = -2; } - else if (millis() > 30000) { // 30sec after reset disable MMU + else if (ELAPSED(millis(), prev_request + 30000)) { // 30sec after reset disable MMU SERIAL_ECHOLNPGM("MMU not responding - DISABLED"); state = 0; } @@ -171,7 +168,7 @@ void MMU2::mmu_loop() { case -2: if (rx_ok()) { - sscanf(rx_buffer, "%huok\n", &version); + const uint16_t version = uint16_t(strtoul(rx_buffer, nullptr, 10)); DEBUG_ECHOLNPGM("MMU => ", version, "\nMMU <= 'S2'"); MMU2_SEND("S2"); // Read Build Number state = -3; @@ -180,17 +177,15 @@ void MMU2::mmu_loop() { case -3: if (rx_ok()) { - sscanf(rx_buffer, "%huok\n", &buildnr); - + const uint16_t buildnr = uint16_t(strtoul(rx_buffer, nullptr, 10)); DEBUG_ECHOLNPGM("MMU => ", buildnr); - check_version(); + check_version(buildnr); #if ENABLED(MMU2_MODE_12V) DEBUG_ECHOLNPGM("MMU <= 'M1'"); MMU2_SEND("M1"); // Stealth Mode state = -5; - #else DEBUG_ECHOLNPGM("MMU <= 'P0'"); MMU2_SEND("P0"); // Read FINDA @@ -200,20 +195,21 @@ void MMU2::mmu_loop() { break; #if ENABLED(MMU2_MODE_12V) - case -5: - // response to M1 - if (rx_ok()) { - DEBUG_ECHOLNPGM("MMU => ok"); - DEBUG_ECHOLNPGM("MMU <= 'P0'"); - MMU2_SEND("P0"); // Read FINDA - state = -4; - } - break; + case -5: + // response to M1 + if (rx_ok()) { + DEBUG_ECHOLNPGM("MMU => ok"); + DEBUG_ECHOLNPGM("MMU <= 'P0'"); + MMU2_SEND("P0"); // Read FINDA + state = -4; + } + break; #endif case -4: if (rx_ok()) { - sscanf(rx_buffer, "%hhuok\n", &finda); + const uint8_t findex = uint8_t(rx_buffer[0] - '0'); + if (findex <= 1) finda = findex; DEBUG_ECHOLNPGM("MMU => ", finda, "\nMMU - ENABLED"); @@ -286,10 +282,11 @@ void MMU2::mmu_loop() { case 2: // response to command P0 if (rx_ok()) { - sscanf(rx_buffer, "%hhuok\n", &finda); + const uint8_t findex = uint8_t(rx_buffer[0] - '0'); + if (findex <= 1) finda = findex; // This is super annoying. Only activate if necessary - // if (finda_runout_valid) DEBUG_ECHOLNPAIR_F("MMU <= 'P0'\nMMU => ", finda, 6); + //if (finda_runout_valid) DEBUG_ECHOLNPGM("MMU <= 'P0'\nMMU => ", p_float_t(finda, 6)); if (!finda && finda_runout_valid) filament_runout(); if (cmd == MMU_CMD_NONE) ready = true; @@ -406,7 +403,7 @@ void MMU2::tx_str(FSTR_P fstr) { void MMU2::tx_printf(FSTR_P format, int argument = -1) { clear_rx_buffer(); const uint8_t len = sprintf_P(tx_buffer, FTOP(format), argument); - LOOP_L_N(i, len) MMU2_SERIAL.write(tx_buffer[i]); + for (uint8_t i = 0; i < len; ++i) MMU2_SERIAL.write(tx_buffer[i]); prev_request = millis(); } @@ -416,7 +413,7 @@ void MMU2::tx_printf(FSTR_P format, int argument = -1) { void MMU2::tx_printf(FSTR_P format, int argument1, int argument2) { clear_rx_buffer(); const uint8_t len = sprintf_P(tx_buffer, FTOP(format), argument1, argument2); - LOOP_L_N(i, len) MMU2_SERIAL.write(tx_buffer[i]); + for (uint8_t i = 0; i < len; ++i) MMU2_SERIAL.write(tx_buffer[i]); prev_request = millis(); } @@ -442,7 +439,7 @@ bool MMU2::rx_ok() { /** * Check if MMU has compatible firmware */ -void MMU2::check_version() { +void MMU2::check_version(const uint16_t buildnr) { if (buildnr < MMU_REQUIRED_FW_BUILDNR) { SERIAL_ERROR_MSG("Invalid MMU2 firmware. Version >= " STRINGIFY(MMU_REQUIRED_FW_BUILDNR) " required."); kill(GET_TEXT_F(MSG_KILL_MMU2_FIRMWARE)); @@ -458,12 +455,19 @@ static void mmu2_not_responding() { BUZZ(100, 659); } +inline void beep_bad_cmd() { BUZZ(400, 40); } + #if HAS_PRUSA_MMU2S + /** + * Load filament until the sensor at the gears is triggered + * and give up after a number of attempts set with MMU2_C0_RETRY. + * Each try has a timeout before returning a fail state. + */ bool MMU2::load_to_gears() { command(MMU_CMD_C0); manage_response(true, true); - LOOP_L_N(i, MMU2_C0_RETRY) { // Keep loading until filament reaches gears + for (uint8_t i = 0; i < MMU2_C0_RETRY; ++i) { // Keep loading until filament reaches gears if (mmu2s_triggered) break; command(MMU_CMD_C0); manage_response(true, true); @@ -484,6 +488,11 @@ static void mmu2_not_responding() { set_runout_valid(false); if (index != extruder) { + if (ENABLED(MMU_IR_UNLOAD_MOVE) && FILAMENT_PRESENT()) { + DEBUG_ECHOLNPGM("Unloading\n"); + while (FILAMENT_PRESENT()) // Filament present? Keep unloading. + unscaled_mmu2_e_move(-0.25, MMM_TO_MMS(120)); // 0.25mm is a guessed value. Adjust to preference. + } stepper.disable_extruder(); ui.status_printf(0, GET_TEXT_F(MSG_MMU2_LOADING_FILAMENT), int(index + 1)); @@ -520,9 +529,9 @@ static void mmu2_not_responding() { #if ENABLED(MMU2_MENUS) const uint8_t index = mmu2_choose_filament(); while (!thermalManager.wait_for_hotend(active_extruder, false)) safe_delay(100); - load_filament_to_nozzle(index); + load_to_nozzle(index); #else - ERR_BUZZ(); + beep_bad_cmd(); #endif } break; @@ -541,13 +550,13 @@ static void mmu2_not_responding() { active_extruder = 0; } #else - ERR_BUZZ(); + beep_bad_cmd(); #endif } break; case 'c': { while (!thermalManager.wait_for_hotend(active_extruder, false)) safe_delay(100); - load_to_nozzle(); + load_to_nozzle_sequence(); } break; } @@ -608,9 +617,9 @@ static void mmu2_not_responding() { #if ENABLED(MMU2_MENUS) uint8_t index = mmu2_choose_filament(); while (!thermalManager.wait_for_hotend(active_extruder, false)) safe_delay(100); - load_filament_to_nozzle(index); + load_to_nozzle(index); #else - ERR_BUZZ(); + beep_bad_cmd(); #endif } break; @@ -630,14 +639,14 @@ static void mmu2_not_responding() { extruder = index; active_extruder = 0; #else - ERR_BUZZ(); + beep_bad_cmd(); #endif } break; case 'c': { DEBUG_ECHOLNPGM("case c\n"); while (!thermalManager.wait_for_hotend(active_extruder, false)) safe_delay(100); - execute_extruder_sequence((const E_Step *)load_to_nozzle_sequence, COUNT(load_to_nozzle_sequence)); + load_to_nozzle_sequence(); } break; } @@ -723,9 +732,9 @@ static void mmu2_not_responding() { #if ENABLED(MMU2_MENUS) uint8_t index = mmu2_choose_filament(); while (!thermalManager.wait_for_hotend(active_extruder, false)) safe_delay(100); - load_filament_to_nozzle(index); + load_to_nozzle(index); #else - ERR_BUZZ(); + beep_bad_cmd(); #endif } break; @@ -744,14 +753,14 @@ static void mmu2_not_responding() { extruder = index; active_extruder = 0; #else - ERR_BUZZ(); + beep_bad_cmd(); #endif } break; case 'c': { DEBUG_ECHOLNPGM("case c\n"); while (!thermalManager.wait_for_hotend(active_extruder, false)) safe_delay(100); - execute_extruder_sequence((const E_Step *)load_to_nozzle_sequence, COUNT(load_to_nozzle_sequence)); + load_to_nozzle_sequence(); } break; } @@ -792,8 +801,7 @@ bool MMU2::get_response() { void MMU2::manage_response(const bool move_axes, const bool turn_off_nozzle) { constexpr xyz_pos_t park_point = NOZZLE_PARK_POINT; - bool response = false; - mmu_print_saved = false; + bool response = false, mmu_print_saved = false; xyz_pos_t resume_position; celsius_t resume_hotend_temp = thermalManager.degTargetHotend(active_extruder); @@ -815,8 +823,7 @@ void MMU2::manage_response(const bool move_axes, const bool turn_off_nozzle) { resume_hotend_temp = thermalManager.degTargetHotend(active_extruder); resume_position = current_position; - if (move_axes && all_axes_homed()) - nozzle.park(0, park_point /*= NOZZLE_PARK_POINT*/); + if (move_axes && all_axes_homed()) nozzle.park(0, park_point); if (turn_off_nozzle) thermalManager.setTargetHotend(0, active_extruder); @@ -824,13 +831,12 @@ void MMU2::manage_response(const bool move_axes, const bool turn_off_nozzle) { } } else if (mmu_print_saved) { - SERIAL_ECHOLNPGM("MMU starts responding\n"); + SERIAL_ECHOLNPGM("\nMMU starts responding"); if (turn_off_nozzle && resume_hotend_temp) { thermalManager.setTargetHotend(resume_hotend_temp, active_extruder); LCD_MESSAGE(MSG_HEATING); ERR_BUZZ(); - while (!thermalManager.wait_for_hotend(active_extruder, false)) safe_delay(1000); } @@ -843,7 +849,6 @@ void MMU2::manage_response(const bool move_axes, const bool turn_off_nozzle) { if (move_axes && all_axes_homed()) { // Move XY to starting position, then Z do_blocking_move_to_xy(resume_position, feedRate_t(NOZZLE_PARK_XY_FEEDRATE)); - // Move Z_AXIS to saved position do_blocking_move_to_z(resume_position.z, feedRate_t(NOZZLE_PARK_Z_FEEDRATE)); } @@ -878,23 +883,24 @@ void MMU2::filament_runout() { } // Slowly spin the extruder during C0 else { - while (planner.movesplanned() < 3) { - current_position.e += 0.25; - line_to_current_position(MMM_TO_MMS(120)); - } + while (planner.movesplanned() < 3) + unscaled_mmu2_e_move(0.25, MMM_TO_MMS(120), false); } } mmu2s_triggered = present; } bool MMU2::can_load() { - execute_extruder_sequence((const E_Step *)can_load_sequence, COUNT(can_load_sequence)); + static const E_Step can_load_sequence[] PROGMEM = { MMU2_CAN_LOAD_SEQUENCE }, + can_load_increment_sequence[] PROGMEM = { MMU2_CAN_LOAD_INCREMENT_SEQUENCE }; + + execute_extruder_sequence(can_load_sequence, COUNT(can_load_sequence)); int filament_detected_count = 0; const int steps = (MMU2_CAN_LOAD_RETRACT) / (MMU2_CAN_LOAD_INCREMENT); DEBUG_ECHOLNPGM("MMU can_load:"); - LOOP_L_N(i, steps) { - execute_extruder_sequence((const E_Step *)can_load_increment_sequence, COUNT(can_load_increment_sequence)); + for (uint8_t i = 0; i < steps; ++i) { + execute_extruder_sequence(can_load_increment_sequence, COUNT(can_load_increment_sequence)); check_filament(); // Don't trust the idle function DEBUG_CHAR(mmu2s_triggered ? 'O' : 'o'); if (mmu2s_triggered) ++filament_detected_count; @@ -912,7 +918,7 @@ void MMU2::filament_runout() { #endif // Load filament into MMU2 -void MMU2::load_filament(const uint8_t index) { +void MMU2::load_to_feeder(const uint8_t index) { if (!_enabled) return; command(MMU_CMD_L0 + index); @@ -923,8 +929,7 @@ void MMU2::load_filament(const uint8_t index) { /** * Switch material and load to nozzle */ -bool MMU2::load_filament_to_nozzle(const uint8_t index) { - +bool MMU2::load_to_nozzle(const uint8_t index) { if (!_enabled) return false; if (thermalManager.tooColdToExtrude(active_extruder)) { @@ -933,6 +938,13 @@ bool MMU2::load_filament_to_nozzle(const uint8_t index) { return false; } + if (TERN0(MMU_IR_UNLOAD_MOVE, index != extruder) && FILAMENT_PRESENT()) { + DEBUG_ECHOLNPGM("Unloading\n"); + ramming_sequence(); // Unloading instructions from printer side when operating LCD + while (FILAMENT_PRESENT()) // Filament present? Keep unloading. + unscaled_mmu2_e_move(-0.25, MMM_TO_MMS(120)); // 0.25mm is a guessed value. Adjust to preference. + } + stepper.disable_extruder(); command(MMU_CMD_T0 + index); manage_response(true, true); @@ -942,23 +954,12 @@ bool MMU2::load_filament_to_nozzle(const uint8_t index) { mmu_loop(); extruder = index; active_extruder = 0; - load_to_nozzle(); + load_to_nozzle_sequence(); mmu2_attn_buzz(); } return success; } -/** - * Load filament to nozzle of multimaterial printer - * - * This function is used only after T? (user select filament) and M600 (change filament). - * It is not used after T0 .. T4 command (select filament), in such case, G-code is responsible for loading - * filament to nozzle. - */ -void MMU2::load_to_nozzle() { - execute_extruder_sequence((const E_Step *)load_to_nozzle_sequence, COUNT(load_to_nozzle_sequence)); -} - bool MMU2::eject_filament(const uint8_t index, const bool recover) { if (!_enabled) return false; @@ -971,20 +972,17 @@ bool MMU2::eject_filament(const uint8_t index, const bool recover) { LCD_MESSAGE(MSG_MMU2_EJECTING_FILAMENT); - stepper.enable_extruder(); - current_position.e -= MMU2_FILAMENTCHANGE_EJECT_FEED; - line_to_current_position(MMM_TO_MMS(2500)); - planner.synchronize(); + unscaled_mmu2_e_move(-(MMU2_FILAMENTCHANGE_EJECT_FEED), MMM_TO_MMS(2500)); command(MMU_CMD_E0 + index); manage_response(false, false); if (recover) { - LCD_MESSAGE(MSG_MMU2_EJECT_RECOVER); + LCD_MESSAGE(MSG_MMU2_REMOVE_AND_CLICK); mmu2_attn_buzz(); - TERN_(HOST_PROMPT_SUPPORT, hostui.prompt_do(PROMPT_USER_CONTINUE, F("MMU2 Eject Recover"), FPSTR(CONTINUE_STR))); - TERN_(EXTENSIBLE_UI, ExtUI::onUserConfirmRequired(F("MMU2 Eject Recover"))); + TERN_(HOST_PROMPT_SUPPORT, hostui.continue_prompt(GET_TEXT_F(MSG_MMU2_EJECT_RECOVER))); + TERN_(EXTENSIBLE_UI, ExtUI::onUserConfirmRequired(GET_TEXT_F(MSG_MMU2_EJECT_RECOVER))); TERN_(HAS_RESUME_CONTINUE, wait_for_user_response()); - mmu2_attn_buzz(true); + mmu2_attn_buzz(); command(MMU_CMD_R0); manage_response(false, false); @@ -1018,7 +1016,7 @@ bool MMU2::unload() { } // Unload sequence to optimize shape of the tip of the unloaded filament - execute_extruder_sequence((const E_Step *)ramming_sequence, sizeof(ramming_sequence) / sizeof(E_Step)); + ramming_sequence(); command(MMU_CMD_U0); manage_response(false, true); @@ -1033,23 +1031,26 @@ bool MMU2::unload() { return true; } +void MMU2::ramming_sequence() { + static const E_Step sequence[] PROGMEM = { MMU2_RAMMING_SEQUENCE }; + execute_extruder_sequence(sequence, COUNT(sequence)); +} + +void MMU2::load_to_nozzle_sequence() { + static const E_Step sequence[] PROGMEM = { MMU2_LOAD_TO_NOZZLE_SEQUENCE }; + execute_extruder_sequence(sequence, COUNT(sequence)); +} + void MMU2::execute_extruder_sequence(const E_Step * sequence, int steps) { - planner.synchronize(); - stepper.enable_extruder(); - const E_Step* step = sequence; + const E_Step *step = sequence; - LOOP_L_N(i, steps) { + for (uint8_t i = 0; i < steps; ++i) { const float es = pgm_read_float(&(step->extrude)); const feedRate_t fr_mm_m = pgm_read_float(&(step->feedRate)); - DEBUG_ECHO_MSG("E step ", es, "/", fr_mm_m); - - current_position.e += es; - line_to_current_position(MMM_TO_MMS(fr_mm_m)); - planner.synchronize(); - + unscaled_mmu2_e_move(es, MMM_TO_MMS(fr_mm_m)); step++; } diff --git a/Marlin/src/feature/mmu/mmu2.h b/Marlin/src/feature/mmu/mmu2.h index 18d6d38a35..2c9fd3308d 100644 --- a/Marlin/src/feature/mmu/mmu2.h +++ b/Marlin/src/feature/mmu/mmu2.h @@ -47,13 +47,12 @@ public: static void mmu_loop(); static void tool_change(const uint8_t index); static void tool_change(const char *special); - static uint8_t get_current_tool(); + static int8_t get_current_tool(); static void set_filament_type(const uint8_t index, const uint8_t type); static bool unload(); - static void load_filament(uint8_t); - static void load_all(); - static bool load_filament_to_nozzle(const uint8_t index); + static void load_to_feeder(const uint8_t index); + static bool load_to_nozzle(const uint8_t index); static bool eject_filament(const uint8_t index, const bool recover); private: @@ -65,14 +64,15 @@ private: static bool rx_ok(); static bool rx_start(); - static void check_version(); + static void check_version(const uint16_t buildnr); static void command(const uint8_t cmd); static bool get_response(); static void manage_response(const bool move_axes, const bool turn_off_nozzle); - static void load_to_nozzle(); static void execute_extruder_sequence(const E_Step * sequence, int steps); + static void ramming_sequence(); + static void load_to_nozzle_sequence(); static void filament_runout(); @@ -90,13 +90,12 @@ private: static void mmu_continue_loading(); #endif - static bool _enabled, ready, mmu_print_saved; + static bool _enabled, ready; static uint8_t cmd, cmd_arg, last_cmd, extruder; static int8_t state; static volatile int8_t finda; static volatile bool finda_runout_valid; - static int16_t version, buildnr; static millis_t prev_request, prev_P0_request; static char rx_buffer[MMU_RX_SIZE], tx_buffer[MMU_TX_SIZE]; diff --git a/Marlin/src/feature/pause.cpp b/Marlin/src/feature/pause.cpp index 1c2ea59d4d..f098ad9c51 100644 --- a/Marlin/src/feature/pause.cpp +++ b/Marlin/src/feature/pause.cpp @@ -91,7 +91,7 @@ static xyze_pos_t resume_position; fil_change_settings_t fc_settings[EXTRUDERS]; -#if ENABLED(SDSUPPORT) +#if HAS_MEDIA #include "../sd/cardreader.h" #endif @@ -201,7 +201,7 @@ bool load_filament(const_float_t slow_load_length/*=0*/, const_float_t fast_load KEEPALIVE_STATE(PAUSED_FOR_USER); wait_for_user = true; // LCD click or M108 will clear this - TERN_(EXTENSIBLE_UI, ExtUI::onUserConfirmRequired(F("Load Filament"))); + TERN_(EXTENSIBLE_UI, ExtUI::onUserConfirmRequired(GET_TEXT_F(MSG_FILAMENTLOAD))); #if ENABLED(HOST_PROMPT_SUPPORT) const char tool = '0' + TERN0(MULTI_FILAMENT_SENSOR, active_extruder); @@ -210,8 +210,8 @@ bool load_filament(const_float_t slow_load_length/*=0*/, const_float_t fast_load while (wait_for_user) { impatient_beep(max_beep_count); - #if BOTH(FILAMENT_CHANGE_RESUME_ON_INSERT, FILAMENT_RUNOUT_SENSOR) - #if ENABLED(MULTI_FILAMENT_SENSOR) + #if ALL(FILAMENT_CHANGE_RESUME_ON_INSERT, FILAMENT_RUNOUT_SENSOR) + #if MULTI_FILAMENT_SENSOR #define _CASE_INSERTED(N) case N-1: if (READ(FIL_RUNOUT##N##_PIN) != FIL_RUNOUT##N##_STATE) wait_for_user = false; break; switch (active_extruder) { REPEAT_1(NUM_RUNOUT_SENSORS, _CASE_INSERTED) @@ -234,6 +234,8 @@ bool load_filament(const_float_t slow_load_length/*=0*/, const_float_t fast_load TERN_(BELTPRINTER, do_blocking_move_to_xy(0.00, 50.00)); + TERN_(MPCTEMP, MPC::e_paused = true); + // Slow Load filament if (slow_load_length) unscaled_e_move(slow_load_length, FILAMENT_CHANGE_SLOW_LOAD_FEEDRATE); @@ -260,7 +262,7 @@ bool load_filament(const_float_t slow_load_length/*=0*/, const_float_t fast_load if (show_lcd) ui.pause_show_message(PAUSE_MESSAGE_PURGE); TERN_(EXTENSIBLE_UI, ExtUI::onUserConfirmRequired(GET_TEXT_F(MSG_FILAMENT_CHANGE_PURGE))); - TERN_(HOST_PROMPT_SUPPORT, hostui.prompt_do(PROMPT_USER_CONTINUE, GET_TEXT_F(MSG_FILAMENT_CHANGE_PURGE), FPSTR(CONTINUE_STR))); + TERN_(HOST_PROMPT_SUPPORT, hostui.continue_prompt(GET_TEXT_F(MSG_FILAMENT_CHANGE_PURGE))); wait_for_user = true; // A click or M108 breaks the purge_length loop for (float purge_count = purge_length; purge_count > 0 && wait_for_user; --purge_count) unscaled_e_move(1, ADVANCED_PAUSE_PURGE_FEEDRATE); @@ -284,7 +286,7 @@ bool load_filament(const_float_t slow_load_length/*=0*/, const_float_t fast_load // Show "Purge More" / "Resume" menu and wait for reply KEEPALIVE_STATE(PAUSED_FOR_USER); wait_for_user = false; - #if EITHER(HAS_MARLINUI_MENU, DWIN_LCD_PROUI) + #if ANY(HAS_MARLINUI_MENU, DWIN_LCD_PROUI) ui.pause_show_message(PAUSE_MESSAGE_OPTION); // Also sets PAUSE_RESPONSE_WAIT_FOR #else pause_menu_response = PAUSE_RESPONSE_WAIT_FOR; @@ -297,6 +299,9 @@ bool load_filament(const_float_t slow_load_length/*=0*/, const_float_t fast_load } while (TERN0(M600_PURGE_MORE_RESUMABLE, pause_menu_response == PAUSE_RESPONSE_EXTRUDE_MORE)); #endif + + TERN_(MPCTEMP, MPC::e_paused = false); + TERN_(HOST_PROMPT_SUPPORT, hostui.prompt_end()); return true; @@ -326,18 +331,18 @@ inline void disable_active_extruder() { */ bool unload_filament(const_float_t unload_length, const bool show_lcd/*=false*/, const PauseMode mode/*=PAUSE_MODE_PAUSE_PRINT*/ - #if BOTH(FILAMENT_UNLOAD_ALL_EXTRUDERS, MIXING_EXTRUDER) + #if ALL(FILAMENT_UNLOAD_ALL_EXTRUDERS, MIXING_EXTRUDER) , const_float_t mix_multiplier/*=1.0*/ #endif ) { DEBUG_SECTION(uf, "unload_filament", true); DEBUG_ECHOLNPGM("... unloadlen:", unload_length, " showlcd:", show_lcd, " mode:", mode - #if BOTH(FILAMENT_UNLOAD_ALL_EXTRUDERS, MIXING_EXTRUDER) + #if ALL(FILAMENT_UNLOAD_ALL_EXTRUDERS, MIXING_EXTRUDER) , " mixmult:", mix_multiplier #endif ); - #if !BOTH(FILAMENT_UNLOAD_ALL_EXTRUDERS, MIXING_EXTRUDER) + #if !ALL(FILAMENT_UNLOAD_ALL_EXTRUDERS, MIXING_EXTRUDER) constexpr float mix_multiplier = 1.0f; #endif @@ -397,8 +402,6 @@ bool pause_print(const_float_t retract, const xyz_pos_t &park_point, const bool DEBUG_SECTION(pp, "pause_print", true); DEBUG_ECHOLNPGM("... park.x:", park_point.x, " y:", park_point.y, " z:", park_point.z, " unloadlen:", unload_length, " showlcd:", show_lcd DXC_SAY); - UNUSED(show_lcd); - if (did_pause_print) return false; // already paused #if ENABLED(HOST_ACTION_COMMANDS) @@ -410,13 +413,12 @@ bool pause_print(const_float_t retract, const xyz_pos_t &park_point, const bool #endif TERN_(HOST_PROMPT_SUPPORT, hostui.prompt_open(PROMPT_INFO, F("Pause"), FPSTR(DISMISS_STR))); - TERN_(DWIN_LCD_PROUI, DWIN_Print_Pause()); // Indicate that the printer is paused ++did_pause_print; // Pause the print job and timer - #if ENABLED(SDSUPPORT) + #if HAS_MEDIA const bool was_sd_printing = IS_SD_PRINTING(); if (was_sd_printing) { card.pauseSDPrint(); @@ -441,7 +443,7 @@ bool pause_print(const_float_t retract, const xyz_pos_t &park_point, const bool // Wait for buffered blocks to complete planner.synchronize(); - #if ENABLED(ADVANCED_PAUSE_FANS_PAUSE) && HAS_FAN + #if ALL(ADVANCED_PAUSE_FANS_PAUSE, HAS_FAN) thermalManager.set_fans_paused(true); #endif @@ -461,6 +463,7 @@ bool pause_print(const_float_t retract, const xyz_pos_t &park_point, const bool // If axes don't need to home then the nozzle can park if (do_park) nozzle.park(0, park_point); // Park the nozzle by doing a Minimum Z Raise followed by an XY Move + if (!do_park) LCD_MESSAGE(MSG_PARK_FAILED); #if ENABLED(DUAL_X_CARRIAGE) const int8_t saved_ext = active_extruder; @@ -472,9 +475,7 @@ bool pause_print(const_float_t retract, const xyz_pos_t &park_point, const bool if (unload_length) unload_filament(unload_length, show_lcd, PAUSE_MODE_CHANGE_FILAMENT); - #if ENABLED(DUAL_X_CARRIAGE) - set_duplication_enabled(saved_ext_dup_mode, saved_ext); - #endif + TERN_(DUAL_X_CARRIAGE, set_duplication_enabled(saved_ext_dup_mode, saved_ext)); // Disable the Extruder for manual change disable_active_extruder(); @@ -501,7 +502,7 @@ void show_continue_prompt(const bool is_reload) { ui.pause_show_message(is_reload ? PAUSE_MESSAGE_INSERT : PAUSE_MESSAGE_WAITING); SERIAL_ECHO_START(); - SERIAL_ECHOF(is_reload ? F(_PMSG(STR_FILAMENT_CHANGE_INSERT) "\n") : F(_PMSG(STR_FILAMENT_CHANGE_WAIT) "\n")); + SERIAL_ECHO(is_reload ? F(_PMSG(STR_FILAMENT_CHANGE_INSERT) "\n") : F(_PMSG(STR_FILAMENT_CHANGE_WAIT) "\n")); } void wait_for_confirmation(const bool is_reload/*=false*/, const int8_t max_beep_count/*=0*/ DXC_ARGS) { @@ -527,7 +528,7 @@ void wait_for_confirmation(const bool is_reload/*=false*/, const int8_t max_beep // Wait for filament insert by user and press button KEEPALIVE_STATE(PAUSED_FOR_USER); - TERN_(HOST_PROMPT_SUPPORT, hostui.prompt_do(PROMPT_USER_CONTINUE, GET_TEXT_F(MSG_NOZZLE_PARKED), FPSTR(CONTINUE_STR))); + TERN_(HOST_PROMPT_SUPPORT, hostui.continue_prompt(GET_TEXT_F(MSG_NOZZLE_PARKED))); TERN_(EXTENSIBLE_UI, ExtUI::onUserConfirmRequired(GET_TEXT_F(MSG_NOZZLE_PARKED))); wait_for_user = true; // LCD click or M108 will clear this while (wait_for_user) { @@ -545,15 +546,17 @@ void wait_for_confirmation(const bool is_reload/*=false*/, const int8_t max_beep TERN_(HOST_PROMPT_SUPPORT, hostui.prompt_do(PROMPT_USER_CONTINUE, GET_TEXT_F(MSG_HEATER_TIMEOUT), GET_TEXT_F(MSG_REHEAT))); - TERN_(EXTENSIBLE_UI, ExtUI::onUserConfirmRequired(GET_TEXT_F(MSG_HEATER_TIMEOUT))); + #if ENABLED(TOUCH_UI_FTDI_EVE) + ExtUI::onUserConfirmRequired(GET_TEXT_F(MSG_FTDI_HEATER_TIMEOUT)); + #elif ENABLED(EXTENSIBLE_UI) + ExtUI::onUserConfirmRequired(GET_TEXT_F(MSG_HEATER_TIMEOUT)); + #endif TERN_(HAS_RESUME_CONTINUE, wait_for_user_response(0, true)); // Wait for LCD click or M108 TERN_(HOST_PROMPT_SUPPORT, hostui.prompt_do(PROMPT_INFO, GET_TEXT_F(MSG_REHEATING))); - TERN_(EXTENSIBLE_UI, ExtUI::onStatusChanged(GET_TEXT_F(MSG_REHEATING))); - - TERN_(DWIN_LCD_PROUI, LCD_MESSAGE(MSG_REHEATING)); + LCD_MESSAGE(MSG_REHEATING); // Re-enable the heaters if they timed out HOTEND_LOOP() thermalManager.reset_hotend_idle_timer(e); @@ -569,9 +572,12 @@ void wait_for_confirmation(const bool is_reload/*=false*/, const int8_t max_beep HOTEND_LOOP() thermalManager.heater_idle[e].start(nozzle_timeout); - TERN_(HOST_PROMPT_SUPPORT, hostui.prompt_do(PROMPT_USER_CONTINUE, GET_TEXT_F(MSG_REHEATDONE), FPSTR(CONTINUE_STR))); - TERN_(EXTENSIBLE_UI, ExtUI::onUserConfirmRequired(GET_TEXT_F(MSG_REHEATDONE))); - TERN_(DWIN_LCD_PROUI, LCD_MESSAGE(MSG_REHEATDONE)); + TERN_(HOST_PROMPT_SUPPORT, hostui.continue_prompt(GET_TEXT_F(MSG_REHEATDONE))); + #if ENABLED(EXTENSIBLE_UI) + ExtUI::onUserConfirmRequired(GET_TEXT_F(MSG_REHEATDONE)); + #else + LCD_MESSAGE(MSG_REHEATDONE); + #endif IF_DISABLED(PAUSE_REHEAT_FAST_RESUME, wait_for_user = true); @@ -580,9 +586,7 @@ void wait_for_confirmation(const bool is_reload/*=false*/, const int8_t max_beep } idle_no_sleep(); } - #if ENABLED(DUAL_X_CARRIAGE) - set_duplication_enabled(saved_ext_dup_mode, saved_ext); - #endif + TERN_(DUAL_X_CARRIAGE, set_duplication_enabled(saved_ext_dup_mode, saved_ext)); } /** @@ -699,7 +703,7 @@ void resume_print(const_float_t slow_load_length/*=0*/, const_float_t fast_load_ // Resume the print job timer if it was running if (print_job_timer.isPaused()) print_job_timer.start(); - #if ENABLED(SDSUPPORT) + #if HAS_MEDIA if (did_pause_print) { --did_pause_print; card.startOrResumeFilePrinting(); @@ -714,13 +718,8 @@ void resume_print(const_float_t slow_load_length/*=0*/, const_float_t fast_load_ TERN_(HAS_FILAMENT_SENSOR, runout.reset()); - #if ENABLED(DWIN_LCD_PROUI) - DWIN_Print_Resume(); - HMI_ReturnScreen(); - #else - ui.reset_status(); - ui.return_to_status(); - #endif + ui.reset_status(); + ui.return_to_status(); } #endif // ADVANCED_PAUSE_FEATURE diff --git a/Marlin/src/feature/pause.h b/Marlin/src/feature/pause.h index 134b1d1b32..45f62dc310 100644 --- a/Marlin/src/feature/pause.h +++ b/Marlin/src/feature/pause.h @@ -48,15 +48,15 @@ enum PauseMessage : char { PAUSE_MESSAGE_PARKING, PAUSE_MESSAGE_CHANGING, PAUSE_MESSAGE_WAITING, - PAUSE_MESSAGE_UNLOAD, PAUSE_MESSAGE_INSERT, PAUSE_MESSAGE_LOAD, + PAUSE_MESSAGE_UNLOAD, PAUSE_MESSAGE_PURGE, PAUSE_MESSAGE_OPTION, PAUSE_MESSAGE_RESUME, - PAUSE_MESSAGE_STATUS, PAUSE_MESSAGE_HEAT, - PAUSE_MESSAGE_HEATING + PAUSE_MESSAGE_HEATING, + PAUSE_MESSAGE_STATUS }; #if M600_PURGE_MORE_RESUMABLE @@ -117,7 +117,7 @@ bool unload_filament( const_float_t unload_length, // (mm) Filament Unload Length - 0 to skip const bool show_lcd=false, // Set LCD status messages? const PauseMode mode=PAUSE_MODE_PAUSE_PRINT // Pause Mode to apply - #if BOTH(FILAMENT_UNLOAD_ALL_EXTRUDERS, MIXING_EXTRUDER) + #if ALL(FILAMENT_UNLOAD_ALL_EXTRUDERS, MIXING_EXTRUDER) , const_float_t mix_multiplier=1.0f // Extrusion multiplier (for a Mixing Extruder) #endif ); diff --git a/Marlin/src/feature/power.cpp b/Marlin/src/feature/power.cpp index 8a16628bac..e908c8292f 100644 --- a/Marlin/src/feature/power.cpp +++ b/Marlin/src/feature/power.cpp @@ -26,7 +26,7 @@ #include "../inc/MarlinConfigPre.h" -#if EITHER(PSU_CONTROL, AUTO_POWER_CONTROL) +#if ANY(PSU_CONTROL, AUTO_POWER_CONTROL) #include "power.h" #include "../module/planner.h" @@ -49,10 +49,14 @@ bool Power::psu_on; #include "../module/stepper.h" #include "../module/temperature.h" - #if BOTH(USE_CONTROLLER_FAN, AUTO_POWER_CONTROLLERFAN) + #if ALL(USE_CONTROLLER_FAN, AUTO_POWER_CONTROLLERFAN) #include "controllerfan.h" #endif + #if ANY(LASER_FEATURE, SPINDLE_FEATURE) + #include "spindle_laser.h" + #endif + millis_t Power::lastPowerOn; #endif @@ -78,7 +82,7 @@ void Power::power_on() { if (psu_on) return; - #if EITHER(POWER_OFF_TIMER, POWER_OFF_WAIT_FOR_COOLDOWN) + #if ANY(POWER_OFF_TIMER, POWER_OFF_WAIT_FOR_COOLDOWN) cancelAutoPowerOff(); #endif @@ -115,12 +119,12 @@ void Power::power_off() { OUT_WRITE(PS_ON_PIN, !PSU_ACTIVE_STATE); psu_on = false; - #if EITHER(POWER_OFF_TIMER, POWER_OFF_WAIT_FOR_COOLDOWN) + #if ANY(POWER_OFF_TIMER, POWER_OFF_WAIT_FOR_COOLDOWN) cancelAutoPowerOff(); #endif } -#if EITHER(AUTO_POWER_CONTROL, POWER_OFF_WAIT_FOR_COOLDOWN) +#if ANY(AUTO_POWER_CONTROL, POWER_OFF_WAIT_FOR_COOLDOWN) bool Power::is_cooling_needed() { #if HAS_HOTEND && AUTO_POWER_E_TEMP @@ -140,7 +144,7 @@ void Power::power_off() { #endif -#if EITHER(POWER_OFF_TIMER, POWER_OFF_WAIT_FOR_COOLDOWN) +#if ANY(POWER_OFF_TIMER, POWER_OFF_WAIT_FOR_COOLDOWN) #if ENABLED(POWER_OFF_TIMER) millis_t Power::power_off_time = 0; @@ -192,10 +196,14 @@ void Power::power_off() { HOTEND_LOOP() if (thermalManager.autofan_speed[e]) return true; #endif - #if BOTH(USE_CONTROLLER_FAN, AUTO_POWER_CONTROLLERFAN) + #if ALL(USE_CONTROLLER_FAN, AUTO_POWER_CONTROLLERFAN) if (controllerFan.state()) return true; #endif + #if ANY(LASER_FEATURE, SPINDLE_FEATURE) + if (TERN0(AUTO_POWER_SPINDLE_LASER, cutter.enabled())) return true; + #endif + if (TERN0(AUTO_POWER_CHAMBER_FAN, thermalManager.chamberfan_speed)) return true; diff --git a/Marlin/src/feature/power.h b/Marlin/src/feature/power.h index 839366ca60..fdbb7126ce 100644 --- a/Marlin/src/feature/power.h +++ b/Marlin/src/feature/power.h @@ -25,7 +25,7 @@ * power.h - power control */ -#if EITHER(AUTO_POWER_CONTROL, POWER_OFF_TIMER) +#if ANY(AUTO_POWER_CONTROL, POWER_OFF_TIMER) #include "../core/millis_t.h" #endif @@ -37,7 +37,7 @@ class Power { static void power_on(); static void power_off(); - #if EITHER(POWER_OFF_TIMER, POWER_OFF_WAIT_FOR_COOLDOWN) + #if ANY(POWER_OFF_TIMER, POWER_OFF_WAIT_FOR_COOLDOWN) #if ENABLED(POWER_OFF_TIMER) static millis_t power_off_time; static void setPowerOffTimer(const millis_t delay_ms); diff --git a/Marlin/src/feature/power_monitor.h b/Marlin/src/feature/power_monitor.h index fa06909053..d57ef6fa67 100644 --- a/Marlin/src/feature/power_monitor.h +++ b/Marlin/src/feature/power_monitor.h @@ -46,11 +46,11 @@ struct pm_lpf_t { class PowerMonitor { private: #if ENABLED(POWER_MONITOR_CURRENT) - static constexpr float amps_adc_scale = float(ADC_VREF) / (POWER_MONITOR_VOLTS_PER_AMP * PM_SAMPLE_RANGE); + static constexpr float amps_adc_scale = (float(ADC_VREF_MV) / 1000.0f) / (POWER_MONITOR_VOLTS_PER_AMP * PM_SAMPLE_RANGE); static pm_lpf_t amps; #endif #if ENABLED(POWER_MONITOR_VOLTAGE) - static constexpr float volts_adc_scale = float(ADC_VREF) / (POWER_MONITOR_VOLTS_PER_VOLT * PM_SAMPLE_RANGE); + static constexpr float volts_adc_scale = (float(ADC_VREF_MV) / 1000.0f) / (POWER_MONITOR_VOLTS_PER_VOLT * PM_SAMPLE_RANGE); static pm_lpf_t volts; #endif @@ -119,7 +119,7 @@ public: volts.reset(); #endif - #if ENABLED(SDSUPPORT) + #if HAS_MEDIA display_item_ms = 0; display_item = 0; #endif diff --git a/Marlin/src/feature/powerloss.cpp b/Marlin/src/feature/powerloss.cpp index d4450adcd8..5a25710084 100644 --- a/Marlin/src/feature/powerloss.cpp +++ b/Marlin/src/feature/powerloss.cpp @@ -31,9 +31,13 @@ #include "powerloss.h" #include "../core/macros.h" +#if ENABLED(EXTENSIBLE_UI) + #include "../lcd/extui/ui_api.h" +#endif + bool PrintJobRecovery::enabled; // Initialized by settings.load() -SdFile PrintJobRecovery::file; +MediaFile PrintJobRecovery::file; job_recovery_info_t PrintJobRecovery::info; const char PrintJobRecovery::filename[5] = "/PLR"; uint8_t PrintJobRecovery::queue_index_r; @@ -78,6 +82,13 @@ PrintJobRecovery recovery; #define POWER_LOSS_RETRACT_LEN 0 #endif +// Allow power-loss recovery to be aborted +#define PLR_CAN_ABORT +#define PROCESS_SUBCOMMANDS_NOW(cmd) do{ \ + if (TERN0(PLR_CAN_ABORT, card.flag.abort_sd_printing)) return; \ + gcode.process_subcommands_now(cmd); \ + }while(0) + /** * Clear the recovery info */ @@ -101,6 +112,7 @@ void PrintJobRecovery::changed() { purge(); else if (IS_SD_PRINTING()) save(true); + TERN_(EXTENSIBLE_UI, ExtUI::onSetPowerLoss(enabled)); } /** @@ -195,7 +207,7 @@ void PrintJobRecovery::save(const bool force/*=false*/, const float zraise/*=POW TERN_(GCODE_REPEAT_MARKERS, info.stored_repeat = repeat); TERN_(HAS_HOME_OFFSET, info.home_offset = home_offset); - TERN_(HAS_POSITION_SHIFT, info.position_shift = position_shift); + TERN_(HAS_WORKSPACE_OFFSET, info.workspace_offset = workspace_offset); E_TERN_(info.active_extruder = active_extruder); #if DISABLED(NO_VOLUMETRICS) @@ -207,15 +219,13 @@ void PrintJobRecovery::save(const bool force/*=false*/, const float zraise/*=POW #endif #endif - #if HAS_EXTRUDERS + #if HAS_HOTEND HOTEND_LOOP() info.target_temperature[e] = thermalManager.degTargetHotend(e); #endif TERN_(HAS_HEATED_BED, info.target_temperature_bed = thermalManager.degTargetBed()); - #if HAS_FAN - COPY(info.fan_speed, thermalManager.fan_speed); - #endif + TERN_(HAS_FAN, COPY(info.fan_speed, thermalManager.fan_speed)); #if HAS_LEVELING info.flag.leveling = planner.leveling_active; @@ -259,11 +269,8 @@ void PrintJobRecovery::save(const bool force/*=false*/, const float zraise/*=POW #if POWER_LOSS_ZRAISE // Raise the Z axis now - if (zraise) { - char cmd[20], str_1[16]; - sprintf_P(cmd, PSTR("G0Z%s"), dtostrf(zraise, 1, 3, str_1)); - gcode.process_subcommands_now(cmd); - } + if (zraise) + gcode.process_subcommands_now(TS(F("G0Z"), p_float_t(zraise, 3))); #else UNUSED(zraise); #endif @@ -305,6 +312,9 @@ void PrintJobRecovery::save(const bool force/*=false*/, const float zraise/*=POW // and a flag whether the raise was already done here. if (IS_SD_PRINTING()) save(true, zraise, ENABLED(BACKUP_POWER_SUPPLY)); + // Tell the LCD about the outage, even though it is about to die + TERN_(EXTENSIBLE_UI, ExtUI::onPowerLoss()); + // Disable all heaters to reduce power loss thermalManager.disable_all_heaters(); @@ -344,29 +354,34 @@ void PrintJobRecovery::write() { * Resume the saved print job */ void PrintJobRecovery::resume() { - - char cmd[MAX_CMD_SIZE+16], str_1[16], str_2[16]; - const uint32_t resume_sdpos = info.sdpos; // Get here before the stepper ISR overwrites it // Apply the dry-run flag if enabled if (info.flag.dryrun) marlin_debug_flags |= MARLIN_DEBUG_DRYRUN; + #if ENABLED(DEBUG_POWER_LOSS_RECOVERY) + struct OnExit { + uint8_t old_flags; + OnExit() { + old_flags = marlin_debug_flags; + marlin_debug_flags |= MARLIN_DEBUG_ECHO; + } + ~OnExit() { marlin_debug_flags = old_flags; } + } on_exit; + #endif + // Restore cold extrusion permission TERN_(PREVENT_COLD_EXTRUSION, thermalManager.allow_cold_extrude = info.flag.allow_cold_extrusion); #if HAS_LEVELING // Make sure leveling is off before any G92 and G28 - gcode.process_subcommands_now(F("M420 S0 Z0")); + PROCESS_SUBCOMMANDS_NOW(F("M420S0")); #endif #if HAS_HEATED_BED + // Restore the bed temperature const celsius_t bt = info.target_temperature_bed; - if (bt) { - // Restore the bed temperature - sprintf_P(cmd, PSTR("M190S%i"), bt); - gcode.process_subcommands_now(cmd); - } + if (bt) PROCESS_SUBCOMMANDS_NOW(TS(F("M190S"), bt)); #endif // Heat hotend enough to soften material @@ -374,12 +389,8 @@ void PrintJobRecovery::resume() { HOTEND_LOOP() { const celsius_t et = _MAX(info.target_temperature[e], 180); if (et) { - #if HAS_MULTI_HOTEND - sprintf_P(cmd, PSTR("T%iS"), e); - gcode.process_subcommands_now(cmd); - #endif - sprintf_P(cmd, PSTR("M109S%i"), et); - gcode.process_subcommands_now(cmd); + TERN_(HAS_MULTI_HOTEND, PROCESS_SUBCOMMANDS_NOW(TS('T', e, 'S'))); + PROCESS_SUBCOMMANDS_NOW(TS(F("M109S"), et)); } } #endif @@ -393,18 +404,18 @@ void PrintJobRecovery::resume() { // establish the current position as best we can. // - gcode.process_subcommands_now(F("G92.9E0")); // Reset E to 0 + PROCESS_SUBCOMMANDS_NOW(F("G92.9E0")); // Reset E to 0 #if Z_HOME_TO_MAX float z_now = z_raised; // If Z homing goes to max then just move back to the "raised" position - sprintf_P(cmd, PSTR( - "G28R0\n" // Home all axes (no raise) - "G1Z%sF1200" // Move Z down to (raised) height - ), dtostrf(z_now, 1, 3, str_1)); - gcode.process_subcommands_now(cmd); + PROCESS_SUBCOMMANDS_NOW(TS( + F( "G28R0\n" // Home all axes (no raise) + "G1F1200Z") // Move Z down to (raised) height + , p_float_t(z_now, 3) + )); #elif DISABLED(BELTPRINTER) @@ -416,27 +427,24 @@ void PrintJobRecovery::resume() { #if !HOMING_Z_DOWN // Set Z to the real position - sprintf_P(cmd, PSTR("G92.9Z%s"), dtostrf(z_now, 1, 3, str_1)); - gcode.process_subcommands_now(cmd); + PROCESS_SUBCOMMANDS_NOW(TS(F("G92.9Z"), p_float_t(z_now, 3))); #endif // Does Z need to be raised now? It should be raised before homing XY. if (z_raised > z_now) { z_now = z_raised; - sprintf_P(cmd, PSTR("G1Z%sF600"), dtostrf(z_now, 1, 3, str_1)); - gcode.process_subcommands_now(cmd); + PROCESS_SUBCOMMANDS_NOW(TS(F("G1F600Z"), p_float_t(z_now, 3))); } // Home XY with no Z raise - gcode.process_subcommands_now(F("G28R0XY")); // No raise during G28 + PROCESS_SUBCOMMANDS_NOW(F("G28R0XY")); // No raise during G28 #endif #if HOMING_Z_DOWN // Move to a safe XY position and home Z while avoiding the print. const xy_pos_t p = xy_pos_t(POWER_LOSS_ZHOME_POS) TERN_(HOMING_Z_WITH_PROBE, - probe.offset_xy); - sprintf_P(cmd, PSTR("G1X%sY%sF1000\nG28HZ"), dtostrf(p.x, 1, 3, str_1), dtostrf(p.y, 1, 3, str_2)); - gcode.process_subcommands_now(cmd); + PROCESS_SUBCOMMANDS_NOW(TS(F("G1F1000X"), p_float_t(p.x, 3), 'Y', p_float_t(p.y, 3), F("\nG28HZ"))); #endif // Mark all axes as having been homed (no effect on current_position) @@ -446,39 +454,30 @@ void PrintJobRecovery::resume() { // Restore Z fade and possibly re-enable bed leveling compensation. // Leveling may already be enabled due to the ENABLE_LEVELING_AFTER_G28 option. // TODO: Add a G28 parameter to leave leveling disabled. - sprintf_P(cmd, PSTR("M420S%cZ%s"), '0' + (char)info.flag.leveling, dtostrf(info.fade, 1, 1, str_1)); - gcode.process_subcommands_now(cmd); + PROCESS_SUBCOMMANDS_NOW(TS(F("M420S"), '0' + (char)info.flag.leveling, 'Z', p_float_t(info.fade, 1))); #if !HOMING_Z_DOWN // The physical Z was adjusted at power-off so undo the M420S1 correction to Z with G92.9. - sprintf_P(cmd, PSTR("G92.9Z%s"), dtostrf(z_now, 1, 1, str_1)); - gcode.process_subcommands_now(cmd); + PROCESS_SUBCOMMANDS_NOW(TS(F("G92.9Z"), p_float_t(z_now, 1))); #endif #endif #if ENABLED(POWER_LOSS_RECOVER_ZHOME) // Z was homed down to the bed, so move up to the raised height. z_now = z_raised; - sprintf_P(cmd, PSTR("G1Z%sF600"), dtostrf(z_now, 1, 3, str_1)); - gcode.process_subcommands_now(cmd); + PROCESS_SUBCOMMANDS_NOW(TS(F("G1F600Z"), p_float_t(z_now, 3))); #endif // Recover volumetric extrusion state #if DISABLED(NO_VOLUMETRICS) #if HAS_MULTI_EXTRUDER - EXTRUDER_LOOP() { - sprintf_P(cmd, PSTR("M200T%iD%s"), e, dtostrf(info.filament_size[e], 1, 3, str_1)); - gcode.process_subcommands_now(cmd); - } - if (!info.flag.volumetric_enabled) { - sprintf_P(cmd, PSTR("M200T%iD0"), info.active_extruder); - gcode.process_subcommands_now(cmd); - } + EXTRUDER_LOOP() + PROCESS_SUBCOMMANDS_NOW(TS(F("M200T"), e, F("D"), p_float_t(info.filament_size[e], 3))); + if (!info.flag.volumetric_enabled) + PROCESS_SUBCOMMANDS_NOW(TS(F("M200D0T"), info.active_extruder)); #else - if (info.flag.volumetric_enabled) { - sprintf_P(cmd, PSTR("M200D%s"), dtostrf(info.filament_size[0], 1, 3, str_1)); - gcode.process_subcommands_now(cmd); - } + if (info.flag.volumetric_enabled) + PROCESS_SUBCOMMANDS_NOW(TS(F("M200D"), p_float_t(info.filament_size[0], 3))); #endif #endif @@ -487,30 +486,22 @@ void PrintJobRecovery::resume() { HOTEND_LOOP() { const celsius_t et = info.target_temperature[e]; if (et) { - #if HAS_MULTI_HOTEND - sprintf_P(cmd, PSTR("T%iS"), e); - gcode.process_subcommands_now(cmd); - #endif - sprintf_P(cmd, PSTR("M109S%i"), et); - gcode.process_subcommands_now(cmd); + TERN_(HAS_MULTI_HOTEND, PROCESS_SUBCOMMANDS_NOW(TS('T', e, 'S'))); + PROCESS_SUBCOMMANDS_NOW(TS(F("M109S"), et)); } } #endif // Restore the previously active tool (with no_move) #if HAS_MULTI_EXTRUDER || HAS_MULTI_HOTEND - sprintf_P(cmd, PSTR("T%i S"), info.active_extruder); - gcode.process_subcommands_now(cmd); + PROCESS_SUBCOMMANDS_NOW(TS('T', info.active_extruder, 'S')); #endif // Restore print cooling fan speeds #if HAS_FAN FANS_LOOP(i) { const int f = info.fan_speed[i]; - if (f) { - sprintf_P(cmd, PSTR("M106P%iS%i"), i, f); - gcode.process_subcommands_now(cmd); - } + if (f) PROCESS_SUBCOMMANDS_NOW(TS(F("M106P"), i, 'S', f)); } #endif @@ -531,77 +522,57 @@ void PrintJobRecovery::resume() { // Un-retract if there was a retract at outage #if ENABLED(BACKUP_POWER_SUPPLY) && POWER_LOSS_RETRACT_LEN > 0 - gcode.process_subcommands_now(F("G1F3000E" STRINGIFY(POWER_LOSS_RETRACT_LEN))); + PROCESS_SUBCOMMANDS_NOW(F("G1F3000E" STRINGIFY(POWER_LOSS_RETRACT_LEN))); #endif // Additional purge on resume if configured #if POWER_LOSS_PURGE_LEN - sprintf_P(cmd, PSTR("G1F3000E%d"), (POWER_LOSS_PURGE_LEN) + (POWER_LOSS_RETRACT_LEN)); - gcode.process_subcommands_now(cmd); + PROCESS_SUBCOMMANDS_NOW(TS(F("G1F3000E"), (POWER_LOSS_PURGE_LEN) + (POWER_LOSS_RETRACT_LEN))); #endif #if ENABLED(NOZZLE_CLEAN_FEATURE) - gcode.process_subcommands_now(F("G12")); + PROCESS_SUBCOMMANDS_NOW(F("G12")); #endif // Move back over to the saved XY - sprintf_P(cmd, PSTR("G1X%sY%sF3000"), - dtostrf(info.current_position.x, 1, 3, str_1), - dtostrf(info.current_position.y, 1, 3, str_2) - ); - gcode.process_subcommands_now(cmd); + PROCESS_SUBCOMMANDS_NOW(TS( + F("G1F3000X"), p_float_t(info.current_position.x, 3), 'Y', p_float_t(info.current_position.y, 3) + )); // Move back down to the saved Z for printing - sprintf_P(cmd, PSTR("G1Z%sF600"), dtostrf(z_print, 1, 3, str_1)); - gcode.process_subcommands_now(cmd); + PROCESS_SUBCOMMANDS_NOW(TS(F("G1F600Z"), p_float_t(z_print, 3))); // Restore the feedrate - sprintf_P(cmd, PSTR("G1F%d"), info.feedrate); - gcode.process_subcommands_now(cmd); + PROCESS_SUBCOMMANDS_NOW(TS(F("G1F"), info.feedrate)); // Restore E position with G92.9 - sprintf_P(cmd, PSTR("G92.9E%s"), dtostrf(info.current_position.e, 1, 3, str_1)); - gcode.process_subcommands_now(cmd); + PROCESS_SUBCOMMANDS_NOW(TS(F("G92.9E"), p_float_t(info.current_position.e, 3))); TERN_(GCODE_REPEAT_MARKERS, repeat = info.stored_repeat); TERN_(HAS_HOME_OFFSET, home_offset = info.home_offset); - TERN_(HAS_POSITION_SHIFT, position_shift = info.position_shift); - #if HAS_HOME_OFFSET || HAS_POSITION_SHIFT - LOOP_NUM_AXES(i) update_workspace_offset((AxisEnum)i); - #endif + TERN_(HAS_WORKSPACE_OFFSET, workspace_offset = info.workspace_offset); // Relative axis modes gcode.axis_relative = info.axis_relative; - #if ENABLED(DEBUG_POWER_LOSS_RECOVERY) - const uint8_t old_flags = marlin_debug_flags; - marlin_debug_flags |= MARLIN_DEBUG_ECHO; - #endif - // Continue to apply PLR when a file is resumed! enable(true); // Resume the SD file from the last position - char *fn = info.sd_filename; - sprintf_P(cmd, M23_STR, fn); - gcode.process_subcommands_now(cmd); - sprintf_P(cmd, PSTR("M24S%ldT%ld"), resume_sdpos, info.print_job_elapsed); - gcode.process_subcommands_now(cmd); - - TERN_(DEBUG_POWER_LOSS_RECOVERY, marlin_debug_flags = old_flags); + PROCESS_SUBCOMMANDS_NOW(MString(F("M23 "), info.sd_filename)); + PROCESS_SUBCOMMANDS_NOW(TS(F("M24S"), resume_sdpos, 'T', info.print_job_elapsed)); } #if ENABLED(DEBUG_POWER_LOSS_RECOVERY) void PrintJobRecovery::debug(FSTR_P const prefix) { - DEBUG_ECHOF(prefix); - DEBUG_ECHOLNPGM(" Job Recovery Info...\nvalid_head:", info.valid_head, " valid_foot:", info.valid_foot); + DEBUG_ECHOLN(prefix, F(" Job Recovery Info...\nvalid_head:"), info.valid_head, F(" valid_foot:"), info.valid_foot); if (info.valid_head) { if (info.valid_head == info.valid_foot) { DEBUG_ECHOPGM("current_position: "); LOOP_LOGICAL_AXES(i) { if (i) DEBUG_CHAR(','); - DEBUG_DECIMAL(info.current_position[i]); + DEBUG_ECHO(info.current_position[i]); } DEBUG_EOL(); @@ -610,25 +581,26 @@ void PrintJobRecovery::resume() { DEBUG_ECHOLNPGM("zraise: ", info.zraise, " ", info.flag.raised ? "(before)" : ""); #if ENABLED(GCODE_REPEAT_MARKERS) - DEBUG_ECHOLNPGM("repeat index: ", info.stored_repeat.index); - LOOP_L_N(i, info.stored_repeat.index) - DEBUG_ECHOLNPGM("..... sdpos: ", info.stored_repeat.marker.sdpos, " count: ", info.stored_repeat.marker.counter); + const uint8_t ind = info.stored_repeat.count(); + DEBUG_ECHOLNPGM("repeat markers: ", ind); + for (uint8_t i = ind; i--;) + DEBUG_ECHOLNPGM("...", i, " sdpos: ", info.stored_repeat.get_marker_sdpos(i), " count: ", info.stored_repeat.get_marker_counter(i)); #endif #if HAS_HOME_OFFSET DEBUG_ECHOPGM("home_offset: "); LOOP_NUM_AXES(i) { if (i) DEBUG_CHAR(','); - DEBUG_DECIMAL(info.home_offset[i]); + DEBUG_ECHO(info.home_offset[i]); } DEBUG_EOL(); #endif - #if HAS_POSITION_SHIFT - DEBUG_ECHOPGM("position_shift: "); + #if HAS_WORKSPACE_OFFSET + DEBUG_ECHOPGM("workspace_offset: "); LOOP_NUM_AXES(i) { if (i) DEBUG_CHAR(','); - DEBUG_DECIMAL(info.position_shift[i]); + DEBUG_ECHO(info.workspace_offset[i]); } DEBUG_EOL(); #endif @@ -680,7 +652,7 @@ void PrintJobRecovery::resume() { #endif // Mixing extruder and gradient - #if BOTH(MIXING_EXTRUDER, GRADIENT_MIX) + #if ALL(MIXING_EXTRUDER, GRADIENT_MIX) DEBUG_ECHOLNPGM("gradient: ", info.gradient.enabled ? "ON" : "OFF"); #endif @@ -699,7 +671,9 @@ void PrintJobRecovery::resume() { DEBUG_ECHOLNPGM("flag.dryrun: ", AS_DIGIT(info.flag.dryrun)); DEBUG_ECHOLNPGM("flag.allow_cold_extrusion: ", AS_DIGIT(info.flag.allow_cold_extrusion)); - DEBUG_ECHOLNPGM("flag.volumetric_enabled: ", AS_DIGIT(info.flag.volumetric_enabled)); + #if DISABLED(NO_VOLUMETRICS) + DEBUG_ECHOLNPGM("flag.volumetric_enabled: ", AS_DIGIT(info.flag.volumetric_enabled)); + #endif } else DEBUG_ECHOLNPGM("INVALID DATA"); diff --git a/Marlin/src/feature/powerloss.h b/Marlin/src/feature/powerloss.h index 4bf0c06e2d..a69862b259 100644 --- a/Marlin/src/feature/powerloss.h +++ b/Marlin/src/feature/powerloss.h @@ -67,8 +67,8 @@ typedef struct { #if HAS_HOME_OFFSET xyz_pos_t home_offset; #endif - #if HAS_POSITION_SHIFT - xyz_pos_t position_shift; + #if HAS_WORKSPACE_OFFSET + xyz_pos_t workspace_offset; #endif #if HAS_MULTI_EXTRUDER uint8_t active_extruder; @@ -113,7 +113,7 @@ typedef struct { millis_t print_job_elapsed; // Relative axis modes - uint8_t axis_relative; + relative_t axis_relative; // Misc. Marlin flags struct { @@ -138,7 +138,7 @@ class PrintJobRecovery { public: static const char filename[5]; - static SdFile file; + static MediaFile file; static job_recovery_info_t info; static uint8_t queue_index_r; //!< Queue index of the active command diff --git a/Marlin/src/feature/probe_temp_comp.cpp b/Marlin/src/feature/probe_temp_comp.cpp index b5f636e698..f640a9fd2f 100644 --- a/Marlin/src/feature/probe_temp_comp.cpp +++ b/Marlin/src/feature/probe_temp_comp.cpp @@ -66,13 +66,13 @@ float ProbeTempComp::init_measurement; // = 0.0 bool ProbeTempComp::enabled = true; void ProbeTempComp::reset() { - TERN_(PTC_PROBE, LOOP_L_N(i, PTC_PROBE_COUNT) z_offsets_probe[i] = z_offsets_probe_default[i]); - TERN_(PTC_BED, LOOP_L_N(i, PTC_BED_COUNT) z_offsets_bed[i] = z_offsets_bed_default[i]); - TERN_(PTC_HOTEND, LOOP_L_N(i, PTC_HOTEND_COUNT) z_offsets_hotend[i] = z_offsets_hotend_default[i]); + TERN_(PTC_PROBE, for (uint8_t i = 0; i < PTC_PROBE_COUNT; ++i) z_offsets_probe[i] = z_offsets_probe_default[i]); + TERN_(PTC_BED, for (uint8_t i = 0; i < PTC_BED_COUNT; ++i) z_offsets_bed[i] = z_offsets_bed_default[i]); + TERN_(PTC_HOTEND, for (uint8_t i = 0; i < PTC_HOTEND_COUNT; ++i) z_offsets_hotend[i] = z_offsets_hotend_default[i]); } void ProbeTempComp::clear_offsets(const TempSensorID tsi) { - LOOP_L_N(i, cali_info[tsi].measurements) + for (uint8_t i = 0; i < cali_info[tsi].measurements; ++i) sensor_z_offsets[tsi][i] = 0; calib_idx = 0; } @@ -84,17 +84,12 @@ bool ProbeTempComp::set_offset(const TempSensorID tsi, const uint8_t idx, const } void ProbeTempComp::print_offsets() { - LOOP_L_N(s, TSI_COUNT) { + for (uint8_t s = 0; s < TSI_COUNT; ++s) { celsius_t temp = cali_info[s].start_temp; for (int16_t i = -1; i < cali_info[s].measurements; ++i) { - SERIAL_ECHOF( - TERN_(PTC_BED, s == TSI_BED ? F("Bed") :) - TERN_(PTC_HOTEND, s == TSI_EXT ? F("Extruder") :) - F("Probe") - ); - SERIAL_ECHOLNPGM( - " temp: ", temp, - "C; Offset: ", i < 0 ? 0.0f : sensor_z_offsets[s][i], " um" + SERIAL_ECHOLN( + TERN_(PTC_BED, s == TSI_BED ? F("Bed") :) TERN_(PTC_HOTEND, s == TSI_EXT ? F("Extruder") :) F("Probe"), + F(" temp: "), temp, F("C; Offset: "), i < 0 ? 0.0f : sensor_z_offsets[s][i], F(" um") ); temp += cali_info[s].temp_resolution; } @@ -232,7 +227,7 @@ bool ProbeTempComp::linear_regression(const TempSensorID tsi, float &k, float &d sum_xy = 0, sum_y = 0; float xi = static_cast(start_temp); - LOOP_L_N(i, calib_idx) { + for (uint8_t i = 0; i < calib_idx; ++i) { const float yi = static_cast(data[i]); xi += res_temp; sum_x += xi; diff --git a/Marlin/src/feature/repeat.cpp b/Marlin/src/feature/repeat.cpp index fed7ac0908..4484dab95b 100644 --- a/Marlin/src/feature/repeat.cpp +++ b/Marlin/src/feature/repeat.cpp @@ -66,7 +66,7 @@ void Repeat::loop() { } } -void Repeat::cancel() { LOOP_L_N(i, index) marker[i].counter = 0; } +void Repeat::cancel() { for (uint8_t i = 0; i < index; ++i) marker[i].counter = 0; } void Repeat::early_parse_M808(char * const cmd) { if (is_command_M808(cmd)) { diff --git a/Marlin/src/feature/repeat.h b/Marlin/src/feature/repeat.h index fc11e4a9e2..ce309f6470 100644 --- a/Marlin/src/feature/repeat.h +++ b/Marlin/src/feature/repeat.h @@ -40,7 +40,7 @@ private: public: static void reset() { index = 0; } static bool is_active() { - LOOP_L_N(i, index) if (marker[i].counter) return true; + for (uint8_t i = 0; i < index; ++i) if (marker[i].counter) return true; return false; } static bool is_command_M808(char * const cmd) { return cmd[0] == 'M' && cmd[1] == '8' && cmd[2] == '0' && cmd[3] == '8' && !NUMERIC(cmd[4]); } @@ -48,6 +48,9 @@ public: static void add_marker(const uint32_t sdpos, const uint16_t count); static void loop(); static void cancel(); + static uint8_t count() { return index; } + static int16_t get_marker_counter(const uint8_t i) { return marker[i].counter; } + static uint32_t get_marker_sdpos(const uint8_t i) { return marker[i].sdpos; } }; extern Repeat repeat; diff --git a/Marlin/src/feature/runout.cpp b/Marlin/src/feature/runout.cpp index 98b6bd0510..1d684c6b85 100644 --- a/Marlin/src/feature/runout.cpp +++ b/Marlin/src/feature/runout.cpp @@ -47,7 +47,7 @@ bool FilamentMonitorBase::enabled = true, #if HAS_FILAMENT_RUNOUT_DISTANCE float RunoutResponseDelayed::runout_distance_mm = FILAMENT_RUNOUT_DISTANCE_MM; - volatile float RunoutResponseDelayed::runout_mm_countdown[NUM_RUNOUT_SENSORS]; + countdown_t RunoutResponseDelayed::mm_countdown; #if ENABLED(FILAMENT_MOTION_SENSOR) uint8_t FilamentSensorEncoder::motion_detected; #endif @@ -88,7 +88,7 @@ void event_filament_runout(const uint8_t extruder) { #endif TERN_(EXTENSIBLE_UI, ExtUI::onFilamentRunout(ExtUI::getTool(extruder))); - TERN_(DWIN_LCD_PROUI, DWIN_FilamentRunout(extruder)); + TERN_(DWIN_LCD_PROUI, dwinFilamentRunout(extruder)); #if ANY(HOST_PROMPT_SUPPORT, HOST_ACTION_COMMANDS, MULTI_FILAMENT_SENSOR) const char tool = '0' + TERN0(MULTI_FILAMENT_SENSOR, extruder); @@ -102,12 +102,16 @@ void event_filament_runout(const uint8_t extruder) { const bool run_runout_script = !runout.host_handling; #if ENABLED(HOST_ACTION_COMMANDS) - if (run_runout_script - && ( strstr(FILAMENT_RUNOUT_SCRIPT, "M600") + + const bool park_or_pause = (false + #ifdef FILAMENT_RUNOUT_SCRIPT + || strstr(FILAMENT_RUNOUT_SCRIPT, "M600") || strstr(FILAMENT_RUNOUT_SCRIPT, "M125") || TERN0(ADVANCED_PAUSE_FEATURE, strstr(FILAMENT_RUNOUT_SCRIPT, "M25")) - ) - ) { + #endif + ); + + if (run_runout_script && park_or_pause) { hostui.paused(false); } else { @@ -124,24 +128,27 @@ void event_filament_runout(const uint8_t extruder) { SERIAL_ECHOPGM(" " ACTION_REASON_ON_FILAMENT_RUNOUT " "); SERIAL_CHAR(tool); SERIAL_EOL(); + #endif // HOST_ACTION_COMMANDS - if (run_runout_script) { - #if MULTI_FILAMENT_SENSOR - char script[strlen(FILAMENT_RUNOUT_SCRIPT) + 1]; - sprintf_P(script, PSTR(FILAMENT_RUNOUT_SCRIPT), tool); - #if ENABLED(FILAMENT_RUNOUT_SENSOR_DEBUG) - SERIAL_ECHOLNPGM("Runout Command: ", script); + #ifdef FILAMENT_RUNOUT_SCRIPT + if (run_runout_script) { + #if MULTI_FILAMENT_SENSOR + MString script; + script.setf(F(FILAMENT_RUNOUT_SCRIPT), C(tool)); + #if ENABLED(FILAMENT_RUNOUT_SENSOR_DEBUG) + SERIAL_ECHOLNPGM("Runout Command: ", &script); + #endif + queue.inject(&script); + #else + #if ENABLED(FILAMENT_RUNOUT_SENSOR_DEBUG) + SERIAL_ECHOPGM("Runout Command: "); + SERIAL_ECHOLNPGM(FILAMENT_RUNOUT_SCRIPT); + #endif + queue.inject(F(FILAMENT_RUNOUT_SCRIPT)); #endif - queue.inject(script); - #else - #if ENABLED(FILAMENT_RUNOUT_SENSOR_DEBUG) - SERIAL_ECHOPGM("Runout Command: "); - SERIAL_ECHOLNPGM(FILAMENT_RUNOUT_SCRIPT); - #endif - queue.inject(F(FILAMENT_RUNOUT_SCRIPT)); - #endif - } + } + #endif } #endif // HAS_FILAMENT_SENSOR diff --git a/Marlin/src/feature/runout.h b/Marlin/src/feature/runout.h index e74d857a79..43c034020a 100644 --- a/Marlin/src/feature/runout.h +++ b/Marlin/src/feature/runout.h @@ -30,7 +30,8 @@ #include "../module/planner.h" #include "../module/stepper.h" // for block_t #include "../gcode/queue.h" -#include "../feature/pause.h" +#include "../feature/pause.h" // for did_pause_print +#include "../MarlinCore.h" // for printingIsActive() #include "../inc/MarlinConfig.h" @@ -43,12 +44,27 @@ #define FILAMENT_RUNOUT_THRESHOLD 5 #endif +#if ENABLED(FILAMENT_MOTION_SENSOR) + #define HAS_FILAMENT_MOTION 1 +#endif +#if DISABLED(FILAMENT_MOTION_SENSOR) || ENABLED(FILAMENT_SWITCH_AND_MOTION) + #define HAS_FILAMENT_SWITCH 1 +#endif + +typedef Flags< + #if NUM_MOTION_SENSORS > NUM_RUNOUT_SENSORS + NUM_MOTION_SENSORS + #else + NUM_RUNOUT_SENSORS + #endif + > runout_flags_t; + void event_filament_runout(const uint8_t extruder); +inline bool should_monitor_runout() { return did_pause_print || printingIsActive(); } template class TFilamentMonitor; -class FilamentSensorEncoder; -class FilamentSensorSwitch; +class FilamentSensor; class RunoutResponseDelayed; class RunoutResponseDebounced; @@ -56,7 +72,7 @@ class RunoutResponseDebounced; typedef TFilamentMonitor< TERN(HAS_FILAMENT_RUNOUT_DISTANCE, RunoutResponseDelayed, RunoutResponseDebounced), - TERN(FILAMENT_MOTION_SENSOR, FilamentSensorEncoder, FilamentSensorSwitch) + FilamentSensor > FilamentMonitor; extern FilamentMonitor runout; @@ -98,6 +114,11 @@ class TFilamentMonitor : public FilamentMonitorBase { static void filament_present(const uint8_t extruder) { response.filament_present(extruder); } + #if ENABLED(FILAMENT_SWITCH_AND_MOTION) + static void filament_motion_present(const uint8_t extruder) { + response.filament_motion_present(extruder); + } + #endif #if HAS_FILAMENT_RUNOUT_DISTANCE static float& runout_distance() { return response.runout_distance_mm; } @@ -115,43 +136,33 @@ class TFilamentMonitor : public FilamentMonitorBase { // Give the response a chance to update its counter. static void run() { - if (enabled && !filament_ran_out && (printingIsActive() || did_pause_print)) { + if (enabled && !filament_ran_out && should_monitor_runout()) { TERN_(HAS_FILAMENT_RUNOUT_DISTANCE, cli()); // Prevent RunoutResponseDelayed::block_completed from accumulating here response.run(); sensor.run(); - const uint8_t runout_flags = response.has_run_out(); + const runout_flags_t runout_flags = response.has_run_out(); TERN_(HAS_FILAMENT_RUNOUT_DISTANCE, sei()); #if MULTI_FILAMENT_SENSOR #if ENABLED(WATCH_ALL_RUNOUT_SENSORS) - const bool ran_out = !!runout_flags; // any sensor triggers + const bool ran_out = bool(runout_flags); // any sensor triggers uint8_t extruder = 0; - if (ran_out) { - uint8_t bitmask = runout_flags; - while (!(bitmask & 1)) { - bitmask >>= 1; - extruder++; - } - } + if (ran_out) while (!runout_flags.test(extruder)) extruder++; #else - const bool ran_out = TEST(runout_flags, active_extruder); // suppress non active extruders + const bool ran_out = runout_flags[active_extruder]; // suppress non active extruders uint8_t extruder = active_extruder; #endif #else - const bool ran_out = !!runout_flags; + const bool ran_out = bool(runout_flags); uint8_t extruder = active_extruder; #endif - #if ENABLED(FILAMENT_RUNOUT_SENSOR_DEBUG) - if (runout_flags) { - SERIAL_ECHOPGM("Runout Sensors: "); - LOOP_L_N(i, 8) SERIAL_ECHO('0' + TEST(runout_flags, i)); - SERIAL_ECHOPGM(" -> ", extruder); - if (ran_out) SERIAL_ECHOPGM(" RUN OUT"); - SERIAL_EOL(); - } - #endif - if (ran_out) { + #if ENABLED(FILAMENT_RUNOUT_SENSOR_DEBUG) + SERIAL_ECHOPGM("Runout Sensors: "); + for (uint8_t i = 0; i < 8; ++i) SERIAL_CHAR('0' + char(runout_flags[i])); + SERIAL_ECHOLNPGM(" -> ", extruder, " RUN OUT"); + #endif + filament_ran_out = true; event_filament_runout(extruder); planner.synchronize(); @@ -171,37 +182,25 @@ class FilamentSensorBase { static void filament_present(const uint8_t extruder) { runout.filament_present(extruder); // ...which calls response.filament_present(extruder) } + #if ENABLED(FILAMENT_SWITCH_AND_MOTION) + static void filament_motion_present(const uint8_t extruder) { + runout.filament_motion_present(extruder); // ...which calls response.filament_motion_present(extruder) + } + #endif public: static void setup() { - #define _INIT_RUNOUT_PIN(P,S,U,D) do{ if (ENABLED(U)) SET_INPUT_PULLUP(P); else if (ENABLED(D)) SET_INPUT_PULLDOWN(P); else SET_INPUT(P); }while(0) - #define INIT_RUNOUT_PIN(N) _INIT_RUNOUT_PIN(FIL_RUNOUT##N##_PIN, FIL_RUNOUT##N##_STATE, FIL_RUNOUT##N##_PULLUP, FIL_RUNOUT##N##_PULLDOWN) - #if NUM_RUNOUT_SENSORS >= 1 - INIT_RUNOUT_PIN(1); - #endif - #if NUM_RUNOUT_SENSORS >= 2 - INIT_RUNOUT_PIN(2); - #endif - #if NUM_RUNOUT_SENSORS >= 3 - INIT_RUNOUT_PIN(3); - #endif - #if NUM_RUNOUT_SENSORS >= 4 - INIT_RUNOUT_PIN(4); - #endif - #if NUM_RUNOUT_SENSORS >= 5 - INIT_RUNOUT_PIN(5); - #endif - #if NUM_RUNOUT_SENSORS >= 6 - INIT_RUNOUT_PIN(6); - #endif - #if NUM_RUNOUT_SENSORS >= 7 - INIT_RUNOUT_PIN(7); - #endif - #if NUM_RUNOUT_SENSORS >= 8 - INIT_RUNOUT_PIN(8); + #define _INIT_RUNOUT_PIN(P,S,U,D) do{ if (ENABLED(U)) SET_INPUT_PULLUP(P); else if (ENABLED(D)) SET_INPUT_PULLDOWN(P); else SET_INPUT(P); }while(0); + #define INIT_RUNOUT_PIN(N) _INIT_RUNOUT_PIN(FIL_RUNOUT##N##_PIN, FIL_RUNOUT##N##_STATE, FIL_RUNOUT##N##_PULLUP, FIL_RUNOUT##N##_PULLDOWN); + REPEAT_1(NUM_RUNOUT_SENSORS, INIT_RUNOUT_PIN) + #undef INIT_RUNOUT_PIN + + #if ENABLED(FILAMENT_SWITCH_AND_MOTION) + #define INIT_MOTION_PIN(N) _INIT_RUNOUT_PIN(FIL_MOTION##N##_PIN, FIL_MOTION##N##_STATE, FIL_MOTION##N##_PULLUP, FIL_MOTION##N##_PULLDOWN); + REPEAT_1(NUM_MOTION_SENSORS, INIT_MOTION_PIN) + #undef INIT_MOTION_PIN #endif #undef _INIT_RUNOUT_PIN - #undef INIT_RUNOUT_PIN } // Return a bitmask of runout pin states @@ -213,36 +212,29 @@ class FilamentSensorBase { // Return a bitmask of runout flag states (1 bits always indicates runout) static uint8_t poll_runout_states() { - return poll_runout_pins() ^ uint8_t(0 - #if NUM_RUNOUT_SENSORS >= 1 - | (FIL_RUNOUT1_STATE ? 0 : _BV(1 - 1)) - #endif - #if NUM_RUNOUT_SENSORS >= 2 - | (FIL_RUNOUT2_STATE ? 0 : _BV(2 - 1)) - #endif - #if NUM_RUNOUT_SENSORS >= 3 - | (FIL_RUNOUT3_STATE ? 0 : _BV(3 - 1)) - #endif - #if NUM_RUNOUT_SENSORS >= 4 - | (FIL_RUNOUT4_STATE ? 0 : _BV(4 - 1)) - #endif - #if NUM_RUNOUT_SENSORS >= 5 - | (FIL_RUNOUT5_STATE ? 0 : _BV(5 - 1)) - #endif - #if NUM_RUNOUT_SENSORS >= 6 - | (FIL_RUNOUT6_STATE ? 0 : _BV(6 - 1)) - #endif - #if NUM_RUNOUT_SENSORS >= 7 - | (FIL_RUNOUT7_STATE ? 0 : _BV(7 - 1)) - #endif - #if NUM_RUNOUT_SENSORS >= 8 - | (FIL_RUNOUT8_STATE ? 0 : _BV(8 - 1)) - #endif - ); + #define _INVERT_BIT(N) | (FIL_RUNOUT##N##_STATE ? 0 : _BV(N - 1)) + return poll_runout_pins() ^ uint8_t(0 REPEAT_1(NUM_RUNOUT_SENSORS, _INVERT_BIT)); + #undef _INVERT_BIT } + + #if ENABLED(FILAMENT_SWITCH_AND_MOTION) + // Return a bitmask of motion pin states + static uint8_t poll_motion_pins() { + #define _OR_MOTION(N) | (READ(FIL_MOTION##N##_PIN) ? _BV((N) - 1) : 0) + return (0 REPEAT_1(NUM_MOTION_SENSORS, _OR_MOTION)); + #undef _OR_MOTION + } + + // Return a bitmask of motion flag states (1 bits always indicates runout) + static uint8_t poll_motion_states() { + #define _OR_MOTION(N) | (FIL_MOTION##N##_STATE ? 0 : _BV(N - 1)) + return poll_motion_pins() ^ uint8_t(0 REPEAT_1(NUM_MOTION_SENSORS, _OR_MOTION)); + #undef _OR_MOTION + } + #endif }; -#if ENABLED(FILAMENT_MOTION_SENSOR) +#if HAS_FILAMENT_MOTION /** * This sensor uses a magnetic encoder disc and a Hall effect @@ -256,14 +248,14 @@ class FilamentSensorBase { static void poll_motion_sensor() { static uint8_t old_state; - const uint8_t new_state = poll_runout_pins(), + const uint8_t new_state = TERN(FILAMENT_SWITCH_AND_MOTION, poll_motion_pins, poll_runout_pins)(), change = old_state ^ new_state; old_state = new_state; #if ENABLED(FILAMENT_RUNOUT_SENSOR_DEBUG) if (change) { SERIAL_ECHOPGM("Motion detected:"); - LOOP_L_N(e, NUM_RUNOUT_SENSORS) + for (uint8_t e = 0; e < TERN(FILAMENT_SWITCH_AND_MOTION, NUM_MOTION_SENSORS, NUM_RUNOUT_SENSORS); ++e) if (TEST(change, e)) SERIAL_CHAR(' ', '0' + e); SERIAL_EOL(); } @@ -277,7 +269,7 @@ class FilamentSensorBase { // If the sensor wheel has moved since the last call to // this method reset the runout counter for the extruder. if (TEST(motion_detected, b->extruder)) - filament_present(b->extruder); + TERN(FILAMENT_SWITCH_AND_MOTION, filament_motion_present, filament_present)(b->extruder); // Clear motion triggers for next block motion_detected = 0; @@ -286,7 +278,9 @@ class FilamentSensorBase { static void run() { poll_motion_sensor(); } }; -#else +#endif // HAS_FILAMENT_MOTION + +#if HAS_FILAMENT_SWITCH /** * This is a simple endstop switch in the path of the filament. @@ -310,39 +304,72 @@ class FilamentSensorBase { static void block_completed(const block_t * const) {} static void run() { - LOOP_L_N(s, NUM_RUNOUT_SENSORS) { + for (uint8_t s = 0; s < NUM_RUNOUT_SENSORS; ++s) { const bool out = poll_runout_state(s); if (!out) filament_present(s); #if ENABLED(FILAMENT_RUNOUT_SENSOR_DEBUG) static uint8_t was_out; // = 0 if (out != TEST(was_out, s)) { TBI(was_out, s); - SERIAL_ECHOLNF(F("Filament Sensor "), AS_DIGIT(s), out ? F(" OUT") : F(" IN")); + SERIAL_ECHOLN(F("Filament Sensor "), AS_DIGIT(s), out ? F(" OUT") : F(" IN")); } #endif } } }; + #endif // HAS_FILAMENT_SWITCH + + /** + * This is a simple endstop switch in the path of the filament. + * It can detect filament runout, but not stripouts or jams. + */ + class FilamentSensor : public FilamentSensorBase { + private: + TERN_(HAS_FILAMENT_MOTION, static FilamentSensorEncoder encoder_sensor); + TERN_(HAS_FILAMENT_SWITCH, static FilamentSensorSwitch switch_sensor); + + public: + static void block_completed(const block_t * const b) { + TERN_(HAS_FILAMENT_MOTION, encoder_sensor.block_completed(b)); + TERN_(HAS_FILAMENT_SWITCH, switch_sensor.block_completed(b)); + } + + static void run() { + TERN_(HAS_FILAMENT_MOTION, encoder_sensor.run()); + TERN_(HAS_FILAMENT_SWITCH, switch_sensor.run()); + } + }; -#endif // !FILAMENT_MOTION_SENSOR /********************************* RESPONSE TYPE *********************************/ #if HAS_FILAMENT_RUNOUT_DISTANCE + typedef struct { + float runout[NUM_RUNOUT_SENSORS]; + Flags runout_reset; // Reset runout later + #if ENABLED(FILAMENT_SWITCH_AND_MOTION) + float motion[NUM_MOTION_SENSORS]; + Flags motion_reset; // Reset motion later + #endif + } countdown_t; + // RunoutResponseDelayed triggers a runout event only if the length // of filament specified by FILAMENT_RUNOUT_DISTANCE_MM has been fed // during a runout condition. class RunoutResponseDelayed { private: - static volatile float runout_mm_countdown[NUM_RUNOUT_SENSORS]; + static countdown_t mm_countdown; public: static float runout_distance_mm; static void reset() { - LOOP_L_N(i, NUM_RUNOUT_SENSORS) filament_present(i); + for (uint8_t i = 0; i < NUM_RUNOUT_SENSORS; ++i) filament_present(i); + #if ENABLED(FILAMENT_SWITCH_AND_MOTION) + for (uint8_t i = 0; i < NUM_MOTION_SENSORS; ++i) filament_motion_present(i); + #endif } static void run() { @@ -351,30 +378,77 @@ class FilamentSensorBase { const millis_t ms = millis(); if (ELAPSED(ms, t)) { t = millis() + 1000UL; - LOOP_L_N(i, NUM_RUNOUT_SENSORS) - SERIAL_ECHOF(i ? F(", ") : F("Remaining mm: "), runout_mm_countdown[i]); + for (uint8_t i = 0; i < NUM_RUNOUT_SENSORS; ++i) + SERIAL_ECHO(i ? F(", ") : F("Runout remaining mm: "), mm_countdown.runout[i]); + #if ENABLED(FILAMENT_SWITCH_AND_MOTION) + for (uint8_t i = 0; i < NUM_MOTION_SENSORS; ++i) + SERIAL_ECHO(i ? F(", ") : F("Motion remaining mm: "), mm_countdown.motion[i]); + #endif SERIAL_EOL(); } #endif } - static uint8_t has_run_out() { - uint8_t runout_flags = 0; - LOOP_L_N(i, NUM_RUNOUT_SENSORS) if (runout_mm_countdown[i] < 0) SBI(runout_flags, i); + static runout_flags_t has_run_out() { + runout_flags_t runout_flags{0}; + for (uint8_t i = 0; i < NUM_RUNOUT_SENSORS; ++i) if (mm_countdown.runout[i] < 0) runout_flags.set(i); + #if ENABLED(FILAMENT_SWITCH_AND_MOTION) + for (uint8_t i = 0; i < NUM_MOTION_SENSORS; ++i) if (mm_countdown.motion[i] < 0) runout_flags.set(i); + #endif return runout_flags; } static void filament_present(const uint8_t extruder) { - runout_mm_countdown[extruder] = runout_distance_mm; + if (mm_countdown.runout[extruder] < runout_distance_mm || did_pause_print) { + // Reset runout only if it is smaller than runout_distance or printing is paused. + // On Bowden systems retract may be larger than runout_distance_mm, so if retract + // was added leave it in place, or the following unretract will cause runout event. + mm_countdown.runout[extruder] = runout_distance_mm; + mm_countdown.runout_reset.clear(extruder); + } + else { + // If runout is larger than runout distance, we cannot reset right now, as Bowden and retract + // distance larger than runout_distance_mm leads to negative runout right after unretract. + // But we cannot ignore filament_present event. After unretract, runout will become smaller + // than runout_distance_mm and should be reset after that. So activate delayed reset. + mm_countdown.runout_reset.set(extruder); + } } - static void block_completed(const block_t * const b) { - if (b->steps.x || b->steps.y || b->steps.z || did_pause_print) { // Allow pause purge move to re-trigger runout state - // Only trigger on extrusion with XYZ movement to allow filament change and retract/recover. - const uint8_t e = b->extruder; - const int32_t steps = b->steps.e; - runout_mm_countdown[e] -= (TEST(b->direction_bits, E_AXIS) ? -steps : steps) * planner.mm_per_step[E_AXIS_N(e)]; + #if ENABLED(FILAMENT_SWITCH_AND_MOTION) + static void filament_motion_present(const uint8_t extruder) { + // Same logic as filament_present + if (mm_countdown.motion[extruder] < runout_distance_mm || did_pause_print) { + mm_countdown.motion[extruder] = runout_distance_mm; + mm_countdown.motion_reset.clear(extruder); + } + else + mm_countdown.motion_reset.set(extruder); } + #endif + + static void block_completed(const block_t * const b) { + const int32_t esteps = b->steps.e; + if (!esteps) return; + + // No calculation unless paused or printing + if (!should_monitor_runout()) return; + + // No need to ignore retract/unretract movement since they complement each other + const uint8_t e = b->extruder; + const float mm = (b->direction_bits.e ? esteps : -esteps) * planner.mm_per_step[E_AXIS_N(e)]; + + if (e < NUM_RUNOUT_SENSORS) { + mm_countdown.runout[e] -= mm; + if (mm_countdown.runout_reset[e]) filament_present(e); // Reset pending. Try to reset. + } + + #if ENABLED(FILAMENT_SWITCH_AND_MOTION) + if (e < NUM_MOTION_SENSORS) { + mm_countdown.motion[e] -= mm; + if (mm_countdown.motion_reset[e]) filament_motion_present(e); // Reset pending. Try to reset. + } + #endif } }; @@ -390,16 +464,16 @@ class FilamentSensorBase { public: static void reset() { - LOOP_L_N(i, NUM_RUNOUT_SENSORS) filament_present(i); + for (uint8_t i = 0; i < NUM_RUNOUT_SENSORS; ++i) filament_present(i); } static void run() { - LOOP_L_N(i, NUM_RUNOUT_SENSORS) if (runout_count[i] >= 0) runout_count[i]--; + for (uint8_t i = 0; i < NUM_RUNOUT_SENSORS; ++i) if (runout_count[i] >= 0) runout_count[i]--; } - static uint8_t has_run_out() { - uint8_t runout_flags = 0; - LOOP_L_N(i, NUM_RUNOUT_SENSORS) if (runout_count[i] < 0) SBI(runout_flags, i); + static runout_flags_t has_run_out() { + runout_flags_t runout_flags{0}; + for (uint8_t i = 0; i < NUM_RUNOUT_SENSORS; ++i) if (runout_count[i] < 0) runout_flags.set(i); return runout_flags; } diff --git a/Marlin/src/feature/solenoid.cpp b/Marlin/src/feature/solenoid.cpp index 861e44ed05..46364eaf8f 100644 --- a/Marlin/src/feature/solenoid.cpp +++ b/Marlin/src/feature/solenoid.cpp @@ -22,7 +22,7 @@ #include "../inc/MarlinConfig.h" -#if EITHER(EXT_SOLENOID, MANUAL_SOLENOID_CONTROL) +#if ANY(EXT_SOLENOID, MANUAL_SOLENOID_CONTROL) #include "solenoid.h" diff --git a/Marlin/src/feature/spindle_laser.cpp b/Marlin/src/feature/spindle_laser.cpp index e7898268e8..c0635c7220 100644 --- a/Marlin/src/feature/spindle_laser.cpp +++ b/Marlin/src/feature/spindle_laser.cpp @@ -141,7 +141,7 @@ void SpindleLaser::apply_power(const uint8_t opwr) { else ocr_off(); #elif ENABLED(SPINDLE_SERVO) - MOVE_SERVO(SPINDLE_SERVO_NR, power); + servo[SPINDLE_SERVO_NR].move(opwr); #else WRITE(SPINDLE_LASER_ENA_PIN, enabled() ? SPINDLE_LASER_ACTIVE_STATE : !SPINDLE_LASER_ACTIVE_STATE); isReadyForUI = true; diff --git a/Marlin/src/feature/spindle_laser.h b/Marlin/src/feature/spindle_laser.h index 0a99585bc0..8908ae6df5 100644 --- a/Marlin/src/feature/spindle_laser.h +++ b/Marlin/src/feature/spindle_laser.h @@ -30,9 +30,7 @@ #include "spindle_laser_types.h" -#if HAS_BEEPER - #include "../libs/buzzer.h" -#endif +#include "../libs/buzzer.h" // Inline laser power #include "../module/planner.h" @@ -203,8 +201,6 @@ public: apply_power(enable ? TERN(SPINDLE_LASER_USE_PWM, (power ?: (unitPower ? upower_to_ocr(cpwr_to_upwr(SPEED_POWER_STARTUP)) : 0)), 255) : 0); break; case CUTTER_MODE_CONTINUOUS: - TERN_(LASER_FEATURE, set_inline_enabled(enable)); - break; case CUTTER_MODE_DYNAMIC: TERN_(LASER_FEATURE, set_inline_enabled(enable)); break; @@ -212,7 +208,7 @@ public: enable = false; apply_power(0); } - #if SPINDLE_LASER_ENA_PIN + #if PIN_EXISTS(SPINDLE_LASER_ENA) WRITE(SPINDLE_LASER_ENA_PIN, enable ? SPINDLE_LASER_ACTIVE_STATE : !SPINDLE_LASER_ACTIVE_STATE); #endif enable_state = enable; @@ -283,7 +279,7 @@ public: set_enabled(state); if (state) { if (!menuPower) menuPower = cpwr_to_upwr(SPEED_POWER_STARTUP); - power = upower_to_ocr(menuPower); + power = TERN(SPINDLE_LASER_USE_PWM, upower_to_ocr(menuPower), 255); apply_power(power); } else apply_power(0); diff --git a/Marlin/src/feature/spindle_laser_types.h b/Marlin/src/feature/spindle_laser_types.h index 2f36a68a1a..4e5e4d06f6 100644 --- a/Marlin/src/feature/spindle_laser_types.h +++ b/Marlin/src/feature/spindle_laser_types.h @@ -57,7 +57,7 @@ #endif #endif -typedef IF<(SPEED_POWER_MAX > 255), uint16_t, uint8_t>::type cutter_cpower_t; +typedef uvalue_t(SPEED_POWER_MAX) cutter_cpower_t; #if CUTTER_UNIT_IS(RPM) && SPEED_POWER_MAX > 255 typedef uint16_t cutter_power_t; diff --git a/Marlin/src/feature/stepper_driver_safety.cpp b/Marlin/src/feature/stepper_driver_safety.cpp index b8762da9b0..acdd695909 100644 --- a/Marlin/src/feature/stepper_driver_safety.cpp +++ b/Marlin/src/feature/stepper_driver_safety.cpp @@ -30,8 +30,7 @@ static uint32_t axis_plug_backward = 0; void stepper_driver_backward_error(FSTR_P const fstr) { SERIAL_ERROR_START(); - SERIAL_ECHOF(fstr); - SERIAL_ECHOLNPGM(" driver is backward!"); + SERIAL_ECHOLN(fstr, F(" driver is backward!")); ui.status_printf(2, F(S_FMT S_FMT), FTOP(fstr), GET_TEXT(MSG_DRIVER_BACKWARD)); } @@ -43,7 +42,7 @@ void stepper_driver_backward_check() { SET_INPUT(AXIS##_ENABLE_PIN); \ OUT_WRITE(AXIS##_STEP_PIN, false); \ delay(20); \ - if (READ(AXIS##_ENABLE_PIN) == false) { \ + if (READ(AXIS##_ENABLE_PIN) == LOW) { \ SBI(axis_plug_backward, BIT); \ stepper_driver_backward_error(F(STRINGIFY(AXIS))); \ } \ diff --git a/Marlin/src/feature/tmc_util.cpp b/Marlin/src/feature/tmc_util.cpp index 0867686363..bff6872e4d 100644 --- a/Marlin/src/feature/tmc_util.cpp +++ b/Marlin/src/feature/tmc_util.cpp @@ -213,47 +213,46 @@ template void report_driver_otpw(TMC &st) { - char timestamp[14]; + MString<13> timestamp; duration_t elapsed = print_job_timer.duration(); const bool has_days = (elapsed.value > 60*60*24L); - (void)elapsed.toDigital(timestamp, has_days); - SERIAL_EOL(); - SERIAL_ECHO(timestamp); - SERIAL_ECHOPGM(": "); + (void)elapsed.toDigital(×tamp, has_days); + TSS('\n', timestamp, F(": ")).echo(); st.printLabel(); - SERIAL_ECHOLNPGM(" driver overtemperature warning! (", st.getMilliamps(), "mA)"); + SString<50>(F(" driver overtemperature warning! ("), st.getMilliamps(), F("mA)")).echoln(); } template void report_polled_driver_data(TMC &st, const TMC_driver_data &data) { const uint32_t pwm_scale = get_pwm_scale(st); st.printLabel(); - SERIAL_CHAR(':'); SERIAL_ECHO(pwm_scale); + SString<60> report(':', pwm_scale); #if ENABLED(TMC_DEBUG) #if HAS_TMCX1X0 || HAS_TMC220x - SERIAL_CHAR('/'); SERIAL_ECHO(data.cs_actual); + report.append('/', data.cs_actual); #endif #if HAS_STALLGUARD - SERIAL_CHAR('/'); + report += '/'; if (data.sg_result_reasonable) - SERIAL_ECHO(data.sg_result); + report += data.sg_result; else - SERIAL_CHAR('-'); + report += '-'; #endif #endif - SERIAL_CHAR('|'); - if (st.error_count) SERIAL_CHAR('E'); // Error - if (data.is_ot) SERIAL_CHAR('O'); // Over-temperature - if (data.is_otpw) SERIAL_CHAR('W'); // over-temperature pre-Warning + report += '|'; + if (st.error_count) report += 'E'; // Error + if (data.is_ot) report += 'O'; // Over-temperature + if (data.is_otpw) report += 'W'; // over-temperature pre-Warning #if ENABLED(TMC_DEBUG) - if (data.is_stall) SERIAL_CHAR('G'); // stallGuard - if (data.is_stealth) SERIAL_CHAR('T'); // stealthChop - if (data.is_standstill) SERIAL_CHAR('I'); // standstIll + if (data.is_stall) report += 'G'; // stallGuard + if (data.is_stealth) report += 'T'; // stealthChop + if (data.is_standstill) report += 'I'; // standstIll #endif - if (st.flag_otpw) SERIAL_CHAR('F'); // otpw Flag - SERIAL_CHAR('|'); - if (st.otpw_count > 0) SERIAL_ECHO(st.otpw_count); - SERIAL_CHAR('\t'); + if (st.flag_otpw) report += 'F'; // otpw Flag + report += '|'; + if (st.otpw_count > 0) report += st.otpw_count; + report += '\t'; + report.echo(); } #if CURRENT_STEP_DOWN > 0 @@ -562,7 +561,7 @@ }; template - static void print_vsense(TMC &st) { SERIAL_ECHOF(st.vsense() ? F("1=.18") : F("0=.325")); } + static void print_vsense(TMC &st) { SERIAL_ECHO(st.vsense() ? F("1=.18") : F("0=.325")); } #if HAS_DRIVER(TMC2130) || HAS_DRIVER(TMC5130) static void _tmc_status(TMC2130Stepper &st, const TMC_debug_enum i) { @@ -601,8 +600,8 @@ case TMC_STEALTHCHOP: serialprint_truefalse(st.en_pwm_mode()); break; case TMC_GLOBAL_SCALER: { - uint16_t value = st.GLOBAL_SCALER(); - SERIAL_ECHO(value ? value : 256); + const uint16_t value = st.GLOBAL_SCALER(); + SERIAL_ECHO(value ?: 256); SERIAL_ECHOPGM("/256"); } break; @@ -680,7 +679,7 @@ case TMC_ENABLED: serialprint_truefalse(st.isEnabled()); break; case TMC_CURRENT: SERIAL_ECHO(st.getMilliamps()); break; case TMC_RMS_CURRENT: SERIAL_ECHO(st.rms_current()); break; - case TMC_MAX_CURRENT: SERIAL_PRINT((float)st.rms_current() * 1.41, 0); break; + case TMC_MAX_CURRENT: SERIAL_ECHO(p_float_t(st.rms_current() * 1.41, 0)); break; case TMC_IRUN: SERIAL_ECHO(st.irun()); SERIAL_ECHOPGM("/31"); @@ -728,12 +727,12 @@ case TMC_ENABLED: serialprint_truefalse(st.isEnabled()); break; case TMC_CURRENT: SERIAL_ECHO(st.getMilliamps()); break; case TMC_RMS_CURRENT: SERIAL_ECHO(st.rms_current()); break; - case TMC_MAX_CURRENT: SERIAL_PRINT((float)st.rms_current() * 1.41, 0); break; + case TMC_MAX_CURRENT: SERIAL_ECHO(p_float_t(st.rms_current() * 1.41, 0)); break; case TMC_IRUN: SERIAL_ECHO(st.cs()); SERIAL_ECHOPGM("/31"); break; - case TMC_VSENSE: SERIAL_ECHOF(st.vsense() ? F("1=.165") : F("0=.310")); break; + case TMC_VSENSE: SERIAL_ECHO(st.vsense() ? F("1=.165") : F("0=.310")); break; case TMC_MICROSTEPS: SERIAL_ECHO(st.microsteps()); break; //case TMC_OTPW: serialprint_truefalse(st.otpw()); break; //case TMC_OTPW_TRIGGERED: serialprint_truefalse(st.getOTPW()); break; @@ -773,8 +772,8 @@ } } - static void tmc_debug_loop(const TMC_debug_enum n, LOGICAL_AXIS_ARGS(const bool)) { - if (x) { + static void tmc_debug_loop(const TMC_debug_enum n OPTARGS_LOGICAL(const bool)) { + if (TERN0(HAS_X_AXIS, x)) { #if AXIS_IS_TMC(X) tmc_status(stepperX, n); #endif @@ -856,8 +855,8 @@ SERIAL_EOL(); } - static void drv_status_loop(const TMC_drv_status_enum n, LOGICAL_AXIS_ARGS(const bool)) { - if (x) { + static void drv_status_loop(const TMC_drv_status_enum n OPTARGS_LOGICAL(const bool)) { + if (TERN0(HAS_X_AXIS, x)) { #if AXIS_IS_TMC(X) tmc_parse_drv_status(stepperX, n); #endif @@ -944,8 +943,8 @@ */ void tmc_report_all(LOGICAL_AXIS_ARGS(const bool)) { - #define TMC_REPORT(LABEL, ITEM) do{ SERIAL_ECHOPGM(LABEL); tmc_debug_loop(ITEM, LOGICAL_AXIS_ARGS()); }while(0) - #define DRV_REPORT(LABEL, ITEM) do{ SERIAL_ECHOPGM(LABEL); drv_status_loop(ITEM, LOGICAL_AXIS_ARGS()); }while(0) + #define TMC_REPORT(LABEL, ITEM) do{ SERIAL_ECHOPGM(LABEL); tmc_debug_loop(ITEM OPTARGS_LOGICAL()); }while(0) + #define DRV_REPORT(LABEL, ITEM) do{ SERIAL_ECHOPGM(LABEL); drv_status_loop(ITEM OPTARGS_LOGICAL()); }while(0) TMC_REPORT("\t", TMC_CODES); #if HAS_DRIVER(TMC2209) @@ -1070,8 +1069,8 @@ } #endif - static void tmc_get_registers(TMC_get_registers_enum n, LOGICAL_AXIS_ARGS(const bool)) { - if (x) { + static void tmc_get_registers(TMC_get_registers_enum n OPTARGS_LOGICAL(const bool)) { + if (TERN0(HAS_X_AXIS, x)) { #if AXIS_IS_TMC(X) tmc_get_registers(stepperX, n); #endif @@ -1154,7 +1153,7 @@ } void tmc_get_registers(LOGICAL_AXIS_ARGS(bool)) { - #define _TMC_GET_REG(LABEL, ITEM) do{ SERIAL_ECHOPGM(LABEL); tmc_get_registers(ITEM, LOGICAL_AXIS_ARGS()); }while(0) + #define _TMC_GET_REG(LABEL, ITEM) do{ SERIAL_ECHOPGM(LABEL); tmc_get_registers(ITEM OPTARGS_LOGICAL()); }while(0) #define TMC_GET_REG(NAME, TABS) _TMC_GET_REG(STRINGIFY(NAME) TABS, TMC_GET_##NAME) _TMC_GET_REG("\t", TMC_AXIS_CODES); TMC_GET_REG(GCONF, "\t\t"); @@ -1228,7 +1227,7 @@ static bool test_connection(TMC &st) { case 1: stat = F("HIGH"); break; case 2: stat = F("LOW"); break; } - SERIAL_ECHOLNF(stat); + SERIAL_ECHOLN(stat); return test_result; } @@ -1236,7 +1235,7 @@ static bool test_connection(TMC &st) { void test_tmc_connection(LOGICAL_AXIS_ARGS(const bool)) { uint8_t axis_connection = 0; - if (x) { + if (TERN0(HAS_X_AXIS, x)) { #if AXIS_IS_TMC(X) axis_connection += test_connection(stepperX); #endif diff --git a/Marlin/src/feature/tmc_util.h b/Marlin/src/feature/tmc_util.h index c10bab6274..a0a72058aa 100644 --- a/Marlin/src/feature/tmc_util.h +++ b/Marlin/src/feature/tmc_util.h @@ -144,7 +144,7 @@ class TMCMarlin : public TMC, public TMCStorage { #endif #endif - #if HAS_MARLINUI_MENU + #if ANY(HAS_MARLINUI_MENU, DWIN_LCD_PROUI) void refresh_stepper_current() { rms_current(this->val_mA); } #if ENABLED(HYBRID_THRESHOLD) @@ -207,7 +207,7 @@ class TMCMarlin : public TMC220 } #endif - #if HAS_MARLINUI_MENU + #if ANY(HAS_MARLINUI_MENU, DWIN_LCD_PROUI) void refresh_stepper_current() { rms_current(this->val_mA); } #if ENABLED(HYBRID_THRESHOLD) @@ -269,7 +269,7 @@ class TMCMarlin : public TMC220 } #endif - #if HAS_MARLINUI_MENU + #if ANY(HAS_MARLINUI_MENU, DWIN_LCD_PROUI) void refresh_stepper_current() { rms_current(this->val_mA); } #if ENABLED(HYBRID_THRESHOLD) @@ -315,7 +315,7 @@ class TMCMarlin : public TMC266 } #endif - #if HAS_MARLINUI_MENU + #if ANY(HAS_MARLINUI_MENU, DWIN_LCD_PROUI) void refresh_stepper_current() { rms_current(this->val_mA); } #if USE_SENSORLESS @@ -348,7 +348,7 @@ void test_tmc_connection(LOGICAL_AXIS_DECL(const bool, true)); #if USE_SENSORLESS // Track enabled status of stealthChop and only re-enable where applicable - struct sensorless_t { bool NUM_AXIS_ARGS(), x2, y2, z2, z3, z4; }; + struct sensorless_t { bool NUM_AXIS_ARGS_() x2, y2, z2, z3, z4; }; #if ENABLED(IMPROVE_HOMING_RELIABILITY) extern millis_t sg_guard_period; @@ -378,6 +378,7 @@ void test_tmc_connection(LOGICAL_AXIS_DECL(const bool, true)); return drv_status.stallGuard; } + #endif // SPI_ENDSTOPS #endif // USE_SENSORLESS diff --git a/Marlin/src/feature/tramming.cpp b/Marlin/src/feature/tramming.cpp index d03f0cf53b..3721c5eb81 100644 --- a/Marlin/src/feature/tramming.cpp +++ b/Marlin/src/feature/tramming.cpp @@ -29,31 +29,11 @@ #define DEBUG_OUT ENABLED(DEBUG_LEVELING_FEATURE) #include "../core/debug_out.h" -PGMSTR(point_name_1, TRAMMING_POINT_NAME_1); -PGMSTR(point_name_2, TRAMMING_POINT_NAME_2); -PGMSTR(point_name_3, TRAMMING_POINT_NAME_3); -#ifdef TRAMMING_POINT_NAME_4 - PGMSTR(point_name_4, TRAMMING_POINT_NAME_4); - #ifdef TRAMMING_POINT_NAME_5 - PGMSTR(point_name_5, TRAMMING_POINT_NAME_5); - #ifdef TRAMMING_POINT_NAME_6 - PGMSTR(point_name_6, TRAMMING_POINT_NAME_6); - #endif - #endif -#endif +#define _TRAM_NAME_DEF(N) PGMSTR(point_name_##N, TRAMMING_POINT_NAME_##N); +#define _TRAM_NAME_ITEM(N) point_name_##N +REPEAT_1(_NR_TRAM_NAMES, _TRAM_NAME_DEF) -PGM_P const tramming_point_name[] PROGMEM = { - point_name_1, point_name_2, point_name_3 - #ifdef TRAMMING_POINT_NAME_4 - , point_name_4 - #ifdef TRAMMING_POINT_NAME_5 - , point_name_5 - #ifdef TRAMMING_POINT_NAME_6 - , point_name_6 - #endif - #endif - #endif -}; +PGM_P const tramming_point_name[] PROGMEM = { REPLIST_1(_NR_TRAM_NAMES, _TRAM_NAME_ITEM) }; #ifdef ASSISTED_TRAMMING_WAIT_POSITION diff --git a/Marlin/src/feature/tramming.h b/Marlin/src/feature/tramming.h index 925659e29d..c8f20f0010 100644 --- a/Marlin/src/feature/tramming.h +++ b/Marlin/src/feature/tramming.h @@ -31,43 +31,34 @@ constexpr xy_pos_t tramming_points[] = TRAMMING_POINT_XY; #define G35_PROBE_COUNT COUNT(tramming_points) -static_assert(WITHIN(G35_PROBE_COUNT, 3, 6), "TRAMMING_POINT_XY requires between 3 and 6 XY positions."); +static_assert(WITHIN(G35_PROBE_COUNT, 3, 9), "TRAMMING_POINT_XY requires between 3 and 9 XY positions."); -#define VALIDATE_TRAMMING_POINT(N) static_assert(N >= G35_PROBE_COUNT || Probe::build_time::can_reach(tramming_points[N]), \ - "TRAMMING_POINT_XY point " STRINGIFY(N) " is not reachable with the default NOZZLE_TO_PROBE offset and PROBING_MARGIN.") -VALIDATE_TRAMMING_POINT(0); VALIDATE_TRAMMING_POINT(1); VALIDATE_TRAMMING_POINT(2); VALIDATE_TRAMMING_POINT(3); VALIDATE_TRAMMING_POINT(4); VALIDATE_TRAMMING_POINT(5); - -extern const char point_name_1[], point_name_2[], point_name_3[] - #ifdef TRAMMING_POINT_NAME_4 - , point_name_4[] - #ifdef TRAMMING_POINT_NAME_5 - , point_name_5[] - #ifdef TRAMMING_POINT_NAME_6 - , point_name_6[] - #endif - #endif - #endif -; - -#define _NR_TRAM_NAMES 2 -#ifdef TRAMMING_POINT_NAME_3 - #undef _NR_TRAM_NAMES +#ifdef TRAMMING_POINT_NAME_9 + #define _NR_TRAM_NAMES 9 +#elif defined(TRAMMING_POINT_NAME_8) + #define _NR_TRAM_NAMES 8 +#elif defined(TRAMMING_POINT_NAME_7) + #define _NR_TRAM_NAMES 7 +#elif defined(TRAMMING_POINT_NAME_6) + #define _NR_TRAM_NAMES 6 +#elif defined(TRAMMING_POINT_NAME_5) + #define _NR_TRAM_NAMES 5 +#elif defined(TRAMMING_POINT_NAME_4) + #define _NR_TRAM_NAMES 4 +#elif defined(TRAMMING_POINT_NAME_3) #define _NR_TRAM_NAMES 3 - #ifdef TRAMMING_POINT_NAME_4 - #undef _NR_TRAM_NAMES - #define _NR_TRAM_NAMES 4 - #ifdef TRAMMING_POINT_NAME_5 - #undef _NR_TRAM_NAMES - #define _NR_TRAM_NAMES 5 - #ifdef TRAMMING_POINT_NAME_6 - #undef _NR_TRAM_NAMES - #define _NR_TRAM_NAMES 6 - #endif - #endif - #endif +#else + #define _NR_TRAM_NAMES 0 #endif + static_assert(_NR_TRAM_NAMES >= G35_PROBE_COUNT, "Define enough TRAMMING_POINT_NAME_s for all TRAMMING_POINT_XY entries."); -#undef _NR_TRAM_NAMES + +#define _TRAM_NAME_PTR(N) point_name_##N[] +extern const char REPLIST_1(_NR_TRAM_NAMES, _TRAM_NAME_PTR); + +#define _CHECK_TRAM_POINT(N) static_assert(Probe::build_time::can_reach(tramming_points[N]), "TRAMMING_POINT_XY point " STRINGIFY(N) " is not reachable with the default NOZZLE_TO_PROBE offset and PROBING_MARGIN."); +REPEAT(_NR_TRAM_NAMES, _CHECK_TRAM_POINT) +#undef _CHECK_TRAM_POINT extern PGM_P const tramming_point_name[]; diff --git a/Marlin/src/feature/twibus.cpp b/Marlin/src/feature/twibus.cpp index 9aec6b0305..5cfe9f9421 100644 --- a/Marlin/src/feature/twibus.cpp +++ b/Marlin/src/feature/twibus.cpp @@ -93,8 +93,7 @@ void TWIBus::send() { // static void TWIBus::echoprefix(uint8_t bytes, FSTR_P const pref, uint8_t adr) { SERIAL_ECHO_START(); - SERIAL_ECHOF(pref); - SERIAL_ECHOPGM(": from:", adr, " bytes:", bytes, " data:"); + SERIAL_ECHO(pref, F(": from:"), adr, F(" bytes:"), bytes, F(" data:")); } // static @@ -145,7 +144,7 @@ void TWIBus::echodata(uint8_t bytes, FSTR_P const pref, uint8_t adr, const uint8 void TWIBus::echobuffer(FSTR_P const prefix, uint8_t adr) { echoprefix(buffer_s, prefix, adr); - LOOP_L_N(i, buffer_s) SERIAL_CHAR(buffer[i]); + for (uint8_t i = 0; i < buffer_s; ++i) SERIAL_CHAR(buffer[i]); SERIAL_EOL(); } diff --git a/Marlin/src/feature/x_twist.cpp b/Marlin/src/feature/x_twist.cpp index b5ad25cba8..b8f7e52ab6 100644 --- a/Marlin/src/feature/x_twist.cpp +++ b/Marlin/src/feature/x_twist.cpp @@ -43,12 +43,12 @@ void XATC::reset() { void XATC::print_points() { SERIAL_ECHOLNPGM(" X-Twist Correction:"); - LOOP_L_N(x, XATC_MAX_POINTS) { + for (uint8_t x = 0; x < XATC_MAX_POINTS; ++x) { SERIAL_CHAR(' '); if (!isnan(z_offset[x])) serial_offset(z_offset[x]); else - LOOP_L_N(i, 6) SERIAL_CHAR(i ? '=' : ' '); + for (uint8_t i = 0; i < 6; ++i) SERIAL_CHAR(i ? '=' : ' '); } SERIAL_EOL(); } diff --git a/Marlin/src/gcode/bedlevel/G26.cpp b/Marlin/src/gcode/bedlevel/G26.cpp index aa6e0c1f0c..30643cb84e 100644 --- a/Marlin/src/gcode/bedlevel/G26.cpp +++ b/Marlin/src/gcode/bedlevel/G26.cpp @@ -162,8 +162,8 @@ float g26_random_deviation = 0.0; */ bool user_canceled() { if (!ui.button_pressed()) return false; // Return if the button isn't pressed - ui.set_status(GET_TEXT_F(MSG_G26_CANCELED), 99); - TERN_(HAS_MARLINUI_MENU, ui.quick_feedback()); + LCD_MESSAGE_MAX(MSG_G26_CANCELED); + ui.quick_feedback(); ui.wait_for_release(); return true; } @@ -321,11 +321,9 @@ typedef struct { #if HAS_HEATED_BED if (bed_temp > 25) { - #if HAS_WIRED_LCD - ui.set_status(GET_TEXT_F(MSG_G26_HEATING_BED), 99); - ui.quick_feedback(); - TERN_(HAS_MARLINUI_MENU, ui.capture()); - #endif + LCD_MESSAGE_MAX(MSG_G26_HEATING_BED); + ui.quick_feedback(); + TERN_(HAS_MARLINUI_MENU, ui.capture()); thermalManager.setTargetBed(bed_temp); // Wait for the temperature to stabilize @@ -340,20 +338,16 @@ typedef struct { #endif // HAS_HEATED_BED // Start heating the active nozzle - #if HAS_WIRED_LCD - ui.set_status(GET_TEXT_F(MSG_G26_HEATING_NOZZLE), 99); - ui.quick_feedback(); - #endif + LCD_MESSAGE_MAX(MSG_G26_HEATING_NOZZLE); + ui.quick_feedback(); thermalManager.setTargetHotend(hotend_temp, active_extruder); // Wait for the temperature to stabilize if (!thermalManager.wait_for_hotend(active_extruder, true OPTARG(G26_CLICK_CAN_CANCEL, true))) return G26_ERR; - #if HAS_WIRED_LCD - ui.reset_status(); - ui.quick_feedback(); - #endif + ui.reset_status(); + ui.completion_feedback(); return G26_OK; } @@ -371,7 +365,7 @@ typedef struct { if (prime_flag == -1) { // The user wants to control how much filament gets purged ui.capture(); - ui.set_status(GET_TEXT_F(MSG_G26_MANUAL_PRIME), 99); + LCD_MESSAGE_MAX(MSG_G26_MANUAL_PRIME); ui.chirp(); destination = current_position; @@ -398,17 +392,15 @@ typedef struct { ui.wait_for_release(); - ui.set_status(GET_TEXT_F(MSG_G26_PRIME_DONE), 99); + LCD_MESSAGE_MAX(MSG_G26_PRIME_DONE); ui.quick_feedback(); ui.release(); } else #endif { - #if HAS_WIRED_LCD - ui.set_status(GET_TEXT_F(MSG_G26_FIXED_LENGTH), 99); - ui.quick_feedback(); - #endif + LCD_MESSAGE_MAX(MSG_G26_FIXED_LENGTH); + ui.quick_feedback(); destination = current_position; destination.e += prime_length; prepare_internal_move_to_destination(fr_slow_e); @@ -636,7 +628,7 @@ void GcodeSuite::G26() { } // Get repeat from 'R', otherwise do one full circuit - int16_t g26_repeats; + grid_count_t g26_repeats; #if HAS_MARLINUI_MENU g26_repeats = parser.intval('R', GRID_MAX_POINTS + 1); #else @@ -715,7 +707,7 @@ void GcodeSuite::G26() { #error "A_CNT must be a positive value. Please change A_INT." #endif float trig_table[A_CNT]; - LOOP_L_N(i, A_CNT) + for (uint8_t i = 0; i < A_CNT; ++i) trig_table[i] = INTERSECTION_CIRCLE_RADIUS * cos(RADIANS(i * A_INT)); #endif // !ARC_SUPPORT @@ -853,7 +845,7 @@ void GcodeSuite::G26() { } while (--g26_repeats && location.valid()); LEAVE: - ui.set_status(GET_TEXT_F(MSG_G26_LEAVING), -1); + LCD_MESSAGE_MIN(MSG_G26_LEAVING); TERN_(EXTENSIBLE_UI, ExtUI::onMeshUpdate(location, ExtUI::G26_FINISH)); g26.retract_filament(destination); diff --git a/Marlin/src/gcode/bedlevel/G35.cpp b/Marlin/src/gcode/bedlevel/G35.cpp index dd828bf0c8..8e11383166 100644 --- a/Marlin/src/gcode/bedlevel/G35.cpp +++ b/Marlin/src/gcode/bedlevel/G35.cpp @@ -59,6 +59,7 @@ * 51 - Counter-Clockwise M5 **/ void GcodeSuite::G35() { + DEBUG_SECTION(log_G35, "G35", DEBUGGING(LEVELING)); if (DEBUGGING(LEVELING)) log_machine_info(); @@ -82,15 +83,9 @@ void GcodeSuite::G35() { set_bed_leveling_enabled(false); #endif - #if ENABLED(CNC_WORKSPACE_PLANES) - workspace_plane = PLANE_XY; - #endif + TERN_(CNC_WORKSPACE_PLANES, workspace_plane = PLANE_XY); - // Always home with tool 0 active - #if HAS_MULTI_HOTEND - const uint8_t old_tool_index = active_extruder; - tool_change(0, true); - #endif + probe.use_probing_tool(); // Disable duplication mode on homing TERN_(HAS_DUPLICATION_MODE, set_duplication_enabled(false)); @@ -101,30 +96,23 @@ void GcodeSuite::G35() { bool err_break = false; // Probe all positions - LOOP_L_N(i, G35_PROBE_COUNT) { - - // In BLTOUCH HS mode, the probe travels in a deployed state. - // Users of G35 might have a badly misaligned bed, so raise Z by the - // length of the deployed pin (BLTOUCH stroke < 7mm) - - // Unsure if this is even required. The probe seems to lift correctly after probe done. - do_blocking_move_to_z(SUM_TERN(BLTOUCH, Z_CLEARANCE_BETWEEN_PROBES, bltouch.z_extra_clearance())); - const float z_probed_height = probe.probe_at_point(tramming_points[i], PROBE_PT_RAISE, 0, true); - + for (uint8_t i = 0; i < G35_PROBE_COUNT; ++i) { + const float z_probed_height = probe.probe_at_point(tramming_points[i], PROBE_PT_RAISE); if (isnan(z_probed_height)) { - SERIAL_ECHOPGM("G35 failed at point ", i + 1, " ("); - SERIAL_ECHOPGM_P((char *)pgm_read_ptr(&tramming_point_name[i])); - SERIAL_CHAR(')'); - SERIAL_ECHOLNPGM_P(SP_X_STR, tramming_points[i].x, SP_Y_STR, tramming_points[i].y); + SERIAL_ECHO( + F("G35 failed at point "), i + 1, F(" ("), FPSTR(pgm_read_ptr(&tramming_point_name[i])), C(')'), + FPSTR(SP_X_STR), tramming_points[i].x, FPSTR(SP_Y_STR), tramming_points[i].y + ); err_break = true; break; } if (DEBUGGING(LEVELING)) { - DEBUG_ECHOPGM("Probing point ", i + 1, " ("); - DEBUG_ECHOF(FPSTR(pgm_read_ptr(&tramming_point_name[i]))); - DEBUG_CHAR(')'); - DEBUG_ECHOLNPGM_P(SP_X_STR, tramming_points[i].x, SP_Y_STR, tramming_points[i].y, SP_Z_STR, z_probed_height); + DEBUG_ECHOLN( + F("Probing point "), i + 1, F(" ("), FPSTR(pgm_read_ptr(&tramming_point_name[i])), C(')'), + FPSTR(SP_X_STR), tramming_points[i].x, FPSTR(SP_Y_STR), tramming_points[i].y, + FPSTR(SP_Z_STR), z_probed_height + ); } z_measured[i] = z_probed_height; @@ -134,7 +122,7 @@ void GcodeSuite::G35() { const float threads_factor[] = { 0.5, 0.7, 0.8 }; // Calculate adjusts - LOOP_S_L_N(i, 1, G35_PROBE_COUNT) { + for (uint8_t i = 1; i < G35_PROBE_COUNT; ++i) { const float diff = z_measured[0] - z_measured[i], adjust = ABS(diff) < 0.001f ? 0 : diff / threads_factor[(screw_thread - 30) / 10]; @@ -154,11 +142,9 @@ void GcodeSuite::G35() { SERIAL_ECHOLNPGM("G35 aborted."); // Restore the active tool after homing - #if HAS_MULTI_HOTEND - if (old_tool_index != 0) tool_change(old_tool_index, DISABLED(PARKING_EXTRUDER)); // Fetch previous toolhead if not PARKING_EXTRUDER - #endif + probe.use_probing_tool(false); - #if BOTH(HAS_LEVELING, RESTORE_LEVELING_AFTER_G35) + #if ALL(HAS_LEVELING, RESTORE_LEVELING_AFTER_G35) set_bed_leveling_enabled(leveling_was_active); #endif diff --git a/Marlin/src/gcode/bedlevel/M420.cpp b/Marlin/src/gcode/bedlevel/M420.cpp index 277f95b9ff..d870a4f430 100644 --- a/Marlin/src/gcode/bedlevel/M420.cpp +++ b/Marlin/src/gcode/bedlevel/M420.cpp @@ -248,7 +248,7 @@ void GcodeSuite::M420_report(const bool forReplay/*=true*/) { report_heading_etc(forReplay, F( TERN(MESH_BED_LEVELING, "Mesh Bed Leveling", TERN(AUTO_BED_LEVELING_UBL, "Unified Bed Leveling", "Auto Bed Leveling")) )); - SERIAL_ECHOF( + SERIAL_ECHO( F(" M420 S"), planner.leveling_active #if ENABLED(ENABLE_LEVELING_FADE_HEIGHT) , FPSTR(SP_Z_STR), LINEAR_UNIT(planner.z_fade_height) diff --git a/Marlin/src/gcode/bedlevel/abl/G29.cpp b/Marlin/src/gcode/bedlevel/abl/G29.cpp index 0fef5ad683..acd920c729 100644 --- a/Marlin/src/gcode/bedlevel/abl/G29.cpp +++ b/Marlin/src/gcode/bedlevel/abl/G29.cpp @@ -42,6 +42,9 @@ #if ABL_PLANAR #include "../../../libs/vector_3.h" #endif +#if ENABLED(BD_SENSOR_PROBE_NO_STOP) + #include "../../../feature/bedlevel/bdl/bdl.h" +#endif #include "../../../lcd/marlinui.h" #if ENABLED(EXTENSIBLE_UI) @@ -78,7 +81,7 @@ static void pre_g29_return(const bool retry, const bool did) { TERN_(FULL_REPORT_TO_HOST_FEATURE, set_and_report_grblstate(M_IDLE, false)); } if (did) { - TERN_(HAS_DWIN_E3V2_BASIC, DWIN_LevelingDone()); + TERN_(HAS_DWIN_E3V2_BASIC, dwinLevelingDone()); TERN_(EXTENSIBLE_UI, ExtUI::onLevelingDone()); } } @@ -97,20 +100,16 @@ public: bool dryrun, reenable; - #if HAS_MULTI_HOTEND - uint8_t tool_index; - #endif - - #if EITHER(PROBE_MANUALLY, AUTO_BED_LEVELING_LINEAR) + #if ANY(PROBE_MANUALLY, AUTO_BED_LEVELING_LINEAR) int abl_probe_index; #endif #if ENABLED(AUTO_BED_LEVELING_LINEAR) - int abl_points; + grid_count_t abl_points; #elif ENABLED(AUTO_BED_LEVELING_3POINT) - static constexpr int abl_points = 3; + static constexpr grid_count_t abl_points = 3; #elif ABL_USES_GRID - static constexpr int abl_points = GRID_MAX_POINTS; + static constexpr grid_count_t abl_points = GRID_MAX_POINTS; #endif #if ABL_USES_GRID @@ -136,16 +135,16 @@ public: #if ENABLED(AUTO_BED_LEVELING_LINEAR) int indexIntoAB[GRID_MAX_POINTS_X][GRID_MAX_POINTS_Y]; - float eqnAMatrix[(GRID_MAX_POINTS) * 3], // "A" matrix of the linear system of equations - eqnBVector[GRID_MAX_POINTS], // "B" vector of Z points + float eqnAMatrix[GRID_MAX_POINTS * 3], // "A" matrix of the linear system of equations + eqnBVector[GRID_MAX_POINTS], // "B" vector of Z points mean; #endif #endif }; -#if ABL_USES_GRID && EITHER(AUTO_BED_LEVELING_3POINT, AUTO_BED_LEVELING_BILINEAR) +#if ABL_USES_GRID && ANY(AUTO_BED_LEVELING_3POINT, AUTO_BED_LEVELING_BILINEAR) constexpr xy_uint8_t G29_State::grid_points; - constexpr int G29_State::abl_points; + constexpr grid_count_t G29_State::abl_points; #endif /** @@ -226,6 +225,7 @@ public: * There's no extra effect if you have a fixed Z probe. */ G29_TYPE GcodeSuite::G29() { + DEBUG_SECTION(log_G29, "G29", DEBUGGING(LEVELING)); // Leveling state is persistent when done manually with multiple G29 commands @@ -235,7 +235,7 @@ G29_TYPE GcodeSuite::G29() { reset_stepper_timeout(); // Q = Query leveling and G29 state - const bool seenQ = EITHER(DEBUG_LEVELING_FEATURE, PROBE_MANUALLY) && parser.seen_test('Q'); + const bool seenQ = ANY(DEBUG_LEVELING_FEATURE, PROBE_MANUALLY) && parser.seen_test('Q'); // G29 Q is also available if debugging #if ENABLED(DEBUG_LEVELING_FEATURE) @@ -281,12 +281,9 @@ G29_TYPE GcodeSuite::G29() { */ if (!g29_in_progress) { - #if HAS_MULTI_HOTEND - abl.tool_index = active_extruder; - if (active_extruder != 0) tool_change(0, true); - #endif + probe.use_probing_tool(); - #if EITHER(PROBE_MANUALLY, AUTO_BED_LEVELING_LINEAR) + #if ANY(PROBE_MANUALLY, AUTO_BED_LEVELING_LINEAR) abl.abl_probe_index = -1; #endif @@ -409,7 +406,7 @@ G29_TYPE GcodeSuite::G29() { if (!probe.good_bounds(abl.probe_position_lf, abl.probe_position_rb)) { if (DEBUGGING(LEVELING)) { DEBUG_ECHOLNPGM("G29 L", abl.probe_position_lf.x, " R", abl.probe_position_rb.x, - " F", abl.probe_position_lf.y, " B", abl.probe_position_rb.y); + " F", abl.probe_position_lf.y, " B", abl.probe_position_rb.y); } SERIAL_ECHOLNPGM("? (L,R,F,B) out of bounds."); G29_RETURN(false, false); @@ -417,7 +414,7 @@ G29_TYPE GcodeSuite::G29() { // Probe at the points of a lattice grid abl.gridSpacing.set((abl.probe_position_rb.x - abl.probe_position_lf.x) / (abl.grid_points.x - 1), - (abl.probe_position_rb.y - abl.probe_position_lf.y) / (abl.grid_points.y - 1)); + (abl.probe_position_rb.y - abl.probe_position_lf.y) / (abl.grid_points.y - 1)); #endif // ABL_USES_GRID @@ -433,7 +430,7 @@ G29_TYPE GcodeSuite::G29() { if (DEBUGGING(LEVELING)) DEBUG_ECHOLNPGM("> 3-point Leveling"); points[0].z = points[1].z = points[2].z = 0; // Probe at 3 arbitrary points #elif ENABLED(AUTO_BED_LEVELING_BILINEAR) - TERN_(DWIN_LCD_PROUI, DWIN_LevelingStart()); + TERN_(DWIN_LCD_PROUI, dwinLevelingStart()); #endif TERN_(EXTENSIBLE_UI, ExtUI::onLevelingStart()); @@ -443,8 +440,8 @@ G29_TYPE GcodeSuite::G29() { #if ENABLED(PREHEAT_BEFORE_LEVELING) if (!abl.dryrun) probe.preheat_for_probing(LEVELING_NOZZLE_TEMP, - #if BOTH(DWIN_LCD_PROUI, HAS_HEATED_BED) - HMI_data.BedLevT + #if ALL(DWIN_LCD_PROUI, HAS_HEATED_BED) + hmiData.bedLevT #else LEVELING_BED_TEMP #endif @@ -453,9 +450,7 @@ G29_TYPE GcodeSuite::G29() { } // Position bed horizontally and Z probe vertically. - #if defined(SAFE_BED_LEVELING_START_X) || defined(SAFE_BED_LEVELING_START_Y) || defined(SAFE_BED_LEVELING_START_Z) \ - || defined(SAFE_BED_LEVELING_START_I) || defined(SAFE_BED_LEVELING_START_J) || defined(SAFE_BED_LEVELING_START_K) \ - || defined(SAFE_BED_LEVELING_START_U) || defined(SAFE_BED_LEVELING_START_V) || defined(SAFE_BED_LEVELING_START_W) + #if HAS_SAFE_BED_LEVELING xyze_pos_t safe_position = current_position; #ifdef SAFE_BED_LEVELING_START_X safe_position.x = SAFE_BED_LEVELING_START_X; @@ -486,14 +481,14 @@ G29_TYPE GcodeSuite::G29() { #endif do_blocking_move_to(safe_position); - #endif + #endif // HAS_SAFE_BED_LEVELING // Disable auto bed leveling during G29. // Be formal so G29 can be done successively without G28. if (!no_action) set_bed_leveling_enabled(false); // Deploy certain probes before starting probing - #if ENABLED(BLTOUCH) + #if ENABLED(BLTOUCH) || ALL(HAS_Z_SERVO_PROBE, Z_SERVO_INTERMEDIATE_STOW) do_z_clearance(Z_CLEARANCE_DEPLOY_PROBE); #elif HAS_BED_PROBE if (probe.deploy()) { // (returns true on deploy failure) @@ -503,20 +498,13 @@ G29_TYPE GcodeSuite::G29() { #endif #if ENABLED(AUTO_BED_LEVELING_BILINEAR) - if (!abl.dryrun - && (abl.gridSpacing != bedlevel.grid_spacing || abl.probe_position_lf != bedlevel.grid_start) - ) { - // Reset grid to 0.0 or "not probed". (Also disables ABL) - reset_bed_level(); - - // Can't re-enable (on error) until the new grid is written - abl.reenable = false; + if (!abl.dryrun && (abl.gridSpacing != bedlevel.grid_spacing || abl.probe_position_lf != bedlevel.grid_start)) { + reset_bed_level(); // Reset grid to 0.0 or "not probed". (Also disables ABL) + abl.reenable = false; // Can't re-enable (on error) until the new grid is written } - // Pre-populate local Z values from the stored mesh TERN_(IS_KINEMATIC, COPY(abl.z_values, bedlevel.z_values)); - - #endif // AUTO_BED_LEVELING_BILINEAR + #endif } // !g29_in_progress @@ -558,7 +546,7 @@ G29_TYPE GcodeSuite::G29() { } else { - #if EITHER(AUTO_BED_LEVELING_LINEAR, AUTO_BED_LEVELING_3POINT) + #if ANY(AUTO_BED_LEVELING_LINEAR, AUTO_BED_LEVELING_3POINT) const uint16_t index = abl.abl_probe_index - 1; #endif @@ -693,7 +681,7 @@ G29_TYPE GcodeSuite::G29() { zig ^= true; // zag // An index to print current state - uint8_t pt_index = (PR_OUTER_VAR) * (PR_INNER_SIZE) + 1; + grid_count_t pt_index = (PR_OUTER_VAR) * (PR_INNER_SIZE) + 1; // Inner loop is Y with PROBE_Y_FIRST enabled // Inner loop is X with PROBE_Y_FIRST disabled @@ -709,7 +697,67 @@ G29_TYPE GcodeSuite::G29() { if (abl.verbose_level) SERIAL_ECHOLNPGM("Probing mesh point ", pt_index, "/", abl.abl_points, "."); TERN_(HAS_STATUS_MESSAGE, ui.status_printf(0, F(S_FMT " %i/%i"), GET_TEXT(MSG_PROBING_POINT), int(pt_index), int(abl.abl_points))); - abl.measured_z = faux ? 0.001f * random(-100, 101) : probe.probe_at_point(abl.probePos, raise_after, abl.verbose_level); + #if ENABLED(BD_SENSOR_PROBE_NO_STOP) + if (PR_INNER_VAR == inStart) { + char tmp_1[32]; + + // move to the start point of new line + abl.measured_z = faux ? 0.001f * random(-100, 101) : probe.probe_at_point(abl.probePos, raise_after, abl.verbose_level); + // Go to the end of the row/column ... and back up by one + // TODO: Why not just use... PR_INNER_VAR = inStop - inInc + for (PR_INNER_VAR = inStart; PR_INNER_VAR != inStop; PR_INNER_VAR += inInc); + PR_INNER_VAR -= inInc; + + // Get the coordinate of the resulting grid point + abl.probePos = abl.probe_position_lf + abl.gridSpacing * abl.meshCount.asFloat(); + + // Coordinate that puts the probe at the grid point + abl.probePos -= probe.offset_xy; + + // Put a G1 move into the buffer + // TODO: Instead of G1, we can just add the move directly to the planner... + // { + // destination = current_position; destination = abl.probePos; + // REMEMBER(fr, feedrate_mm_s, XY_PROBE_FEEDRATE_MM_S); + // prepare_line_to_destination(); + // } + sprintf_P(tmp_1, PSTR("G1X%d.%d Y%d.%d F%d"), + int(abl.probePos.x), int(abl.probePos.x * 10) % 10, + int(abl.probePos.y), int(abl.probePos.y * 10) % 10, + XY_PROBE_FEEDRATE + ); + gcode.process_subcommands_now(tmp_1); + + if (DEBUGGING(LEVELING)) SERIAL_ECHOLNPGM("destX: ", abl.probePos.x, " Y:", abl.probePos.y); + + // Reset the inner counter back to the start + PR_INNER_VAR = inStart; + + // Get the coordinate of the start of the row/column + abl.probePos = abl.probe_position_lf + abl.gridSpacing * abl.meshCount.asFloat(); + } + + // Wait around until the real axis position reaches the comparison point + // TODO: Use NEAR() because float is imprecise + constexpr AxisEnum axis = TERN(PROBE_Y_FIRST, Y_AXIS, X_AXIS); + const float cmp = abl.probePos[axis] - probe.offset_xy[axis]; + float pos; + for (;;) { + pos = planner.get_axis_position_mm(axis); + if (inInc > 0 ? (pos >= cmp) : (pos <= cmp)) break; + idle_no_sleep(); + } + //if (DEBUGGING(LEVELING)) DEBUG_ECHOLNPGM_P(axis == Y_AXIS ? PSTR("Y=") : PSTR("X=", pos); + + safe_delay(4); + abl.measured_z = current_position.z - bdl.read(); + if (DEBUGGING(LEVELING)) SERIAL_ECHOLNPGM("x_cur ", planner.get_axis_position_mm(X_AXIS), " z ", abl.measured_z); + + #else // !BD_SENSOR_PROBE_NO_STOP + + abl.measured_z = faux ? 0.001f * random(-100, 101) : probe.probe_at_point(abl.probePos, raise_after, abl.verbose_level); + + #endif if (isnan(abl.measured_z)) { set_bed_leveling_enabled(abl.reenable); @@ -744,7 +792,7 @@ G29_TYPE GcodeSuite::G29() { // Probe at 3 arbitrary points - LOOP_L_N(i, 3) { + for (uint8_t i = 0; i < 3; ++i) { if (abl.verbose_level) SERIAL_ECHOLNPGM("Probing point ", i + 1, "/3."); TERN_(HAS_STATUS_MESSAGE, ui.status_printf(0, F(S_FMT " %i/3"), GET_TEXT(MSG_PROBING_POINT), int(i + 1))); @@ -833,11 +881,11 @@ G29_TYPE GcodeSuite::G29() { abl.mean /= abl.abl_points; if (abl.verbose_level) { - SERIAL_ECHOPAIR_F("Eqn coefficients: a: ", plane_equation_coefficients.a, 8); - SERIAL_ECHOPAIR_F(" b: ", plane_equation_coefficients.b, 8); - SERIAL_ECHOPAIR_F(" d: ", plane_equation_coefficients.d, 8); + SERIAL_ECHOPGM("Eqn coefficients: a: ", p_float_t(plane_equation_coefficients.a, 8), + " b: ", p_float_t(plane_equation_coefficients.b, 8), + " d: ", p_float_t(plane_equation_coefficients.d, 8)); if (abl.verbose_level > 2) - SERIAL_ECHOPAIR_F("\nMean of sampled points: ", abl.mean, 8); + SERIAL_ECHOPGM("\nMean of sampled points: ", p_float_t(abl.mean, 8)); SERIAL_EOL(); } @@ -853,9 +901,9 @@ G29_TYPE GcodeSuite::G29() { float min_diff = 999; auto print_topo_map = [&](FSTR_P const title, const bool get_min) { - SERIAL_ECHOF(title); + SERIAL_ECHO(title); for (int8_t yy = abl.grid_points.y - 1; yy >= 0; yy--) { - LOOP_L_N(xx, abl.grid_points.x) { + for (uint8_t xx = 0; xx < abl.grid_points.x; ++xx) { const int ind = abl.indexIntoAB[xx][yy]; xyz_float_t tmp = { abl.eqnAMatrix[ind + 0 * abl.abl_points], abl.eqnAMatrix[ind + 1 * abl.abl_points], 0 }; @@ -864,7 +912,7 @@ G29_TYPE GcodeSuite::G29() { const float subval = get_min ? abl.mean : tmp.z + min_diff, diff = abl.eqnBVector[ind] - subval; SERIAL_CHAR(' '); if (diff >= 0.0) SERIAL_CHAR('+'); // Include + for column alignment - SERIAL_ECHO_F(diff, 5); + SERIAL_ECHO(p_float_t(diff, 5)); } // xx SERIAL_EOL(); } // yy @@ -949,7 +997,7 @@ G29_TYPE GcodeSuite::G29() { process_subcommands_now(F(Z_PROBE_END_SCRIPT)); #endif - TERN_(HAS_MULTI_HOTEND, if (abl.tool_index != 0) tool_change(abl.tool_index)); + probe.use_probing_tool(false); report_current_position(); diff --git a/Marlin/src/gcode/bedlevel/abl/M421.cpp b/Marlin/src/gcode/bedlevel/abl/M421.cpp index 3272ea1bd2..f66d023190 100644 --- a/Marlin/src/gcode/bedlevel/abl/M421.cpp +++ b/Marlin/src/gcode/bedlevel/abl/M421.cpp @@ -56,8 +56,8 @@ void GcodeSuite::M421() { const float zval = parser.value_linear_units(); uint8_t sx = ix >= 0 ? ix : 0, ex = ix >= 0 ? ix : GRID_MAX_POINTS_X - 1, sy = iy >= 0 ? iy : 0, ey = iy >= 0 ? iy : GRID_MAX_POINTS_Y - 1; - LOOP_S_LE_N(x, sx, ex) { - LOOP_S_LE_N(y, sy, ey) { + for (uint8_t x = sx; x <= ex; ++x) { + for (uint8_t y = sy; y <= ey; ++y) { bedlevel.z_values[x][y] = zval + (hasQ ? bedlevel.z_values[x][y] : 0); TERN_(EXTENSIBLE_UI, ExtUI::onMeshUpdate(x, y, bedlevel.z_values[x][y])); } diff --git a/Marlin/src/gcode/bedlevel/mbl/G29.cpp b/Marlin/src/gcode/bedlevel/mbl/G29.cpp index e98f3d5ee3..b3f03d03ba 100644 --- a/Marlin/src/gcode/bedlevel/mbl/G29.cpp +++ b/Marlin/src/gcode/bedlevel/mbl/G29.cpp @@ -64,6 +64,7 @@ inline void echo_not_entered(const char c) { SERIAL_CHAR(c); SERIAL_ECHOLNPGM(" * S5 Reset and disable mesh */ void GcodeSuite::G29() { + DEBUG_SECTION(log_G29, "G29", true); // G29 Q is also available if debugging @@ -103,14 +104,11 @@ void GcodeSuite::G29() { bedlevel.reset(); mbl_probe_index = 0; if (!ui.wait_for_move) { - queue.inject(parser.seen_test('N') ? F("G28" TERN(CAN_SET_LEVELING_AFTER_G28, "L0", "") "\nG29S2") : F("G29S2")); - TERN_(EXTENSIBLE_UI, ExtUI::onLevelingStart()); - TERN_(DWIN_LCD_PROUI, DWIN_LevelingStart()); + if (parser.seen_test('N')) + queue.inject(F("G28" TERN_(CAN_SET_LEVELING_AFTER_G28, "L0"))); // Position bed horizontally and Z probe vertically. - #if defined(SAFE_BED_LEVELING_START_X) || defined(SAFE_BED_LEVELING_START_Y) || defined(SAFE_BED_LEVELING_START_Z) \ - || defined(SAFE_BED_LEVELING_START_I) || defined(SAFE_BED_LEVELING_START_J) || defined(SAFE_BED_LEVELING_START_K) \ - || defined(SAFE_BED_LEVELING_START_U) || defined(SAFE_BED_LEVELING_START_V) || defined(SAFE_BED_LEVELING_START_W) + #if HAS_SAFE_BED_LEVELING xyze_pos_t safe_position = current_position; #ifdef SAFE_BED_LEVELING_START_X safe_position.x = SAFE_BED_LEVELING_START_X; @@ -141,7 +139,12 @@ void GcodeSuite::G29() { #endif do_blocking_move_to(safe_position); - #endif + #endif // HAS_SAFE_BED_LEVELING + + queue.inject(F("G29S2")); + + TERN_(EXTENSIBLE_UI, ExtUI::onLevelingStart()); + TERN_(DWIN_LCD_PROUI, dwinLevelingStart()); return; } @@ -167,11 +170,11 @@ void GcodeSuite::G29() { // Save Z for the previous mesh position bedlevel.set_zigzag_z(mbl_probe_index - 1, current_position.z); TERN_(EXTENSIBLE_UI, ExtUI::onMeshUpdate(ix, iy, current_position.z)); - TERN_(DWIN_LCD_PROUI, DWIN_MeshUpdate(_MIN(mbl_probe_index, GRID_MAX_POINTS), int(GRID_MAX_POINTS), current_position.z)); + TERN_(DWIN_LCD_PROUI, dwinMeshUpdate(_MIN(mbl_probe_index, GRID_MAX_POINTS), int(GRID_MAX_POINTS), current_position.z)); SET_SOFT_ENDSTOP_LOOSE(false); } // If there's another point to sample, move there with optional lift. - if (mbl_probe_index < (GRID_MAX_POINTS)) { + if (mbl_probe_index < GRID_MAX_POINTS) { // Disable software endstops to allow manual adjustment // If G29 is left hanging without completion they won't be re-enabled! SET_SOFT_ENDSTOP_LOOSE(true); @@ -234,7 +237,7 @@ void GcodeSuite::G29() { if (parser.seenval('Z')) { bedlevel.z_values[ix][iy] = parser.value_linear_units(); TERN_(EXTENSIBLE_UI, ExtUI::onMeshUpdate(ix, iy, bedlevel.z_values[ix][iy])); - TERN_(DWIN_LCD_PROUI, DWIN_MeshUpdate(ix, iy, bedlevel.z_values[ix][iy])); + TERN_(DWIN_LCD_PROUI, dwinMeshUpdate(ix, iy, bedlevel.z_values[ix][iy])); } else return echo_not_entered('Z'); diff --git a/Marlin/src/gcode/bedlevel/ubl/M421.cpp b/Marlin/src/gcode/bedlevel/ubl/M421.cpp index ff74f4c6f7..3a5aa8cb03 100644 --- a/Marlin/src/gcode/bedlevel/ubl/M421.cpp +++ b/Marlin/src/gcode/bedlevel/ubl/M421.cpp @@ -66,10 +66,10 @@ void GcodeSuite::M421() { else if (!WITHIN(ij.x, 0, GRID_MAX_POINTS_X - 1) || !WITHIN(ij.y, 0, GRID_MAX_POINTS_Y - 1)) SERIAL_ERROR_MSG(STR_ERR_MESH_XY); else { - float &zval = bedlevel.z_values[ij.x][ij.y]; // Altering this Mesh Point + float &zval = bedlevel.z_values[ij.x][ij.y]; // Altering this Mesh Point zval = hasN ? NAN : parser.value_linear_units() + (hasQ ? zval : 0); // N=NAN, Z=NEWVAL, or Q=ADDVAL TERN_(EXTENSIBLE_UI, ExtUI::onMeshUpdate(ij.x, ij.y, zval)); // Ping ExtUI in case it's showing the mesh - TERN_(DWIN_LCD_PROUI, DWIN_MeshUpdate(ij.x, ij.y, zval)); + TERN_(DWIN_LCD_PROUI, dwinMeshUpdate(ij.x, ij.y, zval)); } } diff --git a/Marlin/src/gcode/calibrate/G28.cpp b/Marlin/src/gcode/calibrate/G28.cpp index a6dff2d75a..98d0a40148 100644 --- a/Marlin/src/gcode/calibrate/G28.cpp +++ b/Marlin/src/gcode/calibrate/G28.cpp @@ -36,10 +36,6 @@ #include "../../feature/bedlevel/bedlevel.h" #endif -#if ENABLED(BD_SENSOR) - #include "../../feature/bedlevel/bdl/bdl.h" -#endif - #if ENABLED(SENSORLESS_HOMING) #include "../../feature/tmc_util.h" #endif @@ -86,7 +82,7 @@ NUM_AXIS_LIST( TERN0(X_SENSORLESS, tmc_enable_stallguard(stepperX)), TERN0(Y_SENSORLESS, tmc_enable_stallguard(stepperY)), - false, false, false, false + false, false, false, false, false, false, false ) , TERN0(X2_SENSORLESS, tmc_enable_stallguard(stepperX2)) , TERN0(Y2_SENSORLESS, tmc_enable_stallguard(stepperY2)) @@ -124,14 +120,7 @@ * (Z is already at the right height) */ constexpr xy_float_t safe_homing_xy = { Z_SAFE_HOMING_X_POINT, Z_SAFE_HOMING_Y_POINT }; - #if HAS_HOME_OFFSET - xy_float_t okay_homing_xy = safe_homing_xy; - okay_homing_xy -= home_offset; - #else - constexpr xy_float_t okay_homing_xy = safe_homing_xy; - #endif - - destination.set(okay_homing_xy, current_position.z); + destination.set(safe_homing_xy, current_position.z); TERN_(HOMING_Z_WITH_PROBE, destination -= probe.offset_xy); @@ -166,7 +155,7 @@ planner.settings.max_acceleration_mm_per_s2[X_AXIS] = 100; planner.settings.max_acceleration_mm_per_s2[Y_AXIS] = 100; TERN_(DELTA, planner.settings.max_acceleration_mm_per_s2[Z_AXIS] = 100); - #if HAS_CLASSIC_JERK + #if ENABLED(CLASSIC_JERK) motion_state.jerk_state = planner.max_jerk; planner.max_jerk.set(0, 0 OPTARG(DELTA, 0)); #endif @@ -178,7 +167,7 @@ planner.settings.max_acceleration_mm_per_s2[X_AXIS] = motion_state.acceleration.x; planner.settings.max_acceleration_mm_per_s2[Y_AXIS] = motion_state.acceleration.y; TERN_(DELTA, planner.settings.max_acceleration_mm_per_s2[Z_AXIS] = motion_state.acceleration.z); - TERN_(HAS_CLASSIC_JERK, planner.max_jerk = motion_state.jerk_state); + TERN_(CLASSIC_JERK, planner.max_jerk = motion_state.jerk_state); planner.refresh_acceleration_rates(); } @@ -206,20 +195,6 @@ void GcodeSuite::G28() { DEBUG_SECTION(log_G28, "G28", DEBUGGING(LEVELING)); if (DEBUGGING(LEVELING)) log_machine_info(); - TERN_(BD_SENSOR, bdl.config_state = 0); - - /** - * Set the laser power to false to stop the planner from processing the current power setting. - */ - #if ENABLED(LASER_FEATURE) - planner.laser_inline.status.isPowered = false; - #endif - - #if ENABLED(DUAL_X_CARRIAGE) - bool IDEX_saved_duplication_state = extruder_duplication_enabled; - DualXMode IDEX_saved_mode = dual_x_carriage_mode; - #endif - #if ENABLED(MARLIN_DEV_MODE) if (parser.seen_test('S')) { LOOP_NUM_AXES(a) set_axis_is_at_home((AxisEnum)a); @@ -230,6 +205,13 @@ void GcodeSuite::G28() { } #endif + /** + * Set the laser power to false to stop the planner from processing the current power setting. + */ + #if ENABLED(LASER_FEATURE) + planner.laser_inline.status.isPowered = false; + #endif + // Home (O)nly if position is unknown if (!axes_should_home() && parser.seen_test('O')) { if (DEBUGGING(LEVELING)) DEBUG_ECHOLNPGM("> homing not needed, skip"); @@ -241,193 +223,327 @@ void GcodeSuite::G28() { set_and_report_grblstate(M_HOMING); #endif - TERN_(HAS_DWIN_E3V2_BASIC, DWIN_HomingStart()); + TERN_(HAS_DWIN_E3V2_BASIC, dwinHomingStart()); TERN_(EXTENSIBLE_UI, ExtUI::onHomingStart()); planner.synchronize(); // Wait for planner moves to finish! - SET_SOFT_ENDSTOP_LOOSE(false); // Reset a leftover 'loose' motion state - - // Disable the leveling matrix before homing - #if CAN_SET_LEVELING_AFTER_G28 - const bool leveling_restore_state = parser.boolval('L', TERN1(RESTORE_LEVELING_AFTER_G28, planner.leveling_active)); - #endif - - // Cancel any prior G29 session - TERN_(PROBE_MANUALLY, g29_in_progress = false); - - // Disable leveling before homing - TERN_(HAS_LEVELING, set_bed_leveling_enabled(false)); - - // Reset to the XY plane - TERN_(CNC_WORKSPACE_PLANES, workspace_plane = PLANE_XY); - // Count this command as movement / activity reset_stepper_timeout(); - #define HAS_CURRENT_HOME(N) (defined(N##_CURRENT_HOME) && N##_CURRENT_HOME != N##_CURRENT) - #if HAS_CURRENT_HOME(X) || HAS_CURRENT_HOME(X2) || HAS_CURRENT_HOME(Y) || HAS_CURRENT_HOME(Y2) || (ENABLED(DELTA) && HAS_CURRENT_HOME(Z)) || HAS_CURRENT_HOME(I) || HAS_CURRENT_HOME(J) || HAS_CURRENT_HOME(K) || HAS_CURRENT_HOME(U) || HAS_CURRENT_HOME(V) || HAS_CURRENT_HOME(W) - #define HAS_HOMING_CURRENT 1 - #endif + #if NUM_AXES - #if HAS_HOMING_CURRENT - auto debug_current = [](FSTR_P const s, const int16_t a, const int16_t b) { - DEBUG_ECHOF(s); DEBUG_ECHOLNPGM(" current: ", a, " -> ", b); - }; - #if HAS_CURRENT_HOME(X) - const int16_t tmc_save_current_X = stepperX.getMilliamps(); - stepperX.rms_current(X_CURRENT_HOME); - if (DEBUGGING(LEVELING)) debug_current(F(STR_X), tmc_save_current_X, X_CURRENT_HOME); + #if ENABLED(DUAL_X_CARRIAGE) + bool IDEX_saved_duplication_state = extruder_duplication_enabled; + DualXMode IDEX_saved_mode = dual_x_carriage_mode; #endif - #if HAS_CURRENT_HOME(X2) - const int16_t tmc_save_current_X2 = stepperX2.getMilliamps(); - stepperX2.rms_current(X2_CURRENT_HOME); - if (DEBUGGING(LEVELING)) debug_current(F(STR_X2), tmc_save_current_X2, X2_CURRENT_HOME); + + SET_SOFT_ENDSTOP_LOOSE(false); // Reset a leftover 'loose' motion state + + // Disable the leveling matrix before homing + #if CAN_SET_LEVELING_AFTER_G28 + const bool leveling_restore_state = parser.boolval('L', TERN1(RESTORE_LEVELING_AFTER_G28, planner.leveling_active)); #endif - #if HAS_CURRENT_HOME(Y) - const int16_t tmc_save_current_Y = stepperY.getMilliamps(); - stepperY.rms_current(Y_CURRENT_HOME); - if (DEBUGGING(LEVELING)) debug_current(F(STR_Y), tmc_save_current_Y, Y_CURRENT_HOME); + + // Cancel any prior G29 session + TERN_(PROBE_MANUALLY, g29_in_progress = false); + + // Disable leveling before homing + TERN_(HAS_LEVELING, set_bed_leveling_enabled(false)); + + // Reset to the XY plane + TERN_(CNC_WORKSPACE_PLANES, workspace_plane = PLANE_XY); + + #define _OR_HAS_CURR_HOME(N) HAS_CURRENT_HOME(N) || + #if MAIN_AXIS_MAP(_OR_HAS_CURR_HOME) MAP(_OR_HAS_CURR_HOME, X2, Y2, Z2, Z3, Z4) 0 + #define HAS_HOMING_CURRENT 1 #endif - #if HAS_CURRENT_HOME(Y2) - const int16_t tmc_save_current_Y2 = stepperY2.getMilliamps(); - stepperY2.rms_current(Y2_CURRENT_HOME); - if (DEBUGGING(LEVELING)) debug_current(F(STR_Y2), tmc_save_current_Y2, Y2_CURRENT_HOME); + + #if HAS_HOMING_CURRENT + + #if ENABLED(DEBUG_LEVELING_FEATURE) + auto debug_current = [](FSTR_P const s, const int16_t a, const int16_t b) { + if (DEBUGGING(LEVELING)) { DEBUG_ECHOLN(s, F(" current: "), a, F(" -> "), b); } + }; + #else + #define debug_current(...) + #endif + + #define _SAVE_SET_CURRENT(A) \ + const int16_t saved_current_##A = stepper##A.getMilliamps(); \ + stepper##A.rms_current(A##_CURRENT_HOME); \ + debug_current(F(STR_##A), saved_current_##A, A##_CURRENT_HOME) + + #if HAS_CURRENT_HOME(X) + _SAVE_SET_CURRENT(X); + #endif + #if HAS_CURRENT_HOME(X2) + _SAVE_SET_CURRENT(X2); + #endif + #if HAS_CURRENT_HOME(Y) + _SAVE_SET_CURRENT(Y); + #endif + #if HAS_CURRENT_HOME(Y2) + _SAVE_SET_CURRENT(Y2); + #endif + #if HAS_CURRENT_HOME(Z) + _SAVE_SET_CURRENT(Z); + #endif + #if HAS_CURRENT_HOME(Z2) + _SAVE_SET_CURRENT(Z2); + #endif + #if HAS_CURRENT_HOME(Z3) + _SAVE_SET_CURRENT(Z3); + #endif + #if HAS_CURRENT_HOME(Z4) + _SAVE_SET_CURRENT(Z4); + #endif + #if HAS_CURRENT_HOME(I) + _SAVE_SET_CURRENT(I); + #endif + #if HAS_CURRENT_HOME(J) + _SAVE_SET_CURRENT(J); + #endif + #if HAS_CURRENT_HOME(K) + _SAVE_SET_CURRENT(K); + #endif + #if HAS_CURRENT_HOME(U) + _SAVE_SET_CURRENT(U); + #endif + #if HAS_CURRENT_HOME(V) + _SAVE_SET_CURRENT(V); + #endif + #if HAS_CURRENT_HOME(W) + _SAVE_SET_CURRENT(W); + #endif + #if SENSORLESS_STALLGUARD_DELAY + safe_delay(SENSORLESS_STALLGUARD_DELAY); // Short delay needed to settle + #endif + #endif // HAS_HOMING_CURRENT + + #if ENABLED(IMPROVE_HOMING_RELIABILITY) + motion_state_t saved_motion_state = begin_slow_homing(); #endif - #if HAS_CURRENT_HOME(Z) && ENABLED(DELTA) - const int16_t tmc_save_current_Z = stepperZ.getMilliamps(); - stepperZ.rms_current(Z_CURRENT_HOME); - if (DEBUGGING(LEVELING)) debug_current(F(STR_Z), tmc_save_current_Z, Z_CURRENT_HOME); + + // Always home with tool 0 active + #if HAS_MULTI_HOTEND + #if DISABLED(DELTA) || ENABLED(DELTA_HOME_TO_SAFE_ZONE) + const uint8_t old_tool_index = active_extruder; + #endif + // PARKING_EXTRUDER homing requires different handling of movement / solenoid activation, depending on the side of homing + #if ENABLED(PARKING_EXTRUDER) + const bool pe_final_change_must_unpark = parking_extruder_unpark_after_homing(old_tool_index, X_HOME_DIR + 1 == old_tool_index * 2); + #endif + tool_change(0, true); #endif - #if HAS_CURRENT_HOME(I) - const int16_t tmc_save_current_I = stepperI.getMilliamps(); - stepperI.rms_current(I_CURRENT_HOME); - if (DEBUGGING(LEVELING)) debug_current(F(STR_I), tmc_save_current_I, I_CURRENT_HOME); - #endif - #if HAS_CURRENT_HOME(J) - const int16_t tmc_save_current_J = stepperJ.getMilliamps(); - stepperJ.rms_current(J_CURRENT_HOME); - if (DEBUGGING(LEVELING)) debug_current(F(STR_J), tmc_save_current_J, J_CURRENT_HOME); - #endif - #if HAS_CURRENT_HOME(K) - const int16_t tmc_save_current_K = stepperK.getMilliamps(); - stepperK.rms_current(K_CURRENT_HOME); - if (DEBUGGING(LEVELING)) debug_current(F(STR_K), tmc_save_current_K, K_CURRENT_HOME); - #endif - #if HAS_CURRENT_HOME(U) - const int16_t tmc_save_current_U = stepperU.getMilliamps(); - stepperU.rms_current(U_CURRENT_HOME); - if (DEBUGGING(LEVELING)) debug_current(F(STR_U), tmc_save_current_U, U_CURRENT_HOME); - #endif - #if HAS_CURRENT_HOME(V) - const int16_t tmc_save_current_V = stepperV.getMilliamps(); - stepperV.rms_current(V_CURRENT_HOME); - if (DEBUGGING(LEVELING)) debug_current(F(STR_V), tmc_save_current_V, V_CURRENT_HOME); - #endif - #if HAS_CURRENT_HOME(W) - const int16_t tmc_save_current_W = stepperW.getMilliamps(); - stepperW.rms_current(W_CURRENT_HOME); - if (DEBUGGING(LEVELING)) debug_current(F(STR_W), tmc_save_current_W, W_CURRENT_HOME); - #endif - #if SENSORLESS_STALLGUARD_DELAY - safe_delay(SENSORLESS_STALLGUARD_DELAY); // Short delay needed to settle - #endif - #endif - #if ENABLED(IMPROVE_HOMING_RELIABILITY) - motion_state_t saved_motion_state = begin_slow_homing(); - #endif + TERN_(HAS_DUPLICATION_MODE, set_duplication_enabled(false)); - // Always home with tool 0 active - #if HAS_MULTI_HOTEND - #if DISABLED(DELTA) || ENABLED(DELTA_HOME_TO_SAFE_ZONE) - const uint8_t old_tool_index = active_extruder; - #endif - // PARKING_EXTRUDER homing requires different handling of movement / solenoid activation, depending on the side of homing - #if ENABLED(PARKING_EXTRUDER) - const bool pe_final_change_must_unpark = parking_extruder_unpark_after_homing(old_tool_index, X_HOME_DIR + 1 == old_tool_index * 2); - #endif - tool_change(0, true); - #endif + remember_feedrate_scaling_off(); - TERN_(HAS_DUPLICATION_MODE, set_duplication_enabled(false)); - - remember_feedrate_scaling_off(); - - endstops.enable(true); // Enable endstops for next homing move - - #if ENABLED(DELTA) - - constexpr bool doZ = true; // for NANODLP_Z_SYNC if your DLP is on a DELTA - - home_delta(); - - TERN_(IMPROVE_HOMING_RELIABILITY, end_slow_homing(saved_motion_state)); - - #elif ENABLED(AXEL_TPARA) - - constexpr bool doZ = true; // for NANODLP_Z_SYNC if your DLP is on a TPARA - - home_TPARA(); - - #else - - #define _UNSAFE(A) (homeZ && TERN0(Z_SAFE_HOMING, axes_should_home(_BV(A##_AXIS)))) - - const bool homeZ = TERN0(HAS_Z_AXIS, parser.seen_test('Z')), - NUM_AXIS_LIST( // Other axes should be homed before Z safe-homing - needX = _UNSAFE(X), needY = _UNSAFE(Y), needZ = false, // UNUSED - needI = _UNSAFE(I), needJ = _UNSAFE(J), needK = _UNSAFE(K), - needU = _UNSAFE(U), needV = _UNSAFE(V), needW = _UNSAFE(W) - ), - NUM_AXIS_LIST( // Home each axis if needed or flagged - homeX = needX || parser.seen_test('X'), - homeY = needY || parser.seen_test('Y'), - homeZZ = homeZ, - homeI = needI || parser.seen_test(AXIS4_NAME), homeJ = needJ || parser.seen_test(AXIS5_NAME), - homeK = needK || parser.seen_test(AXIS6_NAME), homeU = needU || parser.seen_test(AXIS7_NAME), - homeV = needV || parser.seen_test(AXIS8_NAME), homeW = needW || parser.seen_test(AXIS9_NAME) - ), - home_all = NUM_AXIS_GANG( // Home-all if all or none are flagged - homeX == homeX, && homeY == homeX, && homeZ == homeX, - && homeI == homeX, && homeJ == homeX, && homeK == homeX, - && homeU == homeX, && homeV == homeX, && homeW == homeX - ), - NUM_AXIS_LIST( - doX = home_all || homeX, doY = home_all || homeY, doZ = home_all || homeZ, - doI = home_all || homeI, doJ = home_all || homeJ, doK = home_all || homeK, - doU = home_all || homeU, doV = home_all || homeV, doW = home_all || homeW - ); + endstops.enable(true); // Enable endstops for next homing move #if HAS_Z_AXIS - UNUSED(needZ); UNUSED(homeZZ); - #else - constexpr bool doZ = false; + bool finalRaiseZ = false; #endif - TERN_(HOME_Z_FIRST, if (doZ) homeaxis(Z_AXIS)); + #if ENABLED(DELTA) - const bool seenR = parser.seenval('R'); - const float z_homing_height = seenR ? parser.value_linear_units() : Z_HOMING_HEIGHT; + constexpr bool doZ = true; // for NANODLP_Z_SYNC if your DLP is on a DELTA - if (z_homing_height && (seenR || NUM_AXIS_GANG(doX, || doY, || TERN0(Z_SAFE_HOMING, doZ), || doI, || doJ, || doK, || doU, || doV, || doW))) { - // Raise Z before homing any other axes and z is not already high enough (never lower z) - if (DEBUGGING(LEVELING)) DEBUG_ECHOLNPGM("Raise Z (before homing) by ", z_homing_height); - do_z_clearance(z_homing_height); - TERN_(BLTOUCH, bltouch.init()); - } + home_delta(); - // Diagonal move first if both are homing - TERN_(QUICK_HOME, if (doX && doY) quick_home_xy()); + TERN_(IMPROVE_HOMING_RELIABILITY, end_slow_homing(saved_motion_state)); - // Home Y (before X) - if (ENABLED(HOME_Y_BEFORE_X) && (doY || TERN0(CODEPENDENT_XY_HOMING, doX))) - homeaxis(Y_AXIS); + #elif ENABLED(AXEL_TPARA) - // Home X - if (doX || (doY && ENABLED(CODEPENDENT_XY_HOMING) && DISABLED(HOME_Y_BEFORE_X))) { + constexpr bool doZ = true; // for NANODLP_Z_SYNC if your DLP is on a TPARA - #if ENABLED(DUAL_X_CARRIAGE) + home_TPARA(); + + #else // !DELTA && !AXEL_TPARA + + #define _UNSAFE(A) (homeZ && TERN0(Z_SAFE_HOMING, axes_should_home(_BV(A##_AXIS)))) + + const bool homeZ = TERN0(HAS_Z_AXIS, parser.seen_test('Z')), + NUM_AXIS_LIST_( // Other axes should be homed before Z safe-homing + needX = _UNSAFE(X), needY = _UNSAFE(Y), needZ = false, // UNUSED + needI = _UNSAFE(I), needJ = _UNSAFE(J), needK = _UNSAFE(K), + needU = _UNSAFE(U), needV = _UNSAFE(V), needW = _UNSAFE(W) + ) + NUM_AXIS_LIST_( // Home each axis if needed or flagged + homeX = needX || parser.seen_test('X'), + homeY = needY || parser.seen_test('Y'), + homeZZ = homeZ, + homeI = needI || parser.seen_test(AXIS4_NAME), homeJ = needJ || parser.seen_test(AXIS5_NAME), + homeK = needK || parser.seen_test(AXIS6_NAME), homeU = needU || parser.seen_test(AXIS7_NAME), + homeV = needV || parser.seen_test(AXIS8_NAME), homeW = needW || parser.seen_test(AXIS9_NAME) + ) + home_all = NUM_AXIS_GANG_( // Home-all if all or none are flagged + homeX == homeX, && homeY == homeX, && homeZ == homeX, + && homeI == homeX, && homeJ == homeX, && homeK == homeX, + && homeU == homeX, && homeV == homeX, && homeW == homeX + ) + NUM_AXIS_LIST( + doX = home_all || homeX, doY = home_all || homeY, doZ = home_all || homeZ, + doI = home_all || homeI, doJ = home_all || homeJ, doK = home_all || homeK, + doU = home_all || homeU, doV = home_all || homeV, doW = home_all || homeW + ); + + #if !HAS_Y_AXIS + constexpr bool doY = false; + #endif + + #if HAS_Z_AXIS + + UNUSED(needZ); UNUSED(homeZZ); + + // Z may home first, e.g., when homing away from the bed. + // This is also permitted when homing with a Z endstop. + if (TERN0(HOME_Z_FIRST, doZ)) homeaxis(Z_AXIS); + + // 'R' to specify a specific raise. 'R0' indicates no raise, e.g., for recovery.resume + // When 'R0' is used, there should already be adequate clearance, e.g., from homing Z to max. + const bool seenR = parser.seenval('R'); + + // Use raise given by 'R' or Z_CLEARANCE_FOR_HOMING (above the probe trigger point) + 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); + + if (seenR && z_homing_height == 0) { + if (DEBUGGING(LEVELING)) DEBUG_ECHOLNPGM("R0 = No Z raise"); + } + else { + bool with_probe = ENABLED(HOMING_Z_WITH_PROBE); + // Raise above the current Z (which should be synced in the planner) + // The "height" for Z is a coordinate. But if Z is not trusted/homed make it relative. + if (seenR || !TERN(HOME_AFTER_DEACTIVATE, axis_is_trusted, axis_was_homed)(Z_AXIS)) { + z_homing_height += current_position.z; + with_probe = false; + } + + if (may_skate) { + // Apply Z clearance before doing any lateral motion + if (DEBUGGING(LEVELING)) DEBUG_ECHOLNPGM("Raise Z before homing:"); + do_z_clearance(z_homing_height, with_probe); + } + } + + // Init BLTouch ahead of any lateral motion, even if not homing with the probe + TERN_(BLTOUCH, if (may_skate) bltouch.init()); + + #endif // HAS_Z_AXIS + + // Diagonal move first if both are homing + TERN_(QUICK_HOME, if (doX && doY) quick_home_xy()); + + #if HAS_Y_AXIS + // Home Y (before X) + if (ENABLED(HOME_Y_BEFORE_X) && (doY || TERN0(CODEPENDENT_XY_HOMING, doX))) + homeaxis(Y_AXIS); + #endif + + // Home X + #if HAS_X_AXIS + if (doX || (doY && ENABLED(CODEPENDENT_XY_HOMING) && DISABLED(HOME_Y_BEFORE_X))) { + + #if ENABLED(DUAL_X_CARRIAGE) + + // Always home the 2nd (right) extruder first + active_extruder = 1; + homeaxis(X_AXIS); + + // Remember this extruder's position for later tool change + inactive_extruder_x = current_position.x; + + // Home the 1st (left) extruder + active_extruder = 0; + homeaxis(X_AXIS); + + // Consider the active extruder to be in its "parked" position + idex_set_parked(); + + #else + + homeaxis(X_AXIS); + + #endif + } + #endif // HAS_X_AXIS + + #if ALL(FOAMCUTTER_XYUV, HAS_I_AXIS) + // Home I (after X) + if (doI) homeaxis(I_AXIS); + #endif + + #if HAS_Y_AXIS + // Home Y (after X) + if (DISABLED(HOME_Y_BEFORE_X) && doY) + homeaxis(Y_AXIS); + #endif + + #if ALL(FOAMCUTTER_XYUV, HAS_J_AXIS) + // Home J (after Y) + if (doJ) homeaxis(J_AXIS); + #endif + + TERN_(IMPROVE_HOMING_RELIABILITY, end_slow_homing(saved_motion_state)); + + #if ENABLED(FOAMCUTTER_XYUV) + + // Skip homing of unused Z axis for foamcutters + if (doZ) set_axis_is_at_home(Z_AXIS); + + #elif HAS_Z_AXIS + + // Home Z last if homing towards the bed + #if DISABLED(HOME_Z_FIRST) + if (doZ) { + #if ANY(Z_MULTI_ENDSTOPS, Z_STEPPER_AUTO_ALIGN) + stepper.set_all_z_lock(false); + stepper.set_separate_multi_axis(false); + #endif + + #if ENABLED(Z_SAFE_HOMING) + if (TERN1(POWER_LOSS_RECOVERY, !parser.seen_test('H'))) home_z_safely(); else homeaxis(Z_AXIS); + #else + homeaxis(Z_AXIS); + #endif + + #if ANY(Z_HOME_TO_MIN, ALLOW_Z_AFTER_HOMING) + finalRaiseZ = true; + #endif + } + #endif + + SECONDARY_AXIS_CODE( + if (doI) homeaxis(I_AXIS), + if (doJ) homeaxis(J_AXIS), + if (doK) homeaxis(K_AXIS), + if (doU) homeaxis(U_AXIS), + if (doV) homeaxis(V_AXIS), + if (doW) homeaxis(W_AXIS) + ); + + #endif // HAS_Z_AXIS + + sync_plan_position(); + + #endif + + /** + * Preserve DXC mode across a G28 for IDEX printers in DXC_DUPLICATION_MODE. + * This is important because it lets a user use the LCD Panel to set an IDEX Duplication mode, and + * then print a standard G-Code file that contains a single print that does a G28 and has no other + * IDEX specific commands in it. + */ + #if ENABLED(DUAL_X_CARRIAGE) + + if (idex_is_duplicating()) { + + TERN_(IMPROVE_HOMING_RELIABILITY, saved_motion_state = begin_slow_homing()); // Always home the 2nd (right) extruder first active_extruder = 1; @@ -440,168 +556,111 @@ void GcodeSuite::G28() { active_extruder = 0; homeaxis(X_AXIS); - // Consider the active extruder to be in its "parked" position + // Consider the active extruder to be parked idex_set_parked(); - #else + dual_x_carriage_mode = IDEX_saved_mode; + set_duplication_enabled(IDEX_saved_duplication_state); - homeaxis(X_AXIS); + TERN_(IMPROVE_HOMING_RELIABILITY, end_slow_homing(saved_motion_state)); + } + #endif // DUAL_X_CARRIAGE + + endstops.not_homing(); + + // Clear endstop state for polled stallGuard endstops + TERN_(SPI_ENDSTOPS, endstops.clear_endstop_state()); + + #if HAS_HOMING_CURRENT + if (DEBUGGING(LEVELING)) DEBUG_ECHOLNPGM("Restore driver current..."); + #if HAS_CURRENT_HOME(X) + stepperX.rms_current(saved_current_X); #endif - } - - #if BOTH(FOAMCUTTER_XYUV, HAS_I_AXIS) - // Home I (after X) - if (doI) homeaxis(I_AXIS); - #endif - - // Home Y (after X) - if (DISABLED(HOME_Y_BEFORE_X) && doY) - homeaxis(Y_AXIS); - - #if BOTH(FOAMCUTTER_XYUV, HAS_J_AXIS) - // Home J (after Y) - if (doJ) homeaxis(J_AXIS); - #endif - - TERN_(IMPROVE_HOMING_RELIABILITY, end_slow_homing(saved_motion_state)); - - #if ENABLED(FOAMCUTTER_XYUV) - // skip homing of unused Z axis for foamcutters - if (doZ) set_axis_is_at_home(Z_AXIS); - #else - // Home Z last if homing towards the bed - #if HAS_Z_AXIS && DISABLED(HOME_Z_FIRST) - if (doZ) { - #if EITHER(Z_MULTI_ENDSTOPS, Z_STEPPER_AUTO_ALIGN) - stepper.set_all_z_lock(false); - stepper.set_separate_multi_axis(false); - #endif - - #if ENABLED(Z_SAFE_HOMING) - if (TERN1(POWER_LOSS_RECOVERY, !parser.seen_test('H'))) home_z_safely(); else homeaxis(Z_AXIS); - #else - homeaxis(Z_AXIS); - #endif - probe.move_z_after_homing(); - } + #if HAS_CURRENT_HOME(X2) + stepperX2.rms_current(saved_current_X2); #endif + #if HAS_CURRENT_HOME(Y) + stepperY.rms_current(saved_current_Y); + #endif + #if HAS_CURRENT_HOME(Y2) + stepperY2.rms_current(saved_current_Y2); + #endif + #if HAS_CURRENT_HOME(Z) + stepperZ.rms_current(saved_current_Z); + #endif + #if HAS_CURRENT_HOME(Z2) + stepperZ2.rms_current(saved_current_Z2); + #endif + #if HAS_CURRENT_HOME(Z3) + stepperZ3.rms_current(saved_current_Z3); + #endif + #if HAS_CURRENT_HOME(Z4) + stepperZ4.rms_current(saved_current_Z4); + #endif + #if HAS_CURRENT_HOME(I) + stepperI.rms_current(saved_current_I); + #endif + #if HAS_CURRENT_HOME(J) + stepperJ.rms_current(saved_current_J); + #endif + #if HAS_CURRENT_HOME(K) + stepperK.rms_current(saved_current_K); + #endif + #if HAS_CURRENT_HOME(U) + stepperU.rms_current(saved_current_U); + #endif + #if HAS_CURRENT_HOME(V) + stepperV.rms_current(saved_current_V); + #endif + #if HAS_CURRENT_HOME(W) + stepperW.rms_current(saved_current_W); + #endif + #if SENSORLESS_STALLGUARD_DELAY + safe_delay(SENSORLESS_STALLGUARD_DELAY); // Short delay needed to settle + #endif + #endif // HAS_HOMING_CURRENT - SECONDARY_AXIS_CODE( - if (doI) homeaxis(I_AXIS), - if (doJ) homeaxis(J_AXIS), - if (doK) homeaxis(K_AXIS), - if (doU) homeaxis(U_AXIS), - if (doV) homeaxis(V_AXIS), - if (doW) homeaxis(W_AXIS) - ); + // Move to a height where we can use the full xy-area + TERN_(DELTA_HOME_TO_SAFE_ZONE, do_blocking_move_to_z(delta_clip_start_height)); + + #if HAS_Z_AXIS + // Move to the configured Z only if Z was homed to MIN, because machines that + // home to MAX historically expect 'G28 Z' to be safe to use at the end of a + // print, and do_move_after_z_homing is not very nuanced. + if (finalRaiseZ) do_move_after_z_homing(); #endif - sync_plan_position(); + TERN_(CAN_SET_LEVELING_AFTER_G28, if (leveling_restore_state) set_bed_leveling_enabled()); - #endif - - /** - * Preserve DXC mode across a G28 for IDEX printers in DXC_DUPLICATION_MODE. - * This is important because it lets a user use the LCD Panel to set an IDEX Duplication mode, and - * then print a standard GCode file that contains a single print that does a G28 and has no other - * IDEX specific commands in it. - */ - #if ENABLED(DUAL_X_CARRIAGE) - - if (idex_is_duplicating()) { - - TERN_(IMPROVE_HOMING_RELIABILITY, saved_motion_state = begin_slow_homing()); - - // Always home the 2nd (right) extruder first - active_extruder = 1; - homeaxis(X_AXIS); - - // Remember this extruder's position for later tool change - inactive_extruder_x = current_position.x; - - // Home the 1st (left) extruder - active_extruder = 0; - homeaxis(X_AXIS); - - // Consider the active extruder to be parked - idex_set_parked(); - - dual_x_carriage_mode = IDEX_saved_mode; - set_duplication_enabled(IDEX_saved_duplication_state); - - TERN_(IMPROVE_HOMING_RELIABILITY, end_slow_homing(saved_motion_state)); - } - - #endif // DUAL_X_CARRIAGE - - endstops.not_homing(); - - // Clear endstop state for polled stallGuard endstops - TERN_(SPI_ENDSTOPS, endstops.clear_endstop_state()); - - // Move to a height where we can use the full xy-area - TERN_(DELTA_HOME_TO_SAFE_ZONE, do_blocking_move_to_z(delta_clip_start_height)); - - TERN_(CAN_SET_LEVELING_AFTER_G28, if (leveling_restore_state) set_bed_leveling_enabled()); - - restore_feedrate_and_scaling(); - - // Restore the active tool after homing - #if HAS_MULTI_HOTEND && (DISABLED(DELTA) || ENABLED(DELTA_HOME_TO_SAFE_ZONE)) - tool_change(old_tool_index, TERN(PARKING_EXTRUDER, !pe_final_change_must_unpark, DISABLED(DUAL_X_CARRIAGE))); // Do move if one of these - #endif - - #if HAS_HOMING_CURRENT - if (DEBUGGING(LEVELING)) DEBUG_ECHOLNPGM("Restore driver current..."); - #if HAS_CURRENT_HOME(X) - stepperX.rms_current(tmc_save_current_X); + // Restore the active tool after homing + #if HAS_MULTI_HOTEND && (DISABLED(DELTA) || ENABLED(DELTA_HOME_TO_SAFE_ZONE)) + tool_change(old_tool_index, TERN(PARKING_EXTRUDER, !pe_final_change_must_unpark, DISABLED(DUAL_X_CARRIAGE))); // Do move if one of these #endif - #if HAS_CURRENT_HOME(X2) - stepperX2.rms_current(tmc_save_current_X2); + + #ifdef XY_AFTER_HOMING + constexpr xy_pos_t xy_after XY_AFTER_HOMING; + do_blocking_move_to(xy_after); #endif - #if HAS_CURRENT_HOME(Y) - stepperY.rms_current(tmc_save_current_Y); - #endif - #if HAS_CURRENT_HOME(Y2) - stepperY2.rms_current(tmc_save_current_Y2); - #endif - #if HAS_CURRENT_HOME(Z) && ENABLED(DELTA) - stepperZ.rms_current(tmc_save_current_Z); - #endif - #if HAS_CURRENT_HOME(I) - stepperI.rms_current(tmc_save_current_I); - #endif - #if HAS_CURRENT_HOME(J) - stepperJ.rms_current(tmc_save_current_J); - #endif - #if HAS_CURRENT_HOME(K) - stepperK.rms_current(tmc_save_current_K); - #endif - #if HAS_CURRENT_HOME(U) - stepperU.rms_current(tmc_save_current_U); - #endif - #if HAS_CURRENT_HOME(V) - stepperV.rms_current(tmc_save_current_V); - #endif - #if HAS_CURRENT_HOME(W) - stepperW.rms_current(tmc_save_current_W); - #endif - #if SENSORLESS_STALLGUARD_DELAY - safe_delay(SENSORLESS_STALLGUARD_DELAY); // Short delay needed to settle - #endif - #endif // HAS_HOMING_CURRENT + + restore_feedrate_and_scaling(); + + if (ENABLED(NANODLP_Z_SYNC) && (ENABLED(NANODLP_ALL_AXIS) || TERN0(HAS_Z_AXIS, doZ))) + SERIAL_ECHOLNPGM(STR_Z_MOVE_COMP); + + #endif // NUM_AXES ui.refresh(); - TERN_(HAS_DWIN_E3V2_BASIC, DWIN_HomingDone()); + TERN_(HAS_DWIN_E3V2_BASIC, dwinHomingDone()); TERN_(EXTENSIBLE_UI, ExtUI::onHomingDone()); report_current_position(); - if (ENABLED(NANODLP_Z_SYNC) && (doZ || ENABLED(NANODLP_ALL_AXIS))) - SERIAL_ECHOLNPGM(STR_Z_MOVE_COMP); - TERN_(FULL_REPORT_TO_HOST_FEATURE, set_and_report_grblstate(old_grblstate)); + #ifdef EVENT_GCODE_AFTER_HOMING + gcode.process_subcommands_now(F(EVENT_GCODE_AFTER_HOMING)); + #endif + } diff --git a/Marlin/src/gcode/calibrate/G33.cpp b/Marlin/src/gcode/calibrate/G33.cpp index 656c23cb78..d8f104bfce 100644 --- a/Marlin/src/gcode/calibrate/G33.cpp +++ b/Marlin/src/gcode/calibrate/G33.cpp @@ -63,22 +63,18 @@ enum CalEnum : char { // the 7 main calibration points - #define LOOP_CAL_RAD(VAR) LOOP_CAL_PT(VAR, __A, _7P_STEP) #define LOOP_CAL_ACT(VAR, _4P, _OP) LOOP_CAL_PT(VAR, _OP ? _AB : __A, _4P ? _4P_STEP : _7P_STEP) -#if HAS_MULTI_HOTEND - const uint8_t old_tool_index = active_extruder; -#endif - float lcd_probe_pt(const xy_pos_t &xy); void ac_home() { endstops.enable(true); - TERN_(SENSORLESS_HOMING, endstops.set_homing_current(true)); + TERN_(SENSORLESS_HOMING, endstops.set_z_sensorless_current(true)); home_delta(); - TERN_(SENSORLESS_HOMING, endstops.set_homing_current(false)); + TERN_(SENSORLESS_HOMING, endstops.set_z_sensorless_current(false)); endstops.not_homing(); } void ac_setup(const bool reset_bed) { - TERN_(HAS_MULTI_HOTEND, tool_change(0, true)); + TERN_(HAS_BED_PROBE, probe.use_probing_tool()); planner.synchronize(); remember_feedrate_scaling_off(); @@ -88,21 +84,20 @@ void ac_setup(const bool reset_bed) { #endif } -void ac_cleanup(TERN_(HAS_MULTI_HOTEND, const uint8_t old_tool_index)) { +void ac_cleanup() { TERN_(DELTA_HOME_TO_SAFE_ZONE, do_blocking_move_to_z(delta_clip_start_height)); TERN_(HAS_BED_PROBE, probe.stow()); restore_feedrate_and_scaling(); - TERN_(HAS_MULTI_HOTEND, tool_change(old_tool_index, true)); + TERN_(HAS_BED_PROBE, probe.use_probing_tool(false)); } void print_signed_float(FSTR_P const prefix, const_float_t f) { - SERIAL_ECHOPGM(" "); - SERIAL_ECHOF(prefix, AS_CHAR(':')); + SERIAL_ECHO(F(" "), prefix, C(':')); serial_offset(f); } /** - * - Print the delta settings + * - Print the delta settings */ static void print_calibration_settings(const bool end_stops, const bool tower_angles) { SERIAL_ECHOPGM(".Height:", delta_height); @@ -128,7 +123,7 @@ static void print_calibration_settings(const bool end_stops, const bool tower_an } /** - * - Print the probe results + * - Print the probe results */ static void print_calibration_results(const float z_pt[NPP + 1], const bool tower_points, const bool opposite_points) { SERIAL_ECHOPGM(". "); @@ -152,7 +147,7 @@ static void print_calibration_results(const float z_pt[NPP + 1], const bool towe } /** - * - Calculate the standard deviation from the zero plane + * - Calculate the standard deviation from the zero plane */ static float std_dev_points(float z_pt[NPP + 1], const bool _0p_cal, const bool _1p_cal, const bool _4p_cal, const bool _4p_opp) { if (!_0p_cal) { @@ -170,11 +165,11 @@ static float std_dev_points(float z_pt[NPP + 1], const bool _0p_cal, const bool } /** - * - Probe a point + * - Probe a point */ static float calibration_probe(const xy_pos_t &xy, const bool stow, const bool probe_at_offset) { #if HAS_BED_PROBE - return probe.probe_at_point(xy, stow ? PROBE_PT_STOW : PROBE_PT_RAISE, 0, probe_at_offset, false); + return probe.probe_at_point(xy, stow ? PROBE_PT_STOW : PROBE_PT_RAISE, 0, probe_at_offset, false, Z_PROBE_LOW_POINT, Z_TWEEN_SAFE_CLEARANCE, true); #else UNUSED(stow); return lcd_probe_pt(xy); @@ -182,7 +177,7 @@ static float calibration_probe(const xy_pos_t &xy, const bool stow, const bool p } /** - * - Probe a grid + * - Probe a grid */ static bool probe_calibration_points(float z_pt[NPP + 1], const int8_t probe_points, const float dcr, const bool towers_set, const bool stow_after_each, const bool probe_at_offset) { const bool _0p_calibration = probe_points == 0, @@ -407,12 +402,12 @@ void GcodeSuite::G33() { towers_set = !parser.seen_test('T'); // The calibration radius is set to a calculated value - float dcr = probe_at_offset ? DELTA_PRINTABLE_RADIUS : DELTA_PRINTABLE_RADIUS - PROBING_MARGIN; + float dcr = probe_at_offset ? PRINTABLE_RADIUS : PRINTABLE_RADIUS - PROBING_MARGIN; #if HAS_PROBE_XY_OFFSET const float total_offset = HYPOT(probe.offset_xy.x, probe.offset_xy.y); dcr -= probe_at_offset ? _MAX(total_offset, PROBING_MARGIN) : total_offset; #endif - NOMORE(dcr, DELTA_PRINTABLE_RADIUS); + NOMORE(dcr, PRINTABLE_RADIUS); if (parser.seenval('R')) dcr -= _MAX(parser.value_float(), 0.0f); TERN_(HAS_DELTA_SENSORLESS_PROBING, dcr *= sensorless_radius_factor); @@ -464,9 +459,8 @@ void GcodeSuite::G33() { SERIAL_ECHOLNPGM("G33 Auto Calibrate"); // Report settings - PGM_P const checkingac = PSTR("Checking... AC"); - SERIAL_ECHOPGM_P(checkingac); - SERIAL_ECHOPGM(" at radius:", dcr); + FSTR_P const checkingac = F("Checking... AC"); + SERIAL_ECHO(checkingac, F(" at radius:"), dcr); if (verbose_level == 0) SERIAL_ECHOPGM(" (DRY-RUN)"); SERIAL_EOL(); ui.set_status(checkingac); @@ -480,8 +474,7 @@ void GcodeSuite::G33() { #if HAS_DELTA_SENSORLESS_PROBING if (verbose_level > 0 && do_save_offset_adj) { offset_sensorless_adj.reset(); - - auto caltower = [&](Probe::sense_bool_t s){ + auto caltower = [&](Probe::sense_bool_t s) { float z_at_pt[NPP + 1]; LOOP_CAL_ALL(rad) z_at_pt[rad] = 0.0f; probe.test_sensitivity = s; @@ -507,7 +500,7 @@ void GcodeSuite::G33() { zero_std_dev_old = zero_std_dev; if (!probe_calibration_points(z_at_pt, probe_points, dcr, towers_set, stow_after_each, probe_at_offset)) { SERIAL_ECHOLNPGM("Correct delta settings with M665 and M666"); - return ac_cleanup(TERN_(HAS_MULTI_HOTEND, old_tool_index)); + return ac_cleanup(); } zero_std_dev = std_dev_points(z_at_pt, _0p_calibration, _1p_calibration, _4p_calibration, _4p_opposite_points); @@ -641,53 +634,50 @@ void GcodeSuite::G33() { else #endif { - SERIAL_ECHOPAIR_F("std dev:", zero_std_dev_min, 3); + SERIAL_ECHOPGM("std dev:", p_float_t(zero_std_dev_min, 3)); } SERIAL_EOL(); - char mess[21]; - strcpy_P(mess, PSTR("Calibration sd:")); + + MString<20> msg(F("Calibration sd:")); if (zero_std_dev_min < 1) - sprintf_P(&mess[15], PSTR("0.%03i"), (int)LROUND(zero_std_dev_min * 1000.0f)); + msg.appendf(F("0.%03i"), (int)LROUND(zero_std_dev_min * 1000.0f)); else - sprintf_P(&mess[15], PSTR("%03i.x"), (int)LROUND(zero_std_dev_min)); - ui.set_status(mess); + msg.appendf(F("%03i.x"), (int)LROUND(zero_std_dev_min)); + ui.set_status(msg); print_calibration_settings(_endstop_results, _angle_results); SERIAL_ECHOLNPGM("Save with M500 and/or copy to Configuration.h"); } else { // !end iterations - char mess[15]; + SString<15> msg; if (iterations < 31) - sprintf_P(mess, PSTR("Iteration : %02i"), (unsigned int)iterations); + msg.setf(F("Iteration : %02i"), (unsigned int)iterations); else - strcpy_P(mess, PSTR("No convergence")); - SERIAL_ECHO(mess); + msg.set(F("No convergence")); + msg.echo(); SERIAL_ECHO_SP(32); - SERIAL_ECHOLNPAIR_F("std dev:", zero_std_dev, 3); - ui.set_status(mess); + SERIAL_ECHOLNPGM("std dev:", p_float_t(zero_std_dev, 3)); + ui.set_status(msg); if (verbose_level > 1) print_calibration_settings(_endstop_results, _angle_results); } } else { // dry run FSTR_P const enddryrun = F("End DRY-RUN"); - SERIAL_ECHOF(enddryrun); + SERIAL_ECHO(enddryrun); SERIAL_ECHO_SP(35); - SERIAL_ECHOLNPAIR_F("std dev:", zero_std_dev, 3); - - char mess[21]; - strcpy_P(mess, FTOP(enddryrun)); - strcpy_P(&mess[11], PSTR(" sd:")); + SERIAL_ECHOLNPGM("std dev:", p_float_t(zero_std_dev, 3)); + MString<30> msg(enddryrun, F(" sd:")); if (zero_std_dev < 1) - sprintf_P(&mess[15], PSTR("0.%03i"), (int)LROUND(zero_std_dev * 1000.0f)); + msg.appendf(F("0.%03i"), (int)LROUND(zero_std_dev * 1000.0f)); else - sprintf_P(&mess[15], PSTR("%03i.x"), (int)LROUND(zero_std_dev)); - ui.set_status(mess); + msg.appendf(F("%03i.x"), (int)LROUND(zero_std_dev)); + ui.set_status(msg); } ac_home(); } while (((zero_std_dev < test_precision && iterations < 31) || iterations <= force_iterations) && zero_std_dev > calibration_precision); - ac_cleanup(TERN_(HAS_MULTI_HOTEND, old_tool_index)); + ac_cleanup(); TERN_(FULL_REPORT_TO_HOST_FEATURE, set_and_report_grblstate(M_IDLE)); #if HAS_DELTA_SENSORLESS_PROBING diff --git a/Marlin/src/gcode/calibrate/G34.cpp b/Marlin/src/gcode/calibrate/G34.cpp index 1be3952ffe..9a0cb0054b 100644 --- a/Marlin/src/gcode/calibrate/G34.cpp +++ b/Marlin/src/gcode/calibrate/G34.cpp @@ -39,6 +39,23 @@ #define DEBUG_OUT ENABLED(DEBUG_LEVELING_FEATURE) #include "../../core/debug_out.h" +/** + * G34 - Align the ends of the X gantry. See https://youtu.be/3jAFQdTk8iw + * + * - The carriage moves to GANTRY_CALIBRATION_SAFE_POSITION, also called the “pounce†position. + * - If possible, the Z stepper current is reduced to the value specified by 'S' + * (or GANTRY_CALIBRATION_CURRENT) to prevent damage to steppers and other parts. + * The reduced current should be just high enough to move the Z axis when not blocked. + * - The Z axis is jogged past the Z limit, only as far as the specified Z distance + * (or GANTRY_CALIBRATION_EXTRA_HEIGHT) at the GANTRY_CALIBRATION_FEEDRATE. + * - The Z axis is moved back to the working area (also at GANTRY_CALIBRATION_FEEDRATE). + * - Stepper current is restored back to normal. + * - The machine is re-homed, according to GANTRY_CALIBRATION_COMMANDS_POST. + * + * Parameters: + * [S] - Current value to use for the raise move. (Default: GANTRY_CALIBRATION_CURRENT) + * [Z] - Extra distance past Z_MAX_POS to move the Z axis. (Default: GANTRY_CALIBRATION_EXTRA_HEIGHT) + */ void GcodeSuite::G34() { // Home before the alignment procedure @@ -58,7 +75,7 @@ void GcodeSuite::G34() { // Move XY to safe position if (DEBUGGING(LEVELING)) DEBUG_ECHOLNPGM("Parking XY"); const xy_pos_t safe_pos = GANTRY_CALIBRATION_SAFE_POSITION; - do_blocking_move_to(safe_pos, MMM_TO_MMS(GANTRY_CALIBRATION_XY_PARK_FEEDRATE)); + do_blocking_move_to_xy(safe_pos, MMM_TO_MMS(GANTRY_CALIBRATION_XY_PARK_FEEDRATE)); #endif const float move_distance = parser.intval('Z', GANTRY_CALIBRATION_EXTRA_HEIGHT), diff --git a/Marlin/src/gcode/calibrate/G34_M422.cpp b/Marlin/src/gcode/calibrate/G34_M422.cpp index c5d25c6235..e07f0bb3f8 100644 --- a/Marlin/src/gcode/calibrate/G34_M422.cpp +++ b/Marlin/src/gcode/calibrate/G34_M422.cpp @@ -22,7 +22,7 @@ #include "../../inc/MarlinConfigPre.h" -#if EITHER(Z_MULTI_ENDSTOPS, Z_STEPPER_AUTO_ALIGN) +#if ANY(Z_MULTI_ENDSTOPS, Z_STEPPER_AUTO_ALIGN) #include "../../feature/z_stepper_align.h" @@ -79,6 +79,7 @@ * R Flag to recalculate points based on current probe offsets */ void GcodeSuite::G34() { + DEBUG_SECTION(log_G34, "G34", DEBUGGING(LEVELING)); if (DEBUGGING(LEVELING)) log_machine_info(); @@ -108,6 +109,7 @@ void GcodeSuite::G34() { } #if ENABLED(Z_STEPPER_AUTO_ALIGN) + do { // break out on error const int8_t z_auto_align_iterations = parser.intval('I', Z_STEPPER_ALIGN_ITERATIONS); @@ -142,26 +144,18 @@ void GcodeSuite::G34() { TERN_(CNC_WORKSPACE_PLANES, workspace_plane = PLANE_XY); - // Always home with tool 0 active - #if HAS_MULTI_HOTEND - const uint8_t old_tool_index = active_extruder; - tool_change(0, true); - #endif + probe.use_probing_tool(); TERN_(HAS_DUPLICATION_MODE, set_duplication_enabled(false)); - // In BLTOUCH HS mode, the probe travels in a deployed state. - // Users of G34 might have a badly misaligned bed, so raise Z by the - // length of the deployed pin (BLTOUCH stroke < 7mm) - #define Z_BASIC_CLEARANCE (Z_CLEARANCE_BETWEEN_PROBES + TERN0(BLTOUCH, bltouch.z_extra_clearance())) - // Compute a worst-case clearance height to probe from. After the first // iteration this will be re-calculated based on the actual bed position auto magnitude2 = [&](const uint8_t i, const uint8_t j) { const xy_pos_t diff = z_stepper_align.xy[i] - z_stepper_align.xy[j]; return HYPOT2(diff.x, diff.y); }; - float z_probe = Z_BASIC_CLEARANCE + (G34_MAX_GRADE) * 0.01f * SQRT(_MAX(0, magnitude2(0, 1) + const float zoffs = (probe.offset.z < 0) ? -probe.offset.z : 0.0f; + float z_probe = (Z_TWEEN_SAFE_CLEARANCE + zoffs) + (G34_MAX_GRADE) * 0.01f * SQRT(_MAX(0, magnitude2(0, 1) #if TRIPLE_Z , magnitude2(2, 1), magnitude2(2, 0) #if QUAD_Z @@ -173,12 +167,6 @@ void GcodeSuite::G34() { // Home before the alignment procedure home_if_needed(); - // Move the Z coordinate realm towards the positive - dirty trick - current_position.z += z_probe * 0.5f; - sync_plan_position(); - // Now, the Z origin lies below the build plate. That allows to probe deeper, before run_z_probe throws an error. - // This hack is un-done at the end of G34 - either by re-homing, or by using the probed heights of the last iteration. - #if !HAS_Z_STEPPER_ALIGN_STEPPER_XY float last_z_align_move[NUM_Z_STEPPERS] = ARRAY_N_1(NUM_Z_STEPPERS, 10000.0f); #else @@ -217,24 +205,20 @@ void GcodeSuite::G34() { float z_measured_max = -100000.0f; // Probe all positions (one per Z-Stepper) - LOOP_L_N(i, NUM_Z_STEPPERS) { + for (uint8_t i = 0; i < NUM_Z_STEPPERS; ++i) { // iteration odd/even --> downward / upward stepper sequence const uint8_t iprobe = (iteration & 1) ? NUM_Z_STEPPERS - 1 - i : i; - // Safe clearance even on an incline - if ((iteration == 0 || i > 0) && z_probe > current_position.z) do_blocking_move_to_z(z_probe); - xy_pos_t &ppos = z_stepper_align.xy[iprobe]; - if (DEBUGGING(LEVELING)) - DEBUG_ECHOLNPGM_P(PSTR("Probing X"), ppos.x, SP_Y_STR, ppos.y); + if (DEBUGGING(LEVELING)) DEBUG_ECHOLNPGM_P(PSTR("Probing X"), ppos.x, SP_Y_STR, ppos.y); // Probe a Z height for each stepper. // Probing sanity check is disabled, as it would trigger even in normal cases because // current_position.z has been manually altered in the "dirty trick" above. const float z_probed_height = probe.probe_at_point(RAW_X_POSITION(z_stepper_align.xy[iprobe].x), RAW_Y_POSITION(z_stepper_align.xy[iprobe].y), raise_after, 0, true, false); if (isnan(z_probed_height)) { - SERIAL_ECHOLNPGM("Probing failed"); + SERIAL_ECHOLNPGM(STR_ERR_PROBING_FAILED); LCD_MESSAGE(MSG_LCD_PROBING_FAILED); err_break = true; break; @@ -242,7 +226,7 @@ void GcodeSuite::G34() { // Add height to each value, to provide a more useful target height for // the next iteration of probing. This allows adjustments to be made away from the bed. - z_measured[iprobe] = z_probed_height + Z_CLEARANCE_BETWEEN_PROBES; + z_measured[iprobe] = z_probed_height + (Z_TWEEN_SAFE_CLEARANCE + zoffs); //do we need to add the clearance to this? if (DEBUGGING(LEVELING)) DEBUG_ECHOLNPGM("> Z", iprobe + 1, " measured position is ", z_measured[iprobe]); @@ -256,7 +240,7 @@ void GcodeSuite::G34() { // Adapt the next probe clearance height based on the new measurements. // Safe_height = lowest distance to bed (= highest measurement) plus highest measured misalignment. z_maxdiff = z_measured_max - z_measured_min; - z_probe = Z_BASIC_CLEARANCE + z_measured_max + z_maxdiff; + z_probe = (Z_TWEEN_SAFE_CLEARANCE + zoffs) + z_measured_max + z_maxdiff; //Not sure we need z_maxdiff, but leaving it in for safety. #if HAS_Z_STEPPER_ALIGN_STEPPER_XY // Replace the initial values in z_measured with calculated heights at @@ -272,14 +256,14 @@ void GcodeSuite::G34() { // This allows the actual adjustment logic to be shared by both algorithms. linear_fit_data lfd; incremental_LSF_reset(&lfd); - LOOP_L_N(i, NUM_Z_STEPPERS) { + for (uint8_t i = 0; i < NUM_Z_STEPPERS; ++i) { SERIAL_ECHOLNPGM("PROBEPT_", i, ": ", z_measured[i]); incremental_LSF(&lfd, z_stepper_align.xy[i], z_measured[i]); } finish_incremental_LSF(&lfd); z_measured_min = 100000.0f; - LOOP_L_N(i, NUM_Z_STEPPERS) { + for (uint8_t i = 0; i < NUM_Z_STEPPERS; ++i) { z_measured[i] = -(lfd.A * z_stepper_align.stepper_xy[i].x + lfd.B * z_stepper_align.stepper_xy[i].y + lfd.D); z_measured_min = _MIN(z_measured_min, z_measured[i]); } @@ -294,42 +278,21 @@ void GcodeSuite::G34() { ); #endif - SERIAL_ECHOLNPGM("\n" - "Z2-Z1=", ABS(z_measured[1] - z_measured[0]) - #if TRIPLE_Z - , " Z3-Z2=", ABS(z_measured[2] - z_measured[1]) - , " Z3-Z1=", ABS(z_measured[2] - z_measured[0]) - #if QUAD_Z - , " Z4-Z3=", ABS(z_measured[3] - z_measured[2]) - , " Z4-Z2=", ABS(z_measured[3] - z_measured[1]) - , " Z4-Z1=", ABS(z_measured[3] - z_measured[0]) - #endif - #endif - ); + SERIAL_EOL(); - #if HAS_STATUS_MESSAGE - char fstr1[10]; - char msg[6 + (6 + 5) * NUM_Z_STEPPERS + 1] - #if TRIPLE_Z - , fstr2[10], fstr3[10] - #if QUAD_Z - , fstr4[10], fstr5[10], fstr6[10] - #endif - #endif - ; - sprintf_P(msg, - PSTR("1:2=%s" TERN_(TRIPLE_Z, " 3-2=%s 3-1=%s") TERN_(QUAD_Z, " 4-3=%s 4-2=%s 4-1=%s")), - dtostrf(ABS(z_measured[1] - z_measured[0]), 1, 3, fstr1) - OPTARG(TRIPLE_Z, - dtostrf(ABS(z_measured[2] - z_measured[1]), 1, 3, fstr2), - dtostrf(ABS(z_measured[2] - z_measured[0]), 1, 3, fstr3)) - OPTARG(QUAD_Z, - dtostrf(ABS(z_measured[3] - z_measured[2]), 1, 3, fstr4), - dtostrf(ABS(z_measured[3] - z_measured[1]), 1, 3, fstr5), - dtostrf(ABS(z_measured[3] - z_measured[0]), 1, 3, fstr6)) - ); - ui.set_status(msg); + SString<15 + TERN0(TRIPLE_Z, 30) + TERN0(QUAD_Z, 45)> msg(F("1:2="), p_float_t(ABS(z_measured[1] - z_measured[0]), 3)); + #if TRIPLE_Z + msg.append(F(" 3-2="), p_float_t(ABS(z_measured[2] - z_measured[1]), 3)) + .append(F(" 3-1="), p_float_t(ABS(z_measured[2] - z_measured[0]), 3)); #endif + #if QUAD_Z + msg.append(F(" 4-3="), p_float_t(ABS(z_measured[3] - z_measured[2]), 3)) + .append(F(" 4-2="), p_float_t(ABS(z_measured[3] - z_measured[1]), 3)) + .append(F(" 4-1="), p_float_t(ABS(z_measured[3] - z_measured[0]), 3)); + #endif + + msg.echoln(); + ui.set_status(msg); auto decreasing_accuracy = [](const_float_t v1, const_float_t v2) { if (v1 < v2 * 0.7f) { @@ -347,12 +310,12 @@ void GcodeSuite::G34() { // Calculate mean value as a reference float z_measured_mean = 0.0f; - LOOP_L_N(zstepper, NUM_Z_STEPPERS) z_measured_mean += z_measured[zstepper]; + for (uint8_t zstepper = 0; zstepper < NUM_Z_STEPPERS; ++zstepper) z_measured_mean += z_measured[zstepper]; z_measured_mean /= NUM_Z_STEPPERS; // Calculate the sum of the absolute deviations from the mean value float z_align_level_indicator = 0.0f; - LOOP_L_N(zstepper, NUM_Z_STEPPERS) + for (uint8_t zstepper = 0; zstepper < NUM_Z_STEPPERS; ++zstepper) z_align_level_indicator += ABS(z_measured[zstepper] - z_measured_mean); // If it's getting worse, stop and throw an error @@ -367,7 +330,7 @@ void GcodeSuite::G34() { bool success_break = true; // Correct the individual stepper offsets - LOOP_L_N(zstepper, NUM_Z_STEPPERS) { + for (uint8_t zstepper = 0; zstepper < NUM_Z_STEPPERS; ++zstepper) { // Calculate current stepper move float z_align_move = z_measured[zstepper] - z_measured_min; const float z_align_abs = ABS(z_align_move); @@ -428,7 +391,7 @@ void GcodeSuite::G34() { SERIAL_ECHOLNPGM("G34 aborted."); else { SERIAL_ECHOLNPGM("Did ", iteration + (iteration != z_auto_align_iterations), " of ", z_auto_align_iterations); - SERIAL_ECHOLNPAIR_F("Accuracy: ", z_maxdiff); + SERIAL_ECHOLNPGM("Accuracy: ", p_float_t(z_maxdiff, 2)); } // Stow the probe because the last call to probe.probe_at_point(...) @@ -436,26 +399,26 @@ void GcodeSuite::G34() { IF_DISABLED(TOUCH_MI_PROBE, probe.stow()); #if ENABLED(HOME_AFTER_G34) - // After this operation the z position needs correction - set_axis_never_homed(Z_AXIS); // Home Z after the alignment procedure process_subcommands_now(F("G28Z")); #else // Use the probed height from the last iteration to determine the Z height. // z_measured_min is used, because all steppers are aligned to z_measured_min. // Ideally, this would be equal to the 'z_probe * 0.5f' which was added earlier. - current_position.z -= z_measured_min - (float)Z_CLEARANCE_BETWEEN_PROBES; + current_position.z -= z_measured_min - (Z_TWEEN_SAFE_CLEARANCE + zoffs); //we shouldn't want to subtract the clearance from here right? (Depends if we added it further up) sync_plan_position(); #endif - // Restore the active tool after homing - TERN_(HAS_MULTI_HOTEND, tool_change(old_tool_index, DISABLED(PARKING_EXTRUDER))); // Fetch previous tool for parking extruder + probe.use_probing_tool(false); - #if BOTH(HAS_LEVELING, RESTORE_LEVELING_AFTER_G34) + #if ALL(HAS_LEVELING, RESTORE_LEVELING_AFTER_G34) set_bed_leveling_enabled(leveling_was_active); #endif }while(0); + + probe.use_probing_tool(false); + #endif // Z_STEPPER_AUTO_ALIGN } @@ -518,8 +481,7 @@ void GcodeSuite::M422() { } if (!WITHIN(position_index, 1, NUM_Z_STEPPERS)) { - SERIAL_ECHOF(err_string); - SERIAL_ECHOLNPGM(" index invalid (1.." STRINGIFY(NUM_Z_STEPPERS) ")."); + SERIAL_ECHOLN(err_string, F(" index invalid (1.." STRINGIFY(NUM_Z_STEPPERS) ").")); return; } @@ -546,7 +508,7 @@ void GcodeSuite::M422() { void GcodeSuite::M422_report(const bool forReplay/*=true*/) { report_heading(forReplay, F(STR_Z_AUTO_ALIGN)); - LOOP_L_N(i, NUM_Z_STEPPERS) { + for (uint8_t i = 0; i < NUM_Z_STEPPERS; ++i) { report_echo_start(forReplay); SERIAL_ECHOLNPGM_P( PSTR(" M422 S"), i + 1, @@ -555,7 +517,7 @@ void GcodeSuite::M422_report(const bool forReplay/*=true*/) { ); } #if HAS_Z_STEPPER_ALIGN_STEPPER_XY - LOOP_L_N(i, NUM_Z_STEPPERS) { + for (uint8_t i = 0; i < NUM_Z_STEPPERS; ++i) { report_echo_start(forReplay); SERIAL_ECHOLNPGM_P( PSTR(" M422 W"), i + 1, diff --git a/Marlin/src/gcode/calibrate/G425.cpp b/Marlin/src/gcode/calibrate/G425.cpp index 008a8fe11c..05ba6106d1 100644 --- a/Marlin/src/gcode/calibrate/G425.cpp +++ b/Marlin/src/gcode/calibrate/G425.cpp @@ -70,7 +70,7 @@ #define CALIBRATION_MEASUREMENT_CERTAIN 0.5 // mm #endif -#if BOTH(CALIBRATION_MEASURE_LEFT, CALIBRATION_MEASURE_RIGHT) +#if ALL(HAS_X_AXIS, CALIBRATION_MEASURE_LEFT, CALIBRATION_MEASURE_RIGHT) #define HAS_X_CENTER 1 #endif #if ALL(HAS_Y_AXIS, CALIBRATION_MEASURE_FRONT, CALIBRATION_MEASURE_BACK) @@ -171,7 +171,7 @@ inline void park_above_object(measurements_t &m, const float uncertainty) { #if HAS_HOTEND_OFFSET inline void normalize_hotend_offsets() { - LOOP_S_L_N(e, 1, HOTENDS) + for (uint8_t e = 1; e < HOTENDS; ++e) hotend_offset[e] -= hotend_offset[0]; hotend_offset[0].reset(); } @@ -271,10 +271,10 @@ inline void probe_side(measurements_t &m, const float uncertainty, const side_t #if AXIS_CAN_CALIBRATE(X) _ACASE(X, RIGHT, LEFT); #endif - #if HAS_Y_AXIS && AXIS_CAN_CALIBRATE(Y) + #if AXIS_CAN_CALIBRATE(Y) _ACASE(Y, BACK, FRONT); #endif - #if HAS_Z_AXIS && AXIS_CAN_CALIBRATE(Z) + #if AXIS_CAN_CALIBRATE(Z) case TOP: { const float measurement = measure(Z_AXIS, -1, true, &m.backlash[TOP], uncertainty); m.obj_center.z = measurement - dimensions.z / 2; @@ -282,22 +282,22 @@ inline void probe_side(measurements_t &m, const float uncertainty, const side_t return; } #endif - #if HAS_I_AXIS && AXIS_CAN_CALIBRATE(I) + #if AXIS_CAN_CALIBRATE(I) _PCASE(I); #endif - #if HAS_J_AXIS && AXIS_CAN_CALIBRATE(J) + #if AXIS_CAN_CALIBRATE(J) _PCASE(J); #endif - #if HAS_K_AXIS && AXIS_CAN_CALIBRATE(K) + #if AXIS_CAN_CALIBRATE(K) _PCASE(K); #endif - #if HAS_U_AXIS && AXIS_CAN_CALIBRATE(U) + #if AXIS_CAN_CALIBRATE(U) _PCASE(U); #endif - #if HAS_V_AXIS && AXIS_CAN_CALIBRATE(V) + #if AXIS_CAN_CALIBRATE(V) _PCASE(V); #endif - #if HAS_W_AXIS && AXIS_CAN_CALIBRATE(W) + #if AXIS_CAN_CALIBRATE(W) _PCASE(W); #endif default: return; @@ -395,14 +395,16 @@ inline void probe_sides(measurements_t &m, const float uncertainty) { #if ENABLED(CALIBRATION_REPORTING) inline void report_measured_faces(const measurements_t &m) { SERIAL_ECHOLNPGM("Sides:"); - #if HAS_Z_AXIS && AXIS_CAN_CALIBRATE(Z) + #if AXIS_CAN_CALIBRATE(Z) SERIAL_ECHOLNPGM(" Top: ", m.obj_side[TOP]); #endif - #if ENABLED(CALIBRATION_MEASURE_LEFT) - SERIAL_ECHOLNPGM(" Left: ", m.obj_side[LEFT]); - #endif - #if ENABLED(CALIBRATION_MEASURE_RIGHT) - SERIAL_ECHOLNPGM(" Right: ", m.obj_side[RIGHT]); + #if HAS_X_AXIS + #if ENABLED(CALIBRATION_MEASURE_LEFT) + SERIAL_ECHOLNPGM(" Left: ", m.obj_side[LEFT]); + #endif + #if ENABLED(CALIBRATION_MEASURE_RIGHT) + SERIAL_ECHOLNPGM(" Right: ", m.obj_side[RIGHT]); + #endif #endif #if HAS_Y_AXIS #if ENABLED(CALIBRATION_MEASURE_FRONT) @@ -503,7 +505,7 @@ inline void probe_sides(measurements_t &m, const float uncertainty) { SERIAL_ECHOLNPGM(" Right: ", m.backlash[RIGHT]); #endif #endif - #if HAS_Y_AXIS && AXIS_CAN_CALIBRATE(Y) + #if AXIS_CAN_CALIBRATE(Y) #if ENABLED(CALIBRATION_MEASURE_FRONT) SERIAL_ECHOLNPGM(" Front: ", m.backlash[FRONT]); #endif @@ -511,10 +513,10 @@ inline void probe_sides(measurements_t &m, const float uncertainty) { SERIAL_ECHOLNPGM(" Back: ", m.backlash[BACK]); #endif #endif - #if HAS_Z_AXIS && AXIS_CAN_CALIBRATE(Z) + #if AXIS_CAN_CALIBRATE(Z) SERIAL_ECHOLNPGM(" Top: ", m.backlash[TOP]); #endif - #if HAS_I_AXIS && AXIS_CAN_CALIBRATE(I) + #if AXIS_CAN_CALIBRATE(I) #if ENABLED(CALIBRATION_MEASURE_IMIN) SERIAL_ECHOLNPGM(" " STR_I_MIN ": ", m.backlash[IMINIMUM]); #endif @@ -522,7 +524,7 @@ inline void probe_sides(measurements_t &m, const float uncertainty) { SERIAL_ECHOLNPGM(" " STR_I_MAX ": ", m.backlash[IMAXIMUM]); #endif #endif - #if HAS_J_AXIS && AXIS_CAN_CALIBRATE(J) + #if AXIS_CAN_CALIBRATE(J) #if ENABLED(CALIBRATION_MEASURE_JMIN) SERIAL_ECHOLNPGM(" " STR_J_MIN ": ", m.backlash[JMINIMUM]); #endif @@ -530,7 +532,7 @@ inline void probe_sides(measurements_t &m, const float uncertainty) { SERIAL_ECHOLNPGM(" " STR_J_MAX ": ", m.backlash[JMAXIMUM]); #endif #endif - #if HAS_K_AXIS && AXIS_CAN_CALIBRATE(K) + #if AXIS_CAN_CALIBRATE(K) #if ENABLED(CALIBRATION_MEASURE_KMIN) SERIAL_ECHOLNPGM(" " STR_K_MIN ": ", m.backlash[KMINIMUM]); #endif @@ -538,7 +540,7 @@ inline void probe_sides(measurements_t &m, const float uncertainty) { SERIAL_ECHOLNPGM(" " STR_K_MAX ": ", m.backlash[KMAXIMUM]); #endif #endif - #if HAS_U_AXIS && AXIS_CAN_CALIBRATE(U) + #if AXIS_CAN_CALIBRATE(U) #if ENABLED(CALIBRATION_MEASURE_UMIN) SERIAL_ECHOLNPGM(" " STR_U_MIN ": ", m.backlash[UMINIMUM]); #endif @@ -546,7 +548,7 @@ inline void probe_sides(measurements_t &m, const float uncertainty) { SERIAL_ECHOLNPGM(" " STR_U_MAX ": ", m.backlash[UMAXIMUM]); #endif #endif - #if HAS_V_AXIS && AXIS_CAN_CALIBRATE(V) + #if AXIS_CAN_CALIBRATE(V) #if ENABLED(CALIBRATION_MEASURE_VMIN) SERIAL_ECHOLNPGM(" " STR_V_MIN ": ", m.backlash[VMINIMUM]); #endif @@ -554,7 +556,7 @@ inline void probe_sides(measurements_t &m, const float uncertainty) { SERIAL_ECHOLNPGM(" " STR_V_MAX ": ", m.backlash[VMAXIMUM]); #endif #endif - #if HAS_W_AXIS && AXIS_CAN_CALIBRATE(W) + #if AXIS_CAN_CALIBRATE(W) #if ENABLED(CALIBRATION_MEASURE_WMIN) SERIAL_ECHOLNPGM(" " STR_W_MIN ": ", m.backlash[WMINIMUM]); #endif @@ -575,7 +577,7 @@ inline void probe_sides(measurements_t &m, const float uncertainty) { #if HAS_Y_CENTER && AXIS_CAN_CALIBRATE(Y) SERIAL_ECHOLNPGM_P(SP_Y_STR, m.pos_error.y); #endif - #if HAS_Z_AXIS && AXIS_CAN_CALIBRATE(Z) + #if AXIS_CAN_CALIBRATE(Z) SERIAL_ECHOLNPGM_P(SP_Z_STR, m.pos_error.z); #endif #if HAS_I_CENTER && AXIS_CAN_CALIBRATE(I) @@ -616,7 +618,7 @@ inline void probe_sides(measurements_t &m, const float uncertainty) { // This function requires normalize_hotend_offsets() to be called // inline void report_hotend_offsets() { - LOOP_S_L_N(e, 1, HOTENDS) + for (uint8_t e = 1; e < HOTENDS; ++e) SERIAL_ECHOLNPGM_P(PSTR("T"), e, PSTR(" Hotend Offset X"), hotend_offset[e].x, SP_Y_STR, hotend_offset[e].y, SP_Z_STR, hotend_offset[e].z); } #endif diff --git a/Marlin/src/gcode/calibrate/G76_M871.cpp b/Marlin/src/gcode/calibrate/G76_M871.cpp index c484d4f1b7..bb69b75d50 100644 --- a/Marlin/src/gcode/calibrate/G76_M871.cpp +++ b/Marlin/src/gcode/calibrate/G76_M871.cpp @@ -34,7 +34,6 @@ #include "../../module/probe.h" #include "../../feature/bedlevel/bedlevel.h" #include "../../module/temperature.h" -#include "../../module/probe.h" #include "../../feature/probe_temp_comp.h" #include "../../lcd/marlinui.h" @@ -82,7 +81,7 @@ * - `P` - Run probe temperature calibration. */ -#if BOTH(PTC_PROBE, PTC_BED) +#if ALL(PTC_PROBE, PTC_BED) static void say_waiting_for() { SERIAL_ECHOPGM("Waiting for "); } static void say_waiting_for_probe_heating() { say_waiting_for(); SERIAL_ECHOLNPGM("probe heating."); } @@ -108,14 +107,13 @@ }; auto g76_probe = [](const TempSensorID sid, celsius_t &targ, const xy_pos_t &nozpos) { - do_z_clearance(5.0); // Raise nozzle before probing ptc.set_enabled(false); const float measured_z = probe.probe_at_point(nozpos, PROBE_PT_STOW, 0, false); // verbose=0, probe_relative=false ptc.set_enabled(true); if (isnan(measured_z)) SERIAL_ECHOLNPGM("!Received NAN. Aborting."); else { - SERIAL_ECHOLNPAIR_F("Measured: ", measured_z); + SERIAL_ECHOLNPGM("Measured: ", p_float_t(measured_z, 2)); if (targ == ProbeTempComp::cali_info[sid].start_temp) ptc.prepare_new_calibration(measured_z); else @@ -258,7 +256,7 @@ say_waiting_for_probe_heating(); SERIAL_ECHOLNPGM(" Bed:", target_bed, " Probe:", target_probe); - const millis_t probe_timeout_ms = millis() + SEC_TO_MS(900UL); + const millis_t probe_timeout_ms = millis() + MIN_TO_MS(15); while (thermalManager.degProbe() < target_probe) { if (report_temps(next_temp_report, probe_timeout_ms)) { SERIAL_ECHOLNPGM("!Probe heating timed out."); diff --git a/Marlin/src/gcode/calibrate/M100.cpp b/Marlin/src/gcode/calibrate/M100.cpp index 338392b597..c05fe12fc3 100644 --- a/Marlin/src/gcode/calibrate/M100.cpp +++ b/Marlin/src/gcode/calibrate/M100.cpp @@ -60,7 +60,7 @@ #define TEST_BYTE ((char) 0xE5) -#if EITHER(__AVR__, IS_32BIT_TEENSY) +#if ANY(__AVR__, IS_32BIT_TEENSY) extern char __bss_end; char *end_bss = &__bss_end, @@ -163,14 +163,14 @@ inline int32_t count_test_bytes(const char * const start_free_memory) { while (start_free_memory < end_free_memory) { print_hex_address(start_free_memory); // Print the address SERIAL_CHAR(':'); - LOOP_L_N(i, 16) { // and 16 data bytes + for (uint8_t i = 0; i < 16; ++i) { // and 16 data bytes if (i == 8) SERIAL_CHAR('-'); print_hex_byte(start_free_memory[i]); SERIAL_CHAR(' '); } serial_delay(25); SERIAL_CHAR('|'); // Point out non test bytes - LOOP_L_N(i, 16) { + for (uint8_t i = 0; i < 16; ++i) { char ccc = (char)start_free_memory[i]; // cast to char before automatically casting to char on assignment, in case the compiler is broken ccc = (ccc == TEST_BYTE) ? ' ' : '?'; SERIAL_CHAR(ccc); @@ -183,7 +183,7 @@ inline int32_t count_test_bytes(const char * const start_free_memory) { } void M100_dump_routine(FSTR_P const title, const char * const start, const uintptr_t size) { - SERIAL_ECHOLNF(title); + SERIAL_ECHOLN(title); // // Round the start and end locations to produce full lines of output // @@ -197,7 +197,7 @@ inline int32_t count_test_bytes(const char * const start_free_memory) { #endif // M100_FREE_MEMORY_DUMPER inline int check_for_free_memory_corruption(FSTR_P const title) { - SERIAL_ECHOF(title); + SERIAL_ECHO(title); char *start_free_memory = free_memory_start, *end_free_memory = free_memory_end; int n = end_free_memory - start_free_memory; diff --git a/Marlin/src/gcode/calibrate/M425.cpp b/Marlin/src/gcode/calibrate/M425.cpp index a6c6ff9dae..cd206ca489 100644 --- a/Marlin/src/gcode/calibrate/M425.cpp +++ b/Marlin/src/gcode/calibrate/M425.cpp @@ -46,12 +46,13 @@ void GcodeSuite::M425() { bool noArgs = true; - auto axis_can_calibrate = [](const uint8_t a) { - #define _CAN_CASE(N) case N##_AXIS: return AXIS_CAN_CALIBRATE(N); + auto axis_can_calibrate = [](const uint8_t a) -> bool { + #define _CAN_CASE(N) case N##_AXIS: return bool(AXIS_CAN_CALIBRATE(N)); switch (a) { - default: return false; MAIN_AXIS_MAP(_CAN_CASE) + default: break; } + return false; }; LOOP_NUM_AXES(a) { @@ -111,17 +112,19 @@ void GcodeSuite::M425_report(const bool forReplay/*=true*/) { #ifdef BACKLASH_SMOOTHING_MM , PSTR(" S"), LINEAR_UNIT(backlash.get_smoothing_mm()) #endif - , LIST_N(DOUBLE(NUM_AXES), - SP_X_STR, LINEAR_UNIT(backlash.get_distance_mm(X_AXIS)), - SP_Y_STR, LINEAR_UNIT(backlash.get_distance_mm(Y_AXIS)), - SP_Z_STR, LINEAR_UNIT(backlash.get_distance_mm(Z_AXIS)), - SP_I_STR, I_AXIS_UNIT(backlash.get_distance_mm(I_AXIS)), - SP_J_STR, J_AXIS_UNIT(backlash.get_distance_mm(J_AXIS)), - SP_K_STR, K_AXIS_UNIT(backlash.get_distance_mm(K_AXIS)), - SP_U_STR, U_AXIS_UNIT(backlash.get_distance_mm(U_AXIS)), - SP_V_STR, V_AXIS_UNIT(backlash.get_distance_mm(V_AXIS)), - SP_W_STR, W_AXIS_UNIT(backlash.get_distance_mm(W_AXIS)) - ) + #if NUM_AXES + , LIST_N(DOUBLE(NUM_AXES), + SP_X_STR, LINEAR_UNIT(backlash.get_distance_mm(X_AXIS)), + SP_Y_STR, LINEAR_UNIT(backlash.get_distance_mm(Y_AXIS)), + SP_Z_STR, LINEAR_UNIT(backlash.get_distance_mm(Z_AXIS)), + SP_I_STR, I_AXIS_UNIT(backlash.get_distance_mm(I_AXIS)), + SP_J_STR, J_AXIS_UNIT(backlash.get_distance_mm(J_AXIS)), + SP_K_STR, K_AXIS_UNIT(backlash.get_distance_mm(K_AXIS)), + SP_U_STR, U_AXIS_UNIT(backlash.get_distance_mm(U_AXIS)), + SP_V_STR, V_AXIS_UNIT(backlash.get_distance_mm(V_AXIS)), + SP_W_STR, W_AXIS_UNIT(backlash.get_distance_mm(W_AXIS)) + ) + #endif ); } diff --git a/Marlin/src/gcode/calibrate/M48.cpp b/Marlin/src/gcode/calibrate/M48.cpp index 8b6ea0bf1f..2d219a07c5 100644 --- a/Marlin/src/gcode/calibrate/M48.cpp +++ b/Marlin/src/gcode/calibrate/M48.cpp @@ -84,7 +84,7 @@ void GcodeSuite::M48() { }; if (!probe.can_reach(test_position)) { - ui.set_status(GET_TEXT_F(MSG_M48_OUT_OF_BOUNDS), 99); + LCD_MESSAGE_MAX(MSG_M48_OUT_OF_BOUNDS); SERIAL_ECHOLNPGM("? (X,Y) out of bounds."); return; } @@ -112,7 +112,7 @@ void GcodeSuite::M48() { set_bed_leveling_enabled(false); #endif - TERN_(HAS_PTC, ptc.set_enabled(!parser.seen('C') || parser.value_bool())); + TERN_(HAS_PTC, ptc.set_enabled(parser.boolval('C', true))); // Work with reasonable feedrates remember_feedrate_scaling_off(); @@ -126,15 +126,13 @@ void GcodeSuite::M48() { auto dev_report = [](const bool verbose, const_float_t mean, const_float_t sigma, const_float_t min, const_float_t max, const bool final=false) { if (verbose) { - SERIAL_ECHOPAIR_F("Mean: ", mean, 6); - if (!final) SERIAL_ECHOPAIR_F(" Sigma: ", sigma, 6); - SERIAL_ECHOPAIR_F(" Min: ", min, 3); - SERIAL_ECHOPAIR_F(" Max: ", max, 3); - SERIAL_ECHOPAIR_F(" Range: ", max-min, 3); + SERIAL_ECHOPGM("Mean: ", p_float_t(mean, 6)); + if (!final) SERIAL_ECHOPGM(" Sigma: ", p_float_t(sigma, 6)); + SERIAL_ECHOPGM(" Min: ", p_float_t(min, 3), " Max: ", p_float_t(max, 3), " Range: ", p_float_t(max-min, 3)); if (final) SERIAL_EOL(); } if (final) { - SERIAL_ECHOLNPAIR_F("Standard Deviation: ", sigma, 6); + SERIAL_ECHOLNPGM("Standard Deviation: ", p_float_t(sigma, 6)); SERIAL_EOL(); } }; @@ -148,7 +146,7 @@ void GcodeSuite::M48() { float sample_sum = 0.0; - LOOP_L_N(n, n_samples) { + for (uint8_t n = 0; n < n_samples; ++n) { #if HAS_STATUS_MESSAGE // Display M48 progress in the status bar ui.status_printf(0, F(S_FMT ": %d/%d"), GET_TEXT(MSG_M48_POINT), int(n + 1), int(n_samples)); @@ -162,8 +160,8 @@ void GcodeSuite::M48() { float angle = random(0, 360); const float radius = random( #if ENABLED(DELTA) - int(0.1250000000 * (DELTA_PRINTABLE_RADIUS)), - int(0.3333333333 * (DELTA_PRINTABLE_RADIUS)) + int(0.1250000000 * (PRINTABLE_RADIUS)), + int(0.3333333333 * (PRINTABLE_RADIUS)) #else int(5), int(0.125 * _MIN(X_BED_SIZE, Y_BED_SIZE)) #endif @@ -175,7 +173,7 @@ void GcodeSuite::M48() { } // Move from leg to leg in rapid succession - LOOP_L_N(l, n_legs - 1) { + for (uint8_t l = 0; l < n_legs - 1; ++l) { // Move some distance around the perimeter float delta_angle; @@ -207,7 +205,7 @@ void GcodeSuite::M48() { while (!probe.can_reach(next_pos)) { next_pos *= 0.8f; if (verbose_level > 3) - SERIAL_ECHOLNPGM_P(PSTR("Moving inward: X"), next_pos.x, SP_Y_STR, next_pos.y); + SERIAL_ECHOLN(F("Moving inward: X"), next_pos.x, FPSTR(SP_Y_STR), next_pos.y); } #elif HAS_ENDSTOPS // For a rectangular bed just keep the probe in bounds @@ -216,14 +214,14 @@ void GcodeSuite::M48() { #endif if (verbose_level > 3) - SERIAL_ECHOLNPGM_P(PSTR("Going to: X"), next_pos.x, SP_Y_STR, next_pos.y); + SERIAL_ECHOLN(F("Going to: X"), next_pos.x, FPSTR(SP_Y_STR), next_pos.y); do_blocking_move_to_xy(next_pos); } // n_legs loop } // n_legs // Probe a single point - const float pz = probe.probe_at_point(test_position, raise_after, 0); + const float pz = probe.probe_at_point(test_position, raise_after); // Break the loop if the probe fails probing_good = !isnan(pz); @@ -243,14 +241,11 @@ void GcodeSuite::M48() { // Calculate the standard deviation so far. // The value after the last sample will be the final output. float dev_sum = 0.0; - LOOP_LE_N(j, n) dev_sum += sq(sample_set[j] - mean); + for (uint8_t j = 0; j <= n; ++j) dev_sum += sq(sample_set[j] - mean); sigma = SQRT(dev_sum / (n + 1)); if (verbose_level > 1) { - SERIAL_ECHO(n + 1); - SERIAL_ECHOPGM(" of ", n_samples); - SERIAL_ECHOPAIR_F(": z: ", pz, 3); - SERIAL_CHAR(' '); + SERIAL_ECHO(n + 1, F(" of "), n_samples, F(": z: "), p_float_t(pz, 3), C(' ')); dev_report(verbose_level > 2, mean, sigma, min, max); SERIAL_EOL(); } diff --git a/Marlin/src/gcode/calibrate/M665.cpp b/Marlin/src/gcode/calibrate/M665.cpp index a8e02831e2..22ad80425a 100644 --- a/Marlin/src/gcode/calibrate/M665.cpp +++ b/Marlin/src/gcode/calibrate/M665.cpp @@ -181,6 +181,25 @@ ); } +#elif ENABLED(POLAR) + + #include "../../module/polar.h" + + /** + * M665: Set POLAR settings + * Parameters: + * S[segments] - Segments-per-second + */ + void GcodeSuite::M665() { + if (!parser.seen_any()) return M665_report(); + if (parser.seenval('S')) segments_per_second = parser.value_float(); + } + + void GcodeSuite::M665_report(const bool forReplay/*=true*/) { + report_heading_etc(forReplay, F(STR_POLAR_SETTINGS)); + SERIAL_ECHOLNPGM_P(PSTR(" M665 S"), segments_per_second); + } + #endif #endif // IS_KINEMATIC diff --git a/Marlin/src/gcode/calibrate/M666.cpp b/Marlin/src/gcode/calibrate/M666.cpp index 90fad1811c..143b6f249a 100644 --- a/Marlin/src/gcode/calibrate/M666.cpp +++ b/Marlin/src/gcode/calibrate/M666.cpp @@ -22,7 +22,7 @@ #include "../../inc/MarlinConfig.h" -#if ENABLED(DELTA) || HAS_EXTRA_ENDSTOPS +#if ANY(DELTA, HAS_EXTRA_ENDSTOPS) #include "../gcode.h" @@ -52,7 +52,7 @@ is_err = true; else { delta_endstop_adj[i] = v; - if (DEBUGGING(LEVELING)) DEBUG_ECHOLNPGM("delta_endstop_adj[", AS_CHAR(AXIS_CHAR(i)), "] = ", v); + if (DEBUGGING(LEVELING)) DEBUG_ECHOLNPGM("delta_endstop_adj[", C(AXIS_CHAR(i)), "] = ", v); } } } diff --git a/Marlin/src/gcode/calibrate/M852.cpp b/Marlin/src/gcode/calibrate/M852.cpp index 6c661dcd61..6d3c004548 100644 --- a/Marlin/src/gcode/calibrate/M852.cpp +++ b/Marlin/src/gcode/calibrate/M852.cpp @@ -93,11 +93,9 @@ void GcodeSuite::M852() { void GcodeSuite::M852_report(const bool forReplay/*=true*/) { report_heading_etc(forReplay, F(STR_SKEW_FACTOR)); - SERIAL_ECHOPAIR_F(" M852 I", planner.skew_factor.xy, 6); + SERIAL_ECHOPGM(" M852 I", p_float_t(planner.skew_factor.xy, 6)); #if ENABLED(SKEW_CORRECTION_FOR_Z) - SERIAL_ECHOPAIR_F(" J", planner.skew_factor.xz, 6); - SERIAL_ECHOPAIR_F(" K", planner.skew_factor.yz, 6); - SERIAL_ECHOLNPGM(" ; XY, XZ, YZ"); + SERIAL_ECHOLNPGM(" J", p_float_t(planner.skew_factor.xz, 6), " K", p_float_t(planner.skew_factor.yz, 6), " ; XY, XZ, YZ"); #else SERIAL_ECHOLNPGM(" ; XY"); #endif diff --git a/Marlin/src/gcode/config/M200-M205.cpp b/Marlin/src/gcode/config/M200-M205.cpp index 87c1f2ce30..899f12099b 100644 --- a/Marlin/src/gcode/config/M200-M205.cpp +++ b/Marlin/src/gcode/config/M200-M205.cpp @@ -64,10 +64,10 @@ if (parser.seenval('L')) { // Set volumetric limit (in mm^3/sec) const float lval = parser.value_float(); - if (WITHIN(lval, 0, 20)) + if (WITHIN(lval, 0, VOLUMETRIC_EXTRUDER_LIMIT_MAX)) planner.set_volumetric_extruder_limit(target_extruder, lval); else - SERIAL_ECHOLNPGM("?L value out of range (0-20)."); + SERIAL_ECHOLNPGM("?L value out of range (0-" STRINGIFY(VOLUMETRIC_EXTRUDER_LIMIT_MAX) ")."); } #endif @@ -143,24 +143,32 @@ void GcodeSuite::M201() { void GcodeSuite::M201_report(const bool forReplay/*=true*/) { report_heading_etc(forReplay, F(STR_MAX_ACCELERATION)); - SERIAL_ECHOLNPGM_P( - LIST_N(DOUBLE(NUM_AXES), - PSTR(" M201 X"), LINEAR_UNIT(planner.settings.max_acceleration_mm_per_s2[X_AXIS]), - SP_Y_STR, LINEAR_UNIT(planner.settings.max_acceleration_mm_per_s2[Y_AXIS]), - SP_Z_STR, LINEAR_UNIT(planner.settings.max_acceleration_mm_per_s2[Z_AXIS]), - SP_I_STR, I_AXIS_UNIT(planner.settings.max_acceleration_mm_per_s2[I_AXIS]), - SP_J_STR, J_AXIS_UNIT(planner.settings.max_acceleration_mm_per_s2[J_AXIS]), - SP_K_STR, K_AXIS_UNIT(planner.settings.max_acceleration_mm_per_s2[K_AXIS]), - SP_U_STR, U_AXIS_UNIT(planner.settings.max_acceleration_mm_per_s2[U_AXIS]), - SP_V_STR, V_AXIS_UNIT(planner.settings.max_acceleration_mm_per_s2[V_AXIS]), - SP_W_STR, W_AXIS_UNIT(planner.settings.max_acceleration_mm_per_s2[W_AXIS]) - ) - #if HAS_EXTRUDERS && DISABLED(DISTINCT_E_FACTORS) - , SP_E_STR, VOLUMETRIC_UNIT(planner.settings.max_acceleration_mm_per_s2[E_AXIS]) - #endif - ); + #if NUM_AXES + SERIAL_ECHOPGM_P( + LIST_N(DOUBLE(NUM_AXES), + PSTR(" M201 X"), LINEAR_UNIT(planner.settings.max_acceleration_mm_per_s2[X_AXIS]), + SP_Y_STR, LINEAR_UNIT(planner.settings.max_acceleration_mm_per_s2[Y_AXIS]), + SP_Z_STR, LINEAR_UNIT(planner.settings.max_acceleration_mm_per_s2[Z_AXIS]), + SP_I_STR, I_AXIS_UNIT(planner.settings.max_acceleration_mm_per_s2[I_AXIS]), + SP_J_STR, J_AXIS_UNIT(planner.settings.max_acceleration_mm_per_s2[J_AXIS]), + SP_K_STR, K_AXIS_UNIT(planner.settings.max_acceleration_mm_per_s2[K_AXIS]), + SP_U_STR, U_AXIS_UNIT(planner.settings.max_acceleration_mm_per_s2[U_AXIS]), + SP_V_STR, V_AXIS_UNIT(planner.settings.max_acceleration_mm_per_s2[V_AXIS]), + SP_W_STR, W_AXIS_UNIT(planner.settings.max_acceleration_mm_per_s2[W_AXIS]) + ) + ); + #endif + + #if HAS_EXTRUDERS && DISABLED(DISTINCT_E_FACTORS) + SERIAL_ECHOPGM_P(SP_E_STR, VOLUMETRIC_UNIT(planner.settings.max_acceleration_mm_per_s2[E_AXIS])); + #endif + + #if NUM_AXES || (HAS_EXTRUDERS && DISABLED(DISTINCT_E_FACTORS)) + SERIAL_EOL(); + #endif + #if ENABLED(DISTINCT_E_FACTORS) - LOOP_L_N(i, E_STEPPERS) { + for (uint8_t i = 0; i < E_STEPPERS; ++i) { report_echo_start(forReplay); SERIAL_ECHOLNPGM_P( PSTR(" M201 T"), i @@ -191,24 +199,32 @@ void GcodeSuite::M203() { void GcodeSuite::M203_report(const bool forReplay/*=true*/) { report_heading_etc(forReplay, F(STR_MAX_FEEDRATES)); - SERIAL_ECHOLNPGM_P( - LIST_N(DOUBLE(NUM_AXES), - PSTR(" M203 X"), LINEAR_UNIT(planner.settings.max_feedrate_mm_s[X_AXIS]), - SP_Y_STR, LINEAR_UNIT(planner.settings.max_feedrate_mm_s[Y_AXIS]), - SP_Z_STR, LINEAR_UNIT(planner.settings.max_feedrate_mm_s[Z_AXIS]), - SP_I_STR, LINEAR_UNIT(planner.settings.max_feedrate_mm_s[I_AXIS]), - SP_J_STR, LINEAR_UNIT(planner.settings.max_feedrate_mm_s[J_AXIS]), - SP_K_STR, LINEAR_UNIT(planner.settings.max_feedrate_mm_s[K_AXIS]), - SP_U_STR, LINEAR_UNIT(planner.settings.max_feedrate_mm_s[U_AXIS]), - SP_V_STR, LINEAR_UNIT(planner.settings.max_feedrate_mm_s[V_AXIS]), - SP_W_STR, LINEAR_UNIT(planner.settings.max_feedrate_mm_s[W_AXIS]) - ) - #if HAS_EXTRUDERS && DISABLED(DISTINCT_E_FACTORS) - , SP_E_STR, VOLUMETRIC_UNIT(planner.settings.max_feedrate_mm_s[E_AXIS]) - #endif - ); + #if NUM_AXES + SERIAL_ECHOPGM_P( + LIST_N(DOUBLE(NUM_AXES), + PSTR(" M203 X"), LINEAR_UNIT(planner.settings.max_feedrate_mm_s[X_AXIS]), + SP_Y_STR, LINEAR_UNIT(planner.settings.max_feedrate_mm_s[Y_AXIS]), + SP_Z_STR, LINEAR_UNIT(planner.settings.max_feedrate_mm_s[Z_AXIS]), + SP_I_STR, LINEAR_UNIT(planner.settings.max_feedrate_mm_s[I_AXIS]), + SP_J_STR, LINEAR_UNIT(planner.settings.max_feedrate_mm_s[J_AXIS]), + SP_K_STR, LINEAR_UNIT(planner.settings.max_feedrate_mm_s[K_AXIS]), + SP_U_STR, LINEAR_UNIT(planner.settings.max_feedrate_mm_s[U_AXIS]), + SP_V_STR, LINEAR_UNIT(planner.settings.max_feedrate_mm_s[V_AXIS]), + SP_W_STR, LINEAR_UNIT(planner.settings.max_feedrate_mm_s[W_AXIS]) + ) + ); + #endif + + #if HAS_EXTRUDERS && DISABLED(DISTINCT_E_FACTORS) + SERIAL_ECHOPGM_P(SP_E_STR, VOLUMETRIC_UNIT(planner.settings.max_feedrate_mm_s[E_AXIS])); + #endif + + #if NUM_AXES || (HAS_EXTRUDERS && DISABLED(DISTINCT_E_FACTORS)) + SERIAL_EOL(); + #endif + #if ENABLED(DISTINCT_E_FACTORS) - LOOP_L_N(i, E_STEPPERS) { + for (uint8_t i = 0; i < E_STEPPERS; ++i) { if (!forReplay) SERIAL_ECHO_START(); SERIAL_ECHOLNPGM_P( PSTR(" M203 T"), i @@ -221,9 +237,9 @@ void GcodeSuite::M203_report(const bool forReplay/*=true*/) { /** * M204: Set Accelerations in units/sec^2 (M204 P1200 R3000 T3000) * - * P = Printing moves - * R = Retract only (no X, Y, Z) moves - * T = Travel (non printing) moves + * P Printing moves + * R Retract only (no X, Y, Z) moves + * T Travel (non printing) moves */ void GcodeSuite::M204() { if (!parser.seen("PRST")) @@ -247,41 +263,51 @@ void GcodeSuite::M204_report(const bool forReplay/*=true*/) { ); } +#if AXIS_COLLISION('B') + #define M205_MIN_SEG_TIME_PARAM 'D' + #define M205_MIN_SEG_TIME_STR "D" + #warning "Use 'M205 D' for Minimum Segment Time." +#else + #define M205_MIN_SEG_TIME_PARAM 'B' + #define M205_MIN_SEG_TIME_STR "B" +#endif + /** * M205: Set Advanced Settings * - * B = Min Segment Time (µs) - * S = Min Feed Rate (units/s) - * T = Min Travel Feed Rate (units/s) - * X = Max X Jerk (units/sec^2) - * Y = Max Y Jerk (units/sec^2) - * Z = Max Z Jerk (units/sec^2) - * E = Max E Jerk (units/sec^2) - * J = Junction Deviation (mm) (If not using CLASSIC_JERK) + * B<µs> : Min Segment Time + * S : Min Feed Rate + * T : Min Travel Feed Rate + * + * With CLASSIC_JERK: + * X : Max X Jerk + * Y : Max Y Jerk + * Z : Max Z Jerk + * ... : etc + * E : Max E Jerk + * + * Without CLASSIC_JERK: + * J(mm) : Junction Deviation */ void GcodeSuite::M205() { - if (!parser.seen("BST" TERN_(HAS_JUNCTION_DEVIATION, "J") TERN_(HAS_CLASSIC_JERK, "XYZE"))) - return M205_report(); + if (!parser.seen_any()) return M205_report(); //planner.synchronize(); - if (parser.seenval('B')) planner.settings.min_segment_time_us = parser.value_ulong(); + if (parser.seenval(M205_MIN_SEG_TIME_PARAM)) planner.settings.min_segment_time_us = parser.value_ulong(); if (parser.seenval('S')) planner.settings.min_feedrate_mm_s = parser.value_linear_units(); if (parser.seenval('T')) planner.settings.min_travel_feedrate_mm_s = parser.value_linear_units(); #if HAS_JUNCTION_DEVIATION - #if HAS_CLASSIC_JERK && AXIS_COLLISION('J') - #error "Can't set_max_jerk for 'J' axis because 'J' is used for Junction Deviation." - #endif if (parser.seenval('J')) { const float junc_dev = parser.value_linear_units(); if (WITHIN(junc_dev, 0.01f, 0.3f)) { planner.junction_deviation_mm = junc_dev; - TERN_(LIN_ADVANCE, planner.recalculate_max_e_jerk()); + TERN_(HAS_LINEAR_E_JERK, planner.recalculate_max_e_jerk()); } else SERIAL_ERROR_MSG("?J out of range (0.01 to 0.3)"); } #endif - #if HAS_CLASSIC_JERK + #if ENABLED(CLASSIC_JERK) bool seenZ = false; LOGICAL_AXIS_CODE( if (parser.seenval('E')) planner.set_max_jerk(E_AXIS, parser.value_linear_units()), @@ -299,14 +325,14 @@ void GcodeSuite::M205() { if (seenZ && planner.max_jerk.z <= 0.1f) SERIAL_ECHOLNPGM("WARNING! Low Z Jerk may lead to unwanted pauses."); #endif - #endif // HAS_CLASSIC_JERK + #endif // CLASSIC_JERK } void GcodeSuite::M205_report(const bool forReplay/*=true*/) { report_heading_etc(forReplay, F( - "Advanced (B S T" + "Advanced (" M205_MIN_SEG_TIME_STR " S T" TERN_(HAS_JUNCTION_DEVIATION, " J") - #if HAS_CLASSIC_JERK + #if ENABLED(CLASSIC_JERK) NUM_AXIS_GANG( " X", " Y", " Z", " " STR_I "", " " STR_J "", " " STR_K "", @@ -317,13 +343,13 @@ void GcodeSuite::M205_report(const bool forReplay/*=true*/) { ")" )); SERIAL_ECHOLNPGM_P( - PSTR(" M205 B"), LINEAR_UNIT(planner.settings.min_segment_time_us) + PSTR(" M205 " M205_MIN_SEG_TIME_STR), LINEAR_UNIT(planner.settings.min_segment_time_us) , PSTR(" S"), LINEAR_UNIT(planner.settings.min_feedrate_mm_s) , SP_T_STR, LINEAR_UNIT(planner.settings.min_travel_feedrate_mm_s) #if HAS_JUNCTION_DEVIATION , PSTR(" J"), LINEAR_UNIT(planner.junction_deviation_mm) #endif - #if HAS_CLASSIC_JERK + #if ENABLED(CLASSIC_JERK) && NUM_AXES , LIST_N(DOUBLE(NUM_AXES), SP_X_STR, LINEAR_UNIT(planner.max_jerk.x), SP_Y_STR, LINEAR_UNIT(planner.max_jerk.y), diff --git a/Marlin/src/gcode/config/M217.cpp b/Marlin/src/gcode/config/M217.cpp index b360739e21..908a19fae7 100644 --- a/Marlin/src/gcode/config/M217.cpp +++ b/Marlin/src/gcode/config/M217.cpp @@ -95,7 +95,9 @@ void GcodeSuite::M217() { #if ENABLED(TOOLCHANGE_PARK) if (parser.seenval('W')) { toolchange_settings.enable_park = parser.value_linear_units(); } - if (parser.seenval('X')) { const int16_t v = parser.value_linear_units(); toolchange_settings.change_point.x = constrain(v, X_MIN_POS, X_MAX_POS); } + #if HAS_X_AXIS + if (parser.seenval('X')) { const int16_t v = parser.value_linear_units(); toolchange_settings.change_point.x = constrain(v, X_MIN_POS, X_MAX_POS); } + #endif #if HAS_Y_AXIS if (parser.seenval('Y')) { const int16_t v = parser.value_linear_units(); toolchange_settings.change_point.y = constrain(v, Y_MIN_POS, Y_MAX_POS); } #endif @@ -183,25 +185,27 @@ void GcodeSuite::M217_report(const bool forReplay/*=true*/) { #endif #if ENABLED(TOOLCHANGE_PARK) - { SERIAL_ECHOPGM(" W", LINEAR_UNIT(toolchange_settings.enable_park)); - SERIAL_ECHOPGM_P( - SP_X_STR, LINEAR_UNIT(toolchange_settings.change_point.x) - #if HAS_Y_AXIS - , SP_Y_STR, LINEAR_UNIT(toolchange_settings.change_point.y) - #endif - #if SECONDARY_AXES >= 1 - , LIST_N(DOUBLE(SECONDARY_AXES) - , SP_I_STR, I_AXIS_UNIT(toolchange_settings.change_point.i) - , SP_J_STR, J_AXIS_UNIT(toolchange_settings.change_point.j) - , SP_K_STR, K_AXIS_UNIT(toolchange_settings.change_point.k) - , SP_C_STR, U_AXIS_UNIT(toolchange_settings.change_point.u) - , PSTR(" H"), V_AXIS_UNIT(toolchange_settings.change_point.v) - , PSTR(" O"), W_AXIS_UNIT(toolchange_settings.change_point.w) - ) - #endif - ); - } + #if NUM_AXES + { + SERIAL_ECHOPGM_P( + SP_X_STR, LINEAR_UNIT(toolchange_settings.change_point.x) + #if HAS_Y_AXIS + , SP_Y_STR, LINEAR_UNIT(toolchange_settings.change_point.y) + #endif + #if SECONDARY_AXES >= 1 + , LIST_N(DOUBLE(SECONDARY_AXES) + , SP_I_STR, I_AXIS_UNIT(toolchange_settings.change_point.i) + , SP_J_STR, J_AXIS_UNIT(toolchange_settings.change_point.j) + , SP_K_STR, K_AXIS_UNIT(toolchange_settings.change_point.k) + , SP_C_STR, U_AXIS_UNIT(toolchange_settings.change_point.u) + , PSTR(" H"), V_AXIS_UNIT(toolchange_settings.change_point.v) + , PSTR(" O"), W_AXIS_UNIT(toolchange_settings.change_point.w) + ) + #endif + ); + } + #endif #endif #if ENABLED(TOOLCHANGE_FS_PRIME_FIRST_USED) diff --git a/Marlin/src/gcode/config/M218.cpp b/Marlin/src/gcode/config/M218.cpp index c39447a28d..ff63dcaf34 100644 --- a/Marlin/src/gcode/config/M218.cpp +++ b/Marlin/src/gcode/config/M218.cpp @@ -46,9 +46,15 @@ void GcodeSuite::M218() { const int8_t target_extruder = get_target_extruder_from_command(); if (target_extruder < 0) return; - if (parser.seenval('X')) hotend_offset[target_extruder].x = parser.value_linear_units(); - if (parser.seenval('Y')) hotend_offset[target_extruder].y = parser.value_linear_units(); - if (parser.seenval('Z')) hotend_offset[target_extruder].z = parser.value_linear_units(); + #if HAS_X_AXIS + if (parser.seenval('X')) hotend_offset[target_extruder].x = parser.value_linear_units(); + #endif + #if HAS_Y_AXIS + if (parser.seenval('Y')) hotend_offset[target_extruder].y = parser.value_linear_units(); + #endif + #if HAS_Z_AXIS + if (parser.seenval('Z')) hotend_offset[target_extruder].z = parser.value_linear_units(); + #endif #if ENABLED(DELTA) if (target_extruder == active_extruder) @@ -58,14 +64,14 @@ void GcodeSuite::M218() { void GcodeSuite::M218_report(const bool forReplay/*=true*/) { report_heading_etc(forReplay, F(STR_HOTEND_OFFSETS)); - LOOP_S_L_N(e, 1, HOTENDS) { + for (uint8_t e = 1; e < HOTENDS; ++e) { report_echo_start(forReplay); - SERIAL_ECHOPGM_P( + SERIAL_ECHOLNPGM_P( PSTR(" M218 T"), e, SP_X_STR, LINEAR_UNIT(hotend_offset[e].x), - SP_Y_STR, LINEAR_UNIT(hotend_offset[e].y) + SP_Y_STR, LINEAR_UNIT(hotend_offset[e].y), + SP_Z_STR, p_float_t(LINEAR_UNIT(hotend_offset[e].z), 3) ); - SERIAL_ECHOLNPAIR_F_P(SP_Z_STR, LINEAR_UNIT(hotend_offset[e].z), 3); } } diff --git a/Marlin/src/gcode/config/M220.cpp b/Marlin/src/gcode/config/M220.cpp index c9070df803..6797df25d5 100644 --- a/Marlin/src/gcode/config/M220.cpp +++ b/Marlin/src/gcode/config/M220.cpp @@ -36,16 +36,15 @@ * R : Flag to restore the last-saved factor */ void GcodeSuite::M220() { + if (!parser.seen_any()) { + SERIAL_ECHOLNPGM("FR:", feedrate_percentage, "%"); + return; + } static int16_t backup_feedrate_percentage = 100; - if (parser.seen('B')) backup_feedrate_percentage = feedrate_percentage; - if (parser.seen('R')) feedrate_percentage = backup_feedrate_percentage; - + const int16_t now_feedrate_perc = feedrate_percentage; + if (parser.seen_test('R')) feedrate_percentage = backup_feedrate_percentage; + if (parser.seen_test('B')) backup_feedrate_percentage = now_feedrate_perc; if (parser.seenval('S')) feedrate_percentage = parser.value_int(); - if (!parser.seen_any()) { - SERIAL_ECHOPGM("FR:", feedrate_percentage); - SERIAL_CHAR('%'); - SERIAL_EOL(); - } } diff --git a/Marlin/src/gcode/config/M281.cpp b/Marlin/src/gcode/config/M281.cpp index e4ef3ab40b..038a5d615a 100644 --- a/Marlin/src/gcode/config/M281.cpp +++ b/Marlin/src/gcode/config/M281.cpp @@ -56,7 +56,7 @@ void GcodeSuite::M281() { void GcodeSuite::M281_report(const bool forReplay/*=true*/) { report_heading_etc(forReplay, F(STR_SERVO_ANGLES)); - LOOP_L_N(i, NUM_SERVOS) { + for (uint8_t i = 0; i < NUM_SERVOS; ++i) { switch (i) { default: break; #if ENABLED(SWITCHING_EXTRUDER) @@ -66,6 +66,9 @@ void GcodeSuite::M281_report(const bool forReplay/*=true*/) { #endif #elif ENABLED(SWITCHING_NOZZLE) case SWITCHING_NOZZLE_SERVO_NR: + #if ENABLED(SWITCHING_NOZZLE_TWO_SERVOS) + case SWITCHING_NOZZLE_E1_SERVO_NR: + #endif #elif ENABLED(BLTOUCH) || (HAS_Z_SERVO_PROBE && defined(Z_SERVO_ANGLES)) case Z_PROBE_SERVO_NR: #endif diff --git a/Marlin/src/gcode/config/M302.cpp b/Marlin/src/gcode/config/M302.cpp index 9f4d569d7b..3373e14325 100644 --- a/Marlin/src/gcode/config/M302.cpp +++ b/Marlin/src/gcode/config/M302.cpp @@ -28,7 +28,7 @@ #include "../../module/temperature.h" #if ENABLED(DWIN_LCD_PROUI) - #include "../../lcd/e3v2/proui/dwin_defines.h" + #include "../../lcd/e3v2/proui/dwin.h" #endif /** @@ -51,7 +51,7 @@ void GcodeSuite::M302() { if (seen_S) { thermalManager.extrude_min_temp = parser.value_celsius(); thermalManager.allow_cold_extrude = (thermalManager.extrude_min_temp == 0); - TERN_(DWIN_LCD_PROUI, HMI_data.ExtMinT = thermalManager.extrude_min_temp); + TERN_(DWIN_LCD_PROUI, hmiData.extMinT = thermalManager.extrude_min_temp); } if (parser.seen('P')) @@ -59,9 +59,7 @@ void GcodeSuite::M302() { else if (!seen_S) { // Report current state SERIAL_ECHO_START(); - SERIAL_ECHOPGM("Cold extrudes are "); - SERIAL_ECHOF(thermalManager.allow_cold_extrude ? F("en") : F("dis")); - SERIAL_ECHOLNPGM("abled (min temp ", thermalManager.extrude_min_temp, "C)"); + SERIAL_ECHOLN(F("Cold extrudes are "), thermalManager.allow_cold_extrude ? F("en") : F("dis"), F("abled (min temp "), thermalManager.extrude_min_temp, F("C)")); } } diff --git a/Marlin/src/gcode/config/M305.cpp b/Marlin/src/gcode/config/M305.cpp index e7746923b3..48d7cf1882 100644 --- a/Marlin/src/gcode/config/M305.cpp +++ b/Marlin/src/gcode/config/M305.cpp @@ -69,7 +69,7 @@ void GcodeSuite::M305() { SERIAL_ECHO_MSG("!Invalid Steinhart-Hart C coeff. (-0.01 < C < +0.01)"); } // If not setting then report parameters else if (t_index < 0) { // ...all user thermistors - LOOP_L_N(i, USER_THERMISTORS) + for (uint8_t i = 0; i < USER_THERMISTORS; ++i) thermalManager.M305_report(i); } else // ...one user thermistor diff --git a/Marlin/src/gcode/config/M43.cpp b/Marlin/src/gcode/config/M43.cpp index 5807844012..5ea89b7136 100644 --- a/Marlin/src/gcode/config/M43.cpp +++ b/Marlin/src/gcode/config/M43.cpp @@ -25,7 +25,7 @@ #if ENABLED(PINS_DEBUGGING) #include "../gcode.h" -#include "../../MarlinCore.h" // for pin_is_protected +#include "../../MarlinCore.h" // for pin_is_protected, wait_for_user #include "../../pins/pinsDebug.h" #include "../../module/endstops.h" @@ -61,7 +61,7 @@ inline void toggle_pins() { end = PARSED_PIN_INDEX('L', NUM_DIGITAL_PINS - 1), wait = parser.intval('W', 500); - LOOP_S_LE_N(i, start, end) { + for (uint8_t i = start; i <= end; ++i) { pin_t pin = GET_PIN_MAP_PIN_M43(i); if (!VALID_PIN(pin)) continue; if (M43_NEVER_TOUCH(i) || (!ignore_protection && pin_is_protected(pin))) { @@ -139,24 +139,15 @@ inline void servo_probe_test() { bool deploy_state = false, stow_state; #if ENABLED(Z_MIN_PROBE_USES_Z_MIN_ENDSTOP_PIN) - #define PROBE_TEST_PIN Z_MIN_PIN - constexpr bool probe_inverting = Z_MIN_ENDSTOP_INVERTING; - - SERIAL_ECHOLNPGM(". Probe Z_MIN_PIN: ", PROBE_TEST_PIN); - SERIAL_ECHOPGM(". Z_MIN_ENDSTOP_INVERTING: "); - + #define _PROBE_PREF "Z_MIN" #else - #define PROBE_TEST_PIN Z_MIN_PROBE_PIN - constexpr bool probe_inverting = Z_MIN_PROBE_ENDSTOP_INVERTING; - - SERIAL_ECHOLNPGM(". Probe Z_MIN_PROBE_PIN: ", PROBE_TEST_PIN); - SERIAL_ECHOPGM( ". Z_MIN_PROBE_ENDSTOP_INVERTING: "); - + #define _PROBE_PREF "Z_MIN_PROBE" #endif - serialprint_truefalse(probe_inverting); + SERIAL_ECHOLNPGM(". Probe " _PROBE_PREF "_PIN: ", PROBE_TEST_PIN); + serial_ternary(F(". " _PROBE_PREF "_ENDSTOP_HIT_STATE: "), PROBE_HIT_STATE, F("HIGH"), F("LOW")); SERIAL_EOL(); SET_INPUT_PULLUP(PROBE_TEST_PIN); @@ -173,11 +164,11 @@ inline void servo_probe_test() { SERIAL_ECHOLNPGM(". Check for BLTOUCH"); bltouch._reset(); bltouch._stow(); - if (probe_inverting == READ(PROBE_TEST_PIN)) { + if (!PROBE_TRIGGERED()) { bltouch._set_SW_mode(); - if (probe_inverting != READ(PROBE_TEST_PIN)) { + if (PROBE_TRIGGERED()) { bltouch._deploy(); - if (probe_inverting == READ(PROBE_TEST_PIN)) { + if (!PROBE_TRIGGERED()) { bltouch._stow(); SERIAL_ECHOLNPGM("= BLTouch Classic 1.2, 1.3, Smart 1.0, 2.0, 2.2, 3.0, 3.1 detected."); // Check for a 3.1 by letting the user trigger it, later @@ -195,31 +186,30 @@ inline void servo_probe_test() { if (!blt) { // DEPLOY and STOW 4 times and see if the signal follows // Then it is a mechanical switch - uint8_t i = 0; SERIAL_ECHOLNPGM(". Deploy & stow 4 times"); - do { + for (uint8_t i = 0; i < 4; ++i) { servo[probe_index].move(servo_angles[Z_PROBE_SERVO_NR][0]); // Deploy safe_delay(500); deploy_state = READ(PROBE_TEST_PIN); servo[probe_index].move(servo_angles[Z_PROBE_SERVO_NR][1]); // Stow safe_delay(500); stow_state = READ(PROBE_TEST_PIN); - } while (++i < 4); + } - if (probe_inverting != deploy_state) SERIAL_ECHOLNPGM("WARNING: INVERTING setting probably backwards."); + if (PROBE_HIT_STATE == deploy_state) SERIAL_ECHOLNPGM("WARNING: " _PROBE_PREF "_ENDSTOP_HIT_STATE is probably wrong."); if (deploy_state != stow_state) { SERIAL_ECHOLNPGM("= Mechanical Switch detected"); if (deploy_state) { - SERIAL_ECHOLNPGM(" DEPLOYED state: HIGH (logic 1)", - " STOWED (triggered) state: LOW (logic 0)"); + SERIAL_ECHOLNPGM(". DEPLOYED state: HIGH (logic 1)\n" + ". STOWED (triggered) state: LOW (logic 0)"); } else { - SERIAL_ECHOLNPGM(" DEPLOYED state: LOW (logic 0)", - " STOWED (triggered) state: HIGH (logic 1)"); + SERIAL_ECHOLNPGM(". DEPLOYED state: LOW (logic 0)\n" + ". STOWED (triggered) state: HIGH (logic 1)"); } #if ENABLED(BLTOUCH) - SERIAL_ECHOLNPGM("FAIL: BLTOUCH enabled - Set up this device as a Servo Probe with INVERTING set to 'true'."); + SERIAL_ECHOLNPGM("FAIL: Can't enable BLTOUCH. Check your settings."); #endif return; } @@ -302,9 +292,7 @@ void GcodeSuite::M43() { // 'E' Enable or disable endstop monitoring and return if (parser.seen('E')) { endstops.monitor_flag = parser.value_bool(); - SERIAL_ECHOPGM("endstop monitor "); - SERIAL_ECHOF(endstops.monitor_flag ? F("en") : F("dis")); - SERIAL_ECHOLNPGM("abled"); + SERIAL_ECHOLN(F("endstop monitor "), endstops.monitor_flag ? F("en") : F("dis"), F("abled")); return; } @@ -313,7 +301,7 @@ void GcodeSuite::M43() { // 'P' Get the range of pins to test or watch uint8_t first_pin = PARSED_PIN_INDEX('P', 0), - last_pin = parser.seenval('L') ? PARSED_PIN_INDEX('L', 0) : parser.seenval('P') ? first_pin : (NUMBER_PINS_TOTAL) - 1; + last_pin = parser.seenval('L') ? PARSED_PIN_INDEX('L', 0) : (parser.seenval('P') ? first_pin : (NUMBER_PINS_TOTAL) - 1); NOMORE(first_pin, (NUMBER_PINS_TOTAL) - 1); NOMORE(last_pin, (NUMBER_PINS_TOTAL) - 1); @@ -329,15 +317,18 @@ void GcodeSuite::M43() { // 'W' Watch until click, M108, or reset if (parser.boolval('W')) { - SERIAL_ECHOLNPGM("Watching pins"); #ifdef ARDUINO_ARCH_SAM NOLESS(first_pin, 2); // Don't hijack the UART pins #endif - uint8_t pin_state[last_pin - first_pin + 1]; - LOOP_S_LE_N(i, first_pin, last_pin) { + + const uint8_t pin_count = last_pin - first_pin + 1; + uint8_t pin_state[pin_count]; + bool can_watch = false; + for (uint8_t i = first_pin; i <= last_pin; ++i) { pin_t pin = GET_PIN_MAP_PIN_M43(i); if (!VALID_PIN(pin)) continue; if (M43_NEVER_TOUCH(i) || (!ignore_protection && pin_is_protected(pin))) continue; + can_watch = true; pinMode(pin, INPUT_PULLUP); delay(1); /* @@ -348,16 +339,36 @@ void GcodeSuite::M43() { pin_state[i - first_pin] = extDigitalRead(pin); } + const bool multipin = (pin_count > 1); + + if (!can_watch) { + SERIAL_ECHOPGM("Specified pin"); + SERIAL_ECHOPGM_P(multipin ? PSTR("s are") : PSTR(" is")); + SERIAL_ECHOLNPGM(" protected. Use 'I' to override."); + return; + } + + // "Watching pin(s) # - #" + SERIAL_ECHOPGM("Watching pin"); + if (multipin) SERIAL_CHAR('s'); + SERIAL_CHAR(' '); SERIAL_ECHO(first_pin); + if (multipin) SERIAL_ECHOPGM(" - ", last_pin); + SERIAL_EOL(); + #if HAS_RESUME_CONTINUE KEEPALIVE_STATE(PAUSED_FOR_USER); wait_for_user = true; - TERN_(HOST_PROMPT_SUPPORT, hostui.prompt_do(PROMPT_USER_CONTINUE, F("M43 Wait Called"), FPSTR(CONTINUE_STR))); - TERN_(EXTENSIBLE_UI, ExtUI::onUserConfirmRequired(F("M43 Wait Called"))); + TERN_(HOST_PROMPT_SUPPORT, hostui.continue_prompt(F("M43 Waiting..."))); + #if ENABLED(EXTENSIBLE_UI) + ExtUI::onUserConfirmRequired(F("M43 Waiting...")); + #else + LCD_MESSAGE(MSG_USERWAIT); + #endif #endif for (;;) { - LOOP_S_LE_N(i, first_pin, last_pin) { - pin_t pin = GET_PIN_MAP_PIN_M43(i); + for (uint8_t i = first_pin; i <= last_pin; ++i) { + const pin_t pin = GET_PIN_MAP_PIN_M43(i); if (!VALID_PIN(pin)) continue; if (M43_NEVER_TOUCH(i) || (!ignore_protection && pin_is_protected(pin))) continue; const byte val = @@ -368,7 +379,7 @@ void GcodeSuite::M43() { //*/ extDigitalRead(pin); if (val != pin_state[i - first_pin]) { - report_pin_state_extended(pin, ignore_protection, false); + report_pin_state_extended(pin, ignore_protection, true); pin_state[i - first_pin] = val; } } @@ -380,11 +391,13 @@ void GcodeSuite::M43() { safe_delay(200); } + + TERN_(HAS_RESUME_CONTINUE, ui.reset_status()); } else { // Report current state of selected pin(s) - LOOP_S_LE_N(i, first_pin, last_pin) { - pin_t pin = GET_PIN_MAP_PIN_M43(i); + for (uint8_t i = first_pin; i <= last_pin; ++i) { + const pin_t pin = GET_PIN_MAP_PIN_M43(i); if (VALID_PIN(pin)) report_pin_state_extended(pin, ignore_protection, true); } } diff --git a/Marlin/src/gcode/config/M672.cpp b/Marlin/src/gcode/config/M672.cpp index 257b49471f..064d05d0b6 100644 --- a/Marlin/src/gcode/config/M672.cpp +++ b/Marlin/src/gcode/config/M672.cpp @@ -54,7 +54,7 @@ // b3 b2 b1 b0 ~b0 ... lo bits, NOT last bit // void M672_send(uint8_t b) { // bit rate requirement: 1kHz +/- 30% - LOOP_L_N(bits, 14) { + for (uint8_t bits = 0; bits < 14; ++bits) { switch (bits) { default: { OUT_WRITE(SMART_EFFECTOR_MOD_PIN, !!(b & 0x80)); b <<= 1; break; } // send bit, shift next into place case 7: diff --git a/Marlin/src/gcode/config/M92.cpp b/Marlin/src/gcode/config/M92.cpp index c7610b83a9..09153c51fd 100644 --- a/Marlin/src/gcode/config/M92.cpp +++ b/Marlin/src/gcode/config/M92.cpp @@ -55,7 +55,7 @@ void GcodeSuite::M92() { const float value = parser.value_per_axis_units((AxisEnum)(E_AXIS_N(target_extruder))); if (value < 20) { float factor = planner.settings.axis_steps_per_mm[E_AXIS_N(target_extruder)] / value; // increase e constants if M92 E14 is given for netfab. - #if HAS_CLASSIC_JERK && HAS_CLASSIC_E_JERK + #if ALL(CLASSIC_JERK, HAS_CLASSIC_E_JERK) planner.max_jerk.e *= factor; #endif planner.settings.max_feedrate_mm_s[E_AXIS_N(target_extruder)] *= factor; @@ -82,7 +82,7 @@ void GcodeSuite::M92() { if (wanted) { const float best = uint16_t(wanted / z_full_step_mm) * z_full_step_mm; SERIAL_ECHOPGM(", best:[", best); - if (best != wanted) { SERIAL_CHAR(','); SERIAL_DECIMAL(best + z_full_step_mm); } + if (best != wanted) { SERIAL_ECHO(C(','), best + z_full_step_mm); } SERIAL_CHAR(']'); } SERIAL_ECHOLNPGM(" }"); @@ -92,24 +92,30 @@ void GcodeSuite::M92() { void GcodeSuite::M92_report(const bool forReplay/*=true*/, const int8_t e/*=-1*/) { report_heading_etc(forReplay, F(STR_STEPS_PER_UNIT)); - SERIAL_ECHOPGM_P(LIST_N(DOUBLE(NUM_AXES), - PSTR(" M92 X"), LINEAR_UNIT(planner.settings.axis_steps_per_mm[X_AXIS]), - SP_Y_STR, LINEAR_UNIT(planner.settings.axis_steps_per_mm[Y_AXIS]), - SP_Z_STR, LINEAR_UNIT(planner.settings.axis_steps_per_mm[Z_AXIS]), - SP_I_STR, I_AXIS_UNIT(planner.settings.axis_steps_per_mm[I_AXIS]), - SP_J_STR, J_AXIS_UNIT(planner.settings.axis_steps_per_mm[J_AXIS]), - SP_K_STR, K_AXIS_UNIT(planner.settings.axis_steps_per_mm[K_AXIS]), - SP_U_STR, U_AXIS_UNIT(planner.settings.axis_steps_per_mm[U_AXIS]), - SP_V_STR, V_AXIS_UNIT(planner.settings.axis_steps_per_mm[V_AXIS]), - SP_W_STR, W_AXIS_UNIT(planner.settings.axis_steps_per_mm[W_AXIS]) - )); + #if NUM_AXES + SERIAL_ECHOPGM_P(LIST_N(DOUBLE(NUM_AXES), + PSTR(" M92 X"), LINEAR_UNIT(planner.settings.axis_steps_per_mm[X_AXIS]), + SP_Y_STR, LINEAR_UNIT(planner.settings.axis_steps_per_mm[Y_AXIS]), + SP_Z_STR, LINEAR_UNIT(planner.settings.axis_steps_per_mm[Z_AXIS]), + SP_I_STR, I_AXIS_UNIT(planner.settings.axis_steps_per_mm[I_AXIS]), + SP_J_STR, J_AXIS_UNIT(planner.settings.axis_steps_per_mm[J_AXIS]), + SP_K_STR, K_AXIS_UNIT(planner.settings.axis_steps_per_mm[K_AXIS]), + SP_U_STR, U_AXIS_UNIT(planner.settings.axis_steps_per_mm[U_AXIS]), + SP_V_STR, V_AXIS_UNIT(planner.settings.axis_steps_per_mm[V_AXIS]), + SP_W_STR, W_AXIS_UNIT(planner.settings.axis_steps_per_mm[W_AXIS]) + )); + #endif + #if HAS_EXTRUDERS && DISABLED(DISTINCT_E_FACTORS) SERIAL_ECHOPGM_P(SP_E_STR, VOLUMETRIC_UNIT(planner.settings.axis_steps_per_mm[E_AXIS])); #endif - SERIAL_EOL(); + + #if NUM_AXES || (HAS_EXTRUDERS && DISABLED(DISTINCT_E_FACTORS)) + SERIAL_EOL(); + #endif #if ENABLED(DISTINCT_E_FACTORS) - LOOP_L_N(i, E_STEPPERS) { + for (uint8_t i = 0; i < E_STEPPERS; ++i) { if (e >= 0 && i != e) continue; report_echo_start(forReplay); SERIAL_ECHOLNPGM_P( diff --git a/Marlin/src/gcode/control/M111.cpp b/Marlin/src/gcode/control/M111.cpp index a92d334ae9..02f37f8497 100644 --- a/Marlin/src/gcode/control/M111.cpp +++ b/Marlin/src/gcode/control/M111.cpp @@ -46,7 +46,7 @@ void GcodeSuite::M111() { SERIAL_ECHOPGM(STR_DEBUG_PREFIX); if (marlin_debug_flags) { uint8_t comma = 0; - LOOP_L_N(i, COUNT(debug_strings)) { + for (uint8_t i = 0; i < COUNT(debug_strings); ++i) { if (TEST(marlin_debug_flags, i)) { if (comma++) SERIAL_CHAR(','); SERIAL_ECHOPGM_P((PGM_P)pgm_read_ptr(&debug_strings[i])); diff --git a/Marlin/src/gcode/control/M17_M18_M84.cpp b/Marlin/src/gcode/control/M17_M18_M84.cpp index 4ff48568fa..1742d288b3 100644 --- a/Marlin/src/gcode/control/M17_M18_M84.cpp +++ b/Marlin/src/gcode/control/M17_M18_M84.cpp @@ -48,17 +48,19 @@ inline stepper_flags_t selected_axis_bits() { selected.bits = e_axis_mask; } #endif - selected.bits |= NUM_AXIS_GANG( - (parser.seen_test('X') << X_AXIS), - | (parser.seen_test('Y') << Y_AXIS), - | (parser.seen_test('Z') << Z_AXIS), - | (parser.seen_test(AXIS4_NAME) << I_AXIS), - | (parser.seen_test(AXIS5_NAME) << J_AXIS), - | (parser.seen_test(AXIS6_NAME) << K_AXIS), - | (parser.seen_test(AXIS7_NAME) << U_AXIS), - | (parser.seen_test(AXIS8_NAME) << V_AXIS), - | (parser.seen_test(AXIS9_NAME) << W_AXIS) - ); + #if NUM_AXES + selected.bits |= NUM_AXIS_GANG( + (parser.seen_test('X') << X_AXIS), + | (parser.seen_test('Y') << Y_AXIS), + | (parser.seen_test('Z') << Z_AXIS), + | (parser.seen_test(AXIS4_NAME) << I_AXIS), + | (parser.seen_test(AXIS5_NAME) << J_AXIS), + | (parser.seen_test(AXIS6_NAME) << K_AXIS), + | (parser.seen_test(AXIS7_NAME) << U_AXIS), + | (parser.seen_test(AXIS8_NAME) << V_AXIS), + | (parser.seen_test(AXIS9_NAME) << W_AXIS) + ); + #endif return selected; } @@ -71,7 +73,7 @@ void do_enable(const stepper_flags_t to_enable) { if (!shall_enable) return; // All specified axes already enabled? - ena_mask_t also_enabled = 0; // Track steppers enabled due to overlap + ena_mask_t also_enabled = 0; // Track steppers enabled due to overlap // Enable all flagged axes LOOP_NUM_AXES(a) { @@ -212,7 +214,7 @@ void try_to_disable(const stepper_flags_t to_disable) { void GcodeSuite::M18_M84() { if (parser.seenval('S')) { reset_stepper_timeout(); - #if HAS_DISABLE_INACTIVE_AXIS + #if HAS_DISABLE_IDLE_AXES const millis_t ms = parser.value_millis_from_seconds(); #if LASER_SAFETY_TIMEOUT_MS > 0 if (ms && ms <= LASER_SAFETY_TIMEOUT_MS) { diff --git a/Marlin/src/gcode/control/M211.cpp b/Marlin/src/gcode/control/M211.cpp index 95ae052a7b..8e7d10ce65 100644 --- a/Marlin/src/gcode/control/M211.cpp +++ b/Marlin/src/gcode/control/M211.cpp @@ -47,8 +47,8 @@ void GcodeSuite::M211_report(const bool forReplay/*=true*/) { report_echo_start(forReplay); const xyz_pos_t l_soft_min = soft_endstop.min.asLogical(), l_soft_max = soft_endstop.max.asLogical(); - print_pos(l_soft_min, F(STR_SOFT_MIN), F(" ")); - print_pos(l_soft_max, F(STR_SOFT_MAX)); + print_xyz(l_soft_min, F(STR_SOFT_MIN), F(" ")); + print_xyz(l_soft_max, F(STR_SOFT_MAX)); } #endif // HAS_SOFTWARE_ENDSTOPS diff --git a/Marlin/src/gcode/control/M3-M5.cpp b/Marlin/src/gcode/control/M3-M5.cpp index 5d5d44e8bf..ec24cf8a65 100644 --- a/Marlin/src/gcode/control/M3-M5.cpp +++ b/Marlin/src/gcode/control/M3-M5.cpp @@ -32,21 +32,18 @@ * Laser: * M3 - Laser ON/Power (Ramped power) * M4 - Laser ON/Power (Ramped power) - * M5 - Set power output to 0 (leaving inline mode unchanged). * * M3I - Enable continuous inline power to be processed by the planner, with power * calculated and set in the planner blocks, processed inline during stepping. - * Within inline mode M3 S-Values will set the power for the next moves e.g. G1 X10 Y10 powers on with the last S-Value. + * In inline mode M3 S-Values will set the power for the next moves. + * (e.g., G1 X10 Y10 powers on with the last S-Value.) * M3I must be set before using planner-synced M3 inline S-Values (LASER_POWER_SYNC). * * M4I - Set dynamic mode which calculates laser power OCR based on the current feedrate. * - * M5I - Clear inline mode and set power to 0. - * * Spindle: * M3 - Spindle ON (Clockwise) * M4 - Spindle ON (Counter-clockwise) - * M5 - Spindle OFF * * Parameters: * S - Set power. S0 will turn the spindle/laser off. @@ -92,19 +89,15 @@ void GcodeSuite::M3_M4(const bool is_M4) { #endif auto get_s_power = [] { - float u; if (parser.seenval('S')) { const float v = parser.value_float(); - u = TERN(LASER_POWER_TRAP, v, cutter.power_to_range(v)); + cutter.menuPower = cutter.unitPower = TERN(LASER_POWER_TRAP, v, cutter.power_to_range(v)); } else if (cutter.cutter_mode == CUTTER_MODE_STANDARD) - u = cutter.cpwr_to_upwr(SPEED_POWER_STARTUP); - - cutter.menuPower = cutter.unitPower = u; + cutter.menuPower = cutter.unitPower = cutter.cpwr_to_upwr(SPEED_POWER_STARTUP); // PWM not implied, power converted to OCR from unit definition and on/off if not PWM. - cutter.power = TERN(SPINDLE_LASER_USE_PWM, cutter.upower_to_ocr(u), u > 0 ? 255 : 0); - return u; + cutter.power = TERN(SPINDLE_LASER_USE_PWM, cutter.upower_to_ocr(cutter.unitPower), cutter.unitPower > 0 ? 255 : 0); }; if (cutter.cutter_mode == CUTTER_MODE_CONTINUOUS || cutter.cutter_mode == CUTTER_MODE_DYNAMIC) { // Laser power in inline mode @@ -138,6 +131,13 @@ void GcodeSuite::M3_M4(const bool is_M4) { /** * M5 - Cutter OFF (when moves are complete) + * + * Laser: + * M5 - Set power output to 0 (leaving inline mode unchanged). + * M5I - Clear inline mode and set power to 0. + * + * Spindle: + * M5 - Spindle OFF */ void GcodeSuite::M5() { planner.synchronize(); diff --git a/Marlin/src/gcode/control/M350_M351.cpp b/Marlin/src/gcode/control/M350_M351.cpp index ac6b5a329b..425abad529 100644 --- a/Marlin/src/gcode/control/M350_M351.cpp +++ b/Marlin/src/gcode/control/M350_M351.cpp @@ -29,9 +29,6 @@ #if NUM_AXES == XYZ && EXTRUDERS >= 1 #define HAS_M350_B_PARAM 1 // "5th axis" (after E0) for an original XYZEB setup. - #if AXIS_COLLISION('B') - #error "M350 parameter 'B' collision with axis name." - #endif #endif /** diff --git a/Marlin/src/gcode/control/M380_M381.cpp b/Marlin/src/gcode/control/M380_M381.cpp index 6bcec891e2..20d24484ed 100644 --- a/Marlin/src/gcode/control/M380_M381.cpp +++ b/Marlin/src/gcode/control/M380_M381.cpp @@ -22,7 +22,7 @@ #include "../../inc/MarlinConfig.h" -#if EITHER(EXT_SOLENOID, MANUAL_SOLENOID_CONTROL) +#if ANY(EXT_SOLENOID, MANUAL_SOLENOID_CONTROL) #include "../gcode.h" #include "../../feature/solenoid.h" diff --git a/Marlin/src/gcode/control/M42.cpp b/Marlin/src/gcode/control/M42.cpp index 1b3a29d100..13965cb72c 100644 --- a/Marlin/src/gcode/control/M42.cpp +++ b/Marlin/src/gcode/control/M42.cpp @@ -25,7 +25,6 @@ #if ENABLED(DIRECT_PIN_CONTROL) #include "../gcode.h" -#include "../../MarlinCore.h" // for pin_is_protected #if HAS_FAN #include "../../module/temperature.h" @@ -38,12 +37,14 @@ #define OUTPUT_OPEN_DRAIN OUTPUT_OPEN_DRAIN #endif +bool pin_is_protected(const pin_t pin); + void protected_pin_err() { SERIAL_ERROR_MSG(STR_ERR_PROTECTED_PIN); } /** - * M42: Change pin status via GCode + * M42: Change pin status via G-Code * * P Pin number (LED if omitted) * For LPC1768 specify pin P1_02 as M42 P102, @@ -53,6 +54,7 @@ void protected_pin_err() { * I Flag to ignore Marlin's pin protection * * T Pin mode: 0=INPUT 1=OUTPUT 2=INPUT_PULLUP 3=INPUT_PULLDOWN + * 4=INPUT_ANALOG 5=OUTPUT_OPEN_DRAIN */ void GcodeSuite::M42() { const int pin_index = PARSED_PIN_INDEX('P', GET_PIN_MAP_INDEX(LED_PIN)); @@ -86,30 +88,8 @@ void GcodeSuite::M42() { #if HAS_FAN switch (pin) { - #if HAS_FAN0 - case FAN0_PIN: thermalManager.fan_speed[0] = pin_status; return; - #endif - #if HAS_FAN1 - case FAN1_PIN: thermalManager.fan_speed[1] = pin_status; return; - #endif - #if HAS_FAN2 - case FAN2_PIN: thermalManager.fan_speed[2] = pin_status; return; - #endif - #if HAS_FAN3 - case FAN3_PIN: thermalManager.fan_speed[3] = pin_status; return; - #endif - #if HAS_FAN4 - case FAN4_PIN: thermalManager.fan_speed[4] = pin_status; return; - #endif - #if HAS_FAN5 - case FAN5_PIN: thermalManager.fan_speed[5] = pin_status; return; - #endif - #if HAS_FAN6 - case FAN6_PIN: thermalManager.fan_speed[6] = pin_status; return; - #endif - #if HAS_FAN7 - case FAN7_PIN: thermalManager.fan_speed[7] = pin_status; return; - #endif + #define _CASE(N) case FAN##N##_PIN: thermalManager.fan_speed[N] = pin_status; return; + REPEAT(FAN_COUNT, _CASE) } #endif @@ -119,7 +99,7 @@ void GcodeSuite::M42() { } // An OUTPUT_OPEN_DRAIN should not be changed to normal OUTPUT (STM32) - // Use M42 Px M1/5 S0/1 to set the output type and then set value + // Use M42 Px T1/5 S0/1 to set the output type and then set value #ifndef OUTPUT_OPEN_DRAIN pinMode(pin, OUTPUT); #endif diff --git a/Marlin/src/gcode/control/M605.cpp b/Marlin/src/gcode/control/M605.cpp index e3ca43e17f..167cdae4a9 100644 --- a/Marlin/src/gcode/control/M605.cpp +++ b/Marlin/src/gcode/control/M605.cpp @@ -127,25 +127,24 @@ case DXC_MIRRORED_MODE: DEBUG_ECHOPGM("MIRRORED"); break; } DEBUG_ECHOPGM("\nActive Ext: ", active_extruder); - if (!active_extruder_parked) DEBUG_ECHOPGM(" NOT "); - DEBUG_ECHOPGM(" parked."); - DEBUG_ECHOPGM("\nactive_extruder_x_pos: ", current_position.x); - DEBUG_ECHOPGM("\ninactive_extruder_x: ", inactive_extruder_x); - DEBUG_ECHOPGM("\nextruder_duplication_enabled: ", extruder_duplication_enabled); - DEBUG_ECHOPGM("\nduplicate_extruder_x_offset: ", duplicate_extruder_x_offset); - DEBUG_ECHOPGM("\nduplicate_extruder_temp_offset: ", duplicate_extruder_temp_offset); - DEBUG_ECHOPGM("\ndelayed_move_time: ", delayed_move_time); - DEBUG_ECHOPGM("\nX1 Home X: ", x_home_pos(0), "\nX1_MIN_POS=", X1_MIN_POS, "\nX1_MAX_POS=", X1_MAX_POS); - DEBUG_ECHOPGM("\nX2 Home X: ", x_home_pos(1), "\nX2_MIN_POS=", X2_MIN_POS, "\nX2_MAX_POS=", X2_MAX_POS); - DEBUG_ECHOPGM("\nX2_HOME_DIR=", X2_HOME_DIR, "\nX2_HOME_POS=", X2_HOME_POS); - DEBUG_ECHOPGM("\nDEFAULT_DUAL_X_CARRIAGE_MODE=", STRINGIFY(DEFAULT_DUAL_X_CARRIAGE_MODE)); - DEBUG_ECHOPGM("\toolchange_settings.z_raise=", toolchange_settings.z_raise); - DEBUG_ECHOPGM("\nDEFAULT_DUPLICATION_X_OFFSET=", DEFAULT_DUPLICATION_X_OFFSET); - DEBUG_EOL(); + if (!active_extruder_parked) DEBUG_ECHOPGM(" NOT ", F(" parked.")); + DEBUG_ECHOLNPGM( + "\nactive_extruder_x_pos: ", current_position.x, + "\ninactive_extruder_x: ", inactive_extruder_x, + "\nextruder_duplication_enabled: ", extruder_duplication_enabled, + "\nduplicate_extruder_x_offset: ", duplicate_extruder_x_offset, + "\nduplicate_extruder_temp_offset: ", duplicate_extruder_temp_offset, + "\ndelayed_move_time: ", delayed_move_time, + "\nX1 Home: ", x_home_pos(0), " X1_MIN_POS=", X1_MIN_POS, " X1_MAX_POS=", X1_MAX_POS, + "\nX2 Home: ", x_home_pos(1), " X2_MIN_POS=", X2_MIN_POS, " X2_MAX_POS=", X2_MAX_POS, + "\nDEFAULT_DUAL_X_CARRIAGE_MODE=", STRINGIFY(DEFAULT_DUAL_X_CARRIAGE_MODE), + "\toolchange_settings.z_raise=", toolchange_settings.z_raise, + "\nDEFAULT_DUPLICATION_X_OFFSET=", DEFAULT_DUPLICATION_X_OFFSET + ); HOTEND_LOOP() { DEBUG_ECHOPGM_P(SP_T_STR, e); - LOOP_NUM_AXES(a) DEBUG_ECHOPGM(" hotend_offset[", e, "].", AS_CHAR(AXIS_CHAR(a) | 0x20), "=", hotend_offset[e][a]); + LOOP_NUM_AXES(a) DEBUG_ECHOPGM(" hotend_offset[", e, "].", C(AXIS_CHAR(a) | 0x20), "=", hotend_offset[e][a]); DEBUG_EOL(); } DEBUG_EOL(); @@ -169,7 +168,7 @@ if (parser.seen("EPS")) { planner.synchronize(); if (parser.seenval('P')) duplication_e_mask = parser.value_int(); // Set the mask directly - else if (parser.seenval('E')) duplication_e_mask = pow(2, parser.value_int() + 1) - 1; // Set the mask by E index + else if (parser.seenval('E')) duplication_e_mask = _BV(parser.value_int() + 1) - 1; // Set the mask by E index ena = (2 == parser.intval('S', extruder_duplication_enabled ? 2 : 0)); set_duplication_enabled(ena && (duplication_e_mask >= 3)); } diff --git a/Marlin/src/gcode/control/M7-M9.cpp b/Marlin/src/gcode/control/M7-M9.cpp index ccde4f552c..837bb114b2 100644 --- a/Marlin/src/gcode/control/M7-M9.cpp +++ b/Marlin/src/gcode/control/M7-M9.cpp @@ -37,7 +37,7 @@ } #endif -#if EITHER(COOLANT_FLOOD, AIR_ASSIST) +#if ANY(COOLANT_FLOOD, AIR_ASSIST) #if ENABLED(AIR_ASSIST) #include "../../feature/spindle_laser.h" diff --git a/Marlin/src/gcode/control/M80_M81.cpp b/Marlin/src/gcode/control/M80_M81.cpp index 90b25e7ed3..2d3e407446 100644 --- a/Marlin/src/gcode/control/M80_M81.cpp +++ b/Marlin/src/gcode/control/M80_M81.cpp @@ -48,7 +48,7 @@ // S: Report the current power supply state and exit if (parser.seen('S')) { - SERIAL_ECHOF(powerManager.psu_on ? F("PS:1\n") : F("PS:0\n")); + SERIAL_ECHO(powerManager.psu_on ? F("PS:1\n") : F("PS:0\n")); return; } @@ -79,7 +79,7 @@ void GcodeSuite::M81() { print_job_timer.stop(); - #if BOTH(HAS_FAN, PROBING_FANS_OFF) + #if ALL(HAS_FAN, PROBING_FANS_OFF) thermalManager.fans_paused = false; ZERO(thermalManager.saved_fan_speed); #endif diff --git a/Marlin/src/gcode/control/M993_M994.cpp b/Marlin/src/gcode/control/M993_M994.cpp index 598a73fab7..bc634ae13c 100644 --- a/Marlin/src/gcode/control/M993_M994.cpp +++ b/Marlin/src/gcode/control/M993_M994.cpp @@ -22,7 +22,7 @@ #include "../../inc/MarlinConfig.h" -#if ALL(SPI_FLASH, SDSUPPORT, MARLIN_DEV_MODE) +#if SPI_FLASH_BACKUP #include "../gcode.h" #include "../../sd/cardreader.h" @@ -85,4 +85,4 @@ void GcodeSuite::M994() { card.closefile(); } -#endif // SPI_FLASH && SDSUPPORT && MARLIN_DEV_MODE +#endif // SPI_FLASH_BACKUP diff --git a/Marlin/src/gcode/control/M997.cpp b/Marlin/src/gcode/control/M997.cpp index 74ed8b0d07..5ac0ba23bb 100644 --- a/Marlin/src/gcode/control/M997.cpp +++ b/Marlin/src/gcode/control/M997.cpp @@ -33,7 +33,7 @@ */ void GcodeSuite::M997() { - TERN_(DWIN_LCD_PROUI, DWIN_RebootScreen()); + TERN_(DWIN_LCD_PROUI, dwinRebootScreen()); flashFirmware(parser.intval('S')); diff --git a/Marlin/src/gcode/control/T.cpp b/Marlin/src/gcode/control/T.cpp index 5e8f6b5436..c5ebbcf50e 100644 --- a/Marlin/src/gcode/control/T.cpp +++ b/Marlin/src/gcode/control/T.cpp @@ -23,7 +23,7 @@ #include "../gcode.h" #include "../../module/tool_change.h" -#if EITHER(HAS_MULTI_EXTRUDER, DEBUG_LEVELING_FEATURE) +#if ANY(HAS_MULTI_EXTRUDER, DEBUG_LEVELING_FEATURE) #include "../../module/motion.h" #endif @@ -41,13 +41,21 @@ * S1 Don't move the tool in XY after change * * For PRUSA_MMU2(S) and EXTENDABLE_EMU_MMU2(S) - * T[n] Gcode to extrude at least 38.10 mm at feedrate 19.02 mm/s must follow immediately to load to extruder wheels. - * T? Gcode to extrude shouldn't have to follow. Load to extruder wheels is done automatically. + * T[n] G-code to extrude at least 38.10 mm at feedrate 19.02 mm/s must follow immediately to load to extruder wheels. + * T? G-code to extrude shouldn't have to follow. Load to extruder wheels is done automatically. * Tx Same as T?, but nozzle doesn't have to be preheated. Tc requires a preheated nozzle to finish filament load. * Tc Load to nozzle after filament was prepared by Tc and nozzle is already heated. */ void GcodeSuite::T(const int8_t tool_index) { + #if HAS_MULTI_EXTRUDER + // For 'T' with no parameter report the current tool. + if (parser.string_arg && *parser.string_arg == '*') { + SERIAL_ECHOLNPGM(STR_ACTIVE_EXTRUDER, active_extruder); + return; + } + #endif + DEBUG_SECTION(log_T, "T", DEBUGGING(LEVELING)); if (DEBUGGING(LEVELING)) DEBUG_ECHOLNPGM("...(", tool_index, ")"); diff --git a/Marlin/src/gcode/eeprom/M500-M504.cpp b/Marlin/src/gcode/eeprom/M500-M504.cpp index 412d003355..c3962117e5 100644 --- a/Marlin/src/gcode/eeprom/M500-M504.cpp +++ b/Marlin/src/gcode/eeprom/M500-M504.cpp @@ -26,7 +26,7 @@ #include "../../inc/MarlinConfig.h" #if ENABLED(CONFIGURATION_EMBEDDING) - #include "../../sd/SdBaseFile.h" + #include "../../sd/cardreader.h" #include "../../mczip.h" #endif @@ -66,11 +66,19 @@ void GcodeSuite::M502() { #if ENABLED(CONFIGURATION_EMBEDDING) if (parser.seen_test('C')) { - SdBaseFile file; - const uint16_t size = sizeof(mc_zip); + MediaFile file; // Need to create the config size on the SD card - if (file.open("mc.zip", O_WRITE|O_CREAT) && file.write(pgm_read_ptr(mc_zip), size) != -1 && file.close()) - SERIAL_ECHO_MSG("Configuration saved as 'mc.zip'"); + MediaFile root = card.getroot(); + if (file.open(&root, "mc.zip", O_WRITE|O_CREAT)) { + bool success = true; + for (uint16_t i = 0; success && i < sizeof(mc_zip); ++i) { + const uint8_t c = pgm_read_byte(&mc_zip[i]); + success = (file.write(c) == 1); + } + success = file.close() && success; + + if (success) SERIAL_ECHO_MSG("Configuration saved as 'mc.zip'"); + } } #endif } diff --git a/Marlin/src/gcode/feature/advance/M900.cpp b/Marlin/src/gcode/feature/advance/M900.cpp index 8c0da41801..5fa9c04dbd 100644 --- a/Marlin/src/gcode/feature/advance/M900.cpp +++ b/Marlin/src/gcode/feature/advance/M900.cpp @@ -120,8 +120,7 @@ void GcodeSuite::M900() { EXTRUDER_LOOP() { const bool slot = TEST(lin_adv_slot, e); SERIAL_ECHOLNPGM("Advance T", e, " S", slot, " K", planner.extruder_advance_K[e], - "(S", !slot, " K", other_extruder_advance_K[e], ")"); - SERIAL_EOL(); + "(S", !slot, " K", other_extruder_advance_K[e], ")"); } #endif @@ -132,10 +131,7 @@ void GcodeSuite::M900() { SERIAL_ECHOLNPGM("Advance K=", planner.extruder_advance_K[0]); #else SERIAL_ECHOPGM("Advance K"); - EXTRUDER_LOOP() { - SERIAL_CHAR(' ', '0' + e, ':'); - SERIAL_DECIMAL(planner.extruder_advance_K[e]); - } + EXTRUDER_LOOP() SERIAL_ECHO(C(' '), C('0' + e), C(':'), planner.extruder_advance_K[e]); SERIAL_EOL(); #endif diff --git a/Marlin/src/gcode/feature/camera/M240.cpp b/Marlin/src/gcode/feature/camera/M240.cpp index 19051ffd42..bb1d3f9eee 100644 --- a/Marlin/src/gcode/feature/camera/M240.cpp +++ b/Marlin/src/gcode/feature/camera/M240.cpp @@ -84,7 +84,7 @@ inline void spin_photo_pin() { static constexpr uint32_t sequence[] = PHOTO_PULSES_US; - LOOP_L_N(i, COUNT(sequence)) + for (uint8_t i = 0; i < COUNT(sequence); ++i) pulse_photo_pin(sequence[i], !(i & 1)); } @@ -111,7 +111,7 @@ * B - Y offset to the return position * F - Override the XY movement feedrate * R - Retract/recover length (current units) - * S - Retract/recover feedrate (mm/m) + * S - Retract/recover feedrate (mm/min) * X - Move to X before triggering the shutter * Y - Move to Y before triggering the shutter * Z - Raise Z by a distance before triggering the shutter @@ -128,11 +128,13 @@ void GcodeSuite::M240() { if (homing_needed_error()) return; - const xyz_pos_t old_pos = { + const xyz_pos_t old_pos = NUM_AXIS_ARRAY( current_position.x + parser.linearval('A'), current_position.y + parser.linearval('B'), - current_position.z - }; + current_position.z, + current_position.i, current_position.j, current_position.k, + current_position.u, current_position.v, current_position.w + ); #ifdef PHOTO_RETRACT_MM const float rval = parser.linearval('R', _PHOTO_RETRACT_MM); @@ -140,7 +142,7 @@ void GcodeSuite::M240() { e_move_m240(-rval, sval); #endif - feedRate_t fr_mm_s = MMM_TO_MMS(parser.linearval('F')); + feedRate_t fr_mm_s = parser.feedrateval('F'); if (fr_mm_s) NOLESS(fr_mm_s, 10.0f); constexpr xyz_pos_t photo_position = PHOTO_POSITION; diff --git a/Marlin/src/gcode/feature/clean/G12.cpp b/Marlin/src/gcode/feature/clean/G12.cpp index 0113170f1d..a5e312f8fd 100644 --- a/Marlin/src/gcode/feature/clean/G12.cpp +++ b/Marlin/src/gcode/feature/clean/G12.cpp @@ -57,10 +57,16 @@ void GcodeSuite::G12() { } #endif - const uint8_t pattern = parser.ushortval('P', 0), - strokes = parser.ushortval('S', NOZZLE_CLEAN_STROKES), - objects = parser.ushortval('T', NOZZLE_CLEAN_TRIANGLES); - const float radius = parser.linearval('R', NOZZLE_CLEAN_CIRCLE_RADIUS); + const uint8_t pattern = ( + #if COUNT_ENABLED(NOZZLE_CLEAN_PATTERN_LINE, NOZZLE_CLEAN_PATTERN_ZIGZAG, NOZZLE_CLEAN_PATTERN_CIRCLE) > 1 + parser.ushortval('P', NOZZLE_CLEAN_DEFAULT_PATTERN) + #else + NOZZLE_CLEAN_DEFAULT_PATTERN + #endif + ); + const uint8_t strokes = parser.ushortval('S', NOZZLE_CLEAN_STROKES), + objects = TERN0(NOZZLE_CLEAN_PATTERN_ZIGZAG, parser.ushortval('T', NOZZLE_CLEAN_TRIANGLES)); + const float radius = TERN0(NOZZLE_CLEAN_PATTERN_CIRCLE, parser.linearval('R', NOZZLE_CLEAN_CIRCLE_RADIUS)); const bool seenxyz = parser.seen("XYZ"); const uint8_t cleans = (!seenxyz || parser.boolval('X') ? _BV(X_AXIS) : 0) diff --git a/Marlin/src/gcode/feature/digipot/M907-M910.cpp b/Marlin/src/gcode/feature/digipot/M907-M910.cpp index 9ebe713cde..8869f8d494 100644 --- a/Marlin/src/gcode/feature/digipot/M907-M910.cpp +++ b/Marlin/src/gcode/feature/digipot/M907-M910.cpp @@ -51,7 +51,7 @@ void GcodeSuite::M907() { if (!parser.seen("BS" STR_AXES_LOGICAL)) return M907_report(); - if (parser.seenval('S')) LOOP_L_N(i, MOTOR_CURRENT_COUNT) stepper.set_digipot_current(i, parser.value_int()); + if (parser.seenval('S')) for (uint8_t i = 0; i < MOTOR_CURRENT_COUNT; ++i) stepper.set_digipot_current(i, parser.value_int()); LOOP_LOGICAL_AXES(i) if (parser.seenval(IAXIS_CHAR(i))) stepper.set_digipot_current(i, parser.value_int()); // X Y Z (I J K U V W) E (map to drivers according to DIGIPOT_CHANNELS. Default with NUM_AXES 3: map X Y Z E to X Y Z E0) // Additional extruders use B,C. // TODO: Change these parameters because 'E' is used and D should be reserved for debugging. B? @@ -82,7 +82,7 @@ void GcodeSuite::M907() { #endif )) return M907_report(); - if (parser.seenval('S')) LOOP_L_N(a, MOTOR_CURRENT_COUNT) stepper.set_digipot_current(a, parser.value_int()); + if (parser.seenval('S')) for (uint8_t a = 0; a < MOTOR_CURRENT_COUNT; ++a) stepper.set_digipot_current(a, parser.value_int()); #if HAS_X_Y_XY_I_J_K_U_V_W if (NUM_AXIS_GANG( @@ -104,7 +104,7 @@ void GcodeSuite::M907() { #if HAS_MOTOR_CURRENT_I2C // this one uses actual amps in floating point - if (parser.seenval('S')) LOOP_L_N(q, DIGIPOT_I2C_NUM_CHANNELS) digipot_i2c.set_current(q, parser.value_float()); + if (parser.seenval('S')) for (uint8_t q = 0; q < DIGIPOT_I2C_NUM_CHANNELS; ++q) digipot_i2c.set_current(q, parser.value_float()); LOOP_LOGICAL_AXES(i) if (parser.seenval(IAXIS_CHAR(i))) digipot_i2c.set_current(i, parser.value_float()); // X Y Z (I J K U V W) E (map to drivers according to pots adresses. Default with NUM_AXES 3 X Y Z E: map to X Y Z E0) // Additional extruders use B,C,D. // TODO: Change these parameters because 'E' is used and because 'D' should be reserved for debugging. B? diff --git a/Marlin/src/gcode/feature/ft_motion/M493.cpp b/Marlin/src/gcode/feature/ft_motion/M493.cpp new file mode 100644 index 0000000000..7f202be413 --- /dev/null +++ b/Marlin/src/gcode/feature/ft_motion/M493.cpp @@ -0,0 +1,385 @@ +/** + * Marlin 3D Printer Firmware + * Copyright (c) 2023 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] + * + * Based on Sprinter and grbl. + * Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +#include "../../../inc/MarlinConfig.h" + +#if ENABLED(FT_MOTION) + +#include "../../gcode.h" +#include "../../../module/ft_motion.h" +#include "../../../module/stepper.h" + +void say_shaping() { + // FT Enabled + SERIAL_ECHO_TERNARY(ftMotion.cfg.mode, "Fixed-Time Motion ", "en", "dis", "abled"); + + // FT Shaping + #if HAS_X_AXIS + if (ftMotion.cfg.mode > ftMotionMode_ENABLED) { + SERIAL_ECHOPGM(" with "); + switch (ftMotion.cfg.mode) { + default: break; + case ftMotionMode_ZV: SERIAL_ECHOPGM("ZV"); break; + case ftMotionMode_ZVD: SERIAL_ECHOPGM("ZVD"); break; + case ftMotionMode_ZVDD: SERIAL_ECHOPGM("ZVDD"); break; + case ftMotionMode_ZVDDD: SERIAL_ECHOPGM("ZVDDD"); break; + case ftMotionMode_EI: SERIAL_ECHOPGM("EI"); break; + case ftMotionMode_2HEI: SERIAL_ECHOPGM("2 Hump EI"); break; + case ftMotionMode_3HEI: SERIAL_ECHOPGM("3 Hump EI"); break; + case ftMotionMode_MZV: SERIAL_ECHOPGM("MZV"); break; + //case ftMotionMode_DISCTF: SERIAL_ECHOPGM("discrete transfer functions"); break; + //case ftMotionMode_ULENDO_FBS: SERIAL_ECHOPGM("Ulendo FBS."); return; + } + SERIAL_ECHOPGM(" shaping"); + } + #endif + SERIAL_ECHOLNPGM("."); + + const bool z_based = TERN0(HAS_DYNAMIC_FREQ_MM, ftMotion.cfg.dynFreqMode == dynFreqMode_Z_BASED), + g_based = TERN0(HAS_DYNAMIC_FREQ_G, ftMotion.cfg.dynFreqMode == dynFreqMode_MASS_BASED), + dynamic = z_based || g_based; + + // FT Dynamic Frequency Mode + if (ftMotion.cfg.modeHasShaper()) { + #if HAS_DYNAMIC_FREQ + SERIAL_ECHOPGM("Dynamic Frequency Mode "); + switch (ftMotion.cfg.dynFreqMode) { + default: + case dynFreqMode_DISABLED: SERIAL_ECHOPGM("disabled"); break; + #if HAS_DYNAMIC_FREQ_MM + case dynFreqMode_Z_BASED: SERIAL_ECHOPGM("Z-based"); break; + #endif + #if HAS_DYNAMIC_FREQ_G + case dynFreqMode_MASS_BASED: SERIAL_ECHOPGM("Mass-based"); break; + #endif + } + SERIAL_ECHOLNPGM("."); + #endif + + #if HAS_X_AXIS + SERIAL_ECHO_TERNARY(dynamic, "X/A ", "base dynamic", "static", " compensator frequency: "); + SERIAL_ECHO(p_float_t(ftMotion.cfg.baseFreq[X_AXIS], 2), F("Hz")); + #if HAS_DYNAMIC_FREQ + if (dynamic) SERIAL_ECHO(" scaling: ", p_float_t(ftMotion.cfg.dynFreqK[X_AXIS], 8), F("Hz/"), z_based ? F("mm") : F("g")); + #endif + SERIAL_EOL(); + #endif + + #if HAS_Y_AXIS + SERIAL_ECHO_TERNARY(dynamic, "Y/B ", "base dynamic", "static", " compensator frequency: "); + SERIAL_ECHO(p_float_t(ftMotion.cfg.baseFreq[Y_AXIS], 2), F(" Hz")); + #if HAS_DYNAMIC_FREQ + if (dynamic) SERIAL_ECHO(F(" scaling: "), p_float_t(ftMotion.cfg.dynFreqK[Y_AXIS], 8), F("Hz/"), z_based ? F("mm") : F("g")); + #endif + SERIAL_EOL(); + #endif + } + + #if HAS_EXTRUDERS + SERIAL_ECHO_TERNARY(ftMotion.cfg.linearAdvEna, "Linear Advance ", "en", "dis", "abled"); + SERIAL_ECHOLN(F(". Gain: "), p_float_t(ftMotion.cfg.linearAdvK, 5)); + #endif +} + +void GcodeSuite::M493_report(const bool forReplay/*=true*/) { + report_heading_etc(forReplay, F(STR_FT_MOTION)); + const ft_config_t &c = ftMotion.cfg; + SERIAL_ECHOPGM(" M493 S", c.mode); + #if HAS_X_AXIS + SERIAL_ECHOPGM(" A", c.baseFreq[X_AXIS]); + #if HAS_Y_AXIS + SERIAL_ECHOPGM(" B", c.baseFreq[Y_AXIS]); + #endif + #endif + #if HAS_DYNAMIC_FREQ + SERIAL_ECHOPGM(" D", c.dynFreqMode); + #if HAS_X_AXIS + SERIAL_ECHOPGM(" F", c.dynFreqK[X_AXIS]); + #if HAS_Y_AXIS + SERIAL_ECHOPGM(" H", c.dynFreqK[Y_AXIS]); + #endif + #endif + #endif + #if HAS_EXTRUDERS + SERIAL_ECHOPGM(" P", c.linearAdvEna, " K", c.linearAdvK); + #endif + SERIAL_EOL(); +} + +/** + * M493: Set Fixed-time Motion Control parameters + * + * S Set the motion / shaping mode. Shaping requires an X axis, at the minimum. + * 0: NORMAL + * 1: FIXED-TIME + * 10: ZV + * 11: ZVD + * 12: EI + * 13: 2HEI + * 14: 3HEI + * 15: MZV + * + * P Enable (1) or Disable (0) Linear Advance pressure control + * + * K Set Linear Advance gain + * + * D Set Dynamic Frequency mode + * 0: DISABLED + * 1: Z-based (Requires a Z axis) + * 2: Mass-based (Requires X and E axes) + * + * A Set static/base frequency for the X axis + * F Set frequency scaling for the X axis + * + * B Set static/base frequency for the Y axis + * H Set frequency scaling for the Y axis + */ +void GcodeSuite::M493() { + struct { bool update_n:1, update_a:1, reset_ft:1, report_h:1; } flag = { false }; + + if (!parser.seen_any()) + flag.report_h = true; + + // Parse 'S' mode parameter. + if (parser.seenval('S')) { + const ftMotionMode_t newmm = (ftMotionMode_t)parser.value_byte(); + + if (newmm != ftMotion.cfg.mode) { + switch (newmm) { + default: SERIAL_ECHOLNPGM("?Invalid control mode [S] value."); return; + #if HAS_X_AXIS + case ftMotionMode_ZV: + case ftMotionMode_ZVD: + case ftMotionMode_ZVDD: + case ftMotionMode_ZVDDD: + case ftMotionMode_EI: + case ftMotionMode_2HEI: + case ftMotionMode_3HEI: + case ftMotionMode_MZV: + //case ftMotionMode_ULENDO_FBS: + //case ftMotionMode_DISCTF: + flag.update_n = flag.update_a = true; + #endif + case ftMotionMode_DISABLED: flag.reset_ft = true; + case ftMotionMode_ENABLED: + ftMotion.cfg.mode = newmm; + flag.report_h = true; + break; + } + } + } + + #if HAS_EXTRUDERS + + // Pressure control (linear advance) parameter. + if (parser.seen('P')) { + const bool val = parser.value_bool(); + ftMotion.cfg.linearAdvEna = val; + flag.report_h = true; + SERIAL_ECHO_TERNARY(val, "Linear Advance ", "en", "dis", "abled.\n"); + } + + // Pressure control (linear advance) gain parameter. + if (parser.seenval('K')) { + const float val = parser.value_float(); + if (val >= 0.0f) { + ftMotion.cfg.linearAdvK = val; + flag.report_h = true; + } + else // Value out of range. + SERIAL_ECHOLNPGM("Linear Advance gain out of range."); + } + + #endif // HAS_EXTRUDERS + + #if HAS_DYNAMIC_FREQ + + // Dynamic frequency mode parameter. + if (parser.seenval('D')) { + if (ftMotion.cfg.modeHasShaper()) { + const dynFreqMode_t val = dynFreqMode_t(parser.value_byte()); + switch (val) { + #if HAS_DYNAMIC_FREQ_MM + case dynFreqMode_Z_BASED: + #endif + #if HAS_DYNAMIC_FREQ_G + case dynFreqMode_MASS_BASED: + #endif + case dynFreqMode_DISABLED: + ftMotion.cfg.dynFreqMode = val; + flag.report_h = true; + break; + default: + SERIAL_ECHOLNPGM("?Invalid Dynamic Frequency Mode [D] value."); + break; + } + } + else { + SERIAL_ECHOLNPGM("?Wrong shaper for [D] Dynamic Frequency mode."); + } + } + + const bool modeUsesDynFreq = ( + TERN0(HAS_DYNAMIC_FREQ_MM, ftMotion.cfg.dynFreqMode == dynFreqMode_Z_BASED) + || TERN0(HAS_DYNAMIC_FREQ_G, ftMotion.cfg.dynFreqMode == dynFreqMode_MASS_BASED) + ); + + #endif // HAS_DYNAMIC_FREQ + + #if HAS_X_AXIS + + // Parse frequency parameter (X axis). + if (parser.seenval('A')) { + if (ftMotion.cfg.modeHasShaper()) { + const float val = parser.value_float(); + // TODO: Frequency minimum is dependent on the shaper used; the above check isn't always correct. + if (WITHIN(val, FTM_MIN_SHAPE_FREQ, (FTM_FS) / 2)) { + ftMotion.cfg.baseFreq[X_AXIS] = val; + flag.update_n = flag.reset_ft = flag.report_h = true; + } + else // Frequency out of range. + SERIAL_ECHOLNPGM("Invalid [", C('A'), "] frequency value."); + } + else // Mode doesn't use frequency. + SERIAL_ECHOLNPGM("Wrong mode for [", C('A'), "] frequency."); + } + + #if HAS_DYNAMIC_FREQ + // Parse frequency scaling parameter (X axis). + if (parser.seenval('F')) { + if (modeUsesDynFreq) { + ftMotion.cfg.dynFreqK[X_AXIS] = parser.value_float(); + flag.report_h = true; + } + else + SERIAL_ECHOLNPGM("Wrong mode for [", C('F'), "] frequency scaling."); + } + #endif + + // Parse zeta parameter (X axis). + if (parser.seenval('I')) { + const float val = parser.value_float(); + if (ftMotion.cfg.modeHasShaper()) { + if (WITHIN(val, 0.01f, 1.0f)) { + ftMotion.cfg.zeta[0] = val; + flag.update_n = flag.update_a = true; + } + else + SERIAL_ECHOLNPGM("Invalid X zeta [", C('I'), "] value."); // Zeta out of range. + } + else + SERIAL_ECHOLNPGM("Wrong mode for zeta parameter."); + } + + // Parse vtol parameter (X axis). + if (parser.seenval('Q')) { + const float val = parser.value_float(); + if (ftMotion.cfg.modeHasShaper() && IS_EI_MODE(ftMotion.cfg.mode)) { + if (WITHIN(val, 0.00f, 1.0f)) { + ftMotion.cfg.vtol[0] = val; + flag.update_a = true; + } + else + SERIAL_ECHOLNPGM("Invalid X vtol [", C('Q'), "] value."); // VTol out of range. + } + else + SERIAL_ECHOLNPGM("Wrong mode for vtol parameter."); + } + + #endif // HAS_X_AXIS + + #if HAS_Y_AXIS + + // Parse frequency parameter (Y axis). + if (parser.seenval('B')) { + if (ftMotion.cfg.modeHasShaper()) { + const float val = parser.value_float(); + if (WITHIN(val, FTM_MIN_SHAPE_FREQ, (FTM_FS) / 2)) { + ftMotion.cfg.baseFreq[Y_AXIS] = val; + flag.update_n = flag.reset_ft = flag.report_h = true; + } + else // Frequency out of range. + SERIAL_ECHOLNPGM("Invalid frequency [", C('B'), "] value."); + } + else // Mode doesn't use frequency. + SERIAL_ECHOLNPGM("Wrong mode for [", C('B'), "] frequency."); + } + + #if HAS_DYNAMIC_FREQ + // Parse frequency scaling parameter (Y axis). + if (parser.seenval('H')) { + if (modeUsesDynFreq) { + ftMotion.cfg.dynFreqK[Y_AXIS] = parser.value_float(); + flag.report_h = true; + } + else + SERIAL_ECHOLNPGM("Wrong mode for [", C('H'), "] frequency scaling."); + } + #endif + + // Parse zeta parameter (Y axis). + if (parser.seenval('J')) { + const float val = parser.value_float(); + if (ftMotion.cfg.modeHasShaper()) { + if (WITHIN(val, 0.01f, 1.0f)) { + ftMotion.cfg.zeta[1] = val; + flag.update_n = flag.update_a = true; + } + else + SERIAL_ECHOLNPGM("Invalid Y zeta [", C('J'), "] value."); // Zeta Out of range + } + else + SERIAL_ECHOLNPGM("Wrong mode for zeta parameter."); + } + + // Parse vtol parameter (Y axis). + if (parser.seenval('R')) { + const float val = parser.value_float(); + if (ftMotion.cfg.modeHasShaper() && IS_EI_MODE(ftMotion.cfg.mode)) { + if (WITHIN(val, 0.00f, 1.0f)) { + ftMotion.cfg.vtol[1] = val; + flag.update_a = true; + } + else + SERIAL_ECHOLNPGM("Invalid Y vtol [", C('R'), "] value."); // VTol out of range. + } + else + SERIAL_ECHOLNPGM("Wrong mode for vtol parameter."); + } + + #endif // HAS_Y_AXIS + + planner.synchronize(); + + if (flag.update_n) ftMotion.refreshShapingN(); + + if (flag.update_a) ftMotion.updateShapingA(); + + if (flag.reset_ft) { + stepper.ftMotion_syncPosition(); + ftMotion.reset(); + } + + if (flag.report_h) say_shaping(); +} + +#endif // FT_MOTION diff --git a/Marlin/src/gcode/feature/input_shaping/M593.cpp b/Marlin/src/gcode/feature/input_shaping/M593.cpp index 040710f3e5..1b6a43f9dd 100644 --- a/Marlin/src/gcode/feature/input_shaping/M593.cpp +++ b/Marlin/src/gcode/feature/input_shaping/M593.cpp @@ -22,7 +22,7 @@ #include "../../../inc/MarlinConfig.h" -#if HAS_SHAPING +#if HAS_ZV_SHAPING #include "../../gcode.h" #include "../../../module/stepper.h" @@ -49,8 +49,8 @@ void GcodeSuite::M593_report(const bool forReplay/*=true*/) { * D Set the zeta/damping factor. If axes (X, Y, etc.) are not specified, set for all axes. * F Set the frequency. If axes (X, Y, etc.) are not specified, set for all axes. * T[map] Input Shaping type, 0:ZV, 1:EI, 2:2H EI (not implemented yet) - * X<1> Set the given parameters only for the X axis. - * Y<1> Set the given parameters only for the Y axis. + * X Set the given parameters only for the X axis. + * Y Set the given parameters only for the Y axis. */ void GcodeSuite::M593() { if (!parser.seen_any()) return M593_report(); @@ -72,13 +72,13 @@ void GcodeSuite::M593() { if (parser.seen('F')) { const float freq = parser.value_float(); - constexpr float max_freq = float(uint32_t(STEPPER_TIMER_RATE) / 2) / shaping_time_t(-2); - if (freq == 0.0f || freq > max_freq) { + constexpr float min_freq = float(uint32_t(STEPPER_TIMER_RATE) / 2) / shaping_time_t(-2); + if (freq == 0.0f || freq > min_freq) { if (for_X) stepper.set_shaping_frequency(X_AXIS, freq); if (for_Y) stepper.set_shaping_frequency(Y_AXIS, freq); } else - SERIAL_ECHOLNPGM("?Frequency (F) must be greater than ", max_freq, " or 0 to disable"); + SERIAL_ECHOLNPGM("?Frequency (F) must be greater than ", min_freq, " or 0 to disable"); } } diff --git a/Marlin/src/gcode/feature/leds/M150.cpp b/Marlin/src/gcode/feature/leds/M150.cpp index 77c58411a3..43062c3f75 100644 --- a/Marlin/src/gcode/feature/leds/M150.cpp +++ b/Marlin/src/gcode/feature/leds/M150.cpp @@ -61,7 +61,12 @@ void GcodeSuite::M150() { #if ENABLED(NEOPIXEL_LED) const pixel_index_t index = parser.intval('I', -1); #if ENABLED(NEOPIXEL2_SEPARATE) - int8_t brightness = neo.brightness(), unit = parser.intval('S', -1); + #ifndef NEOPIXEL_M150_DEFAULT + #define NEOPIXEL_M150_DEFAULT -1 + #elif NEOPIXEL_M150_DEFAULT > 1 + #error "NEOPIXEL_M150_DEFAULT must be -1, 0, or 1." + #endif + int8_t brightness = neo.brightness(), unit = parser.intval('S', NEOPIXEL_M150_DEFAULT); switch (unit) { case -1: neo2.neoindex = index; // fall-thru case 0: neo.neoindex = index; old_color = parser.seen('K') ? neo.pixel_color(index >= 0 ? index : 0) : 0; break; diff --git a/Marlin/src/gcode/feature/leds/M7219.cpp b/Marlin/src/gcode/feature/leds/M7219.cpp index 40d3554dfe..1f74217be3 100644 --- a/Marlin/src/gcode/feature/leds/M7219.cpp +++ b/Marlin/src/gcode/feature/leds/M7219.cpp @@ -79,7 +79,7 @@ void GcodeSuite::M7219() { } if (parser.seen('P')) { - LOOP_L_N(r, MAX7219_LINES) { + for (uint8_t r = 0; r < MAX7219_LINES; ++r) { SERIAL_ECHOPGM("led_line["); if (r < 10) SERIAL_CHAR(' '); SERIAL_ECHO(r); diff --git a/Marlin/src/gcode/feature/mixing/M163-M165.cpp b/Marlin/src/gcode/feature/mixing/M163-M165.cpp index a4cb64e7d6..f4ea52df0a 100644 --- a/Marlin/src/gcode/feature/mixing/M163-M165.cpp +++ b/Marlin/src/gcode/feature/mixing/M163-M165.cpp @@ -76,7 +76,7 @@ void GcodeSuite::M164() { * I[factor] Mix factor for extruder stepper 6 */ void GcodeSuite::M165() { - // Get mixing parameters from the GCode + // Get mixing parameters from the G-Code // The total "must" be 1.0 (but it will be normalized) // If no mix factors are given, the old mix is preserved const char mixing_codes[] = { LIST_N(MIXING_STEPPERS, 'A', 'B', 'C', 'D', 'H', 'I') }; diff --git a/Marlin/src/gcode/feature/network/M552-M554.cpp b/Marlin/src/gcode/feature/network/M552-M554.cpp index 0973fb87bf..7633ec1fd5 100644 --- a/Marlin/src/gcode/feature/network/M552-M554.cpp +++ b/Marlin/src/gcode/feature/network/M552-M554.cpp @@ -46,7 +46,7 @@ void MAC_report() { if (ethernet.hardware_enabled) { Ethernet.MACAddress(mac); SERIAL_ECHOPGM(" MAC: "); - LOOP_L_N(i, 6) { + for (uint8_t i = 0; i < 6; ++i) { if (mac[i] < 16) SERIAL_CHAR('0'); SERIAL_PRINT(mac[i], PrintBase::Hex); if (i < 5) SERIAL_CHAR(':'); @@ -59,12 +59,11 @@ void MAC_report() { // otherwise show the stored values void ip_report(const uint16_t cmd, FSTR_P const post, const IPAddress &ipo) { SERIAL_CHAR('M'); SERIAL_ECHO(cmd); SERIAL_CHAR(' '); - LOOP_L_N(i, 4) { + for (uint8_t i = 0; i < 4; ++i) { SERIAL_ECHO(ipo[i]); if (i < 3) SERIAL_CHAR('.'); } - SERIAL_ECHOPGM(" ; "); - SERIAL_ECHOLNF(post); + SERIAL_ECHOLN(F(" ; "), post); } /** diff --git a/Marlin/src/gcode/feature/nonlinear/M592.cpp b/Marlin/src/gcode/feature/nonlinear/M592.cpp new file mode 100644 index 0000000000..dc8c1e1e58 --- /dev/null +++ b/Marlin/src/gcode/feature/nonlinear/M592.cpp @@ -0,0 +1,51 @@ +/** + * Marlin 3D Printer Firmware + * Copyright (c) 2023 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] + * + * Based on Sprinter and grbl. + * Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +#include "../../../inc/MarlinConfig.h" + +#if ENABLED(NONLINEAR_EXTRUSION) + +#include "../../gcode.h" +#include "../../../module/stepper.h" + +void GcodeSuite::M592_report(const bool forReplay/*=true*/) { + report_heading(forReplay, F(STR_NONLINEAR_EXTRUSION)); + SERIAL_ECHOLNPGM(" M593 A", stepper.ne.A, " B", stepper.ne.B, " C", stepper.ne.C); +} + +/** + * M592: Get or set nonlinear extrusion parameters + * A Linear coefficient (default 0.0) + * B Quadratic coefficient (default 0.0) + * C Constant coefficient (default 1.0) + * + * Adjusts the amount of extrusion based on the instantaneous velocity of extrusion, as a multiplier. + * The amount of extrusion is multiplied by max(C, C + A*v + B*v^2) where v is extruder velocity in mm/s. + * Only adjusts forward extrusions, since those are the ones affected by backpressure. + */ +void GcodeSuite::M592() { + if (parser.seenval('A')) stepper.ne.A = parser.value_float(); + if (parser.seenval('B')) stepper.ne.B = parser.value_float(); + if (parser.seenval('C')) stepper.ne.C = parser.value_float(); +} + +#endif // NONLINEAR_EXTRUSION diff --git a/Marlin/src/gcode/feature/pause/G27.cpp b/Marlin/src/gcode/feature/pause/G27.cpp index f61453e6fb..229b22a96c 100644 --- a/Marlin/src/gcode/feature/pause/G27.cpp +++ b/Marlin/src/gcode/feature/pause/G27.cpp @@ -29,7 +29,14 @@ #include "../../../module/motion.h" /** - * G27: Park the nozzle + * G27: Park the nozzle according with the given style + * + * P