**New Year 2024 (20240107)**

* The background of hot-end icon and bed icon blinks when they are being heating
* Fix for https://github.com/mriscoc/Ender3V2S1/issues/1175
* Adds mesh inset to the mesh validation test
* Fix screen background in trammingWizard regardless an error in the first corner

**New in source code:**
* Enabled M48 menu item only if Z_MIN_PROBE_REPEATABILITY_TEST is enabled
* Moves Bed size menu items after XY MIN/MAX position
* Enables the storage of parameters in the EEPROM only if the respective feature is enabled

**From Marlin Bugfix**
* Slimmer null T command (#26615)
* Followup to optional M111/M115 (#26626)
* Fix hangs in DUE native USB (#26572)
* Fix Bed PID Autotune output (#26606)
* CONFIGURE_FILAMENT_CHANGE - Optional M603 (#26613)
* I3DBEE TECH Beez Mini 12864 (#26596)
* Options to slim M111, remove M115 (#26603)
* BSD string workaround (#26532)
* Fix homing with FT_MOTION (#26595)
* Fix, extend FAN / AUTOFAN confict check (#26591)
* BigTreeTech Manta M8P V2.0 (STM32H723ZE) (#26578)
* Optimize FT_MOTION (#26557)
* TriGorilla Pro default to ONBOARD_SDIO (#26586)
* Specify U8glib-HAL@0.5.4 (#26582)
* Newer Platform & Toolchain for STM32G0 (#26585)
* Initial support for HC32 U8G LCD (#26568)
* Move U8G defines to HALs
* BigTreeTech Kraken V1.0 (STM32H723ZG) (#26565)
* Fix string buffer warning (#26550)
* Fix MARKFORGED_INVERSE typos (#26558)
* Creality Free Runs fixups (#26562)
* Orca 3D Modular Controller (#26534)
* Jerk correction for LIN_ADVANCE + CLASSIC_JERK (#26551)
* Optional FAN_INVERTING
* Just "warn" on SD fail
* FT_MOTION improvements (#26074)
* Fix Creality E3 "Free-runs" (#26533)
* Creality E3 Free-runs Silent Motherboard (#25636)
* Fix planner jerk limits (#26529)
* MARKFORGED_INVERSE (#26516)
* Fix MKS TS35 with BTT SKR 1.3/1.4 (#26176)
* SERIAL_DMA (for some STM32Fx) (#26328)
* Adjust Progress / Completion (#26466)
* Encoder improvements (#26501)
* Use strlcpy with buffer size (#26513)
* Use PIO versioning (including HC32) (#26512)
* Voxelab Aquila N32 (via Maple) (#26470)
* Fix tool-change E prime (#26494)
* Fix thermistor 14 & 60 constexprness (#26499)
* UI refresh for some events (#26487)
* Fix a NeoPixel override (#26492)
* Fix ftostrX3sign (#26497)
* DOUBLE_LCD_FRAMERATE (#26500)
* Fix some action labels (#26490)
* More num-to-string digits / precisions (#26343)
* Fix BLTouch HSMode deploy (#26311)
* Touch fixes (#26455)
* XY_AFTER_HOMING, EVENT_GCODE_AFTER_HOMING (#26469)
* BlackBeezMini 3D by I3DBEE (#26406)
* HAL for HC32F460 (#26414)
* MAX Thermocouples for Heated Bed (#26441)
* Pins for FYSETC Spider King 4.07 (#26461)
* Use ftpl for item strings (#26462)
* BD_SENSOR_PROBE_NO_STOP (#26353)
* Fix PANDA ZHU missing #endif (#26460)
* Update Teensy 4.0/4.1 Serial (#26457)
* Configurable FR/Flow edit ranges (#26446)
* Fix MMU2 sscanf bug, optimize (#26449)
* Fix GT2560_V41b Z2 pin (#26370)
* BTT Octopus Pro V1.0.1 (STM32H723ZE) (#26159)
* Fix Ender-5 S1 env
* Fix more MarlinUI title centering (#26440)
* Fix MarlinUI axis move / UBL strings (#26439)
* Minor touch calibration improvement (#26445)
* Fix rotational AxisFlags (#26444)
* Rotational move items (#26438)
* Define MarlinUI axis moves with lists (#26344)
* Creality STM32F401RC w/out bootloader (#26373)
* Fix runout state in menu (#26394)
And many other Bug fixes and improvements from the Marlin bugfix branch
F4-CRC-TEST
Miguel Risco-Castillo 4 months ago
parent c72017267a
commit f7297881df

21
.gitattributes vendored

@ -0,0 +1,21 @@
# Set the default behavior, in case people don't have core.autocrlf set.
* text=auto
# Files with Unix line endings
*.c text eol=lf
*.cpp text eol=lf
*.h text eol=lf
*.ino text eol=lf
*.py text eol=lf
*.sh text eol=lf
*.scad text eol=lf
# Files with native line endings
# *.sln text
# Binary files
*.png binary
*.jpg binary
*.fon binary
*.bin binary
*.woff binary

@ -1,6 +1,7 @@
name: 🐛 Report a bug
description: Create a bug report to help improve the Professional Firmware
title: "[BUG] (bug summary)"
labels: ["Bug: Potential ?"]
body:
- type: markdown
attributes:
@ -110,8 +111,13 @@ body:
- type: input
attributes:
label: Add-ons
description: Please list any hardware add-ons that could be involved.
label: LCD/Controller
description: Some Marlin behaviors are determined by the controller. Describe your LCD/Controller model and version.
- type: input
attributes:
label: Other add-ons
description: Please list any other hardware add-ons that could be involved.
- type: dropdown
attributes:

@ -28,15 +28,9 @@ Project maintainers are responsible for clarifying the standards of acceptable b
Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful.
## Scope
This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers.
## Enforcement
Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at [marlinfirmware@github.com](mailto:marlinfirmware@github.com). All complaints will be reviewed and investigated and will result in a response that is deemed necessary and appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately.
Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership.
Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by following GitHub's [reporting abuse or spam article](https://docs.github.com/en/communities/maintaining-your-safety-on-github/reporting-abuse-or-spam). All complaints will be reviewed and investigated and will result in a response that is deemed necessary and appropriate to the circumstances.
## Attribution

@ -26,11 +26,12 @@ The following is a set of guidelines for contributing to Marlin, hosted by the [
## Code of Conduct
This project and everyone participating in it is governed by the [Marlin Code of Conduct](code_of_conduct.md). By participating, you are expected to uphold this code. Please report unacceptable behavior to [marlinfirmware@github.com](mailto:marlinfirmware@github.com).
This project and everyone participating in it is governed by the [Marlin Code of Conduct](code_of_conduct.md). By participating, you are expected to uphold this code. Please report unacceptable behavior by following GitHub's [reporting abuse or spam article](https://docs.github.com/en/communities/maintaining-your-safety-on-github/reporting-abuse-or-spam).
## I don't want to read this whole thing I just have a question!!!
> **Note:** Please don't file an issue to ask a question. You'll get faster results by using the resources below.
> [!NOTE]
> Please don't file an issue to ask a question. You'll get faster results by using the resources below.
We have a Message Board and a Facebook group where our knowledgable user community can provide helpful advice if you have questions.
@ -55,7 +56,8 @@ This section guides you through submitting a Bug Report for Marlin. Following th
Before creating a Bug Report, please test the "nightly" development branch, as you might find out that you don't need to create one. When you are creating a Bug Report, please [include as many details as possible](#how-do-i-submit-a-good-bug-report). Fill out [the required template](ISSUE_TEMPLATE/bug_report.yml), the information it asks for helps us resolve issues faster.
> **Note:** Regressions can happen. If you find a **Closed** issue that seems like your issue, go ahead and open a new issue and include a link to the original issue in the body of your new one. All you need to create a link is the issue number, preceded by #. For example, #8888.
> [!NOTE]
> Regressions can happen. If you find a **Closed** issue that seems like your issue, go ahead and open a new issue and include a link to the original issue in the body of your new one. All you need to create a link is the issue number, preceded by #. For example, #8888.
#### How Do I Submit A (Good) Bug Report?

@ -0,0 +1,41 @@
#
# auto-label.yml
# - Find all open issues without a label and a title containing "[BUG]".
# - Apply the label "Bug: Potential ?" to these issues.
#
name: Label Old Bugs
on:
schedule:
- cron: "30 8 * * *"
jobs:
autolabel:
name: Auto Label
if: github.repository == 'mriscoc/Ender3V2S1'
runs-on: ubuntu-latest
steps:
- name: Auto Label for [BUG]
uses: actions/github-script@v7
with:
script: |
// Get all open issues in this repository
const issueList = await github.rest.issues.listForRepo({
owner: context.repo.owner,
repo: context.repo.repo,
state: 'open'
});
// Filter issues without labels that have a title containing '[BUG]'.
const matchingIssues = issueList.data.filter(
issue => issue.title.includes('[BUG]') && issue.labels.length === 0
);
// Process the first 50
for (const issue of matchingIssues.slice(0, 50)) {
await github.rest.issues.addLabels({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: issue.number,
labels: ['Bug: Potential ?']
});
}

@ -12,7 +12,6 @@ on:
- 1.0.x
- 1.1.x
- 2.0.x
- 2.1.x
jobs:
bad_target:

@ -23,6 +23,7 @@ jobs:
- "S: Please Merge"
- "S: Please Test"
- "help wanted"
- "Bug: Potential ?"
- "Needs: Discussion"
- "Needs: Documentation"
- "Needs: More Data"

@ -17,7 +17,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/stale@v3
- uses: actions/stale@v8
with:
repo-token: ${{ secrets.GITHUB_TOKEN }}
stale-issue-message: 'This issue has had no activity in the last 60 days. Please add a reply if you want to keep this issue active, otherwise it will be automatically closed within 10 days.'

@ -9,6 +9,7 @@ on:
pull_request:
branches:
- bugfix-2.1.x
- 2.1.x
paths-ignore:
- config/**
- data/**
@ -17,6 +18,7 @@ on:
push:
branches:
- bugfix-2.1.x
- 2.1.x
paths-ignore:
- config/**
- data/**
@ -96,6 +98,7 @@ jobs:
# STM32H7
- BTT_SKR_SE_BX
- STM32H743VI_btt
# STM32F1 (Maple)
- jgaurora_a5s_a1_maple
@ -111,6 +114,12 @@ jobs:
#- STM32F103RC_btt_maple
#- STM32F103RE_creality_maple
# STM32G0
- STM32G0B1RE_btt
# HC32
- HC32F460C_aquila_101
# LPC176x - Lengthy tests
- LPC1768
- LPC1769
@ -118,7 +127,7 @@ jobs:
steps:
- name: Check out the PR
uses: actions/checkout@v3
uses: actions/checkout@v4
- name: Cache pip
uses: actions/cache@v3
@ -134,11 +143,11 @@ jobs:
path: ~/.platformio
key: ${{ runner.os }}-${{ hashFiles('**/lockfiles') }}
- name: Select Python 3.7
uses: actions/setup-python@v3
- name: Select Python 3.9
uses: actions/setup-python@v4
with:
python-version: '3.7' # Version range or exact version of a Python version to use, using semvers version range syntax.
architecture: 'x64' # optional x64 or x86. Defaults to x64 if not specified
python-version: '3.9'
architecture: 'x64'
- name: Install PlatformIO
run: |

172
.gitignore vendored

@ -0,0 +1,172 @@
#
# 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/>.
#
# Generated files
_Version.h
bdf2u8g.exe
genpages.exe
marlin_config.json
mczip.h
language*.csv
out-csv/
out-language/
*.gen
*.sublime-workspace
# OS
applet/
.DS_Store
# Compiled C++ Object files
*.slo
*.lo
*.o
*.obj
*.ino.cpp
# Precompiled Headers
*.gch
*.pch
# Compiled Dynamic libraries
*.so
*.dylib
*.dll
# Fortran module files
*.mod
*.smod
# Compiled Static libraries
*.lai
*.la
*.a
*.lib
# Executables
*.exe
*.out
*.app
# Compiled C Object files
*.o
*.ko
*.obj
*.elf
# Precompiled Headers
*.gch
*.pch
# Libraries
*.lib
*.a
*.la
*.lo
# Shared objects (inc. Windows DLLs)
*.dll
*.so
*.so.*
*.dylib
# Executables
*.exe
*.out
*.app
*.i*86
*.x86_64
*.hex
# Debug files
*.dSYM/
*.su
# PlatformIO files/dirs
.pio*
.pioenvs
.piolibdeps
.clang_complete
.gcc-flags.json
/lib/
# Secure Credentials
Configuration_Secure.h
# Visual Studio
*.sln
*.vcxproj
*.vcxproj.user
*.vcxproj.filters
Release/
Debug/
__vm/
.vs/
vc-fileutils.settings
# Visual Studio Code
.vscode/*
!.vscode/extensions.json
# Simulation files
imgui.ini
eeprom.dat
spi_flash.bin
fs.img
# CMake
buildroot/share/cmake/*
CMakeLists.txt
!buildroot/share/cmake/CMakeLists.txt
src/CMakeLists.txt
CMakeListsPrivate.txt
build/
# CLion
cmake-build-*
# Eclipse
.project
.cproject
.pydevproject
.settings
.classpath
# Python
__pycache__
# IOLogger logs
*_log.csv
# Misc.
*~
*.orig
*.rej
*.bak
*.idea
*.i
*.ii
*.swp
tags
*.logs
*.bak
/.vscode
/.editorconfig

@ -0,0 +1,69 @@
SCRIPTS_DIR := buildroot/share/scripts
CONTAINER_RT_BIN := docker
CONTAINER_RT_OPTS := --rm -v $(PWD):/code -v platformio-cache:/root/.platformio
CONTAINER_IMAGE := marlin-dev
help:
@echo "Tasks for local development:"
@echo "* format-pins: Reformat all pins files"
@echo "* tests-single-ci: Run a single test from inside the CI"
@echo "* tests-single-local: Run a single test locally"
@echo "* tests-single-local-docker: Run a single test locally, using docker"
@echo "* tests-all-local: Run all tests locally"
@echo "* tests-all-local-docker: Run all tests locally, using docker"
@echo "* setup-local-docker: Build the local docker image"
@echo ""
@echo "Options for testing:"
@echo " TEST_TARGET Set when running tests-single-*, to select the"
@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) PLATFORMIO_BUILD_FLAGS=-DGITHUB_ACTION
.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
@if ! $(CONTAINER_RT_BIN) images -q $(CONTAINER_IMAGE) > /dev/null ; then $(MAKE) setup-local-docker ; fi
$(CONTAINER_RT_BIN) run $(CONTAINER_RT_OPTS) $(CONTAINER_IMAGE) $(MAKE) tests-single-local TEST_TARGET=$(TEST_TARGET) VERBOSE_PLATFORMIO=$(VERBOSE_PLATFORMIO) GIT_RESET_HARD=$(GIT_RESET_HARD) ONLY_TEST="$(ONLY_TEST)"
.PHONY: tests-single-local-docker
tests-all-local:
export PATH="./buildroot/bin/:./buildroot/tests/:${PATH}" \
&& export VERBOSE_PLATFORMIO=$(VERBOSE_PLATFORMIO) \
&& for TEST_TARGET in $$($(SCRIPTS_DIR)/get_test_targets.py) ; do echo "Running tests for $$TEST_TARGET" ; run_tests . $$TEST_TARGET ; done
.PHONY: tests-all-local
tests-all-local-docker:
@if ! $(CONTAINER_RT_BIN) images -q $(CONTAINER_IMAGE) > /dev/null ; then $(MAKE) setup-local-docker ; fi
$(CONTAINER_RT_BIN) run $(CONTAINER_RT_OPTS) $(CONTAINER_IMAGE) $(MAKE) tests-all-local VERBOSE_PLATFORMIO=$(VERBOSE_PLATFORMIO) GIT_RESET_HARD=$(GIT_RESET_HARD)
.PHONY: tests-all-local-docker
setup-local-docker:
$(CONTAINER_RT_BIN) build -t $(CONTAINER_IMAGE) -f docker/Dockerfile .
.PHONY: setup-local-docker
PINS := $(shell find Marlin/src/pins -mindepth 2 -name '*.h')
.PHONY: $(PINS)
$(PINS): %:
@echo "Formatting $@" && node buildroot/share/scripts/pinsformat.js $@
format-pins: $(PINS)

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

@ -0,0 +1,57 @@
/*==============================================================================
Marlin Firmware
(c) 2011-2023 MarlinFirmware
Portions of Marlin are (c) by their respective authors.
All code complies with GPLv2 and/or GPLv3
================================================================================
Greetings! Thank you for choosing Marlin 2 as your 3D printer firmware.
To configure Marlin you must edit Configuration.h and Configuration_adv.h
located in the root 'Marlin' folder. Check our Configurations repository to
see if there's a more suitable starting-point for your specific hardware.
Before diving in, we recommend the following essential links:
Marlin Firmware Official Website
- https://marlinfw.org/
The official Marlin Firmware website contains the most up-to-date
documentation. Contributions are always welcome!
Configuration
- https://github.com/MarlinFirmware/Configurations
Example configurations for several printer models.
- https://youtu.be/3gwWVFtdg-4
A good 20-minute overview of Marlin configuration by Tom Sanladerer.
(Applies to Marlin 1.0.x, so Jerk and Acceleration should be halved.)
Also... https://www.google.com/search?tbs=vid%3A1&q=configure+marlin
- https://marlinfw.org/docs/configuration/configuration.html
Marlin's configuration options are explained in more detail here.
Getting Help
- https://reprap.org/forum/list.php?415
The Marlin Discussion Forum is a great place to get help from other Marlin
users who may have experienced similar issues to your own.
- https://github.com/MarlinFirmware/Marlin/issues
With a free GitHub account you can provide us with feedback, bug reports,
and feature requests via the Marlin Issue Queue.
Contributing
- https://marlinfw.org/docs/development/contributing.html
If you'd like to contribute to Marlin, read this first!
- https://marlinfw.org/docs/development/coding_standards.html
Before submitting code get to know the Coding Standards.
------------------------------------------------------------------------------*/

@ -0,0 +1,83 @@
/**
* 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/>.
*
*/
#pragma once
////////////////////////////
// VENDOR VERSION EXAMPLE //
////////////////////////////
/**
* Marlin release version identifier
*/
#define SHORT_BUILD_VERSION "2.1.3 MRiscoC"
/**
* Verbose version identifier which should contain a reference to the location
* from where the binary was downloaded or the source code was compiled.
*/
#if ENABLED(IS_DEMO)
#define DETAILED_BUILD_VERSION SHORT_BUILD_VERSION " DEMO, NOT FOR PRODUCTION"
#else
#define DETAILED_BUILD_VERSION SHORT_BUILD_VERSION " Ender3S1-F4-TJC, based on bugfix-2.1.x"
#endif
/**
* The STRING_DISTRIBUTION_DATE represents when the binary file was built,
* here we define this default string as the date where the latest release
* version was tagged.
*/
//#define STRING_DISTRIBUTION_DATE "2023-11-24"
#define STRING_DISTRIBUTION_DATE __DATE__
#define STRING_DISTRIBUTION_TIME __TIME__
/**
* Defines a generic printer name to be output to the LCD after booting Marlin.
*/
#define MACHINE_NAME "Ender 3S1"
/**
* The SOURCE_CODE_URL is the location where users will find the Marlin Source
* Code which is installed on the device. In most cases unless the manufacturer
* has a distinct Github fork the Source Code URL should just be the main
* Marlin repository.
*/
#define SOURCE_CODE_URL "github.com/mriscoc/Ender3V2S1"
/**
* Default generic printer UUID.
*/
//#define DEFAULT_MACHINE_UUID "cede2a2f-41a2-4748-9b12-c55c62f367ff"
/**
* The WEBSITE_URL is the location where users can get more information such as
* documentation about a specific Marlin release.
*/
#define WEBSITE_URL "github.com/mriscoc/Ender3V2S1/wiki"
/**
* Set the vendor info the serial USB interface, if changable
* Currently only supported by DUE platform
*/
//#define USB_DEVICE_VENDOR_ID 0x0000
//#define USB_DEVICE_PRODUCT_ID 0x0000
//#define USB_DEVICE_MANUFACTURE_NAME WEBSITE_URL

@ -0,0 +1,97 @@
/**
* 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/>.
*
*/
#pragma once
/**
* Custom Boot Screen bitmap
*
* Place this file in the root with your configuration files
* and enable SHOW_CUSTOM_BOOTSCREEN in Configuration.h.
*
* Use the Marlin Bitmap Converter to make your own:
* https://marlinfw.org/tools/u8glib/converter.html
*/
#define CUSTOM_BOOTSCREEN_TIMEOUT 1000
#define CUSTOM_BOOTSCREEN_BMPWIDTH 81
#define CUSTOM_BOOTSCREEN_INVERTED
const unsigned char custom_start_bmp[] PROGMEM = {
B11111111,B11111111,B11111111,B11111111,B11101111,B11111111,B11111111,B11111111,B11111111,B11111111,B11111111,
B11111111,B11111111,B11111111,B11111111,B11101111,B11101111,B11111111,B11111111,B11111111,B11111111,B11111111,
B11111111,B11111111,B11111111,B11111111,B11100111,B11011111,B11111111,B11111111,B11111111,B11111111,B11111111,
B11111111,B11111111,B11111111,B11111111,B11100111,B11011111,B11111111,B11111111,B11111111,B11111111,B11111111,
B11111111,B11111111,B11111111,B11111111,B11100011,B11011111,B11111111,B11111111,B11111111,B11111111,B11111111,
B11111111,B11111111,B11111111,B11111111,B11110011,B11001111,B11111111,B11111111,B11111111,B11111111,B11111111,
B11111111,B11111111,B11111111,B11100001,B11100001,B11001111,B11111111,B11111111,B11111111,B11111111,B11111111,
B11111111,B11111110,B01111000,B00000000,B00000000,B00000011,B11011101,B11111111,B11111111,B11111111,B11111111,
B11111110,B11111111,B10000000,B01111110,B00000000,B00000001,B11101110,B11111111,B11111111,B11111111,B11111111,
B11111110,B01111101,B11001111,B11111100,B00000000,B00000000,B11110111,B01111111,B11111111,B11111111,B11111111,
B11111111,B10001110,B00000110,B00000000,B00000000,B00000000,B01111011,B10111111,B11111111,B11111111,B11111111,
B11111111,B11000000,B00000000,B00000000,B00000000,B00000000,B01111101,B11011111,B11111111,B11111111,B11111111,
B11111111,B11111100,B00000001,B11111110,B00000000,B00000000,B00111110,B11100111,B11111111,B11111111,B11111111,
B11111111,B11111111,B11111111,B11111100,B00000000,B00000011,B00011111,B01110011,B11111111,B11111111,B11111111,
B11111111,B11111111,B11111111,B11111000,B00000000,B00000001,B10001111,B10000001,B11111111,B11111111,B11111111,
B11111111,B11111111,B11111111,B11100000,B00000000,B00000000,B10000011,B11111001,B11111111,B11111111,B11111111,
B11111111,B11111111,B11111111,B00000000,B11111100,B00000000,B00000000,B11110000,B11111111,B11111111,B11111111,
B11111111,B11111111,B11100000,B00001111,B11111111,B11000000,B00000000,B00000000,B11111111,B11111111,B11111111,
B11111111,B11111110,B00000011,B11111111,B11111111,B11000000,B00000000,B00000000,B11111111,B11111111,B11111111,
B11111111,B11111111,B11111111,B11111111,B11111001,B00000000,B00000000,B00000000,B11111111,B11111111,B11111111,
B11111111,B11111111,B11111111,B11111111,B11111100,B00000000,B00000111,B11000000,B11111111,B11111111,B11111111,
B11111111,B11111111,B11111111,B11111111,B11111111,B00000000,B00000111,B11100000,B11111111,B11111111,B11111111,
B11111111,B11111111,B11111111,B11111111,B11111111,B11100000,B00000111,B11110001,B11111111,B11111111,B11111111,
B11111111,B11111111,B11111111,B11111111,B11111111,B11111100,B00000111,B11111001,B11111111,B11111111,B11111111,
B11111111,B11111111,B11111111,B11111111,B11111111,B11111111,B00000011,B11111001,B11111111,B11111111,B11111111,
B11111111,B11111111,B11111111,B11111111,B11111111,B11111111,B10000011,B11111001,B11111111,B11111111,B11111111,
B11111111,B11111111,B11111111,B11111111,B11111111,B11111111,B11000011,B11111111,B11111111,B11111111,B11111111,
B11111111,B11111111,B11111111,B11111111,B11111111,B11111111,B11100001,B11111111,B11111111,B11111111,B11111111,
B11111111,B11111111,B11111111,B11111111,B11111111,B11111111,B11110000,B10111111,B11111111,B11111111,B11111111,
B11111111,B11111111,B11111111,B11111111,B11111111,B11111011,B11111000,B00111111,B11111111,B11111111,B11111111,
B11111111,B11111111,B11111111,B11111111,B11111111,B11111001,B11111000,B00111111,B11111111,B11111111,B11111111,
B11111111,B11111111,B11111111,B11111111,B11111111,B01111110,B11110000,B11111111,B11111111,B11111111,B11111111,
B11111111,B11111111,B11111111,B11111111,B11111111,B10001110,B00000011,B11111111,B11111111,B11111111,B11111111,
B11111111,B11111111,B11111111,B11111111,B11111111,B11100000,B00011111,B11111111,B11111111,B11111111,B11111111,
B11111111,B11111111,B11111111,B11111111,B11111111,B11111111,B11111111,B11111111,B11111111,B11111111,B11111111,
B11111111,B11111111,B11111111,B11111111,B11111111,B11111111,B11111111,B11111111,B11111111,B11111111,B11111111,
B11111111,B11111111,B11111111,B11111111,B11111111,B11111111,B11111111,B01111111,B11111111,B11111111,B11111111,
B11111111,B00000000,B00000000,B01111111,B11111111,B11111111,B11111000,B01111111,B11111111,B11111111,B11111111,
B11111111,B10000000,B00000000,B01111111,B11111111,B11111111,B11100000,B01111111,B11111111,B11111111,B11111111,
B11111111,B11000011,B11111100,B11111111,B11111111,B11111111,B11111000,B11111111,B11111111,B11111111,B11111111,
B11111111,B11000011,B11111100,B11111111,B11111111,B11111111,B11111000,B11111111,B11111111,B11111111,B11111111,
B11111111,B10000111,B11111101,B11111111,B11111111,B11111111,B11110001,B11111111,B11111111,B11111111,B11111111,
B11111111,B10000111,B11111111,B11111111,B11111111,B11111111,B11110001,B11111111,B11111111,B11111111,B11111111,
B11111111,B00001111,B11100111,B11110011,B00001111,B11111100,B00100011,B11111100,B00111111,B11111111,B11111111,
B11111111,B00001111,B11101111,B10000000,B00000111,B11110000,B00000011,B11110000,B00011110,B00000000,B01111111,
B11111110,B00011111,B11001111,B10000001,B10000111,B11000111,B10000111,B11000111,B00001100,B00000000,B01111111,
B11111110,B00000000,B00011111,B11000111,B11000111,B10001111,B11000111,B10011111,B00001111,B00001100,B11111111,
B11111110,B00000000,B00011111,B10000111,B10001111,B00011111,B10001111,B00011111,B00001111,B00011111,B11111111,
B11111100,B00111111,B10011111,B10001111,B10001111,B00011111,B10001110,B00000000,B00011110,B00111111,B11111111,
B11111100,B01111111,B00111111,B00001111,B00011110,B00111111,B00011110,B00111111,B11111110,B00111111,B11111111,
B11111000,B01111111,B11111111,B00011111,B00011100,B00111111,B00011100,B01111111,B11111100,B01111111,B11111111,
B11111000,B11111111,B11111111,B00011110,B00011100,B01111110,B00011100,B01111111,B11111100,B01111111,B11111111,
B11110000,B11111111,B11001110,B00111110,B00111100,B01111110,B00111100,B01111111,B10111000,B11111111,B11111111,
B11110000,B11111111,B10011110,B00111100,B00111000,B01111100,B00111000,B01111110,B01111000,B11111111,B11111111,
B11100001,B11111111,B00111100,B01111100,B01111000,B01111100,B01111000,B00111100,B11110001,B11111111,B11111111,
B11100001,B11111000,B00111000,B01111000,B01111000,B00010000,B00011000,B00000001,B11110001,B11111111,B11111111,
B00000000,B00000000,B01100000,B00100000,B00111100,B00000000,B01111100,B00000111,B10000000,B01111111,B11111111,
B11111111,B11111111,B11111111,B11111111,B11111110,B00011111,B11111110,B00011111,B11111111,B11111111,B11111111
};

@ -0,0 +1,62 @@
/**
* 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/>.
*
*/
#pragma once
/**
* Custom Status Screen bitmap
*
* Place this file in the root with your configuration files
* and enable CUSTOM_STATUS_SCREEN_IMAGE in Configuration.h.
*
* Use the Marlin Bitmap Converter to make your own:
* https://marlinfw.org/tools/u8glib/converter.html
*/
//
// Status Screen Logo bitmap
//
#define STATUS_LOGO_Y 8
#define STATUS_LOGO_WIDTH 39
const unsigned char status_logo_bmp[] PROGMEM = {
B11111000,B00000001,B10000000,B00000000,B00001100,
B01001000,B00000000,B10000000,B00000000,B00010010,
B01000011,B11000011,B10001100,B11010000,B00000010,
B01110001,B00100100,B10010010,B01100111,B11001100,
B01000001,B00100100,B10011110,B01000000,B00000010,
B01001001,B00100100,B10010000,B01000000,B00010010,
B11111011,B10110011,B11001110,B11100000,B00001100
};
//
// Use default bitmaps
//
#define STATUS_HOTEND_ANIM
#define STATUS_BED_ANIM
#define STATUS_HEATERS_XSPACE 20
#if HOTENDS < 2
#define STATUS_HEATERS_X 48
#define STATUS_BED_X 72
#else
#define STATUS_HEATERS_X 40
#define STATUS_BED_X 80
#endif

@ -0,0 +1,247 @@
#
# Marlin Firmware
# config.ini - Options to apply before the build
#
[config:base]
#
# ini_use_config - A comma-separated list of actions to apply to the Configuration files.
# The actions will be applied in the listed order.
# - none
# Ignore this file and don't apply any configuration options
#
# - base
# Just apply the options in config:base to the configuration
#
# - minimal
# Just apply the options in config:minimal to the configuration
#
# - all
# Apply all 'config:*' sections in this file to the configuration
#
# - another.ini
# Load another INI file with a path relative to this config.ini file (i.e., within Marlin/)
#
# - https://me.myserver.com/path/to/configs
# Fetch configurations from any URL.
#
# - example/Creality/Ender-5 Plus @ bugfix-2.1.x
# Fetch example configuration files from the MarlinFirmware/Configurations repository
# https://raw.githubusercontent.com/MarlinFirmware/Configurations/bugfix-2.1.x/config/examples/Creality/Ender-5%20Plus/
#
# - example/default @ release-2.0.9.7
# Fetch default configuration files from the MarlinFirmware/Configurations repository
# https://raw.githubusercontent.com/MarlinFirmware/Configurations/release-2.0.9.7/config/default/
#
# - [disable]
# Comment out all #defines in both Configuration.h and Configuration_adv.h. This is useful
# to start with a clean slate before applying any config: options, so only the options explicitly
# set in config.ini will be enabled in the configuration.
#
# - [flatten] (Not yet implemented)
# Produce a flattened set of Configuration.h and Configuration_adv.h files with only the enabled
# #defines and no comments. A clean look, but context-free.
#
ini_use_config = none
# Load all config: sections in this file
;ini_use_config = all
# Disable everything and apply subsequent config:base options
;ini_use_config = [disable], base
# Load config file relative to Marlin/
;ini_use_config = another.ini
# Download configurations from GitHub
;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 = 255
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
x_min_endstop_hit_state = HIGH
y_min_endstop_hit_state = HIGH
z_min_endstop_hit_state = HIGH
default_axis_steps_per_unit = { 80, 80, 400, 500 }
axis_relative_modes = { false, false, false, false }
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
step_state_e = HIGH
step_state_x = HIGH
step_state_y = HIGH
step_state_z = HIGH
disable_x = off
disable_y = off
disable_z = off
disable_e = off
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_other_extruders = 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_timeout_sec = 120
default_volumetric_extruder_limit = 0.00
disable_idle_x = on
disable_idle_y = on
disable_idle_z = on
disable_idle_e = on
e0_auto_fan_pin = -1
encoder_100x_steps_per_sec = 80
encoder_10x_steps_per_sec = 30
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

@ -0,0 +1,36 @@
This directory is intended for the project specific (private) libraries.
PlatformIO will compile them to static libraries and link to executable file.
The source code of each library should be placed in separate directory, like
"lib/private_lib/[here are source files]".
For example, see how can be organized `Foo` and `Bar` libraries:
|--lib
| |--Bar
| | |--docs
| | |--examples
| | |--src
| | |- Bar.c
| | |- Bar.h
| |--Foo
| | |- Foo.c
| | |- Foo.h
| |- readme.txt --> THIS FILE
|- platformio.ini
|--src
|- main.c
Then in `src/main.c` you should use:
#include <Foo.h>
#include <Bar.h>
// rest H/C/CPP code
PlatformIO will find your libraries automatically, configure preprocessor's
include paths and build them.
More information about PlatformIO Library Dependency Finder
- https://docs.platformio.org/page/librarymanager/ldf.html

@ -0,0 +1,189 @@
/**
* 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"
#include "HAL.h"
#include <avr/wdt.h>
#ifdef USBCON
DefaultSerial1 MSerial0(false, Serial);
#ifdef BLUETOOTH
BTSerial btSerial(false, bluetoothSerial);
#endif
#endif
// ------------------------
// Public Variables
// ------------------------
// Don't initialize/override variable (which would happen in .init4)
uint8_t MarlinHAL::reset_reason __attribute__((section(".noinit")));
// ------------------------
// Public functions
// ------------------------
__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();
}
#include "registers.h"
MarlinHAL::MarlinHAL() {
TERN_(HAL_AVR_DIRTY_INIT, _ATmega_resetperipherals()); // Clean-wipe the device state.
}
void MarlinHAL::init() {
// Init Servo Pins
#if HAS_SERVO_0
OUT_WRITE(SERVO0_PIN, LOW);
#endif
#if HAS_SERVO_1
OUT_WRITE(SERVO1_PIN, LOW);
#endif
#if HAS_SERVO_2
OUT_WRITE(SERVO2_PIN, LOW);
#endif
#if HAS_SERVO_3
OUT_WRITE(SERVO3_PIN, LOW);
#endif
init_pwm_timers(); // Init user timers to default frequency - 1000HZ
#if PIN_EXISTS(BEEPER) && ENABLED(HAL_AVR_DIRTY_INIT) && DISABLED(ATMEGA_NO_BEEPFIX)
// Make sure no alternative is locked onto the BEEPER.
// This fixes the issue where the ATmega is constantly beeping.
// Might disable other peripherals using the pin; to circumvent that please undefine one of the above things!
// The true culprit is the AVR ArduinoCore that enables peripherals redundantly.
// (USART1 on the GeeeTech GT2560)
// https://www.youtube.com/watch?v=jMgCvRXkexk
_ATmega_savePinAlternate(BEEPER_PIN);
OUT_WRITE(BEEPER_PIN, LOW);
#endif
}
void MarlinHAL::reboot() {
#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 HAS_MEDIA
#include "../../sd/SdFatUtil.h"
int freeMemory() { return SdFatUtil::FreeRam(); }
#else // !HAS_MEDIA
extern "C" {
extern char __bss_end;
extern char __heap_start;
extern void* __brkval;
int freeMemory() {
int free_memory;
if ((int)__brkval == 0)
free_memory = ((int)&free_memory) - ((int)&__bss_end);
else
free_memory = ((int)&free_memory) - ((int)__brkval);
return free_memory;
}
}
#endif // !HAS_MEDIA
#endif // __AVR__

@ -0,0 +1,280 @@
/**
* 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/>.
*
*/
#pragma once
/**
* HAL for Arduino AVR
*/
#include "../shared/Marduino.h"
#include "../shared/HAL_SPI.h"
#include "fastio.h"
#include "math.h"
#ifdef USBCON
#include <HardwareSerial.h>
#else
#include "MarlinSerial.h"
#define BOARD_NO_NATIVE_USB
#endif
#include <stdint.h>
#include <util/delay.h>
#include <avr/eeprom.h>
#include <avr/pgmspace.h>
#include <avr/interrupt.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
// 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
#define pgm_read_ptr_far(address_long) (void*)__ELPM_word((uint32_t)(address_long))
#define pgm_read_ptr_near(address_short) (void*)__LPM_word((uint16_t)(address_short))
#define pgm_read_ptr(address_short) pgm_read_ptr_near(address_short)
#endif
// ------------------------
// Defines
// ------------------------
// AVR PROGMEM extension for sprintf_P
#define S_FMT "%S"
// AVR PROGMEM extension for string define
#define PGMSTR(NAM,STR) const char NAM[] PROGMEM = STR
#ifndef CRITICAL_SECTION_START
#define CRITICAL_SECTION_START() unsigned char _sreg = SREG; cli()
#define CRITICAL_SECTION_END() SREG = _sreg
#endif
#define HAL_CAN_SET_PWM_FREQ // This HAL supports PWM Frequency adjustment
#define PWM_FREQUENCY 1000 // Default PWM frequency when set_pwm_duty() is called without set_pwm_frequency()
// ------------------------
// Types
// ------------------------
typedef int8_t pin_t;
#define SHARED_SERVOS HAS_SERVOS // Use shared/servos.cpp
class Servo;
typedef Servo hal_servo_t;
// ------------------------
// Serial ports
// ------------------------
#ifdef USBCON
#include "../../core/serial_hook.h"
typedef ForwardSerial1Class< decltype(Serial) > DefaultSerial1;
extern DefaultSerial1 MSerial0;
#ifdef BLUETOOTH
typedef ForwardSerial1Class< decltype(bluetoothSerial) > BTSerial;
extern BTSerial btSerial;
#endif
#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
#if !WITHIN(SERIAL_PORT_2, 0, 3)
#error "SERIAL_PORT_2 must be from 0 to 3."
#endif
#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
#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
#if !WITHIN(LCD_SERIAL_PORT, 0, 3)
#error "LCD_SERIAL_PORT must be from 0 to 3."
#endif
#define LCD_SERIAL lcdSerial
#if HAS_DGUS_LCD
#define LCD_SERIAL_TX_BUFFER_FREE() LCD_SERIAL.get_tx_buffer_free()
#endif
#endif
//
// ADC
//
#define HAL_ADC_VREF_MV 5000
#define HAL_ADC_RESOLUTION 10
//
// Pin Mapping for M42, M43, M226
//
#define GET_PIN_MAP_PIN(index) index
#define GET_PIN_MAP_INDEX(pin) pin
#define PARSED_PIN_INDEX(code, dval) parser.intval(code, dval)
#define HAL_SENSITIVE_PINS 0, 1,
#ifdef __AVR_AT90USB1286__
#define JTAG_DISABLE() do{ MCUCR = 0x80; MCUCR = 0x80; }while(0)
#endif
// AVR compatibility
#define strtof strtod
// ------------------------
// Free Memory Accessor
// ------------------------
#pragma GCC diagnostic push
#if GCC_VERSION <= 50000
#pragma GCC diagnostic ignored "-Wunused-function"
#endif
extern "C" int freeMemory();
#pragma GCC diagnostic pop
// ------------------------
// MarlinHAL Class
// ------------------------
class MarlinHAL {
public:
// Earliest possible init, before setup()
MarlinHAL();
// Watchdog
static void watchdog_init() IF_DISABLED(USE_WATCHDOG, {});
static void watchdog_refresh() IF_DISABLED(USE_WATCHDOG, {});
static void init(); // Called early in setup()
static void init_board() {} // Called less early in setup()
static void reboot(); // Restart the firmware from 0x0
// Interrupts
static bool isr_state() { return 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);
};

@ -0,0 +1,254 @@
/**
* 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/>.
*
*/
/**
* Adapted from Arduino Sd2Card Library
* Copyright (c) 2009 by William Greiman
*/
/**
* HAL for AVR - SPI functions
*/
#ifdef __AVR__
#include "../../inc/MarlinConfig.h"
void spiBegin() {
#if PIN_EXISTS(SD_SS)
// Do not init HIGH for boards with pin 4 used as Fans or Heaters or otherwise, not likely to have multiple SPI devices anyway.
#if defined(__AVR_ATmega644__) || defined(__AVR_ATmega644P__) || defined(__AVR_ATmega644PA__) || defined(__AVR_ATmega1284P__)
// SS must be in output mode even it is not chip select
SET_OUTPUT(SD_SS_PIN);
#else
// set SS high - may be chip select for another SPI device
OUT_WRITE(SD_SS_PIN, HIGH);
#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)
// ------------------------
// Hardware SPI
// ------------------------
// make sure SPCR rate is in expected bits
#if (SPR0 != 0 || SPR1 != 1)
#error "unexpected SPCR bits"
#endif
/**
* Initialize hardware SPI
* Set SCK rate to F_CPU/pow(2, 1 + spiRate) for spiRate [0,6]
*/
void spiInit(uint8_t spiRate) {
// See avr processor documentation
CBI(
#ifdef PRR
PRR
#elif defined(PRR0)
PRR0
#endif
, PRSPI
);
SPCR = _BV(SPE) | _BV(MSTR) | (spiRate >> 1);
SPSR = spiRate & 1 || spiRate == 6 ? 0 : _BV(SPI2X);
}
/** SPI receive a byte */
uint8_t spiRec() {
SPDR = 0xFF;
while (!TEST(SPSR, SPIF)) { /* Intentionally left empty */ }
return SPDR;
}
/** SPI read data */
void spiRead(uint8_t *buf, uint16_t nbyte) {
if (nbyte-- == 0) return;
SPDR = 0xFF;
for (uint16_t i = 0; i < nbyte; i++) {
while (!TEST(SPSR, SPIF)) { /* Intentionally left empty */ }
buf[i] = SPDR;
SPDR = 0xFF;
}
while (!TEST(SPSR, SPIF)) { /* Intentionally left empty */ }
buf[nbyte] = SPDR;
}
/** SPI send a byte */
void spiSend(uint8_t b) {
SPDR = b;
while (!TEST(SPSR, SPIF)) { /* Intentionally left empty */ }
}
/** SPI send block */
void spiSendBlock(uint8_t token, const uint8_t *buf) {
SPDR = token;
for (uint16_t i = 0; i < 512; i += 2) {
while (!TEST(SPSR, SPIF)) { /* Intentionally left empty */ }
SPDR = buf[i];
while (!TEST(SPSR, SPIF)) { /* Intentionally left empty */ }
SPDR = buf[i + 1];
}
while (!TEST(SPSR, SPIF)) { /* Intentionally left empty */ }
}
/** begin spi transaction */
void spiBeginTransaction(uint32_t spiClock, uint8_t bitOrder, uint8_t dataMode) {
// Based on Arduino SPI library
// Clock settings are defined as follows. Note that this shows SPI2X
// inverted, so the bits form increasing numbers. Also note that
// fosc/64 appears twice
// SPR1 SPR0 ~SPI2X Freq
// 0 0 0 fosc/2
// 0 0 1 fosc/4
// 0 1 0 fosc/8
// 0 1 1 fosc/16
// 1 0 0 fosc/32
// 1 0 1 fosc/64
// 1 1 0 fosc/64
// 1 1 1 fosc/128
// We find the fastest clock that is less than or equal to the
// given clock rate. The clock divider that results in clock_setting
// is 2 ^^ (clock_div + 1). If nothing is slow enough, we'll use the
// slowest (128 == 2 ^^ 7, so clock_div = 6).
uint8_t clockDiv;
// When the clock is known at compiletime, use this if-then-else
// cascade, which the compiler knows how to completely optimize
// away. When clock is not known, use a loop instead, which generates
// shorter code.
if (__builtin_constant_p(spiClock)) {
if (spiClock >= F_CPU / 2) clockDiv = 0;
else if (spiClock >= F_CPU / 4) clockDiv = 1;
else if (spiClock >= F_CPU / 8) clockDiv = 2;
else if (spiClock >= F_CPU / 16) clockDiv = 3;
else if (spiClock >= F_CPU / 32) clockDiv = 4;
else if (spiClock >= F_CPU / 64) clockDiv = 5;
else clockDiv = 6;
}
else {
uint32_t clockSetting = F_CPU / 2;
clockDiv = 0;
while (clockDiv < 6 && spiClock < clockSetting) {
clockSetting /= 2;
clockDiv++;
}
}
// Compensate for the duplicate fosc/64
if (clockDiv == 6) clockDiv = 7;
// Invert the SPI2X bit
clockDiv ^= 0x1;
SPCR = _BV(SPE) | _BV(MSTR) | ((bitOrder == LSBFIRST) ? _BV(DORD) : 0) |
(dataMode << CPHA) | ((clockDiv >> 1) << SPR0);
SPSR = clockDiv | 0x01;
}
#else // SOFTWARE_SPI || FORCE_SOFT_SPI
// ------------------------
// Software SPI
// ------------------------
// nop to tune soft SPI timing
#define nop asm volatile ("\tnop\n")
void spiInit(uint8_t) { /* do nothing */ }
// Begin SPI transaction, set clock, bit order, data mode
void spiBeginTransaction(uint32_t spiClock, uint8_t bitOrder, uint8_t dataMode) { /* do nothing */ }
// Soft SPI receive byte
uint8_t spiRec() {
uint8_t data = 0;
// no interrupts during byte receive - about 8µs
cli();
// output pin high - like sending 0xFF
WRITE(SD_MOSI_PIN, HIGH);
for (uint8_t i = 0; i < 8; ++i) {
WRITE(SD_SCK_PIN, HIGH);
nop; // adjust so SCK is nice
nop;
data <<= 1;
if (READ(SD_MISO_PIN)) data |= 1;
WRITE(SD_SCK_PIN, LOW);
}
sei();
return data;
}
// Soft SPI read data
void spiRead(uint8_t *buf, uint16_t nbyte) {
for (uint16_t i = 0; i < nbyte; i++)
buf[i] = spiRec();
}
// Soft SPI send byte
void spiSend(uint8_t data) {
// no interrupts during byte send - about 8µs
cli();
for (uint8_t i = 0; i < 8; ++i) {
WRITE(SD_SCK_PIN, LOW);
WRITE(SD_MOSI_PIN, data & 0x80);
data <<= 1;
WRITE(SD_SCK_PIN, HIGH);
}
nop; // hold SCK high for a few ns
nop;
nop;
nop;
WRITE(SD_SCK_PIN, LOW);
sei();
}
// Soft SPI send block
void spiSendBlock(uint8_t token, const uint8_t *buf) {
spiSend(token);
for (uint16_t i = 0; i < 512; i++)
spiSend(buf[i]);
}
#endif // SOFTWARE_SPI || FORCE_SOFT_SPI
#endif // __AVR__

@ -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;

@ -0,0 +1,652 @@
/**
* 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/>.
*
*/
/**
* MarlinSerial.cpp - Hardware serial library for Wiring
* Copyright (c) 2006 Nicholas Zambetti. All right reserved.
*
* Modified 23 November 2006 by David A. Mellis
* Modified 28 September 2010 by Mark Sproul
* Modified 14 February 2016 by Andreas Hardtung (added tx buffer)
* Modified 01 October 2017 by Eduardo José Tagle (added XON/XOFF)
* Modified 10 June 2018 by Eduardo José Tagle (See #10991)
* Templatized 01 October 2018 by Eduardo José Tagle to allow multiple instances
*/
#ifdef __AVR__
// Disable HardwareSerial.cpp to support chips without a UART (Attiny, etc.)
#include "../../inc/MarlinConfig.h"
#if !defined(USBCON) && (defined(UBRRH) || defined(UBRR0H) || defined(UBRR1H) || defined(UBRR2H) || defined(UBRR3H))
#include "MarlinSerial.h"
#include "../../MarlinCore.h"
#if ENABLED(DIRECT_STEPPING)
#include "../../feature/direct_stepping.h"
#endif
template<typename Cfg> typename MarlinSerial<Cfg>::ring_buffer_r MarlinSerial<Cfg>::rx_buffer = { 0, 0, { 0 } };
template<typename Cfg> typename MarlinSerial<Cfg>::ring_buffer_t MarlinSerial<Cfg>::tx_buffer = { 0 };
template<typename Cfg> bool MarlinSerial<Cfg>::_written = false;
template<typename Cfg> uint8_t MarlinSerial<Cfg>::xon_xoff_state = MarlinSerial<Cfg>::XON_XOFF_CHAR_SENT | MarlinSerial<Cfg>::XON_CHAR;
template<typename Cfg> uint8_t MarlinSerial<Cfg>::rx_dropped_bytes = 0;
template<typename Cfg> uint8_t MarlinSerial<Cfg>::rx_buffer_overruns = 0;
template<typename Cfg> uint8_t MarlinSerial<Cfg>::rx_framing_errors = 0;
template<typename Cfg> typename MarlinSerial<Cfg>::ring_buffer_pos_t MarlinSerial<Cfg>::rx_max_enqueued = 0;
// A SW memory barrier, to ensure GCC does not overoptimize loops
#define sw_barrier() asm volatile("": : :"memory");
#include "../../feature/e_parser.h"
// "Atomically" read the RX head index value without disabling interrupts:
// This MUST be called with RX interrupts enabled, and CAN'T be called
// from the RX ISR itself!
template<typename Cfg>
FORCE_INLINE typename MarlinSerial<Cfg>::ring_buffer_pos_t MarlinSerial<Cfg>::atomic_read_rx_head() {
if (Cfg::RX_SIZE > 256) {
// Keep reading until 2 consecutive reads return the same value,
// meaning there was no update in-between caused by an interrupt.
// This works because serial RX interrupts happen at a slower rate
// than successive reads of a variable, so 2 consecutive reads with
// the same value means no interrupt updated it.
ring_buffer_pos_t vold, vnew = rx_buffer.head;
sw_barrier();
do {
vold = vnew;
vnew = rx_buffer.head;
sw_barrier();
} while (vold != vnew);
return vnew;
}
else {
// With an 8bit index, reads are always atomic. No need for special handling
return rx_buffer.head;
}
}
template<typename Cfg>
volatile bool MarlinSerial<Cfg>::rx_tail_value_not_stable = false;
template<typename Cfg>
volatile uint16_t MarlinSerial<Cfg>::rx_tail_value_backup = 0;
// Set RX tail index, taking into account the RX ISR could interrupt
// the write to this variable in the middle - So a backup strategy
// is used to ensure reads of the correct values.
// -Must NOT be called from the RX ISR -
template<typename Cfg>
FORCE_INLINE void MarlinSerial<Cfg>::atomic_set_rx_tail(typename MarlinSerial<Cfg>::ring_buffer_pos_t value) {
if (Cfg::RX_SIZE > 256) {
// Store the new value in the backup
rx_tail_value_backup = value;
sw_barrier();
// Flag we are about to change the true value
rx_tail_value_not_stable = true;
sw_barrier();
// Store the new value
rx_buffer.tail = value;
sw_barrier();
// Signal the new value is completely stored into the value
rx_tail_value_not_stable = false;
sw_barrier();
}
else
rx_buffer.tail = value;
}
// Get the RX tail index, taking into account the read could be
// interrupting in the middle of the update of that index value
// -Called from the RX ISR -
template<typename Cfg>
FORCE_INLINE typename MarlinSerial<Cfg>::ring_buffer_pos_t MarlinSerial<Cfg>::atomic_read_rx_tail() {
if (Cfg::RX_SIZE > 256) {
// If the true index is being modified, return the backup value
if (rx_tail_value_not_stable) return rx_tail_value_backup;
}
// The true index is stable, return it
return rx_buffer.tail;
}
// (called with RX interrupts disabled)
template<typename Cfg>
FORCE_INLINE void MarlinSerial<Cfg>::store_rxd_char() {
static EmergencyParser::State emergency_state; // = EP_RESET
// This must read the R_UCSRA register before reading the received byte to detect error causes
if (Cfg::DROPPED_RX && B_DOR && !++rx_dropped_bytes) --rx_dropped_bytes;
if (Cfg::RX_OVERRUNS && B_DOR && !++rx_buffer_overruns) --rx_buffer_overruns;
if (Cfg::RX_FRAMING_ERRORS && B_FE && !++rx_framing_errors) --rx_framing_errors;
// Read the character from the USART
uint8_t c = R_UDR;
#if ENABLED(DIRECT_STEPPING)
if (page_manager.maybe_store_rxd_char(c)) return;
#endif
// Get the tail - Nothing can alter its value while this ISR is executing, but there's
// a chance that this ISR interrupted the main process while it was updating the index.
// The backup mechanism ensures the correct value is always returned.
const ring_buffer_pos_t t = atomic_read_rx_tail();
// Get the head pointer - This ISR is the only one that modifies its value, so it's safe to read here
ring_buffer_pos_t h = rx_buffer.head;
// Get the next element
ring_buffer_pos_t i = (ring_buffer_pos_t)(h + 1) & (ring_buffer_pos_t)(Cfg::RX_SIZE - 1);
if (Cfg::EMERGENCYPARSER) emergency_parser.update(emergency_state, c);
// If the character is to be stored at the index just before the tail
// (such that the head would advance to the current tail), the RX FIFO is
// full, so don't write the character or advance the head.
if (i != t) {
rx_buffer.buffer[h] = c;
h = i;
}
else if (Cfg::DROPPED_RX && !++rx_dropped_bytes)
--rx_dropped_bytes;
if (Cfg::MAX_RX_QUEUED) {
// Calculate count of bytes stored into the RX buffer
const ring_buffer_pos_t rx_count = (ring_buffer_pos_t)(h - t) & (ring_buffer_pos_t)(Cfg::RX_SIZE - 1);
// Keep track of the maximum count of enqueued bytes
NOLESS(rx_max_enqueued, rx_count);
}
if (Cfg::XONOFF) {
// If the last char that was sent was an XON
if ((xon_xoff_state & XON_XOFF_CHAR_MASK) == XON_CHAR) {
// Bytes stored into the RX buffer
const ring_buffer_pos_t rx_count = (ring_buffer_pos_t)(h - t) & (ring_buffer_pos_t)(Cfg::RX_SIZE - 1);
// If over 12.5% of RX buffer capacity, send XOFF before running out of
// RX buffer space .. 325 bytes @ 250kbits/s needed to let the host react
// and stop sending bytes. This translates to 13mS propagation time.
if (rx_count >= (Cfg::RX_SIZE) / 8) {
// At this point, definitely no TX interrupt was executing, since the TX ISR can't be preempted.
// Don't enable the TX interrupt here as a means to trigger the XOFF char, because if it happens
// to be in the middle of trying to disable the RX interrupt in the main program, eventually the
// enabling of the TX interrupt could be undone. The ONLY reliable thing this can do to ensure
// the sending of the XOFF char is to send it HERE AND NOW.
// About to send the XOFF char
xon_xoff_state = XOFF_CHAR | XON_XOFF_CHAR_SENT;
// Wait until the TX register becomes empty and send it - Here there could be a problem
// - While waiting for the TX register to empty, the RX register could receive a new
// character. This must also handle that situation!
while (!B_UDRE) {
if (B_RXC) {
// A char arrived while waiting for the TX buffer to be empty - Receive and process it!
i = (ring_buffer_pos_t)(h + 1) & (ring_buffer_pos_t)(Cfg::RX_SIZE - 1);
// Read the character from the USART
c = R_UDR;
if (Cfg::EMERGENCYPARSER) emergency_parser.update(emergency_state, c);
// If the character is to be stored at the index just before the tail
// (such that the head would advance to the current tail), the FIFO is
// full, so don't write the character or advance the head.
if (i != t) {
rx_buffer.buffer[h] = c;
h = i;
}
else if (Cfg::DROPPED_RX && !++rx_dropped_bytes)
--rx_dropped_bytes;
}
sw_barrier();
}
R_UDR = XOFF_CHAR;
// Clear the TXC bit -- "can be cleared by writing a one to its bit
// location". This makes sure flush() won't return until the bytes
// actually got written
B_TXC = 1;
// At this point there could be a race condition between the write() function
// and this sending of the XOFF char. This interrupt could happen between the
// wait to be empty TX buffer loop and the actual write of the character. Since
// the TX buffer is full because it's sending the XOFF char, the only way to be
// sure the write() function will succeed is to wait for the XOFF char to be
// completely sent. Since an extra character could be received during the wait
// it must also be handled!
while (!B_UDRE) {
if (B_RXC) {
// A char arrived while waiting for the TX buffer to be empty - Receive and process it!
i = (ring_buffer_pos_t)(h + 1) & (ring_buffer_pos_t)(Cfg::RX_SIZE - 1);
// Read the character from the USART
c = R_UDR;
if (Cfg::EMERGENCYPARSER)
emergency_parser.update(emergency_state, c);
// If the character is to be stored at the index just before the tail
// (such that the head would advance to the current tail), the FIFO is
// full, so don't write the character or advance the head.
if (i != t) {
rx_buffer.buffer[h] = c;
h = i;
}
else if (Cfg::DROPPED_RX && !++rx_dropped_bytes)
--rx_dropped_bytes;
}
sw_barrier();
}
// At this point everything is ready. The write() function won't
// have any issues writing to the UART TX register if it needs to!
}
}
}
// Store the new head value - The main loop will retry until the value is stable
rx_buffer.head = h;
}
// (called with TX irqs disabled)
template<typename Cfg>
FORCE_INLINE void MarlinSerial<Cfg>::_tx_udr_empty_irq() {
if (Cfg::TX_SIZE > 0) {
// Read positions
uint8_t t = tx_buffer.tail;
const uint8_t h = tx_buffer.head;
if (Cfg::XONOFF) {
// If an XON char is pending to be sent, do it now
if (xon_xoff_state == XON_CHAR) {
// Send the character
R_UDR = XON_CHAR;
// clear the TXC bit -- "can be cleared by writing a one to its bit
// location". This makes sure flush() won't return until the bytes
// actually got written
B_TXC = 1;
// Remember we sent it.
xon_xoff_state = XON_CHAR | XON_XOFF_CHAR_SENT;
// If nothing else to transmit, just disable TX interrupts.
if (h == t) B_UDRIE = 0; // (Non-atomic, could be reenabled by the main program, but eventually this will succeed)
return;
}
}
// If nothing to transmit, just disable TX interrupts. This could
// happen as the result of the non atomicity of the disabling of RX
// interrupts that could end reenabling TX interrupts as a side effect.
if (h == t) {
B_UDRIE = 0; // (Non-atomic, could be reenabled by the main program, but eventually this will succeed)
return;
}
// There is something to TX, Send the next byte
const uint8_t c = tx_buffer.buffer[t];
t = (t + 1) & (Cfg::TX_SIZE - 1);
R_UDR = c;
tx_buffer.tail = t;
// Clear the TXC bit (by writing a one to its bit location).
// Ensures flush() won't return until the bytes are actually written/
B_TXC = 1;
// Disable interrupts if there is nothing to transmit following this byte
if (h == t) B_UDRIE = 0; // (Non-atomic, could be reenabled by the main program, but eventually this will succeed)
}
}
// Public Methods
template<typename Cfg>
void MarlinSerial<Cfg>::begin(const long baud) {
uint16_t baud_setting;
bool useU2X = true;
#if F_CPU == 16000000UL && SERIAL_PORT == 0
// Hard-coded exception for compatibility with the bootloader shipped
// with the Duemilanove and previous boards, and the firmware on the
// 8U2 on the Uno and Mega 2560.
if (baud == 57600) useU2X = false;
#endif
R_UCSRA = 0;
if (useU2X) {
B_U2X = 1;
baud_setting = (F_CPU / 4 / baud - 1) / 2;
}
else
baud_setting = (F_CPU / 8 / baud - 1) / 2;
// assign the baud_setting, a.k.a. ubbr (USART Baud Rate Register)
R_UBRRH = baud_setting >> 8;
R_UBRRL = baud_setting;
B_RXEN = 1;
B_TXEN = 1;
B_RXCIE = 1;
if (Cfg::TX_SIZE > 0) B_UDRIE = 0;
_written = false;
}
template<typename Cfg>
void MarlinSerial<Cfg>::end() {
B_RXEN = 0;
B_TXEN = 0;
B_RXCIE = 0;
B_UDRIE = 0;
}
template<typename Cfg>
int MarlinSerial<Cfg>::peek() {
const ring_buffer_pos_t h = atomic_read_rx_head(), t = rx_buffer.tail;
return h == t ? -1 : rx_buffer.buffer[t];
}
template<typename Cfg>
int MarlinSerial<Cfg>::read() {
const ring_buffer_pos_t h = atomic_read_rx_head();
// Read the tail. Main thread owns it, so it is safe to directly read it
ring_buffer_pos_t t = rx_buffer.tail;
// If nothing to read, return now
if (h == t) return -1;
// Get the next char
const int v = rx_buffer.buffer[t];
t = (ring_buffer_pos_t)(t + 1) & (Cfg::RX_SIZE - 1);
// Advance tail - Making sure the RX ISR will always get an stable value, even
// if it interrupts the writing of the value of that variable in the middle.
atomic_set_rx_tail(t);
if (Cfg::XONOFF) {
// If the XOFF char was sent, or about to be sent...
if ((xon_xoff_state & XON_XOFF_CHAR_MASK) == XOFF_CHAR) {
// Get count of bytes in the RX buffer
const ring_buffer_pos_t rx_count = (ring_buffer_pos_t)(h - t) & (ring_buffer_pos_t)(Cfg::RX_SIZE - 1);
if (rx_count < (Cfg::RX_SIZE) / 10) {
if (Cfg::TX_SIZE > 0) {
// Signal we want an XON character to be sent.
xon_xoff_state = XON_CHAR;
// Enable TX ISR. Non atomic, but it will eventually enable them
B_UDRIE = 1;
}
else {
// If not using TX interrupts, we must send the XON char now
xon_xoff_state = XON_CHAR | XON_XOFF_CHAR_SENT;
while (!B_UDRE) sw_barrier();
R_UDR = XON_CHAR;
}
}
}
}
return v;
}
template<typename Cfg>
typename MarlinSerial<Cfg>::ring_buffer_pos_t MarlinSerial<Cfg>::available() {
const ring_buffer_pos_t h = atomic_read_rx_head(), t = rx_buffer.tail;
return (ring_buffer_pos_t)(Cfg::RX_SIZE + h - t) & (Cfg::RX_SIZE - 1);
}
template<typename Cfg>
void MarlinSerial<Cfg>::flush() {
// Set the tail to the head:
// - Read the RX head index in a safe way. (See atomic_read_rx_head.)
// - Set the tail, making sure the RX ISR will always get a stable value, even
// if it interrupts the writing of the value of that variable in the middle.
atomic_set_rx_tail(atomic_read_rx_head());
if (Cfg::XONOFF) {
// If the XOFF char was sent, or about to be sent...
if ((xon_xoff_state & XON_XOFF_CHAR_MASK) == XOFF_CHAR) {
if (Cfg::TX_SIZE > 0) {
// Signal we want an XON character to be sent.
xon_xoff_state = XON_CHAR;
// Enable TX ISR. Non atomic, but it will eventually enable it.
B_UDRIE = 1;
}
else {
// If not using TX interrupts, we must send the XON char now
xon_xoff_state = XON_CHAR | XON_XOFF_CHAR_SENT;
while (!B_UDRE) sw_barrier();
R_UDR = XON_CHAR;
}
}
}
}
template<typename Cfg>
void MarlinSerial<Cfg>::write(const uint8_t c) {
if (Cfg::TX_SIZE == 0) {
_written = true;
while (!B_UDRE) sw_barrier();
R_UDR = c;
}
else {
_written = true;
// If the TX interrupts are disabled and the data register
// is empty, just write the byte to the data register and
// be done. This shortcut helps significantly improve the
// effective datarate at high (>500kbit/s) bitrates, where
// interrupt overhead becomes a slowdown.
// Yes, there is a race condition between the sending of the
// XOFF char at the RX ISR, but it is properly handled there
if (!B_UDRIE && B_UDRE) {
R_UDR = c;
// clear the TXC bit -- "can be cleared by writing a one to its bit
// location". This makes sure flush() won't return until the bytes
// actually got written
B_TXC = 1;
return;
}
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 (!hal.isr_state()) {
// Make room by polling if it is possible to transmit, and do so!
while (i == tx_buffer.tail) {
// If we can transmit another byte, do it.
if (B_UDRE) _tx_udr_empty_irq();
// Make sure compiler rereads tx_buffer.tail
sw_barrier();
}
}
else {
// Interrupts are enabled, just wait until there is space
while (i == tx_buffer.tail) sw_barrier();
}
// Store new char. head is always safe to move
tx_buffer.buffer[tx_buffer.head] = c;
tx_buffer.head = i;
// Enable TX ISR - Non atomic, but it will eventually enable TX ISR
B_UDRIE = 1;
}
}
template<typename Cfg>
void MarlinSerial<Cfg>::flushTX() {
if (Cfg::TX_SIZE == 0) {
// No bytes written, no need to flush. This special case is needed since there's
// no way to force the TXC (transmit complete) bit to 1 during initialization.
if (!_written) return;
// Wait until everything was transmitted
while (!B_TXC) sw_barrier();
// At this point nothing is queued anymore (DRIE is disabled) and
// the hardware finished transmission (TXC is set).
}
else {
// No bytes written, no need to flush. This special case is needed since there's
// no way to force the TXC (transmit complete) bit to 1 during initialization.
if (!_written) return;
// If global interrupts are disabled (as the result of being called from an ISR)...
if (!hal.isr_state()) {
// Wait until everything was transmitted - We must do polling, as interrupts are disabled
while (tx_buffer.head != tx_buffer.tail || !B_TXC) {
// If there is more space, send an extra character
if (B_UDRE) _tx_udr_empty_irq();
sw_barrier();
}
}
else {
// Wait until everything was transmitted
while (tx_buffer.head != tx_buffer.tail || !B_TXC) sw_barrier();
}
// At this point nothing is queued anymore (DRIE is disabled) and
// the hardware finished transmission (TXC is set).
}
}
// Hookup ISR handlers
ISR(SERIAL_REGNAME(USART, SERIAL_PORT, _RX_vect)) {
MarlinSerial<MarlinSerialCfg<SERIAL_PORT>>::store_rxd_char();
}
ISR(SERIAL_REGNAME(USART, SERIAL_PORT, _UDRE_vect)) {
MarlinSerial<MarlinSerialCfg<SERIAL_PORT>>::_tx_udr_empty_irq();
}
// Because of the template definition above, it's required to instantiate the template to have all methods generated
template class MarlinSerial< MarlinSerialCfg<SERIAL_PORT> >;
MSerialT1 customizedSerial1(MSerialT1::HasEmergencyParser);
#ifdef SERIAL_PORT_2
// Hookup ISR handlers
ISR(SERIAL_REGNAME(USART, SERIAL_PORT_2, _RX_vect)) {
MarlinSerial<MarlinSerialCfg<SERIAL_PORT_2>>::store_rxd_char();
}
ISR(SERIAL_REGNAME(USART, SERIAL_PORT_2, _UDRE_vect)) {
MarlinSerial<MarlinSerialCfg<SERIAL_PORT_2>>::_tx_udr_empty_irq();
}
template class MarlinSerial< MarlinSerialCfg<SERIAL_PORT_2> >;
MSerialT2 customizedSerial2(MSerialT2::HasEmergencyParser);
#endif // SERIAL_PORT_2
#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
ISR(SERIAL_REGNAME(USART, MMU2_SERIAL_PORT, _RX_vect)) {
MarlinSerial<MMU2SerialCfg<MMU2_SERIAL_PORT>>::store_rxd_char();
}
ISR(SERIAL_REGNAME(USART, MMU2_SERIAL_PORT, _UDRE_vect)) {
MarlinSerial<MMU2SerialCfg<MMU2_SERIAL_PORT>>::_tx_udr_empty_irq();
}
template class MarlinSerial< MMU2SerialCfg<MMU2_SERIAL_PORT> >;
MSerialMMU2 mmuSerial(MSerialMMU2::HasEmergencyParser);
#endif // MMU2_SERIAL_PORT
#ifdef LCD_SERIAL_PORT
ISR(SERIAL_REGNAME(USART, LCD_SERIAL_PORT, _RX_vect)) {
MarlinSerial<LCDSerialCfg<LCD_SERIAL_PORT>>::store_rxd_char();
}
ISR(SERIAL_REGNAME(USART, LCD_SERIAL_PORT, _UDRE_vect)) {
MarlinSerial<LCDSerialCfg<LCD_SERIAL_PORT>>::_tx_udr_empty_irq();
}
template class MarlinSerial< LCDSerialCfg<LCD_SERIAL_PORT> >;
MSerialLCD lcdSerial(MSerialLCD::HasEmergencyParser);
#if HAS_DGUS_LCD
template<typename Cfg>
typename MarlinSerial<Cfg>::ring_buffer_pos_t MarlinSerial<Cfg>::get_tx_buffer_free() {
const ring_buffer_pos_t t = tx_buffer.tail, // next byte to send.
h = tx_buffer.head; // next pos for queue.
int ret = t - h - 1;
if (ret < 0) ret += Cfg::TX_SIZE + 1;
return ret;
}
#endif
#endif // LCD_SERIAL_PORT
#endif // !USBCON && (UBRRH || UBRR0H || UBRR1H || UBRR2H || UBRR3H)
// For AT90USB targets use the UART for BT interfacing
#if defined(USBCON) && ENABLED(BLUETOOTH)
MSerialBT bluetoothSerial(false);
#endif
#endif // __AVR__

@ -0,0 +1,290 @@
/**
* 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/>.
*
*/
#pragma once
/**
* MarlinSerial.h - Hardware serial library for Wiring
* Copyright (c) 2006 Nicholas Zambetti. All right reserved.
*
* Modified 28 September 2010 by Mark Sproul
* Modified 14 February 2016 by Andreas Hardtung (added tx buffer)
* Modified 01 October 2017 by Eduardo José Tagle (added XON/XOFF)
* Templatized 01 October 2018 by Eduardo José Tagle to allow multiple instances
*/
#include <WString.h>
#include "../../inc/MarlinConfigPre.h"
#include "../../core/types.h"
#include "../../core/serial_hook.h"
#ifndef USBCON
// The presence of the UBRRH register is used to detect a UART.
#define UART_PRESENT(port) ((port == 0 && (defined(UBRRH) || defined(UBRR0H))) || \
(port == 1 && defined(UBRR1H)) || (port == 2 && defined(UBRR2H)) || \
(port == 3 && defined(UBRR3H)))
// These are macros to build serial port register names for the selected SERIAL_PORT (C preprocessor
// requires two levels of indirection to expand macro values properly)
#define SERIAL_REGNAME(registerbase,number,suffix) _SERIAL_REGNAME(registerbase,number,suffix)
#if SERIAL_PORT == 0 && (!defined(UBRR0H) || !defined(UDR0)) // use un-numbered registers if necessary
#define _SERIAL_REGNAME(registerbase,number,suffix) registerbase##suffix
#else
#define _SERIAL_REGNAME(registerbase,number,suffix) registerbase##number##suffix
#endif
// Registers used by MarlinSerial class (expanded depending on selected serial port)
// Templated 8bit register (generic)
#define UART_REGISTER_DECL_BASE(registerbase, suffix) \
template<int portNr> struct R_##registerbase##x##suffix {}
// Templated 8bit register (specialization for each port)
#define UART_REGISTER_DECL(port, registerbase, suffix) \
template<> struct R_##registerbase##x##suffix<port> { \
constexpr R_##registerbase##x##suffix(int) {} \
FORCE_INLINE void operator=(uint8_t newVal) const { SERIAL_REGNAME(registerbase,port,suffix) = newVal; } \
FORCE_INLINE operator uint8_t() const { return SERIAL_REGNAME(registerbase,port,suffix); } \
}
// Templated 1bit register (generic)
#define UART_BIT_DECL_BASE(registerbase, suffix, bit) \
template<int portNr>struct B_##bit##x {}
// Templated 1bit register (specialization for each port)
#define UART_BIT_DECL(port, registerbase, suffix, bit) \
template<> struct B_##bit##x<port> { \
constexpr B_##bit##x(int) {} \
FORCE_INLINE void operator=(int newVal) const { \
if (newVal) \
SBI(SERIAL_REGNAME(registerbase,port,suffix),SERIAL_REGNAME(bit,port,)); \
else \
CBI(SERIAL_REGNAME(registerbase,port,suffix),SERIAL_REGNAME(bit,port,)); \
} \
FORCE_INLINE operator bool() const { return TEST(SERIAL_REGNAME(registerbase,port,suffix),SERIAL_REGNAME(bit,port,)); } \
}
#define UART_DECL_BASE() \
UART_REGISTER_DECL_BASE(UCSR,A);\
UART_REGISTER_DECL_BASE(UDR,);\
UART_REGISTER_DECL_BASE(UBRR,H);\
UART_REGISTER_DECL_BASE(UBRR,L);\
UART_BIT_DECL_BASE(UCSR,B,RXEN);\
UART_BIT_DECL_BASE(UCSR,B,TXEN);\
UART_BIT_DECL_BASE(UCSR,A,TXC);\
UART_BIT_DECL_BASE(UCSR,B,RXCIE);\
UART_BIT_DECL_BASE(UCSR,A,UDRE);\
UART_BIT_DECL_BASE(UCSR,A,FE);\
UART_BIT_DECL_BASE(UCSR,A,DOR);\
UART_BIT_DECL_BASE(UCSR,B,UDRIE);\
UART_BIT_DECL_BASE(UCSR,A,RXC);\
UART_BIT_DECL_BASE(UCSR,A,U2X)
#define UART_DECL(port) \
UART_REGISTER_DECL(port,UCSR,A);\
UART_REGISTER_DECL(port,UDR,);\
UART_REGISTER_DECL(port,UBRR,H);\
UART_REGISTER_DECL(port,UBRR,L);\
UART_BIT_DECL(port,UCSR,B,RXEN);\
UART_BIT_DECL(port,UCSR,B,TXEN);\
UART_BIT_DECL(port,UCSR,A,TXC);\
UART_BIT_DECL(port,UCSR,B,RXCIE);\
UART_BIT_DECL(port,UCSR,A,UDRE);\
UART_BIT_DECL(port,UCSR,A,FE);\
UART_BIT_DECL(port,UCSR,A,DOR);\
UART_BIT_DECL(port,UCSR,B,UDRIE);\
UART_BIT_DECL(port,UCSR,A,RXC);\
UART_BIT_DECL(port,UCSR,A,U2X)
// Declare empty templates
UART_DECL_BASE();
// And all the specializations for each possible serial port
#if UART_PRESENT(0)
UART_DECL(0);
#endif
#if UART_PRESENT(1)
UART_DECL(1);
#endif
#if UART_PRESENT(2)
UART_DECL(2);
#endif
#if UART_PRESENT(3)
UART_DECL(3);
#endif
#define BYTE 0
template<typename Cfg>
class MarlinSerial {
protected:
// Registers
static constexpr R_UCSRxA<Cfg::PORT> R_UCSRA = 0;
static constexpr R_UDRx<Cfg::PORT> R_UDR = 0;
static constexpr R_UBRRxH<Cfg::PORT> R_UBRRH = 0;
static constexpr R_UBRRxL<Cfg::PORT> R_UBRRL = 0;
// Bits
static constexpr B_RXENx<Cfg::PORT> B_RXEN = 0;
static constexpr B_TXENx<Cfg::PORT> B_TXEN = 0;
static constexpr B_TXCx<Cfg::PORT> B_TXC = 0;
static constexpr B_RXCIEx<Cfg::PORT> B_RXCIE = 0;
static constexpr B_UDREx<Cfg::PORT> B_UDRE = 0;
static constexpr B_FEx<Cfg::PORT> B_FE = 0;
static constexpr B_DORx<Cfg::PORT> B_DOR = 0;
static constexpr B_UDRIEx<Cfg::PORT> B_UDRIE = 0;
static constexpr B_RXCx<Cfg::PORT> B_RXC = 0;
static constexpr B_U2Xx<Cfg::PORT> B_U2X = 0;
// Base size of type on buffer size
typedef uvalue_t(Cfg::RX_SIZE - 1) ring_buffer_pos_t;
struct ring_buffer_r {
volatile ring_buffer_pos_t head, tail;
unsigned char buffer[Cfg::RX_SIZE];
};
struct ring_buffer_t {
volatile uint8_t head, tail;
unsigned char buffer[Cfg::TX_SIZE];
};
static ring_buffer_r rx_buffer;
static ring_buffer_t tx_buffer;
static bool _written;
static constexpr uint8_t XON_XOFF_CHAR_SENT = 0x80, // XON / XOFF Character was sent
XON_XOFF_CHAR_MASK = 0x1F; // XON / XOFF character to send
// XON / XOFF character definitions
static constexpr uint8_t XON_CHAR = 17, XOFF_CHAR = 19;
static uint8_t xon_xoff_state,
rx_dropped_bytes,
rx_buffer_overruns,
rx_framing_errors;
static ring_buffer_pos_t rx_max_enqueued;
FORCE_INLINE static ring_buffer_pos_t atomic_read_rx_head();
static volatile bool rx_tail_value_not_stable;
static volatile uint16_t rx_tail_value_backup;
FORCE_INLINE static void atomic_set_rx_tail(ring_buffer_pos_t value);
FORCE_INLINE static ring_buffer_pos_t atomic_read_rx_tail();
public:
FORCE_INLINE static void store_rxd_char();
FORCE_INLINE static void _tx_udr_empty_irq();
public:
static void begin(const long);
static void end();
static int peek();
static int read();
static void flush();
static ring_buffer_pos_t available();
static void write(const uint8_t c);
static void flushTX();
#if HAS_DGUS_LCD
static ring_buffer_pos_t get_tx_buffer_free();
#endif
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 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 ring_buffer_pos_t rxMaxEnqueued() { return Cfg::MAX_RX_QUEUED ? rx_max_enqueued : 0; }
};
template <uint8_t serial>
struct MarlinSerialCfg {
static constexpr int PORT = serial;
static constexpr unsigned int RX_SIZE = RX_BUFFER_SIZE;
static constexpr unsigned int TX_SIZE = TX_BUFFER_SIZE;
static constexpr bool XONOFF = ENABLED(SERIAL_XON_XOFF);
static constexpr bool EMERGENCYPARSER = ENABLED(EMERGENCY_PARSER);
static constexpr bool DROPPED_RX = ENABLED(SERIAL_STATS_DROPPED_RX);
static constexpr bool RX_OVERRUNS = ENABLED(SERIAL_STATS_RX_BUFFER_OVERRUNS);
static constexpr bool RX_FRAMING_ERRORS = ENABLED(SERIAL_STATS_RX_FRAMING_ERRORS);
static constexpr bool MAX_RX_QUEUED = ENABLED(SERIAL_STATS_MAX_RX_QUEUED);
};
typedef Serial1Class< MarlinSerial< MarlinSerialCfg<SERIAL_PORT> > > MSerialT1;
extern MSerialT1 customizedSerial1;
#ifdef SERIAL_PORT_2
typedef Serial1Class< MarlinSerial< MarlinSerialCfg<SERIAL_PORT_2> > > MSerialT2;
extern MSerialT2 customizedSerial2;
#endif
#ifdef SERIAL_PORT_3
typedef Serial1Class< MarlinSerial< MarlinSerialCfg<SERIAL_PORT_3> > > MSerialT3;
extern MSerialT3 customizedSerial3;
#endif
#endif // !USBCON
#ifdef MMU2_SERIAL_PORT
template <uint8_t serial>
struct MMU2SerialCfg {
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 EMERGENCYPARSER = false;
static constexpr bool DROPPED_RX = false;
static constexpr bool RX_FRAMING_ERRORS = false;
static constexpr bool MAX_RX_QUEUED = false;
static constexpr bool RX_OVERRUNS = false;
};
typedef Serial1Class< MarlinSerial< MMU2SerialCfg<MMU2_SERIAL_PORT> > > MSerialMMU2;
extern MSerialMMU2 mmuSerial;
#endif
#ifdef LCD_SERIAL_PORT
template <uint8_t serial>
struct LCDSerialCfg {
static constexpr int PORT = serial;
static constexpr unsigned int RX_SIZE = TERN(HAS_DGUS_LCD, DGUS_RX_BUFFER_SIZE, 64);
static constexpr unsigned int TX_SIZE = TERN(HAS_DGUS_LCD, DGUS_TX_BUFFER_SIZE, 128);
static constexpr bool XONOFF = false;
static constexpr bool EMERGENCYPARSER = ENABLED(EMERGENCY_PARSER);
static constexpr bool DROPPED_RX = false;
static constexpr bool RX_FRAMING_ERRORS = false;
static constexpr bool MAX_RX_QUEUED = false;
static constexpr bool RX_OVERRUNS = ALL(HAS_DGUS_LCD, SERIAL_STATS_RX_BUFFER_OVERRUNS);
};
typedef Serial1Class< MarlinSerial< LCDSerialCfg<LCD_SERIAL_PORT> > > MSerialLCD;
extern MSerialLCD lcdSerial;
#endif
// Use the UART for Bluetooth in AT90USB configurations
#if defined(USBCON) && ENABLED(BLUETOOTH)
typedef Serial1Class<HardwareSerial> MSerialBT;
extern MSerialBT bluetoothSerial;
#endif

@ -0,0 +1,226 @@
/**
* 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/>.
*
*/
/**
* servo.cpp - Interrupt driven Servo library for Arduino using 16 bit timers- Version 2
* Copyright (c) 2009 Michael Margolis. All right reserved.
*/
/**
* A servo is activated by creating an instance of the Servo class passing the desired pin to the attach() method.
* The servos are pulsed in the background using the value most recently written using the write() method
*
* Note that analogWrite of PWM on pins associated with the timer are disabled when the first servo is attached.
* Timers are seized as needed in groups of 12 servos - 24 servos use two timers, 48 servos will use four.
*
* The methods are:
*
* Servo - Class for manipulating servo motors connected to Arduino pins.
*
* attach(pin) - Attach a servo motor to an i/o pin.
* attach(pin, min, max) - Attach to a pin, setting min and max values in microseconds
* Default min is 544, max is 2400
*
* write() - Set the servo angle in degrees. (Invalid angles over MIN_PULSE_WIDTH are treated as µs.)
* writeMicroseconds() - Set the servo pulse width in microseconds.
* move(pin, angle) - Sequence of attach(pin), write(angle), safe_delay(servo_delay[servoIndex]).
* With DEACTIVATE_SERVOS_AFTER_MOVE it detaches after servo_delay[servoIndex].
* read() - Get the last-written servo pulse width as an angle between 0 and 180.
* readMicroseconds() - Get the last-written servo pulse width in microseconds.
* attached() - Return true if a servo is attached.
* detach() - Stop an attached servo from pulsing its i/o pin.
*/
#ifdef __AVR__
#include "../../inc/MarlinConfig.h"
#if HAS_SERVOS
#include <avr/interrupt.h>
#include "../shared/servo.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 functions common to all instances ***********************/
static inline void handle_interrupts(const timer16_Sequence_t timer, volatile uint16_t* TCNTn, volatile uint16_t* OCRnA) {
int8_t cho = Channel[timer]; // Handle the prior Channel[timer] first
if (cho < 0) // Channel -1 indicates the refresh interval completed...
*TCNTn = 0; // ...so reset the timer
else if (SERVO_INDEX(timer, cho) < ServoCount) // prior channel handled?
extDigitalWrite(SERVO(timer, cho).Pin.nbr, LOW); // pulse the prior channel LOW
Channel[timer] = ++cho; // Handle the next channel (or 0)
if (cho < SERVOS_PER_TIMER && SERVO_INDEX(timer, cho) < ServoCount) {
*OCRnA = *TCNTn + SERVO(timer, cho).ticks; // set compare to current ticks plus duration
if (SERVO(timer, cho).Pin.isActive) // activated?
extDigitalWrite(SERVO(timer, cho).Pin.nbr, HIGH); // yes: pulse HIGH
}
else {
// finished all channels so wait for the refresh period to expire before starting over
const unsigned int cval = ((unsigned)*TCNTn) + 32 / (SERVO_TIMER_PRESCALER), // allow 32 cycles to ensure the next OCR1A not missed
ival = (unsigned int)usToTicks(REFRESH_INTERVAL); // at least REFRESH_INTERVAL has elapsed
*OCRnA = max(cval, ival);
Channel[timer] = -1; // reset the timer counter to 0 on the next call
}
}
#ifndef WIRING // Wiring pre-defines signal handlers so don't define any if compiling for the Wiring platform
// Interrupt handlers for Arduino
#ifdef _useTimer1
SIGNAL(TIMER1_COMPA_vect) { handle_interrupts(_timer1, &TCNT1, &OCR1A); }
#endif
#ifdef _useTimer3
SIGNAL(TIMER3_COMPA_vect) { handle_interrupts(_timer3, &TCNT3, &OCR3A); }
#endif
#ifdef _useTimer4
SIGNAL(TIMER4_COMPA_vect) { handle_interrupts(_timer4, &TCNT4, &OCR4A); }
#endif
#ifdef _useTimer5
SIGNAL(TIMER5_COMPA_vect) { handle_interrupts(_timer5, &TCNT5, &OCR5A); }
#endif
#else // WIRING
// Interrupt handlers for Wiring
#ifdef _useTimer1
void Timer1Service() { handle_interrupts(_timer1, &TCNT1, &OCR1A); }
#endif
#ifdef _useTimer3
void Timer3Service() { handle_interrupts(_timer3, &TCNT3, &OCR3A); }
#endif
#endif // WIRING
/****************** end of static functions ******************************/
void initISR(const timer16_Sequence_t timer_index) {
switch (timer_index) {
default: break;
#ifdef _useTimer1
case _timer1:
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
break;
#endif
#ifdef _useTimer3
case _timer3:
TCCR3A = 0; // normal counting mode
TCCR3B = _BV(CS31); // set prescaler of 8
TCNT3 = 0; // clear the timer count
#ifdef __AVR_ATmega128__
SBI(TIFR, OCF3A); // clear any pending interrupts;
SBI(ETIMSK, OCIE3A); // enable the output compare interrupt
#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 _useTimer4
case _timer4:
TCCR4A = 0; // normal counting mode
TCCR4B = _BV(CS41); // set prescaler of 8
TCNT4 = 0; // clear the timer count
TIFR4 = _BV(OCF4A); // clear any pending interrupts;
TIMSK4 = _BV(OCIE4A); // enable the output compare interrupt
break;
#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(const timer16_Sequence_t timer_index) {
// Disable use of the given timer
#ifdef WIRING
switch (timer_index) {
default: break;
case _timer1:
CBI(
#if defined(__AVR_ATmega1281__) || defined(__AVR_ATmega2561__)
TIMSK1
#else
TIMSK
#endif
, OCIE1A // disable timer 1 output compare interrupt
);
timerDetach(TIMER1OUTCOMPAREA_INT);
break;
case _timer3:
CBI(
#if defined(__AVR_ATmega1281__) || defined(__AVR_ATmega2561__)
TIMSK3
#else
ETIMSK
#endif
, OCIE3A // disable the timer3 output compare A interrupt
);
timerDetach(TIMER3OUTCOMPAREA_INT);
break;
}
#else // !WIRING
// For arduino - in future: call here to a currently undefined function to reset the timer
UNUSED(timer_index);
#endif
}
#endif // HAS_SERVOS
#endif // __AVR__

@ -0,0 +1,93 @@
/**
* 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/>.
*
*/
#pragma once
/**
* ServoTimers.h - Interrupt driven Servo library for Arduino using 16 bit timers- Version 2
* Copyright (c) 2009 Michael Margolis. All right reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
/**
* Defines for 16 bit timers used with Servo library
*
* If _useTimerX is defined then TimerX is a 16 bit timer on the current board
* timer16_Sequence_t enumerates the sequence that the timers should be allocated
* _Nbr_16timers indicates how many 16 bit timers are available.
*/
/**
* AVR Only definitions
* --------------------
*/
#define TRIM_DURATION 2 // compensation ticks to trim adjust for digitalWrite delays
#define SERVO_TIMER_PRESCALER 8 // timer prescaler
// Say which 16 bit timers can be used and in what order
#if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)
//#define _useTimer1
#define _useTimer4
#if NUM_SERVOS > SERVOS_PER_TIMER
#define _useTimer3
#if !HAS_MOTOR_CURRENT_PWM && SERVOS > 2 * SERVOS_PER_TIMER
#define _useTimer5 // Timer 5 is used for motor current PWM and can't be used for servos.
#endif
#endif
#elif defined(__AVR_ATmega32U4__)
#define _useTimer3
#elif defined(__AVR_AT90USB646__) || defined(__AVR_AT90USB1286__)
#define _useTimer3
#elif defined(__AVR_ATmega128__) || defined(__AVR_ATmega1281__) || defined(__AVR_ATmega1284P__) || defined(__AVR_ATmega2561__)
#define _useTimer3
#else
// everything else
#endif
typedef enum {
#ifdef _useTimer1
_timer1,
#endif
#ifdef _useTimer3
_timer3,
#endif
#ifdef _useTimer4
_timer4,
#endif
#ifdef _useTimer5
_timer5,
#endif
_Nbr_16timers
} timer16_Sequence_t;

@ -0,0 +1,74 @@
/**
* 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 ANY(EEPROM_SETTINGS, SD_FIRMWARE_UPDATE)
/**
* PersistentStore for Arduino-style EEPROM interface
* with implementations supplied by the framework.
*/
#include "../shared/eeprom_api.h"
#ifndef MARLIN_EEPROM_SIZE
#define MARLIN_EEPROM_SIZE size_t(E2END + 1)
#endif
size_t PersistentStore::capacity() { return MARLIN_EEPROM_SIZE; }
bool PersistentStore::access_start() { return true; }
bool PersistentStore::access_finish() { return true; }
bool PersistentStore::write_data(int &pos, const uint8_t *value, size_t size, uint16_t *crc) {
uint16_t written = 0;
while (size--) {
uint8_t * const p = (uint8_t * const)pos;
uint8_t v = *value;
if (v != eeprom_read_byte(p)) { // EEPROM has only ~100,000 write cycles, so only write bytes that have changed!
eeprom_write_byte(p, v);
if (++written & 0x7F) delay(2); else safe_delay(2); // Avoid triggering watchdog during long EEPROM writes
if (eeprom_read_byte(p) != v) {
SERIAL_ECHO_MSG(STR_ERR_EEPROM_WRITE);
return true;
}
}
crc16(crc, &v, 1);
pos++;
value++;
}
return false;
}
bool PersistentStore::read_data(int &pos, uint8_t *value, size_t size, uint16_t *crc, const bool writing/*=true*/) {
do {
uint8_t c = eeprom_read_byte((uint8_t*)pos);
if (writing) *value = c;
crc16(crc, &c, 1);
pos++;
value++;
} while (--size);
return false; // always assume success for AVR's
}
#endif // EEPROM_SETTINGS || SD_FIRMWARE_UPDATE
#endif // __AVR__

@ -0,0 +1,351 @@
/**
* 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/>.
*
*/
#pragma once
/**
* Endstop Interrupts
*
* Without endstop interrupts the endstop pins must be polled continually in
* the temperature-ISR via endstops.update(), most of the time finding no change.
* With this feature endstops.update() is called only when we know that at
* least one endstop has changed state, saving valuable CPU cycles.
*
* This feature only works when all used endstop pins can generate either an
* 'external interrupt' or a 'pin change interrupt'.
*
* Test whether pins issue interrupts on your board by flashing 'pin_interrupt_test.ino'.
* (Located in Marlin/buildroot/share/pin_interrupt_test/pin_interrupt_test.ino)
*/
#include "../../module/endstops.h"
#include <stdint.h>
// One ISR for all EXT-Interrupts
void endstop_ISR() { endstops.update(); }
/**
* Patch for pins_arduino.h (...\Arduino\hardware\arduino\avr\variants\mega\pins_arduino.h)
*
* These macros for the Arduino MEGA do not include the two connected pins on Port J (D14, D15).
* So we extend them here because these are the normal pins for Y_MIN and Y_MAX on RAMPS.
* There are more PCI-enabled processor pins on Port J, but they are not connected to Arduino MEGA.
*/
#if defined(ARDUINO_AVR_MEGA2560) || defined(ARDUINO_AVR_MEGA)
#define digitalPinHasPCICR(p) (WITHIN(p, 10, 15) || WITHIN(p, 50, 53) || WITHIN(p, 62, 69))
#undef digitalPinToPCICR
#define digitalPinToPCICR(p) (digitalPinHasPCICR(p) ? (&PCICR) : nullptr)
#undef digitalPinToPCICRbit
#define digitalPinToPCICRbit(p) (WITHIN(p, 10, 13) || WITHIN(p, 50, 53) ? 0 : \
WITHIN(p, 14, 15) ? 1 : \
WITHIN(p, 62, 69) ? 2 : \
0)
#undef digitalPinToPCMSK
#define digitalPinToPCMSK(p) (WITHIN(p, 10, 13) || WITHIN(p, 50, 53) ? (&PCMSK0) : \
WITHIN(p, 14, 15) ? (&PCMSK1) : \
WITHIN(p, 62, 69) ? (&PCMSK2) : \
nullptr)
#undef digitalPinToPCMSKbit
#define digitalPinToPCMSKbit(p) (WITHIN(p, 10, 13) ? ((p) - 6) : \
(p) == 14 || (p) == 51 ? 2 : \
(p) == 15 || (p) == 52 ? 1 : \
(p) == 50 ? 3 : \
(p) == 53 ? 0 : \
WITHIN(p, 62, 69) ? ((p) - 62) : \
0)
#elif defined(__AVR_ATmega164A__) || defined(__AVR_ATmega164P__) || defined(__AVR_ATmega324A__) || \
defined(__AVR_ATmega324P__) || defined(__AVR_ATmega324PA__) || defined(__AVR_ATmega324PB__) || \
defined(__AVR_ATmega644A__) || defined(__AVR_ATmega644P__) || defined(__AVR_ATmega1284__) || \
defined(__AVR_ATmega1284P__)
#define digitalPinHasPCICR(p) WITHIN(p, 0, NUM_DIGITAL_PINS)
#else
#error "Unsupported AVR variant!"
#endif
// Install Pin change interrupt for a pin. Can be called multiple times.
void pciSetup(const int8_t pin) {
if (digitalPinHasPCICR(pin)) {
SBI(*digitalPinToPCMSK(pin), digitalPinToPCMSKbit(pin)); // enable pin
SBI(PCIFR, digitalPinToPCICRbit(pin)); // clear any outstanding interrupt
SBI(PCICR, digitalPinToPCICRbit(pin)); // enable interrupt for the group
}
}
// Handlers for pin change interrupts
#ifdef PCINT0_vect
ISR(PCINT0_vect) { endstop_ISR(); }
#endif
#ifdef PCINT1_vect
ISR(PCINT1_vect, ISR_ALIASOF(PCINT0_vect));
#endif
#ifdef PCINT2_vect
ISR(PCINT2_vect, ISR_ALIASOF(PCINT0_vect));
#endif
#ifdef PCINT3_vect
ISR(PCINT3_vect, ISR_ALIASOF(PCINT0_vect));
#endif
void setup_endstop_interrupts() {
#define _ATTACH(P) attachInterrupt(digitalPinToInterrupt(P), endstop_ISR, CHANGE)
#if USE_X_MAX
#if (digitalPinToInterrupt(X_MAX_PIN) != NOT_AN_INTERRUPT)
_ATTACH(X_MAX_PIN);
#else
static_assert(digitalPinHasPCICR(X_MAX_PIN), "X_MAX_PIN is not interrupt-capable. Disable ENDSTOP_INTERRUPTS_FEATURE to continue.");
pciSetup(X_MAX_PIN);
#endif
#endif
#if USE_X_MIN
#if (digitalPinToInterrupt(X_MIN_PIN) != NOT_AN_INTERRUPT)
_ATTACH(X_MIN_PIN);
#else
static_assert(digitalPinHasPCICR(X_MIN_PIN), "X_MIN_PIN is not interrupt-capable. Disable ENDSTOP_INTERRUPTS_FEATURE to continue.");
pciSetup(X_MIN_PIN);
#endif
#endif
#if USE_Y_MAX
#if (digitalPinToInterrupt(Y_MAX_PIN) != NOT_AN_INTERRUPT)
_ATTACH(Y_MAX_PIN);
#else
static_assert(digitalPinHasPCICR(Y_MAX_PIN), "Y_MAX_PIN is not interrupt-capable. Disable ENDSTOP_INTERRUPTS_FEATURE to continue.");
pciSetup(Y_MAX_PIN);
#endif
#endif
#if USE_Y_MIN
#if (digitalPinToInterrupt(Y_MIN_PIN) != NOT_AN_INTERRUPT)
_ATTACH(Y_MIN_PIN);
#else
static_assert(digitalPinHasPCICR(Y_MIN_PIN), "Y_MIN_PIN is not interrupt-capable. Disable ENDSTOP_INTERRUPTS_FEATURE to continue.");
pciSetup(Y_MIN_PIN);
#endif
#endif
#if USE_Z_MAX
#if (digitalPinToInterrupt(Z_MAX_PIN) != NOT_AN_INTERRUPT)
_ATTACH(Z_MAX_PIN);
#else
static_assert(digitalPinHasPCICR(Z_MAX_PIN), "Z_MAX_PIN is not interrupt-capable. Disable ENDSTOP_INTERRUPTS_FEATURE to continue.");
pciSetup(Z_MAX_PIN);
#endif
#endif
#if USE_Z_MIN
#if (digitalPinToInterrupt(Z_MIN_PIN) != NOT_AN_INTERRUPT)
_ATTACH(Z_MIN_PIN);
#else
static_assert(digitalPinHasPCICR(Z_MIN_PIN), "Z_MIN_PIN is not interrupt-capable. Disable ENDSTOP_INTERRUPTS_FEATURE to continue.");
pciSetup(Z_MIN_PIN);
#endif
#endif
#if USE_I_MAX
#if (digitalPinToInterrupt(I_MAX_PIN) != NOT_AN_INTERRUPT)
_ATTACH(I_MAX_PIN);
#else
static_assert(digitalPinHasPCICR(I_MAX_PIN), "I_MAX_PIN is not interrupt-capable. Disable ENDSTOP_INTERRUPTS_FEATURE to continue.");
pciSetup(I_MAX_PIN);
#endif
#elif USE_I_MIN
#if (digitalPinToInterrupt(I_MIN_PIN) != NOT_AN_INTERRUPT)
_ATTACH(I_MIN_PIN);
#else
static_assert(digitalPinHasPCICR(I_MIN_PIN), "I_MIN_PIN is not interrupt-capable. Disable ENDSTOP_INTERRUPTS_FEATURE to continue.");
pciSetup(I_MIN_PIN);
#endif
#endif
#if USE_J_MAX
#if (digitalPinToInterrupt(J_MAX_PIN) != NOT_AN_INTERRUPT)
_ATTACH(J_MAX_PIN);
#else
static_assert(digitalPinHasPCICR(J_MAX_PIN), "J_MAX_PIN is not interrupt-capable. Disable ENDSTOP_INTERRUPTS_FEATURE to continue.");
pciSetup(J_MAX_PIN);
#endif
#elif USE_J_MIN
#if (digitalPinToInterrupt(J_MIN_PIN) != NOT_AN_INTERRUPT)
_ATTACH(J_MIN_PIN);
#else
static_assert(digitalPinHasPCICR(J_MIN_PIN), "J_MIN_PIN is not interrupt-capable. Disable ENDSTOP_INTERRUPTS_FEATURE to continue.");
pciSetup(J_MIN_PIN);
#endif
#endif
#if USE_K_MAX
#if (digitalPinToInterrupt(K_MAX_PIN) != NOT_AN_INTERRUPT)
_ATTACH(K_MAX_PIN);
#else
static_assert(digitalPinHasPCICR(K_MAX_PIN), "K_MAX_PIN is not interrupt-capable. Disable ENDSTOP_INTERRUPTS_FEATURE to continue.");
pciSetup(K_MAX_PIN);
#endif
#elif USE_K_MIN
#if (digitalPinToInterrupt(K_MIN_PIN) != NOT_AN_INTERRUPT)
_ATTACH(K_MIN_PIN);
#else
static_assert(digitalPinHasPCICR(K_MIN_PIN), "K_MIN_PIN is not interrupt-capable. Disable ENDSTOP_INTERRUPTS_FEATURE to continue.");
pciSetup(K_MIN_PIN);
#endif
#endif
#if USE_U_MAX
#if (digitalPinToInterrupt(U_MAX_PIN) != NOT_AN_INTERRUPT)
_ATTACH(U_MAX_PIN);
#else
static_assert(digitalPinHasPCICR(U_MAX_PIN), "U_MAX_PIN is not interrupt-capable. Disable ENDSTOP_INTERRUPTS_FEATURE to continue.");
pciSetup(U_MAX_PIN);
#endif
#elif USE_U_MIN
#if (digitalPinToInterrupt(U_MIN_PIN) != NOT_AN_INTERRUPT)
_ATTACH(U_MIN_PIN);
#else
static_assert(digitalPinHasPCICR(U_MIN_PIN), "U_MIN_PIN is not interrupt-capable. Disable ENDSTOP_INTERRUPTS_FEATURE to continue.");
pciSetup(U_MIN_PIN);
#endif
#endif
#if USE_V_MAX
#if (digitalPinToInterrupt(V_MAX_PIN) != NOT_AN_INTERRUPT)
_ATTACH(V_MAX_PIN);
#else
static_assert(digitalPinHasPCICR(V_MAX_PIN), "V_MAX_PIN is not interrupt-capable. Disable ENDSTOP_INTERRUPTS_FEATURE to continue.");
pciSetup(V_MAX_PIN);
#endif
#elif USE_V_MIN
#if (digitalPinToInterrupt(V_MIN_PIN) != NOT_AN_INTERRUPT)
_ATTACH(V_MIN_PIN);
#else
static_assert(digitalPinHasPCICR(V_MIN_PIN), "V_MIN_PIN is not interrupt-capable. Disable ENDSTOP_INTERRUPTS_FEATURE to continue.");
pciSetup(V_MIN_PIN);
#endif
#endif
#if USE_W_MAX
#if (digitalPinToInterrupt(W_MAX_PIN) != NOT_AN_INTERRUPT)
_ATTACH(W_MAX_PIN);
#else
static_assert(digitalPinHasPCICR(W_MAX_PIN), "W_MAX_PIN is not interrupt-capable. Disable ENDSTOP_INTERRUPTS_FEATURE to continue.");
pciSetup(W_MAX_PIN);
#endif
#elif USE_W_MIN
#if (digitalPinToInterrupt(W_MIN_PIN) != NOT_AN_INTERRUPT)
_ATTACH(W_MIN_PIN);
#else
static_assert(digitalPinHasPCICR(W_MIN_PIN), "W_MIN_PIN is not interrupt-capable. Disable ENDSTOP_INTERRUPTS_FEATURE to continue.");
pciSetup(W_MIN_PIN);
#endif
#endif
#if USE_X2_MAX
#if (digitalPinToInterrupt(X2_MAX_PIN) != NOT_AN_INTERRUPT)
_ATTACH(X2_MAX_PIN);
#else
static_assert(digitalPinHasPCICR(X2_MAX_PIN), "X2_MAX_PIN is not interrupt-capable. Disable ENDSTOP_INTERRUPTS_FEATURE to continue.");
pciSetup(X2_MAX_PIN);
#endif
#endif
#if USE_X2_MIN
#if (digitalPinToInterrupt(X2_MIN_PIN) != NOT_AN_INTERRUPT)
_ATTACH(X2_MIN_PIN);
#else
static_assert(digitalPinHasPCICR(X2_MIN_PIN), "X2_MIN_PIN is not interrupt-capable. Disable ENDSTOP_INTERRUPTS_FEATURE to continue.");
pciSetup(X2_MIN_PIN);
#endif
#endif
#if USE_Y2_MAX
#if (digitalPinToInterrupt(Y2_MAX_PIN) != NOT_AN_INTERRUPT)
_ATTACH(Y2_MAX_PIN);
#else
static_assert(digitalPinHasPCICR(Y2_MAX_PIN), "Y2_MAX_PIN is not interrupt-capable. Disable ENDSTOP_INTERRUPTS_FEATURE to continue.");
pciSetup(Y2_MAX_PIN);
#endif
#endif
#if USE_Y2_MIN
#if (digitalPinToInterrupt(Y2_MIN_PIN) != NOT_AN_INTERRUPT)
_ATTACH(Y2_MIN_PIN);
#else
static_assert(digitalPinHasPCICR(Y2_MIN_PIN), "Y2_MIN_PIN is not interrupt-capable. Disable ENDSTOP_INTERRUPTS_FEATURE to continue.");
pciSetup(Y2_MIN_PIN);
#endif
#endif
#if USE_Z2_MAX
#if (digitalPinToInterrupt(Z2_MAX_PIN) != NOT_AN_INTERRUPT)
_ATTACH(Z2_MAX_PIN);
#else
static_assert(digitalPinHasPCICR(Z2_MAX_PIN), "Z2_MAX_PIN is not interrupt-capable. Disable ENDSTOP_INTERRUPTS_FEATURE to continue.");
pciSetup(Z2_MAX_PIN);
#endif
#endif
#if USE_Z2_MIN
#if (digitalPinToInterrupt(Z2_MIN_PIN) != NOT_AN_INTERRUPT)
_ATTACH(Z2_MIN_PIN);
#else
static_assert(digitalPinHasPCICR(Z2_MIN_PIN), "Z2_MIN_PIN is not interrupt-capable. Disable ENDSTOP_INTERRUPTS_FEATURE to continue.");
pciSetup(Z2_MIN_PIN);
#endif
#endif
#if USE_Z3_MAX
#if (digitalPinToInterrupt(Z3_MAX_PIN) != NOT_AN_INTERRUPT)
_ATTACH(Z3_MAX_PIN);
#else
static_assert(digitalPinHasPCICR(Z3_MAX_PIN), "Z3_MAX_PIN is not interrupt-capable. Disable ENDSTOP_INTERRUPTS_FEATURE to continue.");
pciSetup(Z3_MAX_PIN);
#endif
#endif
#if USE_Z3_MIN
#if (digitalPinToInterrupt(Z3_MIN_PIN) != NOT_AN_INTERRUPT)
_ATTACH(Z3_MIN_PIN);
#else
static_assert(digitalPinHasPCICR(Z3_MIN_PIN), "Z3_MIN_PIN is not interrupt-capable. Disable ENDSTOP_INTERRUPTS_FEATURE to continue.");
pciSetup(Z3_MIN_PIN);
#endif
#endif
#if USE_Z4_MAX
#if (digitalPinToInterrupt(Z4_MAX_PIN) != NOT_AN_INTERRUPT)
_ATTACH(Z4_MAX_PIN);
#else
static_assert(digitalPinHasPCICR(Z4_MAX_PIN), "Z4_MAX_PIN is not interrupt-capable. Disable ENDSTOP_INTERRUPTS_FEATURE to continue.");
pciSetup(Z4_MAX_PIN);
#endif
#endif
#if USE_Z4_MIN
#if (digitalPinToInterrupt(Z4_MIN_PIN) != NOT_AN_INTERRUPT)
_ATTACH(Z4_MIN_PIN);
#else
static_assert(digitalPinHasPCICR(Z4_MIN_PIN), "Z4_MIN_PIN is not interrupt-capable. Disable ENDSTOP_INTERRUPTS_FEATURE to continue.");
pciSetup(Z4_MIN_PIN);
#endif
#endif
#if USE_Z_MIN_PROBE
#if (digitalPinToInterrupt(Z_MIN_PROBE_PIN) != NOT_AN_INTERRUPT)
_ATTACH(Z_MIN_PROBE_PIN);
#else
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);
#endif
#endif
// If we arrive here without raising an assertion, each pin has either an EXT-interrupt or a PCI.
}

@ -0,0 +1,239 @@
/**
* 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"
//#define DEBUG_AVR_FAST_PWM
#define DEBUG_OUT ENABLED(DEBUG_AVR_FAST_PWM)
#include "../../core/debug_out.h"
struct Timer {
volatile uint8_t* TCCRnQ[3]; // max 3 TCCR registers per timer
volatile uint16_t* OCRnQ[3]; // max 3 OCR registers per timer
volatile uint16_t* ICRn; // max 1 ICR register per timer
uint8_t n; // the timer number [0->5]
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)
/**
* Return a Timer struct describing a pin's timer.
*/
const Timer get_pwm_timer(const pin_t pin) {
uint8_t q = 0;
switch (digitalPinToTimer(pin)) {
#ifdef TCCR0A
IF_DISABLED(AVR_AT90USB1286_FAMILY, case TIMER0A:)
#endif
#ifdef TCCR1A
case TIMER1A: case TIMER1B:
#endif
break; // Protect reserved timers (TIMER0 & TIMER1)
#ifdef TCCR0A
case TIMER0B: // Protected timer, but allow setting the duty cycle on OCR0B for pin D4 only
return Timer({ { &TCCR0A, nullptr, nullptr }, { (uint16_t*)&OCR0A, (uint16_t*)&OCR0B, nullptr }, nullptr, 0, 1, true, true });
#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
case TIMER3C: ++q; case TIMER3B: ++q; case TIMER3A:
return Timer({ { &TCCR3A, &TCCR3B, &TCCR3C }, { &OCR3A, &OCR3B, &OCR3C }, &ICR3, 3, q, true, false });
#elif defined(OCR3B)
case TIMER3B: ++q; case TIMER3A:
return Timer({ { &TCCR3A, &TCCR3B, nullptr }, { &OCR3A, &OCR3B, nullptr }, &ICR3, 3, q, true, false });
#endif
#ifdef TCCR4A
case TIMER4C: ++q; case TIMER4B: ++q; case TIMER4A:
return Timer({ { &TCCR4A, &TCCR4B, &TCCR4C }, { &OCR4A, &OCR4B, &OCR4C }, &ICR4, 4, q, true, false });
#endif
#ifdef TCCR5A
case TIMER5C: ++q; case TIMER5B: ++q; case TIMER5A:
return Timer({ { &TCCR5A, &TCCR5B, &TCCR5C }, { &OCR5A, &OCR5B, &OCR5C }, &ICR5, 5, q, true, false });
#endif
}
return Timer();
}
void MarlinHAL::set_pwm_frequency(const pin_t pin, const uint16_t f_desired) {
DEBUG_ECHOLNPGM("set_pwm_frequency(pin=", pin, ", freq=", f_desired, ")");
const Timer timer = get_pwm_timer(pin);
if (timer.isProtected || !timer.isPWM) return; // Don't proceed if protected timer or not recognized
const bool is_timer2 = timer.n == 2;
const uint16_t maxtop = is_timer2 ? 0xFF : 0xFFFF;
DEBUG_ECHOLNPGM("maxtop=", maxtop);
uint16_t res = 0xFF; // resolution (TOP value)
uint8_t j = CS_NONE; // prescaler index
uint8_t wgm = WGM_PWM_PC_8; // waveform generation mode
// Calculating the prescaler and resolution to use to achieve closest frequency
if (f_desired != 0) {
constexpr uint16_t prescaler[] = { 1, 8, (32), 64, (128), 256, 1024 }; // (*) are Timer 2 only
uint16_t f = (F_CPU) / (uint32_t(maxtop) << 11) + 1; // Start with the lowest non-zero frequency achievable (for 16MHz, 1 or 31)
DEBUG_ECHOLNPGM("f=", f);
DEBUG_ECHOLNPGM("(prescaler loop)");
for (uint8_t i = 0; i < COUNT(prescaler); ++i) { // Loop through all prescaler values
const uint32_t p = prescaler[i]; // Extend to 32 bits for calculations
DEBUG_ECHOLNPGM("prescaler[", i, "]=", p);
uint16_t res_fast_temp, res_pc_temp;
if (is_timer2) {
#if ENABLED(USE_OCR2A_AS_TOP) // No resolution calculation for TIMER2 unless enabled USE_OCR2A_AS_TOP
const uint16_t rft = (F_CPU) / (p * f_desired);
res_fast_temp = rft - 1;
res_pc_temp = rft / 2;
DEBUG_ECHOLNPGM("(Timer2) res_fast_temp=", res_fast_temp, " res_pc_temp=", res_pc_temp);
#else
res_fast_temp = res_pc_temp = maxtop;
DEBUG_ECHOLNPGM("(Timer2) res_fast_temp=", maxtop, " res_pc_temp=", maxtop);
#endif
}
else {
if (p == 32 || p == 128) continue; // Skip TIMER2 specific prescalers when not TIMER2
const uint16_t rft = (F_CPU) / (p * f_desired);
DEBUG_ECHOLNPGM("(Not Timer 2) F_CPU=" STRINGIFY(F_CPU), " prescaler=", p, " f_desired=", f_desired);
res_fast_temp = rft - 1;
res_pc_temp = rft / 2;
}
LIMIT(res_fast_temp, 1U, maxtop);
LIMIT(res_pc_temp, 1U, maxtop);
// Calculate frequencies of test prescaler and resolution values
const uint16_t f_fast_temp = (F_CPU) / (p * (1 + res_fast_temp)),
f_pc_temp = (F_CPU) / ((p * res_pc_temp) << 1),
f_diff = _MAX(f, f_desired) - _MIN(f, f_desired),
f_fast_diff = _MAX(f_fast_temp, f_desired) - _MIN(f_fast_temp, f_desired),
f_pc_diff = _MAX(f_pc_temp, f_desired) - _MIN(f_pc_temp, f_desired);
DEBUG_ECHOLNPGM("f_fast_temp=", f_fast_temp, " f_pc_temp=", f_pc_temp, " f_diff=", f_diff, " f_fast_diff=", f_fast_diff, " f_pc_diff=", f_pc_diff);
if (f_fast_diff < f_diff && f_fast_diff <= f_pc_diff) { // FAST values are closest to desired f
// Set the Wave Generation Mode to FAST PWM
wgm = is_timer2 ? uint8_t(TERN(USE_OCR2A_AS_TOP, WGM2_FAST_PWM_OCR2A, WGM2_FAST_PWM)) : uint8_t(WGM_FAST_PWM_ICRn);
// Remember this combination
f = f_fast_temp; res = res_fast_temp; j = i + 1;
DEBUG_ECHOLNPGM("(FAST) updated f=", f);
}
else if (f_pc_diff < f_diff) { // PHASE CORRECT values are closes to desired f
// Set the Wave Generation Mode to PWM PHASE CORRECT
wgm = is_timer2 ? uint8_t(TERN(USE_OCR2A_AS_TOP, WGM2_PWM_PC_OCR2A, WGM2_PWM_PC)) : uint8_t(WGM_PWM_PC_ICRn);
f = f_pc_temp; res = res_pc_temp; j = i + 1;
DEBUG_ECHOLNPGM("(PHASE) updated f=", f);
}
} // prescaler loop
}
_SET_WGMnQ(timer, wgm);
_SET_CSn(timer, j);
if (is_timer2) {
TERN_(USE_OCR2A_AS_TOP, _SET_OCRnQ(timer, 0, res)); // Set OCR2A value (TOP) = res
}
else
_SET_ICRn(timer, res); // Set ICRn value (TOP) = res
}
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.
// Note that digitalWrite also disables PWM output for us (sets COM bit to 0)
if (v == 0)
digitalWrite(pin, invert);
else if (v == v_size)
digitalWrite(pin, !invert);
else {
const Timer timer = get_pwm_timer(pin);
if (timer.isPWM) {
if (timer.n == 0) {
_SET_COMnQ(timer, timer.q, COM_CLEAR_SET); // Only allow a TIMER0B select...
_SET_OCRnQ(timer, timer.q, v); // ...and OCR0B duty update. For output pin D4 no frequency changes are permitted.
}
else if (!timer.isProtected) {
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
}
}
else
digitalWrite(pin, v < v_size / 2 ? LOW : HIGH);
}
}
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
};
for (uint8_t i = 0; i < COUNT(pwm_pin); ++i)
set_pwm_frequency(pwm_pin[i], 1000);
}
#endif // __AVR__

@ -0,0 +1,288 @@
/**
* 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/>.
*
*/
/**
* Fast I/O for extended pins
*/
#ifdef __AVR__
#include "fastio.h"
#ifdef FASTIO_EXT_START
#include "../shared/Marduino.h"
#define _IS_EXT(P) WITHIN(P, FASTIO_EXT_START, FASTIO_EXT_END)
void extDigitalWrite(const int8_t pin, const uint8_t state) {
#define _WCASE(N) case N: WRITE(N, state); break
switch (pin) {
default: digitalWrite(pin, state);
#if _IS_EXT(70)
_WCASE(70);
#endif
#if _IS_EXT(71)
_WCASE(71);
#endif
#if _IS_EXT(72)
_WCASE(72);
#endif
#if _IS_EXT(73)
_WCASE(73);
#endif
#if _IS_EXT(74)
_WCASE(74);
#endif
#if _IS_EXT(75)
_WCASE(75);
#endif
#if _IS_EXT(76)
_WCASE(76);
#endif
#if _IS_EXT(77)
_WCASE(77);
#endif
#if _IS_EXT(78)
_WCASE(78);
#endif
#if _IS_EXT(79)
_WCASE(79);
#endif
#if _IS_EXT(80)
_WCASE(80);
#endif
#if _IS_EXT(81)
_WCASE(81);
#endif
#if _IS_EXT(82)
_WCASE(82);
#endif
#if _IS_EXT(83)
_WCASE(83);
#endif
#if _IS_EXT(84)
_WCASE(84);
#endif
#if _IS_EXT(85)
_WCASE(85);
#endif
#if _IS_EXT(86)
_WCASE(86);
#endif
#if _IS_EXT(87)
_WCASE(87);
#endif
#if _IS_EXT(88)
_WCASE(88);
#endif
#if _IS_EXT(89)
_WCASE(89);
#endif
#if _IS_EXT(90)
_WCASE(90);
#endif
#if _IS_EXT(91)
_WCASE(91);
#endif
#if _IS_EXT(92)
_WCASE(92);
#endif
#if _IS_EXT(93)
_WCASE(93);
#endif
#if _IS_EXT(94)
_WCASE(94);
#endif
#if _IS_EXT(95)
_WCASE(95);
#endif
#if _IS_EXT(96)
_WCASE(96);
#endif
#if _IS_EXT(97)
_WCASE(97);
#endif
#if _IS_EXT(98)
_WCASE(98);
#endif
#if _IS_EXT(99)
_WCASE(99);
#endif
#if _IS_EXT(100)
_WCASE(100);
#endif
}
}
uint8_t extDigitalRead(const int8_t pin) {
#define _RCASE(N) case N: return READ(N)
switch (pin) {
default: return digitalRead(pin);
#if _IS_EXT(70)
_RCASE(70);
#endif
#if _IS_EXT(71)
_RCASE(71);
#endif
#if _IS_EXT(72)
_RCASE(72);
#endif
#if _IS_EXT(73)
_RCASE(73);
#endif
#if _IS_EXT(74)
_RCASE(74);
#endif
#if _IS_EXT(75)
_RCASE(75);
#endif
#if _IS_EXT(76)
_RCASE(76);
#endif
#if _IS_EXT(77)
_RCASE(77);
#endif
#if _IS_EXT(78)
_RCASE(78);
#endif
#if _IS_EXT(79)
_RCASE(79);
#endif
#if _IS_EXT(80)
_RCASE(80);
#endif
#if _IS_EXT(81)
_RCASE(81);
#endif
#if _IS_EXT(82)
_RCASE(82);
#endif
#if _IS_EXT(83)
_RCASE(83);
#endif
#if _IS_EXT(84)
_RCASE(84);
#endif
#if _IS_EXT(85)
_RCASE(85);
#endif
#if _IS_EXT(86)
_RCASE(86);
#endif
#if _IS_EXT(87)
_RCASE(87);
#endif
#if _IS_EXT(88)
_RCASE(88);
#endif
#if _IS_EXT(89)
_RCASE(89);
#endif
#if _IS_EXT(90)
_RCASE(90);
#endif
#if _IS_EXT(91)
_RCASE(91);
#endif
#if _IS_EXT(92)
_RCASE(92);
#endif
#if _IS_EXT(93)
_RCASE(93);
#endif
#if _IS_EXT(94)
_RCASE(94);
#endif
#if _IS_EXT(95)
_RCASE(95);
#endif
#if _IS_EXT(96)
_RCASE(96);
#endif
#if _IS_EXT(97)
_RCASE(97);
#endif
#if _IS_EXT(98)
_RCASE(98);
#endif
#if _IS_EXT(99)
_RCASE(99);
#endif
#if _IS_EXT(100)
_RCASE(100);
#endif
}
}
#if 0
/**
* Set Timer 5 PWM frequency in Hz, from 3.8Hz up to ~16MHz
* with a minimum resolution of 100 steps.
*
* DC values -1.0 to 1.0. Negative duty cycle inverts the pulse.
*/
uint16_t set_pwm_frequency_hz(const_float_t hz, const float dca, const float dcb, const float dcc) {
float count = 0;
if (hz > 0 && (dca || dcb || dcc)) {
count = float(F_CPU) / hz; // 1x prescaler, TOP for 16MHz base freq.
uint16_t prescaler; // Range of 30.5Hz (65535) 64.5kHz (>31)
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. * 8.) { prescaler = 64; SET_CS(5, PRESCALER_64); }
else if (count >= 255.) { prescaler = 8; SET_CS(5, PRESCALER_8); }
else { prescaler = 1; SET_CS(5, PRESCALER_1); }
count /= float(prescaler);
const float pwm_top = round(count); // Get the rounded count
ICR5 = (uint16_t)pwm_top - 1; // Subtract 1 for TOP
OCR5A = pwm_top * ABS(dca); // Update and scale DCs
OCR5B = pwm_top * ABS(dcb);
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, B, dcb ? (dcb < 0 ? COM_SET_CLEAR : COM_CLEAR_SET) : COM_NORMAL);
_SET_COM(5, C, dcc ? (dcc < 0 ? COM_SET_CLEAR : COM_CLEAR_SET) : COM_NORMAL);
SET_WGM(5, FAST_PWM_ICRn); // Fast PWM with ICR5 as TOP
//SERIAL_ECHOLNPGM("Timer 5 Settings:");
//SERIAL_ECHOLNPGM(" Prescaler=", prescaler);
//SERIAL_ECHOLNPGM(" TOP=", ICR5);
//SERIAL_ECHOLNPGM(" OCR5A=", OCR5A);
//SERIAL_ECHOLNPGM(" OCR5B=", OCR5B);
//SERIAL_ECHOLNPGM(" OCR5C=", OCR5C);
}
else {
// Restore the default for Timer 5
SET_WGM(5, PWM_PC_8); // PWM 8-bit (Phase Correct)
SET_COMS(5, NORMAL, NORMAL, NORMAL); // Do nothing
SET_CS(5, PRESCALER_64); // 16MHz / 64 = 250kHz
OCR5A = OCR5B = OCR5C = 0;
}
return round(count);
}
#endif
#endif // FASTIO_EXT_START
#endif // __AVR__

@ -0,0 +1,272 @@
/**
* 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/>.
*
*/
#pragma once
/**
* Fast I/O Routines for AVR
* Use direct port manipulation to save scads of processor time.
* Contributed by Triffid_Hunter and modified by Kliment, thinkyhead, Bob-the-Kuhn, et.al.
*/
#include <avr/io.h>
#if defined(__AVR_AT90USB1287__) || defined(__AVR_AT90USB1286__) || defined(__AVR_AT90USB1286P__) || defined(__AVR_AT90USB646__) || defined(__AVR_AT90USB646P__) || defined(__AVR_AT90USB647__)
#define AVR_AT90USB1286_FAMILY 1
#elif defined(__AVR_ATmega644__) || defined(__AVR_ATmega644P__) || defined(__AVR_ATmega644PA__) || defined(__AVR_ATmega1284P__)
#define AVR_ATmega1284_FAMILY 1
#elif defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)
#define AVR_ATmega2560_FAMILY 1
#elif defined(__AVR_ATmega1281__) || defined(__AVR_ATmega2561__)
#define AVR_ATmega2561_FAMILY 1
#elif defined(__AVR_ATmega168__) || defined(__AVR_ATmega328__) || defined(__AVR_ATmega328P__)
#define AVR_ATmega328_FAMILY 1
#endif
/**
* Include Ports and Functions
*/
#if AVR_ATmega328_FAMILY
#include "fastio/fastio_168.h"
#elif AVR_ATmega1284_FAMILY
#include "fastio/fastio_644.h"
#elif AVR_ATmega2560_FAMILY
#include "fastio/fastio_1280.h"
#elif AVR_AT90USB1286_FAMILY
#include "fastio/fastio_AT90USB.h"
#elif AVR_ATmega2561_FAMILY
#include "fastio/fastio_1281.h"
#else
#error "No FastIO definition for the selected AVR Board."
#endif
/**
* Magic I/O routines
*
* Now you can simply SET_OUTPUT(PIN); WRITE(PIN, HIGH); WRITE(PIN, LOW);
*
* Why double up on these macros? see https://gcc.gnu.org/onlinedocs/cpp/Stringification.html
*/
#define _READ(IO) TEST(DIO ## IO ## _RPORT, DIO ## IO ## _PIN)
#define _WRITE_NC(IO,V) do{ \
if (V) SBI(DIO ## IO ## _WPORT, DIO ## IO ## _PIN); \
else CBI(DIO ## IO ## _WPORT, DIO ## IO ## _PIN); \
}while(0)
#define _WRITE_C(IO,V) do{ \
uint8_t port_bits = DIO ## IO ## _WPORT; /* Get a mask from the current port bits */ \
if (V) port_bits = ~port_bits; /* For setting bits, invert the mask */ \
DIO ## IO ## _RPORT = port_bits & _BV(DIO ## IO ## _PIN); /* Atomically toggle the output port bits */ \
}while(0)
#define _WRITE(IO,V) do{ if (&(DIO ## IO ## _RPORT) < (uint8_t*)0x100) _WRITE_NC(IO,V); else _WRITE_C(IO,V); }while(0)
#define _TOGGLE(IO) (DIO ## IO ## _RPORT = _BV(DIO ## IO ## _PIN))
#define _SET_INPUT(IO) CBI(DIO ## IO ## _DDR, DIO ## IO ## _PIN)
#define _SET_OUTPUT(IO) SBI(DIO ## IO ## _DDR, DIO ## IO ## _PIN)
#define _IS_INPUT(IO) !TEST(DIO ## IO ## _DDR, DIO ## IO ## _PIN)
#define _IS_OUTPUT(IO) TEST(DIO ## IO ## _DDR, DIO ## IO ## _PIN)
// digitalRead/Write wrappers
#ifdef FASTIO_EXT_START
void extDigitalWrite(const int8_t pin, const uint8_t state);
uint8_t extDigitalRead(const int8_t pin);
#else
#define extDigitalWrite(IO,V) digitalWrite(IO,V)
#define extDigitalRead(IO) digitalRead(IO)
#endif
#define READ(IO) _READ(IO)
#define WRITE(IO,V) _WRITE(IO,V)
#define TOGGLE(IO) _TOGGLE(IO)
#define SET_INPUT(IO) _SET_INPUT(IO)
#define SET_INPUT_PULLUP(IO) do{ _SET_INPUT(IO); _WRITE(IO, HIGH); }while(0)
#define SET_INPUT_PULLDOWN SET_INPUT
#define SET_OUTPUT(IO) _SET_OUTPUT(IO)
#define SET_PWM SET_OUTPUT
#define IS_INPUT(IO) _IS_INPUT(IO)
#define IS_OUTPUT(IO) _IS_OUTPUT(IO)
#define OUT_WRITE(IO,V) do{ SET_OUTPUT(IO); WRITE(IO,V); }while(0)
/**
* Timer and Interrupt Control
*/
// Waveform Generation Modes
enum WaveGenMode : uint8_t {
WGM_NORMAL, // 0
WGM_PWM_PC_8, // 1
WGM_PWM_PC_9, // 2
WGM_PWM_PC_10, // 3
WGM_CTC_OCRnA, // 4 COM OCnx
WGM_FAST_PWM_8, // 5
WGM_FAST_PWM_9, // 6
WGM_FAST_PWM_10, // 7
WGM_PWM_PC_FC_ICRn, // 8
WGM_PWM_PC_FC_OCRnA, // 9 COM OCnA
WGM_PWM_PC_ICRn, // 10
WGM_PWM_PC_OCRnA, // 11 COM OCnA
WGM_CTC_ICRn, // 12 COM OCnx
WGM_reserved, // 13
WGM_FAST_PWM_ICRn, // 14 COM OCnA
WGM_FAST_PWM_OCRnA // 15 COM OCnA
};
// Wavefore Generation Modes (Timer 2 only)
enum WaveGenMode2 : uint8_t {
WGM2_NORMAL, // 0
WGM2_PWM_PC, // 1
WGM2_CTC_OCR2A, // 2
WGM2_FAST_PWM, // 3
WGM2_reserved_1, // 4
WGM2_PWM_PC_OCR2A, // 5
WGM2_reserved_2, // 6
WGM2_FAST_PWM_OCR2A, // 7
};
// Compare Modes
enum CompareMode : uint8_t {
COM_NORMAL, // 0
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_SET_CLEAR // 3 Non-PWM: OCnx ... Fast PWM: OCnx/Bottom ... PF-FC: OCnx Up/Down
};
// Clock Sources
enum ClockSource : uint8_t {
CS_NONE, // 0
CS_PRESCALER_1, // 1
CS_PRESCALER_8, // 2
CS_PRESCALER_64, // 3
CS_PRESCALER_256, // 4
CS_PRESCALER_1024, // 5
CS_EXT_FALLING, // 6
CS_EXT_RISING // 7
};
// Clock Sources (Timer 2 only)
enum ClockSource2 : uint8_t {
CS2_NONE, // 0
CS2_PRESCALER_1, // 1
CS2_PRESCALER_8, // 2
CS2_PRESCALER_32, // 3
CS2_PRESCALER_64, // 4
CS2_PRESCALER_128, // 5
CS2_PRESCALER_256, // 6
CS2_PRESCALER_1024 // 7
};
// Get interrupt bits in an orderly way
// Ex: cs = GET_CS(0); coma1 = GET_COM(A,1);
#define GET_WGM(T) (((TCCR##T##A >> WGM##T##0) & 0x3) | ((TCCR##T##B >> WGM##T##2 << 2) & 0xC))
#define GET_CS(T) ((TCCR##T##B >> CS##T##0) & 0x7)
#define GET_COM(T,Q) ((TCCR##T##Q >> COM##T##Q##0) & 0x3)
#define GET_COMA(T) GET_COM(T,A)
#define GET_COMB(T) GET_COM(T,B)
#define GET_COMC(T) GET_COM(T,C)
#define GET_ICNC(T) (!!(TCCR##T##B & _BV(ICNC##T)))
#define GET_ICES(T) (!!(TCCR##T##B & _BV(ICES##T)))
#define GET_FOC(T,Q) (!!(TCCR##T##C & _BV(FOC##T##Q)))
#define GET_FOCA(T) GET_FOC(T,A)
#define GET_FOCB(T) GET_FOC(T,B)
#define GET_FOCC(T) GET_FOC(T,C)
// Set Wave Generation Mode bits
// Ex: SET_WGM(5,CTC_ICRn);
#define _SET_WGM(T,V) do{ \
TCCR##T##A = (TCCR##T##A & ~(0x3 << WGM##T##0)) | (( int(V) & 0x3) << WGM##T##0); \
TCCR##T##B = (TCCR##T##B & ~(0x3 << WGM##T##2)) | (((int(V) >> 2) & 0x3) << WGM##T##2); \
}while(0)
#define SET_WGM(T,V) _SET_WGM(T,WGM_##V)
// Set Clock Select bits
// 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_CS0(V) _SET_CS(0,V)
#define _SET_CS1(V) _SET_CS(1,V)
#define _SET_CS3(V) _SET_CS(3,V)
#define _SET_CS4(V) _SET_CS(4,V)
#define _SET_CS5(V) _SET_CS(5,V)
#define SET_CS0(V) _SET_CS0(CS_##V)
#define SET_CS1(V) _SET_CS1(CS_##V)
#if HAS_TCCR2
#define _SET_CS2(V) (TCCR2 = (TCCR2 & ~(0x7 << CS20)) | (int(V) << CS20))
#define SET_CS2(V) _SET_CS2(CS2_##V)
#else
#define _SET_CS2(V) _SET_CS(2,V)
#define SET_CS2(V) _SET_CS2(CS_##V)
#endif
#define SET_CS3(V) _SET_CS3(CS_##V)
#define SET_CS4(V) _SET_CS4(CS_##V)
#define SET_CS5(V) _SET_CS5(CS_##V)
#define SET_CS(T,V) SET_CS##T(V)
// Set Compare Mode bits
// Ex: SET_COMS(4,CLEAR_SET,CLEAR_SET,CLEAR_SET);
#define _SET_COM(T,Q,V) (TCCR##T##Q = (TCCR##T##Q & ~(0x3 << COM##T##Q##0)) | (int(V) << COM##T##Q##0))
#define SET_COM(T,Q,V) _SET_COM(T,Q,COM_##V)
#define SET_COMA(T,V) SET_COM(T,A,V)
#define SET_COMB(T,V) SET_COM(T,B,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)
// Set Noise Canceler bit
// Ex: SET_ICNC(2,1)
#define SET_ICNC(T,V) (TCCR##T##B = (V) ? TCCR##T##B | _BV(ICNC##T) : TCCR##T##B & ~_BV(ICNC##T))
// Set Input Capture Edge Select bit
// Ex: SET_ICES(5,0)
#define SET_ICES(T,V) (TCCR##T##B = (V) ? TCCR##T##B | _BV(ICES##T) : TCCR##T##B & ~_BV(ICES##T))
// Set Force Output Compare bit
// Ex: SET_FOC(3,A,1)
#define SET_FOC(T,Q,V) (TCCR##T##C = (V) ? TCCR##T##C | _BV(FOC##T##Q) : TCCR##T##C & ~_BV(FOC##T##Q))
#define SET_FOCA(T,V) SET_FOC(T,A,V)
#define SET_FOCB(T,V) SET_FOC(T,B,V)
#define SET_FOCC(T,V) SET_FOC(T,C,V)
// define which hardware PWMs are available for the current CPU
// all timer 1 PWMS deleted from this list because they are never available
#if AVR_ATmega2560_FAMILY
#define PWM_PIN(P) ((P >= 2 && P <= 10) || P == 13 || P == 44 || P == 45 || P == 46)
#elif AVR_ATmega2561_FAMILY
#define PWM_PIN(P) ((P >= 2 && P <= 6) || P == 9)
#elif AVR_ATmega1284_FAMILY
#define PWM_PIN(P) (P == 3 || P == 4 || P == 14 || P == 15)
#elif AVR_AT90USB1286_FAMILY
#define PWM_PIN(P) (P == 0 || P == 1 || P == 14 || P == 15 || P == 16 || P == 24)
#elif AVR_ATmega328_FAMILY
#define PWM_PIN(P) (P == 3 || P == 5 || P == 6 || P == 11)
#else
#error "unknown CPU"
#endif

File diff suppressed because it is too large Load Diff

@ -0,0 +1,715 @@
/**
* 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/>.
*
*/
#pragma once
/**
* Pin mapping for the 1281 and 2561
*
* Logical Pin: 38 39 40 41 42 43 44 45 16 10 11 12 06 07 08 09 30 31 32 33 34 35 36 37 17 18 19 20 21 22 23 24 00 01 13 05 02 03 14 15 46 47 48 49 50 51 52 53 25 26 27 28 29 04
* Port: A0 A1 A2 A3 A4 A5 A6 A7 B0 B1 B2 B3 B4 B5 B6 B7 C0 C1 C2 C3 C4 C5 C6 C7 D0 D1 D2 D3 D4 D5 D6 D7 E0 E1 E2 E3 E4 E5 E6 E7 F0 F1 F2 F3 F4 F5 F6 F7 G0 G1 G2 G3 G4 G5
*
* Arduino Pin Layout video: https://youtu.be/rIqeVCX09FA
* AVR alternate pin function overview video: https://youtu.be/1yd8wuI5Plg
*/
#include "../fastio.h"
// UART
#define RXD 0
#define TXD 1
// SPI
#define SCK 10
#define MISO 12
#define MOSI 11
#define SS 16
// TWI (I2C)
#define SCL 17
#define SDA 18
// Timers and PWM
#define OC0A 9
#define OC0B 4
#define OC1A 7
#define OC1B 8
#define OC2A 6
#define OC3A 5
#define OC3B 2
#define OC3C 3
// Digital I/O
#define DIO0_PIN PINE0
#define DIO0_RPORT PINE
#define DIO0_WPORT PORTE
#define DIO0_DDR DDRE
#define DIO0_PWM nullptr
#define DIO1_PIN PINE1
#define DIO1_RPORT PINE
#define DIO1_WPORT PORTE
#define DIO1_DDR DDRE
#define DIO1_PWM nullptr
#define DIO2_PIN PINE4
#define DIO2_RPORT PINE
#define DIO2_WPORT PORTE
#define DIO2_DDR DDRE
#define DIO2_PWM &OCR3BL
#define DIO3_PIN PINE5
#define DIO3_RPORT PINE
#define DIO3_WPORT PORTE
#define DIO3_DDR DDRE
#define DIO3_PWM &OCR3CL
#define DIO4_PIN PING5
#define DIO4_RPORT PING
#define DIO4_WPORT PORTG
#define DIO4_DDR DDRG
#define DIO4_PWM &OCR0B
#define DIO5_PIN PINE3
#define DIO5_RPORT PINE
#define DIO5_WPORT PORTE
#define DIO5_DDR DDRE
#define DIO5_PWM &OCR3AL
#define DIO6_PIN PINB4
#define DIO6_RPORT PINB
#define DIO6_WPORT PORTB
#define DIO6_DDR DDRB
#define DIO6_PWM &OCR2AL
#define DIO7_PIN PINB5
#define DIO7_RPORT PINB
#define DIO7_WPORT PORTB
#define DIO7_DDR DDRB
#define DIO7_PWM &OCR1AL
#define DIO8_PIN PINB6
#define DIO8_RPORT PINB
#define DIO8_WPORT PORTB
#define DIO8_DDR DDRB
#define DIO8_PWM &OCR1BL
#define DIO9_PIN PINB7
#define DIO9_RPORT PINB
#define DIO9_WPORT PORTB
#define DIO9_DDR DDRB
#define DIO9_PWM &OCR0AL
#define DIO10_PIN PINB1
#define DIO10_RPORT PINB
#define DIO10_WPORT PORTB
#define DIO10_DDR DDRB
#define DIO10_PWM nullptr
#define DIO11_PIN PINB2
#define DIO11_RPORT PINB
#define DIO11_WPORT PORTB
#define DIO11_DDR DDRB
#define DIO11_PWM nullptr
#define DIO12_PIN PINB3
#define DIO12_RPORT PINB
#define DIO12_WPORT PORTB
#define DIO12_DDR DDRB
#define DIO12_PWM nullptr
#define DIO13_PIN PINE2
#define DIO13_RPORT PINE
#define DIO13_WPORT PORTE
#define DIO13_DDR DDRE
#define DIO13_PWM nullptr
#define DIO14_PIN PINE6
#define DIO14_RPORT PINE
#define DIO14_WPORT PORTE
#define DIO14_DDR DDRE
#define DIO14_PWM nullptr
#define DIO15_PIN PINE7
#define DIO15_RPORT PINE
#define DIO15_WPORT PORTE
#define DIO15_DDR DDRE
#define DIO15_PWM nullptr
#define DIO16_PIN PINB0
#define DIO16_RPORT PINB
#define DIO16_WPORT PORTB
#define DIO16_DDR DDRB
#define DIO16_PWM nullptr
#define DIO17_PIN PIND0
#define DIO17_RPORT PIND
#define DIO17_WPORT PORTD
#define DIO17_DDR DDRD
#define DIO17_PWM nullptr
#define DIO18_PIN PIND1
#define DIO18_RPORT PIND
#define DIO18_WPORT PORTD
#define DIO18_DDR DDRD
#define DIO18_PWM nullptr
#define DIO19_PIN PIND2
#define DIO19_RPORT PIND
#define DIO19_WPORT PORTD
#define DIO19_DDR DDRD
#define DIO19_PWM nullptr
#define DIO20_PIN PIND3
#define DIO20_RPORT PIND
#define DIO20_WPORT PORTD
#define DIO20_DDR DDRD
#define DIO20_PWM nullptr
#define DIO21_PIN PIND4
#define DIO21_RPORT PIND
#define DIO21_WPORT PORTD
#define DIO21_DDR DDRD
#define DIO21_PWM nullptr
#define DIO22_PIN PIND5
#define DIO22_RPORT PIND
#define DIO22_WPORT PORTD
#define DIO22_DDR DDRD
#define DIO22_PWM nullptr
#define DIO23_PIN PIND6
#define DIO23_RPORT PIND
#define DIO23_WPORT PORTD
#define DIO23_DDR DDRD
#define DIO23_PWM nullptr
#define DIO24_PIN PIND7
#define DIO24_RPORT PIND
#define DIO24_WPORT PORTD
#define DIO24_DDR DDRD
#define DIO24_PWM nullptr
#define DIO25_PIN PING0
#define DIO25_RPORT PING
#define DIO25_WPORT PORTG
#define DIO25_DDR DDRG
#define DIO25_PWM nullptr
#define DIO26_PIN PING1
#define DIO26_RPORT PING
#define DIO26_WPORT PORTG
#define DIO26_DDR DDRG
#define DIO26_PWM nullptr
#define DIO27_PIN PING2
#define DIO27_RPORT PING
#define DIO27_WPORT PORTG
#define DIO27_DDR DDRG
#define DIO27_PWM nullptr
#define DIO28_PIN PING3
#define DIO28_RPORT PING
#define DIO28_WPORT PORTG
#define DIO28_DDR DDRG
#define DIO28_PWM nullptr
#define DIO29_PIN PING4
#define DIO29_RPORT PING
#define DIO29_WPORT PORTG
#define DIO29_DDR DDRG
#define DIO29_PWM nullptr
#define DIO30_PIN PINC0
#define DIO30_RPORT PINC
#define DIO30_WPORT PORTC
#define DIO30_DDR DDRC
#define DIO30_PWM nullptr
#define DIO31_PIN PINC1
#define DIO31_RPORT PINC
#define DIO31_WPORT PORTC
#define DIO31_DDR DDRC
#define DIO31_PWM nullptr
#define DIO32_PIN PINC2
#define DIO32_RPORT PINC
#define DIO32_WPORT PORTC
#define DIO32_DDR DDRC
#define DIO32_PWM nullptr
#define DIO33_PIN PINC3
#define DIO33_RPORT PINC
#define DIO33_WPORT PORTC
#define DIO33_DDR DDRC
#define DIO33_PWM nullptr
#define DIO34_PIN PINC4
#define DIO34_RPORT PINC
#define DIO34_WPORT PORTC
#define DIO34_DDR DDRC
#define DIO34_PWM nullptr
#define DIO35_PIN PINC5
#define DIO35_RPORT PINC
#define DIO35_WPORT PORTC
#define DIO35_DDR DDRC
#define DIO35_PWM nullptr
#define DIO36_PIN PINC6
#define DIO36_RPORT PINC
#define DIO36_WPORT PORTC
#define DIO36_DDR DDRC
#define DIO36_PWM nullptr
#define DIO37_PIN PINC7
#define DIO37_RPORT PINC
#define DIO37_WPORT PORTC
#define DIO37_DDR DDRC
#define DIO37_PWM nullptr
#define DIO38_PIN PINA0
#define DIO38_RPORT PINA
#define DIO38_WPORT PORTA
#define DIO38_DDR DDRA
#define DIO38_PWM nullptr
#define DIO39_PIN PINA1
#define DIO39_RPORT PINA
#define DIO39_WPORT PORTA
#define DIO39_DDR DDRA
#define DIO39_PWM nullptr
#define DIO40_PIN PINA2
#define DIO40_RPORT PINA
#define DIO40_WPORT PORTA
#define DIO40_DDR DDRA
#define DIO40_PWM nullptr
#define DIO41_PIN PINA3
#define DIO41_RPORT PINA
#define DIO41_WPORT PORTA
#define DIO41_DDR DDRA
#define DIO41_PWM nullptr
#define DIO42_PIN PINA4
#define DIO42_RPORT PINA
#define DIO42_WPORT PORTA
#define DIO42_DDR DDRA
#define DIO42_PWM nullptr
#define DIO43_PIN PINA5
#define DIO43_RPORT PINA
#define DIO43_WPORT PORTA
#define DIO43_DDR DDRA
#define DIO43_PWM nullptr
#define DIO44_PIN PINA6
#define DIO44_RPORT PINA
#define DIO44_WPORT PORTA
#define DIO44_DDR DDRA
#define DIO44_PWM nullptr
#define DIO45_PIN PINA7
#define DIO45_RPORT PINA
#define DIO45_WPORT PORTA
#define DIO45_DDR DDRA
#define DIO45_PWM nullptr
#define DIO46_PIN PINF0
#define DIO46_RPORT PINF
#define DIO46_WPORT PORTF
#define DIO46_DDR DDRF
#define DIO46_PWM nullptr
#define DIO47_PIN PINF1
#define DIO47_RPORT PINF
#define DIO47_WPORT PORTF
#define DIO47_DDR DDRF
#define DIO47_PWM nullptr
#define DIO48_PIN PINF2
#define DIO48_RPORT PINF
#define DIO48_WPORT PORTF
#define DIO48_DDR DDRF
#define DIO48_PWM nullptr
#define DIO49_PIN PINF3
#define DIO49_RPORT PINF
#define DIO49_WPORT PORTF
#define DIO49_DDR DDRF
#define DIO49_PWM nullptr
#define DIO50_PIN PINF4
#define DIO50_RPORT PINF
#define DIO50_WPORT PORTF
#define DIO50_DDR DDRF
#define DIO50_PWM nullptr
#define DIO51_PIN PINF5
#define DIO51_RPORT PINF
#define DIO51_WPORT PORTF
#define DIO51_DDR DDRF
#define DIO51_PWM nullptr
#define DIO52_PIN PINF6
#define DIO52_RPORT PINF
#define DIO52_WPORT PORTF
#define DIO52_DDR DDRF
#define DIO52_PWM nullptr
#define DIO53_PIN PINF7
#define DIO53_RPORT PINF
#define DIO53_WPORT PORTF
#define DIO53_DDR DDRF
#define DIO53_PWM nullptr
#undef PA0
#define PA0_PIN PINA0
#define PA0_RPORT PINA
#define PA0_WPORT PORTA
#define PA0_DDR DDRA
#define PA0_PWM nullptr
#undef PA1
#define PA1_PIN PINA1
#define PA1_RPORT PINA
#define PA1_WPORT PORTA
#define PA1_DDR DDRA
#define PA1_PWM nullptr
#undef PA2
#define PA2_PIN PINA2
#define PA2_RPORT PINA
#define PA2_WPORT PORTA
#define PA2_DDR DDRA
#define PA2_PWM nullptr
#undef PA3
#define PA3_PIN PINA3
#define PA3_RPORT PINA
#define PA3_WPORT PORTA
#define PA3_DDR DDRA
#define PA3_PWM nullptr
#undef PA4
#define PA4_PIN PINA4
#define PA4_RPORT PINA
#define PA4_WPORT PORTA
#define PA4_DDR DDRA
#define PA4_PWM nullptr
#undef PA5
#define PA5_PIN PINA5
#define PA5_RPORT PINA
#define PA5_WPORT PORTA
#define PA5_DDR DDRA
#define PA5_PWM nullptr
#undef PA6
#define PA6_PIN PINA6
#define PA6_RPORT PINA
#define PA6_WPORT PORTA
#define PA6_DDR DDRA
#define PA6_PWM nullptr
#undef PA7
#define PA7_PIN PINA7
#define PA7_RPORT PINA
#define PA7_WPORT PORTA
#define PA7_DDR DDRA
#define PA7_PWM nullptr
#undef PB0
#define PB0_PIN PINB0
#define PB0_RPORT PINB
#define PB0_WPORT PORTB
#define PB0_DDR DDRB
#define PB0_PWM nullptr
#undef PB1
#define PB1_PIN PINB1
#define PB1_RPORT PINB
#define PB1_WPORT PORTB
#define PB1_DDR DDRB
#define PB1_PWM nullptr
#undef PB2
#define PB2_PIN PINB2
#define PB2_RPORT PINB
#define PB2_WPORT PORTB
#define PB2_DDR DDRB
#define PB2_PWM nullptr
#undef PB3
#define PB3_PIN PINB3
#define PB3_RPORT PINB
#define PB3_WPORT PORTB
#define PB3_DDR DDRB
#define PB3_PWM nullptr
#undef PB4
#define PB4_PIN PINB4
#define PB4_RPORT PINB
#define PB4_WPORT PORTB
#define PB4_DDR DDRB
#define PB4_PWM &OCR2A
#undef PB5
#define PB5_PIN PINB5
#define PB5_RPORT PINB
#define PB5_WPORT PORTB
#define PB5_DDR DDRB
#define PB5_PWM nullptr
#undef PB6
#define PB6_PIN PINB6
#define PB6_RPORT PINB
#define PB6_WPORT PORTB
#define PB6_DDR DDRB
#define PB6_PWM nullptr
#undef PB7
#define PB7_PIN PINB7
#define PB7_RPORT PINB
#define PB7_WPORT PORTB
#define PB7_DDR DDRB
#define PB7_PWM &OCR0A
#undef PC0
#define PC0_PIN PINC0
#define PC0_RPORT PINC
#define PC0_WPORT PORTC
#define PC0_DDR DDRC
#define PC0_PWM nullptr
#undef PC1
#define PC1_PIN PINC1
#define PC1_RPORT PINC
#define PC1_WPORT PORTC
#define PC1_DDR DDRC
#define PC1_PWM nullptr
#undef PC2
#define PC2_PIN PINC2
#define PC2_RPORT PINC
#define PC2_WPORT PORTC
#define PC2_DDR DDRC
#define PC2_PWM nullptr
#undef PC3
#define PC3_PIN PINC3
#define PC3_RPORT PINC
#define PC3_WPORT PORTC
#define PC3_DDR DDRC
#define PC3_PWM nullptr
#undef PC4
#define PC4_PIN PINC4
#define PC4_RPORT PINC
#define PC4_WPORT PORTC
#define PC4_DDR DDRC
#define PC4_PWM nullptr
#undef PC5
#define PC5_PIN PINC5
#define PC5_RPORT PINC
#define PC5_WPORT PORTC
#define PC5_DDR DDRC
#define PC5_PWM nullptr
#undef PC6
#define PC6_PIN PINC6
#define PC6_RPORT PINC
#define PC6_WPORT PORTC
#define PC6_DDR DDRC
#define PC6_PWM nullptr
#undef PC7
#define PC7_PIN PINC7
#define PC7_RPORT PINC
#define PC7_WPORT PORTC
#define PC7_DDR DDRC
#define PC7_PWM nullptr
#undef PD0
#define PD0_PIN PIND0
#define PD0_RPORT PIND
#define PD0_WPORT PORTD
#define PD0_DDR DDRD
#define PD0_PWM nullptr
#undef PD1
#define PD1_PIN PIND1
#define PD1_RPORT PIND
#define PD1_WPORT PORTD
#define PD1_DDR DDRD
#define PD1_PWM nullptr
#undef PD2
#define PD2_PIN PIND2
#define PD2_RPORT PIND
#define PD2_WPORT PORTD
#define PD2_DDR DDRD
#define PD2_PWM nullptr
#undef PD3
#define PD3_PIN PIND3
#define PD3_RPORT PIND
#define PD3_WPORT PORTD
#define PD3_DDR DDRD
#define PD3_PWM nullptr
#undef PD4
#define PD4_PIN PIND4
#define PD4_RPORT PIND
#define PD4_WPORT PORTD
#define PD4_DDR DDRD
#define PD4_PWM nullptr
#undef PD5
#define PD5_PIN PIND5
#define PD5_RPORT PIND
#define PD5_WPORT PORTD
#define PD5_DDR DDRD
#define PD5_PWM nullptr
#undef PD6
#define PD6_PIN PIND6
#define PD6_RPORT PIND
#define PD6_WPORT PORTD
#define PD6_DDR DDRD
#define PD6_PWM nullptr
#undef PD7
#define PD7_PIN PIND7
#define PD7_RPORT PIND
#define PD7_WPORT PORTD
#define PD7_DDR DDRD
#define PD7_PWM nullptr
#undef PE0
#define PE0_PIN PINE0
#define PE0_RPORT PINE
#define PE0_WPORT PORTE
#define PE0_DDR DDRE
#define PE0_PWM nullptr
#undef PE1
#define PE1_PIN PINE1
#define PE1_RPORT PINE
#define PE1_WPORT PORTE
#define PE1_DDR DDRE
#define PE1_PWM nullptr
#undef PE2
#define PE2_PIN PINE2
#define PE2_RPORT PINE
#define PE2_WPORT PORTE
#define PE2_DDR DDRE
#define PE2_PWM nullptr
#undef PE3
#define PE3_PIN PINE3
#define PE3_RPORT PINE
#define PE3_WPORT PORTE
#define PE3_DDR DDRE
#define PE3_PWM &OCR3AL
#undef PE4
#define PE4_PIN PINE4
#define PE4_RPORT PINE
#define PE4_WPORT PORTE
#define PE4_DDR DDRE
#define PE4_PWM &OCR3BL
#undef PE5
#define PE5_PIN PINE5
#define PE5_RPORT PINE
#define PE5_WPORT PORTE
#define PE5_DDR DDRE
#define PE5_PWM &OCR3CL
#undef PE6
#define PE6_PIN PINE6
#define PE6_RPORT PINE
#define PE6_WPORT PORTE
#define PE6_DDR DDRE
#define PE6_PWM nullptr
#undef PE7
#define PE7_PIN PINE7
#define PE7_RPORT PINE
#define PE7_WPORT PORTE
#define PE7_DDR DDRE
#define PE7_PWM nullptr
#undef PF0
#define PF0_PIN PINF0
#define PF0_RPORT PINF
#define PF0_WPORT PORTF
#define PF0_DDR DDRF
#define PF0_PWM nullptr
#undef PF1
#define PF1_PIN PINF1
#define PF1_RPORT PINF
#define PF1_WPORT PORTF
#define PF1_DDR DDRF
#define PF1_PWM nullptr
#undef PF2
#define PF2_PIN PINF2
#define PF2_RPORT PINF
#define PF2_WPORT PORTF
#define PF2_DDR DDRF
#define PF2_PWM nullptr
#undef PF3
#define PF3_PIN PINF3
#define PF3_RPORT PINF
#define PF3_WPORT PORTF
#define PF3_DDR DDRF
#define PF3_PWM nullptr
#undef PF4
#define PF4_PIN PINF4
#define PF4_RPORT PINF
#define PF4_WPORT PORTF
#define PF4_DDR DDRF
#define PF4_PWM nullptr
#undef PF5
#define PF5_PIN PINF5
#define PF5_RPORT PINF
#define PF5_WPORT PORTF
#define PF5_DDR DDRF
#define PF5_PWM nullptr
#undef PF6
#define PF6_PIN PINF6
#define PF6_RPORT PINF
#define PF6_WPORT PORTF
#define PF6_DDR DDRF
#define PF6_PWM nullptr
#undef PF7
#define PF7_PIN PINF7
#define PF7_RPORT PINF
#define PF7_WPORT PORTF
#define PF7_DDR DDRF
#define PF7_PWM nullptr
#undef PG0
#define PG0_PIN PING0
#define PG0_RPORT PING
#define PG0_WPORT PORTG
#define PG0_DDR DDRG
#define PG0_PWM nullptr
#undef PG1
#define PG1_PIN PING1
#define PG1_RPORT PING
#define PG1_WPORT PORTG
#define PG1_DDR DDRG
#define PG1_PWM nullptr
#undef PG2
#define PG2_PIN PING2
#define PG2_RPORT PING
#define PG2_WPORT PORTG
#define PG2_DDR DDRG
#define PG2_PWM nullptr
#undef PG3
#define PG3_PIN PING3
#define PG3_RPORT PING
#define PG3_WPORT PORTG
#define PG3_DDR DDRG
#define PG3_PWM nullptr
#undef PG4
#define PG4_PIN PING4
#define PG4_RPORT PING
#define PG4_WPORT PORTG
#define PG4_DDR DDRG
#define PG4_PWM nullptr
#undef PG5
#define PG5_PIN PING5
#define PG5_RPORT PING
#define PG5_WPORT PORTG
#define PG5_DDR DDRG
#define PG5_PWM &OCR0B

@ -0,0 +1,358 @@
/**
* 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/>.
*
*/
#pragma once
/**
* Pin mapping for the 168, 328, and 328P
*
* Logical Pin: 08 09 10 11 12 13 14 15 16 17 18 19 20 21 00 01 02 03 04 05 06 07
* Port: B0 B1 B2 B3 B4 B5 C0 C1 C2 C3 C4 C5 C6 C7 D0 D1 D2 D3 D4 D5 D6 D7
*
* Arduino Pin Layout video: https://youtu.be/rIqeVCX09FA
* AVR alternate pin function overview video: https://youtu.be/1yd8wuI5Plg
*/
#include "../fastio.h"
// UART
#define RXD 0
#define TXD 1
// SPI
#define SS 10
#define MOSI 11
#define MISO 12
#define SCK 13
// TWI (I2C)
#define SCL AIO5
#define SDA AIO4
// Timers and PWM
#define OC0A 6
#define OC0B 5
#define OC1A 9
#define OC1B 10
#define OC2A 11
#define OC2B 3
// Digital I/O
#define DIO0_PIN PIND0
#define DIO0_RPORT PIND
#define DIO0_WPORT PORTD
#define DIO0_DDR DDRD
#define DIO0_PWM nullptr
#define DIO1_PIN PIND1
#define DIO1_RPORT PIND
#define DIO1_WPORT PORTD
#define DIO1_DDR DDRD
#define DIO1_PWM nullptr
#define DIO2_PIN PIND2
#define DIO2_RPORT PIND
#define DIO2_WPORT PORTD
#define DIO2_DDR DDRD
#define DIO2_PWM nullptr
#define DIO3_PIN PIND3
#define DIO3_RPORT PIND
#define DIO3_WPORT PORTD
#define DIO3_DDR DDRD
#define DIO3_PWM &OCR2B
#define DIO4_PIN PIND4
#define DIO4_RPORT PIND
#define DIO4_WPORT PORTD
#define DIO4_DDR DDRD
#define DIO4_PWM nullptr
#define DIO5_PIN PIND5
#define DIO5_RPORT PIND
#define DIO5_WPORT PORTD
#define DIO5_DDR DDRD
#define DIO5_PWM &OCR0B
#define DIO6_PIN PIND6
#define DIO6_RPORT PIND
#define DIO6_WPORT PORTD
#define DIO6_DDR DDRD
#define DIO6_PWM &OCR0A
#define DIO7_PIN PIND7
#define DIO7_RPORT PIND
#define DIO7_WPORT PORTD
#define DIO7_DDR DDRD
#define DIO7_PWM nullptr
#define DIO8_PIN PINB0
#define DIO8_RPORT PINB
#define DIO8_WPORT PORTB
#define DIO8_DDR DDRB
#define DIO8_PWM nullptr
#define DIO9_PIN PINB1
#define DIO9_RPORT PINB
#define DIO9_WPORT PORTB
#define DIO9_DDR DDRB
#define DIO9_PWM nullptr
#define DIO10_PIN PINB2
#define DIO10_RPORT PINB
#define DIO10_WPORT PORTB
#define DIO10_DDR DDRB
#define DIO10_PWM nullptr
#define DIO11_PIN PINB3
#define DIO11_RPORT PINB
#define DIO11_WPORT PORTB
#define DIO11_DDR DDRB
#define DIO11_PWM &OCR2A
#define DIO12_PIN PINB4
#define DIO12_RPORT PINB
#define DIO12_WPORT PORTB
#define DIO12_DDR DDRB
#define DIO12_PWM nullptr
#define DIO13_PIN PINB5
#define DIO13_RPORT PINB
#define DIO13_WPORT PORTB
#define DIO13_DDR DDRB
#define DIO13_PWM nullptr
#define DIO14_PIN PINC0
#define DIO14_RPORT PINC
#define DIO14_WPORT PORTC
#define DIO14_DDR DDRC
#define DIO14_PWM nullptr
#define DIO15_PIN PINC1
#define DIO15_RPORT PINC
#define DIO15_WPORT PORTC
#define DIO15_DDR DDRC
#define DIO15_PWM nullptr
#define DIO16_PIN PINC2
#define DIO16_RPORT PINC
#define DIO16_WPORT PORTC
#define DIO16_DDR DDRC
#define DIO16_PWM nullptr
#define DIO17_PIN PINC3
#define DIO17_RPORT PINC
#define DIO17_WPORT PORTC
#define DIO17_DDR DDRC
#define DIO17_PWM nullptr
#define DIO18_PIN PINC4
#define DIO18_RPORT PINC
#define DIO18_WPORT PORTC
#define DIO18_DDR DDRC
#define DIO18_PWM nullptr
#define DIO19_PIN PINC5
#define DIO19_RPORT PINC
#define DIO19_WPORT PORTC
#define DIO19_DDR DDRC
#define DIO19_PWM nullptr
#define DIO20_PIN PINC6
#define DIO20_RPORT PINC
#define DIO20_WPORT PORTC
#define DIO20_DDR DDRC
#define DIO20_PWM nullptr
#define DIO21_PIN PINC7
#define DIO21_RPORT PINC
#define DIO21_WPORT PORTC
#define DIO21_DDR DDRC
#define DIO21_PWM nullptr
#undef PB0
#define PB0_PIN PINB0
#define PB0_RPORT PINB
#define PB0_WPORT PORTB
#define PB0_DDR DDRB
#define PB0_PWM nullptr
#undef PB1
#define PB1_PIN PINB1
#define PB1_RPORT PINB
#define PB1_WPORT PORTB
#define PB1_DDR DDRB
#define PB1_PWM nullptr
#undef PB2
#define PB2_PIN PINB2
#define PB2_RPORT PINB
#define PB2_WPORT PORTB
#define PB2_DDR DDRB
#define PB2_PWM nullptr
#undef PB3
#define PB3_PIN PINB3
#define PB3_RPORT PINB
#define PB3_WPORT PORTB
#define PB3_DDR DDRB
#define PB3_PWM &OCR2A
#undef PB4
#define PB4_PIN PINB4
#define PB4_RPORT PINB
#define PB4_WPORT PORTB
#define PB4_DDR DDRB
#define PB4_PWM nullptr
#undef PB5
#define PB5_PIN PINB5
#define PB5_RPORT PINB
#define PB5_WPORT PORTB
#define PB5_DDR DDRB
#define PB5_PWM nullptr
#undef PB6
#define PB6_PIN PINB6
#define PB6_RPORT PINB
#define PB6_WPORT PORTB
#define PB6_DDR DDRB
#define PB6_PWM nullptr
#undef PB7
#define PB7_PIN PINB7
#define PB7_RPORT PINB
#define PB7_WPORT PORTB
#define PB7_DDR DDRB
#define PB7_PWM nullptr
#undef PC0
#define PC0_PIN PINC0
#define PC0_RPORT PINC
#define PC0_WPORT PORTC
#define PC0_DDR DDRC
#define PC0_PWM nullptr
#undef PC1
#define PC1_PIN PINC1
#define PC1_RPORT PINC
#define PC1_WPORT PORTC
#define PC1_DDR DDRC
#define PC1_PWM nullptr
#undef PC2
#define PC2_PIN PINC2
#define PC2_RPORT PINC
#define PC2_WPORT PORTC
#define PC2_DDR DDRC
#define PC2_PWM nullptr
#undef PC3
#define PC3_PIN PINC3
#define PC3_RPORT PINC
#define PC3_WPORT PORTC
#define PC3_DDR DDRC
#define PC3_PWM nullptr
#undef PC4
#define PC4_PIN PINC4
#define PC4_RPORT PINC
#define PC4_WPORT PORTC
#define PC4_DDR DDRC
#define PC4_PWM nullptr
#undef PC5
#define PC5_PIN PINC5
#define PC5_RPORT PINC
#define PC5_WPORT PORTC
#define PC5_DDR DDRC
#define PC5_PWM nullptr
#undef PC6
#define PC6_PIN PINC6
#define PC6_RPORT PINC
#define PC6_WPORT PORTC
#define PC6_DDR DDRC
#define PC6_PWM nullptr
#undef PC7
#define PC7_PIN PINC7
#define PC7_RPORT PINC
#define PC7_WPORT PORTC
#define PC7_DDR DDRC
#define PC7_PWM nullptr
#undef PD0
#define PD0_PIN PIND0
#define PD0_RPORT PIND
#define PD0_WPORT PORTD
#define PD0_DDR DDRD
#define PD0_PWM nullptr
#undef PD1
#define PD1_PIN PIND1
#define PD1_RPORT PIND
#define PD1_WPORT PORTD
#define PD1_DDR DDRD
#define PD1_PWM nullptr
#undef PD2
#define PD2_PIN PIND2
#define PD2_RPORT PIND
#define PD2_WPORT PORTD
#define PD2_DDR DDRD
#define PD2_PWM nullptr
#undef PD3
#define PD3_PIN PIND3
#define PD3_RPORT PIND
#define PD3_WPORT PORTD
#define PD3_DDR DDRD
#define PD3_PWM &OCR2B
#undef PD4
#define PD4_PIN PIND4
#define PD4_RPORT PIND
#define PD4_WPORT PORTD
#define PD4_DDR DDRD
#define PD4_PWM nullptr
#undef PD5
#define PD5_PIN PIND5
#define PD5_RPORT PIND
#define PD5_WPORT PORTD
#define PD5_DDR DDRD
#define PD5_PWM &OCR0B
#undef PD6
#define PD6_PIN PIND6
#define PD6_RPORT PIND
#define PD6_WPORT PORTD
#define PD6_DDR DDRD
#define PD6_PWM &OCR0A
#undef PD7
#define PD7_PIN PIND7
#define PD7_RPORT PIND
#define PD7_WPORT PORTD
#define PD7_DDR DDRD
#define PD7_PWM nullptr

@ -0,0 +1,553 @@
/**
* 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/>.
*
*/
#pragma once
/**
* Pin mapping for the 644, 644p, 644pa, and 1284p
*
* Logical Pin: 00 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
* Port: B0 B1 B2 B3 B4 B5 B6 B7 D0 D1 D2 D3 D4 D5 D6 D7 C0 C1 C2 C3 C4 C5 C6 C7 A7 A6 A5 A4 A3 A2 A1 A0
*
* Arduino Pin Layout video: https://youtu.be/rIqeVCX09FA
* AVR alternate pin function overview video: https://youtu.be/1yd8wuI5Plg
*/
/** ATMega644
*
* +---\/---+
* (D 0) PB0 1| |40 PA0 (AI 0 / D31)
* (D 1) PB1 2| |39 PA1 (AI 1 / D30)
* INT2 (D 2) PB2 3| |38 PA2 (AI 2 / D29)
* PWM (D 3) PB3 4| |37 PA3 (AI 3 / D28)
* PWM (D 4) PB4 5| |36 PA4 (AI 4 / D27)
* MOSI (D 5) PB5 6| |35 PA5 (AI 5 / D26)
* MISO (D 6) PB6 7| |34 PA6 (AI 6 / D25)
* SCK (D 7) PB7 8| |33 PA7 (AI 7 / D24)
* RST 9| |32 AREF
* VCC 10| |31 GND
* GND 11| |30 AVCC
* XTAL2 12| |29 PC7 (D 23)
* XTAL1 13| |28 PC6 (D 22)
* RX0 (D 8) PD0 14| |27 PC5 (D 21) TDI
* TX0 (D 9) PD1 15| |26 PC4 (D 20) TDO
* INT0 RX1 (D 10) PD2 16| |25 PC3 (D 19) TMS
* INT1 TX1 (D 11) PD3 17| |24 PC2 (D 18) TCK
* PWM (D 12) PD4 18| |23 PC1 (D 17) SDA
* PWM (D 13) PD5 19| |22 PC0 (D 16) SCL
* PWM (D 14) PD6 20| |21 PD7 (D 15) PWM
* +--------+
*/
#include "../fastio.h"
// UART
#define RXD 8
#define TXD 9
#define RXD0 8
#define TXD0 9
#define RXD1 10
#define TXD1 11
// SPI
#define SS 4
#define MOSI 5
#define MISO 6
#define SCK 7
// TWI (I2C)
#define SCL 16
#define SDA 17
// Timers and PWM
#define OC0A 3
#define OC0B 4
#define OC1A 13
#define OC1B 12
#define OC2A 15
#define OC2B 14
// Digital I/O
#define DIO0_PIN PINB0
#define DIO0_RPORT PINB
#define DIO0_WPORT PORTB
#define DIO0_DDR DDRB
#define DIO0_PWM nullptr
#define DIO1_PIN PINB1
#define DIO1_RPORT PINB
#define DIO1_WPORT PORTB
#define DIO1_DDR DDRB
#define DIO1_PWM nullptr
#define DIO2_PIN PINB2
#define DIO2_RPORT PINB
#define DIO2_WPORT PORTB
#define DIO2_DDR DDRB
#define DIO2_PWM nullptr
#define DIO3_PIN PINB3
#define DIO3_RPORT PINB
#define DIO3_WPORT PORTB
#define DIO3_DDR DDRB
#define DIO3_PWM &OCR0A
#define DIO4_PIN PINB4
#define DIO4_RPORT PINB
#define DIO4_WPORT PORTB
#define DIO4_DDR DDRB
#define DIO4_PWM &OCR0B
#define DIO5_PIN PINB5
#define DIO5_RPORT PINB
#define DIO5_WPORT PORTB
#define DIO5_DDR DDRB
#define DIO5_PWM nullptr
#define DIO6_PIN PINB6
#define DIO6_RPORT PINB
#define DIO6_WPORT PORTB
#define DIO6_DDR DDRB
#define DIO6_PWM nullptr
#define DIO7_PIN PINB7
#define DIO7_RPORT PINB
#define DIO7_WPORT PORTB
#define DIO7_DDR DDRB
#define DIO7_PWM nullptr
#define DIO8_PIN PIND0
#define DIO8_RPORT PIND
#define DIO8_WPORT PORTD
#define DIO8_DDR DDRD
#define DIO8_PWM nullptr
#define DIO9_PIN PIND1
#define DIO9_RPORT PIND
#define DIO9_WPORT PORTD
#define DIO9_DDR DDRD
#define DIO9_PWM nullptr
#define DIO10_PIN PIND2
#define DIO10_RPORT PIND
#define DIO10_WPORT PORTD
#define DIO10_DDR DDRD
#define DIO10_PWM nullptr
#define DIO11_PIN PIND3
#define DIO11_RPORT PIND
#define DIO11_WPORT PORTD
#define DIO11_DDR DDRD
#define DIO11_PWM nullptr
#define DIO12_PIN PIND4
#define DIO12_RPORT PIND
#define DIO12_WPORT PORTD
#define DIO12_DDR DDRD
#define DIO12_PWM &OCR1B
#define DIO13_PIN PIND5
#define DIO13_RPORT PIND
#define DIO13_WPORT PORTD
#define DIO13_DDR DDRD
#define DIO13_PWM &OCR1A
#define DIO14_PIN PIND6
#define DIO14_RPORT PIND
#define DIO14_WPORT PORTD
#define DIO14_DDR DDRD
#define DIO14_PWM &OCR2B
#define DIO15_PIN PIND7
#define DIO15_RPORT PIND
#define DIO15_WPORT PORTD
#define DIO15_DDR DDRD
#define DIO15_PWM &OCR2A
#define DIO16_PIN PINC0
#define DIO16_RPORT PINC
#define DIO16_WPORT PORTC
#define DIO16_DDR DDRC
#define DIO16_PWM nullptr
#define DIO17_PIN PINC1
#define DIO17_RPORT PINC
#define DIO17_WPORT PORTC
#define DIO17_DDR DDRC
#define DIO17_PWM nullptr
#define DIO18_PIN PINC2
#define DIO18_RPORT PINC
#define DIO18_WPORT PORTC
#define DIO18_DDR DDRC
#define DIO18_PWM nullptr
#define DIO19_PIN PINC3
#define DIO19_RPORT PINC
#define DIO19_WPORT PORTC
#define DIO19_DDR DDRC
#define DIO19_PWM nullptr
#define DIO20_PIN PINC4
#define DIO20_RPORT PINC
#define DIO20_WPORT PORTC
#define DIO20_DDR DDRC
#define DIO20_PWM nullptr
#define DIO21_PIN PINC5
#define DIO21_RPORT PINC
#define DIO21_WPORT PORTC
#define DIO21_DDR DDRC
#define DIO21_PWM nullptr
#define DIO22_PIN PINC6
#define DIO22_RPORT PINC
#define DIO22_WPORT PORTC
#define DIO22_DDR DDRC
#define DIO22_PWM nullptr
#define DIO23_PIN PINC7
#define DIO23_RPORT PINC
#define DIO23_WPORT PORTC
#define DIO23_DDR DDRC
#define DIO23_PWM nullptr
#define DIO24_PIN PINA7
#define DIO24_RPORT PINA
#define DIO24_WPORT PORTA
#define DIO24_DDR DDRA
#define DIO24_PWM nullptr
#define DIO25_PIN PINA6
#define DIO25_RPORT PINA
#define DIO25_WPORT PORTA
#define DIO25_DDR DDRA
#define DIO25_PWM nullptr
#define DIO26_PIN PINA5
#define DIO26_RPORT PINA
#define DIO26_WPORT PORTA
#define DIO26_DDR DDRA
#define DIO26_PWM nullptr
#define DIO27_PIN PINA4
#define DIO27_RPORT PINA
#define DIO27_WPORT PORTA
#define DIO27_DDR DDRA
#define DIO27_PWM nullptr
#define DIO28_PIN PINA3
#define DIO28_RPORT PINA
#define DIO28_WPORT PORTA
#define DIO28_DDR DDRA
#define DIO28_PWM nullptr
#define DIO29_PIN PINA2
#define DIO29_RPORT PINA
#define DIO29_WPORT PORTA
#define DIO29_DDR DDRA
#define DIO29_PWM nullptr
#define DIO30_PIN PINA1
#define DIO30_RPORT PINA
#define DIO30_WPORT PORTA
#define DIO30_DDR DDRA
#define DIO30_PWM nullptr
#define DIO31_PIN PINA0
#define DIO31_RPORT PINA
#define DIO31_WPORT PORTA
#define DIO31_DDR DDRA
#define DIO31_PWM nullptr
#define AIO0_PIN PINA0
#define AIO0_RPORT PINA
#define AIO0_WPORT PORTA
#define AIO0_DDR DDRA
#define AIO0_PWM nullptr
#define AIO1_PIN PINA1
#define AIO1_RPORT PINA
#define AIO1_WPORT PORTA
#define AIO1_DDR DDRA
#define AIO1_PWM nullptr
#define AIO2_PIN PINA2
#define AIO2_RPORT PINA
#define AIO2_WPORT PORTA
#define AIO2_DDR DDRA
#define AIO2_PWM nullptr
#define AIO3_PIN PINA3
#define AIO3_RPORT PINA
#define AIO3_WPORT PORTA
#define AIO3_DDR DDRA
#define AIO3_PWM nullptr
#define AIO4_PIN PINA4
#define AIO4_RPORT PINA
#define AIO4_WPORT PORTA
#define AIO4_DDR DDRA
#define AIO4_PWM nullptr
#define AIO5_PIN PINA5
#define AIO5_RPORT PINA
#define AIO5_WPORT PORTA
#define AIO5_DDR DDRA
#define AIO5_PWM nullptr
#define AIO6_PIN PINA6
#define AIO6_RPORT PINA
#define AIO6_WPORT PORTA
#define AIO6_DDR DDRA
#define AIO6_PWM nullptr
#define AIO7_PIN PINA7
#define AIO7_RPORT PINA
#define AIO7_WPORT PORTA
#define AIO7_DDR DDRA
#define AIO7_PWM nullptr
#undef PA0
#define PA0_PIN PINA0
#define PA0_RPORT PINA
#define PA0_WPORT PORTA
#define PA0_DDR DDRA
#define PA0_PWM nullptr
#undef PA1
#define PA1_PIN PINA1
#define PA1_RPORT PINA
#define PA1_WPORT PORTA
#define PA1_DDR DDRA
#define PA1_PWM nullptr
#undef PA2
#define PA2_PIN PINA2
#define PA2_RPORT PINA
#define PA2_WPORT PORTA
#define PA2_DDR DDRA
#define PA2_PWM nullptr
#undef PA3
#define PA3_PIN PINA3
#define PA3_RPORT PINA
#define PA3_WPORT PORTA
#define PA3_DDR DDRA
#define PA3_PWM nullptr
#undef PA4
#define PA4_PIN PINA4
#define PA4_RPORT PINA
#define PA4_WPORT PORTA
#define PA4_DDR DDRA
#define PA4_PWM nullptr
#undef PA5
#define PA5_PIN PINA5
#define PA5_RPORT PINA
#define PA5_WPORT PORTA
#define PA5_DDR DDRA
#define PA5_PWM nullptr
#undef PA6
#define PA6_PIN PINA6
#define PA6_RPORT PINA
#define PA6_WPORT PORTA
#define PA6_DDR DDRA
#define PA6_PWM nullptr
#undef PA7
#define PA7_PIN PINA7
#define PA7_RPORT PINA
#define PA7_WPORT PORTA
#define PA7_DDR DDRA
#define PA7_PWM nullptr
#undef PB0
#define PB0_PIN PINB0
#define PB0_RPORT PINB
#define PB0_WPORT PORTB
#define PB0_DDR DDRB
#define PB0_PWM nullptr
#undef PB1
#define PB1_PIN PINB1
#define PB1_RPORT PINB
#define PB1_WPORT PORTB
#define PB1_DDR DDRB
#define PB1_PWM nullptr
#undef PB2
#define PB2_PIN PINB2
#define PB2_RPORT PINB
#define PB2_WPORT PORTB
#define PB2_DDR DDRB
#define PB2_PWM nullptr
#undef PB3
#define PB3_PIN PINB3
#define PB3_RPORT PINB
#define PB3_WPORT PORTB
#define PB3_DDR DDRB
#define PB3_PWM &OCR0A
#undef PB4
#define PB4_PIN PINB4
#define PB4_RPORT PINB
#define PB4_WPORT PORTB
#define PB4_DDR DDRB
#define PB4_PWM &OCR0B
#undef PB5
#define PB5_PIN PINB5
#define PB5_RPORT PINB
#define PB5_WPORT PORTB
#define PB5_DDR DDRB
#define PB5_PWM nullptr
#undef PB6
#define PB6_PIN PINB6
#define PB6_RPORT PINB
#define PB6_WPORT PORTB
#define PB6_DDR DDRB
#define PB6_PWM nullptr
#undef PB7
#define PB7_PIN PINB7
#define PB7_RPORT PINB
#define PB7_WPORT PORTB
#define PB7_DDR DDRB
#define PB7_PWM nullptr
#undef PC0
#define PC0_PIN PINC0
#define PC0_RPORT PINC
#define PC0_WPORT PORTC
#define PC0_DDR DDRC
#define PC0_PWM nullptr
#undef PC1
#define PC1_PIN PINC1
#define PC1_RPORT PINC
#define PC1_WPORT PORTC
#define PC1_DDR DDRC
#define PC1_PWM nullptr
#undef PC2
#define PC2_PIN PINC2
#define PC2_RPORT PINC
#define PC2_WPORT PORTC
#define PC2_DDR DDRC
#define PC2_PWM nullptr
#undef PC3
#define PC3_PIN PINC3
#define PC3_RPORT PINC
#define PC3_WPORT PORTC
#define PC3_DDR DDRC
#define PC3_PWM nullptr
#undef PC4
#define PC4_PIN PINC4
#define PC4_RPORT PINC
#define PC4_WPORT PORTC
#define PC4_DDR DDRC
#define PC4_PWM nullptr
#undef PC5
#define PC5_PIN PINC5
#define PC5_RPORT PINC
#define PC5_WPORT PORTC
#define PC5_DDR DDRC
#define PC5_PWM nullptr
#undef PC6
#define PC6_PIN PINC6
#define PC6_RPORT PINC
#define PC6_WPORT PORTC
#define PC6_DDR DDRC
#define PC6_PWM nullptr
#undef PC7
#define PC7_PIN PINC7
#define PC7_RPORT PINC
#define PC7_WPORT PORTC
#define PC7_DDR DDRC
#define PC7_PWM nullptr
#undef PD0
#define PD0_PIN PIND0
#define PD0_RPORT PIND
#define PD0_WPORT PORTD
#define PD0_DDR DDRD
#define PD0_PWM nullptr
#undef PD1
#define PD1_PIN PIND1
#define PD1_RPORT PIND
#define PD1_WPORT PORTD
#define PD1_DDR DDRD
#define PD1_PWM nullptr
#undef PD2
#define PD2_PIN PIND2
#define PD2_RPORT PIND
#define PD2_WPORT PORTD
#define PD2_DDR DDRD
#define PD2_PWM nullptr
#undef PD3
#define PD3_PIN PIND3
#define PD3_RPORT PIND
#define PD3_WPORT PORTD
#define PD3_DDR DDRD
#define PD3_PWM nullptr
#undef PD4
#define PD4_PIN PIND4
#define PD4_RPORT PIND
#define PD4_WPORT PORTD
#define PD4_DDR DDRD
#define PD4_PWM nullptr
#undef PD5
#define PD5_PIN PIND5
#define PD5_RPORT PIND
#define PD5_WPORT PORTD
#define PD5_DDR DDRD
#define PD5_PWM nullptr
#undef PD6
#define PD6_PIN PIND6
#define PD6_RPORT PIND
#define PD6_WPORT PORTD
#define PD6_DDR DDRD
#define PD6_PWM &OCR2B
#undef PD7
#define PD7_PIN PIND7
#define PD7_RPORT PIND
#define PD7_WPORT PORTD
#define PD7_DDR DDRD
#define PD7_PWM &OCR2A

@ -0,0 +1,697 @@
/**
* 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/>.
*
*/
#pragma once
/**
* Pin mapping (Teensy) for AT90USB646, 647, 1286, and 1287
*
* Logical Pin: 28 29 30 31 32 33 34 35 20 21 22 23 24 25 26 27 10 11 12 13 14 15 16 17 00 01 02 03 04 05 06 07 08 09(46*47)36 37 18 19 38 39 40 41 42 43 44 45
* Port: A0 A1 A2 A3 A4 A5 A6 A7 B0 B1 B2 B3 B4 B5 B6 B7 C0 C1 C2 C3 C4 C5 C6 C7 D0 D1 D2 D3 D4 D5 D6 D7 E0 E1 E2 E3 E4 E5 E6 E7 F0 F1 F2 F3 F4 F5 F6 F7
* The logical pins 46 and 47 are not supported by Teensyduino, but are supported below as E2 and E3
*
* Arduino Pin Layout video: https://youtu.be/rIqeVCX09FA
* AVR alternate pin function overview video: https://youtu.be/1yd8wuI5Plg
*/
#include "../fastio.h"
// SPI
#define SS 20 // 8
#define SCK 21 // 9
#define MOSI 22 // 10
#define MISO 23 // 11
// Digital I/O
#define DIO0_PIN PIND0
#define DIO0_RPORT PIND
#define DIO0_WPORT PORTD
#define DIO0_PWM 0
#define DIO0_DDR DDRD
#define DIO1_PIN PIND1
#define DIO1_RPORT PIND
#define DIO1_WPORT PORTD
#define DIO1_PWM 0
#define DIO1_DDR DDRD
#define DIO2_PIN PIND2
#define DIO2_RPORT PIND
#define DIO2_WPORT PORTD
#define DIO2_PWM 0
#define DIO2_DDR DDRD
#define DIO3_PIN PIND3
#define DIO3_RPORT PIND
#define DIO3_WPORT PORTD
#define DIO3_PWM 0
#define DIO3_DDR DDRD
#define DIO4_PIN PIND4
#define DIO4_RPORT PIND
#define DIO4_WPORT PORTD
#define DIO4_PWM 0
#define DIO4_DDR DDRD
#define DIO5_PIN PIND5
#define DIO5_RPORT PIND
#define DIO5_WPORT PORTD
#define DIO5_PWM 0
#define DIO5_DDR DDRD
#define DIO6_PIN PIND6
#define DIO6_RPORT PIND
#define DIO6_WPORT PORTD
#define DIO6_PWM 0
#define DIO6_DDR DDRD
#define DIO7_PIN PIND7
#define DIO7_RPORT PIND
#define DIO7_WPORT PORTD
#define DIO7_PWM 0
#define DIO7_DDR DDRD
#define DIO8_PIN PINE0
#define DIO8_RPORT PINE
#define DIO8_WPORT PORTE
#define DIO8_PWM 0
#define DIO8_DDR DDRE
#define DIO9_PIN PINE1
#define DIO9_RPORT PINE
#define DIO9_WPORT PORTE
#define DIO9_PWM 0
#define DIO9_DDR DDRE
#define DIO10_PIN PINC0
#define DIO10_RPORT PINC
#define DIO10_WPORT PORTC
#define DIO10_PWM 0
#define DIO10_DDR DDRC
#define DIO11_PIN PINC1
#define DIO11_RPORT PINC
#define DIO11_WPORT PORTC
#define DIO11_PWM 0
#define DIO11_DDR DDRC
#define DIO12_PIN PINC2
#define DIO12_RPORT PINC
#define DIO12_WPORT PORTC
#define DIO12_PWM 0
#define DIO12_DDR DDRC
#define DIO13_PIN PINC3
#define DIO13_RPORT PINC
#define DIO13_WPORT PORTC
#define DIO13_PWM 0
#define DIO13_DDR DDRC
#define DIO14_PIN PINC4
#define DIO14_RPORT PINC
#define DIO14_WPORT PORTC
#define DIO14_PWM 0 // OC3C
#define DIO14_DDR DDRC
#define DIO15_PIN PINC5
#define DIO15_RPORT PINC
#define DIO15_WPORT PORTC
#define DIO15_PWM 0 // OC3B
#define DIO15_DDR DDRC
#define DIO16_PIN PINC6
#define DIO16_RPORT PINC
#define DIO16_WPORT PORTC
#define DIO16_PWM 0 // OC3A
#define DIO16_DDR DDRC
#define DIO17_PIN PINC7
#define DIO17_RPORT PINC
#define DIO17_WPORT PORTC
#define DIO17_PWM 0
#define DIO17_DDR DDRC
#define DIO18_PIN PINE6
#define DIO18_RPORT PINE
#define DIO18_WPORT PORTE
#define DIO18_PWM 0
#define DIO18_DDR DDRE
#define DIO19_PIN PINE7
#define DIO19_RPORT PINE
#define DIO19_WPORT PORTE
#define DIO19_PWM 0
#define DIO19_DDR DDRE
#define DIO20_PIN PINB0
#define DIO20_RPORT PINB
#define DIO20_WPORT PORTB
#define DIO20_PWM 0
#define DIO20_DDR DDRB
#define DIO21_PIN PINB1
#define DIO21_RPORT PINB
#define DIO21_WPORT PORTB
#define DIO21_PWM 0
#define DIO21_DDR DDRB
#define DIO22_PIN PINB2
#define DIO22_RPORT PINB
#define DIO22_WPORT PORTB
#define DIO22_PWM 0
#define DIO22_DDR DDRB
#define DIO23_PIN PINB3
#define DIO23_RPORT PINB
#define DIO23_WPORT PORTB
#define DIO23_PWM 0
#define DIO23_DDR DDRB
#define DIO24_PIN PINB4
#define DIO24_RPORT PINB
#define DIO24_WPORT PORTB
#define DIO24_PWM 0 // OC2A
#define DIO24_DDR DDRB
#define DIO25_PIN PINB5
#define DIO25_RPORT PINB
#define DIO25_WPORT PORTB
#define DIO25_PWM 0 // OC1A
#define DIO25_DDR DDRB
#define DIO26_PIN PINB6
#define DIO26_RPORT PINB
#define DIO26_WPORT PORTB
#define DIO26_PWM 0 // OC1B
#define DIO26_DDR DDRB
#define DIO27_PIN PINB7
#define DIO27_RPORT PINB
#define DIO27_WPORT PORTB
#define DIO27_PWM 0 // OC1C
#define DIO27_DDR DDRB
#define DIO28_PIN PINA0
#define DIO28_RPORT PINA
#define DIO28_WPORT PORTA
#define DIO28_PWM 0
#define DIO28_DDR DDRA
#define DIO29_PIN PINA1
#define DIO29_RPORT PINA
#define DIO29_WPORT PORTA
#define DIO29_PWM 0
#define DIO29_DDR DDRA
#define DIO30_PIN PINA2
#define DIO30_RPORT PINA
#define DIO30_WPORT PORTA
#define DIO30_PWM 0
#define DIO30_DDR DDRA
#define DIO31_PIN PINA3
#define DIO31_RPORT PINA
#define DIO31_WPORT PORTA
#define DIO31_PWM 0
#define DIO31_DDR DDRA
#define DIO32_PIN PINA4
#define DIO32_RPORT PINA
#define DIO32_WPORT PORTA
#define DIO32_PWM 0
#define DIO32_DDR DDRA
#define DIO33_PIN PINA5
#define DIO33_RPORT PINA
#define DIO33_WPORT PORTA
#define DIO33_PWM 0
#define DIO33_DDR DDRA
#define DIO34_PIN PINA6
#define DIO34_RPORT PINA
#define DIO34_WPORT PORTA
#define DIO34_PWM 0
#define DIO34_DDR DDRA
#define DIO35_PIN PINA7
#define DIO35_RPORT PINA
#define DIO35_WPORT PORTA
#define DIO35_PWM 0
#define DIO35_DDR DDRA
#define DIO36_PIN PINE4
#define DIO36_RPORT PINE
#define DIO36_WPORT PORTE
#define DIO36_PWM 0
#define DIO36_DDR DDRE
#define DIO37_PIN PINE5
#define DIO37_RPORT PINE
#define DIO37_WPORT PORTE
#define DIO37_PWM 0
#define DIO37_DDR DDRE
#define DIO38_PIN PINF0
#define DIO38_RPORT PINF
#define DIO38_WPORT PORTF
#define DIO38_PWM 0
#define DIO38_DDR DDRF
#define DIO39_PIN PINF1
#define DIO39_RPORT PINF
#define DIO39_WPORT PORTF
#define DIO39_PWM 0
#define DIO39_DDR DDRF
#define DIO40_PIN PINF2
#define DIO40_RPORT PINF
#define DIO40_WPORT PORTF
#define DIO40_PWM 0
#define DIO40_DDR DDRF
#define DIO41_PIN PINF3
#define DIO41_RPORT PINF
#define DIO41_WPORT PORTF
#define DIO41_PWM 0
#define DIO41_DDR DDRF
#define DIO42_PIN PINF4
#define DIO42_RPORT PINF
#define DIO42_WPORT PORTF
#define DIO42_PWM 0
#define DIO42_DDR DDRF
#define DIO43_PIN PINF5
#define DIO43_RPORT PINF
#define DIO43_WPORT PORTF
#define DIO43_PWM 0
#define DIO43_DDR DDRF
#define DIO44_PIN PINF6
#define DIO44_RPORT PINF
#define DIO44_WPORT PORTF
#define DIO44_PWM 0
#define DIO44_DDR DDRF
#define DIO45_PIN PINF7
#define DIO45_RPORT PINF
#define DIO45_WPORT PORTF
#define DIO45_PWM 0
#define DIO45_DDR DDRF
#define AIO0_PIN PINF0
#define AIO0_RPORT PINF
#define AIO0_WPORT PORTF
#define AIO0_PWM 0
#define AIO0_DDR DDRF
#define AIO1_PIN PINF1
#define AIO1_RPORT PINF
#define AIO1_WPORT PORTF
#define AIO1_PWM 0
#define AIO1_DDR DDRF
#define AIO2_PIN PINF2
#define AIO2_RPORT PINF
#define AIO2_WPORT PORTF
#define AIO2_PWM 0
#define AIO2_DDR DDRF
#define AIO3_PIN PINF3
#define AIO3_RPORT PINF
#define AIO3_WPORT PORTF
#define AIO3_PWM 0
#define AIO3_DDR DDRF
#define AIO4_PIN PINF4
#define AIO4_RPORT PINF
#define AIO4_WPORT PORTF
#define AIO4_PWM 0
#define AIO4_DDR DDRF
#define AIO5_PIN PINF5
#define AIO5_RPORT PINF
#define AIO5_WPORT PORTF
#define AIO5_PWM 0
#define AIO5_DDR DDRF
#define AIO6_PIN PINF6
#define AIO6_RPORT PINF
#define AIO6_WPORT PORTF
#define AIO6_PWM 0
#define AIO6_DDR DDRF
#define AIO7_PIN PINF7
#define AIO7_RPORT PINF
#define AIO7_WPORT PORTF
#define AIO7_PWM 0
#define AIO7_DDR DDRF
//-- Begin not supported by Teensyduino
//-- don't use Arduino functions on these pins pinMode/digitalWrite/etc
#define DIO46_PIN PINE2
#define DIO46_RPORT PINE
#define DIO46_WPORT PORTE
#define DIO46_PWM 0
#define DIO46_DDR DDRE
#define DIO47_PIN PINE3
#define DIO47_RPORT PINE
#define DIO47_WPORT PORTE
#define DIO47_PWM 0
#define DIO47_DDR DDRE
#define TEENSY_E2 46
#define TEENSY_E3 47
//-- end not supported by Teensyduino
#undef PA0
#define PA0_PIN PINA0
#define PA0_RPORT PINA
#define PA0_WPORT PORTA
#define PA0_PWM 0
#define PA0_DDR DDRA
#undef PA1
#define PA1_PIN PINA1
#define PA1_RPORT PINA
#define PA1_WPORT PORTA
#define PA1_PWM 0
#define PA1_DDR DDRA
#undef PA2
#define PA2_PIN PINA2
#define PA2_RPORT PINA
#define PA2_WPORT PORTA
#define PA2_PWM 0
#define PA2_DDR DDRA
#undef PA3
#define PA3_PIN PINA3
#define PA3_RPORT PINA
#define PA3_WPORT PORTA
#define PA3_PWM 0
#define PA3_DDR DDRA
#undef PA4
#define PA4_PIN PINA4
#define PA4_RPORT PINA
#define PA4_WPORT PORTA
#define PA4_PWM 0
#define PA4_DDR DDRA
#undef PA5
#define PA5_PIN PINA5
#define PA5_RPORT PINA
#define PA5_WPORT PORTA
#define PA5_PWM 0
#define PA5_DDR DDRA
#undef PA6
#define PA6_PIN PINA6
#define PA6_RPORT PINA
#define PA6_WPORT PORTA
#define PA6_PWM 0
#define PA6_DDR DDRA
#undef PA7
#define PA7_PIN PINA7
#define PA7_RPORT PINA
#define PA7_WPORT PORTA
#define PA7_PWM 0
#define PA7_DDR DDRA
#undef PB0
#define PB0_PIN PINB0
#define PB0_RPORT PINB
#define PB0_WPORT PORTB
#define PB0_PWM 0
#define PB0_DDR DDRB
#undef PB1
#define PB1_PIN PINB1
#define PB1_RPORT PINB
#define PB1_WPORT PORTB
#define PB1_PWM 0
#define PB1_DDR DDRB
#undef PB2
#define PB2_PIN PINB2
#define PB2_RPORT PINB
#define PB2_WPORT PORTB
#define PB2_PWM 0
#define PB2_DDR DDRB
#undef PB3
#define PB3_PIN PINB3
#define PB3_RPORT PINB
#define PB3_WPORT PORTB
#define PB3_PWM 0
#define PB3_DDR DDRB
#undef PB4
#define PB4_PIN PINB4
#define PB4_RPORT PINB
#define PB4_WPORT PORTB
#define PB4_PWM 0
#define PB4_DDR DDRB
#undef PB5
#define PB5_PIN PINB5
#define PB5_RPORT PINB
#define PB5_WPORT PORTB
#define PB5_PWM 0
#define PB5_DDR DDRB
#undef PB6
#define PB6_PIN PINB6
#define PB6_RPORT PINB
#define PB6_WPORT PORTB
#define PB6_PWM 0
#define PB6_DDR DDRB
#undef PB7
#define PB7_PIN PINB7
#define PB7_RPORT PINB
#define PB7_WPORT PORTB
#define PB7_PWM 0
#define PB7_DDR DDRB
#undef PC0
#define PC0_PIN PINC0
#define PC0_RPORT PINC
#define PC0_WPORT PORTC
#define PC0_PWM 0
#define PC0_DDR DDRC
#undef PC1
#define PC1_PIN PINC1
#define PC1_RPORT PINC
#define PC1_WPORT PORTC
#define PC1_PWM 0
#define PC1_DDR DDRC
#undef PC2
#define PC2_PIN PINC2
#define PC2_RPORT PINC
#define PC2_WPORT PORTC
#define PC2_PWM 0
#define PC2_DDR DDRC
#undef PC3
#define PC3_PIN PINC3
#define PC3_RPORT PINC
#define PC3_WPORT PORTC
#define PC3_PWM 0
#define PC3_DDR DDRC
#undef PC4
#define PC4_PIN PINC4
#define PC4_RPORT PINC
#define PC4_WPORT PORTC
#define PC4_PWM 0
#define PC4_DDR DDRC
#undef PC5
#define PC5_PIN PINC5
#define PC5_RPORT PINC
#define PC5_WPORT PORTC
#define PC5_PWM 0
#define PC5_DDR DDRC
#undef PC6
#define PC6_PIN PINC6
#define PC6_RPORT PINC
#define PC6_WPORT PORTC
#define PC6_PWM 0
#define PC6_DDR DDRC
#undef PC7
#define PC7_PIN PINC7
#define PC7_RPORT PINC
#define PC7_WPORT PORTC
#define PC7_PWM 0
#define PC7_DDR DDRC
#undef PD0
#define PD0_PIN PIND0
#define PD0_RPORT PIND
#define PD0_WPORT PORTD
#define PD0_PWM 0 // OC0B
#define PD0_DDR DDRD
#undef PD1
#define PD1_PIN PIND1
#define PD1_RPORT PIND
#define PD1_WPORT PORTD
#define PD1_PWM 0 // OC2B
#define PD1_DDR DDRD
#undef PD2
#define PD2_PIN PIND2
#define PD2_RPORT PIND
#define PD2_WPORT PORTD
#define PD2_PWM 0
#define PD2_DDR DDRD
#undef PD3
#define PD3_PIN PIND3
#define PD3_RPORT PIND
#define PD3_WPORT PORTD
#define PD3_PWM 0
#define PD3_DDR DDRD
#undef PD4
#define PD4_PIN PIND4
#define PD4_RPORT PIND
#define PD4_WPORT PORTD
#define PD4_PWM 0
#define PD4_DDR DDRD
#undef PD5
#define PD5_PIN PIND5
#define PD5_RPORT PIND
#define PD5_WPORT PORTD
#define PD5_PWM 0
#define PD5_DDR DDRD
#undef PD6
#define PD6_PIN PIND6
#define PD6_RPORT PIND
#define PD6_WPORT PORTD
#define PD6_PWM 0
#define PD6_DDR DDRD
#undef PD7
#define PD7_PIN PIND7
#define PD7_RPORT PIND
#define PD7_WPORT PORTD
#define PD7_PWM 0
#define PD7_DDR DDRD
#undef PE0
#define PE0_PIN PINE0
#define PE0_RPORT PINE
#define PE0_WPORT PORTE
#define PE0_PWM 0
#define PE0_DDR DDRE
#undef PE1
#define PE1_PIN PINE1
#define PE1_RPORT PINE
#define PE1_WPORT PORTE
#define PE1_PWM 0
#define PE1_DDR DDRE
#undef PE2
#define PE2_PIN PINE2
#define PE2_RPORT PINE
#define PE2_WPORT PORTE
#define PE2_PWM 0
#define PE2_DDR DDRE
#undef PE3
#define PE3_PIN PINE3
#define PE3_RPORT PINE
#define PE3_WPORT PORTE
#define PE3_PWM 0
#define PE3_DDR DDRE
#undef PE4
#define PE4_PIN PINE4
#define PE4_RPORT PINE
#define PE4_WPORT PORTE
#define PE4_PWM 0
#define PE4_DDR DDRE
#undef PE5
#define PE5_PIN PINE5
#define PE5_RPORT PINE
#define PE5_WPORT PORTE
#define PE5_PWM 0
#define PE5_DDR DDRE
#undef PE6
#define PE6_PIN PINE6
#define PE6_RPORT PINE
#define PE6_WPORT PORTE
#define PE6_PWM 0
#define PE6_DDR DDRE
#undef PE7
#define PE7_PIN PINE7
#define PE7_RPORT PINE
#define PE7_WPORT PORTE
#define PE7_PWM 0
#define PE7_DDR DDRE
#undef PF0
#define PF0_PIN PINF0
#define PF0_RPORT PINF
#define PF0_WPORT PORTF
#define PF0_PWM 0
#define PF0_DDR DDRF
#undef PF1
#define PF1_PIN PINF1
#define PF1_RPORT PINF
#define PF1_WPORT PORTF
#define PF1_PWM 0
#define PF1_DDR DDRF
#undef PF2
#define PF2_PIN PINF2
#define PF2_RPORT PINF
#define PF2_WPORT PORTF
#define PF2_PWM 0
#define PF2_DDR DDRF
#undef PF3
#define PF3_PIN PINF3
#define PF3_RPORT PINF
#define PF3_WPORT PORTF
#define PF3_PWM 0
#define PF3_DDR DDRF
#undef PF4
#define PF4_PIN PINF4
#define PF4_RPORT PINF
#define PF4_WPORT PORTF
#define PF4_PWM 0
#define PF4_DDR DDRF
#undef PF5
#define PF5_PIN PINF5
#define PF5_RPORT PINF
#define PF5_WPORT PORTF
#define PF5_PWM 0
#define PF5_DDR DDRF
#undef PF6
#define PF6_PIN PINF6
#define PF6_RPORT PINF
#define PF6_WPORT PORTF
#define PF6_PWM 0
#define PF6_DDR DDRF
#undef PF7
#define PF7_PIN PINF7
#define PF7_RPORT PINF
#define PF7_WPORT PORTF
#define PF7_PWM 0
#define PF7_DDR DDRF
/**
* Some of the pin mapping functions of the Teensduino extension to the Arduino IDE
* do not function the same as the other Arduino extensions.
*/
//digitalPinToTimer(pin) function works like Arduino but Timers are not defined
#define TIMER0B 1
#define TIMER1A 7
#define TIMER1B 8
#define TIMER1C 9
#define TIMER2A 6
#define TIMER2B 2
#define TIMER3A 5
#define TIMER3B 4
#define TIMER3C 3

@ -0,0 +1,26 @@
/**
* 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/>.
*
*/
#pragma once
#ifndef SERIAL_PORT
#define SERIAL_PORT 0
#endif

@ -0,0 +1,22 @@
/**
* 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/>.
*
*/
#pragma once

@ -0,0 +1,22 @@
/**
* 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/>.
*
*/
#pragma once

@ -0,0 +1,115 @@
/**
* 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/>.
*
*/
#pragma once
/**
* Test AVR-specific configuration values for errors at compile-time.
*/
#if HAS_SPI_TFT || HAS_FSMC_TFT
#error "Sorry! TFT displays are not available for HAL/AVR."
#endif
/**
* Check for common serial pin conflicts
*/
#define CHECK_SERIAL_PIN(N) ( \
X_STOP_PIN == N || Y_STOP_PIN == N || Z_STOP_PIN == N \
|| X_MIN_PIN == N || Y_MIN_PIN == N || Z_MIN_PIN == N \
|| X_MAX_PIN == N || Y_MAX_PIN == N || Z_MAX_PIN == N \
|| X_STEP_PIN == N || Y_STEP_PIN == N || Z_STEP_PIN == N \
|| X_DIR_PIN == N || Y_DIR_PIN == N || Z_DIR_PIN == N \
|| X_ENA_PIN == N || Y_ENA_PIN == N || Z_ENA_PIN == N \
|| BTN_EN1 == N || BTN_EN2 == N || LCD_PINS_EN == 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
*/
#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."
#endif
/**
* Checks for SOFT PWM
*/
#if HAS_FAN0 && FAN0_PIN == 9 && DISABLED(FAN_SOFT_PWM) && ENABLED(SPEAKER)
#error "FAN0_PIN 9 Hardware PWM uses Timer 2 which conflicts with Arduino AVR Tone Timer (for SPEAKER)."
#error "Disable SPEAKER or enable FAN_SOFT_PWM."
#endif
/**
* Sanity checks for Spindle / Laser PWM
*/
#if ENABLED(SPINDLE_LASER_USE_PWM)
#include "../ServoTimers.h" // Needed to check timer availability (_useTimer3)
#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."
#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."
#endif
#elif SPINDLE_LASER_FREQUENCY
#error "SPINDLE_LASER_FREQUENCY requires SPINDLE_LASER_USE_PWM."
#endif
/**
* The Trinamic library includes SoftwareSerial.h, leading to a compile error.
*/
#if ALL(HAS_TRINAMIC_CONFIG, ENDSTOP_INTERRUPTS_FEATURE)
#error "TMCStepper includes SoftwareSerial.h which is incompatible with ENDSTOP_INTERRUPTS_FEATURE. Disable ENDSTOP_INTERRUPTS_FEATURE to continue."
#endif
#if ALL(HAS_TMC_SW_SERIAL, MONITOR_DRIVER_STATUS)
#error "MONITOR_DRIVER_STATUS causes performance issues when used with SoftwareSerial-connected drivers. Disable MONITOR_DRIVER_STATUS or use hardware serial to continue."
#endif
/**
* 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

@ -0,0 +1,109 @@
/**
* 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/>.
*
*/
#pragma once
/**
* Optimized math functions for AVR
*/
// intRes = longIn1 * longIn2 >> 24
// uses:
// r1, r0 for the result of mul.
// [tmp1] to store 0.
// [tmp2] to store bits 16-23 of the 56 bit result. The top bit of [tmp2] is used for rounding.
// Note that the lower two bytes and the upper two bytes of the 56 bit result are not calculated.
// This can cause the result to be out by one as the lower bytes may cause carries into the upper ones.
// [intRes] (A B) is bits 24-39 and is the returned value.
// [longIn1] (C B A) is a 24 bit parameter.
// [longIn2] (D C B A) is a 32 bit parameter.
//
FORCE_INLINE static uint16_t MultiU24X32toH16(uint32_t longIn1, uint32_t longIn2) {
uint8_t tmp1;
uint8_t tmp2;
uint16_t intRes;
__asm__ __volatile__(
A("clr %[tmp1]")
A("mul %A[longIn1], %B[longIn2]")
A("mov %[tmp2], r1")
A("mul %B[longIn1], %C[longIn2]")
A("movw %A[intRes], r0")
A("mul %C[longIn1], %C[longIn2]")
A("add %B[intRes], r0")
A("mul %C[longIn1], %B[longIn2]")
A("add %A[intRes], r0")
A("adc %B[intRes], r1")
A("mul %A[longIn1], %C[longIn2]")
A("add %[tmp2], r0")
A("adc %A[intRes], r1")
A("adc %B[intRes], %[tmp1]")
A("mul %B[longIn1], %B[longIn2]")
A("add %[tmp2], r0")
A("adc %A[intRes], r1")
A("adc %B[intRes], %[tmp1]")
A("mul %C[longIn1], %A[longIn2]")
A("add %[tmp2], r0")
A("adc %A[intRes], r1")
A("adc %B[intRes], %[tmp1]")
A("mul %B[longIn1], %A[longIn2]")
A("add %[tmp2], r1")
A("adc %A[intRes], %[tmp1]")
A("adc %B[intRes], %[tmp1]")
A("mul %D[longIn2], %A[longIn1]")
A("lsl %[tmp2]")
A("adc %A[intRes], r0")
A("adc %B[intRes], r1")
A("mul %D[longIn2], %B[longIn1]")
A("add %B[intRes], r0")
A("clr r1")
: [intRes] "=&r" (intRes),
[tmp1] "=&r" (tmp1),
[tmp2] "=&r" (tmp2)
: [longIn1] "d" (longIn1),
[longIn2] "d" (longIn2)
: "cc"
);
return intRes;
}
// charRes = charIn1 * charIn2 >> 8
// uses:
// r1, r0 for the result of mul. After the mul, r0 holds bits 0-7 of the 16 bit result,
// and the top bit of r0 is used for rounding.
// [charRes] is bits 8-15 and is the returned value.
// [charIn1] is an 8 bit parameter.
// [charIn2] is an 8 bit parameter.
//
FORCE_INLINE static uint8_t MultiU8X8toH8(uint8_t charIn1, uint8_t charIn2) {
uint8_t charRes;
__asm__ __volatile__ (
A("mul %[charIn1], %[charIn2]")
A("mov %[charRes], r1")
A("clr r1")
A("lsl r0")
A("adc %[charRes], r1")
: [charRes] "=&r" (charRes)
: [charIn1] "d" (charIn1),
[charIn2] "d" (charIn2)
: "cc"
);
return charRes;
}

@ -0,0 +1,395 @@
/**
* 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/>.
*
*/
#pragma once
/**
* PWM print routines for Atmel 8 bit AVR CPUs
*/
#include "../../inc/MarlinConfig.h"
#define NUMBER_PINS_TOTAL NUM_DIGITAL_PINS
#if MB(BQ_ZUM_MEGA_3D, MIGHTYBOARD_REVE, MINIRAMBO, SCOOVO_X9H, TRIGORILLA_14)
#define AVR_ATmega2560_FAMILY_PLUS_70 1
#endif
#if AVR_AT90USB1286_FAMILY
// Working with Teensyduino extension so need to re-define some things
#include "pinsDebug_Teensyduino.h"
// Can't use the "digitalPinToPort" function from the Teensyduino type IDEs
// portModeRegister takes a different argument
#define digitalPinToTimer_DEBUG(p) digitalPinToTimer(p)
#define digitalPinToBitMask_DEBUG(p) digitalPinToBitMask(p)
#define digitalPinToPort_DEBUG(p) digitalPinToPort(p)
#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
#include "pinsDebug_plus_70.h"
#define digitalPinToTimer_DEBUG(p) digitalPinToTimer_plus_70(p)
#define digitalPinToBitMask_DEBUG(p) digitalPinToBitMask_plus_70(p)
#define digitalPinToPort_DEBUG(p) digitalPinToPort_plus_70(p)
bool GET_PINMODE(int8_t pin) {return *portModeRegister(digitalPinToPort_DEBUG(pin)) & digitalPinToBitMask_DEBUG(pin); }
#else
#define digitalPinToTimer_DEBUG(p) digitalPinToTimer(p)
#define digitalPinToBitMask_DEBUG(p) digitalPinToBitMask(p)
#define digitalPinToPort_DEBUG(p) digitalPinToPort(p)
bool GET_PINMODE(int8_t pin) {return *portModeRegister(digitalPinToPort_DEBUG(pin)) & digitalPinToBitMask_DEBUG(pin); }
#define GET_ARRAY_PIN(p) pgm_read_byte(&pin_array[p].pin)
#endif
#define VALID_PIN(pin) (pin >= 0 && pin < NUM_DIGITAL_PINS ? 1 : 0)
#if AVR_ATmega1284_FAMILY
#define IS_ANALOG(P) WITHIN(P, analogInputToDigitalPin(7), analogInputToDigitalPin(0))
#define DIGITAL_PIN_TO_ANALOG_PIN(P) int(IS_ANALOG(P) ? (P) - analogInputToDigitalPin(7) : -1)
#else
#define _ANALOG1(P) WITHIN(P, analogInputToDigitalPin(0), analogInputToDigitalPin(7))
#define _ANALOG2(P) WITHIN(P, analogInputToDigitalPin(8), analogInputToDigitalPin(15))
#define IS_ANALOG(P) (_ANALOG1(P) || _ANALOG2(P))
#define DIGITAL_PIN_TO_ANALOG_PIN(P) int(_ANALOG1(P) ? (P) - analogInputToDigitalPin(0) : _ANALOG2(P) ? (P) - analogInputToDigitalPin(8) + 8 : -1)
#endif
#define GET_ARRAY_PIN(p) pgm_read_byte(&pin_array[p].pin)
#define MULTI_NAME_PAD 26 // space needed to be pretty if not first name assigned to a pin
void PRINT_ARRAY_NAME(uint8_t x) {
PGM_P const name_mem_pointer = (PGM_P)pgm_read_ptr(&pin_array[x].name);
for (uint8_t y = 0; y < MAX_NAME_LENGTH; ++y) {
char temp_char = pgm_read_byte(name_mem_pointer + y);
if (temp_char != 0)
SERIAL_CHAR(temp_char);
else {
for (uint8_t i = 0; i < MAX_NAME_LENGTH - y; ++i) SERIAL_CHAR(' ');
break;
}
}
}
#define GET_ARRAY_IS_DIGITAL(x) pgm_read_byte(&pin_array[x].is_digital)
#if defined(__AVR_ATmega1284P__) // 1284 IDE extensions set this to the number of
#undef NUM_DIGITAL_PINS // digital only pins while all other CPUs have it
#define NUM_DIGITAL_PINS 32 // set to digital only + digital/analog
#endif
#define PWM_PRINT(V) do{ sprintf_P(buffer, PSTR("PWM: %4d"), V); SERIAL_ECHO(buffer); }while(0)
#define PWM_CASE(N,Z) \
case TIMER##N##Z: \
if (TCCR##N##A & (_BV(COM##N##Z##1) | _BV(COM##N##Z##0))) { \
PWM_PRINT(OCR##N##Z); \
return true; \
} else return false
#define ABTEST(N) defined(TCCR##N##A) && defined(COM##N##A1)
/**
* Print a pin's PWM status.
* Return true if it's currently a PWM pin.
*/
bool pwm_status(uint8_t pin) {
char buffer[20]; // for the sprintf statements
switch (digitalPinToTimer_DEBUG(pin)) {
#if ABTEST(0)
#ifdef TIMER0A
#if !AVR_AT90USB1286_FAMILY // not available in Teensyduino type IDEs
PWM_CASE(0, A);
#endif
#endif
PWM_CASE(0, B);
#endif
#if ABTEST(1)
PWM_CASE(1, A);
PWM_CASE(1, B);
#if defined(COM1C1) && defined(TIMER1C)
PWM_CASE(1, C);
#endif
#endif
#if ABTEST(2)
PWM_CASE(2, A);
PWM_CASE(2, B);
#endif
#if ABTEST(3)
PWM_CASE(3, A);
PWM_CASE(3, B);
#ifdef COM3C1
PWM_CASE(3, C);
#endif
#endif
#ifdef TCCR4A
PWM_CASE(4, A);
PWM_CASE(4, B);
PWM_CASE(4, C);
#endif
#if ABTEST(5)
PWM_CASE(5, A);
PWM_CASE(5, B);
PWM_CASE(5, C);
#endif
case NOT_ON_TIMER:
default:
return false;
}
SERIAL_ECHO_SP(2);
} // pwm_status
const volatile uint8_t* const PWM_other[][3] PROGMEM = {
{ &TCCR0A, &TCCR0B, &TIMSK0 },
{ &TCCR1A, &TCCR1B, &TIMSK1 },
#if ABTEST(2)
{ &TCCR2A, &TCCR2B, &TIMSK2 },
#endif
#if ABTEST(3)
{ &TCCR3A, &TCCR3B, &TIMSK3 },
#endif
#ifdef TCCR4A
{ &TCCR4A, &TCCR4B, &TIMSK4 },
#endif
#if ABTEST(5)
{ &TCCR5A, &TCCR5B, &TIMSK5 },
#endif
};
const volatile uint8_t* const PWM_OCR[][3] PROGMEM = {
#ifdef TIMER0A
{ &OCR0A, &OCR0B, 0 },
#else
{ 0, &OCR0B, 0 },
#endif
#if defined(COM1C1) && defined(TIMER1C)
{ (const uint8_t*)&OCR1A, (const uint8_t*)&OCR1B, (const uint8_t*)&OCR1C },
#else
{ (const uint8_t*)&OCR1A, (const uint8_t*)&OCR1B, 0 },
#endif
#if ABTEST(2)
{ &OCR2A, &OCR2B, 0 },
#endif
#if ABTEST(3)
#ifdef COM3C1
{ (const uint8_t*)&OCR3A, (const uint8_t*)&OCR3B, (const uint8_t*)&OCR3C },
#else
{ (const uint8_t*)&OCR3A, (const uint8_t*)&OCR3B, 0 },
#endif
#endif
#ifdef TCCR4A
{ (const uint8_t*)&OCR4A, (const uint8_t*)&OCR4B, (const uint8_t*)&OCR4C },
#endif
#if ABTEST(5)
{ (const uint8_t*)&OCR5A, (const uint8_t*)&OCR5B, (const uint8_t*)&OCR5C },
#endif
};
#define TCCR_A(T) pgm_read_word(&PWM_other[T][0])
#define TCCR_B(T) pgm_read_word(&PWM_other[T][1])
#define TIMSK(T) pgm_read_word(&PWM_other[T][2])
#define CS_0 0
#define CS_1 1
#define CS_2 2
#define WGM_0 0
#define WGM_1 1
#define WGM_2 3
#define WGM_3 4
#define TOIE 0
#define OCR_VAL(T, L) pgm_read_word(&PWM_OCR[T][L])
void err_is_counter() { SERIAL_ECHOPGM(" non-standard PWM mode"); }
void err_is_interrupt() { SERIAL_ECHOPGM(" compare interrupt enabled"); }
void err_prob_interrupt() { SERIAL_ECHOPGM(" overflow interrupt enabled"); }
void print_is_also_tied() { SERIAL_ECHOPGM(" is also tied to this pin"); SERIAL_ECHO_SP(14); }
void com_print(const uint8_t N, const uint8_t Z) {
const uint8_t *TCCRA = (uint8_t*)TCCR_A(N);
SERIAL_ECHOPGM(" COM", AS_DIGIT(N));
SERIAL_CHAR(Z);
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
char buffer[20]; // for the sprintf statements
const uint8_t *TCCRB = (uint8_t*)TCCR_B(T),
*TCCRA = (uint8_t*)TCCR_A(T);
uint8_t WGM = (((*TCCRB & _BV(WGM_2)) >> 1) | (*TCCRA & (_BV(WGM_0) | _BV(WGM_1))));
if (N == 4) WGM |= ((*TCCRB & _BV(WGM_3)) >> 1);
SERIAL_ECHOPGM(" TIMER", AS_DIGIT(T));
SERIAL_CHAR(L);
SERIAL_ECHO_SP(3);
if (N == 3) {
const uint8_t *OCRVAL8 = (uint8_t*)OCR_VAL(T, L - 'A');
PWM_PRINT(*OCRVAL8);
}
else {
const uint16_t *OCRVAL16 = (uint16_t*)OCR_VAL(T, L - 'A');
PWM_PRINT(*OCRVAL16);
}
SERIAL_ECHOPGM(" WGM: ", WGM);
com_print(T,L);
SERIAL_ECHOPGM(" CS: ", (*TCCRB & (_BV(CS_0) | _BV(CS_1) | _BV(CS_2)) ));
SERIAL_ECHOPGM(" TCCR", AS_DIGIT(T), "A: ", *TCCRA);
SERIAL_ECHOPGM(" TCCR", AS_DIGIT(T), "B: ", *TCCRB);
const uint8_t *TMSK = (uint8_t*)TIMSK(T);
SERIAL_ECHOPGM(" TIMSK", AS_DIGIT(T), ": ", *TMSK);
const uint8_t OCIE = L - 'A' + 1;
if (N == 3) { if (WGM == 0 || WGM == 2 || WGM == 4 || WGM == 6) err_is_counter(); }
else { if (WGM == 0 || WGM == 4 || WGM == 12 || WGM == 13) err_is_counter(); }
if (TEST(*TMSK, OCIE)) err_is_interrupt();
if (TEST(*TMSK, TOIE)) err_prob_interrupt();
}
void pwm_details(uint8_t pin) {
switch (digitalPinToTimer_DEBUG(pin)) {
#if ABTEST(0)
#ifdef TIMER0A
#if !AVR_AT90USB1286_FAMILY // not available in Teensyduino type IDEs
case TIMER0A: timer_prefix(0, 'A', 3); break;
#endif
#endif
case TIMER0B: timer_prefix(0, 'B', 3); break;
#endif
#if ABTEST(1)
case TIMER1A: timer_prefix(1, 'A', 4); break;
case TIMER1B: timer_prefix(1, 'B', 4); break;
#if defined(COM1C1) && defined(TIMER1C)
case TIMER1C: timer_prefix(1, 'C', 4); break;
#endif
#endif
#if ABTEST(2)
case TIMER2A: timer_prefix(2, 'A', 3); break;
case TIMER2B: timer_prefix(2, 'B', 3); break;
#endif
#if ABTEST(3)
case TIMER3A: timer_prefix(3, 'A', 4); break;
case TIMER3B: timer_prefix(3, 'B', 4); break;
#ifdef COM3C1
case TIMER3C: timer_prefix(3, 'C', 4); break;
#endif
#endif
#ifdef TCCR4A
case TIMER4A: timer_prefix(4, 'A', 4); break;
case TIMER4B: timer_prefix(4, 'B', 4); break;
case TIMER4C: timer_prefix(4, 'C', 4); break;
#endif
#if ABTEST(5)
case TIMER5A: timer_prefix(5, 'A', 4); break;
case TIMER5B: timer_prefix(5, 'B', 4); break;
case TIMER5C: timer_prefix(5, 'C', 4); break;
#endif
case NOT_ON_TIMER: break;
}
SERIAL_ECHOPGM(" ");
// on pins that have two PWMs, print info on second PWM
#if AVR_ATmega2560_FAMILY || AVR_AT90USB1286_FAMILY
// looking for port B7 - PWMs 0A and 1C
if (digitalPinToPort_DEBUG(pin) == 'B' - 64 && 0x80 == digitalPinToBitMask_DEBUG(pin)) {
#if !AVR_AT90USB1286_FAMILY
SERIAL_ECHOPGM("\n .");
SERIAL_ECHO_SP(18);
SERIAL_ECHOPGM("TIMER1C");
print_is_also_tied();
timer_prefix(1, 'C', 4);
#else
SERIAL_ECHOPGM("\n .");
SERIAL_ECHO_SP(18);
SERIAL_ECHOPGM("TIMER0A");
print_is_also_tied();
timer_prefix(0, 'A', 3);
#endif
}
#else
UNUSED(print_is_also_tied);
#endif
} // pwm_details
#ifndef digitalRead_mod // Use Teensyduino's version of digitalRead - it doesn't disable the PWMs
int digitalRead_mod(const pin_t pin) { // same as digitalRead except the PWM stop section has been removed
const uint8_t port = digitalPinToPort_DEBUG(pin);
return (port != NOT_A_PIN) && (*portInputRegister(port) & digitalPinToBitMask_DEBUG(pin)) ? HIGH : LOW;
}
#endif
void print_port(const pin_t pin) { // print port number
#ifdef digitalPinToPort_DEBUG
uint8_t x;
SERIAL_ECHOPGM(" Port: ");
#if AVR_AT90USB1286_FAMILY
x = (pin == 46 || pin == 47) ? 'E' : digitalPinToPort_DEBUG(pin) + 64;
#else
x = digitalPinToPort_DEBUG(pin) + 64;
#endif
SERIAL_CHAR(x);
#if AVR_AT90USB1286_FAMILY
if (pin == 46)
x = '2';
else if (pin == 47)
x = '3';
else {
uint8_t temp = digitalPinToBitMask_DEBUG(pin);
for (x = '0'; x < '9' && temp != 1; x++) temp >>= 1;
}
#else
uint8_t temp = digitalPinToBitMask_DEBUG(pin);
for (x = '0'; x < '9' && temp != 1; x++) temp >>= 1;
#endif
SERIAL_CHAR(x);
#else
SERIAL_ECHO_SP(10);
#endif
}
#define PRINT_PIN(p) do{ sprintf_P(buffer, PSTR("%3d "), p); SERIAL_ECHO(buffer); }while(0)
#define PRINT_PIN_ANALOG(p) do{ sprintf_P(buffer, PSTR(" (A%2d) "), DIGITAL_PIN_TO_ANALOG_PIN(pin)); SERIAL_ECHO(buffer); }while(0)
#undef ABTEST

@ -0,0 +1,108 @@
/**
* 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/>.
*
*/
#pragma once
//
// Some of the pin mapping functions of the Arduino IDE Teensduino extension
// function differently from other Arduino extensions.
//
#define TEENSYDUINO_IDE
//digitalPinToTimer(pin) function works like Arduino but Timers are not defined
#define TIMER0B 1
#define TIMER1A 7
#define TIMER1B 8
#define TIMER1C 9
#define TIMER2A 6
#define TIMER2B 2
#define TIMER3A 5
#define TIMER3B 4
#define TIMER3C 3
// digitalPinToPort function just returns the pin number so need to create our own
#define PA 1
#define PB 2
#define PC 3
#define PD 4
#define PE 5
#define PF 6
const uint8_t PROGMEM digital_pin_to_port_PGM[] = {
PD, // 0 - PD0 - INT0 - PWM
PD, // 1 - PD1 - INT1 - PWM
PD, // 2 - PD2 - INT2 - RX
PD, // 3 - PD3 - INT3 - TX
PD, // 4 - PD4
PD, // 5 - PD5
PD, // 6 - PD6
PD, // 7 - PD7
PE, // 8 - PE0
PE, // 9 - PE1
PC, // 10 - PC0
PC, // 11 - PC1
PC, // 12 - PC2
PC, // 13 - PC3
PC, // 14 - PC4 - PWM
PC, // 15 - PC5 - PWM
PC, // 16 - PC6 - PWM
PC, // 17 - PC7
PE, // 18 - PE6 - INT6
PE, // 19 - PE7 - INT7
PB, // 20 - PB0
PB, // 21 - PB1
PB, // 22 - PB2
PB, // 23 - PB3
PB, // 24 - PB4 - PWM
PB, // 25 - PB5 - PWM
PB, // 26 - PB6 - PWM
PB, // 27 - PB7 - PWM
PA, // 28 - PA0
PA, // 29 - PA1
PA, // 30 - PA2
PA, // 31 - PA3
PA, // 32 - PA4
PA, // 33 - PA5
PA, // 34 - PA6
PA, // 35 - PA7
PE, // 36 - PE4 - INT4
PE, // 37 - PE5 - INT5
PF, // 38 - PF0 - A0
PF, // 39 - PF1 - A1
PF, // 40 - PF2 - A2
PF, // 41 - PF3 - A3
PF, // 42 - PF4 - A4
PF, // 43 - PF5 - A5
PF, // 44 - PF6 - A6
PF, // 45 - PF7 - A7
PE, // 46 - PE2 (not defined in teensyduino)
PE, // 47 - PE3 (not defined in teensyduino)
};
#define digitalPinToPort(P) pgm_read_byte(digital_pin_to_port_PGM[P])
// digitalPinToBitMask(pin) is OK
#define digitalRead_mod(p) extDigitalRead(p) // Teensyduino's version of digitalRead doesn't
// disable the PWMs so we can use it as is
// portModeRegister(pin) is OK

@ -0,0 +1,331 @@
/**
* 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/>.
*
*/
#pragma once
/**
* Structures for 2560 family boards that use more than 70 pins
*/
#if MB(BQ_ZUM_MEGA_3D, MINIRAMBO, SCOOVO_X9H, TRIGORILLA_14)
#undef NUM_DIGITAL_PINS
#define NUM_DIGITAL_PINS 85
#elif MB(MIGHTYBOARD_REVE)
#undef NUM_DIGITAL_PINS
#define NUM_DIGITAL_PINS 80
#endif
#define PA 1
#define PB 2
#define PC 3
#define PD 4
#define PE 5
#define PF 6
#define PG 7
#define PH 8
#define PJ 10
#define PK 11
#define PL 12
const uint8_t PROGMEM digital_pin_to_port_PGM_plus_70[] = {
// PORTLIST
// ------------------------
PE , // PE 0 ** 0 ** USART0_RX
PE , // PE 1 ** 1 ** USART0_TX
PE , // PE 4 ** 2 ** PWM2
PE , // PE 5 ** 3 ** PWM3
PG , // PG 5 ** 4 ** PWM4
PE , // PE 3 ** 5 ** PWM5
PH , // PH 3 ** 6 ** PWM6
PH , // PH 4 ** 7 ** PWM7
PH , // PH 5 ** 8 ** PWM8
PH , // PH 6 ** 9 ** PWM9
PB , // PB 4 ** 10 ** PWM10
PB , // PB 5 ** 11 ** PWM11
PB , // PB 6 ** 12 ** PWM12
PB , // PB 7 ** 13 ** PWM13
PJ , // PJ 1 ** 14 ** USART3_TX
PJ , // PJ 0 ** 15 ** USART3_RX
PH , // PH 1 ** 16 ** USART2_TX
PH , // PH 0 ** 17 ** USART2_RX
PD , // PD 3 ** 18 ** USART1_TX
PD , // PD 2 ** 19 ** USART1_RX
PD , // PD 1 ** 20 ** I2C_SDA
PD , // PD 0 ** 21 ** I2C_SCL
PA , // PA 0 ** 22 ** D22
PA , // PA 1 ** 23 ** D23
PA , // PA 2 ** 24 ** D24
PA , // PA 3 ** 25 ** D25
PA , // PA 4 ** 26 ** D26
PA , // PA 5 ** 27 ** D27
PA , // PA 6 ** 28 ** D28
PA , // PA 7 ** 29 ** D29
PC , // PC 7 ** 30 ** D30
PC , // PC 6 ** 31 ** D31
PC , // PC 5 ** 32 ** D32
PC , // PC 4 ** 33 ** D33
PC , // PC 3 ** 34 ** D34
PC , // PC 2 ** 35 ** D35
PC , // PC 1 ** 36 ** D36
PC , // PC 0 ** 37 ** D37
PD , // PD 7 ** 38 ** D38
PG , // PG 2 ** 39 ** D39
PG , // PG 1 ** 40 ** D40
PG , // PG 0 ** 41 ** D41
PL , // PL 7 ** 42 ** D42
PL , // PL 6 ** 43 ** D43
PL , // PL 5 ** 44 ** D44
PL , // PL 4 ** 45 ** D45
PL , // PL 3 ** 46 ** D46
PL , // PL 2 ** 47 ** D47
PL , // PL 1 ** 48 ** D48
PL , // PL 0 ** 49 ** D49
PB , // PB 3 ** 50 ** SPI_MISO
PB , // PB 2 ** 51 ** SPI_MOSI
PB , // PB 1 ** 52 ** SPI_SCK
PB , // PB 0 ** 53 ** SPI_SS
PF , // PF 0 ** 54 ** A0
PF , // PF 1 ** 55 ** A1
PF , // PF 2 ** 56 ** A2
PF , // PF 3 ** 57 ** A3
PF , // PF 4 ** 58 ** A4
PF , // PF 5 ** 59 ** A5
PF , // PF 6 ** 60 ** A6
PF , // PF 7 ** 61 ** A7
PK , // PK 0 ** 62 ** A8
PK , // PK 1 ** 63 ** A9
PK , // PK 2 ** 64 ** A10
PK , // PK 3 ** 65 ** A11
PK , // PK 4 ** 66 ** A12
PK , // PK 5 ** 67 ** A13
PK , // PK 6 ** 68 ** A14
PK , // PK 7 ** 69 ** A15
PG , // PG 4 ** 70 **
PG , // PG 3 ** 71 **
PJ , // PJ 2 ** 72 **
PJ , // PJ 3 ** 73 **
PJ , // PJ 7 ** 74 **
PJ , // PJ 4 ** 75 **
PJ , // PJ 5 ** 76 **
PJ , // PJ 6 ** 77 **
PE , // PE 2 ** 78 **
PE , // PE 6 ** 79 **
PE , // PE 7 ** 80 **
PD , // PD 4 ** 81 **
PD , // PD 5 ** 82 **
PD , // PD 6 ** 83 **
PH , // PH 2 ** 84 **
PH , // PH 7 ** 85 **
};
#define digitalPinToPort_plus_70(P) ( pgm_read_byte( digital_pin_to_port_PGM_plus_70 + (P) ) )
const uint8_t PROGMEM digital_pin_to_bit_mask_PGM_plus_70[] = {
// PIN IN PORT
// ------------------------
_BV( 0 ) , // PE 0 ** 0 ** USART0_RX
_BV( 1 ) , // PE 1 ** 1 ** USART0_TX
_BV( 4 ) , // PE 4 ** 2 ** PWM2
_BV( 5 ) , // PE 5 ** 3 ** PWM3
_BV( 5 ) , // PG 5 ** 4 ** PWM4
_BV( 3 ) , // PE 3 ** 5 ** PWM5
_BV( 3 ) , // PH 3 ** 6 ** PWM6
_BV( 4 ) , // PH 4 ** 7 ** PWM7
_BV( 5 ) , // PH 5 ** 8 ** PWM8
_BV( 6 ) , // PH 6 ** 9 ** PWM9
_BV( 4 ) , // PB 4 ** 10 ** PWM10
_BV( 5 ) , // PB 5 ** 11 ** PWM11
_BV( 6 ) , // PB 6 ** 12 ** PWM12
_BV( 7 ) , // PB 7 ** 13 ** PWM13
_BV( 1 ) , // PJ 1 ** 14 ** USART3_TX
_BV( 0 ) , // PJ 0 ** 15 ** USART3_RX
_BV( 1 ) , // PH 1 ** 16 ** USART2_TX
_BV( 0 ) , // PH 0 ** 17 ** USART2_RX
_BV( 3 ) , // PD 3 ** 18 ** USART1_TX
_BV( 2 ) , // PD 2 ** 19 ** USART1_RX
_BV( 1 ) , // PD 1 ** 20 ** I2C_SDA
_BV( 0 ) , // PD 0 ** 21 ** I2C_SCL
_BV( 0 ) , // PA 0 ** 22 ** D22
_BV( 1 ) , // PA 1 ** 23 ** D23
_BV( 2 ) , // PA 2 ** 24 ** D24
_BV( 3 ) , // PA 3 ** 25 ** D25
_BV( 4 ) , // PA 4 ** 26 ** D26
_BV( 5 ) , // PA 5 ** 27 ** D27
_BV( 6 ) , // PA 6 ** 28 ** D28
_BV( 7 ) , // PA 7 ** 29 ** D29
_BV( 7 ) , // PC 7 ** 30 ** D30
_BV( 6 ) , // PC 6 ** 31 ** D31
_BV( 5 ) , // PC 5 ** 32 ** D32
_BV( 4 ) , // PC 4 ** 33 ** D33
_BV( 3 ) , // PC 3 ** 34 ** D34
_BV( 2 ) , // PC 2 ** 35 ** D35
_BV( 1 ) , // PC 1 ** 36 ** D36
_BV( 0 ) , // PC 0 ** 37 ** D37
_BV( 7 ) , // PD 7 ** 38 ** D38
_BV( 2 ) , // PG 2 ** 39 ** D39
_BV( 1 ) , // PG 1 ** 40 ** D40
_BV( 0 ) , // PG 0 ** 41 ** D41
_BV( 7 ) , // PL 7 ** 42 ** D42
_BV( 6 ) , // PL 6 ** 43 ** D43
_BV( 5 ) , // PL 5 ** 44 ** D44
_BV( 4 ) , // PL 4 ** 45 ** D45
_BV( 3 ) , // PL 3 ** 46 ** D46
_BV( 2 ) , // PL 2 ** 47 ** D47
_BV( 1 ) , // PL 1 ** 48 ** D48
_BV( 0 ) , // PL 0 ** 49 ** D49
_BV( 3 ) , // PB 3 ** 50 ** SPI_MISO
_BV( 2 ) , // PB 2 ** 51 ** SPI_MOSI
_BV( 1 ) , // PB 1 ** 52 ** SPI_SCK
_BV( 0 ) , // PB 0 ** 53 ** SPI_SS
_BV( 0 ) , // PF 0 ** 54 ** A0
_BV( 1 ) , // PF 1 ** 55 ** A1
_BV( 2 ) , // PF 2 ** 56 ** A2
_BV( 3 ) , // PF 3 ** 57 ** A3
_BV( 4 ) , // PF 4 ** 58 ** A4
_BV( 5 ) , // PF 5 ** 59 ** A5
_BV( 6 ) , // PF 6 ** 60 ** A6
_BV( 7 ) , // PF 7 ** 61 ** A7
_BV( 0 ) , // PK 0 ** 62 ** A8
_BV( 1 ) , // PK 1 ** 63 ** A9
_BV( 2 ) , // PK 2 ** 64 ** A10
_BV( 3 ) , // PK 3 ** 65 ** A11
_BV( 4 ) , // PK 4 ** 66 ** A12
_BV( 5 ) , // PK 5 ** 67 ** A13
_BV( 6 ) , // PK 6 ** 68 ** A14
_BV( 7 ) , // PK 7 ** 69 ** A15
_BV( 4 ) , // PG 4 ** 70 **
_BV( 3 ) , // PG 3 ** 71 **
_BV( 2 ) , // PJ 2 ** 72 **
_BV( 3 ) , // PJ 3 ** 73 **
_BV( 7 ) , // PJ 7 ** 74 **
_BV( 4 ) , // PJ 4 ** 75 **
_BV( 5 ) , // PJ 5 ** 76 **
_BV( 6 ) , // PJ 6 ** 77 **
_BV( 2 ) , // PE 2 ** 78 **
_BV( 6 ) , // PE 6 ** 79 **
_BV( 7 ) , // PE 7 ** 80 **
_BV( 4 ) , // PD 4 ** 81 **
_BV( 5 ) , // PD 5 ** 82 **
_BV( 6 ) , // PD 6 ** 83 **
_BV( 2 ) , // PH 2 ** 84 **
_BV( 7 ) , // PH 7 ** 85 **
};
#define digitalPinToBitMask_plus_70(P) ( pgm_read_byte( digital_pin_to_bit_mask_PGM_plus_70 + (P) ) )
const uint8_t PROGMEM digital_pin_to_timer_PGM_plus_70[] = {
// TIMERS
// ------------------------
NOT_ON_TIMER , // PE 0 ** 0 ** USART0_RX
NOT_ON_TIMER , // PE 1 ** 1 ** USART0_TX
TIMER3B , // PE 4 ** 2 ** PWM2
TIMER3C , // PE 5 ** 3 ** PWM3
TIMER0B , // PG 5 ** 4 ** PWM4
TIMER3A , // PE 3 ** 5 ** PWM5
TIMER4A , // PH 3 ** 6 ** PWM6
TIMER4B , // PH 4 ** 7 ** PWM7
TIMER4C , // PH 5 ** 8 ** PWM8
TIMER2B , // PH 6 ** 9 ** PWM9
TIMER2A , // PB 4 ** 10 ** PWM10
TIMER1A , // PB 5 ** 11 ** PWM11
TIMER1B , // PB 6 ** 12 ** PWM12
TIMER0A , // PB 7 ** 13 ** PWM13
NOT_ON_TIMER , // PJ 1 ** 14 ** USART3_TX
NOT_ON_TIMER , // PJ 0 ** 15 ** USART3_RX
NOT_ON_TIMER , // PH 1 ** 16 ** USART2_TX
NOT_ON_TIMER , // PH 0 ** 17 ** USART2_RX
NOT_ON_TIMER , // PD 3 ** 18 ** USART1_TX
NOT_ON_TIMER , // PD 2 ** 19 ** USART1_RX
NOT_ON_TIMER , // PD 1 ** 20 ** I2C_SDA
NOT_ON_TIMER , // PD 0 ** 21 ** I2C_SCL
NOT_ON_TIMER , // PA 0 ** 22 ** D22
NOT_ON_TIMER , // PA 1 ** 23 ** D23
NOT_ON_TIMER , // PA 2 ** 24 ** D24
NOT_ON_TIMER , // PA 3 ** 25 ** D25
NOT_ON_TIMER , // PA 4 ** 26 ** D26
NOT_ON_TIMER , // PA 5 ** 27 ** D27
NOT_ON_TIMER , // PA 6 ** 28 ** D28
NOT_ON_TIMER , // PA 7 ** 29 ** D29
NOT_ON_TIMER , // PC 7 ** 30 ** D30
NOT_ON_TIMER , // PC 6 ** 31 ** D31
NOT_ON_TIMER , // PC 5 ** 32 ** D32
NOT_ON_TIMER , // PC 4 ** 33 ** D33
NOT_ON_TIMER , // PC 3 ** 34 ** D34
NOT_ON_TIMER , // PC 2 ** 35 ** D35
NOT_ON_TIMER , // PC 1 ** 36 ** D36
NOT_ON_TIMER , // PC 0 ** 37 ** D37
NOT_ON_TIMER , // PD 7 ** 38 ** D38
NOT_ON_TIMER , // PG 2 ** 39 ** D39
NOT_ON_TIMER , // PG 1 ** 40 ** D40
NOT_ON_TIMER , // PG 0 ** 41 ** D41
NOT_ON_TIMER , // PL 7 ** 42 ** D42
NOT_ON_TIMER , // PL 6 ** 43 ** D43
TIMER5C , // PL 5 ** 44 ** D44
TIMER5B , // PL 4 ** 45 ** D45
TIMER5A , // PL 3 ** 46 ** D46
NOT_ON_TIMER , // PL 2 ** 47 ** D47
NOT_ON_TIMER , // PL 1 ** 48 ** D48
NOT_ON_TIMER , // PL 0 ** 49 ** D49
NOT_ON_TIMER , // PB 3 ** 50 ** SPI_MISO
NOT_ON_TIMER , // PB 2 ** 51 ** SPI_MOSI
NOT_ON_TIMER , // PB 1 ** 52 ** SPI_SCK
NOT_ON_TIMER , // PB 0 ** 53 ** SPI_SS
NOT_ON_TIMER , // PF 0 ** 54 ** A0
NOT_ON_TIMER , // PF 1 ** 55 ** A1
NOT_ON_TIMER , // PF 2 ** 56 ** A2
NOT_ON_TIMER , // PF 3 ** 57 ** A3
NOT_ON_TIMER , // PF 4 ** 58 ** A4
NOT_ON_TIMER , // PF 5 ** 59 ** A5
NOT_ON_TIMER , // PF 6 ** 60 ** A6
NOT_ON_TIMER , // PF 7 ** 61 ** A7
NOT_ON_TIMER , // PK 0 ** 62 ** A8
NOT_ON_TIMER , // PK 1 ** 63 ** A9
NOT_ON_TIMER , // PK 2 ** 64 ** A10
NOT_ON_TIMER , // PK 3 ** 65 ** A11
NOT_ON_TIMER , // PK 4 ** 66 ** A12
NOT_ON_TIMER , // PK 5 ** 67 ** A13
NOT_ON_TIMER , // PK 6 ** 68 ** A14
NOT_ON_TIMER , // PK 7 ** 69 ** A15
NOT_ON_TIMER , // PG 4 ** 70 **
NOT_ON_TIMER , // PG 3 ** 71 **
NOT_ON_TIMER , // PJ 2 ** 72 **
NOT_ON_TIMER , // PJ 3 ** 73 **
NOT_ON_TIMER , // PJ 7 ** 74 **
NOT_ON_TIMER , // PJ 4 ** 75 **
NOT_ON_TIMER , // PJ 5 ** 76 **
NOT_ON_TIMER , // PJ 6 ** 77 **
NOT_ON_TIMER , // PE 2 ** 78 **
NOT_ON_TIMER , // PE 6 ** 79 **
};
#define digitalPinToTimer_plus_70(P) ( pgm_read_byte( digital_pin_to_timer_PGM_plus_70 + (P) ) )
/**
* Interrupts that are not implemented
*
* INT6 E6 79
* INT7 E7 80
* PCINT11 J2 72
* PCINT12 J3 73
* PCINT13 J4 75
* PCINT14 J5 76
* PCINT15 J6 77
*/

@ -0,0 +1,979 @@
/**
* Marlin 3D Printer Firmware
* Copyright (c) 2023 MarlinFirmware [https://github.com/MarlinFirmware/Marlin]
*
* Based on Sprinter and grbl.
* Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
#ifdef __AVR__
#include "../../inc/MarlinConfigPre.h"
#if ENABLED(HAL_AVR_DIRTY_INIT)
#include "registers.h"
// Since the compiler could be creating multiple copies of function code-graphs for each header inline-inclusion,
// we want to off-load the function definitions that define static memory into this solitary compilation unit.
// This way the ROM is NOT bloated (who knows if the compiler is optimizing same-content constant objects into one?)
ATmegaPinFunctions _ATmega_getPinFunctions(int pin) {
if (pin < 0) return {};
ATmegaPinInfo info = _ATmega_getPinInfo((unsigned int)pin);
#ifdef __AVR_TRM01__
if (info.port == eATmegaPort::PORT_A) {
if (info.pinidx == 7) {
static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::EXTMEM_AD7 };
return { funcs, countof(funcs) };
}
else if (info.pinidx == 6) {
static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::EXTMEM_AD6 };
return { funcs, countof(funcs) };
}
else if (info.pinidx == 5) {
static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::EXTMEM_AD5 };
return { funcs, countof(funcs) };
}
else if (info.pinidx == 4) {
static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::EXTMEM_AD4 };
return { funcs, countof(funcs) };
}
else if (info.pinidx == 3) {
static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::EXTMEM_AD3 };
return { funcs, countof(funcs) };
}
else if (info.pinidx == 2) {
static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::EXTMEM_AD2 };
return { funcs, countof(funcs) };
}
else if (info.pinidx == 1) {
static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::EXTMEM_AD1 };
return { funcs, countof(funcs) };
}
else if (info.pinidx == 0) {
static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::EXTMEM_AD0 };
return { funcs, countof(funcs) };
}
}
else if (info.port == eATmegaPort::PORT_B) {
if (info.pinidx == 7) {
static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::TOC0A, eATmegaPinFunc::TOC1C, eATmegaPinFunc::PCI7 };
return { funcs, countof(funcs) };
}
else if (info.pinidx == 6) {
static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::TOC1B, eATmegaPinFunc::PCI6 };
return { funcs, countof(funcs) };
}
else if (info.pinidx == 5) {
static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::TOC1A, eATmegaPinFunc::PCI5 };
return { funcs, countof(funcs) };
}
else if (info.pinidx == 4) {
static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::TOC2A, eATmegaPinFunc::PCI4 };
return { funcs, countof(funcs) };
}
else if (info.pinidx == 3) {
static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::SPI_MISO, eATmegaPinFunc::PCI3 };
return { funcs, countof(funcs) };
}
else if (info.pinidx == 2) {
static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::SPI_MOSI, eATmegaPinFunc::PCI2 };
return { funcs, countof(funcs) };
}
else if (info.pinidx == 1) {
static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::SPI_SCK, eATmegaPinFunc::PCI1 };
return { funcs, countof(funcs) };
}
else if (info.pinidx == 0) {
static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::SPI_CS, eATmegaPinFunc::PCI0 };
return { funcs, countof(funcs) };
}
}
else if (info.port == eATmegaPort::PORT_C) {
if (info.pinidx == 7) {
static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::EXTMEM_AD15 };
return { funcs, countof(funcs) };
}
else if (info.pinidx == 6) {
static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::EXTMEM_AD14 };
return { funcs, countof(funcs) };
}
else if (info.pinidx == 5) {
static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::EXTMEM_AD13 };
return { funcs, countof(funcs) };
}
else if (info.pinidx == 4) {
static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::EXTMEM_AD12 };
return { funcs, countof(funcs) };
}
else if (info.pinidx == 3) {
static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::EXTMEM_AD11 };
return { funcs, countof(funcs) };
}
else if (info.pinidx == 2) {
static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::EXTMEM_AD10 };
return { funcs, countof(funcs) };
}
else if (info.pinidx == 1) {
static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::EXTMEM_AD9 };
return { funcs, countof(funcs) };
}
else if (info.pinidx == 0) {
static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::EXTMEM_AD8 };
return { funcs, countof(funcs) };
}
}
else if (info.port == eATmegaPort::PORT_D) {
if (info.pinidx == 7) {
static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::TIMER0_CLKI };
return { funcs, countof(funcs) };
}
else if (info.pinidx == 6) {
static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::TIMER1_CLKI };
return { funcs, countof(funcs) };
}
else if (info.pinidx == 5) {
static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::USART1_CLK };
return { funcs, countof(funcs) };
}
else if (info.pinidx == 4) {
static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::TIMER1_ICP };
return { funcs, countof(funcs) };
}
else if (info.pinidx == 3) {
static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::EINT3, eATmegaPinFunc::USART1_TXD };
return { funcs, countof(funcs) };
}
else if (info.pinidx == 2) {
static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::EINT2, eATmegaPinFunc::USART1_RXD };
return { funcs, countof(funcs) };
}
else if (info.pinidx == 1) {
static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::EINT1, eATmegaPinFunc::TWI_SDA };
return { funcs, countof(funcs) };
}
else if (info.pinidx == 0) {
static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::EINT0, eATmegaPinFunc::TWI_CLK };
return { funcs, countof(funcs) };
}
}
else if (info.port == eATmegaPort::PORT_E) {
if (info.pinidx == 7) {
static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::EINT7, eATmegaPinFunc::TIMER3_ICP, eATmegaPinFunc::CLKO };
return { funcs, countof(funcs) };
}
else if (info.pinidx == 6) {
static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::EINT6, eATmegaPinFunc::TIMER3_CLKI };
return { funcs, countof(funcs) };
}
else if (info.pinidx == 5) {
static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::EINT5, eATmegaPinFunc::TOC3C };
return { funcs, countof(funcs) };
}
else if (info.pinidx == 4) {
static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::EINT4, eATmegaPinFunc::TOC3B };
return { funcs, countof(funcs) };
}
else if (info.pinidx == 3) {
static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::AIN1, eATmegaPinFunc::TOC3A };
return { funcs, countof(funcs) };
}
else if (info.pinidx == 2) {
static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::AIN0, eATmegaPinFunc::USART0_CLK };
return { funcs, countof(funcs) };
}
else if (info.pinidx == 1) {
static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::PDO, eATmegaPinFunc::USART0_TXD };
return { funcs, countof(funcs) };
}
else if (info.pinidx == 0) {
static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::PDI, eATmegaPinFunc::USART0_RXD, eATmegaPinFunc::PCI8 };
return { funcs, countof(funcs) };
}
}
else if (info.port == eATmegaPort::PORT_F) {
if (info.pinidx == 7) {
static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::ADC7 };
return { funcs, countof(funcs) };
}
else if (info.pinidx == 6) {
static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::ADC6 };
return { funcs, countof(funcs) };
}
else if (info.pinidx == 5) {
static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::ADC5 };
return { funcs, countof(funcs) };
}
else if (info.pinidx == 4) {
static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::ADC4 };
return { funcs, countof(funcs) };
}
else if (info.pinidx == 3) {
static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::ADC3 };
return { funcs, countof(funcs) };
}
else if (info.pinidx == 2) {
static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::ADC2 };
return { funcs, countof(funcs) };
}
else if (info.pinidx == 1) {
static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::ADC1 };
return { funcs, countof(funcs) };
}
else if (info.pinidx == 0) {
static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::ADC0 };
return { funcs, countof(funcs) };
}
}
else if (info.port == eATmegaPort::PORT_G) {
if (info.pinidx == 5) {
static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::TOC0B };
return { funcs, countof(funcs) };
}
else if (info.pinidx == 4) {
static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::TOSC1 };
return { funcs, countof(funcs) };
}
else if (info.pinidx == 3 ) {
static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::TOSC2 };
return { funcs, countof(funcs) };
}
else if (info.pinidx == 2) {
static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::EXTMEM_ALE };
return { funcs, countof(funcs) };
}
else if (info.pinidx == 1) {
static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::EXTMEM_RD };
return { funcs, countof(funcs) };
}
else if (info.pinidx == 0) {
static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::EXTMEM_WR };
return { funcs, countof(funcs) };
}
}
else if (info.port == eATmegaPort::PORT_H) {
if (info.pinidx == 7) {
static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::TIMER4_CLKI };
return { funcs, countof(funcs) };
}
else if (info.pinidx == 6) {
static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::TOC2B };
return { funcs, countof(funcs) };
}
else if (info.pinidx == 5) {
static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::TOC4C };
return { funcs, countof(funcs) };
}
else if (info.pinidx == 4) {
static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::TOC4B };
return { funcs, countof(funcs) };
}
else if (info.pinidx == 3) {
static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::TOC4A };
return { funcs, countof(funcs) };
}
else if (info.pinidx == 2) {
static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::USART2_CLK };
return { funcs, countof(funcs) };
}
else if (info.pinidx == 1) {
static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::USART2_TXD };
return { funcs, countof(funcs) };
}
else if (info.pinidx == 0) {
static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::USART2_RXD };
return { funcs, countof(funcs) };
}
}
else if (info.port == eATmegaPort::PORT_J) {
if (info.pinidx == 6) {
static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::PCI15 };
return { funcs, countof(funcs) };
}
else if (info.pinidx == 5) {
static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::PCI14 };
return { funcs, countof(funcs) };
}
else if (info.pinidx == 4) {
static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::PCI13 };
return { funcs, countof(funcs) };
}
else if (info.pinidx == 3) {
static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::PCI12 };
return { funcs, countof(funcs) };
}
else if (info.pinidx == 2) {
static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::USART3_CLK, eATmegaPinFunc::PCI11 };
return { funcs, countof(funcs) };
}
else if (info.pinidx == 1) {
static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::USART3_TXD, eATmegaPinFunc::PCI10 };
return { funcs, countof(funcs) };
}
else if (info.pinidx == 0) {
static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::USART3_RXD, eATmegaPinFunc::PCI9 };
return { funcs, countof(funcs) };
}
}
else if (info.port == eATmegaPort::PORT_K) {
if (info.pinidx == 7) {
static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::ADC15, eATmegaPinFunc::PCI23 };
return { funcs, countof(funcs) };
}
else if (info.pinidx == 6) {
static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::ADC14, eATmegaPinFunc::PCI22 };
return { funcs, countof(funcs) };
}
else if (info.pinidx == 5) {
static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::ADC13, eATmegaPinFunc::PCI21 };
return { funcs, countof(funcs) };
}
else if (info.pinidx == 4) {
static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::ADC12, eATmegaPinFunc::PCI20 };
return { funcs, countof(funcs) };
}
else if (info.pinidx == 3) {
static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::ADC11, eATmegaPinFunc::PCI19 };
return { funcs, countof(funcs) };
}
else if (info.pinidx == 2) {
static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::ADC10, eATmegaPinFunc::PCI18 };
return { funcs, countof(funcs) };
}
else if (info.pinidx == 1) {
static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::ADC9, eATmegaPinFunc::PCI17 };
return { funcs, countof(funcs) };
}
else if (info.pinidx == 0) {
static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::ADC8, eATmegaPinFunc::PCI16 };
return { funcs, countof(funcs) };
}
}
else if (info.port == eATmegaPort::PORT_L) {
if (info.pinidx == 5) {
static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::TOC5C };
return { funcs, countof(funcs) };
}
else if (info.pinidx == 4) {
static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::TOC5B };
return { funcs, countof(funcs) };
}
else if (info.pinidx == 3) {
static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::TOC5A };
return { funcs, countof(funcs) };
}
else if (info.pinidx == 2) {
static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::TIMER5_CLKI };
return { funcs, countof(funcs) };
}
else if (info.pinidx == 1) {
static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::TIMER5_ICP };
return { funcs, countof(funcs) };
}
else if (info.pinidx == 0) {
static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::TIMER4_ICP };
return { funcs, countof(funcs) };
}
}
#elif defined(__AVR_TRM02__)
if (info.port == eATmegaPort::PORT_A) {
if (info.pinidx == 7) {
static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::PCI7, eATmegaPinFunc::ADC7 };
return { funcs, countof(funcs) };
}
else if (info.pinidx == 6) {
static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::PCI6, eATmegaPinFunc::ADC6 };
return { funcs, countof(funcs) };
}
else if (info.pinidx == 5) {
static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::PCI5, eATmegaPinFunc::ADC5 };
return { funcs, countof(funcs) };
}
else if (info.pinidx == 4) {
static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::PCI4, eATmegaPinFunc::ADC4 };
return { funcs, countof(funcs) };
}
else if (info.pinidx == 3) {
static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::PCI3, eATmegaPinFunc::ADC3 };
return { funcs, countof(funcs) };
}
else if (info.pinidx == 2) {
static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::PCI2, eATmegaPinFunc::ADC2 };
return { funcs, countof(funcs) };
}
else if (info.pinidx == 1) {
static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::PCI1, eATmegaPinFunc::ADC1 };
return { funcs, countof(funcs) };
}
else if (info.pinidx == 0) {
static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::PCI0, eATmegaPinFunc::ADC0 };
return { funcs, countof(funcs) };
}
}
else if (info.port == eATmegaPort::PORT_B) {
if (info.pinidx == 7) {
static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::SPI_SCK, eATmegaPinFunc::TOC3B, eATmegaPinFunc::PCI15 };
return { funcs, countof(funcs) };
}
else if (info.pinidx == 6) {
static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::SPI_MISO, eATmegaPinFunc::TOC3A, eATmegaPinFunc::PCI14 };
return { funcs, countof(funcs) };
}
else if (info.pinidx == 5) {
static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::SPI_MOSI, eATmegaPinFunc::TIMER3_ICP, eATmegaPinFunc::PCI13 };
return { funcs, countof(funcs) };
}
else if (info.pinidx == 4) {
static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::SPI_CS, eATmegaPinFunc::TOC0B, eATmegaPinFunc::PCI12 };
return { funcs, countof(funcs) };
}
else if (info.pinidx == 3) {
static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::AIN1, eATmegaPinFunc::TOC0A, eATmegaPinFunc::PCI11 };
return { funcs, countof(funcs) };
}
else if (info.pinidx == 2) {
static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::AIN0, eATmegaPinFunc::EINT2, eATmegaPinFunc::PCI10 };
return { funcs, countof(funcs) };
}
else if (info.pinidx == 1) {
static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::TIMER1_ECI, eATmegaPinFunc::CLKO, eATmegaPinFunc::PCI9 };
return { funcs, countof(funcs) };
}
else if (info.pinidx == 0) {
static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::TIMER0_ECI, eATmegaPinFunc::USART0_CLK, eATmegaPinFunc::PCI8 };
return { funcs, countof(funcs) };
}
}
else if (info.port == eATmegaPort::PORT_C) {
if (info.pinidx == 7) {
static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::TOSC2, eATmegaPinFunc::PCI23 };
return { funcs, countof(funcs) };
}
else if (info.pinidx == 6) {
static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::TOSC1, eATmegaPinFunc::PCI22 };
return { funcs, countof(funcs) };
}
else if (info.pinidx == 5) {
static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::PCI21 };
return { funcs, countof(funcs) };
}
else if (info.pinidx == 4) {
static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::PCI20 };
return { funcs, countof(funcs) };
}
else if (info.pinidx == 3) {
static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::PCI19 };
return { funcs, countof(funcs) };
}
else if (info.pinidx == 2) {
static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::PCI18 };
return { funcs, countof(funcs) };
}
else if (info.pinidx == 1) {
static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::PCI17, eATmegaPinFunc::TWI_SDA };
return { funcs, countof(funcs) };
}
else if (info.pinidx == 0) {
static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::TWI_CLK, eATmegaPinFunc::PCI16 };
return { funcs, countof(funcs) };
}
}
else if (info.port == eATmegaPort::PORT_D) {
if (info.pinidx == 7) {
static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::TOC2A, eATmegaPinFunc::PCI31 };
return { funcs, countof(funcs) };
}
else if (info.pinidx == 6) {
static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::TIMER1_ICP, eATmegaPinFunc::TOC2B, eATmegaPinFunc::PCI30 };
return { funcs, countof(funcs) };
}
else if (info.pinidx == 5) {
static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::TOC1A, eATmegaPinFunc::PCI29 };
return { funcs, countof(funcs) };
}
else if (info.pinidx == 4) {
static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::TOC1B, eATmegaPinFunc::USART1_CLK, eATmegaPinFunc::PCI28 };
return { funcs, countof(funcs) };
}
else if (info.pinidx == 3) {
static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::EINT1, eATmegaPinFunc::USART1_TXD, eATmegaPinFunc::PCI27 };
return { funcs, countof(funcs) };
}
else if (info.pinidx == 2) {
static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::EINT0, eATmegaPinFunc::USART1_RXD, eATmegaPinFunc::PCI26 };
return { funcs, countof(funcs) };
}
else if (info.pinidx == 1) {
static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::USART0_TXD, eATmegaPinFunc::PCI25 };
return { funcs, countof(funcs) };
}
else if (info.pinidx == 0) {
static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::USART0_TXD, eATmegaPinFunc::PCI24, eATmegaPinFunc::TIMER3_ECI };
return { funcs, countof(funcs) };
}
}
#elif defined(__AVR_TRM03__)
if (info.port == eATmegaPort::PORT_B) {
if (info.pinidx == 7) {
static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::XTAL2, eATmegaPinFunc::TOSC2, eATmegaPinFunc::PCI7 };
return { funcs, countof(funcs) };
}
else if (info.pinidx == 6) {
static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::XTAL1, eATmegaPinFunc::TOSC1, eATmegaPinFunc::PCI6 };
return { funcs, countof(funcs) };
}
else if (info.pinidx == 5) {
static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::SPI_SCK, eATmegaPinFunc::PCI5 };
return { funcs, countof(funcs) };
}
else if (info.pinidx == 4) {
static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::SPI_MISO, eATmegaPinFunc::PCI4 };
return { funcs, countof(funcs) };
}
else if (info.pinidx == 3) {
static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::SPI_MOSI, eATmegaPinFunc::TOC2A, eATmegaPinFunc::PCI3 };
return { funcs, countof(funcs) };
}
else if (info.pinidx == 2) {
static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::SPI_CS, eATmegaPinFunc::TOC1B, eATmegaPinFunc::PCI2 };
return { funcs, countof(funcs) };
}
else if (info.pinidx == 1) {
static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::TOC1A, eATmegaPinFunc::PCI1 };
return { funcs, countof(funcs) };
}
else if (info.pinidx == 0) {
static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::TIMER1_ICP, eATmegaPinFunc::CLKO, eATmegaPinFunc::PCI0 };
return { funcs, countof(funcs) };
}
}
else if (info.port == eATmegaPort::PORT_C) {
if (info.pinidx == 6) {
static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::PCI14 };
return { funcs, countof(funcs) };
}
else if (info.pinidx == 5) {
static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::ADC5, eATmegaPinFunc::TWI_CLK, eATmegaPinFunc::PCI13 };
return { funcs, countof(funcs) };
}
else if (info.pinidx == 4) {
static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::ADC4, eATmegaPinFunc::TWI_SDA, eATmegaPinFunc::PCI12 };
return { funcs, countof(funcs) };
}
else if (info.pinidx == 3) {
static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::ADC3, eATmegaPinFunc::PCI11 };
return { funcs, countof(funcs) };
}
else if (info.pinidx == 2) {
static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::ADC2, eATmegaPinFunc::PCI10 };
return { funcs, countof(funcs) };
}
else if (info.pinidx == 1) {
static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::ADC1, eATmegaPinFunc::PCI9 };
return { funcs, countof(funcs) };
}
else if (info.pinidx == 0) {
static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::ADC0, eATmegaPinFunc::PCI8 };
return { funcs, countof(funcs) };
}
}
else if (info.port == eATmegaPort::PORT_D) {
if (info.pinidx == 7) {
static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::AIN1, eATmegaPinFunc::PCI23 };
return { funcs, countof(funcs) };
}
else if (info.pinidx == 6) {
static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::AIN0, eATmegaPinFunc::TOC0A, eATmegaPinFunc::PCI22 };
return { funcs, countof(funcs) };
}
else if (info.pinidx == 5) {
static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::TIMER1_ECI, eATmegaPinFunc::TOC0B, eATmegaPinFunc::PCI21 };
return { funcs, countof(funcs) };
}
else if (info.pinidx == 4) {
static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::USART_CLK, eATmegaPinFunc::TIMER0_ECI, eATmegaPinFunc::PCI20 };
return { funcs, countof(funcs) };
}
else if (info.pinidx == 3) {
static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::EINT1, eATmegaPinFunc::TOC2B, eATmegaPinFunc::PCI19 };
return { funcs, countof(funcs) };
}
else if (info.pinidx == 2) {
static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::EINT0, eATmegaPinFunc::PCI18 };
return { funcs, countof(funcs) };
}
else if (info.pinidx == 1) {
static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::USART_TXD, eATmegaPinFunc::PCI17 };
return { funcs, countof(funcs) };
}
else if (info.pinidx == 0) {
static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::USART_RXD, eATmegaPinFunc::PCI16 };
return { funcs, countof(funcs) };
}
}
#elif defined(__AVR_TRM04__)
if (info.port == eATmegaPort::PORT_A) {
if (info.pinidx == 7) {
static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::EXTMEM_AD7 };
return { funcs, countof(funcs) };
}
else if (info.pinidx == 6) {
static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::EXTMEM_AD6 };
return { funcs, countof(funcs) };
}
else if (info.pinidx == 5) {
static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::EXTMEM_AD5 };
return { funcs, countof(funcs) };
}
else if (info.pinidx == 4) {
static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::EXTMEM_AD4 };
return { funcs, countof(funcs) };
}
else if (info.pinidx == 3) {
static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::EXTMEM_AD3 };
return { funcs, countof(funcs) };
}
else if (info.pinidx == 2) {
static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::EXTMEM_AD2 };
return { funcs, countof(funcs) };
}
else if (info.pinidx == 1) {
static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::EXTMEM_AD1 };
return { funcs, countof(funcs) };
}
else if (info.pinidx == 0) {
static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::EXTMEM_AD0 };
return { funcs, countof(funcs) };
}
}
else if (info.port == eATmegaPort::PORT_B) {
if (info.pinidx == 7) {
static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::TOC0A, eATmegaPinFunc::TOC1C, eATmegaPinFunc::PCI7 };
return { funcs, countof(funcs) };
}
else if (info.pinidx == 6) {
static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::TOC1B, eATmegaPinFunc::PCI6 };
return { funcs, countof(funcs) };
}
else if (info.pinidx == 5) {
static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::TOC1A, eATmegaPinFunc::PCI5 };
return { funcs, countof(funcs) };
}
else if (info.pinidx == 4) {
static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::TOC2A, eATmegaPinFunc::PCI4 };
return { funcs, countof(funcs) };
}
else if (info.pinidx == 3) {
static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::PDO, eATmegaPinFunc::SPI_MISO, eATmegaPinFunc::PCI3 };
return { funcs, countof(funcs) };
}
else if (info.pinidx == 2) {
static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::PDI, eATmegaPinFunc::SPI_MOSI, eATmegaPinFunc::PCI2 };
return { funcs, countof(funcs) };
}
else if (info.pinidx == 1) {
static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::SPI_SCK, eATmegaPinFunc::PCI1 };
return { funcs, countof(funcs) };
}
else if (info.pinidx == 0) {
static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::SPI_CS, eATmegaPinFunc::PCI0 };
return { funcs, countof(funcs) };
}
}
else if (info.port == eATmegaPort::PORT_C) {
if (info.pinidx == 7) {
static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::EXTMEM_AD15, eATmegaPinFunc::TIMER3_ICP, eATmegaPinFunc::CLKO };
return { funcs, countof(funcs) };
}
else if (info.pinidx == 6) {
static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::EXTMEM_AD14, eATmegaPinFunc::TOC3A };
return { funcs, countof(funcs) };
}
else if (info.pinidx == 5) {
static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::EXTMEM_AD13, eATmegaPinFunc::TOC3B };
return { funcs, countof(funcs) };
}
else if (info.pinidx == 4) {
static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::EXTMEM_AD12, eATmegaPinFunc::TOC3C };
return { funcs, countof(funcs) };
}
else if (info.pinidx == 3) {
static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::EXTMEM_AD11, eATmegaPinFunc::TIMER3_CLKI };
return { funcs, countof(funcs) };
}
else if (info.pinidx == 2) {
static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::EXTMEM_AD10 };
return { funcs, countof(funcs) };
}
else if (info.pinidx == 1) {
static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::EXTMEM_AD9 };
return { funcs, countof(funcs) };
}
else if (info.pinidx == 0) {
static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::EXTMEM_AD8 };
return { funcs, countof(funcs) };
}
}
else if (info.port == eATmegaPort::PORT_D) {
if (info.pinidx == 7) {
static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::TIMER0_CLKI };
return { funcs, countof(funcs) };
}
else if (info.pinidx == 6) {
static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::TIMER1_CLKI };
return { funcs, countof(funcs) };
}
else if (info.pinidx == 5) {
static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::USART1_CLK };
return { funcs, countof(funcs) };
}
else if (info.pinidx == 4) {
static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::TIMER1_ICP };
return { funcs, countof(funcs) };
}
else if (info.pinidx == 3) {
static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::EINT3, eATmegaPinFunc::USART1_TXD };
return { funcs, countof(funcs) };
}
else if (info.pinidx == 2) {
static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::EINT2, eATmegaPinFunc::USART1_RXD };
return { funcs, countof(funcs) };
}
else if (info.pinidx == 1) {
static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::EINT1, eATmegaPinFunc::TWI_SDA, eATmegaPinFunc::TOC2B };
return { funcs, countof(funcs) };
}
else if (info.pinidx == 0) {
static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::EINT0, eATmegaPinFunc::TWI_CLK, eATmegaPinFunc::TOC0B };
return { funcs, countof(funcs) };
}
}
else if (info.port == eATmegaPort::PORT_E) {
if (info.pinidx == 7) {
static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::EINT7, eATmegaPinFunc::AIN1, eATmegaPinFunc::UVCON };
return { funcs, countof(funcs) };
}
else if (info.pinidx == 6) {
static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::EINT6, eATmegaPinFunc::AIN0 };
return { funcs, countof(funcs) };
}
else if (info.pinidx == 5) {
static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::EINT5, eATmegaPinFunc::TOSC2 };
return { funcs, countof(funcs) };
}
else if (info.pinidx == 4) {
static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::EINT4, eATmegaPinFunc::TOSC2 };
return { funcs, countof(funcs) };
}
else if (info.pinidx == 3) {
static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::UID };
return { funcs, countof(funcs) };
}
else if (info.pinidx == 2) {
static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::EXTMEM_ALE };
return { funcs, countof(funcs) };
}
else if (info.pinidx == 1) {
static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::EXTMEM_RD };
return { funcs, countof(funcs) };
}
else if (info.pinidx == 0) {
static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::EXTMEM_WR };
return { funcs, countof(funcs) };
}
}
else if (info.port == eATmegaPort::PORT_F) {
if (info.pinidx == 7) {
static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::ADC7 };
return { funcs, countof(funcs) };
}
else if (info.pinidx == 6) {
static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::ADC6 };
return { funcs, countof(funcs) };
}
else if (info.pinidx == 5) {
static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::ADC5 };
return { funcs, countof(funcs) };
}
else if (info.pinidx == 4) {
static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::ADC4 };
return { funcs, countof(funcs) };
}
else if (info.pinidx == 3) {
static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::ADC3 };
return { funcs, countof(funcs) };
}
else if (info.pinidx == 2) {
static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::ADC2 };
return { funcs, countof(funcs) };
}
else if (info.pinidx == 1) {
static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::ADC1 };
return { funcs, countof(funcs) };
}
else if (info.pinidx == 0) {
static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::ADC0 };
return { funcs, countof(funcs) };
}
}
#elif defined(__AVR_TRM05__)
if (info.port == eATmegaPort::PORT_A) {
if (info.pinidx == 7) {
static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::ADC7, eATmegaPinFunc::PCI7 };
return { funcs, countof(funcs) };
}
else if (info.pinidx == 6) {
static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::ADC6, eATmegaPinFunc::PCI6 };
return { funcs, countof(funcs) };
}
else if (info.pinidx == 5) {
static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::ADC5, eATmegaPinFunc::PCI5 };
return { funcs, countof(funcs) };
}
else if (info.pinidx == 4) {
static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::ADC4, eATmegaPinFunc::PCI4 };
return { funcs, countof(funcs) };
}
else if (info.pinidx == 3) {
static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::ADC3, eATmegaPinFunc::PCI3 };
return { funcs, countof(funcs) };
}
else if (info.pinidx == 2) {
static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::ADC2, eATmegaPinFunc::PCI2 };
return { funcs, countof(funcs) };
}
else if (info.pinidx == 1) {
static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::ADC1, eATmegaPinFunc::PCI1 };
return { funcs, countof(funcs) };
}
else if (info.pinidx == 0) {
static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::ADC0, eATmegaPinFunc::PCI0 };
return { funcs, countof(funcs) };
}
}
else if (info.port == eATmegaPort::PORT_B) {
if (info.pinidx == 7) {
static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::SPI_SCK, eATmegaPinFunc::PCI15 };
return { funcs, countof(funcs) };
}
else if (info.pinidx == 6) {
static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::SPI_MISO, eATmegaPinFunc::PCI14 };
return { funcs, countof(funcs) };
}
else if (info.pinidx == 5) {
static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::SPI_MOSI, eATmegaPinFunc::PCI13 };
return { funcs, countof(funcs) };
}
else if (info.pinidx == 4) {
static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::SPI_CS, eATmegaPinFunc::TOC0B, eATmegaPinFunc::PCI12 };
return { funcs, countof(funcs) };
}
else if (info.pinidx == 3) {
static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::AIN1, eATmegaPinFunc::TOC0A, eATmegaPinFunc::PCI11 };
return { funcs, countof(funcs) };
}
else if (info.pinidx == 2) {
static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::AIN0, eATmegaPinFunc::EINT2, eATmegaPinFunc::PCI10 };
return { funcs, countof(funcs) };
}
else if (info.pinidx == 1) {
static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::TIMER1_ECI, eATmegaPinFunc::CLKO, eATmegaPinFunc::PCI9 };
return { funcs, countof(funcs) };
}
else if (info.pinidx == 0) {
static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::TIMER0_ECI, eATmegaPinFunc::USART0_CLK, eATmegaPinFunc::PCI8 };
return { funcs, countof(funcs) };
}
}
else if (info.port == eATmegaPort::PORT_C) {
if (info.pinidx == 7) {
static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::TOSC2, eATmegaPinFunc::PCI23 };
return { funcs, countof(funcs) };
}
else if (info.pinidx == 6) {
static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::TOSC1, eATmegaPinFunc::PCI22 };
return { funcs, countof(funcs) };
}
else if (info.pinidx == 5) {
static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::PCI21 };
return { funcs, countof(funcs) };
}
else if (info.pinidx == 4) {
static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::PCI20 };
return { funcs, countof(funcs) };
}
else if (info.pinidx == 3) {
static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::PCI19 };
return { funcs, countof(funcs) };
}
else if (info.pinidx == 2) {
static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::PCI18 };
return { funcs, countof(funcs) };
}
else if (info.pinidx == 1) {
static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::TWI_SDA, eATmegaPinFunc::PCI17 };
return { funcs, countof(funcs) };
}
else if (info.pinidx == 0) {
static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::TWI_CLK, eATmegaPinFunc::PCI16 };
return { funcs, countof(funcs) };
}
}
else if (info.port == eATmegaPort::PORT_D) {
if (info.pinidx == 7) {
static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::TOC2A, eATmegaPinFunc::PCI31 };
return { funcs, countof(funcs) };
}
if (info.pinidx == 6) {
static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::TIMER1_ICP, eATmegaPinFunc::TOC2B, eATmegaPinFunc::PCI30 };
return { funcs, countof(funcs) };
}
if (info.pinidx == 5) {
static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::TOC1A, eATmegaPinFunc::PCI29 };
return { funcs, countof(funcs) };
}
if (info.pinidx == 4) {
static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::TOC1B, eATmegaPinFunc::USART1_CLK, eATmegaPinFunc::PCI28 };
return { funcs, countof(funcs) };
}
if (info.pinidx == 3) {
static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::EINT1, eATmegaPinFunc::USART1_TXD, eATmegaPinFunc::PCI27 };
return { funcs, countof(funcs) };
}
if (info.pinidx == 2) {
static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::EINT0, eATmegaPinFunc::USART1_RXD, eATmegaPinFunc::PCI26 };
return { funcs, countof(funcs) };
}
if (info.pinidx == 1) {
static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::USART0_TXD, eATmegaPinFunc::PCI25 };
return { funcs, countof(funcs) };
}
if (info.pinidx == 0) {
static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::USART0_RXD, eATmegaPinFunc::PCI24 };
return { funcs, countof(funcs) };
}
}
#endif
return ATmegaPinFunctions(); // default and empty.
}
#endif // HAL_AVR_DIRTY_INIT
#endif // __AVR__

File diff suppressed because it is too large Load Diff

@ -0,0 +1,65 @@
/**
* 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/>.
*
*/
#pragma once
/**
* Define SPI Pins: SCK, MISO, MOSI, SS
*/
#if defined(__AVR_ATmega168__) || defined(__AVR_ATmega328__) || defined(__AVR_ATmega328P__)
#define AVR_SCK_PIN 13
#define AVR_MISO_PIN 12
#define AVR_MOSI_PIN 11
#define AVR_SS_PIN 10
#elif defined(__AVR_ATmega644__) || defined(__AVR_ATmega644P__) || defined(__AVR_ATmega644PA__) || defined(__AVR_ATmega1284P__)
#define AVR_SCK_PIN 7
#define AVR_MISO_PIN 6
#define AVR_MOSI_PIN 5
#define AVR_SS_PIN 4
#elif defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)
#define AVR_SCK_PIN 52
#define AVR_MISO_PIN 50
#define AVR_MOSI_PIN 51
#define AVR_SS_PIN 53
#elif defined(__AVR_AT90USB1287__) || defined(__AVR_AT90USB1286__) || defined(__AVR_AT90USB646__) || defined(__AVR_AT90USB647__)
#define AVR_SCK_PIN 21
#define AVR_MISO_PIN 23
#define AVR_MOSI_PIN 22
#define AVR_SS_PIN 20
#elif defined(__AVR_ATmega1281__) || defined(__AVR_ATmega2561__)
#define AVR_SCK_PIN 10
#define AVR_MISO_PIN 12
#define AVR_MOSI_PIN 11
#define AVR_SS_PIN 16
#endif
#ifndef SD_SCK_PIN
#define SD_SCK_PIN AVR_SCK_PIN
#endif
#ifndef SD_MISO_PIN
#define SD_MISO_PIN AVR_MISO_PIN
#endif
#ifndef SD_MOSI_PIN
#define SD_MOSI_PIN AVR_MOSI_PIN
#endif
#ifndef SD_SS_PIN
#define SD_SS_PIN AVR_SS_PIN
#endif

@ -0,0 +1,262 @@
/**
* 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/>.
*
*/
#pragma once
#include <stdint.h>
// ------------------------
// Types
// ------------------------
typedef uint16_t hal_timer_t;
#define HAL_TIMER_TYPE_MAX 0xFFFF
// ------------------------
// Defines
// ------------------------
#define HAL_TIMER_RATE ((F_CPU) / 8) // i.e., 2MHz or 2.5MHz
#ifndef MF_TIMER_STEP
#define MF_TIMER_STEP 1
#endif
#ifndef MF_TIMER_PULSE
#define MF_TIMER_PULSE MF_TIMER_STEP
#endif
#ifndef MF_TIMER_TEMP
#define MF_TIMER_TEMP 0
#endif
#define TEMP_TIMER_FREQUENCY (((F_CPU) + 0x2000) / 0x4000)
#define STEPPER_TIMER_RATE HAL_TIMER_RATE
#define STEPPER_TIMER_PRESCALE 8
#define STEPPER_TIMER_TICKS_PER_US ((STEPPER_TIMER_RATE) / 1000000)
#define PULSE_TIMER_RATE STEPPER_TIMER_RATE
#define PULSE_TIMER_PRESCALE STEPPER_TIMER_PRESCALE
#define PULSE_TIMER_TICKS_PER_US STEPPER_TIMER_TICKS_PER_US
#define ENABLE_STEPPER_DRIVER_INTERRUPT() SBI(TIMSK1, OCIE1A)
#define DISABLE_STEPPER_DRIVER_INTERRUPT() CBI(TIMSK1, OCIE1A)
#define STEPPER_ISR_ENABLED() TEST(TIMSK1, OCIE1A)
#define ENABLE_TEMPERATURE_INTERRUPT() SBI(TIMSK0, OCIE0A)
#define DISABLE_TEMPERATURE_INTERRUPT() CBI(TIMSK0, OCIE0A)
#define TEMPERATURE_ISR_ENABLED() TEST(TIMSK0, OCIE0A)
FORCE_INLINE void HAL_timer_start(const uint8_t timer_num, const uint32_t) {
switch (timer_num) {
case MF_TIMER_STEP:
// waveform generation = 0100 = CTC
SET_WGM(1, CTC_OCRnA);
// output mode = 00 (disconnected)
SET_COMA(1, NORMAL);
// Set the timer pre-scaler
// Generally we use a divider of 8, resulting in a 2MHz timer
// frequency on a 16MHz MCU. If you are going to change this, be
// sure to regenerate speed_lookuptable.h with
// create_speed_lookuptable.py
SET_CS(1, PRESCALER_8); // CS 2 = 1/8 prescaler
// Init Stepper ISR to 122 Hz for quick starting
// (F_CPU) / (STEPPER_TIMER_PRESCALE) / frequency
OCR1A = 0x4000;
TCNT1 = 0;
break;
case MF_TIMER_TEMP:
// Use timer0 for temperature measurement
// Interleave temperature interrupt with millies interrupt
OCR0A = 128;
break;
}
}
#define TIMER_OCR_1 OCR1A
#define TIMER_COUNTER_1 TCNT1
#define TIMER_OCR_0 OCR0A
#define TIMER_COUNTER_0 TCNT0
#define _CAT(a,V...) a##V
#define HAL_timer_set_compare(timer, compare) (_CAT(TIMER_OCR_, timer) = compare)
#define HAL_timer_get_compare(timer) _CAT(TIMER_OCR_, timer)
#define HAL_timer_get_count(timer) _CAT(TIMER_COUNTER_, timer)
/**
* On AVR there is no hardware prioritization and preemption of
* interrupts, so this emulates it. The UART has first priority
* (otherwise, characters will be lost due to UART overflow).
* Then: Stepper, Endstops, Temperature, and -finally- all others.
*/
#define HAL_timer_isr_prologue(T) NOOP
#define HAL_timer_isr_epilogue(T) NOOP
#ifndef HAL_STEP_TIMER_ISR
/* 18 cycles maximum latency */
#define HAL_STEP_TIMER_ISR() \
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)); \
void TIMER1_COMPA_vect() { \
__asm__ __volatile__ ( \
A("push r16") /* 2 Save R16 */ \
A("in r16, __SREG__") /* 1 Get SREG */ \
A("push r16") /* 2 Save SREG into stack */ \
A("lds r16, %[timsk0]") /* 2 Load into R0 the Temperature timer Interrupt mask register */ \
A("push r16") /* 2 Save TIMSK0 into the stack */ \
A("andi r16,~%[msk0]") /* 1 Disable the temperature ISR */ \
A("sts %[timsk0], r16") /* 2 And set the new value */ \
A("lds r16, %[timsk1]") /* 2 Load into R0 the stepper timer Interrupt mask register [TIMSK1] */ \
A("andi r16,~%[msk1]") /* 1 Disable the stepper ISR */ \
A("sts %[timsk1], r16") /* 2 And set the new value */ \
A("push r16") /* 2 Save TIMSK1 into stack */ \
A("in r16, 0x3B") /* 1 Get RAMPZ register */ \
A("push r16") /* 2 Save RAMPZ into stack */ \
A("in r16, 0x3C") /* 1 Get EIND register */ \
A("push r0") /* C runtime can modify all the following registers without restoring them */ \
A("push r1") \
A("push r18") \
A("push r19") \
A("push r20") \
A("push r21") \
A("push r22") \
A("push r23") \
A("push r24") \
A("push r25") \
A("push r26") \
A("push r27") \
A("push r30") \
A("push r31") \
A("clr r1") /* C runtime expects this register to be 0 */ \
A("call TIMER1_COMPA_vect_bottom") /* Call the bottom handler - No inlining allowed, otherwise registers used are not saved */ \
A("pop r31") \
A("pop r30") \
A("pop r27") \
A("pop r26") \
A("pop r25") \
A("pop r24") \
A("pop r23") \
A("pop r22") \
A("pop r21") \
A("pop r20") \
A("pop r19") \
A("pop r18") \
A("pop r1") \
A("pop r0") \
A("out 0x3C, r16") /* 1 Restore EIND register */ \
A("pop r16") /* 2 Get the original RAMPZ register value */ \
A("out 0x3B, r16") /* 1 Restore RAMPZ register to its original value */ \
A("pop r16") /* 2 Get the original TIMSK1 value but with stepper ISR disabled */ \
A("ori r16,%[msk1]") /* 1 Reenable the stepper ISR */ \
A("cli") /* 1 Disable global interrupts - Reenabling Stepper ISR can reenter amd temperature can reenter, and we want that, if it happens, after this ISR has ended */ \
A("sts %[timsk1], r16") /* 2 And restore the old value - This reenables the stepper ISR */ \
A("pop r16") /* 2 Get the temperature timer Interrupt mask register [TIMSK0] */ \
A("sts %[timsk0], r16") /* 2 And restore the old value - This reenables the temperature ISR */ \
A("pop r16") /* 2 Get the old SREG value */ \
A("out __SREG__, r16") /* 1 And restore the SREG value */ \
A("pop r16") /* 2 Restore R16 value */ \
A("reti") /* 4 Return from interrupt */ \
: \
: [timsk0] "i" ((uint16_t)&TIMSK0), \
[timsk1] "i" ((uint16_t)&TIMSK1), \
[msk0] "M" ((uint8_t)(1<<OCIE0A)),\
[msk1] "M" ((uint8_t)(1<<OCIE1A)) \
: \
); \
} \
void TIMER1_COMPA_vect_bottom()
#endif // HAL_STEP_TIMER_ISR
#ifndef HAL_TEMP_TIMER_ISR
/* 14 cycles maximum latency */
#define HAL_TEMP_TIMER_ISR() \
extern "C" void TIMER0_COMPA_vect() __attribute__ ((signal, naked, used, externally_visible)); \
extern "C" void TIMER0_COMPA_vect_bottom() asm ("TIMER0_COMPA_vect_bottom") __attribute__ ((used, externally_visible, noinline)); \
void TIMER0_COMPA_vect() { \
__asm__ __volatile__ ( \
A("push r16") /* 2 Save R16 */ \
A("in r16, __SREG__") /* 1 Get SREG */ \
A("push r16") /* 2 Save SREG into stack */ \
A("lds r16, %[timsk0]") /* 2 Load into R0 the Temperature timer Interrupt mask register */ \
A("andi r16,~%[msk0]") /* 1 Disable the temperature ISR */ \
A("sts %[timsk0], r16") /* 2 And set the new value */ \
A("sei") /* 1 Enable global interrupts - It is safe, as the temperature ISR is disabled, so we cannot reenter it */ \
A("push r16") /* 2 Save TIMSK0 into stack */ \
A("in r16, 0x3B") /* 1 Get RAMPZ register */ \
A("push r16") /* 2 Save RAMPZ into stack */ \
A("in r16, 0x3C") /* 1 Get EIND register */ \
A("push r0") /* C runtime can modify all the following registers without restoring them */ \
A("push r1") \
A("push r18") \
A("push r19") \
A("push r20") \
A("push r21") \
A("push r22") \
A("push r23") \
A("push r24") \
A("push r25") \
A("push r26") \
A("push r27") \
A("push r30") \
A("push r31") \
A("clr r1") /* C runtime expects this register to be 0 */ \
A("call TIMER0_COMPA_vect_bottom") /* Call the bottom handler - No inlining allowed, otherwise registers used are not saved */ \
A("pop r31") \
A("pop r30") \
A("pop r27") \
A("pop r26") \
A("pop r25") \
A("pop r24") \
A("pop r23") \
A("pop r22") \
A("pop r21") \
A("pop r20") \
A("pop r19") \
A("pop r18") \
A("pop r1") \
A("pop r0") \
A("out 0x3C, r16") /* 1 Restore EIND register */ \
A("pop r16") /* 2 Get the original RAMPZ register value */ \
A("out 0x3B, r16") /* 1 Restore RAMPZ register to its original value */ \
A("pop r16") /* 2 Get the original TIMSK0 value but with temperature ISR disabled */ \
A("ori r16,%[msk0]") /* 1 Enable temperature ISR */ \
A("cli") /* 1 Disable global interrupts - We must do this, as we will reenable the temperature ISR, and we don't want to reenter this handler until the current one is done */ \
A("sts %[timsk0], r16") /* 2 And restore the old value */ \
A("pop r16") /* 2 Get the old SREG */ \
A("out __SREG__, r16") /* 1 And restore the SREG value */ \
A("pop r16") /* 2 Restore R16 */ \
A("reti") /* 4 Return from interrupt */ \
: \
: [timsk0] "i"((uint16_t)&TIMSK0), \
[msk0] "M" ((uint8_t)(1<<OCIE0A)) \
: \
); \
} \
void TIMER0_COMPA_vect_bottom()
#endif // HAL_TEMP_TIMER_ISR

@ -0,0 +1,29 @@
/**
* Marlin 3D Printer Firmware
* Copyright (c) 2023 MarlinFirmware [https://github.com/MarlinFirmware/Marlin]
*
* Based on Sprinter and grbl.
* Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
#pragma once
/**
* AVR LCD-specific defines
*/
uint8_t u8g_com_HAL_AVR_sw_sp_fn(u8g_t *u8g, uint8_t msg, uint8_t arg_val, void *arg_ptr);
#define U8G_COM_HAL_SW_SPI_FN u8g_com_HAL_AVR_sw_sp_fn

@ -0,0 +1,193 @@
/**
* 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/>.
*
*/
/**
* Based on u8g_com_st7920_hw_spi.c
*
* Universal 8bit Graphics Library
*
* Copyright (c) 2011, olikraus@gmail.com
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice, this list
* of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright notice, this
* list of conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#if defined(ARDUINO) && !defined(ARDUINO_ARCH_STM32) && !defined(ARDUINO_ARCH_SAM)
#include "../../inc/MarlinConfigPre.h"
#if HAS_MARLINUI_U8GLIB
#include "../shared/Marduino.h"
#include "../shared/Delay.h"
#include <U8glib-HAL.h>
static uint8_t u8g_bitData, u8g_bitNotData, u8g_bitClock, u8g_bitNotClock;
static volatile uint8_t *u8g_outData, *u8g_outClock;
static void u8g_com_arduino_init_shift_out(uint8_t dataPin, uint8_t clockPin) {
u8g_outData = portOutputRegister(digitalPinToPort(dataPin));
u8g_outClock = portOutputRegister(digitalPinToPort(clockPin));
u8g_bitData = digitalPinToBitMask(dataPin);
u8g_bitClock = digitalPinToBitMask(clockPin);
u8g_bitNotClock = u8g_bitClock;
u8g_bitNotClock ^= 0xFF;
u8g_bitNotData = u8g_bitData;
u8g_bitNotData ^= 0xFF;
}
void u8g_spiSend_sw_AVR_mode_0(uint8_t val) {
uint8_t bitData = u8g_bitData,
bitNotData = u8g_bitNotData,
bitClock = u8g_bitClock,
bitNotClock = u8g_bitNotClock;
volatile uint8_t *outData = u8g_outData,
*outClock = u8g_outClock;
U8G_ATOMIC_START();
for (uint8_t i = 0; i < 8; ++i) {
if (val & 0x80)
*outData |= bitData;
else
*outData &= bitNotData;
*outClock |= bitClock;
val <<= 1;
*outClock &= bitNotClock;
}
U8G_ATOMIC_END();
}
void u8g_spiSend_sw_AVR_mode_3(uint8_t val) {
uint8_t bitData = u8g_bitData,
bitNotData = u8g_bitNotData,
bitClock = u8g_bitClock,
bitNotClock = u8g_bitNotClock;
volatile uint8_t *outData = u8g_outData,
*outClock = u8g_outClock;
U8G_ATOMIC_START();
for (uint8_t i = 0; i < 8; ++i) {
*outClock &= bitNotClock;
if (val & 0x80)
*outData |= bitData;
else
*outData &= bitNotData;
*outClock |= bitClock;
val <<= 1;
}
U8G_ATOMIC_END();
}
#if ENABLED(FYSETC_MINI_12864)
#define SPISEND_SW_AVR u8g_spiSend_sw_AVR_mode_3
#else
#define SPISEND_SW_AVR u8g_spiSend_sw_AVR_mode_0
#endif
uint8_t u8g_com_HAL_AVR_sw_sp_fn(u8g_t *u8g, uint8_t msg, uint8_t arg_val, void *arg_ptr) {
switch (msg) {
case U8G_COM_MSG_INIT:
u8g_com_arduino_init_shift_out(u8g->pin_list[U8G_PI_MOSI], u8g->pin_list[U8G_PI_SCK]);
u8g_com_arduino_assign_pin_output_high(u8g);
u8g_com_arduino_digital_write(u8g, U8G_PI_SCK, 0);
u8g_com_arduino_digital_write(u8g, U8G_PI_MOSI, 0);
break;
case U8G_COM_MSG_STOP:
break;
case U8G_COM_MSG_RESET:
if (U8G_PIN_NONE != u8g->pin_list[U8G_PI_RESET]) u8g_com_arduino_digital_write(u8g, U8G_PI_RESET, arg_val);
break;
case U8G_COM_MSG_CHIP_SELECT:
#if ENABLED(FYSETC_MINI_12864) // LCD SPI is running mode 3 while SD card is running mode 0
if (arg_val) { // SCK idle state needs to be set to the proper idle state before
// the next chip select goes active
u8g_com_arduino_digital_write(u8g, U8G_PI_SCK, 1); // Set SCK to mode 3 idle state before CS goes active
u8g_com_arduino_digital_write(u8g, U8G_PI_CS, LOW);
}
else {
u8g_com_arduino_digital_write(u8g, U8G_PI_CS, HIGH);
u8g_com_arduino_digital_write(u8g, U8G_PI_SCK, 0); // Set SCK to mode 0 idle state after CS goes inactive
}
#else
u8g_com_arduino_digital_write(u8g, U8G_PI_CS, !arg_val);
#endif
break;
case U8G_COM_MSG_WRITE_BYTE:
SPISEND_SW_AVR(arg_val);
break;
case U8G_COM_MSG_WRITE_SEQ: {
uint8_t *ptr = (uint8_t *)arg_ptr;
while (arg_val > 0) {
SPISEND_SW_AVR(*ptr++);
arg_val--;
}
}
break;
case U8G_COM_MSG_WRITE_SEQ_P: {
uint8_t *ptr = (uint8_t *)arg_ptr;
while (arg_val > 0) {
SPISEND_SW_AVR(u8g_pgm_read(ptr));
ptr++;
arg_val--;
}
}
break;
case U8G_COM_MSG_ADDRESS: /* define cmd (arg_val = 0) or data mode (arg_val = 1) */
u8g_com_arduino_digital_write(u8g, U8G_PI_A0, arg_val);
break;
}
return 1;
}
#endif // HAS_MARLINUI_U8GLIB
#endif // ARDUINO_ARCH_SAM

@ -0,0 +1,203 @@
/**
* 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/>.
*
*/
/**
* HAL for Arduino Due and compatible (SAM3X8E)
*/
#ifdef ARDUINO_ARCH_SAM
#include "../../inc/MarlinConfig.h"
#include "../../MarlinCore.h"
#include <Wire.h>
#include "usb/usb_task.h"
// ------------------------
// Public Variables
// ------------------------
uint16_t MarlinHAL::adc_result;
// ------------------------
// Public functions
// ------------------------
#if ENABLED(POSTMORTEM_DEBUGGING)
extern void install_min_serial();
#endif
void MarlinHAL::init() {
#if HAS_MEDIA
OUT_WRITE(SDSS, HIGH); // Try to set SDSS inactive before any other SPI users start up
#endif
usb_task_init(); // Initialize the USB stack
TERN_(POSTMORTEM_DEBUGGING, install_min_serial()); // Install the min serial handler
}
void MarlinHAL::init_board() {
#ifdef BOARD_INIT
BOARD_INIT();
#endif
}
void MarlinHAL::idletask() { usb_task_idle(); } // Perform USB stack housekeeping
uint8_t MarlinHAL::get_reset_source() {
switch ((RSTC->RSTC_SR >> 8) & 0x07) {
case 0: return RST_POWER_ON;
case 1: return RST_BACKUP;
case 2: return RST_WATCHDOG;
case 3: return RST_SOFTWARE;
case 4: return RST_EXTERNAL;
default: return 0;
}
}
void MarlinHAL::reboot() { rstc_start_software_reset(RSTC); }
// ------------------------
// 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 unsigned int _ebss; // end of bss section
}
// Return free memory between end of heap (or end bss) and whatever is current
int freeMemory() {
int free_memory, heap_end = (int)_sbrk(0);
return (int)&free_memory - (heap_end ?: (int)&_ebss);
}
// ------------------------
// Serial Ports
// ------------------------
// Forward the default serial ports
#if USING_HW_SERIAL0
DefaultSerial1 MSerial0(false, Serial);
#endif
#if USING_HW_SERIAL1
DefaultSerial2 MSerial1(false, Serial1);
#endif
#if USING_HW_SERIAL2
DefaultSerial3 MSerial2(false, Serial2);
#endif
#if USING_HW_SERIAL3
DefaultSerial4 MSerial3(false, Serial3);
#endif
#endif // ARDUINO_ARCH_SAM

@ -0,0 +1,233 @@
/**
* 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/>.
*
*/
#pragma once
/**
* HAL for Arduino Due and compatible (SAM3X8E)
*/
#define CPU_32_BIT
#include "../shared/Marduino.h"
#include "../shared/eeprom_if.h"
#include "../shared/math_32bit.h"
#include "../shared/HAL_SPI.h"
#include "fastio.h"
#include <stdint.h>
#include "../../core/serial_hook.h"
// ------------------------
// Serial ports
// ------------------------
typedef ForwardSerial1Class< decltype(Serial) > DefaultSerial1;
typedef ForwardSerial1Class< decltype(Serial1) > DefaultSerial2;
typedef ForwardSerial1Class< decltype(Serial2) > DefaultSerial3;
typedef ForwardSerial1Class< decltype(Serial3) > DefaultSerial4;
extern DefaultSerial1 MSerial0;
extern DefaultSerial2 MSerial1;
extern DefaultSerial3 MSerial2;
extern DefaultSerial4 MSerial3;
#define _MSERIAL(X) MSerial##X
#define MSERIAL(X) _MSERIAL(X)
#if SERIAL_PORT == -1 || ENABLED(EMERGENCY_PARSER)
#define MYSERIAL1 customizedSerial1
#elif WITHIN(SERIAL_PORT, 0, 3)
#define MYSERIAL1 MSERIAL(SERIAL_PORT)
#else
#error "The required SERIAL_PORT must be from 0 to 3, or -1 for USB Serial."
#endif
#ifdef SERIAL_PORT_2
#if SERIAL_PORT_2 == -1 || ENABLED(EMERGENCY_PARSER)
#define MYSERIAL2 customizedSerial2
#elif WITHIN(SERIAL_PORT_2, 0, 3)
#define MYSERIAL2 MSERIAL(SERIAL_PORT_2)
#else
#error "SERIAL_PORT_2 must be from 0 to 3, or -1 for USB Serial."
#endif
#endif
#ifdef SERIAL_PORT_3
#if SERIAL_PORT_3 == -1 || ENABLED(EMERGENCY_PARSER)
#define MYSERIAL3 customizedSerial3
#elif WITHIN(SERIAL_PORT_3, 0, 3)
#define MYSERIAL3 MSERIAL(SERIAL_PORT_3)
#else
#error "SERIAL_PORT_3 must be from 0 to 3, or -1 for USB Serial."
#endif
#endif
#ifdef 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
#ifdef LCD_SERIAL_PORT
#if WITHIN(LCD_SERIAL_PORT, 0, 3)
#define LCD_SERIAL MSERIAL(LCD_SERIAL_PORT)
#else
#error "LCD_SERIAL_PORT must be from 0 to 3."
#endif
#endif
#include "MarlinSerial.h"
#include "MarlinSerialUSB.h"
// ------------------------
// Types
// ------------------------
typedef int8_t pin_t;
#define SHARED_SERVOS HAS_SERVOS // Use shared/servos.cpp
class Servo;
typedef Servo hal_servo_t;
//
// Interrupts
//
#define sei() interrupts()
#define cli() noInterrupts()
#define CRITICAL_SECTION_START() const bool _irqon = hal.isr_state(); hal.isr_off()
#define CRITICAL_SECTION_END() if (_irqon) hal.isr_on()
//
// ADC
//
#define HAL_ADC_VREF_MV 3300
#define HAL_ADC_RESOLUTION 10
#ifndef analogInputToDigitalPin
#define analogInputToDigitalPin(p) ((p < 12U) ? (p) + 54U : -1)
#endif
//
// Pin Mapping for M42, M43, M226
//
#define GET_PIN_MAP_PIN(index) index
#define GET_PIN_MAP_INDEX(pin) pin
#define PARSED_PIN_INDEX(code, dval) parser.intval(code, dval)
//
// Tone
//
void tone(const pin_t _pin, const unsigned int frequency, const unsigned long duration=0);
void noTone(const pin_t _pin);
// ------------------------
// Class Utilities
// ------------------------
#pragma GCC diagnostic push
#if GCC_VERSION <= 50000
#pragma GCC diagnostic ignored "-Wunused-function"
#endif
#pragma GCC diagnostic pop
#ifdef __cplusplus
extern "C" {
#endif
char *dtostrf(double __val, signed char __width, unsigned char __prec, char *__s);
#ifdef __cplusplus
}
#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);
}
};

@ -0,0 +1,819 @@
/**
* 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/>.
*
*/
/**
* Software SPI functions originally from Arduino Sd2Card Library
* Copyright (c) 2009 by William Greiman
*
* Completely rewritten and tuned by Eduardo José Tagle in 2017/2018
* in ARM thumb2 inline assembler and tuned for maximum speed and performance
* allowing SPI clocks of up to 12 Mhz to increase SD card read/write performance
*/
/**
* HAL for Arduino Due and compatible (SAM3X8E)
*/
#ifdef ARDUINO_ARCH_SAM
#include "../../inc/MarlinConfig.h"
#include "../shared/Delay.h"
// ------------------------
// Public functions
// ------------------------
#if ANY(DUE_SOFTWARE_SPI, FORCE_SOFT_SPI)
// ------------------------
// Software SPI
// ------------------------
// Make sure GCC optimizes this file.
// Note that this line triggers a bug in GCC which is fixed by casting.
// See the note below.
#pragma GCC optimize (3)
typedef uint8_t (*pfnSpiTransfer)(uint8_t b);
typedef void (*pfnSpiRxBlock)(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 */
#define _PORT(IO) DIO ## IO ## _WPORT
#define _PIN_MASK(IO) MASK(DIO ## IO ## _PIN)
#define _PIN_SHIFT(IO) DIO ## IO ## _PIN
#define PORT(IO) _PORT(IO)
#define PIN_MASK(IO) _PIN_MASK(IO)
#define PIN_SHIFT(IO) _PIN_SHIFT(IO)
// run at ~8 .. ~10Mhz - Tx version (Rx data discarded)
static uint8_t spiTransferTx0(uint8_t bout) { // using Mode 0
uint32_t MOSI_PORT_PLUS30 = ((uint32_t) PORT(SD_MOSI_PIN)) + 0x30; /* SODR of port */
uint32_t MOSI_MASK = PIN_MASK(SD_MOSI_PIN);
uint32_t SCK_PORT_PLUS30 = ((uint32_t) PORT(SD_SCK_PIN)) + 0x30; /* SODR of port */
uint32_t SCK_MASK = PIN_MASK(SD_SCK_PIN);
uint32_t idx = 0;
/* Negate bout, as the assembler requires a negated value */
bout = ~bout;
/* The software SPI routine */
__asm__ __volatile__(
A(".syntax unified") // is to prevent CM0,CM1 non-unified syntax
/* Bit 7 */
A("ubfx %[idx],%[txval],#7,#1") /* Place bit 7 in bit 0 of idx*/
A("str %[mosi_mask],[%[mosi_port], %[idx],LSL #2]") /* Access the proper SODR or CODR registers based on that bit */
A("str %[sck_mask],[%[sck_port]]") /* SODR */
A("ubfx %[idx],%[txval],#6,#1") /* Place bit 6 in bit 0 of idx*/
A("str %[sck_mask],[%[sck_port],#0x4]") /* CODR */
/* Bit 6 */
A("str %[mosi_mask],[%[mosi_port], %[idx],LSL #2]") /* Access the proper SODR or CODR registers based on that bit */
A("str %[sck_mask],[%[sck_port]]") /* SODR */
A("ubfx %[idx],%[txval],#5,#1") /* Place bit 5 in bit 0 of idx*/
A("str %[sck_mask],[%[sck_port],#0x4]") /* CODR */
/* Bit 5 */
A("str %[mosi_mask],[%[mosi_port], %[idx],LSL #2]") /* Access the proper SODR or CODR registers based on that bit */
A("str %[sck_mask],[%[sck_port]]") /* SODR */
A("ubfx %[idx],%[txval],#4,#1") /* Place bit 4 in bit 0 of idx*/
A("str %[sck_mask],[%[sck_port],#0x4]") /* CODR */
/* Bit 4 */
A("str %[mosi_mask],[%[mosi_port], %[idx],LSL #2]") /* Access the proper SODR or CODR registers based on that bit */
A("str %[sck_mask],[%[sck_port]]") /* SODR */
A("ubfx %[idx],%[txval],#3,#1") /* Place bit 3 in bit 0 of idx*/
A("str %[sck_mask],[%[sck_port],#0x4]") /* CODR */
/* Bit 3 */
A("str %[mosi_mask],[%[mosi_port], %[idx],LSL #2]") /* Access the proper SODR or CODR registers based on that bit */
A("str %[sck_mask],[%[sck_port]]") /* SODR */
A("ubfx %[idx],%[txval],#2,#1") /* Place bit 2 in bit 0 of idx*/
A("str %[sck_mask],[%[sck_port],#0x4]") /* CODR */
/* Bit 2 */
A("str %[mosi_mask],[%[mosi_port], %[idx],LSL #2]") /* Access the proper SODR or CODR registers based on that bit */
A("str %[sck_mask],[%[sck_port]]") /* SODR */
A("ubfx %[idx],%[txval],#1,#1") /* Place bit 1 in bit 0 of idx*/
A("str %[sck_mask],[%[sck_port],#0x4]") /* CODR */
/* Bit 1 */
A("str %[mosi_mask],[%[mosi_port], %[idx],LSL #2]") /* Access the proper SODR or CODR registers based on that bit */
A("str %[sck_mask],[%[sck_port]]") /* SODR */
A("ubfx %[idx],%[txval],#0,#1") /* Place bit 0 in bit 0 of idx*/
A("str %[sck_mask],[%[sck_port],#0x4]") /* CODR */
/* Bit 0 */
A("str %[mosi_mask],[%[mosi_port], %[idx],LSL #2]") /* Access the proper SODR or CODR registers based on that bit */
A("str %[sck_mask],[%[sck_port]]") /* SODR */
A("nop") /* Result will be 0 */
A("str %[sck_mask],[%[sck_port],#0x4]") /* CODR */
: [idx]"+r"( idx )
: [txval]"r"( bout ) ,
[mosi_mask]"r"( MOSI_MASK ),
[mosi_port]"r"( MOSI_PORT_PLUS30 ),
[sck_mask]"r"( SCK_MASK ),
[sck_port]"r"( SCK_PORT_PLUS30 )
: "cc"
);
return 0;
}
// Calculates the bit band alias address and returns a pointer address to word.
// addr: The byte address of bitbanding bit.
// bit: The bit position of bitbanding bit.
#define BITBAND_ADDRESS(addr, bit) \
(((uint32_t)(addr) & 0xF0000000) + 0x02000000 + ((uint32_t)(addr)&0xFFFFF)*32 + (bit)*4)
// run at ~8 .. ~10Mhz - Rx version (Tx line not altered)
static uint8_t spiTransferRx0(uint8_t) { // using Mode 0
uint32_t bin = 0;
uint32_t work = 0;
uint32_t BITBAND_MISO_PORT = BITBAND_ADDRESS( ((uint32_t)PORT(SD_MISO_PIN))+0x3C, PIN_SHIFT(SD_MISO_PIN)); /* PDSR of port in bitband area */
uint32_t SCK_PORT_PLUS30 = ((uint32_t) PORT(SD_SCK_PIN)) + 0x30; /* SODR of port */
uint32_t SCK_MASK = PIN_MASK(SD_SCK_PIN);
/* The software SPI routine */
__asm__ __volatile__(
A(".syntax unified") // is to prevent CM0,CM1 non-unified syntax
/* bit 7 */
A("str %[sck_mask],[%[sck_port]]") /* SODR */
A("ldr %[work],[%[bitband_miso_port]]") /* PDSR on bitband area for required bit: work will be 1 or 0 based on port */
A("str %[sck_mask],[%[sck_port],#0x4]") /* CODR */
A("bfi %[bin],%[work],#7,#1") /* Store read bit as the bit 7 */
/* bit 6 */
A("str %[sck_mask],[%[sck_port]]") /* SODR */
A("ldr %[work],[%[bitband_miso_port]]") /* PDSR on bitband area for required bit: work will be 1 or 0 based on port */
A("str %[sck_mask],[%[sck_port],#0x4]") /* CODR */
A("bfi %[bin],%[work],#6,#1") /* Store read bit as the bit 6 */
/* bit 5 */
A("str %[sck_mask],[%[sck_port]]") /* SODR */
A("ldr %[work],[%[bitband_miso_port]]") /* PDSR on bitband area for required bit: work will be 1 or 0 based on port */
A("str %[sck_mask],[%[sck_port],#0x4]") /* CODR */
A("bfi %[bin],%[work],#5,#1") /* Store read bit as the bit 5 */
/* bit 4 */
A("str %[sck_mask],[%[sck_port]]") /* SODR */
A("ldr %[work],[%[bitband_miso_port]]") /* PDSR on bitband area for required bit: work will be 1 or 0 based on port */
A("str %[sck_mask],[%[sck_port],#0x4]") /* CODR */
A("bfi %[bin],%[work],#4,#1") /* Store read bit as the bit 4 */
/* bit 3 */
A("str %[sck_mask],[%[sck_port]]") /* SODR */
A("ldr %[work],[%[bitband_miso_port]]") /* PDSR on bitband area for required bit: work will be 1 or 0 based on port */
A("str %[sck_mask],[%[sck_port],#0x4]") /* CODR */
A("bfi %[bin],%[work],#3,#1") /* Store read bit as the bit 3 */
/* bit 2 */
A("str %[sck_mask],[%[sck_port]]") /* SODR */
A("ldr %[work],[%[bitband_miso_port]]") /* PDSR on bitband area for required bit: work will be 1 or 0 based on port */
A("str %[sck_mask],[%[sck_port],#0x4]") /* CODR */
A("bfi %[bin],%[work],#2,#1") /* Store read bit as the bit 2 */
/* bit 1 */
A("str %[sck_mask],[%[sck_port]]") /* SODR */
A("ldr %[work],[%[bitband_miso_port]]") /* PDSR on bitband area for required bit: work will be 1 or 0 based on port */
A("str %[sck_mask],[%[sck_port],#0x4]") /* CODR */
A("bfi %[bin],%[work],#1,#1") /* Store read bit as the bit 1 */
/* bit 0 */
A("str %[sck_mask],[%[sck_port]]") /* SODR */
A("ldr %[work],[%[bitband_miso_port]]") /* PDSR on bitband area for required bit: work will be 1 or 0 based on port */
A("str %[sck_mask],[%[sck_port],#0x4]") /* CODR */
A("bfi %[bin],%[work],#0,#1") /* Store read bit as the bit 0 */
: [bin]"+r"(bin),
[work]"+r"(work)
: [bitband_miso_port]"r"( BITBAND_MISO_PORT ),
[sck_mask]"r"( SCK_MASK ),
[sck_port]"r"( SCK_PORT_PLUS30 )
: "cc"
);
return bin;
}
// run at ~4Mhz
static uint8_t spiTransfer1(uint8_t b) { // using Mode 0
int bits = 8;
do {
WRITE(SD_MOSI_PIN, b & 0x80);
b <<= 1; // little setup time
WRITE(SD_SCK_PIN, HIGH);
DELAY_NS(125); // 10 cycles @ 84mhz
b |= (READ(SD_MISO_PIN) != 0);
WRITE(SD_SCK_PIN, LOW);
DELAY_NS(125); // 10 cycles @ 84mhz
} while (--bits);
return b;
}
// all the others
static uint16_t spiDelayNS = 4000; // 4000ns => 125khz
static uint8_t spiTransferX(uint8_t b) { // using Mode 0
int bits = 8;
do {
WRITE(SD_MOSI_PIN, b & 0x80);
b <<= 1; // little setup time
WRITE(SD_SCK_PIN, HIGH);
DELAY_NS_VAR(spiDelayNS);
b |= (READ(SD_MISO_PIN) != 0);
WRITE(SD_SCK_PIN, LOW);
DELAY_NS_VAR(spiDelayNS);
} while (--bits);
return b;
}
// Pointers to generic functions for byte transfers
/**
* Note: The cast is unnecessary, but without it, this file triggers a GCC 4.8.3-2014 bug.
* Later GCC versions do not have this problem, but at this time (May 2018) Arduino still
* uses that buggy and obsolete GCC version!!
*/
static pfnSpiTransfer spiTransferRx = (pfnSpiTransfer)spiTransferX;
static pfnSpiTransfer spiTransferTx = (pfnSpiTransfer)spiTransferX;
// Block transfers run at ~8 .. ~10Mhz - Tx version (Rx data discarded)
static void spiTxBlock0(const uint8_t *ptr, uint32_t todo) {
uint32_t MOSI_PORT_PLUS30 = ((uint32_t) PORT(SD_MOSI_PIN)) + 0x30; /* SODR of port */
uint32_t MOSI_MASK = PIN_MASK(SD_MOSI_PIN);
uint32_t SCK_PORT_PLUS30 = ((uint32_t) PORT(SD_SCK_PIN)) + 0x30; /* SODR of port */
uint32_t SCK_MASK = PIN_MASK(SD_SCK_PIN);
uint32_t work = 0;
uint32_t txval = 0;
/* The software SPI routine */
__asm__ __volatile__(
A(".syntax unified") // is to prevent CM0,CM1 non-unified syntax
L("loop%=")
A("ldrb.w %[txval], [%[ptr]], #1") /* Load value to send, increment buffer */
A("mvn %[txval],%[txval]") /* Negate value */
/* Bit 7 */
A("ubfx %[work],%[txval],#7,#1") /* Place bit 7 in bit 0 of work*/
A("str %[mosi_mask],[%[mosi_port], %[work],LSL #2]") /* Access the proper SODR or CODR registers based on that bit */
A("str %[sck_mask],[%[sck_port]]") /* SODR */
A("ubfx %[work],%[txval],#6,#1") /* Place bit 6 in bit 0 of work*/
A("str %[sck_mask],[%[sck_port],#0x4]") /* CODR */
/* Bit 6 */
A("str %[mosi_mask],[%[mosi_port], %[work],LSL #2]") /* Access the proper SODR or CODR registers based on that bit */
A("str %[sck_mask],[%[sck_port]]") /* SODR */
A("ubfx %[work],%[txval],#5,#1") /* Place bit 5 in bit 0 of work*/
A("str %[sck_mask],[%[sck_port],#0x4]") /* CODR */
/* Bit 5 */
A("str %[mosi_mask],[%[mosi_port], %[work],LSL #2]") /* Access the proper SODR or CODR registers based on that bit */
A("str %[sck_mask],[%[sck_port]]") /* SODR */
A("ubfx %[work],%[txval],#4,#1") /* Place bit 4 in bit 0 of work*/
A("str %[sck_mask],[%[sck_port],#0x4]") /* CODR */
/* Bit 4 */
A("str %[mosi_mask],[%[mosi_port], %[work],LSL #2]") /* Access the proper SODR or CODR registers based on that bit */
A("str %[sck_mask],[%[sck_port]]") /* SODR */
A("ubfx %[work],%[txval],#3,#1") /* Place bit 3 in bit 0 of work*/
A("str %[sck_mask],[%[sck_port],#0x4]") /* CODR */
/* Bit 3 */
A("str %[mosi_mask],[%[mosi_port], %[work],LSL #2]") /* Access the proper SODR or CODR registers based on that bit */
A("str %[sck_mask],[%[sck_port]]") /* SODR */
A("ubfx %[work],%[txval],#2,#1") /* Place bit 2 in bit 0 of work*/
A("str %[sck_mask],[%[sck_port],#0x4]") /* CODR */
/* Bit 2 */
A("str %[mosi_mask],[%[mosi_port], %[work],LSL #2]") /* Access the proper SODR or CODR registers based on that bit */
A("str %[sck_mask],[%[sck_port]]") /* SODR */
A("ubfx %[work],%[txval],#1,#1") /* Place bit 1 in bit 0 of work*/
A("str %[sck_mask],[%[sck_port],#0x4]") /* CODR */
/* Bit 1 */
A("str %[mosi_mask],[%[mosi_port], %[work],LSL #2]") /* Access the proper SODR or CODR registers based on that bit */
A("str %[sck_mask],[%[sck_port]]") /* SODR */
A("ubfx %[work],%[txval],#0,#1") /* Place bit 0 in bit 0 of work*/
A("str %[sck_mask],[%[sck_port],#0x4]") /* CODR */
/* Bit 0 */
A("str %[mosi_mask],[%[mosi_port], %[work],LSL #2]") /* Access the proper SODR or CODR registers based on that bit */
A("str %[sck_mask],[%[sck_port]]") /* SODR */
A("subs %[todo],#1") /* Decrement count of pending words to send, update status */
A("str %[sck_mask],[%[sck_port],#0x4]") /* CODR */
A("bne.n loop%=") /* Repeat until done */
: [ptr]"+r" ( ptr ) ,
[todo]"+r" ( todo ) ,
[work]"+r"( work ) ,
[txval]"+r"( txval )
: [mosi_mask]"r"( MOSI_MASK ),
[mosi_port]"r"( MOSI_PORT_PLUS30 ),
[sck_mask]"r"( SCK_MASK ),
[sck_port]"r"( SCK_PORT_PLUS30 )
: "cc"
);
}
static void spiRxBlock0(uint8_t *ptr, uint32_t todo) {
uint32_t bin = 0;
uint32_t work = 0;
uint32_t BITBAND_MISO_PORT = BITBAND_ADDRESS( ((uint32_t)PORT(SD_MISO_PIN))+0x3C, PIN_SHIFT(SD_MISO_PIN)); /* PDSR of port in bitband area */
uint32_t SCK_PORT_PLUS30 = ((uint32_t) PORT(SD_SCK_PIN)) + 0x30; /* SODR of port */
uint32_t SCK_MASK = PIN_MASK(SD_SCK_PIN);
/* The software SPI routine */
__asm__ __volatile__(
A(".syntax unified") // is to prevent CM0,CM1 non-unified syntax
L("loop%=")
/* bit 7 */
A("str %[sck_mask],[%[sck_port]]") /* SODR */
A("ldr %[work],[%[bitband_miso_port]]") /* PDSR on bitband area for required bit: work will be 1 or 0 based on port */
A("str %[sck_mask],[%[sck_port],#0x4]") /* CODR */
A("bfi %[bin],%[work],#7,#1") /* Store read bit as the bit 7 */
/* bit 6 */
A("str %[sck_mask],[%[sck_port]]") /* SODR */
A("ldr %[work],[%[bitband_miso_port]]") /* PDSR on bitband area for required bit: work will be 1 or 0 based on port */
A("str %[sck_mask],[%[sck_port],#0x4]") /* CODR */
A("bfi %[bin],%[work],#6,#1") /* Store read bit as the bit 6 */
/* bit 5 */
A("str %[sck_mask],[%[sck_port]]") /* SODR */
A("ldr %[work],[%[bitband_miso_port]]") /* PDSR on bitband area for required bit: work will be 1 or 0 based on port */
A("str %[sck_mask],[%[sck_port],#0x4]") /* CODR */
A("bfi %[bin],%[work],#5,#1") /* Store read bit as the bit 5 */
/* bit 4 */
A("str %[sck_mask],[%[sck_port]]") /* SODR */
A("ldr %[work],[%[bitband_miso_port]]") /* PDSR on bitband area for required bit: work will be 1 or 0 based on port */
A("str %[sck_mask],[%[sck_port],#0x4]") /* CODR */
A("bfi %[bin],%[work],#4,#1") /* Store read bit as the bit 4 */
/* bit 3 */
A("str %[sck_mask],[%[sck_port]]") /* SODR */
A("ldr %[work],[%[bitband_miso_port]]") /* PDSR on bitband area for required bit: work will be 1 or 0 based on port */
A("str %[sck_mask],[%[sck_port],#0x4]") /* CODR */
A("bfi %[bin],%[work],#3,#1") /* Store read bit as the bit 3 */
/* bit 2 */
A("str %[sck_mask],[%[sck_port]]") /* SODR */
A("ldr %[work],[%[bitband_miso_port]]") /* PDSR on bitband area for required bit: work will be 1 or 0 based on port */
A("str %[sck_mask],[%[sck_port],#0x4]") /* CODR */
A("bfi %[bin],%[work],#2,#1") /* Store read bit as the bit 2 */
/* bit 1 */
A("str %[sck_mask],[%[sck_port]]") /* SODR */
A("ldr %[work],[%[bitband_miso_port]]") /* PDSR on bitband area for required bit: work will be 1 or 0 based on port */
A("str %[sck_mask],[%[sck_port],#0x4]") /* CODR */
A("bfi %[bin],%[work],#1,#1") /* Store read bit as the bit 1 */
/* bit 0 */
A("str %[sck_mask],[%[sck_port]]") /* SODR */
A("ldr %[work],[%[bitband_miso_port]]") /* PDSR on bitband area for required bit: work will be 1 or 0 based on port */
A("str %[sck_mask],[%[sck_port],#0x4]") /* CODR */
A("bfi %[bin],%[work],#0,#1") /* Store read bit as the bit 0 */
A("subs %[todo],#1") /* Decrement count of pending words to send, update status */
A("strb.w %[bin], [%[ptr]], #1") /* Store read value into buffer, increment buffer pointer */
A("bne.n loop%=") /* Repeat until done */
: [ptr]"+r"(ptr),
[todo]"+r"(todo),
[bin]"+r"(bin),
[work]"+r"(work)
: [bitband_miso_port]"r"( BITBAND_MISO_PORT ),
[sck_mask]"r"( SCK_MASK ),
[sck_port]"r"( SCK_PORT_PLUS30 )
: "cc"
);
}
static void spiTxBlockX(const uint8_t *buf, uint32_t todo) {
do {
(void)spiTransferTx(*buf++);
} while (--todo);
}
static void spiRxBlockX(uint8_t *buf, uint32_t todo) {
do {
*buf++ = spiTransferRx(0xFF);
} while (--todo);
}
// Pointers to generic functions for block transfers
static pfnSpiTxBlock spiTxBlock = (pfnSpiTxBlock)spiTxBlockX;
static pfnSpiRxBlock spiRxBlock = (pfnSpiRxBlock)spiRxBlockX;
#if MB(ALLIGATOR)
#define _SS_WRITE(S) WRITE(SD_SS_PIN, S)
#else
#define _SS_WRITE(S) NOOP
#endif
void spiBegin() {
SET_OUTPUT(SD_SS_PIN);
_SS_WRITE(HIGH);
SET_OUTPUT(SD_SCK_PIN);
SET_INPUT(SD_MISO_PIN);
SET_OUTPUT(SD_MOSI_PIN);
}
uint8_t spiRec() {
_SS_WRITE(LOW);
WRITE(SD_MOSI_PIN, HIGH); // Output 1s 1
uint8_t b = spiTransferRx(0xFF);
_SS_WRITE(HIGH);
return b;
}
void spiRead(uint8_t *buf, uint16_t nbyte) {
if (nbyte) {
_SS_WRITE(LOW);
WRITE(SD_MOSI_PIN, HIGH); // Output 1s 1
spiRxBlock(buf, nbyte);
_SS_WRITE(HIGH);
}
}
void spiSend(uint8_t b) {
_SS_WRITE(LOW);
(void)spiTransferTx(b);
_SS_WRITE(HIGH);
}
void spiSendBlock(uint8_t token, const uint8_t *buf) {
_SS_WRITE(LOW);
(void)spiTransferTx(token);
spiTxBlock(buf, 512);
_SS_WRITE(HIGH);
}
/**
* spiRate should be
* 0 : 8 - 10 MHz
* 1 : 4 - 5 MHz
* 2 : 2 - 2.5 MHz
* 3 : 1 - 1.25 MHz
* 4 : 500 - 625 kHz
* 5 : 250 - 312 kHz
* 6 : 125 - 156 kHz
*/
void spiInit(uint8_t spiRate) {
switch (spiRate) {
case 0:
spiTransferTx = (pfnSpiTransfer)spiTransferTx0;
spiTransferRx = (pfnSpiTransfer)spiTransferRx0;
spiTxBlock = (pfnSpiTxBlock)spiTxBlock0;
spiRxBlock = (pfnSpiRxBlock)spiRxBlock0;
break;
case 1:
spiTransferTx = (pfnSpiTransfer)spiTransfer1;
spiTransferRx = (pfnSpiTransfer)spiTransfer1;
spiTxBlock = (pfnSpiTxBlock)spiTxBlockX;
spiRxBlock = (pfnSpiRxBlock)spiRxBlockX;
break;
default:
spiDelayNS = 4000 >> (6 - spiRate); // spiRate of 2 gives the maximum error with current CPU
spiTransferTx = (pfnSpiTransfer)spiTransferX;
spiTransferRx = (pfnSpiTransfer)spiTransferX;
spiTxBlock = (pfnSpiTxBlock)spiTxBlockX;
spiRxBlock = (pfnSpiRxBlock)spiRxBlockX;
break;
}
_SS_WRITE(HIGH);
WRITE(SD_MOSI_PIN, HIGH);
WRITE(SD_SCK_PIN, LOW);
}
/** Begin SPI transaction, set clock, bit order, data mode */
void spiBeginTransaction(uint32_t spiClock, uint8_t bitOrder, uint8_t dataMode) {
// TODO: to be implemented
}
#pragma GCC reset_options
#else // !SOFTWARE_SPI
#define WHILE_TX(N) while ((SPI0->SPI_SR & SPI_SR_TDRE) == (N))
#define WHILE_RX(N) while ((SPI0->SPI_SR & SPI_SR_RDRF) == (N))
#define FLUSH_TX() do{ WHILE_RX(1) SPI0->SPI_RDR; }while(0)
#if MB(ALLIGATOR)
// slave selects controlled by SPI controller
// doesn't support changing SPI speeds for SD card
// ------------------------
// hardware SPI
// ------------------------
static bool spiInitialized = false;
void spiInit(uint8_t spiRate) {
if (spiInitialized) return;
// 8.4 MHz, 4 MHz, 2 MHz, 1 MHz, 0.5 MHz, 0.329 MHz, 0.329 MHz
constexpr int spiDivider[] = { 10, 21, 42, 84, 168, 255, 255 };
if (spiRate > 6) spiRate = 1;
// Set SPI mode 1, clock, select not active after transfer, with delay between transfers
SPI_ConfigureNPCS(SPI0, SPI_CHAN_DAC,
SPI_CSR_CSAAT | SPI_CSR_SCBR(spiDivider[spiRate]) |
SPI_CSR_DLYBCT(1));
// Set SPI mode 0, clock, select not active after transfer, with delay between transfers
SPI_ConfigureNPCS(SPI0, SPI_CHAN_EEPROM1, SPI_CSR_NCPHA |
SPI_CSR_CSAAT | SPI_CSR_SCBR(spiDivider[spiRate]) |
SPI_CSR_DLYBCT(1));
// Set SPI mode 0, clock, select not active after transfer, with delay between transfers
SPI_ConfigureNPCS(SPI0, SPI_CHAN, SPI_CSR_NCPHA |
SPI_CSR_CSAAT | SPI_CSR_SCBR(spiDivider[spiRate]) |
SPI_CSR_DLYBCT(1));
SPI_Enable(SPI0);
spiInitialized = true;
}
void spiBegin() {
if (spiInitialized) return;
// Configure SPI pins
PIO_Configure(
g_APinDescription[SD_SCK_PIN].pPort,
g_APinDescription[SD_SCK_PIN].ulPinType,
g_APinDescription[SD_SCK_PIN].ulPin,
g_APinDescription[SD_SCK_PIN].ulPinConfiguration);
PIO_Configure(
g_APinDescription[SD_MOSI_PIN].pPort,
g_APinDescription[SD_MOSI_PIN].ulPinType,
g_APinDescription[SD_MOSI_PIN].ulPin,
g_APinDescription[SD_MOSI_PIN].ulPinConfiguration);
PIO_Configure(
g_APinDescription[SD_MISO_PIN].pPort,
g_APinDescription[SD_MISO_PIN].ulPinType,
g_APinDescription[SD_MISO_PIN].ulPin,
g_APinDescription[SD_MISO_PIN].ulPinConfiguration);
// set master mode, peripheral select, fault detection
SPI_Configure(SPI0, ID_SPI0, SPI_MR_MSTR | SPI_MR_MODFDIS | SPI_MR_PS);
SPI_Enable(SPI0);
SET_OUTPUT(DAC0_SYNC_PIN);
#if HAS_MULTI_EXTRUDER
OUT_WRITE(DAC1_SYNC_PIN, HIGH);
#endif
WRITE(DAC0_SYNC_PIN, HIGH);
OUT_WRITE(SPI_EEPROM1_CS_PIN, HIGH);
OUT_WRITE(SPI_EEPROM2_CS_PIN, HIGH);
OUT_WRITE(SPI_FLASH_CS_PIN, HIGH);
WRITE(SD_SS_PIN, HIGH);
OUT_WRITE(SDSS, LOW);
PIO_Configure(
g_APinDescription[SPI_PIN].pPort,
g_APinDescription[SPI_PIN].ulPinType,
g_APinDescription[SPI_PIN].ulPin,
g_APinDescription[SPI_PIN].ulPinConfiguration
);
spiInit(1);
}
// Read single byte from SPI
uint8_t spiRec() {
// write dummy byte with address and end transmission flag
SPI0->SPI_TDR = 0x000000FF | SPI_PCS(SPI_CHAN) | SPI_TDR_LASTXFER;
WHILE_TX(0);
WHILE_RX(0);
//DELAY_US(1U);
return SPI0->SPI_RDR;
}
uint8_t spiRec(uint32_t chan) {
WHILE_TX(0);
FLUSH_RX();
// write dummy byte with address and end transmission flag
SPI0->SPI_TDR = 0x000000FF | SPI_PCS(chan) | SPI_TDR_LASTXFER;
WHILE_RX(0);
return SPI0->SPI_RDR;
}
// Read from SPI into buffer
void spiRead(uint8_t *buf, uint16_t nbyte) {
if (!nbyte) return;
--nbyte;
for (int i = 0; i < nbyte; i++) {
//WHILE_TX(0);
SPI0->SPI_TDR = 0x000000FF | SPI_PCS(SPI_CHAN);
WHILE_RX(0);
buf[i] = SPI0->SPI_RDR;
//DELAY_US(1U);
}
buf[nbyte] = spiRec();
}
// Write single byte to SPI
void spiSend(const byte b) {
// write byte with address and end transmission flag
SPI0->SPI_TDR = (uint32_t)b | SPI_PCS(SPI_CHAN) | SPI_TDR_LASTXFER;
WHILE_TX(0);
WHILE_RX(0);
SPI0->SPI_RDR;
//DELAY_US(1U);
}
void spiSend(const uint8_t *buf, size_t nbyte) {
if (!nbyte) return;
--nbyte;
for (size_t i = 0; i < nbyte; i++) {
SPI0->SPI_TDR = (uint32_t)buf[i] | SPI_PCS(SPI_CHAN);
WHILE_TX(0);
WHILE_RX(0);
SPI0->SPI_RDR;
//DELAY_US(1U);
}
spiSend(buf[nbyte]);
}
void spiSend(uint32_t chan, byte b) {
WHILE_TX(0);
// write byte with address and end transmission flag
SPI0->SPI_TDR = (uint32_t)b | SPI_PCS(chan) | SPI_TDR_LASTXFER;
WHILE_RX(0);
FLUSH_RX();
}
void spiSend(uint32_t chan, const uint8_t *buf, size_t nbyte) {
if (!nbyte) return;
--nbyte;
for (size_t i = 0; i < nbyte; i++) {
WHILE_TX(0);
SPI0->SPI_TDR = (uint32_t)buf[i] | SPI_PCS(chan);
WHILE_RX(0);
FLUSH_RX();
}
spiSend(chan, buf[nbyte]);
}
// Write from buffer to SPI
void spiSendBlock(uint8_t token, const uint8_t *buf) {
SPI0->SPI_TDR = (uint32_t)token | SPI_PCS(SPI_CHAN);
WHILE_TX(0);
//WHILE_RX(0);
//SPI0->SPI_RDR;
for (int i = 0; i < 511; i++) {
SPI0->SPI_TDR = (uint32_t)buf[i] | SPI_PCS(SPI_CHAN);
WHILE_TX(0);
WHILE_RX(0);
SPI0->SPI_RDR;
//DELAY_US(1U);
}
spiSend(buf[511]);
}
/** Begin SPI transaction, set clock, bit order, data mode */
void spiBeginTransaction(uint32_t spiClock, uint8_t bitOrder, uint8_t dataMode) {
// TODO: to be implemented
}
#else // U8G compatible hardware SPI
#define SPI_MODE_0_DUE_HW 2 // DUE CPHA control bit is inverted
#define SPI_MODE_1_DUE_HW 3
#define SPI_MODE_2_DUE_HW 0
#define SPI_MODE_3_DUE_HW 1
/**
* The DUE SPI controller is set up so the upper word of the longword
* written to the transmit data register selects which SPI Chip Select
* Register is used. This allows different streams to have different SPI
* settings.
*
* In practice it's spooky. Some combinations hang the system, while others
* upset the peripheral device.
*
* SPI mode should be the same for all streams. The FYSETC_MINI_12864 gets
* upset if the clock phase changes after chip select goes active.
*
* SPI_CSR_CSAAT should be set for all streams. If not the WHILE_TX(0)
* macro returns immediately which can result in the SPI chip select going
* inactive before all the data has been sent.
*
* The TMC2130 library uses SPI0->SPI_CSR[3].
*
* The U8G hardware SPI uses SPI0->SPI_CSR[0]. The system hangs and/or the
* FYSETC_MINI_12864 gets upset if lower baud rates are used and the SD card
* is inserted or removed.
*
* The SD card uses SPI0->SPI_CSR[3]. Efforts were made to use [1] and [2]
* but they all resulted in hangs or garbage on the LCD.
*
* The SPI controlled chip selects are NOT enabled in the GPIO controller.
* The application must control the chip select.
*
* All of the above can be avoided by defining FORCE_SOFT_SPI to force the
* display to use software SPI.
*/
void spiInit(uint8_t spiRate=6) { // Default to slowest rate if not specified)
// Also sets U8G SPI rate to 4MHz and the SPI mode to 3
// 8.4 MHz, 4 MHz, 2 MHz, 1 MHz, 0.5 MHz, 0.329 MHz, 0.329 MHz
constexpr int spiDivider[] = { 10, 21, 42, 84, 168, 255, 255 };
if (spiRate > 6) spiRate = 1;
// Enable PIOA and SPI0
REG_PMC_PCER0 = (1UL << ID_PIOA) | (1UL << ID_SPI0);
// Disable PIO on A26 and A27
REG_PIOA_PDR = 0x0C000000;
OUT_WRITE(SDSS, HIGH);
// Reset SPI0 (from sam lib)
SPI0->SPI_CR = SPI_CR_SPIDIS;
SPI0->SPI_CR = SPI_CR_SWRST;
SPI0->SPI_CR = SPI_CR_SWRST;
SPI0->SPI_CR = SPI_CR_SPIEN;
// TMC2103 compatible setup
// Master mode, no fault detection, PCS bits in data written to TDR select CSR register
SPI0->SPI_MR = SPI_MR_MSTR | SPI_MR_PS | SPI_MR_MODFDIS;
// SPI mode 3, 8 Bit data transfer, baud rate
SPI0->SPI_CSR[3] = SPI_CSR_SCBR(spiDivider[spiRate]) | SPI_CSR_CSAAT | SPI_MODE_3_DUE_HW; // use same CSR as TMC2130
SPI0->SPI_CSR[0] = SPI_CSR_SCBR(spiDivider[1]) | SPI_CSR_CSAAT | SPI_MODE_3_DUE_HW; // U8G default to 4MHz
}
void spiBegin() { spiInit(); }
static uint8_t spiTransfer(uint8_t data) {
WHILE_TX(0);
SPI0->SPI_TDR = (uint32_t)data | 0x00070000UL; // Add TMC2130 PCS bits to every byte (use SPI0->SPI_CSR[3])
WHILE_TX(0);
WHILE_RX(0);
return SPI0->SPI_RDR;
}
uint8_t spiRec() { return (uint8_t)spiTransfer(0xFF); }
void spiRead(uint8_t *buf, uint16_t nbyte) {
for (int i = 0; i < nbyte; i++)
buf[i] = spiTransfer(0xFF);
}
void spiSend(uint8_t data) { spiTransfer(data); }
void spiSend(const uint8_t *buf, size_t nbyte) {
for (uint16_t i = 0; i < nbyte; i++)
spiTransfer(buf[i]);
}
void spiSendBlock(uint8_t token, const uint8_t *buf) {
spiTransfer(token);
for (uint16_t i = 0; i < 512; i++)
spiTransfer(buf[i]);
}
#endif // !ALLIGATOR
#endif // !SOFTWARE_SPI
#endif // ARDUINO_ARCH_SAM

@ -0,0 +1,98 @@
/**
* 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/>.
*
*/
/**
* InterruptVectors_Due.cpp - This module relocates the Interrupt vector table to SRAM,
* allowing to register new interrupt handlers at runtime. Specially valuable and needed
* because Arduino runtime allocates some interrupt handlers that we NEED to override to
* properly support extended functionality, as for example, USB host or USB device (MSD, MTP)
* and custom serial port handlers, and we don't actually want to modify and/or recompile the
* Arduino runtime. We just want to run as much as possible on Stock Arduino
*
* Copyright (c) 2017 Eduardo José Tagle. All right reserved
*/
#ifdef ARDUINO_ARCH_SAM
#include "../../inc/MarlinConfig.h"
#include "HAL.h"
#include "InterruptVectors.h"
/* The relocated Exception/Interrupt Table - According to the ARM
reference manual, alignment to 128 bytes should suffice, but in
practice, we need alignment to 256 bytes to make this work in all
cases */
__attribute__ ((aligned(256)))
static DeviceVectors ram_tab[61] = { nullptr };
/**
* This function checks if the exception/interrupt table is already in SRAM or not.
* If it is not, then it copies the ROM table to the SRAM and relocates the table
* by reprogramming the NVIC registers
*/
static pfnISR_Handler* get_relocated_table_addr() {
// Get the address of the interrupt/exception table
uint32_t isrtab = SCB->VTOR;
// If already relocated, we are done!
if (isrtab >= IRAM0_ADDR)
return (pfnISR_Handler*)isrtab;
// Get the address of the table stored in FLASH
const pfnISR_Handler* romtab = (const pfnISR_Handler*)isrtab;
// Copy it to SRAM
memcpy(&ram_tab, romtab, sizeof(ram_tab));
// Disable global interrupts
CRITICAL_SECTION_START();
// Set the vector table base address to the SRAM copy
SCB->VTOR = (uint32_t)(&ram_tab);
// Reenable interrupts
CRITICAL_SECTION_END();
// Return the address of the table
return (pfnISR_Handler*)(&ram_tab);
}
pfnISR_Handler install_isr(IRQn_Type irq, pfnISR_Handler newHandler) {
// Get the address of the relocated table
pfnISR_Handler *isrtab = get_relocated_table_addr();
// Disable global interrupts
CRITICAL_SECTION_START();
// Get the original handler
pfnISR_Handler oldHandler = isrtab[irq + 16];
// Install the new one
isrtab[irq + 16] = newHandler;
// Reenable interrupts
CRITICAL_SECTION_END();
// Return the original one
return oldHandler;
}
#endif

@ -0,0 +1,45 @@
/**
* 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/>.
*
*/
#pragma once
/**
* InterruptVectors_Due.h
*
* This module relocates the Interrupt vector table to SRAM, allowing new
* interrupt handlers to be added at runtime. This is required because the
* Arduino runtime steals interrupt handlers that Marlin MUST use to support
* extended functionality such as USB hosts and USB devices (MSD, MTP) and
* custom serial port handlers. Rather than modifying and/or recompiling the
* Arduino runtime, We just want to run as much as possible on Stock Arduino.
*
* Copyright (c) 2017 Eduardo José Tagle. All right reserved
*/
#ifdef ARDUINO_ARCH_SAM
// ISR handler type
typedef void (*pfnISR_Handler)();
// Install a new interrupt vector handler for the given irq, returning the old one
pfnISR_Handler install_isr(IRQn_Type irq, pfnISR_Handler newHandler);
#endif // ARDUINO_ARCH_SAM

@ -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;

@ -0,0 +1,494 @@
/**
* 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/>.
*
*/
/**
* MarlinSerial_Due.cpp - Hardware serial library for Arduino DUE
* Copyright (c) 2017 Eduardo José Tagle. 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 "MarlinSerial.h"
#include "InterruptVectors.h"
#include "../../MarlinCore.h"
template<typename Cfg> typename MarlinSerial<Cfg>::ring_buffer_r MarlinSerial<Cfg>::rx_buffer = { 0, 0, { 0 } };
template<typename Cfg> typename MarlinSerial<Cfg>::ring_buffer_t MarlinSerial<Cfg>::tx_buffer = { 0 };
template<typename Cfg> bool MarlinSerial<Cfg>::_written = false;
template<typename Cfg> uint8_t MarlinSerial<Cfg>::xon_xoff_state = MarlinSerial<Cfg>::XON_XOFF_CHAR_SENT | MarlinSerial<Cfg>::XON_CHAR;
template<typename Cfg> uint8_t MarlinSerial<Cfg>::rx_dropped_bytes = 0;
template<typename Cfg> uint8_t MarlinSerial<Cfg>::rx_buffer_overruns = 0;
template<typename Cfg> uint8_t MarlinSerial<Cfg>::rx_framing_errors = 0;
template<typename Cfg> typename MarlinSerial<Cfg>::ring_buffer_pos_t MarlinSerial<Cfg>::rx_max_enqueued = 0;
// A SW memory barrier, to ensure GCC does not overoptimize loops
#define sw_barrier() asm volatile("": : :"memory");
#include "../../feature/e_parser.h"
// (called with RX interrupts disabled)
template<typename Cfg>
FORCE_INLINE void MarlinSerial<Cfg>::store_rxd_char() {
static EmergencyParser::State emergency_state; // = EP_RESET
// Get the tail - Nothing can alter its value while we are at this ISR
const ring_buffer_pos_t t = rx_buffer.tail;
// Get the head pointer
ring_buffer_pos_t h = rx_buffer.head;
// Get the next element
ring_buffer_pos_t i = (ring_buffer_pos_t)(h + 1) & (ring_buffer_pos_t)(Cfg::RX_SIZE - 1);
// Read the character from the USART
uint8_t c = HWUART->UART_RHR;
if (Cfg::EMERGENCYPARSER) emergency_parser.update(emergency_state, c);
// If the character is to be stored at the index just before the tail
// (such that the head would advance to the current tail), the RX FIFO is
// full, so don't write the character or advance the head.
if (i != t) {
rx_buffer.buffer[h] = c;
h = i;
}
else if (Cfg::DROPPED_RX && !++rx_dropped_bytes)
--rx_dropped_bytes;
const ring_buffer_pos_t rx_count = (ring_buffer_pos_t)(h - t) & (ring_buffer_pos_t)(Cfg::RX_SIZE - 1);
// Calculate count of bytes stored into the RX buffer
// Keep track of the maximum count of enqueued bytes
if (Cfg::MAX_RX_QUEUED) NOLESS(rx_max_enqueued, rx_count);
if (Cfg::XONOFF) {
// If the last char that was sent was an XON
if ((xon_xoff_state & XON_XOFF_CHAR_MASK) == XON_CHAR) {
// Bytes stored into the RX buffer
const ring_buffer_pos_t rx_count = (ring_buffer_pos_t)(h - t) & (ring_buffer_pos_t)(Cfg::RX_SIZE - 1);
// If over 12.5% of RX buffer capacity, send XOFF before running out of
// RX buffer space .. 325 bytes @ 250kbits/s needed to let the host react
// and stop sending bytes. This translates to 13mS propagation time.
if (rx_count >= (Cfg::RX_SIZE) / 8) {
// At this point, definitely no TX interrupt was executing, since the TX isr can't be preempted.
// Don't enable the TX interrupt here as a means to trigger the XOFF char, because if it happens
// to be in the middle of trying to disable the RX interrupt in the main program, eventually the
// enabling of the TX interrupt could be undone. The ONLY reliable thing this can do to ensure
// the sending of the XOFF char is to send it HERE AND NOW.
// About to send the XOFF char
xon_xoff_state = XOFF_CHAR | XON_XOFF_CHAR_SENT;
// Wait until the TX register becomes empty and send it - Here there could be a problem
// - While waiting for the TX register to empty, the RX register could receive a new
// character. This must also handle that situation!
uint32_t status;
while (!((status = HWUART->UART_SR) & UART_SR_TXRDY)) {
if (status & UART_SR_RXRDY) {
// We received a char while waiting for the TX buffer to be empty - Receive and process it!
i = (ring_buffer_pos_t)(h + 1) & (ring_buffer_pos_t)(Cfg::RX_SIZE - 1);
// Read the character from the USART
c = HWUART->UART_RHR;
if (Cfg::EMERGENCYPARSER) emergency_parser.update(emergency_state, c);
// If the character is to be stored at the index just before the tail
// (such that the head would advance to the current tail), the FIFO is
// full, so don't write the character or advance the head.
if (i != t) {
rx_buffer.buffer[h] = c;
h = i;
}
else if (Cfg::DROPPED_RX && !++rx_dropped_bytes)
--rx_dropped_bytes;
}
sw_barrier();
}
HWUART->UART_THR = XOFF_CHAR;
// At this point there could be a race condition between the write() function
// and this sending of the XOFF char. This interrupt could happen between the
// wait to be empty TX buffer loop and the actual write of the character. Since
// the TX buffer is full because it's sending the XOFF char, the only way to be
// sure the write() function will succeed is to wait for the XOFF char to be
// completely sent. Since an extra character could be received during the wait
// it must also be handled!
while (!((status = HWUART->UART_SR) & UART_SR_TXRDY)) {
if (status & UART_SR_RXRDY) {
// A char arrived while waiting for the TX buffer to be empty - Receive and process it!
i = (ring_buffer_pos_t)(h + 1) & (ring_buffer_pos_t)(Cfg::RX_SIZE - 1);
// Read the character from the USART
c = HWUART->UART_RHR;
if (Cfg::EMERGENCYPARSER) emergency_parser.update(emergency_state, c);
// If the character is to be stored at the index just before the tail
// (such that the head would advance to the current tail), the FIFO is
// full, so don't write the character or advance the head.
if (i != t) {
rx_buffer.buffer[h] = c;
h = i;
}
else if (Cfg::DROPPED_RX && !++rx_dropped_bytes)
--rx_dropped_bytes;
}
sw_barrier();
}
// At this point everything is ready. The write() function won't
// have any issues writing to the UART TX register if it needs to!
}
}
}
// Store the new head value
rx_buffer.head = h;
}
template<typename Cfg>
FORCE_INLINE void MarlinSerial<Cfg>::_tx_thr_empty_irq() {
if (Cfg::TX_SIZE > 0) {
// Read positions
uint8_t t = tx_buffer.tail;
const uint8_t h = tx_buffer.head;
if (Cfg::XONOFF) {
// If an XON char is pending to be sent, do it now
if (xon_xoff_state == XON_CHAR) {
// Send the character
HWUART->UART_THR = XON_CHAR;
// Remember we sent it.
xon_xoff_state = XON_CHAR | XON_XOFF_CHAR_SENT;
// If nothing else to transmit, just disable TX interrupts.
if (h == t) HWUART->UART_IDR = UART_IDR_TXRDY;
return;
}
}
// If nothing to transmit, just disable TX interrupts. This could
// happen as the result of the non atomicity of the disabling of RX
// interrupts that could end reenabling TX interrupts as a side effect.
if (h == t) {
HWUART->UART_IDR = UART_IDR_TXRDY;
return;
}
// There is something to TX, Send the next byte
const uint8_t c = tx_buffer.buffer[t];
t = (t + 1) & (Cfg::TX_SIZE - 1);
HWUART->UART_THR = c;
tx_buffer.tail = t;
// Disable interrupts if there is nothing to transmit following this byte
if (h == t) HWUART->UART_IDR = UART_IDR_TXRDY;
}
}
template<typename Cfg>
void MarlinSerial<Cfg>::UART_ISR() {
const uint32_t status = HWUART->UART_SR;
// Data received?
if (status & UART_SR_RXRDY) store_rxd_char();
if (Cfg::TX_SIZE > 0) {
// Something to send, and TX interrupts are enabled (meaning something to send)?
if ((status & UART_SR_TXRDY) && (HWUART->UART_IMR & UART_IMR_TXRDY)) _tx_thr_empty_irq();
}
// Acknowledge errors
if ((status & UART_SR_OVRE) || (status & UART_SR_FRAME)) {
if (Cfg::DROPPED_RX && (status & UART_SR_OVRE) && !++rx_dropped_bytes) --rx_dropped_bytes;
if (Cfg::RX_OVERRUNS && (status & UART_SR_OVRE) && !++rx_buffer_overruns) --rx_buffer_overruns;
if (Cfg::RX_FRAMING_ERRORS && (status & UART_SR_FRAME) && !++rx_framing_errors) --rx_framing_errors;
// TODO: error reporting outside ISR
HWUART->UART_CR = UART_CR_RSTSTA;
}
}
// Public Methods
template<typename Cfg>
void MarlinSerial<Cfg>::begin(const long baud_setting) {
// Disable UART interrupt in NVIC
NVIC_DisableIRQ( HWUART_IRQ );
// We NEED memory barriers to ensure Interrupts are actually disabled!
// ( https://dzone.com/articles/nvic-disabling-interrupts-on-arm-cortex-m-and-the )
__DSB();
__ISB();
// Disable clock
pmc_disable_periph_clk( HWUART_IRQ_ID );
// Configure PMC
pmc_enable_periph_clk( HWUART_IRQ_ID );
// Disable PDC channel
HWUART->UART_PTCR = UART_PTCR_RXTDIS | UART_PTCR_TXTDIS;
// Reset and disable receiver and transmitter
HWUART->UART_CR = UART_CR_RSTRX | UART_CR_RSTTX | UART_CR_RXDIS | UART_CR_TXDIS;
// Configure mode: 8bit, No parity, 1 bit stop
HWUART->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)
HWUART->UART_BRGR = (SystemCoreClock / (baud_setting << 4));
// Configure interrupts
HWUART->UART_IDR = 0xFFFFFFFF;
HWUART->UART_IER = UART_IER_RXRDY | UART_IER_OVRE | UART_IER_FRAME;
// Install interrupt handler
install_isr(HWUART_IRQ, UART_ISR);
// Configure priority. We need a very high priority to avoid losing characters
// and we need to be able to preempt the Stepper ISR and everything else!
// (this could probably be fixed by using DMA with the Serial port)
NVIC_SetPriority(HWUART_IRQ, 1);
// Enable UART interrupt in NVIC
NVIC_EnableIRQ(HWUART_IRQ);
// Enable receiver and transmitter
HWUART->UART_CR = UART_CR_RXEN | UART_CR_TXEN;
if (Cfg::TX_SIZE > 0) _written = false;
}
template<typename Cfg>
void MarlinSerial<Cfg>::end() {
// Disable UART interrupt in NVIC
NVIC_DisableIRQ( HWUART_IRQ );
// We NEED memory barriers to ensure Interrupts are actually disabled!
// ( https://dzone.com/articles/nvic-disabling-interrupts-on-arm-cortex-m-and-the )
__DSB();
__ISB();
pmc_disable_periph_clk( HWUART_IRQ_ID );
}
template<typename Cfg>
int MarlinSerial<Cfg>::peek() {
const int v = rx_buffer.head == rx_buffer.tail ? -1 : rx_buffer.buffer[rx_buffer.tail];
return v;
}
template<typename Cfg>
int MarlinSerial<Cfg>::read() {
const ring_buffer_pos_t h = rx_buffer.head;
ring_buffer_pos_t t = rx_buffer.tail;
if (h == t) return -1;
int v = rx_buffer.buffer[t];
t = (ring_buffer_pos_t)(t + 1) & (Cfg::RX_SIZE - 1);
// Advance tail
rx_buffer.tail = t;
if (Cfg::XONOFF) {
// If the XOFF char was sent, or about to be sent...
if ((xon_xoff_state & XON_XOFF_CHAR_MASK) == XOFF_CHAR) {
// Get count of bytes in the RX buffer
const ring_buffer_pos_t rx_count = (ring_buffer_pos_t)(h - t) & (ring_buffer_pos_t)(Cfg::RX_SIZE - 1);
// When below 10% of RX buffer capacity, send XON before running out of RX buffer bytes
if (rx_count < (Cfg::RX_SIZE) / 10) {
if (Cfg::TX_SIZE > 0) {
// Signal we want an XON character to be sent.
xon_xoff_state = XON_CHAR;
// Enable TX isr.
HWUART->UART_IER = UART_IER_TXRDY;
}
else {
// If not using TX interrupts, we must send the XON char now
xon_xoff_state = XON_CHAR | XON_XOFF_CHAR_SENT;
while (!(HWUART->UART_SR & UART_SR_TXRDY)) sw_barrier();
HWUART->UART_THR = XON_CHAR;
}
}
}
}
return v;
}
template<typename Cfg>
typename MarlinSerial<Cfg>::ring_buffer_pos_t MarlinSerial<Cfg>::available() {
const ring_buffer_pos_t h = rx_buffer.head, t = rx_buffer.tail;
return (ring_buffer_pos_t)(Cfg::RX_SIZE + h - t) & (Cfg::RX_SIZE - 1);
}
template<typename Cfg>
void MarlinSerial<Cfg>::flush() {
rx_buffer.tail = rx_buffer.head;
if (Cfg::XONOFF) {
if ((xon_xoff_state & XON_XOFF_CHAR_MASK) == XOFF_CHAR) {
if (Cfg::TX_SIZE > 0) {
// Signal we want an XON character to be sent.
xon_xoff_state = XON_CHAR;
// Enable TX isr.
HWUART->UART_IER = UART_IER_TXRDY;
}
else {
// If not using TX interrupts, we must send the XON char now
xon_xoff_state = XON_CHAR | XON_XOFF_CHAR_SENT;
while (!(HWUART->UART_SR & UART_SR_TXRDY)) sw_barrier();
HWUART->UART_THR = XON_CHAR;
}
}
}
}
template<typename Cfg>
size_t MarlinSerial<Cfg>::write(const uint8_t c) {
_written = true;
if (Cfg::TX_SIZE == 0) {
while (!(HWUART->UART_SR & UART_SR_TXRDY)) sw_barrier();
HWUART->UART_THR = c;
}
else {
// If the TX interrupts are disabled and the data register
// is empty, just write the byte to the data register and
// be done. This shortcut helps significantly improve the
// effective datarate at high (>500kbit/s) bitrates, where
// interrupt overhead becomes a slowdown.
// Yes, there is a race condition between the sending of the
// 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)) {
HWUART->UART_THR = c;
return 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 (!hal.isr_state()) {
// Make room by polling if it is possible to transmit, and do so!
while (i == tx_buffer.tail) {
// If we can transmit another byte, do it.
if (HWUART->UART_SR & UART_SR_TXRDY) _tx_thr_empty_irq();
// Make sure compiler rereads tx_buffer.tail
sw_barrier();
}
}
else {
// Interrupts are enabled, just wait until there is space
while (i == tx_buffer.tail) sw_barrier();
}
// Store new char. head is always safe to move
tx_buffer.buffer[tx_buffer.head] = c;
tx_buffer.head = i;
// Enable TX isr - Non atomic, but it will eventually enable TX isr
HWUART->UART_IER = UART_IER_TXRDY;
}
return 1;
}
template<typename Cfg>
void MarlinSerial<Cfg>::flushTX() {
// TX
if (Cfg::TX_SIZE == 0) {
// No bytes written, no need to flush. This special case is needed since there's
// no way to force the TXC (transmit complete) bit to 1 during initialization.
if (!_written) return;
// Wait until everything was transmitted
while (!(HWUART->UART_SR & UART_SR_TXEMPTY)) sw_barrier();
// At this point nothing is queued anymore (DRIE is disabled) and
// the hardware finished transmission (TXC is set).
}
else {
// If we have never written a byte, no need to flush. This special
// case is needed since there is no way to force the TXC (transmit
// complete) bit to 1 during initialization
if (!_written) return;
// If global interrupts are disabled (as the result of being called from an ISR)...
if (!hal.isr_state()) {
// 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)) {
// If there is more space, send an extra character
if (HWUART->UART_SR & UART_SR_TXRDY) _tx_thr_empty_irq();
sw_barrier();
}
}
else {
// Wait until everything was transmitted
while (tx_buffer.head != tx_buffer.tail || !(HWUART->UART_SR & UART_SR_TXEMPTY)) sw_barrier();
}
// At this point nothing is queued anymore (DRIE is disabled) and
// the hardware finished transmission (TXC is set).
}
}
// If not using the USB port as serial port
#if defined(SERIAL_PORT) && SERIAL_PORT >= 0
template class MarlinSerial< MarlinSerialCfg<SERIAL_PORT> >;
MSerialT1 customizedSerial1(MarlinSerialCfg<SERIAL_PORT>::EMERGENCYPARSER);
#endif
#if defined(SERIAL_PORT_2) && SERIAL_PORT_2 >= 0
template class MarlinSerial< MarlinSerialCfg<SERIAL_PORT_2> >;
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 // ARDUINO_ARCH_SAM

@ -0,0 +1,153 @@
/**
* 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/>.
*
*/
#pragma once
/**
* MarlinSerial_Due.h - Hardware serial library for Arduino DUE
* Copyright (c) 2017 Eduardo José Tagle. All right reserved
* Based on MarlinSerial for AVR, copyright (c) 2006 Nicholas Zambetti. All right reserved.
*/
#include <WString.h>
#include "../../inc/MarlinConfigPre.h"
#include "../../core/types.h"
#include "../../core/serial_hook.h"
// Define constants and variables for buffering incoming serial data. We're
// using a ring buffer (I think), in which rx_buffer_head is the index of the
// location to which to write the next incoming character and rx_buffer_tail
// is the index of the location from which to read.
// 256 is the max limit due to uint8_t head and tail. Use only powers of 2. (...,16,32,64,128,256)
#ifndef RX_BUFFER_SIZE
#define RX_BUFFER_SIZE 128
#endif
#ifndef TX_BUFFER_SIZE
#define TX_BUFFER_SIZE 32
#endif
//#if ENABLED(SERIAL_XON_XOFF) && RX_BUFFER_SIZE < 1024
// #error "SERIAL_XON_XOFF requires RX_BUFFER_SIZE >= 1024 for reliable transfers without drops."
//#elif RX_BUFFER_SIZE && (RX_BUFFER_SIZE < 2 || !IS_POWER_OF_2(RX_BUFFER_SIZE))
// #error "RX_BUFFER_SIZE must be a power of 2 greater than 1."
//#elif TX_BUFFER_SIZE && (TX_BUFFER_SIZE < 2 || TX_BUFFER_SIZE > 256 || !IS_POWER_OF_2(TX_BUFFER_SIZE))
// #error "TX_BUFFER_SIZE must be 0, a power of 2 greater than 1, and no greater than 256."
//#endif
// Templated structure wrapper
template<typename S, unsigned int addr> struct StructWrapper {
constexpr StructWrapper(int) {}
FORCE_INLINE S* operator->() const { return (S*)addr; }
};
template<typename Cfg>
class MarlinSerial {
protected:
// Information for all supported UARTs
static constexpr uint32_t BASES[] = {0x400E0800U, 0x40098000U, 0x4009C000U, 0x400A0000U, 0x400A4000U};
static constexpr IRQn_Type IRQS[] = { UART_IRQn, USART0_IRQn, USART1_IRQn, USART2_IRQn, USART3_IRQn};
static constexpr int IRQ_IDS[] = { ID_UART, ID_USART0, ID_USART1, ID_USART2, ID_USART3};
// Alias for shorter code
static constexpr StructWrapper<Uart,BASES[Cfg::PORT]> HWUART = 0;
static constexpr IRQn_Type HWUART_IRQ = IRQS[Cfg::PORT];
static constexpr int HWUART_IRQ_ID = IRQ_IDS[Cfg::PORT];
// Base size of type on buffer size
typedef uvalue_t(Cfg::RX_SIZE - 1) ring_buffer_pos_t;
struct ring_buffer_r {
volatile ring_buffer_pos_t head, tail;
unsigned char buffer[Cfg::RX_SIZE];
};
struct ring_buffer_t {
volatile uint8_t head, tail;
unsigned char buffer[Cfg::TX_SIZE];
};
static ring_buffer_r rx_buffer;
static ring_buffer_t tx_buffer;
static bool _written;
static constexpr uint8_t XON_XOFF_CHAR_SENT = 0x80, // XON / XOFF Character was sent
XON_XOFF_CHAR_MASK = 0x1F; // XON / XOFF character to send
// XON / XOFF character definitions
static constexpr uint8_t XON_CHAR = 17, XOFF_CHAR = 19;
static uint8_t xon_xoff_state,
rx_dropped_bytes,
rx_buffer_overruns,
rx_framing_errors;
static ring_buffer_pos_t rx_max_enqueued;
FORCE_INLINE static void store_rxd_char();
FORCE_INLINE static void _tx_thr_empty_irq();
static void UART_ISR();
public:
MarlinSerial() {};
static void begin(const long);
static void end();
static int peek();
static int read();
static void flush();
static ring_buffer_pos_t available();
static size_t write(const uint8_t c);
static void flushTX();
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 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 ring_buffer_pos_t rxMaxEnqueued() { return Cfg::MAX_RX_QUEUED ? rx_max_enqueued : 0; }
};
// Serial port configuration
template <uint8_t serial>
struct MarlinSerialCfg {
static constexpr int PORT = serial;
static constexpr unsigned int RX_SIZE = RX_BUFFER_SIZE;
static constexpr unsigned int TX_SIZE = TX_BUFFER_SIZE;
static constexpr bool XONOFF = ENABLED(SERIAL_XON_XOFF);
static constexpr bool EMERGENCYPARSER = ENABLED(EMERGENCY_PARSER);
static constexpr bool DROPPED_RX = ENABLED(SERIAL_STATS_DROPPED_RX);
static constexpr bool RX_OVERRUNS = ENABLED(SERIAL_STATS_RX_BUFFER_OVERRUNS);
static constexpr bool RX_FRAMING_ERRORS = ENABLED(SERIAL_STATS_RX_FRAMING_ERRORS);
static constexpr bool MAX_RX_QUEUED = ENABLED(SERIAL_STATS_MAX_RX_QUEUED);
};
#if defined(SERIAL_PORT) && SERIAL_PORT >= 0
typedef Serial1Class< MarlinSerial< MarlinSerialCfg<SERIAL_PORT> > > MSerialT1;
extern MSerialT1 customizedSerial1;
#endif
#if defined(SERIAL_PORT_2) && SERIAL_PORT_2 >= 0
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

@ -0,0 +1,142 @@
/**
* 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
/**
* MarlinSerial_Due.cpp - Hardware serial library for Arduino DUE
* Copyright (c) 2017 Eduardo José Tagle. All right reserved
* Based on MarlinSerial for AVR, copyright (c) 2006 Nicholas Zambetti. All right reserved.
*/
#include "../../inc/MarlinConfig.h"
#if HAS_USB_SERIAL
#include "MarlinSerialUSB.h"
// Imports from Atmel USB Stack/CDC implementation
extern "C" {
bool usb_task_cdc_isenabled();
bool usb_task_cdc_dtr_active();
bool udi_cdc_is_rx_ready();
int udi_cdc_getc();
bool udi_cdc_is_tx_ready();
int udi_cdc_putc(int value);
}
// Pending character
static int pending_char = -1;
// Public Methods
void MarlinSerialUSB::begin(const long) {}
void MarlinSerialUSB::end() {}
int MarlinSerialUSB::peek() {
if (pending_char >= 0)
return pending_char;
// If USB CDC not enumerated or not configured on the PC side
if (!usb_task_cdc_isenabled())
return -1;
// If no bytes sent from the PC
if (!udi_cdc_is_rx_ready())
return -1;
pending_char = udi_cdc_getc();
TERN_(EMERGENCY_PARSER, emergency_parser.update(static_cast<MSerialT1*>(this)->emergency_state, (char)pending_char));
return pending_char;
}
int MarlinSerialUSB::read() {
if (pending_char >= 0) {
int ret = pending_char;
pending_char = -1;
return ret;
}
// If USB CDC not enumerated or not configured on the PC side
if (!usb_task_cdc_isenabled())
return -1;
// If no bytes sent from the PC
if (!udi_cdc_is_rx_ready())
return -1;
int c = udi_cdc_getc();
TERN_(EMERGENCY_PARSER, emergency_parser.update(static_cast<MSerialT1*>(this)->emergency_state, (char)c));
return c;
}
int MarlinSerialUSB::available() {
if (pending_char > 0) return pending_char;
return pending_char == 0 ||
// or USB CDC enumerated and configured on the PC side and some bytes where sent to us */
(usb_task_cdc_isenabled() && udi_cdc_is_rx_ready());
}
void MarlinSerialUSB::flush() { }
size_t MarlinSerialUSB::write(const uint8_t c) {
/* 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
listening to our messages */
if (!usb_task_cdc_isenabled() || !usb_task_cdc_dtr_active())
return 0;
/* Wait until the PC has read the pending to be sent data */
while (usb_task_cdc_isenabled() &&
usb_task_cdc_dtr_active() &&
!udi_cdc_is_tx_ready()) {
};
/* 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
listening to our messages at this point */
if (!usb_task_cdc_isenabled() || !usb_task_cdc_dtr_active())
return 0;
// Fifo full
// udi_cdc_signal_overrun();
udi_cdc_putc(c);
return 1;
}
// Preinstantiate
#if SERIAL_PORT == -1
MSerialT1 customizedSerial1(TERN0(EMERGENCY_PARSER, true));
#endif
#if SERIAL_PORT_2 == -1
MSerialT2 customizedSerial2(TERN0(EMERGENCY_PARSER, true));
#endif
#if SERIAL_PORT_3 == -1
MSerialT3 customizedSerial3(TERN0(EMERGENCY_PARSER, true));
#endif
#endif // HAS_USB_SERIAL
#endif // ARDUINO_ARCH_SAM

@ -0,0 +1,65 @@
/**
* 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/>.
*
*/
#pragma once
/**
* MarlinSerialUSB_Due.h - Hardware Serial over USB (CDC) library for Arduino DUE
* Copyright (c) 2017 Eduardo José Tagle. All right reserved
*/
#include "../../inc/MarlinConfig.h"
#include "../../core/serial_hook.h"
#include <WString.h>
struct MarlinSerialUSB {
void begin(const long);
void end();
int peek();
int read();
void flush();
int available();
size_t write(const uint8_t c);
#if ENABLED(SERIAL_STATS_DROPPED_RX)
FORCE_INLINE uint32_t dropped() { return 0; }
#endif
#if ENABLED(SERIAL_STATS_MAX_RX_QUEUED)
FORCE_INLINE int rxMaxEnqueued() { return 0; }
#endif
};
#if SERIAL_PORT == -1
typedef Serial1Class<MarlinSerialUSB> MSerialT1;
extern MSerialT1 customizedSerial1;
#endif
#if SERIAL_PORT_2 == -1
typedef Serial1Class<MarlinSerialUSB> MSerialT2;
extern MSerialT2 customizedSerial2;
#endif
#if SERIAL_PORT_3 == -1
typedef Serial1Class<MarlinSerialUSB> MSerialT3;
extern MSerialT3 customizedSerial3;
#endif

@ -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

@ -0,0 +1,163 @@
/**
* 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/>.
*
*/
/*
Copyright (c) 2013 Arduino LLC. All right reserved.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifdef ARDUINO_ARCH_SAM
#include "../../inc/MarlinConfig.h"
#if HAS_SERVOS
#include "../shared/servo.h"
#include "../shared/servo_private.h"
static Flags<_Nbr_16timers> DisablePending; // ISR should disable the timer at the next timer reset
// ------------------------
/// Interrupt handler for the TC0 channel 1.
// ------------------------
void Servo_Handler(const timer16_Sequence_t, Tc*, const uint8_t);
#ifdef _useTimer1
void HANDLER_FOR_TIMER1() { Servo_Handler(_timer1, TC_FOR_TIMER1, CHANNEL_FOR_TIMER1); }
#endif
#ifdef _useTimer2
void HANDLER_FOR_TIMER2() { Servo_Handler(_timer2, TC_FOR_TIMER2, CHANNEL_FOR_TIMER2); }
#endif
#ifdef _useTimer3
void HANDLER_FOR_TIMER3() { Servo_Handler(_timer3, TC_FOR_TIMER3, CHANNEL_FOR_TIMER3); }
#endif
#ifdef _useTimer4
void HANDLER_FOR_TIMER4() { Servo_Handler(_timer4, TC_FOR_TIMER4, CHANNEL_FOR_TIMER4); }
#endif
#ifdef _useTimer5
void HANDLER_FOR_TIMER5() { Servo_Handler(_timer5, TC_FOR_TIMER5, CHANNEL_FOR_TIMER5); }
#endif
void Servo_Handler(const timer16_Sequence_t timer, Tc *tc, const uint8_t channel) {
static int8_t Channel[_Nbr_16timers]; // Servo counters to pulse (or -1 for refresh interval)
int8_t cho = Channel[timer]; // Handle the prior Channel[timer] first
if (cho < 0) { // Channel -1 indicates the refresh interval completed...
tc->TC_CHANNEL[channel].TC_CCR |= TC_CCR_SWTRG; // ...so reset the timer
if (DisablePending[timer]) {
// 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] = ++cho; // go to the next channel (or 0)
if (cho < SERVOS_PER_TIMER && SERVO_INDEX(timer, cho) < ServoCount) {
tc->TC_CHANNEL[channel].TC_RA = tc->TC_CHANNEL[channel].TC_CV + SERVO(timer, cho).ticks;
if (SERVO(timer, cho).Pin.isActive) // activated?
extDigitalWrite(SERVO(timer, cho).Pin.nbr, HIGH); // yes: pulse HIGH
}
else {
// finished all channels so wait for the refresh period to expire before starting over
const unsigned int cval = tc->TC_CHANNEL[channel].TC_CV + 128 / (SERVO_TIMER_PRESCALER), // allow 128 cycles to ensure the next CV not missed
ival = (unsigned int)usToTicks(REFRESH_INTERVAL); // at least REFRESH_INTERVAL has elapsed
tc->TC_CHANNEL[channel].TC_RA = max(cval, ival);
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) {
pmc_enable_periph_clk(id);
TC_Configure(tc, channel,
TC_CMR_WAVE // Waveform mode
| TC_CMR_WAVSEL_UP_RC // Counter running up and reset when equal 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
);
// Wait 1ms before the first ISR
TC_SetRA(tc, channel, (F_CPU) / (SERVO_TIMER_PRESCALER) / 1000UL); // 1ms
// Configure and enable interrupt
NVIC_EnableIRQ(irqn);
tc->TC_CHANNEL[channel].TC_IER = TC_IER_CPAS; // TC_IER_CPAS: RA Compare
// Enables the timer clock and performs a software reset to start the counting
TC_Start(tc, channel);
}
void initISR(const timer16_Sequence_t timer_index) {
CRITICAL_SECTION_START();
const bool disable_soon = DisablePending[timer_index];
DisablePending.clear(timer_index);
CRITICAL_SECTION_END();
if (!disable_soon) switch (timer_index) {
default: break;
#ifdef _useTimer1
case _timer1: return _initISR(TC_FOR_TIMER1, CHANNEL_FOR_TIMER1, ID_TC_FOR_TIMER1, IRQn_FOR_TIMER1);
#endif
#ifdef _useTimer2
case _timer2: return _initISR(TC_FOR_TIMER2, CHANNEL_FOR_TIMER2, ID_TC_FOR_TIMER2, IRQn_FOR_TIMER2);
#endif
#ifdef _useTimer3
case _timer3: return _initISR(TC_FOR_TIMER3, CHANNEL_FOR_TIMER3, ID_TC_FOR_TIMER3, IRQn_FOR_TIMER3);
#endif
#ifdef _useTimer4
case _timer4: return _initISR(TC_FOR_TIMER4, CHANNEL_FOR_TIMER4, ID_TC_FOR_TIMER4, IRQn_FOR_TIMER4);
#endif
#ifdef _useTimer5
case _timer5: return _initISR(TC_FOR_TIMER5, CHANNEL_FOR_TIMER5, ID_TC_FOR_TIMER5, IRQn_FOR_TIMER5);
#endif
}
}
void finISR(const timer16_Sequence_t timer_index) {
// Timer is disabled from the ISR, to ensure proper final pulse length.
DisablePending.set(timer_index);
}
#endif // HAS_SERVOS
#endif // ARDUINO_ARCH_SAM

@ -0,0 +1,107 @@
/**
* Copyright (c) 2013 Arduino LLC. All right reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
/**
* Defines for 16 bit timers used with Servo library
*
* If _useTimerX is defined then TimerX is a 32 bit timer on the current board
* timer16_Sequence_t enumerates the sequence that the timers should be allocated
* _Nbr_16timers indicates how many timers are available.
*/
/**
* SAM Only definitions
* --------------------
*/
// For SAM3X:
//!#define _useTimer1
//!#define _useTimer2
#define _useTimer3
//!#define _useTimer4
#define _useTimer5
#define TRIM_DURATION 2 // compensation ticks to trim adjust for digitalWrite delays
#define SERVO_TIMER_PRESCALER 2 // timer prescaler
/*
TC0, chan 0 => TC0_Handler
TC0, chan 1 => TC1_Handler
TC0, chan 2 => TC2_Handler
TC1, chan 0 => TC3_Handler
TC1, chan 1 => TC4_Handler
TC1, chan 2 => TC5_Handler
TC2, chan 0 => TC6_Handler
TC2, chan 1 => TC7_Handler
TC2, chan 2 => TC8_Handler
*/
#ifdef _useTimer1
#define TC_FOR_TIMER1 TC1
#define CHANNEL_FOR_TIMER1 0
#define ID_TC_FOR_TIMER1 ID_TC3
#define IRQn_FOR_TIMER1 TC3_IRQn
#define HANDLER_FOR_TIMER1 TC3_Handler
#endif
#ifdef _useTimer2
#define TC_FOR_TIMER2 TC1
#define CHANNEL_FOR_TIMER2 1
#define ID_TC_FOR_TIMER2 ID_TC4
#define IRQn_FOR_TIMER2 TC4_IRQn
#define HANDLER_FOR_TIMER2 TC4_Handler
#endif
#ifdef _useTimer3
#define TC_FOR_TIMER3 TC1
#define CHANNEL_FOR_TIMER3 2
#define ID_TC_FOR_TIMER3 ID_TC5
#define IRQn_FOR_TIMER3 TC5_IRQn
#define HANDLER_FOR_TIMER3 TC5_Handler
#endif
#ifdef _useTimer4
#define TC_FOR_TIMER4 TC0
#define CHANNEL_FOR_TIMER4 2
#define ID_TC_FOR_TIMER4 ID_TC2
#define IRQn_FOR_TIMER4 TC2_IRQn
#define HANDLER_FOR_TIMER4 TC2_Handler
#endif
#ifdef _useTimer5
#define TC_FOR_TIMER5 TC0
#define CHANNEL_FOR_TIMER5 0
#define ID_TC_FOR_TIMER5 ID_TC0
#define IRQn_FOR_TIMER5 TC0_IRQn
#define HANDLER_FOR_TIMER5 TC0_Handler
#endif
typedef enum : unsigned char {
#ifdef _useTimer1
_timer1,
#endif
#ifdef _useTimer2
_timer2,
#endif
#ifdef _useTimer3
_timer3,
#endif
#ifdef _useTimer4
_timer4,
#endif
#ifdef _useTimer5
_timer5,
#endif
_Nbr_16timers
} timer16_Sequence_t;

@ -0,0 +1,60 @@
/**
* 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
*
* SAMD51 HAL developed by Giuliano Zaro (AKA GMagician)
*
* 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/>.
*
*/
/**
* Description: Tone function for Arduino Due and compatible (SAM3X8E)
* Derived from https://forum.arduino.cc/index.php?topic=136500.msg2903012#msg2903012
*/
#ifdef ARDUINO_ARCH_SAM
#include "../../inc/MarlinConfig.h"
#include "HAL.h"
static pin_t tone_pin;
volatile static int32_t toggles;
void tone(const pin_t _pin, const unsigned int frequency, const unsigned long duration/*=0*/) {
tone_pin = _pin;
toggles = 2 * frequency * duration / 1000;
HAL_timer_start(MF_TIMER_TONE, 2 * frequency);
}
void noTone(const pin_t _pin) {
HAL_timer_disable_interrupt(MF_TIMER_TONE);
extDigitalWrite(_pin, LOW);
}
HAL_TONE_TIMER_ISR() {
static uint8_t pin_state = 0;
HAL_timer_isr_prologue(MF_TIMER_TONE);
if (toggles) {
toggles--;
extDigitalWrite(tone_pin, (pin_state ^= 1));
}
else noTone(tone_pin); // turn off interrupt
}
#endif // ARDUINO_ARCH_SAM

@ -0,0 +1,997 @@
/**
* 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"
#if ENABLED(FLASH_EEPROM_EMULATION)
/* EEPROM emulation over flash with reduced wear
*
* We will use 2 contiguous groups of pages as main and alternate.
* We want an structure that allows to read as fast as possible,
* without the need of scanning the whole FLASH memory.
*
* FLASH bits default erased state is 1, and can be set to 0
* on a per bit basis. To reset them to 1, a full page erase
* is needed.
*
* Values are stored as differences that should be applied to a
* completely erased EEPROM (filled with 0xFFs). We just encode
* the starting address of the values to change, the length of
* the block of new values, and the values themselves. All diffs
* are accumulated into a RAM buffer, compacted into the least
* amount of non overlapping diffs possible and sorted by starting
* address before being saved into the next available page of FLASH
* of the current group.
* Once the current group is completely full, we compact it and save
* it into the other group, then erase the current group and switch
* to that new group and set it as current.
*
* The FLASH endurance is about 1/10 ... 1/100 of an EEPROM
* endurance, but EEPROM endurance is specified per byte, not
* per page. We can't emulate EE endurance with FLASH for all
* bytes, but we can emulate endurance for a given percent of
* bytes.
*/
//#define EE_EMU_DEBUG
#define EEPROMSize 4096
#define PagesPerGroup 128
#define GroupCount 2
#define PageSize 256U
/* Flash storage */
typedef struct FLASH_SECTOR {
uint8_t page[PageSize];
} FLASH_SECTOR_T;
#define PAGE_FILL \
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, \
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, \
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, \
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, \
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, \
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, \
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, \
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, \
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, \
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, \
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, \
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, \
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, \
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, \
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, \
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF
#define FLASH_INIT_FILL \
PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL, \
PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL, \
PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL, \
PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL, \
PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL, \
PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL, \
PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL, \
PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL, \
PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL, \
PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL, \
PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL, \
PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL, \
PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL, \
PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL, \
PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL, \
PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL, \
PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL, \
PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL, \
PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL, \
PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL, \
PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL, \
PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL, \
PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL, \
PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL, \
PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL, \
PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL, \
PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL, \
PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL, \
PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL, \
PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL, \
PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL, \
PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL
/* This is the FLASH area used to emulate a 2Kbyte EEPROM -- We need this buffer aligned
to a 256 byte boundary. */
static const uint8_t flashStorage[PagesPerGroup * GroupCount * PageSize] __attribute__ ((aligned (PageSize))) = { FLASH_INIT_FILL };
/* Get the address of an specific page */
static const FLASH_SECTOR_T* getFlashStorage(int page) {
return (const FLASH_SECTOR_T*)&flashStorage[page*PageSize];
}
static uint8_t buffer[256] = {0}, // The RAM buffer to accumulate writes
curPage = 0, // Current FLASH page inside the group
curGroup = 0xFF; // Current FLASH group
#define DEBUG_OUT ENABLED(EE_EMU_DEBUG)
#include "../../core/debug_out.h"
static void ee_Dump(const int page, const void *data) {
#ifdef EE_EMU_DEBUG
const uint8_t *c = (const uint8_t*) data;
char buffer[80];
sprintf_P(buffer, PSTR("Page: %d (0x%04x)\n"), page, page);
DEBUG_ECHO(buffer);
char* p = &buffer[0];
for (int i = 0; i< PageSize; ++i) {
if ((i & 0xF) == 0) p += sprintf_P(p, PSTR("%04x] "), i);
p += sprintf_P(p, PSTR(" %02x"), c[i]);
if ((i & 0xF) == 0xF) {
*p++ = '\n';
*p = 0;
DEBUG_ECHO(buffer);
p = &buffer[0];
}
}
#else
UNUSED(page);
UNUSED(data);
#endif
}
/* Flash Writing Protection Key */
#define FWP_KEY 0x5Au
#if SAM4S_SERIES
#define EEFC_FCR_FCMD(value) \
((EEFC_FCR_FCMD_Msk & ((value) << EEFC_FCR_FCMD_Pos)))
#define EEFC_ERROR_FLAGS (EEFC_FSR_FLOCKE | EEFC_FSR_FCMDE | EEFC_FSR_FLERR)
#else
#define EEFC_ERROR_FLAGS (EEFC_FSR_FLOCKE | EEFC_FSR_FCMDE)
#endif
/**
* Writes the contents of the specified page (no previous erase)
* @param page (page #)
* @param data (pointer to the data buffer)
*/
__attribute__ ((long_call, section (".ramfunc")))
static bool ee_PageWrite(uint16_t page, const void *data) {
uint16_t i;
uint32_t addrflash = uint32_t(getFlashStorage(page));
// Read the flash contents
uint32_t pageContents[PageSize>>2];
memcpy(pageContents, (void*)addrflash, PageSize);
// We ONLY want to toggle bits that have changed, and that have changed to 0.
// SAM3X8E tends to destroy contiguous bits if reprogrammed without erasing, so
// we try by all means to avoid this. That is why it says: "The Partial
// Programming mode works only with 128-bit (or higher) boundaries. It cannot
// be used with boundaries lower than 128 bits (8, 16 or 32-bit for example)."
// All bits that did not change, set them to 1.
for (i = 0; i <PageSize >> 2; i++)
pageContents[i] = (((uint32_t*)data)[i]) | (~(pageContents[i] ^ ((uint32_t*)data)[i]));
DEBUG_ECHO_MSG("EEPROM PageWrite ", page);
DEBUG_ECHOLNPGM(" in FLASH address ", (uint32_t)addrflash);
DEBUG_ECHOLNPGM(" base address ", (uint32_t)getFlashStorage(0));
DEBUG_FLUSH();
// Get the page relative to the start of the EFC controller, and the EFC controller to use
Efc *efc;
uint16_t fpage;
if (addrflash >= IFLASH1_ADDR) {
efc = EFC1;
fpage = (addrflash - IFLASH1_ADDR) / IFLASH1_PAGE_SIZE;
}
else {
efc = EFC0;
fpage = (addrflash - IFLASH0_ADDR) / IFLASH0_PAGE_SIZE;
}
// Get the page that must be unlocked, then locked
uint16_t lpage = fpage & (~((IFLASH0_LOCK_REGION_SIZE / IFLASH0_PAGE_SIZE) - 1));
// Disable all interrupts
__disable_irq();
// Get the FLASH wait states
uint32_t orgWS = (efc->EEFC_FMR & EEFC_FMR_FWS_Msk) >> EEFC_FMR_FWS_Pos;
// Set wait states to 6 (SAM errata)
efc->EEFC_FMR = (efc->EEFC_FMR & (~EEFC_FMR_FWS_Msk)) | EEFC_FMR_FWS(6);
// Unlock the flash page
uint32_t status;
efc->EEFC_FCR = EEFC_FCR_FKEY(FWP_KEY) | EEFC_FCR_FARG(lpage) | EEFC_FCR_FCMD(EFC_FCMD_CLB);
while (((status = efc->EEFC_FSR) & EEFC_FSR_FRDY) != EEFC_FSR_FRDY) {
// force compiler to not optimize this -- NOPs don't work!
__asm__ __volatile__("");
};
if ((status & EEFC_ERROR_FLAGS) != 0) {
// Restore original wait states
efc->EEFC_FMR = (efc->EEFC_FMR & (~EEFC_FMR_FWS_Msk)) | EEFC_FMR_FWS(orgWS);
// Reenable interrupts
__enable_irq();
DEBUG_ECHO_MSG("EEPROM Unlock failure for page ", page);
return false;
}
// Write page and lock: Writing 8-bit and 16-bit data is not allowed and may lead to unpredictable data corruption.
const uint32_t * aligned_src = (const uint32_t *) &pageContents[0]; /*data;*/
uint32_t * p_aligned_dest = (uint32_t *) addrflash;
for (i = 0; i < (IFLASH0_PAGE_SIZE / sizeof(uint32_t)); ++i) {
*p_aligned_dest++ = *aligned_src++;
}
efc->EEFC_FCR = EEFC_FCR_FKEY(FWP_KEY) | EEFC_FCR_FARG(fpage) | EEFC_FCR_FCMD(EFC_FCMD_WPL);
while (((status = efc->EEFC_FSR) & EEFC_FSR_FRDY) != EEFC_FSR_FRDY) {
// force compiler to not optimize this -- NOPs don't work!
__asm__ __volatile__("");
};
if ((status & EEFC_ERROR_FLAGS) != 0) {
// Restore original wait states
efc->EEFC_FMR = (efc->EEFC_FMR & (~EEFC_FMR_FWS_Msk)) | EEFC_FMR_FWS(orgWS);
// Reenable interrupts
__enable_irq();
DEBUG_ECHO_MSG("EEPROM Write failure for page ", page);
return false;
}
// Restore original wait states
efc->EEFC_FMR = (efc->EEFC_FMR & (~EEFC_FMR_FWS_Msk)) | EEFC_FMR_FWS(orgWS);
// Reenable interrupts
__enable_irq();
// Compare contents
if (memcmp(getFlashStorage(page),data,PageSize)) {
#ifdef EE_EMU_DEBUG
DEBUG_ECHO_MSG("EEPROM Verify Write failure for page ", page);
ee_Dump( page, (uint32_t *)addrflash);
ee_Dump(-page, data);
// Calculate count of changed bits
uint32_t *p1 = (uint32_t*)addrflash;
uint32_t *p2 = (uint32_t*)data;
int count = 0;
for (i =0; i<PageSize >> 2; i++) {
if (p1[i] != p2[i]) {
uint32_t delta = p1[i] ^ p2[i];
while (delta) {
if ((delta&1) != 0)
count++;
delta >>= 1;
}
}
}
DEBUG_ECHOLNPGM("--> Differing bits: ", count);
#endif
return false;
}
return true;
}
/**
* Erases the contents of the specified page
* @param page (page #)
*/
__attribute__ ((long_call, section (".ramfunc")))
static bool ee_PageErase(uint16_t page) {
uint16_t i;
uint32_t addrflash = uint32_t(getFlashStorage(page));
DEBUG_ECHO_MSG("EEPROM PageErase ", page);
DEBUG_ECHOLNPGM(" in FLASH address ", (uint32_t)addrflash);
DEBUG_ECHOLNPGM(" base address ", (uint32_t)getFlashStorage(0));
DEBUG_FLUSH();
// Get the page relative to the start of the EFC controller, and the EFC controller to use
Efc *efc;
uint16_t fpage;
if (addrflash >= IFLASH1_ADDR) {
efc = EFC1;
fpage = (addrflash - IFLASH1_ADDR) / IFLASH1_PAGE_SIZE;
}
else {
efc = EFC0;
fpage = (addrflash - IFLASH0_ADDR) / IFLASH0_PAGE_SIZE;
}
// Get the page that must be unlocked, then locked
uint16_t lpage = fpage & (~((IFLASH0_LOCK_REGION_SIZE / IFLASH0_PAGE_SIZE) - 1));
// Disable all interrupts
__disable_irq();
// Get the FLASH wait states
uint32_t orgWS = (efc->EEFC_FMR & EEFC_FMR_FWS_Msk) >> EEFC_FMR_FWS_Pos;
// Set wait states to 6 (SAM errata)
efc->EEFC_FMR = (efc->EEFC_FMR & (~EEFC_FMR_FWS_Msk)) | EEFC_FMR_FWS(6);
// Unlock the flash page
uint32_t status;
efc->EEFC_FCR = EEFC_FCR_FKEY(FWP_KEY) | EEFC_FCR_FARG(lpage) | EEFC_FCR_FCMD(EFC_FCMD_CLB);
while (((status = efc->EEFC_FSR) & EEFC_FSR_FRDY) != EEFC_FSR_FRDY) {
// force compiler to not optimize this -- NOPs don't work!
__asm__ __volatile__("");
};
if ((status & EEFC_ERROR_FLAGS) != 0) {
// Restore original wait states
efc->EEFC_FMR = (efc->EEFC_FMR & (~EEFC_FMR_FWS_Msk)) | EEFC_FMR_FWS(orgWS);
// Reenable interrupts
__enable_irq();
DEBUG_ECHO_MSG("EEPROM Unlock failure for page ",page);
return false;
}
// Erase Write page and lock: Writing 8-bit and 16-bit data is not allowed and may lead to unpredictable data corruption.
uint32_t * p_aligned_dest = (uint32_t *) addrflash;
for (i = 0; i < (IFLASH0_PAGE_SIZE / sizeof(uint32_t)); ++i) {
*p_aligned_dest++ = 0xFFFFFFFF;
}
efc->EEFC_FCR = EEFC_FCR_FKEY(FWP_KEY) | EEFC_FCR_FARG(fpage) | EEFC_FCR_FCMD(EFC_FCMD_EWPL);
while (((status = efc->EEFC_FSR) & EEFC_FSR_FRDY) != EEFC_FSR_FRDY) {
// force compiler to not optimize this -- NOPs don't work!
__asm__ __volatile__("");
};
if ((status & EEFC_ERROR_FLAGS) != 0) {
// Restore original wait states
efc->EEFC_FMR = (efc->EEFC_FMR & (~EEFC_FMR_FWS_Msk)) | EEFC_FMR_FWS(orgWS);
// Reenable interrupts
__enable_irq();
DEBUG_ECHO_MSG("EEPROM Erase failure for page ",page);
return false;
}
// Restore original wait states
efc->EEFC_FMR = (efc->EEFC_FMR & (~EEFC_FMR_FWS_Msk)) | EEFC_FMR_FWS(orgWS);
// Reenable interrupts
__enable_irq();
// Check erase
uint32_t * aligned_src = (uint32_t *) addrflash;
for (i = 0; i < PageSize >> 2; i++) {
if (*aligned_src++ != 0xFFFFFFFF) {
DEBUG_ECHO_MSG("EEPROM Verify Erase failure for page ",page);
ee_Dump(page, (uint32_t *)addrflash);
return false;
}
}
return true;
}
static uint8_t ee_Read(uint32_t address, bool excludeRAMBuffer=false) {
uint32_t baddr;
uint32_t blen;
// If we were requested an address outside of the emulated range, fail now
if (address >= EEPROMSize)
return false;
// Check that the value is not contained in the RAM buffer
if (!excludeRAMBuffer) {
uint16_t i = 0;
while (i <= (PageSize - 4)) { /* (PageSize - 4) because otherwise, there is not enough room for data and headers */
// Get the address of the block
baddr = buffer[i] | (buffer[i + 1] << 8);
// Get the length of the block
blen = buffer[i + 2];
// If we reach the end of the list, break loop
if (blen == 0xFF)
break;
// Check if data is contained in this block
if (address >= baddr &&
address < (baddr + blen)) {
// Yes, it is contained. Return it!
return buffer[i + 3 + address - baddr];
}
// As blocks are always sorted, if the starting address of this block is higher
// than the address we are looking for, break loop now - We wont find the value
// associated to the address
if (baddr > address)
break;
// Jump to the next block
i += 3 + blen;
}
}
// It is NOT on the RAM buffer. It could be stored in FLASH. We are
// ensured on a given FLASH page, address contents are never repeated
// but on different pages, there is no such warranty, so we must go
// backwards from the last written FLASH page to the first one.
for (int page = curPage - 1; page >= 0; --page) {
// Get a pointer to the flash page
uint8_t *pflash = (uint8_t*)getFlashStorage(page + curGroup * PagesPerGroup);
uint16_t i = 0;
while (i <= (PageSize - 4)) { /* (PageSize - 4) because otherwise, there is not enough room for data and headers */
// Get the address of the block
baddr = pflash[i] | (pflash[i + 1] << 8);
// Get the length of the block
blen = pflash[i + 2];
// If we reach the end of the list, break loop
if (blen == 0xFF)
break;
// Check if data is contained in this block
if (address >= baddr && address < (baddr + blen))
return pflash[i + 3 + address - baddr]; // Yes, it is contained. Return it!
// As blocks are always sorted, if the starting address of this block is higher
// than the address we are looking for, break loop now - We wont find the value
// associated to the address
if (baddr > address) break;
// Jump to the next block
i += 3 + blen;
}
}
// If reached here, value is not stored, so return its default value
return 0xFF;
}
static uint32_t ee_GetAddrRange(uint32_t address, bool excludeRAMBuffer=false) {
uint32_t baddr,
blen,
nextAddr = 0xFFFF,
nextRange = 0;
// Check that the value is not contained in the RAM buffer
if (!excludeRAMBuffer) {
uint16_t i = 0;
while (i <= (PageSize - 4)) { /* (PageSize - 4) because otherwise, there is not enough room for data and headers */
// Get the address of the block
baddr = buffer[i] | (buffer[i + 1] << 8);
// Get the length of the block
blen = buffer[i + 2];
// If we reach the end of the list, break loop
if (blen == 0xFF) break;
// Check if address and address + 1 is contained in this block
if (address >= baddr && address < (baddr + blen))
return address | ((blen - address + baddr) << 16); // Yes, it is contained. Return it!
// Otherwise, check if we can use it as a limit
if (baddr > address && baddr < nextAddr) {
nextAddr = baddr;
nextRange = blen;
}
// As blocks are always sorted, if the starting address of this block is higher
// than the address we are looking for, break loop now - We wont find the value
// associated to the address
if (baddr > address) break;
// Jump to the next block
i += 3 + blen;
}
}
// It is NOT on the RAM buffer. It could be stored in FLASH. We are
// ensured on a given FLASH page, address contents are never repeated
// but on different pages, there is no such warranty, so we must go
// backwards from the last written FLASH page to the first one.
for (int page = curPage - 1; page >= 0; --page) {
// Get a pointer to the flash page
uint8_t *pflash = (uint8_t*)getFlashStorage(page + curGroup * PagesPerGroup);
uint16_t i = 0;
while (i <= (PageSize - 4)) { /* (PageSize - 4) because otherwise, there is not enough room for data and headers */
// Get the address of the block
baddr = pflash[i] | (pflash[i + 1] << 8);
// Get the length of the block
blen = pflash[i + 2];
// If we reach the end of the list, break loop
if (blen == 0xFF) break;
// Check if data is contained in this block
if (address >= baddr && address < (baddr + blen))
return address | ((blen - address + baddr) << 16); // Yes, it is contained. Return it!
// Otherwise, check if we can use it as a limit
if (baddr > address && baddr < nextAddr) {
nextAddr = baddr;
nextRange = blen;
}
// As blocks are always sorted, if the starting address of this block is higher
// than the address we are looking for, break loop now - We wont find the value
// associated to the address
if (baddr > address) break;
// Jump to the next block
i += 3 + blen;
}
}
// If reached here, we will return the next valid address
return nextAddr | (nextRange << 16);
}
static bool ee_IsPageClean(int page) {
uint32_t *pflash = (uint32_t*) getFlashStorage(page);
for (uint16_t i = 0; i < (PageSize >> 2); ++i)
if (*pflash++ != 0xFFFFFFFF) return false;
return true;
}
static bool ee_Flush(uint32_t overrideAddress = 0xFFFFFFFF, uint8_t overrideData=0xFF) {
// Check if RAM buffer has something to be written
bool isEmpty = true;
uint32_t *p = (uint32_t*) &buffer[0];
for (uint16_t j = 0; j < (PageSize >> 2); j++) {
if (*p++ != 0xFFFFFFFF) {
isEmpty = false;
break;
}
}
// If something has to be written, do so!
if (!isEmpty) {
// Write the current ram buffer into FLASH
ee_PageWrite(curPage + curGroup * PagesPerGroup, buffer);
// Clear the RAM buffer
memset(buffer, 0xFF, sizeof(buffer));
// Increment the page to use the next time
++curPage;
}
// Did we reach the maximum count of available pages per group for storage ?
if (curPage < PagesPerGroup) {
// Do we have an override address ?
if (overrideAddress < EEPROMSize) {
// Yes, just store the value into the RAM buffer
buffer[0] = overrideAddress & 0xFF;
buffer[0 + 1] = (overrideAddress >> 8) & 0xFF;
buffer[0 + 2] = 1;
buffer[0 + 3] = overrideData;
}
// Done!
return true;
}
// We have no space left on the current group - We must compact the values
uint16_t i = 0;
// Compute the next group to use
int curwPage = 0, curwGroup = curGroup + 1;
if (curwGroup >= GroupCount) curwGroup = 0;
uint32_t rdAddr = 0;
do {
// Get the next valid range
uint32_t addrRange = ee_GetAddrRange(rdAddr, true);
// Make sure not to skip the override address, if specified
int rdRange;
if (overrideAddress < EEPROMSize &&
rdAddr <= overrideAddress &&
(addrRange & 0xFFFF) > overrideAddress) {
rdAddr = overrideAddress;
rdRange = 1;
}
else {
rdAddr = addrRange & 0xFFFF;
rdRange = addrRange >> 16;
}
// If no range, break loop
if (rdRange == 0)
break;
do {
// Get the value
uint8_t rdValue = overrideAddress == rdAddr ? overrideData : ee_Read(rdAddr, true);
// Do not bother storing default values
if (rdValue != 0xFF) {
// If we have room, add it to the buffer
if (buffer[i + 2] == 0xFF) {
// Uninitialized buffer, just add it!
buffer[i] = rdAddr & 0xFF;
buffer[i + 1] = (rdAddr >> 8) & 0xFF;
buffer[i + 2] = 1;
buffer[i + 3] = rdValue;
}
else {
// Buffer already has contents. Check if we can extend it
// Get the address of the block
uint32_t baddr = buffer[i] | (buffer[i + 1] << 8);
// Get the length of the block
uint32_t blen = buffer[i + 2];
// Can we expand it ?
if (rdAddr == (baddr + blen) &&
i < (PageSize - 4) && /* This block has a chance to contain data AND */
buffer[i + 2] < (PageSize - i - 3)) {/* There is room for this block to be expanded */
// Yes, do it
++buffer[i + 2];
// And store the value
buffer[i + 3 + rdAddr - baddr] = rdValue;
}
else {
// No, we can't expand it - Skip the existing block
i += 3 + blen;
// Can we create a new slot ?
if (i > (PageSize - 4)) {
// Not enough space - Write the current buffer to FLASH
ee_PageWrite(curwPage + curwGroup * PagesPerGroup, buffer);
// Advance write page (as we are compacting, should never overflow!)
++curwPage;
// Clear RAM buffer
memset(buffer, 0xFF, sizeof(buffer));
// Start fresh */
i = 0;
}
// Enough space, add the new block
buffer[i] = rdAddr & 0xFF;
buffer[i + 1] = (rdAddr >> 8) & 0xFF;
buffer[i + 2] = 1;
buffer[i + 3] = rdValue;
}
}
}
// Go to the next address
++rdAddr;
// Repeat for bytes of this range
} while (--rdRange);
// Repeat until we run out of ranges
} while (rdAddr < EEPROMSize);
// We must erase the previous group, in preparation for the next swap
for (int page = 0; page < curPage; page++) {
ee_PageErase(page + curGroup * PagesPerGroup);
}
// Finally, Now the active group is the created new group
curGroup = curwGroup;
curPage = curwPage;
// Done!
return true;
}
static bool ee_Write(uint32_t address, uint8_t data) {
// If we were requested an address outside of the emulated range, fail now
if (address >= EEPROMSize) return false;
// Lets check if we have a block with that data previously defined. Block
// start addresses are always sorted in ascending order
uint16_t i = 0;
while (i <= (PageSize - 4)) { /* (PageSize - 4) because otherwise, there is not enough room for data and headers */
// Get the address of the block
uint32_t baddr = buffer[i] | (buffer[i + 1] << 8);
// Get the length of the block
uint32_t blen = buffer[i + 2];
// If we reach the end of the list, break loop
if (blen == 0xFF)
break;
// Check if data is contained in this block
if (address >= baddr &&
address < (baddr + blen)) {
// Yes, it is contained. Just modify it
buffer[i + 3 + address - baddr] = data;
// Done!
return true;
}
// Maybe we could add it to the front or to the back
// of this block ?
if ((address + 1) == baddr || address == (baddr + blen)) {
// Potentially, it could be done. But we must ensure there is room
// so we can expand the block. Lets find how much free space remains
uint32_t iend = i;
do {
uint32_t ln = buffer[iend + 2];
if (ln == 0xFF) break;
iend += 3 + ln;
} while (iend <= (PageSize - 4)); /* (PageSize - 4) because otherwise, there is not enough room for data and headers */
// Here, inxt points to the first free address in the buffer. Do we have room ?
if (iend < PageSize) {
// Yes, at least a byte is free - We can expand the block
// Do we have to insert at the beginning ?
if ((address + 1) == baddr) {
// Insert at the beginning
// Make room at the beginning for our byte
memmove(&buffer[i + 3 + 1], &buffer[i + 3], iend - i - 3);
// Adjust the header and store the data
buffer[i] = address & 0xFF;
buffer[i + 1] = (address >> 8) & 0xFF;
buffer[i + 2]++;
buffer[i + 3] = data;
}
else {
// Insert at the end - There is a very interesting thing that could happen here:
// Maybe we could coalesce the next block with this block. Let's try to do it!
uint16_t inext = i + 3 + blen;
if (inext <= (PageSize - 4) &&
(buffer[inext] | uint16_t(buffer[inext + 1] << 8)) == (baddr + blen + 1)) {
// YES! ... we can coalesce blocks! . Do it!
// Adjust this block header to include the next one
buffer[i + 2] += buffer[inext + 2] + 1;
// Store data at the right place
buffer[i + 3 + blen] = data;
// Remove the next block header and append its data
memmove(&buffer[inext + 1], &buffer[inext + 3], iend - inext - 3);
// Finally, as we have saved 2 bytes at the end, make sure to clean them
buffer[iend - 2] = 0xFF;
buffer[iend - 1] = 0xFF;
}
else {
// NO ... No coalescing possible yet
// Make room at the end for our byte
memmove(&buffer[i + 3 + blen + 1], &buffer[i + 3 + blen], iend - i - 3 - blen);
// And add the data to the block
buffer[i + 2]++;
buffer[i + 3 + blen] = data;
}
}
// Done!
return true;
}
}
// As blocks are always sorted, if the starting address of this block is higher
// than the address we are looking for, break loop now - We wont find the value
// associated to the address
if (baddr > address) break;
// Jump to the next block
i += 3 + blen;
}
// Value is not stored AND we can't expand previous block to contain it. We must create a new block
// First, lets find how much free space remains
uint32_t iend = i;
while (iend <= (PageSize - 4)) { /* (PageSize - 4) because otherwise, there is not enough room for data and headers */
uint32_t ln = buffer[iend + 2];
if (ln == 0xFF) break;
iend += 3 + ln;
}
// If there is room for a new block, insert it at the proper place
if (iend <= (PageSize - 4)) {
// We have room to create a new block. Do so --- But add
// the block at the proper position, sorted by starting
// address, so it will be possible to compact it with other blocks.
// Make space
memmove(&buffer[i + 4], &buffer[i], iend - i);
// And add the block
buffer[i] = address & 0xFF;
buffer[i + 1] = (address >> 8) & 0xFF;
buffer[i + 2] = 1;
buffer[i + 3] = data;
// Done!
return true;
}
// Not enough room to store this information on this FLASH page - Perform a
// flush and override the address with the specified contents
return ee_Flush(address, data);
}
static void ee_Init() {
// Just init once!
if (curGroup != 0xFF) return;
// Clean up the SRAM buffer
memset(buffer, 0xFF, sizeof(buffer));
// Now, we must find out the group where settings are stored
for (curGroup = 0; curGroup < GroupCount; curGroup++)
if (!ee_IsPageClean(curGroup * PagesPerGroup)) break;
// If all groups seem to be used, default to first group
if (curGroup >= GroupCount) curGroup = 0;
DEBUG_ECHO_MSG("EEPROM Current Group: ",curGroup);
DEBUG_FLUSH();
// Now, validate that all the other group pages are empty
for (int grp = 0; grp < GroupCount; grp++) {
if (grp == curGroup) continue;
for (int page = 0; page < PagesPerGroup; page++) {
if (!ee_IsPageClean(grp * PagesPerGroup + page)) {
DEBUG_ECHO_MSG("EEPROM Page ", page, " not clean on group ", grp);
DEBUG_FLUSH();
ee_PageErase(grp * PagesPerGroup + page);
}
}
}
// Finally, for the active group, determine the first unused page
// and also validate that all the other ones are clean
for (curPage = 0; curPage < PagesPerGroup; curPage++) {
if (ee_IsPageClean(curGroup * PagesPerGroup + curPage)) {
ee_Dump(curGroup * PagesPerGroup + curPage, getFlashStorage(curGroup * PagesPerGroup + curPage));
break;
}
}
DEBUG_ECHO_MSG("EEPROM Active page: ", curPage);
DEBUG_FLUSH();
// Make sure the pages following the first clean one are also clean
for (int page = curPage + 1; page < PagesPerGroup; page++) {
if (!ee_IsPageClean(curGroup * PagesPerGroup + page)) {
DEBUG_ECHO_MSG("EEPROM Page ", page, " not clean on active group ", curGroup);
DEBUG_FLUSH();
ee_Dump(curGroup * PagesPerGroup + page, getFlashStorage(curGroup * PagesPerGroup + page));
ee_PageErase(curGroup * PagesPerGroup + page);
}
}
}
/* PersistentStore -----------------------------------------------------------*/
#include "../shared/eeprom_api.h"
#ifndef MARLIN_EEPROM_SIZE
#define MARLIN_EEPROM_SIZE 0x1000 // 4KB
#endif
size_t PersistentStore::capacity() { return MARLIN_EEPROM_SIZE; }
bool PersistentStore::access_start() { ee_Init(); 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) {
uint16_t written = 0;
while (size--) {
uint8_t * const p = (uint8_t * const)pos;
uint8_t v = *value;
if (v != ee_Read(uint32_t(p))) { // EEPROM has only ~100,000 write cycles, so only write bytes that have changed!
ee_Write(uint32_t(p), v);
if (++written & 0x7F) delay(2); else safe_delay(2); // Avoid triggering watchdog during long EEPROM writes
if (ee_Read(uint32_t(p)) != v) {
SERIAL_ECHO_MSG(STR_ERR_EEPROM_WRITE);
return true;
}
}
crc16(crc, &v, 1);
pos++;
value++;
}
return false;
}
bool PersistentStore::read_data(int &pos, uint8_t *value, size_t size, uint16_t *crc, const bool writing/*=true*/) {
do {
uint8_t c = ee_Read(uint32_t(pos));
if (writing) *value = c;
crc16(crc, &c, 1);
pos++;
value++;
} while (--size);
return false;
}
#endif // FLASH_EEPROM_EMULATION
#endif // ARDUINO_ARCH_SAM

@ -0,0 +1,75 @@
/**
* 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"
#if USE_WIRED_EEPROM
/**
* PersistentStore for Arduino-style EEPROM interface
* with simple implementations supplied by Marlin.
*/
#include "../shared/eeprom_if.h"
#include "../shared/eeprom_api.h"
#ifndef MARLIN_EEPROM_SIZE
#error "MARLIN_EEPROM_SIZE is required for I2C / SPI EEPROM."
#endif
size_t PersistentStore::capacity() { return MARLIN_EEPROM_SIZE; }
bool PersistentStore::access_start() { eeprom_init(); return true; }
bool PersistentStore::access_finish() { return true; }
bool PersistentStore::write_data(int &pos, const uint8_t *value, size_t size, uint16_t *crc) {
uint16_t written = 0;
while (size--) {
uint8_t * const p = (uint8_t * const)pos;
uint8_t v = *value;
if (v != eeprom_read_byte(p)) { // EEPROM has only ~100,000 write cycles, so only write bytes that have changed!
eeprom_write_byte(p, v);
if (++written & 0x7F) delay(2); else safe_delay(2); // Avoid triggering watchdog during long EEPROM writes
if (eeprom_read_byte(p) != v) {
SERIAL_ECHO_MSG(STR_ERR_EEPROM_WRITE);
return true;
}
}
crc16(crc, &v, 1);
pos++;
value++;
}
return false;
}
bool PersistentStore::read_data(int &pos, uint8_t *value, size_t size, uint16_t *crc, const bool writing/*=true*/) {
do {
uint8_t c = eeprom_read_byte((uint8_t*)pos);
if (writing) *value = c;
crc16(crc, &c, 1);
pos++;
value++;
} while (--size);
return false;
}
#endif // USE_WIRED_EEPROM
#endif // ARDUINO_ARCH_SAM

@ -0,0 +1,79 @@
/**
* 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/>.
*
*/
#pragma once
/**
* Endstop Interrupts
*
* Without endstop interrupts the endstop pins must be polled continually in
* the temperature-ISR via endstops.update(), most of the time finding no change.
* With this feature endstops.update() is called only when we know that at
* least one endstop has changed state, saving valuable CPU cycles.
*
* This feature only works when all used endstop pins can generate an 'external interrupt'.
*
* Test whether pins issue interrupts on your board by flashing 'pin_interrupt_test.ino'.
* (Located in Marlin/buildroot/share/pin_interrupt_test/pin_interrupt_test.ino)
*/
#include "../../module/endstops.h"
// One ISR for all EXT-Interrupts
void endstop_ISR() { endstops.update(); }
/**
* Endstop interrupts for Due based targets.
* On Due, all pins support external interrupt capability.
*/
void setup_endstop_interrupts() {
#define _ATTACH(P) attachInterrupt(digitalPinToInterrupt(P), endstop_ISR, CHANGE)
TERN_(USE_X_MAX, _ATTACH(X_MAX_PIN));
TERN_(USE_X_MIN, _ATTACH(X_MIN_PIN));
TERN_(USE_Y_MAX, _ATTACH(Y_MAX_PIN));
TERN_(USE_Y_MIN, _ATTACH(Y_MIN_PIN));
TERN_(USE_Z_MAX, _ATTACH(Z_MAX_PIN));
TERN_(USE_Z_MIN, _ATTACH(Z_MIN_PIN));
TERN_(USE_X2_MAX, _ATTACH(X2_MAX_PIN));
TERN_(USE_X2_MIN, _ATTACH(X2_MIN_PIN));
TERN_(USE_Y2_MAX, _ATTACH(Y2_MAX_PIN));
TERN_(USE_Y2_MIN, _ATTACH(Y2_MIN_PIN));
TERN_(USE_Z2_MAX, _ATTACH(Z2_MAX_PIN));
TERN_(USE_Z2_MIN, _ATTACH(Z2_MIN_PIN));
TERN_(USE_Z3_MAX, _ATTACH(Z3_MAX_PIN));
TERN_(USE_Z3_MIN, _ATTACH(Z3_MIN_PIN));
TERN_(USE_Z4_MAX, _ATTACH(Z4_MAX_PIN));
TERN_(USE_Z4_MIN, _ATTACH(Z4_MIN_PIN));
TERN_(USE_Z_MIN_PROBE, _ATTACH(Z_MIN_PROBE_PIN));
TERN_(USE_I_MAX, _ATTACH(I_MAX_PIN));
TERN_(USE_I_MIN, _ATTACH(I_MIN_PIN));
TERN_(USE_J_MAX, _ATTACH(J_MAX_PIN));
TERN_(USE_J_MIN, _ATTACH(J_MIN_PIN));
TERN_(USE_K_MAX, _ATTACH(K_MAX_PIN));
TERN_(USE_K_MIN, _ATTACH(K_MIN_PIN));
TERN_(USE_U_MAX, _ATTACH(U_MAX_PIN));
TERN_(USE_U_MIN, _ATTACH(U_MIN_PIN));
TERN_(USE_V_MAX, _ATTACH(V_MAX_PIN));
TERN_(USE_V_MIN, _ATTACH(V_MIN_PIN));
TERN_(USE_W_MAX, _ATTACH(W_MAX_PIN));
TERN_(USE_W_MIN, _ATTACH(W_MIN_PIN));
}

@ -0,0 +1,565 @@
/**
* 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/>.
*
*/
#pragma once
/**
* Fast I/O Routines for SAM3X8E
* Use direct port manipulation to save scads of processor time.
* Contributed by Triffid_Hunter and modified by Kliment, thinkyhead, Bob-the-Kuhn, et.al.
*/
/**
* Description: Fast IO functions for Arduino Due and compatible (SAM3X8E)
*
* For ARDUINO_ARCH_SAM
* 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
* amount of instructions. Be very careful if you modify them, as "clean code"
* leads to less efficient compiled code!!
*/
#include <pins_arduino.h>
#include "../../inc/MarlinConfigPre.h"
/**
* Utility functions
*/
// Due has 12 PWMs assigned to logical pins 2-13.
// 6, 7, 8 & 9 come from the PWM controller. The others come from the timers.
#define PWM_PIN(P) WITHIN(P, 2, 13)
#ifndef MASK
#define MASK(PIN) _BV(PIN)
#endif
/**
* Magic I/O routines
*
* Now you can simply SET_OUTPUT(STEP); WRITE(STEP, HIGH); WRITE(STEP, LOW);
*
* Why double up on these macros? see https://gcc.gnu.org/onlinedocs/cpp/Stringification.html
*/
// Read a pin
#define _READ(IO) bool(DIO ## IO ## _WPORT -> PIO_PDSR & MASK(DIO ## IO ## _PIN))
// Write to a pin
#define _WRITE(IO,V) do { \
volatile Pio* port = (DIO ## IO ## _WPORT); \
const uint32_t mask = MASK(DIO ## IO ## _PIN); \
if (V) port->PIO_SODR = mask; \
else port->PIO_CODR = mask; \
}while(0)
// Toggle a pin
#define _TOGGLE(IO) _WRITE(IO, !READ(IO))
#if MB(PRINTRBOARD_G2)
#include "fastio/G2_pins.h"
// Set pin as input
#define _SET_INPUT(IO) do{ \
pmc_enable_periph_clk(G2_g_APinDescription[IO].ulPeripheralId); \
PIO_Configure((DIO ## IO ## _WPORT), PIO_INPUT, MASK(DIO ## IO ## _PIN), 0); \
}while(0)
// Set pin as output
#define _SET_OUTPUT(IO) do{ \
uint32_t mask = MASK(G2_g_APinDescription[IO].ulPeripheralId); \
if ((PMC->PMC_PCSR0 & mask) != (mask)) PMC->PMC_PCER0 = mask; \
volatile Pio* port = (DIO ## IO ## _WPORT); \
mask = MASK(DIO ## IO ## _PIN); \
if (_READ(IO)) port->PIO_SODR = mask; \
else port->PIO_CODR = mask; \
port->PIO_IDR = mask; \
const uint32_t pin_config = G2_g_APinDescription[IO].ulPinConfiguration; \
if (pin_config & PIO_PULLUP) port->PIO_PUER = mask; \
else port->PIO_PUDR = mask; \
if (pin_config & PIO_OPENDRAIN) port->PIO_MDER = mask; \
else port->PIO_MDDR = mask; \
port->PIO_PER = mask; \
port->PIO_OER = mask; \
g_pinStatus[IO] = (g_pinStatus[IO] & 0xF0) | PIN_STATUS_DIGITAL_OUTPUT; \
}while(0)
/**
* Set pin as output with comments
* #define _SET_OUTPUT(IO) do{ \
* uint32_t mask = MASK(G2_g_APinDescription[IO].ulPeripheralId); \
* if ((PMC->PMC_PCSR0 & mask ) != (mask)) PMC->PMC_PCER0 = mask; \ // enable PIO clock if not already enabled
*
* volatile Pio* port = (DIO ## IO ## _WPORT); \
* const uint32_t mask = MASK(DIO ## IO ## _PIN); \
* if (_READ(IO)) port->PIO_SODR = mask; \ // set output to match input BEFORE setting direction or will glitch the output
* else port->PIO_CODR = mask; \
*
* port->PIO_IDR = mask; \ // disable interrupt
*
* uint32_t pin_config = G2_g_APinDescription[IO].ulPinConfiguration; \
* if (pin_config & PIO_PULLUP) pPio->PIO_PUER = mask; \ // enable pullup if necessary
* else pPio->PIO_PUDR = mask; \
*
* if (pin_config & PIO_OPENDRAIN) port->PIO_MDER = mask; \ // Enable multi-drive if necessary
* else port->PIO_MDDR = mask; \
*
* port->PIO_PER = mask; \
* port->PIO_OER = mask; \ // set to output
*
* g_pinStatus[IO] = (g_pinStatus[IO] & 0xF0) | PIN_STATUS_DIGITAL_OUTPUT; \
* }while(0)
*/
#else
// Set pin as input
#define _SET_INPUT(IO) do{ \
pmc_enable_periph_clk(g_APinDescription[IO].ulPeripheralId); \
PIO_Configure(digitalPinToPort(IO), PIO_INPUT, digitalPinToBitMask(IO), 0); \
}while(0)
// Set pin as output
#define _SET_OUTPUT(IO) do{ \
pmc_enable_periph_clk(g_APinDescription[IO].ulPeripheralId); \
PIO_Configure(digitalPinToPort(IO), _READ(IO) ? PIO_OUTPUT_1 : PIO_OUTPUT_0, digitalPinToBitMask(IO), g_APinDescription[IO].ulPinConfiguration); \
g_pinStatus[IO] = (g_pinStatus[IO] & 0xF0) | PIN_STATUS_DIGITAL_OUTPUT; \
}while(0)
#endif
// Set pin as input with pullup mode
#define _PULLUP(IO,V) pinMode(IO, (V) ? INPUT_PULLUP : INPUT)
// Read a pin (wrapper)
#define READ(IO) _READ(IO)
// Write to a pin (wrapper)
#define WRITE(IO,V) _WRITE(IO,V)
// Toggle a pin (wrapper)
#define TOGGLE(IO) _TOGGLE(IO)
// Set pin as input (wrapper)
#define SET_INPUT(IO) _SET_INPUT(IO)
// Set pin as input with pullup (wrapper)
#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
#define SET_OUTPUT(IO) _SET_OUTPUT(IO)
// Set pin as PWM
#define SET_PWM SET_OUTPUT
// Check if pin is an input
#define IS_INPUT(IO) ((digitalPinToPort(IO)->PIO_OSR & digitalPinToBitMask(IO)) == 0)
// Check if pin is an output
#define IS_OUTPUT(IO) ((digitalPinToPort(IO)->PIO_OSR & digitalPinToBitMask(IO)) != 0)
// Shorthand
#define OUT_WRITE(IO,V) do{ SET_OUTPUT(IO); WRITE(IO,V); }while(0)
// digitalRead/Write wrappers
#define extDigitalRead(IO) digitalRead(IO)
#define extDigitalWrite(IO,V) digitalWrite(IO,V)
/**
* Ports and functions
* Added as necessary or if I feel like it- not a comprehensive list!
*/
// UART
#define RXD 0
#define TXD 1
// TWI (I2C)
#define SCL 21
#define SDA 20
/**
* pins
*/
#define DIO0_PIN 8
#define DIO0_WPORT PIOA
#define DIO1_PIN 9
#define DIO1_WPORT PIOA
#define DIO2_PIN 25
#define DIO2_WPORT PIOB
#define DIO3_PIN 28
#define DIO3_WPORT PIOC
#define DIO4_PIN 26
#define DIO4_WPORT PIOC
#define DIO5_PIN 25
#define DIO5_WPORT PIOC
#define DIO6_PIN 24
#define DIO6_WPORT PIOC
#define DIO7_PIN 23
#define DIO7_WPORT PIOC
#define DIO8_PIN 22
#define DIO8_WPORT PIOC
#define DIO9_PIN 21
#define DIO9_WPORT PIOC
#define DIO10_PIN 29
#define DIO10_WPORT PIOC
#define DIO11_PIN 7
#define DIO11_WPORT PIOD
#define DIO12_PIN 8
#define DIO12_WPORT PIOD
#define DIO13_PIN 27
#define DIO13_WPORT PIOB
#define DIO14_PIN 4
#define DIO14_WPORT PIOD
#define DIO15_PIN 5
#define DIO15_WPORT PIOD
#define DIO16_PIN 13
#define DIO16_WPORT PIOA
#define DIO17_PIN 12
#define DIO17_WPORT PIOA
#define DIO18_PIN 11
#define DIO18_WPORT PIOA
#define DIO19_PIN 10
#define DIO19_WPORT PIOA
#define DIO20_PIN 12
#define DIO20_WPORT PIOB
#define DIO21_PIN 13
#define DIO21_WPORT PIOB
#define DIO22_PIN 26
#define DIO22_WPORT PIOB
#define DIO23_PIN 14
#define DIO23_WPORT PIOA
#define DIO24_PIN 15
#define DIO24_WPORT PIOA
#define DIO25_PIN 0
#define DIO25_WPORT PIOD
#define DIO26_PIN 1
#define DIO26_WPORT PIOD
#define DIO27_PIN 2
#define DIO27_WPORT PIOD
#define DIO28_PIN 3
#define DIO28_WPORT PIOD
#define DIO29_PIN 6
#define DIO29_WPORT PIOD
#define DIO30_PIN 9
#define DIO30_WPORT PIOD
#define DIO31_PIN 7
#define DIO31_WPORT PIOA
#define DIO32_PIN 10
#define DIO32_WPORT PIOD
#define DIO33_PIN 1
#define DIO33_WPORT PIOC
#if !MB(PRINTRBOARD_G2) // normal DUE pin mapping
#define DIO34_PIN 2
#define DIO34_WPORT PIOC
#define DIO35_PIN 3
#define DIO35_WPORT PIOC
#define DIO36_PIN 4
#define DIO36_WPORT PIOC
#define DIO37_PIN 5
#define DIO37_WPORT PIOC
#define DIO38_PIN 6
#define DIO38_WPORT PIOC
#define DIO39_PIN 7
#define DIO39_WPORT PIOC
#define DIO40_PIN 8
#define DIO40_WPORT PIOC
#define DIO41_PIN 9
#define DIO41_WPORT PIOC
#endif // !PRINTRBOARD_G2
#define DIO42_PIN 19
#define DIO42_WPORT PIOA
#define DIO43_PIN 20
#define DIO43_WPORT PIOA
#define DIO44_PIN 19
#define DIO44_WPORT PIOC
#define DIO45_PIN 18
#define DIO45_WPORT PIOC
#define DIO46_PIN 17
#define DIO46_WPORT PIOC
#define DIO47_PIN 16
#define DIO47_WPORT PIOC
#define DIO48_PIN 15
#define DIO48_WPORT PIOC
#define DIO49_PIN 14
#define DIO49_WPORT PIOC
#define DIO50_PIN 13
#define DIO50_WPORT PIOC
#define DIO51_PIN 12
#define DIO51_WPORT PIOC
#define DIO52_PIN 21
#define DIO52_WPORT PIOB
#define DIO53_PIN 14
#define DIO53_WPORT PIOB
#define DIO54_PIN 16
#define DIO54_WPORT PIOA
#define DIO55_PIN 24
#define DIO55_WPORT PIOA
#define DIO56_PIN 23
#define DIO56_WPORT PIOA
#define DIO57_PIN 22
#define DIO57_WPORT PIOA
#define DIO58_PIN 6
#define DIO58_WPORT PIOA
#define DIO59_PIN 4
#define DIO59_WPORT PIOA
#define DIO60_PIN 3
#define DIO60_WPORT PIOA
#define DIO61_PIN 2
#define DIO61_WPORT PIOA
#define DIO62_PIN 17
#define DIO62_WPORT PIOB
#define DIO63_PIN 18
#define DIO63_WPORT PIOB
#define DIO64_PIN 19
#define DIO64_WPORT PIOB
#define DIO65_PIN 20
#define DIO65_WPORT PIOB
#define DIO66_PIN 15
#define DIO66_WPORT PIOB
#define DIO67_PIN 16
#define DIO67_WPORT PIOB
#define DIO68_PIN 1
#define DIO68_WPORT PIOA
#define DIO69_PIN 0
#define DIO69_WPORT PIOA
#define DIO70_PIN 17
#define DIO70_WPORT PIOA
#define DIO71_PIN 18
#define DIO71_WPORT PIOA
#define DIO72_PIN 30
#define DIO72_WPORT PIOC
#define DIO73_PIN 21
#define DIO73_WPORT PIOA
#define DIO74_PIN 25
#define DIO74_WPORT PIOA
#define DIO75_PIN 26
#define DIO75_WPORT PIOA
#define DIO76_PIN 27
#define DIO76_WPORT PIOA
#define DIO77_PIN 28
#define DIO77_WPORT PIOA
#define DIO78_PIN 23
#define DIO78_WPORT PIOB
#define DIO79_PIN 17
#define DIO79_WPORT PIOA
#define DIO80_PIN 12
#define DIO80_WPORT PIOB
#define DIO81_PIN 8
#define DIO81_WPORT PIOA
#define DIO82_PIN 11
#define DIO82_WPORT PIOA
#define DIO83_PIN 13
#define DIO83_WPORT PIOA
#define DIO84_PIN 4
#define DIO84_WPORT PIOD
#define DIO85_PIN 11
#define DIO85_WPORT PIOB
#define DIO86_PIN 21
#define DIO86_WPORT PIOB
#define DIO87_PIN 29
#define DIO87_WPORT PIOA
#define DIO88_PIN 15
#define DIO88_WPORT PIOB
#define DIO89_PIN 14
#define DIO89_WPORT PIOB
#define DIO90_PIN 1
#define DIO90_WPORT PIOA
#define DIO91_PIN 15
#define DIO91_WPORT PIOB
#ifdef ARDUINO_SAM_ARCHIM
#define DIO92_PIN 11
#define DIO92_WPORT PIOC
#define DIO93_PIN 2
#define DIO93_WPORT PIOB
#define DIO94_PIN 1
#define DIO94_WPORT PIOB
#define DIO95_PIN 0
#define DIO95_WPORT PIOB
#define DIO96_PIN 10
#define DIO96_WPORT PIOC
#define DIO97_PIN 24
#define DIO97_WPORT PIOB
#define DIO98_PIN 7
#define DIO98_WPORT PIOB
#define DIO99_PIN 6
#define DIO99_WPORT PIOB
#define DIO100_PIN 8
#define DIO100_WPORT PIOB
#define DIO101_PIN 5
#define DIO101_WPORT PIOB
#define DIO102_PIN 4
#define DIO102_WPORT PIOB
#define DIO103_PIN 3
#define DIO103_WPORT PIOB
#define DIO104_PIN 20
#define DIO104_WPORT PIOC
#define DIO105_PIN 22
#define DIO105_WPORT PIOB
#define DIO106_PIN 27
#define DIO106_WPORT PIOC
#define DIO107_PIN 10
#define DIO107_WPORT PIOB
#define DIO108_PIN 9
#define DIO108_WPORT PIOB
#else // !ARDUINO_SAM_ARCHIM
#define DIO92_PIN 5
#define DIO92_WPORT PIOA
#define DIO93_PIN 12
#define DIO93_WPORT PIOB
#define DIO94_PIN 22
#define DIO94_WPORT PIOB
#define DIO95_PIN 23
#define DIO95_WPORT PIOB
#define DIO96_PIN 24
#define DIO96_WPORT PIOB
#define DIO97_PIN 20
#define DIO97_WPORT PIOC
#define DIO98_PIN 27
#define DIO98_WPORT PIOC
#define DIO99_PIN 10
#define DIO99_WPORT PIOC
#define DIO100_PIN 11
#define DIO100_WPORT PIOC
#endif // !ARDUINO_SAM_ARCHIM

@ -0,0 +1,206 @@
/**
* 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/>.
*
*/
/**
* The PWM module is only used to generate interrupts at specified times. It
* is NOT used to directly toggle pins. The ISR writes to the pin assigned to
* that interrupt.
*
* All PWMs use the same repetition rate. The G2 needs about 10kHz min in order to
* not have obvious ripple on the Vref signals.
*
* The data structures are setup to minimize the computation done by the ISR which
* minimizes ISR execution time. Execution times are 0.8 to 1.1 microseconds.
*
* FIve PWM interrupt sources are used. Channel 0 sets the base period. All Vref
* signals are set active when this counter overflows and resets to zero. The compare
* values in channels 1-4 are set to give the desired duty cycle for that Vref pin.
* When counter 0 matches the compare value then that channel generates an interrupt.
* The ISR checks the source of the interrupt and sets the corresponding pin inactive.
*
* Some jitter in the Vref signal is OK so the interrupt priority is left at its default value.
*/
#include "../../../inc/MarlinConfig.h"
#if MB(PRINTRBOARD_G2)
#include "G2_PWM.h"
#if PIN_EXISTS(MOTOR_CURRENT_PWM_X)
#define G2_PWM_X 1
#else
#define G2_PWM_X 0
#endif
#if PIN_EXISTS(MOTOR_CURRENT_PWM_Y)
#define G2_PWM_Y 1
#else
#define G2_PWM_Y 0
#endif
#if PIN_EXISTS(MOTOR_CURRENT_PWM_Z)
#define G2_PWM_Z 1
#else
#define G2_PWM_Z 0
#endif
#if PIN_EXISTS(MOTOR_CURRENT_PWM_E)
#define G2_PWM_E 1
#else
#define G2_PWM_E 0
#endif
#define G2_MASK_X(V) (G2_PWM_X * (V))
#define G2_MASK_Y(V) (G2_PWM_Y * (V))
#define G2_MASK_Z(V) (G2_PWM_Z * (V))
#define G2_MASK_E(V) (G2_PWM_E * (V))
volatile uint32_t *SODR_A = &PIOA->PIO_SODR,
*SODR_B = &PIOB->PIO_SODR,
*CODR_A = &PIOA->PIO_CODR,
*CODR_B = &PIOB->PIO_CODR;
PWM_map ISR_table[NUM_PWMS] = PWM_MAP_INIT;
void Stepper::digipot_init() {
#if PIN_EXISTS(MOTOR_CURRENT_PWM_X)
OUT_WRITE(MOTOR_CURRENT_PWM_X_PIN, 0); // init pins
#endif
#if PIN_EXISTS(MOTOR_CURRENT_PWM_Y)
OUT_WRITE(MOTOR_CURRENT_PWM_Y_PIN, 0);
#endif
#if G2_PWM_Z
OUT_WRITE(MOTOR_CURRENT_PWM_Z_PIN, 0);
#endif
#if G2_PWM_E
OUT_WRITE(MOTOR_CURRENT_PWM_E_PIN, 0);
#endif
#define WPKEY (0x50574D << 8) // “PWM” in ASCII
#define WPCMD_DIS_SW 0 // command to disable Write Protect SW
#define WPRG_ALL (PWM_WPCR_WPRG0 | PWM_WPCR_WPRG1 | PWM_WPCR_WPRG2 | PWM_WPCR_WPRG3 | PWM_WPCR_WPRG4 | PWM_WPCR_WPRG5) // all Write Protect Groups
#define PWM_CLOCK_F F_CPU / 1000000UL // set clock to 1MHz
PMC->PMC_PCER1 = PMC_PCER1_PID36; // enable PWM controller clock (disabled on power up)
PWM->PWM_WPCR = WPKEY | WPRG_ALL | WPCMD_DIS_SW; // enable setting of all PWM registers
PWM->PWM_CLK = PWM_CLOCK_F; // enable CLK_A and set it to 1MHz, leave CLK_B disabled
PWM->PWM_CH_NUM[0].PWM_CMR = 0b1011; // set channel 0 to Clock A input & to left aligned
if (G2_PWM_X) PWM->PWM_CH_NUM[1].PWM_CMR = 0b1011; // set channel 1 to Clock A input & to left aligned
if (G2_PWM_Y) PWM->PWM_CH_NUM[2].PWM_CMR = 0b1011; // set channel 2 to Clock A input & to left aligned
if (G2_PWM_Z) PWM->PWM_CH_NUM[3].PWM_CMR = 0b1011; // set channel 3 to Clock A input & to left aligned
if (G2_PWM_E) PWM->PWM_CH_NUM[4].PWM_CMR = 0b1011; // set channel 4 to Clock A input & to left aligned
PWM->PWM_CH_NUM[0].PWM_CPRD = PWM_PERIOD_US; // set channel 0 Period
PWM->PWM_IER2 = PWM_IER1_CHID0; // generate interrupt when counter0 overflows
PWM->PWM_IER2 = PWM_IER2_CMPM0
| G2_MASK_X(PWM_IER2_CMPM1)
| G2_MASK_Y(PWM_IER2_CMPM2)
| G2_MASK_Z(PWM_IER2_CMPM3)
| G2_MASK_E(PWM_IER2_CMPM4)
; // generate interrupt on compare event
if (G2_PWM_X) PWM->PWM_CMP[1].PWM_CMPV = 0x010000000LL | G2_VREF_COUNT(G2_VREF(motor_current_setting[0])); // interrupt when counter0 == CMPV - used to set Motor 1 PWM inactive
if (G2_PWM_Y) PWM->PWM_CMP[2].PWM_CMPV = 0x010000000LL | G2_VREF_COUNT(G2_VREF(motor_current_setting[0])); // interrupt when counter0 == CMPV - used to set Motor 2 PWM inactive
if (G2_PWM_Z) PWM->PWM_CMP[3].PWM_CMPV = 0x010000000LL | G2_VREF_COUNT(G2_VREF(motor_current_setting[1])); // interrupt when counter0 == CMPV - used to set Motor 3 PWM inactive
if (G2_PWM_E) PWM->PWM_CMP[4].PWM_CMPV = 0x010000000LL | G2_VREF_COUNT(G2_VREF(motor_current_setting[2])); // interrupt when counter0 == CMPV - used to set Motor 4 PWM inactive
if (G2_PWM_X) PWM->PWM_CMP[1].PWM_CMPM = 0x0001; // enable compare event
if (G2_PWM_Y) PWM->PWM_CMP[2].PWM_CMPM = 0x0001; // enable compare event
if (G2_PWM_Z) PWM->PWM_CMP[3].PWM_CMPM = 0x0001; // enable compare event
if (G2_PWM_E) PWM->PWM_CMP[4].PWM_CMPM = 0x0001; // enable compare event
PWM->PWM_SCM = PWM_SCM_UPDM_MODE0 | PWM_SCM_SYNC0
| G2_MASK_X(PWM_SCM_SYNC1)
| G2_MASK_Y(PWM_SCM_SYNC2)
| G2_MASK_Z(PWM_SCM_SYNC3)
| G2_MASK_E(PWM_SCM_SYNC4)
; // sync 1-4 with 0, use mode 0 for updates
PWM->PWM_ENA = PWM_ENA_CHID0
| G2_MASK_X(PWM_ENA_CHID1)
| G2_MASK_Y(PWM_ENA_CHID2)
| G2_MASK_Z(PWM_ENA_CHID3)
| G2_MASK_E(PWM_ENA_CHID4)
; // enable channels used by G2
PWM->PWM_IER1 = PWM_IER1_CHID0
| G2_MASK_X(PWM_IER1_CHID1)
| G2_MASK_Y(PWM_IER1_CHID2)
| G2_MASK_Z(PWM_IER1_CHID3)
| G2_MASK_E(PWM_IER1_CHID4)
; // enable interrupts for channels used by G2
NVIC_EnableIRQ(PWM_IRQn); // Enable interrupt handler
NVIC_SetPriority(PWM_IRQn, NVIC_EncodePriority(0, 10, 0)); // normal priority for PWM module (can stand some jitter on the Vref signals)
}
void Stepper::set_digipot_current(const uint8_t driver, const int16_t current) {
if (!(PWM->PWM_CH_NUM[0].PWM_CPRD == PWM_PERIOD_US)) digipot_init(); // Init PWM system if needed
switch (driver) {
case 0:
if (G2_PWM_X) PWM->PWM_CMP[1].PWM_CMPVUPD = 0x010000000LL | G2_VREF_COUNT(G2_VREF(current)); // update X & Y
if (G2_PWM_Y) PWM->PWM_CMP[2].PWM_CMPVUPD = 0x010000000LL | G2_VREF_COUNT(G2_VREF(current));
if (G2_PWM_X) PWM->PWM_CMP[1].PWM_CMPMUPD = 0x0001; // enable compare event
if (G2_PWM_Y) PWM->PWM_CMP[2].PWM_CMPMUPD = 0x0001; // enable compare event
if (G2_PWM_X || G2_PWM_Y) PWM->PWM_SCUC = PWM_SCUC_UPDULOCK; // tell the PWM controller to update the values on the next cycle
break;
case 1:
if (G2_PWM_Z) {
PWM->PWM_CMP[3].PWM_CMPVUPD = 0x010000000LL | G2_VREF_COUNT(G2_VREF(current)); // update Z
PWM->PWM_CMP[3].PWM_CMPMUPD = 0x0001; // enable compare event
PWM->PWM_SCUC = PWM_SCUC_UPDULOCK; // tell the PWM controller to update the values on the next cycle
}
break;
default:
if (G2_PWM_E) {
PWM->PWM_CMP[4].PWM_CMPVUPD = 0x010000000LL | G2_VREF_COUNT(G2_VREF(current)); // update E
PWM->PWM_CMP[4].PWM_CMPMUPD = 0x0001; // enable compare event
PWM->PWM_SCUC = PWM_SCUC_UPDULOCK; // tell the PWM controller to update the values on the next cycle
}
break;
}
}
volatile uint32_t PWM_ISR1_STATUS, PWM_ISR2_STATUS;
void PWM_Handler() {
PWM_ISR1_STATUS = PWM->PWM_ISR1;
PWM_ISR2_STATUS = PWM->PWM_ISR2;
if (PWM_ISR1_STATUS & PWM_IER1_CHID0) { // CHAN_0 interrupt
if (G2_PWM_X) *ISR_table[0].set_register = ISR_table[0].write_mask; // set X to active
if (G2_PWM_Y) *ISR_table[1].set_register = ISR_table[1].write_mask; // set Y to active
if (G2_PWM_Z) *ISR_table[2].set_register = ISR_table[2].write_mask; // set Z to active
if (G2_PWM_E) *ISR_table[3].set_register = ISR_table[3].write_mask; // set E to active
}
else {
if (G2_PWM_X && (PWM_ISR2_STATUS & PWM_IER2_CMPM1)) *ISR_table[0].clr_register = ISR_table[0].write_mask; // set X to inactive
if (G2_PWM_Y && (PWM_ISR2_STATUS & PWM_IER2_CMPM2)) *ISR_table[1].clr_register = ISR_table[1].write_mask; // set Y to inactive
if (G2_PWM_Z && (PWM_ISR2_STATUS & PWM_IER2_CMPM3)) *ISR_table[2].clr_register = ISR_table[2].write_mask; // set Z to inactive
if (G2_PWM_E && (PWM_ISR2_STATUS & PWM_IER2_CMPM4)) *ISR_table[3].clr_register = ISR_table[3].write_mask; // set E to inactive
}
return;
}
#endif // PRINTRBOARD_G2

@ -0,0 +1,78 @@
/**
* 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/>.
*
*/
#pragma once
/**
* This module is stripped down version of the LPC1768_PWM.h file from
* PR #7500. It is hardwired for the PRINTRBOARD_G2 Motor Current needs.
*/
#include "../../../inc/MarlinConfigPre.h"
#include "../../../module/stepper.h"
//C:\Users\bobku\Documents\GitHub\Marlin-Bob-2\Marlin\src\module\stepper.h
//C:\Users\bobku\Documents\GitHub\Marlin-Bob-2\Marlin\src\HAL\HAL_DUE\G2_PWM.h
#define PWM_PERIOD_US 100 // base repetition rate in micro seconds
typedef struct { // holds the data needed by the ISR to control the Vref pin
volatile uint32_t* set_register;
volatile uint32_t* clr_register;
uint32_t write_mask;
} PWM_map;
#define G2_VREF(I) (uint32_t)(I * 5 * 0.15) // desired Vref * 1000 (scaled so don't loose accuracy in next step)
#define G2_VREF_COUNT(Q) (uint32_t)map(constrain(Q, 500, 3.3 * 1000), 0, 3.3 * 1000, 0, PWM_PERIOD_US) // under 500 the results are very non-linear
extern volatile uint32_t *SODR_A, *SODR_B, *CODR_A, *CODR_B;
#define _PIN(IO) (DIO ## IO ## _PIN)
#define PWM_MAP_INIT_ROW(IO,ZZ) { ZZ == 'A' ? SODR_A : SODR_B, ZZ == 'A' ? CODR_A : CODR_B, 1 << _PIN(IO) }
#define PWM_MAP_INIT { PWM_MAP_INIT_ROW(MOTOR_CURRENT_PWM_X_PIN, 'B'), \
PWM_MAP_INIT_ROW(MOTOR_CURRENT_PWM_Y_PIN, 'B'), \
PWM_MAP_INIT_ROW(MOTOR_CURRENT_PWM_Z_PIN, 'B'), \
PWM_MAP_INIT_ROW(MOTOR_CURRENT_PWM_E_PIN, 'A'), \
};
#define NUM_PWMS 4
extern PWM_map ISR_table[NUM_PWMS];
extern uint32_t motor_current_setting[3];
#define IR_BIT(p) (WITHIN(p, 0, 3) ? (p) : (p) + 4)
#define COPY_ACTIVE_TABLE() do{ for (uint8_t i = 0; i < 6; ++i) work_table[i] = active_table[i]; }while(0)
#define PWM_MR0 19999 // base repetition rate minus one count - 20mS
#define PWM_PR 24 // prescaler value - prescaler divide by 24 + 1 - 1 MHz output
#define PWM_PCLKSEL0 0x00 // select clock source for prescaler - defaults to 25MHz on power up
// 0: 25MHz, 1: 100MHz, 2: 50MHz, 3: 12.5MHZ to PWM1 prescaler
#define MR0_MARGIN 200 // if channel value too close to MR0 the system locks up
extern bool PWM_table_swap; // flag to tell the ISR that the tables have been swapped
#define HAL_G2_PWM_ISR void PWM_Handler()
extern volatile uint32_t PWM_ISR1_STATUS, PWM_ISR2_STATUS;

@ -0,0 +1,278 @@
/**
* 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/>.
*
*/
#pragma once
#include <stdint.h>
/**
* This file contains the custom port/pin definitions for the PRINTRBOARD_G2
* motherboard. This motherboard uses the SAM3X8C which is a subset of the
* SAM3X8E used in the DUE board. It uses port/pin pairs that are not
* available using the DUE definitions.
*
* The first part is a copy of the pin descriptions in the
* "variants\arduino_due_x\variant.cpp" file but with pins 34-41 replaced by
* the G2 pins.
*
* The second part is the FASTIO port/pin definitions.
*
* THESE PINS CAN ONLY BE ACCESSED VIA FASTIO COMMANDS.
*/
/*
Copyright (c) 2011 Arduino. All right reserved.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
typedef struct _G2_PinDescription {
Pio* pPort;
uint32_t ulPin;
uint32_t ulPeripheralId;
EPioType ulPinType;
uint32_t ulPinConfiguration;
uint32_t ulPinAttribute;
EAnalogChannel ulAnalogChannel; /* Analog pin in the Arduino context (label on the board) */
EAnalogChannel ulADCChannelNumber; /* ADC Channel number in the SAM device */
EPWMChannel ulPWMChannel;
ETCChannel ulTCChannel;
} G2_PinDescription;
/**
* This section is a copy of the pin descriptions in the "variants\arduino_due_x\variant.cpp" file
* with pins 34-41 replaced by the G2 pins.
*/
/**
* Pins descriptions
*/
const G2_PinDescription G2_g_APinDescription[] = {
// 0 .. 53 - Digital pins
// ----------------------
// 0/1 - UART (Serial)
{ PIOA, PIO_PA8A_URXD, ID_PIOA, PIO_PERIPH_A, PIO_DEFAULT, PIN_ATTR_DIGITAL, NO_ADC, NO_ADC, NOT_ON_PWM, NOT_ON_TIMER }, // URXD
{ PIOA, PIO_PA9A_UTXD, ID_PIOA, PIO_PERIPH_A, PIO_DEFAULT, PIN_ATTR_DIGITAL, NO_ADC, NO_ADC, NOT_ON_PWM, NOT_ON_TIMER }, // UTXD
// 2
{ PIOB, PIO_PB25B_TIOA0, ID_PIOB, PIO_PERIPH_B, PIO_DEFAULT, (PIN_ATTR_DIGITAL|PIN_ATTR_TIMER), NO_ADC, NO_ADC, NOT_ON_PWM, TC0_CHA0 }, // TIOA0
{ PIOC, PIO_PC28B_TIOA7, ID_PIOC, PIO_PERIPH_B, PIO_DEFAULT, (PIN_ATTR_DIGITAL|PIN_ATTR_TIMER), NO_ADC, NO_ADC, NOT_ON_PWM, TC2_CHA7 }, // TIOA7
{ PIOC, PIO_PC26B_TIOB6, ID_PIOC, PIO_PERIPH_B, PIO_DEFAULT, (PIN_ATTR_DIGITAL|PIN_ATTR_TIMER), NO_ADC, NO_ADC, NOT_ON_PWM, TC2_CHB6 }, // TIOB6
// 5
{ PIOC, PIO_PC25B_TIOA6, ID_PIOC, PIO_PERIPH_B, PIO_DEFAULT, (PIN_ATTR_DIGITAL|PIN_ATTR_TIMER), NO_ADC, NO_ADC, NOT_ON_PWM, TC2_CHA6 }, // TIOA6
{ PIOC, PIO_PC24B_PWML7, ID_PIOC, PIO_PERIPH_B, PIO_DEFAULT, (PIN_ATTR_DIGITAL|PIN_ATTR_PWM), NO_ADC, NO_ADC, PWM_CH7, NOT_ON_TIMER }, // PWML7
{ PIOC, PIO_PC23B_PWML6, ID_PIOC, PIO_PERIPH_B, PIO_DEFAULT, (PIN_ATTR_DIGITAL|PIN_ATTR_PWM), NO_ADC, NO_ADC, PWM_CH6, NOT_ON_TIMER }, // PWML6
{ PIOC, PIO_PC22B_PWML5, ID_PIOC, PIO_PERIPH_B, PIO_DEFAULT, (PIN_ATTR_DIGITAL|PIN_ATTR_PWM), NO_ADC, NO_ADC, PWM_CH5, NOT_ON_TIMER }, // PWML5
{ PIOC, PIO_PC21B_PWML4, ID_PIOC, PIO_PERIPH_B, PIO_DEFAULT, (PIN_ATTR_DIGITAL|PIN_ATTR_PWM), NO_ADC, NO_ADC, PWM_CH4, NOT_ON_TIMER }, // PWML4
// 10
{ PIOC, PIO_PC29B_TIOB7, ID_PIOC, PIO_PERIPH_B, PIO_DEFAULT, (PIN_ATTR_DIGITAL|PIN_ATTR_TIMER), NO_ADC, NO_ADC, NOT_ON_PWM, TC2_CHB7 }, // TIOB7
{ PIOD, PIO_PD7B_TIOA8, ID_PIOD, PIO_PERIPH_B, PIO_DEFAULT, (PIN_ATTR_DIGITAL|PIN_ATTR_TIMER), NO_ADC, NO_ADC, NOT_ON_PWM, TC2_CHA8 }, // TIOA8
{ PIOD, PIO_PD8B_TIOB8, ID_PIOD, PIO_PERIPH_B, PIO_DEFAULT, (PIN_ATTR_DIGITAL|PIN_ATTR_TIMER), NO_ADC, NO_ADC, NOT_ON_PWM, TC2_CHB8 }, // TIOB8
// 13 - AMBER LED
{ PIOB, PIO_PB27B_TIOB0, ID_PIOB, PIO_PERIPH_B, PIO_DEFAULT, (PIN_ATTR_DIGITAL|PIN_ATTR_TIMER), NO_ADC, NO_ADC, NOT_ON_PWM, TC0_CHB0 }, // TIOB0
// 14/15 - USART3 (Serial3)
{ PIOD, PIO_PD4B_TXD3, ID_PIOD, PIO_PERIPH_B, PIO_DEFAULT, PIN_ATTR_DIGITAL, NO_ADC, NO_ADC, NOT_ON_PWM, NOT_ON_TIMER }, // TXD3
{ PIOD, PIO_PD5B_RXD3, ID_PIOD, PIO_PERIPH_B, PIO_DEFAULT, PIN_ATTR_DIGITAL, NO_ADC, NO_ADC, NOT_ON_PWM, NOT_ON_TIMER }, // RXD3
// 16/17 - USART1 (Serial2)
{ PIOA, PIO_PA13A_TXD1, ID_PIOA, PIO_PERIPH_A, PIO_DEFAULT, PIN_ATTR_DIGITAL, NO_ADC, NO_ADC, NOT_ON_PWM, NOT_ON_TIMER }, // TXD1
{ PIOA, PIO_PA12A_RXD1, ID_PIOA, PIO_PERIPH_A, PIO_DEFAULT, PIN_ATTR_DIGITAL, NO_ADC, NO_ADC, NOT_ON_PWM, NOT_ON_TIMER }, // RXD1
// 18/19 - USART0 (Serial1)
{ PIOA, PIO_PA11A_TXD0, ID_PIOA, PIO_PERIPH_A, PIO_DEFAULT, PIN_ATTR_DIGITAL, NO_ADC, NO_ADC, NOT_ON_PWM, NOT_ON_TIMER }, // TXD0
{ PIOA, PIO_PA10A_RXD0, ID_PIOA, PIO_PERIPH_A, PIO_DEFAULT, PIN_ATTR_DIGITAL, NO_ADC, NO_ADC, NOT_ON_PWM, NOT_ON_TIMER }, // RXD0
// 20/21 - TWI1
{ PIOB, PIO_PB12A_TWD1, ID_PIOB, PIO_PERIPH_A, PIO_DEFAULT, PIN_ATTR_DIGITAL, NO_ADC, NO_ADC, NOT_ON_PWM, NOT_ON_TIMER }, // TWD1 - SDA0
{ PIOB, PIO_PB13A_TWCK1, ID_PIOB, PIO_PERIPH_A, PIO_DEFAULT, PIN_ATTR_DIGITAL, NO_ADC, NO_ADC, NOT_ON_PWM, NOT_ON_TIMER }, // TWCK1 - SCL0
// 22
{ PIOB, PIO_PB26, ID_PIOB, PIO_OUTPUT_0, PIO_DEFAULT, PIN_ATTR_DIGITAL, NO_ADC, NO_ADC, NOT_ON_PWM, NOT_ON_TIMER }, // PIN 22
{ PIOA, PIO_PA14, ID_PIOA, PIO_OUTPUT_0, PIO_DEFAULT, PIN_ATTR_DIGITAL, NO_ADC, NO_ADC, NOT_ON_PWM, NOT_ON_TIMER }, // PIN 23
{ PIOA, PIO_PA15, ID_PIOA, PIO_OUTPUT_0, PIO_DEFAULT, PIN_ATTR_DIGITAL, NO_ADC, NO_ADC, NOT_ON_PWM, NOT_ON_TIMER }, // PIN 24
{ PIOD, PIO_PD0, ID_PIOD, PIO_OUTPUT_0, PIO_DEFAULT, PIN_ATTR_DIGITAL, NO_ADC, NO_ADC, NOT_ON_PWM, NOT_ON_TIMER }, // PIN 25
// 26
{ PIOD, PIO_PD1, ID_PIOD, PIO_OUTPUT_0, PIO_DEFAULT, PIN_ATTR_DIGITAL, NO_ADC, NO_ADC, NOT_ON_PWM, NOT_ON_TIMER }, // PIN 26
{ PIOD, PIO_PD2, ID_PIOD, PIO_OUTPUT_0, PIO_DEFAULT, PIN_ATTR_DIGITAL, NO_ADC, NO_ADC, NOT_ON_PWM, NOT_ON_TIMER }, // PIN 27
{ PIOD, PIO_PD3, ID_PIOD, PIO_OUTPUT_0, PIO_DEFAULT, PIN_ATTR_DIGITAL, NO_ADC, NO_ADC, NOT_ON_PWM, NOT_ON_TIMER }, // PIN 28
{ PIOD, PIO_PD6, ID_PIOD, PIO_OUTPUT_0, PIO_DEFAULT, PIN_ATTR_DIGITAL, NO_ADC, NO_ADC, NOT_ON_PWM, NOT_ON_TIMER }, // PIN 29
// 30
{ PIOD, PIO_PD9, ID_PIOD, PIO_OUTPUT_0, PIO_DEFAULT, PIN_ATTR_DIGITAL, NO_ADC, NO_ADC, NOT_ON_PWM, NOT_ON_TIMER }, // PIN 30
{ PIOA, PIO_PA7, ID_PIOA, PIO_OUTPUT_0, PIO_DEFAULT, PIN_ATTR_DIGITAL, NO_ADC, NO_ADC, NOT_ON_PWM, NOT_ON_TIMER }, // PIN 31
{ PIOD, PIO_PD10, ID_PIOD, PIO_OUTPUT_0, PIO_DEFAULT, PIN_ATTR_DIGITAL, NO_ADC, NO_ADC, NOT_ON_PWM, NOT_ON_TIMER }, // PIN 32
{ PIOC, PIO_PC1, ID_PIOC, PIO_OUTPUT_0, PIO_DEFAULT, PIN_ATTR_DIGITAL, NO_ADC, NO_ADC, NOT_ON_PWM, NOT_ON_TIMER }, // PIN 33
// 34
// start of custom pins
{ PIOA, PIO_PA29, ID_PIOA, PIO_OUTPUT_0, PIO_DEFAULT, PIN_ATTR_DIGITAL, NO_ADC, NO_ADC, NOT_ON_PWM, NOT_ON_TIMER }, // PIN 34 Y_STEP_PIN
{ PIOB, PIO_PB1, ID_PIOB, PIO_OUTPUT_0, PIO_DEFAULT, PIN_ATTR_DIGITAL, NO_ADC, NO_ADC, NOT_ON_PWM, NOT_ON_TIMER }, // PIN 35 Y_DIR_PIN
{ PIOB, PIO_PB0, ID_PIOB, PIO_OUTPUT_0, PIO_DEFAULT, PIN_ATTR_DIGITAL, NO_ADC, NO_ADC, NOT_ON_PWM, NOT_ON_TIMER }, // PIN 36 Y_ENABLE_PIN
{ PIOB, PIO_PB22, ID_PIOB, PIO_OUTPUT_0, PIO_DEFAULT, PIN_ATTR_DIGITAL, NO_ADC, NO_ADC, NOT_ON_PWM, NOT_ON_TIMER }, // PIN 37 E0_ENABLE_PIN
{ PIOB, PIO_PB11, ID_PIOB, PIO_OUTPUT_0, PIO_DEFAULT, PIN_ATTR_DIGITAL, NO_ADC, NO_ADC, NOT_ON_PWM, NOT_ON_TIMER }, // PIN 38 E0_MS1_PIN
{ PIOB, PIO_PB10, ID_PIOB, PIO_OUTPUT_0, PIO_DEFAULT, PIN_ATTR_DIGITAL, NO_ADC, NO_ADC, NOT_ON_PWM, NOT_ON_TIMER }, // PIN 39 E0_MS3_PIN
{ PIOA, PIO_PA5, ID_PIOA, PIO_OUTPUT_0, PIO_DEFAULT, PIN_ATTR_DIGITAL, NO_ADC, NO_ADC, NOT_ON_PWM, NOT_ON_TIMER }, // PIN 40 HEATER_0_PIN
{ PIOB, PIO_PB24, ID_PIOB, PIO_OUTPUT_0, PIO_DEFAULT, PIN_ATTR_DIGITAL, NO_ADC, NO_ADC, NOT_ON_PWM, NOT_ON_TIMER }, // PIN 41 HEATER_BED_PIN
// end of custom pins
// 42
{ PIOA, PIO_PA19, ID_PIOA, PIO_OUTPUT_0, PIO_DEFAULT, PIN_ATTR_DIGITAL, NO_ADC, NO_ADC, NOT_ON_PWM, NOT_ON_TIMER }, // PIN 42
{ PIOA, PIO_PA20, ID_PIOA, PIO_OUTPUT_0, PIO_DEFAULT, PIN_ATTR_DIGITAL, NO_ADC, NO_ADC, NOT_ON_PWM, NOT_ON_TIMER }, // PIN 43
{ PIOC, PIO_PC19, ID_PIOC, PIO_OUTPUT_0, PIO_DEFAULT, PIN_ATTR_DIGITAL, NO_ADC, NO_ADC, NOT_ON_PWM, NOT_ON_TIMER }, // PIN 44
{ PIOC, PIO_PC18, ID_PIOC, PIO_OUTPUT_0, PIO_DEFAULT, PIN_ATTR_DIGITAL, NO_ADC, NO_ADC, NOT_ON_PWM, NOT_ON_TIMER }, // PIN 45
// 46
{ PIOC, PIO_PC17, ID_PIOC, PIO_OUTPUT_0, PIO_DEFAULT, PIN_ATTR_DIGITAL, NO_ADC, NO_ADC, NOT_ON_PWM, NOT_ON_TIMER }, // PIN 46
{ PIOC, PIO_PC16, ID_PIOC, PIO_OUTPUT_0, PIO_DEFAULT, PIN_ATTR_DIGITAL, NO_ADC, NO_ADC, NOT_ON_PWM, NOT_ON_TIMER }, // PIN 47
{ PIOC, PIO_PC15, ID_PIOC, PIO_OUTPUT_0, PIO_DEFAULT, PIN_ATTR_DIGITAL, NO_ADC, NO_ADC, NOT_ON_PWM, NOT_ON_TIMER }, // PIN 48
{ PIOC, PIO_PC14, ID_PIOC, PIO_OUTPUT_0, PIO_DEFAULT, PIN_ATTR_DIGITAL, NO_ADC, NO_ADC, NOT_ON_PWM, NOT_ON_TIMER }, // PIN 49
// 50
{ PIOC, PIO_PC13, ID_PIOC, PIO_OUTPUT_0, PIO_DEFAULT, PIN_ATTR_DIGITAL, NO_ADC, NO_ADC, NOT_ON_PWM, NOT_ON_TIMER }, // PIN 50
{ PIOC, PIO_PC12, ID_PIOC, PIO_OUTPUT_0, PIO_DEFAULT, PIN_ATTR_DIGITAL, NO_ADC, NO_ADC, NOT_ON_PWM, NOT_ON_TIMER }, // PIN 51
{ PIOB, PIO_PB21, ID_PIOB, PIO_OUTPUT_0, PIO_DEFAULT, PIN_ATTR_DIGITAL, NO_ADC, NO_ADC, NOT_ON_PWM, NOT_ON_TIMER }, // PIN 52
{ PIOB, PIO_PB14, ID_PIOB, PIO_OUTPUT_0, PIO_DEFAULT, PIN_ATTR_DIGITAL, NO_ADC, NO_ADC, NOT_ON_PWM, NOT_ON_TIMER }, // PIN 53
// 54 .. 65 - Analog pins
// ----------------------
{ PIOA, PIO_PA16X1_AD7, ID_PIOA, PIO_INPUT, PIO_DEFAULT, PIN_ATTR_ANALOG, ADC0, ADC7, NOT_ON_PWM, NOT_ON_TIMER }, // AD0
{ PIOA, PIO_PA24X1_AD6, ID_PIOA, PIO_INPUT, PIO_DEFAULT, PIN_ATTR_ANALOG, ADC1, ADC6, NOT_ON_PWM, NOT_ON_TIMER }, // AD1
{ PIOA, PIO_PA23X1_AD5, ID_PIOA, PIO_INPUT, PIO_DEFAULT, PIN_ATTR_ANALOG, ADC2, ADC5, NOT_ON_PWM, NOT_ON_TIMER }, // AD2
{ PIOA, PIO_PA22X1_AD4, ID_PIOA, PIO_INPUT, PIO_DEFAULT, PIN_ATTR_ANALOG, ADC3, ADC4, NOT_ON_PWM, NOT_ON_TIMER }, // AD3
// 58
{ PIOA, PIO_PA6X1_AD3, ID_PIOA, PIO_INPUT, PIO_DEFAULT, PIN_ATTR_ANALOG, ADC4, ADC3, NOT_ON_PWM, TC0_CHB2 }, // AD4
{ PIOA, PIO_PA4X1_AD2, ID_PIOA, PIO_INPUT, PIO_DEFAULT, PIN_ATTR_ANALOG, ADC5, ADC2, NOT_ON_PWM, NOT_ON_TIMER }, // AD5
{ PIOA, PIO_PA3X1_AD1, ID_PIOA, PIO_INPUT, PIO_DEFAULT, PIN_ATTR_ANALOG, ADC6, ADC1, NOT_ON_PWM, TC0_CHB1 }, // AD6
{ PIOA, PIO_PA2X1_AD0, ID_PIOA, PIO_INPUT, PIO_DEFAULT, PIN_ATTR_ANALOG, ADC7, ADC0, NOT_ON_PWM, TC0_CHA1 }, // AD7
// 62
{ PIOB, PIO_PB17X1_AD10, ID_PIOB, PIO_INPUT, PIO_DEFAULT, PIN_ATTR_ANALOG, ADC8, ADC10, NOT_ON_PWM, NOT_ON_TIMER }, // AD8
{ PIOB, PIO_PB18X1_AD11, ID_PIOB, PIO_INPUT, PIO_DEFAULT, PIN_ATTR_ANALOG, ADC9, ADC11, NOT_ON_PWM, NOT_ON_TIMER }, // AD9
{ PIOB, PIO_PB19X1_AD12, ID_PIOB, PIO_INPUT, PIO_DEFAULT, PIN_ATTR_ANALOG, ADC10, ADC12, NOT_ON_PWM, NOT_ON_TIMER }, // AD10
{ PIOB, PIO_PB20X1_AD13, ID_PIOB, PIO_INPUT, PIO_DEFAULT, PIN_ATTR_ANALOG, ADC11, ADC13, NOT_ON_PWM, NOT_ON_TIMER }, // AD11
// 66/67 - DAC0/DAC1
{ PIOB, PIO_PB15X1_DAC0, ID_PIOB, PIO_INPUT, PIO_DEFAULT, PIN_ATTR_ANALOG, ADC12, DA0, NOT_ON_PWM, NOT_ON_TIMER }, // DAC0
{ PIOB, PIO_PB16X1_DAC1, ID_PIOB, PIO_INPUT, PIO_DEFAULT, PIN_ATTR_ANALOG, ADC13, DA1, NOT_ON_PWM, NOT_ON_TIMER }, // DAC1
// 68/69 - CANRX0/CANTX0
{ PIOA, PIO_PA1A_CANRX0, ID_PIOA, PIO_PERIPH_A, PIO_DEFAULT, PIN_ATTR_DIGITAL, ADC14, NO_ADC, NOT_ON_PWM, NOT_ON_TIMER }, // CANRX
{ PIOA, PIO_PA0A_CANTX0, ID_PIOA, PIO_PERIPH_A, PIO_DEFAULT, PIN_ATTR_DIGITAL, ADC15, NO_ADC, NOT_ON_PWM, NOT_ON_TIMER }, // CANTX
// 70/71 - TWI0
{ PIOA, PIO_PA17A_TWD0, ID_PIOA, PIO_PERIPH_A, PIO_DEFAULT, PIN_ATTR_DIGITAL, NO_ADC, NO_ADC, NOT_ON_PWM, NOT_ON_TIMER }, // TWD0 - SDA1
{ PIOA, PIO_PA18A_TWCK0, ID_PIOA, PIO_PERIPH_A, PIO_DEFAULT, PIN_ATTR_DIGITAL, NO_ADC, NO_ADC, NOT_ON_PWM, NOT_ON_TIMER }, // TWCK0 - SCL1
// 72/73 - LEDs
{ PIOC, PIO_PC30, ID_PIOC, PIO_OUTPUT_0, PIO_DEFAULT, PIN_ATTR_DIGITAL, NO_ADC, NO_ADC, NOT_ON_PWM, NOT_ON_TIMER }, // LED AMBER RXL
{ PIOA, PIO_PA21, ID_PIOA, PIO_OUTPUT_0, PIO_DEFAULT, PIN_ATTR_DIGITAL, NO_ADC, NO_ADC, NOT_ON_PWM, NOT_ON_TIMER }, // LED AMBER TXL
// 74/75/76 - SPI
{ PIOA, PIO_PA25A_SPI0_MISO,ID_PIOA,PIO_PERIPH_A, PIO_DEFAULT, PIN_ATTR_DIGITAL, NO_ADC, NO_ADC, NOT_ON_PWM, NOT_ON_TIMER }, // MISO
{ PIOA, PIO_PA26A_SPI0_MOSI,ID_PIOA,PIO_PERIPH_A, PIO_DEFAULT, PIN_ATTR_DIGITAL, NO_ADC, NO_ADC, NOT_ON_PWM, NOT_ON_TIMER }, // MOSI
{ PIOA, PIO_PA27A_SPI0_SPCK,ID_PIOA,PIO_PERIPH_A, PIO_DEFAULT, PIN_ATTR_DIGITAL, NO_ADC, NO_ADC, NOT_ON_PWM, NOT_ON_TIMER }, // SPCK
// 77 - SPI CS0
{ PIOA, PIO_PA28A_SPI0_NPCS0,ID_PIOA,PIO_PERIPH_A,PIO_DEFAULT, PIN_ATTR_DIGITAL, NO_ADC, NO_ADC, NOT_ON_PWM, NOT_ON_TIMER }, // NPCS0
// 78 - SPI CS3 (unconnected)
{ PIOB, PIO_PB23B_SPI0_NPCS3,ID_PIOB,PIO_PERIPH_B,PIO_DEFAULT, PIN_ATTR_DIGITAL, NO_ADC, NO_ADC, NOT_ON_PWM, NOT_ON_TIMER }, // NPCS3
// 79 .. 84 - "All pins" masks
// 79 - TWI0 all pins
{ PIOA, PIO_PA17A_TWD0|PIO_PA18A_TWCK0, ID_PIOA, PIO_PERIPH_A, PIO_DEFAULT, (PIN_ATTR_DIGITAL|PIN_ATTR_COMBO), NO_ADC, NO_ADC, NOT_ON_PWM, NOT_ON_TIMER },
// 80 - TWI1 all pins
{ PIOB, PIO_PB12A_TWD1|PIO_PB13A_TWCK1, ID_PIOB, PIO_PERIPH_A, PIO_DEFAULT, (PIN_ATTR_DIGITAL|PIN_ATTR_COMBO), NO_ADC, NO_ADC, NOT_ON_PWM, NOT_ON_TIMER },
// 81 - UART (Serial) all pins
{ PIOA, PIO_PA8A_URXD|PIO_PA9A_UTXD, ID_PIOA, PIO_PERIPH_A, PIO_DEFAULT, (PIN_ATTR_DIGITAL|PIN_ATTR_COMBO), NO_ADC, NO_ADC, NOT_ON_PWM, NOT_ON_TIMER },
// 82 - USART0 (Serial1) all pins
{ PIOA, PIO_PA11A_TXD0|PIO_PA10A_RXD0, ID_PIOA, PIO_PERIPH_A, PIO_DEFAULT, (PIN_ATTR_DIGITAL|PIN_ATTR_COMBO), NO_ADC, NO_ADC, NOT_ON_PWM, NOT_ON_TIMER },
// 83 - USART1 (Serial2) all pins
{ PIOA, PIO_PA13A_TXD1|PIO_PA12A_RXD1, ID_PIOA, PIO_PERIPH_A, PIO_DEFAULT, (PIN_ATTR_DIGITAL|PIN_ATTR_COMBO), NO_ADC, NO_ADC, NOT_ON_PWM, NOT_ON_TIMER },
// 84 - USART3 (Serial3) all pins
{ PIOD, PIO_PD4B_TXD3|PIO_PD5B_RXD3, ID_PIOD, PIO_PERIPH_B, PIO_DEFAULT, (PIN_ATTR_DIGITAL|PIN_ATTR_COMBO), NO_ADC, NO_ADC, NOT_ON_PWM, NOT_ON_TIMER },
// 85 - USB
{ PIOB, PIO_PB11A_UOTGID|PIO_PB10A_UOTGVBOF, ID_PIOB, PIO_PERIPH_A, PIO_DEFAULT, PIN_ATTR_DIGITAL,NO_ADC, NO_ADC, NOT_ON_PWM, NOT_ON_TIMER }, // ID - VBOF
// 86 - SPI CS2
{ PIOB, PIO_PB21B_SPI0_NPCS2, ID_PIOB, PIO_PERIPH_B, PIO_DEFAULT, PIN_ATTR_DIGITAL, NO_ADC, NO_ADC, NOT_ON_PWM, NOT_ON_TIMER }, // NPCS2
// 87 - SPI CS1
{ PIOA, PIO_PA29A_SPI0_NPCS1, ID_PIOA, PIO_PERIPH_A, PIO_DEFAULT, PIN_ATTR_DIGITAL, NO_ADC, NO_ADC, NOT_ON_PWM, NOT_ON_TIMER }, // NPCS1
// 88/89 - CANRX1/CANTX1 (same physical pin for 66/53)
{ PIOB, PIO_PB15A_CANRX1, ID_PIOB, PIO_PERIPH_A, PIO_DEFAULT, PIN_ATTR_DIGITAL, NO_ADC, NO_ADC, NOT_ON_PWM, NOT_ON_TIMER }, // CANRX1
{ PIOB, PIO_PB14A_CANTX1, ID_PIOB, PIO_PERIPH_A, PIO_DEFAULT, PIN_ATTR_DIGITAL, NO_ADC, NO_ADC, NOT_ON_PWM, NOT_ON_TIMER }, // CANTX1
// 90 .. 91 - "All CAN pins" masks
// 90 - CAN0 all pins
{ PIOA, PIO_PA1A_CANRX0|PIO_PA0A_CANTX0, ID_PIOA, PIO_PERIPH_A, PIO_DEFAULT, (PIN_ATTR_DIGITAL|PIN_ATTR_COMBO), NO_ADC, NO_ADC, NOT_ON_PWM, NOT_ON_TIMER },
// 91 - CAN1 all pins
{ PIOB, PIO_PB15A_CANRX1|PIO_PB14A_CANTX1, ID_PIOB, PIO_PERIPH_A, PIO_DEFAULT, (PIN_ATTR_DIGITAL|PIN_ATTR_COMBO), NO_ADC, NO_ADC, NOT_ON_PWM, NOT_ON_TIMER },
// END
{ nullptr, 0, 0, PIO_NOT_A_PIN, PIO_DEFAULT, 0, NO_ADC, NO_ADC, NOT_ON_PWM, NOT_ON_TIMER }
};
// This section replaces the FASTIO definitions of pins 34-41
#define DIO34_PIN 29
#define DIO34_WPORT PIOA // only available via FASTIO // 34 PA29 - Y_STEP_PIN
#define DIO35_PIN 1
#define DIO35_WPORT PIOB // only available via FASTIO // 35 PAB1 - Y_DIR_PIN
#define DIO36_PIN 0
#define DIO36_WPORT PIOB // only available via FASTIO // 36 PB0 - Y_ENABLE_PIN
#define DIO37_PIN 22
#define DIO37_WPORT PIOB // only available via FASTIO // 37 PB22 - E0_ENABLE_PIN
#define DIO38_PIN 11
#define DIO38_WPORT PIOB // only available via FASTIO // 38 PB11 - E0_MS1_PIN
#define DIO39_PIN 10
#define DIO39_WPORT PIOB // only available via FASTIO // 39 PB10 - E0_MS3_PIN
#define DIO40_PIN 5
#define DIO40_WPORT PIOA // only available via FASTIO // 40 PA5 - HEATER_0_PIN
#define DIO41_PIN 24
#define DIO41_WPORT PIOB // only available via FASTIO // 41 PB24 - HEATER_BED_PIN

@ -0,0 +1,22 @@
/**
* 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/>.
*
*/
#pragma once

@ -0,0 +1,22 @@
/**
* 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/>.
*
*/
#pragma once

@ -0,0 +1,28 @@
/**
* 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/>.
*
*/
#pragma once
#if USE_FALLBACK_EEPROM
#define FLASH_EEPROM_EMULATION
#elif ANY(I2C_EEPROM, SPI_EEPROM)
#define USE_SHARED_EEPROM 1
#endif

@ -0,0 +1,93 @@
/**
* 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/>.
*
*/
#pragma once
/**
* Test Arduino Due specific configuration values for errors at compile-time.
*/
#if HAS_SPI_TFT || HAS_FSMC_TFT
#error "Sorry! TFT displays are not available for HAL/DUE."
#endif
/**
* Check for common serial pin conflicts
*/
#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
*
* DUE selects hardware vs. software SPI depending on whether one of the hardware-controllable SDSS pins is in use.
*
* The hardware SPI controller doesn't allow software SPIs to control any shared pins.
*
* When DUE software SPI is used then Trinamic drivers must use the TMC softSPI.
*
* When DUE hardware SPI is used then a Trinamic driver can use either its hardware SPI or, if there are no shared
* pins, its software SPI.
*
* Usually the hardware SPI pins are only available to the LCD. This makes the DUE hard SPI used at the same time
* as the TMC2130 soft SPI the most common setup.
*/
#define _IS_HW_SPI(P) (defined(TMC_SPI_##P) && (TMC_SPI_##P == SD_MOSI_PIN || TMC_SPI_##P == SD_MISO_PIN || TMC_SPI_##P == SD_SCK_PIN))
#if HAS_MEDIA && HAS_DRIVER(TMC2130)
#if ENABLED(TMC_USE_SW_SPI)
#if DISABLED(DUE_SOFTWARE_SPI) && (_IS_HW_SPI(MOSI) || _IS_HW_SPI(MISO) || _IS_HW_SPI(SCK))
#error "DUE hardware SPI is required but is incompatible with TMC2130 software SPI. Either disable TMC_USE_SW_SPI or use separate pins for the two SPIs."
#endif
#elif ENABLED(DUE_SOFTWARE_SPI)
#error "DUE software SPI is required but is incompatible with TMC2130 hardware SPI. Enable TMC_USE_SW_SPI to fix."
#endif
#endif
#if ENABLED(FAST_PWM_FAN) || SPINDLE_LASER_FREQUENCY
#error "Features requiring Hardware PWM (FAST_PWM_FAN, SPINDLE_LASER_FREQUENCY) are not yet supported for HAL/DUE."
#endif
#if HAS_TMC_SW_SERIAL
#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

@ -0,0 +1,186 @@
/**
* 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/>.
*
*/
/**
* Support routines for Due
*/
/**
* Translation of routines & variables used by pinsDebug.h
*/
#include "../shared/Marduino.h"
/**
* Due/Marlin quirks
*
* a) determining the state of a pin
* The Due/Arduino status definitions for the g_pinStatus[pin] array are:
* #define PIN_STATUS_DIGITAL_INPUT_PULLUP (0x01)
* #define PIN_STATUS_DIGITAL_INPUT (0x02)
* #define PIN_STATUS_DIGITAL_OUTPUT (0x03)
* #define PIN_STATUS_ANALOG (0x04)
* #define PIN_STATUS_PWM (0x05)
* #define PIN_STATUS_TIMER (0x06)
*
* These are only valid if the following Due/Arduino provided functions are used:
* analogRead
* analogWrite
* digitalWrite
* pinMode
*
* The FASTIO routines do not touch the g_pinStatus[pin] array.
*
* 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.
*
* 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
*
* d) Pins 0-78 are defined for Due but 78 has a comment of "unconnected!". 78 is
* included just in case.
*/
#define NUMBER_PINS_TOTAL PINS_COUNT
#define digitalRead_mod(p) extDigitalRead(p) // AVR digitalRead disabled PWM before it read the pin
#define PRINT_ARRAY_NAME(x) do{ sprintf_P(buffer, PSTR("%-" STRINGIFY(MAX_NAME_LENGTH) "s"), pin_array[x].name); SERIAL_ECHO(buffer); }while(0)
#define PRINT_PIN(p) do{ sprintf_P(buffer, PSTR("%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_IS_DIGITAL(p) pin_array[p].is_digital
#define VALID_PIN(pin) (pin >= 0 && pin < int8_t(NUMBER_PINS_TOTAL))
#define DIGITAL_PIN_TO_ANALOG_PIN(p) int(p - analogInputToDigitalPin(0))
#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) && \
((g_APinDescription[pin].ulPinAttribute & PIN_ATTR_PWM) == PIN_ATTR_PWM))
#define MULTI_NAME_PAD 14 // space needed to be pretty if not first name assigned to a pin
bool GET_PINMODE(int8_t pin) { // 1: output, 0: input
volatile Pio* port = g_APinDescription[pin].pPort;
uint32_t mask = g_APinDescription[pin].ulPin;
uint8_t pin_status = g_pinStatus[pin] & 0xF;
return ( (pin_status == 0 && (port->PIO_OSR & mask))
|| pin_status == PIN_STATUS_DIGITAL_OUTPUT
|| pwm_status(pin));
}
void pwm_details(int32_t pin) {
if (pwm_status(pin)) {
uint32_t chan = g_APinDescription[pin].ulPWMChannel;
SERIAL_ECHOPGM("PWM = ", PWM_INTERFACE->PWM_CH_NUM[chan].PWM_CDTY);
}
}
void print_port(const pin_t) {}
/**
* DUE Board pin | PORT | Label
* ----------------+--------+-------
* 0 | PA8 | "RX0"
* 1 | PA9 | "TX0"
* 2 TIOA0 | PB25 |
* 3 TIOA7 | PC28 |
* 4 NPCS1 | PA29 |
* TIOB6 | PC26 |
* 5 TIOA6 | PC25 |
* 6 PWML7 | PC24 |
* 7 PWML6 | PC23 |
* 8 PWML5 | PC22 |
* 9 PWML4 | PC21 |
* 10 NPCS0 | PA28 |
* TIOB7 | PC29 |
* 11 TIOA8 | PD7 |
* 12 TIOB8 | PD8 |
* 13 TIOB0 | PB27 | LED AMBER "L"
* 14 TXD3 | PD4 | "TX3"
* 15 RXD3 | PD5 | "RX3"
* 16 TXD1 | PA13 | "TX2"
* 17 RXD1 | PA12 | "RX2"
* 18 TXD0 | PA11 | "TX1"
* 19 RXD0 | PA10 | "RX1"
* 20 | PB12 | "SDA"
* 21 | PB13 | "SCL"
* 22 | PB26 |
* 23 | PA14 |
* 24 | PA15 |
* 25 | PD0 |
* 26 | PD1 |
* 27 | PD2 |
* 28 | PD3 |
* 29 | PD6 |
* 30 | PD9 |
* 31 | PA7 |
* 32 | PD10 |
* 33 | PC1 |
* 34 | PC2 |
* 35 | PC3 |
* 36 | PC4 |
* 37 | PC5 |
* 38 | PC6 |
* 39 | PC7 |
* 40 | PC8 |
* 41 | PC9 |
* 42 | PA19 |
* 43 | PA20 |
* 44 | PC19 |
* 45 | PC18 |
* 46 | PC17 |
* 47 | PC16 |
* 48 | PC15 |
* 49 | PC14 |
* 50 | PC13 |
* 51 | PC12 |
* 52 NPCS2 | PB21 |
* 53 | PB14 |
* 54 | PA16 | "A0"
* 55 | PA24 | "A1"
* 56 | PA23 | "A2"
* 57 | PA22 | "A3"
* 58 TIOB2 | PA6 | "A4"
* 69 | PA4 | "A5"
* 60 TIOB1 | PA3 | "A6"
* 61 TIOA1 | PA2 | "A7"
* 62 | PB17 | "A8"
* 63 | PB18 | "A9"
* 64 | PB19 | "A10"
* 65 | PB20 | "A11"
* 66 | PB15 | "DAC0"
* 67 | PB16 | "DAC1"
* 68 | PA1 | "CANRX"
* 69 | PA0 | "CANTX"
* 70 | PA17 | "SDA1"
* 71 | PA18 | "SCL1"
* 72 | PC30 | LED AMBER "RX"
* 73 | PA21 | LED AMBER "TX"
* 74 MISO | PA25 |
* 75 MOSI | PA26 |
* 76 SCLK | PA27 |
* 77 NPCS0 | PA28 |
* 78 NPCS3 | PB23 | unconnected!
*
* USB pin | PORT
* ----------------+--------
* ID | PB11
* VBOF | PB10
*/

@ -0,0 +1,64 @@
/**
* 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/>.
*
*/
#pragma once
/**
* Define SPI Pins: SCK, MISO, MOSI, SS
*
* Available chip select pins for HW SPI are 4 10 52 77
*/
#if SDSS == 4 || SDSS == 10 || SDSS == 52 || SDSS == 77 || SDSS == 87
#if SDSS == 4
#define SPI_PIN 87
#define SPI_CHAN 1
#elif SDSS == 10
#define SPI_PIN 77
#define SPI_CHAN 0
#elif SDSS == 52
#define SPI_PIN 86
#define SPI_CHAN 2
#elif SDSS == 77
#define SPI_PIN 77
#define SPI_CHAN 0
#else
#define SPI_PIN 87
#define SPI_CHAN 1
#endif
#define SD_SCK_PIN 76
#define SD_MISO_PIN 74
#define SD_MOSI_PIN 75
#else
// defaults
#define DUE_SOFTWARE_SPI
#ifndef SD_SCK_PIN
#define SD_SCK_PIN 52
#endif
#ifndef SD_MISO_PIN
#define SD_MISO_PIN 50
#endif
#ifndef SD_MOSI_PIN
#define SD_MOSI_PIN 51
#endif
#endif
/* A.28, A.29, B.21, C.26, C.29 */
#define SD_SS_PIN SDSS

@ -0,0 +1,139 @@
/**
* 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/>.
*
*/
/**
* HAL Timers for Arduino Due and compatible (SAM3X8E)
*/
#ifdef ARDUINO_ARCH_SAM
// ------------------------
// Includes
// ------------------------
#include "../../inc/MarlinConfig.h"
#include "HAL.h"
// ------------------------
// Local defines
// ------------------------
#define NUM_HARDWARE_TIMERS 9
// ------------------------
// Private Variables
// ------------------------
const tTimerConfig timer_config[NUM_HARDWARE_TIMERS] = {
{ TC0, 0, TC0_IRQn, 3}, // 0 - [servo timer5]
{ TC0, 1, TC1_IRQn, 0}, // 1
{ TC0, 2, TC2_IRQn, 2}, // 2 - stepper
{ TC1, 0, TC3_IRQn, 0}, // 3 - stepper for BOARD_ARCHIM1
{ TC1, 1, TC4_IRQn, 15}, // 4 - temperature
{ TC1, 2, TC5_IRQn, 3}, // 5 - [servo timer3]
{ TC2, 0, TC6_IRQn, 14}, // 6 - tone
{ TC2, 1, TC7_IRQn, 0}, // 7
{ TC2, 2, TC8_IRQn, 0}, // 8
};
// ------------------------
// Public functions
// ------------------------
/*
Timer_clock1: Prescaler 2 -> 42MHz
Timer_clock2: Prescaler 8 -> 10.5MHz
Timer_clock3: Prescaler 32 -> 2.625MHz
Timer_clock4: Prescaler 128 -> 656.25kHz
*/
void HAL_timer_start(const uint8_t timer_num, const uint32_t frequency) {
Tc *tc = timer_config[timer_num].pTimerRegs;
IRQn_Type irq = timer_config[timer_num].IRQ_Id;
uint32_t channel = timer_config[timer_num].channel;
// Disable interrupt, just in case it was already enabled
NVIC_DisableIRQ(irq);
// We NEED memory barriers to ensure Interrupts are actually disabled!
// ( https://dzone.com/articles/nvic-disabling-interrupts-on-arm-cortex-m-and-the )
__DSB();
__ISB();
// Disable timer interrupt
tc->TC_CHANNEL[channel].TC_IDR = TC_IDR_CPCS;
// Stop timer, just in case, to be able to reconfigure it
TC_Stop(tc, channel);
pmc_set_writeprotect(false);
pmc_enable_periph_clk((uint32_t)irq);
NVIC_SetPriority(irq, timer_config[timer_num].priority);
// wave mode, reset counter on match with RC,
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
TC_SetRC(tc, channel, VARIANT_MCK / (HAL_TIMER_PRESCALER) / frequency);
// And start timer
TC_Start(tc, channel);
// enable interrupt on RC compare
tc->TC_CHANNEL[channel].TC_IER = TC_IER_CPCS;
// Finally, enable IRQ
NVIC_EnableIRQ(irq);
}
void HAL_timer_enable_interrupt(const uint8_t timer_num) {
IRQn_Type irq = timer_config[timer_num].IRQ_Id;
NVIC_EnableIRQ(irq);
}
void HAL_timer_disable_interrupt(const uint8_t timer_num) {
IRQn_Type irq = timer_config[timer_num].IRQ_Id;
NVIC_DisableIRQ(irq);
// We NEED memory barriers to ensure Interrupts are actually disabled!
// ( https://dzone.com/articles/nvic-disabling-interrupts-on-arm-cortex-m-and-the )
__DSB();
__ISB();
}
// missing from CMSIS: Check if interrupt is enabled or not
static bool NVIC_GetEnabledIRQ(IRQn_Type IRQn) {
return TEST(NVIC->ISER[uint32_t(IRQn) >> 5], uint32_t(IRQn) & 0x1F);
}
bool HAL_timer_interrupt_enabled(const uint8_t timer_num) {
IRQn_Type irq = timer_config[timer_num].IRQ_Id;
return NVIC_GetEnabledIRQ(irq);
}
#endif // ARDUINO_ARCH_SAM

@ -0,0 +1,130 @@
/**
* 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/>.
*
*/
#pragma once
/**
* HAL Timers for Arduino Due and compatible (SAM3X8E)
*/
#include <stdint.h>
// ------------------------
// Defines
// ------------------------
#define FORCE_INLINE __attribute__((always_inline)) inline
typedef uint32_t hal_timer_t;
#define HAL_TIMER_TYPE_MAX 0xFFFFFFFF
#define HAL_TIMER_PRESCALER 2
#define HAL_TIMER_RATE ((F_CPU) / (HAL_TIMER_PRESCALER)) // frequency of timers peripherals
#ifndef MF_TIMER_STEP
#define MF_TIMER_STEP 2 // Timer Index for Stepper
#endif
#ifndef MF_TIMER_PULSE
#define MF_TIMER_PULSE MF_TIMER_STEP
#endif
#ifndef MF_TIMER_TEMP
#define MF_TIMER_TEMP 4 // Timer Index for Temperature
#endif
#ifndef MF_TIMER_TONE
#define MF_TIMER_TONE 6 // index of timer to use for beeper tones
#endif
#define TEMP_TIMER_FREQUENCY 1000 // temperature interrupt frequency
#define STEPPER_TIMER_RATE HAL_TIMER_RATE // frequency of stepper timer (HAL_TIMER_RATE / STEPPER_TIMER_PRESCALE)
#define STEPPER_TIMER_TICKS_PER_US ((STEPPER_TIMER_RATE) / 1000000) // stepper timer ticks per µs
#define STEPPER_TIMER_PRESCALE (CYCLES_PER_MICROSECOND / STEPPER_TIMER_TICKS_PER_US)
#define PULSE_TIMER_RATE STEPPER_TIMER_RATE // frequency of pulse timer
#define PULSE_TIMER_PRESCALE STEPPER_TIMER_PRESCALE
#define PULSE_TIMER_TICKS_PER_US STEPPER_TIMER_TICKS_PER_US
#define ENABLE_STEPPER_DRIVER_INTERRUPT() HAL_timer_enable_interrupt(MF_TIMER_STEP)
#define DISABLE_STEPPER_DRIVER_INTERRUPT() HAL_timer_disable_interrupt(MF_TIMER_STEP)
#define STEPPER_ISR_ENABLED() HAL_timer_interrupt_enabled(MF_TIMER_STEP)
#define ENABLE_TEMPERATURE_INTERRUPT() HAL_timer_enable_interrupt(MF_TIMER_TEMP)
#define DISABLE_TEMPERATURE_INTERRUPT() HAL_timer_disable_interrupt(MF_TIMER_TEMP)
#ifndef HAL_STEP_TIMER_ISR
#define HAL_STEP_TIMER_ISR() void TC2_Handler()
#endif
#ifndef HAL_TEMP_TIMER_ISR
#define HAL_TEMP_TIMER_ISR() void TC4_Handler()
#endif
#ifndef HAL_TONE_TIMER_ISR
#define HAL_TONE_TIMER_ISR() void TC6_Handler()
#endif
// ------------------------
// Types
// ------------------------
typedef struct {
Tc *pTimerRegs;
uint16_t channel;
IRQn_Type IRQ_Id;
uint8_t priority;
} tTimerConfig;
// ------------------------
// Public Variables
// ------------------------
extern const tTimerConfig timer_config[];
// ------------------------
// Public functions
// ------------------------
void HAL_timer_start(const uint8_t timer_num, const uint32_t frequency);
FORCE_INLINE static void HAL_timer_set_compare(const uint8_t timer_num, const hal_timer_t compare) {
const tTimerConfig * const pConfig = &timer_config[timer_num];
pConfig->pTimerRegs->TC_CHANNEL[pConfig->channel].TC_RC = compare;
}
FORCE_INLINE static hal_timer_t HAL_timer_get_compare(const uint8_t timer_num) {
const tTimerConfig * const pConfig = &timer_config[timer_num];
return pConfig->pTimerRegs->TC_CHANNEL[pConfig->channel].TC_RC;
}
FORCE_INLINE static hal_timer_t HAL_timer_get_count(const uint8_t timer_num) {
const tTimerConfig * const pConfig = &timer_config[timer_num];
return pConfig->pTimerRegs->TC_CHANNEL[pConfig->channel].TC_CV;
}
void HAL_timer_enable_interrupt(const uint8_t timer_num);
void HAL_timer_disable_interrupt(const uint8_t timer_num);
bool HAL_timer_interrupt_enabled(const uint8_t timer_num);
FORCE_INLINE static void HAL_timer_isr_prologue(const uint8_t timer_num) {
const tTimerConfig * const pConfig = &timer_config[timer_num];
// Reading the status register clears the interrupt flag
pConfig->pTimerRegs->TC_CHANNEL[pConfig->channel].TC_SR;
}
#define HAL_timer_isr_epilogue(T) NOOP

@ -0,0 +1,34 @@
/**
* Marlin 3D Printer Firmware
* Copyright (c) 2023 MarlinFirmware [https://github.com/MarlinFirmware/Marlin]
*
* Based on Sprinter and grbl.
* Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
#pragma once
/**
* DUE (SAM3X8E) LCD-specific defines
*/
uint8_t u8g_com_HAL_DUE_sw_spi_fn(u8g_t *u8g, uint8_t msg, uint8_t arg_val, void *arg_ptr);
uint8_t u8g_com_HAL_DUE_shared_hw_spi_fn(u8g_t *u8g, uint8_t msg, uint8_t arg_val, void *arg_ptr);
uint8_t u8g_com_HAL_DUE_ST7920_sw_spi_fn(u8g_t *u8g, uint8_t msg, uint8_t arg_val, void *arg_ptr);
#define U8G_COM_HAL_SW_SPI_FN u8g_com_HAL_DUE_sw_spi_fn
#define U8G_COM_HAL_HW_SPI_FN u8g_com_HAL_DUE_shared_hw_spi_fn
#define U8G_COM_ST7920_HAL_SW_SPI u8g_com_HAL_DUE_ST7920_sw_spi_fn

@ -0,0 +1,143 @@
/**
* 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/>.
*
*/
/**
* Based on u8g_com_msp430_hw_spi.c
*
* Universal 8bit Graphics Library
*
* Copyright (c) 2012, olikraus@gmail.com
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice, this list
* of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright notice, this
* list of conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifdef __SAM3X8E__
#include "../../../inc/MarlinConfigPre.h"
#if HAS_MARLINUI_U8GLIB
#include <U8glib-HAL.h>
#include "../../../MarlinCore.h"
#ifndef LCD_SPI_SPEED
#define LCD_SPI_SPEED SPI_QUARTER_SPEED
#endif
#include "../../shared/HAL_SPI.h"
#include "../fastio.h"
void u8g_SetPIOutput_DUE_hw_spi(u8g_t *u8g, uint8_t pin_index) {
PIO_Configure(g_APinDescription[u8g->pin_list[pin_index]].pPort, PIO_OUTPUT_1,
g_APinDescription[u8g->pin_list[pin_index]].ulPin, g_APinDescription[u8g->pin_list[pin_index]].ulPinConfiguration); // OUTPUT
}
void u8g_SetPILevel_DUE_hw_spi(u8g_t *u8g, uint8_t pin_index, uint8_t level) {
volatile Pio* port = g_APinDescription[u8g->pin_list[pin_index]].pPort;
uint32_t mask = g_APinDescription[u8g->pin_list[pin_index]].ulPin;
if (level) port->PIO_SODR = mask;
else port->PIO_CODR = mask;
}
uint8_t u8g_com_HAL_DUE_shared_hw_spi_fn(u8g_t *u8g, uint8_t msg, uint8_t arg_val, void *arg_ptr) {
switch (msg) {
case U8G_COM_MSG_STOP:
break;
case U8G_COM_MSG_INIT:
u8g_SetPILevel_DUE_hw_spi(u8g, U8G_PI_CS, 1);
u8g_SetPILevel_DUE_hw_spi(u8g, U8G_PI_A0, 1);
u8g_SetPIOutput_DUE_hw_spi(u8g, U8G_PI_CS);
u8g_SetPIOutput_DUE_hw_spi(u8g, U8G_PI_A0);
u8g_Delay(5);
spiBegin();
spiInit(LCD_SPI_SPEED);
break;
case U8G_COM_MSG_ADDRESS: /* define cmd (arg_val = 0) or data mode (arg_val = 1) */
u8g_SetPILevel_DUE_hw_spi(u8g, U8G_PI_A0, arg_val);
break;
case U8G_COM_MSG_CHIP_SELECT:
u8g_SetPILevel_DUE_hw_spi(u8g, U8G_PI_CS, (arg_val ? 0 : 1));
break;
case U8G_COM_MSG_RESET:
break;
case U8G_COM_MSG_WRITE_BYTE:
spiSend((uint8_t)arg_val);
break;
case U8G_COM_MSG_WRITE_SEQ: {
uint8_t *ptr = (uint8_t*) arg_ptr;
while (arg_val > 0) {
spiSend(*ptr++);
arg_val--;
}
}
break;
case U8G_COM_MSG_WRITE_SEQ_P: {
uint8_t *ptr = (uint8_t*) arg_ptr;
while (arg_val > 0) {
spiSend(*ptr++);
arg_val--;
}
}
break;
}
return 1;
}
#endif // HAS_MARLINUI_U8GLIB
#endif // __SAM3X8E__

@ -0,0 +1,186 @@
/**
* 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/>.
*
*/
/**
* Based on u8g_com_st7920_hw_spi.c
*
* Universal 8bit Graphics Library
*
* Copyright (c) 2011, olikraus@gmail.com
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice, this list
* of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright notice, this
* list of conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifdef ARDUINO_ARCH_SAM
#include "../../../inc/MarlinConfigPre.h"
#if IS_U8GLIB_ST7920
#include "../../../inc/MarlinConfig.h"
#include "../../shared/Delay.h"
#include <U8glib-HAL.h>
#include "u8g_com_HAL_DUE_sw_spi_shared.h"
#define SPISEND_SW_DUE u8g_spiSend_sw_DUE_mode_0
static uint8_t rs_last_state = 255;
static void u8g_com_DUE_st7920_write_byte_sw_spi(uint8_t rs, uint8_t val) {
if (rs != rs_last_state) { // time to send a command/data byte
rs_last_state = rs;
SPISEND_SW_DUE(rs ? 0x0FA : 0x0F8); // Command or Data
DELAY_US(40); // give the controller some time to process the data: 20 is bad, 30 is OK, 40 is safe
}
SPISEND_SW_DUE(val & 0xF0);
SPISEND_SW_DUE(val << 4);
}
uint8_t u8g_com_HAL_DUE_ST7920_sw_spi_fn(u8g_t *u8g, uint8_t msg, uint8_t arg_val, void *arg_ptr) {
switch (msg) {
case U8G_COM_MSG_INIT:
SCK_pPio = g_APinDescription[u8g->pin_list[U8G_PI_SCK]].pPort;
SCK_dwMask = g_APinDescription[u8g->pin_list[U8G_PI_SCK]].ulPin;
MOSI_pPio = g_APinDescription[u8g->pin_list[U8G_PI_MOSI]].pPort;
MOSI_dwMask = g_APinDescription[u8g->pin_list[U8G_PI_MOSI]].ulPin;
u8g_SetPILevel_DUE(u8g, U8G_PI_CS, 0);
u8g_SetPIOutput_DUE(u8g, U8G_PI_CS);
u8g_SetPILevel_DUE(u8g, U8G_PI_SCK, 0);
u8g_SetPIOutput_DUE(u8g, U8G_PI_SCK);
u8g_SetPILevel_DUE(u8g, U8G_PI_MOSI, 0);
u8g_SetPIOutput_DUE(u8g, U8G_PI_MOSI);
SCK_pPio->PIO_CODR = SCK_dwMask; //SCK low - needed at power up but not after reset
MOSI_pPio->PIO_CODR = MOSI_dwMask; //MOSI low - needed at power up but not after reset
u8g_Delay(5);
u8g->pin_list[U8G_PI_A0_STATE] = 0; /* initial RS state: command mode */
break;
case U8G_COM_MSG_STOP:
break;
case U8G_COM_MSG_RESET:
if (U8G_PIN_NONE != u8g->pin_list[U8G_PI_RESET]) u8g_SetPILevel_DUE(u8g, U8G_PI_RESET, arg_val);
break;
case U8G_COM_MSG_ADDRESS: /* define cmd (arg_val = 0) or data mode (arg_val = 1) */
u8g->pin_list[U8G_PI_A0_STATE] = arg_val;
break;
case U8G_COM_MSG_CHIP_SELECT:
if (U8G_PIN_NONE != u8g->pin_list[U8G_PI_CS])
u8g_SetPILevel_DUE(u8g, U8G_PI_CS, arg_val); //note: the st7920 has an active high chip select
break;
case U8G_COM_MSG_WRITE_BYTE:
u8g_com_DUE_st7920_write_byte_sw_spi(u8g->pin_list[U8G_PI_A0_STATE], arg_val);
break;
case U8G_COM_MSG_WRITE_SEQ: {
uint8_t *ptr = (uint8_t*) arg_ptr;
while (arg_val > 0) {
u8g_com_DUE_st7920_write_byte_sw_spi(u8g->pin_list[U8G_PI_A0_STATE], *ptr++);
arg_val--;
}
}
break;
case U8G_COM_MSG_WRITE_SEQ_P: {
uint8_t *ptr = (uint8_t*) arg_ptr;
while (arg_val > 0) {
u8g_com_DUE_st7920_write_byte_sw_spi(u8g->pin_list[U8G_PI_A0_STATE], *ptr++);
arg_val--;
}
}
break;
}
return 1;
}
#if ENABLED(LIGHTWEIGHT_UI)
#include "../../../lcd/marlinui.h"
#include "../../shared/HAL_ST7920.h"
#define ST7920_CS_PIN LCD_PINS_RS
#if DOGM_SPI_DELAY_US > 0
#define U8G_DELAY() DELAY_US(DOGM_SPI_DELAY_US)
#else
#define U8G_DELAY() DELAY_US(10)
#endif
void ST7920_cs() {
WRITE(ST7920_CS_PIN, HIGH);
U8G_DELAY();
}
void ST7920_ncs() {
WRITE(ST7920_CS_PIN, LOW);
}
void ST7920_set_cmd() {
SPISEND_SW_DUE(0xF8);
DELAY_US(40);
}
void ST7920_set_dat() {
SPISEND_SW_DUE(0xFA);
DELAY_US(40);
}
void ST7920_write_byte(const uint8_t val) {
SPISEND_SW_DUE(val & 0xF0);
SPISEND_SW_DUE(val << 4);
}
#endif // LIGHTWEIGHT_UI
#endif // IS_U8GLIB_ST7920
#endif // ARDUINO_ARCH_SAM

@ -0,0 +1,145 @@
/**
* 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/>.
*
*/
/**
* Based on u8g_com_std_sw_spi.c
*
* Universal 8bit Graphics Library
*
* Copyright (c) 2015, olikraus@gmail.com
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice, this list
* of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright notice, this
* list of conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifdef ARDUINO_ARCH_SAM
#include "../../../inc/MarlinConfigPre.h"
#if HAS_MARLINUI_U8GLIB && !IS_U8GLIB_ST7920
#include "u8g_com_HAL_DUE_sw_spi_shared.h"
#include "../../shared/Marduino.h"
#include "../../shared/Delay.h"
#include <U8glib-HAL.h>
#if ENABLED(FYSETC_MINI_12864)
#define SPISEND_SW_DUE u8g_spiSend_sw_DUE_mode_3
#else
#define SPISEND_SW_DUE u8g_spiSend_sw_DUE_mode_0
#endif
uint8_t u8g_com_HAL_DUE_sw_spi_fn(u8g_t *u8g, uint8_t msg, uint8_t arg_val, void *arg_ptr) {
switch (msg) {
case U8G_COM_MSG_INIT:
SCK_pPio = g_APinDescription[u8g->pin_list[U8G_PI_SCK]].pPort;
SCK_dwMask = g_APinDescription[u8g->pin_list[U8G_PI_SCK]].ulPin;
MOSI_pPio = g_APinDescription[u8g->pin_list[U8G_PI_MOSI]].pPort;
MOSI_dwMask = g_APinDescription[u8g->pin_list[U8G_PI_MOSI]].ulPin;
u8g_SetPIOutput_DUE(u8g, U8G_PI_SCK);
u8g_SetPIOutput_DUE(u8g, U8G_PI_MOSI);
u8g_SetPIOutput_DUE(u8g, U8G_PI_CS);
u8g_SetPIOutput_DUE(u8g, U8G_PI_A0);
if (U8G_PIN_NONE != u8g->pin_list[U8G_PI_RESET]) u8g_SetPIOutput_DUE(u8g, U8G_PI_RESET);
u8g_SetPILevel_DUE(u8g, U8G_PI_SCK, 0);
u8g_SetPILevel_DUE(u8g, U8G_PI_MOSI, 0);
break;
case U8G_COM_MSG_STOP:
break;
case U8G_COM_MSG_RESET:
if (U8G_PIN_NONE != u8g->pin_list[U8G_PI_RESET]) u8g_SetPILevel_DUE(u8g, U8G_PI_RESET, arg_val);
break;
case U8G_COM_MSG_CHIP_SELECT:
#if ENABLED(FYSETC_MINI_12864) // LCD SPI is running mode 3 while SD card is running mode 0
if (arg_val) { // SCK idle state needs to be set to the proper idle state before
// the next chip select goes active
u8g_SetPILevel_DUE(u8g, U8G_PI_SCK, 1); //set SCK to mode 3 idle state before CS goes active
u8g_SetPILevel_DUE(u8g, U8G_PI_CS, LOW);
}
else {
u8g_SetPILevel_DUE(u8g, U8G_PI_CS, HIGH);
u8g_SetPILevel_DUE(u8g, U8G_PI_SCK, 0); //set SCK to mode 0 idle state after CS goes inactive
}
#else
u8g_SetPILevel_DUE(u8g, U8G_PI_CS, !arg_val);
#endif
break;
case U8G_COM_MSG_WRITE_BYTE:
SPISEND_SW_DUE(arg_val);
break;
case U8G_COM_MSG_WRITE_SEQ: {
uint8_t *ptr = (uint8_t *)arg_ptr;
while (arg_val > 0) {
SPISEND_SW_DUE(*ptr++);
arg_val--;
}
}
break;
case U8G_COM_MSG_WRITE_SEQ_P: {
uint8_t *ptr = (uint8_t *)arg_ptr;
while (arg_val > 0) {
SPISEND_SW_DUE(u8g_pgm_read(ptr));
ptr++;
arg_val--;
}
}
break;
case U8G_COM_MSG_ADDRESS: /* define cmd (arg_val = 0) or data mode (arg_val = 1) */
u8g_SetPILevel_DUE(u8g, U8G_PI_A0, arg_val);
break;
}
return 1;
}
#endif // HAS_MARLINUI_U8GLIB && !IS_U8GLIB_ST7920
#endif // ARDUINO_ARCH_SAM

@ -0,0 +1,113 @@
/**
* 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/>.
*
*/
/**
* Based on u8g_com_st7920_hw_spi.c
*
* Universal 8bit Graphics Library
*
* Copyright (c) 2011, olikraus@gmail.com
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice, this list
* of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright notice, this
* list of conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifdef ARDUINO_ARCH_SAM
#include "../../../inc/MarlinConfigPre.h"
#if HAS_MARLINUI_U8GLIB
#include "../../../inc/MarlinConfig.h"
#include "../../shared/Delay.h"
#include <U8glib-HAL.h>
#include "u8g_com_HAL_DUE_sw_spi_shared.h"
void u8g_SetPIOutput_DUE(u8g_t *u8g, uint8_t pin_index) {
PIO_Configure(g_APinDescription[u8g->pin_list[pin_index]].pPort, PIO_OUTPUT_1,
g_APinDescription[u8g->pin_list[pin_index]].ulPin, g_APinDescription[u8g->pin_list[pin_index]].ulPinConfiguration); // OUTPUT
}
void u8g_SetPILevel_DUE(u8g_t *u8g, uint8_t pin_index, uint8_t level) {
volatile Pio* port = g_APinDescription[u8g->pin_list[pin_index]].pPort;
uint32_t mask = g_APinDescription[u8g->pin_list[pin_index]].ulPin;
if (level) port->PIO_SODR = mask; else port->PIO_CODR = mask;
}
Pio *SCK_pPio, *MOSI_pPio;
uint32_t SCK_dwMask, MOSI_dwMask;
void u8g_spiSend_sw_DUE_mode_0(uint8_t val) { // 3MHz
for (uint8_t i = 0; i < 8; ++i) {
if (val & 0x80)
MOSI_pPio->PIO_SODR = MOSI_dwMask;
else
MOSI_pPio->PIO_CODR = MOSI_dwMask;
DELAY_NS(48);
SCK_pPio->PIO_SODR = SCK_dwMask;
DELAY_NS(905);
val <<= 1;
SCK_pPio->PIO_CODR = SCK_dwMask;
}
}
void u8g_spiSend_sw_DUE_mode_3(uint8_t val) { // 3.5MHz
for (uint8_t i = 0; i < 8; ++i) {
SCK_pPio->PIO_CODR = SCK_dwMask;
DELAY_NS(50);
if (val & 0x80)
MOSI_pPio->PIO_SODR = MOSI_dwMask;
else
MOSI_pPio->PIO_CODR = MOSI_dwMask;
val <<= 1;
DELAY_NS(10);
SCK_pPio->PIO_SODR = SCK_dwMask;
DELAY_NS(70);
}
}
#endif // HAS_MARLINUI_U8GLIB
#endif // ARDUINO_ARCH_SAM

@ -0,0 +1,35 @@
/**
* 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/>.
*
*/
#pragma once
#include "../../../inc/MarlinConfigPre.h"
#include "../../shared/Marduino.h"
#include <U8glib-HAL.h>
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_spiSend_sw_DUE_mode_0(uint8_t val);
void u8g_spiSend_sw_DUE_mode_3(uint8_t val);
extern Pio *SCK_pPio, *MOSI_pPio;
extern uint32_t SCK_dwMask, MOSI_dwMask;

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

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

Loading…
Cancel
Save