mirror of
https://github.com/tinygo-org/tinygo.git
synced 2026-08-11 14:33:41 +00:00
Compare commits
42 Commits
gc-precise
...
v0.6.0
| Author | SHA1 | Date | |
|---|---|---|---|
| da85710894 | |||
| 0ae467d3e2 | |||
| 4442b1304e | |||
| 83ab61e261 | |||
| 2504754325 | |||
| be491abc46 | |||
| 31189deb3b | |||
| 90cd3f8ea5 | |||
| 2f95a5d452 | |||
| eb1d834dd4 | |||
| 3313decb68 | |||
| 191a076956 | |||
| 0f2dcba7b3 | |||
| 94b8214529 | |||
| 421ef04efb | |||
| f7687c43aa | |||
| 5a7bab8808 | |||
| 3a73e64557 | |||
| 9f8340a970 | |||
| 0f6873cf02 | |||
| f2cd4d12e8 | |||
| 7e6a54ac62 | |||
| 7156afca9e | |||
| 87ac804642 | |||
| edcb11f9f6 | |||
| 3568254593 | |||
| 3bf4c06c99 | |||
| f1d9e7b75e | |||
| e4d53daa02 | |||
| 98a3047b58 | |||
| ba85c82fbb | |||
| 7b6ef65fe7 | |||
| de032cddd2 | |||
| 51c6b972bf | |||
| 4cd151faf5 | |||
| 5342d392aa | |||
| f94af9f61e | |||
| 7ada00790c | |||
| dfa713040a | |||
| 82dc14b741 | |||
| d3f2237d44 | |||
| fc2ed2bdd0 |
+17
-55
@@ -40,67 +40,36 @@ commands:
|
|||||||
sudo tar -C /usr/local -xf node-v10.15.1-linux-x64.tar.xz
|
sudo tar -C /usr/local -xf node-v10.15.1-linux-x64.tar.xz
|
||||||
sudo ln -s /usr/local/node-v10.15.1-linux-x64/bin/node /usr/bin/node
|
sudo ln -s /usr/local/node-v10.15.1-linux-x64/bin/node /usr/bin/node
|
||||||
rm node-v10.15.1-linux-x64.tar.xz
|
rm node-v10.15.1-linux-x64.tar.xz
|
||||||
dep:
|
|
||||||
steps:
|
|
||||||
- run:
|
|
||||||
name: "Install Go dependencies"
|
|
||||||
command: |
|
|
||||||
curl https://raw.githubusercontent.com/golang/dep/master/install.sh | sh
|
|
||||||
dep ensure --vendor-only
|
|
||||||
llvm-source-linux:
|
llvm-source-linux:
|
||||||
steps:
|
steps:
|
||||||
- restore_cache:
|
- restore_cache:
|
||||||
keys:
|
keys:
|
||||||
- llvm-source-8-v2
|
- llvm-source-8-v3
|
||||||
- run:
|
- run:
|
||||||
name: "Fetch LLVM source"
|
name: "Fetch LLVM source"
|
||||||
command: make llvm-source
|
command: make llvm-source
|
||||||
- save_cache:
|
- save_cache:
|
||||||
key: llvm-source-8-v2
|
key: llvm-source-8-v3
|
||||||
paths:
|
paths:
|
||||||
- llvm
|
- llvm
|
||||||
smoketest:
|
smoketest:
|
||||||
steps:
|
steps:
|
||||||
- smoketest-no-avr
|
- run: make smoketest
|
||||||
- run: tinygo build -size short -o test.elf -target=arduino examples/blinky1
|
|
||||||
- run: tinygo build -size short -o test.elf -target=digispark examples/blinky1
|
|
||||||
smoketest-no-avr:
|
smoketest-no-avr:
|
||||||
steps:
|
steps:
|
||||||
- run: tinygo build -size short -o test.elf -target=pca10040 examples/blinky1
|
- run: make smoketest-no-avr
|
||||||
- run: tinygo build -size short -o test.elf -target=pca10040 examples/blinky2
|
|
||||||
- run: tinygo build -o blinky2 examples/blinky2 # TODO: re-enable -size flag with MachO support
|
|
||||||
- run: tinygo build -size short -o test.elf -target=pca10040 examples/test
|
|
||||||
- run: tinygo build -size short -o test.elf -target=microbit examples/echo
|
|
||||||
- run: tinygo build -size short -o test.elf -target=nrf52840-mdk examples/blinky1
|
|
||||||
- run: tinygo build -size short -o test.elf -target=pca10031 examples/blinky1
|
|
||||||
- run: tinygo build -size short -o test.elf -target=bluepill examples/blinky1
|
|
||||||
- run: tinygo build -size short -o test.elf -target=reelboard examples/blinky1
|
|
||||||
- run: tinygo build -size short -o test.elf -target=reelboard examples/blinky2
|
|
||||||
- run: tinygo build -size short -o test.elf -target=pca10056 examples/blinky1
|
|
||||||
- run: tinygo build -size short -o test.elf -target=pca10056 examples/blinky2
|
|
||||||
- run: tinygo build -size short -o test.elf -target=itsybitsy-m0 examples/blinky1
|
|
||||||
- run: tinygo build -size short -o test.elf -target=circuitplay-express examples/blinky1
|
|
||||||
- run: tinygo build -size short -o test.elf -target=stm32f4disco examples/blinky1
|
|
||||||
- run: tinygo build -size short -o test.elf -target=stm32f4disco examples/blinky2
|
|
||||||
- run: tinygo build -size short -o test.elf -target=circuitplay-express examples/i2s
|
|
||||||
- run: tinygo build -o wasm.wasm -target=wasm examples/wasm/export
|
|
||||||
- run: tinygo build -o wasm.wasm -target=wasm examples/wasm/main
|
|
||||||
test-linux:
|
test-linux:
|
||||||
parameters:
|
|
||||||
llvm:
|
|
||||||
type: string
|
|
||||||
steps:
|
steps:
|
||||||
- checkout
|
- checkout
|
||||||
- submodules
|
- submodules
|
||||||
- apt-dependencies:
|
- apt-dependencies:
|
||||||
llvm: <<parameters.llvm>>
|
llvm: "-8"
|
||||||
- install-node
|
- install-node
|
||||||
- restore_cache:
|
- restore_cache:
|
||||||
keys:
|
keys:
|
||||||
- go-cache-{{ checksum "Gopkg.lock" }}-{{ .Environment.CIRCLE_PREVIOUS_BUILD_NUM }}
|
- go-cache-{{ checksum "Gopkg.lock" }}-{{ .Environment.CIRCLE_PREVIOUS_BUILD_NUM }}
|
||||||
- go-cache-{{ checksum "Gopkg.lock" }}
|
- go-cache-{{ checksum "Gopkg.lock" }}
|
||||||
- llvm-source-linux
|
- llvm-source-linux
|
||||||
- dep
|
|
||||||
- run: go install .
|
- run: go install .
|
||||||
- run: go test -v
|
- run: go test -v
|
||||||
- run: make gen-device -j4
|
- run: make gen-device -j4
|
||||||
@@ -137,7 +106,7 @@ commands:
|
|||||||
- llvm-source-linux
|
- llvm-source-linux
|
||||||
- restore_cache:
|
- restore_cache:
|
||||||
keys:
|
keys:
|
||||||
- llvm-build-8-linux-v4
|
- llvm-build-8-linux-v5
|
||||||
- run:
|
- run:
|
||||||
name: "Build LLVM"
|
name: "Build LLVM"
|
||||||
command: |
|
command: |
|
||||||
@@ -155,7 +124,7 @@ commands:
|
|||||||
make llvm-build
|
make llvm-build
|
||||||
fi
|
fi
|
||||||
- save_cache:
|
- save_cache:
|
||||||
key: llvm-build-8-linux-v4
|
key: llvm-build-8-linux-v5
|
||||||
paths:
|
paths:
|
||||||
llvm-build
|
llvm-build
|
||||||
- run:
|
- run:
|
||||||
@@ -164,7 +133,6 @@ commands:
|
|||||||
ln -s $PWD/llvm-build/bin/clang-8 /go/bin/clang-8
|
ln -s $PWD/llvm-build/bin/clang-8 /go/bin/clang-8
|
||||||
ln -s $PWD/llvm-build/bin/ld.lld /go/bin/ld.lld-8
|
ln -s $PWD/llvm-build/bin/ld.lld /go/bin/ld.lld-8
|
||||||
ln -s $PWD/llvm-build/bin/wasm-ld /go/bin/wasm-ld-8
|
ln -s $PWD/llvm-build/bin/wasm-ld /go/bin/wasm-ld-8
|
||||||
- dep
|
|
||||||
- run:
|
- run:
|
||||||
name: "Test TinyGo"
|
name: "Test TinyGo"
|
||||||
command: make test
|
command: make test
|
||||||
@@ -195,20 +163,23 @@ commands:
|
|||||||
- run:
|
- run:
|
||||||
name: "Install dependencies"
|
name: "Install dependencies"
|
||||||
command: |
|
command: |
|
||||||
HOMEBREW_NO_AUTO_UPDATE=1 brew install go dep qemu
|
curl https://dl.google.com/go/go1.12.5.darwin-amd64.tar.gz -o go1.12.5.darwin-amd64.tar.gz
|
||||||
|
sudo tar -C /usr/local -xzf go1.12.5.darwin-amd64.tar.gz
|
||||||
|
ln -s /usr/local/go/bin/go /usr/local/bin/go
|
||||||
|
HOMEBREW_NO_AUTO_UPDATE=1 brew install qemu
|
||||||
- restore_cache:
|
- restore_cache:
|
||||||
keys:
|
keys:
|
||||||
- llvm-source-8-macos-v2
|
- llvm-source-8-macos-v3
|
||||||
- run:
|
- run:
|
||||||
name: "Fetch LLVM source"
|
name: "Fetch LLVM source"
|
||||||
command: make llvm-source
|
command: make llvm-source
|
||||||
- save_cache:
|
- save_cache:
|
||||||
key: llvm-source-8-macos-v2
|
key: llvm-source-8-macos-v3
|
||||||
paths:
|
paths:
|
||||||
- llvm
|
- llvm
|
||||||
- restore_cache:
|
- restore_cache:
|
||||||
keys:
|
keys:
|
||||||
- llvm-build-8-macos-v3
|
- llvm-build-8-macos-v4
|
||||||
- run:
|
- run:
|
||||||
name: "Build LLVM"
|
name: "Build LLVM"
|
||||||
command: |
|
command: |
|
||||||
@@ -220,16 +191,13 @@ commands:
|
|||||||
make llvm-build
|
make llvm-build
|
||||||
fi
|
fi
|
||||||
- save_cache:
|
- save_cache:
|
||||||
key: llvm-build-8-macos-v3
|
key: llvm-build-8-macos-v4
|
||||||
paths:
|
paths:
|
||||||
llvm-build
|
llvm-build
|
||||||
- run:
|
- run:
|
||||||
name: "Create LLVM symlinks"
|
name: "Create LLVM symlinks"
|
||||||
command: |
|
command: |
|
||||||
ln -s $PWD/llvm-build/bin/clang-8 /usr/local/bin/clang-8
|
ln -s $PWD/llvm-build/bin/clang-8 /usr/local/bin/clang-8
|
||||||
- run:
|
|
||||||
name: "Install Go dependencies"
|
|
||||||
command: dep ensure --vendor-only
|
|
||||||
- run:
|
- run:
|
||||||
name: "Test TinyGo"
|
name: "Test TinyGo"
|
||||||
command: make test
|
command: make test
|
||||||
@@ -254,27 +222,21 @@ jobs:
|
|||||||
test-llvm8-go111:
|
test-llvm8-go111:
|
||||||
docker:
|
docker:
|
||||||
- image: circleci/golang:1.11
|
- image: circleci/golang:1.11
|
||||||
working_directory: /go/src/github.com/tinygo-org/tinygo
|
|
||||||
steps:
|
steps:
|
||||||
- test-linux:
|
- test-linux
|
||||||
llvm: "-8"
|
|
||||||
test-llvm8-go112:
|
test-llvm8-go112:
|
||||||
docker:
|
docker:
|
||||||
- image: circleci/golang:1.12
|
- image: circleci/golang:1.12
|
||||||
working_directory: /go/src/github.com/tinygo-org/tinygo
|
|
||||||
steps:
|
steps:
|
||||||
- test-linux:
|
- test-linux
|
||||||
llvm: "-8"
|
|
||||||
build-linux:
|
build-linux:
|
||||||
docker:
|
docker:
|
||||||
- image: circleci/golang:1.12
|
- image: circleci/golang:1.12
|
||||||
working_directory: /go/src/github.com/tinygo-org/tinygo
|
|
||||||
steps:
|
steps:
|
||||||
- build-linux
|
- build-linux
|
||||||
build-macos:
|
build-macos:
|
||||||
macos:
|
macos:
|
||||||
xcode: "10.1.0"
|
xcode: "10.1.0"
|
||||||
working_directory: ~/go/src/github.com/tinygo-org/tinygo
|
|
||||||
steps:
|
steps:
|
||||||
- build-macos
|
- build-macos
|
||||||
|
|
||||||
|
|||||||
@@ -1,3 +1,52 @@
|
|||||||
|
0.6.0
|
||||||
|
---
|
||||||
|
* **command line**
|
||||||
|
- some portability improvements
|
||||||
|
- make `$GOROOT` more robust and configurable
|
||||||
|
- check for Clang at the Homebrew install location as fallback
|
||||||
|
* **compiler driver**
|
||||||
|
- support multiple variations of LLVM commands, for non-Debian distributions
|
||||||
|
* **compiler**
|
||||||
|
- improve code quality in multiple ways
|
||||||
|
- make panic configurable, adding trap on panic
|
||||||
|
- refactor many internal parts of the compiler
|
||||||
|
- print all errors encountered during compilation
|
||||||
|
- implement calling function values of a named type
|
||||||
|
- implement returning values from blocking functions
|
||||||
|
- allow larger-than-int values to be sent across a channel
|
||||||
|
- implement complex arithmetic
|
||||||
|
- improve hashmap support
|
||||||
|
- add debuginfo for function arguments
|
||||||
|
- insert nil checks on stores (increasing code size)
|
||||||
|
- implement volatile operations as compiler builtins
|
||||||
|
- add `//go:inline` pragma
|
||||||
|
- add build tags for the Go stdlib version
|
||||||
|
* **cgo**
|
||||||
|
- implement `char`, `enum` and `void*` types
|
||||||
|
- support `#include` for builtin headers
|
||||||
|
- improve typedef/struct/enum support
|
||||||
|
- only include symbols that are necessary, for broader support
|
||||||
|
- mark external function args as `nocapture`
|
||||||
|
- implement support for some `#define` constants
|
||||||
|
- implement support for multiple CGo files in a single package
|
||||||
|
- **standard library**
|
||||||
|
- `machine`: remove microbit matrix (moved to drivers repository)
|
||||||
|
- `machine`: refactor pins to use `Pin` type instead of `GPIO`
|
||||||
|
- `runtime`: print more interface types on panic, including `error`
|
||||||
|
* **targets**
|
||||||
|
- `arm`: print an error on HardFault (including stack overflows)
|
||||||
|
- `atsamd21`: fix a bug in the ADC peripheral
|
||||||
|
- `atsamd21`: add support for I2S
|
||||||
|
- `feather-m0`: add support for this board
|
||||||
|
- `nrf51`: fix a bug in I2C
|
||||||
|
- `stm32f103xx`: fix a bug in I2C
|
||||||
|
- `syscall`: implement `Exit` on unix
|
||||||
|
- `trinket-m0`: add support for this board
|
||||||
|
- `wasm`: make _main_ example smaller
|
||||||
|
- `wasm`: don't cache wasm file in the server, for ease of debugging
|
||||||
|
- `wasm`: work around bug #41508 that caused a deadlock while linking
|
||||||
|
- `wasm`: add support for `js.FuncOf`
|
||||||
|
|
||||||
0.5.0
|
0.5.0
|
||||||
---
|
---
|
||||||
- **compiler driver**
|
- **compiler driver**
|
||||||
|
|||||||
+3
-3
@@ -46,7 +46,7 @@ RUN cd /go/src/github.com/tinygo-org/tinygo/ && \
|
|||||||
apt-get update && \
|
apt-get update && \
|
||||||
apt-get install -y apt-utils python3 make binutils-avr gcc-avr avr-libc && \
|
apt-get install -y apt-utils python3 make binutils-avr gcc-avr avr-libc && \
|
||||||
make gen-device-avr && \
|
make gen-device-avr && \
|
||||||
apt-get remove -y python3 make && \
|
apt-get remove -y python3 && \
|
||||||
apt-get autoremove -y && \
|
apt-get autoremove -y && \
|
||||||
apt-get clean
|
apt-get clean
|
||||||
|
|
||||||
@@ -64,7 +64,7 @@ RUN cd /go/src/github.com/tinygo-org/tinygo/ && \
|
|||||||
apt-get update && \
|
apt-get update && \
|
||||||
apt-get install -y apt-utils python3 make clang-8 && \
|
apt-get install -y apt-utils python3 make clang-8 && \
|
||||||
make gen-device-nrf && make gen-device-stm32 && \
|
make gen-device-nrf && make gen-device-stm32 && \
|
||||||
apt-get remove -y python3 make && \
|
apt-get remove -y python3 && \
|
||||||
apt-get autoremove -y && \
|
apt-get autoremove -y && \
|
||||||
apt-get clean
|
apt-get clean
|
||||||
|
|
||||||
@@ -79,7 +79,7 @@ RUN cd /go/src/github.com/tinygo-org/tinygo/ && \
|
|||||||
apt-get update && \
|
apt-get update && \
|
||||||
apt-get install -y apt-utils python3 make clang-8 binutils-avr gcc-avr avr-libc && \
|
apt-get install -y apt-utils python3 make clang-8 binutils-avr gcc-avr avr-libc && \
|
||||||
make gen-device && \
|
make gen-device && \
|
||||||
apt-get remove -y python3 make && \
|
apt-get remove -y python3 && \
|
||||||
apt-get autoremove -y && \
|
apt-get autoremove -y && \
|
||||||
apt-get clean
|
apt-get clean
|
||||||
|
|
||||||
|
|||||||
@@ -84,6 +84,45 @@ build/tinygo:
|
|||||||
test:
|
test:
|
||||||
CGO_CPPFLAGS="$(CGO_CPPFLAGS)" CGO_CXXFLAGS="$(CGO_CXXFLAGS)" CGO_LDFLAGS="$(CGO_LDFLAGS)" go test -v -tags byollvm .
|
CGO_CPPFLAGS="$(CGO_CPPFLAGS)" CGO_CXXFLAGS="$(CGO_CXXFLAGS)" CGO_LDFLAGS="$(CGO_LDFLAGS)" go test -v -tags byollvm .
|
||||||
|
|
||||||
|
.PHONY: smoketest smoketest-no-avr
|
||||||
|
smoketest: smoketest-no-avr
|
||||||
|
tinygo build -size short -o test.elf -target=arduino examples/blinky1
|
||||||
|
tinygo build -size short -o test.elf -target=digispark examples/blinky1
|
||||||
|
smoketest-no-avr:
|
||||||
|
# test all examples
|
||||||
|
tinygo build -size short -o test.elf -target=pca10040 examples/blinky1
|
||||||
|
tinygo build -size short -o test.elf -target=pca10040 examples/adc
|
||||||
|
tinygo build -size short -o test.elf -target=pca10040 examples/blinkm
|
||||||
|
tinygo build -size short -o test.elf -target=pca10040 examples/blinky2
|
||||||
|
tinygo build -size short -o test.elf -target=pca10040 examples/button
|
||||||
|
tinygo build -size short -o test.elf -target=pca10040 examples/button2
|
||||||
|
tinygo build -size short -o test.elf -target=pca10040 examples/echo
|
||||||
|
tinygo build -size short -o test.elf -target=circuitplay-express examples/i2s
|
||||||
|
tinygo build -size short -o test.elf -target=pca10040 examples/mcp3008
|
||||||
|
tinygo build -size short -o test.elf -target=microbit examples/microbit-blink
|
||||||
|
tinygo build -size short -o test.elf -target=pca10040 examples/pwm
|
||||||
|
tinygo build -size short -o test.elf -target=pca10040 examples/serial
|
||||||
|
tinygo build -size short -o test.elf -target=pca10040 examples/test
|
||||||
|
# test all targets/boards
|
||||||
|
tinygo build -o test.elf examples/blinky2 # TODO: re-enable -size flag with MachO support
|
||||||
|
tinygo build -size short -o test.elf -target=microbit examples/echo
|
||||||
|
tinygo build -size short -o test.elf -target=nrf52840-mdk examples/blinky1
|
||||||
|
tinygo build -size short -o test.elf -target=pca10031 examples/blinky1
|
||||||
|
tinygo build -size short -o test.elf -target=bluepill examples/blinky1
|
||||||
|
tinygo build -size short -o test.elf -target=reelboard examples/blinky1
|
||||||
|
tinygo build -size short -o test.elf -target=reelboard examples/blinky2
|
||||||
|
tinygo build -size short -o test.elf -target=pca10056 examples/blinky1
|
||||||
|
tinygo build -size short -o test.elf -target=pca10056 examples/blinky2
|
||||||
|
tinygo build -size short -o test.elf -target=itsybitsy-m0 examples/blinky1
|
||||||
|
tinygo build -size short -o test.elf -target=feather-m0 examples/blinky1
|
||||||
|
tinygo build -size short -o test.elf -target=trinket-m0 examples/blinky1
|
||||||
|
tinygo build -size short -o test.elf -target=circuitplay-express examples/blinky1
|
||||||
|
tinygo build -size short -o test.elf -target=stm32f4disco examples/blinky1
|
||||||
|
tinygo build -size short -o test.elf -target=stm32f4disco examples/blinky2
|
||||||
|
tinygo build -size short -o test.elf -target=circuitplay-express examples/i2s
|
||||||
|
tinygo build -o wasm.wasm -target=wasm examples/wasm/export
|
||||||
|
tinygo build -o wasm.wasm -target=wasm examples/wasm/main
|
||||||
|
|
||||||
release: build/tinygo gen-device
|
release: build/tinygo gen-device
|
||||||
@mkdir -p build/release/tinygo/bin
|
@mkdir -p build/release/tinygo/bin
|
||||||
@mkdir -p build/release/tinygo/lib/clang/include
|
@mkdir -p build/release/tinygo/lib/clang/include
|
||||||
|
|||||||
@@ -17,8 +17,8 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
led := machine.GPIO{machine.LED}
|
led := machine.LED
|
||||||
led.Configure(machine.GPIOConfig{Mode: machine.GPIO_OUTPUT})
|
led.Configure(machine.PinConfig{Mode: machine.PinOutput})
|
||||||
for {
|
for {
|
||||||
led.Low()
|
led.Low()
|
||||||
time.Sleep(time.Millisecond * 1000)
|
time.Sleep(time.Millisecond * 1000)
|
||||||
@@ -43,13 +43,16 @@ See the [getting started instructions](https://tinygo.org/getting-started/) for
|
|||||||
|
|
||||||
You can compile TinyGo programs for microcontrollers, WebAssembly and Linux.
|
You can compile TinyGo programs for microcontrollers, WebAssembly and Linux.
|
||||||
|
|
||||||
The following microcontroller boards are currently supported:
|
The following 14 microcontroller boards are currently supported:
|
||||||
|
|
||||||
* [Adafruit Circuit Playground Express](https://www.adafruit.com/product/3333)
|
* [Adafruit Circuit Playground Express](https://www.adafruit.com/product/3333)
|
||||||
|
* [Adafruit Feather M0](https://www.adafruit.com/product/2772)
|
||||||
* [Adafruit ItsyBitsy M0](https://www.adafruit.com/product/3727)
|
* [Adafruit ItsyBitsy M0](https://www.adafruit.com/product/3727)
|
||||||
|
* [Adafruit Trinket M0](https://www.adafruit.com/product/3500)
|
||||||
* [Arduino Uno](https://store.arduino.cc/arduino-uno-rev3)
|
* [Arduino Uno](https://store.arduino.cc/arduino-uno-rev3)
|
||||||
* [BBC:Microbit](https://microbit.org/)
|
* [BBC micro:bit](https://microbit.org/)
|
||||||
* [ST Micro STM32F103XX "Bluepill"](http://wiki.stm32duino.com/index.php?title=Blue_Pill)
|
* [ST Micro STM32F103XX "Bluepill"](http://wiki.stm32duino.com/index.php?title=Blue_Pill)
|
||||||
|
* [ST Micro STM32F407 "Discovery"](https://www.st.com/en/evaluation-tools/stm32f4discovery.html)
|
||||||
* [Digispark](http://digistump.com/products/1)
|
* [Digispark](http://digistump.com/products/1)
|
||||||
* [Nordic Semiconductor PCA10031](https://www.nordicsemi.com/eng/Products/nRF51-Dongle)
|
* [Nordic Semiconductor PCA10031](https://www.nordicsemi.com/eng/Products/nRF51-Dongle)
|
||||||
* [Nordic Semiconductor PCA10040](https://www.nordicsemi.com/eng/Products/Bluetooth-low-energy/nRF52-DK)
|
* [Nordic Semiconductor PCA10040](https://www.nordicsemi.com/eng/Products/Bluetooth-low-energy/nRF52-DK)
|
||||||
|
|||||||
+59
@@ -35,6 +35,7 @@ type cgoPackage struct {
|
|||||||
globals map[string]globalInfo
|
globals map[string]globalInfo
|
||||||
typedefs map[string]*typedefInfo
|
typedefs map[string]*typedefInfo
|
||||||
elaboratedTypes map[string]*elaboratedTypeInfo
|
elaboratedTypes map[string]*elaboratedTypeInfo
|
||||||
|
enums map[string]enumInfo
|
||||||
}
|
}
|
||||||
|
|
||||||
// constantInfo stores some information about a CGo constant found by libclang
|
// constantInfo stores some information about a CGo constant found by libclang
|
||||||
@@ -71,6 +72,12 @@ type elaboratedTypeInfo struct {
|
|||||||
pos token.Pos
|
pos token.Pos
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// enumInfo contains information about an enum in the C.
|
||||||
|
type enumInfo struct {
|
||||||
|
typeExpr ast.Expr
|
||||||
|
pos token.Pos
|
||||||
|
}
|
||||||
|
|
||||||
// globalInfo contains information about a declared global variable in C.
|
// globalInfo contains information about a declared global variable in C.
|
||||||
type globalInfo struct {
|
type globalInfo struct {
|
||||||
typeExpr ast.Expr
|
typeExpr ast.Expr
|
||||||
@@ -140,6 +147,7 @@ func Process(files []*ast.File, dir string, fset *token.FileSet, cflags []string
|
|||||||
globals: map[string]globalInfo{},
|
globals: map[string]globalInfo{},
|
||||||
typedefs: map[string]*typedefInfo{},
|
typedefs: map[string]*typedefInfo{},
|
||||||
elaboratedTypes: map[string]*elaboratedTypeInfo{},
|
elaboratedTypes: map[string]*elaboratedTypeInfo{},
|
||||||
|
enums: map[string]enumInfo{},
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add a new location for the following file.
|
// Add a new location for the following file.
|
||||||
@@ -243,6 +251,9 @@ func Process(files []*ast.File, dir string, fset *token.FileSet, cflags []string
|
|||||||
// Add elaborated types for C structs and unions.
|
// Add elaborated types for C structs and unions.
|
||||||
p.addElaboratedTypes()
|
p.addElaboratedTypes()
|
||||||
|
|
||||||
|
// Add enum types and enum constants for C enums.
|
||||||
|
p.addEnumTypes()
|
||||||
|
|
||||||
// Patch the AST to use the declared types and functions.
|
// Patch the AST to use the declared types and functions.
|
||||||
for _, f := range files {
|
for _, f := range files {
|
||||||
astutil.Apply(f, p.walker, nil)
|
astutil.Apply(f, p.walker, nil)
|
||||||
@@ -574,6 +585,54 @@ func (p *cgoPackage) addElaboratedTypes() {
|
|||||||
p.generated.Decls = append(p.generated.Decls, gen)
|
p.generated.Decls = append(p.generated.Decls, gen)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// addEnumTypes adds C enums to the AST. For example, the following C code:
|
||||||
|
//
|
||||||
|
// enum option {
|
||||||
|
// optionA,
|
||||||
|
// optionB = 5,
|
||||||
|
// };
|
||||||
|
//
|
||||||
|
// is translated to the following Go code equivalent:
|
||||||
|
//
|
||||||
|
// type C.enum_option int32
|
||||||
|
//
|
||||||
|
// The constants are treated just like macros so are inserted into the AST by
|
||||||
|
// addConstDecls.
|
||||||
|
// See also: https://en.cppreference.com/w/c/language/enum
|
||||||
|
func (p *cgoPackage) addEnumTypes() {
|
||||||
|
if len(p.enums) == 0 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
gen := &ast.GenDecl{
|
||||||
|
TokPos: token.NoPos,
|
||||||
|
Tok: token.TYPE,
|
||||||
|
}
|
||||||
|
names := make([]string, 0, len(p.enums))
|
||||||
|
for name := range p.enums {
|
||||||
|
names = append(names, name)
|
||||||
|
}
|
||||||
|
sort.Strings(names)
|
||||||
|
for _, name := range names {
|
||||||
|
typ := p.enums[name]
|
||||||
|
typeName := "C.enum_" + name
|
||||||
|
obj := &ast.Object{
|
||||||
|
Kind: ast.Typ,
|
||||||
|
Name: typeName,
|
||||||
|
}
|
||||||
|
typeSpec := &ast.TypeSpec{
|
||||||
|
Name: &ast.Ident{
|
||||||
|
NamePos: typ.pos,
|
||||||
|
Name: typeName,
|
||||||
|
Obj: obj,
|
||||||
|
},
|
||||||
|
Type: typ.typeExpr,
|
||||||
|
}
|
||||||
|
obj.Decl = typeSpec
|
||||||
|
gen.Specs = append(gen.Specs, typeSpec)
|
||||||
|
}
|
||||||
|
p.generated.Decls = append(p.generated.Decls, gen)
|
||||||
|
}
|
||||||
|
|
||||||
// findMissingCGoNames traverses the AST and finds all C.something names. Only
|
// findMissingCGoNames traverses the AST and finds all C.something names. Only
|
||||||
// these symbols are extracted from the parsed C AST and converted to the Go
|
// these symbols are extracted from the parsed C AST and converted to the Go
|
||||||
// equivalent.
|
// equivalent.
|
||||||
|
|||||||
+51
-1
@@ -49,9 +49,12 @@ GoCXCursor tinygo_clang_Cursor_getArgument(GoCXCursor c, unsigned i);
|
|||||||
CXSourceLocation tinygo_clang_getCursorLocation(GoCXCursor c);
|
CXSourceLocation tinygo_clang_getCursorLocation(GoCXCursor c);
|
||||||
CXSourceRange tinygo_clang_getCursorExtent(GoCXCursor c);
|
CXSourceRange tinygo_clang_getCursorExtent(GoCXCursor c);
|
||||||
CXTranslationUnit tinygo_clang_Cursor_getTranslationUnit(GoCXCursor c);
|
CXTranslationUnit tinygo_clang_Cursor_getTranslationUnit(GoCXCursor c);
|
||||||
|
long long tinygo_clang_getEnumConstantDeclValue(GoCXCursor c);
|
||||||
|
CXType tinygo_clang_getEnumDeclIntegerType(GoCXCursor c);
|
||||||
|
|
||||||
int tinygo_clang_globals_visitor(GoCXCursor c, GoCXCursor parent, CXClientData client_data);
|
int tinygo_clang_globals_visitor(GoCXCursor c, GoCXCursor parent, CXClientData client_data);
|
||||||
int tinygo_clang_struct_visitor(GoCXCursor c, GoCXCursor parent, CXClientData client_data);
|
int tinygo_clang_struct_visitor(GoCXCursor c, GoCXCursor parent, CXClientData client_data);
|
||||||
|
int tinygo_clang_enum_visitor(GoCXCursor c, GoCXCursor parent, CXClientData client_data);
|
||||||
*/
|
*/
|
||||||
import "C"
|
import "C"
|
||||||
|
|
||||||
@@ -501,6 +504,8 @@ func (p *cgoPackage) makeASTType(typ C.CXType, pos token.Pos) ast.Expr {
|
|||||||
switch underlying.kind {
|
switch underlying.kind {
|
||||||
case C.CXType_Record:
|
case C.CXType_Record:
|
||||||
return p.makeASTType(underlying, pos)
|
return p.makeASTType(underlying, pos)
|
||||||
|
case C.CXType_Enum:
|
||||||
|
return p.makeASTType(underlying, pos)
|
||||||
default:
|
default:
|
||||||
panic("unknown elaborated type")
|
panic("unknown elaborated type")
|
||||||
}
|
}
|
||||||
@@ -580,11 +585,43 @@ func (p *cgoPackage) makeASTType(typ C.CXType, pos token.Pos) ast.Expr {
|
|||||||
NamePos: pos,
|
NamePos: pos,
|
||||||
Name: "C." + cgoName,
|
Name: "C." + cgoName,
|
||||||
}
|
}
|
||||||
|
case C.CXType_Enum:
|
||||||
|
cursor := C.tinygo_clang_getTypeDeclaration(typ)
|
||||||
|
name := getString(C.tinygo_clang_getCursorSpelling(cursor))
|
||||||
|
underlying := C.tinygo_clang_getEnumDeclIntegerType(cursor)
|
||||||
|
if name == "" {
|
||||||
|
// anonymous enum
|
||||||
|
ref := storedRefs.Put(p)
|
||||||
|
defer storedRefs.Remove(ref)
|
||||||
|
C.tinygo_clang_visitChildren(cursor, C.CXCursorVisitor(C.tinygo_clang_enum_visitor), C.CXClientData(ref))
|
||||||
|
return p.makeASTType(underlying, pos)
|
||||||
|
} else {
|
||||||
|
// named enum
|
||||||
|
if _, ok := p.enums[name]; !ok {
|
||||||
|
ref := storedRefs.Put(p)
|
||||||
|
defer storedRefs.Remove(ref)
|
||||||
|
C.tinygo_clang_visitChildren(cursor, C.CXCursorVisitor(C.tinygo_clang_enum_visitor), C.CXClientData(ref))
|
||||||
|
p.enums[name] = enumInfo{
|
||||||
|
typeExpr: p.makeASTType(underlying, pos),
|
||||||
|
pos: pos,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return &ast.Ident{
|
||||||
|
NamePos: pos,
|
||||||
|
Name: "C.enum_" + name,
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if typeName == "" {
|
if typeName == "" {
|
||||||
|
// Report this as an error.
|
||||||
|
spelling := getString(C.clang_getTypeSpelling(typ))
|
||||||
|
p.errors = append(p.errors, scanner.Error{
|
||||||
|
Pos: p.fset.PositionFor(pos, true),
|
||||||
|
Msg: fmt.Sprintf("unknown C type: %v (libclang type kind %d)", spelling, typ.kind),
|
||||||
|
})
|
||||||
// Fallback, probably incorrect but at least the error points to an odd
|
// Fallback, probably incorrect but at least the error points to an odd
|
||||||
// type name.
|
// type name.
|
||||||
typeName = "C." + getString(C.clang_getTypeSpelling(typ))
|
typeName = "C." + spelling
|
||||||
}
|
}
|
||||||
return &ast.Ident{
|
return &ast.Ident{
|
||||||
NamePos: pos,
|
NamePos: pos,
|
||||||
@@ -622,3 +659,16 @@ func tinygo_clang_struct_visitor(c, parent C.GoCXCursor, client_data C.CXClientD
|
|||||||
fieldList.List = append(fieldList.List, field)
|
fieldList.List = append(fieldList.List, field)
|
||||||
return C.CXChildVisit_Continue
|
return C.CXChildVisit_Continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//export tinygo_clang_enum_visitor
|
||||||
|
func tinygo_clang_enum_visitor(c, parent C.GoCXCursor, client_data C.CXClientData) C.int {
|
||||||
|
p := storedRefs.Get(unsafe.Pointer(client_data)).(*cgoPackage)
|
||||||
|
name := getString(C.tinygo_clang_getCursorSpelling(c))
|
||||||
|
pos := p.getCursorPosition(c)
|
||||||
|
value := C.tinygo_clang_getEnumConstantDeclValue(c)
|
||||||
|
p.constants[name] = constantInfo{
|
||||||
|
expr: &ast.BasicLit{pos, token.INT, strconv.FormatInt(int64(value), 10)},
|
||||||
|
pos: pos,
|
||||||
|
}
|
||||||
|
return C.CXChildVisit_Continue
|
||||||
|
}
|
||||||
|
|||||||
@@ -56,3 +56,11 @@ CXSourceRange tinygo_clang_getCursorExtent(CXCursor c) {
|
|||||||
CXTranslationUnit tinygo_clang_Cursor_getTranslationUnit(CXCursor c) {
|
CXTranslationUnit tinygo_clang_Cursor_getTranslationUnit(CXCursor c) {
|
||||||
return clang_Cursor_getTranslationUnit(c);
|
return clang_Cursor_getTranslationUnit(c);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
long long tinygo_clang_getEnumConstantDeclValue(CXCursor c) {
|
||||||
|
return clang_getEnumConstantDeclValue(c);
|
||||||
|
}
|
||||||
|
|
||||||
|
CXType tinygo_clang_getEnumDeclIntegerType(CXCursor c) {
|
||||||
|
return clang_getEnumDeclIntegerType(c);
|
||||||
|
}
|
||||||
|
|||||||
+11
@@ -4,6 +4,7 @@ import (
|
|||||||
"errors"
|
"errors"
|
||||||
"os"
|
"os"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
|
"runtime"
|
||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -15,6 +16,16 @@ var commands = map[string][]string{
|
|||||||
"wasm-ld": {"wasm-ld-8", "wasm-ld"},
|
"wasm-ld": {"wasm-ld-8", "wasm-ld"},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
// Add the path to a Homebrew-installed LLVM 8 for ease of use (no need to
|
||||||
|
// manually set $PATH).
|
||||||
|
if runtime.GOOS == "darwin" {
|
||||||
|
commands["clang"] = append(commands["clang"], "/usr/local/opt/llvm/bin/clang-8")
|
||||||
|
commands["ld.lld"] = append(commands["ld.lld"], "/usr/local/opt/llvm/bin/ld.lld")
|
||||||
|
commands["wasm-ld"] = append(commands["wasm-ld"], "/usr/local/opt/llvm/bin/wasm-ld")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func execCommand(cmdNames []string, args ...string) error {
|
func execCommand(cmdNames []string, args ...string) error {
|
||||||
for _, cmdName := range cmdNames {
|
for _, cmdName := range cmdNames {
|
||||||
cmd := exec.Command(cmdName, args...)
|
cmd := exec.Command(cmdName, args...)
|
||||||
|
|||||||
+8
-3
@@ -42,7 +42,7 @@ func (c *Compiler) emitLookupBoundsCheck(frame *Frame, arrayLen, index llvm.Valu
|
|||||||
|
|
||||||
// Fail: this is a nil pointer, exit with a panic.
|
// Fail: this is a nil pointer, exit with a panic.
|
||||||
c.builder.SetInsertPointAtEnd(faultBlock)
|
c.builder.SetInsertPointAtEnd(faultBlock)
|
||||||
c.createRuntimeCall("lookuppanic", nil, "")
|
c.createRuntimeCall("lookupPanic", nil, "")
|
||||||
c.builder.CreateUnreachable()
|
c.builder.CreateUnreachable()
|
||||||
|
|
||||||
// Ok: this is a valid pointer.
|
// Ok: this is a valid pointer.
|
||||||
@@ -103,7 +103,7 @@ func (c *Compiler) emitSliceBoundsCheck(frame *Frame, capacity, low, high llvm.V
|
|||||||
|
|
||||||
// Fail: this is a nil pointer, exit with a panic.
|
// Fail: this is a nil pointer, exit with a panic.
|
||||||
c.builder.SetInsertPointAtEnd(faultBlock)
|
c.builder.SetInsertPointAtEnd(faultBlock)
|
||||||
c.createRuntimeCall("slicepanic", nil, "")
|
c.createRuntimeCall("slicePanic", nil, "")
|
||||||
c.builder.CreateUnreachable()
|
c.builder.CreateUnreachable()
|
||||||
|
|
||||||
// Ok: this is a valid pointer.
|
// Ok: this is a valid pointer.
|
||||||
@@ -114,6 +114,11 @@ func (c *Compiler) emitSliceBoundsCheck(frame *Frame, capacity, low, high llvm.V
|
|||||||
// has no effect in well-behaved programs, but makes sure no uncaught nil
|
// has no effect in well-behaved programs, but makes sure no uncaught nil
|
||||||
// pointer dereferences exist in valid Go code.
|
// pointer dereferences exist in valid Go code.
|
||||||
func (c *Compiler) emitNilCheck(frame *Frame, ptr llvm.Value, blockPrefix string) {
|
func (c *Compiler) emitNilCheck(frame *Frame, ptr llvm.Value, blockPrefix string) {
|
||||||
|
// Check whether we need to emit this check at all.
|
||||||
|
if !ptr.IsAGlobalValue().IsNil() {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
// Check whether this is a nil pointer.
|
// Check whether this is a nil pointer.
|
||||||
faultBlock := c.ctx.AddBasicBlock(frame.fn.LLVMFn, blockPrefix+".nil")
|
faultBlock := c.ctx.AddBasicBlock(frame.fn.LLVMFn, blockPrefix+".nil")
|
||||||
nextBlock := c.ctx.AddBasicBlock(frame.fn.LLVMFn, blockPrefix+".next")
|
nextBlock := c.ctx.AddBasicBlock(frame.fn.LLVMFn, blockPrefix+".next")
|
||||||
@@ -141,7 +146,7 @@ func (c *Compiler) emitNilCheck(frame *Frame, ptr llvm.Value, blockPrefix string
|
|||||||
|
|
||||||
// Fail: this is a nil pointer, exit with a panic.
|
// Fail: this is a nil pointer, exit with a panic.
|
||||||
c.builder.SetInsertPointAtEnd(faultBlock)
|
c.builder.SetInsertPointAtEnd(faultBlock)
|
||||||
c.createRuntimeCall("nilpanic", nil, "")
|
c.createRuntimeCall("nilPanic", nil, "")
|
||||||
c.builder.CreateUnreachable()
|
c.builder.CreateUnreachable()
|
||||||
|
|
||||||
// Ok: this is a valid pointer.
|
// Ok: this is a valid pointer.
|
||||||
|
|||||||
+13
-19
@@ -23,47 +23,41 @@ func (c *Compiler) emitMakeChan(expr *ssa.MakeChan) (llvm.Value, error) {
|
|||||||
// emitChanSend emits a pseudo chan send operation. It is lowered to the actual
|
// emitChanSend emits a pseudo chan send operation. It is lowered to the actual
|
||||||
// channel send operation during goroutine lowering.
|
// channel send operation during goroutine lowering.
|
||||||
func (c *Compiler) emitChanSend(frame *Frame, instr *ssa.Send) {
|
func (c *Compiler) emitChanSend(frame *Frame, instr *ssa.Send) {
|
||||||
valueType := c.getLLVMType(instr.X.Type())
|
|
||||||
ch := c.getValue(frame, instr.Chan)
|
ch := c.getValue(frame, instr.Chan)
|
||||||
chanValue := c.getValue(frame, instr.X)
|
chanValue := c.getValue(frame, instr.X)
|
||||||
valueSize := llvm.ConstInt(c.uintptrType, c.targetData.TypeAllocSize(chanValue.Type()), false)
|
|
||||||
coroutine := c.createRuntimeCall("getCoroutine", nil, "")
|
|
||||||
|
|
||||||
// store value-to-send
|
// store value-to-send
|
||||||
c.builder.SetInsertPointBefore(coroutine.InstructionParent().Parent().EntryBasicBlock().FirstInstruction())
|
valueType := c.getLLVMType(instr.X.Type())
|
||||||
valueAlloca := c.builder.CreateAlloca(valueType, "chan.value")
|
valueAlloca, valueAllocaCast, valueAllocaSize := c.createTemporaryAlloca(valueType, "chan.value")
|
||||||
c.builder.SetInsertPointBefore(coroutine)
|
|
||||||
c.builder.SetInsertPointAtEnd(coroutine.InstructionParent())
|
|
||||||
c.builder.CreateStore(chanValue, valueAlloca)
|
c.builder.CreateStore(chanValue, valueAlloca)
|
||||||
valueAllocaCast := c.builder.CreateBitCast(valueAlloca, c.i8ptrType, "chan.value.i8ptr")
|
|
||||||
|
|
||||||
// Do the send.
|
// Do the send.
|
||||||
|
coroutine := c.createRuntimeCall("getCoroutine", nil, "")
|
||||||
|
valueSize := llvm.ConstInt(c.uintptrType, c.targetData.TypeAllocSize(chanValue.Type()), false)
|
||||||
c.createRuntimeCall("chanSend", []llvm.Value{coroutine, ch, valueAllocaCast, valueSize}, "")
|
c.createRuntimeCall("chanSend", []llvm.Value{coroutine, ch, valueAllocaCast, valueSize}, "")
|
||||||
|
|
||||||
// Make sure CoroSplit includes the alloca in the coroutine frame.
|
// End the lifetime of the alloca.
|
||||||
// This is a bit dirty, but it works (at least in LLVM 8).
|
// This also works around a bug in CoroSplit, at least in LLVM 8:
|
||||||
valueSizeI64 := llvm.ConstInt(c.ctx.Int64Type(), c.targetData.TypeAllocSize(chanValue.Type()), false)
|
// https://bugs.llvm.org/show_bug.cgi?id=41742
|
||||||
c.builder.CreateCall(c.getLifetimeEndFunc(), []llvm.Value{valueSizeI64, valueAllocaCast}, "")
|
c.emitLifetimeEnd(valueAllocaCast, valueAllocaSize)
|
||||||
}
|
}
|
||||||
|
|
||||||
// emitChanRecv emits a pseudo chan receive operation. It is lowered to the
|
// emitChanRecv emits a pseudo chan receive operation. It is lowered to the
|
||||||
// actual channel receive operation during goroutine lowering.
|
// actual channel receive operation during goroutine lowering.
|
||||||
func (c *Compiler) emitChanRecv(frame *Frame, unop *ssa.UnOp) llvm.Value {
|
func (c *Compiler) emitChanRecv(frame *Frame, unop *ssa.UnOp) llvm.Value {
|
||||||
valueType := c.getLLVMType(unop.X.Type().(*types.Chan).Elem())
|
valueType := c.getLLVMType(unop.X.Type().(*types.Chan).Elem())
|
||||||
valueSize := llvm.ConstInt(c.uintptrType, c.targetData.TypeAllocSize(valueType), false)
|
|
||||||
ch := c.getValue(frame, unop.X)
|
ch := c.getValue(frame, unop.X)
|
||||||
coroutine := c.createRuntimeCall("getCoroutine", nil, "")
|
|
||||||
|
|
||||||
// Allocate memory to receive into.
|
// Allocate memory to receive into.
|
||||||
c.builder.SetInsertPointBefore(coroutine.InstructionParent().Parent().EntryBasicBlock().FirstInstruction())
|
valueAlloca, valueAllocaCast, valueAllocaSize := c.createTemporaryAlloca(valueType, "chan.value")
|
||||||
valueAlloca := c.builder.CreateAlloca(valueType, "chan.value")
|
|
||||||
c.builder.SetInsertPointBefore(coroutine)
|
|
||||||
c.builder.SetInsertPointAtEnd(coroutine.InstructionParent())
|
|
||||||
valueAllocaCast := c.builder.CreateBitCast(valueAlloca, c.i8ptrType, "chan.value.i8ptr")
|
|
||||||
|
|
||||||
// Do the receive.
|
// Do the receive.
|
||||||
|
coroutine := c.createRuntimeCall("getCoroutine", nil, "")
|
||||||
|
valueSize := llvm.ConstInt(c.uintptrType, c.targetData.TypeAllocSize(valueType), false)
|
||||||
c.createRuntimeCall("chanRecv", []llvm.Value{coroutine, ch, valueAllocaCast, valueSize}, "")
|
c.createRuntimeCall("chanRecv", []llvm.Value{coroutine, ch, valueAllocaCast, valueSize}, "")
|
||||||
received := c.builder.CreateLoad(valueAlloca, "chan.received")
|
received := c.builder.CreateLoad(valueAlloca, "chan.received")
|
||||||
|
c.emitLifetimeEnd(valueAllocaCast, valueAllocaSize)
|
||||||
|
|
||||||
if unop.CommaOk {
|
if unop.CommaOk {
|
||||||
commaOk := c.createRuntimeCall("getTaskPromiseData", []llvm.Value{coroutine}, "chan.commaOk.wide")
|
commaOk := c.createRuntimeCall("getTaskPromiseData", []llvm.Value{coroutine}, "chan.commaOk.wide")
|
||||||
commaOk = c.builder.CreateTrunc(commaOk, c.ctx.Int1Type(), "chan.commaOk")
|
commaOk = c.builder.CreateTrunc(commaOk, c.ctx.Int1Type(), "chan.commaOk")
|
||||||
|
|||||||
+27
-15
@@ -30,6 +30,7 @@ func init() {
|
|||||||
type Config struct {
|
type Config struct {
|
||||||
Triple string // LLVM target triple, e.g. x86_64-unknown-linux-gnu (empty string means default)
|
Triple string // LLVM target triple, e.g. x86_64-unknown-linux-gnu (empty string means default)
|
||||||
CPU string // LLVM CPU name, e.g. atmega328p (empty string means default)
|
CPU string // LLVM CPU name, e.g. atmega328p (empty string means default)
|
||||||
|
Features []string // LLVM CPU features
|
||||||
GOOS string //
|
GOOS string //
|
||||||
GOARCH string //
|
GOARCH string //
|
||||||
GC string // garbage collection strategy
|
GC string // garbage collection strategy
|
||||||
@@ -101,7 +102,11 @@ func NewCompiler(pkgName string, config Config) (*Compiler, error) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
c.machine = target.CreateTargetMachine(config.Triple, config.CPU, "", llvm.CodeGenLevelDefault, llvm.RelocStatic, llvm.CodeModelDefault)
|
features := ""
|
||||||
|
if len(config.Features) > 0 {
|
||||||
|
features = strings.Join(config.Features, `,`)
|
||||||
|
}
|
||||||
|
c.machine = target.CreateTargetMachine(config.Triple, config.CPU, features, llvm.CodeGenLevelDefault, llvm.RelocStatic, llvm.CodeModelDefault)
|
||||||
c.targetData = c.machine.CreateTargetData()
|
c.targetData = c.machine.CreateTargetData()
|
||||||
|
|
||||||
c.ctx = llvm.NewContext()
|
c.ctx = llvm.NewContext()
|
||||||
@@ -820,6 +825,9 @@ func (c *Compiler) parseFunc(frame *Frame) {
|
|||||||
if c.DumpSSA {
|
if c.DumpSSA {
|
||||||
fmt.Printf("\nfunc %s:\n", frame.fn.Function)
|
fmt.Printf("\nfunc %s:\n", frame.fn.Function)
|
||||||
}
|
}
|
||||||
|
if !frame.fn.LLVMFn.IsDeclaration() {
|
||||||
|
panic("function is already defined: " + frame.fn.LLVMFn.Name())
|
||||||
|
}
|
||||||
if !frame.fn.IsExported() {
|
if !frame.fn.IsExported() {
|
||||||
frame.fn.LLVMFn.SetLinkage(llvm.InternalLinkage)
|
frame.fn.LLVMFn.SetLinkage(llvm.InternalLinkage)
|
||||||
frame.fn.LLVMFn.SetUnnamedAddr(true)
|
frame.fn.LLVMFn.SetUnnamedAddr(true)
|
||||||
@@ -1369,7 +1377,6 @@ func (c *Compiler) parseExpr(frame *Frame, expr ssa.Value) (llvm.Value, error) {
|
|||||||
switch expr := expr.(type) {
|
switch expr := expr.(type) {
|
||||||
case *ssa.Alloc:
|
case *ssa.Alloc:
|
||||||
typ := c.getLLVMType(expr.Type().Underlying().(*types.Pointer).Elem())
|
typ := c.getLLVMType(expr.Type().Underlying().(*types.Pointer).Elem())
|
||||||
var buf llvm.Value
|
|
||||||
if expr.Heap {
|
if expr.Heap {
|
||||||
size := c.targetData.TypeAllocSize(typ)
|
size := c.targetData.TypeAllocSize(typ)
|
||||||
// Calculate ^uintptr(0)
|
// Calculate ^uintptr(0)
|
||||||
@@ -1380,15 +1387,16 @@ func (c *Compiler) parseExpr(frame *Frame, expr ssa.Value) (llvm.Value, error) {
|
|||||||
}
|
}
|
||||||
// TODO: escape analysis
|
// TODO: escape analysis
|
||||||
sizeValue := llvm.ConstInt(c.uintptrType, size, false)
|
sizeValue := llvm.ConstInt(c.uintptrType, size, false)
|
||||||
buf = c.createRuntimeCall("alloc", []llvm.Value{sizeValue}, expr.Comment)
|
buf := c.createRuntimeCall("alloc", []llvm.Value{sizeValue}, expr.Comment)
|
||||||
buf = c.builder.CreateBitCast(buf, llvm.PointerType(typ, 0), "")
|
buf = c.builder.CreateBitCast(buf, llvm.PointerType(typ, 0), "")
|
||||||
|
return buf, nil
|
||||||
} else {
|
} else {
|
||||||
buf = c.builder.CreateAlloca(typ, expr.Comment)
|
buf := c.createEntryBlockAlloca(typ, expr.Comment)
|
||||||
if c.targetData.TypeAllocSize(typ) != 0 {
|
if c.targetData.TypeAllocSize(typ) != 0 {
|
||||||
c.builder.CreateStore(c.getZeroValue(typ), buf) // zero-initialize var
|
c.builder.CreateStore(c.getZeroValue(typ), buf) // zero-initialize var
|
||||||
}
|
}
|
||||||
|
return buf, nil
|
||||||
}
|
}
|
||||||
return buf, nil
|
|
||||||
case *ssa.BinOp:
|
case *ssa.BinOp:
|
||||||
x := c.getValue(frame, expr.X)
|
x := c.getValue(frame, expr.X)
|
||||||
y := c.getValue(frame, expr.Y)
|
y := c.getValue(frame, expr.Y)
|
||||||
@@ -1451,10 +1459,12 @@ func (c *Compiler) parseExpr(frame *Frame, expr ssa.Value) (llvm.Value, error) {
|
|||||||
// This could be done directly, but as this is a very infrequent
|
// This could be done directly, but as this is a very infrequent
|
||||||
// operation it's much easier to bitcast it through an alloca.
|
// operation it's much easier to bitcast it through an alloca.
|
||||||
resultType := c.getLLVMType(expr.Type())
|
resultType := c.getLLVMType(expr.Type())
|
||||||
alloca := c.builder.CreateAlloca(value.Type(), "")
|
alloca, allocaPtr, allocaSize := c.createTemporaryAlloca(value.Type(), "union.alloca")
|
||||||
c.builder.CreateStore(value, alloca)
|
c.builder.CreateStore(value, alloca)
|
||||||
bitcast := c.builder.CreateBitCast(alloca, llvm.PointerType(resultType, 0), "")
|
bitcast := c.builder.CreateBitCast(alloca, llvm.PointerType(resultType, 0), "union.bitcast")
|
||||||
return c.builder.CreateLoad(bitcast, ""), nil
|
result := c.builder.CreateLoad(bitcast, "union.result")
|
||||||
|
c.emitLifetimeEnd(allocaPtr, allocaSize)
|
||||||
|
return result, nil
|
||||||
}
|
}
|
||||||
result := c.builder.CreateExtractValue(value, expr.Field, "")
|
result := c.builder.CreateExtractValue(value, expr.Field, "")
|
||||||
return result, nil
|
return result, nil
|
||||||
@@ -1494,11 +1504,13 @@ func (c *Compiler) parseExpr(frame *Frame, expr ssa.Value) (llvm.Value, error) {
|
|||||||
|
|
||||||
// Can't load directly from array (as index is non-constant), so have to
|
// Can't load directly from array (as index is non-constant), so have to
|
||||||
// do it using an alloca+gep+load.
|
// do it using an alloca+gep+load.
|
||||||
alloca := c.builder.CreateAlloca(array.Type(), "index.alloca")
|
alloca, allocaPtr, allocaSize := c.createTemporaryAlloca(array.Type(), "index.alloca")
|
||||||
c.builder.CreateStore(array, alloca)
|
c.builder.CreateStore(array, alloca)
|
||||||
zero := llvm.ConstInt(c.ctx.Int32Type(), 0, false)
|
zero := llvm.ConstInt(c.ctx.Int32Type(), 0, false)
|
||||||
ptr := c.builder.CreateInBoundsGEP(alloca, []llvm.Value{zero, index}, "index.gep")
|
ptr := c.builder.CreateInBoundsGEP(alloca, []llvm.Value{zero, index}, "index.gep")
|
||||||
return c.builder.CreateLoad(ptr, "index.load"), nil
|
result := c.builder.CreateLoad(ptr, "index.load")
|
||||||
|
c.emitLifetimeEnd(allocaPtr, allocaSize)
|
||||||
|
return result, nil
|
||||||
case *ssa.IndexAddr:
|
case *ssa.IndexAddr:
|
||||||
val := c.getValue(frame, expr.X)
|
val := c.getValue(frame, expr.X)
|
||||||
index := c.getValue(frame, expr.Index)
|
index := c.getValue(frame, expr.Index)
|
||||||
@@ -1658,16 +1670,16 @@ func (c *Compiler) parseExpr(frame *Frame, expr ssa.Value) (llvm.Value, error) {
|
|||||||
llvmKeyType := c.getLLVMType(rangeVal.Type().Underlying().(*types.Map).Key())
|
llvmKeyType := c.getLLVMType(rangeVal.Type().Underlying().(*types.Map).Key())
|
||||||
llvmValueType := c.getLLVMType(rangeVal.Type().Underlying().(*types.Map).Elem())
|
llvmValueType := c.getLLVMType(rangeVal.Type().Underlying().(*types.Map).Elem())
|
||||||
|
|
||||||
mapKeyAlloca := c.builder.CreateAlloca(llvmKeyType, "range.key")
|
mapKeyAlloca, mapKeyPtr, mapKeySize := c.createTemporaryAlloca(llvmKeyType, "range.key")
|
||||||
mapKeyPtr := c.builder.CreateBitCast(mapKeyAlloca, c.i8ptrType, "range.keyptr")
|
mapValueAlloca, mapValuePtr, mapValueSize := c.createTemporaryAlloca(llvmValueType, "range.value")
|
||||||
mapValueAlloca := c.builder.CreateAlloca(llvmValueType, "range.value")
|
|
||||||
mapValuePtr := c.builder.CreateBitCast(mapValueAlloca, c.i8ptrType, "range.valueptr")
|
|
||||||
ok := c.createRuntimeCall("hashmapNext", []llvm.Value{llvmRangeVal, it, mapKeyPtr, mapValuePtr}, "range.next")
|
ok := c.createRuntimeCall("hashmapNext", []llvm.Value{llvmRangeVal, it, mapKeyPtr, mapValuePtr}, "range.next")
|
||||||
|
|
||||||
tuple := llvm.Undef(c.ctx.StructType([]llvm.Type{c.ctx.Int1Type(), llvmKeyType, llvmValueType}, false))
|
tuple := llvm.Undef(c.ctx.StructType([]llvm.Type{c.ctx.Int1Type(), llvmKeyType, llvmValueType}, false))
|
||||||
tuple = c.builder.CreateInsertValue(tuple, ok, 0, "")
|
tuple = c.builder.CreateInsertValue(tuple, ok, 0, "")
|
||||||
tuple = c.builder.CreateInsertValue(tuple, c.builder.CreateLoad(mapKeyAlloca, ""), 1, "")
|
tuple = c.builder.CreateInsertValue(tuple, c.builder.CreateLoad(mapKeyAlloca, ""), 1, "")
|
||||||
tuple = c.builder.CreateInsertValue(tuple, c.builder.CreateLoad(mapValueAlloca, ""), 2, "")
|
tuple = c.builder.CreateInsertValue(tuple, c.builder.CreateLoad(mapValueAlloca, ""), 2, "")
|
||||||
|
c.emitLifetimeEnd(mapKeyPtr, mapKeySize)
|
||||||
|
c.emitLifetimeEnd(mapValuePtr, mapValueSize)
|
||||||
return tuple, nil
|
return tuple, nil
|
||||||
}
|
}
|
||||||
case *ssa.Phi:
|
case *ssa.Phi:
|
||||||
@@ -1684,7 +1696,7 @@ func (c *Compiler) parseExpr(frame *Frame, expr ssa.Value) (llvm.Value, error) {
|
|||||||
default:
|
default:
|
||||||
panic("unknown type in range: " + typ.String())
|
panic("unknown type in range: " + typ.String())
|
||||||
}
|
}
|
||||||
it := c.builder.CreateAlloca(iteratorType, "range.it")
|
it, _, _ := c.createTemporaryAlloca(iteratorType, "range.it")
|
||||||
c.builder.CreateStore(c.getZeroValue(iteratorType), it)
|
c.builder.CreateStore(c.getZeroValue(iteratorType), it)
|
||||||
return it, nil
|
return it, nil
|
||||||
case *ssa.Select:
|
case *ssa.Select:
|
||||||
|
|||||||
@@ -154,17 +154,17 @@ func (c *Compiler) LowerFuncValues() {
|
|||||||
// What we'll do is transform the following:
|
// What we'll do is transform the following:
|
||||||
// rawPtr := runtime.getFuncPtr(fn)
|
// rawPtr := runtime.getFuncPtr(fn)
|
||||||
// if func.rawPtr == nil {
|
// if func.rawPtr == nil {
|
||||||
// runtime.nilpanic()
|
// runtime.nilPanic()
|
||||||
// }
|
// }
|
||||||
// result := func.rawPtr(...args, func.context)
|
// result := func.rawPtr(...args, func.context)
|
||||||
// into this:
|
// into this:
|
||||||
// if false {
|
// if false {
|
||||||
// runtime.nilpanic()
|
// runtime.nilPanic()
|
||||||
// }
|
// }
|
||||||
// var result // Phi
|
// var result // Phi
|
||||||
// switch fn.id {
|
// switch fn.id {
|
||||||
// case 0:
|
// case 0:
|
||||||
// runtime.nilpanic()
|
// runtime.nilPanic()
|
||||||
// case 1:
|
// case 1:
|
||||||
// result = call first implementation...
|
// result = call first implementation...
|
||||||
// case 2:
|
// case 2:
|
||||||
@@ -222,7 +222,7 @@ func (c *Compiler) LowerFuncValues() {
|
|||||||
// The 0 case, which is actually a nil check.
|
// The 0 case, which is actually a nil check.
|
||||||
nilBlock := llvm.InsertBasicBlock(nextBlock, "func.nil")
|
nilBlock := llvm.InsertBasicBlock(nextBlock, "func.nil")
|
||||||
c.builder.SetInsertPointAtEnd(nilBlock)
|
c.builder.SetInsertPointAtEnd(nilBlock)
|
||||||
c.createRuntimeCall("nilpanic", nil, "")
|
c.createRuntimeCall("nilPanic", nil, "")
|
||||||
c.builder.CreateUnreachable()
|
c.builder.CreateUnreachable()
|
||||||
sw.AddCase(llvm.ConstInt(c.uintptrType, 0, false), nilBlock)
|
sw.AddCase(llvm.ConstInt(c.uintptrType, 0, false), nilBlock)
|
||||||
|
|
||||||
|
|||||||
@@ -389,7 +389,20 @@ func (c *Compiler) markAsyncFunctions() (needsScheduler bool, err error) {
|
|||||||
|
|
||||||
c.builder.SetInsertPointBefore(inst)
|
c.builder.SetInsertPointBefore(inst)
|
||||||
|
|
||||||
parentHandle := f.LastParam()
|
var parentHandle llvm.Value
|
||||||
|
if f.Linkage() == llvm.ExternalLinkage {
|
||||||
|
// Exported function.
|
||||||
|
// Note that getTaskPromisePtr will panic if it is called with
|
||||||
|
// a nil pointer, so blocking exported functions that try to
|
||||||
|
// return anything will not work.
|
||||||
|
parentHandle = llvm.ConstPointerNull(c.i8ptrType)
|
||||||
|
} else {
|
||||||
|
parentHandle = f.LastParam()
|
||||||
|
if parentHandle.IsNil() || parentHandle.Name() != "parentHandle" {
|
||||||
|
// sanity check
|
||||||
|
panic("trying to make exported function async")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Store return values.
|
// Store return values.
|
||||||
switch inst.OperandsCount() {
|
switch inst.OperandsCount() {
|
||||||
@@ -417,7 +430,7 @@ func (c *Compiler) markAsyncFunctions() (needsScheduler bool, err error) {
|
|||||||
// behavior somehow (with the unreachable instruction).
|
// behavior somehow (with the unreachable instruction).
|
||||||
continuePoint := c.builder.CreateCall(coroSuspendFunc, []llvm.Value{
|
continuePoint := c.builder.CreateCall(coroSuspendFunc, []llvm.Value{
|
||||||
llvm.ConstNull(c.ctx.TokenType()),
|
llvm.ConstNull(c.ctx.TokenType()),
|
||||||
llvm.ConstInt(c.ctx.Int1Type(), 1, false),
|
llvm.ConstInt(c.ctx.Int1Type(), 0, false),
|
||||||
}, "ret")
|
}, "ret")
|
||||||
sw := c.builder.CreateSwitch(continuePoint, frame.suspendBlock, 2)
|
sw := c.builder.CreateSwitch(continuePoint, frame.suspendBlock, 2)
|
||||||
sw.AddCase(llvm.ConstInt(c.ctx.Int8Type(), 0, false), frame.unreachableBlock)
|
sw.AddCase(llvm.ConstInt(c.ctx.Int8Type(), 0, false), frame.unreachableBlock)
|
||||||
@@ -488,7 +501,7 @@ func (c *Compiler) markAsyncFunctions() (needsScheduler bool, err error) {
|
|||||||
c.builder.SetInsertPointBefore(deadlockCall)
|
c.builder.SetInsertPointBefore(deadlockCall)
|
||||||
continuePoint := c.builder.CreateCall(coroSuspendFunc, []llvm.Value{
|
continuePoint := c.builder.CreateCall(coroSuspendFunc, []llvm.Value{
|
||||||
llvm.ConstNull(c.ctx.TokenType()),
|
llvm.ConstNull(c.ctx.TokenType()),
|
||||||
llvm.ConstInt(c.ctx.Int1Type(), 1, false), // final suspend
|
llvm.ConstInt(c.ctx.Int1Type(), 0, false),
|
||||||
}, "")
|
}, "")
|
||||||
c.splitBasicBlock(deadlockCall, llvm.NextBasicBlock(c.builder.GetInsertBlock()), "task.wakeup.dead")
|
c.splitBasicBlock(deadlockCall, llvm.NextBasicBlock(c.builder.GetInsertBlock()), "task.wakeup.dead")
|
||||||
c.builder.SetInsertPointBefore(deadlockCall)
|
c.builder.SetInsertPointBefore(deadlockCall)
|
||||||
|
|||||||
+27
-9
@@ -24,23 +24,41 @@ func getUses(value llvm.Value) []llvm.Value {
|
|||||||
|
|
||||||
// createEntryBlockAlloca creates a new alloca in the entry block, even though
|
// createEntryBlockAlloca creates a new alloca in the entry block, even though
|
||||||
// the IR builder is located elsewhere. It assumes that the insert point is
|
// the IR builder is located elsewhere. It assumes that the insert point is
|
||||||
// after the last instruction in the current block. Also, it adds lifetime
|
// at the end of the current block.
|
||||||
// information to the IR signalling that the alloca won't be used before this
|
func (c *Compiler) createEntryBlockAlloca(t llvm.Type, name string) llvm.Value {
|
||||||
// point.
|
currentBlock := c.builder.GetInsertBlock()
|
||||||
|
entryBlock := currentBlock.Parent().EntryBasicBlock()
|
||||||
|
if entryBlock.FirstInstruction().IsNil() {
|
||||||
|
c.builder.SetInsertPointAtEnd(entryBlock)
|
||||||
|
} else {
|
||||||
|
c.builder.SetInsertPointBefore(entryBlock.FirstInstruction())
|
||||||
|
}
|
||||||
|
alloca := c.builder.CreateAlloca(t, name)
|
||||||
|
c.builder.SetInsertPointAtEnd(currentBlock)
|
||||||
|
return alloca
|
||||||
|
}
|
||||||
|
|
||||||
|
// createTemporaryAlloca creates a new alloca in the entry block and adds
|
||||||
|
// lifetime start infromation in the IR signalling that the alloca won't be used
|
||||||
|
// before this point.
|
||||||
//
|
//
|
||||||
// This is useful for creating temporary allocas for intrinsics. Don't forget to
|
// This is useful for creating temporary allocas for intrinsics. Don't forget to
|
||||||
// end the lifetime after you're done with it.
|
// end the lifetime using emitLifetimeEnd after you're done with it.
|
||||||
func (c *Compiler) createEntryBlockAlloca(t llvm.Type, name string) (alloca, bitcast, size llvm.Value) {
|
func (c *Compiler) createTemporaryAlloca(t llvm.Type, name string) (alloca, bitcast, size llvm.Value) {
|
||||||
currentBlock := c.builder.GetInsertBlock()
|
alloca = c.createEntryBlockAlloca(t, name)
|
||||||
c.builder.SetInsertPointBefore(currentBlock.Parent().EntryBasicBlock().FirstInstruction())
|
|
||||||
alloca = c.builder.CreateAlloca(t, name)
|
|
||||||
c.builder.SetInsertPointAtEnd(currentBlock)
|
|
||||||
bitcast = c.builder.CreateBitCast(alloca, c.i8ptrType, name+".bitcast")
|
bitcast = c.builder.CreateBitCast(alloca, c.i8ptrType, name+".bitcast")
|
||||||
size = llvm.ConstInt(c.ctx.Int64Type(), c.targetData.TypeAllocSize(t), false)
|
size = llvm.ConstInt(c.ctx.Int64Type(), c.targetData.TypeAllocSize(t), false)
|
||||||
c.builder.CreateCall(c.getLifetimeStartFunc(), []llvm.Value{size, bitcast}, "")
|
c.builder.CreateCall(c.getLifetimeStartFunc(), []llvm.Value{size, bitcast}, "")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// emitLifetimeEnd signals the end of an (alloca) lifetime by calling the
|
||||||
|
// llvm.lifetime.end intrinsic. It is commonly used together with
|
||||||
|
// createTemporaryAlloca.
|
||||||
|
func (c *Compiler) emitLifetimeEnd(ptr, size llvm.Value) {
|
||||||
|
c.builder.CreateCall(c.getLifetimeEndFunc(), []llvm.Value{size, ptr}, "")
|
||||||
|
}
|
||||||
|
|
||||||
// getLifetimeStartFunc returns the llvm.lifetime.start intrinsic and creates it
|
// getLifetimeStartFunc returns the llvm.lifetime.start intrinsic and creates it
|
||||||
// first if it doesn't exist yet.
|
// first if it doesn't exist yet.
|
||||||
func (c *Compiler) getLifetimeStartFunc() llvm.Value {
|
func (c *Compiler) getLifetimeStartFunc() llvm.Value {
|
||||||
|
|||||||
+10
-10
@@ -15,7 +15,7 @@ func (c *Compiler) emitMapLookup(keyType, valueType types.Type, m, key llvm.Valu
|
|||||||
// Allocate the memory for the resulting type. Do not zero this memory: it
|
// Allocate the memory for the resulting type. Do not zero this memory: it
|
||||||
// will be zeroed by the hashmap get implementation if the key is not
|
// will be zeroed by the hashmap get implementation if the key is not
|
||||||
// present in the map.
|
// present in the map.
|
||||||
mapValueAlloca, mapValuePtr, mapValueSize := c.createEntryBlockAlloca(llvmValueType, "hashmap.value")
|
mapValueAlloca, mapValuePtr, mapValueSize := c.createTemporaryAlloca(llvmValueType, "hashmap.value")
|
||||||
|
|
||||||
// Do the lookup. How it is done depends on the key type.
|
// Do the lookup. How it is done depends on the key type.
|
||||||
var commaOkValue llvm.Value
|
var commaOkValue llvm.Value
|
||||||
@@ -27,12 +27,12 @@ func (c *Compiler) emitMapLookup(keyType, valueType types.Type, m, key llvm.Valu
|
|||||||
// key can be compared with runtime.memequal
|
// key can be compared with runtime.memequal
|
||||||
// Store the key in an alloca, in the entry block to avoid dynamic stack
|
// Store the key in an alloca, in the entry block to avoid dynamic stack
|
||||||
// growth.
|
// growth.
|
||||||
mapKeyAlloca, mapKeyPtr, mapKeySize := c.createEntryBlockAlloca(key.Type(), "hashmap.key")
|
mapKeyAlloca, mapKeyPtr, mapKeySize := c.createTemporaryAlloca(key.Type(), "hashmap.key")
|
||||||
c.builder.CreateStore(key, mapKeyAlloca)
|
c.builder.CreateStore(key, mapKeyAlloca)
|
||||||
// Fetch the value from the hashmap.
|
// Fetch the value from the hashmap.
|
||||||
params := []llvm.Value{m, mapKeyPtr, mapValuePtr}
|
params := []llvm.Value{m, mapKeyPtr, mapValuePtr}
|
||||||
commaOkValue = c.createRuntimeCall("hashmapBinaryGet", params, "")
|
commaOkValue = c.createRuntimeCall("hashmapBinaryGet", params, "")
|
||||||
c.builder.CreateCall(c.getLifetimeEndFunc(), []llvm.Value{mapKeySize, mapKeyPtr}, "")
|
c.emitLifetimeEnd(mapKeyPtr, mapKeySize)
|
||||||
} else {
|
} else {
|
||||||
// Not trivially comparable using memcmp.
|
// Not trivially comparable using memcmp.
|
||||||
return llvm.Value{}, c.makeError(pos, "only strings, bools, ints or structs of bools/ints are supported as map keys, but got: "+keyType.String())
|
return llvm.Value{}, c.makeError(pos, "only strings, bools, ints or structs of bools/ints are supported as map keys, but got: "+keyType.String())
|
||||||
@@ -41,7 +41,7 @@ func (c *Compiler) emitMapLookup(keyType, valueType types.Type, m, key llvm.Valu
|
|||||||
// Load the resulting value from the hashmap. The value is set to the zero
|
// Load the resulting value from the hashmap. The value is set to the zero
|
||||||
// value if the key doesn't exist in the hashmap.
|
// value if the key doesn't exist in the hashmap.
|
||||||
mapValue := c.builder.CreateLoad(mapValueAlloca, "")
|
mapValue := c.builder.CreateLoad(mapValueAlloca, "")
|
||||||
c.builder.CreateCall(c.getLifetimeEndFunc(), []llvm.Value{mapValueSize, mapValuePtr}, "")
|
c.emitLifetimeEnd(mapValuePtr, mapValueSize)
|
||||||
|
|
||||||
if commaOk {
|
if commaOk {
|
||||||
tuple := llvm.Undef(c.ctx.StructType([]llvm.Type{llvmValueType, c.ctx.Int1Type()}, false))
|
tuple := llvm.Undef(c.ctx.StructType([]llvm.Type{llvmValueType, c.ctx.Int1Type()}, false))
|
||||||
@@ -54,7 +54,7 @@ func (c *Compiler) emitMapLookup(keyType, valueType types.Type, m, key llvm.Valu
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (c *Compiler) emitMapUpdate(keyType types.Type, m, key, value llvm.Value, pos token.Pos) {
|
func (c *Compiler) emitMapUpdate(keyType types.Type, m, key, value llvm.Value, pos token.Pos) {
|
||||||
valueAlloca, valuePtr, valueSize := c.createEntryBlockAlloca(value.Type(), "hashmap.value")
|
valueAlloca, valuePtr, valueSize := c.createTemporaryAlloca(value.Type(), "hashmap.value")
|
||||||
c.builder.CreateStore(value, valueAlloca)
|
c.builder.CreateStore(value, valueAlloca)
|
||||||
keyType = keyType.Underlying()
|
keyType = keyType.Underlying()
|
||||||
if t, ok := keyType.(*types.Basic); ok && t.Info()&types.IsString != 0 {
|
if t, ok := keyType.(*types.Basic); ok && t.Info()&types.IsString != 0 {
|
||||||
@@ -63,15 +63,15 @@ func (c *Compiler) emitMapUpdate(keyType types.Type, m, key, value llvm.Value, p
|
|||||||
c.createRuntimeCall("hashmapStringSet", params, "")
|
c.createRuntimeCall("hashmapStringSet", params, "")
|
||||||
} else if hashmapIsBinaryKey(keyType) {
|
} else if hashmapIsBinaryKey(keyType) {
|
||||||
// key can be compared with runtime.memequal
|
// key can be compared with runtime.memequal
|
||||||
keyAlloca, keyPtr, keySize := c.createEntryBlockAlloca(key.Type(), "hashmap.key")
|
keyAlloca, keyPtr, keySize := c.createTemporaryAlloca(key.Type(), "hashmap.key")
|
||||||
c.builder.CreateStore(key, keyAlloca)
|
c.builder.CreateStore(key, keyAlloca)
|
||||||
params := []llvm.Value{m, keyPtr, valuePtr}
|
params := []llvm.Value{m, keyPtr, valuePtr}
|
||||||
c.createRuntimeCall("hashmapBinarySet", params, "")
|
c.createRuntimeCall("hashmapBinarySet", params, "")
|
||||||
c.builder.CreateCall(c.getLifetimeEndFunc(), []llvm.Value{keySize, keyPtr}, "")
|
c.emitLifetimeEnd(keyPtr, keySize)
|
||||||
} else {
|
} else {
|
||||||
c.addError(pos, "only strings, bools, ints or structs of bools/ints are supported as map keys, but got: "+keyType.String())
|
c.addError(pos, "only strings, bools, ints or structs of bools/ints are supported as map keys, but got: "+keyType.String())
|
||||||
}
|
}
|
||||||
c.builder.CreateCall(c.getLifetimeEndFunc(), []llvm.Value{valueSize, valuePtr}, "")
|
c.emitLifetimeEnd(valuePtr, valueSize)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Compiler) emitMapDelete(keyType types.Type, m, key llvm.Value, pos token.Pos) error {
|
func (c *Compiler) emitMapDelete(keyType types.Type, m, key llvm.Value, pos token.Pos) error {
|
||||||
@@ -82,11 +82,11 @@ func (c *Compiler) emitMapDelete(keyType types.Type, m, key llvm.Value, pos toke
|
|||||||
c.createRuntimeCall("hashmapStringDelete", params, "")
|
c.createRuntimeCall("hashmapStringDelete", params, "")
|
||||||
return nil
|
return nil
|
||||||
} else if hashmapIsBinaryKey(keyType) {
|
} else if hashmapIsBinaryKey(keyType) {
|
||||||
keyAlloca, keyPtr, keySize := c.createEntryBlockAlloca(key.Type(), "hashmap.key")
|
keyAlloca, keyPtr, keySize := c.createTemporaryAlloca(key.Type(), "hashmap.key")
|
||||||
c.builder.CreateStore(key, keyAlloca)
|
c.builder.CreateStore(key, keyAlloca)
|
||||||
params := []llvm.Value{m, keyPtr}
|
params := []llvm.Value{m, keyPtr}
|
||||||
c.createRuntimeCall("hashmapBinaryDelete", params, "")
|
c.createRuntimeCall("hashmapBinaryDelete", params, "")
|
||||||
c.builder.CreateCall(c.getLifetimeEndFunc(), []llvm.Value{keySize, keyPtr}, "")
|
c.emitLifetimeEnd(keyPtr, keySize)
|
||||||
return nil
|
return nil
|
||||||
} else {
|
} else {
|
||||||
return c.makeError(pos, "only strings, bools, ints or structs of bools/ints are supported as map keys, but got: "+keyType.String())
|
return c.makeError(pos, "only strings, bools, ints or structs of bools/ints are supported as map keys, but got: "+keyType.String())
|
||||||
|
|||||||
+13
-4
@@ -34,7 +34,7 @@ func (c *Compiler) emitPointerPack(values []llvm.Value) llvm.Value {
|
|||||||
}
|
}
|
||||||
// Because packedType is a struct and we have to cast it to a *i8, store
|
// Because packedType is a struct and we have to cast it to a *i8, store
|
||||||
// it in an alloca first for bitcasting (store+bitcast+load).
|
// it in an alloca first for bitcasting (store+bitcast+load).
|
||||||
packedAlloc = c.builder.CreateAlloca(packedType, "")
|
packedAlloc, _, _ = c.createTemporaryAlloca(packedType, "")
|
||||||
} else {
|
} else {
|
||||||
// Packed data is bigger than a pointer, so allocate it on the heap.
|
// Packed data is bigger than a pointer, so allocate it on the heap.
|
||||||
sizeValue := llvm.ConstInt(c.uintptrType, size, false)
|
sizeValue := llvm.ConstInt(c.uintptrType, size, false)
|
||||||
@@ -54,7 +54,11 @@ func (c *Compiler) emitPointerPack(values []llvm.Value) llvm.Value {
|
|||||||
if packedHeapAlloc.IsNil() {
|
if packedHeapAlloc.IsNil() {
|
||||||
// Load value (as *i8) from the alloca.
|
// Load value (as *i8) from the alloca.
|
||||||
packedAlloc = c.builder.CreateBitCast(packedAlloc, llvm.PointerType(c.i8ptrType, 0), "")
|
packedAlloc = c.builder.CreateBitCast(packedAlloc, llvm.PointerType(c.i8ptrType, 0), "")
|
||||||
return c.builder.CreateLoad(packedAlloc, "")
|
result := c.builder.CreateLoad(packedAlloc, "")
|
||||||
|
packedPtr := c.builder.CreateBitCast(packedAlloc, c.i8ptrType, "")
|
||||||
|
packedSize := llvm.ConstInt(c.ctx.Int64Type(), c.targetData.TypeAllocSize(packedAlloc.Type()), false)
|
||||||
|
c.emitLifetimeEnd(packedPtr, packedSize)
|
||||||
|
return result
|
||||||
} else {
|
} else {
|
||||||
// Get the original heap allocation pointer, which already is an *i8.
|
// Get the original heap allocation pointer, which already is an *i8.
|
||||||
return packedHeapAlloc
|
return packedHeapAlloc
|
||||||
@@ -66,7 +70,7 @@ func (c *Compiler) emitPointerUnpack(ptr llvm.Value, valueTypes []llvm.Type) []l
|
|||||||
packedType := c.ctx.StructType(valueTypes, false)
|
packedType := c.ctx.StructType(valueTypes, false)
|
||||||
|
|
||||||
// Get a correctly-typed pointer to the packed data.
|
// Get a correctly-typed pointer to the packed data.
|
||||||
var packedAlloc llvm.Value
|
var packedAlloc, packedRawAlloc llvm.Value
|
||||||
size := c.targetData.TypeAllocSize(packedType)
|
size := c.targetData.TypeAllocSize(packedType)
|
||||||
if size == 0 {
|
if size == 0 {
|
||||||
// No data to unpack.
|
// No data to unpack.
|
||||||
@@ -80,7 +84,7 @@ func (c *Compiler) emitPointerUnpack(ptr llvm.Value, valueTypes []llvm.Type) []l
|
|||||||
return []llvm.Value{c.builder.CreatePtrToInt(ptr, valueTypes[0], "unpack.int")}
|
return []llvm.Value{c.builder.CreatePtrToInt(ptr, valueTypes[0], "unpack.int")}
|
||||||
}
|
}
|
||||||
// Fallback: load it using an alloca.
|
// Fallback: load it using an alloca.
|
||||||
packedRawAlloc := c.builder.CreateAlloca(llvm.PointerType(c.i8ptrType, 0), "unpack.raw.alloc")
|
packedRawAlloc, _, _ = c.createTemporaryAlloca(llvm.PointerType(c.i8ptrType, 0), "unpack.raw.alloc")
|
||||||
packedRawValue := c.builder.CreateBitCast(ptr, llvm.PointerType(c.i8ptrType, 0), "unpack.raw.value")
|
packedRawValue := c.builder.CreateBitCast(ptr, llvm.PointerType(c.i8ptrType, 0), "unpack.raw.value")
|
||||||
c.builder.CreateStore(packedRawValue, packedRawAlloc)
|
c.builder.CreateStore(packedRawValue, packedRawAlloc)
|
||||||
packedAlloc = c.builder.CreateBitCast(packedRawAlloc, llvm.PointerType(packedType, 0), "unpack.alloc")
|
packedAlloc = c.builder.CreateBitCast(packedRawAlloc, llvm.PointerType(packedType, 0), "unpack.alloc")
|
||||||
@@ -104,5 +108,10 @@ func (c *Compiler) emitPointerUnpack(ptr llvm.Value, valueTypes []llvm.Type) []l
|
|||||||
gep := c.builder.CreateInBoundsGEP(packedAlloc, indices, "")
|
gep := c.builder.CreateInBoundsGEP(packedAlloc, indices, "")
|
||||||
values[i] = c.builder.CreateLoad(gep, "")
|
values[i] = c.builder.CreateLoad(gep, "")
|
||||||
}
|
}
|
||||||
|
if !packedRawAlloc.IsNil() {
|
||||||
|
allocPtr := c.builder.CreateBitCast(packedRawAlloc, c.i8ptrType, "")
|
||||||
|
allocSize := llvm.ConstInt(c.ctx.Int64Type(), c.targetData.TypeAllocSize(c.uintptrType), false)
|
||||||
|
c.emitLifetimeEnd(allocPtr, allocSize)
|
||||||
|
}
|
||||||
return values
|
return values
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,10 @@
|
|||||||
|
module github.com/tinygo-org/tinygo
|
||||||
|
|
||||||
|
go 1.11
|
||||||
|
|
||||||
|
require (
|
||||||
|
github.com/blakesmith/ar v0.0.0-20150311145944-8bd4349a67f2
|
||||||
|
github.com/marcinbor85/gohex v0.0.0-20180128172054-7a43cd876e46
|
||||||
|
golang.org/x/tools v0.0.0-20190227180812-8dcc6e70cdef
|
||||||
|
tinygo.org/x/go-llvm v0.0.0-20190224120431-7707ae5d1261
|
||||||
|
)
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
github.com/blakesmith/ar v0.0.0-20150311145944-8bd4349a67f2 h1:oMCHnXa6CCCafdPDbMh/lWRhRByN0VFLvv+g+ayx1SI=
|
||||||
|
github.com/blakesmith/ar v0.0.0-20150311145944-8bd4349a67f2/go.mod h1:PkYb9DJNAwrSvRx5DYA+gUcOIgTGVMNkfSCbZM8cWpI=
|
||||||
|
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||||
|
github.com/marcinbor85/gohex v0.0.0-20180128172054-7a43cd876e46 h1:wXG2bA8fO7Vv7lLk2PihFMTqmbT173Tje39oKzQ50Mo=
|
||||||
|
github.com/marcinbor85/gohex v0.0.0-20180128172054-7a43cd876e46/go.mod h1:Pb6XcsXyropB9LNHhnqaknG/vEwYztLkQzVCHv8sQ3M=
|
||||||
|
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
|
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
|
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
|
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
|
golang.org/x/tools v0.0.0-20190227180812-8dcc6e70cdef h1:ymc9FeDom3RIEA3coKokSllBB1hRcMT0tZ1W3Jf9Ids=
|
||||||
|
golang.org/x/tools v0.0.0-20190227180812-8dcc6e70cdef/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
|
||||||
|
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||||
|
tinygo.org/x/go-llvm v0.0.0-20190224120431-7707ae5d1261 h1:rJS2Hga39YAnm7DE4qrPm6Dr/67EOojL0XPzvbEeBiw=
|
||||||
|
tinygo.org/x/go-llvm v0.0.0-20190224120431-7707ae5d1261/go.mod h1:fv1F0BSNpxMfCL0zF3M4OPFbgYHnhtB6ST0HvUtu/LE=
|
||||||
+33
-10
@@ -184,6 +184,25 @@ func (fr *frame) evalBasicBlock(bb, incoming llvm.BasicBlock, indent string) (re
|
|||||||
lhs := fr.getLocal(inst.Operand(0)).(*LocalValue).Underlying
|
lhs := fr.getLocal(inst.Operand(0)).(*LocalValue).Underlying
|
||||||
rhs := fr.getLocal(inst.Operand(1)).(*LocalValue).Underlying
|
rhs := fr.getLocal(inst.Operand(1)).(*LocalValue).Underlying
|
||||||
predicate := inst.IntPredicate()
|
predicate := inst.IntPredicate()
|
||||||
|
if predicate == llvm.IntEQ && lhs.Type().TypeKind() == llvm.PointerTypeKind {
|
||||||
|
// Unfortunately, the const propagation in the IR builder
|
||||||
|
// doesn't handle pointer compares of inttoptr values. So we
|
||||||
|
// implement it manually here.
|
||||||
|
lhsNil, ok1 := isPointerNil(lhs)
|
||||||
|
rhsNil, ok2 := isPointerNil(rhs)
|
||||||
|
if ok1 && ok2 {
|
||||||
|
if lhsNil && rhsNil {
|
||||||
|
// Both are nil, so this icmp is always evaluated to true.
|
||||||
|
fr.locals[inst] = &LocalValue{fr.Eval, llvm.ConstInt(fr.Mod.Context().Int1Type(), 1, false)}
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if lhsNil != rhsNil {
|
||||||
|
// Only one of them is nil, so this comparison must return false.
|
||||||
|
fr.locals[inst] = &LocalValue{fr.Eval, llvm.ConstInt(fr.Mod.Context().Int1Type(), 0, false)}
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
fr.locals[inst] = &LocalValue{fr.Eval, fr.builder.CreateICmp(predicate, lhs, rhs, "")}
|
fr.locals[inst] = &LocalValue{fr.Eval, fr.builder.CreateICmp(predicate, lhs, rhs, "")}
|
||||||
case !inst.IsAFCmpInst().IsNil():
|
case !inst.IsAFCmpInst().IsNil():
|
||||||
lhs := fr.getLocal(inst.Operand(0)).(*LocalValue).Underlying
|
lhs := fr.getLocal(inst.Operand(0)).(*LocalValue).Underlying
|
||||||
@@ -461,17 +480,21 @@ func (fr *frame) evalBasicBlock(bb, incoming llvm.BasicBlock, indent string) (re
|
|||||||
}
|
}
|
||||||
thenBB := inst.Operand(1)
|
thenBB := inst.Operand(1)
|
||||||
elseBB := inst.Operand(2)
|
elseBB := inst.Operand(2)
|
||||||
if !cond.IsConstant() {
|
if !cond.IsAInstruction().IsNil() {
|
||||||
return nil, nil, errors.New("interp: branch on a non-constant")
|
return nil, nil, errors.New("interp: branch on a non-constant")
|
||||||
} else {
|
}
|
||||||
switch cond.ZExtValue() {
|
if !cond.IsAConstantExpr().IsNil() {
|
||||||
case 0: // false
|
// This may happen when the instruction builder could not
|
||||||
return nil, []llvm.Value{thenBB}, nil // then
|
// const-fold some instructions.
|
||||||
case 1: // true
|
return nil, nil, errors.New("interp: branch on a non-const-propagated constant expression")
|
||||||
return nil, []llvm.Value{elseBB}, nil // else
|
}
|
||||||
default:
|
switch cond {
|
||||||
panic("branch was not true or false")
|
case llvm.ConstInt(fr.Mod.Context().Int1Type(), 0, false): // false
|
||||||
}
|
return nil, []llvm.Value{thenBB}, nil // then
|
||||||
|
case llvm.ConstInt(fr.Mod.Context().Int1Type(), 1, false): // true
|
||||||
|
return nil, []llvm.Value{elseBB}, nil // else
|
||||||
|
default:
|
||||||
|
panic("branch was not true or false")
|
||||||
}
|
}
|
||||||
case !inst.IsABranchInst().IsNil() && inst.OperandsCount() == 1:
|
case !inst.IsABranchInst().IsNil() && inst.OperandsCount() == 1:
|
||||||
// unconditional branch (goto)
|
// unconditional branch (goto)
|
||||||
|
|||||||
+10
-1
@@ -109,7 +109,16 @@ func (e *Eval) hasSideEffects(fn llvm.Value) *sideEffectResult {
|
|||||||
default:
|
default:
|
||||||
panic("unreachable")
|
panic("unreachable")
|
||||||
}
|
}
|
||||||
case llvm.Load, llvm.Store:
|
case llvm.Load:
|
||||||
|
if inst.IsVolatile() {
|
||||||
|
result.updateSeverity(sideEffectLimited)
|
||||||
|
}
|
||||||
|
if _, ok := e.dirtyGlobals[inst.Operand(0)]; ok {
|
||||||
|
if e.hasLocalSideEffects(dirtyLocals, inst) {
|
||||||
|
result.updateSeverity(sideEffectLimited)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case llvm.Store:
|
||||||
if inst.IsVolatile() {
|
if inst.IsVolatile() {
|
||||||
result.updateSeverity(sideEffectLimited)
|
result.updateSeverity(sideEffectLimited)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -94,3 +94,29 @@ func isScalar(t llvm.Type) bool {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// isPointerNil returns whether this is a nil pointer or not. The ok value
|
||||||
|
// indicates whether the result is certain: if it is false the result boolean is
|
||||||
|
// not valid.
|
||||||
|
func isPointerNil(v llvm.Value) (result bool, ok bool) {
|
||||||
|
if !v.IsAConstantExpr().IsNil() {
|
||||||
|
switch v.Opcode() {
|
||||||
|
case llvm.IntToPtr:
|
||||||
|
// Whether a constant inttoptr is nil is easy to
|
||||||
|
// determine.
|
||||||
|
operand := v.Operand(0)
|
||||||
|
if operand.IsConstant() {
|
||||||
|
return operand.ZExtValue() == 0, true
|
||||||
|
}
|
||||||
|
case llvm.BitCast, llvm.GetElementPtr:
|
||||||
|
// These const instructions are just a kind of wrappers for the
|
||||||
|
// underlying pointer.
|
||||||
|
return isPointerNil(v.Operand(0))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if !v.IsAConstantPointerNull().IsNil() {
|
||||||
|
// A constant pointer null is always null, of course.
|
||||||
|
return true, true
|
||||||
|
}
|
||||||
|
return false, false // not valid
|
||||||
|
}
|
||||||
|
|||||||
@@ -80,9 +80,21 @@ func Compile(pkgName, outpath string, spec *TargetSpec, config *BuildConfig, act
|
|||||||
if goroot == "" {
|
if goroot == "" {
|
||||||
return errors.New("cannot locate $GOROOT, please set it manually")
|
return errors.New("cannot locate $GOROOT, please set it manually")
|
||||||
}
|
}
|
||||||
|
tags := spec.BuildTags
|
||||||
|
major, minor := getGorootVersion(goroot)
|
||||||
|
if major != 1 {
|
||||||
|
if major == 0 {
|
||||||
|
return errors.New("could not read version from GOROOT: " + goroot)
|
||||||
|
}
|
||||||
|
return fmt.Errorf("expected major version 1, got go%d.%d", major, minor)
|
||||||
|
}
|
||||||
|
for i := 1; i <= minor; i++ {
|
||||||
|
tags = append(tags, fmt.Sprintf("go1.%d", i))
|
||||||
|
}
|
||||||
compilerConfig := compiler.Config{
|
compilerConfig := compiler.Config{
|
||||||
Triple: spec.Triple,
|
Triple: spec.Triple,
|
||||||
CPU: spec.CPU,
|
CPU: spec.CPU,
|
||||||
|
Features: spec.Features,
|
||||||
GOOS: spec.GOOS,
|
GOOS: spec.GOOS,
|
||||||
GOARCH: spec.GOARCH,
|
GOARCH: spec.GOARCH,
|
||||||
GC: config.gc,
|
GC: config.gc,
|
||||||
@@ -94,7 +106,7 @@ func Compile(pkgName, outpath string, spec *TargetSpec, config *BuildConfig, act
|
|||||||
TINYGOROOT: root,
|
TINYGOROOT: root,
|
||||||
GOROOT: goroot,
|
GOROOT: goroot,
|
||||||
GOPATH: getGopath(),
|
GOPATH: getGopath(),
|
||||||
BuildTags: spec.BuildTags,
|
BuildTags: tags,
|
||||||
}
|
}
|
||||||
c, err := compiler.NewCompiler(pkgName, compilerConfig)
|
c, err := compiler.NewCompiler(pkgName, compilerConfig)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@@ -0,0 +1,21 @@
|
|||||||
|
.syntax unified
|
||||||
|
|
||||||
|
.section .text.HardFault_Handler
|
||||||
|
.global HardFault_Handler
|
||||||
|
.type HardFault_Handler, %function
|
||||||
|
HardFault_Handler:
|
||||||
|
// Put the old stack pointer in the first argument, for easy debugging. This
|
||||||
|
// is especially useful on Cortex-M0, which supports far fewer debug
|
||||||
|
// facilities.
|
||||||
|
mov r0, sp
|
||||||
|
|
||||||
|
// Load the default stack pointer from address 0 so that we can call normal
|
||||||
|
// functions again that expect a working stack. However, it will corrupt the
|
||||||
|
// old stack so the function below must not attempt to recover from this
|
||||||
|
// fault.
|
||||||
|
movs r3, #0
|
||||||
|
ldr r3, [r3]
|
||||||
|
mov sp, r3
|
||||||
|
|
||||||
|
// Continue handling this error in Go.
|
||||||
|
bl handleHardFault
|
||||||
@@ -11,8 +11,8 @@ import (
|
|||||||
func main() {
|
func main() {
|
||||||
machine.InitADC()
|
machine.InitADC()
|
||||||
|
|
||||||
led := machine.GPIO{machine.LED}
|
led := machine.LED
|
||||||
led.Configure(machine.GPIOConfig{Mode: machine.GPIO_OUTPUT})
|
led.Configure(machine.PinConfig{Mode: machine.PinOutput})
|
||||||
|
|
||||||
sensor := machine.ADC{machine.ADC2}
|
sensor := machine.ADC{machine.ADC2}
|
||||||
sensor.Configure()
|
sensor.Configure()
|
||||||
|
|||||||
@@ -8,8 +8,8 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
led := machine.GPIO{machine.LED}
|
led := machine.LED
|
||||||
led.Configure(machine.GPIOConfig{Mode: machine.GPIO_OUTPUT})
|
led.Configure(machine.PinConfig{Mode: machine.PinOutput})
|
||||||
for {
|
for {
|
||||||
led.Low()
|
led.Low()
|
||||||
time.Sleep(time.Millisecond * 500)
|
time.Sleep(time.Millisecond * 500)
|
||||||
|
|||||||
@@ -16,8 +16,8 @@ func main() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func led1() {
|
func led1() {
|
||||||
led := machine.GPIO{machine.LED}
|
led := machine.LED1
|
||||||
led.Configure(machine.GPIOConfig{Mode: machine.GPIO_OUTPUT})
|
led.Configure(machine.PinConfig{Mode: machine.PinOutput})
|
||||||
for {
|
for {
|
||||||
println("+")
|
println("+")
|
||||||
led.Low()
|
led.Low()
|
||||||
@@ -30,8 +30,8 @@ func led1() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func led2() {
|
func led2() {
|
||||||
led := machine.GPIO{machine.LED2}
|
led := machine.LED2
|
||||||
led.Configure(machine.GPIOConfig{Mode: machine.GPIO_OUTPUT})
|
led.Configure(machine.PinConfig{Mode: machine.PinOutput})
|
||||||
for {
|
for {
|
||||||
println(" +")
|
println(" +")
|
||||||
led.Low()
|
led.Low()
|
||||||
|
|||||||
@@ -7,14 +7,14 @@ import (
|
|||||||
|
|
||||||
// This example assumes that the button is connected to pin 8. Change the value
|
// This example assumes that the button is connected to pin 8. Change the value
|
||||||
// below to use a different pin.
|
// below to use a different pin.
|
||||||
const buttonPin = 8
|
const (
|
||||||
|
led = machine.LED
|
||||||
|
button = machine.Pin(8)
|
||||||
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
led := machine.GPIO{machine.LED}
|
led.Configure(machine.PinConfig{Mode: machine.PinOutput})
|
||||||
led.Configure(machine.GPIOConfig{Mode: machine.GPIO_OUTPUT})
|
button.Configure(machine.PinConfig{Mode: machine.PinInput})
|
||||||
|
|
||||||
button := machine.GPIO{buttonPin}
|
|
||||||
button.Configure(machine.GPIOConfig{Mode: machine.GPIO_INPUT})
|
|
||||||
|
|
||||||
for {
|
for {
|
||||||
if button.Get() {
|
if button.Get() {
|
||||||
|
|||||||
@@ -8,29 +8,29 @@ import (
|
|||||||
// This example assumes that you are using the pca10040 board
|
// This example assumes that you are using the pca10040 board
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
led1 := machine.GPIO{machine.LED1}
|
led1 := machine.LED1
|
||||||
led1.Configure(machine.GPIOConfig{Mode: machine.GPIO_OUTPUT})
|
led1.Configure(machine.PinConfig{Mode: machine.PinOutput})
|
||||||
|
|
||||||
led2 := machine.GPIO{machine.LED2}
|
led2 := machine.LED2
|
||||||
led2.Configure(machine.GPIOConfig{Mode: machine.GPIO_OUTPUT})
|
led2.Configure(machine.PinConfig{Mode: machine.PinOutput})
|
||||||
|
|
||||||
led3 := machine.GPIO{machine.LED3}
|
led3 := machine.LED3
|
||||||
led3.Configure(machine.GPIOConfig{Mode: machine.GPIO_OUTPUT})
|
led3.Configure(machine.PinConfig{Mode: machine.PinOutput})
|
||||||
|
|
||||||
led4 := machine.GPIO{machine.LED4}
|
led4 := machine.LED4
|
||||||
led4.Configure(machine.GPIOConfig{Mode: machine.GPIO_OUTPUT})
|
led4.Configure(machine.PinConfig{Mode: machine.PinOutput})
|
||||||
|
|
||||||
button1 := machine.GPIO{machine.BUTTON1}
|
button1 := machine.BUTTON1
|
||||||
button1.Configure(machine.GPIOConfig{Mode: machine.GPIO_INPUT_PULLUP})
|
button1.Configure(machine.PinConfig{Mode: machine.PinInputPullup})
|
||||||
|
|
||||||
button2 := machine.GPIO{machine.BUTTON2}
|
button2 := machine.BUTTON2
|
||||||
button2.Configure(machine.GPIOConfig{Mode: machine.GPIO_INPUT_PULLUP})
|
button2.Configure(machine.PinConfig{Mode: machine.PinInputPullup})
|
||||||
|
|
||||||
button3 := machine.GPIO{machine.BUTTON3}
|
button3 := machine.BUTTON3
|
||||||
button3.Configure(machine.GPIOConfig{Mode: machine.GPIO_INPUT_PULLUP})
|
button3.Configure(machine.PinConfig{Mode: machine.PinInputPullup})
|
||||||
|
|
||||||
button4 := machine.GPIO{machine.BUTTON4}
|
button4 := machine.BUTTON4
|
||||||
button4.Configure(machine.GPIOConfig{Mode: machine.GPIO_INPUT_PULLUP})
|
button4.Configure(machine.PinConfig{Mode: machine.PinInputPullup})
|
||||||
|
|
||||||
for {
|
for {
|
||||||
led1.Set(button1.Get())
|
led1.Set(button1.Get())
|
||||||
|
|||||||
@@ -9,9 +9,9 @@ import (
|
|||||||
|
|
||||||
// change these to test a different UART or pins if available
|
// change these to test a different UART or pins if available
|
||||||
var (
|
var (
|
||||||
uart = machine.UART0
|
uart = machine.UART0
|
||||||
tx uint8 = machine.UART_TX_PIN
|
tx = machine.UART_TX_PIN
|
||||||
rx uint8 = machine.UART_RX_PIN
|
rx = machine.UART_RX_PIN
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
|
|||||||
@@ -8,19 +8,17 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
// CS_PIN is the pin used for Chip Select (CS). Change to whatever is in use on your board.
|
// cs is the pin used for Chip Select (CS). Change to whatever is in use on your board.
|
||||||
const CS_PIN = 3
|
const cs = machine.Pin(3)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
tx []byte
|
tx []byte
|
||||||
rx []byte
|
rx []byte
|
||||||
val, result uint16
|
val, result uint16
|
||||||
cs machine.GPIO
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
cs = machine.GPIO{CS_PIN}
|
cs.Configure(machine.PinConfig{Mode: machine.PinOutput})
|
||||||
cs.Configure(machine.GPIOConfig{Mode: machine.GPIO_OUTPUT})
|
|
||||||
|
|
||||||
machine.SPI0.Configure(machine.SPIConfig{
|
machine.SPI0.Configure(machine.SPIConfig{
|
||||||
Frequency: 4000000,
|
Frequency: 4000000,
|
||||||
|
|||||||
@@ -9,10 +9,10 @@ import (
|
|||||||
// The LED matrix in the micro:bit is a multiplexed display: https://en.wikipedia.org/wiki/Multiplexed_display
|
// The LED matrix in the micro:bit is a multiplexed display: https://en.wikipedia.org/wiki/Multiplexed_display
|
||||||
// Driver for easier control: https://github.com/tinygo-org/drivers/tree/master/microbitmatrix
|
// Driver for easier control: https://github.com/tinygo-org/drivers/tree/master/microbitmatrix
|
||||||
func main() {
|
func main() {
|
||||||
ledrow := machine.GPIO{machine.LED_ROW_1}
|
ledrow := machine.LED_ROW_1
|
||||||
ledrow.Configure(machine.GPIOConfig{Mode: machine.GPIO_OUTPUT})
|
ledrow.Configure(machine.PinConfig{Mode: machine.PinOutput})
|
||||||
ledcol := machine.GPIO{machine.LED_COL_1}
|
ledcol := machine.LED_COL_1
|
||||||
ledcol.Configure(machine.GPIOConfig{Mode: machine.GPIO_OUTPUT})
|
ledcol.Configure(machine.PinConfig{Mode: machine.PinOutput})
|
||||||
ledcol.Low()
|
ledcol.Low()
|
||||||
for {
|
for {
|
||||||
ledrow.Low()
|
ledrow.Low()
|
||||||
|
|||||||
@@ -1,10 +1,15 @@
|
|||||||
export: clean wasm_exec
|
export: clean wasm_exec
|
||||||
tinygo build -o ./html/wasm.wasm -target wasm ./export/wasm.go
|
tinygo build -o ./html/wasm.wasm -target wasm -no-debug ./export/wasm.go
|
||||||
cp ./export/wasm.js ./html/
|
cp ./export/wasm.js ./html/
|
||||||
cp ./export/index.html ./html/
|
cp ./export/index.html ./html/
|
||||||
|
|
||||||
|
callback: clean wasm_exec
|
||||||
|
tinygo build -o ./html/wasm.wasm -target wasm ./callback/wasm.go
|
||||||
|
cp ./callback/wasm.js ./html/
|
||||||
|
cp ./callback/index.html ./html/
|
||||||
|
|
||||||
main: clean wasm_exec
|
main: clean wasm_exec
|
||||||
tinygo build -o ./html/wasm.wasm -target wasm ./main/main.go
|
tinygo build -o ./html/wasm.wasm -target wasm -no-debug ./main/main.go
|
||||||
cp ./main/index.html ./html/
|
cp ./main/index.html ./html/
|
||||||
|
|
||||||
wasm_exec:
|
wasm_exec:
|
||||||
|
|||||||
@@ -0,0 +1,19 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
|
||||||
|
<html>
|
||||||
|
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8" />
|
||||||
|
<title>Go WebAssembly</title>
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||||
|
<script src="wasm_exec.js" defer></script>
|
||||||
|
<script src="wasm.js" defer></script>
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
<h1>WebAssembly</h1>
|
||||||
|
<p>Add two numbers, using WebAssembly:</p>
|
||||||
|
<input type="number" id="a" value="0" /> + <input type="number" id="b" value="0" /> = <input type="number" id="result" readonly />
|
||||||
|
</body>
|
||||||
|
|
||||||
|
</html>
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"strconv"
|
||||||
|
"syscall/js"
|
||||||
|
)
|
||||||
|
|
||||||
|
var a, b int
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
document := js.Global().Get("document")
|
||||||
|
document.Call("getElementById", "a").Set("oninput", updater(&a))
|
||||||
|
document.Call("getElementById", "b").Set("oninput", updater(&b))
|
||||||
|
update()
|
||||||
|
}
|
||||||
|
|
||||||
|
func updater(n *int) js.Func {
|
||||||
|
return js.FuncOf(func(this js.Value, args []js.Value) interface{} {
|
||||||
|
*n, _ = strconv.Atoi(this.Get("value").String())
|
||||||
|
update()
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func update() {
|
||||||
|
js.Global().Get("document").Call("getElementById", "result").Set("value", a+b)
|
||||||
|
}
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
const WASM_URL = 'wasm.wasm';
|
||||||
|
|
||||||
|
var wasm;
|
||||||
|
|
||||||
|
function init() {
|
||||||
|
const go = new Go();
|
||||||
|
if ('instantiateStreaming' in WebAssembly) {
|
||||||
|
WebAssembly.instantiateStreaming(fetch(WASM_URL), go.importObject).then(function (obj) {
|
||||||
|
wasm = obj.instance;
|
||||||
|
go.run(wasm);
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
fetch(WASM_URL).then(resp =>
|
||||||
|
resp.arrayBuffer()
|
||||||
|
).then(bytes =>
|
||||||
|
WebAssembly.instantiate(bytes, go.importObject).then(function (obj) {
|
||||||
|
wasm = obj.instance;
|
||||||
|
go.run(wasm);
|
||||||
|
})
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
init();
|
||||||
@@ -5,20 +5,20 @@ package machine
|
|||||||
const CPU_FREQUENCY = 16000000
|
const CPU_FREQUENCY = 16000000
|
||||||
|
|
||||||
// LED on the Arduino
|
// LED on the Arduino
|
||||||
const LED = 13
|
const LED Pin = 13
|
||||||
|
|
||||||
// ADC on the Arduino
|
// ADC on the Arduino
|
||||||
const (
|
const (
|
||||||
ADC0 = 0
|
ADC0 Pin = 0
|
||||||
ADC1 = 1
|
ADC1 Pin = 1
|
||||||
ADC2 = 2
|
ADC2 Pin = 2
|
||||||
ADC3 = 3
|
ADC3 Pin = 3
|
||||||
ADC4 = 4 // Used by TWI for SDA
|
ADC4 Pin = 4 // Used by TWI for SDA
|
||||||
ADC5 = 5 // Used by TWI for SCL
|
ADC5 Pin = 5 // Used by TWI for SCL
|
||||||
)
|
)
|
||||||
|
|
||||||
// UART pins
|
// UART pins
|
||||||
const (
|
const (
|
||||||
UART_TX_PIN = 1
|
UART_TX_PIN Pin = 1
|
||||||
UART_RX_PIN = 0
|
UART_RX_PIN Pin = 0
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ const (
|
|||||||
D8 = PB23
|
D8 = PB23
|
||||||
D9 = PA06
|
D9 = PA06
|
||||||
D10 = PA07
|
D10 = PA07
|
||||||
D11 = 0xff // does not seem to exist
|
D11 = NoPin // does not seem to exist
|
||||||
D12 = PA02
|
D12 = PA02
|
||||||
D13 = PA17 // PWM available
|
D13 = PA17 // PWM available
|
||||||
)
|
)
|
||||||
@@ -80,12 +80,12 @@ var (
|
|||||||
I2C0 = I2C{Bus: sam.SERCOM5_I2CM,
|
I2C0 = I2C{Bus: sam.SERCOM5_I2CM,
|
||||||
SDA: SDA_PIN,
|
SDA: SDA_PIN,
|
||||||
SCL: SCL_PIN,
|
SCL: SCL_PIN,
|
||||||
PinMode: GPIO_SERCOM}
|
PinMode: PinSERCOM}
|
||||||
// internal device
|
// internal device
|
||||||
I2C1 = I2C{Bus: sam.SERCOM1_I2CM,
|
I2C1 = I2C{Bus: sam.SERCOM1_I2CM,
|
||||||
SDA: SDA1_PIN,
|
SDA: SDA1_PIN,
|
||||||
SCL: SCL1_PIN,
|
SCL: SCL1_PIN,
|
||||||
PinMode: GPIO_SERCOM_ALT}
|
PinMode: PinSERCOMAlt}
|
||||||
)
|
)
|
||||||
|
|
||||||
// SPI pins (internal flash)
|
// SPI pins (internal flash)
|
||||||
@@ -104,7 +104,7 @@ var (
|
|||||||
const (
|
const (
|
||||||
I2S_SCK_PIN = PA10
|
I2S_SCK_PIN = PA10
|
||||||
I2S_SD_PIN = PA08
|
I2S_SD_PIN = PA08
|
||||||
I2S_WS_PIN = 0xff // no WS, instead uses SCK to sync
|
I2S_WS_PIN = NoPin // no WS, instead uses SCK to sync
|
||||||
)
|
)
|
||||||
|
|
||||||
// I2S on the Circuit Playground Express.
|
// I2S on the Circuit Playground Express.
|
||||||
|
|||||||
@@ -3,5 +3,5 @@
|
|||||||
package machine
|
package machine
|
||||||
|
|
||||||
const (
|
const (
|
||||||
LED = 1
|
LED Pin = 1
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -0,0 +1,82 @@
|
|||||||
|
// +build sam,atsamd21,feather_m0
|
||||||
|
|
||||||
|
package machine
|
||||||
|
|
||||||
|
import "device/sam"
|
||||||
|
|
||||||
|
// GPIO Pins
|
||||||
|
const (
|
||||||
|
D0 = PA11 // UART0 RX
|
||||||
|
D1 = PA10 // UART0 TX
|
||||||
|
D2 = NoPin // does not seem to exist
|
||||||
|
D3 = PA09
|
||||||
|
D4 = PA08
|
||||||
|
D5 = PA15 // PWM available
|
||||||
|
D6 = PA20 // PWM available
|
||||||
|
D7 = NoPin // does not seem to exist
|
||||||
|
D8 = PA06
|
||||||
|
D9 = PA07 // PWM available
|
||||||
|
D10 = PA18 // can be used for PWM or UART1 TX
|
||||||
|
D11 = PA16 // can be used for PWM or UART1 RX
|
||||||
|
D12 = PA19 // PWM available
|
||||||
|
D13 = PA17 // PWM available
|
||||||
|
)
|
||||||
|
|
||||||
|
// Analog pins
|
||||||
|
const (
|
||||||
|
A0 = PA02 // ADC/AIN[0]
|
||||||
|
A1 = PB08 // ADC/AIN[2]
|
||||||
|
A2 = PB09 // ADC/AIN[3]
|
||||||
|
A3 = PA04 // ADC/AIN[4]
|
||||||
|
A4 = PA05 // ADC/AIN[5]
|
||||||
|
A5 = PB02 // ADC/AIN[10]
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
LED = D13
|
||||||
|
)
|
||||||
|
|
||||||
|
// UART0 aka USBCDC pins
|
||||||
|
const (
|
||||||
|
USBCDC_DM_PIN = PA24
|
||||||
|
USBCDC_DP_PIN = PA25
|
||||||
|
)
|
||||||
|
|
||||||
|
// UART1 pins
|
||||||
|
const (
|
||||||
|
UART_TX_PIN = D10
|
||||||
|
UART_RX_PIN = D11
|
||||||
|
)
|
||||||
|
|
||||||
|
// I2C pins
|
||||||
|
const (
|
||||||
|
SDA_PIN = PA22 // SDA: SERCOM3/PAD[0]
|
||||||
|
SCL_PIN = PA23 // SCL: SERCOM3/PAD[1]
|
||||||
|
)
|
||||||
|
|
||||||
|
// I2C on the Feather M0.
|
||||||
|
var (
|
||||||
|
I2C0 = I2C{Bus: sam.SERCOM3_I2CM,
|
||||||
|
SDA: SDA_PIN,
|
||||||
|
SCL: SCL_PIN,
|
||||||
|
PinMode: PinSERCOM}
|
||||||
|
)
|
||||||
|
|
||||||
|
// SPI pins
|
||||||
|
const (
|
||||||
|
SPI0_SCK_PIN = PB11 // SCK: SERCOM4/PAD[3]
|
||||||
|
SPI0_MOSI_PIN = PB10 // MOSI: SERCOM4/PAD[2]
|
||||||
|
SPI0_MISO_PIN = PA12 // MISO: SERCOM4/PAD[0]
|
||||||
|
)
|
||||||
|
|
||||||
|
// SPI on the Feather M0.
|
||||||
|
var (
|
||||||
|
SPI0 = SPI{Bus: sam.SERCOM4_SPI}
|
||||||
|
)
|
||||||
|
|
||||||
|
// I2S pins
|
||||||
|
const (
|
||||||
|
I2S_SCK_PIN = PA10
|
||||||
|
I2S_SD_PIN = PA08
|
||||||
|
I2S_WS_PIN = NoPin // TODO: figure out what this is on Feather M0.
|
||||||
|
)
|
||||||
@@ -59,7 +59,7 @@ var (
|
|||||||
I2C0 = I2C{Bus: sam.SERCOM3_I2CM,
|
I2C0 = I2C{Bus: sam.SERCOM3_I2CM,
|
||||||
SDA: SDA_PIN,
|
SDA: SDA_PIN,
|
||||||
SCL: SCL_PIN,
|
SCL: SCL_PIN,
|
||||||
PinMode: GPIO_SERCOM}
|
PinMode: PinSERCOM}
|
||||||
)
|
)
|
||||||
|
|
||||||
// SPI pins
|
// SPI pins
|
||||||
@@ -78,7 +78,7 @@ var (
|
|||||||
const (
|
const (
|
||||||
I2S_SCK_PIN = PA10
|
I2S_SCK_PIN = PA10
|
||||||
I2S_SD_PIN = PA08
|
I2S_SD_PIN = PA08
|
||||||
I2S_WS_PIN = 0xff // TODO: figure out what this is on ItsyBitsy M0.
|
I2S_WS_PIN = NoPin // TODO: figure out what this is on ItsyBitsy M0.
|
||||||
)
|
)
|
||||||
|
|
||||||
// I2S on the ItsyBitsy M0.
|
// I2S on the ItsyBitsy M0.
|
||||||
|
|||||||
@@ -7,70 +7,70 @@ const HasLowFrequencyCrystal = false
|
|||||||
|
|
||||||
// Buttons on the micro:bit (A and B)
|
// Buttons on the micro:bit (A and B)
|
||||||
const (
|
const (
|
||||||
BUTTON = BUTTONA
|
BUTTON Pin = BUTTONA
|
||||||
BUTTONA = 17
|
BUTTONA Pin = 17
|
||||||
BUTTONB = 26
|
BUTTONB Pin = 26
|
||||||
)
|
)
|
||||||
|
|
||||||
// UART pins
|
// UART pins
|
||||||
const (
|
const (
|
||||||
UART_TX_PIN = 24
|
UART_TX_PIN Pin = 24
|
||||||
UART_RX_PIN = 25
|
UART_RX_PIN Pin = 25
|
||||||
)
|
)
|
||||||
|
|
||||||
// ADC pins
|
// ADC pins
|
||||||
const (
|
const (
|
||||||
ADC0 = 3 // P0 on the board
|
ADC0 Pin = 3 // P0 on the board
|
||||||
ADC1 = 2 // P1 on the board
|
ADC1 Pin = 2 // P1 on the board
|
||||||
ADC2 = 1 // P2 on the board
|
ADC2 Pin = 1 // P2 on the board
|
||||||
)
|
)
|
||||||
|
|
||||||
// I2C pins
|
// I2C pins
|
||||||
const (
|
const (
|
||||||
SDA_PIN = 30 // P20 on the board
|
SDA_PIN Pin = 30 // P20 on the board
|
||||||
SCL_PIN = 0 // P19 on the board
|
SCL_PIN Pin = 0 // P19 on the board
|
||||||
)
|
)
|
||||||
|
|
||||||
// SPI pins
|
// SPI pins
|
||||||
const (
|
const (
|
||||||
SPI0_SCK_PIN = 23 // P13 on the board
|
SPI0_SCK_PIN Pin = 23 // P13 on the board
|
||||||
SPI0_MOSI_PIN = 21 // P15 on the board
|
SPI0_MOSI_PIN Pin = 21 // P15 on the board
|
||||||
SPI0_MISO_PIN = 22 // P14 on the board
|
SPI0_MISO_PIN Pin = 22 // P14 on the board
|
||||||
)
|
)
|
||||||
|
|
||||||
// GPIO/Analog pins
|
// GPIO/Analog pins
|
||||||
const (
|
const (
|
||||||
P0 = 3
|
P0 Pin = 3
|
||||||
P1 = 2
|
P1 Pin = 2
|
||||||
P2 = 1
|
P2 Pin = 1
|
||||||
P3 = 4
|
P3 Pin = 4
|
||||||
P4 = 5
|
P4 Pin = 5
|
||||||
P5 = 17
|
P5 Pin = 17
|
||||||
P6 = 12
|
P6 Pin = 12
|
||||||
P7 = 11
|
P7 Pin = 11
|
||||||
P8 = 18
|
P8 Pin = 18
|
||||||
P9 = 10
|
P9 Pin = 10
|
||||||
P10 = 6
|
P10 Pin = 6
|
||||||
P11 = 26
|
P11 Pin = 26
|
||||||
P12 = 20
|
P12 Pin = 20
|
||||||
P13 = 23
|
P13 Pin = 23
|
||||||
P14 = 22
|
P14 Pin = 22
|
||||||
P15 = 21
|
P15 Pin = 21
|
||||||
P16 = 16
|
P16 Pin = 16
|
||||||
)
|
)
|
||||||
|
|
||||||
// LED matrix pins
|
// LED matrix pins
|
||||||
const (
|
const (
|
||||||
LED_COL_1 = 4
|
LED_COL_1 Pin = 4
|
||||||
LED_COL_2 = 5
|
LED_COL_2 Pin = 5
|
||||||
LED_COL_3 = 6
|
LED_COL_3 Pin = 6
|
||||||
LED_COL_4 = 7
|
LED_COL_4 Pin = 7
|
||||||
LED_COL_5 = 8
|
LED_COL_5 Pin = 8
|
||||||
LED_COL_6 = 9
|
LED_COL_6 Pin = 9
|
||||||
LED_COL_7 = 10
|
LED_COL_7 Pin = 10
|
||||||
LED_COL_8 = 11
|
LED_COL_8 Pin = 11
|
||||||
LED_COL_9 = 12
|
LED_COL_9 Pin = 12
|
||||||
LED_ROW_1 = 13
|
LED_ROW_1 Pin = 13
|
||||||
LED_ROW_2 = 14
|
LED_ROW_2 Pin = 14
|
||||||
LED_ROW_3 = 15
|
LED_ROW_3 Pin = 15
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -6,27 +6,27 @@ const HasLowFrequencyCrystal = true
|
|||||||
|
|
||||||
// LEDs on the nrf52840-mdk (nRF52840 dev board)
|
// LEDs on the nrf52840-mdk (nRF52840 dev board)
|
||||||
const (
|
const (
|
||||||
LED = LED_GREEN
|
LED Pin = LED_GREEN
|
||||||
LED_GREEN = 22
|
LED_GREEN Pin = 22
|
||||||
LED_RED = 23
|
LED_RED Pin = 23
|
||||||
LED_BLUE = 24
|
LED_BLUE Pin = 24
|
||||||
)
|
)
|
||||||
|
|
||||||
// UART pins
|
// UART pins
|
||||||
const (
|
const (
|
||||||
UART_TX_PIN = 20
|
UART_TX_PIN Pin = 20
|
||||||
UART_RX_PIN = 19
|
UART_RX_PIN Pin = 19
|
||||||
)
|
)
|
||||||
|
|
||||||
// I2C pins (unused)
|
// I2C pins (unused)
|
||||||
const (
|
const (
|
||||||
SDA_PIN = 0xff
|
SDA_PIN = NoPin
|
||||||
SCL_PIN = 0xff
|
SCL_PIN = NoPin
|
||||||
)
|
)
|
||||||
|
|
||||||
// SPI pins (unused)
|
// SPI pins (unused)
|
||||||
const (
|
const (
|
||||||
SPI0_SCK_PIN = 0
|
SPI0_SCK_PIN = NoPin
|
||||||
SPI0_MOSI_PIN = 0
|
SPI0_MOSI_PIN = NoPin
|
||||||
SPI0_MISO_PIN = 0
|
SPI0_MISO_PIN = NoPin
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -10,30 +10,30 @@ const HasLowFrequencyCrystal = true
|
|||||||
|
|
||||||
// LED on the pca10031
|
// LED on the pca10031
|
||||||
const (
|
const (
|
||||||
LED = LED_RED
|
LED Pin = LED_RED
|
||||||
LED1 = LED_RED
|
LED1 Pin = LED_RED
|
||||||
LED2 = LED_GREEN
|
LED2 Pin = LED_GREEN
|
||||||
LED3 = LED_BLUE
|
LED3 Pin = LED_BLUE
|
||||||
LED_RED = 21
|
LED_RED Pin = 21
|
||||||
LED_GREEN = 22
|
LED_GREEN Pin = 22
|
||||||
LED_BLUE = 23
|
LED_BLUE Pin = 23
|
||||||
)
|
)
|
||||||
|
|
||||||
// UART pins
|
// UART pins
|
||||||
const (
|
const (
|
||||||
UART_TX_PIN = 9
|
UART_TX_PIN Pin = 9
|
||||||
UART_RX_PIN = 11
|
UART_RX_PIN Pin = 11
|
||||||
)
|
)
|
||||||
|
|
||||||
// I2C pins (disabled)
|
// I2C pins (disabled)
|
||||||
const (
|
const (
|
||||||
SDA_PIN = 0xff
|
SDA_PIN = NoPin
|
||||||
SCL_PIN = 0xff
|
SCL_PIN = NoPin
|
||||||
)
|
)
|
||||||
|
|
||||||
// SPI pins (unused)
|
// SPI pins (unused)
|
||||||
const (
|
const (
|
||||||
SPI0_SCK_PIN = 0
|
SPI0_SCK_PIN = NoPin
|
||||||
SPI0_MOSI_PIN = 0
|
SPI0_MOSI_PIN = NoPin
|
||||||
SPI0_MISO_PIN = 0
|
SPI0_MISO_PIN = NoPin
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -7,47 +7,47 @@ const HasLowFrequencyCrystal = true
|
|||||||
|
|
||||||
// LEDs on the PCA10040 (nRF52832 dev board)
|
// LEDs on the PCA10040 (nRF52832 dev board)
|
||||||
const (
|
const (
|
||||||
LED = LED1
|
LED Pin = LED1
|
||||||
LED1 = 17
|
LED1 Pin = 17
|
||||||
LED2 = 18
|
LED2 Pin = 18
|
||||||
LED3 = 19
|
LED3 Pin = 19
|
||||||
LED4 = 20
|
LED4 Pin = 20
|
||||||
)
|
)
|
||||||
|
|
||||||
// Buttons on the PCA10040 (nRF52832 dev board)
|
// Buttons on the PCA10040 (nRF52832 dev board)
|
||||||
const (
|
const (
|
||||||
BUTTON = BUTTON1
|
BUTTON Pin = BUTTON1
|
||||||
BUTTON1 = 13
|
BUTTON1 Pin = 13
|
||||||
BUTTON2 = 14
|
BUTTON2 Pin = 14
|
||||||
BUTTON3 = 15
|
BUTTON3 Pin = 15
|
||||||
BUTTON4 = 16
|
BUTTON4 Pin = 16
|
||||||
)
|
)
|
||||||
|
|
||||||
// UART pins for NRF52840-DK
|
// UART pins for NRF52840-DK
|
||||||
const (
|
const (
|
||||||
UART_TX_PIN = 6
|
UART_TX_PIN Pin = 6
|
||||||
UART_RX_PIN = 8
|
UART_RX_PIN Pin = 8
|
||||||
)
|
)
|
||||||
|
|
||||||
// ADC pins
|
// ADC pins
|
||||||
const (
|
const (
|
||||||
ADC0 = 3
|
ADC0 Pin = 3
|
||||||
ADC1 = 4
|
ADC1 Pin = 4
|
||||||
ADC2 = 28
|
ADC2 Pin = 28
|
||||||
ADC3 = 29
|
ADC3 Pin = 29
|
||||||
ADC4 = 30
|
ADC4 Pin = 30
|
||||||
ADC5 = 31
|
ADC5 Pin = 31
|
||||||
)
|
)
|
||||||
|
|
||||||
// I2C pins
|
// I2C pins
|
||||||
const (
|
const (
|
||||||
SDA_PIN = 26
|
SDA_PIN Pin = 26
|
||||||
SCL_PIN = 27
|
SCL_PIN Pin = 27
|
||||||
)
|
)
|
||||||
|
|
||||||
// SPI pins
|
// SPI pins
|
||||||
const (
|
const (
|
||||||
SPI0_SCK_PIN = 25
|
SPI0_SCK_PIN Pin = 25
|
||||||
SPI0_MOSI_PIN = 23
|
SPI0_MOSI_PIN Pin = 23
|
||||||
SPI0_MISO_PIN = 24
|
SPI0_MISO_PIN Pin = 24
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -6,47 +6,47 @@ const HasLowFrequencyCrystal = true
|
|||||||
|
|
||||||
// LEDs on the pca10056
|
// LEDs on the pca10056
|
||||||
const (
|
const (
|
||||||
LED = LED1
|
LED Pin = LED1
|
||||||
LED1 = 13
|
LED1 Pin = 13
|
||||||
LED2 = 14
|
LED2 Pin = 14
|
||||||
LED3 = 15
|
LED3 Pin = 15
|
||||||
LED4 = 16
|
LED4 Pin = 16
|
||||||
)
|
)
|
||||||
|
|
||||||
// Buttons on the pca10056
|
// Buttons on the pca10056
|
||||||
const (
|
const (
|
||||||
BUTTON = BUTTON1
|
BUTTON Pin = BUTTON1
|
||||||
BUTTON1 = 11
|
BUTTON1 Pin = 11
|
||||||
BUTTON2 = 12
|
BUTTON2 Pin = 12
|
||||||
BUTTON3 = 24
|
BUTTON3 Pin = 24
|
||||||
BUTTON4 = 25
|
BUTTON4 Pin = 25
|
||||||
)
|
)
|
||||||
|
|
||||||
// UART pins
|
// UART pins
|
||||||
const (
|
const (
|
||||||
UART_TX_PIN = 6
|
UART_TX_PIN Pin = 6
|
||||||
UART_RX_PIN = 8
|
UART_RX_PIN Pin = 8
|
||||||
)
|
)
|
||||||
|
|
||||||
// ADC pins
|
// ADC pins
|
||||||
const (
|
const (
|
||||||
ADC0 = 3
|
ADC0 Pin = 3
|
||||||
ADC1 = 4
|
ADC1 Pin = 4
|
||||||
ADC2 = 28
|
ADC2 Pin = 28
|
||||||
ADC3 = 29
|
ADC3 Pin = 29
|
||||||
ADC4 = 30
|
ADC4 Pin = 30
|
||||||
ADC5 = 31
|
ADC5 Pin = 31
|
||||||
)
|
)
|
||||||
|
|
||||||
// I2C pins
|
// I2C pins
|
||||||
const (
|
const (
|
||||||
SDA_PIN = 26 // P0.26
|
SDA_PIN Pin = 26 // P0.26
|
||||||
SCL_PIN = 27 // P0.27
|
SCL_PIN Pin = 27 // P0.27
|
||||||
)
|
)
|
||||||
|
|
||||||
// SPI pins
|
// SPI pins
|
||||||
const (
|
const (
|
||||||
SPI0_SCK_PIN = 47 // P1.15
|
SPI0_SCK_PIN Pin = 47 // P1.15
|
||||||
SPI0_MOSI_PIN = 45 // P1.13
|
SPI0_MOSI_PIN Pin = 45 // P1.13
|
||||||
SPI0_MISO_PIN = 46 // P1.14
|
SPI0_MISO_PIN Pin = 46 // P1.14
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -6,37 +6,37 @@ const HasLowFrequencyCrystal = true
|
|||||||
|
|
||||||
// LEDs on the reel board
|
// LEDs on the reel board
|
||||||
const (
|
const (
|
||||||
LED = LED1
|
LED Pin = LED1
|
||||||
LED1 = LED_YELLOW
|
LED1 Pin = LED_YELLOW
|
||||||
LED2 = LED_RED
|
LED2 Pin = LED_RED
|
||||||
LED3 = LED_GREEN
|
LED3 Pin = LED_GREEN
|
||||||
LED4 = LED_BLUE
|
LED4 Pin = LED_BLUE
|
||||||
LED_RED = 11
|
LED_RED Pin = 11
|
||||||
LED_GREEN = 12
|
LED_GREEN Pin = 12
|
||||||
LED_BLUE = 41
|
LED_BLUE Pin = 41
|
||||||
LED_YELLOW = 13
|
LED_YELLOW Pin = 13
|
||||||
)
|
)
|
||||||
|
|
||||||
// User "a" button on the reel board
|
// User "a" button on the reel board
|
||||||
const (
|
const (
|
||||||
BUTTON = 7
|
BUTTON Pin = 7
|
||||||
)
|
)
|
||||||
|
|
||||||
// UART pins
|
// UART pins
|
||||||
const (
|
const (
|
||||||
UART_TX_PIN = 6
|
UART_TX_PIN Pin = 6
|
||||||
UART_RX_PIN = 8
|
UART_RX_PIN Pin = 8
|
||||||
)
|
)
|
||||||
|
|
||||||
// I2C pins
|
// I2C pins
|
||||||
const (
|
const (
|
||||||
SDA_PIN = 26
|
SDA_PIN Pin = 26
|
||||||
SCL_PIN = 27
|
SCL_PIN Pin = 27
|
||||||
)
|
)
|
||||||
|
|
||||||
// SPI pins
|
// SPI pins
|
||||||
const (
|
const (
|
||||||
SPI0_SCK_PIN = 47
|
SPI0_SCK_PIN Pin = 47
|
||||||
SPI0_MOSI_PIN = 45
|
SPI0_MOSI_PIN Pin = 45
|
||||||
SPI0_MISO_PIN = 46
|
SPI0_MISO_PIN Pin = 46
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -0,0 +1,73 @@
|
|||||||
|
// +build sam,atsamd21,trinket_m0
|
||||||
|
|
||||||
|
package machine
|
||||||
|
|
||||||
|
import "device/sam"
|
||||||
|
|
||||||
|
// GPIO Pins
|
||||||
|
const (
|
||||||
|
D0 = PA08 // PWM available
|
||||||
|
D1 = PA02
|
||||||
|
D2 = PA09 // PWM available
|
||||||
|
D3 = PA07 // PWM available / UART0 RX
|
||||||
|
D4 = PA06 // PWM available / UART0 TX
|
||||||
|
D13 = PA10 // LED
|
||||||
|
)
|
||||||
|
|
||||||
|
// Analog pins
|
||||||
|
const (
|
||||||
|
A0 = D1
|
||||||
|
A1 = D2
|
||||||
|
A2 = D0
|
||||||
|
A3 = D3
|
||||||
|
A4 = D4
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
LED = D13
|
||||||
|
)
|
||||||
|
|
||||||
|
// UART0 aka USBCDC pins
|
||||||
|
const (
|
||||||
|
USBCDC_DM_PIN = PA24
|
||||||
|
USBCDC_DP_PIN = PA25
|
||||||
|
)
|
||||||
|
|
||||||
|
// UART1 pins
|
||||||
|
const (
|
||||||
|
UART_TX_PIN = D4
|
||||||
|
UART_RX_PIN = D3
|
||||||
|
)
|
||||||
|
|
||||||
|
// SPI pins
|
||||||
|
const (
|
||||||
|
SPI0_SCK_PIN = D3
|
||||||
|
SPI0_MOSI_PIN = D4
|
||||||
|
SPI0_MISO_PIN = D2
|
||||||
|
)
|
||||||
|
|
||||||
|
// SPI on the Trinket M0.
|
||||||
|
var (
|
||||||
|
SPI0 = SPI{Bus: sam.SERCOM0_SPI}
|
||||||
|
)
|
||||||
|
|
||||||
|
// I2C pins
|
||||||
|
const (
|
||||||
|
SDA_PIN = D0 // SDA
|
||||||
|
SCL_PIN = D2 // SCL
|
||||||
|
)
|
||||||
|
|
||||||
|
// I2C on the Trinket M0.
|
||||||
|
var (
|
||||||
|
I2C0 = I2C{Bus: sam.SERCOM2_I2CM,
|
||||||
|
SDA: SDA_PIN,
|
||||||
|
SCL: SCL_PIN,
|
||||||
|
PinMode: PinSERCOMAlt}
|
||||||
|
)
|
||||||
|
|
||||||
|
// I2S pins
|
||||||
|
const (
|
||||||
|
I2S_SCK_PIN = PA10
|
||||||
|
I2S_SD_PIN = PA08
|
||||||
|
I2S_WS_PIN = NoPin // TODO: figure out what this is on Trinket M0.
|
||||||
|
)
|
||||||
+3
-3
@@ -41,9 +41,9 @@ const (
|
|||||||
|
|
||||||
// All fields are optional and may not be required or used on a particular platform.
|
// All fields are optional and may not be required or used on a particular platform.
|
||||||
type I2SConfig struct {
|
type I2SConfig struct {
|
||||||
SCK uint8
|
SCK Pin
|
||||||
WS uint8
|
WS Pin
|
||||||
SD uint8
|
SD Pin
|
||||||
Mode I2SMode
|
Mode I2SMode
|
||||||
Standard I2SStandard
|
Standard I2SStandard
|
||||||
ClockSource I2SClockSource
|
ClockSource I2SClockSource
|
||||||
|
|||||||
+20
-9
@@ -1,25 +1,36 @@
|
|||||||
package machine
|
package machine
|
||||||
|
|
||||||
type GPIOConfig struct {
|
type PinConfig struct {
|
||||||
Mode GPIOMode
|
Mode PinMode
|
||||||
}
|
}
|
||||||
|
|
||||||
type GPIO struct {
|
// Pin is a single pin on a chip, which may be connected to other hardware
|
||||||
Pin uint8
|
// devices. It can either be used directly as GPIO pin or it can be used in
|
||||||
}
|
// other peripherals like ADC, I2C, etc.
|
||||||
|
type Pin int8
|
||||||
|
|
||||||
func (p GPIO) High() {
|
// NoPin explicitly indicates "not a pin". Use this pin if you want to leave one
|
||||||
|
// of the pins in a peripheral unconfigured (if supported by the hardware).
|
||||||
|
const NoPin = Pin(-1)
|
||||||
|
|
||||||
|
// High sets this GPIO pin to high, assuming it has been configured as an output
|
||||||
|
// pin. It is hardware dependent (and often undefined) what happens if you set a
|
||||||
|
// pin to high that is not configured as an output pin.
|
||||||
|
func (p Pin) High() {
|
||||||
p.Set(true)
|
p.Set(true)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p GPIO) Low() {
|
// Low sets this GPIO pin to low, assuming it has been configured as an output
|
||||||
|
// pin. It is hardware dependent (and often undefined) what happens if you set a
|
||||||
|
// pin to low that is not configured as an output pin.
|
||||||
|
func (p Pin) Low() {
|
||||||
p.Set(false)
|
p.Set(false)
|
||||||
}
|
}
|
||||||
|
|
||||||
type PWM struct {
|
type PWM struct {
|
||||||
Pin uint8
|
Pin Pin
|
||||||
}
|
}
|
||||||
|
|
||||||
type ADC struct {
|
type ADC struct {
|
||||||
Pin uint8
|
Pin Pin
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,38 +7,38 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
// Configure sets the pin to input or output.
|
// Configure sets the pin to input or output.
|
||||||
func (p GPIO) Configure(config GPIOConfig) {
|
func (p Pin) Configure(config PinConfig) {
|
||||||
if config.Mode == GPIO_OUTPUT { // set output bit
|
if config.Mode == PinOutput { // set output bit
|
||||||
if p.Pin < 8 {
|
if p < 8 {
|
||||||
avr.DDRD.SetBits(1 << p.Pin)
|
avr.DDRD.SetBits(1 << uint8(p))
|
||||||
} else {
|
} else {
|
||||||
avr.DDRB.SetBits(1 << (p.Pin - 8))
|
avr.DDRB.SetBits(1 << uint8(p-8))
|
||||||
}
|
}
|
||||||
} else { // configure input: clear output bit
|
} else { // configure input: clear output bit
|
||||||
if p.Pin < 8 {
|
if p < 8 {
|
||||||
avr.DDRD.ClearBits(1 << p.Pin)
|
avr.DDRD.ClearBits(1 << uint8(p))
|
||||||
} else {
|
} else {
|
||||||
avr.DDRB.ClearBits(1 << (p.Pin - 8))
|
avr.DDRB.ClearBits(1 << uint8(p-8))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get returns the current value of a GPIO pin.
|
// Get returns the current value of a GPIO pin.
|
||||||
func (p GPIO) Get() bool {
|
func (p Pin) Get() bool {
|
||||||
if p.Pin < 8 {
|
if p < 8 {
|
||||||
val := avr.PIND.Get() & (1 << p.Pin)
|
val := avr.PIND.Get() & (1 << uint8(p))
|
||||||
return (val > 0)
|
return (val > 0)
|
||||||
} else {
|
} else {
|
||||||
val := avr.PINB.Get() & (1 << (p.Pin - 8))
|
val := avr.PINB.Get() & (1 << uint8(p-8))
|
||||||
return (val > 0)
|
return (val > 0)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p GPIO) getPortMask() (*avr.Register8, uint8) {
|
func (p Pin) getPortMask() (*avr.Register8, uint8) {
|
||||||
if p.Pin < 8 {
|
if p < 8 {
|
||||||
return avr.PORTD, 1 << p.Pin
|
return avr.PORTD, 1 << uint8(p)
|
||||||
} else {
|
} else {
|
||||||
return avr.PORTB, 1 << (p.Pin - 8)
|
return avr.PORTB, 1 << uint8(p-8)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -66,9 +66,9 @@ func InitPWM() {
|
|||||||
// Configure configures a PWM pin for output.
|
// Configure configures a PWM pin for output.
|
||||||
func (pwm PWM) Configure() {
|
func (pwm PWM) Configure() {
|
||||||
if pwm.Pin < 8 {
|
if pwm.Pin < 8 {
|
||||||
avr.DDRD.SetBits(1 << pwm.Pin)
|
avr.DDRD.SetBits(1 << uint8(pwm.Pin))
|
||||||
} else {
|
} else {
|
||||||
avr.DDRB.SetBits(1 << (pwm.Pin - 8))
|
avr.DDRB.SetBits(1 << uint8(pwm.Pin-8))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -165,7 +165,7 @@ func (i2c I2C) start(address uint8, write bool) {
|
|||||||
avr.TWCR.Set((avr.TWCR_TWINT | avr.TWCR_TWSTA | avr.TWCR_TWEN))
|
avr.TWCR.Set((avr.TWCR_TWINT | avr.TWCR_TWSTA | avr.TWCR_TWEN))
|
||||||
|
|
||||||
// Wait till start condition is transmitted.
|
// Wait till start condition is transmitted.
|
||||||
for (avr.TWCR.Get() & avr.TWCR_TWINT) == 0 {
|
for !avr.TWCR.HasBits(avr.TWCR_TWINT) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Write 7-bit shifted peripheral address.
|
// Write 7-bit shifted peripheral address.
|
||||||
@@ -182,7 +182,7 @@ func (i2c I2C) stop() {
|
|||||||
avr.TWCR.Set(avr.TWCR_TWEN | avr.TWCR_TWINT | avr.TWCR_TWSTO)
|
avr.TWCR.Set(avr.TWCR_TWEN | avr.TWCR_TWINT | avr.TWCR_TWSTO)
|
||||||
|
|
||||||
// Wait for stop condition to be executed on bus.
|
// Wait for stop condition to be executed on bus.
|
||||||
for (avr.TWCR.Get() & avr.TWCR_TWSTO) == 0 {
|
for !avr.TWCR.HasBits(avr.TWCR_TWSTO) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -195,7 +195,7 @@ func (i2c I2C) writeByte(data byte) {
|
|||||||
avr.TWCR.Set(avr.TWCR_TWEN | avr.TWCR_TWINT)
|
avr.TWCR.Set(avr.TWCR_TWEN | avr.TWCR_TWINT)
|
||||||
|
|
||||||
// Wait till data is transmitted.
|
// Wait till data is transmitted.
|
||||||
for (avr.TWCR.Get() & avr.TWCR_TWINT) == 0 {
|
for !avr.TWCR.HasBits(avr.TWCR_TWINT) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -205,7 +205,7 @@ func (i2c I2C) readByte() byte {
|
|||||||
avr.TWCR.Set(avr.TWCR_TWEN | avr.TWCR_TWINT | avr.TWCR_TWEA)
|
avr.TWCR.Set(avr.TWCR_TWEN | avr.TWCR_TWINT | avr.TWCR_TWEA)
|
||||||
|
|
||||||
// Wait till read request is transmitted.
|
// Wait till read request is transmitted.
|
||||||
for (avr.TWCR.Get() & avr.TWCR_TWINT) == 0 {
|
for !avr.TWCR.HasBits(avr.TWCR_TWINT) {
|
||||||
}
|
}
|
||||||
|
|
||||||
return byte(avr.TWDR.Get())
|
return byte(avr.TWDR.Get())
|
||||||
@@ -239,7 +239,7 @@ func (uart UART) Configure(config UARTConfig) {
|
|||||||
// WriteByte writes a byte of data to the UART.
|
// WriteByte writes a byte of data to the UART.
|
||||||
func (uart UART) WriteByte(c byte) error {
|
func (uart UART) WriteByte(c byte) error {
|
||||||
// Wait until UART buffer is not busy.
|
// Wait until UART buffer is not busy.
|
||||||
for (avr.UCSR0A.Get() & avr.UCSR0A_UDRE0) == 0 {
|
for !avr.UCSR0A.HasBits(avr.UCSR0A_UDRE0) {
|
||||||
}
|
}
|
||||||
avr.UDR0.Set(c) // send char
|
avr.UDR0.Set(c) // send char
|
||||||
return nil
|
return nil
|
||||||
@@ -251,7 +251,7 @@ func handleUSART_RX() {
|
|||||||
data := avr.UDR0.Get()
|
data := avr.UDR0.Get()
|
||||||
|
|
||||||
// Ensure no error.
|
// Ensure no error.
|
||||||
if (avr.UCSR0A.Get() & (avr.UCSR0A_FE0 | avr.UCSR0A_DOR0 | avr.UCSR0A_UPE0)) == 0 {
|
if !avr.UCSR0A.HasBits(avr.UCSR0A_FE0 | avr.UCSR0A_DOR0 | avr.UCSR0A_UPE0) {
|
||||||
// Put data from UDR register into buffer.
|
// Put data from UDR register into buffer.
|
||||||
UART0.Receive(byte(data))
|
UART0.Receive(byte(data))
|
||||||
}
|
}
|
||||||
|
|||||||
+425
-1027
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,334 @@
|
|||||||
|
// +build sam,atsamd21,atsamd21e18
|
||||||
|
|
||||||
|
// Peripheral abstraction layer for the atsamd21.
|
||||||
|
//
|
||||||
|
// Datasheet:
|
||||||
|
// http://ww1.microchip.com/downloads/en/DeviceDoc/SAMD21-Family-DataSheet-DS40001882D.pdf
|
||||||
|
//
|
||||||
|
package machine
|
||||||
|
|
||||||
|
import (
|
||||||
|
"device/sam"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Return the register and mask to enable a given GPIO pin. This can be used to
|
||||||
|
// implement bit-banged drivers.
|
||||||
|
func (p Pin) PortMaskSet() (*uint32, uint32) {
|
||||||
|
return &sam.PORT.OUTSET0.Reg, 1 << uint8(p)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return the register and mask to disable a given port. This can be used to
|
||||||
|
// implement bit-banged drivers.
|
||||||
|
func (p Pin) PortMaskClear() (*uint32, uint32) {
|
||||||
|
return &sam.PORT.OUTCLR0.Reg, 1 << uint8(p)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set the pin to high or low.
|
||||||
|
// Warning: only use this on an output pin!
|
||||||
|
func (p Pin) Set(high bool) {
|
||||||
|
if high {
|
||||||
|
sam.PORT.OUTSET0.Set(1 << uint8(p))
|
||||||
|
} else {
|
||||||
|
sam.PORT.OUTCLR0.Set(1 << uint8(p))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get returns the current value of a GPIO pin.
|
||||||
|
func (p Pin) Get() bool {
|
||||||
|
return (sam.PORT.IN0.Get()>>uint8(p))&1 > 0
|
||||||
|
}
|
||||||
|
|
||||||
|
// Configure this pin with the given configuration.
|
||||||
|
func (p Pin) Configure(config PinConfig) {
|
||||||
|
switch config.Mode {
|
||||||
|
case PinOutput:
|
||||||
|
sam.PORT.DIRSET0.Set(1 << uint8(p))
|
||||||
|
// output is also set to input enable so pin can read back its own value
|
||||||
|
p.setPinCfg(sam.PORT_PINCFG0_INEN)
|
||||||
|
|
||||||
|
case PinInput:
|
||||||
|
sam.PORT.DIRCLR0.Set(1 << uint8(p))
|
||||||
|
p.setPinCfg(sam.PORT_PINCFG0_INEN)
|
||||||
|
|
||||||
|
case PinInputPulldown:
|
||||||
|
sam.PORT.DIRCLR0.Set(1 << uint8(p))
|
||||||
|
sam.PORT.OUTCLR0.Set(1 << uint8(p))
|
||||||
|
p.setPinCfg(sam.PORT_PINCFG0_INEN | sam.PORT_PINCFG0_PULLEN)
|
||||||
|
|
||||||
|
case PinInputPullup:
|
||||||
|
sam.PORT.DIRCLR0.Set(1 << uint8(p))
|
||||||
|
sam.PORT.OUTSET0.Set(1 << uint8(p))
|
||||||
|
p.setPinCfg(sam.PORT_PINCFG0_INEN | sam.PORT_PINCFG0_PULLEN)
|
||||||
|
|
||||||
|
case PinSERCOM:
|
||||||
|
if uint8(p)&1 > 0 {
|
||||||
|
// odd pin, so save the even pins
|
||||||
|
val := p.getPMux() & sam.PORT_PMUX0_PMUXE_Msk
|
||||||
|
p.setPMux(val | (uint8(PinSERCOM) << sam.PORT_PMUX0_PMUXO_Pos))
|
||||||
|
} else {
|
||||||
|
// even pin, so save the odd pins
|
||||||
|
val := p.getPMux() & sam.PORT_PMUX0_PMUXO_Msk
|
||||||
|
p.setPMux(val | (uint8(PinSERCOM) << sam.PORT_PMUX0_PMUXE_Pos))
|
||||||
|
}
|
||||||
|
// enable port config
|
||||||
|
p.setPinCfg(sam.PORT_PINCFG0_PMUXEN | sam.PORT_PINCFG0_DRVSTR | sam.PORT_PINCFG0_INEN)
|
||||||
|
|
||||||
|
case PinSERCOMAlt:
|
||||||
|
if uint8(p)&1 > 0 {
|
||||||
|
// odd pin, so save the even pins
|
||||||
|
val := p.getPMux() & sam.PORT_PMUX0_PMUXE_Msk
|
||||||
|
p.setPMux(val | (uint8(PinSERCOMAlt) << sam.PORT_PMUX0_PMUXO_Pos))
|
||||||
|
} else {
|
||||||
|
// even pin, so save the odd pins
|
||||||
|
val := p.getPMux() & sam.PORT_PMUX0_PMUXO_Msk
|
||||||
|
p.setPMux(val | (uint8(PinSERCOMAlt) << sam.PORT_PMUX0_PMUXE_Pos))
|
||||||
|
}
|
||||||
|
// enable port config
|
||||||
|
p.setPinCfg(sam.PORT_PINCFG0_PMUXEN | sam.PORT_PINCFG0_DRVSTR)
|
||||||
|
|
||||||
|
case PinCom:
|
||||||
|
if uint8(p)&1 > 0 {
|
||||||
|
// odd pin, so save the even pins
|
||||||
|
val := p.getPMux() & sam.PORT_PMUX0_PMUXE_Msk
|
||||||
|
p.setPMux(val | (uint8(PinCom) << sam.PORT_PMUX0_PMUXO_Pos))
|
||||||
|
} else {
|
||||||
|
// even pin, so save the odd pins
|
||||||
|
val := p.getPMux() & sam.PORT_PMUX0_PMUXO_Msk
|
||||||
|
p.setPMux(val | (uint8(PinCom) << sam.PORT_PMUX0_PMUXE_Pos))
|
||||||
|
}
|
||||||
|
// enable port config
|
||||||
|
p.setPinCfg(sam.PORT_PINCFG0_PMUXEN)
|
||||||
|
case PinAnalog:
|
||||||
|
if uint8(p)&1 > 0 {
|
||||||
|
// odd pin, so save the even pins
|
||||||
|
val := p.getPMux() & sam.PORT_PMUX0_PMUXE_Msk
|
||||||
|
p.setPMux(val | (uint8(PinAnalog) << sam.PORT_PMUX0_PMUXO_Pos))
|
||||||
|
} else {
|
||||||
|
// even pin, so save the odd pins
|
||||||
|
val := p.getPMux() & sam.PORT_PMUX0_PMUXO_Msk
|
||||||
|
p.setPMux(val | (uint8(PinAnalog) << sam.PORT_PMUX0_PMUXE_Pos))
|
||||||
|
}
|
||||||
|
// enable port config
|
||||||
|
p.setPinCfg(sam.PORT_PINCFG0_PMUXEN | sam.PORT_PINCFG0_DRVSTR)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// getPMux returns the value for the correct PMUX register for this pin.
|
||||||
|
func (p Pin) getPMux() uint8 {
|
||||||
|
switch p >> 1 {
|
||||||
|
case 0:
|
||||||
|
return sam.PORT.PMUX0_0.Get()
|
||||||
|
case 1:
|
||||||
|
return sam.PORT.PMUX0_1.Get()
|
||||||
|
case 2:
|
||||||
|
return sam.PORT.PMUX0_2.Get()
|
||||||
|
case 3:
|
||||||
|
return sam.PORT.PMUX0_3.Get()
|
||||||
|
case 4:
|
||||||
|
return sam.PORT.PMUX0_4.Get()
|
||||||
|
case 5:
|
||||||
|
return sam.PORT.PMUX0_5.Get()
|
||||||
|
case 6:
|
||||||
|
return sam.PORT.PMUX0_6.Get()
|
||||||
|
case 7:
|
||||||
|
return sam.PORT.PMUX0_7.Get()
|
||||||
|
case 8:
|
||||||
|
return sam.PORT.PMUX0_8.Get()
|
||||||
|
case 9:
|
||||||
|
return sam.PORT.PMUX0_9.Get()
|
||||||
|
case 10:
|
||||||
|
return sam.PORT.PMUX0_10.Get()
|
||||||
|
case 11:
|
||||||
|
return sam.PORT.PMUX0_11.Get()
|
||||||
|
case 12:
|
||||||
|
return sam.PORT.PMUX0_12.Get()
|
||||||
|
case 13:
|
||||||
|
return sam.PORT.PMUX0_13.Get()
|
||||||
|
case 14:
|
||||||
|
return sam.PORT.PMUX0_14.Get()
|
||||||
|
case 15:
|
||||||
|
return sam.PORT.PMUX0_15.Get()
|
||||||
|
default:
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// setPMux sets the value for the correct PMUX register for this pin.
|
||||||
|
func (p Pin) setPMux(val uint8) {
|
||||||
|
switch p >> 1 {
|
||||||
|
case 0:
|
||||||
|
sam.PORT.PMUX0_0.Set(val)
|
||||||
|
case 1:
|
||||||
|
sam.PORT.PMUX0_1.Set(val)
|
||||||
|
case 2:
|
||||||
|
sam.PORT.PMUX0_2.Set(val)
|
||||||
|
case 3:
|
||||||
|
sam.PORT.PMUX0_3.Set(val)
|
||||||
|
case 4:
|
||||||
|
sam.PORT.PMUX0_4.Set(val)
|
||||||
|
case 5:
|
||||||
|
sam.PORT.PMUX0_5.Set(val)
|
||||||
|
case 6:
|
||||||
|
sam.PORT.PMUX0_6.Set(val)
|
||||||
|
case 7:
|
||||||
|
sam.PORT.PMUX0_7.Set(val)
|
||||||
|
case 8:
|
||||||
|
sam.PORT.PMUX0_8.Set(val)
|
||||||
|
case 9:
|
||||||
|
sam.PORT.PMUX0_9.Set(val)
|
||||||
|
case 10:
|
||||||
|
sam.PORT.PMUX0_10.Set(val)
|
||||||
|
case 11:
|
||||||
|
sam.PORT.PMUX0_11.Set(val)
|
||||||
|
case 12:
|
||||||
|
sam.PORT.PMUX0_12.Set(val)
|
||||||
|
case 13:
|
||||||
|
sam.PORT.PMUX0_13.Set(val)
|
||||||
|
case 14:
|
||||||
|
sam.PORT.PMUX0_14.Set(val)
|
||||||
|
case 15:
|
||||||
|
sam.PORT.PMUX0_15.Set(val)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// getPinCfg returns the value for the correct PINCFG register for this pin.
|
||||||
|
func (p Pin) getPinCfg() uint8 {
|
||||||
|
switch p {
|
||||||
|
case 0:
|
||||||
|
return sam.PORT.PINCFG0_0.Get()
|
||||||
|
case 1:
|
||||||
|
return sam.PORT.PINCFG0_1.Get()
|
||||||
|
case 2:
|
||||||
|
return sam.PORT.PINCFG0_2.Get()
|
||||||
|
case 3:
|
||||||
|
return sam.PORT.PINCFG0_3.Get()
|
||||||
|
case 4:
|
||||||
|
return sam.PORT.PINCFG0_4.Get()
|
||||||
|
case 5:
|
||||||
|
return sam.PORT.PINCFG0_5.Get()
|
||||||
|
case 6:
|
||||||
|
return sam.PORT.PINCFG0_6.Get()
|
||||||
|
case 7:
|
||||||
|
return sam.PORT.PINCFG0_7.Get()
|
||||||
|
case 8:
|
||||||
|
return sam.PORT.PINCFG0_8.Get()
|
||||||
|
case 9:
|
||||||
|
return sam.PORT.PINCFG0_9.Get()
|
||||||
|
case 10:
|
||||||
|
return sam.PORT.PINCFG0_10.Get()
|
||||||
|
case 11:
|
||||||
|
return sam.PORT.PINCFG0_11.Get()
|
||||||
|
case 12:
|
||||||
|
return sam.PORT.PINCFG0_12.Get()
|
||||||
|
case 13:
|
||||||
|
return sam.PORT.PINCFG0_13.Get()
|
||||||
|
case 14:
|
||||||
|
return sam.PORT.PINCFG0_14.Get()
|
||||||
|
case 15:
|
||||||
|
return sam.PORT.PINCFG0_15.Get()
|
||||||
|
case 16:
|
||||||
|
return sam.PORT.PINCFG0_16.Get()
|
||||||
|
case 17:
|
||||||
|
return sam.PORT.PINCFG0_17.Get()
|
||||||
|
case 18:
|
||||||
|
return sam.PORT.PINCFG0_18.Get()
|
||||||
|
case 19:
|
||||||
|
return sam.PORT.PINCFG0_19.Get()
|
||||||
|
case 20:
|
||||||
|
return sam.PORT.PINCFG0_20.Get()
|
||||||
|
case 21:
|
||||||
|
return sam.PORT.PINCFG0_21.Get()
|
||||||
|
case 22:
|
||||||
|
return sam.PORT.PINCFG0_22.Get()
|
||||||
|
case 23:
|
||||||
|
return sam.PORT.PINCFG0_23.Get()
|
||||||
|
case 24:
|
||||||
|
return sam.PORT.PINCFG0_24.Get()
|
||||||
|
case 25:
|
||||||
|
return sam.PORT.PINCFG0_25.Get()
|
||||||
|
case 26:
|
||||||
|
return sam.PORT.PINCFG0_26.Get()
|
||||||
|
case 27:
|
||||||
|
return sam.PORT.PINCFG0_27.Get()
|
||||||
|
case 28:
|
||||||
|
return sam.PORT.PINCFG0_28.Get()
|
||||||
|
case 29:
|
||||||
|
return sam.PORT.PINCFG0_29.Get()
|
||||||
|
case 30:
|
||||||
|
return sam.PORT.PINCFG0_30.Get()
|
||||||
|
case 31:
|
||||||
|
return sam.PORT.PINCFG0_31.Get()
|
||||||
|
default:
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// setPinCfg sets the value for the correct PINCFG register for this pin.
|
||||||
|
func (p Pin) setPinCfg(val uint8) {
|
||||||
|
switch p {
|
||||||
|
case 0:
|
||||||
|
sam.PORT.PINCFG0_0.Set(val)
|
||||||
|
case 1:
|
||||||
|
sam.PORT.PINCFG0_1.Set(val)
|
||||||
|
case 2:
|
||||||
|
sam.PORT.PINCFG0_2.Set(val)
|
||||||
|
case 3:
|
||||||
|
sam.PORT.PINCFG0_3.Set(val)
|
||||||
|
case 4:
|
||||||
|
sam.PORT.PINCFG0_4.Set(val)
|
||||||
|
case 5:
|
||||||
|
sam.PORT.PINCFG0_5.Set(val)
|
||||||
|
case 6:
|
||||||
|
sam.PORT.PINCFG0_6.Set(val)
|
||||||
|
case 7:
|
||||||
|
sam.PORT.PINCFG0_7.Set(val)
|
||||||
|
case 8:
|
||||||
|
sam.PORT.PINCFG0_8.Set(val)
|
||||||
|
case 9:
|
||||||
|
sam.PORT.PINCFG0_9.Set(val)
|
||||||
|
case 10:
|
||||||
|
sam.PORT.PINCFG0_10.Set(val)
|
||||||
|
case 11:
|
||||||
|
sam.PORT.PINCFG0_11.Set(val)
|
||||||
|
case 12:
|
||||||
|
sam.PORT.PINCFG0_12.Set(val)
|
||||||
|
case 13:
|
||||||
|
sam.PORT.PINCFG0_13.Set(val)
|
||||||
|
case 14:
|
||||||
|
sam.PORT.PINCFG0_14.Set(val)
|
||||||
|
case 15:
|
||||||
|
sam.PORT.PINCFG0_15.Set(val)
|
||||||
|
case 16:
|
||||||
|
sam.PORT.PINCFG0_16.Set(val)
|
||||||
|
case 17:
|
||||||
|
sam.PORT.PINCFG0_17.Set(val)
|
||||||
|
case 18:
|
||||||
|
sam.PORT.PINCFG0_18.Set(val)
|
||||||
|
case 19:
|
||||||
|
sam.PORT.PINCFG0_19.Set(val)
|
||||||
|
case 20:
|
||||||
|
sam.PORT.PINCFG0_20.Set(val)
|
||||||
|
case 21:
|
||||||
|
sam.PORT.PINCFG0_21.Set(val)
|
||||||
|
case 22:
|
||||||
|
sam.PORT.PINCFG0_22.Set(val)
|
||||||
|
case 23:
|
||||||
|
sam.PORT.PINCFG0_23.Set(val)
|
||||||
|
case 24:
|
||||||
|
sam.PORT.PINCFG0_24.Set(val)
|
||||||
|
case 25:
|
||||||
|
sam.PORT.PINCFG0_25.Set(val)
|
||||||
|
case 26:
|
||||||
|
sam.PORT.PINCFG0_26.Set(val)
|
||||||
|
case 27:
|
||||||
|
sam.PORT.PINCFG0_27.Set(val)
|
||||||
|
case 28:
|
||||||
|
sam.PORT.PINCFG0_28.Set(val)
|
||||||
|
case 29:
|
||||||
|
sam.PORT.PINCFG0_29.Set(val)
|
||||||
|
case 30:
|
||||||
|
sam.PORT.PINCFG0_30.Set(val)
|
||||||
|
case 31:
|
||||||
|
sam.PORT.PINCFG0_31.Set(val)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,569 @@
|
|||||||
|
// +build sam,atsamd21,atsamd21g18
|
||||||
|
|
||||||
|
// Peripheral abstraction layer for the atsamd21.
|
||||||
|
//
|
||||||
|
// Datasheet:
|
||||||
|
// http://ww1.microchip.com/downloads/en/DeviceDoc/SAMD21-Family-DataSheet-DS40001882D.pdf
|
||||||
|
//
|
||||||
|
package machine
|
||||||
|
|
||||||
|
import (
|
||||||
|
"device/sam"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Return the register and mask to enable a given GPIO pin. This can be used to
|
||||||
|
// implement bit-banged drivers.
|
||||||
|
func (p Pin) PortMaskSet() (*uint32, uint32) {
|
||||||
|
if p < 32 {
|
||||||
|
return &sam.PORT.OUTSET0.Reg, 1 << uint8(p)
|
||||||
|
} else {
|
||||||
|
return &sam.PORT.OUTSET1.Reg, 1 << uint8(p-32)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return the register and mask to disable a given port. This can be used to
|
||||||
|
// implement bit-banged drivers.
|
||||||
|
func (p Pin) PortMaskClear() (*uint32, uint32) {
|
||||||
|
if p < 32 {
|
||||||
|
return &sam.PORT.OUTCLR0.Reg, 1 << uint8(p)
|
||||||
|
} else {
|
||||||
|
return &sam.PORT.OUTCLR1.Reg, 1 << uint8(p-32)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set the pin to high or low.
|
||||||
|
// Warning: only use this on an output pin!
|
||||||
|
func (p Pin) Set(high bool) {
|
||||||
|
if p < 32 {
|
||||||
|
if high {
|
||||||
|
sam.PORT.OUTSET0.Set(1 << uint8(p))
|
||||||
|
} else {
|
||||||
|
sam.PORT.OUTCLR0.Set(1 << uint8(p))
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if high {
|
||||||
|
sam.PORT.OUTSET1.Set(1 << uint8(p-32))
|
||||||
|
} else {
|
||||||
|
sam.PORT.OUTCLR1.Set(1 << uint8(p-32))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get returns the current value of a GPIO pin.
|
||||||
|
func (p Pin) Get() bool {
|
||||||
|
if p < 32 {
|
||||||
|
return (sam.PORT.IN0.Get()>>uint8(p))&1 > 0
|
||||||
|
} else {
|
||||||
|
return (sam.PORT.IN1.Get()>>(uint8(p)-32))&1 > 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Configure this pin with the given configuration.
|
||||||
|
func (p Pin) Configure(config PinConfig) {
|
||||||
|
switch config.Mode {
|
||||||
|
case PinOutput:
|
||||||
|
if p < 32 {
|
||||||
|
sam.PORT.DIRSET0.Set(1 << uint8(p))
|
||||||
|
// output is also set to input enable so pin can read back its own value
|
||||||
|
p.setPinCfg(sam.PORT_PINCFG0_INEN)
|
||||||
|
} else {
|
||||||
|
sam.PORT.DIRSET1.Set(1 << uint8(p-32))
|
||||||
|
// output is also set to input enable so pin can read back its own value
|
||||||
|
p.setPinCfg(sam.PORT_PINCFG0_INEN)
|
||||||
|
}
|
||||||
|
|
||||||
|
case PinInput:
|
||||||
|
if p < 32 {
|
||||||
|
sam.PORT.DIRCLR0.Set(1 << uint8(p))
|
||||||
|
p.setPinCfg(sam.PORT_PINCFG0_INEN)
|
||||||
|
} else {
|
||||||
|
sam.PORT.DIRCLR1.Set(1<<uint8(p) - 32)
|
||||||
|
p.setPinCfg(sam.PORT_PINCFG0_INEN)
|
||||||
|
}
|
||||||
|
|
||||||
|
case PinInputPulldown:
|
||||||
|
if p < 32 {
|
||||||
|
sam.PORT.DIRCLR0.Set(1 << uint8(p))
|
||||||
|
sam.PORT.OUTCLR0.Set(1 << uint8(p))
|
||||||
|
p.setPinCfg(sam.PORT_PINCFG0_INEN | sam.PORT_PINCFG0_PULLEN)
|
||||||
|
} else {
|
||||||
|
sam.PORT.DIRCLR1.Set(1<<uint8(p) - 32)
|
||||||
|
sam.PORT.OUTCLR1.Set(1<<uint8(p) - 32)
|
||||||
|
p.setPinCfg(sam.PORT_PINCFG0_INEN | sam.PORT_PINCFG0_PULLEN)
|
||||||
|
}
|
||||||
|
|
||||||
|
case PinInputPullup:
|
||||||
|
if p < 32 {
|
||||||
|
sam.PORT.DIRCLR0.Set(1 << uint8(p))
|
||||||
|
sam.PORT.OUTSET0.Set(1 << uint8(p))
|
||||||
|
p.setPinCfg(sam.PORT_PINCFG0_INEN | sam.PORT_PINCFG0_PULLEN)
|
||||||
|
} else {
|
||||||
|
sam.PORT.DIRCLR1.Set(1<<uint8(p) - 32)
|
||||||
|
sam.PORT.OUTSET1.Set(1<<uint8(p) - 32)
|
||||||
|
p.setPinCfg(sam.PORT_PINCFG0_INEN | sam.PORT_PINCFG0_PULLEN)
|
||||||
|
}
|
||||||
|
|
||||||
|
case PinSERCOM:
|
||||||
|
if p&1 > 0 {
|
||||||
|
// odd pin, so save the even pins
|
||||||
|
val := p.getPMux() & sam.PORT_PMUX0_PMUXE_Msk
|
||||||
|
p.setPMux(val | (uint8(PinSERCOM) << sam.PORT_PMUX0_PMUXO_Pos))
|
||||||
|
} else {
|
||||||
|
// even pin, so save the odd pins
|
||||||
|
val := p.getPMux() & sam.PORT_PMUX0_PMUXO_Msk
|
||||||
|
p.setPMux(val | (uint8(PinSERCOM) << sam.PORT_PMUX0_PMUXE_Pos))
|
||||||
|
}
|
||||||
|
// enable port config
|
||||||
|
p.setPinCfg(sam.PORT_PINCFG0_PMUXEN | sam.PORT_PINCFG0_DRVSTR | sam.PORT_PINCFG0_INEN)
|
||||||
|
|
||||||
|
case PinSERCOMAlt:
|
||||||
|
if p&1 > 0 {
|
||||||
|
// odd pin, so save the even pins
|
||||||
|
val := p.getPMux() & sam.PORT_PMUX0_PMUXE_Msk
|
||||||
|
p.setPMux(val | (uint8(PinSERCOMAlt) << sam.PORT_PMUX0_PMUXO_Pos))
|
||||||
|
} else {
|
||||||
|
// even pin, so save the odd pins
|
||||||
|
val := p.getPMux() & sam.PORT_PMUX0_PMUXO_Msk
|
||||||
|
p.setPMux(val | (uint8(PinSERCOMAlt) << sam.PORT_PMUX0_PMUXE_Pos))
|
||||||
|
}
|
||||||
|
// enable port config
|
||||||
|
p.setPinCfg(sam.PORT_PINCFG0_PMUXEN | sam.PORT_PINCFG0_DRVSTR)
|
||||||
|
|
||||||
|
case PinCom:
|
||||||
|
if p&1 > 0 {
|
||||||
|
// odd pin, so save the even pins
|
||||||
|
val := p.getPMux() & sam.PORT_PMUX0_PMUXE_Msk
|
||||||
|
p.setPMux(val | (uint8(PinCom) << sam.PORT_PMUX0_PMUXO_Pos))
|
||||||
|
} else {
|
||||||
|
// even pin, so save the odd pins
|
||||||
|
val := p.getPMux() & sam.PORT_PMUX0_PMUXO_Msk
|
||||||
|
p.setPMux(val | (uint8(PinCom) << sam.PORT_PMUX0_PMUXE_Pos))
|
||||||
|
}
|
||||||
|
// enable port config
|
||||||
|
p.setPinCfg(sam.PORT_PINCFG0_PMUXEN)
|
||||||
|
case PinAnalog:
|
||||||
|
if p&1 > 0 {
|
||||||
|
// odd pin, so save the even pins
|
||||||
|
val := p.getPMux() & sam.PORT_PMUX0_PMUXE_Msk
|
||||||
|
p.setPMux(val | (uint8(PinAnalog) << sam.PORT_PMUX0_PMUXO_Pos))
|
||||||
|
} else {
|
||||||
|
// even pin, so save the odd pins
|
||||||
|
val := p.getPMux() & sam.PORT_PMUX0_PMUXO_Msk
|
||||||
|
p.setPMux(val | (uint8(PinAnalog) << sam.PORT_PMUX0_PMUXE_Pos))
|
||||||
|
}
|
||||||
|
// enable port config
|
||||||
|
p.setPinCfg(sam.PORT_PINCFG0_PMUXEN | sam.PORT_PINCFG0_DRVSTR)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// getPMux returns the value for the correct PMUX register for this pin.
|
||||||
|
func (p Pin) getPMux() uint8 {
|
||||||
|
switch uint8(p) >> 1 {
|
||||||
|
case 0:
|
||||||
|
return sam.PORT.PMUX0_0.Get()
|
||||||
|
case 1:
|
||||||
|
return sam.PORT.PMUX0_1.Get()
|
||||||
|
case 2:
|
||||||
|
return sam.PORT.PMUX0_2.Get()
|
||||||
|
case 3:
|
||||||
|
return sam.PORT.PMUX0_3.Get()
|
||||||
|
case 4:
|
||||||
|
return sam.PORT.PMUX0_4.Get()
|
||||||
|
case 5:
|
||||||
|
return sam.PORT.PMUX0_5.Get()
|
||||||
|
case 6:
|
||||||
|
return sam.PORT.PMUX0_6.Get()
|
||||||
|
case 7:
|
||||||
|
return sam.PORT.PMUX0_7.Get()
|
||||||
|
case 8:
|
||||||
|
return sam.PORT.PMUX0_8.Get()
|
||||||
|
case 9:
|
||||||
|
return sam.PORT.PMUX0_9.Get()
|
||||||
|
case 10:
|
||||||
|
return sam.PORT.PMUX0_10.Get()
|
||||||
|
case 11:
|
||||||
|
return sam.PORT.PMUX0_11.Get()
|
||||||
|
case 12:
|
||||||
|
return sam.PORT.PMUX0_12.Get()
|
||||||
|
case 13:
|
||||||
|
return sam.PORT.PMUX0_13.Get()
|
||||||
|
case 14:
|
||||||
|
return sam.PORT.PMUX0_14.Get()
|
||||||
|
case 15:
|
||||||
|
return sam.PORT.PMUX0_15.Get()
|
||||||
|
case 16:
|
||||||
|
return uint8(sam.PORT.PMUX1_0.Get()>>0) & 0xff
|
||||||
|
case 17:
|
||||||
|
return uint8(sam.PORT.PMUX1_0.Get()>>8) & 0xff
|
||||||
|
case 18:
|
||||||
|
return uint8(sam.PORT.PMUX1_0.Get()>>16) & 0xff
|
||||||
|
case 19:
|
||||||
|
return uint8(sam.PORT.PMUX1_0.Get()>>24) & 0xff
|
||||||
|
case 20:
|
||||||
|
return uint8(sam.PORT.PMUX1_4.Get()>>0) & 0xff
|
||||||
|
case 21:
|
||||||
|
return uint8(sam.PORT.PMUX1_4.Get()>>8) & 0xff
|
||||||
|
case 22:
|
||||||
|
return uint8(sam.PORT.PMUX1_4.Get()>>16) & 0xff
|
||||||
|
case 23:
|
||||||
|
return uint8(sam.PORT.PMUX1_4.Get()>>24) & 0xff
|
||||||
|
case 24:
|
||||||
|
return uint8(sam.PORT.PMUX1_8.Get()>>0) & 0xff
|
||||||
|
case 25:
|
||||||
|
return uint8(sam.PORT.PMUX1_8.Get()>>8) & 0xff
|
||||||
|
case 26:
|
||||||
|
return uint8(sam.PORT.PMUX1_8.Get()>>16) & 0xff
|
||||||
|
case 27:
|
||||||
|
return uint8(sam.PORT.PMUX1_8.Get()>>24) & 0xff
|
||||||
|
case 28:
|
||||||
|
return uint8(sam.PORT.PMUX1_12.Get()>>0) & 0xff
|
||||||
|
case 29:
|
||||||
|
return uint8(sam.PORT.PMUX1_12.Get()>>8) & 0xff
|
||||||
|
case 30:
|
||||||
|
return uint8(sam.PORT.PMUX1_12.Get()>>16) & 0xff
|
||||||
|
case 31:
|
||||||
|
return uint8(sam.PORT.PMUX1_12.Get()>>24) & 0xff
|
||||||
|
default:
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// setPMux sets the value for the correct PMUX register for this pin.
|
||||||
|
func (p Pin) setPMux(val uint8) {
|
||||||
|
switch uint8(p) >> 1 {
|
||||||
|
case 0:
|
||||||
|
sam.PORT.PMUX0_0.Set(val)
|
||||||
|
case 1:
|
||||||
|
sam.PORT.PMUX0_1.Set(val)
|
||||||
|
case 2:
|
||||||
|
sam.PORT.PMUX0_2.Set(val)
|
||||||
|
case 3:
|
||||||
|
sam.PORT.PMUX0_3.Set(val)
|
||||||
|
case 4:
|
||||||
|
sam.PORT.PMUX0_4.Set(val)
|
||||||
|
case 5:
|
||||||
|
sam.PORT.PMUX0_5.Set(val)
|
||||||
|
case 6:
|
||||||
|
sam.PORT.PMUX0_6.Set(val)
|
||||||
|
case 7:
|
||||||
|
sam.PORT.PMUX0_7.Set(val)
|
||||||
|
case 8:
|
||||||
|
sam.PORT.PMUX0_8.Set(val)
|
||||||
|
case 9:
|
||||||
|
sam.PORT.PMUX0_9.Set(val)
|
||||||
|
case 10:
|
||||||
|
sam.PORT.PMUX0_10.Set(val)
|
||||||
|
case 11:
|
||||||
|
sam.PORT.PMUX0_11.Set(val)
|
||||||
|
case 12:
|
||||||
|
sam.PORT.PMUX0_12.Set(val)
|
||||||
|
case 13:
|
||||||
|
sam.PORT.PMUX0_13.Set(val)
|
||||||
|
case 14:
|
||||||
|
sam.PORT.PMUX0_14.Set(val)
|
||||||
|
case 15:
|
||||||
|
sam.PORT.PMUX0_15.Set(val)
|
||||||
|
case 16:
|
||||||
|
sam.PORT.PMUX1_0.Set(sam.PORT.PMUX1_0.Get()&^(0xff<<0) | (uint32(val) << 0))
|
||||||
|
case 17:
|
||||||
|
sam.PORT.PMUX1_0.Set(sam.PORT.PMUX1_0.Get()&^(0xff<<8) | (uint32(val) << 8))
|
||||||
|
case 18:
|
||||||
|
sam.PORT.PMUX1_0.Set(sam.PORT.PMUX1_0.Get()&^(0xff<<16) | (uint32(val) << 16))
|
||||||
|
case 19:
|
||||||
|
sam.PORT.PMUX1_0.Set(sam.PORT.PMUX1_0.Get()&^(0xff<<24) | (uint32(val) << 24))
|
||||||
|
case 20:
|
||||||
|
sam.PORT.PMUX1_4.Set(sam.PORT.PMUX1_4.Get()&^(0xff<<0) | (uint32(val) << 0))
|
||||||
|
case 21:
|
||||||
|
sam.PORT.PMUX1_4.Set(sam.PORT.PMUX1_4.Get()&^(0xff<<8) | (uint32(val) << 8))
|
||||||
|
case 22:
|
||||||
|
sam.PORT.PMUX1_4.Set(sam.PORT.PMUX1_4.Get()&^(0xff<<16) | (uint32(val) << 16))
|
||||||
|
case 23:
|
||||||
|
sam.PORT.PMUX1_4.Set(sam.PORT.PMUX1_4.Get()&^(0xff<<24) | (uint32(val) << 24))
|
||||||
|
case 24:
|
||||||
|
sam.PORT.PMUX1_8.Set(sam.PORT.PMUX1_8.Get()&^(0xff<<0) | (uint32(val) << 0))
|
||||||
|
case 25:
|
||||||
|
sam.PORT.PMUX1_8.Set(sam.PORT.PMUX1_8.Get()&^(0xff<<8) | (uint32(val) << 8))
|
||||||
|
case 26:
|
||||||
|
sam.PORT.PMUX1_8.Set(sam.PORT.PMUX1_8.Get()&^(0xff<<16) | (uint32(val) << 16))
|
||||||
|
case 27:
|
||||||
|
sam.PORT.PMUX1_8.Set(sam.PORT.PMUX1_8.Get()&^(0xff<<24) | (uint32(val) << 24))
|
||||||
|
case 28:
|
||||||
|
sam.PORT.PMUX1_12.Set(sam.PORT.PMUX1_12.Get()&^(0xff<<0) | (uint32(val) << 0))
|
||||||
|
case 29:
|
||||||
|
sam.PORT.PMUX1_12.Set(sam.PORT.PMUX1_12.Get()&^(0xff<<8) | (uint32(val) << 8))
|
||||||
|
case 30:
|
||||||
|
sam.PORT.PMUX1_12.Set(sam.PORT.PMUX1_12.Get()&^(0xff<<16) | (uint32(val) << 16))
|
||||||
|
case 31:
|
||||||
|
sam.PORT.PMUX1_12.Set(sam.PORT.PMUX1_12.Get()&^(0xff<<24) | (uint32(val) << 24))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// getPinCfg returns the value for the correct PINCFG register for this pin.
|
||||||
|
func (p Pin) getPinCfg() uint8 {
|
||||||
|
switch p {
|
||||||
|
case 0:
|
||||||
|
return sam.PORT.PINCFG0_0.Get()
|
||||||
|
case 1:
|
||||||
|
return sam.PORT.PINCFG0_1.Get()
|
||||||
|
case 2:
|
||||||
|
return sam.PORT.PINCFG0_2.Get()
|
||||||
|
case 3:
|
||||||
|
return sam.PORT.PINCFG0_3.Get()
|
||||||
|
case 4:
|
||||||
|
return sam.PORT.PINCFG0_4.Get()
|
||||||
|
case 5:
|
||||||
|
return sam.PORT.PINCFG0_5.Get()
|
||||||
|
case 6:
|
||||||
|
return sam.PORT.PINCFG0_6.Get()
|
||||||
|
case 7:
|
||||||
|
return sam.PORT.PINCFG0_7.Get()
|
||||||
|
case 8:
|
||||||
|
return sam.PORT.PINCFG0_8.Get()
|
||||||
|
case 9:
|
||||||
|
return sam.PORT.PINCFG0_9.Get()
|
||||||
|
case 10:
|
||||||
|
return sam.PORT.PINCFG0_10.Get()
|
||||||
|
case 11:
|
||||||
|
return sam.PORT.PINCFG0_11.Get()
|
||||||
|
case 12:
|
||||||
|
return sam.PORT.PINCFG0_12.Get()
|
||||||
|
case 13:
|
||||||
|
return sam.PORT.PINCFG0_13.Get()
|
||||||
|
case 14:
|
||||||
|
return sam.PORT.PINCFG0_14.Get()
|
||||||
|
case 15:
|
||||||
|
return sam.PORT.PINCFG0_15.Get()
|
||||||
|
case 16:
|
||||||
|
return sam.PORT.PINCFG0_16.Get()
|
||||||
|
case 17:
|
||||||
|
return sam.PORT.PINCFG0_17.Get()
|
||||||
|
case 18:
|
||||||
|
return sam.PORT.PINCFG0_18.Get()
|
||||||
|
case 19:
|
||||||
|
return sam.PORT.PINCFG0_19.Get()
|
||||||
|
case 20:
|
||||||
|
return sam.PORT.PINCFG0_20.Get()
|
||||||
|
case 21:
|
||||||
|
return sam.PORT.PINCFG0_21.Get()
|
||||||
|
case 22:
|
||||||
|
return sam.PORT.PINCFG0_22.Get()
|
||||||
|
case 23:
|
||||||
|
return sam.PORT.PINCFG0_23.Get()
|
||||||
|
case 24:
|
||||||
|
return sam.PORT.PINCFG0_24.Get()
|
||||||
|
case 25:
|
||||||
|
return sam.PORT.PINCFG0_25.Get()
|
||||||
|
case 26:
|
||||||
|
return sam.PORT.PINCFG0_26.Get()
|
||||||
|
case 27:
|
||||||
|
return sam.PORT.PINCFG0_27.Get()
|
||||||
|
case 28:
|
||||||
|
return sam.PORT.PINCFG0_28.Get()
|
||||||
|
case 29:
|
||||||
|
return sam.PORT.PINCFG0_29.Get()
|
||||||
|
case 30:
|
||||||
|
return sam.PORT.PINCFG0_30.Get()
|
||||||
|
case 31:
|
||||||
|
return sam.PORT.PINCFG0_31.Get()
|
||||||
|
case 32: // PB00
|
||||||
|
return uint8(sam.PORT.PINCFG1_0.Get()>>0) & 0xff
|
||||||
|
case 33: // PB01
|
||||||
|
return uint8(sam.PORT.PINCFG1_0.Get()>>8) & 0xff
|
||||||
|
case 34: // PB02
|
||||||
|
return uint8(sam.PORT.PINCFG1_0.Get()>>16) & 0xff
|
||||||
|
case 35: // PB03
|
||||||
|
return uint8(sam.PORT.PINCFG1_0.Get()>>24) & 0xff
|
||||||
|
case 37: // PB04
|
||||||
|
return uint8(sam.PORT.PINCFG1_4.Get()>>0) & 0xff
|
||||||
|
case 38: // PB05
|
||||||
|
return uint8(sam.PORT.PINCFG1_4.Get()>>8) & 0xff
|
||||||
|
case 39: // PB06
|
||||||
|
return uint8(sam.PORT.PINCFG1_4.Get()>>16) & 0xff
|
||||||
|
case 40: // PB07
|
||||||
|
return uint8(sam.PORT.PINCFG1_4.Get()>>24) & 0xff
|
||||||
|
case 41: // PB08
|
||||||
|
return uint8(sam.PORT.PINCFG1_8.Get()>>0) & 0xff
|
||||||
|
case 42: // PB09
|
||||||
|
return uint8(sam.PORT.PINCFG1_8.Get()>>8) & 0xff
|
||||||
|
case 43: // PB10
|
||||||
|
return uint8(sam.PORT.PINCFG1_8.Get()>>16) & 0xff
|
||||||
|
case 44: // PB11
|
||||||
|
return uint8(sam.PORT.PINCFG1_8.Get()>>24) & 0xff
|
||||||
|
case 45: // PB12
|
||||||
|
return uint8(sam.PORT.PINCFG1_12.Get()>>0) & 0xff
|
||||||
|
case 46: // PB13
|
||||||
|
return uint8(sam.PORT.PINCFG1_12.Get()>>8) & 0xff
|
||||||
|
case 47: // PB14
|
||||||
|
return uint8(sam.PORT.PINCFG1_12.Get()>>16) & 0xff
|
||||||
|
case 48: // PB15
|
||||||
|
return uint8(sam.PORT.PINCFG1_12.Get()>>24) & 0xff
|
||||||
|
case 49: // PB16
|
||||||
|
return uint8(sam.PORT.PINCFG1_16.Get()>>0) & 0xff
|
||||||
|
case 50: // PB17
|
||||||
|
return uint8(sam.PORT.PINCFG1_16.Get()>>8) & 0xff
|
||||||
|
case 51: // PB18
|
||||||
|
return uint8(sam.PORT.PINCFG1_16.Get()>>16) & 0xff
|
||||||
|
case 52: // PB19
|
||||||
|
return uint8(sam.PORT.PINCFG1_16.Get()>>24) & 0xff
|
||||||
|
case 53: // PB20
|
||||||
|
return uint8(sam.PORT.PINCFG1_20.Get()>>0) & 0xff
|
||||||
|
case 54: // PB21
|
||||||
|
return uint8(sam.PORT.PINCFG1_20.Get()>>8) & 0xff
|
||||||
|
case 55: // PB22
|
||||||
|
return uint8(sam.PORT.PINCFG1_20.Get()>>16) & 0xff
|
||||||
|
case 56: // PB23
|
||||||
|
return uint8(sam.PORT.PINCFG1_20.Get()>>24) & 0xff
|
||||||
|
case 57: // PB24
|
||||||
|
return uint8(sam.PORT.PINCFG1_24.Get()>>0) & 0xff
|
||||||
|
case 58: // PB25
|
||||||
|
return uint8(sam.PORT.PINCFG1_24.Get()>>8) & 0xff
|
||||||
|
case 59: // PB26
|
||||||
|
return uint8(sam.PORT.PINCFG1_24.Get()>>16) & 0xff
|
||||||
|
case 60: // PB27
|
||||||
|
return uint8(sam.PORT.PINCFG1_24.Get()>>24) & 0xff
|
||||||
|
case 61: // PB28
|
||||||
|
return uint8(sam.PORT.PINCFG1_28.Get()>>0) & 0xff
|
||||||
|
case 62: // PB29
|
||||||
|
return uint8(sam.PORT.PINCFG1_28.Get()>>8) & 0xff
|
||||||
|
case 63: // PB30
|
||||||
|
return uint8(sam.PORT.PINCFG1_28.Get()>>16) & 0xff
|
||||||
|
case 64: // PB31
|
||||||
|
return uint8(sam.PORT.PINCFG1_28.Get()>>24) & 0xff
|
||||||
|
default:
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// setPinCfg sets the value for the correct PINCFG register for this pin.
|
||||||
|
func (p Pin) setPinCfg(val uint8) {
|
||||||
|
switch p {
|
||||||
|
case 0:
|
||||||
|
sam.PORT.PINCFG0_0.Set(val)
|
||||||
|
case 1:
|
||||||
|
sam.PORT.PINCFG0_1.Set(val)
|
||||||
|
case 2:
|
||||||
|
sam.PORT.PINCFG0_2.Set(val)
|
||||||
|
case 3:
|
||||||
|
sam.PORT.PINCFG0_3.Set(val)
|
||||||
|
case 4:
|
||||||
|
sam.PORT.PINCFG0_4.Set(val)
|
||||||
|
case 5:
|
||||||
|
sam.PORT.PINCFG0_5.Set(val)
|
||||||
|
case 6:
|
||||||
|
sam.PORT.PINCFG0_6.Set(val)
|
||||||
|
case 7:
|
||||||
|
sam.PORT.PINCFG0_7.Set(val)
|
||||||
|
case 8:
|
||||||
|
sam.PORT.PINCFG0_8.Set(val)
|
||||||
|
case 9:
|
||||||
|
sam.PORT.PINCFG0_9.Set(val)
|
||||||
|
case 10:
|
||||||
|
sam.PORT.PINCFG0_10.Set(val)
|
||||||
|
case 11:
|
||||||
|
sam.PORT.PINCFG0_11.Set(val)
|
||||||
|
case 12:
|
||||||
|
sam.PORT.PINCFG0_12.Set(val)
|
||||||
|
case 13:
|
||||||
|
sam.PORT.PINCFG0_13.Set(val)
|
||||||
|
case 14:
|
||||||
|
sam.PORT.PINCFG0_14.Set(val)
|
||||||
|
case 15:
|
||||||
|
sam.PORT.PINCFG0_15.Set(val)
|
||||||
|
case 16:
|
||||||
|
sam.PORT.PINCFG0_16.Set(val)
|
||||||
|
case 17:
|
||||||
|
sam.PORT.PINCFG0_17.Set(val)
|
||||||
|
case 18:
|
||||||
|
sam.PORT.PINCFG0_18.Set(val)
|
||||||
|
case 19:
|
||||||
|
sam.PORT.PINCFG0_19.Set(val)
|
||||||
|
case 20:
|
||||||
|
sam.PORT.PINCFG0_20.Set(val)
|
||||||
|
case 21:
|
||||||
|
sam.PORT.PINCFG0_21.Set(val)
|
||||||
|
case 22:
|
||||||
|
sam.PORT.PINCFG0_22.Set(val)
|
||||||
|
case 23:
|
||||||
|
sam.PORT.PINCFG0_23.Set(val)
|
||||||
|
case 24:
|
||||||
|
sam.PORT.PINCFG0_24.Set(val)
|
||||||
|
case 25:
|
||||||
|
sam.PORT.PINCFG0_25.Set(val)
|
||||||
|
case 26:
|
||||||
|
sam.PORT.PINCFG0_26.Set(val)
|
||||||
|
case 27:
|
||||||
|
sam.PORT.PINCFG0_27.Set(val)
|
||||||
|
case 28:
|
||||||
|
sam.PORT.PINCFG0_28.Set(val)
|
||||||
|
case 29:
|
||||||
|
sam.PORT.PINCFG0_29.Set(val)
|
||||||
|
case 30:
|
||||||
|
sam.PORT.PINCFG0_30.Set(val)
|
||||||
|
case 31:
|
||||||
|
sam.PORT.PINCFG0_31.Set(val)
|
||||||
|
case 32: // PB00
|
||||||
|
sam.PORT.PINCFG1_0.Set(sam.PORT.PINCFG1_0.Get()&^(0xff<<0) | (uint32(val) << 0))
|
||||||
|
case 33: // PB01
|
||||||
|
sam.PORT.PINCFG1_0.Set(sam.PORT.PINCFG1_0.Get()&^(0xff<<8) | (uint32(val) << 8))
|
||||||
|
case 34: // PB02
|
||||||
|
sam.PORT.PINCFG1_0.Set(sam.PORT.PINCFG1_0.Get()&^(0xff<<16) | (uint32(val) << 16))
|
||||||
|
case 35: // PB03
|
||||||
|
sam.PORT.PINCFG1_0.Set(sam.PORT.PINCFG1_0.Get()&^(0xff<<24) | (uint32(val) << 24))
|
||||||
|
case 36: // PB04
|
||||||
|
sam.PORT.PINCFG1_4.Set(sam.PORT.PINCFG1_4.Get()&^(0xff<<0) | (uint32(val) << 0))
|
||||||
|
case 37: // PB05
|
||||||
|
sam.PORT.PINCFG1_4.Set(sam.PORT.PINCFG1_4.Get()&^(0xff<<8) | (uint32(val) << 8))
|
||||||
|
case 38: // PB06
|
||||||
|
sam.PORT.PINCFG1_4.Set(sam.PORT.PINCFG1_4.Get()&^(0xff<<16) | (uint32(val) << 16))
|
||||||
|
case 39: // PB07
|
||||||
|
sam.PORT.PINCFG1_4.Set(sam.PORT.PINCFG1_4.Get()&^(0xff<<24) | (uint32(val) << 24))
|
||||||
|
case 40: // PB08
|
||||||
|
sam.PORT.PINCFG1_8.Set(sam.PORT.PINCFG1_8.Get()&^(0xff<<0) | (uint32(val) << 0))
|
||||||
|
case 41: // PB09
|
||||||
|
sam.PORT.PINCFG1_8.Set(sam.PORT.PINCFG1_8.Get()&^(0xff<<8) | (uint32(val) << 8))
|
||||||
|
case 42: // PB10
|
||||||
|
sam.PORT.PINCFG1_8.Set(sam.PORT.PINCFG1_8.Get()&^(0xff<<16) | (uint32(val) << 16))
|
||||||
|
case 43: // PB11
|
||||||
|
sam.PORT.PINCFG1_8.Set(sam.PORT.PINCFG1_8.Get()&^(0xff<<24) | (uint32(val) << 24))
|
||||||
|
case 44: // PB12
|
||||||
|
sam.PORT.PINCFG1_12.Set(sam.PORT.PINCFG1_12.Get()&^(0xff<<0) | (uint32(val) << 0))
|
||||||
|
case 45: // PB13
|
||||||
|
sam.PORT.PINCFG1_12.Set(sam.PORT.PINCFG1_12.Get()&^(0xff<<8) | (uint32(val) << 8))
|
||||||
|
case 46: // PB14
|
||||||
|
sam.PORT.PINCFG1_12.Set(sam.PORT.PINCFG1_12.Get()&^(0xff<<16) | (uint32(val) << 16))
|
||||||
|
case 47: // PB15
|
||||||
|
sam.PORT.PINCFG1_12.Set(sam.PORT.PINCFG1_12.Get()&^(0xff<<24) | (uint32(val) << 24))
|
||||||
|
case 48: // PB16
|
||||||
|
sam.PORT.PINCFG1_16.Set(sam.PORT.PINCFG1_16.Get()&^(0xff<<0) | (uint32(val) << 0))
|
||||||
|
case 49: // PB17
|
||||||
|
sam.PORT.PINCFG1_16.Set(sam.PORT.PINCFG1_16.Get()&^(0xff<<8) | (uint32(val) << 8))
|
||||||
|
case 50: // PB18
|
||||||
|
sam.PORT.PINCFG1_16.Set(sam.PORT.PINCFG1_16.Get()&^(0xff<<16) | (uint32(val) << 16))
|
||||||
|
case 51: // PB19
|
||||||
|
sam.PORT.PINCFG1_16.Set(sam.PORT.PINCFG1_16.Get()&^(0xff<<24) | (uint32(val) << 24))
|
||||||
|
case 52: // PB20
|
||||||
|
sam.PORT.PINCFG1_20.Set(sam.PORT.PINCFG1_20.Get()&^(0xff<<0) | (uint32(val) << 0))
|
||||||
|
case 53: // PB21
|
||||||
|
sam.PORT.PINCFG1_20.Set(sam.PORT.PINCFG1_20.Get()&^(0xff<<8) | (uint32(val) << 8))
|
||||||
|
case 54: // PB22
|
||||||
|
sam.PORT.PINCFG1_20.Set(sam.PORT.PINCFG1_20.Get()&^(0xff<<16) | (uint32(val) << 16))
|
||||||
|
case 55: // PB23
|
||||||
|
sam.PORT.PINCFG1_20.Set(sam.PORT.PINCFG1_20.Get()&^(0xff<<24) | (uint32(val) << 24))
|
||||||
|
case 56: // PB24
|
||||||
|
sam.PORT.PINCFG1_24.Set(sam.PORT.PINCFG1_24.Get()&^(0xff<<0) | (uint32(val) << 0))
|
||||||
|
case 57: // PB25
|
||||||
|
sam.PORT.PINCFG1_24.Set(sam.PORT.PINCFG1_24.Get()&^(0xff<<8) | (uint32(val) << 8))
|
||||||
|
case 58: // PB26
|
||||||
|
sam.PORT.PINCFG1_24.Set(sam.PORT.PINCFG1_24.Get()&^(0xff<<16) | (uint32(val) << 16))
|
||||||
|
case 59: // PB27
|
||||||
|
sam.PORT.PINCFG1_24.Set(sam.PORT.PINCFG1_24.Get()&^(0xff<<24) | (uint32(val) << 24))
|
||||||
|
case 60: // PB28
|
||||||
|
sam.PORT.PINCFG1_28.Set(sam.PORT.PINCFG1_28.Get()&^(0xff<<0) | (uint32(val) << 0))
|
||||||
|
case 61: // PB29
|
||||||
|
sam.PORT.PINCFG1_28.Set(sam.PORT.PINCFG1_28.Get()&^(0xff<<8) | (uint32(val) << 8))
|
||||||
|
case 62: // PB30
|
||||||
|
sam.PORT.PINCFG1_28.Set(sam.PORT.PINCFG1_28.Get()&^(0xff<<16) | (uint32(val) << 16))
|
||||||
|
case 63: // PB31
|
||||||
|
sam.PORT.PINCFG1_28.Set(sam.PORT.PINCFG1_28.Get()&^(0xff<<24) | (uint32(val) << 24))
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -7,21 +7,21 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
// Configure sets the pin to input or output.
|
// Configure sets the pin to input or output.
|
||||||
func (p GPIO) Configure(config GPIOConfig) {
|
func (p Pin) Configure(config PinConfig) {
|
||||||
if config.Mode == GPIO_OUTPUT { // set output bit
|
if config.Mode == PinOutput { // set output bit
|
||||||
avr.DDRB.SetBits(1 << p.Pin)
|
avr.DDRB.SetBits(1 << uint8(p))
|
||||||
} else { // configure input: clear output bit
|
} else { // configure input: clear output bit
|
||||||
avr.DDRB.ClearBits(1 << p.Pin)
|
avr.DDRB.ClearBits(1 << uint8(p))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p GPIO) getPortMask() (*avr.Register8, uint8) {
|
func (p Pin) getPortMask() (*avr.Register8, uint8) {
|
||||||
return avr.PORTB, 1 << p.Pin
|
return avr.PORTB, 1 << uint8(p)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get returns the current value of a GPIO pin.
|
// Get returns the current value of a GPIO pin.
|
||||||
func (p GPIO) Get() bool {
|
func (p Pin) Get() bool {
|
||||||
val := avr.PINB.Get() & (1 << p.Pin)
|
val := avr.PINB.Get() & (1 << uint8(p))
|
||||||
return (val > 0)
|
return (val > 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -6,15 +6,15 @@ import (
|
|||||||
"device/avr"
|
"device/avr"
|
||||||
)
|
)
|
||||||
|
|
||||||
type GPIOMode uint8
|
type PinMode uint8
|
||||||
|
|
||||||
const (
|
const (
|
||||||
GPIO_INPUT = iota
|
PinInput PinMode = iota
|
||||||
GPIO_OUTPUT
|
PinOutput
|
||||||
)
|
)
|
||||||
|
|
||||||
// Set changes the value of the GPIO pin. The pin must be configured as output.
|
// Set changes the value of the GPIO pin. The pin must be configured as output.
|
||||||
func (p GPIO) Set(value bool) {
|
func (p Pin) Set(value bool) {
|
||||||
if value { // set bits
|
if value { // set bits
|
||||||
port, mask := p.PortMaskSet()
|
port, mask := p.PortMaskSet()
|
||||||
port.Set(mask)
|
port.Set(mask)
|
||||||
@@ -30,7 +30,7 @@ func (p GPIO) Set(value bool) {
|
|||||||
// Warning: there are no separate pin set/clear registers on the AVR. The
|
// Warning: there are no separate pin set/clear registers on the AVR. The
|
||||||
// returned mask is only valid as long as no other pin in the same port has been
|
// returned mask is only valid as long as no other pin in the same port has been
|
||||||
// changed.
|
// changed.
|
||||||
func (p GPIO) PortMaskSet() (*avr.Register8, uint8) {
|
func (p Pin) PortMaskSet() (*avr.Register8, uint8) {
|
||||||
port, mask := p.getPortMask()
|
port, mask := p.getPortMask()
|
||||||
return port, port.Get() | mask
|
return port, port.Get() | mask
|
||||||
}
|
}
|
||||||
@@ -41,7 +41,7 @@ func (p GPIO) PortMaskSet() (*avr.Register8, uint8) {
|
|||||||
// Warning: there are no separate pin set/clear registers on the AVR. The
|
// Warning: there are no separate pin set/clear registers on the AVR. The
|
||||||
// returned mask is only valid as long as no other pin in the same port has been
|
// returned mask is only valid as long as no other pin in the same port has been
|
||||||
// changed.
|
// changed.
|
||||||
func (p GPIO) PortMaskClear() (*avr.Register8, uint8) {
|
func (p Pin) PortMaskClear() (*avr.Register8, uint8) {
|
||||||
port, mask := p.getPortMask()
|
port, mask := p.getPortMask()
|
||||||
return port, port.Get() &^ mask
|
return port, port.Get() &^ mask
|
||||||
}
|
}
|
||||||
@@ -68,13 +68,13 @@ func (a ADC) Get() uint16 {
|
|||||||
// set the ADLAR bit (left-adjusted result) to get a value scaled to 16
|
// set the ADLAR bit (left-adjusted result) to get a value scaled to 16
|
||||||
// bits. This has the same effect as shifting the return value left by 6
|
// bits. This has the same effect as shifting the return value left by 6
|
||||||
// bits.
|
// bits.
|
||||||
avr.ADMUX.Set(avr.ADMUX_REFS0 | avr.ADMUX_ADLAR | (a.Pin & 0x07))
|
avr.ADMUX.Set(avr.ADMUX_REFS0 | avr.ADMUX_ADLAR | (uint8(a.Pin) & 0x07))
|
||||||
|
|
||||||
// start the conversion
|
// start the conversion
|
||||||
avr.ADCSRA.SetBits(avr.ADCSRA_ADSC)
|
avr.ADCSRA.SetBits(avr.ADCSRA_ADSC)
|
||||||
|
|
||||||
// ADSC is cleared when the conversion finishes
|
// ADSC is cleared when the conversion finishes
|
||||||
for ok := true; ok; ok = (avr.ADCSRA.Get() & avr.ADCSRA_ADSC) > 0 {
|
for ok := true; ok; ok = avr.ADCSRA.HasBits(avr.ADCSRA_ADSC) {
|
||||||
}
|
}
|
||||||
|
|
||||||
return uint16(avr.ADCL.Get()) | uint16(avr.ADCH.Get())<<8
|
return uint16(avr.ADCL.Get()) | uint16(avr.ADCH.Get())<<8
|
||||||
|
|||||||
@@ -4,37 +4,37 @@ package machine
|
|||||||
|
|
||||||
// Dummy machine package, filled with no-ops.
|
// Dummy machine package, filled with no-ops.
|
||||||
|
|
||||||
type GPIOMode uint8
|
type PinMode uint8
|
||||||
|
|
||||||
const (
|
const (
|
||||||
GPIO_INPUT = iota
|
PinInput PinMode = iota
|
||||||
GPIO_OUTPUT
|
PinOutput
|
||||||
)
|
)
|
||||||
|
|
||||||
// Fake LED numbers, for testing.
|
// Fake LED numbers, for testing.
|
||||||
const (
|
const (
|
||||||
LED = LED1
|
LED Pin = LED1
|
||||||
LED1 = 0
|
LED1 Pin = 0
|
||||||
LED2 = 0
|
LED2 Pin = 0
|
||||||
LED3 = 0
|
LED3 Pin = 0
|
||||||
LED4 = 0
|
LED4 Pin = 0
|
||||||
)
|
)
|
||||||
|
|
||||||
// Fake button numbers, for testing.
|
// Fake button numbers, for testing.
|
||||||
const (
|
const (
|
||||||
BUTTON = BUTTON1
|
BUTTON Pin = BUTTON1
|
||||||
BUTTON1 = 0
|
BUTTON1 Pin = 0
|
||||||
BUTTON2 = 0
|
BUTTON2 Pin = 0
|
||||||
BUTTON3 = 0
|
BUTTON3 Pin = 0
|
||||||
BUTTON4 = 0
|
BUTTON4 Pin = 0
|
||||||
)
|
)
|
||||||
|
|
||||||
func (p GPIO) Configure(config GPIOConfig) {
|
func (p Pin) Configure(config PinConfig) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p GPIO) Set(value bool) {
|
func (p Pin) Set(value bool) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p GPIO) Get() bool {
|
func (p Pin) Get() bool {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|||||||
+66
-66
@@ -7,51 +7,51 @@ import (
|
|||||||
"device/nrf"
|
"device/nrf"
|
||||||
)
|
)
|
||||||
|
|
||||||
type GPIOMode uint8
|
type PinMode uint8
|
||||||
|
|
||||||
const (
|
const (
|
||||||
GPIO_INPUT = (nrf.GPIO_PIN_CNF_DIR_Input << nrf.GPIO_PIN_CNF_DIR_Pos) | (nrf.GPIO_PIN_CNF_INPUT_Connect << nrf.GPIO_PIN_CNF_INPUT_Pos)
|
PinInput PinMode = (nrf.GPIO_PIN_CNF_DIR_Input << nrf.GPIO_PIN_CNF_DIR_Pos) | (nrf.GPIO_PIN_CNF_INPUT_Connect << nrf.GPIO_PIN_CNF_INPUT_Pos)
|
||||||
GPIO_INPUT_PULLUP = GPIO_INPUT | (nrf.GPIO_PIN_CNF_PULL_Pullup << nrf.GPIO_PIN_CNF_PULL_Pos)
|
PinInputPullup PinMode = PinInput | (nrf.GPIO_PIN_CNF_PULL_Pullup << nrf.GPIO_PIN_CNF_PULL_Pos)
|
||||||
GPIO_INPUT_PULLDOWN = GPIO_INPUT | (nrf.GPIO_PIN_CNF_PULL_Pulldown << nrf.GPIO_PIN_CNF_PULL_Pos)
|
PinInputPulldown PinMode = PinOutput | (nrf.GPIO_PIN_CNF_PULL_Pulldown << nrf.GPIO_PIN_CNF_PULL_Pos)
|
||||||
GPIO_OUTPUT = (nrf.GPIO_PIN_CNF_DIR_Output << nrf.GPIO_PIN_CNF_DIR_Pos) | (nrf.GPIO_PIN_CNF_INPUT_Disconnect << nrf.GPIO_PIN_CNF_INPUT_Pos)
|
PinOutput PinMode = (nrf.GPIO_PIN_CNF_DIR_Output << nrf.GPIO_PIN_CNF_DIR_Pos) | (nrf.GPIO_PIN_CNF_INPUT_Disconnect << nrf.GPIO_PIN_CNF_INPUT_Pos)
|
||||||
)
|
)
|
||||||
|
|
||||||
// Configure this pin with the given configuration.
|
// Configure this pin with the given configuration.
|
||||||
func (p GPIO) Configure(config GPIOConfig) {
|
func (p Pin) Configure(config PinConfig) {
|
||||||
cfg := config.Mode | nrf.GPIO_PIN_CNF_DRIVE_S0S1 | nrf.GPIO_PIN_CNF_SENSE_Disabled
|
cfg := config.Mode | nrf.GPIO_PIN_CNF_DRIVE_S0S1 | nrf.GPIO_PIN_CNF_SENSE_Disabled
|
||||||
port, pin := p.getPortPin()
|
port, pin := p.getPortPin()
|
||||||
port.PIN_CNF[pin] = nrf.RegValue(cfg)
|
port.PIN_CNF[pin].Set(uint32(cfg))
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set the pin to high or low.
|
// Set the pin to high or low.
|
||||||
// Warning: only use this on an output pin!
|
// Warning: only use this on an output pin!
|
||||||
func (p GPIO) Set(high bool) {
|
func (p Pin) Set(high bool) {
|
||||||
port, pin := p.getPortPin()
|
port, pin := p.getPortPin()
|
||||||
if high {
|
if high {
|
||||||
port.OUTSET = 1 << pin
|
port.OUTSET.Set(1 << pin)
|
||||||
} else {
|
} else {
|
||||||
port.OUTCLR = 1 << pin
|
port.OUTCLR.Set(1 << pin)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Return the register and mask to enable a given GPIO pin. This can be used to
|
// Return the register and mask to enable a given GPIO pin. This can be used to
|
||||||
// implement bit-banged drivers.
|
// implement bit-banged drivers.
|
||||||
func (p GPIO) PortMaskSet() (*uint32, uint32) {
|
func (p Pin) PortMaskSet() (*uint32, uint32) {
|
||||||
port, pin := p.getPortPin()
|
port, pin := p.getPortPin()
|
||||||
return (*uint32)(&port.OUTSET), 1 << pin
|
return &port.OUTSET.Reg, 1 << pin
|
||||||
}
|
}
|
||||||
|
|
||||||
// Return the register and mask to disable a given port. This can be used to
|
// Return the register and mask to disable a given port. This can be used to
|
||||||
// implement bit-banged drivers.
|
// implement bit-banged drivers.
|
||||||
func (p GPIO) PortMaskClear() (*uint32, uint32) {
|
func (p Pin) PortMaskClear() (*uint32, uint32) {
|
||||||
port, pin := p.getPortPin()
|
port, pin := p.getPortPin()
|
||||||
return (*uint32)(&port.OUTCLR), 1 << pin
|
return &port.OUTCLR.Reg, 1 << pin
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get returns the current value of a GPIO pin.
|
// Get returns the current value of a GPIO pin.
|
||||||
func (p GPIO) Get() bool {
|
func (p Pin) Get() bool {
|
||||||
port, pin := p.getPortPin()
|
port, pin := p.getPortPin()
|
||||||
return (port.IN>>pin)&1 != 0
|
return (port.IN.Get()>>pin)&1 != 0
|
||||||
}
|
}
|
||||||
|
|
||||||
// UART on the NRF.
|
// UART on the NRF.
|
||||||
@@ -77,10 +77,10 @@ func (uart UART) Configure(config UARTConfig) {
|
|||||||
// Set TX and RX pins from board.
|
// Set TX and RX pins from board.
|
||||||
uart.setPins(UART_TX_PIN, UART_RX_PIN)
|
uart.setPins(UART_TX_PIN, UART_RX_PIN)
|
||||||
|
|
||||||
nrf.UART0.ENABLE = nrf.UART_ENABLE_ENABLE_Enabled
|
nrf.UART0.ENABLE.Set(nrf.UART_ENABLE_ENABLE_Enabled)
|
||||||
nrf.UART0.TASKS_STARTTX = 1
|
nrf.UART0.TASKS_STARTTX.Set(1)
|
||||||
nrf.UART0.TASKS_STARTRX = 1
|
nrf.UART0.TASKS_STARTRX.Set(1)
|
||||||
nrf.UART0.INTENSET = nrf.UART_INTENSET_RXDRDY_Msk
|
nrf.UART0.INTENSET.Set(nrf.UART_INTENSET_RXDRDY_Msk)
|
||||||
|
|
||||||
// Enable RX IRQ.
|
// Enable RX IRQ.
|
||||||
arm.SetPriority(nrf.IRQ_UART0, 0xc0) // low priority
|
arm.SetPriority(nrf.IRQ_UART0, 0xc0) // low priority
|
||||||
@@ -99,22 +99,22 @@ func (uart UART) SetBaudRate(br uint32) {
|
|||||||
// https://devzone.nordicsemi.com/f/nordic-q-a/391/uart-baudrate-register-values/2046#2046
|
// https://devzone.nordicsemi.com/f/nordic-q-a/391/uart-baudrate-register-values/2046#2046
|
||||||
rate := uint32((uint64(br/400)*uint64(400*0xffffffff/16000000) + 0x800) & 0xffffff000)
|
rate := uint32((uint64(br/400)*uint64(400*0xffffffff/16000000) + 0x800) & 0xffffff000)
|
||||||
|
|
||||||
nrf.UART0.BAUDRATE = nrf.RegValue(rate)
|
nrf.UART0.BAUDRATE.Set(rate)
|
||||||
}
|
}
|
||||||
|
|
||||||
// WriteByte writes a byte of data to the UART.
|
// WriteByte writes a byte of data to the UART.
|
||||||
func (uart UART) WriteByte(c byte) error {
|
func (uart UART) WriteByte(c byte) error {
|
||||||
nrf.UART0.EVENTS_TXDRDY = 0
|
nrf.UART0.EVENTS_TXDRDY.Set(0)
|
||||||
nrf.UART0.TXD = nrf.RegValue(c)
|
nrf.UART0.TXD.Set(uint32(c))
|
||||||
for nrf.UART0.EVENTS_TXDRDY == 0 {
|
for nrf.UART0.EVENTS_TXDRDY.Get() == 0 {
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (uart UART) handleInterrupt() {
|
func (uart UART) handleInterrupt() {
|
||||||
if nrf.UART0.EVENTS_RXDRDY != 0 {
|
if nrf.UART0.EVENTS_RXDRDY.Get() != 0 {
|
||||||
uart.Receive(byte(nrf.UART0.RXD))
|
uart.Receive(byte(nrf.UART0.RXD.Get()))
|
||||||
nrf.UART0.EVENTS_RXDRDY = 0x0
|
nrf.UART0.EVENTS_RXDRDY.Set(0x0)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -132,8 +132,8 @@ var (
|
|||||||
// I2CConfig is used to store config info for I2C.
|
// I2CConfig is used to store config info for I2C.
|
||||||
type I2CConfig struct {
|
type I2CConfig struct {
|
||||||
Frequency uint32
|
Frequency uint32
|
||||||
SCL uint8
|
SCL Pin
|
||||||
SDA uint8
|
SDA Pin
|
||||||
}
|
}
|
||||||
|
|
||||||
// Configure is intended to setup the I2C interface.
|
// Configure is intended to setup the I2C interface.
|
||||||
@@ -149,27 +149,27 @@ func (i2c I2C) Configure(config I2CConfig) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// do config
|
// do config
|
||||||
sclPort, sclPin := GPIO{config.SCL}.getPortPin()
|
sclPort, sclPin := config.SCL.getPortPin()
|
||||||
sclPort.PIN_CNF[sclPin] = (nrf.GPIO_PIN_CNF_DIR_Input << nrf.GPIO_PIN_CNF_DIR_Pos) |
|
sclPort.PIN_CNF[sclPin].Set((nrf.GPIO_PIN_CNF_DIR_Input << nrf.GPIO_PIN_CNF_DIR_Pos) |
|
||||||
(nrf.GPIO_PIN_CNF_INPUT_Connect << nrf.GPIO_PIN_CNF_INPUT_Pos) |
|
(nrf.GPIO_PIN_CNF_INPUT_Connect << nrf.GPIO_PIN_CNF_INPUT_Pos) |
|
||||||
(nrf.GPIO_PIN_CNF_PULL_Pullup << nrf.GPIO_PIN_CNF_PULL_Pos) |
|
(nrf.GPIO_PIN_CNF_PULL_Pullup << nrf.GPIO_PIN_CNF_PULL_Pos) |
|
||||||
(nrf.GPIO_PIN_CNF_DRIVE_S0D1 << nrf.GPIO_PIN_CNF_DRIVE_Pos) |
|
(nrf.GPIO_PIN_CNF_DRIVE_S0D1 << nrf.GPIO_PIN_CNF_DRIVE_Pos) |
|
||||||
(nrf.GPIO_PIN_CNF_SENSE_Disabled << nrf.GPIO_PIN_CNF_SENSE_Pos)
|
(nrf.GPIO_PIN_CNF_SENSE_Disabled << nrf.GPIO_PIN_CNF_SENSE_Pos))
|
||||||
|
|
||||||
sdaPort, sdaPin := GPIO{config.SDA}.getPortPin()
|
sdaPort, sdaPin := config.SDA.getPortPin()
|
||||||
sdaPort.PIN_CNF[sdaPin] = (nrf.GPIO_PIN_CNF_DIR_Input << nrf.GPIO_PIN_CNF_DIR_Pos) |
|
sdaPort.PIN_CNF[sdaPin].Set((nrf.GPIO_PIN_CNF_DIR_Input << nrf.GPIO_PIN_CNF_DIR_Pos) |
|
||||||
(nrf.GPIO_PIN_CNF_INPUT_Connect << nrf.GPIO_PIN_CNF_INPUT_Pos) |
|
(nrf.GPIO_PIN_CNF_INPUT_Connect << nrf.GPIO_PIN_CNF_INPUT_Pos) |
|
||||||
(nrf.GPIO_PIN_CNF_PULL_Pullup << nrf.GPIO_PIN_CNF_PULL_Pos) |
|
(nrf.GPIO_PIN_CNF_PULL_Pullup << nrf.GPIO_PIN_CNF_PULL_Pos) |
|
||||||
(nrf.GPIO_PIN_CNF_DRIVE_S0D1 << nrf.GPIO_PIN_CNF_DRIVE_Pos) |
|
(nrf.GPIO_PIN_CNF_DRIVE_S0D1 << nrf.GPIO_PIN_CNF_DRIVE_Pos) |
|
||||||
(nrf.GPIO_PIN_CNF_SENSE_Disabled << nrf.GPIO_PIN_CNF_SENSE_Pos)
|
(nrf.GPIO_PIN_CNF_SENSE_Disabled << nrf.GPIO_PIN_CNF_SENSE_Pos))
|
||||||
|
|
||||||
if config.Frequency == TWI_FREQ_400KHZ {
|
if config.Frequency == TWI_FREQ_400KHZ {
|
||||||
i2c.Bus.FREQUENCY = nrf.TWI_FREQUENCY_FREQUENCY_K400
|
i2c.Bus.FREQUENCY.Set(nrf.TWI_FREQUENCY_FREQUENCY_K400)
|
||||||
} else {
|
} else {
|
||||||
i2c.Bus.FREQUENCY = nrf.TWI_FREQUENCY_FREQUENCY_K100
|
i2c.Bus.FREQUENCY.Set(nrf.TWI_FREQUENCY_FREQUENCY_K100)
|
||||||
}
|
}
|
||||||
|
|
||||||
i2c.Bus.ENABLE = nrf.TWI_ENABLE_ENABLE_Enabled
|
i2c.Bus.ENABLE.Set(nrf.TWI_ENABLE_ENABLE_Enabled)
|
||||||
i2c.setPins(config.SCL, config.SDA)
|
i2c.setPins(config.SCL, config.SDA)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -177,28 +177,28 @@ func (i2c I2C) Configure(config I2CConfig) {
|
|||||||
// It clocks out the given address, writes the bytes in w, reads back len(r)
|
// It clocks out the given address, writes the bytes in w, reads back len(r)
|
||||||
// bytes and stores them in r, and generates a stop condition on the bus.
|
// bytes and stores them in r, and generates a stop condition on the bus.
|
||||||
func (i2c I2C) Tx(addr uint16, w, r []byte) error {
|
func (i2c I2C) Tx(addr uint16, w, r []byte) error {
|
||||||
i2c.Bus.ADDRESS = nrf.RegValue(addr)
|
i2c.Bus.ADDRESS.Set(uint32(addr))
|
||||||
if len(w) != 0 {
|
if len(w) != 0 {
|
||||||
i2c.Bus.TASKS_STARTTX = 1 // start transmission for writing
|
i2c.Bus.TASKS_STARTTX.Set(1) // start transmission for writing
|
||||||
for _, b := range w {
|
for _, b := range w {
|
||||||
i2c.writeByte(b)
|
i2c.writeByte(b)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if len(r) != 0 {
|
if len(r) != 0 {
|
||||||
// To trigger suspend task when a byte is received
|
// To trigger suspend task when a byte is received
|
||||||
i2c.Bus.SHORTS = nrf.TWI_SHORTS_BB_SUSPEND
|
i2c.Bus.SHORTS.Set(nrf.TWI_SHORTS_BB_SUSPEND)
|
||||||
i2c.Bus.TASKS_STARTRX = 1 // re-start transmission for reading
|
i2c.Bus.TASKS_STARTRX.Set(1) // re-start transmission for reading
|
||||||
for i := range r { // read each char
|
for i := range r { // read each char
|
||||||
if i+1 == len(r) {
|
if i+1 == len(r) {
|
||||||
// To trigger stop task when last byte is received, set before resume task.
|
// To trigger stop task when last byte is received, set before resume task.
|
||||||
i2c.Bus.SHORTS = nrf.TWI_SHORTS_BB_STOP
|
i2c.Bus.SHORTS.Set(nrf.TWI_SHORTS_BB_STOP)
|
||||||
}
|
}
|
||||||
i2c.Bus.TASKS_RESUME = 1 // re-start transmission for reading
|
i2c.Bus.TASKS_RESUME.Set(1) // re-start transmission for reading
|
||||||
r[i] = i2c.readByte()
|
r[i] = i2c.readByte()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
i2c.signalStop()
|
i2c.signalStop()
|
||||||
i2c.Bus.SHORTS = nrf.TWI_SHORTS_BB_SUSPEND_Disabled
|
i2c.Bus.SHORTS.Set(nrf.TWI_SHORTS_BB_SUSPEND_Disabled)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -206,26 +206,26 @@ func (i2c I2C) Tx(addr uint16, w, r []byte) error {
|
|||||||
// it must generate a stop condition after the next character is retrieved when
|
// it must generate a stop condition after the next character is retrieved when
|
||||||
// reading.
|
// reading.
|
||||||
func (i2c I2C) signalStop() {
|
func (i2c I2C) signalStop() {
|
||||||
i2c.Bus.TASKS_STOP = 1
|
i2c.Bus.TASKS_STOP.Set(1)
|
||||||
for i2c.Bus.EVENTS_STOPPED == 0 {
|
for i2c.Bus.EVENTS_STOPPED.Get() == 0 {
|
||||||
}
|
}
|
||||||
i2c.Bus.EVENTS_STOPPED = 0
|
i2c.Bus.EVENTS_STOPPED.Set(0)
|
||||||
}
|
}
|
||||||
|
|
||||||
// writeByte writes a single byte to the I2C bus.
|
// writeByte writes a single byte to the I2C bus.
|
||||||
func (i2c I2C) writeByte(data byte) {
|
func (i2c I2C) writeByte(data byte) {
|
||||||
i2c.Bus.TXD = nrf.RegValue(data)
|
i2c.Bus.TXD.Set(uint32(data))
|
||||||
for i2c.Bus.EVENTS_TXDSENT == 0 {
|
for i2c.Bus.EVENTS_TXDSENT.Get() == 0 {
|
||||||
}
|
}
|
||||||
i2c.Bus.EVENTS_TXDSENT = 0
|
i2c.Bus.EVENTS_TXDSENT.Set(0)
|
||||||
}
|
}
|
||||||
|
|
||||||
// readByte reads a single byte from the I2C bus.
|
// readByte reads a single byte from the I2C bus.
|
||||||
func (i2c I2C) readByte() byte {
|
func (i2c I2C) readByte() byte {
|
||||||
for i2c.Bus.EVENTS_RXDREADY == 0 {
|
for i2c.Bus.EVENTS_RXDREADY.Get() == 0 {
|
||||||
}
|
}
|
||||||
i2c.Bus.EVENTS_RXDREADY = 0
|
i2c.Bus.EVENTS_RXDREADY.Set(0)
|
||||||
return byte(i2c.Bus.RXD)
|
return byte(i2c.Bus.RXD.Get())
|
||||||
}
|
}
|
||||||
|
|
||||||
// SPI on the NRF.
|
// SPI on the NRF.
|
||||||
@@ -242,9 +242,9 @@ var (
|
|||||||
// SPIConfig is used to store config info for SPI.
|
// SPIConfig is used to store config info for SPI.
|
||||||
type SPIConfig struct {
|
type SPIConfig struct {
|
||||||
Frequency uint32
|
Frequency uint32
|
||||||
SCK uint8
|
SCK Pin
|
||||||
MOSI uint8
|
MOSI Pin
|
||||||
MISO uint8
|
MISO Pin
|
||||||
LSBFirst bool
|
LSBFirst bool
|
||||||
Mode uint8
|
Mode uint8
|
||||||
}
|
}
|
||||||
@@ -252,7 +252,7 @@ type SPIConfig struct {
|
|||||||
// Configure is intended to setup the SPI interface.
|
// Configure is intended to setup the SPI interface.
|
||||||
func (spi SPI) Configure(config SPIConfig) {
|
func (spi SPI) Configure(config SPIConfig) {
|
||||||
// Disable bus to configure it
|
// Disable bus to configure it
|
||||||
spi.Bus.ENABLE = nrf.SPI_ENABLE_ENABLE_Disabled
|
spi.Bus.ENABLE.Set(nrf.SPI_ENABLE_ENABLE_Disabled)
|
||||||
|
|
||||||
// set frequency
|
// set frequency
|
||||||
var freq uint32
|
var freq uint32
|
||||||
@@ -275,7 +275,7 @@ func (spi SPI) Configure(config SPIConfig) {
|
|||||||
default:
|
default:
|
||||||
freq = nrf.SPI_FREQUENCY_FREQUENCY_K500
|
freq = nrf.SPI_FREQUENCY_FREQUENCY_K500
|
||||||
}
|
}
|
||||||
spi.Bus.FREQUENCY = nrf.RegValue(freq)
|
spi.Bus.FREQUENCY.Set(freq)
|
||||||
|
|
||||||
var conf uint32
|
var conf uint32
|
||||||
|
|
||||||
@@ -302,22 +302,22 @@ func (spi SPI) Configure(config SPIConfig) {
|
|||||||
conf &^= (nrf.SPI_CONFIG_CPOL_ActiveHigh << nrf.SPI_CONFIG_CPOL_Pos)
|
conf &^= (nrf.SPI_CONFIG_CPOL_ActiveHigh << nrf.SPI_CONFIG_CPOL_Pos)
|
||||||
conf &^= (nrf.SPI_CONFIG_CPHA_Leading << nrf.SPI_CONFIG_CPHA_Pos)
|
conf &^= (nrf.SPI_CONFIG_CPHA_Leading << nrf.SPI_CONFIG_CPHA_Pos)
|
||||||
}
|
}
|
||||||
spi.Bus.CONFIG = nrf.RegValue(conf)
|
spi.Bus.CONFIG.Set(conf)
|
||||||
|
|
||||||
// set pins
|
// set pins
|
||||||
spi.setPins(config.SCK, config.MOSI, config.MISO)
|
spi.setPins(config.SCK, config.MOSI, config.MISO)
|
||||||
|
|
||||||
// Re-enable bus now that it is configured.
|
// Re-enable bus now that it is configured.
|
||||||
spi.Bus.ENABLE = nrf.SPI_ENABLE_ENABLE_Enabled
|
spi.Bus.ENABLE.Set(nrf.SPI_ENABLE_ENABLE_Enabled)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Transfer writes/reads a single byte using the SPI interface.
|
// Transfer writes/reads a single byte using the SPI interface.
|
||||||
func (spi SPI) Transfer(w byte) (byte, error) {
|
func (spi SPI) Transfer(w byte) (byte, error) {
|
||||||
spi.Bus.TXD = nrf.RegValue(w)
|
spi.Bus.TXD.Set(uint32(w))
|
||||||
for spi.Bus.EVENTS_READY == 0 {
|
for spi.Bus.EVENTS_READY.Get() == 0 {
|
||||||
}
|
}
|
||||||
r := spi.Bus.RXD
|
r := spi.Bus.RXD.Get()
|
||||||
spi.Bus.EVENTS_READY = 0
|
spi.Bus.EVENTS_READY.Set(0)
|
||||||
|
|
||||||
// TODO: handle SPI errors
|
// TODO: handle SPI errors
|
||||||
return byte(r), nil
|
return byte(r), nil
|
||||||
|
|||||||
@@ -9,13 +9,13 @@ import (
|
|||||||
const CPU_FREQUENCY = 16000000
|
const CPU_FREQUENCY = 16000000
|
||||||
|
|
||||||
// Get peripheral and pin number for this GPIO pin.
|
// Get peripheral and pin number for this GPIO pin.
|
||||||
func (p GPIO) getPortPin() (*nrf.GPIO_Type, uint8) {
|
func (p Pin) getPortPin() (*nrf.GPIO_Type, uint32) {
|
||||||
return nrf.GPIO, p.Pin
|
return nrf.GPIO, uint32(p)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (uart UART) setPins(tx, rx uint32) {
|
func (uart UART) setPins(tx, rx Pin) {
|
||||||
nrf.UART0.PSELTXD = nrf.RegValue(tx)
|
nrf.UART0.PSELTXD.Set(uint32(tx))
|
||||||
nrf.UART0.PSELRXD = nrf.RegValue(rx)
|
nrf.UART0.PSELRXD.Set(uint32(rx))
|
||||||
}
|
}
|
||||||
|
|
||||||
//go:export UART0_IRQHandler
|
//go:export UART0_IRQHandler
|
||||||
@@ -23,13 +23,13 @@ func handleUART0() {
|
|||||||
UART0.handleInterrupt()
|
UART0.handleInterrupt()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (i2c I2C) setPins(scl, sda uint8) {
|
func (i2c I2C) setPins(scl, sda Pin) {
|
||||||
i2c.Bus.PSELSCL = nrf.RegValue(scl)
|
i2c.Bus.PSELSCL.Set(uint32(scl))
|
||||||
i2c.Bus.PSELSDA = nrf.RegValue(sda)
|
i2c.Bus.PSELSDA.Set(uint32(sda))
|
||||||
}
|
}
|
||||||
|
|
||||||
// SPI
|
// SPI
|
||||||
func (spi SPI) setPins(sck, mosi, miso uint8) {
|
func (spi SPI) setPins(sck, mosi, miso Pin) {
|
||||||
if sck == 0 {
|
if sck == 0 {
|
||||||
sck = SPI0_SCK_PIN
|
sck = SPI0_SCK_PIN
|
||||||
}
|
}
|
||||||
@@ -39,7 +39,7 @@ func (spi SPI) setPins(sck, mosi, miso uint8) {
|
|||||||
if miso == 0 {
|
if miso == 0 {
|
||||||
miso = SPI0_MISO_PIN
|
miso = SPI0_MISO_PIN
|
||||||
}
|
}
|
||||||
spi.Bus.PSELSCK = nrf.RegValue(sck)
|
spi.Bus.PSELSCK.Set(uint32(sck))
|
||||||
spi.Bus.PSELMOSI = nrf.RegValue(mosi)
|
spi.Bus.PSELMOSI.Set(uint32(mosi))
|
||||||
spi.Bus.PSELMISO = nrf.RegValue(miso)
|
spi.Bus.PSELMISO.Set(uint32(miso))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,13 +10,13 @@ import (
|
|||||||
const CPU_FREQUENCY = 64000000
|
const CPU_FREQUENCY = 64000000
|
||||||
|
|
||||||
// Get peripheral and pin number for this GPIO pin.
|
// Get peripheral and pin number for this GPIO pin.
|
||||||
func (p GPIO) getPortPin() (*nrf.GPIO_Type, uint8) {
|
func (p Pin) getPortPin() (*nrf.GPIO_Type, uint32) {
|
||||||
return nrf.P0, p.Pin
|
return nrf.P0, uint32(p)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (uart UART) setPins(tx, rx uint32) {
|
func (uart UART) setPins(tx, rx Pin) {
|
||||||
nrf.UART0.PSELTXD = nrf.RegValue(tx)
|
nrf.UART0.PSELTXD.Set(uint32(tx))
|
||||||
nrf.UART0.PSELRXD = nrf.RegValue(rx)
|
nrf.UART0.PSELRXD.Set(uint32(rx))
|
||||||
}
|
}
|
||||||
|
|
||||||
//go:export UARTE0_UART0_IRQHandler
|
//go:export UARTE0_UART0_IRQHandler
|
||||||
@@ -24,13 +24,13 @@ func handleUART0() {
|
|||||||
UART0.handleInterrupt()
|
UART0.handleInterrupt()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (i2c I2C) setPins(scl, sda uint8) {
|
func (i2c I2C) setPins(scl, sda Pin) {
|
||||||
i2c.Bus.PSELSCL = nrf.RegValue(scl)
|
i2c.Bus.PSELSCL.Set(uint32(scl))
|
||||||
i2c.Bus.PSELSDA = nrf.RegValue(sda)
|
i2c.Bus.PSELSDA.Set(uint32(sda))
|
||||||
}
|
}
|
||||||
|
|
||||||
// SPI
|
// SPI
|
||||||
func (spi SPI) setPins(sck, mosi, miso uint8) {
|
func (spi SPI) setPins(sck, mosi, miso Pin) {
|
||||||
if sck == 0 {
|
if sck == 0 {
|
||||||
sck = SPI0_SCK_PIN
|
sck = SPI0_SCK_PIN
|
||||||
}
|
}
|
||||||
@@ -40,9 +40,9 @@ func (spi SPI) setPins(sck, mosi, miso uint8) {
|
|||||||
if miso == 0 {
|
if miso == 0 {
|
||||||
miso = SPI0_MISO_PIN
|
miso = SPI0_MISO_PIN
|
||||||
}
|
}
|
||||||
spi.Bus.PSEL.SCK = nrf.RegValue(sck)
|
spi.Bus.PSEL.SCK.Set(uint32(sck))
|
||||||
spi.Bus.PSEL.MOSI = nrf.RegValue(mosi)
|
spi.Bus.PSEL.MOSI.Set(uint32(mosi))
|
||||||
spi.Bus.PSEL.MISO = nrf.RegValue(miso)
|
spi.Bus.PSEL.MISO.Set(uint32(miso))
|
||||||
}
|
}
|
||||||
|
|
||||||
// InitADC initializes the registers needed for ADC.
|
// InitADC initializes the registers needed for ADC.
|
||||||
@@ -89,53 +89,53 @@ func (a ADC) Get() uint16 {
|
|||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
nrf.SAADC.RESOLUTION = nrf.SAADC_RESOLUTION_VAL_12bit
|
nrf.SAADC.RESOLUTION.Set(nrf.SAADC_RESOLUTION_VAL_12bit)
|
||||||
|
|
||||||
// Enable ADC.
|
// Enable ADC.
|
||||||
nrf.SAADC.ENABLE = (nrf.SAADC_ENABLE_ENABLE_Enabled << nrf.SAADC_ENABLE_ENABLE_Pos)
|
nrf.SAADC.ENABLE.Set(nrf.SAADC_ENABLE_ENABLE_Enabled << nrf.SAADC_ENABLE_ENABLE_Pos)
|
||||||
for i := 0; i < 8; i++ {
|
for i := 0; i < 8; i++ {
|
||||||
nrf.SAADC.CH[i].PSELN = nrf.SAADC_CH_PSELP_PSELP_NC
|
nrf.SAADC.CH[i].PSELN.Set(nrf.SAADC_CH_PSELP_PSELP_NC)
|
||||||
nrf.SAADC.CH[i].PSELP = nrf.SAADC_CH_PSELP_PSELP_NC
|
nrf.SAADC.CH[i].PSELP.Set(nrf.SAADC_CH_PSELP_PSELP_NC)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Configure ADC.
|
// Configure ADC.
|
||||||
nrf.SAADC.CH[0].CONFIG = ((nrf.SAADC_CH_CONFIG_RESP_Bypass << nrf.SAADC_CH_CONFIG_RESP_Pos) & nrf.SAADC_CH_CONFIG_RESP_Msk) |
|
nrf.SAADC.CH[0].CONFIG.Set(((nrf.SAADC_CH_CONFIG_RESP_Bypass << nrf.SAADC_CH_CONFIG_RESP_Pos) & nrf.SAADC_CH_CONFIG_RESP_Msk) |
|
||||||
((nrf.SAADC_CH_CONFIG_RESP_Bypass << nrf.SAADC_CH_CONFIG_RESN_Pos) & nrf.SAADC_CH_CONFIG_RESN_Msk) |
|
((nrf.SAADC_CH_CONFIG_RESP_Bypass << nrf.SAADC_CH_CONFIG_RESN_Pos) & nrf.SAADC_CH_CONFIG_RESN_Msk) |
|
||||||
((nrf.SAADC_CH_CONFIG_GAIN_Gain1_5 << nrf.SAADC_CH_CONFIG_GAIN_Pos) & nrf.SAADC_CH_CONFIG_GAIN_Msk) |
|
((nrf.SAADC_CH_CONFIG_GAIN_Gain1_5 << nrf.SAADC_CH_CONFIG_GAIN_Pos) & nrf.SAADC_CH_CONFIG_GAIN_Msk) |
|
||||||
((nrf.SAADC_CH_CONFIG_REFSEL_Internal << nrf.SAADC_CH_CONFIG_REFSEL_Pos) & nrf.SAADC_CH_CONFIG_REFSEL_Msk) |
|
((nrf.SAADC_CH_CONFIG_REFSEL_Internal << nrf.SAADC_CH_CONFIG_REFSEL_Pos) & nrf.SAADC_CH_CONFIG_REFSEL_Msk) |
|
||||||
((nrf.SAADC_CH_CONFIG_TACQ_3us << nrf.SAADC_CH_CONFIG_TACQ_Pos) & nrf.SAADC_CH_CONFIG_TACQ_Msk) |
|
((nrf.SAADC_CH_CONFIG_TACQ_3us << nrf.SAADC_CH_CONFIG_TACQ_Pos) & nrf.SAADC_CH_CONFIG_TACQ_Msk) |
|
||||||
((nrf.SAADC_CH_CONFIG_MODE_SE << nrf.SAADC_CH_CONFIG_MODE_Pos) & nrf.SAADC_CH_CONFIG_MODE_Msk)
|
((nrf.SAADC_CH_CONFIG_MODE_SE << nrf.SAADC_CH_CONFIG_MODE_Pos) & nrf.SAADC_CH_CONFIG_MODE_Msk))
|
||||||
|
|
||||||
// Set pin to read.
|
// Set pin to read.
|
||||||
nrf.SAADC.CH[0].PSELN = nrf.RegValue(pwmPin)
|
nrf.SAADC.CH[0].PSELN.Set(pwmPin)
|
||||||
nrf.SAADC.CH[0].PSELP = nrf.RegValue(pwmPin)
|
nrf.SAADC.CH[0].PSELP.Set(pwmPin)
|
||||||
|
|
||||||
// Destination for sample result.
|
// Destination for sample result.
|
||||||
nrf.SAADC.RESULT.PTR = nrf.RegValue(uintptr(unsafe.Pointer(&value)))
|
nrf.SAADC.RESULT.PTR.Set(uint32(uintptr(unsafe.Pointer(&value))))
|
||||||
nrf.SAADC.RESULT.MAXCNT = 1 // One sample
|
nrf.SAADC.RESULT.MAXCNT.Set(1) // One sample
|
||||||
|
|
||||||
// Start tasks.
|
// Start tasks.
|
||||||
nrf.SAADC.TASKS_START = 1
|
nrf.SAADC.TASKS_START.Set(1)
|
||||||
for nrf.SAADC.EVENTS_STARTED == 0 {
|
for nrf.SAADC.EVENTS_STARTED.Get() == 0 {
|
||||||
}
|
}
|
||||||
nrf.SAADC.EVENTS_STARTED = 0x00
|
nrf.SAADC.EVENTS_STARTED.Set(0x00)
|
||||||
|
|
||||||
// Start the sample task.
|
// Start the sample task.
|
||||||
nrf.SAADC.TASKS_SAMPLE = 1
|
nrf.SAADC.TASKS_SAMPLE.Set(1)
|
||||||
|
|
||||||
// Wait until the sample task is done.
|
// Wait until the sample task is done.
|
||||||
for nrf.SAADC.EVENTS_END == 0 {
|
for nrf.SAADC.EVENTS_END.Get() == 0 {
|
||||||
}
|
}
|
||||||
nrf.SAADC.EVENTS_END = 0x00
|
nrf.SAADC.EVENTS_END.Set(0x00)
|
||||||
|
|
||||||
// Stop the ADC
|
// Stop the ADC
|
||||||
nrf.SAADC.TASKS_STOP = 1
|
nrf.SAADC.TASKS_STOP.Set(1)
|
||||||
for nrf.SAADC.EVENTS_STOPPED == 0 {
|
for nrf.SAADC.EVENTS_STOPPED.Get() == 0 {
|
||||||
}
|
}
|
||||||
nrf.SAADC.EVENTS_STOPPED = 0
|
nrf.SAADC.EVENTS_STOPPED.Set(0)
|
||||||
|
|
||||||
// Disable the ADC.
|
// Disable the ADC.
|
||||||
nrf.SAADC.ENABLE = (nrf.SAADC_ENABLE_ENABLE_Disabled << nrf.SAADC_ENABLE_ENABLE_Pos)
|
nrf.SAADC.ENABLE.Set(nrf.SAADC_ENABLE_ENABLE_Disabled << nrf.SAADC_ENABLE_ENABLE_Pos)
|
||||||
|
|
||||||
if value < 0 {
|
if value < 0 {
|
||||||
value = 0
|
value = 0
|
||||||
@@ -170,21 +170,21 @@ func (pwm PWM) Set(value uint16) {
|
|||||||
|
|
||||||
p := pwms[i]
|
p := pwms[i]
|
||||||
|
|
||||||
p.PSEL.OUT[0] = nrf.RegValue(pwm.Pin)
|
p.PSEL.OUT[0].Set(uint32(pwm.Pin))
|
||||||
p.PSEL.OUT[1] = nrf.RegValue(pwm.Pin)
|
p.PSEL.OUT[1].Set(uint32(pwm.Pin))
|
||||||
p.PSEL.OUT[2] = nrf.RegValue(pwm.Pin)
|
p.PSEL.OUT[2].Set(uint32(pwm.Pin))
|
||||||
p.PSEL.OUT[3] = nrf.RegValue(pwm.Pin)
|
p.PSEL.OUT[3].Set(uint32(pwm.Pin))
|
||||||
p.ENABLE = (nrf.PWM_ENABLE_ENABLE_Enabled << nrf.PWM_ENABLE_ENABLE_Pos)
|
p.ENABLE.Set(nrf.PWM_ENABLE_ENABLE_Enabled << nrf.PWM_ENABLE_ENABLE_Pos)
|
||||||
p.PRESCALER = nrf.PWM_PRESCALER_PRESCALER_DIV_2
|
p.PRESCALER.Set(nrf.PWM_PRESCALER_PRESCALER_DIV_2)
|
||||||
p.MODE = nrf.PWM_MODE_UPDOWN_Up
|
p.MODE.Set(nrf.PWM_MODE_UPDOWN_Up)
|
||||||
p.COUNTERTOP = 16384 // frequency
|
p.COUNTERTOP.Set(16384) // frequency
|
||||||
p.LOOP = 0
|
p.LOOP.Set(0)
|
||||||
p.DECODER = (nrf.PWM_DECODER_LOAD_Common << nrf.PWM_DECODER_LOAD_Pos) | (nrf.PWM_DECODER_MODE_RefreshCount << nrf.PWM_DECODER_MODE_Pos)
|
p.DECODER.Set((nrf.PWM_DECODER_LOAD_Common << nrf.PWM_DECODER_LOAD_Pos) | (nrf.PWM_DECODER_MODE_RefreshCount << nrf.PWM_DECODER_MODE_Pos))
|
||||||
p.SEQ[0].PTR = nrf.RegValue(uintptr(unsafe.Pointer(&pwmChannelSequence[i])))
|
p.SEQ[0].PTR.Set(uint32(uintptr(unsafe.Pointer(&pwmChannelSequence[i]))))
|
||||||
p.SEQ[0].CNT = 1
|
p.SEQ[0].CNT.Set(1)
|
||||||
p.SEQ[0].REFRESH = 1
|
p.SEQ[0].REFRESH.Set(1)
|
||||||
p.SEQ[0].ENDDELAY = 0
|
p.SEQ[0].ENDDELAY.Set(0)
|
||||||
p.TASKS_SEQSTART[0] = 1
|
p.TASKS_SEQSTART[0].Set(1)
|
||||||
|
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,17 +10,17 @@ import (
|
|||||||
const CPU_FREQUENCY = 64000000
|
const CPU_FREQUENCY = 64000000
|
||||||
|
|
||||||
// Get peripheral and pin number for this GPIO pin.
|
// Get peripheral and pin number for this GPIO pin.
|
||||||
func (p GPIO) getPortPin() (*nrf.GPIO_Type, uint8) {
|
func (p Pin) getPortPin() (*nrf.GPIO_Type, uint32) {
|
||||||
if p.Pin >= 32 {
|
if p >= 32 {
|
||||||
return nrf.P1, p.Pin - 32
|
return nrf.P1, uint32(p - 32)
|
||||||
} else {
|
} else {
|
||||||
return nrf.P0, p.Pin
|
return nrf.P0, uint32(p)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (uart UART) setPins(tx, rx uint32) {
|
func (uart UART) setPins(tx, rx Pin) {
|
||||||
nrf.UART0.PSEL.TXD = nrf.RegValue(tx)
|
nrf.UART0.PSEL.TXD.Set(uint32(tx))
|
||||||
nrf.UART0.PSEL.RXD = nrf.RegValue(rx)
|
nrf.UART0.PSEL.RXD.Set(uint32(rx))
|
||||||
}
|
}
|
||||||
|
|
||||||
//go:export UARTE0_UART0_IRQHandler
|
//go:export UARTE0_UART0_IRQHandler
|
||||||
@@ -28,13 +28,13 @@ func handleUART0() {
|
|||||||
UART0.handleInterrupt()
|
UART0.handleInterrupt()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (i2c I2C) setPins(scl, sda uint8) {
|
func (i2c I2C) setPins(scl, sda Pin) {
|
||||||
i2c.Bus.PSEL.SCL = nrf.RegValue(scl)
|
i2c.Bus.PSEL.SCL.Set(uint32(scl))
|
||||||
i2c.Bus.PSEL.SDA = nrf.RegValue(sda)
|
i2c.Bus.PSEL.SDA.Set(uint32(sda))
|
||||||
}
|
}
|
||||||
|
|
||||||
// SPI
|
// SPI
|
||||||
func (spi SPI) setPins(sck, mosi, miso uint8) {
|
func (spi SPI) setPins(sck, mosi, miso Pin) {
|
||||||
if sck == 0 {
|
if sck == 0 {
|
||||||
sck = SPI0_SCK_PIN
|
sck = SPI0_SCK_PIN
|
||||||
}
|
}
|
||||||
@@ -44,9 +44,9 @@ func (spi SPI) setPins(sck, mosi, miso uint8) {
|
|||||||
if miso == 0 {
|
if miso == 0 {
|
||||||
miso = SPI0_MISO_PIN
|
miso = SPI0_MISO_PIN
|
||||||
}
|
}
|
||||||
spi.Bus.PSEL.SCK = nrf.RegValue(sck)
|
spi.Bus.PSEL.SCK.Set(uint32(sck))
|
||||||
spi.Bus.PSEL.MOSI = nrf.RegValue(mosi)
|
spi.Bus.PSEL.MOSI.Set(uint32(mosi))
|
||||||
spi.Bus.PSEL.MISO = nrf.RegValue(miso)
|
spi.Bus.PSEL.MISO.Set(uint32(miso))
|
||||||
}
|
}
|
||||||
|
|
||||||
// InitADC initializes the registers needed for ADC.
|
// InitADC initializes the registers needed for ADC.
|
||||||
@@ -93,53 +93,53 @@ func (a ADC) Get() uint16 {
|
|||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
nrf.SAADC.RESOLUTION = nrf.SAADC_RESOLUTION_VAL_12bit
|
nrf.SAADC.RESOLUTION.Set(nrf.SAADC_RESOLUTION_VAL_12bit)
|
||||||
|
|
||||||
// Enable ADC.
|
// Enable ADC.
|
||||||
nrf.SAADC.ENABLE = (nrf.SAADC_ENABLE_ENABLE_Enabled << nrf.SAADC_ENABLE_ENABLE_Pos)
|
nrf.SAADC.ENABLE.Set(nrf.SAADC_ENABLE_ENABLE_Enabled << nrf.SAADC_ENABLE_ENABLE_Pos)
|
||||||
for i := 0; i < 8; i++ {
|
for i := 0; i < 8; i++ {
|
||||||
nrf.SAADC.CH[i].PSELN = nrf.SAADC_CH_PSELP_PSELP_NC
|
nrf.SAADC.CH[i].PSELN.Set(nrf.SAADC_CH_PSELP_PSELP_NC)
|
||||||
nrf.SAADC.CH[i].PSELP = nrf.SAADC_CH_PSELP_PSELP_NC
|
nrf.SAADC.CH[i].PSELP.Set(nrf.SAADC_CH_PSELP_PSELP_NC)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Configure ADC.
|
// Configure ADC.
|
||||||
nrf.SAADC.CH[0].CONFIG = ((nrf.SAADC_CH_CONFIG_RESP_Bypass << nrf.SAADC_CH_CONFIG_RESP_Pos) & nrf.SAADC_CH_CONFIG_RESP_Msk) |
|
nrf.SAADC.CH[0].CONFIG.Set(((nrf.SAADC_CH_CONFIG_RESP_Bypass << nrf.SAADC_CH_CONFIG_RESP_Pos) & nrf.SAADC_CH_CONFIG_RESP_Msk) |
|
||||||
((nrf.SAADC_CH_CONFIG_RESP_Bypass << nrf.SAADC_CH_CONFIG_RESN_Pos) & nrf.SAADC_CH_CONFIG_RESN_Msk) |
|
((nrf.SAADC_CH_CONFIG_RESP_Bypass << nrf.SAADC_CH_CONFIG_RESN_Pos) & nrf.SAADC_CH_CONFIG_RESN_Msk) |
|
||||||
((nrf.SAADC_CH_CONFIG_GAIN_Gain1_5 << nrf.SAADC_CH_CONFIG_GAIN_Pos) & nrf.SAADC_CH_CONFIG_GAIN_Msk) |
|
((nrf.SAADC_CH_CONFIG_GAIN_Gain1_5 << nrf.SAADC_CH_CONFIG_GAIN_Pos) & nrf.SAADC_CH_CONFIG_GAIN_Msk) |
|
||||||
((nrf.SAADC_CH_CONFIG_REFSEL_Internal << nrf.SAADC_CH_CONFIG_REFSEL_Pos) & nrf.SAADC_CH_CONFIG_REFSEL_Msk) |
|
((nrf.SAADC_CH_CONFIG_REFSEL_Internal << nrf.SAADC_CH_CONFIG_REFSEL_Pos) & nrf.SAADC_CH_CONFIG_REFSEL_Msk) |
|
||||||
((nrf.SAADC_CH_CONFIG_TACQ_3us << nrf.SAADC_CH_CONFIG_TACQ_Pos) & nrf.SAADC_CH_CONFIG_TACQ_Msk) |
|
((nrf.SAADC_CH_CONFIG_TACQ_3us << nrf.SAADC_CH_CONFIG_TACQ_Pos) & nrf.SAADC_CH_CONFIG_TACQ_Msk) |
|
||||||
((nrf.SAADC_CH_CONFIG_MODE_SE << nrf.SAADC_CH_CONFIG_MODE_Pos) & nrf.SAADC_CH_CONFIG_MODE_Msk)
|
((nrf.SAADC_CH_CONFIG_MODE_SE << nrf.SAADC_CH_CONFIG_MODE_Pos) & nrf.SAADC_CH_CONFIG_MODE_Msk))
|
||||||
|
|
||||||
// Set pin to read.
|
// Set pin to read.
|
||||||
nrf.SAADC.CH[0].PSELN = nrf.RegValue(pwmPin)
|
nrf.SAADC.CH[0].PSELN.Set(pwmPin)
|
||||||
nrf.SAADC.CH[0].PSELP = nrf.RegValue(pwmPin)
|
nrf.SAADC.CH[0].PSELP.Set(pwmPin)
|
||||||
|
|
||||||
// Destination for sample result.
|
// Destination for sample result.
|
||||||
nrf.SAADC.RESULT.PTR = nrf.RegValue(uintptr(unsafe.Pointer(&value)))
|
nrf.SAADC.RESULT.PTR.Set(uint32(uintptr(unsafe.Pointer(&value))))
|
||||||
nrf.SAADC.RESULT.MAXCNT = 1 // One sample
|
nrf.SAADC.RESULT.MAXCNT.Set(1) // One sample
|
||||||
|
|
||||||
// Start tasks.
|
// Start tasks.
|
||||||
nrf.SAADC.TASKS_START = 1
|
nrf.SAADC.TASKS_START.Set(1)
|
||||||
for nrf.SAADC.EVENTS_STARTED == 0 {
|
for nrf.SAADC.EVENTS_STARTED.Get() == 0 {
|
||||||
}
|
}
|
||||||
nrf.SAADC.EVENTS_STARTED = 0x00
|
nrf.SAADC.EVENTS_STARTED.Set(0x00)
|
||||||
|
|
||||||
// Start the sample task.
|
// Start the sample task.
|
||||||
nrf.SAADC.TASKS_SAMPLE = 1
|
nrf.SAADC.TASKS_SAMPLE.Set(1)
|
||||||
|
|
||||||
// Wait until the sample task is done.
|
// Wait until the sample task is done.
|
||||||
for nrf.SAADC.EVENTS_END == 0 {
|
for nrf.SAADC.EVENTS_END.Get() == 0 {
|
||||||
}
|
}
|
||||||
nrf.SAADC.EVENTS_END = 0x00
|
nrf.SAADC.EVENTS_END.Set(0x00)
|
||||||
|
|
||||||
// Stop the ADC
|
// Stop the ADC
|
||||||
nrf.SAADC.TASKS_STOP = 1
|
nrf.SAADC.TASKS_STOP.Set(1)
|
||||||
for nrf.SAADC.EVENTS_STOPPED == 0 {
|
for nrf.SAADC.EVENTS_STOPPED.Get() == 0 {
|
||||||
}
|
}
|
||||||
nrf.SAADC.EVENTS_STOPPED = 0
|
nrf.SAADC.EVENTS_STOPPED.Set(0)
|
||||||
|
|
||||||
// Disable the ADC.
|
// Disable the ADC.
|
||||||
nrf.SAADC.ENABLE = (nrf.SAADC_ENABLE_ENABLE_Disabled << nrf.SAADC_ENABLE_ENABLE_Pos)
|
nrf.SAADC.ENABLE.Set(nrf.SAADC_ENABLE_ENABLE_Disabled << nrf.SAADC_ENABLE_ENABLE_Pos)
|
||||||
|
|
||||||
if value < 0 {
|
if value < 0 {
|
||||||
value = 0
|
value = 0
|
||||||
@@ -174,21 +174,21 @@ func (pwm PWM) Set(value uint16) {
|
|||||||
|
|
||||||
p := pwms[i]
|
p := pwms[i]
|
||||||
|
|
||||||
p.PSEL.OUT[0] = nrf.RegValue(pwm.Pin)
|
p.PSEL.OUT[0].Set(uint32(pwm.Pin))
|
||||||
p.PSEL.OUT[1] = nrf.RegValue(pwm.Pin)
|
p.PSEL.OUT[1].Set(uint32(pwm.Pin))
|
||||||
p.PSEL.OUT[2] = nrf.RegValue(pwm.Pin)
|
p.PSEL.OUT[2].Set(uint32(pwm.Pin))
|
||||||
p.PSEL.OUT[3] = nrf.RegValue(pwm.Pin)
|
p.PSEL.OUT[3].Set(uint32(pwm.Pin))
|
||||||
p.ENABLE = (nrf.PWM_ENABLE_ENABLE_Enabled << nrf.PWM_ENABLE_ENABLE_Pos)
|
p.ENABLE.Set(nrf.PWM_ENABLE_ENABLE_Enabled << nrf.PWM_ENABLE_ENABLE_Pos)
|
||||||
p.PRESCALER = nrf.PWM_PRESCALER_PRESCALER_DIV_2
|
p.PRESCALER.Set(nrf.PWM_PRESCALER_PRESCALER_DIV_2)
|
||||||
p.MODE = nrf.PWM_MODE_UPDOWN_Up
|
p.MODE.Set(nrf.PWM_MODE_UPDOWN_Up)
|
||||||
p.COUNTERTOP = 16384 // frequency
|
p.COUNTERTOP.Set(16384) // frequency
|
||||||
p.LOOP = 0
|
p.LOOP.Set(0)
|
||||||
p.DECODER = (nrf.PWM_DECODER_LOAD_Common << nrf.PWM_DECODER_LOAD_Pos) | (nrf.PWM_DECODER_MODE_RefreshCount << nrf.PWM_DECODER_MODE_Pos)
|
p.DECODER.Set((nrf.PWM_DECODER_LOAD_Common << nrf.PWM_DECODER_LOAD_Pos) | (nrf.PWM_DECODER_MODE_RefreshCount << nrf.PWM_DECODER_MODE_Pos))
|
||||||
p.SEQ[0].PTR = nrf.RegValue(uintptr(unsafe.Pointer(&pwmChannelSequence[i])))
|
p.SEQ[0].PTR.Set(uint32(uintptr(unsafe.Pointer(&pwmChannelSequence[i]))))
|
||||||
p.SEQ[0].CNT = 1
|
p.SEQ[0].CNT.Set(1)
|
||||||
p.SEQ[0].REFRESH = 1
|
p.SEQ[0].REFRESH.Set(1)
|
||||||
p.SEQ[0].ENDDELAY = 0
|
p.SEQ[0].ENDDELAY.Set(0)
|
||||||
p.TASKS_SEQSTART[0] = 1
|
p.TASKS_SEQSTART[0].Set(1)
|
||||||
|
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,10 +4,10 @@ package machine
|
|||||||
|
|
||||||
// Peripheral abstraction layer for the stm32.
|
// Peripheral abstraction layer for the stm32.
|
||||||
|
|
||||||
type GPIOMode uint8
|
type PinMode uint8
|
||||||
|
|
||||||
const (
|
const (
|
||||||
portA = iota * 16
|
portA Pin = iota * 16
|
||||||
portB
|
portB
|
||||||
portC
|
portC
|
||||||
portD
|
portD
|
||||||
|
|||||||
+131
-126
@@ -13,25 +13,25 @@ import (
|
|||||||
const CPU_FREQUENCY = 72000000
|
const CPU_FREQUENCY = 72000000
|
||||||
|
|
||||||
const (
|
const (
|
||||||
GPIO_INPUT = 0 // Input mode
|
PinInput PinMode = 0 // Input mode
|
||||||
GPIO_OUTPUT_10MHz = 1 // Output mode, max speed 10MHz
|
PinOutput10MHz PinMode = 1 // Output mode, max speed 10MHz
|
||||||
GPIO_OUTPUT_2MHz = 2 // Output mode, max speed 2MHz
|
PinOutput2MHz PinMode = 2 // Output mode, max speed 2MHz
|
||||||
GPIO_OUTPUT_50MHz = 3 // Output mode, max speed 50MHz
|
PinOutput50MHz PinMode = 3 // Output mode, max speed 50MHz
|
||||||
GPIO_OUTPUT = GPIO_OUTPUT_2MHz
|
PinOutput PinMode = PinOutput2MHz
|
||||||
|
|
||||||
GPIO_INPUT_MODE_ANALOG = 0 // Input analog mode
|
PinInputModeAnalog PinMode = 0 // Input analog mode
|
||||||
GPIO_INPUT_MODE_FLOATING = 4 // Input floating mode
|
PinInputModeFloating PinMode = 4 // Input floating mode
|
||||||
GPIO_INPUT_MODE_PULL_UP_DOWN = 8 // Input pull up/down mode
|
PinInputModePullUpDown PinMode = 8 // Input pull up/down mode
|
||||||
GPIO_INPUT_MODE_RESERVED = 12 // Input mode (reserved)
|
PinInputModeReserved PinMode = 12 // Input mode (reserved)
|
||||||
|
|
||||||
GPIO_OUTPUT_MODE_GP_PUSH_PULL = 0 // Output mode general purpose push/pull
|
PinOutputModeGPPushPull PinMode = 0 // Output mode general purpose push/pull
|
||||||
GPIO_OUTPUT_MODE_GP_OPEN_DRAIN = 4 // Output mode general purpose open drain
|
PinOutputModeGPOpenDrain PinMode = 4 // Output mode general purpose open drain
|
||||||
GPIO_OUTPUT_MODE_ALT_PUSH_PULL = 8 // Output mode alt. purpose push/pull
|
PinOutputModeAltPushPull PinMode = 8 // Output mode alt. purpose push/pull
|
||||||
GPIO_OUTPUT_MODE_ALT_OPEN_DRAIN = 12 // Output mode alt. purpose open drain
|
PinOutputModeAltOpenDrain PinMode = 12 // Output mode alt. purpose open drain
|
||||||
)
|
)
|
||||||
|
|
||||||
func (p GPIO) getPort() *stm32.GPIO_Type {
|
func (p Pin) getPort() *stm32.GPIO_Type {
|
||||||
switch p.Pin / 16 {
|
switch p / 16 {
|
||||||
case 0:
|
case 0:
|
||||||
return stm32.GPIOA
|
return stm32.GPIOA
|
||||||
case 1:
|
case 1:
|
||||||
@@ -52,50 +52,50 @@ func (p GPIO) getPort() *stm32.GPIO_Type {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// enableClock enables the clock for this desired GPIO port.
|
// enableClock enables the clock for this desired GPIO port.
|
||||||
func (p GPIO) enableClock() {
|
func (p Pin) enableClock() {
|
||||||
switch p.Pin / 16 {
|
switch p / 16 {
|
||||||
case 0:
|
case 0:
|
||||||
stm32.RCC.APB2ENR |= stm32.RCC_APB2ENR_IOPAEN
|
stm32.RCC.APB2ENR.SetBits(stm32.RCC_APB2ENR_IOPAEN)
|
||||||
case 1:
|
case 1:
|
||||||
stm32.RCC.APB2ENR |= stm32.RCC_APB2ENR_IOPBEN
|
stm32.RCC.APB2ENR.SetBits(stm32.RCC_APB2ENR_IOPBEN)
|
||||||
case 2:
|
case 2:
|
||||||
stm32.RCC.APB2ENR |= stm32.RCC_APB2ENR_IOPCEN
|
stm32.RCC.APB2ENR.SetBits(stm32.RCC_APB2ENR_IOPCEN)
|
||||||
case 3:
|
case 3:
|
||||||
stm32.RCC.APB2ENR |= stm32.RCC_APB2ENR_IOPDEN
|
stm32.RCC.APB2ENR.SetBits(stm32.RCC_APB2ENR_IOPDEN)
|
||||||
case 4:
|
case 4:
|
||||||
stm32.RCC.APB2ENR |= stm32.RCC_APB2ENR_IOPEEN
|
stm32.RCC.APB2ENR.SetBits(stm32.RCC_APB2ENR_IOPEEN)
|
||||||
case 5:
|
case 5:
|
||||||
stm32.RCC.APB2ENR |= stm32.RCC_APB2ENR_IOPFEN
|
stm32.RCC.APB2ENR.SetBits(stm32.RCC_APB2ENR_IOPFEN)
|
||||||
case 6:
|
case 6:
|
||||||
stm32.RCC.APB2ENR |= stm32.RCC_APB2ENR_IOPGEN
|
stm32.RCC.APB2ENR.SetBits(stm32.RCC_APB2ENR_IOPGEN)
|
||||||
default:
|
default:
|
||||||
panic("machine: unknown port")
|
panic("machine: unknown port")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Configure this pin with the given configuration.
|
// Configure this pin with the given configuration.
|
||||||
func (p GPIO) Configure(config GPIOConfig) {
|
func (p Pin) Configure(config PinConfig) {
|
||||||
// Configure the GPIO pin.
|
// Configure the GPIO pin.
|
||||||
p.enableClock()
|
p.enableClock()
|
||||||
port := p.getPort()
|
port := p.getPort()
|
||||||
pin := p.Pin % 16
|
pin := uint8(p) % 16
|
||||||
pos := p.Pin % 8 * 4
|
pos := uint8(p) % 8 * 4
|
||||||
if pin < 8 {
|
if pin < 8 {
|
||||||
port.CRL = stm32.RegValue((uint32(port.CRL) &^ (0xf << pos)) | (uint32(config.Mode) << pos))
|
port.CRL.Set((uint32(port.CRL.Get()) &^ (0xf << pos)) | (uint32(config.Mode) << pos))
|
||||||
} else {
|
} else {
|
||||||
port.CRH = stm32.RegValue((uint32(port.CRH) &^ (0xf << pos)) | (uint32(config.Mode) << pos))
|
port.CRH.Set((uint32(port.CRH.Get()) &^ (0xf << pos)) | (uint32(config.Mode) << pos))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set the pin to high or low.
|
// Set the pin to high or low.
|
||||||
// Warning: only use this on an output pin!
|
// Warning: only use this on an output pin!
|
||||||
func (p GPIO) Set(high bool) {
|
func (p Pin) Set(high bool) {
|
||||||
port := p.getPort()
|
port := p.getPort()
|
||||||
pin := p.Pin % 16
|
pin := uint8(p) % 16
|
||||||
if high {
|
if high {
|
||||||
port.BSRR = 1 << pin
|
port.BSRR.Set(1 << pin)
|
||||||
} else {
|
} else {
|
||||||
port.BSRR = 1 << (pin + 16)
|
port.BSRR.Set(1 << (pin + 16))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -122,24 +122,24 @@ func (uart UART) Configure(config UARTConfig) {
|
|||||||
switch config.TX {
|
switch config.TX {
|
||||||
case PB6:
|
case PB6:
|
||||||
// use alternate TX/RX pins PB6/PB7 via AFIO mapping
|
// use alternate TX/RX pins PB6/PB7 via AFIO mapping
|
||||||
stm32.RCC.APB2ENR |= stm32.RCC_APB2ENR_AFIOEN
|
stm32.RCC.APB2ENR.SetBits(stm32.RCC_APB2ENR_AFIOEN)
|
||||||
stm32.AFIO.MAPR |= stm32.AFIO_MAPR_USART1_REMAP
|
stm32.AFIO.MAPR.SetBits(stm32.AFIO_MAPR_USART1_REMAP)
|
||||||
GPIO{PB6}.Configure(GPIOConfig{Mode: GPIO_OUTPUT_50MHz + GPIO_OUTPUT_MODE_ALT_PUSH_PULL})
|
PB6.Configure(PinConfig{Mode: PinOutput50MHz + PinOutputModeAltPushPull})
|
||||||
GPIO{PB7}.Configure(GPIOConfig{Mode: GPIO_INPUT_MODE_FLOATING})
|
PB7.Configure(PinConfig{Mode: PinInputModeFloating})
|
||||||
default:
|
default:
|
||||||
// use standard TX/RX pins PA9 and PA10
|
// use standard TX/RX pins PA9 and PA10
|
||||||
GPIO{UART_TX_PIN}.Configure(GPIOConfig{Mode: GPIO_OUTPUT_50MHz + GPIO_OUTPUT_MODE_ALT_PUSH_PULL})
|
UART_TX_PIN.Configure(PinConfig{Mode: PinOutput50MHz + PinOutputModeAltPushPull})
|
||||||
GPIO{UART_RX_PIN}.Configure(GPIOConfig{Mode: GPIO_INPUT_MODE_FLOATING})
|
UART_RX_PIN.Configure(PinConfig{Mode: PinInputModeFloating})
|
||||||
}
|
}
|
||||||
|
|
||||||
// Enable USART1 clock
|
// Enable USART1 clock
|
||||||
stm32.RCC.APB2ENR |= stm32.RCC_APB2ENR_USART1EN
|
stm32.RCC.APB2ENR.SetBits(stm32.RCC_APB2ENR_USART1EN)
|
||||||
|
|
||||||
// Set baud rate
|
// Set baud rate
|
||||||
uart.SetBaudRate(config.BaudRate)
|
uart.SetBaudRate(config.BaudRate)
|
||||||
|
|
||||||
// Enable USART1 port.
|
// Enable USART1 port.
|
||||||
stm32.USART1.CR1 = stm32.USART_CR1_TE | stm32.USART_CR1_RE | stm32.USART_CR1_RXNEIE | stm32.USART_CR1_UE
|
stm32.USART1.CR1.Set(stm32.USART_CR1_TE | stm32.USART_CR1_RE | stm32.USART_CR1_RXNEIE | stm32.USART_CR1_UE)
|
||||||
|
|
||||||
// Enable RX IRQ.
|
// Enable RX IRQ.
|
||||||
arm.SetPriority(stm32.IRQ_USART1, 0xc0)
|
arm.SetPriority(stm32.IRQ_USART1, 0xc0)
|
||||||
@@ -150,21 +150,21 @@ func (uart UART) Configure(config UARTConfig) {
|
|||||||
func (uart UART) SetBaudRate(br uint32) {
|
func (uart UART) SetBaudRate(br uint32) {
|
||||||
// first divide by PCLK2 prescaler (div 1) and then desired baudrate
|
// first divide by PCLK2 prescaler (div 1) and then desired baudrate
|
||||||
divider := CPU_FREQUENCY / br
|
divider := CPU_FREQUENCY / br
|
||||||
stm32.USART1.BRR = stm32.RegValue(divider)
|
stm32.USART1.BRR.Set(divider)
|
||||||
}
|
}
|
||||||
|
|
||||||
// WriteByte writes a byte of data to the UART.
|
// WriteByte writes a byte of data to the UART.
|
||||||
func (uart UART) WriteByte(c byte) error {
|
func (uart UART) WriteByte(c byte) error {
|
||||||
stm32.USART1.DR = stm32.RegValue(c)
|
stm32.USART1.DR.Set(uint32(c))
|
||||||
|
|
||||||
for (stm32.USART1.SR & stm32.USART_SR_TXE) == 0 {
|
for !stm32.USART1.SR.HasBits(stm32.USART_SR_TXE) {
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
//go:export USART1_IRQHandler
|
//go:export USART1_IRQHandler
|
||||||
func handleUART1() {
|
func handleUART1() {
|
||||||
UART1.Receive(byte((stm32.USART1.DR & 0xFF)))
|
UART1.Receive(byte((stm32.USART1.DR.Get() & 0xFF)))
|
||||||
}
|
}
|
||||||
|
|
||||||
// SPI on the STM32.
|
// SPI on the STM32.
|
||||||
@@ -183,9 +183,9 @@ var (
|
|||||||
// SPIConfig is used to store config info for SPI.
|
// SPIConfig is used to store config info for SPI.
|
||||||
type SPIConfig struct {
|
type SPIConfig struct {
|
||||||
Frequency uint32
|
Frequency uint32
|
||||||
SCK uint8
|
SCK Pin
|
||||||
MOSI uint8
|
MOSI Pin
|
||||||
MISO uint8
|
MISO Pin
|
||||||
LSBFirst bool
|
LSBFirst bool
|
||||||
Mode uint8
|
Mode uint8
|
||||||
}
|
}
|
||||||
@@ -198,9 +198,9 @@ type SPIConfig struct {
|
|||||||
// - hardware SS pin?
|
// - hardware SS pin?
|
||||||
func (spi SPI) Configure(config SPIConfig) {
|
func (spi SPI) Configure(config SPIConfig) {
|
||||||
// enable clock for SPI
|
// enable clock for SPI
|
||||||
stm32.RCC.APB2ENR |= stm32.RCC_APB2ENR_SPI1EN
|
stm32.RCC.APB2ENR.SetBits(stm32.RCC_APB2ENR_SPI1EN)
|
||||||
|
|
||||||
var conf uint16
|
var conf uint32
|
||||||
|
|
||||||
// set frequency
|
// set frequency
|
||||||
switch config.Frequency {
|
switch config.Frequency {
|
||||||
@@ -250,37 +250,37 @@ func (spi SPI) Configure(config SPIConfig) {
|
|||||||
conf |= stm32.SPI_Mode_Master
|
conf |= stm32.SPI_Mode_Master
|
||||||
|
|
||||||
// now set the configuration
|
// now set the configuration
|
||||||
spi.Bus.CR1 = stm32.RegValue(conf)
|
spi.Bus.CR1.Set(conf)
|
||||||
|
|
||||||
// init pins
|
// init pins
|
||||||
spi.setPins(config.SCK, config.MOSI, config.MISO)
|
spi.setPins(config.SCK, config.MOSI, config.MISO)
|
||||||
|
|
||||||
// enable SPI interface
|
// enable SPI interface
|
||||||
spi.Bus.CR1 |= stm32.SPI_CR1_SPE
|
spi.Bus.CR1.SetBits(stm32.SPI_CR1_SPE)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Transfer writes/reads a single byte using the SPI interface.
|
// Transfer writes/reads a single byte using the SPI interface.
|
||||||
func (spi SPI) Transfer(w byte) (byte, error) {
|
func (spi SPI) Transfer(w byte) (byte, error) {
|
||||||
// Write data to be transmitted to the SPI data register
|
// Write data to be transmitted to the SPI data register
|
||||||
spi.Bus.DR = stm32.RegValue(w)
|
spi.Bus.DR.Set(uint32(w))
|
||||||
|
|
||||||
// Wait until transmit complete
|
// Wait until transmit complete
|
||||||
for (spi.Bus.SR & stm32.SPI_SR_TXE) == 0 {
|
for !spi.Bus.SR.HasBits(stm32.SPI_SR_TXE) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Wait until receive complete
|
// Wait until receive complete
|
||||||
for (spi.Bus.SR & stm32.SPI_SR_RXNE) == 0 {
|
for !spi.Bus.SR.HasBits(stm32.SPI_SR_RXNE) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Wait until SPI is not busy
|
// Wait until SPI is not busy
|
||||||
for (spi.Bus.SR & stm32.SPI_SR_BSY) > 0 {
|
for spi.Bus.SR.HasBits(stm32.SPI_SR_BSY) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Return received data from SPI data register
|
// Return received data from SPI data register
|
||||||
return byte(spi.Bus.DR), nil
|
return byte(spi.Bus.DR.Get()), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (spi SPI) setPins(sck, mosi, miso uint8) {
|
func (spi SPI) setPins(sck, mosi, miso Pin) {
|
||||||
if sck == 0 {
|
if sck == 0 {
|
||||||
sck = SPI0_SCK_PIN
|
sck = SPI0_SCK_PIN
|
||||||
}
|
}
|
||||||
@@ -291,9 +291,9 @@ func (spi SPI) setPins(sck, mosi, miso uint8) {
|
|||||||
miso = SPI0_MISO_PIN
|
miso = SPI0_MISO_PIN
|
||||||
}
|
}
|
||||||
|
|
||||||
GPIO{sck}.Configure(GPIOConfig{Mode: GPIO_OUTPUT_50MHz + GPIO_OUTPUT_MODE_ALT_PUSH_PULL})
|
sck.Configure(PinConfig{Mode: PinOutput50MHz + PinOutputModeAltPushPull})
|
||||||
GPIO{mosi}.Configure(GPIOConfig{Mode: GPIO_OUTPUT_50MHz + GPIO_OUTPUT_MODE_ALT_PUSH_PULL})
|
mosi.Configure(PinConfig{Mode: PinOutput50MHz + PinOutputModeAltPushPull})
|
||||||
GPIO{miso}.Configure(GPIOConfig{Mode: GPIO_INPUT_MODE_FLOATING})
|
miso.Configure(PinConfig{Mode: PinInputModeFloating})
|
||||||
}
|
}
|
||||||
|
|
||||||
// I2C on the STM32F103xx.
|
// I2C on the STM32F103xx.
|
||||||
@@ -312,8 +312,8 @@ var (
|
|||||||
// I2CConfig is used to store config info for I2C.
|
// I2CConfig is used to store config info for I2C.
|
||||||
type I2CConfig struct {
|
type I2CConfig struct {
|
||||||
Frequency uint32
|
Frequency uint32
|
||||||
SCL uint8
|
SCL Pin
|
||||||
SDA uint8
|
SDA Pin
|
||||||
}
|
}
|
||||||
|
|
||||||
// Configure is intended to setup the I2C interface.
|
// Configure is intended to setup the I2C interface.
|
||||||
@@ -324,26 +324,26 @@ func (i2c I2C) Configure(config I2CConfig) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// enable clock for I2C
|
// enable clock for I2C
|
||||||
stm32.RCC.APB1ENR |= stm32.RCC_APB1ENR_I2C1EN
|
stm32.RCC.APB1ENR.SetBits(stm32.RCC_APB1ENR_I2C1EN)
|
||||||
|
|
||||||
// I2C1 pins
|
// I2C1 pins
|
||||||
switch config.SDA {
|
switch config.SDA {
|
||||||
case PB9:
|
case PB9:
|
||||||
config.SCL = PB8
|
config.SCL = PB8
|
||||||
// use alternate I2C1 pins PB8/PB9 via AFIO mapping
|
// use alternate I2C1 pins PB8/PB9 via AFIO mapping
|
||||||
stm32.RCC.APB2ENR |= stm32.RCC_APB2ENR_AFIOEN
|
stm32.RCC.APB2ENR.SetBits(stm32.RCC_APB2ENR_AFIOEN)
|
||||||
stm32.AFIO.MAPR |= stm32.AFIO_MAPR_I2C1_REMAP
|
stm32.AFIO.MAPR.SetBits(stm32.AFIO_MAPR_I2C1_REMAP)
|
||||||
default:
|
default:
|
||||||
// use default I2C1 pins PB6/PB7
|
// use default I2C1 pins PB6/PB7
|
||||||
config.SDA = SDA_PIN
|
config.SDA = SDA_PIN
|
||||||
config.SCL = SCL_PIN
|
config.SCL = SCL_PIN
|
||||||
}
|
}
|
||||||
|
|
||||||
GPIO{config.SDA}.Configure(GPIOConfig{Mode: GPIO_OUTPUT_50MHz + GPIO_OUTPUT_MODE_ALT_OPEN_DRAIN})
|
config.SDA.Configure(PinConfig{Mode: PinOutput50MHz + PinOutputModeAltOpenDrain})
|
||||||
GPIO{config.SCL}.Configure(GPIOConfig{Mode: GPIO_OUTPUT_50MHz + GPIO_OUTPUT_MODE_ALT_OPEN_DRAIN})
|
config.SCL.Configure(PinConfig{Mode: PinOutput50MHz + PinOutputModeAltOpenDrain})
|
||||||
|
|
||||||
// Disable the selected I2C peripheral to configure
|
// Disable the selected I2C peripheral to configure
|
||||||
i2c.Bus.CR1 &^= stm32.I2C_CR1_PE
|
i2c.Bus.CR1.ClearBits(stm32.I2C_CR1_PE)
|
||||||
|
|
||||||
// pclk1 clock speed is main frequency divided by PCK1 prescaler (div 2)
|
// pclk1 clock speed is main frequency divided by PCK1 prescaler (div 2)
|
||||||
pclk1 := uint32(CPU_FREQUENCY / 2)
|
pclk1 := uint32(CPU_FREQUENCY / 2)
|
||||||
@@ -351,40 +351,40 @@ func (i2c I2C) Configure(config I2CConfig) {
|
|||||||
// set freqency range to pclk1 clock speed in Mhz.
|
// set freqency range to pclk1 clock speed in Mhz.
|
||||||
// aka setting the value 36 means to use 36MhZ clock.
|
// aka setting the value 36 means to use 36MhZ clock.
|
||||||
pclk1Mhz := pclk1 / 1000000
|
pclk1Mhz := pclk1 / 1000000
|
||||||
i2c.Bus.CR2 |= stm32.RegValue(pclk1Mhz)
|
i2c.Bus.CR2.SetBits(pclk1Mhz)
|
||||||
|
|
||||||
switch config.Frequency {
|
switch config.Frequency {
|
||||||
case TWI_FREQ_100KHZ:
|
case TWI_FREQ_100KHZ:
|
||||||
// Normal mode speed calculation
|
// Normal mode speed calculation
|
||||||
ccr := pclk1 / (config.Frequency * 2)
|
ccr := pclk1 / (config.Frequency * 2)
|
||||||
i2c.Bus.CCR = stm32.RegValue(ccr)
|
i2c.Bus.CCR.Set(ccr)
|
||||||
|
|
||||||
// duty cycle 2
|
// duty cycle 2
|
||||||
i2c.Bus.CCR &^= stm32.I2C_CCR_DUTY
|
i2c.Bus.CCR.ClearBits(stm32.I2C_CCR_DUTY)
|
||||||
|
|
||||||
// frequency standard mode
|
// frequency standard mode
|
||||||
i2c.Bus.CCR &^= stm32.I2C_CCR_F_S
|
i2c.Bus.CCR.ClearBits(stm32.I2C_CCR_F_S)
|
||||||
|
|
||||||
// Set Maximum Rise Time for standard mode
|
// Set Maximum Rise Time for standard mode
|
||||||
i2c.Bus.TRISE = stm32.RegValue(pclk1Mhz)
|
i2c.Bus.TRISE.Set(pclk1Mhz)
|
||||||
|
|
||||||
case TWI_FREQ_400KHZ:
|
case TWI_FREQ_400KHZ:
|
||||||
// Fast mode speed calculation
|
// Fast mode speed calculation
|
||||||
ccr := pclk1 / (config.Frequency * 3)
|
ccr := pclk1 / (config.Frequency * 3)
|
||||||
i2c.Bus.CCR = stm32.RegValue(ccr)
|
i2c.Bus.CCR.Set(ccr)
|
||||||
|
|
||||||
// duty cycle 2
|
// duty cycle 2
|
||||||
i2c.Bus.CCR &^= stm32.I2C_CCR_DUTY
|
i2c.Bus.CCR.ClearBits(stm32.I2C_CCR_DUTY)
|
||||||
|
|
||||||
// frequency fast mode
|
// frequency fast mode
|
||||||
i2c.Bus.CCR |= stm32.I2C_CCR_F_S
|
i2c.Bus.CCR.SetBits(stm32.I2C_CCR_F_S)
|
||||||
|
|
||||||
// Set Maximum Rise Time for fast mode
|
// Set Maximum Rise Time for fast mode
|
||||||
i2c.Bus.TRISE = stm32.RegValue(((pclk1Mhz * 300) / 1000))
|
i2c.Bus.TRISE.Set(((pclk1Mhz * 300) / 1000))
|
||||||
}
|
}
|
||||||
|
|
||||||
// re-enable the selected I2C peripheral
|
// re-enable the selected I2C peripheral
|
||||||
i2c.Bus.CR1 |= stm32.I2C_CR1_PE
|
i2c.Bus.CR1.SetBits(stm32.I2C_CR1_PE)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Tx does a single I2C transaction at the specified address.
|
// Tx does a single I2C transaction at the specified address.
|
||||||
@@ -435,11 +435,11 @@ func (i2c I2C) Tx(addr uint16, w, r []byte) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Disable ACK of received data
|
// Disable ACK of received data
|
||||||
i2c.Bus.CR1 &^= stm32.I2C_CR1_ACK
|
i2c.Bus.CR1.ClearBits(stm32.I2C_CR1_ACK)
|
||||||
|
|
||||||
// clear timeout here
|
// clear timeout here
|
||||||
timeout := i2cTimeout
|
timeout := i2cTimeout
|
||||||
for i2c.Bus.SR2&(stm32.I2C_SR2_MSL|stm32.I2C_SR2_BUSY) == 0 {
|
for !i2c.Bus.SR2.HasBits(stm32.I2C_SR2_MSL | stm32.I2C_SR2_BUSY) {
|
||||||
timeout--
|
timeout--
|
||||||
if timeout == 0 {
|
if timeout == 0 {
|
||||||
return errors.New("I2C timeout on read clear address")
|
return errors.New("I2C timeout on read clear address")
|
||||||
@@ -447,10 +447,10 @@ func (i2c I2C) Tx(addr uint16, w, r []byte) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Generate stop condition
|
// Generate stop condition
|
||||||
i2c.Bus.CR1 |= stm32.I2C_CR1_STOP
|
i2c.Bus.CR1.SetBits(stm32.I2C_CR1_STOP)
|
||||||
|
|
||||||
timeout = i2cTimeout
|
timeout = i2cTimeout
|
||||||
for (i2c.Bus.SR1 & stm32.I2C_SR1_RxNE) == 0 {
|
for !i2c.Bus.SR1.HasBits(stm32.I2C_SR1_RxNE) {
|
||||||
timeout--
|
timeout--
|
||||||
if timeout == 0 {
|
if timeout == 0 {
|
||||||
return errors.New("I2C timeout on read 1 byte")
|
return errors.New("I2C timeout on read 1 byte")
|
||||||
@@ -458,17 +458,17 @@ func (i2c I2C) Tx(addr uint16, w, r []byte) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Read and return data byte from I2C data register
|
// Read and return data byte from I2C data register
|
||||||
r[0] = byte(i2c.Bus.DR)
|
r[0] = byte(i2c.Bus.DR.Get())
|
||||||
|
|
||||||
// wait for stop
|
// wait for stop
|
||||||
return i2c.waitForStop()
|
return i2c.waitForStop()
|
||||||
|
|
||||||
case 2:
|
case 2:
|
||||||
// enable pos
|
// enable pos
|
||||||
i2c.Bus.CR1 |= stm32.I2C_CR1_POS
|
i2c.Bus.CR1.SetBits(stm32.I2C_CR1_POS)
|
||||||
|
|
||||||
// Enable ACK of received data
|
// Enable ACK of received data
|
||||||
i2c.Bus.CR1 |= stm32.I2C_CR1_ACK
|
i2c.Bus.CR1.SetBits(stm32.I2C_CR1_ACK)
|
||||||
|
|
||||||
// send address
|
// send address
|
||||||
err = i2c.sendAddress(uint8(addr), false)
|
err = i2c.sendAddress(uint8(addr), false)
|
||||||
@@ -478,7 +478,7 @@ func (i2c I2C) Tx(addr uint16, w, r []byte) error {
|
|||||||
|
|
||||||
// clear address here
|
// clear address here
|
||||||
timeout := i2cTimeout
|
timeout := i2cTimeout
|
||||||
for i2c.Bus.SR2&(stm32.I2C_SR2_MSL|stm32.I2C_SR2_BUSY) == 0 {
|
for !i2c.Bus.SR2.HasBits(stm32.I2C_SR2_MSL | stm32.I2C_SR2_BUSY) {
|
||||||
timeout--
|
timeout--
|
||||||
if timeout == 0 {
|
if timeout == 0 {
|
||||||
return errors.New("I2C timeout on read clear address")
|
return errors.New("I2C timeout on read clear address")
|
||||||
@@ -486,11 +486,11 @@ func (i2c I2C) Tx(addr uint16, w, r []byte) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Disable ACK of received data
|
// Disable ACK of received data
|
||||||
i2c.Bus.CR1 &^= stm32.I2C_CR1_ACK
|
i2c.Bus.CR1.ClearBits(stm32.I2C_CR1_ACK)
|
||||||
|
|
||||||
// wait for btf. we need a longer timeout here than normal.
|
// wait for btf. we need a longer timeout here than normal.
|
||||||
timeout = 1000
|
timeout = 1000
|
||||||
for (i2c.Bus.SR1 & stm32.I2C_SR1_BTF) == 0 {
|
for !i2c.Bus.SR1.HasBits(stm32.I2C_SR1_BTF) {
|
||||||
timeout--
|
timeout--
|
||||||
if timeout == 0 {
|
if timeout == 0 {
|
||||||
return errors.New("I2C timeout on read 2 bytes")
|
return errors.New("I2C timeout on read 2 bytes")
|
||||||
@@ -498,18 +498,23 @@ func (i2c I2C) Tx(addr uint16, w, r []byte) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Generate stop condition
|
// Generate stop condition
|
||||||
i2c.Bus.CR1 |= stm32.I2C_CR1_STOP
|
i2c.Bus.CR1.SetBits(stm32.I2C_CR1_STOP)
|
||||||
|
|
||||||
// read the 2 bytes by reading twice.
|
// read the 2 bytes by reading twice.
|
||||||
r[0] = byte(i2c.Bus.DR)
|
r[0] = byte(i2c.Bus.DR.Get())
|
||||||
r[1] = byte(i2c.Bus.DR)
|
r[1] = byte(i2c.Bus.DR.Get())
|
||||||
|
|
||||||
// wait for stop
|
// wait for stop
|
||||||
return i2c.waitForStop()
|
err = i2c.waitForStop()
|
||||||
|
|
||||||
|
//disable pos
|
||||||
|
i2c.Bus.CR1.ClearBits(stm32.I2C_CR1_POS)
|
||||||
|
|
||||||
|
return err
|
||||||
|
|
||||||
case 3:
|
case 3:
|
||||||
// Enable ACK of received data
|
// Enable ACK of received data
|
||||||
i2c.Bus.CR1 |= stm32.I2C_CR1_ACK
|
i2c.Bus.CR1.SetBits(stm32.I2C_CR1_ACK)
|
||||||
|
|
||||||
// send address
|
// send address
|
||||||
err = i2c.sendAddress(uint8(addr), false)
|
err = i2c.sendAddress(uint8(addr), false)
|
||||||
@@ -519,7 +524,7 @@ func (i2c I2C) Tx(addr uint16, w, r []byte) error {
|
|||||||
|
|
||||||
// clear address here
|
// clear address here
|
||||||
timeout := i2cTimeout
|
timeout := i2cTimeout
|
||||||
for i2c.Bus.SR2&(stm32.I2C_SR2_MSL|stm32.I2C_SR2_BUSY) == 0 {
|
for !i2c.Bus.SR2.HasBits(stm32.I2C_SR2_MSL | stm32.I2C_SR2_BUSY) {
|
||||||
timeout--
|
timeout--
|
||||||
if timeout == 0 {
|
if timeout == 0 {
|
||||||
return errors.New("I2C timeout on read clear address")
|
return errors.New("I2C timeout on read clear address")
|
||||||
@@ -527,11 +532,11 @@ func (i2c I2C) Tx(addr uint16, w, r []byte) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Enable ACK of received data
|
// Enable ACK of received data
|
||||||
i2c.Bus.CR1 |= stm32.I2C_CR1_ACK
|
i2c.Bus.CR1.SetBits(stm32.I2C_CR1_ACK)
|
||||||
|
|
||||||
// wait for btf. we need a longer timeout here than normal.
|
// wait for btf. we need a longer timeout here than normal.
|
||||||
timeout = 1000
|
timeout = 1000
|
||||||
for (i2c.Bus.SR1 & stm32.I2C_SR1_BTF) == 0 {
|
for !i2c.Bus.SR1.HasBits(stm32.I2C_SR1_BTF) {
|
||||||
timeout--
|
timeout--
|
||||||
if timeout == 0 {
|
if timeout == 0 {
|
||||||
println("I2C timeout on read 3 bytes")
|
println("I2C timeout on read 3 bytes")
|
||||||
@@ -540,13 +545,13 @@ func (i2c I2C) Tx(addr uint16, w, r []byte) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Disable ACK of received data
|
// Disable ACK of received data
|
||||||
i2c.Bus.CR1 &^= stm32.I2C_CR1_ACK
|
i2c.Bus.CR1.ClearBits(stm32.I2C_CR1_ACK)
|
||||||
|
|
||||||
// read the first byte
|
// read the first byte
|
||||||
r[0] = byte(i2c.Bus.DR)
|
r[0] = byte(i2c.Bus.DR.Get())
|
||||||
|
|
||||||
timeout = 1000
|
timeout = 1000
|
||||||
for (i2c.Bus.SR1 & stm32.I2C_SR1_BTF) == 0 {
|
for !i2c.Bus.SR1.HasBits(stm32.I2C_SR1_BTF) {
|
||||||
timeout--
|
timeout--
|
||||||
if timeout == 0 {
|
if timeout == 0 {
|
||||||
return errors.New("I2C timeout on read 3 bytes")
|
return errors.New("I2C timeout on read 3 bytes")
|
||||||
@@ -554,11 +559,11 @@ func (i2c I2C) Tx(addr uint16, w, r []byte) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Generate stop condition
|
// Generate stop condition
|
||||||
i2c.Bus.CR1 |= stm32.I2C_CR1_STOP
|
i2c.Bus.CR1.SetBits(stm32.I2C_CR1_STOP)
|
||||||
|
|
||||||
// read the last 2 bytes by reading twice.
|
// read the last 2 bytes by reading twice.
|
||||||
r[1] = byte(i2c.Bus.DR)
|
r[1] = byte(i2c.Bus.DR.Get())
|
||||||
r[2] = byte(i2c.Bus.DR)
|
r[2] = byte(i2c.Bus.DR.Get())
|
||||||
|
|
||||||
// wait for stop
|
// wait for stop
|
||||||
return i2c.waitForStop()
|
return i2c.waitForStop()
|
||||||
@@ -574,7 +579,7 @@ func (i2c I2C) Tx(addr uint16, w, r []byte) error {
|
|||||||
|
|
||||||
// clear address here
|
// clear address here
|
||||||
timeout := i2cTimeout
|
timeout := i2cTimeout
|
||||||
for i2c.Bus.SR2&(stm32.I2C_SR2_MSL|stm32.I2C_SR2_BUSY) == 0 {
|
for !i2c.Bus.SR2.HasBits(stm32.I2C_SR2_MSL | stm32.I2C_SR2_BUSY) {
|
||||||
timeout--
|
timeout--
|
||||||
if timeout == 0 {
|
if timeout == 0 {
|
||||||
return errors.New("I2C timeout on read clear address")
|
return errors.New("I2C timeout on read clear address")
|
||||||
@@ -583,11 +588,11 @@ func (i2c I2C) Tx(addr uint16, w, r []byte) error {
|
|||||||
|
|
||||||
for i := 0; i < len(r)-3; i++ {
|
for i := 0; i < len(r)-3; i++ {
|
||||||
// Enable ACK of received data
|
// Enable ACK of received data
|
||||||
i2c.Bus.CR1 |= stm32.I2C_CR1_ACK
|
i2c.Bus.CR1.SetBits(stm32.I2C_CR1_ACK)
|
||||||
|
|
||||||
// wait for btf. we need a longer timeout here than normal.
|
// wait for btf. we need a longer timeout here than normal.
|
||||||
timeout = 1000
|
timeout = 1000
|
||||||
for (i2c.Bus.SR1 & stm32.I2C_SR1_BTF) == 0 {
|
for !i2c.Bus.SR1.HasBits(stm32.I2C_SR1_BTF) {
|
||||||
timeout--
|
timeout--
|
||||||
if timeout == 0 {
|
if timeout == 0 {
|
||||||
println("I2C timeout on read 3 bytes")
|
println("I2C timeout on read 3 bytes")
|
||||||
@@ -596,12 +601,12 @@ func (i2c I2C) Tx(addr uint16, w, r []byte) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// read the next byte
|
// read the next byte
|
||||||
r[i] = byte(i2c.Bus.DR)
|
r[i] = byte(i2c.Bus.DR.Get())
|
||||||
}
|
}
|
||||||
|
|
||||||
// wait for btf. we need a longer timeout here than normal.
|
// wait for btf. we need a longer timeout here than normal.
|
||||||
timeout = 1000
|
timeout = 1000
|
||||||
for (i2c.Bus.SR1 & stm32.I2C_SR1_BTF) == 0 {
|
for !i2c.Bus.SR1.HasBits(stm32.I2C_SR1_BTF) {
|
||||||
timeout--
|
timeout--
|
||||||
if timeout == 0 {
|
if timeout == 0 {
|
||||||
return errors.New("I2C timeout on read more than 3 bytes")
|
return errors.New("I2C timeout on read more than 3 bytes")
|
||||||
@@ -609,19 +614,19 @@ func (i2c I2C) Tx(addr uint16, w, r []byte) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Disable ACK of received data
|
// Disable ACK of received data
|
||||||
i2c.Bus.CR1 &^= stm32.I2C_CR1_ACK
|
i2c.Bus.CR1.ClearBits(stm32.I2C_CR1_ACK)
|
||||||
|
|
||||||
// get third from last byte
|
// get third from last byte
|
||||||
r[len(r)-3] = byte(i2c.Bus.DR)
|
r[len(r)-3] = byte(i2c.Bus.DR.Get())
|
||||||
|
|
||||||
// Generate stop condition
|
// Generate stop condition
|
||||||
i2c.Bus.CR1 |= stm32.I2C_CR1_STOP
|
i2c.Bus.CR1.SetBits(stm32.I2C_CR1_STOP)
|
||||||
|
|
||||||
// get second from last byte
|
// get second from last byte
|
||||||
r[len(r)-2] = byte(i2c.Bus.DR)
|
r[len(r)-2] = byte(i2c.Bus.DR.Get())
|
||||||
|
|
||||||
timeout = i2cTimeout
|
timeout = i2cTimeout
|
||||||
for (i2c.Bus.SR1 & stm32.I2C_SR1_RxNE) == 0 {
|
for !i2c.Bus.SR1.HasBits(stm32.I2C_SR1_RxNE) {
|
||||||
timeout--
|
timeout--
|
||||||
if timeout == 0 {
|
if timeout == 0 {
|
||||||
return errors.New("I2C timeout on read last byte of more than 3")
|
return errors.New("I2C timeout on read last byte of more than 3")
|
||||||
@@ -629,7 +634,7 @@ func (i2c I2C) Tx(addr uint16, w, r []byte) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// get last byte
|
// get last byte
|
||||||
r[len(r)-1] = byte(i2c.Bus.DR)
|
r[len(r)-1] = byte(i2c.Bus.DR.Get())
|
||||||
|
|
||||||
// wait for stop
|
// wait for stop
|
||||||
return i2c.waitForStop()
|
return i2c.waitForStop()
|
||||||
@@ -645,7 +650,7 @@ const i2cTimeout = 500
|
|||||||
func (i2c I2C) signalStart() error {
|
func (i2c I2C) signalStart() error {
|
||||||
// Wait until I2C is not busy
|
// Wait until I2C is not busy
|
||||||
timeout := i2cTimeout
|
timeout := i2cTimeout
|
||||||
for (i2c.Bus.SR2 & stm32.I2C_SR2_BUSY) > 0 {
|
for i2c.Bus.SR2.HasBits(stm32.I2C_SR2_BUSY) {
|
||||||
timeout--
|
timeout--
|
||||||
if timeout == 0 {
|
if timeout == 0 {
|
||||||
return errors.New("I2C busy on start")
|
return errors.New("I2C busy on start")
|
||||||
@@ -653,14 +658,14 @@ func (i2c I2C) signalStart() error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// clear stop
|
// clear stop
|
||||||
i2c.Bus.CR1 &^= stm32.I2C_CR1_STOP
|
i2c.Bus.CR1.ClearBits(stm32.I2C_CR1_STOP)
|
||||||
|
|
||||||
// Generate start condition
|
// Generate start condition
|
||||||
i2c.Bus.CR1 |= stm32.I2C_CR1_START
|
i2c.Bus.CR1.SetBits(stm32.I2C_CR1_START)
|
||||||
|
|
||||||
// Wait for I2C EV5 aka SB flag.
|
// Wait for I2C EV5 aka SB flag.
|
||||||
timeout = i2cTimeout
|
timeout = i2cTimeout
|
||||||
for (i2c.Bus.SR1 & stm32.I2C_SR1_SB) == 0 {
|
for !i2c.Bus.SR1.HasBits(stm32.I2C_SR1_SB) {
|
||||||
timeout--
|
timeout--
|
||||||
if timeout == 0 {
|
if timeout == 0 {
|
||||||
return errors.New("I2C timeout on start")
|
return errors.New("I2C timeout on start")
|
||||||
@@ -673,7 +678,7 @@ func (i2c I2C) signalStart() error {
|
|||||||
// signalStop sends a stop signal and waits for it to succeed.
|
// signalStop sends a stop signal and waits for it to succeed.
|
||||||
func (i2c I2C) signalStop() error {
|
func (i2c I2C) signalStop() error {
|
||||||
// Generate stop condition
|
// Generate stop condition
|
||||||
i2c.Bus.CR1 |= stm32.I2C_CR1_STOP
|
i2c.Bus.CR1.SetBits(stm32.I2C_CR1_STOP)
|
||||||
|
|
||||||
// wait for stop
|
// wait for stop
|
||||||
return i2c.waitForStop()
|
return i2c.waitForStop()
|
||||||
@@ -683,7 +688,7 @@ func (i2c I2C) signalStop() error {
|
|||||||
func (i2c I2C) waitForStop() error {
|
func (i2c I2C) waitForStop() error {
|
||||||
// Wait until I2C is stopped
|
// Wait until I2C is stopped
|
||||||
timeout := i2cTimeout
|
timeout := i2cTimeout
|
||||||
for (i2c.Bus.SR1 & stm32.I2C_SR1_STOPF) > 0 {
|
for i2c.Bus.SR1.HasBits(stm32.I2C_SR1_STOPF) {
|
||||||
timeout--
|
timeout--
|
||||||
if timeout == 0 {
|
if timeout == 0 {
|
||||||
println("I2C timeout on wait for stop signal")
|
println("I2C timeout on wait for stop signal")
|
||||||
@@ -701,14 +706,14 @@ func (i2c I2C) sendAddress(address uint8, write bool) error {
|
|||||||
data |= 1 // set read flag
|
data |= 1 // set read flag
|
||||||
}
|
}
|
||||||
|
|
||||||
i2c.Bus.DR = stm32.RegValue(data)
|
i2c.Bus.DR.Set(uint32(data))
|
||||||
|
|
||||||
// Wait for I2C EV6 event.
|
// Wait for I2C EV6 event.
|
||||||
// Destination device acknowledges address
|
// Destination device acknowledges address
|
||||||
timeout := i2cTimeout
|
timeout := i2cTimeout
|
||||||
if write {
|
if write {
|
||||||
// EV6 which is ADDR flag.
|
// EV6 which is ADDR flag.
|
||||||
for i2c.Bus.SR1&stm32.I2C_SR1_ADDR == 0 {
|
for !i2c.Bus.SR1.HasBits(stm32.I2C_SR1_ADDR) {
|
||||||
timeout--
|
timeout--
|
||||||
if timeout == 0 {
|
if timeout == 0 {
|
||||||
return errors.New("I2C timeout on send write address")
|
return errors.New("I2C timeout on send write address")
|
||||||
@@ -716,7 +721,7 @@ func (i2c I2C) sendAddress(address uint8, write bool) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
timeout = i2cTimeout
|
timeout = i2cTimeout
|
||||||
for i2c.Bus.SR2&(stm32.I2C_SR2_MSL|stm32.I2C_SR2_BUSY|stm32.I2C_SR2_TRA) == 0 {
|
for !i2c.Bus.SR2.HasBits(stm32.I2C_SR2_MSL | stm32.I2C_SR2_BUSY | stm32.I2C_SR2_TRA) {
|
||||||
timeout--
|
timeout--
|
||||||
if timeout == 0 {
|
if timeout == 0 {
|
||||||
return errors.New("I2C timeout on send write address")
|
return errors.New("I2C timeout on send write address")
|
||||||
@@ -724,7 +729,7 @@ func (i2c I2C) sendAddress(address uint8, write bool) error {
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED which is ADDR flag.
|
// I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED which is ADDR flag.
|
||||||
for (i2c.Bus.SR1 & stm32.I2C_SR1_ADDR) == 0 {
|
for !i2c.Bus.SR1.HasBits(stm32.I2C_SR1_ADDR) {
|
||||||
timeout--
|
timeout--
|
||||||
if timeout == 0 {
|
if timeout == 0 {
|
||||||
return errors.New("I2C timeout on send read address")
|
return errors.New("I2C timeout on send read address")
|
||||||
@@ -738,13 +743,13 @@ func (i2c I2C) sendAddress(address uint8, write bool) error {
|
|||||||
// WriteByte writes a single byte to the I2C bus.
|
// WriteByte writes a single byte to the I2C bus.
|
||||||
func (i2c I2C) WriteByte(data byte) error {
|
func (i2c I2C) WriteByte(data byte) error {
|
||||||
// Send data byte
|
// Send data byte
|
||||||
i2c.Bus.DR = stm32.RegValue(data)
|
i2c.Bus.DR.Set(uint32(data))
|
||||||
|
|
||||||
// Wait for I2C EV8_2 when data has been physically shifted out and
|
// Wait for I2C EV8_2 when data has been physically shifted out and
|
||||||
// output on the bus.
|
// output on the bus.
|
||||||
// I2C_EVENT_MASTER_BYTE_TRANSMITTED is TXE flag.
|
// I2C_EVENT_MASTER_BYTE_TRANSMITTED is TXE flag.
|
||||||
timeout := i2cTimeout
|
timeout := i2cTimeout
|
||||||
for i2c.Bus.SR1&stm32.I2C_SR1_TxE == 0 {
|
for !i2c.Bus.SR1.HasBits(stm32.I2C_SR1_TxE) {
|
||||||
timeout--
|
timeout--
|
||||||
if timeout == 0 {
|
if timeout == 0 {
|
||||||
return errors.New("I2C timeout on write")
|
return errors.New("I2C timeout on write")
|
||||||
|
|||||||
@@ -13,15 +13,15 @@ const CPU_FREQUENCY = 168000000
|
|||||||
|
|
||||||
const (
|
const (
|
||||||
// Mode Flag
|
// Mode Flag
|
||||||
GPIO_OUTPUT = 0
|
PinOutput PinMode = 0
|
||||||
GPIO_INPUT = GPIO_INPUT_PULLDOWN
|
PinInput PinMode = PinInputFloating
|
||||||
GPIO_INPUT_FLOATING = 1
|
PinInputFloating PinMode = 1
|
||||||
GPIO_INPUT_PULLDOWN = 2
|
PinInputPulldown PinMode = 2
|
||||||
GPIO_INPUT_PULLUP = 3
|
PinInputPullup PinMode = 3
|
||||||
|
|
||||||
// for UART
|
// for UART
|
||||||
GPIO_UART_TX = 4
|
PinModeUartTX PinMode = 4
|
||||||
GPIO_UART_RX = 5
|
PinModeUartRX PinMode = 5
|
||||||
|
|
||||||
//GPIOx_MODER
|
//GPIOx_MODER
|
||||||
GPIO_MODE_INPUT = 0
|
GPIO_MODE_INPUT = 0
|
||||||
@@ -45,8 +45,8 @@ const (
|
|||||||
GPIO_PULL_DOWN = 2
|
GPIO_PULL_DOWN = 2
|
||||||
)
|
)
|
||||||
|
|
||||||
func (p GPIO) getPort() *stm32.GPIO_Type {
|
func (p Pin) getPort() *stm32.GPIO_Type {
|
||||||
switch p.Pin / 16 {
|
switch p / 16 {
|
||||||
case 0:
|
case 0:
|
||||||
return stm32.GPIOA
|
return stm32.GPIOA
|
||||||
case 1:
|
case 1:
|
||||||
@@ -71,83 +71,83 @@ func (p GPIO) getPort() *stm32.GPIO_Type {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// enableClock enables the clock for this desired GPIO port.
|
// enableClock enables the clock for this desired GPIO port.
|
||||||
func (p GPIO) enableClock() {
|
func (p Pin) enableClock() {
|
||||||
switch p.Pin / 16 {
|
switch p / 16 {
|
||||||
case 0:
|
case 0:
|
||||||
stm32.RCC.AHB1ENR |= stm32.RCC_AHB1ENR_GPIOAEN
|
stm32.RCC.AHB1ENR.SetBits(stm32.RCC_AHB1ENR_GPIOAEN)
|
||||||
case 1:
|
case 1:
|
||||||
stm32.RCC.AHB1ENR |= stm32.RCC_AHB1ENR_GPIOBEN
|
stm32.RCC.AHB1ENR.SetBits(stm32.RCC_AHB1ENR_GPIOBEN)
|
||||||
case 2:
|
case 2:
|
||||||
stm32.RCC.AHB1ENR |= stm32.RCC_AHB1ENR_GPIOCEN
|
stm32.RCC.AHB1ENR.SetBits(stm32.RCC_AHB1ENR_GPIOCEN)
|
||||||
case 3:
|
case 3:
|
||||||
stm32.RCC.AHB1ENR |= stm32.RCC_AHB1ENR_GPIODEN
|
stm32.RCC.AHB1ENR.SetBits(stm32.RCC_AHB1ENR_GPIODEN)
|
||||||
case 4:
|
case 4:
|
||||||
stm32.RCC.AHB1ENR |= stm32.RCC_AHB1ENR_GPIOEEN
|
stm32.RCC.AHB1ENR.SetBits(stm32.RCC_AHB1ENR_GPIOEEN)
|
||||||
case 5:
|
case 5:
|
||||||
stm32.RCC.AHB1ENR |= stm32.RCC_AHB1ENR_GPIOFEN
|
stm32.RCC.AHB1ENR.SetBits(stm32.RCC_AHB1ENR_GPIOFEN)
|
||||||
case 6:
|
case 6:
|
||||||
stm32.RCC.AHB1ENR |= stm32.RCC_AHB1ENR_GPIOGEN
|
stm32.RCC.AHB1ENR.SetBits(stm32.RCC_AHB1ENR_GPIOGEN)
|
||||||
case 7:
|
case 7:
|
||||||
stm32.RCC.AHB1ENR |= stm32.RCC_AHB1ENR_GPIOHEN
|
stm32.RCC.AHB1ENR.SetBits(stm32.RCC_AHB1ENR_GPIOHEN)
|
||||||
case 8:
|
case 8:
|
||||||
stm32.RCC.AHB1ENR |= stm32.RCC_AHB1ENR_GPIOIEN
|
stm32.RCC.AHB1ENR.SetBits(stm32.RCC_AHB1ENR_GPIOIEN)
|
||||||
default:
|
default:
|
||||||
panic("machine: unknown port")
|
panic("machine: unknown port")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Configure this pin with the given configuration.
|
// Configure this pin with the given configuration.
|
||||||
func (p GPIO) Configure(config GPIOConfig) {
|
func (p Pin) Configure(config PinConfig) {
|
||||||
// Configure the GPIO pin.
|
// Configure the GPIO pin.
|
||||||
p.enableClock()
|
p.enableClock()
|
||||||
port := p.getPort()
|
port := p.getPort()
|
||||||
pin := p.Pin % 16
|
pin := uint8(p) % 16
|
||||||
pos := pin * 2
|
pos := pin * 2
|
||||||
|
|
||||||
if config.Mode == GPIO_INPUT_FLOATING {
|
if config.Mode == PinInputFloating {
|
||||||
port.MODER = stm32.RegValue((uint32(port.MODER)&^(0x3<<pos) | (uint32(GPIO_MODE_INPUT) << pos)))
|
port.MODER.Set((uint32(port.MODER.Get())&^(0x3<<pos) | (uint32(GPIO_MODE_INPUT) << pos)))
|
||||||
port.PUPDR = stm32.RegValue((uint32(port.PUPDR)&^(0x3<<pos) | (uint32(GPIO_FLOATING) << pos)))
|
port.PUPDR.Set((uint32(port.PUPDR.Get())&^(0x3<<pos) | (uint32(GPIO_FLOATING) << pos)))
|
||||||
} else if config.Mode == GPIO_INPUT_PULLDOWN {
|
} else if config.Mode == PinInputPulldown {
|
||||||
port.MODER = stm32.RegValue((uint32(port.MODER)&^(0x3<<pos) | (uint32(GPIO_MODE_INPUT) << pos)))
|
port.MODER.Set((uint32(port.MODER.Get())&^(0x3<<pos) | (uint32(GPIO_MODE_INPUT) << pos)))
|
||||||
port.PUPDR = stm32.RegValue((uint32(port.PUPDR)&^(0x3<<pos) | (uint32(GPIO_PULL_DOWN) << pos)))
|
port.PUPDR.Set((uint32(port.PUPDR.Get())&^(0x3<<pos) | (uint32(GPIO_PULL_DOWN) << pos)))
|
||||||
} else if config.Mode == GPIO_INPUT_PULLUP {
|
} else if config.Mode == PinInputPullup {
|
||||||
port.MODER = stm32.RegValue((uint32(port.MODER)&^(0x3<<pos) | (uint32(GPIO_MODE_INPUT) << pos)))
|
port.MODER.Set((uint32(port.MODER.Get())&^(0x3<<pos) | (uint32(GPIO_MODE_INPUT) << pos)))
|
||||||
port.PUPDR = stm32.RegValue((uint32(port.PUPDR)&^(0x3<<pos) | (uint32(GPIO_PULL_UP) << pos)))
|
port.PUPDR.Set((uint32(port.PUPDR.Get())&^(0x3<<pos) | (uint32(GPIO_PULL_UP) << pos)))
|
||||||
} else if config.Mode == GPIO_OUTPUT {
|
} else if config.Mode == PinOutput {
|
||||||
port.MODER = stm32.RegValue((uint32(port.MODER)&^(0x3<<pos) | (uint32(GPIO_MODE_GENERAL_OUTPUT) << pos)))
|
port.MODER.Set((uint32(port.MODER.Get())&^(0x3<<pos) | (uint32(GPIO_MODE_GENERAL_OUTPUT) << pos)))
|
||||||
port.OSPEEDR = stm32.RegValue((uint32(port.OSPEEDR)&^(0x3<<pos) | (uint32(GPIO_SPEED_HI) << pos)))
|
port.OSPEEDR.Set((uint32(port.OSPEEDR.Get())&^(0x3<<pos) | (uint32(GPIO_SPEED_HI) << pos)))
|
||||||
} else if config.Mode == GPIO_UART_TX {
|
} else if config.Mode == PinModeUartTX {
|
||||||
port.MODER = stm32.RegValue((uint32(port.MODER)&^(0x3<<pos) | (uint32(GPIO_MODE_ALTERNABTIVE) << pos)))
|
port.MODER.Set((uint32(port.MODER.Get())&^(0x3<<pos) | (uint32(GPIO_MODE_ALTERNABTIVE) << pos)))
|
||||||
port.OSPEEDR = stm32.RegValue((uint32(port.OSPEEDR)&^(0x3<<pos) | (uint32(GPIO_SPEED_HI) << pos)))
|
port.OSPEEDR.Set((uint32(port.OSPEEDR.Get())&^(0x3<<pos) | (uint32(GPIO_SPEED_HI) << pos)))
|
||||||
port.PUPDR = stm32.RegValue((uint32(port.PUPDR)&^(0x3<<pos) | (uint32(GPIO_PULL_UP) << pos)))
|
port.PUPDR.Set((uint32(port.PUPDR.Get())&^(0x3<<pos) | (uint32(GPIO_PULL_UP) << pos)))
|
||||||
p.setAltFunc(0x7)
|
p.setAltFunc(0x7)
|
||||||
} else if config.Mode == GPIO_UART_RX {
|
} else if config.Mode == PinModeUartRX {
|
||||||
port.MODER = stm32.RegValue((uint32(port.MODER)&^(0x3<<pos) | (uint32(GPIO_MODE_ALTERNABTIVE) << pos)))
|
port.MODER.Set((uint32(port.MODER.Get())&^(0x3<<pos) | (uint32(GPIO_MODE_ALTERNABTIVE) << pos)))
|
||||||
port.PUPDR = stm32.RegValue((uint32(port.PUPDR)&^(0x3<<pos) | (uint32(GPIO_FLOATING) << pos)))
|
port.PUPDR.Set((uint32(port.PUPDR.Get())&^(0x3<<pos) | (uint32(GPIO_FLOATING) << pos)))
|
||||||
p.setAltFunc(0x7)
|
p.setAltFunc(0x7)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p GPIO) setAltFunc(af uint32) {
|
func (p Pin) setAltFunc(af uint32) {
|
||||||
port := p.getPort()
|
port := p.getPort()
|
||||||
pin := p.Pin % 16
|
pin := uint8(p) % 16
|
||||||
pos := pin * 4
|
pos := pin * 4
|
||||||
if pin >= 8 {
|
if pin >= 8 {
|
||||||
port.AFRH = stm32.RegValue(uint32(port.AFRH)&^(0xF<<pos) | ((af & 0xF) << pos))
|
port.AFRH.Set(uint32(port.AFRH.Get())&^(0xF<<pos) | ((af & 0xF) << pos))
|
||||||
} else {
|
} else {
|
||||||
port.AFRL = stm32.RegValue(uint32(port.AFRL)&^(0xF<<pos) | ((af & 0xF) << pos))
|
port.AFRL.Set(uint32(port.AFRL.Get())&^(0xF<<pos) | ((af & 0xF) << pos))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set the pin to high or low.
|
// Set the pin to high or low.
|
||||||
// Warning: only use this on an output pin!
|
// Warning: only use this on an output pin!
|
||||||
func (p GPIO) Set(high bool) {
|
func (p Pin) Set(high bool) {
|
||||||
port := p.getPort()
|
port := p.getPort()
|
||||||
pin := p.Pin % 16
|
pin := p % 16
|
||||||
if high {
|
if high {
|
||||||
port.BSRR = 1 << pin
|
port.BSRR.Set(1 << uint8(pin))
|
||||||
} else {
|
} else {
|
||||||
port.BSRR = 1 << (pin + 16)
|
port.BSRR.Set(1 << uint8(pin+16))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -173,12 +173,12 @@ func (uart UART) Configure(config UARTConfig) {
|
|||||||
switch config.TX {
|
switch config.TX {
|
||||||
default:
|
default:
|
||||||
// use standard TX/RX pins PA2 and PA3
|
// use standard TX/RX pins PA2 and PA3
|
||||||
GPIO{UART_TX_PIN}.Configure(GPIOConfig{Mode: GPIO_UART_TX})
|
UART_TX_PIN.Configure(PinConfig{Mode: PinModeUartTX})
|
||||||
GPIO{UART_RX_PIN}.Configure(GPIOConfig{Mode: GPIO_UART_RX})
|
UART_RX_PIN.Configure(PinConfig{Mode: PinModeUartRX})
|
||||||
}
|
}
|
||||||
|
|
||||||
// Enable USART2 clock
|
// Enable USART2 clock
|
||||||
stm32.RCC.APB1ENR |= stm32.RCC_APB1ENR_USART2EN
|
stm32.RCC.APB1ENR.SetBits(stm32.RCC_APB1ENR_USART2EN)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Set baud rate(115200)
|
Set baud rate(115200)
|
||||||
@@ -195,10 +195,10 @@ func (uart UART) Configure(config UARTConfig) {
|
|||||||
| 115200 | 0x16D |
|
| 115200 | 0x16D |
|
||||||
+----------+--------+
|
+----------+--------+
|
||||||
*/
|
*/
|
||||||
stm32.USART2.BRR = 0x16c
|
stm32.USART2.BRR.Set(0x16c)
|
||||||
|
|
||||||
// Enable USART2 port.
|
// Enable USART2 port.
|
||||||
stm32.USART2.CR1 = stm32.USART_CR1_TE | stm32.USART_CR1_RE | stm32.USART_CR1_RXNEIE | stm32.USART_CR1_UE
|
stm32.USART2.CR1.Set(stm32.USART_CR1_TE | stm32.USART_CR1_RE | stm32.USART_CR1_RXNEIE | stm32.USART_CR1_UE)
|
||||||
|
|
||||||
// Enable RX IRQ.
|
// Enable RX IRQ.
|
||||||
arm.SetPriority(stm32.IRQ_USART2, 0xc0)
|
arm.SetPriority(stm32.IRQ_USART2, 0xc0)
|
||||||
@@ -207,14 +207,14 @@ func (uart UART) Configure(config UARTConfig) {
|
|||||||
|
|
||||||
// WriteByte writes a byte of data to the UART.
|
// WriteByte writes a byte of data to the UART.
|
||||||
func (uart UART) WriteByte(c byte) error {
|
func (uart UART) WriteByte(c byte) error {
|
||||||
stm32.USART2.DR = stm32.RegValue(c)
|
stm32.USART2.DR.Set(uint32(c))
|
||||||
|
|
||||||
for (stm32.USART2.SR & stm32.USART_SR_TXE) == 0 {
|
for !stm32.USART2.SR.HasBits(stm32.USART_SR_TXE) {
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
//go:export USART2_IRQHandler
|
//go:export USART2_IRQHandler
|
||||||
func handleUSART2() {
|
func handleUSART2() {
|
||||||
UART1.Receive(byte((stm32.USART2.DR & 0xFF)))
|
UART1.Receive(byte((stm32.USART2.DR.Get() & 0xFF)))
|
||||||
}
|
}
|
||||||
|
|||||||
+2
-2
@@ -6,8 +6,8 @@ import "errors"
|
|||||||
|
|
||||||
type UARTConfig struct {
|
type UARTConfig struct {
|
||||||
BaudRate uint32
|
BaudRate uint32
|
||||||
TX uint8
|
TX Pin
|
||||||
RX uint8
|
RX Pin
|
||||||
}
|
}
|
||||||
|
|
||||||
// To implement the UART interface for a board, you must declare a concrete type as follows:
|
// To implement the UART interface for a board, you must declare a concrete type as follows:
|
||||||
|
|||||||
+5
-5
@@ -484,11 +484,11 @@ const (
|
|||||||
// RoReg8 Reserved1[0x5];
|
// RoReg8 Reserved1[0x5];
|
||||||
// } UsbDeviceDescBank;
|
// } UsbDeviceDescBank;
|
||||||
type usbDeviceDescBank struct {
|
type usbDeviceDescBank struct {
|
||||||
ADDR sam.RegValue
|
ADDR sam.Register32
|
||||||
PCKSIZE sam.RegValue
|
PCKSIZE sam.Register32
|
||||||
EXTREG sam.RegValue16
|
EXTREG sam.Register16
|
||||||
STATUS_BK sam.RegValue8
|
STATUS_BK sam.Register8
|
||||||
_reserved [5]sam.RegValue8
|
_reserved [5]sam.Register8
|
||||||
}
|
}
|
||||||
|
|
||||||
type usbDeviceDescriptor struct {
|
type usbDeviceDescriptor struct {
|
||||||
|
|||||||
@@ -36,16 +36,20 @@ func isnil(ptr *uint8) bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Panic when trying to dereference a nil pointer.
|
// Panic when trying to dereference a nil pointer.
|
||||||
func nilpanic() {
|
func nilPanic() {
|
||||||
runtimePanic("nil pointer dereference")
|
runtimePanic("nil pointer dereference")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Panic when trying to acces an array or slice out of bounds.
|
// Panic when trying to acces an array or slice out of bounds.
|
||||||
func lookuppanic() {
|
func lookupPanic() {
|
||||||
runtimePanic("index out of range")
|
runtimePanic("index out of range")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Panic when trying to slice a slice out of bounds.
|
// Panic when trying to slice a slice out of bounds.
|
||||||
func slicepanic() {
|
func slicePanic() {
|
||||||
runtimePanic("slice out of range")
|
runtimePanic("slice out of range")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func blockingPanic() {
|
||||||
|
runtimePanic("trying to do blocking operation in exported function")
|
||||||
|
}
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ const Compiler = "tinygo"
|
|||||||
// package.
|
// package.
|
||||||
func initAll()
|
func initAll()
|
||||||
|
|
||||||
// A function call to this function is replaced withone of the following,
|
// A function call to this function is replaced with one of the following,
|
||||||
// depending on whether the scheduler is necessary:
|
// depending on whether the scheduler is necessary:
|
||||||
//
|
//
|
||||||
// Without scheduler:
|
// Without scheduler:
|
||||||
|
|||||||
+54
-107
@@ -36,12 +36,12 @@ func putchar(c byte) {
|
|||||||
|
|
||||||
func initClocks() {
|
func initClocks() {
|
||||||
// Set 1 Flash Wait State for 48MHz, required for 3.3V operation according to SAMD21 Datasheet
|
// Set 1 Flash Wait State for 48MHz, required for 3.3V operation according to SAMD21 Datasheet
|
||||||
sam.NVMCTRL.CTRLB |= (sam.NVMCTRL_CTRLB_RWS_HALF << sam.NVMCTRL_CTRLB_RWS_Pos)
|
sam.NVMCTRL.CTRLB.SetBits(sam.NVMCTRL_CTRLB_RWS_HALF << sam.NVMCTRL_CTRLB_RWS_Pos)
|
||||||
|
|
||||||
// Turn on the digital interface clock
|
// Turn on the digital interface clock
|
||||||
sam.PM.APBAMASK |= sam.PM_APBAMASK_GCLK_
|
sam.PM.APBAMASK.SetBits(sam.PM_APBAMASK_GCLK_)
|
||||||
// turn off RTC
|
// turn off RTC
|
||||||
sam.PM.APBAMASK &^= sam.PM_APBAMASK_RTC_
|
sam.PM.APBAMASK.ClearBits(sam.PM_APBAMASK_RTC_)
|
||||||
|
|
||||||
// Enable OSC32K clock (Internal 32.768Hz oscillator).
|
// Enable OSC32K clock (Internal 32.768Hz oscillator).
|
||||||
// This requires registers that are not included in the SVD file.
|
// This requires registers that are not included in the SVD file.
|
||||||
@@ -61,42 +61,42 @@ func initClocks() {
|
|||||||
// SYSCTRL_OSC32K_CALIB(calib) |
|
// SYSCTRL_OSC32K_CALIB(calib) |
|
||||||
// SYSCTRL_OSC32K_STARTUP(0x6u) |
|
// SYSCTRL_OSC32K_STARTUP(0x6u) |
|
||||||
// SYSCTRL_OSC32K_EN32K | SYSCTRL_OSC32K_ENABLE;
|
// SYSCTRL_OSC32K_EN32K | SYSCTRL_OSC32K_ENABLE;
|
||||||
sam.SYSCTRL.OSC32K = sam.RegValue((calib << sam.SYSCTRL_OSC32K_CALIB_Pos) |
|
sam.SYSCTRL.OSC32K.Set((calib << sam.SYSCTRL_OSC32K_CALIB_Pos) |
|
||||||
(0x6 << sam.SYSCTRL_OSC32K_STARTUP_Pos) |
|
(0x6 << sam.SYSCTRL_OSC32K_STARTUP_Pos) |
|
||||||
sam.SYSCTRL_OSC32K_EN32K |
|
sam.SYSCTRL_OSC32K_EN32K |
|
||||||
sam.SYSCTRL_OSC32K_EN1K |
|
sam.SYSCTRL_OSC32K_EN1K |
|
||||||
sam.SYSCTRL_OSC32K_ENABLE)
|
sam.SYSCTRL_OSC32K_ENABLE)
|
||||||
// Wait for oscillator stabilization
|
// Wait for oscillator stabilization
|
||||||
for (sam.SYSCTRL.PCLKSR & sam.SYSCTRL_PCLKSR_OSC32KRDY) == 0 {
|
for !sam.SYSCTRL.PCLKSR.HasBits(sam.SYSCTRL_PCLKSR_OSC32KRDY) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Software reset the module to ensure it is re-initialized correctly
|
// Software reset the module to ensure it is re-initialized correctly
|
||||||
sam.GCLK.CTRL = sam.GCLK_CTRL_SWRST
|
sam.GCLK.CTRL.Set(sam.GCLK_CTRL_SWRST)
|
||||||
// Wait for reset to complete
|
// Wait for reset to complete
|
||||||
for (sam.GCLK.CTRL&sam.GCLK_CTRL_SWRST) > 0 && (sam.GCLK.STATUS&sam.GCLK_STATUS_SYNCBUSY) > 0 {
|
for sam.GCLK.CTRL.HasBits(sam.GCLK_CTRL_SWRST) && sam.GCLK.STATUS.HasBits(sam.GCLK_STATUS_SYNCBUSY) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Put OSC32K as source of Generic Clock Generator 1
|
// Put OSC32K as source of Generic Clock Generator 1
|
||||||
sam.GCLK.GENDIV = sam.RegValue((1 << sam.GCLK_GENDIV_ID_Pos) |
|
sam.GCLK.GENDIV.Set((1 << sam.GCLK_GENDIV_ID_Pos) |
|
||||||
(0 << sam.GCLK_GENDIV_DIV_Pos))
|
(0 << sam.GCLK_GENDIV_DIV_Pos))
|
||||||
waitForSync()
|
waitForSync()
|
||||||
|
|
||||||
// GCLK_GENCTRL_ID(1) | GCLK_GENCTRL_SRC_OSC32K | GCLK_GENCTRL_GENEN;
|
// GCLK_GENCTRL_ID(1) | GCLK_GENCTRL_SRC_OSC32K | GCLK_GENCTRL_GENEN;
|
||||||
sam.GCLK.GENCTRL = sam.RegValue((1 << sam.GCLK_GENCTRL_ID_Pos) |
|
sam.GCLK.GENCTRL.Set((1 << sam.GCLK_GENCTRL_ID_Pos) |
|
||||||
(sam.GCLK_GENCTRL_SRC_OSC32K << sam.GCLK_GENCTRL_SRC_Pos) |
|
(sam.GCLK_GENCTRL_SRC_OSC32K << sam.GCLK_GENCTRL_SRC_Pos) |
|
||||||
sam.GCLK_GENCTRL_GENEN)
|
sam.GCLK_GENCTRL_GENEN)
|
||||||
waitForSync()
|
waitForSync()
|
||||||
|
|
||||||
// Use Generic Clock Generator 1 as source for Generic Clock Multiplexer 0 (DFLL48M reference)
|
// Use Generic Clock Generator 1 as source for Generic Clock Multiplexer 0 (DFLL48M reference)
|
||||||
sam.GCLK.CLKCTRL = sam.RegValue16((sam.GCLK_CLKCTRL_ID_DFLL48 << sam.GCLK_CLKCTRL_ID_Pos) |
|
sam.GCLK.CLKCTRL.Set((sam.GCLK_CLKCTRL_ID_DFLL48 << sam.GCLK_CLKCTRL_ID_Pos) |
|
||||||
(sam.GCLK_CLKCTRL_GEN_GCLK1 << sam.GCLK_CLKCTRL_GEN_Pos) |
|
(sam.GCLK_CLKCTRL_GEN_GCLK1 << sam.GCLK_CLKCTRL_GEN_Pos) |
|
||||||
sam.GCLK_CLKCTRL_CLKEN)
|
sam.GCLK_CLKCTRL_CLKEN)
|
||||||
waitForSync()
|
waitForSync()
|
||||||
|
|
||||||
// Remove the OnDemand mode, Bug http://avr32.icgroup.norway.atmel.com/bugzilla/show_bug.cgi?id=9905
|
// Remove the OnDemand mode, Bug http://avr32.icgroup.norway.atmel.com/bugzilla/show_bug.cgi?id=9905
|
||||||
sam.SYSCTRL.DFLLCTRL = sam.SYSCTRL_DFLLCTRL_ENABLE
|
sam.SYSCTRL.DFLLCTRL.Set(sam.SYSCTRL_DFLLCTRL_ENABLE)
|
||||||
// Wait for ready
|
// Wait for ready
|
||||||
for (sam.SYSCTRL.PCLKSR & sam.SYSCTRL_PCLKSR_DFLLRDY) == 0 {
|
for !sam.SYSCTRL.PCLKSR.HasBits(sam.SYSCTRL_PCLKSR_DFLLRDY) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handle DFLL calibration based on info learned from Arduino SAMD implementation,
|
// Handle DFLL calibration based on info learned from Arduino SAMD implementation,
|
||||||
@@ -110,107 +110,107 @@ func initClocks() {
|
|||||||
coarse = 0x1f
|
coarse = 0x1f
|
||||||
}
|
}
|
||||||
|
|
||||||
sam.SYSCTRL.DFLLVAL |= sam.RegValue(coarse << sam.SYSCTRL_DFLLVAL_COARSE_Pos)
|
sam.SYSCTRL.DFLLVAL.SetBits(coarse << sam.SYSCTRL_DFLLVAL_COARSE_Pos)
|
||||||
sam.SYSCTRL.DFLLVAL |= (0x1ff << sam.SYSCTRL_DFLLVAL_FINE_Pos)
|
sam.SYSCTRL.DFLLVAL.SetBits(0x1ff << sam.SYSCTRL_DFLLVAL_FINE_Pos)
|
||||||
|
|
||||||
// Write full configuration to DFLL control register
|
// Write full configuration to DFLL control register
|
||||||
// SYSCTRL_DFLLMUL_CSTEP( 0x1f / 4 ) | // Coarse step is 31, half of the max value
|
// SYSCTRL_DFLLMUL_CSTEP( 0x1f / 4 ) | // Coarse step is 31, half of the max value
|
||||||
// SYSCTRL_DFLLMUL_FSTEP( 10 ) |
|
// SYSCTRL_DFLLMUL_FSTEP( 10 ) |
|
||||||
// SYSCTRL_DFLLMUL_MUL( (48000) ) ;
|
// SYSCTRL_DFLLMUL_MUL( (48000) ) ;
|
||||||
sam.SYSCTRL.DFLLMUL = sam.RegValue(((31 / 4) << sam.SYSCTRL_DFLLMUL_CSTEP_Pos) |
|
sam.SYSCTRL.DFLLMUL.Set(((31 / 4) << sam.SYSCTRL_DFLLMUL_CSTEP_Pos) |
|
||||||
(10 << sam.SYSCTRL_DFLLMUL_FSTEP_Pos) |
|
(10 << sam.SYSCTRL_DFLLMUL_FSTEP_Pos) |
|
||||||
(48000 << sam.SYSCTRL_DFLLMUL_MUL_Pos))
|
(48000 << sam.SYSCTRL_DFLLMUL_MUL_Pos))
|
||||||
|
|
||||||
// disable DFLL
|
// disable DFLL
|
||||||
sam.SYSCTRL.DFLLCTRL = 0
|
sam.SYSCTRL.DFLLCTRL.Set(0)
|
||||||
waitForSync()
|
waitForSync()
|
||||||
|
|
||||||
sam.SYSCTRL.DFLLCTRL |= sam.SYSCTRL_DFLLCTRL_MODE |
|
sam.SYSCTRL.DFLLCTRL.SetBits(sam.SYSCTRL_DFLLCTRL_MODE |
|
||||||
sam.SYSCTRL_DFLLCTRL_CCDIS |
|
sam.SYSCTRL_DFLLCTRL_CCDIS |
|
||||||
sam.SYSCTRL_DFLLCTRL_USBCRM |
|
sam.SYSCTRL_DFLLCTRL_USBCRM |
|
||||||
sam.SYSCTRL_DFLLCTRL_BPLCKC
|
sam.SYSCTRL_DFLLCTRL_BPLCKC)
|
||||||
// Wait for ready
|
// Wait for ready
|
||||||
for (sam.SYSCTRL.PCLKSR & sam.SYSCTRL_PCLKSR_DFLLRDY) == 0 {
|
for !sam.SYSCTRL.PCLKSR.HasBits(sam.SYSCTRL_PCLKSR_DFLLRDY) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Re-enable the DFLL
|
// Re-enable the DFLL
|
||||||
sam.SYSCTRL.DFLLCTRL |= sam.SYSCTRL_DFLLCTRL_ENABLE
|
sam.SYSCTRL.DFLLCTRL.SetBits(sam.SYSCTRL_DFLLCTRL_ENABLE)
|
||||||
// Wait for ready
|
// Wait for ready
|
||||||
for (sam.SYSCTRL.PCLKSR & sam.SYSCTRL_PCLKSR_DFLLRDY) == 0 {
|
for !sam.SYSCTRL.PCLKSR.HasBits(sam.SYSCTRL_PCLKSR_DFLLRDY) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Switch Generic Clock Generator 0 to DFLL48M. CPU will run at 48MHz.
|
// Switch Generic Clock Generator 0 to DFLL48M. CPU will run at 48MHz.
|
||||||
sam.GCLK.GENDIV = sam.RegValue((0 << sam.GCLK_GENDIV_ID_Pos) |
|
sam.GCLK.GENDIV.Set((0 << sam.GCLK_GENDIV_ID_Pos) |
|
||||||
(0 << sam.GCLK_GENDIV_DIV_Pos))
|
(0 << sam.GCLK_GENDIV_DIV_Pos))
|
||||||
waitForSync()
|
waitForSync()
|
||||||
|
|
||||||
sam.GCLK.GENCTRL = sam.RegValue((0 << sam.GCLK_GENCTRL_ID_Pos) |
|
sam.GCLK.GENCTRL.Set((0 << sam.GCLK_GENCTRL_ID_Pos) |
|
||||||
(sam.GCLK_GENCTRL_SRC_DFLL48M << sam.GCLK_GENCTRL_SRC_Pos) |
|
(sam.GCLK_GENCTRL_SRC_DFLL48M << sam.GCLK_GENCTRL_SRC_Pos) |
|
||||||
sam.GCLK_GENCTRL_IDC |
|
sam.GCLK_GENCTRL_IDC |
|
||||||
sam.GCLK_GENCTRL_GENEN)
|
sam.GCLK_GENCTRL_GENEN)
|
||||||
waitForSync()
|
waitForSync()
|
||||||
|
|
||||||
// Modify PRESCaler value of OSC8M to have 8MHz
|
// Modify PRESCaler value of OSC8M to have 8MHz
|
||||||
sam.SYSCTRL.OSC8M |= (sam.SYSCTRL_OSC8M_PRESC_0 << sam.SYSCTRL_OSC8M_PRESC_Pos)
|
sam.SYSCTRL.OSC8M.SetBits(sam.SYSCTRL_OSC8M_PRESC_0 << sam.SYSCTRL_OSC8M_PRESC_Pos)
|
||||||
sam.SYSCTRL.OSC8M &^= (1 << sam.SYSCTRL_OSC8M_ONDEMAND_Pos)
|
sam.SYSCTRL.OSC8M.ClearBits(1 << sam.SYSCTRL_OSC8M_ONDEMAND_Pos)
|
||||||
// Wait for oscillator stabilization
|
// Wait for oscillator stabilization
|
||||||
for (sam.SYSCTRL.PCLKSR & sam.SYSCTRL_PCLKSR_OSC8MRDY) == 0 {
|
for !sam.SYSCTRL.PCLKSR.HasBits(sam.SYSCTRL_PCLKSR_OSC8MRDY) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Use OSC8M as source for Generic Clock Generator 3
|
// Use OSC8M as source for Generic Clock Generator 3
|
||||||
sam.GCLK.GENDIV = sam.RegValue((3 << sam.GCLK_GENDIV_ID_Pos))
|
sam.GCLK.GENDIV.Set((3 << sam.GCLK_GENDIV_ID_Pos))
|
||||||
waitForSync()
|
waitForSync()
|
||||||
|
|
||||||
sam.GCLK.GENCTRL = sam.RegValue((3 << sam.GCLK_GENCTRL_ID_Pos) |
|
sam.GCLK.GENCTRL.Set((3 << sam.GCLK_GENCTRL_ID_Pos) |
|
||||||
(sam.GCLK_GENCTRL_SRC_OSC8M << sam.GCLK_GENCTRL_SRC_Pos) |
|
(sam.GCLK_GENCTRL_SRC_OSC8M << sam.GCLK_GENCTRL_SRC_Pos) |
|
||||||
sam.GCLK_GENCTRL_GENEN)
|
sam.GCLK_GENCTRL_GENEN)
|
||||||
waitForSync()
|
waitForSync()
|
||||||
|
|
||||||
// Use OSC32K as source for Generic Clock Generator 2
|
// Use OSC32K as source for Generic Clock Generator 2
|
||||||
// OSC32K/1 -> GCLK2 at 32KHz
|
// OSC32K/1 -> GCLK2 at 32KHz
|
||||||
sam.GCLK.GENDIV = sam.RegValue(2 << sam.GCLK_GENDIV_ID_Pos)
|
sam.GCLK.GENDIV.Set(2 << sam.GCLK_GENDIV_ID_Pos)
|
||||||
waitForSync()
|
waitForSync()
|
||||||
|
|
||||||
sam.GCLK.GENCTRL = sam.RegValue((2 << sam.GCLK_GENCTRL_ID_Pos) |
|
sam.GCLK.GENCTRL.Set((2 << sam.GCLK_GENCTRL_ID_Pos) |
|
||||||
(sam.GCLK_GENCTRL_SRC_OSC32K << sam.GCLK_GENCTRL_SRC_Pos) |
|
(sam.GCLK_GENCTRL_SRC_OSC32K << sam.GCLK_GENCTRL_SRC_Pos) |
|
||||||
sam.GCLK_GENCTRL_GENEN)
|
sam.GCLK_GENCTRL_GENEN)
|
||||||
waitForSync()
|
waitForSync()
|
||||||
|
|
||||||
// Use GCLK2 for RTC
|
// Use GCLK2 for RTC
|
||||||
sam.GCLK.CLKCTRL = sam.RegValue16((sam.GCLK_CLKCTRL_ID_RTC << sam.GCLK_CLKCTRL_ID_Pos) |
|
sam.GCLK.CLKCTRL.Set((sam.GCLK_CLKCTRL_ID_RTC << sam.GCLK_CLKCTRL_ID_Pos) |
|
||||||
(sam.GCLK_CLKCTRL_GEN_GCLK2 << sam.GCLK_CLKCTRL_GEN_Pos) |
|
(sam.GCLK_CLKCTRL_GEN_GCLK2 << sam.GCLK_CLKCTRL_GEN_Pos) |
|
||||||
sam.GCLK_CLKCTRL_CLKEN)
|
sam.GCLK_CLKCTRL_CLKEN)
|
||||||
waitForSync()
|
waitForSync()
|
||||||
|
|
||||||
// Set the CPU, APBA, B, and C dividers
|
// Set the CPU, APBA, B, and C dividers
|
||||||
sam.PM.CPUSEL = sam.PM_CPUSEL_CPUDIV_DIV1
|
sam.PM.CPUSEL.Set(sam.PM_CPUSEL_CPUDIV_DIV1)
|
||||||
sam.PM.APBASEL = sam.PM_APBASEL_APBADIV_DIV1
|
sam.PM.APBASEL.Set(sam.PM_APBASEL_APBADIV_DIV1)
|
||||||
sam.PM.APBBSEL = sam.PM_APBBSEL_APBBDIV_DIV1
|
sam.PM.APBBSEL.Set(sam.PM_APBBSEL_APBBDIV_DIV1)
|
||||||
sam.PM.APBCSEL = sam.PM_APBCSEL_APBCDIV_DIV1
|
sam.PM.APBCSEL.Set(sam.PM_APBCSEL_APBCDIV_DIV1)
|
||||||
|
|
||||||
// Disable automatic NVM write operations
|
// Disable automatic NVM write operations
|
||||||
sam.NVMCTRL.CTRLB |= sam.NVMCTRL_CTRLB_MANW
|
sam.NVMCTRL.CTRLB.SetBits(sam.NVMCTRL_CTRLB_MANW)
|
||||||
}
|
}
|
||||||
|
|
||||||
func initRTC() {
|
func initRTC() {
|
||||||
// turn on digital interface clock
|
// turn on digital interface clock
|
||||||
sam.PM.APBAMASK |= sam.PM_APBAMASK_RTC_
|
sam.PM.APBAMASK.SetBits(sam.PM_APBAMASK_RTC_)
|
||||||
|
|
||||||
// disable RTC
|
// disable RTC
|
||||||
sam.RTC_MODE0.CTRL = 0
|
sam.RTC_MODE0.CTRL.Set(0)
|
||||||
waitForSync()
|
waitForSync()
|
||||||
|
|
||||||
// reset RTC
|
// reset RTC
|
||||||
sam.RTC_MODE0.CTRL |= sam.RTC_MODE0_CTRL_SWRST
|
sam.RTC_MODE0.CTRL.SetBits(sam.RTC_MODE0_CTRL_SWRST)
|
||||||
waitForSync()
|
waitForSync()
|
||||||
|
|
||||||
// set Mode0 to 32-bit counter (mode 0) with prescaler 1 and GCLK2 is 32KHz/1
|
// set Mode0 to 32-bit counter (mode 0) with prescaler 1 and GCLK2 is 32KHz/1
|
||||||
sam.RTC_MODE0.CTRL = sam.RegValue16((sam.RTC_MODE0_CTRL_MODE_COUNT32 << sam.RTC_MODE0_CTRL_MODE_Pos) |
|
sam.RTC_MODE0.CTRL.Set((sam.RTC_MODE0_CTRL_MODE_COUNT32 << sam.RTC_MODE0_CTRL_MODE_Pos) |
|
||||||
(sam.RTC_MODE0_CTRL_PRESCALER_DIV1 << sam.RTC_MODE0_CTRL_PRESCALER_Pos))
|
(sam.RTC_MODE0_CTRL_PRESCALER_DIV1 << sam.RTC_MODE0_CTRL_PRESCALER_Pos))
|
||||||
waitForSync()
|
waitForSync()
|
||||||
|
|
||||||
// re-enable RTC
|
// re-enable RTC
|
||||||
sam.RTC_MODE0.CTRL |= sam.RTC_MODE0_CTRL_ENABLE
|
sam.RTC_MODE0.CTRL.SetBits(sam.RTC_MODE0_CTRL_ENABLE)
|
||||||
waitForSync()
|
waitForSync()
|
||||||
|
|
||||||
arm.SetPriority(sam.IRQ_RTC, 0xc0)
|
arm.SetPriority(sam.IRQ_RTC, 0xc0)
|
||||||
@@ -218,7 +218,7 @@ func initRTC() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func waitForSync() {
|
func waitForSync() {
|
||||||
for (sam.GCLK.STATUS & sam.GCLK_STATUS_SYNCBUSY) > 0 {
|
for sam.GCLK.STATUS.HasBits(sam.GCLK_STATUS_SYNCBUSY) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -250,11 +250,11 @@ func sleepTicks(d timeUnit) {
|
|||||||
// ticks returns number of microseconds since start.
|
// ticks returns number of microseconds since start.
|
||||||
func ticks() timeUnit {
|
func ticks() timeUnit {
|
||||||
// request read of count
|
// request read of count
|
||||||
sam.RTC_MODE0.READREQ = sam.RTC_MODE0_READREQ_RREQ
|
sam.RTC_MODE0.READREQ.Set(sam.RTC_MODE0_READREQ_RREQ)
|
||||||
waitForSync()
|
waitForSync()
|
||||||
|
|
||||||
rtcCounter := (uint64(sam.RTC_MODE0.COUNT) * 305) / 10 // each counter tick == 30.5us
|
rtcCounter := (uint64(sam.RTC_MODE0.COUNT.Get()) * 305) / 10 // each counter tick == 30.5us
|
||||||
offset := (rtcCounter - timerLastCounter) // change since last measurement
|
offset := (rtcCounter - timerLastCounter) // change since last measurement
|
||||||
timerLastCounter = rtcCounter
|
timerLastCounter = rtcCounter
|
||||||
timestamp += timeUnit(offset) // TODO: not precise
|
timestamp += timeUnit(offset) // TODO: not precise
|
||||||
return timestamp
|
return timestamp
|
||||||
@@ -269,16 +269,16 @@ func timerSleep(ticks uint32) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// request read of count
|
// request read of count
|
||||||
sam.RTC_MODE0.READREQ = sam.RTC_MODE0_READREQ_RREQ
|
sam.RTC_MODE0.READREQ.Set(sam.RTC_MODE0_READREQ_RREQ)
|
||||||
waitForSync()
|
waitForSync()
|
||||||
|
|
||||||
// set compare value
|
// set compare value
|
||||||
cnt := sam.RTC_MODE0.COUNT
|
cnt := sam.RTC_MODE0.COUNT.Get()
|
||||||
sam.RTC_MODE0.COMP0 = sam.RegValue(uint32(cnt) + (ticks * 10 / 305)) // each counter tick == 30.5us
|
sam.RTC_MODE0.COMP0.Set(uint32(cnt) + (ticks * 10 / 305)) // each counter tick == 30.5us
|
||||||
waitForSync()
|
waitForSync()
|
||||||
|
|
||||||
// enable IRQ for CMP0 compare
|
// enable IRQ for CMP0 compare
|
||||||
sam.RTC_MODE0.INTENSET |= sam.RTC_MODE0_INTENSET_CMP0
|
sam.RTC_MODE0.INTENSET.SetBits(sam.RTC_MODE0_INTENSET_CMP0)
|
||||||
|
|
||||||
for !timerWakeup {
|
for !timerWakeup {
|
||||||
arm.Asm("wfi")
|
arm.Asm("wfi")
|
||||||
@@ -288,70 +288,17 @@ func timerSleep(ticks uint32) {
|
|||||||
//go:export RTC_IRQHandler
|
//go:export RTC_IRQHandler
|
||||||
func handleRTC() {
|
func handleRTC() {
|
||||||
// disable IRQ for CMP0 compare
|
// disable IRQ for CMP0 compare
|
||||||
sam.RTC_MODE0.INTFLAG = sam.RTC_MODE0_INTENSET_CMP0
|
sam.RTC_MODE0.INTFLAG.Set(sam.RTC_MODE0_INTENSET_CMP0)
|
||||||
|
|
||||||
timerWakeup = true
|
timerWakeup = true
|
||||||
}
|
}
|
||||||
|
|
||||||
func initSERCOMClocks() {
|
|
||||||
// Turn on clock to SERCOM0 for UART0
|
|
||||||
sam.PM.APBCMASK |= sam.PM_APBCMASK_SERCOM0_
|
|
||||||
|
|
||||||
// Use GCLK0 for SERCOM0 aka UART0
|
|
||||||
// GCLK_CLKCTRL_ID( clockId ) | // Generic Clock 0 (SERCOMx)
|
|
||||||
// GCLK_CLKCTRL_GEN_GCLK0 | // Generic Clock Generator 0 is source
|
|
||||||
// GCLK_CLKCTRL_CLKEN ;
|
|
||||||
sam.GCLK.CLKCTRL = sam.RegValue16((sam.GCLK_CLKCTRL_ID_SERCOM0_CORE << sam.GCLK_CLKCTRL_ID_Pos) |
|
|
||||||
(sam.GCLK_CLKCTRL_GEN_GCLK0 << sam.GCLK_CLKCTRL_GEN_Pos) |
|
|
||||||
sam.GCLK_CLKCTRL_CLKEN)
|
|
||||||
waitForSync()
|
|
||||||
|
|
||||||
// Turn on clock to SERCOM1
|
|
||||||
sam.PM.APBCMASK |= sam.PM_APBCMASK_SERCOM1_
|
|
||||||
sam.GCLK.CLKCTRL = sam.RegValue16((sam.GCLK_CLKCTRL_ID_SERCOM1_CORE << sam.GCLK_CLKCTRL_ID_Pos) |
|
|
||||||
(sam.GCLK_CLKCTRL_GEN_GCLK0 << sam.GCLK_CLKCTRL_GEN_Pos) |
|
|
||||||
sam.GCLK_CLKCTRL_CLKEN)
|
|
||||||
waitForSync()
|
|
||||||
|
|
||||||
// Turn on clock to SERCOM2
|
|
||||||
sam.PM.APBCMASK |= sam.PM_APBCMASK_SERCOM2_
|
|
||||||
sam.GCLK.CLKCTRL = sam.RegValue16((sam.GCLK_CLKCTRL_ID_SERCOM2_CORE << sam.GCLK_CLKCTRL_ID_Pos) |
|
|
||||||
(sam.GCLK_CLKCTRL_GEN_GCLK0 << sam.GCLK_CLKCTRL_GEN_Pos) |
|
|
||||||
sam.GCLK_CLKCTRL_CLKEN)
|
|
||||||
waitForSync()
|
|
||||||
|
|
||||||
// Turn on clock to SERCOM3
|
|
||||||
sam.PM.APBCMASK |= sam.PM_APBCMASK_SERCOM3_
|
|
||||||
sam.GCLK.CLKCTRL = sam.RegValue16((sam.GCLK_CLKCTRL_ID_SERCOM3_CORE << sam.GCLK_CLKCTRL_ID_Pos) |
|
|
||||||
(sam.GCLK_CLKCTRL_GEN_GCLK0 << sam.GCLK_CLKCTRL_GEN_Pos) |
|
|
||||||
sam.GCLK_CLKCTRL_CLKEN)
|
|
||||||
waitForSync()
|
|
||||||
|
|
||||||
// Turn on clock to SERCOM4
|
|
||||||
sam.PM.APBCMASK |= sam.PM_APBCMASK_SERCOM4_
|
|
||||||
|
|
||||||
// Use GCLK0 for SERCOM4
|
|
||||||
sam.GCLK.CLKCTRL = sam.RegValue16((sam.GCLK_CLKCTRL_ID_SERCOM4_CORE << sam.GCLK_CLKCTRL_ID_Pos) |
|
|
||||||
(sam.GCLK_CLKCTRL_GEN_GCLK0 << sam.GCLK_CLKCTRL_GEN_Pos) |
|
|
||||||
sam.GCLK_CLKCTRL_CLKEN)
|
|
||||||
waitForSync()
|
|
||||||
|
|
||||||
// Turn on clock to SERCOM5
|
|
||||||
sam.PM.APBCMASK |= sam.PM_APBCMASK_SERCOM5_
|
|
||||||
|
|
||||||
// Use GCLK0 for SERCOM5
|
|
||||||
sam.GCLK.CLKCTRL = sam.RegValue16((sam.GCLK_CLKCTRL_ID_SERCOM5_CORE << sam.GCLK_CLKCTRL_ID_Pos) |
|
|
||||||
(sam.GCLK_CLKCTRL_GEN_GCLK0 << sam.GCLK_CLKCTRL_GEN_Pos) |
|
|
||||||
sam.GCLK_CLKCTRL_CLKEN)
|
|
||||||
waitForSync()
|
|
||||||
}
|
|
||||||
|
|
||||||
func initUSBClock() {
|
func initUSBClock() {
|
||||||
// Turn on clock for USB
|
// Turn on clock for USB
|
||||||
sam.PM.APBBMASK |= sam.PM_APBBMASK_USB_
|
sam.PM.APBBMASK.SetBits(sam.PM_APBBMASK_USB_)
|
||||||
|
|
||||||
// Put Generic Clock Generator 0 as source for Generic Clock Multiplexer 6 (USB reference)
|
// Put Generic Clock Generator 0 as source for Generic Clock Multiplexer 6 (USB reference)
|
||||||
sam.GCLK.CLKCTRL = sam.RegValue16((sam.GCLK_CLKCTRL_ID_USB << sam.GCLK_CLKCTRL_ID_Pos) |
|
sam.GCLK.CLKCTRL.Set((sam.GCLK_CLKCTRL_ID_USB << sam.GCLK_CLKCTRL_ID_Pos) |
|
||||||
(sam.GCLK_CLKCTRL_GEN_GCLK0 << sam.GCLK_CLKCTRL_GEN_Pos) |
|
(sam.GCLK_CLKCTRL_GEN_GCLK0 << sam.GCLK_CLKCTRL_GEN_Pos) |
|
||||||
sam.GCLK_CLKCTRL_CLKEN)
|
sam.GCLK_CLKCTRL_CLKEN)
|
||||||
waitForSync()
|
waitForSync()
|
||||||
@@ -359,10 +306,10 @@ func initUSBClock() {
|
|||||||
|
|
||||||
func initADCClock() {
|
func initADCClock() {
|
||||||
// Turn on clock for ADC
|
// Turn on clock for ADC
|
||||||
sam.PM.APBCMASK |= sam.PM_APBCMASK_ADC_
|
sam.PM.APBCMASK.SetBits(sam.PM_APBCMASK_ADC_)
|
||||||
|
|
||||||
// Put Generic Clock Generator 0 as source for Generic Clock Multiplexer for ADC.
|
// Put Generic Clock Generator 0 as source for Generic Clock Multiplexer for ADC.
|
||||||
sam.GCLK.CLKCTRL = sam.RegValue16((sam.GCLK_CLKCTRL_ID_ADC << sam.GCLK_CLKCTRL_ID_Pos) |
|
sam.GCLK.CLKCTRL.Set((sam.GCLK_CLKCTRL_ID_ADC << sam.GCLK_CLKCTRL_ID_Pos) |
|
||||||
(sam.GCLK_CLKCTRL_GEN_GCLK0 << sam.GCLK_CLKCTRL_GEN_Pos) |
|
(sam.GCLK_CLKCTRL_GEN_GCLK0 << sam.GCLK_CLKCTRL_GEN_Pos) |
|
||||||
sam.GCLK_CLKCTRL_CLKEN)
|
sam.GCLK_CLKCTRL_CLKEN)
|
||||||
waitForSync()
|
waitForSync()
|
||||||
|
|||||||
@@ -0,0 +1,42 @@
|
|||||||
|
// +build sam,atsamd21,atsamd21e18
|
||||||
|
|
||||||
|
package runtime
|
||||||
|
|
||||||
|
import (
|
||||||
|
"device/sam"
|
||||||
|
)
|
||||||
|
|
||||||
|
func initSERCOMClocks() {
|
||||||
|
// Turn on clock to SERCOM0 for UART0
|
||||||
|
sam.PM.APBCMASK.SetBits(sam.PM_APBCMASK_SERCOM0_)
|
||||||
|
|
||||||
|
// Use GCLK0 for SERCOM0 aka UART0
|
||||||
|
// GCLK_CLKCTRL_ID( clockId ) | // Generic Clock 0 (SERCOMx)
|
||||||
|
// GCLK_CLKCTRL_GEN_GCLK0 | // Generic Clock Generator 0 is source
|
||||||
|
// GCLK_CLKCTRL_CLKEN ;
|
||||||
|
sam.GCLK.CLKCTRL.Set((sam.GCLK_CLKCTRL_ID_SERCOM0_CORE << sam.GCLK_CLKCTRL_ID_Pos) |
|
||||||
|
(sam.GCLK_CLKCTRL_GEN_GCLK0 << sam.GCLK_CLKCTRL_GEN_Pos) |
|
||||||
|
sam.GCLK_CLKCTRL_CLKEN)
|
||||||
|
waitForSync()
|
||||||
|
|
||||||
|
// Turn on clock to SERCOM1
|
||||||
|
sam.PM.APBCMASK.SetBits(sam.PM_APBCMASK_SERCOM1_)
|
||||||
|
sam.GCLK.CLKCTRL.Set((sam.GCLK_CLKCTRL_ID_SERCOM1_CORE << sam.GCLK_CLKCTRL_ID_Pos) |
|
||||||
|
(sam.GCLK_CLKCTRL_GEN_GCLK0 << sam.GCLK_CLKCTRL_GEN_Pos) |
|
||||||
|
sam.GCLK_CLKCTRL_CLKEN)
|
||||||
|
waitForSync()
|
||||||
|
|
||||||
|
// Turn on clock to SERCOM2
|
||||||
|
sam.PM.APBCMASK.SetBits(sam.PM_APBCMASK_SERCOM2_)
|
||||||
|
sam.GCLK.CLKCTRL.Set((sam.GCLK_CLKCTRL_ID_SERCOM2_CORE << sam.GCLK_CLKCTRL_ID_Pos) |
|
||||||
|
(sam.GCLK_CLKCTRL_GEN_GCLK0 << sam.GCLK_CLKCTRL_GEN_Pos) |
|
||||||
|
sam.GCLK_CLKCTRL_CLKEN)
|
||||||
|
waitForSync()
|
||||||
|
|
||||||
|
// Turn on clock to SERCOM3
|
||||||
|
sam.PM.APBCMASK.SetBits(sam.PM_APBCMASK_SERCOM3_)
|
||||||
|
sam.GCLK.CLKCTRL.Set((sam.GCLK_CLKCTRL_ID_SERCOM3_CORE << sam.GCLK_CLKCTRL_ID_Pos) |
|
||||||
|
(sam.GCLK_CLKCTRL_GEN_GCLK0 << sam.GCLK_CLKCTRL_GEN_Pos) |
|
||||||
|
sam.GCLK_CLKCTRL_CLKEN)
|
||||||
|
waitForSync()
|
||||||
|
}
|
||||||
@@ -0,0 +1,60 @@
|
|||||||
|
// +build sam,atsamd21,atsamd21g18
|
||||||
|
|
||||||
|
package runtime
|
||||||
|
|
||||||
|
import (
|
||||||
|
"device/sam"
|
||||||
|
)
|
||||||
|
|
||||||
|
func initSERCOMClocks() {
|
||||||
|
// Turn on clock to SERCOM0 for UART0
|
||||||
|
sam.PM.APBCMASK.SetBits(sam.PM_APBCMASK_SERCOM0_)
|
||||||
|
|
||||||
|
// Use GCLK0 for SERCOM0 aka UART0
|
||||||
|
// GCLK_CLKCTRL_ID( clockId ) | // Generic Clock 0 (SERCOMx)
|
||||||
|
// GCLK_CLKCTRL_GEN_GCLK0 | // Generic Clock Generator 0 is source
|
||||||
|
// GCLK_CLKCTRL_CLKEN ;
|
||||||
|
sam.GCLK.CLKCTRL.Set((sam.GCLK_CLKCTRL_ID_SERCOM0_CORE << sam.GCLK_CLKCTRL_ID_Pos) |
|
||||||
|
(sam.GCLK_CLKCTRL_GEN_GCLK0 << sam.GCLK_CLKCTRL_GEN_Pos) |
|
||||||
|
sam.GCLK_CLKCTRL_CLKEN)
|
||||||
|
waitForSync()
|
||||||
|
|
||||||
|
// Turn on clock to SERCOM1
|
||||||
|
sam.PM.APBCMASK.SetBits(sam.PM_APBCMASK_SERCOM1_)
|
||||||
|
sam.GCLK.CLKCTRL.Set((sam.GCLK_CLKCTRL_ID_SERCOM1_CORE << sam.GCLK_CLKCTRL_ID_Pos) |
|
||||||
|
(sam.GCLK_CLKCTRL_GEN_GCLK0 << sam.GCLK_CLKCTRL_GEN_Pos) |
|
||||||
|
sam.GCLK_CLKCTRL_CLKEN)
|
||||||
|
waitForSync()
|
||||||
|
|
||||||
|
// Turn on clock to SERCOM2
|
||||||
|
sam.PM.APBCMASK.SetBits(sam.PM_APBCMASK_SERCOM2_)
|
||||||
|
sam.GCLK.CLKCTRL.Set((sam.GCLK_CLKCTRL_ID_SERCOM2_CORE << sam.GCLK_CLKCTRL_ID_Pos) |
|
||||||
|
(sam.GCLK_CLKCTRL_GEN_GCLK0 << sam.GCLK_CLKCTRL_GEN_Pos) |
|
||||||
|
sam.GCLK_CLKCTRL_CLKEN)
|
||||||
|
waitForSync()
|
||||||
|
|
||||||
|
// Turn on clock to SERCOM3
|
||||||
|
sam.PM.APBCMASK.SetBits(sam.PM_APBCMASK_SERCOM3_)
|
||||||
|
sam.GCLK.CLKCTRL.Set((sam.GCLK_CLKCTRL_ID_SERCOM3_CORE << sam.GCLK_CLKCTRL_ID_Pos) |
|
||||||
|
(sam.GCLK_CLKCTRL_GEN_GCLK0 << sam.GCLK_CLKCTRL_GEN_Pos) |
|
||||||
|
sam.GCLK_CLKCTRL_CLKEN)
|
||||||
|
waitForSync()
|
||||||
|
|
||||||
|
// Turn on clock to SERCOM4
|
||||||
|
sam.PM.APBCMASK.SetBits(sam.PM_APBCMASK_SERCOM4_)
|
||||||
|
|
||||||
|
// Use GCLK0 for SERCOM4
|
||||||
|
sam.GCLK.CLKCTRL.Set((sam.GCLK_CLKCTRL_ID_SERCOM4_CORE << sam.GCLK_CLKCTRL_ID_Pos) |
|
||||||
|
(sam.GCLK_CLKCTRL_GEN_GCLK0 << sam.GCLK_CLKCTRL_GEN_Pos) |
|
||||||
|
sam.GCLK_CLKCTRL_CLKEN)
|
||||||
|
waitForSync()
|
||||||
|
|
||||||
|
// Turn on clock to SERCOM5
|
||||||
|
sam.PM.APBCMASK.SetBits(sam.PM_APBCMASK_SERCOM5_)
|
||||||
|
|
||||||
|
// Use GCLK0 for SERCOM5
|
||||||
|
sam.GCLK.CLKCTRL.Set((sam.GCLK_CLKCTRL_ID_SERCOM5_CORE << sam.GCLK_CLKCTRL_ID_Pos) |
|
||||||
|
(sam.GCLK_CLKCTRL_GEN_GCLK0 << sam.GCLK_CLKCTRL_GEN_Pos) |
|
||||||
|
sam.GCLK_CLKCTRL_CLKEN)
|
||||||
|
waitForSync()
|
||||||
|
}
|
||||||
@@ -41,11 +41,61 @@ func preinit() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func abort() {
|
func abort() {
|
||||||
|
// disable all interrupts
|
||||||
|
arm.DisableInterrupts()
|
||||||
|
|
||||||
|
// lock up forever
|
||||||
for {
|
for {
|
||||||
arm.Asm("wfi")
|
arm.Asm("wfi")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// The stack layout at the moment an interrupt occurs.
|
||||||
|
// Registers can be accessed if the stack pointer is cast to a pointer to this
|
||||||
|
// struct.
|
||||||
|
type interruptStack struct {
|
||||||
|
R0 uintptr
|
||||||
|
R1 uintptr
|
||||||
|
R2 uintptr
|
||||||
|
R3 uintptr
|
||||||
|
R12 uintptr
|
||||||
|
LR uintptr
|
||||||
|
PC uintptr
|
||||||
|
PSR uintptr
|
||||||
|
}
|
||||||
|
|
||||||
|
// This function is called at HardFault.
|
||||||
|
// Before this function is called, the stack pointer is reset to the initial
|
||||||
|
// stack pointer (loaded from addres 0x0) and the previous stack pointer is
|
||||||
|
// passed as an argument to this function. This allows for easy inspection of
|
||||||
|
// the stack the moment a HardFault occurs, but it means that the stack will be
|
||||||
|
// corrupted by this function and thus this handler must not attempt to recover.
|
||||||
|
//
|
||||||
|
// For details, see:
|
||||||
|
// https://community.arm.com/developer/ip-products/system/f/embedded-forum/3257/debugging-a-cortex-m0-hard-fault
|
||||||
|
// https://blog.feabhas.com/2013/02/developing-a-generic-hard-fault-handler-for-arm-cortex-m3cortex-m4/
|
||||||
|
//go:export handleHardFault
|
||||||
|
func handleHardFault(sp *interruptStack) {
|
||||||
|
print("fatal error: ")
|
||||||
|
if uintptr(unsafe.Pointer(sp)) < 0x20000000 {
|
||||||
|
print("stack overflow")
|
||||||
|
} else {
|
||||||
|
// TODO: try to find the cause of the hard fault. Especially on
|
||||||
|
// Cortex-M3 and higher it is possible to find more detailed information
|
||||||
|
// in special status registers.
|
||||||
|
print("HardFault")
|
||||||
|
}
|
||||||
|
print(" with sp=", sp)
|
||||||
|
if uintptr(unsafe.Pointer(&sp.PC)) >= 0x20000000 {
|
||||||
|
// Only print the PC if it points into memory.
|
||||||
|
// It may not point into memory during a stack overflow, so check that
|
||||||
|
// first before accessing the stack.
|
||||||
|
print(" pc=", sp.PC)
|
||||||
|
}
|
||||||
|
println()
|
||||||
|
abort()
|
||||||
|
}
|
||||||
|
|
||||||
// Implement memset for LLVM and compiler-rt.
|
// Implement memset for LLVM and compiler-rt.
|
||||||
//go:export memset
|
//go:export memset
|
||||||
func libc_memset(ptr unsafe.Pointer, c byte, size uintptr) {
|
func libc_memset(ptr unsafe.Pointer, c byte, size uintptr) {
|
||||||
|
|||||||
+10
-10
@@ -32,16 +32,16 @@ func init() {
|
|||||||
|
|
||||||
func initLFCLK() {
|
func initLFCLK() {
|
||||||
if machine.HasLowFrequencyCrystal {
|
if machine.HasLowFrequencyCrystal {
|
||||||
nrf.CLOCK.LFCLKSRC = nrf.CLOCK_LFCLKSTAT_SRC_Xtal
|
nrf.CLOCK.LFCLKSRC.Set(nrf.CLOCK_LFCLKSTAT_SRC_Xtal)
|
||||||
}
|
}
|
||||||
nrf.CLOCK.TASKS_LFCLKSTART = 1
|
nrf.CLOCK.TASKS_LFCLKSTART.Set(1)
|
||||||
for nrf.CLOCK.EVENTS_LFCLKSTARTED == 0 {
|
for nrf.CLOCK.EVENTS_LFCLKSTARTED.Get() == 0 {
|
||||||
}
|
}
|
||||||
nrf.CLOCK.EVENTS_LFCLKSTARTED = 0
|
nrf.CLOCK.EVENTS_LFCLKSTARTED.Set(0)
|
||||||
}
|
}
|
||||||
|
|
||||||
func initRTC() {
|
func initRTC() {
|
||||||
nrf.RTC1.TASKS_START = 1
|
nrf.RTC1.TASKS_START.Set(1)
|
||||||
arm.SetPriority(nrf.IRQ_RTC1, 0xc0) // low priority
|
arm.SetPriority(nrf.IRQ_RTC1, 0xc0) // low priority
|
||||||
arm.EnableIRQ(nrf.IRQ_RTC1)
|
arm.EnableIRQ(nrf.IRQ_RTC1)
|
||||||
}
|
}
|
||||||
@@ -72,7 +72,7 @@ var (
|
|||||||
// overflow the counter, leading to incorrect results. This might be fixed by
|
// overflow the counter, leading to incorrect results. This might be fixed by
|
||||||
// handling the overflow event.
|
// handling the overflow event.
|
||||||
func ticks() timeUnit {
|
func ticks() timeUnit {
|
||||||
rtcCounter := uint32(nrf.RTC1.COUNTER)
|
rtcCounter := uint32(nrf.RTC1.COUNTER.Get())
|
||||||
offset := (rtcCounter - rtcLastCounter) & 0xffffff // change since last measurement
|
offset := (rtcCounter - rtcLastCounter) & 0xffffff // change since last measurement
|
||||||
rtcLastCounter = rtcCounter
|
rtcLastCounter = rtcCounter
|
||||||
timestamp += timeUnit(offset) // TODO: not precise
|
timestamp += timeUnit(offset) // TODO: not precise
|
||||||
@@ -85,7 +85,7 @@ type isrFlag bool
|
|||||||
var rtc_wakeup isrFlag
|
var rtc_wakeup isrFlag
|
||||||
|
|
||||||
func rtc_sleep(ticks uint32) {
|
func rtc_sleep(ticks uint32) {
|
||||||
nrf.RTC1.INTENSET = nrf.RTC_INTENSET_COMPARE0
|
nrf.RTC1.INTENSET.Set(nrf.RTC_INTENSET_COMPARE0)
|
||||||
rtc_wakeup = false
|
rtc_wakeup = false
|
||||||
if ticks == 1 {
|
if ticks == 1 {
|
||||||
// Race condition (even in hardware) at ticks == 1.
|
// Race condition (even in hardware) at ticks == 1.
|
||||||
@@ -93,7 +93,7 @@ func rtc_sleep(ticks uint32) {
|
|||||||
// describes.
|
// describes.
|
||||||
ticks = 2
|
ticks = 2
|
||||||
}
|
}
|
||||||
nrf.RTC1.CC[0] = (nrf.RTC1.COUNTER + nrf.RegValue(ticks)) & 0x00ffffff
|
nrf.RTC1.CC[0].Set((nrf.RTC1.COUNTER.Get() + ticks) & 0x00ffffff)
|
||||||
for !rtc_wakeup {
|
for !rtc_wakeup {
|
||||||
arm.Asm("wfi")
|
arm.Asm("wfi")
|
||||||
}
|
}
|
||||||
@@ -101,7 +101,7 @@ func rtc_sleep(ticks uint32) {
|
|||||||
|
|
||||||
//go:export RTC1_IRQHandler
|
//go:export RTC1_IRQHandler
|
||||||
func handleRTC1() {
|
func handleRTC1() {
|
||||||
nrf.RTC1.INTENCLR = nrf.RTC_INTENSET_COMPARE0
|
nrf.RTC1.INTENCLR.Set(nrf.RTC_INTENSET_COMPARE0)
|
||||||
nrf.RTC1.EVENTS_COMPARE[0] = 0
|
nrf.RTC1.EVENTS_COMPARE[0].Set(0)
|
||||||
rtc_wakeup = true
|
rtc_wakeup = true
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,33 +21,33 @@ func putchar(c byte) {
|
|||||||
|
|
||||||
// initCLK sets clock to 72MHz using HSE 8MHz crystal w/ PLL X 9 (8MHz x 9 = 72MHz).
|
// initCLK sets clock to 72MHz using HSE 8MHz crystal w/ PLL X 9 (8MHz x 9 = 72MHz).
|
||||||
func initCLK() {
|
func initCLK() {
|
||||||
stm32.FLASH.ACR |= stm32.FLASH_ACR_LATENCY_2 // Two wait states, per datasheet
|
stm32.FLASH.ACR.SetBits(stm32.FLASH_ACR_LATENCY_2) // Two wait states, per datasheet
|
||||||
stm32.RCC.CFGR |= stm32.RCC_CFGR_PPRE1_DIV_2 // prescale PCLK1 = HCLK/2
|
stm32.RCC.CFGR.SetBits(stm32.RCC_CFGR_PPRE1_DIV_2) // prescale PCLK1 = HCLK/2
|
||||||
stm32.RCC.CFGR |= stm32.RCC_CFGR_PPRE2_DIV_NONE // prescale PCLK2 = HCLK/1
|
stm32.RCC.CFGR.SetBits(stm32.RCC_CFGR_PPRE2_DIV_NONE) // prescale PCLK2 = HCLK/1
|
||||||
stm32.RCC.CR |= stm32.RCC_CR_HSEON // enable HSE clock
|
stm32.RCC.CR.SetBits(stm32.RCC_CR_HSEON) // enable HSE clock
|
||||||
|
|
||||||
// wait for the HSEREADY flag
|
// wait for the HSEREADY flag
|
||||||
for (stm32.RCC.CR & stm32.RCC_CR_HSERDY) == 0 {
|
for !stm32.RCC.CR.HasBits(stm32.RCC_CR_HSERDY) {
|
||||||
}
|
}
|
||||||
|
|
||||||
stm32.RCC.CR |= stm32.RCC_CR_HSION // enable HSI clock
|
stm32.RCC.CR.SetBits(stm32.RCC_CR_HSION) // enable HSI clock
|
||||||
|
|
||||||
// wait for the HSIREADY flag
|
// wait for the HSIREADY flag
|
||||||
for (stm32.RCC.CR & stm32.RCC_CR_HSIRDY) == 0 {
|
for !stm32.RCC.CR.HasBits(stm32.RCC_CR_HSIRDY) {
|
||||||
}
|
}
|
||||||
|
|
||||||
stm32.RCC.CFGR |= stm32.RCC_CFGR_PLLSRC // set PLL source to HSE
|
stm32.RCC.CFGR.SetBits(stm32.RCC_CFGR_PLLSRC) // set PLL source to HSE
|
||||||
stm32.RCC.CFGR |= stm32.RCC_CFGR_PLLMUL_9 // multiply by 9
|
stm32.RCC.CFGR.SetBits(stm32.RCC_CFGR_PLLMUL_9) // multiply by 9
|
||||||
stm32.RCC.CR |= stm32.RCC_CR_PLLON // enable the PLL
|
stm32.RCC.CR.SetBits(stm32.RCC_CR_PLLON) // enable the PLL
|
||||||
|
|
||||||
// wait for the PLLRDY flag
|
// wait for the PLLRDY flag
|
||||||
for (stm32.RCC.CR & stm32.RCC_CR_PLLRDY) == 0 {
|
for !stm32.RCC.CR.HasBits(stm32.RCC_CR_PLLRDY) {
|
||||||
}
|
}
|
||||||
|
|
||||||
stm32.RCC.CFGR |= stm32.RCC_CFGR_SW_PLL // set clock source to pll
|
stm32.RCC.CFGR.SetBits(stm32.RCC_CFGR_SW_PLL) // set clock source to pll
|
||||||
|
|
||||||
// wait for PLL to be CLK
|
// wait for PLL to be CLK
|
||||||
for (stm32.RCC.CFGR & stm32.RCC_CFGR_SWS_PLL) == 0 {
|
for !stm32.RCC.CFGR.HasBits(stm32.RCC_CFGR_SWS_PLL) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -65,43 +65,43 @@ var timerWakeup isrFlag
|
|||||||
|
|
||||||
func initRTC() {
|
func initRTC() {
|
||||||
// Enable the PWR and BKP.
|
// Enable the PWR and BKP.
|
||||||
stm32.RCC.APB1ENR |= stm32.RCC_APB1ENR_PWREN | stm32.RCC_APB1ENR_BKPEN
|
stm32.RCC.APB1ENR.SetBits(stm32.RCC_APB1ENR_PWREN | stm32.RCC_APB1ENR_BKPEN)
|
||||||
|
|
||||||
// access to backup register
|
// access to backup register
|
||||||
stm32.PWR.CR |= stm32.PWR_CR_DBP
|
stm32.PWR.CR.SetBits(stm32.PWR_CR_DBP)
|
||||||
|
|
||||||
// Enable LSE
|
// Enable LSE
|
||||||
stm32.RCC.BDCR |= stm32.RCC_BDCR_LSEON
|
stm32.RCC.BDCR.SetBits(stm32.RCC_BDCR_LSEON)
|
||||||
|
|
||||||
// wait until LSE is ready
|
// wait until LSE is ready
|
||||||
for stm32.RCC.BDCR&stm32.RCC_BDCR_LSERDY == 0 {
|
for !stm32.RCC.BDCR.HasBits(stm32.RCC_BDCR_LSERDY) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Select LSE
|
// Select LSE
|
||||||
stm32.RCC.BDCR |= stm32.RCC_RTCCLKSource_LSE
|
stm32.RCC.BDCR.SetBits(stm32.RCC_RTCCLKSource_LSE)
|
||||||
|
|
||||||
// set prescaler to "max" per datasheet
|
// set prescaler to "max" per datasheet
|
||||||
stm32.RTC.PRLH = stm32.RTC_PRLH_PRLH_Msk
|
stm32.RTC.PRLH.Set(stm32.RTC_PRLH_PRLH_Msk)
|
||||||
stm32.RTC.PRLL = stm32.RTC_PRLL_PRLL_Msk
|
stm32.RTC.PRLL.Set(stm32.RTC_PRLL_PRLL_Msk)
|
||||||
|
|
||||||
// set count to zero
|
// set count to zero
|
||||||
stm32.RTC.CNTH = 0x0
|
stm32.RTC.CNTH.Set(0x0)
|
||||||
stm32.RTC.CNTL = 0x0
|
stm32.RTC.CNTL.Set(0x0)
|
||||||
|
|
||||||
// Enable RTC
|
// Enable RTC
|
||||||
stm32.RCC.BDCR |= stm32.RCC_BDCR_RTCEN
|
stm32.RCC.BDCR.SetBits(stm32.RCC_BDCR_RTCEN)
|
||||||
|
|
||||||
// Clear RSF
|
// Clear RSF
|
||||||
stm32.RTC.CRL &^= stm32.RTC_CRL_RSF
|
stm32.RTC.CRL.ClearBits(stm32.RTC_CRL_RSF)
|
||||||
|
|
||||||
// Wait till flag is set
|
// Wait till flag is set
|
||||||
for stm32.RTC.CRL&stm32.RTC_CRL_RSF == 0 {
|
for !stm32.RTC.CRL.HasBits(stm32.RTC_CRL_RSF) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Enable the TIM3 clock.
|
// Enable the TIM3 clock.
|
||||||
func initTIM() {
|
func initTIM() {
|
||||||
stm32.RCC.APB1ENR |= stm32.RCC_APB1ENR_TIM3EN
|
stm32.RCC.APB1ENR.SetBits(stm32.RCC_APB1ENR_TIM3EN)
|
||||||
|
|
||||||
arm.SetPriority(stm32.IRQ_TIM3, 0xc3)
|
arm.SetPriority(stm32.IRQ_TIM3, 0xc3)
|
||||||
arm.EnableIRQ(stm32.IRQ_TIM3)
|
arm.EnableIRQ(stm32.IRQ_TIM3)
|
||||||
@@ -122,10 +122,10 @@ func sleepTicks(d timeUnit) {
|
|||||||
// number of ticks (microseconds) since start.
|
// number of ticks (microseconds) since start.
|
||||||
func ticks() timeUnit {
|
func ticks() timeUnit {
|
||||||
// convert RTC counter from seconds to microseconds
|
// convert RTC counter from seconds to microseconds
|
||||||
timerCounter := uint64(stm32.RTC.CNTH<<16|stm32.RTC.CNTL) * 1000 * 1000
|
timerCounter := uint64(stm32.RTC.CNTH.Get()<<16|stm32.RTC.CNTL.Get()) * 1000 * 1000
|
||||||
|
|
||||||
// add the fractional part of current time using DIV register
|
// add the fractional part of current time using DIV register
|
||||||
timerCounter += uint64(0x8000-stm32.RTC.DIVL) * 31
|
timerCounter += uint64(0x8000-stm32.RTC.DIVL.Get()) * 31
|
||||||
|
|
||||||
// change since last measurement
|
// change since last measurement
|
||||||
offset := (timerCounter - timerLastCounter)
|
offset := (timerCounter - timerLastCounter)
|
||||||
@@ -165,16 +165,16 @@ func timerSleep(ticks uint32) {
|
|||||||
// The current scaling only supports a range of 100 usec to 6553 msec.
|
// The current scaling only supports a range of 100 usec to 6553 msec.
|
||||||
|
|
||||||
// prescale counter down from 72mhz to 10khz aka 0.1 ms frequency.
|
// prescale counter down from 72mhz to 10khz aka 0.1 ms frequency.
|
||||||
stm32.TIM3.PSC = machine.CPU_FREQUENCY/10000 - 1 // 7199
|
stm32.TIM3.PSC.Set(machine.CPU_FREQUENCY/10000 - 1) // 7199
|
||||||
|
|
||||||
// set duty aka duration
|
// set duty aka duration
|
||||||
stm32.TIM3.ARR = stm32.RegValue(ticks/100) - 1 // convert from microseconds to 0.1 ms
|
stm32.TIM3.ARR.Set(ticks/100 - 1) // convert from microseconds to 0.1 ms
|
||||||
|
|
||||||
// Enable the hardware interrupt.
|
// Enable the hardware interrupt.
|
||||||
stm32.TIM3.DIER |= stm32.TIM_DIER_UIE
|
stm32.TIM3.DIER.SetBits(stm32.TIM_DIER_UIE)
|
||||||
|
|
||||||
// Enable the timer.
|
// Enable the timer.
|
||||||
stm32.TIM3.CR1 |= stm32.TIM_CR1_CEN
|
stm32.TIM3.CR1.SetBits(stm32.TIM_CR1_CEN)
|
||||||
|
|
||||||
// wait till timer wakes up
|
// wait till timer wakes up
|
||||||
for !timerWakeup {
|
for !timerWakeup {
|
||||||
@@ -184,12 +184,12 @@ func timerSleep(ticks uint32) {
|
|||||||
|
|
||||||
//go:export TIM3_IRQHandler
|
//go:export TIM3_IRQHandler
|
||||||
func handleTIM3() {
|
func handleTIM3() {
|
||||||
if (stm32.TIM3.SR & stm32.TIM_SR_UIF) > 0 {
|
if stm32.TIM3.SR.HasBits(stm32.TIM_SR_UIF) {
|
||||||
// Disable the timer.
|
// Disable the timer.
|
||||||
stm32.TIM3.CR1 &^= stm32.TIM_CR1_CEN
|
stm32.TIM3.CR1.ClearBits(stm32.TIM_CR1_CEN)
|
||||||
|
|
||||||
// clear the update flag
|
// clear the update flag
|
||||||
stm32.TIM3.SR &^= stm32.TIM_SR_UIF
|
stm32.TIM3.SR.ClearBits(stm32.TIM_SR_UIF)
|
||||||
|
|
||||||
// timer was triggered
|
// timer was triggered
|
||||||
timerWakeup = true
|
timerWakeup = true
|
||||||
|
|||||||
@@ -42,58 +42,59 @@ func initCLK() {
|
|||||||
|
|
||||||
// Reset clock registers
|
// Reset clock registers
|
||||||
// Set HSION
|
// Set HSION
|
||||||
stm32.RCC.CR |= stm32.RCC_CR_HSION
|
stm32.RCC.CR.SetBits(stm32.RCC_CR_HSION)
|
||||||
for (stm32.RCC.CR & stm32.RCC_CR_HSIRDY) == 0 {
|
for !stm32.RCC.CR.HasBits(stm32.RCC_CR_HSIRDY) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reset CFGR
|
// Reset CFGR
|
||||||
stm32.RCC.CFGR = 0x00000000
|
stm32.RCC.CFGR.Set(0x00000000)
|
||||||
// Reset HSEON, CSSON and PLLON
|
// Reset HSEON, CSSON and PLLON
|
||||||
stm32.RCC.CR &= 0xFEF6FFFF
|
stm32.RCC.CR.ClearBits(stm32.RCC_CR_HSEON | stm32.RCC_CR_CSSON | stm32.RCC_CR_PLLON)
|
||||||
// Reset PLLCFGR
|
// Reset PLLCFGR
|
||||||
stm32.RCC.PLLCFGR = 0x24003010
|
stm32.RCC.PLLCFGR.Set(0x24003010)
|
||||||
// Reset HSEBYP
|
// Reset HSEBYP
|
||||||
stm32.RCC.CR &= 0xFFFBFFFF
|
stm32.RCC.CR.ClearBits(stm32.RCC_CR_HSEBYP)
|
||||||
// Disable all interrupts
|
// Disable all interrupts
|
||||||
stm32.RCC.CIR = 0x00000000
|
stm32.RCC.CIR.Set(0x00000000)
|
||||||
|
|
||||||
// Set up the clock
|
// Set up the clock
|
||||||
var startupCounter uint32 = 0
|
var startupCounter uint32 = 0
|
||||||
|
|
||||||
// Enable HSE
|
// Enable HSE
|
||||||
stm32.RCC.CR = stm32.RCC_CR_HSEON
|
stm32.RCC.CR.Set(stm32.RCC_CR_HSEON)
|
||||||
|
|
||||||
// Wait till HSE is ready and if timeout is reached exit
|
// Wait till HSE is ready and if timeout is reached exit
|
||||||
for {
|
for {
|
||||||
startupCounter++
|
startupCounter++
|
||||||
if (stm32.RCC.CR&stm32.RCC_CR_HSERDY != 0) || (startupCounter == HSE_STARTUP_TIMEOUT) {
|
if stm32.RCC.CR.HasBits(stm32.RCC_CR_HSERDY) || (startupCounter == HSE_STARTUP_TIMEOUT) {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (stm32.RCC.CR & stm32.RCC_CR_HSERDY) != 0 {
|
if stm32.RCC.CR.HasBits(stm32.RCC_CR_HSERDY) {
|
||||||
// Enable high performance mode, System frequency up to 168MHz
|
// Enable high performance mode, System frequency up to 168MHz
|
||||||
stm32.RCC.APB1ENR |= stm32.RCC_APB1ENR_PWREN
|
stm32.RCC.APB1ENR.SetBits(stm32.RCC_APB1ENR_PWREN)
|
||||||
stm32.PWR.CR |= 0x4000 // PWR_CR_VOS
|
stm32.PWR.CR.SetBits(0x4000) // PWR_CR_VOS
|
||||||
// HCLK = SYSCLK / 1
|
// HCLK = SYSCLK / 1
|
||||||
stm32.RCC.CFGR |= (0x0 << stm32.RCC_CFGR_HPRE_Pos)
|
stm32.RCC.CFGR.SetBits(0x0 << stm32.RCC_CFGR_HPRE_Pos)
|
||||||
// PCLK2 = HCLK / 2
|
// PCLK2 = HCLK / 2
|
||||||
stm32.RCC.CFGR |= (0x4 << stm32.RCC_CFGR_PPRE2_Pos)
|
stm32.RCC.CFGR.SetBits(0x4 << stm32.RCC_CFGR_PPRE2_Pos)
|
||||||
// PCLK1 = HCLK / 4
|
// PCLK1 = HCLK / 4
|
||||||
stm32.RCC.CFGR |= (0x5 << stm32.RCC_CFGR_PPRE1_Pos)
|
stm32.RCC.CFGR.SetBits(0x5 << stm32.RCC_CFGR_PPRE1_Pos)
|
||||||
// Configure the main PLL
|
// Configure the main PLL
|
||||||
// PLL Options - See RM0090 Reference Manual pg. 95
|
// PLL Options - See RM0090 Reference Manual pg. 95
|
||||||
stm32.RCC.PLLCFGR = PLL_M | (PLL_N << 6) | (((PLL_P >> 1) - 1) << 16) |
|
stm32.RCC.PLLCFGR.Set(PLL_M | (PLL_N << 6) | (((PLL_P >> 1) - 1) << 16) |
|
||||||
(1 << stm32.RCC_PLLCFGR_PLLSRC_Pos) | (PLL_Q << 24)
|
(1 << stm32.RCC_PLLCFGR_PLLSRC_Pos) | (PLL_Q << 24))
|
||||||
// Enable main PLL
|
// Enable main PLL
|
||||||
stm32.RCC.CR |= stm32.RCC_CR_PLLON
|
stm32.RCC.CR.SetBits(stm32.RCC_CR_PLLON)
|
||||||
// Wait till the main PLL is ready
|
// Wait till the main PLL is ready
|
||||||
for (stm32.RCC.CR & stm32.RCC_CR_PLLRDY) == 0 {
|
for (stm32.RCC.CR.Get() & stm32.RCC_CR_PLLRDY) == 0 {
|
||||||
}
|
}
|
||||||
// Configure Flash prefetch, Instruction cache, Data cache and wait state
|
// Configure Flash prefetch, Instruction cache, Data cache and wait state
|
||||||
stm32.FLASH.ACR = stm32.FLASH_ACR_ICEN | stm32.FLASH_ACR_DCEN | (5 << stm32.FLASH_ACR_LATENCY_Pos)
|
stm32.FLASH.ACR.Set(stm32.FLASH_ACR_ICEN | stm32.FLASH_ACR_DCEN | (5 << stm32.FLASH_ACR_LATENCY_Pos))
|
||||||
// Select the main PLL as system clock source
|
// Select the main PLL as system clock source
|
||||||
stm32.RCC.CFGR &^= stm32.RCC_CFGR_SW0 | stm32.RCC_CFGR_SW1
|
stm32.RCC.CFGR.ClearBits(stm32.RCC_CFGR_SW0 | stm32.RCC_CFGR_SW1)
|
||||||
stm32.RCC.CFGR |= (0x2 << stm32.RCC_CFGR_SW0_Pos)
|
stm32.RCC.CFGR.SetBits(0x2 << stm32.RCC_CFGR_SW0_Pos)
|
||||||
for (stm32.RCC.CFGR & (0x3 << stm32.RCC_CFGR_SWS0_Pos)) != (0x2 << stm32.RCC_CFGR_SWS0_Pos) {
|
for (stm32.RCC.CFGR.Get() & (0x3 << stm32.RCC_CFGR_SWS0_Pos)) != (0x2 << stm32.RCC_CFGR_SWS0_Pos) {
|
||||||
}
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
@@ -102,7 +103,7 @@ func initCLK() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Enable the CCM RAM clock
|
// Enable the CCM RAM clock
|
||||||
stm32.RCC.AHB1ENR |= (1 << 20)
|
stm32.RCC.AHB1ENR.SetBits(1 << 20)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -120,7 +121,7 @@ var timerWakeup isrFlag
|
|||||||
|
|
||||||
// Enable the TIM3 clock.(sleep count)
|
// Enable the TIM3 clock.(sleep count)
|
||||||
func initTIM3() {
|
func initTIM3() {
|
||||||
stm32.RCC.APB1ENR |= stm32.RCC_APB1ENR_TIM3EN
|
stm32.RCC.APB1ENR.SetBits(stm32.RCC_APB1ENR_TIM3EN)
|
||||||
|
|
||||||
arm.SetPriority(stm32.IRQ_TIM3, 0xc3)
|
arm.SetPriority(stm32.IRQ_TIM3, 0xc3)
|
||||||
arm.EnableIRQ(stm32.IRQ_TIM3)
|
arm.EnableIRQ(stm32.IRQ_TIM3)
|
||||||
@@ -128,17 +129,17 @@ func initTIM3() {
|
|||||||
|
|
||||||
// Enable the TIM7 clock.(tick count)
|
// Enable the TIM7 clock.(tick count)
|
||||||
func initTIM7() {
|
func initTIM7() {
|
||||||
stm32.RCC.APB1ENR |= stm32.RCC_APB1ENR_TIM7EN
|
stm32.RCC.APB1ENR.SetBits(stm32.RCC_APB1ENR_TIM7EN)
|
||||||
|
|
||||||
// CK_INT = APB1 x2 = 84mhz
|
// CK_INT = APB1 x2 = 84mhz
|
||||||
stm32.TIM7.PSC = 84000000/10000 - 1 // 84mhz to 10khz(0.1ms)
|
stm32.TIM7.PSC.Set(84000000/10000 - 1) // 84mhz to 10khz(0.1ms)
|
||||||
stm32.TIM7.ARR = stm32.RegValue(10) - 1 // interrupt per 1ms
|
stm32.TIM7.ARR.Set(10 - 1) // interrupt per 1ms
|
||||||
|
|
||||||
// Enable the hardware interrupt.
|
// Enable the hardware interrupt.
|
||||||
stm32.TIM7.DIER |= stm32.TIM_DIER_UIE
|
stm32.TIM7.DIER.SetBits(stm32.TIM_DIER_UIE)
|
||||||
|
|
||||||
// Enable the timer.
|
// Enable the timer.
|
||||||
stm32.TIM7.CR1 |= stm32.TIM_CR1_CEN
|
stm32.TIM7.CR1.SetBits(stm32.TIM_CR1_CEN)
|
||||||
|
|
||||||
arm.SetPriority(stm32.IRQ_TIM7, 0xc1)
|
arm.SetPriority(stm32.IRQ_TIM7, 0xc1)
|
||||||
arm.EnableIRQ(stm32.IRQ_TIM7)
|
arm.EnableIRQ(stm32.IRQ_TIM7)
|
||||||
@@ -163,20 +164,20 @@ func timerSleep(ticks uint32) {
|
|||||||
|
|
||||||
// CK_INT = APB1 x2 = 84mhz
|
// CK_INT = APB1 x2 = 84mhz
|
||||||
// prescale counter down from 84mhz to 10khz aka 0.1 ms frequency.
|
// prescale counter down from 84mhz to 10khz aka 0.1 ms frequency.
|
||||||
stm32.TIM3.PSC = 84000000/10000 - 1 // 8399
|
stm32.TIM3.PSC.Set(84000000/10000 - 1) // 8399
|
||||||
|
|
||||||
// set duty aka duration
|
// set duty aka duration
|
||||||
arr := (ticks / 100) - 1 // convert from microseconds to 0.1 ms
|
arr := (ticks / 100) - 1 // convert from microseconds to 0.1 ms
|
||||||
if arr == 0 {
|
if arr == 0 {
|
||||||
arr = 1 // avoid blocking
|
arr = 1 // avoid blocking
|
||||||
}
|
}
|
||||||
stm32.TIM3.ARR = stm32.RegValue(arr)
|
stm32.TIM3.ARR.Set(arr)
|
||||||
|
|
||||||
// Enable the hardware interrupt.
|
// Enable the hardware interrupt.
|
||||||
stm32.TIM3.DIER |= stm32.TIM_DIER_UIE
|
stm32.TIM3.DIER.SetBits(stm32.TIM_DIER_UIE)
|
||||||
|
|
||||||
// Enable the timer.
|
// Enable the timer.
|
||||||
stm32.TIM3.CR1 |= stm32.TIM_CR1_CEN
|
stm32.TIM3.CR1.SetBits(stm32.TIM_CR1_CEN)
|
||||||
|
|
||||||
// wait till timer wakes up
|
// wait till timer wakes up
|
||||||
for !timerWakeup {
|
for !timerWakeup {
|
||||||
@@ -186,12 +187,12 @@ func timerSleep(ticks uint32) {
|
|||||||
|
|
||||||
//go:export TIM3_IRQHandler
|
//go:export TIM3_IRQHandler
|
||||||
func handleTIM3() {
|
func handleTIM3() {
|
||||||
if (stm32.TIM3.SR & stm32.TIM_SR_UIF) > 0 {
|
if stm32.TIM3.SR.HasBits(stm32.TIM_SR_UIF) {
|
||||||
// Disable the timer.
|
// Disable the timer.
|
||||||
stm32.TIM3.CR1 &^= stm32.TIM_CR1_CEN
|
stm32.TIM3.CR1.ClearBits(stm32.TIM_CR1_CEN)
|
||||||
|
|
||||||
// clear the update flag
|
// clear the update flag
|
||||||
stm32.TIM3.SR &^= stm32.TIM_SR_UIF
|
stm32.TIM3.SR.ClearBits(stm32.TIM_SR_UIF)
|
||||||
|
|
||||||
// timer was triggered
|
// timer was triggered
|
||||||
timerWakeup = true
|
timerWakeup = true
|
||||||
@@ -200,9 +201,9 @@ func handleTIM3() {
|
|||||||
|
|
||||||
//go:export TIM7_IRQHandler
|
//go:export TIM7_IRQHandler
|
||||||
func handleTIM7() {
|
func handleTIM7() {
|
||||||
if (stm32.TIM7.SR & stm32.TIM_SR_UIF) > 0 {
|
if stm32.TIM7.SR.HasBits(stm32.TIM_SR_UIF) {
|
||||||
// clear the update flag
|
// clear the update flag
|
||||||
stm32.TIM7.SR &^= stm32.TIM_SR_UIF
|
stm32.TIM7.SR.ClearBits(stm32.TIM_SR_UIF)
|
||||||
tickCount++
|
tickCount++
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,6 +18,9 @@ func malloc(size uintptr) unsafe.Pointer
|
|||||||
//go:export abort
|
//go:export abort
|
||||||
func abort()
|
func abort()
|
||||||
|
|
||||||
|
//go:export exit
|
||||||
|
func exit(code int)
|
||||||
|
|
||||||
//go:export clock_gettime
|
//go:export clock_gettime
|
||||||
func clock_gettime(clk_id uint, ts *timespec)
|
func clock_gettime(clk_id uint, ts *timespec)
|
||||||
|
|
||||||
@@ -75,3 +78,8 @@ func monotime() uint64 {
|
|||||||
func ticks() timeUnit {
|
func ticks() timeUnit {
|
||||||
return timeUnit(monotime())
|
return timeUnit(monotime())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//go:linkname syscall_Exit syscall.Exit
|
||||||
|
func syscall_Exit(code int) {
|
||||||
|
exit(code)
|
||||||
|
}
|
||||||
|
|||||||
@@ -37,9 +37,16 @@ func putchar(c byte) {
|
|||||||
resource_write(stdout, &c, 1)
|
resource_write(stdout, &c, 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var handleEvent func()
|
||||||
|
|
||||||
//go:linkname setEventHandler syscall/js.setEventHandler
|
//go:linkname setEventHandler syscall/js.setEventHandler
|
||||||
func setEventHandler(fn func()) {
|
func setEventHandler(fn func()) {
|
||||||
// TODO
|
handleEvent = fn
|
||||||
|
}
|
||||||
|
|
||||||
|
//go:export resume
|
||||||
|
func resume() {
|
||||||
|
handleEvent()
|
||||||
}
|
}
|
||||||
|
|
||||||
//go:export go_scheduler
|
//go:export go_scheduler
|
||||||
|
|||||||
@@ -120,6 +120,9 @@ func setTaskPromisePtr(task *coroutine, value unsafe.Pointer) {
|
|||||||
// getTaskPromisePtr is a helper function to get the current .ptr field from a
|
// getTaskPromisePtr is a helper function to get the current .ptr field from a
|
||||||
// coroutine promise.
|
// coroutine promise.
|
||||||
func getTaskPromisePtr(task *coroutine) unsafe.Pointer {
|
func getTaskPromisePtr(task *coroutine) unsafe.Pointer {
|
||||||
|
if task == nil {
|
||||||
|
blockingPanic()
|
||||||
|
}
|
||||||
return task.promise().ptr
|
return task.promise().ptr
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -166,9 +166,10 @@ func decodeUTF8(s string, index uintptr) (rune, uintptr) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// indexByte returns the index of the first instance of c in s, or -1 if c is not present in s.
|
// indexByteString returns the index of the first instance of c in s, or -1 if c
|
||||||
//go:linkname indexByte strings.IndexByte
|
// is not present in s.
|
||||||
func indexByte(s string, c byte) int {
|
//go:linkname indexByteString internal/bytealg.IndexByteString
|
||||||
|
func indexByteString(s string, c byte) int {
|
||||||
for i := 0; i < len(s); i++ {
|
for i := 0; i < len(s); i++ {
|
||||||
if s[i] == c {
|
if s[i] == c {
|
||||||
return i
|
return i
|
||||||
|
|||||||
@@ -0,0 +1,12 @@
|
|||||||
|
// +build !go1.12
|
||||||
|
|
||||||
|
package runtime
|
||||||
|
|
||||||
|
// indexByte provides compatibility with Go 1.11.
|
||||||
|
// See the following:
|
||||||
|
// https://github.com/tinygo-org/tinygo/issues/351
|
||||||
|
// https://github.com/golang/go/commit/ad4a58e31501bce5de2aad90a620eaecdc1eecb8
|
||||||
|
//go:linkname indexByte strings.IndexByte
|
||||||
|
func indexByte(s string, c byte) int {
|
||||||
|
return indexByteString(s, c)
|
||||||
|
}
|
||||||
@@ -5,11 +5,13 @@ import (
|
|||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
|
"io/ioutil"
|
||||||
"os"
|
"os"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
"os/user"
|
"os/user"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"runtime"
|
"runtime"
|
||||||
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -22,6 +24,7 @@ type TargetSpec struct {
|
|||||||
Inherits []string `json:"inherits"`
|
Inherits []string `json:"inherits"`
|
||||||
Triple string `json:"llvm-target"`
|
Triple string `json:"llvm-target"`
|
||||||
CPU string `json:"cpu"`
|
CPU string `json:"cpu"`
|
||||||
|
Features []string `json:"features"`
|
||||||
GOOS string `json:"goos"`
|
GOOS string `json:"goos"`
|
||||||
GOARCH string `json:"goarch"`
|
GOARCH string `json:"goarch"`
|
||||||
BuildTags []string `json:"build-tags"`
|
BuildTags []string `json:"build-tags"`
|
||||||
@@ -50,6 +53,7 @@ func (spec *TargetSpec) copyProperties(spec2 *TargetSpec) {
|
|||||||
if spec2.CPU != "" {
|
if spec2.CPU != "" {
|
||||||
spec.CPU = spec2.CPU
|
spec.CPU = spec2.CPU
|
||||||
}
|
}
|
||||||
|
spec.Features = append(spec.Features, spec2.Features...)
|
||||||
if spec2.GOOS != "" {
|
if spec2.GOOS != "" {
|
||||||
spec.GOOS = spec2.GOOS
|
spec.GOOS = spec2.GOOS
|
||||||
}
|
}
|
||||||
@@ -368,3 +372,26 @@ func isGoroot(goroot string) bool {
|
|||||||
_, err := os.Stat(filepath.Join(goroot, "src", "runtime", "internal", "sys", "zversion.go"))
|
_, err := os.Stat(filepath.Join(goroot, "src", "runtime", "internal", "sys", "zversion.go"))
|
||||||
return err == nil
|
return err == nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// getGorootVersion returns the major and minor version for a given GOROOT path.
|
||||||
|
// If the goroot cannot be determined, (0, 0) is returned.
|
||||||
|
func getGorootVersion(goroot string) (major, minor int) {
|
||||||
|
data, err := ioutil.ReadFile(filepath.Join(goroot, "VERSION"))
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
s := string(data)
|
||||||
|
if s[:2] != "go" {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
parts := strings.Split(s[2:], ".")
|
||||||
|
if len(parts) < 2 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ignore the errors, strconv.Atoi will return 0 on most errors and we
|
||||||
|
// don't really handle errors here anyway.
|
||||||
|
major, _ = strconv.Atoi(parts[0])
|
||||||
|
minor, _ = strconv.Atoi(parts[1])
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|||||||
@@ -0,0 +1,15 @@
|
|||||||
|
{
|
||||||
|
"inherits": ["cortex-m"],
|
||||||
|
"llvm-target": "armv6m-none-eabi",
|
||||||
|
"build-tags": ["atsamd21e18", "atsamd21", "sam"],
|
||||||
|
"cflags": [
|
||||||
|
"--target=armv6m-none-eabi",
|
||||||
|
"-Qunused-arguments"
|
||||||
|
],
|
||||||
|
"ldflags": [
|
||||||
|
"-T", "targets/atsamd21.ld"
|
||||||
|
],
|
||||||
|
"extra-files": [
|
||||||
|
"src/device/sam/atsamd21e18a.s"
|
||||||
|
]
|
||||||
|
}
|
||||||
@@ -19,5 +19,8 @@
|
|||||||
"ldflags": [
|
"ldflags": [
|
||||||
"--gc-sections"
|
"--gc-sections"
|
||||||
],
|
],
|
||||||
|
"extra-files": [
|
||||||
|
"src/device/arm/cortexm.s"
|
||||||
|
],
|
||||||
"gdb": "arm-none-eabi-gdb"
|
"gdb": "arm-none-eabi-gdb"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,5 @@
|
|||||||
|
{
|
||||||
|
"inherits": ["atsamd21g18a"],
|
||||||
|
"build-tags": ["sam", "atsamd21g18a", "feather_m0"],
|
||||||
|
"flash": "bossac -d -i -e -w -v -R --offset=0x2000 {hex}"
|
||||||
|
}
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
{
|
||||||
|
"inherits": ["atsamd21e18a"],
|
||||||
|
"build-tags": ["sam", "atsamd21e18a", "trinket_m0"],
|
||||||
|
"flash": "bossac -d -i -e -w -v -R --offset=0x2000 {hex}"
|
||||||
|
}
|
||||||
@@ -13,6 +13,7 @@
|
|||||||
],
|
],
|
||||||
"ldflags": [
|
"ldflags": [
|
||||||
"--allow-undefined",
|
"--allow-undefined",
|
||||||
|
"--no-threads",
|
||||||
"--export-all"
|
"--export-all"
|
||||||
],
|
],
|
||||||
"emulator": ["node", "targets/wasm_exec.js"]
|
"emulator": ["node", "targets/wasm_exec.js"]
|
||||||
|
|||||||
+21
-23
@@ -240,9 +240,9 @@
|
|||||||
},
|
},
|
||||||
|
|
||||||
// func valueIndex(v ref, i int) ref
|
// func valueIndex(v ref, i int) ref
|
||||||
//"syscall/js.valueIndex": (sp) => {
|
"syscall/js.valueIndex": (ret_addr, v_addr, i) => {
|
||||||
// storeValue(sp + 24, Reflect.get(loadValue(sp + 8), getInt64(sp + 16)));
|
storeValue(ret_addr, Reflect.get(loadValue(v_addr), i));
|
||||||
//},
|
},
|
||||||
|
|
||||||
// valueSetIndex(v ref, i int, x ref)
|
// valueSetIndex(v ref, i int, x ref)
|
||||||
//"syscall/js.valueSetIndex": (sp) => {
|
//"syscall/js.valueSetIndex": (sp) => {
|
||||||
@@ -291,9 +291,9 @@
|
|||||||
},
|
},
|
||||||
|
|
||||||
// func valueLength(v ref) int
|
// func valueLength(v ref) int
|
||||||
//"syscall/js.valueLength": (sp) => {
|
"syscall/js.valueLength": (v_addr) => {
|
||||||
// setInt64(sp + 16, parseInt(loadValue(sp + 8).length));
|
return loadValue(v_addr).length;
|
||||||
//},
|
},
|
||||||
|
|
||||||
// valuePrepareString(v ref) (ref, int)
|
// valuePrepareString(v ref) (ref, int)
|
||||||
"syscall/js.valuePrepareString": (ret_addr, v_addr) => {
|
"syscall/js.valuePrepareString": (ret_addr, v_addr) => {
|
||||||
@@ -352,25 +352,23 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static _makeCallbackHelper(id, pendingCallbacks, go) {
|
_resume() {
|
||||||
return function () {
|
if (this.exited) {
|
||||||
pendingCallbacks.push({ id: id, args: arguments });
|
throw new Error("Go program has already exited");
|
||||||
go._resolveCallbackPromise();
|
}
|
||||||
};
|
this._inst.exports.resume();
|
||||||
|
if (this.exited) {
|
||||||
|
this._resolveExitPromise();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static _makeEventCallbackHelper(preventDefault, stopPropagation, stopImmediatePropagation, fn) {
|
_makeFuncWrapper(id) {
|
||||||
return function (event) {
|
const go = this;
|
||||||
if (preventDefault) {
|
return function () {
|
||||||
event.preventDefault();
|
const event = { id: id, this: this, args: arguments };
|
||||||
}
|
go._pendingEvent = event;
|
||||||
if (stopPropagation) {
|
go._resume();
|
||||||
event.stopPropagation();
|
return event.result;
|
||||||
}
|
|
||||||
if (stopImmediatePropagation) {
|
|
||||||
event.stopImmediatePropagation();
|
|
||||||
}
|
|
||||||
fn(event);
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Vendored
+1
@@ -17,6 +17,7 @@ int globalStructSize = sizeof(globalStruct);
|
|||||||
short globalArray[3] = {5, 6, 7};
|
short globalArray[3] = {5, 6, 7};
|
||||||
joined_t globalUnion;
|
joined_t globalUnion;
|
||||||
int globalUnionSize = sizeof(globalUnion);
|
int globalUnionSize = sizeof(globalUnion);
|
||||||
|
option_t globalOption = optionG;
|
||||||
|
|
||||||
int fortytwo() {
|
int fortytwo() {
|
||||||
return 42;
|
return 42;
|
||||||
|
|||||||
Vendored
+18
@@ -75,6 +75,24 @@ func main() {
|
|||||||
println("n in chain:", list.n)
|
println("n in chain:", list.n)
|
||||||
list = (*C.list_t)(list.next)
|
list = (*C.list_t)(list.next)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// named enum
|
||||||
|
var _ C.enum_option = C.optionA
|
||||||
|
var _ C.option_t = C.optionA
|
||||||
|
println("option:", C.globalOption)
|
||||||
|
println("option A:", C.optionA)
|
||||||
|
println("option B:", C.optionB)
|
||||||
|
println("option C:", C.optionC)
|
||||||
|
println("option D:", C.optionD)
|
||||||
|
println("option E:", C.optionE)
|
||||||
|
println("option F:", C.optionF)
|
||||||
|
println("option G:", C.optionG)
|
||||||
|
|
||||||
|
// anonymous enum
|
||||||
|
var _ C.option2_t = C.option2A
|
||||||
|
var _ C.option3_t = C.option3A
|
||||||
|
println("option 2A:", C.option2A)
|
||||||
|
println("option 3A:", C.option3A)
|
||||||
}
|
}
|
||||||
|
|
||||||
func printUnion(union C.joined_t) C.joined_t {
|
func printUnion(union C.joined_t) C.joined_t {
|
||||||
|
|||||||
Vendored
+19
@@ -47,6 +47,24 @@ void unionSetShort(short s);
|
|||||||
void unionSetFloat(float f);
|
void unionSetFloat(float f);
|
||||||
void unionSetData(short f0, short f1, short f2);
|
void unionSetData(short f0, short f1, short f2);
|
||||||
|
|
||||||
|
typedef enum option {
|
||||||
|
optionA,
|
||||||
|
optionB,
|
||||||
|
optionC = -5,
|
||||||
|
optionD,
|
||||||
|
optionE = 10,
|
||||||
|
optionF,
|
||||||
|
optionG,
|
||||||
|
} option_t;
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
option2A = 20,
|
||||||
|
} option2_t;
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
option3A = 21,
|
||||||
|
} option3_t;
|
||||||
|
|
||||||
// test globals and datatypes
|
// test globals and datatypes
|
||||||
extern int global;
|
extern int global;
|
||||||
extern int unusedGlobal;
|
extern int unusedGlobal;
|
||||||
@@ -66,6 +84,7 @@ extern int globalStructSize;
|
|||||||
extern short globalArray[3];
|
extern short globalArray[3];
|
||||||
extern joined_t globalUnion;
|
extern joined_t globalUnion;
|
||||||
extern int globalUnionSize;
|
extern int globalUnionSize;
|
||||||
|
extern option_t globalOption;
|
||||||
|
|
||||||
// test duplicate definitions
|
// test duplicate definitions
|
||||||
int add(int a, int b);
|
int add(int a, int b);
|
||||||
|
|||||||
Vendored
+10
@@ -35,3 +35,13 @@ struct: 3 5
|
|||||||
n in chain: 3
|
n in chain: 3
|
||||||
n in chain: 6
|
n in chain: 6
|
||||||
n in chain: 7
|
n in chain: 7
|
||||||
|
option: 12
|
||||||
|
option A: 0
|
||||||
|
option B: 1
|
||||||
|
option C: -5
|
||||||
|
option D: -4
|
||||||
|
option E: 10
|
||||||
|
option F: 11
|
||||||
|
option G: 12
|
||||||
|
option 2A: 20
|
||||||
|
option 3A: 21
|
||||||
|
|||||||
Vendored
+6
@@ -4,12 +4,18 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"math/rand"
|
"math/rand"
|
||||||
"os"
|
"os"
|
||||||
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
|
// package os, fmt
|
||||||
fmt.Println("stdin: ", os.Stdin.Fd())
|
fmt.Println("stdin: ", os.Stdin.Fd())
|
||||||
fmt.Println("stdout:", os.Stdout.Fd())
|
fmt.Println("stdout:", os.Stdout.Fd())
|
||||||
fmt.Println("stderr:", os.Stderr.Fd())
|
fmt.Println("stderr:", os.Stderr.Fd())
|
||||||
|
|
||||||
|
// package math/rand
|
||||||
fmt.Println("pseudorandom number:", rand.Int31())
|
fmt.Println("pseudorandom number:", rand.Int31())
|
||||||
|
|
||||||
|
// package strings
|
||||||
|
fmt.Println("strings.IndexByte:", strings.IndexByte("asdf", 'd'))
|
||||||
}
|
}
|
||||||
|
|||||||
Vendored
+1
@@ -2,3 +2,4 @@ stdin: 0
|
|||||||
stdout: 1
|
stdout: 1
|
||||||
stderr: 2
|
stderr: 2
|
||||||
pseudorandom number: 1298498081
|
pseudorandom number: 1298498081
|
||||||
|
strings.IndexByte: 2
|
||||||
|
|||||||
@@ -200,6 +200,16 @@ func (r *Register8) ClearBits(value uint8) {{
|
|||||||
volatile.StoreUint8(&r.Reg, volatile.LoadUint8(&r.Reg) &^ value)
|
volatile.StoreUint8(&r.Reg, volatile.LoadUint8(&r.Reg) &^ value)
|
||||||
}}
|
}}
|
||||||
|
|
||||||
|
// HasBits reads the register and then checks to see if the passed bits are set. It
|
||||||
|
// is the volatile equivalent of:
|
||||||
|
//
|
||||||
|
// (*r.Reg & value) > 0
|
||||||
|
//
|
||||||
|
//go:inline
|
||||||
|
func (r *Register8) HasBits(value uint8) bool {{
|
||||||
|
return (r.Get() & value) > 0
|
||||||
|
}}
|
||||||
|
|
||||||
// Some information about this device.
|
// Some information about this device.
|
||||||
const (
|
const (
|
||||||
DEVICE = "{name}"
|
DEVICE = "{name}"
|
||||||
|
|||||||
+171
-21
@@ -300,18 +300,168 @@ def writeGo(outdir, device):
|
|||||||
{licenseBlock}
|
{licenseBlock}
|
||||||
package {pkgName}
|
package {pkgName}
|
||||||
|
|
||||||
import "unsafe"
|
import (
|
||||||
|
"runtime/volatile"
|
||||||
|
"unsafe"
|
||||||
|
)
|
||||||
|
|
||||||
// Special types that cause loads/stores to be volatile (necessary for
|
// Special types that causes loads/stores to be volatile (necessary for
|
||||||
// memory-mapped registers).
|
// memory-mapped registers).
|
||||||
//go:volatile
|
type Register8 struct {{
|
||||||
type RegValue uint32
|
Reg uint8
|
||||||
|
}}
|
||||||
|
|
||||||
//go:volatile
|
// Get returns the value in the register. It is the volatile equivalent of:
|
||||||
type RegValue16 uint16
|
//
|
||||||
|
// *r.Reg
|
||||||
|
//
|
||||||
|
//go:inline
|
||||||
|
func (r *Register8) Get() uint8 {{
|
||||||
|
return volatile.LoadUint8(&r.Reg)
|
||||||
|
}}
|
||||||
|
|
||||||
//go:volatile
|
// Set updates the register value. It is the volatile equivalent of:
|
||||||
type RegValue8 uint8
|
//
|
||||||
|
// *r.Reg = value
|
||||||
|
//
|
||||||
|
//go:inline
|
||||||
|
func (r *Register8) Set(value uint8) {{
|
||||||
|
volatile.StoreUint8(&r.Reg, value)
|
||||||
|
}}
|
||||||
|
|
||||||
|
// SetBits reads the register, sets the given bits, and writes it back. It is
|
||||||
|
// the volatile equivalent of:
|
||||||
|
//
|
||||||
|
// r.Reg |= value
|
||||||
|
//
|
||||||
|
//go:inline
|
||||||
|
func (r *Register8) SetBits(value uint8) {{
|
||||||
|
volatile.StoreUint8(&r.Reg, volatile.LoadUint8(&r.Reg) | value)
|
||||||
|
}}
|
||||||
|
|
||||||
|
// ClearBits reads the register, clears the given bits, and writes it back. It
|
||||||
|
// is the volatile equivalent of:
|
||||||
|
//
|
||||||
|
// r.Reg &^= value
|
||||||
|
//
|
||||||
|
//go:inline
|
||||||
|
func (r *Register8) ClearBits(value uint8) {{
|
||||||
|
volatile.StoreUint8(&r.Reg, volatile.LoadUint8(&r.Reg) &^ value)
|
||||||
|
}}
|
||||||
|
|
||||||
|
// HasBits reads the register and then checks to see if the passed bits are set. It
|
||||||
|
// is the volatile equivalent of:
|
||||||
|
//
|
||||||
|
// (*r.Reg & value) > 0
|
||||||
|
//
|
||||||
|
//go:inline
|
||||||
|
func (r *Register8) HasBits(value uint8) bool {{
|
||||||
|
return (r.Get() & value) > 0
|
||||||
|
}}
|
||||||
|
|
||||||
|
type Register16 struct {{
|
||||||
|
Reg uint16
|
||||||
|
}}
|
||||||
|
|
||||||
|
// Get returns the value in the register. It is the volatile equivalent of:
|
||||||
|
//
|
||||||
|
// *r.Reg
|
||||||
|
//
|
||||||
|
//go:inline
|
||||||
|
func (r *Register16) Get() uint16 {{
|
||||||
|
return volatile.LoadUint16(&r.Reg)
|
||||||
|
}}
|
||||||
|
|
||||||
|
// Set updates the register value. It is the volatile equivalent of:
|
||||||
|
//
|
||||||
|
// *r.Reg = value
|
||||||
|
//
|
||||||
|
//go:inline
|
||||||
|
func (r *Register16) Set(value uint16) {{
|
||||||
|
volatile.StoreUint16(&r.Reg, value)
|
||||||
|
}}
|
||||||
|
|
||||||
|
// SetBits reads the register, sets the given bits, and writes it back. It is
|
||||||
|
// the volatile equivalent of:
|
||||||
|
//
|
||||||
|
// r.Reg |= value
|
||||||
|
//
|
||||||
|
//go:inline
|
||||||
|
func (r *Register16) SetBits(value uint16) {{
|
||||||
|
volatile.StoreUint16(&r.Reg, volatile.LoadUint16(&r.Reg) | value)
|
||||||
|
}}
|
||||||
|
|
||||||
|
// ClearBits reads the register, clears the given bits, and writes it back. It
|
||||||
|
// is the volatile equivalent of:
|
||||||
|
//
|
||||||
|
// r.Reg &^= value
|
||||||
|
//
|
||||||
|
//go:inline
|
||||||
|
func (r *Register16) ClearBits(value uint16) {{
|
||||||
|
volatile.StoreUint16(&r.Reg, volatile.LoadUint16(&r.Reg) &^ value)
|
||||||
|
}}
|
||||||
|
|
||||||
|
// HasBits reads the register and then checks to see if the passed bits are set. It
|
||||||
|
// is the volatile equivalent of:
|
||||||
|
//
|
||||||
|
// (*r.Reg & value) > 0
|
||||||
|
//
|
||||||
|
//go:inline
|
||||||
|
func (r *Register16) HasBits(value uint16) bool {{
|
||||||
|
return (r.Get() & value) > 0
|
||||||
|
}}
|
||||||
|
|
||||||
|
type Register32 struct {{
|
||||||
|
Reg uint32
|
||||||
|
}}
|
||||||
|
|
||||||
|
// Get returns the value in the register. It is the volatile equivalent of:
|
||||||
|
//
|
||||||
|
// *r.Reg
|
||||||
|
//
|
||||||
|
//go:inline
|
||||||
|
func (r *Register32) Get() uint32 {{
|
||||||
|
return volatile.LoadUint32(&r.Reg)
|
||||||
|
}}
|
||||||
|
|
||||||
|
// Set updates the register value. It is the volatile equivalent of:
|
||||||
|
//
|
||||||
|
// *r.Reg = value
|
||||||
|
//
|
||||||
|
//go:inline
|
||||||
|
func (r *Register32) Set(value uint32) {{
|
||||||
|
volatile.StoreUint32(&r.Reg, value)
|
||||||
|
}}
|
||||||
|
|
||||||
|
// SetBits reads the register, sets the given bits, and writes it back. It is
|
||||||
|
// the volatile equivalent of:
|
||||||
|
//
|
||||||
|
// r.Reg |= value
|
||||||
|
//
|
||||||
|
//go:inline
|
||||||
|
func (r *Register32) SetBits(value uint32) {{
|
||||||
|
volatile.StoreUint32(&r.Reg, volatile.LoadUint32(&r.Reg) | value)
|
||||||
|
}}
|
||||||
|
|
||||||
|
// ClearBits reads the register, clears the given bits, and writes it back. It
|
||||||
|
// is the volatile equivalent of:
|
||||||
|
//
|
||||||
|
// r.Reg &^= value
|
||||||
|
//
|
||||||
|
//go:inline
|
||||||
|
func (r *Register32) ClearBits(value uint32) {{
|
||||||
|
volatile.StoreUint32(&r.Reg, volatile.LoadUint32(&r.Reg) &^ value)
|
||||||
|
}}
|
||||||
|
|
||||||
|
// HasBits reads the register and then checks to see if the passed bits are set. It
|
||||||
|
// is the volatile equivalent of:
|
||||||
|
//
|
||||||
|
// (*r.Reg & value) > 0
|
||||||
|
//
|
||||||
|
//go:inline
|
||||||
|
func (r *Register32) HasBits(value uint32) bool {{
|
||||||
|
return (r.Get() & value) > 0
|
||||||
|
}}
|
||||||
|
|
||||||
// Some information about this device.
|
// Some information about this device.
|
||||||
const (
|
const (
|
||||||
@@ -349,22 +499,22 @@ const (
|
|||||||
continue
|
continue
|
||||||
eSize = register['elementsize']
|
eSize = register['elementsize']
|
||||||
if eSize == 4:
|
if eSize == 4:
|
||||||
regType = 'RegValue'
|
regType = 'Register32'
|
||||||
elif eSize == 2:
|
elif eSize == 2:
|
||||||
regType = 'RegValue16'
|
regType = 'Register16'
|
||||||
elif eSize == 1:
|
elif eSize == 1:
|
||||||
regType = 'RegValue8'
|
regType = 'Register8'
|
||||||
else:
|
else:
|
||||||
eSize = 4
|
eSize = 4
|
||||||
regType = 'RegValue'
|
regType = 'Register32'
|
||||||
|
|
||||||
# insert padding, if needed
|
# insert padding, if needed
|
||||||
if address < register['address']:
|
if address < register['address']:
|
||||||
bytesNeeded = register['address'] - address
|
bytesNeeded = register['address'] - address
|
||||||
if bytesNeeded == 1:
|
if bytesNeeded == 1:
|
||||||
out.write('\t_padding{padNumber} {regType}\n'.format(padNumber=padNumber, regType='RegValue8'))
|
out.write('\t_padding{padNumber} {regType}\n'.format(padNumber=padNumber, regType='Register8'))
|
||||||
elif bytesNeeded == 2:
|
elif bytesNeeded == 2:
|
||||||
out.write('\t_padding{padNumber} {regType}\n'.format(padNumber=padNumber, regType='RegValue16'))
|
out.write('\t_padding{padNumber} {regType}\n'.format(padNumber=padNumber, regType='Register16'))
|
||||||
else:
|
else:
|
||||||
numSkip = (register['address'] - address) // eSize
|
numSkip = (register['address'] - address) // eSize
|
||||||
if numSkip == 1:
|
if numSkip == 1:
|
||||||
@@ -381,28 +531,28 @@ const (
|
|||||||
subaddress = register['address']
|
subaddress = register['address']
|
||||||
for subregister in register['registers']:
|
for subregister in register['registers']:
|
||||||
if subregister['elementsize'] == 4:
|
if subregister['elementsize'] == 4:
|
||||||
subregType = 'RegValue'
|
subregType = 'Register32'
|
||||||
elif subregister['elementsize'] == 2:
|
elif subregister['elementsize'] == 2:
|
||||||
subregType = 'RegValue16'
|
subregType = 'Register16'
|
||||||
else:
|
else:
|
||||||
subregType = 'RegValue8'
|
subregType = 'Register8'
|
||||||
|
|
||||||
if subregister['array']:
|
if subregister['array']:
|
||||||
subregType = '[{}]{}'.format(subregister['array'], subregType)
|
subregType = '[{}]{}'.format(subregister['array'], subregType)
|
||||||
if subaddress != subregister['address']:
|
if subaddress != subregister['address']:
|
||||||
bytesNeeded = subregister['address'] - subaddress
|
bytesNeeded = subregister['address'] - subaddress
|
||||||
if bytesNeeded == 1:
|
if bytesNeeded == 1:
|
||||||
regType += '\t\t_padding{padNumber} {subregType}\n'.format(padNumber=padNumber, subregType='RegValue8')
|
regType += '\t\t_padding{padNumber} {subregType}\n'.format(padNumber=padNumber, subregType='Register8')
|
||||||
elif bytesNeeded == 2:
|
elif bytesNeeded == 2:
|
||||||
regType += '\t\t_padding{padNumber} {subregType}\n'.format(padNumber=padNumber, subregType='RegValue16')
|
regType += '\t\t_padding{padNumber} {subregType}\n'.format(padNumber=padNumber, subregType='Register16')
|
||||||
else:
|
else:
|
||||||
numSkip = (subregister['address'] - subaddress)
|
numSkip = (subregister['address'] - subaddress)
|
||||||
if numSkip < 1:
|
if numSkip < 1:
|
||||||
continue
|
continue
|
||||||
elif numSkip == 1:
|
elif numSkip == 1:
|
||||||
regType += '\t\t_padding{padNumber} {subregType}\n'.format(padNumber=padNumber, subregType='RegValue8')
|
regType += '\t\t_padding{padNumber} {subregType}\n'.format(padNumber=padNumber, subregType='Register8')
|
||||||
else:
|
else:
|
||||||
regType += '\t\t_padding{padNumber} [{num}]{subregType}\n'.format(padNumber=padNumber, num=numSkip, subregType='RegValue8')
|
regType += '\t\t_padding{padNumber} [{num}]{subregType}\n'.format(padNumber=padNumber, num=numSkip, subregType='Register8')
|
||||||
padNumber += 1
|
padNumber += 1
|
||||||
subaddress += bytesNeeded
|
subaddress += bytesNeeded
|
||||||
if subregister['array'] is not None:
|
if subregister['array'] is not None:
|
||||||
|
|||||||
+1
-1
@@ -2,4 +2,4 @@ package main
|
|||||||
|
|
||||||
// version of this package.
|
// version of this package.
|
||||||
// Update this value before release of new version of software.
|
// Update this value before release of new version of software.
|
||||||
const version = "0.5.0"
|
const version = "0.6.0"
|
||||||
|
|||||||
Reference in New Issue
Block a user