Compare commits
12 commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b798c9704b | ||
|
|
6ed44b3dc4 | ||
|
|
4871a78f0b | ||
|
|
ff6f16e1b1 | ||
|
|
dcd707a201 | ||
|
|
6536a52866 | ||
|
|
161d4c9ca3 | ||
|
|
537a7e346f | ||
|
|
506d3ee57a | ||
|
|
1ebde085d9 | ||
|
|
f707b3817b | ||
|
|
0cb8512c19 |
283 changed files with 1680 additions and 24411 deletions
63
.github/workflows/githubci.yml
vendored
63
.github/workflows/githubci.yml
vendored
|
|
@ -1,63 +0,0 @@
|
||||||
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
3
.gitmodules
vendored
|
|
@ -1,3 +0,0 @@
|
||||||
[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,40 +1,5 @@
|
||||||
SAMD CORE ?.?.?? ????.??.??
|
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
|
SAMD CORE 1.6.18 2018.03.05
|
||||||
|
|
||||||
* Wire: Added support for general call (broadcast)
|
* Wire: Added support for general call (broadcast)
|
||||||
|
|
|
||||||
39
README.md
39
README.md
|
|
@ -1,16 +1,47 @@
|
||||||
# Arduino Core for SAMD21 and SAMD51 CPU
|
# Arduino Core for SAMD21 and SAMD51 CPU
|
||||||
|
|
||||||
[](https://github.com/adafruit/ArduinoCore-samd/actions)
|
## 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
|
||||||
|
|
||||||
This repository contains the source code and configuration files of the Arduino Core
|
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).
|
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
|
In particular, this adds support for the Adafruit SAMD Boards such as the Feather M0
|
||||||
|
|
||||||
## Bugs or Issues
|
## ATSAMD51 Installation on Arduino IDE
|
||||||
|
|
||||||
* AREF must be tied to 3.3V for dac to work. This is a bug in the SAMD51 silicon.
|
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)
|
||||||
* USB host mode doesn't work yet
|
|
||||||
|
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
|
||||||
|
|
||||||
If you find a bug you can submit an issue here on github:
|
If you find a bug you can submit an issue here on github:
|
||||||
|
|
||||||
|
|
|
||||||
1311
boards.txt
1311
boards.txt
File diff suppressed because it is too large
Load diff
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
|
@ -1,502 +0,0 @@
|
||||||
: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,11 +218,7 @@ void I2S_Handler ( void );
|
||||||
* \brief Configuration of the Cortex-M0+ Processor and Core Peripherals
|
* \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
|
#define LITTLE_ENDIAN 1
|
||||||
#endif
|
|
||||||
#define __CM0PLUS_REV 1 /*!< Core revision r0p1 */
|
#define __CM0PLUS_REV 1 /*!< Core revision r0p1 */
|
||||||
#define __MPU_PRESENT 0 /*!< MPU present or not */
|
#define __MPU_PRESENT 0 /*!< MPU present or not */
|
||||||
#define __NVIC_PRIO_BITS 2 /*!< Number of bits used for Priority Levels */
|
#define __NVIC_PRIO_BITS 2 /*!< Number of bits used for Priority Levels */
|
||||||
|
|
|
||||||
|
|
@ -218,11 +218,7 @@ void I2S_Handler ( void );
|
||||||
* \brief Configuration of the Cortex-M0+ Processor and Core Peripherals
|
* \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
|
#define LITTLE_ENDIAN 1
|
||||||
#endif
|
|
||||||
#define __CM0PLUS_REV 1 /*!< Core revision r0p1 */
|
#define __CM0PLUS_REV 1 /*!< Core revision r0p1 */
|
||||||
#define __MPU_PRESENT 0 /*!< MPU present or not */
|
#define __MPU_PRESENT 0 /*!< MPU present or not */
|
||||||
#define __NVIC_PRIO_BITS 2 /*!< Number of bits used for Priority Levels */
|
#define __NVIC_PRIO_BITS 2 /*!< Number of bits used for Priority Levels */
|
||||||
|
|
|
||||||
|
|
@ -218,11 +218,7 @@ void I2S_Handler ( void );
|
||||||
* \brief Configuration of the Cortex-M0+ Processor and Core Peripherals
|
* \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
|
#define LITTLE_ENDIAN 1
|
||||||
#endif
|
|
||||||
#define __CM0PLUS_REV 1 /*!< Core revision r0p1 */
|
#define __CM0PLUS_REV 1 /*!< Core revision r0p1 */
|
||||||
#define __MPU_PRESENT 0 /*!< MPU present or not */
|
#define __MPU_PRESENT 0 /*!< MPU present or not */
|
||||||
#define __NVIC_PRIO_BITS 2 /*!< Number of bits used for Priority Levels */
|
#define __NVIC_PRIO_BITS 2 /*!< Number of bits used for Priority Levels */
|
||||||
|
|
|
||||||
|
|
@ -218,11 +218,7 @@ void I2S_Handler ( void );
|
||||||
* \brief Configuration of the Cortex-M0+ Processor and Core Peripherals
|
* \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
|
#define LITTLE_ENDIAN 1
|
||||||
#endif
|
|
||||||
#define __CM0PLUS_REV 1 /*!< Core revision r0p1 */
|
#define __CM0PLUS_REV 1 /*!< Core revision r0p1 */
|
||||||
#define __MPU_PRESENT 0 /*!< MPU present or not */
|
#define __MPU_PRESENT 0 /*!< MPU present or not */
|
||||||
#define __NVIC_PRIO_BITS 2 /*!< Number of bits used for Priority Levels */
|
#define __NVIC_PRIO_BITS 2 /*!< Number of bits used for Priority Levels */
|
||||||
|
|
|
||||||
|
|
@ -222,11 +222,7 @@ void I2S_Handler ( void );
|
||||||
* \brief Configuration of the Cortex-M0+ Processor and Core Peripherals
|
* \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
|
#define LITTLE_ENDIAN 1
|
||||||
#endif
|
|
||||||
#define __CM0PLUS_REV 1 /*!< Core revision r0p1 */
|
#define __CM0PLUS_REV 1 /*!< Core revision r0p1 */
|
||||||
#define __MPU_PRESENT 0 /*!< MPU present or not */
|
#define __MPU_PRESENT 0 /*!< MPU present or not */
|
||||||
#define __NVIC_PRIO_BITS 2 /*!< Number of bits used for Priority Levels */
|
#define __NVIC_PRIO_BITS 2 /*!< Number of bits used for Priority Levels */
|
||||||
|
|
|
||||||
|
|
@ -222,11 +222,7 @@ void I2S_Handler ( void );
|
||||||
* \brief Configuration of the Cortex-M0+ Processor and Core Peripherals
|
* \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
|
#define LITTLE_ENDIAN 1
|
||||||
#endif
|
|
||||||
#define __CM0PLUS_REV 1 /*!< Core revision r0p1 */
|
#define __CM0PLUS_REV 1 /*!< Core revision r0p1 */
|
||||||
#define __MPU_PRESENT 0 /*!< MPU present or not */
|
#define __MPU_PRESENT 0 /*!< MPU present or not */
|
||||||
#define __NVIC_PRIO_BITS 2 /*!< Number of bits used for Priority Levels */
|
#define __NVIC_PRIO_BITS 2 /*!< Number of bits used for Priority Levels */
|
||||||
|
|
|
||||||
|
|
@ -222,11 +222,7 @@ void I2S_Handler ( void );
|
||||||
* \brief Configuration of the Cortex-M0+ Processor and Core Peripherals
|
* \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
|
#define LITTLE_ENDIAN 1
|
||||||
#endif
|
|
||||||
#define __CM0PLUS_REV 1 /*!< Core revision r0p1 */
|
#define __CM0PLUS_REV 1 /*!< Core revision r0p1 */
|
||||||
#define __MPU_PRESENT 0 /*!< MPU present or not */
|
#define __MPU_PRESENT 0 /*!< MPU present or not */
|
||||||
#define __NVIC_PRIO_BITS 2 /*!< Number of bits used for Priority Levels */
|
#define __NVIC_PRIO_BITS 2 /*!< Number of bits used for Priority Levels */
|
||||||
|
|
|
||||||
|
|
@ -222,11 +222,7 @@ void I2S_Handler ( void );
|
||||||
* \brief Configuration of the Cortex-M0+ Processor and Core Peripherals
|
* \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
|
#define LITTLE_ENDIAN 1
|
||||||
#endif
|
|
||||||
#define __CM0PLUS_REV 1 /*!< Core revision r0p1 */
|
#define __CM0PLUS_REV 1 /*!< Core revision r0p1 */
|
||||||
#define __MPU_PRESENT 0 /*!< MPU present or not */
|
#define __MPU_PRESENT 0 /*!< MPU present or not */
|
||||||
#define __NVIC_PRIO_BITS 2 /*!< Number of bits used for Priority Levels */
|
#define __NVIC_PRIO_BITS 2 /*!< Number of bits used for Priority Levels */
|
||||||
|
|
|
||||||
|
|
@ -226,11 +226,7 @@ void I2S_Handler ( void );
|
||||||
* \brief Configuration of the Cortex-M0+ Processor and Core Peripherals
|
* \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
|
#define LITTLE_ENDIAN 1
|
||||||
#endif
|
|
||||||
#define __CM0PLUS_REV 1 /*!< Core revision r0p1 */
|
#define __CM0PLUS_REV 1 /*!< Core revision r0p1 */
|
||||||
#define __MPU_PRESENT 0 /*!< MPU present or not */
|
#define __MPU_PRESENT 0 /*!< MPU present or not */
|
||||||
#define __NVIC_PRIO_BITS 2 /*!< Number of bits used for Priority Levels */
|
#define __NVIC_PRIO_BITS 2 /*!< Number of bits used for Priority Levels */
|
||||||
|
|
|
||||||
|
|
@ -226,11 +226,7 @@ void I2S_Handler ( void );
|
||||||
* \brief Configuration of the Cortex-M0+ Processor and Core Peripherals
|
* \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
|
#define LITTLE_ENDIAN 1
|
||||||
#endif
|
|
||||||
#define __CM0PLUS_REV 1 /*!< Core revision r0p1 */
|
#define __CM0PLUS_REV 1 /*!< Core revision r0p1 */
|
||||||
#define __MPU_PRESENT 0 /*!< MPU present or not */
|
#define __MPU_PRESENT 0 /*!< MPU present or not */
|
||||||
#define __NVIC_PRIO_BITS 2 /*!< Number of bits used for Priority Levels */
|
#define __NVIC_PRIO_BITS 2 /*!< Number of bits used for Priority Levels */
|
||||||
|
|
|
||||||
|
|
@ -226,11 +226,7 @@ void I2S_Handler ( void );
|
||||||
* \brief Configuration of the Cortex-M0+ Processor and Core Peripherals
|
* \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
|
#define LITTLE_ENDIAN 1
|
||||||
#endif
|
|
||||||
#define __CM0PLUS_REV 1 /*!< Core revision r0p1 */
|
#define __CM0PLUS_REV 1 /*!< Core revision r0p1 */
|
||||||
#define __MPU_PRESENT 0 /*!< MPU present or not */
|
#define __MPU_PRESENT 0 /*!< MPU present or not */
|
||||||
#define __NVIC_PRIO_BITS 2 /*!< Number of bits used for Priority Levels */
|
#define __NVIC_PRIO_BITS 2 /*!< Number of bits used for Priority Levels */
|
||||||
|
|
|
||||||
|
|
@ -226,11 +226,7 @@ void I2S_Handler ( void );
|
||||||
* \brief Configuration of the Cortex-M0+ Processor and Core Peripherals
|
* \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
|
#define LITTLE_ENDIAN 1
|
||||||
#endif
|
|
||||||
#define __CM0PLUS_REV 1 /*!< Core revision r0p1 */
|
#define __CM0PLUS_REV 1 /*!< Core revision r0p1 */
|
||||||
#define __MPU_PRESENT 0 /*!< MPU present or not */
|
#define __MPU_PRESENT 0 /*!< MPU present or not */
|
||||||
#define __NVIC_PRIO_BITS 2 /*!< Number of bits used for Priority Levels */
|
#define __NVIC_PRIO_BITS 2 /*!< Number of bits used for Priority Levels */
|
||||||
|
|
|
||||||
Binary file not shown.
|
|
@ -218,11 +218,7 @@ void I2S_Handler ( void );
|
||||||
* \brief Configuration of the Cortex-M0+ Processor and Core Peripherals
|
* \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
|
#define LITTLE_ENDIAN 1
|
||||||
#endif
|
|
||||||
#define __CM0PLUS_REV 1 /*!< Core revision r0p1 */
|
#define __CM0PLUS_REV 1 /*!< Core revision r0p1 */
|
||||||
#define __MPU_PRESENT 0 /*!< MPU present or not */
|
#define __MPU_PRESENT 0 /*!< MPU present or not */
|
||||||
#define __NVIC_PRIO_BITS 2 /*!< Number of bits used for Priority Levels */
|
#define __NVIC_PRIO_BITS 2 /*!< Number of bits used for Priority Levels */
|
||||||
|
|
|
||||||
|
|
@ -218,11 +218,7 @@ void I2S_Handler ( void );
|
||||||
* \brief Configuration of the Cortex-M0+ Processor and Core Peripherals
|
* \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
|
#define LITTLE_ENDIAN 1
|
||||||
#endif
|
|
||||||
#define __CM0PLUS_REV 1 /*!< Core revision r0p1 */
|
#define __CM0PLUS_REV 1 /*!< Core revision r0p1 */
|
||||||
#define __MPU_PRESENT 0 /*!< MPU present or not */
|
#define __MPU_PRESENT 0 /*!< MPU present or not */
|
||||||
#define __NVIC_PRIO_BITS 2 /*!< Number of bits used for Priority Levels */
|
#define __NVIC_PRIO_BITS 2 /*!< Number of bits used for Priority Levels */
|
||||||
|
|
|
||||||
|
|
@ -218,11 +218,7 @@ void I2S_Handler ( void );
|
||||||
* \brief Configuration of the Cortex-M0+ Processor and Core Peripherals
|
* \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
|
#define LITTLE_ENDIAN 1
|
||||||
#endif
|
|
||||||
#define __CM0PLUS_REV 1 /*!< Core revision r0p1 */
|
#define __CM0PLUS_REV 1 /*!< Core revision r0p1 */
|
||||||
#define __MPU_PRESENT 0 /*!< MPU present or not */
|
#define __MPU_PRESENT 0 /*!< MPU present or not */
|
||||||
#define __NVIC_PRIO_BITS 2 /*!< Number of bits used for Priority Levels */
|
#define __NVIC_PRIO_BITS 2 /*!< Number of bits used for Priority Levels */
|
||||||
|
|
|
||||||
|
|
@ -218,11 +218,7 @@ void I2S_Handler ( void );
|
||||||
* \brief Configuration of the Cortex-M0+ Processor and Core Peripherals
|
* \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
|
#define LITTLE_ENDIAN 1
|
||||||
#endif
|
|
||||||
#define __CM0PLUS_REV 1 /*!< Core revision r0p1 */
|
#define __CM0PLUS_REV 1 /*!< Core revision r0p1 */
|
||||||
#define __MPU_PRESENT 0 /*!< MPU present or not */
|
#define __MPU_PRESENT 0 /*!< MPU present or not */
|
||||||
#define __NVIC_PRIO_BITS 2 /*!< Number of bits used for Priority Levels */
|
#define __NVIC_PRIO_BITS 2 /*!< Number of bits used for Priority Levels */
|
||||||
|
|
|
||||||
|
|
@ -222,11 +222,7 @@ void I2S_Handler ( void );
|
||||||
* \brief Configuration of the Cortex-M0+ Processor and Core Peripherals
|
* \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
|
#define LITTLE_ENDIAN 1
|
||||||
#endif
|
|
||||||
#define __CM0PLUS_REV 1 /*!< Core revision r0p1 */
|
#define __CM0PLUS_REV 1 /*!< Core revision r0p1 */
|
||||||
#define __MPU_PRESENT 0 /*!< MPU present or not */
|
#define __MPU_PRESENT 0 /*!< MPU present or not */
|
||||||
#define __NVIC_PRIO_BITS 2 /*!< Number of bits used for Priority Levels */
|
#define __NVIC_PRIO_BITS 2 /*!< Number of bits used for Priority Levels */
|
||||||
|
|
|
||||||
|
|
@ -222,11 +222,7 @@ void I2S_Handler ( void );
|
||||||
* \brief Configuration of the Cortex-M0+ Processor and Core Peripherals
|
* \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
|
#define LITTLE_ENDIAN 1
|
||||||
#endif
|
|
||||||
#define __CM0PLUS_REV 1 /*!< Core revision r0p1 */
|
#define __CM0PLUS_REV 1 /*!< Core revision r0p1 */
|
||||||
#define __MPU_PRESENT 0 /*!< MPU present or not */
|
#define __MPU_PRESENT 0 /*!< MPU present or not */
|
||||||
#define __NVIC_PRIO_BITS 2 /*!< Number of bits used for Priority Levels */
|
#define __NVIC_PRIO_BITS 2 /*!< Number of bits used for Priority Levels */
|
||||||
|
|
|
||||||
|
|
@ -222,11 +222,7 @@ void I2S_Handler ( void );
|
||||||
* \brief Configuration of the Cortex-M0+ Processor and Core Peripherals
|
* \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
|
#define LITTLE_ENDIAN 1
|
||||||
#endif
|
|
||||||
#define __CM0PLUS_REV 1 /*!< Core revision r0p1 */
|
#define __CM0PLUS_REV 1 /*!< Core revision r0p1 */
|
||||||
#define __MPU_PRESENT 0 /*!< MPU present or not */
|
#define __MPU_PRESENT 0 /*!< MPU present or not */
|
||||||
#define __NVIC_PRIO_BITS 2 /*!< Number of bits used for Priority Levels */
|
#define __NVIC_PRIO_BITS 2 /*!< Number of bits used for Priority Levels */
|
||||||
|
|
|
||||||
|
|
@ -222,11 +222,7 @@ void I2S_Handler ( void );
|
||||||
* \brief Configuration of the Cortex-M0+ Processor and Core Peripherals
|
* \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
|
#define LITTLE_ENDIAN 1
|
||||||
#endif
|
|
||||||
#define __CM0PLUS_REV 1 /*!< Core revision r0p1 */
|
#define __CM0PLUS_REV 1 /*!< Core revision r0p1 */
|
||||||
#define __MPU_PRESENT 0 /*!< MPU present or not */
|
#define __MPU_PRESENT 0 /*!< MPU present or not */
|
||||||
#define __NVIC_PRIO_BITS 2 /*!< Number of bits used for Priority Levels */
|
#define __NVIC_PRIO_BITS 2 /*!< Number of bits used for Priority Levels */
|
||||||
|
|
|
||||||
|
|
@ -226,11 +226,7 @@ void I2S_Handler ( void );
|
||||||
* \brief Configuration of the Cortex-M0+ Processor and Core Peripherals
|
* \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
|
#define LITTLE_ENDIAN 1
|
||||||
#endif
|
|
||||||
#define __CM0PLUS_REV 1 /*!< Core revision r0p1 */
|
#define __CM0PLUS_REV 1 /*!< Core revision r0p1 */
|
||||||
#define __MPU_PRESENT 0 /*!< MPU present or not */
|
#define __MPU_PRESENT 0 /*!< MPU present or not */
|
||||||
#define __NVIC_PRIO_BITS 2 /*!< Number of bits used for Priority Levels */
|
#define __NVIC_PRIO_BITS 2 /*!< Number of bits used for Priority Levels */
|
||||||
|
|
|
||||||
|
|
@ -226,11 +226,7 @@ void I2S_Handler ( void );
|
||||||
* \brief Configuration of the Cortex-M0+ Processor and Core Peripherals
|
* \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
|
#define LITTLE_ENDIAN 1
|
||||||
#endif
|
|
||||||
#define __CM0PLUS_REV 1 /*!< Core revision r0p1 */
|
#define __CM0PLUS_REV 1 /*!< Core revision r0p1 */
|
||||||
#define __MPU_PRESENT 0 /*!< MPU present or not */
|
#define __MPU_PRESENT 0 /*!< MPU present or not */
|
||||||
#define __NVIC_PRIO_BITS 2 /*!< Number of bits used for Priority Levels */
|
#define __NVIC_PRIO_BITS 2 /*!< Number of bits used for Priority Levels */
|
||||||
|
|
|
||||||
|
|
@ -226,11 +226,7 @@ void I2S_Handler ( void );
|
||||||
* \brief Configuration of the Cortex-M0+ Processor and Core Peripherals
|
* \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
|
#define LITTLE_ENDIAN 1
|
||||||
#endif
|
|
||||||
#define __CM0PLUS_REV 1 /*!< Core revision r0p1 */
|
#define __CM0PLUS_REV 1 /*!< Core revision r0p1 */
|
||||||
#define __MPU_PRESENT 0 /*!< MPU present or not */
|
#define __MPU_PRESENT 0 /*!< MPU present or not */
|
||||||
#define __NVIC_PRIO_BITS 2 /*!< Number of bits used for Priority Levels */
|
#define __NVIC_PRIO_BITS 2 /*!< Number of bits used for Priority Levels */
|
||||||
|
|
|
||||||
|
|
@ -226,11 +226,7 @@ void I2S_Handler ( void );
|
||||||
* \brief Configuration of the Cortex-M0+ Processor and Core Peripherals
|
* \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
|
#define LITTLE_ENDIAN 1
|
||||||
#endif
|
|
||||||
#define __CM0PLUS_REV 1 /*!< Core revision r0p1 */
|
#define __CM0PLUS_REV 1 /*!< Core revision r0p1 */
|
||||||
#define __MPU_PRESENT 0 /*!< MPU present or not */
|
#define __MPU_PRESENT 0 /*!< MPU present or not */
|
||||||
#define __NVIC_PRIO_BITS 2 /*!< Number of bits used for Priority Levels */
|
#define __NVIC_PRIO_BITS 2 /*!< Number of bits used for Priority Levels */
|
||||||
|
|
|
||||||
|
|
@ -20,35 +20,6 @@
|
||||||
#ifndef _BOARD_DEFINITIONS_H_
|
#ifndef _BOARD_DEFINITIONS_H_
|
||||||
#define _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
|
* If BOOT_DOUBLE_TAP_ADDRESS is defined the bootloader is started by
|
||||||
* quickly tapping two times on the reset button.
|
* quickly tapping two times on the reset button.
|
||||||
|
|
|
||||||
|
|
@ -1,86 +0,0 @@
|
||||||
/*
|
|
||||||
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,8 +25,5 @@ mv -v samd21_sam_ba_arduino_mkrwan1300.* ../mkrwan1300/
|
||||||
BOARD_ID=arduino_mkrwifi1010 NAME=samd21_sam_ba_arduino_mkrwifi1010 make clean all
|
BOARD_ID=arduino_mkrwifi1010 NAME=samd21_sam_ba_arduino_mkrwifi1010 make clean all
|
||||||
mv -v samd21_sam_ba_arduino_mkrwifi1010.* ../mkrwifi1010/
|
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!
|
echo Done building bootloaders!
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -97,33 +97,8 @@ void loop( void ) ;
|
||||||
#undef abs
|
#undef abs
|
||||||
#endif // abs
|
#endif // abs
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#define min(a,b) ((a)<(b)?(a):(b))
|
||||||
template<class T, class L>
|
#define max(a,b) ((a)>(b)?(a):(b))
|
||||||
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 abs(x) ((x)>0?(x):-(x))
|
||||||
#define constrain(amt,low,high) ((amt)<(low)?(low):((amt)>(high)?(high):(amt)))
|
#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))
|
#define round(x) ((x)>=0?(long)((x)+0.5):(long)((x)-0.5))
|
||||||
|
|
@ -149,14 +124,10 @@ void loop( void ) ;
|
||||||
#define digitalPinToInterrupt(P) ( P )
|
#define digitalPinToInterrupt(P) ( P )
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// USB
|
// USB Device
|
||||||
#ifdef USE_TINYUSB
|
|
||||||
#include "Adafruit_TinyUSB_Core.h"
|
|
||||||
#else
|
|
||||||
#include "USB/USBDesc.h"
|
#include "USB/USBDesc.h"
|
||||||
#include "USB/USBCore.h"
|
#include "USB/USBCore.h"
|
||||||
#include "USB/USBAPI.h"
|
#include "USB/USBAPI.h"
|
||||||
#include "USB/USB_host.h"
|
#include "USB/USB_host.h"
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif // Arduino_h
|
#endif // Arduino_h
|
||||||
|
|
|
||||||
|
|
@ -68,7 +68,7 @@ class HardwareSerial : public Stream
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
virtual void begin(unsigned long) {}
|
virtual void begin(unsigned long) {}
|
||||||
virtual void begin(unsigned long, uint16_t) {}
|
virtual void begin(unsigned long baudrate, uint16_t config) {}
|
||||||
virtual void end() {}
|
virtual void end() {}
|
||||||
virtual int available(void) = 0;
|
virtual int available(void) = 0;
|
||||||
virtual int peek(void) = 0;
|
virtual int peek(void) = 0;
|
||||||
|
|
|
||||||
|
|
@ -186,16 +186,6 @@ size_t Print::println(const Printable& x)
|
||||||
return n;
|
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 /////////////////////////////////////////////////////////////
|
// Private Methods /////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
size_t Print::printNumber(unsigned long n, uint8_t base)
|
size_t Print::printNumber(unsigned long n, uint8_t base)
|
||||||
|
|
@ -248,14 +238,14 @@ size_t Print::printFloat(double number, uint8_t digits)
|
||||||
|
|
||||||
// Print the decimal point, but only if there are digits beyond
|
// Print the decimal point, but only if there are digits beyond
|
||||||
if (digits > 0) {
|
if (digits > 0) {
|
||||||
n += print(".");
|
n += print('.');
|
||||||
}
|
}
|
||||||
|
|
||||||
// Extract digits from the remainder one at a time
|
// Extract digits from the remainder one at a time
|
||||||
while (digits-- > 0)
|
while (digits-- > 0)
|
||||||
{
|
{
|
||||||
remainder *= 10.0;
|
remainder *= 10.0;
|
||||||
unsigned int toPrint = (unsigned int)remainder;
|
unsigned int toPrint = (unsigned int)(remainder);
|
||||||
n += print(toPrint);
|
n += print(toPrint);
|
||||||
remainder -= toPrint;
|
remainder -= toPrint;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -21,8 +21,6 @@
|
||||||
|
|
||||||
#include <inttypes.h>
|
#include <inttypes.h>
|
||||||
#include <stdio.h> // for size_t
|
#include <stdio.h> // for size_t
|
||||||
#include <stdarg.h> // for printf
|
|
||||||
#define PRINTF_BUF 80
|
|
||||||
|
|
||||||
#include "WString.h"
|
#include "WString.h"
|
||||||
#include "Printable.h"
|
#include "Printable.h"
|
||||||
|
|
@ -30,6 +28,9 @@
|
||||||
#define DEC 10
|
#define DEC 10
|
||||||
#define HEX 16
|
#define HEX 16
|
||||||
#define OCT 8
|
#define OCT 8
|
||||||
|
#ifdef BIN // Prevent warnings if BIN is previously defined in "iotnx4.h" or similar
|
||||||
|
#undef BIN
|
||||||
|
#endif
|
||||||
#define BIN 2
|
#define BIN 2
|
||||||
|
|
||||||
class Print
|
class Print
|
||||||
|
|
@ -85,8 +86,6 @@ class Print
|
||||||
size_t println(const Printable&);
|
size_t println(const Printable&);
|
||||||
size_t println(void);
|
size_t println(void);
|
||||||
|
|
||||||
void printf(const char[], ...);
|
|
||||||
|
|
||||||
virtual void flush() { /* Empty implementation for backward compatibility */ }
|
virtual void flush() { /* Empty implementation for backward compatibility */ }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -27,10 +27,7 @@
|
||||||
// using a ring buffer (I think), in which head is the index of the location
|
// 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
|
// to which to write the next incoming character and tail is the index of the
|
||||||
// location from which to read.
|
// location from which to read.
|
||||||
|
#define SERIAL_BUFFER_SIZE 164
|
||||||
#ifndef SERIAL_BUFFER_SIZE
|
|
||||||
#define SERIAL_BUFFER_SIZE 350
|
|
||||||
#endif
|
|
||||||
|
|
||||||
template <int N>
|
template <int N>
|
||||||
class RingBufferN
|
class RingBufferN
|
||||||
|
|
|
||||||
|
|
@ -30,24 +30,6 @@
|
||||||
SERCOM::SERCOM(Sercom* s)
|
SERCOM::SERCOM(Sercom* s)
|
||||||
{
|
{
|
||||||
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__
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* =========================
|
/* =========================
|
||||||
|
|
@ -93,15 +75,13 @@ void SERCOM::initUART(SercomUartMode mode, SercomUartSampleRate sampleRate, uint
|
||||||
void SERCOM::initFrame(SercomUartCharSize charSize, SercomDataOrder dataOrder, SercomParityMode parityMode, SercomNumberStopBit nbStopBits)
|
void SERCOM::initFrame(SercomUartCharSize charSize, SercomDataOrder dataOrder, SercomParityMode parityMode, SercomNumberStopBit nbStopBits)
|
||||||
{
|
{
|
||||||
//Setting the CTRLA register
|
//Setting the CTRLA register
|
||||||
sercom->USART.CTRLA.reg |=
|
sercom->USART.CTRLA.reg |= SERCOM_USART_CTRLA_FORM( (parityMode == SERCOM_NO_PARITY ? 0 : 1) ) |
|
||||||
SERCOM_USART_CTRLA_FORM((parityMode == SERCOM_NO_PARITY ? 0 : 1) ) |
|
|
||||||
dataOrder << SERCOM_USART_CTRLA_DORD_Pos;
|
dataOrder << SERCOM_USART_CTRLA_DORD_Pos;
|
||||||
|
|
||||||
//Setting the CTRLB register
|
//Setting the CTRLB register
|
||||||
sercom->USART.CTRLB.reg |= SERCOM_USART_CTRLB_CHSIZE(charSize) |
|
sercom->USART.CTRLB.reg |= SERCOM_USART_CTRLB_CHSIZE(charSize) |
|
||||||
nbStopBits << SERCOM_USART_CTRLB_SBMODE_Pos |
|
nbStopBits << SERCOM_USART_CTRLB_SBMODE_Pos |
|
||||||
(parityMode == SERCOM_NO_PARITY ? 0 : parityMode) <<
|
(parityMode == SERCOM_NO_PARITY ? 0 : parityMode) << SERCOM_USART_CTRLB_PMODE_Pos; //If no parity use default value
|
||||||
SERCOM_USART_CTRLB_PMODE_Pos; //If no parity use default value
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void SERCOM::initPads(SercomUartTXPad txPad, SercomRXPad rxPad)
|
void SERCOM::initPads(SercomUartTXPad txPad, SercomRXPad rxPad)
|
||||||
|
|
@ -248,6 +228,7 @@ void SERCOM::initSPI(SercomSpiTXPad mosi, SercomRXPad miso, SercomSpiCharSize ch
|
||||||
SERCOM_SPI_CTRLB_RXEN; //Active the SPI receiver.
|
SERCOM_SPI_CTRLB_RXEN; //Active the SPI receiver.
|
||||||
|
|
||||||
while( sercom->SPI.SYNCBUSY.bit.CTRLB == 1 );
|
while( sercom->SPI.SYNCBUSY.bit.CTRLB == 1 );
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void SERCOM::initSPIClock(SercomSpiClockMode clockMode, uint32_t baudrate)
|
void SERCOM::initSPIClock(SercomSpiClockMode clockMode, uint32_t baudrate)
|
||||||
|
|
@ -321,13 +302,14 @@ SercomDataOrder SERCOM::getDataOrderSPI()
|
||||||
|
|
||||||
void SERCOM::setBaudrateSPI(uint8_t divider)
|
void SERCOM::setBaudrateSPI(uint8_t divider)
|
||||||
{
|
{
|
||||||
disableSPI(); // Register is enable-protected
|
//Can't divide by 0
|
||||||
|
if(divider == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
#if defined(__SAMD51__)
|
//Register enable-protected
|
||||||
sercom->SPI.BAUD.reg = calculateBaudrateSynchronous(freqRef / divider);
|
disableSPI();
|
||||||
#else
|
|
||||||
sercom->SPI.BAUD.reg = calculateBaudrateSynchronous(SERCOM_SPI_FREQ_REF / divider);
|
sercom->SPI.BAUD.reg = calculateBaudrateSynchronous( SERCOM_FREQ_REF / divider );
|
||||||
#endif
|
|
||||||
|
|
||||||
enableSPI();
|
enableSPI();
|
||||||
}
|
}
|
||||||
|
|
@ -358,7 +340,10 @@ uint8_t SERCOM::transferDataSPI(uint8_t data)
|
||||||
{
|
{
|
||||||
sercom->SPI.DATA.bit.DATA = data; // Writing data into Data register
|
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
|
return sercom->SPI.DATA.bit.DATA; // Reading data
|
||||||
}
|
}
|
||||||
|
|
@ -386,14 +371,9 @@ bool SERCOM::isDataRegisterEmptySPI()
|
||||||
// return sercom->SPI.INTFLAG.bit.RXC;
|
// return sercom->SPI.INTFLAG.bit.RXC;
|
||||||
//}
|
//}
|
||||||
|
|
||||||
uint8_t SERCOM::calculateBaudrateSynchronous(uint32_t baudrate) {
|
uint8_t SERCOM::calculateBaudrateSynchronous(uint32_t baudrate)
|
||||||
#if defined(__SAMD51__)
|
{
|
||||||
uint16_t b = freqRef / (2 * baudrate);
|
return SERCOM_FREQ_REF / (2 * baudrate) - 1;
|
||||||
#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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -537,18 +517,8 @@ bool SERCOM::startTransmissionWIRE(uint8_t address, SercomWireReadWriteFlag flag
|
||||||
// 7-bits address + 1-bits R/W
|
// 7-bits address + 1-bits R/W
|
||||||
address = (address << 0x1ul) | flag;
|
address = (address << 0x1ul) | flag;
|
||||||
|
|
||||||
// If another master owns the bus or the last bus owner has not properly
|
// Wait idle or owner bus mode
|
||||||
// sent a stop, return failure early. This will prevent some misbehaved
|
while ( !isBusIdleWIRE() && !isBusOwnerWIRE() );
|
||||||
// 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
|
// Send start and address
|
||||||
sercom->I2CM.ADDR.bit.ADDR = address;
|
sercom->I2CM.ADDR.bit.ADDR = address;
|
||||||
|
|
@ -644,21 +614,6 @@ bool SERCOM::isBusOwnerWIRE( void )
|
||||||
return sercom->I2CM.STATUS.bit.BUSSTATE == WIRE_OWNER_STATE;
|
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 )
|
bool SERCOM::isDataReadyWIRE( void )
|
||||||
{
|
{
|
||||||
return sercom->I2CS.INTFLAG.bit.DRDY;
|
return sercom->I2CS.INTFLAG.bit.DRDY;
|
||||||
|
|
@ -714,152 +669,199 @@ 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 )
|
void SERCOM::initClockNVIC( void )
|
||||||
{
|
{
|
||||||
int8_t idx = getSercomIndex();
|
|
||||||
if(idx < 0) return; // We got a problem here
|
|
||||||
|
|
||||||
#if defined(__SAMD51__)
|
#if defined(__SAMD51__)
|
||||||
|
uint32_t clk_core;
|
||||||
|
uint32_t clk_slow;
|
||||||
|
|
||||||
for(uint8_t i=0; i<4; i++) {
|
if(sercom == SERCOM0)
|
||||||
NVIC_ClearPendingIRQ(sercomData[idx].irq[i]);
|
{
|
||||||
NVIC_SetPriority(sercomData[idx].irq[i], SERCOM_NVIC_PRIORITY);
|
clk_core = SERCOM0_GCLK_ID_CORE;
|
||||||
NVIC_EnableIRQ(sercomData[idx].irq[i]);
|
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);
|
||||||
}
|
}
|
||||||
|
else if(sercom == SERCOM1)
|
||||||
|
{
|
||||||
|
clk_core = SERCOM1_GCLK_ID_CORE;
|
||||||
|
clk_slow = SERCOM1_GCLK_ID_SLOW;
|
||||||
|
|
||||||
// SPI DMA speed is dictated by the "slow clock" (I think...maybe) so
|
NVIC_ClearPendingIRQ(SERCOM1_0_IRQn);
|
||||||
// BOTH are set to the same clock source (clk_slow isn't sourced from
|
NVIC_ClearPendingIRQ(SERCOM1_1_IRQn);
|
||||||
// XOSC32K as in prior versions of SAMD core).
|
NVIC_ClearPendingIRQ(SERCOM1_2_IRQn);
|
||||||
// This might have power implications for sleep code.
|
NVIC_ClearPendingIRQ(SERCOM1_3_IRQn);
|
||||||
|
|
||||||
setClockSource(idx, clockSource, true); // true = core clock
|
NVIC_SetPriority (SERCOM1_0_IRQn, (1<<__NVIC_PRIO_BITS) - 1); /* set Priority */
|
||||||
setClockSource(idx, clockSource, false); // false = slow clock
|
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);
|
||||||
|
|
||||||
#else // end if SAMD51 (prob SAMD21)
|
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;
|
||||||
|
|
||||||
uint8_t clockId = sercomData[idx].clock;
|
NVIC_ClearPendingIRQ(SERCOM2_0_IRQn);
|
||||||
IRQn_Type IdNvic = sercomData[idx].irqn;
|
NVIC_ClearPendingIRQ(SERCOM2_1_IRQn);
|
||||||
|
NVIC_ClearPendingIRQ(SERCOM2_2_IRQn);
|
||||||
|
NVIC_ClearPendingIRQ(SERCOM2_3_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
|
// Setting NVIC
|
||||||
NVIC_ClearPendingIRQ(IdNvic);
|
NVIC_ClearPendingIRQ(IdNvic);
|
||||||
NVIC_SetPriority(IdNvic, SERCOM_NVIC_PRIORITY);
|
NVIC_SetPriority (IdNvic, (1<<__NVIC_PRIO_BITS) - 1); /* set Priority */
|
||||||
NVIC_EnableIRQ(IdNvic);
|
NVIC_EnableIRQ(IdNvic);
|
||||||
|
|
||||||
//Setting clock
|
//Setting clock
|
||||||
GCLK->CLKCTRL.reg =
|
GCLK->CLKCTRL.reg = GCLK_CLKCTRL_ID( clockId ) | // Generic Clock 0 (SERCOMx)
|
||||||
GCLK_CLKCTRL_ID( clockId ) | // Generic Clock 0 (SERCOMx)
|
|
||||||
GCLK_CLKCTRL_GEN_GCLK0 | // Generic Clock Generator 0 is source
|
GCLK_CLKCTRL_GEN_GCLK0 | // Generic Clock Generator 0 is source
|
||||||
GCLK_CLKCTRL_CLKEN ;
|
GCLK_CLKCTRL_CLKEN ;
|
||||||
|
|
||||||
while(GCLK->STATUS.reg & GCLK_STATUS_SYNCBUSY); // Wait for synchronization
|
while ( GCLK->STATUS.reg & GCLK_STATUS_SYNCBUSY )
|
||||||
|
{
|
||||||
#endif // end !SAMD51
|
/* Wait for synchronization */
|
||||||
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -21,17 +21,6 @@
|
||||||
|
|
||||||
#include "sam.h"
|
#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_FREQ_REF 48000000ul
|
||||||
#define SERCOM_NVIC_PRIORITY ((1<<__NVIC_PRIO_BITS) - 1)
|
#define SERCOM_NVIC_PRIORITY ((1<<__NVIC_PRIO_BITS) - 1)
|
||||||
|
|
||||||
|
|
@ -152,19 +141,6 @@ typedef enum
|
||||||
WIRE_MASTER_NACK_ACTION
|
WIRE_MASTER_NACK_ACTION
|
||||||
} SercomMasterAckActionWire;
|
} 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
|
class SERCOM
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
@ -195,6 +171,7 @@ class SERCOM
|
||||||
/* ========== SPI ========== */
|
/* ========== SPI ========== */
|
||||||
void initSPI(SercomSpiTXPad mosi, SercomRXPad miso, SercomSpiCharSize charSize, SercomDataOrder dataOrder) ;
|
void initSPI(SercomSpiTXPad mosi, SercomRXPad miso, SercomSpiCharSize charSize, SercomDataOrder dataOrder) ;
|
||||||
void initSPIClock(SercomSpiClockMode clockMode, uint32_t baudrate) ;
|
void initSPIClock(SercomSpiClockMode clockMode, uint32_t baudrate) ;
|
||||||
|
|
||||||
void resetSPI( void ) ;
|
void resetSPI( void ) ;
|
||||||
void enableSPI( void ) ;
|
void enableSPI( void ) ;
|
||||||
void disableSPI( void ) ;
|
void disableSPI( void ) ;
|
||||||
|
|
@ -225,9 +202,6 @@ class SERCOM
|
||||||
bool isSlaveWIRE( void ) ;
|
bool isSlaveWIRE( void ) ;
|
||||||
bool isBusIdleWIRE( void ) ;
|
bool isBusIdleWIRE( void ) ;
|
||||||
bool isBusOwnerWIRE( void ) ;
|
bool isBusOwnerWIRE( void ) ;
|
||||||
bool isBusUnknownWIRE( void ) ;
|
|
||||||
bool isArbLostWIRE( void );
|
|
||||||
bool isBusBusyWIRE( void );
|
|
||||||
bool isDataReadyWIRE( void ) ;
|
bool isDataReadyWIRE( void ) ;
|
||||||
bool isStopDetectedWIRE( void ) ;
|
bool isStopDetectedWIRE( void ) ;
|
||||||
bool isRestartDetectedWIRE( void ) ;
|
bool isRestartDetectedWIRE( void ) ;
|
||||||
|
|
@ -236,29 +210,9 @@ class SERCOM
|
||||||
bool isRXNackReceivedWIRE( void ) ;
|
bool isRXNackReceivedWIRE( void ) ;
|
||||||
int availableWIRE( void ) ;
|
int availableWIRE( void ) ;
|
||||||
uint8_t readDataWIRE( 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:
|
private:
|
||||||
Sercom* sercom;
|
Sercom* sercom;
|
||||||
#if defined(__SAMD51__)
|
|
||||||
SercomClockSource clockSource;
|
|
||||||
uint32_t freqRef; // Frequency corresponding to clockSource
|
|
||||||
#endif
|
|
||||||
uint8_t calculateBaudrateSynchronous(uint32_t baudrate) ;
|
uint8_t calculateBaudrateSynchronous(uint32_t baudrate) ;
|
||||||
uint32_t division(uint32_t dividend, uint32_t divisor) ;
|
uint32_t division(uint32_t dividend, uint32_t divisor) ;
|
||||||
void initClockNVIC( void ) ;
|
void initClockNVIC( void ) ;
|
||||||
|
|
|
||||||
|
|
@ -35,7 +35,6 @@ int Stream::timedRead()
|
||||||
do {
|
do {
|
||||||
c = read();
|
c = read();
|
||||||
if (c >= 0) return c;
|
if (c >= 0) return c;
|
||||||
yield(); // running TinyUSB task
|
|
||||||
} while(millis() - _startMillis < _timeout);
|
} while(millis() - _startMillis < _timeout);
|
||||||
return -1; // -1 indicates timeout
|
return -1; // -1 indicates timeout
|
||||||
}
|
}
|
||||||
|
|
@ -48,7 +47,6 @@ int Stream::timedPeek()
|
||||||
do {
|
do {
|
||||||
c = peek();
|
c = peek();
|
||||||
if (c >= 0) return c;
|
if (c >= 0) return c;
|
||||||
yield(); // running TinyUSB task
|
|
||||||
} while(millis() - _startMillis < _timeout);
|
} while(millis() - _startMillis < _timeout);
|
||||||
return -1; // -1 indicates timeout
|
return -1; // -1 indicates timeout
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1 +0,0 @@
|
||||||
Subproject commit e7b892095f2bb5d8bef6a748238369bdd268ed5e
|
|
||||||
|
|
@ -1,195 +0,0 @@
|
||||||
/*
|
|
||||||
* 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
|
|
||||||
|
|
@ -1,93 +0,0 @@
|
||||||
/*
|
|
||||||
* 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,6 +20,12 @@
|
||||||
#include "Tone.h"
|
#include "Tone.h"
|
||||||
#include "variant.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 toneMaxFrequency = F_CPU / 2;
|
||||||
uint32_t lastOutputPin = 0xFFFFFFFF;
|
uint32_t lastOutputPin = 0xFFFFFFFF;
|
||||||
|
|
||||||
|
|
@ -31,24 +37,22 @@ volatile bool toneIsActive = false;
|
||||||
volatile bool firstTimeRunning = false;
|
volatile bool firstTimeRunning = false;
|
||||||
|
|
||||||
#if defined(__SAMD51__)
|
#if defined(__SAMD51__)
|
||||||
#define TONE_TC TC0
|
#define TONE_TC TC2
|
||||||
#define TONE_TC_IRQn TC0_IRQn
|
#define TONE_TC_IRQn TC2_IRQn
|
||||||
#define TONE_TC_GCLK_ID TC0_GCLK_ID
|
#define TONE_TC_GCLK_ID TC2_GCLK_ID
|
||||||
#define Tone_Handler TC0_Handler
|
|
||||||
|
|
||||||
#define WAIT_TC16_REGS_SYNC(x) while(x->COUNT16.SYNCBUSY.bit.ENABLE);
|
|
||||||
|
|
||||||
#else
|
#else
|
||||||
#define TONE_TC TC5
|
#define TONE_TC TC5
|
||||||
#define TONE_TC_IRQn TC5_IRQn
|
#define TONE_TC_IRQn TC5_IRQn
|
||||||
#define Tone_Handler TC5_Handler
|
|
||||||
|
|
||||||
#define WAIT_TC16_REGS_SYNC(x) while(x->COUNT16.STATUS.bit.SYNCBUSY);
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define TONE_TC_TOP 0xFFFF
|
#define TONE_TC_TOP 0xFFFF
|
||||||
#define TONE_TC_CHANNEL 0
|
#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)
|
static inline void resetTC (Tc* TCx)
|
||||||
{
|
{
|
||||||
// Disable TCx
|
// Disable TCx
|
||||||
|
|
@ -68,14 +72,6 @@ void toneAccurateClock (uint32_t accurateSystemCoreClockFrequency)
|
||||||
|
|
||||||
void tone (uint32_t outputPin, uint32_t frequency, uint32_t duration)
|
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
|
// Configure interrupt request
|
||||||
NVIC_DisableIRQ(TONE_TC_IRQn);
|
NVIC_DisableIRQ(TONE_TC_IRQn);
|
||||||
NVIC_ClearPendingIRQ(TONE_TC_IRQn);
|
NVIC_ClearPendingIRQ(TONE_TC_IRQn);
|
||||||
|
|
@ -84,7 +80,7 @@ void tone (uint32_t outputPin, uint32_t frequency, uint32_t duration)
|
||||||
{
|
{
|
||||||
firstTimeRunning = true;
|
firstTimeRunning = true;
|
||||||
|
|
||||||
NVIC_SetPriority(TONE_TC_IRQn, 5);
|
NVIC_SetPriority(TONE_TC_IRQn, 0);
|
||||||
|
|
||||||
#if defined(__SAMD51__)
|
#if defined(__SAMD51__)
|
||||||
GCLK->PCHCTRL[TONE_TC_GCLK_ID].reg = GCLK_PCHCTRL_GEN_GCLK0_Val | (1 << GCLK_PCHCTRL_CHEN_Pos);
|
GCLK->PCHCTRL[TONE_TC_GCLK_ID].reg = GCLK_PCHCTRL_GEN_GCLK0_Val | (1 << GCLK_PCHCTRL_CHEN_Pos);
|
||||||
|
|
@ -95,6 +91,9 @@ void tone (uint32_t outputPin, uint32_t frequency, uint32_t duration)
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//if it's a rest, set to 1Hz (below audio range)
|
||||||
|
frequency = (frequency > 0 ? frequency : 1);
|
||||||
|
|
||||||
if (toneIsActive && (outputPin != lastOutputPin))
|
if (toneIsActive && (outputPin != lastOutputPin))
|
||||||
noTone(lastOutputPin);
|
noTone(lastOutputPin);
|
||||||
|
|
||||||
|
|
@ -137,7 +136,7 @@ void tone (uint32_t outputPin, uint32_t frequency, uint32_t duration)
|
||||||
default: break;
|
default: break;
|
||||||
}
|
}
|
||||||
|
|
||||||
toggleCount = (duration > 0 ? frequency * duration * 2 / 1000UL : -1LL);
|
toggleCount = (duration > 0 ? frequency * duration * 2 / 1000UL : -1);
|
||||||
|
|
||||||
resetTC(TONE_TC);
|
resetTC(TONE_TC);
|
||||||
|
|
||||||
|
|
@ -179,21 +178,11 @@ void tone (uint32_t outputPin, uint32_t frequency, uint32_t duration)
|
||||||
}
|
}
|
||||||
|
|
||||||
void noTone (uint32_t outputPin)
|
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);
|
resetTC(TONE_TC);
|
||||||
digitalWrite(outputPin, LOW);
|
digitalWrite(outputPin, LOW);
|
||||||
toneIsActive = false;
|
toneIsActive = false;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C" {
|
||||||
|
|
|
||||||
|
|
@ -16,8 +16,6 @@
|
||||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef USE_TINYUSB
|
|
||||||
|
|
||||||
#include <Arduino.h>
|
#include <Arduino.h>
|
||||||
#include <Reset.h> // Needed for auto-reset with 1200bps port touch
|
#include <Reset.h> // Needed for auto-reset with 1200bps port touch
|
||||||
|
|
||||||
|
|
@ -152,7 +150,6 @@ void Serial_::begin(uint32_t /* baud_count */, uint8_t /* config */)
|
||||||
|
|
||||||
void Serial_::end(void)
|
void Serial_::end(void)
|
||||||
{
|
{
|
||||||
memset((void*)&_usbLineInfo, 0, sizeof(_usbLineInfo));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int Serial_::available(void)
|
int Serial_::available(void)
|
||||||
|
|
@ -262,5 +259,3 @@ Serial_::operator bool()
|
||||||
Serial_ Serial(USBDevice);
|
Serial_ Serial(USBDevice);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#endif // USE_TINYUSB
|
|
||||||
|
|
|
||||||
|
|
@ -17,8 +17,6 @@
|
||||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef USE_TINYUSB
|
|
||||||
|
|
||||||
#include "USBAPI.h"
|
#include "USBAPI.h"
|
||||||
#include "USBDesc.h"
|
#include "USBDesc.h"
|
||||||
#include "USBCore.h"
|
#include "USBCore.h"
|
||||||
|
|
@ -116,5 +114,3 @@ PluggableUSB_::PluggableUSB_() : lastIf(CDC_ACM_INTERFACE + CDC_INTERFACE_COUNT)
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#endif // USE_TINYUSB
|
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,6 @@
|
||||||
* Author: deanm
|
* Author: deanm
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef USE_TINYUSB
|
|
||||||
|
|
||||||
#include "SAMD21_USBDevice.h"
|
#include "SAMD21_USBDevice.h"
|
||||||
|
|
||||||
|
|
@ -37,5 +36,3 @@ void USBDevice_SAMD21G18x::calibrate() {
|
||||||
usb.PADCAL.bit.TRANSP = pad_transp;
|
usb.PADCAL.bit.TRANSP = pad_transp;
|
||||||
usb.PADCAL.bit.TRIM = pad_trim;
|
usb.PADCAL.bit.TRIM = pad_trim;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif // USE_TINYUSB
|
|
||||||
|
|
|
||||||
|
|
@ -237,7 +237,7 @@ public:
|
||||||
release();
|
release();
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual ~DoubleBufferedEPOutHandler() {
|
~DoubleBufferedEPOutHandler() {
|
||||||
free((void*)data0);
|
free((void*)data0);
|
||||||
free((void*)data1);
|
free((void*)data1);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -24,174 +24,7 @@
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
typedef uint8_t ep_t;
|
|
||||||
|
|
||||||
class USBDevice_SAMR21G18x {
|
#include "SAMD21_USBDevice.h"
|
||||||
public:
|
|
||||||
USBDevice_SAMR21G18x() : usb(USB->DEVICE) {
|
|
||||||
// Empty
|
|
||||||
}
|
|
||||||
|
|
||||||
// USB Device function mapping
|
|
||||||
// ---------------------------
|
|
||||||
|
|
||||||
// Reset USB Device
|
|
||||||
void reset();
|
|
||||||
|
|
||||||
// Enable
|
|
||||||
inline void enable() { usb.CTRLA.bit.ENABLE = 1; }
|
|
||||||
inline void disable() { usb.CTRLA.bit.ENABLE = 0; }
|
|
||||||
|
|
||||||
// USB mode (device/host)
|
|
||||||
inline void setUSBDeviceMode() { usb.CTRLA.bit.MODE = USB_CTRLA_MODE_DEVICE_Val; }
|
|
||||||
inline void setUSBHostMode() { usb.CTRLA.bit.MODE = USB_CTRLA_MODE_HOST_Val; }
|
|
||||||
|
|
||||||
inline void runInStandby() { usb.CTRLA.bit.RUNSTDBY = 1; }
|
|
||||||
inline void noRunInStandby() { usb.CTRLA.bit.RUNSTDBY = 0; }
|
|
||||||
|
|
||||||
// USB speed
|
|
||||||
inline void setFullSpeed() { usb.CTRLB.bit.SPDCONF = USB_DEVICE_CTRLB_SPDCONF_FS_Val; }
|
|
||||||
inline void setLowSpeed() { usb.CTRLB.bit.SPDCONF = USB_DEVICE_CTRLB_SPDCONF_LS_Val; }
|
|
||||||
inline void setHiSpeed() { usb.CTRLB.bit.SPDCONF = USB_DEVICE_CTRLB_SPDCONF_HS_Val; }
|
|
||||||
inline void setHiSpeedTestMode() { usb.CTRLB.bit.SPDCONF = USB_DEVICE_CTRLB_SPDCONF_HSTM_Val; }
|
|
||||||
|
|
||||||
// Authorize attach if Vbus is present
|
|
||||||
inline void attach() { usb.CTRLB.bit.DETACH = 0; }
|
|
||||||
inline void detach() { usb.CTRLB.bit.DETACH = 1; }
|
|
||||||
|
|
||||||
// USB Interrupts
|
|
||||||
inline bool isEndOfResetInterrupt() { return usb.INTFLAG.bit.EORST; }
|
|
||||||
inline void ackEndOfResetInterrupt() { usb.INTFLAG.reg = USB_DEVICE_INTFLAG_EORST; }
|
|
||||||
inline void enableEndOfResetInterrupt() { usb.INTENSET.bit.EORST = 1; }
|
|
||||||
inline void disableEndOfResetInterrupt() { usb.INTENCLR.bit.EORST = 1; }
|
|
||||||
|
|
||||||
inline bool isStartOfFrameInterrupt() { return usb.INTFLAG.bit.SOF; }
|
|
||||||
inline void ackStartOfFrameInterrupt() { usb.INTFLAG.reg = USB_DEVICE_INTFLAG_SOF; }
|
|
||||||
inline void enableStartOfFrameInterrupt() { usb.INTENSET.bit.SOF = 1; }
|
|
||||||
inline void disableStartOfFrameInterrupt() { usb.INTENCLR.bit.SOF = 1; }
|
|
||||||
|
|
||||||
// USB Address
|
|
||||||
inline void setAddress(uint32_t addr) { usb.DADD.bit.DADD = addr; usb.DADD.bit.ADDEN = 1; }
|
|
||||||
inline void unsetAddress() { usb.DADD.bit.DADD = 0; usb.DADD.bit.ADDEN = 0; }
|
|
||||||
|
|
||||||
// Frame number
|
|
||||||
inline uint16_t frameNumber() { return usb.FNUM.bit.FNUM; }
|
|
||||||
|
|
||||||
// Load calibration values
|
|
||||||
void calibrate();
|
|
||||||
|
|
||||||
// USB Device Endpoints function mapping
|
|
||||||
// -------------------------------------
|
|
||||||
|
|
||||||
// Config
|
|
||||||
inline void epBank0SetType(ep_t ep, uint8_t type) { usb.DeviceEndpoint[ep].EPCFG.bit.EPTYPE0 = type; }
|
|
||||||
inline void epBank1SetType(ep_t ep, uint8_t type) { usb.DeviceEndpoint[ep].EPCFG.bit.EPTYPE1 = type; }
|
|
||||||
|
|
||||||
// Interrupts
|
|
||||||
inline uint16_t epInterruptSummary() { return usb.EPINTSMRY.reg; }
|
|
||||||
|
|
||||||
inline bool epBank0IsSetupReceived(ep_t ep) { return usb.DeviceEndpoint[ep].EPINTFLAG.bit.RXSTP; }
|
|
||||||
inline bool epBank0IsStalled(ep_t ep) { return usb.DeviceEndpoint[ep].EPINTFLAG.bit.STALL0; }
|
|
||||||
inline bool epBank1IsStalled(ep_t ep) { return usb.DeviceEndpoint[ep].EPINTFLAG.bit.STALL1; }
|
|
||||||
inline bool epBank0IsTransferComplete(ep_t ep) { return usb.DeviceEndpoint[ep].EPINTFLAG.bit.TRCPT0; }
|
|
||||||
inline bool epBank1IsTransferComplete(ep_t ep) { return usb.DeviceEndpoint[ep].EPINTFLAG.bit.TRCPT1; }
|
|
||||||
|
|
||||||
inline void epBank0AckSetupReceived(ep_t ep) { usb.DeviceEndpoint[ep].EPINTFLAG.reg = USB_DEVICE_EPINTFLAG_RXSTP; }
|
|
||||||
inline void epBank0AckStalled(ep_t ep) { usb.DeviceEndpoint[ep].EPINTFLAG.reg = USB_DEVICE_EPINTFLAG_STALL(1); }
|
|
||||||
inline void epBank1AckStalled(ep_t ep) { usb.DeviceEndpoint[ep].EPINTFLAG.reg = USB_DEVICE_EPINTFLAG_STALL(2); }
|
|
||||||
inline void epBank0AckTransferComplete(ep_t ep) { usb.DeviceEndpoint[ep].EPINTFLAG.reg = USB_DEVICE_EPINTFLAG_TRCPT(1); }
|
|
||||||
inline void epBank1AckTransferComplete(ep_t ep) { usb.DeviceEndpoint[ep].EPINTFLAG.reg = USB_DEVICE_EPINTFLAG_TRCPT(2); }
|
|
||||||
|
|
||||||
inline void epBank0EnableSetupReceived(ep_t ep) { usb.DeviceEndpoint[ep].EPINTENSET.bit.RXSTP = 1; }
|
|
||||||
inline void epBank0EnableStalled(ep_t ep) { usb.DeviceEndpoint[ep].EPINTENSET.bit.STALL0 = 1; }
|
|
||||||
inline void epBank1EnableStalled(ep_t ep) { usb.DeviceEndpoint[ep].EPINTENSET.bit.STALL1 = 1; }
|
|
||||||
inline void epBank0EnableTransferComplete(ep_t ep) { usb.DeviceEndpoint[ep].EPINTENSET.bit.TRCPT0 = 1; }
|
|
||||||
inline void epBank1EnableTransferComplete(ep_t ep) { usb.DeviceEndpoint[ep].EPINTENSET.bit.TRCPT1 = 1; }
|
|
||||||
|
|
||||||
inline void epBank0DisableSetupReceived(ep_t ep) { usb.DeviceEndpoint[ep].EPINTENCLR.bit.RXSTP = 1; }
|
|
||||||
inline void epBank0DisableStalled(ep_t ep) { usb.DeviceEndpoint[ep].EPINTENCLR.bit.STALL0 = 1; }
|
|
||||||
inline void epBank1DisableStalled(ep_t ep) { usb.DeviceEndpoint[ep].EPINTENCLR.bit.STALL1 = 1; }
|
|
||||||
inline void epBank0DisableTransferComplete(ep_t ep) { usb.DeviceEndpoint[ep].EPINTENCLR.bit.TRCPT0 = 1; }
|
|
||||||
inline void epBank1DisableTransferComplete(ep_t ep) { usb.DeviceEndpoint[ep].EPINTENCLR.bit.TRCPT1 = 1; }
|
|
||||||
|
|
||||||
// Status
|
|
||||||
inline bool epBank0IsReady(ep_t ep) { return usb.DeviceEndpoint[ep].EPSTATUS.bit.BK0RDY; }
|
|
||||||
inline bool epBank1IsReady(ep_t ep) { return usb.DeviceEndpoint[ep].EPSTATUS.bit.BK1RDY; }
|
|
||||||
inline void epBank0SetReady(ep_t ep) { usb.DeviceEndpoint[ep].EPSTATUSSET.bit.BK0RDY = 1; }
|
|
||||||
inline void epBank1SetReady(ep_t ep) { usb.DeviceEndpoint[ep].EPSTATUSSET.bit.BK1RDY = 1; }
|
|
||||||
inline void epBank0ResetReady(ep_t ep) { usb.DeviceEndpoint[ep].EPSTATUSCLR.bit.BK0RDY = 1; }
|
|
||||||
inline void epBank1ResetReady(ep_t ep) { usb.DeviceEndpoint[ep].EPSTATUSCLR.bit.BK1RDY = 1; }
|
|
||||||
|
|
||||||
inline void epBank0SetStallReq(ep_t ep) { usb.DeviceEndpoint[ep].EPSTATUSSET.bit.STALLRQ0 = 1; }
|
|
||||||
inline void epBank1SetStallReq(ep_t ep) { usb.DeviceEndpoint[ep].EPSTATUSSET.bit.STALLRQ1 = 1; }
|
|
||||||
inline void epBank0ResetStallReq(ep_t ep) { usb.DeviceEndpoint[ep].EPSTATUSCLR.bit.STALLRQ0 = 1; }
|
|
||||||
inline void epBank1ResetStallReq(ep_t ep) { usb.DeviceEndpoint[ep].EPSTATUSCLR.bit.STALLRQ1 = 1; }
|
|
||||||
|
|
||||||
// Packet
|
|
||||||
inline uint16_t epBank0ByteCount(ep_t ep) { return EP[ep].DeviceDescBank[0].PCKSIZE.bit.BYTE_COUNT; }
|
|
||||||
inline uint16_t epBank1ByteCount(ep_t ep) { return EP[ep].DeviceDescBank[1].PCKSIZE.bit.BYTE_COUNT; }
|
|
||||||
inline void epBank0SetByteCount(ep_t ep, uint16_t bc) { EP[ep].DeviceDescBank[0].PCKSIZE.bit.BYTE_COUNT = bc; }
|
|
||||||
inline void epBank1SetByteCount(ep_t ep, uint16_t bc) { EP[ep].DeviceDescBank[1].PCKSIZE.bit.BYTE_COUNT = bc; }
|
|
||||||
inline void epBank0SetMultiPacketSize(ep_t ep, uint16_t s) { EP[ep].DeviceDescBank[0].PCKSIZE.bit.MULTI_PACKET_SIZE = s; }
|
|
||||||
inline void epBank1SetMultiPacketSize(ep_t ep, uint16_t s) { EP[ep].DeviceDescBank[1].PCKSIZE.bit.MULTI_PACKET_SIZE = s; }
|
|
||||||
|
|
||||||
inline void epBank0SetAddress(ep_t ep, void *addr) { EP[ep].DeviceDescBank[0].ADDR.reg = (uint32_t)addr; }
|
|
||||||
inline void epBank1SetAddress(ep_t ep, void *addr) { EP[ep].DeviceDescBank[1].ADDR.reg = (uint32_t)addr; }
|
|
||||||
inline void epBank0SetSize(ep_t ep, uint16_t size) { EP[ep].DeviceDescBank[0].PCKSIZE.bit.SIZE = EP_PCKSIZE_SIZE(size); }
|
|
||||||
inline void epBank1SetSize(ep_t ep, uint16_t size) { EP[ep].DeviceDescBank[1].PCKSIZE.bit.SIZE = EP_PCKSIZE_SIZE(size); }
|
|
||||||
inline uint8_t EP_PCKSIZE_SIZE(uint16_t size) {
|
|
||||||
switch (size) {
|
|
||||||
case 8: return 0;
|
|
||||||
case 16: return 1;
|
|
||||||
case 32: return 2;
|
|
||||||
case 64: return 3;
|
|
||||||
case 128: return 4;
|
|
||||||
case 256: return 5;
|
|
||||||
case 512: return 6;
|
|
||||||
case 1023: return 7;
|
|
||||||
default: return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void epBank0DisableAutoZLP(ep_t ep) { EP[ep].DeviceDescBank[0].PCKSIZE.bit.AUTO_ZLP = 0; }
|
|
||||||
inline void epBank1DisableAutoZLP(ep_t ep) { EP[ep].DeviceDescBank[1].PCKSIZE.bit.AUTO_ZLP = 0; }
|
|
||||||
inline void epBank0EnableAutoZLP(ep_t ep) { EP[ep].DeviceDescBank[0].PCKSIZE.bit.AUTO_ZLP = 1; }
|
|
||||||
inline void epBank1EnableAutoZLP(ep_t ep) { EP[ep].DeviceDescBank[1].PCKSIZE.bit.AUTO_ZLP = 1; }
|
|
||||||
|
|
||||||
private:
|
|
||||||
// USB Device registers
|
|
||||||
UsbDevice &usb;
|
|
||||||
|
|
||||||
// Endpoints descriptors table
|
|
||||||
__attribute__((__aligned__(4))) UsbDeviceDescriptor EP[USB_EPT_NUM];
|
|
||||||
};
|
|
||||||
|
|
||||||
void USBDevice_SAMR21G18x::reset() {
|
|
||||||
usb.CTRLA.bit.SWRST = 1;
|
|
||||||
memset(EP, 0, sizeof(EP));
|
|
||||||
while (usb.SYNCBUSY.bit.SWRST) {}
|
|
||||||
usb.DESCADD.reg = (uint32_t)(&EP);
|
|
||||||
}
|
|
||||||
|
|
||||||
void USBDevice_SAMR21G18x::calibrate() {
|
|
||||||
// Load Pad Calibration data from non-volatile memory
|
|
||||||
uint32_t *pad_transn_p = (uint32_t *) USB_FUSES_TRANSN_ADDR;
|
|
||||||
uint32_t *pad_transp_p = (uint32_t *) USB_FUSES_TRANSP_ADDR;
|
|
||||||
uint32_t *pad_trim_p = (uint32_t *) USB_FUSES_TRIM_ADDR;
|
|
||||||
|
|
||||||
uint32_t pad_transn = (*pad_transn_p & USB_FUSES_TRANSN_Msk) >> USB_FUSES_TRANSN_Pos;
|
|
||||||
uint32_t pad_transp = (*pad_transp_p & USB_FUSES_TRANSP_Msk) >> USB_FUSES_TRANSP_Pos;
|
|
||||||
uint32_t pad_trim = (*pad_trim_p & USB_FUSES_TRIM_Msk ) >> USB_FUSES_TRIM_Pos;
|
|
||||||
|
|
||||||
if (pad_transn == 0x1F) // maximum value (31)
|
|
||||||
pad_transn = 5;
|
|
||||||
if (pad_transp == 0x1F) // maximum value (31)
|
|
||||||
pad_transp = 29;
|
|
||||||
if (pad_trim == 0x7) // maximum value (7)
|
|
||||||
pad_trim = 3;
|
|
||||||
|
|
||||||
usb.PADCAL.bit.TRANSN = pad_transn;
|
|
||||||
usb.PADCAL.bit.TRANSP = pad_transp;
|
|
||||||
usb.PADCAL.bit.TRIM = pad_trim;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
typedef class USBDevice_SAMD21G18x USBDevice_SAMR21G18x;
|
||||||
|
|
|
||||||
|
|
@ -65,7 +65,6 @@ public:
|
||||||
|
|
||||||
// USB Device API
|
// USB Device API
|
||||||
void init();
|
void init();
|
||||||
bool end();
|
|
||||||
bool attach();
|
bool attach();
|
||||||
bool detach();
|
bool detach();
|
||||||
void setAddress(uint32_t addr);
|
void setAddress(uint32_t addr);
|
||||||
|
|
|
||||||
|
|
@ -16,7 +16,7 @@
|
||||||
License along with this library; if not, write to the Free Software
|
License along with this library; if not, write to the Free Software
|
||||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
*/
|
*/
|
||||||
#ifndef USE_TINYUSB
|
|
||||||
#if defined(USBCON)
|
#if defined(USBCON)
|
||||||
|
|
||||||
#include <Arduino.h>
|
#include <Arduino.h>
|
||||||
|
|
@ -244,25 +244,26 @@ bool USBDeviceClass::sendDescriptor(USBSetup &setup)
|
||||||
}
|
}
|
||||||
else if (setup.wValueL == ISERIAL) {
|
else if (setup.wValueL == ISERIAL) {
|
||||||
#ifdef PLUGGABLE_USB_ENABLED
|
#ifdef PLUGGABLE_USB_ENABLED
|
||||||
#ifdef __SAMD51__
|
#if defined(__SAMD51__)
|
||||||
#define SERIAL_NUMBER_WORD_0 *(volatile uint32_t*)(0x008061FC)
|
char name[ISERIAL_MAX_LEN];
|
||||||
#define SERIAL_NUMBER_WORD_1 *(volatile uint32_t*)(0x00806010)
|
PluggableUSB().getShortName(name);
|
||||||
#define SERIAL_NUMBER_WORD_2 *(volatile uint32_t*)(0x00806014)
|
return sendStringDescriptor((uint8_t*)name, setup.wLength);
|
||||||
#define SERIAL_NUMBER_WORD_3 *(volatile uint32_t*)(0x00806018)
|
#else
|
||||||
#else // samd21
|
|
||||||
// from section 9.3.3 of the datasheet
|
// from section 9.3.3 of the datasheet
|
||||||
#define SERIAL_NUMBER_WORD_0 *(volatile uint32_t*)(0x0080A00C)
|
#define SERIAL_NUMBER_WORD_0 *(volatile uint32_t*)(0x0080A00C)
|
||||||
#define SERIAL_NUMBER_WORD_1 *(volatile uint32_t*)(0x0080A040)
|
#define SERIAL_NUMBER_WORD_1 *(volatile uint32_t*)(0x0080A040)
|
||||||
#define SERIAL_NUMBER_WORD_2 *(volatile uint32_t*)(0x0080A044)
|
#define SERIAL_NUMBER_WORD_2 *(volatile uint32_t*)(0x0080A044)
|
||||||
#define SERIAL_NUMBER_WORD_3 *(volatile uint32_t*)(0x0080A048)
|
#define SERIAL_NUMBER_WORD_3 *(volatile uint32_t*)(0x0080A048)
|
||||||
#endif
|
|
||||||
char name[ISERIAL_MAX_LEN];
|
char name[ISERIAL_MAX_LEN];
|
||||||
utox8(SERIAL_NUMBER_WORD_0, &name[0]);
|
utox8(SERIAL_NUMBER_WORD_0, &name[0]);
|
||||||
utox8(SERIAL_NUMBER_WORD_1, &name[8]);
|
utox8(SERIAL_NUMBER_WORD_1, &name[8]);
|
||||||
utox8(SERIAL_NUMBER_WORD_2, &name[16]);
|
utox8(SERIAL_NUMBER_WORD_2, &name[16]);
|
||||||
utox8(SERIAL_NUMBER_WORD_3, &name[24]);
|
utox8(SERIAL_NUMBER_WORD_3, &name[24]);
|
||||||
name[32] = '\0';
|
|
||||||
|
PluggableUSB().getShortName(&name[32]);
|
||||||
return sendStringDescriptor((uint8_t*)name, setup.wLength);
|
return sendStringDescriptor((uint8_t*)name, setup.wLength);
|
||||||
|
#endif
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
|
@ -433,13 +434,6 @@ bool USBDeviceClass::detach()
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool USBDeviceClass::end() {
|
|
||||||
if (!initialized)
|
|
||||||
return false;
|
|
||||||
usbd.disable();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool USBDeviceClass::configured()
|
bool USBDeviceClass::configured()
|
||||||
{
|
{
|
||||||
return _usbConfiguration != 0;
|
return _usbConfiguration != 0;
|
||||||
|
|
@ -877,7 +871,6 @@ bool USBDeviceClass::handleStandardSetup(USBSetup &setup)
|
||||||
sendZlp(0);
|
sendZlp(0);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
|
||||||
|
|
||||||
case SET_ADDRESS:
|
case SET_ADDRESS:
|
||||||
setAddress(setup.wValueL);
|
setAddress(setup.wValueL);
|
||||||
|
|
@ -1039,4 +1032,3 @@ void USBDeviceClass::ISRHandler()
|
||||||
USBDeviceClass USBDevice;
|
USBDeviceClass USBDevice;
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
#endif // USE_TINYUSB
|
|
||||||
|
|
|
||||||
|
|
@ -101,7 +101,7 @@
|
||||||
// bMaxPower in Configuration Descriptor
|
// bMaxPower in Configuration Descriptor
|
||||||
#define USB_CONFIG_POWER_MA(mA) ((mA)/2)
|
#define USB_CONFIG_POWER_MA(mA) ((mA)/2)
|
||||||
#ifndef USB_CONFIG_POWER
|
#ifndef USB_CONFIG_POWER
|
||||||
#define USB_CONFIG_POWER (100)
|
#define USB_CONFIG_POWER (500)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define CDC_V1_10 0x0110
|
#define CDC_V1_10 0x0110
|
||||||
|
|
|
||||||
|
|
@ -17,7 +17,6 @@
|
||||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef USE_TINYUSB
|
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
@ -64,6 +63,7 @@ void UHD_Init(void)
|
||||||
uint32_t pad_transn;
|
uint32_t pad_transn;
|
||||||
uint32_t pad_transp;
|
uint32_t pad_transp;
|
||||||
uint32_t pad_trim;
|
uint32_t pad_trim;
|
||||||
|
uint32_t i;
|
||||||
|
|
||||||
USB_SetHandler(&UHD_Handler);
|
USB_SetHandler(&UHD_Handler);
|
||||||
|
|
||||||
|
|
@ -172,7 +172,10 @@ void UHD_Init(void)
|
||||||
USB->HOST.DESCADD.reg = (uint32_t)(&usb_pipe_table[0]);
|
USB->HOST.DESCADD.reg = (uint32_t)(&usb_pipe_table[0]);
|
||||||
// For USB_SPEED_FULL
|
// For USB_SPEED_FULL
|
||||||
uhd_force_full_speed();
|
uhd_force_full_speed();
|
||||||
memset((void *)usb_pipe_table, 0, sizeof(usb_pipe_table));
|
for (i = 0; i < sizeof(usb_pipe_table); i++)
|
||||||
|
{
|
||||||
|
(*(uint32_t *)(&usb_pipe_table[0] + i)) = 0;
|
||||||
|
}
|
||||||
|
|
||||||
uhd_state = UHD_STATE_NO_VBUS;
|
uhd_state = UHD_STATE_NO_VBUS;
|
||||||
|
|
||||||
|
|
@ -554,5 +557,3 @@ uint32_t UHD_Pipe_Is_Transfer_Complete(uint32_t ul_pipe, uint32_t ul_token_type)
|
||||||
// }
|
// }
|
||||||
|
|
||||||
#endif // HOST_DEFINED
|
#endif // HOST_DEFINED
|
||||||
|
|
||||||
#endif // USE_TINYUSB
|
|
||||||
|
|
|
||||||
|
|
@ -93,19 +93,31 @@ void attachInterrupt(uint32_t pin, voidFuncPtr callback, uint32_t mode)
|
||||||
__initialize();
|
__initialize();
|
||||||
enabled = 1;
|
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.
|
// Only store when there is really an ISR to call.
|
||||||
// This allow for calling attachInterrupt(pin, NULL, mode), we set up all needed register
|
// 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.
|
// but won't service the interrupt, this way we also don't need to check it inside the ISR.
|
||||||
if (callback)
|
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) {
|
if (in == EXTERNAL_INT_NMI) {
|
||||||
EIC->NMIFLAG.bit.NMI = 1; // Clear flag
|
EIC->NMIFLAG.bit.NMI = 1; // Clear flag
|
||||||
switch (mode) {
|
switch (mode) {
|
||||||
|
|
@ -135,41 +147,34 @@ void attachInterrupt(uint32_t pin, voidFuncPtr callback, uint32_t mode)
|
||||||
|
|
||||||
} else { // Not NMI, is external interrupt
|
} 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
|
// Assign pin to EIC
|
||||||
pinPeripheral(pin, PIO_EXTINT);
|
pinPeripheral(pin, PIO_EXTINT);
|
||||||
|
|
||||||
// Store interrupts to service in order of when they were attached
|
// Assign callback to interrupt
|
||||||
// to allow for first come first serve handler
|
ISRcallback[in] = callback;
|
||||||
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
|
// Look for right CONFIG register to be addressed
|
||||||
if (in > EXTERNAL_INT_7) {
|
if (in > EXTERNAL_INT_7) {
|
||||||
config = 1;
|
config = 1;
|
||||||
pos = (in - 8) << 2;
|
|
||||||
} else {
|
} else {
|
||||||
config = 0;
|
config = 0;
|
||||||
pos = in << 2;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Configure the interrupt mode
|
||||||
|
pos = (in - (8 * config)) << 2;
|
||||||
|
|
||||||
#if defined (__SAMD51__)
|
#if defined (__SAMD51__)
|
||||||
EIC->CTRLA.bit.ENABLE = 0;
|
EIC->CTRLA.bit.ENABLE = 0;
|
||||||
while (EIC->SYNCBUSY.bit.ENABLE == 1) { }
|
while (EIC->SYNCBUSY.bit.ENABLE == 1) { }
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
EIC->CONFIG[config].reg &=~ (EIC_CONFIG_SENSE0_Msk << pos); // Reset sense mode, important when changing trigger mode during runtime
|
|
||||||
switch (mode)
|
switch (mode)
|
||||||
{
|
{
|
||||||
case LOW:
|
case LOW:
|
||||||
|
|
@ -195,7 +200,6 @@ void attachInterrupt(uint32_t pin, voidFuncPtr callback, uint32_t mode)
|
||||||
}
|
}
|
||||||
// Enable the interrupt
|
// Enable the interrupt
|
||||||
EIC->INTENSET.reg = EIC_INTENSET_EXTINT(1 << in);
|
EIC->INTENSET.reg = EIC_INTENSET_EXTINT(1 << in);
|
||||||
}
|
|
||||||
|
|
||||||
#if defined (__SAMD51__)
|
#if defined (__SAMD51__)
|
||||||
EIC->CTRLA.bit.ENABLE = 1;
|
EIC->CTRLA.bit.ENABLE = 1;
|
||||||
|
|
@ -250,22 +254,17 @@ void detachInterrupt(uint32_t pin)
|
||||||
* External Interrupt Controller NVIC Interrupt Handler
|
* External Interrupt Controller NVIC Interrupt Handler
|
||||||
*/
|
*/
|
||||||
#if defined(__SAMD51__)
|
#if defined(__SAMD51__)
|
||||||
void InterruptHandler(uint32_t unused_i)
|
void InterruptHandler(uint32_t i)
|
||||||
{
|
{
|
||||||
(void)unused_i;
|
if ((EIC->INTFLAG.reg & (1 << i)) != 0)
|
||||||
// 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 if assigned
|
||||||
{
|
if (ISRcallback[i]) {
|
||||||
// Call the callback function
|
|
||||||
ISRcallback[i]();
|
ISRcallback[i]();
|
||||||
// Clear the interrupt
|
|
||||||
EIC->INTFLAG.reg = ISRlist[i];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Clear the interrupt
|
||||||
|
EIC->INTFLAG.reg = 1 << i;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -31,7 +31,7 @@ extern "C" {
|
||||||
#define FALLING 3
|
#define FALLING 3
|
||||||
#define RISING 4
|
#define RISING 4
|
||||||
|
|
||||||
//#define DEFAULT 1
|
#define DEFAULT 1
|
||||||
#define EXTERNAL 0
|
#define EXTERNAL 0
|
||||||
|
|
||||||
typedef void (*voidFuncPtr)(void);
|
typedef void (*voidFuncPtr)(void);
|
||||||
|
|
|
||||||
|
|
@ -57,41 +57,10 @@ typedef enum _EAnalogChannel
|
||||||
ADC_Channel19=19,
|
ADC_Channel19=19,
|
||||||
DAC_Channel0,
|
DAC_Channel0,
|
||||||
DAC_Channel1,
|
DAC_Channel1,
|
||||||
ADC_Channel_Bandgap=0x1B,
|
|
||||||
ADC_Channel_PTAT=0x1C,
|
|
||||||
} EAnalogChannel ;
|
} EAnalogChannel ;
|
||||||
|
|
||||||
#if defined(__SAMD51__)
|
#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
|
typedef enum _ETCChannel
|
||||||
{
|
{
|
||||||
NOT_ON_TIMER=-1,
|
NOT_ON_TIMER=-1,
|
||||||
|
|
@ -107,82 +76,12 @@ typedef enum _ETCChannel
|
||||||
TCC1_CH1 = (1<<8)|(1),
|
TCC1_CH1 = (1<<8)|(1),
|
||||||
TCC1_CH2 = (1<<8)|(2),
|
TCC1_CH2 = (1<<8)|(2),
|
||||||
TCC1_CH3 = (1<<8)|(3),
|
TCC1_CH3 = (1<<8)|(3),
|
||||||
TCC1_CH4 = (1<<8)|(4),
|
TCC1_CH4 = (1<<8)|(0),
|
||||||
TCC1_CH5 = (1<<8)|(5),
|
TCC1_CH5 = (1<<8)|(1),
|
||||||
TCC1_CH6 = (1<<8)|(6),
|
TCC1_CH6 = (1<<8)|(2),
|
||||||
TCC1_CH7 = (1<<8)|(7),
|
TCC1_CH7 = (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 ;
|
} 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
|
#else
|
||||||
// Definitions for TC channels
|
// Definitions for TC channels
|
||||||
typedef enum _ETCChannel
|
typedef enum _ETCChannel
|
||||||
|
|
@ -210,14 +109,40 @@ typedef enum _ETCChannel
|
||||||
TC4_CH1 = (4<<8)|(1),
|
TC4_CH1 = (4<<8)|(1),
|
||||||
TC5_CH0 = (5<<8)|(0),
|
TC5_CH0 = (5<<8)|(0),
|
||||||
TC5_CH1 = (5<<8)|(1),
|
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 ;
|
} 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
|
// Definitions for PWM channels
|
||||||
typedef enum _EPWMChannel
|
typedef enum _EPWMChannel
|
||||||
{
|
{
|
||||||
|
|
@ -254,11 +179,6 @@ typedef enum _EPWMChannel
|
||||||
|
|
||||||
#endif
|
#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
|
typedef enum _EPortType
|
||||||
{
|
{
|
||||||
|
|
@ -266,7 +186,6 @@ typedef enum _EPortType
|
||||||
PORTA=0,
|
PORTA=0,
|
||||||
PORTB=1,
|
PORTB=1,
|
||||||
PORTC=2,
|
PORTC=2,
|
||||||
PORTD=3,
|
|
||||||
} EPortType ;
|
} EPortType ;
|
||||||
|
|
||||||
#define PIN_NOT_A_PIN (UINT_MAX)
|
#define PIN_NOT_A_PIN (UINT_MAX)
|
||||||
|
|
@ -336,19 +255,10 @@ typedef enum _EPioType
|
||||||
#define PIN_ATTR_COMBO (1UL<<0)
|
#define PIN_ATTR_COMBO (1UL<<0)
|
||||||
#define PIN_ATTR_ANALOG (1UL<<1)
|
#define PIN_ATTR_ANALOG (1UL<<1)
|
||||||
#define PIN_ATTR_DIGITAL (1UL<<2)
|
#define PIN_ATTR_DIGITAL (1UL<<2)
|
||||||
|
#define PIN_ATTR_PWM (1UL<<3)
|
||||||
#define PIN_ATTR_TIMER (1UL<<4)
|
#define PIN_ATTR_TIMER (1UL<<4)
|
||||||
#define PIN_ATTR_TIMER_ALT (1UL<<5)
|
#define PIN_ATTR_TIMER_ALT (1UL<<5)
|
||||||
#define PIN_ATTR_EXTINT (1UL<<6)
|
#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 */
|
/* Types used for the table below */
|
||||||
typedef struct _PinDescription
|
typedef struct _PinDescription
|
||||||
|
|
|
||||||
|
|
@ -25,14 +25,8 @@
|
||||||
#ifndef _IO_H_
|
#ifndef _IO_H_
|
||||||
#define _IO_H_
|
#define _IO_H_
|
||||||
|
|
||||||
#ifdef __SAMD51__
|
|
||||||
#define RAMSTART (HSRAM_ADDR)
|
|
||||||
#define RAMSIZE (HSRAM_SIZE)
|
|
||||||
#else
|
|
||||||
#define RAMSTART (HMCRAMC0_ADDR)
|
#define RAMSTART (HMCRAMC0_ADDR)
|
||||||
#define RAMSIZE (HMCRAMC0_SIZE)
|
#define RAMSIZE (HMCRAMC0_SIZE)
|
||||||
#endif
|
|
||||||
|
|
||||||
#define RAMEND (RAMSTART + RAMSIZE - 1)
|
#define RAMEND (RAMSTART + RAMSIZE - 1)
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
|
|
@ -61,33 +61,6 @@ unsigned long micros( void )
|
||||||
// a runtime multiplication and shift, saving a few cycles
|
// 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 )
|
void delay( unsigned long ms )
|
||||||
{
|
{
|
||||||
if ( ms == 0 )
|
if ( ms == 0 )
|
||||||
|
|
@ -95,17 +68,12 @@ void delay( unsigned long ms )
|
||||||
return ;
|
return ;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t start = micros();
|
uint32_t start = _ulTickCount ;
|
||||||
|
|
||||||
while (ms > 0)
|
do
|
||||||
{
|
{
|
||||||
yield() ;
|
yield() ;
|
||||||
while (ms > 0 && (micros() - start) >= 1000)
|
} while ( _ulTickCount - start < ms ) ;
|
||||||
{
|
|
||||||
ms--;
|
|
||||||
start += 1000;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#include "Reset.h" // for tickReset()
|
#include "Reset.h" // for tickReset()
|
||||||
|
|
|
||||||
|
|
@ -61,9 +61,6 @@ extern void delay( unsigned long dwMs ) ;
|
||||||
*
|
*
|
||||||
* \param dwUs the number of microseconds to pause (uint32_t)
|
* \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 ) __attribute__((always_inline, unused)) ;
|
||||||
static __inline__ void delayMicroseconds( unsigned int usec )
|
static __inline__ void delayMicroseconds( unsigned int usec )
|
||||||
{
|
{
|
||||||
|
|
@ -71,6 +68,21 @@ static __inline__ void delayMicroseconds( unsigned int usec )
|
||||||
{
|
{
|
||||||
return ;
|
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:
|
* The following loop:
|
||||||
*
|
*
|
||||||
|
|
@ -97,10 +109,10 @@ static __inline__ void delayMicroseconds( unsigned int usec )
|
||||||
: // no input
|
: // no input
|
||||||
: // no clobber
|
: // no clobber
|
||||||
);
|
);
|
||||||
|
#endif
|
||||||
// https://gcc.gnu.org/onlinedocs/gcc/Extended-Asm.html
|
// https://gcc.gnu.org/onlinedocs/gcc/Extended-Asm.html
|
||||||
// https://gcc.gnu.org/onlinedocs/gcc/Extended-Asm.html#Volatile
|
// https://gcc.gnu.org/onlinedocs/gcc/Extended-Asm.html#Volatile
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -28,7 +28,6 @@
|
||||||
static void __empty() {
|
static void __empty() {
|
||||||
// Empty
|
// Empty
|
||||||
}
|
}
|
||||||
|
|
||||||
void yield(void) __attribute__ ((weak, alias("__empty")));
|
void yield(void) __attribute__ ((weak, alias("__empty")));
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
|
|
@ -39,10 +39,7 @@ int main( void )
|
||||||
initVariant();
|
initVariant();
|
||||||
|
|
||||||
delay(1);
|
delay(1);
|
||||||
|
#if defined(USBCON)
|
||||||
#if defined(USE_TINYUSB)
|
|
||||||
Adafruit_TinyUSB_Core_init();
|
|
||||||
#elif defined(USBCON)
|
|
||||||
USBDevice.init();
|
USBDevice.init();
|
||||||
USBDevice.attach();
|
USBDevice.attach();
|
||||||
#endif
|
#endif
|
||||||
|
|
@ -52,21 +49,8 @@ int main( void )
|
||||||
for (;;)
|
for (;;)
|
||||||
{
|
{
|
||||||
loop();
|
loop();
|
||||||
yield(); // yield run usb background task
|
|
||||||
|
|
||||||
if (serialEventRun) serialEventRun();
|
if (serialEventRun) serialEventRun();
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
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,14 +164,13 @@ 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 arm_compare_fixed_q15(q15_t *pIn, q15_t * pOut, uint32_t numSamples)
|
||||||
{
|
{
|
||||||
uint32_t i;
|
uint32_t i;
|
||||||
int32_t diff;
|
int32_t diff, diffCrnt = 0;
|
||||||
uint32_t diffCrnt = 0;
|
|
||||||
uint32_t maxDiff = 0;
|
uint32_t maxDiff = 0;
|
||||||
|
|
||||||
for (i = 0; i < numSamples; i++)
|
for (i = 0; i < numSamples; i++)
|
||||||
{
|
{
|
||||||
diff = pIn[i] - pOut[i];
|
diff = pIn[i] - pOut[i];
|
||||||
diffCrnt = (uint32_t)( (diff > 0) ? diff : -diff );
|
diffCrnt = (diff > 0) ? diff : -diff;
|
||||||
|
|
||||||
if(diffCrnt > maxDiff)
|
if(diffCrnt > maxDiff)
|
||||||
{
|
{
|
||||||
|
|
@ -193,14 +192,13 @@ 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 arm_compare_fixed_q31(q31_t *pIn, q31_t * pOut, uint32_t numSamples)
|
||||||
{
|
{
|
||||||
uint32_t i;
|
uint32_t i;
|
||||||
int32_t diff;
|
int32_t diff, diffCrnt = 0;
|
||||||
uint32_t diffCrnt = 0;
|
|
||||||
uint32_t maxDiff = 0;
|
uint32_t maxDiff = 0;
|
||||||
|
|
||||||
for (i = 0; i < numSamples; i++)
|
for (i = 0; i < numSamples; i++)
|
||||||
{
|
{
|
||||||
diff = pIn[i] - pOut[i];
|
diff = pIn[i] - pOut[i];
|
||||||
diffCrnt = (uint32_t)( (diff > 0) ? diff : -diff );
|
diffCrnt = (diff > 0) ? diff : -diff;
|
||||||
|
|
||||||
if(diffCrnt > maxDiff)
|
if(diffCrnt > maxDiff)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -34,36 +34,6 @@ uint32_t pulseIn(uint32_t pin, uint32_t state, uint32_t timeout)
|
||||||
uint32_t bit = 1 << p.ulPin;
|
uint32_t bit = 1 << p.ulPin;
|
||||||
uint32_t stateMask = state ? bit : 0;
|
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
|
// convert the timeout from microseconds to a number of times through
|
||||||
// the initial loop; it takes (roughly) 13 clock cycles per iteration.
|
// the initial loop; it takes (roughly) 13 clock cycles per iteration.
|
||||||
uint32_t maxloops = microsecondsToClockCycles(timeout) / 13;
|
uint32_t maxloops = microsecondsToClockCycles(timeout) / 13;
|
||||||
|
|
@ -78,6 +48,5 @@ uint32_t pulseIn(uint32_t pin, uint32_t state, uint32_t timeout)
|
||||||
return clockCyclesToMicroseconds(width * 13 + 16);
|
return clockCyclesToMicroseconds(width * 13 + 16);
|
||||||
else
|
else
|
||||||
return 0;
|
return 0;
|
||||||
#endif // SAMD51
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -97,7 +97,7 @@ void SystemInit( void )
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ----------------------------------------------------------------------------------------------
|
/* ----------------------------------------------------------------------------------------------
|
||||||
* 3) Put OSCULP32K as source for Generic Clock Generator 0
|
* 3) Put Generic Clock Generator 3 as source for Generic Clock Gen 0 (DFLL48M reference)
|
||||||
*/
|
*/
|
||||||
GCLK->GENCTRL[0].reg = GCLK_GENCTRL_SRC(GCLK_GENCTRL_SRC_OSCULP32K) | GCLK_GENCTRL_GENEN;
|
GCLK->GENCTRL[0].reg = GCLK_GENCTRL_SRC(GCLK_GENCTRL_SRC_OSCULP32K) | GCLK_GENCTRL_GENEN;
|
||||||
|
|
||||||
|
|
@ -146,7 +146,7 @@ void SystemInit( void )
|
||||||
/* Wait for synchronization */
|
/* Wait for synchronization */
|
||||||
}
|
}
|
||||||
|
|
||||||
GCLK->GENCTRL[GENERIC_CLOCK_GENERATOR_1M].reg = GCLK_GENCTRL_SRC(GCLK_GENCTRL_SRC_DFLL_Val) | GCLK_GENCTRL_GENEN | GCLK_GENCTRL_DIV(48u);
|
GCLK->GENCTRL[GENERIC_CLOCK_GENERATOR_1M].reg = GCLK_GENCTRL_SRC(GCLK_GENCTRL_SRC_DFLL_Val) | GCLK_GENCTRL_GENEN | GCLK_GENCTRL_DIV(24u);
|
||||||
|
|
||||||
while ( GCLK->SYNCBUSY.bit.GENCTRL5 ){
|
while ( GCLK->SYNCBUSY.bit.GENCTRL5 ){
|
||||||
/* Wait for synchronization */
|
/* Wait for synchronization */
|
||||||
|
|
@ -160,8 +160,7 @@ void SystemInit( void )
|
||||||
//PLL0 is 120MHz
|
//PLL0 is 120MHz
|
||||||
GCLK->PCHCTRL[OSCCTRL_GCLK_ID_FDPLL0].reg = (1 << GCLK_PCHCTRL_CHEN_Pos) | GCLK_PCHCTRL_GEN(GCLK_PCHCTRL_GEN_GCLK5_Val);
|
GCLK->PCHCTRL[OSCCTRL_GCLK_ID_FDPLL0].reg = (1 << GCLK_PCHCTRL_CHEN_Pos) | GCLK_PCHCTRL_GEN(GCLK_PCHCTRL_GEN_GCLK5_Val);
|
||||||
|
|
||||||
// This rounds to nearest full-MHz increment; not currently using frac
|
OSCCTRL->Dpll[0].DPLLRATIO.reg = OSCCTRL_DPLLRATIO_LDRFRAC(0x00) | OSCCTRL_DPLLRATIO_LDR(59); //120 Mhz
|
||||||
OSCCTRL->Dpll[0].DPLLRATIO.reg = OSCCTRL_DPLLRATIO_LDRFRAC(0x00) | OSCCTRL_DPLLRATIO_LDR((F_CPU - 500000) / 1000000);
|
|
||||||
|
|
||||||
while(OSCCTRL->Dpll[0].DPLLSYNCBUSY.bit.DPLLRATIO);
|
while(OSCCTRL->Dpll[0].DPLLSYNCBUSY.bit.DPLLRATIO);
|
||||||
|
|
||||||
|
|
@ -175,7 +174,7 @@ void SystemInit( void )
|
||||||
//PLL1 is 100MHz
|
//PLL1 is 100MHz
|
||||||
GCLK->PCHCTRL[OSCCTRL_GCLK_ID_FDPLL1].reg = (1 << GCLK_PCHCTRL_CHEN_Pos) | GCLK_PCHCTRL_GEN(GCLK_PCHCTRL_GEN_GCLK5_Val);
|
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(99); //100 Mhz
|
OSCCTRL->Dpll[1].DPLLRATIO.reg = OSCCTRL_DPLLRATIO_LDRFRAC(0x00) | OSCCTRL_DPLLRATIO_LDR(49); //100 Mhz
|
||||||
|
|
||||||
while(OSCCTRL->Dpll[1].DPLLSYNCBUSY.bit.DPLLRATIO);
|
while(OSCCTRL->Dpll[1].DPLLSYNCBUSY.bit.DPLLRATIO);
|
||||||
|
|
||||||
|
|
@ -217,7 +216,7 @@ void SystemInit( void )
|
||||||
GCLK->GENCTRL[GENERIC_CLOCK_GENERATOR_12M].reg = GCLK_GENCTRL_SRC(GCLK_GENCTRL_SRC_DFLL_Val) |
|
GCLK->GENCTRL[GENERIC_CLOCK_GENERATOR_12M].reg = GCLK_GENCTRL_SRC(GCLK_GENCTRL_SRC_DFLL_Val) |
|
||||||
GCLK_GENCTRL_IDC |
|
GCLK_GENCTRL_IDC |
|
||||||
GCLK_GENCTRL_DIV(4) |
|
GCLK_GENCTRL_DIV(4) |
|
||||||
//GCLK_GENCTRL_DIVSEL |
|
GCLK_GENCTRL_DIVSEL |
|
||||||
//GCLK_GENCTRL_OE |
|
//GCLK_GENCTRL_OE |
|
||||||
GCLK_GENCTRL_GENEN;
|
GCLK_GENCTRL_GENEN;
|
||||||
|
|
||||||
|
|
@ -254,54 +253,6 @@ void SystemInit( void )
|
||||||
__enable_irq();
|
__enable_irq();
|
||||||
#endif
|
#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 *************************//
|
//*************** END SAMD51 *************************//
|
||||||
|
|
||||||
#else
|
#else
|
||||||
|
|
@ -577,3 +528,4 @@ void SystemInit( void )
|
||||||
NVMCTRL->CTRLB.bit.MANW = 1;
|
NVMCTRL->CTRLB.bit.MANW = 1;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -25,7 +25,8 @@ extern "C" {
|
||||||
|
|
||||||
|
|
||||||
#if defined(__SAMD51__)
|
#if defined(__SAMD51__)
|
||||||
uint32_t SystemCoreClock=F_CPU;
|
//CHANGE THIS IF YOU CHANGE THE CLOCK SPEED
|
||||||
|
uint32_t SystemCoreClock=120000000ul ;
|
||||||
#else
|
#else
|
||||||
/*
|
/*
|
||||||
* System Core Clock is at 1MHz (8MHz/8) at Reset.
|
* System Core Clock is at 1MHz (8MHz/8) at Reset.
|
||||||
|
|
@ -78,21 +79,19 @@ void init( void )
|
||||||
// PM->APBAMASK.reg |= PM_APBAMASK_EIC ;
|
// PM->APBAMASK.reg |= PM_APBAMASK_EIC ;
|
||||||
|
|
||||||
#if defined(__SAMD51__)
|
#if defined(__SAMD51__)
|
||||||
MCLK->APBAMASK.reg |= MCLK_APBAMASK_SERCOM0 | MCLK_APBAMASK_SERCOM1 | MCLK_APBAMASK_TC0 | MCLK_APBAMASK_TC1;
|
MCLK->APBAMASK.reg |= MCLK_APBAMASK_SERCOM0 | MCLK_APBAMASK_SERCOM1;
|
||||||
|
|
||||||
MCLK->APBBMASK.reg |= MCLK_APBBMASK_SERCOM2 | MCLK_APBBMASK_SERCOM3 | MCLK_APBBMASK_TCC0 | MCLK_APBBMASK_TCC1 | MCLK_APBBMASK_TC3 | MCLK_APBBMASK_TC2;
|
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_TCC3 | MCLK_APBCMASK_TC4 | MCLK_APBCMASK_TC5;
|
MCLK->APBCMASK.reg |= MCLK_APBCMASK_TCC2 | 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
|
#else
|
||||||
// Clock SERCOM for Serial
|
// 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 ;
|
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
|
// 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_TC6 | PM_APBCMASK_TC7;
|
PM->APBCMASK.reg |= PM_APBCMASK_TCC0 | PM_APBCMASK_TCC1 | PM_APBCMASK_TCC2 | PM_APBCMASK_TC3 | PM_APBCMASK_TC4 | PM_APBCMASK_TC5 ;
|
||||||
|
|
||||||
// ATSAMR, for example, doesn't have a DAC
|
// ATSAMR, for example, doesn't have a DAC
|
||||||
#ifdef PM_APBCMASK_DAC
|
#ifdef PM_APBCMASK_DAC
|
||||||
|
|
@ -101,45 +100,35 @@ void init( void )
|
||||||
#endif
|
#endif
|
||||||
#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)
|
// Setup all pins (digital and analog) in INPUT mode (default is nothing)
|
||||||
for (uint32_t ul = 0 ; ul < NUM_DIGITAL_PINS ; ul++ )
|
for (uint32_t ul = 0 ; ul < NUM_DIGITAL_PINS ; ul++ )
|
||||||
{
|
{
|
||||||
pinMode( ul, INPUT ) ;
|
pinMode( ul, INPUT ) ;
|
||||||
}
|
}
|
||||||
*/
|
|
||||||
|
|
||||||
// Initialize Analog Controller
|
// Initialize Analog Controller
|
||||||
// Setting clock
|
// Setting clock
|
||||||
#if defined(__SAMD51__)
|
#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[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++){
|
|
||||||
|
|
||||||
adcs[i]->CTRLA.bit.PRESCALER = ADC_CTRLA_PRESCALER_DIV32_Val;
|
ADC0->CTRLA.bit.PRESCALER = ADC_CTRLA_PRESCALER_DIV256_Val;
|
||||||
adcs[i]->CTRLB.bit.RESSEL = ADC_CTRLB_RESSEL_10BIT_Val;
|
ADC0->CTRLB.bit.RESSEL = ADC_CTRLB_RESSEL_10BIT_Val;
|
||||||
|
|
||||||
while( adcs[i]->SYNCBUSY.reg & ADC_SYNCBUSY_CTRLB ); //wait for sync
|
while( ADC0->SYNCBUSY.reg & ADC_SYNCBUSY_CTRLB ); //wait for sync
|
||||||
|
|
||||||
adcs[i]->SAMPCTRL.reg = 5; // sampling Time Length
|
ADC0->SAMPCTRL.reg = 0x3f; // Set max Sampling Time Length
|
||||||
|
|
||||||
while( adcs[i]->SYNCBUSY.reg & ADC_SYNCBUSY_SAMPCTRL ); //wait for sync
|
while( ADC0->SYNCBUSY.reg & ADC_SYNCBUSY_SAMPCTRL ); //wait for sync
|
||||||
|
|
||||||
adcs[i]->INPUTCTRL.reg = ADC_INPUTCTRL_MUXNEG_GND; // No Negative input (Internal Ground)
|
ADC0->INPUTCTRL.reg = ADC_INPUTCTRL_MUXNEG_GND; // No Negative input (Internal Ground)
|
||||||
|
|
||||||
while( adcs[i]->SYNCBUSY.reg & ADC_SYNCBUSY_INPUTCTRL ); //wait for sync
|
while( ADC0->SYNCBUSY.reg & ADC_SYNCBUSY_INPUTCTRL ); //wait for sync
|
||||||
|
|
||||||
// Averaging (see datasheet table in AVGCTRL register description)
|
// Averaging (see datasheet table in AVGCTRL register description)
|
||||||
adcs[i]->AVGCTRL.reg = ADC_AVGCTRL_SAMPLENUM_1 | // 1 sample only (no oversampling nor averaging)
|
ADC0->AVGCTRL.reg = ADC_AVGCTRL_SAMPLENUM_1 | // 1 sample only (no oversampling nor averaging)
|
||||||
ADC_AVGCTRL_ADJRES(0x0ul); // Adjusting result by 0
|
ADC_AVGCTRL_ADJRES(0x0ul); // Adjusting result by 0
|
||||||
|
|
||||||
while( adcs[i]->SYNCBUSY.reg & ADC_SYNCBUSY_AVGCTRL ); //wait for sync
|
while( ADC0->SYNCBUSY.reg & ADC_SYNCBUSY_AVGCTRL ); //wait for sync
|
||||||
}
|
|
||||||
|
|
||||||
analogReference( AR_DEFAULT ) ; // Analog Reference is AREF pin (3.3v)
|
analogReference( AR_DEFAULT ) ; // Analog Reference is AREF pin (3.3v)
|
||||||
|
|
||||||
|
|
@ -157,8 +146,6 @@ void init( void )
|
||||||
DAC->DACCTRL[1].bit.REFRESH = 2;
|
DAC->DACCTRL[1].bit.REFRESH = 2;
|
||||||
|
|
||||||
#else
|
#else
|
||||||
//set to 1/(1/(48000000/32) * 6) = 250000 SPS
|
|
||||||
|
|
||||||
while(GCLK->STATUS.reg & GCLK_STATUS_SYNCBUSY);
|
while(GCLK->STATUS.reg & GCLK_STATUS_SYNCBUSY);
|
||||||
|
|
||||||
GCLK->CLKCTRL.reg = GCLK_CLKCTRL_ID( GCM_ADC ) | // Generic Clock ADC
|
GCLK->CLKCTRL.reg = GCLK_CLKCTRL_ID( GCM_ADC ) | // Generic Clock ADC
|
||||||
|
|
@ -167,10 +154,10 @@ void init( void )
|
||||||
|
|
||||||
while( ADC->STATUS.bit.SYNCBUSY == 1 ); // Wait for synchronization of registers between the clock domains
|
while( ADC->STATUS.bit.SYNCBUSY == 1 ); // Wait for synchronization of registers between the clock domains
|
||||||
|
|
||||||
ADC->CTRLB.reg = ADC_CTRLB_PRESCALER_DIV32 | // Divide Clock by 32.
|
ADC->CTRLB.reg = ADC_CTRLB_PRESCALER_DIV512 | // Divide Clock by 512.
|
||||||
ADC_CTRLB_RESSEL_10BIT; // 10 bits resolution as default
|
ADC_CTRLB_RESSEL_10BIT; // 10 bits resolution as default
|
||||||
|
|
||||||
ADC->SAMPCTRL.reg = 5; // Sampling Time Length
|
ADC->SAMPCTRL.reg = 0x3f; // Set max Sampling Time Length
|
||||||
|
|
||||||
while( ADC->STATUS.bit.SYNCBUSY == 1 ); // Wait for synchronization of registers between the clock domains
|
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;
|
static int _dacResolution = 12;
|
||||||
#else
|
#else
|
||||||
static int _writeResolution = 8;
|
static int _writeResolution = 8;
|
||||||
//static int _dacResolution = 10;
|
static int _dacResolution = 8;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -77,21 +77,17 @@ void analogReadResolution(int res)
|
||||||
|
|
||||||
if (res > 10) {
|
if (res > 10) {
|
||||||
ADC0->CTRLB.bit.RESSEL = ADC_CTRLB_RESSEL_12BIT_Val;
|
ADC0->CTRLB.bit.RESSEL = ADC_CTRLB_RESSEL_12BIT_Val;
|
||||||
ADC1->CTRLB.bit.RESSEL = ADC_CTRLB_RESSEL_12BIT_Val;
|
|
||||||
_ADCResolution = 12;
|
_ADCResolution = 12;
|
||||||
} else if (res > 8) {
|
} else if (res > 8) {
|
||||||
ADC0->CTRLB.bit.RESSEL = ADC_CTRLB_RESSEL_10BIT_Val;
|
ADC0->CTRLB.bit.RESSEL = ADC_CTRLB_RESSEL_10BIT_Val;
|
||||||
ADC1->CTRLB.bit.RESSEL = ADC_CTRLB_RESSEL_10BIT_Val;
|
|
||||||
_ADCResolution = 10;
|
_ADCResolution = 10;
|
||||||
} else {
|
} else {
|
||||||
ADC0->CTRLB.bit.RESSEL = ADC_CTRLB_RESSEL_8BIT_Val;
|
ADC0->CTRLB.bit.RESSEL = ADC_CTRLB_RESSEL_8BIT_Val;
|
||||||
ADC1->CTRLB.bit.RESSEL = ADC_CTRLB_RESSEL_8BIT_Val;
|
|
||||||
_ADCResolution = 8;
|
_ADCResolution = 8;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
while(ADC0->SYNCBUSY.reg & ADC_SYNCBUSY_CTRLB); //wait for sync
|
while(ADC0->SYNCBUSY.reg & ADC_SYNCBUSY_CTRLB); //wait for sync
|
||||||
while(ADC1->SYNCBUSY.reg & ADC_SYNCBUSY_CTRLB); //wait for sync
|
|
||||||
#else
|
#else
|
||||||
|
|
||||||
if (res > 10) {
|
if (res > 10) {
|
||||||
|
|
@ -135,92 +131,38 @@ void analogReference(eAnalogReference mode)
|
||||||
{
|
{
|
||||||
#if defined(__SAMD51__)
|
#if defined(__SAMD51__)
|
||||||
while(ADC0->SYNCBUSY.reg & ADC_SYNCBUSY_REFCTRL); //wait for sync
|
while(ADC0->SYNCBUSY.reg & ADC_SYNCBUSY_REFCTRL); //wait for sync
|
||||||
while(ADC1->SYNCBUSY.reg & ADC_SYNCBUSY_REFCTRL); //wait for sync
|
|
||||||
|
|
||||||
//TODO: fix gains
|
//TODO: fix gains
|
||||||
switch (mode)
|
switch (mode)
|
||||||
{
|
{
|
||||||
case AR_INTERNAL1V0:
|
case AR_INTERNAL:
|
||||||
|
case AR_INTERNAL2V23:
|
||||||
//ADC0->GAINCORR.reg = ADC_GAINCORR_GAINCORR(); // Gain Factor Selection
|
//ADC0->GAINCORR.reg = ADC_GAINCORR_GAINCORR(); // Gain Factor Selection
|
||||||
SUPC->VREF.bit.SEL = SUPC_VREF_SEL_1V0_Val; // select 1.0V
|
ADC0->REFCTRL.bit.REFSEL = ADC_REFCTRL_REFSEL_INTVCC0_Val; // 1/1.48 VDDANA = 1/1.48* 3V3 = 2.2297
|
||||||
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;
|
break;
|
||||||
|
|
||||||
case AR_EXTERNAL:
|
case AR_EXTERNAL:
|
||||||
//ADC0->INPUTCTRL.bit.GAIN = ADC_INPUTCTRL_GAIN_1X_Val; // Gain Factor Selection
|
//ADC0->INPUTCTRL.bit.GAIN = ADC_INPUTCTRL_GAIN_1X_Val; // Gain Factor Selection
|
||||||
ADC0->REFCTRL.bit.REFSEL = ADC_REFCTRL_REFSEL_AREFA_Val; // AREF is jumpered to VCC, so 3.3V
|
ADC0->REFCTRL.bit.REFSEL = ADC_REFCTRL_REFSEL_AREFA_Val;
|
||||||
ADC1->REFCTRL.bit.REFSEL = ADC_REFCTRL_REFSEL_AREFA_Val;
|
|
||||||
break;
|
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:
|
case AR_INTERNAL1V65:
|
||||||
//ADC0->INPUTCTRL.bit.GAIN = ADC_INPUTCTRL_GAIN_DIV2_Val;
|
//ADC0->INPUTCTRL.bit.GAIN = ADC_INPUTCTRL_GAIN_1X_Val; // Gain Factor Selection
|
||||||
ADC0->REFCTRL.bit.REFSEL = ADC_REFCTRL_REFSEL_INTVCC0_Val; // 1/2 VDDANA = 1.65
|
ADC0->REFCTRL.bit.REFSEL = ADC_REFCTRL_REFSEL_INTVCC1_Val; // 1/2 VDDANA = 0.5* 3V3 = 1.65V
|
||||||
ADC1->REFCTRL.bit.REFSEL = ADC_REFCTRL_REFSEL_INTVCC0_Val; //
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case AR_DEFAULT:
|
case AR_DEFAULT:
|
||||||
default:
|
default:
|
||||||
//ADC0->INPUTCTRL.bit.GAIN = ADC_INPUTCTRL_GAIN_DIV2_Val;
|
//ADC0->INPUTCTRL.bit.GAIN = ADC_INPUTCTRL_GAIN_DIV2_Val;
|
||||||
ADC0->REFCTRL.bit.REFSEL = ADC_REFCTRL_REFSEL_INTVCC1_Val; // VDDANA = 3V3
|
ADC0->REFCTRL.bit.REFSEL = ADC_REFCTRL_REFSEL_INTVCC1_Val; // 1/2 VDDANA = 0.5* 3V3 = 1.65V
|
||||||
ADC1->REFCTRL.bit.REFSEL = ADC_REFCTRL_REFSEL_INTVCC1_Val; //
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -228,6 +170,7 @@ void analogReference(eAnalogReference mode)
|
||||||
syncADC();
|
syncADC();
|
||||||
switch (mode)
|
switch (mode)
|
||||||
{
|
{
|
||||||
|
case AR_INTERNAL:
|
||||||
case AR_INTERNAL2V23:
|
case AR_INTERNAL2V23:
|
||||||
ADC->INPUTCTRL.bit.GAIN = ADC_INPUTCTRL_GAIN_1X_Val; // Gain Factor Selection
|
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
|
ADC->REFCTRL.bit.REFSEL = ADC_REFCTRL_REFSEL_INTVCC0_Val; // 1/1.48 VDDANA = 1/1.48* 3V3 = 2.2297
|
||||||
|
|
@ -280,8 +223,8 @@ uint32_t analogRead(uint32_t pin)
|
||||||
#ifdef DAC
|
#ifdef DAC
|
||||||
|
|
||||||
#if defined(__SAMD51__)
|
#if defined(__SAMD51__)
|
||||||
if (pin == PIN_DAC0 || pin == PIN_DAC1) { // Disable DAC, if analogWrite(A0,dval) used previously the DAC is enabled
|
if (pin == A0 || pin == A1) { // Disable DAC, if analogWrite(A0,dval) used previously the DAC is enabled
|
||||||
uint8_t channel = (pin == PIN_DAC0 ? 0 : 1);
|
uint8_t channel = (pin == PIN_A0 ? 0 : 1);
|
||||||
|
|
||||||
if(dacEnabled[channel]){
|
if(dacEnabled[channel]){
|
||||||
dacEnabled[channel] = false;
|
dacEnabled[channel] = false;
|
||||||
|
|
@ -298,7 +241,7 @@ uint32_t analogRead(uint32_t pin)
|
||||||
|
|
||||||
while (DAC->SYNCBUSY.bit.ENABLE);
|
while (DAC->SYNCBUSY.bit.ENABLE);
|
||||||
#else
|
#else
|
||||||
if (pin == PIN_DAC0) { // Disable DAC, if analogWrite(A0,dval) used previously the DAC is enabled
|
if (pin == A0) { // Disable DAC, if analogWrite(A0,dval) used previously the DAC is enabled
|
||||||
syncDAC();
|
syncDAC();
|
||||||
|
|
||||||
DAC->CTRLA.bit.ENABLE = 0x00; // Disable DAC
|
DAC->CTRLA.bit.ENABLE = 0x00; // Disable DAC
|
||||||
|
|
@ -310,13 +253,8 @@ uint32_t analogRead(uint32_t pin)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(__SAMD51__)
|
#if defined(__SAMD51__)
|
||||||
Adc *adc;
|
while( ADC0->SYNCBUSY.reg & ADC_SYNCBUSY_INPUTCTRL ); //wait for sync
|
||||||
if(g_APinDescription[pin].ulPinAttribute & PIN_ATTR_ANALOG) adc = ADC0;
|
ADC0->INPUTCTRL.bit.MUXPOS = g_APinDescription[pin].ulADCChannelNumber; // Selection for the positive ADC input
|
||||||
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
|
// Control A
|
||||||
/*
|
/*
|
||||||
|
|
@ -330,27 +268,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
|
* 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.
|
* configured. The first conversion after the reference is changed must not be used.
|
||||||
*/
|
*/
|
||||||
while( adc->SYNCBUSY.reg & ADC_SYNCBUSY_ENABLE ); //wait for sync
|
while( ADC0->SYNCBUSY.reg & ADC_SYNCBUSY_ENABLE ); //wait for sync
|
||||||
adc->CTRLA.bit.ENABLE = 0x01; // Enable ADC
|
ADC0->CTRLA.bit.ENABLE = 0x01; // Enable ADC
|
||||||
|
|
||||||
// Start conversion
|
// Start conversion
|
||||||
while( adc->SYNCBUSY.reg & ADC_SYNCBUSY_ENABLE ); //wait for sync
|
while( ADC0->SYNCBUSY.reg & ADC_SYNCBUSY_ENABLE ); //wait for sync
|
||||||
|
|
||||||
adc->SWTRIG.bit.START = 1;
|
ADC0->SWTRIG.bit.START = 1;
|
||||||
|
|
||||||
// Clear the Data Ready flag
|
// Clear the Data Ready flag
|
||||||
adc->INTFLAG.reg = ADC_INTFLAG_RESRDY;
|
ADC0->INTFLAG.reg = ADC_INTFLAG_RESRDY;
|
||||||
|
|
||||||
// Start conversion again, since The first conversion after the reference is changed must not be used.
|
// Start conversion again, since The first conversion after the reference is changed must not be used.
|
||||||
adc->SWTRIG.bit.START = 1;
|
ADC0->SWTRIG.bit.START = 1;
|
||||||
|
|
||||||
// Store the value
|
// Store the value
|
||||||
while (adc->INTFLAG.bit.RESRDY == 0); // Waiting for conversion to complete
|
while (ADC0->INTFLAG.bit.RESRDY == 0); // Waiting for conversion to complete
|
||||||
valueRead = adc->RESULT.reg;
|
valueRead = ADC0->RESULT.reg;
|
||||||
|
|
||||||
while( adc->SYNCBUSY.reg & ADC_SYNCBUSY_ENABLE ); //wait for sync
|
while( ADC0->SYNCBUSY.reg & ADC_SYNCBUSY_ENABLE ); //wait for sync
|
||||||
adc->CTRLA.bit.ENABLE = 0x00; // Disable ADC
|
ADC0->CTRLA.bit.ENABLE = 0x00; // Disable ADC
|
||||||
while( adc->SYNCBUSY.reg & ADC_SYNCBUSY_ENABLE ); //wait for sync
|
while( ADC0->SYNCBUSY.reg & ADC_SYNCBUSY_ENABLE ); //wait for sync
|
||||||
|
|
||||||
#else
|
#else
|
||||||
syncADC();
|
syncADC();
|
||||||
|
|
@ -406,21 +344,22 @@ void analogWrite(uint32_t pin, uint32_t value)
|
||||||
|
|
||||||
// ATSAMR, for example, doesn't have a DAC
|
// ATSAMR, for example, doesn't have a DAC
|
||||||
#ifdef DAC
|
#ifdef DAC
|
||||||
|
|
||||||
if ((attr & PIN_ATTR_ANALOG) == PIN_ATTR_ANALOG)
|
if ((attr & PIN_ATTR_ANALOG) == PIN_ATTR_ANALOG)
|
||||||
{
|
{
|
||||||
// DAC handling code
|
// DAC handling code
|
||||||
#if defined(__SAMD51__)
|
#if defined(__SAMD51__)
|
||||||
if (pin == PIN_DAC0 || pin == PIN_DAC1) { // 2 DACs on A0 (PA02) and A1 (PA05)
|
if (pin != PIN_A0 && pin != PIN_A1) { // 2 DACs on A0 (PA02) and A1 (PA05)
|
||||||
#else
|
#else
|
||||||
if (pin == PIN_DAC0) { // Only 1 DAC on A0 (PA02)
|
if (pin != PIN_A0) { // Only 1 DAC on A0 (PA02)
|
||||||
#endif
|
#endif
|
||||||
|
return;
|
||||||
#if defined(__SAMD51__)
|
}
|
||||||
|
|
||||||
value = mapResolution(value, _writeResolution, _dacResolution);
|
value = mapResolution(value, _writeResolution, _dacResolution);
|
||||||
|
|
||||||
|
#if defined(__SAMD51__)
|
||||||
uint8_t channel = (pin == PIN_DAC0 ? 0 : 1);
|
uint8_t channel = (pin == PIN_A0 ? 0 : 1);
|
||||||
|
|
||||||
pinPeripheral(pin, PIO_ANALOG);
|
pinPeripheral(pin, PIO_ANALOG);
|
||||||
|
|
||||||
|
|
@ -472,33 +411,66 @@ void analogWrite(uint32_t pin, uint32_t value)
|
||||||
|
|
||||||
|
|
||||||
#else
|
#else
|
||||||
|
value = mapResolution(value, _dacResolution, 10);
|
||||||
syncDAC();
|
syncDAC();
|
||||||
DAC->DATA.reg = value & 0x3FF; // DAC on 10 bits.
|
DAC->DATA.reg = value & 0x3FF; // DAC on 10 bits.
|
||||||
syncDAC();
|
syncDAC();
|
||||||
DAC->CTRLA.bit.ENABLE = 0x01; // Enable DAC
|
DAC->CTRLA.bit.ENABLE = 0x01; // Enable DAC
|
||||||
syncDAC();
|
syncDAC();
|
||||||
#endif // __SAMD51__
|
#endif
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
#endif
|
||||||
#endif // DAC
|
|
||||||
|
|
||||||
#if defined(__SAMD51__)
|
if ((attr & PIN_ATTR_PWM) == PIN_ATTR_PWM)
|
||||||
if(attr & (PIN_ATTR_PWM_E|PIN_ATTR_PWM_F|PIN_ATTR_PWM_G)){
|
{
|
||||||
|
#ifndef __SAMD51__
|
||||||
|
value = mapResolution(value, _writeResolution, 16);
|
||||||
|
#endif
|
||||||
|
|
||||||
uint32_t tcNum = GetTCNumber(pinDesc.ulPWMChannel);
|
uint32_t tcNum = GetTCNumber(pinDesc.ulPWMChannel);
|
||||||
uint8_t tcChannel = GetTCChannelNumber(pinDesc.ulPWMChannel);
|
uint8_t tcChannel = GetTCChannelNumber(pinDesc.ulPWMChannel);
|
||||||
static bool tcEnabled[TCC_INST_NUM+TC_INST_NUM];
|
static bool tcEnabled[TCC_INST_NUM+TC_INST_NUM];
|
||||||
|
|
||||||
if(attr & PIN_ATTR_PWM_E)
|
if (attr & PIN_ATTR_TIMER) {
|
||||||
pinPeripheral(pin, PIO_TIMER);
|
#if !(ARDUINO_SAMD_VARIANT_COMPLIANCE >= 10603)
|
||||||
else if(attr & PIN_ATTR_PWM_F)
|
// Compatibility for cores based on SAMD core <=1.6.2
|
||||||
|
if (pinDesc.ulPinType == PIO_TIMER_ALT) {
|
||||||
pinPeripheral(pin, PIO_TIMER_ALT);
|
pinPeripheral(pin, PIO_TIMER_ALT);
|
||||||
else if(attr & PIN_ATTR_PWM_G)
|
} else
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
|
||||||
|
#if defined(__SAMD51__)
|
||||||
|
//on SAMD51 we are only using TCC for timers
|
||||||
pinPeripheral(pin, PIO_TCC_PDEC);
|
pinPeripheral(pin, PIO_TCC_PDEC);
|
||||||
|
#else
|
||||||
|
pinPeripheral(pin, PIO_TIMER);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
} 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]) {
|
if (!tcEnabled[tcNum]) {
|
||||||
tcEnabled[tcNum] = true;
|
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
|
GCLK->PCHCTRL[GCLK_CLKCTRL_IDs[tcNum]].reg = GCLK_PCHCTRL_GEN_GCLK0_Val | (1 << GCLK_PCHCTRL_CHEN_Pos); //use clock generator 0
|
||||||
|
|
||||||
// Set PORT
|
// Set PORT
|
||||||
|
|
@ -555,8 +527,7 @@ void analogWrite(uint32_t pin, uint32_t value)
|
||||||
TCCx->CTRLA.bit.ENABLE = 1;
|
TCCx->CTRLA.bit.ENABLE = 1;
|
||||||
while (TCCx->SYNCBUSY.bit.ENABLE);
|
while (TCCx->SYNCBUSY.bit.ENABLE);
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
if (tcNum >= TCC_INST_NUM) {
|
if (tcNum >= TCC_INST_NUM) {
|
||||||
Tc* TCx = (Tc*) GetTC(pinDesc.ulPWMChannel);
|
Tc* TCx = (Tc*) GetTC(pinDesc.ulPWMChannel);
|
||||||
TCx->COUNT8.CC[tcChannel].reg = (uint8_t) value;
|
TCx->COUNT8.CC[tcChannel].reg = (uint8_t) value;
|
||||||
|
|
@ -572,39 +543,7 @@ void analogWrite(uint32_t pin, uint32_t value)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
#else
|
#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[] = {
|
uint16_t GCLK_CLKCTRL_IDs[] = {
|
||||||
GCLK_CLKCTRL_ID(GCM_TCC0_TCC1), // TCC0
|
GCLK_CLKCTRL_ID(GCM_TCC0_TCC1), // TCC0
|
||||||
GCLK_CLKCTRL_ID(GCM_TCC0_TCC1), // TCC1
|
GCLK_CLKCTRL_ID(GCM_TCC0_TCC1), // TCC1
|
||||||
|
|
@ -668,9 +607,10 @@ void analogWrite(uint32_t pin, uint32_t value)
|
||||||
syncTCC(TCCx);
|
syncTCC(TCCx);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
// -- Defaults to digital write
|
// -- Defaults to digital write
|
||||||
pinMode(pin, OUTPUT);
|
pinMode(pin, OUTPUT);
|
||||||
|
|
|
||||||
|
|
@ -27,21 +27,14 @@ extern "C" {
|
||||||
/*
|
/*
|
||||||
* \brief SAMD products have only one reference for ADC
|
* \brief SAMD products have only one reference for ADC
|
||||||
*/
|
*/
|
||||||
// add internal voltages for ATSAMD51 SUPC VREF register
|
|
||||||
typedef enum _eAnalogReference
|
typedef enum _eAnalogReference
|
||||||
{
|
{
|
||||||
AR_DEFAULT,
|
AR_DEFAULT,
|
||||||
|
AR_INTERNAL,
|
||||||
|
AR_EXTERNAL,
|
||||||
AR_INTERNAL1V0,
|
AR_INTERNAL1V0,
|
||||||
AR_INTERNAL1V1,
|
|
||||||
AR_INTERNAL1V2,
|
|
||||||
AR_INTERNAL1V25,
|
|
||||||
AR_INTERNAL2V0,
|
|
||||||
AR_INTERNAL2V2,
|
|
||||||
AR_INTERNAL2V23,
|
|
||||||
AR_INTERNAL2V4,
|
|
||||||
AR_INTERNAL2V5,
|
|
||||||
AR_INTERNAL1V65,
|
AR_INTERNAL1V65,
|
||||||
AR_EXTERNAL
|
AR_INTERNAL2V23
|
||||||
} eAnalogReference ;
|
} eAnalogReference ;
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -30,43 +30,39 @@ void pinMode( uint32_t ulPin, uint32_t ulMode )
|
||||||
return ;
|
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'
|
// Set pin mode according to chapter '22.6.3 I/O Pin Configuration'
|
||||||
switch ( ulMode )
|
switch ( ulMode )
|
||||||
{
|
{
|
||||||
case INPUT:
|
case INPUT:
|
||||||
// Set pin to input mode
|
// Set pin to input mode
|
||||||
PORT->Group[port].PINCFG[pin].reg=(uint8_t)(PORT_PINCFG_INEN) ;
|
PORT->Group[g_APinDescription[ulPin].ulPort].PINCFG[g_APinDescription[ulPin].ulPin].reg=(uint8_t)(PORT_PINCFG_INEN) ;
|
||||||
PORT->Group[port].DIRCLR.reg = pinMask ;
|
PORT->Group[g_APinDescription[ulPin].ulPort].DIRCLR.reg = (uint32_t)(1<<g_APinDescription[ulPin].ulPin) ;
|
||||||
break ;
|
break ;
|
||||||
|
|
||||||
case INPUT_PULLUP:
|
case INPUT_PULLUP:
|
||||||
// Set pin to input mode with pull-up resistor enabled
|
// Set pin to input mode with pull-up resistor enabled
|
||||||
PORT->Group[port].PINCFG[pin].reg=(uint8_t)(PORT_PINCFG_INEN|PORT_PINCFG_PULLEN) ;
|
PORT->Group[g_APinDescription[ulPin].ulPort].PINCFG[g_APinDescription[ulPin].ulPin].reg=(uint8_t)(PORT_PINCFG_INEN|PORT_PINCFG_PULLEN) ;
|
||||||
PORT->Group[port].DIRCLR.reg = pinMask ;
|
PORT->Group[g_APinDescription[ulPin].ulPort].DIRCLR.reg = (uint32_t)(1<<g_APinDescription[ulPin].ulPin) ;
|
||||||
|
|
||||||
// Enable pull level (cf '22.6.3.2 Input Configuration' and '22.8.7 Data Output Value Set')
|
// Enable pull level (cf '22.6.3.2 Input Configuration' and '22.8.7 Data Output Value Set')
|
||||||
PORT->Group[port].OUTSET.reg = pinMask ;
|
PORT->Group[g_APinDescription[ulPin].ulPort].OUTSET.reg = (uint32_t)(1<<g_APinDescription[ulPin].ulPin) ;
|
||||||
break ;
|
break ;
|
||||||
|
|
||||||
case INPUT_PULLDOWN:
|
case INPUT_PULLDOWN:
|
||||||
// Set pin to input mode with pull-down resistor enabled
|
// Set pin to input mode with pull-down resistor enabled
|
||||||
PORT->Group[port].PINCFG[pin].reg=(uint8_t)(PORT_PINCFG_INEN|PORT_PINCFG_PULLEN) ;
|
PORT->Group[g_APinDescription[ulPin].ulPort].PINCFG[g_APinDescription[ulPin].ulPin].reg=(uint8_t)(PORT_PINCFG_INEN|PORT_PINCFG_PULLEN) ;
|
||||||
PORT->Group[port].DIRCLR.reg = pinMask ;
|
PORT->Group[g_APinDescription[ulPin].ulPort].DIRCLR.reg = (uint32_t)(1<<g_APinDescription[ulPin].ulPin) ;
|
||||||
|
|
||||||
// Enable pull level (cf '22.6.3.2 Input Configuration' and '22.8.6 Data Output Value Clear')
|
// Enable pull level (cf '22.6.3.2 Input Configuration' and '22.8.6 Data Output Value Clear')
|
||||||
PORT->Group[port].OUTCLR.reg = pinMask ;
|
PORT->Group[g_APinDescription[ulPin].ulPort].OUTCLR.reg = (uint32_t)(1<<g_APinDescription[ulPin].ulPin) ;
|
||||||
break ;
|
break ;
|
||||||
|
|
||||||
case OUTPUT:
|
case OUTPUT:
|
||||||
// enable input, to support reading back values, with pullups disabled
|
// enable input, to support reading back values, with pullups disabled
|
||||||
PORT->Group[port].PINCFG[pin].reg=(uint8_t)(PORT_PINCFG_INEN) ;
|
PORT->Group[g_APinDescription[ulPin].ulPort].PINCFG[g_APinDescription[ulPin].ulPin].reg=(uint8_t)(PORT_PINCFG_INEN) ;
|
||||||
|
|
||||||
// Set pin to output mode
|
// Set pin to output mode
|
||||||
PORT->Group[port].DIRSET.reg = pinMask ;
|
PORT->Group[g_APinDescription[ulPin].ulPort].DIRSET.reg = (uint32_t)(1<<g_APinDescription[ulPin].ulPin) ;
|
||||||
break ;
|
break ;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
|
|
||||||
|
|
@ -107,7 +107,7 @@ int pinPeripheral( uint32_t ulPin, EPioType ulPeripheral )
|
||||||
// Set new muxing
|
// Set new muxing
|
||||||
PORT->Group[g_APinDescription[ulPin].ulPort].PMUX[g_APinDescription[ulPin].ulPin >> 1].reg = temp|PORT_PMUX_PMUXO( ulPeripheral ) ;
|
PORT->Group[g_APinDescription[ulPin].ulPort].PMUX[g_APinDescription[ulPin].ulPin >> 1].reg = temp|PORT_PMUX_PMUXO( ulPeripheral ) ;
|
||||||
// Enable port mux
|
// Enable port mux
|
||||||
PORT->Group[g_APinDescription[ulPin].ulPort].PINCFG[g_APinDescription[ulPin].ulPin].reg |= PORT_PINCFG_PMUXEN | PORT_PINCFG_DRVSTR;
|
PORT->Group[g_APinDescription[ulPin].ulPort].PINCFG[g_APinDescription[ulPin].ulPin].reg |= PORT_PINCFG_PMUXEN ;
|
||||||
}
|
}
|
||||||
else // even pin
|
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 ) ;
|
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].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 | PORT_PINCFG_DRVSTR ; // Enable port mux
|
PORT->Group[g_APinDescription[ulPin].ulPort].PINCFG[g_APinDescription[ulPin].ulPin].reg |= PORT_PINCFG_PMUXEN ; // Enable port mux
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
break ;
|
break ;
|
||||||
|
|
|
||||||
Binary file not shown.
|
|
@ -46,14 +46,6 @@ StartType=3
|
||||||
ErrorControl=1
|
ErrorControl=1
|
||||||
ServiceBinary=%12%\%DRIVERFILENAME%.sys
|
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
|
; Vista-64bit Sections
|
||||||
;------------------------------------------------------------------------------
|
;------------------------------------------------------------------------------
|
||||||
|
|
@ -81,13 +73,6 @@ StartType=3
|
||||||
ErrorControl=1
|
ErrorControl=1
|
||||||
ServiceBinary=%12%\%DRIVERFILENAME%.sys
|
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
|
; Vendor and Product ID Definitions
|
||||||
|
|
@ -102,14 +87,14 @@ AddService=, 0x00000002
|
||||||
[SourceDisksNames]
|
[SourceDisksNames]
|
||||||
[DeviceList]
|
[DeviceList]
|
||||||
"%DESCRIPTION% UF2 Bootloader (0018:00) BSP"=DriverInstall, USB\VID_239A&PID_0018&MI_00
|
"%DESCRIPTION% UF2 Bootloader (0018:00) 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% UF2 WebUSB dummy (0018:04) BSP"=DriverInstall, USB\VID_239A&PID_0018&MI_00
|
||||||
"%DESCRIPTION% (0019:00) BSP"=DriverInstall, USB\VID_239A&PID_0019&MI_00
|
"%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% 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
|
"%DESCRIPTION% CircuitPython (8019:00) BSP"=DriverInstall, USB\VID_239A&PID_8019&MI_00
|
||||||
|
|
||||||
[DeviceList.NTamd64]
|
[DeviceList.NTamd64]
|
||||||
"%DESCRIPTION% UF2 Bootloader (0018:00) BSP"=DriverInstall, USB\VID_239A&PID_0018&MI_00
|
"%DESCRIPTION% UF2 Bootloader (0018:00) 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% UF2 WebUSB dummy (0018:04) BSP"=DriverInstall, USB\VID_239A&PID_0018&MI_00
|
||||||
"%DESCRIPTION% (0019:00) BSP"=DriverInstall, USB\VID_239A&PID_0019&MI_00
|
"%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% 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
|
"%DESCRIPTION% CircuitPython (8019:00) BSP"=DriverInstall, USB\VID_239A&PID_8019&MI_00
|
||||||
|
|
|
||||||
|
|
@ -1,124 +0,0 @@
|
||||||
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,3 +1,2 @@
|
||||||
SerialGSM KEYWORD1
|
SerialGSM KEYWORD1
|
||||||
SerialSARA KEYWORD1
|
|
||||||
INPUT_PULLDOWN LITERAL1 Constants RESERVED_WORD_2
|
INPUT_PULLDOWN LITERAL1 Constants RESERVED_WORD_2
|
||||||
|
|
|
||||||
|
|
@ -1,654 +0,0 @@
|
||||||
#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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,66 +0,0 @@
|
||||||
#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_
|
|
||||||
|
|
@ -1,22 +0,0 @@
|
||||||
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.
|
|
||||||
|
|
||||||
|
|
@ -1,6 +0,0 @@
|
||||||
# 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.
|
|
||||||
|
|
@ -1,95 +0,0 @@
|
||||||
// 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() { }
|
|
||||||
|
|
@ -1,98 +0,0 @@
|
||||||
// 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() { }
|
|
||||||
|
|
@ -1,104 +0,0 @@
|
||||||
// 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++;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
@ -1,9 +0,0 @@
|
||||||
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
|
|
||||||
|
|
@ -1,145 +0,0 @@
|
||||||
/**
|
|
||||||
* \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 +0,0 @@
|
||||||
// fake empty header file to make Arduino IDE happy
|
|
||||||
|
|
@ -1,12 +0,0 @@
|
||||||
#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);
|
|
||||||
}
|
|
||||||
|
|
@ -28,5 +28,4 @@ buildSDUBootSketch "arduino:samd:mkrfox1200" "$OUTPUT_PATH/mkrfox1200.h"
|
||||||
buildSDUBootSketch "arduino:samd:mkrgsm1400" "$OUTPUT_PATH/mkrgsm1400.h"
|
buildSDUBootSketch "arduino:samd:mkrgsm1400" "$OUTPUT_PATH/mkrgsm1400.h"
|
||||||
buildSDUBootSketch "arduino:samd:mkrwan1300" "$OUTPUT_PATH/mkrwan1300.h"
|
buildSDUBootSketch "arduino:samd:mkrwan1300" "$OUTPUT_PATH/mkrwan1300.h"
|
||||||
buildSDUBootSketch "arduino:samd:mkrwifi1010" "$OUTPUT_PATH/mkrwifi1010.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"
|
buildSDUBootSketch "arduino:samd:mzero_bl" "$OUTPUT_PATH/mzero.h"
|
||||||
|
|
|
||||||
|
|
@ -36,8 +36,6 @@ unsigned char sduBoot[0x4000] = {
|
||||||
#include "boot/mkrwan1300.h"
|
#include "boot/mkrwan1300.h"
|
||||||
#elif defined(ARDUINO_SAMD_MKRWIFI1010)
|
#elif defined(ARDUINO_SAMD_MKRWIFI1010)
|
||||||
#include "boot/mkrwifi1010.h"
|
#include "boot/mkrwifi1010.h"
|
||||||
#elif defined(ARDUINO_SAMD_MKRNB1500)
|
|
||||||
#include "boot/mkrnb1500.h"
|
|
||||||
#elif defined(ARDUINO_SAM_ZERO)
|
#elif defined(ARDUINO_SAM_ZERO)
|
||||||
#include "boot/mzero.h"
|
#include "boot/mzero.h"
|
||||||
#else
|
#else
|
||||||
|
|
|
||||||
File diff suppressed because it is too large
Load diff
|
|
@ -46,16 +46,7 @@ SPIClass::SPIClass(SERCOM *p_sercom, uint8_t uc_pinMISO, uint8_t uc_pinSCK, uint
|
||||||
|
|
||||||
void SPIClass::begin()
|
void SPIClass::begin()
|
||||||
{
|
{
|
||||||
if(!initialized) {
|
init();
|
||||||
interruptMode = SPI_IMODE_NONE;
|
|
||||||
interruptSave = 0;
|
|
||||||
interruptMask = 0;
|
|
||||||
initialized = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(!use_dma) {
|
|
||||||
dmaAllocate();
|
|
||||||
}
|
|
||||||
|
|
||||||
// PIO init
|
// PIO init
|
||||||
pinPeripheral(_uc_pinMiso, g_APinDescription[_uc_pinMiso].ulPinType);
|
pinPeripheral(_uc_pinMiso, g_APinDescription[_uc_pinMiso].ulPinType);
|
||||||
|
|
@ -65,6 +56,16 @@ void SPIClass::begin()
|
||||||
config(DEFAULT_SPI_SETTINGS);
|
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)
|
void SPIClass::config(SPISettings settings)
|
||||||
{
|
{
|
||||||
_p_sercom->disableSPI();
|
_p_sercom->disableSPI();
|
||||||
|
|
@ -79,7 +80,6 @@ void SPIClass::end()
|
||||||
{
|
{
|
||||||
_p_sercom->resetSPI();
|
_p_sercom->resetSPI();
|
||||||
initialized = false;
|
initialized = false;
|
||||||
// Add DMA deallocation here
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifndef interruptsStatus
|
#ifndef interruptsStatus
|
||||||
|
|
@ -235,231 +235,6 @@ 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() {
|
void SPIClass::attachInterrupt() {
|
||||||
// Should be enableInterrupt()
|
// Should be enableInterrupt()
|
||||||
}
|
}
|
||||||
|
|
@ -468,61 +243,6 @@ void SPIClass::detachInterrupt() {
|
||||||
// Should be disableInterrupt()
|
// 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
|
#if SPI_INTERFACES_COUNT > 0
|
||||||
/* In case new variant doesn't define these macros,
|
/* In case new variant doesn't define these macros,
|
||||||
* we put here the ones for Arduino Zero.
|
* we put here the ones for Arduino Zero.
|
||||||
|
|
@ -555,3 +275,4 @@ void SPIClass::setClockSource(SercomClockSource clk) {
|
||||||
#if SPI_INTERFACES_COUNT > 5
|
#if SPI_INTERFACES_COUNT > 5
|
||||||
SPIClass SPI5(&PERIPH_SPI5, PIN_SPI5_MISO, PIN_SPI5_SCK, PIN_SPI5_MOSI, PAD_SPI5_TX, PAD_SPI5_RX);
|
SPIClass SPI5(&PERIPH_SPI5, PIN_SPI5_MISO, PIN_SPI5_SCK, PIN_SPI5_MOSI, PAD_SPI5_TX, PAD_SPI5_RX);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -21,7 +21,6 @@
|
||||||
#define _SPI_H_INCLUDED
|
#define _SPI_H_INCLUDED
|
||||||
|
|
||||||
#include <Arduino.h>
|
#include <Arduino.h>
|
||||||
#include <Adafruit_ZeroDMA.h>
|
|
||||||
|
|
||||||
// SPI_HAS_TRANSACTION means SPI has
|
// SPI_HAS_TRANSACTION means SPI has
|
||||||
// - beginTransaction()
|
// - beginTransaction()
|
||||||
|
|
@ -38,27 +37,12 @@
|
||||||
#define SPI_MODE2 0x03
|
#define SPI_MODE2 0x03
|
||||||
#define SPI_MODE3 0x01
|
#define SPI_MODE3 0x01
|
||||||
|
|
||||||
#if defined(__SAMD51__)
|
#if defined(ARDUINO_ARCH_SAMD)
|
||||||
// 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,
|
// The datasheet specifies a typical SPI SCK period (tSCK) of 42 ns,
|
||||||
// see "Table 36-48. SPI Timing Characteristics and Requirements",
|
// see "Table 36-48. SPI Timing Characteristics and Requirements",
|
||||||
// which translates into a maximum SPI clock of 23.8 MHz.
|
// which translates into a maximum SPI clock of 23.8 MHz.
|
||||||
// We'll permit use of 24 MHz SPI even though this is slightly out
|
// Conservatively, the divider is set for a 12 MHz maximum SPI clock.
|
||||||
// of spec. Given how clock dividers work, the next "sensible"
|
#define SPI_MIN_CLOCK_DIVIDER (uint8_t)(1 + ((F_CPU - 1) / 12000000))
|
||||||
// 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
|
#endif
|
||||||
|
|
||||||
class SPISettings {
|
class SPISettings {
|
||||||
|
|
@ -80,11 +64,7 @@ class SPISettings {
|
||||||
}
|
}
|
||||||
|
|
||||||
void init_AlwaysInline(uint32_t clock, BitOrder bitOrder, uint8_t dataMode) __attribute__((__always_inline__)) {
|
void init_AlwaysInline(uint32_t clock, BitOrder bitOrder, uint8_t dataMode) __attribute__((__always_inline__)) {
|
||||||
#if defined(__SAMD51__)
|
this->clockFreq = (clock >= (F_CPU / SPI_MIN_CLOCK_DIVIDER) ? F_CPU / SPI_MIN_CLOCK_DIVIDER : clock);
|
||||||
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);
|
this->bitOrder = (bitOrder == MSBFIRST ? MSB_FIRST : LSB_FIRST);
|
||||||
|
|
||||||
|
|
@ -114,12 +94,10 @@ class SPIClass {
|
||||||
public:
|
public:
|
||||||
SPIClass(SERCOM *p_sercom, uint8_t uc_pinMISO, uint8_t uc_pinSCK, uint8_t uc_pinMOSI, SercomSpiTXPad, SercomRXPad);
|
SPIClass(SERCOM *p_sercom, uint8_t uc_pinMISO, uint8_t uc_pinSCK, uint8_t uc_pinMOSI, SercomSpiTXPad, SercomRXPad);
|
||||||
|
|
||||||
|
|
||||||
byte transfer(uint8_t data);
|
byte transfer(uint8_t data);
|
||||||
uint16_t transfer16(uint16_t data);
|
uint16_t transfer16(uint16_t data);
|
||||||
void transfer(void *buf, size_t count);
|
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
|
// Transaction Functions
|
||||||
void usingInterrupt(int interruptNumber);
|
void usingInterrupt(int interruptNumber);
|
||||||
|
|
@ -138,21 +116,8 @@ class SPIClass {
|
||||||
void setDataMode(uint8_t uc_mode);
|
void setDataMode(uint8_t uc_mode);
|
||||||
void setClockDivider(uint8_t uc_div);
|
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:
|
private:
|
||||||
|
void init();
|
||||||
void config(SPISettings settings);
|
void config(SPISettings settings);
|
||||||
|
|
||||||
SERCOM *_p_sercom;
|
SERCOM *_p_sercom;
|
||||||
|
|
@ -167,18 +132,6 @@ class SPIClass {
|
||||||
uint8_t interruptMode;
|
uint8_t interruptMode;
|
||||||
char interruptSave;
|
char interruptSave;
|
||||||
uint32_t interruptMask;
|
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
|
#if SPI_INTERFACES_COUNT > 0
|
||||||
|
|
@ -202,12 +155,14 @@ class SPIClass {
|
||||||
|
|
||||||
// For compatibility with sketches designed for AVR @ 16 MHz
|
// For compatibility with sketches designed for AVR @ 16 MHz
|
||||||
// New programs should use SPI.beginTransaction to set the SPI clock
|
// New programs should use SPI.beginTransaction to set the SPI clock
|
||||||
#define SPI_CLOCK_DIV2 (MAX_SPI * 2 / 8000000)
|
#if F_CPU == 48000000
|
||||||
#define SPI_CLOCK_DIV4 (MAX_SPI * 2 / 4000000)
|
#define SPI_CLOCK_DIV2 6
|
||||||
#define SPI_CLOCK_DIV8 (MAX_SPI * 2 / 2000000)
|
#define SPI_CLOCK_DIV4 12
|
||||||
#define SPI_CLOCK_DIV16 (MAX_SPI * 2 / 1000000)
|
#define SPI_CLOCK_DIV8 24
|
||||||
#define SPI_CLOCK_DIV32 (MAX_SPI * 2 / 500000)
|
#define SPI_CLOCK_DIV16 48
|
||||||
#define SPI_CLOCK_DIV64 (MAX_SPI * 2 / 250000)
|
#define SPI_CLOCK_DIV32 96
|
||||||
#define SPI_CLOCK_DIV128 (MAX_SPI * 2 / 125000)
|
#define SPI_CLOCK_DIV64 192
|
||||||
|
#define SPI_CLOCK_DIV128 255
|
||||||
|
#endif
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
|
|
@ -1,25 +0,0 @@
|
||||||
= 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
|
|
||||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue