Compare commits

..

12 commits

283 changed files with 1680 additions and 24411 deletions

View file

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

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

View file

@ -1,40 +1,5 @@
SAMD CORE ?.?.?? ????.??.??
SAMD CORE 1.6.21 2019.04.01
* MKR boards: changed I2C to sercom2, SPI1 + Serial2 to sercom4
* Improved accuracy of delay() function. Thanks @BenF
* MKR 1500: Changed SARA module to be powered off on boot
SAMD CORE 1.6.20 2018.11.28
* Replaced boolean type with bool in examples. Thanks @per1234
* Added c++ linker command to allow to include libstdc++ when linking. Thanks @helmut64
* CPX driver fixes. Thanks @dhalbert
* I2S: Changed library to use 8 MHz oscillator source if 48MHz divider does not fit in 8 bits
* UART: Added frame error handling
* USB: Fixed memory leak on reconnects
* SDU: Added support for Arduino M0. Thanks @jandrassy
* Added arduinoOTA upload keys for Arduino M0. Thanks @jandrassy
* USB: Fixed USB Host failures and fixed memory overwrite in USBHost. Thanks @gdsports
* USB: Added method to return USB error code. Thanks @MarkFischer
* CDC: Clear line state on end()
* USB: Added USB device end() method
* Removed requirement that the DAC is on A0. Thanks @GabrielNotman
* Added alternate ports 44, 45 to make the SWCLK and SWDIO pins available on the Zero. Thanks @helmut64
* Added defines for MKR pin layout
* Fixed freeze in tone()
* Added MKR NB 1500 variant and bootloader
* Increased the default serial buffer size to 256
SAMD CORE 1.6.19 2018.07.11
* Fixed bootloader tools for .org boards
* M0: Updated pin definitions for D6, D7 and D13 to match Zero
* SPI: Fixed interrupt mask to block. Thanks @ggajoch
* Added MKR WiFi 1010 variant and bootloader
* Updated Windows Drivers to 1.4.0 and re-signed Adafruit_Circuit_Playground_Express.inf
SAMD CORE 1.6.18 2018.03.05
* Wire: Added support for general call (broadcast)

View file

@ -1,16 +1,47 @@
# Arduino Core for SAMD21 and SAMD51 CPU
[![Build Status](https://github.com/adafruit/ArduinoCore-samd/workflows/Build/badge.svg)](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
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
## 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.
* USB host mode doesn't work yet
The ATSAMD51 is a significantly new chip, so this is a detailed process for now! For the SAMD21, please install via the board manager (no extra steps required)
1. Install Arduino IDE 1.8.5 or greater
2. Install/update the Adafruit SAMD board support package if you have installed it
3. Now we need to update CMSIS! Download https://github.com/adafruit/ArduinoModule-CMSIS-Atmel/archive/master.zip and unzip
4. Find your Arduino CMSIS, in Mac its "~/Library/Arduino15/packages/arduino/tools/CMSIS-Atmel/1.1.0/CMSIS" version # may vary, you'll need "Go to folder..." feature in the Finder to get to " ~/Library/Arduino15" as it is hidden. In Windows it is "C:\Users\yourusername\AppData\Local\Arduino15\packages\arduino\tools\CMSIS-Atmel\1.1.0\CMSIS" Inside is a folder named Device
For Linux: the Arduino stuff is located in ~/.arduino15/packages/arduino/tools/CMSIS-Atmel/1.1.0/CMSIS
5. Inside the downloaded CMSIS zip, go into the CMSIS-Atmel/CMSIS folder, you should see a folder named Device. *DRAG THE DEVICE FOLDER ONLY* from the zip to your arduino Library folder so that Device is merged with Device. It will replace a bunch of files.
For Linux, it may be better to just delete the original Device Folder then copy over the new one - the drag/drop worked ok on MACOS, but not so well on my Linux box.
6. You will also need to replace bossac. For Windows or Mac: Go here https://github.com/adafruit/BOSSA/releases and download either windows exe or mac app of latest bossac. unzip. Go to Step 12.
For Linux users it is best to build a copy of bossac locally -
clone the Adafruit Repostitory to somewhere on your local machine.
```
git clone https://github.com/adafruit/BOSSA.git
change to the arduino branch
git checkout arduino
```
Follow the instructions to build bossac in README.md or at https://github.com/adafruit/BOSSA/tree/arduino.
7. Replace the binary at ".../Library/Arduino15/packages/arduino/tools/bossac/1.7.0/bossac" or "...\AppData\Local\Arduino15\packages\arduino\tools\bossac\1.7.0\bossac"
8. On Windows 7 you will also need to install the updated serial driver, download https://github.com/adafruit/Adafruit_Windows_Drivers/archive/master.zip to get all the drivers, and point the Device Manager to the unzipped folder. It isn't signed, so just approve the installation manually.
13. That's it!
## Bugs or Issues
If you find a bug you can submit an issue here on github:

1317
boards.txt

File diff suppressed because it is too large Load diff

View file

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

View file

@ -218,11 +218,7 @@ void I2S_Handler ( void );
* \brief Configuration of the Cortex-M0+ Processor and Core Peripherals
*/
#if defined(LITTLE_ENDIAN) && (LITTLE_ENDIAN != 1)
#error "Little Endian is already defined, but to different value than expected?!"
#else
#define LITTLE_ENDIAN 1
#endif
#define LITTLE_ENDIAN 1
#define __CM0PLUS_REV 1 /*!< Core revision r0p1 */
#define __MPU_PRESENT 0 /*!< MPU present or not */
#define __NVIC_PRIO_BITS 2 /*!< Number of bits used for Priority Levels */

View file

@ -218,11 +218,7 @@ void I2S_Handler ( void );
* \brief Configuration of the Cortex-M0+ Processor and Core Peripherals
*/
#if defined(LITTLE_ENDIAN) && (LITTLE_ENDIAN != 1)
#error "Little Endian is already defined, but to different value than expected?!"
#else
#define LITTLE_ENDIAN 1
#endif
#define LITTLE_ENDIAN 1
#define __CM0PLUS_REV 1 /*!< Core revision r0p1 */
#define __MPU_PRESENT 0 /*!< MPU present or not */
#define __NVIC_PRIO_BITS 2 /*!< Number of bits used for Priority Levels */

View file

@ -218,11 +218,7 @@ void I2S_Handler ( void );
* \brief Configuration of the Cortex-M0+ Processor and Core Peripherals
*/
#if defined(LITTLE_ENDIAN) && (LITTLE_ENDIAN != 1)
#error "Little Endian is already defined, but to different value than expected?!"
#else
#define LITTLE_ENDIAN 1
#endif
#define LITTLE_ENDIAN 1
#define __CM0PLUS_REV 1 /*!< Core revision r0p1 */
#define __MPU_PRESENT 0 /*!< MPU present or not */
#define __NVIC_PRIO_BITS 2 /*!< Number of bits used for Priority Levels */

View file

@ -218,11 +218,7 @@ void I2S_Handler ( void );
* \brief Configuration of the Cortex-M0+ Processor and Core Peripherals
*/
#if defined(LITTLE_ENDIAN) && (LITTLE_ENDIAN != 1)
#error "Little Endian is already defined, but to different value than expected?!"
#else
#define LITTLE_ENDIAN 1
#endif
#define LITTLE_ENDIAN 1
#define __CM0PLUS_REV 1 /*!< Core revision r0p1 */
#define __MPU_PRESENT 0 /*!< MPU present or not */
#define __NVIC_PRIO_BITS 2 /*!< Number of bits used for Priority Levels */

View file

@ -222,11 +222,7 @@ void I2S_Handler ( void );
* \brief Configuration of the Cortex-M0+ Processor and Core Peripherals
*/
#if defined(LITTLE_ENDIAN) && (LITTLE_ENDIAN != 1)
#error "Little Endian is already defined, but to different value than expected?!"
#else
#define LITTLE_ENDIAN 1
#endif
#define LITTLE_ENDIAN 1
#define __CM0PLUS_REV 1 /*!< Core revision r0p1 */
#define __MPU_PRESENT 0 /*!< MPU present or not */
#define __NVIC_PRIO_BITS 2 /*!< Number of bits used for Priority Levels */

View file

@ -222,11 +222,7 @@ void I2S_Handler ( void );
* \brief Configuration of the Cortex-M0+ Processor and Core Peripherals
*/
#if defined(LITTLE_ENDIAN) && (LITTLE_ENDIAN != 1)
#error "Little Endian is already defined, but to different value than expected?!"
#else
#define LITTLE_ENDIAN 1
#endif
#define LITTLE_ENDIAN 1
#define __CM0PLUS_REV 1 /*!< Core revision r0p1 */
#define __MPU_PRESENT 0 /*!< MPU present or not */
#define __NVIC_PRIO_BITS 2 /*!< Number of bits used for Priority Levels */

View file

@ -222,11 +222,7 @@ void I2S_Handler ( void );
* \brief Configuration of the Cortex-M0+ Processor and Core Peripherals
*/
#if defined(LITTLE_ENDIAN) && (LITTLE_ENDIAN != 1)
#error "Little Endian is already defined, but to different value than expected?!"
#else
#define LITTLE_ENDIAN 1
#endif
#define LITTLE_ENDIAN 1
#define __CM0PLUS_REV 1 /*!< Core revision r0p1 */
#define __MPU_PRESENT 0 /*!< MPU present or not */
#define __NVIC_PRIO_BITS 2 /*!< Number of bits used for Priority Levels */

View file

@ -222,11 +222,7 @@ void I2S_Handler ( void );
* \brief Configuration of the Cortex-M0+ Processor and Core Peripherals
*/
#if defined(LITTLE_ENDIAN) && (LITTLE_ENDIAN != 1)
#error "Little Endian is already defined, but to different value than expected?!"
#else
#define LITTLE_ENDIAN 1
#endif
#define LITTLE_ENDIAN 1
#define __CM0PLUS_REV 1 /*!< Core revision r0p1 */
#define __MPU_PRESENT 0 /*!< MPU present or not */
#define __NVIC_PRIO_BITS 2 /*!< Number of bits used for Priority Levels */

View file

@ -226,11 +226,7 @@ void I2S_Handler ( void );
* \brief Configuration of the Cortex-M0+ Processor and Core Peripherals
*/
#if defined(LITTLE_ENDIAN) && (LITTLE_ENDIAN != 1)
#error "Little Endian is already defined, but to different value than expected?!"
#else
#define LITTLE_ENDIAN 1
#endif
#define LITTLE_ENDIAN 1
#define __CM0PLUS_REV 1 /*!< Core revision r0p1 */
#define __MPU_PRESENT 0 /*!< MPU present or not */
#define __NVIC_PRIO_BITS 2 /*!< Number of bits used for Priority Levels */

View file

@ -226,11 +226,7 @@ void I2S_Handler ( void );
* \brief Configuration of the Cortex-M0+ Processor and Core Peripherals
*/
#if defined(LITTLE_ENDIAN) && (LITTLE_ENDIAN != 1)
#error "Little Endian is already defined, but to different value than expected?!"
#else
#define LITTLE_ENDIAN 1
#endif
#define LITTLE_ENDIAN 1
#define __CM0PLUS_REV 1 /*!< Core revision r0p1 */
#define __MPU_PRESENT 0 /*!< MPU present or not */
#define __NVIC_PRIO_BITS 2 /*!< Number of bits used for Priority Levels */

View file

@ -226,11 +226,7 @@ void I2S_Handler ( void );
* \brief Configuration of the Cortex-M0+ Processor and Core Peripherals
*/
#if defined(LITTLE_ENDIAN) && (LITTLE_ENDIAN != 1)
#error "Little Endian is already defined, but to different value than expected?!"
#else
#define LITTLE_ENDIAN 1
#endif
#define LITTLE_ENDIAN 1
#define __CM0PLUS_REV 1 /*!< Core revision r0p1 */
#define __MPU_PRESENT 0 /*!< MPU present or not */
#define __NVIC_PRIO_BITS 2 /*!< Number of bits used for Priority Levels */

View file

@ -226,11 +226,7 @@ void I2S_Handler ( void );
* \brief Configuration of the Cortex-M0+ Processor and Core Peripherals
*/
#if defined(LITTLE_ENDIAN) && (LITTLE_ENDIAN != 1)
#error "Little Endian is already defined, but to different value than expected?!"
#else
#define LITTLE_ENDIAN 1
#endif
#define LITTLE_ENDIAN 1
#define __CM0PLUS_REV 1 /*!< Core revision r0p1 */
#define __MPU_PRESENT 0 /*!< MPU present or not */
#define __NVIC_PRIO_BITS 2 /*!< Number of bits used for Priority Levels */

View file

@ -218,11 +218,7 @@ void I2S_Handler ( void );
* \brief Configuration of the Cortex-M0+ Processor and Core Peripherals
*/
#if defined(LITTLE_ENDIAN) && (LITTLE_ENDIAN != 1)
#error "Little Endian is already defined, but to different value than expected?!"
#else
#define LITTLE_ENDIAN 1
#endif
#define LITTLE_ENDIAN 1
#define __CM0PLUS_REV 1 /*!< Core revision r0p1 */
#define __MPU_PRESENT 0 /*!< MPU present or not */
#define __NVIC_PRIO_BITS 2 /*!< Number of bits used for Priority Levels */

View file

@ -218,11 +218,7 @@ void I2S_Handler ( void );
* \brief Configuration of the Cortex-M0+ Processor and Core Peripherals
*/
#if defined(LITTLE_ENDIAN) && (LITTLE_ENDIAN != 1)
#error "Little Endian is already defined, but to different value than expected?!"
#else
#define LITTLE_ENDIAN 1
#endif
#define LITTLE_ENDIAN 1
#define __CM0PLUS_REV 1 /*!< Core revision r0p1 */
#define __MPU_PRESENT 0 /*!< MPU present or not */
#define __NVIC_PRIO_BITS 2 /*!< Number of bits used for Priority Levels */

View file

@ -218,11 +218,7 @@ void I2S_Handler ( void );
* \brief Configuration of the Cortex-M0+ Processor and Core Peripherals
*/
#if defined(LITTLE_ENDIAN) && (LITTLE_ENDIAN != 1)
#error "Little Endian is already defined, but to different value than expected?!"
#else
#define LITTLE_ENDIAN 1
#endif
#define LITTLE_ENDIAN 1
#define __CM0PLUS_REV 1 /*!< Core revision r0p1 */
#define __MPU_PRESENT 0 /*!< MPU present or not */
#define __NVIC_PRIO_BITS 2 /*!< Number of bits used for Priority Levels */

View file

@ -218,11 +218,7 @@ void I2S_Handler ( void );
* \brief Configuration of the Cortex-M0+ Processor and Core Peripherals
*/
#if defined(LITTLE_ENDIAN) && (LITTLE_ENDIAN != 1)
#error "Little Endian is already defined, but to different value than expected?!"
#else
#define LITTLE_ENDIAN 1
#endif
#define LITTLE_ENDIAN 1
#define __CM0PLUS_REV 1 /*!< Core revision r0p1 */
#define __MPU_PRESENT 0 /*!< MPU present or not */
#define __NVIC_PRIO_BITS 2 /*!< Number of bits used for Priority Levels */

View file

@ -222,11 +222,7 @@ void I2S_Handler ( void );
* \brief Configuration of the Cortex-M0+ Processor and Core Peripherals
*/
#if defined(LITTLE_ENDIAN) && (LITTLE_ENDIAN != 1)
#error "Little Endian is already defined, but to different value than expected?!"
#else
#define LITTLE_ENDIAN 1
#endif
#define LITTLE_ENDIAN 1
#define __CM0PLUS_REV 1 /*!< Core revision r0p1 */
#define __MPU_PRESENT 0 /*!< MPU present or not */
#define __NVIC_PRIO_BITS 2 /*!< Number of bits used for Priority Levels */

View file

@ -222,11 +222,7 @@ void I2S_Handler ( void );
* \brief Configuration of the Cortex-M0+ Processor and Core Peripherals
*/
#if defined(LITTLE_ENDIAN) && (LITTLE_ENDIAN != 1)
#error "Little Endian is already defined, but to different value than expected?!"
#else
#define LITTLE_ENDIAN 1
#endif
#define LITTLE_ENDIAN 1
#define __CM0PLUS_REV 1 /*!< Core revision r0p1 */
#define __MPU_PRESENT 0 /*!< MPU present or not */
#define __NVIC_PRIO_BITS 2 /*!< Number of bits used for Priority Levels */

View file

@ -222,11 +222,7 @@ void I2S_Handler ( void );
* \brief Configuration of the Cortex-M0+ Processor and Core Peripherals
*/
#if defined(LITTLE_ENDIAN) && (LITTLE_ENDIAN != 1)
#error "Little Endian is already defined, but to different value than expected?!"
#else
#define LITTLE_ENDIAN 1
#endif
#define LITTLE_ENDIAN 1
#define __CM0PLUS_REV 1 /*!< Core revision r0p1 */
#define __MPU_PRESENT 0 /*!< MPU present or not */
#define __NVIC_PRIO_BITS 2 /*!< Number of bits used for Priority Levels */

View file

@ -222,11 +222,7 @@ void I2S_Handler ( void );
* \brief Configuration of the Cortex-M0+ Processor and Core Peripherals
*/
#if defined(LITTLE_ENDIAN) && (LITTLE_ENDIAN != 1)
#error "Little Endian is already defined, but to different value than expected?!"
#else
#define LITTLE_ENDIAN 1
#endif
#define LITTLE_ENDIAN 1
#define __CM0PLUS_REV 1 /*!< Core revision r0p1 */
#define __MPU_PRESENT 0 /*!< MPU present or not */
#define __NVIC_PRIO_BITS 2 /*!< Number of bits used for Priority Levels */

View file

@ -226,11 +226,7 @@ void I2S_Handler ( void );
* \brief Configuration of the Cortex-M0+ Processor and Core Peripherals
*/
#if defined(LITTLE_ENDIAN) && (LITTLE_ENDIAN != 1)
#error "Little Endian is already defined, but to different value than expected?!"
#else
#define LITTLE_ENDIAN 1
#endif
#define LITTLE_ENDIAN 1
#define __CM0PLUS_REV 1 /*!< Core revision r0p1 */
#define __MPU_PRESENT 0 /*!< MPU present or not */
#define __NVIC_PRIO_BITS 2 /*!< Number of bits used for Priority Levels */

View file

@ -226,11 +226,7 @@ void I2S_Handler ( void );
* \brief Configuration of the Cortex-M0+ Processor and Core Peripherals
*/
#if defined(LITTLE_ENDIAN) && (LITTLE_ENDIAN != 1)
#error "Little Endian is already defined, but to different value than expected?!"
#else
#define LITTLE_ENDIAN 1
#endif
#define LITTLE_ENDIAN 1
#define __CM0PLUS_REV 1 /*!< Core revision r0p1 */
#define __MPU_PRESENT 0 /*!< MPU present or not */
#define __NVIC_PRIO_BITS 2 /*!< Number of bits used for Priority Levels */

View file

@ -226,11 +226,7 @@ void I2S_Handler ( void );
* \brief Configuration of the Cortex-M0+ Processor and Core Peripherals
*/
#if defined(LITTLE_ENDIAN) && (LITTLE_ENDIAN != 1)
#error "Little Endian is already defined, but to different value than expected?!"
#else
#define LITTLE_ENDIAN 1
#endif
#define LITTLE_ENDIAN 1
#define __CM0PLUS_REV 1 /*!< Core revision r0p1 */
#define __MPU_PRESENT 0 /*!< MPU present or not */
#define __NVIC_PRIO_BITS 2 /*!< Number of bits used for Priority Levels */

View file

@ -226,11 +226,7 @@ void I2S_Handler ( void );
* \brief Configuration of the Cortex-M0+ Processor and Core Peripherals
*/
#if defined(LITTLE_ENDIAN) && (LITTLE_ENDIAN != 1)
#error "Little Endian is already defined, but to different value than expected?!"
#else
#define LITTLE_ENDIAN 1
#endif
#define LITTLE_ENDIAN 1
#define __CM0PLUS_REV 1 /*!< Core revision r0p1 */
#define __MPU_PRESENT 0 /*!< MPU present or not */
#define __NVIC_PRIO_BITS 2 /*!< Number of bits used for Priority Levels */

View file

@ -20,35 +20,6 @@
#ifndef _BOARD_DEFINITIONS_H_
#define _BOARD_DEFINITIONS_H_
#if defined(BOARD_ID_arduino_zero)
#include "board_definitions_arduino_zero.h"
#elif defined(BOARD_ID_genuino_zero)
#include "board_definitions_genuino_zero.h"
#elif defined(BOARD_ID_arduino_mkr1000)
#include "board_definitions_arduino_mkr1000.h"
#elif defined(BOARD_ID_genuino_mkr1000)
#include "board_definitions_genuino_mkr1000.h"
#elif defined(BOARD_ID_arduino_mkrzero)
#include "board_definitions_arduino_mkrzero.h"
#elif defined(BOARD_ID_arduino_mkrfox1200)
#include "board_definitions_arduino_mkrfox1200.h"
#elif defined(BOARD_ID_arduino_mkrgsm1400)
#include "board_definitions_arduino_mkrgsm1400.h"
#elif defined(BOARD_ID_arduino_mkrwan1300)
#include "board_definitions_arduino_mkrwan1300.h"
#elif defined(BOARD_ID_arduino_mkrwifi1010)
#include "board_definitions_arduino_mkrwifi1010.h"
#elif defined(BOARD_ID_arduino_mkrnb1500)
#include "board_definitions_arduino_mkrnb1500.h"
#else
#error You must define a BOARD_ID and add the corresponding definitions in board_definitions.h
#endif
// Common definitions
// ------------------
#define BOOT_PIN_MASK (1U << (BOOT_LOAD_PIN & 0x1f))
/*
* If BOOT_DOUBLE_TAP_ADDRESS is defined the bootloader is started by
* quickly tapping two times on the reset button.

View file

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

View file

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

View file

@ -97,33 +97,8 @@ void loop( void ) ;
#undef abs
#endif // abs
#ifdef __cplusplus
template<class T, class L>
auto min(const T& a, const L& b) -> decltype((b < a) ? b : a)
{
return (b < a) ? b : a;
}
template<class T, class L>
auto max(const T& a, const L& b) -> decltype((b < a) ? b : a)
{
return (a < b) ? b : a;
}
#else
#ifndef min
#define min(a,b) \
({ __typeof__ (a) _a = (a); \
__typeof__ (b) _b = (b); \
_a < _b ? _a : _b; })
#endif
#ifndef max
#define max(a,b) \
({ __typeof__ (a) _a = (a); \
__typeof__ (b) _b = (b); \
_a > _b ? _a : _b; })
#endif
#endif
#define min(a,b) ((a)<(b)?(a):(b))
#define max(a,b) ((a)>(b)?(a):(b))
#define abs(x) ((x)>0?(x):-(x))
#define constrain(amt,low,high) ((amt)<(low)?(low):((amt)>(high)?(high):(amt)))
#define round(x) ((x)>=0?(long)((x)+0.5):(long)((x)-0.5))
@ -149,14 +124,10 @@ void loop( void ) ;
#define digitalPinToInterrupt(P) ( P )
#endif
// USB
#ifdef USE_TINYUSB
#include "Adafruit_TinyUSB_Core.h"
#else
// USB Device
#include "USB/USBDesc.h"
#include "USB/USBCore.h"
#include "USB/USBAPI.h"
#include "USB/USB_host.h"
#endif
#endif // Arduino_h

View file

@ -68,7 +68,7 @@ class HardwareSerial : public Stream
{
public:
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 int available(void) = 0;
virtual int peek(void) = 0;

View file

@ -186,16 +186,6 @@ size_t Print::println(const Printable& x)
return n;
}
void Print::printf(const char format[], ...)
{
char buf[PRINTF_BUF];
va_list ap;
va_start(ap, format);
vsnprintf(buf, sizeof(buf), format, ap);
write(buf);
va_end(ap);
}
// Private Methods /////////////////////////////////////////////////////////////
size_t Print::printNumber(unsigned long n, uint8_t base)
@ -248,14 +238,14 @@ size_t Print::printFloat(double number, uint8_t digits)
// Print the decimal point, but only if there are digits beyond
if (digits > 0) {
n += print(".");
n += print('.');
}
// Extract digits from the remainder one at a time
while (digits-- > 0)
{
remainder *= 10.0;
unsigned int toPrint = (unsigned int)remainder;
unsigned int toPrint = (unsigned int)(remainder);
n += print(toPrint);
remainder -= toPrint;
}

View file

@ -21,8 +21,6 @@
#include <inttypes.h>
#include <stdio.h> // for size_t
#include <stdarg.h> // for printf
#define PRINTF_BUF 80
#include "WString.h"
#include "Printable.h"
@ -30,6 +28,9 @@
#define DEC 10
#define HEX 16
#define OCT 8
#ifdef BIN // Prevent warnings if BIN is previously defined in "iotnx4.h" or similar
#undef BIN
#endif
#define BIN 2
class Print
@ -84,8 +85,6 @@ class Print
size_t println(double, int = 2);
size_t println(const Printable&);
size_t println(void);
void printf(const char[], ...);
virtual void flush() { /* Empty implementation for backward compatibility */ }
};

View file

@ -27,10 +27,7 @@
// using a ring buffer (I think), in which head is the index of the location
// to which to write the next incoming character and tail is the index of the
// location from which to read.
#ifndef SERIAL_BUFFER_SIZE
#define SERIAL_BUFFER_SIZE 350
#endif
#define SERIAL_BUFFER_SIZE 164
template <int N>
class RingBufferN

View file

@ -30,29 +30,11 @@
SERCOM::SERCOM(Sercom* s)
{
sercom = s;
#if defined(__SAMD51__)
// A briefly-available but now deprecated feature had the SPI clock source
// set via a compile-time setting (MAX_SPI)...problem was this affected
// ALL SERCOMs, whereas some (anything read/write, e.g. SD cards) should
// not exceed the standard 24 MHz setting. Newer code, if it needs faster
// write-only SPI (e.g. to screen), should override the SERCOM clock on a
// per-peripheral basis. Nonetheless, we check SERCOM_SPI_FREQ_REF here
// (MAX_SPI * 2) to retain compatibility with any interim projects that
// might have relied on the compile-time setting. But please, don't.
#if SERCOM_SPI_FREQ_REF == F_CPU // F_CPU clock = GCLK0
clockSource = SERCOM_CLOCK_SOURCE_FCPU;
#elif SERCOM_SPI_FREQ_REF == 48000000 // 48 MHz clock = GCLK1 (standard)
clockSource = SERCOM_CLOCK_SOURCE_48M;
#elif SERCOM_SPI_FREQ_REF == 100000000 // 100 MHz clock = GCLK2
clockSource = SERCOM_CLOCK_SOURCE_100M;
#endif
#endif // end __SAMD51__
}
/* =========================
* ===== Sercom UART
* =========================
/* =========================
* ===== Sercom UART
* =========================
*/
void SERCOM::initUART(SercomUartMode mode, SercomUartSampleRate sampleRate, uint32_t baudrate)
{
@ -60,12 +42,12 @@ void SERCOM::initUART(SercomUartMode mode, SercomUartSampleRate sampleRate, uint
resetUART();
//Setting the CTRLA register
sercom->USART.CTRLA.reg = SERCOM_USART_CTRLA_MODE(mode) |
SERCOM_USART_CTRLA_SAMPR(sampleRate);
sercom->USART.CTRLA.reg = SERCOM_USART_CTRLA_MODE(mode) |
SERCOM_USART_CTRLA_SAMPR(sampleRate);
//Setting the Interrupt register
sercom->USART.INTENSET.reg = SERCOM_USART_INTENSET_RXC | //Received complete
SERCOM_USART_INTENSET_ERROR; //All others errors
sercom->USART.INTENSET.reg = SERCOM_USART_INTENSET_RXC | //Received complete
SERCOM_USART_INTENSET_ERROR; //All others errors
if ( mode == UART_INT_CLOCK )
{
@ -93,22 +75,20 @@ void SERCOM::initUART(SercomUartMode mode, SercomUartSampleRate sampleRate, uint
void SERCOM::initFrame(SercomUartCharSize charSize, SercomDataOrder dataOrder, SercomParityMode parityMode, SercomNumberStopBit nbStopBits)
{
//Setting the CTRLA register
sercom->USART.CTRLA.reg |=
SERCOM_USART_CTRLA_FORM((parityMode == SERCOM_NO_PARITY ? 0 : 1) ) |
dataOrder << SERCOM_USART_CTRLA_DORD_Pos;
sercom->USART.CTRLA.reg |= SERCOM_USART_CTRLA_FORM( (parityMode == SERCOM_NO_PARITY ? 0 : 1) ) |
dataOrder << SERCOM_USART_CTRLA_DORD_Pos;
//Setting the CTRLB register
sercom->USART.CTRLB.reg |= SERCOM_USART_CTRLB_CHSIZE(charSize) |
nbStopBits << SERCOM_USART_CTRLB_SBMODE_Pos |
(parityMode == SERCOM_NO_PARITY ? 0 : parityMode) <<
SERCOM_USART_CTRLB_PMODE_Pos; //If no parity use default value
sercom->USART.CTRLB.reg |= SERCOM_USART_CTRLB_CHSIZE(charSize) |
nbStopBits << SERCOM_USART_CTRLB_SBMODE_Pos |
(parityMode == SERCOM_NO_PARITY ? 0 : parityMode) << SERCOM_USART_CTRLB_PMODE_Pos; //If no parity use default value
}
void SERCOM::initPads(SercomUartTXPad txPad, SercomRXPad rxPad)
{
//Setting the CTRLA register
sercom->USART.CTRLA.reg |= SERCOM_USART_CTRLA_TXPO(txPad) |
SERCOM_USART_CTRLA_RXPO(rxPad);
sercom->USART.CTRLA.reg |= SERCOM_USART_CTRLA_TXPO(txPad) |
SERCOM_USART_CTRLA_RXPO(rxPad);
// Enable Transceiver and Receiver
sercom->USART.CTRLB.reg |= SERCOM_USART_CTRLB_TXEN | SERCOM_USART_CTRLB_RXEN ;
@ -221,9 +201,9 @@ void SERCOM::disableDataRegisterEmptyInterruptUART()
sercom->USART.INTENCLR.reg = SERCOM_USART_INTENCLR_DRE;
}
/* =========================
* ===== Sercom SPI
* =========================
/* =========================
* ===== Sercom SPI
* =========================
*/
void SERCOM::initSPI(SercomSpiTXPad mosi, SercomRXPad miso, SercomSpiCharSize charSize, SercomDataOrder dataOrder)
{
@ -231,13 +211,13 @@ void SERCOM::initSPI(SercomSpiTXPad mosi, SercomRXPad miso, SercomSpiCharSize ch
initClockNVIC();
#if defined(__SAMD51__)
sercom->SPI.CTRLA.reg = SERCOM_SPI_CTRLA_MODE(0x3) | // master mode
SERCOM_SPI_CTRLA_DOPO(mosi) |
SERCOM_SPI_CTRLA_DIPO(miso) |
dataOrder << SERCOM_SPI_CTRLA_DORD_Pos;
sercom->SPI.CTRLA.reg = SERCOM_SPI_CTRLA_MODE(0x3) | //master mode
SERCOM_SPI_CTRLA_DOPO(mosi) |
SERCOM_SPI_CTRLA_DIPO(miso) |
dataOrder << SERCOM_SPI_CTRLA_DORD_Pos;
#else
//Setting the CTRLA register
sercom->SPI.CTRLA.reg = SERCOM_SPI_CTRLA_MODE_SPI_MASTER |
sercom->SPI.CTRLA.reg = SERCOM_SPI_CTRLA_MODE_SPI_MASTER |
SERCOM_SPI_CTRLA_DOPO(mosi) |
SERCOM_SPI_CTRLA_DIPO(miso) |
dataOrder << SERCOM_SPI_CTRLA_DORD_Pos;
@ -245,9 +225,10 @@ void SERCOM::initSPI(SercomSpiTXPad mosi, SercomRXPad miso, SercomSpiCharSize ch
//Setting the CTRLB register
sercom->SPI.CTRLB.reg = SERCOM_SPI_CTRLB_CHSIZE(charSize) |
SERCOM_SPI_CTRLB_RXEN; //Active the SPI receiver.
SERCOM_SPI_CTRLB_RXEN; //Active the SPI receiver.
while( sercom->SPI.SYNCBUSY.bit.CTRLB == 1 );
}
void SERCOM::initSPIClock(SercomSpiClockMode clockMode, uint32_t baudrate)
@ -266,8 +247,8 @@ void SERCOM::initSPIClock(SercomSpiClockMode clockMode, uint32_t baudrate)
cpol = 1;
//Setting the CTRLA register
sercom->SPI.CTRLA.reg |= ( cpha << SERCOM_SPI_CTRLA_CPHA_Pos ) |
( cpol << SERCOM_SPI_CTRLA_CPOL_Pos );
sercom->SPI.CTRLA.reg |= ( cpha << SERCOM_SPI_CTRLA_CPHA_Pos ) |
( cpol << SERCOM_SPI_CTRLA_CPOL_Pos );
//Synchronous arithmetic
sercom->SPI.BAUD.reg = calculateBaudrateSynchronous(baudrate);
@ -321,13 +302,14 @@ SercomDataOrder SERCOM::getDataOrderSPI()
void SERCOM::setBaudrateSPI(uint8_t divider)
{
disableSPI(); // Register is enable-protected
//Can't divide by 0
if(divider == 0)
return;
#if defined(__SAMD51__)
sercom->SPI.BAUD.reg = calculateBaudrateSynchronous(freqRef / divider);
#else
sercom->SPI.BAUD.reg = calculateBaudrateSynchronous(SERCOM_SPI_FREQ_REF / divider);
#endif
//Register enable-protected
disableSPI();
sercom->SPI.BAUD.reg = calculateBaudrateSynchronous( SERCOM_FREQ_REF / divider );
enableSPI();
}
@ -358,7 +340,10 @@ uint8_t SERCOM::transferDataSPI(uint8_t data)
{
sercom->SPI.DATA.bit.DATA = data; // Writing data into Data register
while(sercom->SPI.INTFLAG.bit.RXC == 0); // Waiting Complete Reception
while( sercom->SPI.INTFLAG.bit.RXC == 0 )
{
// Waiting Complete Reception
}
return sercom->SPI.DATA.bit.DATA; // Reading data
}
@ -376,30 +361,25 @@ bool SERCOM::isDataRegisterEmptySPI()
//bool SERCOM::isTransmitCompleteSPI()
//{
// //TXC : Transmit complete
// return sercom->SPI.INTFLAG.bit.TXC;
// //TXC : Transmit complete
// return sercom->SPI.INTFLAG.bit.TXC;
//}
//
//bool SERCOM::isReceiveCompleteSPI()
//{
// //RXC : Receive complete
// return sercom->SPI.INTFLAG.bit.RXC;
// //RXC : Receive complete
// return sercom->SPI.INTFLAG.bit.RXC;
//}
uint8_t SERCOM::calculateBaudrateSynchronous(uint32_t baudrate) {
#if defined(__SAMD51__)
uint16_t b = freqRef / (2 * baudrate);
#else
uint16_t b = SERCOM_SPI_FREQ_REF / (2 * baudrate);
#endif
if(b > 0) b--; // Don't -1 on baud calc if already at 0
return b;
uint8_t SERCOM::calculateBaudrateSynchronous(uint32_t baudrate)
{
return SERCOM_FREQ_REF / (2 * baudrate) - 1;
}
/* =========================
* ===== Sercom WIRE
* =========================
/* =========================
* ===== Sercom WIRE
* =========================
*/
void SERCOM::resetWIRE()
{
@ -537,18 +517,8 @@ bool SERCOM::startTransmissionWIRE(uint8_t address, SercomWireReadWriteFlag flag
// 7-bits address + 1-bits R/W
address = (address << 0x1ul) | flag;
// If another master owns the bus or the last bus owner has not properly
// sent a stop, return failure early. This will prevent some misbehaved
// devices from deadlocking here at the cost of the caller being responsible
// for retrying the failed transmission. See SercomWireBusState for the
// possible bus states.
if(!isBusOwnerWIRE())
{
if( isBusBusyWIRE() || (isArbLostWIRE() && !isBusIdleWIRE()) || isBusUnknownWIRE() )
{
return false;
}
}
// Wait idle or owner bus mode
while ( !isBusIdleWIRE() && !isBusOwnerWIRE() );
// Send start and address
sercom->I2CM.ADDR.bit.ADDR = address;
@ -644,21 +614,6 @@ bool SERCOM::isBusOwnerWIRE( void )
return sercom->I2CM.STATUS.bit.BUSSTATE == WIRE_OWNER_STATE;
}
bool SERCOM::isBusUnknownWIRE( void )
{
return sercom->I2CM.STATUS.bit.BUSSTATE == WIRE_UNKNOWN_STATE;
}
bool SERCOM::isArbLostWIRE( void )
{
return sercom->I2CM.STATUS.bit.ARBLOST == 1;
}
bool SERCOM::isBusBusyWIRE( void )
{
return sercom->I2CM.STATUS.bit.BUSSTATE == WIRE_BUSY_STATE;
}
bool SERCOM::isDataReadyWIRE( void )
{
return sercom->I2CS.INTFLAG.bit.DRDY;
@ -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 )
{
int8_t idx = getSercomIndex();
if(idx < 0) return; // We got a problem here
#if defined(__SAMD51__)
uint32_t clk_core;
uint32_t clk_slow;
if(sercom == SERCOM0)
{
clk_core = SERCOM0_GCLK_ID_CORE;
clk_slow = SERCOM0_GCLK_ID_SLOW;
for(uint8_t i=0; i<4; i++) {
NVIC_ClearPendingIRQ(sercomData[idx].irq[i]);
NVIC_SetPriority(sercomData[idx].irq[i], SERCOM_NVIC_PRIORITY);
NVIC_EnableIRQ(sercomData[idx].irq[i]);
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;
NVIC_ClearPendingIRQ(SERCOM1_0_IRQn);
NVIC_ClearPendingIRQ(SERCOM1_1_IRQn);
NVIC_ClearPendingIRQ(SERCOM1_2_IRQn);
NVIC_ClearPendingIRQ(SERCOM1_3_IRQn);
NVIC_SetPriority (SERCOM1_0_IRQn, (1<<__NVIC_PRIO_BITS) - 1); /* set Priority */
NVIC_SetPriority (SERCOM1_1_IRQn, (1<<__NVIC_PRIO_BITS) - 1);
NVIC_SetPriority (SERCOM1_2_IRQn, (1<<__NVIC_PRIO_BITS) - 1);
NVIC_SetPriority (SERCOM1_3_IRQn, (1<<__NVIC_PRIO_BITS) - 1);
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;
NVIC_ClearPendingIRQ(SERCOM2_0_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
// SPI DMA speed is dictated by the "slow clock" (I think...maybe) so
// BOTH are set to the same clock source (clk_slow isn't sourced from
// XOSC32K as in prior versions of SAMD core).
// This might have power implications for sleep code.
if ( IdNvic == PendSV_IRQn )
{
// We got a problem here
return ;
}
#endif
setClockSource(idx, clockSource, true); // true = core clock
setClockSource(idx, clockSource, false); // false = slow clock
#else // end if SAMD51 (prob SAMD21)
uint8_t clockId = sercomData[idx].clock;
IRQn_Type IdNvic = sercomData[idx].irqn;
// Setting NVIC
#if defined(__SAMD51__)
GCLK->PCHCTRL[clk_core].reg = GCLK_PCHCTRL_GEN_GCLK1_Val | (1 << GCLK_PCHCTRL_CHEN_Pos);
GCLK->PCHCTRL[clk_slow].reg = GCLK_PCHCTRL_GEN_GCLK3_Val | (1 << GCLK_PCHCTRL_CHEN_Pos);
#else
// Setting NVIC
NVIC_ClearPendingIRQ(IdNvic);
NVIC_SetPriority(IdNvic, SERCOM_NVIC_PRIORITY);
NVIC_SetPriority (IdNvic, (1<<__NVIC_PRIO_BITS) - 1); /* set Priority */
NVIC_EnableIRQ(IdNvic);
// Setting clock
GCLK->CLKCTRL.reg =
GCLK_CLKCTRL_ID( clockId ) | // Generic Clock 0 (SERCOMx)
GCLK_CLKCTRL_GEN_GCLK0 | // Generic Clock Generator 0 is source
GCLK_CLKCTRL_CLKEN;
//Setting clock
GCLK->CLKCTRL.reg = GCLK_CLKCTRL_ID( clockId ) | // Generic Clock 0 (SERCOMx)
GCLK_CLKCTRL_GEN_GCLK0 | // Generic Clock Generator 0 is source
GCLK_CLKCTRL_CLKEN ;
while(GCLK->STATUS.reg & GCLK_STATUS_SYNCBUSY); // Wait for synchronization
#endif // end !SAMD51
while ( GCLK->STATUS.reg & GCLK_STATUS_SYNCBUSY )
{
/* Wait for synchronization */
}
#endif
}

View file

@ -21,19 +21,8 @@
#include "sam.h"
// SAMD51 has configurable MAX_SPI, else use peripheral clock default.
// Update: changing MAX_SPI via compiler flags is DEPRECATED, because
// this affects ALL SPI peripherals including some that should NOT be
// changed (e.g. anything using SD card). Instead, use setClockSource().
// This is left here for compatibility w/interim MAX_SPI-dependent code:
#if defined(MAX_SPI)
#define SERCOM_SPI_FREQ_REF (MAX_SPI * 2)
#else
#define SERCOM_SPI_FREQ_REF 48000000ul
#endif
// Other SERCOM peripherals always use the 48 MHz clock
#define SERCOM_FREQ_REF 48000000ul
#define SERCOM_NVIC_PRIORITY ((1<<__NVIC_PRIO_BITS) - 1)
#define SERCOM_FREQ_REF 48000000ul
#define SERCOM_NVIC_PRIORITY ((1<<__NVIC_PRIO_BITS) - 1)
typedef enum
{
@ -91,23 +80,23 @@ typedef enum
typedef enum
{
UART_TX_PAD_0 = 0x0ul, // Only for UART
UART_TX_PAD_0 = 0x0ul, // Only for UART
UART_TX_PAD_2 = 0x1ul, // Only for UART
UART_TX_RTS_CTS_PAD_0_2_3 = 0x2ul, // Only for UART with TX on PAD0, RTS on PAD2 and CTS on PAD3
} SercomUartTXPad;
typedef enum
{
SAMPLE_RATE_x16 = 0x1, // Fractional
SAMPLE_RATE_x8 = 0x3, // Fractional
SAMPLE_RATE_x16 = 0x1, //Fractional
SAMPLE_RATE_x8 = 0x3, //Fractional
} SercomUartSampleRate;
typedef enum
{
SERCOM_SPI_MODE_0 = 0, // CPOL : 0 | CPHA : 0
SERCOM_SPI_MODE_1, // CPOL : 0 | CPHA : 1
SERCOM_SPI_MODE_2, // CPOL : 1 | CPHA : 0
SERCOM_SPI_MODE_3 // CPOL : 1 | CPHA : 1
SERCOM_SPI_MODE_0 = 0, // CPOL : 0 | CPHA : 0
SERCOM_SPI_MODE_1, // CPOL : 0 | CPHA : 1
SERCOM_SPI_MODE_2, // CPOL : 1 | CPHA : 0
SERCOM_SPI_MODE_3 // CPOL : 1 | CPHA : 1
} SercomSpiClockMode;
typedef enum
@ -152,19 +141,6 @@ typedef enum
WIRE_MASTER_NACK_ACTION
} SercomMasterAckActionWire;
// SERCOM clock source override is available only on SAMD51 (not 21)
// but the enumeration is made regardless so user code doesn't need
// ifdefs or lengthy comments explaining the different situations --
// the clock-sourcing functions just compile to nothing on SAMD21.
typedef enum {
SERCOM_CLOCK_SOURCE_FCPU, // F_CPU clock (GCLK0)
SERCOM_CLOCK_SOURCE_48M, // 48 MHz peripheral clock (GCLK1) (standard)
SERCOM_CLOCK_SOURCE_100M, // 100 MHz peripheral clock (GCLK2)
SERCOM_CLOCK_SOURCE_32K, // XOSC32K clock (GCLK3)
SERCOM_CLOCK_SOURCE_12M, // 12 MHz peripheral clock (GCLK4)
SERCOM_CLOCK_SOURCE_NO_CHANGE // Leave clock source setting unchanged
} SercomClockSource;
class SERCOM
{
public:
@ -195,6 +171,7 @@ class SERCOM
/* ========== SPI ========== */
void initSPI(SercomSpiTXPad mosi, SercomRXPad miso, SercomSpiCharSize charSize, SercomDataOrder dataOrder) ;
void initSPIClock(SercomSpiClockMode clockMode, uint32_t baudrate) ;
void resetSPI( void ) ;
void enableSPI( void ) ;
void disableSPI( void ) ;
@ -225,9 +202,6 @@ class SERCOM
bool isSlaveWIRE( void ) ;
bool isBusIdleWIRE( void ) ;
bool isBusOwnerWIRE( void ) ;
bool isBusUnknownWIRE( void ) ;
bool isArbLostWIRE( void );
bool isBusBusyWIRE( void );
bool isDataReadyWIRE( void ) ;
bool isStopDetectedWIRE( void ) ;
bool isRestartDetectedWIRE( void ) ;
@ -236,30 +210,10 @@ class SERCOM
bool isRXNackReceivedWIRE( void ) ;
int availableWIRE( void ) ;
uint8_t readDataWIRE( void ) ;
int8_t getSercomIndex(void);
#if defined(__SAMD51__)
// SERCOM clock source override is only available on
// SAMD51 (not 21) ... but these functions are declared
// regardless so user code doesn't need ifdefs or lengthy
// comments explaining the different situations -- these
// just compile to nothing on SAMD21.
void setClockSource(int8_t idx, SercomClockSource src, bool core);
SercomClockSource getClockSource(void) { return clockSource; };
uint32_t getFreqRef(void) { return freqRef; };
#else
// The equivalent SAMD21 dummy functions...
void setClockSource(int8_t idx, SercomClockSource src, bool core) { (void)idx; (void)src; (void)core; };
SercomClockSource getClockSource(void) { return SERCOM_CLOCK_SOURCE_FCPU; };
uint32_t getFreqRef(void) { return F_CPU; };
#endif
private:
Sercom* sercom;
#if defined(__SAMD51__)
SercomClockSource clockSource;
uint32_t freqRef; // Frequency corresponding to clockSource
#endif
uint8_t calculateBaudrateSynchronous(uint32_t baudrate);
uint8_t calculateBaudrateSynchronous(uint32_t baudrate) ;
uint32_t division(uint32_t dividend, uint32_t divisor) ;
void initClockNVIC( void ) ;
};

View file

@ -35,7 +35,6 @@ int Stream::timedRead()
do {
c = read();
if (c >= 0) return c;
yield(); // running TinyUSB task
} while(millis() - _startMillis < _timeout);
return -1; // -1 indicates timeout
}
@ -48,7 +47,6 @@ int Stream::timedPeek()
do {
c = peek();
if (c >= 0) return c;
yield(); // running TinyUSB task
} while(millis() - _startMillis < _timeout);
return -1; // -1 indicates timeout
}

@ -1 +0,0 @@
Subproject commit e7b892095f2bb5d8bef6a748238369bdd268ed5e

View file

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

View file

@ -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_ */

View file

@ -20,6 +20,12 @@
#include "Tone.h"
#include "variant.h"
#if defined(__SAMD51__)
#define WAIT_TC16_REGS_SYNC(x) while(x->COUNT16.SYNCBUSY.bit.ENABLE);
#else
#define WAIT_TC16_REGS_SYNC(x) while(x->COUNT16.STATUS.bit.SYNCBUSY);
#endif
uint32_t toneMaxFrequency = F_CPU / 2;
uint32_t lastOutputPin = 0xFFFFFFFF;
@ -31,24 +37,22 @@ volatile bool toneIsActive = false;
volatile bool firstTimeRunning = false;
#if defined(__SAMD51__)
#define TONE_TC TC0
#define TONE_TC_IRQn TC0_IRQn
#define TONE_TC_GCLK_ID TC0_GCLK_ID
#define Tone_Handler TC0_Handler
#define WAIT_TC16_REGS_SYNC(x) while(x->COUNT16.SYNCBUSY.bit.ENABLE);
#define TONE_TC TC2
#define TONE_TC_IRQn TC2_IRQn
#define TONE_TC_GCLK_ID TC2_GCLK_ID
#else
#define TONE_TC TC5
#define TONE_TC_IRQn TC5_IRQn
#define Tone_Handler TC5_Handler
#define WAIT_TC16_REGS_SYNC(x) while(x->COUNT16.STATUS.bit.SYNCBUSY);
#define TONE_TC TC5
#define TONE_TC_IRQn TC5_IRQn
#endif
#define TONE_TC_TOP 0xFFFF
#define TONE_TC_CHANNEL 0
#if defined(__SAMD51__)
void TC2_Handler (void) __attribute__ ((weak, alias("Tone_Handler")));
#else
void TC5_Handler (void) __attribute__ ((weak, alias("Tone_Handler")));
#endif
static inline void resetTC (Tc* TCx)
{
// Disable TCx
@ -68,14 +72,6 @@ void toneAccurateClock (uint32_t accurateSystemCoreClockFrequency)
void tone (uint32_t outputPin, uint32_t frequency, uint32_t duration)
{
// Avoid divide by zero error by calling 'noTone' instead
if (frequency == 0)
{
noTone(outputPin);
return;
}
// Configure interrupt request
NVIC_DisableIRQ(TONE_TC_IRQn);
NVIC_ClearPendingIRQ(TONE_TC_IRQn);
@ -84,16 +80,19 @@ void tone (uint32_t outputPin, uint32_t frequency, uint32_t duration)
{
firstTimeRunning = true;
NVIC_SetPriority(TONE_TC_IRQn, 5);
NVIC_SetPriority(TONE_TC_IRQn, 0);
#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);
#else
// Enable GCLK for TC4 and TC5 (timer counter input clock)
GCLK->CLKCTRL.reg = (uint16_t) (GCLK_CLKCTRL_CLKEN | GCLK_CLKCTRL_GEN_GCLK0 | GCLK_CLKCTRL_ID(GCM_TC4_TC5));
while (GCLK->STATUS.bit.SYNCBUSY);
#endif
}
//if it's a rest, set to 1Hz (below audio range)
frequency = (frequency > 0 ? frequency : 1);
if (toneIsActive && (outputPin != lastOutputPin))
noTone(lastOutputPin);
@ -137,7 +136,7 @@ void tone (uint32_t outputPin, uint32_t frequency, uint32_t duration)
default: break;
}
toggleCount = (duration > 0 ? frequency * duration * 2 / 1000UL : -1LL);
toggleCount = (duration > 0 ? frequency * duration * 2 / 1000UL : -1);
resetTC(TONE_TC);
@ -180,19 +179,9 @@ void tone (uint32_t outputPin, uint32_t frequency, uint32_t duration)
void noTone (uint32_t outputPin)
{
/* 'tone' need to run at least once in order to enable GCLK for
* the timers used for the tone-functionality. If 'noTone' is called
* without ever calling 'tone' before then 'WAIT_TC16_REGS_SYNC(TCx)'
* will wait infinitely. The variable 'firstTimeRunning' is set the
* 1st time 'tone' is set so it can be used to detect wether or not
* 'tone' has been called before.
*/
if(firstTimeRunning)
{
resetTC(TONE_TC);
digitalWrite(outputPin, LOW);
toneIsActive = false;
}
resetTC(TONE_TC);
digitalWrite(outputPin, LOW);
toneIsActive = false;
}
#ifdef __cplusplus

View file

@ -16,8 +16,6 @@
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef USE_TINYUSB
#include <Arduino.h>
#include <Reset.h> // Needed for auto-reset with 1200bps port touch
@ -152,7 +150,6 @@ void Serial_::begin(uint32_t /* baud_count */, uint8_t /* config */)
void Serial_::end(void)
{
memset((void*)&_usbLineInfo, 0, sizeof(_usbLineInfo));
}
int Serial_::available(void)
@ -262,5 +259,3 @@ Serial_::operator bool()
Serial_ Serial(USBDevice);
#endif
#endif // USE_TINYUSB

View file

@ -17,8 +17,6 @@
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef USE_TINYUSB
#include "USBAPI.h"
#include "USBDesc.h"
#include "USBCore.h"
@ -115,6 +113,4 @@ PluggableUSB_::PluggableUSB_() : lastIf(CDC_ACM_INTERFACE + CDC_INTERFACE_COUNT)
}
#endif
#endif
#endif // USE_TINYUSB
#endif

View file

@ -5,7 +5,6 @@
* Author: deanm
*/
#ifndef USE_TINYUSB
#include "SAMD21_USBDevice.h"
@ -37,5 +36,3 @@ void USBDevice_SAMD21G18x::calibrate() {
usb.PADCAL.bit.TRANSP = pad_transp;
usb.PADCAL.bit.TRIM = pad_trim;
}
#endif // USE_TINYUSB

View file

@ -237,7 +237,7 @@ public:
release();
}
virtual ~DoubleBufferedEPOutHandler() {
~DoubleBufferedEPOutHandler() {
free((void*)data0);
free((void*)data1);
}

View file

@ -24,174 +24,7 @@
#include <stdio.h>
#include <stdint.h>
typedef uint8_t ep_t;
class USBDevice_SAMR21G18x {
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;
}
#include "SAMD21_USBDevice.h"
typedef class USBDevice_SAMD21G18x USBDevice_SAMR21G18x;

View file

@ -65,7 +65,6 @@ public:
// USB Device API
void init();
bool end();
bool attach();
bool detach();
void setAddress(uint32_t addr);

View file

@ -16,7 +16,7 @@
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef USE_TINYUSB
#if defined(USBCON)
#include <Arduino.h>
@ -244,25 +244,26 @@ bool USBDeviceClass::sendDescriptor(USBSetup &setup)
}
else if (setup.wValueL == ISERIAL) {
#ifdef PLUGGABLE_USB_ENABLED
#ifdef __SAMD51__
#define SERIAL_NUMBER_WORD_0 *(volatile uint32_t*)(0x008061FC)
#define SERIAL_NUMBER_WORD_1 *(volatile uint32_t*)(0x00806010)
#define SERIAL_NUMBER_WORD_2 *(volatile uint32_t*)(0x00806014)
#define SERIAL_NUMBER_WORD_3 *(volatile uint32_t*)(0x00806018)
#else // samd21
#if defined(__SAMD51__)
char name[ISERIAL_MAX_LEN];
PluggableUSB().getShortName(name);
return sendStringDescriptor((uint8_t*)name, setup.wLength);
#else
// from section 9.3.3 of the datasheet
#define SERIAL_NUMBER_WORD_0 *(volatile uint32_t*)(0x0080A00C)
#define SERIAL_NUMBER_WORD_1 *(volatile uint32_t*)(0x0080A040)
#define SERIAL_NUMBER_WORD_2 *(volatile uint32_t*)(0x0080A044)
#define SERIAL_NUMBER_WORD_3 *(volatile uint32_t*)(0x0080A048)
#endif
char name[ISERIAL_MAX_LEN];
utox8(SERIAL_NUMBER_WORD_0, &name[0]);
utox8(SERIAL_NUMBER_WORD_1, &name[8]);
utox8(SERIAL_NUMBER_WORD_2, &name[16]);
utox8(SERIAL_NUMBER_WORD_3, &name[24]);
name[32] = '\0';
PluggableUSB().getShortName(&name[32]);
return sendStringDescriptor((uint8_t*)name, setup.wLength);
#endif
#endif
}
else {
@ -433,13 +434,6 @@ bool USBDeviceClass::detach()
return true;
}
bool USBDeviceClass::end() {
if (!initialized)
return false;
usbd.disable();
return true;
}
bool USBDeviceClass::configured()
{
return _usbConfiguration != 0;
@ -877,7 +871,6 @@ bool USBDeviceClass::handleStandardSetup(USBSetup &setup)
sendZlp(0);
return true;
}
return false;
case SET_ADDRESS:
setAddress(setup.wValueL);
@ -1039,4 +1032,3 @@ void USBDeviceClass::ISRHandler()
USBDeviceClass USBDevice;
#endif
#endif // USE_TINYUSB

View file

@ -101,7 +101,7 @@
// bMaxPower in Configuration Descriptor
#define USB_CONFIG_POWER_MA(mA) ((mA)/2)
#ifndef USB_CONFIG_POWER
#define USB_CONFIG_POWER (100)
#define USB_CONFIG_POWER (500)
#endif
#define CDC_V1_10 0x0110

View file

@ -17,7 +17,6 @@
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef USE_TINYUSB
#include <stdio.h>
#include <stdint.h>
@ -64,6 +63,7 @@ void UHD_Init(void)
uint32_t pad_transn;
uint32_t pad_transp;
uint32_t pad_trim;
uint32_t i;
USB_SetHandler(&UHD_Handler);
@ -172,7 +172,10 @@ void UHD_Init(void)
USB->HOST.DESCADD.reg = (uint32_t)(&usb_pipe_table[0]);
// For USB_SPEED_FULL
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;
@ -554,5 +557,3 @@ uint32_t UHD_Pipe_Is_Transfer_Complete(uint32_t ul_pipe, uint32_t ul_token_type)
// }
#endif // HOST_DEFINED
#endif // USE_TINYUSB

View file

@ -78,129 +78,133 @@ static void __initialize()
*/
void attachInterrupt(uint32_t pin, voidFuncPtr callback, uint32_t mode)
{
static int enabled = 0;
uint32_t config;
uint32_t pos;
static int enabled = 0;
uint32_t config;
uint32_t pos;
#if ARDUINO_SAMD_VARIANT_COMPLIANCE >= 10606
EExt_Interrupts in = g_APinDescription[pin].ulExtInt;
#else
EExt_Interrupts in = digitalPinToInterrupt(pin);
#endif
if (in == NOT_AN_INTERRUPT) return;
#if ARDUINO_SAMD_VARIANT_COMPLIANCE >= 10606
EExt_Interrupts in = g_APinDescription[pin].ulExtInt;
#else
EExt_Interrupts in = digitalPinToInterrupt(pin);
#endif
if (in == NOT_AN_INTERRUPT) return;
if (!enabled) {
__initialize();
enabled = 1;
}
uint32_t inMask = (1UL << in);
// Enable wakeup capability on pin in case being used during sleep
#if defined(__SAMD51__)
//I believe this is done automatically
#else
EIC->WAKEUP.reg |= (1 << in);
#endif
if (!enabled) {
__initialize();
enabled = 1;
}
// Only store when there is really an ISR to call.
// This allow for calling attachInterrupt(pin, NULL, mode), we set up all needed register
// but won't service the interrupt, this way we also don't need to check it inside the ISR.
if (callback)
{
if (in == EXTERNAL_INT_NMI) {
EIC->NMIFLAG.bit.NMI = 1; // Clear flag
switch (mode) {
case LOW:
EIC->NMICTRL.bit.NMISENSE = EIC_NMICTRL_NMISENSE_LOW;
break;
// Only store when there is really an ISR to call.
// This allow for calling attachInterrupt(pin, NULL, mode), we set up all needed register
// but won't service the interrupt, this way we also don't need to check it inside the ISR.
if (callback)
{
// Store interrupts to service in order of when they were attached
// to allow for first come first serve handler
uint32_t current = 0;
uint32_t inMask = (1UL << in);
case HIGH:
EIC->NMICTRL.bit.NMISENSE = EIC_NMICTRL_NMISENSE_HIGH;
break;
// 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
}
case CHANGE:
EIC->NMICTRL.bit.NMISENSE = EIC_NMICTRL_NMISENSE_BOTH;
break;
if (in == EXTERNAL_INT_NMI) {
EIC->NMIFLAG.bit.NMI = 1; // Clear flag
switch (mode) {
case LOW:
EIC->NMICTRL.bit.NMISENSE = EIC_NMICTRL_NMISENSE_LOW;
break;
case FALLING:
EIC->NMICTRL.bit.NMISENSE = EIC_NMICTRL_NMISENSE_FALL;
break;
case HIGH:
EIC->NMICTRL.bit.NMISENSE = EIC_NMICTRL_NMISENSE_HIGH;
break;
case RISING:
EIC->NMICTRL.bit.NMISENSE = EIC_NMICTRL_NMISENSE_RISE;
break;
}
case CHANGE:
EIC->NMICTRL.bit.NMISENSE = EIC_NMICTRL_NMISENSE_BOTH;
break;
// Assign callback to interrupt
ISRcallback[EXTERNAL_INT_NMI] = callback;
case FALLING:
EIC->NMICTRL.bit.NMISENSE = EIC_NMICTRL_NMISENSE_FALL;
break;
} else { // Not NMI, is external interrupt
case RISING:
EIC->NMICTRL.bit.NMISENSE = EIC_NMICTRL_NMISENSE_RISE;
break;
}
// Assign pin to EIC
pinPeripheral(pin, PIO_EXTINT);
// Assign callback to interrupt
ISRcallback[EXTERNAL_INT_NMI] = callback;
// Store interrupts to service in order of when they were attached
// to allow for first come first serve handler
uint32_t current = 0;
} else { // Not NMI, is external interrupt
// 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
// 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
// Look for right CONFIG register to be addressed
if (in > EXTERNAL_INT_7) {
config = 1;
pos = (in - 8) << 2;
} else {
config = 0;
pos = in << 2;
}
// Assign pin to EIC
pinPeripheral(pin, PIO_EXTINT);
#if defined (__SAMD51__)
EIC->CTRLA.bit.ENABLE = 0;
while (EIC->SYNCBUSY.bit.ENABLE == 1) { }
#endif
// Assign callback to interrupt
ISRcallback[in] = callback;
EIC->CONFIG[config].reg &=~ (EIC_CONFIG_SENSE0_Msk << pos); // Reset sense mode, important when changing trigger mode during runtime
switch (mode)
{
case LOW:
EIC->CONFIG[config].reg |= EIC_CONFIG_SENSE0_LOW_Val << pos;
break;
// Look for right CONFIG register to be addressed
if (in > EXTERNAL_INT_7) {
config = 1;
} else {
config = 0;
}
case HIGH:
EIC->CONFIG[config].reg |= EIC_CONFIG_SENSE0_HIGH_Val << pos;
break;
// Configure the interrupt mode
pos = (in - (8 * config)) << 2;
case CHANGE:
EIC->CONFIG[config].reg |= EIC_CONFIG_SENSE0_BOTH_Val << pos;
break;
#if defined (__SAMD51__)
EIC->CTRLA.bit.ENABLE = 0;
while (EIC->SYNCBUSY.bit.ENABLE == 1) { }
#endif
case FALLING:
EIC->CONFIG[config].reg |= EIC_CONFIG_SENSE0_FALL_Val << pos;
break;
switch (mode)
{
case LOW:
EIC->CONFIG[config].reg |= EIC_CONFIG_SENSE0_LOW_Val << pos;
break;
case RISING:
EIC->CONFIG[config].reg |= EIC_CONFIG_SENSE0_RISE_Val << pos;
break;
}
}
// Enable the interrupt
EIC->INTENSET.reg = EIC_INTENSET_EXTINT(1 << in);
}
case HIGH:
EIC->CONFIG[config].reg |= EIC_CONFIG_SENSE0_HIGH_Val << pos;
break;
#if defined (__SAMD51__)
EIC->CTRLA.bit.ENABLE = 1;
while (EIC->SYNCBUSY.bit.ENABLE == 1) { }
#endif
case CHANGE:
EIC->CONFIG[config].reg |= EIC_CONFIG_SENSE0_BOTH_Val << pos;
break;
case FALLING:
EIC->CONFIG[config].reg |= EIC_CONFIG_SENSE0_FALL_Val << pos;
break;
case RISING:
EIC->CONFIG[config].reg |= EIC_CONFIG_SENSE0_RISE_Val << pos;
break;
}
}
// Enable the interrupt
EIC->INTENSET.reg = EIC_INTENSET_EXTINT(1 << in);
#if defined (__SAMD51__)
EIC->CTRLA.bit.ENABLE = 1;
while (EIC->SYNCBUSY.bit.ENABLE == 1) { }
#endif
}
/*
@ -250,22 +254,17 @@ void detachInterrupt(uint32_t pin)
* External Interrupt Controller NVIC Interrupt Handler
*/
#if defined(__SAMD51__)
void InterruptHandler(uint32_t unused_i)
void InterruptHandler(uint32_t i)
{
(void)unused_i;
// Calling the routine directly from -here- takes about 1us
// Depending on where you are in the list it will take longer
// Loop over all enabled interrupts in the list
for (uint32_t i=0; i<nints; i++)
if ((EIC->INTFLAG.reg & (1 << i)) != 0)
{
if ((EIC->INTFLAG.reg & ISRlist[i]) != 0)
{
// Call the callback function
ISRcallback[i]();
// Clear the interrupt
EIC->INTFLAG.reg = ISRlist[i];
}
// Call the callback function if assigned
if (ISRcallback[i]) {
ISRcallback[i]();
}
// Clear the interrupt
EIC->INTFLAG.reg = 1 << i;
}
}
@ -376,4 +375,4 @@ void NMI_Handler(void)
if (ISRcallback[EXTERNAL_INT_NMI]) ISRcallback[EXTERNAL_INT_NMI]();
EIC->NMIFLAG.bit.NMI = 1; // Clear interrupt
}
#endif
#endif

View file

@ -31,7 +31,7 @@ extern "C" {
#define FALLING 3
#define RISING 4
//#define DEFAULT 1
#define DEFAULT 1
#define EXTERNAL 0
typedef void (*voidFuncPtr)(void);

View file

@ -57,41 +57,10 @@ typedef enum _EAnalogChannel
ADC_Channel19=19,
DAC_Channel0,
DAC_Channel1,
ADC_Channel_Bandgap=0x1B,
ADC_Channel_PTAT=0x1C,
} EAnalogChannel ;
#if defined(__SAMD51__)
#if defined(__SAMD51G19A__)
typedef enum _ETCChannel
{
NOT_ON_TIMER=-1,
TCC0_CH0 = (0<<8)|(0),
TCC0_CH1 = (0<<8)|(1),
TCC0_CH2 = (0<<8)|(2),
TCC0_CH3 = (0<<8)|(3),
TCC0_CH4 = (0<<8)|(4),
TCC0_CH5 = (0<<8)|(5),
TCC1_CH0 = (1<<8)|(0),
TCC1_CH1 = (1<<8)|(1),
TCC1_CH2 = (1<<8)|(2),
TCC1_CH3 = (1<<8)|(3),
TCC2_CH0 = (2<<8)|(0),
TCC2_CH1 = (2<<8)|(1),
TCC2_CH2 = (2<<8)|(2),
TC0_CH0 = (3<<8)|(0),
TC0_CH1 = (3<<8)|(1),
TC1_CH0 = (4<<8)|(0),
TC1_CH1 = (4<<8)|(1),
TC2_CH0 = (5<<8)|(0),
TC2_CH1 = (5<<8)|(1),
TC3_CH0 = (6<<8)|(0),
TC3_CH1 = (6<<8)|(1),
} ETCChannel ;
#elif defined(__SAMD51J19A__) || defined(__SAMD51J20A__)
typedef enum _ETCChannel
{
NOT_ON_TIMER=-1,
@ -107,82 +76,12 @@ typedef enum _ETCChannel
TCC1_CH1 = (1<<8)|(1),
TCC1_CH2 = (1<<8)|(2),
TCC1_CH3 = (1<<8)|(3),
TCC1_CH4 = (1<<8)|(4),
TCC1_CH5 = (1<<8)|(5),
TCC1_CH6 = (1<<8)|(6),
TCC1_CH7 = (1<<8)|(7),
TCC2_CH0 = (2<<8)|(0),
TCC2_CH1 = (2<<8)|(1),
TCC2_CH2 = (2<<8)|(2),
TCC3_CH0 = (3<<8)|(0),
TCC3_CH1 = (3<<8)|(1),
TCC4_CH0 = (4<<8)|(0),
TCC4_CH1 = (4<<8)|(1),
TC0_CH0 = (5<<8)|(0),
TC0_CH1 = (5<<8)|(1),
TC1_CH0 = (6<<8)|(0),
TC1_CH1 = (6<<8)|(1),
TC2_CH0 = (7<<8)|(0),
TC2_CH1 = (7<<8)|(1),
TC3_CH0 = (8<<8)|(0),
TC3_CH1 = (8<<8)|(1),
TC4_CH0 = (9<<8)|(0),
TC4_CH1 = (9<<8)|(1),
TC5_CH0 = (10<<8)|(0),
TC5_CH1 = (10<<8)|(1),
TC6_CH0 = (11<<8)|(0),
TC6_CH1 = (11<<8)|(1),
TC7_CH0 = (12<<8)|(0),
TC7_CH1 = (12<<8)|(1),
TCC1_CH4 = (1<<8)|(0),
TCC1_CH5 = (1<<8)|(1),
TCC1_CH6 = (1<<8)|(2),
TCC1_CH7 = (1<<8)|(3),
} ETCChannel ;
#elif defined(__SAMD51P19A__) || defined(__SAMD51P20A__)
typedef enum _ETCChannel
{
NOT_ON_TIMER=-1,
TCC0_CH0 = (0<<8)|(0),
TCC0_CH1 = (0<<8)|(1),
TCC0_CH2 = (0<<8)|(2),
TCC0_CH3 = (0<<8)|(3),
TCC0_CH4 = (0<<8)|(4),
TCC0_CH5 = (0<<8)|(5),
TCC1_CH0 = (1<<8)|(0),
TCC1_CH1 = (1<<8)|(1),
TCC1_CH2 = (1<<8)|(2),
TCC1_CH3 = (1<<8)|(3),
TCC2_CH0 = (2<<8)|(0),
TCC2_CH1 = (2<<8)|(1),
TCC2_CH2 = (2<<8)|(2),
TCC3_CH0 = (3<<8)|(0),
TCC3_CH1 = (3<<8)|(1),
TCC4_CH0 = (4<<8)|(0),
TCC4_CH1 = (4<<8)|(1),
TC0_CH0 = (5<<8)|(0),
TC0_CH1 = (5<<8)|(1),
TC1_CH0 = (6<<8)|(0),
TC1_CH1 = (6<<8)|(1),
TC2_CH0 = (7<<8)|(0),
TC2_CH1 = (7<<8)|(1),
TC3_CH0 = (8<<8)|(0),
TC3_CH1 = (8<<8)|(1),
TC4_CH0 = (9<<8)|(0),
TC4_CH1 = (9<<8)|(1),
TC5_CH0 = (10<<8)|(0),
TC5_CH1 = (10<<8)|(1),
TC6_CH0 = (11<<8)|(0),
TC6_CH1 = (11<<8)|(1),
TC7_CH0 = (12<<8)|(0),
TC7_CH1 = (12<<8)|(1),
} ETCChannel ;
#endif
typedef ETCChannel EPWMChannel;
extern const uint32_t GCLK_CLKCTRL_IDs[TCC_INST_NUM+TC_INST_NUM];
#define NOT_ON_PWM NOT_ON_TIMER
#else
// Definitions for TC channels
typedef enum _ETCChannel
@ -210,48 +109,7 @@ typedef enum _ETCChannel
TC4_CH1 = (4<<8)|(1),
TC5_CH0 = (5<<8)|(0),
TC5_CH1 = (5<<8)|(1),
#if defined (__SAMD21J18A__)
TC6_CH0 = (6<<8)|(0),
TC6_CH1 = (6<<8)|(1),
TC7_CH0 = (7<<8)|(0),
TC7_CH1 = (7<<8)|(1),
#endif // __SAMD21J18A__
} ETCChannel ;
// Definitions for PWM channels
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,
PWM2_CH0=TCC2_CH0,
PWM2_CH1=TCC2_CH1,
PWM2_CH2=TCC2_CH2,
PWM2_CH3=TCC2_CH3,
PWM3_CH0=TC3_CH0,
PWM3_CH1=TC3_CH1,
PWM4_CH0=TC4_CH0,
PWM4_CH1=TC4_CH1,
PWM5_CH0=TC5_CH0,
PWM5_CH1=TC5_CH1,
#if defined(__SAMD21J18A__)
PWM6_CH0=TC6_CH0,
PWM6_CH1=TC6_CH1,
PWM7_CH0=TC7_CH0,
PWM7_CH1=TC7_CH1,
#endif // __SAMD21J18A__
} EPWMChannel ;
#endif
extern const void* g_apTCInstances[TCC_INST_NUM+TC_INST_NUM] ;
@ -260,13 +118,74 @@ extern const void* g_apTCInstances[TCC_INST_NUM+TC_INST_NUM] ;
#define GetTCChannelNumber( x ) ( (x) & 0xff )
#define GetTC( x ) ( g_apTCInstances[(x) >> 8] )
#if defined(__SAMD51__)
typedef enum _EPWMChannel
{
NOT_ON_PWM=-1,
PWM0_CH0=TCC0_CH0,
PWM0_CH1=TCC0_CH1,
PWM0_CH2=TCC0_CH2,
PWM0_CH3=TCC0_CH3,
PWM0_CH4=TCC0_CH4,
PWM0_CH5=TCC0_CH5,
PWM0_CH6=TCC0_CH6,
PWM0_CH7=TCC0_CH7,
PWM1_CH0=TCC1_CH0,
PWM1_CH1=TCC1_CH1,
PWM1_CH2=TCC1_CH2,
PWM1_CH3=TCC1_CH3,
PWM1_CH4=TCC1_CH4,
PWM1_CH5=TCC1_CH5,
PWM1_CH6=TCC1_CH6,
PWM1_CH7=TCC1_CH7,
} EPWMChannel ;
#else //end __SAMD51J19A__
// Definitions for PWM channels
typedef enum _EPWMChannel
{
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,
PWM2_CH0=TCC2_CH0,
PWM2_CH1=TCC2_CH1,
PWM2_CH2=TCC2_CH2,
PWM2_CH3=TCC2_CH3,
PWM3_CH0=TC3_CH0,
PWM3_CH1=TC3_CH1,
PWM4_CH0=TC4_CH0,
PWM4_CH1=TC4_CH1,
PWM5_CH0=TC5_CH0,
PWM5_CH1=TC5_CH1,
#if defined(__SAMD21J18A__)
PWM6_CH0=TC6_CH0,
PWM6_CH1=TC6_CH1,
PWM7_CH0=TC7_CH0,
PWM7_CH1=TC7_CH1,
#endif // __SAMD21J18A__
} EPWMChannel ;
#endif
typedef enum _EPortType
{
NOT_A_PORT=-1,
PORTA=0,
PORTB=1,
PORTC=2,
PORTD=3,
} EPortType ;
#define PIN_NOT_A_PIN (UINT_MAX)
@ -336,19 +255,10 @@ typedef enum _EPioType
#define PIN_ATTR_COMBO (1UL<<0)
#define PIN_ATTR_ANALOG (1UL<<1)
#define PIN_ATTR_DIGITAL (1UL<<2)
#define PIN_ATTR_PWM (1UL<<3)
#define PIN_ATTR_TIMER (1UL<<4)
#define PIN_ATTR_TIMER_ALT (1UL<<5)
#define PIN_ATTR_EXTINT (1UL<<6)
#define PIN_ATTR_ANALOG_ALT (1UL<<7)
#if defined(__SAMD51__)
// these correspond to the mux table
#define PIN_ATTR_PWM_E (1UL<<3)
#define PIN_ATTR_PWM_F (1UL<<8)
#define PIN_ATTR_PWM_G (1UL<<9)
#else
#define PIN_ATTR_PWM (1UL<<3)
#endif
/* Types used for the table below */
typedef struct _PinDescription

View file

@ -25,14 +25,8 @@
#ifndef _IO_H_
#define _IO_H_
#ifdef __SAMD51__
#define RAMSTART (HSRAM_ADDR)
#define RAMSIZE (HSRAM_SIZE)
#else
#define RAMSTART (HMCRAMC0_ADDR)
#define RAMSIZE (HMCRAMC0_SIZE)
#endif
#define RAMSTART (HMCRAMC0_ADDR)
#define RAMSIZE (HMCRAMC0_SIZE)
#define RAMEND (RAMSTART + RAMSIZE - 1)
#endif

View file

@ -61,51 +61,19 @@ unsigned long micros( void )
// a runtime multiplication and shift, saving a few cycles
}
#ifdef __SAMD51__
/*
* On SAMD51, use the (32bit) cycle count maintained by the DWT unit,
* and count exact number of cycles elapsed, rather than guessing how
* many cycles a loop takes, which is dangerous in the presence of
* cache. The overhead of the call and internal code is "about" 20
* cycles. (at 120MHz, that's about 1/6 us)
*/
void delayMicroseconds(unsigned int us)
{
uint32_t start, elapsed;
uint32_t count;
if (us == 0)
return;
count = us * (VARIANT_MCK / 1000000) - 20; // convert us to cycles.
start = DWT->CYCCNT; //CYCCNT is 32bits, takes 37s or so to wrap.
while (1) {
elapsed = DWT->CYCCNT - start;
if (elapsed >= count)
return;
}
}
#endif
void delay( unsigned long ms )
{
if (ms == 0)
if ( ms == 0 )
{
return;
return ;
}
uint32_t start = micros();
uint32_t start = _ulTickCount ;
while (ms > 0)
do
{
yield();
while (ms > 0 && (micros() - start) >= 1000)
{
ms--;
start += 1000;
}
}
yield() ;
} while ( _ulTickCount - start < ms ) ;
}
#include "Reset.h" // for tickReset()

View file

@ -61,9 +61,6 @@ extern void delay( unsigned long dwMs ) ;
*
* \param dwUs the number of microseconds to pause (uint32_t)
*/
#if defined(__SAMD51__)
extern void delayMicroseconds( unsigned int );
#else
static __inline__ void delayMicroseconds( unsigned int ) __attribute__((always_inline, unused)) ;
static __inline__ void delayMicroseconds( unsigned int usec )
{
@ -71,6 +68,21 @@ static __inline__ void delayMicroseconds( unsigned int usec )
{
return ;
}
#if defined(__SAMD51__)
uint32_t n = usec * (VARIANT_MCK / 1000000) / 12;
__asm__ __volatile__(
"1: \n"
" sub %0, #1 \n" // substract 1 from %0 (n)
" cmp %0, #0 \n" // compare to 0
" bne 1b \n" // if result is not 0 jump to 1
: "+r" (n) // '%0' is n variable with RW constraints
: // no input
: // no clobber
);
#else
/*
* The following loop:
*
@ -97,10 +109,10 @@ static __inline__ void delayMicroseconds( unsigned int usec )
: // no input
: // no clobber
);
#endif
// https://gcc.gnu.org/onlinedocs/gcc/Extended-Asm.html
// https://gcc.gnu.org/onlinedocs/gcc/Extended-Asm.html#Volatile
}
#endif
#ifdef __cplusplus
}

View file

@ -28,7 +28,6 @@
static void __empty() {
// Empty
}
void yield(void) __attribute__ ((weak, alias("__empty")));
/**

View file

@ -39,10 +39,7 @@ int main( void )
initVariant();
delay(1);
#if defined(USE_TINYUSB)
Adafruit_TinyUSB_Core_init();
#elif defined(USBCON)
#if defined(USBCON)
USBDevice.init();
USBDevice.attach();
#endif
@ -52,21 +49,8 @@ int main( void )
for (;;)
{
loop();
yield(); // yield run usb background task
if (serialEventRun) serialEventRun();
}
return 0;
}
#if defined(USE_TINYUSB)
// run TinyUSB background task when yield()
extern "C" void yield(void)
{
tud_task();
tud_cdc_write_flush();
}
#endif

View file

@ -164,19 +164,18 @@ void arm_float_to_q12_20(float *pIn, q31_t * pOut, uint32_t numSamples)
uint32_t arm_compare_fixed_q15(q15_t *pIn, q15_t * pOut, uint32_t numSamples)
{
uint32_t i;
int32_t diff;
uint32_t diffCrnt = 0;
int32_t diff, diffCrnt = 0;
uint32_t maxDiff = 0;
for (i = 0; i < numSamples; i++)
{
diff = pIn[i] - pOut[i];
diffCrnt = (uint32_t)( (diff > 0) ? diff : -diff );
diff = pIn[i] - pOut[i];
diffCrnt = (diff > 0) ? diff : -diff;
if(diffCrnt > maxDiff)
{
maxDiff = diffCrnt;
}
if(diffCrnt > maxDiff)
{
maxDiff = diffCrnt;
}
}
return(maxDiff);
@ -193,19 +192,18 @@ uint32_t arm_compare_fixed_q15(q15_t *pIn, q15_t * pOut, uint32_t numSamples)
uint32_t arm_compare_fixed_q31(q31_t *pIn, q31_t * pOut, uint32_t numSamples)
{
uint32_t i;
int32_t diff;
uint32_t diffCrnt = 0;
int32_t diff, diffCrnt = 0;
uint32_t maxDiff = 0;
for (i = 0; i < numSamples; i++)
{
diff = pIn[i] - pOut[i];
diffCrnt = (uint32_t)( (diff > 0) ? diff : -diff );
diff = pIn[i] - pOut[i];
diffCrnt = (diff > 0) ? diff : -diff;
if(diffCrnt > maxDiff)
{
maxDiff = diffCrnt;
}
if(diffCrnt > maxDiff)
{
maxDiff = diffCrnt;
}
}
return(maxDiff);

View file

@ -34,36 +34,6 @@ uint32_t pulseIn(uint32_t pin, uint32_t state, uint32_t timeout)
uint32_t bit = 1 << p.ulPin;
uint32_t stateMask = state ? bit : 0;
#if defined(__SAMD51__)
/*
* The SAMD51 is fast enough to use really obvious code (similar to
* what was used to produce pulse_asm.S, but using micros() for timing.
* No assembly required, no conversion of loop counts to times (which is
* worrisome in the presence of cache.)
*/
const volatile uint32_t *port = &(PORT->Group[p.ulPort].IN.reg);
uint32_t usCallStart; // microseconds at start of call, for timeout.
uint32_t usPulseStart; // microseconds at start of measured pulse.
usCallStart = usPulseStart = micros();
// wait for any previous pulse to end
while ((*port & bit) == stateMask) {
if (micros() - usCallStart > timeout)
return -1;
}
// wait for the pulse to start
while ((*port & bit) != stateMask) {
usPulseStart = micros();
if (usPulseStart - usCallStart > timeout)
return -2;
}
// wait for the pulse to stop
while ((*port & bit) == stateMask) {
if (micros() - usCallStart > timeout)
return -3;
}
return micros() - usPulseStart;
#else
// convert the timeout from microseconds to a number of times through
// the initial loop; it takes (roughly) 13 clock cycles per iteration.
uint32_t maxloops = microsecondsToClockCycles(timeout) / 13;
@ -78,6 +48,5 @@ uint32_t pulseIn(uint32_t pin, uint32_t state, uint32_t timeout)
return clockCyclesToMicroseconds(width * 13 + 16);
else
return 0;
#endif // SAMD51
}

View file

@ -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;
@ -146,7 +146,7 @@ void SystemInit( void )
/* Wait for synchronization */
}
GCLK->GENCTRL[GENERIC_CLOCK_GENERATOR_1M].reg = GCLK_GENCTRL_SRC(GCLK_GENCTRL_SRC_DFLL_Val) | GCLK_GENCTRL_GENEN | GCLK_GENCTRL_DIV(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 ){
/* Wait for synchronization */
@ -160,8 +160,7 @@ void SystemInit( void )
//PLL0 is 120MHz
GCLK->PCHCTRL[OSCCTRL_GCLK_ID_FDPLL0].reg = (1 << GCLK_PCHCTRL_CHEN_Pos) | GCLK_PCHCTRL_GEN(GCLK_PCHCTRL_GEN_GCLK5_Val);
// This rounds to nearest full-MHz increment; not currently using frac
OSCCTRL->Dpll[0].DPLLRATIO.reg = OSCCTRL_DPLLRATIO_LDRFRAC(0x00) | OSCCTRL_DPLLRATIO_LDR((F_CPU - 500000) / 1000000);
OSCCTRL->Dpll[0].DPLLRATIO.reg = OSCCTRL_DPLLRATIO_LDRFRAC(0x00) | OSCCTRL_DPLLRATIO_LDR(59); //120 Mhz
while(OSCCTRL->Dpll[0].DPLLSYNCBUSY.bit.DPLLRATIO);
@ -175,7 +174,7 @@ void SystemInit( void )
//PLL1 is 100MHz
GCLK->PCHCTRL[OSCCTRL_GCLK_ID_FDPLL1].reg = (1 << GCLK_PCHCTRL_CHEN_Pos) | GCLK_PCHCTRL_GEN(GCLK_PCHCTRL_GEN_GCLK5_Val);
OSCCTRL->Dpll[1].DPLLRATIO.reg = OSCCTRL_DPLLRATIO_LDRFRAC(0x00) | OSCCTRL_DPLLRATIO_LDR(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);
@ -217,7 +216,7 @@ void SystemInit( void )
GCLK->GENCTRL[GENERIC_CLOCK_GENERATOR_12M].reg = GCLK_GENCTRL_SRC(GCLK_GENCTRL_SRC_DFLL_Val) |
GCLK_GENCTRL_IDC |
GCLK_GENCTRL_DIV(4) |
//GCLK_GENCTRL_DIVSEL |
GCLK_GENCTRL_DIVSEL |
//GCLK_GENCTRL_OE |
GCLK_GENCTRL_GENEN;
@ -253,55 +252,7 @@ void SystemInit( void )
CMCC->CTRL.reg = 1;
__enable_irq();
#endif
/*---------------------------------------------------------------------
* Start up the "Debug Watchpoint and Trace" unit, so that we can use
* it's 32bit cycle counter for timing.
*/
CoreDebug->DEMCR |= CoreDebug_DEMCR_TRCENA_Msk;
DWT->CTRL |= DWT_CTRL_CYCCNTENA_Msk;
/* ----------------------------------------------------------------------------------------------
* 5) Load AC factory calibration values
*/
uint32_t bias0 = (*((uint32_t *)AC_FUSES_BIAS0_ADDR) & AC_FUSES_BIAS0_Msk) >> AC_FUSES_BIAS0_Pos;
AC->CALIB.reg = AC_CALIB_BIAS0(bias0);
/* ----------------------------------------------------------------------------------------------
* 6) Load ADC factory calibration values
*/
// ADC0 Bias Calibration
uint32_t biascomp = (*((uint32_t *)ADC0_FUSES_BIASCOMP_ADDR) & ADC0_FUSES_BIASCOMP_Msk) >> ADC0_FUSES_BIASCOMP_Pos;
uint32_t biasr2r = (*((uint32_t *)ADC0_FUSES_BIASR2R_ADDR) & ADC0_FUSES_BIASR2R_Msk) >> ADC0_FUSES_BIASR2R_Pos;
uint32_t biasref = (*((uint32_t *)ADC0_FUSES_BIASREFBUF_ADDR) & ADC0_FUSES_BIASREFBUF_Msk) >> ADC0_FUSES_BIASREFBUF_Pos;
ADC0->CALIB.reg = ADC_CALIB_BIASREFBUF(biasref)
| ADC_CALIB_BIASR2R(biasr2r)
| ADC_CALIB_BIASCOMP(biascomp);
// ADC1 Bias Calibration
biascomp = (*((uint32_t *)ADC1_FUSES_BIASCOMP_ADDR) & ADC1_FUSES_BIASCOMP_Msk) >> ADC1_FUSES_BIASCOMP_Pos;
biasr2r = (*((uint32_t *)ADC1_FUSES_BIASR2R_ADDR) & ADC1_FUSES_BIASR2R_Msk) >> ADC1_FUSES_BIASR2R_Pos;
biasref = (*((uint32_t *)ADC1_FUSES_BIASREFBUF_ADDR) & ADC1_FUSES_BIASREFBUF_Msk) >> ADC1_FUSES_BIASREFBUF_Pos;
ADC1->CALIB.reg = ADC_CALIB_BIASREFBUF(biasref)
| ADC_CALIB_BIASR2R(biasr2r)
| ADC_CALIB_BIASCOMP(biascomp);
/* ----------------------------------------------------------------------------------------------
* 7) Load USB factory calibration values
*/
//USB Calibration
uint32_t usbtransn = (*((uint32_t *)USB_FUSES_TRANSN_ADDR) & USB_FUSES_TRANSN_Msk) >> USB_FUSES_TRANSN_Pos;
uint32_t usbtransp = (*((uint32_t *)USB_FUSES_TRANSP_ADDR) & USB_FUSES_TRANSP_Msk) >> USB_FUSES_TRANSP_Pos;
uint32_t usbtrim = (*((uint32_t *)USB_FUSES_TRIM_ADDR) & USB_FUSES_TRIM_Msk) >> USB_FUSES_TRIM_Pos;
USB->DEVICE.PADCAL.reg = USB_PADCAL_TRIM(usbtrim)
| USB_PADCAL_TRANSN(usbtransn)
| USB_PADCAL_TRANSP(usbtransp);
//*************** END SAMD51 *************************//
#else
@ -577,3 +528,4 @@ void SystemInit( void )
NVMCTRL->CTRLB.bit.MANW = 1;
#endif
}

View file

@ -25,7 +25,8 @@ extern "C" {
#if defined(__SAMD51__)
uint32_t SystemCoreClock=F_CPU;
//CHANGE THIS IF YOU CHANGE THE CLOCK SPEED
uint32_t SystemCoreClock=120000000ul ;
#else
/*
* System Core Clock is at 1MHz (8MHz/8) at Reset.
@ -78,21 +79,19 @@ void init( void )
// PM->APBAMASK.reg |= PM_APBAMASK_EIC ;
#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->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
// Clock SERCOM for Serial
PM->APBCMASK.reg |= PM_APBCMASK_SERCOM0 | PM_APBCMASK_SERCOM1 | PM_APBCMASK_SERCOM2 | PM_APBCMASK_SERCOM3 | PM_APBCMASK_SERCOM4 | PM_APBCMASK_SERCOM5 ;
// Clock TC/TCC for Pulse and Analog
PM->APBCMASK.reg |= PM_APBCMASK_TCC0 | PM_APBCMASK_TCC1 | PM_APBCMASK_TCC2 | PM_APBCMASK_TC3 | PM_APBCMASK_TC4 | PM_APBCMASK_TC5 | PM_APBCMASK_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
#ifdef PM_APBCMASK_DAC
@ -101,45 +100,35 @@ void init( void )
#endif
#endif
/*
Commented out to leave pins in default tri-state. This is
aimed at avoiding power consumption in DeepSleep.
// Setup all pins (digital and analog) in INPUT mode (default is nothing)
for (uint32_t ul = 0 ; ul < NUM_DIGITAL_PINS ; ul++ )
{
pinMode( ul, INPUT ) ;
}
*/
// Initialize Analog Controller
// Setting clock
#if defined(__SAMD51__)
//set to 1/(1/(48000000/32) * 6) = 250000 SPS
GCLK->PCHCTRL[ADC0_GCLK_ID].reg = GCLK_PCHCTRL_GEN_GCLK1_Val | (1 << GCLK_PCHCTRL_CHEN_Pos); //use clock generator 1 (48Mhz)
GCLK->PCHCTRL[ADC1_GCLK_ID].reg = GCLK_PCHCTRL_GEN_GCLK1_Val | (1 << GCLK_PCHCTRL_CHEN_Pos); //use clock generator 1 (48Mhz)
Adc *adcs[] = {ADC0, ADC1};
for(int i=0; i<2; i++){
adcs[i]->CTRLA.bit.PRESCALER = ADC_CTRLA_PRESCALER_DIV32_Val;
adcs[i]->CTRLB.bit.RESSEL = ADC_CTRLB_RESSEL_10BIT_Val;
while( adcs[i]->SYNCBUSY.reg & ADC_SYNCBUSY_CTRLB ); //wait for sync
adcs[i]->SAMPCTRL.reg = 5; // sampling Time Length
while( adcs[i]->SYNCBUSY.reg & ADC_SYNCBUSY_SAMPCTRL ); //wait for sync
adcs[i]->INPUTCTRL.reg = ADC_INPUTCTRL_MUXNEG_GND; // No Negative input (Internal Ground)
while( adcs[i]->SYNCBUSY.reg & ADC_SYNCBUSY_INPUTCTRL ); //wait for sync
// Averaging (see datasheet table in AVGCTRL register description)
adcs[i]->AVGCTRL.reg = ADC_AVGCTRL_SAMPLENUM_1 | // 1 sample only (no oversampling nor averaging)
ADC_AVGCTRL_ADJRES(0x0ul); // Adjusting result by 0
while( adcs[i]->SYNCBUSY.reg & ADC_SYNCBUSY_AVGCTRL ); //wait for sync
}
ADC0->CTRLA.bit.PRESCALER = ADC_CTRLA_PRESCALER_DIV256_Val;
ADC0->CTRLB.bit.RESSEL = ADC_CTRLB_RESSEL_10BIT_Val;
while( ADC0->SYNCBUSY.reg & ADC_SYNCBUSY_CTRLB ); //wait for sync
ADC0->SAMPCTRL.reg = 0x3f; // Set max Sampling Time Length
while( ADC0->SYNCBUSY.reg & ADC_SYNCBUSY_SAMPCTRL ); //wait for sync
ADC0->INPUTCTRL.reg = ADC_INPUTCTRL_MUXNEG_GND; // No Negative input (Internal Ground)
while( ADC0->SYNCBUSY.reg & ADC_SYNCBUSY_INPUTCTRL ); //wait for sync
// Averaging (see datasheet table in AVGCTRL register description)
ADC0->AVGCTRL.reg = ADC_AVGCTRL_SAMPLENUM_1 | // 1 sample only (no oversampling nor averaging)
ADC_AVGCTRL_ADJRES(0x0ul); // Adjusting result by 0
while( ADC0->SYNCBUSY.reg & ADC_SYNCBUSY_AVGCTRL ); //wait for sync
analogReference( AR_DEFAULT ) ; // Analog Reference is AREF pin (3.3v)
@ -157,8 +146,6 @@ void init( void )
DAC->DACCTRL[1].bit.REFRESH = 2;
#else
//set to 1/(1/(48000000/32) * 6) = 250000 SPS
while(GCLK->STATUS.reg & GCLK_STATUS_SYNCBUSY);
GCLK->CLKCTRL.reg = GCLK_CLKCTRL_ID( GCM_ADC ) | // Generic Clock ADC
@ -167,10 +154,10 @@ void init( void )
while( ADC->STATUS.bit.SYNCBUSY == 1 ); // Wait for synchronization of registers between the clock domains
ADC->CTRLB.reg = ADC_CTRLB_PRESCALER_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->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

View file

@ -32,7 +32,7 @@ static int _writeResolution = 12;
static int _dacResolution = 12;
#else
static int _writeResolution = 8;
//static int _dacResolution = 10;
static int _dacResolution = 8;
#endif
@ -77,21 +77,17 @@ void analogReadResolution(int res)
if (res > 10) {
ADC0->CTRLB.bit.RESSEL = ADC_CTRLB_RESSEL_12BIT_Val;
ADC1->CTRLB.bit.RESSEL = ADC_CTRLB_RESSEL_12BIT_Val;
_ADCResolution = 12;
} else if (res > 8) {
ADC0->CTRLB.bit.RESSEL = ADC_CTRLB_RESSEL_10BIT_Val;
ADC1->CTRLB.bit.RESSEL = ADC_CTRLB_RESSEL_10BIT_Val;
_ADCResolution = 10;
} else {
ADC0->CTRLB.bit.RESSEL = ADC_CTRLB_RESSEL_8BIT_Val;
ADC1->CTRLB.bit.RESSEL = ADC_CTRLB_RESSEL_8BIT_Val;
_ADCResolution = 8;
}
while(ADC0->SYNCBUSY.reg & ADC_SYNCBUSY_CTRLB); //wait for sync
while(ADC1->SYNCBUSY.reg & ADC_SYNCBUSY_CTRLB); //wait for sync
#else
if (res > 10) {
@ -135,92 +131,38 @@ void analogReference(eAnalogReference mode)
{
#if defined(__SAMD51__)
while(ADC0->SYNCBUSY.reg & ADC_SYNCBUSY_REFCTRL); //wait for sync
while(ADC1->SYNCBUSY.reg & ADC_SYNCBUSY_REFCTRL); //wait for sync
//TODO: fix gains
switch (mode)
{
case AR_INTERNAL1V0:
case AR_INTERNAL:
case AR_INTERNAL2V23:
//ADC0->GAINCORR.reg = ADC_GAINCORR_GAINCORR(); // Gain Factor Selection
SUPC->VREF.bit.SEL = SUPC_VREF_SEL_1V0_Val; // select 1.0V
SUPC->VREF.bit.VREFOE = 1; // Turn on for use with ADC
ADC0->REFCTRL.bit.REFSEL = ADC_REFCTRL_REFSEL_INTREF_Val; // Use SUPC.VREF
ADC1->REFCTRL.bit.REFSEL = ADC_REFCTRL_REFSEL_INTREF_Val; //
break;
case AR_INTERNAL1V1:
//ADC0->GAINCORR.reg = ADC_GAINCORR_GAINCORR(); // Gain Factor Selection
SUPC->VREF.bit.SEL = SUPC_VREF_SEL_1V1_Val; // select 1.1V
SUPC->VREF.bit.VREFOE = 1; // Turn on for use with ADC
ADC0->REFCTRL.bit.REFSEL = ADC_REFCTRL_REFSEL_INTREF_Val; // Use SUPC.VREF
ADC1->REFCTRL.bit.REFSEL = ADC_REFCTRL_REFSEL_INTREF_Val; //
break;
case AR_INTERNAL1V2:
//ADC0->GAINCORR.reg = ADC_GAINCORR_GAINCORR(); // Gain Factor Selection
SUPC->VREF.bit.SEL = SUPC_VREF_SEL_1V2_Val; // select 1V2
SUPC->VREF.bit.VREFOE = 1; // Turn on for use with ADC
ADC0->REFCTRL.bit.REFSEL = ADC_REFCTRL_REFSEL_INTREF_Val; // Use SUPC.VREF
ADC1->REFCTRL.bit.REFSEL = ADC_REFCTRL_REFSEL_INTREF_Val; //
ADC0->REFCTRL.bit.REFSEL = ADC_REFCTRL_REFSEL_INTVCC0_Val; // 1/1.48 VDDANA = 1/1.48* 3V3 = 2.2297
break;
case AR_INTERNAL1V25:
//ADC0->GAINCORR.reg = ADC_GAINCORR_GAINCORR(); // Gain Factor Selection
SUPC->VREF.bit.SEL = SUPC_VREF_SEL_1V25_Val; // select 1.25V
SUPC->VREF.bit.VREFOE = 1; // Turn on for use with ADC
ADC0->REFCTRL.bit.REFSEL = ADC_REFCTRL_REFSEL_INTREF_Val; // Use SUPC.VREF
ADC1->REFCTRL.bit.REFSEL = ADC_REFCTRL_REFSEL_INTREF_Val; //
break;
case AR_INTERNAL2V0:
//ADC0->GAINCORR.reg = ADC_GAINCORR_GAINCORR(); // Gain Factor Selection
SUPC->VREF.bit.SEL = SUPC_VREF_SEL_2V0_Val; // select 2.0V
SUPC->VREF.bit.VREFOE = 1; // Turn on for use with ADC
ADC0->REFCTRL.bit.REFSEL = ADC_REFCTRL_REFSEL_INTREF_Val; // Use SUPC.VREF
ADC1->REFCTRL.bit.REFSEL = ADC_REFCTRL_REFSEL_INTREF_Val; //
break;
case AR_INTERNAL2V2:
//ADC0->GAINCORR.reg = ADC_GAINCORR_GAINCORR(); // Gain Factor Selection
SUPC->VREF.bit.SEL = SUPC_VREF_SEL_2V2_Val; // select 2.2V
SUPC->VREF.bit.VREFOE = 1; // Turn on for use with ADC
ADC0->REFCTRL.bit.REFSEL = ADC_REFCTRL_REFSEL_INTREF_Val; // Use SUPC.VREF
ADC1->REFCTRL.bit.REFSEL = ADC_REFCTRL_REFSEL_INTREF_Val; //
break;
case AR_INTERNAL2V4:
//ADC0->GAINCORR.reg = ADC_GAINCORR_GAINCORR(); // Gain Factor Selection
SUPC->VREF.bit.SEL = SUPC_VREF_SEL_2V4_Val; // select 2.4V
SUPC->VREF.bit.VREFOE = 1; // Turn on for use with ADC
ADC0->REFCTRL.bit.REFSEL = ADC_REFCTRL_REFSEL_INTREF_Val; // Use SUPC.VREF
ADC1->REFCTRL.bit.REFSEL = ADC_REFCTRL_REFSEL_INTREF_Val; //
break;
case AR_INTERNAL2V5:
//ADC0->GAINCORR.reg = ADC_GAINCORR_GAINCORR(); // Gain Factor Selection
SUPC->VREF.bit.SEL = SUPC_VREF_SEL_2V5_Val; // select 2.5V
SUPC->VREF.bit.VREFOE = 1; // Turn on for use with ADC
ADC0->REFCTRL.bit.REFSEL = ADC_REFCTRL_REFSEL_INTREF_Val; // Use SUPC.VREF
ADC1->REFCTRL.bit.REFSEL = ADC_REFCTRL_REFSEL_INTREF_Val; //
break;
case AR_EXTERNAL:
//ADC0->INPUTCTRL.bit.GAIN = ADC_INPUTCTRL_GAIN_1X_Val; // Gain Factor Selection
ADC0->REFCTRL.bit.REFSEL = ADC_REFCTRL_REFSEL_AREFA_Val; // AREF is jumpered to VCC, so 3.3V
ADC1->REFCTRL.bit.REFSEL = ADC_REFCTRL_REFSEL_AREFA_Val;
ADC0->REFCTRL.bit.REFSEL = ADC_REFCTRL_REFSEL_AREFA_Val;
break;
case AR_INTERNAL1V65:
//ADC0->INPUTCTRL.bit.GAIN = ADC_INPUTCTRL_GAIN_DIV2_Val;
ADC0->REFCTRL.bit.REFSEL = ADC_REFCTRL_REFSEL_INTVCC0_Val; // 1/2 VDDANA = 1.65
ADC1->REFCTRL.bit.REFSEL = ADC_REFCTRL_REFSEL_INTVCC0_Val; //
/* Don't think this works on SAMD51
case AR_INTERNAL1V0:
//ADC0->INPUTCTRL.bit.GAIN = ADC_INPUTCTRL_GAIN_1X_Val; // Gain Factor Selection
ADC0->REFCTRL.bit.REFSEL = ADC_REFCTRL_REFSEL_INT1V_Val; // 1.0V voltage reference
break;
*/
case AR_INTERNAL1V65:
//ADC0->INPUTCTRL.bit.GAIN = ADC_INPUTCTRL_GAIN_1X_Val; // Gain Factor Selection
ADC0->REFCTRL.bit.REFSEL = ADC_REFCTRL_REFSEL_INTVCC1_Val; // 1/2 VDDANA = 0.5* 3V3 = 1.65V
break;
case AR_DEFAULT:
default:
//ADC0->INPUTCTRL.bit.GAIN = ADC_INPUTCTRL_GAIN_DIV2_Val;
ADC0->REFCTRL.bit.REFSEL = ADC_REFCTRL_REFSEL_INTVCC1_Val; // VDDANA = 3V3
ADC1->REFCTRL.bit.REFSEL = ADC_REFCTRL_REFSEL_INTVCC1_Val; //
ADC0->REFCTRL.bit.REFSEL = ADC_REFCTRL_REFSEL_INTVCC1_Val; // 1/2 VDDANA = 0.5* 3V3 = 1.65V
break;
}
@ -228,6 +170,7 @@ void analogReference(eAnalogReference mode)
syncADC();
switch (mode)
{
case AR_INTERNAL:
case AR_INTERNAL2V23:
ADC->INPUTCTRL.bit.GAIN = ADC_INPUTCTRL_GAIN_1X_Val; // Gain Factor Selection
ADC->REFCTRL.bit.REFSEL = ADC_REFCTRL_REFSEL_INTVCC0_Val; // 1/1.48 VDDANA = 1/1.48* 3V3 = 2.2297
@ -280,8 +223,8 @@ uint32_t analogRead(uint32_t pin)
#ifdef DAC
#if defined(__SAMD51__)
if (pin == PIN_DAC0 || pin == PIN_DAC1) { // Disable DAC, if analogWrite(A0,dval) used previously the DAC is enabled
uint8_t channel = (pin == PIN_DAC0 ? 0 : 1);
if (pin == A0 || pin == A1) { // Disable DAC, if analogWrite(A0,dval) used previously the DAC is enabled
uint8_t channel = (pin == PIN_A0 ? 0 : 1);
if(dacEnabled[channel]){
dacEnabled[channel] = false;
@ -298,7 +241,7 @@ uint32_t analogRead(uint32_t pin)
while (DAC->SYNCBUSY.bit.ENABLE);
#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();
DAC->CTRLA.bit.ENABLE = 0x00; // Disable DAC
@ -310,13 +253,8 @@ uint32_t analogRead(uint32_t pin)
#endif
#if defined(__SAMD51__)
Adc *adc;
if(g_APinDescription[pin].ulPinAttribute & PIN_ATTR_ANALOG) adc = ADC0;
else if(g_APinDescription[pin].ulPinAttribute & PIN_ATTR_ANALOG_ALT) adc = ADC1;
else return 0;
while( adc->SYNCBUSY.reg & ADC_SYNCBUSY_INPUTCTRL ); //wait for sync
adc->INPUTCTRL.bit.MUXPOS = g_APinDescription[pin].ulADCChannelNumber; // Selection for the positive ADC input
while( ADC0->SYNCBUSY.reg & ADC_SYNCBUSY_INPUTCTRL ); //wait for sync
ADC0->INPUTCTRL.bit.MUXPOS = g_APinDescription[pin].ulADCChannelNumber; // Selection for the positive ADC input
// 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
* configured. The first conversion after the reference is changed must not be used.
*/
while( adc->SYNCBUSY.reg & ADC_SYNCBUSY_ENABLE ); //wait for sync
adc->CTRLA.bit.ENABLE = 0x01; // Enable ADC
while( ADC0->SYNCBUSY.reg & ADC_SYNCBUSY_ENABLE ); //wait for sync
ADC0->CTRLA.bit.ENABLE = 0x01; // Enable ADC
// 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
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.
adc->SWTRIG.bit.START = 1;
ADC0->SWTRIG.bit.START = 1;
// Store the value
while (adc->INTFLAG.bit.RESRDY == 0); // Waiting for conversion to complete
valueRead = adc->RESULT.reg;
while (ADC0->INTFLAG.bit.RESRDY == 0); // Waiting for conversion to complete
valueRead = ADC0->RESULT.reg;
while( adc->SYNCBUSY.reg & ADC_SYNCBUSY_ENABLE ); //wait for sync
adc->CTRLA.bit.ENABLE = 0x00; // Disable ADC
while( adc->SYNCBUSY.reg & ADC_SYNCBUSY_ENABLE ); //wait for sync
while( ADC0->SYNCBUSY.reg & ADC_SYNCBUSY_ENABLE ); //wait for sync
ADC0->CTRLA.bit.ENABLE = 0x00; // Disable ADC
while( ADC0->SYNCBUSY.reg & ADC_SYNCBUSY_ENABLE ); //wait for sync
#else
syncADC();
@ -406,271 +344,273 @@ void analogWrite(uint32_t pin, uint32_t value)
// ATSAMR, for example, doesn't have a DAC
#ifdef DAC
if ((attr & PIN_ATTR_ANALOG) == PIN_ATTR_ANALOG)
{
// DAC handling code
#if defined(__SAMD51__)
if (pin == PIN_DAC0 || pin == PIN_DAC1) { // 2 DACs on A0 (PA02) and A1 (PA05)
#else
if (pin == PIN_DAC0) { // Only 1 DAC on A0 (PA02)
#endif
#if defined(__SAMD51__)
if (pin != PIN_A0 && pin != PIN_A1) { // 2 DACs on A0 (PA02) and A1 (PA05)
#else
if (pin != PIN_A0) { // Only 1 DAC on A0 (PA02)
#endif
return;
}
#if defined(__SAMD51__)
value = mapResolution(value, _writeResolution, _dacResolution);
value = mapResolution(value, _writeResolution, _dacResolution);
#if defined(__SAMD51__)
uint8_t channel = (pin == PIN_A0 ? 0 : 1);
pinPeripheral(pin, PIO_ANALOG);
if(!dacEnabled[channel]){
dacEnabled[channel] = true;
while (DAC->SYNCBUSY.bit.ENABLE || DAC->SYNCBUSY.bit.SWRST);
DAC->CTRLA.bit.ENABLE = 0; // disable DAC
while (DAC->SYNCBUSY.bit.ENABLE || DAC->SYNCBUSY.bit.SWRST);
DAC->DACCTRL[channel].bit.ENABLE = 1;
while (DAC->SYNCBUSY.bit.ENABLE || DAC->SYNCBUSY.bit.SWRST);
DAC->CTRLA.bit.ENABLE = 1; // enable DAC
uint8_t channel = (pin == PIN_DAC0 ? 0 : 1);
if(channel == 0){
pinPeripheral(pin, PIO_ANALOG);
while ( !DAC->STATUS.bit.READY0 );
if(!dacEnabled[channel]){
dacEnabled[channel] = true;
while (DAC->SYNCBUSY.bit.DATA0);
DAC->DATA[0].reg = value;
}
else if(channel == 1){
while ( !DAC->STATUS.bit.READY1 );
while (DAC->SYNCBUSY.bit.ENABLE || DAC->SYNCBUSY.bit.SWRST);
DAC->CTRLA.bit.ENABLE = 0; // disable DAC
while (DAC->SYNCBUSY.bit.DATA1);
DAC->DATA[1].reg = value;
}
while (DAC->SYNCBUSY.bit.ENABLE || DAC->SYNCBUSY.bit.SWRST);
DAC->DACCTRL[channel].bit.ENABLE = 1;
delayMicroseconds(10000);
}
//ERROR!
while(!DAC->DACCTRL[channel].bit.ENABLE);
if(channel == 0){
while ( !DAC->STATUS.bit.READY0 );
while (DAC->SYNCBUSY.bit.DATA0);
DAC->DATA[0].reg = value; // DAC on 10 bits.
}
else if(channel == 1){
while ( !DAC->STATUS.bit.READY1 );
while (DAC->SYNCBUSY.bit.DATA1);
DAC->DATA[1].reg = value; // DAC on 10 bits.
}
while (DAC->SYNCBUSY.bit.ENABLE || DAC->SYNCBUSY.bit.SWRST);
DAC->CTRLA.bit.ENABLE = 1; // enable DAC
if(channel == 0){
while ( !DAC->STATUS.bit.READY0 );
while (DAC->SYNCBUSY.bit.DATA0);
DAC->DATA[0].reg = value;
}
else if(channel == 1){
while ( !DAC->STATUS.bit.READY1 );
while (DAC->SYNCBUSY.bit.DATA1);
DAC->DATA[1].reg = value;
}
delayMicroseconds(10000);
}
//ERROR!
while(!DAC->DACCTRL[channel].bit.ENABLE);
if(channel == 0){
while ( !DAC->STATUS.bit.READY0 );
while (DAC->SYNCBUSY.bit.DATA0);
DAC->DATA[0].reg = value; // DAC on 10 bits.
}
else if(channel == 1){
while ( !DAC->STATUS.bit.READY1 );
while (DAC->SYNCBUSY.bit.DATA1);
DAC->DATA[1].reg = value; // DAC on 10 bits.
}
#else
syncDAC();
DAC->DATA.reg = value & 0x3FF; // DAC on 10 bits.
syncDAC();
DAC->CTRLA.bit.ENABLE = 0x01; // Enable DAC
syncDAC();
#endif // __SAMD51__
return;
#else
value = mapResolution(value, _dacResolution, 10);
syncDAC();
DAC->DATA.reg = value & 0x3FF; // DAC on 10 bits.
syncDAC();
DAC->CTRLA.bit.ENABLE = 0x01; // Enable DAC
syncDAC();
#endif
return;
}
}
#endif // DAC
#if defined(__SAMD51__)
if(attr & (PIN_ATTR_PWM_E|PIN_ATTR_PWM_F|PIN_ATTR_PWM_G)){
uint32_t tcNum = GetTCNumber(pinDesc.ulPWMChannel);
uint8_t tcChannel = GetTCChannelNumber(pinDesc.ulPWMChannel);
static bool tcEnabled[TCC_INST_NUM+TC_INST_NUM];
if(attr & PIN_ATTR_PWM_E)
pinPeripheral(pin, PIO_TIMER);
else if(attr & PIN_ATTR_PWM_F)
pinPeripheral(pin, PIO_TIMER_ALT);
else if(attr & PIN_ATTR_PWM_G)
pinPeripheral(pin, PIO_TCC_PDEC);
if (!tcEnabled[tcNum]) {
tcEnabled[tcNum] = true;
GCLK->PCHCTRL[GCLK_CLKCTRL_IDs[tcNum]].reg = GCLK_PCHCTRL_GEN_GCLK0_Val | (1 << GCLK_PCHCTRL_CHEN_Pos); //use clock generator 0
// Set PORT
if (tcNum >= TCC_INST_NUM) {
// -- Configure TC
Tc* TCx = (Tc*) GetTC(pinDesc.ulPWMChannel);
//reset
TCx->COUNT8.CTRLA.bit.SWRST = 1;
while (TCx->COUNT8.SYNCBUSY.bit.SWRST);
// Disable TCx
TCx->COUNT8.CTRLA.bit.ENABLE = 0;
while (TCx->COUNT8.SYNCBUSY.bit.ENABLE);
// Set Timer counter Mode to 8 bits, normal PWM, prescaler 1/256
TCx->COUNT8.CTRLA.reg = TC_CTRLA_MODE_COUNT8 | TC_CTRLA_PRESCALER_DIV256;
TCx->COUNT8.WAVE.reg = TC_WAVE_WAVEGEN_NPWM;
while (TCx->COUNT8.SYNCBUSY.bit.CC0);
// Set the initial value
TCx->COUNT8.CC[tcChannel].reg = (uint8_t) value;
while (TCx->COUNT8.SYNCBUSY.bit.CC0);
// Set PER to maximum counter value (resolution : 0xFF)
TCx->COUNT8.PER.reg = 0xFF;
while (TCx->COUNT8.SYNCBUSY.bit.PER);
// Enable TCx
TCx->COUNT8.CTRLA.bit.ENABLE = 1;
while (TCx->COUNT8.SYNCBUSY.bit.ENABLE);
} else {
// -- Configure TCC
Tcc* TCCx = (Tcc*) GetTC(pinDesc.ulPWMChannel);
TCCx->CTRLA.bit.SWRST = 1;
while (TCCx->SYNCBUSY.bit.SWRST);
// Disable TCCx
TCCx->CTRLA.bit.ENABLE = 0;
while (TCCx->SYNCBUSY.bit.ENABLE);
// Set prescaler to 1/256
TCCx->CTRLA.reg = TCC_CTRLA_PRESCALER_DIV256 | TCC_CTRLA_PRESCSYNC_GCLK;
// Set TCx as normal PWM
TCCx->WAVE.reg = TCC_WAVE_WAVEGEN_NPWM;
while ( TCCx->SYNCBUSY.bit.WAVE );
while (TCCx->SYNCBUSY.bit.CC0 || TCCx->SYNCBUSY.bit.CC1);
// Set the initial value
TCCx->CC[tcChannel].reg = (uint32_t) value;
while (TCCx->SYNCBUSY.bit.CC0 || TCCx->SYNCBUSY.bit.CC1);
// Set PER to maximum counter value (resolution : 0xFF)
TCCx->PER.reg = 0xFF;
while (TCCx->SYNCBUSY.bit.PER);
// Enable TCCx
TCCx->CTRLA.bit.ENABLE = 1;
while (TCCx->SYNCBUSY.bit.ENABLE);
}
}
else {
if (tcNum >= TCC_INST_NUM) {
Tc* TCx = (Tc*) GetTC(pinDesc.ulPWMChannel);
TCx->COUNT8.CC[tcChannel].reg = (uint8_t) value;
while (TCx->COUNT8.SYNCBUSY.bit.CC0 || TCx->COUNT8.SYNCBUSY.bit.CC1);
} else {
Tcc* TCCx = (Tcc*) GetTC(pinDesc.ulPWMChannel);
while (TCCx->SYNCBUSY.bit.CTRLB);
while (TCCx->SYNCBUSY.bit.CC0 || TCCx->SYNCBUSY.bit.CC1);
TCCx->CCBUF[tcChannel].reg = (uint32_t) value;
while (TCCx->SYNCBUSY.bit.CC0 || TCCx->SYNCBUSY.bit.CC1);
TCCx->CTRLBCLR.bit.LUPD = 1;
while (TCCx->SYNCBUSY.bit.CTRLB);
}
}
return;
}
#else
#endif
if ((attr & PIN_ATTR_PWM) == PIN_ATTR_PWM)
{
value = mapResolution(value, _writeResolution, 16);
{
#ifndef __SAMD51__
value = mapResolution(value, _writeResolution, 16);
#endif
uint32_t tcNum = GetTCNumber(pinDesc.ulPWMChannel);
uint8_t tcChannel = GetTCChannelNumber(pinDesc.ulPWMChannel);
static bool tcEnabled[TCC_INST_NUM+TC_INST_NUM];
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
if (attr & PIN_ATTR_TIMER) {
#if !(ARDUINO_SAMD_VARIANT_COMPLIANCE >= 10603)
// Compatibility for cores based on SAMD core <=1.6.2
if (pinDesc.ulPinType == PIO_TIMER_ALT) {
pinPeripheral(pin, PIO_TIMER_ALT);
} else
#endif
{
#if defined(__SAMD51__)
//on SAMD51 we are only using TCC for timers
pinPeripheral(pin, PIO_TCC_PDEC);
#else
pinPeripheral(pin, PIO_TIMER);
#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;
}
}
} else if ((attr & PIN_ATTR_TIMER_ALT) == PIN_ATTR_TIMER_ALT){
//this is on an alt timer
pinPeripheral(pin, PIO_TIMER_ALT);
}
else{
return;
}
if (!tcEnabled[tcNum]) {
tcEnabled[tcNum] = true;
uint16_t GCLK_CLKCTRL_IDs[] = {
GCLK_CLKCTRL_ID(GCM_TCC0_TCC1), // TCC0
GCLK_CLKCTRL_ID(GCM_TCC0_TCC1), // TCC1
GCLK_CLKCTRL_ID(GCM_TCC2_TC3), // TCC2
GCLK_CLKCTRL_ID(GCM_TCC2_TC3), // TC3
GCLK_CLKCTRL_ID(GCM_TC4_TC5), // TC4
GCLK_CLKCTRL_ID(GCM_TC4_TC5), // TC5
GCLK_CLKCTRL_ID(GCM_TC6_TC7), // TC6
GCLK_CLKCTRL_ID(GCM_TC6_TC7), // TC7
};
GCLK->CLKCTRL.reg = (uint16_t) (GCLK_CLKCTRL_CLKEN | GCLK_CLKCTRL_GEN_GCLK0 | GCLK_CLKCTRL_IDs[tcNum]);
while (GCLK->STATUS.bit.SYNCBUSY == 1);
if (!tcEnabled[tcNum]) {
tcEnabled[tcNum] = true;
// Set PORT
if (tcNum >= TCC_INST_NUM) {
#if defined(__SAMD51__)
uint32_t GCLK_CLKCTRL_IDs[] = {
TCC0_GCLK_ID,
TCC1_GCLK_ID,
TCC2_GCLK_ID,
#if defined(TCC3)
TCC3_GCLK_ID,
TCC4_GCLK_ID,
TC5_GCLK_ID,
#endif
};
GCLK->PCHCTRL[GCLK_CLKCTRL_IDs[tcNum]].reg = GCLK_PCHCTRL_GEN_GCLK0_Val | (1 << GCLK_PCHCTRL_CHEN_Pos); //use clock generator 0
// Set PORT
if (tcNum >= TCC_INST_NUM) {
// -- Configure TC
Tc* TCx = (Tc*) GetTC(pinDesc.ulPWMChannel);
//reset
TCx->COUNT8.CTRLA.bit.SWRST = 1;
while (TCx->COUNT8.SYNCBUSY.bit.SWRST);
// Disable TCx
TCx->COUNT16.CTRLA.bit.ENABLE = 0;
syncTC_16(TCx);
// Set Timer counter Mode to 16 bits, normal PWM
TCx->COUNT16.CTRLA.reg |= TC_CTRLA_MODE_COUNT16 | TC_CTRLA_WAVEGEN_NPWM;
syncTC_16(TCx);
TCx->COUNT8.CTRLA.bit.ENABLE = 0;
while (TCx->COUNT8.SYNCBUSY.bit.ENABLE);
// Set Timer counter Mode to 8 bits, normal PWM, prescaler 1/256
TCx->COUNT8.CTRLA.reg = TC_CTRLA_MODE_COUNT8 | TC_CTRLA_PRESCALER_DIV256;
TCx->COUNT8.WAVE.reg = TC_WAVE_WAVEGEN_NPWM;
while (TCx->COUNT8.SYNCBUSY.bit.CC0);
// Set the initial value
TCx->COUNT16.CC[tcChannel].reg = (uint32_t) value;
syncTC_16(TCx);
TCx->COUNT8.CC[tcChannel].reg = (uint8_t) value;
while (TCx->COUNT8.SYNCBUSY.bit.CC0);
// Set PER to maximum counter value (resolution : 0xFF)
TCx->COUNT8.PER.reg = 0xFF;
while (TCx->COUNT8.SYNCBUSY.bit.PER);
// Enable TCx
TCx->COUNT16.CTRLA.bit.ENABLE = 1;
syncTC_16(TCx);
} else {
TCx->COUNT8.CTRLA.bit.ENABLE = 1;
while (TCx->COUNT8.SYNCBUSY.bit.ENABLE);
} else {
// -- Configure TCC
Tcc* TCCx = (Tcc*) GetTC(pinDesc.ulPWMChannel);
TCCx->CTRLA.bit.SWRST = 1;
while (TCCx->SYNCBUSY.bit.SWRST);
// Disable TCCx
TCCx->CTRLA.bit.ENABLE = 0;
syncTCC(TCCx);
// Set TCCx as normal PWM
TCCx->WAVE.reg |= TCC_WAVE_WAVEGEN_NPWM;
syncTCC(TCCx);
while (TCCx->SYNCBUSY.bit.ENABLE);
// Set prescaler to 1/256
TCCx->CTRLA.reg = TCC_CTRLA_PRESCALER_DIV256 | TCC_CTRLA_PRESCSYNC_GCLK;
// Set TCx as normal PWM
TCCx->WAVE.reg = TCC_WAVE_WAVEGEN_NPWM;
while ( TCCx->SYNCBUSY.bit.WAVE );
while (TCCx->SYNCBUSY.bit.CC0 || TCCx->SYNCBUSY.bit.CC1);
// Set the initial value
TCCx->CC[tcChannel].reg = (uint32_t) value;
syncTCC(TCCx);
// Set PER to maximum counter value (resolution : 0xFFFF)
TCCx->PER.reg = 0xFFFF;
syncTCC(TCCx);
while (TCCx->SYNCBUSY.bit.CC0 || TCCx->SYNCBUSY.bit.CC1);
// Set PER to maximum counter value (resolution : 0xFF)
TCCx->PER.reg = 0xFF;
while (TCCx->SYNCBUSY.bit.PER);
// Enable TCCx
TCCx->CTRLA.bit.ENABLE = 1;
syncTCC(TCCx);
}
while (TCCx->SYNCBUSY.bit.ENABLE);
}
} else {
if (tcNum >= TCC_INST_NUM) {
Tc* TCx = (Tc*) GetTC(pinDesc.ulPWMChannel);
TCx->COUNT8.CC[tcChannel].reg = (uint8_t) value;
while (TCx->COUNT8.SYNCBUSY.bit.CC0 || TCx->COUNT8.SYNCBUSY.bit.CC1);
} else {
if (tcNum >= TCC_INST_NUM) {
Tc* TCx = (Tc*) GetTC(pinDesc.ulPWMChannel);
TCx->COUNT16.CC[tcChannel].reg = (uint32_t) value;
syncTC_16(TCx);
} else {
Tcc* TCCx = (Tcc*) GetTC(pinDesc.ulPWMChannel);
TCCx->CTRLBSET.bit.LUPD = 1;
syncTCC(TCCx);
TCCx->CCB[tcChannel].reg = (uint32_t) value;
syncTCC(TCCx);
TCCx->CTRLBCLR.bit.LUPD = 1;
syncTCC(TCCx);
}
}
return;
}
Tcc* TCCx = (Tcc*) GetTC(pinDesc.ulPWMChannel);
while (TCCx->SYNCBUSY.bit.CTRLB);
while (TCCx->SYNCBUSY.bit.CC0 || TCCx->SYNCBUSY.bit.CC1);
TCCx->CCBUF[tcChannel].reg = (uint32_t) value;
while (TCCx->SYNCBUSY.bit.CC0 || TCCx->SYNCBUSY.bit.CC1);
TCCx->CTRLBCLR.bit.LUPD = 1;
while (TCCx->SYNCBUSY.bit.CTRLB);
}
}
#else
uint16_t GCLK_CLKCTRL_IDs[] = {
GCLK_CLKCTRL_ID(GCM_TCC0_TCC1), // TCC0
GCLK_CLKCTRL_ID(GCM_TCC0_TCC1), // TCC1
GCLK_CLKCTRL_ID(GCM_TCC2_TC3), // TCC2
GCLK_CLKCTRL_ID(GCM_TCC2_TC3), // TC3
GCLK_CLKCTRL_ID(GCM_TC4_TC5), // TC4
GCLK_CLKCTRL_ID(GCM_TC4_TC5), // TC5
GCLK_CLKCTRL_ID(GCM_TC6_TC7), // TC6
GCLK_CLKCTRL_ID(GCM_TC6_TC7), // TC7
};
GCLK->CLKCTRL.reg = (uint16_t) (GCLK_CLKCTRL_CLKEN | GCLK_CLKCTRL_GEN_GCLK0 | GCLK_CLKCTRL_IDs[tcNum]);
while (GCLK->STATUS.bit.SYNCBUSY == 1);
// Set PORT
if (tcNum >= TCC_INST_NUM) {
// -- Configure TC
Tc* TCx = (Tc*) GetTC(pinDesc.ulPWMChannel);
// Disable TCx
TCx->COUNT16.CTRLA.bit.ENABLE = 0;
syncTC_16(TCx);
// Set Timer counter Mode to 16 bits, normal PWM
TCx->COUNT16.CTRLA.reg |= TC_CTRLA_MODE_COUNT16 | TC_CTRLA_WAVEGEN_NPWM;
syncTC_16(TCx);
// Set the initial value
TCx->COUNT16.CC[tcChannel].reg = (uint32_t) value;
syncTC_16(TCx);
// Enable TCx
TCx->COUNT16.CTRLA.bit.ENABLE = 1;
syncTC_16(TCx);
} else {
// -- Configure TCC
Tcc* TCCx = (Tcc*) GetTC(pinDesc.ulPWMChannel);
// Disable TCCx
TCCx->CTRLA.bit.ENABLE = 0;
syncTCC(TCCx);
// Set TCCx as normal PWM
TCCx->WAVE.reg |= TCC_WAVE_WAVEGEN_NPWM;
syncTCC(TCCx);
// Set the initial value
TCCx->CC[tcChannel].reg = (uint32_t) value;
syncTCC(TCCx);
// Set PER to maximum counter value (resolution : 0xFFFF)
TCCx->PER.reg = 0xFFFF;
syncTCC(TCCx);
// Enable TCCx
TCCx->CTRLA.bit.ENABLE = 1;
syncTCC(TCCx);
}
} else {
if (tcNum >= TCC_INST_NUM) {
Tc* TCx = (Tc*) GetTC(pinDesc.ulPWMChannel);
TCx->COUNT16.CC[tcChannel].reg = (uint32_t) value;
syncTC_16(TCx);
} else {
Tcc* TCCx = (Tcc*) GetTC(pinDesc.ulPWMChannel);
TCCx->CTRLBSET.bit.LUPD = 1;
syncTCC(TCCx);
TCCx->CCB[tcChannel].reg = (uint32_t) value;
syncTCC(TCCx);
TCCx->CTRLBCLR.bit.LUPD = 1;
syncTCC(TCCx);
}
}
#endif
return;
}
// -- Defaults to digital write
pinMode(pin, OUTPUT);

View file

@ -27,21 +27,14 @@ extern "C" {
/*
* \brief SAMD products have only one reference for ADC
*/
// add internal voltages for ATSAMD51 SUPC VREF register
typedef enum _eAnalogReference
{
AR_DEFAULT,
AR_INTERNAL,
AR_EXTERNAL,
AR_INTERNAL1V0,
AR_INTERNAL1V1,
AR_INTERNAL1V2,
AR_INTERNAL1V25,
AR_INTERNAL2V0,
AR_INTERNAL2V2,
AR_INTERNAL2V23,
AR_INTERNAL2V4,
AR_INTERNAL2V5,
AR_INTERNAL1V65,
AR_EXTERNAL
AR_INTERNAL2V23
} eAnalogReference ;

View file

@ -30,43 +30,39 @@ void pinMode( uint32_t ulPin, uint32_t ulMode )
return ;
}
EPortType port = g_APinDescription[ulPin].ulPort;
uint32_t pin = g_APinDescription[ulPin].ulPin;
uint32_t pinMask = (1ul << pin);
// Set pin mode according to chapter '22.6.3 I/O Pin Configuration'
switch ( ulMode )
{
case INPUT:
// Set pin to input mode
PORT->Group[port].PINCFG[pin].reg=(uint8_t)(PORT_PINCFG_INEN) ;
PORT->Group[port].DIRCLR.reg = pinMask ;
PORT->Group[g_APinDescription[ulPin].ulPort].PINCFG[g_APinDescription[ulPin].ulPin].reg=(uint8_t)(PORT_PINCFG_INEN) ;
PORT->Group[g_APinDescription[ulPin].ulPort].DIRCLR.reg = (uint32_t)(1<<g_APinDescription[ulPin].ulPin) ;
break ;
case INPUT_PULLUP:
// 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[port].DIRCLR.reg = pinMask ;
PORT->Group[g_APinDescription[ulPin].ulPort].PINCFG[g_APinDescription[ulPin].ulPin].reg=(uint8_t)(PORT_PINCFG_INEN|PORT_PINCFG_PULLEN) ;
PORT->Group[g_APinDescription[ulPin].ulPort].DIRCLR.reg = (uint32_t)(1<<g_APinDescription[ulPin].ulPin) ;
// 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 ;
case INPUT_PULLDOWN:
// 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[port].DIRCLR.reg = pinMask ;
PORT->Group[g_APinDescription[ulPin].ulPort].PINCFG[g_APinDescription[ulPin].ulPin].reg=(uint8_t)(PORT_PINCFG_INEN|PORT_PINCFG_PULLEN) ;
PORT->Group[g_APinDescription[ulPin].ulPort].DIRCLR.reg = (uint32_t)(1<<g_APinDescription[ulPin].ulPin) ;
// 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 ;
case OUTPUT:
// 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
PORT->Group[port].DIRSET.reg = pinMask ;
PORT->Group[g_APinDescription[ulPin].ulPort].DIRSET.reg = (uint32_t)(1<<g_APinDescription[ulPin].ulPin) ;
break ;
default:

View file

@ -107,7 +107,7 @@ int pinPeripheral( uint32_t ulPin, EPioType ulPeripheral )
// Set new muxing
PORT->Group[g_APinDescription[ulPin].ulPort].PMUX[g_APinDescription[ulPin].ulPin >> 1].reg = temp|PORT_PMUX_PMUXO( ulPeripheral ) ;
// Enable port mux
PORT->Group[g_APinDescription[ulPin].ulPort].PINCFG[g_APinDescription[ulPin].ulPin].reg |= PORT_PINCFG_PMUXEN | PORT_PINCFG_DRVSTR;
PORT->Group[g_APinDescription[ulPin].ulPort].PINCFG[g_APinDescription[ulPin].ulPin].reg |= PORT_PINCFG_PMUXEN ;
}
else // even pin
{
@ -115,7 +115,7 @@ int pinPeripheral( uint32_t ulPin, EPioType ulPeripheral )
temp = (PORT->Group[g_APinDescription[ulPin].ulPort].PMUX[g_APinDescription[ulPin].ulPin >> 1].reg) & PORT_PMUX_PMUXO( 0xF ) ;
PORT->Group[g_APinDescription[ulPin].ulPort].PMUX[g_APinDescription[ulPin].ulPin >> 1].reg = temp|PORT_PMUX_PMUXE( ulPeripheral ) ;
PORT->Group[g_APinDescription[ulPin].ulPort].PINCFG[g_APinDescription[ulPin].ulPin].reg |= PORT_PINCFG_PMUXEN | 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
break ;

View file

@ -46,14 +46,6 @@ StartType=3
ErrorControl=1
ServiceBinary=%12%\%DRIVERFILENAME%.sys
[NullInstall.nt]
; nothing to do for a null driver
[NullInstall.nt.Services]
; null driver has no service and no service name
AddService=, 0x00000002
;------------------------------------------------------------------------------
; Vista-64bit Sections
;------------------------------------------------------------------------------
@ -81,13 +73,6 @@ StartType=3
ErrorControl=1
ServiceBinary=%12%\%DRIVERFILENAME%.sys
[NullInstall.NTamd64]
; nothing to do for a null driver
[NullInstall.NTamd64.Services]
; null driver has no service and no service name
AddService=, 0x00000002
;------------------------------------------------------------------------------
; Vendor and Product ID Definitions
@ -102,14 +87,14 @@ AddService=, 0x00000002
[SourceDisksNames]
[DeviceList]
"%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% Arduino (8018:00) BSP"=DriverInstall, USB\VID_239A&PID_8018&MI_00
"%DESCRIPTION% CircuitPython (8019:00) BSP"=DriverInstall, USB\VID_239A&PID_8019&MI_00
[DeviceList.NTamd64]
"%DESCRIPTION% UF2 Bootloader (0018:00) BSP"=DriverInstall, USB\VID_239A&PID_0018&MI_00
"%DESCRIPTION% UF2 WebUSB dummy (0018:04) BSP"=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% 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

View file

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

View file

@ -1,3 +1,2 @@
SerialGSM KEYWORD1
SerialSARA KEYWORD1
INPUT_PULLDOWN LITERAL1 Constants RESERVED_WORD_2

View file

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

View file

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

View file

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

View file

@ -1,6 +0,0 @@
# Adafruit_ZeroDMA
DMA helper/wrapped for ATSAMD21 such as Arduino Zero &amp; 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.

View file

@ -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() { }

View file

@ -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() { }

View file

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

View file

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

View file

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

View file

@ -1 +0,0 @@
// fake empty header file to make Arduino IDE happy

View file

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

View file

@ -28,5 +28,4 @@ buildSDUBootSketch "arduino:samd:mkrfox1200" "$OUTPUT_PATH/mkrfox1200.h"
buildSDUBootSketch "arduino:samd:mkrgsm1400" "$OUTPUT_PATH/mkrgsm1400.h"
buildSDUBootSketch "arduino:samd:mkrwan1300" "$OUTPUT_PATH/mkrwan1300.h"
buildSDUBootSketch "arduino:samd:mkrwifi1010" "$OUTPUT_PATH/mkrwifi1010.h"
buildSDUBootSketch "arduino:samd:mkrnb1500" "$OUTPUT_PATH/mkrnb1500.h"
buildSDUBootSketch "arduino:samd:mzero_bl" "$OUTPUT_PATH/mzero.h"

View file

@ -36,8 +36,6 @@ unsigned char sduBoot[0x4000] = {
#include "boot/mkrwan1300.h"
#elif defined(ARDUINO_SAMD_MKRWIFI1010)
#include "boot/mkrwifi1010.h"
#elif defined(ARDUINO_SAMD_MKRNB1500)
#include "boot/mkrnb1500.h"
#elif defined(ARDUINO_SAM_ZERO)
#include "boot/mzero.h"
#else

File diff suppressed because it is too large Load diff

View file

@ -46,16 +46,7 @@ SPIClass::SPIClass(SERCOM *p_sercom, uint8_t uc_pinMISO, uint8_t uc_pinSCK, uint
void SPIClass::begin()
{
if(!initialized) {
interruptMode = SPI_IMODE_NONE;
interruptSave = 0;
interruptMask = 0;
initialized = true;
}
if(!use_dma) {
dmaAllocate();
}
init();
// PIO init
pinPeripheral(_uc_pinMiso, g_APinDescription[_uc_pinMiso].ulPinType);
@ -65,6 +56,16 @@ void SPIClass::begin()
config(DEFAULT_SPI_SETTINGS);
}
void SPIClass::init()
{
if (initialized)
return;
interruptMode = SPI_IMODE_NONE;
interruptSave = 0;
interruptMask = 0;
initialized = true;
}
void SPIClass::config(SPISettings settings)
{
_p_sercom->disableSPI();
@ -79,7 +80,6 @@ void SPIClass::end()
{
_p_sercom->resetSPI();
initialized = false;
// Add DMA deallocation here
}
#ifndef interruptsStatus
@ -198,7 +198,7 @@ void SPIClass::setDataMode(uint8_t mode)
void SPIClass::setClockDivider(uint8_t div)
{
if(div < SPI_MIN_CLOCK_DIVIDER) {
if (div < SPI_MIN_CLOCK_DIVIDER) {
_p_sercom->setBaudrateSPI(SPI_MIN_CLOCK_DIVIDER);
} else {
_p_sercom->setBaudrateSPI(div);
@ -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() {
// Should be enableInterrupt()
}
@ -468,61 +243,6 @@ void SPIClass::detachInterrupt() {
// Should be disableInterrupt()
}
// SPI DMA lookup works on both SAMD21 and SAMD51
static const struct {
volatile uint32_t *data_reg;
int dmac_id_tx;
int dmac_id_rx;
} sercomData[] = {
{ &SERCOM0->SPI.DATA.reg, SERCOM0_DMAC_ID_TX, SERCOM0_DMAC_ID_RX },
{ &SERCOM1->SPI.DATA.reg, SERCOM1_DMAC_ID_TX, SERCOM1_DMAC_ID_RX },
{ &SERCOM2->SPI.DATA.reg, SERCOM2_DMAC_ID_TX, SERCOM2_DMAC_ID_RX },
{ &SERCOM3->SPI.DATA.reg, SERCOM3_DMAC_ID_TX, SERCOM3_DMAC_ID_RX },
#if defined(SERCOM4)
{ &SERCOM4->SPI.DATA.reg, SERCOM4_DMAC_ID_TX, SERCOM4_DMAC_ID_RX },
#endif
#if defined(SERCOM5)
{ &SERCOM5->SPI.DATA.reg, SERCOM5_DMAC_ID_TX, SERCOM5_DMAC_ID_RX },
#endif
#if defined(SERCOM6)
{ &SERCOM6->SPI.DATA.reg, SERCOM6_DMAC_ID_TX, SERCOM6_DMAC_ID_RX },
#endif
#if defined(SERCOM7)
{ &SERCOM7->SPI.DATA.reg, SERCOM7_DMAC_ID_TX, SERCOM7_DMAC_ID_RX },
#endif
};
volatile uint32_t *SPIClass::getDataRegister(void) {
int8_t idx = _p_sercom->getSercomIndex();
return (idx >= 0) ? sercomData[idx].data_reg: NULL;
}
int SPIClass::getDMAC_ID_TX(void) {
int8_t idx = _p_sercom->getSercomIndex();
return (idx >= 0) ? sercomData[idx].dmac_id_tx : -1;
}
int SPIClass::getDMAC_ID_RX(void) {
int8_t idx = _p_sercom->getSercomIndex();
return (idx >= 0) ? sercomData[idx].dmac_id_rx : -1;
}
#if defined(__SAMD51__)
// Set the SPI device's SERCOM clock CORE and SLOW clock sources.
// SercomClockSource values are an enumeration in SERCOM.h.
// This works on SAMD51 only. On SAMD21, a dummy function is declared
// in SPI.h which compiles to nothing, so user code doesn't need to check
// and conditionally compile lines for different architectures.
void SPIClass::setClockSource(SercomClockSource clk) {
int8_t idx = _p_sercom->getSercomIndex();
_p_sercom->setClockSource(idx, clk, true); // true = set core clock
_p_sercom->setClockSource(idx, clk, false); // false = set slow clock
}
#endif // end __SAMD51__
#if SPI_INTERFACES_COUNT > 0
/* In case new variant doesn't define these macros,
* we put here the ones for Arduino Zero.
@ -555,3 +275,4 @@ void SPIClass::setClockSource(SercomClockSource clk) {
#if SPI_INTERFACES_COUNT > 5
SPIClass SPI5(&PERIPH_SPI5, PIN_SPI5_MISO, PIN_SPI5_SCK, PIN_SPI5_MOSI, PAD_SPI5_TX, PAD_SPI5_RX);
#endif

View file

@ -21,7 +21,6 @@
#define _SPI_H_INCLUDED
#include <Arduino.h>
#include <Adafruit_ZeroDMA.h>
// SPI_HAS_TRANSACTION means SPI has
// - beginTransaction()
@ -38,27 +37,12 @@
#define SPI_MODE2 0x03
#define SPI_MODE3 0x01
#if defined(__SAMD51__)
// SAMD51 has configurable MAX_SPI, else use peripheral clock default.
// Update: changing MAX_SPI via compiler flags is DEPRECATED, because
// this affects ALL SPI peripherals including some that should NOT be
// changed (e.g. anything using SD card). Use the setClockSource()
// function instead. This is left here for compatibility with interim code.
#if !defined(MAX_SPI)
#define MAX_SPI 24000000
#endif
#define SPI_MIN_CLOCK_DIVIDER 1
#else
#if defined(ARDUINO_ARCH_SAMD)
// The datasheet specifies a typical SPI SCK period (tSCK) of 42 ns,
// see "Table 36-48. SPI Timing Characteristics and Requirements",
// which translates into a maximum SPI clock of 23.8 MHz.
// We'll permit use of 24 MHz SPI even though this is slightly out
// of spec. Given how clock dividers work, the next "sensible"
// threshold would be a substantial drop down to 12 MHz.
#if !defined(MAX_SPI)
#define MAX_SPI 24000000
#endif
#define SPI_MIN_CLOCK_DIVIDER (uint8_t)(1 + ((F_CPU - 1) / MAX_SPI))
// Conservatively, the divider is set for a 12 MHz maximum SPI clock.
#define SPI_MIN_CLOCK_DIVIDER (uint8_t)(1 + ((F_CPU - 1) / 12000000))
#endif
class SPISettings {
@ -80,11 +64,7 @@ class SPISettings {
}
void init_AlwaysInline(uint32_t clock, BitOrder bitOrder, uint8_t dataMode) __attribute__((__always_inline__)) {
#if defined(__SAMD51__)
this->clockFreq = clock; // Clipping handled in SERCOM.cpp
#else
this->clockFreq = clock >= MAX_SPI ? MAX_SPI : clock;
#endif
this->clockFreq = (clock >= (F_CPU / SPI_MIN_CLOCK_DIVIDER) ? F_CPU / SPI_MIN_CLOCK_DIVIDER : clock);
this->bitOrder = (bitOrder == MSBFIRST ? MSB_FIRST : LSB_FIRST);
@ -114,12 +94,10 @@ class SPIClass {
public:
SPIClass(SERCOM *p_sercom, uint8_t uc_pinMISO, uint8_t uc_pinSCK, uint8_t uc_pinMOSI, SercomSpiTXPad, SercomRXPad);
byte transfer(uint8_t data);
uint16_t transfer16(uint16_t data);
void transfer(void *buf, size_t count);
void transfer(const void* txbuf, void* rxbuf, size_t count,
bool block = true);
void waitForTransfer(void);
// Transaction Functions
void usingInterrupt(int interruptNumber);
@ -138,21 +116,8 @@ class SPIClass {
void setDataMode(uint8_t uc_mode);
void setClockDivider(uint8_t uc_div);
// SERCOM lookup functions are available on both SAMD51 and 21.
volatile uint32_t *getDataRegister(void);
int getDMAC_ID_TX(void);
int getDMAC_ID_RX(void);
uint8_t getSercomIndex(void) { return _p_sercom->getSercomIndex(); };
#if defined(__SAMD51__)
// SERCOM clock source override is available only on SAMD51.
void setClockSource(SercomClockSource clk);
#else
// On SAMD21, this compiles to nothing, so user code doesn't need to
// check and conditionally compile lines for different architectures.
void setClockSource(SercomClockSource clk) { (void)clk; };
#endif // end __SAMD51__
private:
void init();
void config(SPISettings settings);
SERCOM *_p_sercom;
@ -167,18 +132,6 @@ class SPIClass {
uint8_t interruptMode;
char interruptSave;
uint32_t interruptMask;
// transfer(txbuf, rxbuf, count, block) uses DMA when possible
Adafruit_ZeroDMA readChannel;
Adafruit_ZeroDMA writeChannel;
DmacDescriptor *firstReadDescriptor = NULL; // List entry point
DmacDescriptor *firstWriteDescriptor = NULL;
DmacDescriptor *extraReadDescriptors = NULL; // Add'l descriptors
DmacDescriptor *extraWriteDescriptors = NULL;
bool use_dma = false; // true on successful alloc
volatile bool dma_busy = false;
void dmaAllocate(void);
static void dmaCallback(Adafruit_ZeroDMA *dma);
};
#if SPI_INTERFACES_COUNT > 0
@ -202,12 +155,14 @@ class SPIClass {
// For compatibility with sketches designed for AVR @ 16 MHz
// New programs should use SPI.beginTransaction to set the SPI clock
#define SPI_CLOCK_DIV2 (MAX_SPI * 2 / 8000000)
#define SPI_CLOCK_DIV4 (MAX_SPI * 2 / 4000000)
#define SPI_CLOCK_DIV8 (MAX_SPI * 2 / 2000000)
#define SPI_CLOCK_DIV16 (MAX_SPI * 2 / 1000000)
#define SPI_CLOCK_DIV32 (MAX_SPI * 2 / 500000)
#define SPI_CLOCK_DIV64 (MAX_SPI * 2 / 250000)
#define SPI_CLOCK_DIV128 (MAX_SPI * 2 / 125000)
#if F_CPU == 48000000
#define SPI_CLOCK_DIV2 6
#define SPI_CLOCK_DIV4 12
#define SPI_CLOCK_DIV8 24
#define SPI_CLOCK_DIV16 48
#define SPI_CLOCK_DIV32 96
#define SPI_CLOCK_DIV64 192
#define SPI_CLOCK_DIV128 255
#endif
#endif

View file

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