mirror of
https://github.com/tinygo-org/tinygo.git
synced 2026-08-01 17:47:46 +00:00
Compare commits
66 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| f0391eac25 | |||
| 05cdde162c | |||
| 25c8d3ec3a | |||
| 7b1e5f6f99 | |||
| 70c52ef1b4 | |||
| 5078ce382d | |||
| 408855da14 | |||
| 58072a5167 | |||
| 5026047cde | |||
| 67aea275c5 | |||
| 99bd4d2c7c | |||
| a4b22bd125 | |||
| 2ed7523001 | |||
| 4aec3d04f9 | |||
| 4f729c323d | |||
| 1f43f32aae | |||
| 6d1cbe6fb9 | |||
| 7cd2890434 | |||
| 13311da7e9 | |||
| 3047d8f321 | |||
| 13ed58950f | |||
| 5271bd8cfa | |||
| 72137d663b | |||
| 740134197e | |||
| 610e7fd16a | |||
| 69a6718b38 | |||
| 7d31d98f0f | |||
| 0a93347e1c | |||
| 411333327e | |||
| 159f7ebbc3 | |||
| 153ff09cc5 | |||
| 57cddf5657 | |||
| 6a35719594 | |||
| 20a46e1b28 | |||
| 926c02b6ff | |||
| f370cd18fc | |||
| a1d7cab080 | |||
| 15a9e2313a | |||
| 58f2533f15 | |||
| 3c2d2a93d3 | |||
| ea36fea5a9 | |||
| 5fdb894760 | |||
| 8fed063820 | |||
| 2f843af286 | |||
| 7afc47d67a | |||
| 0bc7c2a61f | |||
| d434058aef | |||
| 56780c2691 | |||
| 1d99b1ed84 | |||
| e1405640da | |||
| 5996e113ad | |||
| f1e6997018 | |||
| 335a7ad0b7 | |||
| 17deac116f | |||
| b112477e95 | |||
| 2fa24ef752 | |||
| fcefcb191c | |||
| ff7c71c99c | |||
| 7eaad62568 | |||
| 401bd89664 | |||
| 24b1bfcecd | |||
| 27162ebe32 | |||
| b347aea450 | |||
| 1766746c60 | |||
| 07049b87b6 | |||
| f38603530d |
@@ -55,18 +55,20 @@ jobs:
|
||||
labels: ${{ steps.meta.outputs.labels }}
|
||||
cache-from: type=gha
|
||||
cache-to: type=gha,mode=max
|
||||
- name: Trigger Drivers repo build on CircleCI
|
||||
- name: Trigger Drivers repo build on Github Actions
|
||||
run: |
|
||||
curl --location --request POST 'https://circleci.com/api/v2/project/github/tinygo-org/drivers/pipeline' \
|
||||
--header 'Content-Type: application/json' \
|
||||
-d '{"branch": "dev"}' \
|
||||
-u "${{ secrets.CIRCLECI_API_TOKEN }}"
|
||||
- name: Trigger Bluetooth repo build on CircleCI
|
||||
curl -X POST \
|
||||
-H "Authorization: Bearer ${{secrets.GHA_ACCESS_TOKEN}}" \
|
||||
-H "Accept: application/vnd.github.v3+json" \
|
||||
https://api.github.com/repos/tinygo-org/drivers/actions/workflows/build.yml/dispatches \
|
||||
-d '{"ref": "dev"}'
|
||||
- name: Trigger Bluetooth repo build on Github Actions
|
||||
run: |
|
||||
curl --location --request POST 'https://circleci.com/api/v2/project/github/tinygo-org/bluetooth/pipeline' \
|
||||
--header 'Content-Type: application/json' \
|
||||
-d '{"branch": "dev"}' \
|
||||
-u "${{ secrets.CIRCLECI_API_TOKEN }}"
|
||||
curl -X POST \
|
||||
-H "Authorization: Bearer ${{secrets.GHA_ACCESS_TOKEN}}" \
|
||||
-H "Accept: application/vnd.github.v3+json" \
|
||||
https://api.github.com/repos/tinygo-org/bluetooth/actions/workflows/linux.yml/dispatches \
|
||||
-d '{"ref": "dev"}'
|
||||
- name: Trigger TinyFS repo build on CircleCI
|
||||
run: |
|
||||
curl --location --request POST 'https://circleci.com/api/v2/project/github/tinygo-org/tinyfs/pipeline' \
|
||||
|
||||
+29
-16
@@ -14,19 +14,25 @@ concurrency:
|
||||
jobs:
|
||||
build-linux:
|
||||
# Build Linux binaries, ready for release.
|
||||
# This intentionally uses an older Linux image, so that we compile against
|
||||
# an older glibc version and therefore are compatible with a wide range of
|
||||
# Linux distributions.
|
||||
runs-on: ubuntu-18.04
|
||||
# This runs inside an Alpine Linux container so we can more easily create a
|
||||
# statically linked binary.
|
||||
runs-on: ubuntu-latest
|
||||
container:
|
||||
image: alpine:3.16
|
||||
steps:
|
||||
- name: Install apk dependencies
|
||||
# tar: needed for actions/cache@v2
|
||||
# git+openssh: needed for checkout (I think?)
|
||||
# gcompat: needed for go binary
|
||||
# ruby: needed to install fpm
|
||||
run: apk add tar git openssh gcompat make g++ ruby
|
||||
- name: Work around CVE-2022-24765
|
||||
# We're not on a multi-user machine, so this is safe.
|
||||
run: git config --global --add safe.directory "$GITHUB_WORKSPACE"
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v2
|
||||
with:
|
||||
submodules: true
|
||||
- name: Install apt dependencies
|
||||
run: |
|
||||
sudo apt-get install --no-install-recommends \
|
||||
ninja-build
|
||||
- name: Install Go
|
||||
uses: actions/setup-go@v2
|
||||
with:
|
||||
@@ -34,7 +40,7 @@ jobs:
|
||||
- name: Cache Go
|
||||
uses: actions/cache@v2
|
||||
with:
|
||||
key: go-cache-linux-v1-${{ hashFiles('go.mod') }}
|
||||
key: go-cache-linux-alpine-v1-${{ hashFiles('go.mod') }}
|
||||
path: |
|
||||
~/.cache/go-build
|
||||
~/go/pkg/mod
|
||||
@@ -42,7 +48,7 @@ jobs:
|
||||
uses: actions/cache@v2
|
||||
id: cache-llvm-source
|
||||
with:
|
||||
key: llvm-source-14-linux-v2
|
||||
key: llvm-source-14-linux-alpine-v1
|
||||
path: |
|
||||
llvm-project/clang/lib/Headers
|
||||
llvm-project/clang/include
|
||||
@@ -56,7 +62,7 @@ jobs:
|
||||
uses: actions/cache@v2
|
||||
id: cache-llvm-build
|
||||
with:
|
||||
key: llvm-build-14-linux-v1
|
||||
key: llvm-build-14-linux-alpine-v1
|
||||
path: llvm-build
|
||||
- name: Build LLVM
|
||||
if: steps.cache-llvm-build.outputs.cache-hit != 'true'
|
||||
@@ -64,6 +70,8 @@ jobs:
|
||||
# fetch LLVM source
|
||||
rm -rf llvm-project
|
||||
make llvm-source
|
||||
# install dependencies
|
||||
apk add cmake samurai python3
|
||||
# build!
|
||||
make llvm-build
|
||||
# Remove unnecessary object files (to reduce cache size).
|
||||
@@ -72,26 +80,29 @@ jobs:
|
||||
uses: actions/cache@v2
|
||||
id: cache-binaryen
|
||||
with:
|
||||
key: binaryen-linux-v1
|
||||
key: binaryen-linux-alpine-v1
|
||||
path: build/wasm-opt
|
||||
- name: Build Binaryen
|
||||
if: steps.cache-binaryen.outputs.cache-hit != 'true'
|
||||
run: make binaryen
|
||||
run: |
|
||||
apk add cmake samurai python3
|
||||
make binaryen STATIC=1
|
||||
- name: Cache wasi-libc
|
||||
uses: actions/cache@v2
|
||||
id: cache-wasi-libc
|
||||
with:
|
||||
key: wasi-libc-sysroot-linux-asserts-v5
|
||||
key: wasi-libc-sysroot-linux-alpine-v1
|
||||
path: lib/wasi-libc/sysroot
|
||||
- name: Build wasi-libc
|
||||
if: steps.cache-wasi-libc.outputs.cache-hit != 'true'
|
||||
run: make wasi-libc
|
||||
- name: Install fpm
|
||||
run: |
|
||||
sudo gem install --no-document fpm
|
||||
gem install --version 2.7.6 dotenv
|
||||
gem install --no-document fpm
|
||||
- name: Build TinyGo release
|
||||
run: |
|
||||
make release deb -j3
|
||||
make release deb -j3 STATIC=1
|
||||
cp -p build/release.tar.gz /tmp/tinygo.linux-amd64.tar.gz
|
||||
cp -p build/release.deb /tmp/tinygo_amd64.deb
|
||||
- name: Publish release artifact
|
||||
@@ -323,6 +334,7 @@ jobs:
|
||||
make CROSS=arm-linux-gnueabihf binaryen
|
||||
- name: Install fpm
|
||||
run: |
|
||||
sudo gem install --version 2.7.6 dotenv
|
||||
sudo gem install --no-document fpm
|
||||
- name: Build TinyGo binary
|
||||
run: |
|
||||
@@ -424,6 +436,7 @@ jobs:
|
||||
make CROSS=aarch64-linux-gnu binaryen
|
||||
- name: Install fpm
|
||||
run: |
|
||||
sudo gem install --version 2.7.6 dotenv
|
||||
sudo gem install --no-document fpm
|
||||
- name: Build TinyGo binary
|
||||
run: |
|
||||
|
||||
+2
-1
@@ -23,6 +23,7 @@ llvm-project
|
||||
build/*
|
||||
|
||||
# Ignore files generated by smoketest
|
||||
test
|
||||
test.bin
|
||||
test.elf
|
||||
test.exe
|
||||
@@ -30,4 +31,4 @@ test.gba
|
||||
test.hex
|
||||
test.nro
|
||||
test.wasm
|
||||
wasm.wasm
|
||||
wasm.wasm
|
||||
|
||||
@@ -1,3 +1,58 @@
|
||||
0.25.0
|
||||
---
|
||||
|
||||
* **command line**
|
||||
- change to ignore PortReset failures
|
||||
* **compiler**
|
||||
- `compiler`: darwin/arm64 is aarch64, not arm
|
||||
- `compiler`: don't clobber X18 and FP registers on darwin/arm64
|
||||
- `compiler`: fix issue with methods on generic structs
|
||||
- `compiler`: do not try to build generic functions
|
||||
- `compiler`: fix type names for generic named structs
|
||||
- `compiler`: fix multiple defined function issue for generic functions
|
||||
- `compiler`: implement `unsafe.Alignof` and `unsafe.Sizeof` for generic code
|
||||
* **standard library**
|
||||
- `machine`: add DTR and RTS to Serialer interface
|
||||
- `machine`: reorder pin definitions to improve pin list on tinygo.org
|
||||
- `machine/usb`: add support for MIDI
|
||||
- `machine/usb`: adjust buffer alignment (samd21, samd51, nrf52840)
|
||||
- `machine/usb/midi`: add `NoteOn`, `NoteOff`, and `SendCC` methods
|
||||
- `machine/usb/midi`: add definition of MIDI note number
|
||||
- `runtime`: add benchmarks for memhash
|
||||
- `runtime`: add support for printing slices via print/println
|
||||
* **targets**
|
||||
- `avr`: fix some apparent mistake in atmega1280/atmega2560 pin constants
|
||||
- `esp32`: provide hardware pin constants
|
||||
- `esp32`: fix WDT reset on the MCH2022 badge
|
||||
- `esp32`: optimize SPI transmit
|
||||
- `esp32c3`: provide hardware pin constants
|
||||
- `esp8266`: provide hardware pin constants like `GPIO2`
|
||||
- `nrf51`: define and use `P0_xx` constants
|
||||
- `nrf52840`, `samd21`, `samd51`: unify bootloader entry process
|
||||
- `nrf52840`, `samd21`, `samd51`: change usbSetup and sendZlp to public
|
||||
- `nrf52840`, `samd21`, `samd51`: refactor handleStandardSetup and initEndpoint
|
||||
- `nrf52840`, `samd21`, `samd51`: improve usb-device initialization
|
||||
- `nrf52840`, `samd21`, `samd51`: move usbcdc to machine/usb/cdc
|
||||
- `rp2040`: add usb serial vendor/product ID
|
||||
- `rp2040`: add support for usb
|
||||
- `rp2040`: change default for serial to usb
|
||||
- `rp2040`: add support for `machine.EnterBootloader`
|
||||
- `rp2040`: turn off pullup/down when input type is not specified
|
||||
- `rp2040`: make picoprobe default openocd interface
|
||||
- `samd51`: add support for `DAC1`
|
||||
- `samd51`: improve TRNG
|
||||
- `wasm`: stub `runtime.buffered`, `runtime.getchar`
|
||||
- `wasi`: make leveldb runtime hash the default
|
||||
* **boards**
|
||||
- add Challenger RP2040 LoRa
|
||||
- add MCH2022 badge
|
||||
- add XIAO RP2040
|
||||
- `clue`: remove pins `D21`..`D28`
|
||||
- `feather-rp2040`, `macropad-rp2040`: fix qspi-flash settings
|
||||
- `xiao-ble`: add support for flash-1200-bps-reset
|
||||
- `gopherbot`, `gopherbot2`: add these aliases to simplify for newer users
|
||||
|
||||
|
||||
0.24.0
|
||||
---
|
||||
|
||||
|
||||
@@ -56,6 +56,23 @@ else
|
||||
LLVM_OPTION += '-DLLVM_ENABLE_ASSERTIONS=OFF'
|
||||
endif
|
||||
|
||||
ifeq (1, $(STATIC))
|
||||
# Build TinyGo as a fully statically linked binary (no dynamically loaded
|
||||
# libraries such as a libc). This is not supported with glibc which is used
|
||||
# on most major Linux distributions. However, it is supported in Alpine
|
||||
# Linux with musl.
|
||||
CGO_LDFLAGS += -static
|
||||
# Also set the thread stack size to 1MB. This is necessary on musl as the
|
||||
# default stack size is 128kB and LLVM uses more than that.
|
||||
# For more information, see:
|
||||
# https://wiki.musl-libc.org/functional-differences-from-glibc.html#Thread-stack-size
|
||||
CGO_LDFLAGS += -Wl,-z,stack-size=1048576
|
||||
# Build wasm-opt with static linking.
|
||||
# For details, see:
|
||||
# https://github.com/WebAssembly/binaryen/blob/version_102/.github/workflows/ci.yml#L181
|
||||
BINARYEN_OPTION += -DCMAKE_CXX_FLAGS="-static" -DCMAKE_C_FLAGS="-static"
|
||||
endif
|
||||
|
||||
# Cross compiling support.
|
||||
ifneq ($(CROSS),)
|
||||
CC = $(CROSS)-gcc
|
||||
@@ -246,9 +263,9 @@ lib/wasi-libc/sysroot/lib/wasm32-wasi/libc.a:
|
||||
# Build the Go compiler.
|
||||
tinygo:
|
||||
@if [ ! -f "$(LLVM_BUILDDIR)/bin/llvm-config" ]; then echo "Fetch and build LLVM first by running:"; echo " make llvm-source"; echo " make $(LLVM_BUILDDIR)"; exit 1; fi
|
||||
CGO_CPPFLAGS="$(CGO_CPPFLAGS)" CGO_CXXFLAGS="$(CGO_CXXFLAGS)" CGO_LDFLAGS="$(CGO_LDFLAGS)" $(GOENVFLAGS) $(GO) build -buildmode exe -o build/tinygo$(EXE) -tags byollvm -ldflags="-X github.com/tinygo-org/tinygo/goenv.GitSha1=`git rev-parse --short HEAD`" .
|
||||
CGO_CPPFLAGS="$(CGO_CPPFLAGS)" CGO_CXXFLAGS="$(CGO_CXXFLAGS)" CGO_LDFLAGS="$(CGO_LDFLAGS)" $(GOENVFLAGS) $(GO) build -buildmode exe -o build/tinygo$(EXE) -tags "byollvm osusergo" -ldflags="-X github.com/tinygo-org/tinygo/goenv.GitSha1=`git rev-parse --short HEAD`" .
|
||||
test: wasi-libc
|
||||
CGO_CPPFLAGS="$(CGO_CPPFLAGS)" CGO_CXXFLAGS="$(CGO_CXXFLAGS)" CGO_LDFLAGS="$(CGO_LDFLAGS)" $(GO) test $(GOTESTFLAGS) -timeout=20m -buildmode exe -tags byollvm ./builder ./cgo ./compileopts ./compiler ./interp ./transform .
|
||||
CGO_CPPFLAGS="$(CGO_CPPFLAGS)" CGO_CXXFLAGS="$(CGO_CXXFLAGS)" CGO_LDFLAGS="$(CGO_LDFLAGS)" $(GO) test $(GOTESTFLAGS) -timeout=20m -buildmode exe -tags "byollvm osusergo" ./builder ./cgo ./compileopts ./compiler ./interp ./transform .
|
||||
|
||||
# Standard library packages that pass tests on darwin, linux, wasi, and windows, but take over a minute in wasi
|
||||
TEST_PACKAGES_SLOW = \
|
||||
@@ -437,14 +454,14 @@ ifneq ($(WASM), 0)
|
||||
@$(MD5SUM) test.wasm
|
||||
$(TINYGO) build -size short -o test.wasm -tags=reelboard examples/blinky1
|
||||
@$(MD5SUM) test.wasm
|
||||
$(TINYGO) build -size short -o test.wasm -tags=pca10040 examples/blinky2
|
||||
@$(MD5SUM) test.wasm
|
||||
$(TINYGO) build -size short -o test.wasm -tags=pca10056 examples/blinky2
|
||||
$(TINYGO) build -size short -o test.wasm -tags=microbit examples/microbit-blink
|
||||
@$(MD5SUM) test.wasm
|
||||
$(TINYGO) build -size short -o test.wasm -tags=circuitplay_express examples/blinky1
|
||||
@$(MD5SUM) test.wasm
|
||||
$(TINYGO) build -size short -o test.wasm -tags=circuitplay_bluefruit examples/blinky1
|
||||
@$(MD5SUM) test.wasm
|
||||
$(TINYGO) build -size short -o test.wasm -tags=mch2022 examples/serial
|
||||
@$(MD5SUM) test.wasm
|
||||
endif
|
||||
# test all targets/boards
|
||||
$(TINYGO) build -size short -o test.hex -target=pca10040-s132v6 examples/blinky1
|
||||
@@ -567,6 +584,10 @@ endif
|
||||
@$(MD5SUM) test.hex
|
||||
$(TINYGO) build -size short -o test.hex -target=thingplus-rp2040 examples/blinky1
|
||||
@$(MD5SUM) test.hex
|
||||
$(TINYGO) build -size short -o test.hex -target=xiao-rp2040 examples/blinky1
|
||||
@$(MD5SUM) test.hex
|
||||
$(TINYGO) build -size short -o test.hex -target=challenger-rp2040 examples/blinky1
|
||||
@$(MD5SUM) test.hex
|
||||
# test pwm
|
||||
$(TINYGO) build -size short -o test.hex -target=itsybitsy-m0 examples/pwm
|
||||
@$(MD5SUM) test.hex
|
||||
@@ -574,11 +595,13 @@ endif
|
||||
@$(MD5SUM) test.hex
|
||||
$(TINYGO) build -size short -o test.hex -target=feather-m4 examples/pwm
|
||||
@$(MD5SUM) test.hex
|
||||
# test usbhid
|
||||
# test usb
|
||||
$(TINYGO) build -size short -o test.hex -target=feather-nrf52840 examples/hid-keyboard
|
||||
@$(MD5SUM) test.hex
|
||||
$(TINYGO) build -size short -o test.hex -target=circuitplay-express examples/hid-keyboard
|
||||
@$(MD5SUM) test.hex
|
||||
$(TINYGO) build -size short -o test.hex -target=feather-nrf52840 examples/usb-midi
|
||||
@$(MD5SUM) test.hex
|
||||
ifneq ($(STM32), 0)
|
||||
$(TINYGO) build -size short -o test.hex -target=bluepill examples/blinky1
|
||||
@$(MD5SUM) test.hex
|
||||
@@ -642,6 +665,8 @@ ifneq ($(XTENSA), 0)
|
||||
@$(MD5SUM) test.bin
|
||||
$(TINYGO) build -size short -o test.bin -target m5stack examples/serial
|
||||
@$(MD5SUM) test.bin
|
||||
$(TINYGO) build -size short -o test.bin -target mch2022 examples/serial
|
||||
@$(MD5SUM) test.bin
|
||||
endif
|
||||
$(TINYGO) build -size short -o test.bin -target=esp32c3 examples/serial
|
||||
@$(MD5SUM) test.bin
|
||||
|
||||
@@ -43,7 +43,7 @@ See the [getting started instructions](https://tinygo.org/getting-started/) for
|
||||
|
||||
You can compile TinyGo programs for microcontrollers, WebAssembly and Linux.
|
||||
|
||||
The following 85 microcontroller boards are currently supported:
|
||||
The following 88 microcontroller boards are currently supported:
|
||||
|
||||
* [Adafruit Circuit Playground Bluefruit](https://www.adafruit.com/product/4333)
|
||||
* [Adafruit Circuit Playground Express](https://www.adafruit.com/product/3333)
|
||||
@@ -89,11 +89,13 @@ The following 85 microcontroller boards are currently supported:
|
||||
* [ESP8266 - d1mini](https://www.espressif.com/en/products/socs/esp8266)
|
||||
* [ESP8266 - NodeMCU](https://www.espressif.com/en/products/socs/esp8266)
|
||||
* [Game Boy Advance](https://en.wikipedia.org/wiki/Game_Boy_Advance)
|
||||
* [iLabs Challenger RP2040 LoRa](https://ilabs.se/product/challenger-rp2040-lora/)
|
||||
* [M5Stack](https://docs.m5stack.com/en/core/basic)
|
||||
* [M5Stack Core2](https://shop.m5stack.com/products/m5stack-core2-esp32-iot-development-kit)
|
||||
* [M5Stamp C3](https://docs.m5stack.com/en/core/stamp_c3)
|
||||
* [Makerdiary nRF52840-MDK](https://wiki.makerdiary.com/nrf52840-mdk/)
|
||||
* [Makerdiary nRF52840-MDK USB Dongle](https://wiki.makerdiary.com/nrf52840-mdk-usb-dongle/)
|
||||
* [MCH2022 badge](https://badge.team/docs/badges/mch2022/)
|
||||
* [Microchip SAM E54 Xplained Pro](https://www.microchip.com/developmenttools/productdetails/atsame54-xpro)
|
||||
* [nice!nano](https://docs.nicekeyboards.com/#/nice!nano/)
|
||||
* [Nintendo Switch](https://www.nintendo.com/switch/)
|
||||
@@ -105,6 +107,7 @@ The following 85 microcontroller boards are currently supported:
|
||||
* [Particle Boron](https://docs.particle.io/datasheets/cellular/boron-datasheet/)
|
||||
* [Particle Xenon](https://docs.particle.io/datasheets/discontinued/xenon-datasheet/)
|
||||
* [Phytec reel board](https://www.phytec.eu/product-eu/internet-of-things/reelboard/)
|
||||
* [Pimoroni Badger2040](https://shop.pimoroni.com/products/badger-2040)
|
||||
* [PineTime DevKit](https://www.pine64.org/pinetime/)
|
||||
* [PJRC Teensy 3.6](https://www.pjrc.com/store/teensy36.html)
|
||||
* [PJRC Teensy 4.0](https://www.pjrc.com/store/teensy40.html)
|
||||
@@ -114,6 +117,7 @@ The following 85 microcontroller boards are currently supported:
|
||||
* [Raytac MDBT50Q-RX Dongle (with TinyUF2 bootloader)](https://www.adafruit.com/product/5199)
|
||||
* [Seeed Seeeduino XIAO](https://www.seeedstudio.com/Seeeduino-XIAO-Arduino-Microcontroller-SAMD21-Cortex-M0+-p-4426.html)
|
||||
* [Seeed XIAO BLE](https://www.seeedstudio.com/Seeed-XIAO-BLE-nRF52840-p-5201.html)
|
||||
* [Seeed XIAO RP2040](https://www.seeedstudio.com/XIAO-RP2040-v1-0-p-5026.html)
|
||||
* [Seeed LoRa-E5 Development Kit](https://www.seeedstudio.com/LoRa-E5-Dev-Kit-p-4868.html)
|
||||
* [Seeed Sipeed MAix BiT](https://www.seeedstudio.com/Sipeed-MAix-BiT-for-RISC-V-AI-IoT-p-2872.html)
|
||||
* [Seeed Wio Terminal](https://www.seeedstudio.com/Wio-Terminal-p-4509.html)
|
||||
|
||||
@@ -13,10 +13,13 @@ import (
|
||||
"strconv"
|
||||
"strings"
|
||||
"unsafe"
|
||||
|
||||
"tinygo.org/x/go-llvm"
|
||||
)
|
||||
|
||||
/*
|
||||
#include <clang-c/Index.h> // If this fails, libclang headers aren't available. Please take a look here: https://tinygo.org/docs/guides/build/
|
||||
#include <llvm/Config/llvm-config.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
|
||||
@@ -76,6 +79,16 @@ var diagnosticSeverity = [...]string{
|
||||
// theory decoupled from Clang) can also use this type.
|
||||
type clangCursor = C.GoCXCursor
|
||||
|
||||
func init() {
|
||||
// Check that we haven't messed up LLVM versioning.
|
||||
// This can happen when llvm_config_*.go files in either this or the
|
||||
// tinygo.org/x/go-llvm packages is incorrect. It should not ever happen
|
||||
// with byollvm.
|
||||
if C.LLVM_VERSION_STRING != llvm.Version {
|
||||
panic("incorrect build: using LLVM version " + llvm.Version + " in the tinygo.org/x/llvm package, and version " + C.LLVM_VERSION_STRING + " in the ./cgo package")
|
||||
}
|
||||
}
|
||||
|
||||
func (f *cgoFile) readNames(fragment string, cflags []string, filename string, callback func(map[string]clangCursor)) {
|
||||
index := C.clang_createIndex(0, 0)
|
||||
defer C.clang_disposeIndex(index)
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
//go:build !byollvm && !llvm14
|
||||
// +build !byollvm,!llvm14
|
||||
//go:build !byollvm && llvm13
|
||||
// +build !byollvm,llvm13
|
||||
|
||||
package cgo
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
//go:build !byollvm && llvm14
|
||||
// +build !byollvm,llvm14
|
||||
//go:build !byollvm && !llvm13
|
||||
// +build !byollvm,!llvm13
|
||||
|
||||
package cgo
|
||||
|
||||
|
||||
+45
-8
@@ -18,6 +18,7 @@ import (
|
||||
"github.com/tinygo-org/tinygo/compiler/llvmutil"
|
||||
"github.com/tinygo-org/tinygo/loader"
|
||||
"golang.org/x/tools/go/ssa"
|
||||
"golang.org/x/tools/go/types/typeutil"
|
||||
"tinygo.org/x/go-llvm"
|
||||
)
|
||||
|
||||
@@ -70,7 +71,7 @@ type compilerContext struct {
|
||||
cu llvm.Metadata
|
||||
difiles map[string]llvm.Metadata
|
||||
ditypes map[types.Type]llvm.Metadata
|
||||
llvmTypes map[types.Type]llvm.Type
|
||||
llvmTypes typeutil.Map
|
||||
machine llvm.TargetMachine
|
||||
targetData llvm.TargetData
|
||||
intType llvm.Type
|
||||
@@ -95,7 +96,6 @@ func newCompilerContext(moduleName string, machine llvm.TargetMachine, config *C
|
||||
DumpSSA: dumpSSA,
|
||||
difiles: make(map[string]llvm.Metadata),
|
||||
ditypes: make(map[types.Type]llvm.Metadata),
|
||||
llvmTypes: make(map[types.Type]llvm.Type),
|
||||
machine: machine,
|
||||
targetData: machine.CreateTargetData(),
|
||||
astComments: map[string]*ast.CommentGroup{},
|
||||
@@ -329,12 +329,16 @@ func (c *compilerContext) getLLVMRuntimeType(name string) llvm.Type {
|
||||
// important for named struct types (which should only be created once).
|
||||
func (c *compilerContext) getLLVMType(goType types.Type) llvm.Type {
|
||||
// Try to load the LLVM type from the cache.
|
||||
if t, ok := c.llvmTypes[goType]; ok {
|
||||
return t
|
||||
// Note: *types.Named isn't unique when working with generics.
|
||||
// See https://github.com/golang/go/issues/53914
|
||||
// This is the reason for using typeutil.Map to lookup LLVM types for Go types.
|
||||
ival := c.llvmTypes.At(goType)
|
||||
if ival != nil {
|
||||
return ival.(llvm.Type)
|
||||
}
|
||||
// Not already created, so adding this type to the cache.
|
||||
llvmType := c.makeLLVMType(goType)
|
||||
c.llvmTypes[goType] = llvmType
|
||||
c.llvmTypes.Set(goType, llvmType)
|
||||
return llvmType
|
||||
}
|
||||
|
||||
@@ -389,9 +393,9 @@ func (c *compilerContext) makeLLVMType(goType types.Type) llvm.Type {
|
||||
// in LLVM IR, named structs are implemented as named structs in
|
||||
// LLVM. This is because it is otherwise impossible to create
|
||||
// self-referencing types such as linked lists.
|
||||
llvmName := typ.Obj().Pkg().Path() + "." + typ.Obj().Name()
|
||||
llvmName := typ.String()
|
||||
llvmType := c.ctx.StructCreateNamed(llvmName)
|
||||
c.llvmTypes[goType] = llvmType // avoid infinite recursion
|
||||
c.llvmTypes.Set(goType, llvmType) // avoid infinite recursion
|
||||
underlying := c.getLLVMType(st)
|
||||
llvmType.StructSetBody(underlying.StructElementTypes(), false)
|
||||
return llvmType
|
||||
@@ -782,6 +786,10 @@ func (c *compilerContext) createPackage(irbuilder llvm.Builder, pkg *ssa.Package
|
||||
member := pkg.Members[name]
|
||||
switch member := member.(type) {
|
||||
case *ssa.Function:
|
||||
if member.Synthetic == "generic function" {
|
||||
// Do not try to build generic (non-instantiated) functions.
|
||||
continue
|
||||
}
|
||||
// Create the function definition.
|
||||
b := newBuilder(c, irbuilder, member)
|
||||
if member.Blocks == nil {
|
||||
@@ -1031,9 +1039,17 @@ func (b *builder) createFunctionStart() {
|
||||
b.addError(b.fn.Pos(), errValue)
|
||||
return
|
||||
}
|
||||
|
||||
b.addStandardDefinedAttributes(b.llvmFn)
|
||||
if !b.info.exported {
|
||||
b.llvmFn.SetVisibility(llvm.HiddenVisibility)
|
||||
// Do not set visibility for local linkage (internal or private).
|
||||
// Otherwise a "local linkage requires default visibility"
|
||||
// assertion error in llvm-project/llvm/include/llvm/IR/GlobalValue.h:236
|
||||
// is thrown.
|
||||
if b.llvmFn.Linkage() != llvm.InternalLinkage &&
|
||||
b.llvmFn.Linkage() != llvm.PrivateLinkage {
|
||||
b.llvmFn.SetVisibility(llvm.HiddenVisibility)
|
||||
}
|
||||
b.llvmFn.SetUnnamedAddr(true)
|
||||
}
|
||||
if b.info.section != "" {
|
||||
@@ -1257,6 +1273,7 @@ func (b *builder) createFunction() {
|
||||
// Create anonymous functions (closures etc.).
|
||||
for _, sub := range b.fn.AnonFuncs {
|
||||
b := newBuilder(b.compilerContext, b.Builder, sub)
|
||||
b.llvmFn.SetLinkage(llvm.InternalLinkage)
|
||||
b.createFunction()
|
||||
}
|
||||
}
|
||||
@@ -1541,6 +1558,12 @@ func (b *builder) createBuiltin(argTypes []types.Type, argValues []llvm.Value, c
|
||||
case *types.Pointer:
|
||||
ptrValue := b.CreatePtrToInt(value, b.uintptrType, "")
|
||||
b.createRuntimeCall("printptr", []llvm.Value{ptrValue}, "")
|
||||
case *types.Slice:
|
||||
bufptr := b.CreateExtractValue(value, 0, "")
|
||||
buflen := b.CreateExtractValue(value, 1, "")
|
||||
bufcap := b.CreateExtractValue(value, 2, "")
|
||||
ptrValue := b.CreatePtrToInt(bufptr, b.uintptrType, "")
|
||||
b.createRuntimeCall("printslice", []llvm.Value{ptrValue, buflen, bufcap}, "")
|
||||
default:
|
||||
return llvm.Value{}, b.makeError(pos, "unknown arg type: "+typ.String())
|
||||
}
|
||||
@@ -1571,6 +1594,20 @@ func (b *builder) createBuiltin(argTypes []types.Type, argValues []llvm.Value, c
|
||||
ptr := argValues[0]
|
||||
len := argValues[1]
|
||||
return b.CreateGEP(ptr, []llvm.Value{len}, ""), nil
|
||||
case "Alignof": // unsafe.Alignof
|
||||
align := b.targetData.ABITypeAlignment(argValues[0].Type())
|
||||
return llvm.ConstInt(b.uintptrType, uint64(align), false), nil
|
||||
case "Offsetof": // unsafe.Offsetof
|
||||
// This builtin is a bit harder to implement and may need a bit of
|
||||
// refactoring to work (it may be easier to implement if we have access
|
||||
// to the underlying Go SSA instruction). It is also rarely used: it
|
||||
// only applies in generic code and unsafe.Offsetof isn't very commonly
|
||||
// used anyway.
|
||||
// In other words, postpone it to some other day.
|
||||
return llvm.Value{}, b.makeError(pos, "todo: unsafe.Offsetof")
|
||||
case "Sizeof": // unsafe.Sizeof
|
||||
size := b.targetData.TypeAllocSize(argValues[0].Type())
|
||||
return llvm.ConstInt(b.uintptrType, size, false), nil
|
||||
case "Slice": // unsafe.Slice
|
||||
// This creates a slice from a pointer and a length.
|
||||
// Note that the exception mentioned in the documentation (if the
|
||||
|
||||
@@ -65,6 +65,9 @@ func TestCompiler(t *testing.T) {
|
||||
if goMinor >= 17 {
|
||||
tests = append(tests, testCase{"go1.17.go", "", ""})
|
||||
}
|
||||
if goMinor >= 18 {
|
||||
tests = append(tests, testCase{"generics.go", "", ""})
|
||||
}
|
||||
|
||||
for _, tc := range tests {
|
||||
name := tc.file
|
||||
|
||||
+11
-1
@@ -161,7 +161,17 @@ str x2, [x1, #8]
|
||||
mov x0, #0
|
||||
1:
|
||||
`
|
||||
constraints = "={x0},{x1},~{x1},~{x2},~{x3},~{x4},~{x5},~{x6},~{x7},~{x8},~{x9},~{x10},~{x11},~{x12},~{x13},~{x14},~{x15},~{x16},~{x17},~{x18},~{x19},~{x20},~{x21},~{x22},~{x23},~{x24},~{x25},~{x26},~{x27},~{x28},~{fp},~{lr},~{q0},~{q1},~{q2},~{q3},~{q4},~{q5},~{q6},~{q7},~{q8},~{q9},~{q10},~{q11},~{q12},~{q13},~{q14},~{q15},~{q16},~{q17},~{q18},~{q19},~{q20},~{q21},~{q22},~{q23},~{q24},~{q25},~{q26},~{q27},~{q28},~{q29},~{q30},~{nzcv},~{ffr},~{vg},~{memory}"
|
||||
constraints = "={x0},{x1},~{x1},~{x2},~{x3},~{x4},~{x5},~{x6},~{x7},~{x8},~{x9},~{x10},~{x11},~{x12},~{x13},~{x14},~{x15},~{x16},~{x17},~{x19},~{x20},~{x21},~{x22},~{x23},~{x24},~{x25},~{x26},~{x27},~{x28},~{lr},~{q0},~{q1},~{q2},~{q3},~{q4},~{q5},~{q6},~{q7},~{q8},~{q9},~{q10},~{q11},~{q12},~{q13},~{q14},~{q15},~{q16},~{q17},~{q18},~{q19},~{q20},~{q21},~{q22},~{q23},~{q24},~{q25},~{q26},~{q27},~{q28},~{q29},~{q30},~{nzcv},~{ffr},~{vg},~{memory}"
|
||||
if b.GOOS != "darwin" {
|
||||
// These registers cause the following warning when compiling for
|
||||
// MacOS:
|
||||
// warning: inline asm clobber list contains reserved registers:
|
||||
// X18, FP
|
||||
// Reserved registers on the clobber list may not be preserved
|
||||
// across the asm statement, and clobbering them may lead to
|
||||
// undefined behaviour.
|
||||
constraints += ",~{x18},~{fp}"
|
||||
}
|
||||
// TODO: SVE registers, which we don't use in TinyGo at the moment.
|
||||
case "avr":
|
||||
// Note: the Y register (R28:R29) is a fixed register and therefore
|
||||
|
||||
@@ -277,6 +277,9 @@ func (c *compilerContext) getPointerBitmap(typ llvm.Type, pos token.Pos) *big.In
|
||||
// architecture name ("arm").
|
||||
func (c *compilerContext) archFamily() string {
|
||||
arch := strings.Split(c.Triple, "-")[0]
|
||||
if strings.HasPrefix(arch, "arm64") {
|
||||
return "aarch64"
|
||||
}
|
||||
if strings.HasPrefix(arch, "arm") || strings.HasPrefix(arch, "thumb") {
|
||||
return "arm"
|
||||
}
|
||||
|
||||
Vendored
+1
-1
@@ -196,7 +196,7 @@ entry:
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden void @"main.foo$1"(%main.kv.0* dereferenceable_or_null(1) %b, i8* %context) unnamed_addr #1 {
|
||||
define internal void @"main.foo$1"(%main.kv.0* dereferenceable_or_null(1) %b, i8* %context) unnamed_addr #1 {
|
||||
entry:
|
||||
ret void
|
||||
}
|
||||
|
||||
+3
-3
@@ -115,7 +115,7 @@ declare i8* @llvm.stacksave() #2
|
||||
declare void @runtime.setupDeferFrame(%runtime.deferFrame* dereferenceable_or_null(24), i8*, i8*) #0
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden void @"main.deferSimple$1"(i8* %context) unnamed_addr #1 {
|
||||
define internal void @"main.deferSimple$1"(i8* %context) unnamed_addr #1 {
|
||||
entry:
|
||||
call void @runtime.printint32(i32 3, i8* undef) #3
|
||||
ret void
|
||||
@@ -246,14 +246,14 @@ rundefers.end9: ; preds = %rundefers.loophead1
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden void @"main.deferMultiple$1"(i8* %context) unnamed_addr #1 {
|
||||
define internal void @"main.deferMultiple$1"(i8* %context) unnamed_addr #1 {
|
||||
entry:
|
||||
call void @runtime.printint32(i32 3, i8* undef) #3
|
||||
ret void
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden void @"main.deferMultiple$2"(i8* %context) unnamed_addr #1 {
|
||||
define internal void @"main.deferMultiple$2"(i8* %context) unnamed_addr #1 {
|
||||
entry:
|
||||
call void @runtime.printint32(i32 5, i8* undef) #3
|
||||
ret void
|
||||
|
||||
Vendored
+30
@@ -0,0 +1,30 @@
|
||||
package main
|
||||
|
||||
import "unsafe"
|
||||
|
||||
type Coord interface {
|
||||
int | float32
|
||||
}
|
||||
|
||||
type Point[T Coord] struct {
|
||||
X, Y T
|
||||
}
|
||||
|
||||
func Add[T Coord](a, b Point[T]) Point[T] {
|
||||
checkSize(unsafe.Alignof(a))
|
||||
checkSize(unsafe.Sizeof(a))
|
||||
return Point[T]{
|
||||
X: a.X + b.X,
|
||||
Y: a.Y + b.Y,
|
||||
}
|
||||
}
|
||||
|
||||
func main() {
|
||||
var af, bf Point[float32]
|
||||
Add(af, bf)
|
||||
|
||||
var ai, bi Point[int]
|
||||
Add(ai, bi)
|
||||
}
|
||||
|
||||
func checkSize(uintptr)
|
||||
Vendored
+259
@@ -0,0 +1,259 @@
|
||||
; ModuleID = 'generics.go'
|
||||
source_filename = "generics.go"
|
||||
target datalayout = "e-m:e-p:32:32-p10:8:8-p20:8:8-i64:64-n32:64-S128-ni:1:10:20"
|
||||
target triple = "wasm32-unknown-wasi"
|
||||
|
||||
%"main.Point[int]" = type { i32, i32 }
|
||||
%"main.Point[float32]" = type { float, float }
|
||||
|
||||
declare noalias nonnull i8* @runtime.alloc(i32, i8*, i8*) #0
|
||||
|
||||
declare void @runtime.trackPointer(i8* nocapture readonly, i8*) #0
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden void @main.init(i8* %context) unnamed_addr #1 {
|
||||
entry:
|
||||
ret void
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden void @main.main(i8* %context) unnamed_addr #1 {
|
||||
entry:
|
||||
%bi = alloca %"main.Point[int]", align 8
|
||||
%ai = alloca %"main.Point[int]", align 8
|
||||
%bf = alloca %"main.Point[float32]", align 8
|
||||
%af = alloca %"main.Point[float32]", align 8
|
||||
%af.repack = getelementptr inbounds %"main.Point[float32]", %"main.Point[float32]"* %af, i32 0, i32 0
|
||||
store float 0.000000e+00, float* %af.repack, align 8
|
||||
%af.repack1 = getelementptr inbounds %"main.Point[float32]", %"main.Point[float32]"* %af, i32 0, i32 1
|
||||
store float 0.000000e+00, float* %af.repack1, align 4
|
||||
%0 = bitcast %"main.Point[float32]"* %af to i8*
|
||||
call void @runtime.trackPointer(i8* nonnull %0, i8* undef) #2
|
||||
%bf.repack = getelementptr inbounds %"main.Point[float32]", %"main.Point[float32]"* %bf, i32 0, i32 0
|
||||
store float 0.000000e+00, float* %bf.repack, align 8
|
||||
%bf.repack2 = getelementptr inbounds %"main.Point[float32]", %"main.Point[float32]"* %bf, i32 0, i32 1
|
||||
store float 0.000000e+00, float* %bf.repack2, align 4
|
||||
%1 = bitcast %"main.Point[float32]"* %bf to i8*
|
||||
call void @runtime.trackPointer(i8* nonnull %1, i8* undef) #2
|
||||
%.elt = getelementptr inbounds %"main.Point[float32]", %"main.Point[float32]"* %af, i32 0, i32 0
|
||||
%.unpack = load float, float* %.elt, align 8
|
||||
%.elt3 = getelementptr inbounds %"main.Point[float32]", %"main.Point[float32]"* %af, i32 0, i32 1
|
||||
%.unpack4 = load float, float* %.elt3, align 4
|
||||
%.elt5 = getelementptr inbounds %"main.Point[float32]", %"main.Point[float32]"* %bf, i32 0, i32 0
|
||||
%.unpack6 = load float, float* %.elt5, align 8
|
||||
%.elt7 = getelementptr inbounds %"main.Point[float32]", %"main.Point[float32]"* %bf, i32 0, i32 1
|
||||
%.unpack8 = load float, float* %.elt7, align 4
|
||||
%2 = call %"main.Point[float32]" @"main.Add[float32]"(float %.unpack, float %.unpack4, float %.unpack6, float %.unpack8, i8* undef)
|
||||
%ai.repack = getelementptr inbounds %"main.Point[int]", %"main.Point[int]"* %ai, i32 0, i32 0
|
||||
store i32 0, i32* %ai.repack, align 8
|
||||
%ai.repack9 = getelementptr inbounds %"main.Point[int]", %"main.Point[int]"* %ai, i32 0, i32 1
|
||||
store i32 0, i32* %ai.repack9, align 4
|
||||
%3 = bitcast %"main.Point[int]"* %ai to i8*
|
||||
call void @runtime.trackPointer(i8* nonnull %3, i8* undef) #2
|
||||
%bi.repack = getelementptr inbounds %"main.Point[int]", %"main.Point[int]"* %bi, i32 0, i32 0
|
||||
store i32 0, i32* %bi.repack, align 8
|
||||
%bi.repack10 = getelementptr inbounds %"main.Point[int]", %"main.Point[int]"* %bi, i32 0, i32 1
|
||||
store i32 0, i32* %bi.repack10, align 4
|
||||
%4 = bitcast %"main.Point[int]"* %bi to i8*
|
||||
call void @runtime.trackPointer(i8* nonnull %4, i8* undef) #2
|
||||
%.elt11 = getelementptr inbounds %"main.Point[int]", %"main.Point[int]"* %ai, i32 0, i32 0
|
||||
%.unpack12 = load i32, i32* %.elt11, align 8
|
||||
%.elt13 = getelementptr inbounds %"main.Point[int]", %"main.Point[int]"* %ai, i32 0, i32 1
|
||||
%.unpack14 = load i32, i32* %.elt13, align 4
|
||||
%.elt15 = getelementptr inbounds %"main.Point[int]", %"main.Point[int]"* %bi, i32 0, i32 0
|
||||
%.unpack16 = load i32, i32* %.elt15, align 8
|
||||
%.elt17 = getelementptr inbounds %"main.Point[int]", %"main.Point[int]"* %bi, i32 0, i32 1
|
||||
%.unpack18 = load i32, i32* %.elt17, align 4
|
||||
%5 = call %"main.Point[int]" @"main.Add[int]"(i32 %.unpack12, i32 %.unpack14, i32 %.unpack16, i32 %.unpack18, i8* undef)
|
||||
ret void
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define linkonce_odr hidden %"main.Point[float32]" @"main.Add[float32]"(float %a.X, float %a.Y, float %b.X, float %b.Y, i8* %context) unnamed_addr #1 {
|
||||
entry:
|
||||
%complit = alloca %"main.Point[float32]", align 8
|
||||
%b = alloca %"main.Point[float32]", align 8
|
||||
%a = alloca %"main.Point[float32]", align 8
|
||||
%a.repack = getelementptr inbounds %"main.Point[float32]", %"main.Point[float32]"* %a, i32 0, i32 0
|
||||
store float 0.000000e+00, float* %a.repack, align 8
|
||||
%a.repack9 = getelementptr inbounds %"main.Point[float32]", %"main.Point[float32]"* %a, i32 0, i32 1
|
||||
store float 0.000000e+00, float* %a.repack9, align 4
|
||||
%0 = bitcast %"main.Point[float32]"* %a to i8*
|
||||
call void @runtime.trackPointer(i8* nonnull %0, i8* undef) #2
|
||||
%a.repack10 = getelementptr inbounds %"main.Point[float32]", %"main.Point[float32]"* %a, i32 0, i32 0
|
||||
store float %a.X, float* %a.repack10, align 8
|
||||
%a.repack11 = getelementptr inbounds %"main.Point[float32]", %"main.Point[float32]"* %a, i32 0, i32 1
|
||||
store float %a.Y, float* %a.repack11, align 4
|
||||
%b.repack = getelementptr inbounds %"main.Point[float32]", %"main.Point[float32]"* %b, i32 0, i32 0
|
||||
store float 0.000000e+00, float* %b.repack, align 8
|
||||
%b.repack13 = getelementptr inbounds %"main.Point[float32]", %"main.Point[float32]"* %b, i32 0, i32 1
|
||||
store float 0.000000e+00, float* %b.repack13, align 4
|
||||
%1 = bitcast %"main.Point[float32]"* %b to i8*
|
||||
call void @runtime.trackPointer(i8* nonnull %1, i8* undef) #2
|
||||
%b.repack14 = getelementptr inbounds %"main.Point[float32]", %"main.Point[float32]"* %b, i32 0, i32 0
|
||||
store float %b.X, float* %b.repack14, align 8
|
||||
%b.repack15 = getelementptr inbounds %"main.Point[float32]", %"main.Point[float32]"* %b, i32 0, i32 1
|
||||
store float %b.Y, float* %b.repack15, align 4
|
||||
call void @main.checkSize(i32 4, i8* undef) #2
|
||||
call void @main.checkSize(i32 8, i8* undef) #2
|
||||
%complit.repack = getelementptr inbounds %"main.Point[float32]", %"main.Point[float32]"* %complit, i32 0, i32 0
|
||||
store float 0.000000e+00, float* %complit.repack, align 8
|
||||
%complit.repack17 = getelementptr inbounds %"main.Point[float32]", %"main.Point[float32]"* %complit, i32 0, i32 1
|
||||
store float 0.000000e+00, float* %complit.repack17, align 4
|
||||
%2 = bitcast %"main.Point[float32]"* %complit to i8*
|
||||
call void @runtime.trackPointer(i8* nonnull %2, i8* undef) #2
|
||||
%3 = getelementptr inbounds %"main.Point[float32]", %"main.Point[float32]"* %complit, i32 0, i32 0
|
||||
br i1 false, label %deref.throw, label %deref.next
|
||||
|
||||
deref.next: ; preds = %entry
|
||||
br i1 false, label %deref.throw1, label %deref.next2
|
||||
|
||||
deref.next2: ; preds = %deref.next
|
||||
%4 = getelementptr inbounds %"main.Point[float32]", %"main.Point[float32]"* %b, i32 0, i32 0
|
||||
%5 = getelementptr inbounds %"main.Point[float32]", %"main.Point[float32]"* %a, i32 0, i32 0
|
||||
%6 = load float, float* %5, align 8
|
||||
%7 = load float, float* %4, align 8
|
||||
%8 = fadd float %6, %7
|
||||
br i1 false, label %deref.throw3, label %deref.next4
|
||||
|
||||
deref.next4: ; preds = %deref.next2
|
||||
br i1 false, label %deref.throw5, label %deref.next6
|
||||
|
||||
deref.next6: ; preds = %deref.next4
|
||||
%9 = getelementptr inbounds %"main.Point[float32]", %"main.Point[float32]"* %b, i32 0, i32 1
|
||||
%10 = getelementptr inbounds %"main.Point[float32]", %"main.Point[float32]"* %a, i32 0, i32 1
|
||||
%11 = load float, float* %10, align 4
|
||||
%12 = load float, float* %9, align 4
|
||||
br i1 false, label %store.throw, label %store.next
|
||||
|
||||
store.next: ; preds = %deref.next6
|
||||
store float %8, float* %3, align 8
|
||||
br i1 false, label %store.throw7, label %store.next8
|
||||
|
||||
store.next8: ; preds = %store.next
|
||||
%13 = getelementptr inbounds %"main.Point[float32]", %"main.Point[float32]"* %complit, i32 0, i32 1
|
||||
%14 = fadd float %11, %12
|
||||
store float %14, float* %13, align 4
|
||||
%.elt = getelementptr inbounds %"main.Point[float32]", %"main.Point[float32]"* %complit, i32 0, i32 0
|
||||
%.unpack = load float, float* %.elt, align 8
|
||||
%15 = insertvalue %"main.Point[float32]" undef, float %.unpack, 0
|
||||
%16 = insertvalue %"main.Point[float32]" %15, float %14, 1
|
||||
ret %"main.Point[float32]" %16
|
||||
|
||||
deref.throw: ; preds = %entry
|
||||
unreachable
|
||||
|
||||
deref.throw1: ; preds = %deref.next
|
||||
unreachable
|
||||
|
||||
deref.throw3: ; preds = %deref.next2
|
||||
unreachable
|
||||
|
||||
deref.throw5: ; preds = %deref.next4
|
||||
unreachable
|
||||
|
||||
store.throw: ; preds = %deref.next6
|
||||
unreachable
|
||||
|
||||
store.throw7: ; preds = %store.next
|
||||
unreachable
|
||||
}
|
||||
|
||||
declare void @main.checkSize(i32, i8*) #0
|
||||
|
||||
declare void @runtime.nilPanic(i8*) #0
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define linkonce_odr hidden %"main.Point[int]" @"main.Add[int]"(i32 %a.X, i32 %a.Y, i32 %b.X, i32 %b.Y, i8* %context) unnamed_addr #1 {
|
||||
entry:
|
||||
%complit = alloca %"main.Point[int]", align 8
|
||||
%b = alloca %"main.Point[int]", align 8
|
||||
%a = alloca %"main.Point[int]", align 8
|
||||
%a.repack = getelementptr inbounds %"main.Point[int]", %"main.Point[int]"* %a, i32 0, i32 0
|
||||
store i32 0, i32* %a.repack, align 8
|
||||
%a.repack9 = getelementptr inbounds %"main.Point[int]", %"main.Point[int]"* %a, i32 0, i32 1
|
||||
store i32 0, i32* %a.repack9, align 4
|
||||
%0 = bitcast %"main.Point[int]"* %a to i8*
|
||||
call void @runtime.trackPointer(i8* nonnull %0, i8* undef) #2
|
||||
%a.repack10 = getelementptr inbounds %"main.Point[int]", %"main.Point[int]"* %a, i32 0, i32 0
|
||||
store i32 %a.X, i32* %a.repack10, align 8
|
||||
%a.repack11 = getelementptr inbounds %"main.Point[int]", %"main.Point[int]"* %a, i32 0, i32 1
|
||||
store i32 %a.Y, i32* %a.repack11, align 4
|
||||
%b.repack = getelementptr inbounds %"main.Point[int]", %"main.Point[int]"* %b, i32 0, i32 0
|
||||
store i32 0, i32* %b.repack, align 8
|
||||
%b.repack13 = getelementptr inbounds %"main.Point[int]", %"main.Point[int]"* %b, i32 0, i32 1
|
||||
store i32 0, i32* %b.repack13, align 4
|
||||
%1 = bitcast %"main.Point[int]"* %b to i8*
|
||||
call void @runtime.trackPointer(i8* nonnull %1, i8* undef) #2
|
||||
%b.repack14 = getelementptr inbounds %"main.Point[int]", %"main.Point[int]"* %b, i32 0, i32 0
|
||||
store i32 %b.X, i32* %b.repack14, align 8
|
||||
%b.repack15 = getelementptr inbounds %"main.Point[int]", %"main.Point[int]"* %b, i32 0, i32 1
|
||||
store i32 %b.Y, i32* %b.repack15, align 4
|
||||
call void @main.checkSize(i32 4, i8* undef) #2
|
||||
call void @main.checkSize(i32 8, i8* undef) #2
|
||||
%complit.repack = getelementptr inbounds %"main.Point[int]", %"main.Point[int]"* %complit, i32 0, i32 0
|
||||
store i32 0, i32* %complit.repack, align 8
|
||||
%complit.repack17 = getelementptr inbounds %"main.Point[int]", %"main.Point[int]"* %complit, i32 0, i32 1
|
||||
store i32 0, i32* %complit.repack17, align 4
|
||||
%2 = bitcast %"main.Point[int]"* %complit to i8*
|
||||
call void @runtime.trackPointer(i8* nonnull %2, i8* undef) #2
|
||||
%3 = getelementptr inbounds %"main.Point[int]", %"main.Point[int]"* %complit, i32 0, i32 0
|
||||
br i1 false, label %deref.throw, label %deref.next
|
||||
|
||||
deref.next: ; preds = %entry
|
||||
br i1 false, label %deref.throw1, label %deref.next2
|
||||
|
||||
deref.next2: ; preds = %deref.next
|
||||
%4 = getelementptr inbounds %"main.Point[int]", %"main.Point[int]"* %b, i32 0, i32 0
|
||||
%5 = getelementptr inbounds %"main.Point[int]", %"main.Point[int]"* %a, i32 0, i32 0
|
||||
%6 = load i32, i32* %5, align 8
|
||||
%7 = load i32, i32* %4, align 8
|
||||
%8 = add i32 %6, %7
|
||||
br i1 false, label %deref.throw3, label %deref.next4
|
||||
|
||||
deref.next4: ; preds = %deref.next2
|
||||
br i1 false, label %deref.throw5, label %deref.next6
|
||||
|
||||
deref.next6: ; preds = %deref.next4
|
||||
%9 = getelementptr inbounds %"main.Point[int]", %"main.Point[int]"* %b, i32 0, i32 1
|
||||
%10 = getelementptr inbounds %"main.Point[int]", %"main.Point[int]"* %a, i32 0, i32 1
|
||||
%11 = load i32, i32* %10, align 4
|
||||
%12 = load i32, i32* %9, align 4
|
||||
br i1 false, label %store.throw, label %store.next
|
||||
|
||||
store.next: ; preds = %deref.next6
|
||||
store i32 %8, i32* %3, align 8
|
||||
br i1 false, label %store.throw7, label %store.next8
|
||||
|
||||
store.next8: ; preds = %store.next
|
||||
%13 = getelementptr inbounds %"main.Point[int]", %"main.Point[int]"* %complit, i32 0, i32 1
|
||||
%14 = add i32 %11, %12
|
||||
store i32 %14, i32* %13, align 4
|
||||
%.elt = getelementptr inbounds %"main.Point[int]", %"main.Point[int]"* %complit, i32 0, i32 0
|
||||
%.unpack = load i32, i32* %.elt, align 8
|
||||
%15 = insertvalue %"main.Point[int]" undef, i32 %.unpack, 0
|
||||
%16 = insertvalue %"main.Point[int]" %15, i32 %14, 1
|
||||
ret %"main.Point[int]" %16
|
||||
|
||||
deref.throw: ; preds = %entry
|
||||
unreachable
|
||||
|
||||
deref.throw1: ; preds = %deref.next
|
||||
unreachable
|
||||
|
||||
deref.throw3: ; preds = %deref.next2
|
||||
unreachable
|
||||
|
||||
deref.throw5: ; preds = %deref.next4
|
||||
unreachable
|
||||
|
||||
store.throw: ; preds = %deref.next6
|
||||
unreachable
|
||||
|
||||
store.throw7: ; preds = %store.next
|
||||
unreachable
|
||||
}
|
||||
|
||||
attributes #0 = { "target-features"="+bulk-memory,+nontrapping-fptoint,+sign-ext" }
|
||||
attributes #1 = { nounwind "target-features"="+bulk-memory,+nontrapping-fptoint,+sign-ext" }
|
||||
attributes #2 = { nounwind }
|
||||
+2
-2
@@ -51,7 +51,7 @@ entry:
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden void @"main.inlineFunctionGoroutine$1"(i32 %x, i8* %context) unnamed_addr #1 {
|
||||
define internal void @"main.inlineFunctionGoroutine$1"(i32 %x, i8* %context) unnamed_addr #1 {
|
||||
entry:
|
||||
ret void
|
||||
}
|
||||
@@ -84,7 +84,7 @@ entry:
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden void @"main.closureFunctionGoroutine$1"(i32 %x, i8* %context) unnamed_addr #1 {
|
||||
define internal void @"main.closureFunctionGoroutine$1"(i32 %x, i8* %context) unnamed_addr #1 {
|
||||
entry:
|
||||
%unpack.ptr = bitcast i8* %context to i32*
|
||||
store i32 7, i32* %unpack.ptr, align 4
|
||||
|
||||
+2
-2
@@ -53,7 +53,7 @@ entry:
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden void @"main.inlineFunctionGoroutine$1"(i32 %x, i8* %context) unnamed_addr #1 {
|
||||
define internal void @"main.inlineFunctionGoroutine$1"(i32 %x, i8* %context) unnamed_addr #1 {
|
||||
entry:
|
||||
ret void
|
||||
}
|
||||
@@ -90,7 +90,7 @@ entry:
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden void @"main.closureFunctionGoroutine$1"(i32 %x, i8* %context) unnamed_addr #1 {
|
||||
define internal void @"main.closureFunctionGoroutine$1"(i32 %x, i8* %context) unnamed_addr #1 {
|
||||
entry:
|
||||
%unpack.ptr = bitcast i8* %context to i32*
|
||||
store i32 7, i32* %unpack.ptr, align 4
|
||||
|
||||
+1
-1
@@ -12,7 +12,7 @@ import (
|
||||
|
||||
// Version of TinyGo.
|
||||
// Update this value before release of new version of software.
|
||||
const Version = "0.24.0"
|
||||
const Version = "0.25.0"
|
||||
|
||||
var (
|
||||
// This variable is set at build time using -ldflags parameters.
|
||||
|
||||
@@ -350,16 +350,14 @@ func Flash(pkgName, port string, options *compileopts.Options) error {
|
||||
// do we need port reset to put MCU into bootloader mode?
|
||||
if config.Target.PortReset == "true" && flashMethod != "openocd" {
|
||||
port, err := getDefaultPort(port, config.Target.SerialPort)
|
||||
if err != nil {
|
||||
return err
|
||||
if err == nil {
|
||||
err = touchSerialPortAt1200bps(port)
|
||||
if err != nil {
|
||||
return &commandError{"failed to reset port", result.Binary, err}
|
||||
}
|
||||
// give the target MCU a chance to restart into bootloader
|
||||
time.Sleep(3 * time.Second)
|
||||
}
|
||||
|
||||
err = touchSerialPortAt1200bps(port)
|
||||
if err != nil {
|
||||
return &commandError{"failed to reset port", result.Binary, err}
|
||||
}
|
||||
// give the target MCU a chance to restart into bootloader
|
||||
time.Sleep(3 * time.Second)
|
||||
}
|
||||
|
||||
// this flashing method copies the binary data to a Mass Storage Device (msd)
|
||||
|
||||
@@ -0,0 +1,57 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"machine"
|
||||
"machine/usb/midi"
|
||||
"time"
|
||||
)
|
||||
|
||||
// Try it easily by opening the following site in Chrome.
|
||||
// https://www.onlinemusictools.com/kb/
|
||||
|
||||
func main() {
|
||||
led := machine.LED
|
||||
led.Configure(machine.PinConfig{Mode: machine.PinOutput})
|
||||
|
||||
button := machine.BUTTON
|
||||
button.Configure(machine.PinConfig{Mode: machine.PinInputPullup})
|
||||
|
||||
m := midi.New()
|
||||
m.SetHandler(func(b []byte) {
|
||||
led.Set(!led.Get())
|
||||
fmt.Printf("% X\r\n", b)
|
||||
m.Write(b)
|
||||
})
|
||||
|
||||
prev := true
|
||||
chords := []struct {
|
||||
name string
|
||||
keys []midi.Note
|
||||
}{
|
||||
{name: "C ", keys: []midi.Note{midi.C4, midi.E4, midi.G4}},
|
||||
{name: "G ", keys: []midi.Note{midi.G3, midi.B3, midi.D4}},
|
||||
{name: "Am", keys: []midi.Note{midi.A3, midi.C4, midi.E4}},
|
||||
{name: "F ", keys: []midi.Note{midi.F3, midi.A3, midi.C4}},
|
||||
}
|
||||
index := 0
|
||||
|
||||
for {
|
||||
current := button.Get()
|
||||
if prev != current {
|
||||
led.Set(current)
|
||||
if current {
|
||||
for _, c := range chords[index].keys {
|
||||
m.NoteOff(0, 0, c, 0x40)
|
||||
}
|
||||
index = (index + 1) % len(chords)
|
||||
} else {
|
||||
for _, c := range chords[index].keys {
|
||||
m.NoteOn(0, 0, c, 0x40)
|
||||
}
|
||||
}
|
||||
prev = current
|
||||
}
|
||||
time.Sleep(10 * time.Millisecond)
|
||||
}
|
||||
}
|
||||
@@ -9,9 +9,6 @@ func CPUFrequency() uint32 {
|
||||
}
|
||||
|
||||
const (
|
||||
AREF Pin = NoPin
|
||||
LED Pin = PB7
|
||||
|
||||
A0 Pin = PF0
|
||||
A1 Pin = PF1
|
||||
A2 Pin = PF2
|
||||
@@ -102,4 +99,7 @@ const (
|
||||
D51 Pin = PB2
|
||||
D52 Pin = PB1
|
||||
D53 Pin = PB0
|
||||
|
||||
AREF Pin = NoPin
|
||||
LED Pin = PB7
|
||||
)
|
||||
|
||||
@@ -14,9 +14,6 @@ func CPUFrequency() uint32 {
|
||||
}
|
||||
|
||||
const (
|
||||
AREF Pin = NoPin
|
||||
LED Pin = PB7
|
||||
|
||||
A0 Pin = PF0
|
||||
A1 Pin = PF1
|
||||
A2 Pin = PF2
|
||||
@@ -107,6 +104,9 @@ const (
|
||||
D51 Pin = PB2
|
||||
D52 Pin = PB1
|
||||
D53 Pin = PB0
|
||||
|
||||
AREF Pin = NoPin
|
||||
LED Pin = PB7
|
||||
)
|
||||
|
||||
// UART pins
|
||||
|
||||
@@ -12,9 +12,6 @@ const RESET_MAGIC_VALUE = 0x07738135
|
||||
|
||||
// GPIO Pins
|
||||
const (
|
||||
RX0 Pin = PB23 // UART2 RX
|
||||
TX1 Pin = PB22 // UART2 TX
|
||||
|
||||
D0 Pin = PA22 // PWM available
|
||||
D1 Pin = PA23 // PWM available
|
||||
D2 Pin = PA10 // PWM available
|
||||
@@ -31,6 +28,9 @@ const (
|
||||
D12 Pin = PA09 // PWM available, SCL
|
||||
D13 Pin = PB23 // RX
|
||||
D14 Pin = PB22 // TX
|
||||
|
||||
RX0 Pin = PB23 // UART2 RX
|
||||
TX1 Pin = PB22 // UART2 TX
|
||||
)
|
||||
|
||||
// Analog pins
|
||||
|
||||
@@ -12,9 +12,6 @@ const RESET_MAGIC_VALUE = 0x07738135
|
||||
|
||||
// GPIO Pins
|
||||
const (
|
||||
RX0 Pin = PB23 // UART1 RX
|
||||
TX1 Pin = PB22 // UART1 TX
|
||||
|
||||
D0 Pin = PA22 // PWM available
|
||||
D1 Pin = PA23 // PWM available
|
||||
D2 Pin = PA10 // PWM available
|
||||
@@ -31,6 +28,9 @@ const (
|
||||
D12 Pin = PA09 // PWM available, SCL
|
||||
D13 Pin = PB23 // RX
|
||||
D14 Pin = PB22 // TX
|
||||
|
||||
RX0 Pin = PB23 // UART1 RX
|
||||
TX1 Pin = PB22 // UART1 TX
|
||||
)
|
||||
|
||||
// Analog pins
|
||||
|
||||
@@ -28,14 +28,6 @@ const (
|
||||
D13 = PA17 // PWM available
|
||||
)
|
||||
|
||||
// LEDs on the Arduino Zero
|
||||
const (
|
||||
LED = LED1
|
||||
LED1 Pin = D13
|
||||
LED2 Pin = PA27 // TX LED
|
||||
LED3 Pin = PB03 // RX LED
|
||||
)
|
||||
|
||||
// ADC pins
|
||||
const (
|
||||
AREF Pin = PA03
|
||||
@@ -47,6 +39,14 @@ const (
|
||||
ADC5 Pin = PB02
|
||||
)
|
||||
|
||||
// LEDs on the Arduino Zero
|
||||
const (
|
||||
LED = LED1
|
||||
LED1 Pin = D13
|
||||
LED2 Pin = PA27 // TX LED
|
||||
LED3 Pin = PB03 // RX LED
|
||||
)
|
||||
|
||||
// SPI pins - EDBG connected
|
||||
const (
|
||||
SPI0_SDO_PIN Pin = PA16 // MOSI: SERCOM1/PAD[0]
|
||||
|
||||
@@ -9,6 +9,11 @@
|
||||
//
|
||||
package machine
|
||||
|
||||
import (
|
||||
"device/rp"
|
||||
"runtime/interrupt"
|
||||
)
|
||||
|
||||
const (
|
||||
LED Pin = GPIO25
|
||||
|
||||
@@ -79,3 +84,26 @@ var (
|
||||
usb_VID uint16 = 0x2e8a
|
||||
usb_PID uint16 = 0x0003
|
||||
)
|
||||
|
||||
// UART pins
|
||||
const (
|
||||
UART0_TX_PIN = GPIO0
|
||||
UART0_RX_PIN = GPIO1
|
||||
UART_TX_PIN = UART0_TX_PIN
|
||||
UART_RX_PIN = UART0_RX_PIN
|
||||
)
|
||||
|
||||
// UART on the RP2040
|
||||
var (
|
||||
UART0 = &_UART0
|
||||
_UART0 = UART{
|
||||
Buffer: NewRingBuffer(),
|
||||
Bus: rp.UART0,
|
||||
}
|
||||
)
|
||||
|
||||
var DefaultUART = UART0
|
||||
|
||||
func init() {
|
||||
UART0.Interrupt = interrupt.New(rp.IRQ_UART0_IRQ, _UART0.handleInterrupt)
|
||||
}
|
||||
|
||||
@@ -8,14 +8,42 @@ import (
|
||||
"runtime/interrupt"
|
||||
)
|
||||
|
||||
// Pins printed on the silkscreen
|
||||
const (
|
||||
LED = PC13
|
||||
)
|
||||
|
||||
const (
|
||||
// This board does not have a user button, so
|
||||
// use first GPIO pin by default
|
||||
BUTTON = PA0
|
||||
C13 = PC13
|
||||
C14 = PC14
|
||||
C15 = PC15
|
||||
A0 = PA0
|
||||
A1 = PA1
|
||||
A2 = PA2
|
||||
A3 = PA3
|
||||
A4 = PA4
|
||||
A5 = PA5
|
||||
A6 = PA6
|
||||
A7 = PA7
|
||||
B0 = PB0
|
||||
B1 = PB1
|
||||
B10 = PB10
|
||||
B11 = PB11
|
||||
B12 = PB12
|
||||
B13 = PB13
|
||||
B14 = PB14
|
||||
B15 = PB15
|
||||
A8 = PA8
|
||||
A9 = PA9
|
||||
A10 = PA10
|
||||
A11 = PA11
|
||||
A12 = PA12
|
||||
A13 = PA13
|
||||
A14 = PA14
|
||||
A15 = PA15
|
||||
B3 = PB3
|
||||
B4 = PB4
|
||||
B5 = PB5
|
||||
B6 = PB6
|
||||
B7 = PB7
|
||||
B8 = PB8
|
||||
B9 = PB9
|
||||
)
|
||||
|
||||
// Analog Pins
|
||||
@@ -32,6 +60,14 @@ const (
|
||||
ADC9 = PB1
|
||||
)
|
||||
|
||||
const (
|
||||
// This board does not have a user button, so
|
||||
// use first GPIO pin by default
|
||||
BUTTON = PA0
|
||||
|
||||
LED = PC13
|
||||
)
|
||||
|
||||
var DefaultUART = UART1
|
||||
|
||||
// UART pins
|
||||
|
||||
@@ -0,0 +1,119 @@
|
||||
//go:build challenger_rp2040
|
||||
// +build challenger_rp2040
|
||||
|
||||
package machine
|
||||
|
||||
import (
|
||||
"device/rp"
|
||||
"runtime/interrupt"
|
||||
)
|
||||
|
||||
const (
|
||||
LED = GPIO24
|
||||
|
||||
// Onboard crystal oscillator frequency, in MHz.
|
||||
xoscFreq = 12 // MHz
|
||||
)
|
||||
|
||||
// GPIO Pins
|
||||
const (
|
||||
D5 = GPIO2
|
||||
D6 = GPIO3
|
||||
D9 = GPIO4
|
||||
D10 = GPIO5
|
||||
D11 = GPIO6
|
||||
D12 = GPIO7
|
||||
D13 = GPIO8
|
||||
)
|
||||
|
||||
// Analog pins
|
||||
const (
|
||||
A0 = ADC0
|
||||
A1 = ADC1
|
||||
A2 = ADC2
|
||||
A3 = ADC3
|
||||
)
|
||||
|
||||
// I2C Pins.
|
||||
const (
|
||||
I2C0_SDA_PIN = GPIO24
|
||||
I2C0_SCL_PIN = GPIO25
|
||||
|
||||
I2C1_SDA_PIN = GPIO2
|
||||
I2C1_SCL_PIN = GPIO3
|
||||
|
||||
SDA_PIN = I2C1_SDA_PIN
|
||||
SCL_PIN = I2C1_SCL_PIN
|
||||
)
|
||||
|
||||
// SPI default pins
|
||||
const (
|
||||
// Default Serial Clock Bus 0 for SPI communications
|
||||
SPI0_SCK_PIN = GPIO22
|
||||
// Default Serial Out Bus 0 for SPI communications
|
||||
SPI0_SDO_PIN = GPIO23 // Tx
|
||||
// Default Serial In Bus 0 for SPI communications
|
||||
SPI0_SDI_PIN = GPIO20 // Rx
|
||||
|
||||
// Default Serial Clock Bus 1 for SPI communications
|
||||
SPI1_SCK_PIN = GPIO10
|
||||
// Default Serial Out Bus 1 for SPI communications
|
||||
SPI1_SDO_PIN = GPIO11 // Tx
|
||||
// Default Serial In Bus 1 for SPI communications
|
||||
SPI1_SDI_PIN = GPIO12 // Rx
|
||||
)
|
||||
|
||||
// LoRa default pins
|
||||
const (
|
||||
LORA_CS = GPIO9
|
||||
LORA_SCK = GPIO10
|
||||
LORA_SDO = GPIO11
|
||||
LORA_SDI = GPIO12
|
||||
LORA_RESET = GPIO13
|
||||
LORA_DIO0 = GPIO14
|
||||
LORA_DIO1 = GPIO15
|
||||
LORA_DIO2 = GPIO18
|
||||
)
|
||||
|
||||
// UART pins
|
||||
const (
|
||||
UART0_TX_PIN = GPIO16
|
||||
UART0_RX_PIN = GPIO17
|
||||
UART1_TX_PIN = GPIO4
|
||||
UART1_RX_PIN = GPIO5
|
||||
UART_TX_PIN = UART0_TX_PIN
|
||||
UART_RX_PIN = UART0_RX_PIN
|
||||
)
|
||||
|
||||
// UART on the RP2040
|
||||
var (
|
||||
UART0 = &_UART0
|
||||
_UART0 = UART{
|
||||
Buffer: NewRingBuffer(),
|
||||
Bus: rp.UART0,
|
||||
}
|
||||
|
||||
UART1 = &_UART1
|
||||
_UART1 = UART{
|
||||
Buffer: NewRingBuffer(),
|
||||
Bus: rp.UART1,
|
||||
}
|
||||
)
|
||||
|
||||
var DefaultUART = UART0
|
||||
|
||||
func init() {
|
||||
UART0.Interrupt = interrupt.New(rp.IRQ_UART0_IRQ, _UART0.handleInterrupt)
|
||||
UART1.Interrupt = interrupt.New(rp.IRQ_UART1_IRQ, _UART1.handleInterrupt)
|
||||
}
|
||||
|
||||
// USB identifiers
|
||||
const (
|
||||
usb_STRING_PRODUCT = "Challenger 2040 LoRa"
|
||||
usb_STRING_MANUFACTURER = "iLabs"
|
||||
)
|
||||
|
||||
var (
|
||||
usb_VID uint16 = 0x2e8a
|
||||
usb_PID uint16 = 0x1023
|
||||
)
|
||||
@@ -28,14 +28,6 @@ const (
|
||||
D18 = P0_16
|
||||
D19 = P0_25
|
||||
D20 = P0_24
|
||||
D21 = A0
|
||||
D22 = A1
|
||||
D23 = A2
|
||||
D24 = A3
|
||||
D25 = A4
|
||||
D26 = A5
|
||||
D27 = A6
|
||||
D28 = A7
|
||||
D29 = P0_14
|
||||
D30 = P0_15
|
||||
D31 = P0_12
|
||||
|
||||
@@ -3,50 +3,50 @@
|
||||
|
||||
package machine
|
||||
|
||||
const (
|
||||
CLK = GPIO6
|
||||
CMD = GPIO11
|
||||
IO0 = GPIO0
|
||||
IO1 = GPIO1
|
||||
IO2 = GPIO2
|
||||
IO3 = GPIO3
|
||||
IO4 = GPIO4
|
||||
IO5 = GPIO5
|
||||
IO9 = GPIO9
|
||||
IO10 = GPIO10
|
||||
IO16 = GPIO16
|
||||
IO17 = GPIO17
|
||||
IO18 = GPIO18
|
||||
IO19 = GPIO19
|
||||
IO21 = GPIO21
|
||||
IO22 = GPIO22
|
||||
IO23 = GPIO23
|
||||
IO25 = GPIO25
|
||||
IO26 = GPIO26
|
||||
IO27 = GPIO27
|
||||
IO32 = GPIO32
|
||||
IO33 = GPIO33
|
||||
IO34 = GPIO34
|
||||
IO35 = GPIO35
|
||||
IO36 = GPIO36
|
||||
IO39 = GPIO39
|
||||
RXD = GPIO3
|
||||
SD0 = GPIO7
|
||||
SD1 = GPIO8
|
||||
SD2 = GPIO9
|
||||
SD3 = GPIO10
|
||||
SVN = GPIO39
|
||||
SVP = GPIO36
|
||||
TCK = GPIO13
|
||||
TD0 = GPIO15
|
||||
TDI = GPIO12
|
||||
TMS = GPIO14
|
||||
TXD = GPIO1
|
||||
)
|
||||
|
||||
// Built-in LED on some ESP32 boards.
|
||||
const LED = IO2
|
||||
|
||||
const (
|
||||
CLK Pin = 6
|
||||
CMD Pin = 11
|
||||
IO0 Pin = 0
|
||||
IO1 Pin = 1
|
||||
IO10 Pin = 10
|
||||
IO16 Pin = 16
|
||||
IO17 Pin = 17
|
||||
IO18 Pin = 18
|
||||
IO19 Pin = 19
|
||||
IO2 Pin = 2
|
||||
IO21 Pin = 21
|
||||
IO22 Pin = 22
|
||||
IO23 Pin = 23
|
||||
IO25 Pin = 25
|
||||
IO26 Pin = 26
|
||||
IO27 Pin = 27
|
||||
IO3 Pin = 3
|
||||
IO32 Pin = 32
|
||||
IO33 Pin = 33
|
||||
IO34 Pin = 34
|
||||
IO35 Pin = 35
|
||||
IO36 Pin = 36
|
||||
IO39 Pin = 39
|
||||
IO4 Pin = 4
|
||||
IO5 Pin = 5
|
||||
IO9 Pin = 9
|
||||
RXD Pin = 3
|
||||
SD0 Pin = 7
|
||||
SD1 Pin = 8
|
||||
SD2 Pin = 9
|
||||
SD3 Pin = 10
|
||||
SVN Pin = 39
|
||||
SVP Pin = 36
|
||||
TCK Pin = 13
|
||||
TD0 Pin = 15
|
||||
TDI Pin = 12
|
||||
TMS Pin = 14
|
||||
TXD Pin = 1
|
||||
)
|
||||
|
||||
// SPI pins
|
||||
const (
|
||||
SPI0_SCK_PIN = IO18
|
||||
|
||||
@@ -12,21 +12,21 @@ const (
|
||||
)
|
||||
|
||||
const (
|
||||
IO0 Pin = 0
|
||||
IO1 Pin = 1
|
||||
IO10 Pin = 10
|
||||
IO18 Pin = 18
|
||||
IO19 Pin = 19
|
||||
IO2 Pin = 2
|
||||
IO3 Pin = 3
|
||||
IO4 Pin = 4
|
||||
IO5 Pin = 5
|
||||
IO6 Pin = 6
|
||||
IO7 Pin = 7
|
||||
IO8 Pin = 8
|
||||
IO9 Pin = 9
|
||||
RXD Pin = 20
|
||||
TXD Pin = 21
|
||||
IO0 = GPIO0
|
||||
IO1 = GPIO1
|
||||
IO2 = GPIO2
|
||||
IO3 = GPIO3
|
||||
IO4 = GPIO4
|
||||
IO5 = GPIO5
|
||||
IO6 = GPIO6
|
||||
IO7 = GPIO7
|
||||
IO8 = GPIO8
|
||||
IO9 = GPIO9
|
||||
IO10 = GPIO10
|
||||
IO18 = GPIO18
|
||||
IO19 = GPIO19
|
||||
RXD = GPIO20
|
||||
TXD = GPIO21
|
||||
)
|
||||
|
||||
// ADC pins
|
||||
|
||||
@@ -3,13 +3,14 @@
|
||||
|
||||
package machine
|
||||
|
||||
const (
|
||||
LED = GPIO13
|
||||
|
||||
// Onboard crystal oscillator frequency, in MHz.
|
||||
xoscFreq = 12 // MHz
|
||||
import (
|
||||
"device/rp"
|
||||
"runtime/interrupt"
|
||||
)
|
||||
|
||||
// Onboard crystal oscillator frequency, in MHz.
|
||||
const xoscFreq = 12 // MHz
|
||||
|
||||
// GPIO Pins
|
||||
const (
|
||||
D4 = GPIO6
|
||||
@@ -32,6 +33,8 @@ const (
|
||||
A3 = GPIO29
|
||||
)
|
||||
|
||||
const LED = GPIO13
|
||||
|
||||
// I2C Pins.
|
||||
const (
|
||||
I2C0_SDA_PIN = GPIO24
|
||||
@@ -60,3 +63,46 @@ const (
|
||||
// Default Serial In Bus 1 for SPI communications
|
||||
SPI1_SDI_PIN = GPIO12 // Rx
|
||||
)
|
||||
|
||||
// UART pins
|
||||
const (
|
||||
UART0_TX_PIN = GPIO0
|
||||
UART0_RX_PIN = GPIO1
|
||||
UART1_TX_PIN = GPIO8
|
||||
UART1_RX_PIN = GPIO9
|
||||
UART_TX_PIN = UART0_TX_PIN
|
||||
UART_RX_PIN = UART0_RX_PIN
|
||||
)
|
||||
|
||||
// UART on the RP2040
|
||||
var (
|
||||
UART0 = &_UART0
|
||||
_UART0 = UART{
|
||||
Buffer: NewRingBuffer(),
|
||||
Bus: rp.UART0,
|
||||
}
|
||||
|
||||
UART1 = &_UART1
|
||||
_UART1 = UART{
|
||||
Buffer: NewRingBuffer(),
|
||||
Bus: rp.UART1,
|
||||
}
|
||||
)
|
||||
|
||||
var DefaultUART = UART0
|
||||
|
||||
func init() {
|
||||
UART0.Interrupt = interrupt.New(rp.IRQ_UART0_IRQ, _UART0.handleInterrupt)
|
||||
UART1.Interrupt = interrupt.New(rp.IRQ_UART1_IRQ, _UART1.handleInterrupt)
|
||||
}
|
||||
|
||||
// USB identifiers
|
||||
const (
|
||||
usb_STRING_PRODUCT = "Feather RP2040"
|
||||
usb_STRING_MANUFACTURER = "Adafruit"
|
||||
)
|
||||
|
||||
var (
|
||||
usb_VID uint16 = 0x239A
|
||||
usb_PID uint16 = 0x80F1
|
||||
)
|
||||
|
||||
@@ -20,46 +20,40 @@ const (
|
||||
// HPWR | 5V
|
||||
// HPWR | BATTERY
|
||||
|
||||
IO0 Pin = 0
|
||||
IO1 Pin = 1
|
||||
IO2 Pin = 2
|
||||
IO3 Pin = 3
|
||||
IO4 Pin = 4
|
||||
IO5 Pin = 5
|
||||
IO6 Pin = 6
|
||||
IO7 Pin = 7
|
||||
IO8 Pin = 8
|
||||
IO9 Pin = 9
|
||||
IO10 Pin = 10
|
||||
IO11 Pin = 11
|
||||
IO12 Pin = 12
|
||||
IO13 Pin = 13
|
||||
IO14 Pin = 14
|
||||
IO15 Pin = 15
|
||||
IO16 Pin = 16
|
||||
IO17 Pin = 17
|
||||
IO18 Pin = 18
|
||||
IO19 Pin = 19
|
||||
IO20 Pin = 20
|
||||
IO21 Pin = 21
|
||||
IO22 Pin = 22
|
||||
IO23 Pin = 23
|
||||
IO24 Pin = 24
|
||||
IO25 Pin = 25
|
||||
IO26 Pin = 26
|
||||
IO27 Pin = 27
|
||||
IO28 Pin = 28
|
||||
IO29 Pin = 29
|
||||
IO30 Pin = 30
|
||||
IO31 Pin = 31
|
||||
IO32 Pin = 32
|
||||
IO33 Pin = 33
|
||||
IO34 Pin = 34
|
||||
IO35 Pin = 35
|
||||
IO36 Pin = 36
|
||||
IO37 Pin = 37
|
||||
IO38 Pin = 38
|
||||
IO39 Pin = 39
|
||||
IO0 = GPIO0
|
||||
IO1 = GPIO1
|
||||
IO2 = GPIO2
|
||||
IO3 = GPIO3
|
||||
IO4 = GPIO4
|
||||
IO5 = GPIO5
|
||||
IO6 = GPIO6
|
||||
IO7 = GPIO7
|
||||
IO8 = GPIO8
|
||||
IO9 = GPIO9
|
||||
IO10 = GPIO10
|
||||
IO11 = GPIO11
|
||||
IO12 = GPIO12
|
||||
IO13 = GPIO13
|
||||
IO14 = GPIO14
|
||||
IO15 = GPIO15
|
||||
IO16 = GPIO16
|
||||
IO17 = GPIO17
|
||||
IO18 = GPIO18
|
||||
IO19 = GPIO19
|
||||
IO21 = GPIO21
|
||||
IO22 = GPIO22
|
||||
IO23 = GPIO23
|
||||
IO25 = GPIO25
|
||||
IO26 = GPIO26
|
||||
IO27 = GPIO27
|
||||
IO32 = GPIO32
|
||||
IO33 = GPIO33
|
||||
IO34 = GPIO34
|
||||
IO35 = GPIO35
|
||||
IO36 = GPIO36
|
||||
IO37 = GPIO37
|
||||
IO38 = GPIO38
|
||||
IO39 = GPIO39
|
||||
)
|
||||
|
||||
const (
|
||||
|
||||
@@ -20,39 +20,39 @@ const (
|
||||
// N/C | 5V
|
||||
// N/C | BAT
|
||||
|
||||
IO0 Pin = 0
|
||||
IO1 Pin = 1 // U0TXD
|
||||
IO2 Pin = 2
|
||||
IO3 Pin = 3 // U0RXD
|
||||
IO4 Pin = 4
|
||||
IO5 Pin = 5
|
||||
IO6 Pin = 6 // SD_CLK
|
||||
IO7 Pin = 7 // SD_DATA0
|
||||
IO8 Pin = 8 // SD_DATA1
|
||||
IO9 Pin = 9 // SD_DATA2
|
||||
IO10 Pin = 10 // SD_DATA3
|
||||
IO11 Pin = 11 // SD_CMD
|
||||
IO12 Pin = 12
|
||||
IO13 Pin = 13 // U0RXD
|
||||
IO14 Pin = 14 // U1TXD
|
||||
IO15 Pin = 15
|
||||
IO16 Pin = 16
|
||||
IO17 Pin = 17
|
||||
IO18 Pin = 18 // SPI0_SCK
|
||||
IO19 Pin = 19
|
||||
IO21 Pin = 21 // SDA0
|
||||
IO22 Pin = 22 // SCL0
|
||||
IO23 Pin = 23 // SPI0_SDO
|
||||
IO25 Pin = 25
|
||||
IO26 Pin = 26
|
||||
IO27 Pin = 27
|
||||
IO32 Pin = 32 // SDA1
|
||||
IO33 Pin = 33 // SCL1
|
||||
IO34 Pin = 34
|
||||
IO35 Pin = 35 // ADC1
|
||||
IO36 Pin = 36 // ADC2
|
||||
IO38 Pin = 38 // SPI0_SDI
|
||||
IO39 Pin = 39
|
||||
IO0 = GPIO0
|
||||
IO1 = GPIO1 // U0TXD
|
||||
IO2 = GPIO2
|
||||
IO3 = GPIO3 // U0RXD
|
||||
IO4 = GPIO4
|
||||
IO5 = GPIO5
|
||||
IO6 = GPIO6 // SD_CLK
|
||||
IO7 = GPIO7 // SD_DATA0
|
||||
IO8 = GPIO8 // SD_DATA1
|
||||
IO9 = GPIO9 // SD_DATA2
|
||||
IO10 = GPIO10 // SD_DATA3
|
||||
IO11 = GPIO11 // SD_CMD
|
||||
IO12 = GPIO12
|
||||
IO13 = GPIO13 // U0RXD
|
||||
IO14 = GPIO14 // U1TXD
|
||||
IO15 = GPIO15
|
||||
IO16 = GPIO16
|
||||
IO17 = GPIO17
|
||||
IO18 = GPIO18 // SPI0_SCK
|
||||
IO19 = GPIO19
|
||||
IO21 = GPIO21 // SDA0
|
||||
IO22 = GPIO22 // SCL0
|
||||
IO23 = GPIO23 // SPI0_SDO
|
||||
IO25 = GPIO25
|
||||
IO26 = GPIO26
|
||||
IO27 = GPIO27
|
||||
IO32 = GPIO32 // SDA1
|
||||
IO33 = GPIO33 // SCL1
|
||||
IO34 = GPIO34
|
||||
IO35 = GPIO35 // ADC1
|
||||
IO36 = GPIO36 // ADC2
|
||||
IO38 = GPIO38 // SPI0_SDI
|
||||
IO39 = GPIO39
|
||||
)
|
||||
|
||||
// SPI pins
|
||||
|
||||
@@ -4,28 +4,28 @@
|
||||
package machine
|
||||
|
||||
const (
|
||||
IO0 Pin = 0
|
||||
IO1 Pin = 1
|
||||
IO2 Pin = 2
|
||||
IO3 Pin = 3
|
||||
IO4 Pin = 4
|
||||
IO5 Pin = 5
|
||||
IO6 Pin = 6
|
||||
IO7 Pin = 7
|
||||
IO8 Pin = 8
|
||||
IO9 Pin = 9
|
||||
IO10 Pin = 10
|
||||
IO11 Pin = 11
|
||||
IO12 Pin = 12
|
||||
IO13 Pin = 13
|
||||
IO14 Pin = 14
|
||||
IO15 Pin = 15
|
||||
IO16 Pin = 16
|
||||
IO17 Pin = 17
|
||||
IO18 Pin = 18
|
||||
IO19 Pin = 19
|
||||
IO20 Pin = 20
|
||||
IO21 Pin = 21
|
||||
IO0 = GPIO0
|
||||
IO1 = GPIO1
|
||||
IO2 = GPIO2
|
||||
IO3 = GPIO3
|
||||
IO4 = GPIO4
|
||||
IO5 = GPIO5
|
||||
IO6 = GPIO6
|
||||
IO7 = GPIO7
|
||||
IO8 = GPIO8
|
||||
IO9 = GPIO9
|
||||
IO10 = GPIO10
|
||||
IO11 = GPIO11
|
||||
IO12 = GPIO12
|
||||
IO13 = GPIO13
|
||||
IO14 = GPIO14
|
||||
IO15 = GPIO15
|
||||
IO16 = GPIO16
|
||||
IO17 = GPIO17
|
||||
IO18 = GPIO18
|
||||
IO19 = GPIO19
|
||||
IO20 = GPIO20
|
||||
IO21 = GPIO21
|
||||
|
||||
XTAL_32K_P = IO0
|
||||
XTAL_32K_N = IO1
|
||||
|
||||
@@ -3,6 +3,11 @@
|
||||
|
||||
package machine
|
||||
|
||||
import (
|
||||
"device/rp"
|
||||
"runtime/interrupt"
|
||||
)
|
||||
|
||||
const (
|
||||
NeopixelCount = 12
|
||||
|
||||
@@ -64,3 +69,37 @@ const (
|
||||
SPI0_SDO_PIN = 31 // not pinned out
|
||||
SPI0_SDI_PIN = 31 // not pinned out
|
||||
)
|
||||
|
||||
// UART pins
|
||||
const (
|
||||
UART0_TX_PIN = GPIO0
|
||||
UART0_RX_PIN = GPIO1
|
||||
UART_TX_PIN = UART0_TX_PIN
|
||||
UART_RX_PIN = UART0_RX_PIN
|
||||
)
|
||||
|
||||
// UART on the RP2040
|
||||
var (
|
||||
UART0 = &_UART0
|
||||
_UART0 = UART{
|
||||
Buffer: NewRingBuffer(),
|
||||
Bus: rp.UART0,
|
||||
}
|
||||
)
|
||||
|
||||
var DefaultUART = UART0
|
||||
|
||||
func init() {
|
||||
UART0.Interrupt = interrupt.New(rp.IRQ_UART0_IRQ, _UART0.handleInterrupt)
|
||||
}
|
||||
|
||||
// USB identifiers
|
||||
const (
|
||||
usb_STRING_PRODUCT = "MacroPad RP2040"
|
||||
usb_STRING_MANUFACTURER = "Adafruit"
|
||||
)
|
||||
|
||||
var (
|
||||
usb_VID uint16 = 0x239A
|
||||
usb_PID uint16 = 0x8107
|
||||
)
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
//go:build mch2022
|
||||
// +build mch2022
|
||||
|
||||
package machine
|
||||
|
||||
// See: https://badge.team/docs/badges/mch2022/pinout/
|
||||
|
||||
const (
|
||||
UART_TX_PIN Pin = 1
|
||||
UART_RX_PIN Pin = 3
|
||||
|
||||
WS2812 Pin = 5
|
||||
|
||||
PowerOn Pin = 19 // Set high to enable power to LEDs and SD card
|
||||
|
||||
// I2C pins
|
||||
SDA_PIN Pin = 22
|
||||
SCL_PIN Pin = 21
|
||||
|
||||
// SPI and related pins (ICE40 and LCD).
|
||||
LCD_RESET Pin = 25
|
||||
LCD_MODE Pin = 26
|
||||
LCD_DC Pin = 33
|
||||
SPI0_SCK_PIN Pin = 18
|
||||
SPI0_SDO_PIN Pin = 23
|
||||
SPI0_SDI_PIN Pin = 35 // connected to ICE40
|
||||
SPI0_CS_ICE40_PIN Pin = 27
|
||||
SPI0_CS_LCD_PIN Pin = 32
|
||||
)
|
||||
@@ -6,74 +6,74 @@ package machine
|
||||
// The micro:bit does not have a 32kHz crystal on board.
|
||||
const HasLowFrequencyCrystal = false
|
||||
|
||||
// Buttons on the micro:bit (A and B)
|
||||
var DefaultUART = UART0
|
||||
|
||||
// GPIO/Analog pins
|
||||
const (
|
||||
BUTTON Pin = BUTTONA
|
||||
BUTTONA Pin = 17
|
||||
BUTTONB Pin = 26
|
||||
P0 = P0_03
|
||||
P1 = P0_02
|
||||
P2 = P0_01
|
||||
P3 = P0_04
|
||||
P4 = P0_05
|
||||
P5 = P0_17
|
||||
P6 = P0_12
|
||||
P7 = P0_11
|
||||
P8 = P0_18
|
||||
P9 = P0_10
|
||||
P10 = P0_06
|
||||
P11 = P0_26
|
||||
P12 = P0_20
|
||||
P13 = P0_23
|
||||
P14 = P0_22
|
||||
P15 = P0_21
|
||||
P16 = P0_16
|
||||
)
|
||||
|
||||
var DefaultUART = UART0
|
||||
// Buttons on the micro:bit (A and B)
|
||||
const (
|
||||
BUTTONA = P0_17
|
||||
BUTTONB = P0_26
|
||||
BUTTON = BUTTONA
|
||||
)
|
||||
|
||||
// UART pins
|
||||
const (
|
||||
UART_TX_PIN Pin = 24
|
||||
UART_RX_PIN Pin = 25
|
||||
UART_TX_PIN = P0_24
|
||||
UART_RX_PIN = P0_25
|
||||
)
|
||||
|
||||
// ADC pins
|
||||
const (
|
||||
ADC0 Pin = 3 // P0 on the board
|
||||
ADC1 Pin = 2 // P1 on the board
|
||||
ADC2 Pin = 1 // P2 on the board
|
||||
ADC0 = P0_03 // P0 on the board
|
||||
ADC1 = P0_02 // P1 on the board
|
||||
ADC2 = P0_01 // P2 on the board
|
||||
)
|
||||
|
||||
// I2C pins
|
||||
const (
|
||||
SDA_PIN Pin = 30 // P20 on the board
|
||||
SCL_PIN Pin = 0 // P19 on the board
|
||||
SDA_PIN = P0_30 // P20 on the board
|
||||
SCL_PIN = P0_00 // P19 on the board
|
||||
)
|
||||
|
||||
// SPI pins
|
||||
const (
|
||||
SPI0_SCK_PIN Pin = 23 // P13 on the board
|
||||
SPI0_SDO_PIN Pin = 21 // P15 on the board
|
||||
SPI0_SDI_PIN Pin = 22 // P14 on the board
|
||||
)
|
||||
|
||||
// GPIO/Analog pins
|
||||
const (
|
||||
P0 Pin = 3
|
||||
P1 Pin = 2
|
||||
P2 Pin = 1
|
||||
P3 Pin = 4
|
||||
P4 Pin = 5
|
||||
P5 Pin = 17
|
||||
P6 Pin = 12
|
||||
P7 Pin = 11
|
||||
P8 Pin = 18
|
||||
P9 Pin = 10
|
||||
P10 Pin = 6
|
||||
P11 Pin = 26
|
||||
P12 Pin = 20
|
||||
P13 Pin = 23
|
||||
P14 Pin = 22
|
||||
P15 Pin = 21
|
||||
P16 Pin = 16
|
||||
SPI0_SCK_PIN = P0_23 // P13 on the board
|
||||
SPI0_SDO_PIN = P0_21 // P15 on the board
|
||||
SPI0_SDI_PIN = P0_22 // P14 on the board
|
||||
)
|
||||
|
||||
// LED matrix pins
|
||||
const (
|
||||
LED_COL_1 Pin = 4
|
||||
LED_COL_2 Pin = 5
|
||||
LED_COL_3 Pin = 6
|
||||
LED_COL_4 Pin = 7
|
||||
LED_COL_5 Pin = 8
|
||||
LED_COL_6 Pin = 9
|
||||
LED_COL_7 Pin = 10
|
||||
LED_COL_8 Pin = 11
|
||||
LED_COL_9 Pin = 12
|
||||
LED_ROW_1 Pin = 13
|
||||
LED_ROW_2 Pin = 14
|
||||
LED_ROW_3 Pin = 15
|
||||
LED_COL_1 = P0_04
|
||||
LED_COL_2 = P0_05
|
||||
LED_COL_3 = P0_06
|
||||
LED_COL_4 = P0_07
|
||||
LED_COL_5 = P0_08
|
||||
LED_COL_6 = P0_09
|
||||
LED_COL_7 = P0_10
|
||||
LED_COL_8 = P0_11
|
||||
LED_COL_9 = P0_12
|
||||
LED_ROW_1 = P0_13
|
||||
LED_ROW_2 = P0_14
|
||||
LED_ROW_3 = P0_15
|
||||
)
|
||||
|
||||
@@ -13,6 +13,11 @@
|
||||
//
|
||||
package machine
|
||||
|
||||
import (
|
||||
"device/rp"
|
||||
"runtime/interrupt"
|
||||
)
|
||||
|
||||
// Digital Pins
|
||||
const (
|
||||
D2 Pin = GPIO25
|
||||
@@ -104,3 +109,26 @@ var (
|
||||
usb_VID uint16 = 0x2341
|
||||
usb_PID uint16 = 0x005e
|
||||
)
|
||||
|
||||
// UART pins
|
||||
const (
|
||||
UART0_TX_PIN = GPIO0
|
||||
UART0_RX_PIN = GPIO1
|
||||
UART_TX_PIN = UART0_TX_PIN
|
||||
UART_RX_PIN = UART0_RX_PIN
|
||||
)
|
||||
|
||||
// UART on the RP2040
|
||||
var (
|
||||
UART0 = &_UART0
|
||||
_UART0 = UART{
|
||||
Buffer: NewRingBuffer(),
|
||||
Bus: rp.UART0,
|
||||
}
|
||||
)
|
||||
|
||||
var DefaultUART = UART0
|
||||
|
||||
func init() {
|
||||
UART0.Interrupt = interrupt.New(rp.IRQ_UART0_IRQ, _UART0.handleInterrupt)
|
||||
}
|
||||
|
||||
@@ -7,15 +7,15 @@ package machine
|
||||
|
||||
// GPIO pins on the NodeMCU board.
|
||||
const (
|
||||
D0 Pin = 16
|
||||
D1 Pin = 5
|
||||
D2 Pin = 4
|
||||
D3 Pin = 0
|
||||
D4 Pin = 2
|
||||
D5 Pin = 14
|
||||
D6 Pin = 12
|
||||
D7 Pin = 13
|
||||
D8 Pin = 15
|
||||
D0 = GPIO16
|
||||
D1 = GPIO5
|
||||
D2 = GPIO4
|
||||
D3 = GPIO0
|
||||
D4 = GPIO2
|
||||
D5 = GPIO14
|
||||
D6 = GPIO12
|
||||
D7 = GPIO13
|
||||
D8 = GPIO15
|
||||
)
|
||||
|
||||
// Onboard blue LED (on the AI-Thinker module).
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
//go:build nrf51 || microbit
|
||||
// +build nrf51 microbit
|
||||
|
||||
package machine
|
||||
|
||||
func CPUFrequency() uint32 {
|
||||
return 16000000
|
||||
}
|
||||
|
||||
// Hardware pins
|
||||
const (
|
||||
P0_00 Pin = 0
|
||||
P0_01 Pin = 1
|
||||
P0_02 Pin = 2
|
||||
P0_03 Pin = 3
|
||||
P0_04 Pin = 4
|
||||
P0_05 Pin = 5
|
||||
P0_06 Pin = 6
|
||||
P0_07 Pin = 7
|
||||
P0_08 Pin = 8
|
||||
P0_09 Pin = 9
|
||||
P0_10 Pin = 10
|
||||
P0_11 Pin = 11
|
||||
P0_12 Pin = 12
|
||||
P0_13 Pin = 13
|
||||
P0_14 Pin = 14
|
||||
P0_15 Pin = 15
|
||||
P0_16 Pin = 16
|
||||
P0_17 Pin = 17
|
||||
P0_18 Pin = 18
|
||||
P0_19 Pin = 19
|
||||
P0_20 Pin = 20
|
||||
P0_21 Pin = 21
|
||||
P0_22 Pin = 22
|
||||
P0_23 Pin = 23
|
||||
P0_24 Pin = 24
|
||||
P0_25 Pin = 25
|
||||
P0_26 Pin = 26
|
||||
P0_27 Pin = 27
|
||||
P0_28 Pin = 28
|
||||
P0_29 Pin = 29
|
||||
P0_30 Pin = 30
|
||||
P0_31 Pin = 31
|
||||
)
|
||||
@@ -7,10 +7,10 @@ const HasLowFrequencyCrystal = true
|
||||
|
||||
// LEDs on the nrf52840-mdk (nRF52840 dev board)
|
||||
const (
|
||||
LED Pin = LED_GREEN
|
||||
LED_GREEN Pin = 22
|
||||
LED_RED Pin = 23
|
||||
LED_BLUE Pin = 24
|
||||
LED Pin = LED_GREEN
|
||||
)
|
||||
|
||||
// UART pins
|
||||
|
||||
@@ -8,18 +8,6 @@ import (
|
||||
"runtime/interrupt"
|
||||
)
|
||||
|
||||
const (
|
||||
LED = LED_BUILTIN
|
||||
LED_BUILTIN = LED_GREEN
|
||||
LED_GREEN = PB3
|
||||
)
|
||||
|
||||
const (
|
||||
// This board does not have a user button, so
|
||||
// use first GPIO pin by default
|
||||
BUTTON = PA0
|
||||
)
|
||||
|
||||
const (
|
||||
// Arduino Pins
|
||||
A0 = PA0 // ADC_IN0
|
||||
@@ -45,6 +33,18 @@ const (
|
||||
D13 = PB3 // SPI1_SCK
|
||||
)
|
||||
|
||||
const (
|
||||
LED = LED_BUILTIN
|
||||
LED_BUILTIN = LED_GREEN
|
||||
LED_GREEN = PB3
|
||||
)
|
||||
|
||||
const (
|
||||
// This board does not have a user button, so
|
||||
// use first GPIO pin by default
|
||||
BUTTON = PA0
|
||||
)
|
||||
|
||||
const (
|
||||
// UART pins
|
||||
// PA2 and PA15 are connected to the ST-Link Virtual Com Port (VCP)
|
||||
|
||||
@@ -8,18 +8,6 @@ import (
|
||||
"runtime/interrupt"
|
||||
)
|
||||
|
||||
const (
|
||||
LED = LED_BUILTIN
|
||||
LED_BUILTIN = LED_GREEN
|
||||
LED_GREEN = PB3
|
||||
)
|
||||
|
||||
const (
|
||||
// This board does not have a user button, so
|
||||
// use first GPIO pin by default
|
||||
BUTTON = PA0
|
||||
)
|
||||
|
||||
const (
|
||||
// Arduino Pins
|
||||
A0 = PA0
|
||||
@@ -47,6 +35,18 @@ const (
|
||||
D13 = PB3
|
||||
)
|
||||
|
||||
const (
|
||||
LED = LED_BUILTIN
|
||||
LED_BUILTIN = LED_GREEN
|
||||
LED_GREEN = PB3
|
||||
)
|
||||
|
||||
const (
|
||||
// This board does not have a user button, so
|
||||
// use first GPIO pin by default
|
||||
BUTTON = PA0
|
||||
)
|
||||
|
||||
const (
|
||||
// UART pins
|
||||
// PA2 and PA15 are connected to the ST-Link Virtual Com Port (VCP)
|
||||
|
||||
@@ -9,11 +9,11 @@ import (
|
||||
)
|
||||
|
||||
const (
|
||||
LED = LED_BUILTIN
|
||||
LED_BUILTIN = LED_GREEN
|
||||
LED_GREEN = PC7
|
||||
LED_BLUE = PB7
|
||||
LED_RED = PA9
|
||||
LED_BUILTIN = LED_GREEN
|
||||
LED = LED_BUILTIN
|
||||
)
|
||||
|
||||
const (
|
||||
|
||||
@@ -8,14 +8,6 @@ const HasLowFrequencyCrystal = true
|
||||
// More info: https://docs.particle.io/datasheets/wi-fi/argon-datasheet/
|
||||
// Board diagram: https://docs.particle.io/assets/images/argon/argon-block-diagram.png
|
||||
|
||||
// LEDs
|
||||
const (
|
||||
LED Pin = 44
|
||||
LED_GREEN Pin = 14
|
||||
LED_RED Pin = 13
|
||||
LED_BLUE Pin = 15
|
||||
)
|
||||
|
||||
// GPIOs
|
||||
const (
|
||||
A0 Pin = 3
|
||||
@@ -40,6 +32,14 @@ const (
|
||||
D13 Pin = 47 // Also SCK
|
||||
)
|
||||
|
||||
// LEDs
|
||||
const (
|
||||
LED Pin = 44
|
||||
LED_GREEN Pin = 14
|
||||
LED_RED Pin = 13
|
||||
LED_BLUE Pin = 15
|
||||
)
|
||||
|
||||
// UART
|
||||
var (
|
||||
DefaultUART = UART0
|
||||
|
||||
@@ -8,14 +8,6 @@ const HasLowFrequencyCrystal = true
|
||||
// More info: https://docs.particle.io/datasheets/cellular/boron-datasheet/
|
||||
// Board diagram: https://docs.particle.io/assets/images/boron/boron-block-diagram.png
|
||||
|
||||
// LEDs
|
||||
const (
|
||||
LED Pin = 44
|
||||
LED_GREEN Pin = 14
|
||||
LED_RED Pin = 13
|
||||
LED_BLUE Pin = 15
|
||||
)
|
||||
|
||||
// GPIOs
|
||||
const (
|
||||
A0 Pin = 3
|
||||
@@ -40,6 +32,14 @@ const (
|
||||
D13 Pin = 47 // Also SCK
|
||||
)
|
||||
|
||||
// LEDs
|
||||
const (
|
||||
LED Pin = 44
|
||||
LED_GREEN Pin = 14
|
||||
LED_RED Pin = 13
|
||||
LED_BLUE Pin = 15
|
||||
)
|
||||
|
||||
// UART
|
||||
var (
|
||||
DefaultUART = UART0
|
||||
|
||||
@@ -8,14 +8,6 @@ const HasLowFrequencyCrystal = true
|
||||
// More info: https://docs.particle.io/datasheets/discontinued/xenon-datasheet/
|
||||
// Board diagram: https://docs.particle.io/assets/images/xenon/xenon-block-diagram.png
|
||||
|
||||
// LEDs
|
||||
const (
|
||||
LED Pin = 44
|
||||
LED_GREEN Pin = 14
|
||||
LED_RED Pin = 13
|
||||
LED_BLUE Pin = 15
|
||||
)
|
||||
|
||||
// GPIOs
|
||||
const (
|
||||
A0 Pin = 3
|
||||
@@ -40,6 +32,14 @@ const (
|
||||
D13 Pin = 47 // Also SCK
|
||||
)
|
||||
|
||||
// LEDs
|
||||
const (
|
||||
LED Pin = 44
|
||||
LED_GREEN Pin = 14
|
||||
LED_RED Pin = 13
|
||||
LED_BLUE Pin = 15
|
||||
)
|
||||
|
||||
// UART
|
||||
var (
|
||||
DefaultUART = UART0
|
||||
|
||||
@@ -11,21 +11,21 @@ const HasLowFrequencyCrystal = true
|
||||
|
||||
// LED on the pca10031
|
||||
const (
|
||||
LED Pin = LED_RED
|
||||
LED1 Pin = LED_RED
|
||||
LED2 Pin = LED_GREEN
|
||||
LED3 Pin = LED_BLUE
|
||||
LED_RED Pin = 21
|
||||
LED_GREEN Pin = 22
|
||||
LED_BLUE Pin = 23
|
||||
LED1 = LED_RED
|
||||
LED2 = LED_GREEN
|
||||
LED3 = LED_BLUE
|
||||
LED_RED = P0_21
|
||||
LED_GREEN = P0_22
|
||||
LED_BLUE = P0_23
|
||||
LED = LED_RED
|
||||
)
|
||||
|
||||
var DefaultUART = UART0
|
||||
|
||||
// UART pins
|
||||
const (
|
||||
UART_TX_PIN Pin = 9
|
||||
UART_RX_PIN Pin = 11
|
||||
UART_TX_PIN = P0_09
|
||||
UART_RX_PIN = P0_11
|
||||
)
|
||||
|
||||
// I2C pins (disabled)
|
||||
|
||||
@@ -8,20 +8,20 @@ const HasLowFrequencyCrystal = true
|
||||
|
||||
// LEDs on the PCA10040 (nRF52832 dev board)
|
||||
const (
|
||||
LED Pin = LED1
|
||||
LED1 Pin = 17
|
||||
LED2 Pin = 18
|
||||
LED3 Pin = 19
|
||||
LED4 Pin = 20
|
||||
LED Pin = LED1
|
||||
)
|
||||
|
||||
// Buttons on the PCA10040 (nRF52832 dev board)
|
||||
const (
|
||||
BUTTON Pin = BUTTON1
|
||||
BUTTON1 Pin = 13
|
||||
BUTTON2 Pin = 14
|
||||
BUTTON3 Pin = 15
|
||||
BUTTON4 Pin = 16
|
||||
BUTTON Pin = BUTTON1
|
||||
)
|
||||
|
||||
var DefaultUART = UART0
|
||||
|
||||
@@ -7,20 +7,20 @@ const HasLowFrequencyCrystal = true
|
||||
|
||||
// LEDs on the pca10056
|
||||
const (
|
||||
LED Pin = LED1
|
||||
LED1 Pin = 13
|
||||
LED2 Pin = 14
|
||||
LED3 Pin = 15
|
||||
LED4 Pin = 16
|
||||
LED Pin = LED1
|
||||
)
|
||||
|
||||
// Buttons on the pca10056
|
||||
const (
|
||||
BUTTON Pin = BUTTON1
|
||||
BUTTON1 Pin = 11
|
||||
BUTTON2 Pin = 12
|
||||
BUTTON3 Pin = 24
|
||||
BUTTON4 Pin = 25
|
||||
BUTTON Pin = BUTTON1
|
||||
)
|
||||
|
||||
var DefaultUART = UART0
|
||||
|
||||
@@ -8,17 +8,17 @@ const HasLowFrequencyCrystal = true
|
||||
|
||||
// LEDs on the PCA10059 (nRF52840 dongle)
|
||||
const (
|
||||
LED Pin = LED1
|
||||
LED1 Pin = 6
|
||||
LED2 Pin = 8
|
||||
LED3 Pin = (1 << 5) | 9
|
||||
LED4 Pin = 12
|
||||
LED Pin = LED1
|
||||
)
|
||||
|
||||
// Buttons on the PCA10059 (nRF52840 dongle)
|
||||
const (
|
||||
BUTTON Pin = BUTTON1
|
||||
BUTTON1 Pin = (1 << 5) | 6
|
||||
BUTTON Pin = BUTTON1
|
||||
)
|
||||
|
||||
// ADC pins
|
||||
|
||||
@@ -3,6 +3,11 @@
|
||||
|
||||
package machine
|
||||
|
||||
import (
|
||||
"device/rp"
|
||||
"runtime/interrupt"
|
||||
)
|
||||
|
||||
// GPIO pins
|
||||
const (
|
||||
GP0 Pin = GPIO0
|
||||
@@ -64,3 +69,46 @@ const (
|
||||
// Default Serial In Bus 1 for SPI communications
|
||||
SPI1_SDI_PIN = GPIO12 // Rx
|
||||
)
|
||||
|
||||
// UART pins
|
||||
const (
|
||||
UART0_TX_PIN = GPIO0
|
||||
UART0_RX_PIN = GPIO1
|
||||
UART1_TX_PIN = GPIO8
|
||||
UART1_RX_PIN = GPIO9
|
||||
UART_TX_PIN = UART0_TX_PIN
|
||||
UART_RX_PIN = UART0_RX_PIN
|
||||
)
|
||||
|
||||
// UART on the RP2040
|
||||
var (
|
||||
UART0 = &_UART0
|
||||
_UART0 = UART{
|
||||
Buffer: NewRingBuffer(),
|
||||
Bus: rp.UART0,
|
||||
}
|
||||
|
||||
UART1 = &_UART1
|
||||
_UART1 = UART{
|
||||
Buffer: NewRingBuffer(),
|
||||
Bus: rp.UART1,
|
||||
}
|
||||
)
|
||||
|
||||
var DefaultUART = UART0
|
||||
|
||||
func init() {
|
||||
UART0.Interrupt = interrupt.New(rp.IRQ_UART0_IRQ, _UART0.handleInterrupt)
|
||||
UART1.Interrupt = interrupt.New(rp.IRQ_UART1_IRQ, _UART1.handleInterrupt)
|
||||
}
|
||||
|
||||
// USB identifiers
|
||||
const (
|
||||
usb_STRING_PRODUCT = "Pico"
|
||||
usb_STRING_MANUFACTURER = "Raspberry Pi"
|
||||
)
|
||||
|
||||
var (
|
||||
usb_VID uint16 = 0x2E8A
|
||||
usb_PID uint16 = 0x000A
|
||||
)
|
||||
|
||||
@@ -12,10 +12,10 @@ const HasLowFrequencyCrystal = true
|
||||
// LEDs simply expose the three brightness level LEDs on the PineTime. They can
|
||||
// be useful for simple "hello world" style programs.
|
||||
const (
|
||||
LED = LED1
|
||||
LED1 = LCD_BACKLIGHT_HIGH
|
||||
LED2 = LCD_BACKLIGHT_MID
|
||||
LED3 = LCD_BACKLIGHT_LOW
|
||||
LED = LED1
|
||||
)
|
||||
|
||||
var DefaultUART = UART0
|
||||
|
||||
@@ -7,15 +7,15 @@ const HasLowFrequencyCrystal = true
|
||||
|
||||
// Pins on the reel board
|
||||
const (
|
||||
LED Pin = LED1
|
||||
LED1 Pin = LED_YELLOW
|
||||
LED2 Pin = LED_RED
|
||||
LED3 Pin = LED_GREEN
|
||||
LED4 Pin = LED_BLUE
|
||||
LED_RED Pin = 11
|
||||
LED_GREEN Pin = 12
|
||||
LED_BLUE Pin = 41
|
||||
LED_YELLOW Pin = 13
|
||||
LED1 Pin = LED_YELLOW
|
||||
LED2 Pin = LED_RED
|
||||
LED3 Pin = LED_GREEN
|
||||
LED4 Pin = LED_BLUE
|
||||
LED Pin = LED1
|
||||
EPD_BUSY_PIN Pin = 14
|
||||
EPD_RESET_PIN Pin = 15
|
||||
EPD_DC_PIN Pin = 16
|
||||
|
||||
@@ -9,16 +9,16 @@ import (
|
||||
)
|
||||
|
||||
const (
|
||||
LED = LED_BUILTIN
|
||||
LED1 = LED_GREEN
|
||||
LED2 = LED_ORANGE
|
||||
LED3 = LED_RED
|
||||
LED4 = LED_BLUE
|
||||
LED_BUILTIN = LED_GREEN
|
||||
LED_GREEN = PD12
|
||||
LED_ORANGE = PD13
|
||||
LED_RED = PD14
|
||||
LED_BLUE = PD15
|
||||
LED = LED_BUILTIN
|
||||
LED_BUILTIN = LED_GREEN
|
||||
)
|
||||
|
||||
const (
|
||||
|
||||
@@ -9,9 +9,6 @@ func CPUFrequency() uint32 { return 180000000 }
|
||||
// ClockFrequency returns the frequency of the external oscillator (16MHz)
|
||||
func ClockFrequency() uint32 { return 16000000 }
|
||||
|
||||
// LED on the Teensy
|
||||
const LED = PC05
|
||||
|
||||
// digital IO
|
||||
const (
|
||||
D00 = PB16
|
||||
@@ -80,6 +77,9 @@ const (
|
||||
D63 = PE05
|
||||
)
|
||||
|
||||
// LED on the Teensy
|
||||
const LED = PC05
|
||||
|
||||
var (
|
||||
TeensyUART1 = UART0
|
||||
TeensyUART2 = UART1
|
||||
|
||||
@@ -3,13 +3,14 @@
|
||||
|
||||
package machine
|
||||
|
||||
const (
|
||||
LED = GPIO25
|
||||
|
||||
// Onboard crystal oscillator frequency, in MHz.
|
||||
xoscFreq = 12 // MHz
|
||||
import (
|
||||
"device/rp"
|
||||
"runtime/interrupt"
|
||||
)
|
||||
|
||||
// Onboard crystal oscillator frequency, in MHz.
|
||||
const xoscFreq = 12 // MHz
|
||||
|
||||
// GPIO Pins
|
||||
const (
|
||||
GP0 Pin = GPIO0 // TX
|
||||
@@ -51,6 +52,8 @@ const (
|
||||
A3 = GPIO29
|
||||
)
|
||||
|
||||
const LED = GPIO25
|
||||
|
||||
// I2C Pins.
|
||||
const (
|
||||
I2C0_SCL_PIN = GPIO6 // N/A
|
||||
@@ -79,3 +82,37 @@ const (
|
||||
// Default Serial In Bus 1 for SPI communications to muSDcard
|
||||
SPI1_SDI_PIN = GPIO12 // Rx
|
||||
)
|
||||
|
||||
// UART pins
|
||||
const (
|
||||
UART0_TX_PIN = GPIO0
|
||||
UART0_RX_PIN = GPIO1
|
||||
UART_TX_PIN = UART0_TX_PIN
|
||||
UART_RX_PIN = UART0_RX_PIN
|
||||
)
|
||||
|
||||
// UART on the RP2040
|
||||
var (
|
||||
UART0 = &_UART0
|
||||
_UART0 = UART{
|
||||
Buffer: NewRingBuffer(),
|
||||
Bus: rp.UART0,
|
||||
}
|
||||
)
|
||||
|
||||
var DefaultUART = UART0
|
||||
|
||||
func init() {
|
||||
UART0.Interrupt = interrupt.New(rp.IRQ_UART0_IRQ, _UART0.handleInterrupt)
|
||||
}
|
||||
|
||||
// USB identifiers
|
||||
const (
|
||||
usb_STRING_PRODUCT = "Thing Plus RP2040"
|
||||
usb_STRING_MANUFACTURER = "SparkFun"
|
||||
)
|
||||
|
||||
var (
|
||||
usb_VID uint16 = 0x1B4F
|
||||
usb_PID uint16 = 0x0026
|
||||
)
|
||||
|
||||
@@ -0,0 +1,107 @@
|
||||
//go:build xiao_rp2040
|
||||
// +build xiao_rp2040
|
||||
|
||||
// This file contains the pin mappings for the Seeed XIAO RP2040 boards.
|
||||
//
|
||||
// XIAO RP2040 is a microcontroller using the Raspberry Pi RP2040 chip.
|
||||
//
|
||||
// - https://wiki.seeedstudio.com/XIAO-RP2040/
|
||||
//
|
||||
package machine
|
||||
|
||||
import (
|
||||
"device/rp"
|
||||
"runtime/interrupt"
|
||||
)
|
||||
|
||||
// Digital Pins
|
||||
const (
|
||||
D0 Pin = GPIO26
|
||||
D1 Pin = GPIO27
|
||||
D2 Pin = GPIO28
|
||||
D3 Pin = GPIO29
|
||||
D4 Pin = GPIO6
|
||||
D5 Pin = GPIO7
|
||||
D6 Pin = GPIO0
|
||||
D7 Pin = GPIO1
|
||||
D8 Pin = GPIO2
|
||||
D9 Pin = GPIO3
|
||||
D10 Pin = GPIO4
|
||||
)
|
||||
|
||||
// Analog pins
|
||||
const (
|
||||
A0 Pin = D0
|
||||
A1 Pin = D1
|
||||
A2 Pin = D2
|
||||
A3 Pin = D3
|
||||
)
|
||||
|
||||
// Onboard LEDs
|
||||
const (
|
||||
NEOPIXEL = GPIO12
|
||||
|
||||
LED = GPIO17
|
||||
LED_RED = GPIO17
|
||||
LED_GREEN = GPIO16
|
||||
LED_BLUE = GPIO25
|
||||
)
|
||||
|
||||
// I2C pins
|
||||
const (
|
||||
I2C0_SDA_PIN Pin = D4
|
||||
I2C0_SCL_PIN Pin = D5
|
||||
|
||||
I2C1_SDA_PIN Pin = NoPin
|
||||
I2C1_SCL_PIN Pin = NoPin
|
||||
)
|
||||
|
||||
// SPI pins
|
||||
const (
|
||||
SPI0_SCK_PIN Pin = D8
|
||||
SPI0_SDO_PIN Pin = D9
|
||||
SPI0_SDI_PIN Pin = D10
|
||||
|
||||
SPI1_SCK_PIN Pin = NoPin
|
||||
SPI1_SDO_PIN Pin = NoPin
|
||||
SPI1_SDI_PIN Pin = NoPin
|
||||
)
|
||||
|
||||
// Onboard crystal oscillator frequency, in MHz.
|
||||
const (
|
||||
xoscFreq = 12 // MHz
|
||||
)
|
||||
|
||||
// UART pins
|
||||
const (
|
||||
UART0_TX_PIN = GPIO0
|
||||
UART0_RX_PIN = GPIO1
|
||||
UART_TX_PIN = UART0_TX_PIN
|
||||
UART_RX_PIN = UART0_RX_PIN
|
||||
)
|
||||
|
||||
// UART on the RP2040
|
||||
var (
|
||||
UART0 = &_UART0
|
||||
_UART0 = UART{
|
||||
Buffer: NewRingBuffer(),
|
||||
Bus: rp.UART0,
|
||||
}
|
||||
)
|
||||
|
||||
var DefaultUART = UART0
|
||||
|
||||
func init() {
|
||||
UART0.Interrupt = interrupt.New(rp.IRQ_UART0_IRQ, _UART0.handleInterrupt)
|
||||
}
|
||||
|
||||
// USB CDC identifiers
|
||||
const (
|
||||
usb_STRING_PRODUCT = "XIAO RP2040"
|
||||
usb_STRING_MANUFACTURER = "Seeed"
|
||||
)
|
||||
|
||||
var (
|
||||
usb_VID uint16 = 0x2e8a
|
||||
usb_PID uint16 = 0x000a
|
||||
)
|
||||
@@ -85,10 +85,10 @@ const (
|
||||
PK1 = portK + 1
|
||||
PK2 = portK + 2
|
||||
PK3 = portK + 3
|
||||
PK4 = portH + 4
|
||||
PK5 = portH + 5
|
||||
PK6 = portH + 6
|
||||
PK7 = portH + 7
|
||||
PK4 = portK + 4
|
||||
PK5 = portK + 5
|
||||
PK6 = portK + 6
|
||||
PK7 = portK + 7
|
||||
PL0 = portL + 0
|
||||
PL1 = portL + 1
|
||||
PL2 = portL + 2
|
||||
|
||||
@@ -87,10 +87,10 @@ const (
|
||||
PK1 = portK + 1
|
||||
PK2 = portK + 2
|
||||
PK3 = portK + 3
|
||||
PK4 = portH + 4
|
||||
PK5 = portH + 5
|
||||
PK6 = portH + 6
|
||||
PK7 = portH + 7
|
||||
PK4 = portK + 4
|
||||
PK5 = portK + 5
|
||||
PK6 = portK + 6
|
||||
PK7 = portK + 7
|
||||
PL0 = portL + 0
|
||||
PL1 = portL + 1
|
||||
PL2 = portL + 2
|
||||
|
||||
@@ -13,7 +13,6 @@ import (
|
||||
"device/sam"
|
||||
"errors"
|
||||
"runtime/interrupt"
|
||||
"runtime/volatile"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
@@ -1735,929 +1734,9 @@ func (tcc *TCC) Set(channel uint8, value uint32) {
|
||||
}
|
||||
}
|
||||
|
||||
// USBCDC is the USB CDC aka serial over USB interface on the SAMD21.
|
||||
type USBCDC struct {
|
||||
Buffer *RingBuffer
|
||||
TxIdx volatile.Register8
|
||||
waitTxc bool
|
||||
waitTxcRetryCount uint8
|
||||
sent bool
|
||||
configured bool
|
||||
}
|
||||
|
||||
var (
|
||||
USB = &USBCDC{Buffer: NewRingBuffer()}
|
||||
waitHidTxc bool
|
||||
)
|
||||
|
||||
const (
|
||||
usbcdcTxSizeMask uint8 = 0x3F
|
||||
usbcdcTxBankMask uint8 = ^usbcdcTxSizeMask
|
||||
usbcdcTxBank1st uint8 = 0x00
|
||||
usbcdcTxBank2nd uint8 = usbcdcTxSizeMask + 1
|
||||
usbcdcTxMaxRetriesAllowed uint8 = 5
|
||||
)
|
||||
|
||||
// Flush flushes buffered data.
|
||||
func (usbcdc *USBCDC) Flush() error {
|
||||
if usbLineInfo.lineState > 0 {
|
||||
idx := usbcdc.TxIdx.Get()
|
||||
sz := idx & usbcdcTxSizeMask
|
||||
bk := idx & usbcdcTxBankMask
|
||||
if 0 < sz {
|
||||
|
||||
if usbcdc.waitTxc {
|
||||
// waiting for the next flush(), because the transmission is not complete
|
||||
usbcdc.waitTxcRetryCount++
|
||||
return nil
|
||||
}
|
||||
usbcdc.waitTxc = true
|
||||
usbcdc.waitTxcRetryCount = 0
|
||||
|
||||
// set the data
|
||||
usbEndpointDescriptors[usb_CDC_ENDPOINT_IN].DeviceDescBank[1].ADDR.Set(uint32(uintptr(unsafe.Pointer(&udd_ep_in_cache_buffer[usb_CDC_ENDPOINT_IN][bk]))))
|
||||
if bk == usbcdcTxBank1st {
|
||||
usbcdc.TxIdx.Set(usbcdcTxBank2nd)
|
||||
} else {
|
||||
usbcdc.TxIdx.Set(usbcdcTxBank1st)
|
||||
}
|
||||
|
||||
// clean multi packet size of bytes already sent
|
||||
usbEndpointDescriptors[usb_CDC_ENDPOINT_IN].DeviceDescBank[1].PCKSIZE.ClearBits(usb_DEVICE_PCKSIZE_MULTI_PACKET_SIZE_Mask << usb_DEVICE_PCKSIZE_MULTI_PACKET_SIZE_Pos)
|
||||
|
||||
// set count of bytes to be sent
|
||||
usbEndpointDescriptors[usb_CDC_ENDPOINT_IN].DeviceDescBank[1].PCKSIZE.ClearBits(usb_DEVICE_PCKSIZE_BYTE_COUNT_Mask << usb_DEVICE_PCKSIZE_BYTE_COUNT_Pos)
|
||||
usbEndpointDescriptors[usb_CDC_ENDPOINT_IN].DeviceDescBank[1].PCKSIZE.SetBits((uint32(sz) & usb_DEVICE_PCKSIZE_BYTE_COUNT_Mask) << usb_DEVICE_PCKSIZE_BYTE_COUNT_Pos)
|
||||
|
||||
// clear transfer complete flag
|
||||
setEPINTFLAG(usb_CDC_ENDPOINT_IN, sam.USB_DEVICE_EPINTFLAG_TRCPT1)
|
||||
|
||||
// send data by setting bank ready
|
||||
setEPSTATUSSET(usb_CDC_ENDPOINT_IN, sam.USB_DEVICE_EPSTATUSSET_BK1RDY)
|
||||
usbcdc.sent = true
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// WriteByte writes a byte of data to the USB CDC interface.
|
||||
func (usbcdc *USBCDC) WriteByte(c byte) error {
|
||||
// Supposedly to handle problem with Windows USB serial ports?
|
||||
if usbLineInfo.lineState > 0 {
|
||||
ok := false
|
||||
for {
|
||||
mask := interrupt.Disable()
|
||||
|
||||
idx := usbcdc.TxIdx.Get()
|
||||
if (idx & usbcdcTxSizeMask) < usbcdcTxSizeMask {
|
||||
udd_ep_in_cache_buffer[usb_CDC_ENDPOINT_IN][idx] = c
|
||||
usbcdc.TxIdx.Set(idx + 1)
|
||||
ok = true
|
||||
}
|
||||
|
||||
interrupt.Restore(mask)
|
||||
|
||||
if ok {
|
||||
break
|
||||
} else if usbcdcTxMaxRetriesAllowed < usbcdc.waitTxcRetryCount {
|
||||
mask := interrupt.Disable()
|
||||
usbcdc.waitTxc = false
|
||||
usbcdc.waitTxcRetryCount = 0
|
||||
usbcdc.TxIdx.Set(0)
|
||||
usbLineInfo.lineState = 0
|
||||
interrupt.Restore(mask)
|
||||
break
|
||||
} else {
|
||||
mask := interrupt.Disable()
|
||||
if usbcdc.sent {
|
||||
if usbcdc.waitTxc {
|
||||
if (getEPINTFLAG(usb_CDC_ENDPOINT_IN) & sam.USB_DEVICE_EPINTFLAG_TRCPT1) != 0 {
|
||||
setEPSTATUSCLR(usb_CDC_ENDPOINT_IN, sam.USB_DEVICE_EPSTATUSCLR_BK1RDY)
|
||||
setEPINTFLAG(usb_CDC_ENDPOINT_IN, sam.USB_DEVICE_EPINTFLAG_TRCPT1)
|
||||
usbcdc.waitTxc = false
|
||||
usbcdc.Flush()
|
||||
}
|
||||
} else {
|
||||
usbcdc.Flush()
|
||||
}
|
||||
}
|
||||
interrupt.Restore(mask)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (usbcdc *USBCDC) DTR() bool {
|
||||
return (usbLineInfo.lineState & usb_CDC_LINESTATE_DTR) > 0
|
||||
}
|
||||
|
||||
func (usbcdc *USBCDC) RTS() bool {
|
||||
return (usbLineInfo.lineState & usb_CDC_LINESTATE_RTS) > 0
|
||||
}
|
||||
|
||||
const (
|
||||
// these are SAMD21 specific.
|
||||
usb_DEVICE_PCKSIZE_BYTE_COUNT_Pos = 0
|
||||
usb_DEVICE_PCKSIZE_BYTE_COUNT_Mask = 0x3FFF
|
||||
|
||||
usb_DEVICE_PCKSIZE_SIZE_Pos = 28
|
||||
usb_DEVICE_PCKSIZE_SIZE_Mask = 0x7
|
||||
|
||||
usb_DEVICE_PCKSIZE_MULTI_PACKET_SIZE_Pos = 14
|
||||
usb_DEVICE_PCKSIZE_MULTI_PACKET_SIZE_Mask = 0x3FFF
|
||||
)
|
||||
|
||||
var (
|
||||
usbEndpointDescriptors [8]usbDeviceDescriptor
|
||||
|
||||
udd_ep_in_cache_buffer [7][128]uint8
|
||||
udd_ep_out_cache_buffer [7][128]uint8
|
||||
|
||||
isEndpointHalt = false
|
||||
isRemoteWakeUpEnabled = false
|
||||
endPoints = []uint32{usb_ENDPOINT_TYPE_CONTROL,
|
||||
(usb_ENDPOINT_TYPE_INTERRUPT | usbEndpointIn),
|
||||
(usb_ENDPOINT_TYPE_BULK | usbEndpointOut),
|
||||
(usb_ENDPOINT_TYPE_BULK | usbEndpointIn)}
|
||||
|
||||
usbConfiguration uint8
|
||||
usbSetInterface uint8
|
||||
usbLineInfo = cdcLineInfo{115200, 0x00, 0x00, 0x08, 0x00}
|
||||
)
|
||||
|
||||
// Configure the USB CDC interface. The config is here for compatibility with the UART interface.
|
||||
func (usbcdc *USBCDC) Configure(config UARTConfig) {
|
||||
// reset USB interface
|
||||
sam.USB_DEVICE.CTRLA.SetBits(sam.USB_DEVICE_CTRLA_SWRST)
|
||||
for sam.USB_DEVICE.SYNCBUSY.HasBits(sam.USB_DEVICE_SYNCBUSY_SWRST) ||
|
||||
sam.USB_DEVICE.SYNCBUSY.HasBits(sam.USB_DEVICE_SYNCBUSY_ENABLE) {
|
||||
}
|
||||
|
||||
sam.USB_DEVICE.DESCADD.Set(uint32(uintptr(unsafe.Pointer(&usbEndpointDescriptors))))
|
||||
|
||||
// configure pins
|
||||
USBCDC_DM_PIN.Configure(PinConfig{Mode: PinCom})
|
||||
USBCDC_DP_PIN.Configure(PinConfig{Mode: PinCom})
|
||||
|
||||
// performs pad calibration from store fuses
|
||||
handlePadCalibration()
|
||||
|
||||
// run in standby
|
||||
sam.USB_DEVICE.CTRLA.SetBits(sam.USB_DEVICE_CTRLA_RUNSTDBY)
|
||||
|
||||
// set full speed
|
||||
sam.USB_DEVICE.CTRLB.SetBits(sam.USB_DEVICE_CTRLB_SPDCONF_FS << sam.USB_DEVICE_CTRLB_SPDCONF_Pos)
|
||||
|
||||
// attach
|
||||
sam.USB_DEVICE.CTRLB.ClearBits(sam.USB_DEVICE_CTRLB_DETACH)
|
||||
|
||||
// enable interrupt for end of reset
|
||||
sam.USB_DEVICE.INTENSET.SetBits(sam.USB_DEVICE_INTENSET_EORST)
|
||||
|
||||
// enable interrupt for start of frame
|
||||
sam.USB_DEVICE.INTENSET.SetBits(sam.USB_DEVICE_INTENSET_SOF)
|
||||
|
||||
// enable USB
|
||||
sam.USB_DEVICE.CTRLA.SetBits(sam.USB_DEVICE_CTRLA_ENABLE)
|
||||
|
||||
// enable IRQ
|
||||
intr := interrupt.New(sam.IRQ_USB, handleUSB)
|
||||
intr.Enable()
|
||||
|
||||
usbcdc.configured = true
|
||||
}
|
||||
|
||||
// Configured returns whether usbcdc is configured or not.
|
||||
func (usbcdc *USBCDC) Configured() bool {
|
||||
return usbcdc.configured
|
||||
}
|
||||
|
||||
func handlePadCalibration() {
|
||||
// Load Pad Calibration data from non-volatile memory
|
||||
// This requires registers that are not included in the SVD file.
|
||||
// Modeled after defines from samd21g18a.h and nvmctrl.h:
|
||||
//
|
||||
// #define NVMCTRL_OTP4 0x00806020
|
||||
//
|
||||
// #define USB_FUSES_TRANSN_ADDR (NVMCTRL_OTP4 + 4)
|
||||
// #define USB_FUSES_TRANSN_Pos 13 /**< \brief (NVMCTRL_OTP4) USB pad Transn calibration */
|
||||
// #define USB_FUSES_TRANSN_Msk (0x1Fu << USB_FUSES_TRANSN_Pos)
|
||||
// #define USB_FUSES_TRANSN(value) ((USB_FUSES_TRANSN_Msk & ((value) << USB_FUSES_TRANSN_Pos)))
|
||||
|
||||
// #define USB_FUSES_TRANSP_ADDR (NVMCTRL_OTP4 + 4)
|
||||
// #define USB_FUSES_TRANSP_Pos 18 /**< \brief (NVMCTRL_OTP4) USB pad Transp calibration */
|
||||
// #define USB_FUSES_TRANSP_Msk (0x1Fu << USB_FUSES_TRANSP_Pos)
|
||||
// #define USB_FUSES_TRANSP(value) ((USB_FUSES_TRANSP_Msk & ((value) << USB_FUSES_TRANSP_Pos)))
|
||||
|
||||
// #define USB_FUSES_TRIM_ADDR (NVMCTRL_OTP4 + 4)
|
||||
// #define USB_FUSES_TRIM_Pos 23 /**< \brief (NVMCTRL_OTP4) USB pad Trim calibration */
|
||||
// #define USB_FUSES_TRIM_Msk (0x7u << USB_FUSES_TRIM_Pos)
|
||||
// #define USB_FUSES_TRIM(value) ((USB_FUSES_TRIM_Msk & ((value) << USB_FUSES_TRIM_Pos)))
|
||||
//
|
||||
fuse := *(*uint32)(unsafe.Pointer(uintptr(0x00806020) + 4))
|
||||
calibTransN := uint16(fuse>>13) & uint16(0x1f)
|
||||
calibTransP := uint16(fuse>>18) & uint16(0x1f)
|
||||
calibTrim := uint16(fuse>>23) & uint16(0x7)
|
||||
|
||||
if calibTransN == 0x1f {
|
||||
calibTransN = 5
|
||||
}
|
||||
sam.USB_DEVICE.PADCAL.SetBits(calibTransN << sam.USB_DEVICE_PADCAL_TRANSN_Pos)
|
||||
|
||||
if calibTransP == 0x1f {
|
||||
calibTransP = 29
|
||||
}
|
||||
sam.USB_DEVICE.PADCAL.SetBits(calibTransP << sam.USB_DEVICE_PADCAL_TRANSP_Pos)
|
||||
|
||||
if calibTrim == 0x7 {
|
||||
calibTrim = 3
|
||||
}
|
||||
sam.USB_DEVICE.PADCAL.SetBits(calibTrim << sam.USB_DEVICE_PADCAL_TRIM_Pos)
|
||||
}
|
||||
|
||||
func handleUSB(intr interrupt.Interrupt) {
|
||||
// reset all interrupt flags
|
||||
flags := sam.USB_DEVICE.INTFLAG.Get()
|
||||
sam.USB_DEVICE.INTFLAG.Set(flags)
|
||||
|
||||
// End of reset
|
||||
if (flags & sam.USB_DEVICE_INTFLAG_EORST) > 0 {
|
||||
// Configure control endpoint
|
||||
initEndpoint(0, usb_ENDPOINT_TYPE_CONTROL)
|
||||
|
||||
// Enable Setup-Received interrupt
|
||||
setEPINTENSET(0, sam.USB_DEVICE_EPINTENSET_RXSTP)
|
||||
|
||||
usbConfiguration = 0
|
||||
|
||||
// ack the End-Of-Reset interrupt
|
||||
sam.USB_DEVICE.INTFLAG.Set(sam.USB_DEVICE_INTFLAG_EORST)
|
||||
}
|
||||
|
||||
// Start of frame
|
||||
if (flags & sam.USB_DEVICE_INTFLAG_SOF) > 0 {
|
||||
USB.Flush()
|
||||
// if you want to blink LED showing traffic, this would be the place...
|
||||
if hidCallback != nil && !waitHidTxc {
|
||||
hidCallback()
|
||||
}
|
||||
}
|
||||
|
||||
// Endpoint 0 Setup interrupt
|
||||
if getEPINTFLAG(0)&sam.USB_DEVICE_EPINTFLAG_RXSTP > 0 {
|
||||
// ack setup received
|
||||
setEPINTFLAG(0, sam.USB_DEVICE_EPINTFLAG_RXSTP)
|
||||
|
||||
// parse setup
|
||||
setup := newUSBSetup(udd_ep_out_cache_buffer[0][:])
|
||||
|
||||
// Clear the Bank 0 ready flag on Control OUT
|
||||
setEPSTATUSCLR(0, sam.USB_DEVICE_EPSTATUSCLR_BK0RDY)
|
||||
usbEndpointDescriptors[0].DeviceDescBank[0].PCKSIZE.ClearBits(usb_DEVICE_PCKSIZE_BYTE_COUNT_Mask << usb_DEVICE_PCKSIZE_BYTE_COUNT_Pos)
|
||||
|
||||
ok := false
|
||||
if (setup.bmRequestType & usb_REQUEST_TYPE) == usb_REQUEST_STANDARD {
|
||||
// Standard Requests
|
||||
ok = handleStandardSetup(setup)
|
||||
} else {
|
||||
// Class Interface Requests
|
||||
if setup.wIndex == usb_CDC_ACM_INTERFACE {
|
||||
ok = cdcSetup(setup)
|
||||
} else if setup.bmRequestType == usb_SET_REPORT_TYPE && setup.bRequest == usb_SET_IDLE {
|
||||
sendZlp()
|
||||
ok = true
|
||||
}
|
||||
}
|
||||
|
||||
if ok {
|
||||
// set Bank1 ready
|
||||
setEPSTATUSSET(0, sam.USB_DEVICE_EPSTATUSSET_BK1RDY)
|
||||
} else {
|
||||
// Stall endpoint
|
||||
setEPSTATUSSET(0, sam.USB_DEVICE_EPINTFLAG_STALL1)
|
||||
}
|
||||
|
||||
if getEPINTFLAG(0)&sam.USB_DEVICE_EPINTFLAG_STALL1 > 0 {
|
||||
// ack the stall
|
||||
setEPINTFLAG(0, sam.USB_DEVICE_EPINTFLAG_STALL1)
|
||||
|
||||
// clear stall request
|
||||
setEPINTENCLR(0, sam.USB_DEVICE_EPINTENCLR_STALL1)
|
||||
}
|
||||
}
|
||||
|
||||
// Now the actual transfer handlers, ignore endpoint number 0 (setup)
|
||||
var i uint32
|
||||
for i = 1; i < uint32(len(endPoints)); i++ {
|
||||
// Check if endpoint has a pending interrupt
|
||||
epFlags := getEPINTFLAG(i)
|
||||
if (epFlags&sam.USB_DEVICE_EPINTFLAG_TRCPT0) > 0 ||
|
||||
(epFlags&sam.USB_DEVICE_EPINTFLAG_TRCPT1) > 0 {
|
||||
switch i {
|
||||
case usb_CDC_ENDPOINT_OUT:
|
||||
handleEndpoint(i)
|
||||
setEPINTFLAG(i, epFlags)
|
||||
case usb_CDC_ENDPOINT_IN, usb_CDC_ENDPOINT_ACM:
|
||||
setEPSTATUSCLR(i, sam.USB_DEVICE_EPSTATUSCLR_BK1RDY)
|
||||
setEPINTFLAG(i, sam.USB_DEVICE_EPINTFLAG_TRCPT1)
|
||||
|
||||
if i == usb_CDC_ENDPOINT_IN {
|
||||
USB.waitTxc = false
|
||||
}
|
||||
case usb_HID_ENDPOINT_IN:
|
||||
setEPINTFLAG(i, sam.USB_DEVICE_EPINTFLAG_TRCPT1)
|
||||
waitHidTxc = false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func initEndpoint(ep, config uint32) {
|
||||
switch config {
|
||||
case usb_ENDPOINT_TYPE_INTERRUPT | usbEndpointIn:
|
||||
// set packet size
|
||||
usbEndpointDescriptors[ep].DeviceDescBank[1].PCKSIZE.SetBits(epPacketSize(64) << usb_DEVICE_PCKSIZE_SIZE_Pos)
|
||||
|
||||
// set data buffer address
|
||||
usbEndpointDescriptors[ep].DeviceDescBank[1].ADDR.Set(uint32(uintptr(unsafe.Pointer(&udd_ep_in_cache_buffer[ep]))))
|
||||
|
||||
// set endpoint type
|
||||
setEPCFG(ep, ((usb_ENDPOINT_TYPE_INTERRUPT + 1) << sam.USB_DEVICE_EPCFG_EPTYPE1_Pos))
|
||||
|
||||
case usb_ENDPOINT_TYPE_BULK | usbEndpointOut:
|
||||
// set packet size
|
||||
usbEndpointDescriptors[ep].DeviceDescBank[0].PCKSIZE.SetBits(epPacketSize(64) << usb_DEVICE_PCKSIZE_SIZE_Pos)
|
||||
|
||||
// set data buffer address
|
||||
usbEndpointDescriptors[ep].DeviceDescBank[0].ADDR.Set(uint32(uintptr(unsafe.Pointer(&udd_ep_out_cache_buffer[ep]))))
|
||||
|
||||
// set endpoint type
|
||||
setEPCFG(ep, ((usb_ENDPOINT_TYPE_BULK + 1) << sam.USB_DEVICE_EPCFG_EPTYPE0_Pos))
|
||||
|
||||
// receive interrupts when current transfer complete
|
||||
setEPINTENSET(ep, sam.USB_DEVICE_EPINTENSET_TRCPT0)
|
||||
|
||||
// set byte count to zero, we have not received anything yet
|
||||
usbEndpointDescriptors[ep].DeviceDescBank[0].PCKSIZE.ClearBits(usb_DEVICE_PCKSIZE_BYTE_COUNT_Mask << usb_DEVICE_PCKSIZE_BYTE_COUNT_Pos)
|
||||
|
||||
// ready for next transfer
|
||||
setEPSTATUSCLR(ep, sam.USB_DEVICE_EPSTATUSCLR_BK0RDY)
|
||||
|
||||
case usb_ENDPOINT_TYPE_INTERRUPT | usbEndpointOut:
|
||||
// TODO: not really anything, seems like...
|
||||
|
||||
case usb_ENDPOINT_TYPE_BULK | usbEndpointIn:
|
||||
// set packet size
|
||||
usbEndpointDescriptors[ep].DeviceDescBank[1].PCKSIZE.SetBits(epPacketSize(64) << usb_DEVICE_PCKSIZE_SIZE_Pos)
|
||||
|
||||
// set data buffer address
|
||||
usbEndpointDescriptors[ep].DeviceDescBank[1].ADDR.Set(uint32(uintptr(unsafe.Pointer(&udd_ep_in_cache_buffer[ep]))))
|
||||
|
||||
// set endpoint type
|
||||
setEPCFG(ep, ((usb_ENDPOINT_TYPE_BULK + 1) << sam.USB_DEVICE_EPCFG_EPTYPE1_Pos))
|
||||
|
||||
// NAK on endpoint IN, the bank is not yet filled in.
|
||||
setEPSTATUSCLR(ep, sam.USB_DEVICE_EPSTATUSCLR_BK1RDY)
|
||||
|
||||
case usb_ENDPOINT_TYPE_CONTROL:
|
||||
// Control OUT
|
||||
// set packet size
|
||||
usbEndpointDescriptors[ep].DeviceDescBank[0].PCKSIZE.SetBits(epPacketSize(64) << usb_DEVICE_PCKSIZE_SIZE_Pos)
|
||||
|
||||
// set data buffer address
|
||||
usbEndpointDescriptors[ep].DeviceDescBank[0].ADDR.Set(uint32(uintptr(unsafe.Pointer(&udd_ep_out_cache_buffer[ep]))))
|
||||
|
||||
// set endpoint type
|
||||
setEPCFG(ep, getEPCFG(ep)|((usb_ENDPOINT_TYPE_CONTROL+1)<<sam.USB_DEVICE_EPCFG_EPTYPE0_Pos))
|
||||
|
||||
// Control IN
|
||||
// set packet size
|
||||
usbEndpointDescriptors[ep].DeviceDescBank[1].PCKSIZE.SetBits(epPacketSize(64) << usb_DEVICE_PCKSIZE_SIZE_Pos)
|
||||
|
||||
// set data buffer address
|
||||
usbEndpointDescriptors[ep].DeviceDescBank[1].ADDR.Set(uint32(uintptr(unsafe.Pointer(&udd_ep_in_cache_buffer[ep]))))
|
||||
|
||||
// set endpoint type
|
||||
setEPCFG(ep, getEPCFG(ep)|((usb_ENDPOINT_TYPE_CONTROL+1)<<sam.USB_DEVICE_EPCFG_EPTYPE1_Pos))
|
||||
|
||||
// Prepare OUT endpoint for receive
|
||||
// set multi packet size for expected number of receive bytes on control OUT
|
||||
usbEndpointDescriptors[ep].DeviceDescBank[0].PCKSIZE.SetBits(64 << usb_DEVICE_PCKSIZE_MULTI_PACKET_SIZE_Pos)
|
||||
|
||||
// set byte count to zero, we have not received anything yet
|
||||
usbEndpointDescriptors[ep].DeviceDescBank[0].PCKSIZE.ClearBits(usb_DEVICE_PCKSIZE_BYTE_COUNT_Mask << usb_DEVICE_PCKSIZE_BYTE_COUNT_Pos)
|
||||
|
||||
// NAK on endpoint OUT to show we are ready to receive control data
|
||||
setEPSTATUSSET(ep, sam.USB_DEVICE_EPSTATUSSET_BK0RDY)
|
||||
}
|
||||
}
|
||||
|
||||
func handleStandardSetup(setup usbSetup) bool {
|
||||
switch setup.bRequest {
|
||||
case usb_GET_STATUS:
|
||||
buf := []byte{0, 0}
|
||||
|
||||
if setup.bmRequestType != 0 { // endpoint
|
||||
// TODO: actually check if the endpoint in question is currently halted
|
||||
if isEndpointHalt {
|
||||
buf[0] = 1
|
||||
}
|
||||
}
|
||||
|
||||
sendUSBPacket(0, buf, setup.wLength)
|
||||
return true
|
||||
|
||||
case usb_CLEAR_FEATURE:
|
||||
if setup.wValueL == 1 { // DEVICEREMOTEWAKEUP
|
||||
isRemoteWakeUpEnabled = false
|
||||
} else if setup.wValueL == 0 { // ENDPOINTHALT
|
||||
isEndpointHalt = false
|
||||
}
|
||||
sendZlp()
|
||||
return true
|
||||
|
||||
case usb_SET_FEATURE:
|
||||
if setup.wValueL == 1 { // DEVICEREMOTEWAKEUP
|
||||
isRemoteWakeUpEnabled = true
|
||||
} else if setup.wValueL == 0 { // ENDPOINTHALT
|
||||
isEndpointHalt = true
|
||||
}
|
||||
sendZlp()
|
||||
return true
|
||||
|
||||
case usb_SET_ADDRESS:
|
||||
// set packet size 64 with auto Zlp after transfer
|
||||
usbEndpointDescriptors[0].DeviceDescBank[1].PCKSIZE.Set((epPacketSize(64) << usb_DEVICE_PCKSIZE_SIZE_Pos) |
|
||||
uint32(1<<31)) // autozlp
|
||||
|
||||
// ack the transfer is complete from the request
|
||||
setEPINTFLAG(0, sam.USB_DEVICE_EPINTFLAG_TRCPT1)
|
||||
|
||||
// set bank ready for data
|
||||
setEPSTATUSSET(0, sam.USB_DEVICE_EPSTATUSSET_BK1RDY)
|
||||
|
||||
// wait for transfer to complete
|
||||
timeout := 3000
|
||||
for (getEPINTFLAG(0) & sam.USB_DEVICE_EPINTFLAG_TRCPT1) == 0 {
|
||||
timeout--
|
||||
if timeout == 0 {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
// last, set the device address to that requested by host
|
||||
sam.USB_DEVICE.DADD.SetBits(setup.wValueL)
|
||||
sam.USB_DEVICE.DADD.SetBits(sam.USB_DEVICE_DADD_ADDEN)
|
||||
|
||||
return true
|
||||
|
||||
case usb_GET_DESCRIPTOR:
|
||||
sendDescriptor(setup)
|
||||
return true
|
||||
|
||||
case usb_SET_DESCRIPTOR:
|
||||
return false
|
||||
|
||||
case usb_GET_CONFIGURATION:
|
||||
buff := []byte{usbConfiguration}
|
||||
sendUSBPacket(0, buff, setup.wLength)
|
||||
return true
|
||||
|
||||
case usb_SET_CONFIGURATION:
|
||||
if setup.bmRequestType&usb_REQUEST_RECIPIENT == usb_REQUEST_DEVICE {
|
||||
for i := 1; i < len(endPoints); i++ {
|
||||
initEndpoint(uint32(i), endPoints[i])
|
||||
}
|
||||
|
||||
usbConfiguration = setup.wValueL
|
||||
|
||||
// Enable interrupt for CDC control messages from host (OUT packet)
|
||||
setEPINTENSET(usb_CDC_ENDPOINT_ACM, sam.USB_DEVICE_EPINTENSET_TRCPT1)
|
||||
|
||||
// Enable interrupt for CDC data messages from host
|
||||
setEPINTENSET(usb_CDC_ENDPOINT_OUT, sam.USB_DEVICE_EPINTENSET_TRCPT0)
|
||||
|
||||
// Enable interrupt for HID messages from host
|
||||
if hidCallback != nil {
|
||||
setEPINTENSET(usb_HID_ENDPOINT_IN, sam.USB_DEVICE_EPINTENSET_TRCPT1)
|
||||
}
|
||||
|
||||
sendZlp()
|
||||
return true
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
|
||||
case usb_GET_INTERFACE:
|
||||
buff := []byte{usbSetInterface}
|
||||
sendUSBPacket(0, buff, setup.wLength)
|
||||
return true
|
||||
|
||||
case usb_SET_INTERFACE:
|
||||
usbSetInterface = setup.wValueL
|
||||
|
||||
sendZlp()
|
||||
return true
|
||||
|
||||
default:
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
func cdcSetup(setup usbSetup) bool {
|
||||
if setup.bmRequestType == usb_REQUEST_DEVICETOHOST_CLASS_INTERFACE {
|
||||
if setup.bRequest == usb_CDC_GET_LINE_CODING {
|
||||
var b [cdcLineInfoSize]byte
|
||||
b[0] = byte(usbLineInfo.dwDTERate)
|
||||
b[1] = byte(usbLineInfo.dwDTERate >> 8)
|
||||
b[2] = byte(usbLineInfo.dwDTERate >> 16)
|
||||
b[3] = byte(usbLineInfo.dwDTERate >> 24)
|
||||
b[4] = byte(usbLineInfo.bCharFormat)
|
||||
b[5] = byte(usbLineInfo.bParityType)
|
||||
b[6] = byte(usbLineInfo.bDataBits)
|
||||
|
||||
sendUSBPacket(0, b[:], setup.wLength)
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
if setup.bmRequestType == usb_REQUEST_HOSTTODEVICE_CLASS_INTERFACE {
|
||||
if setup.bRequest == usb_CDC_SET_LINE_CODING {
|
||||
b, err := receiveUSBControlPacket()
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
|
||||
usbLineInfo.dwDTERate = uint32(b[0]) | uint32(b[1])<<8 | uint32(b[2])<<16 | uint32(b[3])<<24
|
||||
usbLineInfo.bCharFormat = b[4]
|
||||
usbLineInfo.bParityType = b[5]
|
||||
usbLineInfo.bDataBits = b[6]
|
||||
}
|
||||
|
||||
if setup.bRequest == usb_CDC_SET_CONTROL_LINE_STATE {
|
||||
usbLineInfo.lineState = setup.wValueL
|
||||
}
|
||||
|
||||
if setup.bRequest == usb_CDC_SET_LINE_CODING || setup.bRequest == usb_CDC_SET_CONTROL_LINE_STATE {
|
||||
// auto-reset into the bootloader
|
||||
if usbLineInfo.dwDTERate == 1200 && usbLineInfo.lineState&usb_CDC_LINESTATE_DTR == 0 {
|
||||
ResetProcessor()
|
||||
} else {
|
||||
// TODO: cancel any reset
|
||||
}
|
||||
sendZlp()
|
||||
}
|
||||
|
||||
if setup.bRequest == usb_CDC_SEND_BREAK {
|
||||
// TODO: something with this value?
|
||||
// breakValue = ((uint16_t)setup.wValueH << 8) | setup.wValueL;
|
||||
// return false;
|
||||
sendZlp()
|
||||
}
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// SendUSBHIDPacket sends a packet for USBHID (interrupt / in).
|
||||
func SendUSBHIDPacket(ep uint32, data []byte) bool {
|
||||
if waitHidTxc {
|
||||
return false
|
||||
}
|
||||
sendUSBPacket(ep, data, 0)
|
||||
|
||||
// clear transfer complete flag
|
||||
setEPINTFLAG(ep, sam.USB_DEVICE_EPINTFLAG_TRCPT1)
|
||||
|
||||
// send data by setting bank ready
|
||||
setEPSTATUSSET(ep, sam.USB_DEVICE_EPSTATUSSET_BK1RDY)
|
||||
|
||||
waitHidTxc = true
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
//go:noinline
|
||||
func sendUSBPacket(ep uint32, data []byte, maxsize uint16) {
|
||||
l := uint16(len(data))
|
||||
if 0 < maxsize && maxsize < l {
|
||||
l = maxsize
|
||||
}
|
||||
copy(udd_ep_in_cache_buffer[ep][:], data[:l])
|
||||
|
||||
// Set endpoint address for sending data
|
||||
usbEndpointDescriptors[ep].DeviceDescBank[1].ADDR.Set(uint32(uintptr(unsafe.Pointer(&udd_ep_in_cache_buffer[ep]))))
|
||||
|
||||
// clear multi-packet size which is total bytes already sent
|
||||
usbEndpointDescriptors[ep].DeviceDescBank[1].PCKSIZE.ClearBits(usb_DEVICE_PCKSIZE_MULTI_PACKET_SIZE_Mask << usb_DEVICE_PCKSIZE_MULTI_PACKET_SIZE_Pos)
|
||||
|
||||
// set byte count, which is total number of bytes to be sent
|
||||
usbEndpointDescriptors[ep].DeviceDescBank[1].PCKSIZE.ClearBits(usb_DEVICE_PCKSIZE_BYTE_COUNT_Mask << usb_DEVICE_PCKSIZE_BYTE_COUNT_Pos)
|
||||
usbEndpointDescriptors[ep].DeviceDescBank[1].PCKSIZE.SetBits((uint32(l) & usb_DEVICE_PCKSIZE_BYTE_COUNT_Mask) << usb_DEVICE_PCKSIZE_BYTE_COUNT_Pos)
|
||||
}
|
||||
|
||||
func receiveUSBControlPacket() ([cdcLineInfoSize]byte, error) {
|
||||
var b [cdcLineInfoSize]byte
|
||||
|
||||
// address
|
||||
usbEndpointDescriptors[0].DeviceDescBank[0].ADDR.Set(uint32(uintptr(unsafe.Pointer(&udd_ep_out_cache_buffer[0]))))
|
||||
|
||||
// set byte count to zero
|
||||
usbEndpointDescriptors[0].DeviceDescBank[0].PCKSIZE.ClearBits(usb_DEVICE_PCKSIZE_BYTE_COUNT_Mask << usb_DEVICE_PCKSIZE_BYTE_COUNT_Pos)
|
||||
|
||||
// set ready for next data
|
||||
setEPSTATUSCLR(0, sam.USB_DEVICE_EPSTATUSCLR_BK0RDY)
|
||||
|
||||
// Wait until OUT transfer is ready.
|
||||
timeout := 300000
|
||||
for (getEPSTATUS(0) & sam.USB_DEVICE_EPSTATUS_BK0RDY) == 0 {
|
||||
timeout--
|
||||
if timeout == 0 {
|
||||
return b, errUSBCDCReadTimeout
|
||||
}
|
||||
}
|
||||
|
||||
// Wait until OUT transfer is completed.
|
||||
timeout = 300000
|
||||
for (getEPINTFLAG(0) & sam.USB_DEVICE_EPINTFLAG_TRCPT0) == 0 {
|
||||
timeout--
|
||||
if timeout == 0 {
|
||||
return b, errUSBCDCReadTimeout
|
||||
}
|
||||
}
|
||||
|
||||
// get data
|
||||
bytesread := uint32((usbEndpointDescriptors[0].DeviceDescBank[0].PCKSIZE.Get() >>
|
||||
usb_DEVICE_PCKSIZE_BYTE_COUNT_Pos) & usb_DEVICE_PCKSIZE_BYTE_COUNT_Mask)
|
||||
|
||||
if bytesread != cdcLineInfoSize {
|
||||
return b, errUSBCDCBytesRead
|
||||
}
|
||||
|
||||
copy(b[:7], udd_ep_out_cache_buffer[0][:7])
|
||||
|
||||
return b, nil
|
||||
}
|
||||
|
||||
func handleEndpoint(ep uint32) {
|
||||
// get data
|
||||
count := int((usbEndpointDescriptors[ep].DeviceDescBank[0].PCKSIZE.Get() >>
|
||||
usb_DEVICE_PCKSIZE_BYTE_COUNT_Pos) & usb_DEVICE_PCKSIZE_BYTE_COUNT_Mask)
|
||||
|
||||
// move to ring buffer
|
||||
for i := 0; i < count; i++ {
|
||||
USB.Receive(byte((udd_ep_out_cache_buffer[ep][i] & 0xFF)))
|
||||
}
|
||||
|
||||
// set byte count to zero
|
||||
usbEndpointDescriptors[ep].DeviceDescBank[0].PCKSIZE.ClearBits(usb_DEVICE_PCKSIZE_BYTE_COUNT_Mask << usb_DEVICE_PCKSIZE_BYTE_COUNT_Pos)
|
||||
|
||||
// set multi packet size to 64
|
||||
usbEndpointDescriptors[ep].DeviceDescBank[0].PCKSIZE.SetBits(64 << usb_DEVICE_PCKSIZE_MULTI_PACKET_SIZE_Pos)
|
||||
|
||||
// set ready for next data
|
||||
setEPSTATUSCLR(ep, sam.USB_DEVICE_EPSTATUSCLR_BK0RDY)
|
||||
}
|
||||
|
||||
func sendZlp() {
|
||||
usbEndpointDescriptors[0].DeviceDescBank[1].PCKSIZE.ClearBits(usb_DEVICE_PCKSIZE_BYTE_COUNT_Mask << usb_DEVICE_PCKSIZE_BYTE_COUNT_Pos)
|
||||
}
|
||||
|
||||
func epPacketSize(size uint16) uint32 {
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
func getEPCFG(ep uint32) uint8 {
|
||||
switch ep {
|
||||
case 0:
|
||||
return sam.USB_DEVICE.EPCFG0.Get()
|
||||
case 1:
|
||||
return sam.USB_DEVICE.EPCFG1.Get()
|
||||
case 2:
|
||||
return sam.USB_DEVICE.EPCFG2.Get()
|
||||
case 3:
|
||||
return sam.USB_DEVICE.EPCFG3.Get()
|
||||
case 4:
|
||||
return sam.USB_DEVICE.EPCFG4.Get()
|
||||
case 5:
|
||||
return sam.USB_DEVICE.EPCFG5.Get()
|
||||
case 6:
|
||||
return sam.USB_DEVICE.EPCFG6.Get()
|
||||
case 7:
|
||||
return sam.USB_DEVICE.EPCFG7.Get()
|
||||
default:
|
||||
return 0
|
||||
}
|
||||
}
|
||||
|
||||
func setEPCFG(ep uint32, val uint8) {
|
||||
switch ep {
|
||||
case 0:
|
||||
sam.USB_DEVICE.EPCFG0.Set(val)
|
||||
case 1:
|
||||
sam.USB_DEVICE.EPCFG1.Set(val)
|
||||
case 2:
|
||||
sam.USB_DEVICE.EPCFG2.Set(val)
|
||||
case 3:
|
||||
sam.USB_DEVICE.EPCFG3.Set(val)
|
||||
case 4:
|
||||
sam.USB_DEVICE.EPCFG4.Set(val)
|
||||
case 5:
|
||||
sam.USB_DEVICE.EPCFG5.Set(val)
|
||||
case 6:
|
||||
sam.USB_DEVICE.EPCFG6.Set(val)
|
||||
case 7:
|
||||
sam.USB_DEVICE.EPCFG7.Set(val)
|
||||
default:
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
func setEPSTATUSCLR(ep uint32, val uint8) {
|
||||
switch ep {
|
||||
case 0:
|
||||
sam.USB_DEVICE.EPSTATUSCLR0.Set(val)
|
||||
case 1:
|
||||
sam.USB_DEVICE.EPSTATUSCLR1.Set(val)
|
||||
case 2:
|
||||
sam.USB_DEVICE.EPSTATUSCLR2.Set(val)
|
||||
case 3:
|
||||
sam.USB_DEVICE.EPSTATUSCLR3.Set(val)
|
||||
case 4:
|
||||
sam.USB_DEVICE.EPSTATUSCLR4.Set(val)
|
||||
case 5:
|
||||
sam.USB_DEVICE.EPSTATUSCLR5.Set(val)
|
||||
case 6:
|
||||
sam.USB_DEVICE.EPSTATUSCLR6.Set(val)
|
||||
case 7:
|
||||
sam.USB_DEVICE.EPSTATUSCLR7.Set(val)
|
||||
default:
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
func setEPSTATUSSET(ep uint32, val uint8) {
|
||||
switch ep {
|
||||
case 0:
|
||||
sam.USB_DEVICE.EPSTATUSSET0.Set(val)
|
||||
case 1:
|
||||
sam.USB_DEVICE.EPSTATUSSET1.Set(val)
|
||||
case 2:
|
||||
sam.USB_DEVICE.EPSTATUSSET2.Set(val)
|
||||
case 3:
|
||||
sam.USB_DEVICE.EPSTATUSSET3.Set(val)
|
||||
case 4:
|
||||
sam.USB_DEVICE.EPSTATUSSET4.Set(val)
|
||||
case 5:
|
||||
sam.USB_DEVICE.EPSTATUSSET5.Set(val)
|
||||
case 6:
|
||||
sam.USB_DEVICE.EPSTATUSSET6.Set(val)
|
||||
case 7:
|
||||
sam.USB_DEVICE.EPSTATUSSET7.Set(val)
|
||||
default:
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
func getEPSTATUS(ep uint32) uint8 {
|
||||
switch ep {
|
||||
case 0:
|
||||
return sam.USB_DEVICE.EPSTATUS0.Get()
|
||||
case 1:
|
||||
return sam.USB_DEVICE.EPSTATUS1.Get()
|
||||
case 2:
|
||||
return sam.USB_DEVICE.EPSTATUS2.Get()
|
||||
case 3:
|
||||
return sam.USB_DEVICE.EPSTATUS3.Get()
|
||||
case 4:
|
||||
return sam.USB_DEVICE.EPSTATUS4.Get()
|
||||
case 5:
|
||||
return sam.USB_DEVICE.EPSTATUS5.Get()
|
||||
case 6:
|
||||
return sam.USB_DEVICE.EPSTATUS6.Get()
|
||||
case 7:
|
||||
return sam.USB_DEVICE.EPSTATUS7.Get()
|
||||
default:
|
||||
return 0
|
||||
}
|
||||
}
|
||||
|
||||
func getEPINTFLAG(ep uint32) uint8 {
|
||||
switch ep {
|
||||
case 0:
|
||||
return sam.USB_DEVICE.EPINTFLAG0.Get()
|
||||
case 1:
|
||||
return sam.USB_DEVICE.EPINTFLAG1.Get()
|
||||
case 2:
|
||||
return sam.USB_DEVICE.EPINTFLAG2.Get()
|
||||
case 3:
|
||||
return sam.USB_DEVICE.EPINTFLAG3.Get()
|
||||
case 4:
|
||||
return sam.USB_DEVICE.EPINTFLAG4.Get()
|
||||
case 5:
|
||||
return sam.USB_DEVICE.EPINTFLAG5.Get()
|
||||
case 6:
|
||||
return sam.USB_DEVICE.EPINTFLAG6.Get()
|
||||
case 7:
|
||||
return sam.USB_DEVICE.EPINTFLAG7.Get()
|
||||
default:
|
||||
return 0
|
||||
}
|
||||
}
|
||||
|
||||
func setEPINTFLAG(ep uint32, val uint8) {
|
||||
switch ep {
|
||||
case 0:
|
||||
sam.USB_DEVICE.EPINTFLAG0.Set(val)
|
||||
case 1:
|
||||
sam.USB_DEVICE.EPINTFLAG1.Set(val)
|
||||
case 2:
|
||||
sam.USB_DEVICE.EPINTFLAG2.Set(val)
|
||||
case 3:
|
||||
sam.USB_DEVICE.EPINTFLAG3.Set(val)
|
||||
case 4:
|
||||
sam.USB_DEVICE.EPINTFLAG4.Set(val)
|
||||
case 5:
|
||||
sam.USB_DEVICE.EPINTFLAG5.Set(val)
|
||||
case 6:
|
||||
sam.USB_DEVICE.EPINTFLAG6.Set(val)
|
||||
case 7:
|
||||
sam.USB_DEVICE.EPINTFLAG7.Set(val)
|
||||
default:
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
func setEPINTENCLR(ep uint32, val uint8) {
|
||||
switch ep {
|
||||
case 0:
|
||||
sam.USB_DEVICE.EPINTENCLR0.Set(val)
|
||||
case 1:
|
||||
sam.USB_DEVICE.EPINTENCLR1.Set(val)
|
||||
case 2:
|
||||
sam.USB_DEVICE.EPINTENCLR2.Set(val)
|
||||
case 3:
|
||||
sam.USB_DEVICE.EPINTENCLR3.Set(val)
|
||||
case 4:
|
||||
sam.USB_DEVICE.EPINTENCLR4.Set(val)
|
||||
case 5:
|
||||
sam.USB_DEVICE.EPINTENCLR5.Set(val)
|
||||
case 6:
|
||||
sam.USB_DEVICE.EPINTENCLR6.Set(val)
|
||||
case 7:
|
||||
sam.USB_DEVICE.EPINTENCLR7.Set(val)
|
||||
default:
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
func setEPINTENSET(ep uint32, val uint8) {
|
||||
switch ep {
|
||||
case 0:
|
||||
sam.USB_DEVICE.EPINTENSET0.Set(val)
|
||||
case 1:
|
||||
sam.USB_DEVICE.EPINTENSET1.Set(val)
|
||||
case 2:
|
||||
sam.USB_DEVICE.EPINTENSET2.Set(val)
|
||||
case 3:
|
||||
sam.USB_DEVICE.EPINTENSET3.Set(val)
|
||||
case 4:
|
||||
sam.USB_DEVICE.EPINTENSET4.Set(val)
|
||||
case 5:
|
||||
sam.USB_DEVICE.EPINTENSET5.Set(val)
|
||||
case 6:
|
||||
sam.USB_DEVICE.EPINTENSET6.Set(val)
|
||||
case 7:
|
||||
sam.USB_DEVICE.EPINTENSET7.Set(val)
|
||||
default:
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// ResetProcessor should perform a system reset in preperation
|
||||
// EnterBootloader should perform a system reset in preperation
|
||||
// to switch to the bootloader to flash new firmware.
|
||||
func ResetProcessor() {
|
||||
func EnterBootloader() {
|
||||
arm.DisableInterrupts()
|
||||
|
||||
// Perform magic reset into bootloader, as mentioned in
|
||||
|
||||
@@ -0,0 +1,640 @@
|
||||
//go:build sam && atsamd21
|
||||
// +build sam,atsamd21
|
||||
|
||||
package machine
|
||||
|
||||
import (
|
||||
"device/sam"
|
||||
"machine/usb"
|
||||
"runtime/interrupt"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
const (
|
||||
// these are SAMD21 specific.
|
||||
usb_DEVICE_PCKSIZE_BYTE_COUNT_Pos = 0
|
||||
usb_DEVICE_PCKSIZE_BYTE_COUNT_Mask = 0x3FFF
|
||||
|
||||
usb_DEVICE_PCKSIZE_SIZE_Pos = 28
|
||||
usb_DEVICE_PCKSIZE_SIZE_Mask = 0x7
|
||||
|
||||
usb_DEVICE_PCKSIZE_MULTI_PACKET_SIZE_Pos = 14
|
||||
usb_DEVICE_PCKSIZE_MULTI_PACKET_SIZE_Mask = 0x3FFF
|
||||
)
|
||||
|
||||
// Configure the USB peripheral. The config is here for compatibility with the UART interface.
|
||||
func (dev *USBDevice) Configure(config UARTConfig) {
|
||||
if dev.initcomplete {
|
||||
return
|
||||
}
|
||||
|
||||
// reset USB interface
|
||||
sam.USB_DEVICE.CTRLA.SetBits(sam.USB_DEVICE_CTRLA_SWRST)
|
||||
for sam.USB_DEVICE.SYNCBUSY.HasBits(sam.USB_DEVICE_SYNCBUSY_SWRST) ||
|
||||
sam.USB_DEVICE.SYNCBUSY.HasBits(sam.USB_DEVICE_SYNCBUSY_ENABLE) {
|
||||
}
|
||||
|
||||
sam.USB_DEVICE.DESCADD.Set(uint32(uintptr(unsafe.Pointer(&usbEndpointDescriptors))))
|
||||
|
||||
// configure pins
|
||||
USBCDC_DM_PIN.Configure(PinConfig{Mode: PinCom})
|
||||
USBCDC_DP_PIN.Configure(PinConfig{Mode: PinCom})
|
||||
|
||||
// performs pad calibration from store fuses
|
||||
handlePadCalibration()
|
||||
|
||||
// run in standby
|
||||
sam.USB_DEVICE.CTRLA.SetBits(sam.USB_DEVICE_CTRLA_RUNSTDBY)
|
||||
|
||||
// set full speed
|
||||
sam.USB_DEVICE.CTRLB.SetBits(sam.USB_DEVICE_CTRLB_SPDCONF_FS << sam.USB_DEVICE_CTRLB_SPDCONF_Pos)
|
||||
|
||||
// attach
|
||||
sam.USB_DEVICE.CTRLB.ClearBits(sam.USB_DEVICE_CTRLB_DETACH)
|
||||
|
||||
// enable interrupt for end of reset
|
||||
sam.USB_DEVICE.INTENSET.SetBits(sam.USB_DEVICE_INTENSET_EORST)
|
||||
|
||||
// enable interrupt for start of frame
|
||||
sam.USB_DEVICE.INTENSET.SetBits(sam.USB_DEVICE_INTENSET_SOF)
|
||||
|
||||
// enable USB
|
||||
sam.USB_DEVICE.CTRLA.SetBits(sam.USB_DEVICE_CTRLA_ENABLE)
|
||||
|
||||
// enable IRQ
|
||||
interrupt.New(sam.IRQ_USB, handleUSBIRQ).Enable()
|
||||
|
||||
dev.initcomplete = true
|
||||
}
|
||||
|
||||
func handlePadCalibration() {
|
||||
// Load Pad Calibration data from non-volatile memory
|
||||
// This requires registers that are not included in the SVD file.
|
||||
// Modeled after defines from samd21g18a.h and nvmctrl.h:
|
||||
//
|
||||
// #define NVMCTRL_OTP4 0x00806020
|
||||
//
|
||||
// #define USB_FUSES_TRANSN_ADDR (NVMCTRL_OTP4 + 4)
|
||||
// #define USB_FUSES_TRANSN_Pos 13 /**< \brief (NVMCTRL_OTP4) USB pad Transn calibration */
|
||||
// #define USB_FUSES_TRANSN_Msk (0x1Fu << USB_FUSES_TRANSN_Pos)
|
||||
// #define USB_FUSES_TRANSN(value) ((USB_FUSES_TRANSN_Msk & ((value) << USB_FUSES_TRANSN_Pos)))
|
||||
|
||||
// #define USB_FUSES_TRANSP_ADDR (NVMCTRL_OTP4 + 4)
|
||||
// #define USB_FUSES_TRANSP_Pos 18 /**< \brief (NVMCTRL_OTP4) USB pad Transp calibration */
|
||||
// #define USB_FUSES_TRANSP_Msk (0x1Fu << USB_FUSES_TRANSP_Pos)
|
||||
// #define USB_FUSES_TRANSP(value) ((USB_FUSES_TRANSP_Msk & ((value) << USB_FUSES_TRANSP_Pos)))
|
||||
|
||||
// #define USB_FUSES_TRIM_ADDR (NVMCTRL_OTP4 + 4)
|
||||
// #define USB_FUSES_TRIM_Pos 23 /**< \brief (NVMCTRL_OTP4) USB pad Trim calibration */
|
||||
// #define USB_FUSES_TRIM_Msk (0x7u << USB_FUSES_TRIM_Pos)
|
||||
// #define USB_FUSES_TRIM(value) ((USB_FUSES_TRIM_Msk & ((value) << USB_FUSES_TRIM_Pos)))
|
||||
//
|
||||
fuse := *(*uint32)(unsafe.Pointer(uintptr(0x00806020) + 4))
|
||||
calibTransN := uint16(fuse>>13) & uint16(0x1f)
|
||||
calibTransP := uint16(fuse>>18) & uint16(0x1f)
|
||||
calibTrim := uint16(fuse>>23) & uint16(0x7)
|
||||
|
||||
if calibTransN == 0x1f {
|
||||
calibTransN = 5
|
||||
}
|
||||
sam.USB_DEVICE.PADCAL.SetBits(calibTransN << sam.USB_DEVICE_PADCAL_TRANSN_Pos)
|
||||
|
||||
if calibTransP == 0x1f {
|
||||
calibTransP = 29
|
||||
}
|
||||
sam.USB_DEVICE.PADCAL.SetBits(calibTransP << sam.USB_DEVICE_PADCAL_TRANSP_Pos)
|
||||
|
||||
if calibTrim == 0x7 {
|
||||
calibTrim = 3
|
||||
}
|
||||
sam.USB_DEVICE.PADCAL.SetBits(calibTrim << sam.USB_DEVICE_PADCAL_TRIM_Pos)
|
||||
}
|
||||
|
||||
func handleUSBIRQ(intr interrupt.Interrupt) {
|
||||
// reset all interrupt flags
|
||||
flags := sam.USB_DEVICE.INTFLAG.Get()
|
||||
sam.USB_DEVICE.INTFLAG.Set(flags)
|
||||
|
||||
// End of reset
|
||||
if (flags & sam.USB_DEVICE_INTFLAG_EORST) > 0 {
|
||||
// Configure control endpoint
|
||||
initEndpoint(0, usb.ENDPOINT_TYPE_CONTROL)
|
||||
|
||||
usbConfiguration = 0
|
||||
|
||||
// ack the End-Of-Reset interrupt
|
||||
sam.USB_DEVICE.INTFLAG.Set(sam.USB_DEVICE_INTFLAG_EORST)
|
||||
}
|
||||
|
||||
// Start of frame
|
||||
if (flags & sam.USB_DEVICE_INTFLAG_SOF) > 0 {
|
||||
// if you want to blink LED showing traffic, this would be the place...
|
||||
}
|
||||
|
||||
// Endpoint 0 Setup interrupt
|
||||
if getEPINTFLAG(0)&sam.USB_DEVICE_EPINTFLAG_RXSTP > 0 {
|
||||
// ack setup received
|
||||
setEPINTFLAG(0, sam.USB_DEVICE_EPINTFLAG_RXSTP)
|
||||
|
||||
// parse setup
|
||||
setup := usb.NewSetup(udd_ep_out_cache_buffer[0][:])
|
||||
|
||||
// Clear the Bank 0 ready flag on Control OUT
|
||||
setEPSTATUSCLR(0, sam.USB_DEVICE_EPSTATUSCLR_BK0RDY)
|
||||
usbEndpointDescriptors[0].DeviceDescBank[0].PCKSIZE.ClearBits(usb_DEVICE_PCKSIZE_BYTE_COUNT_Mask << usb_DEVICE_PCKSIZE_BYTE_COUNT_Pos)
|
||||
|
||||
ok := false
|
||||
if (setup.BmRequestType & usb.REQUEST_TYPE) == usb.REQUEST_STANDARD {
|
||||
// Standard Requests
|
||||
ok = handleStandardSetup(setup)
|
||||
} else {
|
||||
// Class Interface Requests
|
||||
if setup.WIndex < uint16(len(usbSetupHandler)) && usbSetupHandler[setup.WIndex] != nil {
|
||||
ok = usbSetupHandler[setup.WIndex](setup)
|
||||
}
|
||||
}
|
||||
|
||||
if ok {
|
||||
// set Bank1 ready
|
||||
setEPSTATUSSET(0, sam.USB_DEVICE_EPSTATUSSET_BK1RDY)
|
||||
} else {
|
||||
// Stall endpoint
|
||||
setEPSTATUSSET(0, sam.USB_DEVICE_EPINTFLAG_STALL1)
|
||||
}
|
||||
|
||||
if getEPINTFLAG(0)&sam.USB_DEVICE_EPINTFLAG_STALL1 > 0 {
|
||||
// ack the stall
|
||||
setEPINTFLAG(0, sam.USB_DEVICE_EPINTFLAG_STALL1)
|
||||
|
||||
// clear stall request
|
||||
setEPINTENCLR(0, sam.USB_DEVICE_EPINTENCLR_STALL1)
|
||||
}
|
||||
}
|
||||
|
||||
// Now the actual transfer handlers, ignore endpoint number 0 (setup)
|
||||
var i uint32
|
||||
for i = 1; i < uint32(len(endPoints)); i++ {
|
||||
// Check if endpoint has a pending interrupt
|
||||
epFlags := getEPINTFLAG(i)
|
||||
setEPINTFLAG(i, epFlags)
|
||||
if (epFlags & sam.USB_DEVICE_EPINTFLAG_TRCPT0) > 0 {
|
||||
buf := handleEndpointRx(i)
|
||||
if usbRxHandler[i] != nil {
|
||||
usbRxHandler[i](buf)
|
||||
}
|
||||
handleEndpointRxComplete(i)
|
||||
} else if (epFlags & sam.USB_DEVICE_EPINTFLAG_TRCPT1) > 0 {
|
||||
if usbTxHandler[i] != nil {
|
||||
usbTxHandler[i]()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func initEndpoint(ep, config uint32) {
|
||||
switch config {
|
||||
case usb.ENDPOINT_TYPE_INTERRUPT | usb.EndpointIn:
|
||||
// set packet size
|
||||
usbEndpointDescriptors[ep].DeviceDescBank[1].PCKSIZE.SetBits(epPacketSize(64) << usb_DEVICE_PCKSIZE_SIZE_Pos)
|
||||
|
||||
// set data buffer address
|
||||
usbEndpointDescriptors[ep].DeviceDescBank[1].ADDR.Set(uint32(uintptr(unsafe.Pointer(&udd_ep_in_cache_buffer[ep]))))
|
||||
|
||||
// set endpoint type
|
||||
setEPCFG(ep, ((usb.ENDPOINT_TYPE_INTERRUPT + 1) << sam.USB_DEVICE_EPCFG_EPTYPE1_Pos))
|
||||
|
||||
setEPINTENSET(ep, sam.USB_DEVICE_EPINTENSET_TRCPT1)
|
||||
|
||||
case usb.ENDPOINT_TYPE_BULK | usb.EndpointOut:
|
||||
// set packet size
|
||||
usbEndpointDescriptors[ep].DeviceDescBank[0].PCKSIZE.SetBits(epPacketSize(64) << usb_DEVICE_PCKSIZE_SIZE_Pos)
|
||||
|
||||
// set data buffer address
|
||||
usbEndpointDescriptors[ep].DeviceDescBank[0].ADDR.Set(uint32(uintptr(unsafe.Pointer(&udd_ep_out_cache_buffer[ep]))))
|
||||
|
||||
// set endpoint type
|
||||
setEPCFG(ep, ((usb.ENDPOINT_TYPE_BULK + 1) << sam.USB_DEVICE_EPCFG_EPTYPE0_Pos))
|
||||
|
||||
// receive interrupts when current transfer complete
|
||||
setEPINTENSET(ep, sam.USB_DEVICE_EPINTENSET_TRCPT0)
|
||||
|
||||
// set byte count to zero, we have not received anything yet
|
||||
usbEndpointDescriptors[ep].DeviceDescBank[0].PCKSIZE.ClearBits(usb_DEVICE_PCKSIZE_BYTE_COUNT_Mask << usb_DEVICE_PCKSIZE_BYTE_COUNT_Pos)
|
||||
|
||||
// ready for next transfer
|
||||
setEPSTATUSCLR(ep, sam.USB_DEVICE_EPSTATUSCLR_BK0RDY)
|
||||
|
||||
case usb.ENDPOINT_TYPE_INTERRUPT | usb.EndpointOut:
|
||||
// TODO: not really anything, seems like...
|
||||
|
||||
case usb.ENDPOINT_TYPE_BULK | usb.EndpointIn:
|
||||
// set packet size
|
||||
usbEndpointDescriptors[ep].DeviceDescBank[1].PCKSIZE.SetBits(epPacketSize(64) << usb_DEVICE_PCKSIZE_SIZE_Pos)
|
||||
|
||||
// set data buffer address
|
||||
usbEndpointDescriptors[ep].DeviceDescBank[1].ADDR.Set(uint32(uintptr(unsafe.Pointer(&udd_ep_in_cache_buffer[ep]))))
|
||||
|
||||
// set endpoint type
|
||||
setEPCFG(ep, ((usb.ENDPOINT_TYPE_BULK + 1) << sam.USB_DEVICE_EPCFG_EPTYPE1_Pos))
|
||||
|
||||
// NAK on endpoint IN, the bank is not yet filled in.
|
||||
setEPSTATUSCLR(ep, sam.USB_DEVICE_EPSTATUSCLR_BK1RDY)
|
||||
|
||||
setEPINTENSET(ep, sam.USB_DEVICE_EPINTENSET_TRCPT1)
|
||||
|
||||
case usb.ENDPOINT_TYPE_CONTROL:
|
||||
// Control OUT
|
||||
// set packet size
|
||||
usbEndpointDescriptors[ep].DeviceDescBank[0].PCKSIZE.SetBits(epPacketSize(64) << usb_DEVICE_PCKSIZE_SIZE_Pos)
|
||||
|
||||
// set data buffer address
|
||||
usbEndpointDescriptors[ep].DeviceDescBank[0].ADDR.Set(uint32(uintptr(unsafe.Pointer(&udd_ep_out_cache_buffer[ep]))))
|
||||
|
||||
// set endpoint type
|
||||
setEPCFG(ep, getEPCFG(ep)|((usb.ENDPOINT_TYPE_CONTROL+1)<<sam.USB_DEVICE_EPCFG_EPTYPE0_Pos))
|
||||
|
||||
// Control IN
|
||||
// set packet size
|
||||
usbEndpointDescriptors[ep].DeviceDescBank[1].PCKSIZE.SetBits(epPacketSize(64) << usb_DEVICE_PCKSIZE_SIZE_Pos)
|
||||
|
||||
// set data buffer address
|
||||
usbEndpointDescriptors[ep].DeviceDescBank[1].ADDR.Set(uint32(uintptr(unsafe.Pointer(&udd_ep_in_cache_buffer[ep]))))
|
||||
|
||||
// set endpoint type
|
||||
setEPCFG(ep, getEPCFG(ep)|((usb.ENDPOINT_TYPE_CONTROL+1)<<sam.USB_DEVICE_EPCFG_EPTYPE1_Pos))
|
||||
|
||||
// Prepare OUT endpoint for receive
|
||||
// set multi packet size for expected number of receive bytes on control OUT
|
||||
usbEndpointDescriptors[ep].DeviceDescBank[0].PCKSIZE.SetBits(64 << usb_DEVICE_PCKSIZE_MULTI_PACKET_SIZE_Pos)
|
||||
|
||||
// set byte count to zero, we have not received anything yet
|
||||
usbEndpointDescriptors[ep].DeviceDescBank[0].PCKSIZE.ClearBits(usb_DEVICE_PCKSIZE_BYTE_COUNT_Mask << usb_DEVICE_PCKSIZE_BYTE_COUNT_Pos)
|
||||
|
||||
// NAK on endpoint OUT to show we are ready to receive control data
|
||||
setEPSTATUSSET(ep, sam.USB_DEVICE_EPSTATUSSET_BK0RDY)
|
||||
|
||||
// Enable Setup-Received interrupt
|
||||
setEPINTENSET(0, sam.USB_DEVICE_EPINTENSET_RXSTP)
|
||||
}
|
||||
}
|
||||
|
||||
func handleUSBSetAddress(setup usb.Setup) bool {
|
||||
// set packet size 64 with auto Zlp after transfer
|
||||
usbEndpointDescriptors[0].DeviceDescBank[1].PCKSIZE.Set((epPacketSize(64) << usb_DEVICE_PCKSIZE_SIZE_Pos) |
|
||||
uint32(1<<31)) // autozlp
|
||||
|
||||
// ack the transfer is complete from the request
|
||||
setEPINTFLAG(0, sam.USB_DEVICE_EPINTFLAG_TRCPT1)
|
||||
|
||||
// set bank ready for data
|
||||
setEPSTATUSSET(0, sam.USB_DEVICE_EPSTATUSSET_BK1RDY)
|
||||
|
||||
// wait for transfer to complete
|
||||
timeout := 3000
|
||||
for (getEPINTFLAG(0) & sam.USB_DEVICE_EPINTFLAG_TRCPT1) == 0 {
|
||||
timeout--
|
||||
if timeout == 0 {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
// last, set the device address to that requested by host
|
||||
sam.USB_DEVICE.DADD.SetBits(setup.WValueL)
|
||||
sam.USB_DEVICE.DADD.SetBits(sam.USB_DEVICE_DADD_ADDEN)
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
// SendUSBInPacket sends a packet for USB (interrupt in / bulk in).
|
||||
func SendUSBInPacket(ep uint32, data []byte) bool {
|
||||
sendUSBPacket(ep, data, 0)
|
||||
|
||||
// clear transfer complete flag
|
||||
setEPINTFLAG(ep, sam.USB_DEVICE_EPINTFLAG_TRCPT1)
|
||||
|
||||
// send data by setting bank ready
|
||||
setEPSTATUSSET(ep, sam.USB_DEVICE_EPSTATUSSET_BK1RDY)
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
//go:noinline
|
||||
func sendUSBPacket(ep uint32, data []byte, maxsize uint16) {
|
||||
l := uint16(len(data))
|
||||
if 0 < maxsize && maxsize < l {
|
||||
l = maxsize
|
||||
}
|
||||
|
||||
// Set endpoint address for sending data
|
||||
if ep == 0 {
|
||||
copy(udd_ep_control_cache_buffer[:], data[:l])
|
||||
usbEndpointDescriptors[ep].DeviceDescBank[1].ADDR.Set(uint32(uintptr(unsafe.Pointer(&udd_ep_control_cache_buffer))))
|
||||
} else {
|
||||
copy(udd_ep_in_cache_buffer[ep][:], data[:l])
|
||||
usbEndpointDescriptors[ep].DeviceDescBank[1].ADDR.Set(uint32(uintptr(unsafe.Pointer(&udd_ep_in_cache_buffer[ep]))))
|
||||
}
|
||||
|
||||
// clear multi-packet size which is total bytes already sent
|
||||
usbEndpointDescriptors[ep].DeviceDescBank[1].PCKSIZE.ClearBits(usb_DEVICE_PCKSIZE_MULTI_PACKET_SIZE_Mask << usb_DEVICE_PCKSIZE_MULTI_PACKET_SIZE_Pos)
|
||||
|
||||
// set byte count, which is total number of bytes to be sent
|
||||
usbEndpointDescriptors[ep].DeviceDescBank[1].PCKSIZE.ClearBits(usb_DEVICE_PCKSIZE_BYTE_COUNT_Mask << usb_DEVICE_PCKSIZE_BYTE_COUNT_Pos)
|
||||
usbEndpointDescriptors[ep].DeviceDescBank[1].PCKSIZE.SetBits((uint32(l) & usb_DEVICE_PCKSIZE_BYTE_COUNT_Mask) << usb_DEVICE_PCKSIZE_BYTE_COUNT_Pos)
|
||||
}
|
||||
|
||||
func ReceiveUSBControlPacket() ([cdcLineInfoSize]byte, error) {
|
||||
var b [cdcLineInfoSize]byte
|
||||
|
||||
// address
|
||||
usbEndpointDescriptors[0].DeviceDescBank[0].ADDR.Set(uint32(uintptr(unsafe.Pointer(&udd_ep_out_cache_buffer[0]))))
|
||||
|
||||
// set byte count to zero
|
||||
usbEndpointDescriptors[0].DeviceDescBank[0].PCKSIZE.ClearBits(usb_DEVICE_PCKSIZE_BYTE_COUNT_Mask << usb_DEVICE_PCKSIZE_BYTE_COUNT_Pos)
|
||||
|
||||
// set ready for next data
|
||||
setEPSTATUSCLR(0, sam.USB_DEVICE_EPSTATUSCLR_BK0RDY)
|
||||
|
||||
// Wait until OUT transfer is ready.
|
||||
timeout := 300000
|
||||
for (getEPSTATUS(0) & sam.USB_DEVICE_EPSTATUS_BK0RDY) == 0 {
|
||||
timeout--
|
||||
if timeout == 0 {
|
||||
return b, ErrUSBReadTimeout
|
||||
}
|
||||
}
|
||||
|
||||
// Wait until OUT transfer is completed.
|
||||
timeout = 300000
|
||||
for (getEPINTFLAG(0) & sam.USB_DEVICE_EPINTFLAG_TRCPT0) == 0 {
|
||||
timeout--
|
||||
if timeout == 0 {
|
||||
return b, ErrUSBReadTimeout
|
||||
}
|
||||
}
|
||||
|
||||
// get data
|
||||
bytesread := uint32((usbEndpointDescriptors[0].DeviceDescBank[0].PCKSIZE.Get() >>
|
||||
usb_DEVICE_PCKSIZE_BYTE_COUNT_Pos) & usb_DEVICE_PCKSIZE_BYTE_COUNT_Mask)
|
||||
|
||||
if bytesread != cdcLineInfoSize {
|
||||
return b, ErrUSBBytesRead
|
||||
}
|
||||
|
||||
copy(b[:7], udd_ep_out_cache_buffer[0][:7])
|
||||
|
||||
return b, nil
|
||||
}
|
||||
|
||||
func handleEndpointRx(ep uint32) []byte {
|
||||
// get data
|
||||
count := int((usbEndpointDescriptors[ep].DeviceDescBank[0].PCKSIZE.Get() >>
|
||||
usb_DEVICE_PCKSIZE_BYTE_COUNT_Pos) & usb_DEVICE_PCKSIZE_BYTE_COUNT_Mask)
|
||||
|
||||
return udd_ep_out_cache_buffer[ep][:count]
|
||||
}
|
||||
|
||||
func handleEndpointRxComplete(ep uint32) {
|
||||
// set byte count to zero
|
||||
usbEndpointDescriptors[ep].DeviceDescBank[0].PCKSIZE.ClearBits(usb_DEVICE_PCKSIZE_BYTE_COUNT_Mask << usb_DEVICE_PCKSIZE_BYTE_COUNT_Pos)
|
||||
|
||||
// set multi packet size to 64
|
||||
usbEndpointDescriptors[ep].DeviceDescBank[0].PCKSIZE.SetBits(64 << usb_DEVICE_PCKSIZE_MULTI_PACKET_SIZE_Pos)
|
||||
|
||||
// set ready for next data
|
||||
setEPSTATUSCLR(ep, sam.USB_DEVICE_EPSTATUSCLR_BK0RDY)
|
||||
|
||||
}
|
||||
|
||||
func SendZlp() {
|
||||
usbEndpointDescriptors[0].DeviceDescBank[1].PCKSIZE.ClearBits(usb_DEVICE_PCKSIZE_BYTE_COUNT_Mask << usb_DEVICE_PCKSIZE_BYTE_COUNT_Pos)
|
||||
}
|
||||
|
||||
func epPacketSize(size uint16) uint32 {
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
func getEPCFG(ep uint32) uint8 {
|
||||
switch ep {
|
||||
case 0:
|
||||
return sam.USB_DEVICE.EPCFG0.Get()
|
||||
case 1:
|
||||
return sam.USB_DEVICE.EPCFG1.Get()
|
||||
case 2:
|
||||
return sam.USB_DEVICE.EPCFG2.Get()
|
||||
case 3:
|
||||
return sam.USB_DEVICE.EPCFG3.Get()
|
||||
case 4:
|
||||
return sam.USB_DEVICE.EPCFG4.Get()
|
||||
case 5:
|
||||
return sam.USB_DEVICE.EPCFG5.Get()
|
||||
case 6:
|
||||
return sam.USB_DEVICE.EPCFG6.Get()
|
||||
case 7:
|
||||
return sam.USB_DEVICE.EPCFG7.Get()
|
||||
default:
|
||||
return 0
|
||||
}
|
||||
}
|
||||
|
||||
func setEPCFG(ep uint32, val uint8) {
|
||||
switch ep {
|
||||
case 0:
|
||||
sam.USB_DEVICE.EPCFG0.Set(val)
|
||||
case 1:
|
||||
sam.USB_DEVICE.EPCFG1.Set(val)
|
||||
case 2:
|
||||
sam.USB_DEVICE.EPCFG2.Set(val)
|
||||
case 3:
|
||||
sam.USB_DEVICE.EPCFG3.Set(val)
|
||||
case 4:
|
||||
sam.USB_DEVICE.EPCFG4.Set(val)
|
||||
case 5:
|
||||
sam.USB_DEVICE.EPCFG5.Set(val)
|
||||
case 6:
|
||||
sam.USB_DEVICE.EPCFG6.Set(val)
|
||||
case 7:
|
||||
sam.USB_DEVICE.EPCFG7.Set(val)
|
||||
default:
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
func setEPSTATUSCLR(ep uint32, val uint8) {
|
||||
switch ep {
|
||||
case 0:
|
||||
sam.USB_DEVICE.EPSTATUSCLR0.Set(val)
|
||||
case 1:
|
||||
sam.USB_DEVICE.EPSTATUSCLR1.Set(val)
|
||||
case 2:
|
||||
sam.USB_DEVICE.EPSTATUSCLR2.Set(val)
|
||||
case 3:
|
||||
sam.USB_DEVICE.EPSTATUSCLR3.Set(val)
|
||||
case 4:
|
||||
sam.USB_DEVICE.EPSTATUSCLR4.Set(val)
|
||||
case 5:
|
||||
sam.USB_DEVICE.EPSTATUSCLR5.Set(val)
|
||||
case 6:
|
||||
sam.USB_DEVICE.EPSTATUSCLR6.Set(val)
|
||||
case 7:
|
||||
sam.USB_DEVICE.EPSTATUSCLR7.Set(val)
|
||||
default:
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
func setEPSTATUSSET(ep uint32, val uint8) {
|
||||
switch ep {
|
||||
case 0:
|
||||
sam.USB_DEVICE.EPSTATUSSET0.Set(val)
|
||||
case 1:
|
||||
sam.USB_DEVICE.EPSTATUSSET1.Set(val)
|
||||
case 2:
|
||||
sam.USB_DEVICE.EPSTATUSSET2.Set(val)
|
||||
case 3:
|
||||
sam.USB_DEVICE.EPSTATUSSET3.Set(val)
|
||||
case 4:
|
||||
sam.USB_DEVICE.EPSTATUSSET4.Set(val)
|
||||
case 5:
|
||||
sam.USB_DEVICE.EPSTATUSSET5.Set(val)
|
||||
case 6:
|
||||
sam.USB_DEVICE.EPSTATUSSET6.Set(val)
|
||||
case 7:
|
||||
sam.USB_DEVICE.EPSTATUSSET7.Set(val)
|
||||
default:
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
func getEPSTATUS(ep uint32) uint8 {
|
||||
switch ep {
|
||||
case 0:
|
||||
return sam.USB_DEVICE.EPSTATUS0.Get()
|
||||
case 1:
|
||||
return sam.USB_DEVICE.EPSTATUS1.Get()
|
||||
case 2:
|
||||
return sam.USB_DEVICE.EPSTATUS2.Get()
|
||||
case 3:
|
||||
return sam.USB_DEVICE.EPSTATUS3.Get()
|
||||
case 4:
|
||||
return sam.USB_DEVICE.EPSTATUS4.Get()
|
||||
case 5:
|
||||
return sam.USB_DEVICE.EPSTATUS5.Get()
|
||||
case 6:
|
||||
return sam.USB_DEVICE.EPSTATUS6.Get()
|
||||
case 7:
|
||||
return sam.USB_DEVICE.EPSTATUS7.Get()
|
||||
default:
|
||||
return 0
|
||||
}
|
||||
}
|
||||
|
||||
func getEPINTFLAG(ep uint32) uint8 {
|
||||
switch ep {
|
||||
case 0:
|
||||
return sam.USB_DEVICE.EPINTFLAG0.Get()
|
||||
case 1:
|
||||
return sam.USB_DEVICE.EPINTFLAG1.Get()
|
||||
case 2:
|
||||
return sam.USB_DEVICE.EPINTFLAG2.Get()
|
||||
case 3:
|
||||
return sam.USB_DEVICE.EPINTFLAG3.Get()
|
||||
case 4:
|
||||
return sam.USB_DEVICE.EPINTFLAG4.Get()
|
||||
case 5:
|
||||
return sam.USB_DEVICE.EPINTFLAG5.Get()
|
||||
case 6:
|
||||
return sam.USB_DEVICE.EPINTFLAG6.Get()
|
||||
case 7:
|
||||
return sam.USB_DEVICE.EPINTFLAG7.Get()
|
||||
default:
|
||||
return 0
|
||||
}
|
||||
}
|
||||
|
||||
func setEPINTFLAG(ep uint32, val uint8) {
|
||||
switch ep {
|
||||
case 0:
|
||||
sam.USB_DEVICE.EPINTFLAG0.Set(val)
|
||||
case 1:
|
||||
sam.USB_DEVICE.EPINTFLAG1.Set(val)
|
||||
case 2:
|
||||
sam.USB_DEVICE.EPINTFLAG2.Set(val)
|
||||
case 3:
|
||||
sam.USB_DEVICE.EPINTFLAG3.Set(val)
|
||||
case 4:
|
||||
sam.USB_DEVICE.EPINTFLAG4.Set(val)
|
||||
case 5:
|
||||
sam.USB_DEVICE.EPINTFLAG5.Set(val)
|
||||
case 6:
|
||||
sam.USB_DEVICE.EPINTFLAG6.Set(val)
|
||||
case 7:
|
||||
sam.USB_DEVICE.EPINTFLAG7.Set(val)
|
||||
default:
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
func setEPINTENCLR(ep uint32, val uint8) {
|
||||
switch ep {
|
||||
case 0:
|
||||
sam.USB_DEVICE.EPINTENCLR0.Set(val)
|
||||
case 1:
|
||||
sam.USB_DEVICE.EPINTENCLR1.Set(val)
|
||||
case 2:
|
||||
sam.USB_DEVICE.EPINTENCLR2.Set(val)
|
||||
case 3:
|
||||
sam.USB_DEVICE.EPINTENCLR3.Set(val)
|
||||
case 4:
|
||||
sam.USB_DEVICE.EPINTENCLR4.Set(val)
|
||||
case 5:
|
||||
sam.USB_DEVICE.EPINTENCLR5.Set(val)
|
||||
case 6:
|
||||
sam.USB_DEVICE.EPINTENCLR6.Set(val)
|
||||
case 7:
|
||||
sam.USB_DEVICE.EPINTENCLR7.Set(val)
|
||||
default:
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
func setEPINTENSET(ep uint32, val uint8) {
|
||||
switch ep {
|
||||
case 0:
|
||||
sam.USB_DEVICE.EPINTENSET0.Set(val)
|
||||
case 1:
|
||||
sam.USB_DEVICE.EPINTENSET1.Set(val)
|
||||
case 2:
|
||||
sam.USB_DEVICE.EPINTENSET2.Set(val)
|
||||
case 3:
|
||||
sam.USB_DEVICE.EPINTENSET3.Set(val)
|
||||
case 4:
|
||||
sam.USB_DEVICE.EPINTENSET4.Set(val)
|
||||
case 5:
|
||||
sam.USB_DEVICE.EPINTENSET5.Set(val)
|
||||
case 6:
|
||||
sam.USB_DEVICE.EPINTENSET6.Set(val)
|
||||
case 7:
|
||||
sam.USB_DEVICE.EPINTENSET7.Set(val)
|
||||
default:
|
||||
return
|
||||
}
|
||||
}
|
||||
+47
-780
@@ -13,7 +13,6 @@ import (
|
||||
"device/sam"
|
||||
"errors"
|
||||
"runtime/interrupt"
|
||||
"runtime/volatile"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
@@ -1975,762 +1974,9 @@ func (tcc *TCC) Set(channel uint8, value uint32) {
|
||||
}
|
||||
}
|
||||
|
||||
// USBCDC is the USB CDC aka serial over USB interface on the SAMD21.
|
||||
type USBCDC struct {
|
||||
Buffer *RingBuffer
|
||||
TxIdx volatile.Register8
|
||||
waitTxc bool
|
||||
waitTxcRetryCount uint8
|
||||
sent bool
|
||||
configured bool
|
||||
}
|
||||
|
||||
var (
|
||||
// USB is a USB CDC interface.
|
||||
USB = &USBCDC{Buffer: NewRingBuffer()}
|
||||
waitHidTxc bool
|
||||
)
|
||||
|
||||
const (
|
||||
usbcdcTxSizeMask uint8 = 0x3F
|
||||
usbcdcTxBankMask uint8 = ^usbcdcTxSizeMask
|
||||
usbcdcTxBank1st uint8 = 0x00
|
||||
usbcdcTxBank2nd uint8 = usbcdcTxSizeMask + 1
|
||||
usbcdcTxMaxRetriesAllowed uint8 = 5
|
||||
)
|
||||
|
||||
// Flush flushes buffered data.
|
||||
func (usbcdc *USBCDC) Flush() error {
|
||||
if usbLineInfo.lineState > 0 {
|
||||
idx := usbcdc.TxIdx.Get()
|
||||
sz := idx & usbcdcTxSizeMask
|
||||
bk := idx & usbcdcTxBankMask
|
||||
if 0 < sz {
|
||||
|
||||
if usbcdc.waitTxc {
|
||||
// waiting for the next flush(), because the transmission is not complete
|
||||
usbcdc.waitTxcRetryCount++
|
||||
return nil
|
||||
}
|
||||
usbcdc.waitTxc = true
|
||||
usbcdc.waitTxcRetryCount = 0
|
||||
|
||||
// set the data
|
||||
usbEndpointDescriptors[usb_CDC_ENDPOINT_IN].DeviceDescBank[1].ADDR.Set(uint32(uintptr(unsafe.Pointer(&udd_ep_in_cache_buffer[usb_CDC_ENDPOINT_IN][bk]))))
|
||||
if bk == usbcdcTxBank1st {
|
||||
usbcdc.TxIdx.Set(usbcdcTxBank2nd)
|
||||
} else {
|
||||
usbcdc.TxIdx.Set(usbcdcTxBank1st)
|
||||
}
|
||||
|
||||
// clean multi packet size of bytes already sent
|
||||
usbEndpointDescriptors[usb_CDC_ENDPOINT_IN].DeviceDescBank[1].PCKSIZE.ClearBits(usb_DEVICE_PCKSIZE_MULTI_PACKET_SIZE_Mask << usb_DEVICE_PCKSIZE_MULTI_PACKET_SIZE_Pos)
|
||||
|
||||
// set count of bytes to be sent
|
||||
usbEndpointDescriptors[usb_CDC_ENDPOINT_IN].DeviceDescBank[1].PCKSIZE.ClearBits(usb_DEVICE_PCKSIZE_BYTE_COUNT_Mask << usb_DEVICE_PCKSIZE_BYTE_COUNT_Pos)
|
||||
usbEndpointDescriptors[usb_CDC_ENDPOINT_IN].DeviceDescBank[1].PCKSIZE.SetBits((uint32(sz) & usb_DEVICE_PCKSIZE_BYTE_COUNT_Mask) << usb_DEVICE_PCKSIZE_BYTE_COUNT_Pos)
|
||||
|
||||
// clear transfer complete flag
|
||||
setEPINTFLAG(usb_CDC_ENDPOINT_IN, sam.USB_DEVICE_ENDPOINT_EPINTFLAG_TRCPT1)
|
||||
|
||||
// send data by setting bank ready
|
||||
setEPSTATUSSET(usb_CDC_ENDPOINT_IN, sam.USB_DEVICE_ENDPOINT_EPSTATUSSET_BK1RDY)
|
||||
usbcdc.sent = true
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// WriteByte writes a byte of data to the USB CDC interface.
|
||||
func (usbcdc *USBCDC) WriteByte(c byte) error {
|
||||
// Supposedly to handle problem with Windows USB serial ports?
|
||||
if usbLineInfo.lineState > 0 {
|
||||
ok := false
|
||||
for {
|
||||
mask := interrupt.Disable()
|
||||
|
||||
idx := usbcdc.TxIdx.Get()
|
||||
if (idx & usbcdcTxSizeMask) < usbcdcTxSizeMask {
|
||||
udd_ep_in_cache_buffer[usb_CDC_ENDPOINT_IN][idx] = c
|
||||
usbcdc.TxIdx.Set(idx + 1)
|
||||
ok = true
|
||||
}
|
||||
|
||||
interrupt.Restore(mask)
|
||||
|
||||
if ok {
|
||||
break
|
||||
} else if usbcdcTxMaxRetriesAllowed < usbcdc.waitTxcRetryCount {
|
||||
mask := interrupt.Disable()
|
||||
usbcdc.waitTxc = false
|
||||
usbcdc.waitTxcRetryCount = 0
|
||||
usbcdc.TxIdx.Set(0)
|
||||
usbLineInfo.lineState = 0
|
||||
interrupt.Restore(mask)
|
||||
break
|
||||
} else {
|
||||
mask := interrupt.Disable()
|
||||
if usbcdc.sent {
|
||||
if usbcdc.waitTxc {
|
||||
if (getEPINTFLAG(usb_CDC_ENDPOINT_IN) & sam.USB_DEVICE_ENDPOINT_EPINTFLAG_TRCPT1) != 0 {
|
||||
setEPSTATUSCLR(usb_CDC_ENDPOINT_IN, sam.USB_DEVICE_ENDPOINT_EPSTATUSCLR_BK1RDY)
|
||||
setEPINTFLAG(usb_CDC_ENDPOINT_IN, sam.USB_DEVICE_ENDPOINT_EPINTFLAG_TRCPT1)
|
||||
usbcdc.waitTxc = false
|
||||
usbcdc.Flush()
|
||||
}
|
||||
} else {
|
||||
usbcdc.Flush()
|
||||
}
|
||||
}
|
||||
interrupt.Restore(mask)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (usbcdc *USBCDC) DTR() bool {
|
||||
return (usbLineInfo.lineState & usb_CDC_LINESTATE_DTR) > 0
|
||||
}
|
||||
|
||||
func (usbcdc *USBCDC) RTS() bool {
|
||||
return (usbLineInfo.lineState & usb_CDC_LINESTATE_RTS) > 0
|
||||
}
|
||||
|
||||
const (
|
||||
// these are SAMD51 specific.
|
||||
usb_DEVICE_PCKSIZE_BYTE_COUNT_Pos = 0
|
||||
usb_DEVICE_PCKSIZE_BYTE_COUNT_Mask = 0x3FFF
|
||||
|
||||
usb_DEVICE_PCKSIZE_SIZE_Pos = 28
|
||||
usb_DEVICE_PCKSIZE_SIZE_Mask = 0x7
|
||||
|
||||
usb_DEVICE_PCKSIZE_MULTI_PACKET_SIZE_Pos = 14
|
||||
usb_DEVICE_PCKSIZE_MULTI_PACKET_SIZE_Mask = 0x3FFF
|
||||
)
|
||||
|
||||
var (
|
||||
usbEndpointDescriptors [8]usbDeviceDescriptor
|
||||
|
||||
udd_ep_in_cache_buffer [7][128]uint8
|
||||
udd_ep_out_cache_buffer [7][128]uint8
|
||||
|
||||
isEndpointHalt = false
|
||||
isRemoteWakeUpEnabled = false
|
||||
endPoints = []uint32{usb_ENDPOINT_TYPE_CONTROL,
|
||||
(usb_ENDPOINT_TYPE_INTERRUPT | usbEndpointIn),
|
||||
(usb_ENDPOINT_TYPE_BULK | usbEndpointOut),
|
||||
(usb_ENDPOINT_TYPE_BULK | usbEndpointIn)}
|
||||
|
||||
usbConfiguration uint8
|
||||
usbSetInterface uint8
|
||||
usbLineInfo = cdcLineInfo{115200, 0x00, 0x00, 0x08, 0x00}
|
||||
)
|
||||
|
||||
// Configure the USB CDC interface. The config is here for compatibility with the UART interface.
|
||||
func (usbcdc *USBCDC) Configure(config UARTConfig) {
|
||||
// reset USB interface
|
||||
sam.USB_DEVICE.CTRLA.SetBits(sam.USB_DEVICE_CTRLA_SWRST)
|
||||
for sam.USB_DEVICE.SYNCBUSY.HasBits(sam.USB_DEVICE_SYNCBUSY_SWRST) ||
|
||||
sam.USB_DEVICE.SYNCBUSY.HasBits(sam.USB_DEVICE_SYNCBUSY_ENABLE) {
|
||||
}
|
||||
|
||||
sam.USB_DEVICE.DESCADD.Set(uint32(uintptr(unsafe.Pointer(&usbEndpointDescriptors))))
|
||||
|
||||
// configure pins
|
||||
USBCDC_DM_PIN.Configure(PinConfig{Mode: PinCom})
|
||||
USBCDC_DP_PIN.Configure(PinConfig{Mode: PinCom})
|
||||
|
||||
// performs pad calibration from store fuses
|
||||
handlePadCalibration()
|
||||
|
||||
// run in standby
|
||||
sam.USB_DEVICE.CTRLA.SetBits(sam.USB_DEVICE_CTRLA_RUNSTDBY)
|
||||
|
||||
// set full speed
|
||||
sam.USB_DEVICE.CTRLB.SetBits(sam.USB_DEVICE_CTRLB_SPDCONF_FS << sam.USB_DEVICE_CTRLB_SPDCONF_Pos)
|
||||
|
||||
// attach
|
||||
sam.USB_DEVICE.CTRLB.ClearBits(sam.USB_DEVICE_CTRLB_DETACH)
|
||||
|
||||
// enable interrupt for end of reset
|
||||
sam.USB_DEVICE.INTENSET.SetBits(sam.USB_DEVICE_INTENSET_EORST)
|
||||
|
||||
// enable interrupt for start of frame
|
||||
sam.USB_DEVICE.INTENSET.SetBits(sam.USB_DEVICE_INTENSET_SOF)
|
||||
|
||||
// enable USB
|
||||
sam.USB_DEVICE.CTRLA.SetBits(sam.USB_DEVICE_CTRLA_ENABLE)
|
||||
|
||||
// enable IRQ at highest priority
|
||||
interrupt.New(sam.IRQ_USB_OTHER, handleUSBIRQ).Enable()
|
||||
interrupt.New(sam.IRQ_USB_SOF_HSOF, handleUSBIRQ).Enable()
|
||||
interrupt.New(sam.IRQ_USB_TRCPT0, handleUSBIRQ).Enable()
|
||||
interrupt.New(sam.IRQ_USB_TRCPT1, handleUSBIRQ).Enable()
|
||||
|
||||
usbcdc.configured = true
|
||||
}
|
||||
|
||||
// Configured returns whether usbcdc is configured or not.
|
||||
func (usbcdc *USBCDC) Configured() bool {
|
||||
return usbcdc.configured
|
||||
}
|
||||
|
||||
func handlePadCalibration() {
|
||||
// Load Pad Calibration data from non-volatile memory
|
||||
// This requires registers that are not included in the SVD file.
|
||||
// Modeled after defines from samd21g18a.h and nvmctrl.h:
|
||||
//
|
||||
// #define NVMCTRL_OTP4 0x00806020
|
||||
//
|
||||
// #define USB_FUSES_TRANSN_ADDR (NVMCTRL_OTP4 + 4)
|
||||
// #define USB_FUSES_TRANSN_Pos 13 /**< \brief (NVMCTRL_OTP4) USB pad Transn calibration */
|
||||
// #define USB_FUSES_TRANSN_Msk (0x1Fu << USB_FUSES_TRANSN_Pos)
|
||||
// #define USB_FUSES_TRANSN(value) ((USB_FUSES_TRANSN_Msk & ((value) << USB_FUSES_TRANSN_Pos)))
|
||||
|
||||
// #define USB_FUSES_TRANSP_ADDR (NVMCTRL_OTP4 + 4)
|
||||
// #define USB_FUSES_TRANSP_Pos 18 /**< \brief (NVMCTRL_OTP4) USB pad Transp calibration */
|
||||
// #define USB_FUSES_TRANSP_Msk (0x1Fu << USB_FUSES_TRANSP_Pos)
|
||||
// #define USB_FUSES_TRANSP(value) ((USB_FUSES_TRANSP_Msk & ((value) << USB_FUSES_TRANSP_Pos)))
|
||||
|
||||
// #define USB_FUSES_TRIM_ADDR (NVMCTRL_OTP4 + 4)
|
||||
// #define USB_FUSES_TRIM_Pos 23 /**< \brief (NVMCTRL_OTP4) USB pad Trim calibration */
|
||||
// #define USB_FUSES_TRIM_Msk (0x7u << USB_FUSES_TRIM_Pos)
|
||||
// #define USB_FUSES_TRIM(value) ((USB_FUSES_TRIM_Msk & ((value) << USB_FUSES_TRIM_Pos)))
|
||||
//
|
||||
fuse := *(*uint32)(unsafe.Pointer(uintptr(0x00806020) + 4))
|
||||
calibTransN := uint16(fuse>>13) & uint16(0x1f)
|
||||
calibTransP := uint16(fuse>>18) & uint16(0x1f)
|
||||
calibTrim := uint16(fuse>>23) & uint16(0x7)
|
||||
|
||||
if calibTransN == 0x1f {
|
||||
calibTransN = 5
|
||||
}
|
||||
sam.USB_DEVICE.PADCAL.SetBits(calibTransN << sam.USB_DEVICE_PADCAL_TRANSN_Pos)
|
||||
|
||||
if calibTransP == 0x1f {
|
||||
calibTransP = 29
|
||||
}
|
||||
sam.USB_DEVICE.PADCAL.SetBits(calibTransP << sam.USB_DEVICE_PADCAL_TRANSP_Pos)
|
||||
|
||||
if calibTrim == 0x7 {
|
||||
calibTrim = 3
|
||||
}
|
||||
sam.USB_DEVICE.PADCAL.SetBits(calibTrim << sam.USB_DEVICE_PADCAL_TRIM_Pos)
|
||||
}
|
||||
|
||||
func handleUSBIRQ(interrupt.Interrupt) {
|
||||
// reset all interrupt flags
|
||||
flags := sam.USB_DEVICE.INTFLAG.Get()
|
||||
sam.USB_DEVICE.INTFLAG.Set(flags)
|
||||
|
||||
// End of reset
|
||||
if (flags & sam.USB_DEVICE_INTFLAG_EORST) > 0 {
|
||||
// Configure control endpoint
|
||||
initEndpoint(0, usb_ENDPOINT_TYPE_CONTROL)
|
||||
|
||||
// Enable Setup-Received interrupt
|
||||
setEPINTENSET(0, sam.USB_DEVICE_ENDPOINT_EPINTENSET_RXSTP)
|
||||
|
||||
usbConfiguration = 0
|
||||
|
||||
// ack the End-Of-Reset interrupt
|
||||
sam.USB_DEVICE.INTFLAG.Set(sam.USB_DEVICE_INTFLAG_EORST)
|
||||
}
|
||||
|
||||
// Start of frame
|
||||
if (flags & sam.USB_DEVICE_INTFLAG_SOF) > 0 {
|
||||
USB.Flush()
|
||||
if hidCallback != nil && !waitHidTxc {
|
||||
hidCallback()
|
||||
}
|
||||
// if you want to blink LED showing traffic, this would be the place...
|
||||
}
|
||||
|
||||
// Endpoint 0 Setup interrupt
|
||||
if getEPINTFLAG(0)&sam.USB_DEVICE_ENDPOINT_EPINTFLAG_RXSTP > 0 {
|
||||
// ack setup received
|
||||
setEPINTFLAG(0, sam.USB_DEVICE_ENDPOINT_EPINTFLAG_RXSTP)
|
||||
|
||||
// parse setup
|
||||
setup := newUSBSetup(udd_ep_out_cache_buffer[0][:])
|
||||
|
||||
// Clear the Bank 0 ready flag on Control OUT
|
||||
setEPSTATUSCLR(0, sam.USB_DEVICE_ENDPOINT_EPSTATUSCLR_BK0RDY)
|
||||
usbEndpointDescriptors[0].DeviceDescBank[0].PCKSIZE.ClearBits(usb_DEVICE_PCKSIZE_BYTE_COUNT_Mask << usb_DEVICE_PCKSIZE_BYTE_COUNT_Pos)
|
||||
|
||||
ok := false
|
||||
if (setup.bmRequestType & usb_REQUEST_TYPE) == usb_REQUEST_STANDARD {
|
||||
// Standard Requests
|
||||
ok = handleStandardSetup(setup)
|
||||
} else {
|
||||
// Class Interface Requests
|
||||
if setup.wIndex == usb_CDC_ACM_INTERFACE {
|
||||
ok = cdcSetup(setup)
|
||||
} else if setup.bmRequestType == usb_SET_REPORT_TYPE && setup.bRequest == usb_SET_IDLE {
|
||||
sendZlp()
|
||||
ok = true
|
||||
}
|
||||
}
|
||||
|
||||
if ok {
|
||||
// set Bank1 ready
|
||||
setEPSTATUSSET(0, sam.USB_DEVICE_ENDPOINT_EPSTATUSSET_BK1RDY)
|
||||
} else {
|
||||
// Stall endpoint
|
||||
setEPSTATUSSET(0, sam.USB_DEVICE_ENDPOINT_EPINTFLAG_STALL1)
|
||||
}
|
||||
|
||||
if getEPINTFLAG(0)&sam.USB_DEVICE_ENDPOINT_EPINTFLAG_STALL1 > 0 {
|
||||
// ack the stall
|
||||
setEPINTFLAG(0, sam.USB_DEVICE_ENDPOINT_EPINTFLAG_STALL1)
|
||||
|
||||
// clear stall request
|
||||
setEPINTENCLR(0, sam.USB_DEVICE_ENDPOINT_EPINTENCLR_STALL1)
|
||||
}
|
||||
}
|
||||
|
||||
// Now the actual transfer handlers, ignore endpoint number 0 (setup)
|
||||
var i uint32
|
||||
for i = 1; i < uint32(len(endPoints)); i++ {
|
||||
// Check if endpoint has a pending interrupt
|
||||
epFlags := getEPINTFLAG(i)
|
||||
if (epFlags&sam.USB_DEVICE_ENDPOINT_EPINTFLAG_TRCPT0) > 0 ||
|
||||
(epFlags&sam.USB_DEVICE_ENDPOINT_EPINTFLAG_TRCPT1) > 0 {
|
||||
switch i {
|
||||
case usb_CDC_ENDPOINT_OUT:
|
||||
handleEndpoint(i)
|
||||
setEPINTFLAG(i, epFlags)
|
||||
case usb_CDC_ENDPOINT_IN, usb_CDC_ENDPOINT_ACM:
|
||||
setEPSTATUSCLR(i, sam.USB_DEVICE_ENDPOINT_EPSTATUSCLR_BK1RDY)
|
||||
setEPINTFLAG(i, sam.USB_DEVICE_ENDPOINT_EPINTFLAG_TRCPT1)
|
||||
|
||||
if i == usb_CDC_ENDPOINT_IN {
|
||||
USB.waitTxc = false
|
||||
}
|
||||
case usb_HID_ENDPOINT_IN:
|
||||
setEPINTFLAG(i, sam.USB_DEVICE_ENDPOINT_EPINTFLAG_TRCPT1)
|
||||
waitHidTxc = false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func initEndpoint(ep, config uint32) {
|
||||
switch config {
|
||||
case usb_ENDPOINT_TYPE_INTERRUPT | usbEndpointIn:
|
||||
// set packet size
|
||||
usbEndpointDescriptors[ep].DeviceDescBank[1].PCKSIZE.SetBits(epPacketSize(64) << usb_DEVICE_PCKSIZE_SIZE_Pos)
|
||||
|
||||
// set data buffer address
|
||||
usbEndpointDescriptors[ep].DeviceDescBank[1].ADDR.Set(uint32(uintptr(unsafe.Pointer(&udd_ep_in_cache_buffer[ep]))))
|
||||
|
||||
// set endpoint type
|
||||
setEPCFG(ep, ((usb_ENDPOINT_TYPE_INTERRUPT + 1) << sam.USB_DEVICE_ENDPOINT_EPCFG_EPTYPE1_Pos))
|
||||
|
||||
case usb_ENDPOINT_TYPE_BULK | usbEndpointOut:
|
||||
// set packet size
|
||||
usbEndpointDescriptors[ep].DeviceDescBank[0].PCKSIZE.SetBits(epPacketSize(64) << usb_DEVICE_PCKSIZE_SIZE_Pos)
|
||||
|
||||
// set data buffer address
|
||||
usbEndpointDescriptors[ep].DeviceDescBank[0].ADDR.Set(uint32(uintptr(unsafe.Pointer(&udd_ep_out_cache_buffer[ep]))))
|
||||
|
||||
// set endpoint type
|
||||
setEPCFG(ep, ((usb_ENDPOINT_TYPE_BULK + 1) << sam.USB_DEVICE_ENDPOINT_EPCFG_EPTYPE0_Pos))
|
||||
|
||||
// receive interrupts when current transfer complete
|
||||
setEPINTENSET(ep, sam.USB_DEVICE_ENDPOINT_EPINTENSET_TRCPT0)
|
||||
|
||||
// set byte count to zero, we have not received anything yet
|
||||
usbEndpointDescriptors[ep].DeviceDescBank[0].PCKSIZE.ClearBits(usb_DEVICE_PCKSIZE_BYTE_COUNT_Mask << usb_DEVICE_PCKSIZE_BYTE_COUNT_Pos)
|
||||
|
||||
// ready for next transfer
|
||||
setEPSTATUSCLR(ep, sam.USB_DEVICE_ENDPOINT_EPSTATUSCLR_BK0RDY)
|
||||
|
||||
case usb_ENDPOINT_TYPE_INTERRUPT | usbEndpointOut:
|
||||
// TODO: not really anything, seems like...
|
||||
|
||||
case usb_ENDPOINT_TYPE_BULK | usbEndpointIn:
|
||||
// set packet size
|
||||
usbEndpointDescriptors[ep].DeviceDescBank[1].PCKSIZE.SetBits(epPacketSize(64) << usb_DEVICE_PCKSIZE_SIZE_Pos)
|
||||
|
||||
// set data buffer address
|
||||
usbEndpointDescriptors[ep].DeviceDescBank[1].ADDR.Set(uint32(uintptr(unsafe.Pointer(&udd_ep_in_cache_buffer[ep]))))
|
||||
|
||||
// set endpoint type
|
||||
setEPCFG(ep, ((usb_ENDPOINT_TYPE_BULK + 1) << sam.USB_DEVICE_ENDPOINT_EPCFG_EPTYPE1_Pos))
|
||||
|
||||
// NAK on endpoint IN, the bank is not yet filled in.
|
||||
setEPSTATUSCLR(ep, sam.USB_DEVICE_ENDPOINT_EPSTATUSCLR_BK1RDY)
|
||||
|
||||
case usb_ENDPOINT_TYPE_CONTROL:
|
||||
// Control OUT
|
||||
// set packet size
|
||||
usbEndpointDescriptors[ep].DeviceDescBank[0].PCKSIZE.SetBits(epPacketSize(64) << usb_DEVICE_PCKSIZE_SIZE_Pos)
|
||||
|
||||
// set data buffer address
|
||||
usbEndpointDescriptors[ep].DeviceDescBank[0].ADDR.Set(uint32(uintptr(unsafe.Pointer(&udd_ep_out_cache_buffer[ep]))))
|
||||
|
||||
// set endpoint type
|
||||
setEPCFG(ep, getEPCFG(ep)|((usb_ENDPOINT_TYPE_CONTROL+1)<<sam.USB_DEVICE_ENDPOINT_EPCFG_EPTYPE0_Pos))
|
||||
|
||||
// Control IN
|
||||
// set packet size
|
||||
usbEndpointDescriptors[ep].DeviceDescBank[1].PCKSIZE.SetBits(epPacketSize(64) << usb_DEVICE_PCKSIZE_SIZE_Pos)
|
||||
|
||||
// set data buffer address
|
||||
usbEndpointDescriptors[ep].DeviceDescBank[1].ADDR.Set(uint32(uintptr(unsafe.Pointer(&udd_ep_in_cache_buffer[ep]))))
|
||||
|
||||
// set endpoint type
|
||||
setEPCFG(ep, getEPCFG(ep)|((usb_ENDPOINT_TYPE_CONTROL+1)<<sam.USB_DEVICE_ENDPOINT_EPCFG_EPTYPE1_Pos))
|
||||
|
||||
// Prepare OUT endpoint for receive
|
||||
// set multi packet size for expected number of receive bytes on control OUT
|
||||
usbEndpointDescriptors[ep].DeviceDescBank[0].PCKSIZE.SetBits(64 << usb_DEVICE_PCKSIZE_MULTI_PACKET_SIZE_Pos)
|
||||
|
||||
// set byte count to zero, we have not received anything yet
|
||||
usbEndpointDescriptors[ep].DeviceDescBank[0].PCKSIZE.ClearBits(usb_DEVICE_PCKSIZE_BYTE_COUNT_Mask << usb_DEVICE_PCKSIZE_BYTE_COUNT_Pos)
|
||||
|
||||
// NAK on endpoint OUT to show we are ready to receive control data
|
||||
setEPSTATUSSET(ep, sam.USB_DEVICE_ENDPOINT_EPSTATUSSET_BK0RDY)
|
||||
}
|
||||
}
|
||||
|
||||
func handleStandardSetup(setup usbSetup) bool {
|
||||
switch setup.bRequest {
|
||||
case usb_GET_STATUS:
|
||||
buf := []byte{0, 0}
|
||||
|
||||
if setup.bmRequestType != 0 { // endpoint
|
||||
// TODO: actually check if the endpoint in question is currently halted
|
||||
if isEndpointHalt {
|
||||
buf[0] = 1
|
||||
}
|
||||
}
|
||||
|
||||
sendUSBPacket(0, buf, setup.wLength)
|
||||
return true
|
||||
|
||||
case usb_CLEAR_FEATURE:
|
||||
if setup.wValueL == 1 { // DEVICEREMOTEWAKEUP
|
||||
isRemoteWakeUpEnabled = false
|
||||
} else if setup.wValueL == 0 { // ENDPOINTHALT
|
||||
isEndpointHalt = false
|
||||
}
|
||||
sendZlp()
|
||||
return true
|
||||
|
||||
case usb_SET_FEATURE:
|
||||
if setup.wValueL == 1 { // DEVICEREMOTEWAKEUP
|
||||
isRemoteWakeUpEnabled = true
|
||||
} else if setup.wValueL == 0 { // ENDPOINTHALT
|
||||
isEndpointHalt = true
|
||||
}
|
||||
sendZlp()
|
||||
return true
|
||||
|
||||
case usb_SET_ADDRESS:
|
||||
// set packet size 64 with auto Zlp after transfer
|
||||
usbEndpointDescriptors[0].DeviceDescBank[1].PCKSIZE.Set((epPacketSize(64) << usb_DEVICE_PCKSIZE_SIZE_Pos) |
|
||||
uint32(1<<31)) // autozlp
|
||||
|
||||
// ack the transfer is complete from the request
|
||||
setEPINTFLAG(0, sam.USB_DEVICE_ENDPOINT_EPINTFLAG_TRCPT1)
|
||||
|
||||
// set bank ready for data
|
||||
setEPSTATUSSET(0, sam.USB_DEVICE_ENDPOINT_EPSTATUSSET_BK1RDY)
|
||||
|
||||
// wait for transfer to complete
|
||||
timeout := 3000
|
||||
for (getEPINTFLAG(0) & sam.USB_DEVICE_ENDPOINT_EPINTFLAG_TRCPT1) == 0 {
|
||||
timeout--
|
||||
if timeout == 0 {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
// last, set the device address to that requested by host
|
||||
sam.USB_DEVICE.DADD.SetBits(setup.wValueL)
|
||||
sam.USB_DEVICE.DADD.SetBits(sam.USB_DEVICE_DADD_ADDEN)
|
||||
|
||||
return true
|
||||
|
||||
case usb_GET_DESCRIPTOR:
|
||||
sendDescriptor(setup)
|
||||
return true
|
||||
|
||||
case usb_SET_DESCRIPTOR:
|
||||
return false
|
||||
|
||||
case usb_GET_CONFIGURATION:
|
||||
buff := []byte{usbConfiguration}
|
||||
sendUSBPacket(0, buff, setup.wLength)
|
||||
return true
|
||||
|
||||
case usb_SET_CONFIGURATION:
|
||||
if setup.bmRequestType&usb_REQUEST_RECIPIENT == usb_REQUEST_DEVICE {
|
||||
for i := 1; i < len(endPoints); i++ {
|
||||
initEndpoint(uint32(i), endPoints[i])
|
||||
}
|
||||
|
||||
usbConfiguration = setup.wValueL
|
||||
|
||||
// Enable interrupt for CDC control messages from host (OUT packet)
|
||||
setEPINTENSET(usb_CDC_ENDPOINT_ACM, sam.USB_DEVICE_ENDPOINT_EPINTENSET_TRCPT1)
|
||||
|
||||
// Enable interrupt for CDC data messages from host
|
||||
setEPINTENSET(usb_CDC_ENDPOINT_OUT, sam.USB_DEVICE_ENDPOINT_EPINTENSET_TRCPT0)
|
||||
|
||||
// Enable interrupt for HID messages from host
|
||||
if hidCallback != nil {
|
||||
setEPINTENSET(usb_HID_ENDPOINT_IN, sam.USB_DEVICE_ENDPOINT_EPINTENSET_TRCPT1)
|
||||
}
|
||||
|
||||
sendZlp()
|
||||
return true
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
|
||||
case usb_GET_INTERFACE:
|
||||
buff := []byte{usbSetInterface}
|
||||
sendUSBPacket(0, buff, setup.wLength)
|
||||
return true
|
||||
|
||||
case usb_SET_INTERFACE:
|
||||
usbSetInterface = setup.wValueL
|
||||
|
||||
sendZlp()
|
||||
return true
|
||||
|
||||
default:
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
func cdcSetup(setup usbSetup) bool {
|
||||
if setup.bmRequestType == usb_REQUEST_DEVICETOHOST_CLASS_INTERFACE {
|
||||
if setup.bRequest == usb_CDC_GET_LINE_CODING {
|
||||
var b [cdcLineInfoSize]byte
|
||||
b[0] = byte(usbLineInfo.dwDTERate)
|
||||
b[1] = byte(usbLineInfo.dwDTERate >> 8)
|
||||
b[2] = byte(usbLineInfo.dwDTERate >> 16)
|
||||
b[3] = byte(usbLineInfo.dwDTERate >> 24)
|
||||
b[4] = byte(usbLineInfo.bCharFormat)
|
||||
b[5] = byte(usbLineInfo.bParityType)
|
||||
b[6] = byte(usbLineInfo.bDataBits)
|
||||
|
||||
sendUSBPacket(0, b[:], setup.wLength)
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
if setup.bmRequestType == usb_REQUEST_HOSTTODEVICE_CLASS_INTERFACE {
|
||||
if setup.bRequest == usb_CDC_SET_LINE_CODING {
|
||||
b, err := receiveUSBControlPacket()
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
|
||||
usbLineInfo.dwDTERate = uint32(b[0]) | uint32(b[1])<<8 | uint32(b[2])<<16 | uint32(b[3])<<24
|
||||
usbLineInfo.bCharFormat = b[4]
|
||||
usbLineInfo.bParityType = b[5]
|
||||
usbLineInfo.bDataBits = b[6]
|
||||
}
|
||||
|
||||
if setup.bRequest == usb_CDC_SET_CONTROL_LINE_STATE {
|
||||
usbLineInfo.lineState = setup.wValueL
|
||||
}
|
||||
|
||||
if setup.bRequest == usb_CDC_SET_LINE_CODING || setup.bRequest == usb_CDC_SET_CONTROL_LINE_STATE {
|
||||
// auto-reset into the bootloader
|
||||
if usbLineInfo.dwDTERate == 1200 && usbLineInfo.lineState&usb_CDC_LINESTATE_DTR == 0 {
|
||||
ResetProcessor()
|
||||
} else {
|
||||
// TODO: cancel any reset
|
||||
}
|
||||
sendZlp()
|
||||
}
|
||||
|
||||
if setup.bRequest == usb_CDC_SEND_BREAK {
|
||||
// TODO: something with this value?
|
||||
// breakValue = ((uint16_t)setup.wValueH << 8) | setup.wValueL;
|
||||
// return false;
|
||||
sendZlp()
|
||||
}
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// SendUSBHIDPacket sends a packet for USBHID (interrupt / in).
|
||||
func SendUSBHIDPacket(ep uint32, data []byte) bool {
|
||||
if waitHidTxc {
|
||||
return false
|
||||
}
|
||||
|
||||
sendUSBPacket(ep, data, 0)
|
||||
|
||||
// clear transfer complete flag
|
||||
setEPINTFLAG(ep, sam.USB_DEVICE_ENDPOINT_EPINTFLAG_TRCPT1)
|
||||
|
||||
// send data by setting bank ready
|
||||
setEPSTATUSSET(ep, sam.USB_DEVICE_ENDPOINT_EPSTATUSSET_BK1RDY)
|
||||
|
||||
waitHidTxc = true
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
//go:noinline
|
||||
func sendUSBPacket(ep uint32, data []byte, maxsize uint16) {
|
||||
l := uint16(len(data))
|
||||
if 0 < maxsize && maxsize < l {
|
||||
l = maxsize
|
||||
}
|
||||
copy(udd_ep_in_cache_buffer[ep][:], data[:l])
|
||||
|
||||
// Set endpoint address for sending data
|
||||
usbEndpointDescriptors[ep].DeviceDescBank[1].ADDR.Set(uint32(uintptr(unsafe.Pointer(&udd_ep_in_cache_buffer[ep]))))
|
||||
|
||||
// clear multi-packet size which is total bytes already sent
|
||||
usbEndpointDescriptors[ep].DeviceDescBank[1].PCKSIZE.ClearBits(usb_DEVICE_PCKSIZE_MULTI_PACKET_SIZE_Mask << usb_DEVICE_PCKSIZE_MULTI_PACKET_SIZE_Pos)
|
||||
|
||||
// set byte count, which is total number of bytes to be sent
|
||||
usbEndpointDescriptors[ep].DeviceDescBank[1].PCKSIZE.ClearBits(usb_DEVICE_PCKSIZE_BYTE_COUNT_Mask << usb_DEVICE_PCKSIZE_BYTE_COUNT_Pos)
|
||||
usbEndpointDescriptors[ep].DeviceDescBank[1].PCKSIZE.SetBits((uint32(l) & usb_DEVICE_PCKSIZE_BYTE_COUNT_Mask) << usb_DEVICE_PCKSIZE_BYTE_COUNT_Pos)
|
||||
}
|
||||
|
||||
func receiveUSBControlPacket() ([cdcLineInfoSize]byte, error) {
|
||||
var b [cdcLineInfoSize]byte
|
||||
|
||||
// address
|
||||
usbEndpointDescriptors[0].DeviceDescBank[0].ADDR.Set(uint32(uintptr(unsafe.Pointer(&udd_ep_out_cache_buffer[0]))))
|
||||
|
||||
// set byte count to zero
|
||||
usbEndpointDescriptors[0].DeviceDescBank[0].PCKSIZE.ClearBits(usb_DEVICE_PCKSIZE_BYTE_COUNT_Mask << usb_DEVICE_PCKSIZE_BYTE_COUNT_Pos)
|
||||
|
||||
// set ready for next data
|
||||
setEPSTATUSCLR(0, sam.USB_DEVICE_ENDPOINT_EPSTATUSCLR_BK0RDY)
|
||||
|
||||
// Wait until OUT transfer is ready.
|
||||
timeout := 300000
|
||||
for (getEPSTATUS(0) & sam.USB_DEVICE_ENDPOINT_EPSTATUS_BK0RDY) == 0 {
|
||||
timeout--
|
||||
if timeout == 0 {
|
||||
return b, errUSBCDCReadTimeout
|
||||
}
|
||||
}
|
||||
|
||||
// Wait until OUT transfer is completed.
|
||||
timeout = 300000
|
||||
for (getEPINTFLAG(0) & sam.USB_DEVICE_ENDPOINT_EPINTFLAG_TRCPT1) == 0 {
|
||||
timeout--
|
||||
if timeout == 0 {
|
||||
return b, errUSBCDCReadTimeout
|
||||
}
|
||||
}
|
||||
|
||||
// get data
|
||||
bytesread := uint32((usbEndpointDescriptors[0].DeviceDescBank[0].PCKSIZE.Get() >>
|
||||
usb_DEVICE_PCKSIZE_BYTE_COUNT_Pos) & usb_DEVICE_PCKSIZE_BYTE_COUNT_Mask)
|
||||
|
||||
if bytesread != cdcLineInfoSize {
|
||||
return b, errUSBCDCBytesRead
|
||||
}
|
||||
|
||||
copy(b[:7], udd_ep_out_cache_buffer[0][:7])
|
||||
|
||||
return b, nil
|
||||
}
|
||||
|
||||
func handleEndpoint(ep uint32) {
|
||||
// get data
|
||||
count := int((usbEndpointDescriptors[ep].DeviceDescBank[0].PCKSIZE.Get() >>
|
||||
usb_DEVICE_PCKSIZE_BYTE_COUNT_Pos) & usb_DEVICE_PCKSIZE_BYTE_COUNT_Mask)
|
||||
|
||||
// move to ring buffer
|
||||
for i := 0; i < count; i++ {
|
||||
USB.Receive(byte((udd_ep_out_cache_buffer[ep][i] & 0xFF)))
|
||||
}
|
||||
|
||||
// set byte count to zero
|
||||
usbEndpointDescriptors[ep].DeviceDescBank[0].PCKSIZE.ClearBits(usb_DEVICE_PCKSIZE_BYTE_COUNT_Mask << usb_DEVICE_PCKSIZE_BYTE_COUNT_Pos)
|
||||
|
||||
// set multi packet size to 64
|
||||
usbEndpointDescriptors[ep].DeviceDescBank[0].PCKSIZE.SetBits(64 << usb_DEVICE_PCKSIZE_MULTI_PACKET_SIZE_Pos)
|
||||
|
||||
// set ready for next data
|
||||
setEPSTATUSCLR(ep, sam.USB_DEVICE_ENDPOINT_EPSTATUSCLR_BK0RDY)
|
||||
}
|
||||
|
||||
func sendZlp() {
|
||||
usbEndpointDescriptors[0].DeviceDescBank[1].PCKSIZE.ClearBits(usb_DEVICE_PCKSIZE_BYTE_COUNT_Mask << usb_DEVICE_PCKSIZE_BYTE_COUNT_Pos)
|
||||
}
|
||||
|
||||
func epPacketSize(size uint16) uint32 {
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
func getEPCFG(ep uint32) uint8 {
|
||||
return sam.USB_DEVICE.DEVICE_ENDPOINT[ep].EPCFG.Get()
|
||||
}
|
||||
|
||||
func setEPCFG(ep uint32, val uint8) {
|
||||
sam.USB_DEVICE.DEVICE_ENDPOINT[ep].EPCFG.Set(val)
|
||||
}
|
||||
|
||||
func setEPSTATUSCLR(ep uint32, val uint8) {
|
||||
sam.USB_DEVICE.DEVICE_ENDPOINT[ep].EPSTATUSCLR.Set(val)
|
||||
}
|
||||
|
||||
func setEPSTATUSSET(ep uint32, val uint8) {
|
||||
sam.USB_DEVICE.DEVICE_ENDPOINT[ep].EPSTATUSSET.Set(val)
|
||||
}
|
||||
|
||||
func getEPSTATUS(ep uint32) uint8 {
|
||||
return sam.USB_DEVICE.DEVICE_ENDPOINT[ep].EPSTATUS.Get()
|
||||
}
|
||||
|
||||
func getEPINTFLAG(ep uint32) uint8 {
|
||||
return sam.USB_DEVICE.DEVICE_ENDPOINT[ep].EPINTFLAG.Get()
|
||||
}
|
||||
|
||||
func setEPINTFLAG(ep uint32, val uint8) {
|
||||
sam.USB_DEVICE.DEVICE_ENDPOINT[ep].EPINTFLAG.Set(val)
|
||||
}
|
||||
|
||||
func setEPINTENCLR(ep uint32, val uint8) {
|
||||
sam.USB_DEVICE.DEVICE_ENDPOINT[ep].EPINTENCLR.Set(val)
|
||||
}
|
||||
|
||||
func setEPINTENSET(ep uint32, val uint8) {
|
||||
sam.USB_DEVICE.DEVICE_ENDPOINT[ep].EPINTENSET.Set(val)
|
||||
}
|
||||
|
||||
// ResetProcessor should perform a system reset in preparation
|
||||
// EnterBootloader should perform a system reset in preparation
|
||||
// to switch to the bootloader to flash new firmware.
|
||||
func ResetProcessor() {
|
||||
func EnterBootloader() {
|
||||
arm.DisableInterrupts()
|
||||
|
||||
// Perform magic reset into bootloader, as mentioned in
|
||||
@@ -2742,10 +1988,12 @@ func ResetProcessor() {
|
||||
|
||||
// DAC on the SAMD51.
|
||||
type DAC struct {
|
||||
Channel uint8
|
||||
}
|
||||
|
||||
var (
|
||||
DAC0 = DAC{}
|
||||
DAC0 = DAC{Channel: 0}
|
||||
DAC1 = DAC{Channel: 1}
|
||||
)
|
||||
|
||||
// DACConfig placeholder for future expansion.
|
||||
@@ -2758,58 +2006,77 @@ func (dac DAC) Configure(config DACConfig) {
|
||||
// Turn on clock for DAC
|
||||
sam.MCLK.APBDMASK.SetBits(sam.MCLK_APBDMASK_DAC_)
|
||||
|
||||
// Use Generic Clock Generator 4 as source for DAC.
|
||||
sam.GCLK.PCHCTRL[42].Set((sam.GCLK_PCHCTRL_GEN_GCLK4 << sam.GCLK_PCHCTRL_GEN_Pos) | sam.GCLK_PCHCTRL_CHEN)
|
||||
for sam.GCLK.SYNCBUSY.HasBits(sam.GCLK_SYNCBUSY_GENCTRL_GCLK4 << sam.GCLK_SYNCBUSY_GENCTRL_Pos) {
|
||||
if !sam.GCLK.PCHCTRL[42].HasBits(sam.GCLK_PCHCTRL_CHEN) {
|
||||
// Use Generic Clock Generator 4 as source for DAC.
|
||||
sam.GCLK.PCHCTRL[42].Set((sam.GCLK_PCHCTRL_GEN_GCLK4 << sam.GCLK_PCHCTRL_GEN_Pos) | sam.GCLK_PCHCTRL_CHEN)
|
||||
for sam.GCLK.SYNCBUSY.HasBits(sam.GCLK_SYNCBUSY_GENCTRL_GCLK4 << sam.GCLK_SYNCBUSY_GENCTRL_Pos) {
|
||||
}
|
||||
|
||||
// reset DAC
|
||||
sam.DAC.CTRLA.Set(sam.DAC_CTRLA_SWRST)
|
||||
|
||||
// wait for reset complete
|
||||
for sam.DAC.CTRLA.HasBits(sam.DAC_CTRLA_SWRST) {
|
||||
}
|
||||
for sam.DAC.SYNCBUSY.HasBits(sam.DAC_SYNCBUSY_SWRST) {
|
||||
}
|
||||
}
|
||||
|
||||
// reset DAC
|
||||
sam.DAC.CTRLA.Set(sam.DAC_CTRLA_SWRST)
|
||||
|
||||
// wait for reset complete
|
||||
for sam.DAC.CTRLA.HasBits(sam.DAC_CTRLA_SWRST) {
|
||||
}
|
||||
for sam.DAC.SYNCBUSY.HasBits(sam.DAC_SYNCBUSY_SWRST) {
|
||||
sam.DAC.CTRLA.ClearBits(sam.DAC_CTRLA_ENABLE)
|
||||
for sam.DAC.SYNCBUSY.HasBits(sam.DAC_SYNCBUSY_ENABLE) {
|
||||
}
|
||||
|
||||
// enable
|
||||
sam.DAC.CTRLB.Set(sam.DAC_CTRLB_REFSEL_VREFPU << sam.DAC_CTRLB_REFSEL_Pos)
|
||||
sam.DAC.DACCTRL[0].SetBits((sam.DAC_DACCTRL_CCTRL_CC12M << sam.DAC_DACCTRL_CCTRL_Pos) | sam.DAC_DACCTRL_ENABLE)
|
||||
sam.DAC.DACCTRL[dac.Channel].SetBits((sam.DAC_DACCTRL_CCTRL_CC12M << sam.DAC_DACCTRL_CCTRL_Pos) | sam.DAC_DACCTRL_ENABLE)
|
||||
sam.DAC.CTRLA.Set(sam.DAC_CTRLA_ENABLE)
|
||||
|
||||
for sam.DAC.SYNCBUSY.HasBits(sam.DAC_SYNCBUSY_ENABLE) {
|
||||
}
|
||||
for !sam.DAC.STATUS.HasBits(sam.DAC_STATUS_READY0) {
|
||||
|
||||
switch dac.Channel {
|
||||
case 0:
|
||||
for !sam.DAC.STATUS.HasBits(sam.DAC_STATUS_READY0) {
|
||||
}
|
||||
default:
|
||||
for !sam.DAC.STATUS.HasBits(sam.DAC_STATUS_READY1) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Set writes a single 16-bit value to the DAC.
|
||||
// Since the ATSAMD51 only has a 12-bit DAC, the passed-in value will be scaled down.
|
||||
func (dac DAC) Set(value uint16) error {
|
||||
sam.DAC.DATA[0].Set(value >> 4)
|
||||
syncDAC()
|
||||
sam.DAC.DATA[dac.Channel].Set(value >> 4)
|
||||
dac.syncDAC()
|
||||
return nil
|
||||
}
|
||||
|
||||
func syncDAC() {
|
||||
for !sam.DAC.STATUS.HasBits(sam.DAC_STATUS_EOC0) {
|
||||
}
|
||||
for sam.DAC.SYNCBUSY.HasBits(sam.DAC_SYNCBUSY_DATA0) {
|
||||
func (dac DAC) syncDAC() {
|
||||
switch dac.Channel {
|
||||
case 0:
|
||||
for !sam.DAC.STATUS.HasBits(sam.DAC_STATUS_EOC0) {
|
||||
}
|
||||
for sam.DAC.SYNCBUSY.HasBits(sam.DAC_SYNCBUSY_DATA0) {
|
||||
}
|
||||
default:
|
||||
for !sam.DAC.STATUS.HasBits(sam.DAC_STATUS_EOC1) {
|
||||
}
|
||||
for sam.DAC.SYNCBUSY.HasBits(sam.DAC_SYNCBUSY_DATA1) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var rngInitDone = false
|
||||
|
||||
// GetRNG returns 32 bits of cryptographically secure random data
|
||||
func GetRNG() (uint32, error) {
|
||||
if !rngInitDone {
|
||||
if !sam.MCLK.APBCMASK.HasBits(sam.MCLK_APBCMASK_TRNG_) {
|
||||
// Turn on clock for TRNG
|
||||
sam.MCLK.APBCMASK.SetBits(sam.MCLK_APBCMASK_TRNG_)
|
||||
|
||||
// enable
|
||||
sam.TRNG.CTRLA.Set(sam.TRNG_CTRLA_ENABLE)
|
||||
|
||||
rngInitDone = true
|
||||
}
|
||||
for !sam.TRNG.INTFLAG.HasBits(sam.TRNG_INTFLAG_DATARDY) {
|
||||
}
|
||||
ret := sam.TRNG.DATA.Get()
|
||||
return ret, nil
|
||||
|
||||
@@ -0,0 +1,471 @@
|
||||
//go:build (sam && atsamd51) || (sam && atsame5x)
|
||||
// +build sam,atsamd51 sam,atsame5x
|
||||
|
||||
package machine
|
||||
|
||||
import (
|
||||
"device/sam"
|
||||
"machine/usb"
|
||||
"runtime/interrupt"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
const (
|
||||
// these are SAMD51 specific.
|
||||
usb_DEVICE_PCKSIZE_BYTE_COUNT_Pos = 0
|
||||
usb_DEVICE_PCKSIZE_BYTE_COUNT_Mask = 0x3FFF
|
||||
|
||||
usb_DEVICE_PCKSIZE_SIZE_Pos = 28
|
||||
usb_DEVICE_PCKSIZE_SIZE_Mask = 0x7
|
||||
|
||||
usb_DEVICE_PCKSIZE_MULTI_PACKET_SIZE_Pos = 14
|
||||
usb_DEVICE_PCKSIZE_MULTI_PACKET_SIZE_Mask = 0x3FFF
|
||||
)
|
||||
|
||||
// Configure the USB peripheral. The config is here for compatibility with the UART interface.
|
||||
func (dev *USBDevice) Configure(config UARTConfig) {
|
||||
if dev.initcomplete {
|
||||
return
|
||||
}
|
||||
|
||||
// reset USB interface
|
||||
sam.USB_DEVICE.CTRLA.SetBits(sam.USB_DEVICE_CTRLA_SWRST)
|
||||
for sam.USB_DEVICE.SYNCBUSY.HasBits(sam.USB_DEVICE_SYNCBUSY_SWRST) ||
|
||||
sam.USB_DEVICE.SYNCBUSY.HasBits(sam.USB_DEVICE_SYNCBUSY_ENABLE) {
|
||||
}
|
||||
|
||||
sam.USB_DEVICE.DESCADD.Set(uint32(uintptr(unsafe.Pointer(&usbEndpointDescriptors))))
|
||||
|
||||
// configure pins
|
||||
USBCDC_DM_PIN.Configure(PinConfig{Mode: PinCom})
|
||||
USBCDC_DP_PIN.Configure(PinConfig{Mode: PinCom})
|
||||
|
||||
// performs pad calibration from store fuses
|
||||
handlePadCalibration()
|
||||
|
||||
// run in standby
|
||||
sam.USB_DEVICE.CTRLA.SetBits(sam.USB_DEVICE_CTRLA_RUNSTDBY)
|
||||
|
||||
// set full speed
|
||||
sam.USB_DEVICE.CTRLB.SetBits(sam.USB_DEVICE_CTRLB_SPDCONF_FS << sam.USB_DEVICE_CTRLB_SPDCONF_Pos)
|
||||
|
||||
// attach
|
||||
sam.USB_DEVICE.CTRLB.ClearBits(sam.USB_DEVICE_CTRLB_DETACH)
|
||||
|
||||
// enable interrupt for end of reset
|
||||
sam.USB_DEVICE.INTENSET.SetBits(sam.USB_DEVICE_INTENSET_EORST)
|
||||
|
||||
// enable interrupt for start of frame
|
||||
sam.USB_DEVICE.INTENSET.SetBits(sam.USB_DEVICE_INTENSET_SOF)
|
||||
|
||||
// enable USB
|
||||
sam.USB_DEVICE.CTRLA.SetBits(sam.USB_DEVICE_CTRLA_ENABLE)
|
||||
|
||||
// enable IRQ
|
||||
interrupt.New(sam.IRQ_USB_OTHER, handleUSBIRQ).Enable()
|
||||
interrupt.New(sam.IRQ_USB_SOF_HSOF, handleUSBIRQ).Enable()
|
||||
interrupt.New(sam.IRQ_USB_TRCPT0, handleUSBIRQ).Enable()
|
||||
interrupt.New(sam.IRQ_USB_TRCPT1, handleUSBIRQ).Enable()
|
||||
|
||||
dev.initcomplete = true
|
||||
}
|
||||
|
||||
func handlePadCalibration() {
|
||||
// Load Pad Calibration data from non-volatile memory
|
||||
// This requires registers that are not included in the SVD file.
|
||||
// Modeled after defines from samd21g18a.h and nvmctrl.h:
|
||||
//
|
||||
// #define NVMCTRL_OTP4 0x00806020
|
||||
//
|
||||
// #define USB_FUSES_TRANSN_ADDR (NVMCTRL_OTP4 + 4)
|
||||
// #define USB_FUSES_TRANSN_Pos 13 /**< \brief (NVMCTRL_OTP4) USB pad Transn calibration */
|
||||
// #define USB_FUSES_TRANSN_Msk (0x1Fu << USB_FUSES_TRANSN_Pos)
|
||||
// #define USB_FUSES_TRANSN(value) ((USB_FUSES_TRANSN_Msk & ((value) << USB_FUSES_TRANSN_Pos)))
|
||||
|
||||
// #define USB_FUSES_TRANSP_ADDR (NVMCTRL_OTP4 + 4)
|
||||
// #define USB_FUSES_TRANSP_Pos 18 /**< \brief (NVMCTRL_OTP4) USB pad Transp calibration */
|
||||
// #define USB_FUSES_TRANSP_Msk (0x1Fu << USB_FUSES_TRANSP_Pos)
|
||||
// #define USB_FUSES_TRANSP(value) ((USB_FUSES_TRANSP_Msk & ((value) << USB_FUSES_TRANSP_Pos)))
|
||||
|
||||
// #define USB_FUSES_TRIM_ADDR (NVMCTRL_OTP4 + 4)
|
||||
// #define USB_FUSES_TRIM_Pos 23 /**< \brief (NVMCTRL_OTP4) USB pad Trim calibration */
|
||||
// #define USB_FUSES_TRIM_Msk (0x7u << USB_FUSES_TRIM_Pos)
|
||||
// #define USB_FUSES_TRIM(value) ((USB_FUSES_TRIM_Msk & ((value) << USB_FUSES_TRIM_Pos)))
|
||||
//
|
||||
fuse := *(*uint32)(unsafe.Pointer(uintptr(0x00806020) + 4))
|
||||
calibTransN := uint16(fuse>>13) & uint16(0x1f)
|
||||
calibTransP := uint16(fuse>>18) & uint16(0x1f)
|
||||
calibTrim := uint16(fuse>>23) & uint16(0x7)
|
||||
|
||||
if calibTransN == 0x1f {
|
||||
calibTransN = 5
|
||||
}
|
||||
sam.USB_DEVICE.PADCAL.SetBits(calibTransN << sam.USB_DEVICE_PADCAL_TRANSN_Pos)
|
||||
|
||||
if calibTransP == 0x1f {
|
||||
calibTransP = 29
|
||||
}
|
||||
sam.USB_DEVICE.PADCAL.SetBits(calibTransP << sam.USB_DEVICE_PADCAL_TRANSP_Pos)
|
||||
|
||||
if calibTrim == 0x7 {
|
||||
calibTrim = 3
|
||||
}
|
||||
sam.USB_DEVICE.PADCAL.SetBits(calibTrim << sam.USB_DEVICE_PADCAL_TRIM_Pos)
|
||||
}
|
||||
|
||||
func handleUSBIRQ(intr interrupt.Interrupt) {
|
||||
// reset all interrupt flags
|
||||
flags := sam.USB_DEVICE.INTFLAG.Get()
|
||||
sam.USB_DEVICE.INTFLAG.Set(flags)
|
||||
|
||||
// End of reset
|
||||
if (flags & sam.USB_DEVICE_INTFLAG_EORST) > 0 {
|
||||
// Configure control endpoint
|
||||
initEndpoint(0, usb.ENDPOINT_TYPE_CONTROL)
|
||||
|
||||
usbConfiguration = 0
|
||||
|
||||
// ack the End-Of-Reset interrupt
|
||||
sam.USB_DEVICE.INTFLAG.Set(sam.USB_DEVICE_INTFLAG_EORST)
|
||||
}
|
||||
|
||||
// Start of frame
|
||||
if (flags & sam.USB_DEVICE_INTFLAG_SOF) > 0 {
|
||||
// if you want to blink LED showing traffic, this would be the place...
|
||||
}
|
||||
|
||||
// Endpoint 0 Setup interrupt
|
||||
if getEPINTFLAG(0)&sam.USB_DEVICE_ENDPOINT_EPINTFLAG_RXSTP > 0 {
|
||||
// ack setup received
|
||||
setEPINTFLAG(0, sam.USB_DEVICE_ENDPOINT_EPINTFLAG_RXSTP)
|
||||
|
||||
// parse setup
|
||||
setup := usb.NewSetup(udd_ep_out_cache_buffer[0][:])
|
||||
|
||||
// Clear the Bank 0 ready flag on Control OUT
|
||||
setEPSTATUSCLR(0, sam.USB_DEVICE_ENDPOINT_EPSTATUSCLR_BK0RDY)
|
||||
usbEndpointDescriptors[0].DeviceDescBank[0].PCKSIZE.ClearBits(usb_DEVICE_PCKSIZE_BYTE_COUNT_Mask << usb_DEVICE_PCKSIZE_BYTE_COUNT_Pos)
|
||||
|
||||
ok := false
|
||||
if (setup.BmRequestType & usb.REQUEST_TYPE) == usb.REQUEST_STANDARD {
|
||||
// Standard Requests
|
||||
ok = handleStandardSetup(setup)
|
||||
} else {
|
||||
// Class Interface Requests
|
||||
if setup.WIndex < uint16(len(usbSetupHandler)) && usbSetupHandler[setup.WIndex] != nil {
|
||||
ok = usbSetupHandler[setup.WIndex](setup)
|
||||
}
|
||||
}
|
||||
|
||||
if ok {
|
||||
// set Bank1 ready
|
||||
setEPSTATUSSET(0, sam.USB_DEVICE_ENDPOINT_EPSTATUSSET_BK1RDY)
|
||||
} else {
|
||||
// Stall endpoint
|
||||
setEPSTATUSSET(0, sam.USB_DEVICE_ENDPOINT_EPINTFLAG_STALL1)
|
||||
}
|
||||
|
||||
if getEPINTFLAG(0)&sam.USB_DEVICE_ENDPOINT_EPINTFLAG_STALL1 > 0 {
|
||||
// ack the stall
|
||||
setEPINTFLAG(0, sam.USB_DEVICE_ENDPOINT_EPINTFLAG_STALL1)
|
||||
|
||||
// clear stall request
|
||||
setEPINTENCLR(0, sam.USB_DEVICE_ENDPOINT_EPINTENCLR_STALL1)
|
||||
}
|
||||
}
|
||||
|
||||
// Now the actual transfer handlers, ignore endpoint number 0 (setup)
|
||||
var i uint32
|
||||
for i = 1; i < uint32(len(endPoints)); i++ {
|
||||
// Check if endpoint has a pending interrupt
|
||||
epFlags := getEPINTFLAG(i)
|
||||
setEPINTFLAG(i, epFlags)
|
||||
if (epFlags & sam.USB_DEVICE_ENDPOINT_EPINTFLAG_TRCPT0) > 0 {
|
||||
buf := handleEndpointRx(i)
|
||||
if usbRxHandler[i] != nil {
|
||||
usbRxHandler[i](buf)
|
||||
}
|
||||
handleEndpointRxComplete(i)
|
||||
} else if (epFlags & sam.USB_DEVICE_ENDPOINT_EPINTFLAG_TRCPT1) > 0 {
|
||||
if usbTxHandler[i] != nil {
|
||||
usbTxHandler[i]()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func initEndpoint(ep, config uint32) {
|
||||
switch config {
|
||||
case usb.ENDPOINT_TYPE_INTERRUPT | usb.EndpointIn:
|
||||
// set packet size
|
||||
usbEndpointDescriptors[ep].DeviceDescBank[1].PCKSIZE.SetBits(epPacketSize(64) << usb_DEVICE_PCKSIZE_SIZE_Pos)
|
||||
|
||||
// set data buffer address
|
||||
usbEndpointDescriptors[ep].DeviceDescBank[1].ADDR.Set(uint32(uintptr(unsafe.Pointer(&udd_ep_in_cache_buffer[ep]))))
|
||||
|
||||
// set endpoint type
|
||||
setEPCFG(ep, ((usb.ENDPOINT_TYPE_INTERRUPT + 1) << sam.USB_DEVICE_ENDPOINT_EPCFG_EPTYPE1_Pos))
|
||||
|
||||
setEPINTENSET(ep, sam.USB_DEVICE_ENDPOINT_EPINTENSET_TRCPT1)
|
||||
|
||||
case usb.ENDPOINT_TYPE_BULK | usb.EndpointOut:
|
||||
// set packet size
|
||||
usbEndpointDescriptors[ep].DeviceDescBank[0].PCKSIZE.SetBits(epPacketSize(64) << usb_DEVICE_PCKSIZE_SIZE_Pos)
|
||||
|
||||
// set data buffer address
|
||||
usbEndpointDescriptors[ep].DeviceDescBank[0].ADDR.Set(uint32(uintptr(unsafe.Pointer(&udd_ep_out_cache_buffer[ep]))))
|
||||
|
||||
// set endpoint type
|
||||
setEPCFG(ep, ((usb.ENDPOINT_TYPE_BULK + 1) << sam.USB_DEVICE_ENDPOINT_EPCFG_EPTYPE0_Pos))
|
||||
|
||||
// receive interrupts when current transfer complete
|
||||
setEPINTENSET(ep, sam.USB_DEVICE_ENDPOINT_EPINTENSET_TRCPT0)
|
||||
|
||||
// set byte count to zero, we have not received anything yet
|
||||
usbEndpointDescriptors[ep].DeviceDescBank[0].PCKSIZE.ClearBits(usb_DEVICE_PCKSIZE_BYTE_COUNT_Mask << usb_DEVICE_PCKSIZE_BYTE_COUNT_Pos)
|
||||
|
||||
// ready for next transfer
|
||||
setEPSTATUSCLR(ep, sam.USB_DEVICE_ENDPOINT_EPSTATUSCLR_BK0RDY)
|
||||
|
||||
case usb.ENDPOINT_TYPE_INTERRUPT | usb.EndpointOut:
|
||||
// TODO: not really anything, seems like...
|
||||
|
||||
case usb.ENDPOINT_TYPE_BULK | usb.EndpointIn:
|
||||
// set packet size
|
||||
usbEndpointDescriptors[ep].DeviceDescBank[1].PCKSIZE.SetBits(epPacketSize(64) << usb_DEVICE_PCKSIZE_SIZE_Pos)
|
||||
|
||||
// set data buffer address
|
||||
usbEndpointDescriptors[ep].DeviceDescBank[1].ADDR.Set(uint32(uintptr(unsafe.Pointer(&udd_ep_in_cache_buffer[ep]))))
|
||||
|
||||
// set endpoint type
|
||||
setEPCFG(ep, ((usb.ENDPOINT_TYPE_BULK + 1) << sam.USB_DEVICE_ENDPOINT_EPCFG_EPTYPE1_Pos))
|
||||
|
||||
// NAK on endpoint IN, the bank is not yet filled in.
|
||||
setEPSTATUSCLR(ep, sam.USB_DEVICE_ENDPOINT_EPSTATUSCLR_BK1RDY)
|
||||
|
||||
setEPINTENSET(ep, sam.USB_DEVICE_ENDPOINT_EPINTENSET_TRCPT1)
|
||||
|
||||
case usb.ENDPOINT_TYPE_CONTROL:
|
||||
// Control OUT
|
||||
// set packet size
|
||||
usbEndpointDescriptors[ep].DeviceDescBank[0].PCKSIZE.SetBits(epPacketSize(64) << usb_DEVICE_PCKSIZE_SIZE_Pos)
|
||||
|
||||
// set data buffer address
|
||||
usbEndpointDescriptors[ep].DeviceDescBank[0].ADDR.Set(uint32(uintptr(unsafe.Pointer(&udd_ep_out_cache_buffer[ep]))))
|
||||
|
||||
// set endpoint type
|
||||
setEPCFG(ep, getEPCFG(ep)|((usb.ENDPOINT_TYPE_CONTROL+1)<<sam.USB_DEVICE_ENDPOINT_EPCFG_EPTYPE0_Pos))
|
||||
|
||||
// Control IN
|
||||
// set packet size
|
||||
usbEndpointDescriptors[ep].DeviceDescBank[1].PCKSIZE.SetBits(epPacketSize(64) << usb_DEVICE_PCKSIZE_SIZE_Pos)
|
||||
|
||||
// set data buffer address
|
||||
usbEndpointDescriptors[ep].DeviceDescBank[1].ADDR.Set(uint32(uintptr(unsafe.Pointer(&udd_ep_in_cache_buffer[ep]))))
|
||||
|
||||
// set endpoint type
|
||||
setEPCFG(ep, getEPCFG(ep)|((usb.ENDPOINT_TYPE_CONTROL+1)<<sam.USB_DEVICE_ENDPOINT_EPCFG_EPTYPE1_Pos))
|
||||
|
||||
// Prepare OUT endpoint for receive
|
||||
// set multi packet size for expected number of receive bytes on control OUT
|
||||
usbEndpointDescriptors[ep].DeviceDescBank[0].PCKSIZE.SetBits(64 << usb_DEVICE_PCKSIZE_MULTI_PACKET_SIZE_Pos)
|
||||
|
||||
// set byte count to zero, we have not received anything yet
|
||||
usbEndpointDescriptors[ep].DeviceDescBank[0].PCKSIZE.ClearBits(usb_DEVICE_PCKSIZE_BYTE_COUNT_Mask << usb_DEVICE_PCKSIZE_BYTE_COUNT_Pos)
|
||||
|
||||
// NAK on endpoint OUT to show we are ready to receive control data
|
||||
setEPSTATUSSET(ep, sam.USB_DEVICE_ENDPOINT_EPSTATUSSET_BK0RDY)
|
||||
|
||||
// Enable Setup-Received interrupt
|
||||
setEPINTENSET(0, sam.USB_DEVICE_ENDPOINT_EPINTENSET_RXSTP)
|
||||
}
|
||||
}
|
||||
|
||||
func handleUSBSetAddress(setup usb.Setup) bool {
|
||||
// set packet size 64 with auto Zlp after transfer
|
||||
usbEndpointDescriptors[0].DeviceDescBank[1].PCKSIZE.Set((epPacketSize(64) << usb_DEVICE_PCKSIZE_SIZE_Pos) |
|
||||
uint32(1<<31)) // autozlp
|
||||
|
||||
// ack the transfer is complete from the request
|
||||
setEPINTFLAG(0, sam.USB_DEVICE_ENDPOINT_EPINTFLAG_TRCPT1)
|
||||
|
||||
// set bank ready for data
|
||||
setEPSTATUSSET(0, sam.USB_DEVICE_ENDPOINT_EPSTATUSSET_BK1RDY)
|
||||
|
||||
// wait for transfer to complete
|
||||
timeout := 3000
|
||||
for (getEPINTFLAG(0) & sam.USB_DEVICE_ENDPOINT_EPINTFLAG_TRCPT1) == 0 {
|
||||
timeout--
|
||||
if timeout == 0 {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
// last, set the device address to that requested by host
|
||||
sam.USB_DEVICE.DADD.SetBits(setup.WValueL)
|
||||
sam.USB_DEVICE.DADD.SetBits(sam.USB_DEVICE_DADD_ADDEN)
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
// SendUSBInPacket sends a packet for USB (interrupt in / bulk in).
|
||||
func SendUSBInPacket(ep uint32, data []byte) bool {
|
||||
sendUSBPacket(ep, data, 0)
|
||||
|
||||
// clear transfer complete flag
|
||||
setEPINTFLAG(ep, sam.USB_DEVICE_ENDPOINT_EPINTFLAG_TRCPT1)
|
||||
|
||||
// send data by setting bank ready
|
||||
setEPSTATUSSET(ep, sam.USB_DEVICE_ENDPOINT_EPSTATUSSET_BK1RDY)
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
//go:noinline
|
||||
func sendUSBPacket(ep uint32, data []byte, maxsize uint16) {
|
||||
l := uint16(len(data))
|
||||
if 0 < maxsize && maxsize < l {
|
||||
l = maxsize
|
||||
}
|
||||
|
||||
// Set endpoint address for sending data
|
||||
if ep == 0 {
|
||||
copy(udd_ep_control_cache_buffer[:], data[:l])
|
||||
usbEndpointDescriptors[ep].DeviceDescBank[1].ADDR.Set(uint32(uintptr(unsafe.Pointer(&udd_ep_control_cache_buffer))))
|
||||
} else {
|
||||
copy(udd_ep_in_cache_buffer[ep][:], data[:l])
|
||||
usbEndpointDescriptors[ep].DeviceDescBank[1].ADDR.Set(uint32(uintptr(unsafe.Pointer(&udd_ep_in_cache_buffer[ep]))))
|
||||
}
|
||||
|
||||
// clear multi-packet size which is total bytes already sent
|
||||
usbEndpointDescriptors[ep].DeviceDescBank[1].PCKSIZE.ClearBits(usb_DEVICE_PCKSIZE_MULTI_PACKET_SIZE_Mask << usb_DEVICE_PCKSIZE_MULTI_PACKET_SIZE_Pos)
|
||||
|
||||
// set byte count, which is total number of bytes to be sent
|
||||
usbEndpointDescriptors[ep].DeviceDescBank[1].PCKSIZE.ClearBits(usb_DEVICE_PCKSIZE_BYTE_COUNT_Mask << usb_DEVICE_PCKSIZE_BYTE_COUNT_Pos)
|
||||
usbEndpointDescriptors[ep].DeviceDescBank[1].PCKSIZE.SetBits((uint32(l) & usb_DEVICE_PCKSIZE_BYTE_COUNT_Mask) << usb_DEVICE_PCKSIZE_BYTE_COUNT_Pos)
|
||||
}
|
||||
|
||||
func ReceiveUSBControlPacket() ([cdcLineInfoSize]byte, error) {
|
||||
var b [cdcLineInfoSize]byte
|
||||
|
||||
// address
|
||||
usbEndpointDescriptors[0].DeviceDescBank[0].ADDR.Set(uint32(uintptr(unsafe.Pointer(&udd_ep_out_cache_buffer[0]))))
|
||||
|
||||
// set byte count to zero
|
||||
usbEndpointDescriptors[0].DeviceDescBank[0].PCKSIZE.ClearBits(usb_DEVICE_PCKSIZE_BYTE_COUNT_Mask << usb_DEVICE_PCKSIZE_BYTE_COUNT_Pos)
|
||||
|
||||
// set ready for next data
|
||||
setEPSTATUSCLR(0, sam.USB_DEVICE_ENDPOINT_EPSTATUSCLR_BK0RDY)
|
||||
|
||||
// Wait until OUT transfer is ready.
|
||||
timeout := 300000
|
||||
for (getEPSTATUS(0) & sam.USB_DEVICE_ENDPOINT_EPSTATUS_BK0RDY) == 0 {
|
||||
timeout--
|
||||
if timeout == 0 {
|
||||
return b, ErrUSBReadTimeout
|
||||
}
|
||||
}
|
||||
|
||||
// Wait until OUT transfer is completed.
|
||||
timeout = 300000
|
||||
for (getEPINTFLAG(0) & sam.USB_DEVICE_ENDPOINT_EPINTFLAG_TRCPT0) == 0 {
|
||||
timeout--
|
||||
if timeout == 0 {
|
||||
return b, ErrUSBReadTimeout
|
||||
}
|
||||
}
|
||||
|
||||
// get data
|
||||
bytesread := uint32((usbEndpointDescriptors[0].DeviceDescBank[0].PCKSIZE.Get() >>
|
||||
usb_DEVICE_PCKSIZE_BYTE_COUNT_Pos) & usb_DEVICE_PCKSIZE_BYTE_COUNT_Mask)
|
||||
|
||||
if bytesread != cdcLineInfoSize {
|
||||
return b, ErrUSBBytesRead
|
||||
}
|
||||
|
||||
copy(b[:7], udd_ep_out_cache_buffer[0][:7])
|
||||
|
||||
return b, nil
|
||||
}
|
||||
|
||||
func handleEndpointRx(ep uint32) []byte {
|
||||
// get data
|
||||
count := int((usbEndpointDescriptors[ep].DeviceDescBank[0].PCKSIZE.Get() >>
|
||||
usb_DEVICE_PCKSIZE_BYTE_COUNT_Pos) & usb_DEVICE_PCKSIZE_BYTE_COUNT_Mask)
|
||||
|
||||
return udd_ep_out_cache_buffer[ep][:count]
|
||||
}
|
||||
|
||||
func handleEndpointRxComplete(ep uint32) {
|
||||
// set byte count to zero
|
||||
usbEndpointDescriptors[ep].DeviceDescBank[0].PCKSIZE.ClearBits(usb_DEVICE_PCKSIZE_BYTE_COUNT_Mask << usb_DEVICE_PCKSIZE_BYTE_COUNT_Pos)
|
||||
|
||||
// set multi packet size to 64
|
||||
usbEndpointDescriptors[ep].DeviceDescBank[0].PCKSIZE.SetBits(64 << usb_DEVICE_PCKSIZE_MULTI_PACKET_SIZE_Pos)
|
||||
|
||||
// set ready for next data
|
||||
setEPSTATUSCLR(ep, sam.USB_DEVICE_ENDPOINT_EPSTATUSCLR_BK0RDY)
|
||||
}
|
||||
|
||||
func SendZlp() {
|
||||
usbEndpointDescriptors[0].DeviceDescBank[1].PCKSIZE.ClearBits(usb_DEVICE_PCKSIZE_BYTE_COUNT_Mask << usb_DEVICE_PCKSIZE_BYTE_COUNT_Pos)
|
||||
}
|
||||
|
||||
func epPacketSize(size uint16) uint32 {
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
func getEPCFG(ep uint32) uint8 {
|
||||
return sam.USB_DEVICE.DEVICE_ENDPOINT[ep].EPCFG.Get()
|
||||
}
|
||||
|
||||
func setEPCFG(ep uint32, val uint8) {
|
||||
sam.USB_DEVICE.DEVICE_ENDPOINT[ep].EPCFG.Set(val)
|
||||
}
|
||||
|
||||
func setEPSTATUSCLR(ep uint32, val uint8) {
|
||||
sam.USB_DEVICE.DEVICE_ENDPOINT[ep].EPSTATUSCLR.Set(val)
|
||||
}
|
||||
|
||||
func setEPSTATUSSET(ep uint32, val uint8) {
|
||||
sam.USB_DEVICE.DEVICE_ENDPOINT[ep].EPSTATUSSET.Set(val)
|
||||
}
|
||||
|
||||
func getEPSTATUS(ep uint32) uint8 {
|
||||
return sam.USB_DEVICE.DEVICE_ENDPOINT[ep].EPSTATUS.Get()
|
||||
}
|
||||
|
||||
func getEPINTFLAG(ep uint32) uint8 {
|
||||
return sam.USB_DEVICE.DEVICE_ENDPOINT[ep].EPINTFLAG.Get()
|
||||
}
|
||||
|
||||
func setEPINTFLAG(ep uint32, val uint8) {
|
||||
sam.USB_DEVICE.DEVICE_ENDPOINT[ep].EPINTFLAG.Set(val)
|
||||
}
|
||||
|
||||
func setEPINTENCLR(ep uint32, val uint8) {
|
||||
sam.USB_DEVICE.DEVICE_ENDPOINT[ep].EPINTENCLR.Set(val)
|
||||
}
|
||||
|
||||
func setEPINTENSET(ep uint32, val uint8) {
|
||||
sam.USB_DEVICE.DEVICE_ENDPOINT[ep].EPINTENSET.Set(val)
|
||||
}
|
||||
@@ -31,6 +31,44 @@ const (
|
||||
PinInputPulldown
|
||||
)
|
||||
|
||||
// Hardware pin numbers
|
||||
const (
|
||||
GPIO0 Pin = 0
|
||||
GPIO1 Pin = 1
|
||||
GPIO2 Pin = 2
|
||||
GPIO3 Pin = 3
|
||||
GPIO4 Pin = 4
|
||||
GPIO5 Pin = 5
|
||||
GPIO6 Pin = 6
|
||||
GPIO7 Pin = 7
|
||||
GPIO8 Pin = 8
|
||||
GPIO9 Pin = 9
|
||||
GPIO10 Pin = 10
|
||||
GPIO11 Pin = 11
|
||||
GPIO12 Pin = 12
|
||||
GPIO13 Pin = 13
|
||||
GPIO14 Pin = 14
|
||||
GPIO15 Pin = 15
|
||||
GPIO16 Pin = 16
|
||||
GPIO17 Pin = 17
|
||||
GPIO18 Pin = 18
|
||||
GPIO19 Pin = 19
|
||||
GPIO21 Pin = 21
|
||||
GPIO22 Pin = 22
|
||||
GPIO23 Pin = 23
|
||||
GPIO25 Pin = 25
|
||||
GPIO26 Pin = 26
|
||||
GPIO27 Pin = 27
|
||||
GPIO32 Pin = 32
|
||||
GPIO33 Pin = 33
|
||||
GPIO34 Pin = 34
|
||||
GPIO35 Pin = 35
|
||||
GPIO36 Pin = 36
|
||||
GPIO37 Pin = 37
|
||||
GPIO38 Pin = 38
|
||||
GPIO39 Pin = 39
|
||||
)
|
||||
|
||||
// Configure this pin with the given configuration.
|
||||
func (p Pin) Configure(config PinConfig) {
|
||||
// Output function 256 is a special value reserved for use as a regular GPIO
|
||||
@@ -440,16 +478,35 @@ func (spi SPI) Tx(w, r []byte) error {
|
||||
|
||||
// Fill tx buffer.
|
||||
transferWords := (*[16]volatile.Register32)(unsafe.Pointer(uintptr(unsafe.Pointer(&spi.Bus.W0))))
|
||||
var outBuf [16]uint32
|
||||
txSize := 64
|
||||
if txSize > len(w) {
|
||||
txSize = len(w)
|
||||
}
|
||||
for i := 0; i < txSize; i++ {
|
||||
outBuf[i/4] = outBuf[i/4] | uint32(w[i])<<((i%4)*8)
|
||||
}
|
||||
for i, word := range outBuf {
|
||||
transferWords[i].Set(word)
|
||||
if len(w) >= 64 {
|
||||
// We can fill the entire 64-byte transfer buffer with data.
|
||||
// This loop is slightly faster than the loop below.
|
||||
for i := 0; i < 16; i++ {
|
||||
word := uint32(w[i*4])<<0 | uint32(w[i*4+1])<<8 | uint32(w[i*4+2])<<16 | uint32(w[i*4+3])<<24
|
||||
transferWords[i].Set(word)
|
||||
}
|
||||
} else {
|
||||
// We can't fill the entire transfer buffer, so we need to be a bit
|
||||
// more careful.
|
||||
// Note that parts of the transfer buffer that aren't used still
|
||||
// need to be set to zero, otherwise we might be transferring
|
||||
// garbage from a previous transmission if w is smaller than r.
|
||||
for i := 0; i < 16; i++ {
|
||||
var word uint32
|
||||
if i*4+3 < len(w) {
|
||||
word |= uint32(w[i*4+3]) << 24
|
||||
}
|
||||
if i*4+2 < len(w) {
|
||||
word |= uint32(w[i*4+2]) << 16
|
||||
}
|
||||
if i*4+1 < len(w) {
|
||||
word |= uint32(w[i*4+1]) << 8
|
||||
}
|
||||
if i*4+0 < len(w) {
|
||||
word |= uint32(w[i*4+0]) << 0
|
||||
}
|
||||
transferWords[i].Set(word)
|
||||
}
|
||||
}
|
||||
|
||||
// Do the transfer.
|
||||
|
||||
@@ -30,6 +30,31 @@ const (
|
||||
PinInputPulldown
|
||||
)
|
||||
|
||||
const (
|
||||
GPIO0 Pin = 0
|
||||
GPIO1 Pin = 1
|
||||
GPIO2 Pin = 2
|
||||
GPIO3 Pin = 3
|
||||
GPIO4 Pin = 4
|
||||
GPIO5 Pin = 5
|
||||
GPIO6 Pin = 6
|
||||
GPIO7 Pin = 7
|
||||
GPIO8 Pin = 8
|
||||
GPIO9 Pin = 9
|
||||
GPIO10 Pin = 10
|
||||
GPIO11 Pin = 11
|
||||
GPIO12 Pin = 12
|
||||
GPIO13 Pin = 13
|
||||
GPIO14 Pin = 14
|
||||
GPIO15 Pin = 15
|
||||
GPIO16 Pin = 16
|
||||
GPIO17 Pin = 17
|
||||
GPIO18 Pin = 18
|
||||
GPIO19 Pin = 19
|
||||
GPIO20 Pin = 20
|
||||
GPIO21 Pin = 21
|
||||
)
|
||||
|
||||
type PinChange uint8
|
||||
|
||||
// Pin change interrupt constants for SetInterrupt.
|
||||
|
||||
@@ -19,6 +19,27 @@ const (
|
||||
PinInput
|
||||
)
|
||||
|
||||
// Hardware pin numbers
|
||||
const (
|
||||
GPIO0 Pin = iota
|
||||
GPIO1
|
||||
GPIO2
|
||||
GPIO3
|
||||
GPIO4
|
||||
GPIO5
|
||||
GPIO6
|
||||
GPIO7
|
||||
GPIO8
|
||||
GPIO9
|
||||
GPIO10
|
||||
GPIO11
|
||||
GPIO12
|
||||
GPIO13
|
||||
GPIO14
|
||||
GPIO15
|
||||
GPIO16
|
||||
)
|
||||
|
||||
// Pins that are fixed by the chip.
|
||||
const (
|
||||
UART_TX_PIN Pin = 1
|
||||
|
||||
@@ -7,10 +7,6 @@ import (
|
||||
"device/nrf"
|
||||
)
|
||||
|
||||
func CPUFrequency() uint32 {
|
||||
return 16000000
|
||||
}
|
||||
|
||||
// Get peripheral and pin number for this GPIO pin.
|
||||
func (p Pin) getPortPin() (*nrf.GPIO_Type, uint32) {
|
||||
return nrf.GPIO, uint32(p)
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
//go:build nrf52840
|
||||
// +build nrf52840
|
||||
|
||||
package machine
|
||||
|
||||
import (
|
||||
"device/arm"
|
||||
"device/nrf"
|
||||
)
|
||||
|
||||
const (
|
||||
DFU_MAGIC_SERIAL_ONLY_RESET = 0x4e
|
||||
DFU_MAGIC_UF2_RESET = 0x57
|
||||
DFU_MAGIC_OTA_RESET = 0xA8
|
||||
)
|
||||
|
||||
// EnterSerialBootloader resets the chip into the serial bootloader. After
|
||||
// reset, it can be flashed using serial/nrfutil.
|
||||
func EnterSerialBootloader() {
|
||||
arm.DisableInterrupts()
|
||||
nrf.POWER.GPREGRET.Set(DFU_MAGIC_SERIAL_ONLY_RESET)
|
||||
arm.SystemReset()
|
||||
}
|
||||
|
||||
// EnterUF2Bootloader resets the chip into the UF2 bootloader. After reset, it
|
||||
// can be flashed via nrfutil or by copying a UF2 file to the mass storage device
|
||||
func EnterUF2Bootloader() {
|
||||
arm.DisableInterrupts()
|
||||
nrf.POWER.GPREGRET.Set(DFU_MAGIC_UF2_RESET)
|
||||
arm.SystemReset()
|
||||
}
|
||||
|
||||
// EnterOTABootloader resets the chip into the bootloader so that it can be
|
||||
// flashed via an OTA update
|
||||
func EnterOTABootloader() {
|
||||
arm.DisableInterrupts()
|
||||
nrf.POWER.GPREGRET.Set(DFU_MAGIC_OTA_RESET)
|
||||
arm.SystemReset()
|
||||
}
|
||||
+170
-370
@@ -6,148 +6,21 @@ package machine
|
||||
import (
|
||||
"device/arm"
|
||||
"device/nrf"
|
||||
"machine/usb"
|
||||
"runtime/interrupt"
|
||||
"runtime/volatile"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
// USBCDC is the USB CDC aka serial over USB interface on the nRF52840
|
||||
type USBCDC struct {
|
||||
Buffer *RingBuffer
|
||||
interrupt interrupt.Interrupt
|
||||
initcomplete bool
|
||||
TxIdx volatile.Register8
|
||||
waitTxc bool
|
||||
waitTxcRetryCount uint8
|
||||
sent bool
|
||||
}
|
||||
|
||||
const (
|
||||
usbcdcTxSizeMask uint8 = 0x3F
|
||||
usbcdcTxBankMask uint8 = ^usbcdcTxSizeMask
|
||||
usbcdcTxBank1st uint8 = 0x00
|
||||
usbcdcTxBank2nd uint8 = usbcdcTxSizeMask + 1
|
||||
usbcdcTxMaxRetriesAllowed uint8 = 5
|
||||
)
|
||||
|
||||
// Flush flushes buffered data.
|
||||
func (usbcdc *USBCDC) Flush() error {
|
||||
if usbLineInfo.lineState > 0 {
|
||||
idx := usbcdc.TxIdx.Get()
|
||||
sz := idx & usbcdcTxSizeMask
|
||||
bk := idx & usbcdcTxBankMask
|
||||
if 0 < sz {
|
||||
|
||||
if usbcdc.waitTxc {
|
||||
// waiting for the next flush(), because the transmission is not complete
|
||||
usbcdc.waitTxcRetryCount++
|
||||
return nil
|
||||
}
|
||||
usbcdc.waitTxc = true
|
||||
usbcdc.waitTxcRetryCount = 0
|
||||
|
||||
// set the data
|
||||
enterCriticalSection()
|
||||
sendViaEPIn(
|
||||
usb_CDC_ENDPOINT_IN,
|
||||
&udd_ep_in_cache_buffer[usb_CDC_ENDPOINT_IN][bk],
|
||||
int(sz),
|
||||
)
|
||||
if bk == usbcdcTxBank1st {
|
||||
usbcdc.TxIdx.Set(usbcdcTxBank2nd)
|
||||
} else {
|
||||
usbcdc.TxIdx.Set(usbcdcTxBank1st)
|
||||
}
|
||||
|
||||
usbcdc.sent = true
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// WriteByte writes a byte of data to the USB CDC interface.
|
||||
func (usbcdc *USBCDC) WriteByte(c byte) error {
|
||||
// Supposedly to handle problem with Windows USB serial ports?
|
||||
if usbLineInfo.lineState > 0 {
|
||||
ok := false
|
||||
for {
|
||||
mask := interrupt.Disable()
|
||||
|
||||
idx := usbcdc.TxIdx.Get()
|
||||
if (idx & usbcdcTxSizeMask) < usbcdcTxSizeMask {
|
||||
udd_ep_in_cache_buffer[usb_CDC_ENDPOINT_IN][idx] = c
|
||||
usbcdc.TxIdx.Set(idx + 1)
|
||||
ok = true
|
||||
}
|
||||
|
||||
interrupt.Restore(mask)
|
||||
|
||||
if ok {
|
||||
break
|
||||
} else if usbcdcTxMaxRetriesAllowed < usbcdc.waitTxcRetryCount {
|
||||
mask := interrupt.Disable()
|
||||
usbcdc.waitTxc = false
|
||||
usbcdc.waitTxcRetryCount = 0
|
||||
usbcdc.TxIdx.Set(0)
|
||||
usbLineInfo.lineState = 0
|
||||
interrupt.Restore(mask)
|
||||
break
|
||||
} else {
|
||||
mask := interrupt.Disable()
|
||||
if usbcdc.sent {
|
||||
if usbcdc.waitTxc {
|
||||
if !easyDMABusy.HasBits(1) {
|
||||
usbcdc.waitTxc = false
|
||||
usbcdc.Flush()
|
||||
}
|
||||
} else {
|
||||
usbcdc.Flush()
|
||||
}
|
||||
}
|
||||
interrupt.Restore(mask)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (usbcdc *USBCDC) DTR() bool {
|
||||
return (usbLineInfo.lineState & usb_CDC_LINESTATE_DTR) > 0
|
||||
}
|
||||
|
||||
func (usbcdc *USBCDC) RTS() bool {
|
||||
return (usbLineInfo.lineState & usb_CDC_LINESTATE_RTS) > 0
|
||||
}
|
||||
|
||||
var (
|
||||
USB = &_USB
|
||||
_USB = USBCDC{Buffer: NewRingBuffer()}
|
||||
waitHidTxc bool
|
||||
|
||||
usbEndpointDescriptors [8]usbDeviceDescriptor
|
||||
|
||||
udd_ep_in_cache_buffer [7][128]uint8
|
||||
udd_ep_out_cache_buffer [7][128]uint8
|
||||
|
||||
sendOnEP0DATADONE struct {
|
||||
ptr *byte
|
||||
count int
|
||||
ptr *byte
|
||||
count int
|
||||
offset int
|
||||
}
|
||||
isEndpointHalt = false
|
||||
isRemoteWakeUpEnabled = false
|
||||
endPoints = []uint32{usb_ENDPOINT_TYPE_CONTROL,
|
||||
(usb_ENDPOINT_TYPE_INTERRUPT | usbEndpointIn),
|
||||
(usb_ENDPOINT_TYPE_BULK | usbEndpointOut),
|
||||
(usb_ENDPOINT_TYPE_BULK | usbEndpointIn)}
|
||||
|
||||
usbConfiguration uint8
|
||||
usbSetInterface uint8
|
||||
usbLineInfo = cdcLineInfo{115200, 0x00, 0x00, 0x08, 0x00}
|
||||
epinen uint32
|
||||
epouten uint32
|
||||
easyDMABusy volatile.Register8
|
||||
epout0data_setlinecoding bool
|
||||
epinen uint32
|
||||
epouten uint32
|
||||
easyDMABusy volatile.Register8
|
||||
)
|
||||
|
||||
// enterCriticalSection is used to protect access to easyDMA - only one thing
|
||||
@@ -167,44 +40,58 @@ func exitCriticalSection() {
|
||||
easyDMABusy.ClearBits(1)
|
||||
}
|
||||
|
||||
// Configure the USB CDC interface. The config is here for compatibility with the UART interface.
|
||||
func (usbcdc *USBCDC) Configure(config UARTConfig) {
|
||||
if usbcdc.initcomplete {
|
||||
// Configure the USB peripheral. The config is here for compatibility with the UART interface.
|
||||
func (dev *USBDevice) Configure(config UARTConfig) {
|
||||
if dev.initcomplete {
|
||||
return
|
||||
}
|
||||
|
||||
state := interrupt.Disable()
|
||||
defer interrupt.Restore(state)
|
||||
|
||||
nrf.USBD.USBPULLUP.Set(0)
|
||||
|
||||
// Enable IRQ. Make sure this is higher than the SWI2 interrupt handler so
|
||||
// that it is possible to print to the console from a BLE interrupt. You
|
||||
// shouldn't generally do that but it is useful for debugging and panic
|
||||
// logging.
|
||||
usbcdc.interrupt = interrupt.New(nrf.IRQ_USBD, _USB.handleInterrupt)
|
||||
usbcdc.interrupt.SetPriority(0x40) // interrupt priority 2 (lower number means more important)
|
||||
usbcdc.interrupt.Enable()
|
||||
intr := interrupt.New(nrf.IRQ_USBD, handleUSBIRQ)
|
||||
intr.SetPriority(0x40) // interrupt priority 2 (lower number means more important)
|
||||
intr.Enable()
|
||||
|
||||
// enable interrupt for end of reset and start of frame
|
||||
nrf.USBD.INTEN.Set(nrf.USBD_INTENSET_USBEVENT)
|
||||
|
||||
// errata 187
|
||||
// https://infocenter.nordicsemi.com/topic/errata_nRF52840_EngB/ERR/nRF52840/EngineeringB/latest/anomaly_840_187.html
|
||||
(*volatile.Register32)(unsafe.Pointer(uintptr(0x4006EC00))).Set(0x00009375)
|
||||
(*volatile.Register32)(unsafe.Pointer(uintptr(0x4006ED14))).Set(0x00000003)
|
||||
(*volatile.Register32)(unsafe.Pointer(uintptr(0x4006EC00))).Set(0x00009375)
|
||||
|
||||
// enable USB
|
||||
nrf.USBD.ENABLE.Set(1)
|
||||
|
||||
// enable interrupt for end of reset and start of frame
|
||||
nrf.USBD.INTENSET.Set(
|
||||
nrf.USBD_INTENSET_EPDATA |
|
||||
nrf.USBD_INTENSET_EP0DATADONE |
|
||||
nrf.USBD_INTENSET_USBEVENT |
|
||||
nrf.USBD_INTENSET_SOF |
|
||||
nrf.USBD_INTENSET_EP0SETUP,
|
||||
)
|
||||
timeout := 300000
|
||||
for !nrf.USBD.EVENTCAUSE.HasBits(nrf.USBD_EVENTCAUSE_READY) {
|
||||
timeout--
|
||||
if timeout == 0 {
|
||||
return
|
||||
}
|
||||
}
|
||||
nrf.USBD.EVENTCAUSE.ClearBits(nrf.USBD_EVENTCAUSE_READY)
|
||||
|
||||
nrf.USBD.USBPULLUP.Set(0)
|
||||
// errata 187
|
||||
(*volatile.Register32)(unsafe.Pointer(uintptr(0x4006EC00))).Set(0x00009375)
|
||||
(*volatile.Register32)(unsafe.Pointer(uintptr(0x4006ED14))).Set(0x00000000)
|
||||
(*volatile.Register32)(unsafe.Pointer(uintptr(0x4006EC00))).Set(0x00009375)
|
||||
|
||||
usbcdc.initcomplete = true
|
||||
dev.initcomplete = true
|
||||
}
|
||||
|
||||
func (usbcdc *USBCDC) handleInterrupt(interrupt.Interrupt) {
|
||||
func handleUSBIRQ(interrupt.Interrupt) {
|
||||
if nrf.USBD.EVENTS_SOF.Get() == 1 {
|
||||
nrf.USBD.EVENTS_SOF.Set(0)
|
||||
usbcdc.Flush()
|
||||
if hidCallback != nil && !waitHidTxc {
|
||||
hidCallback()
|
||||
}
|
||||
|
||||
// if you want to blink LED showing traffic, this would be the place...
|
||||
}
|
||||
|
||||
@@ -214,10 +101,7 @@ func (usbcdc *USBCDC) handleInterrupt(interrupt.Interrupt) {
|
||||
if (nrf.USBD.EVENTCAUSE.Get() & nrf.USBD_EVENTCAUSE_READY) > 0 {
|
||||
|
||||
// Configure control endpoint
|
||||
initEndpoint(0, usb_ENDPOINT_TYPE_CONTROL)
|
||||
|
||||
// Enable Setup-Received interrupt
|
||||
nrf.USBD.INTENSET.Set(nrf.USBD_INTENSET_EP0SETUP)
|
||||
initEndpoint(0, usb.ENDPOINT_TYPE_CONTROL)
|
||||
nrf.USBD.USBPULLUP.Set(1)
|
||||
|
||||
usbConfiguration = 0
|
||||
@@ -228,25 +112,30 @@ func (usbcdc *USBCDC) handleInterrupt(interrupt.Interrupt) {
|
||||
if nrf.USBD.EVENTS_EP0DATADONE.Get() == 1 {
|
||||
// done sending packet - either need to send another or enter status stage
|
||||
nrf.USBD.EVENTS_EP0DATADONE.Set(0)
|
||||
if epout0data_setlinecoding {
|
||||
nrf.USBD.EPOUT[0].PTR.Set(uint32(uintptr(unsafe.Pointer(&udd_ep_out_cache_buffer[0]))))
|
||||
nrf.USBD.EPOUT[0].MAXCNT.Set(64)
|
||||
nrf.USBD.TASKS_STARTEPOUT[0].Set(1)
|
||||
return
|
||||
}
|
||||
if sendOnEP0DATADONE.ptr != nil {
|
||||
// previous data was too big for one packet, so send a second
|
||||
ptr := sendOnEP0DATADONE.ptr
|
||||
count := sendOnEP0DATADONE.count
|
||||
if count > usb.EndpointPacketSize {
|
||||
sendOnEP0DATADONE.offset += usb.EndpointPacketSize
|
||||
sendOnEP0DATADONE.ptr = &udd_ep_control_cache_buffer[sendOnEP0DATADONE.offset]
|
||||
count = usb.EndpointPacketSize
|
||||
}
|
||||
sendOnEP0DATADONE.count -= count
|
||||
sendViaEPIn(
|
||||
0,
|
||||
sendOnEP0DATADONE.ptr,
|
||||
sendOnEP0DATADONE.count,
|
||||
ptr,
|
||||
count,
|
||||
)
|
||||
|
||||
// clear, so we know we're done
|
||||
sendOnEP0DATADONE.ptr = nil
|
||||
if sendOnEP0DATADONE.count == 0 {
|
||||
sendOnEP0DATADONE.ptr = nil
|
||||
sendOnEP0DATADONE.offset = 0
|
||||
}
|
||||
} else {
|
||||
// no more data, so set status stage
|
||||
nrf.USBD.TASKS_EP0STATUS.Set(1)
|
||||
SendZlp() // nrf.USBD.TASKS_EP0STATUS.Set(1)
|
||||
}
|
||||
return
|
||||
}
|
||||
@@ -260,15 +149,13 @@ func (usbcdc *USBCDC) handleInterrupt(interrupt.Interrupt) {
|
||||
setup := parseUSBSetupRegisters()
|
||||
|
||||
ok := false
|
||||
if (setup.bmRequestType & usb_REQUEST_TYPE) == usb_REQUEST_STANDARD {
|
||||
if (setup.BmRequestType & usb.REQUEST_TYPE) == usb.REQUEST_STANDARD {
|
||||
// Standard Requests
|
||||
ok = handleStandardSetup(setup)
|
||||
} else {
|
||||
if setup.wIndex == usb_CDC_ACM_INTERFACE {
|
||||
ok = cdcSetup(setup)
|
||||
} else if setup.bmRequestType == usb_SET_REPORT_TYPE && setup.bRequest == usb_SET_IDLE {
|
||||
sendZlp()
|
||||
ok = true
|
||||
// Class Interface Requests
|
||||
if setup.WIndex < uint16(len(usbSetupHandler)) && usbSetupHandler[setup.WIndex] != nil {
|
||||
ok = usbSetupHandler[setup.WIndex](setup)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -288,25 +175,16 @@ func (usbcdc *USBCDC) handleInterrupt(interrupt.Interrupt) {
|
||||
// Check if endpoint has a pending interrupt
|
||||
inDataDone := epDataStatus&(nrf.USBD_EPDATASTATUS_EPIN1<<(i-1)) > 0
|
||||
outDataDone := epDataStatus&(nrf.USBD_EPDATASTATUS_EPOUT1<<(i-1)) > 0
|
||||
if inDataDone || outDataDone {
|
||||
switch i {
|
||||
case usb_CDC_ENDPOINT_OUT:
|
||||
// setup buffer to receive from host
|
||||
if outDataDone {
|
||||
enterCriticalSection()
|
||||
nrf.USBD.EPOUT[i].PTR.Set(uint32(uintptr(unsafe.Pointer(&udd_ep_out_cache_buffer[i]))))
|
||||
count := nrf.USBD.SIZE.EPOUT[i].Get()
|
||||
nrf.USBD.EPOUT[i].MAXCNT.Set(count)
|
||||
nrf.USBD.TASKS_STARTEPOUT[i].Set(1)
|
||||
}
|
||||
case usb_CDC_ENDPOINT_IN: //, usb_CDC_ENDPOINT_ACM:
|
||||
if inDataDone {
|
||||
usbcdc.waitTxc = false
|
||||
exitCriticalSection()
|
||||
}
|
||||
case usb_HID_ENDPOINT_IN:
|
||||
waitHidTxc = false
|
||||
if inDataDone {
|
||||
if usbTxHandler[i] != nil {
|
||||
usbTxHandler[i]()
|
||||
}
|
||||
} else if outDataDone {
|
||||
enterCriticalSection()
|
||||
nrf.USBD.EPOUT[i].PTR.Set(uint32(uintptr(unsafe.Pointer(&udd_ep_out_cache_buffer[i]))))
|
||||
count := nrf.USBD.SIZE.EPOUT[i].Get()
|
||||
nrf.USBD.EPOUT[i].MAXCNT.Set(count)
|
||||
nrf.USBD.TASKS_STARTEPOUT[i].Set(1)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -315,200 +193,63 @@ func (usbcdc *USBCDC) handleInterrupt(interrupt.Interrupt) {
|
||||
for i := 0; i < len(endPoints); i++ {
|
||||
if nrf.USBD.EVENTS_ENDEPOUT[i].Get() > 0 {
|
||||
nrf.USBD.EVENTS_ENDEPOUT[i].Set(0)
|
||||
if i == 0 && epout0data_setlinecoding {
|
||||
epout0data_setlinecoding = false
|
||||
count := int(nrf.USBD.SIZE.EPOUT[0].Get())
|
||||
if count >= 7 {
|
||||
parseUSBLineInfo(udd_ep_out_cache_buffer[0][:count])
|
||||
checkShouldReset()
|
||||
}
|
||||
nrf.USBD.TASKS_EP0STATUS.Set(1)
|
||||
}
|
||||
if i == usb_CDC_ENDPOINT_OUT {
|
||||
usbcdc.handleEndpoint(uint32(i))
|
||||
buf := handleEndpointRx(uint32(i))
|
||||
if usbRxHandler[i] != nil {
|
||||
usbRxHandler[i](buf)
|
||||
}
|
||||
handleEndpointRxComplete(uint32(i))
|
||||
exitCriticalSection()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func parseUSBLineInfo(b []byte) {
|
||||
usbLineInfo.dwDTERate = uint32(b[0]) | uint32(b[1])<<8 | uint32(b[2])<<16 | uint32(b[3])<<24
|
||||
usbLineInfo.bCharFormat = b[4]
|
||||
usbLineInfo.bParityType = b[5]
|
||||
usbLineInfo.bDataBits = b[6]
|
||||
}
|
||||
|
||||
func parseUSBSetupRegisters() usbSetup {
|
||||
return usbSetup{
|
||||
bmRequestType: uint8(nrf.USBD.BMREQUESTTYPE.Get()),
|
||||
bRequest: uint8(nrf.USBD.BREQUEST.Get()),
|
||||
wValueL: uint8(nrf.USBD.WVALUEL.Get()),
|
||||
wValueH: uint8(nrf.USBD.WVALUEH.Get()),
|
||||
wIndex: uint16((nrf.USBD.WINDEXH.Get() << 8) | nrf.USBD.WINDEXL.Get()),
|
||||
wLength: uint16(((nrf.USBD.WLENGTHH.Get() & 0xff) << 8) | (nrf.USBD.WLENGTHL.Get() & 0xff)),
|
||||
func parseUSBSetupRegisters() usb.Setup {
|
||||
return usb.Setup{
|
||||
BmRequestType: uint8(nrf.USBD.BMREQUESTTYPE.Get()),
|
||||
BRequest: uint8(nrf.USBD.BREQUEST.Get()),
|
||||
WValueL: uint8(nrf.USBD.WVALUEL.Get()),
|
||||
WValueH: uint8(nrf.USBD.WVALUEH.Get()),
|
||||
WIndex: uint16((nrf.USBD.WINDEXH.Get() << 8) | nrf.USBD.WINDEXL.Get()),
|
||||
WLength: uint16(((nrf.USBD.WLENGTHH.Get() & 0xff) << 8) | (nrf.USBD.WLENGTHL.Get() & 0xff)),
|
||||
}
|
||||
}
|
||||
|
||||
func initEndpoint(ep, config uint32) {
|
||||
switch config {
|
||||
case usb_ENDPOINT_TYPE_INTERRUPT | usbEndpointIn:
|
||||
case usb.ENDPOINT_TYPE_INTERRUPT | usb.EndpointIn:
|
||||
enableEPIn(ep)
|
||||
|
||||
case usb_ENDPOINT_TYPE_BULK | usbEndpointOut:
|
||||
case usb.ENDPOINT_TYPE_BULK | usb.EndpointOut:
|
||||
nrf.USBD.INTENSET.Set(nrf.USBD_INTENSET_ENDEPOUT0 << ep)
|
||||
nrf.USBD.SIZE.EPOUT[ep].Set(0)
|
||||
enableEPOut(ep)
|
||||
|
||||
case usb_ENDPOINT_TYPE_INTERRUPT | usbEndpointOut:
|
||||
case usb.ENDPOINT_TYPE_INTERRUPT | usb.EndpointOut:
|
||||
nrf.USBD.INTENSET.Set(nrf.USBD_INTENSET_ENDEPOUT0 << ep)
|
||||
nrf.USBD.SIZE.EPOUT[ep].Set(0)
|
||||
enableEPOut(ep)
|
||||
|
||||
case usb_ENDPOINT_TYPE_BULK | usbEndpointIn:
|
||||
case usb.ENDPOINT_TYPE_BULK | usb.EndpointIn:
|
||||
enableEPIn(ep)
|
||||
|
||||
case usb_ENDPOINT_TYPE_CONTROL:
|
||||
case usb.ENDPOINT_TYPE_CONTROL:
|
||||
enableEPIn(0)
|
||||
enableEPOut(0)
|
||||
nrf.USBD.INTENSET.Set(nrf.USBD_INTENSET_ENDEPOUT0)
|
||||
nrf.USBD.TASKS_EP0STATUS.Set(1)
|
||||
nrf.USBD.INTENSET.Set(nrf.USBD_INTENSET_ENDEPOUT0 |
|
||||
nrf.USBD_INTENSET_EP0SETUP |
|
||||
nrf.USBD_INTENSET_EPDATA |
|
||||
nrf.USBD_INTENSET_EP0DATADONE)
|
||||
SendZlp() // nrf.USBD.TASKS_EP0STATUS.Set(1)
|
||||
}
|
||||
}
|
||||
|
||||
func handleStandardSetup(setup usbSetup) bool {
|
||||
switch setup.bRequest {
|
||||
case usb_GET_STATUS:
|
||||
buf := []byte{0, 0}
|
||||
|
||||
if setup.bmRequestType != 0 { // endpoint
|
||||
if isEndpointHalt {
|
||||
buf[0] = 1
|
||||
}
|
||||
}
|
||||
|
||||
sendUSBPacket(0, buf, setup.wLength)
|
||||
return true
|
||||
|
||||
case usb_CLEAR_FEATURE:
|
||||
if setup.wValueL == 1 { // DEVICEREMOTEWAKEUP
|
||||
isRemoteWakeUpEnabled = false
|
||||
} else if setup.wValueL == 0 { // ENDPOINTHALT
|
||||
isEndpointHalt = false
|
||||
}
|
||||
nrf.USBD.TASKS_EP0STATUS.Set(1)
|
||||
return true
|
||||
|
||||
case usb_SET_FEATURE:
|
||||
if setup.wValueL == 1 { // DEVICEREMOTEWAKEUP
|
||||
isRemoteWakeUpEnabled = true
|
||||
} else if setup.wValueL == 0 { // ENDPOINTHALT
|
||||
isEndpointHalt = true
|
||||
}
|
||||
nrf.USBD.TASKS_EP0STATUS.Set(1)
|
||||
return true
|
||||
|
||||
case usb_SET_ADDRESS:
|
||||
// nrf USBD handles this
|
||||
return true
|
||||
|
||||
case usb_GET_DESCRIPTOR:
|
||||
sendDescriptor(setup)
|
||||
return true
|
||||
|
||||
case usb_SET_DESCRIPTOR:
|
||||
return false
|
||||
|
||||
case usb_GET_CONFIGURATION:
|
||||
buff := []byte{usbConfiguration}
|
||||
sendUSBPacket(0, buff, setup.wLength)
|
||||
return true
|
||||
|
||||
case usb_SET_CONFIGURATION:
|
||||
if setup.bmRequestType&usb_REQUEST_RECIPIENT == usb_REQUEST_DEVICE {
|
||||
nrf.USBD.TASKS_EP0STATUS.Set(1)
|
||||
for i := 1; i < len(endPoints); i++ {
|
||||
initEndpoint(uint32(i), endPoints[i])
|
||||
}
|
||||
|
||||
// Enable interrupt for HID messages from host
|
||||
if hidCallback != nil {
|
||||
nrf.USBD.INTENSET.Set(nrf.USBD_INTENSET_ENDEPOUT0 << usb_HID_ENDPOINT_IN)
|
||||
}
|
||||
|
||||
usbConfiguration = setup.wValueL
|
||||
return true
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
|
||||
case usb_GET_INTERFACE:
|
||||
buff := []byte{usbSetInterface}
|
||||
sendUSBPacket(0, buff, setup.wLength)
|
||||
return true
|
||||
|
||||
case usb_SET_INTERFACE:
|
||||
usbSetInterface = setup.wValueL
|
||||
|
||||
nrf.USBD.TASKS_EP0STATUS.Set(1)
|
||||
return true
|
||||
|
||||
default:
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
func cdcSetup(setup usbSetup) bool {
|
||||
if setup.bmRequestType == usb_REQUEST_DEVICETOHOST_CLASS_INTERFACE {
|
||||
if setup.bRequest == usb_CDC_GET_LINE_CODING {
|
||||
var b [cdcLineInfoSize]byte
|
||||
b[0] = byte(usbLineInfo.dwDTERate)
|
||||
b[1] = byte(usbLineInfo.dwDTERate >> 8)
|
||||
b[2] = byte(usbLineInfo.dwDTERate >> 16)
|
||||
b[3] = byte(usbLineInfo.dwDTERate >> 24)
|
||||
b[4] = byte(usbLineInfo.bCharFormat)
|
||||
b[5] = byte(usbLineInfo.bParityType)
|
||||
b[6] = byte(usbLineInfo.bDataBits)
|
||||
|
||||
sendUSBPacket(0, b[:], setup.wLength)
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
if setup.bmRequestType == usb_REQUEST_HOSTTODEVICE_CLASS_INTERFACE {
|
||||
if setup.bRequest == usb_CDC_SET_LINE_CODING {
|
||||
epout0data_setlinecoding = true
|
||||
nrf.USBD.TASKS_EP0RCVOUT.Set(1)
|
||||
return true
|
||||
}
|
||||
|
||||
if setup.bRequest == usb_CDC_SET_CONTROL_LINE_STATE {
|
||||
usbLineInfo.lineState = setup.wValueL
|
||||
checkShouldReset()
|
||||
nrf.USBD.TASKS_EP0STATUS.Set(1)
|
||||
}
|
||||
|
||||
if setup.bRequest == usb_CDC_SEND_BREAK {
|
||||
nrf.USBD.TASKS_EP0STATUS.Set(1)
|
||||
}
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// SendUSBHIDPacket sends a packet for USBHID (interrupt / in).
|
||||
func SendUSBHIDPacket(ep uint32, data []byte) bool {
|
||||
if waitHidTxc {
|
||||
return false
|
||||
}
|
||||
|
||||
// SendUSBInPacket sends a packet for USBHID (interrupt in / bulk in).
|
||||
func SendUSBInPacket(ep uint32, data []byte) bool {
|
||||
sendUSBPacket(ep, data, 0)
|
||||
|
||||
// clear transfer complete flag
|
||||
nrf.USBD.INTENCLR.Set(nrf.USBD_INTENCLR_ENDEPOUT0 << 4)
|
||||
|
||||
waitHidTxc = true
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
@@ -518,33 +259,43 @@ func sendUSBPacket(ep uint32, data []byte, maxsize uint16) {
|
||||
if 0 < int(maxsize) && int(maxsize) < count {
|
||||
count = int(maxsize)
|
||||
}
|
||||
copy(udd_ep_in_cache_buffer[ep][:], data[:count])
|
||||
if ep == 0 && count > usbEndpointPacketSize {
|
||||
sendOnEP0DATADONE.ptr = &udd_ep_in_cache_buffer[ep][usbEndpointPacketSize]
|
||||
sendOnEP0DATADONE.count = count - usbEndpointPacketSize
|
||||
count = usbEndpointPacketSize
|
||||
|
||||
if ep == 0 {
|
||||
copy(udd_ep_control_cache_buffer[:], data[:count])
|
||||
if count > usb.EndpointPacketSize {
|
||||
sendOnEP0DATADONE.offset = usb.EndpointPacketSize
|
||||
sendOnEP0DATADONE.ptr = &udd_ep_control_cache_buffer[sendOnEP0DATADONE.offset]
|
||||
sendOnEP0DATADONE.count = count - usb.EndpointPacketSize
|
||||
count = usb.EndpointPacketSize
|
||||
}
|
||||
sendViaEPIn(
|
||||
ep,
|
||||
&udd_ep_control_cache_buffer[0],
|
||||
count,
|
||||
)
|
||||
} else {
|
||||
copy(udd_ep_in_cache_buffer[ep][:], data[:count])
|
||||
sendViaEPIn(
|
||||
ep,
|
||||
&udd_ep_in_cache_buffer[ep][0],
|
||||
count,
|
||||
)
|
||||
}
|
||||
sendViaEPIn(
|
||||
ep,
|
||||
&udd_ep_in_cache_buffer[ep][0],
|
||||
count,
|
||||
)
|
||||
}
|
||||
|
||||
func (usbcdc *USBCDC) handleEndpoint(ep uint32) {
|
||||
func handleEndpointRx(ep uint32) []byte {
|
||||
// get data
|
||||
count := int(nrf.USBD.EPOUT[ep].AMOUNT.Get())
|
||||
|
||||
// move to ring buffer
|
||||
for i := 0; i < count; i++ {
|
||||
usbcdc.Receive(byte(udd_ep_out_cache_buffer[ep][i]))
|
||||
}
|
||||
return udd_ep_out_cache_buffer[ep][:count]
|
||||
}
|
||||
|
||||
func handleEndpointRxComplete(ep uint32) {
|
||||
// set ready for next data
|
||||
nrf.USBD.SIZE.EPOUT[ep].Set(0)
|
||||
}
|
||||
|
||||
func sendZlp() {
|
||||
func SendZlp() {
|
||||
nrf.USBD.TASKS_EP0STATUS.Set(1)
|
||||
}
|
||||
|
||||
@@ -565,3 +316,52 @@ func enableEPIn(ep uint32) {
|
||||
epinen = epinen | (nrf.USBD_EPINEN_IN0 << ep)
|
||||
nrf.USBD.EPINEN.Set(epinen)
|
||||
}
|
||||
|
||||
func handleUSBSetAddress(setup usb.Setup) bool {
|
||||
// nrf USBD handles this
|
||||
return true
|
||||
}
|
||||
|
||||
func ReceiveUSBControlPacket() ([cdcLineInfoSize]byte, error) {
|
||||
var b [cdcLineInfoSize]byte
|
||||
|
||||
nrf.USBD.TASKS_EP0RCVOUT.Set(1)
|
||||
|
||||
nrf.USBD.EPOUT[0].PTR.Set(uint32(uintptr(unsafe.Pointer(&udd_ep_out_cache_buffer[0]))))
|
||||
nrf.USBD.EPOUT[0].MAXCNT.Set(64)
|
||||
|
||||
timeout := 300000
|
||||
count := 0
|
||||
for {
|
||||
if nrf.USBD.EVENTS_EP0DATADONE.Get() == 1 {
|
||||
nrf.USBD.EVENTS_EP0DATADONE.Set(0)
|
||||
count = int(nrf.USBD.SIZE.EPOUT[0].Get())
|
||||
nrf.USBD.TASKS_STARTEPOUT[0].Set(1)
|
||||
break
|
||||
}
|
||||
timeout--
|
||||
if timeout == 0 {
|
||||
return b, ErrUSBReadTimeout
|
||||
}
|
||||
}
|
||||
|
||||
timeout = 300000
|
||||
for {
|
||||
if nrf.USBD.EVENTS_ENDEPOUT[0].Get() == 1 {
|
||||
nrf.USBD.EVENTS_ENDEPOUT[0].Set(0)
|
||||
break
|
||||
}
|
||||
|
||||
timeout--
|
||||
if timeout == 0 {
|
||||
return b, ErrUSBReadTimeout
|
||||
}
|
||||
}
|
||||
|
||||
nrf.USBD.TASKS_EP0STATUS.Set(1)
|
||||
nrf.USBD.TASKS_EP0RCVOUT.Set(0)
|
||||
|
||||
copy(b[:7], udd_ep_out_cache_buffer[0][:count])
|
||||
|
||||
return b, nil
|
||||
}
|
||||
|
||||
@@ -3,25 +3,8 @@
|
||||
|
||||
package machine
|
||||
|
||||
import (
|
||||
"device/arm"
|
||||
"device/nrf"
|
||||
)
|
||||
|
||||
const DFU_MAGIC_SERIAL_ONLY_RESET = 0xb0
|
||||
|
||||
// checkShouldReset is called by the USB-CDC implementation to check whether to
|
||||
// reset into the bootloader/OTA and if so, resets the chip appropriately.
|
||||
func checkShouldReset() {
|
||||
if usbLineInfo.dwDTERate == 1200 && usbLineInfo.lineState&usb_CDC_LINESTATE_DTR == 0 {
|
||||
EnterSerialBootloader()
|
||||
}
|
||||
}
|
||||
|
||||
// EnterSerialBootloader resets the chip into the serial bootloader. After
|
||||
// EnterBootloader resets the chip into the serial bootloader. After
|
||||
// reset, it can be flashed using serial/nrfutil.
|
||||
func EnterSerialBootloader() {
|
||||
arm.DisableInterrupts()
|
||||
nrf.POWER.GPREGRET.Set(DFU_MAGIC_SERIAL_ONLY_RESET)
|
||||
arm.SystemReset()
|
||||
func EnterBootloader() {
|
||||
EnterSerialBootloader()
|
||||
}
|
||||
|
||||
@@ -3,5 +3,7 @@
|
||||
|
||||
package machine
|
||||
|
||||
func checkShouldReset() {
|
||||
// EnterBootloader resets the chip into the serial bootloader.
|
||||
func EnterBootloader() {
|
||||
// skip
|
||||
}
|
||||
|
||||
@@ -3,45 +3,8 @@
|
||||
|
||||
package machine
|
||||
|
||||
import (
|
||||
"device/arm"
|
||||
"device/nrf"
|
||||
)
|
||||
|
||||
const (
|
||||
DFU_MAGIC_SERIAL_ONLY_RESET = 0x4e
|
||||
DFU_MAGIC_UF2_RESET = 0x57
|
||||
DFU_MAGIC_OTA_RESET = 0xA8
|
||||
)
|
||||
|
||||
// checkShouldReset is called by the USB-CDC implementation to check whether to
|
||||
// reset into the bootloader/OTA and if so, resets the chip appropriately.
|
||||
func checkShouldReset() {
|
||||
if usbLineInfo.dwDTERate == 1200 && usbLineInfo.lineState&usb_CDC_LINESTATE_DTR == 0 {
|
||||
EnterUF2Bootloader()
|
||||
}
|
||||
}
|
||||
|
||||
// EnterSerialBootloader resets the chip into the serial bootloader. After
|
||||
// reset, it can be flashed using serial/nrfutil.
|
||||
func EnterSerialBootloader() {
|
||||
arm.DisableInterrupts()
|
||||
nrf.POWER.GPREGRET.Set(DFU_MAGIC_SERIAL_ONLY_RESET)
|
||||
arm.SystemReset()
|
||||
}
|
||||
|
||||
// EnterUF2Bootloader resets the chip into the UF2 bootloader. After reset, it
|
||||
// EnterBootloader resets the chip into the UF2 bootloader. After reset, it
|
||||
// can be flashed via nrfutil or by copying a UF2 file to the mass storage device
|
||||
func EnterUF2Bootloader() {
|
||||
arm.DisableInterrupts()
|
||||
nrf.POWER.GPREGRET.Set(DFU_MAGIC_UF2_RESET)
|
||||
arm.SystemReset()
|
||||
}
|
||||
|
||||
// EnterOTABootloader resets the chip into the bootloader so that it can be
|
||||
// flashed via an OTA update
|
||||
func EnterOTABootloader() {
|
||||
arm.DisableInterrupts()
|
||||
nrf.POWER.GPREGRET.Set(DFU_MAGIC_OTA_RESET)
|
||||
arm.SystemReset()
|
||||
func EnterBootloader() {
|
||||
EnterUF2Bootloader()
|
||||
}
|
||||
|
||||
@@ -5,7 +5,6 @@ package machine
|
||||
|
||||
import (
|
||||
"device/rp"
|
||||
"runtime/interrupt"
|
||||
)
|
||||
|
||||
const deviceName = rp.Device
|
||||
@@ -91,38 +90,6 @@ func lightSleep(ticks uint64) {
|
||||
timer.lightSleep(ticks)
|
||||
}
|
||||
|
||||
// UART pins
|
||||
const (
|
||||
UART_TX_PIN = UART0_TX_PIN
|
||||
UART_RX_PIN = UART0_RX_PIN
|
||||
UART0_TX_PIN = GPIO0
|
||||
UART0_RX_PIN = GPIO1
|
||||
UART1_TX_PIN = GPIO8
|
||||
UART1_RX_PIN = GPIO9
|
||||
)
|
||||
|
||||
// UART on the RP2040
|
||||
var (
|
||||
UART0 = &_UART0
|
||||
_UART0 = UART{
|
||||
Buffer: NewRingBuffer(),
|
||||
Bus: rp.UART0,
|
||||
}
|
||||
|
||||
UART1 = &_UART1
|
||||
_UART1 = UART{
|
||||
Buffer: NewRingBuffer(),
|
||||
Bus: rp.UART1,
|
||||
}
|
||||
)
|
||||
|
||||
var DefaultUART = UART0
|
||||
|
||||
func init() {
|
||||
UART0.Interrupt = interrupt.New(rp.IRQ_UART0_IRQ, _UART0.handleInterrupt)
|
||||
UART1.Interrupt = interrupt.New(rp.IRQ_UART1_IRQ, _UART1.handleInterrupt)
|
||||
}
|
||||
|
||||
// CurrentCore returns the core number the call was made from.
|
||||
func CurrentCore() int {
|
||||
return int(rp.SIO.CPUID.Get())
|
||||
|
||||
@@ -0,0 +1,53 @@
|
||||
//go:build rp2040
|
||||
// +build rp2040
|
||||
|
||||
package machine
|
||||
|
||||
/*
|
||||
// https://github.com/raspberrypi/pico-sdk
|
||||
// src/rp2_common/pico_bootrom/include/pico/bootrom.h
|
||||
|
||||
#define ROM_FUNC_POPCOUNT32 ROM_TABLE_CODE('P', '3')
|
||||
#define ROM_FUNC_REVERSE32 ROM_TABLE_CODE('R', '3')
|
||||
#define ROM_FUNC_CLZ32 ROM_TABLE_CODE('L', '3')
|
||||
#define ROM_FUNC_CTZ32 ROM_TABLE_CODE('T', '3')
|
||||
#define ROM_FUNC_MEMSET ROM_TABLE_CODE('M', 'S')
|
||||
#define ROM_FUNC_MEMSET4 ROM_TABLE_CODE('S', '4')
|
||||
#define ROM_FUNC_MEMCPY ROM_TABLE_CODE('M', 'C')
|
||||
#define ROM_FUNC_MEMCPY44 ROM_TABLE_CODE('C', '4')
|
||||
#define ROM_FUNC_RESET_USB_BOOT ROM_TABLE_CODE('U', 'B')
|
||||
#define ROM_FUNC_CONNECT_INTERNAL_FLASH ROM_TABLE_CODE('I', 'F')
|
||||
#define ROM_FUNC_FLASH_EXIT_XIP ROM_TABLE_CODE('E', 'X')
|
||||
#define ROM_FUNC_FLASH_RANGE_ERASE ROM_TABLE_CODE('R', 'E')
|
||||
#define ROM_FUNC_FLASH_RANGE_PROGRAM ROM_TABLE_CODE('R', 'P')
|
||||
#define ROM_FUNC_FLASH_FLUSH_CACHE ROM_TABLE_CODE('F', 'C')
|
||||
#define ROM_FUNC_FLASH_ENTER_CMD_XIP ROM_TABLE_CODE('C', 'X')
|
||||
|
||||
#define ROM_TABLE_CODE(c1, c2) ((c1) | ((c2) << 8))
|
||||
|
||||
typedef unsigned short uint16_t;
|
||||
typedef unsigned long uint32_t;
|
||||
typedef unsigned long uintptr_t;
|
||||
|
||||
typedef void *(*rom_table_lookup_fn)(uint16_t *table, uint32_t code);
|
||||
typedef void __attribute__((noreturn)) (*rom_reset_usb_boot_fn)(uint32_t, uint32_t);
|
||||
#define rom_hword_as_ptr(rom_address) (void *)(uintptr_t)(*(uint16_t *)(uintptr_t)(rom_address))
|
||||
|
||||
void *rom_func_lookup(uint32_t code) {
|
||||
rom_table_lookup_fn rom_table_lookup = (rom_table_lookup_fn) rom_hword_as_ptr(0x18);
|
||||
uint16_t *func_table = (uint16_t *) rom_hword_as_ptr(0x14);
|
||||
return rom_table_lookup(func_table, code);
|
||||
}
|
||||
|
||||
void reset_usb_boot(uint32_t usb_activity_gpio_pin_mask, uint32_t disable_interface_mask) {
|
||||
rom_reset_usb_boot_fn func = (rom_reset_usb_boot_fn) rom_func_lookup(ROM_FUNC_RESET_USB_BOOT);
|
||||
func(usb_activity_gpio_pin_mask, disable_interface_mask);
|
||||
}
|
||||
*/
|
||||
import "C"
|
||||
|
||||
// EnterBootloader should perform a system reset in preparation
|
||||
// to switch to the bootloader to flash new firmware.
|
||||
func EnterBootloader() {
|
||||
C.reset_usb_boot(0, 0)
|
||||
}
|
||||
@@ -181,6 +181,7 @@ func (p Pin) Configure(config PinConfig) {
|
||||
rp.SIO.GPIO_OE_SET.Set(mask)
|
||||
case PinInput:
|
||||
p.setFunc(fnSIO)
|
||||
p.pulloff()
|
||||
case PinInputPulldown:
|
||||
p.setFunc(fnSIO)
|
||||
p.pulldown()
|
||||
|
||||
@@ -0,0 +1,371 @@
|
||||
//go:build rp2040
|
||||
// +build rp2040
|
||||
|
||||
package machine
|
||||
|
||||
import (
|
||||
"device/rp"
|
||||
"machine/usb"
|
||||
"runtime/interrupt"
|
||||
"runtime/volatile"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
var (
|
||||
sendOnEP0DATADONE struct {
|
||||
offset int
|
||||
data []byte
|
||||
pid uint32
|
||||
}
|
||||
)
|
||||
|
||||
// Configure the USB peripheral. The config is here for compatibility with the UART interface.
|
||||
func (dev *USBDevice) Configure(config UARTConfig) {
|
||||
// Reset usb controller
|
||||
resetBlock(rp.RESETS_RESET_USBCTRL)
|
||||
unresetBlockWait(rp.RESETS_RESET_USBCTRL)
|
||||
|
||||
// Clear any previous state in dpram just in case
|
||||
usbDPSRAM.clear()
|
||||
|
||||
// Enable USB interrupt at processor
|
||||
rp.USBCTRL_REGS.INTE.Set(0)
|
||||
intr := interrupt.New(rp.IRQ_USBCTRL_IRQ, handleUSBIRQ)
|
||||
intr.SetPriority(0x00)
|
||||
intr.Enable()
|
||||
irqSet(rp.IRQ_USBCTRL_IRQ, true)
|
||||
|
||||
// Mux the controller to the onboard usb phy
|
||||
rp.USBCTRL_REGS.USB_MUXING.Set(rp.USBCTRL_REGS_USB_MUXING_TO_PHY | rp.USBCTRL_REGS_USB_MUXING_SOFTCON)
|
||||
|
||||
// Force VBUS detect so the device thinks it is plugged into a host
|
||||
rp.USBCTRL_REGS.USB_PWR.Set(rp.USBCTRL_REGS_USB_PWR_VBUS_DETECT | rp.USBCTRL_REGS_USB_PWR_VBUS_DETECT_OVERRIDE_EN)
|
||||
|
||||
// Enable the USB controller in device mode.
|
||||
rp.USBCTRL_REGS.MAIN_CTRL.Set(rp.USBCTRL_REGS_MAIN_CTRL_CONTROLLER_EN)
|
||||
|
||||
// Enable an interrupt per EP0 transaction
|
||||
rp.USBCTRL_REGS.SIE_CTRL.Set(rp.USBCTRL_REGS_SIE_CTRL_EP0_INT_1BUF)
|
||||
|
||||
// Enable interrupts for when a buffer is done, when the bus is reset,
|
||||
// and when a setup packet is received
|
||||
rp.USBCTRL_REGS.INTE.Set(rp.USBCTRL_REGS_INTE_BUFF_STATUS |
|
||||
rp.USBCTRL_REGS_INTE_BUS_RESET |
|
||||
rp.USBCTRL_REGS_INTE_SETUP_REQ)
|
||||
|
||||
// Present full speed device by enabling pull up on DP
|
||||
rp.USBCTRL_REGS.SIE_CTRL.SetBits(rp.USBCTRL_REGS_SIE_CTRL_PULLUP_EN)
|
||||
}
|
||||
|
||||
func handleUSBIRQ(intr interrupt.Interrupt) {
|
||||
status := rp.USBCTRL_REGS.INTS.Get()
|
||||
|
||||
// Setup packet received
|
||||
if (status & rp.USBCTRL_REGS_INTS_SETUP_REQ) > 0 {
|
||||
rp.USBCTRL_REGS.SIE_STATUS.Set(rp.USBCTRL_REGS_SIE_STATUS_SETUP_REC)
|
||||
setup := usb.NewSetup(usbDPSRAM.setupBytes())
|
||||
|
||||
ok := false
|
||||
if (setup.BmRequestType & usb.REQUEST_TYPE) == usb.REQUEST_STANDARD {
|
||||
// Standard Requests
|
||||
ok = handleStandardSetup(setup)
|
||||
} else {
|
||||
// Class Interface Requests
|
||||
if setup.WIndex < uint16(len(usbSetupHandler)) && usbSetupHandler[setup.WIndex] != nil {
|
||||
ok = usbSetupHandler[setup.WIndex](setup)
|
||||
}
|
||||
}
|
||||
|
||||
if !ok {
|
||||
// Stall endpoint?
|
||||
sendStallViaEPIn(0)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Buffer status, one or more buffers have completed
|
||||
if (status & rp.USBCTRL_REGS_INTS_BUFF_STATUS) > 0 {
|
||||
if sendOnEP0DATADONE.offset > 0 {
|
||||
ep := uint32(0)
|
||||
data := sendOnEP0DATADONE.data
|
||||
count := len(data) - sendOnEP0DATADONE.offset
|
||||
if ep == 0 && count > usb.EndpointPacketSize {
|
||||
count = usb.EndpointPacketSize
|
||||
}
|
||||
|
||||
sendViaEPIn(ep, data[sendOnEP0DATADONE.offset:], count)
|
||||
sendOnEP0DATADONE.offset += count
|
||||
if sendOnEP0DATADONE.offset == len(data) {
|
||||
sendOnEP0DATADONE.offset = 0
|
||||
}
|
||||
}
|
||||
|
||||
s2 := rp.USBCTRL_REGS.BUFF_STATUS.Get()
|
||||
|
||||
// OUT (PC -> rp2040)
|
||||
for i := 0; i < 16; i++ {
|
||||
if s2&(1<<(i*2+1)) > 0 {
|
||||
buf := handleEndpointRx(uint32(i))
|
||||
if usbRxHandler[i] != nil {
|
||||
usbRxHandler[i](buf)
|
||||
}
|
||||
handleEndpointRxComplete(uint32(i))
|
||||
}
|
||||
}
|
||||
|
||||
// IN (rp2040 -> PC)
|
||||
for i := 0; i < 16; i++ {
|
||||
if s2&(1<<(i*2)) > 0 {
|
||||
if usbTxHandler[i] != nil {
|
||||
usbTxHandler[i]()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
rp.USBCTRL_REGS.BUFF_STATUS.Set(0xFFFFFFFF)
|
||||
}
|
||||
|
||||
// Bus is reset
|
||||
if (status & rp.USBCTRL_REGS_INTS_BUS_RESET) > 0 {
|
||||
rp.USBCTRL_REGS.SIE_STATUS.Set(rp.USBCTRL_REGS_SIE_STATUS_BUS_RESET)
|
||||
rp.USBCTRL_REGS.ADDR_ENDP.Set(0)
|
||||
|
||||
initEndpoint(0, usb.ENDPOINT_TYPE_CONTROL)
|
||||
}
|
||||
}
|
||||
|
||||
func initEndpoint(ep, config uint32) {
|
||||
val := uint32(usbEpControlEnable) | uint32(usbEpControlInterruptPerBuff)
|
||||
offset := ep*2*USBBufferLen + 0x100
|
||||
val |= offset
|
||||
|
||||
switch config {
|
||||
case usb.ENDPOINT_TYPE_INTERRUPT | usb.EndpointIn:
|
||||
val |= usbEpControlEndpointTypeInterrupt
|
||||
usbDPSRAM.EPxControl[ep].In.Set(val)
|
||||
|
||||
case usb.ENDPOINT_TYPE_BULK | usb.EndpointOut:
|
||||
val |= usbEpControlEndpointTypeBulk
|
||||
usbDPSRAM.EPxControl[ep].Out.Set(val)
|
||||
usbDPSRAM.EPxBufferControl[ep].Out.Set(USBBufferLen & usbBuf0CtrlLenMask)
|
||||
usbDPSRAM.EPxBufferControl[ep].Out.SetBits(usbBuf0CtrlAvail)
|
||||
|
||||
case usb.ENDPOINT_TYPE_INTERRUPT | usb.EndpointOut:
|
||||
// TODO: not really anything, seems like...
|
||||
|
||||
case usb.ENDPOINT_TYPE_BULK | usb.EndpointIn:
|
||||
val |= usbEpControlEndpointTypeBulk
|
||||
usbDPSRAM.EPxControl[ep].In.Set(val)
|
||||
|
||||
case usb.ENDPOINT_TYPE_CONTROL:
|
||||
val |= usbEpControlEndpointTypeControl
|
||||
usbDPSRAM.EPxBufferControl[ep].Out.Set(usbBuf0CtrlData1Pid)
|
||||
usbDPSRAM.EPxBufferControl[ep].Out.SetBits(usbBuf0CtrlAvail)
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
func handleUSBSetAddress(setup usb.Setup) bool {
|
||||
sendUSBPacket(0, []byte{}, 0)
|
||||
|
||||
// last, set the device address to that requested by host
|
||||
// wait for transfer to complete
|
||||
timeout := 3000
|
||||
rp.USBCTRL_REGS.SIE_STATUS.Set(rp.USBCTRL_REGS_SIE_STATUS_ACK_REC)
|
||||
for (rp.USBCTRL_REGS.SIE_STATUS.Get() & rp.USBCTRL_REGS_SIE_STATUS_ACK_REC) == 0 {
|
||||
timeout--
|
||||
if timeout == 0 {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
rp.USBCTRL_REGS.ADDR_ENDP.Set(uint32(setup.WValueL) & rp.USBCTRL_REGS_ADDR_ENDP_ADDRESS_Msk)
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
// SendUSBInPacket sends a packet for USB (interrupt in / bulk in).
|
||||
func SendUSBInPacket(ep uint32, data []byte) bool {
|
||||
sendUSBPacket(ep, data, 0)
|
||||
return true
|
||||
}
|
||||
|
||||
//go:noinline
|
||||
func sendUSBPacket(ep uint32, data []byte, maxsize uint16) {
|
||||
count := len(data)
|
||||
if 0 < int(maxsize) && int(maxsize) < count {
|
||||
count = int(maxsize)
|
||||
}
|
||||
|
||||
if ep == 0 {
|
||||
if count > usb.EndpointPacketSize {
|
||||
count = usb.EndpointPacketSize
|
||||
|
||||
sendOnEP0DATADONE.offset = count
|
||||
sendOnEP0DATADONE.data = data
|
||||
} else {
|
||||
sendOnEP0DATADONE.offset = 0
|
||||
}
|
||||
epXdata0[ep] = true
|
||||
}
|
||||
|
||||
sendViaEPIn(ep, data, count)
|
||||
}
|
||||
|
||||
func ReceiveUSBControlPacket() ([cdcLineInfoSize]byte, error) {
|
||||
var b [cdcLineInfoSize]byte
|
||||
ep := 0
|
||||
|
||||
for !usbDPSRAM.EPxBufferControl[ep].Out.HasBits(usbBuf0CtrlFull) {
|
||||
// TODO: timeout
|
||||
}
|
||||
|
||||
ctrl := usbDPSRAM.EPxBufferControl[ep].Out.Get()
|
||||
usbDPSRAM.EPxBufferControl[ep].Out.Set(USBBufferLen & usbBuf0CtrlLenMask)
|
||||
sz := ctrl & usbBuf0CtrlLenMask
|
||||
|
||||
copy(b[:], usbDPSRAM.EPxBuffer[ep].Buffer0[:sz])
|
||||
|
||||
usbDPSRAM.EPxBufferControl[ep].Out.SetBits(usbBuf0CtrlData1Pid)
|
||||
usbDPSRAM.EPxBufferControl[ep].Out.SetBits(usbBuf0CtrlAvail)
|
||||
|
||||
return b, nil
|
||||
}
|
||||
|
||||
func handleEndpointRx(ep uint32) []byte {
|
||||
ctrl := usbDPSRAM.EPxBufferControl[ep].Out.Get()
|
||||
usbDPSRAM.EPxBufferControl[ep].Out.Set(USBBufferLen & usbBuf0CtrlLenMask)
|
||||
sz := ctrl & usbBuf0CtrlLenMask
|
||||
|
||||
return usbDPSRAM.EPxBuffer[ep].Buffer0[:sz]
|
||||
}
|
||||
|
||||
func handleEndpointRxComplete(ep uint32) {
|
||||
epXdata0[ep] = !epXdata0[ep]
|
||||
if epXdata0[ep] || ep == 0 {
|
||||
usbDPSRAM.EPxBufferControl[ep].Out.SetBits(usbBuf0CtrlData1Pid)
|
||||
}
|
||||
|
||||
usbDPSRAM.EPxBufferControl[ep].Out.SetBits(usbBuf0CtrlAvail)
|
||||
}
|
||||
|
||||
func SendZlp() {
|
||||
sendUSBPacket(0, []byte{}, 0)
|
||||
}
|
||||
|
||||
func sendViaEPIn(ep uint32, data []byte, count int) {
|
||||
// Prepare buffer control register value
|
||||
val := uint32(count) | usbBuf0CtrlAvail
|
||||
|
||||
// DATA0 or DATA1
|
||||
epXdata0[ep&0x7F] = !epXdata0[ep&0x7F]
|
||||
if !epXdata0[ep&0x7F] {
|
||||
val |= usbBuf0CtrlData1Pid
|
||||
}
|
||||
|
||||
// Mark as full
|
||||
val |= usbBuf0CtrlFull
|
||||
|
||||
copy(usbDPSRAM.EPxBuffer[ep&0x7F].Buffer0[:], data[:count])
|
||||
usbDPSRAM.EPxBufferControl[ep&0x7F].In.Set(val)
|
||||
}
|
||||
|
||||
func sendStallViaEPIn(ep uint32) {
|
||||
// Prepare buffer control register value
|
||||
if ep == 0 {
|
||||
rp.USBCTRL_REGS.EP_STALL_ARM.Set(rp.USBCTRL_REGS_EP_STALL_ARM_EP0_IN)
|
||||
}
|
||||
val := uint32(usbBuf0CtrlFull)
|
||||
usbDPSRAM.EPxBufferControl[ep&0x7F].In.Set(val)
|
||||
val |= uint32(usbBuf0CtrlStall)
|
||||
usbDPSRAM.EPxBufferControl[ep&0x7F].In.Set(val)
|
||||
}
|
||||
|
||||
type USBDPSRAM struct {
|
||||
// Note that EPxControl[0] is not EP0Control but 8-byte setup data.
|
||||
EPxControl [16]USBEndpointControlRegister
|
||||
|
||||
EPxBufferControl [16]USBBufferControlRegister
|
||||
|
||||
EPxBuffer [16]USBBuffer
|
||||
}
|
||||
|
||||
type USBEndpointControlRegister struct {
|
||||
In volatile.Register32
|
||||
Out volatile.Register32
|
||||
}
|
||||
type USBBufferControlRegister struct {
|
||||
In volatile.Register32
|
||||
Out volatile.Register32
|
||||
}
|
||||
|
||||
type USBBuffer struct {
|
||||
Buffer0 [USBBufferLen]byte
|
||||
Buffer1 [USBBufferLen]byte
|
||||
}
|
||||
|
||||
var (
|
||||
usbDPSRAM = (*USBDPSRAM)(unsafe.Pointer(uintptr(0x50100000)))
|
||||
epXdata0 [16]bool
|
||||
)
|
||||
|
||||
func (d *USBDPSRAM) setupBytes() []byte {
|
||||
var buf [8]byte
|
||||
|
||||
buf[0] = byte(d.EPxControl[usb.CONTROL_ENDPOINT].In.Get())
|
||||
buf[1] = byte(d.EPxControl[usb.CONTROL_ENDPOINT].In.Get() >> 8)
|
||||
buf[2] = byte(d.EPxControl[usb.CONTROL_ENDPOINT].In.Get() >> 16)
|
||||
buf[3] = byte(d.EPxControl[usb.CONTROL_ENDPOINT].In.Get() >> 24)
|
||||
buf[4] = byte(d.EPxControl[usb.CONTROL_ENDPOINT].Out.Get())
|
||||
buf[5] = byte(d.EPxControl[usb.CONTROL_ENDPOINT].Out.Get() >> 8)
|
||||
buf[6] = byte(d.EPxControl[usb.CONTROL_ENDPOINT].Out.Get() >> 16)
|
||||
buf[7] = byte(d.EPxControl[usb.CONTROL_ENDPOINT].Out.Get() >> 24)
|
||||
|
||||
return buf[:]
|
||||
}
|
||||
|
||||
func (d *USBDPSRAM) clear() {
|
||||
for i := 0; i < len(d.EPxControl); i++ {
|
||||
d.EPxControl[i].In.Set(0)
|
||||
d.EPxControl[i].Out.Set(0)
|
||||
d.EPxBufferControl[i].In.Set(0)
|
||||
d.EPxBufferControl[i].Out.Set(0)
|
||||
}
|
||||
}
|
||||
|
||||
const (
|
||||
// DPRAM : Endpoint control register
|
||||
usbEpControlEnable = 0x80000000
|
||||
usbEpControlDoubleBuffered = 0x40000000
|
||||
usbEpControlInterruptPerBuff = 0x20000000
|
||||
usbEpControlInterruptPerDoubleBuff = 0x10000000
|
||||
usbEpControlEndpointType = 0x0c000000
|
||||
usbEpControlInterruptOnStall = 0x00020000
|
||||
usbEpControlInterruptOnNak = 0x00010000
|
||||
usbEpControlBufferAddress = 0x0000ffff
|
||||
|
||||
usbEpControlEndpointTypeControl = 0x00000000
|
||||
usbEpControlEndpointTypeISO = 0x04000000
|
||||
usbEpControlEndpointTypeBulk = 0x08000000
|
||||
usbEpControlEndpointTypeInterrupt = 0x0c000000
|
||||
|
||||
// Endpoint buffer control bits
|
||||
usbBuf1CtrlFull = 0x80000000
|
||||
usbBuf1CtrlLast = 0x40000000
|
||||
usbBuf1CtrlData0Pid = 0x20000000
|
||||
usbBuf1CtrlData1Pid = 0x00000000
|
||||
usbBuf1CtrlSel = 0x10000000
|
||||
usbBuf1CtrlStall = 0x08000000
|
||||
usbBuf1CtrlAvail = 0x04000000
|
||||
usbBuf1CtrlLenMask = 0x03FF0000
|
||||
usbBuf0CtrlFull = 0x00008000
|
||||
usbBuf0CtrlLast = 0x00004000
|
||||
usbBuf0CtrlData0Pid = 0x00000000
|
||||
usbBuf0CtrlData1Pid = 0x00002000
|
||||
usbBuf0CtrlSel = 0x00001000
|
||||
usbBuf0CtrlStall = 0x00000800
|
||||
usbBuf0CtrlAvail = 0x00000400
|
||||
usbBuf0CtrlLenMask = 0x000003FF
|
||||
|
||||
USBBufferLen = 64
|
||||
)
|
||||
@@ -5,3 +5,7 @@ package machine
|
||||
|
||||
// Serial is a null device: writes to it are ignored.
|
||||
var Serial = NullSerial{}
|
||||
|
||||
func InitSerial() {
|
||||
Serial.Configure(UARTConfig{})
|
||||
}
|
||||
|
||||
@@ -5,3 +5,7 @@ package machine
|
||||
|
||||
// Serial is implemented via the default (usually the first) UART on the chip.
|
||||
var Serial = DefaultUART
|
||||
|
||||
func InitSerial() {
|
||||
Serial.Configure(UARTConfig{})
|
||||
}
|
||||
|
||||
@@ -4,4 +4,8 @@
|
||||
package machine
|
||||
|
||||
// Serial is implemented via USB (USB-CDC).
|
||||
var Serial = USB
|
||||
var Serial Serialer
|
||||
|
||||
func InitSerial() {
|
||||
Serial = USBCDC
|
||||
}
|
||||
|
||||
+180
-266
@@ -1,32 +1,36 @@
|
||||
//go:build sam || nrf52840
|
||||
// +build sam nrf52840
|
||||
//go:build sam || nrf52840 || rp2040
|
||||
// +build sam nrf52840 rp2040
|
||||
|
||||
package machine
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"runtime/volatile"
|
||||
"machine/usb"
|
||||
)
|
||||
|
||||
var usbDescriptor = descriptorCDC
|
||||
type USBDevice struct {
|
||||
initcomplete bool
|
||||
}
|
||||
|
||||
var (
|
||||
errUSBCDCBufferEmpty = errors.New("USB-CDC buffer empty")
|
||||
errUSBCDCWriteByteTimeout = errors.New("USB-CDC write byte timeout")
|
||||
errUSBCDCReadTimeout = errors.New("USB-CDC read timeout")
|
||||
errUSBCDCBytesRead = errors.New("USB-CDC invalid number of bytes read")
|
||||
USBDev = &USBDevice{}
|
||||
USBCDC Serialer
|
||||
)
|
||||
|
||||
const cdcLineInfoSize = 7
|
||||
|
||||
type cdcLineInfo struct {
|
||||
dwDTERate uint32
|
||||
bCharFormat uint8
|
||||
bParityType uint8
|
||||
bDataBits uint8
|
||||
lineState uint8
|
||||
type Serialer interface {
|
||||
WriteByte(c byte) error
|
||||
Write(data []byte) (n int, err error)
|
||||
Configure(config UARTConfig) error
|
||||
Buffered() int
|
||||
ReadByte() (byte, error)
|
||||
DTR() bool
|
||||
RTS() bool
|
||||
}
|
||||
|
||||
var usbDescriptor = usb.DescriptorCDC
|
||||
|
||||
var usbDescriptorConfig uint8 = usb.DescriptorConfigCDC
|
||||
|
||||
// strToUTF16LEDescriptor converts a utf8 string into a string descriptor
|
||||
// note: the following code only converts ascii characters to UTF16LE. In order
|
||||
// to do a "proper" conversion, we would need to pull in the 'unicode/utf16'
|
||||
@@ -34,7 +38,7 @@ type cdcLineInfo struct {
|
||||
// binary.
|
||||
func strToUTF16LEDescriptor(in string, out []byte) {
|
||||
out[0] = byte(len(out))
|
||||
out[1] = usb_STRING_DESCRIPTOR_TYPE
|
||||
out[1] = usb.STRING_DESCRIPTOR_TYPE
|
||||
for i, rune := range in {
|
||||
out[(i<<1)+2] = byte(rune)
|
||||
out[(i<<1)+3] = 0
|
||||
@@ -42,297 +46,207 @@ func strToUTF16LEDescriptor(in string, out []byte) {
|
||||
return
|
||||
}
|
||||
|
||||
const cdcLineInfoSize = 7
|
||||
|
||||
var (
|
||||
// TODO: allow setting these
|
||||
usb_STRING_LANGUAGE = [2]uint16{(3 << 8) | (2 + 2), 0x0409} // English
|
||||
ErrUSBReadTimeout = errors.New("USB read timeout")
|
||||
ErrUSBBytesRead = errors.New("USB invalid number of bytes read")
|
||||
)
|
||||
|
||||
const (
|
||||
usb_IMANUFACTURER = 1
|
||||
usb_IPRODUCT = 2
|
||||
usb_ISERIAL = 3
|
||||
var (
|
||||
usbEndpointDescriptors [usb.NumberOfEndpoints]usb.DeviceDescriptor
|
||||
|
||||
usb_ENDPOINT_TYPE_CONTROL = 0x00
|
||||
usb_ENDPOINT_TYPE_ISOCHRONOUS = 0x01
|
||||
usb_ENDPOINT_TYPE_BULK = 0x02
|
||||
usb_ENDPOINT_TYPE_INTERRUPT = 0x03
|
||||
isEndpointHalt = false
|
||||
isRemoteWakeUpEnabled = false
|
||||
|
||||
usb_DEVICE_DESCRIPTOR_TYPE = 1
|
||||
usb_CONFIGURATION_DESCRIPTOR_TYPE = 2
|
||||
usb_STRING_DESCRIPTOR_TYPE = 3
|
||||
usb_INTERFACE_DESCRIPTOR_TYPE = 4
|
||||
usb_ENDPOINT_DESCRIPTOR_TYPE = 5
|
||||
usb_DEVICE_QUALIFIER = 6
|
||||
usb_OTHER_SPEED_CONFIGURATION = 7
|
||||
usb_SET_REPORT_TYPE = 33
|
||||
usb_HID_REPORT_TYPE = 34
|
||||
|
||||
usbEndpointOut = 0x00
|
||||
usbEndpointIn = 0x80
|
||||
|
||||
usbEndpointPacketSize = 64 // 64 for Full Speed, EPT size max is 1024
|
||||
usb_EPT_NUM = 7
|
||||
|
||||
// standard requests
|
||||
usb_GET_STATUS = 0
|
||||
usb_CLEAR_FEATURE = 1
|
||||
usb_SET_FEATURE = 3
|
||||
usb_SET_ADDRESS = 5
|
||||
usb_GET_DESCRIPTOR = 6
|
||||
usb_SET_DESCRIPTOR = 7
|
||||
usb_GET_CONFIGURATION = 8
|
||||
usb_SET_CONFIGURATION = 9
|
||||
usb_GET_INTERFACE = 10
|
||||
usb_SET_INTERFACE = 11
|
||||
|
||||
// non standard requests
|
||||
usb_SET_IDLE = 10
|
||||
|
||||
usb_DEVICE_CLASS_COMMUNICATIONS = 0x02
|
||||
usb_DEVICE_CLASS_HUMAN_INTERFACE = 0x03
|
||||
usb_DEVICE_CLASS_STORAGE = 0x08
|
||||
usb_DEVICE_CLASS_VENDOR_SPECIFIC = 0xFF
|
||||
|
||||
usb_CONFIG_POWERED_MASK = 0x40
|
||||
usb_CONFIG_BUS_POWERED = 0x80
|
||||
usb_CONFIG_SELF_POWERED = 0xC0
|
||||
usb_CONFIG_REMOTE_WAKEUP = 0x20
|
||||
|
||||
// CDC
|
||||
usb_CDC_ACM_INTERFACE = 0 // CDC ACM
|
||||
usb_CDC_DATA_INTERFACE = 1 // CDC Data
|
||||
usb_CDC_FIRST_ENDPOINT = 1
|
||||
|
||||
// Endpoint
|
||||
usb_CDC_ENDPOINT_ACM = 1
|
||||
usb_CDC_ENDPOINT_OUT = 2
|
||||
usb_CDC_ENDPOINT_IN = 3
|
||||
usb_HID_ENDPOINT_IN = 4
|
||||
|
||||
// bmRequestType
|
||||
usb_REQUEST_HOSTTODEVICE = 0x00
|
||||
usb_REQUEST_DEVICETOHOST = 0x80
|
||||
usb_REQUEST_DIRECTION = 0x80
|
||||
|
||||
usb_REQUEST_STANDARD = 0x00
|
||||
usb_REQUEST_CLASS = 0x20
|
||||
usb_REQUEST_VENDOR = 0x40
|
||||
usb_REQUEST_TYPE = 0x60
|
||||
|
||||
usb_REQUEST_DEVICE = 0x00
|
||||
usb_REQUEST_INTERFACE = 0x01
|
||||
usb_REQUEST_ENDPOINT = 0x02
|
||||
usb_REQUEST_OTHER = 0x03
|
||||
usb_REQUEST_RECIPIENT = 0x1F
|
||||
|
||||
usb_REQUEST_DEVICETOHOST_CLASS_INTERFACE = (usb_REQUEST_DEVICETOHOST | usb_REQUEST_CLASS | usb_REQUEST_INTERFACE)
|
||||
usb_REQUEST_HOSTTODEVICE_CLASS_INTERFACE = (usb_REQUEST_HOSTTODEVICE | usb_REQUEST_CLASS | usb_REQUEST_INTERFACE)
|
||||
usb_REQUEST_DEVICETOHOST_STANDARD_INTERFACE = (usb_REQUEST_DEVICETOHOST | usb_REQUEST_STANDARD | usb_REQUEST_INTERFACE)
|
||||
|
||||
// CDC Class requests
|
||||
usb_CDC_SET_LINE_CODING = 0x20
|
||||
usb_CDC_GET_LINE_CODING = 0x21
|
||||
usb_CDC_SET_CONTROL_LINE_STATE = 0x22
|
||||
usb_CDC_SEND_BREAK = 0x23
|
||||
|
||||
usb_CDC_V1_10 = 0x0110
|
||||
usb_CDC_COMMUNICATION_INTERFACE_CLASS = 0x02
|
||||
|
||||
usb_CDC_CALL_MANAGEMENT = 0x01
|
||||
usb_CDC_ABSTRACT_CONTROL_MODEL = 0x02
|
||||
usb_CDC_HEADER = 0x00
|
||||
usb_CDC_ABSTRACT_CONTROL_MANAGEMENT = 0x02
|
||||
usb_CDC_UNION = 0x06
|
||||
usb_CDC_CS_INTERFACE = 0x24
|
||||
usb_CDC_CS_ENDPOINT = 0x25
|
||||
usb_CDC_DATA_INTERFACE_CLASS = 0x0A
|
||||
|
||||
usb_CDC_LINESTATE_DTR = 0x01
|
||||
usb_CDC_LINESTATE_RTS = 0x02
|
||||
usbConfiguration uint8
|
||||
usbSetInterface uint8
|
||||
)
|
||||
|
||||
// usbDeviceDescBank is the USB device endpoint descriptor.
|
||||
// typedef struct {
|
||||
// __IO USB_DEVICE_ADDR_Type ADDR; /**< \brief Offset: 0x000 (R/W 32) DEVICE_DESC_BANK Endpoint Bank, Adress of Data Buffer */
|
||||
// __IO USB_DEVICE_PCKSIZE_Type PCKSIZE; /**< \brief Offset: 0x004 (R/W 32) DEVICE_DESC_BANK Endpoint Bank, Packet Size */
|
||||
// __IO USB_DEVICE_EXTREG_Type EXTREG; /**< \brief Offset: 0x008 (R/W 16) DEVICE_DESC_BANK Endpoint Bank, Extended */
|
||||
// __IO USB_DEVICE_STATUS_BK_Type STATUS_BK; /**< \brief Offset: 0x00A (R/W 8) DEVICE_DESC_BANK Enpoint Bank, Status of Bank */
|
||||
// RoReg8 Reserved1[0x5];
|
||||
// } UsbDeviceDescBank;
|
||||
type usbDeviceDescBank struct {
|
||||
ADDR volatile.Register32
|
||||
PCKSIZE volatile.Register32
|
||||
EXTREG volatile.Register16
|
||||
STATUS_BK volatile.Register8
|
||||
_reserved [5]volatile.Register8
|
||||
}
|
||||
//go:align 4
|
||||
var udd_ep_control_cache_buffer [256]uint8
|
||||
|
||||
type usbDeviceDescriptor struct {
|
||||
DeviceDescBank [2]usbDeviceDescBank
|
||||
}
|
||||
//go:align 4
|
||||
var udd_ep_in_cache_buffer [7][64]uint8
|
||||
|
||||
// typedef struct {
|
||||
// union {
|
||||
// uint8_t bmRequestType;
|
||||
// struct {
|
||||
// uint8_t direction : 5;
|
||||
// uint8_t type : 2;
|
||||
// uint8_t transferDirection : 1;
|
||||
// };
|
||||
// };
|
||||
// uint8_t bRequest;
|
||||
// uint8_t wValueL;
|
||||
// uint8_t wValueH;
|
||||
// uint16_t wIndex;
|
||||
// uint16_t wLength;
|
||||
// } USBSetup;
|
||||
type usbSetup struct {
|
||||
bmRequestType uint8
|
||||
bRequest uint8
|
||||
wValueL uint8
|
||||
wValueH uint8
|
||||
wIndex uint16
|
||||
wLength uint16
|
||||
}
|
||||
//go:align 4
|
||||
var udd_ep_out_cache_buffer [7][64]uint8
|
||||
|
||||
func newUSBSetup(data []byte) usbSetup {
|
||||
u := usbSetup{}
|
||||
u.bmRequestType = uint8(data[0])
|
||||
u.bRequest = uint8(data[1])
|
||||
u.wValueL = uint8(data[2])
|
||||
u.wValueH = uint8(data[3])
|
||||
u.wIndex = uint16(data[4]) | (uint16(data[5]) << 8)
|
||||
u.wLength = uint16(data[6]) | (uint16(data[7]) << 8)
|
||||
return u
|
||||
}
|
||||
var (
|
||||
usbTxHandler [usb.NumberOfEndpoints]func()
|
||||
usbRxHandler [usb.NumberOfEndpoints]func([]byte)
|
||||
usbSetupHandler [usb.NumberOfInterfaces]func(usb.Setup) bool
|
||||
|
||||
// USBCDC is the serial interface that works over the USB port.
|
||||
// To implement the USBCDC interface for a board, you must declare a concrete type as follows:
|
||||
//
|
||||
// type USBCDC struct {
|
||||
// Buffer *RingBuffer
|
||||
// }
|
||||
//
|
||||
// You can also add additional members to this struct depending on your implementation,
|
||||
// but the *RingBuffer is required.
|
||||
// When you are declaring the USBCDC for your board, make sure that you also declare the
|
||||
// RingBuffer using the NewRingBuffer() function:
|
||||
//
|
||||
// USBCDC{Buffer: NewRingBuffer()}
|
||||
//
|
||||
|
||||
// Read from the RX buffer.
|
||||
func (usbcdc *USBCDC) Read(data []byte) (n int, err error) {
|
||||
// check if RX buffer is empty
|
||||
size := usbcdc.Buffered()
|
||||
if size == 0 {
|
||||
return 0, nil
|
||||
endPoints = []uint32{
|
||||
usb.CONTROL_ENDPOINT: usb.ENDPOINT_TYPE_CONTROL,
|
||||
usb.CDC_ENDPOINT_ACM: (usb.ENDPOINT_TYPE_INTERRUPT | usb.EndpointIn),
|
||||
usb.CDC_ENDPOINT_OUT: (usb.ENDPOINT_TYPE_BULK | usb.EndpointOut),
|
||||
usb.CDC_ENDPOINT_IN: (usb.ENDPOINT_TYPE_BULK | usb.EndpointIn),
|
||||
usb.HID_ENDPOINT_IN: (usb.ENDPOINT_TYPE_DISABLE), // Interrupt In
|
||||
usb.MIDI_ENDPOINT_OUT: (usb.ENDPOINT_TYPE_DISABLE), // Bulk Out
|
||||
usb.MIDI_ENDPOINT_IN: (usb.ENDPOINT_TYPE_DISABLE), // Bulk In
|
||||
}
|
||||
|
||||
// Make sure we do not read more from buffer than the data slice can hold.
|
||||
if len(data) < size {
|
||||
size = len(data)
|
||||
}
|
||||
|
||||
// only read number of bytes used from buffer
|
||||
for i := 0; i < size; i++ {
|
||||
v, _ := usbcdc.ReadByte()
|
||||
data[i] = v
|
||||
}
|
||||
|
||||
return size, nil
|
||||
}
|
||||
|
||||
// Write data to the USBCDC.
|
||||
func (usbcdc *USBCDC) Write(data []byte) (n int, err error) {
|
||||
for _, v := range data {
|
||||
usbcdc.WriteByte(v)
|
||||
}
|
||||
return len(data), nil
|
||||
}
|
||||
|
||||
// ReadByte reads a single byte from the RX buffer.
|
||||
// If there is no data in the buffer, returns an error.
|
||||
func (usbcdc *USBCDC) ReadByte() (byte, error) {
|
||||
// check if RX buffer is empty
|
||||
buf, ok := usbcdc.Buffer.Get()
|
||||
if !ok {
|
||||
return 0, errUSBCDCBufferEmpty
|
||||
}
|
||||
return buf, nil
|
||||
}
|
||||
|
||||
// Buffered returns the number of bytes currently stored in the RX buffer.
|
||||
func (usbcdc *USBCDC) Buffered() int {
|
||||
return int(usbcdc.Buffer.Used())
|
||||
}
|
||||
|
||||
// Receive handles adding data to the UART's data buffer.
|
||||
// Usually called by the IRQ handler for a machine.
|
||||
func (usbcdc *USBCDC) Receive(data byte) {
|
||||
usbcdc.Buffer.Put(data)
|
||||
}
|
||||
)
|
||||
|
||||
// sendDescriptor creates and sends the various USB descriptor types that
|
||||
// can be requested by the host.
|
||||
func sendDescriptor(setup usbSetup) {
|
||||
switch setup.wValueH {
|
||||
case usb_CONFIGURATION_DESCRIPTOR_TYPE:
|
||||
sendUSBPacket(0, usbDescriptor.Configuration, setup.wLength)
|
||||
func sendDescriptor(setup usb.Setup) {
|
||||
switch setup.WValueH {
|
||||
case usb.CONFIGURATION_DESCRIPTOR_TYPE:
|
||||
sendUSBPacket(0, usbDescriptor.Configuration, setup.WLength)
|
||||
return
|
||||
case usb_DEVICE_DESCRIPTOR_TYPE:
|
||||
case usb.DEVICE_DESCRIPTOR_TYPE:
|
||||
// composite descriptor
|
||||
switch {
|
||||
case (usbDescriptorConfig & usb.DescriptorConfigHID) > 0:
|
||||
usbDescriptor = usb.DescriptorCDCHID
|
||||
case (usbDescriptorConfig & usb.DescriptorConfigMIDI) > 0:
|
||||
usbDescriptor = usb.DescriptorCDCMIDI
|
||||
default:
|
||||
usbDescriptor = usb.DescriptorCDC
|
||||
}
|
||||
|
||||
usbDescriptor.Configure(usb_VID, usb_PID)
|
||||
sendUSBPacket(0, usbDescriptor.Device, setup.wLength)
|
||||
sendUSBPacket(0, usbDescriptor.Device, setup.WLength)
|
||||
return
|
||||
|
||||
case usb_STRING_DESCRIPTOR_TYPE:
|
||||
switch setup.wValueL {
|
||||
case usb.STRING_DESCRIPTOR_TYPE:
|
||||
switch setup.WValueL {
|
||||
case 0:
|
||||
b := []byte{0x04, 0x03, 0x09, 0x04}
|
||||
sendUSBPacket(0, b, setup.wLength)
|
||||
sendUSBPacket(0, b, setup.WLength)
|
||||
|
||||
case usb_IPRODUCT:
|
||||
case usb.IPRODUCT:
|
||||
b := make([]byte, (len(usb_STRING_PRODUCT)<<1)+2)
|
||||
strToUTF16LEDescriptor(usb_STRING_PRODUCT, b)
|
||||
sendUSBPacket(0, b, setup.wLength)
|
||||
sendUSBPacket(0, b, setup.WLength)
|
||||
|
||||
case usb_IMANUFACTURER:
|
||||
case usb.IMANUFACTURER:
|
||||
b := make([]byte, (len(usb_STRING_MANUFACTURER)<<1)+2)
|
||||
strToUTF16LEDescriptor(usb_STRING_MANUFACTURER, b)
|
||||
sendUSBPacket(0, b, setup.wLength)
|
||||
sendUSBPacket(0, b, setup.WLength)
|
||||
|
||||
case usb_ISERIAL:
|
||||
case usb.ISERIAL:
|
||||
// TODO: allow returning a product serial number
|
||||
sendZlp()
|
||||
SendZlp()
|
||||
}
|
||||
return
|
||||
case usb_HID_REPORT_TYPE:
|
||||
if h, ok := usbDescriptor.HID[setup.wIndex]; ok {
|
||||
sendUSBPacket(0, h, setup.wLength)
|
||||
case usb.HID_REPORT_TYPE:
|
||||
if h, ok := usbDescriptor.HID[setup.WIndex]; ok {
|
||||
sendUSBPacket(0, h, setup.WLength)
|
||||
return
|
||||
}
|
||||
case usb_DEVICE_QUALIFIER:
|
||||
case usb.DEVICE_QUALIFIER:
|
||||
// skip
|
||||
default:
|
||||
}
|
||||
|
||||
// do not know how to handle this message, so return zero
|
||||
sendZlp()
|
||||
SendZlp()
|
||||
return
|
||||
}
|
||||
|
||||
// EnableHID enables HID. This function must be executed from the init().
|
||||
func EnableHID(callback func()) {
|
||||
usbDescriptor = descriptorCDCHID
|
||||
endPoints = []uint32{usb_ENDPOINT_TYPE_CONTROL,
|
||||
(usb_ENDPOINT_TYPE_INTERRUPT | usbEndpointIn),
|
||||
(usb_ENDPOINT_TYPE_BULK | usbEndpointOut),
|
||||
(usb_ENDPOINT_TYPE_BULK | usbEndpointIn),
|
||||
(usb_ENDPOINT_TYPE_INTERRUPT | usbEndpointIn)}
|
||||
func handleStandardSetup(setup usb.Setup) bool {
|
||||
switch setup.BRequest {
|
||||
case usb.GET_STATUS:
|
||||
buf := []byte{0, 0}
|
||||
|
||||
hidCallback = callback
|
||||
if setup.BmRequestType != 0 { // endpoint
|
||||
if isEndpointHalt {
|
||||
buf[0] = 1
|
||||
}
|
||||
}
|
||||
|
||||
sendUSBPacket(0, buf, setup.WLength)
|
||||
return true
|
||||
|
||||
case usb.CLEAR_FEATURE:
|
||||
if setup.WValueL == 1 { // DEVICEREMOTEWAKEUP
|
||||
isRemoteWakeUpEnabled = false
|
||||
} else if setup.WValueL == 0 { // ENDPOINTHALT
|
||||
isEndpointHalt = false
|
||||
}
|
||||
SendZlp()
|
||||
return true
|
||||
|
||||
case usb.SET_FEATURE:
|
||||
if setup.WValueL == 1 { // DEVICEREMOTEWAKEUP
|
||||
isRemoteWakeUpEnabled = true
|
||||
} else if setup.WValueL == 0 { // ENDPOINTHALT
|
||||
isEndpointHalt = true
|
||||
}
|
||||
SendZlp()
|
||||
return true
|
||||
|
||||
case usb.SET_ADDRESS:
|
||||
return handleUSBSetAddress(setup)
|
||||
|
||||
case usb.GET_DESCRIPTOR:
|
||||
sendDescriptor(setup)
|
||||
return true
|
||||
|
||||
case usb.SET_DESCRIPTOR:
|
||||
return false
|
||||
|
||||
case usb.GET_CONFIGURATION:
|
||||
buff := []byte{usbConfiguration}
|
||||
sendUSBPacket(0, buff, setup.WLength)
|
||||
return true
|
||||
|
||||
case usb.SET_CONFIGURATION:
|
||||
if setup.BmRequestType&usb.REQUEST_RECIPIENT == usb.REQUEST_DEVICE {
|
||||
for i := 1; i < len(endPoints); i++ {
|
||||
initEndpoint(uint32(i), endPoints[i])
|
||||
}
|
||||
|
||||
usbConfiguration = setup.WValueL
|
||||
|
||||
SendZlp()
|
||||
return true
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
|
||||
case usb.GET_INTERFACE:
|
||||
buff := []byte{usbSetInterface}
|
||||
sendUSBPacket(0, buff, setup.WLength)
|
||||
return true
|
||||
|
||||
case usb.SET_INTERFACE:
|
||||
usbSetInterface = setup.WValueL
|
||||
|
||||
SendZlp()
|
||||
return true
|
||||
|
||||
default:
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
// hidCallback is a variable that holds the callback when using HID.
|
||||
var hidCallback func()
|
||||
func EnableCDC(txHandler func(), rxHandler func([]byte), setupHandler func(usb.Setup) bool) {
|
||||
usbDescriptorConfig |= usb.DescriptorConfigCDC
|
||||
endPoints[usb.CDC_ENDPOINT_ACM] = (usb.ENDPOINT_TYPE_INTERRUPT | usb.EndpointIn)
|
||||
endPoints[usb.CDC_ENDPOINT_OUT] = (usb.ENDPOINT_TYPE_BULK | usb.EndpointOut)
|
||||
endPoints[usb.CDC_ENDPOINT_IN] = (usb.ENDPOINT_TYPE_BULK | usb.EndpointIn)
|
||||
usbRxHandler[usb.CDC_ENDPOINT_OUT] = rxHandler
|
||||
usbTxHandler[usb.CDC_ENDPOINT_IN] = txHandler
|
||||
usbSetupHandler[usb.CDC_ACM_INTERFACE] = setupHandler // 0x02 (Communications and CDC Control)
|
||||
usbSetupHandler[usb.CDC_DATA_INTERFACE] = nil // 0x0A (CDC-Data)
|
||||
}
|
||||
|
||||
// EnableHID enables HID. This function must be executed from the init().
|
||||
func EnableHID(txHandler func(), rxHandler func([]byte), setupHandler func(usb.Setup) bool) {
|
||||
usbDescriptorConfig |= usb.DescriptorConfigHID
|
||||
endPoints[usb.HID_ENDPOINT_IN] = (usb.ENDPOINT_TYPE_INTERRUPT | usb.EndpointIn)
|
||||
usbTxHandler[usb.HID_ENDPOINT_IN] = txHandler
|
||||
usbSetupHandler[usb.HID_INTERFACE] = setupHandler // 0x03 (HID - Human Interface Device)
|
||||
}
|
||||
|
||||
// EnableMIDI enables MIDI. This function must be executed from the init().
|
||||
func EnableMIDI(txHandler func(), rxHandler func([]byte), setupHandler func(usb.Setup) bool) {
|
||||
usbDescriptorConfig |= usb.DescriptorConfigMIDI
|
||||
endPoints[usb.MIDI_ENDPOINT_OUT] = (usb.ENDPOINT_TYPE_BULK | usb.EndpointOut)
|
||||
endPoints[usb.MIDI_ENDPOINT_IN] = (usb.ENDPOINT_TYPE_BULK | usb.EndpointIn)
|
||||
usbRxHandler[usb.MIDI_ENDPOINT_OUT] = rxHandler
|
||||
usbTxHandler[usb.MIDI_ENDPOINT_IN] = txHandler
|
||||
}
|
||||
|
||||
@@ -0,0 +1,119 @@
|
||||
package cdc
|
||||
|
||||
import (
|
||||
"runtime/volatile"
|
||||
)
|
||||
|
||||
const rxRingBufferSize = 128
|
||||
|
||||
// rxRingBuffer is ring buffer implementation inspired by post at
|
||||
// https://www.embeddedrelated.com/showthread/comp.arch.embedded/77084-1.php
|
||||
type rxRingBuffer struct {
|
||||
buffer [rxRingBufferSize]volatile.Register8
|
||||
head volatile.Register8
|
||||
tail volatile.Register8
|
||||
}
|
||||
|
||||
// NewRxRingBuffer returns a new ring buffer.
|
||||
func NewRxRingBuffer() *rxRingBuffer {
|
||||
return &rxRingBuffer{}
|
||||
}
|
||||
|
||||
// Used returns how many bytes in buffer have been used.
|
||||
func (rb *rxRingBuffer) Used() uint8 {
|
||||
return uint8(rb.head.Get() - rb.tail.Get())
|
||||
}
|
||||
|
||||
// Put stores a byte in the buffer. If the buffer is already
|
||||
// full, the method will return false.
|
||||
func (rb *rxRingBuffer) Put(val byte) bool {
|
||||
if rb.Used() != rxRingBufferSize {
|
||||
rb.head.Set(rb.head.Get() + 1)
|
||||
rb.buffer[rb.head.Get()%rxRingBufferSize].Set(val)
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// Get returns a byte from the buffer. If the buffer is empty,
|
||||
// the method will return a false as the second value.
|
||||
func (rb *rxRingBuffer) Get() (byte, bool) {
|
||||
if rb.Used() != 0 {
|
||||
rb.tail.Set(rb.tail.Get() + 1)
|
||||
return rb.buffer[rb.tail.Get()%rxRingBufferSize].Get(), true
|
||||
}
|
||||
return 0, false
|
||||
}
|
||||
|
||||
// Clear resets the head and tail pointer to zero.
|
||||
func (rb *rxRingBuffer) Clear() {
|
||||
rb.head.Set(0)
|
||||
rb.tail.Set(0)
|
||||
}
|
||||
|
||||
const txRingBufferSize = 8
|
||||
|
||||
// txRingBuffer is ring buffer implementation inspired by post at
|
||||
// https://www.embeddedrelated.com/showthread/comp.arch.embedded/77084-1.php
|
||||
type txRingBuffer struct {
|
||||
buffer [txRingBufferSize]struct {
|
||||
buf [64]byte
|
||||
size int
|
||||
}
|
||||
head volatile.Register8
|
||||
tail volatile.Register8
|
||||
}
|
||||
|
||||
// NewTxRingBuffer returns a new ring buffer.
|
||||
func NewTxRingBuffer() *txRingBuffer {
|
||||
return &txRingBuffer{}
|
||||
}
|
||||
|
||||
// Used returns how many bytes in buffer have been used.
|
||||
func (rb *txRingBuffer) Used() uint8 {
|
||||
return uint8(rb.head.Get() - rb.tail.Get())
|
||||
}
|
||||
|
||||
// Put stores a byte in the buffer. If the buffer is already
|
||||
// full, the method will return false.
|
||||
func (rb *txRingBuffer) Put(val []byte) bool {
|
||||
if rb.Used() == txRingBufferSize {
|
||||
return false
|
||||
}
|
||||
|
||||
if rb.Used() == 0 {
|
||||
rb.head.Set(rb.head.Get() + 1)
|
||||
rb.buffer[rb.head.Get()%txRingBufferSize].size = 0
|
||||
}
|
||||
buf := &rb.buffer[rb.head.Get()%txRingBufferSize]
|
||||
|
||||
for i := 0; i < len(val); i++ {
|
||||
if buf.size == 64 {
|
||||
// next
|
||||
// TODO: Make sure that data is not corrupted even when the buffer is full
|
||||
rb.head.Set(rb.head.Get() + 1)
|
||||
buf = &rb.buffer[rb.head.Get()%txRingBufferSize]
|
||||
rb.buffer[rb.head.Get()%txRingBufferSize].size = 0
|
||||
}
|
||||
buf.buf[buf.size] = val[i]
|
||||
buf.size++
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// Get returns a byte from the buffer. If the buffer is empty,
|
||||
// the method will return a false as the second value.
|
||||
func (rb *txRingBuffer) Get() ([]byte, bool) {
|
||||
if rb.Used() != 0 {
|
||||
rb.tail.Set(rb.tail.Get() + 1)
|
||||
size := rb.buffer[rb.tail.Get()%txRingBufferSize].size
|
||||
return rb.buffer[rb.tail.Get()%txRingBufferSize].buf[:size], true
|
||||
}
|
||||
return nil, false
|
||||
}
|
||||
|
||||
// Clear resets the head and tail pointer to zero.
|
||||
func (rb *txRingBuffer) Clear() {
|
||||
rb.head.Set(0)
|
||||
rb.tail.Set(0)
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
package cdc
|
||||
|
||||
const (
|
||||
cdcEndpointACM = 1
|
||||
cdcEndpointOut = 2
|
||||
cdcEndpointIn = 3
|
||||
)
|
||||
|
||||
// New returns USBCDC struct.
|
||||
func New() *USBCDC {
|
||||
if USB == nil {
|
||||
USB = &USBCDC{
|
||||
rxBuffer: NewRxRingBuffer(),
|
||||
txBuffer: NewTxRingBuffer(),
|
||||
}
|
||||
}
|
||||
return USB
|
||||
}
|
||||
|
||||
const (
|
||||
// bmRequestType
|
||||
usb_REQUEST_HOSTTODEVICE = 0x00
|
||||
usb_REQUEST_DEVICETOHOST = 0x80
|
||||
usb_REQUEST_DIRECTION = 0x80
|
||||
|
||||
usb_REQUEST_STANDARD = 0x00
|
||||
usb_REQUEST_CLASS = 0x20
|
||||
usb_REQUEST_VENDOR = 0x40
|
||||
usb_REQUEST_TYPE = 0x60
|
||||
|
||||
usb_REQUEST_DEVICE = 0x00
|
||||
usb_REQUEST_INTERFACE = 0x01
|
||||
usb_REQUEST_ENDPOINT = 0x02
|
||||
usb_REQUEST_OTHER = 0x03
|
||||
usb_REQUEST_RECIPIENT = 0x1F
|
||||
|
||||
usb_REQUEST_DEVICETOHOST_CLASS_INTERFACE = (usb_REQUEST_DEVICETOHOST | usb_REQUEST_CLASS | usb_REQUEST_INTERFACE)
|
||||
usb_REQUEST_HOSTTODEVICE_CLASS_INTERFACE = (usb_REQUEST_HOSTTODEVICE | usb_REQUEST_CLASS | usb_REQUEST_INTERFACE)
|
||||
usb_REQUEST_DEVICETOHOST_STANDARD_INTERFACE = (usb_REQUEST_DEVICETOHOST | usb_REQUEST_STANDARD | usb_REQUEST_INTERFACE)
|
||||
|
||||
// CDC Class requests
|
||||
usb_CDC_SET_LINE_CODING = 0x20
|
||||
usb_CDC_GET_LINE_CODING = 0x21
|
||||
usb_CDC_SET_CONTROL_LINE_STATE = 0x22
|
||||
usb_CDC_SEND_BREAK = 0x23
|
||||
|
||||
usb_CDC_V1_10 = 0x0110
|
||||
usb_CDC_COMMUNICATION_INTERFACE_CLASS = 0x02
|
||||
|
||||
usb_CDC_CALL_MANAGEMENT = 0x01
|
||||
usb_CDC_ABSTRACT_CONTROL_MODEL = 0x02
|
||||
usb_CDC_HEADER = 0x00
|
||||
usb_CDC_ABSTRACT_CONTROL_MANAGEMENT = 0x02
|
||||
usb_CDC_UNION = 0x06
|
||||
usb_CDC_CS_INTERFACE = 0x24
|
||||
usb_CDC_CS_ENDPOINT = 0x25
|
||||
usb_CDC_DATA_INTERFACE_CLASS = 0x0A
|
||||
|
||||
usb_CDC_LINESTATE_DTR = 0x01
|
||||
usb_CDC_LINESTATE_RTS = 0x02
|
||||
)
|
||||
@@ -0,0 +1,190 @@
|
||||
package cdc
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"machine"
|
||||
"machine/usb"
|
||||
"runtime/interrupt"
|
||||
)
|
||||
|
||||
var (
|
||||
ErrBufferEmpty = errors.New("USB-CDC buffer empty")
|
||||
)
|
||||
|
||||
const cdcLineInfoSize = 7
|
||||
|
||||
type cdcLineInfo struct {
|
||||
dwDTERate uint32
|
||||
bCharFormat uint8
|
||||
bParityType uint8
|
||||
bDataBits uint8
|
||||
lineState uint8
|
||||
}
|
||||
|
||||
// Read from the RX buffer.
|
||||
func (usbcdc *USBCDC) Read(data []byte) (n int, err error) {
|
||||
// check if RX buffer is empty
|
||||
size := usbcdc.Buffered()
|
||||
if size == 0 {
|
||||
return 0, nil
|
||||
}
|
||||
|
||||
// Make sure we do not read more from buffer than the data slice can hold.
|
||||
if len(data) < size {
|
||||
size = len(data)
|
||||
}
|
||||
|
||||
// only read number of bytes used from buffer
|
||||
for i := 0; i < size; i++ {
|
||||
v, _ := usbcdc.ReadByte()
|
||||
data[i] = v
|
||||
}
|
||||
|
||||
return size, nil
|
||||
}
|
||||
|
||||
// ReadByte reads a single byte from the RX buffer.
|
||||
// If there is no data in the buffer, returns an error.
|
||||
func (usbcdc *USBCDC) ReadByte() (byte, error) {
|
||||
// check if RX buffer is empty
|
||||
buf, ok := usbcdc.rxBuffer.Get()
|
||||
if !ok {
|
||||
return 0, ErrBufferEmpty
|
||||
}
|
||||
return buf, nil
|
||||
}
|
||||
|
||||
// Buffered returns the number of bytes currently stored in the RX buffer.
|
||||
func (usbcdc *USBCDC) Buffered() int {
|
||||
return int(usbcdc.rxBuffer.Used())
|
||||
}
|
||||
|
||||
// Receive handles adding data to the UART's data buffer.
|
||||
// Usually called by the IRQ handler for a machine.
|
||||
func (usbcdc *USBCDC) Receive(data byte) {
|
||||
usbcdc.rxBuffer.Put(data)
|
||||
}
|
||||
|
||||
// USBCDC is the USB CDC aka serial over USB interface.
|
||||
type USBCDC struct {
|
||||
rxBuffer *rxRingBuffer
|
||||
txBuffer *txRingBuffer
|
||||
waitTxc bool
|
||||
}
|
||||
|
||||
var (
|
||||
// USB is a USB CDC interface.
|
||||
USB *USBCDC
|
||||
|
||||
usbLineInfo = cdcLineInfo{115200, 0x00, 0x00, 0x08, 0x00}
|
||||
)
|
||||
|
||||
// Configure the USB CDC interface. The config is here for compatibility with the UART interface.
|
||||
func (usbcdc *USBCDC) Configure(config machine.UARTConfig) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Flush flushes buffered data.
|
||||
func (usbcdc *USBCDC) Flush() {
|
||||
mask := interrupt.Disable()
|
||||
if b, ok := usbcdc.txBuffer.Get(); ok {
|
||||
machine.SendUSBInPacket(cdcEndpointIn, b)
|
||||
} else {
|
||||
usbcdc.waitTxc = false
|
||||
}
|
||||
interrupt.Restore(mask)
|
||||
}
|
||||
|
||||
// Write data to the USBCDC.
|
||||
func (usbcdc *USBCDC) Write(data []byte) (n int, err error) {
|
||||
if usbLineInfo.lineState > 0 {
|
||||
mask := interrupt.Disable()
|
||||
usbcdc.txBuffer.Put(data)
|
||||
if !usbcdc.waitTxc {
|
||||
usbcdc.waitTxc = true
|
||||
usbcdc.Flush()
|
||||
}
|
||||
interrupt.Restore(mask)
|
||||
}
|
||||
return len(data), nil
|
||||
}
|
||||
|
||||
// WriteByte writes a byte of data to the USB CDC interface.
|
||||
func (usbcdc *USBCDC) WriteByte(c byte) error {
|
||||
usbcdc.Write([]byte{c})
|
||||
return nil
|
||||
}
|
||||
|
||||
func (usbcdc *USBCDC) DTR() bool {
|
||||
return (usbLineInfo.lineState & usb_CDC_LINESTATE_DTR) > 0
|
||||
}
|
||||
|
||||
func (usbcdc *USBCDC) RTS() bool {
|
||||
return (usbLineInfo.lineState & usb_CDC_LINESTATE_RTS) > 0
|
||||
}
|
||||
|
||||
func cdcCallbackRx(b []byte) {
|
||||
for i := range b {
|
||||
USB.Receive(b[i])
|
||||
}
|
||||
}
|
||||
|
||||
func cdcSetup(setup usb.Setup) bool {
|
||||
if setup.BmRequestType == usb_REQUEST_DEVICETOHOST_CLASS_INTERFACE {
|
||||
if setup.BRequest == usb_CDC_GET_LINE_CODING {
|
||||
var b [cdcLineInfoSize]byte
|
||||
b[0] = byte(usbLineInfo.dwDTERate)
|
||||
b[1] = byte(usbLineInfo.dwDTERate >> 8)
|
||||
b[2] = byte(usbLineInfo.dwDTERate >> 16)
|
||||
b[3] = byte(usbLineInfo.dwDTERate >> 24)
|
||||
b[4] = byte(usbLineInfo.bCharFormat)
|
||||
b[5] = byte(usbLineInfo.bParityType)
|
||||
b[6] = byte(usbLineInfo.bDataBits)
|
||||
|
||||
machine.SendUSBInPacket(0, b[:])
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
if setup.BmRequestType == usb_REQUEST_HOSTTODEVICE_CLASS_INTERFACE {
|
||||
if setup.BRequest == usb_CDC_SET_LINE_CODING {
|
||||
b, err := machine.ReceiveUSBControlPacket()
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
|
||||
usbLineInfo.dwDTERate = uint32(b[0]) | uint32(b[1])<<8 | uint32(b[2])<<16 | uint32(b[3])<<24
|
||||
usbLineInfo.bCharFormat = b[4]
|
||||
usbLineInfo.bParityType = b[5]
|
||||
usbLineInfo.bDataBits = b[6]
|
||||
}
|
||||
|
||||
if setup.BRequest == usb_CDC_SET_CONTROL_LINE_STATE {
|
||||
usbLineInfo.lineState = setup.WValueL
|
||||
}
|
||||
|
||||
if setup.BRequest == usb_CDC_SET_LINE_CODING || setup.BRequest == usb_CDC_SET_CONTROL_LINE_STATE {
|
||||
// auto-reset into the bootloader
|
||||
if usbLineInfo.dwDTERate == 1200 && usbLineInfo.lineState&usb_CDC_LINESTATE_DTR == 0 {
|
||||
machine.EnterBootloader()
|
||||
} else {
|
||||
// TODO: cancel any reset
|
||||
}
|
||||
machine.SendZlp()
|
||||
}
|
||||
|
||||
if setup.BRequest == usb_CDC_SEND_BREAK {
|
||||
// TODO: something with this value?
|
||||
// breakValue = ((uint16_t)setup.wValueH << 8) | setup.wValueL;
|
||||
// return false;
|
||||
machine.SendZlp()
|
||||
}
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func EnableUSBCDC() {
|
||||
machine.USBCDC = New()
|
||||
machine.EnableCDC(USB.Flush, cdcCallbackRx, cdcSetup)
|
||||
}
|
||||
@@ -1,22 +1,37 @@
|
||||
//go:build sam || nrf52840
|
||||
// +build sam nrf52840
|
||||
package usb
|
||||
|
||||
package machine
|
||||
import "runtime/volatile"
|
||||
|
||||
type USBDescriptor struct {
|
||||
// DeviceDescBank is the USB device endpoint descriptor.
|
||||
type DeviceDescBank struct {
|
||||
ADDR volatile.Register32
|
||||
PCKSIZE volatile.Register32
|
||||
EXTREG volatile.Register16
|
||||
STATUS_BK volatile.Register8
|
||||
_reserved [5]volatile.Register8
|
||||
}
|
||||
|
||||
type DeviceDescriptor struct {
|
||||
DeviceDescBank [2]DeviceDescBank
|
||||
}
|
||||
|
||||
type Descriptor struct {
|
||||
Device []byte
|
||||
Configuration []byte
|
||||
HID map[uint16][]byte
|
||||
}
|
||||
|
||||
func (d *USBDescriptor) Configure(idVendor, idProduct uint16) {
|
||||
func (d *Descriptor) Configure(idVendor, idProduct uint16) {
|
||||
d.Device[8] = byte(idVendor)
|
||||
d.Device[9] = byte(idVendor >> 8)
|
||||
d.Device[10] = byte(idProduct)
|
||||
d.Device[11] = byte(idProduct >> 8)
|
||||
|
||||
d.Configuration[2] = byte(len(d.Configuration))
|
||||
d.Configuration[3] = byte(len(d.Configuration) >> 8)
|
||||
}
|
||||
|
||||
var descriptorCDC = USBDescriptor{
|
||||
var DescriptorCDC = Descriptor{
|
||||
Device: []byte{
|
||||
0x12, 0x01, 0x00, 0x02, 0xef, 0x02, 0x01, 0x40, 0x86, 0x28, 0x2d, 0x80, 0x00, 0x01, 0x01, 0x02, 0x03, 0x01,
|
||||
},
|
||||
@@ -35,7 +50,7 @@ var descriptorCDC = USBDescriptor{
|
||||
},
|
||||
}
|
||||
|
||||
var descriptorCDCHID = USBDescriptor{
|
||||
var DescriptorCDCHID = Descriptor{
|
||||
Device: []byte{
|
||||
0x12, 0x01, 0x00, 0x02, 0xef, 0x02, 0x01, 0x40, 0x86, 0x28, 0x2d, 0x80, 0x00, 0x01, 0x01, 0x02, 0x03, 0x01,
|
||||
},
|
||||
@@ -68,3 +83,35 @@ var descriptorCDCHID = USBDescriptor{
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
var DescriptorCDCMIDI = Descriptor{
|
||||
Device: []byte{
|
||||
0x12, 0x01, 0x00, 0x02, 0xef, 0x02, 0x01, 0x40, 0x86, 0x28, 0x2d, 0x80, 0x00, 0x01, 0x01, 0x02, 0x03, 0x01,
|
||||
},
|
||||
Configuration: []byte{
|
||||
0x09, 0x02, 0xaf, 0x00, 0x04, 0x01, 0x00, 0xa0, 0x32,
|
||||
0x08, 0x0b, 0x00, 0x02, 0x02, 0x02, 0x00, 0x00,
|
||||
0x09, 0x04, 0x00, 0x00, 0x01, 0x02, 0x02, 0x00, 0x00,
|
||||
0x05, 0x24, 0x00, 0x10, 0x01,
|
||||
0x04, 0x24, 0x02, 0x06,
|
||||
0x05, 0x24, 0x06, 0x00, 0x01,
|
||||
0x05, 0x24, 0x01, 0x01, 0x01,
|
||||
0x07, 0x05, 0x81, 0x03, 0x10, 0x00, 0x10,
|
||||
0x09, 0x04, 0x01, 0x00, 0x02, 0x0a, 0x00, 0x00, 0x00,
|
||||
0x07, 0x05, 0x02, 0x02, 0x40, 0x00, 0x00,
|
||||
0x07, 0x05, 0x83, 0x02, 0x40, 0x00, 0x00,
|
||||
0x08, 0x0b, 0x02, 0x02, 0x01, 0x01, 0x00, 0x00,
|
||||
0x09, 0x04, 0x02, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00,
|
||||
0x09, 0x24, 0x01, 0x00, 0x01, 0x09, 0x00, 0x01, 0x03,
|
||||
0x09, 0x04, 0x03, 0x00, 0x02, 0x01, 0x03, 0x00, 0x00,
|
||||
0x07, 0x24, 0x01, 0x00, 0x01, 0x41, 0x00,
|
||||
0x06, 0x24, 0x02, 0x01, 0x01, 0x00,
|
||||
0x06, 0x24, 0x02, 0x02, 0x02, 0x00,
|
||||
0x09, 0x24, 0x03, 0x01, 0x03, 0x01, 0x02, 0x01, 0x00,
|
||||
0x09, 0x24, 0x03, 0x02, 0x04, 0x01, 0x01, 0x01, 0x00,
|
||||
0x09, 0x05, 0x05, 0x02, 0x40, 0x00, 0x00, 0x00, 0x00,
|
||||
0x05, 0x25, 0x01, 0x01, 0x01,
|
||||
0x09, 0x05, 0x86, 0x02, 0x40, 0x00, 0x00, 0x00, 0x00,
|
||||
0x05, 0x25, 0x01, 0x01, 0x03,
|
||||
},
|
||||
}
|
||||
@@ -3,6 +3,7 @@ package hid
|
||||
import (
|
||||
"errors"
|
||||
"machine"
|
||||
"machine/usb"
|
||||
)
|
||||
|
||||
// from usb-hid.go
|
||||
@@ -14,38 +15,50 @@ var (
|
||||
|
||||
const (
|
||||
hidEndpoint = 4
|
||||
|
||||
usb_SET_REPORT_TYPE = 33
|
||||
usb_SET_IDLE = 10
|
||||
)
|
||||
|
||||
type hidDevicer interface {
|
||||
Callback() bool
|
||||
Handler() bool
|
||||
}
|
||||
|
||||
var devices [5]hidDevicer
|
||||
var size int
|
||||
|
||||
// SetCallbackHandler sets the callback. Only the first time it is called, it
|
||||
// SetHandler sets the handler. Only the first time it is called, it
|
||||
// calls machine.EnableHID for USB configuration
|
||||
func SetCallbackHandler(d hidDevicer) {
|
||||
func SetHandler(d hidDevicer) {
|
||||
if size == 0 {
|
||||
machine.EnableHID(callback)
|
||||
machine.EnableHID(handler, nil, setupHandler)
|
||||
}
|
||||
|
||||
devices[size] = d
|
||||
size++
|
||||
}
|
||||
|
||||
func callback() {
|
||||
func handler() {
|
||||
for _, d := range devices {
|
||||
if d == nil {
|
||||
continue
|
||||
}
|
||||
if done := d.Callback(); done {
|
||||
if done := d.Handler(); done {
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func setupHandler(setup usb.Setup) bool {
|
||||
ok := false
|
||||
if setup.BmRequestType == usb_SET_REPORT_TYPE && setup.BRequest == usb_SET_IDLE {
|
||||
machine.SendZlp()
|
||||
ok = true
|
||||
}
|
||||
return ok
|
||||
}
|
||||
|
||||
// SendUSBPacket sends a HIDPacket.
|
||||
func SendUSBPacket(b []byte) {
|
||||
machine.SendUSBHIDPacket(hidEndpoint, b)
|
||||
machine.SendUSBInPacket(hidEndpoint, b)
|
||||
}
|
||||
|
||||
@@ -41,7 +41,8 @@ type keyboard struct {
|
||||
// wideChar holds high bits for the UTF-8 decoder.
|
||||
wideChar uint16
|
||||
|
||||
buf *hid.RingBuffer
|
||||
buf *hid.RingBuffer
|
||||
waitTxc bool
|
||||
}
|
||||
|
||||
// decodeState represents a state in the UTF-8 decode state machine.
|
||||
@@ -58,7 +59,7 @@ const (
|
||||
func init() {
|
||||
if Keyboard == nil {
|
||||
Keyboard = newKeyboard()
|
||||
hid.SetCallbackHandler(Keyboard)
|
||||
hid.SetHandler(Keyboard)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -73,14 +74,25 @@ func newKeyboard() *keyboard {
|
||||
}
|
||||
}
|
||||
|
||||
func (kb *keyboard) Callback() bool {
|
||||
func (kb *keyboard) Handler() bool {
|
||||
kb.waitTxc = false
|
||||
if b, ok := kb.buf.Get(); ok {
|
||||
kb.waitTxc = true
|
||||
hid.SendUSBPacket(b)
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (kb *keyboard) tx(b []byte) {
|
||||
if kb.waitTxc {
|
||||
kb.buf.Put(b)
|
||||
} else {
|
||||
kb.waitTxc = true
|
||||
hid.SendUSBPacket(b)
|
||||
}
|
||||
}
|
||||
|
||||
func (kb *keyboard) ready() bool {
|
||||
return true
|
||||
}
|
||||
@@ -214,7 +226,7 @@ func (kb *keyboard) Press(c Keycode) error {
|
||||
}
|
||||
|
||||
func (kb *keyboard) sendKey(consumer bool, b []byte) bool {
|
||||
kb.buf.Put(b)
|
||||
kb.tx(b)
|
||||
return true
|
||||
}
|
||||
|
||||
|
||||
@@ -15,14 +15,15 @@ const (
|
||||
)
|
||||
|
||||
type mouse struct {
|
||||
buf *hid.RingBuffer
|
||||
button Button
|
||||
buf *hid.RingBuffer
|
||||
button Button
|
||||
waitTxc bool
|
||||
}
|
||||
|
||||
func init() {
|
||||
if Mouse == nil {
|
||||
Mouse = newMouse()
|
||||
hid.SetCallbackHandler(Mouse)
|
||||
hid.SetHandler(Mouse)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -37,14 +38,25 @@ func newMouse() *mouse {
|
||||
}
|
||||
}
|
||||
|
||||
func (m *mouse) Callback() bool {
|
||||
func (m *mouse) Handler() bool {
|
||||
m.waitTxc = false
|
||||
if b, ok := m.buf.Get(); ok {
|
||||
m.waitTxc = true
|
||||
hid.SendUSBPacket(b[:5])
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (m *mouse) tx(b []byte) {
|
||||
if m.waitTxc {
|
||||
m.buf.Put(b)
|
||||
} else {
|
||||
m.waitTxc = true
|
||||
hid.SendUSBPacket(b)
|
||||
}
|
||||
}
|
||||
|
||||
// Move is a function that moves the mouse cursor.
|
||||
func (m *mouse) Move(vx, vy int) {
|
||||
if vx == 0 && vy == 0 {
|
||||
@@ -65,12 +77,12 @@ func (m *mouse) Move(vx, vy int) {
|
||||
vy = 127
|
||||
}
|
||||
|
||||
m.buf.Put([]byte{
|
||||
m.tx([]byte{
|
||||
0x01, byte(m.button), byte(vx), byte(vy), 0x00,
|
||||
})
|
||||
}
|
||||
|
||||
// Cilck clicks the mouse button.
|
||||
// Click clicks the mouse button.
|
||||
func (m *mouse) Click(btn Button) {
|
||||
m.Press(btn)
|
||||
m.Release(btn)
|
||||
@@ -79,7 +91,7 @@ func (m *mouse) Click(btn Button) {
|
||||
// Press presses the given mouse buttons.
|
||||
func (m *mouse) Press(btn Button) {
|
||||
m.button |= btn
|
||||
m.buf.Put([]byte{
|
||||
m.tx([]byte{
|
||||
0x01, byte(m.button), 0x00, 0x00, 0x00,
|
||||
})
|
||||
}
|
||||
@@ -87,7 +99,7 @@ func (m *mouse) Press(btn Button) {
|
||||
// Release releases the given mouse buttons.
|
||||
func (m *mouse) Release(btn Button) {
|
||||
m.button &= ^btn
|
||||
m.buf.Put([]byte{
|
||||
m.tx([]byte{
|
||||
0x01, byte(m.button), 0x00, 0x00, 0x00,
|
||||
})
|
||||
}
|
||||
@@ -105,7 +117,7 @@ func (m *mouse) Wheel(v int) {
|
||||
v = 127
|
||||
}
|
||||
|
||||
m.buf.Put([]byte{
|
||||
m.tx([]byte{
|
||||
0x01, byte(m.button), 0x00, 0x00, byte(v),
|
||||
})
|
||||
}
|
||||
|
||||
@@ -0,0 +1,52 @@
|
||||
package midi
|
||||
|
||||
import (
|
||||
"runtime/volatile"
|
||||
)
|
||||
|
||||
const bufferSize = 128
|
||||
|
||||
// RingBuffer is ring buffer implementation inspired by post at
|
||||
// https://www.embeddedrelated.com/showthread/comp.arch.embedded/77084-1.php
|
||||
type RingBuffer struct {
|
||||
rxbuffer [bufferSize][4]byte
|
||||
head volatile.Register8
|
||||
tail volatile.Register8
|
||||
}
|
||||
|
||||
// NewRingBuffer returns a new ring buffer.
|
||||
func NewRingBuffer() *RingBuffer {
|
||||
return &RingBuffer{}
|
||||
}
|
||||
|
||||
// Used returns how many bytes in buffer have been used.
|
||||
func (rb *RingBuffer) Used() uint8 {
|
||||
return uint8(rb.head.Get() - rb.tail.Get())
|
||||
}
|
||||
|
||||
// Put stores a byte in the buffer. If the buffer is already
|
||||
// full, the method will return false.
|
||||
func (rb *RingBuffer) Put(val []byte) bool {
|
||||
if rb.Used() != bufferSize {
|
||||
rb.head.Set(rb.head.Get() + 1)
|
||||
copy(rb.rxbuffer[rb.head.Get()%bufferSize][:], val)
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// Get returns a byte from the buffer. If the buffer is empty,
|
||||
// the method will return a false as the second value.
|
||||
func (rb *RingBuffer) Get() ([]byte, bool) {
|
||||
if rb.Used() != 0 {
|
||||
rb.tail.Set(rb.tail.Get() + 1)
|
||||
return rb.rxbuffer[rb.tail.Get()%bufferSize][:], true
|
||||
}
|
||||
return nil, false
|
||||
}
|
||||
|
||||
// Clear resets the head and tail pointer to zero.
|
||||
func (rb *RingBuffer) Clear() {
|
||||
rb.head.Set(0)
|
||||
rb.tail.Set(0)
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
package midi
|
||||
|
||||
// NoteOn sends a note on message.
|
||||
func (m *midi) NoteOn(cable, channel uint8, note Note, velocity uint8) {
|
||||
m.msg[0], m.msg[1], m.msg[2], m.msg[3] = (cable&0xf<<4)|0x9, 0x90|(channel&0xf), byte(note)&0x7f, velocity&0x7f
|
||||
m.Write(m.msg[:])
|
||||
}
|
||||
|
||||
// NoteOff sends a note off message.
|
||||
func (m *midi) NoteOff(cable, channel uint8, note Note, velocity uint8) {
|
||||
m.msg[0], m.msg[1], m.msg[2], m.msg[3] = (cable&0xf<<4)|0x8, 0x80|(channel&0xf), byte(note)&0x7f, velocity&0x7f
|
||||
m.Write(m.msg[:])
|
||||
}
|
||||
|
||||
// SendCC sends a continuous controller message.
|
||||
func (m *midi) SendCC(cable, channel, control, value uint8) {
|
||||
m.msg[0], m.msg[1], m.msg[2], m.msg[3] = (cable&0xf<<4)|0xB, 0xB0|(channel&0xf), control&0x7f, value&0x7f
|
||||
m.Write(m.msg[:])
|
||||
}
|
||||
@@ -0,0 +1,80 @@
|
||||
package midi
|
||||
|
||||
import (
|
||||
"machine"
|
||||
)
|
||||
|
||||
const (
|
||||
midiEndpointOut = 5 // from PC
|
||||
midiEndpointIn = 6 // to PC
|
||||
)
|
||||
|
||||
var Midi *midi
|
||||
|
||||
type midi struct {
|
||||
msg [4]byte
|
||||
buf *RingBuffer
|
||||
rxHandler func([]byte)
|
||||
waitTxc bool
|
||||
}
|
||||
|
||||
func init() {
|
||||
if Midi == nil {
|
||||
Midi = newMidi()
|
||||
}
|
||||
}
|
||||
|
||||
// New returns hid-mouse.
|
||||
func New() *midi {
|
||||
return Midi
|
||||
}
|
||||
|
||||
func newMidi() *midi {
|
||||
m := &midi{
|
||||
buf: NewRingBuffer(),
|
||||
}
|
||||
machine.EnableMIDI(m.Handler, m.RxHandler, nil)
|
||||
return m
|
||||
}
|
||||
|
||||
func (m *midi) SetHandler(rxHandler func([]byte)) {
|
||||
m.rxHandler = rxHandler
|
||||
}
|
||||
|
||||
func (m *midi) Write(b []byte) (n int, err error) {
|
||||
i := 0
|
||||
for i = 0; i < len(b); i += 4 {
|
||||
m.tx(b[i : i+4])
|
||||
}
|
||||
return i, nil
|
||||
}
|
||||
|
||||
// sendUSBPacket sends a MIDIPacket.
|
||||
func (m *midi) sendUSBPacket(b []byte) {
|
||||
machine.SendUSBInPacket(midiEndpointIn, b)
|
||||
}
|
||||
|
||||
// from BulkIn
|
||||
func (m *midi) Handler() {
|
||||
m.waitTxc = false
|
||||
if b, ok := m.buf.Get(); ok {
|
||||
m.waitTxc = true
|
||||
m.sendUSBPacket(b)
|
||||
}
|
||||
}
|
||||
|
||||
func (m *midi) tx(b []byte) {
|
||||
if m.waitTxc {
|
||||
m.buf.Put(b)
|
||||
} else {
|
||||
m.waitTxc = true
|
||||
m.sendUSBPacket(b)
|
||||
}
|
||||
}
|
||||
|
||||
// from BulkOut
|
||||
func (m *midi) RxHandler(b []byte) {
|
||||
if m.rxHandler != nil {
|
||||
m.rxHandler(b)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,108 @@
|
||||
package midi
|
||||
|
||||
// Note represents a MIDI note number. For example, Note(69) is A4 or 440Hz.
|
||||
type Note uint8
|
||||
|
||||
// Define all the notes in a format similar to the Tone library in the Arduino
|
||||
// IDE.
|
||||
const (
|
||||
A0 Note = iota + 21 // 27.5Hz
|
||||
AS0
|
||||
B0
|
||||
C1
|
||||
CS1
|
||||
D1
|
||||
DS1
|
||||
E1
|
||||
F1
|
||||
FS1
|
||||
G1
|
||||
GS1
|
||||
A1 // 55Hz
|
||||
AS1
|
||||
B1
|
||||
C2
|
||||
CS2
|
||||
D2
|
||||
DS2
|
||||
E2
|
||||
F2
|
||||
FS2
|
||||
G2
|
||||
GS2
|
||||
A2 // 110Hz
|
||||
AS2
|
||||
B2
|
||||
C3
|
||||
CS3
|
||||
D3
|
||||
DS3
|
||||
E3
|
||||
F3
|
||||
FS3
|
||||
G3
|
||||
GS3
|
||||
A3 // 220Hz
|
||||
AS3
|
||||
B3
|
||||
C4
|
||||
CS4
|
||||
D4
|
||||
DS4
|
||||
E4
|
||||
F4
|
||||
FS4
|
||||
G4
|
||||
GS4
|
||||
A4 // 440Hz
|
||||
AS4
|
||||
B4
|
||||
C5
|
||||
CS5
|
||||
D5
|
||||
DS5
|
||||
E5
|
||||
F5
|
||||
FS5
|
||||
G5
|
||||
GS5
|
||||
A5 // 880Hz
|
||||
AS5
|
||||
B5
|
||||
C6
|
||||
CS6
|
||||
D6
|
||||
DS6
|
||||
E6
|
||||
F6
|
||||
FS6
|
||||
G6
|
||||
GS6
|
||||
A6 // 1760Hz
|
||||
AS6
|
||||
B6
|
||||
C7
|
||||
CS7
|
||||
D7
|
||||
DS7
|
||||
E7
|
||||
F7
|
||||
FS7
|
||||
G7
|
||||
GS7
|
||||
A7 // 3520Hz
|
||||
AS7
|
||||
B7
|
||||
C8
|
||||
CS8
|
||||
D8
|
||||
DS8
|
||||
E8
|
||||
F8
|
||||
FS8
|
||||
G8
|
||||
GS8
|
||||
A8 // 7040Hz
|
||||
AS8
|
||||
B8
|
||||
)
|
||||
@@ -0,0 +1,121 @@
|
||||
package usb
|
||||
|
||||
var (
|
||||
// TODO: allow setting these
|
||||
STRING_LANGUAGE = [2]uint16{(3 << 8) | (2 + 2), 0x0409} // English
|
||||
)
|
||||
|
||||
const (
|
||||
DescriptorConfigCDC = 1 << iota
|
||||
DescriptorConfigHID
|
||||
DescriptorConfigMIDI
|
||||
)
|
||||
|
||||
const (
|
||||
IMANUFACTURER = 1
|
||||
IPRODUCT = 2
|
||||
ISERIAL = 3
|
||||
|
||||
ENDPOINT_TYPE_DISABLE = 0xFF
|
||||
ENDPOINT_TYPE_CONTROL = 0x00
|
||||
ENDPOINT_TYPE_ISOCHRONOUS = 0x01
|
||||
ENDPOINT_TYPE_BULK = 0x02
|
||||
ENDPOINT_TYPE_INTERRUPT = 0x03
|
||||
|
||||
DEVICE_DESCRIPTOR_TYPE = 1
|
||||
CONFIGURATION_DESCRIPTOR_TYPE = 2
|
||||
STRING_DESCRIPTOR_TYPE = 3
|
||||
INTERFACE_DESCRIPTOR_TYPE = 4
|
||||
ENDPOINT_DESCRIPTOR_TYPE = 5
|
||||
DEVICE_QUALIFIER = 6
|
||||
OTHER_SPEED_CONFIGURATION = 7
|
||||
SET_REPORT_TYPE = 33
|
||||
HID_REPORT_TYPE = 34
|
||||
|
||||
EndpointOut = 0x00
|
||||
EndpointIn = 0x80
|
||||
|
||||
NumberOfEndpoints = 8
|
||||
EndpointPacketSize = 64 // 64 for Full Speed, EPT size max is 1024
|
||||
|
||||
// standard requests
|
||||
GET_STATUS = 0
|
||||
CLEAR_FEATURE = 1
|
||||
SET_FEATURE = 3
|
||||
SET_ADDRESS = 5
|
||||
GET_DESCRIPTOR = 6
|
||||
SET_DESCRIPTOR = 7
|
||||
GET_CONFIGURATION = 8
|
||||
SET_CONFIGURATION = 9
|
||||
GET_INTERFACE = 10
|
||||
SET_INTERFACE = 11
|
||||
|
||||
// non standard requests
|
||||
SET_IDLE = 10
|
||||
|
||||
DEVICE_CLASS_COMMUNICATIONS = 0x02
|
||||
DEVICE_CLASS_HUMAN_INTERFACE = 0x03
|
||||
DEVICE_CLASS_STORAGE = 0x08
|
||||
DEVICE_CLASS_VENDOR_SPECIFIC = 0xFF
|
||||
|
||||
CONFIG_POWERED_MASK = 0x40
|
||||
CONFIG_BUS_POWERED = 0x80
|
||||
CONFIG_SELF_POWERED = 0xC0
|
||||
CONFIG_REMOTE_WAKEUP = 0x20
|
||||
|
||||
// Interface
|
||||
NumberOfInterfaces = 3
|
||||
CDC_ACM_INTERFACE = 0 // CDC ACM
|
||||
CDC_DATA_INTERFACE = 1 // CDC Data
|
||||
CDC_FIRST_ENDPOINT = 1
|
||||
HID_INTERFACE = 2 // HID
|
||||
|
||||
// Endpoint
|
||||
CONTROL_ENDPOINT = 0
|
||||
CDC_ENDPOINT_ACM = 1
|
||||
CDC_ENDPOINT_OUT = 2
|
||||
CDC_ENDPOINT_IN = 3
|
||||
HID_ENDPOINT_IN = 4
|
||||
MIDI_ENDPOINT_OUT = 5
|
||||
MIDI_ENDPOINT_IN = 6
|
||||
|
||||
// bmRequestType
|
||||
REQUEST_HOSTTODEVICE = 0x00
|
||||
REQUEST_DEVICETOHOST = 0x80
|
||||
REQUEST_DIRECTION = 0x80
|
||||
|
||||
REQUEST_STANDARD = 0x00
|
||||
REQUEST_CLASS = 0x20
|
||||
REQUEST_VENDOR = 0x40
|
||||
REQUEST_TYPE = 0x60
|
||||
|
||||
REQUEST_DEVICE = 0x00
|
||||
REQUEST_INTERFACE = 0x01
|
||||
REQUEST_ENDPOINT = 0x02
|
||||
REQUEST_OTHER = 0x03
|
||||
REQUEST_RECIPIENT = 0x1F
|
||||
|
||||
REQUEST_DEVICETOHOST_CLASS_INTERFACE = (REQUEST_DEVICETOHOST | REQUEST_CLASS | REQUEST_INTERFACE)
|
||||
REQUEST_HOSTTODEVICE_CLASS_INTERFACE = (REQUEST_HOSTTODEVICE | REQUEST_CLASS | REQUEST_INTERFACE)
|
||||
REQUEST_DEVICETOHOST_STANDARD_INTERFACE = (REQUEST_DEVICETOHOST | REQUEST_STANDARD | REQUEST_INTERFACE)
|
||||
)
|
||||
|
||||
type Setup struct {
|
||||
BmRequestType uint8
|
||||
BRequest uint8
|
||||
WValueL uint8
|
||||
WValueH uint8
|
||||
WIndex uint16
|
||||
WLength uint16
|
||||
}
|
||||
|
||||
func NewSetup(data []byte) Setup {
|
||||
u := Setup{}
|
||||
u.BmRequestType = uint8(data[0])
|
||||
u.BRequest = uint8(data[1])
|
||||
u.WValueL = uint8(data[2])
|
||||
u.WValueH = uint8(data[3])
|
||||
u.WIndex = uint16(data[4]) | (uint16(data[5]) << 8)
|
||||
u.WLength = uint16(data[6]) | (uint16(data[7]) << 8)
|
||||
return u
|
||||
}
|
||||
+21
-8
@@ -39,6 +39,17 @@ func printint8(n int8) {
|
||||
}
|
||||
}
|
||||
|
||||
func printuintptr(n uintptr) {
|
||||
switch unsafe.Sizeof(n) {
|
||||
case 2:
|
||||
printuint16(uint16(n))
|
||||
case 4:
|
||||
printuint32(uint32(n))
|
||||
case 8:
|
||||
printuint64(uint64(n))
|
||||
}
|
||||
}
|
||||
|
||||
func printuint16(n uint16) {
|
||||
printuint32(uint32(n))
|
||||
}
|
||||
@@ -323,14 +334,7 @@ func printitf(msg interface{}) {
|
||||
// cast to underlying type
|
||||
itf := *(*_interface)(unsafe.Pointer(&msg))
|
||||
putchar('(')
|
||||
switch unsafe.Sizeof(itf.typecode) {
|
||||
case 2:
|
||||
printuint16(uint16(itf.typecode))
|
||||
case 4:
|
||||
printuint32(uint32(itf.typecode))
|
||||
case 8:
|
||||
printuint64(uint64(itf.typecode))
|
||||
}
|
||||
printuintptr(uintptr(itf.typecode))
|
||||
putchar(':')
|
||||
print(itf.value)
|
||||
putchar(')')
|
||||
@@ -372,3 +376,12 @@ func printbool(b bool) {
|
||||
printstring("false")
|
||||
}
|
||||
}
|
||||
|
||||
func printslice(ptr, len_, cap_ uintptr) {
|
||||
putchar('[')
|
||||
printuintptr(len_)
|
||||
putchar('/')
|
||||
printuintptr(cap_)
|
||||
putchar(']')
|
||||
printptr(ptr)
|
||||
}
|
||||
|
||||
@@ -9,7 +9,7 @@ import (
|
||||
)
|
||||
|
||||
func initUART() {
|
||||
machine.Serial.Configure(machine.UARTConfig{})
|
||||
machine.InitSerial()
|
||||
}
|
||||
|
||||
func putchar(c byte) {
|
||||
|
||||
@@ -7,6 +7,7 @@ import (
|
||||
"device/arm"
|
||||
"device/sam"
|
||||
"machine"
|
||||
"machine/usb/cdc"
|
||||
"runtime/interrupt"
|
||||
"runtime/volatile"
|
||||
"unsafe"
|
||||
@@ -28,11 +29,9 @@ func init() {
|
||||
initUSBClock()
|
||||
initADCClock()
|
||||
|
||||
// connect to USB CDC interface
|
||||
machine.Serial.Configure(machine.UARTConfig{})
|
||||
if !machine.USB.Configured() {
|
||||
machine.USB.Configure(machine.UARTConfig{})
|
||||
}
|
||||
cdc.EnableUSBCDC()
|
||||
machine.USBDev.Configure(machine.UARTConfig{})
|
||||
machine.InitSerial()
|
||||
}
|
||||
|
||||
func putchar(c byte) {
|
||||
|
||||
@@ -7,6 +7,7 @@ import (
|
||||
"device/arm"
|
||||
"device/sam"
|
||||
"machine"
|
||||
"machine/usb/cdc"
|
||||
"runtime/interrupt"
|
||||
"runtime/volatile"
|
||||
)
|
||||
@@ -28,11 +29,9 @@ func init() {
|
||||
initUSBClock()
|
||||
initADCClock()
|
||||
|
||||
// connect to USB CDC interface
|
||||
machine.Serial.Configure(machine.UARTConfig{})
|
||||
if !machine.USB.Configured() {
|
||||
machine.USB.Configure(machine.UARTConfig{})
|
||||
}
|
||||
cdc.EnableUSBCDC()
|
||||
machine.USBDev.Configure(machine.UARTConfig{})
|
||||
machine.InitSerial()
|
||||
}
|
||||
|
||||
func putchar(c byte) {
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user