Compare commits
506 commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4c6d754c50 | ||
|
|
fa095b35c0 | ||
|
|
9d4bdb8a01 | ||
|
|
9c667a4409 | ||
|
|
e99eb502ae | ||
|
|
a2151f384e | ||
|
|
0d46fb5839 | ||
|
|
4a5f9f7aae | ||
|
|
bdd8ee911b | ||
|
|
a029d61925 | ||
|
|
fad2d91143 | ||
|
|
6a59e8347d | ||
|
|
e6c07cc7d0 | ||
|
|
814a352588 | ||
|
|
4888cdc958 | ||
|
|
a0d7cfdebc | ||
|
|
bdf5ac8117 | ||
|
|
28cbc716e4 | ||
|
|
028ca90052 | ||
|
|
9ba4e98237 | ||
|
|
8d3b49bf39 | ||
|
|
c044ba3929 | ||
|
|
9827155244 | ||
|
|
287d079c4d | ||
|
|
d1c52f223b | ||
|
|
1ba7379107 | ||
|
|
66097a89e7 | ||
|
|
731adc71be | ||
|
|
1264ec61d7 | ||
|
|
83b63b1e83 | ||
|
|
aa5fa81bb7 | ||
|
|
1e92424a50 | ||
|
|
37a6ab97fa | ||
|
|
94e908c453 | ||
|
|
420b9a8429 | ||
|
|
fd40287bcb | ||
|
|
66b0a74073 | ||
|
|
55a9930808 | ||
|
|
134ebe7e18 | ||
|
|
528a25e0ab | ||
|
|
adc0866b7d | ||
|
|
eb3c11472c | ||
|
|
77321a6827 | ||
|
|
a2801a1602 | ||
|
|
25a57896c0 | ||
|
|
00dd2e0097 | ||
|
|
ea9f1a5d28 | ||
|
|
b1572ceb25 | ||
|
|
0947169772 | ||
|
|
d9e9508be4 | ||
|
|
76f0206f01 | ||
|
|
860bc6c6b9 | ||
|
|
3f0f35fbc5 | ||
|
|
4141fce796 | ||
|
|
2555c2d68a | ||
|
|
57db4d7132 | ||
|
|
50f9be1544 | ||
|
|
4b669eadb0 | ||
|
|
2569103e1a | ||
|
|
196a29fc90 | ||
|
|
53c92d46e9 | ||
|
|
290f3d6308 | ||
|
|
246c75a1ae | ||
|
|
00a863c100 | ||
|
|
ff82b735f2 | ||
|
|
fdddb19a3c | ||
|
|
bdf0c84109 | ||
|
|
dad77cd8cc | ||
|
|
52d793ed8e | ||
|
|
e607c3ddbe | ||
|
|
6d6e5b1ee9 | ||
|
|
d60ec0fae3 | ||
|
|
159ae8e550 | ||
|
|
d56901d13b | ||
|
|
a45b5c56f6 | ||
|
|
6c2a982c35 | ||
|
|
aa9792167d | ||
|
|
72ebc1a809 | ||
|
|
f564235648 | ||
|
|
bf24e95f7e | ||
|
|
1112d77c3d | ||
|
|
aa21fb1e13 | ||
|
|
18e455f2df | ||
|
|
bfba9812b7 | ||
|
|
5b24029000 | ||
|
|
a5271b3d1c | ||
|
|
b13e6c68b5 | ||
|
|
f55ecadb78 | ||
|
|
b09a92698a | ||
|
|
6be91634fd | ||
|
|
12c4506437 | ||
|
|
c68c0b19ae | ||
|
|
5cbfd74f4d | ||
|
|
1a89b145ef | ||
|
|
e1e7b37ff3 | ||
|
|
4276526c67 | ||
|
|
a2dd8614d4 | ||
|
|
3253d46f45 | ||
|
|
d5935a8c51 | ||
|
|
4f80972c23 | ||
|
|
9ab68e1aff | ||
|
|
155cbc5262 | ||
|
|
622d9f6183 | ||
|
|
cb97944642 | ||
|
|
bee96c4a80 | ||
|
|
8afd0523b1 | ||
|
|
52c988fea0 | ||
|
|
70d3c1dbfe | ||
|
|
330cb4e652 | ||
|
|
34013bfd63 | ||
|
|
1df7e524ed | ||
|
|
460b1c2249 | ||
|
|
4cc3251b02 | ||
|
|
ed2dded753 | ||
|
|
c14e07828f | ||
|
|
f2a21265b3 | ||
|
|
2cc7f72400 | ||
|
|
bab8b92f60 | ||
|
|
c53c44331e | ||
|
|
9d9b509084 | ||
|
|
1595e2f59b | ||
|
|
90c0b48235 | ||
|
|
411cfa6d9a | ||
|
|
137c0bdf9f | ||
|
|
18b64d471f | ||
|
|
fc737be24e | ||
|
|
32e5394aea | ||
|
|
99f1fa3de8 | ||
|
|
2bf2a37784 | ||
|
|
2ca9dfd40e | ||
|
|
8e3c4bcaac | ||
|
|
1dcf3c53ed | ||
|
|
2179f63a97 | ||
|
|
b1a79758ee | ||
|
|
861fec5dbd | ||
|
|
31fc54d037 | ||
|
|
1941e1717a | ||
|
|
f996c946f3 | ||
|
|
21b3e13b70 | ||
|
|
bffd3048d7 | ||
|
|
dd19013a79 | ||
|
|
4f8ccb165c | ||
|
|
b92b61b36f | ||
|
|
a346cf760f | ||
|
|
2bb0a7a759 | ||
|
|
dfac9e8582 | ||
|
|
4cca5de20a | ||
|
|
516cec5a9b | ||
|
|
6630fe7cc0 | ||
|
|
5f68c65680 | ||
|
|
7f3211f46d | ||
|
|
361481d34d | ||
|
|
a2c0a5b547 | ||
|
|
9df0b07308 | ||
|
|
6be0d1fa34 | ||
|
|
feb846a1ff | ||
|
|
2b052e11f8 | ||
|
|
04a2dd8ace | ||
|
|
7a60a36a05 | ||
|
|
bc5fcc0d35 | ||
|
|
8368e5f487 | ||
|
|
684811d7ac | ||
|
|
ccd2ef97c5 | ||
|
|
43e7bd8356 | ||
|
|
84cef9a876 | ||
|
|
3202e7794e | ||
|
|
0897920a8c | ||
|
|
74cfc245ba | ||
|
|
efd29616db | ||
|
|
3ed74de232 | ||
|
|
4dbfc244cc | ||
|
|
e72343c867 | ||
|
|
c7c17484b1 | ||
|
|
1ab7cb6cdd | ||
|
|
ee9df548b7 | ||
|
|
841a1b8188 | ||
|
|
ceccc257e7 | ||
|
|
6076e22f1a | ||
|
|
a6e9eb3686 | ||
|
|
1efed72ada | ||
|
|
1e9a669f07 | ||
|
|
e204bf375d | ||
|
|
4bcbaa7287 | ||
|
|
ec12be530d | ||
|
|
9a6ab51b0f | ||
|
|
bb4b17bf86 | ||
|
|
2cc8b49e27 | ||
|
|
918379dacd | ||
|
|
a09d821f9e | ||
|
|
e5af75a476 | ||
|
|
e5b45edf5b | ||
|
|
f739f3c37b | ||
|
|
7c02454fc7 | ||
|
|
c4f34905db | ||
|
|
04eb7d174c | ||
|
|
ef4072fc23 | ||
|
|
29c27b6a5a | ||
|
|
256bc5a70d | ||
|
|
3591f2813f | ||
|
|
dcd4e5b4ff | ||
|
|
9417d790a7 | ||
|
|
52ea598baa | ||
|
|
3a022a6812 | ||
|
|
e33ec1fe36 | ||
|
|
3cad30de21 | ||
|
|
c842d61919 | ||
|
|
e214f12e28 | ||
|
|
b369396d0a | ||
|
|
4af46bfaaa | ||
|
|
8f1711f7cc | ||
|
|
42915717a4 | ||
|
|
54be8f04e3 | ||
|
|
3999dffd81 | ||
|
|
0b3ddf585a | ||
|
|
955e28fe56 | ||
|
|
15aaa2459c | ||
|
|
5ff858c1d5 | ||
|
|
c551c20104 | ||
|
|
bc8148ba3a | ||
|
|
49f9e2f066 | ||
|
|
8a97e31803 | ||
|
|
e80f2f1b49 | ||
|
|
6ff862e6a4 | ||
|
|
96adc67184 | ||
|
|
c4aebf3bd7 | ||
|
|
b88912c4cf | ||
|
|
732bc9e3a0 | ||
|
|
6f8675815e | ||
|
|
553d3c8f0e | ||
|
|
e51b006a3f | ||
|
|
b22e7654fc | ||
|
|
0c63da60f7 | ||
|
|
7cc4586130 | ||
|
|
c08f564269 | ||
|
|
2bf7821f70 | ||
|
|
3cd1d9e430 | ||
|
|
e20ac5e5be | ||
|
|
fbc7ec4dff | ||
|
|
10ebeba6b9 | ||
|
|
f937db2251 | ||
|
|
8362ba3b96 | ||
|
|
f4f87c8ba3 | ||
|
|
54910c06cf | ||
|
|
6e78986f34 | ||
|
|
5e7f7a14bb | ||
|
|
d8b0ad85c3 | ||
|
|
0b069c10e7 | ||
|
|
56b5392088 | ||
|
|
751cec6c03 | ||
|
|
2568b78213 | ||
|
|
3bb94f51b8 | ||
|
|
51461f9a3a | ||
|
|
f8208799be | ||
|
|
70240054fb | ||
|
|
9e2724918c | ||
|
|
68e65f2b9a | ||
|
|
fa04386790 | ||
|
|
961c470159 | ||
|
|
edc13ba71f | ||
|
|
e8303705b3 | ||
|
|
b216a22e0e | ||
|
|
11d6f547c3 | ||
|
|
692b4a6944 | ||
|
|
855523d669 | ||
|
|
ff7b62d45b | ||
|
|
0aa2b2fcb6 | ||
|
|
5c318aad3b | ||
|
|
206a7acd99 | ||
|
|
d9ef135999 | ||
|
|
3688c468ce | ||
|
|
3b0115cffc | ||
|
|
5078941dfb | ||
|
|
1672e7124b | ||
|
|
23fd362a72 | ||
|
|
5c60a5ac21 | ||
|
|
fd0d925466 | ||
|
|
616f0c929a | ||
|
|
92d99e90ad | ||
|
|
9b2e698f6b | ||
|
|
b2cf1b106c | ||
|
|
66a844f050 | ||
|
|
135eb717f4 | ||
|
|
29bfe96f8e | ||
|
|
c94e1598bf | ||
|
|
aa23d7a56f | ||
|
|
4269f8a3f3 | ||
|
|
d78c105f08 | ||
|
|
ff27aa43e9 | ||
|
|
d1ae3d83af | ||
|
|
e95527efbb | ||
|
|
b2dab994af | ||
|
|
cec0a6bd7d | ||
|
|
b89404cf52 | ||
|
|
02d93cca94 | ||
|
|
7a550677bc | ||
|
|
3c7073326c | ||
|
|
c84ce7edb1 | ||
|
|
34389498c5 | ||
|
|
a89950536a | ||
|
|
d787240dab | ||
|
|
3ca3967711 | ||
|
|
c85d59c371 | ||
|
|
f8ad400ff2 | ||
|
|
b73c167ce0 | ||
|
|
a027455d39 | ||
|
|
4e4e2846f9 | ||
|
|
e7c57199e8 | ||
|
|
918d820d53 | ||
|
|
3faad0375e | ||
|
|
6194fc367b | ||
|
|
9a07f418ce | ||
|
|
8b88806d46 | ||
|
|
8f123f315b | ||
|
|
99b90ffb48 | ||
|
|
91e43ef443 | ||
|
|
595aa2c126 | ||
|
|
217fe38647 | ||
|
|
a75a324a4c | ||
|
|
404c9e4068 | ||
|
|
10b8b55c27 | ||
|
|
212c1922ba | ||
|
|
0f22c475f5 | ||
|
|
a524e2cbea | ||
|
|
b148e8a614 | ||
|
|
3f79b9db6f | ||
|
|
f36d409355 | ||
|
|
3e415ba7be | ||
|
|
5632e53759 | ||
|
|
caf36be549 | ||
|
|
c727f2b197 | ||
|
|
60c0542463 | ||
|
|
4b57e88b4b | ||
|
|
01ea159d19 | ||
|
|
e86546521f | ||
|
|
adc7241859 | ||
|
|
d81bda401e | ||
|
|
0552d34dab | ||
|
|
af90d98a6e | ||
|
|
3c5f92d49d | ||
|
|
4f9fef7b0e | ||
|
|
7616dab297 | ||
|
|
651862fd47 | ||
|
|
59d869d79d | ||
|
|
d331767eac | ||
|
|
e770ae4301 | ||
|
|
cd0f54edfc | ||
|
|
dda4eaf546 | ||
|
|
4d317b03dc | ||
|
|
c21b6014b6 | ||
|
|
71922ef9e2 | ||
|
|
96075f637e | ||
|
|
7a2e3e1a99 | ||
|
|
ab16f9899d | ||
|
|
498429e7a8 | ||
|
|
617cc6c596 | ||
|
|
9c07070580 | ||
|
|
ff2cb608a9 | ||
|
|
bf24eaaf7d | ||
|
|
356bf82843 | ||
|
|
71e953f011 | ||
|
|
f2f99a2392 | ||
|
|
beb338ebea | ||
|
|
e40e387213 | ||
|
|
046de9b4af | ||
|
|
22efce962f | ||
|
|
54768abed7 | ||
|
|
eb639a9bd7 | ||
|
|
3ec33c9c02 | ||
|
|
1b780ba76d | ||
|
|
68ff9d5402 | ||
|
|
da400c7283 | ||
|
|
896b203184 | ||
|
|
2b2b8f0610 | ||
|
|
e35b44b997 | ||
|
|
39b621391b | ||
|
|
a89a0dfe23 | ||
|
|
bc8d8b861f | ||
|
|
2061fe33c7 | ||
|
|
451a78e430 | ||
|
|
bd082fa1f6 | ||
|
|
cee8257749 | ||
|
|
dea5340516 | ||
|
|
d9d87d60d2 | ||
|
|
4f8619b918 | ||
|
|
904acd1071 | ||
|
|
a2d9587950 | ||
|
|
5564125d7c | ||
|
|
9daef7b4b5 | ||
|
|
79fc15cdc5 | ||
|
|
94ac9318d0 | ||
|
|
4d8adc9be4 | ||
|
|
07c2e57fe4 | ||
|
|
1b2de9f6de | ||
|
|
d22831bcd7 | ||
|
|
ef5bf392c7 | ||
|
|
98e2a3e429 | ||
|
|
3f7a027cf1 | ||
|
|
5df9f65eaf | ||
|
|
3a32265142 | ||
|
|
d2620a72d2 | ||
|
|
2443eac3ac | ||
|
|
6af6f7e417 | ||
|
|
5de9436aae | ||
|
|
abbad5fcb0 | ||
|
|
0145c48321 | ||
|
|
eef12c3d91 | ||
|
|
d86ce47cd4 | ||
|
|
cf1d43cf7c | ||
|
|
87d70e47d4 | ||
|
|
74fc71a2f2 | ||
|
|
4cd8f8c0f2 | ||
|
|
2bd27cd95f | ||
|
|
134067bea8 | ||
|
|
7506ded082 | ||
|
|
3580fc5847 | ||
|
|
1ea494ed0c | ||
|
|
e49bf19a9d | ||
|
|
b0ec44506f | ||
|
|
23190e0165 | ||
|
|
2d4ff30450 | ||
|
|
aaddcc7eeb | ||
|
|
6288f12695 | ||
|
|
126e06acce | ||
|
|
e4b25f2b53 | ||
|
|
458b5d9dd7 | ||
|
|
2ca67fc36b | ||
|
|
f4b1ecfcea | ||
|
|
166b43b8dc | ||
|
|
a69fbe34a5 | ||
|
|
3b6466b5e6 | ||
|
|
2fed3d20e3 | ||
|
|
ef69627363 | ||
|
|
34b81c2c48 | ||
|
|
0c9bb3488b | ||
|
|
f0ca3afab8 | ||
|
|
c7fa463c0d | ||
|
|
97502e969d | ||
|
|
c629896172 | ||
|
|
9d83af3e05 | ||
|
|
6e0a2b52fc | ||
|
|
adc07537f0 | ||
|
|
be9aa4b811 | ||
|
|
622910313c | ||
|
|
f7756d8012 | ||
|
|
da9bfe8cf9 | ||
|
|
4b24b9dcbb | ||
|
|
249cd86f2e | ||
|
|
c48c0cabaf | ||
|
|
0412ef805d | ||
|
|
253f211e16 | ||
|
|
fc95e909c9 | ||
|
|
3d8acdc1c4 | ||
|
|
37b81426ad | ||
|
|
43ebb77dae | ||
|
|
a0fd9d4ce8 | ||
|
|
97bedc773f | ||
|
|
9828191030 | ||
|
|
714a93e1ab | ||
|
|
52c74804ff | ||
|
|
8bb579cd86 | ||
|
|
6a14ce8ff4 | ||
|
|
4a6d6ee5ee | ||
|
|
4d76c57a1a | ||
|
|
f122ab9d5e | ||
|
|
4429b05805 | ||
|
|
0a24711890 | ||
|
|
8b77387af4 | ||
|
|
ddba3e4e6e | ||
|
|
83c5e15af2 | ||
|
|
902d525d3c | ||
|
|
8e9ebb1cc9 | ||
|
|
bcfd9a0faa | ||
|
|
0654cd01b3 | ||
|
|
cba8004131 | ||
|
|
074fe0fa9b | ||
|
|
6631c1bef3 | ||
|
|
a3f9fb1911 | ||
|
|
644b14707f | ||
|
|
37d51b625d | ||
|
|
77f8a5ecfb | ||
|
|
9860605b91 | ||
|
|
bab730bf6e | ||
|
|
584e7bb4b5 | ||
|
|
2ef5b7810e | ||
|
|
253e40e736 | ||
|
|
9ac80d9a3a | ||
|
|
3b38a41278 | ||
|
|
d5557ec4b4 | ||
|
|
a6ab0f3bf6 | ||
|
|
9453bd9417 | ||
|
|
efc0ad189f | ||
|
|
285ca1b285 | ||
|
|
0fd0659852 | ||
|
|
80daae0b36 | ||
|
|
da5ef0b604 | ||
|
|
c91d182c84 | ||
|
|
d2ef319833 | ||
|
|
00dd128b04 | ||
|
|
627c3c979f | ||
|
|
f4daa1282b | ||
|
|
a959a48da2 | ||
|
|
d536980947 | ||
|
|
a8e1302151 | ||
|
|
7ca1399dc5 | ||
|
|
bdfe4a952b | ||
|
|
69d73daa6a |
277 changed files with 24058 additions and 1490 deletions
63
.github/workflows/githubci.yml
vendored
Normal file
63
.github/workflows/githubci.yml
vendored
Normal file
|
|
@ -0,0 +1,63 @@
|
|||
name: Build
|
||||
|
||||
on: [pull_request, push]
|
||||
|
||||
jobs:
|
||||
build:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
arduino-platform: ['metro_m0', 'hallowing', 'circuitplayground_m0',
|
||||
'metro_m4', 'pybadge_m4', 'pygamer_m4', 'hallowing_m4', 'pyportal_m4', 'pyportal_m4_titano']
|
||||
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: Setup Python
|
||||
uses: actions/setup-python@v1
|
||||
with:
|
||||
python-version: '3.x'
|
||||
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v2
|
||||
|
||||
- name: Checkout submodules
|
||||
shell: bash
|
||||
run: |
|
||||
auth_header="$(git config --local --get http.https://github.com/.extraheader)"
|
||||
git submodule sync --recursive
|
||||
git -c "http.extraheader=$auth_header" -c protocol.version=2 submodule update --init --force --recursive
|
||||
|
||||
- name: Install Arduino CLI and Tools
|
||||
run: |
|
||||
# make all our directories we need for files and libraries
|
||||
mkdir $HOME/.arduino15
|
||||
mkdir $HOME/.arduino15/packages
|
||||
mkdir $HOME/Arduino
|
||||
mkdir $HOME/Arduino/libraries
|
||||
curl -fsSL https://raw.githubusercontent.com/arduino/arduino-cli/master/install.sh | sh
|
||||
echo "::add-path::$GITHUB_WORKSPACE/bin"
|
||||
|
||||
- name: Install BSP and Libraries
|
||||
env:
|
||||
BSP_URL: https://adafruit.github.io/arduino-board-index/package_adafruit_index.json
|
||||
BSP_PATH: .arduino15/packages/adafruit/hardware/samd
|
||||
LIB_DEPS: FlashStorage SD
|
||||
run: |
|
||||
arduino-cli config init
|
||||
arduino-cli core update-index
|
||||
arduino-cli core update-index --additional-urls $BSP_URL
|
||||
arduino-cli core install arduino:samd --additional-urls $BSP_URL
|
||||
arduino-cli core install adafruit:samd --additional-urls $BSP_URL
|
||||
# Replace release BSP with our code
|
||||
BSP_VERSION=`eval ls $HOME/$BSP_PATH`
|
||||
rm -r $HOME/$BSP_PATH/*
|
||||
ln -s $GITHUB_WORKSPACE $HOME/$BSP_PATH/$BSP_VERSION
|
||||
arduino-cli lib install $LIB_DEPS
|
||||
|
||||
- name: Build examples
|
||||
run: python3 extras/build_all.py ${{ matrix.arduino-platform }}
|
||||
|
||||
# How to mark this as allowed-to-fail?
|
||||
- name: Build examples (-Wall)
|
||||
run: python3 extras/build_all.py --all_warnings --warnings_do_not_cause_job_failure
|
||||
3
.gitmodules
vendored
Normal file
3
.gitmodules
vendored
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
[submodule "cores/arduino/TinyUSB/Adafruit_TinyUSB_ArduinoCore"]
|
||||
path = cores/arduino/TinyUSB/Adafruit_TinyUSB_ArduinoCore
|
||||
url = https://github.com/adafruit/Adafruit_TinyUSB_ArduinoCore.git
|
||||
35
CHANGELOG
35
CHANGELOG
|
|
@ -1,5 +1,40 @@
|
|||
SAMD CORE ?.?.?? ????.??.??
|
||||
|
||||
SAMD CORE 1.6.21 2019.04.01
|
||||
|
||||
* MKR boards: changed I2C to sercom2, SPI1 + Serial2 to sercom4
|
||||
* Improved accuracy of delay() function. Thanks @BenF
|
||||
* MKR 1500: Changed SARA module to be powered off on boot
|
||||
|
||||
SAMD CORE 1.6.20 2018.11.28
|
||||
|
||||
* Replaced boolean type with bool in examples. Thanks @per1234
|
||||
* Added c++ linker command to allow to include libstdc++ when linking. Thanks @helmut64
|
||||
* CPX driver fixes. Thanks @dhalbert
|
||||
* I2S: Changed library to use 8 MHz oscillator source if 48MHz divider does not fit in 8 bits
|
||||
* UART: Added frame error handling
|
||||
* USB: Fixed memory leak on reconnects
|
||||
* SDU: Added support for Arduino M0. Thanks @jandrassy
|
||||
* Added arduinoOTA upload keys for Arduino M0. Thanks @jandrassy
|
||||
* USB: Fixed USB Host failures and fixed memory overwrite in USBHost. Thanks @gdsports
|
||||
* USB: Added method to return USB error code. Thanks @MarkFischer
|
||||
* CDC: Clear line state on end()
|
||||
* USB: Added USB device end() method
|
||||
* Removed requirement that the DAC is on A0. Thanks @GabrielNotman
|
||||
* Added alternate ports 44, 45 to make the SWCLK and SWDIO pins available on the Zero. Thanks @helmut64
|
||||
* Added defines for MKR pin layout
|
||||
* Fixed freeze in tone()
|
||||
* Added MKR NB 1500 variant and bootloader
|
||||
* Increased the default serial buffer size to 256
|
||||
|
||||
SAMD CORE 1.6.19 2018.07.11
|
||||
|
||||
* Fixed bootloader tools for .org boards
|
||||
* M0: Updated pin definitions for D6, D7 and D13 to match Zero
|
||||
* SPI: Fixed interrupt mask to block. Thanks @ggajoch
|
||||
* Added MKR WiFi 1010 variant and bootloader
|
||||
* Updated Windows Drivers to 1.4.0 and re-signed Adafruit_Circuit_Playground_Express.inf
|
||||
|
||||
SAMD CORE 1.6.18 2018.03.05
|
||||
|
||||
* Wire: Added support for general call (broadcast)
|
||||
|
|
|
|||
39
README.md
39
README.md
|
|
@ -1,48 +1,17 @@
|
|||
# Arduino Core for SAMD21 and SAMD51 CPU
|
||||
|
||||
## Known Issues:
|
||||
* gcc optimizations must be off for sketches to work consistently. We are working to track this down.
|
||||
* AREF must be tied to 3.3V for dac to work. This is a bug in the SAMD51 silicon.
|
||||
* USB host mode doesn't work yet
|
||||
* I2S doesn't work yet
|
||||
[](https://github.com/adafruit/ArduinoCore-samd/actions)
|
||||
|
||||
This repository contains the source code and configuration files of the Arduino Core
|
||||
for Atmel's SAMD21 and SAMD51 processor (used on the Arduino/Genuino Zero, MKR1000 and MKRZero boards).
|
||||
|
||||
In particular, this adds support for the Adafruit SAMD Boards such as the Feather M0
|
||||
|
||||
## ATSAMD51 Installation on Arduino IDE
|
||||
|
||||
The ATSAMD51 is a significantly new chip, so this is a detailed process for now! For the SAMD21, please install via the board manager (no extra steps required)
|
||||
|
||||
1. Install Arduino IDE 1.8.5 or greater
|
||||
2. Install/update the Adafruit SAMD board support package if you have installed it
|
||||
3. Now we need to update CMSIS! Download https://github.com/adafruit/ArduinoModule-CMSIS-Atmel/archive/master.zip and unzip
|
||||
4. Find your Arduino CMSIS, in Mac its "~/Library/Arduino15/packages/arduino/tools/CMSIS-Atmel/1.1.0/CMSIS" version # may vary, you'll need "Go to folder..." feature in the Finder to get to " ~/Library/Arduino15" as it is hidden. In Windows it is "C:\Users\yourusername\AppData\Local\Arduino15\packages\arduino\tools\CMSIS-Atmel\1.1.0\CMSIS" Inside is a folder named Device
|
||||
|
||||
For Linux: the Arduino stuff is located in ~/.arduino15/packages/arduino/tools/CMSIS-Atmel/1.1.0/CMSIS
|
||||
|
||||
5. Inside the downloaded CMSIS zip, go into the CMSIS-Atmel/CMSIS folder, you should see a folder named Device. *DRAG THE DEVICE FOLDER ONLY* from the zip to your arduino Library folder so that Device is merged with Device. It will replace a bunch of files.
|
||||
|
||||
For Linux, it may be better to just delete the original Device Folder then copy over the new one - the drag/drop worked ok on MACOS, but not so well on my Linux box.
|
||||
|
||||
6. You will also need to replace bossac. For Windows or Mac: Go here https://github.com/adafruit/BOSSA/releases and download either windows exe or mac app of latest bossac. unzip. Go to Step 12.
|
||||
|
||||
For Linux users it is best to build a copy of bossac locally -
|
||||
clone the Adafruit Repostitory to somewhere on your local machine.
|
||||
```
|
||||
git clone https://github.com/adafruit/BOSSA.git
|
||||
change to the arduino branch
|
||||
git checkout arduino
|
||||
```
|
||||
Follow the instructions to build bossac in README.md or at https://github.com/adafruit/BOSSA/tree/arduino.
|
||||
|
||||
7. Replace the binary at ".../Library/Arduino15/packages/arduino/tools/bossac/1.7.0/bossac" or "...\AppData\Local\Arduino15\packages\arduino\tools\bossac\1.7.0\bossac"
|
||||
8. On Windows 7 you will also need to install the updated serial driver, download https://github.com/adafruit/Adafruit_Windows_Drivers/archive/master.zip to get all the drivers, and point the Device Manager to the unzipped folder. It isn't signed, so just approve the installation manually.
|
||||
13. That's it!
|
||||
|
||||
## Bugs or Issues
|
||||
|
||||
* AREF must be tied to 3.3V for dac to work. This is a bug in the SAMD51 silicon.
|
||||
* USB host mode doesn't work yet
|
||||
|
||||
If you find a bug you can submit an issue here on github:
|
||||
|
||||
https://github.com/adafruit/ArduinoCore-samd
|
||||
|
|
|
|||
1260
boards.txt
1260
boards.txt
File diff suppressed because it is too large
Load diff
BIN
bootloaders/blmbadge/bootloader-blm_badge.bin
Normal file
BIN
bootloaders/blmbadge/bootloader-blm_badge.bin
Normal file
Binary file not shown.
BIN
bootloaders/grand_central_m4/bootloader-grandcentral_m4.bin
Normal file
BIN
bootloaders/grand_central_m4/bootloader-grandcentral_m4.bin
Normal file
Binary file not shown.
BIN
bootloaders/matrixportalM4/bootloader-matrixportal_m4.bin
Normal file
BIN
bootloaders/matrixportalM4/bootloader-matrixportal_m4.bin
Normal file
Binary file not shown.
BIN
bootloaders/mkrnb1500/samd21_sam_ba_arduino_mkrnb1500.bin
Executable file
BIN
bootloaders/mkrnb1500/samd21_sam_ba_arduino_mkrnb1500.bin
Executable file
Binary file not shown.
502
bootloaders/mkrnb1500/samd21_sam_ba_arduino_mkrnb1500.hex
Normal file
502
bootloaders/mkrnb1500/samd21_sam_ba_arduino_mkrnb1500.hex
Normal file
|
|
@ -0,0 +1,502 @@
|
|||
:10000000FC7F0020810B0000710B0000750B0000CD
|
||||
:1000100000000000000000000000000000000000E0
|
||||
:10002000000000000000000000000000790B00004C
|
||||
:1000300000000000000000007D0B0000D50C000057
|
||||
:1000400010B5064C2378002B07D1054B002B02D0AE
|
||||
:10005000044800E000BF0123237010BD5C000020B5
|
||||
:1000600000000000D41E000008B5084B002B03D090
|
||||
:100070000748084900E000BF07480368002B03D089
|
||||
:10008000064B002B00D0984708BDC046000000007A
|
||||
:10009000D41E000060000020580000200000000076
|
||||
:1000A000064B0322104002040549586808401043DB
|
||||
:1000B0005860DA695107FCD47047C0460008004216
|
||||
:1000C000FFFFFCFF38B5284A284B5A805A7852B2B5
|
||||
:1000D000002AFBDB264B04211A6A264D0A431A62CA
|
||||
:1000E0002B68012213432B602A680123214C1A42FA
|
||||
:1000F000FAD1E2691A42F7D11423236041001E4865
|
||||
:1001000001F00CFD421EE068FF231A4098431043A3
|
||||
:10011000E0602368022213432360EA69154B9107CC
|
||||
:10012000FBD45A8B30218A4310210A435A83EB694E
|
||||
:1001300001205A07FBD4114B02241A7802431A708B
|
||||
:100140000F4B0F22197891431970197821431970B8
|
||||
:100150000C490C782043087019780A401A701A78F4
|
||||
:1001600020210A431A7038BD14400000000C0040E2
|
||||
:100170000004004000080042006CDC0248440041DA
|
||||
:100180003444004149440041F7B500230F1C01925B
|
||||
:100190001D1C994254D001212A4E4000084333705F
|
||||
:1001A000C1B2294B0322588B1C1C000910400128A6
|
||||
:1001B00004D05B8B1B091A40022AF2D1606AC00A84
|
||||
:1001C000C00208436062217E1F4B0122880708D4C9
|
||||
:1001D000197E1142F7D05968C02292020A435A6030
|
||||
:1001E00003E05B8B9B08134201D0002528E03270AE
|
||||
:1001F000237E9907FCD5154A154B117801251970F6
|
||||
:100200006268BD4212D0134B022013406360FFF7B7
|
||||
:1002100047FF33785A1C3270227E9007FCD50B4979
|
||||
:100220000B480A780135C254EDB2E9E78023DB02BE
|
||||
:10023000134363600199002902D00320FFF730FFC8
|
||||
:10024000281CFEBD7800002000080042280800425B
|
||||
:1002500099000020FFFFFBFF024B00221870024BA9
|
||||
:100260001A7070477A00002079000020F8B5274BFB
|
||||
:100270001C786400E4B2264B03215D8B1A1C2D0907
|
||||
:100280000D40012D04D05B8B1B0919400229F2D1CE
|
||||
:10029000536ADB0ADB0223435362117E01231942B6
|
||||
:1002A000FBD01B49498B8908194204D00320FFF772
|
||||
:1002B000F7FE022427E017490D782B1C002B11D0E4
|
||||
:1002C000154EEC1A365D154C2670114E177E012422
|
||||
:1002D000768B274202D12642F7D00BE0B6082642A1
|
||||
:1002E0000ED007E00B701C1C00280CD00320FFF779
|
||||
:1002F000D7FE08E003200B700324FFF7D1FE02E0D5
|
||||
:10030000013BDBB2DAE7201CF8BDC0467A000020D2
|
||||
:1003100000080042790000207B00002028080042ED
|
||||
:10032000034A1378591C1170024AD05401207047B7
|
||||
:10033000790000207B000020154A164B1178002917
|
||||
:1003400009D11549187809784118C9B21970802067
|
||||
:1003500012494003C86111780131C9B2117019788E
|
||||
:10036000F02902D81978092909D80B4908784042A0
|
||||
:10037000C0B20870187809784118C9B2197012789B
|
||||
:100380001B789A4203D18022044B5203DA617047F2
|
||||
:100390007D000020010000200000002000440041FA
|
||||
:1003A00010B5041C6B20FFF757FF201CFFF7B8FFA8
|
||||
:1003B0000120FFF75BFF01210A1C6B20FFF7E4FE21
|
||||
:1003C000014B187810BDC0469900002038B5051CB7
|
||||
:1003D0006B200C1CFFF740FF281CFFF7A1FF201C1F
|
||||
:1003E000FFF79EFF0120FFF741FF022038BD08B54F
|
||||
:1003F0000520FFF7D5FFCE23011C19400520FFF78C
|
||||
:10040000E5FF012008BD000010B5041C0020FFF727
|
||||
:10041000C7FF78232D4A9843C1B2944242D018D8DE
|
||||
:100420002B4B9C4238D009D82A4B9C4230D02A4BC7
|
||||
:100430009C422FD0294B9C4245D13FE0284B9C4207
|
||||
:100440002CD0284B9C422BD0274B9C423BD12023C5
|
||||
:1004500033E0264A94422BD00AD8254B9C4223D025
|
||||
:10046000244B9C4222D0244B9C422CD1402324E09C
|
||||
:10047000224A94421ED004D8214B9C4223D16023AF
|
||||
:100480001BE0204A944217D01F4A944215D01AE02C
|
||||
:10049000082312E0102310E018230EE028230CE0BC
|
||||
:1004A00030230AE0382308E0482306E0502304E024
|
||||
:1004B000582302E0682300E0702319430020FFF76F
|
||||
:1004C00085FF012000E0002010BDC046581100004B
|
||||
:1004D00018100000780F0000C80F0000280F00005F
|
||||
:1004E000B810000008110000681000009812000009
|
||||
:1004F000F811000048120000A81100003813000095
|
||||
:10050000E812000088130000D813000010B5041C86
|
||||
:100510000020FFF745FF07239843E122C1B2920074
|
||||
:10052000944220D008D8962C18D0FA235B009C4225
|
||||
:1005300017D0642C22D11CE0114A944215D005D862
|
||||
:100540009623DB009C4219D1042311E0FA22D20049
|
||||
:1005500094420CD00B4A94420AD00FE0012421436C
|
||||
:1005600007E0022304E0032302E0052300E0062362
|
||||
:1005700019430020FFF72AFF012000E0002010BDF2
|
||||
:10058000DC050000B80B000070B504AC267805ACA3
|
||||
:100590002578441EA041C401002901D040210C430C
|
||||
:1005A000002A01D020221443002B01D010231C4329
|
||||
:1005B000002E01D008231C43002D01D004231C432E
|
||||
:1005C0000220FFF7EDFE0125011C294021430220F6
|
||||
:1005D000FFF7FCFE281C70BD10B5041C0420FFF7BB
|
||||
:1005E000DFFE03231840084B9C4204D0074B9C427B
|
||||
:1005F00008D1B02100E0982101430420FFF7E6FE76
|
||||
:10060000012000E0002010BD10100000701000005C
|
||||
:1006100008B50120FFF7C4FECF23011C19400120BB
|
||||
:10062000FFF7D4FE012008BD07B5FFF7E0FEFFF796
|
||||
:10063000EFFF0948FFF7E8FEFA20C000FFF766FF6A
|
||||
:10064000002300930193181C191C1A1CFFF79CFF30
|
||||
:100650000248FFF7C1FF07BD08110000101000009D
|
||||
:1006600008B50348FFF72EFDFFF7DEFF08BDC046C3
|
||||
:10067000A086010010B5C3699C07FCD4036802245E
|
||||
:10068000A3430360C46901231C42FBD104682343D4
|
||||
:1006900003600368DC07FCD4C46901231C42FBD15E
|
||||
:1006A000C469DC401C42F7D1084B1A430260C3699D
|
||||
:1006B0005A07FCD4C0239B0243608181C3699C0715
|
||||
:1006C000FCD4036802221343036010BD0400004001
|
||||
:1006D000037EDA07FCD5018570470000027E012306
|
||||
:1006E0005107FBD5428B1A4207D1428BDA401A429E
|
||||
:1006F00003D1428B92081A4202D0034B01221A7096
|
||||
:10070000008DC0B27047C0467E00002070B50368FF
|
||||
:10071000041C988B1A1C0821FF32084226D0802026
|
||||
:1007200099839872112353704021144B9171507129
|
||||
:100730005E68134DC0202E40800506435E605E69F2
|
||||
:100740003540284358610F4818600F4818615D68AC
|
||||
:100750000E4828408025AD02284358605868800B19
|
||||
:100760008003586000235171237105E0137ADA0683
|
||||
:1007700002D5201C00F0E8FA207970BD9C01002011
|
||||
:10078000FFFFFF8F9C0000201C010020FF3F00F0B6
|
||||
:10079000002303714371044B016083600B780222D4
|
||||
:1007A00013430B707047C0460D07000038B5364B39
|
||||
:1007B0002021DA6901200A43DA61344B06241A78D1
|
||||
:1007C00002431A70324B0F2219789143197019782D
|
||||
:1007D000214319702F490C782043087019780A407A
|
||||
:1007E0001A701A7860210A431A702B4B2B4A5A80D0
|
||||
:1007F0005A7852B2002AFBDB294B01211A780A43AE
|
||||
:100800001A709A78D107FCD426480268510B1F222F
|
||||
:100810001140914200D1052111408C011D8D2249CA
|
||||
:100820002940214319850468A10C0A401F2A00D1E0
|
||||
:100830001D221C8D1F210A408C4322431A85026809
|
||||
:100840000721D20D0A408A4200D103220A40188DA6
|
||||
:100850001103164A02400A431A8519787F220A407A
|
||||
:100860001A701A78042112480A431A7058621A89B9
|
||||
:100870000C218A431A811A8901218A431A81002195
|
||||
:10088000802201F0A4F938BD000400405844004122
|
||||
:100890003C44004159440041000C00400640000027
|
||||
:1008A00000500041246080003FF8FFFFFF8FFFFFF2
|
||||
:1008B0009C010020F7B5141C1F4A5F0101971D1C05
|
||||
:1008C000D319061C5869271C4000400F0330103311
|
||||
:1008D000C74006D00F1C8022596812060A435A608E
|
||||
:1008E00009E02F1C7B1E9F41144BBF01FF18381CD1
|
||||
:1008F000221C01F063F901990F480835421817616D
|
||||
:10090000131C5269A104920B890C92030A435A6189
|
||||
:1009100059690B4A0A405A616B01F3180222DA71D5
|
||||
:100920005979802252420A435A716B01F318DB79DC
|
||||
:100930009A07FAD5201CFEBD9C0100201C01002056
|
||||
:10094000FF3F00F0F8B51A4E051C3378141C002B3D
|
||||
:1009500012D1184B184A1A645A6C920B92035A64BB
|
||||
:10096000586C164A02405A64A2235B00EA5C40209D
|
||||
:100970000243EA54012333704827FF37EA5D01231D
|
||||
:10098000134012D00B4B5A6C9204920CA24202D22A
|
||||
:100990005C6CA404A40C081C221C074901F00EF98D
|
||||
:1009A0000123EB550023337000E01C1C201CF8BD14
|
||||
:1009B0007F0000209C010020DC000020FF3F00F0B1
|
||||
:1009C000FF3083792022002900D110221343837144
|
||||
:1009D00070470000084BFF305A69920B92035A612E
|
||||
:1009E00002230372827980235B4213438371037A6B
|
||||
:1009F0009A07FCD57047C0469C01002080235B42CB
|
||||
:100A00001943C9B28172704770B5A02303225B00FD
|
||||
:100A1000C254134B134A5C6CC021144089050C432B
|
||||
:100A200046255C64FF35402444550F4D30261D6437
|
||||
:100A300090256D0046555D6B1540294392255963FD
|
||||
:100A40006D0080214155094D1D63B0256D00445551
|
||||
:100A50005C6F22405A67B2235B00C15470BDC04630
|
||||
:100A60009C010020FFFFFF8FDC0000205C010020C4
|
||||
:100A700030B5364A1E235168082099430223194392
|
||||
:100A8000516033498A6902438A613248324A90820E
|
||||
:100A9000908A03439382D3689807FCD52F4B01209B
|
||||
:100AA00018701878C40704D52C48407840B2002844
|
||||
:100AB000F7DB01209860587840B20028FBDB284C17
|
||||
:100AC00026484460587840B20028FBDB8224234843
|
||||
:100AD000E4014480587840B20028FBDB908C8024ED
|
||||
:100AE000A0439084D068C506FCD51E4C1A48C46249
|
||||
:100AF000D4681948E506FBD5848C1B4D2C438484AF
|
||||
:100B0000D4681548E506FBD5848C02252C438484E3
|
||||
:100B1000D0680406FCD51048C0684506F8D5D068F2
|
||||
:100B2000C406FCD500229A605A7852B2002AFBDB38
|
||||
:100B30000E480A4A50605A7852B2002AFBDB002362
|
||||
:100B40000B724B728B72CB7230BDC04600400041BD
|
||||
:100B5000000400400C06000000080040000C0040AB
|
||||
:100B600001050100B805FF7D040A0000000703002D
|
||||
:100B70000EBEFEE70DBEFEE705BEFEE702BEFEE7C7
|
||||
:100B80000E4A0F4838B5824204D10E4A0E4B9342AA
|
||||
:100B90000ED10AE00D4C9442F7D00023D1188842C0
|
||||
:100BA000F3D9E55804330D60F8E700F011F804E0DC
|
||||
:100BB0009342FAD2002102C3FAE7FEE700000020C8
|
||||
:100BC0005C000020AC0300205C000020D81E000068
|
||||
:100BD00038B5344D2B6801331AD0334B2A1D1A60B7
|
||||
:100BE000EAB2002A14D1314B197801231940304B55
|
||||
:100BF0000AD118682F4A904201D1196008E01A60A2
|
||||
:100C00002D4A013A002AFCD11A602C4B01221A709D
|
||||
:100C1000FFF72EFF62B6FFF723FD284B284C1B7809
|
||||
:100C2000002B0AD02B6883F308881E4BFF229343C6
|
||||
:100C3000A3601D4B1B681B68184700F09DFD00F06A
|
||||
:100C40004FF8204B802252039A601F4B1F4A051C0D
|
||||
:100C50005A60216AC0220902090A12060A43226266
|
||||
:100C600000229A6007221A60AB68281C9847184B2C
|
||||
:100C7000002801D001221A701A78002A05D000201D
|
||||
:100C800000F08CFA00F004FBFCE71B78002BEBD1A2
|
||||
:100C900000F0E6FD0028E7D0012000F07FFA00F028
|
||||
:100CA000F7FAFCE7002000001C0200203804004096
|
||||
:100CB000FC7F00203581730748E801008000002098
|
||||
:100CC00000ED00E00044004110E000E0E703000018
|
||||
:100CD0008100002008B5FFF72FFB00F0C3FA08BD24
|
||||
:100CE00010B5054B054C2360FFF760FD201C216803
|
||||
:100CF000FFF74EFD201C10BD0050004120020020D7
|
||||
:100D000070B5051CC0B0081C161C0C1C00F067FF59
|
||||
:100D100040006A46032302305370107076080123A6
|
||||
:100D2000E218013A11785A00002906D1281C6946B8
|
||||
:100D30000023FFF7BFFD40B070BDB342F6DA68464E
|
||||
:100D400081520133ECE70000F7B5BA4A0468137822
|
||||
:100D5000B949271CFF37051C102038720B705378D7
|
||||
:100D6000B648B74E037093783380D1783388090240
|
||||
:100D70000B4333801179B34B1980517918880902DC
|
||||
:100D8000084318809079B0490880D2790888120207
|
||||
:100D900002430A8040227A71A84F3A78A64F120285
|
||||
:100DA00038780F1C0243A9488446181C624500D1BC
|
||||
:100DB000C2E020DC802149008A4200D16EE109DCDA
|
||||
:100DC000812A00D192E0822A00D195E0802A00D0C9
|
||||
:100DD00064E18BE081235B009A4200D1CFE000DA2E
|
||||
:100DE00058E1C0239B009A4200D157E1984B9A42A8
|
||||
:100DF00000D14FE152E190231B019A4269D015DCEA
|
||||
:100E0000D023DB009A4222D088231B019A4269D06A
|
||||
:100E1000A023DB009A4200D040E1201CFFF7DAFD5E
|
||||
:100E20003188286889B2FFF7E9FD3BE1894B9A4296
|
||||
:100E300000D12FE100DC31E1874B9A4200D11DE166
|
||||
:100E4000864B9A4200D029E133886B7122E13388C6
|
||||
:100E50001B0A012B08D10B8812222868934201D863
|
||||
:100E60000A8892B27E4911E133881B0A022B08D10D
|
||||
:100E70000B8843222868934201D80A8892B27949A4
|
||||
:100E800004E133881B0A032B00D007E13388DBB26F
|
||||
:100E9000012B17D0002B07D0022B00D0FEE00A88D0
|
||||
:100EA0002868D2B2704911E0042201A86F4900F00D
|
||||
:100EB00085FE3B8804222868934201D83A8892B282
|
||||
:100EC00001A9E3E00A8828686949D2B2FFF718FF50
|
||||
:100ED000E8E03388201C2B71FFF77CFD201CFFF716
|
||||
:100EE00093FDDFE0291C01C90122CFE06149002305
|
||||
:100EF0000B8028680222CAE05E4900220A80188816
|
||||
:100F0000502210405C4A10701E880F20304018801C
|
||||
:100F10001888032800D9C1E012781B8808335B01C8
|
||||
:100F2000E418A379002A01D09B0600E0DB06DB0F62
|
||||
:100F30000B8028680222A9E019887F2291434E4A3B
|
||||
:100F4000C9B2117018880F21014019803188002919
|
||||
:100F500000D0A3E01988002900D19FE01988032957
|
||||
:100F600000D99BE012781B8808335B01E318002A44
|
||||
:100F700002D020225A718DE0102159718AE0028836
|
||||
:100F80007F239A433C4BD2B21A7001880F220A4049
|
||||
:100F900002803288002A00D080E00288002A00D136
|
||||
:100FA0007CE00288032A00D978E01B78002B1FD050
|
||||
:100FB000038808335B01E3189B799A066AD5038896
|
||||
:100FC000202208335B01E3181A71038808335B01A0
|
||||
:100FD000E318DB795F065DD50388402208335B01A7
|
||||
:100FE000E318DA710388022208335B01E3181EE07C
|
||||
:100FF000038808335B01E3189B79D9064AD5038837
|
||||
:10100000102208335B01E3181A71038808335B016F
|
||||
:10101000E318DB799A063DD50388202208335B016B
|
||||
:10102000E318DA710388012208335B01E3181A71AF
|
||||
:1010300030E0C0469C000020830000208800002093
|
||||
:101040008A0000208C00002086000020020300009F
|
||||
:101050000103000021200000A12100002122000046
|
||||
:10106000281C000004000020141C0000041C0000C8
|
||||
:10107000081C000084000020820000200B88082249
|
||||
:101080002868934201D80A8892B207490023FFF7E3
|
||||
:1010900011FC07E0201CFFF79DFC03E0201C012150
|
||||
:1010A000FFF78EFCF7BDC0464800002007B5054B92
|
||||
:1010B0000122019001A91868131CFFF7FBFB012016
|
||||
:1010C0000EBDC0462002002013B5054B6C46073408
|
||||
:1010D0001868211C0122FFF735FC207816BDC04698
|
||||
:1010E0002002002010B5074C201CFFF70FFB031C4B
|
||||
:1010F0000020834205D022684823FF33D05C0123BF
|
||||
:10110000184010BD2002002010B5054A0C1C031C1D
|
||||
:10111000191C10680123221CFFF7CCFB201C10BDFA
|
||||
:101120002002002070B5084C061C201C0D1CFFF787
|
||||
:10113000EDFA0023984205D02068311C2A1CFFF7E5
|
||||
:1011400001FC031C181C70BD20020020F8B50C4CDB
|
||||
:10115000051C201C0E1CFFF7D9FA0023271C341C89
|
||||
:1011600098420AD0002C07D0291C221C3868FFF7AF
|
||||
:10117000E9FB241A2D18F5E7331C181CF8BDC046EE
|
||||
:101180002002002008B5031C081C111C9847024BC4
|
||||
:1011900064221A8008BDC04692000020012805D1B3
|
||||
:1011A000054B064A1A60064B187004E0002802D16D
|
||||
:1011B000044A014B1A607047900200205C1C00003A
|
||||
:1011C00098000020A81C000030B50A1C1C4985B0FE
|
||||
:1011D0000978031C00292AD0042A01D1006804E000
|
||||
:1011E000022A01D1008800E00078520004A98B187F
|
||||
:1011F0000B3B9C1AA3420BD00F210140092902D8B6
|
||||
:101200003025294300E0373119700009013BF1E72F
|
||||
:1012100001A930230B7078234B700A208B1898702B
|
||||
:101220000D20D870074B04321B68D86803E00549CD
|
||||
:101230000968C868191CFFF7A5FF05B030BDC04696
|
||||
:101240008E0000209002002072B6EFF30883044A5B
|
||||
:101250001360036883F30888436818477047C046E3
|
||||
:1012600094020020084B1A88002A03D01A88013AF9
|
||||
:1012700092B21A80054B1A88002A03D01A88013AC4
|
||||
:1012800092B21A807047C046920000209000002061
|
||||
:10129000F0B591B008A9CC4A0B1C31CA31C351CA70
|
||||
:1012A00051C360CA60C3C94BC9489A687A255203C2
|
||||
:1012B000520F92005258C74902609C68A4B2624320
|
||||
:1012C0000C60C54900240A60C44A1460C44C2570EF
|
||||
:1012D000C44CC54D2368281C1B6940219847002831
|
||||
:1012E00002D0C24B64221A80C14B00221860C14B4D
|
||||
:1012F0001D60C14BC04DBE4F1A602A683B689A42C0
|
||||
:10130000E6D2BC4B1B681A78FF2A00D114E2232ACC
|
||||
:1013100000D0EBE1B94E3378002B06D0B14BB84981
|
||||
:101320001B680222D868FFF72DFFAD4B1B78532BAB
|
||||
:101330003CD13B682A6893421ED9AE4801322A60EC
|
||||
:101340009A1AB04B01681B6801310160AE4E9A4297
|
||||
:1013500001D2326000E03360A04832680068049037
|
||||
:1013600000F02CFC336829685A182A60A14A1668D4
|
||||
:10137000F1181160A54A13702B68013B2B609D4B3F
|
||||
:101380001A68013A1A60A14B9E4A1B7811688B4279
|
||||
:101390000AD222689148C91A0068926990470028C9
|
||||
:1013A00002D0924B64221A80C0468DE1522B0AD1A2
|
||||
:1013B0008A48944A2368006811685B6903909847DB
|
||||
:1013C0006422934B0DE04F2B05D1844B8D4A1B6853
|
||||
:1013D00012681A7078E1482B05D1804B894A1B6846
|
||||
:1013E00012681A8070E1572B05D17C4B854A1B6827
|
||||
:1013F00012681A6068E16F2B03D1784B01211868DD
|
||||
:1014000007E0682B08D1754B7E481B6802211B88BA
|
||||
:101410000360FFF7D9FE57E1772B06D16F4B794870
|
||||
:101420001B6804211B680360F3E7472B13D1754B3E
|
||||
:101430001868FFF709FF774B1B6883F3088862B6CB
|
||||
:10144000754B1B78002B00D13EE1664B06201B68D4
|
||||
:101450001B68984738E1542B04D101233370614B4A
|
||||
:101460001B6864E04E2B0CD13378002B06D15D4B0A
|
||||
:1014700063491B680222D868FFF784FE002333709B
|
||||
:1014800022E1562B57D123686449D8680122FFF71F
|
||||
:1014900079FE23686249D8680322FFF773FE614D25
|
||||
:1014A0002368291CD8680122FFF76CFE23685E4977
|
||||
:1014B000D8680D22FFF766FE2368291CD868012230
|
||||
:1014C000FFF760FE4B4F4C4D5849002339602B60AD
|
||||
:1014D0003A1C281C13685E1C16601B780593002BB1
|
||||
:1014E00003D0036801330360F4E73E4E2A68336893
|
||||
:1014F000D868FFF747FE33684A49D8680122FFF7EA
|
||||
:1015000041FE059929604A4939603A4A1368581CD6
|
||||
:1015100010601B78002B04D0374B1A6801321A6018
|
||||
:10152000F3E733682A68D868FFF72CFE3368D86879
|
||||
:1015300033490222C6E0334A582B17D1244E264D98
|
||||
:10154000366813682A68B10093420AD21F4D5808C2
|
||||
:10155000E861384828801D4D287DC607FBD55B18FB
|
||||
:10156000F2E7204B34491B68D868AAE0592B79D19F
|
||||
:1015700012681A4B3149002A02D11B680B606CE0DB
|
||||
:10158000124D086819686B68104E8025AB439208AD
|
||||
:101590007360002A61D02A4B0C4D2B800B4E337D9B
|
||||
:1015A000DD07FBD500230A4D2D680195AD08AB4240
|
||||
:1015B00003D3244D054E358046E09342F9D09D007B
|
||||
:1015C000465901334E51EEE73C1C000000400041FB
|
||||
:1015D00048020020400200203C0200208C02002033
|
||||
:1015E00038020020900200204C02002090000020D1
|
||||
:1015F0003002002034020020440200208E0000202F
|
||||
:101600009C1C0000980200209C0200202C0200205C
|
||||
:10161000920000209402002098000020781C000016
|
||||
:10162000A11C00007A1C0000C41C00007C1C0000EF
|
||||
:10163000881C000002A5FFFF911C00009400002000
|
||||
:1016400044A5FFFF04A5FFFF3F4E357DEE07FBD508
|
||||
:101650009D0049194019D21A9BE73C4B3C491B6835
|
||||
:10166000D8682EE05A2B2FD13A4B17681D680026F8
|
||||
:10167000EF19BD4206D02878311C00F013F901356E
|
||||
:10168000061CF6E7314B34491B680122D868FFF786
|
||||
:1016900079FD07230F223240111C36093031092A07
|
||||
:1016A00000DD07311820C0186A468154013BF1D291
|
||||
:1016B000236806A9D8680822FFF764FD2368274934
|
||||
:1016C000D8680322FFF75EFD254B7A221A70254B5E
|
||||
:1016D00000221A60244B1B7893422DD01B4B2349C8
|
||||
:1016E0001B680122D868FFF74DFD25E0111C303939
|
||||
:1016F000C8B21C4B092804D81D682A01114319607F
|
||||
:101700001AE0111C4139052903D81E68373A310106
|
||||
:1017100006E0111C6139052904D81868573A0101FF
|
||||
:101720000A4308E02C2A03D10A4A1968116001E033
|
||||
:101730000B490A7000221A600D4B1A6801321A60B8
|
||||
:101740000C4B1A680132D5E50040004190020020A0
|
||||
:10175000951C00008C020020991C00009B1C0000BE
|
||||
:1017600038020020980200208E0000209F1C0000FC
|
||||
:10177000440200203402002010B51C4B01201A78CE
|
||||
:10178000032402431A701A4B0F22197891431970DF
|
||||
:1017900019782143197017490C782043087019787B
|
||||
:1017A0000A401A701A7830210A431A70124B8021AD
|
||||
:1017B0001A6A0A431A62114B114A5A805A7852B275
|
||||
:1017C000002AFBDBC4220F480F499203FEF752FFA9
|
||||
:1017D0000E4A002313700E4A13700E4A13700E4AFD
|
||||
:1017E00013700E4A13700E4A137010BDD644004198
|
||||
:1017F000BB440041D744004100040040000C0040BD
|
||||
:1018000019400000001C00422AF60000A00200203F
|
||||
:1018100027030020A1020020A402002028030020AA
|
||||
:101820002503002008B5C1B20248FEF751FF012090
|
||||
:1018300008BDC046001C0042024B187E4007C00F86
|
||||
:101840007047C046001C004208B5FFF7F5FF0028AE
|
||||
:10185000FBD00248FEF742FF08BDC046001C004214
|
||||
:1018600008B5FFF7E9FF0023984205D0FFF7ECFF2A
|
||||
:10187000031C233B5A425341181C08BD70B5041C7D
|
||||
:101880000D1C4618B44204D02078FFF7CBFF01347A
|
||||
:10189000F8E7281C70BD10B5041CFFF7D5FF2070B9
|
||||
:1018A000012010BD0B0A5840034B4000C05A0902EA
|
||||
:1018B000484080B27047C046D21C0000F7B50024F3
|
||||
:1018C000051C0F1C261CBC4220D0FFF7BDFF114B8E
|
||||
:1018D000C0B21B780190002B1AD1311CFFF7E2FF38
|
||||
:1018E0000D4B061C1A88002A04D10C4A11782A1CB8
|
||||
:1018F000002907D001996A1C2970802F02D119880C
|
||||
:10190000013919800134A4B2151CDCE7301C00E059
|
||||
:101910000120FEBD25030020A20200202603002096
|
||||
:10192000F0B53E4E85B0002203900C1C32703C4B4B
|
||||
:10193000914201D1012201E03A490C801A707F23C3
|
||||
:101940001C4201D080349C43FFF77EFF3378C0B245
|
||||
:10195000002B07D000253570FFF776FF3378C0B233
|
||||
:10196000AB4236D1432803D0712853D01528EBD190
|
||||
:10197000012300930120FFF755FF0098FFF752FF66
|
||||
:1019800000998025C843C0B2FFF74CFF039B002796
|
||||
:101990000293244A1388002B1DD121490193097811
|
||||
:1019A000002918D10198FFF73DFF391C0198FFF776
|
||||
:1019B00079FF013D071C002DEBD1000AC0B2FFF7F3
|
||||
:1019C00031FFF8B2FFF72EFFFFF73EFF3378002B11
|
||||
:1019D0000AD035701FE00299013B09781380029B01
|
||||
:1019E000019101330293DDE7C0B2062807D1009BC5
|
||||
:1019F00003990133DBB280310093803C0391002CCA
|
||||
:101A0000B8D10420FFF70EFFFFF71EFF044B01259E
|
||||
:101A10001C7000E00025281C05B0F0BD2503002047
|
||||
:101A200026030020A2020020F0B5384C87B0002326
|
||||
:101A300001902370994201D1012301E0344A1180C1
|
||||
:101A4000344A642613704320FFF7ECFE324FFFF751
|
||||
:101A5000F3FE002803D1002F03D0013FF7E7002F4A
|
||||
:101A600003D1013E002EEED14DE00125FFF7ECFE43
|
||||
:101A70002378002B38D1C0B20290012805D0042869
|
||||
:101A80003DD10620FFF7CEFE39E005AE0221301C25
|
||||
:101A9000FFF714FF01988021FFF710FF23780390D0
|
||||
:101AA000002B18D1FFF7D0FE0702FFF7CDFEBFB223
|
||||
:101AB00023783F18BFB2012B0DD0039B9F4207D163
|
||||
:101AC0003378AB4204D1EB437278DBB29A4204D054
|
||||
:101AD0001820FFF7A7FE002303E00620FFF7A2FE71
|
||||
:101AE000029B2278002A02D0002626700BE0012BF0
|
||||
:101AF00005D1019A6B1C8032DDB20192B6E7054A2E
|
||||
:101B0000002313700126301C07B0F0BD2503002010
|
||||
:101B1000A20200202603002000350C00002934D04A
|
||||
:101B20000123002210B488422CD301242407A142AF
|
||||
:101B300004D2814202D209011B01F8E7E400A1426C
|
||||
:101B400004D2814202D249005B00F8E7884201D307
|
||||
:101B5000401A1A434C08A04202D3001B5C082243DF
|
||||
:101B60008C08A04202D3001B9C082243CC08A04250
|
||||
:101B700002D3001BDC082243002803D01B0901D03C
|
||||
:101B80000909E3E7101C10BC7047002801D00020B1
|
||||
:101B9000C04307B4024802A14018029003BDC046EA
|
||||
:101BA000190000000029F0D003B5FFF7B9FF0EBC03
|
||||
:101BB0004243891A1847C0467047C04610B50023F3
|
||||
:101BC000934203D0CC5CC4540133F9E710BD031C2D
|
||||
:101BD0008218934202D019700133FAE7704700234C
|
||||
:101BE000C25C0133002AFBD1581E7047F8B5C046CD
|
||||
:101BF000F8BC08BC9E467047F8B5C046F8BC08BCA7
|
||||
:101C00009E4670470403090441726475696E6F2033
|
||||
:101C10004C4C430041726475696E6F204D4B5220ED
|
||||
:101C20004E422031353030001201000202000040E7
|
||||
:101C300041235500000201020001000008000000DD
|
||||
:101C400010000000200000004000000080000000A4
|
||||
:101C50000001000000020000000400002518000040
|
||||
:101C600049180000391800007D180000971800007E
|
||||
:101C700021190000291A0000760020004E6F7620FE
|
||||
:101C8000323620323031380031343A32383A333754
|
||||
:101C900000580A0D00590A0D005A00230A0D003E93
|
||||
:101CA00000322E3000000000AD100000C91000000E
|
||||
:101CB000E5100000091100002511000009110000C5
|
||||
:101CC0004D1100005B41726475696E6F3A58595A44
|
||||
:101CD0005D0000002110422063308440A550C660A2
|
||||
:101CE000E770088129914AA16BB18CC1ADD1CEE1D9
|
||||
:101CF000EFF13112100273325222B5529442F77250
|
||||
:101D0000D662399318837BB35AA3BDD39CC3FFF328
|
||||
:101D1000DEE36224433420040114E664C774A4445F
|
||||
:101D200085546AA54BB528850995EEE5CFF5ACC578
|
||||
:101D30008DD55336722611163006D776F66695562F
|
||||
:101D4000B4465BB77AA719973887DFF7FEE79DD7C8
|
||||
:101D5000BCC7C448E5588668A778400861180228BF
|
||||
:101D60002338CCC9EDD98EE9AFF9488969990AA918
|
||||
:101D70002BB9F55AD44AB77A966A711A500A333A8F
|
||||
:101D8000122AFDDBDCCBBFFB9EEB799B588B3BBB68
|
||||
:101D90001AABA66C877CE44CC55C222C033C600C1F
|
||||
:101DA000411CAEED8FFDECCDCDDD2AAD0BBD688DB8
|
||||
:101DB000499D977EB66ED55EF44E133E322E511E6F
|
||||
:101DC000700E9FFFBEEFDDDFFCCF1BBF3AAF599F08
|
||||
:101DD000788F8891A981CAB1EBA10CD12DC14EF1A8
|
||||
:101DE0006FE18010A100C230E3200450254046700E
|
||||
:101DF0006760B9839893FBA3DAB33DC31CD37FE339
|
||||
:101E00005EF3B1029012F322D2323542145277625D
|
||||
:101E10005672EAB5CBA5A89589856EF54FE52CD508
|
||||
:101E20000DC5E234C324A0148104667447642454AD
|
||||
:101E30000544DBA7FAB79987B8975FE77EF71DC718
|
||||
:101E40003CD7D326F2369106B016576676761546FD
|
||||
:101E500034564CD96DC90EF92FE9C899E9898AB968
|
||||
:101E6000ABA94458654806782768C018E10882384D
|
||||
:101E7000A3287DCB5CDB3FEB1EFBF98BD89BBBAB78
|
||||
:101E80009ABB754A545A376A167AF10AD01AB32A9D
|
||||
:101E9000923A2EFD0FED6CDD4DCDAABD8BADE89DC8
|
||||
:101EA000C98D267C076C645C454CA23C832CE01CED
|
||||
:101EB000C10C1FEF3EFF5DCF7CDF9BAFBABFD98F58
|
||||
:101EC000F89F176E367E554E745E932EB23ED10E3D
|
||||
:081ED000F01E000000000000FC
|
||||
:101ED80001140000090243000201008032090400D5
|
||||
:101EE800000102020000052400100104240200057C
|
||||
:101EF800240600010524010001070583030800FFEB
|
||||
:101F080009040100020A00000007058102400000E0
|
||||
:101F1800070502024000000000C20100000008009E
|
||||
:0C1F280069000000410000000000000003
|
||||
:0400000300000B816D
|
||||
:00000001FF
|
||||
|
|
@ -218,7 +218,11 @@ void I2S_Handler ( void );
|
|||
* \brief Configuration of the Cortex-M0+ Processor and Core Peripherals
|
||||
*/
|
||||
|
||||
#if defined(LITTLE_ENDIAN) && (LITTLE_ENDIAN != 1)
|
||||
#error "Little Endian is already defined, but to different value than expected?!"
|
||||
#else
|
||||
#define LITTLE_ENDIAN 1
|
||||
#endif
|
||||
#define __CM0PLUS_REV 1 /*!< Core revision r0p1 */
|
||||
#define __MPU_PRESENT 0 /*!< MPU present or not */
|
||||
#define __NVIC_PRIO_BITS 2 /*!< Number of bits used for Priority Levels */
|
||||
|
|
|
|||
|
|
@ -218,7 +218,11 @@ void I2S_Handler ( void );
|
|||
* \brief Configuration of the Cortex-M0+ Processor and Core Peripherals
|
||||
*/
|
||||
|
||||
#if defined(LITTLE_ENDIAN) && (LITTLE_ENDIAN != 1)
|
||||
#error "Little Endian is already defined, but to different value than expected?!"
|
||||
#else
|
||||
#define LITTLE_ENDIAN 1
|
||||
#endif
|
||||
#define __CM0PLUS_REV 1 /*!< Core revision r0p1 */
|
||||
#define __MPU_PRESENT 0 /*!< MPU present or not */
|
||||
#define __NVIC_PRIO_BITS 2 /*!< Number of bits used for Priority Levels */
|
||||
|
|
|
|||
|
|
@ -218,7 +218,11 @@ void I2S_Handler ( void );
|
|||
* \brief Configuration of the Cortex-M0+ Processor and Core Peripherals
|
||||
*/
|
||||
|
||||
#if defined(LITTLE_ENDIAN) && (LITTLE_ENDIAN != 1)
|
||||
#error "Little Endian is already defined, but to different value than expected?!"
|
||||
#else
|
||||
#define LITTLE_ENDIAN 1
|
||||
#endif
|
||||
#define __CM0PLUS_REV 1 /*!< Core revision r0p1 */
|
||||
#define __MPU_PRESENT 0 /*!< MPU present or not */
|
||||
#define __NVIC_PRIO_BITS 2 /*!< Number of bits used for Priority Levels */
|
||||
|
|
|
|||
|
|
@ -218,7 +218,11 @@ void I2S_Handler ( void );
|
|||
* \brief Configuration of the Cortex-M0+ Processor and Core Peripherals
|
||||
*/
|
||||
|
||||
#if defined(LITTLE_ENDIAN) && (LITTLE_ENDIAN != 1)
|
||||
#error "Little Endian is already defined, but to different value than expected?!"
|
||||
#else
|
||||
#define LITTLE_ENDIAN 1
|
||||
#endif
|
||||
#define __CM0PLUS_REV 1 /*!< Core revision r0p1 */
|
||||
#define __MPU_PRESENT 0 /*!< MPU present or not */
|
||||
#define __NVIC_PRIO_BITS 2 /*!< Number of bits used for Priority Levels */
|
||||
|
|
|
|||
|
|
@ -222,7 +222,11 @@ void I2S_Handler ( void );
|
|||
* \brief Configuration of the Cortex-M0+ Processor and Core Peripherals
|
||||
*/
|
||||
|
||||
#if defined(LITTLE_ENDIAN) && (LITTLE_ENDIAN != 1)
|
||||
#error "Little Endian is already defined, but to different value than expected?!"
|
||||
#else
|
||||
#define LITTLE_ENDIAN 1
|
||||
#endif
|
||||
#define __CM0PLUS_REV 1 /*!< Core revision r0p1 */
|
||||
#define __MPU_PRESENT 0 /*!< MPU present or not */
|
||||
#define __NVIC_PRIO_BITS 2 /*!< Number of bits used for Priority Levels */
|
||||
|
|
|
|||
|
|
@ -222,7 +222,11 @@ void I2S_Handler ( void );
|
|||
* \brief Configuration of the Cortex-M0+ Processor and Core Peripherals
|
||||
*/
|
||||
|
||||
#if defined(LITTLE_ENDIAN) && (LITTLE_ENDIAN != 1)
|
||||
#error "Little Endian is already defined, but to different value than expected?!"
|
||||
#else
|
||||
#define LITTLE_ENDIAN 1
|
||||
#endif
|
||||
#define __CM0PLUS_REV 1 /*!< Core revision r0p1 */
|
||||
#define __MPU_PRESENT 0 /*!< MPU present or not */
|
||||
#define __NVIC_PRIO_BITS 2 /*!< Number of bits used for Priority Levels */
|
||||
|
|
|
|||
|
|
@ -222,7 +222,11 @@ void I2S_Handler ( void );
|
|||
* \brief Configuration of the Cortex-M0+ Processor and Core Peripherals
|
||||
*/
|
||||
|
||||
#if defined(LITTLE_ENDIAN) && (LITTLE_ENDIAN != 1)
|
||||
#error "Little Endian is already defined, but to different value than expected?!"
|
||||
#else
|
||||
#define LITTLE_ENDIAN 1
|
||||
#endif
|
||||
#define __CM0PLUS_REV 1 /*!< Core revision r0p1 */
|
||||
#define __MPU_PRESENT 0 /*!< MPU present or not */
|
||||
#define __NVIC_PRIO_BITS 2 /*!< Number of bits used for Priority Levels */
|
||||
|
|
|
|||
|
|
@ -222,7 +222,11 @@ void I2S_Handler ( void );
|
|||
* \brief Configuration of the Cortex-M0+ Processor and Core Peripherals
|
||||
*/
|
||||
|
||||
#if defined(LITTLE_ENDIAN) && (LITTLE_ENDIAN != 1)
|
||||
#error "Little Endian is already defined, but to different value than expected?!"
|
||||
#else
|
||||
#define LITTLE_ENDIAN 1
|
||||
#endif
|
||||
#define __CM0PLUS_REV 1 /*!< Core revision r0p1 */
|
||||
#define __MPU_PRESENT 0 /*!< MPU present or not */
|
||||
#define __NVIC_PRIO_BITS 2 /*!< Number of bits used for Priority Levels */
|
||||
|
|
|
|||
|
|
@ -226,7 +226,11 @@ void I2S_Handler ( void );
|
|||
* \brief Configuration of the Cortex-M0+ Processor and Core Peripherals
|
||||
*/
|
||||
|
||||
#if defined(LITTLE_ENDIAN) && (LITTLE_ENDIAN != 1)
|
||||
#error "Little Endian is already defined, but to different value than expected?!"
|
||||
#else
|
||||
#define LITTLE_ENDIAN 1
|
||||
#endif
|
||||
#define __CM0PLUS_REV 1 /*!< Core revision r0p1 */
|
||||
#define __MPU_PRESENT 0 /*!< MPU present or not */
|
||||
#define __NVIC_PRIO_BITS 2 /*!< Number of bits used for Priority Levels */
|
||||
|
|
|
|||
|
|
@ -226,7 +226,11 @@ void I2S_Handler ( void );
|
|||
* \brief Configuration of the Cortex-M0+ Processor and Core Peripherals
|
||||
*/
|
||||
|
||||
#if defined(LITTLE_ENDIAN) && (LITTLE_ENDIAN != 1)
|
||||
#error "Little Endian is already defined, but to different value than expected?!"
|
||||
#else
|
||||
#define LITTLE_ENDIAN 1
|
||||
#endif
|
||||
#define __CM0PLUS_REV 1 /*!< Core revision r0p1 */
|
||||
#define __MPU_PRESENT 0 /*!< MPU present or not */
|
||||
#define __NVIC_PRIO_BITS 2 /*!< Number of bits used for Priority Levels */
|
||||
|
|
|
|||
|
|
@ -226,7 +226,11 @@ void I2S_Handler ( void );
|
|||
* \brief Configuration of the Cortex-M0+ Processor and Core Peripherals
|
||||
*/
|
||||
|
||||
#if defined(LITTLE_ENDIAN) && (LITTLE_ENDIAN != 1)
|
||||
#error "Little Endian is already defined, but to different value than expected?!"
|
||||
#else
|
||||
#define LITTLE_ENDIAN 1
|
||||
#endif
|
||||
#define __CM0PLUS_REV 1 /*!< Core revision r0p1 */
|
||||
#define __MPU_PRESENT 0 /*!< MPU present or not */
|
||||
#define __NVIC_PRIO_BITS 2 /*!< Number of bits used for Priority Levels */
|
||||
|
|
|
|||
|
|
@ -226,7 +226,11 @@ void I2S_Handler ( void );
|
|||
* \brief Configuration of the Cortex-M0+ Processor and Core Peripherals
|
||||
*/
|
||||
|
||||
#if defined(LITTLE_ENDIAN) && (LITTLE_ENDIAN != 1)
|
||||
#error "Little Endian is already defined, but to different value than expected?!"
|
||||
#else
|
||||
#define LITTLE_ENDIAN 1
|
||||
#endif
|
||||
#define __CM0PLUS_REV 1 /*!< Core revision r0p1 */
|
||||
#define __MPU_PRESENT 0 /*!< MPU present or not */
|
||||
#define __NVIC_PRIO_BITS 2 /*!< Number of bits used for Priority Levels */
|
||||
|
|
|
|||
BIN
bootloaders/qtpyM0/bootloader-qtpy_m0.bin
Normal file
BIN
bootloaders/qtpyM0/bootloader-qtpy_m0.bin
Normal file
Binary file not shown.
|
|
@ -218,7 +218,11 @@ void I2S_Handler ( void );
|
|||
* \brief Configuration of the Cortex-M0+ Processor and Core Peripherals
|
||||
*/
|
||||
|
||||
#if defined(LITTLE_ENDIAN) && (LITTLE_ENDIAN != 1)
|
||||
#error "Little Endian is already defined, but to different value than expected?!"
|
||||
#else
|
||||
#define LITTLE_ENDIAN 1
|
||||
#endif
|
||||
#define __CM0PLUS_REV 1 /*!< Core revision r0p1 */
|
||||
#define __MPU_PRESENT 0 /*!< MPU present or not */
|
||||
#define __NVIC_PRIO_BITS 2 /*!< Number of bits used for Priority Levels */
|
||||
|
|
|
|||
|
|
@ -218,7 +218,11 @@ void I2S_Handler ( void );
|
|||
* \brief Configuration of the Cortex-M0+ Processor and Core Peripherals
|
||||
*/
|
||||
|
||||
#if defined(LITTLE_ENDIAN) && (LITTLE_ENDIAN != 1)
|
||||
#error "Little Endian is already defined, but to different value than expected?!"
|
||||
#else
|
||||
#define LITTLE_ENDIAN 1
|
||||
#endif
|
||||
#define __CM0PLUS_REV 1 /*!< Core revision r0p1 */
|
||||
#define __MPU_PRESENT 0 /*!< MPU present or not */
|
||||
#define __NVIC_PRIO_BITS 2 /*!< Number of bits used for Priority Levels */
|
||||
|
|
|
|||
|
|
@ -218,7 +218,11 @@ void I2S_Handler ( void );
|
|||
* \brief Configuration of the Cortex-M0+ Processor and Core Peripherals
|
||||
*/
|
||||
|
||||
#if defined(LITTLE_ENDIAN) && (LITTLE_ENDIAN != 1)
|
||||
#error "Little Endian is already defined, but to different value than expected?!"
|
||||
#else
|
||||
#define LITTLE_ENDIAN 1
|
||||
#endif
|
||||
#define __CM0PLUS_REV 1 /*!< Core revision r0p1 */
|
||||
#define __MPU_PRESENT 0 /*!< MPU present or not */
|
||||
#define __NVIC_PRIO_BITS 2 /*!< Number of bits used for Priority Levels */
|
||||
|
|
|
|||
|
|
@ -218,7 +218,11 @@ void I2S_Handler ( void );
|
|||
* \brief Configuration of the Cortex-M0+ Processor and Core Peripherals
|
||||
*/
|
||||
|
||||
#if defined(LITTLE_ENDIAN) && (LITTLE_ENDIAN != 1)
|
||||
#error "Little Endian is already defined, but to different value than expected?!"
|
||||
#else
|
||||
#define LITTLE_ENDIAN 1
|
||||
#endif
|
||||
#define __CM0PLUS_REV 1 /*!< Core revision r0p1 */
|
||||
#define __MPU_PRESENT 0 /*!< MPU present or not */
|
||||
#define __NVIC_PRIO_BITS 2 /*!< Number of bits used for Priority Levels */
|
||||
|
|
|
|||
|
|
@ -222,7 +222,11 @@ void I2S_Handler ( void );
|
|||
* \brief Configuration of the Cortex-M0+ Processor and Core Peripherals
|
||||
*/
|
||||
|
||||
#if defined(LITTLE_ENDIAN) && (LITTLE_ENDIAN != 1)
|
||||
#error "Little Endian is already defined, but to different value than expected?!"
|
||||
#else
|
||||
#define LITTLE_ENDIAN 1
|
||||
#endif
|
||||
#define __CM0PLUS_REV 1 /*!< Core revision r0p1 */
|
||||
#define __MPU_PRESENT 0 /*!< MPU present or not */
|
||||
#define __NVIC_PRIO_BITS 2 /*!< Number of bits used for Priority Levels */
|
||||
|
|
|
|||
|
|
@ -222,7 +222,11 @@ void I2S_Handler ( void );
|
|||
* \brief Configuration of the Cortex-M0+ Processor and Core Peripherals
|
||||
*/
|
||||
|
||||
#if defined(LITTLE_ENDIAN) && (LITTLE_ENDIAN != 1)
|
||||
#error "Little Endian is already defined, but to different value than expected?!"
|
||||
#else
|
||||
#define LITTLE_ENDIAN 1
|
||||
#endif
|
||||
#define __CM0PLUS_REV 1 /*!< Core revision r0p1 */
|
||||
#define __MPU_PRESENT 0 /*!< MPU present or not */
|
||||
#define __NVIC_PRIO_BITS 2 /*!< Number of bits used for Priority Levels */
|
||||
|
|
|
|||
|
|
@ -222,7 +222,11 @@ void I2S_Handler ( void );
|
|||
* \brief Configuration of the Cortex-M0+ Processor and Core Peripherals
|
||||
*/
|
||||
|
||||
#if defined(LITTLE_ENDIAN) && (LITTLE_ENDIAN != 1)
|
||||
#error "Little Endian is already defined, but to different value than expected?!"
|
||||
#else
|
||||
#define LITTLE_ENDIAN 1
|
||||
#endif
|
||||
#define __CM0PLUS_REV 1 /*!< Core revision r0p1 */
|
||||
#define __MPU_PRESENT 0 /*!< MPU present or not */
|
||||
#define __NVIC_PRIO_BITS 2 /*!< Number of bits used for Priority Levels */
|
||||
|
|
|
|||
|
|
@ -222,7 +222,11 @@ void I2S_Handler ( void );
|
|||
* \brief Configuration of the Cortex-M0+ Processor and Core Peripherals
|
||||
*/
|
||||
|
||||
#if defined(LITTLE_ENDIAN) && (LITTLE_ENDIAN != 1)
|
||||
#error "Little Endian is already defined, but to different value than expected?!"
|
||||
#else
|
||||
#define LITTLE_ENDIAN 1
|
||||
#endif
|
||||
#define __CM0PLUS_REV 1 /*!< Core revision r0p1 */
|
||||
#define __MPU_PRESENT 0 /*!< MPU present or not */
|
||||
#define __NVIC_PRIO_BITS 2 /*!< Number of bits used for Priority Levels */
|
||||
|
|
|
|||
|
|
@ -226,7 +226,11 @@ void I2S_Handler ( void );
|
|||
* \brief Configuration of the Cortex-M0+ Processor and Core Peripherals
|
||||
*/
|
||||
|
||||
#if defined(LITTLE_ENDIAN) && (LITTLE_ENDIAN != 1)
|
||||
#error "Little Endian is already defined, but to different value than expected?!"
|
||||
#else
|
||||
#define LITTLE_ENDIAN 1
|
||||
#endif
|
||||
#define __CM0PLUS_REV 1 /*!< Core revision r0p1 */
|
||||
#define __MPU_PRESENT 0 /*!< MPU present or not */
|
||||
#define __NVIC_PRIO_BITS 2 /*!< Number of bits used for Priority Levels */
|
||||
|
|
|
|||
|
|
@ -226,7 +226,11 @@ void I2S_Handler ( void );
|
|||
* \brief Configuration of the Cortex-M0+ Processor and Core Peripherals
|
||||
*/
|
||||
|
||||
#if defined(LITTLE_ENDIAN) && (LITTLE_ENDIAN != 1)
|
||||
#error "Little Endian is already defined, but to different value than expected?!"
|
||||
#else
|
||||
#define LITTLE_ENDIAN 1
|
||||
#endif
|
||||
#define __CM0PLUS_REV 1 /*!< Core revision r0p1 */
|
||||
#define __MPU_PRESENT 0 /*!< MPU present or not */
|
||||
#define __NVIC_PRIO_BITS 2 /*!< Number of bits used for Priority Levels */
|
||||
|
|
|
|||
|
|
@ -226,7 +226,11 @@ void I2S_Handler ( void );
|
|||
* \brief Configuration of the Cortex-M0+ Processor and Core Peripherals
|
||||
*/
|
||||
|
||||
#if defined(LITTLE_ENDIAN) && (LITTLE_ENDIAN != 1)
|
||||
#error "Little Endian is already defined, but to different value than expected?!"
|
||||
#else
|
||||
#define LITTLE_ENDIAN 1
|
||||
#endif
|
||||
#define __CM0PLUS_REV 1 /*!< Core revision r0p1 */
|
||||
#define __MPU_PRESENT 0 /*!< MPU present or not */
|
||||
#define __NVIC_PRIO_BITS 2 /*!< Number of bits used for Priority Levels */
|
||||
|
|
|
|||
|
|
@ -226,7 +226,11 @@ void I2S_Handler ( void );
|
|||
* \brief Configuration of the Cortex-M0+ Processor and Core Peripherals
|
||||
*/
|
||||
|
||||
#if defined(LITTLE_ENDIAN) && (LITTLE_ENDIAN != 1)
|
||||
#error "Little Endian is already defined, but to different value than expected?!"
|
||||
#else
|
||||
#define LITTLE_ENDIAN 1
|
||||
#endif
|
||||
#define __CM0PLUS_REV 1 /*!< Core revision r0p1 */
|
||||
#define __MPU_PRESENT 0 /*!< MPU present or not */
|
||||
#define __NVIC_PRIO_BITS 2 /*!< Number of bits used for Priority Levels */
|
||||
|
|
|
|||
|
|
@ -20,6 +20,35 @@
|
|||
#ifndef _BOARD_DEFINITIONS_H_
|
||||
#define _BOARD_DEFINITIONS_H_
|
||||
|
||||
#if defined(BOARD_ID_arduino_zero)
|
||||
#include "board_definitions_arduino_zero.h"
|
||||
#elif defined(BOARD_ID_genuino_zero)
|
||||
#include "board_definitions_genuino_zero.h"
|
||||
#elif defined(BOARD_ID_arduino_mkr1000)
|
||||
#include "board_definitions_arduino_mkr1000.h"
|
||||
#elif defined(BOARD_ID_genuino_mkr1000)
|
||||
#include "board_definitions_genuino_mkr1000.h"
|
||||
#elif defined(BOARD_ID_arduino_mkrzero)
|
||||
#include "board_definitions_arduino_mkrzero.h"
|
||||
#elif defined(BOARD_ID_arduino_mkrfox1200)
|
||||
#include "board_definitions_arduino_mkrfox1200.h"
|
||||
#elif defined(BOARD_ID_arduino_mkrgsm1400)
|
||||
#include "board_definitions_arduino_mkrgsm1400.h"
|
||||
#elif defined(BOARD_ID_arduino_mkrwan1300)
|
||||
#include "board_definitions_arduino_mkrwan1300.h"
|
||||
#elif defined(BOARD_ID_arduino_mkrwifi1010)
|
||||
#include "board_definitions_arduino_mkrwifi1010.h"
|
||||
#elif defined(BOARD_ID_arduino_mkrnb1500)
|
||||
#include "board_definitions_arduino_mkrnb1500.h"
|
||||
#else
|
||||
#error You must define a BOARD_ID and add the corresponding definitions in board_definitions.h
|
||||
#endif
|
||||
|
||||
// Common definitions
|
||||
// ------------------
|
||||
|
||||
#define BOOT_PIN_MASK (1U << (BOOT_LOAD_PIN & 0x1f))
|
||||
|
||||
/*
|
||||
* If BOOT_DOUBLE_TAP_ADDRESS is defined the bootloader is started by
|
||||
* quickly tapping two times on the reset button.
|
||||
|
|
|
|||
86
bootloaders/zero/board_definitions_arduino_mkrnb1500.h
Normal file
86
bootloaders/zero/board_definitions_arduino_mkrnb1500.h
Normal file
|
|
@ -0,0 +1,86 @@
|
|||
/*
|
||||
Copyright (c) 2016 Arduino LLC. All right reserved.
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
See the GNU Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#ifndef _BOARD_DEFINITIONS_H_
|
||||
#define _BOARD_DEFINITIONS_H_
|
||||
|
||||
/*
|
||||
* USB device definitions
|
||||
*/
|
||||
#define STRING_PRODUCT "Arduino MKR NB 1500"
|
||||
#define USB_VID_HIGH 0x23
|
||||
#define USB_VID_LOW 0x41
|
||||
#define USB_PID_HIGH 0x00
|
||||
#define USB_PID_LOW 0x55
|
||||
|
||||
/*
|
||||
* If BOOT_DOUBLE_TAP_ADDRESS is defined the bootloader is started by
|
||||
* quickly tapping two times on the reset button.
|
||||
* BOOT_DOUBLE_TAP_ADDRESS must point to a free SRAM cell that must not
|
||||
* be touched from the loaded application.
|
||||
*/
|
||||
#define BOOT_DOUBLE_TAP_ADDRESS (0x20007FFCul)
|
||||
#define BOOT_DOUBLE_TAP_DATA (*((volatile uint32_t *) BOOT_DOUBLE_TAP_ADDRESS))
|
||||
|
||||
/*
|
||||
* If BOOT_LOAD_PIN is defined the bootloader is started if the selected
|
||||
* pin is tied LOW.
|
||||
*/
|
||||
//#define BOOT_LOAD_PIN PIN_PA21
|
||||
//#define BOOT_LOAD_PIN PIN_PA15
|
||||
|
||||
#define BOOT_USART_MODULE SERCOM5
|
||||
#define BOOT_USART_BUS_CLOCK_INDEX PM_APBCMASK_SERCOM5
|
||||
#define BOOT_USART_PER_CLOCK_INDEX GCLK_CLKCTRL_ID_SERCOM5_CORE_Val
|
||||
#define BOOT_USART_PAD_SETTINGS UART_RX_PAD3_TX_PAD2
|
||||
#define BOOT_USART_PAD3 PINMUX_PB23D_SERCOM5_PAD3
|
||||
#define BOOT_USART_PAD2 PINMUX_PB22D_SERCOM5_PAD2
|
||||
#define BOOT_USART_PAD1 PINMUX_UNUSED
|
||||
#define BOOT_USART_PAD0 PINMUX_UNUSED
|
||||
|
||||
/* Master clock frequency */
|
||||
#define CPU_FREQUENCY (48000000ul)
|
||||
#define VARIANT_MCK CPU_FREQUENCY
|
||||
|
||||
/* Frequency of the board main oscillator */
|
||||
#define VARIANT_MAINOSC (32768ul)
|
||||
|
||||
/* Calibration values for DFLL48 pll */
|
||||
#define NVM_SW_CALIB_DFLL48M_COARSE_VAL (58)
|
||||
#define NVM_SW_CALIB_DFLL48M_FINE_VAL (64)
|
||||
|
||||
/*
|
||||
* LEDs definitions
|
||||
*/
|
||||
// PA20 (digital pin 6)
|
||||
#define BOARD_LED_PORT (0)
|
||||
#define BOARD_LED_PIN (20)
|
||||
|
||||
#define CONFIGURE_PMIC 1
|
||||
#define PMIC_PIN_SCL 12
|
||||
#define PMIC_PIN_SDA 11
|
||||
#define PMIC_SERCOM SERCOM0
|
||||
|
||||
// No RX/TX led
|
||||
//#define BOARD_LEDRX_PORT
|
||||
//#define BOARD_LEDRX_PIN
|
||||
|
||||
//#define BOARD_LEDTX_PORT
|
||||
//#define BOARD_LEDTX_PIN
|
||||
|
||||
#endif // _BOARD_DEFINITIONS_H_
|
||||
|
|
@ -25,5 +25,8 @@ mv -v samd21_sam_ba_arduino_mkrwan1300.* ../mkrwan1300/
|
|||
BOARD_ID=arduino_mkrwifi1010 NAME=samd21_sam_ba_arduino_mkrwifi1010 make clean all
|
||||
mv -v samd21_sam_ba_arduino_mkrwifi1010.* ../mkrwifi1010/
|
||||
|
||||
BOARD_ID=arduino_mkrnb1500 NAME=samd21_sam_ba_arduino_mkrnb1500 make clean all
|
||||
mv -v samd21_sam_ba_arduino_mkrnb1500.* ../mkrnb1500/
|
||||
|
||||
echo Done building bootloaders!
|
||||
|
||||
|
|
|
|||
|
|
@ -97,8 +97,33 @@ void loop( void ) ;
|
|||
#undef abs
|
||||
#endif // abs
|
||||
|
||||
#define min(a,b) ((a)<(b)?(a):(b))
|
||||
#define max(a,b) ((a)>(b)?(a):(b))
|
||||
#ifdef __cplusplus
|
||||
template<class T, class L>
|
||||
auto min(const T& a, const L& b) -> decltype((b < a) ? b : a)
|
||||
{
|
||||
return (b < a) ? b : a;
|
||||
}
|
||||
|
||||
template<class T, class L>
|
||||
auto max(const T& a, const L& b) -> decltype((b < a) ? b : a)
|
||||
{
|
||||
return (a < b) ? b : a;
|
||||
}
|
||||
#else
|
||||
#ifndef min
|
||||
#define min(a,b) \
|
||||
({ __typeof__ (a) _a = (a); \
|
||||
__typeof__ (b) _b = (b); \
|
||||
_a < _b ? _a : _b; })
|
||||
#endif
|
||||
#ifndef max
|
||||
#define max(a,b) \
|
||||
({ __typeof__ (a) _a = (a); \
|
||||
__typeof__ (b) _b = (b); \
|
||||
_a > _b ? _a : _b; })
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#define abs(x) ((x)>0?(x):-(x))
|
||||
#define constrain(amt,low,high) ((amt)<(low)?(low):((amt)>(high)?(high):(amt)))
|
||||
#define round(x) ((x)>=0?(long)((x)+0.5):(long)((x)-0.5))
|
||||
|
|
@ -124,10 +149,14 @@ void loop( void ) ;
|
|||
#define digitalPinToInterrupt(P) ( P )
|
||||
#endif
|
||||
|
||||
// USB Device
|
||||
// USB
|
||||
#ifdef USE_TINYUSB
|
||||
#include "Adafruit_TinyUSB_Core.h"
|
||||
#else
|
||||
#include "USB/USBDesc.h"
|
||||
#include "USB/USBCore.h"
|
||||
#include "USB/USBAPI.h"
|
||||
#include "USB/USB_host.h"
|
||||
#endif
|
||||
|
||||
#endif // Arduino_h
|
||||
|
|
|
|||
|
|
@ -68,7 +68,7 @@ class HardwareSerial : public Stream
|
|||
{
|
||||
public:
|
||||
virtual void begin(unsigned long) {}
|
||||
virtual void begin(unsigned long baudrate, uint16_t config) {}
|
||||
virtual void begin(unsigned long, uint16_t) {}
|
||||
virtual void end() {}
|
||||
virtual int available(void) = 0;
|
||||
virtual int peek(void) = 0;
|
||||
|
|
|
|||
|
|
@ -186,6 +186,16 @@ size_t Print::println(const Printable& x)
|
|||
return n;
|
||||
}
|
||||
|
||||
void Print::printf(const char format[], ...)
|
||||
{
|
||||
char buf[PRINTF_BUF];
|
||||
va_list ap;
|
||||
va_start(ap, format);
|
||||
vsnprintf(buf, sizeof(buf), format, ap);
|
||||
write(buf);
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
// Private Methods /////////////////////////////////////////////////////////////
|
||||
|
||||
size_t Print::printNumber(unsigned long n, uint8_t base)
|
||||
|
|
@ -238,14 +248,14 @@ size_t Print::printFloat(double number, uint8_t digits)
|
|||
|
||||
// Print the decimal point, but only if there are digits beyond
|
||||
if (digits > 0) {
|
||||
n += print('.');
|
||||
n += print(".");
|
||||
}
|
||||
|
||||
// Extract digits from the remainder one at a time
|
||||
while (digits-- > 0)
|
||||
{
|
||||
remainder *= 10.0;
|
||||
unsigned int toPrint = (unsigned int)(remainder);
|
||||
unsigned int toPrint = (unsigned int)remainder;
|
||||
n += print(toPrint);
|
||||
remainder -= toPrint;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -21,6 +21,8 @@
|
|||
|
||||
#include <inttypes.h>
|
||||
#include <stdio.h> // for size_t
|
||||
#include <stdarg.h> // for printf
|
||||
#define PRINTF_BUF 80
|
||||
|
||||
#include "WString.h"
|
||||
#include "Printable.h"
|
||||
|
|
@ -28,9 +30,6 @@
|
|||
#define DEC 10
|
||||
#define HEX 16
|
||||
#define OCT 8
|
||||
#ifdef BIN // Prevent warnings if BIN is previously defined in "iotnx4.h" or similar
|
||||
#undef BIN
|
||||
#endif
|
||||
#define BIN 2
|
||||
|
||||
class Print
|
||||
|
|
@ -86,6 +85,8 @@ class Print
|
|||
size_t println(const Printable&);
|
||||
size_t println(void);
|
||||
|
||||
void printf(const char[], ...);
|
||||
|
||||
virtual void flush() { /* Empty implementation for backward compatibility */ }
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -27,7 +27,10 @@
|
|||
// using a ring buffer (I think), in which head is the index of the location
|
||||
// to which to write the next incoming character and tail is the index of the
|
||||
// location from which to read.
|
||||
#define SERIAL_BUFFER_SIZE 164
|
||||
|
||||
#ifndef SERIAL_BUFFER_SIZE
|
||||
#define SERIAL_BUFFER_SIZE 350
|
||||
#endif
|
||||
|
||||
template <int N>
|
||||
class RingBufferN
|
||||
|
|
|
|||
|
|
@ -30,6 +30,24 @@
|
|||
SERCOM::SERCOM(Sercom* s)
|
||||
{
|
||||
sercom = s;
|
||||
|
||||
#if defined(__SAMD51__)
|
||||
// A briefly-available but now deprecated feature had the SPI clock source
|
||||
// set via a compile-time setting (MAX_SPI)...problem was this affected
|
||||
// ALL SERCOMs, whereas some (anything read/write, e.g. SD cards) should
|
||||
// not exceed the standard 24 MHz setting. Newer code, if it needs faster
|
||||
// write-only SPI (e.g. to screen), should override the SERCOM clock on a
|
||||
// per-peripheral basis. Nonetheless, we check SERCOM_SPI_FREQ_REF here
|
||||
// (MAX_SPI * 2) to retain compatibility with any interim projects that
|
||||
// might have relied on the compile-time setting. But please, don't.
|
||||
#if SERCOM_SPI_FREQ_REF == F_CPU // F_CPU clock = GCLK0
|
||||
clockSource = SERCOM_CLOCK_SOURCE_FCPU;
|
||||
#elif SERCOM_SPI_FREQ_REF == 48000000 // 48 MHz clock = GCLK1 (standard)
|
||||
clockSource = SERCOM_CLOCK_SOURCE_48M;
|
||||
#elif SERCOM_SPI_FREQ_REF == 100000000 // 100 MHz clock = GCLK2
|
||||
clockSource = SERCOM_CLOCK_SOURCE_100M;
|
||||
#endif
|
||||
#endif // end __SAMD51__
|
||||
}
|
||||
|
||||
/* =========================
|
||||
|
|
@ -75,13 +93,15 @@ void SERCOM::initUART(SercomUartMode mode, SercomUartSampleRate sampleRate, uint
|
|||
void SERCOM::initFrame(SercomUartCharSize charSize, SercomDataOrder dataOrder, SercomParityMode parityMode, SercomNumberStopBit nbStopBits)
|
||||
{
|
||||
//Setting the CTRLA register
|
||||
sercom->USART.CTRLA.reg |= SERCOM_USART_CTRLA_FORM( (parityMode == SERCOM_NO_PARITY ? 0 : 1) ) |
|
||||
sercom->USART.CTRLA.reg |=
|
||||
SERCOM_USART_CTRLA_FORM((parityMode == SERCOM_NO_PARITY ? 0 : 1) ) |
|
||||
dataOrder << SERCOM_USART_CTRLA_DORD_Pos;
|
||||
|
||||
//Setting the CTRLB register
|
||||
sercom->USART.CTRLB.reg |= SERCOM_USART_CTRLB_CHSIZE(charSize) |
|
||||
nbStopBits << SERCOM_USART_CTRLB_SBMODE_Pos |
|
||||
(parityMode == SERCOM_NO_PARITY ? 0 : parityMode) << SERCOM_USART_CTRLB_PMODE_Pos; //If no parity use default value
|
||||
(parityMode == SERCOM_NO_PARITY ? 0 : parityMode) <<
|
||||
SERCOM_USART_CTRLB_PMODE_Pos; //If no parity use default value
|
||||
}
|
||||
|
||||
void SERCOM::initPads(SercomUartTXPad txPad, SercomRXPad rxPad)
|
||||
|
|
@ -228,7 +248,6 @@ void SERCOM::initSPI(SercomSpiTXPad mosi, SercomRXPad miso, SercomSpiCharSize ch
|
|||
SERCOM_SPI_CTRLB_RXEN; //Active the SPI receiver.
|
||||
|
||||
while( sercom->SPI.SYNCBUSY.bit.CTRLB == 1 );
|
||||
|
||||
}
|
||||
|
||||
void SERCOM::initSPIClock(SercomSpiClockMode clockMode, uint32_t baudrate)
|
||||
|
|
@ -302,14 +321,13 @@ SercomDataOrder SERCOM::getDataOrderSPI()
|
|||
|
||||
void SERCOM::setBaudrateSPI(uint8_t divider)
|
||||
{
|
||||
//Can't divide by 0
|
||||
if(divider == 0)
|
||||
return;
|
||||
disableSPI(); // Register is enable-protected
|
||||
|
||||
//Register enable-protected
|
||||
disableSPI();
|
||||
|
||||
sercom->SPI.BAUD.reg = calculateBaudrateSynchronous( SERCOM_FREQ_REF / divider );
|
||||
#if defined(__SAMD51__)
|
||||
sercom->SPI.BAUD.reg = calculateBaudrateSynchronous(freqRef / divider);
|
||||
#else
|
||||
sercom->SPI.BAUD.reg = calculateBaudrateSynchronous(SERCOM_SPI_FREQ_REF / divider);
|
||||
#endif
|
||||
|
||||
enableSPI();
|
||||
}
|
||||
|
|
@ -340,10 +358,7 @@ uint8_t SERCOM::transferDataSPI(uint8_t data)
|
|||
{
|
||||
sercom->SPI.DATA.bit.DATA = data; // Writing data into Data register
|
||||
|
||||
while( sercom->SPI.INTFLAG.bit.RXC == 0 )
|
||||
{
|
||||
// Waiting Complete Reception
|
||||
}
|
||||
while(sercom->SPI.INTFLAG.bit.RXC == 0); // Waiting Complete Reception
|
||||
|
||||
return sercom->SPI.DATA.bit.DATA; // Reading data
|
||||
}
|
||||
|
|
@ -371,9 +386,14 @@ bool SERCOM::isDataRegisterEmptySPI()
|
|||
// return sercom->SPI.INTFLAG.bit.RXC;
|
||||
//}
|
||||
|
||||
uint8_t SERCOM::calculateBaudrateSynchronous(uint32_t baudrate)
|
||||
{
|
||||
return SERCOM_FREQ_REF / (2 * baudrate) - 1;
|
||||
uint8_t SERCOM::calculateBaudrateSynchronous(uint32_t baudrate) {
|
||||
#if defined(__SAMD51__)
|
||||
uint16_t b = freqRef / (2 * baudrate);
|
||||
#else
|
||||
uint16_t b = SERCOM_SPI_FREQ_REF / (2 * baudrate);
|
||||
#endif
|
||||
if(b > 0) b--; // Don't -1 on baud calc if already at 0
|
||||
return b;
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -517,8 +537,18 @@ bool SERCOM::startTransmissionWIRE(uint8_t address, SercomWireReadWriteFlag flag
|
|||
// 7-bits address + 1-bits R/W
|
||||
address = (address << 0x1ul) | flag;
|
||||
|
||||
// Wait idle or owner bus mode
|
||||
while ( !isBusIdleWIRE() && !isBusOwnerWIRE() );
|
||||
// If another master owns the bus or the last bus owner has not properly
|
||||
// sent a stop, return failure early. This will prevent some misbehaved
|
||||
// devices from deadlocking here at the cost of the caller being responsible
|
||||
// for retrying the failed transmission. See SercomWireBusState for the
|
||||
// possible bus states.
|
||||
if(!isBusOwnerWIRE())
|
||||
{
|
||||
if( isBusBusyWIRE() || (isArbLostWIRE() && !isBusIdleWIRE()) || isBusUnknownWIRE() )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Send start and address
|
||||
sercom->I2CM.ADDR.bit.ADDR = address;
|
||||
|
|
@ -614,6 +644,21 @@ bool SERCOM::isBusOwnerWIRE( void )
|
|||
return sercom->I2CM.STATUS.bit.BUSSTATE == WIRE_OWNER_STATE;
|
||||
}
|
||||
|
||||
bool SERCOM::isBusUnknownWIRE( void )
|
||||
{
|
||||
return sercom->I2CM.STATUS.bit.BUSSTATE == WIRE_UNKNOWN_STATE;
|
||||
}
|
||||
|
||||
bool SERCOM::isArbLostWIRE( void )
|
||||
{
|
||||
return sercom->I2CM.STATUS.bit.ARBLOST == 1;
|
||||
}
|
||||
|
||||
bool SERCOM::isBusBusyWIRE( void )
|
||||
{
|
||||
return sercom->I2CM.STATUS.bit.BUSSTATE == WIRE_BUSY_STATE;
|
||||
}
|
||||
|
||||
bool SERCOM::isDataReadyWIRE( void )
|
||||
{
|
||||
return sercom->I2CS.INTFLAG.bit.DRDY;
|
||||
|
|
@ -669,199 +714,152 @@ uint8_t SERCOM::readDataWIRE( void )
|
|||
}
|
||||
}
|
||||
|
||||
#if defined(__SAMD51__)
|
||||
|
||||
static const struct {
|
||||
Sercom *sercomPtr;
|
||||
uint8_t id_core;
|
||||
uint8_t id_slow;
|
||||
IRQn_Type irq[4];
|
||||
} sercomData[] = {
|
||||
{ SERCOM0, SERCOM0_GCLK_ID_CORE, SERCOM0_GCLK_ID_SLOW,
|
||||
SERCOM0_0_IRQn, SERCOM0_1_IRQn, SERCOM0_2_IRQn, SERCOM0_3_IRQn },
|
||||
{ SERCOM1, SERCOM1_GCLK_ID_CORE, SERCOM1_GCLK_ID_SLOW,
|
||||
SERCOM1_0_IRQn, SERCOM1_1_IRQn, SERCOM1_2_IRQn, SERCOM1_3_IRQn },
|
||||
{ SERCOM2, SERCOM2_GCLK_ID_CORE, SERCOM2_GCLK_ID_SLOW,
|
||||
SERCOM2_0_IRQn, SERCOM2_1_IRQn, SERCOM2_2_IRQn, SERCOM2_3_IRQn },
|
||||
{ SERCOM3, SERCOM3_GCLK_ID_CORE, SERCOM3_GCLK_ID_SLOW,
|
||||
SERCOM3_0_IRQn, SERCOM3_1_IRQn, SERCOM3_2_IRQn, SERCOM3_3_IRQn },
|
||||
{ SERCOM4, SERCOM4_GCLK_ID_CORE, SERCOM4_GCLK_ID_SLOW,
|
||||
SERCOM4_0_IRQn, SERCOM4_1_IRQn, SERCOM4_2_IRQn, SERCOM4_3_IRQn },
|
||||
{ SERCOM5, SERCOM5_GCLK_ID_CORE, SERCOM5_GCLK_ID_SLOW,
|
||||
SERCOM5_0_IRQn, SERCOM5_1_IRQn, SERCOM5_2_IRQn, SERCOM5_3_IRQn },
|
||||
#if defined(SERCOM6)
|
||||
{ SERCOM6, SERCOM6_GCLK_ID_CORE, SERCOM6_GCLK_ID_SLOW,
|
||||
SERCOM6_0_IRQn, SERCOM6_1_IRQn, SERCOM6_2_IRQn, SERCOM6_3_IRQn },
|
||||
#endif
|
||||
#if defined(SERCOM7)
|
||||
{ SERCOM7, SERCOM7_GCLK_ID_CORE, SERCOM7_GCLK_ID_SLOW,
|
||||
SERCOM7_0_IRQn, SERCOM7_1_IRQn, SERCOM7_2_IRQn, SERCOM7_3_IRQn },
|
||||
#endif
|
||||
};
|
||||
|
||||
#else // end if SAMD51 (prob SAMD21)
|
||||
|
||||
static const struct {
|
||||
Sercom *sercomPtr;
|
||||
uint8_t clock;
|
||||
IRQn_Type irqn;
|
||||
} sercomData[] = {
|
||||
SERCOM0, GCM_SERCOM0_CORE, SERCOM0_IRQn,
|
||||
SERCOM1, GCM_SERCOM1_CORE, SERCOM1_IRQn,
|
||||
SERCOM2, GCM_SERCOM2_CORE, SERCOM2_IRQn,
|
||||
SERCOM3, GCM_SERCOM3_CORE, SERCOM3_IRQn,
|
||||
#if defined(SERCOM4)
|
||||
SERCOM4, GCM_SERCOM4_CORE, SERCOM4_IRQn,
|
||||
#endif
|
||||
#if defined(SERCOM5)
|
||||
SERCOM5, GCM_SERCOM5_CORE, SERCOM5_IRQn,
|
||||
#endif
|
||||
};
|
||||
|
||||
#endif // end !SAMD51
|
||||
|
||||
int8_t SERCOM::getSercomIndex(void) {
|
||||
for(uint8_t i=0; i<(sizeof(sercomData) / sizeof(sercomData[0])); i++) {
|
||||
if(sercom == sercomData[i].sercomPtr) return i;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
#if defined(__SAMD51__)
|
||||
// This is currently for overriding an SPI SERCOM's clock source only --
|
||||
// NOT for UART or WIRE SERCOMs, where it will have unintended consequences.
|
||||
// It does not check.
|
||||
// SERCOM clock source override is available only on SAMD51 (not 21).
|
||||
// A dummy function for SAMD21 (compiles to nothing) is present in SERCOM.h
|
||||
// so user code doesn't require a lot of conditional situations.
|
||||
void SERCOM::setClockSource(int8_t idx, SercomClockSource src, bool core) {
|
||||
|
||||
if(src == SERCOM_CLOCK_SOURCE_NO_CHANGE) return;
|
||||
|
||||
uint8_t clk_id = core ? sercomData[idx].id_core : sercomData[idx].id_slow;
|
||||
|
||||
GCLK->PCHCTRL[clk_id].bit.CHEN = 0; // Disable timer
|
||||
while(GCLK->PCHCTRL[clk_id].bit.CHEN); // Wait for disable
|
||||
|
||||
if(core) clockSource = src; // Save SercomClockSource value
|
||||
|
||||
// From cores/arduino/startup.c:
|
||||
// GCLK0 = F_CPU
|
||||
// GCLK1 = 48 MHz
|
||||
// GCLK2 = 100 MHz
|
||||
// GCLK3 = XOSC32K
|
||||
// GCLK4 = 12 MHz
|
||||
if(src == SERCOM_CLOCK_SOURCE_FCPU) {
|
||||
GCLK->PCHCTRL[clk_id].reg =
|
||||
GCLK_PCHCTRL_GEN_GCLK0_Val | (1 << GCLK_PCHCTRL_CHEN_Pos);
|
||||
if(core) freqRef = F_CPU; // Save clock frequency value
|
||||
} else if(src == SERCOM_CLOCK_SOURCE_48M) {
|
||||
GCLK->PCHCTRL[clk_id].reg =
|
||||
GCLK_PCHCTRL_GEN_GCLK1_Val | (1 << GCLK_PCHCTRL_CHEN_Pos);
|
||||
if(core) freqRef = 48000000;
|
||||
} else if(src == SERCOM_CLOCK_SOURCE_100M) {
|
||||
GCLK->PCHCTRL[clk_id].reg =
|
||||
GCLK_PCHCTRL_GEN_GCLK2_Val | (1 << GCLK_PCHCTRL_CHEN_Pos);
|
||||
if(core) freqRef = 100000000;
|
||||
} else if(src == SERCOM_CLOCK_SOURCE_32K) {
|
||||
GCLK->PCHCTRL[clk_id].reg =
|
||||
GCLK_PCHCTRL_GEN_GCLK3_Val | (1 << GCLK_PCHCTRL_CHEN_Pos);
|
||||
if(core) freqRef = 32768;
|
||||
} else if(src == SERCOM_CLOCK_SOURCE_12M) {
|
||||
GCLK->PCHCTRL[clk_id].reg =
|
||||
GCLK_PCHCTRL_GEN_GCLK4_Val | (1 << GCLK_PCHCTRL_CHEN_Pos);
|
||||
if(core) freqRef = 12000000;
|
||||
}
|
||||
|
||||
while(!GCLK->PCHCTRL[clk_id].bit.CHEN); // Wait for clock enable
|
||||
}
|
||||
#endif
|
||||
|
||||
void SERCOM::initClockNVIC( void )
|
||||
{
|
||||
int8_t idx = getSercomIndex();
|
||||
if(idx < 0) return; // We got a problem here
|
||||
|
||||
#if defined(__SAMD51__)
|
||||
uint32_t clk_core;
|
||||
uint32_t clk_slow;
|
||||
|
||||
if(sercom == SERCOM0)
|
||||
{
|
||||
clk_core = SERCOM0_GCLK_ID_CORE;
|
||||
clk_slow = SERCOM0_GCLK_ID_SLOW;
|
||||
|
||||
NVIC_ClearPendingIRQ(SERCOM0_0_IRQn);
|
||||
NVIC_ClearPendingIRQ(SERCOM0_1_IRQn);
|
||||
NVIC_ClearPendingIRQ(SERCOM0_2_IRQn);
|
||||
NVIC_ClearPendingIRQ(SERCOM0_3_IRQn);
|
||||
|
||||
NVIC_SetPriority (SERCOM0_0_IRQn, (1<<__NVIC_PRIO_BITS) - 1); /* set Priority */
|
||||
NVIC_SetPriority (SERCOM0_1_IRQn, (1<<__NVIC_PRIO_BITS) - 1);
|
||||
NVIC_SetPriority (SERCOM0_2_IRQn, (1<<__NVIC_PRIO_BITS) - 1);
|
||||
NVIC_SetPriority (SERCOM0_3_IRQn, (1<<__NVIC_PRIO_BITS) - 1);
|
||||
|
||||
NVIC_EnableIRQ(SERCOM0_0_IRQn);
|
||||
NVIC_EnableIRQ(SERCOM0_1_IRQn);
|
||||
NVIC_EnableIRQ(SERCOM0_2_IRQn);
|
||||
NVIC_EnableIRQ(SERCOM0_3_IRQn);
|
||||
for(uint8_t i=0; i<4; i++) {
|
||||
NVIC_ClearPendingIRQ(sercomData[idx].irq[i]);
|
||||
NVIC_SetPriority(sercomData[idx].irq[i], SERCOM_NVIC_PRIORITY);
|
||||
NVIC_EnableIRQ(sercomData[idx].irq[i]);
|
||||
}
|
||||
else if(sercom == SERCOM1)
|
||||
{
|
||||
clk_core = SERCOM1_GCLK_ID_CORE;
|
||||
clk_slow = SERCOM1_GCLK_ID_SLOW;
|
||||
|
||||
NVIC_ClearPendingIRQ(SERCOM1_0_IRQn);
|
||||
NVIC_ClearPendingIRQ(SERCOM1_1_IRQn);
|
||||
NVIC_ClearPendingIRQ(SERCOM1_2_IRQn);
|
||||
NVIC_ClearPendingIRQ(SERCOM1_3_IRQn);
|
||||
// SPI DMA speed is dictated by the "slow clock" (I think...maybe) so
|
||||
// BOTH are set to the same clock source (clk_slow isn't sourced from
|
||||
// XOSC32K as in prior versions of SAMD core).
|
||||
// This might have power implications for sleep code.
|
||||
|
||||
NVIC_SetPriority (SERCOM1_0_IRQn, (1<<__NVIC_PRIO_BITS) - 1); /* set Priority */
|
||||
NVIC_SetPriority (SERCOM1_1_IRQn, (1<<__NVIC_PRIO_BITS) - 1);
|
||||
NVIC_SetPriority (SERCOM1_2_IRQn, (1<<__NVIC_PRIO_BITS) - 1);
|
||||
NVIC_SetPriority (SERCOM1_3_IRQn, (1<<__NVIC_PRIO_BITS) - 1);
|
||||
setClockSource(idx, clockSource, true); // true = core clock
|
||||
setClockSource(idx, clockSource, false); // false = slow clock
|
||||
|
||||
NVIC_EnableIRQ(SERCOM1_0_IRQn);
|
||||
NVIC_EnableIRQ(SERCOM1_1_IRQn);
|
||||
NVIC_EnableIRQ(SERCOM1_2_IRQn);
|
||||
NVIC_EnableIRQ(SERCOM1_3_IRQn);
|
||||
}
|
||||
else if(sercom == SERCOM2)
|
||||
{
|
||||
clk_core = SERCOM2_GCLK_ID_CORE;
|
||||
clk_slow = SERCOM2_GCLK_ID_SLOW;
|
||||
#else // end if SAMD51 (prob SAMD21)
|
||||
|
||||
NVIC_ClearPendingIRQ(SERCOM2_0_IRQn);
|
||||
NVIC_ClearPendingIRQ(SERCOM2_1_IRQn);
|
||||
NVIC_ClearPendingIRQ(SERCOM2_2_IRQn);
|
||||
NVIC_ClearPendingIRQ(SERCOM2_3_IRQn);
|
||||
uint8_t clockId = sercomData[idx].clock;
|
||||
IRQn_Type IdNvic = sercomData[idx].irqn;
|
||||
|
||||
NVIC_SetPriority (SERCOM2_0_IRQn, (1<<__NVIC_PRIO_BITS) - 1); /* set Priority */
|
||||
NVIC_SetPriority (SERCOM2_1_IRQn, (1<<__NVIC_PRIO_BITS) - 1);
|
||||
NVIC_SetPriority (SERCOM2_2_IRQn, (1<<__NVIC_PRIO_BITS) - 1);
|
||||
NVIC_SetPriority (SERCOM2_3_IRQn, (1<<__NVIC_PRIO_BITS) - 1);
|
||||
|
||||
NVIC_EnableIRQ(SERCOM2_0_IRQn);
|
||||
NVIC_EnableIRQ(SERCOM2_1_IRQn);
|
||||
NVIC_EnableIRQ(SERCOM2_2_IRQn);
|
||||
NVIC_EnableIRQ(SERCOM2_3_IRQn);
|
||||
}
|
||||
else if(sercom == SERCOM3)
|
||||
{
|
||||
clk_core = SERCOM3_GCLK_ID_CORE;
|
||||
clk_slow = SERCOM3_GCLK_ID_SLOW;
|
||||
|
||||
NVIC_ClearPendingIRQ(SERCOM3_0_IRQn);
|
||||
NVIC_ClearPendingIRQ(SERCOM3_1_IRQn);
|
||||
NVIC_ClearPendingIRQ(SERCOM3_2_IRQn);
|
||||
NVIC_ClearPendingIRQ(SERCOM3_3_IRQn);
|
||||
|
||||
NVIC_SetPriority (SERCOM3_0_IRQn, (1<<__NVIC_PRIO_BITS) - 1); /* set Priority */
|
||||
NVIC_SetPriority (SERCOM3_1_IRQn, (1<<__NVIC_PRIO_BITS) - 1);
|
||||
NVIC_SetPriority (SERCOM3_2_IRQn, (1<<__NVIC_PRIO_BITS) - 1);
|
||||
NVIC_SetPriority (SERCOM3_3_IRQn, (1<<__NVIC_PRIO_BITS) - 1);
|
||||
|
||||
NVIC_EnableIRQ(SERCOM3_0_IRQn);
|
||||
NVIC_EnableIRQ(SERCOM3_1_IRQn);
|
||||
NVIC_EnableIRQ(SERCOM3_2_IRQn);
|
||||
NVIC_EnableIRQ(SERCOM3_3_IRQn);
|
||||
}
|
||||
else if(sercom == SERCOM4)
|
||||
{
|
||||
clk_core = SERCOM4_GCLK_ID_CORE;
|
||||
clk_slow = SERCOM4_GCLK_ID_SLOW;
|
||||
|
||||
NVIC_ClearPendingIRQ(SERCOM4_0_IRQn);
|
||||
NVIC_ClearPendingIRQ(SERCOM4_1_IRQn);
|
||||
NVIC_ClearPendingIRQ(SERCOM4_2_IRQn);
|
||||
NVIC_ClearPendingIRQ(SERCOM4_3_IRQn);
|
||||
|
||||
NVIC_SetPriority (SERCOM4_0_IRQn, (1<<__NVIC_PRIO_BITS) - 1); /* set Priority */
|
||||
NVIC_SetPriority (SERCOM4_1_IRQn, (1<<__NVIC_PRIO_BITS) - 1);
|
||||
NVIC_SetPriority (SERCOM4_2_IRQn, (1<<__NVIC_PRIO_BITS) - 1);
|
||||
NVIC_SetPriority (SERCOM4_3_IRQn, (1<<__NVIC_PRIO_BITS) - 1);
|
||||
|
||||
NVIC_EnableIRQ(SERCOM4_0_IRQn);
|
||||
NVIC_EnableIRQ(SERCOM4_1_IRQn);
|
||||
NVIC_EnableIRQ(SERCOM4_2_IRQn);
|
||||
NVIC_EnableIRQ(SERCOM4_3_IRQn);
|
||||
}
|
||||
else if(sercom == SERCOM5)
|
||||
{
|
||||
clk_core = SERCOM5_GCLK_ID_CORE;
|
||||
clk_slow = SERCOM5_GCLK_ID_SLOW;
|
||||
|
||||
NVIC_ClearPendingIRQ(SERCOM5_0_IRQn);
|
||||
NVIC_ClearPendingIRQ(SERCOM5_1_IRQn);
|
||||
NVIC_ClearPendingIRQ(SERCOM5_2_IRQn);
|
||||
NVIC_ClearPendingIRQ(SERCOM5_3_IRQn);
|
||||
|
||||
NVIC_SetPriority (SERCOM5_0_IRQn, (1<<__NVIC_PRIO_BITS) - 1); /* set Priority */
|
||||
NVIC_SetPriority (SERCOM5_1_IRQn, (1<<__NVIC_PRIO_BITS) - 1);
|
||||
NVIC_SetPriority (SERCOM5_2_IRQn, (1<<__NVIC_PRIO_BITS) - 1);
|
||||
NVIC_SetPriority (SERCOM5_3_IRQn, (1<<__NVIC_PRIO_BITS) - 1);
|
||||
|
||||
NVIC_EnableIRQ(SERCOM5_0_IRQn);
|
||||
NVIC_EnableIRQ(SERCOM5_1_IRQn);
|
||||
NVIC_EnableIRQ(SERCOM5_2_IRQn);
|
||||
NVIC_EnableIRQ(SERCOM5_3_IRQn);
|
||||
}
|
||||
#else
|
||||
|
||||
IRQn_Type IdNvic=PendSV_IRQn ; // Dummy init to intercept potential error later
|
||||
|
||||
uint8_t clockId = 0;
|
||||
if(sercom == SERCOM0)
|
||||
{
|
||||
clockId = GCM_SERCOM0_CORE;
|
||||
IdNvic = SERCOM0_IRQn;
|
||||
}
|
||||
else if(sercom == SERCOM1)
|
||||
{
|
||||
clockId = GCM_SERCOM1_CORE;
|
||||
IdNvic = SERCOM1_IRQn;
|
||||
}
|
||||
else if(sercom == SERCOM2)
|
||||
{
|
||||
clockId = GCM_SERCOM2_CORE;
|
||||
IdNvic = SERCOM2_IRQn;
|
||||
}
|
||||
else if(sercom == SERCOM3)
|
||||
{
|
||||
clockId = GCM_SERCOM3_CORE;
|
||||
IdNvic = SERCOM3_IRQn;
|
||||
}
|
||||
#if defined(SERCOM4)
|
||||
else if(sercom == SERCOM4)
|
||||
{
|
||||
clockId = GCM_SERCOM4_CORE;
|
||||
IdNvic = SERCOM4_IRQn;
|
||||
}
|
||||
#endif
|
||||
#if defined(SERCOM5)
|
||||
else if(sercom == SERCOM5)
|
||||
{
|
||||
clockId = GCM_SERCOM5_CORE;
|
||||
IdNvic = SERCOM5_IRQn;
|
||||
}
|
||||
#endif
|
||||
|
||||
if ( IdNvic == PendSV_IRQn )
|
||||
{
|
||||
// We got a problem here
|
||||
return ;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(__SAMD51__)
|
||||
GCLK->PCHCTRL[clk_core].reg = GCLK_PCHCTRL_GEN_GCLK1_Val | (1 << GCLK_PCHCTRL_CHEN_Pos);
|
||||
GCLK->PCHCTRL[clk_slow].reg = GCLK_PCHCTRL_GEN_GCLK3_Val | (1 << GCLK_PCHCTRL_CHEN_Pos);
|
||||
|
||||
#else
|
||||
// Setting NVIC
|
||||
NVIC_ClearPendingIRQ(IdNvic);
|
||||
NVIC_SetPriority (IdNvic, (1<<__NVIC_PRIO_BITS) - 1); /* set Priority */
|
||||
NVIC_SetPriority(IdNvic, SERCOM_NVIC_PRIORITY);
|
||||
NVIC_EnableIRQ(IdNvic);
|
||||
|
||||
// Setting clock
|
||||
GCLK->CLKCTRL.reg = GCLK_CLKCTRL_ID( clockId ) | // Generic Clock 0 (SERCOMx)
|
||||
GCLK->CLKCTRL.reg =
|
||||
GCLK_CLKCTRL_ID( clockId ) | // Generic Clock 0 (SERCOMx)
|
||||
GCLK_CLKCTRL_GEN_GCLK0 | // Generic Clock Generator 0 is source
|
||||
GCLK_CLKCTRL_CLKEN;
|
||||
|
||||
while ( GCLK->STATUS.reg & GCLK_STATUS_SYNCBUSY )
|
||||
{
|
||||
/* Wait for synchronization */
|
||||
}
|
||||
#endif
|
||||
while(GCLK->STATUS.reg & GCLK_STATUS_SYNCBUSY); // Wait for synchronization
|
||||
|
||||
#endif // end !SAMD51
|
||||
}
|
||||
|
|
|
|||
|
|
@ -21,6 +21,17 @@
|
|||
|
||||
#include "sam.h"
|
||||
|
||||
// SAMD51 has configurable MAX_SPI, else use peripheral clock default.
|
||||
// Update: changing MAX_SPI via compiler flags is DEPRECATED, because
|
||||
// this affects ALL SPI peripherals including some that should NOT be
|
||||
// changed (e.g. anything using SD card). Instead, use setClockSource().
|
||||
// This is left here for compatibility w/interim MAX_SPI-dependent code:
|
||||
#if defined(MAX_SPI)
|
||||
#define SERCOM_SPI_FREQ_REF (MAX_SPI * 2)
|
||||
#else
|
||||
#define SERCOM_SPI_FREQ_REF 48000000ul
|
||||
#endif
|
||||
// Other SERCOM peripherals always use the 48 MHz clock
|
||||
#define SERCOM_FREQ_REF 48000000ul
|
||||
#define SERCOM_NVIC_PRIORITY ((1<<__NVIC_PRIO_BITS) - 1)
|
||||
|
||||
|
|
@ -141,6 +152,19 @@ typedef enum
|
|||
WIRE_MASTER_NACK_ACTION
|
||||
} SercomMasterAckActionWire;
|
||||
|
||||
// SERCOM clock source override is available only on SAMD51 (not 21)
|
||||
// but the enumeration is made regardless so user code doesn't need
|
||||
// ifdefs or lengthy comments explaining the different situations --
|
||||
// the clock-sourcing functions just compile to nothing on SAMD21.
|
||||
typedef enum {
|
||||
SERCOM_CLOCK_SOURCE_FCPU, // F_CPU clock (GCLK0)
|
||||
SERCOM_CLOCK_SOURCE_48M, // 48 MHz peripheral clock (GCLK1) (standard)
|
||||
SERCOM_CLOCK_SOURCE_100M, // 100 MHz peripheral clock (GCLK2)
|
||||
SERCOM_CLOCK_SOURCE_32K, // XOSC32K clock (GCLK3)
|
||||
SERCOM_CLOCK_SOURCE_12M, // 12 MHz peripheral clock (GCLK4)
|
||||
SERCOM_CLOCK_SOURCE_NO_CHANGE // Leave clock source setting unchanged
|
||||
} SercomClockSource;
|
||||
|
||||
class SERCOM
|
||||
{
|
||||
public:
|
||||
|
|
@ -171,7 +195,6 @@ class SERCOM
|
|||
/* ========== SPI ========== */
|
||||
void initSPI(SercomSpiTXPad mosi, SercomRXPad miso, SercomSpiCharSize charSize, SercomDataOrder dataOrder) ;
|
||||
void initSPIClock(SercomSpiClockMode clockMode, uint32_t baudrate) ;
|
||||
|
||||
void resetSPI( void ) ;
|
||||
void enableSPI( void ) ;
|
||||
void disableSPI( void ) ;
|
||||
|
|
@ -202,6 +225,9 @@ class SERCOM
|
|||
bool isSlaveWIRE( void ) ;
|
||||
bool isBusIdleWIRE( void ) ;
|
||||
bool isBusOwnerWIRE( void ) ;
|
||||
bool isBusUnknownWIRE( void ) ;
|
||||
bool isArbLostWIRE( void );
|
||||
bool isBusBusyWIRE( void );
|
||||
bool isDataReadyWIRE( void ) ;
|
||||
bool isStopDetectedWIRE( void ) ;
|
||||
bool isRestartDetectedWIRE( void ) ;
|
||||
|
|
@ -210,9 +236,29 @@ class SERCOM
|
|||
bool isRXNackReceivedWIRE( void ) ;
|
||||
int availableWIRE( void ) ;
|
||||
uint8_t readDataWIRE( void ) ;
|
||||
int8_t getSercomIndex(void);
|
||||
#if defined(__SAMD51__)
|
||||
// SERCOM clock source override is only available on
|
||||
// SAMD51 (not 21) ... but these functions are declared
|
||||
// regardless so user code doesn't need ifdefs or lengthy
|
||||
// comments explaining the different situations -- these
|
||||
// just compile to nothing on SAMD21.
|
||||
void setClockSource(int8_t idx, SercomClockSource src, bool core);
|
||||
SercomClockSource getClockSource(void) { return clockSource; };
|
||||
uint32_t getFreqRef(void) { return freqRef; };
|
||||
#else
|
||||
// The equivalent SAMD21 dummy functions...
|
||||
void setClockSource(int8_t idx, SercomClockSource src, bool core) { (void)idx; (void)src; (void)core; };
|
||||
SercomClockSource getClockSource(void) { return SERCOM_CLOCK_SOURCE_FCPU; };
|
||||
uint32_t getFreqRef(void) { return F_CPU; };
|
||||
#endif
|
||||
|
||||
private:
|
||||
Sercom* sercom;
|
||||
#if defined(__SAMD51__)
|
||||
SercomClockSource clockSource;
|
||||
uint32_t freqRef; // Frequency corresponding to clockSource
|
||||
#endif
|
||||
uint8_t calculateBaudrateSynchronous(uint32_t baudrate);
|
||||
uint32_t division(uint32_t dividend, uint32_t divisor) ;
|
||||
void initClockNVIC( void ) ;
|
||||
|
|
|
|||
|
|
@ -35,6 +35,7 @@ int Stream::timedRead()
|
|||
do {
|
||||
c = read();
|
||||
if (c >= 0) return c;
|
||||
yield(); // running TinyUSB task
|
||||
} while(millis() - _startMillis < _timeout);
|
||||
return -1; // -1 indicates timeout
|
||||
}
|
||||
|
|
@ -47,6 +48,7 @@ int Stream::timedPeek()
|
|||
do {
|
||||
c = peek();
|
||||
if (c >= 0) return c;
|
||||
yield(); // running TinyUSB task
|
||||
} while(millis() - _startMillis < _timeout);
|
||||
return -1; // -1 indicates timeout
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1 @@
|
|||
Subproject commit e7b892095f2bb5d8bef6a748238369bdd268ed5e
|
||||
195
cores/arduino/TinyUSB/Adafruit_TinyUSB_SAMD.cpp
Normal file
195
cores/arduino/TinyUSB/Adafruit_TinyUSB_SAMD.cpp
Normal file
|
|
@ -0,0 +1,195 @@
|
|||
/*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2019, hathach for Adafruit
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifdef USE_TINYUSB
|
||||
|
||||
#include "Arduino.h"
|
||||
#include "Adafruit_TinyUSB_Core.h"
|
||||
#include <Reset.h> // Needed for auto-reset with 1200bps port touch
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// Forward USB interrupt events to TinyUSB IRQ Handler
|
||||
//--------------------------------------------------------------------+
|
||||
extern "C"
|
||||
{
|
||||
#if defined(__SAMD51__)
|
||||
|
||||
void USB_0_Handler (void) { tud_int_handler(0); }
|
||||
void USB_1_Handler (void) { tud_int_handler(0); }
|
||||
void USB_2_Handler (void) { tud_int_handler(0); }
|
||||
void USB_3_Handler (void) { tud_int_handler(0); }
|
||||
|
||||
#else
|
||||
|
||||
void USB_Handler(void) { tud_int_handler(0); }
|
||||
|
||||
#endif
|
||||
} // extern C
|
||||
|
||||
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// MACRO TYPEDEF CONSTANT ENUM DECLARATION
|
||||
//--------------------------------------------------------------------+
|
||||
static void usb_hardware_init(void);
|
||||
|
||||
#if CFG_TUSB_DEBUG
|
||||
extern "C" int serial1_printf(const char *__restrict format, ...)
|
||||
{
|
||||
char buf[PRINTF_BUF];
|
||||
va_list ap;
|
||||
va_start(ap, format);
|
||||
vsnprintf(buf, sizeof(buf), format, ap);
|
||||
Serial1.write(buf);
|
||||
va_end(ap);
|
||||
|
||||
}
|
||||
#endif
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// Core Init & Touch1200
|
||||
//--------------------------------------------------------------------+
|
||||
void Adafruit_TinyUSB_Core_init(void)
|
||||
{
|
||||
#if CFG_TUSB_DEBUG
|
||||
Serial1.begin(115200);
|
||||
serial1_printf("TinyUSB debugging with Serial1\n");
|
||||
#endif
|
||||
|
||||
Serial.setStringDescriptor("TinyUSB Serial");
|
||||
USBDevice.addInterface(Serial);
|
||||
USBDevice.setID(USB_VID, USB_PID);
|
||||
USBDevice.begin();
|
||||
|
||||
usb_hardware_init();
|
||||
|
||||
// Init tinyusb stack
|
||||
tusb_init();
|
||||
}
|
||||
|
||||
void Adafruit_TinyUSB_Core_touch1200(void)
|
||||
{
|
||||
initiateReset(250);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// Adafruit_USBD_Device platform dependent
|
||||
//--------------------------------------------------------------------+
|
||||
|
||||
uint8_t Adafruit_USBD_Device::getSerialDescriptor(uint16_t* serial_str)
|
||||
{
|
||||
enum { SERIAL_BYTE_LEN = 16 };
|
||||
|
||||
#ifdef __SAMD51__
|
||||
uint32_t* id_addresses[4] = {(uint32_t *) 0x008061FC, (uint32_t *) 0x00806010,
|
||||
(uint32_t *) 0x00806014, (uint32_t *) 0x00806018};
|
||||
#else // samd21
|
||||
uint32_t* id_addresses[4] = {(uint32_t *) 0x0080A00C, (uint32_t *) 0x0080A040,
|
||||
(uint32_t *) 0x0080A044, (uint32_t *) 0x0080A048};
|
||||
|
||||
#endif
|
||||
|
||||
uint8_t raw_id[SERIAL_BYTE_LEN];
|
||||
|
||||
for (int i=0; i<4; i++) {
|
||||
for (int k=0; k<4; k++) {
|
||||
raw_id[4 * i + (3 - k)] = (*(id_addresses[i]) >> k * 8) & 0xff;
|
||||
}
|
||||
}
|
||||
|
||||
static const char nibble_to_hex[16] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'};
|
||||
|
||||
for (unsigned int i = 0; i < sizeof(raw_id); i++) {
|
||||
for (int j = 0; j < 2; j++) {
|
||||
uint8_t nibble = (raw_id[i] >> (j * 4)) & 0xf;
|
||||
// Strings are UTF-16-LE encoded.
|
||||
serial_str[i * 2 + (1 - j)] = nibble_to_hex[nibble];
|
||||
}
|
||||
}
|
||||
|
||||
return sizeof(raw_id)*2;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// Helpers
|
||||
//--------------------------------------------------------------------+
|
||||
|
||||
// Init usb hardware when starting up. Softdevice is not enabled yet
|
||||
static void usb_hardware_init(void)
|
||||
{
|
||||
#ifdef PIN_LED_TXL
|
||||
// txLEDPulse = 0;
|
||||
pinMode(PIN_LED_TXL, OUTPUT);
|
||||
digitalWrite(PIN_LED_TXL, HIGH);
|
||||
#endif
|
||||
|
||||
#ifdef PIN_LED_RXL
|
||||
// rxLEDPulse = 0;
|
||||
pinMode(PIN_LED_RXL, OUTPUT);
|
||||
digitalWrite(PIN_LED_RXL, HIGH);
|
||||
#endif
|
||||
|
||||
/* Enable USB clock */
|
||||
#if defined(__SAMD51__)
|
||||
MCLK->APBBMASK.reg |= MCLK_APBBMASK_USB;
|
||||
MCLK->AHBMASK.reg |= MCLK_AHBMASK_USB;
|
||||
|
||||
// Set up the USB DP/DN pins
|
||||
PORT->Group[0].PINCFG[PIN_PA24H_USB_DM].bit.PMUXEN = 1;
|
||||
PORT->Group[0].PMUX[PIN_PA24H_USB_DM/2].reg &= ~(0xF << (4 * (PIN_PA24H_USB_DM & 0x01u)));
|
||||
PORT->Group[0].PMUX[PIN_PA24H_USB_DM/2].reg |= MUX_PA24H_USB_DM << (4 * (PIN_PA24H_USB_DM & 0x01u));
|
||||
PORT->Group[0].PINCFG[PIN_PA25H_USB_DP].bit.PMUXEN = 1;
|
||||
PORT->Group[0].PMUX[PIN_PA25H_USB_DP/2].reg &= ~(0xF << (4 * (PIN_PA25H_USB_DP & 0x01u)));
|
||||
PORT->Group[0].PMUX[PIN_PA25H_USB_DP/2].reg |= MUX_PA25H_USB_DP << (4 * (PIN_PA25H_USB_DP & 0x01u));
|
||||
|
||||
|
||||
GCLK->PCHCTRL[USB_GCLK_ID].reg = GCLK_PCHCTRL_GEN_GCLK1_Val | (1 << GCLK_PCHCTRL_CHEN_Pos);
|
||||
|
||||
NVIC_SetPriority(USB_0_IRQn, 0UL);
|
||||
NVIC_SetPriority(USB_1_IRQn, 0UL);
|
||||
NVIC_SetPriority(USB_2_IRQn, 0UL);
|
||||
NVIC_SetPriority(USB_3_IRQn, 0UL);
|
||||
#else
|
||||
PM->APBBMASK.reg |= PM_APBBMASK_USB;
|
||||
|
||||
// Set up the USB DP/DN pins
|
||||
PORT->Group[0].PINCFG[PIN_PA24G_USB_DM].bit.PMUXEN = 1;
|
||||
PORT->Group[0].PMUX[PIN_PA24G_USB_DM/2].reg &= ~(0xF << (4 * (PIN_PA24G_USB_DM & 0x01u)));
|
||||
PORT->Group[0].PMUX[PIN_PA24G_USB_DM/2].reg |= MUX_PA24G_USB_DM << (4 * (PIN_PA24G_USB_DM & 0x01u));
|
||||
PORT->Group[0].PINCFG[PIN_PA25G_USB_DP].bit.PMUXEN = 1;
|
||||
PORT->Group[0].PMUX[PIN_PA25G_USB_DP/2].reg &= ~(0xF << (4 * (PIN_PA25G_USB_DP & 0x01u)));
|
||||
PORT->Group[0].PMUX[PIN_PA25G_USB_DP/2].reg |= MUX_PA25G_USB_DP << (4 * (PIN_PA25G_USB_DP & 0x01u));
|
||||
|
||||
// Put Generic Clock Generator 0 as source for Generic Clock Multiplexer 6 (USB reference)
|
||||
GCLK->CLKCTRL.reg = GCLK_CLKCTRL_ID(6) | // Generic Clock Multiplexer 6
|
||||
GCLK_CLKCTRL_GEN_GCLK0 | // Generic Clock Generator 0 is source
|
||||
GCLK_CLKCTRL_CLKEN;
|
||||
while (GCLK->STATUS.bit.SYNCBUSY)
|
||||
;
|
||||
|
||||
NVIC_SetPriority((IRQn_Type) USB_IRQn, 0UL);
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif // USE_TINYUSB
|
||||
93
cores/arduino/TinyUSB/tusb_config.h
Normal file
93
cores/arduino/TinyUSB/tusb_config.h
Normal file
|
|
@ -0,0 +1,93 @@
|
|||
/*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2018, hathach for Adafruit
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef _TUSB_CONFIG_H_
|
||||
#define _TUSB_CONFIG_H_
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
// COMMON CONFIGURATION
|
||||
//--------------------------------------------------------------------
|
||||
#ifdef __SAMD51__
|
||||
#define CFG_TUSB_MCU OPT_MCU_SAMD51
|
||||
#else
|
||||
#define CFG_TUSB_MCU OPT_MCU_SAMD21
|
||||
#endif
|
||||
|
||||
#ifdef USE_TINYUSB
|
||||
#define CFG_TUSB_RHPORT0_MODE OPT_MODE_DEVICE
|
||||
#else
|
||||
#define CFG_TUSB_RHPORT0_MODE OPT_MODE_NONE
|
||||
#endif
|
||||
|
||||
#define CFG_TUSB_OS OPT_OS_NONE
|
||||
|
||||
#define CFG_TUSB_DEBUG 0
|
||||
#if CFG_TUSB_DEBUG
|
||||
#define tu_printf serial1_printf
|
||||
extern int serial1_printf(const char *__restrict __format, ...);
|
||||
#endif
|
||||
|
||||
#define CFG_TUSB_MEM_SECTION
|
||||
#define CFG_TUSB_MEM_ALIGN TU_ATTR_ALIGNED(4)
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
// DEVICE CONFIGURATION
|
||||
//--------------------------------------------------------------------
|
||||
|
||||
#define CFG_TUD_ENDOINT0_SIZE 64
|
||||
|
||||
//------------- CLASS -------------//
|
||||
#define CFG_TUD_CDC 1
|
||||
#define CFG_TUD_MSC 1
|
||||
#define CFG_TUD_HID 1
|
||||
#define CFG_TUD_MIDI 1
|
||||
#define CFG_TUD_VENDOR 1
|
||||
|
||||
// CDC FIFO size of TX and RX
|
||||
#define CFG_TUD_CDC_RX_BUFSIZE 256
|
||||
#define CFG_TUD_CDC_TX_BUFSIZE 256
|
||||
|
||||
// MSC Buffer size of Device Mass storage
|
||||
#define CFG_TUD_MSC_BUFSIZE 512
|
||||
|
||||
// HID buffer size Should be sufficient to hold ID (if any) + Data
|
||||
#define CFG_TUD_HID_BUFSIZE 64
|
||||
|
||||
// MIDI FIFO size of TX and RX
|
||||
#define CFG_TUD_MIDI_RX_BUFSIZE 128
|
||||
#define CFG_TUD_MIDI_TX_BUFSIZE 128
|
||||
|
||||
// Vendor FIFO size of TX and RX
|
||||
#define CFG_TUD_VENDOR_RX_BUFSIZE 64
|
||||
#define CFG_TUD_VENDOR_TX_BUFSIZE 64
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _TUSB_CONFIG_H_ */
|
||||
|
|
@ -20,12 +20,6 @@
|
|||
#include "Tone.h"
|
||||
#include "variant.h"
|
||||
|
||||
#if defined(__SAMD51__)
|
||||
#define WAIT_TC16_REGS_SYNC(x) while(x->COUNT16.SYNCBUSY.bit.ENABLE);
|
||||
#else
|
||||
#define WAIT_TC16_REGS_SYNC(x) while(x->COUNT16.STATUS.bit.SYNCBUSY);
|
||||
#endif
|
||||
|
||||
uint32_t toneMaxFrequency = F_CPU / 2;
|
||||
uint32_t lastOutputPin = 0xFFFFFFFF;
|
||||
|
||||
|
|
@ -37,22 +31,24 @@ volatile bool toneIsActive = false;
|
|||
volatile bool firstTimeRunning = false;
|
||||
|
||||
#if defined(__SAMD51__)
|
||||
#define TONE_TC TC2
|
||||
#define TONE_TC_IRQn TC2_IRQn
|
||||
#define TONE_TC_GCLK_ID TC2_GCLK_ID
|
||||
#define TONE_TC TC0
|
||||
#define TONE_TC_IRQn TC0_IRQn
|
||||
#define TONE_TC_GCLK_ID TC0_GCLK_ID
|
||||
#define Tone_Handler TC0_Handler
|
||||
|
||||
#define WAIT_TC16_REGS_SYNC(x) while(x->COUNT16.SYNCBUSY.bit.ENABLE);
|
||||
|
||||
#else
|
||||
#define TONE_TC TC5
|
||||
#define TONE_TC_IRQn TC5_IRQn
|
||||
#define Tone_Handler TC5_Handler
|
||||
|
||||
#define WAIT_TC16_REGS_SYNC(x) while(x->COUNT16.STATUS.bit.SYNCBUSY);
|
||||
#endif
|
||||
|
||||
#define TONE_TC_TOP 0xFFFF
|
||||
#define TONE_TC_CHANNEL 0
|
||||
|
||||
#if defined(__SAMD51__)
|
||||
void TC2_Handler (void) __attribute__ ((weak, alias("Tone_Handler")));
|
||||
#else
|
||||
void TC5_Handler (void) __attribute__ ((weak, alias("Tone_Handler")));
|
||||
#endif
|
||||
|
||||
static inline void resetTC (Tc* TCx)
|
||||
{
|
||||
// Disable TCx
|
||||
|
|
@ -72,6 +68,14 @@ void toneAccurateClock (uint32_t accurateSystemCoreClockFrequency)
|
|||
|
||||
void tone (uint32_t outputPin, uint32_t frequency, uint32_t duration)
|
||||
{
|
||||
|
||||
// Avoid divide by zero error by calling 'noTone' instead
|
||||
if (frequency == 0)
|
||||
{
|
||||
noTone(outputPin);
|
||||
return;
|
||||
}
|
||||
|
||||
// Configure interrupt request
|
||||
NVIC_DisableIRQ(TONE_TC_IRQn);
|
||||
NVIC_ClearPendingIRQ(TONE_TC_IRQn);
|
||||
|
|
@ -80,7 +84,7 @@ void tone (uint32_t outputPin, uint32_t frequency, uint32_t duration)
|
|||
{
|
||||
firstTimeRunning = true;
|
||||
|
||||
NVIC_SetPriority(TONE_TC_IRQn, 0);
|
||||
NVIC_SetPriority(TONE_TC_IRQn, 5);
|
||||
|
||||
#if defined(__SAMD51__)
|
||||
GCLK->PCHCTRL[TONE_TC_GCLK_ID].reg = GCLK_PCHCTRL_GEN_GCLK0_Val | (1 << GCLK_PCHCTRL_CHEN_Pos);
|
||||
|
|
@ -91,9 +95,6 @@ void tone (uint32_t outputPin, uint32_t frequency, uint32_t duration)
|
|||
#endif
|
||||
}
|
||||
|
||||
//if it's a rest, set to 1Hz (below audio range)
|
||||
frequency = (frequency > 0 ? frequency : 1);
|
||||
|
||||
if (toneIsActive && (outputPin != lastOutputPin))
|
||||
noTone(lastOutputPin);
|
||||
|
||||
|
|
@ -136,7 +137,7 @@ void tone (uint32_t outputPin, uint32_t frequency, uint32_t duration)
|
|||
default: break;
|
||||
}
|
||||
|
||||
toggleCount = (duration > 0 ? frequency * duration * 2 / 1000UL : -1);
|
||||
toggleCount = (duration > 0 ? frequency * duration * 2 / 1000UL : -1LL);
|
||||
|
||||
resetTC(TONE_TC);
|
||||
|
||||
|
|
@ -178,11 +179,21 @@ void tone (uint32_t outputPin, uint32_t frequency, uint32_t duration)
|
|||
}
|
||||
|
||||
void noTone (uint32_t outputPin)
|
||||
{
|
||||
/* 'tone' need to run at least once in order to enable GCLK for
|
||||
* the timers used for the tone-functionality. If 'noTone' is called
|
||||
* without ever calling 'tone' before then 'WAIT_TC16_REGS_SYNC(TCx)'
|
||||
* will wait infinitely. The variable 'firstTimeRunning' is set the
|
||||
* 1st time 'tone' is set so it can be used to detect wether or not
|
||||
* 'tone' has been called before.
|
||||
*/
|
||||
if(firstTimeRunning)
|
||||
{
|
||||
resetTC(TONE_TC);
|
||||
digitalWrite(outputPin, LOW);
|
||||
toneIsActive = false;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
|
|
|
|||
|
|
@ -16,6 +16,8 @@
|
|||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#ifndef USE_TINYUSB
|
||||
|
||||
#include <Arduino.h>
|
||||
#include <Reset.h> // Needed for auto-reset with 1200bps port touch
|
||||
|
||||
|
|
@ -150,6 +152,7 @@ void Serial_::begin(uint32_t /* baud_count */, uint8_t /* config */)
|
|||
|
||||
void Serial_::end(void)
|
||||
{
|
||||
memset((void*)&_usbLineInfo, 0, sizeof(_usbLineInfo));
|
||||
}
|
||||
|
||||
int Serial_::available(void)
|
||||
|
|
@ -259,3 +262,5 @@ Serial_::operator bool()
|
|||
Serial_ Serial(USBDevice);
|
||||
|
||||
#endif
|
||||
|
||||
#endif // USE_TINYUSB
|
||||
|
|
|
|||
|
|
@ -17,6 +17,8 @@
|
|||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#ifndef USE_TINYUSB
|
||||
|
||||
#include "USBAPI.h"
|
||||
#include "USBDesc.h"
|
||||
#include "USBCore.h"
|
||||
|
|
@ -114,3 +116,5 @@ PluggableUSB_::PluggableUSB_() : lastIf(CDC_ACM_INTERFACE + CDC_INTERFACE_COUNT)
|
|||
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#endif // USE_TINYUSB
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@
|
|||
* Author: deanm
|
||||
*/
|
||||
|
||||
#ifndef USE_TINYUSB
|
||||
|
||||
#include "SAMD21_USBDevice.h"
|
||||
|
||||
|
|
@ -36,3 +37,5 @@ void USBDevice_SAMD21G18x::calibrate() {
|
|||
usb.PADCAL.bit.TRANSP = pad_transp;
|
||||
usb.PADCAL.bit.TRIM = pad_trim;
|
||||
}
|
||||
|
||||
#endif // USE_TINYUSB
|
||||
|
|
|
|||
|
|
@ -237,7 +237,7 @@ public:
|
|||
release();
|
||||
}
|
||||
|
||||
~DoubleBufferedEPOutHandler() {
|
||||
virtual ~DoubleBufferedEPOutHandler() {
|
||||
free((void*)data0);
|
||||
free((void*)data1);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -65,6 +65,7 @@ public:
|
|||
|
||||
// USB Device API
|
||||
void init();
|
||||
bool end();
|
||||
bool attach();
|
||||
bool detach();
|
||||
void setAddress(uint32_t addr);
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@
|
|||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#ifndef USE_TINYUSB
|
||||
#if defined(USBCON)
|
||||
|
||||
#include <Arduino.h>
|
||||
|
|
@ -244,26 +244,25 @@ bool USBDeviceClass::sendDescriptor(USBSetup &setup)
|
|||
}
|
||||
else if (setup.wValueL == ISERIAL) {
|
||||
#ifdef PLUGGABLE_USB_ENABLED
|
||||
#if defined(__SAMD51__)
|
||||
char name[ISERIAL_MAX_LEN];
|
||||
PluggableUSB().getShortName(name);
|
||||
return sendStringDescriptor((uint8_t*)name, setup.wLength);
|
||||
#else
|
||||
#ifdef __SAMD51__
|
||||
#define SERIAL_NUMBER_WORD_0 *(volatile uint32_t*)(0x008061FC)
|
||||
#define SERIAL_NUMBER_WORD_1 *(volatile uint32_t*)(0x00806010)
|
||||
#define SERIAL_NUMBER_WORD_2 *(volatile uint32_t*)(0x00806014)
|
||||
#define SERIAL_NUMBER_WORD_3 *(volatile uint32_t*)(0x00806018)
|
||||
#else // samd21
|
||||
// from section 9.3.3 of the datasheet
|
||||
#define SERIAL_NUMBER_WORD_0 *(volatile uint32_t*)(0x0080A00C)
|
||||
#define SERIAL_NUMBER_WORD_1 *(volatile uint32_t*)(0x0080A040)
|
||||
#define SERIAL_NUMBER_WORD_2 *(volatile uint32_t*)(0x0080A044)
|
||||
#define SERIAL_NUMBER_WORD_3 *(volatile uint32_t*)(0x0080A048)
|
||||
|
||||
#endif
|
||||
char name[ISERIAL_MAX_LEN];
|
||||
utox8(SERIAL_NUMBER_WORD_0, &name[0]);
|
||||
utox8(SERIAL_NUMBER_WORD_1, &name[8]);
|
||||
utox8(SERIAL_NUMBER_WORD_2, &name[16]);
|
||||
utox8(SERIAL_NUMBER_WORD_3, &name[24]);
|
||||
|
||||
PluggableUSB().getShortName(&name[32]);
|
||||
name[32] = '\0';
|
||||
return sendStringDescriptor((uint8_t*)name, setup.wLength);
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
else {
|
||||
|
|
@ -434,6 +433,13 @@ bool USBDeviceClass::detach()
|
|||
return true;
|
||||
}
|
||||
|
||||
bool USBDeviceClass::end() {
|
||||
if (!initialized)
|
||||
return false;
|
||||
usbd.disable();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool USBDeviceClass::configured()
|
||||
{
|
||||
return _usbConfiguration != 0;
|
||||
|
|
@ -871,6 +877,7 @@ bool USBDeviceClass::handleStandardSetup(USBSetup &setup)
|
|||
sendZlp(0);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
||||
case SET_ADDRESS:
|
||||
setAddress(setup.wValueL);
|
||||
|
|
@ -1032,3 +1039,4 @@ void USBDeviceClass::ISRHandler()
|
|||
USBDeviceClass USBDevice;
|
||||
|
||||
#endif
|
||||
#endif // USE_TINYUSB
|
||||
|
|
|
|||
|
|
@ -101,7 +101,7 @@
|
|||
// bMaxPower in Configuration Descriptor
|
||||
#define USB_CONFIG_POWER_MA(mA) ((mA)/2)
|
||||
#ifndef USB_CONFIG_POWER
|
||||
#define USB_CONFIG_POWER (500)
|
||||
#define USB_CONFIG_POWER (100)
|
||||
#endif
|
||||
|
||||
#define CDC_V1_10 0x0110
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@
|
|||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#ifndef USE_TINYUSB
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
|
|
@ -63,7 +64,6 @@ void UHD_Init(void)
|
|||
uint32_t pad_transn;
|
||||
uint32_t pad_transp;
|
||||
uint32_t pad_trim;
|
||||
uint32_t i;
|
||||
|
||||
USB_SetHandler(&UHD_Handler);
|
||||
|
||||
|
|
@ -172,10 +172,7 @@ void UHD_Init(void)
|
|||
USB->HOST.DESCADD.reg = (uint32_t)(&usb_pipe_table[0]);
|
||||
// For USB_SPEED_FULL
|
||||
uhd_force_full_speed();
|
||||
for (i = 0; i < sizeof(usb_pipe_table); i++)
|
||||
{
|
||||
(*(uint32_t *)(&usb_pipe_table[0] + i)) = 0;
|
||||
}
|
||||
memset((void *)usb_pipe_table, 0, sizeof(usb_pipe_table));
|
||||
|
||||
uhd_state = UHD_STATE_NO_VBUS;
|
||||
|
||||
|
|
@ -557,3 +554,5 @@ uint32_t UHD_Pipe_Is_Transfer_Complete(uint32_t ul_pipe, uint32_t ul_token_type)
|
|||
// }
|
||||
|
||||
#endif // HOST_DEFINED
|
||||
|
||||
#endif // USE_TINYUSB
|
||||
|
|
|
|||
|
|
@ -93,31 +93,19 @@ void attachInterrupt(uint32_t pin, voidFuncPtr callback, uint32_t mode)
|
|||
__initialize();
|
||||
enabled = 1;
|
||||
}
|
||||
uint32_t inMask = (1UL << in);
|
||||
// Enable wakeup capability on pin in case being used during sleep
|
||||
#if defined(__SAMD51__)
|
||||
//I believe this is done automatically
|
||||
#else
|
||||
EIC->WAKEUP.reg |= (1 << in);
|
||||
#endif
|
||||
|
||||
// Only store when there is really an ISR to call.
|
||||
// This allow for calling attachInterrupt(pin, NULL, mode), we set up all needed register
|
||||
// but won't service the interrupt, this way we also don't need to check it inside the ISR.
|
||||
if (callback)
|
||||
{
|
||||
// Store interrupts to service in order of when they were attached
|
||||
// to allow for first come first serve handler
|
||||
uint32_t current = 0;
|
||||
uint32_t inMask = (1UL << in);
|
||||
|
||||
// Check if we already have this interrupt
|
||||
for (current=0; current<nints; current++) {
|
||||
if (ISRlist[current] == inMask) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (current == nints) {
|
||||
// Need to make a new entry
|
||||
nints++;
|
||||
}
|
||||
ISRlist[current] = inMask; // List of interrupt in order of when they were attached
|
||||
ISRcallback[current] = callback; // List of callback adresses
|
||||
}
|
||||
|
||||
if (in == EXTERNAL_INT_NMI) {
|
||||
EIC->NMIFLAG.bit.NMI = 1; // Clear flag
|
||||
switch (mode) {
|
||||
|
|
@ -147,34 +135,41 @@ void attachInterrupt(uint32_t pin, voidFuncPtr callback, uint32_t mode)
|
|||
|
||||
} else { // Not NMI, is external interrupt
|
||||
|
||||
// Enable wakeup capability on pin in case being used during sleep
|
||||
#if defined(__SAMD51__)
|
||||
//I believe this is done automatically
|
||||
#else
|
||||
EIC->WAKEUP.reg |= (1 << in);
|
||||
#endif
|
||||
|
||||
// Assign pin to EIC
|
||||
pinPeripheral(pin, PIO_EXTINT);
|
||||
|
||||
// Assign callback to interrupt
|
||||
ISRcallback[in] = callback;
|
||||
// Store interrupts to service in order of when they were attached
|
||||
// to allow for first come first serve handler
|
||||
uint32_t current = 0;
|
||||
|
||||
// Check if we already have this interrupt
|
||||
for (current=0; current<nints; current++) {
|
||||
if (ISRlist[current] == inMask) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (current == nints) {
|
||||
// Need to make a new entry
|
||||
nints++;
|
||||
}
|
||||
ISRlist[current] = inMask; // List of interrupt in order of when they were attached
|
||||
ISRcallback[current] = callback; // List of callback adresses
|
||||
|
||||
// Look for right CONFIG register to be addressed
|
||||
if (in > EXTERNAL_INT_7) {
|
||||
config = 1;
|
||||
pos = (in - 8) << 2;
|
||||
} else {
|
||||
config = 0;
|
||||
pos = in << 2;
|
||||
}
|
||||
|
||||
// Configure the interrupt mode
|
||||
pos = (in - (8 * config)) << 2;
|
||||
|
||||
#if defined (__SAMD51__)
|
||||
EIC->CTRLA.bit.ENABLE = 0;
|
||||
while (EIC->SYNCBUSY.bit.ENABLE == 1) { }
|
||||
#endif
|
||||
|
||||
EIC->CONFIG[config].reg &=~ (EIC_CONFIG_SENSE0_Msk << pos); // Reset sense mode, important when changing trigger mode during runtime
|
||||
switch (mode)
|
||||
{
|
||||
case LOW:
|
||||
|
|
@ -200,6 +195,7 @@ void attachInterrupt(uint32_t pin, voidFuncPtr callback, uint32_t mode)
|
|||
}
|
||||
// Enable the interrupt
|
||||
EIC->INTENSET.reg = EIC_INTENSET_EXTINT(1 << in);
|
||||
}
|
||||
|
||||
#if defined (__SAMD51__)
|
||||
EIC->CTRLA.bit.ENABLE = 1;
|
||||
|
|
@ -254,17 +250,22 @@ void detachInterrupt(uint32_t pin)
|
|||
* External Interrupt Controller NVIC Interrupt Handler
|
||||
*/
|
||||
#if defined(__SAMD51__)
|
||||
void InterruptHandler(uint32_t i)
|
||||
void InterruptHandler(uint32_t unused_i)
|
||||
{
|
||||
if ((EIC->INTFLAG.reg & (1 << i)) != 0)
|
||||
{
|
||||
// Call the callback function if assigned
|
||||
if (ISRcallback[i]) {
|
||||
ISRcallback[i]();
|
||||
}
|
||||
(void)unused_i;
|
||||
// Calling the routine directly from -here- takes about 1us
|
||||
// Depending on where you are in the list it will take longer
|
||||
|
||||
// Loop over all enabled interrupts in the list
|
||||
for (uint32_t i=0; i<nints; i++)
|
||||
{
|
||||
if ((EIC->INTFLAG.reg & ISRlist[i]) != 0)
|
||||
{
|
||||
// Call the callback function
|
||||
ISRcallback[i]();
|
||||
// Clear the interrupt
|
||||
EIC->INTFLAG.reg = 1 << i;
|
||||
EIC->INTFLAG.reg = ISRlist[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -31,7 +31,7 @@ extern "C" {
|
|||
#define FALLING 3
|
||||
#define RISING 4
|
||||
|
||||
#define DEFAULT 1
|
||||
//#define DEFAULT 1
|
||||
#define EXTERNAL 0
|
||||
|
||||
typedef void (*voidFuncPtr)(void);
|
||||
|
|
|
|||
|
|
@ -57,10 +57,41 @@ typedef enum _EAnalogChannel
|
|||
ADC_Channel19=19,
|
||||
DAC_Channel0,
|
||||
DAC_Channel1,
|
||||
ADC_Channel_Bandgap=0x1B,
|
||||
ADC_Channel_PTAT=0x1C,
|
||||
} EAnalogChannel ;
|
||||
|
||||
#if defined(__SAMD51__)
|
||||
|
||||
#if defined(__SAMD51G19A__)
|
||||
|
||||
typedef enum _ETCChannel
|
||||
{
|
||||
NOT_ON_TIMER=-1,
|
||||
TCC0_CH0 = (0<<8)|(0),
|
||||
TCC0_CH1 = (0<<8)|(1),
|
||||
TCC0_CH2 = (0<<8)|(2),
|
||||
TCC0_CH3 = (0<<8)|(3),
|
||||
TCC0_CH4 = (0<<8)|(4),
|
||||
TCC0_CH5 = (0<<8)|(5),
|
||||
TCC1_CH0 = (1<<8)|(0),
|
||||
TCC1_CH1 = (1<<8)|(1),
|
||||
TCC1_CH2 = (1<<8)|(2),
|
||||
TCC1_CH3 = (1<<8)|(3),
|
||||
TCC2_CH0 = (2<<8)|(0),
|
||||
TCC2_CH1 = (2<<8)|(1),
|
||||
TCC2_CH2 = (2<<8)|(2),
|
||||
TC0_CH0 = (3<<8)|(0),
|
||||
TC0_CH1 = (3<<8)|(1),
|
||||
TC1_CH0 = (4<<8)|(0),
|
||||
TC1_CH1 = (4<<8)|(1),
|
||||
TC2_CH0 = (5<<8)|(0),
|
||||
TC2_CH1 = (5<<8)|(1),
|
||||
TC3_CH0 = (6<<8)|(0),
|
||||
TC3_CH1 = (6<<8)|(1),
|
||||
} ETCChannel ;
|
||||
#elif defined(__SAMD51J19A__) || defined(__SAMD51J20A__)
|
||||
|
||||
typedef enum _ETCChannel
|
||||
{
|
||||
NOT_ON_TIMER=-1,
|
||||
|
|
@ -76,12 +107,82 @@ typedef enum _ETCChannel
|
|||
TCC1_CH1 = (1<<8)|(1),
|
||||
TCC1_CH2 = (1<<8)|(2),
|
||||
TCC1_CH3 = (1<<8)|(3),
|
||||
TCC1_CH4 = (1<<8)|(0),
|
||||
TCC1_CH5 = (1<<8)|(1),
|
||||
TCC1_CH6 = (1<<8)|(2),
|
||||
TCC1_CH7 = (1<<8)|(3),
|
||||
TCC1_CH4 = (1<<8)|(4),
|
||||
TCC1_CH5 = (1<<8)|(5),
|
||||
TCC1_CH6 = (1<<8)|(6),
|
||||
TCC1_CH7 = (1<<8)|(7),
|
||||
TCC2_CH0 = (2<<8)|(0),
|
||||
TCC2_CH1 = (2<<8)|(1),
|
||||
TCC2_CH2 = (2<<8)|(2),
|
||||
TCC3_CH0 = (3<<8)|(0),
|
||||
TCC3_CH1 = (3<<8)|(1),
|
||||
TCC4_CH0 = (4<<8)|(0),
|
||||
TCC4_CH1 = (4<<8)|(1),
|
||||
TC0_CH0 = (5<<8)|(0),
|
||||
TC0_CH1 = (5<<8)|(1),
|
||||
TC1_CH0 = (6<<8)|(0),
|
||||
TC1_CH1 = (6<<8)|(1),
|
||||
TC2_CH0 = (7<<8)|(0),
|
||||
TC2_CH1 = (7<<8)|(1),
|
||||
TC3_CH0 = (8<<8)|(0),
|
||||
TC3_CH1 = (8<<8)|(1),
|
||||
TC4_CH0 = (9<<8)|(0),
|
||||
TC4_CH1 = (9<<8)|(1),
|
||||
TC5_CH0 = (10<<8)|(0),
|
||||
TC5_CH1 = (10<<8)|(1),
|
||||
TC6_CH0 = (11<<8)|(0),
|
||||
TC6_CH1 = (11<<8)|(1),
|
||||
TC7_CH0 = (12<<8)|(0),
|
||||
TC7_CH1 = (12<<8)|(1),
|
||||
} ETCChannel ;
|
||||
|
||||
#elif defined(__SAMD51P19A__) || defined(__SAMD51P20A__)
|
||||
|
||||
typedef enum _ETCChannel
|
||||
{
|
||||
NOT_ON_TIMER=-1,
|
||||
TCC0_CH0 = (0<<8)|(0),
|
||||
TCC0_CH1 = (0<<8)|(1),
|
||||
TCC0_CH2 = (0<<8)|(2),
|
||||
TCC0_CH3 = (0<<8)|(3),
|
||||
TCC0_CH4 = (0<<8)|(4),
|
||||
TCC0_CH5 = (0<<8)|(5),
|
||||
TCC1_CH0 = (1<<8)|(0),
|
||||
TCC1_CH1 = (1<<8)|(1),
|
||||
TCC1_CH2 = (1<<8)|(2),
|
||||
TCC1_CH3 = (1<<8)|(3),
|
||||
TCC2_CH0 = (2<<8)|(0),
|
||||
TCC2_CH1 = (2<<8)|(1),
|
||||
TCC2_CH2 = (2<<8)|(2),
|
||||
TCC3_CH0 = (3<<8)|(0),
|
||||
TCC3_CH1 = (3<<8)|(1),
|
||||
TCC4_CH0 = (4<<8)|(0),
|
||||
TCC4_CH1 = (4<<8)|(1),
|
||||
TC0_CH0 = (5<<8)|(0),
|
||||
TC0_CH1 = (5<<8)|(1),
|
||||
TC1_CH0 = (6<<8)|(0),
|
||||
TC1_CH1 = (6<<8)|(1),
|
||||
TC2_CH0 = (7<<8)|(0),
|
||||
TC2_CH1 = (7<<8)|(1),
|
||||
TC3_CH0 = (8<<8)|(0),
|
||||
TC3_CH1 = (8<<8)|(1),
|
||||
TC4_CH0 = (9<<8)|(0),
|
||||
TC4_CH1 = (9<<8)|(1),
|
||||
TC5_CH0 = (10<<8)|(0),
|
||||
TC5_CH1 = (10<<8)|(1),
|
||||
TC6_CH0 = (11<<8)|(0),
|
||||
TC6_CH1 = (11<<8)|(1),
|
||||
TC7_CH0 = (12<<8)|(0),
|
||||
TC7_CH1 = (12<<8)|(1),
|
||||
} ETCChannel ;
|
||||
|
||||
#endif
|
||||
|
||||
typedef ETCChannel EPWMChannel;
|
||||
extern const uint32_t GCLK_CLKCTRL_IDs[TCC_INST_NUM+TC_INST_NUM];
|
||||
|
||||
#define NOT_ON_PWM NOT_ON_TIMER
|
||||
|
||||
#else
|
||||
// Definitions for TC channels
|
||||
typedef enum _ETCChannel
|
||||
|
|
@ -109,40 +210,14 @@ typedef enum _ETCChannel
|
|||
TC4_CH1 = (4<<8)|(1),
|
||||
TC5_CH0 = (5<<8)|(0),
|
||||
TC5_CH1 = (5<<8)|(1),
|
||||
#if defined (__SAMD21J18A__)
|
||||
TC6_CH0 = (6<<8)|(0),
|
||||
TC6_CH1 = (6<<8)|(1),
|
||||
TC7_CH0 = (7<<8)|(0),
|
||||
TC7_CH1 = (7<<8)|(1),
|
||||
#endif // __SAMD21J18A__
|
||||
} ETCChannel ;
|
||||
#endif
|
||||
|
||||
extern const void* g_apTCInstances[TCC_INST_NUM+TC_INST_NUM] ;
|
||||
|
||||
#define GetTCNumber( x ) ( (x) >> 8 )
|
||||
#define GetTCChannelNumber( x ) ( (x) & 0xff )
|
||||
#define GetTC( x ) ( g_apTCInstances[(x) >> 8] )
|
||||
|
||||
|
||||
#if defined(__SAMD51__)
|
||||
|
||||
typedef enum _EPWMChannel
|
||||
{
|
||||
NOT_ON_PWM=-1,
|
||||
PWM0_CH0=TCC0_CH0,
|
||||
PWM0_CH1=TCC0_CH1,
|
||||
PWM0_CH2=TCC0_CH2,
|
||||
PWM0_CH3=TCC0_CH3,
|
||||
PWM0_CH4=TCC0_CH4,
|
||||
PWM0_CH5=TCC0_CH5,
|
||||
PWM0_CH6=TCC0_CH6,
|
||||
PWM0_CH7=TCC0_CH7,
|
||||
PWM1_CH0=TCC1_CH0,
|
||||
PWM1_CH1=TCC1_CH1,
|
||||
PWM1_CH2=TCC1_CH2,
|
||||
PWM1_CH3=TCC1_CH3,
|
||||
PWM1_CH4=TCC1_CH4,
|
||||
PWM1_CH5=TCC1_CH5,
|
||||
PWM1_CH6=TCC1_CH6,
|
||||
PWM1_CH7=TCC1_CH7,
|
||||
} EPWMChannel ;
|
||||
|
||||
#else //end __SAMD51J19A__
|
||||
// Definitions for PWM channels
|
||||
typedef enum _EPWMChannel
|
||||
{
|
||||
|
|
@ -179,6 +254,11 @@ extern const void* g_apTCInstances[TCC_INST_NUM+TC_INST_NUM] ;
|
|||
|
||||
#endif
|
||||
|
||||
extern const void* g_apTCInstances[TCC_INST_NUM+TC_INST_NUM] ;
|
||||
|
||||
#define GetTCNumber( x ) ( (x) >> 8 )
|
||||
#define GetTCChannelNumber( x ) ( (x) & 0xff )
|
||||
#define GetTC( x ) ( g_apTCInstances[(x) >> 8] )
|
||||
|
||||
typedef enum _EPortType
|
||||
{
|
||||
|
|
@ -186,6 +266,7 @@ typedef enum _EPortType
|
|||
PORTA=0,
|
||||
PORTB=1,
|
||||
PORTC=2,
|
||||
PORTD=3,
|
||||
} EPortType ;
|
||||
|
||||
#define PIN_NOT_A_PIN (UINT_MAX)
|
||||
|
|
@ -255,10 +336,19 @@ typedef enum _EPioType
|
|||
#define PIN_ATTR_COMBO (1UL<<0)
|
||||
#define PIN_ATTR_ANALOG (1UL<<1)
|
||||
#define PIN_ATTR_DIGITAL (1UL<<2)
|
||||
#define PIN_ATTR_PWM (1UL<<3)
|
||||
#define PIN_ATTR_TIMER (1UL<<4)
|
||||
#define PIN_ATTR_TIMER_ALT (1UL<<5)
|
||||
#define PIN_ATTR_EXTINT (1UL<<6)
|
||||
#define PIN_ATTR_ANALOG_ALT (1UL<<7)
|
||||
|
||||
#if defined(__SAMD51__)
|
||||
// these correspond to the mux table
|
||||
#define PIN_ATTR_PWM_E (1UL<<3)
|
||||
#define PIN_ATTR_PWM_F (1UL<<8)
|
||||
#define PIN_ATTR_PWM_G (1UL<<9)
|
||||
#else
|
||||
#define PIN_ATTR_PWM (1UL<<3)
|
||||
#endif
|
||||
|
||||
/* Types used for the table below */
|
||||
typedef struct _PinDescription
|
||||
|
|
|
|||
|
|
@ -25,8 +25,14 @@
|
|||
#ifndef _IO_H_
|
||||
#define _IO_H_
|
||||
|
||||
#ifdef __SAMD51__
|
||||
#define RAMSTART (HSRAM_ADDR)
|
||||
#define RAMSIZE (HSRAM_SIZE)
|
||||
#else
|
||||
#define RAMSTART (HMCRAMC0_ADDR)
|
||||
#define RAMSIZE (HMCRAMC0_SIZE)
|
||||
#endif
|
||||
|
||||
#define RAMEND (RAMSTART + RAMSIZE - 1)
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -61,6 +61,33 @@ unsigned long micros( void )
|
|||
// a runtime multiplication and shift, saving a few cycles
|
||||
}
|
||||
|
||||
#ifdef __SAMD51__
|
||||
/*
|
||||
* On SAMD51, use the (32bit) cycle count maintained by the DWT unit,
|
||||
* and count exact number of cycles elapsed, rather than guessing how
|
||||
* many cycles a loop takes, which is dangerous in the presence of
|
||||
* cache. The overhead of the call and internal code is "about" 20
|
||||
* cycles. (at 120MHz, that's about 1/6 us)
|
||||
*/
|
||||
void delayMicroseconds(unsigned int us)
|
||||
{
|
||||
uint32_t start, elapsed;
|
||||
uint32_t count;
|
||||
|
||||
if (us == 0)
|
||||
return;
|
||||
|
||||
count = us * (VARIANT_MCK / 1000000) - 20; // convert us to cycles.
|
||||
start = DWT->CYCCNT; //CYCCNT is 32bits, takes 37s or so to wrap.
|
||||
while (1) {
|
||||
elapsed = DWT->CYCCNT - start;
|
||||
if (elapsed >= count)
|
||||
return;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
void delay( unsigned long ms )
|
||||
{
|
||||
if (ms == 0)
|
||||
|
|
@ -68,12 +95,17 @@ void delay( unsigned long ms )
|
|||
return;
|
||||
}
|
||||
|
||||
uint32_t start = _ulTickCount ;
|
||||
uint32_t start = micros();
|
||||
|
||||
do
|
||||
while (ms > 0)
|
||||
{
|
||||
yield();
|
||||
} while ( _ulTickCount - start < ms ) ;
|
||||
while (ms > 0 && (micros() - start) >= 1000)
|
||||
{
|
||||
ms--;
|
||||
start += 1000;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#include "Reset.h" // for tickReset()
|
||||
|
|
|
|||
|
|
@ -61,6 +61,9 @@ extern void delay( unsigned long dwMs ) ;
|
|||
*
|
||||
* \param dwUs the number of microseconds to pause (uint32_t)
|
||||
*/
|
||||
#if defined(__SAMD51__)
|
||||
extern void delayMicroseconds( unsigned int );
|
||||
#else
|
||||
static __inline__ void delayMicroseconds( unsigned int ) __attribute__((always_inline, unused)) ;
|
||||
static __inline__ void delayMicroseconds( unsigned int usec )
|
||||
{
|
||||
|
|
@ -68,21 +71,6 @@ static __inline__ void delayMicroseconds( unsigned int usec )
|
|||
{
|
||||
return ;
|
||||
}
|
||||
|
||||
#if defined(__SAMD51__)
|
||||
uint32_t n = usec * (VARIANT_MCK / 1000000) / 12;
|
||||
|
||||
__asm__ __volatile__(
|
||||
"1: \n"
|
||||
" sub %0, #1 \n" // substract 1 from %0 (n)
|
||||
" cmp %0, #0 \n" // compare to 0
|
||||
" bne 1b \n" // if result is not 0 jump to 1
|
||||
: "+r" (n) // '%0' is n variable with RW constraints
|
||||
: // no input
|
||||
: // no clobber
|
||||
);
|
||||
|
||||
#else
|
||||
/*
|
||||
* The following loop:
|
||||
*
|
||||
|
|
@ -109,10 +97,10 @@ static __inline__ void delayMicroseconds( unsigned int usec )
|
|||
: // no input
|
||||
: // no clobber
|
||||
);
|
||||
#endif
|
||||
// https://gcc.gnu.org/onlinedocs/gcc/Extended-Asm.html
|
||||
// https://gcc.gnu.org/onlinedocs/gcc/Extended-Asm.html#Volatile
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
|
|
|||
|
|
@ -28,6 +28,7 @@
|
|||
static void __empty() {
|
||||
// Empty
|
||||
}
|
||||
|
||||
void yield(void) __attribute__ ((weak, alias("__empty")));
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -39,7 +39,10 @@ int main( void )
|
|||
initVariant();
|
||||
|
||||
delay(1);
|
||||
#if defined(USBCON)
|
||||
|
||||
#if defined(USE_TINYUSB)
|
||||
Adafruit_TinyUSB_Core_init();
|
||||
#elif defined(USBCON)
|
||||
USBDevice.init();
|
||||
USBDevice.attach();
|
||||
#endif
|
||||
|
|
@ -49,8 +52,21 @@ int main( void )
|
|||
for (;;)
|
||||
{
|
||||
loop();
|
||||
yield(); // yield run usb background task
|
||||
|
||||
if (serialEventRun) serialEventRun();
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if defined(USE_TINYUSB)
|
||||
|
||||
// run TinyUSB background task when yield()
|
||||
extern "C" void yield(void)
|
||||
{
|
||||
tud_task();
|
||||
tud_cdc_write_flush();
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -164,13 +164,14 @@ void arm_float_to_q12_20(float *pIn, q31_t * pOut, uint32_t numSamples)
|
|||
uint32_t arm_compare_fixed_q15(q15_t *pIn, q15_t * pOut, uint32_t numSamples)
|
||||
{
|
||||
uint32_t i;
|
||||
int32_t diff, diffCrnt = 0;
|
||||
int32_t diff;
|
||||
uint32_t diffCrnt = 0;
|
||||
uint32_t maxDiff = 0;
|
||||
|
||||
for (i = 0; i < numSamples; i++)
|
||||
{
|
||||
diff = pIn[i] - pOut[i];
|
||||
diffCrnt = (diff > 0) ? diff : -diff;
|
||||
diffCrnt = (uint32_t)( (diff > 0) ? diff : -diff );
|
||||
|
||||
if(diffCrnt > maxDiff)
|
||||
{
|
||||
|
|
@ -192,13 +193,14 @@ uint32_t arm_compare_fixed_q15(q15_t *pIn, q15_t * pOut, uint32_t numSamples)
|
|||
uint32_t arm_compare_fixed_q31(q31_t *pIn, q31_t * pOut, uint32_t numSamples)
|
||||
{
|
||||
uint32_t i;
|
||||
int32_t diff, diffCrnt = 0;
|
||||
int32_t diff;
|
||||
uint32_t diffCrnt = 0;
|
||||
uint32_t maxDiff = 0;
|
||||
|
||||
for (i = 0; i < numSamples; i++)
|
||||
{
|
||||
diff = pIn[i] - pOut[i];
|
||||
diffCrnt = (diff > 0) ? diff : -diff;
|
||||
diffCrnt = (uint32_t)( (diff > 0) ? diff : -diff );
|
||||
|
||||
if(diffCrnt > maxDiff)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -34,6 +34,36 @@ uint32_t pulseIn(uint32_t pin, uint32_t state, uint32_t timeout)
|
|||
uint32_t bit = 1 << p.ulPin;
|
||||
uint32_t stateMask = state ? bit : 0;
|
||||
|
||||
#if defined(__SAMD51__)
|
||||
/*
|
||||
* The SAMD51 is fast enough to use really obvious code (similar to
|
||||
* what was used to produce pulse_asm.S, but using micros() for timing.
|
||||
* No assembly required, no conversion of loop counts to times (which is
|
||||
* worrisome in the presence of cache.)
|
||||
*/
|
||||
const volatile uint32_t *port = &(PORT->Group[p.ulPort].IN.reg);
|
||||
uint32_t usCallStart; // microseconds at start of call, for timeout.
|
||||
uint32_t usPulseStart; // microseconds at start of measured pulse.
|
||||
usCallStart = usPulseStart = micros();
|
||||
// wait for any previous pulse to end
|
||||
while ((*port & bit) == stateMask) {
|
||||
if (micros() - usCallStart > timeout)
|
||||
return -1;
|
||||
}
|
||||
// wait for the pulse to start
|
||||
while ((*port & bit) != stateMask) {
|
||||
usPulseStart = micros();
|
||||
if (usPulseStart - usCallStart > timeout)
|
||||
return -2;
|
||||
}
|
||||
|
||||
// wait for the pulse to stop
|
||||
while ((*port & bit) == stateMask) {
|
||||
if (micros() - usCallStart > timeout)
|
||||
return -3;
|
||||
}
|
||||
return micros() - usPulseStart;
|
||||
#else
|
||||
// convert the timeout from microseconds to a number of times through
|
||||
// the initial loop; it takes (roughly) 13 clock cycles per iteration.
|
||||
uint32_t maxloops = microsecondsToClockCycles(timeout) / 13;
|
||||
|
|
@ -48,5 +78,6 @@ uint32_t pulseIn(uint32_t pin, uint32_t state, uint32_t timeout)
|
|||
return clockCyclesToMicroseconds(width * 13 + 16);
|
||||
else
|
||||
return 0;
|
||||
#endif // SAMD51
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -97,7 +97,7 @@ void SystemInit( void )
|
|||
}
|
||||
|
||||
/* ----------------------------------------------------------------------------------------------
|
||||
* 3) Put Generic Clock Generator 3 as source for Generic Clock Gen 0 (DFLL48M reference)
|
||||
* 3) Put OSCULP32K as source for Generic Clock Generator 0
|
||||
*/
|
||||
GCLK->GENCTRL[0].reg = GCLK_GENCTRL_SRC(GCLK_GENCTRL_SRC_OSCULP32K) | GCLK_GENCTRL_GENEN;
|
||||
|
||||
|
|
@ -146,7 +146,7 @@ void SystemInit( void )
|
|||
/* Wait for synchronization */
|
||||
}
|
||||
|
||||
GCLK->GENCTRL[GENERIC_CLOCK_GENERATOR_1M].reg = GCLK_GENCTRL_SRC(GCLK_GENCTRL_SRC_DFLL_Val) | GCLK_GENCTRL_GENEN | GCLK_GENCTRL_DIV(24u);
|
||||
GCLK->GENCTRL[GENERIC_CLOCK_GENERATOR_1M].reg = GCLK_GENCTRL_SRC(GCLK_GENCTRL_SRC_DFLL_Val) | GCLK_GENCTRL_GENEN | GCLK_GENCTRL_DIV(48u);
|
||||
|
||||
while ( GCLK->SYNCBUSY.bit.GENCTRL5 ){
|
||||
/* Wait for synchronization */
|
||||
|
|
@ -160,7 +160,8 @@ void SystemInit( void )
|
|||
//PLL0 is 120MHz
|
||||
GCLK->PCHCTRL[OSCCTRL_GCLK_ID_FDPLL0].reg = (1 << GCLK_PCHCTRL_CHEN_Pos) | GCLK_PCHCTRL_GEN(GCLK_PCHCTRL_GEN_GCLK5_Val);
|
||||
|
||||
OSCCTRL->Dpll[0].DPLLRATIO.reg = OSCCTRL_DPLLRATIO_LDRFRAC(0x00) | OSCCTRL_DPLLRATIO_LDR(59); //120 Mhz
|
||||
// This rounds to nearest full-MHz increment; not currently using frac
|
||||
OSCCTRL->Dpll[0].DPLLRATIO.reg = OSCCTRL_DPLLRATIO_LDRFRAC(0x00) | OSCCTRL_DPLLRATIO_LDR((F_CPU - 500000) / 1000000);
|
||||
|
||||
while(OSCCTRL->Dpll[0].DPLLSYNCBUSY.bit.DPLLRATIO);
|
||||
|
||||
|
|
@ -174,7 +175,7 @@ void SystemInit( void )
|
|||
//PLL1 is 100MHz
|
||||
GCLK->PCHCTRL[OSCCTRL_GCLK_ID_FDPLL1].reg = (1 << GCLK_PCHCTRL_CHEN_Pos) | GCLK_PCHCTRL_GEN(GCLK_PCHCTRL_GEN_GCLK5_Val);
|
||||
|
||||
OSCCTRL->Dpll[1].DPLLRATIO.reg = OSCCTRL_DPLLRATIO_LDRFRAC(0x00) | OSCCTRL_DPLLRATIO_LDR(49); //100 Mhz
|
||||
OSCCTRL->Dpll[1].DPLLRATIO.reg = OSCCTRL_DPLLRATIO_LDRFRAC(0x00) | OSCCTRL_DPLLRATIO_LDR(99); //100 Mhz
|
||||
|
||||
while(OSCCTRL->Dpll[1].DPLLSYNCBUSY.bit.DPLLRATIO);
|
||||
|
||||
|
|
@ -216,7 +217,7 @@ void SystemInit( void )
|
|||
GCLK->GENCTRL[GENERIC_CLOCK_GENERATOR_12M].reg = GCLK_GENCTRL_SRC(GCLK_GENCTRL_SRC_DFLL_Val) |
|
||||
GCLK_GENCTRL_IDC |
|
||||
GCLK_GENCTRL_DIV(4) |
|
||||
GCLK_GENCTRL_DIVSEL |
|
||||
//GCLK_GENCTRL_DIVSEL |
|
||||
//GCLK_GENCTRL_OE |
|
||||
GCLK_GENCTRL_GENEN;
|
||||
|
||||
|
|
@ -253,6 +254,54 @@ void SystemInit( void )
|
|||
__enable_irq();
|
||||
#endif
|
||||
|
||||
/*---------------------------------------------------------------------
|
||||
* Start up the "Debug Watchpoint and Trace" unit, so that we can use
|
||||
* it's 32bit cycle counter for timing.
|
||||
*/
|
||||
CoreDebug->DEMCR |= CoreDebug_DEMCR_TRCENA_Msk;
|
||||
DWT->CTRL |= DWT_CTRL_CYCCNTENA_Msk;
|
||||
|
||||
/* ----------------------------------------------------------------------------------------------
|
||||
* 5) Load AC factory calibration values
|
||||
*/
|
||||
|
||||
uint32_t bias0 = (*((uint32_t *)AC_FUSES_BIAS0_ADDR) & AC_FUSES_BIAS0_Msk) >> AC_FUSES_BIAS0_Pos;
|
||||
AC->CALIB.reg = AC_CALIB_BIAS0(bias0);
|
||||
|
||||
/* ----------------------------------------------------------------------------------------------
|
||||
* 6) Load ADC factory calibration values
|
||||
*/
|
||||
|
||||
// ADC0 Bias Calibration
|
||||
uint32_t biascomp = (*((uint32_t *)ADC0_FUSES_BIASCOMP_ADDR) & ADC0_FUSES_BIASCOMP_Msk) >> ADC0_FUSES_BIASCOMP_Pos;
|
||||
uint32_t biasr2r = (*((uint32_t *)ADC0_FUSES_BIASR2R_ADDR) & ADC0_FUSES_BIASR2R_Msk) >> ADC0_FUSES_BIASR2R_Pos;
|
||||
uint32_t biasref = (*((uint32_t *)ADC0_FUSES_BIASREFBUF_ADDR) & ADC0_FUSES_BIASREFBUF_Msk) >> ADC0_FUSES_BIASREFBUF_Pos;
|
||||
|
||||
ADC0->CALIB.reg = ADC_CALIB_BIASREFBUF(biasref)
|
||||
| ADC_CALIB_BIASR2R(biasr2r)
|
||||
| ADC_CALIB_BIASCOMP(biascomp);
|
||||
|
||||
// ADC1 Bias Calibration
|
||||
biascomp = (*((uint32_t *)ADC1_FUSES_BIASCOMP_ADDR) & ADC1_FUSES_BIASCOMP_Msk) >> ADC1_FUSES_BIASCOMP_Pos;
|
||||
biasr2r = (*((uint32_t *)ADC1_FUSES_BIASR2R_ADDR) & ADC1_FUSES_BIASR2R_Msk) >> ADC1_FUSES_BIASR2R_Pos;
|
||||
biasref = (*((uint32_t *)ADC1_FUSES_BIASREFBUF_ADDR) & ADC1_FUSES_BIASREFBUF_Msk) >> ADC1_FUSES_BIASREFBUF_Pos;
|
||||
|
||||
ADC1->CALIB.reg = ADC_CALIB_BIASREFBUF(biasref)
|
||||
| ADC_CALIB_BIASR2R(biasr2r)
|
||||
| ADC_CALIB_BIASCOMP(biascomp);
|
||||
|
||||
/* ----------------------------------------------------------------------------------------------
|
||||
* 7) Load USB factory calibration values
|
||||
*/
|
||||
|
||||
//USB Calibration
|
||||
uint32_t usbtransn = (*((uint32_t *)USB_FUSES_TRANSN_ADDR) & USB_FUSES_TRANSN_Msk) >> USB_FUSES_TRANSN_Pos;
|
||||
uint32_t usbtransp = (*((uint32_t *)USB_FUSES_TRANSP_ADDR) & USB_FUSES_TRANSP_Msk) >> USB_FUSES_TRANSP_Pos;
|
||||
uint32_t usbtrim = (*((uint32_t *)USB_FUSES_TRIM_ADDR) & USB_FUSES_TRIM_Msk) >> USB_FUSES_TRIM_Pos;
|
||||
USB->DEVICE.PADCAL.reg = USB_PADCAL_TRIM(usbtrim)
|
||||
| USB_PADCAL_TRANSN(usbtransn)
|
||||
| USB_PADCAL_TRANSP(usbtransp);
|
||||
|
||||
//*************** END SAMD51 *************************//
|
||||
|
||||
#else
|
||||
|
|
@ -528,4 +577,3 @@ void SystemInit( void )
|
|||
NVMCTRL->CTRLB.bit.MANW = 1;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -25,8 +25,7 @@ extern "C" {
|
|||
|
||||
|
||||
#if defined(__SAMD51__)
|
||||
//CHANGE THIS IF YOU CHANGE THE CLOCK SPEED
|
||||
uint32_t SystemCoreClock=120000000ul ;
|
||||
uint32_t SystemCoreClock=F_CPU;
|
||||
#else
|
||||
/*
|
||||
* System Core Clock is at 1MHz (8MHz/8) at Reset.
|
||||
|
|
@ -79,19 +78,21 @@ void init( void )
|
|||
// PM->APBAMASK.reg |= PM_APBAMASK_EIC ;
|
||||
|
||||
#if defined(__SAMD51__)
|
||||
MCLK->APBAMASK.reg |= MCLK_APBAMASK_SERCOM0 | MCLK_APBAMASK_SERCOM1;
|
||||
MCLK->APBAMASK.reg |= MCLK_APBAMASK_SERCOM0 | MCLK_APBAMASK_SERCOM1 | MCLK_APBAMASK_TC0 | MCLK_APBAMASK_TC1;
|
||||
|
||||
MCLK->APBBMASK.reg |= MCLK_APBBMASK_SERCOM2 | MCLK_APBBMASK_SERCOM3 | MCLK_APBBMASK_TCC0 | MCLK_APBBMASK_TCC1 | MCLK_APBBMASK_TC3 | MCLK_APBBMASK_TC2;
|
||||
|
||||
MCLK->APBCMASK.reg |= MCLK_APBCMASK_TCC2 | MCLK_APBCMASK_TC4 | MCLK_APBCMASK_TC5;
|
||||
MCLK->APBCMASK.reg |= MCLK_APBCMASK_TCC2 | MCLK_APBCMASK_TCC3 | MCLK_APBCMASK_TC4 | MCLK_APBCMASK_TC5;
|
||||
|
||||
MCLK->APBDMASK.reg |= MCLK_APBDMASK_DAC | MCLK_APBDMASK_SERCOM4 | MCLK_APBDMASK_SERCOM5 | MCLK_APBDMASK_ADC0 | MCLK_APBDMASK_ADC1 | MCLK_APBDMASK_TCC4
|
||||
| MCLK_APBDMASK_TC6 | MCLK_APBDMASK_TC7 | MCLK_APBDMASK_SERCOM6 | MCLK_APBDMASK_SERCOM7;
|
||||
|
||||
MCLK->APBDMASK.reg |= MCLK_APBDMASK_DAC | MCLK_APBDMASK_SERCOM4 | MCLK_APBDMASK_SERCOM5 | MCLK_APBDMASK_ADC0 | MCLK_APBDMASK_ADC1;
|
||||
#else
|
||||
// Clock SERCOM for Serial
|
||||
PM->APBCMASK.reg |= PM_APBCMASK_SERCOM0 | PM_APBCMASK_SERCOM1 | PM_APBCMASK_SERCOM2 | PM_APBCMASK_SERCOM3 | PM_APBCMASK_SERCOM4 | PM_APBCMASK_SERCOM5 ;
|
||||
|
||||
// Clock TC/TCC for Pulse and Analog
|
||||
PM->APBCMASK.reg |= PM_APBCMASK_TCC0 | PM_APBCMASK_TCC1 | PM_APBCMASK_TCC2 | PM_APBCMASK_TC3 | PM_APBCMASK_TC4 | PM_APBCMASK_TC5 ;
|
||||
PM->APBCMASK.reg |= PM_APBCMASK_TCC0 | PM_APBCMASK_TCC1 | PM_APBCMASK_TCC2 | PM_APBCMASK_TC3 | PM_APBCMASK_TC4 | PM_APBCMASK_TC5 | PM_APBCMASK_TC6 | PM_APBCMASK_TC7;
|
||||
|
||||
// ATSAMR, for example, doesn't have a DAC
|
||||
#ifdef PM_APBCMASK_DAC
|
||||
|
|
@ -100,35 +101,45 @@ void init( void )
|
|||
#endif
|
||||
#endif
|
||||
|
||||
/*
|
||||
Commented out to leave pins in default tri-state. This is
|
||||
aimed at avoiding power consumption in DeepSleep.
|
||||
|
||||
// Setup all pins (digital and analog) in INPUT mode (default is nothing)
|
||||
for (uint32_t ul = 0 ; ul < NUM_DIGITAL_PINS ; ul++ )
|
||||
{
|
||||
pinMode( ul, INPUT ) ;
|
||||
}
|
||||
*/
|
||||
|
||||
// Initialize Analog Controller
|
||||
// Setting clock
|
||||
#if defined(__SAMD51__)
|
||||
//set to 1/(1/(48000000/32) * 6) = 250000 SPS
|
||||
GCLK->PCHCTRL[ADC0_GCLK_ID].reg = GCLK_PCHCTRL_GEN_GCLK1_Val | (1 << GCLK_PCHCTRL_CHEN_Pos); //use clock generator 1 (48Mhz)
|
||||
GCLK->PCHCTRL[ADC1_GCLK_ID].reg = GCLK_PCHCTRL_GEN_GCLK1_Val | (1 << GCLK_PCHCTRL_CHEN_Pos); //use clock generator 1 (48Mhz)
|
||||
Adc *adcs[] = {ADC0, ADC1};
|
||||
for(int i=0; i<2; i++){
|
||||
|
||||
ADC0->CTRLA.bit.PRESCALER = ADC_CTRLA_PRESCALER_DIV256_Val;
|
||||
ADC0->CTRLB.bit.RESSEL = ADC_CTRLB_RESSEL_10BIT_Val;
|
||||
adcs[i]->CTRLA.bit.PRESCALER = ADC_CTRLA_PRESCALER_DIV32_Val;
|
||||
adcs[i]->CTRLB.bit.RESSEL = ADC_CTRLB_RESSEL_10BIT_Val;
|
||||
|
||||
while( ADC0->SYNCBUSY.reg & ADC_SYNCBUSY_CTRLB ); //wait for sync
|
||||
while( adcs[i]->SYNCBUSY.reg & ADC_SYNCBUSY_CTRLB ); //wait for sync
|
||||
|
||||
ADC0->SAMPCTRL.reg = 0x3f; // Set max Sampling Time Length
|
||||
adcs[i]->SAMPCTRL.reg = 5; // sampling Time Length
|
||||
|
||||
while( ADC0->SYNCBUSY.reg & ADC_SYNCBUSY_SAMPCTRL ); //wait for sync
|
||||
while( adcs[i]->SYNCBUSY.reg & ADC_SYNCBUSY_SAMPCTRL ); //wait for sync
|
||||
|
||||
ADC0->INPUTCTRL.reg = ADC_INPUTCTRL_MUXNEG_GND; // No Negative input (Internal Ground)
|
||||
adcs[i]->INPUTCTRL.reg = ADC_INPUTCTRL_MUXNEG_GND; // No Negative input (Internal Ground)
|
||||
|
||||
while( ADC0->SYNCBUSY.reg & ADC_SYNCBUSY_INPUTCTRL ); //wait for sync
|
||||
while( adcs[i]->SYNCBUSY.reg & ADC_SYNCBUSY_INPUTCTRL ); //wait for sync
|
||||
|
||||
// Averaging (see datasheet table in AVGCTRL register description)
|
||||
ADC0->AVGCTRL.reg = ADC_AVGCTRL_SAMPLENUM_1 | // 1 sample only (no oversampling nor averaging)
|
||||
adcs[i]->AVGCTRL.reg = ADC_AVGCTRL_SAMPLENUM_1 | // 1 sample only (no oversampling nor averaging)
|
||||
ADC_AVGCTRL_ADJRES(0x0ul); // Adjusting result by 0
|
||||
|
||||
while( ADC0->SYNCBUSY.reg & ADC_SYNCBUSY_AVGCTRL ); //wait for sync
|
||||
while( adcs[i]->SYNCBUSY.reg & ADC_SYNCBUSY_AVGCTRL ); //wait for sync
|
||||
}
|
||||
|
||||
analogReference( AR_DEFAULT ) ; // Analog Reference is AREF pin (3.3v)
|
||||
|
||||
|
|
@ -146,6 +157,8 @@ void init( void )
|
|||
DAC->DACCTRL[1].bit.REFRESH = 2;
|
||||
|
||||
#else
|
||||
//set to 1/(1/(48000000/32) * 6) = 250000 SPS
|
||||
|
||||
while(GCLK->STATUS.reg & GCLK_STATUS_SYNCBUSY);
|
||||
|
||||
GCLK->CLKCTRL.reg = GCLK_CLKCTRL_ID( GCM_ADC ) | // Generic Clock ADC
|
||||
|
|
@ -154,10 +167,10 @@ void init( void )
|
|||
|
||||
while( ADC->STATUS.bit.SYNCBUSY == 1 ); // Wait for synchronization of registers between the clock domains
|
||||
|
||||
ADC->CTRLB.reg = ADC_CTRLB_PRESCALER_DIV512 | // Divide Clock by 512.
|
||||
ADC->CTRLB.reg = ADC_CTRLB_PRESCALER_DIV32 | // Divide Clock by 32.
|
||||
ADC_CTRLB_RESSEL_10BIT; // 10 bits resolution as default
|
||||
|
||||
ADC->SAMPCTRL.reg = 0x3f; // Set max Sampling Time Length
|
||||
ADC->SAMPCTRL.reg = 5; // Sampling Time Length
|
||||
|
||||
while( ADC->STATUS.bit.SYNCBUSY == 1 ); // Wait for synchronization of registers between the clock domains
|
||||
|
||||
|
|
|
|||
|
|
@ -32,7 +32,7 @@ static int _writeResolution = 12;
|
|||
static int _dacResolution = 12;
|
||||
#else
|
||||
static int _writeResolution = 8;
|
||||
static int _dacResolution = 8;
|
||||
//static int _dacResolution = 10;
|
||||
#endif
|
||||
|
||||
|
||||
|
|
@ -77,17 +77,21 @@ void analogReadResolution(int res)
|
|||
|
||||
if (res > 10) {
|
||||
ADC0->CTRLB.bit.RESSEL = ADC_CTRLB_RESSEL_12BIT_Val;
|
||||
ADC1->CTRLB.bit.RESSEL = ADC_CTRLB_RESSEL_12BIT_Val;
|
||||
_ADCResolution = 12;
|
||||
} else if (res > 8) {
|
||||
ADC0->CTRLB.bit.RESSEL = ADC_CTRLB_RESSEL_10BIT_Val;
|
||||
ADC1->CTRLB.bit.RESSEL = ADC_CTRLB_RESSEL_10BIT_Val;
|
||||
_ADCResolution = 10;
|
||||
} else {
|
||||
ADC0->CTRLB.bit.RESSEL = ADC_CTRLB_RESSEL_8BIT_Val;
|
||||
ADC1->CTRLB.bit.RESSEL = ADC_CTRLB_RESSEL_8BIT_Val;
|
||||
_ADCResolution = 8;
|
||||
}
|
||||
|
||||
|
||||
while(ADC0->SYNCBUSY.reg & ADC_SYNCBUSY_CTRLB); //wait for sync
|
||||
while(ADC1->SYNCBUSY.reg & ADC_SYNCBUSY_CTRLB); //wait for sync
|
||||
#else
|
||||
|
||||
if (res > 10) {
|
||||
|
|
@ -131,38 +135,92 @@ void analogReference(eAnalogReference mode)
|
|||
{
|
||||
#if defined(__SAMD51__)
|
||||
while(ADC0->SYNCBUSY.reg & ADC_SYNCBUSY_REFCTRL); //wait for sync
|
||||
while(ADC1->SYNCBUSY.reg & ADC_SYNCBUSY_REFCTRL); //wait for sync
|
||||
|
||||
//TODO: fix gains
|
||||
switch (mode)
|
||||
{
|
||||
case AR_INTERNAL:
|
||||
case AR_INTERNAL2V23:
|
||||
case AR_INTERNAL1V0:
|
||||
//ADC0->GAINCORR.reg = ADC_GAINCORR_GAINCORR(); // Gain Factor Selection
|
||||
ADC0->REFCTRL.bit.REFSEL = ADC_REFCTRL_REFSEL_INTVCC0_Val; // 1/1.48 VDDANA = 1/1.48* 3V3 = 2.2297
|
||||
SUPC->VREF.bit.SEL = SUPC_VREF_SEL_1V0_Val; // select 1.0V
|
||||
SUPC->VREF.bit.VREFOE = 1; // Turn on for use with ADC
|
||||
ADC0->REFCTRL.bit.REFSEL = ADC_REFCTRL_REFSEL_INTREF_Val; // Use SUPC.VREF
|
||||
ADC1->REFCTRL.bit.REFSEL = ADC_REFCTRL_REFSEL_INTREF_Val; //
|
||||
break;
|
||||
|
||||
case AR_INTERNAL1V1:
|
||||
//ADC0->GAINCORR.reg = ADC_GAINCORR_GAINCORR(); // Gain Factor Selection
|
||||
SUPC->VREF.bit.SEL = SUPC_VREF_SEL_1V1_Val; // select 1.1V
|
||||
SUPC->VREF.bit.VREFOE = 1; // Turn on for use with ADC
|
||||
ADC0->REFCTRL.bit.REFSEL = ADC_REFCTRL_REFSEL_INTREF_Val; // Use SUPC.VREF
|
||||
ADC1->REFCTRL.bit.REFSEL = ADC_REFCTRL_REFSEL_INTREF_Val; //
|
||||
break;
|
||||
|
||||
case AR_INTERNAL1V2:
|
||||
//ADC0->GAINCORR.reg = ADC_GAINCORR_GAINCORR(); // Gain Factor Selection
|
||||
SUPC->VREF.bit.SEL = SUPC_VREF_SEL_1V2_Val; // select 1V2
|
||||
SUPC->VREF.bit.VREFOE = 1; // Turn on for use with ADC
|
||||
ADC0->REFCTRL.bit.REFSEL = ADC_REFCTRL_REFSEL_INTREF_Val; // Use SUPC.VREF
|
||||
ADC1->REFCTRL.bit.REFSEL = ADC_REFCTRL_REFSEL_INTREF_Val; //
|
||||
break;
|
||||
|
||||
case AR_INTERNAL1V25:
|
||||
//ADC0->GAINCORR.reg = ADC_GAINCORR_GAINCORR(); // Gain Factor Selection
|
||||
SUPC->VREF.bit.SEL = SUPC_VREF_SEL_1V25_Val; // select 1.25V
|
||||
SUPC->VREF.bit.VREFOE = 1; // Turn on for use with ADC
|
||||
ADC0->REFCTRL.bit.REFSEL = ADC_REFCTRL_REFSEL_INTREF_Val; // Use SUPC.VREF
|
||||
ADC1->REFCTRL.bit.REFSEL = ADC_REFCTRL_REFSEL_INTREF_Val; //
|
||||
break;
|
||||
|
||||
case AR_INTERNAL2V0:
|
||||
//ADC0->GAINCORR.reg = ADC_GAINCORR_GAINCORR(); // Gain Factor Selection
|
||||
SUPC->VREF.bit.SEL = SUPC_VREF_SEL_2V0_Val; // select 2.0V
|
||||
SUPC->VREF.bit.VREFOE = 1; // Turn on for use with ADC
|
||||
ADC0->REFCTRL.bit.REFSEL = ADC_REFCTRL_REFSEL_INTREF_Val; // Use SUPC.VREF
|
||||
ADC1->REFCTRL.bit.REFSEL = ADC_REFCTRL_REFSEL_INTREF_Val; //
|
||||
break;
|
||||
|
||||
case AR_INTERNAL2V2:
|
||||
//ADC0->GAINCORR.reg = ADC_GAINCORR_GAINCORR(); // Gain Factor Selection
|
||||
SUPC->VREF.bit.SEL = SUPC_VREF_SEL_2V2_Val; // select 2.2V
|
||||
SUPC->VREF.bit.VREFOE = 1; // Turn on for use with ADC
|
||||
ADC0->REFCTRL.bit.REFSEL = ADC_REFCTRL_REFSEL_INTREF_Val; // Use SUPC.VREF
|
||||
ADC1->REFCTRL.bit.REFSEL = ADC_REFCTRL_REFSEL_INTREF_Val; //
|
||||
break;
|
||||
|
||||
case AR_INTERNAL2V4:
|
||||
//ADC0->GAINCORR.reg = ADC_GAINCORR_GAINCORR(); // Gain Factor Selection
|
||||
SUPC->VREF.bit.SEL = SUPC_VREF_SEL_2V4_Val; // select 2.4V
|
||||
SUPC->VREF.bit.VREFOE = 1; // Turn on for use with ADC
|
||||
ADC0->REFCTRL.bit.REFSEL = ADC_REFCTRL_REFSEL_INTREF_Val; // Use SUPC.VREF
|
||||
ADC1->REFCTRL.bit.REFSEL = ADC_REFCTRL_REFSEL_INTREF_Val; //
|
||||
break;
|
||||
|
||||
case AR_INTERNAL2V5:
|
||||
//ADC0->GAINCORR.reg = ADC_GAINCORR_GAINCORR(); // Gain Factor Selection
|
||||
SUPC->VREF.bit.SEL = SUPC_VREF_SEL_2V5_Val; // select 2.5V
|
||||
SUPC->VREF.bit.VREFOE = 1; // Turn on for use with ADC
|
||||
ADC0->REFCTRL.bit.REFSEL = ADC_REFCTRL_REFSEL_INTREF_Val; // Use SUPC.VREF
|
||||
ADC1->REFCTRL.bit.REFSEL = ADC_REFCTRL_REFSEL_INTREF_Val; //
|
||||
break;
|
||||
|
||||
case AR_EXTERNAL:
|
||||
//ADC0->INPUTCTRL.bit.GAIN = ADC_INPUTCTRL_GAIN_1X_Val; // Gain Factor Selection
|
||||
ADC0->REFCTRL.bit.REFSEL = ADC_REFCTRL_REFSEL_AREFA_Val;
|
||||
ADC0->REFCTRL.bit.REFSEL = ADC_REFCTRL_REFSEL_AREFA_Val; // AREF is jumpered to VCC, so 3.3V
|
||||
ADC1->REFCTRL.bit.REFSEL = ADC_REFCTRL_REFSEL_AREFA_Val;
|
||||
break;
|
||||
|
||||
/* Don't think this works on SAMD51
|
||||
case AR_INTERNAL1V0:
|
||||
//ADC0->INPUTCTRL.bit.GAIN = ADC_INPUTCTRL_GAIN_1X_Val; // Gain Factor Selection
|
||||
ADC0->REFCTRL.bit.REFSEL = ADC_REFCTRL_REFSEL_INT1V_Val; // 1.0V voltage reference
|
||||
break;
|
||||
*/
|
||||
|
||||
case AR_INTERNAL1V65:
|
||||
//ADC0->INPUTCTRL.bit.GAIN = ADC_INPUTCTRL_GAIN_1X_Val; // Gain Factor Selection
|
||||
ADC0->REFCTRL.bit.REFSEL = ADC_REFCTRL_REFSEL_INTVCC1_Val; // 1/2 VDDANA = 0.5* 3V3 = 1.65V
|
||||
//ADC0->INPUTCTRL.bit.GAIN = ADC_INPUTCTRL_GAIN_DIV2_Val;
|
||||
ADC0->REFCTRL.bit.REFSEL = ADC_REFCTRL_REFSEL_INTVCC0_Val; // 1/2 VDDANA = 1.65
|
||||
ADC1->REFCTRL.bit.REFSEL = ADC_REFCTRL_REFSEL_INTVCC0_Val; //
|
||||
break;
|
||||
|
||||
case AR_DEFAULT:
|
||||
default:
|
||||
//ADC0->INPUTCTRL.bit.GAIN = ADC_INPUTCTRL_GAIN_DIV2_Val;
|
||||
ADC0->REFCTRL.bit.REFSEL = ADC_REFCTRL_REFSEL_INTVCC1_Val; // 1/2 VDDANA = 0.5* 3V3 = 1.65V
|
||||
|
||||
ADC0->REFCTRL.bit.REFSEL = ADC_REFCTRL_REFSEL_INTVCC1_Val; // VDDANA = 3V3
|
||||
ADC1->REFCTRL.bit.REFSEL = ADC_REFCTRL_REFSEL_INTVCC1_Val; //
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
@ -170,7 +228,6 @@ void analogReference(eAnalogReference mode)
|
|||
syncADC();
|
||||
switch (mode)
|
||||
{
|
||||
case AR_INTERNAL:
|
||||
case AR_INTERNAL2V23:
|
||||
ADC->INPUTCTRL.bit.GAIN = ADC_INPUTCTRL_GAIN_1X_Val; // Gain Factor Selection
|
||||
ADC->REFCTRL.bit.REFSEL = ADC_REFCTRL_REFSEL_INTVCC0_Val; // 1/1.48 VDDANA = 1/1.48* 3V3 = 2.2297
|
||||
|
|
@ -223,8 +280,8 @@ uint32_t analogRead(uint32_t pin)
|
|||
#ifdef DAC
|
||||
|
||||
#if defined(__SAMD51__)
|
||||
if (pin == A0 || pin == A1) { // Disable DAC, if analogWrite(A0,dval) used previously the DAC is enabled
|
||||
uint8_t channel = (pin == PIN_A0 ? 0 : 1);
|
||||
if (pin == PIN_DAC0 || pin == PIN_DAC1) { // Disable DAC, if analogWrite(A0,dval) used previously the DAC is enabled
|
||||
uint8_t channel = (pin == PIN_DAC0 ? 0 : 1);
|
||||
|
||||
if(dacEnabled[channel]){
|
||||
dacEnabled[channel] = false;
|
||||
|
|
@ -241,7 +298,7 @@ uint32_t analogRead(uint32_t pin)
|
|||
|
||||
while (DAC->SYNCBUSY.bit.ENABLE);
|
||||
#else
|
||||
if (pin == A0) { // Disable DAC, if analogWrite(A0,dval) used previously the DAC is enabled
|
||||
if (pin == PIN_DAC0) { // Disable DAC, if analogWrite(A0,dval) used previously the DAC is enabled
|
||||
syncDAC();
|
||||
|
||||
DAC->CTRLA.bit.ENABLE = 0x00; // Disable DAC
|
||||
|
|
@ -253,8 +310,13 @@ uint32_t analogRead(uint32_t pin)
|
|||
#endif
|
||||
|
||||
#if defined(__SAMD51__)
|
||||
while( ADC0->SYNCBUSY.reg & ADC_SYNCBUSY_INPUTCTRL ); //wait for sync
|
||||
ADC0->INPUTCTRL.bit.MUXPOS = g_APinDescription[pin].ulADCChannelNumber; // Selection for the positive ADC input
|
||||
Adc *adc;
|
||||
if(g_APinDescription[pin].ulPinAttribute & PIN_ATTR_ANALOG) adc = ADC0;
|
||||
else if(g_APinDescription[pin].ulPinAttribute & PIN_ATTR_ANALOG_ALT) adc = ADC1;
|
||||
else return 0;
|
||||
|
||||
while( adc->SYNCBUSY.reg & ADC_SYNCBUSY_INPUTCTRL ); //wait for sync
|
||||
adc->INPUTCTRL.bit.MUXPOS = g_APinDescription[pin].ulADCChannelNumber; // Selection for the positive ADC input
|
||||
|
||||
// Control A
|
||||
/*
|
||||
|
|
@ -268,27 +330,27 @@ uint32_t analogRead(uint32_t pin)
|
|||
* Before enabling the ADC, the asynchronous clock source must be selected and enabled, and the ADC reference must be
|
||||
* configured. The first conversion after the reference is changed must not be used.
|
||||
*/
|
||||
while( ADC0->SYNCBUSY.reg & ADC_SYNCBUSY_ENABLE ); //wait for sync
|
||||
ADC0->CTRLA.bit.ENABLE = 0x01; // Enable ADC
|
||||
while( adc->SYNCBUSY.reg & ADC_SYNCBUSY_ENABLE ); //wait for sync
|
||||
adc->CTRLA.bit.ENABLE = 0x01; // Enable ADC
|
||||
|
||||
// Start conversion
|
||||
while( ADC0->SYNCBUSY.reg & ADC_SYNCBUSY_ENABLE ); //wait for sync
|
||||
while( adc->SYNCBUSY.reg & ADC_SYNCBUSY_ENABLE ); //wait for sync
|
||||
|
||||
ADC0->SWTRIG.bit.START = 1;
|
||||
adc->SWTRIG.bit.START = 1;
|
||||
|
||||
// Clear the Data Ready flag
|
||||
ADC0->INTFLAG.reg = ADC_INTFLAG_RESRDY;
|
||||
adc->INTFLAG.reg = ADC_INTFLAG_RESRDY;
|
||||
|
||||
// Start conversion again, since The first conversion after the reference is changed must not be used.
|
||||
ADC0->SWTRIG.bit.START = 1;
|
||||
adc->SWTRIG.bit.START = 1;
|
||||
|
||||
// Store the value
|
||||
while (ADC0->INTFLAG.bit.RESRDY == 0); // Waiting for conversion to complete
|
||||
valueRead = ADC0->RESULT.reg;
|
||||
while (adc->INTFLAG.bit.RESRDY == 0); // Waiting for conversion to complete
|
||||
valueRead = adc->RESULT.reg;
|
||||
|
||||
while( ADC0->SYNCBUSY.reg & ADC_SYNCBUSY_ENABLE ); //wait for sync
|
||||
ADC0->CTRLA.bit.ENABLE = 0x00; // Disable ADC
|
||||
while( ADC0->SYNCBUSY.reg & ADC_SYNCBUSY_ENABLE ); //wait for sync
|
||||
while( adc->SYNCBUSY.reg & ADC_SYNCBUSY_ENABLE ); //wait for sync
|
||||
adc->CTRLA.bit.ENABLE = 0x00; // Disable ADC
|
||||
while( adc->SYNCBUSY.reg & ADC_SYNCBUSY_ENABLE ); //wait for sync
|
||||
|
||||
#else
|
||||
syncADC();
|
||||
|
|
@ -344,22 +406,21 @@ void analogWrite(uint32_t pin, uint32_t value)
|
|||
|
||||
// ATSAMR, for example, doesn't have a DAC
|
||||
#ifdef DAC
|
||||
|
||||
if ((attr & PIN_ATTR_ANALOG) == PIN_ATTR_ANALOG)
|
||||
{
|
||||
// DAC handling code
|
||||
#if defined(__SAMD51__)
|
||||
if (pin != PIN_A0 && pin != PIN_A1) { // 2 DACs on A0 (PA02) and A1 (PA05)
|
||||
if (pin == PIN_DAC0 || pin == PIN_DAC1) { // 2 DACs on A0 (PA02) and A1 (PA05)
|
||||
#else
|
||||
if (pin != PIN_A0) { // Only 1 DAC on A0 (PA02)
|
||||
if (pin == PIN_DAC0) { // Only 1 DAC on A0 (PA02)
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
|
||||
#if defined(__SAMD51__)
|
||||
|
||||
value = mapResolution(value, _writeResolution, _dacResolution);
|
||||
|
||||
#if defined(__SAMD51__)
|
||||
uint8_t channel = (pin == PIN_A0 ? 0 : 1);
|
||||
|
||||
uint8_t channel = (pin == PIN_DAC0 ? 0 : 1);
|
||||
|
||||
pinPeripheral(pin, PIO_ANALOG);
|
||||
|
||||
|
|
@ -411,66 +472,33 @@ void analogWrite(uint32_t pin, uint32_t value)
|
|||
|
||||
|
||||
#else
|
||||
value = mapResolution(value, _dacResolution, 10);
|
||||
syncDAC();
|
||||
DAC->DATA.reg = value & 0x3FF; // DAC on 10 bits.
|
||||
syncDAC();
|
||||
DAC->CTRLA.bit.ENABLE = 0x01; // Enable DAC
|
||||
syncDAC();
|
||||
#endif
|
||||
#endif // __SAMD51__
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
#endif // DAC
|
||||
|
||||
if ((attr & PIN_ATTR_PWM) == PIN_ATTR_PWM)
|
||||
{
|
||||
#ifndef __SAMD51__
|
||||
value = mapResolution(value, _writeResolution, 16);
|
||||
#endif
|
||||
#if defined(__SAMD51__)
|
||||
if(attr & (PIN_ATTR_PWM_E|PIN_ATTR_PWM_F|PIN_ATTR_PWM_G)){
|
||||
|
||||
uint32_t tcNum = GetTCNumber(pinDesc.ulPWMChannel);
|
||||
uint8_t tcChannel = GetTCChannelNumber(pinDesc.ulPWMChannel);
|
||||
static bool tcEnabled[TCC_INST_NUM+TC_INST_NUM];
|
||||
|
||||
if (attr & PIN_ATTR_TIMER) {
|
||||
#if !(ARDUINO_SAMD_VARIANT_COMPLIANCE >= 10603)
|
||||
// Compatibility for cores based on SAMD core <=1.6.2
|
||||
if (pinDesc.ulPinType == PIO_TIMER_ALT) {
|
||||
pinPeripheral(pin, PIO_TIMER_ALT);
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
|
||||
#if defined(__SAMD51__)
|
||||
//on SAMD51 we are only using TCC for timers
|
||||
pinPeripheral(pin, PIO_TCC_PDEC);
|
||||
#else
|
||||
if(attr & PIN_ATTR_PWM_E)
|
||||
pinPeripheral(pin, PIO_TIMER);
|
||||
#endif
|
||||
}
|
||||
} else if ((attr & PIN_ATTR_TIMER_ALT) == PIN_ATTR_TIMER_ALT){
|
||||
//this is on an alt timer
|
||||
else if(attr & PIN_ATTR_PWM_F)
|
||||
pinPeripheral(pin, PIO_TIMER_ALT);
|
||||
}
|
||||
else{
|
||||
return;
|
||||
}
|
||||
else if(attr & PIN_ATTR_PWM_G)
|
||||
pinPeripheral(pin, PIO_TCC_PDEC);
|
||||
|
||||
if (!tcEnabled[tcNum]) {
|
||||
tcEnabled[tcNum] = true;
|
||||
|
||||
#if defined(__SAMD51__)
|
||||
uint32_t GCLK_CLKCTRL_IDs[] = {
|
||||
TCC0_GCLK_ID,
|
||||
TCC1_GCLK_ID,
|
||||
TCC2_GCLK_ID,
|
||||
#if defined(TCC3)
|
||||
TCC3_GCLK_ID,
|
||||
TCC4_GCLK_ID,
|
||||
TC5_GCLK_ID,
|
||||
#endif
|
||||
};
|
||||
|
||||
GCLK->PCHCTRL[GCLK_CLKCTRL_IDs[tcNum]].reg = GCLK_PCHCTRL_GEN_GCLK0_Val | (1 << GCLK_PCHCTRL_CHEN_Pos); //use clock generator 0
|
||||
|
||||
// Set PORT
|
||||
|
|
@ -527,7 +555,8 @@ void analogWrite(uint32_t pin, uint32_t value)
|
|||
TCCx->CTRLA.bit.ENABLE = 1;
|
||||
while (TCCx->SYNCBUSY.bit.ENABLE);
|
||||
}
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
if (tcNum >= TCC_INST_NUM) {
|
||||
Tc* TCx = (Tc*) GetTC(pinDesc.ulPWMChannel);
|
||||
TCx->COUNT8.CC[tcChannel].reg = (uint8_t) value;
|
||||
|
|
@ -543,7 +572,39 @@ void analogWrite(uint32_t pin, uint32_t value)
|
|||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
if ((attr & PIN_ATTR_PWM) == PIN_ATTR_PWM)
|
||||
{
|
||||
value = mapResolution(value, _writeResolution, 16);
|
||||
|
||||
uint32_t tcNum = GetTCNumber(pinDesc.ulPWMChannel);
|
||||
uint8_t tcChannel = GetTCChannelNumber(pinDesc.ulPWMChannel);
|
||||
static bool tcEnabled[TCC_INST_NUM+TC_INST_NUM];
|
||||
|
||||
if (attr & PIN_ATTR_TIMER) {
|
||||
#if !(ARDUINO_SAMD_VARIANT_COMPLIANCE >= 10603)
|
||||
// Compatibility for cores based on SAMD core <=1.6.2
|
||||
if (pinDesc.ulPinType == PIO_TIMER_ALT) {
|
||||
pinPeripheral(pin, PIO_TIMER_ALT);
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
pinPeripheral(pin, PIO_TIMER);
|
||||
}
|
||||
} else if ((attr & PIN_ATTR_TIMER_ALT) == PIN_ATTR_TIMER_ALT){
|
||||
//this is on an alt timer
|
||||
pinPeripheral(pin, PIO_TIMER_ALT);
|
||||
}
|
||||
else{
|
||||
return;
|
||||
}
|
||||
|
||||
if (!tcEnabled[tcNum]) {
|
||||
tcEnabled[tcNum] = true;
|
||||
uint16_t GCLK_CLKCTRL_IDs[] = {
|
||||
GCLK_CLKCTRL_ID(GCM_TCC0_TCC1), // TCC0
|
||||
GCLK_CLKCTRL_ID(GCM_TCC0_TCC1), // TCC1
|
||||
|
|
@ -607,10 +668,9 @@ void analogWrite(uint32_t pin, uint32_t value)
|
|||
syncTCC(TCCx);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
// -- Defaults to digital write
|
||||
pinMode(pin, OUTPUT);
|
||||
|
|
|
|||
|
|
@ -27,14 +27,21 @@ extern "C" {
|
|||
/*
|
||||
* \brief SAMD products have only one reference for ADC
|
||||
*/
|
||||
// add internal voltages for ATSAMD51 SUPC VREF register
|
||||
typedef enum _eAnalogReference
|
||||
{
|
||||
AR_DEFAULT,
|
||||
AR_INTERNAL,
|
||||
AR_EXTERNAL,
|
||||
AR_INTERNAL1V0,
|
||||
AR_INTERNAL1V1,
|
||||
AR_INTERNAL1V2,
|
||||
AR_INTERNAL1V25,
|
||||
AR_INTERNAL2V0,
|
||||
AR_INTERNAL2V2,
|
||||
AR_INTERNAL2V23,
|
||||
AR_INTERNAL2V4,
|
||||
AR_INTERNAL2V5,
|
||||
AR_INTERNAL1V65,
|
||||
AR_INTERNAL2V23
|
||||
AR_EXTERNAL
|
||||
} eAnalogReference ;
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -30,39 +30,43 @@ void pinMode( uint32_t ulPin, uint32_t ulMode )
|
|||
return ;
|
||||
}
|
||||
|
||||
EPortType port = g_APinDescription[ulPin].ulPort;
|
||||
uint32_t pin = g_APinDescription[ulPin].ulPin;
|
||||
uint32_t pinMask = (1ul << pin);
|
||||
|
||||
// Set pin mode according to chapter '22.6.3 I/O Pin Configuration'
|
||||
switch ( ulMode )
|
||||
{
|
||||
case INPUT:
|
||||
// Set pin to input mode
|
||||
PORT->Group[g_APinDescription[ulPin].ulPort].PINCFG[g_APinDescription[ulPin].ulPin].reg=(uint8_t)(PORT_PINCFG_INEN) ;
|
||||
PORT->Group[g_APinDescription[ulPin].ulPort].DIRCLR.reg = (uint32_t)(1<<g_APinDescription[ulPin].ulPin) ;
|
||||
PORT->Group[port].PINCFG[pin].reg=(uint8_t)(PORT_PINCFG_INEN) ;
|
||||
PORT->Group[port].DIRCLR.reg = pinMask ;
|
||||
break ;
|
||||
|
||||
case INPUT_PULLUP:
|
||||
// Set pin to input mode with pull-up resistor enabled
|
||||
PORT->Group[g_APinDescription[ulPin].ulPort].PINCFG[g_APinDescription[ulPin].ulPin].reg=(uint8_t)(PORT_PINCFG_INEN|PORT_PINCFG_PULLEN) ;
|
||||
PORT->Group[g_APinDescription[ulPin].ulPort].DIRCLR.reg = (uint32_t)(1<<g_APinDescription[ulPin].ulPin) ;
|
||||
PORT->Group[port].PINCFG[pin].reg=(uint8_t)(PORT_PINCFG_INEN|PORT_PINCFG_PULLEN) ;
|
||||
PORT->Group[port].DIRCLR.reg = pinMask ;
|
||||
|
||||
// Enable pull level (cf '22.6.3.2 Input Configuration' and '22.8.7 Data Output Value Set')
|
||||
PORT->Group[g_APinDescription[ulPin].ulPort].OUTSET.reg = (uint32_t)(1<<g_APinDescription[ulPin].ulPin) ;
|
||||
PORT->Group[port].OUTSET.reg = pinMask ;
|
||||
break ;
|
||||
|
||||
case INPUT_PULLDOWN:
|
||||
// Set pin to input mode with pull-down resistor enabled
|
||||
PORT->Group[g_APinDescription[ulPin].ulPort].PINCFG[g_APinDescription[ulPin].ulPin].reg=(uint8_t)(PORT_PINCFG_INEN|PORT_PINCFG_PULLEN) ;
|
||||
PORT->Group[g_APinDescription[ulPin].ulPort].DIRCLR.reg = (uint32_t)(1<<g_APinDescription[ulPin].ulPin) ;
|
||||
PORT->Group[port].PINCFG[pin].reg=(uint8_t)(PORT_PINCFG_INEN|PORT_PINCFG_PULLEN) ;
|
||||
PORT->Group[port].DIRCLR.reg = pinMask ;
|
||||
|
||||
// Enable pull level (cf '22.6.3.2 Input Configuration' and '22.8.6 Data Output Value Clear')
|
||||
PORT->Group[g_APinDescription[ulPin].ulPort].OUTCLR.reg = (uint32_t)(1<<g_APinDescription[ulPin].ulPin) ;
|
||||
PORT->Group[port].OUTCLR.reg = pinMask ;
|
||||
break ;
|
||||
|
||||
case OUTPUT:
|
||||
// enable input, to support reading back values, with pullups disabled
|
||||
PORT->Group[g_APinDescription[ulPin].ulPort].PINCFG[g_APinDescription[ulPin].ulPin].reg=(uint8_t)(PORT_PINCFG_INEN) ;
|
||||
PORT->Group[port].PINCFG[pin].reg=(uint8_t)(PORT_PINCFG_INEN) ;
|
||||
|
||||
// Set pin to output mode
|
||||
PORT->Group[g_APinDescription[ulPin].ulPort].DIRSET.reg = (uint32_t)(1<<g_APinDescription[ulPin].ulPin) ;
|
||||
PORT->Group[port].DIRSET.reg = pinMask ;
|
||||
break ;
|
||||
|
||||
default:
|
||||
|
|
|
|||
|
|
@ -107,7 +107,7 @@ int pinPeripheral( uint32_t ulPin, EPioType ulPeripheral )
|
|||
// Set new muxing
|
||||
PORT->Group[g_APinDescription[ulPin].ulPort].PMUX[g_APinDescription[ulPin].ulPin >> 1].reg = temp|PORT_PMUX_PMUXO( ulPeripheral ) ;
|
||||
// Enable port mux
|
||||
PORT->Group[g_APinDescription[ulPin].ulPort].PINCFG[g_APinDescription[ulPin].ulPin].reg |= PORT_PINCFG_PMUXEN ;
|
||||
PORT->Group[g_APinDescription[ulPin].ulPort].PINCFG[g_APinDescription[ulPin].ulPin].reg |= PORT_PINCFG_PMUXEN | PORT_PINCFG_DRVSTR;
|
||||
}
|
||||
else // even pin
|
||||
{
|
||||
|
|
@ -115,7 +115,7 @@ int pinPeripheral( uint32_t ulPin, EPioType ulPeripheral )
|
|||
|
||||
temp = (PORT->Group[g_APinDescription[ulPin].ulPort].PMUX[g_APinDescription[ulPin].ulPin >> 1].reg) & PORT_PMUX_PMUXO( 0xF ) ;
|
||||
PORT->Group[g_APinDescription[ulPin].ulPort].PMUX[g_APinDescription[ulPin].ulPin >> 1].reg = temp|PORT_PMUX_PMUXE( ulPeripheral ) ;
|
||||
PORT->Group[g_APinDescription[ulPin].ulPort].PINCFG[g_APinDescription[ulPin].ulPin].reg |= PORT_PINCFG_PMUXEN ; // Enable port mux
|
||||
PORT->Group[g_APinDescription[ulPin].ulPort].PINCFG[g_APinDescription[ulPin].ulPin].reg |= PORT_PINCFG_PMUXEN | PORT_PINCFG_DRVSTR ; // Enable port mux
|
||||
}
|
||||
#endif
|
||||
break ;
|
||||
|
|
|
|||
Binary file not shown.
|
|
@ -46,6 +46,14 @@ StartType=3
|
|||
ErrorControl=1
|
||||
ServiceBinary=%12%\%DRIVERFILENAME%.sys
|
||||
|
||||
[NullInstall.nt]
|
||||
; nothing to do for a null driver
|
||||
|
||||
[NullInstall.nt.Services]
|
||||
; null driver has no service and no service name
|
||||
AddService=, 0x00000002
|
||||
|
||||
|
||||
;------------------------------------------------------------------------------
|
||||
; Vista-64bit Sections
|
||||
;------------------------------------------------------------------------------
|
||||
|
|
@ -73,6 +81,13 @@ StartType=3
|
|||
ErrorControl=1
|
||||
ServiceBinary=%12%\%DRIVERFILENAME%.sys
|
||||
|
||||
[NullInstall.NTamd64]
|
||||
; nothing to do for a null driver
|
||||
|
||||
[NullInstall.NTamd64.Services]
|
||||
; null driver has no service and no service name
|
||||
AddService=, 0x00000002
|
||||
|
||||
|
||||
;------------------------------------------------------------------------------
|
||||
; Vendor and Product ID Definitions
|
||||
|
|
@ -87,14 +102,14 @@ ServiceBinary=%12%\%DRIVERFILENAME%.sys
|
|||
[SourceDisksNames]
|
||||
[DeviceList]
|
||||
"%DESCRIPTION% UF2 Bootloader (0018:00) BSP"=DriverInstall, USB\VID_239A&PID_0018&MI_00
|
||||
"%DESCRIPTION% UF2 WebUSB dummy (0018:04) BSP"=DriverInstall, USB\VID_239A&PID_0018&MI_00
|
||||
"%DESCRIPTION% UF2 WebUSB dummy (0018:04) BSP"=NullInstall, USB\VID_239A&PID_0018&MI_04
|
||||
"%DESCRIPTION% (0019:00) BSP"=DriverInstall, USB\VID_239A&PID_0019&MI_00
|
||||
"%DESCRIPTION% Arduino (8018:00) BSP"=DriverInstall, USB\VID_239A&PID_8018&MI_00
|
||||
"%DESCRIPTION% CircuitPython (8019:00) BSP"=DriverInstall, USB\VID_239A&PID_8019&MI_00
|
||||
|
||||
[DeviceList.NTamd64]
|
||||
"%DESCRIPTION% UF2 Bootloader (0018:00) BSP"=DriverInstall, USB\VID_239A&PID_0018&MI_00
|
||||
"%DESCRIPTION% UF2 WebUSB dummy (0018:04) BSP"=DriverInstall, USB\VID_239A&PID_0018&MI_00
|
||||
"%DESCRIPTION% UF2 WebUSB dummy (0018:04) BSP"=NullInstall, USB\VID_239A&PID_0018&MI_04
|
||||
"%DESCRIPTION% (0019:00) BSP"=DriverInstall, USB\VID_239A&PID_0019&MI_00
|
||||
"%DESCRIPTION% Arduino (8018:00) BSP"=DriverInstall, USB\VID_239A&PID_8018&MI_00
|
||||
"%DESCRIPTION% CircuitPython (8019:00) BSP"=DriverInstall, USB\VID_239A&PID_8019&MI_00
|
||||
|
|
|
|||
124
extras/build_all.py
Normal file
124
extras/build_all.py
Normal file
|
|
@ -0,0 +1,124 @@
|
|||
import os
|
||||
import glob
|
||||
import sys
|
||||
import subprocess
|
||||
import time
|
||||
import argparse
|
||||
|
||||
FQBN_PREFIX='adafruit:samd:adafruit_'
|
||||
|
||||
|
||||
parser = argparse.ArgumentParser(
|
||||
description='python wrapper for adafruit arduino CI workflows',
|
||||
allow_abbrev=False
|
||||
)
|
||||
parser.add_argument(
|
||||
'--all_warnings', '--Wall',
|
||||
action='store_true',
|
||||
help='build with all warnings enabled (`--warnings all`)',
|
||||
)
|
||||
parser.add_argument(
|
||||
'--warnings_do_not_cause_job_failure',
|
||||
action='store_true',
|
||||
help='failed builds will be listed as failed, but not cause job to exit with an error status',
|
||||
)
|
||||
parser.add_argument(
|
||||
'build_boards',
|
||||
metavar='board',
|
||||
nargs='*',
|
||||
help='list of boards to be built -- Note that the fqbn is created by prepending "{}"'.format(FQBN_PREFIX),
|
||||
default= [ 'metro_m0', 'metro_m4', 'circuitplayground_m0' ]
|
||||
)
|
||||
args = parser.parse_args()
|
||||
|
||||
exit_status = 0
|
||||
success_count = 0
|
||||
fail_count = 0
|
||||
skip_count = 0
|
||||
build_format = '| {:22} | {:30} | {:9} '
|
||||
build_separator = '-' * 80
|
||||
|
||||
def errorOutputFilter(line: str):
|
||||
if len(line) == 0:
|
||||
return False
|
||||
if line.isspace(): # Note: empty string does not match here!
|
||||
return False
|
||||
# TODO: additional items to remove?
|
||||
return True
|
||||
|
||||
def build_examples(variant: str):
|
||||
global args, exit_status, success_count, fail_count, skip_count, build_format, build_separator
|
||||
|
||||
print('\n')
|
||||
print(build_separator)
|
||||
print('| {:^76} |'.format('Board ' + variant))
|
||||
print(build_separator)
|
||||
print((build_format + '| {:6} |').format('Library', 'Example', 'Result', 'Time'))
|
||||
print(build_separator)
|
||||
|
||||
fqbn = "{}{}".format(FQBN_PREFIX, variant)
|
||||
|
||||
for sketch in glob.iglob('libraries/**/*.ino', recursive=True):
|
||||
start_time = time.monotonic()
|
||||
|
||||
# Skip if contains: ".board.test.skip" or ".all.test.skip"
|
||||
# Skip if not contains: ".board.test.only" for a specific board
|
||||
sketchdir = os.path.dirname(sketch)
|
||||
if os.path.exists(sketchdir + '/.all.test.skip') or os.path.exists(sketchdir + '/.' + variant + '.test.skip'):
|
||||
success = "\033[33mskipped\033[0m "
|
||||
elif glob.glob(sketchdir+"/.*.test.only") and not os.path.exists(sketchdir + '/.build.' + variant):
|
||||
success = "\033[33mskipped\033[0m "
|
||||
else:
|
||||
# TODO - preferably, would have STDERR show up in **both** STDOUT and STDERR.
|
||||
# preferably, would use Python logging handler to get both distinct outputs and one merged output
|
||||
# for now, split STDERR when building with all warnings enabled, so can detect warning/error output.
|
||||
if args.all_warnings:
|
||||
build_result = subprocess.run("arduino-cli compile --warnings all --fqbn {} {}".format(fqbn, sketch), shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
||||
else:
|
||||
build_result = subprocess.run("arduino-cli compile --warnings default --fqbn {} {}".format(fqbn, sketch), shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
|
||||
|
||||
# get stderr into a form where len(warningLines) indicates a true warning was output to stderr
|
||||
warningLines = [];
|
||||
if args.all_warnings and build_result.stderr:
|
||||
tmpWarningLines = build_result.stderr.decode("utf-8").splitlines()
|
||||
warningLines = list(filter(errorOutputFilter, (tmpWarningLines)))
|
||||
|
||||
if build_result.returncode != 0:
|
||||
exit_status = build_result.returncode
|
||||
success = "\033[31mfailed\033[0m "
|
||||
fail_count += 1
|
||||
elif len(warningLines) != 0:
|
||||
if not args.warnings_do_not_cause_job_failure:
|
||||
exit_status = -1
|
||||
success = "\033[31mwarnings\033[0m "
|
||||
fail_count += 1
|
||||
else:
|
||||
success = "\033[32msucceeded\033[0m"
|
||||
success_count += 1
|
||||
|
||||
build_duration = time.monotonic() - start_time
|
||||
|
||||
print((build_format + '| {:5.2f}s |').format(sketch.split(os.path.sep)[1], os.path.basename(sketch), success, build_duration))
|
||||
|
||||
if success != "\033[33mskipped\033[0m ":
|
||||
if build_result.returncode != 0:
|
||||
print(build_result.stdout.decode("utf-8"))
|
||||
if (build_result.stderr):
|
||||
print(build_result.stderr.decode("utf-8"))
|
||||
if len(warningLines) != 0:
|
||||
for line in warningLines:
|
||||
print(line)
|
||||
else:
|
||||
skip_count += 1
|
||||
|
||||
build_time = time.monotonic()
|
||||
|
||||
for board in args.build_boards:
|
||||
build_examples(board)
|
||||
|
||||
print(build_separator)
|
||||
build_time = time.monotonic() - build_time
|
||||
print("Build Summary: {} \033[32msucceeded\033[0m, {} \033[31mfailed\033[0m, {} \033[33mskipped\033[0m and took {:.2f}s".format(success_count, fail_count, skip_count, build_time))
|
||||
print(build_separator)
|
||||
|
||||
sys.exit(exit_status)
|
||||
|
|
@ -1,2 +1,3 @@
|
|||
SerialGSM KEYWORD1
|
||||
SerialSARA KEYWORD1
|
||||
INPUT_PULLDOWN LITERAL1 Constants RESERVED_WORD_2
|
||||
|
|
|
|||
654
libraries/Adafruit_ZeroDMA/Adafruit_ZeroDMA.cpp
Normal file
654
libraries/Adafruit_ZeroDMA/Adafruit_ZeroDMA.cpp
Normal file
|
|
@ -0,0 +1,654 @@
|
|||
#include <Adafruit_ZeroDMA.h>
|
||||
#include <malloc.h> // memalign() function
|
||||
|
||||
#include "utility/dma.h"
|
||||
static volatile uint32_t _channelMask = 0; // Bitmask of allocated channels
|
||||
|
||||
// DMA descriptor list entry point (and writeback buffer) per channel
|
||||
__attribute__((__aligned__(16))) static DmacDescriptor // 128 bit alignment
|
||||
_descriptor[DMAC_CH_NUM] SECTION_DMAC_DESCRIPTOR,
|
||||
_writeback[DMAC_CH_NUM] SECTION_DMAC_DESCRIPTOR;
|
||||
|
||||
// Pointer to ZeroDMA object for each channel is needed for the
|
||||
// ISR (in C, outside of class context) to access callbacks.
|
||||
static Adafruit_ZeroDMA *_dmaPtr[DMAC_CH_NUM] = { 0 }; // Init to NULL
|
||||
|
||||
// Adapted from ASF3 interrupt_sam_nvic.c:
|
||||
|
||||
static volatile unsigned long cpu_irq_critical_section_counter = 0;
|
||||
static volatile unsigned char cpu_irq_prev_interrupt_state = 0;
|
||||
|
||||
static void cpu_irq_enter_critical(void) {
|
||||
if(!cpu_irq_critical_section_counter) {
|
||||
if(__get_PRIMASK() == 0) { // IRQ enabled?
|
||||
__disable_irq(); // Disable it
|
||||
__DMB();
|
||||
cpu_irq_prev_interrupt_state = 1;
|
||||
} else {
|
||||
// Make sure the to save the prev state as false
|
||||
cpu_irq_prev_interrupt_state = 0;
|
||||
}
|
||||
}
|
||||
|
||||
cpu_irq_critical_section_counter++;
|
||||
}
|
||||
|
||||
static void cpu_irq_leave_critical(void) {
|
||||
// Check if the user is trying to leave a critical section
|
||||
// when not in a critical section
|
||||
if(cpu_irq_critical_section_counter > 0) {
|
||||
cpu_irq_critical_section_counter--;
|
||||
|
||||
// Only enable global interrupts when the counter
|
||||
// reaches 0 and the state of the global interrupt flag
|
||||
// was enabled when entering critical state */
|
||||
if((!cpu_irq_critical_section_counter) &&
|
||||
cpu_irq_prev_interrupt_state) {
|
||||
__DMB();
|
||||
__enable_irq();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// CONSTRUCTOR -------------------------------------------------------------
|
||||
|
||||
// Constructor initializes Adafruit_ZeroDMA basics but does NOT allocate a
|
||||
// DMA channel (that's done in allocate()) or start a job (that's done in
|
||||
// startJob()). This is because constructors in a global context are called
|
||||
// before a sketch's setup() function, which may have some other hardware
|
||||
// initialization of its own, don't want it clobbering us.
|
||||
Adafruit_ZeroDMA::Adafruit_ZeroDMA(void) {
|
||||
channel = 0xFF; // Channel not yet allocated
|
||||
jobStatus = DMA_STATUS_OK;
|
||||
hasDescriptors = false; // No descriptors allocated yet
|
||||
loopFlag = false;
|
||||
peripheralTrigger = 0; // Software trigger only by default
|
||||
triggerAction = DMA_TRIGGER_ACTON_TRANSACTION;
|
||||
memset(callback, 0, sizeof(callback));
|
||||
}
|
||||
|
||||
// TODO: add destructor? Should stop job, delete descriptors, free channel.
|
||||
|
||||
// INTERRUPT SERVICE ROUTINE -----------------------------------------------
|
||||
|
||||
// This is a C function that exists outside the Adafruit_ZeroDMA context.
|
||||
// DMA channel number is determined from the INTPEND register, from this
|
||||
// we get a ZeroDMA object pointer through the _dmaPtr[] array.
|
||||
// (It's done this way because jobStatus and callback[] are protected
|
||||
// elements in the ZeroDMA object -- we can't touch them in C, but the
|
||||
// next function after this, being part of the ZeroDMA class, can.)
|
||||
|
||||
#ifdef __SAMD51__
|
||||
void DMAC_0_Handler(void) {
|
||||
#else
|
||||
void DMAC_Handler(void) {
|
||||
#endif
|
||||
cpu_irq_enter_critical();
|
||||
|
||||
uint8_t channel = DMAC->INTPEND.bit.ID; // Channel # causing interrupt
|
||||
if(channel < DMAC_CH_NUM) {
|
||||
Adafruit_ZeroDMA *dma;
|
||||
if((dma = _dmaPtr[channel])) { // -> Channel's ZeroDMA object
|
||||
#ifdef __SAMD51__
|
||||
// Call IRQ handler with channel #
|
||||
dma->_IRQhandler(channel);
|
||||
#else
|
||||
DMAC->CHID.bit.ID = channel;
|
||||
// Call IRQ handler with interrupt flag(s)
|
||||
dma->_IRQhandler(DMAC->CHINTFLAG.reg);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
cpu_irq_leave_critical();
|
||||
}
|
||||
|
||||
#ifdef __SAMD51__
|
||||
void DMAC_1_Handler(void) __attribute__((weak, alias("DMAC_0_Handler")));
|
||||
void DMAC_2_Handler(void) __attribute__((weak, alias("DMAC_0_Handler")));
|
||||
void DMAC_3_Handler(void) __attribute__((weak, alias("DMAC_0_Handler")));
|
||||
void DMAC_4_Handler(void) __attribute__((weak, alias("DMAC_0_Handler")));
|
||||
#endif
|
||||
|
||||
void Adafruit_ZeroDMA::_IRQhandler(uint8_t flags) {
|
||||
#ifdef __SAMD51__
|
||||
// 'flags' is initially passed in as channel number,
|
||||
// from which we look up the actual interrupt flags...
|
||||
flags = DMAC->Channel[flags].CHINTFLAG.reg;
|
||||
#endif
|
||||
if(flags & DMAC_CHINTENCLR_TERR) {
|
||||
// Clear error flag
|
||||
#ifdef __SAMD51__
|
||||
DMAC->Channel[channel].CHINTFLAG.reg = DMAC_CHINTENCLR_TERR;
|
||||
#else
|
||||
DMAC->CHINTFLAG.reg = DMAC_CHINTENCLR_TERR;
|
||||
#endif
|
||||
jobStatus = DMA_STATUS_ERR_IO;
|
||||
if(callback[DMA_CALLBACK_TRANSFER_ERROR]) {
|
||||
callback[DMA_CALLBACK_TRANSFER_ERROR](this);
|
||||
}
|
||||
} else if(flags & DMAC_CHINTENCLR_TCMPL) {
|
||||
// Clear transfer complete flag
|
||||
#ifdef __SAMD51__
|
||||
DMAC->Channel[channel].CHINTFLAG.reg = DMAC_CHINTENCLR_TCMPL;
|
||||
#else
|
||||
DMAC->CHINTFLAG.reg = DMAC_CHINTENCLR_TCMPL;
|
||||
#endif
|
||||
jobStatus = DMA_STATUS_OK;
|
||||
if(callback[DMA_CALLBACK_TRANSFER_DONE]) {
|
||||
callback[DMA_CALLBACK_TRANSFER_DONE](this);
|
||||
}
|
||||
} else if(flags & DMAC_CHINTENCLR_SUSP) {
|
||||
// Clear channel suspend flag
|
||||
#ifdef __SAMD51__
|
||||
DMAC->Channel[channel].CHINTFLAG.reg = DMAC_CHINTENCLR_SUSP;
|
||||
#else
|
||||
DMAC->CHINTFLAG.reg = DMAC_CHINTENCLR_SUSP;
|
||||
#endif
|
||||
jobStatus = DMA_STATUS_SUSPEND;
|
||||
if(callback[DMA_CALLBACK_CHANNEL_SUSPEND]) {
|
||||
callback[DMA_CALLBACK_CHANNEL_SUSPEND](this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// DMA CHANNEL FUNCTIONS ---------------------------------------------------
|
||||
|
||||
// Allocates channel for ZeroDMA object
|
||||
ZeroDMAstatus Adafruit_ZeroDMA::allocate(void) {
|
||||
|
||||
if(channel < DMAC_CH_NUM) return DMA_STATUS_OK; // Already alloc'd!
|
||||
|
||||
// Find index of first free DMA channel. As currently written,
|
||||
// this "does not play well with others" as it assumes _channelMask
|
||||
// is the final arbiter of channels in use (this is true only within
|
||||
// this library -- but other DMA-driven code may have allocated its
|
||||
// own channel(s) elsewhere, sometimes with an equally broken
|
||||
// approach). A possible alternate approach, I haven't tested this
|
||||
// yet, might be to loop through each channel, set DMAC->CHID.bit.ID
|
||||
// and then test whether CHCTRLA.bit.ENABLE is set? But for now...
|
||||
for(channel=0; (channel < DMAC_CH_NUM) &&
|
||||
(_channelMask & (1 << channel)); channel++);
|
||||
// Doesn't help that code later does a software reset of the DMA
|
||||
// controller, which would blow out other DMA-using libraries
|
||||
// anyway (or they're just as likely to blow out this one).
|
||||
// I think it's just an all-or-nothing affair...use one library
|
||||
// for DMA everything, never mix and match.
|
||||
|
||||
if(channel >= DMAC_CH_NUM) { // No free channel!
|
||||
return DMA_STATUS_ERR_NOT_FOUND;
|
||||
}
|
||||
|
||||
cpu_irq_enter_critical();
|
||||
|
||||
if(!_channelMask) { // No channels allocated yet; initialize DMA!
|
||||
#if (SAML21) || (SAML22) || (SAMC20) || (SAMC21)
|
||||
PM->AHBMASK.bit.DMAC_ = 1;
|
||||
#elif defined(__SAMD51__)
|
||||
MCLK->AHBMASK.bit.DMAC_ = 1; // Initialize DMA clocks
|
||||
#else
|
||||
PM->AHBMASK.bit.DMAC_ = 1; // Initialize DMA clocks
|
||||
PM->APBBMASK.bit.DMAC_ = 1;
|
||||
#endif
|
||||
DMAC->CTRL.bit.DMAENABLE = 0; // Disable DMA controller
|
||||
DMAC->CTRL.bit.SWRST = 1; // Perform software reset
|
||||
|
||||
// Initialize descriptor list addresses
|
||||
DMAC->BASEADDR.bit.BASEADDR = (uint32_t)_descriptor;
|
||||
DMAC->WRBADDR.bit.WRBADDR = (uint32_t)_writeback;
|
||||
memset(_descriptor, 0, sizeof(_descriptor));
|
||||
memset(_writeback , 0, sizeof(_writeback));
|
||||
|
||||
// Re-enable DMA controller with all priority levels
|
||||
DMAC->CTRL.reg = DMAC_CTRL_DMAENABLE | DMAC_CTRL_LVLEN(0xF);
|
||||
|
||||
// Enable DMA interrupt at lowest priority
|
||||
#ifdef __SAMD51__
|
||||
IRQn_Type irqs[] = { DMAC_0_IRQn, DMAC_1_IRQn, DMAC_2_IRQn,
|
||||
DMAC_3_IRQn, DMAC_4_IRQn };
|
||||
for(uint8_t i=0; i<(sizeof irqs / sizeof irqs[0]); i++) {
|
||||
NVIC_EnableIRQ(irqs[i]);
|
||||
NVIC_SetPriority(irqs[i], (1<<__NVIC_PRIO_BITS)-1);
|
||||
}
|
||||
#else
|
||||
NVIC_EnableIRQ(DMAC_IRQn);
|
||||
NVIC_SetPriority(DMAC_IRQn, (1 << __NVIC_PRIO_BITS) - 1);
|
||||
#endif
|
||||
}
|
||||
|
||||
_channelMask |= 1 << channel; // Mark channel as allocated
|
||||
_dmaPtr[channel] = this; // Channel-index-to-object pointer
|
||||
|
||||
// Reset the allocated channel
|
||||
#ifdef __SAMD51__
|
||||
DMAC->Channel[channel].CHCTRLA.bit.ENABLE = 0;
|
||||
DMAC->Channel[channel].CHCTRLA.bit.SWRST = 1;
|
||||
#else
|
||||
DMAC->CHID.bit.ID = channel;
|
||||
DMAC->CHCTRLA.bit.ENABLE = 0;
|
||||
DMAC->CHCTRLA.bit.SWRST = 1;
|
||||
#endif
|
||||
|
||||
// Clear software trigger
|
||||
DMAC->SWTRIGCTRL.reg &= ~(1 << channel);
|
||||
|
||||
// Configure default behaviors
|
||||
#ifdef __SAMD51__
|
||||
DMAC->Channel[channel].CHPRILVL.bit.PRILVL = 0;
|
||||
DMAC->Channel[channel].CHCTRLA.bit.TRIGSRC = peripheralTrigger;
|
||||
DMAC->Channel[channel].CHCTRLA.bit.TRIGACT = triggerAction;
|
||||
DMAC->Channel[channel].CHCTRLA.bit.BURSTLEN =
|
||||
DMAC_CHCTRLA_BURSTLEN_SINGLE_Val; // Single-beat burst length
|
||||
#else
|
||||
DMAC->CHCTRLB.bit.LVL = 0;
|
||||
DMAC->CHCTRLB.bit.TRIGSRC = peripheralTrigger;
|
||||
DMAC->CHCTRLB.bit.TRIGACT = triggerAction;
|
||||
#endif
|
||||
|
||||
cpu_irq_leave_critical();
|
||||
|
||||
return DMA_STATUS_OK;
|
||||
}
|
||||
|
||||
void Adafruit_ZeroDMA::setPriority(dma_priority pri) const {
|
||||
#ifdef __SAMD51__
|
||||
DMAC->Channel[channel].CHPRILVL.bit.PRILVL = pri;
|
||||
#else
|
||||
DMAC->CHCTRLB.bit.LVL = pri;
|
||||
#endif
|
||||
}
|
||||
|
||||
// Deallocate DMA channel
|
||||
// TODO: should this delete/deallocate the descriptor list?
|
||||
ZeroDMAstatus Adafruit_ZeroDMA::free(void) {
|
||||
|
||||
ZeroDMAstatus status = DMA_STATUS_OK;
|
||||
|
||||
cpu_irq_enter_critical(); // jobStatus is volatile
|
||||
|
||||
if(jobStatus == DMA_STATUS_BUSY) {
|
||||
status = DMA_STATUS_BUSY; // Can't leave when busy
|
||||
} else if((channel < DMAC_CH_NUM) && (_channelMask & (1 << channel))) {
|
||||
// Valid in-use channel; release it
|
||||
_channelMask &= ~(1 << channel); // Clear bit
|
||||
if(!_channelMask) { // No more channels in use?
|
||||
#ifdef __SAMD51__
|
||||
NVIC_DisableIRQ(DMAC_0_IRQn); // Disable DMA interrupt
|
||||
DMAC->CTRL.bit.DMAENABLE = 0; // Disable DMA
|
||||
MCLK->AHBMASK.bit.DMAC_ = 0; // Disable DMA clock
|
||||
#else
|
||||
NVIC_DisableIRQ(DMAC_IRQn); // Disable DMA interrupt
|
||||
DMAC->CTRL.bit.DMAENABLE = 0; // Disable DMA
|
||||
PM->APBBMASK.bit.DMAC_ = 0; // Disable DMA clocks
|
||||
PM->AHBMASK.bit.DMAC_ = 0;
|
||||
#endif
|
||||
}
|
||||
_dmaPtr[channel] = NULL;
|
||||
channel = 0xFF;
|
||||
} else {
|
||||
status = DMA_STATUS_ERR_NOT_INITIALIZED; // Channel not in use
|
||||
}
|
||||
|
||||
cpu_irq_leave_critical();
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
// Start DMA transfer job. Channel and descriptors should be allocated
|
||||
// before calling this.
|
||||
ZeroDMAstatus Adafruit_ZeroDMA::startJob(void) {
|
||||
ZeroDMAstatus status = DMA_STATUS_OK;
|
||||
|
||||
cpu_irq_enter_critical(); // Job status is volatile
|
||||
|
||||
if(jobStatus == DMA_STATUS_BUSY) {
|
||||
status = DMA_STATUS_BUSY; // Resource is busy
|
||||
} else if(channel >= DMAC_CH_NUM) {
|
||||
status = DMA_STATUS_ERR_NOT_INITIALIZED; // Channel not in use
|
||||
} else if(!hasDescriptors || (_descriptor[channel].BTCNT.reg <= 0)) {
|
||||
status = DMA_STATUS_ERR_INVALID_ARG; // Bad transfer size
|
||||
} else {
|
||||
uint8_t i, interruptMask = 0;
|
||||
for(i=0; i<DMA_CALLBACK_N; i++) {
|
||||
if(callback[i]) interruptMask |= (1 << i);
|
||||
}
|
||||
jobStatus = DMA_STATUS_BUSY;
|
||||
#ifdef __SAMD51__
|
||||
DMAC->Channel[channel].CHINTENSET.reg =
|
||||
DMAC_CHINTENSET_MASK & interruptMask;
|
||||
DMAC->Channel[channel].CHINTENCLR.reg =
|
||||
DMAC_CHINTENCLR_MASK & ~interruptMask;
|
||||
DMAC->Channel[channel].CHCTRLA.bit.ENABLE = 1;
|
||||
#else
|
||||
DMAC->CHID.bit.ID = channel;
|
||||
DMAC->CHINTENSET.reg = DMAC_CHINTENSET_MASK & interruptMask;
|
||||
DMAC->CHINTENCLR.reg = DMAC_CHINTENCLR_MASK & ~interruptMask;
|
||||
DMAC->CHCTRLA.bit.ENABLE = 1; // Enable the transfer channel
|
||||
#endif
|
||||
}
|
||||
|
||||
cpu_irq_leave_critical();
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
// Set and enable callback function for ZeroDMA object. This can be called
|
||||
// before or after channel and/or descriptors are allocated, but needs
|
||||
// to be called before job is started.
|
||||
void Adafruit_ZeroDMA::setCallback(
|
||||
void (*cb)(Adafruit_ZeroDMA *), dma_callback_type type) {
|
||||
callback[type] = cb;
|
||||
}
|
||||
|
||||
// Suspend/resume don't quite do what I thought -- avoid using for now.
|
||||
void Adafruit_ZeroDMA::suspend(void) const {
|
||||
cpu_irq_enter_critical();
|
||||
#ifdef __SAMD51__
|
||||
DMAC->Channel[channel].CHCTRLB.reg |= DMAC_CHCTRLB_CMD_SUSPEND;
|
||||
#else
|
||||
DMAC->CHID.bit.ID = channel;
|
||||
DMAC->CHCTRLB.reg |= DMAC_CHCTRLB_CMD_SUSPEND;
|
||||
#endif
|
||||
cpu_irq_leave_critical();
|
||||
}
|
||||
|
||||
#define MAX_JOB_RESUME_COUNT 10000
|
||||
void Adafruit_ZeroDMA::resume(void) {
|
||||
cpu_irq_enter_critical(); // jobStatus is volatile
|
||||
if(jobStatus == DMA_STATUS_SUSPEND) {
|
||||
int count;
|
||||
uint32_t bitMask = 1 << channel;
|
||||
#ifdef __SAMD51__
|
||||
DMAC->Channel[channel].CHCTRLB.reg |= DMAC_CHCTRLB_CMD_RESUME;
|
||||
#else
|
||||
DMAC->CHID.bit.ID = channel;
|
||||
DMAC->CHCTRLB.reg |= DMAC_CHCTRLB_CMD_RESUME;
|
||||
#endif
|
||||
|
||||
for(count = 0; (count < MAX_JOB_RESUME_COUNT) &&
|
||||
!(DMAC->BUSYCH.reg & bitMask); count++);
|
||||
|
||||
jobStatus = (count < MAX_JOB_RESUME_COUNT) ?
|
||||
DMA_STATUS_BUSY : DMA_STATUS_ERR_TIMEOUT;
|
||||
}
|
||||
cpu_irq_leave_critical();
|
||||
}
|
||||
|
||||
// Abort is OK though.
|
||||
void Adafruit_ZeroDMA::abort(void) {
|
||||
if(channel <= DMAC_CH_NUM) {
|
||||
cpu_irq_enter_critical();
|
||||
#ifdef __SAMD51__
|
||||
DMAC->Channel[channel].CHCTRLA.reg = 0; // Disable channel
|
||||
#else
|
||||
DMAC->CHID.bit.ID = channel; // Select channel
|
||||
DMAC->CHCTRLA.reg = 0; // Disable
|
||||
#endif
|
||||
jobStatus = DMA_STATUS_ABORTED;
|
||||
cpu_irq_leave_critical();
|
||||
}
|
||||
}
|
||||
|
||||
// Set DMA peripheral trigger.
|
||||
// This can be done before or after channel is allocated.
|
||||
void Adafruit_ZeroDMA::setTrigger(uint8_t trigger) {
|
||||
peripheralTrigger = trigger; // Save value for allocate()
|
||||
|
||||
// If channel already allocated, configure peripheral trigger
|
||||
// (old lib required configure before alloc -- either way OK now)
|
||||
if(channel < DMAC_CH_NUM) {
|
||||
cpu_irq_enter_critical();
|
||||
#ifdef __SAMD51__
|
||||
DMAC->Channel[channel].CHCTRLA.bit.TRIGSRC = trigger;
|
||||
#else
|
||||
DMAC->CHID.bit.ID = channel;
|
||||
DMAC->CHCTRLB.bit.TRIGSRC = trigger;
|
||||
#endif
|
||||
cpu_irq_leave_critical();
|
||||
}
|
||||
}
|
||||
|
||||
// Set DMA trigger action.
|
||||
// This can be done before or after channel is allocated.
|
||||
void Adafruit_ZeroDMA::setAction(dma_transfer_trigger_action action) {
|
||||
triggerAction = action; // Save value for allocate()
|
||||
|
||||
// If channel already allocated, configure trigger action
|
||||
// (old lib required configure before alloc -- either way OK now)
|
||||
if(channel < DMAC_CH_NUM) {
|
||||
cpu_irq_enter_critical();
|
||||
#ifdef __SAMD51__
|
||||
DMAC->Channel[channel].CHCTRLA.bit.TRIGACT = action;
|
||||
#else
|
||||
DMAC->CHID.bit.ID = channel;
|
||||
DMAC->CHCTRLB.bit.TRIGACT = action;
|
||||
#endif
|
||||
cpu_irq_leave_critical();
|
||||
}
|
||||
}
|
||||
|
||||
// Issue software trigger. Channel must be allocated & descriptors added!
|
||||
void Adafruit_ZeroDMA::trigger(void) const {
|
||||
if((channel <= DMAC_CH_NUM) & hasDescriptors) {
|
||||
DMAC->SWTRIGCTRL.reg |= (1 << channel);
|
||||
}
|
||||
}
|
||||
|
||||
// Returns true if DMA transfer in progress.
|
||||
bool Adafruit_ZeroDMA::isActive(void) const {
|
||||
return _writeback[channel].BTCTRL.bit.VALID;
|
||||
}
|
||||
|
||||
// DMA DESCRIPTOR FUNCTIONS ------------------------------------------------
|
||||
|
||||
// Allocates a new DMA descriptor (if needed) and appends it to the
|
||||
// channel's descriptor list. Returns pointer to DmacDescriptor,
|
||||
// or NULL on various errors. You'll want to keep the pointer for
|
||||
// later if you need to modify or free the descriptor.
|
||||
// Channel must be allocated first!
|
||||
DmacDescriptor *Adafruit_ZeroDMA::addDescriptor(
|
||||
void *src,
|
||||
void *dst,
|
||||
uint32_t count,
|
||||
dma_beat_size size,
|
||||
bool srcInc,
|
||||
bool dstInc,
|
||||
uint32_t stepSize,
|
||||
bool stepSel) {
|
||||
|
||||
// Channel must be allocated first
|
||||
if(channel >= DMAC_CH_NUM) return NULL;
|
||||
|
||||
// Can't do while job's busy
|
||||
if(jobStatus == DMA_STATUS_BUSY) return NULL;
|
||||
|
||||
DmacDescriptor *desc;
|
||||
|
||||
// Scan descriptor list to find last entry. If an entry's
|
||||
// DESCADDR value is 0, that's the end of the list and it's
|
||||
// currently un-looped. If the DESCADDR value is the same
|
||||
// as the first entry, that's the end of the list and it's
|
||||
// looped. Either way, set the last entry's DESCADDR value
|
||||
// to the new descriptor, and the descriptor's own DESCADDR
|
||||
// will be set later either to 0 or the list head.
|
||||
if(hasDescriptors) {
|
||||
// DMA descriptors must be 128-bit (16 byte) aligned.
|
||||
// memalign() is considered 'obsolete' but it's replacements
|
||||
// (aligned_alloc() or posix_memalign()) are not currently
|
||||
// available in the version of ARM GCC in use, but this is,
|
||||
// so here we are.
|
||||
if(!(desc = (DmacDescriptor *)memalign(16, sizeof(DmacDescriptor)))) {
|
||||
return NULL;
|
||||
}
|
||||
DmacDescriptor *prev = &_descriptor[channel];
|
||||
while(prev->DESCADDR.reg &&
|
||||
(prev->DESCADDR.reg != (uint32_t)&_descriptor[channel])) {
|
||||
prev = (DmacDescriptor *)prev->DESCADDR.reg;
|
||||
}
|
||||
prev->DESCADDR.reg = (uint32_t)desc;
|
||||
} else {
|
||||
desc = &_descriptor[channel];
|
||||
}
|
||||
hasDescriptors = true;
|
||||
|
||||
uint8_t bytesPerBeat; // Beat transfer size IN BYTES
|
||||
switch(size) {
|
||||
default: bytesPerBeat = 1; break;
|
||||
case DMA_BEAT_SIZE_HWORD: bytesPerBeat = 2; break;
|
||||
case DMA_BEAT_SIZE_WORD: bytesPerBeat = 4; break;
|
||||
}
|
||||
|
||||
desc->BTCTRL.bit.VALID = true;
|
||||
desc->BTCTRL.bit.EVOSEL = DMA_EVENT_OUTPUT_DISABLE;
|
||||
desc->BTCTRL.bit.BLOCKACT = DMA_BLOCK_ACTION_NOACT;
|
||||
desc->BTCTRL.bit.BEATSIZE = size;
|
||||
desc->BTCTRL.bit.SRCINC = srcInc;
|
||||
desc->BTCTRL.bit.DSTINC = dstInc;
|
||||
desc->BTCTRL.bit.STEPSEL = stepSel;
|
||||
desc->BTCTRL.bit.STEPSIZE = stepSize;
|
||||
desc->BTCNT.reg = count;
|
||||
desc->SRCADDR.reg = (uint32_t)src;
|
||||
|
||||
if(srcInc) {
|
||||
if(stepSel) {
|
||||
desc->SRCADDR.reg += bytesPerBeat * count * (1 << stepSize);
|
||||
} else {
|
||||
desc->SRCADDR.reg += bytesPerBeat * count;
|
||||
}
|
||||
}
|
||||
|
||||
desc->DSTADDR.reg = (uint32_t)dst;
|
||||
|
||||
if(dstInc) {
|
||||
if(!stepSel) {
|
||||
desc->DSTADDR.reg += bytesPerBeat * count * (1 << stepSize);
|
||||
} else {
|
||||
desc->DSTADDR.reg += bytesPerBeat * count;
|
||||
}
|
||||
}
|
||||
|
||||
desc->DESCADDR.reg = loopFlag ? (uint32_t)&_descriptor[channel] : 0;
|
||||
|
||||
return desc;
|
||||
}
|
||||
|
||||
// Modify DMA descriptor with a new source address, destination address &
|
||||
// block transfer count. All other attributes (including increment enables,
|
||||
// etc.) are unchanged. Mostly for changing the data being pushed to a
|
||||
// peripheral (DAC, SPI, whatev.)
|
||||
void Adafruit_ZeroDMA::changeDescriptor(DmacDescriptor *desc,
|
||||
void *src, void *dst, uint32_t count) {
|
||||
|
||||
uint8_t bytesPerBeat; // Beat transfer size IN BYTES
|
||||
switch(desc->BTCTRL.bit.BEATSIZE) {
|
||||
default: bytesPerBeat = 1; break;
|
||||
case DMA_BEAT_SIZE_HWORD: bytesPerBeat = 2; break;
|
||||
case DMA_BEAT_SIZE_WORD: bytesPerBeat = 4; break;
|
||||
}
|
||||
|
||||
if(count) desc->BTCNT.reg = count;
|
||||
|
||||
if(src) {
|
||||
desc->SRCADDR.reg = (uint32_t)src;
|
||||
if(desc->BTCTRL.bit.SRCINC) {
|
||||
if(desc->BTCTRL.bit.STEPSEL) {
|
||||
desc->SRCADDR.reg += desc->BTCNT.reg *
|
||||
bytesPerBeat * (1 << desc->BTCTRL.bit.STEPSIZE);
|
||||
} else {
|
||||
desc->SRCADDR.reg += desc->BTCNT.reg * bytesPerBeat;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(dst) {
|
||||
desc->DSTADDR.reg = (uint32_t)dst;
|
||||
if(desc->BTCTRL.bit.DSTINC) {
|
||||
if(!desc->BTCTRL.bit.STEPSEL) {
|
||||
desc->DSTADDR.reg += desc->BTCNT.reg *
|
||||
bytesPerBeat * (1 << desc->BTCTRL.bit.STEPSIZE);
|
||||
} else {
|
||||
desc->DSTADDR.reg += desc->BTCNT.reg * bytesPerBeat;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// I think this code is here by accident -- disabling for now.
|
||||
#if 0
|
||||
cpu_irq_enter_critical();
|
||||
jobStatus = DMA_STATUS_OK;
|
||||
#ifdef __SAMD51__
|
||||
DMAC->Channel[channel].CHCTRLA.bit.ENABLE = 1;
|
||||
#else
|
||||
DMAC->CHID.bit.ID = channel;
|
||||
DMAC->CHCTRLA.reg |= DMAC_CHCTRLA_ENABLE;
|
||||
#endif
|
||||
cpu_irq_leave_critical();
|
||||
#endif
|
||||
}
|
||||
|
||||
// TODO: delete descriptor, delete whole descriptor chain
|
||||
|
||||
// Select whether channel's descriptor list should repeat or not.
|
||||
// This can be done before or after channel & any descriptors are allocated.
|
||||
void Adafruit_ZeroDMA::loop(boolean flag) {
|
||||
// The loop selection is 'sticky' -- that is, you can enable or
|
||||
// disable looping before a descriptor list is built, or after
|
||||
// the fact. This requires some extra steps in the library code
|
||||
// but avoids a must-do-in-X-order constraint on user.
|
||||
loopFlag = flag;
|
||||
|
||||
if(hasDescriptors) { // Descriptor list already started?
|
||||
// Scan descriptor list to find last entry. If an entry's
|
||||
// DESCADDR value is 0, that's the end of the list and it's
|
||||
// currently un-looped. If the DESCADDR value is the same
|
||||
// as the first entry, that's the end of the list and it's
|
||||
// already looped.
|
||||
DmacDescriptor *desc = &_descriptor[channel];
|
||||
while(desc->DESCADDR.reg &&
|
||||
(desc->DESCADDR.reg != (uint32_t)&_descriptor[channel])) {
|
||||
desc = (DmacDescriptor *)desc->DESCADDR.reg;
|
||||
}
|
||||
// Loop or unloop descriptor list as appropriate
|
||||
desc->DESCADDR.reg = loopFlag ? (uint32_t)&_descriptor[channel] : 0;
|
||||
}
|
||||
}
|
||||
|
||||
// MISCELLANY --------------------------------------------------------------
|
||||
|
||||
void Adafruit_ZeroDMA::printStatus(ZeroDMAstatus s) const {
|
||||
if(s == DMA_STATUS_JOBSTATUS) s = jobStatus;
|
||||
Serial.print("Status: ");
|
||||
switch(s) {
|
||||
case DMA_STATUS_OK:
|
||||
Serial.println("OK");
|
||||
break;
|
||||
case DMA_STATUS_ERR_NOT_FOUND:
|
||||
Serial.println("NOT FOUND");
|
||||
break;
|
||||
case DMA_STATUS_ERR_NOT_INITIALIZED:
|
||||
Serial.println("NOT INITIALIZED");
|
||||
break;
|
||||
case DMA_STATUS_ERR_INVALID_ARG:
|
||||
Serial.println("INVALID ARGUMENT");
|
||||
break;
|
||||
case DMA_STATUS_ERR_IO:
|
||||
Serial.println("IO ERROR");
|
||||
break;
|
||||
case DMA_STATUS_ERR_TIMEOUT:
|
||||
Serial.println("TIMEOUT");
|
||||
break;
|
||||
case DMA_STATUS_BUSY:
|
||||
Serial.println("BUSY");
|
||||
break;
|
||||
case DMA_STATUS_SUSPEND:
|
||||
Serial.println("SUSPENDED");
|
||||
break;
|
||||
case DMA_STATUS_ABORTED:
|
||||
Serial.println("ABORTED");
|
||||
break;
|
||||
default:
|
||||
Serial.print("Unknown 0x");
|
||||
Serial.println((int)s);
|
||||
break;
|
||||
}
|
||||
}
|
||||
66
libraries/Adafruit_ZeroDMA/Adafruit_ZeroDMA.h
Normal file
66
libraries/Adafruit_ZeroDMA/Adafruit_ZeroDMA.h
Normal file
|
|
@ -0,0 +1,66 @@
|
|||
#ifndef _ADAFRUIT_ZERODMA_H_
|
||||
#define _ADAFRUIT_ZERODMA_H_
|
||||
|
||||
#include "Arduino.h"
|
||||
#include "utility/dma.h"
|
||||
|
||||
// Status codes returned by some DMA functions and/or held in
|
||||
// a channel's jobStatus variable.
|
||||
enum ZeroDMAstatus {
|
||||
DMA_STATUS_OK = 0,
|
||||
DMA_STATUS_ERR_NOT_FOUND,
|
||||
DMA_STATUS_ERR_NOT_INITIALIZED,
|
||||
DMA_STATUS_ERR_INVALID_ARG,
|
||||
DMA_STATUS_ERR_IO,
|
||||
DMA_STATUS_ERR_TIMEOUT,
|
||||
DMA_STATUS_BUSY,
|
||||
DMA_STATUS_SUSPEND,
|
||||
DMA_STATUS_ABORTED,
|
||||
DMA_STATUS_JOBSTATUS = -1 // For printStatus() function
|
||||
};
|
||||
|
||||
class Adafruit_ZeroDMA {
|
||||
public:
|
||||
Adafruit_ZeroDMA(void);
|
||||
|
||||
// DMA channel functions
|
||||
ZeroDMAstatus allocate(void), // Allocates DMA channel
|
||||
startJob(void),
|
||||
free(void); // Deallocates DMA channel
|
||||
void trigger(void) const,
|
||||
setTrigger(uint8_t trigger),
|
||||
setAction(dma_transfer_trigger_action action),
|
||||
setCallback(void (*callback)(Adafruit_ZeroDMA *) = NULL,
|
||||
dma_callback_type type = DMA_CALLBACK_TRANSFER_DONE),
|
||||
loop(boolean flag),
|
||||
suspend(void) const,
|
||||
resume(void),
|
||||
abort(void),
|
||||
setPriority(dma_priority pri) const,
|
||||
printStatus(ZeroDMAstatus s = DMA_STATUS_JOBSTATUS) const;
|
||||
uint8_t getChannel(void) const { return channel; }
|
||||
|
||||
// DMA descriptor functions
|
||||
DmacDescriptor *addDescriptor(void *src, void *dst, uint32_t count = 0,
|
||||
dma_beat_size size = DMA_BEAT_SIZE_BYTE,
|
||||
bool srcInc = true, bool dstInc = true,
|
||||
uint32_t stepSize = DMA_ADDRESS_INCREMENT_STEP_SIZE_1,
|
||||
bool stepSel = DMA_STEPSEL_DST);
|
||||
void changeDescriptor(DmacDescriptor *d, void *src = NULL,
|
||||
void *dst = NULL, uint32_t count = 0);
|
||||
bool isActive(void) const;
|
||||
|
||||
void _IRQhandler(uint8_t flags); // DO NOT TOUCH
|
||||
|
||||
|
||||
protected:
|
||||
uint8_t channel;
|
||||
volatile enum ZeroDMAstatus jobStatus;
|
||||
bool hasDescriptors;
|
||||
bool loopFlag;
|
||||
uint8_t peripheralTrigger;
|
||||
dma_transfer_trigger_action triggerAction;
|
||||
void (*callback[DMA_CALLBACK_N])(Adafruit_ZeroDMA *);
|
||||
};
|
||||
|
||||
#endif // _ADAFRUIT_ZERODMA_H_
|
||||
22
libraries/Adafruit_ZeroDMA/LICENSE
Normal file
22
libraries/Adafruit_ZeroDMA/LICENSE
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2016 Adafruit Industries
|
||||
|
||||
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.
|
||||
|
||||
6
libraries/Adafruit_ZeroDMA/README.md
Normal file
6
libraries/Adafruit_ZeroDMA/README.md
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
# Adafruit_ZeroDMA
|
||||
DMA helper/wrapped for ATSAMD21 such as Arduino Zero & Feather M0
|
||||
|
||||
Current version of this library no longer requires Adafruit_ASFcore as a prerequisite. However...IT BREAKS COMPATIBILITY WITH PRIOR VERSIONS. Function names, calling sequence and return types/values have changed. See examples!
|
||||
|
||||
Item(s) in 'utility' directory are much pared-down derivatives of Atmel ASFcore 3 files. Please keep their original copyright and license intact when editing.
|
||||
|
|
@ -0,0 +1,95 @@
|
|||
// Simple ZeroDMA example -- an equivalent to the memcpy() function.
|
||||
// Decause it uses DMA, unlike memcpy(), your code could be doing other
|
||||
// things simultaneously while the copy operation runs.
|
||||
|
||||
#include <Adafruit_ZeroDMA.h>
|
||||
#include "utility/dma.h"
|
||||
|
||||
Adafruit_ZeroDMA myDMA;
|
||||
ZeroDMAstatus stat; // DMA status codes returned by some functions
|
||||
|
||||
// The memory we'll be moving:
|
||||
#define DATA_LENGTH 1024
|
||||
uint8_t source_memory[DATA_LENGTH],
|
||||
destination_memory[DATA_LENGTH];
|
||||
|
||||
volatile bool transfer_is_done = false; // Done yet?
|
||||
|
||||
// Callback for end-of-DMA-transfer
|
||||
void dma_callback(Adafruit_ZeroDMA *dma) {
|
||||
(void)dma; // avoid compiler warning about unused function parameter
|
||||
transfer_is_done = true;
|
||||
}
|
||||
|
||||
void setup() {
|
||||
uint32_t t;
|
||||
pinMode(LED_BUILTIN, OUTPUT); // Onboard LED can be used for precise
|
||||
digitalWrite(LED_BUILTIN, LOW); // benchmarking with an oscilloscope
|
||||
Serial.begin(115200);
|
||||
while(!Serial); // Wait for Serial monitor before continuing
|
||||
|
||||
Serial.println("DMA test: memory copy");
|
||||
|
||||
Serial.print("Allocating DMA channel...");
|
||||
stat = myDMA.allocate();
|
||||
myDMA.printStatus(stat);
|
||||
|
||||
Serial.println("Setting up transfer");
|
||||
myDMA.addDescriptor(source_memory, destination_memory, DATA_LENGTH);
|
||||
|
||||
Serial.println("Adding callback");
|
||||
// register_callback() can optionally take a second argument
|
||||
// (callback type), default is DMA_CALLBACK_TRANSFER_DONE
|
||||
myDMA.setCallback(dma_callback);
|
||||
|
||||
// Fill the source buffer with incrementing bytes, dest buf with 0's
|
||||
for(uint32_t i=0; i<DATA_LENGTH; i++) source_memory[i] = i;
|
||||
memset(destination_memory, 0, DATA_LENGTH);
|
||||
|
||||
// Show the destination buffer is empty before transfer
|
||||
Serial.println("Destination buffer before transfer:");
|
||||
dump();
|
||||
|
||||
Serial.println("Starting transfer job");
|
||||
stat = myDMA.startJob();
|
||||
myDMA.printStatus(stat);
|
||||
|
||||
Serial.println("Triggering DMA transfer...");
|
||||
t = micros();
|
||||
digitalWrite(LED_BUILTIN, HIGH);
|
||||
myDMA.trigger();
|
||||
|
||||
// Your code could do other things here while copy happens!
|
||||
|
||||
while(!transfer_is_done); // Chill until DMA transfer completes
|
||||
|
||||
digitalWrite(LED_BUILTIN, LOW);
|
||||
t = micros() - t; // Elapsed time
|
||||
|
||||
Serial.print("Done! ");
|
||||
Serial.print(t);
|
||||
Serial.println(" microseconds");
|
||||
|
||||
Serial.println("Destination buffer after transfer:");
|
||||
dump();
|
||||
|
||||
// Now repeat the same operation, but 'manually' using memcpy() (not DMA):
|
||||
t = micros();
|
||||
digitalWrite(LED_BUILTIN, HIGH);
|
||||
memcpy(destination_memory, source_memory, DATA_LENGTH);
|
||||
digitalWrite(LED_BUILTIN, LOW);
|
||||
t = micros() - t; // Elapsed time
|
||||
Serial.print("Same operation without DMA: ");
|
||||
Serial.print(t);
|
||||
Serial.println(" microseconds");
|
||||
}
|
||||
|
||||
// Show contents of destination_memory[] array
|
||||
void dump() {
|
||||
for(uint32_t i=0; i<DATA_LENGTH; i++) {
|
||||
Serial.print(destination_memory[i], HEX); Serial.print(' ');
|
||||
if ((i & 15) == 15) Serial.println();
|
||||
}
|
||||
}
|
||||
|
||||
void loop() { }
|
||||
|
|
@ -0,0 +1,98 @@
|
|||
// DMA-based SPI buffer write. This is transmit-only as written, i.e.
|
||||
// not equivalent to Arduino's SPI.transfer() which both sends and
|
||||
// receives a single byte or word. Also, this is single-buffered to
|
||||
// demonstrate a simple SPI write case. See zerodma_spi2.ino for an
|
||||
// example using double buffering (2 buffers alternating fill & transmit).
|
||||
|
||||
#include <SPI.h>
|
||||
#include <Adafruit_ZeroDMA.h>
|
||||
#include "utility/dma.h"
|
||||
|
||||
Adafruit_ZeroDMA myDMA;
|
||||
ZeroDMAstatus stat; // DMA status codes returned by some functions
|
||||
|
||||
// The memory we'll be issuing to SPI:
|
||||
#define DATA_LENGTH 2048
|
||||
uint8_t source_memory[DATA_LENGTH];
|
||||
|
||||
volatile bool transfer_is_done = false; // Done yet?
|
||||
|
||||
// Callback for end-of-DMA-transfer
|
||||
void dma_callback(Adafruit_ZeroDMA *dma) {
|
||||
(void)dma; // avoid compiler warning about unused parameter
|
||||
transfer_is_done = true;
|
||||
}
|
||||
|
||||
void setup() {
|
||||
uint32_t t;
|
||||
pinMode(LED_BUILTIN, OUTPUT); // Onboard LED can be used for precise
|
||||
digitalWrite(LED_BUILTIN, LOW); // benchmarking with an oscilloscope
|
||||
Serial.begin(115200);
|
||||
while(!Serial); // Wait for Serial monitor before continuing
|
||||
|
||||
Serial.println("DMA test: SPI data out");
|
||||
|
||||
SPI.begin();
|
||||
|
||||
Serial.println("Configuring DMA trigger");
|
||||
#ifdef __SAMD51__
|
||||
// SERCOM2 is the 'native' SPI SERCOM on Metro M4
|
||||
myDMA.setTrigger(SERCOM2_DMAC_ID_TX);
|
||||
#else
|
||||
// SERCOM4 is the 'native' SPI SERCOM on most M0 boards
|
||||
myDMA.setTrigger(SERCOM4_DMAC_ID_TX);
|
||||
#endif
|
||||
myDMA.setAction(DMA_TRIGGER_ACTON_BEAT);
|
||||
|
||||
Serial.print("Allocating DMA channel...");
|
||||
stat = myDMA.allocate();
|
||||
myDMA.printStatus(stat);
|
||||
|
||||
Serial.println("Setting up transfer");
|
||||
myDMA.addDescriptor(
|
||||
source_memory, // move data from here
|
||||
#ifdef __SAMD51__
|
||||
(void *)(&SERCOM2->SPI.DATA.reg), // to here (M4)
|
||||
#else
|
||||
(void *)(&SERCOM4->SPI.DATA.reg), // to here (M0)
|
||||
#endif
|
||||
DATA_LENGTH, // this many...
|
||||
DMA_BEAT_SIZE_BYTE, // bytes/hword/words
|
||||
true, // increment source addr?
|
||||
false); // increment dest addr?
|
||||
|
||||
Serial.println("Adding callback");
|
||||
// register_callback() can optionally take a second argument
|
||||
// (callback type), default is DMA_CALLBACK_TRANSFER_DONE
|
||||
myDMA.setCallback(dma_callback);
|
||||
|
||||
// Fill the source buffer with incrementing bytes
|
||||
for(uint32_t i=0; i<DATA_LENGTH; i++) source_memory[i] = i;
|
||||
|
||||
// Start SPI transaction at 12 MHz
|
||||
SPI.beginTransaction(SPISettings(12000000, MSBFIRST, SPI_MODE0));
|
||||
|
||||
Serial.println("Starting transfer job");
|
||||
t = micros();
|
||||
digitalWrite(LED_BUILTIN, HIGH);
|
||||
|
||||
// Because we've configured a peripheral trigger (SPI), there's
|
||||
// no need to manually trigger transfer, it starts up on its own.
|
||||
stat = myDMA.startJob();
|
||||
|
||||
// Your code could do other things here while SPI write happens!
|
||||
|
||||
while(!transfer_is_done); // Chill until DMA transfer completes
|
||||
|
||||
digitalWrite(LED_BUILTIN, LOW);
|
||||
t = micros() - t; // Elapsed time
|
||||
|
||||
SPI.endTransaction();
|
||||
myDMA.printStatus(stat); // Results of start_transfer_job()
|
||||
|
||||
Serial.print("Done! ");
|
||||
Serial.print(t);
|
||||
Serial.println(" microseconds");
|
||||
}
|
||||
|
||||
void loop() { }
|
||||
|
|
@ -0,0 +1,104 @@
|
|||
// Double-buffered DMA on auxiliary SPI peripheral on pins 11/12/13.
|
||||
// Continuously alternates between two data buffers...one is filled
|
||||
// with new data as the other is being transmitted.
|
||||
|
||||
#include <SPI.h>
|
||||
#include <Adafruit_ZeroDMA.h>
|
||||
#include "utility/dma.h"
|
||||
#include "wiring_private.h" // pinPeripheral() function
|
||||
|
||||
// Declare our own SPI peripheral 'mySPI' on pins 11/12/13:
|
||||
// (Do not call this SPI1; Arduino Zero and Metro M0 already
|
||||
// have an SPI1 (the EDBG interface) and it won't compile.)
|
||||
SPIClass mySPI(
|
||||
&sercom1, // -> Sercom peripheral
|
||||
34, // MISO pin (also digital pin 12)
|
||||
37, // SCK pin (also digital pin 13)
|
||||
35, // MOSI pin (also digital pin 11)
|
||||
SPI_PAD_0_SCK_1, // TX pad (MOSI, SCK pads)
|
||||
SERCOM_RX_PAD_3); // RX pad (MISO pad)
|
||||
|
||||
Adafruit_ZeroDMA myDMA;
|
||||
ZeroDMAstatus stat; // DMA status codes returned by some functions
|
||||
|
||||
// Data we'll issue to mySPI. There are TWO buffers; one being
|
||||
// filled with new data while the other's being transmitted in
|
||||
// the background.
|
||||
#define DATA_LENGTH 512
|
||||
uint8_t source_memory[2][DATA_LENGTH],
|
||||
buffer_being_filled = 0, // Index of 'filling' buffer
|
||||
buffer_value = 0; // Value of fill
|
||||
|
||||
volatile bool transfer_is_done = true; // Done yet?
|
||||
|
||||
// Callback for end-of-DMA-transfer
|
||||
void dma_callback(Adafruit_ZeroDMA *dma) {
|
||||
(void)dma; // avoid compiler warning about unused parameter
|
||||
transfer_is_done = true;
|
||||
}
|
||||
|
||||
DmacDescriptor *desc; // DMA descriptor address (so we can change contents)
|
||||
|
||||
void setup() {
|
||||
Serial.begin(115200);
|
||||
while(!Serial); // Wait for Serial monitor before continuing
|
||||
|
||||
Serial.println("DMA test: SPI data out");
|
||||
|
||||
mySPI.begin();
|
||||
// Assign pins 11, 12, 13 to SERCOM functionality
|
||||
pinPeripheral(11, PIO_SERCOM);
|
||||
pinPeripheral(12, PIO_SERCOM);
|
||||
pinPeripheral(13, PIO_SERCOM);
|
||||
|
||||
// Configure DMA for SERCOM1 (our 'mySPI' port on 11/12/13)
|
||||
Serial.println("Configuring DMA trigger");
|
||||
myDMA.setTrigger(SERCOM1_DMAC_ID_TX);
|
||||
myDMA.setAction(DMA_TRIGGER_ACTON_BEAT);
|
||||
|
||||
Serial.print("Allocating DMA channel...");
|
||||
stat = myDMA.allocate();
|
||||
myDMA.printStatus(stat);
|
||||
|
||||
desc = myDMA.addDescriptor(
|
||||
source_memory[buffer_being_filled], // move data from here
|
||||
(void *)(&SERCOM1->SPI.DATA.reg), // to here
|
||||
DATA_LENGTH, // this many...
|
||||
DMA_BEAT_SIZE_BYTE, // bytes/hword/words
|
||||
true, // increment source addr?
|
||||
false); // increment dest addr?
|
||||
|
||||
Serial.println("Adding callback");
|
||||
// register_callback() can optionally take a second argument
|
||||
// (callback type), default is DMA_CALLBACK_TRANSFER_DONE
|
||||
myDMA.setCallback(dma_callback);
|
||||
}
|
||||
|
||||
void loop() {
|
||||
// Fill buffer with new data. The other buffer might
|
||||
// still be transmitting in the background via DMA.
|
||||
memset(source_memory[buffer_being_filled], buffer_value, DATA_LENGTH);
|
||||
|
||||
// Wait for prior transfer to complete before starting new one...
|
||||
Serial.print("Waiting on prior transfer...");
|
||||
while(!transfer_is_done) Serial.write('.');
|
||||
mySPI.endTransaction();
|
||||
Serial.println("Done!");
|
||||
|
||||
// Modify the DMA descriptor using the newly-filled buffer as source...
|
||||
myDMA.changeDescriptor(desc, // DMA descriptor address
|
||||
source_memory[buffer_being_filled]); // New src; dst & count don't change
|
||||
|
||||
// Begin new transfer...
|
||||
Serial.println("Starting new transfer job");
|
||||
mySPI.beginTransaction(SPISettings(12000000, MSBFIRST, SPI_MODE0));
|
||||
transfer_is_done = false; // Reset 'done' flag
|
||||
stat = myDMA.startJob(); // Go!
|
||||
myDMA.printStatus(stat);
|
||||
|
||||
// Switch buffer indices so the alternate buffer is filled/xfer'd
|
||||
// on the next pass.
|
||||
buffer_being_filled = 1 - buffer_being_filled;
|
||||
buffer_value++;
|
||||
}
|
||||
|
||||
9
libraries/Adafruit_ZeroDMA/library.properties
Normal file
9
libraries/Adafruit_ZeroDMA/library.properties
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
name=Adafruit Zero DMA Library
|
||||
version=1.0.4
|
||||
author=Adafruit
|
||||
maintainer=Adafruit <info@adafruit.com>
|
||||
sentence=DMA helper/wrapped for ATSAMD21 such as Arduino Zero & Feather M0
|
||||
paragraph=DMA helper/wrapped for ATSAMD21 such as Arduino Zero & Feather M0
|
||||
category=Signal Input/Output
|
||||
url=https://github.com/adafruit/Adafruit_ZeroDMA
|
||||
architectures=samd
|
||||
145
libraries/Adafruit_ZeroDMA/utility/dma.h
Normal file
145
libraries/Adafruit_ZeroDMA/utility/dma.h
Normal file
|
|
@ -0,0 +1,145 @@
|
|||
/**
|
||||
* \file
|
||||
*
|
||||
* \brief SAM Direct Memory Access Controller Driver
|
||||
*
|
||||
* Copyright (C) 2014-2015 Atmel Corporation. All rights reserved.
|
||||
*
|
||||
* \asf_license_start
|
||||
*
|
||||
* \page License
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* 3. The name of Atmel may not be used to endorse or promote products derived
|
||||
* from this software without specific prior written permission.
|
||||
*
|
||||
* 4. This software may only be redistributed and used in connection with an
|
||||
* Atmel microcontroller product.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED
|
||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
|
||||
* EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR
|
||||
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
||||
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* \asf_license_stop
|
||||
*
|
||||
*/
|
||||
/*
|
||||
* Support and FAQ: visit <a href="http://www.atmel.com/design-support/">Atmel Support</a>
|
||||
*/
|
||||
#ifndef DMA_H_INCLUDED
|
||||
#define DMA_H_INCLUDED
|
||||
|
||||
// THIS IS A PARED-DOWN VERSION OF DMA.H FROM ATMEL ASFCORE 3.
|
||||
// Please keep original copyright and license intact!
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#if (SAML21) || (SAML22) || (SAMC20) || (SAMC21) || defined(__DOXYGEN__) || defined(__SAMD51__)
|
||||
#define FEATURE_DMA_CHANNEL_STANDBY
|
||||
#endif
|
||||
|
||||
enum dma_transfer_trigger_action{
|
||||
#ifdef __SAMD51__
|
||||
// SAMD51 has a 'burst' transfer which can be set to one
|
||||
// beat to accomplish same idea as SAMD21's 'beat' transfer.
|
||||
// Trigger name is ACTON_BEAT for backward compatibility.
|
||||
DMA_TRIGGER_ACTON_BLOCK = DMAC_CHCTRLA_TRIGACT_BLOCK_Val,
|
||||
DMA_TRIGGER_ACTON_BEAT = DMAC_CHCTRLA_TRIGACT_BURST_Val,
|
||||
DMA_TRIGGER_ACTON_TRANSACTION = DMAC_CHCTRLA_TRIGACT_TRANSACTION_Val,
|
||||
#else
|
||||
DMA_TRIGGER_ACTON_BLOCK = DMAC_CHCTRLB_TRIGACT_BLOCK_Val,
|
||||
DMA_TRIGGER_ACTON_BEAT = DMAC_CHCTRLB_TRIGACT_BEAT_Val,
|
||||
DMA_TRIGGER_ACTON_TRANSACTION = DMAC_CHCTRLB_TRIGACT_TRANSACTION_Val,
|
||||
#endif
|
||||
};
|
||||
|
||||
enum dma_callback_type {
|
||||
// First item here is for any transfer errors. A transfer error is
|
||||
// flagged if a bus error is detected during an AHB access or when
|
||||
// the DMAC fetches an invalid descriptor
|
||||
DMA_CALLBACK_TRANSFER_ERROR,
|
||||
DMA_CALLBACK_TRANSFER_DONE,
|
||||
DMA_CALLBACK_CHANNEL_SUSPEND,
|
||||
DMA_CALLBACK_N, // Number of available callbacks
|
||||
};
|
||||
|
||||
enum dma_beat_size {
|
||||
DMA_BEAT_SIZE_BYTE = 0, // 8-bit
|
||||
DMA_BEAT_SIZE_HWORD, // 16-bit
|
||||
DMA_BEAT_SIZE_WORD, // 32-bit
|
||||
};
|
||||
|
||||
enum dma_event_output_selection {
|
||||
DMA_EVENT_OUTPUT_DISABLE = 0, // Disable event generation
|
||||
DMA_EVENT_OUTPUT_BLOCK, // Event strobe when block xfer complete
|
||||
DMA_EVENT_OUTPUT_RESERVED,
|
||||
DMA_EVENT_OUTPUT_BEAT, // Event strobe when beat xfer complete
|
||||
};
|
||||
|
||||
enum dma_block_action {
|
||||
DMA_BLOCK_ACTION_NOACT = 0,
|
||||
// Channel in normal operation and sets transfer complete interrupt
|
||||
// flag after block transfer
|
||||
DMA_BLOCK_ACTION_INT,
|
||||
// Trigger channel suspend after block transfer and sets channel
|
||||
// suspend interrupt flag once the channel is suspended
|
||||
DMA_BLOCK_ACTION_SUSPEND,
|
||||
// Sets transfer complete interrupt flag after a block transfer and
|
||||
// trigger channel suspend. The channel suspend interrupt flag will
|
||||
// be set once the channel is suspended.
|
||||
DMA_BLOCK_ACTION_BOTH,
|
||||
};
|
||||
|
||||
// DMA step selection. This bit determines whether the step size setting
|
||||
// is applied to source or destination address.
|
||||
enum dma_step_selection {
|
||||
DMA_STEPSEL_DST = 0,
|
||||
DMA_STEPSEL_SRC,
|
||||
};
|
||||
|
||||
// Address increment step size. These bits select the address increment step
|
||||
// size. The setting apply to source or destination address, depending on
|
||||
// STEPSEL setting.
|
||||
enum dma_address_increment_stepsize {
|
||||
DMA_ADDRESS_INCREMENT_STEP_SIZE_1 = 0, // beat size * 1
|
||||
DMA_ADDRESS_INCREMENT_STEP_SIZE_2, // beat size * 2
|
||||
DMA_ADDRESS_INCREMENT_STEP_SIZE_4, // beat size * 4
|
||||
DMA_ADDRESS_INCREMENT_STEP_SIZE_8, // etc...
|
||||
DMA_ADDRESS_INCREMENT_STEP_SIZE_16,
|
||||
DMA_ADDRESS_INCREMENT_STEP_SIZE_32,
|
||||
DMA_ADDRESS_INCREMENT_STEP_SIZE_64,
|
||||
DMA_ADDRESS_INCREMENT_STEP_SIZE_128,
|
||||
};
|
||||
|
||||
// higher numbers are higher priority
|
||||
enum dma_priority {
|
||||
DMA_PRIORITY_0, // lowest (default)
|
||||
DMA_PRIORITY_1,
|
||||
DMA_PRIORITY_2,
|
||||
DMA_PRIORITY_3, // highest
|
||||
};
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // DMA_H_INCLUDED
|
||||
1
libraries/CI_Tests/CI_Tests.h
Normal file
1
libraries/CI_Tests/CI_Tests.h
Normal file
|
|
@ -0,0 +1 @@
|
|||
// fake empty header file to make Arduino IDE happy
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
#include <arm_math.h>
|
||||
|
||||
arm_rfft_fast_instance_f32 plan;
|
||||
|
||||
void setup() {
|
||||
arm_rfft_fast_init_f32(&plan, 256);
|
||||
}
|
||||
|
||||
void loop() {
|
||||
float in[256] = { 0 }, out[256] = { 0 };
|
||||
arm_rfft_fast_f32(&plan, in, out, 0);
|
||||
}
|
||||
0
libraries/I2S/examples/SimpleTone/.metro_m0.test.only
Normal file
0
libraries/I2S/examples/SimpleTone/.metro_m0.test.only
Normal file
0
libraries/SDU/examples/Usage/.metro_m0.test.only
Normal file
0
libraries/SDU/examples/Usage/.metro_m0.test.only
Normal file
0
libraries/SDU/extras/SDUBoot/.metro_m0.test.only
Normal file
0
libraries/SDU/extras/SDUBoot/.metro_m0.test.only
Normal file
|
|
@ -28,4 +28,5 @@ buildSDUBootSketch "arduino:samd:mkrfox1200" "$OUTPUT_PATH/mkrfox1200.h"
|
|||
buildSDUBootSketch "arduino:samd:mkrgsm1400" "$OUTPUT_PATH/mkrgsm1400.h"
|
||||
buildSDUBootSketch "arduino:samd:mkrwan1300" "$OUTPUT_PATH/mkrwan1300.h"
|
||||
buildSDUBootSketch "arduino:samd:mkrwifi1010" "$OUTPUT_PATH/mkrwifi1010.h"
|
||||
buildSDUBootSketch "arduino:samd:mkrnb1500" "$OUTPUT_PATH/mkrnb1500.h"
|
||||
buildSDUBootSketch "arduino:samd:mzero_bl" "$OUTPUT_PATH/mzero.h"
|
||||
|
|
|
|||
|
|
@ -36,6 +36,8 @@ unsigned char sduBoot[0x4000] = {
|
|||
#include "boot/mkrwan1300.h"
|
||||
#elif defined(ARDUINO_SAMD_MKRWIFI1010)
|
||||
#include "boot/mkrwifi1010.h"
|
||||
#elif defined(ARDUINO_SAMD_MKRNB1500)
|
||||
#include "boot/mkrnb1500.h"
|
||||
#elif defined(ARDUINO_SAM_ZERO)
|
||||
#include "boot/mzero.h"
|
||||
#else
|
||||
|
|
|
|||
1236
libraries/SDU/src/boot/mkrnb1500.h
Normal file
1236
libraries/SDU/src/boot/mkrnb1500.h
Normal file
File diff suppressed because it is too large
Load diff
|
|
@ -46,7 +46,16 @@ SPIClass::SPIClass(SERCOM *p_sercom, uint8_t uc_pinMISO, uint8_t uc_pinSCK, uint
|
|||
|
||||
void SPIClass::begin()
|
||||
{
|
||||
init();
|
||||
if(!initialized) {
|
||||
interruptMode = SPI_IMODE_NONE;
|
||||
interruptSave = 0;
|
||||
interruptMask = 0;
|
||||
initialized = true;
|
||||
}
|
||||
|
||||
if(!use_dma) {
|
||||
dmaAllocate();
|
||||
}
|
||||
|
||||
// PIO init
|
||||
pinPeripheral(_uc_pinMiso, g_APinDescription[_uc_pinMiso].ulPinType);
|
||||
|
|
@ -56,16 +65,6 @@ void SPIClass::begin()
|
|||
config(DEFAULT_SPI_SETTINGS);
|
||||
}
|
||||
|
||||
void SPIClass::init()
|
||||
{
|
||||
if (initialized)
|
||||
return;
|
||||
interruptMode = SPI_IMODE_NONE;
|
||||
interruptSave = 0;
|
||||
interruptMask = 0;
|
||||
initialized = true;
|
||||
}
|
||||
|
||||
void SPIClass::config(SPISettings settings)
|
||||
{
|
||||
_p_sercom->disableSPI();
|
||||
|
|
@ -80,6 +79,7 @@ void SPIClass::end()
|
|||
{
|
||||
_p_sercom->resetSPI();
|
||||
initialized = false;
|
||||
// Add DMA deallocation here
|
||||
}
|
||||
|
||||
#ifndef interruptsStatus
|
||||
|
|
@ -235,6 +235,231 @@ void SPIClass::transfer(void *buf, size_t count)
|
|||
}
|
||||
}
|
||||
|
||||
// DMA-based SPI transfer() function ---------------------------------------
|
||||
|
||||
// IMPORTANT: references to 65535 throughout the DMA code are INTENTIONAL.
|
||||
// DO NOT try to 'fix' by changing to 65536, or large transfers will fail!
|
||||
// The BTCNT value of a DMA descriptor is an unsigned 16-bit value with a
|
||||
// max of 65535. Larger transfers are handled by linked descriptors.
|
||||
|
||||
// Pointer to SPIClass object, one per DMA channel. This allows the
|
||||
// DMA callback (which has to exist outside the class context) to have
|
||||
// a reference back to the originating SPIClass object.
|
||||
static SPIClass *spiPtr[DMAC_CH_NUM] = { 0 }; // Legit inits list to NULL
|
||||
|
||||
void SPIClass::dmaCallback(Adafruit_ZeroDMA *dma) {
|
||||
// dmaCallback() receives an Adafruit_ZeroDMA object. From this we can get
|
||||
// a channel number (0 to DMAC_CH_NUM-1, always unique per ZeroDMA object),
|
||||
// then locate the originating SPIClass object using array lookup, setting
|
||||
// the dma_busy element 'false' to indicate end of transfer. Doesn't matter
|
||||
// if it's a read or write transfer...both channels get pointers to it.
|
||||
spiPtr[dma->getChannel()]->dma_busy = false;
|
||||
}
|
||||
|
||||
// For read-only and read+write transfers, a callback is assigned only
|
||||
// to the read channel to indicate end-of-transfer, and the write channel's
|
||||
// callback is assigned to this nonsense function (for reasons I'm not
|
||||
// entirely sure of, setting the callback to NULL doesn't work).
|
||||
static void dmaDoNothingCallback(Adafruit_ZeroDMA *dma) { (void)dma; }
|
||||
|
||||
// This could've gone in begin(), but for the sake of organization...
|
||||
void SPIClass::dmaAllocate(void) {
|
||||
// In order to support fully non-blocking SPI transfers, DMA descriptor
|
||||
// lists must be created for the input and/or output data. Rather than
|
||||
// do this dynamically with every transfer, the lists are allocated once
|
||||
// on SPI init. Maximum list size is finite and knowable -- transfers to
|
||||
// or from RAM or from flash memory will never exceed the corresponding
|
||||
// memory size (if they do, you have bigger problems). Descriptors
|
||||
// aren't large and there's usually only a handful to a dozen, so this
|
||||
// isn't an excessive burden in exchange for big non-blocking transfers.
|
||||
uint32_t maxWriteBytes = FLASH_SIZE; // Writes can't exceed all of flash
|
||||
#if defined(__SAMD51__)
|
||||
uint32_t maxReadBytes = HSRAM_SIZE; // Reads can't exceed all of RAM
|
||||
#else
|
||||
uint32_t maxReadBytes = HMCRAMC0_SIZE;
|
||||
#endif
|
||||
if(maxReadBytes > maxWriteBytes) { // I don't think any SAMD devices
|
||||
maxWriteBytes = maxReadBytes; // have RAM > flash, but just in case
|
||||
}
|
||||
|
||||
// VITAL to alloc read channel first, assigns it a higher DMA priority!
|
||||
if(readChannel.allocate() == DMA_STATUS_OK) {
|
||||
if(writeChannel.allocate() == DMA_STATUS_OK) {
|
||||
|
||||
// Both DMA channels (read and write) allocated successfully,
|
||||
// set up transfer triggers and other basics...
|
||||
|
||||
// readChannel callback only needs to be set up once.
|
||||
// Unlike the write callback which may get switched on or off,
|
||||
// read callback stays put. In certain cases the read DMA job
|
||||
// just isn't started and the callback is a non-issue then.
|
||||
readChannel.setTrigger(getDMAC_ID_RX());
|
||||
readChannel.setAction(DMA_TRIGGER_ACTON_BEAT);
|
||||
readChannel.setCallback(dmaCallback);
|
||||
spiPtr[readChannel.getChannel()] = this;
|
||||
|
||||
writeChannel.setTrigger(getDMAC_ID_TX());
|
||||
writeChannel.setAction(DMA_TRIGGER_ACTON_BEAT);
|
||||
spiPtr[writeChannel.getChannel()] = this;
|
||||
|
||||
// One descriptor per channel has already been allocated
|
||||
// in Adafruit_ZeroDMA, this just gets pointers to them...
|
||||
firstReadDescriptor = readChannel.addDescriptor(
|
||||
(void *)getDataRegister(), // Source address (SPI data reg)
|
||||
NULL, // Dest address (set later)
|
||||
0, // Count (set later)
|
||||
DMA_BEAT_SIZE_BYTE, // Bytes/hwords/words
|
||||
false, // Don't increment source address
|
||||
true); // Increment dest address
|
||||
firstWriteDescriptor = writeChannel.addDescriptor(
|
||||
NULL, // Source address (set later)
|
||||
(void *)getDataRegister(), // Dest (SPI data register)
|
||||
0, // Count (set later)
|
||||
DMA_BEAT_SIZE_BYTE, // Bytes/hwords/words
|
||||
true, // Increment source address
|
||||
false); // Don't increment dest address
|
||||
// This is the number of EXTRA descriptors beyond the first.
|
||||
int numReadDescriptors = ((maxReadBytes + 65534) / 65535) - 1;
|
||||
int numWriteDescriptors = ((maxWriteBytes + 65534) / 65535) - 1;
|
||||
int totalDescriptors = numReadDescriptors + numWriteDescriptors;
|
||||
|
||||
if(totalDescriptors <= 0) { // Don't need extra descriptors,
|
||||
use_dma = true; // channels are allocated, we're good.
|
||||
} else { // Else allocate extra descriptor lists...
|
||||
// Although DMA descriptors are technically a linked list, we just
|
||||
// allocate a chunk all at once, and finesse the pointers later.
|
||||
if((extraReadDescriptors = (DmacDescriptor *)malloc(
|
||||
totalDescriptors * sizeof(DmacDescriptor)))) {
|
||||
use_dma = true; // Everything allocated successfully
|
||||
extraWriteDescriptors = &extraReadDescriptors[numReadDescriptors];
|
||||
// Initialize descriptors (copy from first ones)
|
||||
for(int i=0; i<numReadDescriptors; i++) {
|
||||
memcpy(&extraReadDescriptors[i], firstReadDescriptor,
|
||||
sizeof(DmacDescriptor));
|
||||
}
|
||||
for(int i=0; i<numWriteDescriptors; i++) {
|
||||
memcpy(&extraWriteDescriptors[i], firstWriteDescriptor,
|
||||
sizeof(DmacDescriptor));
|
||||
}
|
||||
} // end malloc
|
||||
} // end extra descriptor check
|
||||
|
||||
if(use_dma) { // If everything allocated successfully,
|
||||
return; // then we're done here.
|
||||
} // Otherwise clean up interim allocations...
|
||||
writeChannel.free();
|
||||
} // end writeChannel alloc
|
||||
readChannel.free();
|
||||
} // end readChannel alloc
|
||||
|
||||
// NOT FATAL if channel or descriptor allocation fails.
|
||||
// transfer() function will fall back on a manual byte-by-byte loop.
|
||||
}
|
||||
|
||||
void SPIClass::transfer(const void *txbuf, void *rxbuf, size_t count,
|
||||
bool block) {
|
||||
|
||||
if((!txbuf && !rxbuf) || !count) { // Validate inputs
|
||||
return;
|
||||
}
|
||||
// OK to assume now that txbuf and/or rxbuf are non-NULL, an if/else is
|
||||
// often sufficient, don't need else-ifs for everything buffer related.
|
||||
|
||||
uint8_t *txbuf8 = (uint8_t *)txbuf; // Must cast to byte size
|
||||
uint8_t *rxbuf8 = (uint8_t *)rxbuf; // for pointer math
|
||||
|
||||
if(use_dma) { // DMA-BASED TRANSFER YAY ----------------------------------
|
||||
|
||||
static const uint8_t dum = 0xFF; // Dummy byte for read-only xfers
|
||||
|
||||
// Set up DMA descriptor lists -----------------------------------------
|
||||
|
||||
DmacDescriptor *rDesc = firstReadDescriptor;
|
||||
DmacDescriptor *wDesc = firstWriteDescriptor;
|
||||
int descIdx = 0; // Index into extra descriptor lists
|
||||
|
||||
while(count) { // Counts down to end of transfer
|
||||
uint32_t bytesThisDescriptor = count;
|
||||
if(bytesThisDescriptor > 65535) { // Limit each descriptor
|
||||
bytesThisDescriptor = 65535; // to 65535 (not 65536) bytes
|
||||
}
|
||||
rDesc->BTCNT.reg = wDesc->BTCNT.reg = bytesThisDescriptor;
|
||||
if(rxbuf) { // Read-only or read+write
|
||||
// Auto-inc addresses in DMA descriptors must point to END of data.
|
||||
// Buf pointers would advance at end of loop anyway, do it now...
|
||||
rxbuf8 += bytesThisDescriptor;
|
||||
rDesc->DSTADDR.reg = (uint32_t)rxbuf8;
|
||||
}
|
||||
if(txbuf) { // Write-only or read+write
|
||||
txbuf8 += bytesThisDescriptor; // Same as above
|
||||
wDesc->SRCADDR.reg = (uint32_t)txbuf8;
|
||||
wDesc->BTCTRL.bit.SRCINC = 1; // Increment source pointer
|
||||
} else { // Read-only requires dummy write
|
||||
wDesc->SRCADDR.reg = (uint32_t)&dum;
|
||||
wDesc->BTCTRL.bit.SRCINC = 0; // Don't increment source pointer
|
||||
}
|
||||
count -= bytesThisDescriptor;
|
||||
if(count) { // Still more data?
|
||||
// Link to next descriptors. Extra descriptors are IN ADDITION
|
||||
// to first, so it's safe and correct that descIdx starts at 0.
|
||||
rDesc->DESCADDR.reg = (uint32_t)&extraReadDescriptors[descIdx];
|
||||
wDesc->DESCADDR.reg = (uint32_t)&extraWriteDescriptors[descIdx];
|
||||
rDesc = &extraReadDescriptors[descIdx]; // Update pointers to
|
||||
wDesc = &extraWriteDescriptors[descIdx]; // next descriptors
|
||||
descIdx++;
|
||||
// A write-only transfer doesn't use the read descriptor list, but
|
||||
// it's quicker to build it (full of nonsense) anyway than to check.
|
||||
} else { // No more data, end descriptor linked lists
|
||||
rDesc->DESCADDR.reg = wDesc->DESCADDR.reg = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// Set up DMA transfer job(s) ------------------------------------------
|
||||
|
||||
if(rxbuf) { // Read+write or read-only
|
||||
// End-of-read callback is already set up, disable write CB, start job
|
||||
writeChannel.setCallback(dmaDoNothingCallback);
|
||||
readChannel.startJob();
|
||||
} else { // Write-only, use end-of-write callback
|
||||
writeChannel.setCallback(dmaCallback);
|
||||
}
|
||||
|
||||
// Run DMA jobs, blocking if requested ---------------------------------
|
||||
|
||||
dma_busy = true;
|
||||
writeChannel.startJob(); // All xfers, even read-only, need write job.
|
||||
if(block) { // If blocking transfer requested,
|
||||
while(dma_busy); // wait for job to finish
|
||||
}
|
||||
|
||||
} else { // NON-DMA FALLBACK ---------------------------------------------
|
||||
|
||||
if(txbuf8) {
|
||||
if(rxbuf8) { // Write + read simultaneously
|
||||
while(count--) {
|
||||
*rxbuf8++ = _p_sercom->transferDataSPI(*txbuf8++);
|
||||
}
|
||||
} else { // Write only
|
||||
while(count--) {
|
||||
(void)_p_sercom->transferDataSPI(*txbuf8++);
|
||||
}
|
||||
}
|
||||
} else { // Read only
|
||||
while(count--) {
|
||||
*rxbuf8++ = _p_sercom->transferDataSPI(0xFF);
|
||||
}
|
||||
}
|
||||
|
||||
} // end non-DMA
|
||||
}
|
||||
|
||||
// Waits for a prior in-background DMA transfer to complete.
|
||||
void SPIClass::waitForTransfer(void) {
|
||||
while(dma_busy);
|
||||
}
|
||||
|
||||
// End DMA-based SPI transfer() code ---------------------------------------
|
||||
|
||||
void SPIClass::attachInterrupt() {
|
||||
// Should be enableInterrupt()
|
||||
}
|
||||
|
|
@ -243,6 +468,61 @@ void SPIClass::detachInterrupt() {
|
|||
// Should be disableInterrupt()
|
||||
}
|
||||
|
||||
// SPI DMA lookup works on both SAMD21 and SAMD51
|
||||
|
||||
static const struct {
|
||||
volatile uint32_t *data_reg;
|
||||
int dmac_id_tx;
|
||||
int dmac_id_rx;
|
||||
} sercomData[] = {
|
||||
{ &SERCOM0->SPI.DATA.reg, SERCOM0_DMAC_ID_TX, SERCOM0_DMAC_ID_RX },
|
||||
{ &SERCOM1->SPI.DATA.reg, SERCOM1_DMAC_ID_TX, SERCOM1_DMAC_ID_RX },
|
||||
{ &SERCOM2->SPI.DATA.reg, SERCOM2_DMAC_ID_TX, SERCOM2_DMAC_ID_RX },
|
||||
{ &SERCOM3->SPI.DATA.reg, SERCOM3_DMAC_ID_TX, SERCOM3_DMAC_ID_RX },
|
||||
#if defined(SERCOM4)
|
||||
{ &SERCOM4->SPI.DATA.reg, SERCOM4_DMAC_ID_TX, SERCOM4_DMAC_ID_RX },
|
||||
#endif
|
||||
#if defined(SERCOM5)
|
||||
{ &SERCOM5->SPI.DATA.reg, SERCOM5_DMAC_ID_TX, SERCOM5_DMAC_ID_RX },
|
||||
#endif
|
||||
#if defined(SERCOM6)
|
||||
{ &SERCOM6->SPI.DATA.reg, SERCOM6_DMAC_ID_TX, SERCOM6_DMAC_ID_RX },
|
||||
#endif
|
||||
#if defined(SERCOM7)
|
||||
{ &SERCOM7->SPI.DATA.reg, SERCOM7_DMAC_ID_TX, SERCOM7_DMAC_ID_RX },
|
||||
#endif
|
||||
};
|
||||
|
||||
volatile uint32_t *SPIClass::getDataRegister(void) {
|
||||
int8_t idx = _p_sercom->getSercomIndex();
|
||||
return (idx >= 0) ? sercomData[idx].data_reg: NULL;
|
||||
}
|
||||
|
||||
int SPIClass::getDMAC_ID_TX(void) {
|
||||
int8_t idx = _p_sercom->getSercomIndex();
|
||||
return (idx >= 0) ? sercomData[idx].dmac_id_tx : -1;
|
||||
}
|
||||
|
||||
int SPIClass::getDMAC_ID_RX(void) {
|
||||
int8_t idx = _p_sercom->getSercomIndex();
|
||||
return (idx >= 0) ? sercomData[idx].dmac_id_rx : -1;
|
||||
}
|
||||
|
||||
#if defined(__SAMD51__)
|
||||
|
||||
// Set the SPI device's SERCOM clock CORE and SLOW clock sources.
|
||||
// SercomClockSource values are an enumeration in SERCOM.h.
|
||||
// This works on SAMD51 only. On SAMD21, a dummy function is declared
|
||||
// in SPI.h which compiles to nothing, so user code doesn't need to check
|
||||
// and conditionally compile lines for different architectures.
|
||||
void SPIClass::setClockSource(SercomClockSource clk) {
|
||||
int8_t idx = _p_sercom->getSercomIndex();
|
||||
_p_sercom->setClockSource(idx, clk, true); // true = set core clock
|
||||
_p_sercom->setClockSource(idx, clk, false); // false = set slow clock
|
||||
}
|
||||
|
||||
#endif // end __SAMD51__
|
||||
|
||||
#if SPI_INTERFACES_COUNT > 0
|
||||
/* In case new variant doesn't define these macros,
|
||||
* we put here the ones for Arduino Zero.
|
||||
|
|
@ -275,4 +555,3 @@ void SPIClass::detachInterrupt() {
|
|||
#if SPI_INTERFACES_COUNT > 5
|
||||
SPIClass SPI5(&PERIPH_SPI5, PIN_SPI5_MISO, PIN_SPI5_SCK, PIN_SPI5_MOSI, PAD_SPI5_TX, PAD_SPI5_RX);
|
||||
#endif
|
||||
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@
|
|||
#define _SPI_H_INCLUDED
|
||||
|
||||
#include <Arduino.h>
|
||||
#include <Adafruit_ZeroDMA.h>
|
||||
|
||||
// SPI_HAS_TRANSACTION means SPI has
|
||||
// - beginTransaction()
|
||||
|
|
@ -37,12 +38,27 @@
|
|||
#define SPI_MODE2 0x03
|
||||
#define SPI_MODE3 0x01
|
||||
|
||||
#if defined(ARDUINO_ARCH_SAMD)
|
||||
#if defined(__SAMD51__)
|
||||
// SAMD51 has configurable MAX_SPI, else use peripheral clock default.
|
||||
// Update: changing MAX_SPI via compiler flags is DEPRECATED, because
|
||||
// this affects ALL SPI peripherals including some that should NOT be
|
||||
// changed (e.g. anything using SD card). Use the setClockSource()
|
||||
// function instead. This is left here for compatibility with interim code.
|
||||
#if !defined(MAX_SPI)
|
||||
#define MAX_SPI 24000000
|
||||
#endif
|
||||
#define SPI_MIN_CLOCK_DIVIDER 1
|
||||
#else
|
||||
// The datasheet specifies a typical SPI SCK period (tSCK) of 42 ns,
|
||||
// see "Table 36-48. SPI Timing Characteristics and Requirements",
|
||||
// which translates into a maximum SPI clock of 23.8 MHz.
|
||||
// Conservatively, the divider is set for a 12 MHz maximum SPI clock.
|
||||
#define SPI_MIN_CLOCK_DIVIDER (uint8_t)(1 + ((F_CPU - 1) / 12000000))
|
||||
// We'll permit use of 24 MHz SPI even though this is slightly out
|
||||
// of spec. Given how clock dividers work, the next "sensible"
|
||||
// threshold would be a substantial drop down to 12 MHz.
|
||||
#if !defined(MAX_SPI)
|
||||
#define MAX_SPI 24000000
|
||||
#endif
|
||||
#define SPI_MIN_CLOCK_DIVIDER (uint8_t)(1 + ((F_CPU - 1) / MAX_SPI))
|
||||
#endif
|
||||
|
||||
class SPISettings {
|
||||
|
|
@ -64,7 +80,11 @@ class SPISettings {
|
|||
}
|
||||
|
||||
void init_AlwaysInline(uint32_t clock, BitOrder bitOrder, uint8_t dataMode) __attribute__((__always_inline__)) {
|
||||
this->clockFreq = (clock >= (F_CPU / SPI_MIN_CLOCK_DIVIDER) ? F_CPU / SPI_MIN_CLOCK_DIVIDER : clock);
|
||||
#if defined(__SAMD51__)
|
||||
this->clockFreq = clock; // Clipping handled in SERCOM.cpp
|
||||
#else
|
||||
this->clockFreq = clock >= MAX_SPI ? MAX_SPI : clock;
|
||||
#endif
|
||||
|
||||
this->bitOrder = (bitOrder == MSBFIRST ? MSB_FIRST : LSB_FIRST);
|
||||
|
||||
|
|
@ -94,10 +114,12 @@ class SPIClass {
|
|||
public:
|
||||
SPIClass(SERCOM *p_sercom, uint8_t uc_pinMISO, uint8_t uc_pinSCK, uint8_t uc_pinMOSI, SercomSpiTXPad, SercomRXPad);
|
||||
|
||||
|
||||
byte transfer(uint8_t data);
|
||||
uint16_t transfer16(uint16_t data);
|
||||
void transfer(void *buf, size_t count);
|
||||
void transfer(const void* txbuf, void* rxbuf, size_t count,
|
||||
bool block = true);
|
||||
void waitForTransfer(void);
|
||||
|
||||
// Transaction Functions
|
||||
void usingInterrupt(int interruptNumber);
|
||||
|
|
@ -116,8 +138,21 @@ class SPIClass {
|
|||
void setDataMode(uint8_t uc_mode);
|
||||
void setClockDivider(uint8_t uc_div);
|
||||
|
||||
// SERCOM lookup functions are available on both SAMD51 and 21.
|
||||
volatile uint32_t *getDataRegister(void);
|
||||
int getDMAC_ID_TX(void);
|
||||
int getDMAC_ID_RX(void);
|
||||
uint8_t getSercomIndex(void) { return _p_sercom->getSercomIndex(); };
|
||||
#if defined(__SAMD51__)
|
||||
// SERCOM clock source override is available only on SAMD51.
|
||||
void setClockSource(SercomClockSource clk);
|
||||
#else
|
||||
// On SAMD21, this compiles to nothing, so user code doesn't need to
|
||||
// check and conditionally compile lines for different architectures.
|
||||
void setClockSource(SercomClockSource clk) { (void)clk; };
|
||||
#endif // end __SAMD51__
|
||||
|
||||
private:
|
||||
void init();
|
||||
void config(SPISettings settings);
|
||||
|
||||
SERCOM *_p_sercom;
|
||||
|
|
@ -132,6 +167,18 @@ class SPIClass {
|
|||
uint8_t interruptMode;
|
||||
char interruptSave;
|
||||
uint32_t interruptMask;
|
||||
|
||||
// transfer(txbuf, rxbuf, count, block) uses DMA when possible
|
||||
Adafruit_ZeroDMA readChannel;
|
||||
Adafruit_ZeroDMA writeChannel;
|
||||
DmacDescriptor *firstReadDescriptor = NULL; // List entry point
|
||||
DmacDescriptor *firstWriteDescriptor = NULL;
|
||||
DmacDescriptor *extraReadDescriptors = NULL; // Add'l descriptors
|
||||
DmacDescriptor *extraWriteDescriptors = NULL;
|
||||
bool use_dma = false; // true on successful alloc
|
||||
volatile bool dma_busy = false;
|
||||
void dmaAllocate(void);
|
||||
static void dmaCallback(Adafruit_ZeroDMA *dma);
|
||||
};
|
||||
|
||||
#if SPI_INTERFACES_COUNT > 0
|
||||
|
|
@ -155,14 +202,12 @@ class SPIClass {
|
|||
|
||||
// For compatibility with sketches designed for AVR @ 16 MHz
|
||||
// New programs should use SPI.beginTransaction to set the SPI clock
|
||||
#if F_CPU == 48000000
|
||||
#define SPI_CLOCK_DIV2 6
|
||||
#define SPI_CLOCK_DIV4 12
|
||||
#define SPI_CLOCK_DIV8 24
|
||||
#define SPI_CLOCK_DIV16 48
|
||||
#define SPI_CLOCK_DIV32 96
|
||||
#define SPI_CLOCK_DIV64 192
|
||||
#define SPI_CLOCK_DIV128 255
|
||||
#endif
|
||||
#define SPI_CLOCK_DIV2 (MAX_SPI * 2 / 8000000)
|
||||
#define SPI_CLOCK_DIV4 (MAX_SPI * 2 / 4000000)
|
||||
#define SPI_CLOCK_DIV8 (MAX_SPI * 2 / 2000000)
|
||||
#define SPI_CLOCK_DIV16 (MAX_SPI * 2 / 1000000)
|
||||
#define SPI_CLOCK_DIV32 (MAX_SPI * 2 / 500000)
|
||||
#define SPI_CLOCK_DIV64 (MAX_SPI * 2 / 250000)
|
||||
#define SPI_CLOCK_DIV128 (MAX_SPI * 2 / 125000)
|
||||
|
||||
#endif
|
||||
|
|
|
|||
25
libraries/Servo/README.adoc
Normal file
25
libraries/Servo/README.adoc
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
= Servo Library for Arduino =
|
||||
|
||||
This library allows an Arduino board to control RC (hobby) servo motors.
|
||||
|
||||
For more information about this library please visit us at
|
||||
http://www.arduino.cc/en/Reference/Servo
|
||||
|
||||
== License ==
|
||||
|
||||
Copyright (c) 2013 Arduino LLC. All right reserved.
|
||||
Copyright (c) 2009 Michael Margolis. All right reserved.
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
27
libraries/Servo/examples/Knob/Knob.ino
Normal file
27
libraries/Servo/examples/Knob/Knob.ino
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
/*
|
||||
Controlling a servo position using a potentiometer (variable resistor)
|
||||
by Michal Rinott <http://people.interaction-ivrea.it/m.rinott>
|
||||
|
||||
modified on 8 Nov 2013
|
||||
by Scott Fitzgerald
|
||||
http://www.arduino.cc/en/Tutorial/Knob
|
||||
*/
|
||||
|
||||
#include <Servo.h>
|
||||
|
||||
Servo myservo; // create servo object to control a servo
|
||||
|
||||
int potpin = 0; // analog pin used to connect the potentiometer
|
||||
int val; // variable to read the value from the analog pin
|
||||
|
||||
void setup() {
|
||||
myservo.attach(9); // attaches the servo on pin 9 to the servo object
|
||||
}
|
||||
|
||||
void loop() {
|
||||
val = analogRead(potpin); // reads the value of the potentiometer (value between 0 and 1023)
|
||||
val = map(val, 0, 1023, 0, 180); // scale it to use it with the servo (value between 0 and 180)
|
||||
myservo.write(val); // sets the servo position according to the scaled value
|
||||
delay(15); // waits for the servo to get there
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue