Professional Firmware - Austral Spring version 20221002

- Shortcut option for turning off the backlight in toolbar
- Filament run-out sensor enable/disable in tune menu
- Enhanced Host printing support
- Better C10 support
- Axis value in dash board shows actual position of the axes, including Z leveling
- Raise Z to Probe Clearance position before of a Probing Z Reference
- New ProUI Info box
- Fix https://github.com/mriscoc/Ender3V2S1/issues/344
- Fix mesh slot load message bug
- Enable support for Creality Slicer G-code file with embedded thumbnail for Ender3V2 Neo
- Implements a user option for center the menu title by defining TITLE_CENTERED in configuration files
- Force drawing of Z-axis value on screen redrawing
- Automatically reboot to apply default settings on first boot after flash.
- Code optimization

From last Marlin bugfix 2.1.x
- Emergency Parse M524 (#24761)
- Fix inverse_accel redefine
- Minor planner optimization (#24737)
- UBL G28 leveling fix (#24622)
- Fix / refactor shared PID (#24673)
- Report M22 / M23 success / fail (#24706)
- Constrain UBL within mesh bounds (#24631)
- Other general fixes
pull/474/head 20221002
Miguel Risco-Castillo 2 years ago
parent 8f2d09c334
commit 24931d8c4a

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

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

@ -0,0 +1,14 @@
blank_issues_enabled: false
contact_links:
- name: 📖 Professional Firmware Documentation
url: https://github.com/mriscoc/Ender3V2S1/wiki
about: Lots of documentation about firmware settings and features.
- name: 📖 Marlin Documentation
url: https://marlinfw.org/
about: Lots of documentation on installing and using Marlin.
- name: 👤 Professional Firmware Facebook group
url: https://www.facebook.com/groups/513889302986197
about: Please ask and answer questions here.
- name: 💸 Want to donate?
url: https://www.paypal.com/paypalme/mriscoc
about: Your contribution to this project is always welcome!

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

@ -1,35 +0,0 @@
<!--
Have you read Marlin's Code of Conduct? By filing an Issue, you are expected to comply with it, including treating everyone with respect: https://github.com/MarlinFirmware/Marlin/blob/bugfix-2.0.x/.github/code_of_conduct.md
Do you want to ask a question? Are you looking for support? Please don't post here. Instead use one of the following options:
- The Marlin Firmware forum at https://reprap.org/forum/list.php?415
- The MarlinFirmware Facebook Group at https://www.facebook.com/groups/1049718498464482/
- The MarlinFirmware Discord Server at https://discord.gg/n5NJ59y.
Before filing an issue be sure to test the latest "bugfix" branch to see whether the issue is already addressed.
-->
### Description
<!-- Description of the bug or requested feature -->
### Steps to Reproduce
<!-- If this is a Bug Report, please describe the steps needed to reproduce the issue -->
1. [First Step]
2. [Second Step]
3. [and so on...]
**Expected behavior:** [What you expect to happen]
**Actual behavior:** [What actually happens]
#### Additional Information
* Include a ZIP file containing your `Configuration.h` and `Configuration_adv.h` files.
* Provide pictures or links to videos that clearly demonstrate the issue.
* See [How Can I Contribute](#how-can-i-contribute) for additional guidelines.

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

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

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

@ -0,0 +1,39 @@
#
# clean-closed.yml
# Remove obsolete labels when an Issue or PR is closed
#
name: Clean Closed
on:
pull_request:
types: [closed]
issues:
types: [closed]
jobs:
remove_label:
runs-on: ubuntu-latest
strategy:
matrix:
label:
- "S: Don't Merge"
- "S: Hold for 2.1"
- "S: Please Merge"
- "S: Please Test"
- "help wanted"
- "Needs: Discussion"
- "Needs: Documentation"
- "Needs: More Data"
- "Needs: Patch"
- "Needs: Testing"
- "Needs: Work"
steps:
- uses: actions/checkout@v2
- name: Remove Labels
uses: actions-ecosystem/action-remove-labels@v1
with:
github_token: ${{ github.token }}
labels: ${{ matrix.label }}

@ -0,0 +1,28 @@
#
# close-stale.yml
# Close open issues after a period of inactivity
#
name: Close Stale Issues
on:
schedule:
- cron: "22 1 * * *"
jobs:
stale:
name: Close Stale Issues
if: github.repository == 'MarlinFirmware/Marlin'
runs-on: ubuntu-latest
steps:
- uses: actions/stale@v3
with:
repo-token: ${{ secrets.GITHUB_TOKEN }}
stale-issue-message: 'This issue has had no activity in the last 60 days. Please add a reply if you want to keep this issue active, otherwise it will be automatically closed within 10 days.'
days-before-stale: 60
days-before-close: 10
stale-issue-label: 'stale-closing-soon'
exempt-all-assignees: true
exempt-issue-labels: 'Bug: Confirmed !,T: Feature Request,Needs: More Data,Needs: Discussion,Needs: Documentation,Needs: Patch,Needs: Work,Needs: Testing,help wanted,no-locking'

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

@ -8,7 +8,7 @@ name: CI
on:
pull_request:
branches:
- bugfix-2.0.x
- bugfix-2.1.x
paths-ignore:
- config/**
- data/**
@ -16,7 +16,7 @@ on:
- '**/*.md'
push:
branches:
- bugfix-2.0.x
- bugfix-2.1.x
paths-ignore:
- config/**
- data/**
@ -45,6 +45,7 @@ jobs:
- teensy35
- teensy41
- SAMD51_grandcentral_m4
- PANDA_PI_V29
# Extended AVR Environments
@ -59,13 +60,13 @@ jobs:
#- STM32F103RC_btt_maple
- STM32F103RC_btt_USB_maple
- STM32F103RC_fysetc_maple
- STM32F103RC_meeb
- STM32F103RC_meeb_maple
- jgaurora_a5s_a1_maple
- STM32F103VE_longer_maple
#- mks_robin_maple
- mks_robin_lite_maple
- mks_robin_pro_maple
#- mks_robin_nano35_maple
#- mks_robin_nano_v1v2_maple
#- STM32F103RE_creality_maple
- STM32F103VE_ZM3E4V2_USB_maple
@ -76,9 +77,9 @@ jobs:
- STM32F103RE_btt
- STM32F103RE_btt_USB
- STM32F103RE_creality
- STM32F401RC_creality
- STM32F103VE_longer
- STM32F407VE_black
- STM32F401VE_STEVAL
- BIGTREE_BTT002
- BIGTREE_SKR_PRO
- BIGTREE_GTR_V1_0
@ -92,12 +93,17 @@ jobs:
- rumba32
- LERDGEX
- LERDGEK
- mks_robin_nano35
- mks_robin_nano_v1v2
#- mks_robin_nano_v1v2_usbmod
#- mks_robin_nano_v1_3_f4_usbmod
- NUCLEO_F767ZI
- REMRAM_V1
- BTT_SKR_SE_BX
- chitu_f103
- Index_Mobo_Rev03
- Opulo_Lumen_REV3
# ESP32 environments
- mks_tinybee
# Put lengthy tests last
@ -113,10 +119,10 @@ jobs:
steps:
- name: Check out the PR
uses: actions/checkout@v2
uses: actions/checkout@v3
- name: Cache pip
uses: actions/cache@v2
uses: actions/cache@v3
with:
path: ~/.cache/pip
key: ${{ runner.os }}-pip-${{ hashFiles('**/requirements.txt') }}
@ -124,21 +130,22 @@ jobs:
${{ runner.os }}-pip-
- name: Cache PlatformIO
uses: actions/cache@v2
uses: actions/cache@v3
with:
path: ~/.platformio
key: ${{ runner.os }}-${{ hashFiles('**/lockfiles') }}
- name: Select Python 3.7
uses: actions/setup-python@v2
uses: actions/setup-python@v3
with:
python-version: '3.7' # Version range or exact version of a Python version to use, using semvers version range syntax.
architecture: 'x64' # optional x64 or x86. Defaults to x64 if not specified
- name: Install PlatformIO
run: |
pip install -U https://github.com/platformio/platformio-core/archive/develop.zip
platformio update
pip install -U platformio
pio upgrade --dev
pio pkg update --global
- name: Run ${{ matrix.test-platform }} Tests
run: |

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

171
.gitignore vendored

@ -0,0 +1,171 @@
#
# 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
marlin_config.json
mczip.h
*.gen
*.sublime-workspace
#
# OS
#
applet/
.DS_Store
#
# Misc
#
*~
*.orig
*.rej
*.bak
*.idea
*.i
*.ii
*.swp
tags
#
# C++
#
# Compiled 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
#
# 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
imgui.ini
eeprom.dat
spi_flash.bin
#cmake
CMakeLists.txt
src/CMakeLists.txt
CMakeListsPrivate.txt
build/
# CLion
cmake-build-*
# Eclipse
.project
.cproject
.pydevproject
.settings
.classpath
# Python
__pycache__
# IOLogger logs
*_log.csv

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

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

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

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

@ -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,47 @@
/**
* 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 "platforms.h"
#ifndef GCC_VERSION
#define GCC_VERSION (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__)
#endif
#include HAL_PATH(.,HAL.h)
extern MarlinHAL hal;
#define HAL_ADC_RANGE _BV(HAL_ADC_RESOLUTION)
#ifndef I2C_ADDRESS
#define I2C_ADDRESS(A) uint8_t(A)
#endif
// Needed for AVR sprintf_P PROGMEM extension
#ifndef S_FMT
#define S_FMT "%s"
#endif
// String helper
#ifndef PGMSTR
#define PGMSTR(NAM,STR) const char NAM[] = STR
#endif

@ -0,0 +1,182 @@
/**
* Marlin 3D Printer Firmware
*
* Copyright (c) 2020 MarlinFirmware [https://github.com/MarlinFirmware/Marlin]
* Copyright (c) 2016 Bob Cousins bobcousins42@googlemail.com
* Copyright (c) 2015-2016 Nico Tonnhofer wurstnase.reprap@gmail.com
* Copyright (c) 2017 Victor Perez
*
* This 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/>.
*
*/
#include "../platforms.h"
#ifdef HAL_STM32
#include "../../inc/MarlinConfig.h"
#include "../shared/Delay.h"
#include "usb_serial.h"
#ifdef USBCON
DefaultSerial1 MSerialUSB(false, SerialUSB);
#endif
#if ENABLED(SRAM_EEPROM_EMULATION)
#if STM32F7xx
#include <stm32f7xx_ll_pwr.h>
#elif STM32F4xx
#include <stm32f4xx_ll_pwr.h>
#else
#error "SRAM_EEPROM_EMULATION is currently only supported for STM32F4xx and STM32F7xx"
#endif
#endif
#if HAS_SD_HOST_DRIVE
#include "msc_sd.h"
#include "usbd_cdc_if.h"
#endif
// ------------------------
// Public Variables
// ------------------------
uint16_t MarlinHAL::adc_result;
// ------------------------
// Public functions
// ------------------------
#if ENABLED(POSTMORTEM_DEBUGGING)
extern void install_min_serial();
#endif
// HAL initialization task
void MarlinHAL::init() {
// Ensure F_CPU is a constant expression.
// If the compiler breaks here, it means that delay code that should compute at compile time will not work.
// So better safe than sorry here.
constexpr int cpuFreq = F_CPU;
UNUSED(cpuFreq);
#if ENABLED(SDSUPPORT) && DISABLED(SDIO_SUPPORT) && (defined(SDSS) && SDSS != -1)
OUT_WRITE(SDSS, HIGH); // Try to set SDSS inactive before any other SPI users start up
#endif
#if PIN_EXISTS(LED)
OUT_WRITE(LED_PIN, LOW);
#endif
#if ENABLED(SRAM_EEPROM_EMULATION)
__HAL_RCC_PWR_CLK_ENABLE();
HAL_PWR_EnableBkUpAccess(); // Enable access to backup SRAM
__HAL_RCC_BKPSRAM_CLK_ENABLE();
LL_PWR_EnableBkUpRegulator(); // Enable backup regulator
while (!LL_PWR_IsActiveFlag_BRR()); // Wait until backup regulator is initialized
#endif
SetTimerInterruptPriorities();
#if ENABLED(EMERGENCY_PARSER) && (USBD_USE_CDC || USBD_USE_CDC_MSC)
USB_Hook_init();
#endif
TERN_(POSTMORTEM_DEBUGGING, install_min_serial()); // Install the min serial handler
TERN_(HAS_SD_HOST_DRIVE, MSC_SD_init()); // Enable USB SD card access
#if PIN_EXISTS(USB_CONNECT)
OUT_WRITE(USB_CONNECT_PIN, !USB_CONNECT_INVERTING); // USB clear connection
delay(1000); // Give OS time to notice
WRITE(USB_CONNECT_PIN, USB_CONNECT_INVERTING);
#endif
}
// HAL idle task
void MarlinHAL::idletask() {
#if HAS_SHARED_MEDIA
// Stm32duino currently doesn't have a "loop/idle" method
CDC_resume_receive();
CDC_continue_transmit();
#endif
}
void MarlinHAL::reboot() { NVIC_SystemReset(); }
uint8_t MarlinHAL::get_reset_source() {
return
#ifdef RCC_FLAG_IWDGRST // Some sources may not exist...
RESET != __HAL_RCC_GET_FLAG(RCC_FLAG_IWDGRST) ? RST_WATCHDOG :
#endif
#ifdef RCC_FLAG_IWDG1RST
RESET != __HAL_RCC_GET_FLAG(RCC_FLAG_IWDG1RST) ? RST_WATCHDOG :
#endif
#ifdef RCC_FLAG_IWDG2RST
RESET != __HAL_RCC_GET_FLAG(RCC_FLAG_IWDG2RST) ? RST_WATCHDOG :
#endif
#ifdef RCC_FLAG_SFTRST
RESET != __HAL_RCC_GET_FLAG(RCC_FLAG_SFTRST) ? RST_SOFTWARE :
#endif
#ifdef RCC_FLAG_PINRST
RESET != __HAL_RCC_GET_FLAG(RCC_FLAG_PINRST) ? RST_EXTERNAL :
#endif
#ifdef RCC_FLAG_PORRST
RESET != __HAL_RCC_GET_FLAG(RCC_FLAG_PORRST) ? RST_POWER_ON :
#endif
0
;
}
void MarlinHAL::clear_reset_source() { __HAL_RCC_CLEAR_RESET_FLAGS(); }
// ------------------------
// Watchdog Timer
// ------------------------
#if ENABLED(USE_WATCHDOG)
#define WDT_TIMEOUT_US TERN(WATCHDOG_DURATION_8S, 8000000, 4000000) // 4 or 8 second timeout
#include <IWatchdog.h>
void MarlinHAL::watchdog_init() {
IF_DISABLED(DISABLE_WATCHDOG_INIT, IWatchdog.begin(WDT_TIMEOUT_US));
}
void MarlinHAL::watchdog_refresh() {
IWatchdog.reload();
#if DISABLED(PINS_DEBUGGING) && PIN_EXISTS(LED)
TOGGLE(LED_PIN); // heartbeat indicator
#endif
}
#endif
extern "C" {
extern unsigned int _ebss; // end of bss section
}
// Reset the system to initiate a firmware flash
WEAK void flashFirmware(const int16_t) { hal.reboot(); }
// Maple Compatibility
volatile uint32_t systick_uptime_millis = 0;
systickCallback_t systick_user_callback;
void systick_attach_callback(systickCallback_t cb) { systick_user_callback = cb; }
void HAL_SYSTICK_Callback() {
systick_uptime_millis++;
if (systick_user_callback) systick_user_callback();
}
#endif // HAL_STM32

@ -0,0 +1,281 @@
/**
* Marlin 3D Printer Firmware
*
* Copyright (c) 2020 MarlinFirmware [https://github.com/MarlinFirmware/Marlin]
* Copyright (c) 2016 Bob Cousins bobcousins42@googlemail.com
* Copyright (c) 2015-2016 Nico Tonnhofer wurstnase.reprap@gmail.com
* Copyright (c) 2017 Victor Perez
*
* This 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 CPU_32_BIT
#include "../../core/macros.h"
#include "../shared/Marduino.h"
#include "../shared/math_32bit.h"
#include "../shared/HAL_SPI.h"
#include "fastio.h"
#include "Servo.h"
#include "MarlinSerial.h"
#include "../../inc/MarlinConfigPre.h"
#include <stdint.h>
//
// Default graphical display delays
//
#define CPU_ST7920_DELAY_1 300
#define CPU_ST7920_DELAY_2 40
#define CPU_ST7920_DELAY_3 340
// ------------------------
// Serial ports
// ------------------------
#ifdef USBCON
#include <USBSerial.h>
#include "../../core/serial_hook.h"
typedef ForwardSerial1Class< decltype(SerialUSB) > DefaultSerial1;
extern DefaultSerial1 MSerialUSB;
#endif
#define _MSERIAL(X) MSerial##X
#define MSERIAL(X) _MSERIAL(X)
#if WITHIN(SERIAL_PORT, 1, 6)
#define MYSERIAL1 MSERIAL(SERIAL_PORT)
#elif !defined(USBCON)
#error "SERIAL_PORT must be from 1 to 6."
#elif SERIAL_PORT == -1
#define MYSERIAL1 MSerialUSB
#else
#error "SERIAL_PORT must be from 1 to 6, or -1 for Native USB."
#endif
#ifdef SERIAL_PORT_2
#if WITHIN(SERIAL_PORT_2, 1, 6)
#define MYSERIAL2 MSERIAL(SERIAL_PORT_2)
#elif !defined(USBCON)
#error "SERIAL_PORT must be from 1 to 6."
#elif SERIAL_PORT_2 == -1
#define MYSERIAL2 MSerialUSB
#else
#error "SERIAL_PORT_2 must be from 1 to 6, or -1 for Native USB."
#endif
#endif
#ifdef SERIAL_PORT_3
#if WITHIN(SERIAL_PORT_3, 1, 6)
#define MYSERIAL3 MSERIAL(SERIAL_PORT_3)
#elif !defined(USBCON)
#error "SERIAL_PORT must be from 1 to 6."
#elif SERIAL_PORT_3 == -1
#define MYSERIAL3 MSerialUSB
#else
#error "SERIAL_PORT_3 must be from 1 to 6, or -1 for Native USB."
#endif
#endif
#ifdef MMU2_SERIAL_PORT
#if WITHIN(MMU2_SERIAL_PORT, 1, 6)
#define MMU2_SERIAL MSERIAL(MMU2_SERIAL_PORT)
#elif !defined(USBCON)
#error "SERIAL_PORT must be from 1 to 6."
#elif MMU2_SERIAL_PORT == -1
#define MMU2_SERIAL MSerialUSB
#else
#error "MMU2_SERIAL_PORT must be from 1 to 6, or -1 for Native USB."
#endif
#endif
#ifdef LCD_SERIAL_PORT
#if WITHIN(LCD_SERIAL_PORT, 1, 6)
#define LCD_SERIAL MSERIAL(LCD_SERIAL_PORT)
#elif !defined(USBCON)
#error "SERIAL_PORT must be from 1 to 6."
#elif LCD_SERIAL_PORT == -1
#define LCD_SERIAL MSerialUSB
#else
#error "LCD_SERIAL_PORT must be from 1 to 6, or -1 for Native USB."
#endif
#if HAS_DGUS_LCD
#define SERIAL_GET_TX_BUFFER_FREE() LCD_SERIAL.availableForWrite()
#endif
#endif
/**
* TODO: review this to return 1 for pins that are not analog input
*/
#ifndef analogInputToDigitalPin
#define analogInputToDigitalPin(p) (p)
#endif
//
// Interrupts
//
#define CRITICAL_SECTION_START() const bool irqon = !__get_PRIMASK(); __disable_irq()
#define CRITICAL_SECTION_END() if (irqon) __enable_irq()
#define cli() __disable_irq()
#define sei() __enable_irq()
// ------------------------
// Types
// ------------------------
typedef double isr_float_t; // FPU ops are used for single-precision, so use double for ISRs.
#ifdef STM32G0B1xx
typedef int32_t pin_t;
#else
typedef int16_t pin_t;
#endif
class libServo;
typedef libServo hal_servo_t;
#define PAUSE_SERVO_OUTPUT() libServo::pause_all_servos()
#define RESUME_SERVO_OUTPUT() libServo::resume_all_servos()
// ------------------------
// ADC
// ------------------------
#ifdef ADC_RESOLUTION
#define HAL_ADC_RESOLUTION ADC_RESOLUTION
#else
#define HAL_ADC_RESOLUTION 12
#endif
#define HAL_ADC_VREF 3.3
//
// 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)
#ifdef STM32F1xx
#define JTAG_DISABLE() AFIO_DBGAFR_CONFIG(AFIO_MAPR_SWJ_CFG_JTAGDISABLE)
#define JTAGSWD_DISABLE() AFIO_DBGAFR_CONFIG(AFIO_MAPR_SWJ_CFG_DISABLE)
#define JTAGSWD_RESET() AFIO_DBGAFR_CONFIG(AFIO_MAPR_SWJ_CFG_RESET); // Reset: FULL SWD+JTAG
#endif
#define PLATFORM_M997_SUPPORT
void flashFirmware(const int16_t);
// Maple Compatibility
typedef void (*systickCallback_t)(void);
void systick_attach_callback(systickCallback_t cb);
void HAL_SYSTICK_Callback();
extern volatile uint32_t systick_uptime_millis;
#define HAL_CAN_SET_PWM_FREQ // This HAL supports PWM Frequency adjustment
// ------------------------
// Class Utilities
// ------------------------
// Memory related
#define __bss_end __bss_end__
extern "C" char* _sbrk(int incr);
#pragma GCC diagnostic push
#if GCC_VERSION <= 50000
#pragma GCC diagnostic ignored "-Wunused-function"
#endif
static inline int freeMemory() {
volatile char top;
return &top - reinterpret_cast<char*>(_sbrk(0));
}
#pragma GCC diagnostic pop
// ------------------------
// MarlinHAL Class
// ------------------------
class MarlinHAL {
public:
// Earliest possible init, before setup()
MarlinHAL() {}
// Watchdog
static void watchdog_init() IF_DISABLED(USE_WATCHDOG, {});
static void watchdog_refresh() IF_DISABLED(USE_WATCHDOG, {});
static void init(); // Called early in setup()
static void init_board() {} // Called less early in setup()
static void reboot(); // Restart the firmware from 0x0
// Interrupts
static bool isr_state() { return !__get_PRIMASK(); }
static void isr_on() { sei(); }
static void isr_off() { cli(); }
static void delay_ms(const int ms) { delay(ms); }
// Tasks, called from idle()
static void idletask();
// Reset
static uint8_t get_reset_source();
static void clear_reset_source();
// Free SRAM
static int freeMemory() { return ::freeMemory(); }
//
// ADC Methods
//
static uint16_t adc_result;
// Called by Temperature::init once at startup
static void adc_init() {
analogReadResolution(HAL_ADC_RESOLUTION);
}
// Called by Temperature::init for each sensor at startup
static void adc_enable(const pin_t pin) { pinMode(pin, INPUT); }
// Begin ADC sampling on the given pin. Called from Temperature::isr!
static void adc_start(const pin_t pin) { adc_result = analogRead(pin); }
// Is the ADC ready for reading?
static bool adc_ready() { return true; }
// The current value of the ADC register
static uint16_t adc_value() { return adc_result; }
/**
* Set the PWM duty cycle for the pin to the given value.
* Optionally invert the duty cycle [default = false]
* Optionally change the maximum size of the provided value to enable finer PWM duty control [default = 255]
*/
static void set_pwm_duty(const pin_t pin, const uint16_t v, const uint16_t v_size=255, const bool invert=false);
/**
* Set the frequency of the timer for the given pin.
* All Timer PWM pins run at the same frequency.
*/
static void set_pwm_frequency(const pin_t pin, const uint16_t f_desired);
};

@ -0,0 +1,231 @@
/**
* 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
* Copyright (c) 2017 Victor Perez
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
#include "../platforms.h"
#ifdef HAL_STM32
#include "../../inc/MarlinConfig.h"
#include <SPI.h>
// ------------------------
// Public Variables
// ------------------------
static SPISettings spiConfig;
// ------------------------
// Public functions
// ------------------------
#if ENABLED(SOFTWARE_SPI)
// ------------------------
// Software SPI
// ------------------------
#include "../shared/Delay.h"
void spiBegin(void) {
#if PIN_EXISTS(SD_SS)
OUT_WRITE(SD_SS_PIN, HIGH);
#endif
OUT_WRITE(SD_SCK_PIN, HIGH);
SET_INPUT(SD_MISO_PIN);
OUT_WRITE(SD_MOSI_PIN, HIGH);
}
// Use function with compile-time value so we can actually reach the desired frequency
// Need to adjust this a little bit: on a 72MHz clock, we have 14ns/clock
// and we'll use ~3 cycles to jump to the method and going back, so it'll take ~40ns from the given clock here
#define CALLING_COST_NS (3U * 1000000000U) / (F_CPU)
void (*delaySPIFunc)();
void delaySPI_125() { DELAY_NS(125 - CALLING_COST_NS); }
void delaySPI_250() { DELAY_NS(250 - CALLING_COST_NS); }
void delaySPI_500() { DELAY_NS(500 - CALLING_COST_NS); }
void delaySPI_1000() { DELAY_NS(1000 - CALLING_COST_NS); }
void delaySPI_2000() { DELAY_NS(2000 - CALLING_COST_NS); }
void delaySPI_4000() { DELAY_NS(4000 - CALLING_COST_NS); }
void spiInit(uint8_t spiRate) {
// Use datarates Marlin uses
switch (spiRate) {
case SPI_FULL_SPEED: delaySPIFunc = &delaySPI_125; break; // desired: 8,000,000 actual: ~1.1M
case SPI_HALF_SPEED: delaySPIFunc = &delaySPI_125; break; // desired: 4,000,000 actual: ~1.1M
case SPI_QUARTER_SPEED:delaySPIFunc = &delaySPI_250; break; // desired: 2,000,000 actual: ~890K
case SPI_EIGHTH_SPEED: delaySPIFunc = &delaySPI_500; break; // desired: 1,000,000 actual: ~590K
case SPI_SPEED_5: delaySPIFunc = &delaySPI_1000; break; // desired: 500,000 actual: ~360K
case SPI_SPEED_6: delaySPIFunc = &delaySPI_2000; break; // desired: 250,000 actual: ~210K
default: delaySPIFunc = &delaySPI_4000; break; // desired: 125,000 actual: ~123K
}
SPI.begin();
}
// Begin SPI transaction, set clock, bit order, data mode
void spiBeginTransaction(uint32_t spiClock, uint8_t bitOrder, uint8_t dataMode) { /* do nothing */ }
uint8_t HAL_SPI_STM32_SpiTransfer_Mode_3(uint8_t b) { // using Mode 3
for (uint8_t bits = 8; bits--;) {
WRITE(SD_SCK_PIN, LOW);
WRITE(SD_MOSI_PIN, b & 0x80);
delaySPIFunc();
WRITE(SD_SCK_PIN, HIGH);
delaySPIFunc();
b <<= 1; // little setup time
b |= (READ(SD_MISO_PIN) != 0);
}
DELAY_NS(125);
return b;
}
// Soft SPI receive byte
uint8_t spiRec() {
hal.isr_off(); // No interrupts during byte receive
const uint8_t data = HAL_SPI_STM32_SpiTransfer_Mode_3(0xFF);
hal.isr_on(); // Enable interrupts
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) {
hal.isr_off(); // No interrupts during byte send
HAL_SPI_STM32_SpiTransfer_Mode_3(data); // Don't care what is received
hal.isr_on(); // Enable interrupts
}
// 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]);
}
#else
// ------------------------
// Hardware SPI
// ------------------------
/**
* VGPV SPI speed start and PCLK2/2, by default 108/2 = 54Mhz
*/
/**
* @brief Begin SPI port setup
*
* @return Nothing
*
* @details Only configures SS pin since stm32duino creates and initialize the SPI object
*/
void spiBegin() {
#if PIN_EXISTS(SD_SS)
OUT_WRITE(SD_SS_PIN, HIGH);
#endif
}
// Configure SPI for specified SPI speed
void spiInit(uint8_t spiRate) {
// Use datarates Marlin uses
uint32_t clock;
switch (spiRate) {
case SPI_FULL_SPEED: clock = 20000000; break; // 13.9mhz=20000000 6.75mhz=10000000 3.38mhz=5000000 .833mhz=1000000
case SPI_HALF_SPEED: clock = 5000000; break;
case SPI_QUARTER_SPEED: clock = 2500000; break;
case SPI_EIGHTH_SPEED: clock = 1250000; break;
case SPI_SPEED_5: clock = 625000; break;
case SPI_SPEED_6: clock = 300000; break;
default:
clock = 4000000; // Default from the SPI library
}
spiConfig = SPISettings(clock, MSBFIRST, SPI_MODE0);
SPI.setMISO(SD_MISO_PIN);
SPI.setMOSI(SD_MOSI_PIN);
SPI.setSCLK(SD_SCK_PIN);
SPI.begin();
}
/**
* @brief Receives a single byte from the SPI port.
*
* @return Byte received
*
* @details
*/
uint8_t spiRec() {
uint8_t returnByte = SPI.transfer(0xFF);
return returnByte;
}
/**
* @brief Receive a number of bytes from the SPI port to a buffer
*
* @param buf Pointer to starting address of buffer to write to.
* @param nbyte Number of bytes to receive.
* @return Nothing
*
* @details Uses DMA
*/
void spiRead(uint8_t *buf, uint16_t nbyte) {
if (nbyte == 0) return;
memset(buf, 0xFF, nbyte);
SPI.transfer(buf, nbyte);
}
/**
* @brief Send a single byte on SPI port
*
* @param b Byte to send
*
* @details
*/
void spiSend(uint8_t b) {
SPI.transfer(b);
}
/**
* @brief Write token and then write from 512 byte buffer to SPI (for SD card)
*
* @param buf Pointer with buffer start address
* @return Nothing
*
* @details Use DMA
*/
void spiSendBlock(uint8_t token, const uint8_t *buf) {
uint8_t rxBuf[512];
SPI.transfer(token);
SPI.transfer((uint8_t*)buf, &rxBuf, 512);
}
#endif // SOFTWARE_SPI
#endif // HAL_STM32

@ -0,0 +1,174 @@
/**
* 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/>.
*
*/
#include "../platforms.h"
#if defined(HAL_STM32) && !defined(STM32H7xx)
#include "MarlinSPI.h"
static void spi_init(spi_t *obj, uint32_t speed, spi_mode_e mode, uint8_t msb, uint32_t dataSize) {
spi_init(obj, speed, mode, msb);
// spi_init set 8bit always
// TODO: copy the code from spi_init and handle data size, to avoid double init always!!
if (dataSize != SPI_DATASIZE_8BIT) {
obj->handle.Init.DataSize = dataSize;
HAL_SPI_Init(&obj->handle);
__HAL_SPI_ENABLE(&obj->handle);
}
}
void MarlinSPI::setClockDivider(uint8_t _div) {
_speed = spi_getClkFreq(&_spi);// / _div;
_clockDivider = _div;
}
void MarlinSPI::begin(void) {
//TODO: only call spi_init if any parameter changed!!
spi_init(&_spi, _speed, _dataMode, _bitOrder, _dataSize);
}
void MarlinSPI::setupDma(SPI_HandleTypeDef &_spiHandle, DMA_HandleTypeDef &_dmaHandle, uint32_t direction, bool minc) {
_dmaHandle.Init.Direction = direction;
_dmaHandle.Init.PeriphInc = DMA_PINC_DISABLE;
_dmaHandle.Init.Mode = DMA_NORMAL;
_dmaHandle.Init.Priority = DMA_PRIORITY_LOW;
_dmaHandle.Init.MemInc = minc ? DMA_MINC_ENABLE : DMA_MINC_DISABLE;
if (_dataSize == DATA_SIZE_8BIT) {
_dmaHandle.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
_dmaHandle.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
}
else {
_dmaHandle.Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD;
_dmaHandle.Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD;
}
#ifdef STM32F4xx
_dmaHandle.Init.FIFOMode = DMA_FIFOMODE_DISABLE;
#endif
// start DMA hardware
// TODO: check if hardware is already enabled
#ifdef SPI1_BASE
if (_spiHandle.Instance == SPI1) {
#ifdef STM32F1xx
__HAL_RCC_DMA1_CLK_ENABLE();
_dmaHandle.Instance = (direction == DMA_MEMORY_TO_PERIPH) ? DMA1_Channel3 : DMA1_Channel2;
#elif defined(STM32F4xx)
__HAL_RCC_DMA2_CLK_ENABLE();
_dmaHandle.Init.Channel = DMA_CHANNEL_3;
_dmaHandle.Instance = (direction == DMA_MEMORY_TO_PERIPH) ? DMA2_Stream3 : DMA2_Stream0;
#endif
}
#endif
#ifdef SPI2_BASE
if (_spiHandle.Instance == SPI2) {
#ifdef STM32F1xx
__HAL_RCC_DMA1_CLK_ENABLE();
_dmaHandle.Instance = (direction == DMA_MEMORY_TO_PERIPH) ? DMA1_Channel5 : DMA1_Channel4;
#elif defined(STM32F4xx)
__HAL_RCC_DMA1_CLK_ENABLE();
_dmaHandle.Init.Channel = DMA_CHANNEL_0;
_dmaHandle.Instance = (direction == DMA_MEMORY_TO_PERIPH) ? DMA1_Stream4 : DMA1_Stream3;
#endif
}
#endif
#ifdef SPI3_BASE
if (_spiHandle.Instance == SPI3) {
#ifdef STM32F1xx
__HAL_RCC_DMA2_CLK_ENABLE();
_dmaHandle.Instance = (direction == DMA_MEMORY_TO_PERIPH) ? DMA2_Channel2 : DMA2_Channel1;
#elif defined(STM32F4xx)
__HAL_RCC_DMA1_CLK_ENABLE();
_dmaHandle.Init.Channel = DMA_CHANNEL_0;
_dmaHandle.Instance = (direction == DMA_MEMORY_TO_PERIPH) ? DMA1_Stream5 : DMA1_Stream2;
#endif
}
#endif
HAL_DMA_Init(&_dmaHandle);
}
byte MarlinSPI::transfer(uint8_t _data) {
uint8_t rxData = 0xFF;
HAL_SPI_TransmitReceive(&_spi.handle, &_data, &rxData, 1, HAL_MAX_DELAY);
return rxData;
}
__STATIC_INLINE void LL_SPI_EnableDMAReq_RX(SPI_TypeDef *SPIx) { SET_BIT(SPIx->CR2, SPI_CR2_RXDMAEN); }
__STATIC_INLINE void LL_SPI_EnableDMAReq_TX(SPI_TypeDef *SPIx) { SET_BIT(SPIx->CR2, SPI_CR2_TXDMAEN); }
uint8_t MarlinSPI::dmaTransfer(const void *transmitBuf, void *receiveBuf, uint16_t length) {
const uint8_t ff = 0xFF;
//if (!LL_SPI_IsEnabled(_spi.handle)) // only enable if disabled
__HAL_SPI_ENABLE(&_spi.handle);
if (receiveBuf) {
setupDma(_spi.handle, _dmaRx, DMA_PERIPH_TO_MEMORY, true);
HAL_DMA_Start(&_dmaRx, (uint32_t)&(_spi.handle.Instance->DR), (uint32_t)receiveBuf, length);
LL_SPI_EnableDMAReq_RX(_spi.handle.Instance); // Enable Rx DMA Request
}
// check for 2 lines transfer
bool mincTransmit = true;
if (transmitBuf == nullptr && _spi.handle.Init.Direction == SPI_DIRECTION_2LINES && _spi.handle.Init.Mode == SPI_MODE_MASTER) {
transmitBuf = &ff;
mincTransmit = false;
}
if (transmitBuf) {
setupDma(_spi.handle, _dmaTx, DMA_MEMORY_TO_PERIPH, mincTransmit);
HAL_DMA_Start(&_dmaTx, (uint32_t)transmitBuf, (uint32_t)&(_spi.handle.Instance->DR), length);
LL_SPI_EnableDMAReq_TX(_spi.handle.Instance); // Enable Tx DMA Request
}
if (transmitBuf) {
HAL_DMA_PollForTransfer(&_dmaTx, HAL_DMA_FULL_TRANSFER, HAL_MAX_DELAY);
HAL_DMA_Abort(&_dmaTx);
HAL_DMA_DeInit(&_dmaTx);
}
// while ((_spi.handle.Instance->SR & SPI_FLAG_RXNE) != SPI_FLAG_RXNE) {}
if (receiveBuf) {
HAL_DMA_PollForTransfer(&_dmaRx, HAL_DMA_FULL_TRANSFER, HAL_MAX_DELAY);
HAL_DMA_Abort(&_dmaRx);
HAL_DMA_DeInit(&_dmaRx);
}
return 1;
}
uint8_t MarlinSPI::dmaSend(const void * transmitBuf, uint16_t length, bool minc) {
setupDma(_spi.handle, _dmaTx, DMA_MEMORY_TO_PERIPH, minc);
HAL_DMA_Start(&_dmaTx, (uint32_t)transmitBuf, (uint32_t)&(_spi.handle.Instance->DR), length);
__HAL_SPI_ENABLE(&_spi.handle);
LL_SPI_EnableDMAReq_TX(_spi.handle.Instance); // Enable Tx DMA Request
HAL_DMA_PollForTransfer(&_dmaTx, HAL_DMA_FULL_TRANSFER, HAL_MAX_DELAY);
HAL_DMA_Abort(&_dmaTx);
// DeInit objects
HAL_DMA_DeInit(&_dmaTx);
return 1;
}
#endif // HAL_STM32 && !STM32H7xx

@ -0,0 +1,107 @@
/**
* 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 "HAL.h"
#include <SPI.h>
extern "C" {
#include <utility/spi_com.h>
}
/**
* Marlin currently requires 3 SPI classes:
*
* SPIClass:
* This class is normally provided by frameworks and has a semi-default interface.
* This is needed because some libraries reference it globally.
*
* SPISettings:
* Container for SPI configs for SPIClass. As above, libraries may reference it globally.
*
* These two classes are often provided by frameworks so we cannot extend them to add
* useful methods for Marlin.
*
* MarlinSPI:
* Provides the default SPIClass interface plus some Marlin goodies such as a simplified
* interface for SPI DMA transfer.
*
*/
#define DATA_SIZE_8BIT SPI_DATASIZE_8BIT
#define DATA_SIZE_16BIT SPI_DATASIZE_16BIT
class MarlinSPI {
public:
MarlinSPI() : MarlinSPI(NC, NC, NC, NC) {}
MarlinSPI(pin_t mosi, pin_t miso, pin_t sclk, pin_t ssel = (pin_t)NC) : _mosiPin(mosi), _misoPin(miso), _sckPin(sclk), _ssPin(ssel) {
_spi.pin_miso = digitalPinToPinName(_misoPin);
_spi.pin_mosi = digitalPinToPinName(_mosiPin);
_spi.pin_sclk = digitalPinToPinName(_sckPin);
_spi.pin_ssel = digitalPinToPinName(_ssPin);
_dataSize = DATA_SIZE_8BIT;
_bitOrder = MSBFIRST;
_dataMode = SPI_MODE_0;
_spi.handle.State = HAL_SPI_STATE_RESET;
setClockDivider(SPI_SPEED_CLOCK_DIV2_MHZ);
}
void begin(void);
void end(void) {}
byte transfer(uint8_t _data);
uint8_t dmaTransfer(const void *transmitBuf, void *receiveBuf, uint16_t length);
uint8_t dmaSend(const void * transmitBuf, uint16_t length, bool minc = true);
/* These methods are deprecated and kept for compatibility.
* Use SPISettings with SPI.beginTransaction() to configure SPI parameters.
*/
void setBitOrder(BitOrder _order) { _bitOrder = _order; }
void setDataMode(uint8_t _mode) {
switch (_mode) {
case SPI_MODE0: _dataMode = SPI_MODE_0; break;
case SPI_MODE1: _dataMode = SPI_MODE_1; break;
case SPI_MODE2: _dataMode = SPI_MODE_2; break;
case SPI_MODE3: _dataMode = SPI_MODE_3; break;
}
}
void setClockDivider(uint8_t _div);
private:
void setupDma(SPI_HandleTypeDef &_spiHandle, DMA_HandleTypeDef &_dmaHandle, uint32_t direction, bool minc = false);
spi_t _spi;
DMA_HandleTypeDef _dmaTx;
DMA_HandleTypeDef _dmaRx;
BitOrder _bitOrder;
spi_mode_e _dataMode;
uint8_t _clockDivider;
uint32_t _speed;
uint32_t _dataSize;
pin_t _mosiPin;
pin_t _misoPin;
pin_t _sckPin;
pin_t _ssPin;
};

@ -0,0 +1,110 @@
/**
* 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/>.
*
*/
#include "../platforms.h"
#ifdef HAL_STM32
#include "../../inc/MarlinConfig.h"
#include "MarlinSerial.h"
#if ENABLED(EMERGENCY_PARSER)
#include "../../feature/e_parser.h"
#endif
#ifndef USART4
#define USART4 UART4
#endif
#ifndef USART5
#define USART5 UART5
#endif
#define DECLARE_SERIAL_PORT(ser_num) \
void _rx_complete_irq_ ## ser_num (serial_t * obj); \
MSerialT MSerial ## ser_num (true, USART ## ser_num, &_rx_complete_irq_ ## ser_num); \
void _rx_complete_irq_ ## ser_num (serial_t * obj) { MSerial ## ser_num ._rx_complete_irq(obj); }
#if USING_HW_SERIAL1
DECLARE_SERIAL_PORT(1)
#endif
#if USING_HW_SERIAL2
DECLARE_SERIAL_PORT(2)
#endif
#if USING_HW_SERIAL3
DECLARE_SERIAL_PORT(3)
#endif
#if USING_HW_SERIAL4
DECLARE_SERIAL_PORT(4)
#endif
#if USING_HW_SERIAL5
DECLARE_SERIAL_PORT(5)
#endif
#if USING_HW_SERIAL6
DECLARE_SERIAL_PORT(6)
#endif
#if USING_HW_SERIAL7
DECLARE_SERIAL_PORT(7)
#endif
#if USING_HW_SERIAL8
DECLARE_SERIAL_PORT(8)
#endif
#if USING_HW_SERIAL9
DECLARE_SERIAL_PORT(9)
#endif
#if USING_HW_SERIAL10
DECLARE_SERIAL_PORT(10)
#endif
#if USING_HW_SERIALLP1
DECLARE_SERIAL_PORT(LP1)
#endif
void MarlinSerial::begin(unsigned long baud, uint8_t config) {
HardwareSerial::begin(baud, config);
// Replace the IRQ callback with the one we have defined
TERN_(EMERGENCY_PARSER, _serial.rx_callback = _rx_callback);
}
// This function is Copyright (c) 2006 Nicholas Zambetti.
void MarlinSerial::_rx_complete_irq(serial_t *obj) {
// No Parity error, read byte and store it in the buffer if there is room
unsigned char c;
if (uart_getc(obj, &c) == 0) {
rx_buffer_index_t i = (unsigned int)(obj->rx_head + 1) % SERIAL_RX_BUFFER_SIZE;
// if we should be storing the received character into the location
// just before the tail (meaning that the head would advance to the
// current location of the tail), we're about to overflow the buffer
// and so we don't write the character or advance the head.
if (i != obj->rx_tail) {
obj->rx_buff[obj->rx_head] = c;
obj->rx_head = i;
}
#if ENABLED(EMERGENCY_PARSER)
emergency_parser.update(static_cast<MSerialT*>(this)->emergency_state, c);
#endif
}
}
#endif // HAL_STM32

@ -0,0 +1,59 @@
/**
* 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"
#if ENABLED(EMERGENCY_PARSER)
#include "../../feature/e_parser.h"
#endif
#include "../../core/serial_hook.h"
typedef void (*usart_rx_callback_t)(serial_t * obj);
struct MarlinSerial : public HardwareSerial {
MarlinSerial(void *peripheral, usart_rx_callback_t rx_callback) :
HardwareSerial(peripheral), _rx_callback(rx_callback)
{ }
void begin(unsigned long baud, uint8_t config);
inline void begin(unsigned long baud) { begin(baud, SERIAL_8N1); }
void _rx_complete_irq(serial_t *obj);
protected:
usart_rx_callback_t _rx_callback;
};
typedef Serial1Class<MarlinSerial> MSerialT;
extern MSerialT MSerial1;
extern MSerialT MSerial2;
extern MSerialT MSerial3;
extern MSerialT MSerial4;
extern MSerialT MSerial5;
extern MSerialT MSerial6;
extern MSerialT MSerial7;
extern MSerialT MSerial8;
extern MSerialT MSerial9;
extern MSerialT MSerial10;
extern MSerialT MSerialLP1;

@ -0,0 +1,153 @@
/**
* 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
* Copyright (c) 2017 Victor Perez
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
#include "../platforms.h"
#ifdef HAL_STM32
#include "../../inc/MarlinConfigPre.h"
#if ENABLED(POSTMORTEM_DEBUGGING)
#include "../shared/MinSerial.h"
/* Instruction Synchronization Barrier */
#define isb() __asm__ __volatile__ ("isb" : : : "memory")
/* Data Synchronization Barrier */
#define dsb() __asm__ __volatile__ ("dsb" : : : "memory")
// Dumb mapping over the registers of a USART device on STM32
struct USARTMin {
volatile uint32_t SR;
volatile uint32_t DR;
volatile uint32_t BRR;
volatile uint32_t CR1;
volatile uint32_t CR2;
};
#if WITHIN(SERIAL_PORT, 1, 6)
// Depending on the CPU, the serial port is different for USART1
static const uintptr_t regsAddr[] = {
TERN(STM32F1xx, 0x40013800, 0x40011000), // USART1
0x40004400, // USART2
0x40004800, // USART3
0x40004C00, // UART4_BASE
0x40005000, // UART5_BASE
0x40011400 // USART6
};
static USARTMin * regs = (USARTMin*)regsAddr[SERIAL_PORT - 1];
#endif
static void TXBegin() {
#if !WITHIN(SERIAL_PORT, 1, 6)
#warning "Using POSTMORTEM_DEBUGGING requires a physical U(S)ART hardware in case of severe error."
#warning "Disabling the severe error reporting feature currently because the used serial port is not a HW port."
#else
// This is common between STM32F1/STM32F2 and STM32F4
const int nvicUART[] = { /* NVIC_USART1 */ 37, /* NVIC_USART2 */ 38, /* NVIC_USART3 */ 39, /* NVIC_UART4 */ 52, /* NVIC_UART5 */ 53, /* NVIC_USART6 */ 71 };
int nvicIndex = nvicUART[SERIAL_PORT - 1];
struct NVICMin {
volatile uint32_t ISER[32];
volatile uint32_t ICER[32];
};
NVICMin *nvicBase = (NVICMin*)0xE000E100;
SBI32(nvicBase->ICER[nvicIndex >> 5], nvicIndex & 0x1F);
// 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();
// Example for USART1 disable: (RCC->APB2ENR &= ~(RCC_APB2ENR_USART1EN))
// Too difficult to reimplement here, let's query the STM32duino macro here
#if SERIAL_PORT == 1
__HAL_RCC_USART1_CLK_DISABLE();
__HAL_RCC_USART1_CLK_ENABLE();
#elif SERIAL_PORT == 2
__HAL_RCC_USART2_CLK_DISABLE();
__HAL_RCC_USART2_CLK_ENABLE();
#elif SERIAL_PORT == 3
__HAL_RCC_USART3_CLK_DISABLE();
__HAL_RCC_USART3_CLK_ENABLE();
#elif SERIAL_PORT == 4
__HAL_RCC_UART4_CLK_DISABLE(); // BEWARE: UART4 and not USART4 here
__HAL_RCC_UART4_CLK_ENABLE();
#elif SERIAL_PORT == 5
__HAL_RCC_UART5_CLK_DISABLE(); // BEWARE: UART5 and not USART5 here
__HAL_RCC_UART5_CLK_ENABLE();
#elif SERIAL_PORT == 6
__HAL_RCC_USART6_CLK_DISABLE();
__HAL_RCC_USART6_CLK_ENABLE();
#endif
uint32_t brr = regs->BRR;
regs->CR1 = 0; // Reset the USART
regs->CR2 = 0; // 1 stop bit
// If we don't touch the BRR (baudrate register), we don't need to recompute.
regs->BRR = brr;
regs->CR1 = _BV(3) | _BV(13); // 8 bits, no parity, 1 stop bit (TE | UE)
#endif
}
// A SW memory barrier, to ensure GCC does not overoptimize loops
#define sw_barrier() __asm__ volatile("": : :"memory");
static void TX(char c) {
#if WITHIN(SERIAL_PORT, 1, 6)
constexpr uint32_t usart_sr_txe = _BV(7);
while (!(regs->SR & usart_sr_txe)) {
hal.watchdog_refresh();
sw_barrier();
}
regs->DR = c;
#else
// Let's hope a mystical guru will fix this, one day by writing interrupt-free USB CDC ACM code (or, at least, by polling the registers since interrupt will be queued but will never trigger)
// For now, it's completely lost to oblivion.
#endif
}
void install_min_serial() {
HAL_min_serial_init = &TXBegin;
HAL_min_serial_out = &TX;
}
#if NONE(DYNAMIC_VECTORTABLE, STM32F0xx, STM32G0xx) // Cortex M0 can't jump to a symbol that's too far from the current function, so we work around this in exception_arm.cpp
extern "C" {
__attribute__((naked)) void JumpHandler_ASM() {
__asm__ __volatile__ (
"b CommonHandler_ASM\n"
);
}
void __attribute__((naked, alias("JumpHandler_ASM"), nothrow)) HardFault_Handler();
void __attribute__((naked, alias("JumpHandler_ASM"), nothrow)) BusFault_Handler();
void __attribute__((naked, alias("JumpHandler_ASM"), nothrow)) UsageFault_Handler();
void __attribute__((naked, alias("JumpHandler_ASM"), nothrow)) MemManage_Handler();
void __attribute__((naked, alias("JumpHandler_ASM"), nothrow)) NMI_Handler();
}
#endif
#endif // POSTMORTEM_DEBUGGING
#endif // HAL_STM32

@ -0,0 +1,11 @@
# Generic STM32 HAL based on the stm32duino core
This HAL is intended to act as the generic STM32 HAL for all STM32 chips (The whole F, H and L family).
Currently it supports:
* STM32F0xx
* STM32F1xx
* STM32F4xx
* STM32F7xx
Targeting the official [Arduino STM32 Core](https://github.com/stm32duino/Arduino_Core_STM32).

@ -0,0 +1,112 @@
/**
* 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
* Copyright (c) 2017 Victor Perez
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
#include "../platforms.h"
#ifdef HAL_STM32
#include "../../inc/MarlinConfig.h"
#if HAS_SERVOS
#include "Servo.h"
static uint_fast8_t servoCount = 0;
static libServo *servos[NUM_SERVOS] = {0};
constexpr millis_t servoDelay[] = SERVO_DELAY;
static_assert(COUNT(servoDelay) == NUM_SERVOS, "SERVO_DELAY must be an array NUM_SERVOS long.");
// Initialize to the default timer priority. This will be overridden by a call from timers.cpp.
// This allows all timer interrupt priorities to be managed from a single location in the HAL.
static uint32_t servo_interrupt_priority = NVIC_EncodePriority(NVIC_GetPriorityGrouping(), TIM_IRQ_PRIO, TIM_IRQ_SUBPRIO);
// This must be called after the STM32 Servo class has initialized the timer.
// It may only be needed after the first call to attach(), but it is possible
// that is is necessary after every detach() call. To be safe this is currently
// called after every call to attach().
static void fixServoTimerInterruptPriority() {
NVIC_SetPriority(getTimerUpIrq(TIMER_SERVO), servo_interrupt_priority);
}
libServo::libServo()
: delay(servoDelay[servoCount]),
was_attached_before_pause(false),
value_before_pause(0)
{
servos[servoCount++] = this;
}
int8_t libServo::attach(const int pin) {
if (servoCount >= MAX_SERVOS) return -1;
if (pin > 0) servo_pin = pin;
auto result = stm32_servo.attach(servo_pin);
fixServoTimerInterruptPriority();
return result;
}
int8_t libServo::attach(const int pin, const int min, const int max) {
if (servoCount >= MAX_SERVOS) return -1;
if (pin > 0) servo_pin = pin;
auto result = stm32_servo.attach(servo_pin, min, max);
fixServoTimerInterruptPriority();
return result;
}
void libServo::move(const int value) {
if (attach(0) >= 0) {
stm32_servo.write(value);
safe_delay(delay);
TERN_(DEACTIVATE_SERVOS_AFTER_MOVE, detach());
}
}
void libServo::pause() {
was_attached_before_pause = stm32_servo.attached();
if (was_attached_before_pause) {
value_before_pause = stm32_servo.read();
stm32_servo.detach();
}
}
void libServo::resume() {
if (was_attached_before_pause) {
attach();
move(value_before_pause);
}
}
void libServo::pause_all_servos() {
for (auto& servo : servos)
if (servo) servo->pause();
}
void libServo::resume_all_servos() {
for (auto& servo : servos)
if (servo) servo->resume();
}
void libServo::setInterruptPriority(uint32_t preemptPriority, uint32_t subPriority) {
servo_interrupt_priority = NVIC_EncodePriority(NVIC_GetPriorityGrouping(), preemptPriority, subPriority);
}
#endif // HAS_SERVOS
#endif // HAL_STM32

@ -0,0 +1,54 @@
/**
* 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
* Copyright (c) 2017 Victor Perez
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
#pragma once
#include <Servo.h>
#include "../../core/millis_t.h"
// Inherit and expand on the official library
class libServo {
public:
libServo();
int8_t attach(const int pin = 0); // pin == 0 uses value from previous call
int8_t attach(const int pin, const int min, const int max);
void detach() { stm32_servo.detach(); }
int read() { return stm32_servo.read(); }
void move(const int value);
void pause();
void resume();
static void pause_all_servos();
static void resume_all_servos();
static void setInterruptPriority(uint32_t preemptPriority, uint32_t subPriority);
private:
Servo stm32_servo;
int servo_pin = 0;
millis_t delay = 0;
bool was_attached_before_pause;
int value_before_pause;
};

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

@ -0,0 +1,277 @@
/**
* Marlin 3D Printer Firmware
*
* Copyright (c) 2020 MarlinFirmware [https://github.com/MarlinFirmware/Marlin]
* Copyright (c) 2016 Bob Cousins bobcousins42@googlemail.com
* Copyright (c) 2015-2016 Nico Tonnhofer wurstnase.reprap@gmail.com
* Copyright (c) 2016 Victor Perez victor_pv@hotmail.com
*
* This 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/>.
*
*/
#include "../platforms.h"
#ifdef HAL_STM32
#include "../../inc/MarlinConfig.h"
#if ENABLED(FLASH_EEPROM_EMULATION)
#include "../shared/eeprom_api.h"
// Better: "utility/stm32_eeprom.h", but only after updating stm32duino to 2.0.0
// Use EEPROM.h for compatibility, for now.
#include <EEPROM.h>
/**
* The STM32 HAL supports chips that deal with "pages" and some with "sectors" and some that
* even have multiple "banks" of flash.
*
* This code is a bit of a mashup of
* framework-arduinoststm32/cores/arduino/stm32/stm32_eeprom.c
* hal/hal_lpc1768/persistent_store_flash.cpp
*
* This has only be written against those that use a single "sector" design.
*
* Those that deal with "pages" could be made to work. Looking at the STM32F07 for example, there are
* 128 "pages", each 2kB in size. If we continued with our EEPROM being 4Kb, we'd always need to operate
* on 2 of these pages. Each write, we'd use 2 different pages from a pool of pages until we are done.
*/
#if ENABLED(FLASH_EEPROM_LEVELING)
#include "stm32_def.h"
#define DEBUG_OUT ENABLED(EEPROM_CHITCHAT)
#include "../../core/debug_out.h"
#ifndef MARLIN_EEPROM_SIZE
#define MARLIN_EEPROM_SIZE 0x1000 // 4KB
#endif
#ifndef FLASH_SECTOR
#define FLASH_SECTOR (FLASH_SECTOR_TOTAL - 1)
#endif
#ifndef FLASH_UNIT_SIZE
#define FLASH_UNIT_SIZE 0x20000 // 128kB
#endif
#ifndef FLASH_ADDRESS_START
#define FLASH_ADDRESS_START (FLASH_END - ((FLASH_SECTOR_TOTAL - (FLASH_SECTOR)) * (FLASH_UNIT_SIZE)) + 1)
#endif
#define FLASH_ADDRESS_END (FLASH_ADDRESS_START + FLASH_UNIT_SIZE - 1)
#define EEPROM_SLOTS ((FLASH_UNIT_SIZE) / (MARLIN_EEPROM_SIZE))
#define SLOT_ADDRESS(slot) (FLASH_ADDRESS_START + (slot * (MARLIN_EEPROM_SIZE)))
#define UNLOCK_FLASH() if (!flash_unlocked) { \
HAL_FLASH_Unlock(); \
__HAL_FLASH_CLEAR_FLAG(FLASH_FLAG_EOP | FLASH_FLAG_OPERR | FLASH_FLAG_WRPERR | \
FLASH_FLAG_PGAERR | FLASH_FLAG_PGPERR | FLASH_FLAG_PGSERR); \
flash_unlocked = true; \
}
#define LOCK_FLASH() if (flash_unlocked) { HAL_FLASH_Lock(); flash_unlocked = false; }
#define EMPTY_UINT32 ((uint32_t)-1)
#define EMPTY_UINT8 ((uint8_t)-1)
static uint8_t ram_eeprom[MARLIN_EEPROM_SIZE] __attribute__((aligned(4))) = {0};
static int current_slot = -1;
static_assert(0 == MARLIN_EEPROM_SIZE % 4, "MARLIN_EEPROM_SIZE must be a multiple of 4"); // Ensure copying as uint32_t is safe
static_assert(0 == FLASH_UNIT_SIZE % MARLIN_EEPROM_SIZE, "MARLIN_EEPROM_SIZE must divide evenly into your FLASH_UNIT_SIZE");
static_assert(FLASH_UNIT_SIZE >= MARLIN_EEPROM_SIZE, "FLASH_UNIT_SIZE must be greater than or equal to your MARLIN_EEPROM_SIZE");
static_assert(IS_FLASH_SECTOR(FLASH_SECTOR), "FLASH_SECTOR is invalid");
static_assert(IS_POWER_OF_2(FLASH_UNIT_SIZE), "FLASH_UNIT_SIZE should be a power of 2, please check your chip's spec sheet");
#endif
static bool eeprom_data_written = false;
#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() {
EEPROM.begin(); // Avoid STM32 EEPROM.h warning (do nothing)
#if ENABLED(FLASH_EEPROM_LEVELING)
if (current_slot == -1 || eeprom_data_written) {
// This must be the first time since power on that we have accessed the storage, or someone
// loaded and called write_data and never called access_finish.
// Lets go looking for the slot that holds our configuration.
if (eeprom_data_written) DEBUG_ECHOLNPGM("Dangling EEPROM write_data");
uint32_t address = FLASH_ADDRESS_START;
while (address <= FLASH_ADDRESS_END) {
uint32_t address_value = (*(__IO uint32_t*)address);
if (address_value != EMPTY_UINT32) {
current_slot = (address - (FLASH_ADDRESS_START)) / (MARLIN_EEPROM_SIZE);
break;
}
address += sizeof(uint32_t);
}
if (current_slot == -1) {
// We didn't find anything, so we'll just initialize to empty
for (int i = 0; i < MARLIN_EEPROM_SIZE; i++) ram_eeprom[i] = EMPTY_UINT8;
current_slot = EEPROM_SLOTS;
}
else {
// load current settings
uint8_t *eeprom_data = (uint8_t *)SLOT_ADDRESS(current_slot);
for (int i = 0; i < MARLIN_EEPROM_SIZE; i++) ram_eeprom[i] = eeprom_data[i];
DEBUG_ECHOLNPGM("EEPROM loaded from slot ", current_slot, ".");
}
eeprom_data_written = false;
}
#else
eeprom_buffer_fill();
#endif
return true;
}
bool PersistentStore::access_finish() {
if (eeprom_data_written) {
#ifdef STM32F4xx
// MCU may come up with flash error bits which prevent some flash operations.
// Clear flags prior to flash operations to prevent errors.
__HAL_FLASH_CLEAR_FLAG(FLASH_FLAG_OPERR | FLASH_FLAG_WRPERR | FLASH_FLAG_PGAERR | FLASH_FLAG_PGPERR | FLASH_FLAG_PGSERR);
#endif
#if ENABLED(FLASH_EEPROM_LEVELING)
HAL_StatusTypeDef status = HAL_ERROR;
bool flash_unlocked = false;
if (--current_slot < 0) {
// all slots have been used, erase everything and start again
FLASH_EraseInitTypeDef EraseInitStruct;
uint32_t SectorError = 0;
EraseInitStruct.TypeErase = FLASH_TYPEERASE_SECTORS;
EraseInitStruct.VoltageRange = FLASH_VOLTAGE_RANGE_3;
EraseInitStruct.Sector = FLASH_SECTOR;
EraseInitStruct.NbSectors = 1;
current_slot = EEPROM_SLOTS - 1;
UNLOCK_FLASH();
TERN_(HAS_PAUSE_SERVO_OUTPUT, PAUSE_SERVO_OUTPUT());
hal.isr_off();
status = HAL_FLASHEx_Erase(&EraseInitStruct, &SectorError);
hal.isr_on();
TERN_(HAS_PAUSE_SERVO_OUTPUT, RESUME_SERVO_OUTPUT());
if (status != HAL_OK) {
DEBUG_ECHOLNPGM("HAL_FLASHEx_Erase=", status);
DEBUG_ECHOLNPGM("GetError=", HAL_FLASH_GetError());
DEBUG_ECHOLNPGM("SectorError=", SectorError);
LOCK_FLASH();
return false;
}
}
UNLOCK_FLASH();
uint32_t offset = 0;
uint32_t address = SLOT_ADDRESS(current_slot);
uint32_t address_end = address + MARLIN_EEPROM_SIZE;
uint32_t data = 0;
bool success = true;
while (address < address_end) {
memcpy(&data, ram_eeprom + offset, sizeof(uint32_t));
status = HAL_FLASH_Program(FLASH_TYPEPROGRAM_WORD, address, data);
if (status == HAL_OK) {
address += sizeof(uint32_t);
offset += sizeof(uint32_t);
}
else {
DEBUG_ECHOLNPGM("HAL_FLASH_Program=", status);
DEBUG_ECHOLNPGM("GetError=", HAL_FLASH_GetError());
DEBUG_ECHOLNPGM("address=", address);
success = false;
break;
}
}
LOCK_FLASH();
if (success) {
eeprom_data_written = false;
DEBUG_ECHOLNPGM("EEPROM saved to slot ", current_slot, ".");
}
return success;
#else
// The following was written for the STM32F4 but may work with other MCUs as well.
// Most STM32F4 flash does not allow reading from flash during erase operations.
// This takes about a second on a STM32F407 with a 128kB sector used as EEPROM.
// Interrupts during this time can have unpredictable results, such as killing Servo
// output. Servo output still glitches with interrupts disabled, but recovers after the
// erase.
TERN_(HAS_PAUSE_SERVO_OUTPUT, PAUSE_SERVO_OUTPUT());
hal.isr_off();
eeprom_buffer_flush();
hal.isr_on();
TERN_(HAS_PAUSE_SERVO_OUTPUT, RESUME_SERVO_OUTPUT());
eeprom_data_written = false;
#endif
}
return true;
}
bool PersistentStore::write_data(int &pos, const uint8_t *value, size_t size, uint16_t *crc) {
while (size--) {
uint8_t v = *value;
#if ENABLED(FLASH_EEPROM_LEVELING)
if (v != ram_eeprom[pos]) {
ram_eeprom[pos] = v;
eeprom_data_written = true;
}
#else
if (v != eeprom_buffered_read_byte(pos)) {
eeprom_buffered_write_byte(pos, v);
eeprom_data_written = true;
}
#endif
crc16(crc, &v, 1);
pos++;
value++;
}
return false;
}
bool PersistentStore::read_data(int &pos, uint8_t *value, size_t size, uint16_t *crc, const bool writing/*=true*/) {
do {
const uint8_t c = TERN(FLASH_EEPROM_LEVELING, ram_eeprom[pos], eeprom_buffered_read_byte(pos));
if (writing) *value = c;
crc16(crc, &c, 1);
pos++;
value++;
} while (--size);
return false;
}
#endif // FLASH_EEPROM_EMULATION
#endif // HAL_STM32

@ -0,0 +1,56 @@
/**
* 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/>.
*
*/
#include "../platforms.h"
#ifdef HAL_STM32
/**
* Platform-independent Arduino functions for I2C EEPROM.
* Enable USE_SHARED_EEPROM if not supplied by the framework.
*/
#include "../../inc/MarlinConfig.h"
#if ENABLED(IIC_BL24CXX_EEPROM)
#include "../../libs/BL24CXX.h"
#include "../shared/eeprom_if.h"
void eeprom_init() { BL24CXX::init(); }
// ------------------------
// Public functions
// ------------------------
void eeprom_write_byte(uint8_t *pos, uint8_t value) {
const unsigned eeprom_address = (unsigned)pos;
return BL24CXX::writeOneByte(eeprom_address, value);
}
uint8_t eeprom_read_byte(uint8_t *pos) {
const unsigned eeprom_address = (unsigned)pos;
return BL24CXX::readOneByte(eeprom_address);
}
#endif // IIC_BL24CXX_EEPROM
#endif // HAL_STM32

@ -0,0 +1,94 @@
/**
* 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/>.
*
*/
#include "../platforms.h"
#ifdef HAL_STM32
/**
* Implementation of EEPROM settings in SD Card
*/
#include "../../inc/MarlinConfig.h"
#if ENABLED(SDCARD_EEPROM_EMULATION)
#include "../shared/eeprom_api.h"
#include "../../sd/cardreader.h"
#define EEPROM_FILENAME "eeprom.dat"
#ifndef MARLIN_EEPROM_SIZE
#define MARLIN_EEPROM_SIZE 0x1000 // 4KB
#endif
size_t PersistentStore::capacity() { return MARLIN_EEPROM_SIZE; }
#define _ALIGN(x) __attribute__ ((aligned(x)))
static char _ALIGN(4) HAL_eeprom_data[MARLIN_EEPROM_SIZE];
bool PersistentStore::access_start() {
if (!card.isMounted()) return false;
SdFile file, root = card.getroot();
if (!file.open(&root, EEPROM_FILENAME, O_RDONLY))
return true;
int bytes_read = file.read(HAL_eeprom_data, MARLIN_EEPROM_SIZE);
if (bytes_read < 0) return false;
for (; bytes_read < MARLIN_EEPROM_SIZE; bytes_read++)
HAL_eeprom_data[bytes_read] = 0xFF;
file.close();
return true;
}
bool PersistentStore::access_finish() {
if (!card.isMounted()) return false;
SdFile file, root = card.getroot();
int bytes_written = 0;
if (file.open(&root, EEPROM_FILENAME, O_CREAT | O_WRITE | O_TRUNC)) {
bytes_written = file.write(HAL_eeprom_data, MARLIN_EEPROM_SIZE);
file.close();
}
return (bytes_written == MARLIN_EEPROM_SIZE);
}
bool PersistentStore::write_data(int &pos, const uint8_t *value, size_t size, uint16_t *crc) {
for (size_t i = 0; i < size; i++)
HAL_eeprom_data[pos + i] = value[i];
crc16(crc, value, size);
pos += size;
return false;
}
bool PersistentStore::read_data(int &pos, uint8_t *value, const size_t size, uint16_t *crc, const bool writing/*=true*/) {
for (size_t i = 0; i < size; i++) {
uint8_t c = HAL_eeprom_data[pos + i];
if (writing) value[i] = c;
crc16(crc, &c, 1);
}
pos += size;
return false;
}
#endif // SDCARD_EEPROM_EMULATION
#endif // HAL_STM32

@ -0,0 +1,70 @@
/**
* Marlin 3D Printer Firmware
*
* Copyright (c) 2020 MarlinFirmware [https://github.com/MarlinFirmware/Marlin]
* Copyright (c) 2016 Bob Cousins bobcousins42@googlemail.com
* Copyright (c) 2015-2016 Nico Tonnhofer wurstnase.reprap@gmail.com
* Copyright (c) 2016 Victor Perez victor_pv@hotmail.com
*
* This 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/>.
*
*/
#include "../platforms.h"
#ifdef HAL_STM32
#include "../../inc/MarlinConfig.h"
#if ENABLED(SRAM_EEPROM_EMULATION)
#include "../shared/eeprom_if.h"
#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() { return true; }
bool PersistentStore::access_finish() { return true; }
bool PersistentStore::write_data(int &pos, const uint8_t *value, size_t size, uint16_t *crc) {
while (size--) {
uint8_t v = *value;
// Save to Backup SRAM
*(__IO uint8_t *)(BKPSRAM_BASE + (uint8_t * const)pos) = v;
crc16(crc, &v, 1);
pos++;
value++;
};
return false;
}
bool PersistentStore::read_data(int &pos, uint8_t *value, size_t size, uint16_t *crc, const bool writing/*=true*/) {
do {
// Read from either external EEPROM, program flash or Backup SRAM
const uint8_t c = ( *(__IO uint8_t *)(BKPSRAM_BASE + ((uint8_t*)pos)) );
if (writing) *value = c;
crc16(crc, &c, 1);
pos++;
value++;
} while (--size);
return false;
}
#endif // SRAM_EEPROM_EMULATION
#endif // HAL_STM32

@ -0,0 +1,80 @@
/**
* Marlin 3D Printer Firmware
*
* Copyright (c) 2020 MarlinFirmware [https://github.com/MarlinFirmware/Marlin]
* Copyright (c) 2016 Bob Cousins bobcousins42@googlemail.com
* Copyright (c) 2015-2016 Nico Tonnhofer wurstnase.reprap@gmail.com
* Copyright (c) 2016 Victor Perez victor_pv@hotmail.com
*
* This 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/>.
*
*/
#include "../platforms.h"
#ifdef HAL_STM32
#include "../../inc/MarlinConfig.h"
#if USE_WIRED_EEPROM
/**
* PersistentStore for Arduino-style EEPROM interface
* with simple implementations supplied by Marlin.
*/
#include "../shared/eeprom_if.h"
#include "../shared/eeprom_api.h"
#ifndef MARLIN_EEPROM_SIZE
#define MARLIN_EEPROM_SIZE size_t(E2END + 1)
#endif
size_t PersistentStore::capacity() { return MARLIN_EEPROM_SIZE; }
bool PersistentStore::access_start() { eeprom_init(); return true; }
bool PersistentStore::access_finish() { return true; }
bool PersistentStore::write_data(int &pos, const uint8_t *value, size_t size, uint16_t *crc) {
uint16_t written = 0;
while (size--) {
uint8_t v = *value;
uint8_t * const p = (uint8_t * const)pos;
if (v != eeprom_read_byte(p)) { // EEPROM has only ~100,000 write cycles, so only write bytes that have changed!
eeprom_write_byte(p, v);
if (++written & 0x7F) delay(2); else safe_delay(2); // Avoid triggering watchdog during long EEPROM writes
if (eeprom_read_byte(p) != v) {
SERIAL_ECHO_MSG(STR_ERR_EEPROM_WRITE);
return true;
}
}
crc16(crc, &v, 1);
pos++;
value++;
}
return false;
}
bool PersistentStore::read_data(int &pos, uint8_t *value, size_t size, uint16_t *crc, const bool writing/*=true*/) {
do {
// Read from either external EEPROM, program flash or Backup SRAM
const 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 // HAL_STM32

@ -0,0 +1,61 @@
/**
* 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
* Copyright (c) 2017 Victor Perez
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
#pragma once
#include "../../module/endstops.h"
// One ISR for all EXT-Interrupts
void endstop_ISR() { endstops.update(); }
void setup_endstop_interrupts() {
#define _ATTACH(P) attachInterrupt(P, endstop_ISR, CHANGE)
TERN_(HAS_X_MAX, _ATTACH(X_MAX_PIN));
TERN_(HAS_X_MIN, _ATTACH(X_MIN_PIN));
TERN_(HAS_Y_MAX, _ATTACH(Y_MAX_PIN));
TERN_(HAS_Y_MIN, _ATTACH(Y_MIN_PIN));
TERN_(HAS_Z_MAX, _ATTACH(Z_MAX_PIN));
TERN_(HAS_Z_MIN, _ATTACH(Z_MIN_PIN));
TERN_(HAS_X2_MAX, _ATTACH(X2_MAX_PIN));
TERN_(HAS_X2_MIN, _ATTACH(X2_MIN_PIN));
TERN_(HAS_Y2_MAX, _ATTACH(Y2_MAX_PIN));
TERN_(HAS_Y2_MIN, _ATTACH(Y2_MIN_PIN));
TERN_(HAS_Z2_MAX, _ATTACH(Z2_MAX_PIN));
TERN_(HAS_Z2_MIN, _ATTACH(Z2_MIN_PIN));
TERN_(HAS_Z3_MAX, _ATTACH(Z3_MAX_PIN));
TERN_(HAS_Z3_MIN, _ATTACH(Z3_MIN_PIN));
TERN_(HAS_Z4_MAX, _ATTACH(Z4_MAX_PIN));
TERN_(HAS_Z4_MIN, _ATTACH(Z4_MIN_PIN));
TERN_(HAS_Z_MIN_PROBE_PIN, _ATTACH(Z_MIN_PROBE_PIN));
TERN_(HAS_I_MAX, _ATTACH(I_MAX_PIN));
TERN_(HAS_I_MIN, _ATTACH(I_MIN_PIN));
TERN_(HAS_J_MAX, _ATTACH(J_MAX_PIN));
TERN_(HAS_J_MIN, _ATTACH(J_MIN_PIN));
TERN_(HAS_K_MAX, _ATTACH(K_MAX_PIN));
TERN_(HAS_K_MIN, _ATTACH(K_MIN_PIN));
TERN_(HAS_U_MAX, _ATTACH(U_MAX_PIN));
TERN_(HAS_U_MIN, _ATTACH(U_MIN_PIN));
TERN_(HAS_V_MAX, _ATTACH(V_MAX_PIN));
TERN_(HAS_V_MIN, _ATTACH(V_MIN_PIN));
TERN_(HAS_W_MAX, _ATTACH(W_MAX_PIN));
TERN_(HAS_W_MIN, _ATTACH(W_MIN_PIN));
}

@ -0,0 +1,88 @@
/**
* 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/>.
*
*/
#include "../platforms.h"
#ifdef HAL_STM32
#include "../../inc/MarlinConfig.h"
// Array to support sticky frequency sets per timer
static uint16_t timer_freq[TIMER_NUM];
void MarlinHAL::set_pwm_duty(const pin_t pin, const uint16_t v, const uint16_t v_size/*=255*/, const bool invert/*=false*/) {
const uint16_t duty = invert ? v_size - v : v;
if (PWM_PIN(pin)) {
const PinName pin_name = digitalPinToPinName(pin);
TIM_TypeDef * const Instance = (TIM_TypeDef *)pinmap_peripheral(pin_name, PinMap_PWM);
const timer_index_t index = get_timer_index(Instance);
const bool needs_freq = (HardwareTimer_Handle[index] == nullptr);
if (needs_freq) // A new instance must be set to the default frequency of PWM_FREQUENCY
HardwareTimer_Handle[index]->__this = new HardwareTimer((TIM_TypeDef *)pinmap_peripheral(pin_name, PinMap_PWM));
HardwareTimer * const HT = (HardwareTimer *)(HardwareTimer_Handle[index]->__this);
const uint32_t channel = STM_PIN_CHANNEL(pinmap_function(pin_name, PinMap_PWM));
const TimerModes_t previousMode = HT->getMode(channel);
if (previousMode != TIMER_OUTPUT_COMPARE_PWM1)
HT->setMode(channel, TIMER_OUTPUT_COMPARE_PWM1, pin);
if (needs_freq && timer_freq[index] == 0) // If the timer is unconfigured and no freq is set then default PWM_FREQUENCY
set_pwm_frequency(pin_name, PWM_FREQUENCY); // Set the frequency and save the value to the assigned index no.
// Note the resolution is sticky here, the input can be upto 16 bits and that would require RESOLUTION_16B_COMPARE_FORMAT (16)
// If such a need were to manifest then we would need to calc the resolution based on the v_size parameter and add code for it.
HT->setCaptureCompare(channel, duty, RESOLUTION_8B_COMPARE_FORMAT); // Set the duty, the calc is done in the library :)
pinmap_pinout(pin_name, PinMap_PWM); // Make sure the pin output state is set.
if (previousMode != TIMER_OUTPUT_COMPARE_PWM1) HT->resume();
}
else {
pinMode(pin, OUTPUT);
digitalWrite(pin, duty < v_size / 2 ? LOW : HIGH);
}
}
void MarlinHAL::set_pwm_frequency(const pin_t pin, const uint16_t f_desired) {
if (!PWM_PIN(pin)) return; // Don't proceed if no hardware timer
const PinName pin_name = digitalPinToPinName(pin);
TIM_TypeDef * const Instance = (TIM_TypeDef *)pinmap_peripheral(pin_name, PinMap_PWM); // Get HAL timer instance
const timer_index_t index = get_timer_index(Instance);
// Protect used timers.
#ifdef STEP_TIMER
if (index == TIMER_INDEX(STEP_TIMER)) return;
#endif
#ifdef TEMP_TIMER
if (index == TIMER_INDEX(TEMP_TIMER)) return;
#endif
#if defined(PULSE_TIMER) && MF_TIMER_PULSE != MF_TIMER_STEP
if (index == TIMER_INDEX(PULSE_TIMER)) return;
#endif
if (HardwareTimer_Handle[index] == nullptr) // If frequency is set before duty we need to create a handle here.
HardwareTimer_Handle[index]->__this = new HardwareTimer((TIM_TypeDef *)pinmap_peripheral(pin_name, PinMap_PWM));
HardwareTimer * const HT = (HardwareTimer *)(HardwareTimer_Handle[index]->__this);
HT->setOverflow(f_desired, HERTZ_FORMAT);
timer_freq[index] = f_desired; // Save the last frequency so duty will not set the default for this timer number.
}
#endif // HAL_STM32

@ -0,0 +1,36 @@
/**
* 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
* Copyright (c) 2017 Victor Perez
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
#include "../platforms.h"
#ifdef HAL_STM32
#include "../../inc/MarlinConfig.h"
GPIO_TypeDef* FastIOPortMap[LastPort + 1] = { 0 };
void FastIO_init() {
LOOP_L_N(i, NUM_DIGITAL_PINS)
FastIOPortMap[STM_PORT(digitalPin[i])] = get_GPIO_Port(STM_PORT(digitalPin[i]));
}
#endif // HAL_STM32

@ -0,0 +1,91 @@
/**
* 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
* Copyright (c) 2017 Victor Perez
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
#pragma once
/**
* Fast I/O interfaces for STM32
* These use GPIO register access for fast port manipulation.
*/
// ------------------------
// Public Variables
// ------------------------
extern GPIO_TypeDef * FastIOPortMap[];
// ------------------------
// Public functions
// ------------------------
void FastIO_init(); // Must be called before using fast io macros
#define FASTIO_INIT() FastIO_init()
// ------------------------
// Defines
// ------------------------
#define _BV32(b) (1UL << (b))
#ifndef PWM
#define PWM OUTPUT
#endif
#if defined(STM32F0xx) || defined(STM32F1xx) || defined(STM32F3xx) || defined(STM32L0xx) || defined(STM32L4xx)
#define _WRITE(IO, V) do { \
if (V) FastIOPortMap[STM_PORT(digitalPinToPinName(IO))]->BSRR = _BV32(STM_PIN(digitalPinToPinName(IO))) ; \
else FastIOPortMap[STM_PORT(digitalPinToPinName(IO))]->BRR = _BV32(STM_PIN(digitalPinToPinName(IO))) ; \
}while(0)
#else
#define _WRITE(IO, V) (FastIOPortMap[STM_PORT(digitalPinToPinName(IO))]->BSRR = _BV32(STM_PIN(digitalPinToPinName(IO)) + ((V) ? 0 : 16)))
#endif
#define _READ(IO) bool(READ_BIT(FastIOPortMap[STM_PORT(digitalPinToPinName(IO))]->IDR, _BV32(STM_PIN(digitalPinToPinName(IO)))))
#define _TOGGLE(IO) TBI32(FastIOPortMap[STM_PORT(digitalPinToPinName(IO))]->ODR, STM_PIN(digitalPinToPinName(IO)))
#define _GET_MODE(IO)
#define _SET_MODE(IO,M) pinMode(IO, M)
#define _SET_OUTPUT(IO) pinMode(IO, OUTPUT) //!< Output Push Pull Mode & GPIO_NOPULL
#define _SET_OUTPUT_OD(IO) pinMode(IO, OUTPUT_OPEN_DRAIN)
#define WRITE(IO,V) _WRITE(IO,V)
#define READ(IO) _READ(IO)
#define TOGGLE(IO) _TOGGLE(IO)
#define OUT_WRITE(IO,V) do{ _SET_OUTPUT(IO); WRITE(IO,V); }while(0)
#define OUT_WRITE_OD(IO,V) do{ _SET_OUTPUT_OD(IO); WRITE(IO,V); }while(0)
#define SET_INPUT(IO) _SET_MODE(IO, INPUT) //!< Input Floating Mode
#define SET_INPUT_PULLUP(IO) _SET_MODE(IO, INPUT_PULLUP) //!< Input with Pull-up activation
#define SET_INPUT_PULLDOWN(IO) _SET_MODE(IO, INPUT_PULLDOWN) //!< Input with Pull-down activation
#define SET_OUTPUT(IO) OUT_WRITE(IO, LOW)
#define SET_PWM(IO) _SET_MODE(IO, PWM)
#define IS_INPUT(IO)
#define IS_OUTPUT(IO)
#define PWM_PIN(P) digitalPinHasPWM(P)
#define NO_COMPILE_TIME_PWM
// digitalRead/Write wrappers
#define extDigitalRead(IO) digitalRead(IO)
#define extDigitalWrite(IO,V) digitalWrite(IO,V)

@ -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,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
#if BOTH(SDSUPPORT, USBD_USE_CDC_MSC) && DISABLED(NO_SD_HOST_DRIVE)
#define HAS_SD_HOST_DRIVE 1
#endif
// Fix F_CPU not being a compile-time constant in STSTM32 framework
#ifdef BOARD_F_CPU
#undef F_CPU
#define F_CPU BOARD_F_CPU
#endif
// The Sensitive Pins array is not optimizable
#define RUNTIME_ONLY_ANALOG_TO_DIGITAL

@ -0,0 +1,34 @@
/**
* 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 no real or emulated EEPROM selected, fall back to SD emulation
#if USE_FALLBACK_EEPROM
#define SDCARD_EEPROM_EMULATION
#elif EITHER(I2C_EEPROM, SPI_EEPROM)
#define USE_SHARED_EEPROM 1
#endif
// Some STM32F4 boards may lose steps when saving to EEPROM during print (PR #17946)
#if defined(STM32F4xx) && ENABLED(FLASH_EEPROM_EMULATION) && PRINTCOUNTER_SAVE_INTERVAL > 0
#define PRINTCOUNTER_SYNC 1
#endif

@ -0,0 +1,52 @@
/**
* 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 STM32-specific configuration values for errors at compile-time.
*/
//#if ENABLED(SPINDLE_LASER_USE_PWM) && !(SPINDLE_LASER_PWM_PIN == 4 || SPINDLE_LASER_PWM_PIN == 6 || SPINDLE_LASER_PWM_PIN == 11)
// #error "SPINDLE_LASER_PWM_PIN must use SERVO0, SERVO1 or SERVO3 connector"
//#endif
#if ENABLED(SDCARD_EEPROM_EMULATION) && DISABLED(SDSUPPORT)
#undef SDCARD_EEPROM_EMULATION // Avoid additional error noise
#if USE_FALLBACK_EEPROM
#warning "EEPROM type not specified. Fallback is SDCARD_EEPROM_EMULATION."
#endif
#error "SDCARD_EEPROM_EMULATION requires SDSUPPORT. Enable SDSUPPORT or choose another EEPROM emulation."
#endif
#if !defined(STM32F4xx) && ENABLED(FLASH_EEPROM_LEVELING)
#error "FLASH_EEPROM_LEVELING is currently only supported on STM32F4 hardware."
#endif
#if ENABLED(SERIAL_STATS_MAX_RX_QUEUED)
#error "SERIAL_STATS_MAX_RX_QUEUED is not supported on STM32."
#elif ENABLED(SERIAL_STATS_DROPPED_RX)
#error "SERIAL_STATS_DROPPED_RX is not supported on STM32."
#endif
#if ANY(TFT_COLOR_UI, TFT_LVGL_UI, TFT_CLASSIC_UI) && NOT_TARGET(STM32H7xx, STM32F4xx, STM32F1xx)
#error "TFT_COLOR_UI, TFT_LVGL_UI and TFT_CLASSIC_UI are currently only supported on STM32H7, STM32F4 and STM32F1 hardware."
#endif

@ -0,0 +1,130 @@
/**
* Marlin 3D Printer Firmware
*
* Copyright (c) 2021 MarlinFirmware [https://github.com/MarlinFirmware/Marlin]
* Copyright (c) 2019 BigTreeTech [https://github.com/bigtreetech]
*
* This 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.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
#include "../platforms.h"
#ifdef HAL_STM32
#include "../../inc/MarlinConfigPre.h"
#if HAS_SD_HOST_DRIVE
#include "../shared/Marduino.h"
#include "msc_sd.h"
#include "usbd_core.h"
#include "../../sd/cardreader.h"
#include <USB.h>
#include <USBMscHandler.h>
#define BLOCK_SIZE 512
#define PRODUCT_ID 0x29
class Sd2CardUSBMscHandler : public USBMscHandler {
public:
DiskIODriver* diskIODriver() {
#if ENABLED(MULTI_VOLUME)
#if SHARED_VOLUME_IS(SD_ONBOARD)
return &card.media_driver_sdcard;
#elif SHARED_VOLUME_IS(USB_FLASH_DRIVE)
return &card.media_driver_usbFlash;
#endif
#else
return card.diskIODriver();
#endif
}
bool GetCapacity(uint32_t *pBlockNum, uint16_t *pBlockSize) {
*pBlockNum = diskIODriver()->cardSize();
*pBlockSize = BLOCK_SIZE;
return true;
}
bool Write(uint8_t *pBuf, uint32_t blkAddr, uint16_t blkLen) {
auto sd2card = diskIODriver();
// single block
if (blkLen == 1) {
hal.watchdog_refresh();
sd2card->writeBlock(blkAddr, pBuf);
return true;
}
// multi block optimization
sd2card->writeStart(blkAddr, blkLen);
while (blkLen--) {
hal.watchdog_refresh();
sd2card->writeData(pBuf);
pBuf += BLOCK_SIZE;
}
sd2card->writeStop();
return true;
}
bool Read(uint8_t *pBuf, uint32_t blkAddr, uint16_t blkLen) {
auto sd2card = diskIODriver();
// single block
if (blkLen == 1) {
hal.watchdog_refresh();
sd2card->readBlock(blkAddr, pBuf);
return true;
}
// multi block optimization
sd2card->readStart(blkAddr);
while (blkLen--) {
hal.watchdog_refresh();
sd2card->readData(pBuf);
pBuf += BLOCK_SIZE;
}
sd2card->readStop();
return true;
}
bool IsReady() {
return diskIODriver()->isReady();
}
};
Sd2CardUSBMscHandler usbMscHandler;
/* USB Mass storage Standard Inquiry Data */
uint8_t Marlin_STORAGE_Inquirydata[] = { /* 36 */
/* LUN 0 */
0x00,
0x80,
0x02,
0x02,
(STANDARD_INQUIRY_DATA_LEN - 5),
0x00,
0x00,
0x00,
'M', 'A', 'R', 'L', 'I', 'N', ' ', ' ', /* Manufacturer : 8 bytes */
'P', 'r', 'o', 'd', 'u', 'c', 't', ' ', /* Product : 16 Bytes */
' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
'0', '.', '0', '1', /* Version : 4 Bytes */
};
USBMscHandler *pSingleMscHandler = &usbMscHandler;
void MSC_SD_init() {
USBDevice.end();
delay(200);
USBDevice.registerMscHandlers(1, &pSingleMscHandler, Marlin_STORAGE_Inquirydata);
USBDevice.begin();
}
#endif // HAS_SD_HOST_DRIVE
#endif // HAL_STM32

@ -0,0 +1,18 @@
/**
* Marlin 3D Printer Firmware
*
* Copyright (c) 2021 MarlinFirmware [https://github.com/MarlinFirmware/Marlin]
* Copyright (c) 2019 BigTreeTech [https://github.com/bigtreetech]
*
* This 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.
*
* 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
void MSC_SD_init();

@ -0,0 +1,287 @@
/**
* 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 <Arduino.h>
#ifndef NUM_DIGITAL_PINS
// Only in ST's Arduino core (STM32duino, STM32Core)
#error "Expected NUM_DIGITAL_PINS not found"
#endif
/**
* Life gets complicated if you want an easy to use 'M43 I' output (in port/pin order)
* because the variants in this platform do not always define all the I/O port/pins
* that a CPU has.
*
* VARIABLES:
* Ard_num - Arduino pin number - defined by the platform. It is used by digitalRead and
* digitalWrite commands and by M42.
* - does not contain port/pin info
* - is not in port/pin order
* - typically a variant will only assign Ard_num to port/pins that are actually used
* Index - M43 counter - only used to get Ard_num
* x - a parameter/argument used to search the pin_array to try to find a signal name
* associated with a Ard_num
* Port_pin - port number and pin number for use with CPU registers and printing reports
*
* Since M43 uses digitalRead and digitalWrite commands, only the Port_pins with an Ard_num
* are accessed and/or displayed.
*
* Three arrays are used.
*
* digitalPin[] is provided by the platform. It consists of the Port_pin numbers in
* Arduino pin number order.
*
* pin_array is a structure generated by the pins/pinsDebug.h header file. It is generated by
* the preprocessor. Only the signals associated with enabled options are in this table.
* It contains:
* - name of the signal
* - the Ard_num assigned by the pins_YOUR_BOARD.h file using the platform defines.
* EXAMPLE: "#define KILL_PIN PB1" results in Ard_num of 57. 57 is then used as the
* argument to digitalPinToPinName(IO) to get the Port_pin number
* - if it is a digital or analog signal. PWMs are considered digital here.
*
* pin_xref is a structure generated by this header file. It is generated by the
* preprocessor. It is in port/pin order. It contains just the port/pin numbers defined by the
* platform for this variant.
* - Ard_num
* - printable version of Port_pin
*
* Routines with an "x" as a parameter/argument are used to search the pin_array to try to
* find a signal name associated with a port/pin.
*
* NOTE - the Arduino pin number is what is used by the M42 command, NOT the port/pin for that
* signal. The Arduino pin number is listed by the M43 I command.
*/
////////////////////////////////////////////////////////
//
// make a list of the Arduino pin numbers in the Port/Pin order
//
#define _PIN_ADD(NAME_ALPHA, ARDUINO_NUM) { NAME_ALPHA, ARDUINO_NUM },
#define PIN_ADD(NAME) _PIN_ADD(#NAME, NAME)
typedef struct {
char Port_pin_alpha[5];
pin_t Ard_num;
} XrefInfo;
const XrefInfo pin_xref[] PROGMEM = {
#include "pins_Xref.h"
};
////////////////////////////////////////////////////////////
#define MODE_PIN_INPUT 0 // Input mode (reset state)
#define MODE_PIN_OUTPUT 1 // General purpose output mode
#define MODE_PIN_ALT 2 // Alternate function mode
#define MODE_PIN_ANALOG 3 // Analog mode
#define PIN_NUM(P) (P & 0x000F)
#define PIN_NUM_ALPHA_LEFT(P) (((P & 0x000F) < 10) ? ('0' + (P & 0x000F)) : '1')
#define PIN_NUM_ALPHA_RIGHT(P) (((P & 0x000F) > 9) ? ('0' + (P & 0x000F) - 10) : 0 )
#define PORT_NUM(P) ((P >> 4) & 0x0007)
#define PORT_ALPHA(P) ('A' + (P >> 4))
/**
* Translation of routines & variables used by pinsDebug.h
*/
#if NUM_ANALOG_FIRST >= NUM_DIGITAL_PINS
#define HAS_HIGH_ANALOG_PINS 1
#endif
#define NUM_ANALOG_LAST ((NUM_ANALOG_FIRST) + (NUM_ANALOG_INPUTS) - 1)
#define NUMBER_PINS_TOTAL ((NUM_DIGITAL_PINS) + TERN0(HAS_HIGH_ANALOG_PINS, NUM_ANALOG_INPUTS))
#define VALID_PIN(P) (WITHIN(P, 0, (NUM_DIGITAL_PINS) - 1) || TERN0(HAS_HIGH_ANALOG_PINS, WITHIN(P, NUM_ANALOG_FIRST, NUM_ANALOG_LAST)))
#define digitalRead_mod(Ard_num) extDigitalRead(Ard_num) // must use Arduino pin numbers when doing reads
#define PRINT_PIN(Q)
#define PRINT_PIN_ANALOG(p) do{ sprintf_P(buffer, PSTR(" (A%2d) "), DIGITAL_PIN_TO_ANALOG_PIN(pin)); SERIAL_ECHO(buffer); }while(0)
#define PRINT_PORT(ANUM) port_print(ANUM)
#define DIGITAL_PIN_TO_ANALOG_PIN(ANUM) -1 // will report analog pin number in the print port routine
// x is a variable used to search pin_array
#define GET_ARRAY_IS_DIGITAL(x) ((bool) pin_array[x].is_digital)
#define GET_ARRAY_PIN(x) ((pin_t) pin_array[x].pin)
#define PRINT_ARRAY_NAME(x) do{ sprintf_P(buffer, PSTR("%-" STRINGIFY(MAX_NAME_LENGTH) "s"), pin_array[x].name); SERIAL_ECHO(buffer); }while(0)
#define MULTI_NAME_PAD 33 // space needed to be pretty if not first name assigned to a pin
//
// Pin Mapping for M43
//
#define GET_PIN_MAP_PIN_M43(Index) pin_xref[Index].Ard_num
#ifndef M43_NEVER_TOUCH
#define _M43_NEVER_TOUCH(Index) (Index >= 9 && Index <= 12) // SERIAL/USB pins: PA9(TX) PA10(RX) PA11(USB_DM) PA12(USB_DP)
#ifdef KILL_PIN
#define M43_NEVER_TOUCH(Index) m43_never_touch(Index)
bool m43_never_touch(const pin_t Index) {
static pin_t M43_kill_index = -1;
if (M43_kill_index < 0)
for (M43_kill_index = 0; M43_kill_index < NUMBER_PINS_TOTAL; M43_kill_index++)
if (KILL_PIN == GET_PIN_MAP_PIN_M43(M43_kill_index)) break;
return _M43_NEVER_TOUCH(Index) || Index == M43_kill_index; // KILL_PIN and SERIAL/USB
}
#else
#define M43_NEVER_TOUCH(Index) _M43_NEVER_TOUCH(Index)
#endif
#endif
uint8_t get_pin_mode(const pin_t Ard_num) {
const PinName dp = digitalPinToPinName(Ard_num);
uint32_t ll_pin = STM_LL_GPIO_PIN(dp);
GPIO_TypeDef *port = get_GPIO_Port(STM_PORT(dp));
uint32_t mode = LL_GPIO_GetPinMode(port, ll_pin);
switch (mode) {
case LL_GPIO_MODE_ANALOG: return MODE_PIN_ANALOG;
case LL_GPIO_MODE_INPUT: return MODE_PIN_INPUT;
case LL_GPIO_MODE_OUTPUT: return MODE_PIN_OUTPUT;
case LL_GPIO_MODE_ALTERNATE: return MODE_PIN_ALT;
TERN_(STM32F1xx, case LL_GPIO_MODE_FLOATING:)
default: return 0;
}
}
bool GET_PINMODE(const pin_t Ard_num) {
const uint8_t pin_mode = get_pin_mode(Ard_num);
return pin_mode == MODE_PIN_OUTPUT || pin_mode == MODE_PIN_ALT; // assume all alt definitions are PWM
}
int8_t digital_pin_to_analog_pin(const pin_t Ard_num) {
if (WITHIN(Ard_num, NUM_ANALOG_FIRST, NUM_ANALOG_LAST))
return Ard_num - NUM_ANALOG_FIRST;
const uint32_t ind = digitalPinToAnalogInput(Ard_num);
return (ind < NUM_ANALOG_INPUTS) ? ind : -1;
}
bool IS_ANALOG(const pin_t Ard_num) {
return get_pin_mode(Ard_num) == MODE_PIN_ANALOG;
}
bool is_digital(const pin_t Ard_num) {
const uint8_t pin_mode = get_pin_mode(pin_array[Ard_num].pin);
return pin_mode == MODE_PIN_INPUT || pin_mode == MODE_PIN_OUTPUT;
}
void port_print(const pin_t Ard_num) {
char buffer[16];
pin_t Index;
for (Index = 0; Index < NUMBER_PINS_TOTAL; Index++)
if (Ard_num == GET_PIN_MAP_PIN_M43(Index)) break;
const char * ppa = pin_xref[Index].Port_pin_alpha;
sprintf_P(buffer, PSTR("%s"), ppa);
SERIAL_ECHO(buffer);
if (ppa[3] == '\0') SERIAL_CHAR(' ');
// print analog pin number
const int8_t Port_pin = digital_pin_to_analog_pin(Ard_num);
if (Port_pin >= 0) {
sprintf_P(buffer, PSTR(" (A%d) "), Port_pin);
SERIAL_ECHO(buffer);
if (Port_pin < 10) SERIAL_CHAR(' ');
}
else
SERIAL_ECHO_SP(7);
// Print number to be used with M42
int calc_p = Ard_num;
if (Ard_num > NUM_DIGITAL_PINS) {
calc_p -= NUM_ANALOG_FIRST;
if (calc_p > 7) calc_p += 8;
}
SERIAL_ECHOPGM(" M42 P", calc_p);
SERIAL_CHAR(' ');
if (calc_p < 100) {
SERIAL_CHAR(' ');
if (calc_p < 10)
SERIAL_CHAR(' ');
}
}
bool pwm_status(const pin_t Ard_num) {
return get_pin_mode(Ard_num) == MODE_PIN_ALT;
}
void pwm_details(const pin_t Ard_num) {
#ifndef STM32F1xx
if (pwm_status(Ard_num)) {
uint32_t alt_all = 0;
const PinName dp = digitalPinToPinName(Ard_num);
pin_t pin_number = uint8_t(PIN_NUM(dp));
const bool over_7 = pin_number >= 8;
const uint8_t ind = over_7 ? 1 : 0;
switch (PORT_ALPHA(dp)) { // get alt function
case 'A' : alt_all = GPIOA->AFR[ind]; break;
case 'B' : alt_all = GPIOB->AFR[ind]; break;
case 'C' : alt_all = GPIOC->AFR[ind]; break;
case 'D' : alt_all = GPIOD->AFR[ind]; break;
#ifdef PE_0
case 'E' : alt_all = GPIOE->AFR[ind]; break;
#elif defined(PF_0)
case 'F' : alt_all = GPIOF->AFR[ind]; break;
#elif defined(PG_0)
case 'G' : alt_all = GPIOG->AFR[ind]; break;
#elif defined(PH_0)
case 'H' : alt_all = GPIOH->AFR[ind]; break;
#elif defined(PI_0)
case 'I' : alt_all = GPIOI->AFR[ind]; break;
#elif defined(PJ_0)
case 'J' : alt_all = GPIOJ->AFR[ind]; break;
#elif defined(PK_0)
case 'K' : alt_all = GPIOK->AFR[ind]; break;
#elif defined(PL_0)
case 'L' : alt_all = GPIOL->AFR[ind]; break;
#endif
}
if (over_7) pin_number -= 8;
uint8_t alt_func = (alt_all >> (4 * pin_number)) & 0x0F;
SERIAL_ECHOPGM("Alt Function: ", alt_func);
if (alt_func < 10) SERIAL_CHAR(' ');
SERIAL_ECHOPGM(" - ");
switch (alt_func) {
case 0 : SERIAL_ECHOPGM("system (misc. I/O)"); break;
case 1 : SERIAL_ECHOPGM("TIM1/TIM2 (probably PWM)"); break;
case 2 : SERIAL_ECHOPGM("TIM3..5 (probably PWM)"); break;
case 3 : SERIAL_ECHOPGM("TIM8..11 (probably PWM)"); break;
case 4 : SERIAL_ECHOPGM("I2C1..3"); break;
case 5 : SERIAL_ECHOPGM("SPI1/SPI2"); break;
case 6 : SERIAL_ECHOPGM("SPI3"); break;
case 7 : SERIAL_ECHOPGM("USART1..3"); break;
case 8 : SERIAL_ECHOPGM("USART4..6"); break;
case 9 : SERIAL_ECHOPGM("CAN1/CAN2, TIM12..14 (probably PWM)"); break;
case 10 : SERIAL_ECHOPGM("OTG"); break;
case 11 : SERIAL_ECHOPGM("ETH"); break;
case 12 : SERIAL_ECHOPGM("FSMC, SDIO, OTG"); break;
case 13 : SERIAL_ECHOPGM("DCMI"); break;
case 14 : SERIAL_ECHOPGM("unused (shouldn't see this)"); break;
case 15 : SERIAL_ECHOPGM("EVENTOUT"); break;
}
}
#else
// TODO: F1 doesn't support changing pins function, so we need to check the function of the PIN and if it's enabled
#endif
} // pwm_details

@ -0,0 +1,612 @@
/**
* 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/>.
*
*/
//
// make a list of the Arduino pin numbers in the Port/Pin order
//
#ifdef PA0
PIN_ADD(PA0)
#endif
#ifdef PA1
PIN_ADD(PA1)
#endif
#ifdef PA2
PIN_ADD(PA2)
#endif
#ifdef PA3
PIN_ADD(PA3)
#endif
#ifdef PA4
PIN_ADD(PA4)
#endif
#ifdef PA5
PIN_ADD(PA5)
#endif
#ifdef PA6
PIN_ADD(PA6)
#endif
#ifdef PA7
PIN_ADD(PA7)
#endif
#ifdef PA8
PIN_ADD(PA8)
#endif
#ifdef PA9
PIN_ADD(PA9)
#endif
#ifdef PA10
PIN_ADD(PA10)
#endif
#ifdef PA11
PIN_ADD(PA11)
#endif
#ifdef PA12
PIN_ADD(PA12)
#endif
#ifdef PA13
PIN_ADD(PA13)
#endif
#ifdef PA14
PIN_ADD(PA14)
#endif
#ifdef PA15
PIN_ADD(PA15)
#endif
#ifdef PB0
PIN_ADD(PB0)
#endif
#ifdef PB1
PIN_ADD(PB1)
#endif
#ifdef PB2
PIN_ADD(PB2)
#endif
#ifdef PB3
PIN_ADD(PB3)
#endif
#ifdef PB4
PIN_ADD(PB4)
#endif
#ifdef PB5
PIN_ADD(PB5)
#endif
#ifdef PB6
PIN_ADD(PB6)
#endif
#ifdef PB7
PIN_ADD(PB7)
#endif
#ifdef PB8
PIN_ADD(PB8)
#endif
#ifdef PB9
PIN_ADD(PB9)
#endif
#ifdef PB10
PIN_ADD(PB10)
#endif
#ifdef PB11
PIN_ADD(PB11)
#endif
#ifdef PB12
PIN_ADD(PB12)
#endif
#ifdef PB13
PIN_ADD(PB13)
#endif
#ifdef PB14
PIN_ADD(PB14)
#endif
#ifdef PB15
PIN_ADD(PB15)
#endif
#ifdef PC0
PIN_ADD(PC0)
#endif
#ifdef PC1
PIN_ADD(PC1)
#endif
#ifdef PC2
PIN_ADD(PC2)
#endif
#ifdef PC3
PIN_ADD(PC3)
#endif
#ifdef PC4
PIN_ADD(PC4)
#endif
#ifdef PC5
PIN_ADD(PC5)
#endif
#ifdef PC6
PIN_ADD(PC6)
#endif
#ifdef PC7
PIN_ADD(PC7)
#endif
#ifdef PC8
PIN_ADD(PC8)
#endif
#ifdef PC9
PIN_ADD(PC9)
#endif
#ifdef PC10
PIN_ADD(PC10)
#endif
#ifdef PC11
PIN_ADD(PC11)
#endif
#ifdef PC12
PIN_ADD(PC12)
#endif
#ifdef PC13
PIN_ADD(PC13)
#endif
#ifdef PC14
PIN_ADD(PC14)
#endif
#ifdef PC15
PIN_ADD(PC15)
#endif
#ifdef PD0
PIN_ADD(PD0)
#endif
#ifdef PD1
PIN_ADD(PD1)
#endif
#ifdef PD2
PIN_ADD(PD2)
#endif
#ifdef PD3
PIN_ADD(PD3)
#endif
#ifdef PD4
PIN_ADD(PD4)
#endif
#ifdef PD5
PIN_ADD(PD5)
#endif
#ifdef PD6
PIN_ADD(PD6)
#endif
#ifdef PD7
PIN_ADD(PD7)
#endif
#ifdef PD8
PIN_ADD(PD8)
#endif
#ifdef PD9
PIN_ADD(PD9)
#endif
#ifdef PD10
PIN_ADD(PD10)
#endif
#ifdef PD11
PIN_ADD(PD11)
#endif
#ifdef PD12
PIN_ADD(PD12)
#endif
#ifdef PD13
PIN_ADD(PD13)
#endif
#ifdef PD14
PIN_ADD(PD14)
#endif
#ifdef PD15
PIN_ADD(PD15)
#endif
#ifdef PE0
PIN_ADD(PE0)
#endif
#ifdef PE1
PIN_ADD(PE1)
#endif
#ifdef PE2
PIN_ADD(PE2)
#endif
#ifdef PE3
PIN_ADD(PE3)
#endif
#ifdef PE4
PIN_ADD(PE4)
#endif
#ifdef PE5
PIN_ADD(PE5)
#endif
#ifdef PE6
PIN_ADD(PE6)
#endif
#ifdef PE7
PIN_ADD(PE7)
#endif
#ifdef PE8
PIN_ADD(PE8)
#endif
#ifdef PE9
PIN_ADD(PE9)
#endif
#ifdef PE10
PIN_ADD(PE10)
#endif
#ifdef PE11
PIN_ADD(PE11)
#endif
#ifdef PE12
PIN_ADD(PE12)
#endif
#ifdef PE13
PIN_ADD(PE13)
#endif
#ifdef PE14
PIN_ADD(PE14)
#endif
#ifdef PE15
PIN_ADD(PE15)
#endif
#ifdef PF0
PIN_ADD(PF0)
#endif
#ifdef PF1
PIN_ADD(PF1)
#endif
#ifdef PF2
PIN_ADD(PF2)
#endif
#ifdef PF3
PIN_ADD(PF3)
#endif
#ifdef PF4
PIN_ADD(PF4)
#endif
#ifdef PF5
PIN_ADD(PF5)
#endif
#ifdef PF6
PIN_ADD(PF6)
#endif
#ifdef PF7
PIN_ADD(PF7)
#endif
#ifdef PF8
PIN_ADD(PF8)
#endif
#ifdef PF9
PIN_ADD(PF9)
#endif
#ifdef PF10
PIN_ADD(PF10)
#endif
#ifdef PF11
PIN_ADD(PF11)
#endif
#ifdef PF12
PIN_ADD(PF12)
#endif
#ifdef PF13
PIN_ADD(PF13)
#endif
#ifdef PF14
PIN_ADD(PF14)
#endif
#ifdef PF15
PIN_ADD(PF15)
#endif
#ifdef PG0
PIN_ADD(PG0)
#endif
#ifdef PG1
PIN_ADD(PG1)
#endif
#ifdef PG2
PIN_ADD(PG2)
#endif
#ifdef PG3
PIN_ADD(PG3)
#endif
#ifdef PG4
PIN_ADD(PG4)
#endif
#ifdef PG5
PIN_ADD(PG5)
#endif
#ifdef PG6
PIN_ADD(PG6)
#endif
#ifdef PG7
PIN_ADD(PG7)
#endif
#ifdef PG8
PIN_ADD(PG8)
#endif
#ifdef PG9
PIN_ADD(PG9)
#endif
#ifdef PG10
PIN_ADD(PG10)
#endif
#ifdef PG11
PIN_ADD(PG11)
#endif
#ifdef PG12
PIN_ADD(PG12)
#endif
#ifdef PG13
PIN_ADD(PG13)
#endif
#ifdef PG14
PIN_ADD(PG14)
#endif
#ifdef PG15
PIN_ADD(PG15)
#endif
#ifdef PH0
PIN_ADD(PH0)
#endif
#ifdef PH1
PIN_ADD(PH1)
#endif
#ifdef PH2
PIN_ADD(PH2)
#endif
#ifdef PH3
PIN_ADD(PH3)
#endif
#ifdef PH4
PIN_ADD(PH4)
#endif
#ifdef PH5
PIN_ADD(PH5)
#endif
#ifdef PH6
PIN_ADD(PH6)
#endif
#ifdef PH7
PIN_ADD(PH7)
#endif
#ifdef PH8
PIN_ADD(PH8)
#endif
#ifdef PH9
PIN_ADD(PH9)
#endif
#ifdef PH10
PIN_ADD(PH10)
#endif
#ifdef PH11
PIN_ADD(PH11)
#endif
#ifdef PH12
PIN_ADD(PH12)
#endif
#ifdef PH13
PIN_ADD(PH13)
#endif
#ifdef PH14
PIN_ADD(PH14)
#endif
#ifdef PH15
PIN_ADD(PH15)
#endif
#ifdef PI0
PIN_ADD(PI0)
#endif
#ifdef PI1
PIN_ADD(PI1)
#endif
#ifdef PI2
PIN_ADD(PI2)
#endif
#ifdef PI3
PIN_ADD(PI3)
#endif
#ifdef PI4
PIN_ADD(PI4)
#endif
#ifdef PI5
PIN_ADD(PI5)
#endif
#ifdef PI6
PIN_ADD(PI6)
#endif
#ifdef PI7
PIN_ADD(PI7)
#endif
#ifdef PI8
PIN_ADD(PI8)
#endif
#ifdef PI9
PIN_ADD(PI9)
#endif
#ifdef PI10
PIN_ADD(PI10)
#endif
#ifdef PI11
PIN_ADD(PI11)
#endif
#ifdef PI12
PIN_ADD(PI12)
#endif
#ifdef PI13
PIN_ADD(PI13)
#endif
#ifdef PI14
PIN_ADD(PI14)
#endif
#ifdef PI15
PIN_ADD(PI15)
#endif
#ifdef PJ0
PIN_ADD(PJ0)
#endif
#ifdef PJ1
PIN_ADD(PJ1)
#endif
#ifdef PJ2
PIN_ADD(PJ2)
#endif
#ifdef PJ3
PIN_ADD(PJ3)
#endif
#ifdef PJ4
PIN_ADD(PJ4)
#endif
#ifdef PJ5
PIN_ADD(PJ5)
#endif
#ifdef PJ6
PIN_ADD(PJ6)
#endif
#ifdef PJ7
PIN_ADD(PJ7)
#endif
#ifdef PJ8
PIN_ADD(PJ8)
#endif
#ifdef PJ9
PIN_ADD(PJ9)
#endif
#ifdef PJ10
PIN_ADD(PJ10)
#endif
#ifdef PJ11
PIN_ADD(PJ11)
#endif
#ifdef PJ12
PIN_ADD(PJ12)
#endif
#ifdef PJ13
PIN_ADD(PJ13)
#endif
#ifdef PJ14
PIN_ADD(PJ14)
#endif
#ifdef PJ15
PIN_ADD(PJ15)
#endif
#ifdef PK0
PIN_ADD(PK0)
#endif
#ifdef PK1
PIN_ADD(PK1)
#endif
#ifdef PK2
PIN_ADD(PK2)
#endif
#ifdef PK3
PIN_ADD(PK3)
#endif
#ifdef PK4
PIN_ADD(PK4)
#endif
#ifdef PK5
PIN_ADD(PK5)
#endif
#ifdef PK6
PIN_ADD(PK6)
#endif
#ifdef PK7
PIN_ADD(PK7)
#endif
#ifdef PK8
PIN_ADD(PK8)
#endif
#ifdef PK9
PIN_ADD(PK9)
#endif
#ifdef PK10
PIN_ADD(PK10)
#endif
#ifdef PK11
PIN_ADD(PK11)
#endif
#ifdef PK12
PIN_ADD(PK12)
#endif
#ifdef PK13
PIN_ADD(PK13)
#endif
#ifdef PK14
PIN_ADD(PK14)
#endif
#ifdef PK15
PIN_ADD(PK15)
#endif
#ifdef PL0
PIN_ADD(PL0)
#endif
#ifdef PL1
PIN_ADD(PL1)
#endif
#ifdef PL2
PIN_ADD(PL2)
#endif
#ifdef PL3
PIN_ADD(PL3)
#endif
#ifdef PL4
PIN_ADD(PL4)
#endif
#ifdef PL5
PIN_ADD(PL5)
#endif
#ifdef PL6
PIN_ADD(PL6)
#endif
#ifdef PL7
PIN_ADD(PL7)
#endif
#ifdef PL8
PIN_ADD(PL8)
#endif
#ifdef PL9
PIN_ADD(PL9)
#endif
#ifdef PL10
PIN_ADD(PL10)
#endif
#ifdef PL11
PIN_ADD(PL11)
#endif
#ifdef PL12
PIN_ADD(PL12)
#endif
#ifdef PL13
PIN_ADD(PL13)
#endif
#ifdef PL14
PIN_ADD(PL14)
#endif
#ifdef PL15
PIN_ADD(PL15)
#endif

@ -0,0 +1,451 @@
/**
* 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/>.
*
*/
#include "../platforms.h"
#ifdef HAL_STM32
#include "../../inc/MarlinConfig.h"
#if ENABLED(SDIO_SUPPORT)
#include "sdio.h"
#include <stdint.h>
#include <stdbool.h>
#if defined(STM32F103xE) || defined(STM32F103xG)
#include <stm32f1xx_hal_rcc_ex.h>
#include <stm32f1xx_hal_sd.h>
#elif defined(STM32F4xx)
#include <stm32f4xx_hal_rcc.h>
#include <stm32f4xx_hal_dma.h>
#include <stm32f4xx_hal_gpio.h>
#include <stm32f4xx_hal_sd.h>
#elif defined(STM32F7xx)
#include <stm32f7xx_hal_rcc.h>
#include <stm32f7xx_hal_dma.h>
#include <stm32f7xx_hal_gpio.h>
#include <stm32f7xx_hal_sd.h>
#elif defined(STM32H7xx)
#define SDIO_FOR_STM32H7
#include <stm32h7xx_hal_rcc.h>
#include <stm32h7xx_hal_dma.h>
#include <stm32h7xx_hal_gpio.h>
#include <stm32h7xx_hal_sd.h>
#else
#error "SDIO is only supported with STM32F103xE, STM32F103xG, STM32F4xx, STM32F7xx, and STM32H7xx."
#endif
// SDIO Max Clock (naming from STM Manual, don't change)
#define SDIOCLK 48000000
// Target Clock, configurable. Default is 18MHz, from STM32F1
#ifndef SDIO_CLOCK
#define SDIO_CLOCK 18000000 // 18 MHz
#endif
SD_HandleTypeDef hsd; // SDIO structure
static uint32_t clock_to_divider(uint32_t clk) {
#ifdef SDIO_FOR_STM32H7
// SDMMC_CK frequency = sdmmc_ker_ck / [2 * CLKDIV].
uint32_t sdmmc_clk = HAL_RCCEx_GetPeriphCLKFreq(RCC_PERIPHCLK_SDMMC);
return sdmmc_clk / (2U * SDIO_CLOCK) + (sdmmc_clk % (2U * SDIO_CLOCK) != 0);
#else
// limit the SDIO master clock to 8/3 of PCLK2. See STM32 Manuals
// Also limited to no more than 48Mhz (SDIOCLK).
const uint32_t pclk2 = HAL_RCC_GetPCLK2Freq();
clk = min(clk, (uint32_t)(pclk2 * 8 / 3));
clk = min(clk, (uint32_t)SDIOCLK);
// Round up divider, so we don't run the card over the speed supported,
// and subtract by 2, because STM32 will add 2, as written in the manual:
// SDIO_CK frequency = SDIOCLK / [CLKDIV + 2]
return pclk2 / clk + (pclk2 % clk != 0) - 2;
#endif
}
// Start the SDIO clock
void HAL_SD_MspInit(SD_HandleTypeDef *hsd) {
UNUSED(hsd);
#ifdef SDIO_FOR_STM32H7
pinmap_pinout(PC_12, PinMap_SD);
pinmap_pinout(PD_2, PinMap_SD);
pinmap_pinout(PC_8, PinMap_SD);
#if PINS_EXIST(SDIO_D1, SDIO_D2, SDIO_D3) // Define D1-D3 only for 4-bit wide SDIO bus
pinmap_pinout(PC_9, PinMap_SD);
pinmap_pinout(PC_10, PinMap_SD);
pinmap_pinout(PC_11, PinMap_SD);
#endif
__HAL_RCC_SDMMC1_CLK_ENABLE();
HAL_NVIC_EnableIRQ(SDMMC1_IRQn);
#else
__HAL_RCC_SDIO_CLK_ENABLE();
#endif
}
#ifdef SDIO_FOR_STM32H7
#define SD_TIMEOUT 1000 // ms
extern "C" void SDMMC1_IRQHandler(void) { HAL_SD_IRQHandler(&hsd); }
uint8_t waitingRxCplt = 0, waitingTxCplt = 0;
void HAL_SD_TxCpltCallback(SD_HandleTypeDef *hsdio) { waitingTxCplt = 0; }
void HAL_SD_RxCpltCallback(SD_HandleTypeDef *hsdio) { waitingRxCplt = 0; }
void HAL_SD_MspDeInit(SD_HandleTypeDef *hsd) {
__HAL_RCC_SDMMC1_FORCE_RESET(); delay(10);
__HAL_RCC_SDMMC1_RELEASE_RESET(); delay(10);
}
bool SDIO_Init() {
HAL_StatusTypeDef sd_state = HAL_OK;
if (hsd.Instance == SDMMC1) HAL_SD_DeInit(&hsd);
// HAL SD initialization
hsd.Instance = SDMMC1;
hsd.Init.ClockEdge = SDMMC_CLOCK_EDGE_RISING;
hsd.Init.ClockPowerSave = SDMMC_CLOCK_POWER_SAVE_DISABLE;
hsd.Init.BusWide = SDMMC_BUS_WIDE_1B;
hsd.Init.HardwareFlowControl = SDMMC_HARDWARE_FLOW_CONTROL_DISABLE;
hsd.Init.ClockDiv = clock_to_divider(SDIO_CLOCK);
sd_state = HAL_SD_Init(&hsd);
#if PINS_EXIST(SDIO_D1, SDIO_D2, SDIO_D3)
if (sd_state == HAL_OK)
sd_state = HAL_SD_ConfigWideBusOperation(&hsd, SDMMC_BUS_WIDE_4B);
#endif
return (sd_state == HAL_OK);
}
#else // !SDIO_FOR_STM32H7
#define SD_TIMEOUT 500 // ms
// SDIO retries, configurable. Default is 3, from STM32F1
#ifndef SDIO_READ_RETRIES
#define SDIO_READ_RETRIES 3
#endif
// F4 supports one DMA for RX and another for TX, but Marlin will never
// do read and write at same time, so we use the same DMA for both.
DMA_HandleTypeDef hdma_sdio;
#ifdef STM32F1xx
#define DMA_IRQ_HANDLER DMA2_Channel4_5_IRQHandler
#elif defined(STM32F4xx)
#define DMA_IRQ_HANDLER DMA2_Stream3_IRQHandler
#else
#error "Unknown STM32 architecture."
#endif
extern "C" void SDIO_IRQHandler(void) { HAL_SD_IRQHandler(&hsd); }
extern "C" void DMA_IRQ_HANDLER(void) { HAL_DMA_IRQHandler(&hdma_sdio); }
/*
SDIO_INIT_CLK_DIV is 118
SDIO clock frequency is 48MHz / (TRANSFER_CLOCK_DIV + 2)
SDIO init clock frequency should not exceed 400kHz = 48MHz / (118 + 2)
Default TRANSFER_CLOCK_DIV is 2 (118 / 40)
Default SDIO clock frequency is 48MHz / (2 + 2) = 12 MHz
This might be too fast for stable SDIO operations
MKS Robin SDIO seems stable with BusWide 1bit and ClockDiv 8 (i.e., 4.8MHz SDIO clock frequency)
More testing is required as there are clearly some 4bit init problems.
*/
void go_to_transfer_speed() {
/* Default SDIO peripheral configuration for SD card initialization */
hsd.Init.ClockEdge = hsd.Init.ClockEdge;
hsd.Init.ClockBypass = hsd.Init.ClockBypass;
hsd.Init.ClockPowerSave = hsd.Init.ClockPowerSave;
hsd.Init.BusWide = hsd.Init.BusWide;
hsd.Init.HardwareFlowControl = hsd.Init.HardwareFlowControl;
hsd.Init.ClockDiv = clock_to_divider(SDIO_CLOCK);
/* Initialize SDIO peripheral interface with default configuration */
SDIO_Init(hsd.Instance, hsd.Init);
}
void SD_LowLevel_Init() {
uint32_t tempreg;
// Enable GPIO clocks
__HAL_RCC_GPIOC_CLK_ENABLE();
__HAL_RCC_GPIOD_CLK_ENABLE();
GPIO_InitTypeDef GPIO_InitStruct;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = 1; // GPIO_NOPULL
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
#if DISABLED(STM32F1xx)
GPIO_InitStruct.Alternate = GPIO_AF12_SDIO;
#endif
GPIO_InitStruct.Pin = GPIO_PIN_8 | GPIO_PIN_12; // D0 & SCK
HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);
#if PINS_EXIST(SDIO_D1, SDIO_D2, SDIO_D3) // define D1-D3 only if have a four bit wide SDIO bus
GPIO_InitStruct.Pin = GPIO_PIN_9 | GPIO_PIN_10 | GPIO_PIN_11; // D1-D3
HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);
#endif
// Configure PD.02 CMD line
GPIO_InitStruct.Pin = GPIO_PIN_2;
HAL_GPIO_Init(GPIOD, &GPIO_InitStruct);
// Setup DMA
#ifdef STM32F1xx
hdma_sdio.Init.Mode = DMA_NORMAL;
hdma_sdio.Instance = DMA2_Channel4;
HAL_NVIC_EnableIRQ(DMA2_Channel4_5_IRQn);
#elif defined(STM32F4xx)
hdma_sdio.Init.Mode = DMA_PFCTRL;
hdma_sdio.Instance = DMA2_Stream3;
hdma_sdio.Init.Channel = DMA_CHANNEL_4;
hdma_sdio.Init.FIFOMode = DMA_FIFOMODE_ENABLE;
hdma_sdio.Init.FIFOThreshold = DMA_FIFO_THRESHOLD_FULL;
hdma_sdio.Init.MemBurst = DMA_MBURST_INC4;
hdma_sdio.Init.PeriphBurst = DMA_PBURST_INC4;
HAL_NVIC_EnableIRQ(DMA2_Stream3_IRQn);
#endif
HAL_NVIC_EnableIRQ(SDIO_IRQn);
hdma_sdio.Init.PeriphInc = DMA_PINC_DISABLE;
hdma_sdio.Init.MemInc = DMA_MINC_ENABLE;
hdma_sdio.Init.PeriphDataAlignment = DMA_PDATAALIGN_WORD;
hdma_sdio.Init.MemDataAlignment = DMA_MDATAALIGN_WORD;
hdma_sdio.Init.Priority = DMA_PRIORITY_LOW;
__HAL_LINKDMA(&hsd, hdmarx, hdma_sdio);
__HAL_LINKDMA(&hsd, hdmatx, hdma_sdio);
#ifdef STM32F1xx
__HAL_RCC_SDIO_CLK_ENABLE();
__HAL_RCC_DMA2_CLK_ENABLE();
#else
__HAL_RCC_SDIO_FORCE_RESET(); delay(2);
__HAL_RCC_SDIO_RELEASE_RESET(); delay(2);
__HAL_RCC_SDIO_CLK_ENABLE();
__HAL_RCC_DMA2_FORCE_RESET(); delay(2);
__HAL_RCC_DMA2_RELEASE_RESET(); delay(2);
__HAL_RCC_DMA2_CLK_ENABLE();
#endif
// Initialize the SDIO (with initial <400Khz Clock)
tempreg = 0 // Reset value
| SDIO_CLKCR_CLKEN // Clock enabled
| SDIO_INIT_CLK_DIV; // Clock Divider. Clock = 48000 / (118 + 2) = 400Khz
// Keep the rest at 0 => HW_Flow Disabled, Rising Clock Edge, Disable CLK ByPass, Bus Width = 0, Power save Disable
SDIO->CLKCR = tempreg;
// Power up the SDIO
SDIO_PowerState_ON(SDIO);
hsd.Instance = SDIO;
}
bool SDIO_Init() {
uint8_t retryCnt = SDIO_READ_RETRIES;
bool status;
hsd.Instance = SDIO;
hsd.State = HAL_SD_STATE_RESET;
SD_LowLevel_Init();
uint8_t retry_Cnt = retryCnt;
for (;;) {
hal.watchdog_refresh();
status = (bool) HAL_SD_Init(&hsd);
if (!status) break;
if (!--retry_Cnt) return false; // return failing status if retries are exhausted
}
go_to_transfer_speed();
#if PINS_EXIST(SDIO_D1, SDIO_D2, SDIO_D3) // go to 4 bit wide mode if pins are defined
retry_Cnt = retryCnt;
for (;;) {
hal.watchdog_refresh();
if (!HAL_SD_ConfigWideBusOperation(&hsd, SDIO_BUS_WIDE_4B)) break; // some cards are only 1 bit wide so a pass here is not required
if (!--retry_Cnt) break;
}
if (!retry_Cnt) { // wide bus failed, go back to one bit wide mode
hsd.State = (HAL_SD_StateTypeDef) 0; // HAL_SD_STATE_RESET
SD_LowLevel_Init();
retry_Cnt = retryCnt;
for (;;) {
hal.watchdog_refresh();
status = (bool) HAL_SD_Init(&hsd);
if (!status) break;
if (!--retry_Cnt) return false; // return failing status if retries are exhausted
}
go_to_transfer_speed();
}
#endif
return true;
}
/**
* @brief Read or Write a block
* @details Read or Write a block with SDIO
*
* @param block The block index
* @param src The data buffer source for a write
* @param dst The data buffer destination for a read
*
* @return true on success
*/
static bool SDIO_ReadWriteBlock_DMA(uint32_t block, const uint8_t *src, uint8_t *dst) {
if (HAL_SD_GetCardState(&hsd) != HAL_SD_CARD_TRANSFER) return false;
hal.watchdog_refresh();
HAL_StatusTypeDef ret;
if (src) {
hdma_sdio.Init.Direction = DMA_MEMORY_TO_PERIPH;
HAL_DMA_Init(&hdma_sdio);
ret = HAL_SD_WriteBlocks_DMA(&hsd, (uint8_t*)src, block, 1);
}
else {
hdma_sdio.Init.Direction = DMA_PERIPH_TO_MEMORY;
HAL_DMA_Init(&hdma_sdio);
ret = HAL_SD_ReadBlocks_DMA(&hsd, (uint8_t*)dst, block, 1);
}
if (ret != HAL_OK) {
HAL_DMA_Abort_IT(&hdma_sdio);
HAL_DMA_DeInit(&hdma_sdio);
return false;
}
millis_t timeout = millis() + SD_TIMEOUT;
// Wait the transfer
while (hsd.State != HAL_SD_STATE_READY) {
if (ELAPSED(millis(), timeout)) {
HAL_DMA_Abort_IT(&hdma_sdio);
HAL_DMA_DeInit(&hdma_sdio);
return false;
}
}
while (__HAL_DMA_GET_FLAG(&hdma_sdio, __HAL_DMA_GET_TC_FLAG_INDEX(&hdma_sdio)) != 0
|| __HAL_DMA_GET_FLAG(&hdma_sdio, __HAL_DMA_GET_TE_FLAG_INDEX(&hdma_sdio)) != 0) { /* nada */ }
HAL_DMA_Abort_IT(&hdma_sdio);
HAL_DMA_DeInit(&hdma_sdio);
timeout = millis() + SD_TIMEOUT;
while (HAL_SD_GetCardState(&hsd) != HAL_SD_CARD_TRANSFER) if (ELAPSED(millis(), timeout)) return false;
return true;
}
#endif // !SDIO_FOR_STM32H7
/**
* @brief Read a block
* @details Read a block from media with SDIO
*
* @param block The block index
* @param src The block buffer
*
* @return true on success
*/
bool SDIO_ReadBlock(uint32_t block, uint8_t *dst) {
#ifdef SDIO_FOR_STM32H7
uint32_t timeout = HAL_GetTick() + SD_TIMEOUT;
while (HAL_SD_GetCardState(&hsd) != HAL_SD_CARD_TRANSFER)
if (HAL_GetTick() >= timeout) return false;
waitingRxCplt = 1;
if (HAL_SD_ReadBlocks_DMA(&hsd, (uint8_t*)dst, block, 1) != HAL_OK)
return false;
timeout = HAL_GetTick() + SD_TIMEOUT;
while (waitingRxCplt)
if (HAL_GetTick() >= timeout) return false;
return true;
#else
uint8_t retries = SDIO_READ_RETRIES;
while (retries--) if (SDIO_ReadWriteBlock_DMA(block, nullptr, dst)) return true;
return false;
#endif
}
/**
* @brief Write a block
* @details Write a block to media with SDIO
*
* @param block The block index
* @param src The block data
*
* @return true on success
*/
bool SDIO_WriteBlock(uint32_t block, const uint8_t *src) {
#ifdef SDIO_FOR_STM32H7
uint32_t timeout = HAL_GetTick() + SD_TIMEOUT;
while (HAL_SD_GetCardState(&hsd) != HAL_SD_CARD_TRANSFER)
if (HAL_GetTick() >= timeout) return false;
waitingTxCplt = 1;
if (HAL_SD_WriteBlocks_DMA(&hsd, (uint8_t*)src, block, 1) != HAL_OK)
return false;
timeout = HAL_GetTick() + SD_TIMEOUT;
while (waitingTxCplt)
if (HAL_GetTick() >= timeout) return false;
return true;
#else
uint8_t retries = SDIO_READ_RETRIES;
while (retries--) if (SDIO_ReadWriteBlock_DMA(block, src, nullptr)) return true;
return false;
#endif
}
bool SDIO_IsReady() {
return hsd.State == HAL_SD_STATE_READY;
}
uint32_t SDIO_GetCardSize() {
return (uint32_t)(hsd.SdCard.BlockNbr) * (hsd.SdCard.BlockSize);
}
#endif // SDIO_SUPPORT
#endif // HAL_STM32

@ -0,0 +1,29 @@
/**
* 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
#define SDIO_D0_PIN PC8
#define SDIO_D1_PIN PC9
#define SDIO_D2_PIN PC10
#define SDIO_D3_PIN PC11
#define SDIO_CK_PIN PC12
#define SDIO_CMD_PIN PD2

@ -0,0 +1,38 @@
/**
* 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
*/
#ifndef SD_SCK_PIN
#define SD_SCK_PIN PIN_SPI_SCK
#endif
#ifndef SD_MISO_PIN
#define SD_MISO_PIN PIN_SPI_MISO
#endif
#ifndef SD_MOSI_PIN
#define SD_MOSI_PIN PIN_SPI_MOSI
#endif
#ifndef SD_SS_PIN
#define SD_SS_PIN PIN_SPI_SS
#endif

@ -0,0 +1,208 @@
/**
* 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/>.
*
*/
#include "../../platforms.h"
#ifdef HAL_STM32
#include "../../../inc/MarlinConfig.h"
#if ENABLED(TFT_TOUCH_DEVICE_GT911)
#include "gt911.h"
#include "pinconfig.h"
SW_IIC::SW_IIC(uint16_t sda, uint16_t scl) {
scl_pin = scl;
sda_pin = sda;
}
// Software I2C hardware io init
void SW_IIC::init() {
OUT_WRITE(scl_pin, HIGH);
OUT_WRITE(sda_pin, HIGH);
}
// Software I2C start signal
void SW_IIC::start() {
write_sda(HIGH); // SDA = 1
write_scl(HIGH); // SCL = 1
iic_delay(2);
write_sda(LOW); // SDA = 0
iic_delay(1);
write_scl(LOW); // SCL = 0 // keep SCL low, avoid false stop caused by level jump caused by SDA switching IN/OUT
}
// Software I2C stop signal
void SW_IIC::stop() {
write_scl(LOW); // SCL = 0
iic_delay(2);
write_sda(LOW); // SDA = 0
iic_delay(2);
write_scl(HIGH); // SCL = 1
iic_delay(2);
write_sda(HIGH); // SDA = 1
}
// Software I2C sends ACK or NACK signal
void SW_IIC::send_ack(bool ack) {
write_sda(ack ? LOW : HIGH); // SDA = !ack
iic_delay(2);
write_scl(HIGH); // SCL = 1
iic_delay(2);
write_scl(LOW); // SCL = 0
}
// Software I2C read ACK or NACK signal
bool SW_IIC::read_ack() {
bool error = 0;
set_sda_in();
iic_delay(2);
write_scl(HIGH); // SCL = 1
error = read_sda();
iic_delay(2);
write_scl(LOW); // SCL = 0
set_sda_out();
return error;
}
void SW_IIC::send_byte(uint8_t txd) {
LOOP_L_N(i, 8) {
write_sda(txd & 0x80); // write data bit
txd <<= 1;
iic_delay(1);
write_scl(HIGH); // SCL = 1
iic_delay(2);
write_scl(LOW); // SCL = 0
iic_delay(1);
}
read_ack(); // wait ack
}
uint8_t SW_IIC::read_byte(bool ack) {
uint8_t data = 0;
set_sda_in();
LOOP_L_N(i, 8) {
write_scl(HIGH); // SCL = 1
iic_delay(1);
data <<= 1;
if (read_sda()) data++;
write_scl(LOW); // SCL = 0
iic_delay(2);
}
set_sda_out();
send_ack(ack);
return data;
}
GT911_REG_MAP GT911::reg;
SW_IIC GT911::sw_iic = SW_IIC(GT911_SW_I2C_SDA_PIN, GT911_SW_I2C_SCL_PIN);
void GT911::write_reg(uint16_t reg, uint8_t reg_len, uint8_t* w_data, uint8_t w_len) {
sw_iic.start();
sw_iic.send_byte(gt911_slave_address); // Set IIC Slave address
LOOP_L_N(i, reg_len) { // Set reg address
uint8_t r = (reg >> (8 * (reg_len - 1 - i))) & 0xFF;
sw_iic.send_byte(r);
}
LOOP_L_N(i, w_len) { // Write data to reg
sw_iic.send_byte(w_data[i]);
}
sw_iic.stop();
}
void GT911::read_reg(uint16_t reg, uint8_t reg_len, uint8_t* r_data, uint8_t r_len) {
sw_iic.start();
sw_iic.send_byte(gt911_slave_address); // Set IIC Slave address
LOOP_L_N(i, reg_len) { // Set reg address
uint8_t r = (reg >> (8 * (reg_len - 1 - i))) & 0xFF;
sw_iic.send_byte(r);
}
sw_iic.start();
sw_iic.send_byte(gt911_slave_address + 1); // Set read mode
LOOP_L_N(i, r_len) {
r_data[i] = sw_iic.read_byte(1); // Read data from reg
}
sw_iic.stop();
}
void GT911::Init() {
OUT_WRITE(GT911_RST_PIN, LOW);
OUT_WRITE(GT911_INT_PIN, LOW);
delay(11);
WRITE(GT911_INT_PIN, HIGH);
delayMicroseconds(110);
WRITE(GT911_RST_PIN, HIGH);
delay(6);
WRITE(GT911_INT_PIN, LOW);
delay(55);
SET_INPUT(GT911_INT_PIN);
sw_iic.init();
uint8_t clear_reg = 0x00;
write_reg(0x814E, 2, &clear_reg, 1); // Reset to 0 for start
}
bool GT911::getFirstTouchPoint(int16_t *x, int16_t *y) {
read_reg(0x814E, 2, &reg.REG.status, 1);
if (reg.REG.status >= 0x80 && reg.REG.status <= 0x85) {
read_reg(0x8150, 2, reg.map + 2, 38);
uint8_t clear_reg = 0x00;
write_reg(0x814E, 2, &clear_reg, 1); // Reset to 0 for start
// First touch point
*x = ((reg.REG.point[0].xh & 0x0F) << 8) | reg.REG.point[0].xl;
*y = ((reg.REG.point[0].yh & 0x0F) << 8) | reg.REG.point[0].yl;
return true;
}
return false;
}
bool GT911::getPoint(int16_t *x, int16_t *y) {
static bool touched = 0;
static int16_t read_x = 0, read_y = 0;
static millis_t next_time = 0;
if (ELAPSED(millis(), next_time)) {
touched = getFirstTouchPoint(&read_x, &read_y);
next_time = millis() + 20;
}
*x = read_x;
*y = read_y;
return touched;
}
#endif // TFT_TOUCH_DEVICE_GT911
#endif // HAL_STM32

@ -0,0 +1,120 @@
/**
* 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 "../../../inc/MarlinConfig.h"
#define GT911_SLAVE_ADDRESS 0x28
#if !PIN_EXISTS(GT911_RST)
#error "GT911_RST_PIN is not defined."
#elif !PIN_EXISTS(GT911_INT)
#error "GT911_INT_PIN is not defined."
#elif !PIN_EXISTS(GT911_SW_I2C_SCL)
#error "GT911_SW_I2C_SCL_PIN is not defined."
#elif !PIN_EXISTS(GT911_SW_I2C_SDA)
#error "GT911_SW_I2C_SDA_PIN is not defined."
#endif
class SW_IIC {
private:
uint16_t scl_pin;
uint16_t sda_pin;
void write_scl(bool level)
{
WRITE(scl_pin, level);
}
void write_sda(bool level)
{
WRITE(sda_pin, level);
}
bool read_sda()
{
return READ(sda_pin);
}
void set_sda_out()
{
SET_OUTPUT(sda_pin);
}
void set_sda_in()
{
SET_INPUT_PULLUP(sda_pin);
}
static void iic_delay(uint8_t t)
{
delayMicroseconds(t);
}
public:
SW_IIC(uint16_t sda, uint16_t scl);
// setSCL/SDA have to be called before begin()
void setSCL(uint16_t scl)
{
scl_pin = scl;
};
void setSDA(uint16_t sda)
{
sda_pin = sda;
};
void init(); // Initialize the IO port of IIC
void start(); // Send IIC start signal
void stop(); // Send IIC stop signal
void send_byte(uint8_t txd); // IIC sends a byte
uint8_t read_byte(bool ack); // IIC reads a byte
void send_ack(bool ack); // IIC sends ACK or NACK signal
bool read_ack();
};
typedef struct __attribute__((__packed__)) {
uint8_t xl;
uint8_t xh;
uint8_t yl;
uint8_t yh;
uint8_t sizel;
uint8_t sizeh;
uint8_t reserved;
uint8_t track_id;
} GT911_POINT;
typedef union __attribute__((__packed__)) {
uint8_t map[42];
struct {
uint8_t status; // 0x814E
uint8_t track_id; // 0x814F
GT911_POINT point[5]; // [0]:0x8150 - 0x8157 / [1]:0x8158 - 0x815F / [2]:0x8160 - 0x8167 / [3]:0x8168 - 0x816F / [4]:0x8170 - 0x8177
} REG;
} GT911_REG_MAP;
class GT911 {
private:
static const uint8_t gt911_slave_address = GT911_SLAVE_ADDRESS;
static GT911_REG_MAP reg;
static SW_IIC sw_iic;
static void write_reg(uint16_t reg, uint8_t reg_len, uint8_t* w_data, uint8_t w_len);
static void read_reg(uint16_t reg, uint8_t reg_len, uint8_t* r_data, uint8_t r_len);
public:
static void Init();
static bool getFirstTouchPoint(int16_t *x, int16_t *y);
static bool getPoint(int16_t *x, int16_t *y);
};

@ -0,0 +1,174 @@
/**
* 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/>.
*
*/
#include "../../platforms.h"
#ifdef HAL_STM32
#include "../../../inc/MarlinConfig.h"
#if HAS_FSMC_TFT
#include "tft_fsmc.h"
#include "pinconfig.h"
SRAM_HandleTypeDef TFT_FSMC::SRAMx;
DMA_HandleTypeDef TFT_FSMC::DMAtx;
LCD_CONTROLLER_TypeDef *TFT_FSMC::LCD;
void TFT_FSMC::Init() {
uint32_t controllerAddress;
FSMC_NORSRAM_TimingTypeDef Timing, ExtTiming;
uint32_t NSBank = (uint32_t)pinmap_peripheral(digitalPinToPinName(TFT_CS_PIN), PinMap_FSMC_CS);
// Perform the SRAM1 memory initialization sequence
SRAMx.Instance = FSMC_NORSRAM_DEVICE;
SRAMx.Extended = FSMC_NORSRAM_EXTENDED_DEVICE;
// SRAMx.Init
SRAMx.Init.NSBank = NSBank;
SRAMx.Init.DataAddressMux = FSMC_DATA_ADDRESS_MUX_DISABLE;
SRAMx.Init.MemoryType = FSMC_MEMORY_TYPE_SRAM;
SRAMx.Init.MemoryDataWidth = TERN(TFT_INTERFACE_FSMC_8BIT, FSMC_NORSRAM_MEM_BUS_WIDTH_8, FSMC_NORSRAM_MEM_BUS_WIDTH_16);
SRAMx.Init.BurstAccessMode = FSMC_BURST_ACCESS_MODE_DISABLE;
SRAMx.Init.WaitSignalPolarity = FSMC_WAIT_SIGNAL_POLARITY_LOW;
SRAMx.Init.WrapMode = FSMC_WRAP_MODE_DISABLE;
SRAMx.Init.WaitSignalActive = FSMC_WAIT_TIMING_BEFORE_WS;
SRAMx.Init.WriteOperation = FSMC_WRITE_OPERATION_ENABLE;
SRAMx.Init.WaitSignal = FSMC_WAIT_SIGNAL_DISABLE;
SRAMx.Init.ExtendedMode = FSMC_EXTENDED_MODE_ENABLE;
SRAMx.Init.AsynchronousWait = FSMC_ASYNCHRONOUS_WAIT_DISABLE;
SRAMx.Init.WriteBurst = FSMC_WRITE_BURST_DISABLE;
#ifdef STM32F4xx
SRAMx.Init.PageSize = FSMC_PAGE_SIZE_NONE;
#endif
// Read Timing - relatively slow to ensure ID information is correctly read from TFT controller
// Can be decreases from 15-15-24 to 4-4-8 with risk of stability loss
Timing.AddressSetupTime = 15;
Timing.AddressHoldTime = 15;
Timing.DataSetupTime = 24;
Timing.BusTurnAroundDuration = 0;
Timing.CLKDivision = 16;
Timing.DataLatency = 17;
Timing.AccessMode = FSMC_ACCESS_MODE_A;
// Write Timing
// Can be decreases from 8-15-8 to 0-0-1 with risk of stability loss
ExtTiming.AddressSetupTime = 8;
ExtTiming.AddressHoldTime = 15;
ExtTiming.DataSetupTime = 8;
ExtTiming.BusTurnAroundDuration = 0;
ExtTiming.CLKDivision = 16;
ExtTiming.DataLatency = 17;
ExtTiming.AccessMode = FSMC_ACCESS_MODE_A;
__HAL_RCC_FSMC_CLK_ENABLE();
for (uint16_t i = 0; PinMap_FSMC[i].pin != NC; i++)
pinmap_pinout(PinMap_FSMC[i].pin, PinMap_FSMC);
pinmap_pinout(digitalPinToPinName(TFT_CS_PIN), PinMap_FSMC_CS);
pinmap_pinout(digitalPinToPinName(TFT_RS_PIN), PinMap_FSMC_RS);
controllerAddress = FSMC_BANK1_1;
#ifdef PF0
switch (NSBank) {
case FSMC_NORSRAM_BANK2: controllerAddress = FSMC_BANK1_2 ; break;
case FSMC_NORSRAM_BANK3: controllerAddress = FSMC_BANK1_3 ; break;
case FSMC_NORSRAM_BANK4: controllerAddress = FSMC_BANK1_4 ; break;
}
#endif
controllerAddress |= (uint32_t)pinmap_peripheral(digitalPinToPinName(TFT_RS_PIN), PinMap_FSMC_RS);
HAL_SRAM_Init(&SRAMx, &Timing, &ExtTiming);
__HAL_RCC_DMA2_CLK_ENABLE();
#ifdef STM32F1xx
DMAtx.Instance = DMA2_Channel1;
#elif defined(STM32F4xx)
DMAtx.Instance = DMA2_Stream0;
DMAtx.Init.Channel = DMA_CHANNEL_0;
DMAtx.Init.FIFOMode = DMA_FIFOMODE_ENABLE;
DMAtx.Init.FIFOThreshold = DMA_FIFO_THRESHOLD_FULL;
DMAtx.Init.MemBurst = DMA_MBURST_SINGLE;
DMAtx.Init.PeriphBurst = DMA_PBURST_SINGLE;
#endif
DMAtx.Init.Direction = DMA_MEMORY_TO_MEMORY;
DMAtx.Init.MemInc = DMA_MINC_DISABLE;
DMAtx.Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD;
DMAtx.Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD;
DMAtx.Init.Mode = DMA_NORMAL;
DMAtx.Init.Priority = DMA_PRIORITY_HIGH;
LCD = (LCD_CONTROLLER_TypeDef *)controllerAddress;
}
uint32_t TFT_FSMC::GetID() {
uint32_t id;
WriteReg(0);
id = LCD->RAM;
if (id == 0)
id = ReadID(LCD_READ_ID);
if ((id & 0xFFFF) == 0 || (id & 0xFFFF) == 0xFFFF)
id = ReadID(LCD_READ_ID4);
return id;
}
uint32_t TFT_FSMC::ReadID(tft_data_t Reg) {
uint32_t id;
WriteReg(Reg);
id = LCD->RAM; // dummy read
id = Reg << 24;
id |= (LCD->RAM & 0x00FF) << 16;
id |= (LCD->RAM & 0x00FF) << 8;
id |= LCD->RAM & 0x00FF;
return id;
}
bool TFT_FSMC::isBusy() {
#ifdef STM32F1xx
volatile bool dmaEnabled = (DMAtx.Instance->CCR & DMA_CCR_EN) != RESET;
#elif defined(STM32F4xx)
volatile bool dmaEnabled = DMAtx.Instance->CR & DMA_SxCR_EN;
#endif
if (dmaEnabled) {
if (__HAL_DMA_GET_FLAG(&DMAtx, __HAL_DMA_GET_TC_FLAG_INDEX(&DMAtx)) != 0 || __HAL_DMA_GET_FLAG(&DMAtx, __HAL_DMA_GET_TE_FLAG_INDEX(&DMAtx)) != 0)
Abort();
}
else
Abort();
return dmaEnabled;
}
void TFT_FSMC::TransmitDMA(uint32_t MemoryIncrease, uint16_t *Data, uint16_t Count) {
DMAtx.Init.PeriphInc = MemoryIncrease;
HAL_DMA_Init(&DMAtx);
DataTransferBegin();
HAL_DMA_Start(&DMAtx, (uint32_t)Data, (uint32_t)&(LCD->RAM), Count);
HAL_DMA_PollForTransfer(&DMAtx, HAL_DMA_FULL_TRANSFER, HAL_MAX_DELAY);
Abort();
}
#endif // HAS_FSMC_TFT
#endif // HAL_STM32

@ -0,0 +1,171 @@
/**
* 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/MarlinConfig.h"
#ifdef STM32F1xx
#include "stm32f1xx_hal.h"
#elif defined(STM32F4xx)
#include "stm32f4xx_hal.h"
#else
#error "FSMC TFT is currently only supported on STM32F1 and STM32F4 hardware."
#endif
#ifndef LCD_READ_ID
#define LCD_READ_ID 0x04 // Read display identification information (0xD3 on ILI9341)
#endif
#ifndef LCD_READ_ID4
#define LCD_READ_ID4 0xD3 // Read display identification information (0xD3 on ILI9341)
#endif
#define DATASIZE_8BIT SPI_DATASIZE_8BIT
#define DATASIZE_16BIT SPI_DATASIZE_16BIT
#define TFT_IO_DRIVER TFT_FSMC
#define TFT_DATASIZE TERN(TFT_INTERFACE_FSMC_8BIT, DATASIZE_8BIT, DATASIZE_16BIT)
typedef TERN(TFT_INTERFACE_FSMC_8BIT, uint8_t, uint16_t) tft_data_t;
typedef struct {
__IO tft_data_t REG;
__IO tft_data_t RAM;
} LCD_CONTROLLER_TypeDef;
class TFT_FSMC {
private:
static SRAM_HandleTypeDef SRAMx;
static DMA_HandleTypeDef DMAtx;
static LCD_CONTROLLER_TypeDef *LCD;
static uint32_t ReadID(tft_data_t Reg);
static void Transmit(tft_data_t Data) { LCD->RAM = Data; __DSB(); }
static void TransmitDMA(uint32_t MemoryIncrease, uint16_t *Data, uint16_t Count);
public:
static void Init();
static uint32_t GetID();
static bool isBusy();
static void Abort() { __HAL_DMA_DISABLE(&DMAtx); }
static void DataTransferBegin(uint16_t DataWidth = TFT_DATASIZE) {}
static void DataTransferEnd() {};
static void WriteData(uint16_t Data) { Transmit(tft_data_t(Data)); }
static void WriteReg(uint16_t Reg) { LCD->REG = tft_data_t(Reg); __DSB(); }
static void WriteSequence(uint16_t *Data, uint16_t Count) { TransmitDMA(DMA_PINC_ENABLE, Data, Count); }
static void WriteMultiple(uint16_t Color, uint16_t Count) { static uint16_t Data; Data = Color; TransmitDMA(DMA_PINC_DISABLE, &Data, Count); }
static void WriteMultiple(uint16_t Color, uint32_t Count) {
static uint16_t Data; Data = Color;
while (Count > 0) {
TransmitDMA(DMA_MINC_DISABLE, &Data, Count > 0xFFFF ? 0xFFFF : Count);
Count = Count > 0xFFFF ? Count - 0xFFFF : 0;
}
}
};
#ifdef STM32F1xx
#define FSMC_PIN_DATA STM_PIN_DATA(STM_MODE_AF_PP, GPIO_NOPULL, AFIO_NONE)
#elif defined(STM32F4xx)
#define FSMC_PIN_DATA STM_PIN_DATA(STM_MODE_AF_PP, GPIO_NOPULL, GPIO_AF12_FSMC)
#define FSMC_BANK1_1 0x60000000U
#define FSMC_BANK1_2 0x64000000U
#define FSMC_BANK1_3 0x68000000U
#define FSMC_BANK1_4 0x6C000000U
#else
#error No configuration for this MCU
#endif
const PinMap PinMap_FSMC[] = {
{PD_14, FSMC_NORSRAM_DEVICE, FSMC_PIN_DATA}, // FSMC_D00
{PD_15, FSMC_NORSRAM_DEVICE, FSMC_PIN_DATA}, // FSMC_D01
{PD_0, FSMC_NORSRAM_DEVICE, FSMC_PIN_DATA}, // FSMC_D02
{PD_1, FSMC_NORSRAM_DEVICE, FSMC_PIN_DATA}, // FSMC_D03
{PE_7, FSMC_NORSRAM_DEVICE, FSMC_PIN_DATA}, // FSMC_D04
{PE_8, FSMC_NORSRAM_DEVICE, FSMC_PIN_DATA}, // FSMC_D05
{PE_9, FSMC_NORSRAM_DEVICE, FSMC_PIN_DATA}, // FSMC_D06
{PE_10, FSMC_NORSRAM_DEVICE, FSMC_PIN_DATA}, // FSMC_D07
#if DISABLED(TFT_INTERFACE_FSMC_8BIT)
{PE_11, FSMC_NORSRAM_DEVICE, FSMC_PIN_DATA}, // FSMC_D08
{PE_12, FSMC_NORSRAM_DEVICE, FSMC_PIN_DATA}, // FSMC_D09
{PE_13, FSMC_NORSRAM_DEVICE, FSMC_PIN_DATA}, // FSMC_D10
{PE_14, FSMC_NORSRAM_DEVICE, FSMC_PIN_DATA}, // FSMC_D11
{PE_15, FSMC_NORSRAM_DEVICE, FSMC_PIN_DATA}, // FSMC_D12
{PD_8, FSMC_NORSRAM_DEVICE, FSMC_PIN_DATA}, // FSMC_D13
{PD_9, FSMC_NORSRAM_DEVICE, FSMC_PIN_DATA}, // FSMC_D14
{PD_10, FSMC_NORSRAM_DEVICE, FSMC_PIN_DATA}, // FSMC_D15
#endif
{PD_4, FSMC_NORSRAM_DEVICE, FSMC_PIN_DATA}, // FSMC_NOE
{PD_5, FSMC_NORSRAM_DEVICE, FSMC_PIN_DATA}, // FSMC_NWE
{NC, NP, 0}
};
const PinMap PinMap_FSMC_CS[] = {
{PD_7, (void *)FSMC_NORSRAM_BANK1, FSMC_PIN_DATA}, // FSMC_NE1
#ifdef PF0
{PG_9, (void *)FSMC_NORSRAM_BANK2, FSMC_PIN_DATA}, // FSMC_NE2
{PG_10, (void *)FSMC_NORSRAM_BANK3, FSMC_PIN_DATA}, // FSMC_NE3
{PG_12, (void *)FSMC_NORSRAM_BANK4, FSMC_PIN_DATA}, // FSMC_NE4
#endif
{NC, NP, 0}
};
#if ENABLED(TFT_INTERFACE_FSMC_8BIT)
#define FSMC_RS(A) (void *)((2 << (A-1)) - 1)
#else
#define FSMC_RS(A) (void *)((2 << A) - 2)
#endif
const PinMap PinMap_FSMC_RS[] = {
#ifdef PF0
{PF_0, FSMC_RS( 0), FSMC_PIN_DATA}, // FSMC_A0
{PF_1, FSMC_RS( 1), FSMC_PIN_DATA}, // FSMC_A1
{PF_2, FSMC_RS( 2), FSMC_PIN_DATA}, // FSMC_A2
{PF_3, FSMC_RS( 3), FSMC_PIN_DATA}, // FSMC_A3
{PF_4, FSMC_RS( 4), FSMC_PIN_DATA}, // FSMC_A4
{PF_5, FSMC_RS( 5), FSMC_PIN_DATA}, // FSMC_A5
{PF_12, FSMC_RS( 6), FSMC_PIN_DATA}, // FSMC_A6
{PF_13, FSMC_RS( 7), FSMC_PIN_DATA}, // FSMC_A7
{PF_14, FSMC_RS( 8), FSMC_PIN_DATA}, // FSMC_A8
{PF_15, FSMC_RS( 9), FSMC_PIN_DATA}, // FSMC_A9
{PG_0, FSMC_RS(10), FSMC_PIN_DATA}, // FSMC_A10
{PG_1, FSMC_RS(11), FSMC_PIN_DATA}, // FSMC_A11
{PG_2, FSMC_RS(12), FSMC_PIN_DATA}, // FSMC_A12
{PG_3, FSMC_RS(13), FSMC_PIN_DATA}, // FSMC_A13
{PG_4, FSMC_RS(14), FSMC_PIN_DATA}, // FSMC_A14
{PG_5, FSMC_RS(15), FSMC_PIN_DATA}, // FSMC_A15
#endif
{PD_11, FSMC_RS(16), FSMC_PIN_DATA}, // FSMC_A16
{PD_12, FSMC_RS(17), FSMC_PIN_DATA}, // FSMC_A17
{PD_13, FSMC_RS(18), FSMC_PIN_DATA}, // FSMC_A18
{PE_3, FSMC_RS(19), FSMC_PIN_DATA}, // FSMC_A19
{PE_4, FSMC_RS(20), FSMC_PIN_DATA}, // FSMC_A20
{PE_5, FSMC_RS(21), FSMC_PIN_DATA}, // FSMC_A21
{PE_6, FSMC_RS(22), FSMC_PIN_DATA}, // FSMC_A22
{PE_2, FSMC_RS(23), FSMC_PIN_DATA}, // FSMC_A23
#ifdef PF0
{PG_13, FSMC_RS(24), FSMC_PIN_DATA}, // FSMC_A24
{PG_14, FSMC_RS(25), FSMC_PIN_DATA}, // FSMC_A25
#endif
{NC, NP, 0}
};

@ -0,0 +1,389 @@
/**
* 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/>.
*
*/
#include "../../platforms.h"
#ifdef HAL_STM32
#include "../../../inc/MarlinConfig.h"
#if HAS_LTDC_TFT
#include "tft_ltdc.h"
#include "pinconfig.h"
#define FRAME_BUFFER_ADDRESS 0XC0000000 // SDRAM address
#define SDRAM_TIMEOUT ((uint32_t)0xFFFF)
#define REFRESH_COUNT ((uint32_t)0x02A5) // SDRAM refresh counter
#define SDRAM_MODEREG_BURST_LENGTH_1 ((uint16_t)0x0000)
#define SDRAM_MODEREG_BURST_LENGTH_2 ((uint16_t)0x0001)
#define SDRAM_MODEREG_BURST_LENGTH_4 ((uint16_t)0x0002)
#define SDRAM_MODEREG_BURST_LENGTH_8 ((uint16_t)0x0004)
#define SDRAM_MODEREG_BURST_TYPE_SEQUENTIAL ((uint16_t)0x0000)
#define SDRAM_MODEREG_BURST_TYPE_INTERLEAVED ((uint16_t)0x0008)
#define SDRAM_MODEREG_CAS_LATENCY_2 ((uint16_t)0x0020)
#define SDRAM_MODEREG_CAS_LATENCY_3 ((uint16_t)0x0030)
#define SDRAM_MODEREG_OPERATING_MODE_STANDARD ((uint16_t)0x0000)
#define SDRAM_MODEREG_WRITEBURST_MODE_PROGRAMMED ((uint16_t)0x0000)
#define SDRAM_MODEREG_WRITEBURST_MODE_SINGLE ((uint16_t)0x0200)
void SDRAM_Initialization_Sequence(SDRAM_HandleTypeDef *hsdram, FMC_SDRAM_CommandTypeDef *Command) {
__IO uint32_t tmpmrd =0;
/* Step 1: Configure a clock configuration enable command */
Command->CommandMode = FMC_SDRAM_CMD_CLK_ENABLE;
Command->CommandTarget = FMC_SDRAM_CMD_TARGET_BANK1;
Command->AutoRefreshNumber = 1;
Command->ModeRegisterDefinition = 0;
/* Send the command */
HAL_SDRAM_SendCommand(hsdram, Command, SDRAM_TIMEOUT);
/* Step 2: Insert 100 us minimum delay */
/* Inserted delay is equal to 1 ms due to systick time base unit (ms) */
HAL_Delay(1);
/* Step 3: Configure a PALL (precharge all) command */
Command->CommandMode = FMC_SDRAM_CMD_PALL;
Command->CommandTarget = FMC_SDRAM_CMD_TARGET_BANK1;
Command->AutoRefreshNumber = 1;
Command->ModeRegisterDefinition = 0;
/* Send the command */
HAL_SDRAM_SendCommand(hsdram, Command, SDRAM_TIMEOUT);
/* Step 4 : Configure a Auto-Refresh command */
Command->CommandMode = FMC_SDRAM_CMD_AUTOREFRESH_MODE;
Command->CommandTarget = FMC_SDRAM_CMD_TARGET_BANK1;
Command->AutoRefreshNumber = 8;
Command->ModeRegisterDefinition = 0;
/* Send the command */
HAL_SDRAM_SendCommand(hsdram, Command, SDRAM_TIMEOUT);
/* Step 5: Program the external memory mode register */
tmpmrd = (uint32_t)(SDRAM_MODEREG_BURST_LENGTH_1 |
SDRAM_MODEREG_BURST_TYPE_SEQUENTIAL |
SDRAM_MODEREG_CAS_LATENCY_2 |
SDRAM_MODEREG_OPERATING_MODE_STANDARD |
SDRAM_MODEREG_WRITEBURST_MODE_SINGLE);
Command->CommandMode = FMC_SDRAM_CMD_LOAD_MODE;
Command->CommandTarget = FMC_SDRAM_CMD_TARGET_BANK1;
Command->AutoRefreshNumber = 1;
Command->ModeRegisterDefinition = tmpmrd;
/* Send the command */
HAL_SDRAM_SendCommand(hsdram, Command, SDRAM_TIMEOUT);
/* Step 6: Set the refresh rate counter */
/* Set the device refresh rate */
HAL_SDRAM_ProgramRefreshRate(hsdram, REFRESH_COUNT);
}
void SDRAM_Config() {
__HAL_RCC_SYSCFG_CLK_ENABLE();
__HAL_RCC_FMC_CLK_ENABLE();
SDRAM_HandleTypeDef hsdram;
FMC_SDRAM_TimingTypeDef SDRAM_Timing;
FMC_SDRAM_CommandTypeDef command;
/* Configure the SDRAM device */
hsdram.Instance = FMC_SDRAM_DEVICE;
hsdram.Init.SDBank = FMC_SDRAM_BANK1;
hsdram.Init.ColumnBitsNumber = FMC_SDRAM_COLUMN_BITS_NUM_9;
hsdram.Init.RowBitsNumber = FMC_SDRAM_ROW_BITS_NUM_13;
hsdram.Init.MemoryDataWidth = FMC_SDRAM_MEM_BUS_WIDTH_16;
hsdram.Init.InternalBankNumber = FMC_SDRAM_INTERN_BANKS_NUM_4;
hsdram.Init.CASLatency = FMC_SDRAM_CAS_LATENCY_2;
hsdram.Init.WriteProtection = FMC_SDRAM_WRITE_PROTECTION_DISABLE;
hsdram.Init.SDClockPeriod = FMC_SDRAM_CLOCK_PERIOD_2;
hsdram.Init.ReadBurst = FMC_SDRAM_RBURST_ENABLE;
hsdram.Init.ReadPipeDelay = FMC_SDRAM_RPIPE_DELAY_0;
/* Timing configuration for 100Mhz as SDRAM clock frequency (System clock is up to 200Mhz) */
SDRAM_Timing.LoadToActiveDelay = 2;
SDRAM_Timing.ExitSelfRefreshDelay = 8;
SDRAM_Timing.SelfRefreshTime = 6;
SDRAM_Timing.RowCycleDelay = 6;
SDRAM_Timing.WriteRecoveryTime = 2;
SDRAM_Timing.RPDelay = 2;
SDRAM_Timing.RCDDelay = 2;
/* Initialize the SDRAM controller */
if (HAL_SDRAM_Init(&hsdram, &SDRAM_Timing) != HAL_OK)
{
/* Initialization Error */
}
/* Program the SDRAM external device */
SDRAM_Initialization_Sequence(&hsdram, &command);
}
void LTDC_Config() {
__HAL_RCC_LTDC_CLK_ENABLE();
__HAL_RCC_DMA2D_CLK_ENABLE();
RCC_PeriphCLKInitTypeDef PeriphClkInitStruct;
/* The PLL3R is configured to provide the LTDC PCLK clock */
/* PLL3_VCO Input = HSE_VALUE / PLL3M = 25Mhz / 5 = 5 Mhz */
/* PLL3_VCO Output = PLL3_VCO Input * PLL3N = 5Mhz * 160 = 800 Mhz */
/* PLLLCDCLK = PLL3_VCO Output/PLL3R = 800Mhz / 16 = 50Mhz */
/* LTDC clock frequency = PLLLCDCLK = 50 Mhz */
PeriphClkInitStruct.PeriphClockSelection = RCC_PERIPHCLK_LTDC;
PeriphClkInitStruct.PLL3.PLL3M = 5;
PeriphClkInitStruct.PLL3.PLL3N = 160;
PeriphClkInitStruct.PLL3.PLL3FRACN = 0;
PeriphClkInitStruct.PLL3.PLL3P = 2;
PeriphClkInitStruct.PLL3.PLL3Q = 2;
PeriphClkInitStruct.PLL3.PLL3R = (800 / LTDC_LCD_CLK);
PeriphClkInitStruct.PLL3.PLL3VCOSEL = RCC_PLL3VCOWIDE;
PeriphClkInitStruct.PLL3.PLL3RGE = RCC_PLL3VCIRANGE_2;
HAL_RCCEx_PeriphCLKConfig(&PeriphClkInitStruct);
LTDC_HandleTypeDef hltdc_F;
LTDC_LayerCfgTypeDef pLayerCfg;
/* LTDC Initialization -------------------------------------------------------*/
/* Polarity configuration */
/* Initialize the horizontal synchronization polarity as active low */
hltdc_F.Init.HSPolarity = LTDC_HSPOLARITY_AL;
/* Initialize the vertical synchronization polarity as active low */
hltdc_F.Init.VSPolarity = LTDC_VSPOLARITY_AL;
/* Initialize the data enable polarity as active low */
hltdc_F.Init.DEPolarity = LTDC_DEPOLARITY_AL;
/* Initialize the pixel clock polarity as input pixel clock */
hltdc_F.Init.PCPolarity = LTDC_PCPOLARITY_IPC;
/* Timing configuration */
hltdc_F.Init.HorizontalSync = (LTDC_LCD_HSYNC - 1);
hltdc_F.Init.VerticalSync = (LTDC_LCD_VSYNC - 1);
hltdc_F.Init.AccumulatedHBP = (LTDC_LCD_HSYNC + LTDC_LCD_HBP - 1);
hltdc_F.Init.AccumulatedVBP = (LTDC_LCD_VSYNC + LTDC_LCD_VBP - 1);
hltdc_F.Init.AccumulatedActiveH = (TFT_HEIGHT + LTDC_LCD_VSYNC + LTDC_LCD_VBP - 1);
hltdc_F.Init.AccumulatedActiveW = (TFT_WIDTH + LTDC_LCD_HSYNC + LTDC_LCD_HBP - 1);
hltdc_F.Init.TotalHeigh = (TFT_HEIGHT + LTDC_LCD_VSYNC + LTDC_LCD_VBP + LTDC_LCD_VFP - 1);
hltdc_F.Init.TotalWidth = (TFT_WIDTH + LTDC_LCD_HSYNC + LTDC_LCD_HBP + LTDC_LCD_HFP - 1);
/* Configure R,G,B component values for LCD background color : all black background */
hltdc_F.Init.Backcolor.Blue = 0;
hltdc_F.Init.Backcolor.Green = 0;
hltdc_F.Init.Backcolor.Red = 0;
hltdc_F.Instance = LTDC;
/* Layer0 Configuration ------------------------------------------------------*/
/* Windowing configuration */
pLayerCfg.WindowX0 = 0;
pLayerCfg.WindowX1 = TFT_WIDTH;
pLayerCfg.WindowY0 = 0;
pLayerCfg.WindowY1 = TFT_HEIGHT;
/* Pixel Format configuration*/
pLayerCfg.PixelFormat = LTDC_PIXEL_FORMAT_RGB565;
/* Start Address configuration : frame buffer is located at SDRAM memory */
pLayerCfg.FBStartAdress = (uint32_t)(FRAME_BUFFER_ADDRESS);
/* Alpha constant (255 == totally opaque) */
pLayerCfg.Alpha = 255;
/* Default Color configuration (configure A,R,G,B component values) : no background color */
pLayerCfg.Alpha0 = 0; /* fully transparent */
pLayerCfg.Backcolor.Blue = 0;
pLayerCfg.Backcolor.Green = 0;
pLayerCfg.Backcolor.Red = 0;
/* Configure blending factors */
pLayerCfg.BlendingFactor1 = LTDC_BLENDING_FACTOR1_CA;
pLayerCfg.BlendingFactor2 = LTDC_BLENDING_FACTOR2_CA;
/* Configure the number of lines and number of pixels per line */
pLayerCfg.ImageWidth = TFT_WIDTH;
pLayerCfg.ImageHeight = TFT_HEIGHT;
/* Configure the LTDC */
if (HAL_LTDC_Init(&hltdc_F) != HAL_OK)
{
/* Initialization Error */
}
/* Configure the Layer*/
if (HAL_LTDC_ConfigLayer(&hltdc_F, &pLayerCfg, 0) != HAL_OK)
{
/* Initialization Error */
}
}
uint16_t TFT_LTDC::x_min = 0;
uint16_t TFT_LTDC::x_max = 0;
uint16_t TFT_LTDC::y_min = 0;
uint16_t TFT_LTDC::y_max = 0;
uint16_t TFT_LTDC::x_cur = 0;
uint16_t TFT_LTDC::y_cur = 0;
uint8_t TFT_LTDC::reg = 0;
volatile uint16_t* TFT_LTDC::framebuffer = (volatile uint16_t* )FRAME_BUFFER_ADDRESS;
void TFT_LTDC::Init() {
// SDRAM pins init
for (uint16_t i = 0; PinMap_SDRAM[i].pin != NC; i++)
pinmap_pinout(PinMap_SDRAM[i].pin, PinMap_SDRAM);
// SDRAM peripheral config
SDRAM_Config();
// LTDC pins init
for (uint16_t i = 0; PinMap_LTDC[i].pin != NC; i++)
pinmap_pinout(PinMap_LTDC[i].pin, PinMap_LTDC);
// LTDC peripheral config
LTDC_Config();
}
uint32_t TFT_LTDC::GetID() {
return 0xABAB;
}
uint32_t TFT_LTDC::ReadID(tft_data_t Reg) {
return 0xABAB;
}
bool TFT_LTDC::isBusy() {
return false;
}
uint16_t TFT_LTDC::ReadPoint(uint16_t x, uint16_t y) {
return framebuffer[(TFT_WIDTH * y) + x];
}
void TFT_LTDC::DrawPoint(uint16_t x, uint16_t y, uint16_t color) {
framebuffer[(TFT_WIDTH * y) + x] = color;
}
void TFT_LTDC::DrawRect(uint16_t sx, uint16_t sy, uint16_t ex, uint16_t ey, uint16_t color) {
if (sx == ex || sy == ey) return;
uint16_t offline = TFT_WIDTH - (ex - sx);
uint32_t addr = (uint32_t)&framebuffer[(TFT_WIDTH * sy) + sx];
CBI(DMA2D->CR, 0);
DMA2D->CR = 3 << 16;
DMA2D->OPFCCR = 0X02;
DMA2D->OOR = offline;
DMA2D->OMAR = addr;
DMA2D->NLR = (ey - sy) | ((ex - sx) << 16);
DMA2D->OCOLR = color;
SBI(DMA2D->CR, 0);
uint32_t timeout = 0;
while (!TEST(DMA2D->ISR, 1)) {
timeout++;
if (timeout > 0x1FFFFF) break;
}
SBI(DMA2D->IFCR, 1);
}
void TFT_LTDC::DrawImage(uint16_t sx, uint16_t sy, uint16_t ex, uint16_t ey, uint16_t *colors) {
if (sx == ex || sy == ey) return;
uint16_t offline = TFT_WIDTH - (ex - sx);
uint32_t addr = (uint32_t)&framebuffer[(TFT_WIDTH * sy) + sx];
CBI(DMA2D->CR, 0);
DMA2D->CR = 0 << 16;
DMA2D->FGPFCCR = 0X02;
DMA2D->FGOR = 0;
DMA2D->OOR = offline;
DMA2D->FGMAR = (uint32_t)colors;
DMA2D->OMAR = addr;
DMA2D->NLR = (ey - sy) | ((ex - sx) << 16);
SBI(DMA2D->CR, 0);
uint32_t timeout = 0;
while (!TEST(DMA2D->ISR, 1)) {
timeout++;
if (timeout > 0x1FFFFF) break;
}
SBI(DMA2D->IFCR, 1);
}
void TFT_LTDC::WriteData(uint16_t data) {
switch (reg) {
case 0x01: x_cur = x_min = data; return;
case 0x02: x_max = data; return;
case 0x03: y_cur = y_min = data; return;
case 0x04: y_max = data; return;
}
Transmit(data);
}
void TFT_LTDC::Transmit(tft_data_t Data) {
DrawPoint(x_cur, y_cur, Data);
x_cur++;
if (x_cur > x_max) {
x_cur = x_min;
y_cur++;
if (y_cur > y_max) y_cur = y_min;
}
}
void TFT_LTDC::WriteReg(uint16_t Reg) {
reg = Reg;
}
void TFT_LTDC::TransmitDMA(uint32_t MemoryIncrease, uint16_t *Data, uint16_t Count) {
while (x_cur != x_min && Count) {
Transmit(*Data);
if (MemoryIncrease == DMA_PINC_ENABLE) Data++;
Count--;
}
uint16_t width = x_max - x_min + 1;
uint16_t height = Count / width;
uint16_t x_end_cnt = Count - (width * height);
if (height) {
if (MemoryIncrease == DMA_PINC_ENABLE) {
DrawImage(x_min, y_cur, x_min + width, y_cur + height, Data);
Data += width * height;
}
else
DrawRect(x_min, y_cur, x_min + width, y_cur + height, *Data);
y_cur += height;
}
while (x_end_cnt) {
Transmit(*Data);
if (MemoryIncrease == DMA_PINC_ENABLE) Data++;
x_end_cnt--;
}
}
#endif // HAS_LTDC_TFT
#endif // HAL_STM32

@ -0,0 +1,155 @@
/**
* 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 "../../../inc/MarlinConfig.h"
#ifdef STM32H7xx
#include "stm32h7xx_hal.h"
#else
#error "LTDC TFT is currently only supported on STM32H7 hardware."
#endif
#define DATASIZE_8BIT SPI_DATASIZE_8BIT
#define DATASIZE_16BIT SPI_DATASIZE_16BIT
#define TFT_IO_DRIVER TFT_LTDC
#define TFT_DATASIZE DATASIZE_16BIT
typedef uint16_t tft_data_t;
class TFT_LTDC {
private:
static volatile uint16_t *framebuffer;
static uint16_t x_min, x_max, y_min, y_max, x_cur, y_cur;
static uint8_t reg;
static uint32_t ReadID(tft_data_t Reg);
static uint16_t ReadPoint(uint16_t x, uint16_t y);
static void DrawPoint(uint16_t x, uint16_t y, uint16_t color);
static void DrawRect(uint16_t sx, uint16_t sy, uint16_t ex, uint16_t ey, uint16_t color);
static void DrawImage(uint16_t sx, uint16_t sy, uint16_t ex, uint16_t ey, uint16_t *colors);
static void Transmit(tft_data_t Data);
static void TransmitDMA(uint32_t MemoryIncrease, uint16_t *Data, uint16_t Count);
public:
static void Init();
static uint32_t GetID();
static bool isBusy();
static void Abort() { /*__HAL_DMA_DISABLE(&DMAtx);*/ }
static void DataTransferBegin(uint16_t DataWidth = TFT_DATASIZE) {}
static void DataTransferEnd() {};
static void WriteData(uint16_t Data);
static void WriteReg(uint16_t Reg);
static void WriteSequence(uint16_t *Data, uint16_t Count) { TransmitDMA(DMA_PINC_ENABLE, Data, Count); }
static void WriteMultiple(uint16_t Color, uint16_t Count) { static uint16_t Data; Data = Color; TransmitDMA(DMA_PINC_DISABLE, &Data, Count); }
static void WriteMultiple(uint16_t Color, uint32_t Count) {
static uint16_t Data; Data = Color;
while (Count > 0) {
TransmitDMA(DMA_MINC_DISABLE, &Data, Count > 0xFFFF ? 0xFFFF : Count);
Count = Count > 0xFFFF ? Count - 0xFFFF : 0;
}
}
};
const PinMap PinMap_LTDC[] = {
{PF_10, LTDC, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF14_LTDC)}, // LCD_DE
{PG_7, LTDC, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF14_LTDC)}, // LCD_CLK
{PI_9, LTDC, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF14_LTDC)}, // LCD_VSYNC
{PI_10, LTDC, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF14_LTDC)}, // LCD_HSYNC
{PG_6, LTDC, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF14_LTDC)}, // LCD_R7
{PH_12, LTDC, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF14_LTDC)}, // LCD_R6
{PH_11, LTDC, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF14_LTDC)}, // LCD_R5
{PH_10, LTDC, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF14_LTDC)}, // LCD_R4
{PH_9, LTDC, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF14_LTDC)}, // LCD_R3
{PI_2, LTDC, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF14_LTDC)}, // LCD_G7
{PI_1, LTDC, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF14_LTDC)}, // LCD_G6
{PI_0, LTDC, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF14_LTDC)}, // LCD_G5
{PH_15, LTDC, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF14_LTDC)}, // LCD_G4
{PH_14, LTDC, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF14_LTDC)}, // LCD_G3
{PH_13, LTDC, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF14_LTDC)}, // LCD_G2
{PI_7, LTDC, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF14_LTDC)}, // LCD_B7
{PI_6, LTDC, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF14_LTDC)}, // LCD_B6
{PI_5, LTDC, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF14_LTDC)}, // LCD_B5
{PI_4, LTDC, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF14_LTDC)}, // LCD_B4
{PG_11, LTDC, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF14_LTDC)}, // LCD_B3
{NC, NP, 0}
};
const PinMap PinMap_SDRAM[] = {
{PC_0, FMC_Bank1_R, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF12_FMC)}, // FMC_SDNWE
{PC_2, FMC_Bank1_R, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF12_FMC)}, // FMC_SDNE0
{PC_3, FMC_Bank1_R, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF12_FMC)}, // FMC_SDCKE0
{PE_0, FMC_Bank1_R, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF12_FMC)}, // FMC_NBL0
{PE_1, FMC_Bank1_R, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF12_FMC)}, // FMC_NBL1
{PF_11, FMC_Bank1_R, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF12_FMC)}, // FMC_SDNRAS
{PG_8, FMC_Bank1_R, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF12_FMC)}, // FMC_SDCLK
{PG_15, FMC_Bank1_R, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF12_FMC)}, // FMC_SDNCAS
{PG_4, FMC_Bank1_R, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF12_FMC)}, // FMC_BA0
{PG_5, FMC_Bank1_R, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF12_FMC)}, // FMC_BA1
{PD_14, FMC_Bank1_R, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF12_FMC)}, // FMC_D0
{PD_15, FMC_Bank1_R, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF12_FMC)}, // FMC_D1
{PD_0, FMC_Bank1_R, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF12_FMC)}, // FMC_D2
{PD_1, FMC_Bank1_R, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF12_FMC)}, // FMC_D3
{PE_7, FMC_Bank1_R, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF12_FMC)}, // FMC_D4
{PE_8, FMC_Bank1_R, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF12_FMC)}, // FMC_D5
{PE_9, FMC_Bank1_R, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF12_FMC)}, // FMC_D6
{PE_10, FMC_Bank1_R, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF12_FMC)}, // FMC_D7
{PE_11, FMC_Bank1_R, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF12_FMC)}, // FMC_D8
{PE_12, FMC_Bank1_R, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF12_FMC)}, // FMC_D9
{PE_13, FMC_Bank1_R, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF12_FMC)}, // FMC_D10
{PE_14, FMC_Bank1_R, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF12_FMC)}, // FMC_D11
{PE_15, FMC_Bank1_R, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF12_FMC)}, // FMC_D12
{PD_8, FMC_Bank1_R, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF12_FMC)}, // FMC_D13
{PD_9, FMC_Bank1_R, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF12_FMC)}, // FMC_D14
{PD_10, FMC_Bank1_R, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF12_FMC)}, // FMC_D15
{PF_0, FMC_Bank1_R, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF12_FMC)}, // FMC_A0
{PF_1, FMC_Bank1_R, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF12_FMC)}, // FMC_A1
{PF_2, FMC_Bank1_R, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF12_FMC)}, // FMC_A2
{PF_3, FMC_Bank1_R, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF12_FMC)}, // FMC_A3
{PF_4, FMC_Bank1_R, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF12_FMC)}, // FMC_A4
{PF_5, FMC_Bank1_R, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF12_FMC)}, // FMC_A5
{PF_12, FMC_Bank1_R, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF12_FMC)}, // FMC_A6
{PF_13, FMC_Bank1_R, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF12_FMC)}, // FMC_A7
{PF_14, FMC_Bank1_R, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF12_FMC)}, // FMC_A8
{PF_15, FMC_Bank1_R, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF12_FMC)}, // FMC_A9
{PG_0, FMC_Bank1_R, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF12_FMC)}, // FMC_A10
{PG_1, FMC_Bank1_R, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF12_FMC)}, // FMC_A11
{PG_2, FMC_Bank1_R, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF12_FMC)}, // FMC_A12
{NC, NP, 0}
};
const PinMap PinMap_QUADSPI[] = {
{PB_2, QUADSPI, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF9_QUADSPI)}, // QUADSPI_CLK
{PB_10, QUADSPI, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF9_QUADSPI)}, // QUADSPI_BK1_NCS
{PF_6, QUADSPI, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF9_QUADSPI)}, // QUADSPI_BK1_IO3
{PF_7, QUADSPI, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF9_QUADSPI)}, // QUADSPI_BK1_IO2
{PF_8, QUADSPI, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF10_QUADSPI)}, // QUADSPI_BK1_IO0
{PF_9, QUADSPI, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF10_QUADSPI)}, // QUADSPI_BK1_IO1
{NC, NP, 0}
};

@ -0,0 +1,270 @@
/**
* 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/>.
*
*/
#include "../../platforms.h"
#ifdef HAL_STM32
#include "../../../inc/MarlinConfig.h"
#if HAS_SPI_TFT
#include "tft_spi.h"
#include "pinconfig.h"
SPI_HandleTypeDef TFT_SPI::SPIx;
DMA_HandleTypeDef TFT_SPI::DMAtx;
void TFT_SPI::Init() {
SPI_TypeDef *spiInstance;
OUT_WRITE(TFT_A0_PIN, HIGH);
OUT_WRITE(TFT_CS_PIN, HIGH);
if ((spiInstance = (SPI_TypeDef *)pinmap_peripheral(digitalPinToPinName(TFT_SCK_PIN), PinMap_SPI_SCLK)) == NP) return;
if (spiInstance != (SPI_TypeDef *)pinmap_peripheral(digitalPinToPinName(TFT_MOSI_PIN), PinMap_SPI_MOSI)) return;
#if PIN_EXISTS(TFT_MISO) && TFT_MISO_PIN != TFT_MOSI_PIN
if (spiInstance != (SPI_TypeDef *)pinmap_peripheral(digitalPinToPinName(TFT_MISO_PIN), PinMap_SPI_MISO)) return;
#endif
SPIx.Instance = spiInstance;
SPIx.State = HAL_SPI_STATE_RESET;
SPIx.Init.NSS = SPI_NSS_SOFT;
SPIx.Init.Mode = SPI_MODE_MASTER;
SPIx.Init.Direction = (TFT_MISO_PIN == TFT_MOSI_PIN) ? SPI_DIRECTION_1LINE : SPI_DIRECTION_2LINES;
SPIx.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_2;
SPIx.Init.CLKPhase = SPI_PHASE_1EDGE;
SPIx.Init.CLKPolarity = SPI_POLARITY_LOW;
SPIx.Init.DataSize = SPI_DATASIZE_8BIT;
SPIx.Init.FirstBit = SPI_FIRSTBIT_MSB;
SPIx.Init.TIMode = SPI_TIMODE_DISABLE;
SPIx.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;
SPIx.Init.CRCPolynomial = 10;
pinmap_pinout(digitalPinToPinName(TFT_SCK_PIN), PinMap_SPI_SCLK);
pinmap_pinout(digitalPinToPinName(TFT_MOSI_PIN), PinMap_SPI_MOSI);
#if PIN_EXISTS(TFT_MISO) && TFT_MISO_PIN != TFT_MOSI_PIN
pinmap_pinout(digitalPinToPinName(TFT_MISO_PIN), PinMap_SPI_MISO);
#endif
pin_PullConfig(get_GPIO_Port(STM_PORT(digitalPinToPinName(TFT_SCK_PIN))), STM_LL_GPIO_PIN(digitalPinToPinName(TFT_SCK_PIN)), GPIO_PULLDOWN);
#ifdef SPI1_BASE
if (SPIx.Instance == SPI1) {
__HAL_RCC_SPI1_CLK_ENABLE();
#ifdef STM32F1xx
__HAL_RCC_DMA1_CLK_ENABLE();
DMAtx.Instance = DMA1_Channel3;
#elif defined(STM32F4xx)
__HAL_RCC_DMA2_CLK_ENABLE();
DMAtx.Instance = DMA2_Stream3;
DMAtx.Init.Channel = DMA_CHANNEL_3;
#endif
SPIx.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_4;
}
#endif
#ifdef SPI2_BASE
if (SPIx.Instance == SPI2) {
__HAL_RCC_SPI2_CLK_ENABLE();
#ifdef STM32F1xx
__HAL_RCC_DMA1_CLK_ENABLE();
DMAtx.Instance = DMA1_Channel5;
#elif defined(STM32F4xx)
__HAL_RCC_DMA1_CLK_ENABLE();
DMAtx.Instance = DMA1_Stream4;
DMAtx.Init.Channel = DMA_CHANNEL_0;
#endif
}
#endif
#ifdef SPI3_BASE
if (SPIx.Instance == SPI3) {
__HAL_RCC_SPI3_CLK_ENABLE();
#ifdef STM32F1xx
__HAL_RCC_DMA2_CLK_ENABLE();
DMAtx.Instance = DMA2_Channel2;
#elif defined(STM32F4xx)
__HAL_RCC_DMA1_CLK_ENABLE();
DMAtx.Instance = DMA1_Stream5;
DMAtx.Init.Channel = DMA_CHANNEL_0;
#endif
}
#endif
HAL_SPI_Init(&SPIx);
DMAtx.Init.Direction = DMA_MEMORY_TO_PERIPH;
DMAtx.Init.PeriphInc = DMA_PINC_DISABLE;
DMAtx.Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD;
DMAtx.Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD;
DMAtx.Init.Mode = DMA_NORMAL;
DMAtx.Init.Priority = DMA_PRIORITY_LOW;
#ifdef STM32F4xx
DMAtx.Init.FIFOMode = DMA_FIFOMODE_DISABLE;
#endif
}
void TFT_SPI::DataTransferBegin(uint16_t DataSize) {
SPIx.Init.DataSize = DataSize == DATASIZE_8BIT ? SPI_DATASIZE_8BIT : SPI_DATASIZE_16BIT;
HAL_SPI_Init(&SPIx);
WRITE(TFT_CS_PIN, LOW);
}
#ifdef TFT_DEFAULT_DRIVER
#include "../../../lcd/tft_io/tft_ids.h"
#endif
uint32_t TFT_SPI::GetID() {
uint32_t id;
id = ReadID(LCD_READ_ID);
if ((id & 0xFFFF) == 0 || (id & 0xFFFF) == 0xFFFF) {
id = ReadID(LCD_READ_ID4);
#ifdef TFT_DEFAULT_DRIVER
if ((id & 0xFFFF) == 0 || (id & 0xFFFF) == 0xFFFF)
id = TFT_DEFAULT_DRIVER;
#endif
}
return id;
}
uint32_t TFT_SPI::ReadID(uint16_t Reg) {
uint32_t Data = 0;
#if PIN_EXISTS(TFT_MISO)
uint32_t BaudRatePrescaler = SPIx.Init.BaudRatePrescaler;
uint32_t i;
SPIx.Init.BaudRatePrescaler = SPIx.Instance == SPI1 ? SPI_BAUDRATEPRESCALER_8 : SPI_BAUDRATEPRESCALER_4;
DataTransferBegin(DATASIZE_8BIT);
WriteReg(Reg);
if (SPIx.Init.Direction == SPI_DIRECTION_1LINE) SPI_1LINE_RX(&SPIx);
__HAL_SPI_ENABLE(&SPIx);
for (i = 0; i < 4; i++) {
#if TFT_MISO_PIN != TFT_MOSI_PIN
//if (hspi->Init.Direction == SPI_DIRECTION_2LINES) {
while (!__HAL_SPI_GET_FLAG(&SPIx, SPI_FLAG_TXE)) {}
SPIx.Instance->DR = 0;
//}
#endif
while (!__HAL_SPI_GET_FLAG(&SPIx, SPI_FLAG_RXNE)) {}
Data = (Data << 8) | SPIx.Instance->DR;
}
__HAL_SPI_DISABLE(&SPIx);
DataTransferEnd();
SPIx.Init.BaudRatePrescaler = BaudRatePrescaler;
#endif
return Data >> 7;
}
bool TFT_SPI::isBusy() {
#ifdef STM32F1xx
volatile bool dmaEnabled = (DMAtx.Instance->CCR & DMA_CCR_EN) != RESET;
#elif defined(STM32F4xx)
volatile bool dmaEnabled = DMAtx.Instance->CR & DMA_SxCR_EN;
#endif
if (dmaEnabled) {
if (__HAL_DMA_GET_FLAG(&DMAtx, __HAL_DMA_GET_TC_FLAG_INDEX(&DMAtx)) != 0 || __HAL_DMA_GET_FLAG(&DMAtx, __HAL_DMA_GET_TE_FLAG_INDEX(&DMAtx)) != 0)
Abort();
}
else
Abort();
return dmaEnabled;
}
void TFT_SPI::Abort() {
// Wait for any running spi
while (!__HAL_SPI_GET_FLAG(&SPIx, SPI_FLAG_TXE)) {}
while ( __HAL_SPI_GET_FLAG(&SPIx, SPI_FLAG_BSY)) {}
// First, abort any running dma
HAL_DMA_Abort(&DMAtx);
// DeInit objects
HAL_DMA_DeInit(&DMAtx);
HAL_SPI_DeInit(&SPIx);
// Deselect CS
DataTransferEnd();
}
void TFT_SPI::Transmit(uint16_t Data) {
if (TFT_MISO_PIN == TFT_MOSI_PIN)
SPI_1LINE_TX(&SPIx);
__HAL_SPI_ENABLE(&SPIx);
SPIx.Instance->DR = Data;
while (!__HAL_SPI_GET_FLAG(&SPIx, SPI_FLAG_TXE)) {}
while ( __HAL_SPI_GET_FLAG(&SPIx, SPI_FLAG_BSY)) {}
if (TFT_MISO_PIN != TFT_MOSI_PIN)
__HAL_SPI_CLEAR_OVRFLAG(&SPIx); // Clear overrun flag in 2 Lines communication mode because received is not read
}
void TFT_SPI::TransmitDMA(uint32_t MemoryIncrease, uint16_t *Data, uint16_t Count) {
// Wait last dma finish, to start another
while (isBusy()) { /* nada */ }
DMAtx.Init.MemInc = MemoryIncrease;
HAL_DMA_Init(&DMAtx);
if (TFT_MISO_PIN == TFT_MOSI_PIN)
SPI_1LINE_TX(&SPIx);
DataTransferBegin();
HAL_DMA_Start(&DMAtx, (uint32_t)Data, (uint32_t)&(SPIx.Instance->DR), Count);
__HAL_SPI_ENABLE(&SPIx);
SET_BIT(SPIx.Instance->CR2, SPI_CR2_TXDMAEN); // Enable Tx DMA Request
HAL_DMA_PollForTransfer(&DMAtx, HAL_DMA_FULL_TRANSFER, HAL_MAX_DELAY);
Abort();
}
#if ENABLED(USE_SPI_DMA_TC)
void TFT_SPI::TransmitDMA_IT(uint32_t MemoryIncrease, uint16_t *Data, uint16_t Count) {
DMAtx.Init.MemInc = MemoryIncrease;
HAL_DMA_Init(&DMAtx);
if (TFT_MISO_PIN == TFT_MOSI_PIN)
SPI_1LINE_TX(&SPIx);
DataTransferBegin();
HAL_NVIC_SetPriority(DMA2_Stream3_IRQn, 5, 0);
HAL_NVIC_EnableIRQ(DMA2_Stream3_IRQn);
HAL_DMA_Start_IT(&DMAtx, (uint32_t)Data, (uint32_t)&(SPIx.Instance->DR), Count);
__HAL_SPI_ENABLE(&SPIx);
SET_BIT(SPIx.Instance->CR2, SPI_CR2_TXDMAEN); // Enable Tx DMA Request
}
extern "C" void DMA2_Stream3_IRQHandler(void) { HAL_DMA_IRQHandler(&TFT_SPI::DMAtx); }
#endif
#endif // HAS_SPI_TFT
#endif // HAL_STM32

@ -0,0 +1,84 @@
/**
* 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
#ifdef STM32F1xx
#include "stm32f1xx_hal.h"
#elif defined(STM32F4xx)
#include "stm32f4xx_hal.h"
#else
#error SPI TFT is currently only supported on STM32F1 and STM32F4 hardware.
#endif
#ifndef LCD_READ_ID
#define LCD_READ_ID 0x04 // Read display identification information (0xD3 on ILI9341)
#endif
#ifndef LCD_READ_ID4
#define LCD_READ_ID4 0xD3 // Read display identification information (0xD3 on ILI9341)
#endif
#define DATASIZE_8BIT SPI_DATASIZE_8BIT
#define DATASIZE_16BIT SPI_DATASIZE_16BIT
#define TFT_IO_DRIVER TFT_SPI
class TFT_SPI {
private:
static SPI_HandleTypeDef SPIx;
static uint32_t ReadID(uint16_t Reg);
static void Transmit(uint16_t Data);
static void TransmitDMA(uint32_t MemoryIncrease, uint16_t *Data, uint16_t Count);
#if ENABLED(USE_SPI_DMA_TC)
static void TransmitDMA_IT(uint32_t MemoryIncrease, uint16_t *Data, uint16_t Count);
#endif
public:
static DMA_HandleTypeDef DMAtx;
static void Init();
static uint32_t GetID();
static bool isBusy();
static void Abort();
static void DataTransferBegin(uint16_t DataWidth = DATASIZE_16BIT);
static void DataTransferEnd() { WRITE(TFT_CS_PIN, HIGH); };
static void DataTransferAbort();
static void WriteData(uint16_t Data) { Transmit(Data); }
static void WriteReg(uint16_t Reg) { WRITE(TFT_A0_PIN, LOW); Transmit(Reg); WRITE(TFT_A0_PIN, HIGH); }
static void WriteSequence(uint16_t *Data, uint16_t Count) { TransmitDMA(DMA_MINC_ENABLE, Data, Count); }
#if ENABLED(USE_SPI_DMA_TC)
static void WriteSequenceIT(uint16_t *Data, uint16_t Count) { TransmitDMA_IT(DMA_MINC_ENABLE, Data, Count); }
#endif
static void WriteMultiple(uint16_t Color, uint16_t Count) { static uint16_t Data; Data = Color; TransmitDMA(DMA_MINC_DISABLE, &Data, Count); }
static void WriteMultiple(uint16_t Color, uint32_t Count) {
static uint16_t Data; Data = Color;
while (Count > 0) {
TransmitDMA(DMA_MINC_DISABLE, &Data, Count > 0xFFFF ? 0xFFFF : Count);
Count = Count > 0xFFFF ? Count - 0xFFFF : 0;
}
}
};

@ -0,0 +1,173 @@
/**
* 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/>.
*
*/
#include "../../platforms.h"
#ifdef HAL_STM32
#include "../../../inc/MarlinConfig.h"
#if HAS_TFT_XPT2046 || HAS_RES_TOUCH_BUTTONS
#include "xpt2046.h"
#include "pinconfig.h"
uint16_t delta(uint16_t a, uint16_t b) { return a > b ? a - b : b - a; }
SPI_HandleTypeDef XPT2046::SPIx;
void XPT2046::Init() {
SPI_TypeDef *spiInstance;
OUT_WRITE(TOUCH_CS_PIN, HIGH);
#if PIN_EXISTS(TOUCH_INT)
// Optional Pendrive interrupt pin
SET_INPUT(TOUCH_INT_PIN);
#endif
spiInstance = (SPI_TypeDef *)pinmap_peripheral(digitalPinToPinName(TOUCH_SCK_PIN), PinMap_SPI_SCLK);
if (spiInstance != (SPI_TypeDef *)pinmap_peripheral(digitalPinToPinName(TOUCH_MOSI_PIN), PinMap_SPI_MOSI)) spiInstance = NP;
if (spiInstance != (SPI_TypeDef *)pinmap_peripheral(digitalPinToPinName(TOUCH_MISO_PIN), PinMap_SPI_MISO)) spiInstance = NP;
SPIx.Instance = spiInstance;
if (SPIx.Instance) {
SPIx.State = HAL_SPI_STATE_RESET;
SPIx.Init.NSS = SPI_NSS_SOFT;
SPIx.Init.Mode = SPI_MODE_MASTER;
SPIx.Init.Direction = SPI_DIRECTION_2LINES;
SPIx.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_8;
SPIx.Init.CLKPhase = SPI_PHASE_2EDGE;
SPIx.Init.CLKPolarity = SPI_POLARITY_HIGH;
SPIx.Init.DataSize = SPI_DATASIZE_8BIT;
SPIx.Init.FirstBit = SPI_FIRSTBIT_MSB;
SPIx.Init.TIMode = SPI_TIMODE_DISABLE;
SPIx.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;
SPIx.Init.CRCPolynomial = 10;
pinmap_pinout(digitalPinToPinName(TOUCH_SCK_PIN), PinMap_SPI_SCLK);
pinmap_pinout(digitalPinToPinName(TOUCH_MOSI_PIN), PinMap_SPI_MOSI);
pinmap_pinout(digitalPinToPinName(TOUCH_MISO_PIN), PinMap_SPI_MISO);
#ifdef SPI1_BASE
if (SPIx.Instance == SPI1) {
__HAL_RCC_SPI1_CLK_ENABLE();
SPIx.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_16;
}
#endif
#ifdef SPI2_BASE
if (SPIx.Instance == SPI2) {
__HAL_RCC_SPI2_CLK_ENABLE();
}
#endif
#ifdef SPI3_BASE
if (SPIx.Instance == SPI3) {
__HAL_RCC_SPI3_CLK_ENABLE();
}
#endif
}
else {
SPIx.Instance = nullptr;
SET_INPUT(TOUCH_MISO_PIN);
SET_OUTPUT(TOUCH_MOSI_PIN);
SET_OUTPUT(TOUCH_SCK_PIN);
}
getRawData(XPT2046_Z1);
}
bool XPT2046::isTouched() {
return isBusy() ? false : (
#if PIN_EXISTS(TOUCH_INT)
READ(TOUCH_INT_PIN) != HIGH
#else
getRawData(XPT2046_Z1) >= XPT2046_Z1_THRESHOLD
#endif
);
}
bool XPT2046::getRawPoint(int16_t *x, int16_t *y) {
if (isBusy()) return false;
if (!isTouched()) return false;
*x = getRawData(XPT2046_X);
*y = getRawData(XPT2046_Y);
return isTouched();
}
uint16_t XPT2046::getRawData(const XPTCoordinate coordinate) {
uint16_t data[3];
DataTransferBegin();
for (uint16_t i = 0; i < 3 ; i++) {
IO(coordinate);
data[i] = (IO() << 4) | (IO() >> 4);
}
DataTransferEnd();
uint16_t delta01 = delta(data[0], data[1]);
uint16_t delta02 = delta(data[0], data[2]);
uint16_t delta12 = delta(data[1], data[2]);
if (delta01 > delta02 || delta01 > delta12) {
if (delta02 > delta12)
data[0] = data[2];
else
data[1] = data[2];
}
return (data[0] + data[1]) >> 1;
}
uint16_t XPT2046::HardwareIO(uint16_t data) {
__HAL_SPI_ENABLE(&SPIx);
while ((SPIx.Instance->SR & SPI_FLAG_TXE) != SPI_FLAG_TXE) {}
SPIx.Instance->DR = data;
while ((SPIx.Instance->SR & SPI_FLAG_RXNE) != SPI_FLAG_RXNE) {}
__HAL_SPI_DISABLE(&SPIx);
return SPIx.Instance->DR;
}
uint16_t XPT2046::SoftwareIO(uint16_t data) {
uint16_t result = 0;
for (uint8_t j = 0x80; j > 0; j >>= 1) {
WRITE(TOUCH_SCK_PIN, LOW);
__DSB();
WRITE(TOUCH_MOSI_PIN, data & j ? HIGH : LOW);
__DSB();
if (READ(TOUCH_MISO_PIN)) result |= j;
__DSB();
WRITE(TOUCH_SCK_PIN, HIGH);
__DSB();
}
WRITE(TOUCH_SCK_PIN, LOW);
__DSB();
return result;
}
#endif // HAS_TFT_XPT2046
#endif // HAL_STM32

@ -0,0 +1,81 @@
/**
* 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
#ifdef STM32F1xx
#include <stm32f1xx_hal.h>
#elif defined(STM32F4xx)
#include <stm32f4xx_hal.h>
#endif
#include "../../../inc/MarlinConfig.h"
// Not using regular SPI interface by default to avoid SPI mode conflicts with other SPI devices
#if !PIN_EXISTS(TOUCH_MISO)
#error "TOUCH_MISO_PIN is not defined."
#elif !PIN_EXISTS(TOUCH_MOSI)
#error "TOUCH_MOSI_PIN is not defined."
#elif !PIN_EXISTS(TOUCH_SCK)
#error "TOUCH_SCK_PIN is not defined."
#elif !PIN_EXISTS(TOUCH_CS)
#error "TOUCH_CS_PIN is not defined."
#endif
#ifndef TOUCH_INT_PIN
#define TOUCH_INT_PIN -1
#endif
#define XPT2046_DFR_MODE 0x00
#define XPT2046_SER_MODE 0x04
#define XPT2046_CONTROL 0x80
enum XPTCoordinate : uint8_t {
XPT2046_X = 0x10 | XPT2046_CONTROL | XPT2046_DFR_MODE,
XPT2046_Y = 0x50 | XPT2046_CONTROL | XPT2046_DFR_MODE,
XPT2046_Z1 = 0x30 | XPT2046_CONTROL | XPT2046_DFR_MODE,
XPT2046_Z2 = 0x40 | XPT2046_CONTROL | XPT2046_DFR_MODE,
};
#ifndef XPT2046_Z1_THRESHOLD
#define XPT2046_Z1_THRESHOLD 10
#endif
class XPT2046 {
private:
static SPI_HandleTypeDef SPIx;
static bool isBusy() { return false; }
static uint16_t getRawData(const XPTCoordinate coordinate);
static bool isTouched();
static void DataTransferBegin() { if (SPIx.Instance) { HAL_SPI_Init(&SPIx); } WRITE(TOUCH_CS_PIN, LOW); };
static void DataTransferEnd() { WRITE(TOUCH_CS_PIN, HIGH); };
static uint16_t HardwareIO(uint16_t data);
static uint16_t SoftwareIO(uint16_t data);
static uint16_t IO(uint16_t data = 0) { return SPIx.Instance ? HardwareIO(data) : SoftwareIO(data); }
public:
static void Init();
static bool getRawPoint(int16_t *x, int16_t *y);
};

@ -0,0 +1,330 @@
/**
* Marlin 3D Printer Firmware
*
* Copyright (c) 2020 MarlinFirmware [https://github.com/MarlinFirmware/Marlin]
* Copyright (c) 2016 Bob Cousins bobcousins42@googlemail.com
* Copyright (c) 2015-2016 Nico Tonnhofer wurstnase.reprap@gmail.com
*
* This 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/>.
*
*/
#include "../platforms.h"
#ifdef HAL_STM32
#include "../../inc/MarlinConfig.h"
// ------------------------
// Local defines
// ------------------------
// Default timer priorities. Override by specifying alternate priorities in the board pins file.
// The TONE timer is not present here, as it currently cannot be set programmatically. It is set
// by defining TIM_IRQ_PRIO in the variant.h or platformio.ini file, which adjusts the default
// priority for STM32 HardwareTimer objects.
#define SWSERIAL_TIMER_IRQ_PRIO_DEFAULT 1 // Requires tight bit timing to communicate reliably with TMC drivers
#define SERVO_TIMER_IRQ_PRIO_DEFAULT 1 // Requires tight PWM timing to control a BLTouch reliably
#define STEP_TIMER_IRQ_PRIO_DEFAULT 2
#define TEMP_TIMER_IRQ_PRIO_DEFAULT 14 // Low priority avoids interference with other hardware and timers
#ifndef STEP_TIMER_IRQ_PRIO
#define STEP_TIMER_IRQ_PRIO STEP_TIMER_IRQ_PRIO_DEFAULT
#endif
#ifndef TEMP_TIMER_IRQ_PRIO
#define TEMP_TIMER_IRQ_PRIO TEMP_TIMER_IRQ_PRIO_DEFAULT
#endif
#if HAS_TMC_SW_SERIAL
#include <SoftwareSerial.h>
#ifndef SWSERIAL_TIMER_IRQ_PRIO
#define SWSERIAL_TIMER_IRQ_PRIO SWSERIAL_TIMER_IRQ_PRIO_DEFAULT
#endif
#endif
#if HAS_SERVOS
#include "Servo.h"
#ifndef SERVO_TIMER_IRQ_PRIO
#define SERVO_TIMER_IRQ_PRIO SERVO_TIMER_IRQ_PRIO_DEFAULT
#endif
#endif
#if ENABLED(SPEAKER)
// Ensure the default timer priority is somewhere between the STEP and TEMP priorities.
// The STM32 framework defaults to interrupt 14 for all timers. This should be increased so that
// timing-sensitive operations such as speaker output are not impacted by the long-running
// temperature ISR. This must be defined in the platformio.ini file or the board's variant.h,
// so that it will be consumed by framework code.
#if !(TIM_IRQ_PRIO > STEP_TIMER_IRQ_PRIO && TIM_IRQ_PRIO < TEMP_TIMER_IRQ_PRIO)
#error "Default timer interrupt priority is unspecified or set to a value which may degrade performance."
#endif
#endif
#if defined(STM32F0xx) || defined(STM32G0xx)
#define MCU_STEP_TIMER 16
#define MCU_TEMP_TIMER 17
#elif defined(STM32F1xx)
#define MCU_STEP_TIMER 4
#define MCU_TEMP_TIMER 2
#elif defined(STM32F401xC) || defined(STM32F401xE)
#define MCU_STEP_TIMER 9 // STM32F401 has no TIM6, TIM7, or TIM8
#define MCU_TEMP_TIMER 10
#elif defined(STM32F4xx) || defined(STM32F7xx) || defined(STM32H7xx)
#define MCU_STEP_TIMER 6
#define MCU_TEMP_TIMER 14 // TIM7 is consumed by Software Serial if used.
#endif
#ifndef HAL_TIMER_RATE
#define HAL_TIMER_RATE GetStepperTimerClkFreq()
#endif
#ifndef STEP_TIMER
#define STEP_TIMER MCU_STEP_TIMER
#endif
#ifndef TEMP_TIMER
#define TEMP_TIMER MCU_TEMP_TIMER
#endif
#define __TIMER_DEV(X) TIM##X
#define _TIMER_DEV(X) __TIMER_DEV(X)
#define STEP_TIMER_DEV _TIMER_DEV(STEP_TIMER)
#define TEMP_TIMER_DEV _TIMER_DEV(TEMP_TIMER)
// --------------------------------------------------------------------------
// Local defines
// --------------------------------------------------------------------------
#define NUM_HARDWARE_TIMERS 2
// --------------------------------------------------------------------------
// Private Variables
// --------------------------------------------------------------------------
HardwareTimer *timer_instance[NUM_HARDWARE_TIMERS] = { nullptr };
// ------------------------
// Public functions
// ------------------------
uint32_t GetStepperTimerClkFreq() {
// Timer input clocks vary between devices, and in some cases between timers on the same device.
// Retrieve at runtime to ensure device compatibility. Cache result to avoid repeated overhead.
static uint32_t clkfreq = timer_instance[MF_TIMER_STEP]->getTimerClkFreq();
return clkfreq;
}
// frequency is in Hertz
void HAL_timer_start(const uint8_t timer_num, const uint32_t frequency) {
if (!HAL_timer_initialized(timer_num)) {
switch (timer_num) {
case MF_TIMER_STEP: // STEPPER TIMER - use a 32bit timer if possible
timer_instance[timer_num] = new HardwareTimer(STEP_TIMER_DEV);
/* Set the prescaler to the final desired value.
* This will change the effective ISR callback frequency but when
* HAL_timer_start(timer_num=0) is called in the core for the first time
* the real frequency isn't important as long as, after boot, the ISR
* gets called with the correct prescaler and count register. So here
* we set the prescaler to the correct, final value and ignore the frequency
* asked. We will call back the ISR in 1 second to start at full speed.
*
* The proper fix, however, would be a correct initialization OR a
* HAL_timer_change(const uint8_t timer_num, const uint32_t frequency)
* which changes the prescaler when an IRQ frequency change is needed
* (for example when steppers are turned on)
*/
timer_instance[timer_num]->setPrescaleFactor(STEPPER_TIMER_PRESCALE); //the -1 is done internally
timer_instance[timer_num]->setOverflow(_MIN(hal_timer_t(HAL_TIMER_TYPE_MAX), (HAL_TIMER_RATE) / (STEPPER_TIMER_PRESCALE) /* /frequency */), TICK_FORMAT);
break;
case MF_TIMER_TEMP: // TEMP TIMER - any available 16bit timer
timer_instance[timer_num] = new HardwareTimer(TEMP_TIMER_DEV);
// The prescale factor is computed automatically for HERTZ_FORMAT
timer_instance[timer_num]->setOverflow(frequency, HERTZ_FORMAT);
break;
}
// Disable preload. Leaving it default-enabled can cause the timer to stop if it happens
// to exit the ISR after the start time for the next interrupt has already passed.
timer_instance[timer_num]->setPreloadEnable(false);
HAL_timer_enable_interrupt(timer_num);
// Start the timer.
timer_instance[timer_num]->resume(); // First call to resume() MUST follow the attachInterrupt()
// This is fixed in Arduino_Core_STM32 1.8.
// These calls can be removed and replaced with
// timer_instance[timer_num]->setInterruptPriority
switch (timer_num) {
case MF_TIMER_STEP:
timer_instance[timer_num]->setInterruptPriority(STEP_TIMER_IRQ_PRIO, 0);
break;
case MF_TIMER_TEMP:
timer_instance[timer_num]->setInterruptPriority(TEMP_TIMER_IRQ_PRIO, 0);
break;
}
}
}
void HAL_timer_enable_interrupt(const uint8_t timer_num) {
if (HAL_timer_initialized(timer_num) && !timer_instance[timer_num]->hasInterrupt()) {
switch (timer_num) {
case MF_TIMER_STEP:
timer_instance[timer_num]->attachInterrupt(Step_Handler);
break;
case MF_TIMER_TEMP:
timer_instance[timer_num]->attachInterrupt(Temp_Handler);
break;
}
}
}
void HAL_timer_disable_interrupt(const uint8_t timer_num) {
if (HAL_timer_initialized(timer_num)) timer_instance[timer_num]->detachInterrupt();
}
bool HAL_timer_interrupt_enabled(const uint8_t timer_num) {
return HAL_timer_initialized(timer_num) && timer_instance[timer_num]->hasInterrupt();
}
void SetTimerInterruptPriorities() {
TERN_(HAS_TMC_SW_SERIAL, SoftwareSerial::setInterruptPriority(SWSERIAL_TIMER_IRQ_PRIO, 0));
TERN_(HAS_SERVOS, libServo::setInterruptPriority(SERVO_TIMER_IRQ_PRIO, 0));
}
// ------------------------
// Detect timer conflicts
// ------------------------
// This list serves two purposes. Firstly, it facilitates build-time mapping between
// variant-defined timer names (such as TIM1) and timer numbers. It also replicates
// the order of timers used in the framework's SoftwareSerial.cpp. The first timer in
// this list will be automatically used by SoftwareSerial if it is not already defined
// in the board's variant or compiler options.
static constexpr struct {uintptr_t base_address; int timer_number;} stm32_timer_map[] = {
#ifdef TIM18_BASE
{ uintptr_t(TIM18), 18 },
#endif
#ifdef TIM7_BASE
{ uintptr_t(TIM7), 7 },
#endif
#ifdef TIM6_BASE
{ uintptr_t(TIM6), 6 },
#endif
#ifdef TIM22_BASE
{ uintptr_t(TIM22), 22 },
#endif
#ifdef TIM21_BASE
{ uintptr_t(TIM21), 21 },
#endif
#ifdef TIM17_BASE
{ uintptr_t(TIM17), 17 },
#endif
#ifdef TIM16_BASE
{ uintptr_t(TIM16), 16 },
#endif
#ifdef TIM15_BASE
{ uintptr_t(TIM15), 15 },
#endif
#ifdef TIM14_BASE
{ uintptr_t(TIM14), 14 },
#endif
#ifdef TIM13_BASE
{ uintptr_t(TIM13), 13 },
#endif
#ifdef TIM11_BASE
{ uintptr_t(TIM11), 11 },
#endif
#ifdef TIM10_BASE
{ uintptr_t(TIM10), 10 },
#endif
#ifdef TIM12_BASE
{ uintptr_t(TIM12), 12 },
#endif
#ifdef TIM19_BASE
{ uintptr_t(TIM19), 19 },
#endif
#ifdef TIM9_BASE
{ uintptr_t(TIM9), 9 },
#endif
#ifdef TIM5_BASE
{ uintptr_t(TIM5), 5 },
#endif
#ifdef TIM4_BASE
{ uintptr_t(TIM4), 4 },
#endif
#ifdef TIM3_BASE
{ uintptr_t(TIM3), 3 },
#endif
#ifdef TIM2_BASE
{ uintptr_t(TIM2), 2 },
#endif
#ifdef TIM20_BASE
{ uintptr_t(TIM20), 20 },
#endif
#ifdef TIM8_BASE
{ uintptr_t(TIM8), 8 },
#endif
#ifdef TIM1_BASE
{ uintptr_t(TIM1), 1 }
#endif
};
// Convert from a timer base address to its integer timer number.
static constexpr int get_timer_num_from_base_address(uintptr_t base_address) {
for (const auto &timer : stm32_timer_map)
if (timer.base_address == base_address) return timer.timer_number;
return 0;
}
// The platform's SoftwareSerial.cpp will use the first timer from stm32_timer_map.
#if HAS_TMC_SW_SERIAL && !defined(TIMER_SERIAL)
#define TIMER_SERIAL (stm32_timer_map[0].base_address)
#endif
// constexpr doesn't like using the base address pointers that timers evaluate to.
// We can get away with casting them to uintptr_t, if we do so inside an array.
// GCC will not currently do it directly to a uintptr_t.
IF_ENABLED(HAS_TMC_SW_SERIAL, static constexpr uintptr_t timer_serial[] = {uintptr_t(TIMER_SERIAL)});
IF_ENABLED(SPEAKER, static constexpr uintptr_t timer_tone[] = {uintptr_t(TIMER_TONE)});
IF_ENABLED(HAS_SERVOS, static constexpr uintptr_t timer_servo[] = {uintptr_t(TIMER_SERVO)});
enum TimerPurpose { TP_SERIAL, TP_TONE, TP_SERVO, TP_STEP, TP_TEMP };
// List of timers, to enable checking for conflicts.
// Includes the purpose of each timer to ease debugging when evaluating at build-time.
// This cannot yet account for timers used for PWM output, such as for fans.
static constexpr struct { TimerPurpose p; int t; } timers_in_use[] = {
#if HAS_TMC_SW_SERIAL
{ TP_SERIAL, get_timer_num_from_base_address(timer_serial[0]) }, // Set in variant.h, or as a define in platformio.h if not present in variant.h
#endif
#if ENABLED(SPEAKER)
{ TP_TONE, get_timer_num_from_base_address(timer_tone[0]) }, // Set in variant.h, or as a define in platformio.h if not present in variant.h
#endif
#if HAS_SERVOS
{ TP_SERVO, get_timer_num_from_base_address(timer_servo[0]) }, // Set in variant.h, or as a define in platformio.h if not present in variant.h
#endif
{ TP_STEP, STEP_TIMER },
{ TP_TEMP, TEMP_TIMER },
};
static constexpr bool verify_no_timer_conflicts() {
LOOP_L_N(i, COUNT(timers_in_use))
LOOP_S_L_N(j, i + 1, COUNT(timers_in_use))
if (timers_in_use[i].t == timers_in_use[j].t) return false;
return true;
}
// If this assertion fails at compile time, review the timers_in_use array.
// If default_envs is defined properly in platformio.ini, VS Code can evaluate the array
// when hovering over it, making it easy to identify the conflicting timers.
static_assert(verify_no_timer_conflicts(), "One or more timer conflict detected. Examine \"timers_in_use\" to help identify conflict.");
#endif // HAL_STM32

@ -0,0 +1,120 @@
/**
* Marlin 3D Printer Firmware
*
* Copyright (c) 2020 MarlinFirmware [https://github.com/MarlinFirmware/Marlin]
* Copyright (c) 2016 Bob Cousins bobcousins42@googlemail.com
* Copyright (c) 2017 Victor Perez
*
* This 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/MarlinConfig.h"
// ------------------------
// Defines
// ------------------------
// STM32 timers may be 16 or 32 bit. Limiting HAL_TIMER_TYPE_MAX to 16 bits
// avoids issues with STM32F0 MCUs, which seem to pause timers if UINT32_MAX
// is written to the register. STM32F4 timers do not manifest this issue,
// even when writing to 16 bit timers.
//
// The range of the timer can be queried at runtime using IS_TIM_32B_COUNTER_INSTANCE.
// This is a more expensive check than a simple compile-time constant, so its
// implementation is deferred until the desire for a 32-bit range outweighs the cost
// of adding a run-time check and HAL_TIMER_TYPE_MAX is refactored to allow unique
// values for each timer.
#define hal_timer_t uint32_t
#define HAL_TIMER_TYPE_MAX UINT16_MAX
// Marlin timer_instance[] content (unrelated to timer selection)
#define MF_TIMER_STEP 0 // Timer Index for Stepper
#define MF_TIMER_TEMP 1 // Timer Index for Temperature
#define MF_TIMER_PULSE MF_TIMER_STEP
#define TIMER_INDEX_(T) TIMER##T##_INDEX // TIMER#_INDEX enums (timer_index_t) depend on TIM#_BASE defines.
#define TIMER_INDEX(T) TIMER_INDEX_(T) // Convert Timer ID to HardwareTimer_Handle index.
#define TEMP_TIMER_FREQUENCY 1000 // Temperature::isr() is expected to be called at around 1kHz
// TODO: get rid of manual rate/prescale/ticks/cycles taken for procedures in stepper.cpp
#define STEPPER_TIMER_RATE 2000000 // 2 Mhz
extern uint32_t GetStepperTimerClkFreq();
#define STEPPER_TIMER_PRESCALE (GetStepperTimerClkFreq() / (STEPPER_TIMER_RATE))
#define STEPPER_TIMER_TICKS_PER_US ((STEPPER_TIMER_RATE) / 1000000) // stepper timer ticks per µs
#define PULSE_TIMER_RATE STEPPER_TIMER_RATE
#define PULSE_TIMER_PRESCALE STEPPER_TIMER_PRESCALE
#define PULSE_TIMER_TICKS_PER_US STEPPER_TIMER_TICKS_PER_US
#define ENABLE_STEPPER_DRIVER_INTERRUPT() HAL_timer_enable_interrupt(MF_TIMER_STEP)
#define DISABLE_STEPPER_DRIVER_INTERRUPT() HAL_timer_disable_interrupt(MF_TIMER_STEP)
#define STEPPER_ISR_ENABLED() HAL_timer_interrupt_enabled(MF_TIMER_STEP)
#define ENABLE_TEMPERATURE_INTERRUPT() HAL_timer_enable_interrupt(MF_TIMER_TEMP)
#define DISABLE_TEMPERATURE_INTERRUPT() HAL_timer_disable_interrupt(MF_TIMER_TEMP)
extern void Step_Handler();
extern void Temp_Handler();
#ifndef HAL_STEP_TIMER_ISR
#define HAL_STEP_TIMER_ISR() void Step_Handler()
#endif
#ifndef HAL_TEMP_TIMER_ISR
#define HAL_TEMP_TIMER_ISR() void Temp_Handler()
#endif
// ------------------------
// Public Variables
// ------------------------
extern HardwareTimer *timer_instance[];
// ------------------------
// Public functions
// ------------------------
void HAL_timer_start(const uint8_t timer_num, const uint32_t frequency);
void HAL_timer_enable_interrupt(const uint8_t timer_num);
void HAL_timer_disable_interrupt(const uint8_t timer_num);
bool HAL_timer_interrupt_enabled(const uint8_t timer_num);
// Configure timer priorities for peripherals such as Software Serial or Servos.
// Exposed here to allow all timer priority information to reside in timers.cpp
void SetTimerInterruptPriorities();
// FORCE_INLINE because these are used in performance-critical situations
FORCE_INLINE bool HAL_timer_initialized(const uint8_t timer_num) {
return timer_instance[timer_num] != nullptr;
}
FORCE_INLINE static hal_timer_t HAL_timer_get_count(const uint8_t timer_num) {
return HAL_timer_initialized(timer_num) ? timer_instance[timer_num]->getCount() : 0;
}
// NOTE: Method name may be misleading.
// STM32 has an Auto-Reload Register (ARR) as opposed to a "compare" register
FORCE_INLINE static void HAL_timer_set_compare(const uint8_t timer_num, const hal_timer_t overflow) {
if (HAL_timer_initialized(timer_num)) {
timer_instance[timer_num]->setOverflow(overflow + 1, TICK_FORMAT); // Value decremented by setOverflow()
// wiki: "force all registers (Autoreload, prescaler, compare) to be taken into account"
// So, if the new overflow value is less than the count it will trigger a rollover interrupt.
if (overflow < timer_instance[timer_num]->getCount()) // Added 'if' here because reports say it won't boot without it
timer_instance[timer_num]->refresh();
}
}
#define HAL_timer_isr_prologue(T) NOOP
#define HAL_timer_isr_epilogue(T) NOOP

@ -0,0 +1,119 @@
/**
* 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/>.
*
*/
#include "../platforms.h"
#ifdef HAL_STM32
#include "../../inc/MarlinConfig.h"
#if BOTH(USE_OTG_USB_HOST, USBHOST)
#include "usb_host.h"
#include "../shared/Marduino.h"
#include "usbh_core.h"
#include "usbh_msc.h"
USBH_HandleTypeDef hUsbHost;
USBHost usb;
BulkStorage bulk(&usb);
static void USBH_UserProcess(USBH_HandleTypeDef *phost, uint8_t id) {
switch(id) {
case HOST_USER_SELECT_CONFIGURATION:
//SERIAL_ECHOLNPGM("APPLICATION_SELECT_CONFIGURATION");
break;
case HOST_USER_DISCONNECTION:
//SERIAL_ECHOLNPGM("APPLICATION_DISCONNECT");
//usb.setUsbTaskState(USB_STATE_RUNNING);
break;
case HOST_USER_CLASS_ACTIVE:
//SERIAL_ECHOLNPGM("APPLICATION_READY");
usb.setUsbTaskState(USB_STATE_RUNNING);
break;
case HOST_USER_CONNECTION:
break;
default:
break;
}
}
bool USBHost::start() {
if (USBH_Init(&hUsbHost, USBH_UserProcess, TERN(USE_USB_HS_IN_FS, HOST_HS, HOST_FS)) != USBH_OK) {
SERIAL_ECHOLNPGM("Error: USBH_Init");
return false;
}
if (USBH_RegisterClass(&hUsbHost, USBH_MSC_CLASS) != USBH_OK) {
SERIAL_ECHOLNPGM("Error: USBH_RegisterClass");
return false;
}
if (USBH_Start(&hUsbHost) != USBH_OK) {
SERIAL_ECHOLNPGM("Error: USBH_Start");
return false;
}
return true;
}
void USBHost::Task() {
USBH_Process(&hUsbHost);
}
uint8_t USBHost::getUsbTaskState() {
return usb_task_state;
}
void USBHost::setUsbTaskState(uint8_t state) {
usb_task_state = state;
if (usb_task_state == USB_STATE_RUNNING) {
MSC_LUNTypeDef info;
USBH_MSC_GetLUNInfo(&hUsbHost, usb.lun, &info);
capacity = info.capacity.block_nbr / 2000;
block_size = info.capacity.block_size;
block_count = info.capacity.block_nbr;
//SERIAL_ECHOLNPGM("info.capacity.block_nbr : %ld\n", info.capacity.block_nbr);
//SERIAL_ECHOLNPGM("info.capacity.block_size: %d\n", info.capacity.block_size);
//SERIAL_ECHOLNPGM("capacity : %d MB\n", capacity);
}
};
bool BulkStorage::LUNIsGood(uint8_t t) {
return USBH_MSC_IsReady(&hUsbHost) && USBH_MSC_UnitIsReady(&hUsbHost, t);
}
uint32_t BulkStorage::GetCapacity(uint8_t lun) {
return usb->block_count;
}
uint16_t BulkStorage::GetSectorSize(uint8_t lun) {
return usb->block_size;
}
uint8_t BulkStorage::Read(uint8_t lun, uint32_t addr, uint16_t bsize, uint8_t blocks, uint8_t *buf) {
return USBH_MSC_Read(&hUsbHost, lun, addr, buf, blocks) != USBH_OK;
}
uint8_t BulkStorage::Write(uint8_t lun, uint32_t addr, uint16_t bsize, uint8_t blocks, const uint8_t * buf) {
return USBH_MSC_Write(&hUsbHost, lun, addr, const_cast<uint8_t*>(buf), blocks) != USBH_OK;
}
#endif // USE_OTG_USB_HOST && USBHOST
#endif // HAL_STM32

@ -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
*
* This 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>
typedef enum {
USB_STATE_INIT,
USB_STATE_ERROR,
USB_STATE_RUNNING,
} usb_state_t;
class USBHost {
public:
bool start();
void Task();
uint8_t getUsbTaskState();
void setUsbTaskState(uint8_t state);
uint8_t regRd(uint8_t reg) { return 0x0; };
uint8_t usb_task_state = USB_STATE_INIT;
uint8_t lun = 0;
uint32_t capacity = 0;
uint16_t block_size = 0;
uint32_t block_count = 0;
};
class BulkStorage {
public:
BulkStorage(USBHost *usb) : usb(usb) {};
bool LUNIsGood(uint8_t t);
uint32_t GetCapacity(uint8_t lun);
uint16_t GetSectorSize(uint8_t lun);
uint8_t Read(uint8_t lun, uint32_t addr, uint16_t bsize, uint8_t blocks, uint8_t *buf);
uint8_t Write(uint8_t lun, uint32_t addr, uint16_t bsize, uint8_t blocks, const uint8_t * buf);
USBHost *usb;
};
extern USBHost usb;
extern BulkStorage bulk;

@ -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
*
* This 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/>.
*
*/
#include "../platforms.h"
#ifdef HAL_STM32
#include "../../inc/MarlinConfigPre.h"
#if ENABLED(EMERGENCY_PARSER) && (USBD_USE_CDC || USBD_USE_CDC_MSC)
#include "usb_serial.h"
#include "../../feature/e_parser.h"
EmergencyParser::State emergency_state = EmergencyParser::State::EP_RESET;
int8_t (*USBD_CDC_Receive_original) (uint8_t *Buf, uint32_t *Len) = nullptr;
static int8_t USBD_CDC_Receive_hook(uint8_t *Buf, uint32_t *Len) {
for (uint32_t i = 0; i < *Len; i++)
emergency_parser.update(emergency_state, Buf[i]);
return USBD_CDC_Receive_original(Buf, Len);
}
typedef struct _USBD_CDC_Itf {
int8_t (* Init)(void);
int8_t (* DeInit)(void);
int8_t (* Control)(uint8_t cmd, uint8_t *pbuf, uint16_t length);
int8_t (* Receive)(uint8_t *Buf, uint32_t *Len);
int8_t (* Transferred)(void);
} USBD_CDC_ItfTypeDef;
extern USBD_CDC_ItfTypeDef USBD_CDC_fops;
void USB_Hook_init() {
USBD_CDC_Receive_original = USBD_CDC_fops.Receive;
USBD_CDC_fops.Receive = USBD_CDC_Receive_hook;
}
#endif // EMERGENCY_PARSER && USBD_USE_CDC
#endif // HAL_STM32

@ -0,0 +1,24 @@
/**
* 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
void USB_Hook_init();

@ -0,0 +1,387 @@
/**
* Marlin 3D Printer Firmware
*
* Copyright (c) 2020 MarlinFirmware [https://github.com/MarlinFirmware/Marlin]
* Copyright (c) 2016 Bob Cousins bobcousins42@googlemail.com
* Copyright (c) 2015-2016 Nico Tonnhofer wurstnase.reprap@gmail.com
* Copyright (c) 2017 Victor Perez
*
* This 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 stm32duino.com based on Libmaple and compatible (STM32F1)
*/
#ifdef __STM32F1__
#include "../../inc/MarlinConfig.h"
#include "HAL.h"
#include <STM32ADC.h>
// ------------------------
// Types
// ------------------------
#define __I
#define __IO volatile
typedef struct {
__I uint32_t CPUID; /*!< Offset: 0x000 (R/ ) CPUID Base Register */
__IO uint32_t ICSR; /*!< Offset: 0x004 (R/W) Interrupt Control and State Register */
__IO uint32_t VTOR; /*!< Offset: 0x008 (R/W) Vector Table Offset Register */
__IO uint32_t AIRCR; /*!< Offset: 0x00C (R/W) Application Interrupt and Reset Control Register */
__IO uint32_t SCR; /*!< Offset: 0x010 (R/W) System Control Register */
__IO uint32_t CCR; /*!< Offset: 0x014 (R/W) Configuration Control Register */
__IO uint8_t SHP[12]; /*!< Offset: 0x018 (R/W) System Handlers Priority Registers (4-7, 8-11, 12-15) */
__IO uint32_t SHCSR; /*!< Offset: 0x024 (R/W) System Handler Control and State Register */
__IO uint32_t CFSR; /*!< Offset: 0x028 (R/W) Configurable Fault Status Register */
__IO uint32_t HFSR; /*!< Offset: 0x02C (R/W) HardFault Status Register */
__IO uint32_t DFSR; /*!< Offset: 0x030 (R/W) Debug Fault Status Register */
__IO uint32_t MMFAR; /*!< Offset: 0x034 (R/W) MemManage Fault Address Register */
__IO uint32_t BFAR; /*!< Offset: 0x038 (R/W) BusFault Address Register */
__IO uint32_t AFSR; /*!< Offset: 0x03C (R/W) Auxiliary Fault Status Register */
__I uint32_t PFR[2]; /*!< Offset: 0x040 (R/ ) Processor Feature Register */
__I uint32_t DFR; /*!< Offset: 0x048 (R/ ) Debug Feature Register */
__I uint32_t ADR; /*!< Offset: 0x04C (R/ ) Auxiliary Feature Register */
__I uint32_t MMFR[4]; /*!< Offset: 0x050 (R/ ) Memory Model Feature Register */
__I uint32_t ISAR[5]; /*!< Offset: 0x060 (R/ ) Instruction Set Attributes Register */
uint32_t RESERVED0[5];
__IO uint32_t CPACR; /*!< Offset: 0x088 (R/W) Coprocessor Access Control Register */
} SCB_Type;
// ------------------------
// Local defines
// ------------------------
#define SCS_BASE (0xE000E000UL) /*!< System Control Space Base Address */
#define SCB_BASE (SCS_BASE + 0x0D00UL) /*!< System Control Block Base Address */
#define SCB ((SCB_Type *) SCB_BASE ) /*!< SCB configuration struct */
/* SCB Application Interrupt and Reset Control Register Definitions */
#define SCB_AIRCR_VECTKEY_Pos 16 /*!< SCB AIRCR: VECTKEY Position */
#define SCB_AIRCR_VECTKEY_Msk (0xFFFFUL << SCB_AIRCR_VECTKEY_Pos) /*!< SCB AIRCR: VECTKEY Mask */
#define SCB_AIRCR_PRIGROUP_Pos 8 /*!< SCB AIRCR: PRIGROUP Position */
#define SCB_AIRCR_PRIGROUP_Msk (7UL << SCB_AIRCR_PRIGROUP_Pos) /*!< SCB AIRCR: PRIGROUP Mask */
// ------------------------
// Serial ports
// ------------------------
#if defined(SERIAL_USB) && !HAS_SD_HOST_DRIVE
USBSerial SerialUSB;
DefaultSerial1 MSerial0(true, SerialUSB);
#if ENABLED(EMERGENCY_PARSER)
#include "../libmaple/usb/stm32f1/usb_reg_map.h"
#include "libmaple/usb_cdcacm.h"
// The original callback is not called (no way to retrieve address).
// That callback detects a special STM32 reset sequence: this functionality is not essential
// as M997 achieves the same.
void my_rx_callback(unsigned int, void*) {
// max length of 16 is enough to contain all emergency commands
uint8 buf[16];
//rx is usbSerialPart.endpoints[2]
uint16 len = usb_get_ep_rx_count(USB_CDCACM_RX_ENDP);
uint32 total = usb_cdcacm_data_available();
if (len == 0 || total == 0 || !WITHIN(total, len, COUNT(buf)))
return;
// cannot get character by character due to bug in composite_cdcacm_peek_ex
len = usb_cdcacm_peek(buf, total);
for (uint32 i = 0; i < len; i++)
emergency_parser.update(MSerial0.emergency_state, buf[i + total - len]);
}
#endif
#endif
// ------------------------
// Watchdog Timer
// ------------------------
#if ENABLED(USE_WATCHDOG)
#include <libmaple/iwdg.h>
void watchdogSetup() {
// do whatever. don't remove this function.
}
/**
* The watchdog clock is 40Khz. So for a 4s or 8s interval use a /256 preescaler and 625 or 1250 reload value (counts down to 0).
*/
#define STM32F1_WD_RELOAD TERN(WATCHDOG_DURATION_8S, 1250, 625) // 4 or 8 second timeout
/**
* @brief Initialize the independent hardware watchdog.
*
* @return No return
*
* @details The watchdog clock is 40Khz. So for a 4s or 8s interval use a /256 preescaler and 625 or 1250 reload value (counts down to 0).
*/
void MarlinHAL::watchdog_init() {
#if DISABLED(DISABLE_WATCHDOG_INIT)
iwdg_init(IWDG_PRE_256, STM32F1_WD_RELOAD);
#endif
}
// Reset watchdog. MUST be called every 4 or 8 seconds after the
// first watchdog_init or the STM32F1 will reset.
void MarlinHAL::watchdog_refresh() {
#if DISABLED(PINS_DEBUGGING) && PIN_EXISTS(LED)
TOGGLE(LED_PIN); // heartbeat indicator
#endif
iwdg_feed();
}
#endif // USE_WATCHDOG
// ------------------------
// ADC
// ------------------------
// Watch out for recursion here! Our pin_t is signed, so pass through to Arduino -> analogRead(uint8_t)
uint16_t analogRead(const pin_t pin) {
const bool is_analog = _GET_MODE(pin) == GPIO_INPUT_ANALOG;
return is_analog ? analogRead(uint8_t(pin)) : 0;
}
// Wrapper to maple unprotected analogWrite
void analogWrite(const pin_t pin, int pwm_val8) {
if (PWM_PIN(pin)) analogWrite(uint8_t(pin), pwm_val8);
}
uint16_t MarlinHAL::adc_result;
// ------------------------
// Private functions
// ------------------------
static void NVIC_SetPriorityGrouping(uint32_t PriorityGroup) {
uint32_t reg_value;
uint32_t PriorityGroupTmp = (PriorityGroup & (uint32_t)0x07); // only values 0..7 are used
reg_value = SCB->AIRCR; // read old register configuration
reg_value &= ~(SCB_AIRCR_VECTKEY_Msk | SCB_AIRCR_PRIGROUP_Msk); // clear bits to change
reg_value = (reg_value |
((uint32_t)0x5FA << SCB_AIRCR_VECTKEY_Pos) |
(PriorityGroupTmp << 8)); // Insert write key & priority group
SCB->AIRCR = reg_value;
}
// ------------------------
// Public functions
// ------------------------
void flashFirmware(const int16_t) { hal.reboot(); }
//
// Leave PA11/PA12 intact if USBSerial is not used
//
#if SERIAL_USB
namespace wirish { namespace priv {
#if SERIAL_PORT > 0
#if SERIAL_PORT2
#if SERIAL_PORT2 > 0
void board_setup_usb() {}
#endif
#else
void board_setup_usb() {}
#endif
#endif
} }
#endif
TERN_(POSTMORTEM_DEBUGGING, extern void install_min_serial());
// ------------------------
// MarlinHAL class
// ------------------------
void MarlinHAL::init() {
NVIC_SetPriorityGrouping(0x3);
#if PIN_EXISTS(LED)
OUT_WRITE(LED_PIN, LOW);
#endif
#if HAS_SD_HOST_DRIVE
MSC_SD_init();
#elif BOTH(SERIAL_USB, EMERGENCY_PARSER)
usb_cdcacm_set_hooks(USB_CDCACM_HOOK_RX, my_rx_callback);
#endif
#if PIN_EXISTS(USB_CONNECT)
OUT_WRITE(USB_CONNECT_PIN, !USB_CONNECT_INVERTING); // USB clear connection
delay(1000); // Give OS time to notice
WRITE(USB_CONNECT_PIN, USB_CONNECT_INVERTING);
#endif
TERN_(POSTMORTEM_DEBUGGING, install_min_serial()); // Install the minimal serial handler
}
// HAL idle task
void MarlinHAL::idletask() {
#if HAS_SHARED_MEDIA
// If Marlin is using the SD card we need to lock it to prevent access from
// a PC via USB.
// Other HALs use IS_SD_PRINTING() and IS_SD_FILE_OPEN() to check for access but
// this will not reliably detect delete operations. To be safe we will lock
// the disk if Marlin has it mounted. Unfortunately there is currently no way
// to unmount the disk from the LCD menu.
// if (IS_SD_PRINTING() || IS_SD_FILE_OPEN())
/* copy from lpc1768 framework, should be fixed later for process HAS_SD_HOST_DRIVE*/
// process USB mass storage device class loop
MarlinMSC.loop();
#endif
}
void MarlinHAL::reboot() { nvic_sys_reset(); }
// ------------------------
// Free Memory Accessor
// ------------------------
extern "C" {
extern unsigned int _ebss; // end of bss section
}
/**
* TODO: Change this to correct it for libmaple
*/
// return free memory between end of heap (or end bss) and whatever is current
/*
#include <wirish/syscalls.c>
//extern caddr_t _sbrk(int incr);
#ifndef CONFIG_HEAP_END
extern char _lm_heap_end;
#define CONFIG_HEAP_END ((caddr_t)&_lm_heap_end)
#endif
extern "C" {
static int freeMemory() {
char top = 't';
return &top - reinterpret_cast<char*>(sbrk(0));
}
int freeMemory() {
int free_memory;
int heap_end = (int)_sbrk(0);
free_memory = ((int)&free_memory) - ((int)heap_end);
return free_memory;
}
}
*/
// ------------------------
// ADC
// ------------------------
enum ADCIndex : uint8_t {
OPTITEM(HAS_TEMP_ADC_0, TEMP_0)
OPTITEM(HAS_TEMP_ADC_1, TEMP_1)
OPTITEM(HAS_TEMP_ADC_2, TEMP_2)
OPTITEM(HAS_TEMP_ADC_3, TEMP_3)
OPTITEM(HAS_TEMP_ADC_4, TEMP_4)
OPTITEM(HAS_TEMP_ADC_5, TEMP_5)
OPTITEM(HAS_TEMP_ADC_6, TEMP_6)
OPTITEM(HAS_TEMP_ADC_7, TEMP_7)
OPTITEM(HAS_HEATED_BED, TEMP_BED)
OPTITEM(HAS_TEMP_CHAMBER, TEMP_CHAMBER)
OPTITEM(HAS_TEMP_ADC_PROBE, TEMP_PROBE)
OPTITEM(HAS_TEMP_COOLER, TEMP_COOLER)
OPTITEM(HAS_TEMP_BOARD, TEMP_BOARD)
OPTITEM(FILAMENT_WIDTH_SENSOR, FILWIDTH)
OPTITEM(HAS_ADC_BUTTONS, ADC_KEY)
OPTITEM(HAS_JOY_ADC_X, JOY_X)
OPTITEM(HAS_JOY_ADC_Y, JOY_Y)
OPTITEM(HAS_JOY_ADC_Z, JOY_Z)
OPTITEM(POWER_MONITOR_CURRENT, POWERMON_CURRENT)
OPTITEM(POWER_MONITOR_VOLTAGE, POWERMON_VOLTS)
ADC_COUNT
};
static uint16_t adc_results[ADC_COUNT];
// Init the AD in continuous capture mode
void MarlinHAL::adc_init() {
static const uint8_t adc_pins[] = {
OPTITEM(HAS_TEMP_ADC_0, TEMP_0_PIN)
OPTITEM(HAS_TEMP_ADC_1, TEMP_1_PIN)
OPTITEM(HAS_TEMP_ADC_2, TEMP_2_PIN)
OPTITEM(HAS_TEMP_ADC_3, TEMP_3_PIN)
OPTITEM(HAS_TEMP_ADC_4, TEMP_4_PIN)
OPTITEM(HAS_TEMP_ADC_5, TEMP_5_PIN)
OPTITEM(HAS_TEMP_ADC_6, TEMP_6_PIN)
OPTITEM(HAS_TEMP_ADC_7, TEMP_7_PIN)
OPTITEM(HAS_HEATED_BED, TEMP_BED_PIN)
OPTITEM(HAS_TEMP_CHAMBER, TEMP_CHAMBER_PIN)
OPTITEM(HAS_TEMP_ADC_PROBE, TEMP_PROBE_PIN)
OPTITEM(HAS_TEMP_COOLER, TEMP_COOLER_PIN)
OPTITEM(HAS_TEMP_BOARD, TEMP_BOARD_PIN)
OPTITEM(FILAMENT_WIDTH_SENSOR, FILWIDTH_PIN)
OPTITEM(HAS_ADC_BUTTONS, ADC_KEYPAD_PIN)
OPTITEM(HAS_JOY_ADC_X, JOY_X_PIN)
OPTITEM(HAS_JOY_ADC_Y, JOY_Y_PIN)
OPTITEM(HAS_JOY_ADC_Z, JOY_Z_PIN)
OPTITEM(POWER_MONITOR_CURRENT, POWER_MONITOR_CURRENT_PIN)
OPTITEM(POWER_MONITOR_VOLTAGE, POWER_MONITOR_VOLTAGE_PIN)
};
static STM32ADC adc(ADC1);
// configure the ADC
adc.calibrate();
adc.setSampleRate((F_CPU > 72000000) ? ADC_SMPR_71_5 : ADC_SMPR_41_5); // 71.5 or 41.5 ADC cycles
adc.setPins((uint8_t *)adc_pins, ADC_COUNT);
adc.setDMA(adc_results, uint16_t(ADC_COUNT), uint32_t(DMA_MINC_MODE | DMA_CIRC_MODE), nullptr);
adc.setScanMode();
adc.setContinuous();
adc.startConversion();
}
void MarlinHAL::adc_start(const pin_t pin) {
#define __TCASE(N,I) case N: pin_index = I; break;
#define _TCASE(C,N,I) TERN_(C, __TCASE(N, I))
ADCIndex pin_index;
switch (pin) {
default: return;
_TCASE(HAS_TEMP_ADC_0, TEMP_0_PIN, TEMP_0)
_TCASE(HAS_TEMP_ADC_1, TEMP_1_PIN, TEMP_1)
_TCASE(HAS_TEMP_ADC_2, TEMP_2_PIN, TEMP_2)
_TCASE(HAS_TEMP_ADC_3, TEMP_3_PIN, TEMP_3)
_TCASE(HAS_TEMP_ADC_4, TEMP_4_PIN, TEMP_4)
_TCASE(HAS_TEMP_ADC_5, TEMP_5_PIN, TEMP_5)
_TCASE(HAS_TEMP_ADC_6, TEMP_6_PIN, TEMP_6)
_TCASE(HAS_TEMP_ADC_7, TEMP_7_PIN, TEMP_7)
_TCASE(HAS_HEATED_BED, TEMP_BED_PIN, TEMP_BED)
_TCASE(HAS_TEMP_CHAMBER, TEMP_CHAMBER_PIN, TEMP_CHAMBER)
_TCASE(HAS_TEMP_ADC_PROBE, TEMP_PROBE_PIN, TEMP_PROBE)
_TCASE(HAS_TEMP_COOLER, TEMP_COOLER_PIN, TEMP_COOLER)
_TCASE(HAS_TEMP_BOARD, TEMP_BOARD_PIN, TEMP_BOARD)
_TCASE(HAS_JOY_ADC_X, JOY_X_PIN, JOY_X)
_TCASE(HAS_JOY_ADC_Y, JOY_Y_PIN, JOY_Y)
_TCASE(HAS_JOY_ADC_Z, JOY_Z_PIN, JOY_Z)
_TCASE(FILAMENT_WIDTH_SENSOR, FILWIDTH_PIN, FILWIDTH)
_TCASE(HAS_ADC_BUTTONS, ADC_KEYPAD_PIN, ADC_KEY)
_TCASE(POWER_MONITOR_CURRENT, POWER_MONITOR_CURRENT_PIN, POWERMON_CURRENT)
_TCASE(POWER_MONITOR_VOLTAGE, POWER_MONITOR_VOLTAGE_PIN, POWERMON_VOLTS)
}
adc_result = (adc_results[(int)pin_index] & 0xFFF) >> (12 - HAL_ADC_RESOLUTION); // shift out unused bits
}
#endif // __STM32F1__

@ -0,0 +1,309 @@
/**
* Marlin 3D Printer Firmware
*
* Copyright (c) 2020 MarlinFirmware [https://github.com/MarlinFirmware/Marlin]
* Copyright (c) 2016 Bob Cousins bobcousins42@googlemail.com
* Copyright (c) 2015-2016 Nico Tonnhofer wurstnase.reprap@gmail.com
* Copyright (c) 2017 Victor Perez
*
* This 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 stm32duino.com based on Libmaple and compatible (STM32F1)
*/
#define CPU_32_BIT
#include "../../core/macros.h"
#include "../shared/Marduino.h"
#include "../shared/math_32bit.h"
#include "../shared/HAL_SPI.h"
#include "fastio.h"
#include <stdint.h>
#include <util/atomic.h>
#include "../../inc/MarlinConfigPre.h"
#if HAS_SD_HOST_DRIVE
#include "msc_sd.h"
#endif
#include "MarlinSerial.h"
// ------------------------
// Defines
// ------------------------
//
// Default graphical display delays
//
#define CPU_ST7920_DELAY_1 300
#define CPU_ST7920_DELAY_2 40
#define CPU_ST7920_DELAY_3 340
#ifndef STM32_FLASH_SIZE
#if ANY(MCU_STM32F103RE, MCU_STM32F103VE, MCU_STM32F103ZE)
#define STM32_FLASH_SIZE 512
#else
#define STM32_FLASH_SIZE 256
#endif
#endif
// ------------------------
// Serial ports
// ------------------------
#ifdef SERIAL_USB
typedef ForwardSerial1Class< USBSerial > DefaultSerial1;
extern DefaultSerial1 MSerial0;
#if HAS_SD_HOST_DRIVE
#define UsbSerial MarlinCompositeSerial
#else
#define UsbSerial MSerial0
#endif
#endif
#define _MSERIAL(X) MSerial##X
#define MSERIAL(X) _MSERIAL(X)
#if EITHER(STM32_HIGH_DENSITY, STM32_XL_DENSITY)
#define NUM_UARTS 5
#else
#define NUM_UARTS 3
#endif
#if SERIAL_PORT == -1
#define MYSERIAL1 UsbSerial
#elif WITHIN(SERIAL_PORT, 1, NUM_UARTS)
#define MYSERIAL1 MSERIAL(SERIAL_PORT)
#else
#define MYSERIAL1 MSERIAL(1) // dummy port
static_assert(false, "SERIAL_PORT must be from 1 to " STRINGIFY(NUM_UARTS) ". You can also use -1 if the board supports Native USB.")
#endif
#ifdef SERIAL_PORT_2
#if SERIAL_PORT_2 == -1
#define MYSERIAL2 UsbSerial
#elif WITHIN(SERIAL_PORT_2, 1, NUM_UARTS)
#define MYSERIAL2 MSERIAL(SERIAL_PORT_2)
#else
#define MYSERIAL2 MSERIAL(1) // dummy port
static_assert(false, "SERIAL_PORT_2 must be from 1 to " STRINGIFY(NUM_UARTS) ". You can also use -1 if the board supports Native USB.")
#endif
#endif
#ifdef SERIAL_PORT_3
#if SERIAL_PORT_3 == -1
#define MYSERIAL3 UsbSerial
#elif WITHIN(SERIAL_PORT_3, 1, NUM_UARTS)
#define MYSERIAL3 MSERIAL(SERIAL_PORT_3)
#else
#define MYSERIAL3 MSERIAL(1) // dummy port
static_assert(false, "SERIAL_PORT_3 must be from 1 to " STRINGIFY(NUM_UARTS) ". You can also use -1 if the board supports Native USB.")
#endif
#endif
#ifdef MMU2_SERIAL_PORT
#if MMU2_SERIAL_PORT == -1
#define MMU2_SERIAL UsbSerial
#elif WITHIN(MMU2_SERIAL_PORT, 1, NUM_UARTS)
#define MMU2_SERIAL MSERIAL(MMU2_SERIAL_PORT)
#else
#define MMU2_SERIAL MSERIAL(1) // dummy port
static_assert(false, "MMU2_SERIAL_PORT must be from 1 to " STRINGIFY(NUM_UARTS) ". You can also use -1 if the board supports Native USB.")
#endif
#endif
#ifdef LCD_SERIAL_PORT
#if LCD_SERIAL_PORT == -1
#define LCD_SERIAL UsbSerial
#elif WITHIN(LCD_SERIAL_PORT, 1, NUM_UARTS)
#define LCD_SERIAL MSERIAL(LCD_SERIAL_PORT)
#else
#define LCD_SERIAL MSERIAL(1) // dummy port
static_assert(false, "LCD_SERIAL_PORT must be from 1 to " STRINGIFY(NUM_UARTS) ". You can also use -1 if the board supports Native USB.")
#endif
#if HAS_DGUS_LCD
#define SERIAL_GET_TX_BUFFER_FREE() LCD_SERIAL.availableForWrite()
#endif
#endif
/**
* TODO: review this to return 1 for pins that are not analog input
*/
#ifndef analogInputToDigitalPin
#define analogInputToDigitalPin(p) (p)
#endif
#ifndef digitalPinHasPWM
#define digitalPinHasPWM(P) !!PIN_MAP[P].timer_device
#define NO_COMPILE_TIME_PWM
#endif
// Reset Reason
#define RST_POWER_ON 1
#define RST_EXTERNAL 2
#define RST_BROWN_OUT 4
#define RST_WATCHDOG 8
#define RST_JTAG 16
#define RST_SOFTWARE 32
#define RST_BACKUP 64
// ------------------------
// Types
// ------------------------
typedef int8_t pin_t;
// ------------------------
// Interrupts
// ------------------------
#define CRITICAL_SECTION_START() const bool irqon = !__get_primask(); (void)__iCliRetVal()
#define CRITICAL_SECTION_END() if (!irqon) (void)__iSeiRetVal()
#define cli() noInterrupts()
#define sei() interrupts()
// ------------------------
// ADC
// ------------------------
#ifdef ADC_RESOLUTION
#define HAL_ADC_RESOLUTION ADC_RESOLUTION
#else
#define HAL_ADC_RESOLUTION 12
#endif
#define HAL_ADC_VREF 3.3
uint16_t analogRead(const pin_t pin); // need hal.adc_enable() first
void analogWrite(const pin_t pin, int pwm_val8); // PWM only! mul by 257 in maple!?
//
// 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 JTAG_DISABLE() afio_cfg_debug_ports(AFIO_DEBUG_SW_ONLY)
#define JTAGSWD_DISABLE() afio_cfg_debug_ports(AFIO_DEBUG_NONE)
#define PLATFORM_M997_SUPPORT
void flashFirmware(const int16_t);
#define HAL_CAN_SET_PWM_FREQ // This HAL supports PWM Frequency adjustment
#ifndef PWM_FREQUENCY
#define PWM_FREQUENCY 1000 // Default PWM Frequency
#endif
// ------------------------
// Class Utilities
// ------------------------
// Memory related
#define __bss_end __bss_end__
void _delay_ms(const int ms);
extern "C" char* _sbrk(int incr);
#pragma GCC diagnostic push
#if GCC_VERSION <= 50000
#pragma GCC diagnostic ignored "-Wunused-function"
#endif
static inline int freeMemory() {
volatile char top;
return &top - _sbrk(0);
}
#pragma GCC diagnostic pop
// ------------------------
// MarlinHAL Class
// ------------------------
class MarlinHAL {
public:
// Earliest possible init, before setup()
MarlinHAL() {}
// Watchdog
static void watchdog_init() IF_DISABLED(USE_WATCHDOG, {});
static void watchdog_refresh() IF_DISABLED(USE_WATCHDOG, {});
static void init(); // Called early in setup()
static void init_board() {} // Called less early in setup()
static void reboot(); // Restart the firmware from 0x0
// Interrupts
static bool isr_state() { return !__get_primask(); }
static void isr_on() { ((void)__iSeiRetVal()); }
static void isr_off() { ((void)__iCliRetVal()); }
static void delay_ms(const int ms) { delay(ms); }
// Tasks, called from idle()
static void idletask();
// Reset
static uint8_t get_reset_source() { return RST_POWER_ON; }
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 pin_t pin) { pinMode(pin, INPUT_ANALOG); }
// Begin ADC sampling on the given pin. Called from Temperature::isr!
static void adc_start(const pin_t pin);
// Is the ADC ready for reading?
static bool adc_ready() { return true; }
// The current value of the ADC register
static uint16_t adc_value() { return adc_result; }
/**
* Set the PWM duty cycle for the pin to the given value.
* Optionally invert the duty cycle [default = false]
* Optionally change the maximum size of the provided value to enable finer PWM duty control [default = 255]
* The timer must be pre-configured with set_pwm_frequency() if the default frequency is not desired.
*/
static void set_pwm_duty(const pin_t pin, const uint16_t v, const uint16_t=255, const bool=false);
/**
* Set the frequency of the timer for the given pin.
* All Timer PWM pins run at the same frequency.
*/
static void set_pwm_frequency(const pin_t pin, const uint16_t f_desired);
};

@ -0,0 +1,171 @@
/**
* 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
* Copyright (c) 2017 Victor Perez
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
/**
* Software SPI functions originally from Arduino Sd2Card Library
* Copyright (c) 2009 by William Greiman
* Adapted to the STM32F1 HAL
*/
#ifdef __STM32F1__
#include "../../inc/MarlinConfig.h"
#include <SPI.h>
// ------------------------
// Public functions
// ------------------------
#if ENABLED(SOFTWARE_SPI)
// ------------------------
// Software SPI
// ------------------------
#error "Software SPI not supported for STM32F1. Use hardware SPI."
#else
// ------------------------
// Hardware SPI
// ------------------------
/**
* VGPV SPI speed start and F_CPU/2, by default 72/2 = 36Mhz
*/
/**
* @brief Begin SPI port setup
*
* @return Nothing
*
* @details Only configures SS pin since libmaple creates and initialize the SPI object
*/
void spiBegin() {
#if PIN_EXISTS(SD_SS)
OUT_WRITE(SD_SS_PIN, HIGH);
#endif
}
/**
* @brief Initialize SPI port to required speed rate and transfer mode (MSB, SPI MODE 0)
*
* @param spiRate Rate as declared in HAL.h (speed do not match AVR)
* @return Nothing
*
* @details
*/
void spiInit(uint8_t spiRate) {
/**
* STM32F1 APB2 = 72MHz, APB1 = 36MHz, max SPI speed of this MCU if 18Mhz
* STM32F1 has 3 SPI ports, SPI1 in APB2, SPI2/SPI3 in APB1
* so the minimum prescale of SPI1 is DIV4, SPI2/SPI3 is DIV2
*/
#if SPI_DEVICE == 1
#define SPI_CLOCK_MAX SPI_CLOCK_DIV4
#else
#define SPI_CLOCK_MAX SPI_CLOCK_DIV2
#endif
uint8_t clock;
switch (spiRate) {
case SPI_FULL_SPEED: clock = SPI_CLOCK_MAX ; break;
case SPI_HALF_SPEED: clock = SPI_CLOCK_DIV4 ; break;
case SPI_QUARTER_SPEED: clock = SPI_CLOCK_DIV8 ; break;
case SPI_EIGHTH_SPEED: clock = SPI_CLOCK_DIV16; break;
case SPI_SPEED_5: clock = SPI_CLOCK_DIV32; break;
case SPI_SPEED_6: clock = SPI_CLOCK_DIV64; break;
default: clock = SPI_CLOCK_DIV2; // Default from the SPI library
}
SPI.setModule(SPI_DEVICE);
SPI.begin();
SPI.setClockDivider(clock);
SPI.setBitOrder(MSBFIRST);
SPI.setDataMode(SPI_MODE0);
}
/**
* @brief Receive a single byte from the SPI port.
*
* @return Byte received
*
* @details
*/
uint8_t spiRec() {
uint8_t returnByte = SPI.transfer(0xFF);
return returnByte;
}
/**
* @brief Receive a number of bytes from the SPI port to a buffer
*
* @param buf Pointer to starting address of buffer to write to.
* @param nbyte Number of bytes to receive.
* @return Nothing
*
* @details Uses DMA
*/
void spiRead(uint8_t *buf, uint16_t nbyte) {
SPI.dmaTransfer(0, const_cast<uint8_t*>(buf), nbyte);
}
/**
* @brief Send a single byte on SPI port
*
* @param b Byte to send
*
* @details
*/
void spiSend(uint8_t b) {
SPI.send(b);
}
/**
* @brief Write token and then write from 512 byte buffer to SPI (for SD card)
*
* @param buf Pointer with buffer start address
* @return Nothing
*
* @details Use DMA
*/
void spiSendBlock(uint8_t token, const uint8_t *buf) {
SPI.send(token);
SPI.dmaSend(const_cast<uint8_t*>(buf), 512);
}
#if ENABLED(SPI_EEPROM)
// Read single byte from specified SPI channel
uint8_t spiRec(uint32_t chan) { return SPI.transfer(0xFF); }
// Write single byte to specified SPI channel
void spiSend(uint32_t chan, byte b) { SPI.send(b); }
// Write buffer to specified SPI channel
void spiSend(uint32_t chan, const uint8_t *buf, size_t n) {
for (size_t p = 0; p < n; p++) spiSend(chan, buf[p]);
}
#endif // SPI_EEPROM
#endif // SOFTWARE_SPI
#endif // __STM32F1__

@ -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
#include <SPI.h>
/**
* Marlin currently requires 3 SPI classes:
*
* SPIClass:
* This class is normally provided by frameworks and has a semi-default interface.
* This is needed because some libraries reference it globally.
*
* SPISettings:
* Container for SPI configs for SPIClass. As above, libraries may reference it globally.
*
* These two classes are often provided by frameworks so we cannot extend them to add
* useful methods for Marlin.
*
* MarlinSPI:
* Provides the default SPIClass interface plus some Marlin goodies such as a simplified
* interface for SPI DMA transfer.
*
*/
using MarlinSPI = SPIClass;

@ -0,0 +1,204 @@
/**
* 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 __STM32F1__
#include "../../inc/MarlinConfig.h"
#include "MarlinSerial.h"
#include <libmaple/usart.h>
// Copied from ~/.platformio/packages/framework-arduinoststm32-maple/STM32F1/system/libmaple/usart_private.h
// Changed to handle Emergency Parser
static inline __always_inline void my_usart_irq(ring_buffer *rb, ring_buffer *wb, usart_reg_map *regs, MSerialT &serial) {
/* Handle RXNEIE and TXEIE interrupts.
* RXNE signifies availability of a byte in DR.
*
* See table 198 (sec 27.4, p809) in STM document RM0008 rev 15.
* We enable RXNEIE.
*/
uint32_t srflags = regs->SR, cr1its = regs->CR1;
if ((cr1its & USART_CR1_RXNEIE) && (srflags & USART_SR_RXNE)) {
if (srflags & USART_SR_FE || srflags & USART_SR_PE ) {
// framing error or parity error
regs->DR; // Read and throw away the data, which also clears FE and PE
}
else {
uint8_t c = (uint8)regs->DR;
#ifdef USART_SAFE_INSERT
// If the buffer is full and the user defines USART_SAFE_INSERT,
// ignore new bytes.
rb_safe_insert(rb, c);
#else
// By default, push bytes around in the ring buffer.
rb_push_insert(rb, c);
#endif
#if ENABLED(EMERGENCY_PARSER)
if (serial.emergency_parser_enabled())
emergency_parser.update(serial.emergency_state, c);
#endif
}
}
else if (srflags & USART_SR_ORE) {
// overrun and empty data, just do a dummy read to clear ORE
// and prevent a raise condition where a continuous interrupt stream (due to ORE set) occurs
// (see chapter "Overrun error" ) in STM32 reference manual
regs->DR;
}
// TXE signifies readiness to send a byte to DR.
if ((cr1its & USART_CR1_TXEIE) && (srflags & USART_SR_TXE)) {
if (!rb_is_empty(wb))
regs->DR=rb_remove(wb);
else
regs->CR1 &= ~((uint32)USART_CR1_TXEIE); // disable TXEIE
}
}
// Not every MarlinSerial port should handle emergency parsing.
// It would not make sense to parse GCode from TMC responses, for example.
constexpr bool serial_handles_emergency(int port) {
return false
#ifdef SERIAL_PORT
|| (SERIAL_PORT) == port
#endif
#ifdef SERIAL_PORT_2
|| (SERIAL_PORT_2) == port
#endif
#ifdef LCD_SERIAL_PORT
|| (LCD_SERIAL_PORT) == port
#endif
;
}
#define DEFINE_HWSERIAL_MARLIN(name, n) \
MSerialT name(serial_handles_emergency(n),\
USART##n, \
BOARD_USART##n##_TX_PIN, \
BOARD_USART##n##_RX_PIN); \
extern "C" void __irq_usart##n(void) { \
my_usart_irq(USART##n->rb, USART##n->wb, USART##n##_BASE, MSerial##n); \
}
#define DEFINE_HWSERIAL_UART_MARLIN(name, n) \
MSerialT name(serial_handles_emergency(n), \
UART##n, \
BOARD_USART##n##_TX_PIN, \
BOARD_USART##n##_RX_PIN); \
extern "C" void __irq_usart##n(void) { \
my_usart_irq(UART##n->rb, UART##n->wb, UART##n##_BASE, MSerial##n); \
}
// Instantiate all UARTs even if they are not needed
// This avoids a bunch of logic to figure out every serial
// port which may be in use on the system.
#if DISABLED(MKS_WIFI_MODULE)
DEFINE_HWSERIAL_MARLIN(MSerial1, 1);
#endif
DEFINE_HWSERIAL_MARLIN(MSerial2, 2);
DEFINE_HWSERIAL_MARLIN(MSerial3, 3);
#if EITHER(STM32_HIGH_DENSITY, STM32_XL_DENSITY)
DEFINE_HWSERIAL_UART_MARLIN(MSerial4, 4);
DEFINE_HWSERIAL_UART_MARLIN(MSerial5, 5);
#endif
// Check the type of each serial port by passing it to a template function.
// HardwareSerial is known to sometimes hang the controller when an error occurs,
// so this case will fail the static assert. All other classes are assumed to be ok.
template <typename T>
constexpr bool IsSerialClassAllowed(const T&) { return true; }
constexpr bool IsSerialClassAllowed(const HardwareSerial&) { return false; }
#define CHECK_CFG_SERIAL(A) static_assert(IsSerialClassAllowed(A), STRINGIFY(A) " is defined incorrectly");
#define CHECK_AXIS_SERIAL(A) static_assert(IsSerialClassAllowed(A##_HARDWARE_SERIAL), STRINGIFY(A) "_HARDWARE_SERIAL must be defined in the form MSerial1, rather than Serial1");
// If you encounter this error, replace SerialX with MSerialX, for example MSerial3.
// Non-TMC ports were already validated in HAL.h, so do not require verbose error messages.
#ifdef MYSERIAL1
CHECK_CFG_SERIAL(MYSERIAL1);
#endif
#ifdef MYSERIAL2
CHECK_CFG_SERIAL(MYSERIAL2);
#endif
#ifdef LCD_SERIAL
CHECK_CFG_SERIAL(LCD_SERIAL);
#endif
#if AXIS_HAS_HW_SERIAL(X)
CHECK_AXIS_SERIAL(X);
#endif
#if AXIS_HAS_HW_SERIAL(X2)
CHECK_AXIS_SERIAL(X2);
#endif
#if AXIS_HAS_HW_SERIAL(Y)
CHECK_AXIS_SERIAL(Y);
#endif
#if AXIS_HAS_HW_SERIAL(Y2)
CHECK_AXIS_SERIAL(Y2);
#endif
#if AXIS_HAS_HW_SERIAL(Z)
CHECK_AXIS_SERIAL(Z);
#endif
#if AXIS_HAS_HW_SERIAL(Z2)
CHECK_AXIS_SERIAL(Z2);
#endif
#if AXIS_HAS_HW_SERIAL(Z3)
CHECK_AXIS_SERIAL(Z3);
#endif
#if AXIS_HAS_HW_SERIAL(Z4)
CHECK_AXIS_SERIAL(Z4);
#endif
#if AXIS_HAS_HW_SERIAL(I)
CHECK_AXIS_SERIAL(I);
#endif
#if AXIS_HAS_HW_SERIAL(J)
CHECK_AXIS_SERIAL(J);
#endif
#if AXIS_HAS_HW_SERIAL(K)
CHECK_AXIS_SERIAL(K);
#endif
#if AXIS_HAS_HW_SERIAL(E0)
CHECK_AXIS_SERIAL(E0);
#endif
#if AXIS_HAS_HW_SERIAL(E1)
CHECK_AXIS_SERIAL(E1);
#endif
#if AXIS_HAS_HW_SERIAL(E2)
CHECK_AXIS_SERIAL(E2);
#endif
#if AXIS_HAS_HW_SERIAL(E3)
CHECK_AXIS_SERIAL(E3);
#endif
#if AXIS_HAS_HW_SERIAL(E4)
CHECK_AXIS_SERIAL(E4);
#endif
#if AXIS_HAS_HW_SERIAL(E5)
CHECK_AXIS_SERIAL(E5);
#endif
#if AXIS_HAS_HW_SERIAL(E6)
CHECK_AXIS_SERIAL(E6);
#endif
#if AXIS_HAS_HW_SERIAL(E7)
CHECK_AXIS_SERIAL(E7);
#endif
#endif // __STM32F1__

@ -0,0 +1,58 @@
/**
* 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 <HardwareSerial.h>
#include <libmaple/usart.h>
#include <WString.h>
#include "../../inc/MarlinConfigPre.h"
#include "../../core/serial_hook.h"
// Increase priority of serial interrupts, to reduce overflow errors
#define UART_IRQ_PRIO 1
struct MarlinSerial : public HardwareSerial {
MarlinSerial(struct usart_dev *usart_device, uint8 tx_pin, uint8 rx_pin) : HardwareSerial(usart_device, tx_pin, rx_pin) { }
#ifdef UART_IRQ_PRIO
// Shadow the parent methods to set IRQ priority after begin()
void begin(uint32 baud) {
MarlinSerial::begin(baud, SERIAL_8N1);
}
void begin(uint32 baud, uint8_t config) {
HardwareSerial::begin(baud, config);
nvic_irq_set_priority(c_dev()->irq_num, UART_IRQ_PRIO);
}
#endif
};
typedef Serial1Class<MarlinSerial> MSerialT;
extern MSerialT MSerial1;
extern MSerialT MSerial2;
extern MSerialT MSerial3;
#if EITHER(STM32_HIGH_DENSITY, STM32_XL_DENSITY)
extern MSerialT MSerial4;
extern MSerialT MSerial5;
#endif

@ -0,0 +1,117 @@
/**
* 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
* Copyright (c) 2017 Victor Perez
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
#ifdef __STM32F1__
#include "../../inc/MarlinConfigPre.h"
#if ENABLED(POSTMORTEM_DEBUGGING)
#include "../shared/MinSerial.h"
#include <libmaple/usart.h>
#include <libmaple/rcc.h>
#include <libmaple/nvic.h>
/* Instruction Synchronization Barrier */
#define isb() __asm__ __volatile__ ("isb" : : : "memory")
/* Data Synchronization Barrier */
#define dsb() __asm__ __volatile__ ("dsb" : : : "memory")
static void TXBegin() {
#if !WITHIN(SERIAL_PORT, 1, 6)
#warning "Using POSTMORTEM_DEBUGGING requires a physical U(S)ART hardware in case of severe error."
#warning "Disabling the severe error reporting feature currently because the used serial port is not a HW port."
#else
// We use MYSERIAL1 here, so we need to figure out how to get the linked register
struct usart_dev* dev = MYSERIAL1.c_dev();
// Or use this if removing libmaple
// int irq = dev->irq_num;
// int nvicUART[] = { NVIC_USART1 /* = 37 */, NVIC_USART2 /* = 38 */, NVIC_USART3 /* = 39 */, NVIC_UART4 /* = 52 */, NVIC_UART5 /* = 53 */ };
// Disabling irq means setting the bit in the NVIC ICER register located at
// Disable UART interrupt in NVIC
nvic_irq_disable(dev->irq_num);
// Use this if removing libmaple
//SBI(NVIC_BASE->ICER[1], irq - 32);
// 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();
rcc_clk_disable(dev->clk_id);
rcc_clk_enable(dev->clk_id);
usart_reg_map *regs = dev->regs;
regs->CR1 = 0; // Reset the USART
regs->CR2 = 0; // 1 stop bit
// If we don't touch the BRR (baudrate register), we don't need to recompute. Else we would need to call
usart_set_baud_rate(dev, 0, BAUDRATE);
regs->CR1 = (USART_CR1_TE | USART_CR1_UE); // 8 bits, no parity, 1 stop bit
#endif
}
// A SW memory barrier, to ensure GCC does not overoptimize loops
#define sw_barrier() __asm__ volatile("": : :"memory");
static void TX(char c) {
#if WITHIN(SERIAL_PORT, 1, 6)
struct usart_dev* dev = MYSERIAL1.c_dev();
while (!(dev->regs->SR & USART_SR_TXE)) {
hal.watchdog_refresh();
sw_barrier();
}
dev->regs->DR = c;
#endif
}
void install_min_serial() {
HAL_min_serial_init = &TXBegin;
HAL_min_serial_out = &TX;
}
#if DISABLED(DYNAMIC_VECTORTABLE) && DISABLED(STM32F0xx) // Cortex M0 can't branch to a symbol that's too far, so we have a specific hack for them
extern "C" {
__attribute__((naked)) void JumpHandler_ASM() {
__asm__ __volatile__ (
"b CommonHandler_ASM\n"
);
}
void __attribute__((naked, alias("JumpHandler_ASM"), nothrow)) __exc_hardfault();
void __attribute__((naked, alias("JumpHandler_ASM"), nothrow)) __exc_busfault();
void __attribute__((naked, alias("JumpHandler_ASM"), nothrow)) __exc_usagefault();
void __attribute__((naked, alias("JumpHandler_ASM"), nothrow)) __exc_memmanage();
void __attribute__((naked, alias("JumpHandler_ASM"), nothrow)) __exc_nmi();
void __attribute__((naked, alias("JumpHandler_ASM"), nothrow)) __stm32reservedexception7();
void __attribute__((naked, alias("JumpHandler_ASM"), nothrow)) __stm32reservedexception8();
void __attribute__((naked, alias("JumpHandler_ASM"), nothrow)) __stm32reservedexception9();
void __attribute__((naked, alias("JumpHandler_ASM"), nothrow)) __stm32reservedexception10();
void __attribute__((naked, alias("JumpHandler_ASM"), nothrow)) __stm32reservedexception13();
}
#endif
#endif // POSTMORTEM_DEBUGGING
#endif // __STM32F1__

@ -0,0 +1,11 @@
# STM32F1
This HAL is for STM32F103 boards used with [Arduino STM32](https://github.com/rogerclarkmelbourne/Arduino_STM32) framework.
Currently has been tested in Malyan M200 (103CBT6), SKRmini (103RCT6), Chitu 3d (103ZET6), and various 103VET6 boards.
### Main developers:
- Victorpv
- xC000005
- thisiskeithb
- tpruvot

@ -0,0 +1,738 @@
/******************************************************************************
* The MIT License
*
* Copyright (c) 2010 Perry Hung.
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without
* restriction, including without limitation the rights to use, copy,
* modify, merge, publish, distribute, sublicense, and/or sell copies
* of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*****************************************************************************/
/**
* @author Marti Bolivar <mbolivar@leaflabs.com>
* @brief Wirish SPI implementation.
*/
#ifdef __STM32F1__
#include <SPI.h>
#include <libmaple/timer.h>
#include <libmaple/util.h>
#include <libmaple/rcc.h>
#include <boards.h>
#include <wirish.h>
#include "../../inc/MarlinConfig.h"
#include "spi_pins.h"
/** Time in ms for DMA receive timeout */
#define DMA_TIMEOUT 100
#if CYCLES_PER_MICROSECOND != 72
#warning "Unexpected clock speed; SPI frequency calculation will be incorrect"
#endif
struct spi_pins { uint8_t nss, sck, miso, mosi; };
static const spi_pins* dev_to_spi_pins(spi_dev *dev);
static void configure_gpios(spi_dev *dev, bool as_master);
static spi_baud_rate determine_baud_rate(spi_dev *dev, uint32_t freq);
#if BOARD_NR_SPI >= 3 && !defined(STM32_HIGH_DENSITY)
#error "The SPI library is misconfigured: 3 SPI ports only available on high density STM32 devices"
#endif
static const spi_pins board_spi_pins[] __FLASH__ = {
#if BOARD_NR_SPI >= 1
{ BOARD_SPI1_NSS_PIN,
BOARD_SPI1_SCK_PIN,
BOARD_SPI1_MISO_PIN,
BOARD_SPI1_MOSI_PIN },
#endif
#if BOARD_NR_SPI >= 2
{ BOARD_SPI2_NSS_PIN,
BOARD_SPI2_SCK_PIN,
BOARD_SPI2_MISO_PIN,
BOARD_SPI2_MOSI_PIN },
#endif
#if BOARD_NR_SPI >= 3
{ BOARD_SPI3_NSS_PIN,
BOARD_SPI3_SCK_PIN,
BOARD_SPI3_MISO_PIN,
BOARD_SPI3_MOSI_PIN },
#endif
};
#if BOARD_NR_SPI >= 1
static void *_spi1_this;
#endif
#if BOARD_NR_SPI >= 2
static void *_spi2_this;
#endif
#if BOARD_NR_SPI >= 3
static void *_spi3_this;
#endif
/**
* @brief Wait until TXE (tx empty) flag is set and BSY (busy) flag unset.
*/
static inline void waitSpiTxEnd(spi_dev *spi_d) {
while (spi_is_tx_empty(spi_d) == 0) { /* nada */ } // wait until TXE=1
while (spi_is_busy(spi_d) != 0) { /* nada */ } // wait until BSY=0
}
/**
* Constructor
*/
SPIClass::SPIClass(uint32_t spi_num) {
_currentSetting = &_settings[spi_num - 1]; // SPI channels are called 1 2 and 3 but the array is zero indexed
switch (spi_num) {
#if BOARD_NR_SPI >= 1
case 1:
_currentSetting->spi_d = SPI1;
_spi1_this = (void*)this;
break;
#endif
#if BOARD_NR_SPI >= 2
case 2:
_currentSetting->spi_d = SPI2;
_spi2_this = (void*)this;
break;
#endif
#if BOARD_NR_SPI >= 3
case 3:
_currentSetting->spi_d = SPI3;
_spi3_this = (void*)this;
break;
#endif
default: ASSERT(0);
}
// Init things specific to each SPI device
// clock divider setup is a bit of hack, and needs to be improved at a later date.
#if BOARD_NR_SPI >= 1
_settings[0].spi_d = SPI1;
_settings[0].clockDivider = determine_baud_rate(_settings[0].spi_d, _settings[0].clock);
_settings[0].spiDmaDev = DMA1;
_settings[0].spiTxDmaChannel = DMA_CH3;
_settings[0].spiRxDmaChannel = DMA_CH2;
#endif
#if BOARD_NR_SPI >= 2
_settings[1].spi_d = SPI2;
_settings[1].clockDivider = determine_baud_rate(_settings[1].spi_d, _settings[1].clock);
_settings[1].spiDmaDev = DMA1;
_settings[1].spiTxDmaChannel = DMA_CH5;
_settings[1].spiRxDmaChannel = DMA_CH4;
#endif
#if BOARD_NR_SPI >= 3
_settings[2].spi_d = SPI3;
_settings[2].clockDivider = determine_baud_rate(_settings[2].spi_d, _settings[2].clock);
_settings[2].spiDmaDev = DMA2;
_settings[2].spiTxDmaChannel = DMA_CH2;
_settings[2].spiRxDmaChannel = DMA_CH1;
#endif
// added for DMA callbacks.
_currentSetting->state = SPI_STATE_IDLE;
}
SPIClass::SPIClass(int8_t mosi, int8_t miso, int8_t sclk, int8_t ssel) : SPIClass(1) {
#if BOARD_NR_SPI >= 1
if (mosi == BOARD_SPI1_MOSI_PIN) setModule(1);
#endif
#if BOARD_NR_SPI >= 2
if (mosi == BOARD_SPI2_MOSI_PIN) setModule(2);
#endif
#if BOARD_NR_SPI >= 3
if (mosi == BOARD_SPI3_MOSI_PIN) setModule(3);
#endif
}
/**
* Set up/tear down
*/
void SPIClass::updateSettings() {
uint32_t flags = ((_currentSetting->bitOrder == MSBFIRST ? SPI_FRAME_MSB : SPI_FRAME_LSB) | _currentSetting->dataSize | SPI_SW_SLAVE | SPI_SOFT_SS);
spi_master_enable(_currentSetting->spi_d, (spi_baud_rate)_currentSetting->clockDivider, (spi_mode)_currentSetting->dataMode, flags);
}
void SPIClass::begin() {
spi_init(_currentSetting->spi_d);
configure_gpios(_currentSetting->spi_d, 1);
updateSettings();
// added for DMA callbacks.
_currentSetting->state = SPI_STATE_READY;
}
void SPIClass::beginSlave() {
spi_init(_currentSetting->spi_d);
configure_gpios(_currentSetting->spi_d, 0);
uint32_t flags = ((_currentSetting->bitOrder == MSBFIRST ? SPI_FRAME_MSB : SPI_FRAME_LSB) | _currentSetting->dataSize);
spi_slave_enable(_currentSetting->spi_d, (spi_mode)_currentSetting->dataMode, flags);
// added for DMA callbacks.
_currentSetting->state = SPI_STATE_READY;
}
void SPIClass::end() {
if (!spi_is_enabled(_currentSetting->spi_d)) return;
// Follows RM0008's sequence for disabling a SPI in master/slave
// full duplex mode.
while (spi_is_rx_nonempty(_currentSetting->spi_d)) {
// FIXME [0.1.0] remove this once you have an interrupt based driver
volatile uint16_t rx __attribute__((unused)) = spi_rx_reg(_currentSetting->spi_d);
}
waitSpiTxEnd(_currentSetting->spi_d);
spi_peripheral_disable(_currentSetting->spi_d);
// added for DMA callbacks.
// Need to add unsetting the callbacks for the DMA channels.
_currentSetting->state = SPI_STATE_IDLE;
}
/* Roger Clark added 3 functions */
void SPIClass::setClockDivider(uint32_t clockDivider) {
_currentSetting->clockDivider = clockDivider;
uint32_t cr1 = _currentSetting->spi_d->regs->CR1 & ~(SPI_CR1_BR);
_currentSetting->spi_d->regs->CR1 = cr1 | (clockDivider & SPI_CR1_BR);
}
void SPIClass::setBitOrder(BitOrder bitOrder) {
_currentSetting->bitOrder = bitOrder;
uint32_t cr1 = _currentSetting->spi_d->regs->CR1 & ~(SPI_CR1_LSBFIRST);
if (bitOrder == LSBFIRST) cr1 |= SPI_CR1_LSBFIRST;
_currentSetting->spi_d->regs->CR1 = cr1;
}
/**
* Victor Perez. Added to test changing datasize from 8 to 16 bit modes on the fly.
* Input parameter should be SPI_CR1_DFF set to 0 or 1 on a 32bit word.
*/
void SPIClass::setDataSize(uint32_t datasize) {
_currentSetting->dataSize = datasize;
uint32_t cr1 = _currentSetting->spi_d->regs->CR1 & ~(SPI_CR1_DFF);
uint8_t en = spi_is_enabled(_currentSetting->spi_d);
spi_peripheral_disable(_currentSetting->spi_d);
_currentSetting->spi_d->regs->CR1 = cr1 | (datasize & SPI_CR1_DFF) | en;
}
void SPIClass::setDataMode(uint8_t dataMode) {
/**
* Notes:
* As far as we know the AVR numbers for dataMode match the numbers required by the STM32.
* From the AVR doc https://www.atmel.com/images/doc2585.pdf section 2.4
*
* SPI Mode CPOL CPHA Shift SCK-edge Capture SCK-edge
* 0 0 0 Falling Rising
* 1 0 1 Rising Falling
* 2 1 0 Rising Falling
* 3 1 1 Falling Rising
*
* On the STM32 it appears to be
*
* bit 1 - CPOL : Clock polarity
* (This bit should not be changed when communication is ongoing)
* 0 : CLK to 0 when idle
* 1 : CLK to 1 when idle
*
* bit 0 - CPHA : Clock phase
* (This bit should not be changed when communication is ongoing)
* 0 : The first clock transition is the first data capture edge
* 1 : The second clock transition is the first data capture edge
*
* If someone finds this is not the case or sees a logic error with this let me know ;-)
*/
_currentSetting->dataMode = dataMode;
uint32_t cr1 = _currentSetting->spi_d->regs->CR1 & ~(SPI_CR1_CPOL|SPI_CR1_CPHA);
_currentSetting->spi_d->regs->CR1 = cr1 | (dataMode & (SPI_CR1_CPOL|SPI_CR1_CPHA));
}
void SPIClass::beginTransaction(uint8_t pin, const SPISettings &settings) {
setBitOrder(settings.bitOrder);
setDataMode(settings.dataMode);
setDataSize(settings.dataSize);
setClockDivider(determine_baud_rate(_currentSetting->spi_d, settings.clock));
begin();
}
void SPIClass::beginTransactionSlave(const SPISettings &settings) {
setBitOrder(settings.bitOrder);
setDataMode(settings.dataMode);
setDataSize(settings.dataSize);
beginSlave();
}
void SPIClass::endTransaction() { }
/**
* I/O
*/
uint16_t SPIClass::read() {
while (!spi_is_rx_nonempty(_currentSetting->spi_d)) { /* nada */ }
return (uint16_t)spi_rx_reg(_currentSetting->spi_d);
}
void SPIClass::read(uint8_t *buf, uint32_t len) {
if (len == 0) return;
spi_rx_reg(_currentSetting->spi_d); // clear the RX buffer in case a byte is waiting on it.
spi_reg_map * regs = _currentSetting->spi_d->regs;
// start sequence: write byte 0
regs->DR = 0x00FF; // write the first byte
// main loop
while (--len) {
while (!(regs->SR & SPI_SR_TXE)) { /* nada */ } // wait for TXE flag
noInterrupts(); // go atomic level - avoid interrupts to surely get the previously received data
regs->DR = 0x00FF; // write the next data item to be transmitted into the SPI_DR register. This clears the TXE flag.
while (!(regs->SR & SPI_SR_RXNE)) { /* nada */ } // wait till data is available in the DR register
*buf++ = (uint8)(regs->DR); // read and store the received byte. This clears the RXNE flag.
interrupts(); // let systick do its job
}
// read remaining last byte
while (!(regs->SR & SPI_SR_RXNE)) { /* nada */ } // wait till data is available in the Rx register
*buf++ = (uint8)(regs->DR); // read and store the received byte
}
void SPIClass::write(uint16_t data) {
/* Added for 16bit data Victor Perez. Roger Clark
* Improved speed by just directly writing the single byte to the SPI data reg and wait for completion,
* by taking the Tx code from transfer(byte)
* This almost doubles the speed of this function.
*/
spi_tx_reg(_currentSetting->spi_d, data); // write the data to be transmitted into the SPI_DR register (this clears the TXE flag)
waitSpiTxEnd(_currentSetting->spi_d);
}
void SPIClass::write16(uint16_t data) {
// Added by stevestrong: write two consecutive bytes in 8 bit mode (DFF=0)
spi_tx_reg(_currentSetting->spi_d, data>>8); // write high byte
while (!spi_is_tx_empty(_currentSetting->spi_d)) { /* nada */ } // Wait until TXE=1
spi_tx_reg(_currentSetting->spi_d, data); // write low byte
waitSpiTxEnd(_currentSetting->spi_d);
}
void SPIClass::write(uint16_t data, uint32_t n) {
// Added by stevstrong: Repeatedly send same data by the specified number of times
spi_reg_map * regs = _currentSetting->spi_d->regs;
while (n--) {
regs->DR = data; // write the data to be transmitted into the SPI_DR register (this clears the TXE flag)
while (!(regs->SR & SPI_SR_TXE)) { /* nada */ } // wait till Tx empty
}
while (regs->SR & SPI_SR_BSY) { /* nada */ } // wait until BSY=0 before returning
}
void SPIClass::write(const void *data, uint32_t length) {
spi_dev * spi_d = _currentSetting->spi_d;
spi_tx(spi_d, data, length); // data can be array of bytes or words
waitSpiTxEnd(spi_d);
}
uint8_t SPIClass::transfer(uint8_t byte) const {
spi_dev * spi_d = _currentSetting->spi_d;
spi_rx_reg(spi_d); // read any previous data
spi_tx_reg(spi_d, byte); // Write the data item to be transmitted into the SPI_DR register
waitSpiTxEnd(spi_d);
return (uint8)spi_rx_reg(spi_d); // "... and read the last received data."
}
uint16_t SPIClass::transfer16(uint16_t data) const {
// Modified by stevestrong: write & read two consecutive bytes in 8 bit mode (DFF=0)
// This is more effective than two distinct byte transfers
spi_dev * spi_d = _currentSetting->spi_d;
spi_rx_reg(spi_d); // read any previous data
spi_tx_reg(spi_d, data>>8); // write high byte
waitSpiTxEnd(spi_d); // wait until TXE=1 and then wait until BSY=0
uint16_t ret = spi_rx_reg(spi_d)<<8; // read and shift high byte
spi_tx_reg(spi_d, data); // write low byte
waitSpiTxEnd(spi_d); // wait until TXE=1 and then wait until BSY=0
ret += spi_rx_reg(spi_d); // read low byte
return ret;
}
/**
* Roger Clark and Victor Perez, 2015
* Performs a DMA SPI transfer with at least a receive buffer.
* If a TX buffer is not provided, FF is sent over and over for the length of the transfer.
* On exit TX buffer is not modified, and RX buffer contains the received data.
* Still in progress.
*/
void SPIClass::dmaTransferSet(const void *transmitBuf, void *receiveBuf) {
dma_init(_currentSetting->spiDmaDev);
//spi_rx_dma_enable(_currentSetting->spi_d);
//spi_tx_dma_enable(_currentSetting->spi_d);
dma_xfer_size dma_bit_size = (_currentSetting->dataSize==DATA_SIZE_16BIT) ? DMA_SIZE_16BITS : DMA_SIZE_8BITS;
dma_setup_transfer(_currentSetting->spiDmaDev, _currentSetting->spiRxDmaChannel, &_currentSetting->spi_d->regs->DR,
dma_bit_size, receiveBuf, dma_bit_size, (DMA_MINC_MODE | DMA_TRNS_CMPLT ));// receive buffer DMA
if (!transmitBuf) {
transmitBuf = &ff;
dma_setup_transfer(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel, &_currentSetting->spi_d->regs->DR,
dma_bit_size, (volatile void*)transmitBuf, dma_bit_size, (DMA_FROM_MEM));// Transmit FF repeatedly
}
else {
dma_setup_transfer(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel, &_currentSetting->spi_d->regs->DR,
dma_bit_size, (volatile void*)transmitBuf, dma_bit_size, (DMA_MINC_MODE | DMA_FROM_MEM ));// Transmit buffer DMA
}
dma_set_priority(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel, DMA_PRIORITY_LOW);
dma_set_priority(_currentSetting->spiDmaDev, _currentSetting->spiRxDmaChannel, DMA_PRIORITY_VERY_HIGH);
}
uint8_t SPIClass::dmaTransferRepeat(uint16_t length) {
if (length == 0) return 0;
if (spi_is_rx_nonempty(_currentSetting->spi_d) == 1) spi_rx_reg(_currentSetting->spi_d);
_currentSetting->state = SPI_STATE_TRANSFER;
dma_set_num_transfers(_currentSetting->spiDmaDev, _currentSetting->spiRxDmaChannel, length);
dma_set_num_transfers(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel, length);
dma_enable(_currentSetting->spiDmaDev, _currentSetting->spiRxDmaChannel);// enable receive
dma_enable(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel);// enable transmit
spi_rx_dma_enable(_currentSetting->spi_d);
spi_tx_dma_enable(_currentSetting->spi_d);
if (_currentSetting->receiveCallback)
return 0;
//uint32_t m = millis();
uint8_t b = 0;
uint32_t m = millis();
while (!(dma_get_isr_bits(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel) & DMA_ISR_TCIF1)) {
// Avoid interrupts and just loop waiting for the flag to be set.
if ((millis() - m) > DMA_TIMEOUT) { b = 2; break; }
}
waitSpiTxEnd(_currentSetting->spi_d); // until TXE=1 and BSY=0
spi_tx_dma_disable(_currentSetting->spi_d);
spi_rx_dma_disable(_currentSetting->spi_d);
dma_disable(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel);
dma_disable(_currentSetting->spiDmaDev, _currentSetting->spiRxDmaChannel);
dma_clear_isr_bits(_currentSetting->spiDmaDev, _currentSetting->spiRxDmaChannel);
dma_clear_isr_bits(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel);
_currentSetting->state = SPI_STATE_READY;
return b;
}
/**
* Roger Clark and Victor Perez, 2015
* Performs a DMA SPI transfer with at least a receive buffer.
* If a TX buffer is not provided, FF is sent over and over for the length of the transfer.
* On exit TX buffer is not modified, and RX buffer contains the received data.
* Still in progress.
*/
uint8_t SPIClass::dmaTransfer(const void *transmitBuf, void *receiveBuf, uint16_t length) {
dmaTransferSet(transmitBuf, receiveBuf);
return dmaTransferRepeat(length);
}
/**
* Roger Clark and Victor Perez, 2015
* Performs a DMA SPI send using a TX buffer.
* On exit TX buffer is not modified.
* Still in progress.
* 2016 - stevstrong - reworked to automatically detect bit size from SPI setting
*/
void SPIClass::dmaSendSet(const void * transmitBuf, bool minc) {
uint32_t flags = ( (DMA_MINC_MODE*minc) | DMA_FROM_MEM | DMA_TRNS_CMPLT);
dma_init(_currentSetting->spiDmaDev);
dma_xfer_size dma_bit_size = (_currentSetting->dataSize==DATA_SIZE_16BIT) ? DMA_SIZE_16BITS : DMA_SIZE_8BITS;
dma_setup_transfer(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel, &_currentSetting->spi_d->regs->DR, dma_bit_size,
(volatile void*)transmitBuf, dma_bit_size, flags);// Transmit buffer DMA
dma_set_priority(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel, DMA_PRIORITY_LOW);
}
uint8_t SPIClass::dmaSendRepeat(uint16_t length) {
if (length == 0) return 0;
dma_clear_isr_bits(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel);
dma_set_num_transfers(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel, length);
_currentSetting->state = SPI_STATE_TRANSMIT;
dma_enable(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel); // enable transmit
spi_tx_dma_enable(_currentSetting->spi_d);
if (_currentSetting->transmitCallback) return 0;
uint32_t m = millis();
uint8_t b = 0;
while (!(dma_get_isr_bits(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel) & DMA_ISR_TCIF1)) {
// Avoid interrupts and just loop waiting for the flag to be set.
if ((millis() - m) > DMA_TIMEOUT) { b = 2; break; }
}
waitSpiTxEnd(_currentSetting->spi_d); // until TXE=1 and BSY=0
spi_tx_dma_disable(_currentSetting->spi_d);
dma_disable(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel);
dma_clear_isr_bits(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel);
_currentSetting->state = SPI_STATE_READY;
return b;
}
uint8_t SPIClass::dmaSend(const void * transmitBuf, uint16_t length, bool minc) {
dmaSendSet(transmitBuf, minc);
return dmaSendRepeat(length);
}
uint8_t SPIClass::dmaSendAsync(const void * transmitBuf, uint16_t length, bool minc) {
uint8_t b = 0;
if (_currentSetting->state != SPI_STATE_READY) {
uint32_t m = millis();
while (!(dma_get_isr_bits(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel) & DMA_ISR_TCIF1)) {
//Avoid interrupts and just loop waiting for the flag to be set.
//delayMicroseconds(10);
if ((millis() - m) > DMA_TIMEOUT) { b = 2; break; }
}
waitSpiTxEnd(_currentSetting->spi_d); // until TXE=1 and BSY=0
spi_tx_dma_disable(_currentSetting->spi_d);
dma_disable(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel);
_currentSetting->state = SPI_STATE_READY;
}
if (length == 0) return 0;
uint32_t flags = ( (DMA_MINC_MODE*minc) | DMA_FROM_MEM | DMA_TRNS_CMPLT);
dma_init(_currentSetting->spiDmaDev);
// TX
dma_xfer_size dma_bit_size = (_currentSetting->dataSize==DATA_SIZE_16BIT) ? DMA_SIZE_16BITS : DMA_SIZE_8BITS;
dma_setup_transfer(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel, &_currentSetting->spi_d->regs->DR,
dma_bit_size, (volatile void*)transmitBuf, dma_bit_size, flags);// Transmit buffer DMA
dma_set_num_transfers(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel, length);
dma_clear_isr_bits(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel);
dma_enable(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel);// enable transmit
spi_tx_dma_enable(_currentSetting->spi_d);
_currentSetting->state = SPI_STATE_TRANSMIT;
return b;
}
/**
* New functions added to manage callbacks.
* Victor Perez 2017
*/
void SPIClass::onReceive(void(*callback)()) {
_currentSetting->receiveCallback = callback;
if (callback) {
switch (_currentSetting->spi_d->clk_id) {
#if BOARD_NR_SPI >= 1
case RCC_SPI1:
dma_attach_interrupt(_currentSetting->spiDmaDev, _currentSetting->spiRxDmaChannel, &SPIClass::_spi1EventCallback);
break;
#endif
#if BOARD_NR_SPI >= 2
case RCC_SPI2:
dma_attach_interrupt(_currentSetting->spiDmaDev, _currentSetting->spiRxDmaChannel, &SPIClass::_spi2EventCallback);
break;
#endif
#if BOARD_NR_SPI >= 3
case RCC_SPI3:
dma_attach_interrupt(_currentSetting->spiDmaDev, _currentSetting->spiRxDmaChannel, &SPIClass::_spi3EventCallback);
break;
#endif
default:
ASSERT(0);
}
}
else {
dma_detach_interrupt(_currentSetting->spiDmaDev, _currentSetting->spiRxDmaChannel);
}
}
void SPIClass::onTransmit(void(*callback)()) {
_currentSetting->transmitCallback = callback;
if (callback) {
switch (_currentSetting->spi_d->clk_id) {
#if BOARD_NR_SPI >= 1
case RCC_SPI1:
dma_attach_interrupt(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel, &SPIClass::_spi1EventCallback);
break;
#endif
#if BOARD_NR_SPI >= 2
case RCC_SPI2:
dma_attach_interrupt(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel, &SPIClass::_spi2EventCallback);
break;
#endif
#if BOARD_NR_SPI >= 3
case RCC_SPI3:
dma_attach_interrupt(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel, &SPIClass::_spi3EventCallback);
break;
#endif
default:
ASSERT(0);
}
}
else {
dma_detach_interrupt(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel);
}
}
/**
* TODO: check if better to first call the customer code, next disable the DMA requests.
* Also see if we need to check whether callbacks are set or not, may be better to be checked
* during the initial setup and only set the callback to EventCallback if they are set.
*/
void SPIClass::EventCallback() {
waitSpiTxEnd(_currentSetting->spi_d);
switch (_currentSetting->state) {
case SPI_STATE_TRANSFER:
while (spi_is_rx_nonempty(_currentSetting->spi_d)) { /* nada */ }
_currentSetting->state = SPI_STATE_READY;
spi_tx_dma_disable(_currentSetting->spi_d);
spi_rx_dma_disable(_currentSetting->spi_d);
//dma_disable(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel);
//dma_disable(_currentSetting->spiDmaDev, _currentSetting->spiRxDmaChannel);
if (_currentSetting->receiveCallback)
_currentSetting->receiveCallback();
break;
case SPI_STATE_TRANSMIT:
_currentSetting->state = SPI_STATE_READY;
spi_tx_dma_disable(_currentSetting->spi_d);
//dma_disable(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel);
if (_currentSetting->transmitCallback)
_currentSetting->transmitCallback();
break;
default:
break;
}
}
void SPIClass::attachInterrupt() {
// Should be enableInterrupt()
}
void SPIClass::detachInterrupt() {
// Should be disableInterrupt()
}
/**
* Pin accessors
*/
uint8_t SPIClass::misoPin() {
return dev_to_spi_pins(_currentSetting->spi_d)->miso;
}
uint8_t SPIClass::mosiPin() {
return dev_to_spi_pins(_currentSetting->spi_d)->mosi;
}
uint8_t SPIClass::sckPin() {
return dev_to_spi_pins(_currentSetting->spi_d)->sck;
}
uint8_t SPIClass::nssPin() {
return dev_to_spi_pins(_currentSetting->spi_d)->nss;
}
/**
* Deprecated functions
*/
uint8_t SPIClass::send(uint8_t data) { write(data); return 1; }
uint8_t SPIClass::send(uint8_t *buf, uint32_t len) { write(buf, len); return len; }
uint8_t SPIClass::recv() { return read(); }
/**
* DMA call back functions, one per port.
*/
#if BOARD_NR_SPI >= 1
void SPIClass::_spi1EventCallback() {
reinterpret_cast<class SPIClass*>(_spi1_this)->EventCallback();
}
#endif
#if BOARD_NR_SPI >= 2
void SPIClass::_spi2EventCallback() {
reinterpret_cast<class SPIClass*>(_spi2_this)->EventCallback();
}
#endif
#if BOARD_NR_SPI >= 3
void SPIClass::_spi3EventCallback() {
reinterpret_cast<class SPIClass*>(_spi3_this)->EventCallback();
}
#endif
/**
* Auxiliary functions
*/
static const spi_pins* dev_to_spi_pins(spi_dev *dev) {
switch (dev->clk_id) {
#if BOARD_NR_SPI >= 1
case RCC_SPI1: return board_spi_pins;
#endif
#if BOARD_NR_SPI >= 2
case RCC_SPI2: return board_spi_pins + 1;
#endif
#if BOARD_NR_SPI >= 3
case RCC_SPI3: return board_spi_pins + 2;
#endif
default: return nullptr;
}
}
static void disable_pwm(const stm32_pin_info *i) {
if (i->timer_device)
timer_set_mode(i->timer_device, i->timer_channel, TIMER_DISABLED);
}
static void configure_gpios(spi_dev *dev, bool as_master) {
const spi_pins *pins = dev_to_spi_pins(dev);
if (!pins) return;
const stm32_pin_info *nssi = &PIN_MAP[pins->nss],
*scki = &PIN_MAP[pins->sck],
*misoi = &PIN_MAP[pins->miso],
*mosii = &PIN_MAP[pins->mosi];
disable_pwm(nssi);
disable_pwm(scki);
disable_pwm(misoi);
disable_pwm(mosii);
spi_config_gpios(dev, as_master, nssi->gpio_device, nssi->gpio_bit,
scki->gpio_device, scki->gpio_bit, misoi->gpio_bit,
mosii->gpio_bit);
}
static const spi_baud_rate baud_rates[8] __FLASH__ = {
SPI_BAUD_PCLK_DIV_2,
SPI_BAUD_PCLK_DIV_4,
SPI_BAUD_PCLK_DIV_8,
SPI_BAUD_PCLK_DIV_16,
SPI_BAUD_PCLK_DIV_32,
SPI_BAUD_PCLK_DIV_64,
SPI_BAUD_PCLK_DIV_128,
SPI_BAUD_PCLK_DIV_256,
};
/**
* Note: This assumes you're on a LeafLabs-style board
* (CYCLES_PER_MICROSECOND == 72, APB2 at 72MHz, APB1 at 36MHz).
*/
static spi_baud_rate determine_baud_rate(spi_dev *dev, uint32_t freq) {
uint32_t clock = 0;
switch (rcc_dev_clk(dev->clk_id)) {
case RCC_AHB:
case RCC_APB2: clock = STM32_PCLK2; break; // 72 Mhz
case RCC_APB1: clock = STM32_PCLK1; break; // 36 Mhz
}
clock >>= 1;
uint8_t i = 0;
while (i < 7 && freq < clock) { clock >>= 1; i++; }
return baud_rates[i];
}
SPIClass SPI(SPI_DEVICE);
#endif // __STM32F1__

@ -0,0 +1,417 @@
/******************************************************************************
* The MIT License
*
* Copyright (c) 2010 Perry Hung.
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without
* restriction, including without limitation the rights to use, copy,
* modify, merge, publish, distribute, sublicense, and/or sell copies
* of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*****************************************************************************/
#pragma once
#include <libmaple/libmaple_types.h>
#include <libmaple/spi.h>
#include <libmaple/dma.h>
#include <boards.h>
#include <stdint.h>
#include <wirish.h>
// SPI_HAS_TRANSACTION means SPI has
// - beginTransaction()
// - endTransaction()
// - usingInterrupt()
// - SPISetting(clock, bitOrder, dataMode)
//#define SPI_HAS_TRANSACTION
#define SPI_CLOCK_DIV2 SPI_BAUD_PCLK_DIV_2
#define SPI_CLOCK_DIV4 SPI_BAUD_PCLK_DIV_4
#define SPI_CLOCK_DIV8 SPI_BAUD_PCLK_DIV_8
#define SPI_CLOCK_DIV16 SPI_BAUD_PCLK_DIV_16
#define SPI_CLOCK_DIV32 SPI_BAUD_PCLK_DIV_32
#define SPI_CLOCK_DIV64 SPI_BAUD_PCLK_DIV_64
#define SPI_CLOCK_DIV128 SPI_BAUD_PCLK_DIV_128
#define SPI_CLOCK_DIV256 SPI_BAUD_PCLK_DIV_256
/*
* Roger Clark. 20150106
* Commented out redundant AVR defined
*
#define SPI_MODE_MASK 0x0C // CPOL = bit 3, CPHA = bit 2 on SPCR
#define SPI_CLOCK_MASK 0x03 // SPR1 = bit 1, SPR0 = bit 0 on SPCR
#define SPI_2XCLOCK_MASK 0x01 // SPI2X = bit 0 on SPSR
// define SPI_AVR_EIMSK for AVR boards with external interrupt pins
#ifdef EIMSK
#define SPI_AVR_EIMSK EIMSK
#elif defined(GICR)
#define SPI_AVR_EIMSK GICR
#elif defined(GIMSK)
#define SPI_AVR_EIMSK GIMSK
#endif
*/
#ifndef STM32_LSBFIRST
#define STM32_LSBFIRST 0
#endif
#ifndef STM32_MSBFIRST
#define STM32_MSBFIRST 1
#endif
// PC13 or PA4
#define BOARD_SPI_DEFAULT_SS PA4
//#define BOARD_SPI_DEFAULT_SS PC13
#define SPI_MODE0 SPI_MODE_0
#define SPI_MODE1 SPI_MODE_1
#define SPI_MODE2 SPI_MODE_2
#define SPI_MODE3 SPI_MODE_3
#define DATA_SIZE_8BIT SPI_CR1_DFF_8_BIT
#define DATA_SIZE_16BIT SPI_CR1_DFF_16_BIT
typedef enum {
SPI_STATE_IDLE,
SPI_STATE_READY,
SPI_STATE_RECEIVE,
SPI_STATE_TRANSMIT,
SPI_STATE_TRANSFER
} spi_mode_t;
class SPISettings {
public:
SPISettings(uint32_t inClock, BitOrder inBitOrder, uint8_t inDataMode) {
if (__builtin_constant_p(inClock))
init_AlwaysInline(inClock, inBitOrder, inDataMode, DATA_SIZE_8BIT);
else
init_MightInline(inClock, inBitOrder, inDataMode, DATA_SIZE_8BIT);
}
SPISettings(uint32_t inClock, BitOrder inBitOrder, uint8_t inDataMode, uint32_t inDataSize) {
if (__builtin_constant_p(inClock))
init_AlwaysInline(inClock, inBitOrder, inDataMode, inDataSize);
else
init_MightInline(inClock, inBitOrder, inDataMode, inDataSize);
}
SPISettings(uint32_t inClock) {
if (__builtin_constant_p(inClock))
init_AlwaysInline(inClock, MSBFIRST, SPI_MODE0, DATA_SIZE_8BIT);
else
init_MightInline(inClock, MSBFIRST, SPI_MODE0, DATA_SIZE_8BIT);
}
SPISettings() {
init_AlwaysInline(4000000, MSBFIRST, SPI_MODE0, DATA_SIZE_8BIT);
}
private:
void init_MightInline(uint32_t inClock, BitOrder inBitOrder, uint8_t inDataMode, uint32_t inDataSize) {
init_AlwaysInline(inClock, inBitOrder, inDataMode, inDataSize);
}
void init_AlwaysInline(uint32_t inClock, BitOrder inBitOrder, uint8_t inDataMode, uint32_t inDataSize) __attribute__((__always_inline__)) {
clock = inClock;
bitOrder = inBitOrder;
dataMode = inDataMode;
dataSize = inDataSize;
//state = SPI_STATE_IDLE;
}
uint32_t clock;
uint32_t dataSize;
uint32_t clockDivider;
BitOrder bitOrder;
uint8_t dataMode;
uint8_t _SSPin;
volatile spi_mode_t state;
spi_dev *spi_d;
dma_channel spiRxDmaChannel, spiTxDmaChannel;
dma_dev* spiDmaDev;
void (*receiveCallback)() = nullptr;
void (*transmitCallback)() = nullptr;
friend class SPIClass;
};
/*
* Kept for compat.
*/
static const uint8_t ff = 0xFF;
/**
* @brief Wirish SPI interface.
*
* This implementation uses software slave management, so the caller
* is responsible for controlling the slave select line.
*/
class SPIClass {
public:
/**
* @param spiPortNumber Number of the SPI port to manage.
*/
SPIClass(uint32_t spiPortNumber);
/**
* Init using pins
*/
SPIClass(int8_t mosi, int8_t miso, int8_t sclk, int8_t ssel=-1);
/**
* @brief Equivalent to begin(SPI_1_125MHZ, MSBFIRST, 0).
*/
void begin();
/**
* @brief Turn on a SPI port and set its GPIO pin modes for use as a slave.
*
* SPI port is enabled in full duplex mode, with software slave management.
*
* @param bitOrder Either LSBFIRST (little-endian) or MSBFIRST(big-endian)
* @param mode SPI mode to use
*/
void beginSlave(uint32_t bitOrder, uint32_t mode);
/**
* @brief Equivalent to beginSlave(MSBFIRST, 0).
*/
void beginSlave();
/**
* @brief Disables the SPI port, but leaves its GPIO pin modes unchanged.
*/
void end();
void beginTransaction(const SPISettings &settings) { beginTransaction(BOARD_SPI_DEFAULT_SS, settings); }
void beginTransaction(uint8_t pin, const SPISettings &settings);
void endTransaction();
void beginTransactionSlave(const SPISettings &settings);
void setClockDivider(uint32_t clockDivider);
void setBitOrder(BitOrder bitOrder);
void setDataMode(uint8_t dataMode);
// SPI Configuration methods
void attachInterrupt();
void detachInterrupt();
/* Victor Perez. Added to change datasize from 8 to 16 bit modes on the fly.
* Input parameter should be SPI_CR1_DFF set to 0 or 1 on a 32bit word.
* Requires an added function spi_data_size on STM32F1 / cores / maple / libmaple / spi.c
*/
void setDataSize(uint32_t ds);
uint32_t getDataSize() { return _currentSetting->dataSize; }
/* Victor Perez 2017. Added to set and clear callback functions for callback
* on DMA transfer completion.
* onReceive used to set the callback in case of dmaTransfer (tx/rx), once rx is completed
* onTransmit used to set the callback in case of dmaSend (tx only). That function
* will NOT be called in case of TX/RX
*/
void onReceive(void(*)());
void onTransmit(void(*)());
/*
* I/O
*/
/**
* @brief Return the next unread byte/word.
*
* If there is no unread byte/word waiting, this function will block
* until one is received.
*/
uint16_t read();
/**
* @brief Read length bytes, storing them into buffer.
* @param buffer Buffer to store received bytes into.
* @param length Number of bytes to store in buffer. This
* function will block until the desired number of
* bytes have been read.
*/
void read(uint8_t *buffer, uint32_t length);
/**
* @brief Transmit one byte/word.
* @param data to transmit.
*/
void write(uint16_t data);
void write16(uint16_t data); // write 2 bytes in 8 bit mode (DFF=0)
/**
* @brief Transmit one byte/word a specified number of times.
* @param data to transmit.
*/
void write(uint16_t data, uint32_t n);
/**
* @brief Transmit multiple bytes/words.
* @param buffer Bytes/words to transmit.
* @param length Number of bytes/words in buffer to transmit.
*/
void write(const void * buffer, uint32_t length);
/**
* @brief Transmit a byte, then return the next unread byte.
*
* This function transmits before receiving.
*
* @param data Byte to transmit.
* @return Next unread byte.
*/
uint8_t transfer(uint8_t data) const;
uint16_t transfer16(uint16_t data) const;
/**
* @brief Sets up a DMA Transfer for "length" bytes.
* The transfer mode (8 or 16 bit mode) is evaluated from the SPI peripheral setting.
*
* This function transmits and receives to buffers.
*
* @param transmitBuf buffer Bytes to transmit. If passed as 0, it sends FF repeatedly for "length" bytes
* @param receiveBuf buffer Bytes to save received data.
* @param length Number of bytes in buffer to transmit.
*/
uint8_t dmaTransfer(const void * transmitBuf, void * receiveBuf, uint16_t length);
void dmaTransferSet(const void *transmitBuf, void *receiveBuf);
uint8_t dmaTransferRepeat(uint16_t length);
/**
* @brief Sets up a DMA Transmit for SPI 8 or 16 bit transfer mode.
* The transfer mode (8 or 16 bit mode) is evaluated from the SPI peripheral setting.
*
* This function only transmits and does not care about the RX fifo.
*
* @param data buffer half words to transmit,
* @param length Number of bytes in buffer to transmit.
* @param minc Set to use Memory Increment mode, clear to use Circular mode.
*/
uint8_t dmaSend(const void * transmitBuf, uint16_t length, bool minc = 1);
void dmaSendSet(const void * transmitBuf, bool minc);
uint8_t dmaSendRepeat(uint16_t length);
uint8_t dmaSendAsync(const void * transmitBuf, uint16_t length, bool minc = 1);
/*
* Pin accessors
*/
/**
* @brief Return the number of the MISO (master in, slave out) pin
*/
uint8_t misoPin();
/**
* @brief Return the number of the MOSI (master out, slave in) pin
*/
uint8_t mosiPin();
/**
* @brief Return the number of the SCK (serial clock) pin
*/
uint8_t sckPin();
/**
* @brief Return the number of the NSS (slave select) pin
*/
uint8_t nssPin();
/* Escape hatch */
/**
* @brief Get a pointer to the underlying libmaple spi_dev for
* this HardwareSPI instance.
*/
spi_dev* c_dev() { return _currentSetting->spi_d; }
spi_dev* dev() { return _currentSetting->spi_d; }
/**
* @brief Sets the number of the SPI peripheral to be used by
* this HardwareSPI instance.
*
* @param spi_num Number of the SPI port. 1-2 in low density devices
* or 1-3 in high density devices.
*/
void setModule(int spi_num) {
_currentSetting = &_settings[spi_num - 1];// SPI channels are called 1 2 and 3 but the array is zero indexed
}
/* -- The following methods are deprecated --------------------------- */
/**
* @brief Deprecated.
*
* Use HardwareSPI::transfer() instead.
*
* @see HardwareSPI::transfer()
*/
uint8_t send(uint8_t data);
/**
* @brief Deprecated.
*
* Use HardwareSPI::write() in combination with
* HardwareSPI::read() (or HardwareSPI::transfer()) instead.
*
* @see HardwareSPI::write()
* @see HardwareSPI::read()
* @see HardwareSPI::transfer()
*/
uint8_t send(uint8_t *data, uint32_t length);
/**
* @brief Deprecated.
*
* Use HardwareSPI::read() instead.
*
* @see HardwareSPI::read()
*/
uint8_t recv();
private:
SPISettings _settings[BOARD_NR_SPI];
SPISettings *_currentSetting;
void updateSettings();
/*
* Functions added for DMA transfers with Callback.
* Experimental.
*/
void EventCallback();
#if BOARD_NR_SPI >= 1
static void _spi1EventCallback();
#endif
#if BOARD_NR_SPI >= 2
static void _spi2EventCallback();
#endif
#if BOARD_NR_SPI >= 3
static void _spi3EventCallback();
#endif
/*
spi_dev *spi_d;
uint8_t _SSPin;
uint32_t clockDivider;
uint8_t dataMode;
BitOrder bitOrder;
*/
};
extern SPIClass SPI;

@ -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
* Copyright (c) 2017 Victor Perez
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
#ifdef __STM32F1__
#include "../../inc/MarlinConfig.h"
#if HAS_SERVOS
uint8_t ServoCount = 0;
#include "Servo.h"
//#include "Servo.h"
#include <boards.h>
#include <io.h>
#include <pwm.h>
#include <wirish_math.h>
/**
* 20 millisecond period config. For a 1-based prescaler,
*
* (prescaler * overflow / CYC_MSEC) msec = 1 timer cycle = 20 msec
* => prescaler * overflow = 20 * CYC_MSEC
*
* This uses the smallest prescaler that allows an overflow < 2^16.
*/
#define MAX_OVERFLOW UINT16_MAX // _BV(16) - 1
#define CYC_MSEC (1000 * CYCLES_PER_MICROSECOND)
#define TAU_MSEC 20
#define TAU_USEC (TAU_MSEC * 1000)
#define TAU_CYC (TAU_MSEC * CYC_MSEC)
#define SERVO_PRESCALER (TAU_CYC / MAX_OVERFLOW + 1)
#define SERVO_OVERFLOW ((uint16_t)round((double)TAU_CYC / SERVO_PRESCALER))
// Unit conversions
#define US_TO_COMPARE(us) uint16_t(map((us), 0, TAU_USEC, 0, SERVO_OVERFLOW))
#define COMPARE_TO_US(c) uint32_t(map((c), 0, SERVO_OVERFLOW, 0, TAU_USEC))
#define ANGLE_TO_US(a) uint16_t(map((a), minAngle, maxAngle, SERVO_DEFAULT_MIN_PW, SERVO_DEFAULT_MAX_PW))
#define US_TO_ANGLE(us) int16_t(map((us), SERVO_DEFAULT_MIN_PW, SERVO_DEFAULT_MAX_PW, minAngle, maxAngle))
void libServo::servoWrite(uint8_t inPin, uint16_t duty_cycle) {
#ifdef MF_TIMER_SERVO0
if (servoIndex == 0) {
pwmSetDuty(duty_cycle);
return;
}
#endif
timer_dev *tdev = PIN_MAP[inPin].timer_device;
uint8_t tchan = PIN_MAP[inPin].timer_channel;
if (tdev) timer_set_compare(tdev, tchan, duty_cycle);
}
libServo::libServo() {
servoIndex = ServoCount < MAX_SERVOS ? ServoCount++ : INVALID_SERVO;
HAL_timer_set_interrupt_priority(MF_TIMER_SERVO0, SERVO0_TIMER_IRQ_PRIO);
}
bool libServo::attach(const int32_t inPin, const int32_t inMinAngle, const int32_t inMaxAngle) {
if (servoIndex >= MAX_SERVOS) return false;
if (inPin >= BOARD_NR_GPIO_PINS) return false;
minAngle = inMinAngle;
maxAngle = inMaxAngle;
angle = -1;
#ifdef MF_TIMER_SERVO0
if (servoIndex == 0 && setupSoftPWM(inPin)) {
pin = inPin; // set attached()
return true;
}
#endif
if (!PWM_PIN(inPin)) return false;
timer_dev *tdev = PIN_MAP[inPin].timer_device;
//uint8_t tchan = PIN_MAP[inPin].timer_channel;
SET_PWM(inPin);
servoWrite(inPin, 0);
timer_pause(tdev);
timer_set_prescaler(tdev, SERVO_PRESCALER - 1); // prescaler is 1-based
timer_set_reload(tdev, SERVO_OVERFLOW);
timer_generate_update(tdev);
timer_resume(tdev);
pin = inPin; // set attached()
return true;
}
bool libServo::detach() {
if (!attached()) return false;
angle = -1;
servoWrite(pin, 0);
return true;
}
int32_t libServo::read() const {
if (attached()) {
#ifdef MF_TIMER_SERVO0
if (servoIndex == 0) return angle;
#endif
timer_dev *tdev = PIN_MAP[pin].timer_device;
uint8_t tchan = PIN_MAP[pin].timer_channel;
return US_TO_ANGLE(COMPARE_TO_US(timer_get_compare(tdev, tchan)));
}
return 0;
}
void libServo::move(const int32_t value) {
constexpr uint16_t servo_delay[] = SERVO_DELAY;
static_assert(COUNT(servo_delay) == NUM_SERVOS, "SERVO_DELAY must be an array NUM_SERVOS long.");
if (attached()) {
angle = constrain(value, minAngle, maxAngle);
servoWrite(pin, US_TO_COMPARE(ANGLE_TO_US(angle)));
safe_delay(servo_delay[servoIndex]);
TERN_(DEACTIVATE_SERVOS_AFTER_MOVE, detach());
}
}
#ifdef MF_TIMER_SERVO0
extern "C" void Servo_IRQHandler() {
static timer_dev *tdev = HAL_get_timer_dev(MF_TIMER_SERVO0);
uint16_t SR = timer_get_status(tdev);
if (SR & TIMER_SR_CC1IF) { // channel 1 off
#ifdef SERVO0_PWM_OD
OUT_WRITE_OD(SERVO0_PIN, HIGH); // off
#else
OUT_WRITE(SERVO0_PIN, LOW);
#endif
timer_reset_status_bit(tdev, TIMER_SR_CC1IF_BIT);
}
if (SR & TIMER_SR_CC2IF) { // channel 2 resume
#ifdef SERVO0_PWM_OD
OUT_WRITE_OD(SERVO0_PIN, LOW); // on
#else
OUT_WRITE(SERVO0_PIN, HIGH);
#endif
timer_reset_status_bit(tdev, TIMER_SR_CC2IF_BIT);
}
}
bool libServo::setupSoftPWM(const int32_t inPin) {
timer_dev *tdev = HAL_get_timer_dev(MF_TIMER_SERVO0);
if (!tdev) return false;
#ifdef SERVO0_PWM_OD
OUT_WRITE_OD(inPin, HIGH);
#else
OUT_WRITE(inPin, LOW);
#endif
timer_pause(tdev);
timer_set_mode(tdev, 1, TIMER_OUTPUT_COMPARE); // counter with isr
timer_oc_set_mode(tdev, 1, TIMER_OC_MODE_FROZEN, 0); // no pin output change
timer_oc_set_mode(tdev, 2, TIMER_OC_MODE_FROZEN, 0); // no pin output change
timer_set_prescaler(tdev, SERVO_PRESCALER - 1); // prescaler is 1-based
timer_set_reload(tdev, SERVO_OVERFLOW);
timer_set_compare(tdev, 1, SERVO_OVERFLOW);
timer_set_compare(tdev, 2, SERVO_OVERFLOW);
timer_attach_interrupt(tdev, 1, Servo_IRQHandler);
timer_attach_interrupt(tdev, 2, Servo_IRQHandler);
timer_generate_update(tdev);
timer_resume(tdev);
return true;
}
void libServo::pwmSetDuty(const uint16_t duty_cycle) {
timer_dev *tdev = HAL_get_timer_dev(MF_TIMER_SERVO0);
timer_set_compare(tdev, 1, duty_cycle);
timer_generate_update(tdev);
if (duty_cycle) {
timer_enable_irq(tdev, 1);
timer_enable_irq(tdev, 2);
}
else {
timer_disable_irq(tdev, 1);
timer_disable_irq(tdev, 2);
#ifdef SERVO0_PWM_OD
OUT_WRITE_OD(pin, HIGH); // off
#else
OUT_WRITE(pin, LOW);
#endif
}
}
void libServo::pauseSoftPWM() { // detach
timer_dev *tdev = HAL_get_timer_dev(MF_TIMER_SERVO0);
timer_pause(tdev);
pwmSetDuty(0);
}
#else
bool libServo::setupSoftPWM(const int32_t inPin) { return false; }
void libServo::pwmSetDuty(const uint16_t duty_cycle) {}
void libServo::pauseSoftPWM() {}
#endif
#endif // HAS_SERVOS
#endif // __STM32F1__

@ -0,0 +1,61 @@
/**
* 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
* Copyright (c) 2017 Victor Perez
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
#pragma once
// Pin number of unattached pins
#define NOT_ATTACHED (-1)
#define INVALID_SERVO 255
#ifndef MAX_SERVOS
#define MAX_SERVOS 3
#endif
#define SERVO_DEFAULT_MIN_PW 544
#define SERVO_DEFAULT_MAX_PW 2400
#define SERVO_DEFAULT_MIN_ANGLE 0
#define SERVO_DEFAULT_MAX_ANGLE 180
class libServo;
typedef libServo hal_servo_t;
class libServo {
public:
libServo();
bool attach(const int32_t pin, const int32_t minAngle=SERVO_DEFAULT_MIN_ANGLE, const int32_t maxAngle=SERVO_DEFAULT_MAX_ANGLE);
bool attached() const { return pin != NOT_ATTACHED; }
bool detach();
void move(const int32_t value);
int32_t read() const;
private:
void servoWrite(uint8_t pin, const uint16_t duty_cycle);
uint8_t servoIndex; // index into the channel data for this servo
int32_t pin = NOT_ATTACHED;
int32_t minAngle;
int32_t maxAngle;
int32_t angle;
bool setupSoftPWM(const int32_t pin);
void pauseSoftPWM();
void pwmSetDuty(const uint16_t duty_cycle);
};

@ -0,0 +1,56 @@
from __future__ import print_function
import sys
#dynamic build flags for generic compile options
if __name__ == "__main__":
args = " ".join([ "-std=gnu++14",
"-Os",
"-mcpu=cortex-m3",
"-mthumb",
"-fsigned-char",
"-fno-move-loop-invariants",
"-fno-strict-aliasing",
"-fsingle-precision-constant",
"--specs=nano.specs",
"--specs=nosys.specs",
"-IMarlin/src/HAL/STM32F1",
"-MMD",
"-MP",
"-DTARGET_STM32F1"
])
for i in range(1, len(sys.argv)):
args += " " + sys.argv[i]
print(args)
# extra script for linker options
else:
import pioutil
if pioutil.is_pio_build():
from SCons.Script import DefaultEnvironment
env = DefaultEnvironment()
env.Append(
ARFLAGS=["rcs"],
ASFLAGS=["-x", "assembler-with-cpp"],
CXXFLAGS=[
"-fabi-version=0",
"-fno-use-cxa-atexit",
"-fno-threadsafe-statics"
],
LINKFLAGS=[
"-Os",
"-mcpu=cortex-m3",
"-ffreestanding",
"-mthumb",
"--specs=nano.specs",
"--specs=nosys.specs",
"-u_printf_float",
],
)

@ -0,0 +1,170 @@
/**
* 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 __STM32F1__
#include "../../../inc/MarlinConfig.h"
#if BOTH(HAS_MARLINUI_U8GLIB, FORCE_SOFT_SPI)
#include <U8glib-HAL.h>
#include "../../shared/HAL_SPI.h"
#ifndef LCD_SPI_SPEED
#define LCD_SPI_SPEED SPI_FULL_SPEED // Fastest
//#define LCD_SPI_SPEED SPI_QUARTER_SPEED // Slower
#endif
static uint8_t SPI_speed = LCD_SPI_SPEED;
static inline uint8_t swSpiTransfer_mode_0(uint8_t b, const uint8_t spi_speed, const pin_t miso_pin=-1) {
LOOP_L_N(i, 8) {
if (spi_speed == 0) {
WRITE(DOGLCD_MOSI, !!(b & 0x80));
WRITE(DOGLCD_SCK, HIGH);
b <<= 1;
if (miso_pin >= 0 && READ(miso_pin)) b |= 1;
WRITE(DOGLCD_SCK, LOW);
}
else {
const uint8_t state = (b & 0x80) ? HIGH : LOW;
LOOP_L_N(j, spi_speed)
WRITE(DOGLCD_MOSI, state);
LOOP_L_N(j, spi_speed + (miso_pin >= 0 ? 0 : 1))
WRITE(DOGLCD_SCK, HIGH);
b <<= 1;
if (miso_pin >= 0 && READ(miso_pin)) b |= 1;
LOOP_L_N(j, spi_speed)
WRITE(DOGLCD_SCK, LOW);
}
}
return b;
}
static inline uint8_t swSpiTransfer_mode_3(uint8_t b, const uint8_t spi_speed, const pin_t miso_pin=-1) {
LOOP_L_N(i, 8) {
const uint8_t state = (b & 0x80) ? HIGH : LOW;
if (spi_speed == 0) {
WRITE(DOGLCD_SCK, LOW);
WRITE(DOGLCD_MOSI, state);
WRITE(DOGLCD_MOSI, state); // need some setup time
WRITE(DOGLCD_SCK, HIGH);
}
else {
LOOP_L_N(j, spi_speed + (miso_pin >= 0 ? 0 : 1))
WRITE(DOGLCD_SCK, LOW);
LOOP_L_N(j, spi_speed)
WRITE(DOGLCD_MOSI, state);
LOOP_L_N(j, spi_speed)
WRITE(DOGLCD_SCK, HIGH);
}
b <<= 1;
if (miso_pin >= 0 && READ(miso_pin)) b |= 1;
}
return b;
}
static void u8g_sw_spi_HAL_STM32F1_shift_out(uint8_t val) {
#if ENABLED(FYSETC_MINI_12864)
swSpiTransfer_mode_3(val, SPI_speed);
#else
swSpiTransfer_mode_0(val, SPI_speed);
#endif
}
static uint8_t swSpiInit(const uint8_t spi_speed) {
#if PIN_EXISTS(LCD_RESET)
SET_OUTPUT(LCD_RESET_PIN);
#endif
SET_OUTPUT(DOGLCD_A0);
OUT_WRITE(DOGLCD_SCK, LOW);
OUT_WRITE(DOGLCD_MOSI, LOW);
OUT_WRITE(DOGLCD_CS, HIGH);
return spi_speed;
}
uint8_t u8g_com_HAL_STM32F1_sw_spi_fn(u8g_t *u8g, uint8_t msg, uint8_t arg_val, void *arg_ptr) {
switch (msg) {
case U8G_COM_MSG_INIT:
SPI_speed = swSpiInit(LCD_SPI_SPEED);
break;
case U8G_COM_MSG_STOP:
break;
case U8G_COM_MSG_RESET:
#if PIN_EXISTS(LCD_RESET)
WRITE(LCD_RESET_PIN, arg_val);
#endif
break;
case U8G_COM_MSG_CHIP_SELECT:
#if ENABLED(FYSETC_MINI_12864) // This LCD SPI is running mode 3 while SD card is running mode 0
if (arg_val) { // SCK idle state needs to be set to the proper idle state before
// the next chip select goes active
WRITE(DOGLCD_SCK, HIGH); // Set SCK to mode 3 idle state before CS goes active
WRITE(DOGLCD_CS, LOW);
}
else {
WRITE(DOGLCD_CS, HIGH);
WRITE(DOGLCD_SCK, LOW); // Set SCK to mode 0 idle state after CS goes inactive
}
#else
WRITE(DOGLCD_CS, !arg_val);
#endif
break;
case U8G_COM_MSG_WRITE_BYTE:
u8g_sw_spi_HAL_STM32F1_shift_out(arg_val);
break;
case U8G_COM_MSG_WRITE_SEQ: {
uint8_t *ptr = (uint8_t *)arg_ptr;
while (arg_val > 0) {
u8g_sw_spi_HAL_STM32F1_shift_out(*ptr++);
arg_val--;
}
} break;
case U8G_COM_MSG_WRITE_SEQ_P: {
uint8_t *ptr = (uint8_t *)arg_ptr;
while (arg_val > 0) {
u8g_sw_spi_HAL_STM32F1_shift_out(u8g_pgm_read(ptr));
ptr++;
arg_val--;
}
} break;
case U8G_COM_MSG_ADDRESS: /* define cmd (arg_val = 0) or data mode (arg_val = 1) */
WRITE(DOGLCD_A0, arg_val);
break;
}
return 1;
}
#endif // HAS_MARLINUI_U8GLIB && FORCE_SOFT_SPI
#endif // STM32F1

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

@ -0,0 +1,113 @@
/**
* Marlin 3D Printer Firmware
*
* Copyright (c) 2020 MarlinFirmware [https://github.com/MarlinFirmware/Marlin]
* Copyright (c) 2016 Bob Cousins bobcousins42@googlemail.com
* Copyright (c) 2015-2016 Nico Tonnhofer wurstnase.reprap@gmail.com
* Copyright (c) 2016 Victor Perez victor_pv@hotmail.com
*
* This 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/>.
*
*/
/**
* persistent_store_flash.cpp
* HAL for stm32duino and compatible (STM32F1)
* Implementation of EEPROM settings in SDCard
*/
#ifdef __STM32F1__
#include "../../inc/MarlinConfig.h"
#if ENABLED(FLASH_EEPROM_EMULATION)
#include "../shared/eeprom_api.h"
#include <flash_stm32.h>
#include <EEPROM.h>
// Store settings in the last two pages
#ifndef MARLIN_EEPROM_SIZE
#define MARLIN_EEPROM_SIZE ((EEPROM_PAGE_SIZE) * 2)
#endif
size_t PersistentStore::capacity() { return MARLIN_EEPROM_SIZE; }
static uint8_t ram_eeprom[MARLIN_EEPROM_SIZE] __attribute__((aligned(4))) = {0};
static bool eeprom_dirty = false;
bool PersistentStore::access_start() {
const uint32_t *source = reinterpret_cast<const uint32_t*>(EEPROM_PAGE0_BASE);
uint32_t *destination = reinterpret_cast<uint32_t*>(ram_eeprom);
static_assert(0 == (MARLIN_EEPROM_SIZE) % 4, "MARLIN_EEPROM_SIZE is corrupted. (Must be a multiple of 4.)"); // Ensure copying as uint32_t is safe
constexpr size_t eeprom_size_u32 = (MARLIN_EEPROM_SIZE) / 4;
for (size_t i = 0; i < eeprom_size_u32; ++i, ++destination, ++source)
*destination = *source;
eeprom_dirty = false;
return true;
}
bool PersistentStore::access_finish() {
if (eeprom_dirty) {
FLASH_Status status;
// Instead of erasing all (both) pages, maybe in the loop we check what page we are in, and if the
// data has changed in that page. We then erase the first time we "detect" a change. In theory, if
// nothing changed in a page, we wouldn't need to erase/write it.
// Or, instead of checking at this point, turn eeprom_dirty into an array of bool the size of number
// of pages. Inside write_data, we set the flag to true at that time if something in that
// page changes...either way, something to look at later.
FLASH_Unlock();
#define ACCESS_FINISHED(TF) { FLASH_Lock(); eeprom_dirty = false; return TF; }
status = FLASH_ErasePage(EEPROM_PAGE0_BASE);
if (status != FLASH_COMPLETE) ACCESS_FINISHED(true);
status = FLASH_ErasePage(EEPROM_PAGE1_BASE);
if (status != FLASH_COMPLETE) ACCESS_FINISHED(true);
const uint16_t *source = reinterpret_cast<const uint16_t*>(ram_eeprom);
for (size_t i = 0; i < MARLIN_EEPROM_SIZE; i += 2, ++source) {
if (FLASH_ProgramHalfWord(EEPROM_PAGE0_BASE + i, *source) != FLASH_COMPLETE)
ACCESS_FINISHED(false);
}
ACCESS_FINISHED(true);
}
return true;
}
bool PersistentStore::write_data(int &pos, const uint8_t *value, size_t size, uint16_t *crc) {
for (size_t i = 0; i < size; ++i) ram_eeprom[pos + i] = value[i];
eeprom_dirty = true;
crc16(crc, value, size);
pos += size;
return false; // return true for any error
}
bool PersistentStore::read_data(int &pos, uint8_t *value, const size_t size, uint16_t *crc, const bool writing/*=true*/) {
const uint8_t * const buff = writing ? &value[0] : &ram_eeprom[pos];
if (writing) for (size_t i = 0; i < size; i++) value[i] = ram_eeprom[pos + i];
crc16(crc, buff, size);
pos += size;
return false; // return true for any error
}
#endif // FLASH_EEPROM_EMULATION
#endif // __STM32F1__

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

Loading…
Cancel
Save