Merge tag '2.1.2'

This commit is contained in:
Adam Bissen 2023-06-07 20:05:48 -05:00
commit 691d011459
2610 changed files with 280502 additions and 109410 deletions

View File

@ -4,16 +4,20 @@ root = true
[{*.patch,syntax_test_*}] [{*.patch,syntax_test_*}]
trim_trailing_whitespace = false trim_trailing_whitespace = false
[{*.c,*.cpp,*.h}] [{*.c,*.cpp,*.h,*.ino}]
charset = utf-8 charset = utf-8
[{*.c,*.cpp,*.h,Makefile}] [{*.c,*.cpp,*.h,*.ino,Makefile}]
trim_trailing_whitespace = true trim_trailing_whitespace = true
insert_final_newline = true insert_final_newline = true
end_of_line = lf end_of_line = lf
indent_style = space indent_style = space
indent_size = 2 indent_size = 2
[{*.py,*.conf,*.sublime-project}] [{*.py}]
indent_style = space
indent_size = 4
[{*.conf,*.sublime-project}]
indent_style = tab indent_style = tab
indent_size = 4 indent_size = 4

2
.gitattributes vendored
View File

@ -17,3 +17,5 @@
*.png binary *.png binary
*.jpg binary *.jpg binary
*.fon binary *.fon binary
*.bin binary
*.woff binary

View File

@ -1,43 +0,0 @@
---
name: Bug report
about: Report a bug in Marlin
title: "[BUG] (short description)"
labels: ''
assignees: ''
---
<!--
Have you read Marlin's Code of Conduct? By filing an Issue, you are expected to comply with it, including treating everyone with respect: https://github.com/MarlinFirmware/Marlin/blob/master/.github/code_of_conduct.md
Do you want to ask a question? Are you looking for support? Please don't post here. Instead please use one of the support links at https://github.com/MarlinFirmware/Marlin/issues/new/choose
Before filing an issue be sure to test the "bugfix" branches to see whether the issue has been resolved.
-->
### Bug Description
<!-- Description of the bug -->
### My Configurations
**Required:** Please include a ZIP file containing your `Configuration.h` and `Configuration_adv.h` files.
### Steps to Reproduce
<!-- Please describe the steps needed to reproduce the issue -->
1. [First Step]
2. [Second Step]
3. [and so on...]
**Expected behavior:** [What you expect to happen]
**Actual behavior:** [What actually happens]
#### Additional Information
* Provide pictures or links to videos that clearly demonstrate the issue.
* See [How Can I Contribute](#how-can-i-contribute) for additional guidelines.

View File

@ -1,17 +0,0 @@
blank_issues_enabled: false
contact_links:
- name: Marlin Documentation
url: http://marlinfw.org/
about: Lots of documentation on installing and using Marlin.
- name: MarlinFirmware Facebook group
url: https://www.facebook.com/groups/1049718498464482
about: Please ask and answer questions here.
- name: Marlin on Discord
url: https://discord.gg/n5NJ59y
about: Join the Discord server for support and discussion.
- name: Marlin Discussion Forum
url: http://forums.reprap.org/list.php?415
about: A searchable web forum hosted by RepRap dot org.
- name: Marlin Videos on YouTube
url: https://www.youtube.com/results?search_query=marlin+firmware
about: Tutorials and more from Marlin users all around the world. Great for new users!

View File

@ -1,35 +0,0 @@
---
name: Feature request
about: Request a Feature
title: "[FR] (feature request title)"
labels: 'T: Feature Request'
assignees: ''
---
<!--
Have you read Marlin's Code of Conduct? By filing an Issue, you are expected to comply with it, including treating everyone with respect: https://github.com/MarlinFirmware/Marlin/blob/master/.github/code_of_conduct.md
Do you want to ask a question? Are you looking for support? Please don't post here. Instead please use one of the support links at https://github.com/MarlinFirmware/Marlin/issues/new/choose
Before filing an issue be sure to test the "bugfix" branches to see whether the issue has been resolved.
-->
### Description
<!-- Description of the requested feature -->
### Feature Workflow
<!-- Please describe the feature's behavior, user interaction, etc. -->
1. [First Action]
2. [Second Action]
3. [and so on...]
#### Additional Information
* Provide pictures or links that demonstrate a similar feature or concept.
* See [How Can I Contribute](#how-can-i-contribute) for additional guidelines.

View File

@ -34,8 +34,11 @@ This project and everyone participating in it is governed by the [Marlin Code of
We have a Message Board and a Facebook group where our knowledgable user community can provide helpful advice if you have questions. We have a Message Board and a Facebook group where our knowledgable user community can provide helpful advice if you have questions.
* [Marlin RepRap forum](https://reprap.org/forum/list.php?415) - [Marlin Documentation](https://marlinfw.org) - Official Marlin documentation
* [MarlinFirmware on Facebook](https://www.facebook.com/groups/1049718498464482/) - Facebook Group ["Marlin Firmware"](https://www.facebook.com/groups/1049718498464482/)
- RepRap.org [Marlin Forum](https://forums.reprap.org/list.php?415)
- Facebook Group ["Marlin Firmware for 3D Printers"](https://www.facebook.com/groups/3Dtechtalk/)
- [Marlin Configuration](https://www.youtube.com/results?search_query=marlin+configuration) on YouTube
If chat is more your speed, you can join the MarlinFirmware Discord server: If chat is more your speed, you can join the MarlinFirmware Discord server:
@ -50,13 +53,13 @@ If chat is more your speed, you can join the MarlinFirmware Discord server:
This section guides you through submitting a Bug Report for Marlin. Following these guidelines helps maintainers and the community understand your report, reproduce the behavior, and find related reports. This section guides you through submitting a Bug Report for Marlin. Following these guidelines helps maintainers and the community understand your report, reproduce the behavior, and find related reports.
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.md), the information it asks for helps us resolve issues faster. 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? #### How Do I Submit A (Good) Bug Report?
Bugs are tracked as [GitHub issues](https://guides.github.com/features/issues/). Use the New Issue button to create an issue and provide the following information by filling in [the template](issue_template.md). Bugs are tracked as [GitHub issues](https://guides.github.com/features/issues/). Use the New Issue button to create an issue and provide the following information by filling in [the template](ISSUE_TEMPLATE/bug_report.yml).
Explain the problem and include additional details to help maintainers reproduce the problem: Explain the problem and include additional details to help maintainers reproduce the problem:
@ -88,12 +91,12 @@ Include details about your configuration and environment:
This section guides you through submitting a suggestion for Marlin, including completely new features and minor improvements to existing functionality. Following these guidelines helps maintainers and the community understand your suggestion and find related suggestions. This section guides you through submitting a suggestion for Marlin, including completely new features and minor improvements to existing functionality. Following these guidelines helps maintainers and the community understand your suggestion and find related suggestions.
Before creating a suggestion, please check [this list](#before-submitting-a-suggestion) as you might find out that you don't need to create one. When you are creating an enhancement suggestion, please [include as many details as possible](#how-do-i-submit-a-good-enhancement-suggestion). Fill in [the template](issue_template.md), including the steps that you imagine you would take if the feature you're requesting existed. Before creating a suggestion, please check [this list](https://github.com/MarlinFirmware/Marlin/issues?q=is%3Aopen+is%3Aissue+label%3A%22T%3A+Feature+Request%22) as you might find out that you don't need to create one. When you are creating an enhancement suggestion, please [include as many details as possible](#how-do-i-submit-a-good-feature-request). Fill in [the template](ISSUE_TEMPLATE/feature_request.yml), including the steps that you imagine you would take if the feature you're requesting existed.
#### Before Submitting a Feature Request #### Before Submitting a Feature Request
* **Check the [Marlin website](https://marlinfw.org/)** for tips — you might discover that the feature is already included. Most importantly, check if you're using [the latest version of Marlin](https://github.com/MarlinFirmware/Marlin/releases) and if you can get the desired behavior by changing [Marlin's config settings](https://marlinfw.org/docs/configuration/configuration.html). * **Check the [Marlin website](https://marlinfw.org/)** for tips — you might discover that the feature is already included. Most importantly, check if you're using [the latest version of Marlin](https://github.com/MarlinFirmware/Marlin/releases) and if you can get the desired behavior by changing [Marlin's config settings](https://marlinfw.org/docs/configuration/configuration.html).
* **Perform a [cursory search](https://github.com/MarlinFirmware/Marlin/issues?q=is%3Aissue)** to see if the enhancement has already been suggested. If it has, add a comment to the existing issue instead of opening a new one. * **Perform a [cursory search](https://github.com/MarlinFirmware/Marlin/issues?q=is%3Aopen+is%3Aissue+label%3A%22T%3A+Feature+Request%22)** to see if the enhancement has already been suggested. If it has, add a comment to the existing issue instead of opening a new one.
#### How Do I Submit A (Good) Feature Request? #### How Do I Submit A (Good) Feature Request?
@ -116,7 +119,7 @@ Unsure where to begin contributing to Marlin? You can start by looking through t
### Pull Requests ### Pull Requests
Pull Requests should always be targeted to working branches (e.g., `bugfix-1.1.x` and/or `bugfix-2.0.x`) and never to release branches (e.g., `1.1.x`). If this is your first Pull Request, please read our [Guide to Pull Requests](https://marlinfw.org/docs/development/getting_started_pull_requests.html) and Github's [Pull Request](https://help.github.com/articles/creating-a-pull-request/) documentation. Pull Requests should always be targeted to working branches (e.g., `bugfix-2.1.x` and/or `bugfix-1.1.x`) and never to release branches (e.g., `2.0.x` and/or `1.1.x`). If this is your first Pull Request, please read our [Guide to Pull Requests](https://marlinfw.org/docs/development/getting_started_pull_requests.html) and Github's [Pull Request](https://help.github.com/articles/creating-a-pull-request/) documentation.
* Fill in [the required template](pull_request_template.md). * Fill in [the required template](pull_request_template.md).
* Don't include issue numbers in the PR title. * Don't include issue numbers in the PR title.

View File

@ -1,11 +0,0 @@
# NO SUPPORT REQUESTS PLEASE
Do you want to ask a question? Are you looking for support? Please don't post here. Support Requests posted here will be automatically closed!
Instead use one of the following options:
- The Marlin Firmware forum at https://reprap.org/forum/list.php?415
- The MarlinFirmware Facebook Group at https://www.facebook.com/groups/1049718498464482/
- The MarlinFirmware Discord Server at https://discord.gg/n5NJ59y.
Before filing an issue be sure to test the latest "bugfix" branch to see whether the issue is already addressed.

40
.github/lock.yml vendored
View File

@ -1,40 +0,0 @@
#
# Configuration for Lock Threads - https://github.com/dessant/lock-threads-app
#
# Number of days of inactivity before a closed issue or pull request is locked
daysUntilLock: 60
# Skip issues and pull requests created before a given timestamp. Timestamp must
# follow ISO 8601 (`YYYY-MM-DD`). Set to `false` to disable
skipCreatedBefore: false
# Issues and pull requests with these labels will be ignored. Set to `[]` to disable
exemptLabels: [ 'no-locking' ]
# Label to add before locking, such as `outdated`. Set to `false` to disable
lockLabel: false
# Comment to post before locking. Set to `false` to disable
lockComment: >
This thread has been automatically locked since there has not been
any recent activity after it was closed. Please open a new issue for
related bugs.
# Assign `resolved` as the reason for locking. Set to `false` to disable
setLockReason: true
# Limit to only `issues` or `pulls`
# only: issues
# Optionally, specify configuration settings just for `issues` or `pulls`
# issues:
# exemptLabels:
# - help-wanted
# lockLabel: outdated
# pulls:
# daysUntilLock: 30
# Repository to extend settings from
# _extends: repo

View File

@ -1,23 +1,33 @@
### Requirements <!--
* Filling out this template is required. Pull Requests without a clear description may be closed at the maintainers' discretion. Submitting a Pull Request
- Please fill out all sections of this form. You can delete the helpful comments.
- Pull Requests without clear information will take longer and may even be rejected.
- We get a high volume of submissions so please be patient during review.
-->
### Description ### Description
<!-- <!--
We must be able to understand your proposed change from this description. If we can't understand what the code will do from this description, the Pull Request may be closed at the maintainers' discretion. Keep in mind that the maintainer reviewing this PR may not be familiar with or have worked with the code recently, so please walk us through the concepts. Clearly describe the submitted changes with lots of details. Include images where helpful. Initial reviewers may not be familiar with the subject, so be as thorough as possible. You can use MarkDown syntax to improve readability with bullet lists, code blocks, and so on. PREVIEW and fix up formatting before submitting.
--> -->
### Requirements
<!-- Does this PR require a specific board, LCD, etc.? -->
### Benefits ### Benefits
<!-- What does this fix or improve? --> <!-- What does this PR fix or improve? -->
### Configurations ### Configurations
<!-- Attach any Configuration.h, Configuration_adv.h, or platformio.ini files needed to compile/test your Pull Request. --> <!-- Attach Configurations ZIP and any other files needed to test this PR. -->
### Related Issues ### Related Issues
<!-- Whether this fixes a bug or fulfills a feature request, please list any related Issues here. --> <!-- Does this PR fix a bug or fulfill a Feature Request? Link related Issues here. -->

View File

@ -1,35 +0,0 @@
#
# bump-date.yml
# Bump the distribution date once per day
#
name: Bump Distribution Date
on:
schedule:
- cron: '0 0 * * *'
jobs:
bump_date:
name: Bump Distribution Date
if: github.repository == 'MarlinFirmware/Marlin'
runs-on: ubuntu-latest
steps:
- name: Check out bugfix-2.0.x
uses: actions/checkout@v2
with:
ref: bugfix-2.0.x
- name: Bump Distribution Date
run: |
# Inline Bump Script
DIST=$( date +"%Y-%m-%d" )
eval "sed -E -i 's/(#define +STRING_DISTRIBUTION_DATE) .*$/\1 \"$DIST\"/g' Marlin/src/inc/Version.h" && \
git config user.name "${GITHUB_ACTOR}" && \
git config user.email "${GITHUB_ACTOR}@users.noreply.github.com" && \
git add . && \
git commit -m "[cron] Bump distribution date ($DIST)" && \
git push

View File

@ -1,33 +0,0 @@
#
# check-pr.yml
# Close PRs directed at release branches
#
name: PR Bad Target
on:
pull_request:
branches:
- 1.0.x
- 1.1.x
- 2.0.x
jobs:
bad_target:
name: PR Bad Target
if: github.repository == 'MarlinFirmware/Marlin'
runs-on: ubuntu-latest
steps:
- uses: peter-evans/close-pull@v1
with:
delete-branch: false
comment: >
Thanks for your contribution! Unfortunately we can't accept PRs directed at release branches. We make patches to the bugfix branches and only later do we push them out as releases.
Please redo this PR starting with the `bugfix-2.0.x` branch and be careful to target `bugfix-2.0.x` when resubmitting the PR.
It may help to set your fork's default branch to `bugfix-2.0.x`.
See [this page](http://marlinfw.org/docs/development/getting_started_pull_requests.html) for full instructions.

View File

@ -1,27 +0,0 @@
#
# close-stale.yml
# Close open issues after a period of inactivity
#
name: Close Stale Issues
on:
schedule:
- cron: "22 1 * * *"
jobs:
stale:
name: Close Stale Issues
if: github.repository == 'MarlinFirmware/Marlin'
runs-on: ubuntu-latest
steps:
- uses: actions/stale@v3
with:
repo-token: ${{ secrets.GITHUB_TOKEN }}
stale-issue-message: 'This issue has had no activity in the last 30 days. Please add a reply if you want to keep this issue active, otherwise it will be automatically closed within 7 days.'
days-before-stale: 30
days-before-close: 7
stale-issue-label: 'stale-closing-soon'
exempt-issue-labels: 'T: Feature Request'

View File

@ -1,32 +0,0 @@
#
# lock-closed.yml
# Lock closed issues after a period of inactivity
#
name: Lock Closed Issues
on:
schedule:
- cron: '0 1/13 * * *'
jobs:
lock:
name: Lock Closed Issues
if: github.repository == 'MarlinFirmware/Marlin'
runs-on: ubuntu-latest
steps:
- uses: dessant/lock-threads@v2
with:
github-token: ${{ github.token }}
process-only: 'issues'
issue-lock-inactive-days: '60'
issue-exclude-created-before: ''
issue-exclude-labels: 'no-locking'
issue-lock-labels: ''
issue-lock-comment: >
This issue has been automatically locked since there
has not been any recent activity after it was closed.
Please open a new issue for related bugs.
issue-lock-reason: ''

View File

@ -1,123 +0,0 @@
#
# test-builds.yml
# Do test builds to catch compile errors
#
name: CI
on:
pull_request:
branches:
- bugfix-2.0.x
paths-ignore:
- config/**
- data/**
- docs/**
- '**/*.md'
push:
branches:
- bugfix-2.0.x
paths-ignore:
- config/**
- data/**
- docs/**
- '**/*.md'
jobs:
test_builds:
name: Run All Tests
if: github.repository == 'MarlinFirmware/Marlin'
runs-on: ubuntu-latest
strategy:
matrix:
test-platform:
# Base Environments
- DUE
- esp32
- linux_native
- mega2560
- teensy31
- teensy35
- teensy41
- SAMD51_grandcentral_m4
# Extended AVR Environments
- FYSETC_F6_13
- mega1280
- rambo
- sanguino1284p
- sanguino644p
# Extended STM32 Environments
- STM32F103RC_btt
- STM32F103RC_btt_USB
- STM32F103RE_btt
- STM32F103RE_btt_USB
- STM32F103RC_fysetc
- STM32F103RC_meeb
- jgaurora_a5s_a1
- STM32F103VE_longer
- STM32F407VE_black
- STM32F401VE_STEVAL
- BIGTREE_BTT002
- BIGTREE_SKR_PRO
- BIGTREE_GTR_V1_0
- mks_robin
- mks_robin_stm32
- ARMED
- FYSETC_S6
- STM32F070CB_malyan
- STM32F070RB_malyan
- malyan_M300
- mks_robin_lite
- FLYF407ZG
- rumba32
- mks_robin_pro
- STM32F103RET6_creality
- LERDGEX
- mks_robin_nano35
# Put lengthy tests last
- LPC1768
- LPC1769
# STM32 with non-STM framework. both broken for now. they should use HAL_STM32 which is working.
#- STM32F4
#- STM32F7
# Non-working environment tests
#- at90usb1286_cdc
#- at90usb1286_dfu
#- STM32F103CB_malyan
#- mks_robin_mini
steps:
- name: Select Python 3.7
uses: actions/setup-python@v1
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
- name: Install PlatformIO
run: |
pip install -U https://github.com/platformio/platformio-core/archive/develop.zip
platformio update
- name: Check out the PR
uses: actions/checkout@v2
- name: Run ${{ matrix.test-platform }} Tests
run: |
# Inline tests script
chmod +x buildroot/bin/*
chmod +x buildroot/tests/*
export PATH=./buildroot/bin/:./buildroot/tests/:${PATH}
run_tests . ${{ matrix.test-platform }}

View File

@ -1,22 +0,0 @@
#
# unlock-reopened.yml
# Unlock an issue whenever it is re-opened
#
name: "Unlock reopened issue"
on:
issues:
types: [reopened]
jobs:
unlock:
name: Unlock Reopened
if: github.repository == 'MarlinFirmware/Marlin'
runs-on: ubuntu-latest
steps:
- uses: OSDKDev/unlock-issues@v1.1
with:
repo-token: "${{ secrets.GITHUB_TOKEN }}"

62
.gitignore vendored
View File

@ -19,15 +19,19 @@
# along with this program. If not, see <https://www.gnu.org/licenses/>. # along with this program. If not, see <https://www.gnu.org/licenses/>.
# #
# Our automatic versioning scheme generates the following file # Generated files
# NEVER put it in the repository
_Version.h _Version.h
bdf2u8g
marlin_config.json
mczip.h
*.gen
*.sublime-workspace
# #
# OS # OS
# #
applet/ applet/
*.DS_Store .DS_Store
# #
# Misc # Misc
@ -37,7 +41,6 @@ applet/
*.rej *.rej
*.bak *.bak
*.idea *.idea
*.s
*.i *.i
*.ii *.ii
*.swp *.swp
@ -77,7 +80,6 @@ tags
*.out *.out
*.app *.app
# #
# C # C
# #
@ -123,33 +125,10 @@ tags
.gcc-flags.json .gcc-flags.json
/lib/ /lib/
# Workaround for Deviot+platformio quirks
Marlin/lib
Marlin/platformio.ini
Marlin/*/platformio.ini
Marlin/*/*/platformio.ini
Marlin/*/*/*/platformio.ini
Marlin/*/*/*/*/platformio.ini
Marlin/.travis.yml
Marlin/*/.travis.yml
Marlin/*/*/.travis.yml
Marlin/*/*/*/.travis.yml
Marlin/*/*/*/*/.travis.yml
Marlin/.gitignore
Marlin/*/.gitignore
Marlin/*/*/.gitignore
Marlin/*/*/*/.gitignore
Marlin/*/*/*/*/.gitignore
Marlin/readme.txt
Marlin/*/readme.txt
Marlin/*/*/readme.txt
Marlin/*/*/*/readme.txt
Marlin/*/*/*/*/readme.txt
# Secure Credentials # Secure Credentials
Configuration_Secure.h Configuration_Secure.h
#Visual Studio # Visual Studio
*.sln *.sln
*.vcxproj *.vcxproj
*.vcxproj.user *.vcxproj.user
@ -160,27 +139,34 @@ __vm/
.vs/ .vs/
vc-fileutils.settings vc-fileutils.settings
#Visual Studio Code # Visual Studio Code
.vscode .vscode/*
.vscode/.browse.c_cpp.db* !.vscode/extensions.json
.vscode/c_cpp_properties.json
.vscode/launch.json #Simulation
.vscode/*.db imgui.ini
eeprom.dat
spi_flash.bin
fs.img
#cmake #cmake
CMakeLists.txt CMakeLists.txt
src/CMakeLists.txt src/CMakeLists.txt
CMakeListsPrivate.txt CMakeListsPrivate.txt
build/
#CLion # CLion
cmake-build-* cmake-build-*
#Eclipse # Eclipse
.project .project
.cproject .cproject
.pydevproject .pydevproject
.settings .settings
.classpath .classpath
#Python # Python
__pycache__ __pycache__
# IOLogger logs
*_log.csv

11
.vscode/extensions.json vendored Normal file
View File

@ -0,0 +1,11 @@
{
// See http://go.microsoft.com/fwlink/?LinkId=827846
// for the documentation about the extensions.json format
"recommendations": [
"marlinfirmware.auto-build",
"platformio.platformio-ide"
],
"unwantedRecommendations": [
"ms-vscode.cpptools-extension-pack"
]
}

52
Makefile Normal file
View File

@ -0,0 +1,52 @@
help:
@echo "Tasks for local development:"
@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-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 ""
@echo "Options for testing:"
@echo " TEST_TARGET Set when running tests-single-*, to select the"
@echo " test. If you set it to ALL it will run all "
@echo " tests, but some of them are broken: use "
@echo " tests-all-* instead to run only the ones that "
@echo " run on GitHub CI"
@echo " ONLY_TEST Limit tests to only those that contain this, or"
@echo " the index of the test (1-based)"
@echo " VERBOSE_PLATFORMIO If you want the full PIO output, set any value"
@echo " GIT_RESET_HARD Used by CI: reset all local changes. WARNING:"
@echo " THIS WILL UNDO ANY CHANGES YOU'VE MADE!"
.PHONY: help
tests-single-ci:
export GIT_RESET_HARD=true
$(MAKE) tests-single-local TEST_TARGET=$(TEST_TARGET)
.PHONY: tests-single-ci
tests-single-local:
@if ! test -n "$(TEST_TARGET)" ; then echo "***ERROR*** Set TEST_TARGET=<your-module> or use make tests-all-local" ; return 1; fi
export PATH="./buildroot/bin/:./buildroot/tests/:${PATH}" \
&& export VERBOSE_PLATFORMIO=$(VERBOSE_PLATFORMIO) \
&& run_tests . $(TEST_TARGET) "$(ONLY_TEST)"
.PHONY: tests-single-local
tests-single-local-docker:
@if ! test -n "$(TEST_TARGET)" ; then echo "***ERROR*** Set TEST_TARGET=<your-module> 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)"
.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
.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)
.PHONY: tests-all-local-docker
setup-local-docker:
docker-compose build
.PHONY: setup-local-docker

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -109,8 +109,8 @@ LIQUID_TWI2 ?= 0
# This defines if Wire is needed # This defines if Wire is needed
WIRE ?= 0 WIRE ?= 0
# This defines if Tone is needed (i.e SPEAKER is defined in Configuration.h) # This defines if Tone is needed (i.e., SPEAKER is defined in Configuration.h)
# Disabling this (and SPEAKER) saves approximatively 350 bytes of memory. # Disabling this (and SPEAKER) saves approximately 350 bytes of memory.
TONE ?= 1 TONE ?= 1
# This defines if U8GLIB is needed (may require RELOC_WORKAROUND) # This defines if U8GLIB is needed (may require RELOC_WORKAROUND)
@ -132,7 +132,7 @@ CC_MIN:=$(shell $(CC) -dM -E - < /dev/null | grep __GNUC_MINOR__ | cut -f3 -d\ )
CC_PATCHLEVEL:=$(shell $(CC) -dM -E - < /dev/null | grep __GNUC_PATCHLEVEL__ | cut -f3 -d\ ) CC_PATCHLEVEL:=$(shell $(CC) -dM -E - < /dev/null | grep __GNUC_PATCHLEVEL__ | cut -f3 -d\ )
CC_VER:=$(shell echo $$(( $(CC_MAJ) * 10000 + $(CC_MIN) * 100 + $(CC_PATCHLEVEL) ))) CC_VER:=$(shell echo $$(( $(CC_MAJ) * 10000 + $(CC_MIN) * 100 + $(CC_PATCHLEVEL) )))
ifeq ($(shell test $(CC_VER) -lt 40901 && echo 1),1) ifeq ($(shell test $(CC_VER) -lt 40901 && echo 1),1)
@echo This version of GCC is likely broken. Enabling relocation workaround. $(warning This GCC version $(CC_VER) is likely broken. Enabling relocation workaround.)
RELOC_WORKAROUND = 1 RELOC_WORKAROUND = 1
endif endif
@ -207,11 +207,11 @@ else ifeq ($(HARDWARE_MOTHERBOARD),1105)
else ifeq ($(HARDWARE_MOTHERBOARD),1106) else ifeq ($(HARDWARE_MOTHERBOARD),1106)
# MKS BASE v1.0 # MKS BASE v1.0
else ifeq ($(HARDWARE_MOTHERBOARD),1107) else ifeq ($(HARDWARE_MOTHERBOARD),1107)
# MKS v1.4 with A4982 stepper drivers # MKS BASE v1.4 with Allegro A4982 stepper drivers
else ifeq ($(HARDWARE_MOTHERBOARD),1108) else ifeq ($(HARDWARE_MOTHERBOARD),1108)
# MKS v1.5 with Allegro A4982 stepper drivers # MKS BASE v1.5 with Allegro A4982 stepper drivers
else ifeq ($(HARDWARE_MOTHERBOARD),1109) else ifeq ($(HARDWARE_MOTHERBOARD),1109)
# MKS v1.6 with Allegro A4982 stepper drivers # MKS BASE v1.6 with Allegro A4982 stepper drivers
else ifeq ($(HARDWARE_MOTHERBOARD),1110) else ifeq ($(HARDWARE_MOTHERBOARD),1110)
# MKS BASE 1.0 with Heroic HR4982 stepper drivers # MKS BASE 1.0 with Heroic HR4982 stepper drivers
else ifeq ($(HARDWARE_MOTHERBOARD),1111) else ifeq ($(HARDWARE_MOTHERBOARD),1111)
@ -219,93 +219,110 @@ else ifeq ($(HARDWARE_MOTHERBOARD),1111)
else ifeq ($(HARDWARE_MOTHERBOARD),1112) else ifeq ($(HARDWARE_MOTHERBOARD),1112)
# MKS GEN L # MKS GEN L
else ifeq ($(HARDWARE_MOTHERBOARD),1113) else ifeq ($(HARDWARE_MOTHERBOARD),1113)
# zrib V2.0 control board (Chinese knock off RAMPS replica)
else ifeq ($(HARDWARE_MOTHERBOARD),1114)
# BigTreeTech or BIQU KFB2.0 # BigTreeTech or BIQU KFB2.0
else ifeq ($(HARDWARE_MOTHERBOARD),1114)
# zrib V2.0 (Chinese RAMPS replica)
else ifeq ($(HARDWARE_MOTHERBOARD),1115) else ifeq ($(HARDWARE_MOTHERBOARD),1115)
# Felix 2.0+ Electronics Board (RAMPS like) # zrib V5.2 (Chinese RAMPS replica)
else ifeq ($(HARDWARE_MOTHERBOARD),1116) else ifeq ($(HARDWARE_MOTHERBOARD),1116)
# Invent-A-Part RigidBoard # Felix 2.0+ Electronics Board (RAMPS like)
else ifeq ($(HARDWARE_MOTHERBOARD),1117) else ifeq ($(HARDWARE_MOTHERBOARD),1117)
# Invent-A-Part RigidBoard V2 # Invent-A-Part RigidBoard
else ifeq ($(HARDWARE_MOTHERBOARD),1118) else ifeq ($(HARDWARE_MOTHERBOARD),1118)
# Sainsmart 2-in-1 board # Invent-A-Part RigidBoard V2
else ifeq ($(HARDWARE_MOTHERBOARD),1119) else ifeq ($(HARDWARE_MOTHERBOARD),1119)
# Ultimaker # Sainsmart 2-in-1 board
else ifeq ($(HARDWARE_MOTHERBOARD),1120) else ifeq ($(HARDWARE_MOTHERBOARD),1120)
# Ultimaker (Older electronics. Pre 1.5.4. This is rare) # Ultimaker
else ifeq ($(HARDWARE_MOTHERBOARD),1121) else ifeq ($(HARDWARE_MOTHERBOARD),1121)
# Ultimaker (Older electronics. Pre 1.5.4. This is rare)
else ifeq ($(HARDWARE_MOTHERBOARD),1122)
MCU ?= atmega1280 MCU ?= atmega1280
PROG_MCU ?= m1280 PROG_MCU ?= m1280
# Azteeg X3 # Azteeg X3
else ifeq ($(HARDWARE_MOTHERBOARD),1122)
# Azteeg X3 Pro
else ifeq ($(HARDWARE_MOTHERBOARD),1123) else ifeq ($(HARDWARE_MOTHERBOARD),1123)
# Ultimainboard 2.x (Uses TEMP_SENSOR 20) # Azteeg X3 Pro
else ifeq ($(HARDWARE_MOTHERBOARD),1124) else ifeq ($(HARDWARE_MOTHERBOARD),1124)
# Rumba # Ultimainboard 2.x (Uses TEMP_SENSOR 20)
else ifeq ($(HARDWARE_MOTHERBOARD),1125) else ifeq ($(HARDWARE_MOTHERBOARD),1125)
# Raise3D Rumba # Rumba
else ifeq ($(HARDWARE_MOTHERBOARD),1126) else ifeq ($(HARDWARE_MOTHERBOARD),1126)
# Rapide Lite RL200 Rumba # Raise3D N series Rumba derivative
else ifeq ($(HARDWARE_MOTHERBOARD),1127) else ifeq ($(HARDWARE_MOTHERBOARD),1127)
# Formbot T-Rex 2 Plus # Rapide Lite 200 (v1, low-cost RUMBA clone with drv)
else ifeq ($(HARDWARE_MOTHERBOARD),1128) else ifeq ($(HARDWARE_MOTHERBOARD),1128)
# Formbot T-Rex 3 # Formbot T-Rex 2 Plus
else ifeq ($(HARDWARE_MOTHERBOARD),1129) else ifeq ($(HARDWARE_MOTHERBOARD),1129)
# Formbot Raptor # Formbot T-Rex 3
else ifeq ($(HARDWARE_MOTHERBOARD),1130) else ifeq ($(HARDWARE_MOTHERBOARD),1130)
# Formbot Raptor 2 # Formbot Raptor
else ifeq ($(HARDWARE_MOTHERBOARD),1131) else ifeq ($(HARDWARE_MOTHERBOARD),1131)
# bq ZUM Mega 3D # Formbot Raptor 2
else ifeq ($(HARDWARE_MOTHERBOARD),1132) else ifeq ($(HARDWARE_MOTHERBOARD),1132)
# MakeBoard Mini v2.1.2 is a control board sold by MicroMake # bq ZUM Mega 3D
else ifeq ($(HARDWARE_MOTHERBOARD),1133) else ifeq ($(HARDWARE_MOTHERBOARD),1133)
# TriGorilla Anycubic version 1.3 based on RAMPS EFB # MakeBoard Mini v2.1.2 by MicroMake
else ifeq ($(HARDWARE_MOTHERBOARD),1134) else ifeq ($(HARDWARE_MOTHERBOARD),1134)
# TriGorilla Anycubic version 1.4 based on RAMPS EFB # TriGorilla Anycubic version 1.3-based on RAMPS EFB
else ifeq ($(HARDWARE_MOTHERBOARD),1135) else ifeq ($(HARDWARE_MOTHERBOARD),1135)
# TriGorilla Anycubic version 1.4 Rev 1.1 # ... Ver 1.4
else ifeq ($(HARDWARE_MOTHERBOARD),1136) else ifeq ($(HARDWARE_MOTHERBOARD),1136)
# Creality: Ender-4, CR-8 # ... Rev 1.1 (new servo pin order)
else ifeq ($(HARDWARE_MOTHERBOARD),1137) else ifeq ($(HARDWARE_MOTHERBOARD),1137)
# Creality: CR10S, CR20, CR-X # Creality: Ender-4, CR-8
else ifeq ($(HARDWARE_MOTHERBOARD),1138) else ifeq ($(HARDWARE_MOTHERBOARD),1138)
# Dagoma F5 # Creality: CR10S, CR20, CR-X
else ifeq ($(HARDWARE_MOTHERBOARD),1139) else ifeq ($(HARDWARE_MOTHERBOARD),1139)
# FYSETC F6 1.3 # Dagoma F5
else ifeq ($(HARDWARE_MOTHERBOARD),1140) else ifeq ($(HARDWARE_MOTHERBOARD),1140)
# FYSETC F6 1.5 # FYSETC F6 1.3
else ifeq ($(HARDWARE_MOTHERBOARD),1141) else ifeq ($(HARDWARE_MOTHERBOARD),1141)
# Duplicator i3 Plus # FYSETC F6 1.4
else ifeq ($(HARDWARE_MOTHERBOARD),1142) else ifeq ($(HARDWARE_MOTHERBOARD),1142)
# VORON # Wanhao Duplicator i3 Plus
else ifeq ($(HARDWARE_MOTHERBOARD),1143) else ifeq ($(HARDWARE_MOTHERBOARD),1143)
# TRONXY V3 1.0 # VORON Design
else ifeq ($(HARDWARE_MOTHERBOARD),1144) else ifeq ($(HARDWARE_MOTHERBOARD),1144)
# Z-Bolt X Series # Tronxy TRONXY-V3-1.0
else ifeq ($(HARDWARE_MOTHERBOARD),1145) else ifeq ($(HARDWARE_MOTHERBOARD),1145)
# TT OSCAR # Z-Bolt X Series
else ifeq ($(HARDWARE_MOTHERBOARD),1146) else ifeq ($(HARDWARE_MOTHERBOARD),1146)
# Overlord/Overlord Pro # TT OSCAR
else ifeq ($(HARDWARE_MOTHERBOARD),1147) else ifeq ($(HARDWARE_MOTHERBOARD),1147)
# ADIMLab Gantry v1 # Overlord/Overlord Pro
else ifeq ($(HARDWARE_MOTHERBOARD),1148) else ifeq ($(HARDWARE_MOTHERBOARD),1148)
# ADIMLab Gantry v2 # ADIMLab Gantry v1
else ifeq ($(HARDWARE_MOTHERBOARD),1149) else ifeq ($(HARDWARE_MOTHERBOARD),1149)
# BIQU Tango V1 # ADIMLab Gantry v2
else ifeq ($(HARDWARE_MOTHERBOARD),1150) else ifeq ($(HARDWARE_MOTHERBOARD),1150)
# MKS GEN L V2 # BIQU Tango V1
else ifeq ($(HARDWARE_MOTHERBOARD),1151) else ifeq ($(HARDWARE_MOTHERBOARD),1151)
# MKS GEN L V2.1 # MKS GEN L V2
else ifeq ($(HARDWARE_MOTHERBOARD),1152) else ifeq ($(HARDWARE_MOTHERBOARD),1152)
# Copymaster 3D # MKS GEN L V2.1
else ifeq ($(HARDWARE_MOTHERBOARD),1153) else ifeq ($(HARDWARE_MOTHERBOARD),1153)
# Ortur 4 # Copymaster 3D
else ifeq ($(HARDWARE_MOTHERBOARD),1154) else ifeq ($(HARDWARE_MOTHERBOARD),1154)
# Tenlog D3 Hero # Ortur 4
else ifeq ($(HARDWARE_MOTHERBOARD),1155) else ifeq ($(HARDWARE_MOTHERBOARD),1155)
# Tenlog D3 Hero IDEX printer
else ifeq ($(HARDWARE_MOTHERBOARD),1156)
# Tenlog D3,5,6 Pro IDEX printers
else ifeq ($(HARDWARE_MOTHERBOARD),1157)
# Ramps S 1.2 by Sakul.cz (Power outputs: Hotend0, Hotend1, Fan, Bed)
else ifeq ($(HARDWARE_MOTHERBOARD),1158)
# Ramps S 1.2 by Sakul.cz (Power outputs: Hotend0, Hotend1, Hotend2, Bed)
else ifeq ($(HARDWARE_MOTHERBOARD),1159)
# Ramps S 1.2 by Sakul.cz (Power outputs: Hotend, Fan0, Fan1, Bed)
else ifeq ($(HARDWARE_MOTHERBOARD),1160)
# Longer LK1 PRO / Alfawise U20 Pro (PRO version)
else ifeq ($(HARDWARE_MOTHERBOARD),1161)
# Longer LKx PRO / Alfawise Uxx Pro (PRO version)
else ifeq ($(HARDWARE_MOTHERBOARD),1162)
# Zonestar zrib V5.3 (Chinese RAMPS replica)
else ifeq ($(HARDWARE_MOTHERBOARD),1163)
# Pxmalion Core I3
else ifeq ($(HARDWARE_MOTHERBOARD),1164)
# #
# RAMBo and derivatives # RAMBo and derivatives
@ -323,6 +340,8 @@ else ifeq ($(HARDWARE_MOTHERBOARD),1203)
else ifeq ($(HARDWARE_MOTHERBOARD),1204) else ifeq ($(HARDWARE_MOTHERBOARD),1204)
# abee Scoovo X9H # abee Scoovo X9H
else ifeq ($(HARDWARE_MOTHERBOARD),1205) else ifeq ($(HARDWARE_MOTHERBOARD),1205)
# Rambo ThinkerV2
else ifeq ($(HARDWARE_MOTHERBOARD),1206)
# #
# Other ATmega1280, ATmega2560 # Other ATmega1280, ATmega2560
@ -356,20 +375,38 @@ else ifeq ($(HARDWARE_MOTHERBOARD),1311)
else ifeq ($(HARDWARE_MOTHERBOARD),1312) else ifeq ($(HARDWARE_MOTHERBOARD),1312)
# Mega controller # Mega controller
else ifeq ($(HARDWARE_MOTHERBOARD),1313) else ifeq ($(HARDWARE_MOTHERBOARD),1313)
# Geeetech GT2560 Rev B for Mecreator2 # Geeetech GT2560 Rev A
else ifeq ($(HARDWARE_MOTHERBOARD),1314) else ifeq ($(HARDWARE_MOTHERBOARD),1314)
# Geeetech GT2560 Rev. A # Geeetech GT2560 Rev A+ (with auto level probe)
else ifeq ($(HARDWARE_MOTHERBOARD),1315) else ifeq ($(HARDWARE_MOTHERBOARD),1315)
# Geeetech GT2560 Rev. A+ (with auto level probe) # Geeetech GT2560 Rev B
else ifeq ($(HARDWARE_MOTHERBOARD),1316) else ifeq ($(HARDWARE_MOTHERBOARD),1316)
# Geeetech GT2560 Rev B for A10(M/D) # Geeetech GT2560 Rev B for A10(M/T/D)
else ifeq ($(HARDWARE_MOTHERBOARD),1317) else ifeq ($(HARDWARE_MOTHERBOARD),1317)
# Geeetech GT2560 Rev B for A20(M/D) # Geeetech GT2560 Rev B for A10(M/T/D)
else ifeq ($(HARDWARE_MOTHERBOARD),1318) else ifeq ($(HARDWARE_MOTHERBOARD),1318)
# Einstart retrofit # Geeetech GT2560 Rev B for Mecreator2
else ifeq ($(HARDWARE_MOTHERBOARD),1319) else ifeq ($(HARDWARE_MOTHERBOARD),1319)
# Wanhao 0ne+ i3 Mini # Geeetech GT2560 Rev B for A20(M/T/D)
else ifeq ($(HARDWARE_MOTHERBOARD),1320) else ifeq ($(HARDWARE_MOTHERBOARD),1320)
# Einstart retrofit
else ifeq ($(HARDWARE_MOTHERBOARD),1321)
# Wanhao 0ne+ i3 Mini
else ifeq ($(HARDWARE_MOTHERBOARD),1322)
# Leapfrog Xeed 2015
else ifeq ($(HARDWARE_MOTHERBOARD),1323)
# PICA Shield (original version)
else ifeq ($(HARDWARE_MOTHERBOARD),1324)
# PICA Shield (rev C or later)
else ifeq ($(HARDWARE_MOTHERBOARD),1325)
# Intamsys 4.0 (Funmat HT)
else ifeq ($(HARDWARE_MOTHERBOARD),1326)
# Malyan M180 Mainboard Version 2 (no display function, direct G-code only)
else ifeq ($(HARDWARE_MOTHERBOARD),1327)
# Geeetech GT2560 Rev B for A20(M/T/D)
else ifeq ($(HARDWARE_MOTHERBOARD),1328)
# Mega controller & Protoneer CNC Shield V3.00
else ifeq ($(HARDWARE_MOTHERBOARD),1329)
# #
# ATmega1281, ATmega2561 # ATmega1281, ATmega2561
@ -443,6 +480,11 @@ else ifeq ($(HARDWARE_MOTHERBOARD),1510)
HARDWARE_VARIANT ?= Sanguino HARDWARE_VARIANT ?= Sanguino
MCU ?= atmega1284p MCU ?= atmega1284p
PROG_MCU ?= m1284p PROG_MCU ?= m1284p
# ZoneStar ZMIB V2
else ifeq ($(HARDWARE_MOTHERBOARD),1511)
HARDWARE_VARIANT ?= Sanguino
MCU ?= atmega1284p
PROG_MCU ?= m1284p
# #
# Other ATmega644P, ATmega644, ATmega1284P # Other ATmega644P, ATmega644, ATmega1284P
@ -991,5 +1033,5 @@ clean:
.PHONY: all build elf hex eep lss sym program coff extcoff clean depend sizebefore sizeafter .PHONY: all build elf hex eep lss sym program coff extcoff clean depend sizebefore sizeafter
# Automaticaly include the dependency files created by gcc # Automatically include the dependency files created by gcc
-include ${patsubst %.o, %.d, ${OBJ}} -include ${patsubst %.o, %.d, ${OBJ}}

View File

@ -28,7 +28,7 @@
/** /**
* Marlin release version identifier * Marlin release version identifier
*/ */
//#define SHORT_BUILD_VERSION "2.0.7.2" //#define SHORT_BUILD_VERSION "2.1.2"
/** /**
* Verbose version identifier which should contain a reference to the location * Verbose version identifier which should contain a reference to the location
@ -41,7 +41,7 @@
* here we define this default string as the date where the latest release * here we define this default string as the date where the latest release
* version was tagged. * version was tagged.
*/ */
//#define STRING_DISTRIBUTION_DATE "2020-07-09" //#define STRING_DISTRIBUTION_DATE "2022-12-17"
/** /**
* Defines a generic printer name to be output to the LCD after booting Marlin. * Defines a generic printer name to be output to the LCD after booting Marlin.
@ -54,7 +54,7 @@
* has a distinct Github fork the Source Code URL should just be the main * has a distinct Github fork the Source Code URL should just be the main
* Marlin repository. * Marlin repository.
*/ */
//#define SOURCE_CODE_URL "https://github.com/MarlinFirmware/Marlin" //#define SOURCE_CODE_URL "github.com/MarlinFirmware/Marlin"
/** /**
* Default generic printer UUID. * Default generic printer UUID.
@ -65,7 +65,7 @@
* The WEBSITE_URL is the location where users can get more information such as * The WEBSITE_URL is the location where users can get more information such as
* documentation about a specific Marlin release. * documentation about a specific Marlin release.
*/ */
//#define WEBSITE_URL "https://marlinfw.org" //#define WEBSITE_URL "marlinfw.org"
/** /**
* Set the vendor info the serial USB interface, if changable * Set the vendor info the serial USB interface, if changable

211
Marlin/config.ini Normal file
View File

@ -0,0 +1,211 @@
#
# Marlin Firmware
# config.ini - Options to apply before the build
#
[config:base]
ini_use_config = none
# Load all config: sections in this file
;ini_use_config = all
# Load config file relative to Marlin/
;ini_use_config = another.ini
# Download configurations from GitHub
;ini_use_config = example/Creality/Ender-5 Plus @ bugfix-2.1.x
# Download configurations from your server
;ini_use_config = https://me.myserver.com/path/to/configs
# Evaluate config:base and do a config dump
;ini_use_config = base
;config_export = 2
[config:minimal]
motherboard = BOARD_RAMPS_14_EFB
serial_port = 0
baudrate = 250000
use_watchdog = on
thermal_protection_hotends = on
thermal_protection_hysteresis = 4
thermal_protection_period = 40
bufsize = 4
block_buffer_size = 16
max_cmd_size = 96
extruders = 1
temp_sensor_0 = 1
temp_hysteresis = 3
heater_0_mintemp = 5
heater_0_maxtemp = 275
preheat_1_temp_hotend = 180
bang_max = 255
pidtemp = on
pid_k1 = 0.95
pid_max = BANG_MAX
pid_functional_range = 10
default_kp = 22.20
default_ki = 1.08
default_kd = 114.00
x_driver_type = A4988
y_driver_type = A4988
z_driver_type = A4988
e0_driver_type = A4988
x_bed_size = 200
x_min_pos = 0
x_max_pos = X_BED_SIZE
y_bed_size = 200
y_min_pos = 0
y_max_pos = Y_BED_SIZE
z_min_pos = 0
z_max_pos = 200
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
default_axis_steps_per_unit = { 80, 80, 400, 500 }
axis_relative_modes = { false, false, false, false }
default_max_feedrate = { 300, 300, 5, 25 }
default_max_acceleration = { 3000, 3000, 100, 10000 }
homing_feedrate_mm_m = { (50*60), (50*60), (4*60) }
homing_bump_divisor = { 2, 2, 4 }
x_enable_on = 0
y_enable_on = 0
z_enable_on = 0
e_enable_on = 0
invert_x_dir = false
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
disable_x = false
disable_y = false
disable_z = false
disable_e = false
proportional_font_ratio = 1.0
default_nominal_filament_dia = 1.75
junction_deviation_mm = 0.013
default_acceleration = 3000
default_travel_acceleration = 3000
default_retract_acceleration = 3000
default_minimumfeedrate = 0.0
default_mintravelfeedrate = 0.0
minimum_planner_speed = 0.05
min_steps_per_segment = 6
default_minsegmenttime = 20000
[config:basic]
bed_overshoot = 10
busy_while_heating = on
default_ejerk = 5.0
default_keepalive_interval = 2
default_leveling_fade_height = 0.0
disable_inactive_extruder = on
display_charset_hd44780 = JAPANESE
eeprom_boot_silent = on
eeprom_chitchat = on
endstoppullups = on
extrude_maxlength = 200
extrude_mintemp = 170
host_keepalive_feature = on
hotend_overshoot = 15
jd_handle_small_segments = on
lcd_info_screen_style = 0
lcd_language = en
max_bed_power = 255
mesh_inset = 0
min_software_endstops = on
max_software_endstops = on
min_software_endstop_x = on
min_software_endstop_y = on
min_software_endstop_z = on
max_software_endstop_x = on
max_software_endstop_y = on
max_software_endstop_z = on
preheat_1_fan_speed = 0
preheat_1_label = "PLA"
preheat_1_temp_bed = 70
prevent_cold_extrusion = on
prevent_lengthy_extrude = on
printjob_timer_autostart = on
probing_margin = 10
show_bootscreen = on
soft_pwm_scale = 0
string_config_h_author = "(none, default config)"
temp_bed_hysteresis = 3
temp_bed_residency_time = 10
temp_bed_window = 1
temp_residency_time = 10
temp_window = 1
validate_homing_endstops = on
xy_probe_feedrate = (133*60)
z_clearance_between_probes = 5
z_clearance_deploy_probe = 10
z_clearance_multi_probe = 5
[config:advanced]
arc_support = on
auto_report_temperatures = on
autotemp = on
autotemp_oldweight = 0.98
bed_check_interval = 5000
default_stepper_deactive_time = 120
default_volumetric_extruder_limit = 0.00
disable_inactive_e = true
disable_inactive_x = true
disable_inactive_y = true
disable_inactive_z = true
e0_auto_fan_pin = -1
encoder_100x_steps_per_sec = 80
encoder_10x_steps_per_sec = 30
encoder_rate_multiplier = on
extended_capabilities_report = on
extruder_auto_fan_speed = 255
extruder_auto_fan_temperature = 50
fanmux0_pin = -1
fanmux1_pin = -1
fanmux2_pin = -1
faster_gcode_parser = on
homing_bump_mm = { 5, 5, 2 }
max_arc_segment_mm = 1.0
min_arc_segment_mm = 0.1
min_circle_segments = 72
n_arc_correction = 25
serial_overrun_protection = on
slowdown = on
slowdown_divisor = 2
temp_sensor_bed = 0
thermal_protection_bed_hysteresis = 2
thermocouple_max_errors = 15
tx_buffer_size = 0
watch_bed_temp_increase = 2
watch_bed_temp_period = 60
watch_temp_increase = 2
watch_temp_period = 20

View File

@ -23,18 +23,45 @@
#include "../../inc/MarlinConfig.h" #include "../../inc/MarlinConfig.h"
#include "HAL.h" #include "HAL.h"
#include <avr/wdt.h>
#ifdef USBCON
DefaultSerial1 MSerial0(false, Serial);
#ifdef BLUETOOTH
BTSerial btSerial(false, bluetoothSerial);
#endif
#endif
// ------------------------ // ------------------------
// Public Variables // Public Variables
// ------------------------ // ------------------------
//uint8_t MCUSR; // Don't initialize/override variable (which would happen in .init4)
uint8_t MarlinHAL::reset_reason __attribute__((section(".noinit")));
// ------------------------ // ------------------------
// Public functions // Public functions
// ------------------------ // ------------------------
void HAL_init() { __attribute__((naked)) // Don't output function pro- and epilogue
__attribute__((used)) // Output the function, even if "not used"
__attribute__((section(".init3"))) // Put in an early user definable section
void save_reset_reason() {
#if ENABLED(OPTIBOOT_RESET_REASON)
__asm__ __volatile__(
A("STS %0, r2")
: "=m"(hal.reset_reason)
);
#else
hal.reset_reason = MCUSR;
#endif
// Clear within 16ms since WDRF bit enables a 16ms watchdog timer -> Boot loop
hal.clear_reset_source();
wdt_disable();
}
void MarlinHAL::init() {
// Init Servo Pins // Init Servo Pins
#define INIT_SERVO(N) OUT_WRITE(SERVO##N##_PIN, LOW) #define INIT_SERVO(N) OUT_WRITE(SERVO##N##_PIN, LOW)
#if HAS_SERVO_0 #if HAS_SERVO_0
@ -49,8 +76,75 @@ void HAL_init() {
#if HAS_SERVO_3 #if HAS_SERVO_3
INIT_SERVO(3); INIT_SERVO(3);
#endif #endif
init_pwm_timers(); // Init user timers to default frequency - 1000HZ
} }
void MarlinHAL::reboot() {
#if ENABLED(USE_WATCHDOG)
while (1) { /* run out the watchdog */ }
#else
void (*resetFunc)() = 0; // Declare resetFunc() at address 0
resetFunc(); // Jump to address 0
#endif
}
// ------------------------
// Watchdog Timer
// ------------------------
#if ENABLED(USE_WATCHDOG)
#include <avr/wdt.h>
#include "../../MarlinCore.h"
// Initialize watchdog with 8s timeout, if possible. Otherwise, make it 4s.
void MarlinHAL::watchdog_init() {
#if ENABLED(WATCHDOG_DURATION_8S) && defined(WDTO_8S)
#define WDTO_NS WDTO_8S
#else
#define WDTO_NS WDTO_4S
#endif
#if ENABLED(WATCHDOG_RESET_MANUAL)
// Enable the watchdog timer, but only for the interrupt.
// Take care, as this requires the correct order of operation, with interrupts disabled.
// See the datasheet of any AVR chip for details.
wdt_reset();
cli();
_WD_CONTROL_REG = _BV(_WD_CHANGE_BIT) | _BV(WDE);
_WD_CONTROL_REG = _BV(WDIE) | (WDTO_NS & 0x07) | ((WDTO_NS & 0x08) << 2); // WDTO_NS directly does not work. bit 0-2 are consecutive in the register but the highest value bit is at bit 5
// So worked for up to WDTO_2S
sei();
wdt_reset();
#else
wdt_enable(WDTO_NS); // The function handles the upper bit correct.
#endif
//delay(10000); // test it!
}
//===========================================================================
//=================================== ISR ===================================
//===========================================================================
// Watchdog timer interrupt, called if main program blocks >4sec and manual reset is enabled.
#if ENABLED(WATCHDOG_RESET_MANUAL)
ISR(WDT_vect) {
sei(); // With the interrupt driven serial we need to allow interrupts.
SERIAL_ERROR_MSG(STR_WATCHDOG_FIRED);
minkill(); // interrupt-safe final kill and infinite loop
}
#endif
// Reset watchdog. MUST be called at least every 4 seconds after the
// first watchdog_init or AVR will go into emergency procedures.
void MarlinHAL::watchdog_refresh() { wdt_reset(); }
#endif // USE_WATCHDOG
// ------------------------
// Free Memory Accessor
// ------------------------
#if ENABLED(SDSUPPORT) #if ENABLED(SDSUPPORT)
#include "../../sd/SdFatUtil.h" #include "../../sd/SdFatUtil.h"
@ -58,20 +152,20 @@ void HAL_init() {
#else // !SDSUPPORT #else // !SDSUPPORT
extern "C" { extern "C" {
extern char __bss_end; extern char __bss_end;
extern char __heap_start; extern char __heap_start;
extern void* __brkval; extern void* __brkval;
int freeMemory() { int freeMemory() {
int free_memory; int free_memory;
if ((int)__brkval == 0) if ((int)__brkval == 0)
free_memory = ((int)&free_memory) - ((int)&__bss_end); free_memory = ((int)&free_memory) - ((int)&__bss_end);
else else
free_memory = ((int)&free_memory) - ((int)__brkval); free_memory = ((int)&free_memory) - ((int)__brkval);
return free_memory; return free_memory;
}
} }
}
#endif // !SDSUPPORT #endif // !SDSUPPORT

View File

@ -19,17 +19,20 @@
*/ */
#pragma once #pragma once
/**
* HAL for Arduino AVR
*/
#include "../shared/Marduino.h" #include "../shared/Marduino.h"
#include "../shared/HAL_SPI.h" #include "../shared/HAL_SPI.h"
#include "fastio.h" #include "fastio.h"
#include "watchdog.h"
#include "math.h" #include "math.h"
#ifdef IS_AT90USB #ifdef USBCON
#include <HardwareSerial.h> #include <HardwareSerial.h>
#else #else
#define HardwareSerial_h // Hack to prevent HardwareSerial.h header inclusion
#include "MarlinSerial.h" #include "MarlinSerial.h"
#define BOARD_NO_NATIVE_USB
#endif #endif
#include <stdint.h> #include <stdint.h>
@ -39,6 +42,19 @@
#include <avr/interrupt.h> #include <avr/interrupt.h>
#include <avr/io.h> #include <avr/io.h>
//
// Default graphical display delays
//
#if F_CPU >= 20000000
#define CPU_ST7920_DELAY_1 150
#define CPU_ST7920_DELAY_2 0
#define CPU_ST7920_DELAY_3 150
#elif F_CPU == 16000000
#define CPU_ST7920_DELAY_1 125
#define CPU_ST7920_DELAY_2 0
#define CPU_ST7920_DELAY_3 188
#endif
#ifndef pgm_read_ptr #ifndef pgm_read_ptr
// Compatibility for avr-libc 1.8.0-4.1 included with Ubuntu for // Compatibility for avr-libc 1.8.0-4.1 included with Ubuntu for
// Windows Subsystem for Linux on Windows 10 as of 10/18/2019 // Windows Subsystem for Linux on Windows 10 as of 10/18/2019
@ -61,9 +77,9 @@
#define CRITICAL_SECTION_START() unsigned char _sreg = SREG; cli() #define CRITICAL_SECTION_START() unsigned char _sreg = SREG; cli()
#define CRITICAL_SECTION_END() SREG = _sreg #define CRITICAL_SECTION_END() SREG = _sreg
#endif #endif
#define ISRS_ENABLED() TEST(SREG, SREG_I)
#define ENABLE_ISRS() sei() #define HAL_CAN_SET_PWM_FREQ // This HAL supports PWM Frequency adjustment
#define DISABLE_ISRS() cli() #define PWM_FREQUENCY 1000 // Default PWM frequency when set_pwm_duty() is called without set_pwm_frequency()
// ------------------------ // ------------------------
// Types // Types
@ -71,35 +87,56 @@
typedef int8_t pin_t; typedef int8_t pin_t;
#define SHARED_SERVOS HAS_SERVOS #define SHARED_SERVOS HAS_SERVOS // Use shared/servos.cpp
#define HAL_SERVO_LIB Servo
class Servo;
typedef Servo hal_servo_t;
// ------------------------ // ------------------------
// Public Variables
// ------------------------
//extern uint8_t MCUSR;
// Serial ports // Serial ports
#ifdef IS_AT90USB // ------------------------
#define MYSERIAL0 TERN(BLUETOOTH, bluetoothSerial, Serial)
#else #ifdef USBCON
#if !WITHIN(SERIAL_PORT, -1, 3) #include "../../core/serial_hook.h"
#error "SERIAL_PORT must be from -1 to 3. Please update your configuration." typedef ForwardSerial1Class< decltype(Serial) > DefaultSerial1;
extern DefaultSerial1 MSerial0;
#ifdef BLUETOOTH
typedef ForwardSerial1Class< decltype(bluetoothSerial) > BTSerial;
extern BTSerial btSerial;
#endif #endif
#define MYSERIAL0 customizedSerial1
#define MYSERIAL1 TERN(BLUETOOTH, btSerial, MSerial0)
#else
#if !WITHIN(SERIAL_PORT, 0, 3)
#error "SERIAL_PORT must be from 0 to 3."
#endif
#define MYSERIAL1 customizedSerial1
#ifdef SERIAL_PORT_2 #ifdef SERIAL_PORT_2
#if !WITHIN(SERIAL_PORT_2, -1, 3) #if !WITHIN(SERIAL_PORT_2, 0, 3)
#error "SERIAL_PORT_2 must be from -1 to 3. Please update your configuration." #error "SERIAL_PORT_2 must be from 0 to 3."
#endif #endif
#define MYSERIAL1 customizedSerial2 #define MYSERIAL2 customizedSerial2
#endif
#ifdef SERIAL_PORT_3
#if !WITHIN(SERIAL_PORT_3, 0, 3)
#error "SERIAL_PORT_3 must be from 0 to 3."
#endif
#define MYSERIAL3 customizedSerial3
#endif #endif
#endif #endif
#ifdef MMU2_SERIAL_PORT
#if !WITHIN(MMU2_SERIAL_PORT, 0, 3)
#error "MMU2_SERIAL_PORT must be from 0 to 3"
#endif
#define MMU2_SERIAL mmuSerial
#endif
#ifdef LCD_SERIAL_PORT #ifdef LCD_SERIAL_PORT
#if !WITHIN(LCD_SERIAL_PORT, -1, 3) #if !WITHIN(LCD_SERIAL_PORT, 0, 3)
#error "LCD_SERIAL_PORT must be from -1 to 3. Please update your configuration." #error "LCD_SERIAL_PORT must be from 0 to 3."
#endif #endif
#define LCD_SERIAL lcdSerial #define LCD_SERIAL lcdSerial
#if HAS_DGUS_LCD #if HAS_DGUS_LCD
@ -107,60 +144,20 @@ typedef int8_t pin_t;
#endif #endif
#endif #endif
// ------------------------ //
// Public functions
// ------------------------
void HAL_init();
//void cli();
//void _delay_ms(const int delay);
inline void HAL_clear_reset_source() { MCUSR = 0; }
inline uint8_t HAL_get_reset_source() { return MCUSR; }
inline void HAL_reboot() {} // reboot the board or restart the bootloader
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wunused-function"
extern "C" {
int freeMemory();
}
#pragma GCC diagnostic pop
// ADC // ADC
#ifdef DIDR2 //
#define HAL_ANALOG_SELECT(ind) do{ if (ind < 8) SBI(DIDR0, ind); else SBI(DIDR2, ind & 0x07); }while(0)
#else
#define HAL_ANALOG_SELECT(ind) SBI(DIDR0, ind);
#endif
inline void HAL_adc_init() {
ADCSRA = _BV(ADEN) | _BV(ADSC) | _BV(ADIF) | 0x07;
DIDR0 = 0;
#ifdef DIDR2
DIDR2 = 0;
#endif
}
#define SET_ADMUX_ADCSRA(ch) ADMUX = _BV(REFS0) | (ch & 0x07); SBI(ADCSRA, ADSC)
#ifdef MUX5
#define HAL_START_ADC(ch) if (ch > 7) ADCSRB = _BV(MUX5); else ADCSRB = 0; SET_ADMUX_ADCSRA(ch)
#else
#define HAL_START_ADC(ch) ADCSRB = 0; SET_ADMUX_ADCSRA(ch)
#endif
#define HAL_ADC_VREF 5.0 #define HAL_ADC_VREF 5.0
#define HAL_ADC_RESOLUTION 10 #define HAL_ADC_RESOLUTION 10
#define HAL_READ_ADC() ADC
#define HAL_ADC_READY() !TEST(ADCSRA, ADSC)
//
// Pin Mapping for M42, M43, M226
//
#define GET_PIN_MAP_PIN(index) index #define GET_PIN_MAP_PIN(index) index
#define GET_PIN_MAP_INDEX(pin) pin #define GET_PIN_MAP_INDEX(pin) pin
#define PARSED_PIN_INDEX(code, dval) parser.intval(code, dval) #define PARSED_PIN_INDEX(code, dval) parser.intval(code, dval)
#define HAL_SENSITIVE_PINS 0, 1 #define HAL_SENSITIVE_PINS 0, 1,
#ifdef __AVR_AT90USB1286__ #ifdef __AVR_AT90USB1286__
#define JTAG_DISABLE() do{ MCUCR = 0x80; MCUCR = 0x80; }while(0) #define JTAG_DISABLE() do{ MCUCR = 0x80; MCUCR = 0x80; }while(0)
@ -169,23 +166,113 @@ inline void HAL_adc_init() {
// AVR compatibility // AVR compatibility
#define strtof strtod #define strtof strtod
#define HAL_CAN_SET_PWM_FREQ // This HAL supports PWM Frequency adjustment // ------------------------
// Free Memory Accessor
// ------------------------
/** #pragma GCC diagnostic push
* set_pwm_frequency #if GCC_VERSION <= 50000
* Sets the frequency of the timer corresponding to the provided pin #pragma GCC diagnostic ignored "-Wunused-function"
* as close as possible to the provided desired frequency. Internally #endif
* calculates the required waveform generation mode, prescaler and
* resolution values required and sets the timer registers accordingly.
* NOTE that the frequency is applied to all pins on the timer (Ex OC3A, OC3B and OC3B)
* NOTE that there are limitations, particularly if using TIMER2. (see Configuration_adv.h -> FAST FAN PWM Settings)
*/
void set_pwm_frequency(const pin_t pin, int f_desired);
/** extern "C" int freeMemory();
* set_pwm_duty
* Sets the PWM duty cycle of the provided pin to the provided value #pragma GCC diagnostic pop
* Optionally allows inverting the duty cycle [default = false]
* Optionally allows changing the maximum size of the provided value to enable finer PWM duty control [default = 255] // ------------------------
*/ // MarlinHAL Class
void set_pwm_duty(const pin_t pin, const uint16_t v, const uint16_t v_size=255, const bool invert=false); // ------------------------
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 TEST(SREG, SREG_I); }
static void isr_on() { sei(); }
static void isr_off() { cli(); }
static void delay_ms(const int ms) { _delay_ms(ms); }
// Tasks, called from idle()
static void idletask() {}
// Reset
static uint8_t reset_reason;
static uint8_t get_reset_source() { return reset_reason; }
static void clear_reset_source() { MCUSR = 0; }
// Free SRAM
static int freeMemory() { return ::freeMemory(); }
//
// ADC Methods
//
// Called by Temperature::init once at startup
static void adc_init() {
ADCSRA = _BV(ADEN) | _BV(ADSC) | _BV(ADIF) | 0x07;
DIDR0 = 0;
#ifdef DIDR2
DIDR2 = 0;
#endif
}
// Called by Temperature::init for each sensor at startup
static void adc_enable(const uint8_t ch) {
#ifdef DIDR2
if (ch > 7) { SBI(DIDR2, ch & 0x07); return; }
#endif
SBI(DIDR0, ch);
}
// Begin ADC sampling on the given channel. Called from Temperature::isr!
static void adc_start(const uint8_t ch) {
#ifdef MUX5
ADCSRB = ch > 7 ? _BV(MUX5) : 0;
#else
ADCSRB = 0;
#endif
ADMUX = _BV(REFS0) | (ch & 0x07);
SBI(ADCSRA, ADSC);
}
// Is the ADC ready for reading?
static bool adc_ready() { return !TEST(ADCSRA, ADSC); }
// The current value of the ADC register
static __typeof__(ADC) adc_value() { return ADC; }
/**
* init_pwm_timers
* Set the default frequency for timers 2-5 to 1000HZ
*/
static void init_pwm_timers();
/**
* Set the PWM duty cycle for the pin to the given value.
* Optionally invert the duty cycle [default = false]
* Optionally change the scale of the provided value to enable finer PWM duty control [default = 255]
*/
static void set_pwm_duty(const pin_t pin, const uint16_t v, const uint16_t v_size=255, const bool invert=false);
/**
* Set the frequency of the timer for the given pin as close as
* possible to the provided desired frequency. Internally calculate
* the required waveform generation mode, prescaler, and resolution
* values and set timer registers accordingly.
* NOTE that the frequency is applied to all pins on the timer (Ex OC3A, OC3B and OC3B)
* NOTE that there are limitations, particularly if using TIMER2. (see Configuration_adv.h -> FAST_PWM_FAN Settings)
*/
static void set_pwm_frequency(const pin_t pin, const uint16_t f_desired);
};

View File

@ -34,21 +34,21 @@
#include "../../inc/MarlinConfig.h" #include "../../inc/MarlinConfig.h"
void spiBegin() { void spiBegin() {
OUT_WRITE(SS_PIN, HIGH); #if PIN_EXISTS(SD_SS)
SET_OUTPUT(SCK_PIN); // Do not init HIGH for boards with pin 4 used as Fans or Heaters or otherwise, not likely to have multiple SPI devices anyway.
SET_INPUT(MISO_PIN); #if defined(__AVR_ATmega644__) || defined(__AVR_ATmega644P__) || defined(__AVR_ATmega644PA__) || defined(__AVR_ATmega1284P__)
SET_OUTPUT(MOSI_PIN); // SS must be in output mode even it is not chip select
SET_OUTPUT(SD_SS_PIN);
#if DISABLED(SOFTWARE_SPI) #else
// SS must be in output mode even it is not chip select // set SS high - may be chip select for another SPI device
//SET_OUTPUT(SS_PIN); OUT_WRITE(SD_SS_PIN, HIGH);
// set SS high - may be chip select for another SPI device #endif
//#if SET_SPI_SS_HIGH
//WRITE(SS_PIN, HIGH);
//#endif
// set a default rate
spiInit(1);
#endif #endif
SET_OUTPUT(SD_SCK_PIN);
SET_INPUT(SD_MISO_PIN);
SET_OUTPUT(SD_MOSI_PIN);
IF_DISABLED(SOFTWARE_SPI, spiInit(SPI_HALF_SPEED));
} }
#if NONE(SOFTWARE_SPI, FORCE_SOFT_SPI) #if NONE(SOFTWARE_SPI, FORCE_SOFT_SPI)
@ -74,7 +74,8 @@ void spiBegin() {
#elif defined(PRR0) #elif defined(PRR0)
PRR0 PRR0
#endif #endif
, PRSPI); , PRSPI
);
SPCR = _BV(SPE) | _BV(MSTR) | (spiRate >> 1); SPCR = _BV(SPE) | _BV(MSTR) | (spiRate >> 1);
SPSR = spiRate & 1 || spiRate == 6 ? 0 : _BV(SPI2X); SPSR = spiRate & 1 || spiRate == 6 ? 0 : _BV(SPI2X);
@ -88,7 +89,7 @@ void spiBegin() {
} }
/** SPI read data */ /** SPI read data */
void spiRead(uint8_t* buf, uint16_t nbyte) { void spiRead(uint8_t *buf, uint16_t nbyte) {
if (nbyte-- == 0) return; if (nbyte-- == 0) return;
SPDR = 0xFF; SPDR = 0xFF;
for (uint16_t i = 0; i < nbyte; i++) { for (uint16_t i = 0; i < nbyte; i++) {
@ -107,7 +108,7 @@ void spiBegin() {
} }
/** SPI send block */ /** SPI send block */
void spiSendBlock(uint8_t token, const uint8_t* buf) { void spiSendBlock(uint8_t token, const uint8_t *buf) {
SPDR = token; SPDR = token;
for (uint16_t i = 0; i < 512; i += 2) { for (uint16_t i = 0; i < 512; i += 2) {
while (!TEST(SPSR, SPIF)) { /* Intentionally left empty */ } while (!TEST(SPSR, SPIF)) { /* Intentionally left empty */ }
@ -195,19 +196,19 @@ void spiBegin() {
// no interrupts during byte receive - about 8µs // no interrupts during byte receive - about 8µs
cli(); cli();
// output pin high - like sending 0xFF // output pin high - like sending 0xFF
WRITE(MOSI_PIN, HIGH); WRITE(SD_MOSI_PIN, HIGH);
LOOP_L_N(i, 8) { LOOP_L_N(i, 8) {
WRITE(SCK_PIN, HIGH); WRITE(SD_SCK_PIN, HIGH);
nop; // adjust so SCK is nice nop; // adjust so SCK is nice
nop; nop;
data <<= 1; data <<= 1;
if (READ(MISO_PIN)) data |= 1; if (READ(SD_MISO_PIN)) data |= 1;
WRITE(SCK_PIN, LOW); WRITE(SD_SCK_PIN, LOW);
} }
sei(); sei();
@ -215,7 +216,7 @@ void spiBegin() {
} }
// Soft SPI read data // Soft SPI read data
void spiRead(uint8_t* buf, uint16_t nbyte) { void spiRead(uint8_t *buf, uint16_t nbyte) {
for (uint16_t i = 0; i < nbyte; i++) for (uint16_t i = 0; i < nbyte; i++)
buf[i] = spiRec(); buf[i] = spiRec();
} }
@ -225,10 +226,10 @@ void spiBegin() {
// no interrupts during byte send - about 8µs // no interrupts during byte send - about 8µs
cli(); cli();
LOOP_L_N(i, 8) { LOOP_L_N(i, 8) {
WRITE(SCK_PIN, LOW); WRITE(SD_SCK_PIN, LOW);
WRITE(MOSI_PIN, data & 0x80); WRITE(SD_MOSI_PIN, data & 0x80);
data <<= 1; data <<= 1;
WRITE(SCK_PIN, HIGH); WRITE(SD_SCK_PIN, HIGH);
} }
nop; // hold SCK high for a few ns nop; // hold SCK high for a few ns
@ -236,13 +237,13 @@ void spiBegin() {
nop; nop;
nop; nop;
WRITE(SCK_PIN, LOW); WRITE(SD_SCK_PIN, LOW);
sei(); sei();
} }
// Soft SPI send block // Soft SPI send block
void spiSendBlock(uint8_t token, const uint8_t* buf) { void spiSendBlock(uint8_t token, const uint8_t *buf) {
spiSend(token); spiSend(token);
for (uint16_t i = 0; i < 512; i++) for (uint16_t i = 0; i < 512; i++)
spiSend(buf[i]); spiSend(buf[i]);

View File

@ -1,6 +1,6 @@
/** /**
* Marlin 3D Printer Firmware * Marlin 3D Printer Firmware
* Copyright (c) 2020 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] * Copyright (c) 2021 MarlinFirmware [https://github.com/MarlinFirmware/Marlin]
* *
* Based on Sprinter and grbl. * Based on Sprinter and grbl.
* Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm * Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm
@ -21,5 +21,6 @@
*/ */
#pragma once #pragma once
void watchdog_init(); #include <SPI.h>
void HAL_watchdog_refresh();
using MarlinSPI = SPIClass;

View File

@ -38,7 +38,7 @@
#include "../../inc/MarlinConfig.h" #include "../../inc/MarlinConfig.h"
#if !IS_AT90USB && (defined(UBRRH) || defined(UBRR0H) || defined(UBRR1H) || defined(UBRR2H) || defined(UBRR3H)) #if !defined(USBCON) && (defined(UBRRH) || defined(UBRR0H) || defined(UBRR1H) || defined(UBRR2H) || defined(UBRR3H))
#include "MarlinSerial.h" #include "MarlinSerial.h"
#include "../../MarlinCore.h" #include "../../MarlinCore.h"
@ -486,7 +486,7 @@ void MarlinSerial<Cfg>::write(const uint8_t c) {
const uint8_t i = (tx_buffer.head + 1) & (Cfg::TX_SIZE - 1); const uint8_t i = (tx_buffer.head + 1) & (Cfg::TX_SIZE - 1);
// If global interrupts are disabled (as the result of being called from an ISR)... // If global interrupts are disabled (as the result of being called from an ISR)...
if (!ISRS_ENABLED()) { if (!hal.isr_state()) {
// Make room by polling if it is possible to transmit, and do so! // Make room by polling if it is possible to transmit, and do so!
while (i == tx_buffer.tail) { while (i == tx_buffer.tail) {
@ -534,7 +534,7 @@ void MarlinSerial<Cfg>::flushTX() {
if (!_written) return; if (!_written) return;
// If global interrupts are disabled (as the result of being called from an ISR)... // If global interrupts are disabled (as the result of being called from an ISR)...
if (!ISRS_ENABLED()) { if (!hal.isr_state()) {
// Wait until everything was transmitted - We must do polling, as interrupts are disabled // Wait until everything was transmitted - We must do polling, as interrupts are disabled
while (tx_buffer.head != tx_buffer.tail || !B_TXC) { while (tx_buffer.head != tx_buffer.tail || !B_TXC) {
@ -556,161 +556,6 @@ void MarlinSerial<Cfg>::flushTX() {
} }
} }
/**
* Imports from print.h
*/
template<typename Cfg>
void MarlinSerial<Cfg>::print(char c, int base) {
print((long)c, base);
}
template<typename Cfg>
void MarlinSerial<Cfg>::print(unsigned char b, int base) {
print((unsigned long)b, base);
}
template<typename Cfg>
void MarlinSerial<Cfg>::print(int n, int base) {
print((long)n, base);
}
template<typename Cfg>
void MarlinSerial<Cfg>::print(unsigned int n, int base) {
print((unsigned long)n, base);
}
template<typename Cfg>
void MarlinSerial<Cfg>::print(long n, int base) {
if (base == 0) write(n);
else if (base == 10) {
if (n < 0) { print('-'); n = -n; }
printNumber(n, 10);
}
else
printNumber(n, base);
}
template<typename Cfg>
void MarlinSerial<Cfg>::print(unsigned long n, int base) {
if (base == 0) write(n);
else printNumber(n, base);
}
template<typename Cfg>
void MarlinSerial<Cfg>::print(double n, int digits) {
printFloat(n, digits);
}
template<typename Cfg>
void MarlinSerial<Cfg>::println() {
print('\r');
print('\n');
}
template<typename Cfg>
void MarlinSerial<Cfg>::println(const String& s) {
print(s);
println();
}
template<typename Cfg>
void MarlinSerial<Cfg>::println(const char c[]) {
print(c);
println();
}
template<typename Cfg>
void MarlinSerial<Cfg>::println(char c, int base) {
print(c, base);
println();
}
template<typename Cfg>
void MarlinSerial<Cfg>::println(unsigned char b, int base) {
print(b, base);
println();
}
template<typename Cfg>
void MarlinSerial<Cfg>::println(int n, int base) {
print(n, base);
println();
}
template<typename Cfg>
void MarlinSerial<Cfg>::println(unsigned int n, int base) {
print(n, base);
println();
}
template<typename Cfg>
void MarlinSerial<Cfg>::println(long n, int base) {
print(n, base);
println();
}
template<typename Cfg>
void MarlinSerial<Cfg>::println(unsigned long n, int base) {
print(n, base);
println();
}
template<typename Cfg>
void MarlinSerial<Cfg>::println(double n, int digits) {
print(n, digits);
println();
}
// Private Methods
template<typename Cfg>
void MarlinSerial<Cfg>::printNumber(unsigned long n, uint8_t base) {
if (n) {
unsigned char buf[8 * sizeof(long)]; // Enough space for base 2
int8_t i = 0;
while (n) {
buf[i++] = n % base;
n /= base;
}
while (i--)
print((char)(buf[i] + (buf[i] < 10 ? '0' : 'A' - 10)));
}
else
print('0');
}
template<typename Cfg>
void MarlinSerial<Cfg>::printFloat(double number, uint8_t digits) {
// Handle negative numbers
if (number < 0.0) {
print('-');
number = -number;
}
// Round correctly so that print(1.999, 2) prints as "2.00"
double rounding = 0.5;
LOOP_L_N(i, digits) rounding *= 0.1;
number += rounding;
// Extract the integer part of the number and print it
unsigned long int_part = (unsigned long)number;
double remainder = number - (double)int_part;
print(int_part);
// Print the decimal point, but only if there are digits beyond
if (digits) {
print('.');
// Extract digits from the remainder one at a time
while (digits--) {
remainder *= 10.0;
int toPrint = int(remainder);
print(toPrint);
remainder -= toPrint;
}
}
}
// Hookup ISR handlers // Hookup ISR handlers
ISR(SERIAL_REGNAME(USART, SERIAL_PORT, _RX_vect)) { ISR(SERIAL_REGNAME(USART, SERIAL_PORT, _RX_vect)) {
MarlinSerial<MarlinSerialCfg<SERIAL_PORT>>::store_rxd_char(); MarlinSerial<MarlinSerialCfg<SERIAL_PORT>>::store_rxd_char();
@ -720,11 +565,9 @@ ISR(SERIAL_REGNAME(USART, SERIAL_PORT, _UDRE_vect)) {
MarlinSerial<MarlinSerialCfg<SERIAL_PORT>>::_tx_udr_empty_irq(); MarlinSerial<MarlinSerialCfg<SERIAL_PORT>>::_tx_udr_empty_irq();
} }
// Preinstantiate // Because of the template definition above, it's required to instantiate the template to have all methods generated
template class MarlinSerial<MarlinSerialCfg<SERIAL_PORT>>; template class MarlinSerial< MarlinSerialCfg<SERIAL_PORT> >;
MSerialT1 customizedSerial1(MSerialT1::HasEmergencyParser);
// Instantiate
MarlinSerial<MarlinSerialCfg<SERIAL_PORT>> customizedSerial1;
#ifdef SERIAL_PORT_2 #ifdef SERIAL_PORT_2
@ -737,13 +580,26 @@ MarlinSerial<MarlinSerialCfg<SERIAL_PORT>> customizedSerial1;
MarlinSerial<MarlinSerialCfg<SERIAL_PORT_2>>::_tx_udr_empty_irq(); MarlinSerial<MarlinSerialCfg<SERIAL_PORT_2>>::_tx_udr_empty_irq();
} }
// Preinstantiate template class MarlinSerial< MarlinSerialCfg<SERIAL_PORT_2> >;
template class MarlinSerial<MarlinSerialCfg<SERIAL_PORT_2>>; MSerialT2 customizedSerial2(MSerialT2::HasEmergencyParser);
// Instantiate #endif // SERIAL_PORT_2
MarlinSerial<MarlinSerialCfg<SERIAL_PORT_2>> customizedSerial2;
#endif #ifdef SERIAL_PORT_3
// Hookup ISR handlers
ISR(SERIAL_REGNAME(USART, SERIAL_PORT_3, _RX_vect)) {
MarlinSerial<MarlinSerialCfg<SERIAL_PORT_3>>::store_rxd_char();
}
ISR(SERIAL_REGNAME(USART, SERIAL_PORT_3, _UDRE_vect)) {
MarlinSerial<MarlinSerialCfg<SERIAL_PORT_3>>::_tx_udr_empty_irq();
}
template class MarlinSerial< MarlinSerialCfg<SERIAL_PORT_3> >;
MSerialT3 customizedSerial3(MSerialT3::HasEmergencyParser);
#endif // SERIAL_PORT_3
#ifdef MMU2_SERIAL_PORT #ifdef MMU2_SERIAL_PORT
@ -755,13 +611,10 @@ MarlinSerial<MarlinSerialCfg<SERIAL_PORT>> customizedSerial1;
MarlinSerial<MMU2SerialCfg<MMU2_SERIAL_PORT>>::_tx_udr_empty_irq(); MarlinSerial<MMU2SerialCfg<MMU2_SERIAL_PORT>>::_tx_udr_empty_irq();
} }
// Preinstantiate template class MarlinSerial< MMU2SerialCfg<MMU2_SERIAL_PORT> >;
template class MarlinSerial<MMU2SerialCfg<MMU2_SERIAL_PORT>>; MSerialMMU2 mmuSerial(MSerialMMU2::HasEmergencyParser);
// Instantiate #endif // MMU2_SERIAL_PORT
MarlinSerial<MMU2SerialCfg<MMU2_SERIAL_PORT>> mmuSerial;
#endif
#ifdef LCD_SERIAL_PORT #ifdef LCD_SERIAL_PORT
@ -773,11 +626,8 @@ MarlinSerial<MarlinSerialCfg<SERIAL_PORT>> customizedSerial1;
MarlinSerial<LCDSerialCfg<LCD_SERIAL_PORT>>::_tx_udr_empty_irq(); MarlinSerial<LCDSerialCfg<LCD_SERIAL_PORT>>::_tx_udr_empty_irq();
} }
// Preinstantiate template class MarlinSerial< LCDSerialCfg<LCD_SERIAL_PORT> >;
template class MarlinSerial<LCDSerialCfg<LCD_SERIAL_PORT>>; MSerialLCD lcdSerial(MSerialLCD::HasEmergencyParser);
// Instantiate
MarlinSerial<LCDSerialCfg<LCD_SERIAL_PORT>> lcdSerial;
#if HAS_DGUS_LCD #if HAS_DGUS_LCD
template<typename Cfg> template<typename Cfg>
@ -790,13 +640,13 @@ MarlinSerial<MarlinSerialCfg<SERIAL_PORT>> customizedSerial1;
} }
#endif #endif
#endif #endif // LCD_SERIAL_PORT
#endif // !IS_AT90USB && (UBRRH || UBRR0H || UBRR1H || UBRR2H || UBRR3H) #endif // !USBCON && (UBRRH || UBRR0H || UBRR1H || UBRR2H || UBRR3H)
// For AT90USB targets use the UART for BT interfacing // For AT90USB targets use the UART for BT interfacing
#if BOTH(IS_AT90USB, BLUETOOTH) #if defined(USBCON) && ENABLED(BLUETOOTH)
HardwareSerial bluetoothSerial; MSerialBT bluetoothSerial(false);
#endif #endif
#endif // __AVR__ #endif // __AVR__

View File

@ -34,6 +34,7 @@
#include <WString.h> #include <WString.h>
#include "../../inc/MarlinConfigPre.h" #include "../../inc/MarlinConfigPre.h"
#include "../../core/serial_hook.h"
#ifndef SERIAL_PORT #ifndef SERIAL_PORT
#define SERIAL_PORT 0 #define SERIAL_PORT 0
@ -135,10 +136,6 @@
UART_DECL(3); UART_DECL(3);
#endif #endif
#define DEC 10
#define HEX 16
#define OCT 8
#define BIN 2
#define BYTE 0 #define BYTE 0
// Templated type selector // Templated type selector
@ -194,68 +191,38 @@
rx_framing_errors; rx_framing_errors;
static ring_buffer_pos_t rx_max_enqueued; static ring_buffer_pos_t rx_max_enqueued;
static FORCE_INLINE ring_buffer_pos_t atomic_read_rx_head(); FORCE_INLINE static ring_buffer_pos_t atomic_read_rx_head();
static volatile bool rx_tail_value_not_stable; static volatile bool rx_tail_value_not_stable;
static volatile uint16_t rx_tail_value_backup; static volatile uint16_t rx_tail_value_backup;
static FORCE_INLINE void atomic_set_rx_tail(ring_buffer_pos_t value); FORCE_INLINE static void atomic_set_rx_tail(ring_buffer_pos_t value);
static FORCE_INLINE ring_buffer_pos_t atomic_read_rx_tail(); FORCE_INLINE static ring_buffer_pos_t atomic_read_rx_tail();
public:
public:
FORCE_INLINE static void store_rxd_char(); FORCE_INLINE static void store_rxd_char();
FORCE_INLINE static void _tx_udr_empty_irq(); FORCE_INLINE static void _tx_udr_empty_irq();
public: public:
MarlinSerial() {}; static void begin(const long);
static void begin(const long); static void end();
static void end(); static int peek();
static int peek(); static int read();
static int read(); static void flush();
static void flush(); static ring_buffer_pos_t available();
static ring_buffer_pos_t available(); static void write(const uint8_t c);
static void write(const uint8_t c); static void flushTX();
static void flushTX(); #if HAS_DGUS_LCD
#if HAS_DGUS_LCD static ring_buffer_pos_t get_tx_buffer_free();
static ring_buffer_pos_t get_tx_buffer_free(); #endif
#endif
static inline bool emergency_parser_enabled() { return Cfg::EMERGENCYPARSER; } enum { HasEmergencyParser = Cfg::EMERGENCYPARSER };
static bool emergency_parser_enabled() { return Cfg::EMERGENCYPARSER; }
FORCE_INLINE static uint8_t dropped() { return Cfg::DROPPED_RX ? rx_dropped_bytes : 0; } FORCE_INLINE static uint8_t dropped() { return Cfg::DROPPED_RX ? rx_dropped_bytes : 0; }
FORCE_INLINE static uint8_t buffer_overruns() { return Cfg::RX_OVERRUNS ? rx_buffer_overruns : 0; } FORCE_INLINE static uint8_t buffer_overruns() { return Cfg::RX_OVERRUNS ? rx_buffer_overruns : 0; }
FORCE_INLINE static uint8_t framing_errors() { return Cfg::RX_FRAMING_ERRORS ? rx_framing_errors : 0; } FORCE_INLINE static uint8_t framing_errors() { return Cfg::RX_FRAMING_ERRORS ? rx_framing_errors : 0; }
FORCE_INLINE static ring_buffer_pos_t rxMaxEnqueued() { return Cfg::MAX_RX_QUEUED ? rx_max_enqueued : 0; } FORCE_INLINE static ring_buffer_pos_t rxMaxEnqueued() { return Cfg::MAX_RX_QUEUED ? rx_max_enqueued : 0; }
FORCE_INLINE static void write(const char* str) { while (*str) write(*str++); }
FORCE_INLINE static void write(const uint8_t* buffer, size_t size) { while (size--) write(*buffer++); }
FORCE_INLINE static void print(const String& s) { for (int i = 0; i < (int)s.length(); i++) write(s[i]); }
FORCE_INLINE static void print(const char* str) { write(str); }
static void print(char, int = BYTE);
static void print(unsigned char, int = BYTE);
static void print(int, int = DEC);
static void print(unsigned int, int = DEC);
static void print(long, int = DEC);
static void print(unsigned long, int = DEC);
static void print(double, int = 2);
static void println(const String& s);
static void println(const char[]);
static void println(char, int = BYTE);
static void println(unsigned char, int = BYTE);
static void println(int, int = DEC);
static void println(unsigned int, int = DEC);
static void println(long, int = DEC);
static void println(unsigned long, int = DEC);
static void println(double, int = 2);
static void println();
operator bool() { return true; }
private:
static void printNumber(unsigned long, const uint8_t);
static void printFloat(double, uint8_t);
}; };
template <uint8_t serial> template <uint8_t serial>
@ -270,12 +237,18 @@
static constexpr bool RX_FRAMING_ERRORS = ENABLED(SERIAL_STATS_RX_FRAMING_ERRORS); static constexpr bool RX_FRAMING_ERRORS = ENABLED(SERIAL_STATS_RX_FRAMING_ERRORS);
static constexpr bool MAX_RX_QUEUED = ENABLED(SERIAL_STATS_MAX_RX_QUEUED); static constexpr bool MAX_RX_QUEUED = ENABLED(SERIAL_STATS_MAX_RX_QUEUED);
}; };
extern MarlinSerial<MarlinSerialCfg<SERIAL_PORT>> customizedSerial1;
typedef Serial1Class< MarlinSerial< MarlinSerialCfg<SERIAL_PORT> > > MSerialT1;
extern MSerialT1 customizedSerial1;
#ifdef SERIAL_PORT_2 #ifdef SERIAL_PORT_2
typedef Serial1Class< MarlinSerial< MarlinSerialCfg<SERIAL_PORT_2> > > MSerialT2;
extern MSerialT2 customizedSerial2;
#endif
extern MarlinSerial<MarlinSerialCfg<SERIAL_PORT_2>> customizedSerial2; #ifdef SERIAL_PORT_3
typedef Serial1Class< MarlinSerial< MarlinSerialCfg<SERIAL_PORT_3> > > MSerialT3;
extern MSerialT3 customizedSerial3;
#endif #endif
#endif // !USBCON #endif // !USBCON
@ -284,49 +257,41 @@
template <uint8_t serial> template <uint8_t serial>
struct MMU2SerialCfg { struct MMU2SerialCfg {
static constexpr int PORT = serial; static constexpr int PORT = serial;
static constexpr unsigned int RX_SIZE = 32;
static constexpr unsigned int TX_SIZE = 32;
static constexpr bool XONOFF = false; static constexpr bool XONOFF = false;
static constexpr bool EMERGENCYPARSER = false; static constexpr bool EMERGENCYPARSER = false;
static constexpr bool DROPPED_RX = false; static constexpr bool DROPPED_RX = false;
static constexpr bool RX_FRAMING_ERRORS = false; static constexpr bool RX_FRAMING_ERRORS = false;
static constexpr bool MAX_RX_QUEUED = false; static constexpr bool MAX_RX_QUEUED = false;
static constexpr unsigned int RX_SIZE = 32;
static constexpr unsigned int TX_SIZE = 32;
static constexpr bool RX_OVERRUNS = false; static constexpr bool RX_OVERRUNS = false;
}; };
extern MarlinSerial<MMU2SerialCfg<MMU2_SERIAL_PORT>> mmuSerial; typedef Serial1Class< MarlinSerial< MMU2SerialCfg<MMU2_SERIAL_PORT> > > MSerialMMU2;
extern MSerialMMU2 mmuSerial;
#endif #endif
#ifdef LCD_SERIAL_PORT #ifdef LCD_SERIAL_PORT
template <uint8_t serial> template <uint8_t serial>
struct LCDSerialCfg { struct LCDSerialCfg {
static constexpr int PORT = serial; static constexpr int PORT = serial;
static constexpr bool XONOFF = false; static constexpr unsigned int RX_SIZE = TERN(HAS_DGUS_LCD, DGUS_RX_BUFFER_SIZE, 64);
static constexpr bool EMERGENCYPARSER = ENABLED(EMERGENCY_PARSER); static constexpr unsigned int TX_SIZE = TERN(HAS_DGUS_LCD, DGUS_TX_BUFFER_SIZE, 128);
static constexpr bool DROPPED_RX = false; static constexpr bool XONOFF = false;
static constexpr bool RX_FRAMING_ERRORS = false; static constexpr bool EMERGENCYPARSER = ENABLED(EMERGENCY_PARSER);
static constexpr bool MAX_RX_QUEUED = false; static constexpr bool DROPPED_RX = false;
#if HAS_DGUS_LCD static constexpr bool RX_FRAMING_ERRORS = false;
static constexpr unsigned int RX_SIZE = DGUS_RX_BUFFER_SIZE; static constexpr bool MAX_RX_QUEUED = false;
static constexpr unsigned int TX_SIZE = DGUS_TX_BUFFER_SIZE; static constexpr bool RX_OVERRUNS = BOTH(HAS_DGUS_LCD, SERIAL_STATS_RX_BUFFER_OVERRUNS);
static constexpr bool RX_OVERRUNS = ENABLED(SERIAL_STATS_RX_BUFFER_OVERRUNS);
#elif EITHER(ANYCUBIC_LCD_I3MEGA, ANYCUBIC_LCD_CHIRON)
static constexpr unsigned int RX_SIZE = 64;
static constexpr unsigned int TX_SIZE = 128;
static constexpr bool RX_OVERRUNS = false;
#else
static constexpr unsigned int RX_SIZE = 64;
static constexpr unsigned int TX_SIZE = 128;
static constexpr bool RX_OVERRUNS = false
#endif
}; };
extern MarlinSerial<LCDSerialCfg<LCD_SERIAL_PORT>> lcdSerial; typedef Serial1Class< MarlinSerial< LCDSerialCfg<LCD_SERIAL_PORT> > > MSerialLCD;
extern MSerialLCD lcdSerial;
#endif #endif
// Use the UART for Bluetooth in AT90USB configurations // Use the UART for Bluetooth in AT90USB configurations
#if BOTH(IS_AT90USB, BLUETOOTH) #if defined(USBCON) && ENABLED(BLUETOOTH)
extern HardwareSerial bluetoothSerial; typedef Serial1Class<HardwareSerial> MSerialBT;
extern MSerialBT bluetoothSerial;
#endif #endif

View File

@ -66,27 +66,26 @@ static volatile int8_t Channel[_Nbr_16timers]; // counter for the s
/************ static functions common to all instances ***********************/ /************ static functions common to all instances ***********************/
static inline void handle_interrupts(timer16_Sequence_t timer, volatile uint16_t* TCNTn, volatile uint16_t* OCRnA) { static inline void handle_interrupts(const timer16_Sequence_t timer, volatile uint16_t* TCNTn, volatile uint16_t* OCRnA) {
if (Channel[timer] < 0) int8_t cho = Channel[timer]; // Handle the prior Channel[timer] first
*TCNTn = 0; // channel set to -1 indicated that refresh interval completed so reset the timer if (cho < 0) // Channel -1 indicates the refresh interval completed...
else { *TCNTn = 0; // ...so reset the timer
if (SERVO_INDEX(timer, Channel[timer]) < ServoCount && SERVO(timer, Channel[timer]).Pin.isActive) else if (SERVO_INDEX(timer, cho) < ServoCount) // prior channel handled?
extDigitalWrite(SERVO(timer, Channel[timer]).Pin.nbr, LOW); // pulse this channel low if activated extDigitalWrite(SERVO(timer, cho).Pin.nbr, LOW); // pulse the prior channel LOW
}
Channel[timer]++; // increment to the next channel Channel[timer] = ++cho; // Handle the next channel (or 0)
if (SERVO_INDEX(timer, Channel[timer]) < ServoCount && Channel[timer] < SERVOS_PER_TIMER) { if (cho < SERVOS_PER_TIMER && SERVO_INDEX(timer, cho) < ServoCount) {
*OCRnA = *TCNTn + SERVO(timer, Channel[timer]).ticks; *OCRnA = *TCNTn + SERVO(timer, cho).ticks; // set compare to current ticks plus duration
if (SERVO(timer, Channel[timer]).Pin.isActive) // check if activated if (SERVO(timer, cho).Pin.isActive) // activated?
extDigitalWrite(SERVO(timer, Channel[timer]).Pin.nbr, HIGH); // it's an active channel so pulse it high extDigitalWrite(SERVO(timer, cho).Pin.nbr, HIGH); // yes: pulse HIGH
} }
else { else {
// finished all channels so wait for the refresh period to expire before starting over // finished all channels so wait for the refresh period to expire before starting over
if (((unsigned)*TCNTn) + 4 < usToTicks(REFRESH_INTERVAL)) // allow a few ticks to ensure the next OCR1A not missed const unsigned int cval = ((unsigned)*TCNTn) + 32 / (SERVO_TIMER_PRESCALER), // allow 32 cycles to ensure the next OCR1A not missed
*OCRnA = (unsigned int)usToTicks(REFRESH_INTERVAL); ival = (unsigned int)usToTicks(REFRESH_INTERVAL); // at least REFRESH_INTERVAL has elapsed
else *OCRnA = max(cval, ival);
*OCRnA = *TCNTn + 4; // at least REFRESH_INTERVAL has elapsed
Channel[timer] = -1; // this will get incremented at the end of the refresh period to start again at the first channel Channel[timer] = -1; // reset the timer counter to 0 on the next call
} }
} }
@ -123,91 +122,102 @@ static inline void handle_interrupts(timer16_Sequence_t timer, volatile uint16_t
/****************** end of static functions ******************************/ /****************** end of static functions ******************************/
void initISR(timer16_Sequence_t timer) { void initISR(const timer16_Sequence_t timer_index) {
#ifdef _useTimer1 switch (timer_index) {
if (timer == _timer1) { default: break;
TCCR1A = 0; // normal counting mode
TCCR1B = _BV(CS11); // set prescaler of 8
TCNT1 = 0; // clear the timer count
#if defined(__AVR_ATmega8__) || defined(__AVR_ATmega128__)
SBI(TIFR, OCF1A); // clear any pending interrupts;
SBI(TIMSK, OCIE1A); // enable the output compare interrupt
#else
// here if not ATmega8 or ATmega128
SBI(TIFR1, OCF1A); // clear any pending interrupts;
SBI(TIMSK1, OCIE1A); // enable the output compare interrupt
#endif
#ifdef WIRING
timerAttach(TIMER1OUTCOMPAREA_INT, Timer1Service);
#endif
}
#endif
#ifdef _useTimer3 #ifdef _useTimer1
if (timer == _timer3) { case _timer1:
TCCR3A = 0; // normal counting mode TCCR1A = 0; // normal counting mode
TCCR3B = _BV(CS31); // set prescaler of 8 TCCR1B = _BV(CS11); // set prescaler of 8
TCNT3 = 0; // clear the timer count TCNT1 = 0; // clear the timer count
#ifdef __AVR_ATmega128__ #if defined(__AVR_ATmega8__) || defined(__AVR_ATmega128__)
SBI(TIFR, OCF3A); // clear any pending interrupts; SBI(TIFR, OCF1A); // clear any pending interrupts;
SBI(ETIMSK, OCIE3A); // enable the output compare interrupt SBI(TIMSK, OCIE1A); // enable the output compare interrupt
#else #else
SBI(TIFR3, OCF3A); // clear any pending interrupts; // here if not ATmega8 or ATmega128
SBI(TIMSK3, OCIE3A); // enable the output compare interrupt SBI(TIFR1, OCF1A); // clear any pending interrupts;
#endif SBI(TIMSK1, OCIE1A); // enable the output compare interrupt
#ifdef WIRING #endif
timerAttach(TIMER3OUTCOMPAREA_INT, Timer3Service); // for Wiring platform only #ifdef WIRING
#endif timerAttach(TIMER1OUTCOMPAREA_INT, Timer1Service);
} #endif
#endif break;
#endif
#ifdef _useTimer4 #ifdef _useTimer3
if (timer == _timer4) { case _timer3:
TCCR4A = 0; // normal counting mode TCCR3A = 0; // normal counting mode
TCCR4B = _BV(CS41); // set prescaler of 8 TCCR3B = _BV(CS31); // set prescaler of 8
TCNT4 = 0; // clear the timer count TCNT3 = 0; // clear the timer count
TIFR4 = _BV(OCF4A); // clear any pending interrupts; #ifdef __AVR_ATmega128__
TIMSK4 = _BV(OCIE4A); // enable the output compare interrupt SBI(TIFR, OCF3A); // clear any pending interrupts;
} SBI(ETIMSK, OCIE3A); // enable the output compare interrupt
#endif #else
SBI(TIFR3, OCF3A); // clear any pending interrupts;
SBI(TIMSK3, OCIE3A); // enable the output compare interrupt
#endif
#ifdef WIRING
timerAttach(TIMER3OUTCOMPAREA_INT, Timer3Service); // for Wiring platform only
#endif
break;
#endif
#ifdef _useTimer5 #ifdef _useTimer4
if (timer == _timer5) { case _timer4:
TCCR5A = 0; // normal counting mode TCCR4A = 0; // normal counting mode
TCCR5B = _BV(CS51); // set prescaler of 8 TCCR4B = _BV(CS41); // set prescaler of 8
TCNT5 = 0; // clear the timer count TCNT4 = 0; // clear the timer count
TIFR5 = _BV(OCF5A); // clear any pending interrupts; TIFR4 = _BV(OCF4A); // clear any pending interrupts;
TIMSK5 = _BV(OCIE5A); // enable the output compare interrupt TIMSK4 = _BV(OCIE4A); // enable the output compare interrupt
} break;
#endif #endif
#ifdef _useTimer5
case _timer5:
TCCR5A = 0; // normal counting mode
TCCR5B = _BV(CS51); // set prescaler of 8
TCNT5 = 0; // clear the timer count
TIFR5 = _BV(OCF5A); // clear any pending interrupts;
TIMSK5 = _BV(OCIE5A); // enable the output compare interrupt
break;
#endif
}
} }
void finISR(timer16_Sequence_t timer) { void finISR(const timer16_Sequence_t timer_index) {
// Disable use of the given timer // Disable use of the given timer
#ifdef WIRING #ifdef WIRING
if (timer == _timer1) { switch (timer_index) {
CBI( default: break;
#if defined(__AVR_ATmega1281__) || defined(__AVR_ATmega2561__)
TIMSK1 case _timer1:
#else CBI(
TIMSK #if defined(__AVR_ATmega1281__) || defined(__AVR_ATmega2561__)
#endif TIMSK1
, OCIE1A); // disable timer 1 output compare interrupt #else
timerDetach(TIMER1OUTCOMPAREA_INT); TIMSK
} #endif
else if (timer == _timer3) { , OCIE1A // disable timer 1 output compare interrupt
CBI( );
#if defined(__AVR_ATmega1281__) || defined(__AVR_ATmega2561__) timerDetach(TIMER1OUTCOMPAREA_INT);
TIMSK3 break;
#else
ETIMSK case _timer3:
#endif CBI(
, OCIE3A); // disable the timer3 output compare A interrupt #if defined(__AVR_ATmega1281__) || defined(__AVR_ATmega2561__)
timerDetach(TIMER3OUTCOMPAREA_INT); TIMSK3
#else
ETIMSK
#endif
, OCIE3A // disable the timer3 output compare A interrupt
);
timerDetach(TIMER3OUTCOMPAREA_INT);
break;
} }
#else // !WIRING #else // !WIRING
// For arduino - in future: call here to a currently undefined function to reset the timer // For arduino - in future: call here to a currently undefined function to reset the timer
UNUSED(timer); UNUSED(timer_index);
#endif #endif
} }

View File

@ -40,13 +40,13 @@ bool PersistentStore::access_start() { return true; }
bool PersistentStore::access_finish() { return true; } bool PersistentStore::access_finish() { return true; }
bool PersistentStore::write_data(int &pos, const uint8_t *value, size_t size, uint16_t *crc) { bool PersistentStore::write_data(int &pos, const uint8_t *value, size_t size, uint16_t *crc) {
uint16_t written = 0;
while (size--) { while (size--) {
uint8_t * const p = (uint8_t * const)pos; uint8_t * const p = (uint8_t * const)pos;
uint8_t v = *value; uint8_t v = *value;
// EEPROM has only ~100,000 write cycles, if (v != eeprom_read_byte(p)) { // EEPROM has only ~100,000 write cycles, so only write bytes that have changed!
// so only write bytes that have changed!
if (v != eeprom_read_byte(p)) {
eeprom_write_byte(p, v); 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) { if (eeprom_read_byte(p) != v) {
SERIAL_ECHO_MSG(STR_ERR_EEPROM_WRITE); SERIAL_ECHO_MSG(STR_ERR_EEPROM_WRITE);
return true; return true;
@ -59,7 +59,7 @@ bool PersistentStore::write_data(int &pos, const uint8_t *value, size_t size, ui
return false; return false;
} }
bool PersistentStore::read_data(int &pos, uint8_t* value, size_t size, uint16_t *crc, const bool writing/*=true*/) { bool PersistentStore::read_data(int &pos, uint8_t *value, size_t size, uint16_t *crc, const bool writing/*=true*/) {
do { do {
uint8_t c = eeprom_read_byte((uint8_t*)pos); uint8_t c = eeprom_read_byte((uint8_t*)pos);
if (writing) *value = c; if (writing) *value = c;

View File

@ -124,7 +124,7 @@ void setup_endstop_interrupts() {
#if (digitalPinToInterrupt(X_MAX_PIN) != NOT_AN_INTERRUPT) #if (digitalPinToInterrupt(X_MAX_PIN) != NOT_AN_INTERRUPT)
_ATTACH(X_MAX_PIN); _ATTACH(X_MAX_PIN);
#else #else
static_assert(digitalPinHasPCICR(X_MAX_PIN), "X_MAX_PIN is not interrupt-capable"); static_assert(digitalPinHasPCICR(X_MAX_PIN), "X_MAX_PIN is not interrupt-capable. Disable ENDSTOP_INTERRUPTS_FEATURE to continue.");
pciSetup(X_MAX_PIN); pciSetup(X_MAX_PIN);
#endif #endif
#endif #endif
@ -132,7 +132,7 @@ void setup_endstop_interrupts() {
#if (digitalPinToInterrupt(X_MIN_PIN) != NOT_AN_INTERRUPT) #if (digitalPinToInterrupt(X_MIN_PIN) != NOT_AN_INTERRUPT)
_ATTACH(X_MIN_PIN); _ATTACH(X_MIN_PIN);
#else #else
static_assert(digitalPinHasPCICR(X_MIN_PIN), "X_MIN_PIN is not interrupt-capable"); static_assert(digitalPinHasPCICR(X_MIN_PIN), "X_MIN_PIN is not interrupt-capable. Disable ENDSTOP_INTERRUPTS_FEATURE to continue.");
pciSetup(X_MIN_PIN); pciSetup(X_MIN_PIN);
#endif #endif
#endif #endif
@ -140,7 +140,7 @@ void setup_endstop_interrupts() {
#if (digitalPinToInterrupt(Y_MAX_PIN) != NOT_AN_INTERRUPT) #if (digitalPinToInterrupt(Y_MAX_PIN) != NOT_AN_INTERRUPT)
_ATTACH(Y_MAX_PIN); _ATTACH(Y_MAX_PIN);
#else #else
static_assert(digitalPinHasPCICR(Y_MAX_PIN), "Y_MAX_PIN is not interrupt-capable"); static_assert(digitalPinHasPCICR(Y_MAX_PIN), "Y_MAX_PIN is not interrupt-capable. Disable ENDSTOP_INTERRUPTS_FEATURE to continue.");
pciSetup(Y_MAX_PIN); pciSetup(Y_MAX_PIN);
#endif #endif
#endif #endif
@ -148,7 +148,7 @@ void setup_endstop_interrupts() {
#if (digitalPinToInterrupt(Y_MIN_PIN) != NOT_AN_INTERRUPT) #if (digitalPinToInterrupt(Y_MIN_PIN) != NOT_AN_INTERRUPT)
_ATTACH(Y_MIN_PIN); _ATTACH(Y_MIN_PIN);
#else #else
static_assert(digitalPinHasPCICR(Y_MIN_PIN), "Y_MIN_PIN is not interrupt-capable"); static_assert(digitalPinHasPCICR(Y_MIN_PIN), "Y_MIN_PIN is not interrupt-capable. Disable ENDSTOP_INTERRUPTS_FEATURE to continue.");
pciSetup(Y_MIN_PIN); pciSetup(Y_MIN_PIN);
#endif #endif
#endif #endif
@ -156,7 +156,7 @@ void setup_endstop_interrupts() {
#if (digitalPinToInterrupt(Z_MAX_PIN) != NOT_AN_INTERRUPT) #if (digitalPinToInterrupt(Z_MAX_PIN) != NOT_AN_INTERRUPT)
_ATTACH(Z_MAX_PIN); _ATTACH(Z_MAX_PIN);
#else #else
static_assert(digitalPinHasPCICR(Z_MAX_PIN), "Z_MAX_PIN is not interrupt-capable"); static_assert(digitalPinHasPCICR(Z_MAX_PIN), "Z_MAX_PIN is not interrupt-capable. Disable ENDSTOP_INTERRUPTS_FEATURE to continue.");
pciSetup(Z_MAX_PIN); pciSetup(Z_MAX_PIN);
#endif #endif
#endif #endif
@ -164,15 +164,105 @@ void setup_endstop_interrupts() {
#if (digitalPinToInterrupt(Z_MIN_PIN) != NOT_AN_INTERRUPT) #if (digitalPinToInterrupt(Z_MIN_PIN) != NOT_AN_INTERRUPT)
_ATTACH(Z_MIN_PIN); _ATTACH(Z_MIN_PIN);
#else #else
static_assert(digitalPinHasPCICR(Z_MIN_PIN), "Z_MIN_PIN is not interrupt-capable"); static_assert(digitalPinHasPCICR(Z_MIN_PIN), "Z_MIN_PIN is not interrupt-capable. Disable ENDSTOP_INTERRUPTS_FEATURE to continue.");
pciSetup(Z_MIN_PIN); pciSetup(Z_MIN_PIN);
#endif #endif
#endif #endif
#if HAS_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");
pciSetup(I_MAX_PIN);
#endif
#elif HAS_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");
pciSetup(I_MIN_PIN);
#endif
#endif
#if HAS_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");
pciSetup(J_MAX_PIN);
#endif
#elif HAS_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");
pciSetup(J_MIN_PIN);
#endif
#endif
#if HAS_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");
pciSetup(K_MAX_PIN);
#endif
#elif HAS_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");
pciSetup(K_MIN_PIN);
#endif
#endif
#if HAS_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");
pciSetup(U_MAX_PIN);
#endif
#elif HAS_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");
pciSetup(U_MIN_PIN);
#endif
#endif
#if HAS_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");
pciSetup(V_MAX_PIN);
#endif
#elif HAS_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");
pciSetup(V_MIN_PIN);
#endif
#endif
#if HAS_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");
pciSetup(W_MAX_PIN);
#endif
#elif HAS_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");
pciSetup(W_MIN_PIN);
#endif
#endif
#if HAS_X2_MAX #if HAS_X2_MAX
#if (digitalPinToInterrupt(X2_MAX_PIN) != NOT_AN_INTERRUPT) #if (digitalPinToInterrupt(X2_MAX_PIN) != NOT_AN_INTERRUPT)
_ATTACH(X2_MAX_PIN); _ATTACH(X2_MAX_PIN);
#else #else
static_assert(digitalPinHasPCICR(X2_MAX_PIN), "X2_MAX_PIN is not interrupt-capable"); static_assert(digitalPinHasPCICR(X2_MAX_PIN), "X2_MAX_PIN is not interrupt-capable. Disable ENDSTOP_INTERRUPTS_FEATURE to continue.");
pciSetup(X2_MAX_PIN); pciSetup(X2_MAX_PIN);
#endif #endif
#endif #endif
@ -180,7 +270,7 @@ void setup_endstop_interrupts() {
#if (digitalPinToInterrupt(X2_MIN_PIN) != NOT_AN_INTERRUPT) #if (digitalPinToInterrupt(X2_MIN_PIN) != NOT_AN_INTERRUPT)
_ATTACH(X2_MIN_PIN); _ATTACH(X2_MIN_PIN);
#else #else
static_assert(digitalPinHasPCICR(X2_MIN_PIN), "X2_MIN_PIN is not interrupt-capable"); static_assert(digitalPinHasPCICR(X2_MIN_PIN), "X2_MIN_PIN is not interrupt-capable. Disable ENDSTOP_INTERRUPTS_FEATURE to continue.");
pciSetup(X2_MIN_PIN); pciSetup(X2_MIN_PIN);
#endif #endif
#endif #endif
@ -188,7 +278,7 @@ void setup_endstop_interrupts() {
#if (digitalPinToInterrupt(Y2_MAX_PIN) != NOT_AN_INTERRUPT) #if (digitalPinToInterrupt(Y2_MAX_PIN) != NOT_AN_INTERRUPT)
_ATTACH(Y2_MAX_PIN); _ATTACH(Y2_MAX_PIN);
#else #else
static_assert(digitalPinHasPCICR(Y2_MAX_PIN), "Y2_MAX_PIN is not interrupt-capable"); static_assert(digitalPinHasPCICR(Y2_MAX_PIN), "Y2_MAX_PIN is not interrupt-capable. Disable ENDSTOP_INTERRUPTS_FEATURE to continue.");
pciSetup(Y2_MAX_PIN); pciSetup(Y2_MAX_PIN);
#endif #endif
#endif #endif
@ -196,7 +286,7 @@ void setup_endstop_interrupts() {
#if (digitalPinToInterrupt(Y2_MIN_PIN) != NOT_AN_INTERRUPT) #if (digitalPinToInterrupt(Y2_MIN_PIN) != NOT_AN_INTERRUPT)
_ATTACH(Y2_MIN_PIN); _ATTACH(Y2_MIN_PIN);
#else #else
static_assert(digitalPinHasPCICR(Y2_MIN_PIN), "Y2_MIN_PIN is not interrupt-capable"); static_assert(digitalPinHasPCICR(Y2_MIN_PIN), "Y2_MIN_PIN is not interrupt-capable. Disable ENDSTOP_INTERRUPTS_FEATURE to continue.");
pciSetup(Y2_MIN_PIN); pciSetup(Y2_MIN_PIN);
#endif #endif
#endif #endif
@ -204,7 +294,7 @@ void setup_endstop_interrupts() {
#if (digitalPinToInterrupt(Z2_MAX_PIN) != NOT_AN_INTERRUPT) #if (digitalPinToInterrupt(Z2_MAX_PIN) != NOT_AN_INTERRUPT)
_ATTACH(Z2_MAX_PIN); _ATTACH(Z2_MAX_PIN);
#else #else
static_assert(digitalPinHasPCICR(Z2_MAX_PIN), "Z2_MAX_PIN is not interrupt-capable"); static_assert(digitalPinHasPCICR(Z2_MAX_PIN), "Z2_MAX_PIN is not interrupt-capable. Disable ENDSTOP_INTERRUPTS_FEATURE to continue.");
pciSetup(Z2_MAX_PIN); pciSetup(Z2_MAX_PIN);
#endif #endif
#endif #endif
@ -212,7 +302,7 @@ void setup_endstop_interrupts() {
#if (digitalPinToInterrupt(Z2_MIN_PIN) != NOT_AN_INTERRUPT) #if (digitalPinToInterrupt(Z2_MIN_PIN) != NOT_AN_INTERRUPT)
_ATTACH(Z2_MIN_PIN); _ATTACH(Z2_MIN_PIN);
#else #else
static_assert(digitalPinHasPCICR(Z2_MIN_PIN), "Z2_MIN_PIN is not interrupt-capable"); static_assert(digitalPinHasPCICR(Z2_MIN_PIN), "Z2_MIN_PIN is not interrupt-capable. Disable ENDSTOP_INTERRUPTS_FEATURE to continue.");
pciSetup(Z2_MIN_PIN); pciSetup(Z2_MIN_PIN);
#endif #endif
#endif #endif
@ -220,7 +310,7 @@ void setup_endstop_interrupts() {
#if (digitalPinToInterrupt(Z3_MAX_PIN) != NOT_AN_INTERRUPT) #if (digitalPinToInterrupt(Z3_MAX_PIN) != NOT_AN_INTERRUPT)
_ATTACH(Z3_MAX_PIN); _ATTACH(Z3_MAX_PIN);
#else #else
static_assert(digitalPinHasPCICR(Z3_MAX_PIN), "Z3_MAX_PIN is not interrupt-capable"); static_assert(digitalPinHasPCICR(Z3_MAX_PIN), "Z3_MAX_PIN is not interrupt-capable. Disable ENDSTOP_INTERRUPTS_FEATURE to continue.");
pciSetup(Z3_MAX_PIN); pciSetup(Z3_MAX_PIN);
#endif #endif
#endif #endif
@ -228,7 +318,7 @@ void setup_endstop_interrupts() {
#if (digitalPinToInterrupt(Z3_MIN_PIN) != NOT_AN_INTERRUPT) #if (digitalPinToInterrupt(Z3_MIN_PIN) != NOT_AN_INTERRUPT)
_ATTACH(Z3_MIN_PIN); _ATTACH(Z3_MIN_PIN);
#else #else
static_assert(digitalPinHasPCICR(Z3_MIN_PIN), "Z3_MIN_PIN is not interrupt-capable"); static_assert(digitalPinHasPCICR(Z3_MIN_PIN), "Z3_MIN_PIN is not interrupt-capable. Disable ENDSTOP_INTERRUPTS_FEATURE to continue.");
pciSetup(Z3_MIN_PIN); pciSetup(Z3_MIN_PIN);
#endif #endif
#endif #endif
@ -236,7 +326,7 @@ void setup_endstop_interrupts() {
#if (digitalPinToInterrupt(Z4_MAX_PIN) != NOT_AN_INTERRUPT) #if (digitalPinToInterrupt(Z4_MAX_PIN) != NOT_AN_INTERRUPT)
_ATTACH(Z4_MAX_PIN); _ATTACH(Z4_MAX_PIN);
#else #else
static_assert(digitalPinHasPCICR(Z4_MAX_PIN), "Z4_MAX_PIN is not interrupt-capable"); static_assert(digitalPinHasPCICR(Z4_MAX_PIN), "Z4_MAX_PIN is not interrupt-capable. Disable ENDSTOP_INTERRUPTS_FEATURE to continue.");
pciSetup(Z4_MAX_PIN); pciSetup(Z4_MAX_PIN);
#endif #endif
#endif #endif
@ -244,7 +334,7 @@ void setup_endstop_interrupts() {
#if (digitalPinToInterrupt(Z4_MIN_PIN) != NOT_AN_INTERRUPT) #if (digitalPinToInterrupt(Z4_MIN_PIN) != NOT_AN_INTERRUPT)
_ATTACH(Z4_MIN_PIN); _ATTACH(Z4_MIN_PIN);
#else #else
static_assert(digitalPinHasPCICR(Z4_MIN_PIN), "Z4_MIN_PIN is not interrupt-capable"); static_assert(digitalPinHasPCICR(Z4_MIN_PIN), "Z4_MIN_PIN is not interrupt-capable. Disable ENDSTOP_INTERRUPTS_FEATURE to continue.");
pciSetup(Z4_MIN_PIN); pciSetup(Z4_MIN_PIN);
#endif #endif
#endif #endif
@ -252,7 +342,7 @@ void setup_endstop_interrupts() {
#if (digitalPinToInterrupt(Z_MIN_PROBE_PIN) != NOT_AN_INTERRUPT) #if (digitalPinToInterrupt(Z_MIN_PROBE_PIN) != NOT_AN_INTERRUPT)
_ATTACH(Z_MIN_PROBE_PIN); _ATTACH(Z_MIN_PROBE_PIN);
#else #else
static_assert(digitalPinHasPCICR(Z_MIN_PROBE_PIN), "Z_MIN_PROBE_PIN is not interrupt-capable"); static_assert(digitalPinHasPCICR(Z_MIN_PROBE_PIN), "Z_MIN_PROBE_PIN is not interrupt-capable. Disable ENDSTOP_INTERRUPTS_FEATURE to continue.");
pciSetup(Z_MIN_PROBE_PIN); pciSetup(Z_MIN_PROBE_PIN);
#endif #endif
#endif #endif

View File

@ -21,11 +21,7 @@
*/ */
#ifdef __AVR__ #ifdef __AVR__
#include "../../inc/MarlinConfigPre.h" #include "../../inc/MarlinConfig.h"
#if NEEDS_HARDWARE_PWM // Specific meta-flag for features that mandate PWM
#include "HAL.h"
struct Timer { struct Timer {
volatile uint8_t* TCCRnQ[3]; // max 3 TCCR registers per timer volatile uint8_t* TCCRnQ[3]; // max 3 TCCR registers per timer
@ -33,250 +29,194 @@ struct Timer {
volatile uint16_t* ICRn; // max 1 ICR register per timer volatile uint16_t* ICRn; // max 1 ICR register per timer
uint8_t n; // the timer number [0->5] uint8_t n; // the timer number [0->5]
uint8_t q; // the timer output [0->2] (A->C) uint8_t q; // the timer output [0->2] (A->C)
bool isPWM; // True if pin is a "hardware timer"
bool isProtected; // True if timer is protected
}; };
// Macros for the Timer structure
#define _SET_WGMnQ(T, V) do{ \
*(T.TCCRnQ)[0] = (*(T.TCCRnQ)[0] & ~(0x3 << 0)) | (( int(V) & 0x3) << 0); \
*(T.TCCRnQ)[1] = (*(T.TCCRnQ)[1] & ~(0x3 << 3)) | (((int(V) >> 2) & 0x3) << 3); \
}while(0)
// Set TCCR CS bits
#define _SET_CSn(T, V) (*(T.TCCRnQ)[1] = (*(T.TCCRnQ[1]) & ~(0x7 << 0)) | ((int(V) & 0x7) << 0))
// Set TCCR COM bits
#define _SET_COMnQ(T, Q, V) (*(T.TCCRnQ)[0] = (*(T.TCCRnQ)[0] & ~(0x3 << (6-2*(Q)))) | (int(V) << (6-2*(Q))))
// Set OCRnQ register
#define _SET_OCRnQ(T, Q, V) (*(T.OCRnQ)[Q] = int(V) & 0xFFFF)
// Set ICRn register (one per timer)
#define _SET_ICRn(T, V) (*(T.ICRn) = int(V) & 0xFFFF)
/** /**
* get_pwm_timer * Return a Timer struct describing a pin's timer.
* Get the timer information and register of the provided pin.
* Return a Timer struct containing this information.
* Used by set_pwm_frequency, set_pwm_duty
*/ */
Timer get_pwm_timer(const pin_t pin) { const Timer get_pwm_timer(const pin_t pin) {
uint8_t q = 0; uint8_t q = 0;
switch (digitalPinToTimer(pin)) { switch (digitalPinToTimer(pin)) {
// Protect reserved timers (TIMER0 & TIMER1)
#ifdef TCCR0A #ifdef TCCR0A
#if !AVR_AT90USB1286_FAMILY IF_DISABLED(AVR_AT90USB1286_FAMILY, case TIMER0A:)
case TIMER0A:
#endif
case TIMER0B:
#endif #endif
#ifdef TCCR1A #ifdef TCCR1A
case TIMER1A: case TIMER1B: case TIMER1A: case TIMER1B:
#endif #endif
break;
#if defined(TCCR2) || defined(TCCR2A) break; // Protect reserved timers (TIMER0 & TIMER1)
#ifdef TCCR2
case TIMER2: { #ifdef TCCR0A
Timer timer = { case TIMER0B: // Protected timer, but allow setting the duty cycle on OCR0B for pin D4 only
/*TCCRnQ*/ { &TCCR2, nullptr, nullptr }, return Timer({ { &TCCR0A, nullptr, nullptr }, { (uint16_t*)&OCR0A, (uint16_t*)&OCR0B, nullptr }, nullptr, 0, 1, true, true });
/*OCRnQ*/ { (uint16_t*)&OCR2, nullptr, nullptr },
/*ICRn*/ nullptr,
/*n, q*/ 2, 0
};
}
#elif defined(TCCR2A)
#if ENABLED(USE_OCR2A_AS_TOP)
case TIMER2A: break; // protect TIMER2A
case TIMER2B: {
Timer timer = {
/*TCCRnQ*/ { &TCCR2A, &TCCR2B, nullptr },
/*OCRnQ*/ { (uint16_t*)&OCR2A, (uint16_t*)&OCR2B, nullptr },
/*ICRn*/ nullptr,
/*n, q*/ 2, 1
};
return timer;
}
#else
case TIMER2B: ++q;
case TIMER2A: {
Timer timer = {
/*TCCRnQ*/ { &TCCR2A, &TCCR2B, nullptr },
/*OCRnQ*/ { (uint16_t*)&OCR2A, (uint16_t*)&OCR2B, nullptr },
/*ICRn*/ nullptr,
2, q
};
return timer;
}
#endif
#endif
#endif #endif
#if HAS_TCCR2
case TIMER2:
return Timer({ { &TCCR2, nullptr, nullptr }, { (uint16_t*)&OCR2, nullptr, nullptr }, nullptr, 2, 0, true, false });
#elif ENABLED(USE_OCR2A_AS_TOP)
case TIMER2A: break; // Protect TIMER2A since its OCR is used by TIMER2B
case TIMER2B:
return Timer({ { &TCCR2A, &TCCR2B, nullptr }, { (uint16_t*)&OCR2A, (uint16_t*)&OCR2B, nullptr }, nullptr, 2, 1, true, false });
#elif defined(TCCR2A)
case TIMER2B: ++q; case TIMER2A:
return Timer({ { &TCCR2A, &TCCR2B, nullptr }, { (uint16_t*)&OCR2A, (uint16_t*)&OCR2B, nullptr }, nullptr, 2, q, true, false });
#endif
#ifdef OCR3C #ifdef OCR3C
case TIMER3C: ++q; case TIMER3C: ++q; case TIMER3B: ++q; case TIMER3A:
case TIMER3B: ++q; return Timer({ { &TCCR3A, &TCCR3B, &TCCR3C }, { &OCR3A, &OCR3B, &OCR3C }, &ICR3, 3, q, true, false });
case TIMER3A: {
Timer timer = {
/*TCCRnQ*/ { &TCCR3A, &TCCR3B, &TCCR3C },
/*OCRnQ*/ { &OCR3A, &OCR3B, &OCR3C },
/*ICRn*/ &ICR3,
/*n, q*/ 3, q
};
return timer;
}
#elif defined(OCR3B) #elif defined(OCR3B)
case TIMER3B: ++q; case TIMER3B: ++q; case TIMER3A:
case TIMER3A: { return Timer({ { &TCCR3A, &TCCR3B, nullptr }, { &OCR3A, &OCR3B, nullptr }, &ICR3, 3, q, true, false });
Timer timer = {
/*TCCRnQ*/ { &TCCR3A, &TCCR3B, nullptr },
/*OCRnQ*/ { &OCR3A, &OCR3B, nullptr },
/*ICRn*/ &ICR3,
/*n, q*/ 3, q
};
return timer;
}
#endif #endif
#ifdef TCCR4A #ifdef TCCR4A
case TIMER4C: ++q; case TIMER4C: ++q; case TIMER4B: ++q; case TIMER4A:
case TIMER4B: ++q; return Timer({ { &TCCR4A, &TCCR4B, &TCCR4C }, { &OCR4A, &OCR4B, &OCR4C }, &ICR4, 4, q, true, false });
case TIMER4A: {
Timer timer = {
/*TCCRnQ*/ { &TCCR4A, &TCCR4B, &TCCR4C },
/*OCRnQ*/ { &OCR4A, &OCR4B, &OCR4C },
/*ICRn*/ &ICR4,
/*n, q*/ 4, q
};
return timer;
}
#endif #endif
#ifdef TCCR5A #ifdef TCCR5A
case TIMER5C: ++q; case TIMER5C: ++q; case TIMER5B: ++q; case TIMER5A:
case TIMER5B: ++q; return Timer({ { &TCCR5A, &TCCR5B, &TCCR5C }, { &OCR5A, &OCR5B, &OCR5C }, &ICR5, 5, q, true, false });
case TIMER5A: {
Timer timer = {
/*TCCRnQ*/ { &TCCR5A, &TCCR5B, &TCCR5C },
/*OCRnQ*/ { &OCR5A, &OCR5B, &OCR5C },
/*ICRn*/ &ICR5,
/*n, q*/ 5, q
};
return timer;
}
#endif #endif
} }
Timer timer = {
/*TCCRnQ*/ { nullptr, nullptr, nullptr }, return Timer();
/*OCRnQ*/ { nullptr, nullptr, nullptr },
/*ICRn*/ nullptr,
0, 0
};
return timer;
} }
void set_pwm_frequency(const pin_t pin, int f_desired) { void MarlinHAL::set_pwm_frequency(const pin_t pin, const uint16_t f_desired) {
Timer timer = get_pwm_timer(pin); const Timer timer = get_pwm_timer(pin);
if (timer.n == 0) return; // Don't proceed if protected timer or not recognised if (timer.isProtected || !timer.isPWM) return; // Don't proceed if protected timer or not recognized
uint16_t size;
if (timer.n == 2) size = 255; else size = 65535;
uint16_t res = 255; // resolution (TOP value) const bool is_timer2 = timer.n == 2;
uint8_t j = 0; // prescaler index const uint16_t maxtop = is_timer2 ? 0xFF : 0xFFFF;
uint8_t wgm = 1; // waveform generation mode
uint16_t res = 0xFF; // resolution (TOP value)
uint8_t j = CS_NONE; // prescaler index
uint8_t wgm = WGM_PWM_PC_8; // waveform generation mode
// Calculating the prescaler and resolution to use to achieve closest frequency // Calculating the prescaler and resolution to use to achieve closest frequency
if (f_desired != 0) { if (f_desired != 0) {
int f = (F_CPU) / (2 * 1024 * size) + 1; // Initialize frequency as lowest (non-zero) achievable constexpr uint16_t prescaler[] = { 1, 8, (32), 64, (128), 256, 1024 }; // (*) are Timer 2 only
uint16_t prescaler[] = { 0, 1, 8, /*TIMER2 ONLY*/32, 64, /*TIMER2 ONLY*/128, 256, 1024 }; uint16_t f = (F_CPU) / (2 * 1024 * maxtop) + 1; // Start with the lowest non-zero frequency achievable (1 or 31)
// loop over prescaler values LOOP_L_N(i, COUNT(prescaler)) { // Loop through all prescaler values
LOOP_S_L_N(i, 1, 8) { const uint16_t p = prescaler[i];
uint16_t res_temp_fast = 255, res_temp_phase_correct = 255; uint16_t res_fast_temp, res_pc_temp;
if (timer.n == 2) { if (is_timer2) {
// No resolution calculation for TIMER2 unless enabled USE_OCR2A_AS_TOP #if ENABLED(USE_OCR2A_AS_TOP) // No resolution calculation for TIMER2 unless enabled USE_OCR2A_AS_TOP
#if ENABLED(USE_OCR2A_AS_TOP) const uint16_t rft = (F_CPU) / (p * f_desired);
const uint16_t rtf = (F_CPU) / (prescaler[i] * f_desired); res_fast_temp = rft - 1;
res_temp_fast = rtf - 1; res_pc_temp = rft / 2;
res_temp_phase_correct = rtf / 2; #else
res_fast_temp = res_pc_temp = maxtop;
#endif #endif
} }
else { else {
// Skip TIMER2 specific prescalers when not TIMER2 if (p == 32 || p == 128) continue; // Skip TIMER2 specific prescalers when not TIMER2
if (i == 3 || i == 5) continue; const uint16_t rft = (F_CPU) / (p * f_desired);
const uint16_t rtf = (F_CPU) / (prescaler[i] * f_desired); res_fast_temp = rft - 1;
res_temp_fast = rtf - 1; res_pc_temp = rft / 2;
res_temp_phase_correct = rtf / 2;
} }
LIMIT(res_temp_fast, 1U, size); LIMIT(res_fast_temp, 1U, maxtop);
LIMIT(res_temp_phase_correct, 1U, size); LIMIT(res_pc_temp, 1U, maxtop);
// Calculate frequencies of test prescaler and resolution values // Calculate frequencies of test prescaler and resolution values
const int f_temp_fast = (F_CPU) / (prescaler[i] * (1 + res_temp_fast)), const uint16_t f_fast_temp = (F_CPU) / (p * (1 + res_fast_temp)),
f_temp_phase_correct = (F_CPU) / (2 * prescaler[i] * res_temp_phase_correct), f_pc_temp = (F_CPU) / (2 * p * res_pc_temp);
f_diff = ABS(f - f_desired), const int f_diff = _MAX(f, f_desired) - _MIN(f, f_desired),
f_fast_diff = ABS(f_temp_fast - f_desired), f_fast_diff = _MAX(f_fast_temp, f_desired) - _MIN(f_fast_temp, f_desired),
f_phase_diff = ABS(f_temp_phase_correct - f_desired); f_pc_diff = _MAX(f_pc_temp, f_desired) - _MIN(f_pc_temp, f_desired);
// If FAST values are closest to desired f if (f_fast_diff < f_diff && f_fast_diff <= f_pc_diff) { // FAST values are closest to desired f
if (f_fast_diff < f_diff && f_fast_diff <= f_phase_diff) {
// Remember this combination
f = f_temp_fast;
res = res_temp_fast;
j = i;
// Set the Wave Generation Mode to FAST PWM // Set the Wave Generation Mode to FAST PWM
if (timer.n == 2) { wgm = is_timer2 ? uint8_t(TERN(USE_OCR2A_AS_TOP, WGM2_FAST_PWM_OCR2A, WGM2_FAST_PWM)) : uint8_t(WGM_FAST_PWM_ICRn);
wgm = ( // Remember this combination
#if ENABLED(USE_OCR2A_AS_TOP) f = f_fast_temp; res = res_fast_temp; j = i + 1;
WGM2_FAST_PWM_OCR2A
#else
WGM2_FAST_PWM
#endif
);
}
else wgm = WGM_FAST_PWM_ICRn;
} }
// If PHASE CORRECT values are closes to desired f else if (f_pc_diff < f_diff) { // PHASE CORRECT values are closes to desired f
else if (f_phase_diff < f_diff) {
f = f_temp_phase_correct;
res = res_temp_phase_correct;
j = i;
// Set the Wave Generation Mode to PWM PHASE CORRECT // Set the Wave Generation Mode to PWM PHASE CORRECT
if (timer.n == 2) { wgm = is_timer2 ? uint8_t(TERN(USE_OCR2A_AS_TOP, WGM2_PWM_PC_OCR2A, WGM2_PWM_PC)) : uint8_t(WGM_PWM_PC_ICRn);
wgm = ( f = f_pc_temp; res = res_pc_temp; j = i + 1;
#if ENABLED(USE_OCR2A_AS_TOP)
WGM2_PWM_PC_OCR2A
#else
WGM2_PWM_PC
#endif
);
}
else wgm = WGM_PWM_PC_ICRn;
} }
} }
} }
_SET_WGMnQ(timer.TCCRnQ, wgm);
_SET_CSn(timer.TCCRnQ, j);
if (timer.n == 2) { _SET_WGMnQ(timer, wgm);
#if ENABLED(USE_OCR2A_AS_TOP) _SET_CSn(timer, j);
_SET_OCRnQ(timer.OCRnQ, 0, res); // Set OCR2A value (TOP) = res
#endif if (is_timer2) {
TERN_(USE_OCR2A_AS_TOP, _SET_OCRnQ(timer, 0, res)); // Set OCR2A value (TOP) = res
} }
else else
_SET_ICRn(timer.ICRn, res); // Set ICRn value (TOP) = res _SET_ICRn(timer, res); // Set ICRn value (TOP) = res
} }
void set_pwm_duty(const pin_t pin, const uint16_t v, const uint16_t v_size/*=255*/, const bool invert/*=false*/) { void MarlinHAL::set_pwm_duty(const pin_t pin, const uint16_t v, const uint16_t v_size/*=255*/, const bool invert/*=false*/) {
// If v is 0 or v_size (max), digitalWrite to LOW or HIGH. // If v is 0 or v_size (max), digitalWrite to LOW or HIGH.
// Note that digitalWrite also disables pwm output for us (sets COM bit to 0) // Note that digitalWrite also disables PWM output for us (sets COM bit to 0)
if (v == 0) if (v == 0)
digitalWrite(pin, invert); digitalWrite(pin, invert);
else if (v == v_size) else if (v == v_size)
digitalWrite(pin, !invert); digitalWrite(pin, !invert);
else { else {
Timer timer = get_pwm_timer(pin); const Timer timer = get_pwm_timer(pin);
if (timer.n == 0) return; // Don't proceed if protected timer or not recognised if (timer.isPWM) {
// Set compare output mode to CLEAR -> SET or SET -> CLEAR (if inverted) if (timer.n == 0) {
_SET_COMnQ(timer.TCCRnQ, (timer.q _SET_COMnQ(timer, timer.q, COM_CLEAR_SET); // Only allow a TIMER0B select...
#ifdef TCCR2 _SET_OCRnQ(timer, timer.q, v); // ...and OCR0B duty update. For output pin D4 no frequency changes are permitted.
+ (timer.q == 2) // COM20 is on bit 4 of TCCR2, thus requires q + 1 in the macro }
#endif else if (!timer.isProtected) {
), COM_CLEAR_SET + invert const uint16_t top = timer.n == 2 ? TERN(USE_OCR2A_AS_TOP, *timer.OCRnQ[0], 255) : *timer.ICRn;
); _SET_COMnQ(timer, SUM_TERN(HAS_TCCR2, timer.q, timer.q == 2), COM_CLEAR_SET + invert); // COM20 is on bit 4 of TCCR2, so +1 for q==2
_SET_OCRnQ(timer, timer.q, uint16_t(uint32_t(v) * top / v_size)); // Scale 8/16-bit v to top value
uint16_t top; }
if (timer.n == 2) { // if TIMER2
top = (
#if ENABLED(USE_OCR2A_AS_TOP)
*timer.OCRnQ[0] // top = OCR2A
#else
255 // top = 0xFF (max)
#endif
);
} }
else else
top = *timer.ICRn; // top = ICRn digitalWrite(pin, v < v_size / 2 ? LOW : HIGH);
_SET_OCRnQ(timer.OCRnQ, timer.q, v * float(top) / float(v_size)); // Scale 8/16-bit v to top value
} }
} }
#endif // NEEDS_HARDWARE_PWM void MarlinHAL::init_pwm_timers() {
// Init some timer frequencies to a default 1KHz
const pin_t pwm_pin[] = {
#ifdef __AVR_ATmega2560__
10, 5, 6, 46
#elif defined(__AVR_ATmega1280__)
12, 31
#elif defined(__AVR_ATmega644__) || defined(__AVR_ATmega1284__)
15, 6
#elif defined(__AVR_AT90USB1286__) || defined(__AVR_mega64) || defined(__AVR_mega128)
16, 24
#endif
};
LOOP_L_N(i, COUNT(pwm_pin))
set_pwm_frequency(pwm_pin[i], 1000);
}
#endif // __AVR__ #endif // __AVR__

View File

@ -241,11 +241,11 @@ uint8_t extDigitalRead(const int8_t pin) {
* *
* DC values -1.0 to 1.0. Negative duty cycle inverts the pulse. * DC values -1.0 to 1.0. Negative duty cycle inverts the pulse.
*/ */
uint16_t set_pwm_frequency_hz(const float &hz, const float dca, const float dcb, const float dcc) { uint16_t set_pwm_frequency_hz(const_float_t hz, const float dca, const float dcb, const float dcc) {
float count = 0; float count = 0;
if (hz > 0 && (dca || dcb || dcc)) { if (hz > 0 && (dca || dcb || dcc)) {
count = float(F_CPU) / hz; // 1x prescaler, TOP for 16MHz base freq. count = float(F_CPU) / hz; // 1x prescaler, TOP for 16MHz base freq.
uint16_t prescaler; // Range of 30.5Hz (65535) 64.5KHz (>31) uint16_t prescaler; // Range of 30.5Hz (65535) 64.5kHz (>31)
if (count >= 255. * 256.) { prescaler = 1024; SET_CS(5, PRESCALER_1024); } if (count >= 255. * 256.) { prescaler = 1024; SET_CS(5, PRESCALER_1024); }
else if (count >= 255. * 64.) { prescaler = 256; SET_CS(5, PRESCALER_256); } else if (count >= 255. * 64.) { prescaler = 256; SET_CS(5, PRESCALER_256); }
@ -257,7 +257,7 @@ uint16_t set_pwm_frequency_hz(const float &hz, const float dca, const float dcb,
const float pwm_top = round(count); // Get the rounded count const float pwm_top = round(count); // Get the rounded count
ICR5 = (uint16_t)pwm_top - 1; // Subtract 1 for TOP ICR5 = (uint16_t)pwm_top - 1; // Subtract 1 for TOP
OCR5A = pwm_top * ABS(dca); // Update and scale DCs OCR5A = pwm_top * ABS(dca); // Update and scale DCs
OCR5B = pwm_top * ABS(dcb); OCR5B = pwm_top * ABS(dcb);
OCR5C = pwm_top * ABS(dcc); OCR5C = pwm_top * ABS(dcc);
_SET_COM(5, A, dca ? (dca < 0 ? COM_SET_CLEAR : COM_CLEAR_SET) : COM_NORMAL); // Set compare modes _SET_COM(5, A, dca ? (dca < 0 ? COM_SET_CLEAR : COM_CLEAR_SET) : COM_NORMAL); // Set compare modes
@ -267,17 +267,17 @@ uint16_t set_pwm_frequency_hz(const float &hz, const float dca, const float dcb,
SET_WGM(5, FAST_PWM_ICRn); // Fast PWM with ICR5 as TOP SET_WGM(5, FAST_PWM_ICRn); // Fast PWM with ICR5 as TOP
//SERIAL_ECHOLNPGM("Timer 5 Settings:"); //SERIAL_ECHOLNPGM("Timer 5 Settings:");
//SERIAL_ECHOLNPAIR(" Prescaler=", prescaler); //SERIAL_ECHOLNPGM(" Prescaler=", prescaler);
//SERIAL_ECHOLNPAIR(" TOP=", ICR5); //SERIAL_ECHOLNPGM(" TOP=", ICR5);
//SERIAL_ECHOLNPAIR(" OCR5A=", OCR5A); //SERIAL_ECHOLNPGM(" OCR5A=", OCR5A);
//SERIAL_ECHOLNPAIR(" OCR5B=", OCR5B); //SERIAL_ECHOLNPGM(" OCR5B=", OCR5B);
//SERIAL_ECHOLNPAIR(" OCR5C=", OCR5C); //SERIAL_ECHOLNPGM(" OCR5C=", OCR5C);
} }
else { else {
// Restore the default for Timer 5 // Restore the default for Timer 5
SET_WGM(5, PWM_PC_8); // PWM 8-bit (Phase Correct) SET_WGM(5, PWM_PC_8); // PWM 8-bit (Phase Correct)
SET_COMS(5, NORMAL, NORMAL, NORMAL); // Do nothing SET_COMS(5, NORMAL, NORMAL, NORMAL); // Do nothing
SET_CS(5, PRESCALER_64); // 16MHz / 64 = 250KHz SET_CS(5, PRESCALER_64); // 16MHz / 64 = 250kHz
OCR5A = OCR5B = OCR5C = 0; OCR5A = OCR5B = OCR5C = 0;
} }
return round(count); return round(count);

View File

@ -118,7 +118,7 @@
*/ */
// Waveform Generation Modes // Waveform Generation Modes
enum WaveGenMode : char { enum WaveGenMode : uint8_t {
WGM_NORMAL, // 0 WGM_NORMAL, // 0
WGM_PWM_PC_8, // 1 WGM_PWM_PC_8, // 1
WGM_PWM_PC_9, // 2 WGM_PWM_PC_9, // 2
@ -138,19 +138,19 @@ enum WaveGenMode : char {
}; };
// Wavefore Generation Modes (Timer 2 only) // Wavefore Generation Modes (Timer 2 only)
enum WaveGenMode2 : char { enum WaveGenMode2 : uint8_t {
WGM2_NORMAL, // 0 WGM2_NORMAL, // 0
WGM2_PWM_PC, // 1 WGM2_PWM_PC, // 1
WGM2_CTC_OCR2A, // 2 WGM2_CTC_OCR2A, // 2
WGM2_FAST_PWM, // 3 WGM2_FAST_PWM, // 3
WGM2_reserved_1, // 4 WGM2_reserved_1, // 4
WGM2_PWM_PC_OCR2A, // 5 WGM2_PWM_PC_OCR2A, // 5
WGM2_reserved_2, // 6 WGM2_reserved_2, // 6
WGM2_FAST_PWM_OCR2A, // 7 WGM2_FAST_PWM_OCR2A, // 7
}; };
// Compare Modes // Compare Modes
enum CompareMode : char { enum CompareMode : uint8_t {
COM_NORMAL, // 0 COM_NORMAL, // 0
COM_TOGGLE, // 1 Non-PWM: OCnx ... Both PWM (WGM 9,11,14,15): OCnA only ... else NORMAL COM_TOGGLE, // 1 Non-PWM: OCnx ... Both PWM (WGM 9,11,14,15): OCnA only ... else NORMAL
COM_CLEAR_SET, // 2 Non-PWM: OCnx ... Fast PWM: OCnx/Bottom ... PF-FC: OCnx Up/Down COM_CLEAR_SET, // 2 Non-PWM: OCnx ... Fast PWM: OCnx/Bottom ... PF-FC: OCnx Up/Down
@ -158,7 +158,7 @@ enum CompareMode : char {
}; };
// Clock Sources // Clock Sources
enum ClockSource : char { enum ClockSource : uint8_t {
CS_NONE, // 0 CS_NONE, // 0
CS_PRESCALER_1, // 1 CS_PRESCALER_1, // 1
CS_PRESCALER_8, // 2 CS_PRESCALER_8, // 2
@ -170,7 +170,7 @@ enum ClockSource : char {
}; };
// Clock Sources (Timer 2 only) // Clock Sources (Timer 2 only)
enum ClockSource2 : char { enum ClockSource2 : uint8_t {
CS2_NONE, // 0 CS2_NONE, // 0
CS2_PRESCALER_1, // 1 CS2_PRESCALER_1, // 1
CS2_PRESCALER_8, // 2 CS2_PRESCALER_8, // 2
@ -203,40 +203,33 @@ enum ClockSource2 : char {
TCCR##T##B = (TCCR##T##B & ~(0x3 << WGM##T##2)) | (((int(V) >> 2) & 0x3) << WGM##T##2); \ TCCR##T##B = (TCCR##T##B & ~(0x3 << WGM##T##2)) | (((int(V) >> 2) & 0x3) << WGM##T##2); \
}while(0) }while(0)
#define SET_WGM(T,V) _SET_WGM(T,WGM_##V) #define SET_WGM(T,V) _SET_WGM(T,WGM_##V)
// Runtime (see set_pwm_frequency):
#define _SET_WGMnQ(TCCRnQ, V) do{ \
*(TCCRnQ)[0] = (*(TCCRnQ)[0] & ~(0x3 << 0)) | (( int(V) & 0x3) << 0); \
*(TCCRnQ)[1] = (*(TCCRnQ)[1] & ~(0x3 << 3)) | (((int(V) >> 2) & 0x3) << 3); \
}while(0)
// Set Clock Select bits // Set Clock Select bits
// Ex: SET_CS3(PRESCALER_64); // Ex: SET_CS3(PRESCALER_64);
#ifdef TCCR2
#define HAS_TCCR2 1
#endif
#define _SET_CS(T,V) (TCCR##T##B = (TCCR##T##B & ~(0x7 << CS##T##0)) | ((int(V) & 0x7) << CS##T##0)) #define _SET_CS(T,V) (TCCR##T##B = (TCCR##T##B & ~(0x7 << CS##T##0)) | ((int(V) & 0x7) << CS##T##0))
#define _SET_CS0(V) _SET_CS(0,V) #define _SET_CS0(V) _SET_CS(0,V)
#define _SET_CS1(V) _SET_CS(1,V) #define _SET_CS1(V) _SET_CS(1,V)
#ifdef TCCR2
#define _SET_CS2(V) (TCCR2 = (TCCR2 & ~(0x7 << CS20)) | (int(V) << CS20))
#else
#define _SET_CS2(V) _SET_CS(2,V)
#endif
#define _SET_CS3(V) _SET_CS(3,V) #define _SET_CS3(V) _SET_CS(3,V)
#define _SET_CS4(V) _SET_CS(4,V) #define _SET_CS4(V) _SET_CS(4,V)
#define _SET_CS5(V) _SET_CS(5,V) #define _SET_CS5(V) _SET_CS(5,V)
#define SET_CS0(V) _SET_CS0(CS_##V) #define SET_CS0(V) _SET_CS0(CS_##V)
#define SET_CS1(V) _SET_CS1(CS_##V) #define SET_CS1(V) _SET_CS1(CS_##V)
#ifdef TCCR2
#if HAS_TCCR2
#define _SET_CS2(V) (TCCR2 = (TCCR2 & ~(0x7 << CS20)) | (int(V) << CS20))
#define SET_CS2(V) _SET_CS2(CS2_##V) #define SET_CS2(V) _SET_CS2(CS2_##V)
#else #else
#define _SET_CS2(V) _SET_CS(2,V)
#define SET_CS2(V) _SET_CS2(CS_##V) #define SET_CS2(V) _SET_CS2(CS_##V)
#endif #endif
#define SET_CS3(V) _SET_CS3(CS_##V) #define SET_CS3(V) _SET_CS3(CS_##V)
#define SET_CS4(V) _SET_CS4(CS_##V) #define SET_CS4(V) _SET_CS4(CS_##V)
#define SET_CS5(V) _SET_CS5(CS_##V) #define SET_CS5(V) _SET_CS5(CS_##V)
#define SET_CS(T,V) SET_CS##T(V) #define SET_CS(T,V) SET_CS##T(V)
// Runtime (see set_pwm_frequency)
#define _SET_CSn(TCCRnQ, V) do{ \
(*(TCCRnQ)[1] = (*(TCCRnQ[1]) & ~(0x7 << 0)) | ((int(V) & 0x7) << 0)); \
}while(0)
// Set Compare Mode bits // Set Compare Mode bits
// Ex: SET_COMS(4,CLEAR_SET,CLEAR_SET,CLEAR_SET); // Ex: SET_COMS(4,CLEAR_SET,CLEAR_SET,CLEAR_SET);
@ -246,22 +239,6 @@ enum ClockSource2 : char {
#define SET_COMB(T,V) SET_COM(T,B,V) #define SET_COMB(T,V) SET_COM(T,B,V)
#define SET_COMC(T,V) SET_COM(T,C,V) #define SET_COMC(T,V) SET_COM(T,C,V)
#define SET_COMS(T,V1,V2,V3) do{ SET_COMA(T,V1); SET_COMB(T,V2); SET_COMC(T,V3); }while(0) #define SET_COMS(T,V1,V2,V3) do{ SET_COMA(T,V1); SET_COMB(T,V2); SET_COMC(T,V3); }while(0)
// Runtime (see set_pwm_duty)
#define _SET_COMnQ(TCCRnQ, Q, V) do{ \
(*(TCCRnQ)[0] = (*(TCCRnQ)[0] & ~(0x3 << (6-2*(Q)))) | (int(V) << (6-2*(Q)))); \
}while(0)
// Set OCRnQ register
// Runtime (see set_pwm_duty):
#define _SET_OCRnQ(OCRnQ, Q, V) do{ \
(*(OCRnQ)[(Q)] = (0x0000) | (int(V) & 0xFFFF)); \
}while(0)
// Set ICRn register (one per timer)
// Runtime (see set_pwm_frequency)
#define _SET_ICRn(ICRn, V) do{ \
(*(ICRn) = (0x0000) | (int(V) & 0xFFFF)); \
}while(0)
// Set Noise Canceler bit // Set Noise Canceler bit
// Ex: SET_ICNC(2,1) // Ex: SET_ICNC(2,1)
@ -284,8 +261,8 @@ enum ClockSource2 : char {
* PWM availability macros * PWM availability macros
*/ */
// Determine which harware PWMs are already in use // 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) #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) #if PIN_EXISTS(CONTROLLER_FAN)
#define PWM_CHK_FAN_B(P) (_PWM_CHK_FAN_B(P) || P == CONTROLLER_FAN_PIN) #define PWM_CHK_FAN_B(P) (_PWM_CHK_FAN_B(P) || P == CONTROLLER_FAN_PIN)
#else #else
@ -316,11 +293,11 @@ enum ClockSource2 : char {
#if HAS_MOTOR_CURRENT_PWM #if HAS_MOTOR_CURRENT_PWM
#if PIN_EXISTS(MOTOR_CURRENT_PWM_XY) #if PIN_EXISTS(MOTOR_CURRENT_PWM_XY)
#define PWM_CHK_MOTOR_CURRENT(P) (P == MOTOR_CURRENT_PWM_E || P == MOTOR_CURRENT_PWM_Z || P == 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) #elif PIN_EXISTS(MOTOR_CURRENT_PWM_Z)
#define PWM_CHK_MOTOR_CURRENT(P) (P == MOTOR_CURRENT_PWM_E || P == 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 #else
#define PWM_CHK_MOTOR_CURRENT(P) (P == MOTOR_CURRENT_PWM_E) #define PWM_CHK_MOTOR_CURRENT(P) (P == MOTOR_CURRENT_PWM_E || P == MOTOR_CURRENT_PWM_E0 || P == MOTOR_CURRENT_PWM_E1)
#endif #endif
#else #else
#define PWM_CHK_MOTOR_CURRENT(P) false #define PWM_CHK_MOTOR_CURRENT(P) false

View File

@ -25,25 +25,67 @@
* Test AVR-specific configuration values for errors at compile-time. * Test AVR-specific configuration values for errors at compile-time.
*/ */
/**
* 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 \
)
#if SERIAL_IN_USE(0)
// D0-D1. No known conflicts.
#endif
#if SERIAL_IN_USE(1)
#if NOT_TARGET(__AVR_ATmega644P__, __AVR_ATmega1284P__)
#if CHECK_SERIAL_PIN(18) || CHECK_SERIAL_PIN(19)
#error "Serial Port 1 pin D18 and/or D19 conflicts with another pin on the board."
#endif
#else
#if CHECK_SERIAL_PIN(10) || CHECK_SERIAL_PIN(11)
#error "Serial Port 1 pin D10 and/or D11 conflicts with another pin on the board."
#endif
#endif
#endif
#if SERIAL_IN_USE(2) && (CHECK_SERIAL_PIN(16) || CHECK_SERIAL_PIN(17))
#error "Serial Port 2 pin D16 and/or D17 conflicts with another pin on the board."
#endif
#if SERIAL_IN_USE(3) && (CHECK_SERIAL_PIN(14) || CHECK_SERIAL_PIN(15))
#error "Serial Port 3 pin D14 and/or D15 conflicts with another pin on the board."
#endif
#undef CHECK_SERIAL_PIN
/** /**
* Checks for FAST PWM * Checks for FAST PWM
*/ */
#if ENABLED(FAST_PWM_FAN) && (ENABLED(USE_OCR2A_AS_TOP) && defined(TCCR2)) #if ALL(FAST_PWM_FAN, USE_OCR2A_AS_TOP, HAS_TCCR2)
#error "USE_OCR2A_AS_TOP does not apply to devices with a single output TIMER2" #error "USE_OCR2A_AS_TOP does not apply to devices with a single output TIMER2."
#endif
/**
* 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)."
#error "Disable SPEAKER or enable FAN_SOFT_PWM."
#endif #endif
/** /**
* Sanity checks for Spindle / Laser PWM * Sanity checks for Spindle / Laser PWM
*/ */
#if ENABLED(SPINDLE_LASER_PWM) #if ENABLED(SPINDLE_LASER_USE_PWM)
#include "../ServoTimers.h" // Needed to check timer availability (_useTimer3) #include "../ServoTimers.h" // Needed to check timer availability (_useTimer3)
#if SPINDLE_LASER_PWM_PIN == 4 || WITHIN(SPINDLE_LASER_PWM_PIN, 11, 13) #if SPINDLE_LASER_PWM_PIN == 4 || WITHIN(SPINDLE_LASER_PWM_PIN, 11, 13)
#error "Counter/Timer for SPINDLE_LASER_PWM_PIN is used by a system interrupt." #error "Counter/Timer for SPINDLE_LASER_PWM_PIN is used by a system interrupt."
#elif NUM_SERVOS > 0 && defined(_useTimer3) && (WITHIN(SPINDLE_LASER_PWM_PIN, 2, 3) || SPINDLE_LASER_PWM_PIN == 5) #elif NUM_SERVOS > 0 && defined(_useTimer3) && (WITHIN(SPINDLE_LASER_PWM_PIN, 2, 3) || SPINDLE_LASER_PWM_PIN == 5)
#error "Counter/Timer for SPINDLE_LASER_PWM_PIN is used by the servo system." #error "Counter/Timer for SPINDLE_LASER_PWM_PIN is used by the servo system."
#endif #endif
#elif defined(SPINDLE_LASER_FREQUENCY) #elif SPINDLE_LASER_FREQUENCY
#error "SPINDLE_LASER_FREQUENCY requires SPINDLE_LASER_PWM." #error "SPINDLE_LASER_FREQUENCY requires SPINDLE_LASER_USE_PWM."
#endif #endif
/** /**
@ -56,3 +98,14 @@
#if BOTH(HAS_TMC_SW_SERIAL, MONITOR_DRIVER_STATUS) #if BOTH(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." #error "MONITOR_DRIVER_STATUS causes performance issues when used with SoftwareSerial-connected drivers. Disable MONITOR_DRIVER_STATUS or use hardware serial to continue."
#endif #endif
/**
* Postmortem debugging
*/
#if ENABLED(POSTMORTEM_DEBUGGING)
#error "POSTMORTEM_DEBUGGING is not supported on AVR boards."
#endif
#if USING_PULLDOWNS
#error "PULLDOWN pin mode is not available on AVR boards."
#endif

View File

@ -35,7 +35,7 @@
// C B A is longIn1 // C B A is longIn1
// D C B A is longIn2 // D C B A is longIn2
// //
static FORCE_INLINE uint16_t MultiU24X32toH16(uint32_t longIn1, uint32_t longIn2) { FORCE_INLINE static uint16_t MultiU24X32toH16(uint32_t longIn1, uint32_t longIn2) {
uint8_t tmp1; uint8_t tmp1;
uint8_t tmp2; uint8_t tmp2;
uint16_t intRes; uint16_t intRes;
@ -89,7 +89,7 @@ static FORCE_INLINE uint16_t MultiU24X32toH16(uint32_t longIn1, uint32_t longIn2
// uses: // uses:
// r26 to store 0 // r26 to store 0
// r27 to store the byte 1 of the 24 bit result // r27 to store the byte 1 of the 24 bit result
static FORCE_INLINE uint16_t MultiU16X8toH16(uint8_t charIn1, uint16_t intIn2) { FORCE_INLINE static uint16_t MultiU16X8toH16(uint8_t charIn1, uint16_t intIn2) {
uint8_t tmp; uint8_t tmp;
uint16_t intRes; uint16_t intRes;
__asm__ __volatile__ ( __asm__ __volatile__ (

View File

@ -2,6 +2,9 @@
* Marlin 3D Printer Firmware * Marlin 3D Printer Firmware
* Copyright (c) 2020 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] * 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 * 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 * it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or * the Free Software Foundation, either version 3 of the License, or
@ -38,7 +41,7 @@
// portModeRegister takes a different argument // portModeRegister takes a different argument
#define digitalPinToTimer_DEBUG(p) digitalPinToTimer(p) #define digitalPinToTimer_DEBUG(p) digitalPinToTimer(p)
#define digitalPinToBitMask_DEBUG(p) digitalPinToBitMask(p) #define digitalPinToBitMask_DEBUG(p) digitalPinToBitMask(p)
#define digitalPinToPort_DEBUG(p) digitalPinToPort_Teensy(p) #define digitalPinToPort_DEBUG(p) digitalPinToPort(p)
#define GET_PINMODE(pin) (*portModeRegister(pin) & digitalPinToBitMask_DEBUG(pin)) #define GET_PINMODE(pin) (*portModeRegister(pin) & digitalPinToBitMask_DEBUG(pin))
#elif AVR_ATmega2560_FAMILY_PLUS_70 // So we can access/display all the pins on boards using more than 70 #elif AVR_ATmega2560_FAMILY_PLUS_70 // So we can access/display all the pins on boards using more than 70
@ -71,7 +74,7 @@
#define MULTI_NAME_PAD 26 // space needed to be pretty if not first name assigned to a 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) { void PRINT_ARRAY_NAME(uint8_t x) {
char *name_mem_pointer = (char*)pgm_read_ptr(&pin_array[x].name); PGM_P const name_mem_pointer = (PGM_P)pgm_read_ptr(&pin_array[x].name);
LOOP_L_N(y, MAX_NAME_LENGTH) { LOOP_L_N(y, MAX_NAME_LENGTH) {
char temp_char = pgm_read_byte(name_mem_pointer + y); char temp_char = pgm_read_byte(name_mem_pointer + y);
if (temp_char != 0) if (temp_char != 0)
@ -99,7 +102,7 @@ void PRINT_ARRAY_NAME(uint8_t x) {
return true; \ return true; \
} else return false } else return false
#define ABTEST(N) defined(TCCR##N##A) && defined(COM##N##A1)
/** /**
* Print a pin's PWM status. * Print a pin's PWM status.
@ -110,7 +113,7 @@ static bool pwm_status(uint8_t pin) {
switch (digitalPinToTimer_DEBUG(pin)) { switch (digitalPinToTimer_DEBUG(pin)) {
#if defined(TCCR0A) && defined(COM0A1) #if ABTEST(0)
#ifdef TIMER0A #ifdef TIMER0A
#if !AVR_AT90USB1286_FAMILY // not available in Teensyduino type IDEs #if !AVR_AT90USB1286_FAMILY // not available in Teensyduino type IDEs
PWM_CASE(0, A); PWM_CASE(0, A);
@ -119,20 +122,20 @@ static bool pwm_status(uint8_t pin) {
PWM_CASE(0, B); PWM_CASE(0, B);
#endif #endif
#if defined(TCCR1A) && defined(COM1A1) #if ABTEST(1)
PWM_CASE(1, A); PWM_CASE(1, A);
PWM_CASE(1, B); PWM_CASE(1, B);
#if defined(COM1C1) && defined(TIMER1C) #if defined(COM1C1) && defined(TIMER1C)
PWM_CASE(1, C); PWM_CASE(1, C);
#endif #endif
#endif #endif
#if defined(TCCR2A) && defined(COM2A1) #if ABTEST(2)
PWM_CASE(2, A); PWM_CASE(2, A);
PWM_CASE(2, B); PWM_CASE(2, B);
#endif #endif
#if defined(TCCR3A) && defined(COM3A1) #if ABTEST(3)
PWM_CASE(3, A); PWM_CASE(3, A);
PWM_CASE(3, B); PWM_CASE(3, B);
#ifdef COM3C1 #ifdef COM3C1
@ -146,7 +149,7 @@ static bool pwm_status(uint8_t pin) {
PWM_CASE(4, C); PWM_CASE(4, C);
#endif #endif
#if defined(TCCR5A) && defined(COM5A1) #if ABTEST(5)
PWM_CASE(5, A); PWM_CASE(5, A);
PWM_CASE(5, B); PWM_CASE(5, B);
PWM_CASE(5, C); PWM_CASE(5, C);
@ -163,16 +166,16 @@ static bool pwm_status(uint8_t pin) {
const volatile uint8_t* const PWM_other[][3] PROGMEM = { const volatile uint8_t* const PWM_other[][3] PROGMEM = {
{ &TCCR0A, &TCCR0B, &TIMSK0 }, { &TCCR0A, &TCCR0B, &TIMSK0 },
{ &TCCR1A, &TCCR1B, &TIMSK1 }, { &TCCR1A, &TCCR1B, &TIMSK1 },
#if defined(TCCR2A) && defined(COM2A1) #if ABTEST(2)
{ &TCCR2A, &TCCR2B, &TIMSK2 }, { &TCCR2A, &TCCR2B, &TIMSK2 },
#endif #endif
#if defined(TCCR3A) && defined(COM3A1) #if ABTEST(3)
{ &TCCR3A, &TCCR3B, &TIMSK3 }, { &TCCR3A, &TCCR3B, &TIMSK3 },
#endif #endif
#ifdef TCCR4A #ifdef TCCR4A
{ &TCCR4A, &TCCR4B, &TIMSK4 }, { &TCCR4A, &TCCR4B, &TIMSK4 },
#endif #endif
#if defined(TCCR5A) && defined(COM5A1) #if ABTEST(5)
{ &TCCR5A, &TCCR5B, &TIMSK5 }, { &TCCR5A, &TCCR5B, &TIMSK5 },
#endif #endif
}; };
@ -192,11 +195,11 @@ const volatile uint8_t* const PWM_OCR[][3] PROGMEM = {
{ (const uint8_t*)&OCR1A, (const uint8_t*)&OCR1B, 0 }, { (const uint8_t*)&OCR1A, (const uint8_t*)&OCR1B, 0 },
#endif #endif
#if defined(TCCR2A) && defined(COM2A1) #if ABTEST(2)
{ &OCR2A, &OCR2B, 0 }, { &OCR2A, &OCR2B, 0 },
#endif #endif
#if defined(TCCR3A) && defined(COM3A1) #if ABTEST(3)
#ifdef COM3C1 #ifdef COM3C1
{ (const uint8_t*)&OCR3A, (const uint8_t*)&OCR3B, (const uint8_t*)&OCR3C }, { (const uint8_t*)&OCR3A, (const uint8_t*)&OCR3B, (const uint8_t*)&OCR3C },
#else #else
@ -208,7 +211,7 @@ const volatile uint8_t* const PWM_OCR[][3] PROGMEM = {
{ (const uint8_t*)&OCR4A, (const uint8_t*)&OCR4B, (const uint8_t*)&OCR4C }, { (const uint8_t*)&OCR4A, (const uint8_t*)&OCR4B, (const uint8_t*)&OCR4C },
#endif #endif
#if defined(TCCR5A) && defined(COM5A1) #if ABTEST(5)
{ (const uint8_t*)&OCR5A, (const uint8_t*)&OCR5B, (const uint8_t*)&OCR5C }, { (const uint8_t*)&OCR5A, (const uint8_t*)&OCR5B, (const uint8_t*)&OCR5C },
#endif #endif
}; };
@ -235,9 +238,9 @@ static void print_is_also_tied() { SERIAL_ECHOPGM(" is also tied to this pin");
inline void com_print(const uint8_t N, const uint8_t Z) { inline void com_print(const uint8_t N, const uint8_t Z) {
const uint8_t *TCCRA = (uint8_t*)TCCR_A(N); const uint8_t *TCCRA = (uint8_t*)TCCR_A(N);
SERIAL_ECHOPGM(" COM"); SERIAL_ECHOPGM(" COM", AS_DIGIT(N));
SERIAL_CHAR('0' + N, Z); SERIAL_CHAR(Z);
SERIAL_ECHOPAIR(": ", int((*TCCRA >> (6 - Z * 2)) & 0x03)); SERIAL_ECHOPGM(": ", int((*TCCRA >> (6 - Z * 2)) & 0x03));
} }
void timer_prefix(uint8_t T, char L, uint8_t N) { // T - timer L - pwm N - WGM bit layout void timer_prefix(uint8_t T, char L, uint8_t N) { // T - timer L - pwm N - WGM bit layout
@ -247,8 +250,8 @@ void timer_prefix(uint8_t T, char L, uint8_t N) { // T - timer L - pwm N -
uint8_t WGM = (((*TCCRB & _BV(WGM_2)) >> 1) | (*TCCRA & (_BV(WGM_0) | _BV(WGM_1)))); uint8_t WGM = (((*TCCRB & _BV(WGM_2)) >> 1) | (*TCCRA & (_BV(WGM_0) | _BV(WGM_1))));
if (N == 4) WGM |= ((*TCCRB & _BV(WGM_3)) >> 1); if (N == 4) WGM |= ((*TCCRB & _BV(WGM_3)) >> 1);
SERIAL_ECHOPGM(" TIMER"); SERIAL_ECHOPGM(" TIMER", AS_DIGIT(T));
SERIAL_CHAR(T + '0', L); SERIAL_CHAR(L);
SERIAL_ECHO_SP(3); SERIAL_ECHO_SP(3);
if (N == 3) { if (N == 3) {
@ -259,22 +262,14 @@ void timer_prefix(uint8_t T, char L, uint8_t N) { // T - timer L - pwm N -
const uint16_t *OCRVAL16 = (uint16_t*)OCR_VAL(T, L - 'A'); const uint16_t *OCRVAL16 = (uint16_t*)OCR_VAL(T, L - 'A');
PWM_PRINT(*OCRVAL16); PWM_PRINT(*OCRVAL16);
} }
SERIAL_ECHOPAIR(" WGM: ", WGM); SERIAL_ECHOPGM(" WGM: ", WGM);
com_print(T,L); com_print(T,L);
SERIAL_ECHOPAIR(" CS: ", (*TCCRB & (_BV(CS_0) | _BV(CS_1) | _BV(CS_2)) )); SERIAL_ECHOPGM(" CS: ", (*TCCRB & (_BV(CS_0) | _BV(CS_1) | _BV(CS_2)) ));
SERIAL_ECHOPGM(" TCCR", AS_DIGIT(T), "A: ", *TCCRA);
SERIAL_ECHOPGM(" TCCR"); SERIAL_ECHOPGM(" TCCR", AS_DIGIT(T), "B: ", *TCCRB);
SERIAL_CHAR(T + '0');
SERIAL_ECHOPAIR("A: ", *TCCRA);
SERIAL_ECHOPGM(" TCCR");
SERIAL_CHAR(T + '0');
SERIAL_ECHOPAIR("B: ", *TCCRB);
const uint8_t *TMSK = (uint8_t*)TIMSK(T); const uint8_t *TMSK = (uint8_t*)TIMSK(T);
SERIAL_ECHOPGM(" TIMSK"); SERIAL_ECHOPGM(" TIMSK", AS_DIGIT(T), ": ", *TMSK);
SERIAL_CHAR(T + '0');
SERIAL_ECHOPAIR(": ", *TMSK);
const uint8_t OCIE = L - 'A' + 1; const uint8_t OCIE = L - 'A' + 1;
if (N == 3) { if (WGM == 0 || WGM == 2 || WGM == 4 || WGM == 6) err_is_counter(); } if (N == 3) { if (WGM == 0 || WGM == 2 || WGM == 4 || WGM == 6) err_is_counter(); }
@ -286,7 +281,7 @@ void timer_prefix(uint8_t T, char L, uint8_t N) { // T - timer L - pwm N -
static void pwm_details(uint8_t pin) { static void pwm_details(uint8_t pin) {
switch (digitalPinToTimer_DEBUG(pin)) { switch (digitalPinToTimer_DEBUG(pin)) {
#if defined(TCCR0A) && defined(COM0A1) #if ABTEST(0)
#ifdef TIMER0A #ifdef TIMER0A
#if !AVR_AT90USB1286_FAMILY // not available in Teensyduino type IDEs #if !AVR_AT90USB1286_FAMILY // not available in Teensyduino type IDEs
case TIMER0A: timer_prefix(0, 'A', 3); break; case TIMER0A: timer_prefix(0, 'A', 3); break;
@ -295,7 +290,7 @@ static void pwm_details(uint8_t pin) {
case TIMER0B: timer_prefix(0, 'B', 3); break; case TIMER0B: timer_prefix(0, 'B', 3); break;
#endif #endif
#if defined(TCCR1A) && defined(COM1A1) #if ABTEST(1)
case TIMER1A: timer_prefix(1, 'A', 4); break; case TIMER1A: timer_prefix(1, 'A', 4); break;
case TIMER1B: timer_prefix(1, 'B', 4); break; case TIMER1B: timer_prefix(1, 'B', 4); break;
#if defined(COM1C1) && defined(TIMER1C) #if defined(COM1C1) && defined(TIMER1C)
@ -303,12 +298,12 @@ static void pwm_details(uint8_t pin) {
#endif #endif
#endif #endif
#if defined(TCCR2A) && defined(COM2A1) #if ABTEST(2)
case TIMER2A: timer_prefix(2, 'A', 3); break; case TIMER2A: timer_prefix(2, 'A', 3); break;
case TIMER2B: timer_prefix(2, 'B', 3); break; case TIMER2B: timer_prefix(2, 'B', 3); break;
#endif #endif
#if defined(TCCR3A) && defined(COM3A1) #if ABTEST(3)
case TIMER3A: timer_prefix(3, 'A', 4); break; case TIMER3A: timer_prefix(3, 'A', 4); break;
case TIMER3B: timer_prefix(3, 'B', 4); break; case TIMER3B: timer_prefix(3, 'B', 4); break;
#ifdef COM3C1 #ifdef COM3C1
@ -322,7 +317,7 @@ static void pwm_details(uint8_t pin) {
case TIMER4C: timer_prefix(4, 'C', 4); break; case TIMER4C: timer_prefix(4, 'C', 4); break;
#endif #endif
#if defined(TCCR5A) && defined(COM5A1) #if ABTEST(5)
case TIMER5A: timer_prefix(5, 'A', 4); break; case TIMER5A: timer_prefix(5, 'A', 4); break;
case TIMER5B: timer_prefix(5, 'B', 4); break; case TIMER5B: timer_prefix(5, 'B', 4); break;
case TIMER5C: timer_prefix(5, 'C', 4); break; case TIMER5C: timer_prefix(5, 'C', 4); break;
@ -356,7 +351,6 @@ static void pwm_details(uint8_t pin) {
#endif #endif
} // pwm_details } // pwm_details
#ifndef digitalRead_mod // Use Teensyduino's version of digitalRead - it doesn't disable the PWMs #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 int8_t pin) { // same as digitalRead except the PWM stop section has been removed
const uint8_t port = digitalPinToPort_DEBUG(pin); const uint8_t port = digitalPinToPort_DEBUG(pin);
@ -401,3 +395,6 @@ static void pwm_details(uint8_t pin) {
#endif #endif
#define PRINT_PIN(p) do{ sprintf_P(buffer, PSTR("%3d "), p); 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)
#undef ABTEST

View File

@ -2,6 +2,9 @@
* Marlin 3D Printer Firmware * Marlin 3D Printer Firmware
* Copyright (c) 2020 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] * 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 * 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 * it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or * the Free Software Foundation, either version 3 of the License, or

View File

@ -2,6 +2,9 @@
* Marlin 3D Printer Firmware * Marlin 3D Printer Firmware
* Copyright (c) 2020 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] * 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 * 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 * it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or * the Free Software Foundation, either version 3 of the License, or

View File

@ -51,15 +51,15 @@
#define AVR_SS_PIN 16 #define AVR_SS_PIN 16
#endif #endif
#ifndef SCK_PIN #ifndef SD_SCK_PIN
#define SCK_PIN AVR_SCK_PIN #define SD_SCK_PIN AVR_SCK_PIN
#endif #endif
#ifndef MISO_PIN #ifndef SD_MISO_PIN
#define MISO_PIN AVR_MISO_PIN #define SD_MISO_PIN AVR_MISO_PIN
#endif #endif
#ifndef MOSI_PIN #ifndef SD_MOSI_PIN
#define MOSI_PIN AVR_MOSI_PIN #define SD_MOSI_PIN AVR_MOSI_PIN
#endif #endif
#ifndef SS_PIN #ifndef SD_SS_PIN
#define SS_PIN AVR_SS_PIN #define SD_SS_PIN AVR_SS_PIN
#endif #endif

View File

@ -34,14 +34,14 @@ typedef uint16_t hal_timer_t;
#define HAL_TIMER_RATE ((F_CPU) / 8) // i.e., 2MHz or 2.5MHz #define HAL_TIMER_RATE ((F_CPU) / 8) // i.e., 2MHz or 2.5MHz
#ifndef STEP_TIMER_NUM #ifndef MF_TIMER_STEP
#define STEP_TIMER_NUM 1 #define MF_TIMER_STEP 1
#endif #endif
#ifndef PULSE_TIMER_NUM #ifndef MF_TIMER_PULSE
#define PULSE_TIMER_NUM STEP_TIMER_NUM #define MF_TIMER_PULSE MF_TIMER_STEP
#endif #endif
#ifndef TEMP_TIMER_NUM #ifndef MF_TIMER_TEMP
#define TEMP_TIMER_NUM 0 #define MF_TIMER_TEMP 0
#endif #endif
#define TEMP_TIMER_FREQUENCY ((F_CPU) / 64.0 / 256.0) #define TEMP_TIMER_FREQUENCY ((F_CPU) / 64.0 / 256.0)
@ -58,13 +58,13 @@ typedef uint16_t hal_timer_t;
#define DISABLE_STEPPER_DRIVER_INTERRUPT() CBI(TIMSK1, OCIE1A) #define DISABLE_STEPPER_DRIVER_INTERRUPT() CBI(TIMSK1, OCIE1A)
#define STEPPER_ISR_ENABLED() TEST(TIMSK1, OCIE1A) #define STEPPER_ISR_ENABLED() TEST(TIMSK1, OCIE1A)
#define ENABLE_TEMPERATURE_INTERRUPT() SBI(TIMSK0, OCIE0B) #define ENABLE_TEMPERATURE_INTERRUPT() SBI(TIMSK0, OCIE0A)
#define DISABLE_TEMPERATURE_INTERRUPT() CBI(TIMSK0, OCIE0B) #define DISABLE_TEMPERATURE_INTERRUPT() CBI(TIMSK0, OCIE0A)
#define TEMPERATURE_ISR_ENABLED() TEST(TIMSK0, OCIE0B) #define TEMPERATURE_ISR_ENABLED() TEST(TIMSK0, OCIE0A)
FORCE_INLINE void HAL_timer_start(const uint8_t timer_num, const uint32_t) { FORCE_INLINE void HAL_timer_start(const uint8_t timer_num, const uint32_t) {
switch (timer_num) { switch (timer_num) {
case STEP_TIMER_NUM: case MF_TIMER_STEP:
// waveform generation = 0100 = CTC // waveform generation = 0100 = CTC
SET_WGM(1, CTC_OCRnA); SET_WGM(1, CTC_OCRnA);
@ -84,10 +84,10 @@ FORCE_INLINE void HAL_timer_start(const uint8_t timer_num, const uint32_t) {
TCNT1 = 0; TCNT1 = 0;
break; break;
case TEMP_TIMER_NUM: case MF_TIMER_TEMP:
// Use timer0 for temperature measurement // Use timer0 for temperature measurement
// Interleave temperature interrupt with millies interrupt // Interleave temperature interrupt with millies interrupt
OCR0B = 128; OCR0A = 128;
break; break;
} }
} }
@ -109,12 +109,12 @@ FORCE_INLINE void HAL_timer_start(const uint8_t timer_num, const uint32_t) {
* (otherwise, characters will be lost due to UART overflow). * (otherwise, characters will be lost due to UART overflow).
* Then: Stepper, Endstops, Temperature, and -finally- all others. * Then: Stepper, Endstops, Temperature, and -finally- all others.
*/ */
#define HAL_timer_isr_prologue(TIMER_NUM) #define HAL_timer_isr_prologue(T) NOOP
#define HAL_timer_isr_epilogue(TIMER_NUM) #define HAL_timer_isr_epilogue(T) NOOP
/* 18 cycles maximum latency */
#ifndef HAL_STEP_TIMER_ISR #ifndef HAL_STEP_TIMER_ISR
/* 18 cycles maximum latency */
#define HAL_STEP_TIMER_ISR() \ #define HAL_STEP_TIMER_ISR() \
extern "C" void TIMER1_COMPA_vect() __attribute__ ((signal, naked, used, externally_visible)); \ extern "C" void TIMER1_COMPA_vect() __attribute__ ((signal, naked, used, externally_visible)); \
extern "C" void TIMER1_COMPA_vect_bottom() asm ("TIMER1_COMPA_vect_bottom") __attribute__ ((used, externally_visible, noinline)); \ extern "C" void TIMER1_COMPA_vect_bottom() asm ("TIMER1_COMPA_vect_bottom") __attribute__ ((used, externally_visible, noinline)); \
@ -180,7 +180,7 @@ void TIMER1_COMPA_vect() { \
: \ : \
: [timsk0] "i" ((uint16_t)&TIMSK0), \ : [timsk0] "i" ((uint16_t)&TIMSK0), \
[timsk1] "i" ((uint16_t)&TIMSK1), \ [timsk1] "i" ((uint16_t)&TIMSK1), \
[msk0] "M" ((uint8_t)(1<<OCIE0B)),\ [msk0] "M" ((uint8_t)(1<<OCIE0A)),\
[msk1] "M" ((uint8_t)(1<<OCIE1A)) \ [msk1] "M" ((uint8_t)(1<<OCIE1A)) \
: \ : \
); \ ); \
@ -193,9 +193,9 @@ void TIMER1_COMPA_vect_bottom()
/* 14 cycles maximum latency */ /* 14 cycles maximum latency */
#define HAL_TEMP_TIMER_ISR() \ #define HAL_TEMP_TIMER_ISR() \
extern "C" void TIMER0_COMPB_vect() __attribute__ ((signal, naked, used, externally_visible)); \ extern "C" void TIMER0_COMPA_vect() __attribute__ ((signal, naked, used, externally_visible)); \
extern "C" void TIMER0_COMPB_vect_bottom() asm ("TIMER0_COMPB_vect_bottom") __attribute__ ((used, externally_visible, noinline)); \ extern "C" void TIMER0_COMPA_vect_bottom() asm ("TIMER0_COMPA_vect_bottom") __attribute__ ((used, externally_visible, noinline)); \
void TIMER0_COMPB_vect() { \ void TIMER0_COMPA_vect() { \
__asm__ __volatile__ ( \ __asm__ __volatile__ ( \
A("push r16") /* 2 Save R16 */ \ A("push r16") /* 2 Save R16 */ \
A("in r16, __SREG__") /* 1 Get SREG */ \ A("in r16, __SREG__") /* 1 Get SREG */ \
@ -223,7 +223,7 @@ void TIMER0_COMPB_vect() { \
A("push r30") \ A("push r30") \
A("push r31") \ A("push r31") \
A("clr r1") /* C runtime expects this register to be 0 */ \ A("clr r1") /* C runtime expects this register to be 0 */ \
A("call TIMER0_COMPB_vect_bottom") /* Call the bottom handler - No inlining allowed, otherwise registers used are not saved */ \ A("call TIMER0_COMPA_vect_bottom") /* Call the bottom handler - No inlining allowed, otherwise registers used are not saved */ \
A("pop r31") \ A("pop r31") \
A("pop r30") \ A("pop r30") \
A("pop r27") \ A("pop r27") \
@ -251,10 +251,10 @@ void TIMER0_COMPB_vect() { \
A("reti") /* 4 Return from interrupt */ \ A("reti") /* 4 Return from interrupt */ \
: \ : \
: [timsk0] "i"((uint16_t)&TIMSK0), \ : [timsk0] "i"((uint16_t)&TIMSK0), \
[msk0] "M" ((uint8_t)(1<<OCIE0B)) \ [msk0] "M" ((uint8_t)(1<<OCIE0A)) \
: \ : \
); \ ); \
} \ } \
void TIMER0_COMPB_vect_bottom() void TIMER0_COMPA_vect_bottom()
#endif // HAL_TEMP_TIMER_ISR #endif // HAL_TEMP_TIMER_ISR

View File

@ -62,10 +62,10 @@
#include "../shared/Marduino.h" #include "../shared/Marduino.h"
#include "../shared/Delay.h" #include "../shared/Delay.h"
#include <U8glib.h> #include <U8glib-HAL.h>
uint8_t u8g_bitData, u8g_bitNotData, u8g_bitClock, u8g_bitNotClock; static uint8_t u8g_bitData, u8g_bitNotData, u8g_bitClock, u8g_bitNotClock;
volatile uint8_t *u8g_outData, *u8g_outClock; static volatile uint8_t *u8g_outData, *u8g_outClock;
static void u8g_com_arduino_init_shift_out(uint8_t dataPin, uint8_t clockPin) { static void u8g_com_arduino_init_shift_out(uint8_t dataPin, uint8_t clockPin) {
u8g_outData = portOutputRegister(digitalPinToPort(dataPin)); u8g_outData = portOutputRegister(digitalPinToPort(dataPin));

View File

@ -1,70 +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 <https://www.gnu.org/licenses/>.
*
*/
#ifdef __AVR__
#include "../../inc/MarlinConfig.h"
#if ENABLED(USE_WATCHDOG)
#include "watchdog.h"
#include "../../MarlinCore.h"
// Initialize watchdog with 8s timeout, if possible. Otherwise, make it 4s.
void watchdog_init() {
#if ENABLED(WATCHDOG_DURATION_8S) && defined(WDTO_8S)
#define WDTO_NS WDTO_8S
#else
#define WDTO_NS WDTO_4S
#endif
#if ENABLED(WATCHDOG_RESET_MANUAL)
// Enable the watchdog timer, but only for the interrupt.
// Take care, as this requires the correct order of operation, with interrupts disabled.
// See the datasheet of any AVR chip for details.
wdt_reset();
cli();
_WD_CONTROL_REG = _BV(_WD_CHANGE_BIT) | _BV(WDE);
_WD_CONTROL_REG = _BV(WDIE) | (WDTO_NS & 0x07) | ((WDTO_NS & 0x08) << 2); // WDTO_NS directly does not work. bit 0-2 are consecutive in the register but the highest value bit is at bit 5
// So worked for up to WDTO_2S
sei();
wdt_reset();
#else
wdt_enable(WDTO_NS); // The function handles the upper bit correct.
#endif
//delay(10000); // test it!
}
//===========================================================================
//=================================== ISR ===================================
//===========================================================================
// Watchdog timer interrupt, called if main program blocks >4sec and manual reset is enabled.
#if ENABLED(WATCHDOG_RESET_MANUAL)
ISR(WDT_vect) {
sei(); // With the interrupt driven serial we need to allow interrupts.
SERIAL_ERROR_MSG(STR_WATCHDOG_FIRED);
minkill(); // interrupt-safe final kill and infinite loop
}
#endif
#endif // USE_WATCHDOG
#endif // __AVR__

View File

@ -1,342 +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 <https://www.gnu.org/licenses/>.
*
*/
#ifdef ARDUINO_ARCH_SAM
#include "../../core/macros.h"
#include "../../core/serial.h"
#include "../shared/backtrace/unwinder.h"
#include "../shared/backtrace/unwmemaccess.h"
#include <stdarg.h>
// Debug monitor that dumps to the Programming port all status when
// an exception or WDT timeout happens - And then resets the board
// All the Monitor routines must run with interrupts disabled and
// under an ISR execution context. That is why we cannot reuse the
// Serial interrupt routines or any C runtime, as we don't know the
// state we are when running them
// A SW memory barrier, to ensure GCC does not overoptimize loops
#define sw_barrier() __asm__ volatile("": : :"memory");
// (re)initialize UART0 as a monitor output to 250000,n,8,1
static void TXBegin() {
// Disable UART interrupt in NVIC
NVIC_DisableIRQ( UART_IRQn );
// 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();
// Disable clock
pmc_disable_periph_clk( ID_UART );
// Configure PMC
pmc_enable_periph_clk( ID_UART );
// Disable PDC channel
UART->UART_PTCR = UART_PTCR_RXTDIS | UART_PTCR_TXTDIS;
// Reset and disable receiver and transmitter
UART->UART_CR = UART_CR_RSTRX | UART_CR_RSTTX | UART_CR_RXDIS | UART_CR_TXDIS;
// Configure mode: 8bit, No parity, 1 bit stop
UART->UART_MR = UART_MR_CHMODE_NORMAL | US_MR_CHRL_8_BIT | US_MR_NBSTOP_1_BIT | UART_MR_PAR_NO;
// Configure baudrate (asynchronous, no oversampling) to BAUDRATE bauds
UART->UART_BRGR = (SystemCoreClock / (BAUDRATE << 4));
// Enable receiver and transmitter
UART->UART_CR = UART_CR_RXEN | UART_CR_TXEN;
}
// Send character through UART with no interrupts
static void TX(char c) {
while (!(UART->UART_SR & UART_SR_TXRDY)) { WDT_Restart(WDT); sw_barrier(); };
UART->UART_THR = c;
}
// Send String through UART
static void TX(const char* s) {
while (*s) TX(*s++);
}
static void TXDigit(uint32_t d) {
if (d < 10) TX((char)(d+'0'));
else if (d < 16) TX((char)(d+'A'-10));
else TX('?');
}
// Send Hex number thru UART
static void TXHex(uint32_t v) {
TX("0x");
for (uint8_t i = 0; i < 8; i++, v <<= 4)
TXDigit((v >> 28) & 0xF);
}
// Send Decimal number thru UART
static void TXDec(uint32_t v) {
if (!v) {
TX('0');
return;
}
char nbrs[14];
char *p = &nbrs[0];
while (v != 0) {
*p++ = '0' + (v % 10);
v /= 10;
}
do {
p--;
TX(*p);
} while (p != &nbrs[0]);
}
// Dump a backtrace entry
static bool UnwReportOut(void* ctx, const UnwReport* bte) {
int* p = (int*)ctx;
(*p)++;
TX('#'); TXDec(*p); TX(" : ");
TX(bte->name?bte->name:"unknown"); TX('@'); TXHex(bte->function);
TX('+'); TXDec(bte->address - bte->function);
TX(" PC:");TXHex(bte->address); TX('\n');
return true;
}
#ifdef UNW_DEBUG
void UnwPrintf(const char* format, ...) {
char dest[256];
va_list argptr;
va_start(argptr, format);
vsprintf(dest, format, argptr);
va_end(argptr);
TX(&dest[0]);
}
#endif
/* Table of function pointers for passing to the unwinder */
static const UnwindCallbacks UnwCallbacks = {
UnwReportOut,
UnwReadW,
UnwReadH,
UnwReadB
#ifdef UNW_DEBUG
, UnwPrintf
#endif
};
/**
* HardFaultHandler_C:
* This is called from the HardFault_HandlerAsm with a pointer the Fault stack
* as the parameter. We can then read the values from the stack and place them
* into local variables for ease of reading.
* We then read the various Fault Status and Address Registers to help decode
* cause of the fault.
* The function ends with a BKPT instruction to force control back into the debugger
*/
extern "C"
void HardFault_HandlerC(unsigned long *sp, unsigned long lr, unsigned long cause) {
static const char* causestr[] = {
"NMI","Hard","Mem","Bus","Usage","Debug","WDT","RSTC"
};
UnwindFrame btf;
// Dump report to the Programming port (interrupts are DISABLED)
TXBegin();
TX("\n\n## Software Fault detected ##\n");
TX("Cause: "); TX(causestr[cause]); TX('\n');
TX("R0 : "); TXHex(((unsigned long)sp[0])); TX('\n');
TX("R1 : "); TXHex(((unsigned long)sp[1])); TX('\n');
TX("R2 : "); TXHex(((unsigned long)sp[2])); TX('\n');
TX("R3 : "); TXHex(((unsigned long)sp[3])); TX('\n');
TX("R12 : "); TXHex(((unsigned long)sp[4])); TX('\n');
TX("LR : "); TXHex(((unsigned long)sp[5])); TX('\n');
TX("PC : "); TXHex(((unsigned long)sp[6])); TX('\n');
TX("PSR : "); TXHex(((unsigned long)sp[7])); TX('\n');
// Configurable Fault Status Register
// Consists of MMSR, BFSR and UFSR
TX("CFSR : "); TXHex((*((volatile unsigned long *)(0xE000ED28)))); TX('\n');
// Hard Fault Status Register
TX("HFSR : "); TXHex((*((volatile unsigned long *)(0xE000ED2C)))); TX('\n');
// Debug Fault Status Register
TX("DFSR : "); TXHex((*((volatile unsigned long *)(0xE000ED30)))); TX('\n');
// Auxiliary Fault Status Register
TX("AFSR : "); TXHex((*((volatile unsigned long *)(0xE000ED3C)))); TX('\n');
// Read the Fault Address Registers. These may not contain valid values.
// Check BFARVALID/MMARVALID to see if they are valid values
// MemManage Fault Address Register
TX("MMAR : "); TXHex((*((volatile unsigned long *)(0xE000ED34)))); TX('\n');
// Bus Fault Address Register
TX("BFAR : "); TXHex((*((volatile unsigned long *)(0xE000ED38)))); TX('\n');
TX("ExcLR: "); TXHex(lr); TX('\n');
TX("ExcSP: "); TXHex((unsigned long)sp); TX('\n');
btf.sp = ((unsigned long)sp) + 8*4; // The original stack pointer
btf.fp = btf.sp;
btf.lr = ((unsigned long)sp[5]);
btf.pc = ((unsigned long)sp[6]) | 1; // Force Thumb, as CORTEX only support it
// Perform a backtrace
TX("\nBacktrace:\n\n");
int ctr = 0;
UnwindStart(&btf, &UnwCallbacks, &ctr);
// Disable all NVIC interrupts
NVIC->ICER[0] = 0xFFFFFFFF;
NVIC->ICER[1] = 0xFFFFFFFF;
// Relocate VTOR table to default position
SCB->VTOR = 0;
// Disable USB
otg_disable();
// Restart watchdog
WDT_Restart(WDT);
// Reset controller
NVIC_SystemReset();
for (;;) WDT_Restart(WDT);
}
__attribute__((naked)) void NMI_Handler() {
__asm__ __volatile__ (
".syntax unified" "\n\t"
A("tst lr, #4")
A("ite eq")
A("mrseq r0, msp")
A("mrsne r0, psp")
A("mov r1,lr")
A("mov r2,#0")
A("b HardFault_HandlerC")
);
}
__attribute__((naked)) void HardFault_Handler() {
__asm__ __volatile__ (
".syntax unified" "\n\t"
A("tst lr, #4")
A("ite eq")
A("mrseq r0, msp")
A("mrsne r0, psp")
A("mov r1,lr")
A("mov r2,#1")
A("b HardFault_HandlerC")
);
}
__attribute__((naked)) void MemManage_Handler() {
__asm__ __volatile__ (
".syntax unified" "\n\t"
A("tst lr, #4")
A("ite eq")
A("mrseq r0, msp")
A("mrsne r0, psp")
A("mov r1,lr")
A("mov r2,#2")
A("b HardFault_HandlerC")
);
}
__attribute__((naked)) void BusFault_Handler() {
__asm__ __volatile__ (
".syntax unified" "\n\t"
A("tst lr, #4")
A("ite eq")
A("mrseq r0, msp")
A("mrsne r0, psp")
A("mov r1,lr")
A("mov r2,#3")
A("b HardFault_HandlerC")
);
}
__attribute__((naked)) void UsageFault_Handler() {
__asm__ __volatile__ (
".syntax unified" "\n\t"
A("tst lr, #4")
A("ite eq")
A("mrseq r0, msp")
A("mrsne r0, psp")
A("mov r1,lr")
A("mov r2,#4")
A("b HardFault_HandlerC")
);
}
__attribute__((naked)) void DebugMon_Handler() {
__asm__ __volatile__ (
".syntax unified" "\n\t"
A("tst lr, #4")
A("ite eq")
A("mrseq r0, msp")
A("mrsne r0, psp")
A("mov r1,lr")
A("mov r2,#5")
A("b HardFault_HandlerC")
);
}
/* This is NOT an exception, it is an interrupt handler - Nevertheless, the framing is the same */
__attribute__((naked)) void WDT_Handler() {
__asm__ __volatile__ (
".syntax unified" "\n\t"
A("tst lr, #4")
A("ite eq")
A("mrseq r0, msp")
A("mrsne r0, psp")
A("mov r1,lr")
A("mov r2,#6")
A("b HardFault_HandlerC")
);
}
__attribute__((naked)) void RSTC_Handler() {
__asm__ __volatile__ (
".syntax unified" "\n\t"
A("tst lr, #4")
A("ite eq")
A("mrseq r0, msp")
A("mrsne r0, psp")
A("mov r1,lr")
A("mov r2,#7")
A("b HardFault_HandlerC")
);
}
#endif // ARDUINO_ARCH_SAM

View File

@ -25,7 +25,7 @@
#ifdef ARDUINO_ARCH_SAM #ifdef ARDUINO_ARCH_SAM
#include "../../inc/MarlinConfig.h" #include "../../inc/MarlinConfig.h"
#include "HAL.h" #include "../../MarlinCore.h"
#include <Wire.h> #include <Wire.h>
#include "usb/usb_task.h" #include "usb/usb_task.h"
@ -34,36 +34,33 @@
// Public Variables // Public Variables
// ------------------------ // ------------------------
uint16_t HAL_adc_result; uint16_t MarlinHAL::adc_result;
// ------------------------ // ------------------------
// Public functions // Public functions
// ------------------------ // ------------------------
// HAL initialization task #if ENABLED(POSTMORTEM_DEBUGGING)
void HAL_init() { extern void install_min_serial();
// Initialize the USB stack #endif
void MarlinHAL::init() {
#if ENABLED(SDSUPPORT) #if ENABLED(SDSUPPORT)
OUT_WRITE(SDSS, HIGH); // Try to set SDSS inactive before any other SPI users start up OUT_WRITE(SDSS, HIGH); // Try to set SDSS inactive before any other SPI users start up
#endif #endif
usb_task_init(); usb_task_init(); // Initialize the USB stack
TERN_(POSTMORTEM_DEBUGGING, install_min_serial()); // Install the min serial handler
} }
// HAL idle task void MarlinHAL::init_board() {
void HAL_idletask() { #ifdef BOARD_INIT
// Perform USB stack housekeeping BOARD_INIT();
usb_task_idle(); #endif
} }
// Disable interrupts void MarlinHAL::idletask() { usb_task_idle(); } // Perform USB stack housekeeping
void cli() { noInterrupts(); }
// Enable interrupts uint8_t MarlinHAL::get_reset_source() {
void sei() { interrupts(); }
void HAL_clear_reset_source() { }
uint8_t HAL_get_reset_source() {
switch ((RSTC->RSTC_SR >> 8) & 0x07) { switch ((RSTC->RSTC_SR >> 8) & 0x07) {
case 0: return RST_POWER_ON; case 0: return RST_POWER_ON;
case 1: return RST_BACKUP; case 1: return RST_BACKUP;
@ -74,11 +71,105 @@ uint8_t HAL_get_reset_source() {
} }
} }
void _delay_ms(const int delay_ms) { void MarlinHAL::reboot() { rstc_start_software_reset(RSTC); }
// Todo: port for Due?
delay(delay_ms); // ------------------------
// Watchdog Timer
// ------------------------
#if ENABLED(USE_WATCHDOG)
// Initialize watchdog - On SAM3X, Watchdog was already configured
// and enabled or disabled at startup, so no need to reconfigure it
// here.
void MarlinHAL::watchdog_init() { WDT_Restart(WDT); } // Reset watchdog to start clean
// Reset watchdog. MUST be called at least every 4 seconds after the
// first watchdog_init or AVR will go into emergency procedures.
void MarlinHAL::watchdog_refresh() { watchdogReset(); }
#endif
// Override Arduino runtime to either config or disable the watchdog
//
// We need to configure the watchdog as soon as possible in the boot
// process, because watchdog initialization at hardware reset on SAM3X8E
// is unreliable, and there is risk of unintended resets if we delay
// that initialization to a later time.
void watchdogSetup() {
#if ENABLED(USE_WATCHDOG)
// 4 seconds timeout
uint32_t timeout = TERN(WATCHDOG_DURATION_8S, 8000, 4000);
// Calculate timeout value in WDT counter ticks: This assumes
// the slow clock is running at 32.768 kHz watchdog
// frequency is therefore 32768 / 128 = 256 Hz
timeout = (timeout << 8) / 1000;
if (timeout == 0)
timeout = 1;
else if (timeout > 0xFFF)
timeout = 0xFFF;
// We want to enable the watchdog with the specified timeout
uint32_t value =
WDT_MR_WDV(timeout) | // With the specified timeout
WDT_MR_WDD(timeout) | // and no invalid write window
#if !(SAMV70 || SAMV71 || SAME70 || SAMS70)
WDT_MR_WDRPROC | // WDT fault resets processor only - We want
// to keep PIO controller state
#endif
WDT_MR_WDDBGHLT | // WDT stops in debug state.
WDT_MR_WDIDLEHLT; // WDT stops in idle state.
#if ENABLED(WATCHDOG_RESET_MANUAL)
// We enable the watchdog timer, but only for the interrupt.
// Configure WDT to only trigger an interrupt
value |= WDT_MR_WDFIEN; // Enable WDT fault interrupt.
// Disable WDT interrupt (just in case, to avoid triggering it!)
NVIC_DisableIRQ(WDT_IRQn);
// 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();
// Initialize WDT with the given parameters
WDT_Enable(WDT, value);
// Configure and enable WDT interrupt.
NVIC_ClearPendingIRQ(WDT_IRQn);
NVIC_SetPriority(WDT_IRQn, 0); // Use highest priority, so we detect all kinds of lockups
NVIC_EnableIRQ(WDT_IRQn);
#else
// a WDT fault triggers a reset
value |= WDT_MR_WDRSTEN;
// Initialize WDT with the given parameters
WDT_Enable(WDT, value);
#endif
// Reset the watchdog
WDT_Restart(WDT);
#else
// Make sure to completely disable the Watchdog
WDT_Disable(WDT);
#endif
} }
// ------------------------
// Free Memory Accessor
// ------------------------
extern "C" { extern "C" {
extern unsigned int _ebss; // end of bss section extern unsigned int _ebss; // end of bss section
} }
@ -90,16 +181,21 @@ int freeMemory() {
} }
// ------------------------ // ------------------------
// ADC // Serial Ports
// ------------------------ // ------------------------
void HAL_adc_start_conversion(const uint8_t ch) { // Forward the default serial ports
HAL_adc_result = analogRead(ch); #if USING_HW_SERIAL0
} DefaultSerial1 MSerial0(false, Serial);
#endif
uint16_t HAL_adc_get_result() { #if USING_HW_SERIAL1
// nop DefaultSerial2 MSerial1(false, Serial1);
return HAL_adc_result; #endif
} #if USING_HW_SERIAL2
DefaultSerial3 MSerial2(false, Serial2);
#endif
#if USING_HW_SERIAL3
DefaultSerial4 MSerial3(false, Serial3);
#endif
#endif // ARDUINO_ARCH_SAM #endif // ARDUINO_ARCH_SAM

View File

@ -32,105 +32,106 @@
#include "../shared/math_32bit.h" #include "../shared/math_32bit.h"
#include "../shared/HAL_SPI.h" #include "../shared/HAL_SPI.h"
#include "fastio.h" #include "fastio.h"
#include "watchdog.h"
#include <stdint.h> #include <stdint.h>
#define _MSERIAL(X) Serial##X #include "../../core/serial_hook.h"
#define MSERIAL(X) _MSERIAL(X)
#define Serial0 Serial // ------------------------
// Serial ports
// ------------------------
typedef ForwardSerial1Class< decltype(Serial) > DefaultSerial1;
typedef ForwardSerial1Class< decltype(Serial1) > DefaultSerial2;
typedef ForwardSerial1Class< decltype(Serial2) > DefaultSerial3;
typedef ForwardSerial1Class< decltype(Serial3) > DefaultSerial4;
extern DefaultSerial1 MSerial0;
extern DefaultSerial2 MSerial1;
extern DefaultSerial3 MSerial2;
extern DefaultSerial4 MSerial3;
#define _MSERIAL(X) MSerial##X
#define MSERIAL(X) _MSERIAL(X)
// Define MYSERIAL0/1 before MarlinSerial includes!
#if SERIAL_PORT == -1 || ENABLED(EMERGENCY_PARSER) #if SERIAL_PORT == -1 || ENABLED(EMERGENCY_PARSER)
#define MYSERIAL0 customizedSerial1 #define MYSERIAL1 customizedSerial1
#elif WITHIN(SERIAL_PORT, 0, 3) #elif WITHIN(SERIAL_PORT, 0, 3)
#define MYSERIAL0 MSERIAL(SERIAL_PORT) #define MYSERIAL1 MSERIAL(SERIAL_PORT)
#else #else
#error "The required SERIAL_PORT must be from -1 to 3. Please update your configuration." #error "The required SERIAL_PORT must be from 0 to 3, or -1 for USB Serial."
#endif #endif
#ifdef SERIAL_PORT_2 #ifdef SERIAL_PORT_2
#if SERIAL_PORT_2 == -1 || ENABLED(EMERGENCY_PARSER) #if SERIAL_PORT_2 == -1 || ENABLED(EMERGENCY_PARSER)
#define MYSERIAL1 customizedSerial2 #define MYSERIAL2 customizedSerial2
#elif WITHIN(SERIAL_PORT_2, 0, 3) #elif WITHIN(SERIAL_PORT_2, 0, 3)
#define MYSERIAL1 MSERIAL(SERIAL_PORT_2) #define MYSERIAL2 MSERIAL(SERIAL_PORT_2)
#else #else
#error "SERIAL_PORT_2 must be from -1 to 3. Please update your configuration." #error "SERIAL_PORT_2 must be from 0 to 3, or -1 for USB Serial."
#endif
#endif
#ifdef SERIAL_PORT_3
#if SERIAL_PORT_3 == -1 || ENABLED(EMERGENCY_PARSER)
#define MYSERIAL3 customizedSerial3
#elif WITHIN(SERIAL_PORT_3, 0, 3)
#define MYSERIAL3 MSERIAL(SERIAL_PORT_3)
#else
#error "SERIAL_PORT_3 must be from 0 to 3, or -1 for USB Serial."
#endif
#endif
#ifdef MMU2_SERIAL_PORT
#if WITHIN(MMU2_SERIAL_PORT, 0, 3)
#define MMU2_SERIAL MSERIAL(MMU2_SERIAL_PORT)
#else
#error "MMU2_SERIAL_PORT must be from 0 to 3."
#endif #endif
#endif #endif
#ifdef LCD_SERIAL_PORT #ifdef LCD_SERIAL_PORT
#if LCD_SERIAL_PORT == -1 #if WITHIN(LCD_SERIAL_PORT, 0, 3)
#define LCD_SERIAL lcdSerial
#elif WITHIN(LCD_SERIAL_PORT, 0, 3)
#define LCD_SERIAL MSERIAL(LCD_SERIAL_PORT) #define LCD_SERIAL MSERIAL(LCD_SERIAL_PORT)
#else #else
#error "LCD_SERIAL_PORT must be from -1 to 3. Please update your configuration." #error "LCD_SERIAL_PORT must be from 0 to 3."
#endif #endif
#endif #endif
#include "MarlinSerial.h" #include "MarlinSerial.h"
#include "MarlinSerialUSB.h" #include "MarlinSerialUSB.h"
// On AVR this is in math.h? // ------------------------
#define square(x) ((x)*(x)) // Types
// ------------------------
#ifndef strncpy_P
#define strncpy_P(dest, src, num) strncpy((dest), (src), (num))
#endif
// Fix bug in pgm_read_ptr
#undef pgm_read_ptr
#define pgm_read_ptr(addr) (*((void**)(addr)))
#undef pgm_read_word
#define pgm_read_word(addr) (*((uint16_t*)(addr)))
typedef int8_t pin_t; typedef int8_t pin_t;
#define SHARED_SERVOS HAS_SERVOS #define SHARED_SERVOS HAS_SERVOS // Use shared/servos.cpp
#define HAL_SERVO_LIB Servo
class Servo;
typedef Servo hal_servo_t;
// //
// Interrupts // Interrupts
// //
#define CRITICAL_SECTION_START() uint32_t primask = __get_PRIMASK(); __disable_irq() #define sei() interrupts()
#define CRITICAL_SECTION_END() if (!primask) __enable_irq() #define cli() noInterrupts()
#define ISRS_ENABLED() (!__get_PRIMASK())
#define ENABLE_ISRS() __enable_irq()
#define DISABLE_ISRS() __disable_irq()
void cli(); // Disable interrupts #define CRITICAL_SECTION_START() const bool _irqon = hal.isr_state(); hal.isr_off()
void sei(); // Enable interrupts #define CRITICAL_SECTION_END() if (_irqon) hal.isr_on()
void HAL_clear_reset_source(); // clear reset reason
uint8_t HAL_get_reset_source(); // get reset reason
inline void HAL_reboot() {} // reboot the board or restart the bootloader
// //
// ADC // ADC
// //
extern uint16_t HAL_adc_result; // result of last ADC conversion #define HAL_ADC_VREF 3.3
#define HAL_ADC_RESOLUTION 10
#ifndef analogInputToDigitalPin #ifndef analogInputToDigitalPin
#define analogInputToDigitalPin(p) ((p < 12U) ? (p) + 54U : -1) #define analogInputToDigitalPin(p) ((p < 12U) ? (p) + 54U : -1)
#endif #endif
#define HAL_ANALOG_SELECT(ch)
inline void HAL_adc_init() {}//todo
#define HAL_ADC_VREF 3.3
#define HAL_ADC_RESOLUTION 10
#define HAL_START_ADC(ch) HAL_adc_start_conversion(ch)
#define HAL_READ_ADC() HAL_adc_result
#define HAL_ADC_READY() true
void HAL_adc_start_conversion(const uint8_t ch);
uint16_t HAL_adc_get_result();
// //
// Pin Map // Pin Mapping for M42, M43, M226
// //
#define GET_PIN_MAP_PIN(index) index #define GET_PIN_MAP_PIN(index) index
#define GET_PIN_MAP_INDEX(pin) pin #define GET_PIN_MAP_INDEX(pin) pin
@ -139,23 +140,18 @@ uint16_t HAL_adc_get_result();
// //
// Tone // Tone
// //
void toneInit();
void tone(const pin_t _pin, const unsigned int frequency, const unsigned long duration=0); void tone(const pin_t _pin, const unsigned int frequency, const unsigned long duration=0);
void noTone(const pin_t _pin); void noTone(const pin_t _pin);
// Enable hooks into idle and setup for HAL // ------------------------
#define HAL_IDLETASK 1 // Class Utilities
void HAL_idletask(); // ------------------------
void HAL_init();
//
// Utility functions
//
void _delay_ms(const int delay);
#pragma GCC diagnostic push #pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wunused-function" #if GCC_VERSION <= 50000
int freeMemory(); #pragma GCC diagnostic ignored "-Wunused-function"
#endif
#pragma GCC diagnostic pop #pragma GCC diagnostic pop
#ifdef __cplusplus #ifdef __cplusplus
@ -165,3 +161,73 @@ char *dtostrf(double __val, signed char __width, unsigned char __prec, char *__s
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif
// Return free RAM between end of heap (or end bss) and whatever is current
int freeMemory();
// ------------------------
// 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
// Interrupts
static bool isr_state() { return !__get_PRIMASK(); }
static void isr_on() { __enable_irq(); }
static void isr_off() { __disable_irq(); }
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 channel. Called from Temperature::isr!
static void adc_start(const uint8_t ch) { adc_result = analogRead(ch); }
// 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 inverting the duty cycle in this HAL.
* No changing the maximum size of the provided value to enable finer PWM duty control in this HAL.
*/
static void set_pwm_duty(const pin_t pin, const uint16_t v, const uint16_t=255, const bool=false) {
analogWrite(pin, v);
}
};

View File

@ -31,8 +31,6 @@
/** /**
* HAL for Arduino Due and compatible (SAM3X8E) * HAL for Arduino Due and compatible (SAM3X8E)
*
* For ARDUINO_ARCH_SAM
*/ */
#ifdef ARDUINO_ARCH_SAM #ifdef ARDUINO_ARCH_SAM
@ -56,8 +54,8 @@
#pragma GCC optimize (3) #pragma GCC optimize (3)
typedef uint8_t (*pfnSpiTransfer)(uint8_t b); typedef uint8_t (*pfnSpiTransfer)(uint8_t b);
typedef void (*pfnSpiRxBlock)(uint8_t* buf, uint32_t nbyte); typedef void (*pfnSpiRxBlock)(uint8_t *buf, uint32_t nbyte);
typedef void (*pfnSpiTxBlock)(const uint8_t* buf, uint32_t nbyte); typedef void (*pfnSpiTxBlock)(const uint8_t *buf, uint32_t nbyte);
/* ---------------- Macros to be able to access definitions from asm */ /* ---------------- Macros to be able to access definitions from asm */
#define _PORT(IO) DIO ## IO ## _WPORT #define _PORT(IO) DIO ## IO ## _WPORT
@ -69,10 +67,10 @@
// run at ~8 .. ~10Mhz - Tx version (Rx data discarded) // run at ~8 .. ~10Mhz - Tx version (Rx data discarded)
static uint8_t spiTransferTx0(uint8_t bout) { // using Mode 0 static uint8_t spiTransferTx0(uint8_t bout) { // using Mode 0
uint32_t MOSI_PORT_PLUS30 = ((uint32_t) PORT(MOSI_PIN)) + 0x30; /* SODR of port */ uint32_t MOSI_PORT_PLUS30 = ((uint32_t) PORT(SD_MOSI_PIN)) + 0x30; /* SODR of port */
uint32_t MOSI_MASK = PIN_MASK(MOSI_PIN); uint32_t MOSI_MASK = PIN_MASK(SD_MOSI_PIN);
uint32_t SCK_PORT_PLUS30 = ((uint32_t) PORT(SCK_PIN)) + 0x30; /* SODR of port */ uint32_t SCK_PORT_PLUS30 = ((uint32_t) PORT(SD_SCK_PIN)) + 0x30; /* SODR of port */
uint32_t SCK_MASK = PIN_MASK(SCK_PIN); uint32_t SCK_MASK = PIN_MASK(SD_SCK_PIN);
uint32_t idx = 0; uint32_t idx = 0;
/* Negate bout, as the assembler requires a negated value */ /* Negate bout, as the assembler requires a negated value */
@ -154,9 +152,9 @@
static uint8_t spiTransferRx0(uint8_t) { // using Mode 0 static uint8_t spiTransferRx0(uint8_t) { // using Mode 0
uint32_t bin = 0; uint32_t bin = 0;
uint32_t work = 0; uint32_t work = 0;
uint32_t BITBAND_MISO_PORT = BITBAND_ADDRESS( ((uint32_t)PORT(MISO_PIN))+0x3C, PIN_SHIFT(MISO_PIN)); /* PDSR of port in bitband area */ uint32_t BITBAND_MISO_PORT = BITBAND_ADDRESS( ((uint32_t)PORT(SD_MISO_PIN))+0x3C, PIN_SHIFT(SD_MISO_PIN)); /* PDSR of port in bitband area */
uint32_t SCK_PORT_PLUS30 = ((uint32_t) PORT(SCK_PIN)) + 0x30; /* SODR of port */ uint32_t SCK_PORT_PLUS30 = ((uint32_t) PORT(SD_SCK_PIN)) + 0x30; /* SODR of port */
uint32_t SCK_MASK = PIN_MASK(SCK_PIN); uint32_t SCK_MASK = PIN_MASK(SD_SCK_PIN);
/* The software SPI routine */ /* The software SPI routine */
__asm__ __volatile__( __asm__ __volatile__(
@ -225,36 +223,36 @@
static uint8_t spiTransfer1(uint8_t b) { // using Mode 0 static uint8_t spiTransfer1(uint8_t b) { // using Mode 0
int bits = 8; int bits = 8;
do { do {
WRITE(MOSI_PIN, b & 0x80); WRITE(SD_MOSI_PIN, b & 0x80);
b <<= 1; // little setup time b <<= 1; // little setup time
WRITE(SCK_PIN, HIGH); WRITE(SD_SCK_PIN, HIGH);
DELAY_NS(125); // 10 cycles @ 84mhz DELAY_NS(125); // 10 cycles @ 84mhz
b |= (READ(MISO_PIN) != 0); b |= (READ(SD_MISO_PIN) != 0);
WRITE(SCK_PIN, LOW); WRITE(SD_SCK_PIN, LOW);
DELAY_NS(125); // 10 cycles @ 84mhz DELAY_NS(125); // 10 cycles @ 84mhz
} while (--bits); } while (--bits);
return b; return b;
} }
// all the others // all the others
static uint32_t spiDelayCyclesX4 = (F_CPU) / 1000000; // 4µs => 125khz static uint16_t spiDelayNS = 4000; // 4000ns => 125khz
static uint8_t spiTransferX(uint8_t b) { // using Mode 0 static uint8_t spiTransferX(uint8_t b) { // using Mode 0
int bits = 8; int bits = 8;
do { do {
WRITE(MOSI_PIN, b & 0x80); WRITE(SD_MOSI_PIN, b & 0x80);
b <<= 1; // little setup time b <<= 1; // little setup time
WRITE(SCK_PIN, HIGH); WRITE(SD_SCK_PIN, HIGH);
__delay_4cycles(spiDelayCyclesX4); DELAY_NS_VAR(spiDelayNS);
b |= (READ(MISO_PIN) != 0); b |= (READ(SD_MISO_PIN) != 0);
WRITE(SCK_PIN, LOW); WRITE(SD_SCK_PIN, LOW);
__delay_4cycles(spiDelayCyclesX4); DELAY_NS_VAR(spiDelayNS);
} while (--bits); } while (--bits);
return b; return b;
} }
@ -270,11 +268,11 @@
static pfnSpiTransfer spiTransferTx = (pfnSpiTransfer)spiTransferX; static pfnSpiTransfer spiTransferTx = (pfnSpiTransfer)spiTransferX;
// Block transfers run at ~8 .. ~10Mhz - Tx version (Rx data discarded) // Block transfers run at ~8 .. ~10Mhz - Tx version (Rx data discarded)
static void spiTxBlock0(const uint8_t* ptr, uint32_t todo) { static void spiTxBlock0(const uint8_t *ptr, uint32_t todo) {
uint32_t MOSI_PORT_PLUS30 = ((uint32_t) PORT(MOSI_PIN)) + 0x30; /* SODR of port */ uint32_t MOSI_PORT_PLUS30 = ((uint32_t) PORT(SD_MOSI_PIN)) + 0x30; /* SODR of port */
uint32_t MOSI_MASK = PIN_MASK(MOSI_PIN); uint32_t MOSI_MASK = PIN_MASK(SD_MOSI_PIN);
uint32_t SCK_PORT_PLUS30 = ((uint32_t) PORT(SCK_PIN)) + 0x30; /* SODR of port */ uint32_t SCK_PORT_PLUS30 = ((uint32_t) PORT(SD_SCK_PIN)) + 0x30; /* SODR of port */
uint32_t SCK_MASK = PIN_MASK(SCK_PIN); uint32_t SCK_MASK = PIN_MASK(SD_SCK_PIN);
uint32_t work = 0; uint32_t work = 0;
uint32_t txval = 0; uint32_t txval = 0;
@ -349,12 +347,12 @@
); );
} }
static void spiRxBlock0(uint8_t* ptr, uint32_t todo) { static void spiRxBlock0(uint8_t *ptr, uint32_t todo) {
uint32_t bin = 0; uint32_t bin = 0;
uint32_t work = 0; uint32_t work = 0;
uint32_t BITBAND_MISO_PORT = BITBAND_ADDRESS( ((uint32_t)PORT(MISO_PIN))+0x3C, PIN_SHIFT(MISO_PIN)); /* PDSR of port in bitband area */ uint32_t BITBAND_MISO_PORT = BITBAND_ADDRESS( ((uint32_t)PORT(SD_MISO_PIN))+0x3C, PIN_SHIFT(SD_MISO_PIN)); /* PDSR of port in bitband area */
uint32_t SCK_PORT_PLUS30 = ((uint32_t) PORT(SCK_PIN)) + 0x30; /* SODR of port */ uint32_t SCK_PORT_PLUS30 = ((uint32_t) PORT(SD_SCK_PIN)) + 0x30; /* SODR of port */
uint32_t SCK_MASK = PIN_MASK(SCK_PIN); uint32_t SCK_MASK = PIN_MASK(SD_SCK_PIN);
/* The software SPI routine */ /* The software SPI routine */
__asm__ __volatile__( __asm__ __volatile__(
@ -425,48 +423,48 @@
); );
} }
static void spiTxBlockX(const uint8_t* buf, uint32_t todo) { static void spiTxBlockX(const uint8_t *buf, uint32_t todo) {
do { do {
(void)spiTransferTx(*buf++); (void)spiTransferTx(*buf++);
} while (--todo); } while (--todo);
} }
static void spiRxBlockX(uint8_t* buf, uint32_t todo) { static void spiRxBlockX(uint8_t *buf, uint32_t todo) {
do { do {
*buf++ = spiTransferRx(0xFF); *buf++ = spiTransferRx(0xFF);
} while (--todo); } while (--todo);
} }
// Pointers to generic functions for block tranfers // Pointers to generic functions for block transfers
static pfnSpiTxBlock spiTxBlock = (pfnSpiTxBlock)spiTxBlockX; static pfnSpiTxBlock spiTxBlock = (pfnSpiTxBlock)spiTxBlockX;
static pfnSpiRxBlock spiRxBlock = (pfnSpiRxBlock)spiRxBlockX; static pfnSpiRxBlock spiRxBlock = (pfnSpiRxBlock)spiRxBlockX;
#if MB(ALLIGATOR) #if MB(ALLIGATOR)
#define _SS_WRITE(S) WRITE(SS_PIN, S) #define _SS_WRITE(S) WRITE(SD_SS_PIN, S)
#else #else
#define _SS_WRITE(S) NOOP #define _SS_WRITE(S) NOOP
#endif #endif
void spiBegin() { void spiBegin() {
SET_OUTPUT(SS_PIN); SET_OUTPUT(SD_SS_PIN);
_SS_WRITE(HIGH); _SS_WRITE(HIGH);
SET_OUTPUT(SCK_PIN); SET_OUTPUT(SD_SCK_PIN);
SET_INPUT(MISO_PIN); SET_INPUT(SD_MISO_PIN);
SET_OUTPUT(MOSI_PIN); SET_OUTPUT(SD_MOSI_PIN);
} }
uint8_t spiRec() { uint8_t spiRec() {
_SS_WRITE(LOW); _SS_WRITE(LOW);
WRITE(MOSI_PIN, HIGH); // Output 1s 1 WRITE(SD_MOSI_PIN, HIGH); // Output 1s 1
uint8_t b = spiTransferRx(0xFF); uint8_t b = spiTransferRx(0xFF);
_SS_WRITE(HIGH); _SS_WRITE(HIGH);
return b; return b;
} }
void spiRead(uint8_t* buf, uint16_t nbyte) { void spiRead(uint8_t *buf, uint16_t nbyte) {
if (nbyte) { if (nbyte) {
_SS_WRITE(LOW); _SS_WRITE(LOW);
WRITE(MOSI_PIN, HIGH); // Output 1s 1 WRITE(SD_MOSI_PIN, HIGH); // Output 1s 1
spiRxBlock(buf, nbyte); spiRxBlock(buf, nbyte);
_SS_WRITE(HIGH); _SS_WRITE(HIGH);
} }
@ -478,7 +476,7 @@
_SS_WRITE(HIGH); _SS_WRITE(HIGH);
} }
void spiSendBlock(uint8_t token, const uint8_t* buf) { void spiSendBlock(uint8_t token, const uint8_t *buf) {
_SS_WRITE(LOW); _SS_WRITE(LOW);
(void)spiTransferTx(token); (void)spiTransferTx(token);
spiTxBlock(buf, 512); spiTxBlock(buf, 512);
@ -510,7 +508,7 @@
spiRxBlock = (pfnSpiRxBlock)spiRxBlockX; spiRxBlock = (pfnSpiRxBlock)spiRxBlockX;
break; break;
default: default:
spiDelayCyclesX4 = ((F_CPU) / 1000000) >> (6 - spiRate); spiDelayNS = 4000 >> (6 - spiRate); // spiRate of 2 gives the maximum error with current CPU
spiTransferTx = (pfnSpiTransfer)spiTransferX; spiTransferTx = (pfnSpiTransfer)spiTransferX;
spiTransferRx = (pfnSpiTransfer)spiTransferX; spiTransferRx = (pfnSpiTransfer)spiTransferX;
spiTxBlock = (pfnSpiTxBlock)spiTxBlockX; spiTxBlock = (pfnSpiTxBlock)spiTxBlockX;
@ -519,8 +517,8 @@
} }
_SS_WRITE(HIGH); _SS_WRITE(HIGH);
WRITE(MOSI_PIN, HIGH); WRITE(SD_MOSI_PIN, HIGH);
WRITE(SCK_PIN, LOW); WRITE(SD_SCK_PIN, LOW);
} }
/** Begin SPI transaction, set clock, bit order, data mode */ /** Begin SPI transaction, set clock, bit order, data mode */
@ -575,38 +573,34 @@
// Configure SPI pins // Configure SPI pins
PIO_Configure( PIO_Configure(
g_APinDescription[SCK_PIN].pPort, g_APinDescription[SD_SCK_PIN].pPort,
g_APinDescription[SCK_PIN].ulPinType, g_APinDescription[SD_SCK_PIN].ulPinType,
g_APinDescription[SCK_PIN].ulPin, g_APinDescription[SD_SCK_PIN].ulPin,
g_APinDescription[SCK_PIN].ulPinConfiguration); g_APinDescription[SD_SCK_PIN].ulPinConfiguration);
PIO_Configure( PIO_Configure(
g_APinDescription[MOSI_PIN].pPort, g_APinDescription[SD_MOSI_PIN].pPort,
g_APinDescription[MOSI_PIN].ulPinType, g_APinDescription[SD_MOSI_PIN].ulPinType,
g_APinDescription[MOSI_PIN].ulPin, g_APinDescription[SD_MOSI_PIN].ulPin,
g_APinDescription[MOSI_PIN].ulPinConfiguration); g_APinDescription[SD_MOSI_PIN].ulPinConfiguration);
PIO_Configure( PIO_Configure(
g_APinDescription[MISO_PIN].pPort, g_APinDescription[SD_MISO_PIN].pPort,
g_APinDescription[MISO_PIN].ulPinType, g_APinDescription[SD_MISO_PIN].ulPinType,
g_APinDescription[MISO_PIN].ulPin, g_APinDescription[SD_MISO_PIN].ulPin,
g_APinDescription[MISO_PIN].ulPinConfiguration); g_APinDescription[SD_MISO_PIN].ulPinConfiguration);
// set master mode, peripheral select, fault detection // set master mode, peripheral select, fault detection
SPI_Configure(SPI0, ID_SPI0, SPI_MR_MSTR | SPI_MR_MODFDIS | SPI_MR_PS); SPI_Configure(SPI0, ID_SPI0, SPI_MR_MSTR | SPI_MR_MODFDIS | SPI_MR_PS);
SPI_Enable(SPI0); SPI_Enable(SPI0);
SET_OUTPUT(DAC0_SYNC); SET_OUTPUT(DAC0_SYNC_PIN);
#if HAS_MULTI_EXTRUDER #if HAS_MULTI_EXTRUDER
SET_OUTPUT(DAC1_SYNC); OUT_WRITE(DAC1_SYNC_PIN, HIGH);
WRITE(DAC1_SYNC, HIGH);
#endif #endif
SET_OUTPUT(SPI_EEPROM1_CS); WRITE(DAC0_SYNC_PIN, HIGH);
SET_OUTPUT(SPI_EEPROM2_CS); OUT_WRITE(SPI_EEPROM1_CS_PIN, HIGH);
SET_OUTPUT(SPI_FLASH_CS); OUT_WRITE(SPI_EEPROM2_CS_PIN, HIGH);
WRITE(DAC0_SYNC, HIGH); OUT_WRITE(SPI_FLASH_CS_PIN, HIGH);
WRITE(SPI_EEPROM1_CS, HIGH); WRITE(SD_SS_PIN, HIGH);
WRITE(SPI_EEPROM2_CS, HIGH);
WRITE(SPI_FLASH_CS, HIGH);
WRITE(SS_PIN, HIGH);
OUT_WRITE(SDSS, LOW); OUT_WRITE(SDSS, LOW);
@ -645,7 +639,7 @@
} }
// Read from SPI into buffer // Read from SPI into buffer
void spiRead(uint8_t* buf, uint16_t nbyte) { void spiRead(uint8_t *buf, uint16_t nbyte) {
if (!nbyte) return; if (!nbyte) return;
--nbyte; --nbyte;
for (int i = 0; i < nbyte; i++) { for (int i = 0; i < nbyte; i++) {
@ -668,7 +662,7 @@
//DELAY_US(1U); //DELAY_US(1U);
} }
void spiSend(const uint8_t* buf, size_t nbyte) { void spiSend(const uint8_t *buf, size_t nbyte) {
if (!nbyte) return; if (!nbyte) return;
--nbyte; --nbyte;
for (size_t i = 0; i < nbyte; i++) { for (size_t i = 0; i < nbyte; i++) {
@ -689,7 +683,7 @@
FLUSH_RX(); FLUSH_RX();
} }
void spiSend(uint32_t chan, const uint8_t* buf, size_t nbyte) { void spiSend(uint32_t chan, const uint8_t *buf, size_t nbyte) {
if (!nbyte) return; if (!nbyte) return;
--nbyte; --nbyte;
for (size_t i = 0; i < nbyte; i++) { for (size_t i = 0; i < nbyte; i++) {
@ -702,7 +696,7 @@
} }
// Write from buffer to SPI // Write from buffer to SPI
void spiSendBlock(uint8_t token, const uint8_t* buf) { void spiSendBlock(uint8_t token, const uint8_t *buf) {
SPI0->SPI_TDR = (uint32_t)token | SPI_PCS(SPI_CHAN); SPI0->SPI_TDR = (uint32_t)token | SPI_PCS(SPI_CHAN);
WHILE_TX(0); WHILE_TX(0);
//WHILE_RX(0); //WHILE_RX(0);
@ -801,19 +795,19 @@
uint8_t spiRec() { return (uint8_t)spiTransfer(0xFF); } uint8_t spiRec() { return (uint8_t)spiTransfer(0xFF); }
void spiRead(uint8_t* buf, uint16_t nbyte) { void spiRead(uint8_t *buf, uint16_t nbyte) {
for (int i = 0; i < nbyte; i++) for (int i = 0; i < nbyte; i++)
buf[i] = spiTransfer(0xFF); buf[i] = spiTransfer(0xFF);
} }
void spiSend(uint8_t data) { spiTransfer(data); } void spiSend(uint8_t data) { spiTransfer(data); }
void spiSend(const uint8_t* buf, size_t nbyte) { void spiSend(const uint8_t *buf, size_t nbyte) {
for (uint16_t i = 0; i < nbyte; i++) for (uint16_t i = 0; i < nbyte; i++)
spiTransfer(buf[i]); spiTransfer(buf[i]);
} }
void spiSendBlock(uint8_t token, const uint8_t* buf) { void spiSendBlock(uint8_t token, const uint8_t *buf) {
spiTransfer(token); spiTransfer(token);
for (uint16_t i = 0; i < 512; i++) for (uint16_t i = 0; i < 512; i++)
spiTransfer(buf[i]); spiTransfer(buf[i]);

View File

@ -41,7 +41,7 @@
practice, we need alignment to 256 bytes to make this work in all practice, we need alignment to 256 bytes to make this work in all
cases */ cases */
__attribute__ ((aligned(256))) __attribute__ ((aligned(256)))
static DeviceVectors ram_tab = { nullptr }; static DeviceVectors ram_tab[61] = { nullptr };
/** /**
* This function checks if the exception/interrupt table is already in SRAM or not. * This function checks if the exception/interrupt table is already in SRAM or not.

View File

@ -1,6 +1,6 @@
/** /**
* Marlin 3D Printer Firmware * Marlin 3D Printer Firmware
* Copyright (c) 2020 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] * Copyright (c) 2021 MarlinFirmware [https://github.com/MarlinFirmware/Marlin]
* *
* Based on Sprinter and grbl. * Based on Sprinter and grbl.
* Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm * Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm
@ -21,7 +21,6 @@
*/ */
#pragma once #pragma once
extern IWDG_HandleTypeDef hiwdg; #include <SPI.h>
void watchdog_init(); using MarlinSPI = SPIClass;
void HAL_watchdog_refresh();

View File

@ -382,7 +382,7 @@ void MarlinSerial<Cfg>::flush() {
} }
template<typename Cfg> template<typename Cfg>
void MarlinSerial<Cfg>::write(const uint8_t c) { size_t MarlinSerial<Cfg>::write(const uint8_t c) {
_written = true; _written = true;
if (Cfg::TX_SIZE == 0) { if (Cfg::TX_SIZE == 0) {
@ -400,13 +400,13 @@ void MarlinSerial<Cfg>::write(const uint8_t c) {
// XOFF char at the RX isr, but it is properly handled there // XOFF char at the RX isr, but it is properly handled there
if (!(HWUART->UART_IMR & UART_IMR_TXRDY) && (HWUART->UART_SR & UART_SR_TXRDY)) { if (!(HWUART->UART_IMR & UART_IMR_TXRDY) && (HWUART->UART_SR & UART_SR_TXRDY)) {
HWUART->UART_THR = c; HWUART->UART_THR = c;
return; return 1;
} }
const uint8_t i = (tx_buffer.head + 1) & (Cfg::TX_SIZE - 1); const uint8_t i = (tx_buffer.head + 1) & (Cfg::TX_SIZE - 1);
// If global interrupts are disabled (as the result of being called from an ISR)... // If global interrupts are disabled (as the result of being called from an ISR)...
if (!ISRS_ENABLED()) { if (!hal.isr_state()) {
// Make room by polling if it is possible to transmit, and do so! // Make room by polling if it is possible to transmit, and do so!
while (i == tx_buffer.tail) { while (i == tx_buffer.tail) {
@ -428,6 +428,7 @@ void MarlinSerial<Cfg>::write(const uint8_t c) {
// Enable TX isr - Non atomic, but it will eventually enable TX isr // Enable TX isr - Non atomic, but it will eventually enable TX isr
HWUART->UART_IER = UART_IER_TXRDY; HWUART->UART_IER = UART_IER_TXRDY;
} }
return 1;
} }
template<typename Cfg> template<typename Cfg>
@ -453,7 +454,7 @@ void MarlinSerial<Cfg>::flushTX() {
if (!_written) return; if (!_written) return;
// If global interrupts are disabled (as the result of being called from an ISR)... // If global interrupts are disabled (as the result of being called from an ISR)...
if (!ISRS_ENABLED()) { if (!hal.isr_state()) {
// Wait until everything was transmitted - We must do polling, as interrupts are disabled // Wait until everything was transmitted - We must do polling, as interrupts are disabled
while (tx_buffer.head != tx_buffer.tail || !(HWUART->UART_SR & UART_SR_TXEMPTY)) { while (tx_buffer.head != tx_buffer.tail || !(HWUART->UART_SR & UART_SR_TXEMPTY)) {
@ -473,169 +474,21 @@ void MarlinSerial<Cfg>::flushTX() {
} }
} }
/**
* Imports from print.h
*/
template<typename Cfg>
void MarlinSerial<Cfg>::print(char c, int base) {
print((long)c, base);
}
template<typename Cfg>
void MarlinSerial<Cfg>::print(unsigned char b, int base) {
print((unsigned long)b, base);
}
template<typename Cfg>
void MarlinSerial<Cfg>::print(int n, int base) {
print((long)n, base);
}
template<typename Cfg>
void MarlinSerial<Cfg>::print(unsigned int n, int base) {
print((unsigned long)n, base);
}
template<typename Cfg>
void MarlinSerial<Cfg>::print(long n, int base) {
if (base == 0) write(n);
else if (base == 10) {
if (n < 0) { print('-'); n = -n; }
printNumber(n, 10);
}
else
printNumber(n, base);
}
template<typename Cfg>
void MarlinSerial<Cfg>::print(unsigned long n, int base) {
if (base == 0) write(n);
else printNumber(n, base);
}
template<typename Cfg>
void MarlinSerial<Cfg>::print(double n, int digits) {
printFloat(n, digits);
}
template<typename Cfg>
void MarlinSerial<Cfg>::println() {
print('\r');
print('\n');
}
template<typename Cfg>
void MarlinSerial<Cfg>::println(const String& s) {
print(s);
println();
}
template<typename Cfg>
void MarlinSerial<Cfg>::println(const char c[]) {
print(c);
println();
}
template<typename Cfg>
void MarlinSerial<Cfg>::println(char c, int base) {
print(c, base);
println();
}
template<typename Cfg>
void MarlinSerial<Cfg>::println(unsigned char b, int base) {
print(b, base);
println();
}
template<typename Cfg>
void MarlinSerial<Cfg>::println(int n, int base) {
print(n, base);
println();
}
template<typename Cfg>
void MarlinSerial<Cfg>::println(unsigned int n, int base) {
print(n, base);
println();
}
template<typename Cfg>
void MarlinSerial<Cfg>::println(long n, int base) {
print(n, base);
println();
}
template<typename Cfg>
void MarlinSerial<Cfg>::println(unsigned long n, int base) {
print(n, base);
println();
}
template<typename Cfg>
void MarlinSerial<Cfg>::println(double n, int digits) {
print(n, digits);
println();
}
// Private Methods
template<typename Cfg>
void MarlinSerial<Cfg>::printNumber(unsigned long n, uint8_t base) {
if (n) {
unsigned char buf[8 * sizeof(long)]; // Enough space for base 2
int8_t i = 0;
while (n) {
buf[i++] = n % base;
n /= base;
}
while (i--)
print((char)(buf[i] + (buf[i] < 10 ? '0' : 'A' - 10)));
}
else
print('0');
}
template<typename Cfg>
void MarlinSerial<Cfg>::printFloat(double number, uint8_t digits) {
// Handle negative numbers
if (number < 0.0) {
print('-');
number = -number;
}
// Round correctly so that print(1.999, 2) prints as "2.00"
double rounding = 0.5;
LOOP_L_N(i, digits) rounding *= 0.1;
number += rounding;
// Extract the integer part of the number and print it
unsigned long int_part = (unsigned long)number;
double remainder = number - (double)int_part;
print(int_part);
// Print the decimal point, but only if there are digits beyond
if (digits) {
print('.');
// Extract digits from the remainder one at a time
while (digits--) {
remainder *= 10.0;
int toPrint = int(remainder);
print(toPrint);
remainder -= toPrint;
}
}
}
// If not using the USB port as serial port // If not using the USB port as serial port
#if SERIAL_PORT >= 0 #if defined(SERIAL_PORT) && SERIAL_PORT >= 0
template class MarlinSerial<MarlinSerialCfg<SERIAL_PORT>>; // Define template class MarlinSerial< MarlinSerialCfg<SERIAL_PORT> >;
MarlinSerial<MarlinSerialCfg<SERIAL_PORT>> customizedSerial1; // Instantiate MSerialT1 customizedSerial1(MarlinSerialCfg<SERIAL_PORT>::EMERGENCYPARSER);
#endif #endif
#if defined(SERIAL_PORT_2) && SERIAL_PORT_2 >= 0 #if defined(SERIAL_PORT_2) && SERIAL_PORT_2 >= 0
template class MarlinSerial<MarlinSerialCfg<SERIAL_PORT_2>>; // Define template class MarlinSerial< MarlinSerialCfg<SERIAL_PORT_2> >;
MarlinSerial<MarlinSerialCfg<SERIAL_PORT_2>> customizedSerial2; // Instantiate MSerialT2 customizedSerial2(MarlinSerialCfg<SERIAL_PORT_2>::EMERGENCYPARSER);
#endif
#if defined(SERIAL_PORT_3) && SERIAL_PORT_3 >= 0
template class MarlinSerial< MarlinSerialCfg<SERIAL_PORT_3> >;
MSerialT3 customizedSerial3(MarlinSerialCfg<SERIAL_PORT_3>::EMERGENCYPARSER);
#endif #endif
#endif // ARDUINO_ARCH_SAM #endif // ARDUINO_ARCH_SAM

View File

@ -30,11 +30,7 @@
#include <WString.h> #include <WString.h>
#include "../../inc/MarlinConfigPre.h" #include "../../inc/MarlinConfigPre.h"
#include "../../core/serial_hook.h"
#define DEC 10
#define HEX 16
#define OCT 8
#define BIN 2
// Define constants and variables for buffering incoming serial data. We're // Define constants and variables for buffering incoming serial data. We're
// using a ring buffer (I think), in which rx_buffer_head is the index of the // using a ring buffer (I think), in which rx_buffer_head is the index of the
@ -119,44 +115,15 @@ public:
static int read(); static int read();
static void flush(); static void flush();
static ring_buffer_pos_t available(); static ring_buffer_pos_t available();
static void write(const uint8_t c); static size_t write(const uint8_t c);
static void flushTX(); static void flushTX();
static inline bool emergency_parser_enabled() { return Cfg::EMERGENCYPARSER; } static bool emergency_parser_enabled() { return Cfg::EMERGENCYPARSER; }
FORCE_INLINE static uint8_t dropped() { return Cfg::DROPPED_RX ? rx_dropped_bytes : 0; } FORCE_INLINE static uint8_t dropped() { return Cfg::DROPPED_RX ? rx_dropped_bytes : 0; }
FORCE_INLINE static uint8_t buffer_overruns() { return Cfg::RX_OVERRUNS ? rx_buffer_overruns : 0; } FORCE_INLINE static uint8_t buffer_overruns() { return Cfg::RX_OVERRUNS ? rx_buffer_overruns : 0; }
FORCE_INLINE static uint8_t framing_errors() { return Cfg::RX_FRAMING_ERRORS ? rx_framing_errors : 0; } FORCE_INLINE static uint8_t framing_errors() { return Cfg::RX_FRAMING_ERRORS ? rx_framing_errors : 0; }
FORCE_INLINE static ring_buffer_pos_t rxMaxEnqueued() { return Cfg::MAX_RX_QUEUED ? rx_max_enqueued : 0; } FORCE_INLINE static ring_buffer_pos_t rxMaxEnqueued() { return Cfg::MAX_RX_QUEUED ? rx_max_enqueued : 0; }
FORCE_INLINE static void write(const char* str) { while (*str) write(*str++); }
FORCE_INLINE static void write(const uint8_t* buffer, size_t size) { while (size--) write(*buffer++); }
FORCE_INLINE static void print(const String& s) { for (int i = 0; i < (int)s.length(); i++) write(s[i]); }
FORCE_INLINE static void print(const char* str) { write(str); }
static void print(char, int = 0);
static void print(unsigned char, int = 0);
static void print(int, int = DEC);
static void print(unsigned int, int = DEC);
static void print(long, int = DEC);
static void print(unsigned long, int = DEC);
static void print(double, int = 2);
static void println(const String& s);
static void println(const char[]);
static void println(char, int = 0);
static void println(unsigned char, int = 0);
static void println(int, int = DEC);
static void println(unsigned int, int = DEC);
static void println(long, int = DEC);
static void println(unsigned long, int = DEC);
static void println(double, int = 2);
static void println();
operator bool() { return true; }
private:
static void printNumber(unsigned long, const uint8_t);
static void printFloat(double, uint8_t);
}; };
// Serial port configuration // Serial port configuration
@ -173,10 +140,17 @@ struct MarlinSerialCfg {
static constexpr bool MAX_RX_QUEUED = ENABLED(SERIAL_STATS_MAX_RX_QUEUED); static constexpr bool MAX_RX_QUEUED = ENABLED(SERIAL_STATS_MAX_RX_QUEUED);
}; };
#if SERIAL_PORT >= 0 #if defined(SERIAL_PORT) && SERIAL_PORT >= 0
extern MarlinSerial<MarlinSerialCfg<SERIAL_PORT>> customizedSerial1; typedef Serial1Class< MarlinSerial< MarlinSerialCfg<SERIAL_PORT> > > MSerialT1;
extern MSerialT1 customizedSerial1;
#endif #endif
#if defined(SERIAL_PORT_2) && SERIAL_PORT_2 >= 0 #if defined(SERIAL_PORT_2) && SERIAL_PORT_2 >= 0
extern MarlinSerial<MarlinSerialCfg<SERIAL_PORT_2>> customizedSerial2; typedef Serial1Class< MarlinSerial< MarlinSerialCfg<SERIAL_PORT_2> > > MSerialT2;
extern MSerialT2 customizedSerial2;
#endif
#if defined(SERIAL_PORT_3) && SERIAL_PORT_3 >= 0
typedef Serial1Class< MarlinSerial< MarlinSerialCfg<SERIAL_PORT_3> > > MSerialT3;
extern MSerialT3 customizedSerial3;
#endif #endif

View File

@ -19,13 +19,13 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>. * along with this program. If not, see <https://www.gnu.org/licenses/>.
* *
*/ */
#ifdef ARDUINO_ARCH_SAM
/** /**
* MarlinSerial_Due.cpp - Hardware serial library for Arduino DUE * MarlinSerial_Due.cpp - Hardware serial library for Arduino DUE
* Copyright (c) 2017 Eduardo José Tagle. All right reserved * Copyright (c) 2017 Eduardo José Tagle. All right reserved
* Based on MarlinSerial for AVR, copyright (c) 2006 Nicholas Zambetti. All right reserved. * Based on MarlinSerial for AVR, copyright (c) 2006 Nicholas Zambetti. All right reserved.
*/ */
#ifdef ARDUINO_ARCH_SAM
#include "../../inc/MarlinConfig.h" #include "../../inc/MarlinConfig.h"
@ -33,10 +33,6 @@
#include "MarlinSerialUSB.h" #include "MarlinSerialUSB.h"
#if ENABLED(EMERGENCY_PARSER)
#include "../../feature/e_parser.h"
#endif
// Imports from Atmel USB Stack/CDC implementation // Imports from Atmel USB Stack/CDC implementation
extern "C" { extern "C" {
bool usb_task_cdc_isenabled(); bool usb_task_cdc_isenabled();
@ -45,15 +41,11 @@ extern "C" {
int udi_cdc_getc(); int udi_cdc_getc();
bool udi_cdc_is_tx_ready(); bool udi_cdc_is_tx_ready();
int udi_cdc_putc(int value); int udi_cdc_putc(int value);
}; }
// Pending character // Pending character
static int pending_char = -1; static int pending_char = -1;
#if ENABLED(EMERGENCY_PARSER)
static EmergencyParser::State emergency_state; // = EP_RESET
#endif
// Public Methods // Public Methods
void MarlinSerialUSB::begin(const long) {} void MarlinSerialUSB::begin(const long) {}
@ -73,7 +65,7 @@ int MarlinSerialUSB::peek() {
pending_char = udi_cdc_getc(); pending_char = udi_cdc_getc();
TERN_(EMERGENCY_PARSER, emergency_parser.update(emergency_state, (char)pending_char)); TERN_(EMERGENCY_PARSER, emergency_parser.update(static_cast<MSerialT1*>(this)->emergency_state, (char)pending_char));
return pending_char; return pending_char;
} }
@ -95,29 +87,27 @@ int MarlinSerialUSB::read() {
int c = udi_cdc_getc(); int c = udi_cdc_getc();
TERN_(EMERGENCY_PARSER, emergency_parser.update(emergency_state, (char)c)); TERN_(EMERGENCY_PARSER, emergency_parser.update(static_cast<MSerialT1*>(this)->emergency_state, (char)c));
return c; return c;
} }
bool MarlinSerialUSB::available() { int MarlinSerialUSB::available() {
/* If Pending chars */ if (pending_char > 0) return pending_char;
return pending_char >= 0 || return pending_char == 0 ||
/* or USB CDC enumerated and configured on the PC side and some // or USB CDC enumerated and configured on the PC side and some bytes where sent to us */
bytes where sent to us */ (usb_task_cdc_isenabled() && udi_cdc_is_rx_ready());
(usb_task_cdc_isenabled() && udi_cdc_is_rx_ready());
} }
void MarlinSerialUSB::flush() { } void MarlinSerialUSB::flush() { }
void MarlinSerialUSB::flushTX() { }
void MarlinSerialUSB::write(const uint8_t c) { size_t MarlinSerialUSB::write(const uint8_t c) {
/* Do not even bother sending anything if USB CDC is not enumerated /* Do not even bother sending anything if USB CDC is not enumerated
or not configured on the PC side or there is no program on the PC or not configured on the PC side or there is no program on the PC
listening to our messages */ listening to our messages */
if (!usb_task_cdc_isenabled() || !usb_task_cdc_dtr_active()) if (!usb_task_cdc_isenabled() || !usb_task_cdc_dtr_active())
return; return 0;
/* Wait until the PC has read the pending to be sent data */ /* Wait until the PC has read the pending to be sent data */
while (usb_task_cdc_isenabled() && while (usb_task_cdc_isenabled() &&
@ -129,161 +119,23 @@ void MarlinSerialUSB::write(const uint8_t c) {
or not configured on the PC side or there is no program on the PC or not configured on the PC side or there is no program on the PC
listening to our messages at this point */ listening to our messages at this point */
if (!usb_task_cdc_isenabled() || !usb_task_cdc_dtr_active()) if (!usb_task_cdc_isenabled() || !usb_task_cdc_dtr_active())
return; return 0;
// Fifo full // Fifo full
// udi_cdc_signal_overrun(); // udi_cdc_signal_overrun();
udi_cdc_putc(c); udi_cdc_putc(c);
} return 1;
/**
* Imports from print.h
*/
void MarlinSerialUSB::print(char c, int base) {
print((long)c, base);
}
void MarlinSerialUSB::print(unsigned char b, int base) {
print((unsigned long)b, base);
}
void MarlinSerialUSB::print(int n, int base) {
print((long)n, base);
}
void MarlinSerialUSB::print(unsigned int n, int base) {
print((unsigned long)n, base);
}
void MarlinSerialUSB::print(long n, int base) {
if (base == 0)
write(n);
else if (base == 10) {
if (n < 0) {
print('-');
n = -n;
}
printNumber(n, 10);
}
else
printNumber(n, base);
}
void MarlinSerialUSB::print(unsigned long n, int base) {
if (base == 0) write(n);
else printNumber(n, base);
}
void MarlinSerialUSB::print(double n, int digits) {
printFloat(n, digits);
}
void MarlinSerialUSB::println() {
print('\r');
print('\n');
}
void MarlinSerialUSB::println(const String& s) {
print(s);
println();
}
void MarlinSerialUSB::println(const char c[]) {
print(c);
println();
}
void MarlinSerialUSB::println(char c, int base) {
print(c, base);
println();
}
void MarlinSerialUSB::println(unsigned char b, int base) {
print(b, base);
println();
}
void MarlinSerialUSB::println(int n, int base) {
print(n, base);
println();
}
void MarlinSerialUSB::println(unsigned int n, int base) {
print(n, base);
println();
}
void MarlinSerialUSB::println(long n, int base) {
print(n, base);
println();
}
void MarlinSerialUSB::println(unsigned long n, int base) {
print(n, base);
println();
}
void MarlinSerialUSB::println(double n, int digits) {
print(n, digits);
println();
}
// Private Methods
void MarlinSerialUSB::printNumber(unsigned long n, uint8_t base) {
if (n) {
unsigned char buf[8 * sizeof(long)]; // Enough space for base 2
int8_t i = 0;
while (n) {
buf[i++] = n % base;
n /= base;
}
while (i--)
print((char)(buf[i] + (buf[i] < 10 ? '0' : 'A' - 10)));
}
else
print('0');
}
void MarlinSerialUSB::printFloat(double number, uint8_t digits) {
// Handle negative numbers
if (number < 0.0) {
print('-');
number = -number;
}
// Round correctly so that print(1.999, 2) prints as "2.00"
double rounding = 0.5;
LOOP_L_N(i, digits)
rounding *= 0.1;
number += rounding;
// Extract the integer part of the number and print it
unsigned long int_part = (unsigned long)number;
double remainder = number - (double)int_part;
print(int_part);
// Print the decimal point, but only if there are digits beyond
if (digits) {
print('.');
// Extract digits from the remainder one at a time
while (digits--) {
remainder *= 10.0;
int toPrint = int(remainder);
print(toPrint);
remainder -= toPrint;
}
}
} }
// Preinstantiate // Preinstantiate
#if SERIAL_PORT == -1 #if SERIAL_PORT == -1
MarlinSerialUSB customizedSerial1; MSerialT1 customizedSerial1(TERN0(EMERGENCY_PARSER, true));
#endif #endif
#if SERIAL_PORT_2 == -1 #if SERIAL_PORT_2 == -1
MarlinSerialUSB customizedSerial2; MSerialT2 customizedSerial2(TERN0(EMERGENCY_PARSER, true));
#endif
#if SERIAL_PORT_3 == -1
MSerialT3 customizedSerial3(TERN0(EMERGENCY_PARSER, true));
#endif #endif
#endif // HAS_USB_SERIAL #endif // HAS_USB_SERIAL

View File

@ -27,73 +27,39 @@
*/ */
#include "../../inc/MarlinConfig.h" #include "../../inc/MarlinConfig.h"
#include "../../core/serial_hook.h"
#if HAS_USB_SERIAL
#include <WString.h> #include <WString.h>
#define DEC 10 struct MarlinSerialUSB {
#define HEX 16 void begin(const long);
#define OCT 8 void end();
#define BIN 2 int peek();
int read();
class MarlinSerialUSB { void flush();
int available();
public: size_t write(const uint8_t c);
MarlinSerialUSB() {};
static void begin(const long);
static void end();
static int peek();
static int read();
static void flush();
static void flushTX();
static bool available();
static void write(const uint8_t c);
#if ENABLED(SERIAL_STATS_DROPPED_RX) #if ENABLED(SERIAL_STATS_DROPPED_RX)
FORCE_INLINE static uint32_t dropped() { return 0; } FORCE_INLINE uint32_t dropped() { return 0; }
#endif #endif
#if ENABLED(SERIAL_STATS_MAX_RX_QUEUED) #if ENABLED(SERIAL_STATS_MAX_RX_QUEUED)
FORCE_INLINE static int rxMaxEnqueued() { return 0; } FORCE_INLINE int rxMaxEnqueued() { return 0; }
#endif #endif
FORCE_INLINE static void write(const char* str) { while (*str) write(*str++); }
FORCE_INLINE static void write(const uint8_t* buffer, size_t size) { while (size--) write(*buffer++); }
FORCE_INLINE static void print(const String& s) { for (int i = 0; i < (int)s.length(); i++) write(s[i]); }
FORCE_INLINE static void print(const char* str) { write(str); }
static void print(char, int = 0);
static void print(unsigned char, int = 0);
static void print(int, int = DEC);
static void print(unsigned int, int = DEC);
static void print(long, int = DEC);
static void print(unsigned long, int = DEC);
static void print(double, int = 2);
static void println(const String& s);
static void println(const char[]);
static void println(char, int = 0);
static void println(unsigned char, int = 0);
static void println(int, int = DEC);
static void println(unsigned int, int = DEC);
static void println(long, int = DEC);
static void println(unsigned long, int = DEC);
static void println(double, int = 2);
static void println();
operator bool() { return true; }
private:
static void printNumber(unsigned long, const uint8_t);
static void printFloat(double, uint8_t);
}; };
#if SERIAL_PORT == -1 #if SERIAL_PORT == -1
extern MarlinSerialUSB customizedSerial1; typedef Serial1Class<MarlinSerialUSB> MSerialT1;
extern MSerialT1 customizedSerial1;
#endif #endif
#if SERIAL_PORT_2 == -1 #if SERIAL_PORT_2 == -1
extern MarlinSerialUSB customizedSerial2; typedef Serial1Class<MarlinSerialUSB> MSerialT2;
extern MSerialT2 customizedSerial2;
#endif #endif
#endif // HAS_USB_SERIAL #if SERIAL_PORT_3 == -1
typedef Serial1Class<MarlinSerialUSB> MSerialT3;
extern MSerialT3 customizedSerial3;
#endif

View File

@ -0,0 +1,91 @@
/**
* 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 <https://www.gnu.org/licenses/>.
*
*/
#ifdef ARDUINO_ARCH_SAM
#include "../../inc/MarlinConfigPre.h"
#if ENABLED(POSTMORTEM_DEBUGGING)
#include "../shared/MinSerial.h"
#include <stdarg.h>
static void TXBegin() {
// Disable UART interrupt in NVIC
NVIC_DisableIRQ( UART_IRQn );
// 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();
// Disable clock
pmc_disable_periph_clk( ID_UART );
// Configure PMC
pmc_enable_periph_clk( ID_UART );
// Disable PDC channel
UART->UART_PTCR = UART_PTCR_RXTDIS | UART_PTCR_TXTDIS;
// Reset and disable receiver and transmitter
UART->UART_CR = UART_CR_RSTRX | UART_CR_RSTTX | UART_CR_RXDIS | UART_CR_TXDIS;
// Configure mode: 8bit, No parity, 1 bit stop
UART->UART_MR = UART_MR_CHMODE_NORMAL | US_MR_CHRL_8_BIT | US_MR_NBSTOP_1_BIT | UART_MR_PAR_NO;
// Configure baudrate (asynchronous, no oversampling) to BAUDRATE bauds
UART->UART_BRGR = (SystemCoreClock / (BAUDRATE << 4));
// Enable receiver and transmitter
UART->UART_CR = UART_CR_RXEN | UART_CR_TXEN;
}
// A SW memory barrier, to ensure GCC does not overoptimize loops
#define sw_barrier() __asm__ volatile("": : :"memory");
static void TX(char c) {
while (!(UART->UART_SR & UART_SR_TXRDY)) { WDT_Restart(WDT); sw_barrier(); };
UART->UART_THR = c;
}
void install_min_serial() {
HAL_min_serial_init = &TXBegin;
HAL_min_serial_out = &TX;
}
#if DISABLED(DYNAMIC_VECTORTABLE)
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();
}
#endif
#endif // POSTMORTEM_DEBUGGING
#endif // ARDUINO_ARCH_SAM

View File

@ -47,12 +47,12 @@
#include "../shared/servo.h" #include "../shared/servo.h"
#include "../shared/servo_private.h" #include "../shared/servo_private.h"
static volatile int8_t Channel[_Nbr_16timers]; // counter for the servo being pulsed for each timer (or -1 if refresh interval) static Flags<_Nbr_16timers> DisablePending; // ISR should disable the timer at the next timer reset
// ------------------------ // ------------------------
/// Interrupt handler for the TC0 channel 1. /// Interrupt handler for the TC0 channel 1.
// ------------------------ // ------------------------
void Servo_Handler(timer16_Sequence_t timer, Tc *pTc, uint8_t channel); void Servo_Handler(const timer16_Sequence_t, Tc*, const uint8_t);
#ifdef _useTimer1 #ifdef _useTimer1
void HANDLER_FOR_TIMER1() { Servo_Handler(_timer1, TC_FOR_TIMER1, CHANNEL_FOR_TIMER1); } void HANDLER_FOR_TIMER1() { Servo_Handler(_timer1, TC_FOR_TIMER1, CHANNEL_FOR_TIMER1); }
@ -70,88 +70,92 @@ void Servo_Handler(timer16_Sequence_t timer, Tc *pTc, uint8_t channel);
void HANDLER_FOR_TIMER5() { Servo_Handler(_timer5, TC_FOR_TIMER5, CHANNEL_FOR_TIMER5); } void HANDLER_FOR_TIMER5() { Servo_Handler(_timer5, TC_FOR_TIMER5, CHANNEL_FOR_TIMER5); }
#endif #endif
void Servo_Handler(timer16_Sequence_t timer, Tc *tc, uint8_t channel) { void Servo_Handler(const timer16_Sequence_t timer, Tc *tc, const uint8_t channel) {
// clear interrupt static int8_t Channel[_Nbr_16timers]; // Servo counters to pulse (or -1 for refresh interval)
tc->TC_CHANNEL[channel].TC_SR; int8_t cho = Channel[timer]; // Handle the prior Channel[timer] first
if (Channel[timer] < 0) if (cho < 0) { // Channel -1 indicates the refresh interval completed...
tc->TC_CHANNEL[channel].TC_CCR |= TC_CCR_SWTRG; // channel set to -1 indicated that refresh interval completed so reset the timer tc->TC_CHANNEL[channel].TC_CCR |= TC_CCR_SWTRG; // ...so reset the timer
else if (SERVO_INDEX(timer, Channel[timer]) < ServoCount && SERVO(timer, Channel[timer]).Pin.isActive) if (DisablePending[timer]) {
extDigitalWrite(SERVO(timer, Channel[timer]).Pin.nbr, LOW); // pulse this channel low if activated // Disabling only after the full servo period expires prevents
// pulses being too close together if immediately re-enabled.
DisablePending.clear(timer);
TC_Stop(tc, channel);
tc->TC_CHANNEL[channel].TC_SR; // clear interrupt
return;
}
}
else if (SERVO_INDEX(timer, cho) < ServoCount) // prior channel handled?
extDigitalWrite(SERVO(timer, cho).Pin.nbr, LOW); // pulse the prior channel LOW
Channel[timer]++; // increment to the next channel Channel[timer] = ++cho; // go to the next channel (or 0)
if (SERVO_INDEX(timer, Channel[timer]) < ServoCount && Channel[timer] < SERVOS_PER_TIMER) { if (cho < SERVOS_PER_TIMER && SERVO_INDEX(timer, cho) < ServoCount) {
tc->TC_CHANNEL[channel].TC_RA = tc->TC_CHANNEL[channel].TC_CV + SERVO(timer,Channel[timer]).ticks; tc->TC_CHANNEL[channel].TC_RA = tc->TC_CHANNEL[channel].TC_CV + SERVO(timer, cho).ticks;
if (SERVO(timer,Channel[timer]).Pin.isActive) // check if activated if (SERVO(timer, cho).Pin.isActive) // activated?
extDigitalWrite(SERVO(timer, Channel[timer]).Pin.nbr, HIGH); // its an active channel so pulse it high extDigitalWrite(SERVO(timer, cho).Pin.nbr, HIGH); // yes: pulse HIGH
} }
else { else {
// finished all channels so wait for the refresh period to expire before starting over // finished all channels so wait for the refresh period to expire before starting over
tc->TC_CHANNEL[channel].TC_RA = const unsigned int cval = tc->TC_CHANNEL[channel].TC_CV + 128 / (SERVO_TIMER_PRESCALER), // allow 128 cycles to ensure the next CV not missed
tc->TC_CHANNEL[channel].TC_CV < usToTicks(REFRESH_INTERVAL) - 4 ival = (unsigned int)usToTicks(REFRESH_INTERVAL); // at least REFRESH_INTERVAL has elapsed
? (unsigned int)usToTicks(REFRESH_INTERVAL) // allow a few ticks to ensure the next OCR1A not missed tc->TC_CHANNEL[channel].TC_RA = max(cval, ival);
: tc->TC_CHANNEL[channel].TC_CV + 4; // at least REFRESH_INTERVAL has elapsed
Channel[timer] = -1; // this will get incremented at the end of the refresh period to start again at the first channel Channel[timer] = -1; // reset the timer CCR on the next call
} }
tc->TC_CHANNEL[channel].TC_SR; // clear interrupt
} }
static void _initISR(Tc *tc, uint32_t channel, uint32_t id, IRQn_Type irqn) { static void _initISR(Tc *tc, uint32_t channel, uint32_t id, IRQn_Type irqn) {
pmc_enable_periph_clk(id); pmc_enable_periph_clk(id);
TC_Configure(tc, channel, TC_Configure(tc, channel,
TC_CMR_TCCLKS_TIMER_CLOCK3 | // MCK/32 TC_CMR_WAVE // Waveform mode
TC_CMR_WAVE | // Waveform mode | TC_CMR_WAVSEL_UP_RC // Counter running up and reset when equal to RC
TC_CMR_WAVSEL_UP_RC ); // Counter running up and reset when equals to RC | (SERVO_TIMER_PRESCALER == 2 ? TC_CMR_TCCLKS_TIMER_CLOCK1 : 0) // MCK/2
| (SERVO_TIMER_PRESCALER == 8 ? TC_CMR_TCCLKS_TIMER_CLOCK2 : 0) // MCK/8
| (SERVO_TIMER_PRESCALER == 32 ? TC_CMR_TCCLKS_TIMER_CLOCK3 : 0) // MCK/32
| (SERVO_TIMER_PRESCALER == 128 ? TC_CMR_TCCLKS_TIMER_CLOCK4 : 0) // MCK/128
);
/* 84MHz, MCK/32, for 1.5ms: 3937 */ // Wait 1ms before the first ISR
TC_SetRA(tc, channel, 2625); // 1ms TC_SetRA(tc, channel, (F_CPU) / (SERVO_TIMER_PRESCALER) / 1000UL); // 1ms
/* Configure and enable interrupt */ // Configure and enable interrupt
NVIC_EnableIRQ(irqn); NVIC_EnableIRQ(irqn);
// TC_IER_CPAS: RA Compare tc->TC_CHANNEL[channel].TC_IER = TC_IER_CPAS; // TC_IER_CPAS: RA Compare
tc->TC_CHANNEL[channel].TC_IER = TC_IER_CPAS;
// Enables the timer clock and performs a software reset to start the counting // Enables the timer clock and performs a software reset to start the counting
TC_Start(tc, channel); TC_Start(tc, channel);
} }
void initISR(timer16_Sequence_t timer) { void initISR(const timer16_Sequence_t timer_index) {
#ifdef _useTimer1 CRITICAL_SECTION_START();
if (timer == _timer1) const bool disable_soon = DisablePending[timer_index];
_initISR(TC_FOR_TIMER1, CHANNEL_FOR_TIMER1, ID_TC_FOR_TIMER1, IRQn_FOR_TIMER1); DisablePending.clear(timer_index);
#endif CRITICAL_SECTION_END();
#ifdef _useTimer2
if (timer == _timer2) if (!disable_soon) switch (timer_index) {
_initISR(TC_FOR_TIMER2, CHANNEL_FOR_TIMER2, ID_TC_FOR_TIMER2, IRQn_FOR_TIMER2); default: break;
#endif #ifdef _useTimer1
#ifdef _useTimer3 case _timer1: return _initISR(TC_FOR_TIMER1, CHANNEL_FOR_TIMER1, ID_TC_FOR_TIMER1, IRQn_FOR_TIMER1);
if (timer == _timer3) #endif
_initISR(TC_FOR_TIMER3, CHANNEL_FOR_TIMER3, ID_TC_FOR_TIMER3, IRQn_FOR_TIMER3); #ifdef _useTimer2
#endif case _timer2: return _initISR(TC_FOR_TIMER2, CHANNEL_FOR_TIMER2, ID_TC_FOR_TIMER2, IRQn_FOR_TIMER2);
#ifdef _useTimer4 #endif
if (timer == _timer4) #ifdef _useTimer3
_initISR(TC_FOR_TIMER4, CHANNEL_FOR_TIMER4, ID_TC_FOR_TIMER4, IRQn_FOR_TIMER4); case _timer3: return _initISR(TC_FOR_TIMER3, CHANNEL_FOR_TIMER3, ID_TC_FOR_TIMER3, IRQn_FOR_TIMER3);
#endif #endif
#ifdef _useTimer5 #ifdef _useTimer4
if (timer == _timer5) case _timer4: return _initISR(TC_FOR_TIMER4, CHANNEL_FOR_TIMER4, ID_TC_FOR_TIMER4, IRQn_FOR_TIMER4);
_initISR(TC_FOR_TIMER5, CHANNEL_FOR_TIMER5, ID_TC_FOR_TIMER5, IRQn_FOR_TIMER5); #endif
#endif #ifdef _useTimer5
case _timer5: return _initISR(TC_FOR_TIMER5, CHANNEL_FOR_TIMER5, ID_TC_FOR_TIMER5, IRQn_FOR_TIMER5);
#endif
}
} }
void finISR(timer16_Sequence_t) { void finISR(const timer16_Sequence_t timer_index) {
#ifdef _useTimer1 // Timer is disabled from the ISR, to ensure proper final pulse length.
TC_Stop(TC_FOR_TIMER1, CHANNEL_FOR_TIMER1); DisablePending.set(timer_index);
#endif
#ifdef _useTimer2
TC_Stop(TC_FOR_TIMER2, CHANNEL_FOR_TIMER2);
#endif
#ifdef _useTimer3
TC_Stop(TC_FOR_TIMER3, CHANNEL_FOR_TIMER3);
#endif
#ifdef _useTimer4
TC_Stop(TC_FOR_TIMER4, CHANNEL_FOR_TIMER4);
#endif
#ifdef _useTimer5
TC_Stop(TC_FOR_TIMER5, CHANNEL_FOR_TIMER5);
#endif
} }
#endif // HAS_SERVOS #endif // HAS_SERVOS

View File

@ -37,7 +37,7 @@
#define _useTimer5 #define _useTimer5
#define TRIM_DURATION 2 // compensation ticks to trim adjust for digitalWrite delays #define TRIM_DURATION 2 // compensation ticks to trim adjust for digitalWrite delays
#define SERVO_TIMER_PRESCALER 32 // timer prescaler #define SERVO_TIMER_PRESCALER 2 // timer prescaler
/* /*
TC0, chan 0 => TC0_Handler TC0, chan 0 => TC0_Handler

View File

@ -35,20 +35,20 @@
static pin_t tone_pin; static pin_t tone_pin;
volatile static int32_t toggles; volatile static int32_t toggles;
void tone(const pin_t _pin, const unsigned int frequency, const unsigned long duration) { void tone(const pin_t _pin, const unsigned int frequency, const unsigned long duration/*=0*/) {
tone_pin = _pin; tone_pin = _pin;
toggles = 2 * frequency * duration / 1000; toggles = 2 * frequency * duration / 1000;
HAL_timer_start(TONE_TIMER_NUM, 2 * frequency); HAL_timer_start(MF_TIMER_TONE, 2 * frequency);
} }
void noTone(const pin_t _pin) { void noTone(const pin_t _pin) {
HAL_timer_disable_interrupt(TONE_TIMER_NUM); HAL_timer_disable_interrupt(MF_TIMER_TONE);
extDigitalWrite(_pin, LOW); extDigitalWrite(_pin, LOW);
} }
HAL_TONE_TIMER_ISR() { HAL_TONE_TIMER_ISR() {
static uint8_t pin_state = 0; static uint8_t pin_state = 0;
HAL_timer_isr_prologue(TONE_TIMER_NUM); HAL_timer_isr_prologue(MF_TIMER_TONE);
if (toggles) { if (toggles) {
toggles--; toggles--;

View File

@ -20,7 +20,6 @@
* *
*/ */
/** /**
* Based on u8g_com_msp430_hw_spi.c * Based on u8g_com_msp430_hw_spi.c
* *
@ -60,16 +59,15 @@
#if HAS_MARLINUI_U8GLIB #if HAS_MARLINUI_U8GLIB
#include <U8glib.h> #include <U8glib-HAL.h>
#include "../../../MarlinCore.h" #include "../../../MarlinCore.h"
void spiBegin(); #ifndef LCD_SPI_SPEED
void spiInit(uint8_t spiRate); #define LCD_SPI_SPEED SPI_QUARTER_SPEED
void spiSend(uint8_t b); #endif
void spiSend(const uint8_t* buf, size_t n);
#include "../../shared/Marduino.h" #include "../../shared/HAL_SPI.h"
#include "../fastio.h" #include "../fastio.h"
void u8g_SetPIOutput_DUE_hw_spi(u8g_t *u8g, uint8_t pin_index) { void u8g_SetPIOutput_DUE_hw_spi(u8g_t *u8g, uint8_t pin_index) {
@ -100,11 +98,7 @@ uint8_t u8g_com_HAL_DUE_shared_hw_spi_fn(u8g_t *u8g, uint8_t msg, uint8_t arg_va
spiBegin(); spiBegin();
#ifndef SPI_SPEED spiInit(LCD_SPI_SPEED);
#define SPI_SPEED SPI_FULL_SPEED // use same SPI speed as SD card
#endif
spiInit(2);
break; break;
case U8G_COM_MSG_ADDRESS: /* define cmd (arg_val = 0) or data mode (arg_val = 1) */ case U8G_COM_MSG_ADDRESS: /* define cmd (arg_val = 0) or data mode (arg_val = 1) */

View File

@ -57,11 +57,12 @@
#include "../../../inc/MarlinConfigPre.h" #include "../../../inc/MarlinConfigPre.h"
#if ENABLED(U8GLIB_ST7920) #if IS_U8GLIB_ST7920
#include "../../../inc/MarlinConfig.h"
#include "../../shared/Delay.h" #include "../../shared/Delay.h"
#include <U8glib.h> #include <U8glib-HAL.h>
#include "u8g_com_HAL_DUE_sw_spi_shared.h" #include "u8g_com_HAL_DUE_sw_spi_shared.h"
@ -145,7 +146,7 @@ uint8_t u8g_com_HAL_DUE_ST7920_sw_spi_fn(u8g_t *u8g, uint8_t msg, uint8_t arg_va
} }
#if ENABLED(LIGHTWEIGHT_UI) #if ENABLED(LIGHTWEIGHT_UI)
#include "../../../lcd/ultralcd.h" #include "../../../lcd/marlinui.h"
#include "../../shared/HAL_ST7920.h" #include "../../shared/HAL_ST7920.h"
#define ST7920_CS_PIN LCD_PINS_RS #define ST7920_CS_PIN LCD_PINS_RS
@ -181,5 +182,5 @@ uint8_t u8g_com_HAL_DUE_ST7920_sw_spi_fn(u8g_t *u8g, uint8_t msg, uint8_t arg_va
} }
#endif // LIGHTWEIGHT_UI #endif // LIGHTWEIGHT_UI
#endif // U8GLIB_ST7920 #endif // IS_U8GLIB_ST7920
#endif // ARDUINO_ARCH_SAM #endif // ARDUINO_ARCH_SAM

View File

@ -57,17 +57,14 @@
#include "../../../inc/MarlinConfigPre.h" #include "../../../inc/MarlinConfigPre.h"
#if HAS_MARLINUI_U8GLIB && DISABLED(U8GLIB_ST7920) #if HAS_MARLINUI_U8GLIB && !IS_U8GLIB_ST7920
#undef SPI_SPEED
#define SPI_SPEED 2 // About 2 MHz
#include "u8g_com_HAL_DUE_sw_spi_shared.h" #include "u8g_com_HAL_DUE_sw_spi_shared.h"
#include "../../shared/Marduino.h" #include "../../shared/Marduino.h"
#include "../../shared/Delay.h" #include "../../shared/Delay.h"
#include <U8glib.h> #include <U8glib-HAL.h>
#if ENABLED(FYSETC_MINI_12864) #if ENABLED(FYSETC_MINI_12864)
#define SPISEND_SW_DUE u8g_spiSend_sw_DUE_mode_3 #define SPISEND_SW_DUE u8g_spiSend_sw_DUE_mode_3
@ -144,5 +141,5 @@ uint8_t u8g_com_HAL_DUE_sw_spi_fn(u8g_t *u8g, uint8_t msg, uint8_t arg_val, void
return 1; return 1;
} }
#endif // HAS_MARLINUI_U8GLIB && !U8GLIB_ST7920 #endif // HAS_MARLINUI_U8GLIB && !IS_U8GLIB_ST7920
#endif // ARDUINO_ARCH_SAM #endif // ARDUINO_ARCH_SAM

View File

@ -59,9 +59,10 @@
#if HAS_MARLINUI_U8GLIB #if HAS_MARLINUI_U8GLIB
#include "../../../inc/MarlinConfig.h"
#include "../../shared/Delay.h" #include "../../shared/Delay.h"
#include <U8glib.h> #include <U8glib-HAL.h>
#include "u8g_com_HAL_DUE_sw_spi_shared.h" #include "u8g_com_HAL_DUE_sw_spi_shared.h"

View File

@ -23,7 +23,7 @@
#include "../../../inc/MarlinConfigPre.h" #include "../../../inc/MarlinConfigPre.h"
#include "../../shared/Marduino.h" #include "../../shared/Marduino.h"
#include <U8glib.h> #include <U8glib-HAL.h>
void u8g_SetPIOutput_DUE(u8g_t *u8g, uint8_t pin_index); void u8g_SetPIOutput_DUE(u8g_t *u8g, uint8_t pin_index);
void u8g_SetPILevel_DUE(u8g_t *u8g, uint8_t pin_index, uint8_t level); void u8g_SetPILevel_DUE(u8g_t *u8g, uint8_t pin_index, uint8_t level);

View File

@ -135,11 +135,11 @@ static uint8_t buffer[256] = {0}, // The RAM buffer to accumulate writes
#define DEBUG_OUT ENABLED(EE_EMU_DEBUG) #define DEBUG_OUT ENABLED(EE_EMU_DEBUG)
#include "../../core/debug_out.h" #include "../../core/debug_out.h"
static void ee_Dump(const int page, const void* data) { static void ee_Dump(const int page, const void *data) {
#ifdef EE_EMU_DEBUG #ifdef EE_EMU_DEBUG
const uint8_t* c = (const uint8_t*) data; const uint8_t *c = (const uint8_t*) data;
char buffer[80]; char buffer[80];
sprintf_P(buffer, PSTR("Page: %d (0x%04x)\n"), page, page); sprintf_P(buffer, PSTR("Page: %d (0x%04x)\n"), page, page);
@ -181,7 +181,7 @@ static void ee_Dump(const int page, const void* data) {
* @param data (pointer to the data buffer) * @param data (pointer to the data buffer)
*/ */
__attribute__ ((long_call, section (".ramfunc"))) __attribute__ ((long_call, section (".ramfunc")))
static bool ee_PageWrite(uint16_t page, const void* data) { static bool ee_PageWrite(uint16_t page, const void *data) {
uint16_t i; uint16_t i;
uint32_t addrflash = uint32_t(getFlashStorage(page)); uint32_t addrflash = uint32_t(getFlashStorage(page));
@ -199,10 +199,9 @@ static bool ee_PageWrite(uint16_t page, const void* data) {
for (i = 0; i <PageSize >> 2; i++) for (i = 0; i <PageSize >> 2; i++)
pageContents[i] = (((uint32_t*)data)[i]) | (~(pageContents[i] ^ ((uint32_t*)data)[i])); pageContents[i] = (((uint32_t*)data)[i]) | (~(pageContents[i] ^ ((uint32_t*)data)[i]));
DEBUG_ECHO_START(); DEBUG_ECHO_MSG("EEPROM PageWrite ", page);
DEBUG_ECHOLNPAIR("EEPROM PageWrite ", page); DEBUG_ECHOLNPGM(" in FLASH address ", (uint32_t)addrflash);
DEBUG_ECHOLNPAIR(" in FLASH address ", (uint32_t)addrflash); DEBUG_ECHOLNPGM(" base address ", (uint32_t)getFlashStorage(0));
DEBUG_ECHOLNPAIR(" base address ", (uint32_t)getFlashStorage(0));
DEBUG_FLUSH(); DEBUG_FLUSH();
// Get the page relative to the start of the EFC controller, and the EFC controller to use // Get the page relative to the start of the EFC controller, and the EFC controller to use
@ -245,8 +244,7 @@ static bool ee_PageWrite(uint16_t page, const void* data) {
// Reenable interrupts // Reenable interrupts
__enable_irq(); __enable_irq();
DEBUG_ECHO_START(); DEBUG_ECHO_MSG("EEPROM Unlock failure for page ", page);
DEBUG_ECHOLNPAIR("EEPROM Unlock failure for page ", page);
return false; return false;
} }
@ -270,8 +268,7 @@ static bool ee_PageWrite(uint16_t page, const void* data) {
// Reenable interrupts // Reenable interrupts
__enable_irq(); __enable_irq();
DEBUG_ECHO_START(); DEBUG_ECHO_MSG("EEPROM Write failure for page ", page);
DEBUG_ECHOLNPAIR("EEPROM Write failure for page ", page);
return false; return false;
} }
@ -286,15 +283,14 @@ static bool ee_PageWrite(uint16_t page, const void* data) {
if (memcmp(getFlashStorage(page),data,PageSize)) { if (memcmp(getFlashStorage(page),data,PageSize)) {
#ifdef EE_EMU_DEBUG #ifdef EE_EMU_DEBUG
DEBUG_ECHO_START(); DEBUG_ECHO_MSG("EEPROM Verify Write failure for page ", page);
DEBUG_ECHOLNPAIR("EEPROM Verify Write failure for page ", page);
ee_Dump( page, (uint32_t *)addrflash); ee_Dump( page, (uint32_t *)addrflash);
ee_Dump(-page, data); ee_Dump(-page, data);
// Calculate count of changed bits // Calculate count of changed bits
uint32_t* p1 = (uint32_t*)addrflash; uint32_t *p1 = (uint32_t*)addrflash;
uint32_t* p2 = (uint32_t*)data; uint32_t *p2 = (uint32_t*)data;
int count = 0; int count = 0;
for (i =0; i<PageSize >> 2; i++) { for (i =0; i<PageSize >> 2; i++) {
if (p1[i] != p2[i]) { if (p1[i] != p2[i]) {
@ -306,7 +302,7 @@ static bool ee_PageWrite(uint16_t page, const void* data) {
} }
} }
} }
DEBUG_ECHOLNPAIR("--> Differing bits: ", count); DEBUG_ECHOLNPGM("--> Differing bits: ", count);
#endif #endif
return false; return false;
@ -325,10 +321,9 @@ static bool ee_PageErase(uint16_t page) {
uint16_t i; uint16_t i;
uint32_t addrflash = uint32_t(getFlashStorage(page)); uint32_t addrflash = uint32_t(getFlashStorage(page));
DEBUG_ECHO_START(); DEBUG_ECHO_MSG("EEPROM PageErase ", page);
DEBUG_ECHOLNPAIR("EEPROM PageErase ", page); DEBUG_ECHOLNPGM(" in FLASH address ", (uint32_t)addrflash);
DEBUG_ECHOLNPAIR(" in FLASH address ", (uint32_t)addrflash); DEBUG_ECHOLNPGM(" base address ", (uint32_t)getFlashStorage(0));
DEBUG_ECHOLNPAIR(" base address ", (uint32_t)getFlashStorage(0));
DEBUG_FLUSH(); DEBUG_FLUSH();
// Get the page relative to the start of the EFC controller, and the EFC controller to use // Get the page relative to the start of the EFC controller, and the EFC controller to use
@ -370,8 +365,7 @@ static bool ee_PageErase(uint16_t page) {
// Reenable interrupts // Reenable interrupts
__enable_irq(); __enable_irq();
DEBUG_ECHO_START(); DEBUG_ECHO_MSG("EEPROM Unlock failure for page ",page);
DEBUG_ECHOLNPAIR("EEPROM Unlock failure for page ",page);
return false; return false;
} }
@ -394,8 +388,7 @@ static bool ee_PageErase(uint16_t page) {
// Reenable interrupts // Reenable interrupts
__enable_irq(); __enable_irq();
DEBUG_ECHO_START(); DEBUG_ECHO_MSG("EEPROM Erase failure for page ",page);
DEBUG_ECHOLNPAIR("EEPROM Erase failure for page ",page);
return false; return false;
} }
@ -410,8 +403,7 @@ static bool ee_PageErase(uint16_t page) {
uint32_t * aligned_src = (uint32_t *) addrflash; uint32_t * aligned_src = (uint32_t *) addrflash;
for (i = 0; i < PageSize >> 2; i++) { for (i = 0; i < PageSize >> 2; i++) {
if (*aligned_src++ != 0xFFFFFFFF) { if (*aligned_src++ != 0xFFFFFFFF) {
DEBUG_ECHO_START(); DEBUG_ECHO_MSG("EEPROM Verify Erase failure for page ",page);
DEBUG_ECHOLNPAIR("EEPROM Verify Erase failure for page ",page);
ee_Dump(page, (uint32_t *)addrflash); ee_Dump(page, (uint32_t *)addrflash);
return false; return false;
} }
@ -470,7 +462,7 @@ static uint8_t ee_Read(uint32_t address, bool excludeRAMBuffer=false) {
for (int page = curPage - 1; page >= 0; --page) { for (int page = curPage - 1; page >= 0; --page) {
// Get a pointer to the flash page // Get a pointer to the flash page
uint8_t* pflash = (uint8_t*)getFlashStorage(page + curGroup * PagesPerGroup); uint8_t *pflash = (uint8_t*)getFlashStorage(page + curGroup * PagesPerGroup);
uint16_t i = 0; uint16_t i = 0;
while (i <= (PageSize - 4)) { /* (PageSize - 4) because otherwise, there is not enough room for data and headers */ while (i <= (PageSize - 4)) { /* (PageSize - 4) because otherwise, there is not enough room for data and headers */
@ -550,7 +542,7 @@ static uint32_t ee_GetAddrRange(uint32_t address, bool excludeRAMBuffer=false) {
for (int page = curPage - 1; page >= 0; --page) { for (int page = curPage - 1; page >= 0; --page) {
// Get a pointer to the flash page // Get a pointer to the flash page
uint8_t* pflash = (uint8_t*)getFlashStorage(page + curGroup * PagesPerGroup); uint8_t *pflash = (uint8_t*)getFlashStorage(page + curGroup * PagesPerGroup);
uint16_t i = 0; uint16_t i = 0;
while (i <= (PageSize - 4)) { /* (PageSize - 4) because otherwise, there is not enough room for data and headers */ while (i <= (PageSize - 4)) { /* (PageSize - 4) because otherwise, there is not enough room for data and headers */
@ -589,7 +581,7 @@ static uint32_t ee_GetAddrRange(uint32_t address, bool excludeRAMBuffer=false) {
} }
static bool ee_IsPageClean(int page) { static bool ee_IsPageClean(int page) {
uint32_t* pflash = (uint32_t*) getFlashStorage(page); uint32_t *pflash = (uint32_t*) getFlashStorage(page);
for (uint16_t i = 0; i < (PageSize >> 2); ++i) for (uint16_t i = 0; i < (PageSize >> 2); ++i)
if (*pflash++ != 0xFFFFFFFF) return false; if (*pflash++ != 0xFFFFFFFF) return false;
return true; return true;
@ -599,7 +591,7 @@ static bool ee_Flush(uint32_t overrideAddress = 0xFFFFFFFF, uint8_t overrideData
// Check if RAM buffer has something to be written // Check if RAM buffer has something to be written
bool isEmpty = true; bool isEmpty = true;
uint32_t* p = (uint32_t*) &buffer[0]; uint32_t *p = (uint32_t*) &buffer[0];
for (uint16_t j = 0; j < (PageSize >> 2); j++) { for (uint16_t j = 0; j < (PageSize >> 2); j++) {
if (*p++ != 0xFFFFFFFF) { if (*p++ != 0xFFFFFFFF) {
isEmpty = false; isEmpty = false;
@ -921,8 +913,7 @@ static void ee_Init() {
// If all groups seem to be used, default to first group // If all groups seem to be used, default to first group
if (curGroup >= GroupCount) curGroup = 0; if (curGroup >= GroupCount) curGroup = 0;
DEBUG_ECHO_START(); DEBUG_ECHO_MSG("EEPROM Current Group: ",curGroup);
DEBUG_ECHOLNPAIR("EEPROM Current Group: ",curGroup);
DEBUG_FLUSH(); DEBUG_FLUSH();
// Now, validate that all the other group pages are empty // Now, validate that all the other group pages are empty
@ -931,8 +922,7 @@ static void ee_Init() {
for (int page = 0; page < PagesPerGroup; page++) { for (int page = 0; page < PagesPerGroup; page++) {
if (!ee_IsPageClean(grp * PagesPerGroup + page)) { if (!ee_IsPageClean(grp * PagesPerGroup + page)) {
DEBUG_ECHO_START(); DEBUG_ECHO_MSG("EEPROM Page ", page, " not clean on group ", grp);
DEBUG_ECHOLNPAIR("EEPROM Page ", page, " not clean on group ", grp);
DEBUG_FLUSH(); DEBUG_FLUSH();
ee_PageErase(grp * PagesPerGroup + page); ee_PageErase(grp * PagesPerGroup + page);
} }
@ -948,15 +938,13 @@ static void ee_Init() {
} }
} }
DEBUG_ECHO_START(); DEBUG_ECHO_MSG("EEPROM Active page: ", curPage);
DEBUG_ECHOLNPAIR("EEPROM Active page: ", curPage);
DEBUG_FLUSH(); DEBUG_FLUSH();
// Make sure the pages following the first clean one are also clean // Make sure the pages following the first clean one are also clean
for (int page = curPage + 1; page < PagesPerGroup; page++) { for (int page = curPage + 1; page < PagesPerGroup; page++) {
if (!ee_IsPageClean(curGroup * PagesPerGroup + page)) { if (!ee_IsPageClean(curGroup * PagesPerGroup + page)) {
DEBUG_ECHO_START(); DEBUG_ECHO_MSG("EEPROM Page ", page, " not clean on active group ", curGroup);
DEBUG_ECHOLNPAIR("EEPROM Page ", page, " not clean on active group ", curGroup);
DEBUG_FLUSH(); DEBUG_FLUSH();
ee_Dump(curGroup * PagesPerGroup + page, getFlashStorage(curGroup * PagesPerGroup + page)); ee_Dump(curGroup * PagesPerGroup + page, getFlashStorage(curGroup * PagesPerGroup + page));
ee_PageErase(curGroup * PagesPerGroup + page); ee_PageErase(curGroup * PagesPerGroup + page);
@ -976,14 +964,13 @@ bool PersistentStore::access_start() { ee_Init(); return true; }
bool PersistentStore::access_finish() { ee_Flush(); return true; } bool PersistentStore::access_finish() { ee_Flush(); return true; }
bool PersistentStore::write_data(int &pos, const uint8_t *value, size_t size, uint16_t *crc) { bool PersistentStore::write_data(int &pos, const uint8_t *value, size_t size, uint16_t *crc) {
uint16_t written = 0;
while (size--) { while (size--) {
uint8_t * const p = (uint8_t * const)pos; uint8_t * const p = (uint8_t * const)pos;
uint8_t v = *value; uint8_t v = *value;
// EEPROM has only ~100,000 write cycles, if (v != ee_Read(uint32_t(p))) { // EEPROM has only ~100,000 write cycles, so only write bytes that have changed!
// so only write bytes that have changed!
if (v != ee_Read(uint32_t(p))) {
ee_Write(uint32_t(p), v); ee_Write(uint32_t(p), v);
delay(2); if (++written & 0x7F) delay(2); else safe_delay(2); // Avoid triggering watchdog during long EEPROM writes
if (ee_Read(uint32_t(p)) != v) { if (ee_Read(uint32_t(p)) != v) {
SERIAL_ECHO_MSG(STR_ERR_EEPROM_WRITE); SERIAL_ECHO_MSG(STR_ERR_EEPROM_WRITE);
return true; return true;
@ -996,7 +983,7 @@ bool PersistentStore::write_data(int &pos, const uint8_t *value, size_t size, ui
return false; return false;
} }
bool PersistentStore::read_data(int &pos, uint8_t* value, size_t size, uint16_t *crc, const bool writing/*=true*/) { bool PersistentStore::read_data(int &pos, uint8_t *value, size_t size, uint16_t *crc, const bool writing/*=true*/) {
do { do {
uint8_t c = ee_Read(uint32_t(pos)); uint8_t c = ee_Read(uint32_t(pos));
if (writing) *value = c; if (writing) *value = c;

View File

@ -42,14 +42,13 @@ bool PersistentStore::access_start() { eeprom_init(); return true; }
bool PersistentStore::access_finish() { return true; } bool PersistentStore::access_finish() { return true; }
bool PersistentStore::write_data(int &pos, const uint8_t *value, size_t size, uint16_t *crc) { bool PersistentStore::write_data(int &pos, const uint8_t *value, size_t size, uint16_t *crc) {
uint16_t written = 0;
while (size--) { while (size--) {
uint8_t * const p = (uint8_t * const)pos; uint8_t * const p = (uint8_t * const)pos;
uint8_t v = *value; uint8_t v = *value;
// EEPROM has only ~100,000 write cycles, if (v != eeprom_read_byte(p)) { // EEPROM has only ~100,000 write cycles, so only write bytes that have changed!
// so only write bytes that have changed!
if (v != eeprom_read_byte(p)) {
eeprom_write_byte(p, v); eeprom_write_byte(p, v);
delay(2); if (++written & 0x7F) delay(2); else safe_delay(2); // Avoid triggering watchdog during long EEPROM writes
if (eeprom_read_byte(p) != v) { if (eeprom_read_byte(p) != v) {
SERIAL_ECHO_MSG(STR_ERR_EEPROM_WRITE); SERIAL_ECHO_MSG(STR_ERR_EEPROM_WRITE);
return true; return true;
@ -62,7 +61,7 @@ bool PersistentStore::write_data(int &pos, const uint8_t *value, size_t size, ui
return false; return false;
} }
bool PersistentStore::read_data(int &pos, uint8_t* value, size_t size, uint16_t *crc, const bool writing/*=true*/) { bool PersistentStore::read_data(int &pos, uint8_t *value, size_t size, uint16_t *crc, const bool writing/*=true*/) {
do { do {
uint8_t c = eeprom_read_byte((uint8_t*)pos); uint8_t c = eeprom_read_byte((uint8_t*)pos);
if (writing) *value = c; if (writing) *value = c;

View File

@ -64,4 +64,16 @@ void setup_endstop_interrupts() {
TERN_(HAS_Z4_MAX, _ATTACH(Z4_MAX_PIN)); TERN_(HAS_Z4_MAX, _ATTACH(Z4_MAX_PIN));
TERN_(HAS_Z4_MIN, _ATTACH(Z4_MIN_PIN)); TERN_(HAS_Z4_MIN, _ATTACH(Z4_MIN_PIN));
TERN_(HAS_Z_MIN_PROBE_PIN, _ATTACH(Z_MIN_PROBE_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));
} }

View File

@ -33,7 +33,7 @@
* For ARDUINO_ARCH_SAM * For ARDUINO_ARCH_SAM
* Note the code here was specifically crafted by disassembling what GCC produces * Note the code here was specifically crafted by disassembling what GCC produces
* out of it, so GCC is able to optimize it out as much as possible to the least * out of it, so GCC is able to optimize it out as much as possible to the least
* amount of instructions. Be very carefull if you modify them, as "clean code" * amount of instructions. Be very careful if you modify them, as "clean code"
* leads to less efficient compiled code!! * leads to less efficient compiled code!!
*/ */
@ -50,7 +50,7 @@
#define PWM_PIN(P) WITHIN(P, 2, 13) #define PWM_PIN(P) WITHIN(P, 2, 13)
#ifndef MASK #ifndef MASK
#define MASK(PIN) (1 << PIN) #define MASK(PIN) _BV(PIN)
#endif #endif
/** /**
@ -163,6 +163,9 @@
#define SET_INPUT(IO) _SET_INPUT(IO) #define SET_INPUT(IO) _SET_INPUT(IO)
// Set pin as input with pullup (wrapper) // Set pin as input with pullup (wrapper)
#define SET_INPUT_PULLUP(IO) do{ _SET_INPUT(IO); _PULLUP(IO, HIGH); }while(0) #define SET_INPUT_PULLUP(IO) do{ _SET_INPUT(IO); _PULLUP(IO, HIGH); }while(0)
// Set pin as input with pulldown (substitution)
#define SET_INPUT_PULLDOWN SET_INPUT
// Set pin as output (wrapper) - reads the pin and sets the output to that value // Set pin as output (wrapper) - reads the pin and sets the output to that value
#define SET_OUTPUT(IO) _SET_OUTPUT(IO) #define SET_OUTPUT(IO) _SET_OUTPUT(IO)
// Set pin as PWM // Set pin as PWM
@ -477,7 +480,7 @@
#define DIO91_PIN 15 #define DIO91_PIN 15
#define DIO91_WPORT PIOB #define DIO91_WPORT PIOB
#if ARDUINO_SAM_ARCHIM #ifdef ARDUINO_SAM_ARCHIM
#define DIO92_PIN 11 #define DIO92_PIN 11
#define DIO92_WPORT PIOC #define DIO92_WPORT PIOC

View File

@ -25,7 +25,7 @@
* is NOT used to directly toggle pins. The ISR writes to the pin assigned to * is NOT used to directly toggle pins. The ISR writes to the pin assigned to
* that interrupt. * that interrupt.
* *
* All PWMs use the same repetition rate. The G2 needs about 10KHz min in order to * All PWMs use the same repetition rate. The G2 needs about 10kHz min in order to
* not have obvious ripple on the Vref signals. * not have obvious ripple on the Vref signals.
* *
* The data structures are setup to minimize the computation done by the ISR which * The data structures are setup to minimize the computation done by the ISR which

View File

@ -25,6 +25,30 @@
* Test Arduino Due specific configuration values for errors at compile-time. * Test Arduino Due specific configuration values for errors at compile-time.
*/ */
/**
* 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 \
)
#if SERIAL_IN_USE(0) // D0-D1. No known conflicts.
#endif
#if SERIAL_IN_USE(1) && (CHECK_SERIAL_PIN(18) || CHECK_SERIAL_PIN(19))
#error "Serial Port 1 pin D18 and/or D19 conflicts with another pin on the board."
#endif
#if SERIAL_IN_USE(2) && (CHECK_SERIAL_PIN(16) || CHECK_SERIAL_PIN(17))
#error "Serial Port 2 pin D16 and/or D17 conflicts with another pin on the board."
#endif
#if SERIAL_IN_USE(3) && (CHECK_SERIAL_PIN(14) || CHECK_SERIAL_PIN(15))
#error "Serial Port 3 pin D14 and/or D15 conflicts with another pin on the board."
#endif
#undef CHECK_SERIAL_PIN
/** /**
* HARDWARE VS. SOFTWARE SPI COMPATIBILITY * HARDWARE VS. SOFTWARE SPI COMPATIBILITY
* *
@ -40,7 +64,7 @@
* Usually the hardware SPI pins are only available to the LCD. This makes the DUE hard SPI used at the same time * 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. * as the TMC2130 soft SPI the most common setup.
*/ */
#define _IS_HW_SPI(P) (defined(TMC_SW_##P) && (TMC_SW_##P == MOSI_PIN || TMC_SW_##P == MISO_PIN || TMC_SW_##P == SCK_PIN)) #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))
#if ENABLED(SDSUPPORT) && HAS_DRIVER(TMC2130) #if ENABLED(SDSUPPORT) && HAS_DRIVER(TMC2130)
#if ENABLED(TMC_USE_SW_SPI) #if ENABLED(TMC_USE_SW_SPI)
@ -57,5 +81,9 @@
#endif #endif
#if HAS_TMC_SW_SERIAL #if HAS_TMC_SW_SERIAL
#error "TMC220x Software Serial is not supported on this platform." #error "TMC220x Software Serial is not supported on the DUE platform."
#endif
#if USING_PULLDOWNS
#error "PULLDOWN pin mode is not available on DUE boards."
#endif #endif

View File

@ -2,6 +2,9 @@
* Marlin 3D Printer Firmware * Marlin 3D Printer Firmware
* Copyright (c) 2020 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] * 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 * 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 * it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or * the Free Software Foundation, either version 3 of the License, or
@ -50,7 +53,7 @@
* The net result is that both the g_pinStatus[pin] array and the PIO_OSR register * The net result is that both the g_pinStatus[pin] array and the PIO_OSR register
* needs to be looked at when determining if a pin is an input or an output. * needs to be looked at when determining if a pin is an input or an output.
* *
* b) Due has only pins 6, 7, 8 & 9 enabled for PWMs. FYI - they run at 1KHz * b) Due has only pins 6, 7, 8 & 9 enabled for PWMs. FYI - they run at 1kHz
* *
* c) NUM_DIGITAL_PINS does not include the analog pins * c) NUM_DIGITAL_PINS does not include the analog pins
* *
@ -64,9 +67,10 @@
#define PRINT_PORT(p) #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_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(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)
#define GET_ARRAY_PIN(p) pin_array[p].pin #define GET_ARRAY_PIN(p) pin_array[p].pin
#define GET_ARRAY_IS_DIGITAL(p) pin_array[p].is_digital #define GET_ARRAY_IS_DIGITAL(p) pin_array[p].is_digital
#define VALID_PIN(pin) (pin >= 0 && pin < (int8_t)NUMBER_PINS_TOTAL ? 1 : 0) #define VALID_PIN(pin) (pin >= 0 && pin < int8_t(NUMBER_PINS_TOTAL))
#define DIGITAL_PIN_TO_ANALOG_PIN(p) int(p - analogInputToDigitalPin(0)) #define DIGITAL_PIN_TO_ANALOG_PIN(p) int(p - analogInputToDigitalPin(0))
#define IS_ANALOG(P) WITHIN(P, char(analogInputToDigitalPin(0)), char(analogInputToDigitalPin(NUM_ANALOG_INPUTS - 1))) #define IS_ANALOG(P) WITHIN(P, char(analogInputToDigitalPin(0)), char(analogInputToDigitalPin(NUM_ANALOG_INPUTS - 1)))
#define pwm_status(pin) (((g_pinStatus[pin] & 0xF) == PIN_STATUS_PWM) && \ #define pwm_status(pin) (((g_pinStatus[pin] & 0xF) == PIN_STATUS_PWM) && \
@ -82,11 +86,10 @@ bool GET_PINMODE(int8_t pin) { // 1: output, 0: input
|| pwm_status(pin)); || pwm_status(pin));
} }
void pwm_details(int32_t pin) { void pwm_details(int32_t pin) {
if (pwm_status(pin)) { if (pwm_status(pin)) {
uint32_t chan = g_APinDescription[pin].ulPWMChannel; uint32_t chan = g_APinDescription[pin].ulPWMChannel;
SERIAL_ECHOPAIR("PWM = ", PWM_INTERFACE->PWM_CH_NUM[chan].PWM_CDTY); SERIAL_ECHOPGM("PWM = ", PWM_INTERFACE->PWM_CH_NUM[chan].PWM_CDTY);
} }
} }

View File

@ -43,22 +43,22 @@
#define SPI_PIN 87 #define SPI_PIN 87
#define SPI_CHAN 1 #define SPI_CHAN 1
#endif #endif
#define SCK_PIN 76 #define SD_SCK_PIN 76
#define MISO_PIN 74 #define SD_MISO_PIN 74
#define MOSI_PIN 75 #define SD_MOSI_PIN 75
#else #else
// defaults // defaults
#define DUE_SOFTWARE_SPI #define DUE_SOFTWARE_SPI
#ifndef SCK_PIN #ifndef SD_SCK_PIN
#define SCK_PIN 52 #define SD_SCK_PIN 52
#endif #endif
#ifndef MISO_PIN #ifndef SD_MISO_PIN
#define MISO_PIN 50 #define SD_MISO_PIN 50
#endif #endif
#ifndef MOSI_PIN #ifndef SD_MOSI_PIN
#define MOSI_PIN 51 #define SD_MOSI_PIN 51
#endif #endif
#endif #endif
/* A.28, A.29, B.21, C.26, C.29 */ /* A.28, A.29, B.21, C.26, C.29 */
#define SS_PIN SDSS #define SD_SS_PIN SDSS

View File

@ -42,7 +42,7 @@
// Private Variables // Private Variables
// ------------------------ // ------------------------
const tTimerConfig TimerConfig [NUM_HARDWARE_TIMERS] = { const tTimerConfig timer_config[NUM_HARDWARE_TIMERS] = {
{ TC0, 0, TC0_IRQn, 3}, // 0 - [servo timer5] { TC0, 0, TC0_IRQn, 3}, // 0 - [servo timer5]
{ TC0, 1, TC1_IRQn, 0}, // 1 { TC0, 1, TC1_IRQn, 0}, // 1
{ TC0, 2, TC2_IRQn, 2}, // 2 - stepper { TC0, 2, TC2_IRQn, 2}, // 2 - stepper
@ -66,9 +66,9 @@ const tTimerConfig TimerConfig [NUM_HARDWARE_TIMERS] = {
*/ */
void HAL_timer_start(const uint8_t timer_num, const uint32_t frequency) { void HAL_timer_start(const uint8_t timer_num, const uint32_t frequency) {
Tc *tc = TimerConfig[timer_num].pTimerRegs; Tc *tc = timer_config[timer_num].pTimerRegs;
IRQn_Type irq = TimerConfig[timer_num].IRQ_Id; IRQn_Type irq = timer_config[timer_num].IRQ_Id;
uint32_t channel = TimerConfig[timer_num].channel; uint32_t channel = timer_config[timer_num].channel;
// Disable interrupt, just in case it was already enabled // Disable interrupt, just in case it was already enabled
NVIC_DisableIRQ(irq); NVIC_DisableIRQ(irq);
@ -86,13 +86,20 @@ void HAL_timer_start(const uint8_t timer_num, const uint32_t frequency) {
pmc_set_writeprotect(false); pmc_set_writeprotect(false);
pmc_enable_periph_clk((uint32_t)irq); pmc_enable_periph_clk((uint32_t)irq);
NVIC_SetPriority(irq, TimerConfig [timer_num].priority); NVIC_SetPriority(irq, timer_config[timer_num].priority);
// wave mode, reset counter on match with RC, // wave mode, reset counter on match with RC,
TC_Configure(tc, channel, TC_CMR_WAVE | TC_CMR_WAVSEL_UP_RC | TC_CMR_TCCLKS_TIMER_CLOCK1); TC_Configure(tc, channel,
TC_CMR_WAVE
| TC_CMR_WAVSEL_UP_RC
| (HAL_TIMER_PRESCALER == 2 ? TC_CMR_TCCLKS_TIMER_CLOCK1 : 0)
| (HAL_TIMER_PRESCALER == 8 ? TC_CMR_TCCLKS_TIMER_CLOCK2 : 0)
| (HAL_TIMER_PRESCALER == 32 ? TC_CMR_TCCLKS_TIMER_CLOCK3 : 0)
| (HAL_TIMER_PRESCALER == 128 ? TC_CMR_TCCLKS_TIMER_CLOCK4 : 0)
);
// Set compare value // Set compare value
TC_SetRC(tc, channel, VARIANT_MCK / 2 / frequency); TC_SetRC(tc, channel, VARIANT_MCK / (HAL_TIMER_PRESCALER) / frequency);
// And start timer // And start timer
TC_Start(tc, channel); TC_Start(tc, channel);
@ -105,12 +112,12 @@ void HAL_timer_start(const uint8_t timer_num, const uint32_t frequency) {
} }
void HAL_timer_enable_interrupt(const uint8_t timer_num) { void HAL_timer_enable_interrupt(const uint8_t timer_num) {
IRQn_Type irq = TimerConfig[timer_num].IRQ_Id; IRQn_Type irq = timer_config[timer_num].IRQ_Id;
NVIC_EnableIRQ(irq); NVIC_EnableIRQ(irq);
} }
void HAL_timer_disable_interrupt(const uint8_t timer_num) { void HAL_timer_disable_interrupt(const uint8_t timer_num) {
IRQn_Type irq = TimerConfig[timer_num].IRQ_Id; IRQn_Type irq = timer_config[timer_num].IRQ_Id;
NVIC_DisableIRQ(irq); NVIC_DisableIRQ(irq);
// We NEED memory barriers to ensure Interrupts are actually disabled! // We NEED memory barriers to ensure Interrupts are actually disabled!
@ -121,11 +128,11 @@ void HAL_timer_disable_interrupt(const uint8_t timer_num) {
// missing from CMSIS: Check if interrupt is enabled or not // missing from CMSIS: Check if interrupt is enabled or not
static bool NVIC_GetEnabledIRQ(IRQn_Type IRQn) { static bool NVIC_GetEnabledIRQ(IRQn_Type IRQn) {
return (NVIC->ISER[(uint32_t)(IRQn) >> 5] & (1 << ((uint32_t)(IRQn) & 0x1F))) != 0; return TEST(NVIC->ISER[uint32_t(IRQn) >> 5], uint32_t(IRQn) & 0x1F);
} }
bool HAL_timer_interrupt_enabled(const uint8_t timer_num) { bool HAL_timer_interrupt_enabled(const uint8_t timer_num) {
IRQn_Type irq = TimerConfig[timer_num].IRQ_Id; IRQn_Type irq = timer_config[timer_num].IRQ_Id;
return NVIC_GetEnabledIRQ(irq); return NVIC_GetEnabledIRQ(irq);
} }

View File

@ -35,37 +35,38 @@
typedef uint32_t hal_timer_t; typedef uint32_t hal_timer_t;
#define HAL_TIMER_TYPE_MAX 0xFFFFFFFF #define HAL_TIMER_TYPE_MAX 0xFFFFFFFF
#define HAL_TIMER_RATE ((F_CPU) / 2) // frequency of timers peripherals #define HAL_TIMER_PRESCALER 2
#define HAL_TIMER_RATE ((F_CPU) / (HAL_TIMER_PRESCALER)) // frequency of timers peripherals
#ifndef STEP_TIMER_NUM #ifndef MF_TIMER_STEP
#define STEP_TIMER_NUM 2 // Timer Index for Stepper #define MF_TIMER_STEP 2 // Timer Index for Stepper
#endif #endif
#ifndef PULSE_TIMER_NUM #ifndef MF_TIMER_PULSE
#define PULSE_TIMER_NUM STEP_TIMER_NUM #define MF_TIMER_PULSE MF_TIMER_STEP
#endif #endif
#ifndef TEMP_TIMER_NUM #ifndef MF_TIMER_TEMP
#define TEMP_TIMER_NUM 4 // Timer Index for Temperature #define MF_TIMER_TEMP 4 // Timer Index for Temperature
#endif #endif
#ifndef TONE_TIMER_NUM #ifndef MF_TIMER_TONE
#define TONE_TIMER_NUM 6 // index of timer to use for beeper tones #define MF_TIMER_TONE 6 // index of timer to use for beeper tones
#endif #endif
#define TEMP_TIMER_FREQUENCY 1000 // temperature interrupt frequency #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_RATE HAL_TIMER_RATE // frequency of stepper timer (HAL_TIMER_RATE / STEPPER_TIMER_PRESCALE)
#define STEPPER_TIMER_TICKS_PER_US ((STEPPER_TIMER_RATE) / 1000000) // stepper timer ticks per µs #define STEPPER_TIMER_TICKS_PER_US ((STEPPER_TIMER_RATE) / 1000000) // stepper timer ticks per µs
#define STEPPER_TIMER_PRESCALE (CYCLES_PER_MICROSECOND / STEPPER_TIMER_TICKS_PER_US) #define STEPPER_TIMER_PRESCALE (CYCLES_PER_MICROSECOND / STEPPER_TIMER_TICKS_PER_US)
#define PULSE_TIMER_RATE STEPPER_TIMER_RATE // frequency of pulse timer #define PULSE_TIMER_RATE STEPPER_TIMER_RATE // frequency of pulse timer
#define PULSE_TIMER_PRESCALE STEPPER_TIMER_PRESCALE #define PULSE_TIMER_PRESCALE STEPPER_TIMER_PRESCALE
#define PULSE_TIMER_TICKS_PER_US STEPPER_TIMER_TICKS_PER_US #define PULSE_TIMER_TICKS_PER_US STEPPER_TIMER_TICKS_PER_US
#define ENABLE_STEPPER_DRIVER_INTERRUPT() HAL_timer_enable_interrupt(STEP_TIMER_NUM) #define ENABLE_STEPPER_DRIVER_INTERRUPT() HAL_timer_enable_interrupt(MF_TIMER_STEP)
#define DISABLE_STEPPER_DRIVER_INTERRUPT() HAL_timer_disable_interrupt(STEP_TIMER_NUM) #define DISABLE_STEPPER_DRIVER_INTERRUPT() HAL_timer_disable_interrupt(MF_TIMER_STEP)
#define STEPPER_ISR_ENABLED() HAL_timer_interrupt_enabled(STEP_TIMER_NUM) #define STEPPER_ISR_ENABLED() HAL_timer_interrupt_enabled(MF_TIMER_STEP)
#define ENABLE_TEMPERATURE_INTERRUPT() HAL_timer_enable_interrupt(TEMP_TIMER_NUM) #define ENABLE_TEMPERATURE_INTERRUPT() HAL_timer_enable_interrupt(MF_TIMER_TEMP)
#define DISABLE_TEMPERATURE_INTERRUPT() HAL_timer_disable_interrupt(TEMP_TIMER_NUM) #define DISABLE_TEMPERATURE_INTERRUPT() HAL_timer_disable_interrupt(MF_TIMER_TEMP)
#ifndef HAL_STEP_TIMER_ISR #ifndef HAL_STEP_TIMER_ISR
#define HAL_STEP_TIMER_ISR() void TC2_Handler() #define HAL_STEP_TIMER_ISR() void TC2_Handler()
@ -92,7 +93,7 @@ typedef struct {
// Public Variables // Public Variables
// ------------------------ // ------------------------
extern const tTimerConfig TimerConfig[]; extern const tTimerConfig timer_config[];
// ------------------------ // ------------------------
// Public functions // Public functions
@ -101,17 +102,17 @@ extern const tTimerConfig TimerConfig[];
void HAL_timer_start(const uint8_t timer_num, const uint32_t frequency); 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) { FORCE_INLINE static void HAL_timer_set_compare(const uint8_t timer_num, const hal_timer_t compare) {
const tTimerConfig * const pConfig = &TimerConfig[timer_num]; const tTimerConfig * const pConfig = &timer_config[timer_num];
pConfig->pTimerRegs->TC_CHANNEL[pConfig->channel].TC_RC = compare; pConfig->pTimerRegs->TC_CHANNEL[pConfig->channel].TC_RC = compare;
} }
FORCE_INLINE static hal_timer_t HAL_timer_get_compare(const uint8_t timer_num) { FORCE_INLINE static hal_timer_t HAL_timer_get_compare(const uint8_t timer_num) {
const tTimerConfig * const pConfig = &TimerConfig[timer_num]; const tTimerConfig * const pConfig = &timer_config[timer_num];
return pConfig->pTimerRegs->TC_CHANNEL[pConfig->channel].TC_RC; return pConfig->pTimerRegs->TC_CHANNEL[pConfig->channel].TC_RC;
} }
FORCE_INLINE static hal_timer_t HAL_timer_get_count(const uint8_t timer_num) { FORCE_INLINE static hal_timer_t HAL_timer_get_count(const uint8_t timer_num) {
const tTimerConfig * const pConfig = &TimerConfig[timer_num]; const tTimerConfig * const pConfig = &timer_config[timer_num];
return pConfig->pTimerRegs->TC_CHANNEL[pConfig->channel].TC_CV; return pConfig->pTimerRegs->TC_CHANNEL[pConfig->channel].TC_CV;
} }
@ -120,9 +121,9 @@ void HAL_timer_disable_interrupt(const uint8_t timer_num);
bool HAL_timer_interrupt_enabled(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) { FORCE_INLINE static void HAL_timer_isr_prologue(const uint8_t timer_num) {
const tTimerConfig * const pConfig = &TimerConfig[timer_num]; const tTimerConfig * const pConfig = &timer_config[timer_num];
// Reading the status register clears the interrupt flag // Reading the status register clears the interrupt flag
pConfig->pTimerRegs->TC_CHANNEL[pConfig->channel].TC_SR; pConfig->pTimerRegs->TC_CHANNEL[pConfig->channel].TC_SR;
} }
#define HAL_timer_isr_epilogue(TIMER_NUM) #define HAL_timer_isr_epilogue(T) NOOP

View File

@ -4,15 +4,16 @@
# Windows: bossac.exe # Windows: bossac.exe
# Other: leave unchanged # Other: leave unchanged
# #
import pioutil
if pioutil.is_pio_build():
import platform
current_OS = platform.system()
import platform if current_OS == 'Windows':
current_OS = platform.system()
if current_OS == 'Windows': Import("env")
Import("env") # Use bossac.exe on Windows
env.Replace(
# Use bossac.exe on Windows UPLOADCMD="bossac --info --unlock --write --verify --reset --erase -U false --boot $SOURCE"
env.Replace( )
UPLOADCMD="bossac --info --unlock --write --verify --reset --erase -U false --boot $SOURCE"
)

View File

@ -71,7 +71,7 @@
/* ------------------------------------------------------------------------ */ /* ------------------------------------------------------------------------ */
/** /**
* \page arduino_due_x_board_info "Arduino Due/X - Board informations" * \page arduino_due_x_board_info "Arduino Due/X - Board information"
* This page lists several definition related to the board description. * This page lists several definition related to the board description.
* *
*/ */

View File

@ -1059,7 +1059,7 @@ static inline void convert_64_bit_to_byte_array(uint64_t value, uint8_t *data)
while (val_index < 8) while (val_index < 8)
{ {
data[val_index++] = value & 0xFF; data[val_index++] = value & 0xFF;
value = value >> 8; value >>= 8;
} }
} }

View File

@ -10,7 +10,7 @@
#include "../../../sd/cardreader.h" #include "../../../sd/cardreader.h"
extern "C" { extern "C" {
#include "sd_mmc_spi_mem.h" #include "sd_mmc_spi_mem.h"
} }
#define SD_MMC_BLOCK_SIZE 512 #define SD_MMC_BLOCK_SIZE 512
@ -32,7 +32,7 @@ Ctrl_status sd_mmc_spi_test_unit_ready() {
Ctrl_status sd_mmc_spi_read_capacity(uint32_t *nb_sector) { Ctrl_status sd_mmc_spi_read_capacity(uint32_t *nb_sector) {
if (!IS_SD_INSERTED() || IS_SD_PRINTING() || IS_SD_FILE_OPEN() || !card.isMounted()) if (!IS_SD_INSERTED() || IS_SD_PRINTING() || IS_SD_FILE_OPEN() || !card.isMounted())
return CTRL_NO_PRESENT; return CTRL_NO_PRESENT;
*nb_sector = card.getSd2Card().cardSize() - 1; *nb_sector = card.diskIODriver()->cardSize() - 1;
return CTRL_GOOD; return CTRL_GOOD;
} }
@ -68,30 +68,30 @@ Ctrl_status sd_mmc_spi_usb_read_10(uint32_t addr, uint16_t nb_sector) {
{ {
char buffer[80]; char buffer[80];
sprintf_P(buffer, PSTR("SDRD: %d @ 0x%08x\n"), nb_sector, addr); sprintf_P(buffer, PSTR("SDRD: %d @ 0x%08x\n"), nb_sector, addr);
PORT_REDIRECT(0); PORT_REDIRECT(SERIAL_PORTMASK(0));
SERIAL_ECHO(buffer); SERIAL_ECHO(buffer);
} }
#endif #endif
// Start reading // Start reading
if (!card.getSd2Card().readStart(addr)) if (!card.diskIODriver()->readStart(addr))
return CTRL_FAIL; return CTRL_FAIL;
// For each specified sector // For each specified sector
while (nb_sector--) { while (nb_sector--) {
// Read a sector // Read a sector
card.getSd2Card().readData(sector_buf); card.diskIODriver()->readData(sector_buf);
// RAM -> USB // RAM -> USB
if (!udi_msc_trans_block(true, sector_buf, SD_MMC_BLOCK_SIZE, NULL)) { if (!udi_msc_trans_block(true, sector_buf, SD_MMC_BLOCK_SIZE, nullptr)) {
card.getSd2Card().readStop(); card.diskIODriver()->readStop();
return CTRL_FAIL; return CTRL_FAIL;
} }
} }
// Stop reading // Stop reading
card.getSd2Card().readStop(); card.diskIODriver()->readStop();
// Done // Done
return CTRL_GOOD; return CTRL_GOOD;
@ -108,29 +108,29 @@ Ctrl_status sd_mmc_spi_usb_write_10(uint32_t addr, uint16_t nb_sector) {
{ {
char buffer[80]; char buffer[80];
sprintf_P(buffer, PSTR("SDWR: %d @ 0x%08x\n"), nb_sector, addr); sprintf_P(buffer, PSTR("SDWR: %d @ 0x%08x\n"), nb_sector, addr);
PORT_REDIRECT(0); PORT_REDIRECT(SERIAL_PORTMASK(0));
SERIAL_ECHO(buffer); SERIAL_ECHO(buffer);
} }
#endif #endif
if (!card.getSd2Card().writeStart(addr, nb_sector)) if (!card.diskIODriver()->writeStart(addr, nb_sector))
return CTRL_FAIL; return CTRL_FAIL;
// For each specified sector // For each specified sector
while (nb_sector--) { while (nb_sector--) {
// USB -> RAM // USB -> RAM
if (!udi_msc_trans_block(false, sector_buf, SD_MMC_BLOCK_SIZE, NULL)) { if (!udi_msc_trans_block(false, sector_buf, SD_MMC_BLOCK_SIZE, nullptr)) {
card.getSd2Card().writeStop(); card.diskIODriver()->writeStop();
return CTRL_FAIL; return CTRL_FAIL;
} }
// Write a sector // Write a sector
card.getSd2Card().writeData(sector_buf); card.diskIODriver()->writeData(sector_buf);
} }
// Stop writing // Stop writing
card.getSd2Card().writeStop(); card.diskIODriver()->writeStop();
// Done // Done
return CTRL_GOOD; return CTRL_GOOD;

View File

@ -74,7 +74,7 @@
#define SD_MMC_REMOVING 2 #define SD_MMC_REMOVING 2
//---- CONTROL FONCTIONS ---- //---- CONTROL FUNCTIONS ----
//! //!
//! @brief This function initializes the hw/sw resources required to drive the SD_MMC_SPI. //! @brief This function initializes the hw/sw resources required to drive the SD_MMC_SPI.
//!/ //!/
@ -134,7 +134,7 @@ extern bool sd_mmc_spi_wr_protect(void);
extern bool sd_mmc_spi_removal(void); extern bool sd_mmc_spi_removal(void);
//---- ACCESS DATA FONCTIONS ---- //---- ACCESS DATA FUNCTIONS ----
#if ACCESS_USB == true #if ACCESS_USB == true
// Standard functions for open in read/write mode the device // Standard functions for open in read/write mode the device

View File

@ -90,7 +90,7 @@ typedef struct {
//! This buffer must be word align for DATA IN phase (use prefix COMPILER_WORD_ALIGNED for buffer) //! This buffer must be word align for DATA IN phase (use prefix COMPILER_WORD_ALIGNED for buffer)
uint8_t *payload; uint8_t *payload;
//! Size of buffer to send or fill, and content the number of byte transfered //! Size of buffer to send or fill, and content the number of byte transferred
uint16_t payload_size; uint16_t payload_size;
//! Callback called after reception of ZLP from setup request //! Callback called after reception of ZLP from setup request
@ -132,10 +132,10 @@ typedef void (*udd_callback_halt_cleared_t)(void);
* *
* \param status UDD_EP_TRANSFER_OK, if transfer is complete * \param status UDD_EP_TRANSFER_OK, if transfer is complete
* \param status UDD_EP_TRANSFER_ABORT, if transfer is aborted * \param status UDD_EP_TRANSFER_ABORT, if transfer is aborted
* \param n number of data transfered * \param n number of data transferred
*/ */
typedef void (*udd_callback_trans_t) (udd_ep_status_t status, typedef void (*udd_callback_trans_t) (udd_ep_status_t status,
iram_size_t nb_transfered, udd_ep_id_t ep); iram_size_t nb_transferred, udd_ep_id_t ep);
/** /**
* \brief Authorizes the VBUS event * \brief Authorizes the VBUS event
@ -303,7 +303,7 @@ bool udd_ep_wait_stall_clear(udd_ep_id_t ep,
* The driver uses a specific DMA USB to transfer data * The driver uses a specific DMA USB to transfer data
* from internal RAM to endpoint, if this one is available. * from internal RAM to endpoint, if this one is available.
* When the transfer is finished or aborted (stall, reset, ...), the \a callback is called. * When the transfer is finished or aborted (stall, reset, ...), the \a callback is called.
* The \a callback returns the transfer status and eventually the number of byte transfered. * The \a callback returns the transfer status and eventually the number of byte transferred.
* Note: The control endpoint is not authorized. * Note: The control endpoint is not authorized.
* *
* \param ep The ID of the endpoint to use * \param ep The ID of the endpoint to use

View File

@ -162,7 +162,7 @@ static void udi_cdc_ctrl_state_notify(uint8_t port, udd_ep_id_t ep);
* *
* \param status UDD_EP_TRANSFER_OK, if transfer finished * \param status UDD_EP_TRANSFER_OK, if transfer finished
* \param status UDD_EP_TRANSFER_ABORT, if transfer aborted * \param status UDD_EP_TRANSFER_ABORT, if transfer aborted
* \param n number of data transfered * \param n number of data transferred
*/ */
static void udi_cdc_serial_state_msg_sent(udd_ep_status_t status, iram_size_t n, udd_ep_id_t ep); static void udi_cdc_serial_state_msg_sent(udd_ep_status_t status, iram_size_t n, udd_ep_id_t ep);
@ -200,7 +200,7 @@ static void udi_cdc_data_received(udd_ep_status_t status, iram_size_t n, udd_ep_
* *
* \param status UDD_EP_TRANSFER_OK, if transfer finished * \param status UDD_EP_TRANSFER_OK, if transfer finished
* \param status UDD_EP_TRANSFER_ABORT, if transfer aborted * \param status UDD_EP_TRANSFER_ABORT, if transfer aborted
* \param n number of data transfered * \param n number of data transferred
*/ */
static void udi_cdc_data_sent(udd_ep_status_t status, iram_size_t n, udd_ep_id_t ep); static void udi_cdc_data_sent(udd_ep_status_t status, iram_size_t n, udd_ep_id_t ep);

View File

@ -675,11 +675,11 @@ iram_size_t udi_cdc_multi_write_buf(uint8_t port, const void* buf, iram_size_t s
* - \code // Waits and gets a value on CDC line * - \code // Waits and gets a value on CDC line
int udi_cdc_getc(void); int udi_cdc_getc(void);
// Reads a RAM buffer on CDC line // Reads a RAM buffer on CDC line
iram_size_t udi_cdc_read_buf(int* buf, iram_size_t size); iram_size_t udi_cdc_read_buf(int *buf, iram_size_t size);
// Puts a byte on CDC line // Puts a byte on CDC line
int udi_cdc_putc(int value); int udi_cdc_putc(int value);
// Writes a RAM buffer on CDC line // Writes a RAM buffer on CDC line
iram_size_t udi_cdc_write_buf(const int* buf, iram_size_t size); \endcode iram_size_t udi_cdc_write_buf(const int *buf, iram_size_t size); \endcode
* *
* \section udi_cdc_use_cases Advanced use cases * \section udi_cdc_use_cases Advanced use cases
* For more advanced use of the UDI CDC module, see the following use cases: * For more advanced use of the UDI CDC module, see the following use cases:

View File

@ -106,7 +106,7 @@ extern "C" {
*/ */
//@{ //@{
# if UDI_CDC_PORT_NB > 2 # if UDI_CDC_PORT_NB > 2
# error USBB, UDP, UDPHS and UOTGHS interfaces have not enought endpoints. # error USBB, UDP, UDPHS and UOTGHS interfaces have not enough endpoints.
# endif # endif
#define UDI_CDC_DATA_EP_IN_0 (1 | USB_EP_DIR_IN) // TX #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_DATA_EP_OUT_0 (2 | USB_EP_DIR_OUT) // RX

View File

@ -173,7 +173,7 @@ static void udi_msc_cbw_wait(void);
* *
* \param status UDD_EP_TRANSFER_OK, if transfer is finished * \param status UDD_EP_TRANSFER_OK, if transfer is finished
* \param status UDD_EP_TRANSFER_ABORT, if transfer is aborted * \param status UDD_EP_TRANSFER_ABORT, if transfer is aborted
* \param nb_received number of data transfered * \param nb_received number of data transferred
*/ */
static void udi_msc_cbw_received(udd_ep_status_t status, 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);
@ -211,7 +211,7 @@ static void udi_msc_data_send(uint8_t * buffer, uint8_t buf_size);
* *
* \param status UDD_EP_TRANSFER_OK, if transfer finish * \param status UDD_EP_TRANSFER_OK, if transfer finish
* \param status UDD_EP_TRANSFER_ABORT, if transfer aborted * \param status UDD_EP_TRANSFER_ABORT, if transfer aborted
* \param nb_sent number of data transfered * \param nb_sent number of data transferred
*/ */
static void udi_msc_data_sent(udd_ep_status_t status, iram_size_t nb_sent, 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);
@ -244,7 +244,7 @@ void udi_msc_csw_send(void);
* *
* \param status UDD_EP_TRANSFER_OK, if transfer is finished * \param status UDD_EP_TRANSFER_OK, if transfer is finished
* \param status UDD_EP_TRANSFER_ABORT, if transfer is aborted * \param status UDD_EP_TRANSFER_ABORT, if transfer is aborted
* \param nb_sent number of data transfered * \param nb_sent number of data transferred
*/ */
static void udi_msc_csw_sent(udd_ep_status_t status, iram_size_t nb_sent, 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);
@ -463,7 +463,7 @@ uint8_t udi_msc_getsetting(void)
static void udi_msc_cbw_invalid(void) static void udi_msc_cbw_invalid(void)
{ {
if (!udi_msc_b_cbw_invalid) if (!udi_msc_b_cbw_invalid)
return; // Don't re-stall endpoint if error reseted by setup return; // Don't re-stall endpoint if error reset by setup
udd_ep_set_halt(UDI_MSC_EP_OUT); udd_ep_set_halt(UDI_MSC_EP_OUT);
// If stall cleared then re-stall it. Only Setup MSC Reset can clear it // If stall cleared then re-stall it. Only Setup MSC Reset can clear it
udd_ep_wait_stall_clear(UDI_MSC_EP_OUT, udi_msc_cbw_invalid); udd_ep_wait_stall_clear(UDI_MSC_EP_OUT, udi_msc_cbw_invalid);
@ -472,7 +472,7 @@ static void udi_msc_cbw_invalid(void)
static void udi_msc_csw_invalid(void) static void udi_msc_csw_invalid(void)
{ {
if (!udi_msc_b_cbw_invalid) if (!udi_msc_b_cbw_invalid)
return; // Don't re-stall endpoint if error reseted by setup return; // Don't re-stall endpoint if error reset by setup
udd_ep_set_halt(UDI_MSC_EP_IN); udd_ep_set_halt(UDI_MSC_EP_IN);
// If stall cleared then re-stall it. Only Setup MSC Reset can clear it // If stall cleared then re-stall it. Only Setup MSC Reset can clear it
udd_ep_wait_stall_clear(UDI_MSC_EP_IN, udi_msc_csw_invalid); udd_ep_wait_stall_clear(UDI_MSC_EP_IN, udi_msc_csw_invalid);

View File

@ -325,7 +325,7 @@ static void udd_sleep_mode(bool b_idle)
/** /**
* \name Control endpoint low level management routine. * \name Control endpoint low level management routine.
* *
* This function performs control endpoint mangement. * This function performs control endpoint management.
* It handle the SETUP/DATA/HANDSHAKE phases of a control transaction. * It handle the SETUP/DATA/HANDSHAKE phases of a control transaction.
*/ */
//@{ //@{
@ -397,9 +397,9 @@ static void udd_ctrl_endofrequest(void);
/** /**
* \brief Main interrupt routine for control endpoint * \brief Main interrupt routine for control endpoint
* *
* This switchs control endpoint events to correct sub function. * This switches control endpoint events to correct sub function.
* *
* \return \c 1 if an event about control endpoint is occured, otherwise \c 0. * \return \c 1 if an event about control endpoint is occurred, otherwise \c 0.
*/ */
static bool udd_ctrl_interrupt(void); static bool udd_ctrl_interrupt(void);
@ -410,7 +410,7 @@ static bool udd_ctrl_interrupt(void);
* \name Management of bulk/interrupt/isochronous endpoints * \name Management of bulk/interrupt/isochronous endpoints
* *
* The UDD manages the data transfer on endpoints: * The UDD manages the data transfer on endpoints:
* - Start data tranfer on endpoint with USB Device DMA * - Start data transfer on endpoint with USB Device DMA
* - Send a ZLP packet if requested * - Send a ZLP packet if requested
* - Call callback registered to signal end of transfer * - Call callback registered to signal end of transfer
* The transfer abort and stall feature are supported. * The transfer abort and stall feature are supported.
@ -431,7 +431,7 @@ typedef struct {
uint8_t *buf; uint8_t *buf;
//! Size of buffer to send or fill //! Size of buffer to send or fill
iram_size_t buf_size; iram_size_t buf_size;
//!< Size of data transfered //!< Size of data transferred
iram_size_t buf_cnt; iram_size_t buf_cnt;
//!< Size of data loaded (or prepared for DMA) last time //!< Size of data loaded (or prepared for DMA) last time
iram_size_t buf_load; iram_size_t buf_load;
@ -486,7 +486,7 @@ static void udd_ep_finish_job(udd_ep_job_t * ptr_job, bool b_abort, uint8_t ep_n
#ifdef UDD_EP_DMA_SUPPORTED #ifdef UDD_EP_DMA_SUPPORTED
/** /**
* \brief Start the next transfer if necessary or complet the job associated. * \brief Start the next transfer if necessary or complete the job associated.
* *
* \param ep endpoint number without direction flag * \param ep endpoint number without direction flag
*/ */
@ -496,9 +496,9 @@ static void udd_ep_finish_job(udd_ep_job_t * ptr_job, bool b_abort, uint8_t ep_n
/** /**
* \brief Main interrupt routine for bulk/interrupt/isochronous endpoints * \brief Main interrupt routine for bulk/interrupt/isochronous endpoints
* *
* This switchs endpoint events to correct sub function. * This switches endpoint events to correct sub function.
* *
* \return \c 1 if an event about bulk/interrupt/isochronous endpoints has occured, otherwise \c 0. * \return \c 1 if an event about bulk/interrupt/isochronous endpoints has occurred, otherwise \c 0.
*/ */
static bool udd_ep_interrupt(void); static bool udd_ep_interrupt(void);
@ -520,7 +520,7 @@ static bool udd_ep_interrupt(void);
* *
* Note: * Note:
* Here, the global interrupt mask is not clear when an USB interrupt is enabled * Here, the global interrupt mask is not clear when an USB interrupt is enabled
* because this one can not be occured during the USB ISR (=during INTX is masked). * because this one can not be occurred during the USB ISR (=during INTX is masked).
* See Technical reference $3.8.3 Masking interrupt requests in peripheral modules. * See Technical reference $3.8.3 Masking interrupt requests in peripheral modules.
*/ */
#ifdef UHD_ENABLE #ifdef UHD_ENABLE
@ -787,7 +787,7 @@ void udd_attach(void)
udd_sleep_mode(true); udd_sleep_mode(true);
otg_unfreeze_clock(); otg_unfreeze_clock();
// This section of clock check can be improved with a chek of // This section of clock check can be improved with a check of
// USB clock source via sysclk() // USB clock source via sysclk()
// Check USB clock because the source can be a PLL // Check USB clock because the source can be a PLL
while (!Is_otg_clock_usable()); while (!Is_otg_clock_usable());
@ -803,7 +803,7 @@ void udd_attach(void)
#ifdef USB_DEVICE_HS_SUPPORT #ifdef USB_DEVICE_HS_SUPPORT
udd_enable_msof_interrupt(); udd_enable_msof_interrupt();
#endif #endif
// Reset following interupts flag // Reset following interrupts flag
udd_ack_reset(); udd_ack_reset();
udd_ack_sof(); udd_ack_sof();
udd_ack_msof(); udd_ack_msof();
@ -902,7 +902,7 @@ bool udd_ep_alloc(udd_ep_id_t ep, uint8_t bmAttributes,
} }
dbg_print("alloc(%x, %d) ", ep, MaxEndpointSize); dbg_print("alloc(%x, %d) ", ep, MaxEndpointSize);
// Bank choise // Bank choice
switch (bmAttributes & USB_EP_TYPE_MASK) { switch (bmAttributes & USB_EP_TYPE_MASK) {
case USB_EP_TYPE_ISOCHRONOUS: case USB_EP_TYPE_ISOCHRONOUS:
nb_bank = UDD_ISOCHRONOUS_NB_BANK(ep); nb_bank = UDD_ISOCHRONOUS_NB_BANK(ep);
@ -1228,7 +1228,7 @@ bool udd_ep_wait_stall_clear(udd_ep_id_t ep,
if (Is_udd_endpoint_stall_requested(ep) if (Is_udd_endpoint_stall_requested(ep)
|| ptr_job->stall_requested) { || ptr_job->stall_requested) {
// Endpoint halted then registes the callback // Endpoint halted then registers the callback
ptr_job->busy = true; ptr_job->busy = true;
ptr_job->call_nohalt = callback; ptr_job->call_nohalt = callback;
} else { } else {
@ -1386,7 +1386,7 @@ static void udd_ctrl_setup_received(void)
// Decode setup request // Decode setup request
if (udc_process_setup() == false) { if (udc_process_setup() == false) {
// Setup request unknow then stall it // Setup request unknown then stall it
udd_ctrl_stall_data(); udd_ctrl_stall_data();
udd_ack_setup_received(0); udd_ack_setup_received(0);
return; return;
@ -1447,7 +1447,7 @@ static void udd_ctrl_in_sent(void)
udd_ctrl_prev_payload_buf_cnt += udd_ctrl_payload_buf_cnt; udd_ctrl_prev_payload_buf_cnt += udd_ctrl_payload_buf_cnt;
if ((udd_g_ctrlreq.req.wLength == udd_ctrl_prev_payload_buf_cnt) if ((udd_g_ctrlreq.req.wLength == udd_ctrl_prev_payload_buf_cnt)
|| b_shortpacket) { || b_shortpacket) {
// All data requested are transfered or a short packet has been sent // All data requested are transferred or a short packet has been sent
// then it is the end of data phase. // then it is the end of data phase.
// Generate an OUT ZLP for handshake phase. // Generate an OUT ZLP for handshake phase.
udd_ctrl_send_zlp_out(); udd_ctrl_send_zlp_out();
@ -1516,7 +1516,7 @@ static void udd_ctrl_out_received(void)
// End of SETUP request: // End of SETUP request:
// - Data IN Phase aborted, // - Data IN Phase aborted,
// - or last Data IN Phase hidden by ZLP OUT sending quiclky, // - or last Data IN Phase hidden by ZLP OUT sending quiclky,
// - or ZLP OUT received normaly. // - or ZLP OUT received normally.
udd_ctrl_endofrequest(); udd_ctrl_endofrequest();
} else { } else {
// Protocol error during SETUP request // Protocol error during SETUP request
@ -1544,7 +1544,7 @@ static void udd_ctrl_out_received(void)
(udd_ctrl_prev_payload_buf_cnt + (udd_ctrl_prev_payload_buf_cnt +
udd_ctrl_payload_buf_cnt))) { udd_ctrl_payload_buf_cnt))) {
// End of reception because it is a short packet // End of reception because it is a short packet
// Before send ZLP, call intermediat calback // Before send ZLP, call intermediate callback
// in case of data receiv generate a stall // in case of data receiv generate a stall
udd_g_ctrlreq.payload_size = udd_ctrl_payload_buf_cnt; udd_g_ctrlreq.payload_size = udd_ctrl_payload_buf_cnt;
if (NULL != udd_g_ctrlreq.over_under_run) { if (NULL != udd_g_ctrlreq.over_under_run) {
@ -1565,7 +1565,7 @@ static void udd_ctrl_out_received(void)
if (udd_g_ctrlreq.payload_size == udd_ctrl_payload_buf_cnt) { if (udd_g_ctrlreq.payload_size == udd_ctrl_payload_buf_cnt) {
// Overrun then request a new payload buffer // Overrun then request a new payload buffer
if (!udd_g_ctrlreq.over_under_run) { if (!udd_g_ctrlreq.over_under_run) {
// No callback availabled to request a new payload buffer // No callback available to request a new payload buffer
udd_ctrl_stall_data(); udd_ctrl_stall_data();
// Ack reception of OUT to replace NAK by a STALL // Ack reception of OUT to replace NAK by a STALL
udd_ack_out_received(0); udd_ack_out_received(0);
@ -1805,7 +1805,7 @@ static void udd_ep_trans_done(udd_ep_id_t ep)
// transfer size of UDD_ENDPOINT_MAX_TRANS Bytes // transfer size of UDD_ENDPOINT_MAX_TRANS Bytes
next_trans = UDD_ENDPOINT_MAX_TRANS; next_trans = UDD_ENDPOINT_MAX_TRANS;
// Set 0 to tranfer the maximum // Set 0 to transfer the maximum
udd_dma_ctrl = UOTGHS_DEVDMACONTROL_BUFF_LENGTH(0); udd_dma_ctrl = UOTGHS_DEVDMACONTROL_BUFF_LENGTH(0);
} else { } else {
udd_dma_ctrl = UOTGHS_DEVDMACONTROL_BUFF_LENGTH(next_trans); udd_dma_ctrl = UOTGHS_DEVDMACONTROL_BUFF_LENGTH(next_trans);
@ -1850,7 +1850,7 @@ static void udd_ep_trans_done(udd_ep_id_t ep)
} }
cpu_irq_restore(flags); cpu_irq_restore(flags);
// Here a ZLP has been recieved // Here a ZLP has been received
// and the DMA transfer must be not started. // and the DMA transfer must be not started.
// It is the end of transfer // It is the end of transfer
ptr_job->buf_size = ptr_job->buf_cnt; ptr_job->buf_size = ptr_job->buf_cnt;
@ -1991,13 +1991,13 @@ static bool udd_ep_interrupt(void)
} }
dbg_print("dma%x: ", ep); dbg_print("dma%x: ", ep);
udd_disable_endpoint_dma_interrupt(ep); udd_disable_endpoint_dma_interrupt(ep);
// Save number of data no transfered // Save number of data no transferred
nb_remaining = (udd_endpoint_dma_get_status(ep) & nb_remaining = (udd_endpoint_dma_get_status(ep) &
UOTGHS_DEVDMASTATUS_BUFF_COUNT_Msk) UOTGHS_DEVDMASTATUS_BUFF_COUNT_Msk)
>> UOTGHS_DEVDMASTATUS_BUFF_COUNT_Pos; >> UOTGHS_DEVDMASTATUS_BUFF_COUNT_Pos;
if (nb_remaining) { if (nb_remaining) {
// Transfer no complete (short packet or ZLP) then: // Transfer no complete (short packet or ZLP) then:
// Update number of data transfered // Update number of data transferred
ptr_job->buf_cnt -= nb_remaining; ptr_job->buf_cnt -= nb_remaining;
// Set transfer complete to stop the transfer // Set transfer complete to stop the transfer
ptr_job->buf_size = ptr_job->buf_cnt; ptr_job->buf_size = ptr_job->buf_cnt;
@ -2056,7 +2056,7 @@ static bool udd_ep_interrupt(void)
udd_disable_endpoint_interrupt(ep); udd_disable_endpoint_interrupt(ep);
Assert(ptr_job->stall_requested); Assert(ptr_job->stall_requested);
// A stall has been requested during backgound transfer // A stall has been requested during background transfer
ptr_job->stall_requested = false; ptr_job->stall_requested = false;
udd_disable_endpoint_bank_autoswitch(ep); udd_disable_endpoint_bank_autoswitch(ep);
udd_enable_stall_handshake(ep); udd_enable_stall_handshake(ep);

View File

@ -130,7 +130,7 @@ struct usb_msc_cbw {
struct usb_msc_csw { struct usb_msc_csw {
le32_t dCSWSignature; //!< Must contain 'USBS' le32_t dCSWSignature; //!< Must contain 'USBS'
le32_t dCSWTag; //!< Same as dCBWTag le32_t dCSWTag; //!< Same as dCBWTag
le32_t dCSWDataResidue; //!< Number of bytes not transfered le32_t dCSWDataResidue; //!< Number of bytes not transferred
uint8_t bCSWStatus; //!< Status code uint8_t bCSWStatus; //!< Status code
}; };

View File

@ -62,7 +62,7 @@ void usb_task_idle(void) {
// Attend SD card access from the USB MSD -- Prioritize access to improve speed // Attend SD card access from the USB MSD -- Prioritize access to improve speed
int delay = 2; int delay = 2;
while (main_b_msc_enable && --delay > 0) { while (main_b_msc_enable && --delay > 0) {
if (udi_msc_process_trans()) delay = 10000; if (udi_msc_process_trans()) delay = 20;
// Reset the watchdog, just to be sure // Reset the watchdog, just to be sure
REG_WDT_CR = WDT_CR_WDRSTT | WDT_CR_KEY(0xA5); REG_WDT_CR = WDT_CR_WDRSTT | WDT_CR_KEY(0xA5);
@ -264,7 +264,7 @@ bool usb_task_extra_string(void) {
** Handle device requests that the ASF stack doesn't ** Handle device requests that the ASF stack doesn't
*/ */
bool usb_task_other_requests(void) { bool usb_task_other_requests(void) {
uint8_t* ptr = 0; uint8_t *ptr = 0;
uint16_t size = 0; uint16_t size = 0;
if (Udd_setup_type() == USB_REQ_TYPE_VENDOR) { if (Udd_setup_type() == USB_REQ_TYPE_VENDOR) {
@ -322,7 +322,7 @@ void usb_task_init(void) {
char *sptr; char *sptr;
// Patch in the filament diameter // Patch in the filament diameter
sprintf_P(diam, PSTR("%d"), (int)((DEFAULT_NOMINAL_FILAMENT_DIA) * 1000.0)); itoa((int)((DEFAULT_NOMINAL_FILAMENT_DIA) * 1000), diam, 10);
// And copy it to the proper place, expanding it to unicode // And copy it to the proper place, expanding it to unicode
sptr = &diam[0]; sptr = &diam[0];

View File

@ -1,114 +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 <https://www.gnu.org/licenses/>.
*
*/
#ifdef ARDUINO_ARCH_SAM
#include "../../inc/MarlinConfig.h"
#include "../../MarlinCore.h"
#include "watchdog.h"
// Override Arduino runtime to either config or disable the watchdog
//
// We need to configure the watchdog as soon as possible in the boot
// process, because watchdog initialization at hardware reset on SAM3X8E
// is unreliable, and there is risk of unintended resets if we delay
// that initialization to a later time.
void watchdogSetup() {
#if ENABLED(USE_WATCHDOG)
// 4 seconds timeout
uint32_t timeout = 4000;
// Calculate timeout value in WDT counter ticks: This assumes
// the slow clock is running at 32.768 kHz watchdog
// frequency is therefore 32768 / 128 = 256 Hz
timeout = (timeout << 8) / 1000;
if (timeout == 0)
timeout = 1;
else if (timeout > 0xFFF)
timeout = 0xFFF;
// We want to enable the watchdog with the specified timeout
uint32_t value =
WDT_MR_WDV(timeout) | // With the specified timeout
WDT_MR_WDD(timeout) | // and no invalid write window
#if !(SAMV70 || SAMV71 || SAME70 || SAMS70)
WDT_MR_WDRPROC | // WDT fault resets processor only - We want
// to keep PIO controller state
#endif
WDT_MR_WDDBGHLT | // WDT stops in debug state.
WDT_MR_WDIDLEHLT; // WDT stops in idle state.
#if ENABLED(WATCHDOG_RESET_MANUAL)
// We enable the watchdog timer, but only for the interrupt.
// Configure WDT to only trigger an interrupt
value |= WDT_MR_WDFIEN; // Enable WDT fault interrupt.
// Disable WDT interrupt (just in case, to avoid triggering it!)
NVIC_DisableIRQ(WDT_IRQn);
// 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();
// Initialize WDT with the given parameters
WDT_Enable(WDT, value);
// Configure and enable WDT interrupt.
NVIC_ClearPendingIRQ(WDT_IRQn);
NVIC_SetPriority(WDT_IRQn, 0); // Use highest priority, so we detect all kinds of lockups
NVIC_EnableIRQ(WDT_IRQn);
#else
// a WDT fault triggers a reset
value |= WDT_MR_WDRSTEN;
// Initialize WDT with the given parameters
WDT_Enable(WDT, value);
#endif
// Reset the watchdog
WDT_Restart(WDT);
#else
// Make sure to completely disable the Watchdog
WDT_Disable(WDT);
#endif
}
#if ENABLED(USE_WATCHDOG)
// Initialize watchdog - On SAM3X, Watchdog was already configured
// and enabled or disabled at startup, so no need to reconfigure it
// here.
void watchdog_init() {
// Reset watchdog to start clean
WDT_Restart(WDT);
}
#endif // USE_WATCHDOG
#endif

View File

@ -20,14 +20,10 @@
* *
*/ */
#include "FlushableHardwareSerial.h"
#ifdef ARDUINO_ARCH_ESP32 #ifdef ARDUINO_ARCH_ESP32
FlushableHardwareSerial::FlushableHardwareSerial(int uart_nr) #include "FlushableHardwareSerial.h"
: HardwareSerial(uart_nr)
{}
FlushableHardwareSerial flushableSerial(0); Serial1Class<FlushableHardwareSerial> flushableSerial(false, 0);
#endif // ARDUINO_ARCH_ESP32 #endif

View File

@ -21,17 +21,14 @@
*/ */
#pragma once #pragma once
#ifdef ARDUINO_ARCH_ESP32
#include <HardwareSerial.h> #include <HardwareSerial.h>
#include "../shared/Marduino.h"
#include "../../core/serial_hook.h"
class FlushableHardwareSerial : public HardwareSerial { class FlushableHardwareSerial : public HardwareSerial {
public: public:
FlushableHardwareSerial(int uart_nr); FlushableHardwareSerial(int uart_nr) : HardwareSerial(uart_nr) {}
inline void flushTX() { /* No need to flush the hardware serial, but defined here for compatibility. */ }
}; };
extern FlushableHardwareSerial flushableSerial; extern Serial1Class<FlushableHardwareSerial> flushableSerial;
#endif // ARDUINO_ARCH_ESP32

View File

@ -28,6 +28,10 @@
#include <esp_adc_cal.h> #include <esp_adc_cal.h>
#include <HardwareSerial.h> #include <HardwareSerial.h>
#if ENABLED(USE_ESP32_TASK_WDT)
#include <esp_task_wdt.h>
#endif
#if ENABLED(WIFISUPPORT) #if ENABLED(WIFISUPPORT)
#include <ESPAsyncWebServer.h> #include <ESPAsyncWebServer.h>
#include "wifi.h" #include "wifi.h"
@ -40,11 +44,15 @@
#endif #endif
#endif #endif
#if ENABLED(ESP3D_WIFISUPPORT)
DefaultSerial1 MSerial0(false, Serial2Socket);
#endif
// ------------------------ // ------------------------
// Externs // Externs
// ------------------------ // ------------------------
portMUX_TYPE spinlock = portMUX_INITIALIZER_UNLOCKED; portMUX_TYPE MarlinHAL::spinlock = portMUX_INITIALIZER_UNLOCKED;
// ------------------------ // ------------------------
// Local defines // Local defines
@ -56,7 +64,8 @@ portMUX_TYPE spinlock = portMUX_INITIALIZER_UNLOCKED;
// Public Variables // Public Variables
// ------------------------ // ------------------------
uint16_t HAL_adc_result; uint16_t MarlinHAL::adc_result;
pwm_pin_t MarlinHAL::pwm_pin_data[MAX_EXPANDER_BITS];
// ------------------------ // ------------------------
// Private Variables // Private Variables
@ -65,9 +74,16 @@ uint16_t HAL_adc_result;
esp_adc_cal_characteristics_t characteristics[ADC_ATTEN_MAX]; esp_adc_cal_characteristics_t characteristics[ADC_ATTEN_MAX];
adc_atten_t attenuations[ADC1_CHANNEL_MAX] = {}; adc_atten_t attenuations[ADC1_CHANNEL_MAX] = {};
uint32_t thresholds[ADC_ATTEN_MAX]; uint32_t thresholds[ADC_ATTEN_MAX];
volatile int numPWMUsed = 0,
pwmPins[MAX_PWM_PINS], volatile int numPWMUsed = 0;
pwmValues[MAX_PWM_PINS]; volatile struct { pin_t pin; int value; } pwmState[MAX_PWM_PINS];
pin_t chan_pin[CHANNEL_MAX_NUM + 1] = { 0 }; // PWM capable IOpins - not 0 or >33 on ESP32
struct {
uint32_t freq; // ledcReadFreq doesn't work if a duty hasn't been set yet!
uint16_t res;
} pwmInfo[(CHANNEL_MAX_NUM + 1) / 2];
// ------------------------ // ------------------------
// Public functions // Public functions
@ -86,10 +102,26 @@ volatile int numPWMUsed = 0,
#endif #endif
void HAL_init() { i2s_init(); } #if ENABLED(USE_ESP32_EXIO)
void HAL_init_board() { HardwareSerial YSerial2(2);
void Write_EXIO(uint8_t IO, uint8_t v) {
if (hal.isr_state()) {
hal.isr_off();
YSerial2.write(0x80 | (((char)v) << 5) | (IO - 100));
hal.isr_on();
}
else
YSerial2.write(0x80 | (((char)v) << 5) | (IO - 100));
}
#endif
void MarlinHAL::init_board() {
#if ENABLED(USE_ESP32_TASK_WDT)
esp_task_wdt_init(10, true);
#endif
#if ENABLED(ESP3D_WIFISUPPORT) #if ENABLED(ESP3D_WIFISUPPORT)
esp3dlib.init(); esp3dlib.init();
#elif ENABLED(WIFISUPPORT) #elif ENABLED(WIFISUPPORT)
@ -122,27 +154,61 @@ void HAL_init_board() {
#endif #endif
#endif #endif
// Initialize the i2s peripheral only if the I2S stepper stream is enabled.
// The following initialization is performed after Serial1 and Serial2 are defined as
// their native pins might conflict with the i2s stream even when they are remapped.
#if ENABLED(USE_ESP32_EXIO)
YSerial2.begin(460800 * 3, SERIAL_8N1, 16, 17);
#elif ENABLED(I2S_STEPPER_STREAM)
i2s_init();
#endif
} }
void HAL_idletask() { void MarlinHAL::idletask() {
#if BOTH(WIFISUPPORT, OTASUPPORT) #if BOTH(WIFISUPPORT, OTASUPPORT)
OTA_handle(); OTA_handle();
#endif #endif
TERN_(ESP3D_WIFISUPPORT, esp3dlib.idletask()); TERN_(ESP3D_WIFISUPPORT, esp3dlib.idletask());
} }
void HAL_clear_reset_source() { } uint8_t MarlinHAL::get_reset_source() { return rtc_get_reset_reason(1); }
uint8_t HAL_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(int delay_ms) { delay(delay_ms); }
// return free memory between end of heap (or end bss) and whatever is current // return free memory between end of heap (or end bss) and whatever is current
int freeMemory() { return ESP.getFreeHeap(); } int MarlinHAL::freeMemory() { return ESP.getFreeHeap(); }
// ------------------------
// Watchdog Timer
// ------------------------
#if ENABLED(USE_WATCHDOG)
#define WDT_TIMEOUT_US TERN(WATCHDOG_DURATION_8S, 8000000, 4000000) // 4 or 8 second timeout
extern "C" {
esp_err_t esp_task_wdt_reset();
}
void watchdogSetup() {
// do whatever. don't remove this function.
}
void MarlinHAL::watchdog_init() {
// TODO
}
// Reset watchdog.
void MarlinHAL::watchdog_refresh() { esp_task_wdt_reset(); }
#endif
// ------------------------ // ------------------------
// ADC // ADC
// ------------------------ // ------------------------
#define ADC1_CHANNEL(pin) ADC1_GPIO ## pin ## _CHANNEL #define ADC1_CHANNEL(pin) ADC1_GPIO ## pin ## _CHANNEL
adc1_channel_t get_channel(int pin) { adc1_channel_t get_channel(int pin) {
@ -164,21 +230,24 @@ void adc1_set_attenuation(adc1_channel_t chan, adc_atten_t atten) {
} }
} }
void HAL_adc_init() { void MarlinHAL::adc_init() {
// Configure ADC // Configure ADC
adc1_config_width(ADC_WIDTH_12Bit); adc1_config_width(ADC_WIDTH_12Bit);
// Configure channels only if used as (re-)configuring a pin for ADC that is used elsewhere might have adverse effects // Configure channels only if used as (re-)configuring a pin for ADC that is used elsewhere might have adverse effects
TERN_(HAS_TEMP_ADC_0, adc1_set_attenuation(get_channel(TEMP_0_PIN), ADC_ATTEN_11db)); TERN_(HAS_TEMP_ADC_0, adc1_set_attenuation(get_channel(TEMP_0_PIN), ADC_ATTEN_11db));
TERN_(HAS_TEMP_ADC_1, adc1_set_attenuation(get_channel(TEMP_1_PIN), ADC_ATTEN_11db)); TERN_(HAS_TEMP_ADC_1, adc1_set_attenuation(get_channel(TEMP_1_PIN), ADC_ATTEN_11db));
TERN_(HAS_TEMP_ADC_2, adc1_set_attenuation(get_channel(TEMP_2_PIN), ADC_ATTEN_11db)); TERN_(HAS_TEMP_ADC_2, adc1_set_attenuation(get_channel(TEMP_2_PIN), ADC_ATTEN_11db));
TERN_(HAS_TEMP_ADC_3, adc1_set_attenuation(get_channel(TEMP_3_PIN), ADC_ATTEN_11db)); TERN_(HAS_TEMP_ADC_3, adc1_set_attenuation(get_channel(TEMP_3_PIN), ADC_ATTEN_11db));
TERN_(HAS_TEMP_ADC_4, adc1_set_attenuation(get_channel(TEMP_4_PIN), ADC_ATTEN_11db)); TERN_(HAS_TEMP_ADC_4, adc1_set_attenuation(get_channel(TEMP_4_PIN), ADC_ATTEN_11db));
TERN_(HAS_TEMP_ADC_5, adc1_set_attenuation(get_channel(TEMP_5_PIN), ADC_ATTEN_11db)); TERN_(HAS_TEMP_ADC_5, adc1_set_attenuation(get_channel(TEMP_5_PIN), ADC_ATTEN_11db));
TERN_(HAS_TEMP_ADC_6, adc2_set_attenuation(get_channel(TEMP_6_PIN), ADC_ATTEN_11db)); TERN_(HAS_TEMP_ADC_6, adc2_set_attenuation(get_channel(TEMP_6_PIN), ADC_ATTEN_11db));
TERN_(HAS_TEMP_ADC_7, adc3_set_attenuation(get_channel(TEMP_7_PIN), ADC_ATTEN_11db)); TERN_(HAS_TEMP_ADC_7, adc3_set_attenuation(get_channel(TEMP_7_PIN), ADC_ATTEN_11db));
TERN_(HAS_HEATED_BED, adc1_set_attenuation(get_channel(TEMP_BED_PIN), ADC_ATTEN_11db)); TERN_(HAS_HEATED_BED, adc1_set_attenuation(get_channel(TEMP_BED_PIN), ADC_ATTEN_11db));
TERN_(HAS_TEMP_CHAMBER, adc1_set_attenuation(get_channel(TEMP_CHAMBER_PIN), ADC_ATTEN_11db)); TERN_(HAS_TEMP_CHAMBER, adc1_set_attenuation(get_channel(TEMP_CHAMBER_PIN), ADC_ATTEN_11db));
TERN_(HAS_TEMP_PROBE, adc1_set_attenuation(get_channel(TEMP_PROBE_PIN), ADC_ATTEN_11db));
TERN_(HAS_TEMP_COOLER, adc1_set_attenuation(get_channel(TEMP_COOLER_PIN), ADC_ATTEN_11db));
TERN_(HAS_TEMP_BOARD, adc1_set_attenuation(get_channel(TEMP_BOARD_PIN), ADC_ATTEN_11db));
TERN_(FILAMENT_WIDTH_SENSOR, adc1_set_attenuation(get_channel(FILWIDTH_PIN), ADC_ATTEN_11db)); TERN_(FILAMENT_WIDTH_SENSOR, adc1_set_attenuation(get_channel(FILWIDTH_PIN), ADC_ATTEN_11db));
// Note that adc2 is shared with the WiFi module, which has higher priority, so the conversion may fail. // Note that adc2 is shared with the WiFi module, which has higher priority, so the conversion may fail.
@ -193,11 +262,16 @@ void HAL_adc_init() {
} }
} }
void HAL_adc_start_conversion(const uint8_t adc_pin) { #ifndef ADC_REFERENCE_VOLTAGE
const adc1_channel_t chan = get_channel(adc_pin); #define ADC_REFERENCE_VOLTAGE 3.3
#endif
void MarlinHAL::adc_start(const pin_t pin) {
const adc1_channel_t chan = get_channel(pin);
uint32_t mv; uint32_t mv;
esp_adc_cal_get_voltage((adc_channel_t)chan, &characteristics[attenuations[chan]], &mv); esp_adc_cal_get_voltage((adc_channel_t)chan, &characteristics[attenuations[chan]], &mv);
HAL_adc_result = mv * 1023.0 / 3300.0;
adc_result = mv * isr_float_t(1023) / isr_float_t(ADC_REFERENCE_VOLTAGE) / isr_float_t(1000);
// Change the attenuation level based on the new reading // Change the attenuation level based on the new reading
adc_atten_t atten; adc_atten_t atten;
@ -214,25 +288,106 @@ void HAL_adc_start_conversion(const uint8_t adc_pin) {
adc1_set_attenuation(chan, atten); adc1_set_attenuation(chan, atten);
} }
void analogWrite(pin_t pin, int value) { // ------------------------
// Use ledc hardware for internal pins // PWM
if (pin < 34) { // ------------------------
static int cnt_channel = 1, pin_to_channel[40] = { 0 };
if (pin_to_channel[pin] == 0) { int8_t channel_for_pin(const uint8_t pin) {
ledcAttachPin(pin, cnt_channel); for (int i = 0; i <= CHANNEL_MAX_NUM; i++)
ledcSetup(cnt_channel, 490, 8); if (chan_pin[i] == pin) return i;
ledcWrite(cnt_channel, value); return -1;
pin_to_channel[pin] = cnt_channel++; }
// get PWM channel for pin - if none then attach a new one
// return -1 if fail or invalid pin#, channel # (0-15) if success
int8_t get_pwm_channel(const pin_t pin, const uint32_t freq, const uint16_t res) {
if (!WITHIN(pin, 1, MAX_PWM_IOPIN)) return -1; // Not a hardware PWM pin!
int8_t cid = channel_for_pin(pin);
if (cid >= 0) return cid;
// Find an empty adjacent channel (same timer & freq/res)
for (int i = 0; i <= CHANNEL_MAX_NUM; i++) {
if (chan_pin[i] == 0) {
if (chan_pin[i ^ 0x1] != 0) {
if (pwmInfo[i / 2].freq == freq && pwmInfo[i / 2].res == res) {
chan_pin[i] = pin; // Allocate PWM to this channel
ledcAttachPin(pin, i);
return i;
}
}
else if (cid == -1) // Pair of empty channels?
cid = i & 0xFE; // Save lower channel number
} }
ledcWrite(pin_to_channel[pin], value); }
// not attached, is an empty timer slot avail?
if (cid >= 0) {
chan_pin[cid] = pin;
pwmInfo[cid / 2].freq = freq;
pwmInfo[cid / 2].res = res;
ledcSetup(cid, freq, res);
ledcAttachPin(pin, cid);
}
return cid; // -1 if no channel avail
}
void MarlinHAL::set_pwm_duty(const pin_t pin, const uint16_t v, const uint16_t v_size/*=_BV(PWM_RESOLUTION)-1*/, const bool invert/*=false*/) {
#if ENABLED(I2S_STEPPER_STREAM)
if (pin > 127) {
const uint8_t pinlo = pin & 0x7F;
pwm_pin_t &pindata = pwm_pin_data[pinlo];
const uint32_t duty = map(invert ? v_size - v : v, 0, v_size, 0, pindata.pwm_cycle_ticks);
if (duty == 0 || duty == pindata.pwm_cycle_ticks) { // max or min (i.e., on/off)
pindata.pwm_duty_ticks = 0; // turn off PWM for this pin
duty ? SBI32(i2s_port_data, pinlo) : CBI32(i2s_port_data, pinlo); // set pin level
}
else
pindata.pwm_duty_ticks = duty; // PWM duty count = # of 4µs ticks per full PWM cycle
}
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);
}
}
}
int8_t MarlinHAL::set_pwm_frequency(const pin_t pin, const uint32_t f_desired) {
#if ENABLED(I2S_STEPPER_STREAM)
if (pin > 127) {
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
}
}
// use hardware PWM if avail, if not then ISR
void analogWrite(const pin_t pin, const uint16_t value, const uint32_t freq/*=PWM_FREQUENCY*/, const uint16_t res/*=8*/) { // always 8 bit resolution!
// Use ledc hardware for internal pins
const int8_t cid = get_pwm_channel(pin, freq, res);
if (cid >= 0) {
ledcWrite(cid, value); // set duty value
return; return;
} }
// not a hardware PWM pin OR no PWM channels available
int idx = -1; int idx = -1;
// Search Pin // Search Pin
for (int i = 0; i < numPWMUsed; ++i) for (int i = 0; i < numPWMUsed; ++i)
if (pwmPins[i] == pin) { idx = i; break; } if (pwmState[i].pin == pin) { idx = i; break; }
// not found ? // not found ?
if (idx < 0) { if (idx < 0) {
@ -241,34 +396,34 @@ void analogWrite(pin_t pin, int value) {
// Take new slot for pin // Take new slot for pin
idx = numPWMUsed; idx = numPWMUsed;
pwmPins[idx] = pin; pwmState[idx].pin = pin;
// Start timer on first use // Start timer on first use
if (idx == 0) HAL_timer_start(PWM_TIMER_NUM, PWM_TIMER_FREQUENCY); if (idx == 0) HAL_timer_start(MF_TIMER_PWM, PWM_TIMER_FREQUENCY);
++numPWMUsed; ++numPWMUsed;
} }
// Use 7bit internal value - add 1 to have 100% high at 255 // Use 7bit internal value - add 1 to have 100% high at 255
pwmValues[idx] = (value + 1) / 2; pwmState[idx].value = (value + 1) / 2;
} }
// Handle PWM timer interrupt // Handle PWM timer interrupt
HAL_PWM_TIMER_ISR() { HAL_PWM_TIMER_ISR() {
HAL_timer_isr_prologue(PWM_TIMER_NUM); HAL_timer_isr_prologue(MF_TIMER_PWM);
static uint8_t count = 0; static uint8_t count = 0;
for (int i = 0; i < numPWMUsed; ++i) { for (int i = 0; i < numPWMUsed; ++i) {
if (count == 0) // Start of interval if (count == 0) // Start of interval
WRITE(pwmPins[i], pwmValues[i] ? HIGH : LOW); digitalWrite(pwmState[i].pin, pwmState[i].value ? HIGH : LOW);
else if (pwmValues[i] == count) // End of duration else if (pwmState[i].value == count) // End of duration
WRITE(pwmPins[i], LOW); digitalWrite(pwmState[i].pin, LOW);
} }
// 128 for 7 Bit resolution // 128 for 7 Bit resolution
count = (count + 1) & 0x7F; count = (count + 1) & 0x7F;
HAL_timer_isr_epilogue(PWM_TIMER_NUM); HAL_timer_isr_epilogue(MF_TIMER_PWM);
} }
#endif // ARDUINO_ARCH_ESP32 #endif // ARDUINO_ARCH_ESP32

View File

@ -32,7 +32,6 @@
#include "../shared/HAL_SPI.h" #include "../shared/HAL_SPI.h"
#include "fastio.h" #include "fastio.h"
#include "watchdog.h"
#include "i2s.h" #include "i2s.h"
#if ENABLED(WIFISUPPORT) #if ENABLED(WIFISUPPORT)
@ -49,87 +48,68 @@
// Defines // Defines
// ------------------------ // ------------------------
extern portMUX_TYPE spinlock; #define MYSERIAL1 flushableSerial
#define MYSERIAL0 flushableSerial
#if EITHER(WIFISUPPORT, ESP3D_WIFISUPPORT) #if EITHER(WIFISUPPORT, ESP3D_WIFISUPPORT)
#if ENABLED(ESP3D_WIFISUPPORT) #if ENABLED(ESP3D_WIFISUPPORT)
#define MYSERIAL1 Serial2Socket typedef ForwardSerial1Class< decltype(Serial2Socket) > DefaultSerial1;
extern DefaultSerial1 MSerial0;
#define MYSERIAL2 MSerial0
#else #else
#define MYSERIAL1 webSocketSerial #define MYSERIAL2 webSocketSerial
#endif #endif
#endif #endif
#define CRITICAL_SECTION_START() portENTER_CRITICAL(&spinlock) #define CRITICAL_SECTION_START() portENTER_CRITICAL(&hal.spinlock)
#define CRITICAL_SECTION_END() portEXIT_CRITICAL(&spinlock) #define CRITICAL_SECTION_END() portEXIT_CRITICAL(&hal.spinlock)
#define ISRS_ENABLED() (spinlock.owner == portMUX_FREE_VAL)
#define ENABLE_ISRS() if (spinlock.owner != portMUX_FREE_VAL) portEXIT_CRITICAL(&spinlock)
#define DISABLE_ISRS() portENTER_CRITICAL(&spinlock)
// Fix bug in pgm_read_ptr #define HAL_CAN_SET_PWM_FREQ // This HAL supports PWM Frequency adjustment
#undef pgm_read_ptr #define PWM_FREQUENCY 1000u // Default PWM frequency when set_pwm_duty() is called without set_pwm_frequency()
#define pgm_read_ptr(addr) (*(addr)) #define PWM_RESOLUTION 10u // Default PWM bit resolution
#define CHANNEL_MAX_NUM 15u // max PWM channel # to allocate (7 to only use low speed, 15 to use low & high)
#define MAX_PWM_IOPIN 33u // hardware pwm pins < 34
#ifndef MAX_EXPANDER_BITS
#define MAX_EXPANDER_BITS 32 // I2S expander bit width (max 32)
#endif
// ------------------------ // ------------------------
// Types // Types
// ------------------------ // ------------------------
typedef double isr_float_t; // FPU ops are used for single-precision, so use double for ISRs.
typedef int16_t pin_t; typedef int16_t pin_t;
#define HAL_SERVO_LIB Servo typedef struct pwm_pin {
uint32_t pwm_cycle_ticks = 1000000UL / (PWM_FREQUENCY) / 4; // # ticks per pwm cycle
uint32_t pwm_tick_count = 0; // current tick count
uint32_t pwm_duty_ticks = 0; // # of ticks for current duty cycle
} pwm_pin_t;
// ------------------------ class Servo;
// Public Variables typedef Servo hal_servo_t;
// ------------------------
/** result of last ADC conversion */
extern uint16_t HAL_adc_result;
// ------------------------ // ------------------------
// Public functions // Public functions
// ------------------------ // ------------------------
// clear reset reason //
void HAL_clear_reset_source(); // Tone
//
// reset reason void tone(const pin_t _pin, const unsigned int frequency, const unsigned long duration=0);
uint8_t HAL_get_reset_source(); void noTone(const pin_t _pin);
int8_t get_pwm_channel(const pin_t pin, const uint32_t freq, const uint16_t res);
inline void HAL_reboot() {} // reboot the board or restart the bootloader void analogWrite(const pin_t pin, const uint16_t value, const uint32_t freq=PWM_FREQUENCY, const uint16_t res=8);
void _delay_ms(int delay);
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wunused-function"
int freeMemory();
#pragma GCC diagnostic pop
void analogWrite(pin_t pin, int value);
// ADC
#define HAL_ANALOG_SELECT(pin)
void HAL_adc_init();
#define HAL_ADC_VREF 3.3
#define HAL_ADC_RESOLUTION 10
#define HAL_START_ADC(pin) HAL_adc_start_conversion(pin)
#define HAL_READ_ADC() HAL_adc_result
#define HAL_ADC_READY() true
void HAL_adc_start_conversion(const uint8_t adc_pin);
//
// Pin Mapping for M42, M43, M226
//
#define GET_PIN_MAP_PIN(index) index #define GET_PIN_MAP_PIN(index) index
#define GET_PIN_MAP_INDEX(pin) pin #define GET_PIN_MAP_INDEX(pin) pin
#define PARSED_PIN_INDEX(code, dval) parser.intval(code, dval) #define PARSED_PIN_INDEX(code, dval) parser.intval(code, dval)
// Enable hooks into idle and setup for HAL #if ENABLED(USE_ESP32_EXIO)
#define HAL_IDLETASK 1 void Write_EXIO(uint8_t IO, uint8_t v);
#define BOARD_INIT() HAL_init_board(); #endif
void HAL_idletask();
void HAL_init();
void HAL_init_board();
// //
// Delay in cycles (used by DELAY_NS / DELAY_US) // Delay in cycles (used by DELAY_NS / DELAY_US)
@ -171,3 +151,96 @@ FORCE_INLINE static void DELAY_CYCLES(uint32_t x) {
} }
} }
// ------------------------
// Class Utilities
// ------------------------
#pragma GCC diagnostic push
#if GCC_VERSION <= 50000
#pragma GCC diagnostic ignored "-Wunused-function"
#endif
int freeMemory();
#pragma GCC diagnostic pop
void _delay_ms(const int ms);
// ------------------------
// MarlinHAL Class
// ------------------------
#define HAL_ADC_VREF 3.3
#define HAL_ADC_RESOLUTION 10
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
// Interrupts
static portMUX_TYPE spinlock;
static bool isr_state() { return spinlock.owner == portMUX_FREE_VAL; }
static void isr_on() { if (spinlock.owner != portMUX_FREE_VAL) portEXIT_CRITICAL(&spinlock); }
static void isr_off() { portENTER_CRITICAL(&spinlock); }
static void delay_ms(const int ms) { _delay_ms(ms); }
// Tasks, called from idle()
static void idletask();
// Reset
static uint8_t get_reset_source();
static void clear_reset_source() {}
// Free SRAM
static int freeMemory();
static pwm_pin_t pwm_pin_data[MAX_EXPANDER_BITS];
//
// 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 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() { return true; }
// The current value of the ADC register
static uint16_t adc_value() { return adc_result; }
/**
* If not already allocated, allocate a hardware PWM channel
* to the pin and set the duty cycle..
* Optionally invert the duty cycle [default = false]
* Optionally change the scale of the provided value to enable finer PWM duty control [default = 255]
*/
static void set_pwm_duty(const pin_t pin, const uint16_t v, const uint16_t v_size=255, const bool invert=false);
/**
* Allocate and set the frequency of a hardware PWM pin
* Returns -1 if no pin available.
*/
static int8_t set_pwm_frequency(const pin_t pin, const uint32_t f_desired);
};

View File

@ -53,11 +53,9 @@ static SPISettings spiConfig;
// ------------------------ // ------------------------
void spiBegin() { void spiBegin() {
#if !PIN_EXISTS(SS) #if ENABLED(SDSUPPORT) && PIN_EXISTS(SD_SS)
#error "SS_PIN not defined!" OUT_WRITE(SD_SS_PIN, HIGH);
#endif #endif
OUT_WRITE(SS_PIN, HIGH);
} }
void spiInit(uint8_t spiRate) { void spiInit(uint8_t spiRate) {
@ -85,7 +83,7 @@ uint8_t spiRec() {
return returnByte; return returnByte;
} }
void spiRead(uint8_t* buf, uint16_t nbyte) { void spiRead(uint8_t *buf, uint16_t nbyte) {
SPI.beginTransaction(spiConfig); SPI.beginTransaction(spiConfig);
SPI.transferBytes(0, buf, nbyte); SPI.transferBytes(0, buf, nbyte);
SPI.endTransaction(); SPI.endTransaction();
@ -97,7 +95,7 @@ void spiSend(uint8_t b) {
SPI.endTransaction(); SPI.endTransaction();
} }
void spiSendBlock(uint8_t token, const uint8_t* buf) { void spiSendBlock(uint8_t token, const uint8_t *buf) {
SPI.beginTransaction(spiConfig); SPI.beginTransaction(spiConfig);
SPI.transfer(token); SPI.transfer(token);
SPI.writeBytes(const_cast<uint8_t*>(buf), 512); SPI.writeBytes(const_cast<uint8_t*>(buf), 512);

View File

@ -0,0 +1,26 @@
/**
* 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 <https://www.gnu.org/licenses/>.
*
*/
#pragma once
#include <SPI.h>
using MarlinSPI = SPIClass;

View File

@ -31,20 +31,18 @@
// so we only allocate servo channels up high to avoid side effects with regards to analogWrite (fans, leds, laser pwm etc.) // so we only allocate servo channels up high to avoid side effects with regards to analogWrite (fans, leds, laser pwm etc.)
int Servo::channel_next_free = 12; int Servo::channel_next_free = 12;
Servo::Servo() { Servo::Servo() {}
channel = channel_next_free++;
}
int8_t Servo::attach(const int inPin) { int8_t Servo::attach(const int inPin) {
if (channel >= CHANNEL_MAX_NUM) return -1;
if (inPin > 0) pin = inPin; if (inPin > 0) pin = inPin;
channel = get_pwm_channel(pin, 50u, 16u);
ledcSetup(channel, 50, 16); // channel X, 50 Hz, 16-bit depth return channel; // -1 if no PWM avail.
ledcAttachPin(pin, channel);
return true;
} }
void Servo::detach() { ledcDetachPin(pin); } // leave channel connected to servo - set duty to zero
void Servo::detach() {
if (channel >= 0) ledcWrite(channel, 0);
}
int Servo::read() { return degrees; } int Servo::read() { return degrees; }
@ -52,7 +50,7 @@ void Servo::write(int inDegrees) {
degrees = constrain(inDegrees, MIN_ANGLE, MAX_ANGLE); degrees = constrain(inDegrees, MIN_ANGLE, MAX_ANGLE);
int us = map(degrees, MIN_ANGLE, MAX_ANGLE, MIN_PULSE_WIDTH, MAX_PULSE_WIDTH); int us = map(degrees, MIN_ANGLE, MAX_ANGLE, MIN_PULSE_WIDTH, MAX_PULSE_WIDTH);
int duty = map(us, 0, TAU_USEC, 0, MAX_COMPARE); int duty = map(us, 0, TAU_USEC, 0, MAX_COMPARE);
ledcWrite(channel, duty); if (channel >= 0) ledcWrite(channel, duty); // don't save duty for servos!
} }
void Servo::move(const int value) { void Servo::move(const int value) {

View File

@ -30,8 +30,7 @@ class Servo {
MAX_PULSE_WIDTH = 2400, // Longest pulse sent to a servo MAX_PULSE_WIDTH = 2400, // Longest pulse sent to a servo
TAU_MSEC = 20, TAU_MSEC = 20,
TAU_USEC = (TAU_MSEC * 1000), TAU_USEC = (TAU_MSEC * 1000),
MAX_COMPARE = ((1 << 16) - 1), // 65535 MAX_COMPARE = _BV(16) - 1; // 65535
CHANNEL_MAX_NUM = 16;
public: public:
Servo(); Servo();

View File

@ -5,6 +5,8 @@
* Based on Sprinter and grbl. * Based on Sprinter and grbl.
* Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm * Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm
* *
* Copypaste of SAMD51 HAL developed by Giuliano Zaro (AKA GMagician)
*
* This program is free software: you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or * the Free Software Foundation, either version 3 of the License, or
@ -21,41 +23,37 @@
*/ */
/** /**
* HAL for stm32duino.com based on Libmaple and compatible (STM32F1) * Description: Tone function for ESP32
* Derived from https://forum.arduino.cc/index.php?topic=136500.msg2903012#msg2903012
*/ */
#ifdef __STM32F1__ #ifdef ARDUINO_ARCH_ESP32
#include "../../inc/MarlinConfig.h" #include "../../inc/MarlinConfig.h"
#include "HAL.h"
#if ENABLED(USE_WATCHDOG) static pin_t tone_pin;
volatile static int32_t toggles;
#include <libmaple/iwdg.h> void tone(const pin_t _pin, const unsigned int frequency, const unsigned long duration/*=0*/) {
#include "watchdog.h" tone_pin = _pin;
toggles = 2 * frequency * duration / 1000;
void HAL_watchdog_refresh() { HAL_timer_start(MF_TIMER_TONE, 2 * frequency);
#if DISABLED(PINS_DEBUGGING) && PIN_EXISTS(LED)
TOGGLE(LED_PIN); // heartbeat indicator
#endif
iwdg_feed();
} }
void watchdogSetup() { void noTone(const pin_t _pin) {
// do whatever. don't remove this function. HAL_timer_disable_interrupt(MF_TIMER_TONE);
WRITE(_pin, LOW);
} }
/** HAL_TONE_TIMER_ISR() {
* @brief Initialized the independent hardware watchdog. HAL_timer_isr_prologue(MF_TIMER_TONE);
*
* @return No return if (toggles) {
* toggles--;
* @details The watchdog clock is 40Khz. We need a 4 seconds interval, so use a /256 preescaler and 625 reload value (counts down to 0) TOGGLE(tone_pin);
*/ }
void watchdog_init() { else noTone(tone_pin); // turn off interrupt
#if DISABLED(DISABLE_WATCHDOG_INIT)
iwdg_init(IWDG_PRE_256, STM32F1_WD_RELOAD);
#endif
} }
#endif // USE_WATCHDOG #endif // ARDUINO_ARCH_ESP32
#endif // __STM32F1__

View File

@ -29,7 +29,7 @@
#include "wifi.h" #include "wifi.h"
#include <ESPAsyncWebServer.h> #include <ESPAsyncWebServer.h>
WebSocketSerial webSocketSerial; MSerialWebSocketT webSocketSerial(false);
AsyncWebSocket ws("/ws"); // TODO Move inside the class. AsyncWebSocket ws("/ws"); // TODO Move inside the class.
// RingBuffer impl // RingBuffer impl
@ -137,16 +137,12 @@ size_t WebSocketSerial::write(const uint8_t c) {
return ret; return ret;
} }
size_t WebSocketSerial::write(const uint8_t* buffer, size_t size) { size_t WebSocketSerial::write(const uint8_t *buffer, size_t size) {
size_t written = 0; size_t written = 0;
for (size_t i = 0; i < size; i++) for (size_t i = 0; i < size; i++)
written += write(buffer[i]); written += write(buffer[i]);
return written; return written;
} }
void WebSocketSerial::flushTX() {
// No need to do anything as there's no benefit to sending partial lines over the websocket connection.
}
#endif // WIFISUPPORT #endif // WIFISUPPORT
#endif // ARDUINO_ARCH_ESP32 #endif // ARDUINO_ARCH_ESP32

View File

@ -22,6 +22,7 @@
#pragma once #pragma once
#include "../../inc/MarlinConfig.h" #include "../../inc/MarlinConfig.h"
#include "../../core/serial_hook.h"
#include <Stream.h> #include <Stream.h>
@ -53,7 +54,7 @@ public:
ring_buffer_pos_t read(uint8_t *buffer); ring_buffer_pos_t read(uint8_t *buffer);
void flush(); void flush();
ring_buffer_pos_t write(const uint8_t c); ring_buffer_pos_t write(const uint8_t c);
ring_buffer_pos_t write(const uint8_t* buffer, ring_buffer_pos_t size); ring_buffer_pos_t write(const uint8_t *buffer, ring_buffer_pos_t size);
}; };
class WebSocketSerial: public Stream { class WebSocketSerial: public Stream {
@ -68,11 +69,8 @@ public:
int peek(); int peek();
int read(); int read();
void flush(); void flush();
void flushTX();
size_t write(const uint8_t c); size_t write(const uint8_t c);
size_t write(const uint8_t* buffer, size_t size); size_t write(const uint8_t *buffer, size_t size);
operator bool() { return true; }
#if ENABLED(SERIAL_STATS_DROPPED_RX) #if ENABLED(SERIAL_STATS_DROPPED_RX)
FORCE_INLINE uint32_t dropped() { return 0; } FORCE_INLINE uint32_t dropped() { return 0; }
@ -83,4 +81,5 @@ public:
#endif #endif
}; };
extern WebSocketSerial webSocketSerial; typedef Serial1Class<WebSocketSerial> MSerialWebSocketT;
extern MSerialWebSocketT webSocketSerial;

View File

@ -44,7 +44,7 @@ bool PersistentStore::write_data(int &pos, const uint8_t *value, size_t size, ui
return false; return false;
} }
bool PersistentStore::read_data(int &pos, uint8_t* value, size_t size, uint16_t *crc, const bool writing/*=true*/) { bool PersistentStore::read_data(int &pos, uint8_t *value, size_t size, uint16_t *crc, const bool writing/*=true*/) {
for (size_t i = 0; i < size; i++) { for (size_t i = 0; i < size; i++) {
uint8_t c = EEPROM.read(pos++); uint8_t c = EEPROM.read(pos++);
if (writing) value[i] = c; if (writing) value[i] = c;

View File

@ -59,4 +59,16 @@ void setup_endstop_interrupts() {
TERN_(HAS_Z4_MAX, _ATTACH(Z4_MAX_PIN)); TERN_(HAS_Z4_MAX, _ATTACH(Z4_MAX_PIN));
TERN_(HAS_Z4_MIN, _ATTACH(Z4_MIN_PIN)); TERN_(HAS_Z4_MIN, _ATTACH(Z4_MIN_PIN));
TERN_(HAS_Z_MIN_PROBE_PIN, _ATTACH(Z_MIN_PROBE_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));
} }

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